xref: /rk3399_ARM-atf/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c (revision 2adcad64dc44959e0c1a84654a2c2464af083e99)
19901dcf6SCaesar Wang /*
29901dcf6SCaesar Wang  * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
39901dcf6SCaesar Wang  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
59901dcf6SCaesar Wang  */
69901dcf6SCaesar Wang #include <assert.h>
79901dcf6SCaesar Wang #include <debug.h>
89901dcf6SCaesar Wang #include <delay_timer.h>
99901dcf6SCaesar Wang #include <errno.h>
109901dcf6SCaesar Wang #include <gpio.h>
119901dcf6SCaesar Wang #include <mmio.h>
12ee1ebbd1SIsla Mitchell #include <plat_private.h>
139901dcf6SCaesar Wang #include <platform.h>
149901dcf6SCaesar Wang #include <platform_def.h>
159901dcf6SCaesar Wang #include <soc.h>
169901dcf6SCaesar Wang 
179901dcf6SCaesar Wang uint32_t gpio_port[] = {
189901dcf6SCaesar Wang 	GPIO0_BASE,
199901dcf6SCaesar Wang 	GPIO1_BASE,
209901dcf6SCaesar Wang 	GPIO2_BASE,
219901dcf6SCaesar Wang 	GPIO3_BASE,
229901dcf6SCaesar Wang 	GPIO4_BASE,
239901dcf6SCaesar Wang };
249901dcf6SCaesar Wang 
25*2adcad64SLin Huang struct {
26*2adcad64SLin Huang 	uint32_t swporta_dr;
27*2adcad64SLin Huang 	uint32_t swporta_ddr;
28*2adcad64SLin Huang 	uint32_t inten;
29*2adcad64SLin Huang 	uint32_t intmask;
30*2adcad64SLin Huang 	uint32_t inttype_level;
31*2adcad64SLin Huang 	uint32_t int_polarity;
32*2adcad64SLin Huang 	uint32_t debounce;
33*2adcad64SLin Huang 	uint32_t ls_sync;
34*2adcad64SLin Huang } store_gpio[3];
35*2adcad64SLin Huang 
36*2adcad64SLin Huang static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1];
37*2adcad64SLin Huang 
389901dcf6SCaesar Wang #define SWPORTA_DR	0x00
399901dcf6SCaesar Wang #define SWPORTA_DDR	0x04
40*2adcad64SLin Huang #define INTEN		0x30
41*2adcad64SLin Huang #define INTMASK		0x34
42*2adcad64SLin Huang #define INTTYPE_LEVEL	0x38
43*2adcad64SLin Huang #define INT_POLARITY	0x3c
44*2adcad64SLin Huang #define DEBOUNCE	0x48
45*2adcad64SLin Huang #define LS_SYNC		0x60
469901dcf6SCaesar Wang 
47*2adcad64SLin Huang #define EXT_PORTA	0x50
489901dcf6SCaesar Wang #define PMU_GPIO_PORT0	0
499901dcf6SCaesar Wang #define PMU_GPIO_PORT1	1
50536c2492SCaesar Wang #define GPIO_PORT2	2
51536c2492SCaesar Wang #define GPIO_PORT3	3
52536c2492SCaesar Wang #define GPIO_PORT4	4
539901dcf6SCaesar Wang 
549901dcf6SCaesar Wang #define PMU_GRF_GPIO0A_P	0x40
559901dcf6SCaesar Wang #define GRF_GPIO2A_P		0xe040
569901dcf6SCaesar Wang #define GPIO_P_MASK		0x03
579901dcf6SCaesar Wang 
58536c2492SCaesar Wang #define GET_GPIO_PORT(pin)	(pin / 32)
59536c2492SCaesar Wang #define GET_GPIO_NUM(pin)	(pin % 32)
60536c2492SCaesar Wang #define GET_GPIO_BANK(pin)	((pin % 32) / 8)
61536c2492SCaesar Wang #define GET_GPIO_ID(pin)	((pin % 32) % 8)
62536c2492SCaesar Wang 
63536c2492SCaesar Wang /* returns old clock state, enables clock, in order to do GPIO access */
64536c2492SCaesar Wang static int gpio_get_clock(uint32_t gpio_number)
659901dcf6SCaesar Wang {
66536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio_number);
67536c2492SCaesar Wang 	uint32_t clock_state = 0;
689901dcf6SCaesar Wang 
699901dcf6SCaesar Wang 	assert(port < 5);
709901dcf6SCaesar Wang 
719901dcf6SCaesar Wang 	switch (port) {
72536c2492SCaesar Wang 	case PMU_GPIO_PORT0:
73536c2492SCaesar Wang 		clock_state = (mmio_read_32(PMUCRU_BASE +
74536c2492SCaesar Wang 					    CRU_PMU_CLKGATE_CON(1)) >>
75536c2492SCaesar Wang 					    PCLK_GPIO0_GATE_SHIFT) & 0x01;
769901dcf6SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
77536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
789901dcf6SCaesar Wang 					      PCLK_GPIO0_GATE_SHIFT));
799901dcf6SCaesar Wang 		break;
80536c2492SCaesar Wang 	case PMU_GPIO_PORT1:
81536c2492SCaesar Wang 		clock_state = (mmio_read_32(PMUCRU_BASE +
82536c2492SCaesar Wang 					    CRU_PMU_CLKGATE_CON(1)) >>
83536c2492SCaesar Wang 					    PCLK_GPIO1_GATE_SHIFT) & 0x01;
849901dcf6SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
85536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
869901dcf6SCaesar Wang 					      PCLK_GPIO1_GATE_SHIFT));
879901dcf6SCaesar Wang 		break;
88536c2492SCaesar Wang 	case GPIO_PORT2:
89536c2492SCaesar Wang 		clock_state = (mmio_read_32(CRU_BASE +
90536c2492SCaesar Wang 					    CRU_CLKGATE_CON(31)) >>
91536c2492SCaesar Wang 					    PCLK_GPIO2_GATE_SHIFT) & 0x01;
929901dcf6SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
93536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
949901dcf6SCaesar Wang 					      PCLK_GPIO2_GATE_SHIFT));
959901dcf6SCaesar Wang 		break;
96536c2492SCaesar Wang 	case GPIO_PORT3:
97536c2492SCaesar Wang 		clock_state = (mmio_read_32(CRU_BASE +
98536c2492SCaesar Wang 					    CRU_CLKGATE_CON(31)) >>
99536c2492SCaesar Wang 					    PCLK_GPIO3_GATE_SHIFT) & 0x01;
1009901dcf6SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
101536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
102536c2492SCaesar Wang 					      PCLK_GPIO3_GATE_SHIFT));
103536c2492SCaesar Wang 		break;
104536c2492SCaesar Wang 	case GPIO_PORT4:
105536c2492SCaesar Wang 		clock_state = (mmio_read_32(CRU_BASE +
106536c2492SCaesar Wang 					    CRU_CLKGATE_CON(31)) >>
107536c2492SCaesar Wang 					    PCLK_GPIO4_GATE_SHIFT) & 0x01;
108536c2492SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
109536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
110536c2492SCaesar Wang 					      PCLK_GPIO4_GATE_SHIFT));
111536c2492SCaesar Wang 		break;
112536c2492SCaesar Wang 	default:
113536c2492SCaesar Wang 		break;
114536c2492SCaesar Wang 	}
115536c2492SCaesar Wang 
116536c2492SCaesar Wang 	return clock_state;
117536c2492SCaesar Wang }
118536c2492SCaesar Wang 
119536c2492SCaesar Wang /* restores old state of gpio clock */
120536c2492SCaesar Wang void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
121536c2492SCaesar Wang {
122536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio_number);
123536c2492SCaesar Wang 
124536c2492SCaesar Wang 	switch (port) {
125536c2492SCaesar Wang 	case PMU_GPIO_PORT0:
126536c2492SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
127536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
128536c2492SCaesar Wang 					      PCLK_GPIO0_GATE_SHIFT));
129536c2492SCaesar Wang 		break;
130536c2492SCaesar Wang 	case PMU_GPIO_PORT1:
131536c2492SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
132536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
133536c2492SCaesar Wang 					      PCLK_GPIO1_GATE_SHIFT));
134536c2492SCaesar Wang 		break;
135536c2492SCaesar Wang 	case GPIO_PORT2:
136536c2492SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
137536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
138536c2492SCaesar Wang 					      PCLK_GPIO2_GATE_SHIFT));
139536c2492SCaesar Wang 		break;
140536c2492SCaesar Wang 	case GPIO_PORT3:
141536c2492SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
142536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
1439901dcf6SCaesar Wang 					      PCLK_GPIO3_GATE_SHIFT));
1449901dcf6SCaesar Wang 
1459901dcf6SCaesar Wang 		break;
146536c2492SCaesar Wang 	case GPIO_PORT4:
1479901dcf6SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
148536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
1499901dcf6SCaesar Wang 					      PCLK_GPIO4_GATE_SHIFT));
1509901dcf6SCaesar Wang 		break;
1519901dcf6SCaesar Wang 	default:
1529901dcf6SCaesar Wang 		break;
1539901dcf6SCaesar Wang 	}
1549901dcf6SCaesar Wang }
1559901dcf6SCaesar Wang 
156536c2492SCaesar Wang static int get_pull(int gpio)
1579901dcf6SCaesar Wang {
158536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
159536c2492SCaesar Wang 	uint32_t bank = GET_GPIO_BANK(gpio);
160536c2492SCaesar Wang 	uint32_t id = GET_GPIO_ID(gpio);
161536c2492SCaesar Wang 	uint32_t val, clock_state;
1629901dcf6SCaesar Wang 
163536c2492SCaesar Wang 	assert((port < 5) && (bank < 4));
1649901dcf6SCaesar Wang 
165536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
166536c2492SCaesar Wang 
167536c2492SCaesar Wang 	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
168536c2492SCaesar Wang 		val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
169536c2492SCaesar Wang 				   port * 16 + bank * 4);
170536c2492SCaesar Wang 		val = (val >> (id * 2)) & GPIO_P_MASK;
171536c2492SCaesar Wang 	} else {
172536c2492SCaesar Wang 		val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P +
173536c2492SCaesar Wang 				   (port - 2) * 16 + bank * 4);
174536c2492SCaesar Wang 		val = (val >> (id * 2)) & GPIO_P_MASK;
175536c2492SCaesar Wang 	}
176536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
1779901dcf6SCaesar Wang 
1789901dcf6SCaesar Wang 	/*
1799901dcf6SCaesar Wang 	 * in gpio0a, gpio0b, gpio2c, gpio2d,
1809901dcf6SCaesar Wang 	 * 00: Z
1819901dcf6SCaesar Wang 	 * 01: pull down
1829901dcf6SCaesar Wang 	 * 10: Z
1839901dcf6SCaesar Wang 	 * 11: pull up
1849901dcf6SCaesar Wang 	 * different with other gpio, so need to correct it
1859901dcf6SCaesar Wang 	 */
186536c2492SCaesar Wang 	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
187536c2492SCaesar Wang 		if (val == 3)
188536c2492SCaesar Wang 			val = GPIO_PULL_UP;
189536c2492SCaesar Wang 		else if (val == 1)
190536c2492SCaesar Wang 			val = GPIO_PULL_DOWN;
191536c2492SCaesar Wang 		else
192536c2492SCaesar Wang 			val = 0;
193536c2492SCaesar Wang 	}
194536c2492SCaesar Wang 
195536c2492SCaesar Wang 	return val;
196536c2492SCaesar Wang }
197536c2492SCaesar Wang 
198536c2492SCaesar Wang static void set_pull(int gpio, int pull)
199536c2492SCaesar Wang {
200536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
201536c2492SCaesar Wang 	uint32_t bank = GET_GPIO_BANK(gpio);
202536c2492SCaesar Wang 	uint32_t id = GET_GPIO_ID(gpio);
203536c2492SCaesar Wang 	uint32_t clock_state;
204536c2492SCaesar Wang 
205536c2492SCaesar Wang 	assert((port < 5) && (bank < 4));
206536c2492SCaesar Wang 
207536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
208536c2492SCaesar Wang 
209536c2492SCaesar Wang 	/*
210536c2492SCaesar Wang 	 * in gpio0a, gpio0b, gpio2c, gpio2d,
211536c2492SCaesar Wang 	 * 00: Z
212536c2492SCaesar Wang 	 * 01: pull down
213536c2492SCaesar Wang 	 * 10: Z
214536c2492SCaesar Wang 	 * 11: pull up
215536c2492SCaesar Wang 	 * different with other gpio, so need to correct it
216536c2492SCaesar Wang 	 */
217536c2492SCaesar Wang 	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
2189901dcf6SCaesar Wang 		if (pull == GPIO_PULL_UP)
2199901dcf6SCaesar Wang 			pull = 3;
2209901dcf6SCaesar Wang 		else if (pull == GPIO_PULL_DOWN)
2219901dcf6SCaesar Wang 			pull = 1;
2229901dcf6SCaesar Wang 		else
2239901dcf6SCaesar Wang 			pull = 0;
2249901dcf6SCaesar Wang 	}
2259901dcf6SCaesar Wang 
2269901dcf6SCaesar Wang 	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
2279901dcf6SCaesar Wang 		mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
2289901dcf6SCaesar Wang 			      port * 16 + bank * 4,
2299901dcf6SCaesar Wang 			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
2309901dcf6SCaesar Wang 	} else {
2319901dcf6SCaesar Wang 		mmio_write_32(GRF_BASE + GRF_GPIO2A_P +
2329901dcf6SCaesar Wang 			      (port - 2) * 16 + bank * 4,
2339901dcf6SCaesar Wang 			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
2349901dcf6SCaesar Wang 	}
235536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2369901dcf6SCaesar Wang }
2379901dcf6SCaesar Wang 
2389901dcf6SCaesar Wang static void set_direction(int gpio, int direction)
2399901dcf6SCaesar Wang {
240536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
241536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
242536c2492SCaesar Wang 	uint32_t clock_state;
2439901dcf6SCaesar Wang 
2449901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2459901dcf6SCaesar Wang 
246536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2479901dcf6SCaesar Wang 
2489901dcf6SCaesar Wang 	/*
2499901dcf6SCaesar Wang 	 * in gpio.h
2509901dcf6SCaesar Wang 	 * #define GPIO_DIR_OUT	0
2519901dcf6SCaesar Wang 	 * #define GPIO_DIR_IN	1
2529901dcf6SCaesar Wang 	 * but rk3399 gpio direction 1: output, 0: input
2539901dcf6SCaesar Wang 	 * so need to revert direction value
2549901dcf6SCaesar Wang 	 */
2559901dcf6SCaesar Wang 	mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num);
256536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2579901dcf6SCaesar Wang }
2589901dcf6SCaesar Wang 
2599901dcf6SCaesar Wang static int get_direction(int gpio)
2609901dcf6SCaesar Wang {
261536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
262536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
263536c2492SCaesar Wang 	int direction, clock_state;
2649901dcf6SCaesar Wang 
2659901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2669901dcf6SCaesar Wang 
267536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2689901dcf6SCaesar Wang 
2699901dcf6SCaesar Wang 	/*
2709901dcf6SCaesar Wang 	 * in gpio.h
2719901dcf6SCaesar Wang 	 * #define GPIO_DIR_OUT	0
2729901dcf6SCaesar Wang 	 * #define GPIO_DIR_IN	1
2739901dcf6SCaesar Wang 	 * but rk3399 gpio direction 1: output, 0: input
2749901dcf6SCaesar Wang 	 * so need to revert direction value
2759901dcf6SCaesar Wang 	 */
2769901dcf6SCaesar Wang 	direction = !((mmio_read_32(gpio_port[port] +
2779901dcf6SCaesar Wang 				    SWPORTA_DDR) >> num) & 0x1);
278536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2799901dcf6SCaesar Wang 
2809901dcf6SCaesar Wang 	return direction;
2819901dcf6SCaesar Wang }
2829901dcf6SCaesar Wang 
2839901dcf6SCaesar Wang static int get_value(int gpio)
2849901dcf6SCaesar Wang {
285536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
286536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
287536c2492SCaesar Wang 	int value, clock_state;
2889901dcf6SCaesar Wang 
2899901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2909901dcf6SCaesar Wang 
291536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2929901dcf6SCaesar Wang 	value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1;
293536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2949901dcf6SCaesar Wang 
2959901dcf6SCaesar Wang 	return value;
2969901dcf6SCaesar Wang }
2979901dcf6SCaesar Wang 
2989901dcf6SCaesar Wang static void set_value(int gpio, int value)
2999901dcf6SCaesar Wang {
300536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
301536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
302536c2492SCaesar Wang 	uint32_t clock_state;
3039901dcf6SCaesar Wang 
3049901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
3059901dcf6SCaesar Wang 
306536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
3079901dcf6SCaesar Wang 	mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num,
3089901dcf6SCaesar Wang 							 !!value << num);
309536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
3109901dcf6SCaesar Wang }
3119901dcf6SCaesar Wang 
312*2adcad64SLin Huang void plat_rockchip_save_gpio(void)
313*2adcad64SLin Huang {
314*2adcad64SLin Huang 	int i;
315*2adcad64SLin Huang 	uint32_t cru_gate_save;
316*2adcad64SLin Huang 
317*2adcad64SLin Huang 	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
318*2adcad64SLin Huang 
319*2adcad64SLin Huang 	/*
320*2adcad64SLin Huang 	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
321*2adcad64SLin Huang 	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
322*2adcad64SLin Huang 	 * and we do not care gpio0 and gpio1 clock gate, since we never
323*2adcad64SLin Huang 	 * gating them
324*2adcad64SLin Huang 	 */
325*2adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
326*2adcad64SLin Huang 		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
327*2adcad64SLin Huang 
328*2adcad64SLin Huang 	/*
329*2adcad64SLin Huang 	 * since gpio0, gpio1 are pmugpio, they will keep ther value
330*2adcad64SLin Huang 	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
331*2adcad64SLin Huang 	 * register value
332*2adcad64SLin Huang 	 */
333*2adcad64SLin Huang 	for (i = 2; i < 5; i++) {
334*2adcad64SLin Huang 		store_gpio[i - 2].swporta_dr =
335*2adcad64SLin Huang 			mmio_read_32(gpio_port[i] + SWPORTA_DR);
336*2adcad64SLin Huang 		store_gpio[i - 2].swporta_ddr =
337*2adcad64SLin Huang 			mmio_read_32(gpio_port[i] + SWPORTA_DDR);
338*2adcad64SLin Huang 		store_gpio[i - 2].inten =
339*2adcad64SLin Huang 			mmio_read_32(gpio_port[i] + INTEN);
340*2adcad64SLin Huang 		store_gpio[i - 2].intmask =
341*2adcad64SLin Huang 			mmio_read_32(gpio_port[i] + INTMASK);
342*2adcad64SLin Huang 		store_gpio[i - 2].inttype_level =
343*2adcad64SLin Huang 			mmio_read_32(gpio_port[i] + INTTYPE_LEVEL);
344*2adcad64SLin Huang 		store_gpio[i - 2].int_polarity =
345*2adcad64SLin Huang 			mmio_read_32(gpio_port[i] + INT_POLARITY);
346*2adcad64SLin Huang 		store_gpio[i - 2].debounce =
347*2adcad64SLin Huang 			mmio_read_32(gpio_port[i] + DEBOUNCE);
348*2adcad64SLin Huang 		store_gpio[i - 2].ls_sync =
349*2adcad64SLin Huang 			mmio_read_32(gpio_port[i] + LS_SYNC);
350*2adcad64SLin Huang 	}
351*2adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
352*2adcad64SLin Huang 			cru_gate_save | REG_SOC_WMSK);
353*2adcad64SLin Huang 
354*2adcad64SLin Huang 	/*
355*2adcad64SLin Huang 	 * gpio0, gpio1 in pmuiomux, they will keep ther value
356*2adcad64SLin Huang 	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
357*2adcad64SLin Huang 	 * iomux register value
358*2adcad64SLin Huang 	 */
359*2adcad64SLin Huang 	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
360*2adcad64SLin Huang 		store_grf_gpio[i] =
361*2adcad64SLin Huang 			mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4);
362*2adcad64SLin Huang }
363*2adcad64SLin Huang 
364*2adcad64SLin Huang void plat_rockchip_restore_gpio(void)
365*2adcad64SLin Huang {
366*2adcad64SLin Huang 	int i;
367*2adcad64SLin Huang 	uint32_t cru_gate_save;
368*2adcad64SLin Huang 
369*2adcad64SLin Huang 	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
370*2adcad64SLin Huang 		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
371*2adcad64SLin Huang 		      REG_SOC_WMSK | store_grf_gpio[i]);
372*2adcad64SLin Huang 
373*2adcad64SLin Huang 	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
374*2adcad64SLin Huang 
375*2adcad64SLin Huang 	/*
376*2adcad64SLin Huang 	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
377*2adcad64SLin Huang 	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
378*2adcad64SLin Huang 	 * and we do not care gpio0 and gpio1 clock gate, since we never
379*2adcad64SLin Huang 	 * gating them
380*2adcad64SLin Huang 	 */
381*2adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
382*2adcad64SLin Huang 		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
383*2adcad64SLin Huang 
384*2adcad64SLin Huang 	for (i = 2; i < 5; i++) {
385*2adcad64SLin Huang 		mmio_write_32(gpio_port[i] + SWPORTA_DR,
386*2adcad64SLin Huang 				store_gpio[i - 2].swporta_dr);
387*2adcad64SLin Huang 		mmio_write_32(gpio_port[i] + SWPORTA_DDR,
388*2adcad64SLin Huang 				store_gpio[i - 2].swporta_ddr);
389*2adcad64SLin Huang 		mmio_write_32(gpio_port[i] + INTEN, store_gpio[i - 2].inten);
390*2adcad64SLin Huang 		mmio_write_32(gpio_port[i] + INTMASK,
391*2adcad64SLin Huang 				store_gpio[i - 2].intmask);
392*2adcad64SLin Huang 		mmio_write_32(gpio_port[i] + INTTYPE_LEVEL,
393*2adcad64SLin Huang 				store_gpio[i - 2].inttype_level);
394*2adcad64SLin Huang 		mmio_write_32(gpio_port[i] + INT_POLARITY,
395*2adcad64SLin Huang 				store_gpio[i - 2].int_polarity);
396*2adcad64SLin Huang 		mmio_write_32(gpio_port[i] + DEBOUNCE,
397*2adcad64SLin Huang 				store_gpio[i - 2].debounce);
398*2adcad64SLin Huang 		mmio_write_32(gpio_port[i] + LS_SYNC,
399*2adcad64SLin Huang 				store_gpio[i - 2].ls_sync);
400*2adcad64SLin Huang 	}
401*2adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
402*2adcad64SLin Huang 			cru_gate_save | REG_SOC_WMSK);
403*2adcad64SLin Huang }
404*2adcad64SLin Huang 
4059901dcf6SCaesar Wang const gpio_ops_t rk3399_gpio_ops = {
4069901dcf6SCaesar Wang 	.get_direction = get_direction,
4079901dcf6SCaesar Wang 	.set_direction = set_direction,
4089901dcf6SCaesar Wang 	.get_value = get_value,
4099901dcf6SCaesar Wang 	.set_value = set_value,
4109901dcf6SCaesar Wang 	.set_pull = set_pull,
411536c2492SCaesar Wang 	.get_pull = get_pull,
4129901dcf6SCaesar Wang };
4139901dcf6SCaesar Wang 
4149901dcf6SCaesar Wang void plat_rockchip_gpio_init(void)
4159901dcf6SCaesar Wang {
4169901dcf6SCaesar Wang 	gpio_init(&rk3399_gpio_ops);
4179901dcf6SCaesar Wang }
418