1262427Sian/*- 2262427Sian * Copyright (c) 2014 Juergen Weiss <weiss@uni-mainz.de> 3262427Sian * Copyright (c) 2014 Ian Lepore <ian@freebsd.org> 4262427Sian * All rights reserved. 5262427Sian * 6262427Sian * Redistribution and use in source and binary forms, with or without 7262427Sian * modification, are permitted provided that the following conditions 8262427Sian * are met: 9262427Sian * 1. Redistributions of source code must retain the above copyright 10262427Sian * notice, this list of conditions and the following disclaimer. 11262427Sian * 2. Redistributions in binary form must reproduce the above copyright 12262427Sian * notice, this list of conditions and the following disclaimer in the 13262427Sian * documentation and/or other materials provided with the distribution. 14262427Sian * 15262427Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16262427Sian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17262427Sian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18262427Sian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19262427Sian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20262427Sian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21262427Sian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22262427Sian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23262427Sian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24262427Sian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25262427Sian */ 26262427Sian 27262427Sian#include <sys/cdefs.h> 28262427Sian__FBSDID("$FreeBSD$"); 29262427Sian#include <sys/param.h> 30262427Sian#include <sys/systm.h> 31262427Sian#include <sys/bus.h> 32266274Sian#include <sys/kernel.h> 33262427Sian#include <sys/lock.h> 34262427Sian#include <sys/mutex.h> 35262427Sian#include <sys/smp.h> 36262427Sian 37262427Sian#include <machine/smp.h> 38262427Sian#include <machine/fdt.h> 39262427Sian#include <machine/intr.h> 40262427Sian 41262427Sian#define SCU_PHYSBASE 0x00a00000 42262427Sian#define SCU_SIZE 0x00001000 43262427Sian 44262427Sian#define SCU_CONTROL_REG 0x00 45262427Sian#define SCU_CONTROL_ENABLE (1 << 0) 46262427Sian#define SCU_CONFIG_REG 0x04 47262427Sian#define SCU_CONFIG_REG_NCPU_MASK 0x03 48262427Sian#define SCU_CPUPOWER_REG 0x08 49262427Sian#define SCU_INV_TAGS_REG 0x0c 50262427Sian#define SCU_DIAG_CONTROL 0x30 51262427Sian#define SCU_DIAG_DISABLE_MIGBIT (1 << 0) 52262427Sian#define SCU_FILTER_START_REG 0x40 53262427Sian#define SCU_FILTER_END_REG 0x44 54262427Sian#define SCU_SECURE_ACCESS_REG 0x50 55262427Sian#define SCU_NONSECURE_ACCESS_REG 0x54 56262427Sian 57262427Sian#define SRC_PHYSBASE 0x020d8000 58262427Sian#define SRC_SIZE 0x4000 59262427Sian#define SRC_CONTROL_REG 0x00 60262427Sian#define SRC_CONTROL_C1ENA_SHIFT 22 /* Bit for Core 1 enable */ 61262427Sian#define SRC_CONTROL_C1RST_SHIFT 14 /* Bit for Core 1 reset */ 62262427Sian#define SRC_GPR0_C1FUNC 0x20 /* Register for Core 1 entry func */ 63262427Sian#define SRC_GPR1_C1ARG 0x24 /* Register for Core 1 entry arg */ 64262427Sian 65262427Sianvoid 66262427Sianplatform_mp_init_secondary(void) 67262427Sian{ 68262427Sian 69262427Sian gic_init_secondary(); 70262427Sian} 71262427Sian 72262427Sianvoid 73262427Sianplatform_mp_setmaxid(void) 74262427Sian{ 75262427Sian bus_space_handle_t scu; 76266274Sian int hwcpu, ncpu; 77262427Sian uint32_t val; 78262427Sian 79262427Sian /* If we've already set the global vars don't bother to do it again. */ 80262427Sian if (mp_ncpus != 0) 81262427Sian return; 82262427Sian 83262427Sian if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) 84262427Sian panic("Couldn't map the SCU\n"); 85262427Sian val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG); 86266274Sian hwcpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1; 87262427Sian bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); 88262427Sian 89266274Sian ncpu = hwcpu; 90266274Sian TUNABLE_INT_FETCH("hw.ncpu", &ncpu); 91266274Sian if (ncpu < 1 || ncpu > hwcpu) 92266274Sian ncpu = hwcpu; 93266274Sian 94266274Sian mp_ncpus = ncpu; 95266274Sian mp_maxid = ncpu - 1; 96262427Sian} 97262427Sian 98262427Sianint 99262427Sianplatform_mp_probe(void) 100262427Sian{ 101262427Sian 102262427Sian /* I think platform_mp_setmaxid must get called first, but be safe. */ 103262427Sian if (mp_ncpus == 0) 104262427Sian platform_mp_setmaxid(); 105262427Sian 106262427Sian return (mp_ncpus > 1); 107262427Sian} 108262427Sian 109262427Sianvoid 110262427Sianplatform_mp_start_ap(void) 111262427Sian{ 112262427Sian bus_space_handle_t scu; 113262427Sian bus_space_handle_t src; 114262427Sian 115262427Sian uint32_t val; 116262427Sian int i; 117262427Sian 118262427Sian if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) 119262427Sian panic("Couldn't map the SCU\n"); 120262427Sian if (bus_space_map(fdtbus_bs_tag, SRC_PHYSBASE, SRC_SIZE, 0, &src) != 0) 121262427Sian panic("Couldn't map the system reset controller (SRC)\n"); 122262427Sian 123262427Sian /* 124266203Sian * Invalidate SCU cache tags. The 0x0000ffff constant invalidates all 125266203Sian * ways on all cores 0-3. Per the ARM docs, it's harmless to write to 126266203Sian * the bits for cores that are not present. 127262427Sian */ 128266203Sian bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff); 129262427Sian 130262427Sian /* 131262427Sian * Erratum ARM/MP: 764369 (problems with cache maintenance). 132262427Sian * Setting the "disable-migratory bit" in the undocumented SCU 133262427Sian * Diagnostic Control Register helps work around the problem. 134262427Sian */ 135262427Sian val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL); 136262427Sian bus_space_write_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL, 137262427Sian val | SCU_DIAG_DISABLE_MIGBIT); 138262427Sian 139266203Sian /* 140266203Sian * Enable the SCU, then clean the cache on this core. After these two 141266203Sian * operations the cache tag ram in the SCU is coherent with the contents 142266203Sian * of the cache on this core. The other cores aren't running yet so 143266203Sian * their caches can't contain valid data yet, but we've initialized 144266203Sian * their SCU tag ram above, so they will be coherent from startup. 145266203Sian */ 146262427Sian val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG); 147262427Sian bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, 148262427Sian val | SCU_CONTROL_ENABLE); 149262427Sian cpu_idcache_wbinv_all(); 150262427Sian 151262427Sian /* 152262427Sian * For each AP core, set the entry point address and argument registers, 153262427Sian * and set the core-enable and core-reset bits in the control register. 154262427Sian */ 155262427Sian val = bus_space_read_4(fdtbus_bs_tag, src, SRC_CONTROL_REG); 156262427Sian for (i=1; i < mp_ncpus; i++) { 157262427Sian bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR0_C1FUNC + 8*i, 158262427Sian pmap_kextract((vm_offset_t)mpentry)); 159262427Sian bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR1_C1ARG + 8*i, 0); 160262427Sian 161262427Sian val |= ((1 << (SRC_CONTROL_C1ENA_SHIFT - 1 + i )) | 162262427Sian ( 1 << (SRC_CONTROL_C1RST_SHIFT - 1 + i))); 163262427Sian 164262427Sian } 165269104Sian bus_space_write_4(fdtbus_bs_tag, src, SRC_CONTROL_REG, val); 166262427Sian 167262427Sian armv7_sev(); 168262427Sian 169262427Sian bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); 170262427Sian bus_space_unmap(fdtbus_bs_tag, src, SRC_SIZE); 171262427Sian} 172262427Sian 173262427Sianvoid 174262427Sianplatform_ipi_send(cpuset_t cpus, u_int ipi) 175262427Sian{ 176262427Sian 177262427Sian pic_ipi_send(cpus, ipi); 178262427Sian} 179