18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights 38c2ecf20Sopenharmony_ci * reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 68c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 78c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 88c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the NetLogic 98c2ecf20Sopenharmony_ci * license below: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 128c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 138c2ecf20Sopenharmony_ci * are met: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 168c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 178c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 188c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 198c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 208c2ecf20Sopenharmony_ci * distribution. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR 238c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 248c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 258c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE 268c2ecf20Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 278c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 288c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 298c2ecf20Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 308c2ecf20Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 318c2ecf20Sopenharmony_ci * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 328c2ecf20Sopenharmony_ci * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/kernel.h> 368c2ecf20Sopenharmony_ci#include <linux/threads.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <asm/asm.h> 398c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h> 408c2ecf20Sopenharmony_ci#include <asm/mipsregs.h> 418c2ecf20Sopenharmony_ci#include <asm/addrspace.h> 428c2ecf20Sopenharmony_ci#include <asm/string.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <asm/netlogic/haldefs.h> 458c2ecf20Sopenharmony_ci#include <asm/netlogic/common.h> 468c2ecf20Sopenharmony_ci#include <asm/netlogic/mips-extns.h> 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#include <asm/netlogic/xlp-hal/iomap.h> 498c2ecf20Sopenharmony_ci#include <asm/netlogic/xlp-hal/xlp.h> 508c2ecf20Sopenharmony_ci#include <asm/netlogic/xlp-hal/pic.h> 518c2ecf20Sopenharmony_ci#include <asm/netlogic/xlp-hal/sys.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int xlp_wakeup_core(uint64_t sysbase, int node, int core) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci uint32_t coremask, value; 568c2ecf20Sopenharmony_ci int count, resetreg; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci coremask = (1 << core); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* Enable CPU clock in case of 8xx/3xx */ 618c2ecf20Sopenharmony_ci if (!cpu_is_xlpii()) { 628c2ecf20Sopenharmony_ci value = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL); 638c2ecf20Sopenharmony_ci value &= ~coremask; 648c2ecf20Sopenharmony_ci nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, value); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* On 9XX, mark coherent first */ 688c2ecf20Sopenharmony_ci if (cpu_is_xlp9xx()) { 698c2ecf20Sopenharmony_ci value = nlm_read_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE); 708c2ecf20Sopenharmony_ci value &= ~coremask; 718c2ecf20Sopenharmony_ci nlm_write_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE, value); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Remove CPU Reset */ 758c2ecf20Sopenharmony_ci resetreg = cpu_is_xlp9xx() ? SYS_9XX_CPU_RESET : SYS_CPU_RESET; 768c2ecf20Sopenharmony_ci value = nlm_read_sys_reg(sysbase, resetreg); 778c2ecf20Sopenharmony_ci value &= ~coremask; 788c2ecf20Sopenharmony_ci nlm_write_sys_reg(sysbase, resetreg, value); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* We are done on 9XX */ 818c2ecf20Sopenharmony_ci if (cpu_is_xlp9xx()) 828c2ecf20Sopenharmony_ci return 1; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* Poll for CPU to mark itself coherent on other type of XLP */ 858c2ecf20Sopenharmony_ci count = 100000; 868c2ecf20Sopenharmony_ci do { 878c2ecf20Sopenharmony_ci value = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE); 888c2ecf20Sopenharmony_ci } while ((value & coremask) != 0 && --count > 0); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return count != 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int wait_for_cpus(int cpu, int bootcpu) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci volatile uint32_t *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY); 968c2ecf20Sopenharmony_ci int i, count, notready; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci count = 0x800000; 998c2ecf20Sopenharmony_ci do { 1008c2ecf20Sopenharmony_ci notready = nlm_threads_per_core; 1018c2ecf20Sopenharmony_ci for (i = 0; i < nlm_threads_per_core; i++) 1028c2ecf20Sopenharmony_ci if (cpu_ready[cpu + i] || (cpu + i) == bootcpu) 1038c2ecf20Sopenharmony_ci --notready; 1048c2ecf20Sopenharmony_ci } while (notready != 0 && --count > 0); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return count != 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct nlm_soc_info *nodep; 1128c2ecf20Sopenharmony_ci uint64_t syspcibase, fusebase; 1138c2ecf20Sopenharmony_ci uint32_t syscoremask, mask, fusemask; 1148c2ecf20Sopenharmony_ci int core, n, cpu, ncores; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci for (n = 0; n < NLM_NR_NODES; n++) { 1178c2ecf20Sopenharmony_ci if (n != 0) { 1188c2ecf20Sopenharmony_ci /* check if node exists and is online */ 1198c2ecf20Sopenharmony_ci if (cpu_is_xlp9xx()) { 1208c2ecf20Sopenharmony_ci int b = xlp9xx_get_socbus(n); 1218c2ecf20Sopenharmony_ci pr_info("Node %d SoC PCI bus %d.\n", n, b); 1228c2ecf20Sopenharmony_ci if (b == 0) 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci } else { 1258c2ecf20Sopenharmony_ci syspcibase = nlm_get_sys_pcibase(n); 1268c2ecf20Sopenharmony_ci if (nlm_read_reg(syspcibase, 0) == 0xffffffff) 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci nlm_node_init(n); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* read cores in reset from SYS */ 1338c2ecf20Sopenharmony_ci nodep = nlm_get_node(n); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (cpu_is_xlp9xx()) { 1368c2ecf20Sopenharmony_ci fusebase = nlm_get_fuse_regbase(n); 1378c2ecf20Sopenharmony_ci fusemask = nlm_read_reg(fusebase, FUSE_9XX_DEVCFG6); 1388c2ecf20Sopenharmony_ci switch (read_c0_prid() & PRID_IMP_MASK) { 1398c2ecf20Sopenharmony_ci case PRID_IMP_NETLOGIC_XLP5XX: 1408c2ecf20Sopenharmony_ci mask = 0xff; 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci case PRID_IMP_NETLOGIC_XLP9XX: 1438c2ecf20Sopenharmony_ci default: 1448c2ecf20Sopenharmony_ci mask = 0xfffff; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci } else { 1488c2ecf20Sopenharmony_ci fusemask = nlm_read_sys_reg(nodep->sysbase, 1498c2ecf20Sopenharmony_ci SYS_EFUSE_DEVICE_CFG_STATUS0); 1508c2ecf20Sopenharmony_ci switch (read_c0_prid() & PRID_IMP_MASK) { 1518c2ecf20Sopenharmony_ci case PRID_IMP_NETLOGIC_XLP3XX: 1528c2ecf20Sopenharmony_ci mask = 0xf; 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci case PRID_IMP_NETLOGIC_XLP2XX: 1558c2ecf20Sopenharmony_ci mask = 0x3; 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case PRID_IMP_NETLOGIC_XLP8XX: 1588c2ecf20Sopenharmony_ci default: 1598c2ecf20Sopenharmony_ci mask = 0xff; 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* 1658c2ecf20Sopenharmony_ci * Fused out cores are set in the fusemask, and the remaining 1668c2ecf20Sopenharmony_ci * cores are renumbered to range 0 .. nactive-1 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_ci syscoremask = (1 << hweight32(~fusemask & mask)) - 1; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci pr_info("Node %d - SYS/FUSE coremask %x\n", n, syscoremask); 1718c2ecf20Sopenharmony_ci ncores = nlm_cores_per_node(); 1728c2ecf20Sopenharmony_ci for (core = 0; core < ncores; core++) { 1738c2ecf20Sopenharmony_ci /* we will be on node 0 core 0 */ 1748c2ecf20Sopenharmony_ci if (n == 0 && core == 0) 1758c2ecf20Sopenharmony_ci continue; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* see if the core exists */ 1788c2ecf20Sopenharmony_ci if ((syscoremask & (1 << core)) == 0) 1798c2ecf20Sopenharmony_ci continue; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* see if at least the first hw thread is enabled */ 1828c2ecf20Sopenharmony_ci cpu = (n * ncores + core) * NLM_THREADS_PER_CORE; 1838c2ecf20Sopenharmony_ci if (!cpumask_test_cpu(cpu, wakeup_mask)) 1848c2ecf20Sopenharmony_ci continue; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* wake up the core */ 1878c2ecf20Sopenharmony_ci if (!xlp_wakeup_core(nodep->sysbase, n, core)) 1888c2ecf20Sopenharmony_ci continue; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* core is up */ 1918c2ecf20Sopenharmony_ci nodep->coremask |= 1u << core; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* spin until the hw threads sets their ready */ 1948c2ecf20Sopenharmony_ci if (!wait_for_cpus(cpu, 0)) 1958c2ecf20Sopenharmony_ci pr_err("Node %d : timeout core %d\n", n, core); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_civoid xlp_wakeup_secondary_cpus(void) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * In case of u-boot, the secondaries are in reset 2048c2ecf20Sopenharmony_ci * first wakeup core 0 threads 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci xlp_boot_core0_siblings(); 2078c2ecf20Sopenharmony_ci if (!wait_for_cpus(0, 0)) 2088c2ecf20Sopenharmony_ci pr_err("Node 0 : timeout core 0\n"); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* now get other cores out of reset */ 2118c2ecf20Sopenharmony_ci xlp_enable_secondary_cores(&nlm_cpumask); 2128c2ecf20Sopenharmony_ci} 213