Home | History | Annotate | Download | only in spm
      1 /*
      2  * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 #include <bakery_lock.h>
      7 #include <debug.h>
      8 #include <mmio.h>
      9 #include <mt8173_def.h>
     10 #include <spm.h>
     11 #include <spm_suspend.h>
     12 
     13 /*
     14  * System Power Manager (SPM) is a hardware module, which controls cpu or
     15  * system power for different power scenarios using different firmware, i.e.,
     16  * - spm_hotplug.c for cpu power control in cpu hotplug flow.
     17  * - spm_mcdi.c for cpu power control in cpu idle power saving state.
     18  * - spm_suspend.c for system power control in system suspend scenario.
     19  *
     20  * This file provide utility functions common to hotplug, mcdi(idle), suspend
     21  * power scenarios. A bakery lock (software lock) is incoporated to protect
     22  * certain critical sections to avoid kicking different SPM firmware
     23  * concurrently.
     24  */
     25 
     26 #define SPM_SYSCLK_SETTLE       128	/* 3.9ms */
     27 
     28 DEFINE_BAKERY_LOCK(spm_lock);
     29 
     30 static int spm_hotplug_ready __section("tzfw_coherent_mem");
     31 static int spm_mcdi_ready __section("tzfw_coherent_mem");
     32 static int spm_suspend_ready __section("tzfw_coherent_mem");
     33 
     34 void spm_lock_init(void)
     35 {
     36 	bakery_lock_init(&spm_lock);
     37 }
     38 
     39 void spm_lock_get(void)
     40 {
     41 	bakery_lock_get(&spm_lock);
     42 }
     43 
     44 void spm_lock_release(void)
     45 {
     46 	bakery_lock_release(&spm_lock);
     47 }
     48 
     49 int is_mcdi_ready(void)
     50 {
     51 	return spm_mcdi_ready;
     52 }
     53 
     54 int is_hotplug_ready(void)
     55 {
     56 	return spm_hotplug_ready;
     57 }
     58 
     59 int is_suspend_ready(void)
     60 {
     61 	return spm_suspend_ready;
     62 }
     63 
     64 void set_mcdi_ready(void)
     65 {
     66 	spm_mcdi_ready = 1;
     67 	spm_hotplug_ready = 0;
     68 	spm_suspend_ready = 0;
     69 }
     70 
     71 void set_hotplug_ready(void)
     72 {
     73 	spm_mcdi_ready = 0;
     74 	spm_hotplug_ready = 1;
     75 	spm_suspend_ready = 0;
     76 }
     77 
     78 void set_suspend_ready(void)
     79 {
     80 	spm_mcdi_ready = 0;
     81 	spm_hotplug_ready = 0;
     82 	spm_suspend_ready = 1;
     83 }
     84 
     85 void clear_all_ready(void)
     86 {
     87 	spm_mcdi_ready = 0;
     88 	spm_hotplug_ready = 0;
     89 	spm_suspend_ready = 0;
     90 }
     91 
     92 void spm_register_init(void)
     93 {
     94 	mmio_write_32(SPM_POWERON_CONFIG_SET, SPM_REGWR_CFG_KEY | SPM_REGWR_EN);
     95 
     96 	mmio_write_32(SPM_POWER_ON_VAL0, 0);
     97 	mmio_write_32(SPM_POWER_ON_VAL1, POWER_ON_VAL1_DEF);
     98 	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
     99 
    100 	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_PCM_SW_RESET);
    101 	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY);
    102 	if (mmio_read_32(SPM_PCM_FSM_STA) != PCM_FSM_STA_DEF)
    103 		WARN("PCM reset failed\n");
    104 
    105 	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_IM_SLEEP_DVS);
    106 	mmio_write_32(SPM_PCM_CON1, CON1_CFG_KEY | CON1_EVENT_LOCK_EN |
    107 		CON1_SPM_SRAM_ISO_B | CON1_SPM_SRAM_SLP_B | CON1_MIF_APBEN);
    108 	mmio_write_32(SPM_PCM_IM_PTR, 0);
    109 	mmio_write_32(SPM_PCM_IM_LEN, 0);
    110 
    111 	mmio_write_32(SPM_CLK_CON, CC_SYSCLK0_EN_1 | CC_SYSCLK0_EN_0 |
    112 		CC_SYSCLK1_EN_0 | CC_SRCLKENA_MASK_0 | CC_CLKSQ1_SEL |
    113 		CC_CXO32K_RM_EN_MD2 | CC_CXO32K_RM_EN_MD1 | CC_MD32_DCM_EN);
    114 
    115 	mmio_write_32(SPM_SLEEP_ISR_MASK, 0xff0c);
    116 	mmio_write_32(SPM_SLEEP_ISR_STATUS, 0xc);
    117 	mmio_write_32(SPM_PCM_SW_INT_CLEAR, 0xff);
    118 	mmio_write_32(SPM_MD32_SRAM_CON, 0xff0);
    119 }
    120 
    121 void spm_reset_and_init_pcm(void)
    122 {
    123 	unsigned int con1;
    124 	int i = 0;
    125 
    126 	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_PCM_SW_RESET);
    127 	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY);
    128 	while (mmio_read_32(SPM_PCM_FSM_STA) != PCM_FSM_STA_DEF) {
    129 		i++;
    130 		if (i > 1000) {
    131 			i = 0;
    132 			WARN("PCM reset failed\n");
    133 			break;
    134 		}
    135 	}
    136 
    137 	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_IM_SLEEP_DVS);
    138 
    139 	con1 = mmio_read_32(SPM_PCM_CON1) &
    140 		(CON1_PCM_WDT_WAKE_MODE | CON1_PCM_WDT_EN);
    141 	mmio_write_32(SPM_PCM_CON1, con1 | CON1_CFG_KEY | CON1_EVENT_LOCK_EN |
    142 		CON1_SPM_SRAM_ISO_B | CON1_SPM_SRAM_SLP_B |
    143 		CON1_IM_NONRP_EN | CON1_MIF_APBEN);
    144 }
    145 
    146 void spm_init_pcm_register(void)
    147 {
    148 	mmio_write_32(SPM_PCM_REG_DATA_INI, mmio_read_32(SPM_POWER_ON_VAL0));
    149 	mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R0);
    150 	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
    151 
    152 	mmio_write_32(SPM_PCM_REG_DATA_INI, mmio_read_32(SPM_POWER_ON_VAL1));
    153 	mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R7);
    154 	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
    155 }
    156 
    157 void spm_set_power_control(const struct pwr_ctrl *pwrctrl)
    158 {
    159 	mmio_write_32(SPM_AP_STANBY_CON, (!pwrctrl->md32_req_mask << 21) |
    160 					 (!pwrctrl->mfg_req_mask << 17) |
    161 					 (!pwrctrl->disp_req_mask << 16) |
    162 					 (!!pwrctrl->mcusys_idle_mask << 7) |
    163 					 (!!pwrctrl->ca15top_idle_mask << 6) |
    164 					 (!!pwrctrl->ca7top_idle_mask << 5) |
    165 					 (!!pwrctrl->wfi_op << 4));
    166 	mmio_write_32(SPM_PCM_SRC_REQ, (!!pwrctrl->pcm_apsrc_req << 0));
    167 	mmio_write_32(SPM_PCM_PASR_DPD_2, 0);
    168 
    169 	mmio_clrsetbits_32(SPM_CLK_CON, CC_SRCLKENA_MASK_0,
    170 		(pwrctrl->srclkenai_mask ? CC_SRCLKENA_MASK_0 : 0));
    171 
    172 	mmio_write_32(SPM_SLEEP_CA15_WFI0_EN, !!pwrctrl->ca15_wfi0_en);
    173 	mmio_write_32(SPM_SLEEP_CA15_WFI1_EN, !!pwrctrl->ca15_wfi1_en);
    174 	mmio_write_32(SPM_SLEEP_CA15_WFI2_EN, !!pwrctrl->ca15_wfi2_en);
    175 	mmio_write_32(SPM_SLEEP_CA15_WFI3_EN, !!pwrctrl->ca15_wfi3_en);
    176 	mmio_write_32(SPM_SLEEP_CA7_WFI0_EN, !!pwrctrl->ca7_wfi0_en);
    177 	mmio_write_32(SPM_SLEEP_CA7_WFI1_EN, !!pwrctrl->ca7_wfi1_en);
    178 	mmio_write_32(SPM_SLEEP_CA7_WFI2_EN, !!pwrctrl->ca7_wfi2_en);
    179 	mmio_write_32(SPM_SLEEP_CA7_WFI3_EN, !!pwrctrl->ca7_wfi3_en);
    180 }
    181 
    182 void spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl)
    183 {
    184 	unsigned int val, mask;
    185 
    186 	if (pwrctrl->timer_val_cust == 0)
    187 		val = pwrctrl->timer_val ? pwrctrl->timer_val : PCM_TIMER_MAX;
    188 	else
    189 		val = pwrctrl->timer_val_cust;
    190 
    191 	mmio_write_32(SPM_PCM_TIMER_VAL, val);
    192 	mmio_setbits_32(SPM_PCM_CON1, CON1_CFG_KEY);
    193 
    194 	if (pwrctrl->wake_src_cust == 0)
    195 		mask = pwrctrl->wake_src;
    196 	else
    197 		mask = pwrctrl->wake_src_cust;
    198 
    199 	if (pwrctrl->syspwreq_mask)
    200 		mask &= ~WAKE_SRC_SYSPWREQ;
    201 
    202 	mmio_write_32(SPM_SLEEP_WAKEUP_EVENT_MASK, ~mask);
    203 	mmio_write_32(SPM_SLEEP_ISR_MASK, 0xfe04);
    204 }
    205 
    206 void spm_get_wakeup_status(struct wake_status *wakesta)
    207 {
    208 	wakesta->assert_pc = mmio_read_32(SPM_PCM_REG_DATA_INI);
    209 	wakesta->r12 = mmio_read_32(SPM_PCM_REG12_DATA);
    210 	wakesta->raw_sta = mmio_read_32(SPM_SLEEP_ISR_RAW_STA);
    211 	wakesta->wake_misc = mmio_read_32(SPM_SLEEP_WAKEUP_MISC);
    212 	wakesta->timer_out = mmio_read_32(SPM_PCM_TIMER_OUT);
    213 	wakesta->r13 = mmio_read_32(SPM_PCM_REG13_DATA);
    214 	wakesta->idle_sta = mmio_read_32(SPM_SLEEP_SUBSYS_IDLE_STA);
    215 	wakesta->debug_flag = mmio_read_32(SPM_PCM_PASR_DPD_3);
    216 	wakesta->event_reg = mmio_read_32(SPM_PCM_EVENT_REG_STA);
    217 	wakesta->isr = mmio_read_32(SPM_SLEEP_ISR_STATUS);
    218 }
    219 
    220 void spm_init_event_vector(const struct pcm_desc *pcmdesc)
    221 {
    222 	/* init event vector register */
    223 	mmio_write_32(SPM_PCM_EVENT_VECTOR0, pcmdesc->vec0);
    224 	mmio_write_32(SPM_PCM_EVENT_VECTOR1, pcmdesc->vec1);
    225 	mmio_write_32(SPM_PCM_EVENT_VECTOR2, pcmdesc->vec2);
    226 	mmio_write_32(SPM_PCM_EVENT_VECTOR3, pcmdesc->vec3);
    227 	mmio_write_32(SPM_PCM_EVENT_VECTOR4, pcmdesc->vec4);
    228 	mmio_write_32(SPM_PCM_EVENT_VECTOR5, pcmdesc->vec5);
    229 	mmio_write_32(SPM_PCM_EVENT_VECTOR6, pcmdesc->vec6);
    230 	mmio_write_32(SPM_PCM_EVENT_VECTOR7, pcmdesc->vec7);
    231 
    232 	/* event vector will be enabled by PCM itself */
    233 }
    234 
    235 void spm_kick_im_to_fetch(const struct pcm_desc *pcmdesc)
    236 {
    237 	unsigned int ptr = 0, len, con0;
    238 
    239 	ptr = (unsigned int)(unsigned long)(pcmdesc->base);
    240 	len = pcmdesc->size - 1;
    241 	if (mmio_read_32(SPM_PCM_IM_PTR) != ptr ||
    242 	    mmio_read_32(SPM_PCM_IM_LEN) != len ||
    243 	    pcmdesc->sess > 2) {
    244 		mmio_write_32(SPM_PCM_IM_PTR, ptr);
    245 		mmio_write_32(SPM_PCM_IM_LEN, len);
    246 	} else {
    247 		mmio_setbits_32(SPM_PCM_CON1, CON1_CFG_KEY | CON1_IM_SLAVE);
    248 	}
    249 
    250 	/* kick IM to fetch (only toggle IM_KICK) */
    251 	con0 = mmio_read_32(SPM_PCM_CON0) & ~(CON0_IM_KICK | CON0_PCM_KICK);
    252 	mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY | CON0_IM_KICK);
    253 	mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY);
    254 
    255 	/* kick IM to fetch (only toggle PCM_KICK) */
    256 	con0 = mmio_read_32(SPM_PCM_CON0) & ~(CON0_IM_KICK | CON0_PCM_KICK);
    257 	mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY | CON0_PCM_KICK);
    258 	mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY);
    259 }
    260 
    261 void spm_set_sysclk_settle(void)
    262 {
    263 	mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE);
    264 
    265 	INFO("settle = %u\n", mmio_read_32(SPM_CLK_SETTLE));
    266 }
    267 
    268 void spm_kick_pcm_to_run(struct pwr_ctrl *pwrctrl)
    269 {
    270 	unsigned int con1;
    271 
    272 	con1 = mmio_read_32(SPM_PCM_CON1) &
    273 		~(CON1_PCM_WDT_WAKE_MODE | CON1_PCM_WDT_EN);
    274 
    275 	mmio_write_32(SPM_PCM_CON1, CON1_CFG_KEY | con1);
    276 
    277 	if (mmio_read_32(SPM_PCM_TIMER_VAL) > PCM_TIMER_MAX)
    278 		mmio_write_32(SPM_PCM_TIMER_VAL, PCM_TIMER_MAX);
    279 
    280 	mmio_write_32(SPM_PCM_WDT_TIMER_VAL,
    281 		mmio_read_32(SPM_PCM_TIMER_VAL) + PCM_WDT_TIMEOUT);
    282 
    283 	mmio_write_32(SPM_PCM_CON1, con1 | CON1_CFG_KEY | CON1_PCM_WDT_EN);
    284 	mmio_write_32(SPM_PCM_PASR_DPD_0, 0);
    285 
    286 	mmio_write_32(SPM_PCM_MAS_PAUSE_MASK, 0xffffffff);
    287 	mmio_write_32(SPM_PCM_REG_DATA_INI, 0);
    288 	mmio_clrbits_32(SPM_CLK_CON, CC_DISABLE_DORM_PWR);
    289 
    290 	mmio_write_32(SPM_PCM_FLAGS, pwrctrl->pcm_flags);
    291 
    292 	mmio_clrsetbits_32(SPM_CLK_CON, CC_LOCK_INFRA_DCM,
    293 		(pwrctrl->infra_dcm_lock ? CC_LOCK_INFRA_DCM : 0));
    294 
    295 	mmio_write_32(SPM_PCM_PWR_IO_EN,
    296 		(pwrctrl->r0_ctrl_en ? PCM_PWRIO_EN_R0 : 0) |
    297 		(pwrctrl->r7_ctrl_en ? PCM_PWRIO_EN_R7 : 0));
    298 }
    299 
    300 void spm_clean_after_wakeup(void)
    301 {
    302 	mmio_clrsetbits_32(SPM_PCM_CON1, CON1_PCM_WDT_EN, CON1_CFG_KEY);
    303 
    304 	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
    305 	mmio_write_32(SPM_SLEEP_CPU_WAKEUP_EVENT, 0);
    306 	mmio_clrsetbits_32(SPM_PCM_CON1, CON1_PCM_TIMER_EN, CON1_CFG_KEY);
    307 
    308 	mmio_write_32(SPM_SLEEP_WAKEUP_EVENT_MASK, ~0);
    309 	mmio_write_32(SPM_SLEEP_ISR_MASK, 0xFF0C);
    310 	mmio_write_32(SPM_SLEEP_ISR_STATUS, 0xC);
    311 	mmio_write_32(SPM_PCM_SW_INT_CLEAR, 0xFF);
    312 }
    313 
    314 enum wake_reason_t spm_output_wake_reason(struct wake_status *wakesta)
    315 {
    316 	enum wake_reason_t wr;
    317 	int i;
    318 
    319 	wr = WR_UNKNOWN;
    320 
    321 	if (wakesta->assert_pc != 0) {
    322 		ERROR("PCM ASSERT AT %u, r12=0x%x, r13=0x%x, debug_flag=0x%x\n",
    323 		      wakesta->assert_pc, wakesta->r12, wakesta->r13,
    324 		      wakesta->debug_flag);
    325 		return WR_PCM_ASSERT;
    326 	}
    327 
    328 	if (wakesta->r12 & WAKE_SRC_SPM_MERGE) {
    329 		if (wakesta->wake_misc & WAKE_MISC_PCM_TIMER)
    330 			wr = WR_PCM_TIMER;
    331 		if (wakesta->wake_misc & WAKE_MISC_CPU_WAKE)
    332 			wr = WR_WAKE_SRC;
    333 	}
    334 
    335 	for (i = 1; i < 32; i++) {
    336 		if (wakesta->r12 & (1U << i))
    337 			wr = WR_WAKE_SRC;
    338 	}
    339 
    340 	if ((wakesta->event_reg & 0x100000) == 0) {
    341 		INFO("pcm sleep abort!\n");
    342 		wr = WR_PCM_ABORT;
    343 	}
    344 
    345 	INFO("timer_out = %u, r12 = 0x%x, r13 = 0x%x, debug_flag = 0x%x\n",
    346 	     wakesta->timer_out, wakesta->r12, wakesta->r13,
    347 	     wakesta->debug_flag);
    348 
    349 	INFO("raw_sta = 0x%x, idle_sta = 0x%x, event_reg = 0x%x, isr = 0x%x\n",
    350 	     wakesta->raw_sta, wakesta->idle_sta, wakesta->event_reg,
    351 	     wakesta->isr);
    352 
    353 	return wr;
    354 }
    355 
    356 void spm_boot_init(void)
    357 {
    358 	/* set spm transaction to secure mode */
    359 	mmio_write_32(DEVAPC0_APC_CON, 0x0);
    360 	mmio_write_32(DEVAPC0_MAS_SEC_0, 0x200);
    361 
    362 	/* Only CPU0 is online during boot, initialize cpu online reserve bit */
    363 	mmio_write_32(SPM_PCM_RESERVE, 0xFE);
    364 	mmio_clrbits_32(AP_PLL_CON3, 0xFFFFF);
    365 	mmio_clrbits_32(AP_PLL_CON4, 0xF);
    366 	spm_lock_init();
    367 	spm_register_init();
    368 }
    369