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