This imports support for the StarFive GPIO controller from the vendor's kernel tree. Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-starfive-vic.c | 177 +++++++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-single.c | 4 +- include/pinctrl.h | 6 ++ 5 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 drivers/gpio/gpio-starfive-vic.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a8ee9e58b84e..98a44fbbb578 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -171,6 +171,14 @@ config GPIO_SIFIVE help Say yes here to support the GPIO device on SiFive SoCs. +config GPIO_STARFIVE + bool "StarFive GPIO support" + depends on SOC_STARFIVE || CROSS_COMPILE + depends on OF_GPIO + select GPIO_GENERIC + help + Say yes here to support the GPIO device on StarFive SoCs. + config GPIO_LIBFTDI1 bool "libftdi1 driver" depends on SANDBOX diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 25e12105d83d..638cbb19a328 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o obj-$(CONFIG_GPIO_SIFIVE) += gpio-sifive.o +obj-$(CONFIG_GPIO_STARFIVE) += gpio-starfive-vic.o diff --git a/drivers/gpio/gpio-starfive-vic.c b/drivers/gpio/gpio-starfive-vic.c new file mode 100644 index 000000000000..baa4f584d5e8 --- /dev/null +++ b/drivers/gpio/gpio-starfive-vic.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * COPYRIGHT 2020 Shanghai StarFive Technology Co., Ltd. + */ + +#include <linux/basic_mmio_gpio.h> +#include <linux/reset.h> +#include <linux/clk.h> +#include <printk.h> +#include <driver.h> +#include <errno.h> +#include <pinctrl.h> + +#define GPIO_EN 0x0 +#define GPIO_IS_LOW 0x10 +#define GPIO_IS_HIGH 0x14 +#define GPIO_IBE_LOW 0x18 +#define GPIO_IBE_HIGH 0x1c +#define GPIO_IEV_LOW 0x20 +#define GPIO_IEV_HIGH 0x24 +#define GPIO_IE_LOW 0x28 +#define GPIO_IE_HIGH 0x2c +#define GPIO_IC_LOW 0x30 +#define GPIO_IC_HIGH 0x34 +//read only +#define GPIO_RIS_LOW 0x38 +#define GPIO_RIS_HIGH 0x3c +#define GPIO_MIS_LOW 0x40 +#define GPIO_MIS_HIGH 0x44 +#define GPIO_DIN_LOW 0x48 +#define GPIO_DIN_HIGH 0x4c + +#define GPIO_DOUT_X_REG 0x50 +#define GPIO_DOEN_X_REG 0x54 + +#define MAX_GPIO 64 + +struct starfive_gpio { + void __iomem *base; + struct gpio_chip gc; +}; + +#define to_starfive_gpio(gc) container_of(gc, struct starfive_gpio, gc) + +static int starfive_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct starfive_gpio *chip = to_starfive_gpio(gc); + + if (offset >= gc->ngpio) + return -EINVAL; + + writel(0x1, chip->base + GPIO_DOEN_X_REG + offset * 8); + + return 0; +} + +static int starfive_direction_output(struct gpio_chip *gc, unsigned offset, int value) +{ + struct starfive_gpio *chip = to_starfive_gpio(gc); + + if (offset >= gc->ngpio) + return -EINVAL; + writel(0x0, chip->base + GPIO_DOEN_X_REG + offset * 8); + writel(value, chip->base + GPIO_DOUT_X_REG + offset * 8); + + return 0; +} + +static int starfive_get_direction(struct gpio_chip *gc, unsigned offset) +{ + struct starfive_gpio *chip = to_starfive_gpio(gc); + + if (offset >= gc->ngpio) + return -EINVAL; + + return readl(chip->base + GPIO_DOEN_X_REG + offset * 8) & 0x1; +} + +static int starfive_get_value(struct gpio_chip *gc, unsigned offset) +{ + struct starfive_gpio *chip = to_starfive_gpio(gc); + int value; + + if (offset >= gc->ngpio) + return -EINVAL; + + if(offset < 32){ + value = readl(chip->base + GPIO_DIN_LOW); + return (value >> offset) & 0x1; + } else { + value = readl(chip->base + GPIO_DIN_HIGH); + return (value >> (offset - 32)) & 0x1; + } +} + +static void starfive_set_value(struct gpio_chip *gc, unsigned offset, int value) +{ + struct starfive_gpio *chip = to_starfive_gpio(gc); + + if (offset >= gc->ngpio) + return; + + writel(value, chip->base + GPIO_DOUT_X_REG + offset * 8); +} + +static struct gpio_ops starfive_gpio_ops = { + .direction_input = starfive_direction_input, + .direction_output = starfive_direction_output, + .get_direction = starfive_get_direction, + .get = starfive_get_value, + .set = starfive_set_value, +}; + +static int starfive_gpio_probe(struct device_d *dev) +{ + struct starfive_gpio *chip; + struct resource *res; + struct clk *clk; + int ret; + + clk = clk_get(dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + clk_enable(clk); + + ret = device_reset(dev); + if (ret) + return ret; + + ret = pinctrl_single_probe(dev); + if (ret) + return ret; + + res = dev_get_resource(dev, IORESOURCE_MEM, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + + chip = xzalloc(sizeof(*chip)); + chip->base = IOMEM(res->start); + + chip->gc.base = -1; + chip->gc.ngpio = MAX_GPIO; + chip->gc.dev = dev; + chip->gc.ops = &starfive_gpio_ops; + + /* Disable all GPIO interrupts */ + iowrite32(0, chip->base + GPIO_IE_HIGH); + iowrite32(0, chip->base + GPIO_IE_LOW); + + ret = gpiochip_add(&chip->gc); + if (ret) { + dev_err(dev, "could not add gpiochip\n"); + gpiochip_remove(&chip->gc); + return ret; + } + + writel(1, chip->base + GPIO_EN); + + return 0; +} + +static const struct of_device_id starfive_gpio_match[] = { + { .compatible = "starfive,gpio0", }, + { }, +}; + +static struct driver_d starfive_gpio_driver = { + .probe = starfive_gpio_probe, + .name = "starfive_gpio", + .of_compatible = starfive_gpio_match, +}; +postcore_platform_driver(starfive_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huan Feng <huan.feng@xxxxxxxxxxxxxxxx>"); +MODULE_DESCRIPTION("Starfive VIC GPIO generator driver"); diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index c77466023216..cf2f724d187d 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -128,7 +128,7 @@ static struct pinctrl_ops pcs_ops = { .set_state = pcs_set_state, }; -static int pcs_probe(struct device_d *dev) +int pinctrl_single_probe(struct device_d *dev) { struct resource *iores; struct pinctrl_single *pcs; @@ -215,7 +215,7 @@ static __maybe_unused struct of_device_id pcs_dt_ids[] = { static struct driver_d pcs_driver = { .name = "pinctrl-single", - .probe = pcs_probe, + .probe = pinctrl_single_probe, .of_compatible = DRV_OF_COMPAT(pcs_dt_ids), }; diff --git a/include/pinctrl.h b/include/pinctrl.h index 0fd7f491189c..a628c3aac95b 100644 --- a/include/pinctrl.h +++ b/include/pinctrl.h @@ -29,6 +29,7 @@ int of_pinctrl_select_state_default(struct device_node *np); int pinctrl_gpio_direction_input(unsigned pin); int pinctrl_gpio_direction_output(unsigned int pin); int pinctrl_gpio_get_direction(unsigned pin); +int pinctrl_single_probe(struct device_d *dev); #else static inline int pinctrl_select_state(struct device_d *dev, const char *state) { @@ -64,6 +65,11 @@ static inline int pinctrl_gpio_get_direction(unsigned pin) { return -ENOTSUPP; } + +static inline int pinctrl_single_probe(struct device_d *dev) +{ + return -ENOSYS; +} #endif #endif /* PINCTRL_H */ -- 2.29.2 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox