From ed2d859119f9cb04410d94b5fbd2bb12907c8932 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 9 Jun 2014 17:52:45 -0300 Subject: ARM: mvebu: Fix broken SoC ID detection Currently the mvebu boards need to detect the SoC revision in order to apply some quirks needed to workaround issues found on I2C and thermal controllers present only in very early SoC. This detection requires PCI address translation to work, so we need to explicitly select OF_ADDRESS_PCI. This can be considered a partial revert of the following commit, that wrongly removed the option selection: commit 55400f3a1f89e39761f45c19f6e4235a329c400b Author: Rob Herring Date: Tue Apr 22 14:15:52 2014 -0500 ARM: mvebu: clean-up unneeded kconfig selects Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1402347165-19988-1-git-send-email-ezequiel.garcia@free-electrons.com Acked-by: Rob Herring Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 6090b9e..61ac80a 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -10,6 +10,7 @@ config ARCH_MVEBU select ZONE_DMA if ARM_LPAE select ARCH_REQUIRE_GPIOLIB select PCI_QUIRKS if PCI + select OF_ADDRESS_PCI if ARCH_MVEBU -- cgit v1.1 From 52fcc56753de91ae337aeaa0a664f72d93f19827 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 11 Jun 2014 14:06:37 +0200 Subject: ARM: mvebu: select ARM_CPU_SUSPEND for Marvell EBU v7 platforms On Marvell Armada platforms, the PMSU (Power Management Service Unit) controls a number of power management related activities, needed for things like suspend/resume, CPU hotplug, cpuidle or even simply SMP. Since cpuidle support was added for Armada XP, the pmsu.c file in arch/arm/mach-mvebu/ calls the cpu_suspend() and cpu_resume() ARM functions, which are only available when CONFIG_ARM_CPU_SUSPEND=y. Therefore, configurations that have CONFIG_ARM_CPU_SUSPEND disabled due to PM_SLEEP being disabled no longer build properly, due to undefined references to cpu_suspend() and cpu_resume(). To fix this, this patch simply ensures CONFIG_ARM_CPU_SUSPEND is always enabled for Marvell EBU v7 platforms. Doing things in a more fine-grained way would require a lot of #ifdef-ery in pmsu.c to isolate the parts that use cpu_suspend()/cpu_resume(), and those parts would anyway have been needed as soon as either one of suspend/resume, CPU hotplug or cpuidle was enabled. Reported-by: Ezequiel Garcia Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1402488397-31381-1-git-send-email-thomas.petazzoni@free-electrons.com Acked-by: Ezequiel Garcia Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 61ac80a..ea039ed 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -20,6 +20,7 @@ config MACH_MVEBU_V7 bool select ARMADA_370_XP_TIMER select CACHE_L2X0 + select ARM_CPU_SUSPEND config MACH_ARMADA_370 bool "Marvell Armada 370 boards" if ARCH_MULTI_V7 -- cgit v1.1 From 752ef800a604c0b855077ec480dc9c6ea5b797ee Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 12 Jun 2014 17:09:31 +0200 Subject: ARM: mvebu: move Armada 375 external abort logic as a quirk In preparation to a small re-organization of the initialization sequence in board-v7.c, this commit moves the registration of the custom external abort handler on Armada 375 later in the boot sequence, and makes it more similar to the other quirks that we already have. There is indeed no need to register this abort handler particularly early, it simply needs to be registered before switching to userspace. In addition to this, this commit makes the registration of the custom abort handler conditional on Armada 375 Z1, because Armada 375 A0 and later iterations are not affected by the issue. This commit was tested on both Armada 375 Z1 and Armada 375 A0 platforms. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1402585772-10405-3-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/board-v7.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index 8bb742f..804c952 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -78,10 +78,17 @@ static void __init mvebu_timer_and_clk_init(void) mvebu_scu_enable(); coherency_init(); BUG_ON(mvebu_mbus_dt_init(coherency_available())); +} + +static void __init external_abort_quirk(void) +{ + u32 dev, rev; - if (of_machine_is_compatible("marvell,armada375")) - hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0, - "imprecise external abort"); + if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV) + return; + + hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0, + "imprecise external abort"); } static void __init i2c_quirk(void) @@ -169,8 +176,10 @@ 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.1 From 011788907ba955f87875fcfb4914881b28f7f99d Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 12 Jun 2014 17:09:32 +0200 Subject: ARM: mvebu: update L2/PCIe deadlock workaround after L2CC cleanup Commit 497a92308af8e9385fa3d135f7f416a997e4b93b ("ARM: mvebu: implement L2/PCIe deadlock workaround") introduced some logic in coherency.c to adjust the PL310 cache controller Device Tree node of Armada 375 and Armada 38x platform to include the 'arm,io-coherent' property if the system is running with hardware I/O coherency enabled. However, with the L2CC driver cleanup done by Russell King, the initialization of the L2CC driver has been moved earlier, and is now part of the init_IRQ() ARM function in arch/arm/kernel/irq.c. Therefore, calling coherency_init() in ->init_time() is now too late, as the Device Tree property gets added too late (after the L2CC driver has been initialized). In order to fix this, this commit removes the ->init_time() callback use in board-v7.c and replaces it with an ->init_irq() callback. We therefore no longer use the default ->init_irq() callback, but we now use the default ->init_time() callback. In this newly introduced ->init_irq() callback, we call irqchip_init() which is the default behavior when ->init_irq() isn't defined, and then do the initialization related to the coherency: SCU, coherency fabric, and mvebu-mbus (which is needed to start secondary CPUs). Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1402585772-10405-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/board-v7.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index 804c952..b2524d6 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -71,10 +72,9 @@ static int armada_375_external_abort_wa(unsigned long addr, unsigned int fsr, return 1; } -static void __init mvebu_timer_and_clk_init(void) +static void __init mvebu_init_irq(void) { - of_clk_init(NULL); - clocksource_of_init(); + irqchip_init(); mvebu_scu_enable(); coherency_init(); BUG_ON(mvebu_mbus_dt_init(coherency_available())); @@ -194,7 +194,7 @@ DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)") .l2c_aux_mask = ~0, .smp = smp_ops(armada_xp_smp_ops), .init_machine = mvebu_dt_init, - .init_time = mvebu_timer_and_clk_init, + .init_irq = mvebu_init_irq, .restart = mvebu_restart, .dt_compat = armada_370_xp_dt_compat, MACHINE_END @@ -207,7 +207,7 @@ static const char * const armada_375_dt_compat[] = { DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)") .l2c_aux_val = 0, .l2c_aux_mask = ~0, - .init_time = mvebu_timer_and_clk_init, + .init_irq = mvebu_init_irq, .init_machine = mvebu_dt_init, .restart = mvebu_restart, .dt_compat = armada_375_dt_compat, @@ -222,7 +222,7 @@ static const char * const armada_38x_dt_compat[] = { DT_MACHINE_START(ARMADA_38X_DT, "Marvell Armada 380/385 (Device Tree)") .l2c_aux_val = 0, .l2c_aux_mask = ~0, - .init_time = mvebu_timer_and_clk_init, + .init_irq = mvebu_init_irq, .restart = mvebu_restart, .dt_compat = armada_38x_dt_compat, MACHINE_END -- cgit v1.1 From 6509dc74c9f55ffaa558738b96c4da8b98d39571 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 30 Jun 2014 14:09:25 +0200 Subject: ARM: mvebu: fix cpuidle implementation to work on big-endian systems On Marvell Armada XP, when a CPU comes back from deep idle state of cpuidle, it restarts its execution at armada_370_xp_cpu_resume(), which puts back the CPU into the coherency, and then calls the generic cpu_resume() function. While this works on little-endian configurations, it doesn't work on big-endian configurations because the CPU restarts in little-endian, and therefore must be switched back to big-endian to operate properly. To achieve this, a 'setend be' instruction must be executed in big-endian configurations. However, the ARM_BE8() macro that is used to implement nice compile-time conditional for ARM LE vs. ARM BE8 is not easily usable in inline assembly. Therefore, this patch moves the armada_370_xp_cpu_resume() C function, which was anyway just a block of inline assembly, into a proper pmsu_ll.S file, and adds the appropriate ARM_BE8(setend be) instruction. Without this patch, an Armada XP big endian configuration with cpuidle enabled fails to boot, as it hangs as soon as one of the CPU hits the deep idle state. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1404130165-3593-1-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/Makefile | 2 +- arch/arm/mach-mvebu/pmsu.c | 9 ++------- arch/arm/mach-mvebu/pmsu_ll.S | 25 +++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 arch/arm/mach-mvebu/pmsu_ll.S (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 2ecb828..1636cdb 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -7,7 +7,7 @@ CFLAGS_pmsu.o := -march=armv7-a obj-y += 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 +obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o endif diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 53a55c8..a1d407c 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -66,6 +66,8 @@ static void __iomem *pmsu_mp_base; extern void ll_disable_coherency(void); extern void ll_enable_coherency(void); +extern void armada_370_xp_cpu_resume(void); + static struct platform_device armada_xp_cpuidle_device = { .name = "cpuidle-armada-370-xp", }; @@ -140,13 +142,6 @@ static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) writel(reg, pmsu_mp_base + L2C_NFABRIC_PM_CTL); } -static void armada_370_xp_cpu_resume(void) -{ - asm volatile("bl ll_add_cpu_to_smp_group\n\t" - "bl ll_enable_coherency\n\t" - "b cpu_resume\n\t"); -} - /* No locking is needed because we only access per-CPU registers */ void armada_370_xp_pmsu_idle_prepare(bool deepidle) { diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S new file mode 100644 index 0000000..fc3de68 --- /dev/null +++ b/arch/arm/mach-mvebu/pmsu_ll.S @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni + * Gregory Clement + * + * 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 + +/* + * This is the entry point through which CPUs exiting cpuidle deep + * idle state are going. + */ +ENTRY(armada_370_xp_cpu_resume) +ARM_BE8(setend be ) @ go BE8 if entered LE + bl ll_add_cpu_to_smp_group + bl ll_enable_coherency + b cpu_resume +ENDPROC(armada_370_xp_cpu_resume) + -- cgit v1.1 From 0e2be4c1121ae3dc2771c4d9b99d4c39ea9577d8 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 1 Jul 2014 17:23:06 +0200 Subject: ARM: mvebu: fix SMP boot for Armada 38x and Armada 375 Z1 in big endian The SMP boot on Armada 38x and Armada 375 Z1 is currently broken in big-endian configurations, and this commit fixes it for both platforms. For Armada 375 Z1, the problem was in the armada_375_smp_cpu1_enable_code part of the code that gets copied to the Crypto SRAM as a work-around for an issue of the Z1 stepping. This piece of code was not switching the CPU core to big-endian, and not endian-swapping the value read from the Resume Address register (the value is stored little-endian). Due to the introduction of the conditional 'rev r1, r1' instruction, the offset between the 'ldr r0, [pc, #4]' instruction and the value it was looking is different between LE and BE configurations. To solve this, we instead use one 'adr' instruction followed by one 'ldr'. For Armada 38x, the problem was simply that the CPU core was not switched to big endian in the secondary CPU startup function. This change was tested in LE and BE configurations on Armada 385, Armada 375 Z1 and Armada 375 A0. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1404228186-21203-1-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/headsmp-a9.S | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S index 5925366..da5bb29 100644 --- a/arch/arm/mach-mvebu/headsmp-a9.S +++ b/arch/arm/mach-mvebu/headsmp-a9.S @@ -15,6 +15,8 @@ #include #include +#include + __CPUINIT #define CPU_RESUME_ADDR_REG 0xf10182d4 @@ -22,13 +24,18 @@ .global armada_375_smp_cpu1_enable_code_end armada_375_smp_cpu1_enable_code_start: - ldr r0, [pc, #4] +ARM_BE8(setend be) + adr r0, 1f + ldr r0, [r0] ldr r1, [r0] +ARM_BE8(rev r1, r1) mov pc, r1 +1: .word CPU_RESUME_ADDR_REG armada_375_smp_cpu1_enable_code_end: ENTRY(mvebu_cortex_a9_secondary_startup) +ARM_BE8(setend be) bl v7_invalidate_l1 b secondary_startup ENDPROC(mvebu_cortex_a9_secondary_startup) -- cgit v1.1 From 0d461e1b087048b0cc37c9d7b351649578c507b4 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 4 Jul 2014 16:22:16 +0200 Subject: ARM: mvebu: Fix the operand list in the inline asm of armada_370_xp_pmsu_idle_enter In the inline asm part of the function armada_370_xp_pmsu_idle_enter() the input operand was used. The intent here was to let the compiler choose this register so it could do the optimization it needed. However an input operand is not supposed to be modified by the inline asm code. This can lead to improper generated instructions. In some case generated instruction the compiler made the choice to reuse the same register to store the return value. But in the assembly part this register was modified, so it can lead to return an wrong value. The fix is to use a clobber. Thanks to this the compiler will know that the value of this register will be modified. Signed-off-by: Gregory CLEMENT Reviewed-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1404483736-16938-1-git-send-email-gregory.clement@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index a1d407c..25aa823 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -201,12 +201,12 @@ static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle) /* Test the CR_C bit and set it if it was cleared */ asm volatile( - "mrc p15, 0, %0, c1, c0, 0 \n\t" - "tst %0, #(1 << 2) \n\t" - "orreq %0, %0, #(1 << 2) \n\t" - "mcreq p15, 0, %0, c1, c0, 0 \n\t" + "mrc p15, 0, r0, c1, c0, 0 \n\t" + "tst r0, #(1 << 2) \n\t" + "orreq r0, r0, #(1 << 2) \n\t" + "mcreq p15, 0, r0, c1, c0, 0 \n\t" "isb " - : : "r" (0)); + : : : "r0"); pr_warn("Failed to suspend the system\n"); -- cgit v1.1 From a728b977429383b3fe92b6e3bff9e69365609e0f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 8 Jul 2014 10:37:37 -0300 Subject: ARM: mvebu: Fix coherency bus notifiers by using separate notifiers Currently, the coherency fabric support registers two bus notifiers; one for platform, one for pci bus types, with the same notifier block. However, this is illegal and can cause serious issues: the notifier block is also a link in the notifier list and cannot be inserted twice. This commit fixes this by using different notifier blocks (with the same notifier callback) to set the platform and pci bus types notifiers. Fixes: b0063aad5dd8 ("ARM: mvebu: use hardware I/O coherency also for PCI devices") Reported-by: Paolo Pisati Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1404826657-6977-1-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/coherency.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 477202f..2bdc323 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -292,6 +292,10 @@ static struct notifier_block mvebu_hwcc_nb = { .notifier_call = mvebu_hwcc_notifier, }; +static struct notifier_block mvebu_hwcc_pci_nb = { + .notifier_call = mvebu_hwcc_notifier, +}; + static void __init armada_370_coherency_init(struct device_node *np) { struct resource res; @@ -427,7 +431,7 @@ static int __init coherency_pci_init(void) { if (coherency_available()) bus_register_notifier(&pci_bus_type, - &mvebu_hwcc_nb); + &mvebu_hwcc_pci_nb); return 0; } -- cgit v1.1 From 9ce35884bd961700d34f8a5d908645be2fd0ba76 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:38 +0200 Subject: ARM: mvebu: split again armada_370_xp_pmsu_idle_enter() in PMSU code do_armada_370_xp_cpu_suspend() and armada_370_xp_pmsu_idle_prepare(), have been merged into a single function called armada_370_xp_pmsu_idle_enter() by the commit "bbb92284b6c8 ARM: mvebu: slightly refactor/rename PMSU idle related functions", in prepare for the introduction of the CPU hotplug support for Armada XP. But for cpuidle the prepare function will be common to all the mvebu SoCs that use the PMSU, while the suspend function will be specific to each SoC. Keeping the prepare function separate will help reducing code duplication while new SoC support is added. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-2-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index b31a829..5fda549 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -143,7 +143,7 @@ static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) } /* No locking is needed because we only access per-CPU registers */ -int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) +static int armada_370_xp_prepare(unsigned long deepidle) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -179,6 +179,17 @@ int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); + return 0; +} + +int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) +{ + int ret; + + ret = armada_370_xp_prepare(deepidle); + if (ret) + return ret; + v7_exit_coherency_flush(all); ll_disable_coherency(); -- cgit v1.1 From 3e328428d4d0abe257ee9342d3e370c6487e9601 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:39 +0200 Subject: ARM: mvebu: sort the #include of pmsu.c in alphabetic order Sorting the headers in alphabetic order will help to reduce conflicts when adding new headers later. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-3-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 5fda549..9e18cce 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -19,13 +19,13 @@ #define pr_fmt(fmt) "mvebu-pmsu: " fmt #include -#include #include -#include #include +#include +#include #include -#include #include +#include #include #include #include -- cgit v1.1 From 3076cc58c958090ad50acf50fc855845e3462523 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:40 +0200 Subject: ARM: mvebu: add a common function for the boot address work around On some of the mvebu SoCs and due to internal BootROM issue, the CPU initial jump code must be placed in the SRAM memory of the SoC. In order to achieve this, we have to unmap the BootROM and at some specific location where the BootROM was placed, create a dedicated MBus window for the SRAM. This SRAM is initialized with a few instructions of code that allows to jump to the real secondary CPU boot address. The SRAM used is the Crypto engine one. This work around is currently needed for booting SMP on Armada 375 Z1 and will be needed for cpuidle support on Armada 370. Instead of duplicating the same code, this commit introduces a common function to handle it: mvebu_setup_boot_addr_wa(). Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 47 +++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/pmsu.h | 3 +++ arch/arm/mach-mvebu/pmsu_ll.S | 22 ++++++++++++++++++++ 3 files changed, 72 insertions(+) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 9e18cce..272a9c05 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,10 @@ static void __iomem *pmsu_mp_base; #define L2C_NFABRIC_PM_CTL 0x4 #define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20) +#define SRAM_PHYS_BASE 0xFFFF0000 +#define BOOTROM_BASE 0xFFF00000 +#define BOOTROM_SIZE 0x100000 + extern void ll_disable_coherency(void); extern void ll_enable_coherency(void); @@ -85,6 +90,48 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); } +extern unsigned char mvebu_boot_wa_start; +extern unsigned char mvebu_boot_wa_end; + +/* + * This function sets up the boot address workaround needed for SMP + * boot on Armada 375 Z1 and cpuidle on Armada 370. It unmaps the + * BootROM Mbus window, and instead remaps a crypto SRAM into which a + * custom piece of code is copied to replace the problematic BootROM. + */ +int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, + unsigned int crypto_eng_attribute, + phys_addr_t resume_addr_reg) +{ + void __iomem *sram_virt_base; + u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start; + + mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE); + mvebu_mbus_add_window_by_id(crypto_eng_target, crypto_eng_attribute, + SRAM_PHYS_BASE, SZ_64K); + + sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K); + if (!sram_virt_base) { + pr_err("Unable to map SRAM to setup the boot address WA\n"); + return -ENOMEM; + } + + memcpy(sram_virt_base, &mvebu_boot_wa_start, code_len); + + /* + * The last word of the code copied in SRAM must contain the + * physical base address of the PMSU register. We + * intentionally store this address in the native endianness + * of the system. + */ + __raw_writel((unsigned long)resume_addr_reg, + sram_virt_base + code_len - 4); + + iounmap(sram_virt_base); + + return 0; +} + static int __init armada_370_xp_pmsu_init(void) { struct device_node *np; diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index 07a737c..ae50194 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h @@ -12,5 +12,8 @@ #define __MACH_MVEBU_PMSU_H int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr); +int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, + unsigned int crypto_eng_attribute, + phys_addr_t resume_addr_reg); #endif /* __MACH_370_XP_PMSU_H */ diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S index fc3de68..17d7f3b 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S @@ -23,3 +23,25 @@ ARM_BE8(setend be ) @ go BE8 if entered LE b cpu_resume ENDPROC(armada_370_xp_cpu_resume) +.global mvebu_boot_wa_start +.global mvebu_boot_wa_end + +/* The following code will be executed from SRAM */ +ENTRY(mvebu_boot_wa_start) +mvebu_boot_wa_start: +ARM_BE8(setend be) + adr r0, 1f + ldr r0, [r0] @ load the address of the + @ resume register + ldr r0, [r0] @ load the value in the + @ resume register +ARM_BE8(rev r0, r0) @ the value is stored LE + mov pc, r0 @ jump to this value +/* + * the last word of this piece of code will be filled by the physical + * address of the boot address register just after being copied in SRAM + */ +1: + .long . +mvebu_boot_wa_end: +ENDPROC(mvebu_boot_wa_end) -- cgit v1.1 From 305969fb629284bcd35065911179a79f41954b9a Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:41 +0200 Subject: ARM: mvebu: use the common function for Armada 375 SMP workaround Use the common function mvebu_setup_boot_addr_wa() introduced in the commit "ARM: mvebu: Add a common function for the boot address work around" instead of the dedicated version for Armada 375. This commit also moves the workaround in the system-controller module. Indeed the workaround on 375 is really related to setting the boot address which is done by the system controller. As a bonus we no longer use an harcoded value to access the register storing the boot address. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-5-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/headsmp-a9.S | 15 ------------ arch/arm/mach-mvebu/platsmp-a9.c | 42 +++------------------------------ arch/arm/mach-mvebu/system-controller.c | 31 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 54 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S index da5bb29..be51c99 100644 --- a/arch/arm/mach-mvebu/headsmp-a9.S +++ b/arch/arm/mach-mvebu/headsmp-a9.S @@ -18,21 +18,6 @@ #include __CPUINIT -#define CPU_RESUME_ADDR_REG 0xf10182d4 - -.global armada_375_smp_cpu1_enable_code_start -.global armada_375_smp_cpu1_enable_code_end - -armada_375_smp_cpu1_enable_code_start: -ARM_BE8(setend be) - adr r0, 1f - ldr r0, [r0] - ldr r1, [r0] -ARM_BE8(rev r1, r1) - mov pc, r1 -1: - .word CPU_RESUME_ADDR_REG -armada_375_smp_cpu1_enable_code_end: ENTRY(mvebu_cortex_a9_secondary_startup) ARM_BE8(setend be) diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c index 43aaf3f..47a71a9 100644 --- a/arch/arm/mach-mvebu/platsmp-a9.c +++ b/arch/arm/mach-mvebu/platsmp-a9.c @@ -20,33 +20,8 @@ #include #include #include "common.h" -#include "mvebu-soc-id.h" #include "pmsu.h" -#define CRYPT0_ENG_ID 41 -#define CRYPT0_ENG_ATTR 0x1 -#define SRAM_PHYS_BASE 0xFFFF0000 - -#define BOOTROM_BASE 0xFFF00000 -#define BOOTROM_SIZE 0x100000 - -extern unsigned char armada_375_smp_cpu1_enable_code_end; -extern unsigned char armada_375_smp_cpu1_enable_code_start; - -static void armada_375_smp_cpu1_enable_wa(void) -{ - void __iomem *sram_virt_base; - - mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE); - mvebu_mbus_add_window_by_id(CRYPT0_ENG_ID, CRYPT0_ENG_ATTR, - SRAM_PHYS_BASE, SZ_64K); - sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K); - - memcpy(sram_virt_base, &armada_375_smp_cpu1_enable_code_start, - &armada_375_smp_cpu1_enable_code_end - - &armada_375_smp_cpu1_enable_code_start); -} - extern void mvebu_cortex_a9_secondary_startup(void); static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, @@ -63,21 +38,10 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, * address. */ hw_cpu = cpu_logical_map(cpu); - - if (of_machine_is_compatible("marvell,armada375")) { - u32 dev, rev; - - if (mvebu_get_soc_id(&dev, &rev) == 0 && - rev == ARMADA_375_Z1_REV) - armada_375_smp_cpu1_enable_wa(); - + if (of_machine_is_compatible("marvell,armada375")) mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup); - } - else { - mvebu_pmsu_set_cpu_boot_addr(hw_cpu, - mvebu_cortex_a9_secondary_startup); - } - + else + mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup); smp_wmb(); ret = mvebu_cpu_reset_deassert(hw_cpu); if (ret) { diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c index b2b4e3d..a068cb5 100644 --- a/arch/arm/mach-mvebu/system-controller.c +++ b/arch/arm/mach-mvebu/system-controller.c @@ -28,8 +28,14 @@ #include #include #include "common.h" +#include "mvebu-soc-id.h" +#include "pmsu.h" + +#define ARMADA_375_CRYPT0_ENG_TARGET 41 +#define ARMADA_375_CRYPT0_ENG_ATTR 1 static void __iomem *system_controller_base; +static phys_addr_t system_controller_phys_base; struct mvebu_system_controller { u32 rstoutn_mask_offset; @@ -121,10 +127,32 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev) } #ifdef CONFIG_SMP +void mvebu_armada375_smp_wa_init(void) +{ + u32 dev, rev; + phys_addr_t resume_addr_reg; + + if (mvebu_get_soc_id(&dev, &rev) != 0) + return; + + if (rev != ARMADA_375_Z1_REV) + return; + + resume_addr_reg = system_controller_phys_base + + mvebu_sc->resume_boot_addr; + mvebu_setup_boot_addr_wa(ARMADA_375_CRYPT0_ENG_TARGET, + ARMADA_375_CRYPT0_ENG_ATTR, + resume_addr_reg); +} + void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) { BUG_ON(system_controller_base == NULL); BUG_ON(mvebu_sc->resume_boot_addr == 0); + + if (of_machine_is_compatible("marvell,armada375")) + mvebu_armada375_smp_wa_init(); + writel(virt_to_phys(boot_addr), system_controller_base + mvebu_sc->resume_boot_addr); } @@ -138,7 +166,10 @@ static int __init mvebu_system_controller_init(void) np = of_find_matching_node_and_match(NULL, of_system_controller_table, &match); if (np) { + struct resource res; system_controller_base = of_iomap(np, 0); + of_address_to_resource(np, 0, &res); + system_controller_phys_base = res.start; mvebu_sc = (struct mvebu_system_controller *)match->data; of_node_put(np); } -- cgit v1.1 From 898ef3e9bfc7f5c94a1e67d0a540e224e2496909 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:42 +0200 Subject: ARM: mvebu: rename the armada_370_xp symbols to mvebu_v7 in pmsu.c Most of the function related to the PMSU are not specific to the Armada 370 or Armada XP SoCs. They can also be used for most of the other mvebu ARMv7 SoCs, and will actually be used to support cpuidle on Armada 38x. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-6-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/armada-370-xp.h | 1 - arch/arm/mach-mvebu/platsmp.c | 2 +- arch/arm/mach-mvebu/pmsu.c | 34 +++++++++++++++++----------------- arch/arm/mach-mvebu/pmsu.h | 2 ++ 4 files changed, 20 insertions(+), 19 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h index 52c1603a..84cd90d 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.h +++ b/arch/arm/mach-mvebu/armada-370-xp.h @@ -25,6 +25,5 @@ extern struct smp_operations armada_xp_smp_ops; #endif int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); -void armada_370_xp_pmsu_idle_exit(void); #endif /* __MACH_ARMADA_370_XP_H */ diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index b6fa9f0..6da2b72 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -108,7 +108,7 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) */ static void armada_xp_secondary_init(unsigned int cpu) { - armada_370_xp_pmsu_idle_exit(); + mvebu_v7_pmsu_idle_exit(); } static void __init armada_xp_smp_init_cpus(void) diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 272a9c05..501d450 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -73,7 +73,7 @@ extern void ll_enable_coherency(void); extern void armada_370_xp_cpu_resume(void); -static struct platform_device armada_xp_cpuidle_device = { +static struct platform_device mvebu_v7_cpuidle_device = { .name = "cpuidle-armada-370-xp", }; @@ -132,7 +132,7 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, return 0; } -static int __init armada_370_xp_pmsu_init(void) +static int __init mvebu_v7_pmsu_init(void) { struct device_node *np; struct resource res; @@ -176,7 +176,7 @@ static int __init armada_370_xp_pmsu_init(void) return ret; } -static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) +static void mvebu_v7_pmsu_enable_l2_powerdown_onidle(void) { u32 reg; @@ -190,7 +190,7 @@ static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) } /* No locking is needed because we only access per-CPU registers */ -static int armada_370_xp_prepare(unsigned long deepidle) +static int mvebu_v7_pmsu_idle_prepare(bool deepidle) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -233,7 +233,7 @@ int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) { int ret; - ret = armada_370_xp_prepare(deepidle); + ret = mvebu_v7_pmsu_idle_prepare(deepidle); if (ret) return ret; @@ -272,7 +272,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle) } /* No locking is needed because we only access per-CPU registers */ -void armada_370_xp_pmsu_idle_exit(void) +void mvebu_v7_pmsu_idle_exit(void) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -294,24 +294,24 @@ void armada_370_xp_pmsu_idle_exit(void) writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu)); } -static int armada_370_xp_cpu_pm_notify(struct notifier_block *self, +static int mvebu_v7_cpu_pm_notify(struct notifier_block *self, unsigned long action, void *hcpu) { if (action == CPU_PM_ENTER) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume); } else if (action == CPU_PM_EXIT) { - armada_370_xp_pmsu_idle_exit(); + mvebu_v7_pmsu_idle_exit(); } return NOTIFY_OK; } -static struct notifier_block armada_370_xp_cpu_pm_notifier = { - .notifier_call = armada_370_xp_cpu_pm_notify, +static struct notifier_block mvebu_v7_cpu_pm_notifier = { + .notifier_call = mvebu_v7_cpu_pm_notify, }; -static int __init armada_370_xp_cpu_pm_init(void) +static int __init mvebu_v7_cpu_pm_init(void) { struct device_node *np; @@ -334,13 +334,13 @@ static int __init armada_370_xp_cpu_pm_init(void) return 0; of_node_put(np); - armada_370_xp_pmsu_enable_l2_powerdown_onidle(); - armada_xp_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; - platform_device_register(&armada_xp_cpuidle_device); - cpu_pm_register_notifier(&armada_370_xp_cpu_pm_notifier); + mvebu_v7_pmsu_enable_l2_powerdown_onidle(); + mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; + platform_device_register(&mvebu_v7_cpuidle_device); + cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier); return 0; } -arch_initcall(armada_370_xp_cpu_pm_init); -early_initcall(armada_370_xp_pmsu_init); +arch_initcall(mvebu_v7_cpu_pm_init); +early_initcall(mvebu_v7_pmsu_init); diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index ae50194..6b58c1f 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h @@ -16,4 +16,6 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, unsigned int crypto_eng_attribute, phys_addr_t resume_addr_reg); +void mvebu_v7_pmsu_idle_exit(void); + #endif /* __MACH_370_XP_PMSU_H */ -- cgit v1.1 From 54a4d1b8d4ca808f46fc3ad3fd9b2c6fd79286a9 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:43 +0200 Subject: ARM: mvebu: make the cpuidle initialization more generic In preparation to the addition of the cpuidle support for more SoCs, this patch moves the Armada XP specific initialization to a separate function. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-7-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 501d450..e976c3e 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -311,31 +311,39 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = { .notifier_call = mvebu_v7_cpu_pm_notify, }; -static int __init mvebu_v7_cpu_pm_init(void) +static int __init armada_xp_cpuidle_init(void) { struct device_node *np; - /* - * Check that all the requirements are available to enable - * cpuidle. So far, it is only supported on Armada XP, cpuidle - * needs the coherency fabric and the PMSU enabled - */ - - if (!of_machine_is_compatible("marvell,armadaxp")) - return 0; - np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); if (!np) - return 0; + return -ENODEV; of_node_put(np); + mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; + + return 0; +} + +static int __init mvebu_v7_cpu_pm_init(void) +{ + struct device_node *np; + int ret; + np = of_find_matching_node(NULL, of_pmsu_table); if (!np) return 0; of_node_put(np); + if (of_machine_is_compatible("marvell,armadaxp")) + ret = armada_xp_cpuidle_init(); + else + return 0; + + if (ret) + return ret; + mvebu_v7_pmsu_enable_l2_powerdown_onidle(); - mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; platform_device_register(&mvebu_v7_cpuidle_device); cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier); -- cgit v1.1 From 752a99377673cd251517623df138ca3c5b8fe772 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:44 +0200 Subject: ARM: mvebu: use a local variable to store the resume address The resume address used by the cpuidle code will not always be the same depending on the SoC. Using a local variable to store the resume address allows to keep the same function for the PM notifier but with a different address. This address will be set during the initialization of the cpuidle logic in pmsu.c. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-8-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index e976c3e..ab525b7 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -73,6 +73,8 @@ extern void ll_enable_coherency(void); extern void armada_370_xp_cpu_resume(void); +static void *mvebu_cpu_resume; + static struct platform_device mvebu_v7_cpuidle_device = { .name = "cpuidle-armada-370-xp", }; @@ -299,7 +301,7 @@ static int mvebu_v7_cpu_pm_notify(struct notifier_block *self, { if (action == CPU_PM_ENTER) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); - mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume); + mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cpu_resume); } else if (action == CPU_PM_EXIT) { mvebu_v7_pmsu_idle_exit(); } @@ -320,6 +322,7 @@ static int __init armada_xp_cpuidle_init(void) return -ENODEV; of_node_put(np); + mvebu_cpu_resume = armada_370_xp_cpu_resume; mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; return 0; -- cgit v1.1 From 5da964e0fae05fd96a97a0fcc6bc53dad655f61d Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:45 +0200 Subject: ARM: mvebu: make the snoop disabling optional in mvebu_v7_pmsu_idle_prepare() On some mvebu v7 SoCs (the ones using a Cortex-A9 core and not a PJ4B core), the snoop disabling feature does not exist as the hardware coherency is handled in a different way. Therefore, in preparation to the introduction of the cpuidle support for those SoCs, this commit modifies the mvebu_v7_psmu_idle_prepare() function to take several flags, which allow to decide whether snooping should be disabled, and whether we should use the deep idle mode or not. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-9-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index ab525b7..15e67bf 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -191,8 +191,14 @@ static void mvebu_v7_pmsu_enable_l2_powerdown_onidle(void) writel(reg, pmsu_mp_base + L2C_NFABRIC_PM_CTL); } +enum pmsu_idle_prepare_flags { + PMSU_PREPARE_NORMAL = 0, + PMSU_PREPARE_DEEP_IDLE = BIT(0), + PMSU_PREPARE_SNOOP_DISABLE = BIT(1), +}; + /* No locking is needed because we only access per-CPU registers */ -static int mvebu_v7_pmsu_idle_prepare(bool deepidle) +static int mvebu_v7_pmsu_idle_prepare(unsigned long flags) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -216,26 +222,32 @@ static int mvebu_v7_pmsu_idle_prepare(bool deepidle) reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); /* ask HW to power down the L2 Cache if needed */ - if (deepidle) + if (flags & PMSU_PREPARE_DEEP_IDLE) reg |= PMSU_CONTROL_AND_CONFIG_L2_PWDDN; /* request power down */ reg |= PMSU_CONTROL_AND_CONFIG_PWDDN_REQ; writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); - /* Disable snoop disable by HW - SW is taking care of it */ - reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); - reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; - writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); + if (flags & PMSU_PREPARE_SNOOP_DISABLE) { + /* Disable snoop disable by HW - SW is taking care of it */ + reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); + reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; + writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); + } return 0; } int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) { + unsigned long flags = PMSU_PREPARE_SNOOP_DISABLE; int ret; - ret = mvebu_v7_pmsu_idle_prepare(deepidle); + if (deepidle) + flags |= PMSU_PREPARE_DEEP_IDLE; + + ret = mvebu_v7_pmsu_idle_prepare(flags); if (ret) return ret; -- cgit v1.1 From 6a2b5343e23b177e684f97302f30696dfcfe0af4 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:46 +0200 Subject: ARM: mvebu: export the SCU address The SCU address will be needed in other files than board-v7.c, especially in pmsu.c for cpuidle related activities. So this patch adds a function that allows to retrieve the virtual address at which the SCU has been mapped. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-10-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/board-v7.c | 9 +++++++-- arch/arm/mach-mvebu/common.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index f244622..6478626 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -34,14 +34,14 @@ #include "coherency.h" #include "mvebu-soc-id.h" +static void __iomem *scu_base; + /* * Enables the SCU when available. Obviously, this is only useful on * Cortex-A based SOCs, not on PJ4B based ones. */ static void __init mvebu_scu_enable(void) { - void __iomem *scu_base; - struct device_node *np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); if (np) { @@ -51,6 +51,11 @@ static void __init mvebu_scu_enable(void) } } +void __iomem *mvebu_get_scu_base(void) +{ + return scu_base; +} + /* * Early versions of Armada 375 SoC have a bug where the BootROM * leaves an external data abort pending. The kernel is hit by this diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index a97778e..3ccb40c 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -23,4 +23,6 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr); void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr); int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev); +void __iomem *mvebu_get_scu_base(void); + #endif -- cgit v1.1 From f50ee824713863016dd684fe43c9eb472963f4fd Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:48 +0200 Subject: cpuidle: mvebu: rename the driver from armada-370-xp to mvebu-v7 This driver will be able to manage the cpuidle for more SoCs than just Armada 370 and XP. It will also support Armada 38x and potentially other SoC of the Marvell Armada EBU family. To take this into account, this patch renames the driver and its symbols. It also changes the driver name from cpuidle-armada-370-xp to cpuidle-armada-xp, because separate platform drivers will be registered for the other SoC types. This change must be done simultaneously in the cpuidle driver and in the PMSU code in order to remain bisectable. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Acked-by: Daniel Lezcano Link: https://lkml.kernel.org/r/1406120453-29291-12-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 15e67bf..0cd2d09 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -76,7 +76,7 @@ extern void armada_370_xp_cpu_resume(void); static void *mvebu_cpu_resume; static struct platform_device mvebu_v7_cpuidle_device = { - .name = "cpuidle-armada-370-xp", + .name = "cpuidle-armada-xp", }; static struct of_device_id of_pmsu_table[] = { -- cgit v1.1 From 3b9e4b1441aedcb26079f690aa11f3f9f93e5182 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:51 +0200 Subject: ARM: mvebu: add cpuidle support for Armada 370 This commit introduces the cpuidle support for Armada 370. The main difference compared to the already supported Armada XP is that the Armada 370 has an issue caused by "a slow exit process from the deep idle state due to heavy L1/L2 cache cleanup operations performed by the BootROM software" (cf errata GL-BootROM-10). To work around this issue, we replace the restart code of the BootROM by some custom code located in an internal SRAM. For this purpose, we use the common function mvebu_boot_addr_wa() introduced in the commit "ARM: mvebu: Add a common function for the boot address work around". The message in case of failure to suspend the system was switched from the warn level to the debug level. Indeed due to the "slow exit process from the deep idle state" in Armada 370, this situation happens quite often. Using the debug level avoids spamming the kernel logs, but still allows to enable it if needed. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-15-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 51 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 0cd2d09..9190ae8 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -34,7 +34,6 @@ #include #include "common.h" -static void __iomem *pmsu_mp_base; #define PMSU_BASE_OFFSET 0x100 #define PMSU_REG_SIZE 0x1000 @@ -68,17 +67,18 @@ static void __iomem *pmsu_mp_base; #define BOOTROM_BASE 0xFFF00000 #define BOOTROM_SIZE 0x100000 +#define ARMADA_370_CRYPT0_ENG_TARGET 0x9 +#define ARMADA_370_CRYPT0_ENG_ATTR 0x1 + extern void ll_disable_coherency(void); extern void ll_enable_coherency(void); extern void armada_370_xp_cpu_resume(void); +static phys_addr_t pmsu_mp_phys_base; +static void __iomem *pmsu_mp_base; static void *mvebu_cpu_resume; -static struct platform_device mvebu_v7_cpuidle_device = { - .name = "cpuidle-armada-xp", -}; - static struct of_device_id of_pmsu_table[] = { { .compatible = "marvell,armada-370-pmsu", }, { .compatible = "marvell,armada-370-xp-pmsu", }, @@ -165,6 +165,8 @@ static int __init mvebu_v7_pmsu_init(void) goto out; } + pmsu_mp_phys_base = res.start; + pmsu_mp_base = ioremap(res.start, resource_size(&res)); if (!pmsu_mp_base) { pr_err("unable to map registers\n"); @@ -275,7 +277,7 @@ int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) "isb " : : : "r0"); - pr_warn("Failed to suspend the system\n"); + pr_debug("Failed to suspend the system\n"); return 0; } @@ -325,7 +327,39 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = { .notifier_call = mvebu_v7_cpu_pm_notify, }; -static int __init armada_xp_cpuidle_init(void) +static struct platform_device mvebu_v7_cpuidle_device; + +static __init int armada_370_cpuidle_init(void) +{ + struct device_node *np; + phys_addr_t redirect_reg; + + np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); + if (!np) + return -ENODEV; + of_node_put(np); + + /* + * On Armada 370, there is "a slow exit process from the deep + * idle state due to heavy L1/L2 cache cleanup operations + * performed by the BootROM software". To avoid this, we + * replace the restart code of the bootrom by a a simple jump + * to the boot address. Then the code located at this boot + * address will take care of the initialization. + */ + redirect_reg = pmsu_mp_phys_base + PMSU_BOOT_ADDR_REDIRECT_OFFSET(0); + mvebu_setup_boot_addr_wa(ARMADA_370_CRYPT0_ENG_TARGET, + ARMADA_370_CRYPT0_ENG_ATTR, + redirect_reg); + + mvebu_cpu_resume = armada_370_xp_cpu_resume; + mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; + mvebu_v7_cpuidle_device.name = "cpuidle-armada-370"; + + return 0; +} + +static __init int armada_xp_cpuidle_init(void) { struct device_node *np; @@ -336,6 +370,7 @@ static int __init armada_xp_cpuidle_init(void) mvebu_cpu_resume = armada_370_xp_cpu_resume; mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; + mvebu_v7_cpuidle_device.name = "cpuidle-armada-xp"; return 0; } @@ -352,6 +387,8 @@ static int __init mvebu_v7_cpu_pm_init(void) if (of_machine_is_compatible("marvell,armadaxp")) ret = armada_xp_cpuidle_init(); + else if (of_machine_is_compatible("marvell,armada370")) + ret = armada_370_cpuidle_init(); else return 0; -- cgit v1.1 From e53b1fd432497942a0fdfd0e89c3d30241cb4d2c Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:52 +0200 Subject: ARM: mvebu: add cpuidle support for Armada 38x Unlike the Armada XP and the Armada 370, this SoC uses a Cortex A9 core. Consequently, the procedure to enter the idle state is different: interaction with the SCU, not disabling snooping, etc. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-16-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 85 ++++++++++++++++++++++++++++++++++++++++++- arch/arm/mach-mvebu/pmsu_ll.S | 14 +++++++ 2 files changed, 98 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 9190ae8..bd7c66a 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,18 @@ #define L2C_NFABRIC_PM_CTL 0x4 #define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20) +/* PMSU delay registers */ +#define PMSU_POWERDOWN_DELAY 0xF04 +#define PMSU_POWERDOWN_DELAY_PMU BIT(1) +#define PMSU_POWERDOWN_DELAY_MASK 0xFFFE +#define PMSU_DFLT_ARMADA38X_DELAY 0x64 + +/* CA9 MPcore SoC Control registers */ + +#define MPCORE_RESET_CTL 0x64 +#define MPCORE_RESET_CTL_L2 BIT(0) +#define MPCORE_RESET_CTL_DEBUG BIT(16) + #define SRAM_PHYS_BASE 0xFFFF0000 #define BOOTROM_BASE 0xFFF00000 #define BOOTROM_SIZE 0x100000 @@ -74,6 +87,8 @@ extern void ll_disable_coherency(void); extern void ll_enable_coherency(void); extern void armada_370_xp_cpu_resume(void); +extern void armada_38x_cpu_resume(void); + static phys_addr_t pmsu_mp_phys_base; static void __iomem *pmsu_mp_base; @@ -287,6 +302,32 @@ 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) +{ + unsigned long flags = 0; + + if (deepidle) + flags |= PMSU_PREPARE_DEEP_IDLE; + + mvebu_v7_pmsu_idle_prepare(flags); + /* + * Already flushed cache, but do it again as the outer cache + * functions dirty the cache with spinlocks + */ + v7_exit_coherency_flush(louis); + + scu_power_mode(mvebu_get_scu_base(), SCU_PM_POWEROFF); + + cpu_do_idle(); + + return 1; +} + +static int armada_38x_cpu_suspend(unsigned long deepidle) +{ + return cpu_suspend(false, armada_38x_do_cpu_suspend); +} + /* No locking is needed because we only access per-CPU registers */ void mvebu_v7_pmsu_idle_exit(void) { @@ -295,7 +336,6 @@ void mvebu_v7_pmsu_idle_exit(void) if (pmsu_mp_base == NULL) return; - /* cancel ask HW to power down the L2 Cache if possible */ reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN; @@ -359,6 +399,47 @@ static __init int armada_370_cpuidle_init(void) return 0; } +static __init int armada_38x_cpuidle_init(void) +{ + struct device_node *np; + void __iomem *mpsoc_base; + u32 reg; + + np = of_find_compatible_node(NULL, NULL, + "marvell,armada-380-coherency-fabric"); + if (!np) + return -ENODEV; + of_node_put(np); + + np = of_find_compatible_node(NULL, NULL, + "marvell,armada-380-mpcore-soc-ctrl"); + if (!np) + return -ENODEV; + mpsoc_base = of_iomap(np, 0); + BUG_ON(!mpsoc_base); + of_node_put(np); + + /* Set up reset mask when powering down the cpus */ + reg = readl(mpsoc_base + MPCORE_RESET_CTL); + reg |= MPCORE_RESET_CTL_L2; + reg |= MPCORE_RESET_CTL_DEBUG; + writel(reg, mpsoc_base + MPCORE_RESET_CTL); + iounmap(mpsoc_base); + + /* Set up delay */ + reg = readl(pmsu_mp_base + PMSU_POWERDOWN_DELAY); + reg &= ~PMSU_POWERDOWN_DELAY_MASK; + reg |= PMSU_DFLT_ARMADA38X_DELAY; + reg |= PMSU_POWERDOWN_DELAY_PMU; + writel(reg, pmsu_mp_base + PMSU_POWERDOWN_DELAY); + + mvebu_cpu_resume = armada_38x_cpu_resume; + mvebu_v7_cpuidle_device.dev.platform_data = armada_38x_cpu_suspend; + mvebu_v7_cpuidle_device.name = "cpuidle-armada-38x"; + + return 0; +} + static __init int armada_xp_cpuidle_init(void) { struct device_node *np; @@ -389,6 +470,8 @@ static int __init mvebu_v7_cpu_pm_init(void) ret = armada_xp_cpuidle_init(); else if (of_machine_is_compatible("marvell,armada370")) ret = armada_370_cpuidle_init(); + else if (of_machine_is_compatible("marvell,armada380")) + ret = armada_38x_cpuidle_init(); else return 0; diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S index 17d7f3b..a945756 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S @@ -23,6 +23,20 @@ ARM_BE8(setend be ) @ go BE8 if entered LE b cpu_resume ENDPROC(armada_370_xp_cpu_resume) +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 + b cpu_resume +ENDPROC(armada_38x_cpu_resume) + .global mvebu_boot_wa_start .global mvebu_boot_wa_end -- cgit v1.1