blob: e4463a223f7b235e323d67eda270586f0c7c62f5 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Ian Campbellabce2c62014-06-05 19:00:15 +01002/*
3 * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
4 *
5 * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c:
6 *
7 * (C) Copyright 2007-2011
8 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
9 * Tom Cubie <tangliang@allwinnertech.com>
Ian Campbellabce2c62014-06-05 19:00:15 +010010 */
11
12#include <common.h>
Simon Glass7aa97482014-10-30 20:25:49 -060013#include <dm.h>
14#include <errno.h>
15#include <fdtdec.h>
16#include <malloc.h>
Ian Campbellabce2c62014-06-05 19:00:15 +010017#include <asm/io.h>
18#include <asm/gpio.h>
Chen-Yu Tsai4694dc52016-07-22 16:12:59 +080019#include <dt-bindings/gpio/gpio.h>
Andre Przywara207ed0a2022-09-06 10:36:38 +010020#include <sunxi_gpio.h>
Ian Campbellabce2c62014-06-05 19:00:15 +010021
Andre Przywara20b78c52022-09-06 10:36:38 +010022/*
23 * =======================================================================
24 * Low level GPIO/pin controller access functions, to be shared by non-DM
25 * SPL code and the DM pinctrl/GPIO drivers.
26 * The functions ending in "bank" take a base pointer to a GPIO bank, and
27 * the pin offset is relative to that bank.
28 * The functions without "bank" in their name take a linear GPIO number,
29 * covering all ports, and starting at 0 for PortA.
30 * =======================================================================
31 */
32
Andre Przywara20b78c52022-09-06 10:36:38 +010033#define GPIO_BANK(pin) ((pin) >> 5)
34#define GPIO_NUM(pin) ((pin) & 0x1f)
35
Andre Przywara30097ee2022-09-05 18:12:39 +010036#define GPIO_CFG_REG_OFFSET 0x00
Andre Przywara20b78c52022-09-06 10:36:38 +010037#define GPIO_CFG_INDEX(pin) (((pin) & 0x1f) >> 3)
38#define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1f) & 0x7) << 2)
39
Andre Przywara30097ee2022-09-05 18:12:39 +010040#define GPIO_DAT_REG_OFFSET 0x10
41
42#define GPIO_DRV_REG_OFFSET 0x14
Andre Przywara452369c2022-09-06 12:12:50 +010043
44/* Newer SoCs use a slightly different register layout */
45#ifdef CONFIG_SUNXI_NEW_PINCTRL
46/* pin drive strength: 4 bits per pin */
47#define GPIO_DRV_INDEX(pin) ((pin) / 8)
48#define GPIO_DRV_OFFSET(pin) (((pin) % 8) * 4)
49
50#define GPIO_PULL_REG_OFFSET 0x24
51
52#else /* older generation pin controllers */
53/* pin drive strength: 2 bits per pin */
54#define GPIO_DRV_INDEX(pin) ((pin) / 16)
55#define GPIO_DRV_OFFSET(pin) (((pin) % 16) * 2)
Andre Przywara20b78c52022-09-06 10:36:38 +010056
Andre Przywara30097ee2022-09-05 18:12:39 +010057#define GPIO_PULL_REG_OFFSET 0x1c
Andre Przywara452369c2022-09-06 12:12:50 +010058#endif
59
Andre Przywara20b78c52022-09-06 10:36:38 +010060#define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4)
61#define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
62
Andre Przywara30097ee2022-09-05 18:12:39 +010063static void* BANK_TO_GPIO(int bank)
Andre Przywara20b78c52022-09-06 10:36:38 +010064{
Andre Przywara30097ee2022-09-05 18:12:39 +010065 void *pio_base;
Andre Przywara20b78c52022-09-06 10:36:38 +010066
Andre Przywara30097ee2022-09-05 18:12:39 +010067 if (bank < SUNXI_GPIO_L) {
68 pio_base = (void *)(uintptr_t)SUNXI_PIO_BASE;
69 } else {
70 pio_base = (void *)(uintptr_t)SUNXI_R_PIO_BASE;
71 bank -= SUNXI_GPIO_L;
72 }
73
74 return pio_base + bank * SUNXI_PINCTRL_BANK_SIZE;
75}
76
77void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
78{
79 u32 index = GPIO_CFG_INDEX(pin_offset);
80 u32 offset = GPIO_CFG_OFFSET(pin_offset);
81
82 clrsetbits_le32(bank_base + GPIO_CFG_REG_OFFSET + index * 4,
83 0xfU << offset, val << offset);
Andre Przywara20b78c52022-09-06 10:36:38 +010084}
85
86void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
87{
88 u32 bank = GPIO_BANK(pin);
Andre Przywara30097ee2022-09-05 18:12:39 +010089 void *pio = BANK_TO_GPIO(bank);
Andre Przywara20b78c52022-09-06 10:36:38 +010090
Andre Przywara30097ee2022-09-05 18:12:39 +010091 sunxi_gpio_set_cfgbank(pio, GPIO_NUM(pin), val);
Andre Przywara20b78c52022-09-06 10:36:38 +010092}
93
Andre Przywara30097ee2022-09-05 18:12:39 +010094int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset)
Andre Przywara20b78c52022-09-06 10:36:38 +010095{
Andre Przywara30097ee2022-09-05 18:12:39 +010096 u32 index = GPIO_CFG_INDEX(pin_offset);
97 u32 offset = GPIO_CFG_OFFSET(pin_offset);
Andre Przywara20b78c52022-09-06 10:36:38 +010098 u32 cfg;
99
Andre Przywara30097ee2022-09-05 18:12:39 +0100100 cfg = readl(bank_base + GPIO_CFG_REG_OFFSET + index * 4);
Andre Przywara20b78c52022-09-06 10:36:38 +0100101 cfg >>= offset;
102
103 return cfg & 0xf;
104}
105
106int sunxi_gpio_get_cfgpin(u32 pin)
107{
108 u32 bank = GPIO_BANK(pin);
Andre Przywara30097ee2022-09-05 18:12:39 +0100109 void *bank_base = BANK_TO_GPIO(bank);
Andre Przywara20b78c52022-09-06 10:36:38 +0100110
Andre Przywara30097ee2022-09-05 18:12:39 +0100111 return sunxi_gpio_get_cfgbank(bank_base, GPIO_NUM(pin));
Andre Przywara20b78c52022-09-06 10:36:38 +0100112}
113
Andre Przywara30097ee2022-09-05 18:12:39 +0100114static void sunxi_gpio_set_value_bank(void *bank_base, int pin, bool set)
Andre Przywara316ec7f2022-09-06 10:07:18 +0100115{
116 u32 mask = 1U << pin;
117
Andre Przywara30097ee2022-09-05 18:12:39 +0100118 clrsetbits_le32(bank_base + GPIO_DAT_REG_OFFSET,
119 set ? 0 : mask, set ? mask : 0);
Andre Przywara316ec7f2022-09-06 10:07:18 +0100120}
121
Andre Przywara30097ee2022-09-05 18:12:39 +0100122static int sunxi_gpio_get_value_bank(void *bank_base, int pin)
Andre Przywara316ec7f2022-09-06 10:07:18 +0100123{
Andre Przywara30097ee2022-09-05 18:12:39 +0100124 return !!(readl(bank_base + GPIO_DAT_REG_OFFSET) & (1U << pin));
Andre Przywara316ec7f2022-09-06 10:07:18 +0100125}
126
Andre Przywara20b78c52022-09-06 10:36:38 +0100127void sunxi_gpio_set_drv(u32 pin, u32 val)
128{
129 u32 bank = GPIO_BANK(pin);
Andre Przywara30097ee2022-09-05 18:12:39 +0100130 void *bank_base = BANK_TO_GPIO(bank);
Andre Przywara20b78c52022-09-06 10:36:38 +0100131
Andre Przywara30097ee2022-09-05 18:12:39 +0100132 sunxi_gpio_set_drv_bank(bank_base, GPIO_NUM(pin), val);
Andre Przywara20b78c52022-09-06 10:36:38 +0100133}
134
Andre Przywara30097ee2022-09-05 18:12:39 +0100135void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val)
Andre Przywara20b78c52022-09-06 10:36:38 +0100136{
Andre Przywara30097ee2022-09-05 18:12:39 +0100137 u32 index = GPIO_DRV_INDEX(pin_offset);
138 u32 offset = GPIO_DRV_OFFSET(pin_offset);
Andre Przywara20b78c52022-09-06 10:36:38 +0100139
Andre Przywara30097ee2022-09-05 18:12:39 +0100140 clrsetbits_le32(bank_base + GPIO_DRV_REG_OFFSET + index * 4,
141 0x3U << offset, val << offset);
Andre Przywara20b78c52022-09-06 10:36:38 +0100142}
143
144void sunxi_gpio_set_pull(u32 pin, u32 val)
145{
146 u32 bank = GPIO_BANK(pin);
Andre Przywara30097ee2022-09-05 18:12:39 +0100147 void *bank_base = BANK_TO_GPIO(bank);
Andre Przywara20b78c52022-09-06 10:36:38 +0100148
Andre Przywara30097ee2022-09-05 18:12:39 +0100149 sunxi_gpio_set_pull_bank(bank_base, GPIO_NUM(pin), val);
Andre Przywara20b78c52022-09-06 10:36:38 +0100150}
151
Andre Przywara30097ee2022-09-05 18:12:39 +0100152void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val)
Andre Przywara20b78c52022-09-06 10:36:38 +0100153{
Andre Przywara30097ee2022-09-05 18:12:39 +0100154 u32 index = GPIO_PULL_INDEX(pin_offset);
155 u32 offset = GPIO_PULL_OFFSET(pin_offset);
Andre Przywara20b78c52022-09-06 10:36:38 +0100156
Andre Przywara30097ee2022-09-05 18:12:39 +0100157 clrsetbits_le32(bank_base + GPIO_PULL_REG_OFFSET + index * 4,
158 0x3U << offset, val << offset);
Andre Przywara20b78c52022-09-06 10:36:38 +0100159}
160
161
162/* =========== Non-DM code, used by the SPL. ============ */
163
Simon Glassbcee8d62019-12-06 21:41:35 -0700164#if !CONFIG_IS_ENABLED(DM_GPIO)
Andre Przywara316ec7f2022-09-06 10:07:18 +0100165static void sunxi_gpio_set_value(u32 pin, bool set)
Ian Campbellabce2c62014-06-05 19:00:15 +0100166{
Ian Campbellabce2c62014-06-05 19:00:15 +0100167 u32 bank = GPIO_BANK(pin);
Andre Przywara30097ee2022-09-05 18:12:39 +0100168 void *pio = BANK_TO_GPIO(bank);
Ian Campbellabce2c62014-06-05 19:00:15 +0100169
Andre Przywara316ec7f2022-09-06 10:07:18 +0100170 sunxi_gpio_set_value_bank(pio, GPIO_NUM(pin), set);
Ian Campbellabce2c62014-06-05 19:00:15 +0100171}
172
Andre Przywara316ec7f2022-09-06 10:07:18 +0100173static int sunxi_gpio_get_value(u32 pin)
Ian Campbellabce2c62014-06-05 19:00:15 +0100174{
Ian Campbellabce2c62014-06-05 19:00:15 +0100175 u32 bank = GPIO_BANK(pin);
Andre Przywara30097ee2022-09-05 18:12:39 +0100176 void *pio = BANK_TO_GPIO(bank);
Ian Campbellabce2c62014-06-05 19:00:15 +0100177
Andre Przywara316ec7f2022-09-06 10:07:18 +0100178 return sunxi_gpio_get_value_bank(pio, GPIO_NUM(pin));
Ian Campbellabce2c62014-06-05 19:00:15 +0100179}
180
181int gpio_request(unsigned gpio, const char *label)
182{
183 return 0;
184}
185
186int gpio_free(unsigned gpio)
187{
188 return 0;
189}
190
191int gpio_direction_input(unsigned gpio)
192{
193 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
194
Axel Linb0c4ae12014-12-20 11:41:25 +0800195 return 0;
Ian Campbellabce2c62014-06-05 19:00:15 +0100196}
197
198int gpio_direction_output(unsigned gpio, int value)
199{
200 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
Andre Przywara316ec7f2022-09-06 10:07:18 +0100201 sunxi_gpio_set_value(gpio, value);
Ian Campbellabce2c62014-06-05 19:00:15 +0100202
Andre Przywara316ec7f2022-09-06 10:07:18 +0100203 return 0;
Ian Campbellabce2c62014-06-05 19:00:15 +0100204}
205
206int gpio_get_value(unsigned gpio)
207{
Andre Przywara316ec7f2022-09-06 10:07:18 +0100208 return sunxi_gpio_get_value(gpio);
Ian Campbellabce2c62014-06-05 19:00:15 +0100209}
210
211int gpio_set_value(unsigned gpio, int value)
212{
Andre Przywara316ec7f2022-09-06 10:07:18 +0100213 sunxi_gpio_set_value(gpio, value);
214
215 return 0;
Ian Campbellabce2c62014-06-05 19:00:15 +0100216}
217
218int sunxi_name_to_gpio(const char *name)
219{
220 int group = 0;
221 int groupsize = 9 * 32;
222 long pin;
223 char *eptr;
Hans de Goede6c727e02014-12-24 19:34:38 +0100224
Ian Campbellabce2c62014-06-05 19:00:15 +0100225 if (*name == 'P' || *name == 'p')
226 name++;
227 if (*name >= 'A') {
228 group = *name - (*name > 'a' ? 'a' : 'A');
229 groupsize = 32;
230 name++;
231 }
232
233 pin = simple_strtol(name, &eptr, 10);
234 if (!*name || *eptr)
235 return -1;
236 if (pin < 0 || pin > groupsize || group >= 9)
237 return -1;
238 return group * 32 + pin;
239}
Andre Przywara20b78c52022-09-06 10:36:38 +0100240#endif /* !DM_GPIO */
241
242/* =========== DM code, used by U-Boot proper. ============ */
Simon Glass7aa97482014-10-30 20:25:49 -0600243
Simon Glassbcee8d62019-12-06 21:41:35 -0700244#if CONFIG_IS_ENABLED(DM_GPIO)
Simon Glassa5ab8832015-04-18 11:33:43 -0600245/* TODO(sjg@chromium.org): Remove this function and use device tree */
246int sunxi_name_to_gpio(const char *name)
247{
248 unsigned int gpio;
249 int ret;
Hans de Goedef9b7a042015-04-22 11:31:22 +0200250#if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
251 char lookup[8];
Simon Glassa5ab8832015-04-18 11:33:43 -0600252
Samuel Holland09cbd382023-01-22 17:46:22 -0600253 if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
Hans de Goedef9b7a042015-04-22 11:31:22 +0200254 sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
255 SUNXI_GPIO_AXP0_VBUS_ENABLE);
256 name = lookup;
257 }
258#endif
Simon Glassa5ab8832015-04-18 11:33:43 -0600259 ret = gpio_lookup_name(name, NULL, NULL, &gpio);
260
261 return ret ? ret : gpio;
262}
263
Simon Glass7aa97482014-10-30 20:25:49 -0600264static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
265{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700266 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
Simon Glass7aa97482014-10-30 20:25:49 -0600267
Andre Przywara316ec7f2022-09-06 10:07:18 +0100268 return sunxi_gpio_get_value_bank(plat->regs, offset);
Simon Glass7aa97482014-10-30 20:25:49 -0600269}
270
Simon Glass7aa97482014-10-30 20:25:49 -0600271static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
272{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700273 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
Simon Glass7aa97482014-10-30 20:25:49 -0600274 int func;
275
276 func = sunxi_gpio_get_cfgbank(plat->regs, offset);
277 if (func == SUNXI_GPIO_OUTPUT)
278 return GPIOF_OUTPUT;
279 else if (func == SUNXI_GPIO_INPUT)
280 return GPIOF_INPUT;
281 else
282 return GPIOF_FUNC;
283}
284
Chen-Yu Tsai4694dc52016-07-22 16:12:59 +0800285static int sunxi_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
Simon Glass3a571232017-05-18 20:09:18 -0600286 struct ofnode_phandle_args *args)
Chen-Yu Tsai4694dc52016-07-22 16:12:59 +0800287{
288 int ret;
289
290 ret = device_get_child(dev, args->args[0], &desc->dev);
291 if (ret)
292 return ret;
293 desc->offset = args->args[1];
Samuel Holland35ae1262021-10-20 23:52:56 -0500294 desc->flags = gpio_flags_xlate(args->args[2]);
295
296 return 0;
297}
298
299static int sunxi_gpio_set_flags(struct udevice *dev, unsigned int offset,
300 ulong flags)
301{
302 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
303
304 if (flags & GPIOD_IS_OUT) {
305 u32 value = !!(flags & GPIOD_IS_OUT_ACTIVE);
Samuel Holland35ae1262021-10-20 23:52:56 -0500306
Andre Przywara316ec7f2022-09-06 10:07:18 +0100307 sunxi_gpio_set_value_bank(plat->regs, offset, value);
Samuel Holland35ae1262021-10-20 23:52:56 -0500308 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
309 } else if (flags & GPIOD_IS_IN) {
310 u32 pull = 0;
311
312 if (flags & GPIOD_PULL_UP)
313 pull = 1;
314 else if (flags & GPIOD_PULL_DOWN)
315 pull = 2;
316 sunxi_gpio_set_pull_bank(plat->regs, offset, pull);
317 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
318 }
Chen-Yu Tsai4694dc52016-07-22 16:12:59 +0800319
320 return 0;
321}
322
Simon Glass7aa97482014-10-30 20:25:49 -0600323static const struct dm_gpio_ops gpio_sunxi_ops = {
Simon Glass7aa97482014-10-30 20:25:49 -0600324 .get_value = sunxi_gpio_get_value,
Simon Glass7aa97482014-10-30 20:25:49 -0600325 .get_function = sunxi_gpio_get_function,
Chen-Yu Tsai4694dc52016-07-22 16:12:59 +0800326 .xlate = sunxi_gpio_xlate,
Samuel Holland35ae1262021-10-20 23:52:56 -0500327 .set_flags = sunxi_gpio_set_flags,
Simon Glass7aa97482014-10-30 20:25:49 -0600328};
329
Simon Glass7aa97482014-10-30 20:25:49 -0600330static int gpio_sunxi_probe(struct udevice *dev)
331{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700332 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
Simon Glasse564f052015-03-05 12:25:20 -0700333 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glass7aa97482014-10-30 20:25:49 -0600334
335 /* Tell the uclass how many GPIOs we have */
336 if (plat) {
Samuel Hollandb799eab2021-08-12 20:09:43 -0500337 uc_priv->gpio_count = SUNXI_GPIOS_PER_BANK;
Simon Glass7aa97482014-10-30 20:25:49 -0600338 uc_priv->bank_name = plat->bank_name;
339 }
340
341 return 0;
342}
Stephen Warren6f82fac2016-05-11 15:26:25 -0600343
Simon Glass7aa97482014-10-30 20:25:49 -0600344U_BOOT_DRIVER(gpio_sunxi) = {
345 .name = "gpio_sunxi",
346 .id = UCLASS_GPIO,
Simon Glass7aa97482014-10-30 20:25:49 -0600347 .probe = gpio_sunxi_probe,
Samuel Hollandb799eab2021-08-12 20:09:43 -0500348 .ops = &gpio_sunxi_ops,
Simon Glass7aa97482014-10-30 20:25:49 -0600349};
Simon Glassbcee8d62019-12-06 21:41:35 -0700350#endif /* DM_GPIO */