aml8726_mp.c revision 295319
1228753Smm/*- 2228753Smm * Copyright 2015 John Wehle <john@feith.com> 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17228753Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22228753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24228753Smm * SUCH DAMAGE. 25228753Smm */ 26228753Smm 27228753Smm/* 28228753Smm * Amlogic aml8726 multiprocessor support. 29229592Smm * 30228753Smm * Some processors require powering on which involves poking registers 31228753Smm * on the aobus and cbus ... it's expected that these locations are set 32228753Smm * in stone. 33228753Smm * 34228753Smm * Locking is not used as these routines should only be called by the BP 35228753Smm * during startup and should complete prior to the APs being released (the 36228753Smm * issue being to ensure that a register such as AML_SOC_CPU_CLK_CNTL_REG 37228753Smm * is not concurrently modified). 38228753Smm */ 39228753Smm 40228753Smm#include <sys/cdefs.h> 41228753Smm__FBSDID("$FreeBSD: head/sys/arm/amlogic/aml8726/aml8726_mp.c 295319 2016-02-05 14:57:41Z mmel $"); 42228753Smm#include <sys/param.h> 43228753Smm#include <sys/systm.h> 44228753Smm#include <sys/bus.h> 45228753Smm#include <sys/kernel.h> 46228753Smm#include <sys/module.h> 47228753Smm#include <sys/lock.h> 48228753Smm#include <sys/mutex.h> 49228753Smm#include <sys/resource.h> 50228753Smm#include <sys/rman.h> 51228753Smm#include <sys/smp.h> 52228753Smm 53228753Smm#include <vm/vm.h> 54228753Smm#include <vm/pmap.h> 55228753Smm 56228753Smm#include <machine/cpu.h> 57228753Smm#include <machine/bus.h> 58228753Smm#include <machine/smp.h> 59228753Smm#include <machine/fdt.h> 60228753Smm#include <machine/intr.h> 61228753Smm 62228753Smm#include <dev/fdt/fdt_common.h> 63228753Smm#include <dev/ofw/ofw_bus.h> 64228753Smm#include <dev/ofw/ofw_bus_subr.h> 65228753Smm 66228753Smm#include <arm/amlogic/aml8726/aml8726_soc.h> 67228753Smm 68228753Smmstatic const char *scu_compatible[] = { 69228753Smm "arm,cortex-a5-scu", 70228753Smm "arm,cortex-a9-scu", 71228753Smm NULL 72228753Smm}; 73228753Smm 74228753Smmstatic const char *scu_errata_764369[] = { 75228753Smm "arm,cortex-a9-scu", 76228753Smm NULL 77228753Smm}; 78228753Smm 79228753Smmstatic const char *cpucfg_compatible[] = { 80228753Smm "amlogic,aml8726-cpuconfig", 81228753Smm NULL 82228753Smm}; 83228753Smm 84228753Smmstatic struct { 85228753Smm boolean_t errata_764369; 86228753Smm u_long scu_size; 87228753Smm struct resource scu_res; 88228753Smm u_long cpucfg_size; 89228753Smm struct resource cpucfg_res; 90228753Smm struct resource aobus_res; 91228753Smm struct resource cbus_res; 92228753Smm} aml8726_smp; 93228753Smm 94228753Smm#define AML_SCU_CONTROL_REG 0 95228753Smm#define AML_SCU_CONTROL_ENABLE 1 96228753Smm#define AML_SCU_CONFIG_REG 4 97228753Smm#define AML_SCU_CONFIG_NCPU_MASK 0x3 98228753Smm#define AML_SCU_CPU_PWR_STATUS_REG 8 99228753Smm#define AML_SCU_CPU_PWR_STATUS_CPU3_MASK (3 << 24) 100228753Smm#define AML_SCU_CPU_PWR_STATUS_CPU2_MASK (3 << 16) 101228753Smm#define AML_SCU_CPU_PWR_STATUS_CPU1_MASK (3 << 8) 102228753Smm#define AML_SCU_CPU_PWR_STATUS_CPU0_MASK 3 103228753Smm#define AML_SCU_INV_TAGS_REG 12 104228753Smm#define AML_SCU_DIAG_CONTROL_REG 48 105228753Smm#define AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT 1 106228753Smm 107228753Smm#define AML_CPUCONF_CONTROL_REG 0 108228753Smm#define AML_CPUCONF_CPU1_ADDR_REG 4 109228753Smm#define AML_CPUCONF_CPU2_ADDR_REG 8 110228753Smm#define AML_CPUCONF_CPU3_ADDR_REG 12 111228753Smm 112228753Smm/* aobus */ 113228753Smm 114228753Smm#define AML_M8_CPU_PWR_CNTL0_REG 0xe0 115228753Smm#define AML_M8B_CPU_PWR_CNTL0_MODE_CPU3_MASK (3 << 22) 116228753Smm#define AML_M8B_CPU_PWR_CNTL0_MODE_CPU2_MASK (3 << 20) 117228753Smm#define AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK (3 << 18) 118228753Smm 119228753Smm#define AML_M8_CPU_PWR_CNTL0_ISO_CPU3 (1 << 3) 120228753Smm#define AML_M8_CPU_PWR_CNTL0_ISO_CPU2 (1 << 2) 121228753Smm#define AML_M8_CPU_PWR_CNTL0_ISO_CPU1 (1 << 1) 122228753Smm 123228753Smm#define AML_M8_CPU_PWR_CNTL1_REG 0xe4 124228753Smm#define AML_M8B_CPU_PWR_CNTL1_PWR_CPU3 (1 << 19) 125228753Smm#define AML_M8B_CPU_PWR_CNTL1_PWR_CPU2 (1 << 18) 126228753Smm#define AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 (1 << 17) 127228753Smm 128228753Smm#define AML_M8_CPU_PWR_CNTL1_MODE_CPU3_MASK (3 << 8) 129228753Smm#define AML_M8_CPU_PWR_CNTL1_MODE_CPU2_MASK (3 << 6) 130228753Smm#define AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK (3 << 4) 131228753Smm 132228753Smm#define AML_M8B_CPU_PWR_MEM_PD0_REG 0xf4 133228753Smm#define AML_M8B_CPU_PWR_MEM_PD0_CPU3 (0xf << 20) 134228753Smm#define AML_M8B_CPU_PWR_MEM_PD0_CPU2 (0xf << 24) 135228753Smm#define AML_M8B_CPU_PWR_MEM_PD0_CPU1 (0xf << 28) 136228753Smm 137228753Smm/* cbus */ 138228753Smm 139228753Smm#define AML_SOC_CPU_CLK_CNTL_REG 0x419c 140228753Smm#define AML_M8_CPU_CLK_CNTL_RESET_CPU3 (1 << 27) 141228753Smm#define AML_M8_CPU_CLK_CNTL_RESET_CPU2 (1 << 26) 142228753Smm#define AML_M8_CPU_CLK_CNTL_RESET_CPU1 (1 << 25) 143228753Smm 144228753Smm#define SCU_WRITE_4(reg, value) bus_write_4(&aml8726_smp.scu_res, \ 145228753Smm (reg), (value)) 146228753Smm#define SCU_READ_4(reg) bus_read_4(&aml8726_smp.scu_res, (reg)) 147228753Smm#define SCU_BARRIER(reg) bus_barrier(&aml8726_smp.scu_res, \ 148228753Smm (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 149228753Smm 150228753Smm#define CPUCONF_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cpucfg_res, \ 151228753Smm (reg), (value)) 152228753Smm#define CPUCONF_READ_4(reg) bus_read_4(&aml8726_smp.cpucfg_res, \ 153228753Smm (reg)) 154228753Smm#define CPUCONF_BARRIER(reg) bus_barrier(&aml8726_smp.cpucfg_res, \ 155228753Smm (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 156228753Smm 157228753Smm#define AOBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.aobus_res, \ 158228753Smm (reg), (value)) 159228753Smm#define AOBUS_READ_4(reg) bus_read_4(&aml8726_smp.aobus_res, \ 160228753Smm (reg)) 161228753Smm#define AOBUS_BARRIER(reg) bus_barrier(&aml8726_smp.aobus_res, \ 162228753Smm (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 163228753Smm 164228753Smm#define CBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cbus_res, \ 165228753Smm (reg), (value)) 166228753Smm#define CBUS_READ_4(reg) bus_read_4(&aml8726_smp.cbus_res, \ 167228753Smm (reg)) 168228753Smm#define CBUS_BARRIER(reg) bus_barrier(&aml8726_smp.cbus_res, \ 169228753Smm (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 170228753Smm 171228753Smmstatic phandle_t 172228753Smmfind_node_for_device(const char *device, const char **compatible) 173228753Smm{ 174228753Smm int i; 175228753Smm phandle_t node; 176228753Smm 177228753Smm /* 178228753Smm * Try to access the node directly i.e. through /aliases/. 179228753Smm */ 180228753Smm 181228753Smm if ((node = OF_finddevice(device)) != 0) 182228753Smm for (i = 0; compatible[i]; i++) 183228753Smm if (fdt_is_compatible_strict(node, compatible[i])) 184228753Smm return node; 185228753Smm 186228753Smm /* 187228753Smm * Find the node the long way. 188228753Smm */ 189228753Smm 190228753Smm for (i = 0; compatible[i]; i++) { 191228753Smm if ((node = OF_finddevice("/soc")) == 0) 192228753Smm return (0); 193228753Smm 194228753Smm if ((node = fdt_find_compatible(node, compatible[i], 1)) != 0) 195228753Smm return node; 196228753Smm } 197228753Smm 198228753Smm return (0); 199228753Smm} 200228753Smm 201228753Smm 202228753Smmstatic int 203228753Smmalloc_resource_for_node(phandle_t node, struct resource *res, u_long *size) 204228753Smm{ 205228753Smm int err; 206228753Smm u_long pbase, psize; 207228753Smm u_long start; 208228753Smm 209228753Smm if ((err = fdt_get_range(OF_parent(node), 0, &pbase, &psize)) != 0 || 210228753Smm (err = fdt_regsize(node, &start, size)) != 0) 211228753Smm return (err); 212228753Smm 213228753Smm start += pbase; 214228753Smm 215228753Smm memset(res, 0, sizeof(*res)); 216228753Smm 217228753Smm res->r_bustag = fdtbus_bs_tag; 218228753Smm 219228753Smm err = bus_space_map(res->r_bustag, start, *size, 0, &res->r_bushandle); 220228753Smm 221228753Smm return (err); 222228753Smm} 223228753Smm 224228753Smm 225228753Smmstatic void 226228753Smmpower_on_cpu(int cpu) 227228753Smm{ 228228753Smm uint32_t scpsr; 229228753Smm uint32_t value; 230228753Smm 231228753Smm if (cpu <= 0) 232228753Smm return; 233228753Smm 234228753Smm /* 235228753Smm * Power on the CPU if the intricate details are known, otherwise 236228753Smm * just hope for the best (it may have already be powered on by 237228753Smm * the hardware / firmware). 238228753Smm */ 239228753Smm 240228753Smm switch (aml8726_soc_hw_rev) { 241228753Smm case AML_SOC_HW_REV_M8: 242228753Smm case AML_SOC_HW_REV_M8B: 243228753Smm /* 244228753Smm * Set the SCU power status for the CPU to normal mode. 245228753Smm */ 246228753Smm scpsr = SCU_READ_4(AML_SCU_CPU_PWR_STATUS_REG); 247228753Smm scpsr &= ~(AML_SCU_CPU_PWR_STATUS_CPU1_MASK << ((cpu - 1) * 8)); 248228753Smm SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr); 249228753Smm SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG); 250228753Smm 251228753Smm if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 252228753Smm /* 253228753Smm * Reset may cause the current power status from the 254228753Smm * actual CPU to be written to the SCU (over-writing 255228753Smm * the value we've just written) so set it to normal 256228753Smm * mode as well. 257228753Smm */ 258228753Smm value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG); 259228753Smm value &= ~(AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK << 260228753Smm ((cpu - 1) * 2)); 261228753Smm AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value); 262228753Smm AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG); 263228753Smm } 264228753Smm 265228753Smm DELAY(5); 266228753Smm 267228753Smm /* 268228753Smm * Assert reset. 269228753Smm */ 270228753Smm value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG); 271228753Smm value |= AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1); 272228753Smm CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value); 273228753Smm CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG); 274228753Smm 275228753Smm if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 276228753Smm /* 277228753Smm * Release RAM pull-down. 278228753Smm */ 279228753Smm value = AOBUS_READ_4(AML_M8B_CPU_PWR_MEM_PD0_REG); 280228753Smm value &= ~((uint32_t)AML_M8B_CPU_PWR_MEM_PD0_CPU1 >> 281228753Smm ((cpu - 1) * 4)); 282228753Smm AOBUS_WRITE_4(AML_M8B_CPU_PWR_MEM_PD0_REG, value); 283228753Smm AOBUS_BARRIER(AML_M8B_CPU_PWR_MEM_PD0_REG); 284228753Smm } 285228753Smm 286228753Smm /* 287228753Smm * Power on CPU. 288228753Smm */ 289228753Smm value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG); 290228753Smm value &= ~(AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK << 291228753Smm ((cpu - 1) * 2)); 292228753Smm AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL1_REG, value); 293228753Smm AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL1_REG); 294228753Smm 295228753Smm DELAY(10); 296228753Smm 297228753Smm if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 298228753Smm /* 299228753Smm * Wait for power on confirmation. 300228753Smm */ 301228753Smm for ( ; ; ) { 302228753Smm value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG); 303228753Smm value &= AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 << 304228753Smm (cpu - 1); 305228753Smm if (value) 306228753Smm break; 307228753Smm DELAY(10); 308228753Smm } 309228753Smm } 310228753Smm 311228753Smm /* 312228753Smm * Release peripheral clamp. 313228753Smm */ 314228753Smm value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG); 315228753Smm value &= ~(AML_M8_CPU_PWR_CNTL0_ISO_CPU1 << (cpu - 1)); 316228753Smm AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value); 317228753Smm AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG); 318228753Smm 319228753Smm /* 320228753Smm * Release reset. 321228753Smm */ 322228753Smm value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG); 323228753Smm value &= ~(AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1)); 324228753Smm CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value); 325228753Smm CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG); 326228753Smm 327228753Smm if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 328228753Smm /* 329228753Smm * The Amlogic Linux platform code sets the SCU power 330228753Smm * status for the CPU again for some reason so we 331228753Smm * follow suit (perhaps in case the reset caused 332228753Smm * a stale power status from the actual CPU to be 333228753Smm * written to the SCU). 334228753Smm */ 335228753Smm SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr); 336228753Smm SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG); 337228753Smm } 338228753Smm break; 339228753Smm default: 340228753Smm break; 341228753Smm } 342228753Smm} 343228753Smm 344228753Smm 345228753Smmvoid 346228753Smmplatform_mp_init_secondary(void) 347228753Smm{ 348228753Smm 349228753Smm /* 350228753Smm * Consider modifying the timer driver to support 351228753Smm * per-cpu timers and then enabling the timer for 352228753Smm * each AP. 353228753Smm */ 354228753Smm 355228753Smm intr_pic_init_secondary(); 356228753Smm} 357228753Smm 358228753Smm 359228753Smmvoid 360228753Smmplatform_mp_setmaxid(void) 361228753Smm{ 362228753Smm int err; 363228753Smm int i; 364228753Smm int ncpu; 365228753Smm phandle_t cpucfg_node; 366228753Smm phandle_t scu_node; 367228753Smm uint32_t value; 368228753Smm 369228753Smm if (mp_ncpus != 0) 370228753Smm return; 371228753Smm 372228753Smm ncpu = 1; 373228753Smm 374228753Smm /* 375228753Smm * Is the hardware necessary for SMP present? 376228753Smm */ 377228753Smm 378228753Smm if ((scu_node = find_node_for_device("scu", scu_compatible)) == 0) 379228753Smm goto moveon; 380228753Smm 381228753Smm if ((cpucfg_node = find_node_for_device("cpuconfig", 382228753Smm cpucfg_compatible)) == 0) 383228753Smm goto moveon; 384228753Smm 385228753Smm if (alloc_resource_for_node(scu_node, &aml8726_smp.scu_res, 386228753Smm &aml8726_smp.scu_size) != 0) 387228753Smm panic("Could not allocate resource for SCU"); 388228753Smm 389228753Smm if (alloc_resource_for_node(cpucfg_node, &aml8726_smp.cpucfg_res, 390228753Smm &aml8726_smp.cpucfg_size) != 0) 391228753Smm panic("Could not allocate resource for CPUCONFIG"); 392228753Smm 393228753Smm 394228753Smm /* 395228753Smm * Strictly speaking the aobus and cbus may not be required in 396228753Smm * order to start an AP (it depends on the processor), however 397228753Smm * always mapping them in simplifies the code. 398228753Smm */ 399228753Smm 400228753Smm aml8726_smp.aobus_res.r_bustag = fdtbus_bs_tag; 401228753Smm 402228753Smm err = bus_space_map(aml8726_smp.aobus_res.r_bustag, 403228753Smm AML_SOC_AOBUS_BASE_ADDR, 0x100000, 404228753Smm 0, &aml8726_smp.aobus_res.r_bushandle); 405228753Smm 406228753Smm if (err) 407228753Smm panic("Could not allocate resource for AOBUS"); 408228753Smm 409228753Smm aml8726_smp.cbus_res.r_bustag = fdtbus_bs_tag; 410228753Smm 411228753Smm err = bus_space_map(aml8726_smp.cbus_res.r_bustag, 412228753Smm AML_SOC_CBUS_BASE_ADDR, 0x100000, 413228753Smm 0, &aml8726_smp.cbus_res.r_bushandle); 414228753Smm 415228753Smm if (err) 416228753Smm panic("Could not allocate resource for CBUS"); 417228753Smm 418228753Smm aml8726_smp.errata_764369 = false; 419228753Smm for (i = 0; scu_errata_764369[i]; i++) 420228753Smm if (fdt_is_compatible_strict(scu_node, scu_errata_764369[i])) { 421228753Smm aml8726_smp.errata_764369 = true; 422228753Smm break; 423228753Smm } 424228753Smm 425228753Smm /* 426228753Smm * Read the number of CPUs present. 427228753Smm */ 428228753Smm value = SCU_READ_4(AML_SCU_CONFIG_REG); 429228753Smm ncpu = (value & AML_SCU_CONFIG_NCPU_MASK) + 1; 430228753Smm 431228753Smmmoveon: 432228753Smm mp_ncpus = ncpu; 433228753Smm mp_maxid = ncpu - 1; 434228753Smm} 435228753Smm 436228753Smm 437228753Smmint 438228753Smmplatform_mp_probe(void) 439228753Smm{ 440228753Smm 441228753Smm if (mp_ncpus == 0) 442228753Smm platform_mp_setmaxid(); 443228753Smm 444228753Smm return (mp_ncpus > 1); 445228753Smm} 446228753Smm 447228753Smm 448228753Smmvoid 449228753Smmplatform_mp_start_ap(void) 450228753Smm{ 451228753Smm int i; 452228753Smm uint32_t reg; 453228753Smm uint32_t value; 454228753Smm vm_paddr_t paddr; 455228753Smm 456228753Smm if (mp_ncpus < 2) 457228753Smm return; 458228753Smm 459228753Smm /* 460228753Smm * Invalidate SCU cache tags. The 0x0000ffff constant invalidates 461228753Smm * all ways on all cores 0-3. Per the ARM docs, it's harmless to 462228753Smm * write to the bits for cores that are not present. 463228753Smm */ 464228753Smm SCU_WRITE_4(AML_SCU_INV_TAGS_REG, 0x0000ffff); 465228753Smm 466228753Smm if (aml8726_smp.errata_764369) { 467228753Smm /* 468228753Smm * Erratum ARM/MP: 764369 (problems with cache maintenance). 469228753Smm * Setting the "disable-migratory bit" in the undocumented SCU 470228753Smm * Diagnostic Control Register helps work around the problem. 471228753Smm */ 472228753Smm value = SCU_READ_4(AML_SCU_DIAG_CONTROL_REG); 473228753Smm value |= AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT; 474228753Smm SCU_WRITE_4(AML_SCU_DIAG_CONTROL_REG, value); 475228753Smm } 476228753Smm 477228753Smm /* 478228753Smm * Enable the SCU, then clean the cache on this core. After these 479228753Smm * two operations the cache tag ram in the SCU is coherent with 480228753Smm * the contents of the cache on this core. The other cores aren't 481228753Smm * running yet so their caches can't contain valid data yet, however 482228753Smm * we've initialized their SCU tag ram above, so they will be 483228753Smm * coherent from startup. 484228753Smm */ 485228753Smm value = SCU_READ_4(AML_SCU_CONTROL_REG); 486228753Smm value |= AML_SCU_CONTROL_ENABLE; 487228753Smm SCU_WRITE_4(AML_SCU_CONTROL_REG, value); 488228753Smm SCU_BARRIER(AML_SCU_CONTROL_REG); 489228753Smm dcache_wbinv_poc_all(); 490228753Smm 491228753Smm /* Set the boot address and power on each AP. */ 492228753Smm paddr = pmap_kextract((vm_offset_t)mpentry); 493228753Smm for (i = 1; i < mp_ncpus; i++) { 494228753Smm reg = AML_CPUCONF_CPU1_ADDR_REG + ((i - 1) * 4); 495228753Smm CPUCONF_WRITE_4(reg, paddr); 496228753Smm CPUCONF_BARRIER(reg); 497228753Smm 498228753Smm power_on_cpu(i); 499228753Smm } 500228753Smm 501228753Smm /* 502228753Smm * Enable the APs. 503228753Smm * 504228753Smm * The Amlogic Linux platform code sets the lsb for some reason 505228753Smm * in addition to the enable bit for each AP so we follow suit 506228753Smm * (the lsb may be the enable bit for the BP, though in that case 507228753Smm * it should already be set since it's currently running). 508228753Smm */ 509228753Smm value = CPUCONF_READ_4(AML_CPUCONF_CONTROL_REG); 510228753Smm value |= 1; 511228753Smm for (i = 1; i < mp_ncpus; i++) 512228753Smm value |= (1 << i); 513228753Smm CPUCONF_WRITE_4(AML_CPUCONF_CONTROL_REG, value); 514228753Smm CPUCONF_BARRIER(AML_CPUCONF_CONTROL_REG); 515228753Smm 516228753Smm /* Wakeup the now enabled APs */ 517228753Smm armv7_sev(); 518228753Smm 519228753Smm /* 520228753Smm * Free the resources which are not needed after startup. 521228753Smm */ 522228753Smm bus_space_unmap(aml8726_smp.scu_res.r_bustag, 523228753Smm aml8726_smp.scu_res.r_bushandle, 524228753Smm aml8726_smp.scu_size); 525228753Smm bus_space_unmap(aml8726_smp.cpucfg_res.r_bustag, 526228753Smm aml8726_smp.cpucfg_res.r_bushandle, 527228753Smm aml8726_smp.cpucfg_size); 528228753Smm bus_space_unmap(aml8726_smp.aobus_res.r_bustag, 529228753Smm aml8726_smp.aobus_res.r_bushandle, 530228753Smm 0x100000); 531228753Smm bus_space_unmap(aml8726_smp.cbus_res.r_bustag, 532228753Smm aml8726_smp.cbus_res.r_bushandle, 533228753Smm 0x100000); 534228753Smm memset(&aml8726_smp, 0, sizeof(aml8726_smp)); 535228753Smm} 536228753Smm 537228753Smmvoid 538228753Smmplatform_ipi_send(cpuset_t cpus, u_int ipi) 539228753Smm{ 540228753Smm 541228753Smm pic_ipi_send(cpus, ipi); 542228753Smm} 543228753Smm 544228753Smm/* 545228753Smm * Stub drivers for cosmetic purposes. 546228753Smm */ 547228753Smmstruct aml8726_scu_softc { 548228753Smm device_t dev; 549228753Smm}; 550228753Smm 551228753Smmstatic int 552228753Smmaml8726_scu_probe(device_t dev) 553228753Smm{ 554228753Smm int i; 555228753Smm 556228753Smm for (i = 0; scu_compatible[i]; i++) 557228753Smm if (ofw_bus_is_compatible(dev, scu_compatible[i])) 558228753Smm break; 559228753Smm 560228753Smm if (!scu_compatible[i]) 561228753Smm return (ENXIO); 562228753Smm 563228753Smm device_set_desc(dev, "ARM Snoop Control Unit"); 564228753Smm 565228753Smm return (BUS_PROBE_DEFAULT); 566228753Smm} 567228753Smm 568228753Smmstatic int 569228753Smmaml8726_scu_attach(device_t dev) 570228753Smm{ 571228753Smm struct aml8726_scu_softc *sc = device_get_softc(dev); 572228753Smm 573228753Smm sc->dev = dev; 574228753Smm 575228753Smm return (0); 576228753Smm} 577228753Smm 578228753Smmstatic int 579228753Smmaml8726_scu_detach(device_t dev) 580228753Smm{ 581228753Smm 582228753Smm return (0); 583228753Smm} 584228753Smm 585228753Smmstatic device_method_t aml8726_scu_methods[] = { 586228753Smm /* Device interface */ 587228753Smm DEVMETHOD(device_probe, aml8726_scu_probe), 588228753Smm DEVMETHOD(device_attach, aml8726_scu_attach), 589228753Smm DEVMETHOD(device_detach, aml8726_scu_detach), 590228753Smm 591228753Smm DEVMETHOD_END 592228753Smm}; 593228753Smm 594228753Smmstatic driver_t aml8726_scu_driver = { 595228753Smm "scu", 596228753Smm aml8726_scu_methods, 597228753Smm sizeof(struct aml8726_scu_softc), 598228753Smm}; 599228753Smm 600228753Smmstatic devclass_t aml8726_scu_devclass; 601228753Smm 602228753SmmEARLY_DRIVER_MODULE(scu, simplebus, aml8726_scu_driver, aml8726_scu_devclass, 603228753Smm 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); 604228753Smm 605228753Smmstruct aml8726_cpucfg_softc { 606228753Smm device_t dev; 607228753Smm}; 608228753Smm 609228753Smmstatic int 610228753Smmaml8726_cpucfg_probe(device_t dev) 611228753Smm{ 612228753Smm int i; 613228753Smm 614228753Smm for (i = 0; cpucfg_compatible[i]; i++) 615228753Smm if (ofw_bus_is_compatible(dev, cpucfg_compatible[i])) 616228753Smm break; 617228753Smm 618228753Smm if (!cpucfg_compatible[i]) 619228753Smm return (ENXIO); 620228753Smm 621228753Smm device_set_desc(dev, "Amlogic CPU Config"); 622228753Smm 623228753Smm return (BUS_PROBE_DEFAULT); 624228753Smm} 625228753Smm 626228753Smmstatic int 627228753Smmaml8726_cpucfg_attach(device_t dev) 628228753Smm{ 629228753Smm struct aml8726_cpucfg_softc *sc = device_get_softc(dev); 630228753Smm 631228753Smm sc->dev = dev; 632228753Smm 633228753Smm return (0); 634228753Smm} 635228753Smm 636228753Smmstatic int 637228753Smmaml8726_cpucfg_detach(device_t dev) 638228753Smm{ 639228753Smm 640228753Smm return (0); 641228753Smm} 642228753Smm 643228753Smmstatic device_method_t aml8726_cpucfg_methods[] = { 644228753Smm /* Device interface */ 645228753Smm DEVMETHOD(device_probe, aml8726_cpucfg_probe), 646228753Smm DEVMETHOD(device_attach, aml8726_cpucfg_attach), 647228753Smm DEVMETHOD(device_detach, aml8726_cpucfg_detach), 648228753Smm 649228753Smm DEVMETHOD_END 650228753Smm}; 651228753Smm 652228753Smmstatic driver_t aml8726_cpucfg_driver = { 653228753Smm "cpuconfig", 654228753Smm aml8726_cpucfg_methods, 655228753Smm sizeof(struct aml8726_cpucfg_softc), 656228753Smm}; 657228753Smm 658228753Smmstatic devclass_t aml8726_cpucfg_devclass; 659228753Smm 660228753SmmEARLY_DRIVER_MODULE(cpuconfig, simplebus, aml8726_cpucfg_driver, 661228753Smm aml8726_cpucfg_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); 662228753Smm