1167598Srrs/*- 2169382Srrs * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold@freebsd.org> 3167598Srrs * All rights reserved. 4167598Srrs * 5167598Srrs * Redistribution and use in source and binary forms, with or without 6167598Srrs * modification, are permitted provided that the following conditions 7167598Srrs * are met: 8167598Srrs * 1. Redistributions of source code must retain the above copyright 9167598Srrs * notice, this list of conditions and the following disclaimer. 10167598Srrs * 2. Redistributions in binary form must reproduce the above copyright 11167598Srrs * notice, this list of conditions and the following disclaimer in the 12167598Srrs * documentation and/or other materials provided with the distribution. 13167598Srrs * 14167598Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15167598Srrs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16167598Srrs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17167598Srrs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18167598Srrs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19167598Srrs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20167598Srrs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21167598Srrs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22167598Srrs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23167598Srrs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24167598Srrs */ 25167598Srrs 26167598Srrs#include <sys/cdefs.h> 27167598Srrs__FBSDID("$FreeBSD$"); 28167598Srrs#include <sys/param.h> 29167598Srrs#include <sys/systm.h> 30167598Srrs#include <sys/bus.h> 31167598Srrs#include <sys/kernel.h> 32167598Srrs#include <sys/lock.h> 33167598Srrs#include <sys/mutex.h> 34167598Srrs#include <sys/smp.h> 35167598Srrs 36167598Srrs#include <machine/smp.h> 37167598Srrs#include <machine/fdt.h> 38167598Srrs#include <machine/intr.h> 39167598Srrs 40167598Srrs#define SCU_PHYSBASE 0x1013c000 41167598Srrs#define SCU_SIZE 0x100 42167598Srrs 43167598Srrs#define SCU_CONTROL_REG 0x00 44167598Srrs#define SCU_CONTROL_ENABLE (1 << 0) 45167598Srrs#define SCU_STANDBY_EN (1 << 5) 46167598Srrs#define SCU_CONFIG_REG 0x04 47167598Srrs#define SCU_CONFIG_REG_NCPU_MASK 0x03 48167598Srrs#define SCU_CPUPOWER_REG 0x08 49167598Srrs#define SCU_INV_TAGS_REG 0x0c 50167598Srrs 51167598Srrs#define SCU_FILTER_START_REG 0x10 52167598Srrs#define SCU_FILTER_END_REG 0x14 53167598Srrs#define SCU_SECURE_ACCESS_REG 0x18 54167598Srrs#define SCU_NONSECURE_ACCESS_REG 0x1c 55167598Srrs 56167598Srrs#define IMEM_PHYSBASE 0x10080000 57167598Srrs#define IMEM_SIZE 0x20 58167598Srrs 59167598Srrs#define PMU_PHYSBASE 0x20004000 60167598Srrs#define PMU_SIZE 0x100 61167598Srrs#define PMU_PWRDN_CON 0x08 62167598Srrs#define PMU_PWRDN_SCU (1 << 4) 63167598Srrs 64167598Srrsextern char *mpentry_addr; 65167598Srrsstatic void rk30xx_boot2(void); 66167598Srrs 67167598Srrsstatic void 68167598Srrsrk30xx_boot2(void) 69167598Srrs{ 70167598Srrs 71167598Srrs __asm __volatile( 72167598Srrs "ldr pc, 1f\n" 73167598Srrs ".globl mpentry_addr\n" 74167598Srrs "mpentry_addr:\n" 75167598Srrs "1: .space 4\n"); 76167598Srrs} 77167598Srrs 78167598Srrsvoid 79167598Srrsplatform_mp_init_secondary(void) 80167598Srrs{ 81167598Srrs 82167598Srrs gic_init_secondary(); 83167598Srrs} 84167598Srrs 85167598Srrsvoid 86167598Srrsplatform_mp_setmaxid(void) 87167598Srrs{ 88167598Srrs bus_space_handle_t scu; 89167598Srrs int ncpu; 90167598Srrs uint32_t val; 91167598Srrs 92167598Srrs if (mp_ncpus != 0) 93167598Srrs return; 94167598Srrs 95167598Srrs if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) 96167598Srrs panic("Could not map the SCU"); 97167598Srrs 98167598Srrs val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG); 99167598Srrs ncpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1; 100167598Srrs bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); 101167598Srrs 102167598Srrs mp_ncpus = ncpu; 103167598Srrs mp_maxid = ncpu - 1; 104170642Srrs} 105167598Srrs 106167598Srrsint 107167598Srrsplatform_mp_probe(void) 108167598Srrs{ 109167598Srrs 110167598Srrs if (mp_ncpus == 0) 111167598Srrs platform_mp_setmaxid(); 112167598Srrs 113167598Srrs return (mp_ncpus > 1); 114167598Srrs} 115167598Srrs 116167598Srrsvoid 117167598Srrsplatform_mp_start_ap(void) 118167598Srrs{ 119167598Srrs bus_space_handle_t scu; 120167598Srrs bus_space_handle_t imem; 121167598Srrs bus_space_handle_t pmu; 122167598Srrs uint32_t val; 123167598Srrs int i; 124167598Srrs 125167598Srrs if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) 126167598Srrs panic("Could not map the SCU"); 127167598Srrs if (bus_space_map(fdtbus_bs_tag, IMEM_PHYSBASE, 128167598Srrs IMEM_SIZE, 0, &imem) != 0) 129167598Srrs panic("Could not map the IMEM"); 130167598Srrs if (bus_space_map(fdtbus_bs_tag, PMU_PHYSBASE, PMU_SIZE, 0, &pmu) != 0) 131167598Srrs panic("Could not map the PMU"); 132167598Srrs 133167598Srrs /* 134167598Srrs * Invalidate SCU cache tags. The 0x0000ffff constant invalidates all 135167598Srrs * ways on all cores 0-3. Per the ARM docs, it's harmless to write to 136167598Srrs * the bits for cores that are not present. 137167598Srrs */ 138167598Srrs bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff); 139167598Srrs 140167598Srrs /* Make sure all cores except the first are off */ 141167598Srrs val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON); 142167598Srrs for (i = 1; i < mp_ncpus; i++) 143167598Srrs val |= 1 << i; 144167598Srrs bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val); 145167598Srrs 146167598Srrs /* Enable SCU power domain */ 147167598Srrs val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON); 148167598Srrs val &= ~PMU_PWRDN_SCU; 149167598Srrs bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val); 150167598Srrs 151167598Srrs /* Enable SCU */ 152167598Srrs val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG); 153167598Srrs bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, 154167598Srrs val | SCU_CONTROL_ENABLE); 155167598Srrs 156167598Srrs /* 157167598Srrs * Cores will execute the code which resides at the start of 158167598Srrs * the on-chip bootram/sram after power-on. This sram region 159167598Srrs * should be reserved and the trampoline code that directs 160167598Srrs * the core to the real startup code in ram should be copied 161167598Srrs * into this sram region. 162167598Srrs * 163167598Srrs * First set boot function for the sram code. 164167598Srrs */ 165167598Srrs mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry); 166167598Srrs 167167598Srrs /* Copy trampoline to sram, that runs during startup of the core */ 168167598Srrs bus_space_write_region_4(fdtbus_bs_tag, imem, 0, 169167598Srrs (uint32_t *)&rk30xx_boot2, 8); 170167598Srrs 171167598Srrs cpu_idcache_wbinv_all(); 172167598Srrs cpu_l2cache_wbinv_all(); 173167598Srrs 174167598Srrs /* Start all cores */ 175167598Srrs val = bus_space_read_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON); 176167598Srrs for (i = 1; i < mp_ncpus; i++) 177167598Srrs val &= ~(1 << i); 178167598Srrs bus_space_write_4(fdtbus_bs_tag, pmu, PMU_PWRDN_CON, val); 179167598Srrs 180167598Srrs armv7_sev(); 181167598Srrs 182167598Srrs bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); 183167598Srrs bus_space_unmap(fdtbus_bs_tag, imem, IMEM_SIZE); 184167598Srrs bus_space_unmap(fdtbus_bs_tag, pmu, PMU_SIZE); 185167598Srrs} 186167598Srrs 187167598Srrsvoid 188167598Srrsplatform_ipi_send(cpuset_t cpus, u_int ipi) 189167598Srrs{ 190167598Srrs 191167598Srrs pic_ipi_send(cpus, ipi); 192167598Srrs} 193167598Srrs