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