1/*- 2 * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: releng/10.2/sys/arm/rockchip/rk30xx_mp.c 266397 2014-05-18 13:05:07Z ian $"); 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/bus.h> 31#include <sys/kernel.h> 32#include <sys/lock.h> 33#include <sys/mutex.h> 34#include <sys/smp.h> 35 36#include <machine/smp.h> 37#include <machine/fdt.h> 38#include <machine/intr.h> 39 40#define SCU_PHYSBASE 0x1013c000 41#define SCU_SIZE 0x100 42 43#define SCU_CONTROL_REG 0x00 44#define SCU_CONTROL_ENABLE (1 << 0) 45#define SCU_STANDBY_EN (1 << 5) 46#define SCU_CONFIG_REG 0x04 47#define SCU_CONFIG_REG_NCPU_MASK 0x03 48#define SCU_CPUPOWER_REG 0x08 49#define SCU_INV_TAGS_REG 0x0c 50 51#define SCU_FILTER_START_REG 0x10 52#define SCU_FILTER_END_REG 0x14 53#define SCU_SECURE_ACCESS_REG 0x18 54#define SCU_NONSECURE_ACCESS_REG 0x1c 55 56#define IMEM_PHYSBASE 0x10080000 57#define IMEM_SIZE 0x20 58 59#define PMU_PHYSBASE 0x20004000 60#define PMU_SIZE 0x100 61#define PMU_PWRDN_CON 0x08 62#define PMU_PWRDN_SCU (1 << 4) 63 64extern char *mpentry_addr; 65static void rk30xx_boot2(void); 66 67static void 68rk30xx_boot2(void) 69{ 70 71 __asm __volatile( 72 "ldr pc, 1f\n" 73 ".globl mpentry_addr\n" 74 "mpentry_addr:\n" 75 "1: .space 4\n"); 76} 77 78void 79platform_mp_init_secondary(void) 80{ 81 82 gic_init_secondary(); 83} 84 85void 86platform_mp_setmaxid(void) 87{ 88 bus_space_handle_t scu; 89 int ncpu; 90 uint32_t val; 91 92 if (mp_ncpus != 0) 93 return; 94 95 if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) 96 panic("Could not map the SCU"); 97 98 val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG); 99 ncpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1; 100 bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); 101 102 mp_ncpus = ncpu; 103 mp_maxid = ncpu - 1; 104} 105 106int 107platform_mp_probe(void) 108{ 109 110 if (mp_ncpus == 0) 111 platform_mp_setmaxid(); 112 113 return (mp_ncpus > 1); 114} 115 116void 117platform_mp_start_ap(void) 118{ 119 bus_space_handle_t scu; 120 bus_space_handle_t imem; 121 bus_space_handle_t pmu; 122 uint32_t val; 123 int i; 124 125 if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) 126 panic("Could not map the SCU"); 127 if (bus_space_map(fdtbus_bs_tag, IMEM_PHYSBASE, 128 IMEM_SIZE, 0, &imem) != 0) 129 panic("Could not map the IMEM"); 130 if (bus_space_map(fdtbus_bs_tag, PMU_PHYSBASE, PMU_SIZE, 0, &pmu) != 0) 131 panic("Could not map the PMU"); 132 133 /* 134 * Invalidate SCU cache tags. The 0x0000ffff constant invalidates all 135 * ways on all cores 0-3. Per the ARM docs, it's harmless to write to 136 * the bits for cores that are not present. 137 */ 138 bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff); 139 140 /* Make sure all cores except the first are off */ 141 val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON); 142 for (i = 1; i < mp_ncpus; i++) 143 val |= 1 << i; 144 bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val); 145 146 /* Enable SCU power domain */ 147 val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON); 148 val &= ~PMU_PWRDN_SCU; 149 bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val); 150 151 /* Enable SCU */ 152 val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG); 153 bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, 154 val | SCU_CONTROL_ENABLE); 155 156 /* 157 * Cores will execute the code which resides at the start of 158 * the on-chip bootram/sram after power-on. This sram region 159 * should be reserved and the trampoline code that directs 160 * the core to the real startup code in ram should be copied 161 * into this sram region. 162 * 163 * First set boot function for the sram code. 164 */ 165 mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry); 166 167 /* Copy trampoline to sram, that runs during startup of the core */ 168 bus_space_write_region_4(fdtbus_bs_tag, imem, 0, 169 (uint32_t *)&rk30xx_boot2, 8); 170 171 cpu_idcache_wbinv_all(); 172 cpu_l2cache_wbinv_all(); 173 174 /* Start all cores */ 175 val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON); 176 for (i = 1; i < mp_ncpus; i++) 177 val &= ~(1 << i); 178 bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val); 179 180 armv7_sev(); 181 182 bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); 183 bus_space_unmap(fdtbus_bs_tag, imem, IMEM_SIZE); 184 bus_space_unmap(fdtbus_bs_tag, pmu, PMU_SIZE); 185} 186 187void 188platform_ipi_send(cpuset_t cpus, u_int ipi) 189{ 190 191 pic_ipi_send(cpus, ipi); 192} 193