blob: e74c4d91a7de2cf85e781c0b467c782c1984cb6d [file] [log] [blame]
Caesar Wang038f6aa2016-05-25 19:21:43 +08001/*
2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Caesar Wang038f6aa2016-05-25 19:21:43 +08005 */
6#include <assert.h>
7#include <debug.h>
8#include <delay_timer.h>
9#include <errno.h>
10#include <gpio.h>
11#include <mmio.h>
Isla Mitchelle3631462017-07-14 10:46:32 +010012#include <plat_private.h>
Caesar Wang038f6aa2016-05-25 19:21:43 +080013#include <platform.h>
14#include <platform_def.h>
Caesar Wang038f6aa2016-05-25 19:21:43 +080015#include <soc.h>
16
17uint32_t gpio_port[] = {
18 GPIO0_BASE,
19 GPIO1_BASE,
20 GPIO2_BASE,
21 GPIO3_BASE,
22 GPIO4_BASE,
23};
24
Lin Huang2c60b5f2017-05-18 18:04:25 +080025struct {
26 uint32_t swporta_dr;
27 uint32_t swporta_ddr;
28 uint32_t inten;
29 uint32_t intmask;
30 uint32_t inttype_level;
31 uint32_t int_polarity;
32 uint32_t debounce;
33 uint32_t ls_sync;
34} store_gpio[3];
35
36static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1];
37
Caesar Wang038f6aa2016-05-25 19:21:43 +080038#define SWPORTA_DR 0x00
39#define SWPORTA_DDR 0x04
Lin Huang2c60b5f2017-05-18 18:04:25 +080040#define INTEN 0x30
41#define INTMASK 0x34
42#define INTTYPE_LEVEL 0x38
43#define INT_POLARITY 0x3c
44#define DEBOUNCE 0x48
45#define LS_SYNC 0x60
Caesar Wang038f6aa2016-05-25 19:21:43 +080046
Lin Huang2c60b5f2017-05-18 18:04:25 +080047#define EXT_PORTA 0x50
Caesar Wang038f6aa2016-05-25 19:21:43 +080048#define PMU_GPIO_PORT0 0
49#define PMU_GPIO_PORT1 1
Caesar Wang884cb262016-09-10 02:42:32 +080050#define GPIO_PORT2 2
51#define GPIO_PORT3 3
52#define GPIO_PORT4 4
Caesar Wang038f6aa2016-05-25 19:21:43 +080053
54#define PMU_GRF_GPIO0A_P 0x40
55#define GRF_GPIO2A_P 0xe040
56#define GPIO_P_MASK 0x03
57
Caesar Wang884cb262016-09-10 02:42:32 +080058#define GET_GPIO_PORT(pin) (pin / 32)
59#define GET_GPIO_NUM(pin) (pin % 32)
60#define GET_GPIO_BANK(pin) ((pin % 32) / 8)
61#define GET_GPIO_ID(pin) ((pin % 32) % 8)
62
63/* returns old clock state, enables clock, in order to do GPIO access */
64static int gpio_get_clock(uint32_t gpio_number)
Caesar Wang038f6aa2016-05-25 19:21:43 +080065{
Caesar Wang884cb262016-09-10 02:42:32 +080066 uint32_t port = GET_GPIO_PORT(gpio_number);
67 uint32_t clock_state = 0;
Caesar Wang038f6aa2016-05-25 19:21:43 +080068
69 assert(port < 5);
70
71 switch (port) {
Caesar Wang884cb262016-09-10 02:42:32 +080072 case PMU_GPIO_PORT0:
73 clock_state = (mmio_read_32(PMUCRU_BASE +
74 CRU_PMU_CLKGATE_CON(1)) >>
75 PCLK_GPIO0_GATE_SHIFT) & 0x01;
Caesar Wang038f6aa2016-05-25 19:21:43 +080076 mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
Caesar Wang884cb262016-09-10 02:42:32 +080077 BITS_WITH_WMASK(0, CLK_GATE_MASK,
Caesar Wang038f6aa2016-05-25 19:21:43 +080078 PCLK_GPIO0_GATE_SHIFT));
79 break;
Caesar Wang884cb262016-09-10 02:42:32 +080080 case PMU_GPIO_PORT1:
81 clock_state = (mmio_read_32(PMUCRU_BASE +
82 CRU_PMU_CLKGATE_CON(1)) >>
83 PCLK_GPIO1_GATE_SHIFT) & 0x01;
Caesar Wang038f6aa2016-05-25 19:21:43 +080084 mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
Caesar Wang884cb262016-09-10 02:42:32 +080085 BITS_WITH_WMASK(0, CLK_GATE_MASK,
Caesar Wang038f6aa2016-05-25 19:21:43 +080086 PCLK_GPIO1_GATE_SHIFT));
87 break;
Caesar Wang884cb262016-09-10 02:42:32 +080088 case GPIO_PORT2:
89 clock_state = (mmio_read_32(CRU_BASE +
90 CRU_CLKGATE_CON(31)) >>
91 PCLK_GPIO2_GATE_SHIFT) & 0x01;
Caesar Wang038f6aa2016-05-25 19:21:43 +080092 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
Caesar Wang884cb262016-09-10 02:42:32 +080093 BITS_WITH_WMASK(0, CLK_GATE_MASK,
Caesar Wang038f6aa2016-05-25 19:21:43 +080094 PCLK_GPIO2_GATE_SHIFT));
95 break;
Caesar Wang884cb262016-09-10 02:42:32 +080096 case GPIO_PORT3:
97 clock_state = (mmio_read_32(CRU_BASE +
98 CRU_CLKGATE_CON(31)) >>
99 PCLK_GPIO3_GATE_SHIFT) & 0x01;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800100 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
Caesar Wang884cb262016-09-10 02:42:32 +0800101 BITS_WITH_WMASK(0, CLK_GATE_MASK,
Caesar Wang038f6aa2016-05-25 19:21:43 +0800102 PCLK_GPIO3_GATE_SHIFT));
Caesar Wang884cb262016-09-10 02:42:32 +0800103 break;
104 case GPIO_PORT4:
105 clock_state = (mmio_read_32(CRU_BASE +
106 CRU_CLKGATE_CON(31)) >>
107 PCLK_GPIO4_GATE_SHIFT) & 0x01;
108 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
109 BITS_WITH_WMASK(0, CLK_GATE_MASK,
110 PCLK_GPIO4_GATE_SHIFT));
111 break;
112 default:
113 break;
114 }
115
116 return clock_state;
117}
118
119/* restores old state of gpio clock */
120void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
121{
122 uint32_t port = GET_GPIO_PORT(gpio_number);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800123
Caesar Wang884cb262016-09-10 02:42:32 +0800124 switch (port) {
125 case PMU_GPIO_PORT0:
126 mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
127 BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
128 PCLK_GPIO0_GATE_SHIFT));
129 break;
130 case PMU_GPIO_PORT1:
131 mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
132 BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
133 PCLK_GPIO1_GATE_SHIFT));
Caesar Wang038f6aa2016-05-25 19:21:43 +0800134 break;
Caesar Wang884cb262016-09-10 02:42:32 +0800135 case GPIO_PORT2:
Caesar Wang038f6aa2016-05-25 19:21:43 +0800136 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
Caesar Wang884cb262016-09-10 02:42:32 +0800137 BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
138 PCLK_GPIO2_GATE_SHIFT));
139 break;
140 case GPIO_PORT3:
141 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
142 BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
143 PCLK_GPIO3_GATE_SHIFT));
144
145 break;
146 case GPIO_PORT4:
147 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
148 BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
Caesar Wang038f6aa2016-05-25 19:21:43 +0800149 PCLK_GPIO4_GATE_SHIFT));
150 break;
151 default:
152 break;
153 }
154}
155
Caesar Wang884cb262016-09-10 02:42:32 +0800156static int get_pull(int gpio)
157{
158 uint32_t port = GET_GPIO_PORT(gpio);
159 uint32_t bank = GET_GPIO_BANK(gpio);
160 uint32_t id = GET_GPIO_ID(gpio);
161 uint32_t val, clock_state;
162
163 assert((port < 5) && (bank < 4));
164
165 clock_state = gpio_get_clock(gpio);
166
167 if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
168 val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
169 port * 16 + bank * 4);
170 val = (val >> (id * 2)) & GPIO_P_MASK;
171 } else {
172 val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P +
173 (port - 2) * 16 + bank * 4);
174 val = (val >> (id * 2)) & GPIO_P_MASK;
175 }
176 gpio_put_clock(gpio, clock_state);
177
178 /*
179 * in gpio0a, gpio0b, gpio2c, gpio2d,
180 * 00: Z
181 * 01: pull down
182 * 10: Z
183 * 11: pull up
184 * different with other gpio, so need to correct it
185 */
186 if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
187 if (val == 3)
188 val = GPIO_PULL_UP;
189 else if (val == 1)
190 val = GPIO_PULL_DOWN;
191 else
192 val = 0;
193 }
194
195 return val;
196}
197
Caesar Wang038f6aa2016-05-25 19:21:43 +0800198static void set_pull(int gpio, int pull)
199{
Caesar Wang884cb262016-09-10 02:42:32 +0800200 uint32_t port = GET_GPIO_PORT(gpio);
201 uint32_t bank = GET_GPIO_BANK(gpio);
202 uint32_t id = GET_GPIO_ID(gpio);
203 uint32_t clock_state;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800204
Caesar Wang884cb262016-09-10 02:42:32 +0800205 assert((port < 5) && (bank < 4));
Caesar Wang038f6aa2016-05-25 19:21:43 +0800206
Caesar Wang884cb262016-09-10 02:42:32 +0800207 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800208
209 /*
210 * in gpio0a, gpio0b, gpio2c, gpio2d,
211 * 00: Z
212 * 01: pull down
213 * 10: Z
214 * 11: pull up
215 * different with other gpio, so need to correct it
216 */
Caesar Wang884cb262016-09-10 02:42:32 +0800217 if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
Caesar Wang038f6aa2016-05-25 19:21:43 +0800218 if (pull == GPIO_PULL_UP)
219 pull = 3;
220 else if (pull == GPIO_PULL_DOWN)
221 pull = 1;
222 else
223 pull = 0;
224 }
225
226 if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
227 mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
228 port * 16 + bank * 4,
229 BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
230 } else {
231 mmio_write_32(GRF_BASE + GRF_GPIO2A_P +
232 (port - 2) * 16 + bank * 4,
233 BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
234 }
Caesar Wang884cb262016-09-10 02:42:32 +0800235 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800236}
237
238static void set_direction(int gpio, int direction)
239{
Caesar Wang884cb262016-09-10 02:42:32 +0800240 uint32_t port = GET_GPIO_PORT(gpio);
241 uint32_t num = GET_GPIO_NUM(gpio);
242 uint32_t clock_state;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800243
244 assert((port < 5) && (num < 32));
245
Caesar Wang884cb262016-09-10 02:42:32 +0800246 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800247
248 /*
249 * in gpio.h
250 * #define GPIO_DIR_OUT 0
251 * #define GPIO_DIR_IN 1
252 * but rk3399 gpio direction 1: output, 0: input
253 * so need to revert direction value
254 */
255 mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num);
Caesar Wang884cb262016-09-10 02:42:32 +0800256 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800257}
258
259static int get_direction(int gpio)
260{
Caesar Wang884cb262016-09-10 02:42:32 +0800261 uint32_t port = GET_GPIO_PORT(gpio);
262 uint32_t num = GET_GPIO_NUM(gpio);
263 int direction, clock_state;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800264
265 assert((port < 5) && (num < 32));
266
Caesar Wang884cb262016-09-10 02:42:32 +0800267 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800268
269 /*
270 * in gpio.h
271 * #define GPIO_DIR_OUT 0
272 * #define GPIO_DIR_IN 1
273 * but rk3399 gpio direction 1: output, 0: input
274 * so need to revert direction value
275 */
276 direction = !((mmio_read_32(gpio_port[port] +
277 SWPORTA_DDR) >> num) & 0x1);
Caesar Wang884cb262016-09-10 02:42:32 +0800278 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800279
280 return direction;
281}
282
283static int get_value(int gpio)
284{
Caesar Wang884cb262016-09-10 02:42:32 +0800285 uint32_t port = GET_GPIO_PORT(gpio);
286 uint32_t num = GET_GPIO_NUM(gpio);
287 int value, clock_state;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800288
289 assert((port < 5) && (num < 32));
290
Caesar Wang884cb262016-09-10 02:42:32 +0800291 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800292 value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1;
Caesar Wang884cb262016-09-10 02:42:32 +0800293 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800294
295 return value;
296}
297
298static void set_value(int gpio, int value)
299{
Caesar Wang884cb262016-09-10 02:42:32 +0800300 uint32_t port = GET_GPIO_PORT(gpio);
301 uint32_t num = GET_GPIO_NUM(gpio);
302 uint32_t clock_state;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800303
304 assert((port < 5) && (num < 32));
305
Caesar Wang884cb262016-09-10 02:42:32 +0800306 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800307 mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num,
308 !!value << num);
Caesar Wang884cb262016-09-10 02:42:32 +0800309 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800310}
311
Lin Huang2c60b5f2017-05-18 18:04:25 +0800312void plat_rockchip_save_gpio(void)
313{
314 int i;
315 uint32_t cru_gate_save;
316
317 cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
318
319 /*
320 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
321 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
322 * and we do not care gpio0 and gpio1 clock gate, since we never
323 * gating them
324 */
325 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
326 BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
327
328 /*
329 * since gpio0, gpio1 are pmugpio, they will keep ther value
330 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
331 * register value
332 */
333 for (i = 2; i < 5; i++) {
334 store_gpio[i - 2].swporta_dr =
335 mmio_read_32(gpio_port[i] + SWPORTA_DR);
336 store_gpio[i - 2].swporta_ddr =
337 mmio_read_32(gpio_port[i] + SWPORTA_DDR);
338 store_gpio[i - 2].inten =
339 mmio_read_32(gpio_port[i] + INTEN);
340 store_gpio[i - 2].intmask =
341 mmio_read_32(gpio_port[i] + INTMASK);
342 store_gpio[i - 2].inttype_level =
343 mmio_read_32(gpio_port[i] + INTTYPE_LEVEL);
344 store_gpio[i - 2].int_polarity =
345 mmio_read_32(gpio_port[i] + INT_POLARITY);
346 store_gpio[i - 2].debounce =
347 mmio_read_32(gpio_port[i] + DEBOUNCE);
348 store_gpio[i - 2].ls_sync =
349 mmio_read_32(gpio_port[i] + LS_SYNC);
350 }
351 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
352 cru_gate_save | REG_SOC_WMSK);
353
354 /*
355 * gpio0, gpio1 in pmuiomux, they will keep ther value
356 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
357 * iomux register value
358 */
359 for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
360 store_grf_gpio[i] =
361 mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4);
362}
363
364void plat_rockchip_restore_gpio(void)
365{
366 int i;
367 uint32_t cru_gate_save;
368
369 for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
370 mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
371 REG_SOC_WMSK | store_grf_gpio[i]);
372
373 cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
374
375 /*
376 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
377 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
378 * and we do not care gpio0 and gpio1 clock gate, since we never
379 * gating them
380 */
381 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
382 BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
383
384 for (i = 2; i < 5; i++) {
385 mmio_write_32(gpio_port[i] + SWPORTA_DR,
386 store_gpio[i - 2].swporta_dr);
387 mmio_write_32(gpio_port[i] + SWPORTA_DDR,
388 store_gpio[i - 2].swporta_ddr);
389 mmio_write_32(gpio_port[i] + INTEN, store_gpio[i - 2].inten);
390 mmio_write_32(gpio_port[i] + INTMASK,
391 store_gpio[i - 2].intmask);
392 mmio_write_32(gpio_port[i] + INTTYPE_LEVEL,
393 store_gpio[i - 2].inttype_level);
394 mmio_write_32(gpio_port[i] + INT_POLARITY,
395 store_gpio[i - 2].int_polarity);
396 mmio_write_32(gpio_port[i] + DEBOUNCE,
397 store_gpio[i - 2].debounce);
398 mmio_write_32(gpio_port[i] + LS_SYNC,
399 store_gpio[i - 2].ls_sync);
400 }
401 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
402 cru_gate_save | REG_SOC_WMSK);
403}
404
Caesar Wang038f6aa2016-05-25 19:21:43 +0800405const gpio_ops_t rk3399_gpio_ops = {
406 .get_direction = get_direction,
407 .set_direction = set_direction,
408 .get_value = get_value,
409 .set_value = set_value,
410 .set_pull = set_pull,
Caesar Wang884cb262016-09-10 02:42:32 +0800411 .get_pull = get_pull,
Caesar Wang038f6aa2016-05-25 19:21:43 +0800412};
413
414void plat_rockchip_gpio_init(void)
415{
416 gpio_init(&rk3399_gpio_ops);
417}