xref: /openbmc/linux/arch/arm/mach-imx/platsmp.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
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