xref: /rk3399_ARM-atf/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
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  */
6*09d40e0eSAntonio Nino Diaz 
79901dcf6SCaesar Wang #include <assert.h>
89901dcf6SCaesar Wang #include <errno.h>
9*09d40e0eSAntonio Nino Diaz 
109901dcf6SCaesar Wang #include <platform_def.h>
11*09d40e0eSAntonio Nino Diaz 
12*09d40e0eSAntonio Nino Diaz #include <common/debug.h>
13*09d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
14*09d40e0eSAntonio Nino Diaz #include <drivers/gpio.h>
15*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
16*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
17*09d40e0eSAntonio Nino Diaz 
18*09d40e0eSAntonio Nino Diaz #include <plat_private.h>
199901dcf6SCaesar Wang #include <soc.h>
209901dcf6SCaesar Wang 
219901dcf6SCaesar Wang uint32_t gpio_port[] = {
229901dcf6SCaesar Wang 	GPIO0_BASE,
239901dcf6SCaesar Wang 	GPIO1_BASE,
249901dcf6SCaesar Wang 	GPIO2_BASE,
259901dcf6SCaesar Wang 	GPIO3_BASE,
269901dcf6SCaesar Wang 	GPIO4_BASE,
279901dcf6SCaesar Wang };
289901dcf6SCaesar Wang 
292adcad64SLin Huang struct {
302adcad64SLin Huang 	uint32_t swporta_dr;
312adcad64SLin Huang 	uint32_t swporta_ddr;
322adcad64SLin Huang 	uint32_t inten;
332adcad64SLin Huang 	uint32_t intmask;
342adcad64SLin Huang 	uint32_t inttype_level;
352adcad64SLin Huang 	uint32_t int_polarity;
362adcad64SLin Huang 	uint32_t debounce;
372adcad64SLin Huang 	uint32_t ls_sync;
382adcad64SLin Huang } store_gpio[3];
392adcad64SLin Huang 
402adcad64SLin Huang static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1];
412adcad64SLin Huang 
429901dcf6SCaesar Wang #define SWPORTA_DR	0x00
439901dcf6SCaesar Wang #define SWPORTA_DDR	0x04
442adcad64SLin Huang #define INTEN		0x30
452adcad64SLin Huang #define INTMASK		0x34
462adcad64SLin Huang #define INTTYPE_LEVEL	0x38
472adcad64SLin Huang #define INT_POLARITY	0x3c
482adcad64SLin Huang #define DEBOUNCE	0x48
492adcad64SLin Huang #define LS_SYNC		0x60
509901dcf6SCaesar Wang 
512adcad64SLin Huang #define EXT_PORTA	0x50
529901dcf6SCaesar Wang #define PMU_GPIO_PORT0	0
539901dcf6SCaesar Wang #define PMU_GPIO_PORT1	1
54536c2492SCaesar Wang #define GPIO_PORT2	2
55536c2492SCaesar Wang #define GPIO_PORT3	3
56536c2492SCaesar Wang #define GPIO_PORT4	4
579901dcf6SCaesar Wang 
589901dcf6SCaesar Wang #define PMU_GRF_GPIO0A_P	0x40
599901dcf6SCaesar Wang #define GRF_GPIO2A_P		0xe040
609901dcf6SCaesar Wang #define GPIO_P_MASK		0x03
619901dcf6SCaesar Wang 
62536c2492SCaesar Wang #define GET_GPIO_PORT(pin)	(pin / 32)
63536c2492SCaesar Wang #define GET_GPIO_NUM(pin)	(pin % 32)
64536c2492SCaesar Wang #define GET_GPIO_BANK(pin)	((pin % 32) / 8)
65536c2492SCaesar Wang #define GET_GPIO_ID(pin)	((pin % 32) % 8)
66536c2492SCaesar Wang 
67536c2492SCaesar Wang /* returns old clock state, enables clock, in order to do GPIO access */
68536c2492SCaesar Wang static int gpio_get_clock(uint32_t gpio_number)
699901dcf6SCaesar Wang {
70536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio_number);
71536c2492SCaesar Wang 	uint32_t clock_state = 0;
729901dcf6SCaesar Wang 
739901dcf6SCaesar Wang 	assert(port < 5);
749901dcf6SCaesar Wang 
759901dcf6SCaesar Wang 	switch (port) {
76536c2492SCaesar Wang 	case PMU_GPIO_PORT0:
77536c2492SCaesar Wang 		clock_state = (mmio_read_32(PMUCRU_BASE +
78536c2492SCaesar Wang 					    CRU_PMU_CLKGATE_CON(1)) >>
79536c2492SCaesar Wang 					    PCLK_GPIO0_GATE_SHIFT) & 0x01;
809901dcf6SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
81536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
829901dcf6SCaesar Wang 					      PCLK_GPIO0_GATE_SHIFT));
839901dcf6SCaesar Wang 		break;
84536c2492SCaesar Wang 	case PMU_GPIO_PORT1:
85536c2492SCaesar Wang 		clock_state = (mmio_read_32(PMUCRU_BASE +
86536c2492SCaesar Wang 					    CRU_PMU_CLKGATE_CON(1)) >>
87536c2492SCaesar Wang 					    PCLK_GPIO1_GATE_SHIFT) & 0x01;
889901dcf6SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
89536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
909901dcf6SCaesar Wang 					      PCLK_GPIO1_GATE_SHIFT));
919901dcf6SCaesar Wang 		break;
92536c2492SCaesar Wang 	case GPIO_PORT2:
93536c2492SCaesar Wang 		clock_state = (mmio_read_32(CRU_BASE +
94536c2492SCaesar Wang 					    CRU_CLKGATE_CON(31)) >>
95536c2492SCaesar Wang 					    PCLK_GPIO2_GATE_SHIFT) & 0x01;
969901dcf6SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
97536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
989901dcf6SCaesar Wang 					      PCLK_GPIO2_GATE_SHIFT));
999901dcf6SCaesar Wang 		break;
100536c2492SCaesar Wang 	case GPIO_PORT3:
101536c2492SCaesar Wang 		clock_state = (mmio_read_32(CRU_BASE +
102536c2492SCaesar Wang 					    CRU_CLKGATE_CON(31)) >>
103536c2492SCaesar Wang 					    PCLK_GPIO3_GATE_SHIFT) & 0x01;
1049901dcf6SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
105536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
106536c2492SCaesar Wang 					      PCLK_GPIO3_GATE_SHIFT));
107536c2492SCaesar Wang 		break;
108536c2492SCaesar Wang 	case GPIO_PORT4:
109536c2492SCaesar Wang 		clock_state = (mmio_read_32(CRU_BASE +
110536c2492SCaesar Wang 					    CRU_CLKGATE_CON(31)) >>
111536c2492SCaesar Wang 					    PCLK_GPIO4_GATE_SHIFT) & 0x01;
112536c2492SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
113536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
114536c2492SCaesar Wang 					      PCLK_GPIO4_GATE_SHIFT));
115536c2492SCaesar Wang 		break;
116536c2492SCaesar Wang 	default:
117536c2492SCaesar Wang 		break;
118536c2492SCaesar Wang 	}
119536c2492SCaesar Wang 
120536c2492SCaesar Wang 	return clock_state;
121536c2492SCaesar Wang }
122536c2492SCaesar Wang 
123536c2492SCaesar Wang /* restores old state of gpio clock */
124536c2492SCaesar Wang void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
125536c2492SCaesar Wang {
126536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio_number);
127536c2492SCaesar Wang 
128536c2492SCaesar Wang 	switch (port) {
129536c2492SCaesar Wang 	case PMU_GPIO_PORT0:
130536c2492SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
131536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
132536c2492SCaesar Wang 					      PCLK_GPIO0_GATE_SHIFT));
133536c2492SCaesar Wang 		break;
134536c2492SCaesar Wang 	case PMU_GPIO_PORT1:
135536c2492SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
136536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
137536c2492SCaesar Wang 					      PCLK_GPIO1_GATE_SHIFT));
138536c2492SCaesar Wang 		break;
139536c2492SCaesar Wang 	case GPIO_PORT2:
140536c2492SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
141536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
142536c2492SCaesar Wang 					      PCLK_GPIO2_GATE_SHIFT));
143536c2492SCaesar Wang 		break;
144536c2492SCaesar Wang 	case GPIO_PORT3:
145536c2492SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
146536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
1479901dcf6SCaesar Wang 					      PCLK_GPIO3_GATE_SHIFT));
1489901dcf6SCaesar Wang 
1499901dcf6SCaesar Wang 		break;
150536c2492SCaesar Wang 	case GPIO_PORT4:
1519901dcf6SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
152536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
1539901dcf6SCaesar Wang 					      PCLK_GPIO4_GATE_SHIFT));
1549901dcf6SCaesar Wang 		break;
1559901dcf6SCaesar Wang 	default:
1569901dcf6SCaesar Wang 		break;
1579901dcf6SCaesar Wang 	}
1589901dcf6SCaesar Wang }
1599901dcf6SCaesar Wang 
160536c2492SCaesar Wang static int get_pull(int gpio)
1619901dcf6SCaesar Wang {
162536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
163536c2492SCaesar Wang 	uint32_t bank = GET_GPIO_BANK(gpio);
164536c2492SCaesar Wang 	uint32_t id = GET_GPIO_ID(gpio);
165536c2492SCaesar Wang 	uint32_t val, clock_state;
1669901dcf6SCaesar Wang 
167536c2492SCaesar Wang 	assert((port < 5) && (bank < 4));
1689901dcf6SCaesar Wang 
169536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
170536c2492SCaesar Wang 
171536c2492SCaesar Wang 	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
172536c2492SCaesar Wang 		val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
173536c2492SCaesar Wang 				   port * 16 + bank * 4);
174536c2492SCaesar Wang 		val = (val >> (id * 2)) & GPIO_P_MASK;
175536c2492SCaesar Wang 	} else {
176536c2492SCaesar Wang 		val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P +
177536c2492SCaesar Wang 				   (port - 2) * 16 + bank * 4);
178536c2492SCaesar Wang 		val = (val >> (id * 2)) & GPIO_P_MASK;
179536c2492SCaesar Wang 	}
180536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
1819901dcf6SCaesar Wang 
1829901dcf6SCaesar Wang 	/*
1839901dcf6SCaesar Wang 	 * in gpio0a, gpio0b, gpio2c, gpio2d,
1849901dcf6SCaesar Wang 	 * 00: Z
1859901dcf6SCaesar Wang 	 * 01: pull down
1869901dcf6SCaesar Wang 	 * 10: Z
1879901dcf6SCaesar Wang 	 * 11: pull up
1889901dcf6SCaesar Wang 	 * different with other gpio, so need to correct it
1899901dcf6SCaesar Wang 	 */
190536c2492SCaesar Wang 	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
191536c2492SCaesar Wang 		if (val == 3)
192536c2492SCaesar Wang 			val = GPIO_PULL_UP;
193536c2492SCaesar Wang 		else if (val == 1)
194536c2492SCaesar Wang 			val = GPIO_PULL_DOWN;
195536c2492SCaesar Wang 		else
196536c2492SCaesar Wang 			val = 0;
197536c2492SCaesar Wang 	}
198536c2492SCaesar Wang 
199536c2492SCaesar Wang 	return val;
200536c2492SCaesar Wang }
201536c2492SCaesar Wang 
202536c2492SCaesar Wang static void set_pull(int gpio, int pull)
203536c2492SCaesar Wang {
204536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
205536c2492SCaesar Wang 	uint32_t bank = GET_GPIO_BANK(gpio);
206536c2492SCaesar Wang 	uint32_t id = GET_GPIO_ID(gpio);
207536c2492SCaesar Wang 	uint32_t clock_state;
208536c2492SCaesar Wang 
209536c2492SCaesar Wang 	assert((port < 5) && (bank < 4));
210536c2492SCaesar Wang 
211536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
212536c2492SCaesar Wang 
213536c2492SCaesar Wang 	/*
214536c2492SCaesar Wang 	 * in gpio0a, gpio0b, gpio2c, gpio2d,
215536c2492SCaesar Wang 	 * 00: Z
216536c2492SCaesar Wang 	 * 01: pull down
217536c2492SCaesar Wang 	 * 10: Z
218536c2492SCaesar Wang 	 * 11: pull up
219536c2492SCaesar Wang 	 * different with other gpio, so need to correct it
220536c2492SCaesar Wang 	 */
221536c2492SCaesar Wang 	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
2229901dcf6SCaesar Wang 		if (pull == GPIO_PULL_UP)
2239901dcf6SCaesar Wang 			pull = 3;
2249901dcf6SCaesar Wang 		else if (pull == GPIO_PULL_DOWN)
2259901dcf6SCaesar Wang 			pull = 1;
2269901dcf6SCaesar Wang 		else
2279901dcf6SCaesar Wang 			pull = 0;
2289901dcf6SCaesar Wang 	}
2299901dcf6SCaesar Wang 
2309901dcf6SCaesar Wang 	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
2319901dcf6SCaesar Wang 		mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
2329901dcf6SCaesar Wang 			      port * 16 + bank * 4,
2339901dcf6SCaesar Wang 			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
2349901dcf6SCaesar Wang 	} else {
2359901dcf6SCaesar Wang 		mmio_write_32(GRF_BASE + GRF_GPIO2A_P +
2369901dcf6SCaesar Wang 			      (port - 2) * 16 + bank * 4,
2379901dcf6SCaesar Wang 			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
2389901dcf6SCaesar Wang 	}
239536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2409901dcf6SCaesar Wang }
2419901dcf6SCaesar Wang 
2429901dcf6SCaesar Wang static void set_direction(int gpio, int direction)
2439901dcf6SCaesar Wang {
244536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
245536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
246536c2492SCaesar Wang 	uint32_t clock_state;
2479901dcf6SCaesar Wang 
2489901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2499901dcf6SCaesar Wang 
250536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2519901dcf6SCaesar Wang 
2529901dcf6SCaesar Wang 	/*
2539901dcf6SCaesar Wang 	 * in gpio.h
2549901dcf6SCaesar Wang 	 * #define GPIO_DIR_OUT	0
2559901dcf6SCaesar Wang 	 * #define GPIO_DIR_IN	1
2569901dcf6SCaesar Wang 	 * but rk3399 gpio direction 1: output, 0: input
2579901dcf6SCaesar Wang 	 * so need to revert direction value
2589901dcf6SCaesar Wang 	 */
2599901dcf6SCaesar Wang 	mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num);
260536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2619901dcf6SCaesar Wang }
2629901dcf6SCaesar Wang 
2639901dcf6SCaesar Wang static int get_direction(int gpio)
2649901dcf6SCaesar Wang {
265536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
266536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
267536c2492SCaesar Wang 	int direction, clock_state;
2689901dcf6SCaesar Wang 
2699901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2709901dcf6SCaesar Wang 
271536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2729901dcf6SCaesar Wang 
2739901dcf6SCaesar Wang 	/*
2749901dcf6SCaesar Wang 	 * in gpio.h
2759901dcf6SCaesar Wang 	 * #define GPIO_DIR_OUT	0
2769901dcf6SCaesar Wang 	 * #define GPIO_DIR_IN	1
2779901dcf6SCaesar Wang 	 * but rk3399 gpio direction 1: output, 0: input
2789901dcf6SCaesar Wang 	 * so need to revert direction value
2799901dcf6SCaesar Wang 	 */
2809901dcf6SCaesar Wang 	direction = !((mmio_read_32(gpio_port[port] +
2819901dcf6SCaesar Wang 				    SWPORTA_DDR) >> num) & 0x1);
282536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2839901dcf6SCaesar Wang 
2849901dcf6SCaesar Wang 	return direction;
2859901dcf6SCaesar Wang }
2869901dcf6SCaesar Wang 
2879901dcf6SCaesar Wang static int get_value(int gpio)
2889901dcf6SCaesar Wang {
289536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
290536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
291536c2492SCaesar Wang 	int value, clock_state;
2929901dcf6SCaesar Wang 
2939901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2949901dcf6SCaesar Wang 
295536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2969901dcf6SCaesar Wang 	value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1;
297536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2989901dcf6SCaesar Wang 
2999901dcf6SCaesar Wang 	return value;
3009901dcf6SCaesar Wang }
3019901dcf6SCaesar Wang 
3029901dcf6SCaesar Wang static void set_value(int gpio, int value)
3039901dcf6SCaesar Wang {
304536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
305536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
306536c2492SCaesar Wang 	uint32_t clock_state;
3079901dcf6SCaesar Wang 
3089901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
3099901dcf6SCaesar Wang 
310536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
3119901dcf6SCaesar Wang 	mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num,
3129901dcf6SCaesar Wang 							 !!value << num);
313536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
3149901dcf6SCaesar Wang }
3159901dcf6SCaesar Wang 
3162adcad64SLin Huang void plat_rockchip_save_gpio(void)
3172adcad64SLin Huang {
3182adcad64SLin Huang 	int i;
3192adcad64SLin Huang 	uint32_t cru_gate_save;
3202adcad64SLin Huang 
3212adcad64SLin Huang 	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
3222adcad64SLin Huang 
3232adcad64SLin Huang 	/*
3242adcad64SLin Huang 	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
3252adcad64SLin Huang 	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
3262adcad64SLin Huang 	 * and we do not care gpio0 and gpio1 clock gate, since we never
3272adcad64SLin Huang 	 * gating them
3282adcad64SLin Huang 	 */
3292adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
3302adcad64SLin Huang 		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
3312adcad64SLin Huang 
3322adcad64SLin Huang 	/*
3332adcad64SLin Huang 	 * since gpio0, gpio1 are pmugpio, they will keep ther value
3342adcad64SLin Huang 	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
3352adcad64SLin Huang 	 * register value
3362adcad64SLin Huang 	 */
3372adcad64SLin Huang 	for (i = 2; i < 5; i++) {
3382adcad64SLin Huang 		store_gpio[i - 2].swporta_dr =
3392adcad64SLin Huang 			mmio_read_32(gpio_port[i] + SWPORTA_DR);
3402adcad64SLin Huang 		store_gpio[i - 2].swporta_ddr =
3412adcad64SLin Huang 			mmio_read_32(gpio_port[i] + SWPORTA_DDR);
3422adcad64SLin Huang 		store_gpio[i - 2].inten =
3432adcad64SLin Huang 			mmio_read_32(gpio_port[i] + INTEN);
3442adcad64SLin Huang 		store_gpio[i - 2].intmask =
3452adcad64SLin Huang 			mmio_read_32(gpio_port[i] + INTMASK);
3462adcad64SLin Huang 		store_gpio[i - 2].inttype_level =
3472adcad64SLin Huang 			mmio_read_32(gpio_port[i] + INTTYPE_LEVEL);
3482adcad64SLin Huang 		store_gpio[i - 2].int_polarity =
3492adcad64SLin Huang 			mmio_read_32(gpio_port[i] + INT_POLARITY);
3502adcad64SLin Huang 		store_gpio[i - 2].debounce =
3512adcad64SLin Huang 			mmio_read_32(gpio_port[i] + DEBOUNCE);
3522adcad64SLin Huang 		store_gpio[i - 2].ls_sync =
3532adcad64SLin Huang 			mmio_read_32(gpio_port[i] + LS_SYNC);
3542adcad64SLin Huang 	}
3552adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
3562adcad64SLin Huang 			cru_gate_save | REG_SOC_WMSK);
3572adcad64SLin Huang 
3582adcad64SLin Huang 	/*
3592adcad64SLin Huang 	 * gpio0, gpio1 in pmuiomux, they will keep ther value
3602adcad64SLin Huang 	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
3612adcad64SLin Huang 	 * iomux register value
3622adcad64SLin Huang 	 */
3632adcad64SLin Huang 	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
3642adcad64SLin Huang 		store_grf_gpio[i] =
3652adcad64SLin Huang 			mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4);
3662adcad64SLin Huang }
3672adcad64SLin Huang 
3682adcad64SLin Huang void plat_rockchip_restore_gpio(void)
3692adcad64SLin Huang {
3702adcad64SLin Huang 	int i;
3712adcad64SLin Huang 	uint32_t cru_gate_save;
3722adcad64SLin Huang 
3732adcad64SLin Huang 	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
3742adcad64SLin Huang 		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
3752adcad64SLin Huang 		      REG_SOC_WMSK | store_grf_gpio[i]);
3762adcad64SLin Huang 
3772adcad64SLin Huang 	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
3782adcad64SLin Huang 
3792adcad64SLin Huang 	/*
3802adcad64SLin Huang 	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
3812adcad64SLin Huang 	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
3822adcad64SLin Huang 	 * and we do not care gpio0 and gpio1 clock gate, since we never
3832adcad64SLin Huang 	 * gating them
3842adcad64SLin Huang 	 */
3852adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
3862adcad64SLin Huang 		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
3872adcad64SLin Huang 
3882adcad64SLin Huang 	for (i = 2; i < 5; i++) {
3892adcad64SLin Huang 		mmio_write_32(gpio_port[i] + SWPORTA_DR,
3902adcad64SLin Huang 				store_gpio[i - 2].swporta_dr);
3912adcad64SLin Huang 		mmio_write_32(gpio_port[i] + SWPORTA_DDR,
3922adcad64SLin Huang 				store_gpio[i - 2].swporta_ddr);
3932adcad64SLin Huang 		mmio_write_32(gpio_port[i] + INTEN, store_gpio[i - 2].inten);
3942adcad64SLin Huang 		mmio_write_32(gpio_port[i] + INTMASK,
3952adcad64SLin Huang 				store_gpio[i - 2].intmask);
3962adcad64SLin Huang 		mmio_write_32(gpio_port[i] + INTTYPE_LEVEL,
3972adcad64SLin Huang 				store_gpio[i - 2].inttype_level);
3982adcad64SLin Huang 		mmio_write_32(gpio_port[i] + INT_POLARITY,
3992adcad64SLin Huang 				store_gpio[i - 2].int_polarity);
4002adcad64SLin Huang 		mmio_write_32(gpio_port[i] + DEBOUNCE,
4012adcad64SLin Huang 				store_gpio[i - 2].debounce);
4022adcad64SLin Huang 		mmio_write_32(gpio_port[i] + LS_SYNC,
4032adcad64SLin Huang 				store_gpio[i - 2].ls_sync);
4042adcad64SLin Huang 	}
4052adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
4062adcad64SLin Huang 			cru_gate_save | REG_SOC_WMSK);
4072adcad64SLin Huang }
4082adcad64SLin Huang 
4099901dcf6SCaesar Wang const gpio_ops_t rk3399_gpio_ops = {
4109901dcf6SCaesar Wang 	.get_direction = get_direction,
4119901dcf6SCaesar Wang 	.set_direction = set_direction,
4129901dcf6SCaesar Wang 	.get_value = get_value,
4139901dcf6SCaesar Wang 	.set_value = set_value,
4149901dcf6SCaesar Wang 	.set_pull = set_pull,
415536c2492SCaesar Wang 	.get_pull = get_pull,
4169901dcf6SCaesar Wang };
4179901dcf6SCaesar Wang 
4189901dcf6SCaesar Wang void plat_rockchip_gpio_init(void)
4199901dcf6SCaesar Wang {
4209901dcf6SCaesar Wang 	gpio_init(&rk3399_gpio_ops);
4219901dcf6SCaesar Wang }
422