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