1*962940ceSLuiz Otavio O Souza /*- 2*962940ceSLuiz Otavio O Souza * Copyright (C) 2015 Daisuke Aoyama <aoyama@peach.ne.jp> 3*962940ceSLuiz Otavio O Souza * All rights reserved. 4*962940ceSLuiz Otavio O Souza * 5*962940ceSLuiz Otavio O Souza * Redistribution and use in source and binary forms, with or without 6*962940ceSLuiz Otavio O Souza * modification, are permitted provided that the following conditions 7*962940ceSLuiz Otavio O Souza * are met: 8*962940ceSLuiz Otavio O Souza * 1. Redistributions of source code must retain the above copyright 9*962940ceSLuiz Otavio O Souza * notice, this list of conditions and the following disclaimer. 10*962940ceSLuiz Otavio O Souza * 2. Redistributions in binary form must reproduce the above copyright 11*962940ceSLuiz Otavio O Souza * notice, this list of conditions and the following disclaimer in the 12*962940ceSLuiz Otavio O Souza * documentation and/or other materials provided with the distribution. 13*962940ceSLuiz Otavio O Souza * 14*962940ceSLuiz Otavio O Souza * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*962940ceSLuiz Otavio O Souza * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*962940ceSLuiz Otavio O Souza * 17*962940ceSLuiz Otavio O Souza * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*962940ceSLuiz Otavio O Souza * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*962940ceSLuiz Otavio O Souza * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*962940ceSLuiz Otavio O Souza * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*962940ceSLuiz Otavio O Souza * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*962940ceSLuiz Otavio O Souza * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*962940ceSLuiz Otavio O Souza * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*962940ceSLuiz Otavio O Souza * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*962940ceSLuiz Otavio O Souza * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*962940ceSLuiz Otavio O Souza * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*962940ceSLuiz Otavio O Souza * SUCH DAMAGE. 28*962940ceSLuiz Otavio O Souza * 29*962940ceSLuiz Otavio O Souza */ 30*962940ceSLuiz Otavio O Souza 31*962940ceSLuiz Otavio O Souza #include <sys/cdefs.h> 32*962940ceSLuiz Otavio O Souza __FBSDID("$FreeBSD$"); 33*962940ceSLuiz Otavio O Souza 34*962940ceSLuiz Otavio O Souza #include <sys/param.h> 35*962940ceSLuiz Otavio O Souza #include <sys/systm.h> 36*962940ceSLuiz Otavio O Souza #include <sys/kernel.h> 37*962940ceSLuiz Otavio O Souza #include <sys/bus.h> 38*962940ceSLuiz Otavio O Souza #include <sys/smp.h> 39*962940ceSLuiz Otavio O Souza 40*962940ceSLuiz Otavio O Souza #include <vm/vm.h> 41*962940ceSLuiz Otavio O Souza #include <vm/pmap.h> 42*962940ceSLuiz Otavio O Souza 43*962940ceSLuiz Otavio O Souza #include <machine/smp.h> 44*962940ceSLuiz Otavio O Souza #include <machine/bus.h> 45*962940ceSLuiz Otavio O Souza #include <machine/fdt.h> 46*962940ceSLuiz Otavio O Souza #include <machine/intr.h> 47*962940ceSLuiz Otavio O Souza 48*962940ceSLuiz Otavio O Souza #ifdef DEBUG 49*962940ceSLuiz Otavio O Souza #define DPRINTF(fmt, ...) do { \ 50*962940ceSLuiz Otavio O Souza printf("%s:%u: ", __func__, __LINE__); \ 51*962940ceSLuiz Otavio O Souza printf(fmt, ##__VA_ARGS__); \ 52*962940ceSLuiz Otavio O Souza } while (0) 53*962940ceSLuiz Otavio O Souza #else 54*962940ceSLuiz Otavio O Souza #define DPRINTF(fmt, ...) 55*962940ceSLuiz Otavio O Souza #endif 56*962940ceSLuiz Otavio O Souza 57*962940ceSLuiz Otavio O Souza #define ARM_LOCAL_BASE 0x40000000 58*962940ceSLuiz Otavio O Souza #define ARM_LOCAL_SIZE 0x00001000 59*962940ceSLuiz Otavio O Souza 60*962940ceSLuiz Otavio O Souza /* mailbox registers */ 61*962940ceSLuiz Otavio O Souza #define MBOXINTRCTRL_CORE(n) (0x00000050 + (0x04 * (n))) 62*962940ceSLuiz Otavio O Souza #define MBOX0SET_CORE(n) (0x00000080 + (0x10 * (n))) 63*962940ceSLuiz Otavio O Souza #define MBOX1SET_CORE(n) (0x00000084 + (0x10 * (n))) 64*962940ceSLuiz Otavio O Souza #define MBOX2SET_CORE(n) (0x00000088 + (0x10 * (n))) 65*962940ceSLuiz Otavio O Souza #define MBOX3SET_CORE(n) (0x0000008C + (0x10 * (n))) 66*962940ceSLuiz Otavio O Souza #define MBOX0CLR_CORE(n) (0x000000C0 + (0x10 * (n))) 67*962940ceSLuiz Otavio O Souza #define MBOX1CLR_CORE(n) (0x000000C4 + (0x10 * (n))) 68*962940ceSLuiz Otavio O Souza #define MBOX2CLR_CORE(n) (0x000000C8 + (0x10 * (n))) 69*962940ceSLuiz Otavio O Souza #define MBOX3CLR_CORE(n) (0x000000CC + (0x10 * (n))) 70*962940ceSLuiz Otavio O Souza 71*962940ceSLuiz Otavio O Souza static bus_space_handle_t bs_periph; 72*962940ceSLuiz Otavio O Souza 73*962940ceSLuiz Otavio O Souza #define BSRD4(addr) \ 74*962940ceSLuiz Otavio O Souza bus_space_read_4(fdtbus_bs_tag, bs_periph, (addr)) 75*962940ceSLuiz Otavio O Souza #define BSWR4(addr, val) \ 76*962940ceSLuiz Otavio O Souza bus_space_write_4(fdtbus_bs_tag, bs_periph, (addr), (val)) 77*962940ceSLuiz Otavio O Souza 78*962940ceSLuiz Otavio O Souza void 79*962940ceSLuiz Otavio O Souza platform_mp_init_secondary(void) 80*962940ceSLuiz Otavio O Souza { 81*962940ceSLuiz Otavio O Souza 82*962940ceSLuiz Otavio O Souza } 83*962940ceSLuiz Otavio O Souza 84*962940ceSLuiz Otavio O Souza void 85*962940ceSLuiz Otavio O Souza platform_mp_setmaxid(void) 86*962940ceSLuiz Otavio O Souza { 87*962940ceSLuiz Otavio O Souza 88*962940ceSLuiz Otavio O Souza DPRINTF("platform_mp_setmaxid\n"); 89*962940ceSLuiz Otavio O Souza if (mp_ncpus != 0) 90*962940ceSLuiz Otavio O Souza return; 91*962940ceSLuiz Otavio O Souza 92*962940ceSLuiz Otavio O Souza mp_ncpus = 4; 93*962940ceSLuiz Otavio O Souza mp_maxid = mp_ncpus - 1; 94*962940ceSLuiz Otavio O Souza DPRINTF("mp_maxid=%d\n", mp_maxid); 95*962940ceSLuiz Otavio O Souza } 96*962940ceSLuiz Otavio O Souza 97*962940ceSLuiz Otavio O Souza int 98*962940ceSLuiz Otavio O Souza platform_mp_probe(void) 99*962940ceSLuiz Otavio O Souza { 100*962940ceSLuiz Otavio O Souza 101*962940ceSLuiz Otavio O Souza DPRINTF("platform_mp_probe\n"); 102*962940ceSLuiz Otavio O Souza CPU_SETOF(0, &all_cpus); 103*962940ceSLuiz Otavio O Souza if (mp_ncpus == 0) 104*962940ceSLuiz Otavio O Souza platform_mp_setmaxid(); 105*962940ceSLuiz Otavio O Souza return (mp_ncpus > 1); 106*962940ceSLuiz Otavio O Souza } 107*962940ceSLuiz Otavio O Souza 108*962940ceSLuiz Otavio O Souza void 109*962940ceSLuiz Otavio O Souza platform_mp_start_ap(void) 110*962940ceSLuiz Otavio O Souza { 111*962940ceSLuiz Otavio O Souza uint32_t val; 112*962940ceSLuiz Otavio O Souza int i, retry; 113*962940ceSLuiz Otavio O Souza 114*962940ceSLuiz Otavio O Souza DPRINTF("platform_mp_start_ap\n"); 115*962940ceSLuiz Otavio O Souza 116*962940ceSLuiz Otavio O Souza /* initialize */ 117*962940ceSLuiz Otavio O Souza if (bus_space_map(fdtbus_bs_tag, ARM_LOCAL_BASE, ARM_LOCAL_SIZE, 118*962940ceSLuiz Otavio O Souza 0, &bs_periph) != 0) 119*962940ceSLuiz Otavio O Souza panic("can't map local peripheral\n"); 120*962940ceSLuiz Otavio O Souza for (i = 0; i < mp_ncpus; i++) { 121*962940ceSLuiz Otavio O Souza /* clear mailbox 0/3 */ 122*962940ceSLuiz Otavio O Souza BSWR4(MBOX0CLR_CORE(i), 0xffffffff); 123*962940ceSLuiz Otavio O Souza BSWR4(MBOX3CLR_CORE(i), 0xffffffff); 124*962940ceSLuiz Otavio O Souza } 125*962940ceSLuiz Otavio O Souza wmb(); 126*962940ceSLuiz Otavio O Souza 127*962940ceSLuiz Otavio O Souza /* boot secondary CPUs */ 128*962940ceSLuiz Otavio O Souza for (i = 1; i < mp_ncpus; i++) { 129*962940ceSLuiz Otavio O Souza /* set entry point to mailbox 3 */ 130*962940ceSLuiz Otavio O Souza BSWR4(MBOX3SET_CORE(i), 131*962940ceSLuiz Otavio O Souza (uint32_t)pmap_kextract((vm_offset_t)mpentry)); 132*962940ceSLuiz Otavio O Souza wmb(); 133*962940ceSLuiz Otavio O Souza 134*962940ceSLuiz Otavio O Souza /* wait for bootup */ 135*962940ceSLuiz Otavio O Souza retry = 1000; 136*962940ceSLuiz Otavio O Souza do { 137*962940ceSLuiz Otavio O Souza /* check entry point */ 138*962940ceSLuiz Otavio O Souza val = BSRD4(MBOX3CLR_CORE(i)); 139*962940ceSLuiz Otavio O Souza if (val == 0) 140*962940ceSLuiz Otavio O Souza break; 141*962940ceSLuiz Otavio O Souza DELAY(100); 142*962940ceSLuiz Otavio O Souza retry--; 143*962940ceSLuiz Otavio O Souza if (retry <= 0) { 144*962940ceSLuiz Otavio O Souza printf("can't start for CPU%d\n", i); 145*962940ceSLuiz Otavio O Souza break; 146*962940ceSLuiz Otavio O Souza } 147*962940ceSLuiz Otavio O Souza } while (1); 148*962940ceSLuiz Otavio O Souza 149*962940ceSLuiz Otavio O Souza /* dsb and sev */ 150*962940ceSLuiz Otavio O Souza armv7_sev(); 151*962940ceSLuiz Otavio O Souza 152*962940ceSLuiz Otavio O Souza /* recode AP in CPU map */ 153*962940ceSLuiz Otavio O Souza CPU_SET(i, &all_cpus); 154*962940ceSLuiz Otavio O Souza } 155*962940ceSLuiz Otavio O Souza 156*962940ceSLuiz Otavio O Souza cpu_idcache_wbinv_all(); 157*962940ceSLuiz Otavio O Souza cpu_l2cache_wbinv_all(); 158*962940ceSLuiz Otavio O Souza } 159*962940ceSLuiz Otavio O Souza 160*962940ceSLuiz Otavio O Souza void 161*962940ceSLuiz Otavio O Souza pic_ipi_send(cpuset_t cpus, u_int ipi) 162*962940ceSLuiz Otavio O Souza { 163*962940ceSLuiz Otavio O Souza int i; 164*962940ceSLuiz Otavio O Souza 165*962940ceSLuiz Otavio O Souza dsb(); 166*962940ceSLuiz Otavio O Souza for (i = 0; i < mp_ncpus; i++) { 167*962940ceSLuiz Otavio O Souza if (CPU_ISSET(i, &cpus)) 168*962940ceSLuiz Otavio O Souza BSWR4(MBOX0SET_CORE(i), 1 << ipi); 169*962940ceSLuiz Otavio O Souza } 170*962940ceSLuiz Otavio O Souza wmb(); 171*962940ceSLuiz Otavio O Souza } 172*962940ceSLuiz Otavio O Souza 173*962940ceSLuiz Otavio O Souza int 174*962940ceSLuiz Otavio O Souza pic_ipi_read(int i) 175*962940ceSLuiz Otavio O Souza { 176*962940ceSLuiz Otavio O Souza uint32_t val; 177*962940ceSLuiz Otavio O Souza int cpu, ipi; 178*962940ceSLuiz Otavio O Souza 179*962940ceSLuiz Otavio O Souza cpu = PCPU_GET(cpuid); 180*962940ceSLuiz Otavio O Souza dsb(); 181*962940ceSLuiz Otavio O Souza if (i != -1) { 182*962940ceSLuiz Otavio O Souza val = BSRD4(MBOX0CLR_CORE(cpu)); 183*962940ceSLuiz Otavio O Souza if (val == 0) 184*962940ceSLuiz Otavio O Souza return (0); 185*962940ceSLuiz Otavio O Souza ipi = ffs(val) - 1; 186*962940ceSLuiz Otavio O Souza return (ipi); 187*962940ceSLuiz Otavio O Souza } 188*962940ceSLuiz Otavio O Souza return (0x3ff); 189*962940ceSLuiz Otavio O Souza } 190*962940ceSLuiz Otavio O Souza 191*962940ceSLuiz Otavio O Souza void 192*962940ceSLuiz Otavio O Souza pic_ipi_clear(int ipi) 193*962940ceSLuiz Otavio O Souza { 194*962940ceSLuiz Otavio O Souza int cpu; 195*962940ceSLuiz Otavio O Souza 196*962940ceSLuiz Otavio O Souza cpu = PCPU_GET(cpuid); 197*962940ceSLuiz Otavio O Souza dsb(); 198*962940ceSLuiz Otavio O Souza BSWR4(MBOX0CLR_CORE(cpu), 1 << ipi); 199*962940ceSLuiz Otavio O Souza wmb(); 200*962940ceSLuiz Otavio O Souza } 201*962940ceSLuiz Otavio O Souza 202*962940ceSLuiz Otavio O Souza void 203*962940ceSLuiz Otavio O Souza platform_ipi_send(cpuset_t cpus, u_int ipi) 204*962940ceSLuiz Otavio O Souza { 205*962940ceSLuiz Otavio O Souza 206*962940ceSLuiz Otavio O Souza pic_ipi_send(cpus, ipi); 207*962940ceSLuiz Otavio O Souza } 208