xref: /rk3399_ARM-atf/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c (revision 4bd8c929b4bc6e1731c2892b38d4a8c43e8e89dc)
19901dcf6SCaesar Wang /*
29565962cSJona Stubbe  * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
39901dcf6SCaesar Wang  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
59901dcf6SCaesar Wang  */
609d40e0eSAntonio Nino Diaz 
79901dcf6SCaesar Wang #include <assert.h>
89901dcf6SCaesar Wang #include <errno.h>
909d40e0eSAntonio Nino Diaz 
109901dcf6SCaesar Wang #include <platform_def.h>
1109d40e0eSAntonio Nino Diaz 
1209d40e0eSAntonio Nino Diaz #include <common/debug.h>
1309d40e0eSAntonio Nino Diaz #include <drivers/delay_timer.h>
1409d40e0eSAntonio Nino Diaz #include <drivers/gpio.h>
1509d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
1609d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
1709d40e0eSAntonio Nino Diaz 
1809d40e0eSAntonio Nino Diaz #include <plat_private.h>
199901dcf6SCaesar Wang #include <soc.h>
209901dcf6SCaesar Wang 
219565962cSJona Stubbe struct gpio_save {
222adcad64SLin Huang 	uint32_t swporta_dr;
232adcad64SLin Huang 	uint32_t swporta_ddr;
242adcad64SLin Huang 	uint32_t inten;
252adcad64SLin Huang 	uint32_t intmask;
262adcad64SLin Huang 	uint32_t inttype_level;
272adcad64SLin Huang 	uint32_t int_polarity;
282adcad64SLin Huang 	uint32_t debounce;
292adcad64SLin Huang 	uint32_t ls_sync;
302adcad64SLin Huang } store_gpio[3];
312adcad64SLin Huang 
322adcad64SLin Huang static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1];
332adcad64SLin Huang 
349901dcf6SCaesar Wang #define SWPORTA_DR	0x00
359901dcf6SCaesar Wang #define SWPORTA_DDR	0x04
362adcad64SLin Huang #define INTEN		0x30
372adcad64SLin Huang #define INTMASK		0x34
382adcad64SLin Huang #define INTTYPE_LEVEL	0x38
392adcad64SLin Huang #define INT_POLARITY	0x3c
402adcad64SLin Huang #define DEBOUNCE	0x48
412adcad64SLin Huang #define LS_SYNC		0x60
429901dcf6SCaesar Wang 
432adcad64SLin Huang #define EXT_PORTA	0x50
449901dcf6SCaesar Wang #define PMU_GPIO_PORT0	0
459901dcf6SCaesar Wang #define PMU_GPIO_PORT1	1
46536c2492SCaesar Wang #define GPIO_PORT2	2
47536c2492SCaesar Wang #define GPIO_PORT3	3
48536c2492SCaesar Wang #define GPIO_PORT4	4
499901dcf6SCaesar Wang 
509901dcf6SCaesar Wang #define PMU_GRF_GPIO0A_P	0x40
519901dcf6SCaesar Wang #define GRF_GPIO2A_P		0xe040
529901dcf6SCaesar Wang #define GPIO_P_MASK		0x03
539901dcf6SCaesar Wang 
54536c2492SCaesar Wang #define GET_GPIO_PORT(pin)	(pin / 32)
55536c2492SCaesar Wang #define GET_GPIO_NUM(pin)	(pin % 32)
56536c2492SCaesar Wang #define GET_GPIO_BANK(pin)	((pin % 32) / 8)
57536c2492SCaesar Wang #define GET_GPIO_ID(pin)	((pin % 32) % 8)
58536c2492SCaesar Wang 
599565962cSJona Stubbe enum {
609565962cSJona Stubbe 	ENC_ZDZU,
619565962cSJona Stubbe 	ENC_ZUDR,
629565962cSJona Stubbe 	ENC_ZUDZ,
639565962cSJona Stubbe 	NUM_ENC
649565962cSJona Stubbe };
659565962cSJona Stubbe 
669565962cSJona Stubbe static const struct port_info {
679565962cSJona Stubbe 	uint32_t clkgate_reg;
689565962cSJona Stubbe 	uint32_t pull_base;
699565962cSJona Stubbe 	uint32_t port_base;
709565962cSJona Stubbe 	/*
719565962cSJona Stubbe 	 * Selects the pull mode encoding per bank,
729565962cSJona Stubbe 	 * first index for pull_type_{hw2sw,sw2hw}
739565962cSJona Stubbe 	 */
749565962cSJona Stubbe 	uint8_t pull_enc[4];
759565962cSJona Stubbe 	uint8_t clkgate_bit;
769565962cSJona Stubbe 	uint8_t max_bank;
779565962cSJona Stubbe } port_info[] = {
789565962cSJona Stubbe 	{
799565962cSJona Stubbe 		.clkgate_reg = PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
809565962cSJona Stubbe 		.pull_base = PMUGRF_BASE + PMUGRF_GPIO0A_P,
819565962cSJona Stubbe 		.port_base = GPIO0_BASE,
829565962cSJona Stubbe 		.pull_enc = {ENC_ZDZU, ENC_ZDZU},
839565962cSJona Stubbe 		.clkgate_bit = PCLK_GPIO0_GATE_SHIFT,
849565962cSJona Stubbe 		.max_bank = 1,
859565962cSJona Stubbe 	}, {
869565962cSJona Stubbe 		.clkgate_reg = PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
879565962cSJona Stubbe 		.pull_base = PMUGRF_BASE + PMUGRF_GPIO1A_P,
889565962cSJona Stubbe 		.port_base = GPIO1_BASE,
899565962cSJona Stubbe 		.pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZUDR, ENC_ZUDR},
909565962cSJona Stubbe 		.clkgate_bit = PCLK_GPIO1_GATE_SHIFT,
919565962cSJona Stubbe 		.max_bank = 3,
929565962cSJona Stubbe 	}, {
939565962cSJona Stubbe 		.clkgate_reg = CRU_BASE + CRU_CLKGATE_CON(31),
949565962cSJona Stubbe 		.pull_base = GRF_BASE + GRF_GPIO2A_P,
959565962cSJona Stubbe 		.port_base = GPIO2_BASE,
969565962cSJona Stubbe 		.pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZDZU, ENC_ZDZU},
979565962cSJona Stubbe 		.clkgate_bit = PCLK_GPIO2_GATE_SHIFT,
989565962cSJona Stubbe 		.max_bank = 3,
999565962cSJona Stubbe 	}, {
1009565962cSJona Stubbe 		.clkgate_reg = CRU_BASE + CRU_CLKGATE_CON(31),
1019565962cSJona Stubbe 		.pull_base = GRF_BASE + GRF_GPIO3A_P,
1029565962cSJona Stubbe 		.port_base = GPIO3_BASE,
1039565962cSJona Stubbe 		.pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZUDR, ENC_ZUDR},
1049565962cSJona Stubbe 		.clkgate_bit = PCLK_GPIO3_GATE_SHIFT,
1059565962cSJona Stubbe 		.max_bank = 3,
1069565962cSJona Stubbe 	}, {
1079565962cSJona Stubbe 		.clkgate_reg = CRU_BASE + CRU_CLKGATE_CON(31),
1089565962cSJona Stubbe 		.pull_base = GRF_BASE + GRF_GPIO4A_P,
1099565962cSJona Stubbe 		.port_base = GPIO4_BASE,
1109565962cSJona Stubbe 		.pull_enc = {ENC_ZUDR, ENC_ZUDR, ENC_ZUDR, ENC_ZUDR},
1119565962cSJona Stubbe 		.clkgate_bit = PCLK_GPIO4_GATE_SHIFT,
1129565962cSJona Stubbe 		.max_bank = 3,
1139565962cSJona Stubbe 	}
1149565962cSJona Stubbe };
1159565962cSJona Stubbe 
1169565962cSJona Stubbe /*
1179565962cSJona Stubbe  * Mappings between TF-A constants and hardware encodings:
1189565962cSJona Stubbe  * there are 3 different encoding schemes that may differ between
1199565962cSJona Stubbe  * banks of the same port: the corresponding value of the pull_enc array
1209565962cSJona Stubbe  * in port_info is used as the first index
1219565962cSJona Stubbe  */
1229565962cSJona Stubbe static const uint8_t pull_type_hw2sw[NUM_ENC][4] = {
1239565962cSJona Stubbe 	[ENC_ZDZU] = {GPIO_PULL_NONE, GPIO_PULL_DOWN, GPIO_PULL_NONE, GPIO_PULL_UP},
1249565962cSJona Stubbe 	[ENC_ZUDR] = {GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN, GPIO_PULL_REPEATER},
1259565962cSJona Stubbe 	[ENC_ZUDZ] = {GPIO_PULL_NONE, GPIO_PULL_UP, GPIO_PULL_DOWN, GPIO_PULL_NONE}
1269565962cSJona Stubbe };
1279565962cSJona Stubbe static const uint8_t pull_type_sw2hw[NUM_ENC][4] = {
1289565962cSJona Stubbe 	[ENC_ZDZU] = {
1299565962cSJona Stubbe 		[GPIO_PULL_NONE] = 0,
1309565962cSJona Stubbe 		[GPIO_PULL_DOWN] = 1,
1319565962cSJona Stubbe 		[GPIO_PULL_UP] = 3,
1329565962cSJona Stubbe 		[GPIO_PULL_REPEATER] = -1
1339565962cSJona Stubbe 	},
1349565962cSJona Stubbe 	[ENC_ZUDR] = {
1359565962cSJona Stubbe 		[GPIO_PULL_NONE] = 0,
1369565962cSJona Stubbe 		[GPIO_PULL_DOWN] = 2,
1379565962cSJona Stubbe 		[GPIO_PULL_UP] = 1,
1389565962cSJona Stubbe 		[GPIO_PULL_REPEATER] = 3
1399565962cSJona Stubbe 	},
1409565962cSJona Stubbe 	[ENC_ZUDZ] = {
1419565962cSJona Stubbe 		[GPIO_PULL_NONE] = 0,
1429565962cSJona Stubbe 		[GPIO_PULL_DOWN] = 2,
1439565962cSJona Stubbe 		[GPIO_PULL_UP] = 1,
1449565962cSJona Stubbe 		[GPIO_PULL_REPEATER] = -1
1459565962cSJona Stubbe 	}
1469565962cSJona Stubbe };
1479565962cSJona Stubbe 
1489565962cSJona Stubbe /* Return old clock state, enables clock, in order to do GPIO access */
gpio_get_clock(uint32_t gpio_number)149536c2492SCaesar Wang static int gpio_get_clock(uint32_t gpio_number)
1509901dcf6SCaesar Wang {
151536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio_number);
1529565962cSJona Stubbe 	assert(port < 5U);
1539901dcf6SCaesar Wang 
1549565962cSJona Stubbe 	const struct port_info *info = &port_info[port];
1559901dcf6SCaesar Wang 
1569565962cSJona Stubbe 	if ((mmio_read_32(info->clkgate_reg) & (1U << info->clkgate_bit)) == 0U) {
1579565962cSJona Stubbe 		return 0;
1589565962cSJona Stubbe 	}
1599565962cSJona Stubbe 	mmio_write_32(
1609565962cSJona Stubbe 		info->clkgate_reg,
1619565962cSJona Stubbe 		BITS_WITH_WMASK(0, 1, info->clkgate_bit)
1629565962cSJona Stubbe 	);
1639565962cSJona Stubbe 	return 1;
164536c2492SCaesar Wang }
165536c2492SCaesar Wang 
1669565962cSJona Stubbe /* Restore old state of gpio clock, assuming it is running now */
gpio_put_clock(uint32_t gpio_number,uint32_t clock_state)167536c2492SCaesar Wang void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
168536c2492SCaesar Wang {
1699565962cSJona Stubbe 	if (clock_state == 0) {
1709565962cSJona Stubbe 		return;
1719901dcf6SCaesar Wang 	}
1729565962cSJona Stubbe 	uint32_t port = GET_GPIO_PORT(gpio_number);
1739565962cSJona Stubbe 	const struct port_info *info = &port_info[port];
1749565962cSJona Stubbe 
1759565962cSJona Stubbe 	mmio_write_32(info->clkgate_reg, BITS_WITH_WMASK(1, 1, info->clkgate_bit));
1769901dcf6SCaesar Wang }
1779901dcf6SCaesar Wang 
get_pull(int gpio)178536c2492SCaesar Wang static int get_pull(int gpio)
1799901dcf6SCaesar Wang {
180536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
181536c2492SCaesar Wang 	uint32_t bank = GET_GPIO_BANK(gpio);
182536c2492SCaesar Wang 	uint32_t id = GET_GPIO_ID(gpio);
183536c2492SCaesar Wang 	uint32_t val, clock_state;
1849901dcf6SCaesar Wang 
1859565962cSJona Stubbe 	assert(port < 5U);
1869565962cSJona Stubbe 	const struct port_info *info = &port_info[port];
1879565962cSJona Stubbe 
1889565962cSJona Stubbe 	assert(bank <= info->max_bank);
1899901dcf6SCaesar Wang 
190536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
1919565962cSJona Stubbe 	val = (mmio_read_32(info->pull_base + 4 * bank) >> (id * 2)) & GPIO_P_MASK;
192536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
1939901dcf6SCaesar Wang 
1949565962cSJona Stubbe 	return pull_type_hw2sw[info->pull_enc[bank]][val];
195536c2492SCaesar Wang }
196536c2492SCaesar Wang 
set_pull(int gpio,int pull)197536c2492SCaesar Wang static void set_pull(int gpio, int pull)
198536c2492SCaesar Wang {
199536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
200536c2492SCaesar Wang 	uint32_t bank = GET_GPIO_BANK(gpio);
201536c2492SCaesar Wang 	uint32_t id = GET_GPIO_ID(gpio);
202536c2492SCaesar Wang 	uint32_t clock_state;
203536c2492SCaesar Wang 
2049565962cSJona Stubbe 	assert(port < 5U);
2059565962cSJona Stubbe 	const struct port_info *info = &port_info[port];
2069565962cSJona Stubbe 
2079565962cSJona Stubbe 	assert(bank <= info->max_bank);
2089565962cSJona Stubbe 
2099565962cSJona Stubbe 	uint8_t val = pull_type_sw2hw[info->pull_enc[bank]][pull];
2109565962cSJona Stubbe 
2119565962cSJona Stubbe 	assert(val != (uint8_t)-1);
212536c2492SCaesar Wang 
213536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2149565962cSJona Stubbe 	mmio_write_32(
2159565962cSJona Stubbe 		info->pull_base + 4 * bank,
2169565962cSJona Stubbe 		BITS_WITH_WMASK(val, GPIO_P_MASK, id * 2)
2179565962cSJona Stubbe 	);
218536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2199901dcf6SCaesar Wang }
2209901dcf6SCaesar Wang 
set_direction(int gpio,int direction)2219901dcf6SCaesar Wang static void set_direction(int gpio, int direction)
2229901dcf6SCaesar Wang {
223536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
224536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
225536c2492SCaesar Wang 	uint32_t clock_state;
2269901dcf6SCaesar Wang 
2279901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2289901dcf6SCaesar Wang 
229536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2309901dcf6SCaesar Wang 
2319901dcf6SCaesar Wang 	/*
2329901dcf6SCaesar Wang 	 * in gpio.h
2339901dcf6SCaesar Wang 	 * #define GPIO_DIR_OUT	0
2349901dcf6SCaesar Wang 	 * #define GPIO_DIR_IN	1
2359901dcf6SCaesar Wang 	 * but rk3399 gpio direction 1: output, 0: input
2369901dcf6SCaesar Wang 	 * so need to revert direction value
2379901dcf6SCaesar Wang 	 */
2389565962cSJona Stubbe 	mmio_setbits_32(
2399565962cSJona Stubbe 		port_info[port].port_base + SWPORTA_DDR,
2409565962cSJona Stubbe 		((direction == 0) ? 1 : 0) << num
2419565962cSJona Stubbe 	);
242536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2439901dcf6SCaesar Wang }
2449901dcf6SCaesar Wang 
get_direction(int gpio)2459901dcf6SCaesar Wang static int get_direction(int gpio)
2469901dcf6SCaesar Wang {
247536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
248536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
249536c2492SCaesar Wang 	int direction, clock_state;
2509901dcf6SCaesar Wang 
2519565962cSJona Stubbe 	assert((port < 5U) && (num < 32U));
2529901dcf6SCaesar Wang 
253536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2549901dcf6SCaesar Wang 
2559901dcf6SCaesar Wang 	/*
2569901dcf6SCaesar Wang 	 * in gpio.h
2579901dcf6SCaesar Wang 	 * #define GPIO_DIR_OUT	0
2589901dcf6SCaesar Wang 	 * #define GPIO_DIR_IN	1
2599901dcf6SCaesar Wang 	 * but rk3399 gpio direction 1: output, 0: input
2609901dcf6SCaesar Wang 	 * so need to revert direction value
2619901dcf6SCaesar Wang 	 */
2629565962cSJona Stubbe 	direction = (((mmio_read_32(
2639565962cSJona Stubbe 		port_info[port].port_base + SWPORTA_DDR
2649565962cSJona Stubbe 	) >> num) & 1U) == 0) ? 1 : 0;
265536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2669901dcf6SCaesar Wang 
2679901dcf6SCaesar Wang 	return direction;
2689901dcf6SCaesar Wang }
2699901dcf6SCaesar Wang 
get_value(int gpio)2709901dcf6SCaesar Wang static int get_value(int gpio)
2719901dcf6SCaesar Wang {
272536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
273536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
274536c2492SCaesar Wang 	int value, clock_state;
2759901dcf6SCaesar Wang 
2769901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2779901dcf6SCaesar Wang 
278536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2799565962cSJona Stubbe 	value = (mmio_read_32(port_info[port].port_base + EXT_PORTA) >> num) &
2809565962cSJona Stubbe 		0x1U;
281536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2829901dcf6SCaesar Wang 
2839901dcf6SCaesar Wang 	return value;
2849901dcf6SCaesar Wang }
2859901dcf6SCaesar Wang 
set_value(int gpio,int value)2869901dcf6SCaesar Wang static void set_value(int gpio, int value)
2879901dcf6SCaesar Wang {
288536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
289536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
290536c2492SCaesar Wang 	uint32_t clock_state;
2919901dcf6SCaesar Wang 
2929565962cSJona Stubbe 	assert((port < 5U) && (num < 32U));
2939901dcf6SCaesar Wang 
294536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2959565962cSJona Stubbe 	mmio_clrsetbits_32(
2969565962cSJona Stubbe 		port_info[port].port_base + SWPORTA_DR,
2979565962cSJona Stubbe 		1 << num,
2989565962cSJona Stubbe 		((value == 0) ? 0 : 1) << num
2999565962cSJona Stubbe 	);
300536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
3019901dcf6SCaesar Wang }
3029901dcf6SCaesar Wang 
plat_rockchip_save_gpio(void)3032adcad64SLin Huang void plat_rockchip_save_gpio(void)
3042adcad64SLin Huang {
3059565962cSJona Stubbe 	unsigned int i;
3062adcad64SLin Huang 	uint32_t cru_gate_save;
3072adcad64SLin Huang 
3082adcad64SLin Huang 	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
3092adcad64SLin Huang 
3102adcad64SLin Huang 	/*
3112adcad64SLin Huang 	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
3122adcad64SLin Huang 	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
3132adcad64SLin Huang 	 * and we do not care gpio0 and gpio1 clock gate, since we never
3142adcad64SLin Huang 	 * gating them
3152adcad64SLin Huang 	 */
3162adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
3172adcad64SLin Huang 		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
3182adcad64SLin Huang 
3192adcad64SLin Huang 	/*
3202adcad64SLin Huang 	 * since gpio0, gpio1 are pmugpio, they will keep ther value
3212adcad64SLin Huang 	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
3222adcad64SLin Huang 	 * register value
3232adcad64SLin Huang 	 */
3242adcad64SLin Huang 	for (i = 2; i < 5; i++) {
3259565962cSJona Stubbe 		uint32_t base = port_info[i].port_base;
3269565962cSJona Stubbe 
3279565962cSJona Stubbe 		store_gpio[i - 2] = (struct gpio_save) {
3289565962cSJona Stubbe 			.swporta_dr = mmio_read_32(base + SWPORTA_DR),
3299565962cSJona Stubbe 			.swporta_ddr = mmio_read_32(base + SWPORTA_DDR),
3309565962cSJona Stubbe 			.inten = mmio_read_32(base + INTEN),
3319565962cSJona Stubbe 			.intmask = mmio_read_32(base + INTMASK),
3329565962cSJona Stubbe 			.inttype_level = mmio_read_32(base + INTTYPE_LEVEL),
3339565962cSJona Stubbe 			.int_polarity = mmio_read_32(base + INT_POLARITY),
3349565962cSJona Stubbe 			.debounce = mmio_read_32(base + DEBOUNCE),
3359565962cSJona Stubbe 			.ls_sync = mmio_read_32(base + LS_SYNC),
3369565962cSJona Stubbe 		};
3372adcad64SLin Huang 	}
3382adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
3392adcad64SLin Huang 			cru_gate_save | REG_SOC_WMSK);
3402adcad64SLin Huang 
3412adcad64SLin Huang 	/*
3422adcad64SLin Huang 	 * gpio0, gpio1 in pmuiomux, they will keep ther value
3432adcad64SLin Huang 	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
3442adcad64SLin Huang 	 * iomux register value
3452adcad64SLin Huang 	 */
3462adcad64SLin Huang 	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
3472adcad64SLin Huang 		store_grf_gpio[i] =
3482adcad64SLin Huang 			mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4);
3492adcad64SLin Huang }
3502adcad64SLin Huang 
plat_rockchip_restore_gpio(void)3512adcad64SLin Huang void plat_rockchip_restore_gpio(void)
3522adcad64SLin Huang {
3532adcad64SLin Huang 	int i;
3542adcad64SLin Huang 	uint32_t cru_gate_save;
3552adcad64SLin Huang 
3562adcad64SLin Huang 	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
3572adcad64SLin Huang 		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
3582adcad64SLin Huang 		      REG_SOC_WMSK | store_grf_gpio[i]);
3592adcad64SLin Huang 
3602adcad64SLin Huang 	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
3612adcad64SLin Huang 
3622adcad64SLin Huang 	/*
3632adcad64SLin Huang 	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
3642adcad64SLin Huang 	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
3652adcad64SLin Huang 	 * and we do not care gpio0 and gpio1 clock gate, since we never
3662adcad64SLin Huang 	 * gating them
3672adcad64SLin Huang 	 */
3682adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
3692adcad64SLin Huang 		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
3702adcad64SLin Huang 
3712adcad64SLin Huang 	for (i = 2; i < 5; i++) {
3729565962cSJona Stubbe 		uint32_t base = port_info[i].port_base;
3739565962cSJona Stubbe 		const struct gpio_save *save = &store_gpio[i - 2];
3749565962cSJona Stubbe 
3759565962cSJona Stubbe 		mmio_write_32(base + SWPORTA_DR, save->swporta_dr);
3769565962cSJona Stubbe 		mmio_write_32(base + SWPORTA_DDR, save->swporta_ddr);
3779565962cSJona Stubbe 		mmio_write_32(base + INTEN, save->inten);
3789565962cSJona Stubbe 		mmio_write_32(base + INTMASK, save->intmask);
379*8557d491SElyes Haouas 		mmio_write_32(base + INTTYPE_LEVEL, save->inttype_level);
3809565962cSJona Stubbe 		mmio_write_32(base + INT_POLARITY, save->int_polarity);
3819565962cSJona Stubbe 		mmio_write_32(base + DEBOUNCE, save->debounce);
3829565962cSJona Stubbe 		mmio_write_32(base + LS_SYNC, save->ls_sync);
3832adcad64SLin Huang 	}
3842adcad64SLin Huang 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
3852adcad64SLin Huang 			cru_gate_save | REG_SOC_WMSK);
3862adcad64SLin Huang }
3872adcad64SLin Huang 
3889901dcf6SCaesar Wang const gpio_ops_t rk3399_gpio_ops = {
3899901dcf6SCaesar Wang 	.get_direction = get_direction,
3909901dcf6SCaesar Wang 	.set_direction = set_direction,
3919901dcf6SCaesar Wang 	.get_value = get_value,
3929901dcf6SCaesar Wang 	.set_value = set_value,
3939901dcf6SCaesar Wang 	.set_pull = set_pull,
394536c2492SCaesar Wang 	.get_pull = get_pull,
3959901dcf6SCaesar Wang };
3969901dcf6SCaesar Wang 
plat_rockchip_gpio_init(void)3979901dcf6SCaesar Wang void plat_rockchip_gpio_init(void)
3989901dcf6SCaesar Wang {
3999901dcf6SCaesar Wang 	gpio_init(&rk3399_gpio_ops);
4009901dcf6SCaesar Wang }
401