sunxi_mc_smp.c revision 1.2
1/* $NetBSD: sunxi_mc_smp.c,v 1.2 2019/01/03 12:52:40 jmcneill Exp $ */ 2 3/*- 4 * Copyright (c) 2019 Jared McNeill <jmcneill@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.2 2019/01/03 12:52:40 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 A83T_SMP_ENABLE_METHOD "allwinner,sun8i-a83t-smp" 50 51#define PRCM_BASE 0x01f01400 52#define PRCM_SIZE 0x800 53 54#define PRCM_CL_RST_CTRL(cluster) (0x4 + (cluster) * 0x4) 55#define PRCM_CL_PWROFF(cluster) (0x100 + (cluster) * 0x4) 56#define PRCM_CL_PWR_CLAMP(cluster, cpu) (0x140 + (cluster) * 0x10 + (cpu) * 0x4) 57 58#define CPUCFG_BASE 0x01f01c00 59#define CPUCFG_SIZE 0x400 60 61#define CPUCFG_CL_RST(cluster) (0x30 + (cluster) * 0x4) 62#define CPUCFG_P_REG0 0x1a4 63 64#define CPUXCFG_BASE 0x01700000 65#define CPUXCFG_SIZE 0x400 66 67#define CPUXCFG_CL_RST(cluster) (0x80 + (cluster) * 0x4) 68#define CPUXCFG_CL_RST_SOC_DBG_RST __BIT(24) 69#define CPUXCFG_CL_RST_ETM_RST(cpu) __BIT(20 + (cpu)) 70#define CPUXCFG_CL_RST_DBG_RST(cpu) __BIT(16 + (cpu)) 71#define CPUXCFG_CL_RST_H_RST __BIT(12) 72#define CPUXCFG_CL_RST_L2_RST __BIT(8) 73#define CPUXCFG_CL_CTRL0(cluster) (0x0 + (cluster) * 0x10) 74#define CPUXCFG_CL_CTRL1(cluster) (0x4 + (cluster) * 0x10) 75#define CPUXCFG_CL_CTRL1_ACINACTM __BIT(0) 76 77#define CCI_BASE 0x01790000 78#define CCI_SLAVEIF3_BASE (CCI_BASE + 0x4000) 79#define CCI_SLAVEIF4_BASE (CCI_BASE + 0x5000) 80 81extern struct bus_space arm_generic_bs_tag; 82 83uint32_t sunxi_mc_cci_port[MAXCPUS] = { 84 CCI_SLAVEIF3_BASE, 85 CCI_SLAVEIF3_BASE, 86 CCI_SLAVEIF3_BASE, 87 CCI_SLAVEIF3_BASE, 88 CCI_SLAVEIF4_BASE, 89 CCI_SLAVEIF4_BASE, 90 CCI_SLAVEIF4_BASE, 91 CCI_SLAVEIF4_BASE, 92}; 93 94static uint32_t 95sunxi_mc_smp_pa(void) 96{ 97 extern void sunxi_mc_mpstart(void); 98 bool ok __diagused; 99 paddr_t pa; 100 101 ok = pmap_extract(pmap_kernel(), (vaddr_t)sunxi_mc_mpstart, &pa); 102 KASSERT(ok); 103 104 return pa; 105} 106 107static int 108sunxi_mc_smp_start(bus_space_tag_t bst, bus_space_handle_t prcm, bus_space_handle_t cpucfg, 109 bus_space_handle_t cpuxcfg, u_int cluster, u_int cpu) 110{ 111 uint32_t val; 112 int i; 113 114 /* Set start vector */ 115 bus_space_write_4(bst, cpucfg, CPUCFG_P_REG0, sunxi_mc_smp_pa()); 116 117 /* Assert core reset */ 118 val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster)); 119 val &= ~__BIT(cpu); 120 bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster), val); 121 122 /* Assert power-on reset */ 123 val = bus_space_read_4(bst, cpucfg, CPUCFG_CL_RST(cluster)); 124 val &= ~__BIT(cpu); 125 bus_space_write_4(bst, cpucfg, CPUCFG_CL_RST(cluster), val); 126 127 /* Disable automatic L1 cache invalidate at reset */ 128 val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_CTRL0(cluster)); 129 val &= ~__BIT(cpu); 130 bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_CTRL0(cluster), val); 131 132 /* Release power clamp */ 133 for (i = 0; i <= 8; i++) { 134 bus_space_write_4(bst, prcm, PRCM_CL_PWR_CLAMP(cluster, cpu), 0xff >> i); 135 delay(10); 136 } 137 for (i = 100000; i > 0; i--) { 138 if (bus_space_read_4(bst, prcm, PRCM_CL_PWR_CLAMP(cluster, cpu)) == 0) 139 break; 140 } 141 if (i == 0) { 142 printf("CPU %#llx failed to start\n", __SHIFTIN(cluster, MPIDR_AFF1) | __SHIFTIN(cpu, MPIDR_AFF0)); 143 return ETIMEDOUT; 144 } 145 146 /* Clear power-off gating */ 147 val = bus_space_read_4(bst, prcm, PRCM_CL_PWROFF(cluster)); 148 if (cpu == 0) 149 val &= ~__BIT(4); 150 val &= ~__BIT(cpu); 151 bus_space_write_4(bst, prcm, PRCM_CL_PWROFF(cluster), val); 152 153 /* De-assert power-on reset */ 154 val = bus_space_read_4(bst, prcm, PRCM_CL_RST_CTRL(cluster)); 155 val |= __BIT(cpu); 156 bus_space_write_4(bst, prcm, PRCM_CL_RST_CTRL(cluster), val); 157 158 val = bus_space_read_4(bst, cpucfg, CPUCFG_CL_RST(cluster)); 159 val |= __BIT(cpu); 160 bus_space_write_4(bst, cpucfg, CPUCFG_CL_RST(cluster), val); 161 delay(10); 162 163 /* De-assert core reset */ 164 val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster)); 165 val |= __BIT(cpu); 166 val |= CPUXCFG_CL_RST_SOC_DBG_RST; 167 val |= CPUXCFG_CL_RST_ETM_RST(cpu); 168 val |= CPUXCFG_CL_RST_DBG_RST(cpu); 169 val |= CPUXCFG_CL_RST_L2_RST; 170 val |= CPUXCFG_CL_RST_H_RST; 171 bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_RST(cluster), val); 172 173 /* De-assert ACINACTM */ 174 val = bus_space_read_4(bst, cpuxcfg, CPUXCFG_CL_CTRL1(cluster)); 175 val &= ~CPUXCFG_CL_CTRL1_ACINACTM; 176 bus_space_write_4(bst, cpuxcfg, CPUXCFG_CL_CTRL1(cluster), val); 177 178 return 0; 179} 180 181int 182sunxi_mc_smp_enable(u_int mpidr) 183{ 184 bus_space_tag_t bst = &arm_generic_bs_tag; 185 bus_space_handle_t prcm, cpucfg, cpuxcfg; 186 int error; 187 188 const u_int cluster = __SHIFTOUT(mpidr, MPIDR_AFF1); 189 const u_int cpu = __SHIFTOUT(mpidr, MPIDR_AFF0); 190 191 if (bus_space_map(bst, PRCM_BASE, PRCM_SIZE, 0, &prcm) != 0 || 192 bus_space_map(bst, CPUCFG_BASE, CPUCFG_SIZE, 0, &cpucfg) != 0 || 193 bus_space_map(bst, CPUXCFG_BASE, CPUXCFG_SIZE, 0, &cpuxcfg) != 0) 194 return ENOMEM; 195 196 error = sunxi_mc_smp_start(bst, prcm, cpucfg, cpuxcfg, cluster, cpu); 197 198 bus_space_unmap(bst, cpuxcfg, CPUXCFG_SIZE); 199 bus_space_unmap(bst, cpucfg, CPUCFG_SIZE); 200 bus_space_unmap(bst, prcm, PRCM_SIZE); 201 202 return error; 203} 204