xref: /rk3399_ARM-atf/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c (revision 51faada71a219a8b94cd8d8e423f0f22e9da4d8f)
1 /*
2  * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of ARM nor the names of its contributors may be used
15  * to endorse or promote products derived from this software without specific
16  * prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 #include <assert.h>
31 #include <debug.h>
32 #include <delay_timer.h>
33 #include <errno.h>
34 #include <gpio.h>
35 #include <mmio.h>
36 #include <platform.h>
37 #include <platform_def.h>
38 #include <plat_private.h>
39 #include <soc.h>
40 
41 uint32_t gpio_port[] = {
42 	GPIO0_BASE,
43 	GPIO1_BASE,
44 	GPIO2_BASE,
45 	GPIO3_BASE,
46 	GPIO4_BASE,
47 };
48 
49 #define SWPORTA_DR	0x00
50 #define SWPORTA_DDR	0x04
51 #define EXT_PORTA	0x50
52 
53 #define PMU_GPIO_PORT0	0
54 #define PMU_GPIO_PORT1	1
55 #define GPIO_PORT2	2
56 #define GPIO_PORT3	3
57 #define GPIO_PORT4	4
58 
59 #define PMU_GRF_GPIO0A_P	0x40
60 #define GRF_GPIO2A_P		0xe040
61 #define GPIO_P_MASK		0x03
62 
63 #define GET_GPIO_PORT(pin)	(pin / 32)
64 #define GET_GPIO_NUM(pin)	(pin % 32)
65 #define GET_GPIO_BANK(pin)	((pin % 32) / 8)
66 #define GET_GPIO_ID(pin)	((pin % 32) % 8)
67 
68 /* returns old clock state, enables clock, in order to do GPIO access */
69 static int gpio_get_clock(uint32_t gpio_number)
70 {
71 	uint32_t port = GET_GPIO_PORT(gpio_number);
72 	uint32_t clock_state = 0;
73 
74 	assert(port < 5);
75 
76 	switch (port) {
77 	case PMU_GPIO_PORT0:
78 		clock_state = (mmio_read_32(PMUCRU_BASE +
79 					    CRU_PMU_CLKGATE_CON(1)) >>
80 					    PCLK_GPIO0_GATE_SHIFT) & 0x01;
81 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
82 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
83 					      PCLK_GPIO0_GATE_SHIFT));
84 		break;
85 	case PMU_GPIO_PORT1:
86 		clock_state = (mmio_read_32(PMUCRU_BASE +
87 					    CRU_PMU_CLKGATE_CON(1)) >>
88 					    PCLK_GPIO1_GATE_SHIFT) & 0x01;
89 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
90 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
91 					      PCLK_GPIO1_GATE_SHIFT));
92 		break;
93 	case GPIO_PORT2:
94 		clock_state = (mmio_read_32(CRU_BASE +
95 					    CRU_CLKGATE_CON(31)) >>
96 					    PCLK_GPIO2_GATE_SHIFT) & 0x01;
97 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
98 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
99 					      PCLK_GPIO2_GATE_SHIFT));
100 		break;
101 	case GPIO_PORT3:
102 		clock_state = (mmio_read_32(CRU_BASE +
103 					    CRU_CLKGATE_CON(31)) >>
104 					    PCLK_GPIO3_GATE_SHIFT) & 0x01;
105 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
106 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
107 					      PCLK_GPIO3_GATE_SHIFT));
108 		break;
109 	case GPIO_PORT4:
110 		clock_state = (mmio_read_32(CRU_BASE +
111 					    CRU_CLKGATE_CON(31)) >>
112 					    PCLK_GPIO4_GATE_SHIFT) & 0x01;
113 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
114 			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
115 					      PCLK_GPIO4_GATE_SHIFT));
116 		break;
117 	default:
118 		break;
119 	}
120 
121 	return clock_state;
122 }
123 
124 /* restores old state of gpio clock */
125 void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
126 {
127 	uint32_t port = GET_GPIO_PORT(gpio_number);
128 
129 	switch (port) {
130 	case PMU_GPIO_PORT0:
131 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
132 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
133 					      PCLK_GPIO0_GATE_SHIFT));
134 		break;
135 	case PMU_GPIO_PORT1:
136 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
137 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
138 					      PCLK_GPIO1_GATE_SHIFT));
139 		break;
140 	case GPIO_PORT2:
141 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
142 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
143 					      PCLK_GPIO2_GATE_SHIFT));
144 		break;
145 	case GPIO_PORT3:
146 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
147 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
148 					      PCLK_GPIO3_GATE_SHIFT));
149 
150 		break;
151 	case GPIO_PORT4:
152 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
153 			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
154 					      PCLK_GPIO4_GATE_SHIFT));
155 		break;
156 	default:
157 		break;
158 	}
159 }
160 
161 static int get_pull(int gpio)
162 {
163 	uint32_t port = GET_GPIO_PORT(gpio);
164 	uint32_t bank = GET_GPIO_BANK(gpio);
165 	uint32_t id = GET_GPIO_ID(gpio);
166 	uint32_t val, clock_state;
167 
168 	assert((port < 5) && (bank < 4));
169 
170 	clock_state = gpio_get_clock(gpio);
171 
172 	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
173 		val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
174 				   port * 16 + bank * 4);
175 		val = (val >> (id * 2)) & GPIO_P_MASK;
176 	} else {
177 		val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P +
178 				   (port - 2) * 16 + bank * 4);
179 		val = (val >> (id * 2)) & GPIO_P_MASK;
180 	}
181 	gpio_put_clock(gpio, clock_state);
182 
183 	/*
184 	 * in gpio0a, gpio0b, gpio2c, gpio2d,
185 	 * 00: Z
186 	 * 01: pull down
187 	 * 10: Z
188 	 * 11: pull up
189 	 * different with other gpio, so need to correct it
190 	 */
191 	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
192 		if (val == 3)
193 			val = GPIO_PULL_UP;
194 		else if (val == 1)
195 			val = GPIO_PULL_DOWN;
196 		else
197 			val = 0;
198 	}
199 
200 	return val;
201 }
202 
203 static void set_pull(int gpio, int pull)
204 {
205 	uint32_t port = GET_GPIO_PORT(gpio);
206 	uint32_t bank = GET_GPIO_BANK(gpio);
207 	uint32_t id = GET_GPIO_ID(gpio);
208 	uint32_t clock_state;
209 
210 	assert((port < 5) && (bank < 4));
211 
212 	clock_state = gpio_get_clock(gpio);
213 
214 	/*
215 	 * in gpio0a, gpio0b, gpio2c, gpio2d,
216 	 * 00: Z
217 	 * 01: pull down
218 	 * 10: Z
219 	 * 11: pull up
220 	 * different with other gpio, so need to correct it
221 	 */
222 	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
223 		if (pull == GPIO_PULL_UP)
224 			pull = 3;
225 		else if (pull == GPIO_PULL_DOWN)
226 			pull = 1;
227 		else
228 			pull = 0;
229 	}
230 
231 	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
232 		mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
233 			      port * 16 + bank * 4,
234 			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
235 	} else {
236 		mmio_write_32(GRF_BASE + GRF_GPIO2A_P +
237 			      (port - 2) * 16 + bank * 4,
238 			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
239 	}
240 	gpio_put_clock(gpio, clock_state);
241 }
242 
243 static void set_direction(int gpio, int direction)
244 {
245 	uint32_t port = GET_GPIO_PORT(gpio);
246 	uint32_t num = GET_GPIO_NUM(gpio);
247 	uint32_t clock_state;
248 
249 	assert((port < 5) && (num < 32));
250 
251 	clock_state = gpio_get_clock(gpio);
252 
253 	/*
254 	 * in gpio.h
255 	 * #define GPIO_DIR_OUT	0
256 	 * #define GPIO_DIR_IN	1
257 	 * but rk3399 gpio direction 1: output, 0: input
258 	 * so need to revert direction value
259 	 */
260 	mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num);
261 	gpio_put_clock(gpio, clock_state);
262 }
263 
264 static int get_direction(int gpio)
265 {
266 	uint32_t port = GET_GPIO_PORT(gpio);
267 	uint32_t num = GET_GPIO_NUM(gpio);
268 	int direction, clock_state;
269 
270 	assert((port < 5) && (num < 32));
271 
272 	clock_state = gpio_get_clock(gpio);
273 
274 	/*
275 	 * in gpio.h
276 	 * #define GPIO_DIR_OUT	0
277 	 * #define GPIO_DIR_IN	1
278 	 * but rk3399 gpio direction 1: output, 0: input
279 	 * so need to revert direction value
280 	 */
281 	direction = !((mmio_read_32(gpio_port[port] +
282 				    SWPORTA_DDR) >> num) & 0x1);
283 	gpio_put_clock(gpio, clock_state);
284 
285 	return direction;
286 }
287 
288 static int get_value(int gpio)
289 {
290 	uint32_t port = GET_GPIO_PORT(gpio);
291 	uint32_t num = GET_GPIO_NUM(gpio);
292 	int value, clock_state;
293 
294 	assert((port < 5) && (num < 32));
295 
296 	clock_state = gpio_get_clock(gpio);
297 	value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1;
298 	gpio_put_clock(gpio, clock_state);
299 
300 	return value;
301 }
302 
303 static void set_value(int gpio, int value)
304 {
305 	uint32_t port = GET_GPIO_PORT(gpio);
306 	uint32_t num = GET_GPIO_NUM(gpio);
307 	uint32_t clock_state;
308 
309 	assert((port < 5) && (num < 32));
310 
311 	clock_state = gpio_get_clock(gpio);
312 	mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num,
313 							 !!value << num);
314 	gpio_put_clock(gpio, clock_state);
315 }
316 
317 const gpio_ops_t rk3399_gpio_ops = {
318 	.get_direction = get_direction,
319 	.set_direction = set_direction,
320 	.get_value = get_value,
321 	.set_value = set_value,
322 	.set_pull = set_pull,
323 	.get_pull = get_pull,
324 };
325 
326 void plat_rockchip_gpio_init(void)
327 {
328 	gpio_init(&rk3399_gpio_ops);
329 }
330