blob: 2e825c8cd7082dfae1ba78ff8c1ca13a66673b3c [file] [log] [blame]
Alexander Filippov2226dea2020-05-22 14:22:37 +03001From 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