1 /* 2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 9 #include <platform_def.h> 10 11 #include <arch_helpers.h> 12 #include <lib/mmio.h> 13 #include <plat/common/platform.h> 14 15 #include <../hikey960_def.h> 16 #include <hisi_ipc.h> 17 #include "hisi_pwrc.h" 18 19 20 /* resource lock api */ 21 #define RES0_LOCK_BASE (SOC_PCTRL_RESOURCE0_LOCK_ADDR(PCTRL_BASE)) 22 #define RES1_LOCK_BASE (SOC_PCTRL_RESOURCE1_LOCK_ADDR(PCTRL_BASE)) 23 #define RES2_LOCK_BASE (SOC_PCTRL_RESOURCE2_LOCK_ADDR(PCTRL_BASE)) 24 25 #define LOCK_BIT (0x1 << 28) 26 #define LOCK_ID_MASK (0x7 << 29) 27 #define CPUIDLE_LOCK_ID(core) (0x6 - (core)) 28 #define LOCK_UNLOCK_OFFSET 0x4 29 #define LOCK_STAT_OFFSET 0x8 30 31 #define CLUSTER0_CPUS_ONLINE_MASK (0xF << 16) 32 #define CLUSTER1_CPUS_ONLINE_MASK (0xF << 20) 33 34 /* cpu hotplug flag api */ 35 #define SCTRL_BASE (SOC_ACPU_SCTRL_BASE_ADDR) 36 #define REG_SCBAKDATA3_OFFSET (SOC_SCTRL_SCBAKDATA3_ADDR(SCTRL_BASE)) 37 #define REG_SCBAKDATA8_OFFSET (SOC_SCTRL_SCBAKDATA8_ADDR(SCTRL_BASE)) 38 #define REG_SCBAKDATA9_OFFSET (SOC_SCTRL_SCBAKDATA9_ADDR(SCTRL_BASE)) 39 40 #define CPUIDLE_FLAG_REG(cluster) \ 41 ((cluster == 0) ? REG_SCBAKDATA8_OFFSET : \ 42 REG_SCBAKDATA9_OFFSET) 43 #define CLUSTER_IDLE_BIT BIT(8) 44 #define CLUSTER_IDLE_MASK (CLUSTER_IDLE_BIT | 0x0F) 45 46 #define AP_SUSPEND_FLAG (1 << 16) 47 48 #define CLUSTER_PWDN_IDLE (0<<28) 49 #define CLUSTER_PWDN_HOTPLUG (1<<28) 50 #define CLUSTER_PWDN_SR (2<<28) 51 52 #define CLUSTER0_PDC_OFFSET 0x260 53 #define CLUSTER1_PDC_OFFSET 0x300 54 55 #define PDC_EN_OFFSET 0x0 56 #define PDC_COREPWRINTEN_OFFSET 0x4 57 #define PDC_COREPWRINTSTAT_OFFSET 0x8 58 #define PDC_COREGICMASK_OFFSET 0xc 59 #define PDC_COREPOWERUP_OFFSET 0x10 60 #define PDC_COREPOWERDN_OFFSET 0x14 61 #define PDC_COREPOWERSTAT_OFFSET 0x18 62 63 #define PDC_COREPWRSTAT_MASK (0XFFFF) 64 65 enum pdc_gic_mask { 66 PDC_MASK_GIC_WAKE_IRQ, 67 PDC_UNMASK_GIC_WAKE_IRQ 68 }; 69 70 enum pdc_finish_int_mask { 71 PDC_DISABLE_FINISH_INT, 72 PDC_ENABLE_FINISH_INT 73 }; 74 75 static void hisi_resource_lock(unsigned int lockid, unsigned int offset) 76 { 77 unsigned int lock_id = (lockid << 29); 78 unsigned int lock_val = lock_id | LOCK_BIT; 79 unsigned int lock_state; 80 81 do { 82 mmio_write_32(offset, lock_val); 83 lock_state = mmio_read_32(LOCK_STAT_OFFSET + (uintptr_t)offset); 84 } while ((lock_state & LOCK_ID_MASK) != lock_id); 85 } 86 87 static void hisi_resource_unlock(unsigned int lockid, unsigned int offset) 88 { 89 unsigned int lock_val = (lockid << 29) | LOCK_BIT; 90 91 mmio_write_32((LOCK_UNLOCK_OFFSET + (uintptr_t)offset), lock_val); 92 } 93 94 95 static void hisi_cpuhotplug_lock(unsigned int cluster, unsigned int core) 96 { 97 unsigned int lock_id; 98 99 lock_id = (cluster << 2) + core; 100 101 hisi_resource_lock(lock_id, RES2_LOCK_BASE); 102 } 103 104 static void hisi_cpuhotplug_unlock(unsigned int cluster, unsigned int core) 105 { 106 unsigned int lock_id; 107 108 lock_id = (cluster << 2) + core; 109 110 hisi_resource_unlock(lock_id, RES2_LOCK_BASE); 111 } 112 113 /* get the resource lock */ 114 void hisi_cpuidle_lock(unsigned int cluster, unsigned int core) 115 { 116 unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE); 117 118 hisi_resource_lock(CPUIDLE_LOCK_ID(core), offset); 119 } 120 121 /* release the resource lock */ 122 void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core) 123 { 124 unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE); 125 126 hisi_resource_unlock(CPUIDLE_LOCK_ID(core), offset); 127 } 128 129 unsigned int hisi_get_cpuidle_flag(unsigned int cluster) 130 { 131 unsigned int val; 132 133 val = mmio_read_32(CPUIDLE_FLAG_REG(cluster)); 134 val &= 0xF; 135 136 return val; 137 } 138 139 void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core) 140 { 141 mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core)); 142 } 143 144 void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core) 145 { 146 mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core)); 147 148 } 149 150 int hisi_test_ap_suspend_flag(unsigned int cluster) 151 { 152 unsigned int val; 153 154 val = mmio_read_32(CPUIDLE_FLAG_REG(cluster)); 155 val &= AP_SUSPEND_FLAG; 156 return !!val; 157 } 158 159 void hisi_set_cluster_pwdn_flag(unsigned int cluster, 160 unsigned int core, unsigned int value) 161 { 162 unsigned int val; 163 164 hisi_cpuhotplug_lock(cluster, core); 165 166 val = mmio_read_32(REG_SCBAKDATA3_OFFSET); 167 val = (value << (cluster << 1)) | (val & 0xFFFFFFF); 168 mmio_write_32(REG_SCBAKDATA3_OFFSET, val); 169 170 hisi_cpuhotplug_unlock(cluster, core); 171 } 172 173 unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core) 174 { 175 unsigned int val; 176 177 hisi_cpuhotplug_lock(cluster, core); 178 val = mmio_read_32(REG_SCBAKDATA3_OFFSET); 179 val = val >> (16 + (cluster << 2)); 180 val &= 0xF; 181 hisi_cpuhotplug_unlock(cluster, core); 182 183 return val; 184 } 185 186 unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core) 187 { 188 unsigned int val; 189 190 hisi_cpuhotplug_lock(cluster, core); 191 val = mmio_read_32(REG_SCBAKDATA3_OFFSET); 192 val = val >> (16 + (cluster << 2)); 193 val &= 0xF; 194 hisi_cpuhotplug_unlock(cluster, core); 195 196 if (val) 197 return 0; 198 else 199 return 1; 200 } 201 202 void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core) 203 { 204 unsigned int flag = BIT((cluster<<2) + core + 16); 205 206 hisi_cpuhotplug_lock(cluster, core); 207 208 mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag); 209 210 hisi_cpuhotplug_unlock(cluster, core); 211 } 212 213 void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core) 214 { 215 unsigned int flag = BIT((cluster<<2) + core + 16); 216 217 hisi_cpuhotplug_lock(cluster, core); 218 219 mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag); 220 221 hisi_cpuhotplug_unlock(cluster, core); 222 } 223 224 int cluster_is_powered_on(unsigned int cluster) 225 { 226 unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET); 227 int ret; 228 229 if (cluster == 0) 230 ret = val & CLUSTER0_CPUS_ONLINE_MASK; 231 else 232 ret = val & CLUSTER1_CPUS_ONLINE_MASK; 233 234 return !!ret; 235 } 236 237 static void *hisi_get_pdc_addr(unsigned int cluster) 238 { 239 void *pdc_base_addr; 240 uintptr_t addr; 241 242 if (cluster == 0) 243 addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE); 244 else 245 addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE); 246 pdc_base_addr = (void *)addr; 247 248 return pdc_base_addr; 249 } 250 251 static unsigned int hisi_get_pdc_stat(unsigned int cluster) 252 { 253 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 254 unsigned int val; 255 256 val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET); 257 258 return val; 259 } 260 261 int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core) 262 { 263 unsigned int mask = 0xf << (core * 4); 264 unsigned int pdc_stat = hisi_get_pdc_stat(cluster); 265 unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core); 266 unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster); 267 268 mask = (PDC_COREPWRSTAT_MASK & (~mask)); 269 pdc_stat &= mask; 270 271 if ((boot_flag ^ cpuidle_flag) || pdc_stat) 272 return 0; 273 else 274 return 1; 275 } 276 277 void hisi_disable_pdc(unsigned int cluster) 278 { 279 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 280 281 mmio_write_32((uintptr_t)pdc_base_addr, 0x0); 282 } 283 284 void hisi_enable_pdc(unsigned int cluster) 285 { 286 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 287 288 mmio_write_32((uintptr_t)pdc_base_addr, 0x1); 289 } 290 291 void hisi_pdc_set_intmask(void *pdc_base_addr, 292 unsigned int core, 293 enum pdc_finish_int_mask intmask) 294 { 295 unsigned int val; 296 297 val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET); 298 if (intmask == PDC_ENABLE_FINISH_INT) 299 val |= BIT(core); 300 else 301 val &= ~BIT(core); 302 303 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val); 304 } 305 306 static inline void hisi_pdc_set_gicmask(void *pdc_base_addr, 307 unsigned int core, 308 enum pdc_gic_mask gicmask) 309 { 310 unsigned int val; 311 312 val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET); 313 if (gicmask == PDC_MASK_GIC_WAKE_IRQ) 314 val |= BIT(core); 315 else 316 val &= ~BIT(core); 317 318 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val); 319 } 320 321 void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster) 322 { 323 int i; 324 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 325 326 for (i = 0; i < 4; i++) 327 hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ); 328 } 329 330 static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core, 331 enum pdc_gic_mask gicmask, 332 enum pdc_finish_int_mask intmask) 333 { 334 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 335 336 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET, 337 BIT(core)); 338 } 339 340 static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core, 341 enum pdc_gic_mask gicmask, 342 enum pdc_finish_int_mask intmask) 343 { 344 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 345 346 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET, 347 BIT(core)); 348 } 349 350 void hisi_powerup_core(unsigned int cluster, unsigned int core) 351 { 352 hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ, 353 PDC_DISABLE_FINISH_INT); 354 } 355 356 void hisi_powerdn_core(unsigned int cluster, unsigned int core) 357 { 358 hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ, 359 PDC_DISABLE_FINISH_INT); 360 } 361 362 void hisi_powerup_cluster(unsigned int cluster, unsigned int core) 363 { 364 hisi_ipc_pm_on_off(core, cluster, PM_ON); 365 } 366 367 void hisi_powerdn_cluster(unsigned int cluster, unsigned int core) 368 { 369 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 370 371 hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG); 372 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, 373 (0x10001 << core)); 374 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET, 375 BIT(core)); 376 } 377 378 void hisi_enter_core_idle(unsigned int cluster, unsigned int core) 379 { 380 hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ, 381 PDC_DISABLE_FINISH_INT); 382 } 383 384 void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core) 385 { 386 void *pdc_base_addr = hisi_get_pdc_addr(cluster); 387 388 hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE); 389 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, 390 (0x10001 << core)); 391 mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET, 392 BIT(core)); 393 } 394 395 void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core) 396 { 397 hisi_ipc_pm_suspend(core, cluster, 0x3); 398 } 399