1fcaf2036SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
269c31b7aSShawn Guo /*
369c31b7aSShawn Guo * Copyright 2011 Freescale Semiconductor, Inc.
469c31b7aSShawn Guo * Copyright 2011 Linaro Ltd.
569c31b7aSShawn Guo */
669c31b7aSShawn Guo
769c31b7aSShawn Guo #include <linux/init.h>
84e3fea4aSJingchang Lu #include <linux/of_address.h>
94e3fea4aSJingchang Lu #include <linux/of.h>
1069c31b7aSShawn Guo #include <linux/smp.h>
114e3fea4aSJingchang Lu
12087bb283SShawn Guo #include <asm/cacheflush.h>
1369c31b7aSShawn Guo #include <asm/page.h>
1469c31b7aSShawn Guo #include <asm/smp_scu.h>
1569c31b7aSShawn Guo #include <asm/mach/map.h>
1669c31b7aSShawn Guo
17e3372474SShawn Guo #include "common.h"
1850f2de61SShawn Guo #include "hardware.h"
19e3372474SShawn Guo
20087bb283SShawn Guo u32 g_diag_reg;
2169c31b7aSShawn Guo static void __iomem *scu_base;
2269c31b7aSShawn Guo
2369c31b7aSShawn Guo static struct map_desc scu_io_desc __initdata = {
2469c31b7aSShawn Guo /* .virtual and .pfn are run-time assigned */
2569c31b7aSShawn Guo .length = SZ_4K,
2669c31b7aSShawn Guo .type = MT_DEVICE,
2769c31b7aSShawn Guo };
2869c31b7aSShawn Guo
imx_scu_map_io(void)2969c31b7aSShawn Guo void __init imx_scu_map_io(void)
3069c31b7aSShawn Guo {
3169c31b7aSShawn Guo unsigned long base;
3269c31b7aSShawn Guo
3369c31b7aSShawn Guo /* Get SCU base */
3469c31b7aSShawn Guo asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
3569c31b7aSShawn Guo
3669c31b7aSShawn Guo scu_io_desc.virtual = IMX_IO_P2V(base);
3769c31b7aSShawn Guo scu_io_desc.pfn = __phys_to_pfn(base);
3869c31b7aSShawn Guo iotable_init(&scu_io_desc, 1);
3969c31b7aSShawn Guo
4069c31b7aSShawn Guo scu_base = IMX_IO_ADDRESS(base);
4169c31b7aSShawn Guo }
4269c31b7aSShawn Guo
imx_boot_secondary(unsigned int cpu,struct task_struct * idle)438bd26e3aSPaul Gortmaker static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle)
4469c31b7aSShawn Guo {
4569c31b7aSShawn Guo imx_set_cpu_jump(cpu, v7_secondary_startup);
4669c31b7aSShawn Guo imx_enable_cpu(cpu, true);
4769c31b7aSShawn Guo return 0;
4869c31b7aSShawn Guo }
4969c31b7aSShawn Guo
5069c31b7aSShawn Guo /*
5169c31b7aSShawn Guo * Initialise the CPU possible map early - this describes the CPUs
5269c31b7aSShawn Guo * which may be present or become present in the system.
5369c31b7aSShawn Guo */
imx_smp_init_cpus(void)54e4f2d979SMarc Zyngier static void __init imx_smp_init_cpus(void)
5569c31b7aSShawn Guo {
5669c31b7aSShawn Guo int i, ncores;
5769c31b7aSShawn Guo
5869c31b7aSShawn Guo ncores = scu_get_core_count(scu_base);
5969c31b7aSShawn Guo
60dc13ba29SShawn Guo for (i = ncores; i < NR_CPUS; i++)
61dc13ba29SShawn Guo set_cpu_possible(i, false);
6269c31b7aSShawn Guo }
6369c31b7aSShawn Guo
imx_smp_prepare(void)6469c31b7aSShawn Guo void imx_smp_prepare(void)
6569c31b7aSShawn Guo {
6669c31b7aSShawn Guo scu_enable(scu_base);
6769c31b7aSShawn Guo }
6869c31b7aSShawn Guo
imx_smp_prepare_cpus(unsigned int max_cpus)69e4f2d979SMarc Zyngier static void __init imx_smp_prepare_cpus(unsigned int max_cpus)
7069c31b7aSShawn Guo {
7169c31b7aSShawn Guo imx_smp_prepare();
72087bb283SShawn Guo
73087bb283SShawn Guo /*
74087bb283SShawn Guo * The diagnostic register holds the errata bits. Mostly bootloader
75087bb283SShawn Guo * does not bring up secondary cores, so that when errata bits are set
76087bb283SShawn Guo * in bootloader, they are set only for boot cpu. But on a SMP
77087bb283SShawn Guo * configuration, it should be equally done on every single core.
78087bb283SShawn Guo * Read the register from boot cpu here, and will replicate it into
79087bb283SShawn Guo * secondary cores when booting them.
80087bb283SShawn Guo */
81087bb283SShawn Guo asm("mrc p15, 0, %0, c15, c0, 1" : "=r" (g_diag_reg) : : "cc");
82f45913fdSNicolas Pitre sync_cache_w(&g_diag_reg);
8369c31b7aSShawn Guo }
84e4f2d979SMarc Zyngier
8575305275SMasahiro Yamada const struct smp_operations imx_smp_ops __initconst = {
86e4f2d979SMarc Zyngier .smp_init_cpus = imx_smp_init_cpus,
87e4f2d979SMarc Zyngier .smp_prepare_cpus = imx_smp_prepare_cpus,
88e4f2d979SMarc Zyngier .smp_boot_secondary = imx_boot_secondary,
89e4f2d979SMarc Zyngier #ifdef CONFIG_HOTPLUG_CPU
90e4f2d979SMarc Zyngier .cpu_die = imx_cpu_die,
9183757664SShawn Guo .cpu_kill = imx_cpu_kill,
92e4f2d979SMarc Zyngier #endif
93e4f2d979SMarc Zyngier };
944e3fea4aSJingchang Lu
95*e34645f4SAnson Huang /*
96*e34645f4SAnson Huang * Initialise the CPU possible map early - this describes the CPUs
97*e34645f4SAnson Huang * which may be present or become present in the system.
98*e34645f4SAnson Huang */
imx7_smp_init_cpus(void)99*e34645f4SAnson Huang static void __init imx7_smp_init_cpus(void)
100*e34645f4SAnson Huang {
101*e34645f4SAnson Huang struct device_node *np;
102*e34645f4SAnson Huang int i, ncores = 0;
103*e34645f4SAnson Huang
104*e34645f4SAnson Huang /* The iMX7D SCU does not report core count, get it from DT */
105*e34645f4SAnson Huang for_each_of_cpu_node(np)
106*e34645f4SAnson Huang ncores++;
107*e34645f4SAnson Huang
108*e34645f4SAnson Huang for (i = ncores; i < NR_CPUS; i++)
109*e34645f4SAnson Huang set_cpu_possible(i, false);
110*e34645f4SAnson Huang }
111*e34645f4SAnson Huang
112*e34645f4SAnson Huang const struct smp_operations imx7_smp_ops __initconst = {
113*e34645f4SAnson Huang .smp_init_cpus = imx7_smp_init_cpus,
114*e34645f4SAnson Huang .smp_boot_secondary = imx_boot_secondary,
115*e34645f4SAnson Huang #ifdef CONFIG_HOTPLUG_CPU
116*e34645f4SAnson Huang .cpu_die = imx_cpu_die,
117*e34645f4SAnson Huang .cpu_kill = imx_cpu_kill,
118*e34645f4SAnson Huang #endif
119*e34645f4SAnson Huang };
120*e34645f4SAnson Huang
1214e3fea4aSJingchang Lu #define DCFG_CCSR_SCRATCHRW1 0x200
1224e3fea4aSJingchang Lu
ls1021a_boot_secondary(unsigned int cpu,struct task_struct * idle)1234e3fea4aSJingchang Lu static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle)
1244e3fea4aSJingchang Lu {
1254e3fea4aSJingchang Lu arch_send_wakeup_ipi_mask(cpumask_of(cpu));
1264e3fea4aSJingchang Lu
1274e3fea4aSJingchang Lu return 0;
1284e3fea4aSJingchang Lu }
1294e3fea4aSJingchang Lu
ls1021a_smp_prepare_cpus(unsigned int max_cpus)1304e3fea4aSJingchang Lu static void __init ls1021a_smp_prepare_cpus(unsigned int max_cpus)
1314e3fea4aSJingchang Lu {
1324e3fea4aSJingchang Lu struct device_node *np;
1334e3fea4aSJingchang Lu void __iomem *dcfg_base;
1344e3fea4aSJingchang Lu unsigned long paddr;
1354e3fea4aSJingchang Lu
1364e3fea4aSJingchang Lu np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg");
1374e3fea4aSJingchang Lu dcfg_base = of_iomap(np, 0);
1384a4fb661SAnson Huang of_node_put(np);
1394e3fea4aSJingchang Lu BUG_ON(!dcfg_base);
1404e3fea4aSJingchang Lu
14164fc2a94SFlorian Fainelli paddr = __pa_symbol(secondary_startup);
1424e3fea4aSJingchang Lu writel_relaxed(cpu_to_be32(paddr), dcfg_base + DCFG_CCSR_SCRATCHRW1);
1434e3fea4aSJingchang Lu
1444e3fea4aSJingchang Lu iounmap(dcfg_base);
1454e3fea4aSJingchang Lu }
1464e3fea4aSJingchang Lu
14775305275SMasahiro Yamada const struct smp_operations ls1021a_smp_ops __initconst = {
1484e3fea4aSJingchang Lu .smp_prepare_cpus = ls1021a_smp_prepare_cpus,
1494e3fea4aSJingchang Lu .smp_boot_secondary = ls1021a_boot_secondary,
1504e3fea4aSJingchang Lu };
151