xref: /rk3399_ARM-atf/plat/imx/imx8m/imx8mq/gpc.c (revision 88a264657fad2f71369fec4b53478e8a595d10e9)
181136819SBai Ping /*
2*88a26465SJacky Bai  * Copyright (c) 2018-2023, 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>
1009d40e0eSAntonio Nino Diaz 
11*88a26465SJacky Bai #include <arch_helpers.h>
1209d40e0eSAntonio Nino Diaz #include <common/debug.h>
1366345b8bSJacky Bai #include <drivers/delay_timer.h>
1409d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
1509d40e0eSAntonio Nino Diaz #include <lib/psci/psci.h>
16*88a26465SJacky Bai #include <lib/smccc.h>
17*88a26465SJacky Bai #include <lib/spinlock.h>
18*88a26465SJacky Bai #include <plat/common/platform.h>
1909d40e0eSAntonio Nino Diaz #include <services/std_svc.h>
2009d40e0eSAntonio Nino Diaz 
2109d40e0eSAntonio Nino Diaz #include <gpc.h>
22*88a26465SJacky Bai #include <platform_def.h>
23*88a26465SJacky Bai 
24*88a26465SJacky Bai #define FSL_SIP_CONFIG_GPC_MASK		U(0x00)
25*88a26465SJacky Bai #define FSL_SIP_CONFIG_GPC_UNMASK	U(0x01)
26*88a26465SJacky Bai #define FSL_SIP_CONFIG_GPC_SET_WAKE	U(0x02)
27*88a26465SJacky Bai #define FSL_SIP_CONFIG_GPC_PM_DOMAIN	U(0x03)
28*88a26465SJacky Bai #define FSL_SIP_CONFIG_GPC_SET_AFF	U(0x04)
29*88a26465SJacky Bai #define FSL_SIP_CONFIG_GPC_CORE_WAKE	U(0x05)
30*88a26465SJacky Bai 
31*88a26465SJacky Bai #define MAX_HW_IRQ_NUM		U(128)
32*88a26465SJacky Bai #define MAX_IMR_NUM		U(4)
33*88a26465SJacky Bai 
34*88a26465SJacky Bai static uint32_t gpc_saved_imrs[16];
35*88a26465SJacky Bai static uint32_t gpc_wake_irqs[4];
36*88a26465SJacky Bai static uint32_t gpc_imr_offset[] = {
37*88a26465SJacky Bai 	IMX_GPC_BASE + IMR1_CORE0_A53,
38*88a26465SJacky Bai 	IMX_GPC_BASE + IMR1_CORE1_A53,
39*88a26465SJacky Bai 	IMX_GPC_BASE + IMR1_CORE2_A53,
40*88a26465SJacky Bai 	IMX_GPC_BASE + IMR1_CORE3_A53,
41*88a26465SJacky Bai 	IMX_GPC_BASE + IMR1_CORE0_M4,
42*88a26465SJacky Bai };
43*88a26465SJacky Bai 
44*88a26465SJacky Bai spinlock_t gpc_imr_lock[4];
45*88a26465SJacky Bai 
46*88a26465SJacky Bai static void gpc_imr_core_spin_lock(unsigned int core_id)
47*88a26465SJacky Bai {
48*88a26465SJacky Bai 	spin_lock(&gpc_imr_lock[core_id]);
49*88a26465SJacky Bai }
50*88a26465SJacky Bai 
51*88a26465SJacky Bai static void gpc_imr_core_spin_unlock(unsigned int core_id)
52*88a26465SJacky Bai {
53*88a26465SJacky Bai 	spin_unlock(&gpc_imr_lock[core_id]);
54*88a26465SJacky Bai }
55*88a26465SJacky Bai 
56*88a26465SJacky Bai static void gpc_save_imr_lpm(unsigned int core_id, unsigned int imr_idx)
57*88a26465SJacky Bai {
58*88a26465SJacky Bai 	uint32_t reg = gpc_imr_offset[core_id] + imr_idx * 4;
59*88a26465SJacky Bai 
60*88a26465SJacky Bai 	gpc_imr_core_spin_lock(core_id);
61*88a26465SJacky Bai 
62*88a26465SJacky Bai 	gpc_saved_imrs[core_id + imr_idx * 4] = mmio_read_32(reg);
63*88a26465SJacky Bai 	mmio_write_32(reg, ~gpc_wake_irqs[imr_idx]);
64*88a26465SJacky Bai 
65*88a26465SJacky Bai 	gpc_imr_core_spin_unlock(core_id);
66*88a26465SJacky Bai }
67*88a26465SJacky Bai 
68*88a26465SJacky Bai static void gpc_restore_imr_lpm(unsigned int core_id, unsigned int imr_idx)
69*88a26465SJacky Bai {
70*88a26465SJacky Bai 	uint32_t reg = gpc_imr_offset[core_id] + imr_idx * 4;
71*88a26465SJacky Bai 	uint32_t val = gpc_saved_imrs[core_id + imr_idx * 4];
72*88a26465SJacky Bai 
73*88a26465SJacky Bai 	gpc_imr_core_spin_lock(core_id);
74*88a26465SJacky Bai 
75*88a26465SJacky Bai 	mmio_write_32(reg, val);
76*88a26465SJacky Bai 
77*88a26465SJacky Bai 	gpc_imr_core_spin_unlock(core_id);
78*88a26465SJacky Bai }
79*88a26465SJacky Bai 
80*88a26465SJacky Bai /*
81*88a26465SJacky Bai  * On i.MX8MQ, only in system suspend mode, the A53 cluster can
82*88a26465SJacky Bai  * enter LPM mode and shutdown the A53 PLAT power domain. So LPM
83*88a26465SJacky Bai  * wakeup only used for system suspend. when system enter suspend,
84*88a26465SJacky Bai  * any A53 CORE can be the last core to suspend the system, But
85*88a26465SJacky Bai  * the LPM wakeup can only use the C0's IMR to wakeup A53 cluster
86*88a26465SJacky Bai  * from LPM, so save C0's IMRs before suspend, restore back after
87*88a26465SJacky Bai  * resume.
88*88a26465SJacky Bai  */
89*88a26465SJacky Bai void imx_set_sys_wakeup(unsigned int last_core, bool pdn)
90*88a26465SJacky Bai {
91*88a26465SJacky Bai 	unsigned int imr, core;
92*88a26465SJacky Bai 
93*88a26465SJacky Bai 	if (pdn) {
94*88a26465SJacky Bai 		for (imr = 0U; imr < MAX_IMR_NUM; imr++) {
95*88a26465SJacky Bai 			for (core = 0U; core < PLATFORM_CORE_COUNT; core++) {
96*88a26465SJacky Bai 				gpc_save_imr_lpm(core, imr);
97*88a26465SJacky Bai 			}
98*88a26465SJacky Bai 		}
99*88a26465SJacky Bai 	} else {
100*88a26465SJacky Bai 		for (imr = 0U; imr < MAX_IMR_NUM; imr++) {
101*88a26465SJacky Bai 			for (core = 0U; core < PLATFORM_CORE_COUNT; core++) {
102*88a26465SJacky Bai 				gpc_restore_imr_lpm(core, imr);
103*88a26465SJacky Bai 			}
104*88a26465SJacky Bai 		}
105*88a26465SJacky Bai 	}
106*88a26465SJacky Bai }
107*88a26465SJacky Bai 
108*88a26465SJacky Bai static void imx_gpc_hwirq_mask(unsigned int hwirq)
109*88a26465SJacky Bai {
110*88a26465SJacky Bai 	uintptr_t reg;
111*88a26465SJacky Bai 	unsigned int val;
112*88a26465SJacky Bai 
113*88a26465SJacky Bai 	if (hwirq >= MAX_HW_IRQ_NUM) {
114*88a26465SJacky Bai 		return;
115*88a26465SJacky Bai 	}
116*88a26465SJacky Bai 
117*88a26465SJacky Bai 	gpc_imr_core_spin_lock(0);
118*88a26465SJacky Bai 	reg = gpc_imr_offset[0] + (hwirq / 32) * 4;
119*88a26465SJacky Bai 	val = mmio_read_32(reg);
120*88a26465SJacky Bai 	val |= 1 << hwirq % 32;
121*88a26465SJacky Bai 	mmio_write_32(reg, val);
122*88a26465SJacky Bai 	gpc_imr_core_spin_unlock(0);
123*88a26465SJacky Bai }
124*88a26465SJacky Bai 
125*88a26465SJacky Bai static void imx_gpc_hwirq_unmask(unsigned int hwirq)
126*88a26465SJacky Bai {
127*88a26465SJacky Bai 	uintptr_t reg;
128*88a26465SJacky Bai 	unsigned int val;
129*88a26465SJacky Bai 
130*88a26465SJacky Bai 	if (hwirq >= MAX_HW_IRQ_NUM) {
131*88a26465SJacky Bai 		return;
132*88a26465SJacky Bai 	}
133*88a26465SJacky Bai 
134*88a26465SJacky Bai 	gpc_imr_core_spin_lock(0);
135*88a26465SJacky Bai 	reg = gpc_imr_offset[0] + (hwirq / 32) * 4;
136*88a26465SJacky Bai 	val = mmio_read_32(reg);
137*88a26465SJacky Bai 	val &= ~(1 << hwirq % 32);
138*88a26465SJacky Bai 	mmio_write_32(reg, val);
139*88a26465SJacky Bai 	gpc_imr_core_spin_unlock(0);
140*88a26465SJacky Bai }
141*88a26465SJacky Bai 
142*88a26465SJacky Bai static void imx_gpc_set_wake(uint32_t hwirq, bool on)
143*88a26465SJacky Bai {
144*88a26465SJacky Bai 	uint32_t mask, idx;
145*88a26465SJacky Bai 
146*88a26465SJacky Bai 	if (hwirq >= MAX_HW_IRQ_NUM) {
147*88a26465SJacky Bai 		return;
148*88a26465SJacky Bai 	}
149*88a26465SJacky Bai 
150*88a26465SJacky Bai 	mask = 1 << hwirq % 32;
151*88a26465SJacky Bai 	idx = hwirq / 32;
152*88a26465SJacky Bai 	gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
153*88a26465SJacky Bai 				 gpc_wake_irqs[idx] & ~mask;
154*88a26465SJacky Bai }
155*88a26465SJacky Bai 
156*88a26465SJacky Bai static void imx_gpc_mask_irq0(uint32_t core_id, uint32_t mask)
157*88a26465SJacky Bai {
158*88a26465SJacky Bai 	gpc_imr_core_spin_lock(core_id);
159*88a26465SJacky Bai 	if (mask) {
160*88a26465SJacky Bai 		mmio_setbits_32(gpc_imr_offset[core_id], 1);
161*88a26465SJacky Bai 	} else {
162*88a26465SJacky Bai 		mmio_clrbits_32(gpc_imr_offset[core_id], 1);
163*88a26465SJacky Bai 	}
164*88a26465SJacky Bai 
165*88a26465SJacky Bai 	dsb();
166*88a26465SJacky Bai 	gpc_imr_core_spin_unlock(core_id);
167*88a26465SJacky Bai }
168*88a26465SJacky Bai 
169*88a26465SJacky Bai void imx_gpc_core_wake(uint32_t cpumask)
170*88a26465SJacky Bai {
171*88a26465SJacky Bai 	for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
172*88a26465SJacky Bai 		if (cpumask & (1 << i)) {
173*88a26465SJacky Bai 			imx_gpc_mask_irq0(i, false);
174*88a26465SJacky Bai 		}
175*88a26465SJacky Bai 	}
176*88a26465SJacky Bai }
177*88a26465SJacky Bai 
178*88a26465SJacky Bai void imx_gpc_set_a53_core_awake(uint32_t core_id)
179*88a26465SJacky Bai {
180*88a26465SJacky Bai 	imx_gpc_mask_irq0(core_id, true);
181*88a26465SJacky Bai }
182*88a26465SJacky Bai 
183*88a26465SJacky Bai static void imx_gpc_set_affinity(uint32_t hwirq, unsigned int cpu_idx)
184*88a26465SJacky Bai {
185*88a26465SJacky Bai 	uintptr_t reg;
186*88a26465SJacky Bai 	unsigned int val;
187*88a26465SJacky Bai 
188*88a26465SJacky Bai 	if (hwirq >= MAX_HW_IRQ_NUM || cpu_idx >= 4) {
189*88a26465SJacky Bai 		return;
190*88a26465SJacky Bai 	}
191*88a26465SJacky Bai 
192*88a26465SJacky Bai 	/*
193*88a26465SJacky Bai 	 * using the mask/unmask bit as affinity function.unmask the
194*88a26465SJacky Bai 	 * IMR bit to enable IRQ wakeup for this core.
195*88a26465SJacky Bai 	 */
196*88a26465SJacky Bai 	gpc_imr_core_spin_lock(cpu_idx);
197*88a26465SJacky Bai 	reg = gpc_imr_offset[cpu_idx] + (hwirq / 32) * 4;
198*88a26465SJacky Bai 	val = mmio_read_32(reg);
199*88a26465SJacky Bai 	val &= ~(1 << hwirq % 32);
200*88a26465SJacky Bai 	mmio_write_32(reg, val);
201*88a26465SJacky Bai 	gpc_imr_core_spin_unlock(cpu_idx);
202*88a26465SJacky Bai 
203*88a26465SJacky Bai 	/* clear affinity of other core */
204*88a26465SJacky Bai 	for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
205*88a26465SJacky Bai 		if (cpu_idx != i) {
206*88a26465SJacky Bai 			gpc_imr_core_spin_lock(i);
207*88a26465SJacky Bai 			reg = gpc_imr_offset[i] + (hwirq / 32) * 4;
208*88a26465SJacky Bai 			val = mmio_read_32(reg);
209*88a26465SJacky Bai 			val |= (1 << hwirq % 32);
210*88a26465SJacky Bai 			mmio_write_32(reg, val);
211*88a26465SJacky Bai 			gpc_imr_core_spin_unlock(i);
212*88a26465SJacky Bai 		}
213*88a26465SJacky Bai 	}
214*88a26465SJacky Bai }
21581136819SBai Ping 
21681136819SBai Ping /* use wfi power down the core */
21781136819SBai Ping void imx_set_cpu_pwr_off(unsigned int core_id)
21881136819SBai Ping {
219fe5e1c14SJacky Bai 	bakery_lock_get(&gpc_lock);
220fe5e1c14SJacky Bai 
22181136819SBai Ping 	/* enable the wfi power down of the core */
22281136819SBai Ping 	mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
22381136819SBai Ping 			(1 << (core_id + 20)));
224fe5e1c14SJacky Bai 
225fe5e1c14SJacky Bai 	bakery_lock_release(&gpc_lock);
226fe5e1c14SJacky Bai 
22781136819SBai Ping 	/* assert the pcg pcr bit of the core */
22881136819SBai Ping 	mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
22981136819SBai Ping };
23081136819SBai Ping 
23181136819SBai Ping /* if out of lpm, we need to do reverse steps */
23281136819SBai Ping void imx_set_cpu_lpm(unsigned int core_id, bool pdn)
23381136819SBai Ping {
234fe5e1c14SJacky Bai 	bakery_lock_get(&gpc_lock);
235fe5e1c14SJacky Bai 
23681136819SBai Ping 	if (pdn) {
23781136819SBai Ping 		/* enable the core WFI PDN & IRQ PUP */
23881136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
23981136819SBai Ping 				(1 << (core_id + 20)) | COREx_IRQ_WUP(core_id));
24081136819SBai Ping 		/* assert the pcg pcr bit of the core */
24181136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
24281136819SBai Ping 	} else {
24381136819SBai Ping 		/* disable CORE WFI PDN & IRQ PUP */
24481136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
24581136819SBai Ping 				COREx_IRQ_WUP(core_id));
24681136819SBai Ping 		/* deassert the pcg pcr bit of the core */
24781136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
24881136819SBai Ping 	}
249fe5e1c14SJacky Bai 
250fe5e1c14SJacky Bai 	bakery_lock_release(&gpc_lock);
25181136819SBai Ping }
25281136819SBai Ping 
25381136819SBai Ping void imx_pup_pdn_slot_config(int last_core, bool pdn)
25481136819SBai Ping {
25581136819SBai Ping 	if (pdn) {
25681136819SBai Ping 		/* SLOT0 for A53 PLAT power down */
25781136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), SLT_PLAT_PDN);
25881136819SBai Ping 		/* SLOT1 for A53 PLAT power up */
25981136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(1), SLT_PLAT_PUP);
26081136819SBai Ping 		/* SLOT2 for A53 primary core power up */
26181136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(2), SLT_COREx_PUP(last_core));
26281136819SBai Ping 		/* ACK setting: PLAT ACK for PDN, CORE ACK for PUP */
26381136819SBai Ping 		mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
26481136819SBai Ping 			A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK);
26581136819SBai Ping 	} else {
26681136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), 0xFFFFFFFF);
26781136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(1), 0xFFFFFFFF);
26881136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(2), 0xFFFFFFFF);
26981136819SBai Ping 		mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
27081136819SBai Ping 			A53_DUMMY_PDN_ACK | A53_DUMMY_PUP_ACK);
27181136819SBai Ping 	}
27281136819SBai Ping }
27381136819SBai Ping 
27481136819SBai Ping void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state)
27581136819SBai Ping {
27681136819SBai Ping 	uint32_t val;
27781136819SBai Ping 
27881136819SBai Ping 	if (is_local_state_off(power_state)) {
27981136819SBai Ping 		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
28081136819SBai Ping 		val |= A53_LPM_STOP; /* enable C0-C1's STOP mode */
28181136819SBai Ping 		val &= ~CPU_CLOCK_ON_LPM; /* disable CPU clock in LPM mode */
28281136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
28381136819SBai Ping 
28481136819SBai Ping 		/* enable C2-3's STOP mode */
28581136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_STOP);
28681136819SBai Ping 
28781136819SBai Ping 		/* enable PLAT/SCU power down */
28881136819SBai Ping 		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
28981136819SBai Ping 		val &= ~EN_L2_WFI_PDN;
29081136819SBai Ping 		val |= L2PGE | EN_PLAT_PDN;
29181136819SBai Ping 		val &= ~COREx_IRQ_WUP(last_core); /* disable IRQ PUP for last core */
29281136819SBai Ping 		val |= COREx_LPM_PUP(last_core); /* enable LPM PUP for last core */
29381136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
29481136819SBai Ping 
29581136819SBai Ping 		imx_pup_pdn_slot_config(last_core, true);
29681136819SBai Ping 
29781136819SBai Ping 		/* enable PLAT PGC */
29881136819SBai Ping 		mmio_setbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
29981136819SBai Ping 	} else {
30081136819SBai Ping 		/* clear PLAT PGC */
30181136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
30281136819SBai Ping 
30381136819SBai Ping 		/* clear the slot and ack for cluster power down */
30481136819SBai Ping 		imx_pup_pdn_slot_config(last_core, false);
30581136819SBai Ping 
30681136819SBai Ping 		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
30781136819SBai Ping 		val &= ~A53_LPM_MASK; /* clear the C0~1 LPM */
30881136819SBai Ping 		val |= CPU_CLOCK_ON_LPM; /* disable cpu clock in LPM */
30981136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
31081136819SBai Ping 
31181136819SBai Ping 		/* set A53 LPM to RUN mode */
31281136819SBai Ping 		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_MASK);
31381136819SBai Ping 
31481136819SBai Ping 		/* clear PLAT/SCU power down */
31581136819SBai Ping 		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
31681136819SBai Ping 		val |= EN_L2_WFI_PDN;
31781136819SBai Ping 		val &= ~(L2PGE | EN_PLAT_PDN);
31881136819SBai Ping 		val &= ~COREx_LPM_PUP(last_core);  /* disable C0's LPM PUP */
31981136819SBai Ping 		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
32081136819SBai Ping 	}
32181136819SBai Ping }
32281136819SBai Ping 
323*88a26465SJacky Bai int imx_gpc_handler(uint32_t smc_fid,
324*88a26465SJacky Bai 			  u_register_t x1,
325*88a26465SJacky Bai 			  u_register_t x2,
326*88a26465SJacky Bai 			  u_register_t x3)
327*88a26465SJacky Bai {
328*88a26465SJacky Bai 	switch (x1) {
329*88a26465SJacky Bai 	case FSL_SIP_CONFIG_GPC_CORE_WAKE:
330*88a26465SJacky Bai 		imx_gpc_core_wake(x2);
331*88a26465SJacky Bai 		break;
332*88a26465SJacky Bai 	case FSL_SIP_CONFIG_GPC_SET_WAKE:
333*88a26465SJacky Bai 		imx_gpc_set_wake(x2, x3);
334*88a26465SJacky Bai 		break;
335*88a26465SJacky Bai 	case FSL_SIP_CONFIG_GPC_MASK:
336*88a26465SJacky Bai 		imx_gpc_hwirq_mask(x2);
337*88a26465SJacky Bai 		break;
338*88a26465SJacky Bai 	case FSL_SIP_CONFIG_GPC_UNMASK:
339*88a26465SJacky Bai 		imx_gpc_hwirq_unmask(x2);
340*88a26465SJacky Bai 		break;
341*88a26465SJacky Bai 	case FSL_SIP_CONFIG_GPC_SET_AFF:
342*88a26465SJacky Bai 		imx_gpc_set_affinity(x2, x3);
343*88a26465SJacky Bai 		break;
344*88a26465SJacky Bai 	default:
345*88a26465SJacky Bai 		return SMC_UNK;
346*88a26465SJacky Bai 	}
347*88a26465SJacky Bai 
348*88a26465SJacky Bai 	return 0;
349*88a26465SJacky Bai }
350*88a26465SJacky Bai 
35181136819SBai Ping void imx_gpc_init(void)
35281136819SBai Ping {
35381136819SBai Ping 	uint32_t val;
354*88a26465SJacky Bai 	unsigned int i, j;
355*88a26465SJacky Bai 
35681136819SBai Ping 	/* mask all the interrupt by default */
357*88a26465SJacky Bai 	for (i = 0U; i < PLATFORM_CORE_COUNT; i++) {
358*88a26465SJacky Bai 		for (j = 0U; j < ARRAY_SIZE(gpc_imr_offset); j++) {
359*88a26465SJacky Bai 			mmio_write_32(gpc_imr_offset[j] + i * 4, ~0x0);
3607696880aSLeonard Crestez 		}
361*88a26465SJacky Bai 	}
362*88a26465SJacky Bai 
36381136819SBai Ping 	/* Due to the hardware design requirement, need to make
36481136819SBai Ping 	 * sure GPR interrupt(#32) is unmasked during RUN mode to
36581136819SBai Ping 	 * avoid entering DSM mode by mistake.
36681136819SBai Ping 	 */
367*88a26465SJacky Bai 	for (i = 0U; i < PLATFORM_CORE_COUNT; i++) {
368*88a26465SJacky Bai 		mmio_write_32(gpc_imr_offset[i], ~0x1);
369*88a26465SJacky Bai 	}
370*88a26465SJacky Bai 
371*88a26465SJacky Bai 	/* leave the IOMUX_GPC bit 12 on for core wakeup */
372*88a26465SJacky Bai 	mmio_setbits_32(IMX_IOMUX_GPR_BASE + 0x4, 1 << 12);
37381136819SBai Ping 
37481136819SBai Ping 	/* use external IRQs to wakeup C0~C3 from LPM */
37581136819SBai Ping 	val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
37681136819SBai Ping 	val |= IRQ_SRC_A53_WUP;
37781136819SBai Ping 	/* clear the MASTER0 LPM handshake */
37881136819SBai Ping 	val &= ~MASTER0_LPM_HSK;
37981136819SBai Ping 	mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
38081136819SBai Ping 
38181136819SBai Ping 	/* mask M4 DSM trigger if M4 is NOT enabled */
38281136819SBai Ping 	mmio_setbits_32(IMX_GPC_BASE + LPCR_M4, DSM_MODE_MASK);
38381136819SBai Ping 
38481136819SBai Ping 	/* set all mix/PU in A53 domain */
38581136819SBai Ping 	mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xfffd);
38681136819SBai Ping 
38781136819SBai Ping 	/* set SCU timming */
38881136819SBai Ping 	mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING,
38981136819SBai Ping 		      (0x59 << 10) | 0x5B | (0x2 << 20));
39081136819SBai Ping 
39181136819SBai Ping 	/* set DUMMY PDN/PUP ACK by default for A53 domain */
39281136819SBai Ping 	mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK |
39381136819SBai Ping 		A53_DUMMY_PDN_ACK);
39481136819SBai Ping 
39581136819SBai Ping 	/* disable DSM mode by default */
39681136819SBai Ping 	mmio_clrbits_32(IMX_GPC_BASE + SLPCR, DSM_MODE_MASK);
39781136819SBai Ping 
39881136819SBai Ping 	/*
39981136819SBai Ping 	 * USB PHY power up needs to make sure RESET bit in SRC is clear,
40081136819SBai Ping 	 * otherwise, the PU power up bit in GPC will NOT self-cleared.
40181136819SBai Ping 	 * only need to do it once.
40281136819SBai Ping 	 */
40381136819SBai Ping 	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1);
40481136819SBai Ping 	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1);
405e1958506SLeonard Crestez 
40666345b8bSJacky Bai 	/*
40766345b8bSJacky Bai 	 * for USB OTG, the limitation are:
40866345b8bSJacky Bai 	 * 1. before system clock config, the IPG clock run at 12.5MHz, delay time
40966345b8bSJacky Bai 	 *    should be longer than 82us.
41066345b8bSJacky Bai 	 * 2. after system clock config, ipg clock run at 66.5MHz, delay time
41166345b8bSJacky Bai 	 *    be longer that 15.3 us.
41266345b8bSJacky Bai 	 *    Add 100us to make sure the USB OTG SRC is clear safely.
41366345b8bSJacky Bai 	 */
41466345b8bSJacky Bai 	udelay(100);
41581136819SBai Ping }
416