xref: /arm-trusted-firmware/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <platform_def.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include <common/debug.h>
13*91f16700Schasinglulu #include <drivers/delay_timer.h>
14*91f16700Schasinglulu #include <drivers/gpio.h>
15*91f16700Schasinglulu #include <lib/mmio.h>
16*91f16700Schasinglulu #include <plat/common/platform.h>
17*91f16700Schasinglulu 
18*91f16700Schasinglulu #include <plat_private.h>
19*91f16700Schasinglulu #include <soc.h>
20*91f16700Schasinglulu 
21*91f16700Schasinglulu struct gpio_save {
22*91f16700Schasinglulu 	uint32_t swporta_dr;
23*91f16700Schasinglulu 	uint32_t swporta_ddr;
24*91f16700Schasinglulu 	uint32_t inten;
25*91f16700Schasinglulu 	uint32_t intmask;
26*91f16700Schasinglulu 	uint32_t inttype_level;
27*91f16700Schasinglulu 	uint32_t int_polarity;
28*91f16700Schasinglulu 	uint32_t debounce;
29*91f16700Schasinglulu 	uint32_t ls_sync;
30*91f16700Schasinglulu } store_gpio[3];
31*91f16700Schasinglulu 
32*91f16700Schasinglulu static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1];
33*91f16700Schasinglulu 
34*91f16700Schasinglulu #define SWPORTA_DR	0x00
35*91f16700Schasinglulu #define SWPORTA_DDR	0x04
36*91f16700Schasinglulu #define INTEN		0x30
37*91f16700Schasinglulu #define INTMASK		0x34
38*91f16700Schasinglulu #define INTTYPE_LEVEL	0x38
39*91f16700Schasinglulu #define INT_POLARITY	0x3c
40*91f16700Schasinglulu #define DEBOUNCE	0x48
41*91f16700Schasinglulu #define LS_SYNC		0x60
42*91f16700Schasinglulu 
43*91f16700Schasinglulu #define EXT_PORTA	0x50
44*91f16700Schasinglulu #define PMU_GPIO_PORT0	0
45*91f16700Schasinglulu #define PMU_GPIO_PORT1	1
46*91f16700Schasinglulu #define GPIO_PORT2	2
47*91f16700Schasinglulu #define GPIO_PORT3	3
48*91f16700Schasinglulu #define GPIO_PORT4	4
49*91f16700Schasinglulu 
50*91f16700Schasinglulu #define PMU_GRF_GPIO0A_P	0x40
51*91f16700Schasinglulu #define GRF_GPIO2A_P		0xe040
52*91f16700Schasinglulu #define GPIO_P_MASK		0x03
53*91f16700Schasinglulu 
54*91f16700Schasinglulu #define GET_GPIO_PORT(pin)	(pin / 32)
55*91f16700Schasinglulu #define GET_GPIO_NUM(pin)	(pin % 32)
56*91f16700Schasinglulu #define GET_GPIO_BANK(pin)	((pin % 32) / 8)
57*91f16700Schasinglulu #define GET_GPIO_ID(pin)	((pin % 32) % 8)
58*91f16700Schasinglulu 
59*91f16700Schasinglulu enum {
60*91f16700Schasinglulu 	ENC_ZDZU,
61*91f16700Schasinglulu 	ENC_ZUDR,
62*91f16700Schasinglulu 	ENC_ZUDZ,
63*91f16700Schasinglulu 	NUM_ENC
64*91f16700Schasinglulu };
65*91f16700Schasinglulu 
66*91f16700Schasinglulu static const struct port_info {
67*91f16700Schasinglulu 	uint32_t clkgate_reg;
68*91f16700Schasinglulu 	uint32_t pull_base;
69*91f16700Schasinglulu 	uint32_t port_base;
70*91f16700Schasinglulu 	/*
71*91f16700Schasinglulu 	 * Selects the pull mode encoding per bank,
72*91f16700Schasinglulu 	 * first index for pull_type_{hw2sw,sw2hw}
73*91f16700Schasinglulu 	 */
74*91f16700Schasinglulu 	uint8_t pull_enc[4];
75*91f16700Schasinglulu 	uint8_t clkgate_bit;
76*91f16700Schasinglulu 	uint8_t max_bank;
77*91f16700Schasinglulu } port_info[] = {
78*91f16700Schasinglulu 	{
79*91f16700Schasinglulu 		.clkgate_reg = PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
80*91f16700Schasinglulu 		.pull_base = PMUGRF_BASE + PMUGRF_GPIO0A_P,
81*91f16700Schasinglulu 		.port_base = GPIO0_BASE,
82*91f16700Schasinglulu 		.pull_enc = {ENC_ZDZU, ENC_ZDZU},
83*91f16700Schasinglulu 		.clkgate_bit = PCLK_GPIO0_GATE_SHIFT,
84*91f16700Schasinglulu 		.max_bank = 1,
85*91f16700Schasinglulu 	}, {
86*91f16700Schasinglulu 		.clkgate_reg = PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
87*91f16700Schasinglulu 		.pull_base = PMUGRF_BASE + PMUGRF_GPIO1A_P,
88*91f16700Schasinglulu 		.port_base = GPIO1_BASE,
89*91f16700Schasinglulu 		.pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZUDR, ENC_ZUDR},
90*91f16700Schasinglulu 		.clkgate_bit = PCLK_GPIO1_GATE_SHIFT,
91*91f16700Schasinglulu 		.max_bank = 3,
92*91f16700Schasinglulu 	}, {
93*91f16700Schasinglulu 		.clkgate_reg = CRU_BASE + CRU_CLKGATE_CON(31),
94*91f16700Schasinglulu 		.pull_base = GRF_BASE + GRF_GPIO2A_P,
95*91f16700Schasinglulu 		.port_base = GPIO2_BASE,
96*91f16700Schasinglulu 		.pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZDZU, ENC_ZDZU},
97*91f16700Schasinglulu 		.clkgate_bit = PCLK_GPIO2_GATE_SHIFT,
98*91f16700Schasinglulu 		.max_bank = 3,
99*91f16700Schasinglulu 	}, {
100*91f16700Schasinglulu 		.clkgate_reg = CRU_BASE + CRU_CLKGATE_CON(31),
101*91f16700Schasinglulu 		.pull_base = GRF_BASE + GRF_GPIO3A_P,
102*91f16700Schasinglulu 		.port_base = GPIO3_BASE,
103*91f16700Schasinglulu 		.pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZUDR, ENC_ZUDR},
104*91f16700Schasinglulu 		.clkgate_bit = PCLK_GPIO3_GATE_SHIFT,
105*91f16700Schasinglulu 		.max_bank = 3,
106*91f16700Schasinglulu 	}, {
107*91f16700Schasinglulu 		.clkgate_reg = CRU_BASE + CRU_CLKGATE_CON(31),
108*91f16700Schasinglulu 		.pull_base = GRF_BASE + GRF_GPIO4A_P,
109*91f16700Schasinglulu 		.port_base = GPIO4_BASE,
110*91f16700Schasinglulu 		.pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZUDR, ENC_ZUDR},
111*91f16700Schasinglulu 		.clkgate_bit = PCLK_GPIO4_GATE_SHIFT,
112*91f16700Schasinglulu 		.max_bank = 3,
113*91f16700Schasinglulu 	}
114*91f16700Schasinglulu };
115*91f16700Schasinglulu 
116*91f16700Schasinglulu /*
117*91f16700Schasinglulu  * Mappings between TF-A constants and hardware encodings:
118*91f16700Schasinglulu  * there are 3 different encoding schemes that may differ between
119*91f16700Schasinglulu  * banks of the same port: the corresponding value of the pull_enc array
120*91f16700Schasinglulu  * in port_info is used as the first index
121*91f16700Schasinglulu  */
122*91f16700Schasinglulu static const uint8_t pull_type_hw2sw[NUM_ENC][4] = {
123*91f16700Schasinglulu 	[ENC_ZDZU] = {GPIO_PULL_NONE, GPIO_PULL_DOWN, GPIO_PULL_NONE, GPIO_PULL_UP},
124*91f16700Schasinglulu 	[ENC_ZUDR] = {GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN, GPIO_PULL_REPEATER},
125*91f16700Schasinglulu 	[ENC_ZUDZ] = {GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN, GPIO_PULL_NONE}
126*91f16700Schasinglulu };
127*91f16700Schasinglulu static const uint8_t pull_type_sw2hw[NUM_ENC][4] = {
128*91f16700Schasinglulu 	[ENC_ZDZU] = {
129*91f16700Schasinglulu 		[GPIO_PULL_NONE] = 0,
130*91f16700Schasinglulu 		[GPIO_PULL_DOWN] = 1,
131*91f16700Schasinglulu 		[GPIO_PULL_UP] = 3,
132*91f16700Schasinglulu 		[GPIO_PULL_REPEATER] = -1
133*91f16700Schasinglulu 	},
134*91f16700Schasinglulu 	[ENC_ZUDR] = {
135*91f16700Schasinglulu 		[GPIO_PULL_NONE] = 0,
136*91f16700Schasinglulu 		[GPIO_PULL_DOWN] = 2,
137*91f16700Schasinglulu 		[GPIO_PULL_UP] = 1,
138*91f16700Schasinglulu 		[GPIO_PULL_REPEATER] = 3
139*91f16700Schasinglulu 	},
140*91f16700Schasinglulu 	[ENC_ZUDZ] = {
141*91f16700Schasinglulu 		[GPIO_PULL_NONE] = 0,
142*91f16700Schasinglulu 		[GPIO_PULL_DOWN] = 2,
143*91f16700Schasinglulu 		[GPIO_PULL_UP] = 1,
144*91f16700Schasinglulu 		[GPIO_PULL_REPEATER] = -1
145*91f16700Schasinglulu 	}
146*91f16700Schasinglulu };
147*91f16700Schasinglulu 
148*91f16700Schasinglulu /* Return old clock state, enables clock, in order to do GPIO access */
149*91f16700Schasinglulu static int gpio_get_clock(uint32_t gpio_number)
150*91f16700Schasinglulu {
151*91f16700Schasinglulu 	uint32_t port = GET_GPIO_PORT(gpio_number);
152*91f16700Schasinglulu 	assert(port < 5U);
153*91f16700Schasinglulu 
154*91f16700Schasinglulu 	const struct port_info *info = &port_info[port];
155*91f16700Schasinglulu 
156*91f16700Schasinglulu 	if ((mmio_read_32(info->clkgate_reg) & (1U << info->clkgate_bit)) == 0U) {
157*91f16700Schasinglulu 		return 0;
158*91f16700Schasinglulu 	}
159*91f16700Schasinglulu 	mmio_write_32(
160*91f16700Schasinglulu 		info->clkgate_reg,
161*91f16700Schasinglulu 		BITS_WITH_WMASK(0, 1, info->clkgate_bit)
162*91f16700Schasinglulu 	);
163*91f16700Schasinglulu 	return 1;
164*91f16700Schasinglulu }
165*91f16700Schasinglulu 
166*91f16700Schasinglulu /* Restore old state of gpio clock, assuming it is running now */
167*91f16700Schasinglulu void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
168*91f16700Schasinglulu {
169*91f16700Schasinglulu 	if (clock_state == 0) {
170*91f16700Schasinglulu 		return;
171*91f16700Schasinglulu 	}
172*91f16700Schasinglulu 	uint32_t port = GET_GPIO_PORT(gpio_number);
173*91f16700Schasinglulu 	const struct port_info *info = &port_info[port];
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 	mmio_write_32(info->clkgate_reg, BITS_WITH_WMASK(1, 1, info->clkgate_bit));
176*91f16700Schasinglulu }
177*91f16700Schasinglulu 
178*91f16700Schasinglulu static int get_pull(int gpio)
179*91f16700Schasinglulu {
180*91f16700Schasinglulu 	uint32_t port = GET_GPIO_PORT(gpio);
181*91f16700Schasinglulu 	uint32_t bank = GET_GPIO_BANK(gpio);
182*91f16700Schasinglulu 	uint32_t id = GET_GPIO_ID(gpio);
183*91f16700Schasinglulu 	uint32_t val, clock_state;
184*91f16700Schasinglulu 
185*91f16700Schasinglulu 	assert(port < 5U);
186*91f16700Schasinglulu 	const struct port_info *info = &port_info[port];
187*91f16700Schasinglulu 
188*91f16700Schasinglulu 	assert(bank <= info->max_bank);
189*91f16700Schasinglulu 
190*91f16700Schasinglulu 	clock_state = gpio_get_clock(gpio);
191*91f16700Schasinglulu 	val = (mmio_read_32(info->pull_base + 4 * bank) >> (id * 2)) & GPIO_P_MASK;
192*91f16700Schasinglulu 	gpio_put_clock(gpio, clock_state);
193*91f16700Schasinglulu 
194*91f16700Schasinglulu 	return pull_type_hw2sw[info->pull_enc[bank]][val];
195*91f16700Schasinglulu }
196*91f16700Schasinglulu 
197*91f16700Schasinglulu static void set_pull(int gpio, int pull)
198*91f16700Schasinglulu {
199*91f16700Schasinglulu 	uint32_t port = GET_GPIO_PORT(gpio);
200*91f16700Schasinglulu 	uint32_t bank = GET_GPIO_BANK(gpio);
201*91f16700Schasinglulu 	uint32_t id = GET_GPIO_ID(gpio);
202*91f16700Schasinglulu 	uint32_t clock_state;
203*91f16700Schasinglulu 
204*91f16700Schasinglulu 	assert(port < 5U);
205*91f16700Schasinglulu 	const struct port_info *info = &port_info[port];
206*91f16700Schasinglulu 
207*91f16700Schasinglulu 	assert(bank <= info->max_bank);
208*91f16700Schasinglulu 
209*91f16700Schasinglulu 	uint8_t val = pull_type_sw2hw[info->pull_enc[bank]][pull];
210*91f16700Schasinglulu 
211*91f16700Schasinglulu 	assert(val != (uint8_t)-1);
212*91f16700Schasinglulu 
213*91f16700Schasinglulu 	clock_state = gpio_get_clock(gpio);
214*91f16700Schasinglulu 	mmio_write_32(
215*91f16700Schasinglulu 		info->pull_base + 4 * bank,
216*91f16700Schasinglulu 		BITS_WITH_WMASK(val, GPIO_P_MASK, id * 2)
217*91f16700Schasinglulu 	);
218*91f16700Schasinglulu 	gpio_put_clock(gpio, clock_state);
219*91f16700Schasinglulu }
220*91f16700Schasinglulu 
221*91f16700Schasinglulu static void set_direction(int gpio, int direction)
222*91f16700Schasinglulu {
223*91f16700Schasinglulu 	uint32_t port = GET_GPIO_PORT(gpio);
224*91f16700Schasinglulu 	uint32_t num = GET_GPIO_NUM(gpio);
225*91f16700Schasinglulu 	uint32_t clock_state;
226*91f16700Schasinglulu 
227*91f16700Schasinglulu 	assert((port < 5) && (num < 32));
228*91f16700Schasinglulu 
229*91f16700Schasinglulu 	clock_state = gpio_get_clock(gpio);
230*91f16700Schasinglulu 
231*91f16700Schasinglulu 	/*
232*91f16700Schasinglulu 	 * in gpio.h
233*91f16700Schasinglulu 	 * #define GPIO_DIR_OUT	0
234*91f16700Schasinglulu 	 * #define GPIO_DIR_IN	1
235*91f16700Schasinglulu 	 * but rk3399 gpio direction 1: output, 0: input
236*91f16700Schasinglulu 	 * so need to revert direction value
237*91f16700Schasinglulu 	 */
238*91f16700Schasinglulu 	mmio_setbits_32(
239*91f16700Schasinglulu 		port_info[port].port_base + SWPORTA_DDR,
240*91f16700Schasinglulu 		((direction == 0) ? 1 : 0) << num
241*91f16700Schasinglulu 	);
242*91f16700Schasinglulu 	gpio_put_clock(gpio, clock_state);
243*91f16700Schasinglulu }
244*91f16700Schasinglulu 
245*91f16700Schasinglulu static int get_direction(int gpio)
246*91f16700Schasinglulu {
247*91f16700Schasinglulu 	uint32_t port = GET_GPIO_PORT(gpio);
248*91f16700Schasinglulu 	uint32_t num = GET_GPIO_NUM(gpio);
249*91f16700Schasinglulu 	int direction, clock_state;
250*91f16700Schasinglulu 
251*91f16700Schasinglulu 	assert((port < 5U) && (num < 32U));
252*91f16700Schasinglulu 
253*91f16700Schasinglulu 	clock_state = gpio_get_clock(gpio);
254*91f16700Schasinglulu 
255*91f16700Schasinglulu 	/*
256*91f16700Schasinglulu 	 * in gpio.h
257*91f16700Schasinglulu 	 * #define GPIO_DIR_OUT	0
258*91f16700Schasinglulu 	 * #define GPIO_DIR_IN	1
259*91f16700Schasinglulu 	 * but rk3399 gpio direction 1: output, 0: input
260*91f16700Schasinglulu 	 * so need to revert direction value
261*91f16700Schasinglulu 	 */
262*91f16700Schasinglulu 	direction = (((mmio_read_32(
263*91f16700Schasinglulu 		port_info[port].port_base + SWPORTA_DDR
264*91f16700Schasinglulu 	) >> num) & 1U) == 0) ? 1 : 0;
265*91f16700Schasinglulu 	gpio_put_clock(gpio, clock_state);
266*91f16700Schasinglulu 
267*91f16700Schasinglulu 	return direction;
268*91f16700Schasinglulu }
269*91f16700Schasinglulu 
270*91f16700Schasinglulu static int get_value(int gpio)
271*91f16700Schasinglulu {
272*91f16700Schasinglulu 	uint32_t port = GET_GPIO_PORT(gpio);
273*91f16700Schasinglulu 	uint32_t num = GET_GPIO_NUM(gpio);
274*91f16700Schasinglulu 	int value, clock_state;
275*91f16700Schasinglulu 
276*91f16700Schasinglulu 	assert((port < 5) && (num < 32));
277*91f16700Schasinglulu 
278*91f16700Schasinglulu 	clock_state = gpio_get_clock(gpio);
279*91f16700Schasinglulu 	value = (mmio_read_32(port_info[port].port_base + EXT_PORTA) >> num) &
280*91f16700Schasinglulu 		0x1U;
281*91f16700Schasinglulu 	gpio_put_clock(gpio, clock_state);
282*91f16700Schasinglulu 
283*91f16700Schasinglulu 	return value;
284*91f16700Schasinglulu }
285*91f16700Schasinglulu 
286*91f16700Schasinglulu static void set_value(int gpio, int value)
287*91f16700Schasinglulu {
288*91f16700Schasinglulu 	uint32_t port = GET_GPIO_PORT(gpio);
289*91f16700Schasinglulu 	uint32_t num = GET_GPIO_NUM(gpio);
290*91f16700Schasinglulu 	uint32_t clock_state;
291*91f16700Schasinglulu 
292*91f16700Schasinglulu 	assert((port < 5U) && (num < 32U));
293*91f16700Schasinglulu 
294*91f16700Schasinglulu 	clock_state = gpio_get_clock(gpio);
295*91f16700Schasinglulu 	mmio_clrsetbits_32(
296*91f16700Schasinglulu 		port_info[port].port_base + SWPORTA_DR,
297*91f16700Schasinglulu 		1 << num,
298*91f16700Schasinglulu 		((value == 0) ? 0 : 1) << num
299*91f16700Schasinglulu 	);
300*91f16700Schasinglulu 	gpio_put_clock(gpio, clock_state);
301*91f16700Schasinglulu }
302*91f16700Schasinglulu 
303*91f16700Schasinglulu void plat_rockchip_save_gpio(void)
304*91f16700Schasinglulu {
305*91f16700Schasinglulu 	unsigned int i;
306*91f16700Schasinglulu 	uint32_t cru_gate_save;
307*91f16700Schasinglulu 
308*91f16700Schasinglulu 	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
309*91f16700Schasinglulu 
310*91f16700Schasinglulu 	/*
311*91f16700Schasinglulu 	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
312*91f16700Schasinglulu 	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
313*91f16700Schasinglulu 	 * and we do not care gpio0 and gpio1 clock gate, since we never
314*91f16700Schasinglulu 	 * gating them
315*91f16700Schasinglulu 	 */
316*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
317*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
318*91f16700Schasinglulu 
319*91f16700Schasinglulu 	/*
320*91f16700Schasinglulu 	 * since gpio0, gpio1 are pmugpio, they will keep ther value
321*91f16700Schasinglulu 	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
322*91f16700Schasinglulu 	 * register value
323*91f16700Schasinglulu 	 */
324*91f16700Schasinglulu 	for (i = 2; i < 5; i++) {
325*91f16700Schasinglulu 		uint32_t base = port_info[i].port_base;
326*91f16700Schasinglulu 
327*91f16700Schasinglulu 		store_gpio[i - 2] = (struct gpio_save) {
328*91f16700Schasinglulu 			.swporta_dr = mmio_read_32(base + SWPORTA_DR),
329*91f16700Schasinglulu 			.swporta_ddr = mmio_read_32(base + SWPORTA_DDR),
330*91f16700Schasinglulu 			.inten = mmio_read_32(base + INTEN),
331*91f16700Schasinglulu 			.intmask = mmio_read_32(base + INTMASK),
332*91f16700Schasinglulu 			.inttype_level = mmio_read_32(base + INTTYPE_LEVEL),
333*91f16700Schasinglulu 			.int_polarity = mmio_read_32(base + INT_POLARITY),
334*91f16700Schasinglulu 			.debounce = mmio_read_32(base + DEBOUNCE),
335*91f16700Schasinglulu 			.ls_sync = mmio_read_32(base + LS_SYNC),
336*91f16700Schasinglulu 		};
337*91f16700Schasinglulu 	}
338*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
339*91f16700Schasinglulu 			cru_gate_save | REG_SOC_WMSK);
340*91f16700Schasinglulu 
341*91f16700Schasinglulu 	/*
342*91f16700Schasinglulu 	 * gpio0, gpio1 in pmuiomux, they will keep ther value
343*91f16700Schasinglulu 	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
344*91f16700Schasinglulu 	 * iomux register value
345*91f16700Schasinglulu 	 */
346*91f16700Schasinglulu 	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
347*91f16700Schasinglulu 		store_grf_gpio[i] =
348*91f16700Schasinglulu 			mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4);
349*91f16700Schasinglulu }
350*91f16700Schasinglulu 
351*91f16700Schasinglulu void plat_rockchip_restore_gpio(void)
352*91f16700Schasinglulu {
353*91f16700Schasinglulu 	int i;
354*91f16700Schasinglulu 	uint32_t cru_gate_save;
355*91f16700Schasinglulu 
356*91f16700Schasinglulu 	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
357*91f16700Schasinglulu 		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
358*91f16700Schasinglulu 		      REG_SOC_WMSK | store_grf_gpio[i]);
359*91f16700Schasinglulu 
360*91f16700Schasinglulu 	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
361*91f16700Schasinglulu 
362*91f16700Schasinglulu 	/*
363*91f16700Schasinglulu 	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
364*91f16700Schasinglulu 	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
365*91f16700Schasinglulu 	 * and we do not care gpio0 and gpio1 clock gate, since we never
366*91f16700Schasinglulu 	 * gating them
367*91f16700Schasinglulu 	 */
368*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
369*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
370*91f16700Schasinglulu 
371*91f16700Schasinglulu 	for (i = 2; i < 5; i++) {
372*91f16700Schasinglulu 		uint32_t base = port_info[i].port_base;
373*91f16700Schasinglulu 		const struct gpio_save *save = &store_gpio[i - 2];
374*91f16700Schasinglulu 
375*91f16700Schasinglulu 		mmio_write_32(base + SWPORTA_DR, save->swporta_dr);
376*91f16700Schasinglulu 		mmio_write_32(base + SWPORTA_DDR, save->swporta_ddr);
377*91f16700Schasinglulu 		mmio_write_32(base + INTEN, save->inten);
378*91f16700Schasinglulu 		mmio_write_32(base + INTMASK, save->intmask);
379*91f16700Schasinglulu 		mmio_write_32(base + INTTYPE_LEVEL, save->inttype_level);
380*91f16700Schasinglulu 		mmio_write_32(base + INT_POLARITY, save->int_polarity);
381*91f16700Schasinglulu 		mmio_write_32(base + DEBOUNCE, save->debounce);
382*91f16700Schasinglulu 		mmio_write_32(base + LS_SYNC, save->ls_sync);
383*91f16700Schasinglulu 	}
384*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
385*91f16700Schasinglulu 			cru_gate_save | REG_SOC_WMSK);
386*91f16700Schasinglulu }
387*91f16700Schasinglulu 
388*91f16700Schasinglulu const gpio_ops_t rk3399_gpio_ops = {
389*91f16700Schasinglulu 	.get_direction = get_direction,
390*91f16700Schasinglulu 	.set_direction = set_direction,
391*91f16700Schasinglulu 	.get_value = get_value,
392*91f16700Schasinglulu 	.set_value = set_value,
393*91f16700Schasinglulu 	.set_pull = set_pull,
394*91f16700Schasinglulu 	.get_pull = get_pull,
395*91f16700Schasinglulu };
396*91f16700Schasinglulu 
397*91f16700Schasinglulu void plat_rockchip_gpio_init(void)
398*91f16700Schasinglulu {
399*91f16700Schasinglulu 	gpio_init(&rk3399_gpio_ops);
400*91f16700Schasinglulu }
401