From d21bf89240a892e755f7ee3f2dd54f136028cffd Mon Sep 17 00:00:00 2001 From: "chunzhi.lin" Date: Sun, 25 Jun 2023 14:10:03 +0800 Subject: [PATCH] lib:utils:add reset and gpio device --- lib/utils/gpio/Kconfig | 4 + lib/utils/gpio/fdt_gpio_sophgo.c | 141 ++++++++++++++++++++++++ lib/utils/gpio/objects.mk | 3 + lib/utils/reset/Kconfig | 10 ++ lib/utils/reset/fdt_reset_sophgo_cpld.c | 126 +++++++++++++++++++++ lib/utils/reset/fdt_reset_sophgo_wdt.c | 122 ++++++++++++++++++++ lib/utils/reset/objects.mk | 6 + platform/generic/configs/defconfig | 3 + 8 files changed, 415 insertions(+) create mode 100644 lib/utils/gpio/fdt_gpio_sophgo.c create mode 100644 lib/utils/reset/fdt_reset_sophgo_cpld.c create mode 100644 lib/utils/reset/fdt_reset_sophgo_wdt.c diff --git a/lib/utils/gpio/Kconfig b/lib/utils/gpio/Kconfig index 1b338a6f..9ddefa45 100644 --- a/lib/utils/gpio/Kconfig +++ b/lib/utils/gpio/Kconfig @@ -14,6 +14,10 @@ config FDT_GPIO_SIFIVE bool "SiFive GPIO FDT driver" default n +config FDT_GPIO_SOPHGO + bool "Sophgo GPIO FDT driver" + default n + config FDT_GPIO_STARFIVE bool "StarFive GPIO FDT driver" default n diff --git a/lib/utils/gpio/fdt_gpio_sophgo.c b/lib/utils/gpio/fdt_gpio_sophgo.c new file mode 100644 index 00000000..0cc95288 --- /dev/null +++ b/lib/utils/gpio/fdt_gpio_sophgo.c @@ -0,0 +1,141 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Sophgo + * + * Author: + * Chunzhi Lin + */ + +#include +#include +#include +#include +#include +#include + +#define SOPHGO_GPIO_CHIP_MAX 3 + +#define SOPHGO_GPIO_PINS_MIN 0 +#define SOPHGO_GPIO_PINS_MAX 31 +#define SOPHGO_GPIO_PINS_DEF 16 + +#define SOPHGO_GPIO_SWPORTA_DR_OFFSET 0x00 +#define SOPHGO_GPIO_SWPORTA_DDR_OFFSET 0x04 +#define SOPHGO_GPIO_SWPORTA_CTL_OFFSET 0x08 + +#define SOPHGO_GPIO_BIT(offset) (1U << (offset)) + +struct sophgo_gpio_chip { + unsigned long addr; + struct gpio_chip chip; +}; + +static unsigned int sophgo_gpio_chip_count; +static struct sophgo_gpio_chip sophgo_gpio_chip_array[SOPHGO_GPIO_CHIP_MAX]; + +static int sophgo_gpio_direction_output(struct gpio_pin *gp, int value) +{ + unsigned int v; + struct sophgo_gpio_chip *chip = + container_of(gp->chip, struct sophgo_gpio_chip, chip); + + v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET)); + v |= SOPHGO_GPIO_BIT(gp->offset); + writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET)); + + v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); + if (!value) + v &= ~SOPHGO_GPIO_BIT(gp->offset); + else + v |= SOPHGO_GPIO_BIT(gp->offset); + writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); + + return 0; +} + +static void sophgo_gpio_set(struct gpio_pin *gp, int value) +{ + unsigned int v; + struct sophgo_gpio_chip *chip = + container_of(gp->chip, struct sophgo_gpio_chip, chip); + + v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); + + if (!value) + v &= ~SOPHGO_GPIO_BIT(gp->offset); + else + v |= SOPHGO_GPIO_BIT(gp->offset); + + writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); + + return; +} + +static int sophgo_gpio_addr_get(void *fdt, int nodeoff, unsigned long *addr) +{ + int rc; + unsigned long addr_high, addr_low; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 1, &addr_low, NULL); + if (rc) + return rc; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr_high, NULL); + if (rc) + return rc; + + *addr = addr_high << 32 | addr_low; + + return 0; +} + +extern struct fdt_gpio fdt_gpio_sophgo; + +static int sophgo_gpio_init(void *fdt, int nodeoff, u32 phandle, + const struct fdt_match *match) +{ + int rc; + struct sophgo_gpio_chip *chip; + unsigned long addr; + + if (SOPHGO_GPIO_CHIP_MAX <= sophgo_gpio_chip_count) { + rc = SBI_ENOSPC; + goto out; + } + + chip = &sophgo_gpio_chip_array[sophgo_gpio_chip_count]; + + rc = sophgo_gpio_addr_get(fdt, nodeoff, &addr); + if (rc) + goto out; + + chip->addr = addr; + chip->chip.driver = &fdt_gpio_sophgo; + chip->chip.id = phandle; + chip->chip.ngpio = SOPHGO_GPIO_PINS_MAX; + chip->chip.direction_output = sophgo_gpio_direction_output; + chip->chip.set = sophgo_gpio_set; + rc = gpio_chip_add(&chip->chip); + + if (rc) + goto out; + + sophgo_gpio_chip_count++; + +out: + fdt_del_node(fdt, nodeoff); + + return rc; +} + +static const struct fdt_match sophgo_gpio_match[] = { + { .compatible = "sophgo,gpio0" }, + { }, +}; + +struct fdt_gpio fdt_gpio_sophgo = { + .match_table = sophgo_gpio_match, + .xlate = fdt_gpio_simple_xlate, + .init = sophgo_gpio_init, +}; diff --git a/lib/utils/gpio/objects.mk b/lib/utils/gpio/objects.mk index 8f4a6a84..4347c858 100644 --- a/lib/utils/gpio/objects.mk +++ b/lib/utils/gpio/objects.mk @@ -13,6 +13,9 @@ libsbiutils-objs-$(CONFIG_FDT_GPIO) += gpio/fdt_gpio_drivers.o carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_SIFIVE) += fdt_gpio_sifive libsbiutils-objs-$(CONFIG_FDT_GPIO_SIFIVE) += gpio/fdt_gpio_sifive.o +carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_SOPHGO) += fdt_gpio_sophgo +libsbiutils-objs-$(CONFIG_FDT_GPIO_SOPHGO) += gpio/fdt_gpio_sophgo.o + carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_STARFIVE) += fdt_gpio_starfive libsbiutils-objs-$(CONFIG_FDT_GPIO_STARFIVE) += gpio/fdt_gpio_starfive.o diff --git a/lib/utils/reset/Kconfig b/lib/utils/reset/Kconfig index 0a1703de..b4e53e46 100644 --- a/lib/utils/reset/Kconfig +++ b/lib/utils/reset/Kconfig @@ -29,11 +29,21 @@ config FDT_RESET_SIFIVE_TEST select SYS_SIFIVE_TEST default n +config FDT_RESET_SOPHGO_CPLD + bool "Sophgo CPLD FDT reset driver" + select SYS_SOPHGO_CPLD + default n + config FDT_RESET_SOPHGO_MCU bool "Sophgo MCU FDT reset driver" select SYS_SOPHGO_MCU default n +config FDT_RESET_SOPHGO_WDT + bool "Sophgo WDT FDT reset driver" + select SYS_SOPHGO_WDT + default n + config FDT_RESET_SUNXI_WDT bool "Sunxi WDT FDT reset driver" default n diff --git a/lib/utils/reset/fdt_reset_sophgo_cpld.c b/lib/utils/reset/fdt_reset_sophgo_cpld.c new file mode 100644 index 00000000..070437de --- /dev/null +++ b/lib/utils/reset/fdt_reset_sophgo_cpld.c @@ -0,0 +1,126 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Sophgo + * + * Authors: + * Chunzhi Lin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct cpld_reset { + struct gpio_pin pin; + u32 active_delay; + u32 inactive_delay; +}; + +static struct cpld_reset poweroff = { + .active_delay = 300, + .inactive_delay = 300 +}; + +static struct cpld_reset *cpld_reset_get(u32 type) +{ + struct cpld_reset *reset = NULL; + + switch (type) { + case SBI_SRST_RESET_TYPE_SHUTDOWN: + reset = &poweroff; + break; + case SBI_SRST_RESET_TYPE_COLD_REBOOT: + case SBI_SRST_RESET_TYPE_WARM_REBOOT: + break; + } + + if (reset && !reset->pin.chip) + reset = NULL; + + return reset; +} + +static void cpld_reset_exec(struct cpld_reset *reset) +{ + if (reset) { + /* drive it active, also inactive->active edge */ + gpio_direction_output(&reset->pin, 1); + sbi_timer_mdelay(reset->active_delay); + + /* drive inactive, also active->inactive edge */ + gpio_set(&reset->pin, 0); + sbi_timer_mdelay(reset->inactive_delay); + } + /* hang !!! */ + sbi_hart_hang(); +} + +static int cpld_system_poweroff_check(u32 type, u32 reason) +{ + if (cpld_reset_get(type)) + return 128; + + return 0; +} + +static void cpld_system_poweroff(u32 type, u32 reason) +{ + cpld_reset_exec(cpld_reset_get(type)); +} + +static struct sbi_system_reset_device mango_reset_gpio = { + .name = "mango-cpld", + .system_reset_check = cpld_system_poweroff_check, + .system_reset = cpld_system_poweroff +}; + +static int mango_cpld_reset_init(void *fdt, int nodeoff, + const struct fdt_match *match) +{ + int rc, len; + const fdt32_t *val; + struct cpld_reset *reset = &poweroff; + const char *dir_prop = "output"; + + rc = fdt_gpio_pin_get(fdt, nodeoff, 0, &reset->pin); + if (rc) + goto out; + + if (fdt_getprop(fdt, nodeoff, dir_prop, &len)) { + rc = gpio_direction_output(&reset->pin, 0); + if (rc) + goto out; + } + + val = fdt_getprop(fdt, nodeoff, "active-delay-ms", &len); + if (len > 0) + reset->active_delay = fdt32_to_cpu(*val); + + val = fdt_getprop(fdt, nodeoff, "inactive-delay-ms", &len); + if (len > 0) + reset->inactive_delay = fdt32_to_cpu(*val); + + sbi_system_reset_add_device(&mango_reset_gpio); + +out: + fdt_del_node(fdt, nodeoff); + + return rc; +} + +static const struct fdt_match mango_cpld_reset_match[] = { + { .compatible = "mango,cpld-reset", .data = (void *)true}, + { }, +}; + +struct fdt_reset fdt_reset_sophgo_cpld = { + .match_table = mango_cpld_reset_match, + .init = mango_cpld_reset_init, +}; \ No newline at end of file diff --git a/lib/utils/reset/fdt_reset_sophgo_wdt.c b/lib/utils/reset/fdt_reset_sophgo_wdt.c new file mode 100644 index 00000000..799eb0bb --- /dev/null +++ b/lib/utils/reset/fdt_reset_sophgo_wdt.c @@ -0,0 +1,122 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Sophgo + * + * Authors: + * Chunzhi Lin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TOP_BASE 0x7030010000 +#define SOPHGO_TOP_CTRL_REG_OFFSET 0x008 + +#define REG_BIT(offset) (1U << (offset)) +#define BIT_MASK_TOP_CTRL_SW_ROOT_RESET_EN REG_BIT(2) + +#define SOPHGO_WDT_CR_REG_OFFSET 0x00 +#define SOPHGO_WDT_TORR_REG_OFFSET 0x04 +#define SOPHGO_WDT_CRR_REG_OFFSET 0x0C + +static volatile char *sophgo_wdt_base; +static volatile char *sophgo_top_base; + +static void sophgo_wdt_system_reset(u32 type, u32 reason) +{ + u32 val; + + val = readl(sophgo_top_base + SOPHGO_TOP_CTRL_REG_OFFSET); + writel((val | BIT_MASK_TOP_CTRL_SW_ROOT_RESET_EN), + sophgo_top_base + SOPHGO_TOP_CTRL_REG_OFFSET); + sbi_timer_udelay(1); + + /*next reset time = 2^(16 + 0x0b) / 100M = 1.34s */ + writel(0x0b, sophgo_wdt_base + SOPHGO_WDT_TORR_REG_OFFSET); + sbi_timer_udelay(1); + + /* a safety feature for counter restart register */ + writel(0x76, sophgo_wdt_base + SOPHGO_WDT_CRR_REG_OFFSET); + sbi_timer_udelay(1); + + /* reset pluse length: 32 pclk cycles; enable wdt */ + writel(0x11, sophgo_wdt_base + SOPHGO_WDT_CR_REG_OFFSET); + + return; +} + +static int sophgo_wdt_system_reset_check(u32 type, u32 reason) +{ + switch (type) { + case SBI_SRST_RESET_TYPE_COLD_REBOOT: + case SBI_SRST_RESET_TYPE_WARM_REBOOT: + return 1; + } + + return 0; +} + +static int sophgo_wdt_system_get_top_base(void *fdt, + int nodeoff, unsigned long *addr) +{ + const fdt32_t *val; + int len, noff; + + val = fdt_getprop(fdt, nodeoff, "subctrl-syscon", &len); + if (val || len >= sizeof(fdt32_t)) { + noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val)); + if (noff < 0) + return noff; + } + + return fdt_get_node_addr_size(fdt, noff, 0, addr, NULL); +} + +static struct sbi_system_reset_device mango_reset_wdt = { + .name = "mango-wdt", + .system_reset_check = sophgo_wdt_system_reset_check, + .system_reset = sophgo_wdt_system_reset, +}; + +static int mango_wdt_reset_init(void *fdt, int nodeoff, + const struct fdt_match *match) +{ + unsigned long wdt_addr, top_addr; + int rc; + // struct device_node *np; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &wdt_addr, NULL); + if (rc < 0 || !wdt_addr) { + return SBI_ENODEV; + } + + sophgo_wdt_base = (volatile char *)(unsigned long)wdt_addr; + + rc = sophgo_wdt_system_get_top_base(fdt, nodeoff, &top_addr); + if (rc < 0 || !top_addr) + return SBI_ENODEV; + + sophgo_top_base = (volatile char *)(unsigned long)top_addr; + + sbi_system_reset_add_device(&mango_reset_wdt); + + return 0; +} + +static const struct fdt_match mango_wdt_reset_match[] = { + { .compatible = "mango,wdt-reset", .data = (void *)true}, + { }, +}; + +struct fdt_reset fdt_reset_sophgo_wdt = { + .match_table = mango_wdt_reset_match, + .init = mango_wdt_reset_init, +}; diff --git a/lib/utils/reset/objects.mk b/lib/utils/reset/objects.mk index 209a1fba..a0abf108 100644 --- a/lib/utils/reset/objects.mk +++ b/lib/utils/reset/objects.mk @@ -23,9 +23,15 @@ libsbiutils-objs-$(CONFIG_FDT_RESET_HTIF) += reset/fdt_reset_htif.o carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SIFIVE_TEST) += fdt_reset_sifive_test libsbiutils-objs-$(CONFIG_FDT_RESET_SIFIVE_TEST) += reset/fdt_reset_sifive_test.o +carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += fdt_reset_sophgo_cpld +libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += reset/fdt_reset_sophgo_cpld.o + carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SOPHGO_MCU) += fdt_reset_sophgo_mcu libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_MCU) += reset/fdt_reset_sophgo_mcu.o +carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SOPHGO_WDT) += fdt_reset_sophgo_wdt +libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_WDT) += reset/fdt_reset_sophgo_wdt.o + carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SUNXI_WDT) += fdt_reset_sunxi_wdt libsbiutils-objs-$(CONFIG_FDT_RESET_SUNXI_WDT) += reset/fdt_reset_sunxi_wdt.o diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index b20ab30a..ed52c92d 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -7,6 +7,7 @@ CONFIG_PLATFORM_STARFIVE_JH7110=y CONFIG_PLATFORM_SOPHGO_MANGO=y CONFIG_FDT_GPIO=y CONFIG_FDT_GPIO_SIFIVE=y +CONFIG_FDT_GPIO_SOPHGO=y CONFIG_FDT_GPIO_STARFIVE=y CONFIG_FDT_I2C=y CONFIG_FDT_I2C_SIFIVE=y @@ -23,7 +24,9 @@ CONFIG_FDT_RESET_ATCWDT200=y CONFIG_FDT_RESET_GPIO=y CONFIG_FDT_RESET_HTIF=y CONFIG_FDT_RESET_SIFIVE_TEST=y +CONFIG_FDT_RESET_SOPHGO_CPLD=y CONFIG_FDT_RESET_SOPHGO_MCU=y +CONFIG_FDT_RESET_SOPHGO_WDT=y CONFIG_FDT_RESET_SUNXI_WDT=y CONFIG_FDT_RESET_THEAD=y CONFIG_FDT_SERIAL=y