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: stable/11/sys/arm/freescale/imx/imx6_mp.c 307344 2016-10-15 08:27:54Z mmel $"); 29262427Sian#include <sys/param.h> 30262427Sian#include <sys/systm.h> 31262427Sian#include <sys/bus.h> 32262695Sian#include <sys/kernel.h> 33262427Sian#include <sys/lock.h> 34262427Sian#include <sys/mutex.h> 35262427Sian#include <sys/smp.h> 36262427Sian 37281092Sandrew#include <vm/vm.h> 38281092Sandrew#include <vm/pmap.h> 39281092Sandrew 40295319Smmel#include <machine/cpu.h> 41262427Sian#include <machine/smp.h> 42262427Sian#include <machine/fdt.h> 43262427Sian#include <machine/intr.h> 44262427Sian 45262427Sian#define SCU_PHYSBASE 0x00a00000 46262427Sian#define SCU_SIZE 0x00001000 47262427Sian 48262427Sian#define SCU_CONTROL_REG 0x00 49262427Sian#define SCU_CONTROL_ENABLE (1 << 0) 50262427Sian#define SCU_CONFIG_REG 0x04 51262427Sian#define SCU_CONFIG_REG_NCPU_MASK 0x03 52262427Sian#define SCU_CPUPOWER_REG 0x08 53262427Sian#define SCU_INV_TAGS_REG 0x0c 54262427Sian#define SCU_DIAG_CONTROL 0x30 55262427Sian#define SCU_DIAG_DISABLE_MIGBIT (1 << 0) 56262427Sian#define SCU_FILTER_START_REG 0x40 57262427Sian#define SCU_FILTER_END_REG 0x44 58262427Sian#define SCU_SECURE_ACCESS_REG 0x50 59262427Sian#define SCU_NONSECURE_ACCESS_REG 0x54 60262427Sian 61262427Sian#define SRC_PHYSBASE 0x020d8000 62262427Sian#define SRC_SIZE 0x4000 63262427Sian#define SRC_CONTROL_REG 0x00 64262427Sian#define SRC_CONTROL_C1ENA_SHIFT 22 /* Bit for Core 1 enable */ 65262427Sian#define SRC_CONTROL_C1RST_SHIFT 14 /* Bit for Core 1 reset */ 66262427Sian#define SRC_GPR0_C1FUNC 0x20 /* Register for Core 1 entry func */ 67262427Sian#define SRC_GPR1_C1ARG 0x24 /* Register for Core 1 entry arg */ 68262427Sian 69262427Sianvoid 70262427Sianplatform_mp_setmaxid(void) 71262427Sian{ 72262427Sian bus_space_handle_t scu; 73262695Sian int hwcpu, ncpu; 74262427Sian uint32_t val; 75262427Sian 76262427Sian /* If we've already set the global vars don't bother to do it again. */ 77262427Sian if (mp_ncpus != 0) 78262427Sian return; 79262427Sian 80262427Sian if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) 81262427Sian panic("Couldn't map the SCU\n"); 82262427Sian val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG); 83262695Sian hwcpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1; 84262427Sian bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); 85262427Sian 86262695Sian ncpu = hwcpu; 87262695Sian TUNABLE_INT_FETCH("hw.ncpu", &ncpu); 88262695Sian if (ncpu < 1 || ncpu > hwcpu) 89262695Sian ncpu = hwcpu; 90262695Sian 91262695Sian mp_ncpus = ncpu; 92262695Sian mp_maxid = ncpu - 1; 93262427Sian} 94262427Sian 95262427Sianvoid 96262427Sianplatform_mp_start_ap(void) 97262427Sian{ 98262427Sian bus_space_handle_t scu; 99262427Sian bus_space_handle_t src; 100262427Sian 101262427Sian uint32_t val; 102262427Sian int i; 103262427Sian 104262427Sian if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0) 105262427Sian panic("Couldn't map the SCU\n"); 106262427Sian if (bus_space_map(fdtbus_bs_tag, SRC_PHYSBASE, SRC_SIZE, 0, &src) != 0) 107262427Sian panic("Couldn't map the system reset controller (SRC)\n"); 108262427Sian 109262427Sian /* 110262482Sian * Invalidate SCU cache tags. The 0x0000ffff constant invalidates all 111262482Sian * ways on all cores 0-3. Per the ARM docs, it's harmless to write to 112262482Sian * the bits for cores that are not present. 113262427Sian */ 114262482Sian bus_space_write_4(fdtbus_bs_tag, scu, SCU_INV_TAGS_REG, 0x0000ffff); 115262427Sian 116262427Sian /* 117262427Sian * Erratum ARM/MP: 764369 (problems with cache maintenance). 118262427Sian * Setting the "disable-migratory bit" in the undocumented SCU 119262427Sian * Diagnostic Control Register helps work around the problem. 120262427Sian */ 121262427Sian val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL); 122262427Sian bus_space_write_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL, 123262427Sian val | SCU_DIAG_DISABLE_MIGBIT); 124262427Sian 125262482Sian /* 126262482Sian * Enable the SCU, then clean the cache on this core. After these two 127262482Sian * operations the cache tag ram in the SCU is coherent with the contents 128262482Sian * of the cache on this core. The other cores aren't running yet so 129262482Sian * their caches can't contain valid data yet, but we've initialized 130262482Sian * their SCU tag ram above, so they will be coherent from startup. 131262482Sian */ 132262427Sian val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG); 133262427Sian bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, 134262427Sian val | SCU_CONTROL_ENABLE); 135295319Smmel dcache_wbinv_poc_all(); 136262427Sian 137262427Sian /* 138262427Sian * For each AP core, set the entry point address and argument registers, 139262427Sian * and set the core-enable and core-reset bits in the control register. 140262427Sian */ 141262427Sian val = bus_space_read_4(fdtbus_bs_tag, src, SRC_CONTROL_REG); 142262427Sian for (i=1; i < mp_ncpus; i++) { 143262427Sian bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR0_C1FUNC + 8*i, 144262427Sian pmap_kextract((vm_offset_t)mpentry)); 145262427Sian bus_space_write_4(fdtbus_bs_tag, src, SRC_GPR1_C1ARG + 8*i, 0); 146262427Sian 147262427Sian val |= ((1 << (SRC_CONTROL_C1ENA_SHIFT - 1 + i )) | 148262427Sian ( 1 << (SRC_CONTROL_C1RST_SHIFT - 1 + i))); 149262427Sian 150262427Sian } 151268401Sian bus_space_write_4(fdtbus_bs_tag, src, SRC_CONTROL_REG, val); 152262427Sian 153307344Smmel dsb(); 154307344Smmel sev(); 155262427Sian 156262427Sian bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE); 157262427Sian bus_space_unmap(fdtbus_bs_tag, src, SRC_SIZE); 158262427Sian} 159