From 35b2775416d96a735999eddf94b4d0af0f6e3f9e Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 27 Oct 2016 15:33:59 +0300 Subject: [PATCH] MLK-11265-7 ARM: imx: add smp support for imx7d Add SMP support for i.MX7D, including CPU hotplug support. Signed-off-by: Anson Huang --- arch/arm/mach-imx/headsmp.S | 13 ++++++- arch/arm/mach-imx/hotplug.c | 5 ++- arch/arm/mach-imx/mach-imx7d.c | 1 + arch/arm/mach-imx/platsmp.c | 38 +++++++++++++++--- arch/arm/mach-imx/src.c | 70 +++++++++++++++++++++++++--------- 5 files changed, 103 insertions(+), 24 deletions(-) diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S index 6c28d28b3c64..5d6a5e2fe9ee 100644 --- a/arch/arm/mach-imx/headsmp.S +++ b/arch/arm/mach-imx/headsmp.S @@ -1,5 +1,5 @@ /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -27,6 +27,17 @@ diag_reg_offset: ENTRY(v7_secondary_startup) ARM_BE8(setend be) @ go BE8 if entered LE + mrc p15, 0, r0, c0, c0, 0 + ldr r1, =0xf00 + orr r1, r1, #0xff + mov r0, r0, lsr #4 + and r0, r0, r1 + /* 0xc07 is cortex A7's ID */ + ldr r1, =0xc00 + orr r1, r1, #0x7 + cmp r0, r1 + beq secondary_startup + set_diag_reg b secondary_startup ENDPROC(v7_secondary_startup) diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index b35e99cc5e5b..06dab2fc1c25 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -1,5 +1,5 @@ /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -16,6 +16,7 @@ #include #include "common.h" +#include "hardware.h" static inline void cpu_enter_lowpower(void) { @@ -66,5 +67,7 @@ int imx_cpu_kill(unsigned int cpu) return 0; imx_enable_cpu(cpu, false); imx_set_cpu_arg(cpu, 0); + if (cpu_is_imx7d()) + imx_gpcv2_set_core1_pdn_pup_by_software(true); return 1; } diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c index 003ef45b8d52..8b9b8cbfae30 100644 --- a/arch/arm/mach-imx/mach-imx7d.c +++ b/arch/arm/mach-imx/mach-imx7d.c @@ -118,6 +118,7 @@ static const char *const imx7d_dt_compat[] __initconst = { DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)") .map_io = imx7d_map_io, + .smp = smp_ops(imx_smp_ops), .init_irq = imx7d_init_irq, .init_machine = imx7d_init_machine, .dt_compat = imx7d_dt_compat, diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index 711dbbd5badd..8ec0a278a9c5 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -1,5 +1,5 @@ /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -24,7 +24,7 @@ #include "hardware.h" u32 g_diag_reg; -static void __iomem *scu_base; +static void __iomem *imx_scu_base; static struct map_desc scu_io_desc __initdata = { /* .virtual and .pfn are run-time assigned */ @@ -43,7 +43,7 @@ void __init imx_scu_map_io(void) scu_io_desc.pfn = __phys_to_pfn(base); iotable_init(&scu_io_desc, 1); - scu_base = IMX_IO_ADDRESS(base); + imx_scu_base = IMX_IO_ADDRESS(base); } static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle) @@ -53,15 +53,39 @@ static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle) return 0; } +#define MXC_ARCH_CA7 0xc07 +static unsigned long __mxc_arch_type; + +static inline bool arm_is_ca7(void) +{ + return __mxc_arch_type == MXC_ARCH_CA7; +} /* * Initialise the CPU possible map early - this describes the CPUs * which may be present or become present in the system. */ static void __init imx_smp_init_cpus(void) { + unsigned long arch_type; int i, ncores; - ncores = scu_get_core_count(scu_base); + asm volatile( + ".align 4\n" + "mrc p15, 0, %0, c0, c0, 0\n" + : "=r" (arch_type) + ); + /* MIDR[15:4] defines ARCH type */ + __mxc_arch_type = (arch_type >> 4) & 0xfff; + + if (arm_is_ca7()) { + unsigned long val; + + /* CA7 core number, [25:24] of CP15 L2CTLR */ + asm volatile("mrc p15, 1, %0, c9, c0, 2" : "=r" (val)); + ncores = ((val >> 24) & 0x3) + 1; + } else { + ncores = scu_get_core_count(imx_scu_base); + } for (i = ncores; i < NR_CPUS; i++) set_cpu_possible(i, false); @@ -69,11 +93,15 @@ static void __init imx_smp_init_cpus(void) void imx_smp_prepare(void) { - scu_enable(scu_base); + if (arm_is_ca7()) + return; + scu_enable(imx_scu_base); } static void __init imx_smp_prepare_cpus(unsigned int max_cpus) { + if (arm_is_ca7()) + return; imx_smp_prepare(); /* diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index 70b083fe934a..f09821356e51 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -1,5 +1,5 @@ /* - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011-2015 Freescale Semiconductor, Inc. * Copyright 2011 Linaro Ltd. * * The code contained herein is licensed under the GNU General Public @@ -18,6 +18,7 @@ #include #include #include "common.h" +#include "hardware.h" #define SRC_SCR 0x000 #define SRC_GPR1 0x020 @@ -29,9 +30,16 @@ #define BP_SRC_SCR_SW_IPU2_RST 12 #define BP_SRC_SCR_CORE1_RST 14 #define BP_SRC_SCR_CORE1_ENABLE 22 +/* below is for i.MX7D */ +#define SRC_GPR1_V2 0x074 +#define SRC_A7RCR0 0x004 +#define SRC_A7RCR1 0x008 + +#define BP_SRC_A7RCR0_A7_CORE_RESET0 0 +#define BP_SRC_A7RCR1_A7_CORE1_ENABLE 1 static void __iomem *src_base; -static DEFINE_SPINLOCK(scr_lock); +static DEFINE_SPINLOCK(src_lock); static const int sw_reset_bits[5] = { BP_SRC_SCR_SW_GPU_RST, @@ -57,11 +65,11 @@ static int imx_src_reset_module(struct reset_controller_dev *rcdev, bit = 1 << sw_reset_bits[sw_reset_idx]; - spin_lock_irqsave(&scr_lock, flags); + spin_lock_irqsave(&src_lock, flags); val = readl_relaxed(src_base + SRC_SCR); val |= bit; writel_relaxed(val, src_base + SRC_SCR); - spin_unlock_irqrestore(&scr_lock, flags); + spin_unlock_irqrestore(&src_lock, flags); timeout = jiffies + msecs_to_jiffies(1000); while (readl(src_base + SRC_SCR) & bit) { @@ -87,32 +95,57 @@ void imx_enable_cpu(int cpu, bool enable) u32 mask, val; cpu = cpu_logical_map(cpu); - mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); - spin_lock(&scr_lock); - val = readl_relaxed(src_base + SRC_SCR); - val = enable ? val | mask : val & ~mask; - val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); - writel_relaxed(val, src_base + SRC_SCR); - spin_unlock(&scr_lock); + spin_lock(&src_lock); + if (cpu_is_imx7d()) { + /* enable core */ + if (enable) + imx_gpcv2_set_core1_pdn_pup_by_software(false); + + mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_A7RCR1); + val = enable ? val | mask : val & ~mask; + writel_relaxed(val, src_base + SRC_A7RCR1); + } else { + mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_SCR); + val = enable ? val | mask : val & ~mask; + val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); + writel_relaxed(val, src_base + SRC_SCR); + } + spin_unlock(&src_lock); } void imx_set_cpu_jump(int cpu, void *jump_addr) { cpu = cpu_logical_map(cpu); - writel_relaxed(virt_to_phys(jump_addr), - src_base + SRC_GPR1 + cpu * 8); + if (cpu_is_imx7d()) + writel_relaxed(virt_to_phys(jump_addr), + src_base + SRC_GPR1_V2 + cpu * 8); + else + writel_relaxed(virt_to_phys(jump_addr), + src_base + SRC_GPR1 + cpu * 8); } u32 imx_get_cpu_arg(int cpu) { cpu = cpu_logical_map(cpu); - return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4); + if (cpu_is_imx7d()) + return readl_relaxed(src_base + SRC_GPR1_V2 + + cpu * 8 + 4); + else + return readl_relaxed(src_base + SRC_GPR1 + + cpu * 8 + 4); } void imx_set_cpu_arg(int cpu, u32 arg) { cpu = cpu_logical_map(cpu); - writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4); + if (cpu_is_imx7d()) + writel_relaxed(arg, src_base + SRC_GPR1_V2 + + cpu * 8 + 4); + else + writel_relaxed(arg, src_base + SRC_GPR1 + + cpu * 8 + 4); } void __init imx_src_init(void) @@ -126,6 +159,9 @@ void __init imx_src_init(void) src_base = of_iomap(np, 0); WARN_ON(!src_base); + if (cpu_is_imx7d()) + return; + imx_reset_controller.of_node = np; if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) reset_controller_register(&imx_reset_controller); @@ -134,9 +170,9 @@ void __init imx_src_init(void) * force warm reset sources to generate cold reset * for a more reliable restart */ - spin_lock(&scr_lock); + spin_lock(&src_lock); val = readl_relaxed(src_base + SRC_SCR); val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE); writel_relaxed(val, src_base + SRC_SCR); - spin_unlock(&scr_lock); + spin_unlock(&src_lock); } -- 2.17.1