aml8726_mp.c revision 280905
11556Srgrimes/*- 21556Srgrimes * Copyright 2015 John Wehle <john@feith.com> 31556Srgrimes * All rights reserved. 41556Srgrimes * 51556Srgrimes * Redistribution and use in source and binary forms, with or without 61556Srgrimes * modification, are permitted provided that the following conditions 71556Srgrimes * are met: 81556Srgrimes * 1. Redistributions of source code must retain the above copyright 91556Srgrimes * notice, this list of conditions and the following disclaimer. 101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111556Srgrimes * notice, this list of conditions and the following disclaimer in the 121556Srgrimes * documentation and/or other materials provided with the distribution. 131556Srgrimes * 141556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241556Srgrimes * SUCH DAMAGE. 251556Srgrimes */ 261556Srgrimes 271556Srgrimes/* 281556Srgrimes * Amlogic aml8726 multiprocessor support. 291556Srgrimes * 301556Srgrimes * Some processors require powering on which involves poking registers 311556Srgrimes * on the aobus and cbus ... it's expected that these locations are set 321556Srgrimes * in stone. 331556Srgrimes * 3436150Scharnier * Locking is not used as these routines should only be called by the BP 3536150Scharnier * during startup and should complete prior to the APs being released (the 3636150Scharnier * issue being to ensure that a register such as AML_SOC_CPU_CLK_CNTL_REG 371556Srgrimes * is not concurrently modified). 3899110Sobrien */ 3999110Sobrien 401556Srgrimes#include <sys/cdefs.h> 411556Srgrimes__FBSDID("$FreeBSD: head/sys/arm/amlogic/aml8726/aml8726_mp.c 280905 2015-03-31 11:50:46Z ganbold $"); 421556Srgrimes#include <sys/param.h> 431556Srgrimes#include <sys/systm.h> 441556Srgrimes#include <sys/bus.h> 451556Srgrimes#include <sys/kernel.h> 461556Srgrimes#include <sys/module.h> 471556Srgrimes#include <sys/lock.h> 481556Srgrimes#include <sys/mutex.h> 491556Srgrimes#include <sys/resource.h> 501556Srgrimes#include <sys/rman.h> 511556Srgrimes#include <sys/smp.h> 5217987Speter 5317987Speter#include <machine/bus.h> 541556Srgrimes#include <machine/smp.h> 5517987Speter#include <machine/fdt.h> 5617987Speter#include <machine/intr.h> 571556Srgrimes 5817987Speter#include <dev/fdt/fdt_common.h> 5917987Speter#include <dev/ofw/ofw_bus.h> 6017987Speter#include <dev/ofw/ofw_bus_subr.h> 6117987Speter 6217987Speter#include <arm/amlogic/aml8726/aml8726_soc.h> 6397909Stjr 641556Srgrimesstatic const char *scu_compatible[] = { 6517987Speter "arm,cortex-a5-scu", 661556Srgrimes "arm,cortex-a9-scu", 671556Srgrimes NULL 681556Srgrimes}; 691556Srgrimes 701556Srgrimesstatic const char *scu_errata_764369[] = { 71104286Stjr "arm,cortex-a9-scu", 721556Srgrimes NULL 731556Srgrimes}; 74199629Sjilles 751556Srgrimesstatic const char *cpucfg_compatible[] = { 761556Srgrimes "amlogic,aml8726-cpuconfig", 771556Srgrimes NULL 781556Srgrimes}; 791556Srgrimes 801556Srgrimesstatic struct { 811556Srgrimes boolean_t errata_764369; 821556Srgrimes u_long scu_size; 831556Srgrimes struct resource scu_res; 841556Srgrimes u_long cpucfg_size; 851556Srgrimes struct resource cpucfg_res; 861556Srgrimes struct resource aobus_res; 871556Srgrimes struct resource cbus_res; 881556Srgrimes} aml8726_smp; 891556Srgrimes 901556Srgrimes#define AML_SCU_CONTROL_REG 0 911556Srgrimes#define AML_SCU_CONTROL_ENABLE 1 921556Srgrimes#define AML_SCU_CONFIG_REG 4 931556Srgrimes#define AML_SCU_CONFIG_NCPU_MASK 0x3 941556Srgrimes#define AML_SCU_CPU_PWR_STATUS_REG 8 951556Srgrimes#define AML_SCU_CPU_PWR_STATUS_CPU3_MASK (3 << 24) 961556Srgrimes#define AML_SCU_CPU_PWR_STATUS_CPU2_MASK (3 << 16) 971556Srgrimes#define AML_SCU_CPU_PWR_STATUS_CPU1_MASK (3 << 8) 981556Srgrimes#define AML_SCU_CPU_PWR_STATUS_CPU0_MASK 3 9990111Simp#define AML_SCU_INV_TAGS_REG 12 10090111Simp#define AML_SCU_DIAG_CONTROL_REG 48 1011556Srgrimes#define AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT 1 1021556Srgrimes 1031556Srgrimes#define AML_CPUCONF_CONTROL_REG 0 10497815Stjr#define AML_CPUCONF_CPU1_ADDR_REG 4 10597815Stjr#define AML_CPUCONF_CPU2_ADDR_REG 8 10697815Stjr#define AML_CPUCONF_CPU3_ADDR_REG 12 10797815Stjr 10897815Stjr/* aobus */ 1091556Srgrimes 1101556Srgrimes#define AML_M8_CPU_PWR_CNTL0_REG 0xe0 11190111Simp#define AML_M8B_CPU_PWR_CNTL0_MODE_CPU3_MASK (3 << 22) 11290111Simp#define AML_M8B_CPU_PWR_CNTL0_MODE_CPU2_MASK (3 << 20) 1131556Srgrimes#define AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK (3 << 18) 1141556Srgrimes 1151556Srgrimes#define AML_M8_CPU_PWR_CNTL0_ISO_CPU3 (1 << 3) 11697815Stjr#define AML_M8_CPU_PWR_CNTL0_ISO_CPU2 (1 << 2) 11797815Stjr#define AML_M8_CPU_PWR_CNTL0_ISO_CPU1 (1 << 1) 11897815Stjr 11997815Stjr#define AML_M8_CPU_PWR_CNTL1_REG 0xe4 12097815Stjr#define AML_M8B_CPU_PWR_CNTL1_PWR_CPU3 (1 << 19) 1211556Srgrimes#define AML_M8B_CPU_PWR_CNTL1_PWR_CPU2 (1 << 18) 1221556Srgrimes#define AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 (1 << 17) 12390111Simp 12490111Simp#define AML_M8_CPU_PWR_CNTL1_MODE_CPU3_MASK (3 << 8) 1251556Srgrimes#define AML_M8_CPU_PWR_CNTL1_MODE_CPU2_MASK (3 << 6) 1261556Srgrimes#define AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK (3 << 4) 1271556Srgrimes 1281556Srgrimes#define AML_M8B_CPU_PWR_MEM_PD0_REG 0xf4 12997815Stjr#define AML_M8B_CPU_PWR_MEM_PD0_CPU3 (0xf << 20) 13097815Stjr#define AML_M8B_CPU_PWR_MEM_PD0_CPU2 (0xf << 24) 13197815Stjr#define AML_M8B_CPU_PWR_MEM_PD0_CPU1 (0xf << 28) 13297815Stjr 13397815Stjr/* cbus */ 134194516Sjilles 1351556Srgrimes#define AML_SOC_CPU_CLK_CNTL_REG 0x419c 136153245Sstefanf#define AML_M8_CPU_CLK_CNTL_RESET_CPU3 (1 << 27) 137153245Sstefanf#define AML_M8_CPU_CLK_CNTL_RESET_CPU2 (1 << 26) 138153245Sstefanf#define AML_M8_CPU_CLK_CNTL_RESET_CPU1 (1 << 25) 139153245Sstefanf 140194516Sjilles#define SCU_WRITE_4(reg, value) bus_write_4(&aml8726_smp.scu_res, \ 141194516Sjilles (reg), (value)) 142194516Sjilles#define SCU_READ_4(reg) bus_read_4(&aml8726_smp.scu_res, (reg)) 14397909Stjr#define SCU_BARRIER(reg) bus_barrier(&aml8726_smp.scu_res, \ 14497909Stjr (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 14597909Stjr 14697909Stjr#define CPUCONF_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cpucfg_res, \ 147194516Sjilles (reg), (value)) 14897815Stjr#define CPUCONF_READ_4(reg) bus_read_4(&aml8726_smp.cpucfg_res, \ 14997815Stjr (reg)) 15097815Stjr#define CPUCONF_BARRIER(reg) bus_barrier(&aml8726_smp.cpucfg_res, \ 151194516Sjilles (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 152194516Sjilles 153194516Sjilles#define AOBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.aobus_res, \ 154194516Sjilles (reg), (value)) 155194516Sjilles#define AOBUS_READ_4(reg) bus_read_4(&aml8726_smp.aobus_res, \ 15697815Stjr (reg)) 15797815Stjr#define AOBUS_BARRIER(reg) bus_barrier(&aml8726_smp.aobus_res, \ 158194516Sjilles (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 159194516Sjilles 160194516Sjilles#define CBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cbus_res, \ 16197815Stjr (reg), (value)) 16297815Stjr#define CBUS_READ_4(reg) bus_read_4(&aml8726_smp.cbus_res, \ 16397815Stjr (reg)) 164194516Sjilles#define CBUS_BARRIER(reg) bus_barrier(&aml8726_smp.cbus_res, \ 165194516Sjilles (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 16697815Stjr 16797815Stjrstatic phandle_t 168117261Sddsfind_node_for_device(const char *device, const char **compatible) 1691556Srgrimes{ 1701556Srgrimes int i; 17190111Simp phandle_t node; 17290111Simp 1731556Srgrimes /* 1741556Srgrimes * Try to access the node directly i.e. through /aliases/. 1751556Srgrimes */ 1761556Srgrimes 1771556Srgrimes if ((node = OF_finddevice(device)) != 0) 1781556Srgrimes for (i = 0; compatible[i]; i++) 1791556Srgrimes if (fdt_is_compatible_strict(node, compatible[i])) 1801556Srgrimes return node; 1811556Srgrimes 1821556Srgrimes /* 1831556Srgrimes * Find the node the long way. 1841556Srgrimes */ 1851556Srgrimes 1861556Srgrimes for (i = 0; compatible[i]; i++) { 1871556Srgrimes if ((node = OF_finddevice("/soc")) == 0) 1881556Srgrimes return (0); 1891556Srgrimes 1901556Srgrimes if ((node = fdt_find_compatible(node, compatible[i], 1)) != 0) 1911556Srgrimes return node; 1921556Srgrimes } 1931556Srgrimes 1941556Srgrimes return (0); 1951556Srgrimes} 1961556Srgrimes 1971556Srgrimes 1981556Srgrimesstatic int 1991556Srgrimesalloc_resource_for_node(phandle_t node, struct resource *res, u_long *size) 2001556Srgrimes{ 20190111Simp int err; 20290111Simp u_long pbase, psize; 2031556Srgrimes u_long start; 2041556Srgrimes 2051556Srgrimes if ((err = fdt_get_range(OF_parent(node), 0, &pbase, &psize)) != 0 || 2061556Srgrimes (err = fdt_regsize(node, &start, size)) != 0) 2071556Srgrimes return (err); 2081556Srgrimes 20990111Simp start += pbase; 21090111Simp 2111556Srgrimes memset(res, 0, sizeof(*res)); 2121556Srgrimes 2131556Srgrimes res->r_bustag = fdtbus_bs_tag; 2141556Srgrimes 2151556Srgrimes err = bus_space_map(res->r_bustag, start, *size, 0, &res->r_bushandle); 2161556Srgrimes 2171556Srgrimes return (err); 2181556Srgrimes} 2191556Srgrimes 2201556Srgrimes 2211556Srgrimesstatic void 22290111Simppower_on_cpu(int cpu) 22390111Simp{ 2241556Srgrimes uint32_t scpsr; 2251556Srgrimes uint32_t value; 2261556Srgrimes 2271556Srgrimes if (cpu <= 0) 2281556Srgrimes return; 2291556Srgrimes 2301556Srgrimes /* 2311556Srgrimes * Power on the CPU if the intricate details are known, otherwise 2321556Srgrimes * just hope for the best (it may have already be powered on by 2331556Srgrimes * the hardware / firmware). 2341556Srgrimes */ 23590111Simp 23690111Simp switch (aml8726_soc_hw_rev) { 2371556Srgrimes case AML_SOC_HW_REV_M8: 2381556Srgrimes case AML_SOC_HW_REV_M8B: 2391556Srgrimes /* 2401556Srgrimes * Set the SCU power status for the CPU to normal mode. 2411556Srgrimes */ 2421556Srgrimes scpsr = SCU_READ_4(AML_SCU_CPU_PWR_STATUS_REG); 2431556Srgrimes scpsr &= ~(AML_SCU_CPU_PWR_STATUS_CPU1_MASK << ((cpu - 1) * 8)); 2441556Srgrimes SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr); 2451556Srgrimes SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG); 24690111Simp 24790111Simp if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 2481556Srgrimes /* 2491556Srgrimes * Reset may cause the current power status from the 2501556Srgrimes * actual CPU to be written to the SCU (over-writing 2511556Srgrimes * the value we've just written) so set it to normal 2521556Srgrimes * mode as well. 2531556Srgrimes */ 2541556Srgrimes value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG); 2551556Srgrimes value &= ~(AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK << 256199629Sjilles ((cpu - 1) * 2)); 25790111Simp AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value); 2581556Srgrimes AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG); 2591556Srgrimes } 2601556Srgrimes 2611556Srgrimes DELAY(5); 2621556Srgrimes 2631556Srgrimes /* 2641556Srgrimes * Assert reset. 2651556Srgrimes */ 2661556Srgrimes value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG); 26790111Simp value |= AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1); 26890111Simp CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value); 2691556Srgrimes CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG); 270104289Stjr 2711556Srgrimes if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 272104289Stjr /* 273104289Stjr * Release RAM pull-down. 274104289Stjr */ 275104289Stjr value = AOBUS_READ_4(AML_M8B_CPU_PWR_MEM_PD0_REG); 2761556Srgrimes value &= ~((uint32_t)AML_M8B_CPU_PWR_MEM_PD0_CPU1 >> 277104289Stjr ((cpu - 1) * 4)); 278104286Stjr AOBUS_WRITE_4(AML_M8B_CPU_PWR_MEM_PD0_REG, value); 279104289Stjr AOBUS_BARRIER(AML_M8B_CPU_PWR_MEM_PD0_REG); 280104289Stjr } 281104289Stjr 2821556Srgrimes /* 2831556Srgrimes * Power on CPU. 284104286Stjr */ 285104286Stjr value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG); 286104286Stjr value &= ~(AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK << 287104286Stjr ((cpu - 1) * 2)); 288104286Stjr AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL1_REG, value); 289104286Stjr AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL1_REG); 2901556Srgrimes 291104286Stjr DELAY(10); 292104286Stjr 293104286Stjr if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 294104286Stjr /* 295104286Stjr * Wait for power on confirmation. 296104286Stjr */ 2971556Srgrimes for ( ; ; ) { 298104286Stjr value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG); 299104286Stjr value &= AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 << 3001556Srgrimes (cpu - 1); 3011556Srgrimes if (value) 30290111Simp break; 30390111Simp DELAY(10); 304104286Stjr } 3051556Srgrimes } 306104286Stjr 307104286Stjr /* 308104286Stjr * Release peripheral clamp. 3091556Srgrimes */ 3101556Srgrimes value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG); 3111556Srgrimes value &= ~(AML_M8_CPU_PWR_CNTL0_ISO_CPU1 << (cpu - 1)); 3121556Srgrimes AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value); 3131556Srgrimes AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG); 3141556Srgrimes 3151556Srgrimes /* 3161556Srgrimes * Release reset. 31790111Simp */ 31890111Simp value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG); 3191556Srgrimes value &= ~(AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1)); 3201556Srgrimes CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value); 3211556Srgrimes CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG); 3221556Srgrimes 3231556Srgrimes if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 3241556Srgrimes /* 3251556Srgrimes * The Amlogic Linux platform code sets the SCU power 3261556Srgrimes * status for the CPU again for some reason so we 3271556Srgrimes * follow suit (perhaps in case the reset caused 3281556Srgrimes * a stale power status from the actual CPU to be 3291556Srgrimes * written to the SCU). 3301556Srgrimes */ 3311556Srgrimes SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr); 3321556Srgrimes SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG); 3331556Srgrimes } 3341556Srgrimes break; 3351556Srgrimes default: 3361556Srgrimes break; 3371556Srgrimes } 3381556Srgrimes} 3391556Srgrimes 340 341void 342platform_mp_init_secondary(void) 343{ 344 345 /* 346 * Consider modifying the timer driver to support 347 * per-cpu timers and then enabling the timer for 348 * each AP. 349 */ 350 351 arm_init_secondary_ic(); 352} 353 354 355void 356platform_mp_setmaxid(void) 357{ 358 int err; 359 int i; 360 int ncpu; 361 phandle_t cpucfg_node; 362 phandle_t scu_node; 363 uint32_t value; 364 365 if (mp_ncpus != 0) 366 return; 367 368 ncpu = 1; 369 370 /* 371 * Is the hardware necessary for SMP present? 372 */ 373 374 if ((scu_node = find_node_for_device("scu", scu_compatible)) == 0) 375 goto moveon; 376 377 if ((cpucfg_node = find_node_for_device("cpuconfig", 378 cpucfg_compatible)) == 0) 379 goto moveon; 380 381 if (alloc_resource_for_node(scu_node, &aml8726_smp.scu_res, 382 &aml8726_smp.scu_size) != 0) 383 panic("Could not allocate resource for SCU"); 384 385 if (alloc_resource_for_node(cpucfg_node, &aml8726_smp.cpucfg_res, 386 &aml8726_smp.cpucfg_size) != 0) 387 panic("Could not allocate resource for CPUCONFIG"); 388 389 390 /* 391 * Strictly speaking the aobus and cbus may not be required in 392 * order to start an AP (it depends on the processor), however 393 * always mapping them in simplifies the code. 394 */ 395 396 aml8726_smp.aobus_res.r_bustag = fdtbus_bs_tag; 397 398 err = bus_space_map(aml8726_smp.aobus_res.r_bustag, 399 AML_SOC_AOBUS_BASE_ADDR, 0x100000, 400 0, &aml8726_smp.aobus_res.r_bushandle); 401 402 if (err) 403 panic("Could not allocate resource for AOBUS"); 404 405 aml8726_smp.cbus_res.r_bustag = fdtbus_bs_tag; 406 407 err = bus_space_map(aml8726_smp.cbus_res.r_bustag, 408 AML_SOC_CBUS_BASE_ADDR, 0x100000, 409 0, &aml8726_smp.cbus_res.r_bushandle); 410 411 if (err) 412 panic("Could not allocate resource for CBUS"); 413 414 aml8726_smp.errata_764369 = false; 415 for (i = 0; scu_errata_764369[i]; i++) 416 if (fdt_is_compatible_strict(scu_node, scu_errata_764369[i])) { 417 aml8726_smp.errata_764369 = true; 418 break; 419 } 420 421 /* 422 * Read the number of CPUs present. 423 */ 424 value = SCU_READ_4(AML_SCU_CONFIG_REG); 425 ncpu = (value & AML_SCU_CONFIG_NCPU_MASK) + 1; 426 427moveon: 428 mp_ncpus = ncpu; 429 mp_maxid = ncpu - 1; 430} 431 432 433int 434platform_mp_probe(void) 435{ 436 437 if (mp_ncpus == 0) 438 platform_mp_setmaxid(); 439 440 return (mp_ncpus > 1); 441} 442 443 444void 445platform_mp_start_ap(void) 446{ 447 int i; 448 uint32_t reg; 449 uint32_t value; 450 vm_paddr_t paddr; 451 452 if (mp_ncpus < 2) 453 return; 454 455 /* 456 * Invalidate SCU cache tags. The 0x0000ffff constant invalidates 457 * all ways on all cores 0-3. Per the ARM docs, it's harmless to 458 * write to the bits for cores that are not present. 459 */ 460 SCU_WRITE_4(AML_SCU_INV_TAGS_REG, 0x0000ffff); 461 462 if (aml8726_smp.errata_764369) { 463 /* 464 * Erratum ARM/MP: 764369 (problems with cache maintenance). 465 * Setting the "disable-migratory bit" in the undocumented SCU 466 * Diagnostic Control Register helps work around the problem. 467 */ 468 value = SCU_READ_4(AML_SCU_DIAG_CONTROL_REG); 469 value |= AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT; 470 SCU_WRITE_4(AML_SCU_DIAG_CONTROL_REG, value); 471 } 472 473 /* 474 * Enable the SCU, then clean the cache on this core. After these 475 * two operations the cache tag ram in the SCU is coherent with 476 * the contents of the cache on this core. The other cores aren't 477 * running yet so their caches can't contain valid data yet, however 478 * we've initialized their SCU tag ram above, so they will be 479 * coherent from startup. 480 */ 481 value = SCU_READ_4(AML_SCU_CONTROL_REG); 482 value |= AML_SCU_CONTROL_ENABLE; 483 SCU_WRITE_4(AML_SCU_CONTROL_REG, value); 484 SCU_BARRIER(AML_SCU_CONTROL_REG); 485 cpu_idcache_wbinv_all(); 486 487 /* Set the boot address and power on each AP. */ 488 paddr = pmap_kextract((vm_offset_t)mpentry); 489 for (i = 1; i < mp_ncpus; i++) { 490 reg = AML_CPUCONF_CPU1_ADDR_REG + ((i - 1) * 4); 491 CPUCONF_WRITE_4(reg, paddr); 492 CPUCONF_BARRIER(reg); 493 494 power_on_cpu(i); 495 } 496 497 /* 498 * Enable the APs. 499 * 500 * The Amlogic Linux platform code sets the lsb for some reason 501 * in addition to the enable bit for each AP so we follow suit 502 * (the lsb may be the enable bit for the BP, though in that case 503 * it should already be set since it's currently running). 504 */ 505 value = CPUCONF_READ_4(AML_CPUCONF_CONTROL_REG); 506 value |= 1; 507 for (i = 1; i < mp_ncpus; i++) 508 value |= (1 << i); 509 CPUCONF_WRITE_4(AML_CPUCONF_CONTROL_REG, value); 510 CPUCONF_BARRIER(AML_CPUCONF_CONTROL_REG); 511 512 /* Wakeup the now enabled APs */ 513 armv7_sev(); 514 515 /* 516 * Free the resources which are not needed after startup. 517 */ 518 bus_space_unmap(aml8726_smp.scu_res.r_bustag, 519 aml8726_smp.scu_res.r_bushandle, 520 aml8726_smp.scu_size); 521 bus_space_unmap(aml8726_smp.cpucfg_res.r_bustag, 522 aml8726_smp.cpucfg_res.r_bushandle, 523 aml8726_smp.cpucfg_size); 524 bus_space_unmap(aml8726_smp.aobus_res.r_bustag, 525 aml8726_smp.aobus_res.r_bushandle, 526 0x100000); 527 bus_space_unmap(aml8726_smp.cbus_res.r_bustag, 528 aml8726_smp.cbus_res.r_bushandle, 529 0x100000); 530 memset(&aml8726_smp, 0, sizeof(aml8726_smp)); 531} 532 533void 534platform_ipi_send(cpuset_t cpus, u_int ipi) 535{ 536 537 pic_ipi_send(cpus, ipi); 538} 539 540/* 541 * Stub drivers for cosmetic purposes. 542 */ 543struct aml8726_scu_softc { 544 device_t dev; 545}; 546 547static int 548aml8726_scu_probe(device_t dev) 549{ 550 int i; 551 552 for (i = 0; scu_compatible[i]; i++) 553 if (ofw_bus_is_compatible(dev, scu_compatible[i])) 554 break; 555 556 if (!scu_compatible[i]) 557 return (ENXIO); 558 559 device_set_desc(dev, "ARM Snoop Control Unit"); 560 561 return (BUS_PROBE_DEFAULT); 562} 563 564static int 565aml8726_scu_attach(device_t dev) 566{ 567 struct aml8726_scu_softc *sc = device_get_softc(dev); 568 569 sc->dev = dev; 570 571 return (0); 572} 573 574static int 575aml8726_scu_detach(device_t dev) 576{ 577 578 return (0); 579} 580 581static device_method_t aml8726_scu_methods[] = { 582 /* Device interface */ 583 DEVMETHOD(device_probe, aml8726_scu_probe), 584 DEVMETHOD(device_attach, aml8726_scu_attach), 585 DEVMETHOD(device_detach, aml8726_scu_detach), 586 587 DEVMETHOD_END 588}; 589 590static driver_t aml8726_scu_driver = { 591 "scu", 592 aml8726_scu_methods, 593 sizeof(struct aml8726_scu_softc), 594}; 595 596static devclass_t aml8726_scu_devclass; 597 598EARLY_DRIVER_MODULE(scu, simplebus, aml8726_scu_driver, aml8726_scu_devclass, 599 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); 600 601struct aml8726_cpucfg_softc { 602 device_t dev; 603}; 604 605static int 606aml8726_cpucfg_probe(device_t dev) 607{ 608 int i; 609 610 for (i = 0; cpucfg_compatible[i]; i++) 611 if (ofw_bus_is_compatible(dev, cpucfg_compatible[i])) 612 break; 613 614 if (!cpucfg_compatible[i]) 615 return (ENXIO); 616 617 device_set_desc(dev, "Amlogic CPU Config"); 618 619 return (BUS_PROBE_DEFAULT); 620} 621 622static int 623aml8726_cpucfg_attach(device_t dev) 624{ 625 struct aml8726_cpucfg_softc *sc = device_get_softc(dev); 626 627 sc->dev = dev; 628 629 return (0); 630} 631 632static int 633aml8726_cpucfg_detach(device_t dev) 634{ 635 636 return (0); 637} 638 639static device_method_t aml8726_cpucfg_methods[] = { 640 /* Device interface */ 641 DEVMETHOD(device_probe, aml8726_cpucfg_probe), 642 DEVMETHOD(device_attach, aml8726_cpucfg_attach), 643 DEVMETHOD(device_detach, aml8726_cpucfg_detach), 644 645 DEVMETHOD_END 646}; 647 648static driver_t aml8726_cpucfg_driver = { 649 "cpuconfig", 650 aml8726_cpucfg_methods, 651 sizeof(struct aml8726_cpucfg_softc), 652}; 653 654static devclass_t aml8726_cpucfg_devclass; 655 656EARLY_DRIVER_MODULE(cpuconfig, simplebus, aml8726_cpucfg_driver, 657 aml8726_cpucfg_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); 658