Home | History | Annotate | Line # | Download | only in sunxi
      1 /* $NetBSD: sunxi_mc_smp.c,v 1.4 2019/03/03 17:00:22 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2019 Jared McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 
     31 __KERNEL_RCSID(0, "$NetBSD: sunxi_mc_smp.c,v 1.4 2019/03/03 17:00:22 jmcneill Exp $");
     32 
     33 #include <sys/param.h>
     34 #include <sys/bus.h>
     35 #include <sys/device.h>
     36 #include <sys/systm.h>
     37 
     38 #include <uvm/uvm_extern.h>
     39 
     40 #include <dev/fdt/fdtvar.h>
     41 
     42 #include <arm/armreg.h>
     43 #include <arm/cpu.h>
     44 #include <arm/cpufunc.h>
     45 #include <arm/locore.h>
     46 
     47 #include <arm/sunxi/sunxi_mc_smp.h>
     48 
     49 #define	A80_PRCM_BASE		0x08001400
     50 #define	A80_PRCM_SIZE		0x200
     51 
     52 #define	A83T_PRCM_BASE		0x01f01400
     53 #define	A83T_PRCM_SIZE		0x800
     54 
     55 #define	 PRCM_CL_RST_CTRL(cluster)	(0x4 + (cluster) * 0x4)
     56 #define	 PRCM_CL_PWROFF(cluster)	(0x100 + (cluster) * 0x4)
     57 #define	 PRCM_CL_PWR_CLAMP(cluster, cpu) (0x140 + (cluster) * 0x10 + (cpu) * 0x4)
     58 #define	 PRCM_CPU_SOFT_ENTRY		0x164
     59 
     60 #define	CPUCFG_BASE	0x01f01c00
     61 #define	CPUCFG_SIZE	0x400
     62 
     63 #define	 CPUCFG_CL_RST(cluster)		(0x30 + (cluster) * 0x4)
     64 #define	 CPUCFG_P_REG0			0x1a4
     65 
     66 #define	CPUXCFG_BASE	0x01700000
     67 #define	CPUXCFG_SIZE	0x400
     68 
     69 #define	 CPUXCFG_CL_RST(cluster)	(0x80 + (cluster) * 0x4)
     70 #define	  CPUXCFG_CL_RST_SOC_DBG_RST	__BIT(24)
     71 #define	  CPUXCFG_CL_RST_ETM_RST(cpu)	__BIT(20 + (cpu))
     72 #define	  CPUXCFG_CL_RST_DBG_RST(cpu)	__BIT(16 + (cpu))
     73 #define	  CPUXCFG_CL_RST_H_RST		__BIT(12)
     74 #define	  CPUXCFG_CL_RST_L2_RST		__BIT(8)
     75 #define	  CPUXCFG_CL_RST_CX_RST(cpu)	__BIT(4 + (cpu))
     76 #define	 CPUXCFG_CL_CTRL0(cluster)	(0x0 + (cluster) * 0x10)
     77 #define	 CPUXCFG_CL_CTRL1(cluster)	(0x4 + (cluster) * 0x10)
     78 #define	  CPUXCFG_CL_CTRL1_ACINACTM	__BIT(0)
     79 
     80 #define	A80_CCI_BASE		0x01c90000
     81 #define	A83T_CCI_BASE		0x01790000
     82 
     83 #define	CCI_SLAVEIF3_OFFSET	0x4000
     84 #define	CCI_SLAVEIF4_OFFSET	0x5000
     85 
     86 extern struct bus_space arm_generic_bs_tag;
     87 
     88 enum sunxi_mc_soc {
     89 	MC_SOC_A80,
     90 	MC_SOC_A83T
     91 };
     92 
     93 enum sunxi_mc_cpu {
     94 	MC_CORE_CA7,
     95 	MC_CORE_CA15
     96 };
     97 
     98 uint32_t sunxi_mc_cci_port[MAXCPUS];
     99 
    100 static uint32_t
    101 sunxi_mc_smp_pa(void)
    102 {
    103 	extern void sunxi_mc_mpstart(void);
    104 	bool ok __diagused;
    105 	paddr_t pa;
    106 
    107 	ok = pmap_extract(pmap_kernel(), (vaddr_t)sunxi_mc_mpstart, &pa);
    108 	KASSERT(ok);
    109 
    110 	return pa;
    111 }
    112 
    113 static int
    114 sunxi_mc_smp_start(bus_space_tag_t bst, bus_space_handle_t prcm, bus_space_handle_t cpucfg,
    115     bus_space_handle_t cpuxcfg, u_int cluster, u_int cpu, enum sunxi_mc_soc soc,
    116     enum sunxi_mc_cpu core)
    117 {
    118 	uint32_t val;
    119 	int i;
    120 
    121 	/* Assert core reset */
    122 	val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster));
    123 	val &= ~__BIT(cpu);
    124 	bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster), val);
    125 
    126 	if (soc == MC_SOC_A83T) {
    127 		/* Assert power-on reset */
    128 		val = bus_space_read_4(bst, cpucfg, CPUCFG_CL_RST(cluster));
    129 		val &= ~__BIT(cpu);
    130 		bus_space_write_4(bst, cpucfg, CPUCFG_CL_RST(cluster), val);
    131 	}
    132 
    133 	if (core == MC_CORE_CA7) {
    134 		/* Disable automatic L1 cache invalidate at reset */
    135 		val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_CTRL0(cluster));
    136 		val &= ~__BIT(cpu);
    137 		bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_CTRL0(cluster), val);
    138 	}
    139 
    140 	/* Release power clamp */
    141 	for (i = 0; i <= 8; i++) {
    142 		bus_space_write_4(bst, prcm, PRCM_CL_PWR_CLAMP(cluster, cpu), 0xff >> i);
    143 		delay(10);
    144 	}
    145 	for (i = 100000; i > 0; i--) {
    146 		if (bus_space_read_4(bst, prcm, PRCM_CL_PWR_CLAMP(cluster, cpu)) == 0)
    147 			break;
    148 	}
    149 	if (i == 0) {
    150 		printf("CPU %#llx failed to start\n", __SHIFTIN(cluster, MPIDR_AFF1) | __SHIFTIN(cpu, MPIDR_AFF0));
    151 		return ETIMEDOUT;
    152 	}
    153 
    154 	/* Clear power-off gating */
    155 	val = bus_space_read_4(bst, prcm, PRCM_CL_PWROFF(cluster));
    156 	if (soc == MC_SOC_A83T) {
    157 		if (cpu == 0)
    158 			val &= ~__BIT(4);
    159 		else
    160 			val &= ~__BIT(cpu);
    161 		val &= ~__BIT(0);	/* cluster power gate */
    162 	} else {
    163 		val &= ~__BIT(cpu);
    164 		val &= ~__BIT(4);	/* cluster power gate */
    165 	}
    166 	bus_space_write_4(bst, prcm, PRCM_CL_PWROFF(cluster), val);
    167 
    168 	/* De-assert power-on reset */
    169 	val = bus_space_read_4(bst, prcm, PRCM_CL_RST_CTRL(cluster));
    170 	val |= __BIT(cpu);
    171 	bus_space_write_4(bst, prcm, PRCM_CL_RST_CTRL(cluster), val);
    172 
    173 	if (soc == MC_SOC_A83T) {
    174 		val = bus_space_read_4(bst, cpucfg, CPUCFG_CL_RST(cluster));
    175 		val |= __BIT(cpu);
    176 		bus_space_write_4(bst, cpucfg, CPUCFG_CL_RST(cluster), val);
    177 		delay(10);
    178 	}
    179 
    180 	/* De-assert core reset */
    181 	val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster));
    182 	val |= __BIT(cpu);
    183 	val |= CPUXCFG_CL_RST_SOC_DBG_RST;
    184 	if (core == MC_CORE_CA7)
    185 		val |= CPUXCFG_CL_RST_ETM_RST(cpu);
    186 	else
    187 		val |= CPUXCFG_CL_RST_CX_RST(cpu);
    188 	val |= CPUXCFG_CL_RST_DBG_RST(cpu);
    189 	val |= CPUXCFG_CL_RST_L2_RST;
    190 	val |= CPUXCFG_CL_RST_H_RST;
    191 	bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster), val);
    192 
    193 	/* De-assert ACINACTM */
    194 	val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_CTRL1(cluster));
    195 	val &= ~CPUXCFG_CL_CTRL1_ACINACTM;
    196 	bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_CTRL1(cluster), val);
    197 
    198 	return 0;
    199 }
    200 
    201 int
    202 sun8i_a83t_smp_enable(u_int mpidr)
    203 {
    204 	bus_space_tag_t bst = &arm_generic_bs_tag;
    205 	bus_space_handle_t prcm, cpucfg, cpuxcfg;
    206 	int error;
    207 
    208 	const u_int cluster = __SHIFTOUT(mpidr, MPIDR_AFF1);
    209 	const u_int cpu = __SHIFTOUT(mpidr, MPIDR_AFF0);
    210 
    211 	if (bus_space_map(bst, A83T_PRCM_BASE, A83T_PRCM_SIZE, 0, &prcm) != 0 ||
    212 	    bus_space_map(bst, CPUCFG_BASE, CPUCFG_SIZE, 0, &cpucfg) != 0 ||
    213 	    bus_space_map(bst, CPUXCFG_BASE, CPUXCFG_SIZE, 0, &cpuxcfg) != 0)
    214 		return ENOMEM;
    215 
    216 	for (int i = 0; i < 4; i++)
    217 		sunxi_mc_cci_port[i] = A83T_CCI_BASE + CCI_SLAVEIF3_OFFSET;
    218 	for (int i = 4; i < 8; i++)
    219 		sunxi_mc_cci_port[i] = A83T_CCI_BASE + CCI_SLAVEIF4_OFFSET;
    220 
    221 	/* Set start vector */
    222 	bus_space_write_4(bst, cpucfg, CPUCFG_P_REG0, sunxi_mc_smp_pa());
    223 	cpu_idcache_wbinv_all();
    224 
    225 	error = sunxi_mc_smp_start(bst, prcm, cpucfg, cpuxcfg, cluster, cpu,
    226 	    MC_SOC_A83T, MC_CORE_CA7);
    227 
    228 	bus_space_unmap(bst, cpuxcfg, CPUXCFG_SIZE);
    229 	bus_space_unmap(bst, cpucfg, CPUCFG_SIZE);
    230 	bus_space_unmap(bst, prcm, A83T_PRCM_SIZE);
    231 
    232 	return error;
    233 }
    234 
    235 int
    236 sun9i_a80_smp_enable(u_int mpidr)
    237 {
    238 	bus_space_tag_t bst = &arm_generic_bs_tag;
    239 	bus_space_handle_t prcm, cpuxcfg;
    240 	int error;
    241 
    242 	const u_int cluster = __SHIFTOUT(mpidr, MPIDR_AFF1);
    243 	const u_int cpu = __SHIFTOUT(mpidr, MPIDR_AFF0);
    244 
    245 	if (bus_space_map(bst, A80_PRCM_BASE, A80_PRCM_SIZE, 0, &prcm) != 0 ||
    246 	    bus_space_map(bst, CPUXCFG_BASE, CPUXCFG_SIZE, 0, &cpuxcfg) != 0)
    247 		return ENOMEM;
    248 
    249 	for (int i = 0; i < 4; i++)
    250 		sunxi_mc_cci_port[i] = A80_CCI_BASE + CCI_SLAVEIF3_OFFSET;
    251 	for (int i = 4; i < 8; i++)
    252 		sunxi_mc_cci_port[i] = A80_CCI_BASE + CCI_SLAVEIF4_OFFSET;
    253 
    254 	/* Set start vector */
    255 	bus_space_write_4(bst, prcm, PRCM_CPU_SOFT_ENTRY, sunxi_mc_smp_pa());
    256 	cpu_idcache_wbinv_all();
    257 
    258 	error = sunxi_mc_smp_start(bst, prcm, 0, cpuxcfg, cluster, cpu,
    259 	    MC_SOC_A80, cluster == 0 ? MC_CORE_CA7 : MC_CORE_CA15);
    260 
    261 	bus_space_unmap(bst, cpuxcfg, CPUXCFG_SIZE);
    262 	bus_space_unmap(bst, prcm, A80_PRCM_SIZE);
    263 
    264 	return error;
    265 }
    266