|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
| 2 | + |
| 3 | +#include <arch/defines.h> |
| 4 | +#include <bits.h> |
| 5 | +#include <debug.h> |
| 6 | +#include <kernel/thread.h> |
| 7 | +#include <platform/timer.h> |
| 8 | +#include <reg.h> |
| 9 | + |
| 10 | +#include "../cpu-boot.h" |
| 11 | + |
| 12 | +#define CPU_PWR_CTL 0x4 |
| 13 | +#define APC_PWR_GATE_CTL 0x14 |
| 14 | + |
| 15 | +#define L1_RST_DIS 0x284 |
| 16 | + |
| 17 | +#define L2_VREG_CTL 0x1c |
| 18 | +#define L2_PWR_CTL 0x14 |
| 19 | +#define L2_PWR_CTL_OVERRIDE 0xc |
| 20 | +#define L2_PWR_STATUS_L2_HS_STS_MSM8994 (BIT(9) | BIT(28)) |
| 21 | + |
| 22 | +// delay for voltage to settle on the core |
| 23 | +#define REGULATOR_SETUP_VOLTAGE_TIMEOUT 2000 |
| 24 | + |
| 25 | +/** |
| 26 | + * enum msm8994_cpu_node_mpidrs - Enum that used for mapping cores and its mpidrs |
| 27 | + */ |
| 28 | +enum msm8994_cpu_node_mpidrs { |
| 29 | + CPU0 = 0x0, |
| 30 | + CPU1 = 0x1, |
| 31 | + CPU2 = 0x2, |
| 32 | + CPU3 = 0x3, |
| 33 | + CPU4 = 0x100, |
| 34 | + CPU5 = 0x101, |
| 35 | + CPU6 = 0x102, |
| 36 | + CPU7 = 0x103, |
| 37 | +}; |
| 38 | + |
| 39 | +/** |
| 40 | + * enum msm8994_cpu_clusters - Enum that used for clusters |
| 41 | + * @first: describes little cluster |
| 42 | + * @second: describes BIG cluster |
| 43 | + */ |
| 44 | +enum msm8994_cpu_clusters { |
| 45 | + first, |
| 46 | + second, |
| 47 | +}; |
| 48 | + |
| 49 | +/** |
| 50 | + * struct msm8994_cpu_info - This struct used to describe the core values |
| 51 | + * needed to enable it |
| 52 | + * @base: this value had got from downstream dts this way: cpu@X -> qcom,acc -> reg |
| 53 | + * @cache_info: description of next-level-cache node in cpu@X |
| 54 | + */ |
| 55 | +struct msm8994_cpu_info { |
| 56 | + uint32_t base; |
| 57 | + const struct msm8994_cpu_cache_info *cache_info; |
| 58 | +}; |
| 59 | + |
| 60 | +/** |
| 61 | + * struct msm8994_cpu_cache_info - This struct used to describe cache node |
| 62 | + * (and children's) values needed to enable the cpu cache |
| 63 | + * @l2ccc_base: this value had got from downstream dts this way: l2-cache -> power-domain -> reg |
| 64 | + * @vctl_base_0: l2-cache -> power-domain -> qcom,vctl-node -> reg (first value of first tuple) |
| 65 | + * @vctl_base_1: l2-cache -> power-domain -> qcom,vctl-node -> reg (first value of second tuple) |
| 66 | + * @vctl_val: l2-cache -> power-domain -> qcom,vctl-val (may be absent, then set as 0) |
| 67 | + */ |
| 68 | +struct msm8994_cpu_cache_info { |
| 69 | + uint32_t l2ccc_base; |
| 70 | + uint32_t vctl_base_0; |
| 71 | + uint32_t vctl_base_1; |
| 72 | + uint32_t vctl_val; |
| 73 | +}; |
| 74 | + |
| 75 | +static const struct msm8994_cpu_cache_info cache_info[] = { |
| 76 | + [first] = { |
| 77 | + .l2ccc_base = 0xf900d000, |
| 78 | + .vctl_base_0 = 0xf9012000, |
| 79 | + .vctl_base_1 = 0xf900d210, |
| 80 | + .vctl_val = 0, |
| 81 | + }, |
| 82 | + [second] = { |
| 83 | + .l2ccc_base = 0xf900f000, |
| 84 | + .vctl_base_0 = 0xf9013000, |
| 85 | + .vctl_base_1 = 0xf900f210, |
| 86 | + .vctl_val = 0xb8, |
| 87 | + }, |
| 88 | +}; |
| 89 | + |
| 90 | +static const struct msm8994_cpu_info cpu_info[] = { |
| 91 | + [CPU0] = { |
| 92 | + .base = 0xf908b000, |
| 93 | + .cache_info = &cache_info[first], |
| 94 | + }, |
| 95 | + [CPU1] = { |
| 96 | + .base = 0xf909b000, |
| 97 | + .cache_info = &cache_info[first], |
| 98 | + }, |
| 99 | + [CPU2] = { |
| 100 | + .base = 0xf90ab000, |
| 101 | + .cache_info = &cache_info[first], |
| 102 | + }, |
| 103 | + [CPU3] = { |
| 104 | + .base = 0xf90bb000, |
| 105 | + .cache_info = &cache_info[first], |
| 106 | + }, |
| 107 | + [CPU4] = { |
| 108 | + .base = 0xf90cb000, |
| 109 | + .cache_info = &cache_info[second], |
| 110 | + }, |
| 111 | + [CPU5] = { |
| 112 | + .base = 0xf90db000, |
| 113 | + .cache_info = &cache_info[second], |
| 114 | + }, |
| 115 | + [CPU6] = { |
| 116 | + .base = 0xf90eb000, |
| 117 | + .cache_info = &cache_info[second], |
| 118 | + }, |
| 119 | + [CPU7] = { |
| 120 | + .base = 0xf90fb000, |
| 121 | + .cache_info = &cache_info[second], |
| 122 | + }, |
| 123 | +}; |
| 124 | + |
| 125 | +/** |
| 126 | + * msm_spm_turn_on_cpu_rail() - Power on cpu rail before turning on core |
| 127 | + * @vctl_base_0: first qcom,vctl-node reg address |
| 128 | + * @vctl_base_1: second qcom,vctl-node reg address |
| 129 | + * @vctl_val: The value to be set on the rail |
| 130 | + */ |
| 131 | +static void msm_spm_turn_on_cpu_rail(uint32_t vctl_base_0, uint32_t vctl_base_1, |
| 132 | + unsigned int vctl_val) |
| 133 | +{ |
| 134 | + if (vctl_base_1) { |
| 135 | + /* |
| 136 | + * Program Q2S to disable SPM legacy mode and ignore Q2S |
| 137 | + * channel requests. |
| 138 | + * bit[1] = qchannel_ignore = 1 |
| 139 | + * bit[2] = spm_legacy_mode = 0 |
| 140 | + */ |
| 141 | + writel(0x2, vctl_base_1); |
| 142 | + dsb(); |
| 143 | + } |
| 144 | + |
| 145 | + /* Set the CPU supply regulator voltage */ |
| 146 | + vctl_val = (vctl_val & 0xFF); |
| 147 | + writel(vctl_val, vctl_base_0 + L2_VREG_CTL); |
| 148 | + dsb(); |
| 149 | + udelay(REGULATOR_SETUP_VOLTAGE_TIMEOUT); |
| 150 | + |
| 151 | + /* Enable the CPU supply regulator*/ |
| 152 | + vctl_val = 0x30080; |
| 153 | + writel(vctl_val, vctl_base_0 + L2_VREG_CTL); |
| 154 | + dsb(); |
| 155 | + udelay(REGULATOR_SETUP_VOLTAGE_TIMEOUT); |
| 156 | +} |
| 157 | + |
| 158 | +/** |
| 159 | + * power_on_l2_cache_msm8994() - This function used to enable l2 cache |
| 160 | + * @l2ccc_base: value of l2 clock controller reg |
| 161 | + * @vctl_base_0: first qcom,vctl-node reg address |
| 162 | + * @vctl_base_1: second qcom,vctl-node reg address |
| 163 | + * @vctl_val: The value to be set on the rail |
| 164 | + * |
| 165 | + * As l2 cache for first(boot) cluster enabled by lk1st, |
| 166 | + * this function skips it and work only for second cluster |
| 167 | + * Function has a check if cache at @l2ccc_base already enabled |
| 168 | + */ |
| 169 | +static void power_on_l2_cache_msm8994(uint32_t l2ccc_base, uint32_t vctl_base_0, |
| 170 | + uint32_t vctl_base_1, uint32_t vctl_val) { |
| 171 | + /* Skip if cluster L2 is already powered on */ |
| 172 | + if (readl(l2ccc_base + L2_PWR_CTL) & L2_PWR_STATUS_L2_HS_STS_MSM8994) |
| 173 | + return; |
| 174 | + |
| 175 | + dprintf(INFO, "Powering on L2 cache @ %#08x\n", l2ccc_base); |
| 176 | + |
| 177 | + if(vctl_val != 0) { |
| 178 | + dprintf(INFO, "Not found qcom,vctl-val for this l2 cache node, so skip msm_spm_turn_on_cpu_rail\n"); |
| 179 | + msm_spm_turn_on_cpu_rail(vctl_base_0, vctl_base_1, vctl_val); |
| 180 | + } |
| 181 | + |
| 182 | + enter_critical_section(); |
| 183 | + |
| 184 | + /* Enable L1 invalidation by h/w */ |
| 185 | + writel(0x00000000, l2ccc_base + L1_RST_DIS); |
| 186 | + dsb(); |
| 187 | + |
| 188 | + /* Assert PRESETDBGn */ |
| 189 | + writel(0x00400000 , l2ccc_base + L2_PWR_CTL_OVERRIDE); |
| 190 | + dsb(); |
| 191 | + |
| 192 | + /* Close L2/SCU Logic GDHS and power up the cache */ |
| 193 | + writel(0x00029716 , l2ccc_base + L2_PWR_CTL); |
| 194 | + dsb(); |
| 195 | + udelay(8); |
| 196 | + |
| 197 | + /* De-assert L2/SCU memory Clamp */ |
| 198 | + writel(0x00023716 , l2ccc_base + L2_PWR_CTL); |
| 199 | + dsb(); |
| 200 | + |
| 201 | + /* Wakeup L2/SCU RAMs by deasserting sleep signals */ |
| 202 | + writel(0x0002371E , l2ccc_base + L2_PWR_CTL); |
| 203 | + dsb(); |
| 204 | + udelay(8); |
| 205 | + |
| 206 | + /* Un-gate clock and wait for sequential waking up |
| 207 | + * of L2 rams with a delay of 2*X0 cycles |
| 208 | + */ |
| 209 | + writel(0x0002371C , l2ccc_base + L2_PWR_CTL); |
| 210 | + dsb(); |
| 211 | + udelay(4); |
| 212 | + |
| 213 | + /* De-assert L2/SCU logic clamp */ |
| 214 | + writel(0x0002361C , l2ccc_base + L2_PWR_CTL); |
| 215 | + dsb(); |
| 216 | + udelay(2); |
| 217 | + |
| 218 | + /* De-assert L2/SCU logic reset */ |
| 219 | + writel(0x00022218 , l2ccc_base + L2_PWR_CTL); |
| 220 | + dsb(); |
| 221 | + udelay(4); |
| 222 | + |
| 223 | + /* Turn on the PMIC_APC */ |
| 224 | + writel(0x10022218 , l2ccc_base + L2_PWR_CTL); |
| 225 | + dsb(); |
| 226 | + |
| 227 | + /* De-assert PRESETDBGn */ |
| 228 | + writel(0x00000000 , l2ccc_base + L2_PWR_CTL_OVERRIDE); |
| 229 | + dsb(); |
| 230 | + exit_critical_section(); |
| 231 | +} |
| 232 | + |
| 233 | +void cpu_boot_cortex_a_msm8994(uint32_t mpidr) |
| 234 | +{ |
| 235 | + uint32_t base, l2ccc_base, vctl_base_0, vctl_base_1, vctl_val; |
| 236 | + |
| 237 | + struct msm8994_cpu_info *info = &cpu_info[mpidr]; |
| 238 | + base = info->base; |
| 239 | + l2ccc_base = info->cache_info->l2ccc_base; |
| 240 | + vctl_base_0 = info->cache_info->vctl_base_0; |
| 241 | + vctl_base_1 = info->cache_info->vctl_base_1; |
| 242 | + vctl_val = info->cache_info->vctl_val; |
| 243 | + |
| 244 | + if (l2ccc_base) |
| 245 | + power_on_l2_cache_msm8994(l2ccc_base, vctl_base_0, vctl_base_1, vctl_val); |
| 246 | + |
| 247 | + enter_critical_section(); |
| 248 | + |
| 249 | + /* Assert head switch enable few */ |
| 250 | + writel(0x00000001, base + APC_PWR_GATE_CTL); |
| 251 | + dsb(); |
| 252 | + udelay(1); |
| 253 | + |
| 254 | + /* Assert head switch enable rest */ |
| 255 | + writel(0x00000003, base + APC_PWR_GATE_CTL); |
| 256 | + dsb(); |
| 257 | + udelay(1); |
| 258 | + |
| 259 | + /* De-assert coremem clamp. This is asserted by default */ |
| 260 | + writel(0x00000079, base + CPU_PWR_CTL); |
| 261 | + dsb(); |
| 262 | + udelay(2); |
| 263 | + |
| 264 | + /* Close coremem array gdhs */ |
| 265 | + writel(0x0000007D, base + CPU_PWR_CTL); |
| 266 | + dsb(); |
| 267 | + udelay(2); |
| 268 | + |
| 269 | + /* De-assert clamp */ |
| 270 | + writel(0x0000003D, base + CPU_PWR_CTL); |
| 271 | + dsb(); |
| 272 | + |
| 273 | + /* De-assert clamp */ |
| 274 | + writel(0x0000003C, base + CPU_PWR_CTL); |
| 275 | + dsb(); |
| 276 | + udelay(1); |
| 277 | + |
| 278 | + /* De-assert core0 reset */ |
| 279 | + writel(0x0000000C, base + CPU_PWR_CTL); |
| 280 | + dsb(); |
| 281 | + |
| 282 | + /* Assert PWRDUP */ |
| 283 | + writel(0x0000008C, base + CPU_PWR_CTL); |
| 284 | + dsb(); |
| 285 | + |
| 286 | + exit_critical_section(); |
| 287 | +} |
0 commit comments