xref: /rk3399_ARM-atf/plat/imx/imx8m/imx8mq/gpc.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
181136819SBai Ping /*
281136819SBai Ping  * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
381136819SBai Ping  *
481136819SBai Ping  * SPDX-License-Identifier: BSD-3-Clause
581136819SBai Ping  */
681136819SBai Ping 
781136819SBai Ping #include <stdlib.h>
881136819SBai Ping #include <stdint.h>
981136819SBai Ping #include <stdbool.h>
10*09d40e0eSAntonio Nino Diaz 
11*09d40e0eSAntonio Nino Diaz #include <common/debug.h>
12*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
13*09d40e0eSAntonio Nino Diaz #include <lib/psci/psci.h>
14*09d40e0eSAntonio Nino Diaz #include <platform_def.h>
15*09d40e0eSAntonio Nino Diaz #include <services/std_svc.h>
16*09d40e0eSAntonio Nino Diaz 
17*09d40e0eSAntonio Nino Diaz #include <gpc.h>
1881136819SBai Ping 
1981136819SBai Ping void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint)
2081136819SBai Ping {
2181136819SBai Ping 	uint64_t temp_base;
2281136819SBai Ping 
2381136819SBai Ping 	temp_base = (uint64_t) sec_entrypoint;
2481136819SBai Ping 	temp_base >>= 2;
2581136819SBai Ping 
2681136819SBai Ping 	mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3),
2781136819SBai Ping 		((uint32_t)(temp_base >> 22) & 0xffff));
2881136819SBai Ping 	mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4,
2981136819SBai Ping 		((uint32_t)temp_base & 0x003fffff));
3081136819SBai Ping }
3181136819SBai Ping 
3281136819SBai Ping /* use wfi power down the core */
3381136819SBai Ping void imx_set_cpu_pwr_off(unsigned int core_id)
3481136819SBai Ping {
3581136819SBai Ping 	/* enable the wfi power down of the core */
3681136819SBai Ping 	mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
3781136819SBai Ping 			(1 << (core_id + 20)));
3881136819SBai Ping 	/* assert the pcg pcr bit of the core */
3981136819SBai Ping 	mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
4081136819SBai Ping };
4181136819SBai Ping 
4281136819SBai Ping /* use the sw method to power up the core */
4381136819SBai Ping void imx_set_cpu_pwr_on(unsigned int core_id)
4481136819SBai Ping {
4581136819SBai Ping 	/* clear the wfi power down bit of the core */
4681136819SBai Ping 	mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id));
4781136819SBai Ping 	/* assert the ncpuporeset */
4881136819SBai Ping 	mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id));
4981136819SBai Ping 	/* assert the pcg pcr bit of the core */
5081136819SBai Ping 	mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
5181136819SBai Ping 	/* sw power up the core */
5281136819SBai Ping 	mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id));
5381136819SBai Ping 
5481136819SBai Ping 	/* wait for the power up finished */
5581136819SBai Ping 	while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0)
5681136819SBai Ping 		;
5781136819SBai Ping 
5881136819SBai Ping 	/* deassert the pcg pcr bit of the core */
5981136819SBai Ping 	mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
6081136819SBai Ping 	/* deassert the ncpuporeset */
6181136819SBai Ping 	mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id));
6281136819SBai Ping }
6381136819SBai Ping 
6481136819SBai Ping /* if out of lpm, we need to do reverse steps */
6581136819SBai Ping void imx_set_cpu_lpm(unsigned int core_id, bool pdn)
6681136819SBai Ping {
6781136819SBai Ping 	if (pdn) {
6881136819SBai Ping 		/* enable the core WFI PDN & IRQ PUP */
6981136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
7081136819SBai Ping 				(1 << (core_id + 20)) | COREx_IRQ_WUP(core_id));
7181136819SBai Ping 		/* assert the pcg pcr bit of the core */
7281136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
7381136819SBai Ping 	} else {
7481136819SBai Ping 		/* disable CORE WFI PDN & IRQ PUP */
7581136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
7681136819SBai Ping 				COREx_IRQ_WUP(core_id));
7781136819SBai Ping 		/* deassert the pcg pcr bit of the core */
7881136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
7981136819SBai Ping 	}
8081136819SBai Ping }
8181136819SBai Ping 
8281136819SBai Ping void imx_set_sys_wakeup(unsigned int last_core, bool pdn)
8381136819SBai Ping {
8481136819SBai Ping 	/* TODO */
8581136819SBai Ping }
8681136819SBai Ping 
8781136819SBai Ping void imx_pup_pdn_slot_config(int last_core, bool pdn)
8881136819SBai Ping {
8981136819SBai Ping 	if (pdn) {
9081136819SBai Ping 		/* SLOT0 for A53 PLAT power down */
9181136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), SLT_PLAT_PDN);
9281136819SBai Ping 		/* SLOT1 for A53 PLAT power up */
9381136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(1), SLT_PLAT_PUP);
9481136819SBai Ping 		/* SLOT2 for A53 primary core power up */
9581136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(2), SLT_COREx_PUP(last_core));
9681136819SBai Ping 		/* ACK setting: PLAT ACK for PDN, CORE ACK for PUP */
9781136819SBai Ping 		mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
9881136819SBai Ping 			A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK);
9981136819SBai Ping 	} else {
10081136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), 0xFFFFFFFF);
10181136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(1), 0xFFFFFFFF);
10281136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(2), 0xFFFFFFFF);
10381136819SBai Ping 		mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
10481136819SBai Ping 			A53_DUMMY_PDN_ACK | A53_DUMMY_PUP_ACK);
10581136819SBai Ping 	}
10681136819SBai Ping }
10781136819SBai Ping 
10881136819SBai Ping void imx_set_cluster_standby(bool retention)
10981136819SBai Ping {
11081136819SBai Ping 	/*
11181136819SBai Ping 	 * Enable BIT 6 of A53 AD register to make sure system
11281136819SBai Ping 	 * don't enter LPM mode.
11381136819SBai Ping 	 */
11481136819SBai Ping 	if (retention)
11581136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6));
11681136819SBai Ping 	else
11781136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6));
11881136819SBai Ping }
11981136819SBai Ping 
12081136819SBai Ping void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state)
12181136819SBai Ping {
12281136819SBai Ping 	uint32_t val;
12381136819SBai Ping 
12481136819SBai Ping 	if (is_local_state_off(power_state)) {
12581136819SBai Ping 		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
12681136819SBai Ping 		val |= A53_LPM_STOP; /* enable C0-C1's STOP mode */
12781136819SBai Ping 		val &= ~CPU_CLOCK_ON_LPM; /* disable CPU clock in LPM mode */
12881136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
12981136819SBai Ping 
13081136819SBai Ping 		/* enable C2-3's STOP mode */
13181136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_STOP);
13281136819SBai Ping 
13381136819SBai Ping 		/* enable PLAT/SCU power down */
13481136819SBai Ping 		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
13581136819SBai Ping 		val &= ~EN_L2_WFI_PDN;
13681136819SBai Ping 		val |= L2PGE | EN_PLAT_PDN;
13781136819SBai Ping 		val &= ~COREx_IRQ_WUP(last_core); /* disable IRQ PUP for last core */
13881136819SBai Ping 		val |= COREx_LPM_PUP(last_core); /* enable LPM PUP for last core */
13981136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
14081136819SBai Ping 
14181136819SBai Ping 		imx_pup_pdn_slot_config(last_core, true);
14281136819SBai Ping 
14381136819SBai Ping 		/* enable PLAT PGC */
14481136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
14581136819SBai Ping 	} else {
14681136819SBai Ping 		/* clear PLAT PGC */
14781136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
14881136819SBai Ping 
14981136819SBai Ping 		/* clear the slot and ack for cluster power down */
15081136819SBai Ping 		imx_pup_pdn_slot_config(last_core, false);
15181136819SBai Ping 
15281136819SBai Ping 		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
15381136819SBai Ping 		val &= ~A53_LPM_MASK; /* clear the C0~1 LPM */
15481136819SBai Ping 		val |= CPU_CLOCK_ON_LPM; /* disable cpu clock in LPM */
15581136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
15681136819SBai Ping 
15781136819SBai Ping 		/* set A53 LPM to RUN mode */
15881136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_MASK);
15981136819SBai Ping 
16081136819SBai Ping 		/* clear PLAT/SCU power down */
16181136819SBai Ping 		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
16281136819SBai Ping 		val |= EN_L2_WFI_PDN;
16381136819SBai Ping 		val &= ~(L2PGE | EN_PLAT_PDN);
16481136819SBai Ping 		val &= ~COREx_LPM_PUP(last_core);  /* disable C0's LPM PUP */
16581136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
16681136819SBai Ping 	}
16781136819SBai Ping }
16881136819SBai Ping 
16981136819SBai Ping /* config the system level power mode */
17081136819SBai Ping void imx_set_sys_lpm(bool retention)
17181136819SBai Ping {
17281136819SBai Ping 	uint32_t val;
17381136819SBai Ping 
17481136819SBai Ping 	/* set system DSM mode SLPCR(0x14) */
17581136819SBai Ping 	val = mmio_read_32(IMX_GPC_BASE + SLPCR);
17681136819SBai Ping 	val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
17781136819SBai Ping 		 SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN);
17881136819SBai Ping 
17981136819SBai Ping 	if (retention)
18081136819SBai Ping 		val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
18181136819SBai Ping 			 SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN |
18281136819SBai Ping 			 SLPCR_A53_FASTWUP_STOP_MODE);
18381136819SBai Ping 
18481136819SBai Ping 	mmio_write_32(IMX_GPC_BASE + SLPCR, val);
18581136819SBai Ping }
18681136819SBai Ping 
18781136819SBai Ping void imx_set_rbc_count(void)
18881136819SBai Ping {
18981136819SBai Ping 	mmio_setbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT);
19081136819SBai Ping }
19181136819SBai Ping 
19281136819SBai Ping void imx_clear_rbc_count(void)
19381136819SBai Ping {
19481136819SBai Ping 	mmio_clrbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT);
19581136819SBai Ping }
19681136819SBai Ping 
19781136819SBai Ping void imx_gpc_init(void)
19881136819SBai Ping {
19981136819SBai Ping 	uint32_t val;
20081136819SBai Ping 	int i;
20181136819SBai Ping 	/* mask all the interrupt by default */
20281136819SBai Ping 	/* Due to the hardware design requirement, need to make
20381136819SBai Ping 	 * sure GPR interrupt(#32) is unmasked during RUN mode to
20481136819SBai Ping 	 * avoid entering DSM mode by mistake.
20581136819SBai Ping 	 */
20681136819SBai Ping 	for (i = 0; i < 4; i++) {
20781136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, 0xFFFFFFFE);
20881136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, 0xFFFFFFFE);
20981136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, 0xFFFFFFFE);
21081136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, 0xFFFFFFFE);
21181136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0);
21281136819SBai Ping 	}
21381136819SBai Ping 
21481136819SBai Ping 	/* use external IRQs to wakeup C0~C3 from LPM */
21581136819SBai Ping 	val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
21681136819SBai Ping 	val |= IRQ_SRC_A53_WUP;
21781136819SBai Ping 	/* clear the MASTER0 LPM handshake */
21881136819SBai Ping 	val &= ~MASTER0_LPM_HSK;
21981136819SBai Ping 	mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
22081136819SBai Ping 
22181136819SBai Ping 	/* mask M4 DSM trigger if M4 is NOT enabled */
22281136819SBai Ping 	mmio_setbits_32(IMX_GPC_BASE + LPCR_M4, DSM_MODE_MASK);
22381136819SBai Ping 
22481136819SBai Ping 	/* set all mix/PU in A53 domain */
22581136819SBai Ping 	mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xfffd);
22681136819SBai Ping 
22781136819SBai Ping 	/* set SCU timming */
22881136819SBai Ping 	mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING,
22981136819SBai Ping 		      (0x59 << 10) | 0x5B | (0x2 << 20));
23081136819SBai Ping 
23181136819SBai Ping 	/* set DUMMY PDN/PUP ACK by default for A53 domain */
23281136819SBai Ping 	mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK |
23381136819SBai Ping 		A53_DUMMY_PDN_ACK);
23481136819SBai Ping 
23581136819SBai Ping 	/* disable DSM mode by default */
23681136819SBai Ping 	mmio_clrbits_32(IMX_GPC_BASE + SLPCR, DSM_MODE_MASK);
23781136819SBai Ping 
23881136819SBai Ping 	/*
23981136819SBai Ping 	 * USB PHY power up needs to make sure RESET bit in SRC is clear,
24081136819SBai Ping 	 * otherwise, the PU power up bit in GPC will NOT self-cleared.
24181136819SBai Ping 	 * only need to do it once.
24281136819SBai Ping 	 */
24381136819SBai Ping 	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1);
24481136819SBai Ping 	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1);
24581136819SBai Ping }
246