From 47b06fc2d97a0d98d6053357561f2953d6547d25 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sat, 13 Sep 2014 00:34:31 +0200 Subject: ARM: rockchip: add a cpufreq-cpu0 device Rockchip SoCs can sucessfully use the generic cpufreq-cpu0 driver to do frequency scaling. Therefore add a platform device in the machine init code. Signed-off-by: Heiko Stuebner --- arch/arm/mach-rockchip/rockchip.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c index 8ab9e0e7ff04..eea1f06366e6 100644 --- a/arch/arm/mach-rockchip/rockchip.c +++ b/arch/arm/mach-rockchip/rockchip.c @@ -24,6 +24,12 @@ #include #include "core.h" +static void __init rockchip_dt_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + platform_device_register_simple("cpufreq-cpu0", 0, NULL, 0); +} + static const char * const rockchip_board_dt_compat[] = { "rockchip,rk2928", "rockchip,rk3066a", @@ -37,4 +43,5 @@ DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)") .l2c_aux_val = 0, .l2c_aux_mask = ~0, .dt_compat = rockchip_board_dt_compat, + .init_machine = rockchip_dt_init, MACHINE_END -- cgit v1.2.3-59-g8ed1b From 3eb79a5a9d46b32f63f6b9cd86f9b2bba43e127a Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 30 Sep 2014 10:33:27 +0200 Subject: ARM: rockchip: honor renaming of cpufreq-cpu0 to cpufreq-dt cpufreq-cpu0 got renamed to a more generic name cpufreq-dt, so adapt the created platform-device to this. Reported-by: Viresh Kumar Signed-off-by: Heiko Stuebner --- arch/arm/mach-rockchip/rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c index eea1f06366e6..d226b71d21d5 100644 --- a/arch/arm/mach-rockchip/rockchip.c +++ b/arch/arm/mach-rockchip/rockchip.c @@ -27,7 +27,7 @@ static void __init rockchip_dt_init(void) { of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - platform_device_register_simple("cpufreq-cpu0", 0, NULL, 0); + platform_device_register_simple("cpufreq-dt", 0, NULL, 0); } static const char * const rockchip_board_dt_compat[] = { -- cgit v1.2.3-59-g8ed1b From 0da6e72504f327c051979745843b5c614565e2ed Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 24 Sep 2014 23:09:09 +0800 Subject: Documentation: sunxi: Update Allwinner SoC documentation (A31/A31s/A23) Lately we have received documentation for A31 and A31s, in addition to A23 documentation which was received earlier but not added. Add these to the README, and update to reflect that A31 and A23 are supported. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- Documentation/arm/sunxi/README | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README index 7945238453ed..57c4da6a9ed2 100644 --- a/Documentation/arm/sunxi/README +++ b/Documentation/arm/sunxi/README @@ -37,15 +37,24 @@ SunXi family http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf - Allwinner A23 - + Not Supported + + Datasheet + http://dl.linux-sunxi.org/A23/A23%20Datasheet%20V1.0%2020130830.pdf + + User Manual + http://dl.linux-sunxi.org/A23/A23%20User%20Manual%20V1.0%2020130830.pdf * Quad ARM Cortex-A7 based SoCs - Allwinner A31 (sun6i) + Datasheet - http://dl.linux-sunxi.org/A31/A31%20Datasheet%20-%20v1.00%20(2012-12-24).pdf + http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20datasheet%20V1.3%2020131106.pdf + + User Manual + http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20user%20manual%20V1.1%2020130630.pdf - Allwinner A31s (sun6i) + Not Supported + + Datasheet + http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20datasheet%20V1.3%2020131106.pdf + + User Manual + http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20User%20Manual%20%20V1.0%2020130322.pdf * Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs - Allwinner A80 -- cgit v1.2.3-59-g8ed1b From d4da889a53d9dabe1c75384f3175dab7ff06c4ee Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 24 Sep 2014 22:48:56 +0800 Subject: ARM: sunxi: Add debug uart used by sun9i (Allwinner A80) The uarts on sun9i are still compatible with the dw_8250, but are located at different addresses. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/Kconfig.debug | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 03dc4c1a8736..0bc06ab9fb86 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -731,6 +731,14 @@ choice Say Y here if you want kernel low-level debugging support on SOCFPGA based platforms. + config DEBUG_SUN9I_UART0 + bool "Kernel low-level debugging messages via sun9i UART0" + depends on MACH_SUN9I + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on Allwinner A80 based platforms on the UART0. + config DEBUG_SUNXI_UART0 bool "Kernel low-level debugging messages via sunXi UART0" depends on ARCH_SUNXI @@ -1106,6 +1114,7 @@ config DEBUG_UART_PHYS default 0x02530c00 if DEBUG_KEYSTONE_UART0 default 0x02531000 if DEBUG_KEYSTONE_UART1 default 0x03010fe0 if ARCH_RPC + default 0x07000000 if DEBUG_SUN9I_UART0 default 0x10009000 if DEBUG_REALVIEW_STD_PORT || \ DEBUG_VEXPRESS_UART0_CA9 default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT @@ -1190,6 +1199,7 @@ config DEBUG_UART_VIRT default 0xf2100000 if DEBUG_PXA_UART1 default 0xf4090000 if ARCH_LPC32XX default 0xf4200000 if ARCH_GEMINI + default 0xf7000000 if DEBUG_SUN9I_UART0 default 0xf7000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \ DEBUG_S3C2410_UART0) default 0xf7004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \ -- cgit v1.2.3-59-g8ed1b From bb647665bae4dfdf7e1d07540325eab81f9800a8 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 24 Sep 2014 22:48:59 +0800 Subject: devicetree: bindings: Add vendor prefix for Merrii Technology Co., Ltd. Merrii Technology Co., Ltd. is a Chinese ARM integration developer that specializes in Allwinner SoC based designs. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 723999d73744..3da78a14e6c7 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -90,6 +90,7 @@ lltc Linear Technology Corporation marvell Marvell Technology Group Ltd. maxim Maxim Integrated Products mediatek MediaTek Inc. +merrii Merrii Technology Co., Ltd. micrel Micrel Inc. microchip Microchip Technology Inc. mitsubishi Mitsubishi Electric Corporation -- cgit v1.2.3-59-g8ed1b From 3d4c2f1ced78fc6f74d0d9ddb25f66722f978fd1 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 8 Oct 2014 21:02:52 +0800 Subject: ARM: sunxi: Introduce Allwinner A80 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Allwinner A80 is a new Cortex octo-core A7/A15 big.LITTLE SoC. While it's processor cores and interconnecting bus are new, it re-uses many peripherals found in earlier Allwinner SoCs. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Tested-by: Andreas Färber --- arch/arm/mach-sunxi/Kconfig | 5 +++++ arch/arm/mach-sunxi/sunxi.c | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 1aaa1e15ef70..d04f84b4f937 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -42,4 +42,9 @@ config MACH_SUN8I select MFD_SUN6I_PRCM select RESET_CONTROLLER +config MACH_SUN9I + bool "Allwinner (sun9i) SoCs support" + default ARCH_SUNXI + select ARM_GIC + endif diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c index d7598aeed803..1f986758784a 100644 --- a/arch/arm/mach-sunxi/sunxi.c +++ b/arch/arm/mach-sunxi/sunxi.c @@ -63,3 +63,12 @@ static const char * const sun8i_board_dt_compat[] = { DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family") .dt_compat = sun8i_board_dt_compat, MACHINE_END + +static const char * const sun9i_board_dt_compat[] = { + "allwinner,sun9i-a80", + NULL, +}; + +DT_MACHINE_START(SUN9I_DT, "Allwinner sun9i Family") + .dt_compat = sun9i_board_dt_compat, +MACHINE_END -- cgit v1.2.3-59-g8ed1b From a1a0193bdd855d0bcfbfc62fa59882242236882b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 8 Oct 2014 21:02:55 +0800 Subject: devicetree: bindings: Document supported Allwinner sunxi SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a list of supported Allwinner SoC bindings. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Tested-by: Andreas Färber --- Documentation/devicetree/bindings/arm/sunxi.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/sunxi.txt diff --git a/Documentation/devicetree/bindings/arm/sunxi.txt b/Documentation/devicetree/bindings/arm/sunxi.txt new file mode 100644 index 000000000000..42941fdefb11 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/sunxi.txt @@ -0,0 +1,12 @@ +Allwinner sunXi Platforms Device Tree Bindings + +Each device tree must specify which Allwinner SoC it uses, +using one of the following compatible strings: + + allwinner,sun4i-a10 + allwinner,sun5i-a10s + allwinner,sun5i-a13 + allwinner,sun6i-a31 + allwinner,sun7i-a20 + allwinner,sun8i-a23 + allwinner,sun9i-a80 -- cgit v1.2.3-59-g8ed1b From 19e704e35e33e2e468a4d038f83003ff9e9bd4cd Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 8 Oct 2014 21:02:56 +0800 Subject: Documentation: sunxi: Add A80 datasheet link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now have initial support for the A80, as well a the datasheet. Update the documents to reflect this. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Tested-by: Andreas Färber --- Documentation/arm/sunxi/README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README index 57c4da6a9ed2..e68d163df33d 100644 --- a/Documentation/arm/sunxi/README +++ b/Documentation/arm/sunxi/README @@ -58,4 +58,5 @@ SunXi family * Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs - Allwinner A80 - + Not Supported \ No newline at end of file + + Datasheet + http://dl.linux-sunxi.org/A80/A80_Datasheet_Revision_1.0_0404.pdf -- cgit v1.2.3-59-g8ed1b From 2f4bc73445fd3786b91d24b879fed527ef533cbf Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sun, 12 Oct 2014 17:40:24 +0800 Subject: ARM: sunxi: Select ARCH_HAS_RESET_CONTROLLER and RESET_CONTROLLER for sun9i The A80 SoC has reset controls matching bus clock gates. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/mach-sunxi/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index d04f84b4f937..a77604fbaf25 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -45,6 +45,8 @@ config MACH_SUN8I config MACH_SUN9I bool "Allwinner (sun9i) SoCs support" default ARCH_SUNXI + select ARCH_HAS_RESET_CONTROLLER select ARM_GIC + select RESET_CONTROLLER endif -- cgit v1.2.3-59-g8ed1b From 32ed35ff22ec03d8a935dfe8b90c599da4b4cb02 Mon Sep 17 00:00:00 2001 From: Vikas Sajjan Date: Wed, 24 Sep 2014 16:45:13 +0900 Subject: ARM: EXYNOS: Move Disabling of JPEG USE_RETENTION for exynos5250 to pmu.c Move the Disabling of JPEG USE_RETENTION for exynos5250 to pmu.c to make way for refactoring of pm.c and to create common functions across exynos4 and exynos5250. Signed-off-by: Vikas Sajjan Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pm.c | 7 +------ arch/arm/mach-exynos/pmu.c | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index abefacb45976..31e209b38f41 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -255,13 +255,8 @@ static void exynos_pm_prepare(void) s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - if (soc_is_exynos5250()) { + if (soc_is_exynos5250()) s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save)); - /* Disable USE_RETENTION of JPEG_MEM_OPTION */ - tmp = pmu_raw_readl(EXYNOS5_JPEG_MEM_OPTION); - tmp &= ~EXYNOS5_OPTION_USE_RETENTION; - pmu_raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION); - } /* Set value of power down register for sleep mode */ diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index ff9d23f0a7d9..cfc62e86cdee 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -264,6 +264,7 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = { { EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_JPEG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS5_JPEG_MEM_OPTION, { 0x10, 0x10, 0x0} }, { EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_MCUIOP_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_SATA_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, -- cgit v1.2.3-59-g8ed1b From 066da1ae52c30ae7e2792dbbb0d6bcbba493245e Mon Sep 17 00:00:00 2001 From: Vikas Sajjan Date: Wed, 24 Sep 2014 16:45:14 +0900 Subject: ARM: EXYNOS: Refactor the pm code to use DT based lookup Refactoring the pm.c to avoid using "soc_is_exynos" checks, instead use the DT based lookup. While at it, consolidate the common code across SoCs and create static helper functions. Signed-off-by: Vikas Sajjan Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pm.c | 167 ++++++++++++++++++++++++++++++---------- arch/arm/mach-exynos/regs-pmu.h | 1 + 2 files changed, 126 insertions(+), 42 deletions(-) diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 31e209b38f41..16b23d156eec 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -36,6 +36,8 @@ #include "regs-pmu.h" #include "regs-sys.h" +#define REG_TABLE_END (-1U) + /** * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping * @hwirq: Hardware IRQ signal of the GIC @@ -59,6 +61,21 @@ static struct sleep_save exynos_core_save[] = { SAVE_ITEM(S5P_SROM_BC3), }; +struct exynos_pm_data { + const struct exynos_wkup_irq *wkup_irq; + struct sleep_save *extra_save; + int num_extra_save; + unsigned int wake_disable_mask; + unsigned int *release_ret_regs; + + void (*pm_prepare)(void); + void (*pm_resume)(void); + int (*pm_suspend)(void); + int (*cpu_suspend)(unsigned long); +}; + +struct exynos_pm_data *pm_data; + /* * GIC wake-up support */ @@ -77,14 +94,24 @@ static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { { /* sentinel */ }, }; +unsigned int exynos_release_ret_regs[] = { + S5P_PAD_RET_MAUDIO_OPTION, + S5P_PAD_RET_GPIO_OPTION, + S5P_PAD_RET_UART_OPTION, + S5P_PAD_RET_MMCA_OPTION, + S5P_PAD_RET_MMCB_OPTION, + S5P_PAD_RET_EBIA_OPTION, + S5P_PAD_RET_EBIB_OPTION, + REG_TABLE_END, +}; + static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) { const struct exynos_wkup_irq *wkup_irq; - if (soc_is_exynos5250()) - wkup_irq = exynos5250_wkup_irq; - else - wkup_irq = exynos4_wkup_irq; + if (!pm_data->wkup_irq) + return -ENOENT; + wkup_irq = pm_data->wkup_irq; while (wkup_irq->mask) { if (wkup_irq->hwirq == data->hwirq) { @@ -229,15 +256,8 @@ void exynos_enter_aftr(void) cpu_pm_exit(); } -static int exynos_cpu_suspend(unsigned long arg) +static int exynos_cpu_do_idle(void) { -#ifdef CONFIG_CACHE_L2X0 - outer_flush_all(); -#endif - - if (soc_is_exynos5250()) - flush_cache_all(); - /* issue the standby signal into the pm unit. */ cpu_do_idle(); @@ -245,29 +265,44 @@ static int exynos_cpu_suspend(unsigned long arg) return 1; /* Aborting suspend */ } -static void exynos_pm_prepare(void) +static int exynos_cpu_suspend(unsigned long arg) { - unsigned int tmp; + flush_cache_all(); + outer_flush_all(); + return exynos_cpu_do_idle(); +} +static void exynos_pm_set_wakeup_mask(void) +{ /* Set wake-up mask registers */ pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); +} - s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - - if (soc_is_exynos5250()) - s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save)); - +static void exynos_pm_enter_sleep_mode(void) +{ /* Set value of power down register for sleep mode */ - exynos_sys_powerdown_conf(SYS_SLEEP); pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); /* ensure at least INFORM0 has the resume address */ - pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); } +static void exynos_pm_prepare(void) +{ + /* Set wake-up mask registers */ + exynos_pm_set_wakeup_mask(); + + s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + + if (pm_data->extra_save) + s3c_pm_do_save(pm_data->extra_save, + pm_data->num_extra_save); + + exynos_pm_enter_sleep_mode(); +} + static int exynos_pm_suspend(void) { unsigned long tmp; @@ -285,6 +320,15 @@ static int exynos_pm_suspend(void) return 0; } +static void exynos_pm_release_retention(void) +{ + unsigned int i; + + for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++) + pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR, + pm_data->release_ret_regs[i]); +} + static void exynos_pm_resume(void) { if (exynos_pm_central_resume()) @@ -294,18 +338,11 @@ static void exynos_pm_resume(void) exynos_cpu_restore_register(); /* For release retention */ + exynos_pm_release_retention(); - pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION); - - if (soc_is_exynos5250()) - s3c_pm_do_restore(exynos5_sys_save, - ARRAY_SIZE(exynos5_sys_save)); + if (pm_data->extra_save) + s3c_pm_do_restore_core(pm_data->extra_save, + pm_data->num_extra_save); s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); @@ -316,15 +353,8 @@ early_wakeup: /* Clear SLEEP mode set in INFORM1 */ pmu_raw_writel(0x0, S5P_INFORM1); - - return; } -static struct syscore_ops exynos_pm_syscore_ops = { - .suspend = exynos_pm_suspend, - .resume = exynos_pm_resume, -}; - /* * Suspend Ops */ @@ -348,11 +378,12 @@ static int exynos_suspend_enter(suspend_state_t state) } s3c_pm_save_uarts(); - exynos_pm_prepare(); + if (pm_data->pm_prepare) + pm_data->pm_prepare(); flush_cache_all(); s3c_pm_check_store(); - ret = cpu_suspend(0, exynos_cpu_suspend); + ret = cpu_suspend(0, pm_data->cpu_suspend); if (ret) return ret; @@ -387,18 +418,70 @@ static const struct platform_suspend_ops exynos_suspend_ops = { .valid = suspend_valid_only_mem, }; +static const struct exynos_pm_data exynos4_pm_data = { + .wkup_irq = exynos4_wkup_irq, + .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), + .release_ret_regs = exynos_release_ret_regs, + .pm_suspend = exynos_pm_suspend, + .pm_resume = exynos_pm_resume, + .pm_prepare = exynos_pm_prepare, + .cpu_suspend = exynos_cpu_suspend, +}; + +static const struct exynos_pm_data exynos5250_pm_data = { + .wkup_irq = exynos5250_wkup_irq, + .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), + .release_ret_regs = exynos_release_ret_regs, + .extra_save = exynos5_sys_save, + .num_extra_save = ARRAY_SIZE(exynos5_sys_save), + .pm_suspend = exynos_pm_suspend, + .pm_resume = exynos_pm_resume, + .pm_prepare = exynos_pm_prepare, + .cpu_suspend = exynos_cpu_suspend, +}; + +static struct of_device_id exynos_pmu_of_device_ids[] = { + { + .compatible = "samsung,exynos4210-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos4212-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos4412-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos5250-pmu", + .data = &exynos5250_pm_data, + }, + { /*sentinel*/ }, +}; + +static struct syscore_ops exynos_pm_syscore_ops; + void __init exynos_pm_init(void) { + const struct of_device_id *match; u32 tmp; + of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); + if (!match) { + pr_err("Failed to find PMU node\n"); + return; + } + pm_data = (struct exynos_pm_data *) match->data; + /* Platform-specific GIC callback */ gic_arch_extn.irq_set_wake = exynos_irq_set_wake; /* All wakeup disable */ tmp = pmu_raw_readl(S5P_WAKEUP_MASK); - tmp |= ((0xFF << 8) | (0x1F << 1)); + tmp |= pm_data->wake_disable_mask; pmu_raw_writel(tmp, S5P_WAKEUP_MASK); + exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; + exynos_pm_syscore_ops.resume = pm_data->pm_resume; + register_syscore_ops(&exynos_pm_syscore_ops); suspend_set_ops(&exynos_suspend_ops); } diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 96a1569262b5..30c03017aa6a 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -21,6 +21,7 @@ #define S5P_USE_STANDBY_WFI0 (1 << 16) #define S5P_USE_STANDBY_WFE0 (1 << 24) +#define EXYNOS_WAKEUP_FROM_LOWPWR (1 << 28) #define EXYNOS_SWRESET 0x0400 #define EXYNOS5440_SWRESET 0x00C4 -- cgit v1.2.3-59-g8ed1b From 9c261f89a30010a33c15e6b7cfc7c79ae6bea653 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Wed, 24 Sep 2014 01:24:35 +0900 Subject: ARM: firmware: Introduce suspend and resume operations This patch extends the firmware_ops structure with two new callbacks: .suspend() and .resume(). The former is intended to ask the firmware to save all its volatile state and suspend the system, without returning back to the kernel in between. The latter is to be called early by very low level platform suspend code after waking up to restore low level hardware state, which can't be restored in non-secure mode. While at it, outdated version of the structure is removed from the documentation and replaced with a reference to the header file. Signed-off-by: Tomasz Figa Acked-by: Alexandre Courbot Signed-off-by: Kukjin Kim --- Documentation/arm/firmware.txt | 28 +++++----------------------- arch/arm/include/asm/firmware.h | 8 ++++++++ 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/Documentation/arm/firmware.txt b/Documentation/arm/firmware.txt index c2e468fe7b0b..da6713adac8a 100644 --- a/Documentation/arm/firmware.txt +++ b/Documentation/arm/firmware.txt @@ -7,32 +7,14 @@ world, which changes the way some things have to be initialized. This makes a need to provide an interface for such platforms to specify available firmware operations and call them when needed. -Firmware operations can be specified using struct firmware_ops - - struct firmware_ops { - /* - * Enters CPU idle mode - */ - int (*do_idle)(void); - /* - * Sets boot address of specified physical CPU - */ - int (*set_cpu_boot_addr)(int cpu, unsigned long boot_addr); - /* - * Boots specified physical CPU - */ - int (*cpu_boot)(int cpu); - /* - * Initializes L2 cache - */ - int (*l2x0_init)(void); - }; - -and then registered with register_firmware_ops function +Firmware operations can be specified by filling in a struct firmware_ops +with appropriate callbacks and then registering it with register_firmware_ops() +function. void register_firmware_ops(const struct firmware_ops *ops) -the ops pointer must be non-NULL. +The ops pointer must be non-NULL. More information about struct firmware_ops +and its members can be found in arch/arm/include/asm/firmware.h header. There is a default, empty set of operations provided, so there is no need to set anything if platform does not require firmware operations. diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 2c9f10df7568..5904f59b0409 100644 --- a/arch/arm/include/asm/firmware.h +++ b/arch/arm/include/asm/firmware.h @@ -41,6 +41,14 @@ struct firmware_ops { * Initializes L2 cache */ int (*l2x0_init)(void); + /* + * Enter system-wide suspend. + */ + int (*suspend)(void); + /* + * Restore state of privileged hardware after system-wide suspend. + */ + int (*resume)(void); }; /* Global pointer for current firmware_ops structure, can't be NULL. */ -- cgit v1.2.3-59-g8ed1b From 2b9d9c321b5900c7ce82110a81cf3827ca9b33c6 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Wed, 24 Sep 2014 01:24:39 +0900 Subject: ARM: EXYNOS: Add support for firmware-assisted suspend/resume On a numer of Exynos-based boards Linux kernel is running in non-secure mode under a secure firmware. This means that certain operations need to be handled in special way, with firmware assistance. System-wide suspend/resume is an example of such operations. This patch adds support for firmware-assisted suspend/resume by leveraging recently introduced suspend and resume firmware operations and modifying existing suspend/resume paths to account for presence of secure firmware. Signed-off-by: Tomasz Figa [kgene.kim@samsung.com: rebased] Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/Makefile | 1 + arch/arm/mach-exynos/common.h | 4 ++++ arch/arm/mach-exynos/firmware.c | 45 +++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-exynos/pm.c | 16 ++++++++++----- arch/arm/mach-exynos/sleep.S | 28 +++++++++++++++++++++++++ arch/arm/mach-exynos/smc.h | 4 ++++ 6 files changed, 93 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 27ae6144679c..45bef21a3b66 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -21,6 +21,7 @@ CFLAGS_hotplug.o += -march=armv7-a plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_sec) +AFLAGS_sleep.o :=-Wa,-march=armv7-a$(plus_sec) obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o CFLAGS_mcpm-exynos.o += -march=armv7-a diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 47b904b3b973..c218200f8544 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -111,6 +111,9 @@ IS_SAMSUNG_CPU(exynos5800, EXYNOS5800_SOC_ID, EXYNOS5_SOC_MASK) #define soc_is_exynos5() (soc_is_exynos5250() || soc_is_exynos5410() || \ soc_is_exynos5420() || soc_is_exynos5800()) +extern u32 cp15_save_diag; +extern u32 cp15_save_power; + extern void __iomem *sysram_ns_base_addr; extern void __iomem *sysram_base_addr; extern void __iomem *pmu_base_addr; @@ -127,6 +130,7 @@ static inline void exynos_pm_init(void) {} #endif extern void exynos_cpu_resume(void); +extern void exynos_cpu_resume_ns(void); extern struct smp_operations exynos_smp_ops; diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index e8797bb78871..f5e626d55951 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -14,13 +14,20 @@ #include #include +#include +#include #include +#include #include #include "common.h" #include "smc.h" +#define EXYNOS_SLEEP_MAGIC 0x00000bad +#define EXYNOS_BOOT_ADDR 0x8 +#define EXYNOS_BOOT_FLAG 0xc + static int exynos_do_idle(void) { exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); @@ -69,10 +76,48 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr) return 0; } +static int exynos_cpu_suspend(unsigned long arg) +{ + flush_cache_all(); + outer_flush_all(); + + exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + + pr_info("Failed to suspend the system\n"); + writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); + return 1; +} + +static int exynos_suspend(void) +{ + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { + /* Save Power control and Diagnostic registers */ + asm ("mrc p15, 0, %0, c15, c0, 0\n" + "mrc p15, 0, %1, c15, c0, 1\n" + : "=r" (cp15_save_power), "=r" (cp15_save_diag) + : : "cc"); + } + + writel(EXYNOS_SLEEP_MAGIC, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); + writel(virt_to_phys(exynos_cpu_resume_ns), + sysram_ns_base_addr + EXYNOS_BOOT_ADDR); + + return cpu_suspend(0, exynos_cpu_suspend); +} + +static int exynos_resume(void) +{ + writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); + + return 0; +} + static const struct firmware_ops exynos_firmware_ops = { .do_idle = exynos_do_idle, .set_cpu_boot_addr = exynos_set_cpu_boot_addr, .cpu_boot = exynos_cpu_boot, + .suspend = exynos_suspend, + .resume = exynos_resume, }; void __init exynos_firmware_init(void) diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 16b23d156eec..047ac302835d 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -331,12 +332,11 @@ static void exynos_pm_release_retention(void) static void exynos_pm_resume(void) { + u32 cpuid = read_cpuid_part(); + if (exynos_pm_central_resume()) goto early_wakeup; - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_restore_register(); - /* For release retention */ exynos_pm_release_retention(); @@ -346,9 +346,13 @@ static void exynos_pm_resume(void) s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + if (cpuid == ARM_CPU_PART_CORTEX_A9) scu_enable(S5P_VA_SCU); + if (call_firmware_op(resume) == -ENOSYS + && cpuid == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_restore_register(); + early_wakeup: /* Clear SLEEP mode set in INFORM1 */ @@ -383,7 +387,9 @@ static int exynos_suspend_enter(suspend_state_t state) flush_cache_all(); s3c_pm_check_store(); - ret = cpu_suspend(0, pm_data->cpu_suspend); + ret = call_firmware_op(suspend); + if (ret == -ENOSYS) + ret = cpu_suspend(0, pm_data->cpu_suspend); if (ret) return ret; diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S index 108a45f4bb62..e3c373082bbe 100644 --- a/arch/arm/mach-exynos/sleep.S +++ b/arch/arm/mach-exynos/sleep.S @@ -16,6 +16,7 @@ */ #include +#include "smc.h" #define CPU_MASK 0xff0ffff0 #define CPU_CORTEX_A9 0x410fc090 @@ -55,3 +56,30 @@ ENTRY(exynos_cpu_resume) #endif b cpu_resume ENDPROC(exynos_cpu_resume) + + .align + +ENTRY(exynos_cpu_resume_ns) + mrc p15, 0, r0, c0, c0, 0 + ldr r1, =CPU_MASK + and r0, r0, r1 + ldr r1, =CPU_CORTEX_A9 + cmp r0, r1 + bne skip_cp15 + + adr r0, cp15_save_power + ldr r1, [r0] + adr r0, cp15_save_diag + ldr r2, [r0] + mov r0, #SMC_CMD_C15RESUME + dsb + smc #0 +skip_cp15: + b cpu_resume +ENDPROC(exynos_cpu_resume_ns) + .globl cp15_save_diag +cp15_save_diag: + .long 0 @ cp15 diagnostic + .globl cp15_save_power +cp15_save_power: + .long 0 @ cp15 power control diff --git a/arch/arm/mach-exynos/smc.h b/arch/arm/mach-exynos/smc.h index 13a1dc8ecbf2..f7b82f9c1e21 100644 --- a/arch/arm/mach-exynos/smc.h +++ b/arch/arm/mach-exynos/smc.h @@ -26,6 +26,10 @@ #define SMC_CMD_L2X0INVALL (-24) #define SMC_CMD_L2X0DEBUG (-25) +#ifndef __ASSEMBLY__ + extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3); +#endif /* __ASSEMBLY__ */ + #endif -- cgit v1.2.3-59-g8ed1b From 134abc297e43438cdb47f30fc673680b16bc6339 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 25 Sep 2014 17:59:40 +0900 Subject: ARM: EXYNOS: replace EXYNOS_BOOT_VECTOR_* macros by static inlines Replace EXYNOS_BOOT_VECTOR_ADDR and EXYNOS_BOOT_VECTOR_FLAG macros by exynos_boot_vector_addr() and exynos_boot_vector_flag() static inlines. This patch shouldn't cause any functionality changes. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Kyungmin Park Acked-by: Daniel Lezcano Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pm.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 047ac302835d..3407fc162449 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -128,16 +128,23 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) return -ENOENT; } -#define EXYNOS_BOOT_VECTOR_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ - pmu_base_addr + S5P_INFORM7 : \ - (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (sysram_base_addr + 0x24) : \ - pmu_base_addr + S5P_INFORM0)) -#define EXYNOS_BOOT_VECTOR_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ - pmu_base_addr + S5P_INFORM6 : \ - (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (sysram_base_addr + 0x20) : \ - pmu_base_addr + S5P_INFORM1)) +static inline void __iomem *exynos_boot_vector_addr(void) +{ + if (samsung_rev() == EXYNOS4210_REV_1_1) + return pmu_base_addr + S5P_INFORM7; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return sysram_base_addr + 0x24; + return pmu_base_addr + S5P_INFORM0; +} + +static inline void __iomem *exynos_boot_vector_flag(void) +{ + if (samsung_rev() == EXYNOS4210_REV_1_1) + return pmu_base_addr + S5P_INFORM6; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return sysram_base_addr + 0x20; + return pmu_base_addr + S5P_INFORM1; +} #define S5P_CHECK_AFTR 0xFCBA0D10 #define S5P_CHECK_SLEEP 0x00000BAD @@ -222,8 +229,9 @@ static void exynos_set_wakeupmask(long mask) static void exynos_cpu_set_boot_vector(long flags) { - __raw_writel(virt_to_phys(exynos_cpu_resume), EXYNOS_BOOT_VECTOR_ADDR); - __raw_writel(flags, EXYNOS_BOOT_VECTOR_FLAG); + __raw_writel(virt_to_phys(exynos_cpu_resume), + exynos_boot_vector_addr()); + __raw_writel(flags, exynos_boot_vector_flag()); } static int exynos_aftr_finisher(unsigned long flags) -- cgit v1.2.3-59-g8ed1b From 0b7778a801fde0eacd5ee08242290273507e60a2 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 25 Sep 2014 17:59:41 +0900 Subject: ARM: firmware: add AFTR mode support to firmware do_idle method On some platforms (i.e. EXYNOS ones) more than one idle mode is available and we need to distinguish them in firmware do_idle method. Add mode parameter to do_idle firmware method and AFTR mode support to EXYNOS do_idle implementation. This change is a preparation for adding secure firmware support to EXYNOS cpuidle driver. This patch shouldn't cause any functionality changes. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Kyungmin Park Acked-by: Thierry Reding Signed-off-by: Kukjin Kim --- arch/arm/include/asm/firmware.h | 2 +- arch/arm/mach-exynos/common.h | 5 +++++ arch/arm/mach-exynos/firmware.c | 10 ++++++++-- arch/arm/mach-tegra/cpuidle-tegra114.c | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 5904f59b0409..89aefe10d66b 100644 --- a/arch/arm/include/asm/firmware.h +++ b/arch/arm/include/asm/firmware.h @@ -28,7 +28,7 @@ struct firmware_ops { /* * Enters CPU idle mode */ - int (*do_idle)(void); + int (*do_idle)(unsigned long mode); /* * Sets boot address of specified physical CPU */ diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index c218200f8544..2d830df0f647 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -119,6 +119,11 @@ extern void __iomem *sysram_base_addr; extern void __iomem *pmu_base_addr; void exynos_sysram_init(void); +enum { + FW_DO_IDLE_SLEEP, + FW_DO_IDLE_AFTR, +}; + void exynos_firmware_init(void); extern u32 exynos_get_eint_wake_mask(void); diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index f5e626d55951..e57b7c3039a2 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -28,9 +28,15 @@ #define EXYNOS_BOOT_ADDR 0x8 #define EXYNOS_BOOT_FLAG 0xc -static int exynos_do_idle(void) +static int exynos_do_idle(unsigned long mode) { - exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + switch (mode) { + case FW_DO_IDLE_AFTR: + exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0); + break; + case FW_DO_IDLE_SLEEP: + exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + } return 0; } diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index e3ebdce3e71f..425b6c8f0cb0 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, call_firmware_op(prepare_idle); /* Do suspend by ourselves if the firmware does not implement it */ - if (call_firmware_op(do_idle) == -ENOSYS) + if (call_firmware_op(do_idle, 0) == -ENOSYS) cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); -- cgit v1.2.3-59-g8ed1b From a135e20185fe6f0258fa6837455043f3063601d8 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 25 Sep 2014 17:59:41 +0900 Subject: ARM: EXYNOS: add secure firmware support to AFTR mode code * Move cp15 registers saving to exynos_save_cp15() helper and add additional helper usage to do_idle firmware method. * Use resume firmware method instead of exynos_cpu_restore_register() and skip exynos_cpu_save_register() on boards with secure firmware enabled. * Use sysram_ns_base_addr + 0x24/0x20 addresses instead of the default ones used by exynos_cpu_set_boot_vector() on boards with secure firmware enabled. * Use do_idle firmware method instead of cpu_do_idle() on boards with secure firmware enabled. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/firmware.c | 24 +++++++++++++++++------- arch/arm/mach-exynos/pm.c | 17 ++++++++++++----- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index e57b7c3039a2..2c5bc6bfcbdf 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -25,13 +25,28 @@ #include "smc.h" #define EXYNOS_SLEEP_MAGIC 0x00000bad +#define EXYNOS_AFTR_MAGIC 0xfcba0d10 #define EXYNOS_BOOT_ADDR 0x8 #define EXYNOS_BOOT_FLAG 0xc +static void exynos_save_cp15(void) +{ + /* Save Power control and Diagnostic registers */ + asm ("mrc p15, 0, %0, c15, c0, 0\n" + "mrc p15, 0, %1, c15, c0, 1\n" + : "=r" (cp15_save_power), "=r" (cp15_save_diag) + : : "cc"); +} + static int exynos_do_idle(unsigned long mode) { switch (mode) { case FW_DO_IDLE_AFTR: + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_save_cp15(); + __raw_writel(virt_to_phys(exynos_cpu_resume_ns), + sysram_ns_base_addr + 0x24); + __raw_writel(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20); exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0); break; case FW_DO_IDLE_SLEEP: @@ -96,13 +111,8 @@ static int exynos_cpu_suspend(unsigned long arg) static int exynos_suspend(void) { - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { - /* Save Power control and Diagnostic registers */ - asm ("mrc p15, 0, %0, c15, c0, 0\n" - "mrc p15, 0, %1, c15, c0, 1\n" - : "=r" (cp15_save_power), "=r" (cp15_save_diag) - : : "cc"); - } + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_save_cp15(); writel(EXYNOS_SLEEP_MAGIC, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); writel(virt_to_phys(exynos_cpu_resume_ns), diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 3407fc162449..6796fce923e2 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -236,11 +236,19 @@ static void exynos_cpu_set_boot_vector(long flags) static int exynos_aftr_finisher(unsigned long flags) { + int ret; + exynos_set_wakeupmask(0x0000ff3e); - exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); /* Set value of power down register for aftr mode */ exynos_sys_powerdown_conf(SYS_AFTR); - cpu_do_idle(); + + ret = call_firmware_op(do_idle, FW_DO_IDLE_AFTR); + if (ret == -ENOSYS) { + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_save_register(); + exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); + cpu_do_idle(); + } return 1; } @@ -250,14 +258,13 @@ void exynos_enter_aftr(void) cpu_pm_enter(); exynos_pm_central_suspend(); - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_save_register(); cpu_suspend(0, exynos_aftr_finisher); if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { scu_enable(S5P_VA_SCU); - exynos_cpu_restore_register(); + if (call_firmware_op(resume) == -ENOSYS) + exynos_cpu_restore_register(); } exynos_pm_central_resume(); -- cgit v1.2.3-59-g8ed1b From c2dd114d24865662a6d7381b101741fc898a0059 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 25 Sep 2014 17:59:41 +0900 Subject: ARM: EXYNOS: fix register setup for AFTR mode code Add S5P_CENTRAL_SEQ_OPTION register setup to cpuidle AFTR mode code by moving the relevant code from exynos_pm_suspend() (used only by suspend) to exynos_pm_central_suspend() (used by both suspend and AFTR). Without this setup AFTR mode doesn't show any benefit over WFI one (at least on Exynos4412 SoC). When this setup is applied AFTR mode reduces power consumption by ~12% (as measured on Trats2 board). This change is a preparation for adding secure firmware support to EXYNOS cpuidle driver. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pm.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 6796fce923e2..16c5c3206f14 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -196,6 +196,10 @@ static void exynos_pm_central_suspend(void) tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); tmp &= ~S5P_CENTRAL_LOWPWR_CFG; pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); + + /* Setting SEQ_OPTION register */ + pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0, + S5P_CENTRAL_SEQ_OPTION); } static int exynos_pm_central_resume(void) @@ -321,15 +325,8 @@ static void exynos_pm_prepare(void) static int exynos_pm_suspend(void) { - unsigned long tmp; - exynos_pm_central_suspend(); - /* Setting SEQ_OPTION register */ - - tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); - pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) exynos_cpu_save_register(); -- cgit v1.2.3-59-g8ed1b From 42d5dc37866610448453859bf2c4be57fce3834c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 25 Sep 2014 17:59:41 +0900 Subject: ARM: EXYNOS: allow driver usage on Exynos4x12 SoCs Register cpuidle platform device on Exynos4x12 SoCs allowing EXYNOS cpuidle driver usage on these SoCs. AFTR mode reduces power consumption on Trats2 board (Exynos4412 SoC with secure firmware enabled) by ~12% when EXYNOS cpuidle driver is enabled (in both cases the default exynos_defconfig config is used and CPU1-3 are offlined). Currently Exynos4412 SoC support is limited to Trats2 board. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/exynos.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 6b283eb3202e..a487e59555da 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -318,7 +318,10 @@ static void __init exynos_dt_machine_init(void) exynos_sysram_init(); if (of_machine_is_compatible("samsung,exynos4210") || - of_machine_is_compatible("samsung,exynos5250")) + of_machine_is_compatible("samsung,exynos4212") || + (of_machine_is_compatible("samsung,exynos4412") && + of_machine_is_compatible("samsung,trats2")) || + of_machine_is_compatible("samsung,exynos5250")) platform_device_register(&exynos_cpuidle); platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); -- cgit v1.2.3-59-g8ed1b From 0d713cf1a6286aae6a12affab0887dbe2a4fbb83 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 25 Sep 2014 18:02:45 +0900 Subject: ARM: EXYNOS: Fix build with PM_SLEEP=n and ARM_EXYNOS_CPUIDLE=y Fix building of exynos_defconfig with CONFIG_PM_SLEEP disabled and CONFIG_ARM_EXYNOS_CPUIDLE enabled by: * adding EXYNOS_CPU_SUSPEND config option * always building sleep.o * building pm.o if EXYNOS_CPU_SUSPEND is enabled * moving suspend specific code from pm.c to suspend.c * enabling pm-common.o build also for EXYNOS_CPU_SUSPEND option [ Please note that there are no changes in the code moved from pm.c to suspend.c except making few functions non-static and cleaning up includes. ] Also while at it update Copyright dates. The build error messages: drivers/built-in.o: In function `exynos_enter_core0_aftr': /home/bzolnier/linux/drivers/cpuidle/cpuidle-exynos.c:36: undefined reference to `cpu_suspend' arch/arm/mach-exynos/built-in.o:(.data+0x74): undefined reference to `exynos_enter_aftr' make: *** [vmlinux] Error 1 This patch has been tested on Exynos4210 based Origen board. Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/Kconfig | 5 + arch/arm/mach-exynos/Makefile | 5 +- arch/arm/mach-exynos/common.h | 4 + arch/arm/mach-exynos/pm.c | 338 +------------------------------------- arch/arm/mach-exynos/suspend.c | 356 +++++++++++++++++++++++++++++++++++++++++ arch/arm/plat-samsung/Makefile | 1 + 6 files changed, 374 insertions(+), 335 deletions(-) create mode 100644 arch/arm/mach-exynos/suspend.c diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 2d0240f241b8..46f3c0d0d01f 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -123,4 +123,9 @@ config EXYNOS5420_MCPM This is needed to provide CPU and cluster power management on Exynos5420 implementing big.LITTLE. +config EXYNOS_CPU_SUSPEND + bool + select ARM_CPU_SUSPEND + default PM_SLEEP || ARM_EXYNOS_CPUIDLE + endif diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 45bef21a3b66..3d680f2a5520 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -9,9 +9,10 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree) # Core -obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o +obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o sleep.o -obj-$(CONFIG_PM_SLEEP) += pm.o sleep.o +obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o +obj-$(CONFIG_PM_SLEEP) += suspend.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 2d830df0f647..ef95cb1cc00a 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -164,6 +164,10 @@ extern int exynos_cpu_power_state(int cpu); extern void exynos_cluster_power_down(int cluster); extern void exynos_cluster_power_up(int cluster); extern int exynos_cluster_power_state(int cluster); +extern void exynos_cpu_save_register(void); +extern void exynos_cpu_restore_register(void); +extern void exynos_pm_central_suspend(void); +extern int exynos_pm_central_resume(void); extern void exynos_enter_aftr(void); extern void s5p_init_cpu(void __iomem *cpuid_addr); diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 16c5c3206f14..4f10fa6bfe10 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * * EXYNOS - Power Management support @@ -15,119 +15,20 @@ #include #include -#include #include #include -#include #include -#include -#include #include -#include #include #include #include -#include - -#include #include "common.h" #include "regs-pmu.h" #include "regs-sys.h" -#define REG_TABLE_END (-1U) - -/** - * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping - * @hwirq: Hardware IRQ signal of the GIC - * @mask: Mask in PMU wake-up mask register - */ -struct exynos_wkup_irq { - unsigned int hwirq; - u32 mask; -}; - -static struct sleep_save exynos5_sys_save[] = { - SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), -}; - -static struct sleep_save exynos_core_save[] = { - /* SROM side */ - SAVE_ITEM(S5P_SROM_BW), - SAVE_ITEM(S5P_SROM_BC0), - SAVE_ITEM(S5P_SROM_BC1), - SAVE_ITEM(S5P_SROM_BC2), - SAVE_ITEM(S5P_SROM_BC3), -}; - -struct exynos_pm_data { - const struct exynos_wkup_irq *wkup_irq; - struct sleep_save *extra_save; - int num_extra_save; - unsigned int wake_disable_mask; - unsigned int *release_ret_regs; - - void (*pm_prepare)(void); - void (*pm_resume)(void); - int (*pm_suspend)(void); - int (*cpu_suspend)(unsigned long); -}; - -struct exynos_pm_data *pm_data; - -/* - * GIC wake-up support - */ - -static u32 exynos_irqwake_intmask = 0xffffffff; - -static const struct exynos_wkup_irq exynos4_wkup_irq[] = { - { 76, BIT(1) }, /* RTC alarm */ - { 77, BIT(2) }, /* RTC tick */ - { /* sentinel */ }, -}; - -static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { - { 75, BIT(1) }, /* RTC alarm */ - { 76, BIT(2) }, /* RTC tick */ - { /* sentinel */ }, -}; - -unsigned int exynos_release_ret_regs[] = { - S5P_PAD_RET_MAUDIO_OPTION, - S5P_PAD_RET_GPIO_OPTION, - S5P_PAD_RET_UART_OPTION, - S5P_PAD_RET_MMCA_OPTION, - S5P_PAD_RET_MMCB_OPTION, - S5P_PAD_RET_EBIA_OPTION, - S5P_PAD_RET_EBIB_OPTION, - REG_TABLE_END, -}; - -static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) -{ - const struct exynos_wkup_irq *wkup_irq; - - if (!pm_data->wkup_irq) - return -ENOENT; - wkup_irq = pm_data->wkup_irq; - - while (wkup_irq->mask) { - if (wkup_irq->hwirq == data->hwirq) { - if (!state) - exynos_irqwake_intmask |= wkup_irq->mask; - else - exynos_irqwake_intmask &= ~wkup_irq->mask; - return 0; - } - ++wkup_irq; - } - - return -ENOENT; -} - static inline void __iomem *exynos_boot_vector_addr(void) { if (samsung_rev() == EXYNOS4210_REV_1_1) @@ -147,12 +48,11 @@ static inline void __iomem *exynos_boot_vector_flag(void) } #define S5P_CHECK_AFTR 0xFCBA0D10 -#define S5P_CHECK_SLEEP 0x00000BAD /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; -static void exynos_cpu_save_register(void) +void exynos_cpu_save_register(void) { unsigned long tmp; @@ -169,7 +69,7 @@ static void exynos_cpu_save_register(void) save_arm_register[1] = tmp; } -static void exynos_cpu_restore_register(void) +void exynos_cpu_restore_register(void) { unsigned long tmp; @@ -188,7 +88,7 @@ static void exynos_cpu_restore_register(void) : "cc"); } -static void exynos_pm_central_suspend(void) +void exynos_pm_central_suspend(void) { unsigned long tmp; @@ -202,7 +102,7 @@ static void exynos_pm_central_suspend(void) S5P_CENTRAL_SEQ_OPTION); } -static int exynos_pm_central_resume(void) +int exynos_pm_central_resume(void) { unsigned long tmp; @@ -275,231 +175,3 @@ void exynos_enter_aftr(void) cpu_pm_exit(); } - -static int exynos_cpu_do_idle(void) -{ - /* issue the standby signal into the pm unit. */ - cpu_do_idle(); - - pr_info("Failed to suspend the system\n"); - return 1; /* Aborting suspend */ -} - -static int exynos_cpu_suspend(unsigned long arg) -{ - flush_cache_all(); - outer_flush_all(); - return exynos_cpu_do_idle(); -} - -static void exynos_pm_set_wakeup_mask(void) -{ - /* Set wake-up mask registers */ - pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); - pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); -} - -static void exynos_pm_enter_sleep_mode(void) -{ - /* Set value of power down register for sleep mode */ - exynos_sys_powerdown_conf(SYS_SLEEP); - pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); - - /* ensure at least INFORM0 has the resume address */ - pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); -} - -static void exynos_pm_prepare(void) -{ - /* Set wake-up mask registers */ - exynos_pm_set_wakeup_mask(); - - s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - - if (pm_data->extra_save) - s3c_pm_do_save(pm_data->extra_save, - pm_data->num_extra_save); - - exynos_pm_enter_sleep_mode(); -} - -static int exynos_pm_suspend(void) -{ - exynos_pm_central_suspend(); - - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_save_register(); - - return 0; -} - -static void exynos_pm_release_retention(void) -{ - unsigned int i; - - for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++) - pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR, - pm_data->release_ret_regs[i]); -} - -static void exynos_pm_resume(void) -{ - u32 cpuid = read_cpuid_part(); - - if (exynos_pm_central_resume()) - goto early_wakeup; - - /* For release retention */ - exynos_pm_release_retention(); - - if (pm_data->extra_save) - s3c_pm_do_restore_core(pm_data->extra_save, - pm_data->num_extra_save); - - s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - - if (cpuid == ARM_CPU_PART_CORTEX_A9) - scu_enable(S5P_VA_SCU); - - if (call_firmware_op(resume) == -ENOSYS - && cpuid == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_restore_register(); - -early_wakeup: - - /* Clear SLEEP mode set in INFORM1 */ - pmu_raw_writel(0x0, S5P_INFORM1); -} - -/* - * Suspend Ops - */ - -static int exynos_suspend_enter(suspend_state_t state) -{ - int ret; - - s3c_pm_debug_init(); - - S3C_PMDBG("%s: suspending the system...\n", __func__); - - S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, - exynos_irqwake_intmask, exynos_get_eint_wake_mask()); - - if (exynos_irqwake_intmask == -1U - && exynos_get_eint_wake_mask() == -1U) { - pr_err("%s: No wake-up sources!\n", __func__); - pr_err("%s: Aborting sleep\n", __func__); - return -EINVAL; - } - - s3c_pm_save_uarts(); - if (pm_data->pm_prepare) - pm_data->pm_prepare(); - flush_cache_all(); - s3c_pm_check_store(); - - ret = call_firmware_op(suspend); - if (ret == -ENOSYS) - ret = cpu_suspend(0, pm_data->cpu_suspend); - if (ret) - return ret; - - s3c_pm_restore_uarts(); - - S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, - pmu_raw_readl(S5P_WAKEUP_STAT)); - - s3c_pm_check_restore(); - - S3C_PMDBG("%s: resuming the system...\n", __func__); - - return 0; -} - -static int exynos_suspend_prepare(void) -{ - s3c_pm_check_prepare(); - - return 0; -} - -static void exynos_suspend_finish(void) -{ - s3c_pm_check_cleanup(); -} - -static const struct platform_suspend_ops exynos_suspend_ops = { - .enter = exynos_suspend_enter, - .prepare = exynos_suspend_prepare, - .finish = exynos_suspend_finish, - .valid = suspend_valid_only_mem, -}; - -static const struct exynos_pm_data exynos4_pm_data = { - .wkup_irq = exynos4_wkup_irq, - .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), - .release_ret_regs = exynos_release_ret_regs, - .pm_suspend = exynos_pm_suspend, - .pm_resume = exynos_pm_resume, - .pm_prepare = exynos_pm_prepare, - .cpu_suspend = exynos_cpu_suspend, -}; - -static const struct exynos_pm_data exynos5250_pm_data = { - .wkup_irq = exynos5250_wkup_irq, - .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), - .release_ret_regs = exynos_release_ret_regs, - .extra_save = exynos5_sys_save, - .num_extra_save = ARRAY_SIZE(exynos5_sys_save), - .pm_suspend = exynos_pm_suspend, - .pm_resume = exynos_pm_resume, - .pm_prepare = exynos_pm_prepare, - .cpu_suspend = exynos_cpu_suspend, -}; - -static struct of_device_id exynos_pmu_of_device_ids[] = { - { - .compatible = "samsung,exynos4210-pmu", - .data = &exynos4_pm_data, - }, { - .compatible = "samsung,exynos4212-pmu", - .data = &exynos4_pm_data, - }, { - .compatible = "samsung,exynos4412-pmu", - .data = &exynos4_pm_data, - }, { - .compatible = "samsung,exynos5250-pmu", - .data = &exynos5250_pm_data, - }, - { /*sentinel*/ }, -}; - -static struct syscore_ops exynos_pm_syscore_ops; - -void __init exynos_pm_init(void) -{ - const struct of_device_id *match; - u32 tmp; - - of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); - if (!match) { - pr_err("Failed to find PMU node\n"); - return; - } - pm_data = (struct exynos_pm_data *) match->data; - - /* Platform-specific GIC callback */ - gic_arch_extn.irq_set_wake = exynos_irq_set_wake; - - /* All wakeup disable */ - tmp = pmu_raw_readl(S5P_WAKEUP_MASK); - tmp |= pm_data->wake_disable_mask; - pmu_raw_writel(tmp, S5P_WAKEUP_MASK); - - exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; - exynos_pm_syscore_ops.resume = pm_data->pm_resume; - - register_syscore_ops(&exynos_pm_syscore_ops); - suspend_set_ops(&exynos_suspend_ops); -} diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c new file mode 100644 index 000000000000..f5d9773066eb --- /dev/null +++ b/arch/arm/mach-exynos/suspend.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - Suspend support + * + * Based on arch/arm/mach-s3c2410/pm.c + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" +#include "regs-pmu.h" +#include "regs-sys.h" + +#define S5P_CHECK_SLEEP 0x00000BAD + +#define REG_TABLE_END (-1U) + +/** + * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping + * @hwirq: Hardware IRQ signal of the GIC + * @mask: Mask in PMU wake-up mask register + */ +struct exynos_wkup_irq { + unsigned int hwirq; + u32 mask; +}; + +static struct sleep_save exynos5_sys_save[] = { + SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), +}; + +static struct sleep_save exynos_core_save[] = { + /* SROM side */ + SAVE_ITEM(S5P_SROM_BW), + SAVE_ITEM(S5P_SROM_BC0), + SAVE_ITEM(S5P_SROM_BC1), + SAVE_ITEM(S5P_SROM_BC2), + SAVE_ITEM(S5P_SROM_BC3), +}; + +struct exynos_pm_data { + const struct exynos_wkup_irq *wkup_irq; + struct sleep_save *extra_save; + int num_extra_save; + unsigned int wake_disable_mask; + unsigned int *release_ret_regs; + + void (*pm_prepare)(void); + void (*pm_resume)(void); + int (*pm_suspend)(void); + int (*cpu_suspend)(unsigned long); +}; + +struct exynos_pm_data *pm_data; + +/* + * GIC wake-up support + */ + +static u32 exynos_irqwake_intmask = 0xffffffff; + +static const struct exynos_wkup_irq exynos4_wkup_irq[] = { + { 76, BIT(1) }, /* RTC alarm */ + { 77, BIT(2) }, /* RTC tick */ + { /* sentinel */ }, +}; + +static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { + { 75, BIT(1) }, /* RTC alarm */ + { 76, BIT(2) }, /* RTC tick */ + { /* sentinel */ }, +}; + +unsigned int exynos_release_ret_regs[] = { + S5P_PAD_RET_MAUDIO_OPTION, + S5P_PAD_RET_GPIO_OPTION, + S5P_PAD_RET_UART_OPTION, + S5P_PAD_RET_MMCA_OPTION, + S5P_PAD_RET_MMCB_OPTION, + S5P_PAD_RET_EBIA_OPTION, + S5P_PAD_RET_EBIB_OPTION, + REG_TABLE_END, +}; + +static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) +{ + const struct exynos_wkup_irq *wkup_irq; + + if (!pm_data->wkup_irq) + return -ENOENT; + wkup_irq = pm_data->wkup_irq; + + while (wkup_irq->mask) { + if (wkup_irq->hwirq == data->hwirq) { + if (!state) + exynos_irqwake_intmask |= wkup_irq->mask; + else + exynos_irqwake_intmask &= ~wkup_irq->mask; + return 0; + } + ++wkup_irq; + } + + return -ENOENT; +} + +static int exynos_cpu_do_idle(void) +{ + /* issue the standby signal into the pm unit. */ + cpu_do_idle(); + + pr_info("Failed to suspend the system\n"); + return 1; /* Aborting suspend */ +} + +static int exynos_cpu_suspend(unsigned long arg) +{ + flush_cache_all(); + outer_flush_all(); + return exynos_cpu_do_idle(); +} + +static void exynos_pm_set_wakeup_mask(void) +{ + /* Set wake-up mask registers */ + pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); + pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); +} + +static void exynos_pm_enter_sleep_mode(void) +{ + /* Set value of power down register for sleep mode */ + exynos_sys_powerdown_conf(SYS_SLEEP); + pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); + + /* ensure at least INFORM0 has the resume address */ + pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); +} + +static void exynos_pm_prepare(void) +{ + /* Set wake-up mask registers */ + exynos_pm_set_wakeup_mask(); + + s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + + if (pm_data->extra_save) + s3c_pm_do_save(pm_data->extra_save, + pm_data->num_extra_save); + + exynos_pm_enter_sleep_mode(); +} + +static int exynos_pm_suspend(void) +{ + exynos_pm_central_suspend(); + + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_save_register(); + + return 0; +} + +static void exynos_pm_release_retention(void) +{ + unsigned int i; + + for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++) + pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR, + pm_data->release_ret_regs[i]); +} + +static void exynos_pm_resume(void) +{ + u32 cpuid = read_cpuid_part(); + + if (exynos_pm_central_resume()) + goto early_wakeup; + + /* For release retention */ + exynos_pm_release_retention(); + + if (pm_data->extra_save) + s3c_pm_do_restore_core(pm_data->extra_save, + pm_data->num_extra_save); + + s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + + if (cpuid == ARM_CPU_PART_CORTEX_A9) + scu_enable(S5P_VA_SCU); + + if (call_firmware_op(resume) == -ENOSYS + && cpuid == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_restore_register(); + +early_wakeup: + + /* Clear SLEEP mode set in INFORM1 */ + pmu_raw_writel(0x0, S5P_INFORM1); +} + +/* + * Suspend Ops + */ + +static int exynos_suspend_enter(suspend_state_t state) +{ + int ret; + + s3c_pm_debug_init(); + + S3C_PMDBG("%s: suspending the system...\n", __func__); + + S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, + exynos_irqwake_intmask, exynos_get_eint_wake_mask()); + + if (exynos_irqwake_intmask == -1U + && exynos_get_eint_wake_mask() == -1U) { + pr_err("%s: No wake-up sources!\n", __func__); + pr_err("%s: Aborting sleep\n", __func__); + return -EINVAL; + } + + s3c_pm_save_uarts(); + if (pm_data->pm_prepare) + pm_data->pm_prepare(); + flush_cache_all(); + s3c_pm_check_store(); + + ret = call_firmware_op(suspend); + if (ret == -ENOSYS) + ret = cpu_suspend(0, pm_data->cpu_suspend); + if (ret) + return ret; + + s3c_pm_restore_uarts(); + + S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, + pmu_raw_readl(S5P_WAKEUP_STAT)); + + s3c_pm_check_restore(); + + S3C_PMDBG("%s: resuming the system...\n", __func__); + + return 0; +} + +static int exynos_suspend_prepare(void) +{ + s3c_pm_check_prepare(); + + return 0; +} + +static void exynos_suspend_finish(void) +{ + s3c_pm_check_cleanup(); +} + +static const struct platform_suspend_ops exynos_suspend_ops = { + .enter = exynos_suspend_enter, + .prepare = exynos_suspend_prepare, + .finish = exynos_suspend_finish, + .valid = suspend_valid_only_mem, +}; + +static const struct exynos_pm_data exynos4_pm_data = { + .wkup_irq = exynos4_wkup_irq, + .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), + .release_ret_regs = exynos_release_ret_regs, + .pm_suspend = exynos_pm_suspend, + .pm_resume = exynos_pm_resume, + .pm_prepare = exynos_pm_prepare, + .cpu_suspend = exynos_cpu_suspend, +}; + +static const struct exynos_pm_data exynos5250_pm_data = { + .wkup_irq = exynos5250_wkup_irq, + .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), + .release_ret_regs = exynos_release_ret_regs, + .extra_save = exynos5_sys_save, + .num_extra_save = ARRAY_SIZE(exynos5_sys_save), + .pm_suspend = exynos_pm_suspend, + .pm_resume = exynos_pm_resume, + .pm_prepare = exynos_pm_prepare, + .cpu_suspend = exynos_cpu_suspend, +}; + +static struct of_device_id exynos_pmu_of_device_ids[] = { + { + .compatible = "samsung,exynos4210-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos4212-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos4412-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos5250-pmu", + .data = &exynos5250_pm_data, + }, + { /*sentinel*/ }, +}; + +static struct syscore_ops exynos_pm_syscore_ops; + +void __init exynos_pm_init(void) +{ + const struct of_device_id *match; + u32 tmp; + + of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); + if (!match) { + pr_err("Failed to find PMU node\n"); + return; + } + pm_data = (struct exynos_pm_data *) match->data; + + /* Platform-specific GIC callback */ + gic_arch_extn.irq_set_wake = exynos_irq_set_wake; + + /* All wakeup disable */ + tmp = pmu_raw_readl(S5P_WAKEUP_MASK); + tmp |= pm_data->wake_disable_mask; + pmu_raw_writel(tmp, S5P_WAKEUP_MASK); + + exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; + exynos_pm_syscore_ops.resume = pm_data->pm_resume; + + register_syscore_ops(&exynos_pm_syscore_ops); + suspend_set_ops(&exynos_suspend_ops); +} diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index f0a008496993..87746c37f030 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o # PM support obj-$(CONFIG_PM_SLEEP) += pm-common.o +obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm-common.o obj-$(CONFIG_SAMSUNG_PM) += pm.o obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o -- cgit v1.2.3-59-g8ed1b From b588aaec6d0d846c88bfa2ba95e76147386a4cd6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 25 Sep 2014 18:15:13 +0900 Subject: ARM: EXYNOS: SWRESET is needed to boot secondary CPU on exynos3250 Without software reset the secondary CPU does not power up and exynos_boot_secondary() ends with pen_release equal to 1. This can be observed in dmesg: CPU1: failed to come online Brought up 1 CPUs SMP: Total of 1 processors activated. CPU: All CPU(s) started in SVC mode. When booting the secondary CPU on Exynos3250 execute also software reset for core 1. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/platsmp.c | 23 +++++++++++++++++++++++ arch/arm/mach-exynos/regs-pmu.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 41ae28d69e6f..8543064dc445 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -120,6 +120,26 @@ static inline void __iomem *cpu_boot_reg(int cpu) return boot_reg; } +/* + * Set wake up by local power mode and execute software reset for given core. + * + * Currently this is needed only when booting secondary CPU on Exynos3250. + */ +static void exynos_core_restart(u32 core_id) +{ + u32 val; + + if (!of_machine_is_compatible("samsung,exynos3250")) + return; + + val = pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(core_id)); + val |= S5P_CORE_WAKEUP_FROM_LOCAL_CFG; + pmu_raw_writel(val, EXYNOS_ARM_CORE_STATUS(core_id)); + + pr_info("CPU%u: Software reset\n", core_id); + pmu_raw_writel(EXYNOS_CORE_PO_RESET(core_id), EXYNOS_SWRESET); +} + /* * Write pen_release in a way that is guaranteed to be visible to all * observers, irrespective of whether they're taking part in coherency @@ -196,6 +216,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) return -ETIMEDOUT; } } + + exynos_core_restart(core_id); + /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 30c03017aa6a..4ea5e320c6d1 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -21,6 +21,7 @@ #define S5P_USE_STANDBY_WFI0 (1 << 16) #define S5P_USE_STANDBY_WFE0 (1 << 24) +#define EXYNOS_CORE_PO_RESET(n) ((1 << 4) << n) #define EXYNOS_WAKEUP_FROM_LOWPWR (1 << 28) #define EXYNOS_SWRESET 0x0400 #define EXYNOS5440_SWRESET 0x00C4 @@ -125,6 +126,7 @@ #define S5P_PAD_RET_EBIB_OPTION 0x31A8 #define S5P_CORE_LOCAL_PWR_EN 0x3 +#define S5P_CORE_WAKEUP_FROM_LOCAL_CFG (0x3 << 8) /* Only for EXYNOS4210 */ #define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154 -- cgit v1.2.3-59-g8ed1b From 81b43a6e2d072126df5eb016524819f6921262f3 Mon Sep 17 00:00:00 2001 From: Marc Carino Date: Wed, 13 Aug 2014 15:50:02 -0700 Subject: ARM: brcmstb: add debug UART for earlyprintk support Add the UART definitions needed to support earlyprintk on brcmstb machines. Signed-off-by: Marc Carino Acked-by: Florian Fainelli Acked-by: Arnd Bergmann Signed-off-by: Brian Norris Signed-off-by: Florian Fainelli --- arch/arm/Kconfig.debug | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 03dc4c1a8736..6a4ee008b092 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -139,6 +139,17 @@ choice Say Y here if you want kernel low-level debugging support on Marvell Berlin SoC based platforms. + config DEBUG_BRCMSTB_UART + bool "Use BRCMSTB UART for low-level debug" + depends on ARCH_BRCMSTB + select DEBUG_UART_8250 + help + Say Y here if you want the debug print routines to direct + their output to the first serial port on these devices. + + If you have a Broadcom STB chip and would like early print + messages to appear over the UART, select this option. + config DEBUG_CLPS711X_UART1 bool "Kernel low-level debugging messages via UART1" depends on ARCH_CLPS711X @@ -1153,6 +1164,7 @@ config DEBUG_UART_PHYS default 0xe0000000 if ARCH_SPEAR13XX default 0xe4007000 if DEBUG_HIP04_UART default 0xf0000be0 if ARCH_EBSA110 + default 0xf040ab00 if DEBUG_BRCMSTB_UART default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE default 0xf1012000 if ARCH_DOVE || ARCH_MV78XX0 || \ ARCH_ORION5X @@ -1204,6 +1216,7 @@ config DEBUG_UART_VIRT default 0xfb002000 if DEBUG_CNS3XXX default 0xfb009000 if DEBUG_REALVIEW_STD_PORT default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT + default 0xfc40ab00 if DEBUG_BRCMSTB_UART default 0xfcfe8600 if DEBUG_UART_BCM63XX default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX default 0xfd000000 if ARCH_SPEAR13XX @@ -1260,7 +1273,8 @@ config DEBUG_UART_8250_WORD ARCH_KEYSTONE || \ DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \ DEBUG_DAVINCI_DA8XX_UART2 || \ - DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 + DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 || \ + DEBUG_BRCMSTB_UART config DEBUG_UART_8250_FLOW_CONTROL bool "Enable flow control for 8250 UART" -- cgit v1.2.3-59-g8ed1b From 62639c2f5332a0f25b11806ddcfe1d95d3d635fb Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 5 Sep 2014 16:31:04 -0700 Subject: ARM: brcmstb: reintroduce SMP support Support for SMP bringup of the B15 CPUs on Broadcom STB chips was added in commit 4fbe66d9903425156c193ae44c81c0f7557755c4 but was reverted in commit fc3e825fa91636a5d1b992e769b2d8279877bfad to address some late review comments. This reintroduces SMP support. Signed-off-by: Marc Carino Signed-off-by: Brian Norris Signed-off-by: Florian Fainelli --- arch/arm/mach-bcm/Makefile | 2 + arch/arm/mach-bcm/brcmstb.h | 19 +++ arch/arm/mach-bcm/headsmp-brcmstb.S | 33 ++++ arch/arm/mach-bcm/platsmp-brcmstb.c | 329 ++++++++++++++++++++++++++++++++++++ 4 files changed, 383 insertions(+) create mode 100644 arch/arm/mach-bcm/brcmstb.h create mode 100644 arch/arm/mach-bcm/headsmp-brcmstb.S create mode 100644 arch/arm/mach-bcm/platsmp-brcmstb.c diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 300ae4b79ae6..6710ea321220 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -38,5 +38,7 @@ obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o ifeq ($(CONFIG_ARCH_BRCMSTB),y) +CFLAGS_platsmp-brcmstb.o += -march=armv7-a obj-y += brcmstb.o +obj-$(CONFIG_SMP) += headsmp-brcmstb.o platsmp-brcmstb.o endif diff --git a/arch/arm/mach-bcm/brcmstb.h b/arch/arm/mach-bcm/brcmstb.h new file mode 100644 index 000000000000..ec0c3d112b36 --- /dev/null +++ b/arch/arm/mach-bcm/brcmstb.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2013-2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __BRCMSTB_H__ +#define __BRCMSTB_H__ + +void brcmstb_secondary_startup(void); + +#endif /* __BRCMSTB_H__ */ diff --git a/arch/arm/mach-bcm/headsmp-brcmstb.S b/arch/arm/mach-bcm/headsmp-brcmstb.S new file mode 100644 index 000000000000..199c1ea58248 --- /dev/null +++ b/arch/arm/mach-bcm/headsmp-brcmstb.S @@ -0,0 +1,33 @@ +/* + * SMP boot code for secondary CPUs + * Based on arch/arm/mach-tegra/headsmp.S + * + * Copyright (C) 2010 NVIDIA, Inc. + * Copyright (C) 2013-2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + + .section ".text.head", "ax" + +ENTRY(brcmstb_secondary_startup) + /* + * Ensure CPU is in a sane state by disabling all IRQs and switching + * into SVC mode. + */ + setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r0 + + bl v7_invalidate_l1 + b secondary_startup +ENDPROC(brcmstb_secondary_startup) diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c new file mode 100644 index 000000000000..31c87a284a34 --- /dev/null +++ b/arch/arm/mach-bcm/platsmp-brcmstb.c @@ -0,0 +1,329 @@ +/* + * Broadcom STB CPU SMP and hotplug support for ARM + * + * Copyright (C) 2013-2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "brcmstb.h" + +enum { + ZONE_MAN_CLKEN_MASK = BIT(0), + ZONE_MAN_RESET_CNTL_MASK = BIT(1), + ZONE_MAN_MEM_PWR_MASK = BIT(4), + ZONE_RESERVED_1_MASK = BIT(5), + ZONE_MAN_ISO_CNTL_MASK = BIT(6), + ZONE_MANUAL_CONTROL_MASK = BIT(7), + ZONE_PWR_DN_REQ_MASK = BIT(9), + ZONE_PWR_UP_REQ_MASK = BIT(10), + ZONE_BLK_RST_ASSERT_MASK = BIT(12), + ZONE_PWR_OFF_STATE_MASK = BIT(25), + ZONE_PWR_ON_STATE_MASK = BIT(26), + ZONE_DPG_PWR_STATE_MASK = BIT(28), + ZONE_MEM_PWR_STATE_MASK = BIT(29), + ZONE_RESET_STATE_MASK = BIT(31), + CPU0_PWR_ZONE_CTRL_REG = 1, + CPU_RESET_CONFIG_REG = 2, +}; + +static void __iomem *cpubiuctrl_block; +static void __iomem *hif_cont_block; +static u32 cpu0_pwr_zone_ctrl_reg; +static u32 cpu_rst_cfg_reg; +static u32 hif_cont_reg; + +#ifdef CONFIG_HOTPLUG_CPU +/* + * We must quiesce a dying CPU before it can be killed by the boot CPU. Because + * one or more cache may be disabled, we must flush to ensure coherency. We + * cannot use traditionl completion structures or spinlocks as they rely on + * coherency. + */ +static DEFINE_PER_CPU_ALIGNED(int, per_cpu_sw_state); + +static int per_cpu_sw_state_rd(u32 cpu) +{ + sync_cache_r(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu))); + return per_cpu(per_cpu_sw_state, cpu); +} + +static void per_cpu_sw_state_wr(u32 cpu, int val) +{ + dmb(); + per_cpu(per_cpu_sw_state, cpu) = val; + sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu))); +} +#else +static inline void per_cpu_sw_state_wr(u32 cpu, int val) { } +#endif + +static void __iomem *pwr_ctrl_get_base(u32 cpu) +{ + void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg; + base += (cpu_logical_map(cpu) * 4); + return base; +} + +static u32 pwr_ctrl_rd(u32 cpu) +{ + void __iomem *base = pwr_ctrl_get_base(cpu); + return readl_relaxed(base); +} + +static void pwr_ctrl_wr(u32 cpu, u32 val) +{ + void __iomem *base = pwr_ctrl_get_base(cpu); + writel(val, base); +} + +static void cpu_rst_cfg_set(u32 cpu, int set) +{ + u32 val; + val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg); + if (set) + val |= BIT(cpu_logical_map(cpu)); + else + val &= ~BIT(cpu_logical_map(cpu)); + writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg); +} + +static void cpu_set_boot_addr(u32 cpu, unsigned long boot_addr) +{ + const int reg_ofs = cpu_logical_map(cpu) * 8; + writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs); + writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs); +} + +static void brcmstb_cpu_boot(u32 cpu) +{ + /* Mark this CPU as "up" */ + per_cpu_sw_state_wr(cpu, 1); + + /* + * Set the reset vector to point to the secondary_startup + * routine + */ + cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup)); + + /* Unhalt the cpu */ + cpu_rst_cfg_set(cpu, 0); +} + +static void brcmstb_cpu_power_on(u32 cpu) +{ + /* + * The secondary cores power was cut, so we must go through + * power-on initialization. + */ + u32 tmp; + + /* Request zone power up */ + pwr_ctrl_wr(cpu, ZONE_PWR_UP_REQ_MASK); + + /* Wait for the power up FSM to complete */ + do { + tmp = pwr_ctrl_rd(cpu); + } while (!(tmp & ZONE_PWR_ON_STATE_MASK)); +} + +static int brcmstb_cpu_get_power_state(u32 cpu) +{ + int tmp = pwr_ctrl_rd(cpu); + return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1; +} + +#ifdef CONFIG_HOTPLUG_CPU + +static void brcmstb_cpu_die(u32 cpu) +{ + v7_exit_coherency_flush(all); + + per_cpu_sw_state_wr(cpu, 0); + + /* Sit and wait to die */ + wfi(); + + /* We should never get here... */ + while (1) + ; +} + +static int brcmstb_cpu_kill(u32 cpu) +{ + u32 tmp; + + while (per_cpu_sw_state_rd(cpu)) + ; + + /* Program zone reset */ + pwr_ctrl_wr(cpu, ZONE_RESET_STATE_MASK | ZONE_BLK_RST_ASSERT_MASK | + ZONE_PWR_DN_REQ_MASK); + + /* Verify zone reset */ + tmp = pwr_ctrl_rd(cpu); + if (!(tmp & ZONE_RESET_STATE_MASK)) + pr_err("%s: Zone reset bit for CPU %d not asserted!\n", + __func__, cpu); + + /* Wait for power down */ + do { + tmp = pwr_ctrl_rd(cpu); + } while (!(tmp & ZONE_PWR_OFF_STATE_MASK)); + + /* Flush pipeline before resetting CPU */ + mb(); + + /* Assert reset on the CPU */ + cpu_rst_cfg_set(cpu, 1); + + return 1; +} + +#endif /* CONFIG_HOTPLUG_CPU */ + +static int __init setup_hifcpubiuctrl_regs(struct device_node *np) +{ + int rc = 0; + char *name; + struct device_node *syscon_np = NULL; + + name = "syscon-cpu"; + + syscon_np = of_parse_phandle(np, name, 0); + if (!syscon_np) { + pr_err("can't find phandle %s\n", name); + rc = -EINVAL; + goto cleanup; + } + + cpubiuctrl_block = of_iomap(syscon_np, 0); + if (!cpubiuctrl_block) { + pr_err("iomap failed for cpubiuctrl_block\n"); + rc = -EINVAL; + goto cleanup; + } + + rc = of_property_read_u32_index(np, name, CPU0_PWR_ZONE_CTRL_REG, + &cpu0_pwr_zone_ctrl_reg); + if (rc) { + pr_err("failed to read 1st entry from %s property (%d)\n", name, + rc); + rc = -EINVAL; + goto cleanup; + } + + rc = of_property_read_u32_index(np, name, CPU_RESET_CONFIG_REG, + &cpu_rst_cfg_reg); + if (rc) { + pr_err("failed to read 2nd entry from %s property (%d)\n", name, + rc); + rc = -EINVAL; + goto cleanup; + } + +cleanup: + of_node_put(syscon_np); + return rc; +} + +static int __init setup_hifcont_regs(struct device_node *np) +{ + int rc = 0; + char *name; + struct device_node *syscon_np = NULL; + + name = "syscon-cont"; + + syscon_np = of_parse_phandle(np, name, 0); + if (!syscon_np) { + pr_err("can't find phandle %s\n", name); + rc = -EINVAL; + goto cleanup; + } + + hif_cont_block = of_iomap(syscon_np, 0); + if (!hif_cont_block) { + pr_err("iomap failed for hif_cont_block\n"); + rc = -EINVAL; + goto cleanup; + } + + /* Offset is at top of hif_cont_block */ + hif_cont_reg = 0; + +cleanup: + of_node_put(syscon_np); + return rc; +} + +static void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus) +{ + int rc; + struct device_node *np; + char *name; + + name = "brcm,brcmstb-smpboot"; + np = of_find_compatible_node(NULL, NULL, name); + if (!np) { + pr_err("can't find compatible node %s\n", name); + return; + } + + rc = setup_hifcpubiuctrl_regs(np); + if (rc) + return; + + rc = setup_hifcont_regs(np); + if (rc) + return; +} + +static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + /* Missing the brcm,brcmstb-smpboot DT node? */ + if (!cpubiuctrl_block || !hif_cont_block) + return -ENODEV; + + /* Bring up power to the core if necessary */ + if (brcmstb_cpu_get_power_state(cpu) == 0) + brcmstb_cpu_power_on(cpu); + + brcmstb_cpu_boot(cpu); + + return 0; +} + +static struct smp_operations brcmstb_smp_ops __initdata = { + .smp_prepare_cpus = brcmstb_cpu_ctrl_setup, + .smp_boot_secondary = brcmstb_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_kill = brcmstb_cpu_kill, + .cpu_die = brcmstb_cpu_die, +#endif +}; + +CPU_METHOD_OF_DECLARE(brcmstb_smp, "brcm,brahma-b15", &brcmstb_smp_ops); -- cgit v1.2.3-59-g8ed1b From 1aaaad3ffaec839929cc69992f419d656e18dc55 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 5 Sep 2014 16:25:37 -0700 Subject: ARM: brcmstb: Kconfig: drop unneeded symbol selections These are either implied or not necessary. Signed-off-by: Brian Norris Signed-off-by: Florian Fainelli --- arch/arm/mach-bcm/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 2abad742516d..9625dddb5cd3 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -118,10 +118,7 @@ config ARCH_BCM_63XX config ARCH_BRCMSTB bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7 - depends on MMU select ARM_GIC - select MIGHT_HAVE_PCI - select HAVE_SMP select HAVE_ARM_ARCH_TIMER select BRCMSTB_GISB_ARB select BRCMSTB_L2_IRQ -- cgit v1.2.3-59-g8ed1b From f1bee783dd37d088a8a7924205476ba1cf675378 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 18 Sep 2014 12:32:10 -0700 Subject: bus: brcmstb_gisb: register the fault code hook Commit 44127b771d9c31 ("bus: add Broadcom GISB bus arbiter timeout/error handler") added everything that is required to register an ARM fault handler for imprecise external aborts, except that there is nothing calling this currently. We do not need to export that specific function and have to update arch/arm/mach-bcm/brcmstb.c to call it, simply, register the fault handler during the probe() function of the driver. Signed-off-by: Florian Fainelli --- drivers/bus/brcmstb_gisb.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index f2cd6a2d40b4..41b09418f515 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -160,12 +160,6 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr, return ret; } -void __init brcmstb_hook_fault_code(void) -{ - hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0, - "imprecise external abort"); -} - static irqreturn_t brcmstb_gisb_timeout_handler(int irq, void *dev_id) { brcmstb_gisb_arb_decode_addr(dev_id, "timeout"); @@ -261,6 +255,9 @@ static int brcmstb_gisb_arb_probe(struct platform_device *pdev) list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list); + hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0, + "imprecise external abort"); + dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n", gdev->base, timeout_irq, tea_irq); -- cgit v1.2.3-59-g8ed1b From 203bb85ed605e43eadca62afb3a8cd128a8ec10a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 18 Sep 2014 12:37:14 -0700 Subject: bus: brcmstb_gisb: save and restore GISB timeout When the system enters S3, we will lose the GISB timeout value we have configured, make sure that we do save this timeout value, and restore this timeout value prior to re-enabling interrupts such that the GISB timeout interrupt will fire with the expected timeout. Signed-off-by: Florian Fainelli --- drivers/bus/brcmstb_gisb.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index 41b09418f515..e7ccd21a45c9 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ struct brcmstb_gisb_arb_device { struct list_head next; u32 valid_mask; const char *master_names[sizeof(u32) * BITS_PER_BYTE]; + u32 saved_timeout; }; static LIST_HEAD(brcmstb_gisb_arb_device_list); @@ -264,6 +266,39 @@ static int brcmstb_gisb_arb_probe(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int brcmstb_gisb_arb_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + + gdev->saved_timeout = ioread32(gdev->base + ARB_TIMER); + + return 0; +} + +/* Make sure we provide the same timeout value that was configured before, and + * do this before the GISB timeout interrupt handler has any chance to run. + */ +static int brcmstb_gisb_arb_resume_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + + iowrite32(gdev->saved_timeout, gdev->base + ARB_TIMER); + + return 0; +} +#else +#define brcmstb_gisb_arb_suspend NULL +#define brcmstb_gisb_arb_resume_noirq NULL +#endif + +static const struct dev_pm_ops brcmstb_gisb_arb_pm_ops = { + .suspend = brcmstb_gisb_arb_suspend, + .resume_noirq = brcmstb_gisb_arb_resume_noirq, +}; + static const struct of_device_id brcmstb_gisb_arb_of_match[] = { { .compatible = "brcm,gisb-arb" }, { }, @@ -275,6 +310,7 @@ static struct platform_driver brcmstb_gisb_arb_driver = { .name = "brcm-gisb-arb", .owner = THIS_MODULE, .of_match_table = brcmstb_gisb_arb_of_match, + .pm = &brcmstb_gisb_arb_pm_ops, }, }; -- cgit v1.2.3-59-g8ed1b From e9246c8726312aae36202b9e50c7e76a8609b712 Mon Sep 17 00:00:00 2001 From: Antoine Ténart Date: Wed, 3 Sep 2014 09:48:22 +0200 Subject: ARM: Berlin: select the reset controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Marvell Berlin SoCs now has a reset controller. Add the needed configuration. While at it reorder Kconfigs alphabetically. Signed-off-by: Antoine Ténart Signed-off-by: Sebastian Hesselbarth --- arch/arm/mach-berlin/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig index 24f85be71671..84d34e07209c 100644 --- a/arch/arm/mach-berlin/Kconfig +++ b/arch/arm/mach-berlin/Kconfig @@ -1,11 +1,13 @@ menuconfig ARCH_BERLIN bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 + select ARCH_HAS_RESET_CONTROLLER select ARCH_REQUIRE_GPIOLIB select ARM_GIC - select GENERIC_IRQ_CHIP select DW_APB_ICTL select DW_APB_TIMER_OF + select GENERIC_IRQ_CHIP select PINCTRL + select RESET_CONTROLLER if ARCH_BERLIN -- cgit v1.2.3-59-g8ed1b From 68f3b875f7848f5304472184a4634148c5330cbd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 22 May 2014 23:30:35 +0200 Subject: ARM: integrator: make the Integrator multiplatform This converts the ARM Integrator reference designs to be fully multiplatform. V4T, V5 and V6 multiplatform builds become possible after this patch. Signed-off-by: Linus Walleij --- arch/arm/Kconfig | 18 -------- arch/arm/mach-integrator/Kconfig | 18 ++++++++ arch/arm/mach-integrator/include/mach/uncompress.h | 48 ---------------------- 3 files changed, 18 insertions(+), 66 deletions(-) delete mode 100644 arch/arm/mach-integrator/include/mach/uncompress.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 89c4b5ccc68d..2075ebdccf5d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -320,24 +320,6 @@ config ARCH_MULTIPLATFORM select SPARSE_IRQ select USE_OF -config ARCH_INTEGRATOR - bool "ARM Ltd. Integrator family" - select ARM_AMBA - select ARM_PATCH_PHYS_VIRT if MMU - select AUTO_ZRELADDR - select COMMON_CLK - select COMMON_CLK_VERSATILE - select GENERIC_CLOCKEVENTS - select HAVE_TCM - select ICST - select MULTI_IRQ_HANDLER - select PLAT_VERSATILE - select SPARSE_IRQ - select USE_OF - select VERSATILE_FPGA_IRQ - help - Support for ARM's Integrator platform. - config ARCH_REALVIEW bool "ARM Ltd. RealView family" select ARCH_WANT_OPTIONAL_GPIOLIB diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index c455e974bbfe..aa7eb272e602 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -1,3 +1,21 @@ +config ARCH_INTEGRATOR + bool "ARM Ltd. Integrator family" if (ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6) + select ARM_AMBA + select ARM_PATCH_PHYS_VIRT if MMU + select AUTO_ZRELADDR + select COMMON_CLK + select COMMON_CLK_VERSATILE + select GENERIC_CLOCKEVENTS + select HAVE_TCM + select ICST + select MULTI_IRQ_HANDLER + select PLAT_VERSATILE + select SPARSE_IRQ + select USE_OF + select VERSATILE_FPGA_IRQ + help + Support for ARM's Integrator platform. + if ARCH_INTEGRATOR menu "Integrator Options" diff --git a/arch/arm/mach-integrator/include/mach/uncompress.h b/arch/arm/mach-integrator/include/mach/uncompress.h deleted file mode 100644 index 8f3cc9954c16..000000000000 --- a/arch/arm/mach-integrator/include/mach/uncompress.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * arch/arm/mach-integrator/include/mach/uncompress.h - * - * Copyright (C) 1999 ARM Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define AMBA_UART_DR (*(volatile unsigned char *)0x16000000) -#define AMBA_UART_LCRH (*(volatile unsigned char *)0x16000008) -#define AMBA_UART_LCRM (*(volatile unsigned char *)0x1600000c) -#define AMBA_UART_LCRL (*(volatile unsigned char *)0x16000010) -#define AMBA_UART_CR (*(volatile unsigned char *)0x16000014) -#define AMBA_UART_FR (*(volatile unsigned char *)0x16000018) - -/* - * This does not append a newline - */ -static void putc(int c) -{ - while (AMBA_UART_FR & (1 << 5)) - barrier(); - - AMBA_UART_DR = c; -} - -static inline void flush(void) -{ - while (AMBA_UART_FR & (1 << 3)) - barrier(); -} - -/* - * nothing to do - */ -#define arch_decomp_setup() -- cgit v1.2.3-59-g8ed1b From 9713497b6c64c67c8763f8f07fad325b193764b6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 27 Jun 2014 10:44:14 +0200 Subject: ARM: integrator: set V4T and V5 as default multitargets When switching the Integrator machines to multiplatform, the V7 target becomes default, but most Integrators are V4T or V5, so set these two as default in the defconfig and deselect V7. Signed-off-by: Linus Walleij --- arch/arm/configs/integrator_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig index c1f5adc5493e..71f14675d009 100644 --- a/arch/arm/configs/integrator_defconfig +++ b/arch/arm/configs/integrator_defconfig @@ -8,6 +8,9 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_MULTI_V4T=y +CONFIG_ARCH_MULTI_V5=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_INTEGRATOR=y CONFIG_ARCH_INTEGRATOR_AP=y CONFIG_ARCH_INTEGRATOR_CP=y -- cgit v1.2.3-59-g8ed1b From 27f3c70874fc1d114e26c807e900fec4b50b1217 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 6 Oct 2014 08:59:20 +0900 Subject: ARM: shmobile: Handle CA7 arch timer delay Update the delay code to include arch timer checks for CA7. From a arch timer availability perspective CA7 should be treated same as CA15. Signed-off-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/timer.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 87c6be1e79bd..32ee335d2632 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -45,6 +45,7 @@ void __init shmobile_init_delay(void) struct device_node *np, *cpus; bool is_a7_a8_a9 = false; bool is_a15 = false; + bool has_arch_timer = false; u32 max_freq = 0; cpus = of_find_node_by_path("/cpus"); @@ -57,12 +58,16 @@ void __init shmobile_init_delay(void) if (!of_property_read_u32(np, "clock-frequency", &freq)) max_freq = max(max_freq, freq); - if (of_device_is_compatible(np, "arm,cortex-a7") || - of_device_is_compatible(np, "arm,cortex-a8") || - of_device_is_compatible(np, "arm,cortex-a9")) + if (of_device_is_compatible(np, "arm,cortex-a8") || + of_device_is_compatible(np, "arm,cortex-a9")) { is_a7_a8_a9 = true; - else if (of_device_is_compatible(np, "arm,cortex-a15")) + } else if (of_device_is_compatible(np, "arm,cortex-a7")) { + is_a7_a8_a9 = true; + has_arch_timer = true; + } else if (of_device_is_compatible(np, "arm,cortex-a15")) { is_a15 = true; + has_arch_timer = true; + } } of_node_put(cpus); @@ -70,10 +75,12 @@ void __init shmobile_init_delay(void) if (!max_freq) return; - if (is_a7_a8_a9) - shmobile_setup_delay_hz(max_freq, 1, 3); - else if (is_a15 && !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) - shmobile_setup_delay_hz(max_freq, 2, 4); + if (!has_arch_timer || !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) { + if (is_a7_a8_a9) + shmobile_setup_delay_hz(max_freq, 1, 3); + else if (is_a15) + shmobile_setup_delay_hz(max_freq, 2, 4); + } } static void __init shmobile_late_time_init(void) -- cgit v1.2.3-59-g8ed1b From 27c1bb20d45830a64bf344cc1cb5e0a745e2d206 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 17 Oct 2014 14:22:37 +0200 Subject: ARM: shmobile: sh7372: Add shmobile_init_late() Extend sh7372 SoC machine vector to include shmobile_init_late() so Suspend-to-RAM and CPUIdle are setup as expected. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-sh7372.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index d646c8d12423..769ff008571d 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -1012,6 +1012,7 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)") .init_irq = sh7372_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = sh7372_add_standard_devices_dt, + .init_late = shmobile_init_late, .dt_compat = sh7372_boards_compat_dt, MACHINE_END -- cgit v1.2.3-59-g8ed1b From 9ce3fa6816c2fb59d128248c9b0509aef1c5dae7 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Fri, 12 Sep 2014 10:52:05 +0200 Subject: ARM: shmobile: rcar-gen2: Add CA7 arch_timer initialization for r8a7794 On E2, the arch timer is hooked up to a different clock, and the CA7's arch timer CNTVOFF register must be initialized. Based on work by Hisashi Nakamura. Signed-off-by: Ulrich Hecht Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-rcar-gen2.c | 72 ++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c index 42d5b4308923..7ed92790d13f 100644 --- a/arch/arm/mach-shmobile/setup-rcar-gen2.c +++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c @@ -3,6 +3,7 @@ * * Copyright (C) 2013 Renesas Solutions Corp. * Copyright (C) 2013 Magnus Damm + * Copyright (C) 2014 Ulrich Hecht * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +25,7 @@ #include #include #include +#include #include #include #include "common.h" @@ -54,37 +56,61 @@ void __init rcar_gen2_timer_init(void) { #if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK) u32 mode = rcar_gen2_read_mode_pins(); + bool is_e2 = (bool)of_find_compatible_node(NULL, NULL, + "renesas,r8a7794"); #endif #ifdef CONFIG_ARM_ARCH_TIMER void __iomem *base; int extal_mhz = 0; u32 freq; - /* At Linux boot time the r8a7790 arch timer comes up - * with the counter disabled. Moreover, it may also report - * a potentially incorrect fixed 13 MHz frequency. To be - * correct these registers need to be updated to use the - * frequency EXTAL / 2 which can be determined by the MD pins. - */ - - switch (mode & (MD(14) | MD(13))) { - case 0: - extal_mhz = 15; - break; - case MD(13): - extal_mhz = 20; - break; - case MD(14): - extal_mhz = 26; - break; - case MD(13) | MD(14): - extal_mhz = 30; - break; + if (is_e2) { + freq = 260000000 / 8; /* ZS / 8 */ + /* CNTVOFF has to be initialized either from non-secure + * Hypervisor mode or secure Monitor mode with SCR.NS==1. + * If TrustZone is enabled then it should be handled by the + * secure code. + */ + asm volatile( + " cps 0x16\n" + " mrc p15, 0, r1, c1, c1, 0\n" + " orr r0, r1, #1\n" + " mcr p15, 0, r0, c1, c1, 0\n" + " isb\n" + " mov r0, #0\n" + " mcrr p15, 4, r0, r0, c14\n" + " isb\n" + " mcr p15, 0, r1, c1, c1, 0\n" + " isb\n" + " cps 0x13\n" + : : : "r0", "r1"); + } else { + /* At Linux boot time the r8a7790 arch timer comes up + * with the counter disabled. Moreover, it may also report + * a potentially incorrect fixed 13 MHz frequency. To be + * correct these registers need to be updated to use the + * frequency EXTAL / 2 which can be determined by the MD pins. + */ + + switch (mode & (MD(14) | MD(13))) { + case 0: + extal_mhz = 15; + break; + case MD(13): + extal_mhz = 20; + break; + case MD(14): + extal_mhz = 26; + break; + case MD(13) | MD(14): + extal_mhz = 30; + break; + } + + /* The arch timer frequency equals EXTAL / 2 */ + freq = extal_mhz * (1000000 / 2); } - /* The arch timer frequency equals EXTAL / 2 */ - freq = extal_mhz * (1000000 / 2); - /* Remap "armgcnt address map" space */ base = ioremap(0xe6080000, PAGE_SIZE); -- cgit v1.2.3-59-g8ed1b From 3381eb47f3f21d11603440b19896280f82d9ce91 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:23 -0700 Subject: ARM: DRA7: PRM: add voltage processor check behind a prm_feature flag This is done in attempt to get rid of cpu_is_X calls from the PRM core. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/prm.h | 1 + arch/arm/mach-omap2/prm44xx.c | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 48480d557b61..9f4d74758616 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -29,6 +29,7 @@ int of_prcm_init(void); * PRM_HAS_VOLTAGE: has voltage domains */ #define PRM_HAS_IO_WAKEUP (1 << 0) +#define PRM_HAS_VOLTAGE (1 << 1) /* * MAX_MODULE_SOFTRESET_WAIT: Maximum microseconds to wait for OMAP diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index 0958d070d3db..76e75aa91c4f 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -652,11 +652,10 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) static int omap4_check_vcvp(void) { - /* No VC/VP on dra7xx devices */ - if (soc_is_dra7xx()) - return 0; + if (prm_features & PRM_HAS_VOLTAGE) + return 1; - return 1; + return 0; } struct pwrdm_ops omap4_pwrdm_operations = { @@ -696,6 +695,9 @@ int __init omap44xx_prm_init(void) if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) prm_features |= PRM_HAS_IO_WAKEUP; + if (!soc_is_dra7xx()) + prm_features |= PRM_HAS_VOLTAGE; + return prm_register(&omap44xx_prm_ll_data); } -- cgit v1.2.3-59-g8ed1b From 8843b119ed65cf88560fce6bbbcf027561c3103a Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:23 -0700 Subject: ARM: AM43XX: PRM: use OMAP4 PRM driver AM43xx will be re-using OMAP4 PRM driver, thus call its init function. Signed-off-by: Tero Kristo Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 03cbb16898a3..5f46f2729759 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -591,6 +591,7 @@ void __init am43xx_init_early(void) omap_cm_base_init(); omap3xxx_check_revision(); am33xx_check_features(); + omap44xx_prm_init(); am43xx_powerdomains_init(); am43xx_clockdomains_init(); am43xx_hwmod_init(); -- cgit v1.2.3-59-g8ed1b From 9002e921aa9a97de9de86fad34917c573dfc822b Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:23 -0700 Subject: ARM: OMAP2/3: hwmod: merge wait_target_ready functions for omap2/3 The implementation on these is identical, so no need to have them separate. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 716247ed9e0c..67bf7274ce89 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2927,7 +2927,7 @@ static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois) /* Static functions intended only for use in soc_ops field function pointers */ /** - * _omap2xxx_wait_target_ready - wait for a module to leave slave idle + * _omap2xxx_3xxx_wait_target_ready - wait for a module to leave slave idle * @oh: struct omap_hwmod * * * Wait for a module @oh to leave slave idle. Returns 0 if the module @@ -2935,7 +2935,7 @@ static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois) * slave idle; otherwise, pass along the return value of the * appropriate *_cm*_wait_module_ready() function. */ -static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh) +static int _omap2xxx_3xxx_wait_target_ready(struct omap_hwmod *oh) { if (!oh) return -EINVAL; @@ -2953,33 +2953,6 @@ static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh) oh->prcm.omap2.idlest_idle_bit); } -/** - * _omap3xxx_wait_target_ready - wait for a module to leave slave idle - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to leave slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully leaves - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_ready() function. - */ -static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh) -{ - if (!oh) - return -EINVAL; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - if (!_find_mpu_rt_port(oh)) - return 0; - - /* XXX check module SIDLEMODE, hardreset status, enabled clocks */ - - return omap3xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs, - oh->prcm.omap2.idlest_reg_id, - oh->prcm.omap2.idlest_idle_bit); -} - /** * _omap4_wait_target_ready - wait for a module to leave slave idle * @oh: struct omap_hwmod * @@ -4234,12 +4207,12 @@ int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx) void __init omap_hwmod_init(void) { if (cpu_is_omap24xx()) { - soc_ops.wait_target_ready = _omap2xxx_wait_target_ready; + soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready; soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; } else if (cpu_is_omap34xx()) { - soc_ops.wait_target_ready = _omap3xxx_wait_target_ready; + soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready; soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; -- cgit v1.2.3-59-g8ed1b From 9907f85eb27d98c2184a56f3b636cb82536807a0 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:23 -0700 Subject: ARM: AM33xx/OMAP4+: CM: remove cdoffs parameter from wait_module_idle/ready This is not needed for anything. This also eases the consolidation of the wait_module_ready / wait_module_idle calls behind a generic CM driver API by reducing the number of needed parameters. Signed-off-by: Tero Kristo Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/cm33xx.c | 18 +++++++----------- arch/arm/mach-omap2/cm33xx.h | 13 +++++-------- arch/arm/mach-omap2/cminst44xx.c | 19 +++++++------------ arch/arm/mach-omap2/cminst44xx.h | 5 ++--- arch/arm/mach-omap2/omap_hwmod.c | 4 ---- 5 files changed, 21 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c index b3f99e93def0..ef9e9018f4d5 100644 --- a/arch/arm/mach-omap2/cm33xx.c +++ b/arch/arm/mach-omap2/cm33xx.c @@ -96,13 +96,12 @@ static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask) /** * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to * bit 0. */ -static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs) { u32 v = am33xx_cm_read_reg(inst, clkctrl_offs); v &= AM33XX_IDLEST_MASK; @@ -113,17 +112,16 @@ static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * _is_module_ready - can module registers be accessed without causing an abort? * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. */ -static bool _is_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static bool _is_module_ready(u16 inst, u16 clkctrl_offs) { u32 v; - v = _clkctrl_idlest(inst, cdoffs, clkctrl_offs); + v = _clkctrl_idlest(inst, clkctrl_offs); return (v == CLKCTRL_IDLEST_FUNCTIONAL || v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; @@ -229,7 +227,6 @@ void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) /** * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Wait for the module IDLEST to be functional. If the idle state is in any @@ -237,11 +234,11 @@ void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) * sysconfig cannot be accessed and will probably lead to an "imprecise * external abort" */ -int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) +int am33xx_cm_wait_module_ready(u16 inst, u16 clkctrl_offs) { int i = 0; - omap_test_timeout(_is_module_ready(inst, cdoffs, clkctrl_offs), + omap_test_timeout(_is_module_ready(inst, clkctrl_offs), MAX_MODULE_READY_TIME, i); return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; @@ -251,21 +248,20 @@ int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled' * state * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Wait for the module IDLEST to be disabled. Some PRCM transition, * like reset assertion or parent clock de-activation must wait the * module to be fully disabled. */ -int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs) +int am33xx_cm_wait_module_idle(u16 inst, u16 clkctrl_offs) { int i = 0; if (!clkctrl_offs) return 0; - omap_test_timeout((_clkctrl_idlest(inst, cdoffs, clkctrl_offs) == + omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) == CLKCTRL_IDLEST_DISABLED), MAX_MODULE_READY_TIME, i); diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h index bd2441790779..1771fc17fd8c 100644 --- a/arch/arm/mach-omap2/cm33xx.h +++ b/arch/arm/mach-omap2/cm33xx.h @@ -381,17 +381,14 @@ void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs); void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs); #if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) -extern int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, - u16 clkctrl_offs); +int am33xx_cm_wait_module_idle(u16 inst, u16 clkctrl_offs); extern void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs); extern void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs); -extern int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, - u16 clkctrl_offs); +int am33xx_cm_wait_module_ready(u16 inst, u16 clkctrl_offs); #else -static inline int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, - u16 clkctrl_offs) +static inline int am33xx_cm_wait_module_idle(u16 inst, u16 clkctrl_offs) { return 0; } @@ -403,8 +400,8 @@ static inline void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs) { } -static inline int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, - u16 clkctrl_offs) + +static inline int am33xx_cm_wait_module_ready(u16 inst, u16 clkctrl_offs) { return 0; } diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 12aca56942c0..7e6970af1d66 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -78,13 +78,12 @@ void omap_cm_base_init(void) * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to * bit 0. */ -static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static u32 _clkctrl_idlest(u8 part, u16 inst, u16 clkctrl_offs) { u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs); v &= OMAP4430_IDLEST_MASK; @@ -96,17 +95,16 @@ static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) * _is_module_ready - can module registers be accessed without causing an abort? * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. */ -static bool _is_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static bool _is_module_ready(u8 part, u16 inst, u16 clkctrl_offs) { u32 v; - v = _clkctrl_idlest(part, inst, cdoffs, clkctrl_offs); + v = _clkctrl_idlest(part, inst, clkctrl_offs); return (v == CLKCTRL_IDLEST_FUNCTIONAL || v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; @@ -267,7 +265,6 @@ void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) * omap4_cminst_wait_module_ready - wait for a module to be in 'func' state * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Wait for the module IDLEST to be functional. If the idle state is in any @@ -275,15 +272,14 @@ void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) * sysconfig cannot be accessed and will probably lead to an "imprecise * external abort" */ -int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs) +int omap4_cminst_wait_module_ready(u8 part, u16 inst, u16 clkctrl_offs) { int i = 0; if (!clkctrl_offs) return 0; - omap_test_timeout(_is_module_ready(part, inst, cdoffs, clkctrl_offs), + omap_test_timeout(_is_module_ready(part, inst, clkctrl_offs), MAX_MODULE_READY_TIME, i); return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; @@ -294,21 +290,20 @@ int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, * state * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Wait for the module IDLEST to be disabled. Some PRCM transition, * like reset assertion or parent clock de-activation must wait the * module to be fully disabled. */ -int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) +int omap4_cminst_wait_module_idle(u8 part, u16 inst, u16 clkctrl_offs) { int i = 0; if (!clkctrl_offs) return 0; - omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) == + omap_test_timeout((_clkctrl_idlest(part, inst, clkctrl_offs) == CLKCTRL_IDLEST_DISABLED), MAX_MODULE_DISABLE_TIME, i); diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h index 7f56ea444bc4..67a05f9f9eab 100644 --- a/arch/arm/mach-omap2/cminst44xx.h +++ b/arch/arm/mach-omap2/cminst44xx.h @@ -16,9 +16,8 @@ void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs); void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs); void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs); void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs); -extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); -extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs); +int omap4_cminst_wait_module_ready(u8 part, u16 inst, u16 clkctrl_offs); +int omap4_cminst_wait_module_idle(u8 part, u16 inst, u16 clkctrl_offs); extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 67bf7274ce89..2dca1a896943 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1028,7 +1028,6 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition, oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, oh->prcm.omap4.clkctrl_offs); } @@ -1053,7 +1052,6 @@ static int _am33xx_wait_target_disable(struct omap_hwmod *oh) return 0; return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, oh->prcm.omap4.clkctrl_offs); } @@ -2977,7 +2975,6 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh) return omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition, oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, oh->prcm.omap4.clkctrl_offs); } @@ -3004,7 +3001,6 @@ static int _am33xx_wait_target_ready(struct omap_hwmod *oh) /* XXX check module SIDLEMODE, hardreset status */ return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, oh->prcm.omap4.clkctrl_offs); } -- cgit v1.2.3-59-g8ed1b From 7632a02f80eb99e942999e522b2eb0f6592ea5b5 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:23 -0700 Subject: ARM: OMAP4/AM33xx: add cm_init / cm_exit calls for AM33xx and OMAP4+ This is needed for expanding the generic CM driver API to include AM33xx and OMAP4 also. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/cm33xx.c | 13 +++++++++++++ arch/arm/mach-omap2/cm33xx.h | 1 + arch/arm/mach-omap2/cminst44xx.c | 13 +++++++++++++ arch/arm/mach-omap2/cminst44xx.h | 1 + arch/arm/mach-omap2/io.c | 6 ++++++ 5 files changed, 34 insertions(+) diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c index ef9e9018f4d5..e02988fd237f 100644 --- a/arch/arm/mach-omap2/cm33xx.c +++ b/arch/arm/mach-omap2/cm33xx.c @@ -358,3 +358,16 @@ struct clkdm_ops am33xx_clkdm_operations = { .clkdm_clk_enable = am33xx_clkdm_clk_enable, .clkdm_clk_disable = am33xx_clkdm_clk_disable, }; + +static struct cm_ll_data am33xx_cm_ll_data; + +int __init am33xx_cm_init(void) +{ + return cm_register(&am33xx_cm_ll_data); +} + +static void __exit am33xx_cm_exit(void) +{ + cm_unregister(&am33xx_cm_ll_data); +} +__exitcall(am33xx_cm_exit); diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h index 1771fc17fd8c..1d3cde732648 100644 --- a/arch/arm/mach-omap2/cm33xx.h +++ b/arch/arm/mach-omap2/cm33xx.h @@ -379,6 +379,7 @@ void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs); void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs); void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs); void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs); +int am33xx_cm_init(void); #if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) int am33xx_cm_wait_module_idle(u16 inst, u16 clkctrl_offs); diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 7e6970af1d66..695e71e802a5 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -505,3 +505,16 @@ struct clkdm_ops am43xx_clkdm_operations = { .clkdm_clk_enable = omap4_clkdm_clk_enable, .clkdm_clk_disable = omap4_clkdm_clk_disable, }; + +static struct cm_ll_data omap4xxx_cm_ll_data; + +int __init omap4_cm_init(void) +{ + return cm_register(&omap4xxx_cm_ll_data); +} + +static void __exit omap4_cm_exit(void) +{ + cm_unregister(&omap4xxx_cm_ll_data); +} +__exitcall(omap4_cm_exit); diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h index 67a05f9f9eab..cc3c9133a304 100644 --- a/arch/arm/mach-omap2/cminst44xx.h +++ b/arch/arm/mach-omap2/cminst44xx.h @@ -38,5 +38,6 @@ extern u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask); extern void omap_cm_base_init(void); +int omap4_cm_init(void); #endif diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 5f46f2729759..dc251673103a 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -45,6 +45,7 @@ #include "sram.h" #include "cm2xxx.h" #include "cm3xxx.h" +#include "cm33xx.h" #include "prm.h" #include "cm.h" #include "prcm_mpu44xx.h" @@ -565,6 +566,7 @@ void __init am33xx_init_early(void) omap2_set_globals_cm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE), NULL); omap3xxx_check_revision(); am33xx_check_features(); + am33xx_cm_init(); am33xx_powerdomains_init(); am33xx_clockdomains_init(); am33xx_hwmod_init(); @@ -592,6 +594,7 @@ void __init am43xx_init_early(void) omap3xxx_check_revision(); am33xx_check_features(); omap44xx_prm_init(); + omap4_cm_init(); am43xx_powerdomains_init(); am43xx_clockdomains_init(); am43xx_hwmod_init(); @@ -621,6 +624,7 @@ void __init omap4430_init_early(void) omap_cm_base_init(); omap4xxx_check_revision(); omap4xxx_check_features(); + omap4_cm_init(); omap4_pm_init_early(); omap44xx_prm_init(); omap44xx_voltagedomains_init(); @@ -656,6 +660,7 @@ void __init omap5_init_early(void) omap_cm_base_init(); omap44xx_prm_init(); omap5xxx_check_revision(); + omap4_cm_init(); omap54xx_voltagedomains_init(); omap54xx_powerdomains_init(); omap54xx_clockdomains_init(); @@ -687,6 +692,7 @@ void __init dra7xx_init_early(void) omap_cm_base_init(); omap44xx_prm_init(); dra7xxx_check_revision(); + omap4_cm_init(); dra7xx_powerdomains_init(); dra7xx_clockdomains_init(); dra7xx_hwmod_init(); -- cgit v1.2.3-59-g8ed1b From 021b6ff05c4a17cb20d71c05e251ea7f80b1c516 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:23 -0700 Subject: ARM: OMAP2+: CM: add common API for cm_wait_module_ready This patch consolidates the parameters provided for the SoC specific cm_*_wait_module_ready calls, adds the missing cm_ll_data function pointers and uses the now generic call from the mach-omap2 board code. SoC specific *_wait_module_ready calls are also made static so they can only be accessed through the generic CM driver API only. Signed-off-by: Tero Kristo Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock.c | 3 ++- arch/arm/mach-omap2/cm.h | 7 ++++--- arch/arm/mach-omap2/cm2xxx.c | 6 ++++-- arch/arm/mach-omap2/cm2xxx.h | 4 ++-- arch/arm/mach-omap2/cm33xx.c | 9 +++++++-- arch/arm/mach-omap2/cm33xx.h | 6 ------ arch/arm/mach-omap2/cm3xxx.c | 4 +++- arch/arm/mach-omap2/cm3xxx.h | 2 -- arch/arm/mach-omap2/cm_common.c | 11 +++++++---- arch/arm/mach-omap2/cminst44xx.c | 8 ++++++-- arch/arm/mach-omap2/cminst44xx.h | 1 - arch/arm/mach-omap2/omap_hwmod.c | 16 ++++++++-------- 12 files changed, 43 insertions(+), 34 deletions(-) diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 500530d1364a..ff2eb669bc08 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -171,7 +171,8 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk) _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), idlest_val, __clk_get_name(clk->hw.clk)); } else { - cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit); + omap_cm_wait_module_ready(0, prcm_mod, idlest_reg_id, + idlest_bit); }; } diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 93473f9a551c..695c34dd37ca 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -49,13 +49,14 @@ extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2); struct cm_ll_data { int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); - int (*wait_module_ready)(s16 prcm_mod, u8 idlest_id, u8 idlest_shift); + int (*wait_module_ready)(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); }; extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); -extern int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift); - +int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); extern int cm_register(struct cm_ll_data *cld); extern int cm_unregister(struct cm_ll_data *cld); diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index 8be6ea50c092..f913efb6e9ba 100644 --- a/arch/arm/mach-omap2/cm2xxx.c +++ b/arch/arm/mach-omap2/cm2xxx.c @@ -150,7 +150,7 @@ static int _omap2xxx_apll_enable(u8 enable_bit, u8 status_bit) v |= m; omap2_cm_write_mod_reg(v, PLL_MOD, CM_CLKEN); - omap2xxx_cm_wait_module_ready(PLL_MOD, 1, status_bit); + omap2xxx_cm_wait_module_ready(0, PLL_MOD, 1, status_bit); /* * REVISIT: Should we return an error code if @@ -238,6 +238,7 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, /** * omap2xxx_cm_wait_module_ready - wait for a module to leave idle or standby + * @part: PRCM partition, ignored for OMAP2 * @prcm_mod: PRCM module offset * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_shift: shift of the bit in the CM_IDLEST* register to check @@ -246,7 +247,8 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon * success or -EBUSY if the module doesn't enable in time. */ -int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift) { int ena = 0, i = 0; u8 cm_idlest_reg; diff --git a/arch/arm/mach-omap2/cm2xxx.h b/arch/arm/mach-omap2/cm2xxx.h index 891d81c3c8f4..2526a8fd3d10 100644 --- a/arch/arm/mach-omap2/cm2xxx.h +++ b/arch/arm/mach-omap2/cm2xxx.h @@ -58,8 +58,8 @@ extern void omap2xxx_cm_set_apll96_disable_autoidle(void); extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void); extern bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); -extern int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, - u8 idlest_shift); +int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift); extern int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); extern int omap2xxx_cm_fclks_active(void); diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c index e02988fd237f..e022a8d57060 100644 --- a/arch/arm/mach-omap2/cm33xx.c +++ b/arch/arm/mach-omap2/cm33xx.c @@ -226,15 +226,18 @@ void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) /** * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state + * @part: PRCM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: bit shift for the register, ignored for AM33xx * * Wait for the module IDLEST to be functional. If the idle state is in any * the non functional state (trans, idle or disabled), module and thus the * sysconfig cannot be accessed and will probably lead to an "imprecise * external abort" */ -int am33xx_cm_wait_module_ready(u16 inst, u16 clkctrl_offs) +static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; @@ -359,7 +362,9 @@ struct clkdm_ops am33xx_clkdm_operations = { .clkdm_clk_disable = am33xx_clkdm_clk_disable, }; -static struct cm_ll_data am33xx_cm_ll_data; +static struct cm_ll_data am33xx_cm_ll_data = { + .wait_module_ready = &am33xx_cm_wait_module_ready, +}; int __init am33xx_cm_init(void) { diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h index 1d3cde732648..fbbedf2c9bec 100644 --- a/arch/arm/mach-omap2/cm33xx.h +++ b/arch/arm/mach-omap2/cm33xx.h @@ -387,7 +387,6 @@ extern void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs); extern void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs); -int am33xx_cm_wait_module_ready(u16 inst, u16 clkctrl_offs); #else static inline int am33xx_cm_wait_module_idle(u16 inst, u16 clkctrl_offs) { @@ -401,11 +400,6 @@ static inline void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs) { } - -static inline int am33xx_cm_wait_module_ready(u16 inst, u16 clkctrl_offs) -{ - return 0; -} #endif #endif /* ASSEMBLER */ diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index 129a4e7f6ef5..6a3c01e16274 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c @@ -79,6 +79,7 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) /** * omap3xxx_cm_wait_module_ready - wait for a module to leave idle or standby + * @part: PRCM partition, ignored for OMAP3 * @prcm_mod: PRCM module offset * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_shift: shift of the bit in the CM_IDLEST* register to check @@ -87,7 +88,8 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon * success or -EBUSY if the module doesn't enable in time. */ -int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +static int omap3xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift) { int ena = 0, i = 0; u8 cm_idlest_reg; diff --git a/arch/arm/mach-omap2/cm3xxx.h b/arch/arm/mach-omap2/cm3xxx.h index 7a16b5598127..55faf0e149a2 100644 --- a/arch/arm/mach-omap2/cm3xxx.h +++ b/arch/arm/mach-omap2/cm3xxx.h @@ -74,8 +74,6 @@ extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask); extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask); extern bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); -extern int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, - u8 idlest_shift); extern int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c index 8f6c4710877e..dd191837ac13 100644 --- a/arch/arm/mach-omap2/cm_common.c +++ b/arch/arm/mach-omap2/cm_common.c @@ -72,9 +72,10 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, } /** - * cm_wait_module_ready - wait for a module to leave idle or standby + * omap_cm_wait_module_ready - wait for a module to leave idle or standby + * @part: PRCM partition * @prcm_mod: PRCM module offset - * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) + * @idlest_reg: CM_IDLESTx register * @idlest_shift: shift of the bit in the CM_IDLEST* register to check * * Wait for the PRCM to indicate that the module identified by @@ -83,7 +84,8 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, * no per-SoC wait_module_ready() function pointer has been registered * or if the idlest register is unknown on the SoC. */ -int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift) { if (!cm_ll_data->wait_module_ready) { WARN_ONCE(1, "cm: %s: no low-level function defined\n", @@ -91,7 +93,8 @@ int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) return -EINVAL; } - return cm_ll_data->wait_module_ready(prcm_mod, idlest_id, idlest_shift); + return cm_ll_data->wait_module_ready(part, prcm_mod, idlest_reg, + idlest_shift); } /** diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 695e71e802a5..c4f42de7f718 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -266,13 +266,15 @@ void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: bit shift for the register, ignored for OMAP4+ * * Wait for the module IDLEST to be functional. If the idle state is in any * the non functional state (trans, idle or disabled), module and thus the * sysconfig cannot be accessed and will probably lead to an "imprecise * external abort" */ -int omap4_cminst_wait_module_ready(u8 part, u16 inst, u16 clkctrl_offs) +static int omap4_cminst_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; @@ -506,7 +508,9 @@ struct clkdm_ops am43xx_clkdm_operations = { .clkdm_clk_disable = omap4_clkdm_clk_disable, }; -static struct cm_ll_data omap4xxx_cm_ll_data; +static struct cm_ll_data omap4xxx_cm_ll_data = { + .wait_module_ready = &omap4_cminst_wait_module_ready, +}; int __init omap4_cm_init(void) { diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h index cc3c9133a304..fad0a97c033b 100644 --- a/arch/arm/mach-omap2/cminst44xx.h +++ b/arch/arm/mach-omap2/cminst44xx.h @@ -16,7 +16,6 @@ void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs); void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs); void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs); void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs); -int omap4_cminst_wait_module_ready(u8 part, u16 inst, u16 clkctrl_offs); int omap4_cminst_wait_module_idle(u8 part, u16 inst, u16 clkctrl_offs); extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 2dca1a896943..1f7dd7dca7bb 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2946,9 +2946,9 @@ static int _omap2xxx_3xxx_wait_target_ready(struct omap_hwmod *oh) /* XXX check module SIDLEMODE, hardreset status, enabled clocks */ - return omap2xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs, - oh->prcm.omap2.idlest_reg_id, - oh->prcm.omap2.idlest_idle_bit); + return omap_cm_wait_module_ready(0, oh->prcm.omap2.module_offs, + oh->prcm.omap2.idlest_reg_id, + oh->prcm.omap2.idlest_idle_bit); } /** @@ -2973,9 +2973,9 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh) /* XXX check module SIDLEMODE, hardreset status */ - return omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_ready(oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** @@ -3000,8 +3000,8 @@ static int _am33xx_wait_target_ready(struct omap_hwmod *oh) /* XXX check module SIDLEMODE, hardreset status */ - return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_ready(0, oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** -- cgit v1.2.3-59-g8ed1b From a8ae5afa5cb820afa251b9acfe3f0a938b6a6c0d Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:23 -0700 Subject: ARM: OMAP4+/AM33xx: CM: add common API for cm_wait_module_idle Adds a generic CM driver API for waiting module to enter idle / standby. The SoC specific implementations are registered through cm_ll_data. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/cm.h | 5 +++++ arch/arm/mach-omap2/cm33xx.c | 6 +++++- arch/arm/mach-omap2/cm33xx.h | 5 ----- arch/arm/mach-omap2/cm_common.c | 26 ++++++++++++++++++++++++++ arch/arm/mach-omap2/cminst44xx.c | 5 ++++- arch/arm/mach-omap2/cminst44xx.h | 1 - arch/arm/mach-omap2/omap_hwmod.c | 10 +++++----- 7 files changed, 45 insertions(+), 13 deletions(-) diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 695c34dd37ca..3ecc5d73e2c5 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -45,18 +45,23 @@ extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2); * struct cm_ll_data - fn ptrs to per-SoC CM function implementations * @split_idlest_reg: ptr to the SoC CM-specific split_idlest_reg impl * @wait_module_ready: ptr to the SoC CM-specific wait_module_ready impl + * @wait_module_idle: ptr to the SoC CM-specific wait_module_idle impl */ struct cm_ll_data { int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); int (*wait_module_ready)(u8 part, s16 prcm_mod, u16 idlest_reg, u8 idlest_shift); + int (*wait_module_idle)(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); }; extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg, u8 idlest_shift); +int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); extern int cm_register(struct cm_ll_data *cld); extern int cm_unregister(struct cm_ll_data *cld); diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c index e022a8d57060..d57fa5fe9e51 100644 --- a/arch/arm/mach-omap2/cm33xx.c +++ b/arch/arm/mach-omap2/cm33xx.c @@ -250,14 +250,17 @@ static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs, /** * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled' * state + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: bit shift for the register, ignored for AM33xx * * Wait for the module IDLEST to be disabled. Some PRCM transition, * like reset assertion or parent clock de-activation must wait the * module to be fully disabled. */ -int am33xx_cm_wait_module_idle(u16 inst, u16 clkctrl_offs) +static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; @@ -364,6 +367,7 @@ struct clkdm_ops am33xx_clkdm_operations = { static struct cm_ll_data am33xx_cm_ll_data = { .wait_module_ready = &am33xx_cm_wait_module_ready, + .wait_module_idle = &am33xx_cm_wait_module_idle, }; int __init am33xx_cm_init(void) diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h index fbbedf2c9bec..a0daea84fbe9 100644 --- a/arch/arm/mach-omap2/cm33xx.h +++ b/arch/arm/mach-omap2/cm33xx.h @@ -382,16 +382,11 @@ void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs); int am33xx_cm_init(void); #if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) -int am33xx_cm_wait_module_idle(u16 inst, u16 clkctrl_offs); extern void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs); extern void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs); #else -static inline int am33xx_cm_wait_module_idle(u16 inst, u16 clkctrl_offs) -{ - return 0; -} static inline void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) { diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c index dd191837ac13..c6237df288d8 100644 --- a/arch/arm/mach-omap2/cm_common.c +++ b/arch/arm/mach-omap2/cm_common.c @@ -97,6 +97,32 @@ int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg, idlest_shift); } +/** + * omap_cm_wait_module_idle - wait for a module to enter idle or standby + * @part: PRCM partition + * @prcm_mod: PRCM module offset + * @idlest_reg: CM_IDLESTx register + * @idlest_shift: shift of the bit in the CM_IDLEST* register to check + * + * Wait for the PRCM to indicate that the module identified by + * (@prcm_mod, @idlest_id, @idlest_shift) is no longer clocked. Return + * 0 upon success, -EBUSY if the module doesn't enable in time, or + * -EINVAL if no per-SoC wait_module_idle() function pointer has been + * registered or if the idlest register is unknown on the SoC. + */ +int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift) +{ + if (!cm_ll_data->wait_module_idle) { + WARN_ONCE(1, "cm: %s: no low-level function defined\n", + __func__); + return -EINVAL; + } + + return cm_ll_data->wait_module_idle(part, prcm_mod, idlest_reg, + idlest_shift); +} + /** * cm_register - register per-SoC low-level data with the CM * @cld: low-level per-SoC OMAP CM data & function pointers to register diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index c4f42de7f718..7ae1cc22eb5c 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -293,12 +293,14 @@ static int omap4_cminst_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs, * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: Bit shift for the register, ignored for OMAP4+ * * Wait for the module IDLEST to be disabled. Some PRCM transition, * like reset assertion or parent clock de-activation must wait the * module to be fully disabled. */ -int omap4_cminst_wait_module_idle(u8 part, u16 inst, u16 clkctrl_offs) +static int omap4_cminst_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; @@ -510,6 +512,7 @@ struct clkdm_ops am43xx_clkdm_operations = { static struct cm_ll_data omap4xxx_cm_ll_data = { .wait_module_ready = &omap4_cminst_wait_module_ready, + .wait_module_idle = &omap4_cminst_wait_module_idle, }; int __init omap4_cm_init(void) diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h index fad0a97c033b..9a223ddc9467 100644 --- a/arch/arm/mach-omap2/cminst44xx.h +++ b/arch/arm/mach-omap2/cminst44xx.h @@ -16,7 +16,6 @@ void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs); void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs); void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs); void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs); -int omap4_cminst_wait_module_idle(u8 part, u16 inst, u16 clkctrl_offs); extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 1f7dd7dca7bb..03a42b37ef18 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1026,9 +1026,9 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) if (oh->flags & HWMOD_NO_IDLEST) return 0; - return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_idle(oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** @@ -1051,8 +1051,8 @@ static int _am33xx_wait_target_disable(struct omap_hwmod *oh) if (oh->flags & HWMOD_NO_IDLEST) return 0; - return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_idle(0, oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** -- cgit v1.2.3-59-g8ed1b From f2650d6e4fb797b436af5999ea89aa279712544b Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:24 -0700 Subject: ARM: OMAP2+: CM: make clkdm_hwsup operations static These are not accessed outside the cm*.c files themselves, so make them static. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/cm2xxx.c | 6 +++--- arch/arm/mach-omap2/cm2xxx.h | 4 ---- arch/arm/mach-omap2/cm33xx.c | 10 +++++----- arch/arm/mach-omap2/cm33xx.h | 5 ----- arch/arm/mach-omap2/cm3xxx.c | 10 +++++----- arch/arm/mach-omap2/cm3xxx.h | 7 ------- arch/arm/mach-omap2/cminst44xx.c | 10 +++++----- arch/arm/mach-omap2/cminst44xx.h | 5 ----- 8 files changed, 18 insertions(+), 39 deletions(-) diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index f913efb6e9ba..365df9e32d1c 100644 --- a/arch/arm/mach-omap2/cm2xxx.c +++ b/arch/arm/mach-omap2/cm2xxx.c @@ -53,7 +53,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask) omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL); } -bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) +static bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) { u32 v; @@ -64,12 +64,12 @@ bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) return (v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0; } -void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) +static void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP24XX_CLKSTCTRL_ENABLE_AUTO, module, mask); } -void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) +static void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP24XX_CLKSTCTRL_DISABLE_AUTO, module, mask); } diff --git a/arch/arm/mach-omap2/cm2xxx.h b/arch/arm/mach-omap2/cm2xxx.h index 2526a8fd3d10..a14094bbed1a 100644 --- a/arch/arm/mach-omap2/cm2xxx.h +++ b/arch/arm/mach-omap2/cm2xxx.h @@ -46,9 +46,6 @@ #ifndef __ASSEMBLER__ -extern void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask); -extern void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask); - extern void omap2xxx_cm_set_dpll_disable_autoidle(void); extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void); @@ -57,7 +54,6 @@ extern void omap2xxx_cm_set_apll54_auto_low_power_stop(void); extern void omap2xxx_cm_set_apll96_disable_autoidle(void); extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void); -extern bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, u8 idlest_shift); extern int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c index d57fa5fe9e51..ffdcb7abf092 100644 --- a/arch/arm/mach-omap2/cm33xx.c +++ b/arch/arm/mach-omap2/cm33xx.c @@ -156,7 +156,7 @@ static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs) * Returns true if the clockdomain referred to by (@inst, @cdoffs) * is in hardware-supervised idle mode, or 0 otherwise. */ -bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) +static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) { u32 v; @@ -175,7 +175,7 @@ bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) * Put a clockdomain referred to by (@inst, @cdoffs) into * hardware-supervised idle mode. No return value. */ -void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs); } @@ -189,7 +189,7 @@ void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) * software-supervised idle mode, i.e., controlled manually by the * Linux OMAP clockdomain code. No return value. */ -void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs); } @@ -202,7 +202,7 @@ void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) * Put a clockdomain referred to by (@inst, @cdoffs) into idle * No return value. */ -void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs); } @@ -215,7 +215,7 @@ void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) * Take a clockdomain referred to by (@inst, @cdoffs) out of idle, * waking it up. No return value. */ -void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs); } diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h index a0daea84fbe9..78a61e5d80e2 100644 --- a/arch/arm/mach-omap2/cm33xx.h +++ b/arch/arm/mach-omap2/cm33xx.h @@ -374,11 +374,6 @@ #ifndef __ASSEMBLER__ -bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs); int am33xx_cm_init(void); #if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index 6a3c01e16274..018063b96cbc 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c @@ -42,7 +42,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask) omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL); } -bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) +static bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) { u32 v; @@ -53,22 +53,22 @@ bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0; } -void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, module, mask); } -void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, module, mask); } -void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, module, mask); } -void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask); } diff --git a/arch/arm/mach-omap2/cm3xxx.h b/arch/arm/mach-omap2/cm3xxx.h index 55faf0e149a2..33491c746b4c 100644 --- a/arch/arm/mach-omap2/cm3xxx.h +++ b/arch/arm/mach-omap2/cm3xxx.h @@ -68,13 +68,6 @@ #ifndef __ASSEMBLER__ -extern void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask); -extern void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask); -extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask); -extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask); - -extern bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); - extern int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 7ae1cc22eb5c..b189a2b46808 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -198,7 +198,7 @@ static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs) * Returns true if the clockdomain referred to by (@part, @inst, @cdoffs) * is in hardware-supervised idle mode, or 0 otherwise. */ -bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) +static bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) { u32 v; @@ -218,7 +218,7 @@ bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) * Put a clockdomain referred to by (@part, @inst, @cdoffs) into * hardware-supervised idle mode. No return value. */ -void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs); } @@ -233,7 +233,7 @@ void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) * software-supervised idle mode, i.e., controlled manually by the * Linux OMAP clockdomain code. No return value. */ -void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs); } @@ -247,7 +247,7 @@ void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) * Take a clockdomain referred to by (@part, @inst, @cdoffs) out of idle, * waking it up. No return value. */ -void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs); } @@ -256,7 +256,7 @@ void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) * */ -void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs); } diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h index 9a223ddc9467..d6634fada357 100644 --- a/arch/arm/mach-omap2/cminst44xx.h +++ b/arch/arm/mach-omap2/cminst44xx.h @@ -11,11 +11,6 @@ #ifndef __ARCH_ASM_MACH_OMAP2_CMINST44XX_H #define __ARCH_ASM_MACH_OMAP2_CMINST44XX_H -bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs); extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, -- cgit v1.2.3-59-g8ed1b From 128603f05af371acc09e4cfd9124388f1b3e2966 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:24 -0700 Subject: ARM: OMAP2+: CM: add common APIs for cm_module_enable/disable Adds a generic CM driver API for enabling/disabling modules. The SoC specific implementations are registered through cm_ll_data. Signed-off-by: Tero Kristo Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/cm.h | 6 ++++++ arch/arm/mach-omap2/cm33xx.c | 11 ++++++---- arch/arm/mach-omap2/cm33xx.h | 17 --------------- arch/arm/mach-omap2/cm_common.c | 45 ++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/cminst44xx.c | 11 +++++----- arch/arm/mach-omap2/cminst44xx.h | 4 ---- arch/arm/mach-omap2/omap_hwmod.c | 23 ++++++++------------ 7 files changed, 72 insertions(+), 45 deletions(-) diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 3ecc5d73e2c5..6222e87a79b6 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -46,6 +46,8 @@ extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2); * @split_idlest_reg: ptr to the SoC CM-specific split_idlest_reg impl * @wait_module_ready: ptr to the SoC CM-specific wait_module_ready impl * @wait_module_idle: ptr to the SoC CM-specific wait_module_idle impl + * @module_enable: ptr to the SoC CM-specific module_enable impl + * @module_disable: ptr to the SoC CM-specific module_disable impl */ struct cm_ll_data { int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst, @@ -54,6 +56,8 @@ struct cm_ll_data { u8 idlest_shift); int (*wait_module_idle)(u8 part, s16 prcm_mod, u16 idlest_reg, u8 idlest_shift); + void (*module_enable)(u8 mode, u8 part, u16 inst, u16 clkctrl_offs); + void (*module_disable)(u8 part, u16 inst, u16 clkctrl_offs); }; extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, @@ -62,6 +66,8 @@ int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg, u8 idlest_shift); int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg, u8 idlest_shift); +int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs); +int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs); extern int cm_register(struct cm_ll_data *cld); extern int cm_unregister(struct cm_ll_data *cld); diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c index ffdcb7abf092..b9ad463a368a 100644 --- a/arch/arm/mach-omap2/cm33xx.c +++ b/arch/arm/mach-omap2/cm33xx.c @@ -277,13 +277,14 @@ static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs, /** * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL * @mode: Module mode (SW or HW) + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst, + u16 clkctrl_offs) { u32 v; @@ -295,13 +296,13 @@ void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * am33xx_cm_module_disable - Disable the module inside CLKCTRL + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs) { u32 v; @@ -368,6 +369,8 @@ struct clkdm_ops am33xx_clkdm_operations = { static struct cm_ll_data am33xx_cm_ll_data = { .wait_module_ready = &am33xx_cm_wait_module_ready, .wait_module_idle = &am33xx_cm_wait_module_idle, + .module_enable = &am33xx_cm_module_enable, + .module_disable = &am33xx_cm_module_disable, }; int __init am33xx_cm_init(void) diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h index 78a61e5d80e2..046b4b2bc9d9 100644 --- a/arch/arm/mach-omap2/cm33xx.h +++ b/arch/arm/mach-omap2/cm33xx.h @@ -375,22 +375,5 @@ #ifndef __ASSEMBLER__ int am33xx_cm_init(void); - -#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) -extern void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void am33xx_cm_module_disable(u16 inst, s16 cdoffs, - u16 clkctrl_offs); -#else -static inline void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ -} -static inline void am33xx_cm_module_disable(u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ -} -#endif - #endif /* ASSEMBLER */ #endif diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c index c6237df288d8..8fe02fcedc48 100644 --- a/arch/arm/mach-omap2/cm_common.c +++ b/arch/arm/mach-omap2/cm_common.c @@ -123,6 +123,51 @@ int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg, idlest_shift); } +/** + * omap_cm_module_enable - enable a module + * @mode: target mode for the module + * @part: PRCM partition + * @inst: PRCM instance + * @clkctrl_offs: CM_CLKCTRL register offset for the module + * + * Enables clocks for a module identified by (@part, @inst, @clkctrl_offs) + * making its IO space accessible. Return 0 upon success, -EINVAL if no + * per-SoC module_enable() function pointer has been registered. + */ +int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs) +{ + if (!cm_ll_data->module_enable) { + WARN_ONCE(1, "cm: %s: no low-level function defined\n", + __func__); + return -EINVAL; + } + + cm_ll_data->module_enable(mode, part, inst, clkctrl_offs); + return 0; +} + +/** + * omap_cm_module_disable - disable a module + * @part: PRCM partition + * @inst: PRCM instance + * @clkctrl_offs: CM_CLKCTRL register offset for the module + * + * Disables clocks for a module identified by (@part, @inst, @clkctrl_offs) + * makings its IO space inaccessible. Return 0 upon success, -EINVAL if + * no per-SoC module_disable() function pointer has been registered. + */ +int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs) +{ + if (!cm_ll_data->module_disable) { + WARN_ONCE(1, "cm: %s: no low-level function defined\n", + __func__); + return -EINVAL; + } + + cm_ll_data->module_disable(part, inst, clkctrl_offs); + return 0; +} + /** * cm_register - register per-SoC low-level data with the CM * @cld: low-level per-SoC OMAP CM data & function pointers to register diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index b189a2b46808..ac034109078e 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -319,13 +319,12 @@ static int omap4_cminst_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs, * @mode: Module mode (SW or HW) * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs) +static void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, + u16 clkctrl_offs) { u32 v; @@ -339,13 +338,11 @@ void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, * omap4_cminst_module_disable - Disable the module inside CLKCTRL * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs) +static void omap4_cminst_module_disable(u8 part, u16 inst, u16 clkctrl_offs) { u32 v; @@ -513,6 +510,8 @@ struct clkdm_ops am43xx_clkdm_operations = { static struct cm_ll_data omap4xxx_cm_ll_data = { .wait_module_ready = &omap4_cminst_wait_module_ready, .wait_module_idle = &omap4_cminst_wait_module_idle, + .module_enable = &omap4_cminst_module_enable, + .module_disable = &omap4_cminst_module_disable, }; int __init omap4_cm_init(void) diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h index d6634fada357..ffbd7219bb81 100644 --- a/arch/arm/mach-omap2/cminst44xx.h +++ b/arch/arm/mach-omap2/cminst44xx.h @@ -11,10 +11,6 @@ #ifndef __ARCH_ASM_MACH_OMAP2_CMINST44XX_H #define __ARCH_ASM_MACH_OMAP2_CMINST44XX_H -extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs); /* * In an ideal world, we would not export these low-level functions, * but this will probably take some time to fix properly diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 03a42b37ef18..a8f57ef1e1d4 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -979,11 +979,9 @@ static void _omap4_enable_module(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: %s: %d\n", oh->name, __func__, oh->prcm.omap4.modulemode); - omap4_cminst_module_enable(oh->prcm.omap4.modulemode, - oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_enable(oh->prcm.omap4.modulemode, + oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs); } /** @@ -1001,9 +999,8 @@ static void _am33xx_enable_module(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: %s: %d\n", oh->name, __func__, oh->prcm.omap4.modulemode); - am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_enable(oh->prcm.omap4.modulemode, 0, oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs); } /** @@ -1857,10 +1854,8 @@ static int _omap4_disable_module(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); - omap4_cminst_module_disable(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_disable(oh->clkdm->prcm_partition, oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs); v = _omap4_wait_target_disable(oh); if (v) @@ -1889,8 +1884,8 @@ static int _am33xx_disable_module(struct omap_hwmod *oh) if (_are_any_hardreset_lines_asserted(oh)) return 0; - am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_disable(0, oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs); v = _am33xx_wait_target_disable(oh); if (v) -- cgit v1.2.3-59-g8ed1b From 2196a9b84ab0752692950a6f5fc332db4a25d9b5 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:24 -0700 Subject: ARM: OMAP2/3: CM: make cm_split_idlest_reg SoC calls static CM driver has a generic API which calls the SoC specific split function through cm_ll_data, so there is no need for the SoC specific functions to be publicly available. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/cm2xxx.c | 5 +++-- arch/arm/mach-omap2/cm2xxx.h | 2 -- arch/arm/mach-omap2/cm3xxx.c | 5 +++-- arch/arm/mach-omap2/cm3xxx.h | 3 --- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index 365df9e32d1c..a96d901b1d5d 100644 --- a/arch/arm/mach-omap2/cm2xxx.c +++ b/arch/arm/mach-omap2/cm2xxx.c @@ -204,8 +204,9 @@ void omap2xxx_cm_apll96_disable(void) * XXX This function is only needed until absolute register addresses are * removed from the OMAP struct clk records. */ -int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, - u8 *idlest_reg_id) +static int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, + s16 *prcm_inst, + u8 *idlest_reg_id) { unsigned long offs; u8 idlest_offs; diff --git a/arch/arm/mach-omap2/cm2xxx.h b/arch/arm/mach-omap2/cm2xxx.h index a14094bbed1a..c89502b168ae 100644 --- a/arch/arm/mach-omap2/cm2xxx.h +++ b/arch/arm/mach-omap2/cm2xxx.h @@ -56,8 +56,6 @@ extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void); int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, u8 idlest_shift); -extern int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, - s16 *prcm_inst, u8 *idlest_reg_id); extern int omap2xxx_cm_fclks_active(void); extern int omap2xxx_cm_mpu_retention_allowed(void); extern u32 omap2xxx_cm_get_core_clk_src(void); diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index 018063b96cbc..ebead8f035f9 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c @@ -118,8 +118,9 @@ static int omap3xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, * XXX This function is only needed until absolute register addresses are * removed from the OMAP struct clk records. */ -int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, - u8 *idlest_reg_id) +static int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, + s16 *prcm_inst, + u8 *idlest_reg_id) { unsigned long offs; u8 idlest_offs; diff --git a/arch/arm/mach-omap2/cm3xxx.h b/arch/arm/mach-omap2/cm3xxx.h index 33491c746b4c..734a8581c0c4 100644 --- a/arch/arm/mach-omap2/cm3xxx.h +++ b/arch/arm/mach-omap2/cm3xxx.h @@ -68,9 +68,6 @@ #ifndef __ASSEMBLER__ -extern int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, - s16 *prcm_inst, u8 *idlest_reg_id); - extern void omap3_cm_save_context(void); extern void omap3_cm_restore_context(void); extern void omap3_cm_save_scratchpad_contents(u32 *ptr); -- cgit v1.2.3-59-g8ed1b From 05d2b09329ad34a9f8b5b9ac25ab11f4fc077bc7 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:24 -0700 Subject: ARM: AM33xx: hwmod: remove am33xx specific module SoC opts These are now identical with the OMAP4 implementations, so use the OMAP4 versions and remove the AM33xx ones. Signed-off-by: Tero Kristo Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 105 ++------------------------------------- 1 file changed, 3 insertions(+), 102 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index a8f57ef1e1d4..9fec604ee625 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -984,25 +984,6 @@ static void _omap4_enable_module(struct omap_hwmod *oh) oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs); } -/** - * _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX - * @oh: struct omap_hwmod * - * - * Enables the PRCM module mode related to the hwmod @oh. - * No return value. - */ -static void _am33xx_enable_module(struct omap_hwmod *oh) -{ - if (!oh->clkdm || !oh->prcm.omap4.modulemode) - return; - - pr_debug("omap_hwmod: %s: %s: %d\n", - oh->name, __func__, oh->prcm.omap4.modulemode); - - omap_cm_module_enable(oh->prcm.omap4.modulemode, 0, oh->clkdm->cm_inst, - oh->prcm.omap4.clkctrl_offs); -} - /** * _omap4_wait_target_disable - wait for a module to be disabled on OMAP4 * @oh: struct omap_hwmod * @@ -1028,30 +1009,6 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) oh->prcm.omap4.clkctrl_offs, 0); } -/** - * _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to enter slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully enters - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_idle() function. - */ -static int _am33xx_wait_target_disable(struct omap_hwmod *oh) -{ - if (!oh) - return -EINVAL; - - if (oh->_int_flags & _HWMOD_NO_MPU_PORT) - return 0; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - return omap_cm_wait_module_idle(0, oh->clkdm->cm_inst, - oh->prcm.omap4.clkctrl_offs, 0); -} - /** * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh * @oh: struct omap_hwmod *oh @@ -1865,36 +1822,6 @@ static int _omap4_disable_module(struct omap_hwmod *oh) return 0; } -/** - * _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX - * @oh: struct omap_hwmod * - * - * Disable the PRCM module mode related to the hwmod @oh. - * Return EINVAL if the modulemode is not supported and 0 in case of success. - */ -static int _am33xx_disable_module(struct omap_hwmod *oh) -{ - int v; - - if (!oh->clkdm || !oh->prcm.omap4.modulemode) - return -EINVAL; - - pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); - - if (_are_any_hardreset_lines_asserted(oh)) - return 0; - - omap_cm_module_disable(0, oh->clkdm->cm_inst, - oh->prcm.omap4.clkctrl_offs); - - v = _am33xx_wait_target_disable(oh); - if (v) - pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", - oh->name); - - return 0; -} - /** * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit * @oh: struct omap_hwmod * @@ -2973,32 +2900,6 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh) oh->prcm.omap4.clkctrl_offs, 0); } -/** - * _am33xx_wait_target_ready - wait for a module to leave slave idle - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to leave slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully leaves - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_ready() function. - */ -static int _am33xx_wait_target_ready(struct omap_hwmod *oh) -{ - if (!oh || !oh->clkdm) - return -EINVAL; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - if (!_find_mpu_rt_port(oh)) - return 0; - - /* XXX check module SIDLEMODE, hardreset status */ - - return omap_cm_wait_module_ready(0, oh->clkdm->cm_inst, - oh->prcm.omap4.clkctrl_offs, 0); -} - /** * _omap2_assert_hardreset - call OMAP2 PRM hardreset fn with hwmod args * @oh: struct omap_hwmod * to assert hardreset @@ -4227,9 +4128,9 @@ void __init omap_hwmod_init(void) soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; soc_ops.init_clkdm = _init_clkdm; } else if (soc_is_am33xx()) { - soc_ops.enable_module = _am33xx_enable_module; - soc_ops.disable_module = _am33xx_disable_module; - soc_ops.wait_target_ready = _am33xx_wait_target_ready; + soc_ops.enable_module = _omap4_enable_module; + soc_ops.disable_module = _omap4_disable_module; + soc_ops.wait_target_ready = _omap4_wait_target_ready; soc_ops.assert_hardreset = _am33xx_assert_hardreset; soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; -- cgit v1.2.3-59-g8ed1b From 409d70632357122fa89db298256a162bb563a08b Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:24 -0700 Subject: ARM: AM43xx: hwmod: use OMAP4 hardreset ops instead of the AM33xx version AM43xx is using OMAP4+ PRM driver, so it should be using the corresponding hardreset ops from the hwmod also. Signed-off-by: Tero Kristo Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 9fec604ee625..af4482d3d308 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -4123,9 +4123,9 @@ void __init omap_hwmod_init(void) soc_ops.enable_module = _omap4_enable_module; soc_ops.disable_module = _omap4_disable_module; soc_ops.wait_target_ready = _omap4_wait_target_ready; - soc_ops.assert_hardreset = _am33xx_assert_hardreset; - soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; - soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; + soc_ops.assert_hardreset = _omap4_assert_hardreset; + soc_ops.deassert_hardreset = _omap4_deassert_hardreset; + soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; soc_ops.init_clkdm = _init_clkdm; } else if (soc_is_am33xx()) { soc_ops.enable_module = _omap4_enable_module; -- cgit v1.2.3-59-g8ed1b From d9bbe84f6723b78bc9980b3d5d609a6b73b350be Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:24 -0700 Subject: ARM: AM33xx: PRM: add support for prm_init Added support for prm_init for AM33xx SoC. This is needed to register SoC specific prm_ll_data for these devices. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/io.c | 2 ++ arch/arm/mach-omap2/prm33xx.c | 13 +++++++++++++ arch/arm/mach-omap2/prm33xx.h | 2 ++ 3 files changed, 17 insertions(+) diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index dc251673103a..55380bb89a54 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -53,6 +53,7 @@ #include "cminst44xx.h" #include "prm2xxx.h" #include "prm3xxx.h" +#include "prm33xx.h" #include "prm44xx.h" #include "opp2xxx.h" @@ -566,6 +567,7 @@ void __init am33xx_init_early(void) omap2_set_globals_cm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE), NULL); omap3xxx_check_revision(); am33xx_check_features(); + am33xx_prm_init(); am33xx_cm_init(); am33xx_powerdomains_init(); am33xx_clockdomains_init(); diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index 62709cd2f9c5..f149e7c9f948 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -342,3 +342,16 @@ struct pwrdm_ops am33xx_pwrdm_operations = { .pwrdm_wait_transition = am33xx_pwrdm_wait_transition, .pwrdm_has_voltdm = am33xx_check_vcvp, }; + +static struct prm_ll_data am33xx_prm_ll_data; + +int __init am33xx_prm_init(void) +{ + return prm_register(&am33xx_prm_ll_data); +} + +static void __exit am33xx_prm_exit(void) +{ + prm_unregister(&am33xx_prm_ll_data); +} +__exitcall(am33xx_prm_exit); diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h index 9b9918dfb119..5cdfdc02c342 100644 --- a/arch/arm/mach-omap2/prm33xx.h +++ b/arch/arm/mach-omap2/prm33xx.h @@ -127,5 +127,7 @@ extern int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, extern int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs); extern int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, u16 rstctrl_offs, u16 rstst_offs); +int am33xx_prm_init(void); + #endif /* ASSEMBLER */ #endif -- cgit v1.2.3-59-g8ed1b From efd44dc35f550e0cedd983d13e180da5e0d368a9 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:24 -0700 Subject: ARM: OMAP2+: PRM: add generic API for asserting hardware reset PRM driver now has a generic API for asserting hardware resets. SoC specific support functions are registered through the prm_ll_data. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 18 +++++++++--------- arch/arm/mach-omap2/prm.h | 3 +++ arch/arm/mach-omap2/prm2xxx.c | 1 + arch/arm/mach-omap2/prm2xxx_3xxx.c | 6 ++++-- arch/arm/mach-omap2/prm2xxx_3xxx.h | 3 ++- arch/arm/mach-omap2/prm33xx.c | 8 ++++++-- arch/arm/mach-omap2/prm33xx.h | 1 - arch/arm/mach-omap2/prm3xxx.c | 1 + arch/arm/mach-omap2/prm44xx.c | 1 + arch/arm/mach-omap2/prm_common.c | 20 ++++++++++++++++++++ 10 files changed, 47 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index af4482d3d308..66198e57708f 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2914,8 +2914,8 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh) static int _omap2_assert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, - ohri->rst_shift); + return omap_prm_assert_hardreset(ohri->rst_shift, 0, + oh->prcm.omap2.module_offs, 0); } /** @@ -2974,10 +2974,10 @@ static int _omap4_assert_hardreset(struct omap_hwmod *oh, if (!oh->clkdm) return -EINVAL; - return omap4_prminst_assert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_assert_hardreset(ohri->rst_shift, + oh->clkdm->pwrdm.ptr->prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3047,9 +3047,9 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return am33xx_prm_assert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_assert_hardreset(ohri->rst_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 9f4d74758616..9b8711b6adde 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -128,6 +128,7 @@ struct prm_reset_src_map { * @was_any_context_lost_old: ptr to the SoC PRM context loss test fn * @clear_context_loss_flags_old: ptr to the SoC PRM context loss flag clear fn * @late_init: ptr to the late init function + * @assert_hardreset: ptr to the SoC PRM hardreset assert impl * * XXX @was_any_context_lost_old and @clear_context_loss_flags_old are * deprecated. @@ -137,11 +138,13 @@ struct prm_ll_data { bool (*was_any_context_lost_old)(u8 part, s16 inst, u16 idx); void (*clear_context_loss_flags_old)(u8 part, s16 inst, u16 idx); int (*late_init)(void); + int (*assert_hardreset)(u8 shift, u8 part, s16 prm_mod, u16 offset); }; extern int prm_register(struct prm_ll_data *pld); extern int prm_unregister(struct prm_ll_data *pld); +int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset); extern u32 prm_read_reset_sources(void); extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx); extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx); diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c index 86958050547a..fa4448b9f716 100644 --- a/arch/arm/mach-omap2/prm2xxx.c +++ b/arch/arm/mach-omap2/prm2xxx.c @@ -212,6 +212,7 @@ struct pwrdm_ops omap2_pwrdm_operations = { static struct prm_ll_data omap2xxx_prm_ll_data = { .read_reset_sources = &omap2xxx_prm_read_reset_sources, + .assert_hardreset = &omap2_prm_assert_hardreset, }; int __init omap2xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index c13b4e293ffa..8758cd6f2eed 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -39,8 +39,10 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) /** * omap2_prm_assert_hardreset - assert the HW reset line of a submodule - * @prm_mod: PRM submodule base (e.g. CORE_MOD) * @shift: register bit shift corresponding to the reset line to assert + * @part: PRM partition, ignored for OMAP2 + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @offset: register offset, ignored for OMAP2 * * Some IPs like dsp or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -49,7 +51,7 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) * place the submodule into reset. Returns 0 upon success or -EINVAL * upon an argument error. */ -int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) +int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) { u32 mask; diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h index 1a3a96392b97..967496220f58 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h @@ -101,7 +101,8 @@ static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) /* These omap2_ PRM functions apply to both OMAP2 and 3 */ extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); -extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); +int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, + u16 offset); extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift); extern int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst); diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index f149e7c9f948..992a40e72284 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -73,6 +73,7 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) /** * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule * @shift: register bit shift corresponding to the reset line to assert + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) * @rstctrl_reg: RM_RSTCTRL register address for this module * @@ -83,7 +84,8 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) * place the submodule into reset. Returns 0 upon success or -EINVAL * upon an argument error. */ -int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) +static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst, + u16 rstctrl_offs) { u32 mask = 1 << shift; @@ -343,7 +345,9 @@ struct pwrdm_ops am33xx_pwrdm_operations = { .pwrdm_has_voltdm = am33xx_check_vcvp, }; -static struct prm_ll_data am33xx_prm_ll_data; +static struct prm_ll_data am33xx_prm_ll_data = { + .assert_hardreset = am33xx_prm_assert_hardreset, +}; int __init am33xx_prm_init(void) { diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h index 5cdfdc02c342..1d9aad8e84f3 100644 --- a/arch/arm/mach-omap2/prm33xx.h +++ b/arch/arm/mach-omap2/prm33xx.h @@ -124,7 +124,6 @@ extern u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); extern void am33xx_prm_global_warm_sw_reset(void); extern int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs); -extern int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs); extern int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, u16 rstctrl_offs, u16 rstst_offs); int am33xx_prm_init(void); diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index ff08da385a2d..8d9a7d49d6dc 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -664,6 +664,7 @@ static int omap3xxx_prm_late_init(void); static struct prm_ll_data omap3xxx_prm_ll_data = { .read_reset_sources = &omap3xxx_prm_read_reset_sources, .late_init = &omap3xxx_prm_late_init, + .assert_hardreset = &omap2_prm_assert_hardreset, }; int __init omap3xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index 76e75aa91c4f..1c86270014ed 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -688,6 +688,7 @@ static struct prm_ll_data omap44xx_prm_ll_data = { .was_any_context_lost_old = &omap44xx_prm_was_any_context_lost_old, .clear_context_loss_flags_old = &omap44xx_prm_clear_context_loss_flags_old, .late_init = &omap44xx_prm_late_init, + .assert_hardreset = omap4_prminst_assert_hardreset, }; int __init omap44xx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index ee2b5222eac0..4f8c22075d39 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -422,6 +422,26 @@ void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx) __func__); } +/** + * omap_prm_assert_hardreset - assert hardreset for an IP block + * @shift: register bit shift corresponding to the reset line + * @part: PRM partition + * @prm_mod: PRM submodule base or instance offset + * @offset: register offset + * + * Asserts a hardware reset line for an IP block. + */ +int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) +{ + if (!prm_ll_data->assert_hardreset) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return -EINVAL; + } + + return prm_ll_data->assert_hardreset(shift, part, prm_mod, offset); +} + /** * prm_register - register per-SoC low-level data with the PRM * @pld: low-level per-SoC OMAP PRM data & function pointers to register -- cgit v1.2.3-59-g8ed1b From 37fb59d7e0b471f3aacd26bfdbb64a4dc71f189b Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:25 -0700 Subject: ARM: OMAP2+: PRM: add generic API for deasserting hardware reset PRM driver now has a generic API for deasserting hardware resets. SoC specific support functions are registered through the prm_ll_data. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 22 ++++++++++------------ arch/arm/mach-omap2/prm.h | 7 +++++++ arch/arm/mach-omap2/prm2xxx.c | 1 + arch/arm/mach-omap2/prm2xxx_3xxx.c | 7 ++++++- arch/arm/mach-omap2/prm2xxx_3xxx.h | 4 +++- arch/arm/mach-omap2/prm33xx.c | 8 ++++++-- arch/arm/mach-omap2/prm33xx.h | 2 -- arch/arm/mach-omap2/prm3xxx.c | 1 + arch/arm/mach-omap2/prm44xx.c | 1 + arch/arm/mach-omap2/prm_common.c | 24 ++++++++++++++++++++++++ arch/arm/mach-omap2/prminst44xx.c | 10 +++++++--- arch/arm/mach-omap2/prminst44xx.h | 5 +++-- 12 files changed, 69 insertions(+), 23 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 66198e57708f..4159368edfe7 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2932,9 +2932,8 @@ static int _omap2_assert_hardreset(struct omap_hwmod *oh, static int _omap2_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, - ohri->rst_shift, - ohri->st_shift); + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0, + oh->prcm.omap2.module_offs, 0, 0); } /** @@ -3001,10 +3000,10 @@ static int _omap4_deassert_hardreset(struct omap_hwmod *oh, if (ohri->st_shift) pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", oh->name, ohri->name); - return omap4_prminst_deassert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_deassert_hardreset(ohri->rst_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs, 0); } /** @@ -3067,11 +3066,10 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return am33xx_prm_deassert_hardreset(ohri->rst_shift, - ohri->st_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs, - oh->prcm.omap4.rstst_offs); + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs, + oh->prcm.omap4.rstst_offs); } /** diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 9b8711b6adde..26bf3e604d3c 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -129,6 +129,7 @@ struct prm_reset_src_map { * @clear_context_loss_flags_old: ptr to the SoC PRM context loss flag clear fn * @late_init: ptr to the late init function * @assert_hardreset: ptr to the SoC PRM hardreset assert impl + * @deassert_hardreset: ptr to the SoC PRM hardreset deassert impl * * XXX @was_any_context_lost_old and @clear_context_loss_flags_old are * deprecated. @@ -139,12 +140,18 @@ struct prm_ll_data { void (*clear_context_loss_flags_old)(u8 part, s16 inst, u16 idx); int (*late_init)(void); int (*assert_hardreset)(u8 shift, u8 part, s16 prm_mod, u16 offset); + int (*deassert_hardreset)(u8 shift, u8 st_shift, u8 part, s16 prm_mod, + u16 offset, u16 st_offset); + int (*is_hardreset_asserted)(u8 shift, u8 part, s16 prm_mod, + u16 offset); }; extern int prm_register(struct prm_ll_data *pld); extern int prm_unregister(struct prm_ll_data *pld); int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset); +int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod, + u16 offset, u16 st_offset); extern u32 prm_read_reset_sources(void); extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx); extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx); diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c index fa4448b9f716..343fc734c61e 100644 --- a/arch/arm/mach-omap2/prm2xxx.c +++ b/arch/arm/mach-omap2/prm2xxx.c @@ -213,6 +213,7 @@ struct pwrdm_ops omap2_pwrdm_operations = { static struct prm_ll_data omap2xxx_prm_ll_data = { .read_reset_sources = &omap2xxx_prm_read_reset_sources, .assert_hardreset = &omap2_prm_assert_hardreset, + .deassert_hardreset = &omap2_prm_deassert_hardreset, }; int __init omap2xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index 8758cd6f2eed..9466b1ea63a9 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -66,6 +66,10 @@ int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) * @prm_mod: PRM submodule base (e.g. CORE_MOD) * @rst_shift: register bit shift corresponding to the reset line to deassert * @st_shift: register bit shift for the status of the deasserted submodule + * @part: PRM partition, not used for OMAP2 + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @rst_offset: reset register offset, not used for OMAP2 + * @st_offset: reset status register offset, not used for OMAP2 * * Some IPs like dsp or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -76,7 +80,8 @@ int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) * -EINVAL upon an argument error, -EEXIST if the submodule was already out * of reset, or -EBUSY if the submodule did not exit reset promptly. */ -int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift) +int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part, + s16 prm_mod, u16 rst_offset, u16 st_offset) { u32 rst, st; int c; diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h index 967496220f58..253d4148737d 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h @@ -103,7 +103,9 @@ static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset); -extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift); +int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part, + s16 prm_mod, u16 reset_offset, + u16 st_offset); extern int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst); extern int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm); diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index 992a40e72284..ea0fea68e36c 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -98,6 +98,8 @@ static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst, * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and * wait * @shift: register bit shift corresponding to the reset line to deassert + * @st_shift: reset status register bit shift corresponding to the reset line + * @part: PRM partition, not used for AM33xx * @inst: CM instance register offset (*_INST macro) * @rstctrl_reg: RM_RSTCTRL register address for this module * @rstst_reg: RM_RSTST register address for this module @@ -111,8 +113,9 @@ static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst, * -EINVAL upon an argument error, -EEXIST if the submodule was already out * of reset, or -EBUSY if the submodule did not exit reset promptly. */ -int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, - u16 rstctrl_offs, u16 rstst_offs) +static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, + s16 inst, u16 rstctrl_offs, + u16 rstst_offs) { int c; u32 mask = 1 << st_shift; @@ -347,6 +350,7 @@ struct pwrdm_ops am33xx_pwrdm_operations = { static struct prm_ll_data am33xx_prm_ll_data = { .assert_hardreset = am33xx_prm_assert_hardreset, + .deassert_hardreset = am33xx_prm_deassert_hardreset, }; int __init am33xx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h index 1d9aad8e84f3..6d483e02c104 100644 --- a/arch/arm/mach-omap2/prm33xx.h +++ b/arch/arm/mach-omap2/prm33xx.h @@ -124,8 +124,6 @@ extern u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); extern void am33xx_prm_global_warm_sw_reset(void); extern int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs); -extern int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, - u16 rstctrl_offs, u16 rstst_offs); int am33xx_prm_init(void); #endif /* ASSEMBLER */ diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index 8d9a7d49d6dc..7298311c9ab7 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -665,6 +665,7 @@ static struct prm_ll_data omap3xxx_prm_ll_data = { .read_reset_sources = &omap3xxx_prm_read_reset_sources, .late_init = &omap3xxx_prm_late_init, .assert_hardreset = &omap2_prm_assert_hardreset, + .deassert_hardreset = &omap2_prm_deassert_hardreset, }; int __init omap3xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index 1c86270014ed..0da2ba854412 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -689,6 +689,7 @@ static struct prm_ll_data omap44xx_prm_ll_data = { .clear_context_loss_flags_old = &omap44xx_prm_clear_context_loss_flags_old, .late_init = &omap44xx_prm_late_init, .assert_hardreset = omap4_prminst_assert_hardreset, + .deassert_hardreset = omap4_prminst_deassert_hardreset, }; int __init omap44xx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index 4f8c22075d39..912d99c4d75d 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -442,6 +442,30 @@ int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) return prm_ll_data->assert_hardreset(shift, part, prm_mod, offset); } +/** + * omap_prm_deassert_hardreset - deassert hardreset for an IP block + * @shift: register bit shift corresponding to the reset line + * @st_shift: reset status bit shift corresponding to the reset line + * @part: PRM partition + * @prm_mod: PRM submodule base or instance offset + * @offset: register offset + * @st_offset: status register offset + * + * Deasserts a hardware reset line for an IP block. + */ +int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod, + u16 offset, u16 st_offset) +{ + if (!prm_ll_data->deassert_hardreset) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return -EINVAL; + } + + return prm_ll_data->deassert_hardreset(shift, st_shift, part, prm_mod, + offset, st_offset); +} + /** * prm_register - register per-SoC low-level data with the PRM * @pld: low-level per-SoC OMAP PRM data & function pointers to register diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c index 225e0258d76d..8adf7b1a1dce 100644 --- a/arch/arm/mach-omap2/prminst44xx.c +++ b/arch/arm/mach-omap2/prminst44xx.c @@ -148,8 +148,12 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, /** * omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and * wait - * @rstctrl_reg: RM_RSTCTRL register address for this module * @shift: register bit shift corresponding to the reset line to deassert + * @st_shift: status bit offset, not used for OMAP4+ + * @part: PRM partition + * @inst: PRM instance offset + * @rstctrl_offs: reset register offset + * @st_offs: reset status register offset, not used for OMAP4+ * * Some IPs like dsp, ipu or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -160,8 +164,8 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, * -EINVAL upon an argument error, -EEXIST if the submodule was already out * of reset, or -EBUSY if the submodule did not exit reset promptly. */ -int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst, - u16 rstctrl_offs) +int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst, + u16 rstctrl_offs, u16 st_offs) { int c; u32 mask = 1 << shift; diff --git a/arch/arm/mach-omap2/prminst44xx.h b/arch/arm/mach-omap2/prminst44xx.h index 583aa3774571..fb1c9d7a2f9d 100644 --- a/arch/arm/mach-omap2/prminst44xx.h +++ b/arch/arm/mach-omap2/prminst44xx.h @@ -30,8 +30,9 @@ extern int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst, u16 rstctrl_offs); extern int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, u16 rstctrl_offs); -extern int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst, - u16 rstctrl_offs); +int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, + s16 inst, u16 rstctrl_offs, + u16 rstst_offs); extern void omap_prm_base_init(void); -- cgit v1.2.3-59-g8ed1b From 1bc28b3472dc44e6282b464fdb851adcea859be7 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:25 -0700 Subject: ARM: OMAP2+: PRM: add generic API for checking hardreset status PRM driver now has a generic API for checking hardreset status. SoC specific support functions are registered through the prm_ll_data. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 19 ++++++++++--------- arch/arm/mach-omap2/prm.h | 1 + arch/arm/mach-omap2/prm2xxx.c | 1 + arch/arm/mach-omap2/prm2xxx_3xxx.c | 6 ++++-- arch/arm/mach-omap2/prm2xxx_3xxx.h | 2 +- arch/arm/mach-omap2/prm33xx.c | 9 ++++++--- arch/arm/mach-omap2/prm33xx.h | 2 -- arch/arm/mach-omap2/prm3xxx.c | 1 + arch/arm/mach-omap2/prm44xx.c | 1 + arch/arm/mach-omap2/prm_common.c | 20 ++++++++++++++++++++ 10 files changed, 45 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 4159368edfe7..48f0d4d29c1b 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2951,8 +2951,8 @@ static int _omap2_deassert_hardreset(struct omap_hwmod *oh, static int _omap2_is_hardreset_asserted(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, - ohri->st_shift); + return omap_prm_is_hardreset_asserted(ohri->st_shift, 0, + oh->prcm.omap2.module_offs, 0); } /** @@ -3024,10 +3024,11 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh, if (!oh->clkdm) return -EINVAL; - return omap4_prminst_is_hardreset_asserted(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_is_hardreset_asserted(ohri->rst_shift, + oh->clkdm->pwrdm.ptr-> + prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3087,9 +3088,9 @@ static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return am33xx_prm_is_hardreset_asserted(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_is_hardreset_asserted(ohri->rst_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /* Public functions */ diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 26bf3e604d3c..d72dd7120920 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -152,6 +152,7 @@ extern int prm_unregister(struct prm_ll_data *pld); int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset); int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod, u16 offset, u16 st_offset); +int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset); extern u32 prm_read_reset_sources(void); extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx); extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx); diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c index 343fc734c61e..54ae55520da6 100644 --- a/arch/arm/mach-omap2/prm2xxx.c +++ b/arch/arm/mach-omap2/prm2xxx.c @@ -214,6 +214,7 @@ static struct prm_ll_data omap2xxx_prm_ll_data = { .read_reset_sources = &omap2xxx_prm_read_reset_sources, .assert_hardreset = &omap2_prm_assert_hardreset, .deassert_hardreset = &omap2_prm_deassert_hardreset, + .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, }; int __init omap2xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index 9466b1ea63a9..cc3341f263cd 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -24,14 +24,16 @@ /** * omap2_prm_is_hardreset_asserted - read the HW reset line state of * submodules contained in the hwmod module - * @prm_mod: PRM submodule base (e.g. CORE_MOD) * @shift: register bit shift corresponding to the reset line to check + * @part: PRM partition, ignored for OMAP2 + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @offset: register offset, ignored for OMAP2 * * Returns 1 if the (sub)module hardreset line is currently asserted, * 0 if the (sub)module hardreset line is not currently asserted, or * -EINVAL if called while running on a non-OMAP2/3 chip. */ -int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) +int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset) { return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, (1 << shift)); diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h index 253d4148737d..f57e29b0e041 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h @@ -100,7 +100,7 @@ static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) } /* These omap2_ PRM functions apply to both OMAP2 and 3 */ -extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); +int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset); int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset); int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part, diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index ea0fea68e36c..3cbfb78ed5e9 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -52,6 +52,7 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) * am33xx_prm_is_hardreset_asserted - read the HW reset line state of * submodules contained in the hwmod module * @shift: register bit shift corresponding to the reset line to check + * @part: PRM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) * @rstctrl_offs: RM_RSTCTRL register address offset for this module * @@ -59,7 +60,8 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) * 0 if the (sub)module hardreset line is not currently asserted, or * -EINVAL upon parameter error. */ -int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) +static int am33xx_prm_is_hardreset_asserted(u8 shift, u8 part, s16 inst, + u16 rstctrl_offs) { u32 v; @@ -121,7 +123,7 @@ static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, u32 mask = 1 << st_shift; /* Check the current status to avoid de-asserting the line twice */ - if (am33xx_prm_is_hardreset_asserted(shift, inst, rstctrl_offs) == 0) + if (am33xx_prm_is_hardreset_asserted(shift, 0, inst, rstctrl_offs) == 0) return -EEXIST; /* Clear the reset status by writing 1 to the status bit */ @@ -133,7 +135,7 @@ static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs); /* wait the status to be set */ - omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, inst, + omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, 0, inst, rstst_offs), MAX_MODULE_HARDRESET_WAIT, c); @@ -351,6 +353,7 @@ struct pwrdm_ops am33xx_pwrdm_operations = { static struct prm_ll_data am33xx_prm_ll_data = { .assert_hardreset = am33xx_prm_assert_hardreset, .deassert_hardreset = am33xx_prm_deassert_hardreset, + .is_hardreset_asserted = am33xx_prm_is_hardreset_asserted, }; int __init am33xx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h index 6d483e02c104..49ad5b862919 100644 --- a/arch/arm/mach-omap2/prm33xx.h +++ b/arch/arm/mach-omap2/prm33xx.h @@ -122,8 +122,6 @@ extern u32 am33xx_prm_read_reg(s16 inst, u16 idx); extern void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx); extern u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); extern void am33xx_prm_global_warm_sw_reset(void); -extern int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, - u16 rstctrl_offs); int am33xx_prm_init(void); #endif /* ASSEMBLER */ diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index 7298311c9ab7..956e0ca2fb64 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -666,6 +666,7 @@ static struct prm_ll_data omap3xxx_prm_ll_data = { .late_init = &omap3xxx_prm_late_init, .assert_hardreset = &omap2_prm_assert_hardreset, .deassert_hardreset = &omap2_prm_deassert_hardreset, + .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, }; int __init omap3xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index 0da2ba854412..d357ca901b75 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -690,6 +690,7 @@ static struct prm_ll_data omap44xx_prm_ll_data = { .late_init = &omap44xx_prm_late_init, .assert_hardreset = omap4_prminst_assert_hardreset, .deassert_hardreset = omap4_prminst_deassert_hardreset, + .is_hardreset_asserted = omap4_prminst_is_hardreset_asserted, }; int __init omap44xx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index 912d99c4d75d..ce0434a16ad6 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -466,6 +466,26 @@ int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod, offset, st_offset); } +/** + * omap_prm_is_hardreset_asserted - check the hardreset status for an IP block + * @shift: register bit shift corresponding to the reset line + * @part: PRM partition + * @prm_mod: PRM submodule base or instance offset + * @offset: register offset + * + * Checks if a hardware reset line for an IP block is enabled or not. + */ +int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset) +{ + if (!prm_ll_data->is_hardreset_asserted) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return -EINVAL; + } + + return prm_ll_data->is_hardreset_asserted(shift, part, prm_mod, offset); +} + /** * prm_register - register per-SoC low-level data with the PRM * @pld: low-level per-SoC OMAP PRM data & function pointers to register -- cgit v1.2.3-59-g8ed1b From ab6c9bbf28e2b251a61261a95e99d588da73e9a6 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:25 -0700 Subject: ARM: OMAP4: CM: move public definitions from cminst44xx.h to cm44xx.h cminst44xx.h will be removed, thus move the public APIs to cm44xx.h header. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/cm44xx.h | 3 +++ arch/arm/mach-omap2/cminst44xx.h | 3 --- arch/arm/mach-omap2/io.c | 2 +- arch/arm/mach-omap2/omap_hwmod.c | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h index 3380beeace6e..728d06a4af19 100644 --- a/arch/arm/mach-omap2/cm44xx.h +++ b/arch/arm/mach-omap2/cm44xx.h @@ -23,4 +23,7 @@ #define OMAP4_CM_CLKSTCTRL 0x0000 #define OMAP4_CM_STATICDEP 0x0004 +void omap_cm_base_init(void); +int omap4_cm_init(void); + #endif diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h index ffbd7219bb81..3ef3bf615078 100644 --- a/arch/arm/mach-omap2/cminst44xx.h +++ b/arch/arm/mach-omap2/cminst44xx.h @@ -26,7 +26,4 @@ u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, extern u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask); -extern void omap_cm_base_init(void); -int omap4_cm_init(void); - #endif diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 55380bb89a54..4fc838354e31 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -46,11 +46,11 @@ #include "cm2xxx.h" #include "cm3xxx.h" #include "cm33xx.h" +#include "cm44xx.h" #include "prm.h" #include "cm.h" #include "prcm_mpu44xx.h" #include "prminst44xx.h" -#include "cminst44xx.h" #include "prm2xxx.h" #include "prm3xxx.h" #include "prm33xx.h" diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 48f0d4d29c1b..e8098ca28dc5 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -153,7 +153,6 @@ #include "powerdomain.h" #include "cm2xxx.h" #include "cm3xxx.h" -#include "cminst44xx.h" #include "cm33xx.h" #include "prm.h" #include "prm3xxx.h" -- cgit v1.2.3-59-g8ed1b From 4215afaf3d540ffaee3274ede4d298132d03d773 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:25 -0700 Subject: ARM: OMAP4: CM: make cminst direct register access functions static These shall not be accessed outside the CM driver. This also removes the need for the cminst44xx.h header. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/cminst44xx.c | 20 ++++++++++---------- arch/arm/mach-omap2/cminst44xx.h | 29 ----------------------------- 2 files changed, 10 insertions(+), 39 deletions(-) delete mode 100644 arch/arm/mach-omap2/cminst44xx.h diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index ac034109078e..95a8cff66aff 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -26,7 +26,6 @@ #include "cm1_44xx.h" #include "cm2_44xx.h" #include "cm44xx.h" -#include "cminst44xx.h" #include "cm-regbits-34xx.h" #include "prcm44xx.h" #include "prm44xx.h" @@ -74,6 +73,8 @@ void omap_cm_base_init(void) /* Private functions */ +static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx); + /** * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield * @part: PRCM partition ID that the CM_CLKCTRL register exists in @@ -110,10 +111,8 @@ static bool _is_module_ready(u8 part, u16 inst, u16 clkctrl_offs) v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; } -/* Public functions */ - /* Read a register in a CM instance */ -u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) +static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) { BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || part == OMAP4430_INVALID_PRCM_PARTITION || @@ -122,7 +121,7 @@ u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) } /* Write into a register in a CM instance */ -void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) +static void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) { BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || part == OMAP4430_INVALID_PRCM_PARTITION || @@ -131,8 +130,8 @@ void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) } /* Read-modify-write a register in CM1. Caller must lock */ -u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, - s16 idx) +static u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, + s16 idx) { u32 v; @@ -144,17 +143,18 @@ u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, return v; } -u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) +static u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) { return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx); } -u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) +static u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, + s16 idx) { return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx); } -u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask) +static u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask) { u32 v; diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h deleted file mode 100644 index 3ef3bf615078..000000000000 --- a/arch/arm/mach-omap2/cminst44xx.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * OMAP4 Clock Management (CM) function prototypes - * - * Copyright (C) 2010 Nokia Corporation - * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef __ARCH_ASM_MACH_OMAP2_CMINST44XX_H -#define __ARCH_ASM_MACH_OMAP2_CMINST44XX_H - -/* - * In an ideal world, we would not export these low-level functions, - * but this will probably take some time to fix properly - */ -u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx); -void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx); -u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, - u16 inst, s16 idx); -u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, - s16 idx); -u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, - s16 idx); -extern u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, - u32 mask); - -#endif -- cgit v1.2.3-59-g8ed1b From 88f9474f18b4f235b7e9a91d76810fd616fe611a Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:25 -0700 Subject: ARM: OMAP4+: CM: remove omap4_cm1/cm2_* functions These are not used for anything, so remove both the implementations and header file references. Signed-off-by: Tero Kristo Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/cm1_44xx.h | 2 -- arch/arm/mach-omap2/cm1_54xx.h | 2 -- arch/arm/mach-omap2/cm1_7xx.h | 2 -- arch/arm/mach-omap2/cm2_44xx.h | 2 -- arch/arm/mach-omap2/cm2_54xx.h | 2 -- arch/arm/mach-omap2/cm2_7xx.h | 2 -- arch/arm/mach-omap2/cm44xx.c | 49 -------------------------------------- arch/arm/mach-omap2/cm_44xx_54xx.h | 36 ---------------------------- 9 files changed, 1 insertion(+), 98 deletions(-) delete mode 100644 arch/arm/mach-omap2/cm44xx.c delete mode 100644 arch/arm/mach-omap2/cm_44xx_54xx.h diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index d9e94122073e..3b653b3ac268 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -113,7 +113,7 @@ obj-y += prm_common.o cm_common.o obj-$(CONFIG_ARCH_OMAP2) += prm2xxx_3xxx.o prm2xxx.o cm2xxx.o obj-$(CONFIG_ARCH_OMAP3) += prm2xxx_3xxx.o prm3xxx.o cm3xxx.o obj-$(CONFIG_ARCH_OMAP3) += vc3xxx_data.o vp3xxx_data.o -omap-prcm-4-5-common = cminst44xx.o cm44xx.o prm44xx.o \ +omap-prcm-4-5-common = cminst44xx.o prm44xx.o \ prcm_mpu44xx.o prminst44xx.o \ vc44xx_data.o vp44xx_data.o obj-$(CONFIG_ARCH_OMAP4) += $(omap-prcm-4-5-common) diff --git a/arch/arm/mach-omap2/cm1_44xx.h b/arch/arm/mach-omap2/cm1_44xx.h index 5ae8fe39d6ee..a5949927b661 100644 --- a/arch/arm/mach-omap2/cm1_44xx.h +++ b/arch/arm/mach-omap2/cm1_44xx.h @@ -25,8 +25,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM1_44XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_44XX_H -#include "cm_44xx_54xx.h" - /* CM1 base address */ #define OMAP4430_CM1_BASE 0x4a004000 diff --git a/arch/arm/mach-omap2/cm1_54xx.h b/arch/arm/mach-omap2/cm1_54xx.h index 90b3348e6672..fd245dfa7391 100644 --- a/arch/arm/mach-omap2/cm1_54xx.h +++ b/arch/arm/mach-omap2/cm1_54xx.h @@ -22,8 +22,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM1_54XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_54XX_H -#include "cm_44xx_54xx.h" - /* CM1 base address */ #define OMAP54XX_CM_CORE_AON_BASE 0x4a004000 diff --git a/arch/arm/mach-omap2/cm1_7xx.h b/arch/arm/mach-omap2/cm1_7xx.h index ca6fa1febaac..2f1c09eea021 100644 --- a/arch/arm/mach-omap2/cm1_7xx.h +++ b/arch/arm/mach-omap2/cm1_7xx.h @@ -23,8 +23,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM1_7XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_7XX_H -#include "cm_44xx_54xx.h" - /* CM1 base address */ #define DRA7XX_CM_CORE_AON_BASE 0x4a005000 diff --git a/arch/arm/mach-omap2/cm2_44xx.h b/arch/arm/mach-omap2/cm2_44xx.h index ee5136d7cdda..7521abf3d830 100644 --- a/arch/arm/mach-omap2/cm2_44xx.h +++ b/arch/arm/mach-omap2/cm2_44xx.h @@ -25,8 +25,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM2_44XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_44XX_H -#include "cm_44xx_54xx.h" - /* CM2 base address */ #define OMAP4430_CM2_BASE 0x4a008000 diff --git a/arch/arm/mach-omap2/cm2_54xx.h b/arch/arm/mach-omap2/cm2_54xx.h index 2683231b299b..ff4040c196d8 100644 --- a/arch/arm/mach-omap2/cm2_54xx.h +++ b/arch/arm/mach-omap2/cm2_54xx.h @@ -21,8 +21,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM2_54XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_54XX_H -#include "cm_44xx_54xx.h" - /* CM2 base address */ #define OMAP54XX_CM_CORE_BASE 0x4a008000 diff --git a/arch/arm/mach-omap2/cm2_7xx.h b/arch/arm/mach-omap2/cm2_7xx.h index e966e3a3c931..ce63fdb68056 100644 --- a/arch/arm/mach-omap2/cm2_7xx.h +++ b/arch/arm/mach-omap2/cm2_7xx.h @@ -22,8 +22,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM2_7XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_7XX_H -#include "cm_44xx_54xx.h" - /* CM2 base address */ #define DRA7XX_CM_CORE_BASE 0x4a008000 diff --git a/arch/arm/mach-omap2/cm44xx.c b/arch/arm/mach-omap2/cm44xx.c deleted file mode 100644 index fe5cc7bae489..000000000000 --- a/arch/arm/mach-omap2/cm44xx.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * OMAP4 CM1, CM2 module low-level functions - * - * Copyright (C) 2010 Nokia Corporation - * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * These functions are intended to be used only by the cminst44xx.c file. - * XXX Perhaps we should just move them there and make them static. - */ - -#include -#include -#include -#include -#include - -#include "cm.h" -#include "cm1_44xx.h" -#include "cm2_44xx.h" - -/* CM1 hardware module low-level functions */ - -/* Read a register in CM1 */ -u32 omap4_cm1_read_inst_reg(s16 inst, u16 reg) -{ - return readl_relaxed(cm_base + inst + reg); -} - -/* Write into a register in CM1 */ -void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 reg) -{ - writel_relaxed(val, cm_base + inst + reg); -} - -/* Read a register in CM2 */ -u32 omap4_cm2_read_inst_reg(s16 inst, u16 reg) -{ - return readl_relaxed(cm2_base + inst + reg); -} - -/* Write into a register in CM2 */ -void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) -{ - writel_relaxed(val, cm2_base + inst + reg); -} diff --git a/arch/arm/mach-omap2/cm_44xx_54xx.h b/arch/arm/mach-omap2/cm_44xx_54xx.h deleted file mode 100644 index cbb211690321..000000000000 --- a/arch/arm/mach-omap2/cm_44xx_54xx.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * OMAP44xx and OMAP54xx CM1/CM2 function prototypes - * - * Copyright (C) 2009-2013 Texas Instruments, Inc. - * Copyright (C) 2009-2010 Nokia Corporation - * - * Paul Walmsley (paul@pwsan.com) - * Rajendra Nayak (rnayak@ti.com) - * Benoit Cousson (b-cousson@ti.com) - * - * This file is automatically generated from the OMAP hardware databases. - * We respectfully ask that any modifications to this file be coordinated - * with the public linux-omap@vger.kernel.org mailing list and the - * authors above to ensure that the autogeneration scripts are kept - * up-to-date with the file contents. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#ifndef __ARCH_ARM_MACH_OMAP2_CM_44XX_54XX_H -#define __ARCH_ARM_MACH_OMAP2_CM_44XX_55XX_H - -/* CM1 Function prototypes */ -extern u32 omap4_cm1_read_inst_reg(s16 inst, u16 idx); -extern void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 idx); -extern u32 omap4_cm1_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); - -/* CM2 Function prototypes */ -extern u32 omap4_cm2_read_inst_reg(s16 inst, u16 idx); -extern void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 idx); -extern u32 omap4_cm2_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); - -#endif -- cgit v1.2.3-59-g8ed1b From 840b7eb8342a64ad6fc6a2140262c3fed3676bd4 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:25 -0700 Subject: ARM: AM33xx: PRM: move global warm reset implementation to driver Moved the implementation from am33xx-restart.c to the prm33xx.c file to isolate the PRM register accesses to be private for PRM driver. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/am33xx-restart.c | 9 +-------- arch/arm/mach-omap2/prm33xx.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-omap2/am33xx-restart.c b/arch/arm/mach-omap2/am33xx-restart.c index c88d8df753c2..728638913cd1 100644 --- a/arch/arm/mach-omap2/am33xx-restart.c +++ b/arch/arm/mach-omap2/am33xx-restart.c @@ -24,12 +24,5 @@ void am33xx_restart(enum reboot_mode mode, const char *cmd) { /* TODO: Handle mode and cmd if necessary */ - am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK, - AM33XX_RST_GLOBAL_WARM_SW_MASK, - AM33XX_PRM_DEVICE_MOD, - AM33XX_PRM_RSTCTRL_OFFSET); - - /* OCP barrier */ - (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD, - AM33XX_PRM_RSTCTRL_OFFSET); + am33xx_prm_global_warm_sw_reset(); } diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index 3cbfb78ed5e9..03960bc9b419 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -23,6 +23,10 @@ #include "prm33xx.h" #include "prm-regbits-33xx.h" +#define AM33XX_PRM_RSTCTRL_OFFSET 0x0000 + +#define AM33XX_RST_GLOBAL_WARM_SW_MASK (1 << 0) + /* Read a register in a PRM instance */ u32 am33xx_prm_read_reg(s16 inst, u16 idx) { @@ -332,6 +336,23 @@ static int am33xx_check_vcvp(void) return 0; } +/** + * am33xx_prm_global_warm_sw_reset - reboot the device via warm reset + * + * Immediately reboots the device through warm reset. + */ +void am33xx_prm_global_warm_sw_reset(void) +{ + am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK, + AM33XX_RST_GLOBAL_WARM_SW_MASK, + AM33XX_PRM_DEVICE_MOD, + AM33XX_PRM_RSTCTRL_OFFSET); + + /* OCP barrier */ + (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD, + AM33XX_PRM_RSTCTRL_OFFSET); +} + struct pwrdm_ops am33xx_pwrdm_operations = { .pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst, .pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst, -- cgit v1.2.3-59-g8ed1b From 85d6670f1bef12b5d014a604fc2e7db3a74a7199 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:25 -0700 Subject: ARM: AM33xx: PRM: make direct register access functions static These should not be accessed outside driver, thus removed the APIs from the header file and made the implementation static. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/prm33xx.c | 6 +++--- arch/arm/mach-omap2/prm33xx.h | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index 03960bc9b419..4a843f7cac02 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -28,19 +28,19 @@ #define AM33XX_RST_GLOBAL_WARM_SW_MASK (1 << 0) /* Read a register in a PRM instance */ -u32 am33xx_prm_read_reg(s16 inst, u16 idx) +static u32 am33xx_prm_read_reg(s16 inst, u16 idx) { return readl_relaxed(prm_base + inst + idx); } /* Write into a register in a PRM instance */ -void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) +static void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) { writel_relaxed(val, prm_base + inst + idx); } /* Read-modify-write a register in PRM. Caller must lock */ -u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) +static u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) { u32 v; diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h index 49ad5b862919..937d56e70b3e 100644 --- a/arch/arm/mach-omap2/prm33xx.h +++ b/arch/arm/mach-omap2/prm33xx.h @@ -118,9 +118,6 @@ #define AM33XX_PM_CEFUSE_PWRSTST AM33XX_PRM_REGADDR(AM33XX_PRM_CEFUSE_MOD, 0x0004) #ifndef __ASSEMBLER__ -extern u32 am33xx_prm_read_reg(s16 inst, u16 idx); -extern void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx); -extern u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); extern void am33xx_prm_global_warm_sw_reset(void); int am33xx_prm_init(void); -- cgit v1.2.3-59-g8ed1b From f3f220f046d677b618cae9533c20ecae4d463dc8 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:26 -0700 Subject: ARM: OMAP4: PRM: make omap4_prm_read/write_inst_reg calls static These are not (and should not be) used by anybody outside the PRM driver itself. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/prm44xx.c | 6 +++--- arch/arm/mach-omap2/prm44xx_54xx.h | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index d357ca901b75..15b46463d8b5 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -80,19 +80,19 @@ static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = { /* PRM low-level functions */ /* Read a register in a CM/PRM instance in the PRM module */ -u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) +static u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) { return readl_relaxed(prm_base + inst + reg); } /* Write into a register in a CM/PRM instance in the PRM module */ -void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) +static void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) { writel_relaxed(val, prm_base + inst + reg); } /* Read-modify-write a register in a PRM module. Caller must lock */ -u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg) +static u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg) { u32 v; diff --git a/arch/arm/mach-omap2/prm44xx_54xx.h b/arch/arm/mach-omap2/prm44xx_54xx.h index 8d95aa543ef5..96477e74508d 100644 --- a/arch/arm/mach-omap2/prm44xx_54xx.h +++ b/arch/arm/mach-omap2/prm44xx_54xx.h @@ -26,10 +26,6 @@ /* Function prototypes */ #ifndef __ASSEMBLER__ -extern u32 omap4_prm_read_inst_reg(s16 inst, u16 idx); -extern void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 idx); -extern u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); - /* OMAP4/OMAP5-specific VP functions */ u32 omap4_prm_vp_check_txdone(u8 vp_id); void omap4_prm_vp_clear_txdone(u8 vp_id); -- cgit v1.2.3-59-g8ed1b From c8e069d7a6a7963b44264a3c9e80aa4d13fd3093 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:26 -0700 Subject: ARM: OMAP3: PRM: make PRCM interrupt handler related functions static These are not needed outside the PRM driver, so make them static and remove the prototypes from the public header. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/prm3xxx.c | 13 +++++++++---- arch/arm/mach-omap2/prm3xxx.h | 6 ------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index 956e0ca2fb64..cb71354c503c 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -30,6 +30,11 @@ #include "cm3xxx.h" #include "cm-regbits-34xx.h" +static void omap3xxx_prm_read_pending_irqs(unsigned long *events); +static void omap3xxx_prm_ocp_barrier(void); +static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); +static void omap3xxx_prm_restore_irqen(u32 *saved_mask); + static const struct omap_prcm_irq omap3_prcm_irqs[] = { OMAP_PRCM_IRQ("wkup", 0, 0), OMAP_PRCM_IRQ("io", 9, 1), @@ -147,7 +152,7 @@ void omap3xxx_prm_dpll3_reset(void) * MPU IRQs, and store the result into the u32 pointed to by @events. * No return value. */ -void omap3xxx_prm_read_pending_irqs(unsigned long *events) +static void omap3xxx_prm_read_pending_irqs(unsigned long *events) { u32 mask, st; @@ -166,7 +171,7 @@ void omap3xxx_prm_read_pending_irqs(unsigned long *events) * block, to avoid race conditions after acknowledging or clearing IRQ * bits. No return value. */ -void omap3xxx_prm_ocp_barrier(void) +static void omap3xxx_prm_ocp_barrier(void) { omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET); } @@ -182,7 +187,7 @@ void omap3xxx_prm_ocp_barrier(void) * returning; otherwise, spurious interrupts might occur. No return * value. */ -void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) +static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) { saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); @@ -202,7 +207,7 @@ void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) * barrier should be needed here; any pending PRM interrupts will fire * once the writes reach the PRM. No return value. */ -void omap3xxx_prm_restore_irqen(u32 *saved_mask) +static void omap3xxx_prm_restore_irqen(u32 *saved_mask) { omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); diff --git a/arch/arm/mach-omap2/prm3xxx.h b/arch/arm/mach-omap2/prm3xxx.h index bc37d42a8704..5d993d2df7ef 100644 --- a/arch/arm/mach-omap2/prm3xxx.h +++ b/arch/arm/mach-omap2/prm3xxx.h @@ -152,12 +152,6 @@ static inline void omap3xxx_prm_reconfigure_io_chain(void) } #endif -/* PRM interrupt-related functions */ -extern void omap3xxx_prm_read_pending_irqs(unsigned long *events); -extern void omap3xxx_prm_ocp_barrier(void); -extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); -extern void omap3xxx_prm_restore_irqen(u32 *saved_mask); - extern void omap3xxx_prm_dpll3_reset(void); extern int __init omap3xxx_prm_init(void); -- cgit v1.2.3-59-g8ed1b From 28db51f428bf284dc12a60a0c0a12fa522a530f5 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:26 -0700 Subject: ARM: OMAP4: PRM: make PRCM interrupt handler related functions static These are not needed outside the PRM driver, so make them static and remove the prototypes from the public header. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/prm44xx.c | 13 +++++++++---- arch/arm/mach-omap2/prm44xx_54xx.h | 6 ------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index 15b46463d8b5..bfcc3562e015 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -32,6 +32,11 @@ /* Static data */ +static void omap44xx_prm_read_pending_irqs(unsigned long *events); +static void omap44xx_prm_ocp_barrier(void); +static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask); +static void omap44xx_prm_restore_irqen(u32 *saved_mask); + static const struct omap_prcm_irq omap4_prcm_irqs[] = { OMAP_PRCM_IRQ("io", 9, 1), }; @@ -207,7 +212,7 @@ static inline u32 _read_pending_irq_reg(u16 irqen_offs, u16 irqst_offs) * MPU IRQs, and store the result into the two u32s pointed to by @events. * No return value. */ -void omap44xx_prm_read_pending_irqs(unsigned long *events) +static void omap44xx_prm_read_pending_irqs(unsigned long *events) { events[0] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_OFFSET, OMAP4_PRM_IRQSTATUS_MPU_OFFSET); @@ -224,7 +229,7 @@ void omap44xx_prm_read_pending_irqs(unsigned long *events) * block, to avoid race conditions after acknowledging or clearing IRQ * bits. No return value. */ -void omap44xx_prm_ocp_barrier(void) +static void omap44xx_prm_ocp_barrier(void) { omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, OMAP4_REVISION_PRM_OFFSET); @@ -241,7 +246,7 @@ void omap44xx_prm_ocp_barrier(void) * interrupts reaches the PRM before returning; otherwise, spurious * interrupts might occur. No return value. */ -void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) +static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) { saved_mask[0] = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, @@ -270,7 +275,7 @@ void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) * No OCP barrier should be needed here; any pending PRM interrupts will fire * once the writes reach the PRM. No return value. */ -void omap44xx_prm_restore_irqen(u32 *saved_mask) +static void omap44xx_prm_restore_irqen(u32 *saved_mask) { omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_OCP_SOCKET_INST, OMAP4_PRM_IRQENABLE_MPU_OFFSET); diff --git a/arch/arm/mach-omap2/prm44xx_54xx.h b/arch/arm/mach-omap2/prm44xx_54xx.h index 96477e74508d..faa7411c79eb 100644 --- a/arch/arm/mach-omap2/prm44xx_54xx.h +++ b/arch/arm/mach-omap2/prm44xx_54xx.h @@ -47,12 +47,6 @@ static inline void omap44xx_prm_reconfigure_io_chain(void) } #endif -/* PRM interrupt-related functions */ -extern void omap44xx_prm_read_pending_irqs(unsigned long *events); -extern void omap44xx_prm_ocp_barrier(void); -extern void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask); -extern void omap44xx_prm_restore_irqen(u32 *saved_mask); - extern int __init omap44xx_prm_init(void); extern u32 omap44xx_prm_get_reset_sources(void); -- cgit v1.2.3-59-g8ed1b From 4984eeaf71f033d1ca6b644e4fcdef4b3e6a97b4 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:26 -0700 Subject: ARM: OMAP3+: PRM: add generic API for reconfiguring I/O chain This adds a generic API for reconfiguring the I/O chain. The implementation will call the SoC specific function registered during init time. The SoC specific reconfigure functions are also made static, as they don't need to be accessed outside the PRM driver itself. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon [tony@atomide.com: updated for recent omap3 prcm fixes] Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 5 +---- arch/arm/mach-omap2/prm.h | 2 ++ arch/arm/mach-omap2/prm3xxx.c | 13 ++----------- arch/arm/mach-omap2/prm3xxx.h | 8 -------- arch/arm/mach-omap2/prm44xx.c | 3 ++- arch/arm/mach-omap2/prm44xx_54xx.h | 9 --------- arch/arm/mach-omap2/prm_common.c | 16 ++++++++++++++++ 7 files changed, 23 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index e8098ca28dc5..cedbbb5d4825 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1984,10 +1984,7 @@ static void _reconfigure_io_chain(void) spin_lock_irqsave(&io_chain_lock, flags); - if (cpu_is_omap34xx()) - omap3xxx_prm_reconfigure_io_chain(); - else if (cpu_is_omap44xx()) - omap44xx_prm_reconfigure_io_chain(); + omap_prm_reconfigure_io_chain(); spin_unlock_irqrestore(&io_chain_lock, flags); } diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index d72dd7120920..dd802eec0dec 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -157,6 +157,8 @@ extern u32 prm_read_reset_sources(void); extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx); extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx); +void omap_prm_reconfigure_io_chain(void); + #endif diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index cb71354c503c..9da15e9db6d2 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -380,7 +380,7 @@ void __init omap3_prm_init_pm(bool has_uart4, bool has_iva) * The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only * thing we can do is toggle EN_IO bit for earlier omaps. */ -void omap3430_pre_es3_1_reconfigure_io_chain(void) +static void omap3430_pre_es3_1_reconfigure_io_chain(void) { omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN); @@ -398,7 +398,7 @@ void omap3430_pre_es3_1_reconfigure_io_chain(void) * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No * return value. These registers are only available in 3430 es3.1 and later. */ -void omap3_prm_reconfigure_io_chain(void) +static void omap3_prm_reconfigure_io_chain(void) { int i = 0; @@ -420,15 +420,6 @@ void omap3_prm_reconfigure_io_chain(void) omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST); } -/** - * omap3xxx_prm_reconfigure_io_chain - reconfigure I/O chain - */ -void omap3xxx_prm_reconfigure_io_chain(void) -{ - if (omap3_prcm_irq_setup.reconfigure_io_chain) - omap3_prcm_irq_setup.reconfigure_io_chain(); -} - /** * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches * diff --git a/arch/arm/mach-omap2/prm3xxx.h b/arch/arm/mach-omap2/prm3xxx.h index 5d993d2df7ef..321568bc0847 100644 --- a/arch/arm/mach-omap2/prm3xxx.h +++ b/arch/arm/mach-omap2/prm3xxx.h @@ -144,14 +144,6 @@ extern u32 omap3_prm_vcvp_read(u8 offset); extern void omap3_prm_vcvp_write(u32 val, u8 offset); extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); -#ifdef CONFIG_ARCH_OMAP3 -void omap3xxx_prm_reconfigure_io_chain(void); -#else -static inline void omap3xxx_prm_reconfigure_io_chain(void) -{ -} -#endif - extern void omap3xxx_prm_dpll3_reset(void); extern int __init omap3xxx_prm_init(void); diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index bfcc3562e015..e7ac7e209edc 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -36,6 +36,7 @@ static void omap44xx_prm_read_pending_irqs(unsigned long *events); static void omap44xx_prm_ocp_barrier(void); static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask); static void omap44xx_prm_restore_irqen(u32 *saved_mask); +static void omap44xx_prm_reconfigure_io_chain(void); static const struct omap_prcm_irq omap4_prcm_irqs[] = { OMAP_PRCM_IRQ("io", 9, 1), @@ -292,7 +293,7 @@ static void omap44xx_prm_restore_irqen(u32 *saved_mask) * deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted. * No return value. XXX Are the final two steps necessary? */ -void omap44xx_prm_reconfigure_io_chain(void) +static void omap44xx_prm_reconfigure_io_chain(void) { int i = 0; s32 inst = omap4_prmst_get_prm_dev_inst(); diff --git a/arch/arm/mach-omap2/prm44xx_54xx.h b/arch/arm/mach-omap2/prm44xx_54xx.h index faa7411c79eb..f7512515fde5 100644 --- a/arch/arm/mach-omap2/prm44xx_54xx.h +++ b/arch/arm/mach-omap2/prm44xx_54xx.h @@ -38,15 +38,6 @@ extern u32 omap4_prm_vcvp_read(u8 offset); extern void omap4_prm_vcvp_write(u32 val, u8 offset); extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); -#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ - defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM43XX) -void omap44xx_prm_reconfigure_io_chain(void); -#else -static inline void omap44xx_prm_reconfigure_io_chain(void) -{ -} -#endif - extern int __init omap44xx_prm_init(void); extern u32 omap44xx_prm_get_reset_sources(void); diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index ce0434a16ad6..be40824acf5f 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -486,6 +486,22 @@ int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset) return prm_ll_data->is_hardreset_asserted(shift, part, prm_mod, offset); } +/** + * omap_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain + * + * Clear any previously-latched I/O wakeup events and ensure that the + * I/O wakeup gates are aligned with the current mux settings. + * Calls SoC specific I/O chain reconfigure function if available, + * otherwise does nothing. + */ +void omap_prm_reconfigure_io_chain(void) +{ + if (!prcm_irq_setup || !prcm_irq_setup->reconfigure_io_chain) + return; + + prcm_irq_setup->reconfigure_io_chain(); +} + /** * prm_register - register per-SoC low-level data with the PRM * @pld: low-level per-SoC OMAP PRM data & function pointers to register -- cgit v1.2.3-59-g8ed1b From 61c8621e2bd14faad9b89ab2284955b28000bcd5 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Oct 2014 08:39:26 -0700 Subject: ARM: OMAP2+: PRM: provide generic API for system reset This patch combines the various prm_warm_reset calls under a common API prm_reset_system, and adds the SoC specific implementation under prm_ll_data. Signed-off-by: Tero Kristo Acked-by: Paul Walmsley Tested-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/am33xx-restart.c | 5 ++--- arch/arm/mach-omap2/omap2-restart.c | 5 ++--- arch/arm/mach-omap2/omap3-restart.c | 7 ++----- arch/arm/mach-omap2/omap4-restart.c | 6 ++---- arch/arm/mach-omap2/prm.h | 2 ++ arch/arm/mach-omap2/prm2xxx.c | 3 ++- arch/arm/mach-omap2/prm2xxx.h | 1 - arch/arm/mach-omap2/prm33xx.c | 3 ++- arch/arm/mach-omap2/prm33xx.h | 1 - arch/arm/mach-omap2/prm3xxx.c | 3 ++- arch/arm/mach-omap2/prm3xxx.h | 2 -- arch/arm/mach-omap2/prm44xx.c | 1 + arch/arm/mach-omap2/prm_common.c | 19 +++++++++++++++++++ 13 files changed, 36 insertions(+), 22 deletions(-) diff --git a/arch/arm/mach-omap2/am33xx-restart.c b/arch/arm/mach-omap2/am33xx-restart.c index 728638913cd1..5bace6a45ffb 100644 --- a/arch/arm/mach-omap2/am33xx-restart.c +++ b/arch/arm/mach-omap2/am33xx-restart.c @@ -9,8 +9,7 @@ #include #include "common.h" -#include "prm-regbits-33xx.h" -#include "prm33xx.h" +#include "prm.h" /** * am3xx_restart - trigger a software restart of the SoC @@ -24,5 +23,5 @@ void am33xx_restart(enum reboot_mode mode, const char *cmd) { /* TODO: Handle mode and cmd if necessary */ - am33xx_prm_global_warm_sw_reset(); + omap_prm_reset_system(); } diff --git a/arch/arm/mach-omap2/omap2-restart.c b/arch/arm/mach-omap2/omap2-restart.c index 68423e26399d..d937b2e4040b 100644 --- a/arch/arm/mach-omap2/omap2-restart.c +++ b/arch/arm/mach-omap2/omap2-restart.c @@ -15,7 +15,7 @@ #include "soc.h" #include "common.h" -#include "prm2xxx.h" +#include "prm.h" /* * reset_virt_prcm_set_ck, reset_sys_ck: pointers to the virt_prcm_set @@ -40,8 +40,7 @@ void omap2xxx_restart(enum reboot_mode mode, const char *cmd) /* XXX Should save the cmd argument for use after the reboot */ - omap2xxx_prm_dpll_reset(); /* never returns */ - while (1); + omap_prm_reset_system(); } /** diff --git a/arch/arm/mach-omap2/omap3-restart.c b/arch/arm/mach-omap2/omap3-restart.c index 5de2a0c2979d..103a49f68bcb 100644 --- a/arch/arm/mach-omap2/omap3-restart.c +++ b/arch/arm/mach-omap2/omap3-restart.c @@ -14,10 +14,8 @@ #include #include -#include "iomap.h" -#include "common.h" #include "control.h" -#include "prm3xxx.h" +#include "prm.h" /* Global address base setup code */ @@ -32,6 +30,5 @@ void omap3xxx_restart(enum reboot_mode mode, const char *cmd) { omap3_ctrl_write_boot_mode((cmd ? (u8)*cmd : 0)); - omap3xxx_prm_dpll3_reset(); /* never returns */ - while (1); + omap_prm_reset_system(); } diff --git a/arch/arm/mach-omap2/omap4-restart.c b/arch/arm/mach-omap2/omap4-restart.c index 41dfd7da8170..a99e7f7fb5be 100644 --- a/arch/arm/mach-omap2/omap4-restart.c +++ b/arch/arm/mach-omap2/omap4-restart.c @@ -9,7 +9,7 @@ #include #include -#include "prminst44xx.h" +#include "prm.h" /** * omap44xx_restart - trigger a software restart of the SoC @@ -22,7 +22,5 @@ void omap44xx_restart(enum reboot_mode mode, const char *cmd) { /* XXX Should save 'cmd' into scratchpad for use after reboot */ - omap4_prminst_global_warm_sw_reset(); /* never returns */ - while (1) - ; + omap_prm_reset_system(); } diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index dd802eec0dec..77752e49d8d4 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -144,6 +144,7 @@ struct prm_ll_data { u16 offset, u16 st_offset); int (*is_hardreset_asserted)(u8 shift, u8 part, s16 prm_mod, u16 offset); + void (*reset_system)(void); }; extern int prm_register(struct prm_ll_data *pld); @@ -156,6 +157,7 @@ int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset); extern u32 prm_read_reset_sources(void); extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx); extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx); +void omap_prm_reset_system(void); void omap_prm_reconfigure_io_chain(void); diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c index 54ae55520da6..af0f15278fc2 100644 --- a/arch/arm/mach-omap2/prm2xxx.c +++ b/arch/arm/mach-omap2/prm2xxx.c @@ -106,7 +106,7 @@ static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst) * Set the DPLL reset bit, which should reboot the SoC. This is the * recommended way to restart the SoC. No return value. */ -void omap2xxx_prm_dpll_reset(void) +static void omap2xxx_prm_dpll_reset(void) { omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD, OMAP2_RM_RSTCTRL); @@ -215,6 +215,7 @@ static struct prm_ll_data omap2xxx_prm_ll_data = { .assert_hardreset = &omap2_prm_assert_hardreset, .deassert_hardreset = &omap2_prm_deassert_hardreset, .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, + .reset_system = &omap2xxx_prm_dpll_reset, }; int __init omap2xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm2xxx.h b/arch/arm/mach-omap2/prm2xxx.h index d73414139292..1d51643062f7 100644 --- a/arch/arm/mach-omap2/prm2xxx.h +++ b/arch/arm/mach-omap2/prm2xxx.h @@ -124,7 +124,6 @@ extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm); extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm); -extern void omap2xxx_prm_dpll_reset(void); void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask); extern int __init omap2xxx_prm_init(void); diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index 4a843f7cac02..02f628601b09 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -341,7 +341,7 @@ static int am33xx_check_vcvp(void) * * Immediately reboots the device through warm reset. */ -void am33xx_prm_global_warm_sw_reset(void) +static void am33xx_prm_global_warm_sw_reset(void) { am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK, AM33XX_RST_GLOBAL_WARM_SW_MASK, @@ -375,6 +375,7 @@ static struct prm_ll_data am33xx_prm_ll_data = { .assert_hardreset = am33xx_prm_assert_hardreset, .deassert_hardreset = am33xx_prm_deassert_hardreset, .is_hardreset_asserted = am33xx_prm_is_hardreset_asserted, + .reset_system = am33xx_prm_global_warm_sw_reset, }; int __init am33xx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h index 937d56e70b3e..98ac41f271da 100644 --- a/arch/arm/mach-omap2/prm33xx.h +++ b/arch/arm/mach-omap2/prm33xx.h @@ -118,7 +118,6 @@ #define AM33XX_PM_CEFUSE_PWRSTST AM33XX_PRM_REGADDR(AM33XX_PRM_CEFUSE_MOD, 0x0004) #ifndef __ASSEMBLER__ -extern void am33xx_prm_global_warm_sw_reset(void); int am33xx_prm_init(void); #endif /* ASSEMBLER */ diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index 9da15e9db6d2..c5e00c6714b1 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -136,7 +136,7 @@ u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) * recommended way to restart the SoC, considering Errata i520. No * return value. */ -void omap3xxx_prm_dpll3_reset(void) +static void omap3xxx_prm_dpll3_reset(void) { omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, OMAP3430_GR_MOD, OMAP2_RM_RSTCTRL); @@ -663,6 +663,7 @@ static struct prm_ll_data omap3xxx_prm_ll_data = { .assert_hardreset = &omap2_prm_assert_hardreset, .deassert_hardreset = &omap2_prm_deassert_hardreset, .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, + .reset_system = &omap3xxx_prm_dpll3_reset, }; int __init omap3xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm3xxx.h b/arch/arm/mach-omap2/prm3xxx.h index 321568bc0847..cfde3f4a03cc 100644 --- a/arch/arm/mach-omap2/prm3xxx.h +++ b/arch/arm/mach-omap2/prm3xxx.h @@ -144,8 +144,6 @@ extern u32 omap3_prm_vcvp_read(u8 offset); extern void omap3_prm_vcvp_write(u32 val, u8 offset); extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); -extern void omap3xxx_prm_dpll3_reset(void); - extern int __init omap3xxx_prm_init(void); extern u32 omap3xxx_prm_get_reset_sources(void); int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits); diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index e7ac7e209edc..cc170fb81ff7 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -697,6 +697,7 @@ static struct prm_ll_data omap44xx_prm_ll_data = { .assert_hardreset = omap4_prminst_assert_hardreset, .deassert_hardreset = omap4_prminst_deassert_hardreset, .is_hardreset_asserted = omap4_prminst_is_hardreset_asserted, + .reset_system = omap4_prminst_global_warm_sw_reset, }; int __init omap44xx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index be40824acf5f..779940cb6e56 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -502,6 +502,25 @@ void omap_prm_reconfigure_io_chain(void) prcm_irq_setup->reconfigure_io_chain(); } +/** + * omap_prm_reset_system - trigger global SW reset + * + * Triggers SoC specific global warm reset to reboot the device. + */ +void omap_prm_reset_system(void) +{ + if (!prm_ll_data->reset_system) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return; + } + + prm_ll_data->reset_system(); + + while (1) + cpu_relax(); +} + /** * prm_register - register per-SoC low-level data with the PRM * @pld: low-level per-SoC OMAP PRM data & function pointers to register -- cgit v1.2.3-59-g8ed1b From 03c1b7609fbb367c7a9ae49bd41e72cad38fe305 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 28 Oct 2014 08:10:21 +0900 Subject: ARM: EXYNOS: Fix build with ARM_CPU_SUSPEND=n "ARM: EXYNOS: Add support for firmware-assisted suspend/resume" patch added to arch/arm/mach-exynos/firmware.c new references to functions from arch/arm/mach-exynos/sleep.S causing the new CONFIG_PM_SLEEP=n build breakages. Then "ARM: EXYNOS: Fix build with PM_SLEEP=n and ARM_EXYNOS_CPUIDLE=y" patch tried to fix the CONFIG_PM_SLEEP=n issues by always building sleep.S which caused the CONFIG_ARM_CPU_SUSPEND=n build breakage. Fix it by building arch/arm/mach-exynos/sleep.o only for CONFIG_EXYNOS_CPU_SUSPEND=y and adding appropriate IS_ENABLED() checks to arch/arm/mach-exynos/firmware.c. Signed-off-by: Arnd Bergmann [b.zolnierkie: fixed ->resume check and added patch description] Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/Makefile | 4 ++-- arch/arm/mach-exynos/firmware.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 3d680f2a5520..775ee35cb277 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -9,9 +9,9 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree) # Core -obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o sleep.o +obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o -obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o +obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o obj-$(CONFIG_PM_SLEEP) += suspend.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index 2c5bc6bfcbdf..766f57d2f029 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -129,11 +129,11 @@ static int exynos_resume(void) } static const struct firmware_ops exynos_firmware_ops = { - .do_idle = exynos_do_idle, + .do_idle = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_do_idle : NULL, .set_cpu_boot_addr = exynos_set_cpu_boot_addr, .cpu_boot = exynos_cpu_boot, - .suspend = exynos_suspend, - .resume = exynos_resume, + .suspend = IS_ENABLED(CONFIG_PM_SLEEP) ? exynos_suspend : NULL, + .resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL, }; void __init exynos_firmware_init(void) -- cgit v1.2.3-59-g8ed1b From 80f643b39346768878317eb04bd4b1deb4551537 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:18:51 +0200 Subject: ARM: shmobile: r8a7740: Add missing A3SP pm domain devices Commit 802a5639aa7041b2 ("ARM: shmobile: r8a7740: add A3SP pm domain support") added the A3SP power domain, but forgot to hook up the IPPMU, DMAC0/1/2, and USBDMAC hardware blocks. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7740.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 8894e1b7ab0e..6992d4013ef0 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -756,6 +756,11 @@ void __init r8a7740_add_standard_devices(void) { "A3SP", &scif7_device }, { "A3SP", &scif8_device }, { "A3SP", &i2c1_device }, + { "A3SP", &ipmmu_device }, + { "A3SP", &dma0_device }, + { "A3SP", &dma1_device }, + { "A3SP", &dma2_device }, + { "A3SP", &usb_dma_device }, }; /* I2C work-around */ -- cgit v1.2.3-59-g8ed1b From 3b358cb8b7c73304ea2c634afc644cfad37adbdc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:18:52 +0200 Subject: ARM: shmobile: r8a7740: Add missing A4S pm domain devices Commit 8459293c27bcd13a ("ARM: shmobile: r8a7740: add A4S pm domain support") added the A4S power domain, but forgot to hook up the INTCA hardware block. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-r8a7740.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 6992d4013ef0..dbf8a93ccc4f 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -746,6 +746,10 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev) void __init r8a7740_add_standard_devices(void) { static struct pm_domain_device domain_devices[] __initdata = { + { "A4S", &irqpin0_device }, + { "A4S", &irqpin1_device }, + { "A4S", &irqpin2_device }, + { "A4S", &irqpin3_device }, { "A3SP", &scif0_device }, { "A3SP", &scif1_device }, { "A3SP", &scif2_device }, -- cgit v1.2.3-59-g8ed1b From 4311d9654c66b7cc7147035b8ec74f41ddffa650 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:18:53 +0200 Subject: ARM: shmobile: armadillo800eva legacy: Add missing A3SP pm domain devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 802a5639aa7041b2 ("ARM: shmobile: r8a7740: add A3SP pm domain support") added the A3SP power domain, but forgot to hook up the TPU, SDHI0/1, and MMCIF hardware blocks. Note: As the default PM QoS latency constraint for SDHI is only 100 µs (cfr. commit c419e611c3c59c0e ("tmio_mmc / PM: Use PM QoS latency constraint"), while DEFAULT_DEV_LATENCY_NS is 250000, suspend fails with -EBUSY, unless the constraint is increased first to more than 500 µs using e.g. echo 501 > /sys/devices/platform/sh_mobile_sdhi.0/power/pm_qos_resume_latency_us Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-armadillo800eva.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index e70983534403..4bc202dd828a 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -1234,8 +1234,11 @@ static void __init eva_init(void) static struct pm_domain_device domain_devices[] __initdata = { { "A4LC", &lcdc0_device }, { "A4LC", &hdmi_lcdc_device }, + { "A3SP", &pwm_device }, + { "A3SP", &sdhi0_device }, + { "A3SP", &sh_mmcif_device }, }; - struct platform_device *usb = NULL; + struct platform_device *usb = NULL, *sdhi1 = NULL; regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, ARRAY_SIZE(fixed3v3_power_consumers), 3300000); @@ -1304,6 +1307,7 @@ static void __init eva_init(void) platform_device_register(&vcc_sdhi1); platform_device_register(&sdhi1_device); + sdhi1 = &sdhi1_device; } @@ -1324,6 +1328,8 @@ static void __init eva_init(void) ARRAY_SIZE(domain_devices)); if (usb) rmobile_add_device_to_domain("A3SP", usb); + if (sdhi1) + rmobile_add_device_to_domain("A3SP", sdhi1); r8a7740_pm_init(); } -- cgit v1.2.3-59-g8ed1b From 671c522a69fc6fa6960ada4c55bc7186f7d89a3a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:18:54 +0200 Subject: ARM: shmobile: armadillo800eva legacy: Add missing A4S pm domain devices Commit 8459293c27bcd13a ("ARM: shmobile: r8a7740: add A4S pm domain support") added the A4S power domain, but forgot to hook up the GbEther hardware block. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-armadillo800eva.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index 4bc202dd828a..0aa5bbdbd153 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -1234,6 +1234,7 @@ static void __init eva_init(void) static struct pm_domain_device domain_devices[] __initdata = { { "A4LC", &lcdc0_device }, { "A4LC", &hdmi_lcdc_device }, + { "A4S", &sh_eth_device }, { "A3SP", &pwm_device }, { "A3SP", &sdhi0_device }, { "A3SP", &sh_mmcif_device }, -- cgit v1.2.3-59-g8ed1b From 995d925058b63f8300b20d458d941a8a1306d8fb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:18:55 +0200 Subject: ARM: shmobile: r8a7740: Add A3RV pm domain support Add support for the A3RV power domain. This domain contains the VPU5F and VCP1 hardware blocks, which are currently not used by any driver. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/pm-r8a7740.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index e3f146448237..1d916038660d 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -36,6 +36,9 @@ static struct rmobile_pm_domain r8a7740_pm_domains[] = { { .genpd.name = "A4LC", .bit_shift = 1, + }, { + .genpd.name = "A3RV", + .bit_shift = 6, }, { .genpd.name = "A4S", .bit_shift = 10, -- cgit v1.2.3-59-g8ed1b From 92e88fd7793401dc7bc1b5cec93761e83b19b947 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:18:56 +0200 Subject: ARM: shmobile: r8a7740: Add A3SG pm domain support Add support for the A3SG power domain, and hook it up as a subdomain of A4S. This domain contains the SGX540 hardware block, which is currently not used by any driver. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/pm-r8a7740.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index 1d916038660d..932c2a621e81 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -51,6 +51,9 @@ static struct rmobile_pm_domain r8a7740_pm_domains[] = { .gov = &pm_domain_always_on_gov, .no_debug = true, .suspend = r8a7740_pd_a3sp_suspend, + }, { + .genpd.name = "A3SG", + .bit_shift = 13, }, }; @@ -58,6 +61,7 @@ void __init r8a7740_init_pm_domains(void) { rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains)); pm_genpd_add_subdomain_names("A4S", "A3SP"); + pm_genpd_add_subdomain_names("A4S", "A3SG"); } #endif /* CONFIG_PM && !CONFIG_ARCH_MULTIPLATFORM */ -- cgit v1.2.3-59-g8ed1b From 77192e1e25a57a519df30015b29c046bd6a769fc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:18:57 +0200 Subject: ARM: shmobile: r8a7740/armadillo legacy: Add A4MP pm domain support Add support for the A4MP power domain, and hook up the HDMI-Link and FSI hardware blocks. This domain also contains the SPU2, FMSI, and BBIF2 hardware blocks, but these are currently not used by any driver. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-armadillo800eva.c | 2 ++ arch/arm/mach-shmobile/pm-r8a7740.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index 0aa5bbdbd153..e06444370a86 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -1234,6 +1234,8 @@ static void __init eva_init(void) static struct pm_domain_device domain_devices[] __initdata = { { "A4LC", &lcdc0_device }, { "A4LC", &hdmi_lcdc_device }, + { "A4MP", &hdmi_device }, + { "A4MP", &fsi_device }, { "A4S", &sh_eth_device }, { "A3SP", &pwm_device }, { "A3SP", &sdhi0_device }, diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index 932c2a621e81..081a4f9726a0 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -36,6 +36,9 @@ static struct rmobile_pm_domain r8a7740_pm_domains[] = { { .genpd.name = "A4LC", .bit_shift = 1, + }, { + .genpd.name = "A4MP", + .bit_shift = 2, }, { .genpd.name = "A3RV", .bit_shift = 6, -- cgit v1.2.3-59-g8ed1b From 7e81f5434db5bbef3ac55d3f44f702566c0323c6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:18:58 +0200 Subject: ARM: shmobile: r8a7740: Add D4 pm domain support Add support for the D4 power domain. This domain contains the Coresight-ETM hardware block. As long as the ARM debug/perf code doesn't use resource management with runtime PM support, the D4 power domain must be kept powered to avoid a crash during resume from s2ram (dbg_cpu_pm_notify() calls reset_ctrl_regs() unconditionally, causing an undefined instruction oops). Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/pm-r8a7740.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index 081a4f9726a0..8b1af2a585ab 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -32,6 +32,16 @@ static int r8a7740_pd_a3sp_suspend(void) return console_suspend_enabled ? 0 : -EBUSY; } +static int r8a7740_pd_d4_suspend(void) +{ + /* + * The D4 domain contains the Coresight-ETM hardware block and + * therefore it should only be turned off if the debug module is + * not in use. + */ + return -EBUSY; +} + static struct rmobile_pm_domain r8a7740_pm_domains[] = { { .genpd.name = "A4LC", @@ -39,6 +49,11 @@ static struct rmobile_pm_domain r8a7740_pm_domains[] = { }, { .genpd.name = "A4MP", .bit_shift = 2, + }, { + .genpd.name = "D4", + .bit_shift = 3, + .gov = &pm_domain_always_on_gov, + .suspend = r8a7740_pd_d4_suspend, }, { .genpd.name = "A3RV", .bit_shift = 6, -- cgit v1.2.3-59-g8ed1b From 1618a677046b0391621708734f56886233210047 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:18:59 +0200 Subject: ARM: shmobile: r8a7740/armadillo legacy: Add A4R pm domain support Add support for the A4R power domain, and hook up the A3RV subdomain, and the CEU0, TMU0, and IIC0 hardware blocks. This domain also contains the Realtime CPU (SH-4A), Realtime CPU debug modules, H-UDI, RT-SHwy, INTCS, RT-HPB, VIO6C, JPU, RTDMAC1/2, SSP, MSIOF0, CMT0, ICB, DREQPAK (RT), 2DDMAC, IPMMUI, and 2DG hardware blocks, but these are currently not used by any driver. Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-armadillo800eva.c | 1 + arch/arm/mach-shmobile/pm-r8a7740.c | 4 ++++ arch/arm/mach-shmobile/setup-r8a7740.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index e06444370a86..25813dac77d9 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -1236,6 +1236,7 @@ static void __init eva_init(void) { "A4LC", &hdmi_lcdc_device }, { "A4MP", &hdmi_device }, { "A4MP", &fsi_device }, + { "A4R", &ceu0_device }, { "A4S", &sh_eth_device }, { "A3SP", &pwm_device }, { "A3SP", &sdhi0_device }, diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index 8b1af2a585ab..74e6a67a28d3 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -54,6 +54,9 @@ static struct rmobile_pm_domain r8a7740_pm_domains[] = { .bit_shift = 3, .gov = &pm_domain_always_on_gov, .suspend = r8a7740_pd_d4_suspend, + }, { + .genpd.name = "A4R", + .bit_shift = 5, }, { .genpd.name = "A3RV", .bit_shift = 6, @@ -78,6 +81,7 @@ static struct rmobile_pm_domain r8a7740_pm_domains[] = { void __init r8a7740_init_pm_domains(void) { rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains)); + pm_genpd_add_subdomain_names("A4R", "A3RV"); pm_genpd_add_subdomain_names("A4S", "A3SP"); pm_genpd_add_subdomain_names("A4S", "A3SG"); } diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index dbf8a93ccc4f..b77c226ab891 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -746,6 +746,8 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev) void __init r8a7740_add_standard_devices(void) { static struct pm_domain_device domain_devices[] __initdata = { + { "A4R", &tmu0_device }, + { "A4R", &i2c0_device }, { "A4S", &irqpin0_device }, { "A4S", &irqpin1_device }, { "A4S", &irqpin2_device }, -- cgit v1.2.3-59-g8ed1b From 4ee7830c3ef9224bd078abe41a33c7396f827078 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:19:00 +0200 Subject: ARM: shmobile: r8a7740: Add A4SU pm domain support Add support for the A4SU power domain. This domain contains the USBPHY hardware block, which is currently not used by any driver. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/pm-r8a7740.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index 74e6a67a28d3..27117a8a49ad 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -75,6 +75,9 @@ static struct rmobile_pm_domain r8a7740_pm_domains[] = { }, { .genpd.name = "A3SG", .bit_shift = 13, + }, { + .genpd.name = "A4SU", + .bit_shift = 20, }, }; -- cgit v1.2.3-59-g8ed1b From dc4470e177973feedd82596969d86468a1695b1e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 23 Oct 2014 13:19:01 +0200 Subject: ARM: shmobile: r8a7740: Add A3SM pm domain support Add support for the A3SM power domain, and hook it up as a subdomain of A4S. This domain contains the System CPU (Cortex-A9) hardware block. Hence move the special CPU handling from A4S to A3SM. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/pm-r8a7740.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index 27117a8a49ad..ac2eecd6f5ea 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -14,10 +14,10 @@ #include "pm-rmobile.h" #if defined(CONFIG_PM) && !defined(CONFIG_ARCH_MULTIPLATFORM) -static int r8a7740_pd_a4s_suspend(void) +static int r8a7740_pd_a3sm_suspend(void) { /* - * The A4S domain contains the CPU core and therefore it should + * The A3SM domain contains the CPU core and therefore it should * only be turned off if the CPU is not in use. */ return -EBUSY; @@ -63,15 +63,18 @@ static struct rmobile_pm_domain r8a7740_pm_domains[] = { }, { .genpd.name = "A4S", .bit_shift = 10, - .gov = &pm_domain_always_on_gov, .no_debug = true, - .suspend = r8a7740_pd_a4s_suspend, }, { .genpd.name = "A3SP", .bit_shift = 11, .gov = &pm_domain_always_on_gov, .no_debug = true, .suspend = r8a7740_pd_a3sp_suspend, + }, { + .genpd.name = "A3SM", + .bit_shift = 12, + .gov = &pm_domain_always_on_gov, + .suspend = r8a7740_pd_a3sm_suspend, }, { .genpd.name = "A3SG", .bit_shift = 13, @@ -86,6 +89,7 @@ void __init r8a7740_init_pm_domains(void) rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains)); pm_genpd_add_subdomain_names("A4R", "A3RV"); pm_genpd_add_subdomain_names("A4S", "A3SP"); + pm_genpd_add_subdomain_names("A4S", "A3SM"); pm_genpd_add_subdomain_names("A4S", "A3SG"); } #endif /* CONFIG_PM && !CONFIG_ARCH_MULTIPLATFORM */ -- cgit v1.2.3-59-g8ed1b From 3794705aeb318c431c07072f04380c78cc5a84ac Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 23 Oct 2014 17:38:31 +0300 Subject: ARM: shmobile: Select CONFIG_ZONE_DMA when CONFIG_ARM_LPAE is enabled Most IP cores on ARM Renesas platforms can only address 32 bits of physical memory for DMA. Without CONFIG_ZONE_DMA enabled and with the recent CMA highmem allocation support, the default CMA zone is reserved above the 4GiB limit when LPAE is enabled, resulting in various driver failures. Fix the problem by selecting CONFIG_ZONE_DMA. Other options to investigate in the future would be to either enable IOMMU support or use custom CMA reservations for peripherals not supporting LPAE. While not a strict dependency, the "[PATCH 0/4] Low/high memory CMA reservation fixes" series is also required to fix a different but related CMA allocation problem. Signed-off-by: Laurent Pinchart Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 21f457b56c01..6bc018fc5dc1 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -1,5 +1,6 @@ config ARCH_SHMOBILE bool + select ZONE_DMA if ARM_LPAE config PM_RCAR bool -- cgit v1.2.3-59-g8ed1b From 2197eb81e368b73d58961207b3914136921eda84 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 13 Sep 2014 11:31:19 -0700 Subject: ARM: u300: Convert pr_warning to pr_warn Use the more common pr_warn. Other miscellanea: o Coalesce formats o Realign arguments o typo fixes of Siple to Simple Signed-off-by: Joe Perches Signed-off-by: Linus Walleij --- arch/arm/mach-u300/dummyspichip.c | 65 +++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/arch/arm/mach-u300/dummyspichip.c b/arch/arm/mach-u300/dummyspichip.c index ec0283cf9a32..131996805690 100644 --- a/arch/arm/mach-u300/dummyspichip.c +++ b/arch/arm/mach-u300/dummyspichip.c @@ -80,8 +80,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 8bit mode\n"); status = spi_w8r8(spi, 0xAA); if (status < 0) - pr_warning("Siple test 1: FAILURE: spi_write_then_read " - "failed with status %d\n", status); + pr_warn("Simple test 1: FAILURE: spi_write_then_read failed with status %d\n", + status); else pr_info("Simple test 1: SUCCESS!\n"); @@ -89,8 +89,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 8bit mode (full FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); if (status < 0) - pr_warning("Simple test 2: FAILURE: spi_write_then_read() " - "failed with status %d\n", status); + pr_warn("Simple test 2: FAILURE: spi_write_then_read() failed with status %d\n", + status); else pr_info("Simple test 2: SUCCESS!\n"); @@ -98,8 +98,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 8bit mode (see if we overflow FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); if (status < 0) - pr_warning("Simple test 3: FAILURE: failed with status %d " - "(probably FIFO overrun)\n", status); + pr_warn("Simple test 3: FAILURE: failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 3: SUCCESS!\n"); @@ -107,14 +107,14 @@ static ssize_t dummy_looptest(struct device *dev, "bytes garbage with spi_read() in 8bit mode\n"); status = spi_write(spi, &txbuf[0], 8); if (status < 0) - pr_warning("Simple test 4 step 1: FAILURE: spi_write() " - "failed with status %d\n", status); + pr_warn("Simple test 4 step 1: FAILURE: spi_write() failed with status %d\n", + status); else pr_info("Simple test 4 step 1: SUCCESS!\n"); status = spi_read(spi, &rxbuf[0], 8); if (status < 0) - pr_warning("Simple test 4 step 2: FAILURE: spi_read() " - "failed with status %d\n", status); + pr_warn("Simple test 4 step 2: FAILURE: spi_read() failed with status %d\n", + status); else pr_info("Simple test 4 step 2: SUCCESS!\n"); @@ -122,16 +122,14 @@ static ssize_t dummy_looptest(struct device *dev, "14 bytes garbage with spi_read() in 8bit mode\n"); status = spi_write(spi, &txbuf[0], 14); if (status < 0) - pr_warning("Simple test 5 step 1: FAILURE: spi_write() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 5 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 5 step 1: SUCCESS!\n"); status = spi_read(spi, &rxbuf[0], 14); if (status < 0) - pr_warning("Simple test 5 step 2: FAILURE: spi_read() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 5 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 5: SUCCESS!\n"); @@ -140,16 +138,14 @@ static ssize_t dummy_looptest(struct device *dev, DMA_TEST_SIZE, DMA_TEST_SIZE); status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 6 step 1: FAILURE: spi_write() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 6 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 6 step 1: SUCCESS!\n"); status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 6 step 2: FAILURE: spi_read() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 6 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 6: SUCCESS!\n"); @@ -169,18 +165,17 @@ static ssize_t dummy_looptest(struct device *dev, pr_info("Simple test 7: SUCCESS! (expected failure with " "status EIO)\n"); else if (status < 0) - pr_warning("Siple test 7: FAILURE: spi_write_then_read " - "failed with status %d\n", status); + pr_warn("Simple test 7: FAILURE: spi_write_then_read failed with status %d\n", + status); else - pr_warning("Siple test 7: FAILURE: spi_write_then_read " - "succeeded but it was expected to fail!\n"); + pr_warn("Simple test 7: FAILURE: spi_write_then_read succeeded but it was expected to fail!\n"); pr_info("Simple test 8: write 8 bytes, read back 8 bytes garbage " "in 16bit mode (full FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); if (status < 0) - pr_warning("Simple test 8: FAILURE: spi_write_then_read() " - "failed with status %d\n", status); + pr_warn("Simple test 8: FAILURE: spi_write_then_read() failed with status %d\n", + status); else pr_info("Simple test 8: SUCCESS!\n"); @@ -188,8 +183,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 16bit mode (see if we overflow FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); if (status < 0) - pr_warning("Simple test 9: FAILURE: failed with status %d " - "(probably FIFO overrun)\n", status); + pr_warn("Simple test 9: FAILURE: failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 9: SUCCESS!\n"); @@ -198,17 +193,15 @@ static ssize_t dummy_looptest(struct device *dev, DMA_TEST_SIZE, DMA_TEST_SIZE); status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 10 step 1: FAILURE: spi_write() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 10 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 10 step 1: SUCCESS!\n"); status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 10 step 2: FAILURE: spi_read() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 10 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 10: SUCCESS!\n"); -- cgit v1.2.3-59-g8ed1b From 24a543254b4aba9bbf4d0793ad8d7d91a07b7182 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Oct 2014 11:12:54 +0200 Subject: dt: bindings: ux500: Add documentation for PM domains Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij --- .../devicetree/bindings/arm/ux500/power_domain.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/ux500/power_domain.txt diff --git a/Documentation/devicetree/bindings/arm/ux500/power_domain.txt b/Documentation/devicetree/bindings/arm/ux500/power_domain.txt new file mode 100644 index 000000000000..5679d1742d3e --- /dev/null +++ b/Documentation/devicetree/bindings/arm/ux500/power_domain.txt @@ -0,0 +1,35 @@ +* ST-Ericsson UX500 PM Domains + +UX500 supports multiple PM domains which are used to gate power to one or +more peripherals on the SOC. + +The implementation of PM domains for UX500 are based upon the generic PM domain +and use the corresponding DT bindings. + +==PM domain providers== + +Required properties: + - compatible: Must be "stericsson,ux500-pm-domains". + - #power-domain-cells : Number of cells in a power domain specifier, must be 1. + +Example: + pm_domains: pm_domains0 { + compatible = "stericsson,ux500-pm-domains"; + #power-domain-cells = <1>; + }; + +==PM domain consumers== + +Required properties: + - power-domains: A phandle and PM domain specifier. Below are the list of + valid specifiers: + + Index Specifier + ----- --------- + 0 DOMAIN_VAPE + +Example: + sdi0_per1@80126000 { + compatible = "arm,pl18x", "arm,primecell"; + power-domains = <&pm_domains DOMAIN_VAPE> + }; -- cgit v1.2.3-59-g8ed1b From 5dcb10159b1848b2c91ac2a11745d229f16fc26b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Oct 2014 11:12:55 +0200 Subject: dt: bindings: ux500: Add header for PM domains specifiers Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij --- include/dt-bindings/arm/ux500_pm_domains.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 include/dt-bindings/arm/ux500_pm_domains.h diff --git a/include/dt-bindings/arm/ux500_pm_domains.h b/include/dt-bindings/arm/ux500_pm_domains.h new file mode 100644 index 000000000000..398a6c0288d1 --- /dev/null +++ b/include/dt-bindings/arm/ux500_pm_domains.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Ulf Hansson + * License terms: GNU General Public License (GPL) version 2 + */ +#ifndef _DT_BINDINGS_ARM_UX500_PM_DOMAINS_H +#define _DT_BINDINGS_ARM_UX500_PM_DOMAINS_H + +#define DOMAIN_VAPE 0 + +/* Number of PM domains. */ +#define NR_DOMAINS (DOMAIN_VAPE + 1) + +#endif -- cgit v1.2.3-59-g8ed1b From cd931dcfda5e5e5e2c55bd243919b1820105cdde Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Oct 2014 11:12:56 +0200 Subject: ARM: ux500: Initial support for PM domains The ux500 SoC uses the generic PM domain and requires the domains to be specified through DT. Currently the genpd callbacks for handling power gating|ungating are implemented as dummy functions. To be able to enable those to perform PM domain gating/ungating, each device that resides in the VAPE domain must be properly handled from a runtime PM perspective. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij --- arch/arm/mach-ux500/Makefile | 1 + arch/arm/mach-ux500/pm.c | 4 ++ arch/arm/mach-ux500/pm_domains.c | 79 ++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-ux500/pm_domains.h | 17 +++++++++ 4 files changed, 101 insertions(+) create mode 100644 arch/arm/mach-ux500/pm_domains.c create mode 100644 arch/arm/mach-ux500/pm_domains.h diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 9741de956b3e..4418a5078833 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \ board-mop500-audio.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o CFLAGS_hotplug.o += -march=armv7-a diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c index b80a9a2e356e..2cb587b50905 100644 --- a/arch/arm/mach-ux500/pm.c +++ b/arch/arm/mach-ux500/pm.c @@ -17,6 +17,7 @@ #include #include "db8500-regs.h" +#include "pm_domains.h" /* ARM WFI Standby signal register */ #define PRCM_ARM_WFI_STANDBY (prcmu_base + 0x130) @@ -191,4 +192,7 @@ void __init ux500_pm_init(u32 phy_base, u32 size) /* Set up ux500 suspend callbacks. */ suspend_set_ops(UX500_SUSPEND_OPS); + + /* Initialize ux500 power domains */ + ux500_pm_domains_init(); } diff --git a/arch/arm/mach-ux500/pm_domains.c b/arch/arm/mach-ux500/pm_domains.c new file mode 100644 index 000000000000..0d4b5b46f15b --- /dev/null +++ b/arch/arm/mach-ux500/pm_domains.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Ulf Hansson + * License terms: GNU General Public License (GPL) version 2 + * + * Implements PM domains using the generic PM domain for ux500. + */ +#include +#include +#include +#include +#include + +#include +#include "pm_domains.h" + +static int pd_power_off(struct generic_pm_domain *domain) +{ + /* + * Handle the gating of the PM domain regulator here. + * + * Drivers/subsystems handling devices in the PM domain needs to perform + * register context save/restore from their respective runtime PM + * callbacks, to be able to enable PM domain gating/ungating. + */ + return 0; +} + +static int pd_power_on(struct generic_pm_domain *domain) +{ + /* + * Handle the ungating of the PM domain regulator here. + * + * Drivers/subsystems handling devices in the PM domain needs to perform + * register context save/restore from their respective runtime PM + * callbacks, to be able to enable PM domain gating/ungating. + */ + return 0; +} + +static struct generic_pm_domain ux500_pm_domain_vape = { + .name = "VAPE", + .power_off = pd_power_off, + .power_on = pd_power_on, +}; + +static struct generic_pm_domain *ux500_pm_domains[NR_DOMAINS] = { + [DOMAIN_VAPE] = &ux500_pm_domain_vape, +}; + +static struct of_device_id ux500_pm_domain_matches[] = { + { .compatible = "stericsson,ux500-pm-domains", }, + { }, +}; + +int __init ux500_pm_domains_init(void) +{ + struct device_node *np; + struct genpd_onecell_data *genpd_data; + int i; + + np = of_find_matching_node(NULL, ux500_pm_domain_matches); + if (!np) + return -ENODEV; + + genpd_data = kzalloc(sizeof(*genpd_data), GFP_KERNEL); + if (!genpd_data) + return -ENOMEM; + + genpd_data->domains = ux500_pm_domains; + genpd_data->num_domains = ARRAY_SIZE(ux500_pm_domains); + + for (i = 0; i < ARRAY_SIZE(ux500_pm_domains); ++i) + pm_genpd_init(ux500_pm_domains[i], NULL, false); + + of_genpd_add_provider_onecell(np, genpd_data); + return 0; +} diff --git a/arch/arm/mach-ux500/pm_domains.h b/arch/arm/mach-ux500/pm_domains.h new file mode 100644 index 000000000000..263d3ba97177 --- /dev/null +++ b/arch/arm/mach-ux500/pm_domains.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Ulf Hansson + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __MACH_UX500_PM_DOMAINS_H +#define __MACH_UX500_PM_DOMAINS_H + +#ifdef CONFIG_PM_GENERIC_DOMAINS +extern int __init ux500_pm_domains_init(void); +#else +static inline int ux500_pm_domains_init(void) { return 0; } +#endif + +#endif -- cgit v1.2.3-59-g8ed1b From c8f4594381922cd611384455083a02740df12a25 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Oct 2014 11:12:57 +0200 Subject: ARM: ux500: Enable Kconfig for the generic PM domain Since ux500 uses the generic PM domain, let's enable the corresponding Kconfig as long as CONFIG_PM also is enabled. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij --- arch/arm/mach-ux500/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 699e8601dbf0..c9ac19b24e5a 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -32,6 +32,7 @@ config UX500_SOC_DB8500 select PINCTRL_AB8540 select REGULATOR select REGULATOR_DB8500_PRCMU + select PM_GENERIC_DOMAINS if PM config MACH_MOP500 bool "U8500 Development platform, MOP500 versions" -- cgit v1.2.3-59-g8ed1b From 6c6693599b33b2e45a9c14b209729b839b379ee6 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Oct 2014 11:12:58 +0200 Subject: ARM: ux500: Add DT node for ux500 PM domains Add a DT node for the ux500 PM domains. Follow the DT semantics of the generic PM domain. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-dbx5x0.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index 9d2323020d34..d4169746819e 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -43,6 +43,10 @@ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>; }; + pm_domains: pm_domains0 { + compatible = "stericsson,ux500-pm-domains"; + #power-domain-cells = <1>; + }; clocks { compatible = "stericsson,u8500-clks"; -- cgit v1.2.3-59-g8ed1b From 067addec0ec5f95be5a698043d78940622f642b8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Oct 2014 11:12:59 +0200 Subject: ARM: ux500: Add sdi devices to the VAPE PM domain The mmci driver handle these devices properly from a runtime PM perspective, including register context save/restore. Therefore let's add them into VAPE PM domain for ux500. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-dbx5x0.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index d4169746819e..41009c1004f3 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -11,6 +11,7 @@ #include #include +#include #include "skeleton.dtsi" / { @@ -840,6 +841,7 @@ clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -855,6 +857,7 @@ clocks = <&prcc_kclk 2 4>, <&prcc_pclk 2 6>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -870,6 +873,7 @@ clocks = <&prcc_kclk 3 4>, <&prcc_pclk 3 4>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -885,6 +889,7 @@ clocks = <&prcc_kclk 2 5>, <&prcc_pclk 2 7>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -900,6 +905,7 @@ clocks = <&prcc_kclk 2 2>, <&prcc_pclk 2 4>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -915,6 +921,7 @@ clocks = <&prcc_kclk 3 7>, <&prcc_pclk 3 7>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; -- cgit v1.2.3-59-g8ed1b From 770e2f6bc32523dbd9f336d75be4ce6dbccd8423 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Oct 2014 11:13:00 +0200 Subject: ARM: ux500: Add spi and ssp devices to the VAPE PM domain The spi-pl022 driver handle these devices properly from a runtime PM perspective. Therefore, let's add them into VAPE PM domain for ux500. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-dbx5x0.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index 41009c1004f3..c51c11f560df 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -714,6 +714,7 @@ dmas = <&dma 8 0 0x2>, /* Logical - DevToMem */ <&dma 8 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; ssp@80003000 { @@ -727,6 +728,7 @@ dmas = <&dma 9 0 0x2>, /* Logical - DevToMem */ <&dma 9 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@8011a000 { @@ -741,6 +743,7 @@ dmas = <&dma 0 0 0x2>, /* Logical - DevToMem */ <&dma 0 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@80112000 { @@ -755,6 +758,7 @@ dmas = <&dma 35 0 0x2>, /* Logical - DevToMem */ <&dma 35 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@80111000 { @@ -769,6 +773,7 @@ dmas = <&dma 33 0 0x2>, /* Logical - DevToMem */ <&dma 33 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@80129000 { @@ -783,6 +788,7 @@ dmas = <&dma 40 0 0x2>, /* Logical - DevToMem */ <&dma 40 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; uart@80120000 { -- cgit v1.2.3-59-g8ed1b From 29417fe80ad2fd4f62f00dcca96c7198870e5642 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Oct 2014 11:13:01 +0200 Subject: ARM: ux500: Add i2c devices to the VAPE PM domain The i2c-nomadik driver handle these devices properly from a runtime PM perspective. Therefore, let's add them into VAPE PM domain for ux500. Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-dbx5x0.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index c51c11f560df..bfd3f1c734b8 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -641,6 +641,7 @@ clock-frequency = <400000>; clocks = <&prcc_kclk 3 3>, <&prcc_pclk 3 3>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@80122000 { @@ -656,6 +657,7 @@ clocks = <&prcc_kclk 1 2>, <&prcc_pclk 1 2>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@80128000 { @@ -671,6 +673,7 @@ clocks = <&prcc_kclk 1 6>, <&prcc_pclk 1 6>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@80110000 { @@ -686,6 +689,7 @@ clocks = <&prcc_kclk 2 0>, <&prcc_pclk 2 0>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@8012a000 { @@ -701,6 +705,7 @@ clocks = <&prcc_kclk 1 9>, <&prcc_pclk 1 10>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; ssp@80002000 { -- cgit v1.2.3-59-g8ed1b From beb5818bd012953c79de38f9726f327d8e311569 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 15 Oct 2014 15:30:25 +0200 Subject: ARM: integrator: move AP timer to clocksource This moves the timer/clocksource implementation for the Integrator/AP down to drivers/clocksource and augments the driver a little to use CLOCKSOURCE_OF_DECLARE(). Remove the static mapping of the timer blocks while we're at it. Tested on the Integrator/AP. Acked-by: Thomas Gleixner Acked-by: Daniel Lezcano Signed-off-by: Linus Walleij --- arch/arm/mach-integrator/integrator_ap.c | 190 --------------------------- drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-integrator-ap.c | 210 ++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+), 190 deletions(-) create mode 100644 drivers/clocksource/timer-integrator-ap.c diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 8ca290b479b1..8a879b654fde 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -27,13 +27,9 @@ #include #include #include -#include -#include -#include #include #include #include -#include #include #include #include @@ -41,8 +37,6 @@ #include #include #include -#include -#include #include #include @@ -89,11 +83,6 @@ static void __iomem *ebi_base; static struct map_desc ap_io_desc[] __initdata __maybe_unused = { { - .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), .length = SZ_4K, @@ -257,188 +246,10 @@ struct amba_pl010_data ap_uart_data = { .set_mctrl = integrator_uart_set_mctrl, }; -/* - * Where is the timer (VA)? - */ -#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE) -#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE) -#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE) - -static unsigned long timer_reload; - -static u64 notrace integrator_read_sched_clock(void) -{ - return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE); -} - -static void integrator_clocksource_init(unsigned long inrate, - void __iomem *base) -{ - u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; - unsigned long rate = inrate; - - if (rate >= 1500000) { - rate /= 16; - ctrl |= TIMER_CTRL_DIV16; - } - - writel(0xffff, base + TIMER_LOAD); - writel(ctrl, base + TIMER_CTRL); - - clocksource_mmio_init(base + TIMER_VALUE, "timer2", - rate, 200, 16, clocksource_mmio_readl_down); - sched_clock_register(integrator_read_sched_clock, 16, rate); -} - -static void __iomem * clkevt_base; - -/* - * IRQ handler for the timer - */ -static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - - /* clear the interrupt */ - writel(1, clkevt_base + TIMER_INTCLR); - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - -static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) -{ - u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; - - /* Disable timer */ - writel(ctrl, clkevt_base + TIMER_CTRL); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* Enable the timer and start the periodic tick */ - writel(timer_reload, clkevt_base + TIMER_LOAD); - ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Leave the timer disabled, .set_next_event will enable it */ - ctrl &= ~TIMER_CTRL_PERIODIC; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - default: - /* Just leave in disabled state */ - break; - } - -} - -static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) -{ - unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); - - writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); - writel(next, clkevt_base + TIMER_LOAD); - writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); - - return 0; -} - -static struct clock_event_device integrator_clockevent = { - .name = "timer1", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = clkevt_set_mode, - .set_next_event = clkevt_set_next_event, - .rating = 300, -}; - -static struct irqaction integrator_timer_irq = { - .name = "timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = integrator_timer_interrupt, - .dev_id = &integrator_clockevent, -}; - -static void integrator_clockevent_init(unsigned long inrate, - void __iomem *base, int irq) -{ - unsigned long rate = inrate; - unsigned int ctrl = 0; - - clkevt_base = base; - /* Calculate and program a divisor */ - if (rate > 0x100000 * HZ) { - rate /= 256; - ctrl |= TIMER_CTRL_DIV256; - } else if (rate > 0x10000 * HZ) { - rate /= 16; - ctrl |= TIMER_CTRL_DIV16; - } - timer_reload = rate / HZ; - writel(ctrl, clkevt_base + TIMER_CTRL); - - setup_irq(irq, &integrator_timer_irq); - clockevents_config_and_register(&integrator_clockevent, - rate, - 1, - 0xffffU); -} - void __init ap_init_early(void) { } -static void __init ap_of_timer_init(void) -{ - struct device_node *node; - const char *path; - void __iomem *base; - int err; - int irq; - struct clk *clk; - unsigned long rate; - - of_clk_init(NULL); - - err = of_property_read_string(of_aliases, - "arm,timer-primary", &path); - if (WARN_ON(err)) - return; - node = of_find_node_by_path(path); - base = of_iomap(node, 0); - if (WARN_ON(!base)) - return; - - clk = of_clk_get(node, 0); - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); - rate = clk_get_rate(clk); - - writel(0, base + TIMER_CTRL); - integrator_clocksource_init(rate, base); - - err = of_property_read_string(of_aliases, - "arm,timer-secondary", &path); - if (WARN_ON(err)) - return; - node = of_find_node_by_path(path); - base = of_iomap(node, 0); - if (WARN_ON(!base)) - return; - irq = irq_of_parse_and_map(node, 0); - - clk = of_clk_get(node, 0); - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); - rate = clk_get_rate(clk); - - writel(0, base + TIMER_CTRL); - integrator_clockevent_init(rate, base, irq); -} - static void __init ap_init_irq_of(void) { cm_init(); @@ -553,7 +364,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") .map_io = ap_map_io, .init_early = ap_init_early, .init_irq = ap_init_irq_of, - .init_time = ap_of_timer_init, .init_machine = ap_init_of, .restart = integrator_restart, .dt_compat = ap_dt_board_compat, diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 756f6f10efa0..fae0435cc23d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o +obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c new file mode 100644 index 000000000000..b9efd30513d5 --- /dev/null +++ b/drivers/clocksource/timer-integrator-ap.c @@ -0,0 +1,210 @@ +/* + * Integrator/AP timer driver + * Copyright (C) 2000-2003 Deep Blue Solutions Ltd + * Copyright (c) 2014, Linaro Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __iomem * sched_clk_base; + +static u64 notrace integrator_read_sched_clock(void) +{ + return -readl(sched_clk_base + TIMER_VALUE); +} + +static void integrator_clocksource_init(unsigned long inrate, + void __iomem *base) +{ + u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; + unsigned long rate = inrate; + + if (rate >= 1500000) { + rate /= 16; + ctrl |= TIMER_CTRL_DIV16; + } + + writel(0xffff, base + TIMER_LOAD); + writel(ctrl, base + TIMER_CTRL); + + clocksource_mmio_init(base + TIMER_VALUE, "timer2", + rate, 200, 16, clocksource_mmio_readl_down); + + sched_clk_base = base; + sched_clock_register(integrator_read_sched_clock, 16, rate); +} + +static unsigned long timer_reload; +static void __iomem * clkevt_base; + +/* + * IRQ handler for the timer + */ +static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + /* clear the interrupt */ + writel(1, clkevt_base + TIMER_INTCLR); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +{ + u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; + + /* Disable timer */ + writel(ctrl, clkevt_base + TIMER_CTRL); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* Enable the timer and start the periodic tick */ + writel(timer_reload, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* Leave the timer disabled, .set_next_event will enable it */ + ctrl &= ~TIMER_CTRL_PERIODIC; + writel(ctrl, clkevt_base + TIMER_CTRL); + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_RESUME: + default: + /* Just leave in disabled state */ + break; + } + +} + +static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) +{ + unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); + + writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + writel(next, clkevt_base + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + + return 0; +} + +static struct clock_event_device integrator_clockevent = { + .name = "timer1", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = clkevt_set_mode, + .set_next_event = clkevt_set_next_event, + .rating = 300, +}; + +static struct irqaction integrator_timer_irq = { + .name = "timer", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = integrator_timer_interrupt, + .dev_id = &integrator_clockevent, +}; + +static void integrator_clockevent_init(unsigned long inrate, + void __iomem *base, int irq) +{ + unsigned long rate = inrate; + unsigned int ctrl = 0; + + clkevt_base = base; + /* Calculate and program a divisor */ + if (rate > 0x100000 * HZ) { + rate /= 256; + ctrl |= TIMER_CTRL_DIV256; + } else if (rate > 0x10000 * HZ) { + rate /= 16; + ctrl |= TIMER_CTRL_DIV16; + } + timer_reload = rate / HZ; + writel(ctrl, clkevt_base + TIMER_CTRL); + + setup_irq(irq, &integrator_timer_irq); + clockevents_config_and_register(&integrator_clockevent, + rate, + 1, + 0xffffU); +} + +static void __init integrator_ap_timer_init_of(struct device_node *node) +{ + const char *path; + void __iomem *base; + int err; + int irq; + struct clk *clk; + unsigned long rate; + struct device_node *pri_node; + struct device_node *sec_node; + + base = of_io_request_and_map(node, 0, "integrator-timer"); + if (!base) + return; + + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_err("No clock for %s\n", node->name); + return; + } + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + writel(0, base + TIMER_CTRL); + + err = of_property_read_string(of_aliases, + "arm,timer-primary", &path); + if (WARN_ON(err)) + return; + pri_node = of_find_node_by_path(path); + err = of_property_read_string(of_aliases, + "arm,timer-secondary", &path); + if (WARN_ON(err)) + return; + sec_node = of_find_node_by_path(path); + + if (node == pri_node) { + /* The primary timer lacks IRQ, use as clocksource */ + integrator_clocksource_init(rate, base); + return; + } + + if (node == sec_node) { + /* The secondary timer will drive the clock event */ + irq = irq_of_parse_and_map(node, 0); + integrator_clockevent_init(rate, base, irq); + return; + } + + pr_info("Timer @%p unused\n", base); + clk_disable_unprepare(clk); +} + +CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer", + integrator_ap_timer_init_of); -- cgit v1.2.3-59-g8ed1b From a8d2ff39c7c4a5ce50df2a47d5f8523810dd4c29 Mon Sep 17 00:00:00 2001 From: Hisashi Nakamura Date: Fri, 24 Oct 2014 17:33:08 +0900 Subject: ARM: shmobile: Separate APMU resource data into CPU dependant part APMU resources are not common to all R-Car SoCs so don't share this data. A subsequent patch will correct the CPU cores for the r8a7791. Signed-off-by: Hisashi Nakamura Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/common.h | 5 ----- arch/arm/mach-shmobile/platsmp-apmu.c | 27 +++++++++------------------ arch/arm/mach-shmobile/platsmp-apmu.h | 32 ++++++++++++++++++++++++++++++++ arch/arm/mach-shmobile/smp-r8a7790.c | 16 +++++++++++++++- arch/arm/mach-shmobile/smp-r8a7791.c | 16 +++++++++++++++- 5 files changed, 71 insertions(+), 25 deletions(-) create mode 100644 arch/arm/mach-shmobile/platsmp-apmu.h diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h index 72087c79ad7b..309025efd4cf 100644 --- a/arch/arm/mach-shmobile/common.h +++ b/arch/arm/mach-shmobile/common.h @@ -19,11 +19,6 @@ extern void shmobile_boot_scu(void); extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus); extern void shmobile_smp_scu_cpu_die(unsigned int cpu); extern int shmobile_smp_scu_cpu_kill(unsigned int cpu); -extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus); -extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu, - struct task_struct *idle); -extern void shmobile_smp_apmu_cpu_die(unsigned int cpu); -extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu); struct clk; extern int shmobile_clk_init(void); extern void shmobile_handle_irq_intc(struct pt_regs *); diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c index 2c06810d3a70..f483b560b066 100644 --- a/arch/arm/mach-shmobile/platsmp-apmu.c +++ b/arch/arm/mach-shmobile/platsmp-apmu.c @@ -1,6 +1,7 @@ /* * SMP support for SoCs with APMU * + * Copyright (C) 2014 Renesas Electronics Corporation * Copyright (C) 2013 Magnus Damm * * This program is free software; you can redistribute it and/or modify @@ -22,6 +23,7 @@ #include #include #include "common.h" +#include "platsmp-apmu.h" static struct { void __iomem *iomem; @@ -83,28 +85,15 @@ static void apmu_init_cpu(struct resource *res, int cpu, int bit) pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res); } -static struct { - struct resource iomem; - int cpus[4]; -} apmu_config[] = { - { - .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), - .cpus = { 0, 1, 2, 3 }, - }, - { - .iomem = DEFINE_RES_MEM(0xe6151000, 0x88), - .cpus = { 0x100, 0x101, 0x102, 0x103 }, - } -}; - -static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit)) +static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit), + struct rcar_apmu_config *apmu_config, int num) { u32 id; int k; int bit, index; bool is_allowed; - for (k = 0; k < ARRAY_SIZE(apmu_config); k++) { + for (k = 0; k < num; k++) { /* only enable the cluster that includes the boot CPU */ is_allowed = false; for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) { @@ -128,14 +117,16 @@ static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit)) } } -void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus) +void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus, + struct rcar_apmu_config *apmu_config, + int num) { /* install boot code shared by all CPUs */ shmobile_boot_fn = virt_to_phys(shmobile_smp_boot); shmobile_boot_arg = MPIDR_HWID_BITMASK; /* perform per-cpu setup */ - apmu_parse_cfg(apmu_init_cpu); + apmu_parse_cfg(apmu_init_cpu, apmu_config, num); } #ifdef CONFIG_SMP diff --git a/arch/arm/mach-shmobile/platsmp-apmu.h b/arch/arm/mach-shmobile/platsmp-apmu.h new file mode 100644 index 000000000000..76512c9a2545 --- /dev/null +++ b/arch/arm/mach-shmobile/platsmp-apmu.h @@ -0,0 +1,32 @@ +/* + * rmobile apmu definition + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef PLATSMP_APMU_H +#define PLATSMP_APMU_H + +struct rcar_apmu_config { + struct resource iomem; + int cpus[4]; +}; + +extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus, + struct rcar_apmu_config *apmu_config, + int num); +extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu, + struct task_struct *idle); +extern void shmobile_smp_apmu_cpu_die(unsigned int cpu); +extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu); + +#endif /* PLATSMP_APMU_H */ diff --git a/arch/arm/mach-shmobile/smp-r8a7790.c b/arch/arm/mach-shmobile/smp-r8a7790.c index 2311694636e1..9c3da1345b8b 100644 --- a/arch/arm/mach-shmobile/smp-r8a7790.c +++ b/arch/arm/mach-shmobile/smp-r8a7790.c @@ -21,6 +21,7 @@ #include #include "common.h" +#include "platsmp-apmu.h" #include "pm-rcar.h" #include "r8a7790.h" @@ -34,10 +35,23 @@ static struct rcar_sysc_ch r8a7790_ca7_scu = { .isr_bit = 21, /* CA7-SCU */ }; +static struct rcar_apmu_config r8a7790_apmu_config[] = { + { + .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), + .cpus = { 0, 1, 2, 3 }, + }, + { + .iomem = DEFINE_RES_MEM(0xe6151000, 0x88), + .cpus = { 0x100, 0x0101, 0x102, 0x103 }, + } +}; + static void __init r8a7790_smp_prepare_cpus(unsigned int max_cpus) { /* let APMU code install data related to shmobile_boot_vector */ - shmobile_smp_apmu_prepare_cpus(max_cpus); + shmobile_smp_apmu_prepare_cpus(max_cpus, + r8a7790_apmu_config, + ARRAY_SIZE(r8a7790_apmu_config)); /* turn on power to SCU */ r8a7790_pm_init(); diff --git a/arch/arm/mach-shmobile/smp-r8a7791.c b/arch/arm/mach-shmobile/smp-r8a7791.c index f743386166fb..96e392c2573c 100644 --- a/arch/arm/mach-shmobile/smp-r8a7791.c +++ b/arch/arm/mach-shmobile/smp-r8a7791.c @@ -21,13 +21,27 @@ #include #include "common.h" +#include "platsmp-apmu.h" #include "r8a7791.h" #include "rcar-gen2.h" +static struct rcar_apmu_config r8a7791_apmu_config[] = { + { + .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), + .cpus = { 0, 1, 2, 3 }, + }, + { + .iomem = DEFINE_RES_MEM(0xe6151000, 0x88), + .cpus = { 0x100, 0x0101, 0x102, 0x103 }, + } +}; + static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus) { /* let APMU code install data related to shmobile_boot_vector */ - shmobile_smp_apmu_prepare_cpus(max_cpus); + shmobile_smp_apmu_prepare_cpus(max_cpus, + r8a7791_apmu_config, + ARRAY_SIZE(r8a7791_apmu_config)); r8a7791_pm_init(); } -- cgit v1.2.3-59-g8ed1b From 7466c52e1706d98392b6a4650b04e94f39f3a794 Mon Sep 17 00:00:00 2001 From: Hisashi Nakamura Date: Fri, 24 Oct 2014 17:33:09 +0900 Subject: ARM: shmobile: r8a7791: Correct number of CPU cores The r8a7791 only has 2 CPU CA15 cores, not 4 CA15 and 4 CA7 cores. Signed-off-by: Hisashi Nakamura Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/smp-r8a7791.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/arm/mach-shmobile/smp-r8a7791.c b/arch/arm/mach-shmobile/smp-r8a7791.c index 96e392c2573c..7e49e0a52e32 100644 --- a/arch/arm/mach-shmobile/smp-r8a7791.c +++ b/arch/arm/mach-shmobile/smp-r8a7791.c @@ -28,11 +28,7 @@ static struct rcar_apmu_config r8a7791_apmu_config[] = { { .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), - .cpus = { 0, 1, 2, 3 }, - }, - { - .iomem = DEFINE_RES_MEM(0xe6151000, 0x88), - .cpus = { 0x100, 0x0101, 0x102, 0x103 }, + .cpus = { 0, 1 }, } }; -- cgit v1.2.3-59-g8ed1b From 950a3f0e7dd32c372c9957d5c050b08de7ec9e56 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Tue, 4 Nov 2014 17:38:28 +0000 Subject: ARM: shmobile: Enable PCI domains for R-Car Gen2 devices The PCI core will soon automatically handle the PCI domain number, allowing the internal PCI and external PCIe bridges work at the same time. In order for that to work, we need to enable PCI_DOMAINS. Signed-off-by: Phil Edworthy Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 6bc018fc5dc1..b0a9e1a7955a 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -19,6 +19,7 @@ config ARCH_RCAR_GEN2 select PM_RCAR if PM || SMP select RENESAS_IRQC select SYS_SUPPORTS_SH_CMT + select PCI_DOMAINS if PCI config ARCH_RMOBILE bool -- cgit v1.2.3-59-g8ed1b From d003b58c8389d596e9fc6a131fc2901e3d039343 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 15 Oct 2014 10:23:00 -0700 Subject: ARM: rockchip: convert to regmap and use pmu syscon if available The pmu register space is - like the GRF - shared by quite some peripherals. On the rk3188 and rk3288 even parts of the pinctrl are living there. Therefore we normally shouldn't map it a second time when the syscon does this already. Therefore convert the cpu power-domain handling to access the pmu via a regmap and at first try to get it via the syscon interface. Getting this syscon will only fail if the pmu node does not have the "syscon" compatible and thus does not get shared with other drivers. In this case we map it like before and create the necessary regmap on top of it. Signed-off-by: Kever Yang Tested-by: Kevin Hilman Signed-off-by: Heiko Stuebner --- arch/arm/mach-rockchip/platsmp.c | 104 +++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 189684f55927..4c36fbf99afb 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -37,23 +39,42 @@ static int ncores; #define PMU_PWRDN_SCU 4 -static void __iomem *pmu_base_addr; +static struct regmap *pmu; -static inline bool pmu_power_domain_is_on(int pd) +static int pmu_power_domain_is_on(int pd) { - return !(readl_relaxed(pmu_base_addr + PMU_PWRDN_ST) & BIT(pd)); + u32 val; + int ret; + + ret = regmap_read(pmu, PMU_PWRDN_ST, &val); + if (ret < 0) + return ret; + + return !(val & BIT(pd)); } -static void pmu_set_power_domain(int pd, bool on) +static int pmu_set_power_domain(int pd, bool on) { - u32 val = readl_relaxed(pmu_base_addr + PMU_PWRDN_CON); - if (on) - val &= ~BIT(pd); - else - val |= BIT(pd); - writel(val, pmu_base_addr + PMU_PWRDN_CON); - - while (pmu_power_domain_is_on(pd) != on) { } + u32 val = (on) ? 0 : BIT(pd); + int ret; + + ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val); + if (ret < 0) { + pr_err("%s: could not update power domain\n", __func__); + return ret; + } + + ret = -1; + while (ret != on) { + ret = pmu_power_domain_is_on(pd); + if (ret < 0) { + pr_err("%s: could not read power domain state\n", + __func__); + return ret; + } + } + + return 0; } /* @@ -63,7 +84,7 @@ static void pmu_set_power_domain(int pd, bool on) static int __cpuinit rockchip_boot_secondary(unsigned int cpu, struct task_struct *idle) { - if (!sram_base_addr || !pmu_base_addr) { + if (!sram_base_addr || !pmu) { pr_err("%s: sram or pmu missing for cpu boot\n", __func__); return -ENXIO; } @@ -75,9 +96,7 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu, } /* start the core */ - pmu_set_power_domain(0 + cpu, true); - - return 0; + return pmu_set_power_domain(0 + cpu, true); } /** @@ -125,6 +144,48 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node) return 0; } +static struct regmap_config rockchip_pmu_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int __init rockchip_smp_prepare_pmu(void) +{ + struct device_node *node; + void __iomem *pmu_base; + + pmu = syscon_regmap_lookup_by_compatible("rockchip,rk3066-pmu"); + if (!IS_ERR(pmu)) + return 0; + + /* fallback, create our own regmap for the pmu area */ + pmu = NULL; + node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu"); + if (!node) { + pr_err("%s: could not find pmu dt node\n", __func__); + return -ENODEV; + } + + pmu_base = of_iomap(node, 0); + if (!pmu_base) { + pr_err("%s: could not map pmu registers\n", __func__); + return -ENOMEM; + } + + pmu = regmap_init_mmio(NULL, pmu_base, &rockchip_pmu_regmap_config); + if (IS_ERR(pmu)) { + int ret = PTR_ERR(pmu); + + iounmap(pmu_base); + pmu = NULL; + pr_err("%s: regmap init failed\n", __func__); + return ret; + } + + return 0; +} + static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) { struct device_node *node; @@ -151,17 +212,8 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) if (rockchip_smp_prepare_sram(node)) return; - node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu"); - if (!node) { - pr_err("%s: could not find pmu dt node\n", __func__); + if (rockchip_smp_prepare_pmu()) return; - } - - pmu_base_addr = of_iomap(node, 0); - if (!pmu_base_addr) { - pr_err("%s: could not map pmu registers\n", __func__); - return; - } /* enable the SCU power domain */ pmu_set_power_domain(PMU_PWRDN_SCU, true); -- cgit v1.2.3-59-g8ed1b From 6de2d21adaf05b7a456077625b6e311feabd3718 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 15 Oct 2014 10:23:01 -0700 Subject: ARM: rockchip: add option to access the pmu via a phandle in smp_operations Makes it possible to define a rockchip,pmu phandle in the cpus node directly referencing the pmu syscon instead of searching for specific compatible. The old way of finding the pmu stays of course available. Signed-off-by: Kever Yang Tested-by: Kevin Hilman Signed-off-by: Heiko Stuebner --- Documentation/devicetree/bindings/arm/cpus.txt | 9 +++++++++ arch/arm/mach-rockchip/platsmp.c | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index fc446347ab6d..b2aacbe16ed9 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt @@ -227,6 +227,15 @@ nodes to be present and contain the properties described below. # List of phandles to idle state nodes supported by this cpu [3]. + - rockchip,pmu + Usage: optional for systems that have an "enable-method" + property value of "rockchip,rk3066-smp" + While optional, it is the preferred way to get access to + the cpu-core power-domains. + Value type: + Definition: Specifies the syscon node controlling the cpu core + power domains. + Example 1 (dual-cluster big.LITTLE system 32-bit): cpus { diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 4c36fbf99afb..57b53b32e103 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -155,6 +155,19 @@ static int __init rockchip_smp_prepare_pmu(void) struct device_node *node; void __iomem *pmu_base; + /* + * This function is only called via smp_ops->smp_prepare_cpu(). + * That only happens if a "/cpus" device tree node exists + * and has an "enable-method" property that selects the SMP + * operations defined herein. + */ + node = of_find_node_by_path("/cpus"); + + pmu = syscon_regmap_lookup_by_phandle(node, "rockchip,pmu"); + of_node_put(node); + if (!IS_ERR(pmu)) + return 0; + pmu = syscon_regmap_lookup_by_compatible("rockchip,rk3066-pmu"); if (!IS_ERR(pmu)) return 0; -- cgit v1.2.3-59-g8ed1b From 3ee851e212d0bb6be8c462059fba74ce2e3f6064 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Wed, 15 Oct 2014 10:23:03 -0700 Subject: ARM: rockchip: add basic smp support for rk3288 This patch add basic rk3288 smp support. Only cortex-A9 need invalid L1, A7/A12/A15/A17 should not invalid L1, since for A7/A12/A15, the invalidation would be taken as clean and invalidate. If you use the software manual invalidation instead of hardware invalidation (assert l1/l2rstdisable during reset) after reset, there is tiny change that some cachelines would be in dirty and valid state after reset(since the ram content would be random value after reset), then the unexpected clean might lead to system crash. It is a known issue for the A12/A17 MPCore multiprocessor that the active processors might be stalled when the individual processor is powered down, we can avoid this prolbem by softreset the processor before power it down. Signed-off-by: Kever Yang Tested-by: Kevin Hilman Signed-off-by: Heiko Stuebner --- arch/arm/mach-rockchip/headsmp.S | 5 +- arch/arm/mach-rockchip/platsmp.c | 120 +++++++++++++++++++++++++++++++-------- 2 files changed, 100 insertions(+), 25 deletions(-) diff --git a/arch/arm/mach-rockchip/headsmp.S b/arch/arm/mach-rockchip/headsmp.S index 73206e360e31..46c22dedf632 100644 --- a/arch/arm/mach-rockchip/headsmp.S +++ b/arch/arm/mach-rockchip/headsmp.S @@ -16,7 +16,10 @@ #include ENTRY(rockchip_secondary_startup) - bl v7_invalidate_l1 + mrc p15, 0, r0, c0, c0, 0 @ read main ID register + ldr r1, =0x00000c09 @ Cortex-A9 primary part number + teq r0, r1 + beq v7_invalidate_l1 b secondary_startup ENDPROC(rockchip_secondary_startup) diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 57b53b32e103..f26fcdca2445 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include #include @@ -53,11 +55,47 @@ static int pmu_power_domain_is_on(int pd) return !(val & BIT(pd)); } +struct reset_control *rockchip_get_core_reset(int cpu) +{ + struct device *dev = get_cpu_device(cpu); + struct device_node *np; + + /* The cpu device is only available after the initial core bringup */ + if (dev) + np = dev->of_node; + else + np = of_get_cpu_node(cpu, 0); + + return of_reset_control_get(np, NULL); +} + static int pmu_set_power_domain(int pd, bool on) { u32 val = (on) ? 0 : BIT(pd); int ret; + /* + * We need to soft reset the cpu when we turn off the cpu power domain, + * or else the active processors might be stalled when the individual + * processor is powered down. + */ + if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) { + struct reset_control *rstc = rockchip_get_core_reset(pd); + + if (IS_ERR(rstc)) { + pr_err("%s: could not get reset control for core %d\n", + __func__, pd); + return PTR_ERR(rstc); + } + + if (on) + reset_control_deassert(rstc); + else + reset_control_assert(rstc); + + reset_control_put(rstc); + } + ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val); if (ret < 0) { pr_err("%s: could not update power domain\n", __func__); @@ -84,6 +122,8 @@ static int pmu_set_power_domain(int pd, bool on) static int __cpuinit rockchip_boot_secondary(unsigned int cpu, struct task_struct *idle) { + int ret; + if (!sram_base_addr || !pmu) { pr_err("%s: sram or pmu missing for cpu boot\n", __func__); return -ENXIO; @@ -96,7 +136,26 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu, } /* start the core */ - return pmu_set_power_domain(0 + cpu, true); + ret = pmu_set_power_domain(0 + cpu, true); + if (ret < 0) + return ret; + + if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) { + /* We communicate with the bootrom to active the cpus other + * than cpu0, after a blob of initialize code, they will + * stay at wfe state, once they are actived, they will check + * the mailbox: + * sram_base_addr + 4: 0xdeadbeaf + * sram_base_addr + 8: start address for pc + * */ + udelay(10); + writel(virt_to_phys(rockchip_secondary_startup), + sram_base_addr + 8); + writel(0xDEADBEAF, sram_base_addr + 4); + dsb_sev(); + } + + return 0; } /** @@ -129,8 +188,6 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node) return -EINVAL; } - sram_base_addr = of_iomap(node, 0); - /* set the boot function for the sram code */ rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup); @@ -204,40 +261,55 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) struct device_node *node; unsigned int i; - node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); - if (!node) { - pr_err("%s: missing scu\n", __func__); - return; - } - - scu_base_addr = of_iomap(node, 0); - if (!scu_base_addr) { - pr_err("%s: could not map scu registers\n", __func__); - return; - } - node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram"); if (!node) { pr_err("%s: could not find sram dt node\n", __func__); return; } - if (rockchip_smp_prepare_sram(node)) + sram_base_addr = of_iomap(node, 0); + if (!sram_base_addr) { + pr_err("%s: could not map sram registers\n", __func__); return; + } if (rockchip_smp_prepare_pmu()) return; - /* enable the SCU power domain */ - pmu_set_power_domain(PMU_PWRDN_SCU, true); + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { + if (rockchip_smp_prepare_sram(node)) + return; - /* - * While the number of cpus is gathered from dt, also get the number - * of cores from the scu to verify this value when booting the cores. - */ - ncores = scu_get_core_count(scu_base_addr); + /* enable the SCU power domain */ + pmu_set_power_domain(PMU_PWRDN_SCU, true); + + node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); + if (!node) { + pr_err("%s: missing scu\n", __func__); + return; + } - scu_enable(scu_base_addr); + scu_base_addr = of_iomap(node, 0); + if (!scu_base_addr) { + pr_err("%s: could not map scu registers\n", __func__); + return; + } + + /* + * While the number of cpus is gathered from dt, also get the + * number of cores from the scu to verify this value when + * booting the cores. + */ + ncores = scu_get_core_count(scu_base_addr); + pr_err("%s: ncores %d\n", __func__, ncores); + + scu_enable(scu_base_addr); + } else { + unsigned int l2ctlr; + + asm ("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr)); + ncores = ((l2ctlr >> 24) & 0x3) + 1; + } /* Make sure that all cores except the first are really off */ for (i = 1; i < ncores; i++) -- cgit v1.2.3-59-g8ed1b From 172ed82cef421a205e1f557372a4a1338dc46edc Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 4 Nov 2014 13:00:39 -0300 Subject: ARM: mvebu: Remove thermal quirk for A375 Z1 revision The Armada 375 Z1 SoC revision is no longer supported. This commit removes the quirk required to "fix" the reg property and the compatible string of the thermal devicetree node. Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1415116839-4323-3-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/board-v7.c | 66 +----------------------------------------- 1 file changed, 1 insertion(+), 65 deletions(-) diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index 6478626e3ff6..461e726a7012 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -124,76 +124,12 @@ static void __init i2c_quirk(void) return; } -#define A375_Z1_THERMAL_FIXUP_OFFSET 0xc - -static void __init thermal_quirk(void) -{ - struct device_node *np; - u32 dev, rev; - int res; - - /* - * The early SoC Z1 revision needs a quirk to be applied in order - * for the thermal controller to work properly. This quirk breaks - * the thermal support if applied on a SoC that doesn't need it, - * so we enforce the SoC revision to be known. - */ - res = mvebu_get_soc_id(&dev, &rev); - if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV)) - return; - - for_each_compatible_node(np, NULL, "marvell,armada375-thermal") { - struct property *prop; - __be32 newval, *newprop, *oldprop; - int len; - - /* - * The register offset is at a wrong location. This quirk - * creates a new reg property as a clone of the previous - * one and corrects the offset. - */ - oldprop = (__be32 *)of_get_property(np, "reg", &len); - if (!oldprop) - continue; - - /* Create a duplicate of the 'reg' property */ - prop = kzalloc(sizeof(*prop), GFP_KERNEL); - prop->length = len; - prop->name = kstrdup("reg", GFP_KERNEL); - prop->value = kzalloc(len, GFP_KERNEL); - memcpy(prop->value, oldprop, len); - - /* Fixup the register offset of the second entry */ - oldprop += 2; - newprop = (__be32 *)prop->value + 2; - newval = cpu_to_be32(be32_to_cpu(*oldprop) - - A375_Z1_THERMAL_FIXUP_OFFSET); - *newprop = newval; - of_update_property(np, prop); - - /* - * The thermal controller needs some quirk too, so let's change - * the compatible string to reflect this and allow the driver - * the take the necessary action. - */ - prop = kzalloc(sizeof(*prop), GFP_KERNEL); - prop->name = kstrdup("compatible", GFP_KERNEL); - prop->length = sizeof("marvell,armada375-z1-thermal"); - prop->value = kstrdup("marvell,armada375-z1-thermal", - GFP_KERNEL); - of_update_property(np, prop); - } - return; -} - static void __init mvebu_dt_init(void) { if (of_machine_is_compatible("plathome,openblocks-ax3-4")) i2c_quirk(); - if (of_machine_is_compatible("marvell,a375-db")) { + if (of_machine_is_compatible("marvell,a375-db")) external_abort_quirk(); - thermal_quirk(); - } of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } -- cgit v1.2.3-59-g8ed1b From 534547c036afad3f23d49d8352896f5d05709685 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 7 Nov 2014 14:46:32 +0100 Subject: ARM: shmobile: kzm9g-reference: Add restart callback Port the sh73a0 restart handling from the kzm9g-legacy board code to the kzm9g-reference board code. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/board-kzm9g-reference.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/mach-shmobile/board-kzm9g-reference.c b/arch/arm/mach-shmobile/board-kzm9g-reference.c index d9cdf9a97e23..0e1de7455c5c 100644 --- a/arch/arm/mach-shmobile/board-kzm9g-reference.c +++ b/arch/arm/mach-shmobile/board-kzm9g-reference.c @@ -43,6 +43,13 @@ static void __init kzm_init(void) #endif } +#define RESCNT2 IOMEM(0xe6188020) +static void kzm9g_restart(enum reboot_mode mode, const char *cmd) +{ + /* Do soft power on reset */ + writel((1 << 31), RESCNT2); +} + static const char *kzm9g_boards_compat_dt[] __initdata = { "renesas,kzm9g-reference", NULL, @@ -54,5 +61,6 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g-reference") .init_early = shmobile_init_delay, .init_machine = kzm_init, .init_late = shmobile_init_late, + .restart = kzm9g_restart, .dt_compat = kzm9g_boards_compat_dt, MACHINE_END -- cgit v1.2.3-59-g8ed1b From 9008d83fe9dc2e0f19b8ba17a423b3759d8e0fd7 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 21 Oct 2014 15:22:28 -0500 Subject: ARM: OMAP4: PM: Only do static dependency configuration in omap4_init_static_deps Commit 705814b5ea6f ("ARM: OMAP4+: PM: Consolidate OMAP4 PM code to re-use it for OMAP5") Moved logic generic for OMAP5+ as part of the init routine by introducing omap4_pm_init. However, the patch left the powerdomain initial setup, an unused omap4430 es1.0 check and a spurious log "Power Management for TI OMAP4." in the original code. Remove the duplicate code which is already present in omap4_pm_init from omap4_init_static_deps. As part of this change, also move the u-boot version print out of the static dependency function to the omap4_pm_init function. Fixes: 705814b5ea6f ("ARM: OMAP4+: PM: Consolidate OMAP4 PM code to re-use it for OMAP5") Signed-off-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/pm44xx.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 503097c72b82..e7f823b960c2 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -160,26 +160,6 @@ static inline int omap4_init_static_deps(void) struct clockdomain *ducati_clkdm, *l3_2_clkdm; int ret = 0; - if (omap_rev() == OMAP4430_REV_ES1_0) { - WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); - return -ENODEV; - } - - pr_err("Power Management for TI OMAP4.\n"); - /* - * OMAP4 chip PM currently works only with certain (newer) - * versions of bootloaders. This is due to missing code in the - * kernel to properly reset and initialize some devices. - * http://www.spinics.net/lists/arm-kernel/msg218641.html - */ - pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n"); - - ret = pwrdm_for_each(pwrdms_setup, NULL); - if (ret) { - pr_err("Failed to setup powerdomains\n"); - return ret; - } - /* * The dynamic dependency between MPUSS -> MEMIF and * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as @@ -272,6 +252,15 @@ int __init omap4_pm_init(void) pr_info("Power Management for TI OMAP4+ devices.\n"); + /* + * OMAP4 chip PM currently works only with certain (newer) + * versions of bootloaders. This is due to missing code in the + * kernel to properly reset and initialize some devices. + * http://www.spinics.net/lists/arm-kernel/msg218641.html + */ + if (cpu_is_omap44xx()) + pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n"); + ret = pwrdm_for_each(pwrdms_setup, NULL); if (ret) { pr_err("Failed to setup powerdomains.\n"); -- cgit v1.2.3-59-g8ed1b From b9f5fe6425ef1622fb0f16f0fa33f19b993863a6 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 21 Oct 2014 15:22:29 -0500 Subject: ARM: OMAP4+: PM: Centralize static dependency mapping table As we add more static dependency mapping for various errata, the logic gets clunkier. Since it is a simple lookup and map logic, centralize the same and provide the mapping as a simple list. Signed-off-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/pm44xx.c | 117 +++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index e7f823b960c2..d697cecf762b 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -37,6 +37,16 @@ struct power_state { struct list_head node; }; +/** + * struct static_dep_map - Static dependency map + * @from: from clockdomain + * @to: to clockdomain + */ +struct static_dep_map { + const char *from; + const char *to; +}; + static u32 cpu_suspend_state = PWRDM_POWER_OFF; static LIST_HEAD(pwrst_list); @@ -148,74 +158,61 @@ static void omap_default_idle(void) omap_do_wfi(); } -/** - * omap4_init_static_deps - Add OMAP4 static dependencies - * - * Add needed static clockdomain dependencies on OMAP4 devices. - * Return: 0 on success or 'err' on failures +/* + * The dynamic dependency between MPUSS -> MEMIF and + * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as + * expected. The hardware recommendation is to enable static + * dependencies for these to avoid system lock ups or random crashes. + * The L4 wakeup depedency is added to workaround the OCP sync hardware + * BUG with 32K synctimer which lead to incorrect timer value read + * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which + * are part of L4 wakeup clockdomain. */ -static inline int omap4_init_static_deps(void) -{ - struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm; - struct clockdomain *ducati_clkdm, *l3_2_clkdm; - int ret = 0; - - /* - * The dynamic dependency between MPUSS -> MEMIF and - * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as - * expected. The hardware recommendation is to enable static - * dependencies for these to avoid system lock ups or random crashes. - * The L4 wakeup depedency is added to workaround the OCP sync hardware - * BUG with 32K synctimer which lead to incorrect timer value read - * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which - * are part of L4 wakeup clockdomain. - */ - mpuss_clkdm = clkdm_lookup("mpuss_clkdm"); - emif_clkdm = clkdm_lookup("l3_emif_clkdm"); - l3_1_clkdm = clkdm_lookup("l3_1_clkdm"); - l3_2_clkdm = clkdm_lookup("l3_2_clkdm"); - ducati_clkdm = clkdm_lookup("ducati_clkdm"); - if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) || - (!l3_2_clkdm) || (!ducati_clkdm)) - return -EINVAL; - - ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm); - ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm); - ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm); - ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm); - ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm); - if (ret) { - pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 wakeup dependency\n"); - return -EINVAL; - } +static const struct static_dep_map omap4_static_dep_map[] = { + {.from = "mpuss_clkdm", .to = "l3_emif_clkdm"}, + {.from = "mpuss_clkdm", .to = "l3_1_clkdm"}, + {.from = "mpuss_clkdm", .to = "l3_2_clkdm"}, + {.from = "ducati_clkdm", .to = "l3_1_clkdm"}, + {.from = "ducati_clkdm", .to = "l3_2_clkdm"}, + {.from = NULL} /* TERMINATION */ +}; - return ret; -} +static const struct static_dep_map omap5_dra7_static_dep_map[] = { + {.from = "mpu_clkdm", .to = "emif_clkdm"}, + {.from = NULL} /* TERMINATION */ +}; /** - * omap5_dra7_init_static_deps - Init static clkdm dependencies on OMAP5 and - * DRA7 - * - * The dynamic dependency between MPUSS -> EMIF is broken and has - * not worked as expected. The hardware recommendation is to - * enable static dependencies for these to avoid system - * lock ups or random crashes. + * omap4plus_init_static_deps() - Initialize a static dependency map + * @map: Mapping of clock domains */ -static inline int omap5_dra7_init_static_deps(void) +static inline int omap4plus_init_static_deps(const struct static_dep_map *map) { - struct clockdomain *mpuss_clkdm, *emif_clkdm; int ret; + struct clockdomain *from, *to; - mpuss_clkdm = clkdm_lookup("mpu_clkdm"); - emif_clkdm = clkdm_lookup("emif_clkdm"); - if (!mpuss_clkdm || !emif_clkdm) - return -EINVAL; + if (!map) + return 0; + + while (map->from) { + from = clkdm_lookup(map->from); + to = clkdm_lookup(map->to); + if (!from || !to) { + pr_err("Failed lookup %s or %s for wakeup dependency\n", + map->from, map->to); + return -EINVAL; + } + ret = clkdm_add_wkdep(from, to); + if (ret) { + pr_err("Failed to add %s -> %s wakeup dependency(%d)\n", + map->from, map->to, ret); + return ret; + } - ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm); - if (ret) - pr_err("Failed to add MPUSS -> EMIF wakeup dependency\n"); + map++; + }; - return ret; + return 0; } /** @@ -268,9 +265,9 @@ int __init omap4_pm_init(void) } if (cpu_is_omap44xx()) - ret = omap4_init_static_deps(); + ret = omap4plus_init_static_deps(omap4_static_dep_map); else if (soc_is_omap54xx() || soc_is_dra7xx()) - ret = omap5_dra7_init_static_deps(); + ret = omap4plus_init_static_deps(omap5_dra7_static_dep_map); if (ret) { pr_err("Failed to initialise static dependencies.\n"); -- cgit v1.2.3-59-g8ed1b From a30d81b98a778c4ce113ba9c2e03deb2f9522d66 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 21 Oct 2014 15:24:36 -0500 Subject: ARM: OMAP4+: PM: Program CPU logic power state CPU logic power state is never programmed in either the initialization or the suspend/resume logic, instead, we depend on mpuss to program this properly. However, this leaves CPU logic power state indeterminate and most probably in reset configuration (If bootloader or other similar software have'nt monkeyed with the register). This can make powerstate= RET be either programmed for CSWR (logic=ret) or OSWR(logic = OFF) and in OSWR, there can be context loss when the code does not expect it. To prevent all these confusions, just support clearly ON, INA, CSWR, OFF which is the intent of the existing code by explicitly programming logic state. NOTE: since this is a hot path (using in cpuidle), the exit path just programs powerstate (logic state is immaterial when powerstate is ON). Without doing this, we end up with lockups when CPUs enter OSWR and multiple blocks loose context, when we expect them to hit CSWR. Signed-off-by: Nishanth Menon Acked-by: Kevin Hilman Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap-mpuss-lowpower.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 6944ae3674e8..79f49d904a06 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -227,7 +227,7 @@ static void __init save_l2x0_context(void) int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); - unsigned int save_state = 0; + unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET; unsigned int wakeup_cpu; if (omap_rev() == OMAP4430_REV_ES1_0) @@ -239,6 +239,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) save_state = 0; break; case PWRDM_POWER_OFF: + cpu_logic_state = PWRDM_POWER_OFF; save_state = 1; break; case PWRDM_POWER_RET: @@ -270,6 +271,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) cpu_clear_prev_logic_pwrst(cpu); pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); + pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state); set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume)); omap_pm_ops.scu_prepare(cpu, power_state); l2x0_pwrst_prepare(cpu, save_state); -- cgit v1.2.3-59-g8ed1b From dc680b989d519952e0e0d37204fec850925a0225 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 10 Nov 2014 18:52:31 +0100 Subject: ARM: fix multiplatform allmodcompile Commit 68f3b875f7848f5304472184a4634148c5330cbd "ARM: integrator: make the Integrator multiplatform" broke allmodconfig like this: >> arch/arm/include/asm/cmpxchg.h:114:2: error: #error "SMP is not supported on this platform" (etc) This is due to the fact that as we turned on multiplatform for the Integrator, this enabled a lot of non-applicable CPU's to be selected for its multiplatform images, due to a lot of "depends on ARCH_INTEGRATOR" restrictions in arch/arm/mm/Kconfig for the different ARM CPU types. Fix this by restricting the CPU selections to respective multiplatform config, which now becomes a subset of the possible Integrator configurations, or alternatively the non-multiplatform config plus ARCH_INTEGRATOR, i.e.: if (!ARCH_MULTIPLATFORM || ARCH_MULTI_Vx) && (ARCH_INTEGRATOR || ARCH_FOO ...) Since the Integrator has been converted to multiplatform, this will often take the short form: if (ARCH_MULTI_Vx && ARCH_INTEGRATOR) If no other non-multiplatform platforms are elegible. Reported-by: Build bot for Mark Brown Reported-by: Kbuild test robot Suggested-by: Russell King Signed-off-by: Linus Walleij Signed-off-by: Arnd Bergmann --- arch/arm/mm/Kconfig | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index ae69809a9e47..179a100493f5 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -21,7 +21,7 @@ config CPU_ARM7TDMI # ARM720T config CPU_ARM720T - bool "Support ARM720T processor" if ARCH_INTEGRATOR + bool "Support ARM720T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) select CPU_32v4T select CPU_ABRT_LV4T select CPU_CACHE_V4 @@ -39,7 +39,7 @@ config CPU_ARM720T # ARM740T config CPU_ARM740T - bool "Support ARM740T processor" if ARCH_INTEGRATOR + bool "Support ARM740T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) depends on !MMU select CPU_32v4T select CPU_ABRT_LV4T @@ -71,7 +71,7 @@ config CPU_ARM9TDMI # ARM920T config CPU_ARM920T - bool "Support ARM920T processor" if ARCH_INTEGRATOR + bool "Support ARM920T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) select CPU_32v4T select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -89,7 +89,7 @@ config CPU_ARM920T # ARM922T config CPU_ARM922T - bool "Support ARM922T processor" if ARCH_INTEGRATOR + bool "Support ARM922T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) select CPU_32v4T select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -127,7 +127,7 @@ config CPU_ARM925T # ARM926T config CPU_ARM926T - bool "Support ARM926T processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB + bool "Support ARM926T processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V5) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB) select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_CACHE_VIVT @@ -163,7 +163,7 @@ config CPU_FA526 # ARM940T config CPU_ARM940T - bool "Support ARM940T processor" if ARCH_INTEGRATOR + bool "Support ARM940T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) depends on !MMU select CPU_32v4T select CPU_ABRT_NOMMU @@ -181,7 +181,7 @@ config CPU_ARM940T # ARM946E-S config CPU_ARM946E - bool "Support ARM946E-S processor" if ARCH_INTEGRATOR + bool "Support ARM946E-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) depends on !MMU select CPU_32v5 select CPU_ABRT_NOMMU @@ -198,7 +198,7 @@ config CPU_ARM946E # ARM1020 - needs validating config CPU_ARM1020 - bool "Support ARM1020T (rev 0) processor" if ARCH_INTEGRATOR + bool "Support ARM1020T (rev 0) processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) select CPU_32v5 select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -216,7 +216,7 @@ config CPU_ARM1020 # ARM1020E - needs validating config CPU_ARM1020E - bool "Support ARM1020E processor" if ARCH_INTEGRATOR + bool "Support ARM1020E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) depends on n select CPU_32v5 select CPU_ABRT_EV4T @@ -229,7 +229,7 @@ config CPU_ARM1020E # ARM1022E config CPU_ARM1022 - bool "Support ARM1022E processor" if ARCH_INTEGRATOR + bool "Support ARM1022E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) select CPU_32v5 select CPU_ABRT_EV4T select CPU_CACHE_VIVT @@ -247,7 +247,7 @@ config CPU_ARM1022 # ARM1026EJ-S config CPU_ARM1026 - bool "Support ARM1026EJ-S processor" if ARCH_INTEGRATOR + bool "Support ARM1026EJ-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) select CPU_32v5 select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10 select CPU_CACHE_VIVT @@ -358,7 +358,7 @@ config CPU_PJ4B # ARMv6 config CPU_V6 - bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX + bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX) select CPU_32v6 select CPU_ABRT_EV6 select CPU_CACHE_V6 @@ -371,7 +371,7 @@ config CPU_V6 # ARMv6k config CPU_V6K - bool "Support ARM V6K processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX + bool "Support ARM V6K processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX) select CPU_32v6 select CPU_32v6K select CPU_ABRT_EV6 @@ -385,7 +385,7 @@ config CPU_V6K # ARMv7 config CPU_V7 - bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX + bool "Support ARM V7 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V7) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX) select CPU_32v6K select CPU_32v7 select CPU_ABRT_EV7 -- cgit v1.2.3-59-g8ed1b From cad900819fba01760833c6c6ed89f464f9c93690 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 7 Nov 2014 14:46:33 +0100 Subject: ARM: shmobile: sh73a0: Add restart callback Port the sh73a0 restart handling from the kzm9g-legacy board code to the generic sh73a0 code. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/setup-sh73a0.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index b7bd8e509668..3447ca7e90d9 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -775,6 +775,13 @@ void __init sh73a0_add_standard_devices_dt(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } +#define RESCNT2 IOMEM(0xe6188020) +static void sh73a0_restart(enum reboot_mode mode, const char *cmd) +{ + /* Do soft power on reset */ + writel((1 << 31), RESCNT2); +} + static const char *sh73a0_boards_compat_dt[] __initdata = { "renesas,sh73a0", NULL, @@ -786,6 +793,7 @@ DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)") .init_early = sh73a0_init_delay, .init_machine = sh73a0_add_standard_devices_dt, .init_late = shmobile_init_late, + .restart = sh73a0_restart, .dt_compat = sh73a0_boards_compat_dt, MACHINE_END #endif /* CONFIG_USE_OF */ -- cgit v1.2.3-59-g8ed1b From 1b475f8d02f98d6ca549b12c7c64e9c27b6a4c8e Mon Sep 17 00:00:00 2001 From: Jonathan Richardson Date: Fri, 15 Aug 2014 12:52:00 -0700 Subject: ARM: cygnus: Initial support for Broadcom Cygnus SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds initial support for the Cygnus SoC based on Broadcom’s iProc series. Reviewed-by: Ray Jui Reviewed-by: Desmond Liu Reviewed-by: JD (Jiandong) Zheng Tested-by: Jonathan Richardson Signed-off-by: Scott Branden Signed-off-by: Florian Fainelli --- arch/arm/mach-bcm/Kconfig | 32 ++++++++++++++++++++++++++++++++ arch/arm/mach-bcm/Makefile | 3 +++ arch/arm/mach-bcm/bcm_cygnus.c | 25 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 arch/arm/mach-bcm/bcm_cygnus.c diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 2abad742516d..73d95c2b355b 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -5,6 +5,36 @@ menuconfig ARCH_BCM if ARCH_BCM +comment "IPROC architected SoCs" + +config ARCH_BCM_IPROC + bool + select ARM_GIC + select CACHE_L2X0 + select HAVE_ARM_SCU if SMP + select HAVE_ARM_TWD if SMP + select ARM_GLOBAL_TIMER + + select CLKSRC_MMIO + select ARCH_REQUIRE_GPIOLIB + select ARM_AMBA + select PINCTRL + help + This enables support for systems based on Broadcom IPROC architected SoCs. + The IPROC complex contains one or more ARM CPUs along with common + core periperals. Application specific SoCs are created by adding a + uArchitecture containing peripherals outside of the IPROC complex. + Currently supported SoCs are Cygnus. + +config ARCH_BCM_CYGNUS + bool "Broadcom Cygnus Support" if ARCH_MULTI_V7 + select ARCH_BCM_IPROC + help + Enable support for the Cygnus family, + which includes the following variants: + BCM11300, BCM11320, BCM11350, BCM11360, + BCM58300, BCM58302, BCM58303, BCM58305. + config ARCH_BCM_MOBILE bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7 select ARCH_REQUIRE_GPIOLIB @@ -65,6 +95,8 @@ endmenu endif +comment "Other Architectures" + config ARCH_BCM2835 bool "Broadcom BCM2835 family" if ARCH_MULTI_V6 select ARCH_REQUIRE_GPIOLIB diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 300ae4b79ae6..34d45ba2a4d1 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -10,6 +10,9 @@ # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. +# Cygnus +obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o + # BCM281XX obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c new file mode 100644 index 000000000000..30dc58be51b8 --- /dev/null +++ b/arch/arm/mach-bcm/bcm_cygnus.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +static const char const *bcm_cygnus_dt_compat[] = { + "brcm,cygnus", + NULL, +}; + +DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC") + .l2c_aux_val = 0, + .l2c_aux_mask = ~0, + .dt_compat = bcm_cygnus_dt_compat, +MACHINE_END -- cgit v1.2.3-59-g8ed1b From d318987ecd0b26318857172c9624b059a01c9451 Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Tue, 21 Oct 2014 18:51:33 -0700 Subject: ARM: mach-bcm: Consolidate currently supported IPROC SoCs Move ARCH_BCM_5301X subarch under ARCH_IPROC architecture. Additional IPROC chipsets that share a lot of commonality should be added under ARCH_IPROC as well. Signed-off-by: Scott Branden Signed-off-by: Florian Fainelli --- arch/arm/mach-bcm/Kconfig | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 73d95c2b355b..6e796961faf1 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -35,6 +35,22 @@ config ARCH_BCM_CYGNUS BCM11300, BCM11320, BCM11350, BCM11360, BCM58300, BCM58302, BCM58303, BCM58305. +config ARCH_BCM_5301X + bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 + select ARCH_BCM_IPROC + help + Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. + + This is a network SoC line mostly used in home routers and + wifi access points, it's internal name is Northstar. + This inclused the following SoC: BCM53010, BCM53011, BCM53012, + BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707, + BCM4708 and BCM4709. + + Do not confuse this with the BCM4760 which is a totally + different SoC or with the older BCM47XX and BCM53XX based + network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx + config ARCH_BCM_MOBILE bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7 select ARCH_REQUIRE_GPIOLIB @@ -110,27 +126,6 @@ config ARCH_BCM2835 This enables support for the Broadcom BCM2835 SoC. This SoC is used in the Raspberry Pi and Roku 2 devices. -config ARCH_BCM_5301X - bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 - select ARM_GIC - select CACHE_L2X0 - select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if SMP - select ARM_GLOBAL_TIMER - select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK - help - Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. - - This is a network SoC line mostly used in home routers and - wifi access points, it's internal name is Northstar. - This inclused the following SoC: BCM53010, BCM53011, BCM53012, - BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707, - BCM4708 and BCM4709. - - Do not confuse this with the BCM4760 which is a totally - different SoC or with the older BCM47XX and BCM53XX based - network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx - config ARCH_BCM_63XX bool "Broadcom BCM63xx DSL SoC" if ARCH_MULTI_V7 depends on MMU -- cgit v1.2.3-59-g8ed1b From 64e74aa788f996cd0e328a1c4223e9d438b78e9c Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Wed, 22 Oct 2014 09:52:13 -0700 Subject: ARM: mach-bcm: ARCH_BCM_MOBILE: remove one level of menu from Kconfig remove menu "Broadcom Mobile SoC Selection" This requires: - selecting ARCH_BCM_MOBILE based on SoC selections - fixup bcm_defconfig and multi_v7_defconfig to work with new menu levels. Signed-off-by: Scott Branden Signed-off-by: Florian Fainelli --- arch/arm/mach-bcm/Kconfig | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 6e796961faf1..cceb69fea9c4 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -51,8 +51,10 @@ config ARCH_BCM_5301X different SoC or with the older BCM47XX and BCM53XX based network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx +comment "KONA architected SoCs" + config ARCH_BCM_MOBILE - bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7 + bool select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_754322 select ARM_ERRATA_775420 @@ -61,16 +63,13 @@ config ARCH_BCM_MOBILE select TICK_ONESHOT select HAVE_ARM_ARCH_TIMER select PINCTRL + select ARCH_BCM_MOBILE_SMP if SMP help This enables support for systems based on Broadcom mobile SoCs. -if ARCH_BCM_MOBILE - -menu "Broadcom Mobile SoC Selection" - config ARCH_BCM_281XX bool "Broadcom BCM281XX SoC family" - default y + select ARCH_BCM_MOBILE select HAVE_SMP help Enable support for the BCM281XX family, which includes @@ -79,7 +78,7 @@ config ARCH_BCM_281XX config ARCH_BCM_21664 bool "Broadcom BCM21664 SoC family" - default y + select ARCH_BCM_MOBILE select HAVE_SMP help Enable support for the BCM21664 family, which includes @@ -87,19 +86,18 @@ config ARCH_BCM_21664 config ARCH_BCM_MOBILE_L2_CACHE bool "Broadcom mobile SoC level 2 cache support" - depends on (ARCH_BCM_281XX || ARCH_BCM_21664) + depends on ARCH_BCM_MOBILE default y select CACHE_L2X0 select ARCH_BCM_MOBILE_SMC config ARCH_BCM_MOBILE_SMC bool - depends on ARCH_BCM_281XX || ARCH_BCM_21664 + depends on ARCH_BCM_MOBILE config ARCH_BCM_MOBILE_SMP - bool "Broadcom mobile SoC SMP support" - depends on (ARCH_BCM_281XX || ARCH_BCM_21664) && SMP - default y + bool + depends on ARCH_BCM_MOBILE select HAVE_ARM_SCU select ARM_ERRATA_764369 help @@ -107,10 +105,6 @@ config ARCH_BCM_MOBILE_SMP Provided as an option so SMP support for SoCs of this type can be disabled for an SMP-enabled kernel. -endmenu - -endif - comment "Other Architectures" config ARCH_BCM2835 -- cgit v1.2.3-59-g8ed1b From b316a9f98a2e328d10f5ed3c341fa28880152af3 Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Wed, 22 Oct 2014 09:52:13 -0700 Subject: ARM: bcm_defconfig: remove one level of menu from Kconfig remove menu "Broadcom Mobile SoC Selection" This requires: - selecting ARCH_BCM_MOBILE based on SoC selections - fixup bcm_defconfig to work with new menu levels. - multi_v7_defconfig in another patch for merge purposes as per Olof Johansson's request Signed-off-by: Scott Branden Signed-off-by: Florian Fainelli --- arch/arm/configs/bcm_defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig index bc614f44b33d..83a87e48901c 100644 --- a/arch/arm/configs/bcm_defconfig +++ b/arch/arm/configs/bcm_defconfig @@ -25,7 +25,8 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_BCM=y -CONFIG_ARCH_BCM_MOBILE=y +CONFIG_ARCH_BCM_21664=y +CONFIG_ARCH_BCM_281XX=y CONFIG_ARM_THUMBEE=y CONFIG_SMP=y CONFIG_PREEMPT=y -- cgit v1.2.3-59-g8ed1b From e3d163329753b3b473f40c9be71561ed8eb98aea Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 11 Nov 2014 16:36:50 +0100 Subject: ARM: shmobile: always build rcar setup for armv7 In a combined ARMv6/v7 kernel, the setup-rcar-gen2.c cannot currently be compiled correctly because it uses the isb instruction that is not available on ARMv6. Adding the -march=armv7-a flag lets the compiler know that it is safe to build this file for ARMv7. Signed-off-by: Arnd Bergmann Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index e20f2786ec72..71e68ca56886 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -36,6 +36,7 @@ cpu-y := platsmp.o headsmp.o # Shared SoC family objects obj-$(CONFIG_ARCH_RCAR_GEN2) += setup-rcar-gen2.o platsmp-apmu.o $(cpu-y) +CFLAGS_setup-rcar-gen2.o += -march=armv7-a # SMP objects smp-y := $(cpu-y) -- cgit v1.2.3-59-g8ed1b From b437c52c296715eaad77c949fcfc074911a72427 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 17 Oct 2014 16:18:59 +0200 Subject: ARM: integrator: move restart to the device tree Using the augmented reset driver for the Versatile family, we can move the reset handling for the Integrator out of the machine. We add a "syscon" attribute to the core module, and access the syscon registers using this handle. We need to select SYSCON, POWER, POWER_RESET and POWER_RESET_VERSATILE in order for the restart functionality to always be available on all systems (it should not be optional). Signed-off-by: Linus Walleij --- arch/arm/boot/dts/integrator.dtsi | 2 +- arch/arm/mach-integrator/Kconfig | 4 ++++ arch/arm/mach-integrator/cm.h | 1 - arch/arm/mach-integrator/common.h | 1 - arch/arm/mach-integrator/core.c | 8 -------- arch/arm/mach-integrator/integrator_ap.c | 1 - arch/arm/mach-integrator/integrator_cp.c | 1 - 7 files changed, 5 insertions(+), 13 deletions(-) diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi index 88e3d477bf16..5546630c4fd2 100644 --- a/arch/arm/boot/dts/integrator.dtsi +++ b/arch/arm/boot/dts/integrator.dtsi @@ -6,7 +6,7 @@ / { core-module@10000000 { - compatible = "arm,core-module-integrator"; + compatible = "arm,core-module-integrator", "syscon"; reg = <0x10000000 0x200>; }; diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index aa7eb272e602..62e6db4bd533 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -8,8 +8,12 @@ config ARCH_INTEGRATOR select GENERIC_CLOCKEVENTS select HAVE_TCM select ICST + select MFD_SYSCON select MULTI_IRQ_HANDLER select PLAT_VERSATILE + select POWER_RESET + select POWER_RESET_VERSATILE + select POWER_SUPPLY select SPARSE_IRQ select USE_OF select VERSATILE_FPGA_IRQ diff --git a/arch/arm/mach-integrator/cm.h b/arch/arm/mach-integrator/cm.h index 4ecff7bff482..5b8ba8247f45 100644 --- a/arch/arm/mach-integrator/cm.h +++ b/arch/arm/mach-integrator/cm.h @@ -11,7 +11,6 @@ void cm_clear_irqs(void); #define CM_CTRL_LED (1 << 0) #define CM_CTRL_nMBDET (1 << 1) #define CM_CTRL_REMAP (1 << 2) -#define CM_CTRL_RESET (1 << 3) /* * Integrator/AP,PP2 specific diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h index ad0ac5547b2c..27a627aa1e8f 100644 --- a/arch/arm/mach-integrator/common.h +++ b/arch/arm/mach-integrator/common.h @@ -4,5 +4,4 @@ extern struct amba_pl010_data ap_uart_data; void integrator_init_early(void); int integrator_init(bool is_cp); void integrator_reserve(void); -void integrator_restart(enum reboot_mode, const char *); void integrator_init_sysfs(struct device *parent, u32 id); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index e3f3aca43efb..b06fd9f99a46 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -140,14 +140,6 @@ void __init integrator_reserve(void) memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); } -/* - * To reset, we hit the on-board reset register in the system FPGA - */ -void integrator_restart(enum reboot_mode mode, const char *cmd) -{ - cm_control(CM_CTRL_RESET, CM_CTRL_RESET); -} - static u32 integrator_id; static ssize_t intcp_get_manf(struct device *dev, diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 8a879b654fde..e6854c3f854e 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -365,6 +365,5 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") .init_early = ap_init_early, .init_irq = ap_init_irq_of, .init_machine = ap_init_of, - .restart = integrator_restart, .dt_compat = ap_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index cca02eb75eb5..fa8475b4872d 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -324,6 +324,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") .init_early = intcp_init_early, .init_irq = intcp_init_irq_of, .init_machine = intcp_init_of, - .restart = integrator_restart, .dt_compat = intcp_dt_board_compat, MACHINE_END -- cgit v1.2.3-59-g8ed1b From 7e61006436a2d01be6ef06f877867205acbdb177 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 15 Oct 2014 17:33:13 +0200 Subject: ARM: integrator: move debug LEDs to syscon LED driver The Integrator debug block is a simple set of registers, make it a syscon and register the four LEDs on the Integrator/AP baseboard as syscon LEDs. Signed-off-by: Linus Walleij --- arch/arm/boot/dts/integrator.dtsi | 36 +++++++++++++++++++++++++++++ arch/arm/mach-integrator/leds.c | 48 ++------------------------------------- 2 files changed, 38 insertions(+), 46 deletions(-) diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi index 5546630c4fd2..5d27087d5248 100644 --- a/arch/arm/boot/dts/integrator.dtsi +++ b/arch/arm/boot/dts/integrator.dtsi @@ -82,5 +82,41 @@ reg = <0x19000000 0x1000>; interrupts = <4>; }; + + syscon { + /* Debug registers mapped as syscon */ + compatible = "syscon"; + reg = <0x1a000000 0x10>; + + led@04.0 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x01>; + label = "integrator:green0"; + linux,default-trigger = "heartbeat"; + default-state = "on"; + }; + led@04.1 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x02>; + label = "integrator:yellow"; + default-state = "off"; + }; + led@04.2 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x04>; + label = "integrator:red"; + default-state = "off"; + }; + led@04.3 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x08>; + label = "integrator:green1"; + default-state = "off"; + }; + }; }; }; diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c index f1dcb57a59e2..56f243744b98 100644 --- a/arch/arm/mach-integrator/leds.c +++ b/arch/arm/mach-integrator/leds.c @@ -16,12 +16,8 @@ #if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) -#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE) -#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET) - struct integrator_led { struct led_classdev cdev; - u8 mask; }; /* @@ -32,40 +28,9 @@ static const struct { const char *name; const char *trigger; } integrator_leds[] = { - { "integrator:green0", "heartbeat", }, - { "integrator:yellow", }, - { "integrator:red", }, - { "integrator:green1", }, { "integrator:core_module", "cpu0", }, }; -static void integrator_led_set(struct led_classdev *cdev, - enum led_brightness b) -{ - struct integrator_led *led = container_of(cdev, - struct integrator_led, cdev); - u32 reg = __raw_readl(LEDREG); - - if (b != LED_OFF) - reg |= led->mask; - else - reg &= ~led->mask; - - while (__raw_readl(ALPHA_REG) & 1) - cpu_relax(); - - __raw_writel(reg, LEDREG); -} - -static enum led_brightness integrator_led_get(struct led_classdev *cdev) -{ - struct integrator_led *led = container_of(cdev, - struct integrator_led, cdev); - u32 reg = __raw_readl(LEDREG); - - return (reg & led->mask) ? LED_FULL : LED_OFF; -} - static void cm_led_set(struct led_classdev *cdev, enum led_brightness b) { @@ -93,19 +58,10 @@ static int __init integrator_leds_init(void) if (!led) break; - led->cdev.name = integrator_leds[i].name; - - if (i == 4) { /* Setting for LED in core module */ - led->cdev.brightness_set = cm_led_set; - led->cdev.brightness_get = cm_led_get; - } else { - led->cdev.brightness_set = integrator_led_set; - led->cdev.brightness_get = integrator_led_get; - } - + led->cdev.brightness_set = cm_led_set; + led->cdev.brightness_get = cm_led_get; led->cdev.default_trigger = integrator_leds[i].trigger; - led->mask = BIT(i); if (led_classdev_register(NULL, &led->cdev) < 0) { kfree(led); -- cgit v1.2.3-59-g8ed1b From bcc397de5af74ed31f35c0ca4cbd9faadb775c2e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 22 Oct 2014 10:05:44 +0200 Subject: ARM: integrator: move core module LED to device tree This gets rid of the custom LED driver in the Integrator directory altogether and switches us over to using the syscon LEDs for this. Signed-off-by: Linus Walleij --- arch/arm/boot/dts/integrator.dtsi | 10 +++++ arch/arm/mach-integrator/Makefile | 2 +- arch/arm/mach-integrator/leds.c | 80 --------------------------------------- 3 files changed, 11 insertions(+), 81 deletions(-) delete mode 100644 arch/arm/mach-integrator/leds.c diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi index 5d27087d5248..28e38f8c6b0f 100644 --- a/arch/arm/boot/dts/integrator.dtsi +++ b/arch/arm/boot/dts/integrator.dtsi @@ -8,6 +8,16 @@ core-module@10000000 { compatible = "arm,core-module-integrator", "syscon"; reg = <0x10000000 0x200>; + + /* Use core module LED to indicate CPU load */ + led@0c.0 { + compatible = "register-bit-led"; + offset = <0x0c>; + mask = <0x01>; + label = "integrator:core_module"; + linux,default-trigger = "cpu0"; + default-state = "on"; + }; }; ebi@12000000 { diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index ec759ded7b60..1ebe45356b09 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := core.o lm.o leds.o +obj-y := core.o lm.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c deleted file mode 100644 index 56f243744b98..000000000000 --- a/arch/arm/mach-integrator/leds.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard - * Based on Versatile and RealView machine LED code - * - * License terms: GNU General Public License (GPL) version 2 - * Author: Bryan Wu - */ -#include -#include -#include -#include -#include - -#include "hardware.h" -#include "cm.h" - -#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) - -struct integrator_led { - struct led_classdev cdev; -}; - -/* - * The triggers lines up below will only be used if the - * LED triggers are compiled in. - */ -static const struct { - const char *name; - const char *trigger; -} integrator_leds[] = { - { "integrator:core_module", "cpu0", }, -}; - -static void cm_led_set(struct led_classdev *cdev, - enum led_brightness b) -{ - if (b != LED_OFF) - cm_control(CM_CTRL_LED, CM_CTRL_LED); - else - cm_control(CM_CTRL_LED, 0); -} - -static enum led_brightness cm_led_get(struct led_classdev *cdev) -{ - u32 reg = cm_get(); - - return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF; -} - -static int __init integrator_leds_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) { - struct integrator_led *led; - - led = kzalloc(sizeof(*led), GFP_KERNEL); - if (!led) - break; - - led->cdev.name = integrator_leds[i].name; - led->cdev.brightness_set = cm_led_set; - led->cdev.brightness_get = cm_led_get; - led->cdev.default_trigger = integrator_leds[i].trigger; - - if (led_classdev_register(NULL, &led->cdev) < 0) { - kfree(led); - break; - } - } - - return 0; -} - -/* - * Since we may have triggers on any subsystem, defer registration - * until after subsystem_init. - */ -fs_initcall(integrator_leds_init); -#endif -- cgit v1.2.3-59-g8ed1b From f956a785a282f6b5a3e7d59937548f8b7c04d1ac Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 24 Oct 2014 12:51:20 +0200 Subject: soc: move SoC driver for the ARM Integrator This creates a new SoC bus driver for the ARM Integrator family core modules to register the SoC bus and provide sysfs info for the core module. We delete the corresponding code from the Integrator machine and select this driver to get a clean result. Signed-off-by: Linus Walleij --- arch/arm/mach-integrator/Kconfig | 1 + arch/arm/mach-integrator/common.h | 1 - arch/arm/mach-integrator/core.c | 95 ------------------- arch/arm/mach-integrator/integrator_ap.c | 27 ------ arch/arm/mach-integrator/integrator_cp.c | 27 ------ drivers/soc/versatile/Kconfig | 9 ++ drivers/soc/versatile/Makefile | 1 + drivers/soc/versatile/soc-integrator.c | 154 +++++++++++++++++++++++++++++++ 8 files changed, 165 insertions(+), 150 deletions(-) create mode 100644 drivers/soc/versatile/soc-integrator.c diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index 62e6db4bd533..02d083489a26 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -14,6 +14,7 @@ config ARCH_INTEGRATOR select POWER_RESET select POWER_RESET_VERSATILE select POWER_SUPPLY + select SOC_INTEGRATOR_CM select SPARSE_IRQ select USE_OF select VERSATILE_FPGA_IRQ diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h index 27a627aa1e8f..96c9dc56cabf 100644 --- a/arch/arm/mach-integrator/common.h +++ b/arch/arm/mach-integrator/common.h @@ -4,4 +4,3 @@ extern struct amba_pl010_data ap_uart_data; void integrator_init_early(void); int integrator_init(bool is_cp); void integrator_reserve(void); -void integrator_init_sysfs(struct device *parent, u32 id); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index b06fd9f99a46..948872a419c1 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -60,40 +60,6 @@ void cm_control(u32 mask, u32 set) raw_spin_unlock_irqrestore(&cm_lock, flags); } -static const char *integrator_arch_str(u32 id) -{ - switch ((id >> 16) & 0xff) { - case 0x00: - return "ASB little-endian"; - case 0x01: - return "AHB little-endian"; - case 0x03: - return "AHB-Lite system bus, bi-endian"; - case 0x04: - return "AHB"; - case 0x08: - return "AHB system bus, ASB processor bus"; - default: - return "Unknown"; - } -} - -static const char *integrator_fpga_str(u32 id) -{ - switch ((id >> 12) & 0xf) { - case 0x01: - return "XC4062"; - case 0x02: - return "XC4085"; - case 0x03: - return "XVC600"; - case 0x04: - return "EPM7256AE (Altera PLD)"; - default: - return "Unknown"; - } -} - void cm_clear_irqs(void) { /* disable core module IRQs */ @@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = { void cm_init(void) { struct device_node *cm = of_find_matching_node(NULL, cm_match); - u32 val; if (!cm) { pr_crit("no core module node found in device tree\n"); @@ -121,13 +86,6 @@ void cm_init(void) return; } cm_clear_irqs(); - val = readl(cm_base + INTEGRATOR_HDR_ID_OFFSET); - pr_info("Detected ARM core module:\n"); - pr_info(" Manufacturer: %02x\n", (val >> 24)); - pr_info(" Architecture: %s\n", integrator_arch_str(val)); - pr_info(" FPGA: %s\n", integrator_fpga_str(val)); - pr_info(" Build: %02x\n", (val >> 4) & 0xFF); - pr_info(" Rev: %c\n", ('A' + (val & 0x03))); } /* @@ -139,56 +97,3 @@ void __init integrator_reserve(void) { memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); } - -static u32 integrator_id; - -static ssize_t intcp_get_manf(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%02x\n", integrator_id >> 24); -} - -static struct device_attribute intcp_manf_attr = - __ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL); - -static ssize_t intcp_get_arch(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s\n", integrator_arch_str(integrator_id)); -} - -static struct device_attribute intcp_arch_attr = - __ATTR(architecture, S_IRUGO, intcp_get_arch, NULL); - -static ssize_t intcp_get_fpga(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s\n", integrator_fpga_str(integrator_id)); -} - -static struct device_attribute intcp_fpga_attr = - __ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL); - -static ssize_t intcp_get_build(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF); -} - -static struct device_attribute intcp_build_attr = - __ATTR(build, S_IRUGO, intcp_get_build, NULL); - - - -void integrator_init_sysfs(struct device *parent, u32 id) -{ - integrator_id = id; - device_create_file(parent, &intcp_manf_attr); - device_create_file(parent, &intcp_arch_attr); - device_create_file(parent, &intcp_fpga_attr); - device_create_file(parent, &intcp_build_attr); -} diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index e6854c3f854e..30003ba447a5 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -288,10 +287,6 @@ static void __init ap_init_of(void) unsigned long sc_dec; struct device_node *syscon; struct device_node *ebi; - struct device *parent; - struct soc_device *soc_dev; - struct soc_device_attribute *soc_dev_attr; - u32 ap_sc_id; int i; syscon = of_find_matching_node(NULL, ap_syscon_match); @@ -311,28 +306,6 @@ static void __init ap_init_of(void) of_platform_populate(NULL, of_default_bus_match_table, ap_auxdata_lookup, NULL); - ap_sc_id = readl(ap_syscon_base); - - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); - if (!soc_dev_attr) - return; - - soc_dev_attr->soc_id = "XVC"; - soc_dev_attr->machine = "Integrator/AP"; - soc_dev_attr->family = "Integrator"; - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", - 'A' + (ap_sc_id & 0x0f)); - - soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - kfree(soc_dev_attr->revision); - kfree(soc_dev_attr); - return; - } - - parent = soc_device_to_device(soc_dev); - integrator_init_sysfs(parent, ap_sc_id); - sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET); for (i = 0; i < 4; i++) { struct lm_device *lmdev; diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index fa8475b4872d..b5fb71a36ee6 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -274,10 +273,6 @@ static const struct of_device_id intcp_syscon_match[] = { static void __init intcp_init_of(void) { struct device_node *cpcon; - struct device *parent; - struct soc_device *soc_dev; - struct soc_device_attribute *soc_dev_attr; - u32 intcp_sc_id; cpcon = of_find_matching_node(NULL, intcp_syscon_match); if (!cpcon) @@ -289,28 +284,6 @@ static void __init intcp_init_of(void) of_platform_populate(NULL, of_default_bus_match_table, intcp_auxdata_lookup, NULL); - - intcp_sc_id = readl(intcp_con_base); - - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); - if (!soc_dev_attr) - return; - - soc_dev_attr->soc_id = "XCV"; - soc_dev_attr->machine = "Integrator/CP"; - soc_dev_attr->family = "Integrator"; - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", - 'A' + (intcp_sc_id & 0x0f)); - - soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - kfree(soc_dev_attr->revision); - kfree(soc_dev_attr); - return; - } - - parent = soc_device_to_device(soc_dev); - integrator_init_sysfs(parent, intcp_sc_id); } static const char * intcp_dt_board_compat[] = { diff --git a/drivers/soc/versatile/Kconfig b/drivers/soc/versatile/Kconfig index bf5ee9c85330..a928a7fc6be4 100644 --- a/drivers/soc/versatile/Kconfig +++ b/drivers/soc/versatile/Kconfig @@ -1,6 +1,15 @@ # # ARM Versatile SoC drivers # +config SOC_INTEGRATOR_CM + bool "SoC bus device for the ARM Integrator platform core modules" + depends on ARCH_INTEGRATOR + select SOC_BUS + help + Include support for the SoC bus on the ARM Integrator platform + core modules providing some sysfs information about the ASIC + variant. + config SOC_REALVIEW bool "SoC bus device for the ARM RealView platforms" depends on ARCH_REALVIEW diff --git a/drivers/soc/versatile/Makefile b/drivers/soc/versatile/Makefile index ad547435648e..cf612fe3a659 100644 --- a/drivers/soc/versatile/Makefile +++ b/drivers/soc/versatile/Makefile @@ -1 +1,2 @@ +obj-$(CONFIG_SOC_INTEGRATOR_CM) += soc-integrator.o obj-$(CONFIG_SOC_REALVIEW) += soc-realview.o diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c new file mode 100644 index 000000000000..ccaa53739ab4 --- /dev/null +++ b/drivers/soc/versatile/soc-integrator.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Linus Walleij + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define INTEGRATOR_HDR_ID_OFFSET 0x00 + +static u32 integrator_coreid; + +static const struct of_device_id integrator_cm_match[] = { + { .compatible = "arm,core-module-integrator", }, +}; + +static const char *integrator_arch_str(u32 id) +{ + switch ((id >> 16) & 0xff) { + case 0x00: + return "ASB little-endian"; + case 0x01: + return "AHB little-endian"; + case 0x03: + return "AHB-Lite system bus, bi-endian"; + case 0x04: + return "AHB"; + case 0x08: + return "AHB system bus, ASB processor bus"; + default: + return "Unknown"; + } +} + +static const char *integrator_fpga_str(u32 id) +{ + switch ((id >> 12) & 0xf) { + case 0x01: + return "XC4062"; + case 0x02: + return "XC4085"; + case 0x03: + return "XVC600"; + case 0x04: + return "EPM7256AE (Altera PLD)"; + default: + return "Unknown"; + } +} + +static ssize_t integrator_get_manf(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%02x\n", integrator_coreid >> 24); +} + +static struct device_attribute integrator_manf_attr = + __ATTR(manufacturer, S_IRUGO, integrator_get_manf, NULL); + +static ssize_t integrator_get_arch(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", integrator_arch_str(integrator_coreid)); +} + +static struct device_attribute integrator_arch_attr = + __ATTR(arch, S_IRUGO, integrator_get_arch, NULL); + +static ssize_t integrator_get_fpga(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", integrator_fpga_str(integrator_coreid)); +} + +static struct device_attribute integrator_fpga_attr = + __ATTR(fpga, S_IRUGO, integrator_get_fpga, NULL); + +static ssize_t integrator_get_build(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%02x\n", (integrator_coreid >> 4) & 0xFF); +} + +static struct device_attribute integrator_build_attr = + __ATTR(build, S_IRUGO, integrator_get_build, NULL); + +static int __init integrator_soc_init(void) +{ + static struct regmap *syscon_regmap; + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + struct device_node *np; + struct device *dev; + u32 val; + int ret; + + np = of_find_matching_node(NULL, integrator_cm_match); + if (!np) + return -ENODEV; + + syscon_regmap = syscon_node_to_regmap(np); + if (IS_ERR(syscon_regmap)) + return PTR_ERR(syscon_regmap); + + ret = regmap_read(syscon_regmap, INTEGRATOR_HDR_ID_OFFSET, + &val); + if (ret) + return -ENODEV; + integrator_coreid = val; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->soc_id = "Integrator"; + soc_dev_attr->machine = "Integrator"; + soc_dev_attr->family = "Versatile"; + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr); + return -ENODEV; + } + dev = soc_device_to_device(soc_dev); + + device_create_file(dev, &integrator_manf_attr); + device_create_file(dev, &integrator_arch_attr); + device_create_file(dev, &integrator_fpga_attr); + device_create_file(dev, &integrator_build_attr); + + dev_info(dev, "Detected ARM core module:\n"); + dev_info(dev, " Manufacturer: %02x\n", (val >> 24)); + dev_info(dev, " Architecture: %s\n", integrator_arch_str(val)); + dev_info(dev, " FPGA: %s\n", integrator_fpga_str(val)); + dev_info(dev, " Build: %02x\n", (val >> 4) & 0xFF); + dev_info(dev, " Rev: %c\n", ('A' + (val & 0x03))); + + return 0; +} +device_initcall(integrator_soc_init); -- cgit v1.2.3-59-g8ed1b From f0d2f68a6387867c4748bc94c9b0165a49701204 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 3 Oct 2014 16:57:10 +0300 Subject: ARM: OMAP3: clock: use clk_features flags for omap3 DPLL4 checks DPLL4 can't be reprogrammed on OMAP3430 ES1.0 due to hardware limitation. Currently, the code does runtime omap_rev() check to see the chip it is being executed on, instead, change this to use clk_features flags. This avoids need for runtime omap_rev() checks. Signed-off-by: Tero Kristo Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock.c | 4 ++++ arch/arm/mach-omap2/clock.h | 1 + arch/arm/mach-omap2/clock3xxx.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 500530d1364a..c2b239857cc4 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -771,4 +771,8 @@ void __init ti_clk_init_features(void) ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL; else if (cpu_is_omap34xx()) ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL; + + /* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */ + if (omap_rev() == OMAP3430_REV_ES1_0) + ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM; } diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 4592a2762592..641337c6cde9 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -234,6 +234,7 @@ struct ti_clk_features { }; #define TI_CLK_DPLL_HAS_FREQSEL (1 << 0) +#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1) extern struct ti_clk_features ti_clk_features; diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c index 0b02b4161d71..9a2560181909 100644 --- a/arch/arm/mach-omap2/clock3xxx.c +++ b/arch/arm/mach-omap2/clock3xxx.c @@ -46,7 +46,7 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, * on 3430ES1 prevents us from changing DPLL multipliers or dividers * on DPLL4. */ - if (omap_rev() == OMAP3430_REV_ES1_0) { + if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From d539efa37f1f789339699c941e72e320d12d5f28 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 3 Oct 2014 16:57:11 +0300 Subject: ARM: OMAP3: clock: add new rate changing logic support for noncore DPLLs Currently, DPLL code hides the re-parenting within its internals, which is wrong. This needs to be exposed to the common clock code via determine_rate and set_rate_and_parent APIs. This patch adds support for these, which will be taken into use in the following patches. Signed-off-by: Tero Kristo Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/dpll3xxx.c | 147 +++++++++++++++++++++++++++++++++++++++++ include/linux/clk/ti.h | 9 +++ 2 files changed, 156 insertions(+) diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index ac3d789ac3cd..cfe7c30235d1 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -546,6 +546,153 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } +/** + * omap3_noncore_dpll_determine_rate - determine rate for a DPLL + * @hw: pointer to the clock to determine rate for + * @rate: target rate for the DPLL + * @best_parent_rate: pointer for returning best parent rate + * @best_parent_clk: pointer for returning best parent clock + * + * Determines which DPLL mode to use for reaching a desired target rate. + * Checks whether the DPLL shall be in bypass or locked mode, and if + * locked, calculates the M,N values for the DPLL via round-rate. + * Returns a positive clock rate with success, negative error value + * in failure. + */ +long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + if (__clk_get_rate(dd->clk_bypass) == rate && + (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { + *best_parent_clk = dd->clk_bypass; + } else { + rate = omap2_dpll_round_rate(hw, rate, best_parent_rate); + *best_parent_clk = dd->clk_ref; + } + + *best_parent_rate = rate; + + return rate; +} + +/** + * omap3_noncore_dpll_set_parent - set parent for a DPLL clock + * @hw: pointer to the clock to set parent for + * @index: parent index to select + * + * Sets parent for a DPLL clock. This sets the DPLL into bypass or + * locked mode. Returns 0 with success, negative error value otherwise. + */ +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + int ret; + + if (!hw) + return -EINVAL; + + if (index) + ret = _omap3_noncore_dpll_bypass(clk); + else + ret = _omap3_noncore_dpll_lock(clk); + + return ret; +} + +/** + * omap3_noncore_dpll_set_rate_new - set rate for a DPLL clock + * @hw: pointer to the clock to set parent for + * @rate: target rate for the clock + * @parent_rate: rate of the parent clock + * + * Sets rate for a DPLL clock. First checks if the clock parent is + * reference clock (in bypass mode, the rate of the clock can't be + * changed) and proceeds with the rate change operation. Returns 0 + * with success, negative error value otherwise. + */ +static int omap3_noncore_dpll_set_rate_new(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + u16 freqsel = 0; + int ret; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + if (__clk_get_parent(hw->clk) != dd->clk_ref) + return -EINVAL; + + if (dd->last_rounded_rate == 0) + return -EINVAL; + + /* Freqsel is available only on OMAP343X devices */ + if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { + freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); + WARN_ON(!freqsel); + } + + pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__, + __clk_get_name(hw->clk), rate); + + ret = omap3_noncore_dpll_program(clk, freqsel); + + return ret; +} + +/** + * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock + * @hw: pointer to the clock to set rate and parent for + * @rate: target rate for the DPLL + * @parent_rate: clock rate of the DPLL parent + * @index: new parent index for the DPLL, 0 - reference, 1 - bypass + * + * Sets rate and parent for a DPLL clock. If new parent is the bypass + * clock, only selects the parent. Otherwise proceeds with a rate + * change, as this will effectively also change the parent as the + * DPLL is put into locked mode. Returns 0 with success, negative error + * value otherwise. + */ +int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index) +{ + int ret; + + if (!hw || !rate) + return -EINVAL; + + /* + * clk-ref at index[0], in which case we only need to set rate, + * the parent will be changed automatically with the lock sequence. + * With clk-bypass case we only need to change parent. + */ + if (index) + ret = omap3_noncore_dpll_set_parent(hw, index); + else + ret = omap3_noncore_dpll_set_rate_new(hw, rate, parent_rate); + + return ret; +} + /* DPLL autoidle read/set code */ /** diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index f75acbf70e96..6f9fb77ffdd5 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -254,8 +254,17 @@ extern const struct clk_ops ti_clk_mux_ops; void omap2_init_clk_hw_omap_clocks(struct clk *clk); int omap3_noncore_dpll_enable(struct clk_hw *hw); void omap3_noncore_dpll_disable(struct clk_hw *hw); +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index); int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate); +int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index); +long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk); unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, -- cgit v1.2.3-59-g8ed1b From 83501ff0a5032dfbd63ab1ca9d9d25b97ec49fb9 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 3 Oct 2014 16:57:12 +0300 Subject: ARM: OMAP4: clock: add support for determine_rate for omap4 regm4xen DPLL Similarly to OMAP3 noncore DPLL, the implementation of this DPLL clock type is wrong. This patch adds basic functionality for determine_rate for this clock type which will be taken into use in the patches following later. Signed-off-by: Tero Kristo Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/dpll44xx.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/linux/clk/ti.h | 4 ++++ 2 files changed, 45 insertions(+) diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index 4613f1e86988..535822fcf4bb 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -207,3 +207,44 @@ out: return dd->last_rounded_rate; } + +/** + * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL + * @hw: pointer to the clock to determine rate for + * @rate: target rate for the DPLL + * @best_parent_rate: pointer for returning best parent rate + * @best_parent_clk: pointer for returning best parent clock + * + * Determines which DPLL mode to use for reaching a desired rate. + * Checks whether the DPLL shall be in bypass or locked mode, and if + * locked, calculates the M,N values for the DPLL via round-rate. + * Returns a positive clock rate with success, negative error value + * in failure. + */ +long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + if (__clk_get_rate(dd->clk_bypass) == rate && + (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { + *best_parent_clk = dd->clk_bypass; + } else { + rate = omap4_dpll_regm4xen_round_rate(hw, rate, + best_parent_rate); + *best_parent_clk = dd->clk_ref; + } + + *best_parent_rate = rate; + + return rate; +} diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 6f9fb77ffdd5..abc702a73aca 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -270,6 +270,10 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long *parent_rate); +long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk); u8 omap2_init_dpll_parent(struct clk_hw *hw); unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, -- cgit v1.2.3-59-g8ed1b From e3ab6013ab06d3a861ed00c1f8d32aa4e6b66ddd Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 3 Oct 2014 16:57:13 +0300 Subject: ARM: OMAP3: clock: add support for dpll4_set_rate_and_parent Expand the support of omap4 per-dpll to provide set_rate_and_parent. This is required for proper behavior of clk_change_rate with determine_rate support. Signed-off-by: Tero Kristo Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock3xxx.c | 36 ++++++++++++++++++++++++++++++++++++ include/linux/clk/ti.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c index 9a2560181909..a9e86db5daf9 100644 --- a/arch/arm/mach-omap2/clock3xxx.c +++ b/arch/arm/mach-omap2/clock3xxx.c @@ -38,6 +38,18 @@ /* needed by omap3_core_dpll_m2_set_rate() */ struct clk *sdrc_ick_p, *arm_fck_p; + +/** + * omap3_dpll4_set_rate - set rate for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * + * Check if the current SoC supports the per-dpll reprogram operation + * or not, and then do the rate change if supported. Returns -EINVAL + * if not supported, 0 for success, and potential error codes from the + * clock rate change. + */ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -54,6 +66,30 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, return omap3_noncore_dpll_set_rate(hw, rate, parent_rate); } +/** + * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * @index: parent index, 0 - reference clock, 1 - bypass clock + * + * Check if the current SoC support the per-dpll reprogram operation + * or not, and then do the rate + parent change if supported. Returns + * -EINVAL if not supported, 0 for success, and potential error codes + * from the clock rate change. + */ +int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index) +{ + if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { + pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); + return -EINVAL; + } + + return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate, + index); +} + void __init omap3_clk_lock_dpll5(void) { struct clk *dpll5_clk; diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index abc702a73aca..74e5341463c9 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -291,6 +291,8 @@ int omap2_clk_disable_autoidle_all(void); void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, unsigned long parent_rate); +int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index); int omap2_dflt_clk_enable(struct clk_hw *hw); void omap2_dflt_clk_disable(struct clk_hw *hw); int omap2_dflt_clk_is_enabled(struct clk_hw *hw); -- cgit v1.2.3-59-g8ed1b From 2e1a7b014f9c3d61fbf12b429f0479242264dbec Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 3 Oct 2014 16:57:14 +0300 Subject: ARM: OMAP3+: DPLL: use determine_rate() and set_rate_and_parent() Currently, DPLLs are hiding the gory details of switching parent within set_rate, which confuses the common clock code and is wrong. Fixed by applying the new determine_rate() and set_rate_and_parent() functionality to any clock-ops previously using the broken approach. This patch also removes the broken legacy code. Signed-off-by: Tero Kristo Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/cclock3xxx_data.c | 6 +++ arch/arm/mach-omap2/dpll3xxx.c | 96 ++--------------------------------- drivers/clk/ti/dpll.c | 15 ++++++ 3 files changed, 25 insertions(+), 92 deletions(-) diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c index eb8c75ec3b1a..5c5ebb4db5f7 100644 --- a/arch/arm/mach-omap2/cclock3xxx_data.c +++ b/arch/arm/mach-omap2/cclock3xxx_data.c @@ -257,6 +257,9 @@ static const struct clk_ops dpll1_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; @@ -367,6 +370,9 @@ static const struct clk_ops dpll4_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_dpll4_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index cfe7c30235d1..20e120d071dd 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -459,93 +459,6 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw) /* Non-CORE DPLL rate set code */ -/** - * omap3_noncore_dpll_set_rate - set non-core DPLL rate - * @clk: struct clk * of DPLL to set - * @rate: rounded target rate - * - * Set the DPLL CLKOUT to the target rate. If the DPLL can enter - * low-power bypass, and the target rate is the bypass source clock - * rate, then configure the DPLL for bypass. Otherwise, round the - * target rate if it hasn't been done already, then program and lock - * the DPLL. Returns -EINVAL upon error, or 0 upon success. - */ -int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - struct clk *new_parent = NULL; - unsigned long rrate; - u16 freqsel = 0; - struct dpll_data *dd; - int ret; - - if (!hw || !rate) - return -EINVAL; - - dd = clk->dpll_data; - if (!dd) - return -EINVAL; - - if (__clk_get_rate(dd->clk_bypass) == rate && - (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - pr_debug("%s: %s: set rate: entering bypass.\n", - __func__, __clk_get_name(hw->clk)); - - __clk_prepare(dd->clk_bypass); - clk_enable(dd->clk_bypass); - ret = _omap3_noncore_dpll_bypass(clk); - if (!ret) - new_parent = dd->clk_bypass; - clk_disable(dd->clk_bypass); - __clk_unprepare(dd->clk_bypass); - } else { - __clk_prepare(dd->clk_ref); - clk_enable(dd->clk_ref); - - /* XXX this check is probably pointless in the CCF context */ - if (dd->last_rounded_rate != rate) { - rrate = __clk_round_rate(hw->clk, rate); - if (rrate != rate) { - pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n", - __func__, __clk_get_name(hw->clk), - rrate, rate); - rate = rrate; - } - } - - if (dd->last_rounded_rate == 0) - return -EINVAL; - - /* Freqsel is available only on OMAP343X devices */ - if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { - freqsel = _omap3_dpll_compute_freqsel(clk, - dd->last_rounded_n); - WARN_ON(!freqsel); - } - - pr_debug("%s: %s: set rate: locking rate to %lu.\n", - __func__, __clk_get_name(hw->clk), rate); - - ret = omap3_noncore_dpll_program(clk, freqsel); - if (!ret) - new_parent = dd->clk_ref; - clk_disable(dd->clk_ref); - __clk_unprepare(dd->clk_ref); - } - /* - * FIXME - this is all wrong. common code handles reparenting and - * migrating prepare/enable counts. dplls should be a multiplexer - * clock and this should be a set_parent operation so that all of that - * stuff is inherited for free - */ - - if (!ret && clk_get_parent(hw->clk) != new_parent) - __clk_reparent(hw->clk, new_parent); - - return 0; -} - /** * omap3_noncore_dpll_determine_rate - determine rate for a DPLL * @hw: pointer to the clock to determine rate for @@ -611,7 +524,7 @@ int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index) } /** - * omap3_noncore_dpll_set_rate_new - set rate for a DPLL clock + * omap3_noncore_dpll_set_rate - set rate for a DPLL clock * @hw: pointer to the clock to set parent for * @rate: target rate for the clock * @parent_rate: rate of the parent clock @@ -621,9 +534,8 @@ int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index) * changed) and proceeds with the rate change operation. Returns 0 * with success, negative error value otherwise. */ -static int omap3_noncore_dpll_set_rate_new(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate) +int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct dpll_data *dd; @@ -688,7 +600,7 @@ int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, if (index) ret = omap3_noncore_dpll_set_parent(hw, index); else - ret = omap3_noncore_dpll_set_rate_new(hw, rate, parent_rate); + ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate); return ret; } diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 79791e1bf282..85ac0dd501de 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -33,6 +33,9 @@ static const struct clk_ops dpll_m4xen_ck_ops = { .recalc_rate = &omap4_dpll_regm4xen_recalc, .round_rate = &omap4_dpll_regm4xen_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap4_dpll_regm4xen_determine_rate, .get_parent = &omap2_init_dpll_parent, }; #else @@ -53,6 +56,9 @@ static const struct clk_ops dpll_ck_ops = { .recalc_rate = &omap3_dpll_recalc, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .get_parent = &omap2_init_dpll_parent, }; @@ -61,6 +67,9 @@ static const struct clk_ops dpll_no_gate_ck_ops = { .get_parent = &omap2_init_dpll_parent, .round_rate = &omap2_dpll_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, }; #else static const struct clk_ops dpll_core_ck_ops = {}; @@ -97,6 +106,9 @@ static const struct clk_ops omap3_dpll_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; @@ -106,6 +118,9 @@ static const struct clk_ops omap3_dpll_per_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_dpll4_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; #endif -- cgit v1.2.3-59-g8ed1b From 79005fbd3e1d671d08c45c9140ee9826efdc367c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 13 Nov 2014 09:36:55 -0700 Subject: ARM: OMAP2+: hwmod: drop unnecessary list initialization ml->node and sl->node are currently initialized by means of INIT_LIST_HEAD(). That initialiation is followed by a list_add() call. Looking at what both these functions do we will have: ml->node.next = &ml->node; ml->node.prev = &ml->node; oi->master->master_ports.next.prev = &ml->node; ml->node.next = &oi->master->master_ports.next; ml->node.prev = &oi->master->master_ports; oi->master->master_ports.next = &ml->node; from this, it's clear that both INIT_LIST_HEAD() calls are unnecessary and can be safely removed. Signed-off-by: Felipe Balbi Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 716247ed9e0c..acae6d5d1151 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2832,12 +2832,10 @@ static int __init _add_link(struct omap_hwmod_ocp_if *oi) _alloc_links(&ml, &sl); ml->ocp_if = oi; - INIT_LIST_HEAD(&ml->node); list_add(&ml->node, &oi->master->master_ports); oi->master->masters_cnt++; sl->ocp_if = oi; - INIT_LIST_HEAD(&sl->node); list_add(&sl->node, &oi->slave->slave_ports); oi->slave->slaves_cnt++; -- cgit v1.2.3-59-g8ed1b From 65ec48c0c784bc8f4a0794ab2a7f3674affeb747 Mon Sep 17 00:00:00 2001 From: "Joe.C" Date: Tue, 4 Nov 2014 15:30:54 +0800 Subject: ARM: mediatek: Add earlyprintk support for mt8127 & mt8135 Enable low-level debug for Mediatek mt8127 & mt8135 SoC. Signed-off-by: Joe.C Signed-off-by: Matthias Brugger --- arch/arm/Kconfig.debug | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 03dc4c1a8736..7d78ed749525 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -866,6 +866,22 @@ choice Say Y here if you want kernel low-level debugging support for Mediatek mt6589 based platforms on UART0. + config DEBUG_MT8127_UART0 + bool "Mediatek mt8127 UART0" + depends on ARCH_MEDIATEK + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + for Mediatek mt8127 based platforms on UART0. + + config DEBUG_MT8135_UART3 + bool "Mediatek mt8135 UART3" + depends on ARCH_MEDIATEK + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + for Mediatek mt8135 based platforms on UART3. + config DEBUG_VEXPRESS_UART0_DETECT bool "Autodetect UART0 on Versatile Express Cortex-A core tiles" depends on ARCH_VEXPRESS && CPU_CP15_MMU @@ -1113,7 +1129,9 @@ config DEBUG_UART_PHYS default 0x10126000 if DEBUG_RK3X_UART1 default 0x101f1000 if ARCH_VERSATILE default 0x101fb000 if DEBUG_NOMADIK_UART + default 0x11002000 if DEBUG_MT8127_UART0 default 0x11006000 if DEBUG_MT6589_UART0 + default 0x11009000 if DEBUG_MT8135_UART3 default 0x16000000 if ARCH_INTEGRATOR default 0x18000300 if DEBUG_BCM_5301X default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1 @@ -1181,7 +1199,9 @@ config DEBUG_UART_VIRT default 0xf01fb000 if DEBUG_NOMADIK_UART default 0xf0201000 if DEBUG_BCM2835 default 0xf1000300 if DEBUG_BCM_5301X + default 0xf1002000 if DEBUG_MT8127_UART0 default 0xf1006000 if DEBUG_MT6589_UART0 + default 0xf1009000 if DEBUG_MT8135_UART3 default 0xf11f1000 if ARCH_VERSATILE default 0xf1600000 if ARCH_INTEGRATOR default 0xf1c28000 if DEBUG_SUNXI_UART0 -- cgit v1.2.3-59-g8ed1b From af49f5a2a1902c40d734a9c43f67d2fb434fcb91 Mon Sep 17 00:00:00 2001 From: "Joe.C" Date: Tue, 4 Nov 2014 15:30:55 +0800 Subject: ARM: mediatek: Fix description for mediatek SoCs We support more MediaTek SoCs now, update the description. Signed-off-by: Joe.C Signed-off-by: Matthias Brugger --- arch/arm/mach-mediatek/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig index 2c043a210db0..f73f588f649c 100644 --- a/arch/arm/mach-mediatek/Kconfig +++ b/arch/arm/mach-mediatek/Kconfig @@ -1,6 +1,6 @@ config ARCH_MEDIATEK - bool "Mediatek MT6589 SoC" if ARCH_MULTI_V7 + bool "Mediatek MT65xx & MT81xx SoC" if ARCH_MULTI_V7 select ARM_GIC select MTK_TIMER help - Support for Mediatek Cortex-A7 Quad-Core-SoC MT6589. + Support for Mediatek MT65xx & MT81xx SoCs -- cgit v1.2.3-59-g8ed1b From 02c24f7dc2449203a9309c6ecdb4feed2d884f43 Mon Sep 17 00:00:00 2001 From: Emilio López Date: Sat, 15 Nov 2014 20:53:38 -0300 Subject: ARM: sunxi: make sun6i SMP ops static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sun6i SMP ops are currently not marked as static, as reported by sparse. Let's mark it as such. Signed-off-by: Emilio López Signed-off-by: Maxime Ripard --- arch/arm/mach-sunxi/platsmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/platsmp.c b/arch/arm/mach-sunxi/platsmp.c index c53077bb8c3f..e44d028555a4 100644 --- a/arch/arm/mach-sunxi/platsmp.c +++ b/arch/arm/mach-sunxi/platsmp.c @@ -116,7 +116,7 @@ static int sun6i_smp_boot_secondary(unsigned int cpu, return 0; } -struct smp_operations sun6i_smp_ops __initdata = { +static struct smp_operations sun6i_smp_ops __initdata = { .smp_prepare_cpus = sun6i_smp_prepare_cpus, .smp_boot_secondary = sun6i_smp_boot_secondary, }; -- cgit v1.2.3-59-g8ed1b From 7a2071c58f36450fbf44a27d2e5d371c18534a25 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Nov 2014 16:49:47 +0100 Subject: ARM: shmobile: Add early debugging support using SCIF(A) Add serial port debug macros for the SCIF(A) serial ports. This includes all supported shmobile SoCs, except for EMEV2. The configuration logic (both Kconfig and #ifdef) is more complicated than one would expect, for several reasons: 1. Not all SoCs have the same serial devices, and they're not always at the same addresses. 2. There are two different types: SCIF and SCIFA. Fortunately they can easily be distinguished by physical address. 3. Not all boards use the same serial port for the console. The defaults correspond to the boards that are supported in mainline. If you want to use a different serial port, just change the value of CONFIG_DEBUG_UART_PHYS, and the rest will auto-adapt. 4. debug_ll_io_init() maps the SCIF(A) registers to a fixed virtual address. 0xfdxxxxxx was chosen, as it should lie below VMALLOC_END = 0xff000000, and must not conflict with the 2 MiB reserved region at PCI_IO_VIRT_BASE = 0xfee00000. - On SoCs not using the legacy machine_desc.map_io(), debug_ll_io_init() is called by the ARM core code. - On SoCs using the legacy machine_desc.map_io(), debug_ll_io_init() must be called explicitly. Calls are added for r8a7740, r8a7779, sh7372, and sh73a0. This was derived from the r8a7790 version by Laurent Pinchart. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Acked-by: Arnd Bergmann Tested-by: Simon Horman Signed-off-by: Simon Horman --- MAINTAINERS | 1 + arch/arm/Kconfig.debug | 80 +++++++++++++++++++++++++++++++++- arch/arm/include/debug/renesas-scif.S | 52 ++++++++++++++++++++++ arch/arm/mach-shmobile/setup-r8a7740.c | 1 + arch/arm/mach-shmobile/setup-r8a7779.c | 1 + arch/arm/mach-shmobile/setup-sh7372.c | 1 + arch/arm/mach-shmobile/setup-sh73a0.c | 1 + 7 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/debug/renesas-scif.S diff --git a/MAINTAINERS b/MAINTAINERS index a20df9bf8ab0..7d843099e9c6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1387,6 +1387,7 @@ F: arch/arm/configs/lager_defconfig F: arch/arm/configs/mackerel_defconfig F: arch/arm/configs/marzen_defconfig F: arch/arm/configs/shmobile_defconfig +F: arch/arm/include/debug/renesas-scif.S F: arch/arm/mach-shmobile/ F: drivers/sh/ diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 03dc4c1a8736..6ac3758f85d8 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -653,6 +653,64 @@ choice Say Y here if you want kernel low-level debugging support on Rockchip RK32xx based platforms. + config DEBUG_R7S72100_SCIF2 + bool "Kernel low-level debugging messages via SCIF2 on R7S72100" + depends on ARCH_R7S72100 + help + Say Y here if you want kernel low-level debugging support + via SCIF2 on Renesas RZ/A1H (R7S72100). + + config DEBUG_RCAR_GEN1_SCIF0 + bool "Kernel low-level debugging messages via SCIF0 on R8A7778" + depends on ARCH_R8A7778 + help + Say Y here if you want kernel low-level debugging support + via SCIF0 on Renesas R-Car M1A (R8A7778). + + config DEBUG_RCAR_GEN1_SCIF2 + bool "Kernel low-level debugging messages via SCIF2 on R8A7779" + depends on ARCH_R8A7779 + help + Say Y here if you want kernel low-level debugging support + via SCIF2 on Renesas R-Car H1 (R8A7779). + + config DEBUG_RCAR_GEN2_SCIF0 + bool "Kernel low-level debugging messages via SCIF0 on R8A7790/R8A7791/R8A7793)" + depends on ARCH_R8A7790 || ARCH_R8A7791 || ARCH_R8A7793 + help + Say Y here if you want kernel low-level debugging support + via SCIF0 on Renesas R-Car H2 (R8A7790), M2-W (R8A7791), or + M2-N (R8A7793). + + config DEBUG_RCAR_GEN2_SCIF2 + bool "Kernel low-level debugging messages via SCIF2 on R8A7794" + depends on ARCH_R8A7794 + help + Say Y here if you want kernel low-level debugging support + via SCIF2 on Renesas R-Car E2 (R8A7794). + + config DEBUG_RMOBILE_SCIFA0 + bool "Kernel low-level debugging messages via SCIFA0 on R8A73A4/SH7372" + depends on ARCH_R8A73A4 || ARCH_SH7372 + help + Say Y here if you want kernel low-level debugging support + via SCIFA0 on Renesas R-Mobile APE6 (R8A73A4) or SH-Mobile + AP4 (SH7372). + + config DEBUG_RMOBILE_SCIFA1 + bool "Kernel low-level debugging messages via SCIFA1 on R8A7740" + depends on ARCH_R8A7740 + help + Say Y here if you want kernel low-level debugging support + via SCIFA1 on Renesas R-Mobile A1 (R8A7740). + + config DEBUG_RMOBILE_SCIFA4 + bool "Kernel low-level debugging messages via SCIFA4 on SH73A0" + depends on ARCH_SH73A0 + help + Say Y here if you want kernel low-level debugging support + via SCIFA4 on Renesas SH-Mobile AG5 (SH73A0). + config DEBUG_S3C_UART0 depends on PLAT_SAMSUNG select DEBUG_EXYNOS_UART if ARCH_EXYNOS @@ -1061,6 +1119,14 @@ config DEBUG_LL_INCLUDE DEBUG_IMX6SX_UART default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART + default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2 + default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0 + default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF2 + default "debug/renesas-scif.S" if DEBUG_RCAR_GEN2_SCIF0 + default "debug/renesas-scif.S" if DEBUG_RCAR_GEN2_SCIF2 + default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA0 + default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA1 + default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA4 default "debug/s3c24xx.S" if DEBUG_S3C24XX_UART default "debug/s5pv210.S" if DEBUG_S5PV210_UART default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1 @@ -1152,6 +1218,12 @@ config DEBUG_UART_PHYS default 0xd4018000 if DEBUG_MMP_UART3 default 0xe0000000 if ARCH_SPEAR13XX default 0xe4007000 if DEBUG_HIP04_UART + default 0xe6c40000 if DEBUG_RMOBILE_SCIFA0 + default 0xe6c50000 if DEBUG_RMOBILE_SCIFA1 + default 0xe6c80000 if DEBUG_RMOBILE_SCIFA4 + default 0xe6e58000 if DEBUG_RCAR_GEN2_SCIF2 + default 0xe6e60000 if DEBUG_RCAR_GEN2_SCIF0 + default 0xe8008000 if DEBUG_R7S72100_SCIF2 default 0xf0000be0 if ARCH_EBSA110 default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE default 0xf1012000 if ARCH_DOVE || ARCH_MV78XX0 || \ @@ -1164,13 +1236,19 @@ config DEBUG_UART_PHYS default 0xff690000 if DEBUG_RK32_UART2 default 0xffc02000 if DEBUG_SOCFPGA_UART default 0xffd82340 if ARCH_IOP13XX + default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0 + default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2 default 0xfff36000 if DEBUG_HIGHBANK_UART default 0xfffe8600 if DEBUG_UART_BCM63XX default 0xfffff700 if ARCH_IOP33X depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ DEBUG_LL_UART_EFM32 || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ - DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ + DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \ + DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \ + DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \ + DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ + DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \ DEBUG_UART_BCM63XX config DEBUG_UART_VIRT diff --git a/arch/arm/include/debug/renesas-scif.S b/arch/arm/include/debug/renesas-scif.S new file mode 100644 index 000000000000..97820a8df51a --- /dev/null +++ b/arch/arm/include/debug/renesas-scif.S @@ -0,0 +1,52 @@ +/* + * Renesas SCIF(A) debugging macro include header + * + * Based on r8a7790.S + * + * Copyright (C) 2012-2013 Renesas Electronics Corporation + * Copyright (C) 1994-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define SCIF_PHYS CONFIG_DEBUG_UART_PHYS +#define SCIF_VIRT ((SCIF_PHYS & 0x00ffffff) | 0xfd000000) + +#if CONFIG_DEBUG_UART_PHYS < 0xe6e00000 +/* SCIFA */ +#define FTDR 0x20 +#define FSR 0x14 +#else +/* SCIF */ +#define FTDR 0x0c +#define FSR 0x10 +#endif + +#define TDFE (1 << 5) +#define TEND (1 << 6) + + .macro addruart, rp, rv, tmp + ldr \rp, =SCIF_PHYS + ldr \rv, =SCIF_VIRT + .endm + + .macro waituart, rd, rx +1001: ldrh \rd, [\rx, #FSR] + tst \rd, #TDFE + beq 1001b + .endm + + .macro senduart, rd, rx + strb \rd, [\rx, #FTDR] + ldrh \rd, [\rx, #FSR] + bic \rd, \rd, #TEND + strh \rd, [\rx, #FSR] + .endm + + .macro busyuart, rd, rx +1001: ldrh \rd, [\rx, #FSR] + tst \rd, #TEND + beq 1001b + .endm diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 8894e1b7ab0e..0bfe2261c4e7 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -71,6 +71,7 @@ static struct map_desc r8a7740_io_desc[] __initdata = { void __init r8a7740_map_io(void) { + debug_ll_io_init(); iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc)); } diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index 136078ab9407..434d1504066a 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -70,6 +70,7 @@ static struct map_desc r8a7779_io_desc[] __initdata = { void __init r8a7779_map_io(void) { + debug_ll_io_init(); iotable_init(r8a7779_io_desc, ARRAY_SIZE(r8a7779_io_desc)); } diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index 769ff008571d..322e2dc3fa36 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -60,6 +60,7 @@ static struct map_desc sh7372_io_desc[] __initdata = { void __init sh7372_map_io(void) { + debug_ll_io_init(); iotable_init(sh7372_io_desc, ARRAY_SIZE(sh7372_io_desc)); } diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index 3447ca7e90d9..fa7cab820ab9 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -58,6 +58,7 @@ static struct map_desc sh73a0_io_desc[] __initdata = { void __init sh73a0_map_io(void) { + debug_ll_io_init(); iotable_init(sh73a0_io_desc, ARRAY_SIZE(sh73a0_io_desc)); } -- cgit v1.2.3-59-g8ed1b From e790af67b2f8579ab0c46b6e011111ce2200cfe3 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sun, 5 Oct 2014 23:59:13 +0200 Subject: ARM: meson: add meson8 support Add a MACH_MESON8 symbol and add "amlogic,meson8" to the list of compatible strings for the Meson DT machine to support devices based on the Meson8 family of SoCs. Signed-off-by: Beniamino Galvani Acked-by: Arnd Bergmann Signed-off-by: Carlo Caione --- arch/arm/mach-meson/Kconfig | 5 +++++ arch/arm/mach-meson/meson.c | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index 2c1154e1794a..b289e8e1625f 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -10,4 +10,9 @@ config MACH_MESON6 default ARCH_MESON select MESON6_TIMER +config MACH_MESON8 + bool "Amlogic Meson8 SoCs support" + default ARCH_MESON + select MESON6_TIMER + endif diff --git a/arch/arm/mach-meson/meson.c b/arch/arm/mach-meson/meson.c index 5ee064f5a89f..8f42d8fbb505 100644 --- a/arch/arm/mach-meson/meson.c +++ b/arch/arm/mach-meson/meson.c @@ -16,12 +16,12 @@ #include #include -static const char * const m6_common_board_compat[] = { +static const char * const meson_common_board_compat[] = { "amlogic,meson6", + "amlogic,meson8", NULL, }; -DT_MACHINE_START(AML8726_MX, "Amlogic Meson6 platform") - .dt_compat = m6_common_board_compat, +DT_MACHINE_START(MESON, "Amlogic Meson platform") + .dt_compat = meson_common_board_compat, MACHINE_END - -- cgit v1.2.3-59-g8ed1b From a25a6772db05b252d9861b80b6387b67f69a8b8e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sun, 5 Oct 2014 23:59:18 +0200 Subject: ARM: meson: document meson8 compatible properties Add device tree bindings documentation for Amlogic Meson8 SoCs. Signed-off-by: Beniamino Galvani Acked-by: Arnd Bergmann Signed-off-by: Carlo Caione --- Documentation/devicetree/bindings/arm/amlogic.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt index 7eece72b1a35..8fe815046140 100644 --- a/Documentation/devicetree/bindings/arm/amlogic.txt +++ b/Documentation/devicetree/bindings/arm/amlogic.txt @@ -2,7 +2,9 @@ Amlogic MesonX device tree bindings ------------------------------------------- Boards with the Amlogic Meson6 SoC shall have the following properties: + Required root node property: + compatible: "amlogic,meson6" -Required root node property: - -compatible = "amlogic,meson6"; +Boards with the Amlogic Meson8 SoC shall have the following properties: + Required root node property: + compatible: "amlogic,meson8"; -- cgit v1.2.3-59-g8ed1b From 6a4ccd9a8e7cc2169b1c623d98d01201e9dcbacc Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 18 Nov 2014 15:25:41 +0100 Subject: ARM: meson: enable L2 cache This enables the L2 cache controller available in Amlogic SoCs. Signed-off-by: Beniamino Galvani Acked-by: Arnd Bergmann Signed-off-by: Carlo Caione --- arch/arm/mach-meson/Kconfig | 1 + arch/arm/mach-meson/meson.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index b289e8e1625f..18301dc9d2e7 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -2,6 +2,7 @@ menuconfig ARCH_MESON bool "Amlogic Meson SoCs" if ARCH_MULTI_V7 select GENERIC_IRQ_CHIP select ARM_GIC + select CACHE_L2X0 if ARCH_MESON diff --git a/arch/arm/mach-meson/meson.c b/arch/arm/mach-meson/meson.c index 8f42d8fbb505..5d6affe6a694 100644 --- a/arch/arm/mach-meson/meson.c +++ b/arch/arm/mach-meson/meson.c @@ -24,4 +24,6 @@ static const char * const meson_common_board_compat[] = { DT_MACHINE_START(MESON, "Amlogic Meson platform") .dt_compat = meson_common_board_compat, + .l2c_aux_val = 0, + .l2c_aux_mask = ~0, MACHINE_END -- cgit v1.2.3-59-g8ed1b From 7b6b0a455d98c7a314278e0fdca25ec6395a502a Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 18 Nov 2014 16:41:20 +0100 Subject: clocksource: meson6: Select CLKSRC_MMIO Select CLKSRC_MMIO when the meson6_timer driver is enabled since it depends on clocksource MMIO functions. Signed-off-by: Beniamino Galvani Signed-off-by: Carlo Caione --- drivers/clocksource/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 90420600e1eb..f657a48d20eb 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -32,6 +32,7 @@ config ARMADA_370_XP_TIMER config MESON6_TIMER bool + select CLKSRC_MMIO config ORION_TIMER select CLKSRC_OF -- cgit v1.2.3-59-g8ed1b From 81906906d8d95837c87b934a1a929cc43b61f4ee Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Mon, 17 Nov 2014 14:33:12 +0100 Subject: ARM: berlin: do not select RESET_CONTROLLER RESET_CONTROLLER is meant to be user-selectable. To respect that, do not select it automatically when using ARCH_BERLIN. Signed-off-by: Antoine Tenart Signed-off-by: Sebastian Hesselbarth --- arch/arm/mach-berlin/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig index 84d34e07209c..3e40a947f3ea 100644 --- a/arch/arm/mach-berlin/Kconfig +++ b/arch/arm/mach-berlin/Kconfig @@ -7,7 +7,6 @@ menuconfig ARCH_BERLIN select DW_APB_TIMER_OF select GENERIC_IRQ_CHIP select PINCTRL - select RESET_CONTROLLER if ARCH_BERLIN -- cgit v1.2.3-59-g8ed1b From f22d2545517a0ffb8da2879d3a0dbcae99848e6c Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Oct 2014 17:03:14 +0300 Subject: ARM: OMAP2+: hwmod: add parent_hwmod support Add parent_hwmod pointer to omap_hwmod. This can be set to point to a "parent" hwmod that needs to be enabled for the "child" hwmod to work. This is used at hwmod setup time: when doing the initial setup and reset, first enable the parent hwmod, and after setup and reset is done, restore the parent hwmod to postsetup_state. Signed-off-by: Tomi Valkeinen Reviewed-by: Archit Taneja [paul@pwsan.com: add kerneldoc documentation for parent_hwmod; note that it is a temporary workaround] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 22 ++++++++++++++++++++++ arch/arm/mach-omap2/omap_hwmod.h | 8 ++++++++ 2 files changed, 30 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index acae6d5d1151..a2c7b300fe89 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2719,11 +2719,33 @@ static int __init _setup(struct omap_hwmod *oh, void *data) if (oh->_state != _HWMOD_STATE_INITIALIZED) return 0; + if (oh->parent_hwmod) { + int r; + + r = _enable(oh->parent_hwmod); + WARN(r, "hwmod: %s: setup: failed to enable parent hwmod %s\n", + oh->name, oh->parent_hwmod->name); + } + _setup_iclk_autoidle(oh); if (!_setup_reset(oh)) _setup_postsetup(oh); + if (oh->parent_hwmod) { + u8 postsetup_state; + + postsetup_state = oh->parent_hwmod->_postsetup_state; + + if (postsetup_state == _HWMOD_STATE_IDLE) + _idle(oh->parent_hwmod); + else if (postsetup_state == _HWMOD_STATE_DISABLED) + _shutdown(oh->parent_hwmod); + else if (postsetup_state != _HWMOD_STATE_ENABLED) + WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n", + oh->parent_hwmod->name, postsetup_state); + } + return 0; } diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index 512f809a3f4d..35ca6efbec31 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -633,6 +633,7 @@ struct omap_hwmod_link { * @flags: hwmod flags (documented below) * @_lock: spinlock serializing operations on this hwmod * @node: list node for hwmod list (internal use) + * @parent_hwmod: (temporary) a pointer to the hierarchical parent of this hwmod * * @main_clk refers to this module's "main clock," which for our * purposes is defined as "the functional clock needed for register @@ -643,6 +644,12 @@ struct omap_hwmod_link { * the omap_hwmod code and should not be set during initialization. * * @masters and @slaves are now deprecated. + * + * @parent_hwmod is temporary; there should be no need for it, as this + * information should already be expressed in the OCP interface + * structures. @parent_hwmod is present as a workaround until we improve + * handling for hwmods with multiple parents (e.g., OMAP4+ DSS with + * multiple register targets across different interconnects). */ struct omap_hwmod { const char *name; @@ -680,6 +687,7 @@ struct omap_hwmod { u8 _int_flags; u8 _state; u8 _postsetup_state; + struct omap_hwmod *parent_hwmod; }; struct omap_hwmod *omap_hwmod_lookup(const char *name); -- cgit v1.2.3-59-g8ed1b From 7b472ac75689af196d868b3f2322edb44b8096d3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 13 Sep 2014 11:31:18 -0700 Subject: arm: mach-pxa: Convert pr_warning to pr_warn Use the more common pr_warn. Other miscellanea: o Coalesce formats o Realign arguments Signed-off-by: Joe Perches Signed-off-by: Robert Jarzmik --- arch/arm/mach-pxa/em-x270.c | 4 ++-- arch/arm/mach-pxa/gumstix.c | 3 +-- arch/arm/mach-pxa/mfp-pxa2xx.c | 12 +++++------- arch/arm/mach-pxa/poodle.c | 2 +- arch/arm/mach-pxa/pxa3xx-ulpi.c | 6 +++--- arch/arm/mach-pxa/raumfeld.c | 26 +++++++++++++------------- 6 files changed, 25 insertions(+), 28 deletions(-) diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 6915a9f6b3a3..51531ecffca8 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -378,7 +378,7 @@ static void __init em_x270_init_nand(void) err = gpio_request(GPIO11_NAND_CS, "NAND CS"); if (err) { - pr_warning("EM-X270: failed to request NAND CS gpio\n"); + pr_warn("EM-X270: failed to request NAND CS gpio\n"); return; } @@ -386,7 +386,7 @@ static void __init em_x270_init_nand(void) err = gpio_request(nand_rb, "NAND R/B"); if (err) { - pr_warning("EM-X270: failed to request NAND R/B gpio\n"); + pr_warn("EM-X270: failed to request NAND R/B gpio\n"); gpio_free(GPIO11_NAND_CS); return; } diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c index 00b92dad7b81..f6c76a3ee3b2 100644 --- a/arch/arm/mach-pxa/gumstix.c +++ b/arch/arm/mach-pxa/gumstix.c @@ -140,8 +140,7 @@ static void gumstix_setup_bt_clock(void) int timeout = 500; if (!(OSCC & OSCC_OOK)) - pr_warning("32kHz clock was not on. Bootloader may need to " - "be updated\n"); + pr_warn("32kHz clock was not on. Bootloader may need to be updated\n"); else return; diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index ef0426a159d4..666b78972c40 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c @@ -93,8 +93,8 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) break; default: /* warning and fall through, treat as MFP_LPM_DEFAULT */ - pr_warning("%s: GPIO%d: unsupported low power mode\n", - __func__, gpio); + pr_warn("%s: GPIO%d: unsupported low power mode\n", + __func__, gpio); break; } @@ -107,14 +107,12 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) * configurations of those pins not able to wakeup */ if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) { - pr_warning("%s: GPIO%d unable to wakeup\n", - __func__, gpio); + pr_warn("%s: GPIO%d unable to wakeup\n", __func__, gpio); return -EINVAL; } if ((c & MFP_LPM_CAN_WAKEUP) && is_out) { - pr_warning("%s: output GPIO%d unable to wakeup\n", - __func__, gpio); + pr_warn("%s: output GPIO%d unable to wakeup\n", __func__, gpio); return -EINVAL; } @@ -126,7 +124,7 @@ static inline int __mfp_validate(int mfp) int gpio = mfp_to_gpio(mfp); if ((mfp > MFP_PIN_GPIO127) || !gpio_desc[gpio].valid) { - pr_warning("%s: GPIO%d is invalid pin\n", __func__, gpio); + pr_warn("%s: GPIO%d is invalid pin\n", __func__, gpio); return -1; } diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 131991629116..29019beae591 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -446,7 +446,7 @@ static void __init poodle_init(void) ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret) - pr_warning("poodle: Unable to register LoCoMo device\n"); + pr_warn("poodle: Unable to register LoCoMo device\n"); pxa_set_fb_info(&poodle_locomo_device.dev, &poodle_fb_info); pxa_set_udc_info(&udc_info); diff --git a/arch/arm/mach-pxa/pxa3xx-ulpi.c b/arch/arm/mach-pxa/pxa3xx-ulpi.c index e329ccefd364..614003e8b081 100644 --- a/arch/arm/mach-pxa/pxa3xx-ulpi.c +++ b/arch/arm/mach-pxa/pxa3xx-ulpi.c @@ -74,7 +74,7 @@ static int pxa310_ulpi_poll(void) cpu_relax(); } - pr_warning("%s: ULPI access timed out!\n", __func__); + pr_warn("%s: ULPI access timed out!\n", __func__); return -ETIMEDOUT; } @@ -84,7 +84,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg) int err; if (pxa310_ulpi_get_phymode() != SYNCH) { - pr_warning("%s: PHY is not in SYNCH mode!\n", __func__); + pr_warn("%s: PHY is not in SYNCH mode!\n", __func__); return -EBUSY; } @@ -101,7 +101,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg) static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg) { if (pxa310_ulpi_get_phymode() != SYNCH) { - pr_warning("%s: PHY is not in SYNCH mode!\n", __func__); + pr_warn("%s: PHY is not in SYNCH mode!\n", __func__); return -EBUSY; } diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 8386dc30b3e4..a762b23ac830 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -521,7 +521,7 @@ static void __init raumfeld_w1_init(void) "W1 external pullup enable"); if (ret < 0) - pr_warning("Unable to request GPIO_W1_PULLUP_ENABLE\n"); + pr_warn("Unable to request GPIO_W1_PULLUP_ENABLE\n"); else gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0); @@ -600,7 +600,7 @@ static void __init raumfeld_lcd_init(void) ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable"); if (ret < 0) - pr_warning("Unable to request GPIO_TFT_VA_EN\n"); + pr_warn("Unable to request GPIO_TFT_VA_EN\n"); else gpio_direction_output(GPIO_TFT_VA_EN, 1); @@ -608,7 +608,7 @@ static void __init raumfeld_lcd_init(void) ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable"); if (ret < 0) - pr_warning("Unable to request GPIO_DISPLAY_ENABLE\n"); + pr_warn("Unable to request GPIO_DISPLAY_ENABLE\n"); else gpio_direction_output(GPIO_DISPLAY_ENABLE, 1); @@ -814,17 +814,17 @@ static void __init raumfeld_power_init(void) /* Set PEN2 high to enable maximum charge current */ ret = gpio_request(GPIO_CHRG_PEN2, "CHRG_PEN2"); if (ret < 0) - pr_warning("Unable to request GPIO_CHRG_PEN2\n"); + pr_warn("Unable to request GPIO_CHRG_PEN2\n"); else gpio_direction_output(GPIO_CHRG_PEN2, 1); ret = gpio_request(GPIO_CHARGE_DC_OK, "CABLE_DC_OK"); if (ret < 0) - pr_warning("Unable to request GPIO_CHARGE_DC_OK\n"); + pr_warn("Unable to request GPIO_CHARGE_DC_OK\n"); ret = gpio_request(GPIO_CHARGE_USB_SUSP, "CHARGE_USB_SUSP"); if (ret < 0) - pr_warning("Unable to request GPIO_CHARGE_USB_SUSP\n"); + pr_warn("Unable to request GPIO_CHARGE_USB_SUSP\n"); else gpio_direction_output(GPIO_CHARGE_USB_SUSP, 0); @@ -976,19 +976,19 @@ static void __init raumfeld_audio_init(void) ret = gpio_request(GPIO_CODEC_RESET, "cs4270 reset"); if (ret < 0) - pr_warning("unable to request GPIO_CODEC_RESET\n"); + pr_warn("unable to request GPIO_CODEC_RESET\n"); else gpio_direction_output(GPIO_CODEC_RESET, 1); ret = gpio_request(GPIO_SPDIF_RESET, "ak4104 s/pdif reset"); if (ret < 0) - pr_warning("unable to request GPIO_SPDIF_RESET\n"); + pr_warn("unable to request GPIO_SPDIF_RESET\n"); else gpio_direction_output(GPIO_SPDIF_RESET, 1); ret = gpio_request(GPIO_MCLK_RESET, "MCLK reset"); if (ret < 0) - pr_warning("unable to request GPIO_MCLK_RESET\n"); + pr_warn("unable to request GPIO_MCLK_RESET\n"); else gpio_direction_output(GPIO_MCLK_RESET, 1); @@ -1019,20 +1019,20 @@ static void __init raumfeld_common_init(void) ret = gpio_request(GPIO_W2W_RESET, "Wi2Wi reset"); if (ret < 0) - pr_warning("Unable to request GPIO_W2W_RESET\n"); + pr_warn("Unable to request GPIO_W2W_RESET\n"); else gpio_direction_output(GPIO_W2W_RESET, 0); ret = gpio_request(GPIO_W2W_PDN, "Wi2Wi powerup"); if (ret < 0) - pr_warning("Unable to request GPIO_W2W_PDN\n"); + pr_warn("Unable to request GPIO_W2W_PDN\n"); else gpio_direction_output(GPIO_W2W_PDN, 0); /* this can be used to switch off the device */ ret = gpio_request(GPIO_SHUTDOWN_SUPPLY, "supply shutdown"); if (ret < 0) - pr_warning("Unable to request GPIO_SHUTDOWN_SUPPLY\n"); + pr_warn("Unable to request GPIO_SHUTDOWN_SUPPLY\n"); else gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0); @@ -1051,7 +1051,7 @@ static void __init raumfeld_controller_init(void) ret = gpio_request(GPIO_SHUTDOWN_BATT, "battery shutdown"); if (ret < 0) - pr_warning("Unable to request GPIO_SHUTDOWN_BATT\n"); + pr_warn("Unable to request GPIO_SHUTDOWN_BATT\n"); else gpio_direction_output(GPIO_SHUTDOWN_BATT, 0); -- cgit v1.2.3-59-g8ed1b From 62a7575720c5079846e20553fc95fcdb78544d69 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Fri, 24 Oct 2014 21:14:22 +0400 Subject: ARM: pxa: tosa: switch to gpio-charger Switch to simpler gpio-charger module. PDA power requires additional setup in platform file and is more suited for boards with separate AC and USB charging inputs. Tosa has a unified input, so it's better suited for gpio-charger. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Robert Jarzmik --- arch/arm/mach-pxa/tosa.c | 41 +++++++---------------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index c158a6e3e0aa..7780d1faa06f 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -361,44 +361,17 @@ static struct pxaficp_platform_data tosa_ficp_platform_data = { /* * Tosa AC IN */ -static int tosa_power_init(struct device *dev) -{ - int ret = gpio_request(TOSA_GPIO_AC_IN, "ac in"); - if (ret) - goto err_gpio_req; - - ret = gpio_direction_input(TOSA_GPIO_AC_IN); - if (ret) - goto err_gpio_in; - - return 0; - -err_gpio_in: - gpio_free(TOSA_GPIO_AC_IN); -err_gpio_req: - return ret; -} - -static void tosa_power_exit(struct device *dev) -{ - gpio_free(TOSA_GPIO_AC_IN); -} - -static int tosa_power_ac_online(void) -{ - return gpio_get_value(TOSA_GPIO_AC_IN) == 0; -} - static char *tosa_ac_supplied_to[] = { "main-battery", "backup-battery", "jacket-battery", }; -static struct pda_power_pdata tosa_power_data = { - .init = tosa_power_init, - .is_ac_online = tosa_power_ac_online, - .exit = tosa_power_exit, +static struct gpio_charger_platform_data tosa_power_data = { + .name = "charger", + .type = POWER_SUPPLY_TYPE_MAINS, + .gpio = TOSA_GPIO_AC_IN, + .gpio_active_low = 1, .supplied_to = tosa_ac_supplied_to, .num_supplicants = ARRAY_SIZE(tosa_ac_supplied_to), }; @@ -415,7 +388,7 @@ static struct resource tosa_power_resource[] = { }; static struct platform_device tosa_power_device = { - .name = "pda-power", + .name = "gpio-charger", .id = -1, .dev.platform_data = &tosa_power_data, .resource = tosa_power_resource, -- cgit v1.2.3-59-g8ed1b From ef6dbda600ecf037c539c7f4c7f8fe93fb66ef3e Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 28 Sep 2014 15:20:06 +0200 Subject: arm: pxa: add device-tree irq init for pxa27x Add the initializer for irqs in a device-tree machine on a pxa27x. Signed-off-by: Robert Jarzmik Acked-by: Arnd Bergmann --- arch/arm/mach-pxa/pxa27x.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index b040d7d14888..af423a48c2e3 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -398,6 +398,12 @@ void __init pxa27x_init_irq(void) pxa_init_irq(34, pxa27x_set_wake); } +void __init pxa27x_dt_init_irq(void) +{ + if (IS_ENABLED(CONFIG_OF)) + pxa_dt_irq_init(pxa27x_set_wake); +} + static struct map_desc pxa27x_io_desc[] __initdata = { { /* Mem Ctl */ .virtual = (unsigned long)SMEMC_VIRT, -- cgit v1.2.3-59-g8ed1b From 4508f7751728980873c0368dedb298fc6f550b50 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 28 Sep 2014 13:59:41 +0200 Subject: arm: pxa: move init functions into generic.h In order to have a unique .c file for all pxa variants device-tree definitions, all the initialization functions for MACHINE_START and DT_MACHINE_START have been put together into generic.h. The alternative would have been one pxaXXX-dt.c file per variant. The move is necessary because each include/mach/pxaXXX.h includes the variant register descriptions which intersects and conflicts one with each other. The change is a preparation for pxa-dt.c to support multiple pxa, ie. pxa3xx and pxa27x. The machine files including mach/pxaXXX.h all include generic.h, which guarantees no regression should be introduced. Signed-off-by: Robert Jarzmik Acked-by: Arnd Bergmann --- arch/arm/mach-pxa/generic.h | 65 +++++++++++++++++++++------------ arch/arm/mach-pxa/include/mach/pxa25x.h | 8 ---- arch/arm/mach-pxa/include/mach/pxa27x.h | 4 -- arch/arm/mach-pxa/include/mach/pxa3xx.h | 5 --- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index 8963984d1f43..7a9fa1aa4e41 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -13,11 +13,11 @@ struct irq_data; -extern void pxa_timer_init(void); - -extern void __init pxa_map_io(void); - extern unsigned int get_clk_frequency_khz(int info); +extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, + unsigned int)); +extern void __init pxa_map_io(void); +extern void pxa_timer_init(void); #define SET_BANK(__nr,__start,__size) \ mi->bank[__nr].start = (__start), \ @@ -25,6 +25,43 @@ extern unsigned int get_clk_frequency_khz(int info); #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) +#define pxa25x_handle_irq icip_handle_irq +extern void __init pxa25x_init_irq(void); +extern void __init pxa25x_map_io(void); +extern void __init pxa26x_init_irq(void); + +#define pxa27x_handle_irq ichp_handle_irq +extern void __init pxa27x_dt_init_irq(void); +extern unsigned pxa27x_get_clk_frequency_khz(int); +extern void __init pxa27x_init_irq(void); +extern void __init pxa27x_map_io(void); + +#define pxa3xx_handle_irq ichp_handle_irq +extern void __init pxa3xx_dt_init_irq(void); +extern void __init pxa3xx_init_irq(void); +extern void __init pxa3xx_map_io(void); + +extern struct syscore_ops pxa_irq_syscore_ops; +extern struct syscore_ops pxa2xx_mfp_syscore_ops; +extern struct syscore_ops pxa3xx_mfp_syscore_ops; + +void __init pxa_set_ffuart_info(void *info); +void __init pxa_set_btuart_info(void *info); +void __init pxa_set_stuart_info(void *info); +void __init pxa_set_hwuart_info(void *info); + +void pxa_restart(enum reboot_mode, const char *); + +#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) +extern void pxa2xx_clear_reset_status(unsigned int); +#else +static inline void pxa2xx_clear_reset_status(unsigned int mask) {} +#endif + +/* + * Once fully converted to the clock framework, all these functions should be + * removed, and replaced with a clk_get(NULL, "core"). + */ #ifdef CONFIG_PXA25x extern unsigned pxa25x_get_clk_frequency_khz(int); #else @@ -32,30 +69,12 @@ extern unsigned pxa25x_get_clk_frequency_khz(int); #endif #ifdef CONFIG_PXA27x -extern unsigned pxa27x_get_clk_frequency_khz(int); #else #define pxa27x_get_clk_frequency_khz(x) (0) #endif -#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) -extern void pxa2xx_clear_reset_status(unsigned int); -#else -static inline void pxa2xx_clear_reset_status(unsigned int mask) {} -#endif - #ifdef CONFIG_PXA3xx -extern unsigned pxa3xx_get_clk_frequency_khz(int); +extern unsigned pxa3xx_get_clk_frequency_khz(int); #else #define pxa3xx_get_clk_frequency_khz(x) (0) #endif - -extern struct syscore_ops pxa_irq_syscore_ops; -extern struct syscore_ops pxa2xx_mfp_syscore_ops; -extern struct syscore_ops pxa3xx_mfp_syscore_ops; - -void __init pxa_set_ffuart_info(void *info); -void __init pxa_set_btuart_info(void *info); -void __init pxa_set_stuart_info(void *info); -void __init pxa_set_hwuart_info(void *info); - -void pxa_restart(enum reboot_mode, const char *); diff --git a/arch/arm/mach-pxa/include/mach/pxa25x.h b/arch/arm/mach-pxa/include/mach/pxa25x.h index 3ac0baac7350..5a341752e32c 100644 --- a/arch/arm/mach-pxa/include/mach/pxa25x.h +++ b/arch/arm/mach-pxa/include/mach/pxa25x.h @@ -6,12 +6,4 @@ #include #include -extern void __init pxa25x_map_io(void); -extern void __init pxa25x_init_irq(void); -#ifdef CONFIG_CPU_PXA26x -extern void __init pxa26x_init_irq(void); -#endif - -#define pxa25x_handle_irq icip_handle_irq - #endif /* __MACH_PXA25x_H */ diff --git a/arch/arm/mach-pxa/include/mach/pxa27x.h b/arch/arm/mach-pxa/include/mach/pxa27x.h index 7cff640582b8..599b925a657c 100644 --- a/arch/arm/mach-pxa/include/mach/pxa27x.h +++ b/arch/arm/mach-pxa/include/mach/pxa27x.h @@ -19,11 +19,7 @@ #define ARB_CORE_PARK (1<<24) /* Be parked with core when idle */ #define ARB_LOCK_FLAG (1<<23) /* Only Locking masters gain access to the bus */ -extern void __init pxa27x_map_io(void); -extern void __init pxa27x_init_irq(void); extern int __init pxa27x_set_pwrmode(unsigned int mode); extern void pxa27x_cpu_pm_enter(suspend_state_t state); -#define pxa27x_handle_irq ichp_handle_irq - #endif /* __MACH_PXA27x_H */ diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx.h b/arch/arm/mach-pxa/include/mach/pxa3xx.h index 6dd7fa163e29..b4143fb6631f 100644 --- a/arch/arm/mach-pxa/include/mach/pxa3xx.h +++ b/arch/arm/mach-pxa/include/mach/pxa3xx.h @@ -5,9 +5,4 @@ #include #include -extern void __init pxa3xx_map_io(void); -extern void __init pxa3xx_init_irq(void); - -#define pxa3xx_handle_irq ichp_handle_irq - #endif /* __MACH_PXA3XX_H */ -- cgit v1.2.3-59-g8ed1b From bec942fcf4e7fac6965e1b5a33c51d034d276385 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 28 Sep 2014 14:10:54 +0200 Subject: arm: pxa: remove unnecessary includes from pxa-dt As the init functions necessary for machine init have moved to generic.h, remove the unnecessary includes and prototypes definitions from pxa-dt.c. This removes the include of mach/pxaXXX-regs.h, and make pxa-dt generic enough to accept other pxa variants. Signed-off-by: Robert Jarzmik Acked-by: Arnd Bergmann --- arch/arm/mach-pxa/pxa-dt.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c index f6a2c4b1c1dc..b070196f5a43 100644 --- a/arch/arm/mach-pxa/pxa-dt.c +++ b/arch/arm/mach-pxa/pxa-dt.c @@ -15,13 +15,10 @@ #include #include #include -#include #include "generic.h" #ifdef CONFIG_PXA3xx -extern void __init pxa3xx_dt_init_irq(void); - static const struct of_dev_auxdata pxa3xx_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40100000, "pxa2xx-uart.0", NULL), OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40200000, "pxa2xx-uart.1", NULL), -- cgit v1.2.3-59-g8ed1b From 03ec7fe70c5ce850a20aabe66c88e1a39111f9dd Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 28 Sep 2014 14:13:21 +0200 Subject: arm: pxa: add pxa27x device-tree support Add a device-tree machine entry (DT_MACHINE_START) for pxa27x based platforms. Signed-off-by: Robert Jarzmik Acked-by: Arnd Bergmann --- arch/arm/mach-pxa/Kconfig | 11 +++++++++++ arch/arm/mach-pxa/Makefile | 1 + arch/arm/mach-pxa/pxa-dt.c | 15 +++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index e6690a44917d..83efe914bf7d 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -4,6 +4,17 @@ menu "Intel PXA2xx/PXA3xx Implementations" comment "Intel/Marvell Dev Platforms (sorted by hardware release time)" +config MACH_PXA27X_DT + bool "Support PXA27x platforms from device tree" + select CPU_PXA27x + select POWER_SUPPLY + select PXA27x + select USE_OF + help + Include support for Marvell PXA27x based platforms using + the device tree. Needn't select any other machine while + MACH_PXA27X_DT is enabled. + config MACH_PXA3XX_DT bool "Support PXA3xx platforms from device tree" select CPU_PXA300 diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 2fe1824c6dcb..eb0bf7678a99 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_CPU_PXA930) += pxa930.o # Device Tree support obj-$(CONFIG_MACH_PXA3XX_DT) += pxa-dt.o +obj-$(CONFIG_MACH_PXA27X_DT) += pxa-dt.o # Intel/Marvell Dev Platforms obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c index b070196f5a43..7e0e5bd0c9de 100644 --- a/arch/arm/mach-pxa/pxa-dt.c +++ b/arch/arm/mach-pxa/pxa-dt.c @@ -58,3 +58,18 @@ DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)") .dt_compat = pxa3xx_dt_board_compat, MACHINE_END #endif + +#ifdef CONFIG_PXA27x +static const char * const pxa27x_dt_board_compat[] __initconst = { + "marvell,pxa270", + NULL, +}; + +DT_MACHINE_START(PXA27X_DT, "Marvell PXA2xx (Device Tree Support)") + .map_io = pxa27x_map_io, + .init_irq = pxa27x_dt_init_irq, + .handle_irq = pxa27x_handle_irq, + .restart = pxa_restart, + .dt_compat = pxa27x_dt_board_compat, +MACHINE_END +#endif -- cgit v1.2.3-59-g8ed1b From 9ed69650897e8738c959fe8242ec41499f3f3f35 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Oct 2014 17:03:15 +0300 Subject: ARM: OMAP5: hwmod: set DSS submodule parent hwmods Set DSS core hwmod as the parent for all the DSS submodules. Signed-off-by: Tomi Valkeinen Reviewed-by: Archit Taneja Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_54xx_data.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c index 1103aa0e0d29..229c7fb7e1c3 100644 --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c @@ -421,6 +421,7 @@ static struct omap_hwmod omap54xx_dss_dispc_hwmod = { .opt_clks = dss_dispc_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dispc_opt_clks), .dev_attr = &dss_dispc_dev_attr, + .parent_hwmod = &omap54xx_dss_hwmod, }; /* @@ -462,6 +463,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_a_hwmod = { }, .opt_clks = dss_dsi1_a_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dsi1_a_opt_clks), + .parent_hwmod = &omap54xx_dss_hwmod, }; /* dss_dsi1_c */ @@ -482,6 +484,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_c_hwmod = { }, .opt_clks = dss_dsi1_c_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dsi1_c_opt_clks), + .parent_hwmod = &omap54xx_dss_hwmod, }; /* @@ -521,6 +524,7 @@ static struct omap_hwmod omap54xx_dss_hdmi_hwmod = { }, .opt_clks = dss_hdmi_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks), + .parent_hwmod = &omap54xx_dss_hwmod, }; /* @@ -560,6 +564,7 @@ static struct omap_hwmod omap54xx_dss_rfbi_hwmod = { }, .opt_clks = dss_rfbi_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks), + .parent_hwmod = &omap54xx_dss_hwmod, }; /* -- cgit v1.2.3-59-g8ed1b From 543b2847d4bdb07eb1b50003095bc65cf2a1e2c0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Oct 2014 17:03:16 +0300 Subject: ARM: OMAP4: hwmod: set DSS submodule parent hwmods Set DSS core hwmod as the parent for all the DSS submodules. Signed-off-by: Tomi Valkeinen Reviewed-by: Archit Taneja Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 44e5634bba34..df8dc0f6530f 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -647,7 +647,8 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = { .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET, }, }, - .dev_attr = &omap44xx_dss_dispc_dev_attr + .dev_attr = &omap44xx_dss_dispc_dev_attr, + .parent_hwmod = &omap44xx_dss_hwmod, }; /* @@ -701,6 +702,7 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = { }, .opt_clks = dss_dsi1_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dsi1_opt_clks), + .parent_hwmod = &omap44xx_dss_hwmod, }; /* dss_dsi2 */ @@ -733,6 +735,7 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = { }, .opt_clks = dss_dsi2_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dsi2_opt_clks), + .parent_hwmod = &omap44xx_dss_hwmod, }; /* @@ -790,6 +793,7 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = { }, .opt_clks = dss_hdmi_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks), + .parent_hwmod = &omap44xx_dss_hwmod, }; /* @@ -836,6 +840,7 @@ static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { }, .opt_clks = dss_rfbi_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks), + .parent_hwmod = &omap44xx_dss_hwmod, }; /* @@ -859,6 +864,7 @@ static struct omap_hwmod omap44xx_dss_venc_hwmod = { .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET, }, }, + .parent_hwmod = &omap44xx_dss_hwmod, }; /* -- cgit v1.2.3-59-g8ed1b From 7ede8561614afcc82f0e17bb70ae64fd620b94b0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Oct 2014 17:03:17 +0300 Subject: ARM: OMAP4: hwmod: use MODULEMODE properly Instead of using a hacky "dss_fck" clock (which toggles the MODULEMODE bit) as DSS L3 interface clock, set the .modulemode field in the omap44xx_dss_hwmod. This works now that the DSS core hwmod is enabled during DSS submodule resets. Signed-off-by: Tomi Valkeinen Reviewed-by: Archit Taneja Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index df8dc0f6530f..8126f178d57e 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -589,6 +589,7 @@ static struct omap_hwmod omap44xx_dss_hwmod = { .omap4 = { .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET, .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, }, }, .opt_clks = dss_opt_clks, @@ -3677,7 +3678,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3713,7 +3714,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dispc_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dispc = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_dispc_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_dispc_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3749,7 +3750,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi1_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi1 = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_dsi1_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_dsi1_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3785,7 +3786,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi2_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi2 = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_dsi2_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_dsi2_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3821,7 +3822,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_hdmi_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_hdmi = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_hdmi_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_hdmi_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3857,7 +3858,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_rfbi_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_rfbi = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_rfbi_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_rfbi_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3893,7 +3894,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_venc_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_venc = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_venc_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_venc_dma_addrs, .user = OCP_USER_SDMA, }; -- cgit v1.2.3-59-g8ed1b From 2cc84f46de7118d4a5a5b7ed1dced40c2247083d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Oct 2014 17:03:18 +0300 Subject: ARM: OMAP4: fix RFBI iclk RFBI iclk was set to point to hacky "dss_fck", which will be removed. Instead use "l3_div_ck", which is the proper clock for this. "l3_div_ck" is the parent of "dss_fck", so the clock rate is the same as previously. Signed-off-by: Tomi Valkeinen Reviewed-by: Archit Taneja Signed-off-by: Paul Walmsley --- arch/arm/boot/dts/omap4.dtsi | 2 +- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 878c979203d0..84045a5c3ce8 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -895,7 +895,7 @@ reg = <0x58002000 0x1000>; status = "disabled"; ti,hwmods = "dss_rfbi"; - clocks = <&dss_dss_clk>, <&dss_fck>; + clocks = <&dss_dss_clk>, <&l3_div_ck>; clock-names = "fck", "ick"; }; diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 8126f178d57e..d6f41e1b6d1b 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -824,7 +824,7 @@ static struct omap_hwmod_dma_info omap44xx_dss_rfbi_sdma_reqs[] = { }; static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = { - { .role = "ick", .clk = "dss_fck" }, + { .role = "ick", .clk = "l3_div_ck" }, }; static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { -- cgit v1.2.3-59-g8ed1b From e01600e3125be3caf5635d90bb182864f3b2d9b3 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 9 Oct 2014 17:03:19 +0300 Subject: ARM: dts: omap4.dtsi: remove dss_fck "dss_fck" is a hacky clock, used to work around problems with MODULEMODE bit handling in DSS hwmods. These problems have now been solved, so we can remove the dss_fck clock. Signed-off-by: Tomi Valkeinen Reviewed-by: Archit Taneja Signed-off-by: Paul Walmsley --- arch/arm/boot/dts/omap44xx-clocks.dtsi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm/boot/dts/omap44xx-clocks.dtsi b/arch/arm/boot/dts/omap44xx-clocks.dtsi index c821ff5e9b8d..f2c48f09824e 100644 --- a/arch/arm/boot/dts/omap44xx-clocks.dtsi +++ b/arch/arm/boot/dts/omap44xx-clocks.dtsi @@ -1018,14 +1018,6 @@ reg = <0x1120>; }; - dss_fck: dss_fck { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3_div_ck>; - ti,bit-shift = <1>; - reg = <0x1120>; - }; - fdif_fck: fdif_fck { #clock-cells = <0>; compatible = "ti,divider-clock"; -- cgit v1.2.3-59-g8ed1b From 33acc9fff9e0c48d3e1416a077cf9532b998ced0 Mon Sep 17 00:00:00 2001 From: Ambresh K Date: Tue, 21 Oct 2014 11:17:51 -0500 Subject: ARM: DRA7: hwmod data: Add missing UART hwmod data We had constrainted hwmod entries to entries in dts which were present only for default mapped interrupts, the ones such as UARTs > 6 which needed IRQ crossbar configured were never added to hwmod database. Add them now that IRQ crossbar is functional Without this, enabling UARTs7 to 10 in dts results in the following crash: [ 1.893829] omap_uart 48420000.serial: _od_fail_runtime_resume: FIXME: missing hwmod/omap_dev info [ 1.903381] Unhandled fault: imprecise external abort (0x1406) at 0x00000000 [ 1.903381] ------------[ cut here ]------------ [ 1.903381] WARNING: CPU: 0 PID: 0 at drivers/bus/omap_l3_noc.c:147 l3_interrupt_handler+0x2ac/0x32c() [ 1.903411] 44000000.ocp:L3 Custom Error: MASTER MPU TARGET L4_PER2_P3 (Read): Data Access in User mode during Functional access [ 1.903411] Modules linked in: [ 1.903411] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.18.0-rc1-dirty #3 [ 1.903442] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 1.903442] [] (show_stack) from [] (dump_stack+0x78/0x94) [ 1.903472] [] (dump_stack) from [] (warn_slowpath_common+0x6c/0x8c) [ 1.903472] [] (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40) [ 1.903472] [] (warn_slowpath_fmt) from [] (l3_interrupt_handler+0x2ac/0x32c) [ 1.903503] [] (l3_interrupt_handler) from [] (handle_irq_event_percpu+0x60/0x230) [ 1.903503] [] (handle_irq_event_percpu) from [] (handle_irq_event+0x3c/0x5c) [ 1.903503] [] (handle_irq_event) from [] (handle_fasteoi_irq+0xc4/0x190) [ 1.903503] [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x20/0x30) [ 1.903533] [] (generic_handle_irq) from [] (__handle_domain_irq+0x64/0xb8) [ 1.903533] [] (__handle_domain_irq) from [] (gic_handle_irq+0x20/0x60) [ 1.903533] [] (gic_handle_irq) from [] (__irq_svc+0x44/0x5c) [ 1.903533] Exception stack(0xc08d1f60 to 0xc08d1fa8) [ 1.903564] 1f60: 00000001 00000001 00000000 c08dc930 c08d0000 00000000 00000000 00000000 [ 1.903564] 1f80: ffffffed c0978028 c08d89dc c08d8978 00000000 c08d1fa8 c0083fc0 c000f160 [ 1.903564] 1fa0: 20000013 ffffffff [ 1.903564] [] (__irq_svc) from [] (arch_cpu_idle+0x20/0x3c) [ 1.903594] [] (arch_cpu_idle) from [] (cpu_startup_entry+0x198/0x338) [ 1.903594] [] (cpu_startup_entry) from [] (start_kernel+0x358/0x3c4) [ 1.903594] [] (start_kernel) from [<80008074>] (0x80008074) [ 1.903594] ---[ end trace 293fc95d463cff71 ]--- [ 2.117553] Internal error: : 1406 [#1] SMP ARM [ 2.122314] Modules linked in: [ 2.125518] CPU: 1 PID: 1 Comm: swapper/0 Tainted: G W 3.18.0-rc1-dirty #3 [ 2.133850] task: ed868b80 ti: ed86a000 task.ti: ed86a000 [ 2.139526] PC is at serial_omap_probe+0x2fc/0x514 [ 2.144561] LR is at trace_hardirqs_on_caller+0xec/0x1c4 [ 2.150146] pc : [] lr : [] psr: 40000013 [ 2.150146] sp : ed86be18 ip : ed9bb57c fp : f005e000 [ 2.162231] r10: 0000012a r9 : ed9b4f80 r8 : edc5bdcd [ 2.167724] r7 : edc58810 r6 : ed9bb400 r5 : ed9bb410 r4 : edc5bc10 [ 2.174560] r3 : 00000000 r2 : 00000000 r1 : 00000014 r0 : ffffffed [ 2.181427] Flags: nZcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel [ 2.189117] Control: 10c5387d Table: 8000406a DAC: 00000015 [ 2.195159] Process swapper/0 (pid: 1, stack limit = 0xed86a248) [ 2.201477] Stack: (0xed86be18 to 0xed86c000) [ 2.206054] be00: ed9ba2d0 00000000 [ 2.214660] be20: edc50150 00000001 c08cba58 00000000 00000000 ed9bb410 ffffffed c09481d8 [ 2.223236] be40: 00000000 c09481d8 c08cba58 00000000 00000000 c039bcfc c1170958 ed9bb410 [ 2.231842] be60: ed9bb444 c039a6f4 00000000 ed9bb410 c09481d8 ed9bb444 00000000 c08dc698 [ 2.240447] be80: edc4a100 c039a8b0 c09481d8 c039a81c 00000000 c0399060 ed8afaa8 ed92c110 [ 2.249053] bea0: c09481d8 edc482c0 c0949308 c0399ee0 c077f80c c09481d8 ed86a000 c09481d8 [ 2.257659] bec0: ed86a000 c08dc698 00000000 c039b088 00000000 00000000 ed86a000 c08a1924 [ 2.266235] bee0: c08a1904 c00089c4 00000000 00000000 00000000 00000000 60000093 00000000 [ 2.274841] bf00: 00000004 00000000 ed868b80 00000004 00000000 60000053 00000000 00000001 [ 2.283447] bf20: 00000000 c0083ea8 00000001 ed86a000 c08334bc ef7fc307 000000b2 c0059358 [ 2.292053] bf40: c07e176c c083299c 00000006 00000006 c08cb588 c08b69cc 00000006 c08b69ac [ 2.300659] bf60: c097a280 000000b2 c08cba58 c0869588 00000000 c0869e04 00000006 00000006 [ 2.309234] bf80: c0869588 00000000 00000000 c05dfd7c 00000000 00000000 00000000 00000000 [ 2.317840] bfa0: 00000000 c05dfd84 00000000 c000e668 00000000 00000000 00000000 00000000 [ 2.326446] bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 2.335052] bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 020405d0 00090c40 [ 2.343658] [] (serial_omap_probe) from [] (platform_drv_probe+0x48/0x98) [ 2.352630] [] (platform_drv_probe) from [] (driver_probe_device+0x10c/0x234) [ 2.361968] [] (driver_probe_device) from [] (__driver_attach+0x94/0x98) [ 2.370819] [] (__driver_attach) from [] (bus_for_each_dev+0x54/0x88) [ 2.379425] [] (bus_for_each_dev) from [] (bus_add_driver+0xdc/0x1d4) [ 2.388031] [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [ 2.396453] [] (driver_register) from [] (serial_omap_init+0x20/0x40) [ 2.405059] [] (serial_omap_init) from [] (do_one_initcall+0x80/0x1cc) [ 2.413757] [] (do_one_initcall) from [] (kernel_init_freeable+0x1b8/0x28c) [ 2.422912] [] (kernel_init_freeable) from [] (kernel_init+0x8/0xe4) [ 2.431396] [] (kernel_init) from [] (ret_from_fork+0x14/0x2c) [ 2.439361] Code: e1b02f23 020320f0 0203300f 01a02222 (0a000021) [ 2.445770] ---[ end trace 293fc95d463cff72 ]--- [ 2.450683] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 2.450683] [ 2.460296] CPU0: stopping [ 2.463134] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G D W 3.18.0-rc1-dirty #3 [ 2.471405] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 2.479522] [] (show_stack) from [] (dump_stack+0x78/0x94) [ 2.487060] [] (dump_stack) from [] (handle_IPI+0x190/0x264) [ 2.494781] [] (handle_IPI) from [] (gic_handle_irq+0x58/0x60) [ 2.502716] [] (gic_handle_irq) from [] (__irq_svc+0x44/0x5c) [ 2.510528] Exception stack(0xc08d1f60 to 0xc08d1fa8) [ 2.515808] 1f60: c000f15c 00000000 00000000 00000000 c08d0000 00000000 00000000 00000000 [ 2.524353] 1f80: ffffffed c0978028 c08d89dc c08d8978 00000000 c08d1fa8 c000f15c c000f160 [ 2.532897] 1fa0: 60000013 ffffffff [ 2.536529] [] (__irq_svc) from [] (arch_cpu_idle+0x20/0x3c) [ 2.544281] [] (arch_cpu_idle) from [] (cpu_startup_entry+0x198/0x338) [ 2.552917] [] (cpu_startup_entry) from [] (start_kernel+0x358/0x3c4) [ 2.561462] [] (start_kernel) from [<80008074>] (0x80008074) [ 2.568298] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ Reported-by: Franklin Cooper Jr. Signed-off-by: Nishanth Menon Signed-off-by: Ambresh K Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_7xx_data.c | 100 ++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c index 5684f112654b..e2a70439bf35 100644 --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c @@ -2075,6 +2075,70 @@ static struct omap_hwmod dra7xx_uart6_hwmod = { }, }; +/* uart7 */ +static struct omap_hwmod dra7xx_uart7_hwmod = { + .name = "uart7", + .class = &dra7xx_uart_hwmod_class, + .clkdm_name = "l4per2_clkdm", + .main_clk = "uart7_gfclk_mux", + .flags = HWMOD_SWSUP_SIDLE_ACT, + .prcm = { + .omap4 = { + .clkctrl_offs = DRA7XX_CM_L4PER2_UART7_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_UART7_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + +/* uart8 */ +static struct omap_hwmod dra7xx_uart8_hwmod = { + .name = "uart8", + .class = &dra7xx_uart_hwmod_class, + .clkdm_name = "l4per2_clkdm", + .main_clk = "uart8_gfclk_mux", + .flags = HWMOD_SWSUP_SIDLE_ACT, + .prcm = { + .omap4 = { + .clkctrl_offs = DRA7XX_CM_L4PER2_UART8_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_UART8_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + +/* uart9 */ +static struct omap_hwmod dra7xx_uart9_hwmod = { + .name = "uart9", + .class = &dra7xx_uart_hwmod_class, + .clkdm_name = "l4per2_clkdm", + .main_clk = "uart9_gfclk_mux", + .flags = HWMOD_SWSUP_SIDLE_ACT, + .prcm = { + .omap4 = { + .clkctrl_offs = DRA7XX_CM_L4PER2_UART9_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_UART9_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + +/* uart10 */ +static struct omap_hwmod dra7xx_uart10_hwmod = { + .name = "uart10", + .class = &dra7xx_uart_hwmod_class, + .clkdm_name = "wkupaon_clkdm", + .main_clk = "uart10_gfclk_mux", + .flags = HWMOD_SWSUP_SIDLE_ACT, + .prcm = { + .omap4 = { + .clkctrl_offs = DRA7XX_CM_WKUPAON_UART10_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_WKUPAON_UART10_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + /* * 'usb_otg_ss' class * @@ -3095,6 +3159,38 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart6 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* l4_per2 -> uart7 */ +static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart7 = { + .master = &dra7xx_l4_per2_hwmod, + .slave = &dra7xx_uart7_hwmod, + .clk = "l3_iclk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* l4_per2 -> uart8 */ +static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart8 = { + .master = &dra7xx_l4_per2_hwmod, + .slave = &dra7xx_uart8_hwmod, + .clk = "l3_iclk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* l4_per2 -> uart9 */ +static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart9 = { + .master = &dra7xx_l4_per2_hwmod, + .slave = &dra7xx_uart9_hwmod, + .clk = "l3_iclk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* l4_wkup -> uart10 */ +static struct omap_hwmod_ocp_if dra7xx_l4_wkup__uart10 = { + .master = &dra7xx_l4_wkup_hwmod, + .slave = &dra7xx_uart10_hwmod, + .clk = "wkupaon_iclk_mux", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + /* l4_per3 -> usb_otg_ss1 */ static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss1 = { .master = &dra7xx_l4_per3_hwmod, @@ -3259,6 +3355,10 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = { &dra7xx_l4_per1__uart4, &dra7xx_l4_per1__uart5, &dra7xx_l4_per1__uart6, + &dra7xx_l4_per2__uart7, + &dra7xx_l4_per2__uart8, + &dra7xx_l4_per2__uart9, + &dra7xx_l4_wkup__uart10, &dra7xx_l4_per3__usb_otg_ss1, &dra7xx_l4_per3__usb_otg_ss2, &dra7xx_l4_per3__usb_otg_ss3, -- cgit v1.2.3-59-g8ed1b From e6131fa3835483944c13d03bcff1d9103d9f53ce Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Thu, 6 Nov 2014 10:20:23 +0300 Subject: ARM: debug: move StrongARM debug include to arch/arm/include/debug StrongARM debug-macro.S is quite standalone thing, depending only on register mappings. Move it to proper place and add Kconfig entry. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Arnd Bergmann --- arch/arm/Kconfig.debug | 9 ++++ arch/arm/include/debug/sa1100.S | 68 +++++++++++++++++++++++++ arch/arm/mach-sa1100/include/mach/debug-macro.S | 62 ---------------------- 3 files changed, 77 insertions(+), 62 deletions(-) create mode 100644 arch/arm/include/debug/sa1100.S delete mode 100644 arch/arm/mach-sa1100/include/mach/debug-macro.S diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 6a4ee008b092..6c23769318ac 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -734,6 +734,14 @@ choice their output to UART 2. The port must have been initialised by the boot-loader before use. + config DEBUG_SA1100 + depends on ARCH_SA1100 + bool "Use SA1100 UARTs for low-level debug" + help + Say Y here if you want kernel low-level debugging support + on SA-11x0 UART ports. The kernel will check for the first + enabled UART in a sequence 3-1-2. + config DEBUG_SOCFPGA_UART depends on ARCH_SOCFPGA bool "Use SOCFPGA UART for low-level debug" @@ -1052,6 +1060,7 @@ config DEBUG_STI_UART config DEBUG_LL_INCLUDE string + default "debug/sa1100.S" if DEBUG_SA1100 default "debug/8250.S" if DEBUG_LL_UART_8250 || DEBUG_UART_8250 default "debug/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2 default "debug/meson.S" if DEBUG_MESON_UARTAO diff --git a/arch/arm/include/debug/sa1100.S b/arch/arm/include/debug/sa1100.S new file mode 100644 index 000000000000..a0ae4f4cd924 --- /dev/null +++ b/arch/arm/include/debug/sa1100.S @@ -0,0 +1,68 @@ +/* arch/arm/include/debug/sa1100.S + * + * Debugging macro include header + * + * Copyright (C) 1994-1999 Russell King + * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +*/ + +#define UTCR3 0x0c +#define UTDR 0x14 +#define UTSR1 0x20 +#define UTCR3_TXE 0x00000002 /* Transmit Enable */ +#define UTSR1_TBY 0x00000001 /* Transmitter BusY (read) */ +#define UTSR1_TNF 0x00000004 /* Transmit FIFO Not Full (read) */ + + .macro addruart, rp, rv, tmp + mrc p15, 0, \rp, c1, c0 + tst \rp, #1 @ MMU enabled? + moveq \rp, #0x80000000 @ physical base address + movne \rp, #0xf8000000 @ virtual address + + @ We probe for the active serial port here, coherently with + @ the comment in arch/arm/mach-sa1100/include/mach/uncompress.h. + @ We assume r1 can be clobbered. + + @ see if Ser3 is active + add \rp, \rp, #0x00050000 + ldr \rv, [\rp, #UTCR3] + tst \rv, #UTCR3_TXE + + @ if Ser3 is inactive, then try Ser1 + addeq \rp, \rp, #(0x00010000 - 0x00050000) + ldreq \rv, [\rp, #UTCR3] + tsteq \rv, #UTCR3_TXE + + @ if Ser1 is inactive, then try Ser2 + addeq \rp, \rp, #(0x00030000 - 0x00010000) + ldreq \rv, [\rp, #UTCR3] + tsteq \rv, #UTCR3_TXE + + @ clear top bits, and generate both phys and virt addresses + lsl \rp, \rp, #8 + lsr \rp, \rp, #8 + orr \rv, \rp, #0xf8000000 @ virtual + orr \rp, \rp, #0x80000000 @ physical + + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #UTDR] + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #UTSR1] + tst \rd, #UTSR1_TNF + beq 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #UTSR1] + tst \rd, #UTSR1_TBY + bne 1001b + .endm diff --git a/arch/arm/mach-sa1100/include/mach/debug-macro.S b/arch/arm/mach-sa1100/include/mach/debug-macro.S deleted file mode 100644 index 530772d937ad..000000000000 --- a/arch/arm/mach-sa1100/include/mach/debug-macro.S +++ /dev/null @@ -1,62 +0,0 @@ -/* arch/arm/mach-sa1100/include/mach/debug-macro.S - * - * Debugging macro include header - * - * Copyright (C) 1994-1999 Russell King - * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * -*/ -#include - - .macro addruart, rp, rv, tmp - mrc p15, 0, \rp, c1, c0 - tst \rp, #1 @ MMU enabled? - moveq \rp, #0x80000000 @ physical base address - movne \rp, #0xf8000000 @ virtual address - - @ We probe for the active serial port here, coherently with - @ the comment in arch/arm/mach-sa1100/include/mach/uncompress.h. - @ We assume r1 can be clobbered. - - @ see if Ser3 is active - add \rp, \rp, #0x00050000 - ldr \rv, [\rp, #UTCR3] - tst \rv, #UTCR3_TXE - - @ if Ser3 is inactive, then try Ser1 - addeq \rp, \rp, #(0x00010000 - 0x00050000) - ldreq \rv, [\rp, #UTCR3] - tsteq \rv, #UTCR3_TXE - - @ if Ser1 is inactive, then try Ser2 - addeq \rp, \rp, #(0x00030000 - 0x00010000) - ldreq \rv, [\rp, #UTCR3] - tsteq \rv, #UTCR3_TXE - - @ clear top bits, and generate both phys and virt addresses - lsl \rp, \rp, #8 - lsr \rp, \rp, #8 - orr \rv, \rp, #0xf8000000 @ virtual - orr \rp, \rp, #0x80000000 @ physical - - .endm - - .macro senduart,rd,rx - str \rd, [\rx, #UTDR] - .endm - - .macro waituart,rd,rx -1001: ldr \rd, [\rx, #UTSR1] - tst \rd, #UTSR1_TNF - beq 1001b - .endm - - .macro busyuart,rd,rx -1001: ldr \rd, [\rx, #UTSR1] - tst \rd, #UTSR1_TBY - bne 1001b - .endm -- cgit v1.2.3-59-g8ed1b From d686ce4204c5dc131396f1fca81beebc46cb8cdb Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Tue, 14 Oct 2014 19:33:38 +0000 Subject: socfpga: hotplug: put cpu1 in wfi Use WFI when putting CPU1 to sleep. Don't hold CPU1 in reset since that results in increased power consumption. Reset CPU1 briefly during CPU1 bootup. This has been tested for hotplug and suspend/resume and results in no increased power consumption. Signed-off-by: Alan Tull Acked-by: Pavel Machek Signed-off-by: Dinh Nguyen Signed-off-by: Arnd Bergmann --- arch/arm/mach-socfpga/core.h | 3 +++ arch/arm/mach-socfpga/platsmp.c | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h index 60c443dadb58..483cb467bf65 100644 --- a/arch/arm/mach-socfpga/core.h +++ b/arch/arm/mach-socfpga/core.h @@ -21,6 +21,7 @@ #define __MACH_CORE_H #define SOCFPGA_RSTMGR_CTRL 0x04 +#define SOCFPGA_RSTMGR_MODMPURST 0x10 #define SOCFPGA_RSTMGR_MODPERRST 0x14 #define SOCFPGA_RSTMGR_BRGMODRST 0x1c @@ -28,6 +29,8 @@ #define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */ #define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */ +#define RSTMGR_MPUMODRST_CPU1 0x2 /* CPU1 Reset */ + extern void socfpga_secondary_startup(void); extern void __iomem *socfpga_scu_base_addr; diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c index 16ca97b039f9..c64d89b7c0ca 100644 --- a/arch/arm/mach-socfpga/platsmp.c +++ b/arch/arm/mach-socfpga/platsmp.c @@ -34,17 +34,21 @@ static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle) int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; if (socfpga_cpu1start_addr) { + /* This will put CPU #1 into reset. */ + writel(RSTMGR_MPUMODRST_CPU1, + rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST); + memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); - __raw_writel(virt_to_phys(socfpga_secondary_startup), - (sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff))); + writel(virt_to_phys(socfpga_secondary_startup), + sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff)); flush_cache_all(); smp_wmb(); outer_clean_range(0, trampoline_size); - /* This will release CPU #1 out of reset.*/ - __raw_writel(0, rst_manager_base_addr + 0x10); + /* This will release CPU #1 out of reset. */ + writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST); } return 0; @@ -86,10 +90,9 @@ static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus) */ static void socfpga_cpu_die(unsigned int cpu) { - cpu_do_idle(); - - /* We should have never returned from idle */ - panic("cpu %d unexpectedly exit from shutdown\n", cpu); + /* Do WFI. If we wake up early, go back into WFI */ + while (1) + cpu_do_idle(); } struct smp_operations socfpga_smp_ops __initdata = { -- cgit v1.2.3-59-g8ed1b From 140bd60383309e82b5cae3294a907c11a0a12b90 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 14 Sep 2014 21:43:40 +0200 Subject: ARM: BCM5301X: fix early serial console This device actually has a 8250 serial with a shift of 0. Tested this on a BCM4708. Signed-off-by: Hauke Mehrtens Signed-off-by: Arnd Bergmann --- arch/arm/Kconfig.debug | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 1c4889dbc714..a52884351e4f 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -113,7 +113,7 @@ choice config DEBUG_BCM_5301X bool "Kernel low-level debugging on BCM5301X UART1" depends on ARCH_BCM_5301X - select DEBUG_UART_PL01X + select DEBUG_UART_8250 config DEBUG_BCM_KONA_UART bool "Kernel low-level debugging messages via BCM KONA UART" @@ -1301,7 +1301,7 @@ config DEBUG_UART_VIRT config DEBUG_UART_8250_SHIFT int "Register offset shift for the 8250 debug UART" depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250 - default 0 if FOOTBRIDGE || ARCH_IOP32X + default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X default 2 config DEBUG_UART_8250_WORD -- cgit v1.2.3-59-g8ed1b From c0adae9e51ab88293d6cc729c46fdb4365bf77f5 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 7 Nov 2014 08:20:09 +0900 Subject: ARM: EXYNOS: Add support for exynos4415 SoC This patch adds support for Exynos4415 SoC. Exynos4415 is based on the 32-bit RISC processor for Smartphone. Exynos4415 has Cortex A9 quad-cores and has a target speed of 1.6GHz and provides 8.5GB/s memory bandwidth. Signed-off-by: Chanwoo Choi Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/Kconfig | 5 +++++ arch/arm/mach-exynos/exynos.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 46f3c0d0d01f..349c86708298 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -75,6 +75,11 @@ config SOC_EXYNOS4412 default y depends on ARCH_EXYNOS4 +config SOC_EXYNOS4415 + bool "SAMSUNG EXYNOS4415" + default y + depends on ARCH_EXYNOS4 + config SOC_EXYNOS5250 bool "SAMSUNG EXYNOS5250" default y diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index a487e59555da..6dc332fa55db 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -252,6 +252,7 @@ static const struct of_device_id exynos_dt_pmu_match[] = { { .compatible = "samsung,exynos4210-pmu" }, { .compatible = "samsung,exynos4212-pmu" }, { .compatible = "samsung,exynos4412-pmu" }, + { .compatible = "samsung,exynos4415-pmu" }, { .compatible = "samsung,exynos5250-pmu" }, { .compatible = "samsung,exynos5260-pmu" }, { .compatible = "samsung,exynos5410-pmu" }, @@ -336,6 +337,7 @@ static char const *exynos_dt_compat[] __initconst = { "samsung,exynos4210", "samsung,exynos4212", "samsung,exynos4412", + "samsung,exynos4415", "samsung,exynos5", "samsung,exynos5250", "samsung,exynos5260", -- cgit v1.2.3-59-g8ed1b From 14fc8b93d47323561edf5d482d4a4b3ee1b90286 Mon Sep 17 00:00:00 2001 From: Pankaj Dubey Date: Fri, 7 Nov 2014 09:26:40 +0900 Subject: ARM: EXYNOS: Add platform driver support for Exynos PMU This patch modifies Exynos Power Management Unit (PMU) initialization implementation in following way: - Added platform driver support for Exynos PMU IP. - Added platform struct exynos_pmu_data to hold platform specific data. - For each SoC's PMU support now we can add platform data and statically bind PMU configuration and SoC specific initialization function. - Separate each SoC's PMU initialization function and make it as part of platform data. - It also removes uses of soc_is_exynosXYZ(). Signed-off-by: Pankaj Dubey Reviewed-by: Tomasz Figa Tested-by: Javier Martinez Canillas Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/Kconfig | 1 + arch/arm/mach-exynos/pmu.c | 171 ++++++++++++++++++++++++++++++++----------- 2 files changed, 130 insertions(+), 42 deletions(-) diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 349c86708298..b9e3f1c61baf 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -24,6 +24,7 @@ menuconfig ARCH_EXYNOS select PM_GENERIC_DOMAINS if PM_RUNTIME select S5P_DEV_MFC select SRAM + select MFD_SYSCON help Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5) diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index e5e1846f10c9..24cd4c471c47 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * EXYNOS - CPU PMU(Power Management Unit) support @@ -10,12 +10,26 @@ */ #include -#include +#include +#include #include "common.h" #include "regs-pmu.h" -static const struct exynos_pmu_conf *exynos_pmu_config; +struct exynos_pmu_data { + const struct exynos_pmu_conf *pmu_config; + const struct exynos_pmu_conf *pmu_config_extra; + + void (*pmu_init)(void); + void (*powerdown_conf)(enum sys_powerdown); +}; + +struct exynos_pmu_context { + struct device *dev; + const struct exynos_pmu_data *pmu_data; +}; + +static struct exynos_pmu_context *pmu_context; static const struct exynos_pmu_conf exynos4210_pmu_config[] = { /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ @@ -336,7 +350,7 @@ static unsigned int const exynos5_list_disable_wfi_wfe[] = { EXYNOS5_ISP_ARM_OPTION, }; -static void exynos5_init_pmu(void) +static void exynos5_powerdown_conf(enum sys_powerdown mode) { unsigned int i; unsigned int tmp; @@ -344,7 +358,7 @@ static void exynos5_init_pmu(void) /* * Enable both SC_FEEDBACK and SC_COUNTER */ - for (i = 0 ; i < ARRAY_SIZE(exynos5_list_both_cnt_feed) ; i++) { + for (i = 0; i < ARRAY_SIZE(exynos5_list_both_cnt_feed); i++) { tmp = pmu_raw_readl(exynos5_list_both_cnt_feed[i]); tmp |= (EXYNOS5_USE_SC_FEEDBACK | EXYNOS5_USE_SC_COUNTER); @@ -361,7 +375,7 @@ static void exynos5_init_pmu(void) /* * Disable WFI/WFE on XXX_OPTION */ - for (i = 0 ; i < ARRAY_SIZE(exynos5_list_disable_wfi_wfe) ; i++) { + for (i = 0; i < ARRAY_SIZE(exynos5_list_disable_wfi_wfe); i++) { tmp = pmu_raw_readl(exynos5_list_disable_wfi_wfe[i]); tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE | EXYNOS5_OPTION_USE_STANDBYWFI); @@ -373,51 +387,124 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode) { unsigned int i; - if (soc_is_exynos5250()) - exynos5_init_pmu(); + const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data; - for (i = 0; (exynos_pmu_config[i].offset != PMU_TABLE_END) ; i++) - pmu_raw_writel(exynos_pmu_config[i].val[mode], - exynos_pmu_config[i].offset); + if (pmu_data->powerdown_conf) + pmu_data->powerdown_conf(mode); - if (soc_is_exynos4412()) { - for (i = 0; exynos4412_pmu_config[i].offset != PMU_TABLE_END ; i++) - pmu_raw_writel(exynos4412_pmu_config[i].val[mode], - exynos4412_pmu_config[i].offset); + if (pmu_data->pmu_config) { + for (i = 0; (pmu_data->pmu_config[i].offset != PMU_TABLE_END); i++) + pmu_raw_writel(pmu_data->pmu_config[i].val[mode], + pmu_data->pmu_config[i].offset); + } + + if (pmu_data->pmu_config_extra) { + for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++) + pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode], + pmu_data->pmu_config_extra[i].offset); } } -static int __init exynos_pmu_init(void) +static void exynos5250_pmu_init(void) { unsigned int value; + /* + * When SYS_WDTRESET is set, watchdog timer reset request + * is ignored by power management unit. + */ + value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE); + value &= ~EXYNOS5_SYS_WDTRESET; + pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE); + + value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST); + value &= ~EXYNOS5_SYS_WDTRESET; + pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); +} + +static const struct exynos_pmu_data exynos4210_pmu_data = { + .pmu_config = exynos4210_pmu_config, +}; + +static const struct exynos_pmu_data exynos4212_pmu_data = { + .pmu_config = exynos4x12_pmu_config, +}; + +static const struct exynos_pmu_data exynos4412_pmu_data = { + .pmu_config = exynos4x12_pmu_config, + .pmu_config_extra = exynos4412_pmu_config, +}; + +static const struct exynos_pmu_data exynos5250_pmu_data = { + .pmu_config = exynos5250_pmu_config, + .pmu_init = exynos5250_pmu_init, + .powerdown_conf = exynos5_powerdown_conf, +}; + +/* + * PMU platform driver and devicetree bindings. + */ +static const struct of_device_id exynos_pmu_of_device_ids[] = { + { + .compatible = "samsung,exynos4210-pmu", + .data = &exynos4210_pmu_data, + }, { + .compatible = "samsung,exynos4212-pmu", + .data = &exynos4212_pmu_data, + }, { + .compatible = "samsung,exynos4412-pmu", + .data = &exynos4412_pmu_data, + }, { + .compatible = "samsung,exynos5250-pmu", + .data = &exynos5250_pmu_data, + }, + { /*sentinel*/ }, +}; - exynos_pmu_config = exynos4210_pmu_config; - - if (soc_is_exynos4210()) { - exynos_pmu_config = exynos4210_pmu_config; - pr_info("EXYNOS4210 PMU Initialize\n"); - } else if (soc_is_exynos4212() || soc_is_exynos4412()) { - exynos_pmu_config = exynos4x12_pmu_config; - pr_info("EXYNOS4x12 PMU Initialize\n"); - } else if (soc_is_exynos5250()) { - /* - * When SYS_WDTRESET is set, watchdog timer reset request - * is ignored by power management unit. - */ - value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE); - value &= ~EXYNOS5_SYS_WDTRESET; - pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE); - - value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST); - value &= ~EXYNOS5_SYS_WDTRESET; - pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); - - exynos_pmu_config = exynos5250_pmu_config; - pr_info("EXYNOS5250 PMU Initialize\n"); - } else { - pr_info("EXYNOS: PMU not supported\n"); +static int exynos_pmu_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device *dev = &pdev->dev; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pmu_base_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(pmu_base_addr)) + return PTR_ERR(pmu_base_addr); + + pmu_context = devm_kzalloc(&pdev->dev, + sizeof(struct exynos_pmu_context), + GFP_KERNEL); + if (!pmu_context) { + dev_err(dev, "Cannot allocate memory.\n"); + return -ENOMEM; } + pmu_context->dev = dev; + + match = of_match_node(exynos_pmu_of_device_ids, dev->of_node); + + pmu_context->pmu_data = match->data; + if (pmu_context->pmu_data->pmu_init) + pmu_context->pmu_data->pmu_init(); + + platform_set_drvdata(pdev, pmu_context); + + dev_dbg(dev, "Exynos PMU Driver probe done\n"); return 0; } -arch_initcall(exynos_pmu_init); + +static struct platform_driver exynos_pmu_driver = { + .driver = { + .name = "exynos-pmu", + .owner = THIS_MODULE, + .of_match_table = exynos_pmu_of_device_ids, + }, + .probe = exynos_pmu_probe, +}; + +static int __init exynos_pmu_init(void) +{ + return platform_driver_register(&exynos_pmu_driver); + +} +postcore_initcall(exynos_pmu_init); -- cgit v1.2.3-59-g8ed1b From 6b7bfd8292ab27180662bcba175e7a3822486c2d Mon Sep 17 00:00:00 2001 From: Pankaj Dubey Date: Fri, 7 Nov 2014 09:26:47 +0900 Subject: ARM: EXYNOS: Move PMU specific definitions from common.h This patch moves PMU specific definitions into a new file as exynos-pmu.h. This will help in reducing dependency of common.h in pmu.c. Signed-off-by: Pankaj Dubey Reviewed-by: Tomasz Figa Tested-by: Javier Martinez Canillas Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/common.h | 17 ----------------- arch/arm/mach-exynos/exynos-pmu.h | 24 ++++++++++++++++++++++++ arch/arm/mach-exynos/pm.c | 1 + arch/arm/mach-exynos/pmu.c | 20 +++++++++++++++++++- arch/arm/mach-exynos/suspend.c | 1 + 5 files changed, 45 insertions(+), 18 deletions(-) create mode 100644 arch/arm/mach-exynos/exynos-pmu.h diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index d4d09bc1e48c..431be1bca2e8 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -139,23 +139,6 @@ extern void exynos_cpu_resume_ns(void); extern struct smp_operations exynos_smp_ops; -/* PMU(Power Management Unit) support */ - -#define PMU_TABLE_END (-1U) - -enum sys_powerdown { - SYS_AFTR, - SYS_LPA, - SYS_SLEEP, - NUM_SYS_POWERDOWN, -}; - -struct exynos_pmu_conf { - unsigned int offset; - unsigned int val[NUM_SYS_POWERDOWN]; -}; - -extern void exynos_sys_powerdown_conf(enum sys_powerdown mode); extern void exynos_cpu_power_down(int cpu); extern void exynos_cpu_power_up(int cpu); extern int exynos_cpu_power_state(int cpu); diff --git a/arch/arm/mach-exynos/exynos-pmu.h b/arch/arm/mach-exynos/exynos-pmu.h new file mode 100644 index 000000000000..a2ab0d52b230 --- /dev/null +++ b/arch/arm/mach-exynos/exynos-pmu.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Header for EXYNOS PMU Driver support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __EXYNOS_PMU_H +#define __EXYNOS_PMU_H + +enum sys_powerdown { + SYS_AFTR, + SYS_LPA, + SYS_SLEEP, + NUM_SYS_POWERDOWN, +}; + +extern void exynos_sys_powerdown_conf(enum sys_powerdown mode); + +#endif /* __EXYNOS_PMU_H */ diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 4f10fa6bfe10..86f3ecd88f78 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -26,6 +26,7 @@ #include #include "common.h" +#include "exynos-pmu.h" #include "regs-pmu.h" #include "regs-sys.h" diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index 24cd4c471c47..88d3f793e267 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -13,9 +13,16 @@ #include #include -#include "common.h" +#include "exynos-pmu.h" #include "regs-pmu.h" +#define PMU_TABLE_END (-1U) + +struct exynos_pmu_conf { + unsigned int offset; + unsigned int val[NUM_SYS_POWERDOWN]; +}; + struct exynos_pmu_data { const struct exynos_pmu_conf *pmu_config; const struct exynos_pmu_conf *pmu_config_extra; @@ -29,8 +36,19 @@ struct exynos_pmu_context { const struct exynos_pmu_data *pmu_data; }; +static void __iomem *pmu_base_addr; static struct exynos_pmu_context *pmu_context; +static inline void pmu_raw_writel(u32 val, u32 offset) +{ + writel_relaxed(val, pmu_base_addr + offset); +} + +static inline u32 pmu_raw_readl(u32 offset) +{ + return readl_relaxed(pmu_base_addr + offset); +} + static const struct exynos_pmu_conf exynos4210_pmu_config[] = { /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ { S5P_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } }, diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index f5d9773066eb..079d999b8b23 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -33,6 +33,7 @@ #include "common.h" #include "regs-pmu.h" #include "regs-sys.h" +#include "exynos-pmu.h" #define S5P_CHECK_SLEEP 0x00000BAD -- cgit v1.2.3-59-g8ed1b From af2e0a0754accf2276d58d6dfaa15563133130aa Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Fri, 7 Nov 2014 09:27:33 +0900 Subject: ARM: EXYNOS: Add PMU support for exynos5420 Adds initial PMU settings for exynos5420. This is required for future S2R and Switching support. Signed-off-by: Thomas Abraham Signed-off-by: Abhilash Kesavan Signed-off-by: Vikas Sajjan Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pmu.c | 287 ++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-exynos/regs-pmu.h | 227 +++++++++++++++++++++++++++++++ 2 files changed, 514 insertions(+) diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index 88d3f793e267..6c8a76dd5494 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -12,6 +12,8 @@ #include #include #include +#include + #include "exynos-pmu.h" #include "regs-pmu.h" @@ -348,6 +350,151 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = { { PMU_TABLE_END,}, }; +static struct exynos_pmu_conf exynos5420_pmu_config[] = { + /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ + { EXYNOS5_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_ARM_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_ARM_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS5_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS5_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x0} }, + { EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS5_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} }, + { EXYNOS5420_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} }, + { EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_GSCL_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_DISP1_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_MAU_SYS_PWR_REG, { 0x7, 0x7, 0x0} }, + { EXYNOS5420_G2D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_MSC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_FSYS_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_FSYS2_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_PSGEN_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_PERIC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_WCORE_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { PMU_TABLE_END,}, +}; + static unsigned int const exynos5_list_both_cnt_feed[] = { EXYNOS5_ARM_CORE0_OPTION, EXYNOS5_ARM_CORE1_OPTION, @@ -368,6 +515,75 @@ static unsigned int const exynos5_list_disable_wfi_wfe[] = { EXYNOS5_ISP_ARM_OPTION, }; +static unsigned int const exynos5420_list_disable_pmu_reg[] = { + EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, + EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, + EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG, + EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, + EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, + EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG, + EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, + EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, + EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG, +}; + +static void exynos5_power_off(void) +{ + unsigned int tmp; + + pr_info("Power down.\n"); + tmp = pmu_raw_readl(EXYNOS_PS_HOLD_CONTROL); + tmp ^= (1 << 8); + pmu_raw_writel(tmp, EXYNOS_PS_HOLD_CONTROL); + + /* Wait a little so we don't give a false warning below */ + mdelay(100); + + pr_err("Power down failed, please power off system manually.\n"); + while (1) + ; +} + +void exynos5420_powerdown_conf(enum sys_powerdown mode) +{ + u32 this_cluster; + + this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); + + /* + * set the cluster id to IROM register to ensure that we wake + * up with the current cluster. + */ + pmu_raw_writel(this_cluster, EXYNOS_IROM_DATA2); +} + + static void exynos5_powerdown_conf(enum sys_powerdown mode) { unsigned int i; @@ -439,6 +655,68 @@ static void exynos5250_pmu_init(void) pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); } +static void exynos5420_pmu_init(void) +{ + unsigned int value; + int i; + + /* + * Set the CMU_RESET, CMU_SYSCLK and CMU_CLKSTOP registers + * for local power blocks to Low initially as per Table 8-4: + * "System-Level Power-Down Configuration Registers". + */ + for (i = 0; i < ARRAY_SIZE(exynos5420_list_disable_pmu_reg); i++) + pmu_raw_writel(0, exynos5420_list_disable_pmu_reg[i]); + + /* Enable USE_STANDBY_WFI for all CORE */ + pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); + + value = pmu_raw_readl(EXYNOS_L2_OPTION(0)); + value &= ~EXYNOS5_USE_RETENTION; + pmu_raw_writel(value, EXYNOS_L2_OPTION(0)); + + value = pmu_raw_readl(EXYNOS_L2_OPTION(1)); + value &= ~EXYNOS5_USE_RETENTION; + pmu_raw_writel(value, EXYNOS_L2_OPTION(1)); + + /* + * If L2_COMMON is turned off, clocks related to ATB async + * bridge are gated. Thus, when ISP power is gated, LPI + * may get stuck. + */ + value = pmu_raw_readl(EXYNOS5420_LPI_MASK); + value |= EXYNOS5420_ATB_ISP_ARM; + pmu_raw_writel(value, EXYNOS5420_LPI_MASK); + + value = pmu_raw_readl(EXYNOS5420_LPI_MASK1); + value |= EXYNOS5420_ATB_KFC; + pmu_raw_writel(value, EXYNOS5420_LPI_MASK1); + + /* Prevent issue of new bus request from L2 memory */ + value = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); + value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; + pmu_raw_writel(value, EXYNOS5420_ARM_COMMON_OPTION); + + value = pmu_raw_readl(EXYNOS5420_KFC_COMMON_OPTION); + value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; + pmu_raw_writel(value, EXYNOS5420_KFC_COMMON_OPTION); + + /* This setting is to reduce suspend/resume time */ + pmu_raw_writel(DUR_WAIT_RESET, EXYNOS5420_LOGIC_RESET_DURATION3); + + /* Serialized CPU wakeup of Eagle */ + pmu_raw_writel(SPREAD_ENABLE, EXYNOS5420_ARM_INTR_SPREAD_ENABLE); + + pmu_raw_writel(SPREAD_USE_STANDWFI, + EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI); + + pmu_raw_writel(0x1, EXYNOS5420_UP_SCHEDULER); + + pm_power_off = exynos5_power_off; + pr_info("EXYNOS5420 PMU initialized\n"); +} + + static const struct exynos_pmu_data exynos4210_pmu_data = { .pmu_config = exynos4210_pmu_config, }; @@ -458,6 +736,12 @@ static const struct exynos_pmu_data exynos5250_pmu_data = { .powerdown_conf = exynos5_powerdown_conf, }; +static struct exynos_pmu_data exynos5420_pmu_data = { + .pmu_config = exynos5420_pmu_config, + .pmu_init = exynos5420_pmu_init, + .powerdown_conf = exynos5420_powerdown_conf, +}; + /* * PMU platform driver and devicetree bindings. */ @@ -474,6 +758,9 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = { }, { .compatible = "samsung,exynos5250-pmu", .data = &exynos5250_pmu_data, + }, { + .compatible = "samsung,exynos5420-pmu", + .data = &exynos5420_pmu_data, }, { /*sentinel*/ }, }; diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 322f13277c3b..46b973b8cd83 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -38,6 +38,7 @@ #define S5P_INFORM7 0x081C #define S5P_PMU_SPARE3 0x090C +#define EXYNOS_IROM_DATA2 0x0988 #define S5P_ARM_CORE0_LOWPWR 0x1000 #define S5P_DIS_IRQ_CORE0 0x1004 #define S5P_DIS_IRQ_CENTRAL0 0x1008 @@ -120,6 +121,31 @@ #define EXYNOS_COMMON_OPTION(_nr) \ (EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8) +#define EXYNOS_CORE_LOCAL_PWR_EN 0x3 + +#define EXYNOS_ARM_COMMON_STATUS 0x2504 +#define EXYNOS_COMMON_OPTION(_nr) \ + (EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8) + +#define EXYNOS_ARM_L2_CONFIGURATION 0x2600 +#define EXYNOS_L2_CONFIGURATION(_nr) \ + (EXYNOS_ARM_L2_CONFIGURATION + ((_nr) * 0x80)) +#define EXYNOS_L2_STATUS(_nr) \ + (EXYNOS_L2_CONFIGURATION(_nr) + 0x4) +#define EXYNOS_L2_OPTION(_nr) \ + (EXYNOS_L2_CONFIGURATION(_nr) + 0x8) +#define EXYNOS_L2_COMMON_PWR_EN 0x3 + +#define EXYNOS_ARM_CORE_X_STATUS_OFFSET 0x4 + +#define EXYNOS5_APLL_SYSCLK_CONFIGURATION 0x2A00 +#define EXYNOS5_APLL_SYSCLK_STATUS 0x2A04 + +#define EXYNOS5_ARM_L2_OPTION 0x2608 +#define EXYNOS5_USE_RETENTION BIT(4) + +#define EXYNOS5_L2RSTDISABLE_VALUE BIT(3) + #define S5P_PAD_RET_MAUDIO_OPTION 0x3028 #define S5P_PAD_RET_GPIO_OPTION 0x3108 #define S5P_PAD_RET_UART_OPTION 0x3128 @@ -193,6 +219,7 @@ #define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408 #define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C +#define EXYNOS5_USE_RETENTION BIT(4) #define EXYNOS5_SYS_WDTRESET (1 << 20) #define EXYNOS5_ARM_CORE0_SYS_PWR_REG 0x1000 @@ -332,4 +359,204 @@ static inline unsigned int exynos_pmu_cpunr(unsigned int mpidr) + MPIDR_AFFINITY_LEVEL(mpidr, 0)); } +/* Only for EXYNOS5420 */ +#define EXYNOS5420_ISP_ARM_OPTION 0x2488 +#define EXYNOS5420_L2RSTDISABLE_VALUE BIT(3) + +#define EXYNOS5420_LPI_MASK 0x0004 +#define EXYNOS5420_LPI_MASK1 0x0008 +#define EXYNOS5420_UFS BIT(8) +#define EXYNOS5420_ATB_KFC BIT(13) +#define EXYNOS5420_ATB_ISP_ARM BIT(19) +#define EXYNOS5420_EMULATION BIT(31) +#define ATB_ISP_ARM BIT(12) +#define ATB_KFC BIT(13) +#define ATB_NOC BIT(14) + +#define EXYNOS5420_ARM_INTR_SPREAD_ENABLE 0x0100 +#define EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI 0x0104 +#define EXYNOS5420_UP_SCHEDULER 0x0120 +#define SPREAD_ENABLE 0xF +#define SPREAD_USE_STANDWFI 0xF + +#define EXYNOS5420_BB_CON1 0x0784 +#define EXYNOS5420_BB_SEL_EN BIT(31) +#define EXYNOS5420_BB_PMOS_EN BIT(7) +#define EXYNOS5420_BB_1300X 0XF + +#define EXYNOS5420_ARM_CORE2_SYS_PWR_REG 0x1020 +#define EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG 0x1024 +#define EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG 0x1028 +#define EXYNOS5420_ARM_CORE3_SYS_PWR_REG 0x1030 +#define EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG 0x1034 +#define EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG 0x1038 +#define EXYNOS5420_KFC_CORE0_SYS_PWR_REG 0x1040 +#define EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG 0x1044 +#define EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG 0x1048 +#define EXYNOS5420_KFC_CORE1_SYS_PWR_REG 0x1050 +#define EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG 0x1054 +#define EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG 0x1058 +#define EXYNOS5420_KFC_CORE2_SYS_PWR_REG 0x1060 +#define EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG 0x1064 +#define EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG 0x1068 +#define EXYNOS5420_KFC_CORE3_SYS_PWR_REG 0x1070 +#define EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG 0x1074 +#define EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG 0x1078 +#define EXYNOS5420_ISP_ARM_SYS_PWR_REG 0x1090 +#define EXYNOS5420_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1094 +#define EXYNOS5420_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1098 +#define EXYNOS5420_ARM_COMMON_SYS_PWR_REG 0x10A0 +#define EXYNOS5420_KFC_COMMON_SYS_PWR_REG 0x10B0 +#define EXYNOS5420_KFC_L2_SYS_PWR_REG 0x10D0 +#define EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG 0x1158 +#define EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG 0x115C +#define EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG 0x1160 +#define EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG 0x1174 +#define EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG 0x1178 +#define EXYNOS5420_INTRAM_MEM_SYS_PWR_REG 0x11B8 +#define EXYNOS5420_INTROM_MEM_SYS_PWR_REG 0x11BC +#define EXYNOS5420_ONENANDXL_MEM_SYS_PWR 0x11C0 +#define EXYNOS5420_USBDEV_MEM_SYS_PWR 0x11CC +#define EXYNOS5420_USBDEV1_MEM_SYS_PWR 0x11D0 +#define EXYNOS5420_SDMMC_MEM_SYS_PWR 0x11D4 +#define EXYNOS5420_CSSYS_MEM_SYS_PWR 0x11D8 +#define EXYNOS5420_SECSS_MEM_SYS_PWR 0x11DC +#define EXYNOS5420_ROTATOR_MEM_SYS_PWR 0x11E0 +#define EXYNOS5420_INTRAM_MEM_SYS_PWR 0x11E4 +#define EXYNOS5420_INTROM_MEM_SYS_PWR 0x11E8 +#define EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1208 +#define EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1210 +#define EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG 0x1214 +#define EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1218 +#define EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG 0x121C +#define EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1220 +#define EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG 0x1224 +#define EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1228 +#define EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG 0x122C +#define EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG 0x1230 +#define EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG 0x1234 +#define EXYNOS5420_DISP1_SYS_PWR_REG 0x1410 +#define EXYNOS5420_MAU_SYS_PWR_REG 0x1414 +#define EXYNOS5420_G2D_SYS_PWR_REG 0x1418 +#define EXYNOS5420_MSC_SYS_PWR_REG 0x141C +#define EXYNOS5420_FSYS_SYS_PWR_REG 0x1420 +#define EXYNOS5420_FSYS2_SYS_PWR_REG 0x1424 +#define EXYNOS5420_PSGEN_SYS_PWR_REG 0x1428 +#define EXYNOS5420_PERIC_SYS_PWR_REG 0x142C +#define EXYNOS5420_WCORE_SYS_PWR_REG 0x1430 +#define EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG 0x1490 +#define EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG 0x1494 +#define EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG 0x1498 +#define EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG 0x149C +#define EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG 0x14A0 +#define EXYNOS5420_CMU_CLKSTOP_FSYS2_SYS_PWR_REG 0x14A4 +#define EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG 0x14A8 +#define EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG 0x14AC +#define EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG 0x14B0 +#define EXYNOS5420_CMU_SYSCLK_TOPPWR_SYS_PWR_REG 0x14BC +#define EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG 0x14D0 +#define EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG 0x14D4 +#define EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG 0x14D8 +#define EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG 0x14DC +#define EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG 0x14E0 +#define EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG 0x14E4 +#define EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG 0x14E8 +#define EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG 0x14EC +#define EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG 0x14F0 +#define EXYNOS5420_CMU_SYSCLK_SYSMEM_TOPPWR_SYS_PWR_REG 0x14F4 +#define EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG 0x1570 +#define EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG 0x1574 +#define EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG 0x1578 +#define EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG 0x157C +#define EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG 0x1590 +#define EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG 0x1594 +#define EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG 0x1598 +#define EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG 0x159C +#define EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG 0x15A0 +#define EXYNOS5420_SFR_AXI_CGDIS1 0x15E4 +#define EXYNOS_ARM_CORE2_CONFIGURATION 0x2100 +#define EXYNOS5420_ARM_CORE2_OPTION 0x2108 +#define EXYNOS_ARM_CORE3_CONFIGURATION 0x2180 +#define EXYNOS5420_ARM_CORE3_OPTION 0x2188 +#define EXYNOS5420_ARM_COMMON_STATUS 0x2504 +#define EXYNOS5420_ARM_COMMON_OPTION 0x2508 +#define EXYNOS5420_KFC_COMMON_STATUS 0x2584 +#define EXYNOS5420_KFC_COMMON_OPTION 0x2588 +#define EXYNOS5420_LOGIC_RESET_DURATION3 0x2D1C + +#define EXYNOS5420_PAD_RET_GPIO_OPTION 0x30C8 +#define EXYNOS5420_PAD_RET_UART_OPTION 0x30E8 +#define EXYNOS5420_PAD_RET_MMCA_OPTION 0x3108 +#define EXYNOS5420_PAD_RET_MMCB_OPTION 0x3128 +#define EXYNOS5420_PAD_RET_MMCC_OPTION 0x3148 +#define EXYNOS5420_PAD_RET_HSI_OPTION 0x3168 +#define EXYNOS5420_PAD_RET_SPI_OPTION 0x31C8 +#define EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION 0x31E8 +#define EXYNOS_PAD_RET_DRAM_OPTION 0x3008 +#define EXYNOS_PAD_RET_MAUDIO_OPTION 0x3028 +#define EXYNOS_PAD_RET_JTAG_OPTION 0x3048 +#define EXYNOS_PAD_RET_GPIO_OPTION 0x3108 +#define EXYNOS_PAD_RET_UART_OPTION 0x3128 +#define EXYNOS_PAD_RET_MMCA_OPTION 0x3148 +#define EXYNOS_PAD_RET_MMCB_OPTION 0x3168 +#define EXYNOS_PAD_RET_EBIA_OPTION 0x3188 +#define EXYNOS_PAD_RET_EBIB_OPTION 0x31A8 + +#define EXYNOS_PS_HOLD_CONTROL 0x330C + +/* For SYS_PWR_REG */ +#define EXYNOS_SYS_PWR_CFG BIT(0) + +#define EXYNOS5420_MFC_CONFIGURATION 0x4060 +#define EXYNOS5420_MFC_STATUS 0x4064 +#define EXYNOS5420_MFC_OPTION 0x4068 +#define EXYNOS5420_G3D_CONFIGURATION 0x4080 +#define EXYNOS5420_G3D_STATUS 0x4084 +#define EXYNOS5420_G3D_OPTION 0x4088 +#define EXYNOS5420_DISP0_CONFIGURATION 0x40A0 +#define EXYNOS5420_DISP0_STATUS 0x40A4 +#define EXYNOS5420_DISP0_OPTION 0x40A8 +#define EXYNOS5420_DISP1_CONFIGURATION 0x40C0 +#define EXYNOS5420_DISP1_STATUS 0x40C4 +#define EXYNOS5420_DISP1_OPTION 0x40C8 +#define EXYNOS5420_MAU_CONFIGURATION 0x40E0 +#define EXYNOS5420_MAU_STATUS 0x40E4 +#define EXYNOS5420_MAU_OPTION 0x40E8 +#define EXYNOS5420_FSYS2_OPTION 0x4168 +#define EXYNOS5420_PSGEN_OPTION 0x4188 + +/* For EXYNOS_CENTRAL_SEQ_OPTION */ +#define EXYNOS5_USE_STANDBYWFI_ARM_CORE0 BIT(16) +#define EXYNOS5_USE_STANDBYWFI_ARM_CORE1 BUT(17) +#define EXYNOS5_USE_STANDBYWFE_ARM_CORE0 BIT(24) +#define EXYNOS5_USE_STANDBYWFE_ARM_CORE1 BIT(25) + +#define EXYNOS5420_ARM_USE_STANDBY_WFI0 BIT(4) +#define EXYNOS5420_ARM_USE_STANDBY_WFI1 BIT(5) +#define EXYNOS5420_ARM_USE_STANDBY_WFI2 BIT(6) +#define EXYNOS5420_ARM_USE_STANDBY_WFI3 BIT(7) +#define EXYNOS5420_KFC_USE_STANDBY_WFI0 BIT(8) +#define EXYNOS5420_KFC_USE_STANDBY_WFI1 BIT(9) +#define EXYNOS5420_KFC_USE_STANDBY_WFI2 BIT(10) +#define EXYNOS5420_KFC_USE_STANDBY_WFI3 BIT(11) +#define EXYNOS5420_ARM_USE_STANDBY_WFE0 BIT(16) +#define EXYNOS5420_ARM_USE_STANDBY_WFE1 BIT(17) +#define EXYNOS5420_ARM_USE_STANDBY_WFE2 BIT(18) +#define EXYNOS5420_ARM_USE_STANDBY_WFE3 BIT(19) +#define EXYNOS5420_KFC_USE_STANDBY_WFE0 BIT(20) +#define EXYNOS5420_KFC_USE_STANDBY_WFE1 BIT(21) +#define EXYNOS5420_KFC_USE_STANDBY_WFE2 BIT(22) +#define EXYNOS5420_KFC_USE_STANDBY_WFE3 BIT(23) + +#define DUR_WAIT_RESET 0xF + +#define EXYNOS5420_USE_STANDBY_WFI_ALL (EXYNOS5420_ARM_USE_STANDBY_WFI0 \ + | EXYNOS5420_ARM_USE_STANDBY_WFI1 \ + | EXYNOS5420_ARM_USE_STANDBY_WFI2 \ + | EXYNOS5420_ARM_USE_STANDBY_WFI3 \ + | EXYNOS5420_KFC_USE_STANDBY_WFI0 \ + | EXYNOS5420_KFC_USE_STANDBY_WFI1 \ + | EXYNOS5420_KFC_USE_STANDBY_WFI2 \ + | EXYNOS5420_KFC_USE_STANDBY_WFI3) + #endif /* __ASM_ARCH_REGS_PMU_H */ -- cgit v1.2.3-59-g8ed1b From 0fdf088fd84d87d6fc5d3961cc86feb8bd295398 Mon Sep 17 00:00:00 2001 From: Vikas Sajjan Date: Fri, 7 Nov 2014 09:17:36 +0900 Subject: ARM: EXYNOS: Add Suspend-to-RAM support for exynos5420 Adds Suspend-to-RAM support for EXYNOS5420 Signed-off-by: Vikas Sajjan Signed-off-by: Abhilash Kesavan Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/suspend.c | 151 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index 079d999b8b23..8cef6141c408 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -39,6 +39,8 @@ #define REG_TABLE_END (-1U) +#define EXYNOS5420_CPU_STATE 0x28 + /** * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping * @hwirq: Hardware IRQ signal of the GIC @@ -77,6 +79,9 @@ struct exynos_pm_data { struct exynos_pm_data *pm_data; +static int exynos5420_cpu_state; +static unsigned int exynos_pmu_spare3; + /* * GIC wake-up support */ @@ -106,6 +111,23 @@ unsigned int exynos_release_ret_regs[] = { REG_TABLE_END, }; +unsigned int exynos5420_release_ret_regs[] = { + EXYNOS_PAD_RET_DRAM_OPTION, + EXYNOS_PAD_RET_MAUDIO_OPTION, + EXYNOS_PAD_RET_JTAG_OPTION, + EXYNOS5420_PAD_RET_GPIO_OPTION, + EXYNOS5420_PAD_RET_UART_OPTION, + EXYNOS5420_PAD_RET_MMCA_OPTION, + EXYNOS5420_PAD_RET_MMCB_OPTION, + EXYNOS5420_PAD_RET_MMCC_OPTION, + EXYNOS5420_PAD_RET_HSI_OPTION, + EXYNOS_PAD_RET_EBIA_OPTION, + EXYNOS_PAD_RET_EBIB_OPTION, + EXYNOS5420_PAD_RET_SPI_OPTION, + EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION, + REG_TABLE_END, +}; + static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) { const struct exynos_wkup_irq *wkup_irq; @@ -136,11 +158,22 @@ static int exynos_cpu_do_idle(void) pr_info("Failed to suspend the system\n"); return 1; /* Aborting suspend */ } - -static int exynos_cpu_suspend(unsigned long arg) +static void exynos_flush_cache_all(void) { flush_cache_all(); outer_flush_all(); +} + +static int exynos_cpu_suspend(unsigned long arg) +{ + exynos_flush_cache_all(); + return exynos_cpu_do_idle(); +} + +static int exynos5420_cpu_suspend(unsigned long arg) +{ + exynos_flush_cache_all(); + __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE); return exynos_cpu_do_idle(); } @@ -175,6 +208,50 @@ static void exynos_pm_prepare(void) exynos_pm_enter_sleep_mode(); } +static void exynos5420_pm_prepare(void) +{ + unsigned int tmp; + + /* Set wake-up mask registers */ + exynos_pm_set_wakeup_mask(); + + s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + + exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3); + /* + * The cpu state needs to be saved and restored so that the + * secondary CPUs will enter low power start. Though the U-Boot + * is setting the cpu state with low power flag, the kernel + * needs to restore it back in case, the primary cpu fails to + * suspend for any reason. + */ + exynos5420_cpu_state = __raw_readl(sysram_base_addr + + EXYNOS5420_CPU_STATE); + + exynos_pm_enter_sleep_mode(); + + tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION); + tmp &= ~EXYNOS5_USE_RETENTION; + pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION); + + tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); + tmp |= EXYNOS5420_UFS; + pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); + + tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); + tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE; + pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION); + + tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); + tmp |= EXYNOS5420_EMULATION; + pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); + + tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); + tmp |= EXYNOS5420_EMULATION; + pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); +} + + static int exynos_pm_suspend(void) { exynos_pm_central_suspend(); @@ -185,6 +262,24 @@ static int exynos_pm_suspend(void) return 0; } +static int exynos5420_pm_suspend(void) +{ + u32 this_cluster; + + exynos_pm_central_suspend(); + + /* Setting SEQ_OPTION register */ + + this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); + if (!this_cluster) + pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0, + S5P_CENTRAL_SEQ_OPTION); + else + pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0, + S5P_CENTRAL_SEQ_OPTION); + return 0; +} + static void exynos_pm_release_retention(void) { unsigned int i; @@ -223,6 +318,45 @@ early_wakeup: pmu_raw_writel(0x0, S5P_INFORM1); } +static void exynos5420_pm_resume(void) +{ + unsigned long tmp; + + /* Restore the sysram cpu state register */ + __raw_writel(exynos5420_cpu_state, + sysram_base_addr + EXYNOS5420_CPU_STATE); + + pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, + S5P_CENTRAL_SEQ_OPTION); + + if (exynos_pm_central_resume()) + goto early_wakeup; + + /* For release retention */ + exynos_pm_release_retention(); + + pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3); + + s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + +early_wakeup: + + tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); + tmp &= ~EXYNOS5420_UFS; + pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); + + tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); + tmp &= ~EXYNOS5420_EMULATION; + pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); + + tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); + tmp &= ~EXYNOS5420_EMULATION; + pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); + + /* Clear SLEEP mode set in INFORM1 */ + pmu_raw_writel(0x0, S5P_INFORM1); +} + /* * Suspend Ops */ @@ -310,6 +444,16 @@ static const struct exynos_pm_data exynos5250_pm_data = { .cpu_suspend = exynos_cpu_suspend, }; +static struct exynos_pm_data exynos5420_pm_data = { + .wkup_irq = exynos5250_wkup_irq, + .wake_disable_mask = (0x7F << 7) | (0x1F << 1), + .release_ret_regs = exynos5420_release_ret_regs, + .pm_resume = exynos5420_pm_resume, + .pm_suspend = exynos5420_pm_suspend, + .pm_prepare = exynos5420_pm_prepare, + .cpu_suspend = exynos5420_cpu_suspend, +}; + static struct of_device_id exynos_pmu_of_device_ids[] = { { .compatible = "samsung,exynos4210-pmu", @@ -323,6 +467,9 @@ static struct of_device_id exynos_pmu_of_device_ids[] = { }, { .compatible = "samsung,exynos5250-pmu", .data = &exynos5250_pm_data, + }, { + .compatible = "samsung,exynos5420-pmu", + .data = &exynos5420_pm_data, }, { /*sentinel*/ }, }; -- cgit v1.2.3-59-g8ed1b From adc548d77c22daa371d5217b382a139b593dec47 Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Fri, 7 Nov 2014 09:20:16 +0900 Subject: ARM: EXYNOS: Use MCPM call-backs to support S2R on exynos5420 Use the MCPM layer to handle core suspend/resume on Exynos5420. Also, restore the entry address setup code post-resume. Signed-off-by: Abhilash Kesavan Acked-by: Nicolas Pitre Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/mcpm-exynos.c | 32 +++++++++++++++++-------- arch/arm/mach-exynos/platsmp.c | 12 ++++++++++ arch/arm/mach-exynos/suspend.c | 49 ++++++++++++++++++++++++++++++++++---- 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c index dc9a764a7c37..b0d3c2e876fb 100644 --- a/arch/arm/mach-exynos/mcpm-exynos.c +++ b/arch/arm/mach-exynos/mcpm-exynos.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,8 @@ #define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29) #define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30) +static void __iomem *ns_sram_base_addr; + /* * The common v7_exit_coherency_flush API could not be used because of the * Erratum 799270 workaround. This macro is the same as the common one (in @@ -318,10 +321,26 @@ static const struct of_device_id exynos_dt_mcpm_match[] = { {}, }; +static void exynos_mcpm_setup_entry_point(void) +{ + /* + * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr + * as part of secondary_cpu_start(). Let's redirect it to the + * mcpm_entry_point(). This is done during both secondary boot-up as + * well as system resume. + */ + __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */ + __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */ + __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8); +} + +static struct syscore_ops exynos_mcpm_syscore_ops = { + .resume = exynos_mcpm_setup_entry_point, +}; + static int __init exynos_mcpm_init(void) { struct device_node *node; - void __iomem *ns_sram_base_addr; unsigned int value, i; int ret; @@ -387,16 +406,9 @@ static int __init exynos_mcpm_init(void) pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i)); } - /* - * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr - * as part of secondary_cpu_start(). Let's redirect it to the - * mcpm_entry_point(). - */ - __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */ - __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */ - __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8); + exynos_mcpm_setup_entry_point(); - iounmap(ns_sram_base_addr); + register_syscore_ops(&exynos_mcpm_syscore_ops); return ret; } diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index adb36a8e8785..7a1ebfeeeeb8 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -126,6 +126,18 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) */ void exynos_cpu_power_down(int cpu) { + if (cpu == 0 && (of_machine_is_compatible("samsung,exynos5420") || + of_machine_is_compatible("samsung,exynos5800"))) { + /* + * Bypass power down for CPU0 during suspend. Check for + * the SYS_PWR_REG value to decide if we are suspending + * the system. + */ + int val = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG); + + if (!(val & S5P_CORE_LOCAL_PWR_EN)) + return; + } pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu)); } diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index 8cef6141c408..cc8d2374f1b1 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,7 @@ struct exynos_pm_data { unsigned int *release_ret_regs; void (*pm_prepare)(void); + void (*pm_resume_prepare)(void); void (*pm_resume)(void); int (*pm_suspend)(void); int (*cpu_suspend)(unsigned long); @@ -172,9 +174,28 @@ static int exynos_cpu_suspend(unsigned long arg) static int exynos5420_cpu_suspend(unsigned long arg) { - exynos_flush_cache_all(); + /* MCPM works with HW CPU identifiers */ + unsigned int mpidr = read_cpuid_mpidr(); + unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE); - return exynos_cpu_do_idle(); + + if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) { + mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume); + + /* + * Residency value passed to mcpm_cpu_suspend back-end + * has to be given clear semantics. Set to 0 as a + * temporary value. + */ + mcpm_cpu_suspend(0); + } + + pr_info("Failed to suspend the system\n"); + + /* return value != 0 means failure */ + return 1; } static void exynos_pm_set_wakeup_mask(void) @@ -189,9 +210,6 @@ static void exynos_pm_enter_sleep_mode(void) /* Set value of power down register for sleep mode */ exynos_sys_powerdown_conf(SYS_SLEEP); pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); - - /* ensure at least INFORM0 has the resume address */ - pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); } static void exynos_pm_prepare(void) @@ -206,6 +224,9 @@ static void exynos_pm_prepare(void) pm_data->num_extra_save); exynos_pm_enter_sleep_mode(); + + /* ensure at least INFORM0 has the resume address */ + pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); } static void exynos5420_pm_prepare(void) @@ -230,6 +251,10 @@ static void exynos5420_pm_prepare(void) exynos_pm_enter_sleep_mode(); + /* ensure at least INFORM0 has the resume address */ + if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) + pmu_raw_writel(virt_to_phys(mcpm_entry_point), S5P_INFORM0); + tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION); tmp &= ~EXYNOS5_USE_RETENTION; pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION); @@ -318,10 +343,21 @@ early_wakeup: pmu_raw_writel(0x0, S5P_INFORM1); } +static void exynos5420_prepare_pm_resume(void) +{ + if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) + WARN_ON(mcpm_cpu_powered_up()); +} + static void exynos5420_pm_resume(void) { unsigned long tmp; + /* Restore the CPU0 low power state register */ + tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG); + pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN, + EXYNOS5_ARM_CORE0_SYS_PWR_REG); + /* Restore the sysram cpu state register */ __raw_writel(exynos5420_cpu_state, sysram_base_addr + EXYNOS5420_CPU_STATE); @@ -391,6 +427,8 @@ static int exynos_suspend_enter(suspend_state_t state) if (ret) return ret; + if (pm_data->pm_resume_prepare) + pm_data->pm_resume_prepare(); s3c_pm_restore_uarts(); S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, @@ -448,6 +486,7 @@ static struct exynos_pm_data exynos5420_pm_data = { .wkup_irq = exynos5250_wkup_irq, .wake_disable_mask = (0x7F << 7) | (0x1F << 1), .release_ret_regs = exynos5420_release_ret_regs, + .pm_resume_prepare = exynos5420_prepare_pm_resume, .pm_resume = exynos5420_pm_resume, .pm_suspend = exynos5420_pm_suspend, .pm_prepare = exynos5420_pm_prepare, -- cgit v1.2.3-59-g8ed1b From c645a598f99768e6cc82129081458dfdd0c273b7 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 13 Nov 2014 11:14:40 +0900 Subject: ARM: EXYNOS: Call regulator core suspend prepare and finish functions The regulator framework has a set of helpers functions to be used when the system is entering and leaving from suspend but these are not called on Exynos platforms. This means that the .set_suspend_* function handlers defined by regulator drivers are not called when the system is suspended. Suggested-by: Doug Anderson Signed-off-by: Javier Martinez Canillas Reviewed-by: Doug Anderson Reviewed-by: Chanwoo Choi Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/suspend.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index cc8d2374f1b1..f8e7dcd17055 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -443,6 +444,22 @@ static int exynos_suspend_enter(suspend_state_t state) static int exynos_suspend_prepare(void) { + int ret; + + /* + * REVISIT: It would be better if struct platform_suspend_ops + * .prepare handler get the suspend_state_t as a parameter to + * avoid hard-coding the suspend to mem state. It's safe to do + * it now only because the suspend_valid_only_mem function is + * used as the .valid callback used to check if a given state + * is supported by the platform anyways. + */ + ret = regulator_suspend_prepare(PM_SUSPEND_MEM); + if (ret) { + pr_err("Failed to prepare regulators for suspend (%d)\n", ret); + return ret; + } + s3c_pm_check_prepare(); return 0; @@ -450,7 +467,13 @@ static int exynos_suspend_prepare(void) static void exynos_suspend_finish(void) { + int ret; + s3c_pm_check_cleanup(); + + ret = regulator_suspend_finish(); + if (ret) + pr_warn("Failed to resume regulators from suspend (%d)\n", ret); } static const struct platform_suspend_ops exynos_suspend_ops = { -- cgit v1.2.3-59-g8ed1b From d1180f69b82337cc778c82819aac0dbb39bd1267 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Fri, 21 Nov 2014 15:44:21 +0530 Subject: ARM: OMAP2+: hwmod: AM43x: add hwmod support for ADC on AM43xx This patch adds hwmod support for ADC on AM43xx. Since clockdomain and offsets of adc_tsc are different from AM33xx, ADC data has been directly added to AM43xx hwmod file. Signed-off-by: Vignesh R [paul@pwsan.com: fixed spelling of "Anolog"; converted spaces to tabs] Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_43xx_data.c | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c index fea01aa3ef42..5c6c8410160e 100644 --- a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c @@ -417,6 +417,37 @@ static struct omap_hwmod am43xx_qspi_hwmod = { }, }; +/* + * 'adc/tsc' class + * TouchScreen Controller (Analog-To-Digital Converter) + */ +static struct omap_hwmod_class_sysconfig am43xx_adc_tsc_sysc = { + .rev_offs = 0x00, + .sysc_offs = 0x10, + .sysc_flags = SYSC_HAS_SIDLEMODE, + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + SIDLE_SMART_WKUP), + .sysc_fields = &omap_hwmod_sysc_type2, +}; + +static struct omap_hwmod_class am43xx_adc_tsc_hwmod_class = { + .name = "adc_tsc", + .sysc = &am43xx_adc_tsc_sysc, +}; + +static struct omap_hwmod am43xx_adc_tsc_hwmod = { + .name = "adc_tsc", + .class = &am43xx_adc_tsc_hwmod_class, + .clkdm_name = "l3s_tsc_clkdm", + .main_clk = "adc_tsc_fck", + .prcm = { + .omap4 = { + .clkctrl_offs = AM43XX_CM_WKUP_ADC_TSC_CLKCTRL_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + /* dss */ static struct omap_hwmod am43xx_dss_core_hwmod = { @@ -547,6 +578,13 @@ static struct omap_hwmod_ocp_if am43xx_l4_wkup__gpio0 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +static struct omap_hwmod_ocp_if am43xx_l4_wkup__adc_tsc = { + .master = &am33xx_l4_wkup_hwmod, + .slave = &am43xx_adc_tsc_hwmod, + .clk = "dpll_core_m4_div2_ck", + .user = OCP_USER_MPU, +}; + static struct omap_hwmod_ocp_if am43xx_l4_hs__cpgmac0 = { .master = &am43xx_l4_hs_hwmod, .slave = &am33xx_cpgmac0_hwmod, @@ -789,6 +827,7 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = { &am43xx_l4_wkup__i2c1, &am43xx_l4_wkup__gpio0, &am43xx_l4_wkup__wd_timer1, + &am43xx_l4_wkup__adc_tsc, &am43xx_l3_s__qspi, &am33xx_l4_per__dcan0, &am33xx_l4_per__dcan1, -- cgit v1.2.3-59-g8ed1b From 29c4ce17bcad34a086348dfd5c42b8cf5fda110b Mon Sep 17 00:00:00 2001 From: Dmitry Lifshitz Date: Tue, 18 Nov 2014 11:13:24 +0200 Subject: ARM: dts: cm-t3x30: add keypad support Add twl4030 matrtix keypad support. Signed-off-by: Dmitry Lifshitz Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-cm-t3x30.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi index 25ba08331d88..3cbaf98c1372 100644 --- a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi +++ b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi @@ -64,6 +64,7 @@ #include "twl4030.dtsi" #include "twl4030_omap3.dtsi" +#include &mmc1 { vmmc-supply = <&vmmc1>; @@ -75,6 +76,22 @@ ti,pullups = <0x000001>; }; +&twl_keypad { + linux,keymap = < + MATRIX_KEY(0x00, 0x01, KEY_A) + MATRIX_KEY(0x00, 0x02, KEY_B) + MATRIX_KEY(0x00, 0x03, KEY_LEFT) + + MATRIX_KEY(0x01, 0x01, KEY_UP) + MATRIX_KEY(0x01, 0x02, KEY_ENTER) + MATRIX_KEY(0x01, 0x03, KEY_DOWN) + + MATRIX_KEY(0x02, 0x01, KEY_RIGHT) + MATRIX_KEY(0x02, 0x02, KEY_C) + MATRIX_KEY(0x02, 0x03, KEY_D) + >; +}; + &hsusb1_phy { reset-gpios = <&twl_gpio 6 GPIO_ACTIVE_LOW>; }; -- cgit v1.2.3-59-g8ed1b From e92293a2a7edc68a37ee124b6665ca240fb2ce07 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 16:59:58 +0100 Subject: Documentation: dt-bindings: minimal documentation for MVEBU SDRAM controller The suspend/resume code for Armada XP has to modify certain registers of the SDRAM controller. Therefore, we need to define a Device Tree binding for this hardware block. Signed-off-by: Thomas Petazzoni Cc: devicetree@vger.kernel.org Cc: Kumar Gala Cc: Ian Campbell Cc: Mark Rutland Cc: Rob Herring Reviewed-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-2-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- .../memory-controllers/mvebu-sdram-controller.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt diff --git a/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt b/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt new file mode 100644 index 000000000000..89657d1d4cd4 --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt @@ -0,0 +1,21 @@ +Device Tree bindings for MVEBU SDRAM controllers + +The Marvell EBU SoCs all have a SDRAM controller. The SDRAM controller +differs from one SoC variant to another, but they also share a number +of commonalities. + +For now, this Device Tree binding documentation only documents the +Armada XP SDRAM controller. + +Required properties: + + - compatible: for Armada XP, "marvell,armada-xp-sdram-controller" + - reg: a resource specifier for the register space, which should + include all SDRAM controller registers as per the datasheet. + +Example: + +sdramc@1400 { + compatible = "marvell,armada-xp-sdram-controller"; + reg = <0x1400 0x500>; +}; -- cgit v1.2.3-59-g8ed1b From 30cdef97107370a7f63ab5d80fd2de30540750c8 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 13 Nov 2014 10:38:56 +0100 Subject: ARM: mvebu: make the coherency_ll.S functions work with no coherency fabric The ll_add_cpu_to_smp_group(), ll_enable_coherency() and ll_disable_coherency() are used on Armada XP to control the coherency fabric. However, they make the assumption that the coherency fabric is always available, which is currently a correct assumption but will no longer be true with a followup commit that disables the usage of the coherency fabric when the conditions are not met to use it. Therefore, this commit modifies those functions so that they check the return value of ll_get_coherency_base(), and if the return value is 0, they simply return without configuring anything in the coherency fabric. The ll_get_coherency_base() function is also modified to properly return 0 when the function is called with the MMU disabled. In this case, it normally returns the physical address of the coherency fabric, but we now check if the virtual address is 0, and if that's case, return a physical address of 0 to indicate that the coherency fabric is not enabled. Signed-off-by: Thomas Petazzoni Cc: # v3.8+ Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1415871540-20302-2-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/coherency_ll.S | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S index f5d881b5d0f7..8b2fbc8b6bc6 100644 --- a/arch/arm/mach-mvebu/coherency_ll.S +++ b/arch/arm/mach-mvebu/coherency_ll.S @@ -24,7 +24,10 @@ #include .text -/* Returns the coherency base address in r1 (r0 is untouched) */ +/* + * Returns the coherency base address in r1 (r0 is untouched), or 0 if + * the coherency fabric is not enabled. + */ ENTRY(ll_get_coherency_base) mrc p15, 0, r1, c1, c0, 0 tst r1, #CR_M @ Check MMU bit enabled @@ -32,8 +35,13 @@ ENTRY(ll_get_coherency_base) /* * MMU is disabled, use the physical address of the coherency - * base address. + * base address. However, if the coherency fabric isn't mapped + * (i.e its virtual address is zero), it means coherency is + * not enabled, so we return 0. */ + ldr r1, =coherency_base + cmp r1, #0 + beq 2f adr r1, 3f ldr r3, [r1] ldr r1, [r1, r3] @@ -85,6 +93,9 @@ ENTRY(ll_add_cpu_to_smp_group) */ mov r0, lr bl ll_get_coherency_base + /* Bail out if the coherency is not enabled */ + cmp r1, #0 + reteq r0 bl ll_get_coherency_cpumask mov lr, r0 add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET @@ -107,6 +118,9 @@ ENTRY(ll_enable_coherency) */ mov r0, lr bl ll_get_coherency_base + /* Bail out if the coherency is not enabled */ + cmp r1, #0 + reteq r0 bl ll_get_coherency_cpumask mov lr, r0 add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET @@ -131,6 +145,9 @@ ENTRY(ll_disable_coherency) */ mov r0, lr bl ll_get_coherency_base + /* Bail out if the coherency is not enabled */ + cmp r1, #0 + reteq r0 bl ll_get_coherency_cpumask mov lr, r0 add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET -- cgit v1.2.3-59-g8ed1b From e55355453600a33bb5ca4f71f2d7214875f3b061 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 13 Nov 2014 10:38:57 +0100 Subject: ARM: mvebu: disable I/O coherency on non-SMP situations on Armada 370/375/38x/XP Enabling the hardware I/O coherency on Armada 370, Armada 375, Armada 38x and Armada XP requires a certain number of conditions: - On Armada 370, the cache policy must be set to write-allocate. - On Armada 375, 38x and XP, the cache policy must be set to write-allocate, the pages must be mapped with the shareable attribute, and the SMP bit must be set Currently, on Armada XP, when CONFIG_SMP is enabled, those conditions are met. However, when Armada XP is used in a !CONFIG_SMP kernel, none of these conditions are met. With Armada 370, the situation is worse: since the processor is single core, regardless of whether CONFIG_SMP or !CONFIG_SMP is used, the cache policy will be set to write-back by the kernel and not write-allocate. Since solving this problem turns out to be quite complicated, and we don't want to let users with a mainline kernel known to have infrequent but existing data corruptions, this commit proposes to simply disable hardware I/O coherency in situations where it is known not to work. And basically, the is_smp() function of the kernel tells us whether it is OK to enable hardware I/O coherency or not, so this commit slightly refactors the coherency_type() function to return COHERENCY_FABRIC_TYPE_NONE when is_smp() is false, or the appropriate type of the coherency fabric in the other case. Thanks to this, the I/O coherency fabric will no longer be used at all in !CONFIG_SMP configurations. It will continue to be used in CONFIG_SMP configurations on Armada XP, Armada 375 and Armada 38x (which are multiple cores processors), but will no longer be used on Armada 370 (which is a single core processor). In the process, it simplifies the implementation of the coherency_type() function, and adds a missing call to of_node_put(). Signed-off-by: Thomas Petazzoni Fixes: e60304f8cb7bb545e79fe62d9b9762460c254ec2 ("arm: mvebu: Add hardware I/O Coherency support") Cc: # v3.8+ Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1415871540-20302-3-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/coherency.c | 44 ++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 044b51185fcc..c31f4c00b1fc 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -361,25 +361,41 @@ static int coherency_type(void) { struct device_node *np; const struct of_device_id *match; + int type; - np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); - if (np) { - int type = (int) match->data; + /* + * The coherency fabric is needed: + * - For coherency between processors on Armada XP, so only + * when SMP is enabled. + * - For coherency between the processor and I/O devices, but + * this coherency requires many pre-requisites (write + * allocate cache policy, shareable pages, SMP bit set) that + * are only meant in SMP situations. + * + * Note that this means that on Armada 370, there is currently + * no way to use hardware I/O coherency, because even when + * CONFIG_SMP is enabled, is_smp() returns false due to the + * Armada 370 being a single-core processor. To lift this + * limitation, we would have to find a way to make the cache + * policy set to write-allocate (on all Armada SoCs), and to + * set the shareable attribute in page tables (on all Armada + * SoCs except the Armada 370). Unfortunately, such decisions + * are taken very early in the kernel boot process, at a point + * where we don't know yet on which SoC we are running. - /* Armada 370/XP coherency works in both UP and SMP */ - if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) - return type; + */ + if (!is_smp()) + return COHERENCY_FABRIC_TYPE_NONE; - /* Armada 375 coherency works only on SMP */ - else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp()) - return type; + np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); + if (!np) + return COHERENCY_FABRIC_TYPE_NONE; - /* Armada 380 coherency works only on SMP */ - else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp()) - return type; - } + type = (int) match->data; + + of_node_put(np); - return COHERENCY_FABRIC_TYPE_NONE; + return type; } int coherency_available(void) -- cgit v1.2.3-59-g8ed1b From 3b8509b5f2c14403d4bfaec56842ad0ed5389022 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 13 Nov 2014 10:38:58 +0100 Subject: ARM: mvebu: remove unused register offset definition Since commit b21dcafea36d ("arm: mvebu: remove dependency of SMP init on static I/O mapping"), the COHERENCY_FABRIC_CFG_OFFSET register offset definition is no longer used, so this commit removes it. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1415871540-20302-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/coherency.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index c31f4c00b1fc..db2f5bd280dd 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -42,8 +42,6 @@ void __iomem *coherency_base; static void __iomem *coherency_cpu_base; /* Coherency fabric registers */ -#define COHERENCY_FABRIC_CFG_OFFSET 0x4 - #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 enum { -- cgit v1.2.3-59-g8ed1b From ef01c6c36bb8d176e5f2302507fb1f688875d3ab Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 13 Nov 2014 10:38:59 +0100 Subject: ARM: mvebu: remove Armada 375 Z1 workaround for I/O coherency This reverts commit 5ab5afd8ba83 ("ARM: mvebu: implement Armada 375 coherency workaround"), since we are removing the support for the very early Z1 revision of the Armada 375 SoC. This commit is an exact revert, with two exceptions: - minor adaptations needed due to other changes that have taken place in coherency.c since the original commit - keep the definition of pr_fmt. This shouldn't originally have been part of the Armada 375 Z1 workaround commit since it had nothing to do with it. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1415871540-20302-5-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/coherency.c | 169 +--------------------------------------- 1 file changed, 3 insertions(+), 166 deletions(-) diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index db2f5bd280dd..e568b2ef6830 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -77,157 +76,8 @@ int set_cpu_coherent(void) return ll_enable_coherency(); } -/* - * The below code implements the I/O coherency workaround on Armada - * 375. This workaround consists in using the two channels of the - * first XOR engine to trigger a XOR transaction that serves as the - * I/O coherency barrier. - */ - -static void __iomem *xor_base, *xor_high_base; -static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS]; -static void *coherency_wa_buf[CONFIG_NR_CPUS]; -static bool coherency_wa_enabled; - -#define XOR_CONFIG(chan) (0x10 + (chan * 4)) -#define XOR_ACTIVATION(chan) (0x20 + (chan * 4)) -#define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2)) -#define WINDOW_BASE(w) (0x250 + ((w) << 2)) -#define WINDOW_SIZE(w) (0x270 + ((w) << 2)) -#define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2)) -#define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2)) -#define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4)) -#define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4)) -#define XOR_INIT_VALUE_LOW 0x2E0 -#define XOR_INIT_VALUE_HIGH 0x2E4 - -static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void) -{ - int idx = smp_processor_id(); - - /* Write '1' to the first word of the buffer */ - writel(0x1, coherency_wa_buf[idx]); - - /* Wait until the engine is idle */ - while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3) - ; - - dmb(); - - /* Trigger channel */ - writel(0x1, xor_base + XOR_ACTIVATION(idx)); - - /* Poll the data until it is cleared by the XOR transaction */ - while (readl(coherency_wa_buf[idx])) - ; -} - -static void __init armada_375_coherency_init_wa(void) -{ - const struct mbus_dram_target_info *dram; - struct device_node *xor_node; - struct property *xor_status; - struct clk *xor_clk; - u32 win_enable = 0; - int i; - - pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n"); - - /* - * Since the workaround uses one XOR engine, we grab a - * reference to its Device Tree node first. - */ - xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor"); - BUG_ON(!xor_node); - - /* - * Then we mark it as disabled so that the real XOR driver - * will not use it. - */ - xor_status = kzalloc(sizeof(struct property), GFP_KERNEL); - BUG_ON(!xor_status); - - xor_status->value = kstrdup("disabled", GFP_KERNEL); - BUG_ON(!xor_status->value); - - xor_status->length = 8; - xor_status->name = kstrdup("status", GFP_KERNEL); - BUG_ON(!xor_status->name); - - of_update_property(xor_node, xor_status); - - /* - * And we remap the registers, get the clock, and do the - * initial configuration of the XOR engine. - */ - xor_base = of_iomap(xor_node, 0); - xor_high_base = of_iomap(xor_node, 1); - - xor_clk = of_clk_get_by_name(xor_node, NULL); - BUG_ON(!xor_clk); - - clk_prepare_enable(xor_clk); - - dram = mv_mbus_dram_info(); - - for (i = 0; i < 8; i++) { - writel(0, xor_base + WINDOW_BASE(i)); - writel(0, xor_base + WINDOW_SIZE(i)); - if (i < 4) - writel(0, xor_base + WINDOW_REMAP_HIGH(i)); - } - - for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; - writel((cs->base & 0xffff0000) | - (cs->mbus_attr << 8) | - dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i)); - writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i)); - - win_enable |= (1 << i); - win_enable |= 3 << (16 + (2 * i)); - } - - writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0)); - writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1)); - writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0)); - writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1)); - - for (i = 0; i < CONFIG_NR_CPUS; i++) { - coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL); - BUG_ON(!coherency_wa_buf[i]); - - /* - * We can't use the DMA mapping API, since we don't - * have a valid 'struct device' pointer - */ - coherency_wa_buf_phys[i] = - virt_to_phys(coherency_wa_buf[i]); - BUG_ON(!coherency_wa_buf_phys[i]); - - /* - * Configure the XOR engine for memset operation, with - * a 128 bytes block size - */ - writel(0x444, xor_base + XOR_CONFIG(i)); - writel(128, xor_base + XOR_BLOCK_SIZE(i)); - writel(coherency_wa_buf_phys[i], - xor_base + XOR_DEST_POINTER(i)); - } - - writel(0x0, xor_base + XOR_INIT_VALUE_LOW); - writel(0x0, xor_base + XOR_INIT_VALUE_HIGH); - - coherency_wa_enabled = true; -} - static inline void mvebu_hwcc_sync_io_barrier(void) { - if (coherency_wa_enabled) { - mvebu_hwcc_armada375_sync_io_barrier_wa(); - return; - } - writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); } @@ -421,22 +271,9 @@ int __init coherency_init(void) static int __init coherency_late_init(void) { - int type = coherency_type(); - - if (type == COHERENCY_FABRIC_TYPE_NONE) - return 0; - - if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) { - u32 dev, rev; - - if (mvebu_get_soc_id(&dev, &rev) == 0 && - rev == ARMADA_375_Z1_REV) - armada_375_coherency_init_wa(); - } - - bus_register_notifier(&platform_bus_type, - &mvebu_hwcc_nb); - + if (coherency_available()) + bus_register_notifier(&platform_bus_type, + &mvebu_hwcc_nb); return 0; } -- cgit v1.2.3-59-g8ed1b From e12f12ac1a3245d0f5d751de63d20d8dded03fc3 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 13 Nov 2014 10:39:00 +0100 Subject: ARM: mvebu: update comments in coherency.c The coherency.c top-level comment mentions that it supports the coherency fabric for Armada 370 and XP, but it also supports the coherency fabric on Armada 375 and 38x, so this commit updates the comment accordingly. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1415871540-20302-6-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/coherency.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index e568b2ef6830..c18da36c75b1 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -1,5 +1,6 @@ /* - * Coherency fabric (Aurora) support for Armada 370 and XP platforms. + * Coherency fabric (Aurora) support for Armada 370, 375, 38x and XP + * platforms. * * Copyright (C) 2012 Marvell * @@ -11,7 +12,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. * - * The Armada 370 and Armada XP SOCs have a coherency fabric which is + * The Armada 370, 375, 38x and XP SOCs have a coherency fabric which is * responsible for ensuring hardware coherency between all CPUs and between * CPUs and I/O masters. This file initializes the coherency fabric and * supplies basic routines for configuring and controlling hardware coherency -- cgit v1.2.3-59-g8ed1b From 316fbbc400875c647c3a220c7525ffa8d2c80306 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 30 Oct 2014 12:39:41 +0100 Subject: ARM: mvebu: Clean-up the Armada XP support This patch removes the unneeded include of the armada-370-xp.h header. It also moves some declarations from this file into more accurate places. Finally, it also adds a comment explaining that we can't remove yet the smp field in the dt machine struct due to backward compatibly of the device tree. In a few releases, when the old device tree will be obsolete, we will be able to remove the smp field and then the armada-370-xp.h header. Signed-off-by: Gregory CLEMENT Tested-by: Thomas Petazzoni Reviewed-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1414669184-16785-2-git-send-email-gregory.clement@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/armada-370-xp.h | 6 ------ arch/arm/mach-mvebu/board-v7.c | 5 +++++ arch/arm/mach-mvebu/coherency.c | 1 - arch/arm/mach-mvebu/cpu-reset.c | 1 - arch/arm/mach-mvebu/platsmp.c | 2 ++ arch/arm/mach-mvebu/pmsu.c | 1 - arch/arm/mach-mvebu/pmsu.h | 1 + 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h index 84cd90d9b860..c55bbf81de0e 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.h +++ b/arch/arm/mach-mvebu/armada-370-xp.h @@ -16,14 +16,8 @@ #define __MACH_ARMADA_370_XP_H #ifdef CONFIG_SMP -#include - -#define ARMADA_XP_MAX_CPUS 4 - void armada_xp_secondary_startup(void); extern struct smp_operations armada_xp_smp_ops; #endif -int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); - #endif /* __MACH_ARMADA_370_XP_H */ diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index d965d0c0ef2d..e15ead876a48 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -142,6 +142,11 @@ static const char * const armada_370_xp_dt_compat[] = { DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)") .l2c_aux_val = 0, .l2c_aux_mask = ~0, +/* + * The following field (.smp) is still needed to ensure backward + * compatibility with old Device Trees that were not specifying the + * cpus enable-method property. + */ .smp = smp_ops(armada_xp_smp_ops), .init_machine = mvebu_dt_init, .init_irq = mvebu_init_irq, diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index c18da36c75b1..3585cb394e9b 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -33,7 +33,6 @@ #include #include #include -#include "armada-370-xp.h" #include "coherency.h" #include "mvebu-soc-id.h" diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c index 60fb53787004..4a2cadd6b48e 100644 --- a/arch/arm/mach-mvebu/cpu-reset.c +++ b/arch/arm/mach-mvebu/cpu-reset.c @@ -15,7 +15,6 @@ #include #include #include -#include "armada-370-xp.h" static void __iomem *cpu_reset_base; static size_t cpu_reset_size; diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index 895dc373c8a1..622315c185b2 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -30,6 +30,8 @@ #include "pmsu.h" #include "coherency.h" +#define ARMADA_XP_MAX_CPUS 4 + #define AXP_BOOTROM_BASE 0xfff00000 #define AXP_BOOTROM_SIZE 0x100000 diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index bbd8664d1bac..5af58927a56d 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -39,7 +39,6 @@ #include #include #include "common.h" -#include "armada-370-xp.h" #define PMSU_BASE_OFFSET 0x100 diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index 6b58c1fe2b0d..e1eb4959a2d4 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h @@ -18,4 +18,5 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, void mvebu_v7_pmsu_idle_exit(void); +int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); #endif /* __MACH_370_XP_PMSU_H */ -- cgit v1.2.3-59-g8ed1b From f746ac327b2fe7235a3b94de3d6d4b2be0f8f6a0 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 30 Oct 2014 12:39:42 +0100 Subject: ARM: mvebu: Move SCU power up in a function This will allow reusing the same function in the secondary_startup for the Cortex A9 SoC. Signed-off-by: Gregory CLEMENT Tested-by: Thomas Petazzoni Reviewed-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1414669184-16785-3-git-send-email-gregory.clement@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu_ll.S | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S index a945756cfb45..83d014698314 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S @@ -12,6 +12,18 @@ #include #include + +ENTRY(armada_38x_scu_power_up) + mrc p15, 4, r1, c15, c0 @ get SCU base address + orr r1, r1, #0x8 @ SCU CPU Power Status Register + mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID + and r0, r0, #15 + add r1, r1, r0 + mov r0, #0x0 + strb r0, [r1] @ switch SCU power state to Normal mode + ret lr +ENDPROC(armada_38x_scu_power_up) + /* * This is the entry point through which CPUs exiting cpuidle deep * idle state are going. @@ -27,13 +39,7 @@ ENTRY(armada_38x_cpu_resume) /* do we need it for Armada 38x*/ ARM_BE8(setend be ) @ go BE8 if entered LE bl v7_invalidate_l1 - mrc p15, 4, r1, c15, c0 @ get SCU base address - orr r1, r1, #0x8 @ SCU CPU Power Status Register - mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID - and r0, r0, #15 - add r1, r1, r0 - mov r0, #0x0 - strb r0, [r1] @ switch SCU power state to Normal mode + bl armada_38x_scu_power_up b cpu_resume ENDPROC(armada_38x_cpu_resume) -- cgit v1.2.3-59-g8ed1b From f5789cbb22a01c0750d12cb54c4bbd416e04f7ff Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 30 Oct 2014 12:39:43 +0100 Subject: ARM: mvebu: Fix the secondary startup for Cortex A9 SoC During the secondary startup the SCU was assumed to be in normal mode. It is not always the case, and especially after a kexec. This commit adds the needed sequence to put the SCU in normal mode. Signed-off-by: Gregory CLEMENT Tested-by: Thomas Petazzoni Reviewed-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1414669184-16785-4-git-send-email-gregory.clement@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/headsmp-a9.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S index be51c998c0cd..08d5ed46b996 100644 --- a/arch/arm/mach-mvebu/headsmp-a9.S +++ b/arch/arm/mach-mvebu/headsmp-a9.S @@ -22,5 +22,6 @@ ENTRY(mvebu_cortex_a9_secondary_startup) ARM_BE8(setend be) bl v7_invalidate_l1 + bl armada_38x_scu_power_up b secondary_startup ENDPROC(mvebu_cortex_a9_secondary_startup) -- cgit v1.2.3-59-g8ed1b From 626d686487bfd8136c4543bee7b6b2e52c33b3f8 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Thu, 30 Oct 2014 12:39:44 +0100 Subject: ARM: mvebu: Implement the CPU hotplug support for the Armada 38x SoCs This commit implements the CPU hotplug support for the Marvell Armada 38x platform. Similarly to what was done for the Armada XP, this commit: * Implements the ->cpu_die() function of SMP operations by calling armada_38x_do_cpu_suspend() to enter the deep idle state for CPUs going offline. * Implements a dummy ->cpu_kill() function, simply needed for the kernel to know we have CPU hotplug support. * The mvebu_cortex_a9_boot_secondary() function makes sure to wake up the CPU if waiting in deep idle state by sending an IPI before deasserting the CPUs from reset. This is because mvebu_cortex_a9_boot_secondary() is now used in two different situations: for the initial boot of secondary CPUs (where CPU reset deassert is used to wake up CPUs) and for CPU hotplug (where an IPI is used to take CPU out of deep idle). * At boot time, we exit from the idle state in the ->smp_secondary_init() hook. This commit has been tested using CPU hotplug through sysfs (/sys/devices/system/cpu/cpuX/online) and using kexec. Signed-off-by: Gregory CLEMENT Tested-by: Thomas Petazzoni Reviewed-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1414669184-16785-5-git-send-email-gregory.clement@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/platsmp-a9.c | 53 ++++++++++++++++++++++++++++++++++++++-- arch/arm/mach-mvebu/pmsu.c | 2 +- arch/arm/mach-mvebu/pmsu.h | 1 + 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c index 47a71a924b96..2ec1a42b4321 100644 --- a/arch/arm/mach-mvebu/platsmp-a9.c +++ b/arch/arm/mach-mvebu/platsmp-a9.c @@ -43,21 +43,70 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, else mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup); smp_wmb(); + + /* + * Doing this before deasserting the CPUs is needed to wake up CPUs + * in the offline state after using CPU hotplug. + */ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + ret = mvebu_cpu_reset_deassert(hw_cpu); if (ret) { pr_err("Could not start the secondary CPU: %d\n", ret); return ret; } - arch_send_wakeup_ipi_mask(cpumask_of(cpu)); return 0; } +/* + * When a CPU is brought back online, either through CPU hotplug, or + * because of the boot of a kexec'ed kernel, the PMSU configuration + * for this CPU might be in the deep idle state, preventing this CPU + * from receiving interrupts. Here, we therefore take out the current + * CPU from this state, which was entered by armada_38x_cpu_die() + * below. + */ +static void armada_38x_secondary_init(unsigned int cpu) +{ + mvebu_v7_pmsu_idle_exit(); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void armada_38x_cpu_die(unsigned int cpu) +{ + /* + * CPU hotplug is implemented by putting offline CPUs into the + * deep idle sleep state. + */ + armada_38x_do_cpu_suspend(true); +} + +/* + * We need a dummy function, so that platform_can_cpu_hotplug() knows + * we support CPU hotplug. However, the function does not need to do + * anything, because CPUs going offline can enter the deep idle state + * by themselves, without any help from a still alive CPU. + */ +static int armada_38x_cpu_kill(unsigned int cpu) +{ + return 1; +} +#endif static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, }; +static struct smp_operations armada_38x_smp_ops __initdata = { + .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, + .smp_secondary_init = armada_38x_secondary_init, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = armada_38x_cpu_die, + .cpu_kill = armada_38x_cpu_kill, +#endif +}; + CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", &mvebu_cortex_a9_smp_ops); CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", - &mvebu_cortex_a9_smp_ops); + &armada_38x_smp_ops); diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 5af58927a56d..5a757f929927 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -311,7 +311,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle) return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter); } -static int armada_38x_do_cpu_suspend(unsigned long deepidle) +int armada_38x_do_cpu_suspend(unsigned long deepidle) { unsigned long flags = 0; diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index e1eb4959a2d4..c2c95db4f648 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h @@ -19,4 +19,5 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, void mvebu_v7_pmsu_idle_exit(void); int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); +int armada_38x_do_cpu_suspend(unsigned long deepidle); #endif /* __MACH_370_XP_PMSU_H */ -- cgit v1.2.3-59-g8ed1b From 8fcc774fc72910fa26767ae8ca2da3d64ae80a01 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sat, 22 Nov 2014 23:03:40 +0900 Subject: ARM: EXYNOS: add exynos3250 PMU support This patch prepares the PMU code for the future: - suspend/resume (S2R) support - cpuidle AFTR/W-AFTR modes support on Exynos3250. Cc: Vikas Sajjan Reviewed-by: Pankaj Dubey Acked-by: Kyungmin Park Signed-off-by: Chanwoo Choi Signed-off-by: Bartlomiej Zolnierkiewicz [kgene.kim@samsung.com: fixed coding style] Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pmu.c | 167 ++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-exynos/regs-pmu.h | 128 ++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+) diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index 6c8a76dd5494..fcb3b672e39b 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -31,6 +31,7 @@ struct exynos_pmu_data { void (*pmu_init)(void); void (*powerdown_conf)(enum sys_powerdown); + void (*powerdown_conf_extra)(enum sys_powerdown); }; struct exynos_pmu_context { @@ -51,6 +52,92 @@ static inline u32 pmu_raw_readl(u32 offset) return readl_relaxed(pmu_base_addr + offset); } +static struct exynos_pmu_conf exynos3250_pmu_config[] = { + /* { .offset = offset, .val = { AFTR, W-AFTR, SLEEP } */ + { EXYNOS3_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, + { EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, + { EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, + { EXYNOS3_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x3} }, + { EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS3_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x3} }, + { EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG, { 0x3, 0x3, 0x3} }, + { EXYNOS3_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_CAM_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_LCD0_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_MAUDIO_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { PMU_TABLE_END,}, +}; + static const struct exynos_pmu_conf exynos4210_pmu_config[] = { /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ { S5P_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } }, @@ -495,6 +582,44 @@ static struct exynos_pmu_conf exynos5420_pmu_config[] = { { PMU_TABLE_END,}, }; +static unsigned int const exynos3250_list_feed[] = { + EXYNOS3_ARM_CORE_OPTION(0), + EXYNOS3_ARM_CORE_OPTION(1), + EXYNOS3_ARM_CORE_OPTION(2), + EXYNOS3_ARM_CORE_OPTION(3), + EXYNOS3_ARM_COMMON_OPTION, + EXYNOS3_TOP_PWR_OPTION, + EXYNOS3_CORE_TOP_PWR_OPTION, + S5P_CAM_OPTION, + S5P_MFC_OPTION, + S5P_G3D_OPTION, + S5P_LCD0_OPTION, + S5P_ISP_OPTION, +}; + +static void exynos3250_powerdown_conf_extra(enum sys_powerdown mode) +{ + unsigned int i; + unsigned int tmp; + + /* Enable only SC_FEEDBACK */ + for (i = 0; i < ARRAY_SIZE(exynos3250_list_feed); i++) { + tmp = pmu_raw_readl(exynos3250_list_feed[i]); + tmp &= ~(EXYNOS3_OPTION_USE_SC_COUNTER); + tmp |= EXYNOS3_OPTION_USE_SC_FEEDBACK; + pmu_raw_writel(tmp, exynos3250_list_feed[i]); + } + + if (mode != SYS_SLEEP) + return; + + pmu_raw_writel(XUSBXTI_DURATION, EXYNOS3_XUSBXTI_DURATION); + pmu_raw_writel(XXTI_DURATION, EXYNOS3_XXTI_DURATION); + pmu_raw_writel(EXT_REGULATOR_DURATION, EXYNOS3_EXT_REGULATOR_DURATION); + pmu_raw_writel(EXT_REGULATOR_COREBLK_DURATION, + EXYNOS3_EXT_REGULATOR_COREBLK_DURATION); +} + static unsigned int const exynos5_list_both_cnt_feed[] = { EXYNOS5_ARM_CORE0_OPTION, EXYNOS5_ARM_CORE1_OPTION, @@ -632,6 +757,9 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode) pmu_data->pmu_config[i].offset); } + if (pmu_data->powerdown_conf_extra) + pmu_data->powerdown_conf_extra(mode); + if (pmu_data->pmu_config_extra) { for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++) pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode], @@ -639,6 +767,36 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode) } } +static void exynos3250_pmu_init(void) +{ + unsigned int value; + + /* + * To prevent from issuing new bus request form L2 memory system + * If core status is power down, should be set '1' to L2 power down + */ + value = pmu_raw_readl(EXYNOS3_ARM_COMMON_OPTION); + value |= EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN; + pmu_raw_writel(value, EXYNOS3_ARM_COMMON_OPTION); + + /* Enable USE_STANDBY_WFI for all CORE */ + pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); + + /* + * Set PSHOLD port for output high + */ + value = pmu_raw_readl(S5P_PS_HOLD_CONTROL); + value |= S5P_PS_HOLD_OUTPUT_HIGH; + pmu_raw_writel(value, S5P_PS_HOLD_CONTROL); + + /* + * Enable signal for PSHOLD port + */ + value = pmu_raw_readl(S5P_PS_HOLD_CONTROL); + value |= S5P_PS_HOLD_EN; + pmu_raw_writel(value, S5P_PS_HOLD_CONTROL); +} + static void exynos5250_pmu_init(void) { unsigned int value; @@ -717,6 +875,12 @@ static void exynos5420_pmu_init(void) } +static const struct exynos_pmu_data exynos3250_pmu_data = { + .pmu_config = exynos3250_pmu_config, + .pmu_init = exynos3250_pmu_init, + .powerdown_conf_extra = exynos3250_powerdown_conf_extra, +}; + static const struct exynos_pmu_data exynos4210_pmu_data = { .pmu_config = exynos4210_pmu_config, }; @@ -747,6 +911,9 @@ static struct exynos_pmu_data exynos5420_pmu_data = { */ static const struct of_device_id exynos_pmu_of_device_ids[] = { { + .compatible = "samsung,exynos3250-pmu", + .data = &exynos3250_pmu_data, + }, { .compatible = "samsung,exynos4210-pmu", .data = &exynos4210_pmu_data, }, { diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 46b973b8cd83..b5f4406fc1b5 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -19,7 +19,20 @@ #define S5P_CENTRAL_SEQ_OPTION 0x0208 #define S5P_USE_STANDBY_WFI0 (1 << 16) +#define S5P_USE_STANDBY_WFI1 (1 << 17) +#define S5P_USE_STANDBY_WFI2 (1 << 19) +#define S5P_USE_STANDBY_WFI3 (1 << 20) #define S5P_USE_STANDBY_WFE0 (1 << 24) +#define S5P_USE_STANDBY_WFE1 (1 << 25) +#define S5P_USE_STANDBY_WFE2 (1 << 27) +#define S5P_USE_STANDBY_WFE3 (1 << 28) + +#define S5P_USE_STANDBY_WFI_ALL \ + (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFI1 | \ + S5P_USE_STANDBY_WFI2 | S5P_USE_STANDBY_WFI3 | \ + S5P_USE_STANDBY_WFE0 | S5P_USE_STANDBY_WFE1 | \ + S5P_USE_STANDBY_WFE2 | S5P_USE_STANDBY_WFE3) + #define S5P_USE_DELAYED_RESET_ASSERTION BIT(12) #define EXYNOS_CORE_PO_RESET(n) ((1 << 4) << n) @@ -154,6 +167,17 @@ #define S5P_PAD_RET_EBIA_OPTION 0x3188 #define S5P_PAD_RET_EBIB_OPTION 0x31A8 +#define S5P_PS_HOLD_CONTROL 0x330C +#define S5P_PS_HOLD_EN (1 << 31) +#define S5P_PS_HOLD_OUTPUT_HIGH (3 << 8) + +#define S5P_CAM_OPTION 0x3C08 +#define S5P_MFC_OPTION 0x3C48 +#define S5P_G3D_OPTION 0x3C68 +#define S5P_LCD0_OPTION 0x3C88 +#define S5P_LCD1_OPTION 0x3CA8 +#define S5P_ISP_OPTION S5P_LCD1_OPTION + #define S5P_CORE_LOCAL_PWR_EN 0x3 #define S5P_CORE_WAKEUP_FROM_LOCAL_CFG (0x3 << 8) @@ -214,6 +238,110 @@ #define S5P_DIS_IRQ_CORE3 0x1034 #define S5P_DIS_IRQ_CENTRAL3 0x1038 +/* Only for EXYNOS3XXX */ +#define EXYNOS3_ARM_CORE0_SYS_PWR_REG 0x1000 +#define EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG 0x1004 +#define EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG 0x1008 +#define EXYNOS3_ARM_CORE1_SYS_PWR_REG 0x1010 +#define EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG 0x1014 +#define EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG 0x1018 +#define EXYNOS3_ISP_ARM_SYS_PWR_REG 0x1050 +#define EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1054 +#define EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1058 +#define EXYNOS3_ARM_COMMON_SYS_PWR_REG 0x1080 +#define EXYNOS3_ARM_L2_SYS_PWR_REG 0x10C0 +#define EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG 0x1100 +#define EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG 0x1104 +#define EXYNOS3_CMU_RESET_SYS_PWR_REG 0x110C +#define EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG 0x1110 +#define EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG 0x1114 +#define EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG 0x111C +#define EXYNOS3_APLL_SYSCLK_SYS_PWR_REG 0x1120 +#define EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG 0x1124 +#define EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG 0x1128 +#define EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG 0x112C +#define EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG 0x1130 +#define EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG 0x1134 +#define EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG 0x1138 +#define EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140 +#define EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148 +#define EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C +#define EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150 +#define EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG 0x1154 +#define EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158 +#define EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG 0x1160 +#define EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG 0x1168 +#define EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG 0x116C +#define EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG 0x1170 +#define EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG 0x1174 +#define EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178 +#define EXYNOS3_TOP_BUS_SYS_PWR_REG 0x1180 +#define EXYNOS3_TOP_RETENTION_SYS_PWR_REG 0x1184 +#define EXYNOS3_TOP_PWR_SYS_PWR_REG 0x1188 +#define EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG 0x1190 +#define EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG 0x1194 +#define EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG 0x1198 +#define EXYNOS3_LOGIC_RESET_SYS_PWR_REG 0x11A0 +#define EXYNOS3_OSCCLK_GATE_SYS_PWR_REG 0x11A4 +#define EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG 0x11B0 +#define EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG 0x11B4 +#define EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200 +#define EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204 +#define EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG 0x1208 +#define EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1218 +#define EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220 +#define EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG 0x1224 +#define EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1228 +#define EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG 0x122C +#define EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230 +#define EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234 +#define EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1238 +#define EXYNOS3_PAD_ISOLATION_SYS_PWR_REG 0x1240 +#define EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG 0x1260 +#define EXYNOS3_XUSBXTI_SYS_PWR_REG 0x1280 +#define EXYNOS3_XXTI_SYS_PWR_REG 0x1284 +#define EXYNOS3_EXT_REGULATOR_SYS_PWR_REG 0x12C0 +#define EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG 0x12C4 +#define EXYNOS3_GPIO_MODE_SYS_PWR_REG 0x1300 +#define EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340 +#define EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG 0x1344 +#define EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG 0x1348 +#define EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG 0x1350 +#define EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG 0x1354 +#define EXYNOS3_CAM_SYS_PWR_REG 0x1380 +#define EXYNOS3_MFC_SYS_PWR_REG 0x1388 +#define EXYNOS3_G3D_SYS_PWR_REG 0x138C +#define EXYNOS3_LCD0_SYS_PWR_REG 0x1390 +#define EXYNOS3_ISP_SYS_PWR_REG 0x1394 +#define EXYNOS3_MAUDIO_SYS_PWR_REG 0x1398 +#define EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG 0x13B0 +#define EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG 0x13B4 +#define EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG 0x13B8 +#define EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG 0x13C0 +#define EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG 0x13C4 +#define EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG 0x13C8 + +#define EXYNOS3_ARM_CORE0_OPTION 0x2008 +#define EXYNOS3_ARM_CORE_OPTION(_nr) \ + (EXYNOS3_ARM_CORE0_OPTION + ((_nr) * 0x80)) + +#define EXYNOS3_ARM_COMMON_OPTION 0x2408 +#define EXYNOS3_TOP_PWR_OPTION 0x2C48 +#define EXYNOS3_CORE_TOP_PWR_OPTION 0x2CA8 +#define EXYNOS3_XUSBXTI_DURATION 0x341C +#define EXYNOS3_XXTI_DURATION 0x343C +#define EXYNOS3_EXT_REGULATOR_DURATION 0x361C +#define EXYNOS3_EXT_REGULATOR_COREBLK_DURATION 0x363C +#define XUSBXTI_DURATION 0x00000BB8 +#define XXTI_DURATION XUSBXTI_DURATION +#define EXT_REGULATOR_DURATION 0x00001D4C +#define EXT_REGULATOR_COREBLK_DURATION EXT_REGULATOR_DURATION + +/* for XXX_OPTION */ +#define EXYNOS3_OPTION_USE_SC_COUNTER (1 << 0) +#define EXYNOS3_OPTION_USE_SC_FEEDBACK (1 << 1) +#define EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN (1 << 7) + /* For EXYNOS5 */ #define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408 -- cgit v1.2.3-59-g8ed1b From 5e6473f422909a9f929619c04c6bab7620531b69 Mon Sep 17 00:00:00 2001 From: Pankaj Dubey Date: Sat, 22 Nov 2014 23:07:21 +0900 Subject: clk: exynos5440: move restart code into clock driver Let's register restart handler for Exynos5440 from it's clock driver for restart functionality. So that we can cleanup restart hooks from machine specific file. CC: Sylwester Nawrocki CC: Tomasz Figa Signed-off-by: Pankaj Dubey Acked-by: Guenter Roeck Acked-by: Sylwester Nawrocki Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/exynos.c | 19 +------------------ drivers/clk/samsung/clk-exynos5440.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 6dc332fa55db..67cf65fd77bb 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -139,24 +139,7 @@ static struct map_desc exynos5_iodesc[] __initdata = { static void exynos_restart(enum reboot_mode mode, const char *cmd) { - struct device_node *np; - u32 val = 0x1; - void __iomem *addr = pmu_base_addr + EXYNOS_SWRESET; - - if (of_machine_is_compatible("samsung,exynos5440")) { - u32 status; - np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock"); - - addr = of_iomap(np, 0) + 0xbc; - status = __raw_readl(addr); - - addr = of_iomap(np, 0) + 0xcc; - val = __raw_readl(addr); - - val = (val & 0xffff0000) | (status & 0xffff); - } - - __raw_writel(val, addr); + __raw_writel(0x1, pmu_base_addr + EXYNOS_SWRESET); } static struct platform_device exynos_cpuidle = { diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c index 00d1d00a41de..979e81389cdd 100644 --- a/drivers/clk/samsung/clk-exynos5440.c +++ b/drivers/clk/samsung/clk-exynos5440.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include "clk.h" #include "clk-pll.h" @@ -23,6 +25,8 @@ #define CPU_CLK_STATUS 0xfc #define MISC_DOUT1 0x558 +static void __iomem *reg_base; + /* parent clock name list */ PNAME(mout_armclk_p) = { "cplla", "cpllb" }; PNAME(mout_spi_p) = { "div125", "div200" }; @@ -89,10 +93,30 @@ static const struct of_device_id ext_clk_match[] __initconst = { {}, }; +static int exynos5440_clk_restart_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + u32 val, status; + + status = readl_relaxed(reg_base + 0xbc); + val = readl_relaxed(reg_base + 0xcc); + val = (val & 0xffff0000) | (status & 0xffff); + writel_relaxed(val, reg_base + 0xcc); + + return NOTIFY_DONE; +} + +/* + * Exynos5440 Clock restart notifier, handles restart functionality + */ +static struct notifier_block exynos5440_clk_restart_handler = { + .notifier_call = exynos5440_clk_restart_notify, + .priority = 128, +}; + /* register exynos5440 clocks */ static void __init exynos5440_clk_init(struct device_node *np) { - void __iomem *reg_base; struct samsung_clk_provider *ctx; reg_base = of_iomap(np, 0); @@ -125,6 +149,9 @@ static void __init exynos5440_clk_init(struct device_node *np) samsung_clk_of_add_provider(np, ctx); + if (register_restart_handler(&exynos5440_clk_restart_handler)) + pr_warn("exynos5440 clock can't register restart handler\n"); + pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk")); pr_info("exynos5440 clock initialization complete\n"); } -- cgit v1.2.3-59-g8ed1b From 8cfc7fdd33080e30b86d21b1a8c9ad0686427ddc Mon Sep 17 00:00:00 2001 From: Pankaj Dubey Date: Sat, 22 Nov 2014 23:10:23 +0900 Subject: ARM: EXYNOS: move restart code into pmu driver Let's register restart handler from PMU driver for restart functionality. So that we can remove restart hooks from machine specific file, and thus moving ahead when PMU moved to driver folder, this functionality can be reused for ARM64 based Exynos SoC's. Signed-off-by: Pankaj Dubey Acked-by: Guenter Roeck Tested-by: Vivek Gautam Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/common.h | 1 - arch/arm/mach-exynos/exynos.c | 6 ------ arch/arm/mach-exynos/pmu.c | 23 +++++++++++++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 431be1bca2e8..865f878063cc 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -12,7 +12,6 @@ #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H #define __ARCH_ARM_MACH_EXYNOS_COMMON_H -#include #include #define EXYNOS3250_SOC_ID 0xE3472000 diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 67cf65fd77bb..80d744db7dc7 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -137,11 +137,6 @@ static struct map_desc exynos5_iodesc[] __initdata = { }, }; -static void exynos_restart(enum reboot_mode mode, const char *cmd) -{ - __raw_writel(0x1, pmu_base_addr + EXYNOS_SWRESET); -} - static struct platform_device exynos_cpuidle = { .name = "exynos_cpuidle", #ifdef CONFIG_ARM_EXYNOS_CPUIDLE @@ -366,7 +361,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)") .init_machine = exynos_dt_machine_init, .init_late = exynos_init_late, .dt_compat = exynos_dt_compat, - .restart = exynos_restart, .reserve = exynos_reserve, .dt_fixup = exynos_dt_fixup, MACHINE_END diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index fcb3b672e39b..ccb012009cd8 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -11,8 +11,11 @@ #include #include +#include #include #include +#include +#include #include "exynos-pmu.h" @@ -874,6 +877,13 @@ static void exynos5420_pmu_init(void) pr_info("EXYNOS5420 PMU initialized\n"); } +static int pmu_restart_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + pmu_raw_writel(0x1, EXYNOS_SWRESET); + + return NOTIFY_DONE; +} static const struct exynos_pmu_data exynos3250_pmu_data = { .pmu_config = exynos3250_pmu_config, @@ -932,11 +942,20 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = { { /*sentinel*/ }, }; +/* + * Exynos PMU restart notifier, handles restart functionality + */ +static struct notifier_block pmu_restart_handler = { + .notifier_call = pmu_restart_notify, + .priority = 128, +}; + static int exynos_pmu_probe(struct platform_device *pdev) { const struct of_device_id *match; struct device *dev = &pdev->dev; struct resource *res; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pmu_base_addr = devm_ioremap_resource(dev, res); @@ -961,6 +980,10 @@ static int exynos_pmu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pmu_context); + ret = register_restart_handler(&pmu_restart_handler); + if (ret) + dev_warn(dev, "can't register restart handler err=%d\n", ret); + dev_dbg(dev, "Exynos PMU Driver probe done\n"); return 0; } -- cgit v1.2.3-59-g8ed1b From ec336b284136610a43c9daac56d66b20d43ddf7b Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 17 Sep 2014 11:11:45 +0800 Subject: ARM: imx: replace cpu type check with ddr type check As the DDR/IO and MMDC setting are different on LPDDR2 and DDR3, we used cpu type to decide how to do these settings in suspend before which is NOT flexible, take i.MX6SL for example, although it has LPDDR2 on EVK board, but users can also use DDR3 on other boards, so it is better to read the DDR type from MMDC then decide how to do related settings. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 1 + arch/arm/mach-imx/mmdc.c | 17 +++++++++++++++++ arch/arm/mach-imx/mxc.h | 2 ++ arch/arm/mach-imx/pm-imx6.c | 10 +++------- arch/arm/mach-imx/suspend-imx6.S | 14 +++++++------- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 1dabf435c592..23c84e67a56d 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -116,6 +116,7 @@ void imx_anatop_post_resume(void); int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); void imx6q_set_int_mem_clk_lpm(bool enable); void imx6sl_set_wait_clk(bool enter); +int imx_mmdc_get_ddr_type(void); void imx_cpu_die(unsigned int cpu); int imx_cpu_kill(unsigned int cpu); diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index 7a9686ad994c..3729d90cfa46 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -21,6 +21,12 @@ #define BP_MMDC_MAPSR_PSD 0 #define BP_MMDC_MAPSR_PSS 4 +#define MMDC_MDMISC 0x18 +#define BM_MMDC_MDMISC_DDR_TYPE 0x18 +#define BP_MMDC_MDMISC_DDR_TYPE 0x3 + +static int ddr_type; + static int imx_mmdc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -31,6 +37,12 @@ static int imx_mmdc_probe(struct platform_device *pdev) mmdc_base = of_iomap(np, 0); WARN_ON(!mmdc_base); + reg = mmdc_base + MMDC_MDMISC; + /* Get ddr type */ + val = readl_relaxed(reg); + ddr_type = (val & BM_MMDC_MDMISC_DDR_TYPE) >> + BP_MMDC_MDMISC_DDR_TYPE; + reg = mmdc_base + MMDC_MAPSR; /* Enable automatic power saving */ @@ -51,6 +63,11 @@ static int imx_mmdc_probe(struct platform_device *pdev) return 0; } +int imx_mmdc_get_ddr_type(void) +{ + return ddr_type; +} + static struct of_device_id imx_mmdc_dt_ids[] = { { .compatible = "fsl,imx6q-mmdc", }, { /* sentinel */ } diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 17a41ca65acf..4c1343df2ba4 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -55,6 +55,8 @@ #define IMX_CHIP_REVISION_3_3 0x33 #define IMX_CHIP_REVISION_UNKNOWN 0xff +#define IMX_DDR_TYPE_LPDDR2 1 + #ifndef __ASSEMBLY__ extern unsigned int __mxc_cpu_type; #endif diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index 5c3af8f993d0..c653dd4c9103 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -88,7 +88,7 @@ struct imx6_pm_base { }; struct imx6_pm_socdata { - u32 cpu_type; + u32 ddr_type; const char *mmdc_compat; const char *src_compat; const char *iomuxc_compat; @@ -138,7 +138,6 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = { }; static const struct imx6_pm_socdata imx6q_pm_data __initconst = { - .cpu_type = MXC_CPU_IMX6Q, .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6q-iomuxc", @@ -148,7 +147,6 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { - .cpu_type = MXC_CPU_IMX6DL, .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6dl-iomuxc", @@ -158,7 +156,6 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { - .cpu_type = MXC_CPU_IMX6SL, .mmdc_compat = "fsl,imx6sl-mmdc", .src_compat = "fsl,imx6sl-src", .iomuxc_compat = "fsl,imx6sl-iomuxc", @@ -168,7 +165,6 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { - .cpu_type = MXC_CPU_IMX6SX, .mmdc_compat = "fsl,imx6sx-mmdc", .src_compat = "fsl,imx6sx-src", .iomuxc_compat = "fsl,imx6sx-iomuxc", @@ -187,7 +183,7 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { struct imx6_cpu_pm_info { phys_addr_t pbase; /* The physical address of pm_info. */ phys_addr_t resume_addr; /* The physical resume address for asm code */ - u32 cpu_type; + u32 ddr_type; u32 pm_info_size; /* Size of pm_info. */ struct imx6_pm_base mmdc_base; struct imx6_pm_base src_base; @@ -522,7 +518,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) goto pl310_cache_map_failed; } - pm_info->cpu_type = socdata->cpu_type; + pm_info->ddr_type = imx_mmdc_get_ddr_type(); pm_info->mmdc_io_num = socdata->mmdc_io_num; mmdc_offset_array = socdata->mmdc_io_offset; diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S index ca4ea2daf25b..b99987b023fa 100644 --- a/arch/arm/mach-imx/suspend-imx6.S +++ b/arch/arm/mach-imx/suspend-imx6.S @@ -45,7 +45,7 @@ */ #define PM_INFO_PBASE_OFFSET 0x0 #define PM_INFO_RESUME_ADDR_OFFSET 0x4 -#define PM_INFO_CPU_TYPE_OFFSET 0x8 +#define PM_INFO_DDR_TYPE_OFFSET 0x8 #define PM_INFO_PM_INFO_SIZE_OFFSET 0xC #define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 #define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 @@ -110,7 +110,7 @@ ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] - cmp r3, #MXC_CPU_IMX6SL + cmp r3, #IMX_DDR_TYPE_LPDDR2 bne 4f /* reset read FIFO, RST_RD_FIFO */ @@ -151,7 +151,7 @@ ENTRY(imx6_suspend) ldr r1, [r0, #PM_INFO_PBASE_OFFSET] ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] - ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET] + ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] /* @@ -209,8 +209,8 @@ poll_dvfs_set: ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET add r8, r8, r0 - /* i.MX6SL's last 3 IOs need special setting */ - cmp r3, #MXC_CPU_IMX6SL + /* LPDDR2's last 3 IOs need special setting */ + cmp r3, #IMX_DDR_TYPE_LPDDR2 subeq r7, r7, #0x3 set_mmdc_io_lpm: ldr r9, [r8], #0x8 @@ -218,7 +218,7 @@ set_mmdc_io_lpm: subs r7, r7, #0x1 bne set_mmdc_io_lpm - cmp r3, #MXC_CPU_IMX6SL + cmp r3, #IMX_DDR_TYPE_LPDDR2 bne set_mmdc_io_lpm_done ldr r6, =0x1000 ldr r9, [r8], #0x8 @@ -324,7 +324,7 @@ resume: str r7, [r11, #MX6Q_SRC_GPR1] str r7, [r11, #MX6Q_SRC_GPR2] - ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET] + ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] mov r5, #0x1 resume_mmdc -- cgit v1.2.3-59-g8ed1b From bc4abc3e5f40edc43e54da41b7acf8222e9cb888 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 17 Sep 2014 11:11:46 +0800 Subject: ARM: imx: add anatop settings for LPDDR2 when enter DSM mode For LPDDR2 platform, no need to enable weak2P5 in DSM mode, it can be pulled down to save power(~0.65mW). And per design team's recommendation, we should disconnect VDDHIGH and SNVS in DSM mode on i.MX6SL. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/mach-imx/anatop.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c index 8259a625a920..7f262fe4ba77 100644 --- a/arch/arm/mach-imx/anatop.c +++ b/arch/arm/mach-imx/anatop.c @@ -30,8 +30,11 @@ #define ANADIG_DIGPROG_IMX6SL 0x280 #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000 +#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8 #define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000 +/* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */ +#define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS 0x2000 #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x80000 #define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000 @@ -56,16 +59,43 @@ static void imx_anatop_enable_fet_odrive(bool enable) BM_ANADIG_REG_CORE_FET_ODRIVE); } +static inline void imx_anatop_enable_2p5_pulldown(bool enable) +{ + regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR), + BM_ANADIG_REG_2P5_ENABLE_PULLDOWN); +} + +static inline void imx_anatop_disconnect_high_snvs(bool enable) +{ + regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR), + BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS); +} + void imx_anatop_pre_suspend(void) { - imx_anatop_enable_weak2p5(true); + if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) + imx_anatop_enable_2p5_pulldown(true); + else + imx_anatop_enable_weak2p5(true); + imx_anatop_enable_fet_odrive(true); + + if (cpu_is_imx6sl()) + imx_anatop_disconnect_high_snvs(true); } void imx_anatop_post_resume(void) { + if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) + imx_anatop_enable_2p5_pulldown(false); + else + imx_anatop_enable_weak2p5(false); + imx_anatop_enable_fet_odrive(false); - imx_anatop_enable_weak2p5(false); + + if (cpu_is_imx6sl()) + imx_anatop_disconnect_high_snvs(false); + } static void imx_anatop_usb_chrg_detect_disable(void) -- cgit v1.2.3-59-g8ed1b From 2a61cba71fba5b73b11e0de665869a6ee619af0e Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 24 Sep 2014 18:20:10 +0200 Subject: ARM: vf610: Add ARM Global Timer clocksource option Add the ARM Global Timer as clocksource/scheduler clock option and use it as default scheduler clock. This leaves the PIT timer for other users e.g. the secondary Cortex-M4 core. Also, the Global Timer has double the precission (running at pheripheral clock compared to IPG clock) and a 64-bit incrementing counter register. We still keep the PIT timer as an secondary option in case the ARM Global Timer is not available. Signed-off-by: Stefan Agner Acked-by: Bill Pringlemeir Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Kconfig | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 11b2957f792b..e26b0fdd72db 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -633,12 +633,31 @@ config SOC_VF610 bool "Vybrid Family VF610 support" select ARM_GIC select PINCTRL_VF610 - select VF_PIT_TIMER select PL310_ERRATA_769419 if CACHE_L2X0 help This enable support for Freescale Vybrid VF610 processor. +choice + prompt "Clocksource for scheduler clock" + depends on SOC_VF610 + default VF_USE_ARM_GLOBAL_TIMER + + config VF_USE_ARM_GLOBAL_TIMER + bool "Use ARM Global Timer" + select ARM_GLOBAL_TIMER + select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK + help + Use the ARM Global Timer as clocksource + + config VF_USE_PIT_TIMER + bool "Use PIT timer" + select VF_PIT_TIMER + help + Use SoC Periodic Interrupt Timer (PIT) as clocksource + +endchoice + endif source "arch/arm/mach-imx/devices/Kconfig" -- cgit v1.2.3-59-g8ed1b From 49c71d1c3dccff640cc082875bd8d62988d63df9 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 24 Sep 2014 10:11:18 +0800 Subject: ARM: imx6sx: add imx6sx iomux-gpr field define Add imx6sx iomux-gpr register field define in "imx6q-iomuxc-gpr.h" header file, which is not fully define all iomux-gpr registers and fields, only align with freescale internal tree related GPR macro define. Signed-off-by: Fugang Duan Signed-off-by: Shawn Guo --- include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h index ff44374a1a4e..c877cad61a13 100644 --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h @@ -395,4 +395,43 @@ #define IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK (0x3 << 17) #define IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK (0x1 << 14) +/* For imx6sx iomux gpr register field define */ +#define IMX6SX_GPR1_VDEC_SW_RST_MASK (0x1 << 20) +#define IMX6SX_GPR1_VDEC_SW_RST_RESET (0x1 << 20) +#define IMX6SX_GPR1_VDEC_SW_RST_RELEASE (0x0 << 20) +#define IMX6SX_GPR1_VADC_SW_RST_MASK (0x1 << 19) +#define IMX6SX_GPR1_VADC_SW_RST_RESET (0x1 << 19) +#define IMX6SX_GPR1_VADC_SW_RST_RELEASE (0x0 << 19) +#define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK (0x3 << 13) +#define IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK (0x3 << 17) +#define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_EXT (0x3 << 13) + +#define IMX6SX_GPR4_FEC_ENET1_STOP_REQ (0x1 << 3) +#define IMX6SX_GPR4_FEC_ENET2_STOP_REQ (0x1 << 4) + +#define IMX6SX_GPR5_DISP_MUX_LDB_CTRL_MASK (0x1 << 3) +#define IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF1 (0x0 << 3) +#define IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF2 (0x1 << 3) + +#define IMX6SX_GPR5_CSI2_MUX_CTRL_MASK (0x3 << 27) +#define IMX6SX_GPR5_CSI2_MUX_CTRL_EXT_PIN (0x0 << 27) +#define IMX6SX_GPR5_CSI2_MUX_CTRL_CVD (0x1 << 27) +#define IMX6SX_GPR5_CSI2_MUX_CTRL_VDAC_TO_CSI (0x2 << 27) +#define IMX6SX_GPR5_CSI2_MUX_CTRL_GND (0x3 << 27) +#define IMX6SX_GPR5_VADC_TO_CSI_CAPTURE_EN_MASK (0x1 << 26) +#define IMX6SX_GPR5_VADC_TO_CSI_CAPTURE_EN_ENABLE (0x1 << 26) +#define IMX6SX_GPR5_VADC_TO_CSI_CAPTURE_EN_DISABLE (0x0 << 26) +#define IMX6SX_GPR5_CSI1_MUX_CTRL_MASK (0x3 << 4) +#define IMX6SX_GPR5_CSI1_MUX_CTRL_EXT_PIN (0x0 << 4) +#define IMX6SX_GPR5_CSI1_MUX_CTRL_CVD (0x1 << 4) +#define IMX6SX_GPR5_CSI1_MUX_CTRL_VDAC_TO_CSI (0x2 << 4) +#define IMX6SX_GPR5_CSI1_MUX_CTRL_GND (0x3 << 4) + +#define IMX6SX_GPR5_DISP_MUX_DCIC2_LCDIF2 (0x0 << 2) +#define IMX6SX_GPR5_DISP_MUX_DCIC2_LVDS (0x1 << 2) +#define IMX6SX_GPR5_DISP_MUX_DCIC2_MASK (0x1 << 2) +#define IMX6SX_GPR5_DISP_MUX_DCIC1_LCDIF1 (0x0 << 1) +#define IMX6SX_GPR5_DISP_MUX_DCIC1_LVDS (0x1 << 1) +#define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1) + #endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */ -- cgit v1.2.3-59-g8ed1b From 8f0b287e0d60521052c9c4d818f670e40f4ee0e6 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 24 Sep 2014 10:11:19 +0800 Subject: ARM: imx: add enet init for i.mx6sx Add enet init for i.mx6sx: - Add phy ar8031 fixup - Set enet clock source from internal PLL Signed-off-by: Fugang Duan Signed-off-by: Shawn Guo --- arch/arm/mach-imx/mach-imx6sx.c | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c index 3de3b7369aef..982224922fb1 100644 --- a/arch/arm/mach-imx/mach-imx6sx.c +++ b/arch/arm/mach-imx/mach-imx6sx.c @@ -8,12 +8,62 @@ #include #include +#include +#include +#include +#include #include #include #include "common.h" #include "cpuidle.h" +static int ar8031_phy_fixup(struct phy_device *dev) +{ + u16 val; + + /* Set RGMII IO voltage to 1.8V */ + phy_write(dev, 0x1d, 0x1f); + phy_write(dev, 0x1e, 0x8); + + /* introduce tx clock delay */ + phy_write(dev, 0x1d, 0x5); + val = phy_read(dev, 0x1e); + val |= 0x0100; + phy_write(dev, 0x1e, val); + + return 0; +} + +#define PHY_ID_AR8031 0x004dd074 +static void __init imx6sx_enet_phy_init(void) +{ + if (IS_BUILTIN(CONFIG_PHYLIB)) + phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, + ar8031_phy_fixup); +} + +static void __init imx6sx_enet_clk_sel(void) +{ + struct regmap *gpr; + + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr"); + if (!IS_ERR(gpr)) { + regmap_update_bits(gpr, IOMUXC_GPR1, + IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK, 0); + regmap_update_bits(gpr, IOMUXC_GPR1, + IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK, 0); + } else { + pr_err("failed to find fsl,imx6sx-iomux-gpr regmap\n"); + } +} + +static inline void imx6sx_enet_init(void) +{ + imx6sx_enet_phy_init(); + imx6sx_enet_clk_sel(); +} + static void __init imx6sx_init_machine(void) { struct device *parent; @@ -26,6 +76,7 @@ static void __init imx6sx_init_machine(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); + imx6sx_enet_init(); imx_anatop_init(); imx6sx_pm_init(); } -- cgit v1.2.3-59-g8ed1b From 6f0628aa9f0fb7c877e52d4d8c6edb11bcd91736 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 26 Sep 2014 15:41:00 +0200 Subject: ARM: imx5: add step clock, used when reprogramming PLL1 This is the bypass clock used to feed the ARM partition while we reprogram PLL1 to another rate. Signed-off-by: Philipp Zabel Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx51-imx53.c | 9 ++++++++- include/dt-bindings/clock/imx5-clock.h | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 72d65214223e..aafccf4b47c2 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -125,6 +125,8 @@ static const char *mx53_spdif_xtal_sel[] = { "osc", "ckih", "ckih2", "pll4_sw", static const char *spdif_sel[] = { "pll1_sw", "pll2_sw", "pll3_sw", "spdif_xtal_sel", }; static const char *spdif0_com_sel[] = { "spdif0_podf", "ssi1_root_gate", }; static const char *mx51_spdif1_com_sel[] = { "spdif1_podf", "ssi2_root_gate", }; +static const char *step_sels[] = { "lp_apm", }; +static const char *cpu_podf_sels[] = { "pll1_sw", "step_sel" }; static struct clk *clk[IMX5_CLK_END]; static struct clk_onecell_data clk_data; @@ -193,7 +195,9 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_USB_PHY_PODF] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", MXC_CCM_CDCDR, 0, 3); clk[IMX5_CLK_USB_PHY_SEL] = imx_clk_mux("usb_phy_sel", MXC_CCM_CSCMR1, 26, 1, usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str)); - clk[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", "pll1_sw", MXC_CCM_CACRR, 0, 3); + clk[IMX5_CLK_STEP_SEL] = imx_clk_mux("step_sel", MXC_CCM_CCSR, 7, 2, step_sels, ARRAY_SIZE(step_sels)); + clk[IMX5_CLK_CPU_PODF_SEL] = imx_clk_mux("cpu_podf_sel", MXC_CCM_CCSR, 2, 1, cpu_podf_sels, ARRAY_SIZE(cpu_podf_sels)); + clk[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", "cpu_podf_sel", MXC_CCM_CACRR, 0, 3); clk[IMX5_CLK_DI_PRED] = imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3); clk[IMX5_CLK_IIM_GATE] = imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30); clk[IMX5_CLK_UART1_IPG_GATE] = imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6); @@ -551,6 +555,9 @@ static void __init mx53_clocks_init(struct device_node *np) /* move can bus clk to 24MHz */ clk_set_parent(clk[IMX5_CLK_CAN_SEL], clk[IMX5_CLK_LP_APM]); + /* make sure step clock is running from 24MHz */ + clk_set_parent(clk[IMX5_CLK_STEP_SEL], clk[IMX5_CLK_LP_APM]); + clk_prepare_enable(clk[IMX5_CLK_IIM_GATE]); imx_print_silicon_rev("i.MX53", mx53_revision()); clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]); diff --git a/include/dt-bindings/clock/imx5-clock.h b/include/dt-bindings/clock/imx5-clock.h index 5f2667ecd98e..1a36ff4ace1e 100644 --- a/include/dt-bindings/clock/imx5-clock.h +++ b/include/dt-bindings/clock/imx5-clock.h @@ -198,6 +198,8 @@ #define IMX5_CLK_OCRAM 186 #define IMX5_CLK_SAHARA_IPG_GATE 187 #define IMX5_CLK_SATA_REF 188 -#define IMX5_CLK_END 189 +#define IMX5_CLK_STEP_SEL 189 +#define IMX5_CLK_CPU_PODF_SEL 190 +#define IMX5_CLK_END 191 #endif /* __DT_BINDINGS_CLOCK_IMX5_H */ -- cgit v1.2.3-59-g8ed1b From e0fed5133cc3656319e94c258e4a064dca8ccb27 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 26 Sep 2014 15:41:01 +0200 Subject: ARM: imx: add CPU clock type This implements a virtual clock used to abstract away all the steps needed in order to change the ARM clock, so we don't have to push all this clock handling into the cpufreq driver. While it will be used for i.MX53 at first it is generic enough to be used on i.MX6 later on. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 2 +- arch/arm/mach-imx/clk-cpu.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-imx/clk.h | 4 ++ 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/clk-cpu.c diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 6e4fcd8339cd..b8580f363e51 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci- obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o imx5-pm-$(CONFIG_PM) += pm-imx5.o -obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o $(imx5-pm-y) +obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o clk-cpu.o $(imx5-pm-y) obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ clk-pfd.o clk-busy.o clk.o \ diff --git a/arch/arm/mach-imx/clk-cpu.c b/arch/arm/mach-imx/clk-cpu.c new file mode 100644 index 000000000000..aa1c345e2a19 --- /dev/null +++ b/arch/arm/mach-imx/clk-cpu.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014 Lucas Stach , Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include + +struct clk_cpu { + struct clk_hw hw; + struct clk *div; + struct clk *mux; + struct clk *pll; + struct clk *step; +}; + +static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw) +{ + return container_of(hw, struct clk_cpu, hw); +} + +static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_cpu *cpu = to_clk_cpu(hw); + + return clk_get_rate(cpu->div); +} + +static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_cpu *cpu = to_clk_cpu(hw); + + return clk_round_rate(cpu->pll, rate); +} + +static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_cpu *cpu = to_clk_cpu(hw); + int ret; + + /* switch to PLL bypass clock */ + ret = clk_set_parent(cpu->mux, cpu->step); + if (ret) + return ret; + + /* reprogram PLL */ + ret = clk_set_rate(cpu->pll, rate); + if (ret) { + clk_set_parent(cpu->mux, cpu->pll); + return ret; + } + /* switch back to PLL clock */ + clk_set_parent(cpu->mux, cpu->pll); + + /* Ensure the divider is what we expect */ + clk_set_rate(cpu->div, rate); + + return 0; +} + +static const struct clk_ops clk_cpu_ops = { + .recalc_rate = clk_cpu_recalc_rate, + .round_rate = clk_cpu_round_rate, + .set_rate = clk_cpu_set_rate, +}; + +struct clk *imx_clk_cpu(const char *name, const char *parent_name, + struct clk *div, struct clk *mux, struct clk *pll, + struct clk *step) +{ + struct clk_cpu *cpu; + struct clk *clk; + struct clk_init_data init; + + cpu = kzalloc(sizeof(*cpu), GFP_KERNEL); + if (!cpu) + return ERR_PTR(-ENOMEM); + + cpu->div = div; + cpu->mux = mux; + cpu->pll = pll; + cpu->step = step; + + init.name = name; + init.ops = &clk_cpu_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + cpu->hw.init = &init; + + clk = clk_register(NULL, &cpu->hw); + if (IS_ERR(clk)) + kfree(cpu); + + return clk; +} diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 4cdf8b6a74e8..5ef82e2f8fc5 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h @@ -131,4 +131,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name, CLK_SET_RATE_PARENT, mult, div); } +struct clk *imx_clk_cpu(const char *name, const char *parent_name, + struct clk *div, struct clk *mux, struct clk *pll, + struct clk *step); + #endif -- cgit v1.2.3-59-g8ed1b From 82a40b54820601aad0facf72050c62ae7fc7d4df Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 26 Sep 2014 15:41:02 +0200 Subject: ARM: imx53: clk: add ARM clock The ARM clock is a virtual clock feeding the ARM partition of the SoC. It controls multiple other clocks to ensure the right sequencing when cpufreq changes the CPU clock rate. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx51-imx53.c | 5 +++++ include/dt-bindings/clock/imx5-clock.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index aafccf4b47c2..0f7e536147cb 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -541,6 +541,11 @@ static void __init mx53_clocks_init(struct device_node *np) clk[IMX5_CLK_CKO2] = imx_clk_gate2("cko2", "cko2_podf", MXC_CCM_CCOSR, 24); clk[IMX5_CLK_SPDIF_XTAL_SEL] = imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2, mx53_spdif_xtal_sel, ARRAY_SIZE(mx53_spdif_xtal_sel)); + clk[IMX5_CLK_ARM] = imx_clk_cpu("arm", "cpu_podf", + clk[IMX5_CLK_CPU_PODF], + clk[IMX5_CLK_CPU_PODF_SEL], + clk[IMX5_CLK_PLL1_SW], + clk[IMX5_CLK_STEP_SEL]); imx_check_clocks(clk, ARRAY_SIZE(clk)); diff --git a/include/dt-bindings/clock/imx5-clock.h b/include/dt-bindings/clock/imx5-clock.h index 1a36ff4ace1e..f4b7478e23c8 100644 --- a/include/dt-bindings/clock/imx5-clock.h +++ b/include/dt-bindings/clock/imx5-clock.h @@ -200,6 +200,7 @@ #define IMX5_CLK_SATA_REF 188 #define IMX5_CLK_STEP_SEL 189 #define IMX5_CLK_CPU_PODF_SEL 190 -#define IMX5_CLK_END 191 +#define IMX5_CLK_ARM 191 +#define IMX5_CLK_END 192 #endif /* __DT_BINDINGS_CLOCK_IMX5_H */ -- cgit v1.2.3-59-g8ed1b From 9a31634d4641c14227bd6105c538ab335616463d Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 26 Sep 2014 15:41:04 +0200 Subject: ARM: imx53: add cpufreq support Instanciate device for the generic cpufreq-dt driver. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- arch/arm/mach-imx/mach-imx53.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-imx/mach-imx53.c b/arch/arm/mach-imx/mach-imx53.c index 03dd6ea13acc..7587cf0cba3e 100644 --- a/arch/arm/mach-imx/mach-imx53.c +++ b/arch/arm/mach-imx/mach-imx53.c @@ -41,6 +41,8 @@ static void __init imx53_dt_init(void) static void __init imx53_init_late(void) { imx53_pm_init(); + + platform_device_register_simple("cpufreq-dt", -1, NULL, 0); } static const char * const imx53_dt_board_compat[] __initconst = { -- cgit v1.2.3-59-g8ed1b From 7f0fb6104b3a9c48d7b253d3984d3a619bb1e654 Mon Sep 17 00:00:00 2001 From: Jingchang Lu Date: Fri, 31 Oct 2014 17:01:12 +0800 Subject: ARM: imx: Add initial support for Freescale LS1021A The LS1021A SoC is a dual-core Cortex-A7 based processor, this adds the initial support for it. Signed-off-by: Jingchang Lu Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Kconfig | 14 ++++++++++++++ arch/arm/mach-imx/Makefile | 2 ++ arch/arm/mach-imx/mach-ls1021a.c | 21 +++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 arch/arm/mach-imx/mach-ls1021a.c diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index e26b0fdd72db..ef549ef1cd6d 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -658,6 +658,20 @@ choice endchoice +config FSL_SOC + bool + +config SOC_LS1021A + bool "Freescale LS1021A support" + select ARM_GIC + select HAVE_ARM_ARCH_TIMER + select FSL_SOC + select PCI_DOMAINS if PCI + select ZONE_DMA if ARM_LPAE + + help + This enable support for Freescale LS1021A processor. + endif source "arch/arm/mach-imx/devices/Kconfig" diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index b8580f363e51..19dc7bfa8a8c 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -110,4 +110,6 @@ obj-$(CONFIG_SOC_IMX53) += mach-imx53.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o +obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o + obj-y += devices/ diff --git a/arch/arm/mach-imx/mach-ls1021a.c b/arch/arm/mach-imx/mach-ls1021a.c new file mode 100644 index 000000000000..9d2034b1a150 --- /dev/null +++ b/arch/arm/mach-imx/mach-ls1021a.c @@ -0,0 +1,21 @@ +/* + * Copyright 2013-2014 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +#include "common.h" + +static const char * const ls1021a_dt_compat[] __initconst = { + "fsl,ls1021a", + NULL, +}; + +DT_MACHINE_START(LS1021A, "Freescale LS1021A") + .dt_compat = ls1021a_dt_compat, +MACHINE_END -- cgit v1.2.3-59-g8ed1b From 4e3fea4a950e3ec22ec8f99a7438aa5ba584263a Mon Sep 17 00:00:00 2001 From: Jingchang Lu Date: Fri, 31 Oct 2014 17:01:13 +0800 Subject: ARM: imx: Add Freescale LS1021A SMP support Freescale LS1021A SoCs deploy two cortex-A7 processors, this adds bring-up support for the secondary core. Signed-off-by: Jingchang Lu Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 2 +- arch/arm/mach-imx/common.h | 1 + arch/arm/mach-imx/mach-ls1021a.c | 1 + arch/arm/mach-imx/platsmp.c | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 19dc7bfa8a8c..f5ac685a29fc 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -89,7 +89,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o -ifdef CONFIG_SOC_IMX6 +ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),) AFLAGS_headsmp.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 23c84e67a56d..fe9a908da3ed 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -158,5 +158,6 @@ static inline void imx_init_l2cache(void) {} #endif extern struct smp_operations imx_smp_ops; +extern struct smp_operations ls1021a_smp_ops; #endif diff --git a/arch/arm/mach-imx/mach-ls1021a.c b/arch/arm/mach-imx/mach-ls1021a.c index 9d2034b1a150..b89c858ebfd6 100644 --- a/arch/arm/mach-imx/mach-ls1021a.c +++ b/arch/arm/mach-imx/mach-ls1021a.c @@ -17,5 +17,6 @@ static const char * const ls1021a_dt_compat[] __initconst = { }; DT_MACHINE_START(LS1021A, "Freescale LS1021A") + .smp = smp_ops(ls1021a_smp_ops), .dt_compat = ls1021a_dt_compat, MACHINE_END diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index 771bd25c1025..7f270015fe58 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -11,7 +11,10 @@ */ #include +#include +#include #include + #include #include #include @@ -94,3 +97,33 @@ struct smp_operations imx_smp_ops __initdata = { .cpu_kill = imx_cpu_kill, #endif }; + +#define DCFG_CCSR_SCRATCHRW1 0x200 + +static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + return 0; +} + +static void __init ls1021a_smp_prepare_cpus(unsigned int max_cpus) +{ + struct device_node *np; + void __iomem *dcfg_base; + unsigned long paddr; + + np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg"); + dcfg_base = of_iomap(np, 0); + BUG_ON(!dcfg_base); + + paddr = virt_to_phys(secondary_startup); + writel_relaxed(cpu_to_be32(paddr), dcfg_base + DCFG_CCSR_SCRATCHRW1); + + iounmap(dcfg_base); +} + +struct smp_operations ls1021a_smp_ops __initdata = { + .smp_prepare_cpus = ls1021a_smp_prepare_cpus, + .smp_boot_secondary = ls1021a_boot_secondary, +}; -- cgit v1.2.3-59-g8ed1b From a41820d690379a4eb4b72a3ddd553aac7ed4eb6a Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sun, 2 Nov 2014 21:36:45 +0100 Subject: ARM: imx: clk-vf610: get input clocks from assigned clocks With the clock assignment device tree changes, the clocks get initialized properly but the search for those clocks fails with errors: [ 0.000000] i.MX clk 4: register failed with -17 [ 0.000000] i.MX clk 5: register failed with -17 This is because the module can't find those clocks anymore, and tries to initialize fixed clocks with the same name. Get the clock modules input clocks from the assigned clocks by default by using of_clk_get_by_name(). If this function returns not a valid clock, fall back to the old behaviour and search the input clock from the device tree's /clocks/$name node. Signed-off-by: Stefan Agner Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-vf610.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c index 409637254594..5937ddee1a99 100644 --- a/arch/arm/mach-imx/clk-vf610.c +++ b/arch/arm/mach-imx/clk-vf610.c @@ -120,6 +120,17 @@ static unsigned int const clks_init_on[] __initconst = { VF610_CLK_DDR_SEL, }; +static struct clk * __init vf610_get_fixed_clock( + struct device_node *ccm_node, const char *name) +{ + struct clk *clk = of_clk_get_by_name(ccm_node, name); + + /* Backward compatibility if device tree is missing clks assignments */ + if (IS_ERR(clk)) + clk = imx_obtain_fixed_clock(name, 0); + return clk; +}; + static void __init vf610_clocks_init(struct device_node *ccm_node) { struct device_node *np; @@ -130,13 +141,13 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_SIRC_32K] = imx_clk_fixed("sirc_32k", 32000); clk[VF610_CLK_FIRC] = imx_clk_fixed("firc", 24000000); - clk[VF610_CLK_SXOSC] = imx_obtain_fixed_clock("sxosc", 0); - clk[VF610_CLK_FXOSC] = imx_obtain_fixed_clock("fxosc", 0); - clk[VF610_CLK_AUDIO_EXT] = imx_obtain_fixed_clock("audio_ext", 0); - clk[VF610_CLK_ENET_EXT] = imx_obtain_fixed_clock("enet_ext", 0); + clk[VF610_CLK_SXOSC] = vf610_get_fixed_clock(ccm_node, "sxosc"); + clk[VF610_CLK_FXOSC] = vf610_get_fixed_clock(ccm_node, "fxosc"); + clk[VF610_CLK_AUDIO_EXT] = vf610_get_fixed_clock(ccm_node, "audio_ext"); + clk[VF610_CLK_ENET_EXT] = vf610_get_fixed_clock(ccm_node, "enet_ext"); /* Clock source from external clock via LVDs PAD */ - clk[VF610_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0); + clk[VF610_CLK_ANACLK1] = vf610_get_fixed_clock(ccm_node, "anaclk1"); clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half", "fxosc", 1, 2); -- cgit v1.2.3-59-g8ed1b From cfd074ad860016d3aafd28a06b03d575d17aac0a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 11 Nov 2014 17:03:25 +0100 Subject: ARM: imx: temporarily remove CONFIG_SOC_FSL from LS1021A The newly introduced LS1021A SoC selects CONFIG_SOC_FSL, which is originally symbol used for the PowerPC based platforms and guards lots of code that does not build on ARM. This breaks allmodconfig, so let's remove it for now, until either all those drivers are fixed or they use a dependency on IMX instead. Signed-off-by: Arnd Bergmann Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index ef549ef1cd6d..e8627e04e1e6 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -658,14 +658,10 @@ choice endchoice -config FSL_SOC - bool - config SOC_LS1021A bool "Freescale LS1021A support" select ARM_GIC select HAVE_ARM_ARCH_TIMER - select FSL_SOC select PCI_DOMAINS if PCI select ZONE_DMA if ARM_LPAE -- cgit v1.2.3-59-g8ed1b From 3db47dc0ae4d370ec3c86fc357608132ca695c27 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Wed, 12 Nov 2014 16:20:38 +0800 Subject: power: reset: imx-snvs-poweroff: add power off driver for i.mx6 This driver register pm_power_off with snvs power off function. If your boards NOT use PMIC_ON_REQ to turn on/off external pmic, or use other pin to do, please disable the driver in dts, otherwise, your pm_power_off maybe overwrote by this driver. Signed-off-by: Robin Gong Acked-By: Sebastian Reichel Signed-off-by: Shawn Guo --- .../bindings/power_supply/imx-snvs-poweroff.txt | 23 ++++++++ drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile | 1 + drivers/power/reset/imx-snvs-poweroff.c | 66 ++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt create mode 100644 drivers/power/reset/imx-snvs-poweroff.c diff --git a/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt b/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt new file mode 100644 index 000000000000..dc7c9bad63ea --- /dev/null +++ b/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt @@ -0,0 +1,23 @@ +i.mx6 Poweroff Driver + +SNVS_LPCR in SNVS module can power off the whole system by pull +PMIC_ON_REQ low if PMIC_ON_REQ is connected with external PMIC. +If you don't want to use PMIC_ON_REQ as power on/off control, +please set status='disabled' to disable this driver. + +Required Properties: +-compatible: "fsl,sec-v4.0-poweroff" +-reg: Specifies the physical address of the SNVS_LPCR register + +Example: + snvs@020cc000 { + compatible = "fsl,sec-v4.0-mon", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x020cc000 0x4000>; + ..... + snvs_poweroff: snvs-poweroff@38 { + compatible = "fsl,sec-v4.0-poweroff"; + reg = <0x38 0x4>; + }; + } diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index f65ff49bb275..028e76504519 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -71,6 +71,15 @@ config POWER_RESET_HISI help Reboot support for Hisilicon boards. +config POWER_RESET_IMX + bool "IMX6 power-off driver" + depends on POWER_RESET && SOC_IMX6 + help + This driver support power off external PMIC by PMIC_ON_REQ on i.mx6 + boards.If you want to use other pin to control external power,please + say N here or disable in dts to make sure pm_power_off never be + overwrote wrongly by this driver. + config POWER_RESET_MSM bool "Qualcomm MSM power-off driver" depends on ARCH_QCOM diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 76ce1c59469b..1d4804d6b323 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o +obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o diff --git a/drivers/power/reset/imx-snvs-poweroff.c b/drivers/power/reset/imx-snvs-poweroff.c new file mode 100644 index 000000000000..ad6ce5020ea7 --- /dev/null +++ b/drivers/power/reset/imx-snvs-poweroff.c @@ -0,0 +1,66 @@ +/* Power off driver for i.mx6 + * Copyright (c) 2014, FREESCALE CORPORATION. All rights reserved. + * + * based on msm-poweroff.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void __iomem *snvs_base; + +static void do_imx_poweroff(void) +{ + u32 value = readl(snvs_base); + + /* set TOP and DP_EN bit */ + writel(value | 0x60, snvs_base); +} + +static int imx_poweroff_probe(struct platform_device *pdev) +{ + snvs_base = of_iomap(pdev->dev.of_node, 0); + if (!snvs_base) { + dev_err(&pdev->dev, "failed to get memory\n"); + return -ENODEV; + } + + pm_power_off = do_imx_poweroff; + return 0; +} + +static const struct of_device_id of_imx_poweroff_match[] = { + { .compatible = "fsl,sec-v4.0-poweroff", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_imx_poweroff_match); + +static struct platform_driver imx_poweroff_driver = { + .probe = imx_poweroff_probe, + .driver = { + .name = "imx-snvs-poweroff", + .of_match_table = of_match_ptr(of_imx_poweroff_match), + }, +}; + +static int __init imx_poweroff_init(void) +{ + return platform_driver_register(&imx_poweroff_driver); +} +device_initcall(imx_poweroff_init); -- cgit v1.2.3-59-g8ed1b From b04fa9f704aa818b87509ff4149bba810ef8bbd8 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 27 Nov 2014 02:47:05 +0900 Subject: ARM: EXYNOS: use u8 for val[] in struct exynos_pmu_conf Values stored in val[] are never bigger than a byte. text data bss dec hex filename 7716 3692 8 11416 2c98 arch/arm/mach-exynos/pmu.o.before 5436 1908 8 7352 1cb8 arch/arm/mach-exynos/pmu.o.after Cc: Pankaj Dubey Cc: Amit Daniel Kachhap Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index ccb012009cd8..c15761ca2f18 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -25,7 +25,7 @@ struct exynos_pmu_conf { unsigned int offset; - unsigned int val[NUM_SYS_POWERDOWN]; + u8 val[NUM_SYS_POWERDOWN]; }; struct exynos_pmu_data { -- cgit v1.2.3-59-g8ed1b From d9bfc86dc69af78fb42fe075f9f2576880fd22a4 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 24 Nov 2014 12:08:27 +0100 Subject: ARM: add mach-asm9260 it is low cost (?) SoC targeted for market in China and India which trying to compete with AT91SAM9G25. Here is some info: http://www.alphascale.com/index.asp?ics/615.html One of products: http://www.aliexpress.com/store/product/2014-hot-sales-FREE-SHIPPING-new-Purple-core-ARM9-development-board-ASM9260T-SDRAM-power-line/433637_1931495721.html In some cases this SoC looks similar to iMX23/iMX28. But currently it makes no sense to merge mach code of this devices. Especially because most differences are already collected mach-mxs folder. Signed-off-by: Oleksij Rempel Signed-off-by: Arnd Bergmann --- arch/arm/Kconfig | 2 ++ arch/arm/mach-asm9260/Kconfig | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 arch/arm/mach-asm9260/Kconfig diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2075ebdccf5d..b9bde0c337b1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -836,6 +836,8 @@ config ARCH_VIRT # source "arch/arm/mach-mvebu/Kconfig" +source "arch/arm/mach-asm9260/Kconfig" + source "arch/arm/mach-at91/Kconfig" source "arch/arm/mach-axxia/Kconfig" diff --git a/arch/arm/mach-asm9260/Kconfig b/arch/arm/mach-asm9260/Kconfig new file mode 100644 index 000000000000..8423be76080e --- /dev/null +++ b/arch/arm/mach-asm9260/Kconfig @@ -0,0 +1,6 @@ +config MACH_ASM9260 + bool "Alphascale ASM9260" + depends on ARCH_MULTI_V5 + select CPU_ARM926T + help + Support for Alphascale ASM9260 based platform. -- cgit v1.2.3-59-g8ed1b From d5bd4e8df43ca930ff3892963f6b3bf7984038e3 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 24 Nov 2014 12:08:28 +0100 Subject: ARM: add lolevel debug support for asm9260 Since there is no public documentation, this patch also provide register offsets for different UART units on this SoC. Signed-off-by: Oleksij Rempel Signed-off-by: Arnd Bergmann --- arch/arm/Kconfig.debug | 28 ++++++++++++++++++++++++++-- arch/arm/include/debug/asm9260.S | 29 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 arch/arm/include/debug/asm9260.S diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index e4917aebc31f..66ebfb88c505 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -93,6 +93,27 @@ choice prompt "Kernel low-level debugging port" depends on DEBUG_LL + config DEBUG_ASM9260_UART + bool "Kernel low-level debugging via asm9260 UART" + depends on MACH_ASM9260 + help + Say Y here if you want the debug print routines to direct + their output to an UART or USART port on asm9260 based + machines. + + DEBUG_UART_PHYS | DEBUG_UART_VIRT + + 0x80000000 | 0xf0000000 | UART0 + 0x80004000 | 0xf0004000 | UART1 + 0x80008000 | 0xf0008000 | UART2 + 0x8000c000 | 0xf000c000 | UART3 + 0x80010000 | 0xf0010000 | UART4 + 0x80014000 | 0xf0014000 | UART5 + 0x80018000 | 0xf0018000 | UART6 + 0x8001c000 | 0xf001c000 | UART7 + 0x80020000 | 0xf0020000 | UART8 + 0x80024000 | 0xf0024000 | UART9 + config AT91_DEBUG_LL_DBGU0 bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10 and 9rl" depends on HAVE_AT91_DBGU0 @@ -1144,6 +1165,7 @@ config DEBUG_LL_INCLUDE string default "debug/sa1100.S" if DEBUG_SA1100 default "debug/8250.S" if DEBUG_LL_UART_8250 || DEBUG_UART_8250 + default "debug/asm9260.S" if DEBUG_ASM9260_UART default "debug/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2 default "debug/meson.S" if DEBUG_MESON_UARTAO default "debug/pl01x.S" if DEBUG_LL_UART_PL01X || DEBUG_UART_PL01X @@ -1248,6 +1270,7 @@ config DEBUG_UART_PHYS default 0x78000000 if DEBUG_CNS3XXX default 0x7c0003f8 if FOOTBRIDGE default 0x78000000 if DEBUG_CNS3XXX + default 0x80010000 if DEBUG_ASM9260_UART default 0x80070000 if DEBUG_IMX23_UART default 0x80074000 if DEBUG_IMX28_UART default 0x80230000 if DEBUG_PICOXCELL_UART @@ -1297,13 +1320,14 @@ config DEBUG_UART_PHYS DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \ DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \ - DEBUG_UART_BCM63XX + DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART config DEBUG_UART_VIRT hex "Virtual base address of debug UART" default 0xe0010fe0 if ARCH_RPC default 0xe1000000 if DEBUG_MSM_UART default 0xf0000be0 if ARCH_EBSA110 + default 0xf0010000 if DEBUG_ASM9260_UART default 0xf01fb000 if DEBUG_NOMADIK_UART default 0xf0201000 if DEBUG_BCM2835 default 0xf1000300 if DEBUG_BCM_5301X @@ -1374,7 +1398,7 @@ config DEBUG_UART_VIRT depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ - DEBUG_UART_BCM63XX + DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART config DEBUG_UART_8250_SHIFT int "Register offset shift for the 8250 debug UART" diff --git a/arch/arm/include/debug/asm9260.S b/arch/arm/include/debug/asm9260.S new file mode 100644 index 000000000000..292f85b49fca --- /dev/null +++ b/arch/arm/include/debug/asm9260.S @@ -0,0 +1,29 @@ +/* Debugging macro include header + * + * Copyright (C) 1994-1999 Russell King + * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks + * Modified for ASM9260 by Oleksij Remepl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + + .macro addruart, rp, rv, tmp + ldr \rp, = CONFIG_DEBUG_UART_PHYS + ldr \rv, = CONFIG_DEBUG_UART_VIRT + .endm + + .macro waituart,rd,rx + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x50] @ TXDATA + .endm + + .macro busyuart,rd,rx +1002: ldr \rd, [\rx, #0x60] @ STAT + tst \rd, #1 << 27 @ TXEMPTY + beq 1002b @ wait until transmit done + .endm -- cgit v1.2.3-59-g8ed1b From 0f077eb5cfaf453ad7379963a721b8c04f7c62a2 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:00 +0100 Subject: irqchip: armada-370-xp: Add suspend/resume support This commit adds suspend/resume support to the irqchip driver used on Armada XP platforms (amongst others). It does so by adding a set of suspend/resume syscore_ops, that will respectively save and restore the necessary registers to ensure interrupts continue to work after resume. It is worth mentioning that the affinity is lost during a suspend/resume cycle, because when a secondary CPU is brought off-line, all interrupts that are assigned to this CPU in terms of affinity gets re-assigned to a still running CPU. Therefore, right before entering suspend, all interrupts are assigned to the boot CPU. Signed-off-by: Thomas Petazzoni Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-kernel@vger.kernel.org Link: https://lkml.kernel.org/r/1416585613-2113-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- drivers/irqchip/irq-armada-370-xp.c | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 3e238cd049e6..4ec137bba7f6 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ static void __iomem *per_cpu_int_base; static void __iomem *main_int_base; static struct irq_domain *armada_370_xp_mpic_domain; +static u32 doorbell_mask_reg; #ifdef CONFIG_PCI_MSI static struct irq_domain *armada_370_xp_msi_domain; static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); @@ -474,6 +476,54 @@ armada_370_xp_handle_irq(struct pt_regs *regs) } while (1); } +static int armada_370_xp_mpic_suspend(void) +{ + doorbell_mask_reg = readl(per_cpu_int_base + + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); + return 0; +} + +static void armada_370_xp_mpic_resume(void) +{ + int nirqs; + irq_hw_number_t irq; + + /* Re-enable interrupts */ + nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff; + for (irq = 0; irq < nirqs; irq++) { + struct irq_data *data; + int virq; + + virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq); + if (virq == 0) + continue; + + if (irq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) + writel(irq, per_cpu_int_base + + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + else + writel(irq, main_int_base + + ARMADA_370_XP_INT_SET_ENABLE_OFFS); + + data = irq_get_irq_data(virq); + if (!irqd_irq_disabled(data)) + armada_370_xp_irq_unmask(data); + } + + /* Reconfigure doorbells for IPIs and MSIs */ + writel(doorbell_mask_reg, + per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); + if (doorbell_mask_reg & IPI_DOORBELL_MASK) + writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); + if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK) + writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); +} + +struct syscore_ops armada_370_xp_mpic_syscore_ops = { + .suspend = armada_370_xp_mpic_suspend, + .resume = armada_370_xp_mpic_resume, +}; + static int __init armada_370_xp_mpic_of_init(struct device_node *node, struct device_node *parent) { @@ -530,6 +580,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node, armada_370_xp_mpic_handle_cascade_irq); } + register_syscore_ops(&armada_370_xp_mpic_syscore_ops); + return 0; } -- cgit v1.2.3-59-g8ed1b From f9a49ab53a269fda39ae57063bd336b4bd62fa76 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:01 +0100 Subject: clocksource: time-armada-370-xp: add suspend/resume support This commit adds a set of suspend/resume syscore_ops to respectively save and restore a number of timer registers, in order to make sure the clockevent and clocksource devices continue to work properly across a suspend/resume cycle. Signed-off-by: Thomas Petazzoni Cc: Daniel Lezcano Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Acked-by: Daniel Lezcano Link: https://lkml.kernel.org/r/1416585613-2113-5-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- drivers/clocksource/time-armada-370-xp.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 0451e62fac7a..ff37d3abb806 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -43,6 +43,7 @@ #include #include #include +#include /* * Timer block registers. @@ -223,6 +224,28 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = { .notifier_call = armada_370_xp_timer_cpu_notify, }; +static u32 timer0_ctrl_reg, timer0_local_ctrl_reg; + +static int armada_370_xp_timer_suspend(void) +{ + timer0_ctrl_reg = readl(timer_base + TIMER_CTRL_OFF); + timer0_local_ctrl_reg = readl(local_base + TIMER_CTRL_OFF); + return 0; +} + +static void armada_370_xp_timer_resume(void) +{ + writel(0xffffffff, timer_base + TIMER0_VAL_OFF); + writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); + writel(timer0_ctrl_reg, timer_base + TIMER_CTRL_OFF); + writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF); +} + +struct syscore_ops armada_370_xp_timer_syscore_ops = { + .suspend = armada_370_xp_timer_suspend, + .resume = armada_370_xp_timer_resume, +}; + static void __init armada_370_xp_timer_common_init(struct device_node *np) { u32 clr = 0, set = 0; @@ -285,6 +308,8 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np) /* Immediately configure the timer on the boot CPU */ if (!res) armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); + + register_syscore_ops(&armada_370_xp_timer_syscore_ops); } static void __init armada_xp_timer_init(struct device_node *np) -- cgit v1.2.3-59-g8ed1b From a0e89c02da974838053a3604025e43600dc6ac45 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:03 +0100 Subject: bus: mvebu-mbus: suspend/resume support This commit extends the mvebu-mbus driver to provide suspend/resume support. Since mvebu-mbus is not a platform_driver, the syscore_ops mechanism is used to get ->suspend() and ->resume() hooks called into the driver. In those hooks, we save and restore the MBus windows state, to make sure after resume all Mbus windows are properly restored. Note that while the state of some windows could be gathered by looking again at the Device Tree (for statically described windows), it is not the case of dynamically described windows such as the PCIe memory and I/O windows. Therefore, we take the simple approach of saving and restoring the registers for all MBus windows. In addition, the commit extends the Device Tree binding of the MBus controller, to control the MBus bridge registers (which define which parts of the physical address space is routed to MBus windows vs. normal RAM memory). Those registers must be saved and restored during suspend/resume. The Device Tree binding extension is made is a backward compatible fashion, but of course, suspend/resume will not work without the Device Tree update. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1416585613-2113-7-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- .../devicetree/bindings/bus/mvebu-mbus.txt | 17 +-- drivers/bus/mvebu-mbus.c | 124 ++++++++++++++++++++- 2 files changed, 130 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt index 5fa44f52a0b8..5e16c3ccb061 100644 --- a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt +++ b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt @@ -48,9 +48,12 @@ Required properties: - compatible: Should be set to "marvell,mbus-controller". - reg: Device's register space. - Two entries are expected (see the examples below): - the first one controls the devices decoding window and - the second one controls the SDRAM decoding window. + Two or three entries are expected (see the examples below): + the first one controls the devices decoding window, + the second one controls the SDRAM decoding window and + the third controls the MBus bridge (only with the + marvell,armada370-mbus and marvell,armadaxp-mbus + compatible strings) Example: @@ -67,7 +70,7 @@ Example: mbusc: mbus-controller@20000 { compatible = "marvell,mbus-controller"; - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; }; /* more children ...*/ @@ -126,7 +129,7 @@ are skipped. mbusc: mbus-controller@20000 { compatible = "marvell,mbus-controller"; - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; }; /* more children ...*/ @@ -170,7 +173,7 @@ Using this macro, the above example would be: mbusc: mbus-controller@20000 { compatible = "marvell,mbus-controller"; - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; }; /* other children */ @@ -266,7 +269,7 @@ See the example below, where a more complete device tree is shown: ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>; mbusc: mbus-controller@20000 { - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; }; interrupt-controller@20000 { diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index 26c3779d871d..e8c159399c82 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -57,6 +57,7 @@ #include #include #include +#include /* * DDR target is the same on all platforms. @@ -94,20 +95,39 @@ #define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4) +/* Relative to mbusbridge_base */ +#define MBUS_BRIDGE_CTRL_OFF 0x0 +#define MBUS_BRIDGE_BASE_OFF 0x4 + +/* Maximum number of windows, for all known platforms */ +#define MBUS_WINS_MAX 20 + struct mvebu_mbus_state; struct mvebu_mbus_soc_data { unsigned int num_wins; unsigned int num_remappable_wins; + bool has_mbus_bridge; unsigned int (*win_cfg_offset)(const int win); void (*setup_cpu_target)(struct mvebu_mbus_state *s); int (*show_cpu_target)(struct mvebu_mbus_state *s, struct seq_file *seq, void *v); }; +/* + * Used to store the state of one MBus window accross suspend/resume. + */ +struct mvebu_mbus_win_data { + u32 ctrl; + u32 base; + u32 remap_lo; + u32 remap_hi; +}; + struct mvebu_mbus_state { void __iomem *mbuswins_base; void __iomem *sdramwins_base; + void __iomem *mbusbridge_base; struct dentry *debugfs_root; struct dentry *debugfs_sdram; struct dentry *debugfs_devs; @@ -115,6 +135,11 @@ struct mvebu_mbus_state { struct resource pcie_io_aperture; const struct mvebu_mbus_soc_data *soc; int hw_io_coherency; + + /* Used during suspend/resume */ + u32 mbus_bridge_ctrl; + u32 mbus_bridge_base; + struct mvebu_mbus_win_data wins[MBUS_WINS_MAX]; }; static struct mvebu_mbus_state mbus_state; @@ -549,6 +574,7 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { .num_wins = 20, .num_remappable_wins = 8, + .has_mbus_bridge = true, .win_cfg_offset = armada_370_xp_mbus_win_offset, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, @@ -698,11 +724,73 @@ static __init int mvebu_mbus_debugfs_init(void) } fs_initcall(mvebu_mbus_debugfs_init); +static int mvebu_mbus_suspend(void) +{ + struct mvebu_mbus_state *s = &mbus_state; + int win; + + if (!s->mbusbridge_base) + return -ENODEV; + + for (win = 0; win < s->soc->num_wins; win++) { + void __iomem *addr = s->mbuswins_base + + s->soc->win_cfg_offset(win); + + s->wins[win].base = readl(addr + WIN_BASE_OFF); + s->wins[win].ctrl = readl(addr + WIN_CTRL_OFF); + + if (win >= s->soc->num_remappable_wins) + continue; + + s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF); + s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF); + } + + s->mbus_bridge_ctrl = readl(s->mbusbridge_base + + MBUS_BRIDGE_CTRL_OFF); + s->mbus_bridge_base = readl(s->mbusbridge_base + + MBUS_BRIDGE_BASE_OFF); + + return 0; +} + +static void mvebu_mbus_resume(void) +{ + struct mvebu_mbus_state *s = &mbus_state; + int win; + + writel(s->mbus_bridge_ctrl, + s->mbusbridge_base + MBUS_BRIDGE_CTRL_OFF); + writel(s->mbus_bridge_base, + s->mbusbridge_base + MBUS_BRIDGE_BASE_OFF); + + for (win = 0; win < s->soc->num_wins; win++) { + void __iomem *addr = s->mbuswins_base + + s->soc->win_cfg_offset(win); + + writel(s->wins[win].base, addr + WIN_BASE_OFF); + writel(s->wins[win].ctrl, addr + WIN_CTRL_OFF); + + if (win >= s->soc->num_remappable_wins) + continue; + + writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF); + writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF); + } +} + +struct syscore_ops mvebu_mbus_syscore_ops = { + .suspend = mvebu_mbus_suspend, + .resume = mvebu_mbus_resume, +}; + static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, phys_addr_t mbuswins_phys_base, size_t mbuswins_size, phys_addr_t sdramwins_phys_base, - size_t sdramwins_size) + size_t sdramwins_size, + phys_addr_t mbusbridge_phys_base, + size_t mbusbridge_size) { int win; @@ -716,11 +804,24 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, return -ENOMEM; } + if (mbusbridge_phys_base) { + mbus->mbusbridge_base = ioremap(mbusbridge_phys_base, + mbusbridge_size); + if (!mbus->mbusbridge_base) { + iounmap(mbus->sdramwins_base); + iounmap(mbus->mbuswins_base); + return -ENOMEM; + } + } else + mbus->mbusbridge_base = NULL; + for (win = 0; win < mbus->soc->num_wins; win++) mvebu_mbus_disable_window(mbus, win); mbus->soc->setup_cpu_target(mbus); + register_syscore_ops(&mvebu_mbus_syscore_ops); + return 0; } @@ -746,7 +847,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base, mbuswins_phys_base, mbuswins_size, sdramwins_phys_base, - sdramwins_size); + sdramwins_size, 0, 0); } #ifdef CONFIG_OF @@ -887,7 +988,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np, int __init mvebu_mbus_dt_init(bool is_coherent) { - struct resource mbuswins_res, sdramwins_res; + struct resource mbuswins_res, sdramwins_res, mbusbridge_res; struct device_node *np, *controller; const struct of_device_id *of_id; const __be32 *prop; @@ -923,6 +1024,19 @@ int __init mvebu_mbus_dt_init(bool is_coherent) return -EINVAL; } + /* + * Set the resource to 0 so that it can be left unmapped by + * mvebu_mbus_common_init() if the DT doesn't carry the + * necessary information. This is needed to preserve backward + * compatibility. + */ + memset(&mbusbridge_res, 0, sizeof(mbusbridge_res)); + + if (mbus_state.soc->has_mbus_bridge) { + if (of_address_to_resource(controller, 2, &mbusbridge_res)) + pr_warn(FW_WARN "deprecated mbus-mvebu Device Tree, suspend/resume will not work\n"); + } + mbus_state.hw_io_coherency = is_coherent; /* Get optional pcie-{mem,io}-aperture properties */ @@ -933,7 +1047,9 @@ int __init mvebu_mbus_dt_init(bool is_coherent) mbuswins_res.start, resource_size(&mbuswins_res), sdramwins_res.start, - resource_size(&sdramwins_res)); + resource_size(&sdramwins_res), + mbusbridge_res.start, + resource_size(&mbusbridge_res)); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 4749c02b8da6d8dbc29218652985bda844017e95 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:04 +0100 Subject: bus: mvebu-mbus: provide a mechanism to save SDRAM window configuration On Marvell EBU platforms, when doing suspend/resume, the SDRAM window configuration must be saved on suspend, and restored on resume. However, it needs to be restored on resume *before* re-entering the kernel, because the SDRAM window configuration defines the layout of the memory. For this reason, it cannot simply be done in the ->suspend() and ->resume() hooks of the mvebu-mbus driver. Instead, it needs to be restored by the bootloader "boot info" mechanism used when resuming. This mechanism allows the kernel to define a list of (address, value) pairs when suspending, that the bootloader will restore on resume before jumping back into the kernel. This commit therefore adds a new function to the mvebu-mbus driver, called mvebu_mbus_save_cpu_target(), which will be called by the platform code to make the mvebu-mbus driver save the SDRAM window configuration in a way that can be understood by the bootloader "boot info" mechanism. Signed-off-by: Thomas Petazzoni Reviewed-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-8-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- drivers/bus/mvebu-mbus.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mbus.h | 1 + 2 files changed, 57 insertions(+) diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index e8c159399c82..eb7682dc123b 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -110,6 +110,8 @@ struct mvebu_mbus_soc_data { bool has_mbus_bridge; unsigned int (*win_cfg_offset)(const int win); void (*setup_cpu_target)(struct mvebu_mbus_state *s); + int (*save_cpu_target)(struct mvebu_mbus_state *s, + u32 *store_addr); int (*show_cpu_target)(struct mvebu_mbus_state *s, struct seq_file *seq, void *v); }; @@ -128,6 +130,7 @@ struct mvebu_mbus_state { void __iomem *mbuswins_base; void __iomem *sdramwins_base; void __iomem *mbusbridge_base; + phys_addr_t sdramwins_phys_base; struct dentry *debugfs_root; struct dentry *debugfs_sdram; struct dentry *debugfs_devs; @@ -541,6 +544,28 @@ mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus) mvebu_mbus_dram_info.num_cs = cs; } +static int +mvebu_mbus_default_save_cpu_target(struct mvebu_mbus_state *mbus, + u32 *store_addr) +{ + int i; + + for (i = 0; i < 4; i++) { + u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i)); + u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i)); + + writel(mbus->sdramwins_phys_base + DDR_BASE_CS_OFF(i), + store_addr++); + writel(base, store_addr++); + writel(mbus->sdramwins_phys_base + DDR_SIZE_CS_OFF(i), + store_addr++); + writel(size, store_addr++); + } + + /* We've written 16 words to the store address */ + return 16; +} + static void __init mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) { @@ -571,11 +596,35 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) mvebu_mbus_dram_info.num_cs = cs; } +static int +mvebu_mbus_dove_save_cpu_target(struct mvebu_mbus_state *mbus, + u32 *store_addr) +{ + int i; + + for (i = 0; i < 2; i++) { + u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i)); + + writel(mbus->sdramwins_phys_base + DOVE_DDR_BASE_CS_OFF(i), + store_addr++); + writel(map, store_addr++); + } + + /* We've written 4 words to the store address */ + return 4; +} + +int mvebu_mbus_save_cpu_target(u32 *store_addr) +{ + return mbus_state.soc->save_cpu_target(&mbus_state, store_addr); +} + static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { .num_wins = 20, .num_remappable_wins = 8, .has_mbus_bridge = true, .win_cfg_offset = armada_370_xp_mbus_win_offset, + .save_cpu_target = mvebu_mbus_default_save_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; @@ -584,6 +633,7 @@ static const struct mvebu_mbus_soc_data kirkwood_mbus_data = { .num_wins = 8, .num_remappable_wins = 4, .win_cfg_offset = orion_mbus_win_offset, + .save_cpu_target = mvebu_mbus_default_save_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; @@ -592,6 +642,7 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = { .num_wins = 8, .num_remappable_wins = 4, .win_cfg_offset = orion_mbus_win_offset, + .save_cpu_target = mvebu_mbus_dove_save_cpu_target, .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_dove, }; @@ -604,6 +655,7 @@ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = { .num_wins = 8, .num_remappable_wins = 4, .win_cfg_offset = orion_mbus_win_offset, + .save_cpu_target = mvebu_mbus_default_save_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; @@ -612,6 +664,7 @@ static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = { .num_wins = 8, .num_remappable_wins = 2, .win_cfg_offset = orion_mbus_win_offset, + .save_cpu_target = mvebu_mbus_default_save_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; @@ -620,6 +673,7 @@ static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = { .num_wins = 14, .num_remappable_wins = 8, .win_cfg_offset = mv78xx0_mbus_win_offset, + .save_cpu_target = mvebu_mbus_default_save_cpu_target, .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, .show_cpu_target = mvebu_sdram_debug_show_orion, }; @@ -804,6 +858,8 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, return -ENOMEM; } + mbus->sdramwins_phys_base = sdramwins_phys_base; + if (mbusbridge_phys_base) { mbus->mbusbridge_base = ioremap(mbusbridge_phys_base, mbusbridge_size); diff --git a/include/linux/mbus.h b/include/linux/mbus.h index 550c88fb0267..611b69fa8594 100644 --- a/include/linux/mbus.h +++ b/include/linux/mbus.h @@ -61,6 +61,7 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void) } #endif +int mvebu_mbus_save_cpu_target(u32 *store_addr); void mvebu_mbus_get_pcie_mem_aperture(struct resource *res); void mvebu_mbus_get_pcie_io_aperture(struct resource *res); int mvebu_mbus_add_window_remap_by_id(unsigned int target, -- cgit v1.2.3-59-g8ed1b From f571053152f660769f9f39f150ac984bc4c6ac85 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:05 +0100 Subject: clk: mvebu: add suspend/resume for gatable clocks This commit adds suspend/resume support for the gatable clock driver used on Marvell EBU platforms. When getting out of suspend, the Marvell EBU platforms go through the bootloader, which re-enables all gatable clocks. However, upon resume, the clock framework will not disable again all gatable clocks that are not used. Therefore, if the clock driver does not save/restore the state of the gatable clocks, all gatable clocks that are not claimed by any device driver will remain enabled after a resume. This is why this driver saves and restores the state of those clocks. Since clocks aren't real devices, we don't have the normal ->suspend() and ->resume() of the device model, and have to use the ->suspend() and ->resume() hooks of the syscore_ops mechanism. This mechanism has the unfortunate idea of not providing a way of passing private data, which requires us to change the driver to make the assumption that there is only once instance of the gatable clock control structure. Signed-off-by: Thomas Petazzoni Cc: Mike Turquette Cc: linux-kernel@vger.kernel.org Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-9-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- drivers/clk/mvebu/common.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index b7fcb469c87a..0d4d1216f2dd 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "common.h" @@ -177,14 +178,17 @@ struct clk_gating_ctrl { spinlock_t *lock; struct clk **gates; int num_gates; + void __iomem *base; + u32 saved_reg; }; #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) +static struct clk_gating_ctrl *ctrl; + static struct clk *clk_gating_get_src( struct of_phandle_args *clkspec, void *data) { - struct clk_gating_ctrl *ctrl = (struct clk_gating_ctrl *)data; int n; if (clkspec->args_count < 1) @@ -199,15 +203,35 @@ static struct clk *clk_gating_get_src( return ERR_PTR(-ENODEV); } +static int mvebu_clk_gating_suspend(void) +{ + ctrl->saved_reg = readl(ctrl->base); + return 0; +} + +static void mvebu_clk_gating_resume(void) +{ + writel(ctrl->saved_reg, ctrl->base); +} + +static struct syscore_ops clk_gate_syscore_ops = { + .suspend = mvebu_clk_gating_suspend, + .resume = mvebu_clk_gating_resume, +}; + void __init mvebu_clk_gating_setup(struct device_node *np, const struct clk_gating_soc_desc *desc) { - struct clk_gating_ctrl *ctrl; struct clk *clk; void __iomem *base; const char *default_parent = NULL; int n; + if (ctrl) { + pr_err("mvebu-clk-gating: cannot instantiate more than one gatable clock device\n"); + return; + } + base = of_iomap(np, 0); if (WARN_ON(!base)) return; @@ -225,6 +249,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, /* lock must already be initialized */ ctrl->lock = &ctrl_gating_lock; + ctrl->base = base; + /* Count, allocate, and register clock gates */ for (n = 0; desc[n].name;) n++; @@ -246,6 +272,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, of_clk_add_provider(np, clk_gating_get_src, ctrl); + register_syscore_ops(&clk_gate_syscore_ops); + return; gates_out: kfree(ctrl); -- cgit v1.2.3-59-g8ed1b From 8446be5d030c0d986cf90e0b395764f2c6ca443d Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:06 +0100 Subject: ARM: mvebu: implement suspend/resume support for Armada XP This commit implements the core of the platform code to enable suspend/resume on Armada XP. It registers the platform_suspend_ops structure, and implements the ->enter() hook of this structure. It is worth mentioning that this commit only provides the SoC-level part of suspend/resume, which calls into some board-specific code provided in a follow-up commit. The most important thing that this SoC-level code has to do is to build an in-memory structure that contains a magic number, the return address in the kernel after resume, and a set of address/value pairs. This structure is used by the bootloader to restore a certain number of registers (according to the set of address/value pairs) and then jump back into the kernel at the provided location. The code also puts the SDRAM into self-refresh mode, before calling into board-specific code to actually enter the suspend to RAM state. [ jac - add email exchange between Andrew Lunn and Thomas Petazzoni to better describe who consumes the address/value pairs ] > > Is this a well defined mechanism supported by mainline uboot, barebox > > etc. Or is it some Marvell extension to their uboot? > > As far as I know, it is a Marvell extension to their "binary header", > so it's done even before U-Boot starts. Since the hardware needs > assistance from the bootloader to do suspend/resume, there is > necessarily a certain amount of cooperation/agreement needed by what > the kernel does and what the bootloader expects. I'm not sure there's > any "standard" mechanism here. Do you know of any? > > I know the suspend/resume on the Blackfin architecture works the same > way (at least it used to work that way years ago when I did a bit of > Blackfin stuff). And here as well, there was some cooperation between > the kernel and the bootloader. See > arch/blackfin/mach-common/dpmc_modes.S, function do_hibernate() at the > end. > Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1416585613-2113-10-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/Makefile | 2 +- arch/arm/mach-mvebu/common.h | 2 + arch/arm/mach-mvebu/pm.c | 218 +++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/pmsu.h | 1 + 4 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-mvebu/pm.c diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index e24136b42765..e2bd96f619bc 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -7,7 +7,7 @@ CFLAGS_pmsu.o := -march=armv7-a obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o ifeq ($(CONFIG_MACH_MVEBU_V7),y) -obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o +obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o pm.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o endif diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index 3ccb40c3bf94..3e0aca1f288a 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -25,4 +25,6 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev); void __iomem *mvebu_get_scu_base(void); +int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)); + #endif diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c new file mode 100644 index 000000000000..6573a8f11f70 --- /dev/null +++ b/arch/arm/mach-mvebu/pm.c @@ -0,0 +1,218 @@ +/* + * Suspend/resume support. Currently supporting Armada XP only. + * + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coherency.h" +#include "pmsu.h" + +#define SDRAM_CONFIG_OFFS 0x0 +#define SDRAM_CONFIG_SR_MODE_BIT BIT(24) +#define SDRAM_OPERATION_OFFS 0x18 +#define SDRAM_OPERATION_SELF_REFRESH 0x7 +#define SDRAM_DLB_EVICTION_OFFS 0x30c +#define SDRAM_DLB_EVICTION_THRESHOLD_MASK 0xff + +static void (*mvebu_board_pm_enter)(void __iomem *sdram_reg, u32 srcmd); +static void __iomem *sdram_ctrl; + +static int mvebu_pm_powerdown(unsigned long data) +{ + u32 reg, srcmd; + + flush_cache_all(); + outer_flush_all(); + + /* + * Issue a Data Synchronization Barrier instruction to ensure + * that all state saving has been completed. + */ + dsb(); + + /* Flush the DLB and wait ~7 usec */ + reg = readl(sdram_ctrl + SDRAM_DLB_EVICTION_OFFS); + reg &= ~SDRAM_DLB_EVICTION_THRESHOLD_MASK; + writel(reg, sdram_ctrl + SDRAM_DLB_EVICTION_OFFS); + + udelay(7); + + /* Set DRAM in battery backup mode */ + reg = readl(sdram_ctrl + SDRAM_CONFIG_OFFS); + reg &= ~SDRAM_CONFIG_SR_MODE_BIT; + writel(reg, sdram_ctrl + SDRAM_CONFIG_OFFS); + + /* Prepare to go to self-refresh */ + + srcmd = readl(sdram_ctrl + SDRAM_OPERATION_OFFS); + srcmd &= ~0x1F; + srcmd |= SDRAM_OPERATION_SELF_REFRESH; + + mvebu_board_pm_enter(sdram_ctrl + SDRAM_OPERATION_OFFS, srcmd); + + return 0; +} + +#define BOOT_INFO_ADDR 0x3000 +#define BOOT_MAGIC_WORD 0xdeadb002 +#define BOOT_MAGIC_LIST_END 0xffffffff + +/* + * Those registers are accessed before switching the internal register + * base, which is why we hardcode the 0xd0000000 base address, the one + * used by the SoC out of reset. + */ +#define MBUS_WINDOW_12_CTRL 0xd00200b0 +#define MBUS_INTERNAL_REG_ADDRESS 0xd0020080 + +#define SDRAM_WIN_BASE_REG(x) (0x20180 + (0x8*x)) +#define SDRAM_WIN_CTRL_REG(x) (0x20184 + (0x8*x)) + +static phys_addr_t mvebu_internal_reg_base(void) +{ + struct device_node *np; + __be32 in_addr[2]; + + np = of_find_node_by_name(NULL, "internal-regs"); + BUG_ON(!np); + + /* + * Ask the DT what is the internal register address on this + * platform. In the mvebu-mbus DT binding, 0xf0010000 + * corresponds to the internal register window. + */ + in_addr[0] = cpu_to_be32(0xf0010000); + in_addr[1] = 0x0; + + return of_translate_address(np, in_addr); +} + +static void mvebu_pm_store_bootinfo(void) +{ + u32 *store_addr; + phys_addr_t resume_pc; + + store_addr = phys_to_virt(BOOT_INFO_ADDR); + resume_pc = virt_to_phys(armada_370_xp_cpu_resume); + + /* + * The bootloader expects the first two words to be a magic + * value (BOOT_MAGIC_WORD), followed by the address of the + * resume code to jump to. Then, it expects a sequence of + * (address, value) pairs, which can be used to restore the + * value of certain registers. This sequence must end with the + * BOOT_MAGIC_LIST_END magic value. + */ + + writel(BOOT_MAGIC_WORD, store_addr++); + writel(resume_pc, store_addr++); + + /* + * Some platforms remap their internal register base address + * to 0xf1000000. However, out of reset, window 12 starts at + * 0xf0000000 and ends at 0xf7ffffff, which would overlap with + * the internal registers. Therefore, disable window 12. + */ + writel(MBUS_WINDOW_12_CTRL, store_addr++); + writel(0x0, store_addr++); + + /* + * Set the internal register base address to the value + * expected by Linux, as read from the Device Tree. + */ + writel(MBUS_INTERNAL_REG_ADDRESS, store_addr++); + writel(mvebu_internal_reg_base(), store_addr++); + + /* + * Ask the mvebu-mbus driver to store the SDRAM window + * configuration, which has to be restored by the bootloader + * before re-entering the kernel on resume. + */ + store_addr += mvebu_mbus_save_cpu_target(store_addr); + + writel(BOOT_MAGIC_LIST_END, store_addr); +} + +static int mvebu_pm_enter(suspend_state_t state) +{ + if (state != PM_SUSPEND_MEM) + return -EINVAL; + + cpu_pm_enter(); + + mvebu_pm_store_bootinfo(); + cpu_suspend(0, mvebu_pm_powerdown); + + outer_resume(); + + mvebu_v7_pmsu_idle_exit(); + + set_cpu_coherent(); + + cpu_pm_exit(); + + return 0; +} + +static const struct platform_suspend_ops mvebu_pm_ops = { + .enter = mvebu_pm_enter, + .valid = suspend_valid_only_mem, +}; + +int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)) +{ + struct device_node *np; + struct resource res; + + if (!of_machine_is_compatible("marvell,armadaxp")) + return -ENODEV; + + np = of_find_compatible_node(NULL, NULL, + "marvell,armada-xp-sdram-controller"); + if (!np) + return -ENODEV; + + if (of_address_to_resource(np, 0, &res)) { + of_node_put(np); + return -ENODEV; + } + + if (!request_mem_region(res.start, resource_size(&res), + np->full_name)) { + of_node_put(np); + return -EBUSY; + } + + sdram_ctrl = ioremap(res.start, resource_size(&res)); + if (!sdram_ctrl) { + release_mem_region(res.start, resource_size(&res)); + of_node_put(np); + return -ENOMEM; + } + + of_node_put(np); + + mvebu_board_pm_enter = board_pm_enter; + + suspend_set_ops(&mvebu_pm_ops); + + return 0; +} diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index 6b58c1fe2b0d..a7c242dc2ebd 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h @@ -17,5 +17,6 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, phys_addr_t resume_addr_reg); void mvebu_v7_pmsu_idle_exit(void); +void armada_370_xp_cpu_resume(void); #endif /* __MACH_370_XP_PMSU_H */ -- cgit v1.2.3-59-g8ed1b From 8da2b2f7ceeed931af0fc1d4fca800650bb41826 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:07 +0100 Subject: ARM: mvebu: reserve the first 10 KB of each memory bank for suspend/resume When going out of suspend to RAM, the Marvell EBU platforms go through the bootloader, which re-configures the DRAM controller. To achieve this, the bootloader executes a piece of code called the "DDR3 training code". It does some reads/writes to the memory to find out the optimal timings for the memory chip being used. This has the nasty side effect that the first 10 KB of each DRAM chip-select are overwritten by the bootloader when exiting the suspend to RAM state. Therefore, this commit implements the ->reserve() hook for the 'struct machine_desc' used on Armada XP, to reserve the 10 KB of each DRAM chip-select using the memblock API. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-11-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/board-v7.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index 6478626e3ff6..bc52231dfd1c 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -16,10 +16,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -56,6 +58,54 @@ void __iomem *mvebu_get_scu_base(void) return scu_base; } +/* + * When returning from suspend, the platform goes through the + * bootloader, which executes its DDR3 training code. This code has + * the unfortunate idea of using the first 10 KB of each DRAM bank to + * exercise the RAM and calculate the optimal timings. Therefore, this + * area of RAM is overwritten, and shouldn't be used by the kernel if + * suspend/resume is supported. + */ + +#ifdef CONFIG_SUSPEND +#define MVEBU_DDR_TRAINING_AREA_SZ (10 * SZ_1K) +static int __init mvebu_scan_mem(unsigned long node, const char *uname, + int depth, void *data) +{ + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const __be32 *reg, *endp; + int l; + + if (type == NULL || strcmp(type, "memory")) + return 0; + + reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); + if (reg == NULL) + reg = of_get_flat_dt_prop(node, "reg", &l); + if (reg == NULL) + return 0; + + endp = reg + (l / sizeof(__be32)); + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { + u64 base, size; + + base = dt_mem_next_cell(dt_root_addr_cells, ®); + size = dt_mem_next_cell(dt_root_size_cells, ®); + + memblock_reserve(base, MVEBU_DDR_TRAINING_AREA_SZ); + } + + return 0; +} + +static void __init mvebu_memblock_reserve(void) +{ + of_scan_flat_dt(mvebu_scan_mem, NULL); +} +#else +static void __init mvebu_memblock_reserve(void) {} +#endif + /* * Early versions of Armada 375 SoC have a bug where the BootROM * leaves an external data abort pending. The kernel is hit by this @@ -210,6 +260,7 @@ DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)") .init_machine = mvebu_dt_init, .init_irq = mvebu_init_irq, .restart = mvebu_restart, + .reserve = mvebu_memblock_reserve, .dt_compat = armada_370_xp_dt_compat, MACHINE_END -- cgit v1.2.3-59-g8ed1b From 27432825ae19fc26f099156c666cbcc4861e3e54 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:08 +0100 Subject: ARM: mvebu: Armada XP GP specific suspend/resume code On the Armada XP GP platform, entering suspend to RAM state is triggering by talking to an external PIC micro-controller connected to the SoC using 3 GPIOs. There is then a small magic sequence of GPIO toggling that needs to be used to tell the PIC to turn off the SoC. The code uses the Device Tree to find out which GPIOs are used to connect to the PIC micro-controller, and then registers its mvebu_armada_xp_gp_pm_enter() callback to the SoC-level PM code. The SoC PM code will call back into this registered function at the very end of the suspend procedure. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1416585613-2113-12-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/Makefile | 2 +- arch/arm/mach-mvebu/pm-board.c | 141 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-mvebu/pm-board.c diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index e2bd96f619bc..b4f01497ce0b 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -7,7 +7,7 @@ CFLAGS_pmsu.o := -march=armv7-a obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o ifeq ($(CONFIG_MACH_MVEBU_V7),y) -obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o pm.o +obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o pm.o pm-board.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o endif diff --git a/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c new file mode 100644 index 000000000000..6dfd4ab97b2a --- /dev/null +++ b/arch/arm/mach-mvebu/pm-board.c @@ -0,0 +1,141 @@ +/* + * Board-level suspend/resume support. + * + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +#define ARMADA_XP_GP_PIC_NR_GPIOS 3 + +static void __iomem *gpio_ctrl; +static int pic_gpios[ARMADA_XP_GP_PIC_NR_GPIOS]; +static int pic_raw_gpios[ARMADA_XP_GP_PIC_NR_GPIOS]; + +static void mvebu_armada_xp_gp_pm_enter(void __iomem *sdram_reg, u32 srcmd) +{ + u32 reg, ackcmd; + int i; + + /* Put 001 as value on the GPIOs */ + reg = readl(gpio_ctrl); + for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) + reg &= ~BIT(pic_raw_gpios[i]); + reg |= BIT(pic_raw_gpios[0]); + writel(reg, gpio_ctrl); + + /* Prepare writing 111 to the GPIOs */ + ackcmd = readl(gpio_ctrl); + for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) + ackcmd |= BIT(pic_raw_gpios[i]); + + /* + * Wait a while, the PIC needs quite a bit of time between the + * two GPIO commands. + */ + mdelay(3000); + + asm volatile ( + /* Align to a cache line */ + ".balign 32\n\t" + + /* Enter self refresh */ + "str %[srcmd], [%[sdram_reg]]\n\t" + + /* + * Wait 100 cycles for DDR to enter self refresh, by + * doing 50 times two instructions. + */ + "mov r1, #50\n\t" + "1: subs r1, r1, #1\n\t" + "bne 1b\n\t" + + /* Issue the command ACK */ + "str %[ackcmd], [%[gpio_ctrl]]\n\t" + + /* Trap the processor */ + "b .\n\t" + : : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg), + [ackcmd] "r" (ackcmd), [gpio_ctrl] "r" (gpio_ctrl) : "r1"); +} + +static int mvebu_armada_xp_gp_pm_init(void) +{ + struct device_node *np; + struct device_node *gpio_ctrl_np; + int ret = 0, i; + + if (!of_machine_is_compatible("marvell,axp-gp")) + return -ENODEV; + + np = of_find_node_by_name(NULL, "pm_pic"); + if (!np) + return -ENODEV; + + for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) { + char *name; + struct of_phandle_args args; + + pic_gpios[i] = of_get_named_gpio(np, "ctrl-gpios", i); + if (pic_gpios[i] < 0) { + ret = -ENODEV; + goto out; + } + + name = kasprintf(GFP_KERNEL, "pic-pin%d", i); + if (!name) { + ret = -ENOMEM; + goto out; + } + + ret = gpio_request(pic_gpios[i], name); + if (ret < 0) { + kfree(name); + goto out; + } + + ret = gpio_direction_output(pic_gpios[i], 0); + if (ret < 0) { + gpio_free(pic_gpios[i]); + kfree(name); + goto out; + } + + ret = of_parse_phandle_with_fixed_args(np, "ctrl-gpios", 2, + i, &args); + if (ret < 0) { + gpio_free(pic_gpios[i]); + kfree(name); + goto out; + } + + gpio_ctrl_np = args.np; + pic_raw_gpios[i] = args.args[0]; + } + + gpio_ctrl = of_iomap(gpio_ctrl_np, 0); + if (!gpio_ctrl) + return -ENOMEM; + + mvebu_pm_init(mvebu_armada_xp_gp_pm_enter); + +out: + of_node_put(np); + return ret; +} + +late_initcall(mvebu_armada_xp_gp_pm_init); -- cgit v1.2.3-59-g8ed1b From 77ea46d1331e5b46ff4dd98e7296eb17355cff75 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:09 +0100 Subject: ARM: mvebu: make sure MMU is disabled in armada_370_xp_cpu_resume The armada_370_xp_cpu_resume() until now was used only as the function called by the SoC when returning from a deep idle state (as used in cpuidle, or when the CPU is brought offline using CPU hotplug). However, it is now also used when exiting the suspend to RAM state. In this case, it is the bootloader that calls back into this function, with the MMU left enabled by the BootROM. Having the MMU enabled when entering this function confuses the kerrnel because we are not using the kernel page tables at this point, but in other mvebu functions we use the information on whether the MMU is enabled or not to find out whether we should talk to the coherency fabric using a physical address or a virtual address. To fix that, we simply disable the MMU when entering this function, so that the kernel is in an expected situation. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-13-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu_ll.S | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S index a945756cfb45..ae7e6b06fadc 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S @@ -18,6 +18,14 @@ */ ENTRY(armada_370_xp_cpu_resume) ARM_BE8(setend be ) @ go BE8 if entered LE + /* + * Disable the MMU that might have been enabled in BootROM if + * this code is used in the resume path of a suspend/resume + * cycle. + */ + mrc p15, 0, r1, c1, c0, 0 + bic r1, #1 + mcr p15, 0, r1, c1, c0, 0 bl ll_add_cpu_to_smp_group bl ll_enable_coherency b cpu_resume -- cgit v1.2.3-59-g8ed1b From b9b1de0f4da37dac76d812a27d6065eba02dc05b Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:10 +0100 Subject: ARM: mvebu: synchronize secondary CPU clocks on resume The Armada XP has multiple cores clocked by independent clocks. The SMP startup code contains a function called set_secondary_cpus_clock() called in armada_xp_smp_prepare_cpus() to ensure the clocks of the secondary CPUs match the clock of the boot CPU. With the introduction of suspend/resume, this operation is no longer needed when booting the system, but also when existing the suspend to RAM state. Therefore this commit reworks a bit the logic: instead of configuring the clock of all secondary CPUs in armada_xp_smp_prepare_cpus(), we do it on a per-secondary CPU basis in armada_xp_boot_secondary(), as this function gets called when existing suspend to RAM for each secondary CPU. Since the function now only takes care of one CPU, we rename it from set_secondary_cpus_clock() to set_secondary_cpu_clock(), and it looses its __init marker, as it is now used beyond the system initialization. Note that we can't use smp_processor_id() directly, because when exiting from suspend to RAM, the code is apparently executed with preemption enabled, so smp_processor_id() is not happy (prints a warning). We therefore switch to using get_cpu()/put_cpu(), even though we pretty much have the guarantee that the code starting the secondary CPUs is going to run on the boot CPU and will not be migrated. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-14-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/platsmp.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index 895dc373c8a1..e65e69a7e65d 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -33,7 +33,7 @@ #define AXP_BOOTROM_BASE 0xfff00000 #define AXP_BOOTROM_SIZE 0x100000 -static struct clk *__init get_cpu_clk(int cpu) +static struct clk *get_cpu_clk(int cpu) { struct clk *cpu_clk; struct device_node *np = of_get_cpu_node(cpu, NULL); @@ -46,29 +46,28 @@ static struct clk *__init get_cpu_clk(int cpu) return cpu_clk; } -static void __init set_secondary_cpus_clock(void) +static void set_secondary_cpu_clock(unsigned int cpu) { - int thiscpu, cpu; + int thiscpu; unsigned long rate; struct clk *cpu_clk; - thiscpu = smp_processor_id(); + thiscpu = get_cpu(); + cpu_clk = get_cpu_clk(thiscpu); if (!cpu_clk) - return; + goto out; clk_prepare_enable(cpu_clk); rate = clk_get_rate(cpu_clk); - /* set all the other CPU clk to the same rate than the boot CPU */ - for_each_possible_cpu(cpu) { - if (cpu == thiscpu) - continue; - cpu_clk = get_cpu_clk(cpu); - if (!cpu_clk) - return; - clk_set_rate(cpu_clk, rate); - clk_prepare_enable(cpu_clk); - } + cpu_clk = get_cpu_clk(cpu); + if (!cpu_clk) + goto out; + clk_set_rate(cpu_clk, rate); + clk_prepare_enable(cpu_clk); + +out: + put_cpu(); } static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) @@ -78,6 +77,7 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) pr_info("Booting CPU %d\n", cpu); hw_cpu = cpu_logical_map(cpu); + set_secondary_cpu_clock(hw_cpu); mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup); /* @@ -126,7 +126,6 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) struct resource res; int err; - set_secondary_cpus_clock(); flush_cache_all(); set_cpu_coherent(); -- cgit v1.2.3-59-g8ed1b From 389a367a5bfcde677f82d05c6a6cd1458b9c54bf Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:11 +0100 Subject: ARM: mvebu: add suspend/resume DT information for Armada XP GP This commit improves the Armada XP GP Device Tree description to describe the 3 GPIOs that are used to connect the SoC to the PIC micro-controller that we talk to shutdown the SoC when entering suspend to RAM. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-15-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-xp-gp.dts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts index 0478c55ca656..ea8673647494 100644 --- a/arch/arm/boot/dts/armada-xp-gp.dts +++ b/arch/arm/boot/dts/armada-xp-gp.dts @@ -23,6 +23,7 @@ */ /dts-v1/; +#include #include "armada-xp-mv78460.dtsi" / { @@ -48,6 +49,14 @@ <0x00000001 0x00000000 0x00000001 0x00000000>; }; + cpus { + pm_pic { + ctrl-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>, + <&gpio0 17 GPIO_ACTIVE_LOW>, + <&gpio0 18 GPIO_ACTIVE_LOW>; + }; + }; + soc { ranges = ; + pinctrl-names = "default"; + pic_pins: pic-pins-0 { + marvell,pins = "mpp16", "mpp17", + "mpp18"; + marvell,function = "gpio"; + }; + }; sata@a0000 { nr-ports = <2>; status = "okay"; -- cgit v1.2.3-59-g8ed1b From 8b7dc9d37a44e12bd2e5656b2b8e8dc77498aa95 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:12 +0100 Subject: ARM: mvebu: adjust mbus controller description on Armada 370/XP In order to support suspend/resume on Armada XP, an additional set of registers need to be described at the MBus controller level. This commit therefore adjusts the Device Tree of the Armada 370/XP SoC to include those registers in the MBus controller description; Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-16-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-370-xp.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index 83286ec9702c..90dba78554c8 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi @@ -180,7 +180,8 @@ mbusc: mbus-controller@20000 { compatible = "marvell,mbus-controller"; - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, + <0x20250 0x8>; }; mpic: interrupt-controller@20000 { -- cgit v1.2.3-59-g8ed1b From 6e6db2bea3ea9424a0cb19d89d47664bc13e31bc Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 21 Nov 2014 17:00:13 +0100 Subject: ARM: mvebu: add SDRAM controller description for Armada XP The suspend/resume sequence on Armada XP needs to modify a number of registers in the SDRAM controller. Therefore, this commit updates the Armada XP Device Tree description to include the SDRAM controller Device Tree node. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1416585613-2113-17-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-xp.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi index bff9f6c18db1..2be244a96edf 100644 --- a/arch/arm/boot/dts/armada-xp.dtsi +++ b/arch/arm/boot/dts/armada-xp.dtsi @@ -35,6 +35,11 @@ }; internal-regs { + sdramc@1400 { + compatible = "marvell,armada-xp-sdram-controller"; + reg = <0x1400 0x500>; + }; + L2: l2-cache { compatible = "marvell,aurora-system-cache"; reg = <0x08000 0x1000>; -- cgit v1.2.3-59-g8ed1b From c747803861f7e3849673754062e827d8d21dbcc4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 29 Nov 2014 22:50:47 +0800 Subject: soc: integrator: Add terminating entry for integrator_cm_match The of_device_id table is supposed to be zero-terminated. Signed-off-by: Axel Lin Acked-by: Linus Walleij Signed-off-by: Arnd Bergmann --- drivers/soc/versatile/soc-integrator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c index ccaa53739ab4..a5d7d39ae0ad 100644 --- a/drivers/soc/versatile/soc-integrator.c +++ b/drivers/soc/versatile/soc-integrator.c @@ -23,6 +23,7 @@ static u32 integrator_coreid; static const struct of_device_id integrator_cm_match[] = { { .compatible = "arm,core-module-integrator", }, + { } }; static const char *integrator_arch_str(u32 id) -- cgit v1.2.3-59-g8ed1b From 842f7d2c4d392c0571cf72e3eaca26742bebbd1e Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 2 Dec 2014 17:48:02 +0100 Subject: ARM: mvebu: use the cpufreq-dt platform_data for independent clocks This commit adjusts the registration of the cpufreq-dt driver in the mvebu platform to indicate to the cpufreq driver that the platform has independent clocks for each CPU. Signed-off-by: Thomas Petazzoni Acked-by: Jason Cooper Signed-off-by: Arnd Bergmann --- arch/arm/mach-mvebu/pmsu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 5a757f929927..d8ab605a44fa 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -571,6 +572,10 @@ int mvebu_pmsu_dfs_request(int cpu) return 0; } +struct cpufreq_dt_platform_data cpufreq_dt_pd = { + .independent_clocks = true, +}; + static int __init armada_xp_pmsu_cpufreq_init(void) { struct device_node *np; @@ -643,7 +648,8 @@ static int __init armada_xp_pmsu_cpufreq_init(void) } } - platform_device_register_simple("cpufreq-dt", -1, NULL, 0); + platform_device_register_data(NULL, "cpufreq-dt", -1, + &cpufreq_dt_pd, sizeof(cpufreq_dt_pd)); return 0; } -- cgit v1.2.3-59-g8ed1b