summaryrefslogtreecommitdiff
path: root/meta-ampere
diff options
context:
space:
mode:
authorChanh Nguyen <chanh@os.amperecomputing.com>2021-03-09 05:38:56 +0300
committerThang Q. Nguyen <thang@os.amperecomputing.com>2021-03-09 17:35:42 +0300
commit89f59764099ab93cc61f94dc10eadb1733bb02c4 (patch)
tree0419463d2e89a10dc9ea0dfda54e8f1179b14385 /meta-ampere
parentaae820c542c0bbf907fff93e3b0fc865465fad60 (diff)
downloadopenbmc-89f59764099ab93cc61f94dc10eadb1733bb02c4.tar.xz
meta-ampere:mtjade:u-boot: Add GPIO support
This is an initial support for the parallel GPIO pins directly connected to the AHB on the Aspeed 2400/2500. This brings the functions and a shell command to manipulate the GPIO state. The GPIO value reading and writing work in non interrupt mode only. This is back ported from the patch file from meta-yadro/meta-nicole/recipes-bsp/u-boot/files/0003-aspeed-add-gpio-support.patch to support GPIO configuration Signed-off-by: Alexander Filippov <a.filippov@yadro.com> Signed-off-by: Thang Q. Nguyen <thangqn@amperecomputing.com> Signed-off-by: Chanh Nguyen <chanh@os.amperecomputing.com> Change-Id: I2d97c0fbb9f80bd6c262f03302775936f732b1f1
Diffstat (limited to 'meta-ampere')
-rw-r--r--meta-ampere/meta-jade/recipes-bsp/u-boot/u-boot-aspeed/0004-aspeed-add-gpio-support.patch518
-rw-r--r--meta-ampere/meta-jade/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend1
2 files changed, 519 insertions, 0 deletions
diff --git a/meta-ampere/meta-jade/recipes-bsp/u-boot/u-boot-aspeed/0004-aspeed-add-gpio-support.patch b/meta-ampere/meta-jade/recipes-bsp/u-boot/u-boot-aspeed/0004-aspeed-add-gpio-support.patch
new file mode 100644
index 000000000..2f8ff45bd
--- /dev/null
+++ b/meta-ampere/meta-jade/recipes-bsp/u-boot/u-boot-aspeed/0004-aspeed-add-gpio-support.patch
@@ -0,0 +1,518 @@
+From 7372552ae247e4870fb6dc80df7610f86d736a57 Mon Sep 17 00:00:00 2001
+From: Chanh Nguyen <chanh@os.amperecomputing.com>
+Date: Tue, 9 Mar 2021 11:04:56 +0700
+Subject: [PATCH] aspeed: add gpio support
+
+This is an initial support for the parallel GPIO pins directly connected
+to the AHB on the Aspeed 2400/2500.
+
+This brings the functions and a shell command to manipulate the GPIO
+state. The GPIO value reading and writing work in non interrupt mode
+only.
+
+This is back ported from the patch file from
+meta-yadro/meta-nicole/recipes-bsp/u-boot/files/0003-aspeed-add-gpio-support.patch
+to support GPIO configuration
+
+Signed-off-by: Alexander Filippov <a.filippov@yadro.com>
+Signed-off-by: Thang Q. Nguyen <thangqn@amperecomputing.com>
+Signed-off-by: Chanh Nguyen <chanh@os.amperecomputing.com>
+---
+ arch/arm/include/asm/arch-aspeed/gpio.h | 65 ++++
+ drivers/gpio/Makefile | 2 +
+ drivers/gpio/aspeed_gpio.c | 386 ++++++++++++++++++++++++
+ include/configs/ast-g5-phy.h | 1 +
+ 4 files changed, 454 insertions(+)
+ create mode 100644 arch/arm/include/asm/arch-aspeed/gpio.h
+ create mode 100644 drivers/gpio/aspeed_gpio.c
+
+diff --git a/arch/arm/include/asm/arch-aspeed/gpio.h b/arch/arm/include/asm/arch-aspeed/gpio.h
+new file mode 100644
+index 0000000000..c63987e917
+--- /dev/null
++++ b/arch/arm/include/asm/arch-aspeed/gpio.h
+@@ -0,0 +1,65 @@
++/*
++ * SPDX-License-Identifier: GPL-2.0+
++ * Copyright (C) 2020 YADRO.
++ */
++#ifndef _ASPEED_GPIO_H
++#define _ASPEED_GPIO_H
++
++#define ASPEED_GPIO_PORT_A 0
++#define ASPEED_GPIO_PORT_B 1
++#define ASPEED_GPIO_PORT_C 2
++#define ASPEED_GPIO_PORT_D 3
++#define ASPEED_GPIO_PORT_E 4
++#define ASPEED_GPIO_PORT_F 5
++#define ASPEED_GPIO_PORT_G 6
++#define ASPEED_GPIO_PORT_H 7
++#define ASPEED_GPIO_PORT_I 8
++#define ASPEED_GPIO_PORT_J 9
++#define ASPEED_GPIO_PORT_K 10
++#define ASPEED_GPIO_PORT_L 11
++#define ASPEED_GPIO_PORT_M 12
++#define ASPEED_GPIO_PORT_N 13
++#define ASPEED_GPIO_PORT_O 14
++#define ASPEED_GPIO_PORT_P 15
++#define ASPEED_GPIO_PORT_Q 16
++#define ASPEED_GPIO_PORT_R 17
++#define ASPEED_GPIO_PORT_S 18
++#define ASPEED_GPIO_PORT_T 19
++#define ASPEED_GPIO_PORT_U 20
++#define ASPEED_GPIO_PORT_V 21
++#define ASPEED_GPIO_PORT_W 22
++#define ASPEED_GPIO_PORT_X 23
++#define ASPEED_GPIO_PORT_Y 24
++#define ASPEED_GPIO_PORT_Z 25
++#define ASPEED_GPIO_PORT_AA 26
++#define ASPEED_GPIO_PORT_AB 27
++#define ASPEED_GPIO_PORT_AC 28
++
++#define ASPEED_GPIO_PORT_SHIFT 3
++#define ASPEED_GPIO_PIN_MASK 0x7
++#define ASPEED_GPIO(port, pin) \
++ ((ASPEED_GPIO_PORT_##port << ASPEED_GPIO_PORT_SHIFT) | \
++ (pin & ASPEED_GPIO_PIN_MASK))
++
++/* Direction values */
++#define ASPEED_GPIO_INPUT 0
++#define ASPEED_GPIO_OUTPUT 1
++
++/* Trigger values */
++#define ASPEED_GPIO_FALLING_EDGE 0
++#define ASPEED_GPIO_RISING_EDGE 1
++#define ASPEED_GPIO_LOW_LEVEL 2
++#define ASPEED_GPIO_HIGH_LEVEL 3
++#define ASPEED_GPIO_DUAL_EDGE 4
++
++/* Debounce values */
++#define ASPEED_GPIO_DEBOUNCE_NONE 0
++#define ASPEED_GPIO_DEBOUNCE_1 1
++#define ASPEED_GPIO_DEBOUNCE_2 2
++#define ASPEED_GPIO_DEBOUNCE_3 3
++
++#define gpio_status() gpio_info()
++
++extern void gpio_info(void);
++
++#endif /* #ifndef _ASPEED_GPIO_H */
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index 792d19186a..5f043e07ce 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -14,6 +14,8 @@ obj-$(CONFIG_DM_GPIO) += gpio-uclass.o
+ obj-$(CONFIG_DM_PCA953X) += pca953x_gpio.o
+ obj-$(CONFIG_DM_74X164) += 74x164_gpio.o
+
++obj-$(CONFIG_ARCH_AST2400) += aspeed_gpio.o
++obj-$(CONFIG_ARCH_AST2500) += aspeed_gpio.o
+ obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
+ obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
+ obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
+diff --git a/drivers/gpio/aspeed_gpio.c b/drivers/gpio/aspeed_gpio.c
+new file mode 100644
+index 0000000000..dc07f5a520
+--- /dev/null
++++ b/drivers/gpio/aspeed_gpio.c
+@@ -0,0 +1,386 @@
++/*
++ * SPDX-License-Identifier: GPL-2.0+
++ * Copyright (C) 2020 YADRO.
++ */
++
++#include <common.h>
++
++#include <asm/arch/gpio.h>
++#include <asm/arch/platform.h>
++#include <asm/io.h>
++#include <linux/ctype.h>
++
++typedef struct _ast_gpio_regs
++{
++ uint32_t base; /* data and direction registers */
++ uint32_t intcfg; /* interrupt config */
++ uint32_t debounce; /* debounce config */
++ uint32_t cmdsrc; /* command source config */
++ uint32_t data; /* data read register */
++} ast_gpio_regs_t;
++
++static ast_gpio_regs_t ast_gpio_regs[] = {
++ /* A/B/C/D */
++ {AST_GPIO_BASE + 0x0000, AST_GPIO_BASE + 0x0008, AST_GPIO_BASE + 0x0040,
++ AST_GPIO_BASE + 0x0060, AST_GPIO_BASE + 0x00C0},
++ /* E/F/G/H */
++ {AST_GPIO_BASE + 0x0020, AST_GPIO_BASE + 0x0028, AST_GPIO_BASE + 0x0048,
++ AST_GPIO_BASE + 0x0068, AST_GPIO_BASE + 0x00C4},
++ /* I/J/K/L */
++ {AST_GPIO_BASE + 0x0070, AST_GPIO_BASE + 0x0098, AST_GPIO_BASE + 0x00B0,
++ AST_GPIO_BASE + 0x0090, AST_GPIO_BASE + 0x00C8},
++ /* M/N/O/P */
++ {AST_GPIO_BASE + 0x0078, AST_GPIO_BASE + 0x00E8, AST_GPIO_BASE + 0x0100,
++ AST_GPIO_BASE + 0x00E0, AST_GPIO_BASE + 0x00CC},
++ /* Q/R/S/T */
++ {AST_GPIO_BASE + 0x0080, AST_GPIO_BASE + 0x0118, AST_GPIO_BASE + 0x0130,
++ AST_GPIO_BASE + 0x0110, AST_GPIO_BASE + 0x00D0},
++ /* U/V/W/X */
++ {AST_GPIO_BASE + 0x0088, AST_GPIO_BASE + 0x0148, AST_GPIO_BASE + 0x0160,
++ AST_GPIO_BASE + 0x0140, AST_GPIO_BASE + 0x00D4},
++ /* Y/Z/AA/AB */
++ {AST_GPIO_BASE + 0x01E0, AST_GPIO_BASE + 0x0178, AST_GPIO_BASE + 0x0190,
++ AST_GPIO_BASE + 0x0170, AST_GPIO_BASE + 0x00D8},
++ /* AC */
++ {AST_GPIO_BASE + 0x01E8, AST_GPIO_BASE + 0x01A8, AST_GPIO_BASE + 0x01C0,
++ AST_GPIO_BASE + 0x01A0, AST_GPIO_BASE + 0x00DC},
++};
++
++#define AST_GPIO_PINS_PER_PORT 8
++#define AST_GPIO_PORTS_PER_REGISTER 4
++
++#define AST_GPIO_PORT(gpio) (gpio >> ASPEED_GPIO_PORT_SHIFT)
++#define AST_GPIO_PIN(gpio) (gpio & ASPEED_GPIO_PIN_MASK)
++#define AST_GPIO_SHIFT(gpio) \
++ ((AST_GPIO_PORT(gpio) % AST_GPIO_PORTS_PER_REGISTER) * \
++ AST_GPIO_PINS_PER_PORT + \
++ AST_GPIO_PIN(gpio))
++
++#define AST_GPIO_REG_INDEX(gpio) \
++ (AST_GPIO_PORT(gpio) / AST_GPIO_PORTS_PER_REGISTER)
++
++/**
++ * @return Pointer to corresponding item from ast_gpio_regs table.
++ */
++#define AST_GPIO_REGS(gpio) \
++ ((AST_GPIO_REG_INDEX(gpio) < ARRAY_SIZE(ast_gpio_regs)) \
++ ? (ast_gpio_regs + AST_GPIO_REG_INDEX(gpio)) \
++ : NULL)
++
++/**
++ * @brief Set a corresponding bit in specified register.
++ *
++ * @param val - Required bit value
++ * @param base - Register address
++ * @param shift - Bit index.
++ */
++#define AST_GPIO_WRITE(val, base, shift) \
++ writel(((val) ? readl(base) | (1 << (shift)) \
++ : readl(base) & ~(1 << (shift))), \
++ base)
++
++/**
++ * @brief Get value of corresponging bit from specified register.
++ *
++ * @param base - Register address
++ * @param shift - Bit index
++ *
++ * @return Bit value
++ */
++#define AST_GPIO_READ(base, shift) ((readl(base) >> (shift)) & 1)
++
++#define IS_VALID_GPIO(gpio) \
++ ((gpio) >= ASPEED_GPIO(A, 0) && (gpio) <= ASPEED_GPIO(AC, 7))
++
++#define AST_GPIO_DIRECTION 0x04
++#define AST_GPIO_INT_SENS0 0x04
++#define AST_GPIO_INT_SENS1 0x08
++#define AST_GPIO_INT_SENS2 0x0C
++#define AST_GPIO_INT_STATUS 0x10
++#define AST_GPIO_DEBOUNCE0 0x00
++#define AST_GPIO_DEBOUNCE1 0x04
++#define AST_GPIO_CMD_SRC0 0x00
++#define AST_GPIO_CMD_SRC1 0x04
++
++/**
++ * @brief Set a GPIO direction
++ *
++ * @param gpio GPIO line
++ * @param direction GPIO direction (0 for input or 1 for output)
++ *
++ * @return 0 if ok, -1 on error
++ */
++static int ast_gpio_set_direction(unsigned gpio, unsigned direction)
++{
++ ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
++ if (!regs)
++ {
++ printf("%s: Invalid GPIO!\n", __func__);
++ return -1;
++ }
++
++ AST_GPIO_WRITE(direction, regs->base + AST_GPIO_DIRECTION,
++ AST_GPIO_SHIFT(gpio));
++ return 0;
++}
++
++/**
++ * The 6 following functions are generic u-boot gpio implementation.
++ * They are declared in `include/asm-generic/gpio.h`
++ */
++
++int gpio_request(unsigned gpio, const char *label)
++{
++ return (IS_VALID_GPIO(gpio) ? 0 : -1);
++}
++
++int gpio_free(unsigned gpio)
++{
++ return (IS_VALID_GPIO(gpio) ? 0 : -1);
++}
++
++int gpio_get_value(unsigned gpio)
++{
++ ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
++ if (!regs)
++ {
++ printf("%s: Invalid GPIO!\n", __func__);
++ return -1;
++ }
++
++ return AST_GPIO_READ(regs->base, AST_GPIO_SHIFT(gpio));
++}
++
++int gpio_set_value(unsigned gpio, int value)
++{
++ ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
++ if (!regs)
++ {
++ printf("%s: Invalid GPIO!\n", __func__);
++ return -1;
++ }
++
++ AST_GPIO_WRITE(value, regs->base, AST_GPIO_SHIFT(gpio));
++ return 0;
++}
++
++int gpio_direction_input(unsigned gpio)
++{
++ return ast_gpio_set_direction(gpio, ASPEED_GPIO_INPUT);
++}
++
++int gpio_direction_output(unsigned gpio, int value)
++{
++ int rc = ast_gpio_set_direction(gpio, ASPEED_GPIO_OUTPUT);
++ return (rc == 0 ? gpio_set_value(gpio, value) : rc);
++}
++
++/**
++ * @brief Convert a string to GPIO line. Used by `do_gpio()` from `cmd/gpio.c`
++ *
++ * @param str a GPIO name or line number
++ *
++ * @return GPIO line if ok, -1 on error
++ */
++int name_to_gpio(const char *str)
++{
++ int gpio = -1;
++
++ if (str)
++ {
++ if (isalpha(*str))
++ {
++ gpio = (toupper(*str) - 'A') << ASPEED_GPIO_PORT_SHIFT;
++
++ if (toupper(*str) == 'A' && toupper(*(str + 1)) >= 'A' &&
++ toupper(*(str + 1)) <= 'C')
++ {
++ str++;
++ gpio = (ASPEED_GPIO_PORT_AA + toupper(*str) - 'A')
++ << ASPEED_GPIO_PORT_SHIFT;
++ }
++
++ str++;
++ if (*str >= '0' && *str <= '7' && !*(str + 1))
++ {
++ gpio += *str - '0';
++ }
++ else
++ {
++ gpio = -1;
++ }
++ }
++ else if (isdigit(*str))
++ {
++ gpio = simple_strtoul(str, NULL, 0);
++ }
++ }
++
++ return gpio;
++}
++
++/**
++ * @return A GPIO direction in human readable format.
++ */
++static const char *ast_gpio_direction(unsigned gpio)
++{
++ ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
++ if (regs)
++ {
++ int direction = AST_GPIO_READ(regs->base + AST_GPIO_DIRECTION,
++ AST_GPIO_SHIFT(gpio));
++ switch (direction)
++ {
++ case ASPEED_GPIO_INPUT:
++ return "input";
++ case ASPEED_GPIO_OUTPUT:
++ return "output";
++ default:
++ break;
++ }
++ }
++ return "error";
++}
++
++/**
++ * @return An interrupt trigger settings in human readable format.
++ */
++static const char *ast_gpio_trigger(unsigned gpio)
++{
++ ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
++ if (regs)
++ {
++ unsigned shift = AST_GPIO_SHIFT(gpio);
++ unsigned trigger =
++ (AST_GPIO_READ(regs->intcfg + AST_GPIO_INT_SENS0, shift) << 0) |
++ (AST_GPIO_READ(regs->intcfg + AST_GPIO_INT_SENS1, shift) << 1) |
++ (AST_GPIO_READ(regs->intcfg + AST_GPIO_INT_SENS2, shift) << 2);
++
++ switch (trigger)
++ {
++ case ASPEED_GPIO_FALLING_EDGE:
++ return "fall";
++ case ASPEED_GPIO_RISING_EDGE:
++ return "rise";
++ case ASPEED_GPIO_LOW_LEVEL:
++ return "low ";
++ case ASPEED_GPIO_HIGH_LEVEL:
++ return "high";
++ default:
++ return "both";
++ }
++ }
++ return "error";
++}
++
++/**
++ * @return An interrupt status in human readable format.
++ */
++static const char *ast_gpio_int_status(unsigned gpio)
++{
++ ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
++ if (regs)
++ {
++ unsigned shift = AST_GPIO_SHIFT(gpio);
++ if (AST_GPIO_READ(regs->intcfg, shift))
++ {
++ return AST_GPIO_READ(regs->intcfg + AST_GPIO_INT_STATUS, shift)
++ ? "pending"
++ : "cleaned";
++ }
++ return "disabled";
++ }
++
++ return "error";
++}
++
++/**
++ * @return A debounce value in human readable format.
++ */
++static const char *ast_gpio_debounce(unsigned gpio)
++{
++ ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
++ if (regs)
++ {
++ unsigned shift = AST_GPIO_SHIFT(gpio);
++ unsigned debounce =
++ (AST_GPIO_READ(regs->debounce + AST_GPIO_DEBOUNCE0, shift) << 0) |
++ (AST_GPIO_READ(regs->debounce + AST_GPIO_DEBOUNCE1, shift) << 1);
++ switch (debounce)
++ {
++ case ASPEED_GPIO_DEBOUNCE_NONE:
++ return "none";
++ case ASPEED_GPIO_DEBOUNCE_1:
++ return "timer1";
++ case ASPEED_GPIO_DEBOUNCE_2:
++ return "timer2";
++ case ASPEED_GPIO_DEBOUNCE_3:
++ return "timer3";
++ default:
++ break;
++ }
++ }
++
++ return "error";
++}
++
++/**
++ * @return A command source value in human readable format.
++ */
++static const char *ast_gpio_command_source(unsigned gpio)
++{
++ ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
++ if (regs)
++ {
++ /* Used one bit per gpio port */
++ unsigned shift = AST_GPIO_SHIFT(gpio) - AST_GPIO_PIN(gpio);
++ unsigned cmdsrc =
++ (AST_GPIO_READ(regs->cmdsrc + AST_GPIO_CMD_SRC0, shift) << 0) |
++ (AST_GPIO_READ(regs->cmdsrc + AST_GPIO_CMD_SRC1, shift) << 1);
++
++ switch (cmdsrc)
++ {
++ /* The single place where these values are used is here. */
++ case 0x0:
++ return "ARM";
++ case 0x1:
++ return "LPC";
++ case 0x2:
++ return "CoCPU";
++ default:
++ return "Unknown";
++ }
++ }
++
++ return "error";
++}
++
++/**
++ * @brief Show all GPIO pins statuses. Used by `do_gpio()` in `cmd/gpio.c`
++ */
++void gpio_info(void)
++{
++ unsigned first = ASPEED_GPIO(A, 0);
++ unsigned last = ASPEED_GPIO(AC, 7);
++ for (unsigned gpio = first; gpio <= last; gpio++)
++ {
++ unsigned port = AST_GPIO_PORT(gpio);
++ unsigned pin = AST_GPIO_PIN(gpio);
++ unsigned shift = AST_GPIO_SHIFT(gpio);
++ ast_gpio_regs_t *regs = AST_GPIO_REGS(gpio);
++ if (!regs)
++ {
++ printf("gpio %u is invalid!\n", gpio);
++ continue;
++ }
++
++ printf("gpio %c%c%c line %3d: %s, int: %s, %s, deb: %s, src: %s, "
++ "val: %d/%d\n",
++ (port >= ASPEED_GPIO_PORT_AA ? 'A' : ' '),
++ ('A' + port % ASPEED_GPIO_PORT_AA), ('0' + pin), gpio,
++ ast_gpio_direction(gpio), ast_gpio_trigger(gpio),
++ ast_gpio_int_status(gpio), ast_gpio_debounce(gpio),
++ ast_gpio_command_source(gpio), gpio_get_value(gpio),
++ AST_GPIO_READ(regs->data, shift));
++ }
++}
+diff --git a/include/configs/ast-g5-phy.h b/include/configs/ast-g5-phy.h
+index 5443a26cab..ea7c66716a 100644
+--- a/include/configs/ast-g5-phy.h
++++ b/include/configs/ast-g5-phy.h
+@@ -32,5 +32,6 @@
+
+ /* Call board_late_init */
+ #define CONFIG_BOARD_LATE_INIT 1
++#define CONFIG_CMD_GPIO 1 /* Enable gpio command in shell */
+
+ #endif /* __AST_G5_PHY_CONFIG_H */
+--
+2.17.1
+
diff --git a/meta-ampere/meta-jade/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend b/meta-ampere/meta-jade/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend
index 77a58f523..4f882dcee 100644
--- a/meta-ampere/meta-jade/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend
+++ b/meta-ampere/meta-jade/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend
@@ -4,4 +4,5 @@ SRC_URI += " \
file://0001-aspeed-scu-Switch-PWM-pin-to-GPIO-input-mode.patch \
file://0002-aspeed-Disable-internal-PD-resistors-for-GPIOs.patch \
file://0003-aspeed-support-passing-system-reset-status-to-kernel.patch \
+ file://0004-aspeed-add-gpio-support.patch \
"