1*d3514c29SAdrian Chadd /*- 2*d3514c29SAdrian Chadd * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*d3514c29SAdrian Chadd * 4*d3514c29SAdrian Chadd * Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org> 5*d3514c29SAdrian Chadd * 6*d3514c29SAdrian Chadd * Redistribution and use in source and binary forms, with or without 7*d3514c29SAdrian Chadd * modification, are permitted provided that the following conditions 8*d3514c29SAdrian Chadd * are met: 9*d3514c29SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 10*d3514c29SAdrian Chadd * notice, this list of conditions and the following disclaimer. 11*d3514c29SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 12*d3514c29SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 13*d3514c29SAdrian Chadd * documentation and/or other materials provided with the distribution. 14*d3514c29SAdrian Chadd * 15*d3514c29SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*d3514c29SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*d3514c29SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*d3514c29SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*d3514c29SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*d3514c29SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*d3514c29SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*d3514c29SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*d3514c29SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*d3514c29SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*d3514c29SAdrian Chadd * SUCH DAMAGE. 26*d3514c29SAdrian Chadd */ 27*d3514c29SAdrian Chadd 28*d3514c29SAdrian Chadd #include "opt_platform.h" 29*d3514c29SAdrian Chadd 30*d3514c29SAdrian Chadd #include <sys/cdefs.h> 31*d3514c29SAdrian Chadd __FBSDID("$FreeBSD$"); 32*d3514c29SAdrian Chadd 33*d3514c29SAdrian Chadd #include <sys/param.h> 34*d3514c29SAdrian Chadd #include <sys/systm.h> 35*d3514c29SAdrian Chadd #include <sys/bus.h> 36*d3514c29SAdrian Chadd #include <sys/reboot.h> 37*d3514c29SAdrian Chadd #include <sys/devmap.h> 38*d3514c29SAdrian Chadd #include <sys/smp.h> 39*d3514c29SAdrian Chadd 40*d3514c29SAdrian Chadd #include <vm/vm.h> 41*d3514c29SAdrian Chadd 42*d3514c29SAdrian Chadd #include <machine/cpu.h> 43*d3514c29SAdrian Chadd #include <machine/bus.h> 44*d3514c29SAdrian Chadd #include <machine/intr.h> 45*d3514c29SAdrian Chadd #include <machine/machdep.h> 46*d3514c29SAdrian Chadd #include <machine/platformvar.h> 47*d3514c29SAdrian Chadd #include <machine/smp.h> 48*d3514c29SAdrian Chadd 49*d3514c29SAdrian Chadd #include <dev/fdt/fdt_common.h> 50*d3514c29SAdrian Chadd #include <dev/ofw/openfirm.h> 51*d3514c29SAdrian Chadd #include <dev/ofw/ofw_cpu.h> 52*d3514c29SAdrian Chadd 53*d3514c29SAdrian Chadd #include <arm/qualcomm/qcom_cpu_kpssv2_reg.h> 54*d3514c29SAdrian Chadd #include <arm/qualcomm/qcom_cpu_kpssv2.h> 55*d3514c29SAdrian Chadd 56*d3514c29SAdrian Chadd #include "platform_if.h" 57*d3514c29SAdrian Chadd 58*d3514c29SAdrian Chadd /* 59*d3514c29SAdrian Chadd * Since DELAY() hangs this early, we need some way to 60*d3514c29SAdrian Chadd * delay things to settle. 61*d3514c29SAdrian Chadd */ 62*d3514c29SAdrian Chadd static inline void 63*d3514c29SAdrian Chadd loop_delay(int usec) 64*d3514c29SAdrian Chadd { 65*d3514c29SAdrian Chadd int lcount = usec * 100000; 66*d3514c29SAdrian Chadd 67*d3514c29SAdrian Chadd for (volatile int i = 0; i < lcount; i++) 68*d3514c29SAdrian Chadd ; 69*d3514c29SAdrian Chadd } 70*d3514c29SAdrian Chadd 71*d3514c29SAdrian Chadd /* 72*d3514c29SAdrian Chadd * This is the KPSSv2 (eg IPQ4018) regulator path for CPU 73*d3514c29SAdrian Chadd * and shared L2 cache power-on. 74*d3514c29SAdrian Chadd */ 75*d3514c29SAdrian Chadd boolean_t 76*d3514c29SAdrian Chadd qcom_cpu_kpssv2_regulator_start(u_int id, phandle_t node) 77*d3514c29SAdrian Chadd { 78*d3514c29SAdrian Chadd phandle_t acc_phandle, l2_phandle, saw_phandle; 79*d3514c29SAdrian Chadd bus_space_tag_t acc_tag, saw_tag; 80*d3514c29SAdrian Chadd bus_space_handle_t acc_handle, saw_handle; 81*d3514c29SAdrian Chadd bus_size_t acc_sz, saw_sz; 82*d3514c29SAdrian Chadd ssize_t sret; 83*d3514c29SAdrian Chadd int ret; 84*d3514c29SAdrian Chadd uint32_t reg_val; 85*d3514c29SAdrian Chadd 86*d3514c29SAdrian Chadd /* 87*d3514c29SAdrian Chadd * We don't need to power up CPU 0! This will power it 88*d3514c29SAdrian Chadd * down first and ... then everything hangs. 89*d3514c29SAdrian Chadd */ 90*d3514c29SAdrian Chadd if (id == 0) 91*d3514c29SAdrian Chadd return true; 92*d3514c29SAdrian Chadd 93*d3514c29SAdrian Chadd /* 94*d3514c29SAdrian Chadd * Walk the qcom,acc and next-level-cache entries to find their 95*d3514c29SAdrian Chadd * child phandles and thus regulators. 96*d3514c29SAdrian Chadd * 97*d3514c29SAdrian Chadd * The qcom,acc is a phandle to a node. 98*d3514c29SAdrian Chadd * 99*d3514c29SAdrian Chadd * The next-level-cache actually is a phandle through to a qcom,saw 100*d3514c29SAdrian Chadd * entry. 101*d3514c29SAdrian Chadd */ 102*d3514c29SAdrian Chadd sret = OF_getencprop(node, "qcom,acc", (void *) &acc_phandle, 103*d3514c29SAdrian Chadd sizeof(acc_phandle)); 104*d3514c29SAdrian Chadd if (sret != sizeof(acc_phandle)) 105*d3514c29SAdrian Chadd panic("***couldn't get phandle for qcom,acc"); 106*d3514c29SAdrian Chadd acc_phandle = OF_node_from_xref(acc_phandle); 107*d3514c29SAdrian Chadd 108*d3514c29SAdrian Chadd sret = OF_getencprop(node, "next-level-cache", (void *) &l2_phandle, 109*d3514c29SAdrian Chadd sizeof(l2_phandle)); 110*d3514c29SAdrian Chadd if (sret != sizeof(l2_phandle)) 111*d3514c29SAdrian Chadd panic("***couldn't get phandle for next-level-cache"); 112*d3514c29SAdrian Chadd l2_phandle = OF_node_from_xref(l2_phandle); 113*d3514c29SAdrian Chadd 114*d3514c29SAdrian Chadd sret = OF_getencprop(l2_phandle, "qcom,saw", (void *) &saw_phandle, 115*d3514c29SAdrian Chadd sizeof(saw_phandle)); 116*d3514c29SAdrian Chadd if (sret != sizeof(saw_phandle)) 117*d3514c29SAdrian Chadd panic("***couldn't get phandle for qcom,saw"); 118*d3514c29SAdrian Chadd l2_phandle = OF_node_from_xref(l2_phandle); 119*d3514c29SAdrian Chadd 120*d3514c29SAdrian Chadd /* 121*d3514c29SAdrian Chadd * Now that we have the phandles referencing the correct locations, 122*d3514c29SAdrian Chadd * do some KVA mappings so we can go access the registers. 123*d3514c29SAdrian Chadd */ 124*d3514c29SAdrian Chadd ret = OF_decode_addr(acc_phandle, 0, &acc_tag, &acc_handle, &acc_sz); 125*d3514c29SAdrian Chadd if (ret != 0) 126*d3514c29SAdrian Chadd panic("*** couldn't map qcom,acc space (%d)", ret); 127*d3514c29SAdrian Chadd ret = OF_decode_addr(saw_phandle, 0, &saw_tag, &saw_handle, &saw_sz); 128*d3514c29SAdrian Chadd if (ret != 0) 129*d3514c29SAdrian Chadd panic("*** couldn't map next-level-cache -> " 130*d3514c29SAdrian Chadd "qcom,saw space (%d)", ret); 131*d3514c29SAdrian Chadd 132*d3514c29SAdrian Chadd /* 133*d3514c29SAdrian Chadd * Power sequencing to ensure the cores are off, then power them on 134*d3514c29SAdrian Chadd * and bring them out of reset. 135*d3514c29SAdrian Chadd */ 136*d3514c29SAdrian Chadd 137*d3514c29SAdrian Chadd /* 138*d3514c29SAdrian Chadd * BHS: off 139*d3514c29SAdrian Chadd * LDO: bypassed, powered off 140*d3514c29SAdrian Chadd */ 141*d3514c29SAdrian Chadd reg_val = (64 << QCOM_APC_PWR_GATE_CTL_BHS_CNT_SHIFT) 142*d3514c29SAdrian Chadd | (0x3f << QCOM_APC_PWR_GATE_CTL_LDO_PWR_DWN_SHIFT) 143*d3514c29SAdrian Chadd | QCOM_APC_PWR_GATE_CTL_BHS_EN; 144*d3514c29SAdrian Chadd bus_space_write_4(acc_tag, acc_handle, QCOM_APC_PWR_GATE_CTL, reg_val); 145*d3514c29SAdrian Chadd mb(); 146*d3514c29SAdrian Chadd /* Settle time */ 147*d3514c29SAdrian Chadd loop_delay(1); 148*d3514c29SAdrian Chadd 149*d3514c29SAdrian Chadd /* 150*d3514c29SAdrian Chadd * Start up BHS segments. 151*d3514c29SAdrian Chadd */ 152*d3514c29SAdrian Chadd reg_val |= 0x3f << QCOM_APC_PWR_GATE_CTL_BHS_SEG_SHIFT; 153*d3514c29SAdrian Chadd bus_space_write_4(acc_tag, acc_handle, QCOM_APC_PWR_GATE_CTL, reg_val); 154*d3514c29SAdrian Chadd mb(); 155*d3514c29SAdrian Chadd /* Settle time */ 156*d3514c29SAdrian Chadd loop_delay(1); 157*d3514c29SAdrian Chadd 158*d3514c29SAdrian Chadd /* 159*d3514c29SAdrian Chadd * Switch on the LDO bypass; BHS will now supply power. 160*d3514c29SAdrian Chadd */ 161*d3514c29SAdrian Chadd reg_val |= 0x3f << QCOM_APC_PWR_GATE_CTL_LDO_BYP_SHIFT; 162*d3514c29SAdrian Chadd bus_space_write_4(acc_tag, acc_handle, QCOM_APC_PWR_GATE_CTL, reg_val); 163*d3514c29SAdrian Chadd 164*d3514c29SAdrian Chadd /* 165*d3514c29SAdrian Chadd * Shared L2 regulator control. 166*d3514c29SAdrian Chadd */ 167*d3514c29SAdrian Chadd bus_space_write_4(saw_tag, saw_handle, QCOM_APCS_SAW2_2_VCTL, 0x10003); 168*d3514c29SAdrian Chadd mb(); 169*d3514c29SAdrian Chadd /* Settle time */ 170*d3514c29SAdrian Chadd loop_delay(50); 171*d3514c29SAdrian Chadd 172*d3514c29SAdrian Chadd /* 173*d3514c29SAdrian Chadd * Put the core in reset. 174*d3514c29SAdrian Chadd */ 175*d3514c29SAdrian Chadd reg_val = QCOM_APCS_CPU_PWR_CTL_COREPOR_RST 176*d3514c29SAdrian Chadd | QCOM_APCS_CPU_PWR_CTL_CLAMP; 177*d3514c29SAdrian Chadd bus_space_write_4(acc_tag, acc_handle, QCOM_APCS_CPU_PWR_CTL, reg_val); 178*d3514c29SAdrian Chadd mb(); 179*d3514c29SAdrian Chadd loop_delay(2); 180*d3514c29SAdrian Chadd 181*d3514c29SAdrian Chadd /* 182*d3514c29SAdrian Chadd * Remove power-down clamp. 183*d3514c29SAdrian Chadd */ 184*d3514c29SAdrian Chadd reg_val &= ~QCOM_APCS_CPU_PWR_CTL_CLAMP; 185*d3514c29SAdrian Chadd bus_space_write_4(acc_tag, acc_handle, QCOM_APCS_CPU_PWR_CTL, reg_val); 186*d3514c29SAdrian Chadd mb(); 187*d3514c29SAdrian Chadd loop_delay(2); 188*d3514c29SAdrian Chadd 189*d3514c29SAdrian Chadd /* 190*d3514c29SAdrian Chadd * Clear core power reset. 191*d3514c29SAdrian Chadd */ 192*d3514c29SAdrian Chadd reg_val &= ~QCOM_APCS_CPU_PWR_CTL_COREPOR_RST; 193*d3514c29SAdrian Chadd bus_space_write_4(acc_tag, acc_handle, QCOM_APCS_CPU_PWR_CTL, reg_val); 194*d3514c29SAdrian Chadd mb(); 195*d3514c29SAdrian Chadd 196*d3514c29SAdrian Chadd /* 197*d3514c29SAdrian Chadd * The power is ready, the core is out of reset, signal the core 198*d3514c29SAdrian Chadd * to power up. 199*d3514c29SAdrian Chadd */ 200*d3514c29SAdrian Chadd reg_val |= QCOM_APCS_CPU_PWR_CTL_CORE_PWRD_UP; 201*d3514c29SAdrian Chadd bus_space_write_4(acc_tag, acc_handle, QCOM_APCS_CPU_PWR_CTL, reg_val); 202*d3514c29SAdrian Chadd mb(); 203*d3514c29SAdrian Chadd 204*d3514c29SAdrian Chadd /* 205*d3514c29SAdrian Chadd * Finished with these KVA mappings, so release them. 206*d3514c29SAdrian Chadd */ 207*d3514c29SAdrian Chadd bus_space_unmap(acc_tag, acc_handle, acc_sz); 208*d3514c29SAdrian Chadd bus_space_unmap(saw_tag, saw_handle, saw_sz); 209*d3514c29SAdrian Chadd 210*d3514c29SAdrian Chadd return true; 211*d3514c29SAdrian Chadd } 212