blob: 4995d56461e216a0aa4a73eb225a8d01887daaa7 [file] [log] [blame]
Caesar Wang038f6aa2016-05-25 19:21:43 +08001/*
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
41uint32_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
Caesar Wang884cb262016-09-10 02:42:32 +080055#define GPIO_PORT2 2
56#define GPIO_PORT3 3
57#define GPIO_PORT4 4
Caesar Wang038f6aa2016-05-25 19:21:43 +080058
59#define PMU_GRF_GPIO0A_P 0x40
60#define GRF_GPIO2A_P 0xe040
61#define GPIO_P_MASK 0x03
62
Caesar Wang884cb262016-09-10 02:42:32 +080063#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 */
69static int gpio_get_clock(uint32_t gpio_number)
Caesar Wang038f6aa2016-05-25 19:21:43 +080070{
Caesar Wang884cb262016-09-10 02:42:32 +080071 uint32_t port = GET_GPIO_PORT(gpio_number);
72 uint32_t clock_state = 0;
Caesar Wang038f6aa2016-05-25 19:21:43 +080073
74 assert(port < 5);
75
76 switch (port) {
Caesar Wang884cb262016-09-10 02:42:32 +080077 case PMU_GPIO_PORT0:
78 clock_state = (mmio_read_32(PMUCRU_BASE +
79 CRU_PMU_CLKGATE_CON(1)) >>
80 PCLK_GPIO0_GATE_SHIFT) & 0x01;
Caesar Wang038f6aa2016-05-25 19:21:43 +080081 mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
Caesar Wang884cb262016-09-10 02:42:32 +080082 BITS_WITH_WMASK(0, CLK_GATE_MASK,
Caesar Wang038f6aa2016-05-25 19:21:43 +080083 PCLK_GPIO0_GATE_SHIFT));
84 break;
Caesar Wang884cb262016-09-10 02:42:32 +080085 case PMU_GPIO_PORT1:
86 clock_state = (mmio_read_32(PMUCRU_BASE +
87 CRU_PMU_CLKGATE_CON(1)) >>
88 PCLK_GPIO1_GATE_SHIFT) & 0x01;
Caesar Wang038f6aa2016-05-25 19:21:43 +080089 mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
Caesar Wang884cb262016-09-10 02:42:32 +080090 BITS_WITH_WMASK(0, CLK_GATE_MASK,
Caesar Wang038f6aa2016-05-25 19:21:43 +080091 PCLK_GPIO1_GATE_SHIFT));
92 break;
Caesar Wang884cb262016-09-10 02:42:32 +080093 case GPIO_PORT2:
94 clock_state = (mmio_read_32(CRU_BASE +
95 CRU_CLKGATE_CON(31)) >>
96 PCLK_GPIO2_GATE_SHIFT) & 0x01;
Caesar Wang038f6aa2016-05-25 19:21:43 +080097 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
Caesar Wang884cb262016-09-10 02:42:32 +080098 BITS_WITH_WMASK(0, CLK_GATE_MASK,
Caesar Wang038f6aa2016-05-25 19:21:43 +080099 PCLK_GPIO2_GATE_SHIFT));
100 break;
Caesar Wang884cb262016-09-10 02:42:32 +0800101 case GPIO_PORT3:
102 clock_state = (mmio_read_32(CRU_BASE +
103 CRU_CLKGATE_CON(31)) >>
104 PCLK_GPIO3_GATE_SHIFT) & 0x01;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800105 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
Caesar Wang884cb262016-09-10 02:42:32 +0800106 BITS_WITH_WMASK(0, CLK_GATE_MASK,
Caesar Wang038f6aa2016-05-25 19:21:43 +0800107 PCLK_GPIO3_GATE_SHIFT));
Caesar Wang884cb262016-09-10 02:42:32 +0800108 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 */
125void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
126{
127 uint32_t port = GET_GPIO_PORT(gpio_number);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800128
Caesar Wang884cb262016-09-10 02:42:32 +0800129 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));
Caesar Wang038f6aa2016-05-25 19:21:43 +0800139 break;
Caesar Wang884cb262016-09-10 02:42:32 +0800140 case GPIO_PORT2:
Caesar Wang038f6aa2016-05-25 19:21:43 +0800141 mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
Caesar Wang884cb262016-09-10 02:42:32 +0800142 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,
Caesar Wang038f6aa2016-05-25 19:21:43 +0800154 PCLK_GPIO4_GATE_SHIFT));
155 break;
156 default:
157 break;
158 }
159}
160
Caesar Wang884cb262016-09-10 02:42:32 +0800161static 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
Caesar Wang038f6aa2016-05-25 19:21:43 +0800203static void set_pull(int gpio, int pull)
204{
Caesar Wang884cb262016-09-10 02:42:32 +0800205 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;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800209
Caesar Wang884cb262016-09-10 02:42:32 +0800210 assert((port < 5) && (bank < 4));
Caesar Wang038f6aa2016-05-25 19:21:43 +0800211
Caesar Wang884cb262016-09-10 02:42:32 +0800212 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800213
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 */
Caesar Wang884cb262016-09-10 02:42:32 +0800222 if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
Caesar Wang038f6aa2016-05-25 19:21:43 +0800223 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 }
Caesar Wang884cb262016-09-10 02:42:32 +0800240 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800241}
242
243static void set_direction(int gpio, int direction)
244{
Caesar Wang884cb262016-09-10 02:42:32 +0800245 uint32_t port = GET_GPIO_PORT(gpio);
246 uint32_t num = GET_GPIO_NUM(gpio);
247 uint32_t clock_state;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800248
249 assert((port < 5) && (num < 32));
250
Caesar Wang884cb262016-09-10 02:42:32 +0800251 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800252
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);
Caesar Wang884cb262016-09-10 02:42:32 +0800261 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800262}
263
264static int get_direction(int gpio)
265{
Caesar Wang884cb262016-09-10 02:42:32 +0800266 uint32_t port = GET_GPIO_PORT(gpio);
267 uint32_t num = GET_GPIO_NUM(gpio);
268 int direction, clock_state;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800269
270 assert((port < 5) && (num < 32));
271
Caesar Wang884cb262016-09-10 02:42:32 +0800272 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800273
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);
Caesar Wang884cb262016-09-10 02:42:32 +0800283 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800284
285 return direction;
286}
287
288static int get_value(int gpio)
289{
Caesar Wang884cb262016-09-10 02:42:32 +0800290 uint32_t port = GET_GPIO_PORT(gpio);
291 uint32_t num = GET_GPIO_NUM(gpio);
292 int value, clock_state;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800293
294 assert((port < 5) && (num < 32));
295
Caesar Wang884cb262016-09-10 02:42:32 +0800296 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800297 value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1;
Caesar Wang884cb262016-09-10 02:42:32 +0800298 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800299
300 return value;
301}
302
303static void set_value(int gpio, int value)
304{
Caesar Wang884cb262016-09-10 02:42:32 +0800305 uint32_t port = GET_GPIO_PORT(gpio);
306 uint32_t num = GET_GPIO_NUM(gpio);
307 uint32_t clock_state;
Caesar Wang038f6aa2016-05-25 19:21:43 +0800308
309 assert((port < 5) && (num < 32));
310
Caesar Wang884cb262016-09-10 02:42:32 +0800311 clock_state = gpio_get_clock(gpio);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800312 mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num,
313 !!value << num);
Caesar Wang884cb262016-09-10 02:42:32 +0800314 gpio_put_clock(gpio, clock_state);
Caesar Wang038f6aa2016-05-25 19:21:43 +0800315}
316
317const 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,
Caesar Wang884cb262016-09-10 02:42:32 +0800323 .get_pull = get_pull,
Caesar Wang038f6aa2016-05-25 19:21:43 +0800324};
325
326void plat_rockchip_gpio_init(void)
327{
328 gpio_init(&rk3399_gpio_ops);
329}