[PATCH 3/3] ARM: imx: add SMP support for i.MX7D

From: Anson Huang
Date: Thu Aug 25 2016 - 23:59:19 EST


i.MX7D has 2 cortex-a7 ARM core, add support for
booting up SMP kernel with 2 CPUs.

The existing i.MX SMP code is designed for i.MX6
series SoCs which have cortex-a9 ARM core, but i.MX7D
has 2 cortex-a7 ARM core, so we need to add runtime
check for those differences between cortex-a9 and
cortex-a7.

Signed-off-by: Anson Huang <Anson.Huang@xxxxxxx>
---
arch/arm/mach-imx/headsmp.S | 11 +++++++++++
arch/arm/mach-imx/mach-imx7d.c | 2 ++
arch/arm/mach-imx/platsmp.c | 19 ++++++++++++++++++-
arch/arm/mach-imx/src.c | 38 ++++++++++++++++++++++++++++++--------
4 files changed, 61 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S
index 6c28d28..a26e459 100644
--- a/arch/arm/mach-imx/headsmp.S
+++ b/arch/arm/mach-imx/headsmp.S
@@ -26,7 +26,18 @@ diag_reg_offset:
.endm

ENTRY(v7_secondary_startup)
+ .word 0xc070 @ 0xc07 is cortex-a7 id
+ .word 0xfff0 @ mask for core type
+
ARM_BE8(setend be) @ go BE8 if entered LE
+ mrc p15, 0, r0, c0, c0, 0
+ adr r1, v7_secondary_startup
+ ldr r2, [r1]
+ ldr r3, [r1, #0x4]
+ and r0, r0, r3
+ cmp r0, r2
+ beq secondary_startup
+
set_diag_reg
b secondary_startup
ENDPROC(v7_secondary_startup)
diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c
index 26ca744..ef3dce6 100644
--- a/arch/arm/mach-imx/mach-imx7d.c
+++ b/arch/arm/mach-imx/mach-imx7d.c
@@ -99,6 +99,7 @@ static void __init imx7d_init_machine(void)

static void __init imx7d_init_irq(void)
{
+ imx_gpcv2_check_dt();
imx_init_revision_from_anatop();
imx_src_init();
irqchip_init();
@@ -111,6 +112,7 @@ static const char *const imx7d_dt_compat[] __initconst = {
};

DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
+ .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 711dbbd..63af911 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -60,8 +60,17 @@ static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle)
static void __init imx_smp_init_cpus(void)
{
int i, ncores;
+ unsigned long val, arch_type;

- ncores = scu_get_core_count(scu_base);
+ asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (arch_type));
+
+ if (((arch_type >> 4) & 0xfff) == 0xc07) {
+ /* cortex-a7 core number is in bit[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(scu_base);
+ }

for (i = ncores; i < NR_CPUS; i++)
set_cpu_possible(i, false);
@@ -74,6 +83,14 @@ void imx_smp_prepare(void)

static void __init imx_smp_prepare_cpus(unsigned int max_cpus)
{
+ unsigned long arch_type;
+
+ asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (arch_type));
+
+ /* no need for cortex-a7 */
+ if (((arch_type >> 4) & 0xfff) == 0xc07)
+ return;
+
imx_smp_prepare();

/*
diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c
index 70b083f..1fda72a 100644
--- a/arch/arm/mach-imx/src.c
+++ b/arch/arm/mach-imx/src.c
@@ -18,6 +18,7 @@
#include <linux/smp.h>
#include <asm/smp_plat.h>
#include "common.h"
+#include "hardware.h"

#define SRC_SCR 0x000
#define SRC_GPR1 0x020
@@ -30,6 +31,15 @@
#define BP_SRC_SCR_CORE1_RST 14
#define BP_SRC_SCR_CORE1_ENABLE 22

+/* below are for i.MX7D */
+#define SRC_GPR1_V2 0x074
+#define SRC_A7RCR0 0x004
+#define SRC_A7RCR1 0x008
+#define SRC_M4RCR 0x00C
+
+#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);

@@ -87,12 +97,21 @@ 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);
+ if (cpu_is_imx7d()) {
+ 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(&scr_lock);
}

@@ -100,19 +119,22 @@ 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);
+ src_base + (cpu_is_imx7d() ?
+ SRC_GPR1_V2 : 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);
+ return readl_relaxed(src_base + (cpu_is_imx7d() ?
+ SRC_GPR1_V2 : 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);
+ writel_relaxed(arg, src_base + (cpu_is_imx7d() ?
+ SRC_GPR1_V2 : SRC_GPR1) + cpu * 8 + 4);
}

void __init imx_src_init(void)
--
1.9.1