xref: /rk3399_ARM-atf/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c (revision 82cb2c1ad9897473743f08437d0a3995bed561b9)
19901dcf6SCaesar Wang /*
29901dcf6SCaesar Wang  * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
39901dcf6SCaesar Wang  *
4*82cb2c1aSdp-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>
129901dcf6SCaesar Wang #include <platform.h>
139901dcf6SCaesar Wang #include <platform_def.h>
149901dcf6SCaesar Wang #include <plat_private.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 
259901dcf6SCaesar Wang #define SWPORTA_DR	0x00
269901dcf6SCaesar Wang #define SWPORTA_DDR	0x04
279901dcf6SCaesar Wang #define EXT_PORTA	0x50
289901dcf6SCaesar Wang 
299901dcf6SCaesar Wang #define PMU_GPIO_PORT0	0
309901dcf6SCaesar Wang #define PMU_GPIO_PORT1	1
31536c2492SCaesar Wang #define GPIO_PORT2	2
32536c2492SCaesar Wang #define GPIO_PORT3	3
33536c2492SCaesar Wang #define GPIO_PORT4	4
349901dcf6SCaesar Wang 
359901dcf6SCaesar Wang #define PMU_GRF_GPIO0A_P	0x40
369901dcf6SCaesar Wang #define GRF_GPIO2A_P		0xe040
379901dcf6SCaesar Wang #define GPIO_P_MASK		0x03
389901dcf6SCaesar Wang 
39536c2492SCaesar Wang #define GET_GPIO_PORT(pin)	(pin / 32)
40536c2492SCaesar Wang #define GET_GPIO_NUM(pin)	(pin % 32)
41536c2492SCaesar Wang #define GET_GPIO_BANK(pin)	((pin % 32) / 8)
42536c2492SCaesar Wang #define GET_GPIO_ID(pin)	((pin % 32) % 8)
43536c2492SCaesar Wang 
44536c2492SCaesar Wang /* returns old clock state, enables clock, in order to do GPIO access */
45536c2492SCaesar Wang static int gpio_get_clock(uint32_t gpio_number)
469901dcf6SCaesar Wang {
47536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio_number);
48536c2492SCaesar Wang 	uint32_t clock_state = 0;
499901dcf6SCaesar Wang 
509901dcf6SCaesar Wang 	assert(port < 5);
519901dcf6SCaesar Wang 
529901dcf6SCaesar Wang 	switch (port) {
53536c2492SCaesar Wang 	case PMU_GPIO_PORT0:
54536c2492SCaesar Wang 		clock_state = (mmio_read_32(PMUCRU_BASE +
55536c2492SCaesar Wang 					    CRU_PMU_CLKGATE_CON(1)) >>
56536c2492SCaesar Wang 					    PCLK_GPIO0_GATE_SHIFT) & 0x01;
579901dcf6SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
58536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
599901dcf6SCaesar Wang 					      PCLK_GPIO0_GATE_SHIFT));
609901dcf6SCaesar Wang 		break;
61536c2492SCaesar Wang 	case PMU_GPIO_PORT1:
62536c2492SCaesar Wang 		clock_state = (mmio_read_32(PMUCRU_BASE +
63536c2492SCaesar Wang 					    CRU_PMU_CLKGATE_CON(1)) >>
64536c2492SCaesar Wang 					    PCLK_GPIO1_GATE_SHIFT) & 0x01;
659901dcf6SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
66536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
679901dcf6SCaesar Wang 					      PCLK_GPIO1_GATE_SHIFT));
689901dcf6SCaesar Wang 		break;
69536c2492SCaesar Wang 	case GPIO_PORT2:
70536c2492SCaesar Wang 		clock_state = (mmio_read_32(CRU_BASE +
71536c2492SCaesar Wang 					    CRU_CLKGATE_CON(31)) >>
72536c2492SCaesar Wang 					    PCLK_GPIO2_GATE_SHIFT) & 0x01;
739901dcf6SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
74536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
759901dcf6SCaesar Wang 					      PCLK_GPIO2_GATE_SHIFT));
769901dcf6SCaesar Wang 		break;
77536c2492SCaesar Wang 	case GPIO_PORT3:
78536c2492SCaesar Wang 		clock_state = (mmio_read_32(CRU_BASE +
79536c2492SCaesar Wang 					    CRU_CLKGATE_CON(31)) >>
80536c2492SCaesar Wang 					    PCLK_GPIO3_GATE_SHIFT) & 0x01;
819901dcf6SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
82536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
83536c2492SCaesar Wang 					      PCLK_GPIO3_GATE_SHIFT));
84536c2492SCaesar Wang 		break;
85536c2492SCaesar Wang 	case GPIO_PORT4:
86536c2492SCaesar Wang 		clock_state = (mmio_read_32(CRU_BASE +
87536c2492SCaesar Wang 					    CRU_CLKGATE_CON(31)) >>
88536c2492SCaesar Wang 					    PCLK_GPIO4_GATE_SHIFT) & 0x01;
89536c2492SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
90536c2492SCaesar Wang 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
91536c2492SCaesar Wang 					      PCLK_GPIO4_GATE_SHIFT));
92536c2492SCaesar Wang 		break;
93536c2492SCaesar Wang 	default:
94536c2492SCaesar Wang 		break;
95536c2492SCaesar Wang 	}
96536c2492SCaesar Wang 
97536c2492SCaesar Wang 	return clock_state;
98536c2492SCaesar Wang }
99536c2492SCaesar Wang 
100536c2492SCaesar Wang /* restores old state of gpio clock */
101536c2492SCaesar Wang void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
102536c2492SCaesar Wang {
103536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio_number);
104536c2492SCaesar Wang 
105536c2492SCaesar Wang 	switch (port) {
106536c2492SCaesar Wang 	case PMU_GPIO_PORT0:
107536c2492SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
108536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
109536c2492SCaesar Wang 					      PCLK_GPIO0_GATE_SHIFT));
110536c2492SCaesar Wang 		break;
111536c2492SCaesar Wang 	case PMU_GPIO_PORT1:
112536c2492SCaesar Wang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
113536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
114536c2492SCaesar Wang 					      PCLK_GPIO1_GATE_SHIFT));
115536c2492SCaesar Wang 		break;
116536c2492SCaesar Wang 	case GPIO_PORT2:
117536c2492SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
118536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
119536c2492SCaesar Wang 					      PCLK_GPIO2_GATE_SHIFT));
120536c2492SCaesar Wang 		break;
121536c2492SCaesar Wang 	case GPIO_PORT3:
122536c2492SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
123536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
1249901dcf6SCaesar Wang 					      PCLK_GPIO3_GATE_SHIFT));
1259901dcf6SCaesar Wang 
1269901dcf6SCaesar Wang 		break;
127536c2492SCaesar Wang 	case GPIO_PORT4:
1289901dcf6SCaesar Wang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
129536c2492SCaesar Wang 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
1309901dcf6SCaesar Wang 					      PCLK_GPIO4_GATE_SHIFT));
1319901dcf6SCaesar Wang 		break;
1329901dcf6SCaesar Wang 	default:
1339901dcf6SCaesar Wang 		break;
1349901dcf6SCaesar Wang 	}
1359901dcf6SCaesar Wang }
1369901dcf6SCaesar Wang 
137536c2492SCaesar Wang static int get_pull(int gpio)
1389901dcf6SCaesar Wang {
139536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
140536c2492SCaesar Wang 	uint32_t bank = GET_GPIO_BANK(gpio);
141536c2492SCaesar Wang 	uint32_t id = GET_GPIO_ID(gpio);
142536c2492SCaesar Wang 	uint32_t val, clock_state;
1439901dcf6SCaesar Wang 
144536c2492SCaesar Wang 	assert((port < 5) && (bank < 4));
1459901dcf6SCaesar Wang 
146536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
147536c2492SCaesar Wang 
148536c2492SCaesar Wang 	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
149536c2492SCaesar Wang 		val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
150536c2492SCaesar Wang 				   port * 16 + bank * 4);
151536c2492SCaesar Wang 		val = (val >> (id * 2)) & GPIO_P_MASK;
152536c2492SCaesar Wang 	} else {
153536c2492SCaesar Wang 		val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P +
154536c2492SCaesar Wang 				   (port - 2) * 16 + bank * 4);
155536c2492SCaesar Wang 		val = (val >> (id * 2)) & GPIO_P_MASK;
156536c2492SCaesar Wang 	}
157536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
1589901dcf6SCaesar Wang 
1599901dcf6SCaesar Wang 	/*
1609901dcf6SCaesar Wang 	 * in gpio0a, gpio0b, gpio2c, gpio2d,
1619901dcf6SCaesar Wang 	 * 00: Z
1629901dcf6SCaesar Wang 	 * 01: pull down
1639901dcf6SCaesar Wang 	 * 10: Z
1649901dcf6SCaesar Wang 	 * 11: pull up
1659901dcf6SCaesar Wang 	 * different with other gpio, so need to correct it
1669901dcf6SCaesar Wang 	 */
167536c2492SCaesar Wang 	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
168536c2492SCaesar Wang 		if (val == 3)
169536c2492SCaesar Wang 			val = GPIO_PULL_UP;
170536c2492SCaesar Wang 		else if (val == 1)
171536c2492SCaesar Wang 			val = GPIO_PULL_DOWN;
172536c2492SCaesar Wang 		else
173536c2492SCaesar Wang 			val = 0;
174536c2492SCaesar Wang 	}
175536c2492SCaesar Wang 
176536c2492SCaesar Wang 	return val;
177536c2492SCaesar Wang }
178536c2492SCaesar Wang 
179536c2492SCaesar Wang static void set_pull(int gpio, int pull)
180536c2492SCaesar Wang {
181536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
182536c2492SCaesar Wang 	uint32_t bank = GET_GPIO_BANK(gpio);
183536c2492SCaesar Wang 	uint32_t id = GET_GPIO_ID(gpio);
184536c2492SCaesar Wang 	uint32_t clock_state;
185536c2492SCaesar Wang 
186536c2492SCaesar Wang 	assert((port < 5) && (bank < 4));
187536c2492SCaesar Wang 
188536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
189536c2492SCaesar Wang 
190536c2492SCaesar Wang 	/*
191536c2492SCaesar Wang 	 * in gpio0a, gpio0b, gpio2c, gpio2d,
192536c2492SCaesar Wang 	 * 00: Z
193536c2492SCaesar Wang 	 * 01: pull down
194536c2492SCaesar Wang 	 * 10: Z
195536c2492SCaesar Wang 	 * 11: pull up
196536c2492SCaesar Wang 	 * different with other gpio, so need to correct it
197536c2492SCaesar Wang 	 */
198536c2492SCaesar Wang 	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
1999901dcf6SCaesar Wang 		if (pull == GPIO_PULL_UP)
2009901dcf6SCaesar Wang 			pull = 3;
2019901dcf6SCaesar Wang 		else if (pull == GPIO_PULL_DOWN)
2029901dcf6SCaesar Wang 			pull = 1;
2039901dcf6SCaesar Wang 		else
2049901dcf6SCaesar Wang 			pull = 0;
2059901dcf6SCaesar Wang 	}
2069901dcf6SCaesar Wang 
2079901dcf6SCaesar Wang 	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
2089901dcf6SCaesar Wang 		mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
2099901dcf6SCaesar Wang 			      port * 16 + bank * 4,
2109901dcf6SCaesar Wang 			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
2119901dcf6SCaesar Wang 	} else {
2129901dcf6SCaesar Wang 		mmio_write_32(GRF_BASE + GRF_GPIO2A_P +
2139901dcf6SCaesar Wang 			      (port - 2) * 16 + bank * 4,
2149901dcf6SCaesar Wang 			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
2159901dcf6SCaesar Wang 	}
216536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2179901dcf6SCaesar Wang }
2189901dcf6SCaesar Wang 
2199901dcf6SCaesar Wang static void set_direction(int gpio, int direction)
2209901dcf6SCaesar Wang {
221536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
222536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
223536c2492SCaesar Wang 	uint32_t clock_state;
2249901dcf6SCaesar Wang 
2259901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2269901dcf6SCaesar Wang 
227536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2289901dcf6SCaesar Wang 
2299901dcf6SCaesar Wang 	/*
2309901dcf6SCaesar Wang 	 * in gpio.h
2319901dcf6SCaesar Wang 	 * #define GPIO_DIR_OUT	0
2329901dcf6SCaesar Wang 	 * #define GPIO_DIR_IN	1
2339901dcf6SCaesar Wang 	 * but rk3399 gpio direction 1: output, 0: input
2349901dcf6SCaesar Wang 	 * so need to revert direction value
2359901dcf6SCaesar Wang 	 */
2369901dcf6SCaesar Wang 	mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num);
237536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2389901dcf6SCaesar Wang }
2399901dcf6SCaesar Wang 
2409901dcf6SCaesar Wang static int get_direction(int gpio)
2419901dcf6SCaesar Wang {
242536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
243536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
244536c2492SCaesar Wang 	int direction, clock_state;
2459901dcf6SCaesar Wang 
2469901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2479901dcf6SCaesar Wang 
248536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2499901dcf6SCaesar Wang 
2509901dcf6SCaesar Wang 	/*
2519901dcf6SCaesar Wang 	 * in gpio.h
2529901dcf6SCaesar Wang 	 * #define GPIO_DIR_OUT	0
2539901dcf6SCaesar Wang 	 * #define GPIO_DIR_IN	1
2549901dcf6SCaesar Wang 	 * but rk3399 gpio direction 1: output, 0: input
2559901dcf6SCaesar Wang 	 * so need to revert direction value
2569901dcf6SCaesar Wang 	 */
2579901dcf6SCaesar Wang 	direction = !((mmio_read_32(gpio_port[port] +
2589901dcf6SCaesar Wang 				    SWPORTA_DDR) >> num) & 0x1);
259536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2609901dcf6SCaesar Wang 
2619901dcf6SCaesar Wang 	return direction;
2629901dcf6SCaesar Wang }
2639901dcf6SCaesar Wang 
2649901dcf6SCaesar Wang static int get_value(int gpio)
2659901dcf6SCaesar Wang {
266536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
267536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
268536c2492SCaesar Wang 	int value, clock_state;
2699901dcf6SCaesar Wang 
2709901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2719901dcf6SCaesar Wang 
272536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2739901dcf6SCaesar Wang 	value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1;
274536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2759901dcf6SCaesar Wang 
2769901dcf6SCaesar Wang 	return value;
2779901dcf6SCaesar Wang }
2789901dcf6SCaesar Wang 
2799901dcf6SCaesar Wang static void set_value(int gpio, int value)
2809901dcf6SCaesar Wang {
281536c2492SCaesar Wang 	uint32_t port = GET_GPIO_PORT(gpio);
282536c2492SCaesar Wang 	uint32_t num = GET_GPIO_NUM(gpio);
283536c2492SCaesar Wang 	uint32_t clock_state;
2849901dcf6SCaesar Wang 
2859901dcf6SCaesar Wang 	assert((port < 5) && (num < 32));
2869901dcf6SCaesar Wang 
287536c2492SCaesar Wang 	clock_state = gpio_get_clock(gpio);
2889901dcf6SCaesar Wang 	mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num,
2899901dcf6SCaesar Wang 							 !!value << num);
290536c2492SCaesar Wang 	gpio_put_clock(gpio, clock_state);
2919901dcf6SCaesar Wang }
2929901dcf6SCaesar Wang 
2939901dcf6SCaesar Wang const gpio_ops_t rk3399_gpio_ops = {
2949901dcf6SCaesar Wang 	.get_direction = get_direction,
2959901dcf6SCaesar Wang 	.set_direction = set_direction,
2969901dcf6SCaesar Wang 	.get_value = get_value,
2979901dcf6SCaesar Wang 	.set_value = set_value,
2989901dcf6SCaesar Wang 	.set_pull = set_pull,
299536c2492SCaesar Wang 	.get_pull = get_pull,
3009901dcf6SCaesar Wang };
3019901dcf6SCaesar Wang 
3029901dcf6SCaesar Wang void plat_rockchip_gpio_init(void)
3039901dcf6SCaesar Wang {
3049901dcf6SCaesar Wang 	gpio_init(&rk3399_gpio_ops);
3059901dcf6SCaesar Wang }
306