xref: /netbsd-src/sys/arch/arm/sunxi/sunxi_mc_smp.c (revision 9cae9137acfdd7ffc6712f8130a72719a72025d6)
1*9cae9137Sjmcneill /* $NetBSD: sunxi_mc_smp.c,v 1.4 2019/03/03 17:00:22 jmcneill Exp $ */
208185578Sjmcneill 
308185578Sjmcneill /*-
408185578Sjmcneill  * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca>
508185578Sjmcneill  * All rights reserved.
608185578Sjmcneill  *
708185578Sjmcneill  * Redistribution and use in source and binary forms, with or without
808185578Sjmcneill  * modification, are permitted provided that the following conditions
908185578Sjmcneill  * are met:
1008185578Sjmcneill  * 1. Redistributions of source code must retain the above copyright
1108185578Sjmcneill  *    notice, this list of conditions and the following disclaimer.
1208185578Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
1308185578Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
1408185578Sjmcneill  *    documentation and/or other materials provided with the distribution.
1508185578Sjmcneill  *
1608185578Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1708185578Sjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1808185578Sjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1908185578Sjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2008185578Sjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2108185578Sjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2208185578Sjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2308185578Sjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2408185578Sjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2508185578Sjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2608185578Sjmcneill  * SUCH DAMAGE.
2708185578Sjmcneill  */
2808185578Sjmcneill 
2908185578Sjmcneill #include <sys/cdefs.h>
3008185578Sjmcneill 
31*9cae9137Sjmcneill __KERNEL_RCSID(0, "$NetBSD: sunxi_mc_smp.c,v 1.4 2019/03/03 17:00:22 jmcneill Exp $");
3208185578Sjmcneill 
3308185578Sjmcneill #include <sys/param.h>
3408185578Sjmcneill #include <sys/bus.h>
3508185578Sjmcneill #include <sys/device.h>
3608185578Sjmcneill #include <sys/systm.h>
3708185578Sjmcneill 
3808185578Sjmcneill #include <uvm/uvm_extern.h>
3908185578Sjmcneill 
4008185578Sjmcneill #include <dev/fdt/fdtvar.h>
4108185578Sjmcneill 
4208185578Sjmcneill #include <arm/armreg.h>
4308185578Sjmcneill #include <arm/cpu.h>
4408185578Sjmcneill #include <arm/cpufunc.h>
4508185578Sjmcneill #include <arm/locore.h>
4608185578Sjmcneill 
4708185578Sjmcneill #include <arm/sunxi/sunxi_mc_smp.h>
4808185578Sjmcneill 
4943331e8dSjmcneill #define	A80_PRCM_BASE		0x08001400
5043331e8dSjmcneill #define	A80_PRCM_SIZE		0x200
5108185578Sjmcneill 
5243331e8dSjmcneill #define	A83T_PRCM_BASE		0x01f01400
5343331e8dSjmcneill #define	A83T_PRCM_SIZE		0x800
5408185578Sjmcneill 
5508185578Sjmcneill #define	 PRCM_CL_RST_CTRL(cluster)	(0x4 + (cluster) * 0x4)
5608185578Sjmcneill #define	 PRCM_CL_PWROFF(cluster)	(0x100 + (cluster) * 0x4)
5708185578Sjmcneill #define	 PRCM_CL_PWR_CLAMP(cluster, cpu) (0x140 + (cluster) * 0x10 + (cpu) * 0x4)
5843331e8dSjmcneill #define	 PRCM_CPU_SOFT_ENTRY		0x164
5908185578Sjmcneill 
6008185578Sjmcneill #define	CPUCFG_BASE	0x01f01c00
6108185578Sjmcneill #define	CPUCFG_SIZE	0x400
6208185578Sjmcneill 
6308185578Sjmcneill #define	 CPUCFG_CL_RST(cluster)		(0x30 + (cluster) * 0x4)
6408185578Sjmcneill #define	 CPUCFG_P_REG0			0x1a4
6508185578Sjmcneill 
6608185578Sjmcneill #define	CPUXCFG_BASE	0x01700000
6708185578Sjmcneill #define	CPUXCFG_SIZE	0x400
6808185578Sjmcneill 
6908185578Sjmcneill #define	 CPUXCFG_CL_RST(cluster)	(0x80 + (cluster) * 0x4)
7008185578Sjmcneill #define	  CPUXCFG_CL_RST_SOC_DBG_RST	__BIT(24)
7108185578Sjmcneill #define	  CPUXCFG_CL_RST_ETM_RST(cpu)	__BIT(20 + (cpu))
7208185578Sjmcneill #define	  CPUXCFG_CL_RST_DBG_RST(cpu)	__BIT(16 + (cpu))
7308185578Sjmcneill #define	  CPUXCFG_CL_RST_H_RST		__BIT(12)
7408185578Sjmcneill #define	  CPUXCFG_CL_RST_L2_RST		__BIT(8)
7543331e8dSjmcneill #define	  CPUXCFG_CL_RST_CX_RST(cpu)	__BIT(4 + (cpu))
7608185578Sjmcneill #define	 CPUXCFG_CL_CTRL0(cluster)	(0x0 + (cluster) * 0x10)
7708185578Sjmcneill #define	 CPUXCFG_CL_CTRL1(cluster)	(0x4 + (cluster) * 0x10)
7808185578Sjmcneill #define	  CPUXCFG_CL_CTRL1_ACINACTM	__BIT(0)
7908185578Sjmcneill 
8043331e8dSjmcneill #define	A80_CCI_BASE		0x01c90000
8143331e8dSjmcneill #define	A83T_CCI_BASE		0x01790000
8243331e8dSjmcneill 
8343331e8dSjmcneill #define	CCI_SLAVEIF3_OFFSET	0x4000
8443331e8dSjmcneill #define	CCI_SLAVEIF4_OFFSET	0x5000
8508185578Sjmcneill 
8608185578Sjmcneill extern struct bus_space arm_generic_bs_tag;
8708185578Sjmcneill 
8843331e8dSjmcneill enum sunxi_mc_soc {
8943331e8dSjmcneill 	MC_SOC_A80,
9043331e8dSjmcneill 	MC_SOC_A83T
9108185578Sjmcneill };
9208185578Sjmcneill 
9343331e8dSjmcneill enum sunxi_mc_cpu {
9443331e8dSjmcneill 	MC_CORE_CA7,
9543331e8dSjmcneill 	MC_CORE_CA15
9643331e8dSjmcneill };
9743331e8dSjmcneill 
9843331e8dSjmcneill uint32_t sunxi_mc_cci_port[MAXCPUS];
9943331e8dSjmcneill 
10008185578Sjmcneill static uint32_t
sunxi_mc_smp_pa(void)10108185578Sjmcneill sunxi_mc_smp_pa(void)
10208185578Sjmcneill {
10308185578Sjmcneill 	extern void sunxi_mc_mpstart(void);
10408185578Sjmcneill 	bool ok __diagused;
10508185578Sjmcneill 	paddr_t pa;
10608185578Sjmcneill 
10708185578Sjmcneill 	ok = pmap_extract(pmap_kernel(), (vaddr_t)sunxi_mc_mpstart, &pa);
10808185578Sjmcneill 	KASSERT(ok);
10908185578Sjmcneill 
11008185578Sjmcneill 	return pa;
11108185578Sjmcneill }
11208185578Sjmcneill 
11308185578Sjmcneill static int
sunxi_mc_smp_start(bus_space_tag_t bst,bus_space_handle_t prcm,bus_space_handle_t cpucfg,bus_space_handle_t cpuxcfg,u_int cluster,u_int cpu,enum sunxi_mc_soc soc,enum sunxi_mc_cpu core)11408185578Sjmcneill sunxi_mc_smp_start(bus_space_tag_t bst, bus_space_handle_t prcm, bus_space_handle_t cpucfg,
11543331e8dSjmcneill     bus_space_handle_t cpuxcfg, u_int cluster, u_int cpu, enum sunxi_mc_soc soc,
11643331e8dSjmcneill     enum sunxi_mc_cpu core)
11708185578Sjmcneill {
11808185578Sjmcneill 	uint32_t val;
11908185578Sjmcneill 	int i;
12008185578Sjmcneill 
12108185578Sjmcneill 	/* Assert core reset */
12208185578Sjmcneill 	val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster));
12308185578Sjmcneill 	val &= ~__BIT(cpu);
12408185578Sjmcneill 	bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster), val);
12508185578Sjmcneill 
12643331e8dSjmcneill 	if (soc == MC_SOC_A83T) {
12708185578Sjmcneill 		/* Assert power-on reset */
12808185578Sjmcneill 		val = bus_space_read_4(bst, cpucfg, CPUCFG_CL_RST(cluster));
12908185578Sjmcneill 		val &= ~__BIT(cpu);
13008185578Sjmcneill 		bus_space_write_4(bst, cpucfg, CPUCFG_CL_RST(cluster), val);
13143331e8dSjmcneill 	}
13208185578Sjmcneill 
13343331e8dSjmcneill 	if (core == MC_CORE_CA7) {
13408185578Sjmcneill 		/* Disable automatic L1 cache invalidate at reset */
13508185578Sjmcneill 		val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_CTRL0(cluster));
13608185578Sjmcneill 		val &= ~__BIT(cpu);
13708185578Sjmcneill 		bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_CTRL0(cluster), val);
13843331e8dSjmcneill 	}
13908185578Sjmcneill 
14008185578Sjmcneill 	/* Release power clamp */
14108185578Sjmcneill 	for (i = 0; i <= 8; i++) {
14208185578Sjmcneill 		bus_space_write_4(bst, prcm, PRCM_CL_PWR_CLAMP(cluster, cpu), 0xff >> i);
14308185578Sjmcneill 		delay(10);
14408185578Sjmcneill 	}
14508185578Sjmcneill 	for (i = 100000; i > 0; i--) {
14608185578Sjmcneill 		if (bus_space_read_4(bst, prcm, PRCM_CL_PWR_CLAMP(cluster, cpu)) == 0)
14708185578Sjmcneill 			break;
14808185578Sjmcneill 	}
14908185578Sjmcneill 	if (i == 0) {
15008185578Sjmcneill 		printf("CPU %#llx failed to start\n", __SHIFTIN(cluster, MPIDR_AFF1) | __SHIFTIN(cpu, MPIDR_AFF0));
15108185578Sjmcneill 		return ETIMEDOUT;
15208185578Sjmcneill 	}
15308185578Sjmcneill 
15408185578Sjmcneill 	/* Clear power-off gating */
15508185578Sjmcneill 	val = bus_space_read_4(bst, prcm, PRCM_CL_PWROFF(cluster));
15643331e8dSjmcneill 	if (soc == MC_SOC_A83T) {
15708185578Sjmcneill 		if (cpu == 0)
15808185578Sjmcneill 			val &= ~__BIT(4);
159*9cae9137Sjmcneill 		else
160*9cae9137Sjmcneill 			val &= ~__BIT(cpu);
16143331e8dSjmcneill 		val &= ~__BIT(0);	/* cluster power gate */
16243331e8dSjmcneill 	} else {
16308185578Sjmcneill 		val &= ~__BIT(cpu);
16443331e8dSjmcneill 		val &= ~__BIT(4);	/* cluster power gate */
16543331e8dSjmcneill 	}
16608185578Sjmcneill 	bus_space_write_4(bst, prcm, PRCM_CL_PWROFF(cluster), val);
16708185578Sjmcneill 
16808185578Sjmcneill 	/* De-assert power-on reset */
16908185578Sjmcneill 	val = bus_space_read_4(bst, prcm, PRCM_CL_RST_CTRL(cluster));
17008185578Sjmcneill 	val |= __BIT(cpu);
17108185578Sjmcneill 	bus_space_write_4(bst, prcm, PRCM_CL_RST_CTRL(cluster), val);
17208185578Sjmcneill 
17343331e8dSjmcneill 	if (soc == MC_SOC_A83T) {
17408185578Sjmcneill 		val = bus_space_read_4(bst, cpucfg, CPUCFG_CL_RST(cluster));
17508185578Sjmcneill 		val |= __BIT(cpu);
17608185578Sjmcneill 		bus_space_write_4(bst, cpucfg, CPUCFG_CL_RST(cluster), val);
17708185578Sjmcneill 		delay(10);
17843331e8dSjmcneill 	}
17908185578Sjmcneill 
18008185578Sjmcneill 	/* De-assert core reset */
18108185578Sjmcneill 	val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster));
18208185578Sjmcneill 	val |= __BIT(cpu);
18308185578Sjmcneill 	val |= CPUXCFG_CL_RST_SOC_DBG_RST;
18443331e8dSjmcneill 	if (core == MC_CORE_CA7)
18508185578Sjmcneill 		val |= CPUXCFG_CL_RST_ETM_RST(cpu);
18643331e8dSjmcneill 	else
18743331e8dSjmcneill 		val |= CPUXCFG_CL_RST_CX_RST(cpu);
18808185578Sjmcneill 	val |= CPUXCFG_CL_RST_DBG_RST(cpu);
18908185578Sjmcneill 	val |= CPUXCFG_CL_RST_L2_RST;
19008185578Sjmcneill 	val |= CPUXCFG_CL_RST_H_RST;
19108185578Sjmcneill 	bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster), val);
19208185578Sjmcneill 
19308185578Sjmcneill 	/* De-assert ACINACTM */
19408185578Sjmcneill 	val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_CTRL1(cluster));
19508185578Sjmcneill 	val &= ~CPUXCFG_CL_CTRL1_ACINACTM;
19608185578Sjmcneill 	bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_CTRL1(cluster), val);
19708185578Sjmcneill 
19808185578Sjmcneill 	return 0;
19908185578Sjmcneill }
20008185578Sjmcneill 
20108185578Sjmcneill int
sun8i_a83t_smp_enable(u_int mpidr)20243331e8dSjmcneill sun8i_a83t_smp_enable(u_int mpidr)
20308185578Sjmcneill {
20408185578Sjmcneill 	bus_space_tag_t bst = &arm_generic_bs_tag;
20508185578Sjmcneill 	bus_space_handle_t prcm, cpucfg, cpuxcfg;
20608185578Sjmcneill 	int error;
20708185578Sjmcneill 
20808185578Sjmcneill 	const u_int cluster = __SHIFTOUT(mpidr, MPIDR_AFF1);
20908185578Sjmcneill 	const u_int cpu = __SHIFTOUT(mpidr, MPIDR_AFF0);
21008185578Sjmcneill 
21143331e8dSjmcneill 	if (bus_space_map(bst, A83T_PRCM_BASE, A83T_PRCM_SIZE, 0, &prcm) != 0 ||
21208185578Sjmcneill 	    bus_space_map(bst, CPUCFG_BASE, CPUCFG_SIZE, 0, &cpucfg) != 0 ||
21308185578Sjmcneill 	    bus_space_map(bst, CPUXCFG_BASE, CPUXCFG_SIZE, 0, &cpuxcfg) != 0)
21408185578Sjmcneill 		return ENOMEM;
21508185578Sjmcneill 
21643331e8dSjmcneill 	for (int i = 0; i < 4; i++)
21743331e8dSjmcneill 		sunxi_mc_cci_port[i] = A83T_CCI_BASE + CCI_SLAVEIF3_OFFSET;
21843331e8dSjmcneill 	for (int i = 4; i < 8; i++)
21943331e8dSjmcneill 		sunxi_mc_cci_port[i] = A83T_CCI_BASE + CCI_SLAVEIF4_OFFSET;
22043331e8dSjmcneill 
22143331e8dSjmcneill 	/* Set start vector */
22243331e8dSjmcneill 	bus_space_write_4(bst, cpucfg, CPUCFG_P_REG0, sunxi_mc_smp_pa());
22343331e8dSjmcneill 	cpu_idcache_wbinv_all();
22443331e8dSjmcneill 
22543331e8dSjmcneill 	error = sunxi_mc_smp_start(bst, prcm, cpucfg, cpuxcfg, cluster, cpu,
22643331e8dSjmcneill 	    MC_SOC_A83T, MC_CORE_CA7);
22708185578Sjmcneill 
22808185578Sjmcneill 	bus_space_unmap(bst, cpuxcfg, CPUXCFG_SIZE);
22908185578Sjmcneill 	bus_space_unmap(bst, cpucfg, CPUCFG_SIZE);
23043331e8dSjmcneill 	bus_space_unmap(bst, prcm, A83T_PRCM_SIZE);
23143331e8dSjmcneill 
23243331e8dSjmcneill 	return error;
23343331e8dSjmcneill }
23443331e8dSjmcneill 
23543331e8dSjmcneill int
sun9i_a80_smp_enable(u_int mpidr)23643331e8dSjmcneill sun9i_a80_smp_enable(u_int mpidr)
23743331e8dSjmcneill {
23843331e8dSjmcneill 	bus_space_tag_t bst = &arm_generic_bs_tag;
23943331e8dSjmcneill 	bus_space_handle_t prcm, cpuxcfg;
24043331e8dSjmcneill 	int error;
24143331e8dSjmcneill 
24243331e8dSjmcneill 	const u_int cluster = __SHIFTOUT(mpidr, MPIDR_AFF1);
24343331e8dSjmcneill 	const u_int cpu = __SHIFTOUT(mpidr, MPIDR_AFF0);
24443331e8dSjmcneill 
24543331e8dSjmcneill 	if (bus_space_map(bst, A80_PRCM_BASE, A80_PRCM_SIZE, 0, &prcm) != 0 ||
24643331e8dSjmcneill 	    bus_space_map(bst, CPUXCFG_BASE, CPUXCFG_SIZE, 0, &cpuxcfg) != 0)
24743331e8dSjmcneill 		return ENOMEM;
24843331e8dSjmcneill 
24943331e8dSjmcneill 	for (int i = 0; i < 4; i++)
25043331e8dSjmcneill 		sunxi_mc_cci_port[i] = A80_CCI_BASE + CCI_SLAVEIF3_OFFSET;
25143331e8dSjmcneill 	for (int i = 4; i < 8; i++)
25243331e8dSjmcneill 		sunxi_mc_cci_port[i] = A80_CCI_BASE + CCI_SLAVEIF4_OFFSET;
25343331e8dSjmcneill 
25443331e8dSjmcneill 	/* Set start vector */
25543331e8dSjmcneill 	bus_space_write_4(bst, prcm, PRCM_CPU_SOFT_ENTRY, sunxi_mc_smp_pa());
25643331e8dSjmcneill 	cpu_idcache_wbinv_all();
25743331e8dSjmcneill 
25843331e8dSjmcneill 	error = sunxi_mc_smp_start(bst, prcm, 0, cpuxcfg, cluster, cpu,
25943331e8dSjmcneill 	    MC_SOC_A80, cluster == 0 ? MC_CORE_CA7 : MC_CORE_CA15);
26043331e8dSjmcneill 
26143331e8dSjmcneill 	bus_space_unmap(bst, cpuxcfg, CPUXCFG_SIZE);
26243331e8dSjmcneill 	bus_space_unmap(bst, prcm, A80_PRCM_SIZE);
26308185578Sjmcneill 
26408185578Sjmcneill 	return error;
26508185578Sjmcneill }
266