xref: /openbmc/openbmc/meta-yadro/meta-nicole/recipes-bsp/u-boot/files/0003-aspeed-add-gpio-support.patch (revision 2226dea415e2003b136d0ac32a48f779b7058e7b)
1From 9bb68d8820480519e8b331f7a8b866b8718ad7fd Mon Sep 17 00:00:00 2001
2From: Alexander Filippov <a.filippov@yadro.com>
3Date: Tue, 19 May 2020 18:55:41 +0300
4Subject: [PATCH] aspeed: add gpio support
5
6This is an initial support for the parallel GPIO pins directly connected
7to the AHB on the Aspeed 2400/2500.
8
9This brings the functions and a shell command to manipulate the GPIO
10state. The GPIO value reading and writing work in non interrupt mode
11only.
12
13Signed-off-by: Alexander Filippov <a.filippov@yadro.com>
14---
15 arch/arm/include/asm/arch-aspeed/gpio.h     |  65 ++++
16 arch/arm/include/asm/arch-aspeed/platform.h |   1 +
17 drivers/gpio/Makefile                       |   2 +
18 drivers/gpio/aspeed_gpio.c                  | 386 ++++++++++++++++++++
19 4 files changed, 454 insertions(+)
20 create mode 100644 arch/arm/include/asm/arch-aspeed/gpio.h
21 create mode 100644 drivers/gpio/aspeed_gpio.c
22
23diff --git a/arch/arm/include/asm/arch-aspeed/gpio.h b/arch/arm/include/asm/arch-aspeed/gpio.h
24new file mode 100644
25index 0000000000..c63987e917
26--- /dev/null
27+++ b/arch/arm/include/asm/arch-aspeed/gpio.h
28@@ -0,0 +1,65 @@
29+/*
30+ * SPDX-License-Identifier: GPL-2.0+
31+ * Copyright (C) 2020 YADRO.
32+ */
33+#ifndef _ASPEED_GPIO_H
34+#define _ASPEED_GPIO_H
35+
36+#define ASPEED_GPIO_PORT_A 0
37+#define ASPEED_GPIO_PORT_B 1
38+#define ASPEED_GPIO_PORT_C 2
39+#define ASPEED_GPIO_PORT_D 3
40+#define ASPEED_GPIO_PORT_E 4
41+#define ASPEED_GPIO_PORT_F 5
42+#define ASPEED_GPIO_PORT_G 6
43+#define ASPEED_GPIO_PORT_H 7
44+#define ASPEED_GPIO_PORT_I 8
45+#define ASPEED_GPIO_PORT_J 9
46+#define ASPEED_GPIO_PORT_K 10
47+#define ASPEED_GPIO_PORT_L 11
48+#define ASPEED_GPIO_PORT_M 12
49+#define ASPEED_GPIO_PORT_N 13
50+#define ASPEED_GPIO_PORT_O 14
51+#define ASPEED_GPIO_PORT_P 15
52+#define ASPEED_GPIO_PORT_Q 16
53+#define ASPEED_GPIO_PORT_R 17
54+#define ASPEED_GPIO_PORT_S 18
55+#define ASPEED_GPIO_PORT_T 19
56+#define ASPEED_GPIO_PORT_U 20
57+#define ASPEED_GPIO_PORT_V 21
58+#define ASPEED_GPIO_PORT_W 22
59+#define ASPEED_GPIO_PORT_X 23
60+#define ASPEED_GPIO_PORT_Y 24
61+#define ASPEED_GPIO_PORT_Z 25
62+#define ASPEED_GPIO_PORT_AA 26
63+#define ASPEED_GPIO_PORT_AB 27
64+#define ASPEED_GPIO_PORT_AC 28
65+
66+#define ASPEED_GPIO_PORT_SHIFT 3
67+#define ASPEED_GPIO_PIN_MASK 0x7
68+#define ASPEED_GPIO(port, pin)                                                 \
69+    ((ASPEED_GPIO_PORT_##port << ASPEED_GPIO_PORT_SHIFT) |                     \
70+     (pin & ASPEED_GPIO_PIN_MASK))
71+
72+/* Direction values */
73+#define ASPEED_GPIO_INPUT 0
74+#define ASPEED_GPIO_OUTPUT 1
75+
76+/* Trigger values */
77+#define ASPEED_GPIO_FALLING_EDGE 0
78+#define ASPEED_GPIO_RISING_EDGE 1
79+#define ASPEED_GPIO_LOW_LEVEL 2
80+#define ASPEED_GPIO_HIGH_LEVEL 3
81+#define ASPEED_GPIO_DUAL_EDGE 4
82+
83+/* Debounce values */
84+#define ASPEED_GPIO_DEBOUNCE_NONE 0
85+#define ASPEED_GPIO_DEBOUNCE_1 1
86+#define ASPEED_GPIO_DEBOUNCE_2 2
87+#define ASPEED_GPIO_DEBOUNCE_3 3
88+
89+#define gpio_status() gpio_info()
90+
91+extern void gpio_info(void);
92+
93+#endif /* #ifndef _ASPEED_GPIO_H */
94diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h
95index b9207c492f..0a05a7a7a0 100644
96--- a/arch/arm/include/asm/arch-aspeed/platform.h
97+++ b/arch/arm/include/asm/arch-aspeed/platform.h
98@@ -32,5 +32,6 @@
99 #endif
100
101 #define CONFIG_BOARD_LATE_INIT 1 /* Call board_late_init */
102+#define CONFIG_CMD_GPIO 1        /* Enable gpio command in shell */
103
104 #endif
105diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
106index 792d19186a..5f043e07ce 100644
107--- a/drivers/gpio/Makefile
108+++ b/drivers/gpio/Makefile
109@@ -14,6 +14,8 @@ obj-$(CONFIG_DM_GPIO)		+= gpio-uclass.o
110 obj-$(CONFIG_DM_PCA953X)	+= pca953x_gpio.o
111 obj-$(CONFIG_DM_74X164)		+= 74x164_gpio.o
112
113+obj-$(CONFIG_ARCH_AST2400)	+= aspeed_gpio.o
114+obj-$(CONFIG_ARCH_AST2500)	+= aspeed_gpio.o
115 obj-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
116 obj-$(CONFIG_ATMEL_PIO4)	+= atmel_pio4.o
117 obj-$(CONFIG_INTEL_ICH6_GPIO)	+= intel_ich6_gpio.o
118diff --git a/drivers/gpio/aspeed_gpio.c b/drivers/gpio/aspeed_gpio.c
119new file mode 100644
120index 0000000000..dc07f5a520
121--- /dev/null
122+++ b/drivers/gpio/aspeed_gpio.c
123@@ -0,0 +1,386 @@
124+/*
125+ * SPDX-License-Identifier: GPL-2.0+
126+ * Copyright (C) 2020 YADRO.
127+ */
128+
129+#include <common.h>
130+
131+#include <asm/arch/gpio.h>
132+#include <asm/arch/platform.h>
133+#include <asm/io.h>
134+#include <linux/ctype.h>
135+
136+typedef struct _ast_gpio_regs
137+{
138+    uint32_t base;     /* data and direction registers */
139+    uint32_t intcfg;   /* interrupt config */
140+    uint32_t debounce; /* debounce config */
141+    uint32_t cmdsrc;   /* command source config */
142+    uint32_t data;     /* data read register */
143+} ast_gpio_regs_t;
144+
145+static ast_gpio_regs_t ast_gpio_regs[] = {
146+    /* A/B/C/D */
147+    {AST_GPIO_BASE + 0x0000, AST_GPIO_BASE + 0x0008, AST_GPIO_BASE + 0x0040,
148+     AST_GPIO_BASE + 0x0060, AST_GPIO_BASE + 0x00C0},
149+    /* E/F/G/H */
150+    {AST_GPIO_BASE + 0x0020, AST_GPIO_BASE + 0x0028, AST_GPIO_BASE + 0x0048,
151+     AST_GPIO_BASE + 0x0068, AST_GPIO_BASE + 0x00C4},
152+    /* I/J/K/L */
153+    {AST_GPIO_BASE + 0x0070, AST_GPIO_BASE + 0x0098, AST_GPIO_BASE + 0x00B0,
154+     AST_GPIO_BASE + 0x0090, AST_GPIO_BASE + 0x00C8},
155+    /* M/N/O/P */
156+    {AST_GPIO_BASE + 0x0078, AST_GPIO_BASE + 0x00E8, AST_GPIO_BASE + 0x0100,
157+     AST_GPIO_BASE + 0x00E0, AST_GPIO_BASE + 0x00CC},
158+    /* Q/R/S/T */
159+    {AST_GPIO_BASE + 0x0080, AST_GPIO_BASE + 0x0118, AST_GPIO_BASE + 0x0130,
160+     AST_GPIO_BASE + 0x0110, AST_GPIO_BASE + 0x00D0},
161+    /* U/V/W/X */
162+    {AST_GPIO_BASE + 0x0088, AST_GPIO_BASE + 0x0148, AST_GPIO_BASE + 0x0160,
163+     AST_GPIO_BASE + 0x0140, AST_GPIO_BASE + 0x00D4},
164+    /* Y/Z/AA/AB */
165+    {AST_GPIO_BASE + 0x01E0, AST_GPIO_BASE + 0x0178, AST_GPIO_BASE + 0x0190,
166+     AST_GPIO_BASE + 0x0170, AST_GPIO_BASE + 0x00D8},
167+    /* AC */
168+    {AST_GPIO_BASE + 0x01E8, AST_GPIO_BASE + 0x01A8, AST_GPIO_BASE + 0x01C0,
169+     AST_GPIO_BASE + 0x01A0, AST_GPIO_BASE + 0x00DC},
170+};
171+
172+#define AST_GPIO_PINS_PER_PORT 8
173+#define AST_GPIO_PORTS_PER_REGISTER 4
174+
175+#define AST_GPIO_PORT(gpio) (gpio >> ASPEED_GPIO_PORT_SHIFT)
176+#define AST_GPIO_PIN(gpio) (gpio & ASPEED_GPIO_PIN_MASK)
177+#define AST_GPIO_SHIFT(gpio)                                                   \
178+    ((AST_GPIO_PORT(gpio) % AST_GPIO_PORTS_PER_REGISTER) *                     \
179+         AST_GPIO_PINS_PER_PORT +                                              \
180+     AST_GPIO_PIN(gpio))
181+
182+#define AST_GPIO_REG_INDEX(gpio)                                               \
183+    (AST_GPIO_PORT(gpio) / AST_GPIO_PORTS_PER_REGISTER)
184+
185+/**
186+ * @return Pointer to corresponding item from ast_gpio_regs table.
187+ */
188+#define AST_GPIO_REGS(gpio)                                                    \
189+    ((AST_GPIO_REG_INDEX(gpio) < ARRAY_SIZE(ast_gpio_regs))                    \
190+         ? (ast_gpio_regs + AST_GPIO_REG_INDEX(gpio))                          \
191+         : NULL)
192+
193+/**
194+ * @brief Set a corresponding bit in specified register.
195+ *
196+ * @param val - Required bit value
197+ * @param base - Register address
198+ * @param shift - Bit index.
199+ */
200+#define AST_GPIO_WRITE(val, base, shift)                                       \
201+    writel(((val) ? readl(base) | (1 << (shift))                               \
202+                  : readl(base) & ~(1 << (shift))),                            \
203+           base)
204+
205+/**
206+ * @brief Get value of corresponging bit from specified register.
207+ *
208+ * @param base - Register address
209+ * @param shift - Bit index
210+ *
211+ * @return Bit value
212+ */
213+#define AST_GPIO_READ(base, shift) ((readl(base) >> (shift)) & 1)
214+
215+#define IS_VALID_GPIO(gpio)                                                    \
216+    ((gpio) >= ASPEED_GPIO(A, 0) && (gpio) <= ASPEED_GPIO(AC, 7))
217+
218+#define AST_GPIO_DIRECTION 0x04
219+#define AST_GPIO_INT_SENS0 0x04
220+#define AST_GPIO_INT_SENS1 0x08
221+#define AST_GPIO_INT_SENS2 0x0C
222+#define AST_GPIO_INT_STATUS 0x10
223+#define AST_GPIO_DEBOUNCE0 0x00
224+#define AST_GPIO_DEBOUNCE1 0x04
225+#define AST_GPIO_CMD_SRC0 0x00
226+#define AST_GPIO_CMD_SRC1 0x04
227+
228+/**
229+ * @brief Set a GPIO direction
230+ *
231+ * @param gpio      GPIO line
232+ * @param direction GPIO direction (0 for input or 1 for output)
233+ *
234+ * @return 0 if ok, -1 on error
235+ */
236+static int ast_gpio_set_direction(unsigned gpio, unsigned direction)
237+{
238+    ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
239+    if (!regs)
240+    {
241+        printf("%s: Invalid GPIO!\n", __func__);
242+        return -1;
243+    }
244+
245+    AST_GPIO_WRITE(direction, regs->base + AST_GPIO_DIRECTION,
246+                   AST_GPIO_SHIFT(gpio));
247+    return 0;
248+}
249+
250+/**
251+ * The 6 following functions are generic u-boot gpio implementation.
252+ * They are declared in `include/asm-generic/gpio.h`
253+ */
254+
255+int gpio_request(unsigned gpio, const char *label)
256+{
257+    return (IS_VALID_GPIO(gpio) ? 0 : -1);
258+}
259+
260+int gpio_free(unsigned gpio)
261+{
262+    return (IS_VALID_GPIO(gpio) ? 0 : -1);
263+}
264+
265+int gpio_get_value(unsigned gpio)
266+{
267+    ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
268+    if (!regs)
269+    {
270+        printf("%s: Invalid GPIO!\n", __func__);
271+        return -1;
272+    }
273+
274+    return AST_GPIO_READ(regs->base, AST_GPIO_SHIFT(gpio));
275+}
276+
277+int gpio_set_value(unsigned gpio, int value)
278+{
279+    ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
280+    if (!regs)
281+    {
282+        printf("%s: Invalid GPIO!\n", __func__);
283+        return -1;
284+    }
285+
286+    AST_GPIO_WRITE(value, regs->base, AST_GPIO_SHIFT(gpio));
287+    return 0;
288+}
289+
290+int gpio_direction_input(unsigned gpio)
291+{
292+    return ast_gpio_set_direction(gpio, ASPEED_GPIO_INPUT);
293+}
294+
295+int gpio_direction_output(unsigned gpio, int value)
296+{
297+    int rc = ast_gpio_set_direction(gpio, ASPEED_GPIO_OUTPUT);
298+    return (rc == 0 ? gpio_set_value(gpio, value) : rc);
299+}
300+
301+/**
302+ * @brief Convert a string to GPIO line. Used by `do_gpio()` from `cmd/gpio.c`
303+ *
304+ * @param str a GPIO name or line number
305+ *
306+ * @return GPIO line if ok, -1 on error
307+ */
308+int name_to_gpio(const char *str)
309+{
310+    int gpio = -1;
311+
312+    if (str)
313+    {
314+        if (isalpha(*str))
315+        {
316+            gpio = (toupper(*str) - 'A') << ASPEED_GPIO_PORT_SHIFT;
317+
318+            if (toupper(*str) == 'A' && toupper(*(str + 1)) >= 'A' &&
319+                toupper(*(str + 1)) <= 'C')
320+            {
321+                str++;
322+                gpio = (ASPEED_GPIO_PORT_AA + toupper(*str) - 'A')
323+                       << ASPEED_GPIO_PORT_SHIFT;
324+            }
325+
326+            str++;
327+            if (*str >= '0' && *str <= '7' && !*(str + 1))
328+            {
329+                gpio += *str - '0';
330+            }
331+            else
332+            {
333+                gpio = -1;
334+            }
335+        }
336+        else if (isdigit(*str))
337+        {
338+            gpio = simple_strtoul(str, NULL, 0);
339+        }
340+    }
341+
342+    return gpio;
343+}
344+
345+/**
346+ * @return A GPIO direction in human readable format.
347+ */
348+static const char *ast_gpio_direction(unsigned gpio)
349+{
350+    ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
351+    if (regs)
352+    {
353+        int direction = AST_GPIO_READ(regs->base + AST_GPIO_DIRECTION,
354+                                      AST_GPIO_SHIFT(gpio));
355+        switch (direction)
356+        {
357+            case ASPEED_GPIO_INPUT:
358+                return "input";
359+            case ASPEED_GPIO_OUTPUT:
360+                return "output";
361+            default:
362+                break;
363+        }
364+    }
365+    return "error";
366+}
367+
368+/**
369+ * @return An interrupt trigger settings in human readable format.
370+ */
371+static const char *ast_gpio_trigger(unsigned gpio)
372+{
373+    ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
374+    if (regs)
375+    {
376+        unsigned shift = AST_GPIO_SHIFT(gpio);
377+        unsigned trigger =
378+            (AST_GPIO_READ(regs->intcfg + AST_GPIO_INT_SENS0, shift) << 0) |
379+            (AST_GPIO_READ(regs->intcfg + AST_GPIO_INT_SENS1, shift) << 1) |
380+            (AST_GPIO_READ(regs->intcfg + AST_GPIO_INT_SENS2, shift) << 2);
381+
382+        switch (trigger)
383+        {
384+            case ASPEED_GPIO_FALLING_EDGE:
385+                return "fall";
386+            case ASPEED_GPIO_RISING_EDGE:
387+                return "rise";
388+            case ASPEED_GPIO_LOW_LEVEL:
389+                return "low ";
390+            case ASPEED_GPIO_HIGH_LEVEL:
391+                return "high";
392+            default:
393+                return "both";
394+        }
395+    }
396+    return "error";
397+}
398+
399+/**
400+ * @return An interrupt status in human readable format.
401+ */
402+static const char *ast_gpio_int_status(unsigned gpio)
403+{
404+    ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
405+    if (regs)
406+    {
407+        unsigned shift = AST_GPIO_SHIFT(gpio);
408+        if (AST_GPIO_READ(regs->intcfg, shift))
409+        {
410+            return AST_GPIO_READ(regs->intcfg + AST_GPIO_INT_STATUS, shift)
411+                       ? "pending"
412+                       : "cleaned";
413+        }
414+        return "disabled";
415+    }
416+
417+    return "error";
418+}
419+
420+/**
421+ * @return A debounce value in human readable format.
422+ */
423+static const char *ast_gpio_debounce(unsigned gpio)
424+{
425+    ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
426+    if (regs)
427+    {
428+        unsigned shift = AST_GPIO_SHIFT(gpio);
429+        unsigned debounce =
430+            (AST_GPIO_READ(regs->debounce + AST_GPIO_DEBOUNCE0, shift) << 0) |
431+            (AST_GPIO_READ(regs->debounce + AST_GPIO_DEBOUNCE1, shift) << 1);
432+        switch (debounce)
433+        {
434+            case ASPEED_GPIO_DEBOUNCE_NONE:
435+                return "none";
436+            case ASPEED_GPIO_DEBOUNCE_1:
437+                return "timer1";
438+            case ASPEED_GPIO_DEBOUNCE_2:
439+                return "timer2";
440+            case ASPEED_GPIO_DEBOUNCE_3:
441+                return "timer3";
442+            default:
443+                break;
444+        }
445+    }
446+
447+    return "error";
448+}
449+
450+/**
451+ * @return A command source value in human readable format.
452+ */
453+static const char *ast_gpio_command_source(unsigned gpio)
454+{
455+    ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
456+    if (regs)
457+    {
458+        /* Used one bit per gpio port */
459+        unsigned shift = AST_GPIO_SHIFT(gpio) - AST_GPIO_PIN(gpio);
460+        unsigned cmdsrc =
461+            (AST_GPIO_READ(regs->cmdsrc + AST_GPIO_CMD_SRC0, shift) << 0) |
462+            (AST_GPIO_READ(regs->cmdsrc + AST_GPIO_CMD_SRC1, shift) << 1);
463+
464+        switch (cmdsrc)
465+        {
466+            /* The single place where these values are used is here. */
467+            case 0x0:
468+                return "ARM";
469+            case 0x1:
470+                return "LPC";
471+            case 0x2:
472+                return "CoCPU";
473+            default:
474+                return "Unknown";
475+        }
476+    }
477+
478+    return "error";
479+}
480+
481+/**
482+ * @brief Show all GPIO pins statuses. Used by `do_gpio()` in `cmd/gpio.c`
483+ */
484+void gpio_info(void)
485+{
486+    unsigned first = ASPEED_GPIO(A, 0);
487+    unsigned last = ASPEED_GPIO(AC, 7);
488+    for (unsigned gpio = first; gpio <= last; gpio++)
489+    {
490+        unsigned port = AST_GPIO_PORT(gpio);
491+        unsigned pin = AST_GPIO_PIN(gpio);
492+        unsigned shift = AST_GPIO_SHIFT(gpio);
493+        ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
494+        if (!regs)
495+        {
496+            printf("gpio %u is invalid!\n", gpio);
497+            continue;
498+        }
499+
500+        printf("gpio %c%c%c line %3d: %s, int: %s, %s, deb: %s, src: %s, "
501+               "val: %d/%d\n",
502+               (port >= ASPEED_GPIO_PORT_AA ? 'A' : ' '),
503+               ('A' + port % ASPEED_GPIO_PORT_AA), ('0' + pin), gpio,
504+               ast_gpio_direction(gpio), ast_gpio_trigger(gpio),
505+               ast_gpio_int_status(gpio), ast_gpio_debounce(gpio),
506+               ast_gpio_command_source(gpio), gpio_get_value(gpio),
507+               AST_GPIO_READ(regs->data, shift));
508+    }
509+}
510--
5112.25.4
512
513