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