diff options
author | Stefan Agner <stefan.agner@toradex.com> | 2014-12-12 14:28:40 +0100 |
---|---|---|
committer | Stefan Agner <stefan.agner@toradex.com> | 2014-12-12 14:28:40 +0100 |
commit | 0ab36cda6160128c22e3096a059344e424973e66 (patch) | |
tree | 06cc1a96dff7cb618558ea078a35fd6ae2cf0e5d | |
parent | 468a53d361f09314b988699e80c390099e093f2e (diff) | |
parent | 150e89eb50b28b8012b3b72284637fdd5761102f (diff) |
Merge branch 'vf610-mscm-3.18' into toradex_vf_3.18-next-test
-rw-r--r-- | arch/arm/boot/dts/vf500.dtsi | 1 | ||||
-rw-r--r-- | arch/arm/boot/dts/vfxxx.dtsi | 5 | ||||
-rw-r--r-- | arch/arm/mach-imx/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-imx/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/common.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/gpc.c | 18 | ||||
-rw-r--r-- | arch/arm/mach-imx/mach-vf610.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/mscm-vf610.c | 133 |
8 files changed, 155 insertions, 9 deletions
diff --git a/arch/arm/boot/dts/vf500.dtsi b/arch/arm/boot/dts/vf500.dtsi index 6e00169f9908..b78db4728d97 100644 --- a/arch/arm/boot/dts/vf500.dtsi +++ b/arch/arm/boot/dts/vf500.dtsi @@ -30,6 +30,7 @@ intc: interrupt-controller@40002000 { compatible = "arm,cortex-a9-gic"; + arm,routable-irqs = <144>; #interrupt-cells = <3>; interrupt-controller; reg = <0x40003000 0x1000>, diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi index 8d04d8add4a0..ecfe68036c23 100644 --- a/arch/arm/boot/dts/vfxxx.dtsi +++ b/arch/arm/boot/dts/vfxxx.dtsi @@ -76,6 +76,11 @@ #size-cells = <1>; ranges; + mscm: mscm@40001000 { + compatible = "fsl,vf610-mscm"; + reg = <0x40001000 0x1000>; + }; + edma0: dma-controller@40018000 { #dma-cells = <2>; compatible = "fsl,vf610-edma"; diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index dd765bc63abd..286c7ffd1006 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -58,6 +58,9 @@ config HAVE_IMX_SRC def_bool y if SMP select ARCH_HAS_RESET_CONTROLLER +config HAVE_VF610_MSCM + bool + config IMX_HAVE_IOMUX_V1 bool @@ -631,6 +634,7 @@ config SOC_IMX6SX config SOC_VF610 bool "Vybrid Family VF610 support" + select HAVE_VF610_MSCM select ARM_GIC select PINCTRL_VF610 select HAVE_IMX_GPC diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 2b17bb35d0bb..302fe835ecd0 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -109,6 +109,7 @@ obj-$(CONFIG_SOC_IMX50) += mach-imx50.o obj-$(CONFIG_SOC_IMX51) += mach-imx51.o obj-$(CONFIG_SOC_IMX53) += mach-imx53.o +obj-$(CONFIG_HAVE_VF610_MSCM) += mscm-vf610.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index c0a536f821ea..58b59643f868 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -111,6 +111,7 @@ static inline void imx_smp_prepare(void) {} void imx_src_init(void); void imx6_gpc_init(void); void vf610_gpc_init(void); +void vf610_mscm_init(void); void imx_gpc_pre_suspend(bool arm_power_off); void imx_gpc_post_resume(void); void imx_gpc_mask_all(void); diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 4ac7a48065d1..017f40a8d04a 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -58,14 +58,14 @@ void imx_gpc_post_resume(void) static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) { - unsigned int idx = d->irq / 32 - 1; + unsigned int idx = d->hwirq / 32 - 1; u32 mask; /* Sanity check for SPI irq */ - if (d->irq < 32) + if (d->hwirq < 32) return -EINVAL; - mask = 1 << d->irq % 32; + mask = 1 << d->hwirq % 32; gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask : gpc_wake_irqs[idx] & ~mask; @@ -97,12 +97,12 @@ void imx_gpc_irq_unmask(struct irq_data *d) u32 val; /* Sanity check for SPI irq */ - if (d->irq < 32) + if (d->hwirq < 32) return; - reg = gpc_imr_base + (d->irq / 32 - 1) * 4; + reg = gpc_imr_base + (d->hwirq / 32 - 1) * 4; val = readl_relaxed(reg); - val &= ~(1 << d->irq % 32); + val &= ~(1 << d->hwirq % 32); writel_relaxed(val, reg); } @@ -112,12 +112,12 @@ void imx_gpc_irq_mask(struct irq_data *d) u32 val; /* Sanity check for SPI irq */ - if (d->irq < 32) + if (d->hwirq < 32) return; - reg = gpc_imr_base + (d->irq / 32 - 1) * 4; + reg = gpc_imr_base + (d->hwirq / 32 - 1) * 4; val = readl_relaxed(reg); - val |= 1 << (d->irq % 32); + val |= 1 << (d->hwirq % 32); writel_relaxed(val, reg); } diff --git a/arch/arm/mach-imx/mach-vf610.c b/arch/arm/mach-imx/mach-vf610.c index 4ba460263349..f9335384c6aa 100644 --- a/arch/arm/mach-imx/mach-vf610.c +++ b/arch/arm/mach-imx/mach-vf610.c @@ -16,6 +16,7 @@ static void __init vf610_init_irq(void) { vf610_gpc_init(); + vf610_mscm_init(); irqchip_init(); } diff --git a/arch/arm/mach-imx/mscm-vf610.c b/arch/arm/mach-imx/mscm-vf610.c new file mode 100644 index 000000000000..6dc45b52b811 --- /dev/null +++ b/arch/arm/mach-imx/mscm-vf610.c @@ -0,0 +1,133 @@ +/* + * Copyright 2014 Stefan Agner + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/cpu_pm.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/irqchip/arm-gic.h> +#include "common.h" + +#define MSCM_CPxNUM 0x4 +#define MSCM_IRSPRC(n) (0x880 + 2 * (n)) +#define MSCM_IRSPRC_CPEN_MASK 0x3 + +#define MSCM_IRSPRC_NUM 112 + +#define MSCM_IRQ_OFFSET 32 + +static void __iomem *mscm_base; +static u16 mscm_saved_irsprc[MSCM_IRSPRC_NUM]; +static u16 cpu_id; + +static int vf610_mscm_notifier(struct notifier_block *self, unsigned long cmd, + void *v) +{ + int i; + + /* Only the primary (boot CPU) should do suspend/resume */ + if (cpu_id > 0) + return NOTIFY_OK; + + switch (cmd) { + case CPU_CLUSTER_PM_ENTER: + for (i = 0; i < MSCM_IRSPRC_NUM; i++) + mscm_saved_irsprc[i] = + readw_relaxed(mscm_base + MSCM_IRSPRC(i)); + break; + case CPU_CLUSTER_PM_ENTER_FAILED: + case CPU_CLUSTER_PM_EXIT: + for (i = 0; i < MSCM_IRSPRC_NUM; i++) + writew_relaxed(mscm_saved_irsprc[i], + mscm_base + MSCM_IRSPRC(i)); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block mscm_notifier_block = { + .notifier_call = vf610_mscm_notifier, +}; + +static int vf610_mscm_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + u16 irsprc; + + /* Do not handle non Interrupt Router IRQs */ + if (hw < MSCM_IRQ_OFFSET) + return 0; + + hw -= MSCM_IRQ_OFFSET; + irsprc = readw_relaxed(mscm_base + MSCM_IRSPRC(hw)); + irsprc &= MSCM_IRSPRC_CPEN_MASK; + + /* Warn if interrupt is enabled on another CPU */ + WARN_ON(irsprc & ~(0x1 << cpu_id)); + + writew_relaxed(0x1 << cpu_id, mscm_base + MSCM_IRSPRC(hw)); + + return 0; +} + +static void vf610_mscm_domain_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq; + u16 irsprc; + + /* Do not handle non Interrupt Router IRQs */ + if (hw < MSCM_IRQ_OFFSET) + return; + + hw -= MSCM_IRQ_OFFSET; + irsprc = readw_relaxed(mscm_base + MSCM_IRSPRC(hw)); + irsprc &= MSCM_IRSPRC_CPEN_MASK; + + writew_relaxed(0x1 << cpu_id, mscm_base + MSCM_IRSPRC(hw)); +} + +static int vf610_mscm_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + *out_hwirq += 16; + return 0; +} +static const struct irq_domain_ops routable_irq_domain_ops = { + .map = vf610_mscm_domain_map, + .unmap = vf610_mscm_domain_unmap, + .xlate = vf610_mscm_domain_xlate, +}; + +void __init vf610_mscm_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,vf610-mscm"); + mscm_base = of_iomap(np, 0); + + if (!mscm_base) { + WARN_ON(1); + return; + } + + cpu_id = readl_relaxed(mscm_base + MSCM_CPxNUM); + + /* Register MSCM as interrupt router */ + register_routable_domain_ops(&routable_irq_domain_ops); + + cpu_pm_register_notifier(&mscm_notifier_block); +} |