Hi Bin, On Wed, Oct 2, 2019 at 6:33 PM Bin Meng <[email protected]> wrote: > > On Wed, Oct 2, 2019 at 1:01 AM Sagar Shrikant Kadam > <[email protected]> wrote: > > > > This patch adds a DM based driver model for gpio controller present in > > FU540-C000 SoC on HiFive Unleashed A00 board. This SoC has one GPIO > > bank and 16 GPIO lines in total, out of which GPIO0 to GPIO9 and > > GPIO15 are routed to the J1 header on the board. > > > > This implementation is ported from linux based gpio driver submitted > > for review by Wesley W. Terpstra <[email protected]> and/or Atish Patra > > <[email protected]> (many thanks !!). The linux driver can be referred > > here [1] > > > > [1]: https://lkml.org/lkml/2018/10/9/1103 > > > > Signed-off-by: Sagar Shrikant Kadam <[email protected]> > > --- > > arch/riscv/include/asm/arch-generic/gpio.h | 35 ++++++ > > arch/riscv/include/asm/gpio.h | 6 + > > drivers/gpio/Kconfig | 7 ++ > > drivers/gpio/Makefile | 1 + > > drivers/gpio/sifive-gpio.c | 177 > > +++++++++++++++++++++++++++++ > > 5 files changed, 226 insertions(+) > > create mode 100644 arch/riscv/include/asm/arch-generic/gpio.h > > create mode 100644 arch/riscv/include/asm/gpio.h > > create mode 100644 drivers/gpio/sifive-gpio.c > > > > diff --git a/arch/riscv/include/asm/arch-generic/gpio.h > > b/arch/riscv/include/asm/arch-generic/gpio.h > > new file mode 100644 > > index 0000000..dfcb753 > > --- /dev/null > > +++ b/arch/riscv/include/asm/arch-generic/gpio.h > > @@ -0,0 +1,35 @@ > > +/* SPDX-License-Identifier: GPL-2.0+ */ > > +/* > > + * Copyright (C) 2019 SiFive, Inc. > > + */ > > + > > +#ifndef _GPIO_SIFIVE_H > > +#define _GPIO_SIFIVE_H > > + > > +#define GPIO_INPUT_VAL 0x00 > > +#define GPIO_INPUT_EN 0x04 > > +#define GPIO_OUTPUT_EN 0x08 > > +#define GPIO_OUTPUT_VAL 0x0C > > +#define GPIO_RISE_IE 0x18 > > +#define GPIO_RISE_IP 0x1C > > +#define GPIO_FALL_IE 0x20 > > +#define GPIO_FALL_IP 0x24 > > +#define GPIO_HIGH_IE 0x28 > > +#define GPIO_HIGH_IP 0x2C > > +#define GPIO_LOW_IE 0x30 > > +#define GPIO_LOW_IP 0x34 > > +#define GPIO_OUTPUT_XOR 0x40 > > + > > +#define NR_GPIOS 16 > > + > > +enum gpio_state { > > + LOW, > > + HIGH > > +}; > > + > > +/* Details about a GPIO bank */ > > +struct sifive_gpio_platdata { > > + void *base; /* address of registers in physical memory */ > > +}; > > + > > +#endif /* _GPIO_SIFIVE_H */ > > diff --git a/arch/riscv/include/asm/gpio.h b/arch/riscv/include/asm/gpio.h > > new file mode 100644 > > index 0000000..008d756 > > --- /dev/null > > +++ b/arch/riscv/include/asm/gpio.h > > @@ -0,0 +1,6 @@ > > +/* SPDX-License-Identifier: GPL-2.0+ */ > > +/* > > + * Copyright 2018 SiFive, Inc. > > + */ > > + > > +#include <asm-generic/gpio.h> > > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > > index f2dabb5..39f2c7e 100644 > > --- a/drivers/gpio/Kconfig > > +++ b/drivers/gpio/Kconfig > > @@ -285,6 +285,13 @@ config STM32_GPIO > > usable on many stm32 families like stm32f4/f7/h7 and stm32mp1. > > Tested on STM32F7. > > > > +config SIFIVE_GPIO > > + bool "SiFive GPIO driver" > > + depends on DM_GPIO > > + help > > + Device model driver for GPIO controller present in SiFive FU540 > > SoC. This > > + driver enables GPIO interface on HiFive Unleashed A00 board. > > + > > config MVEBU_GPIO > > bool "Marvell MVEBU GPIO driver" > > depends on DM_GPIO && ARCH_MVEBU > > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > > index 4a8aa0f..ccc49e2 100644 > > --- a/drivers/gpio/Makefile > > +++ b/drivers/gpio/Makefile > > @@ -61,3 +61,4 @@ obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o > > obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o > > obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o > > obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o > > +obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o > > diff --git a/drivers/gpio/sifive-gpio.c b/drivers/gpio/sifive-gpio.c > > new file mode 100644 > > index 0000000..76d5a1d3 > > --- /dev/null > > +++ b/drivers/gpio/sifive-gpio.c > > @@ -0,0 +1,177 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* > > + * SiFive GPIO driver > > + * > > + * Copyright (C) 2019 SiFive, Inc. > > + */ > > + > > +#include <common.h> > > +#include <dm.h> > > +#include <asm/arch/gpio.h> > > +#include <asm/io.h> > > +#include <errno.h> > > +#include <asm/gpio.h> > > + > > +static int sifive_gpio_probe(struct udevice *dev) > > +{ > > + struct sifive_gpio_platdata *plat = dev_get_platdata(dev); > > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); > > + char name[18], *str; > > + > > + sprintf(name, "gpio@%4lx_", (uintptr_t)plat->base); > > + str = strdup(name); > > + if (!str) > > + return -ENOMEM; > > + uc_priv->bank_name = str; > > + > > + /* > > + * Use the gpio count mentioned in device tree, > > + * if not specified in dt, set NR_GPIOS as default > > + */ > > + uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", NR_GPIOS); > > + > > + return 0; > > +} > > + > > +static void sifive_update_gpio_reg(void *bptr, u32 offset, bool value) > > +{ > > + void __iomem *ptr = (void __iomem *)bptr; > > + > > + u32 bit = BIT(offset); > > + u32 old = readl(ptr); > > + > > + if (value) > > + writel(old | bit, ptr); > > + else > > + writel(old & ~bit, ptr); > > +} > > + > > +static int sifive_gpio_direction_input(struct udevice *dev, u32 offset) > > +{ > > + struct sifive_gpio_platdata *plat = dev_get_platdata(dev); > > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); > > + > > + if (offset > uc_priv->gpio_count) > > + return -EINVAL; > > + > > + /* Configure gpio direction as input */ > > + sifive_update_gpio_reg(plat->base + GPIO_INPUT_EN, offset, true); > > + sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, false); > > + > > + return 0; > > +} > > + > > +static int sifive_gpio_direction_output(struct udevice *dev, u32 offset, > > + int value) > > +{ > > + struct sifive_gpio_platdata *plat = dev_get_platdata(dev); > > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); > > + > > + if (offset > uc_priv->gpio_count) > > + return -EINVAL; > > + > > + /* Configure gpio direction as output */ > > + sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, true); > > + sifive_update_gpio_reg(plat->base + GPIO_INPUT_EN, offset, false); > > + > > + /* Set the output state of the pin */ > > + sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value); > > + > > + return 0; > > +} > > + > > +static int sifive_gpio_get_value(struct udevice *dev, u32 offset) > > +{ > > + struct sifive_gpio_platdata *plat = dev_get_platdata(dev); > > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); > > + int val; > > + int dir; > > + > > + if (offset > uc_priv->gpio_count) > > + return -EINVAL; > > + > > + /* Get direction of the pin */ > > + dir = !(readl(plat->base + GPIO_OUTPUT_EN) & BIT(offset)); > > + > > + if (dir) > > + val = readl(plat->base + GPIO_INPUT_VAL) & BIT(offset); > > + else > > + val = readl(plat->base + GPIO_OUTPUT_VAL) & BIT(offset); > > + > > + return val ? HIGH : LOW; > > +} > > + > > +static int sifive_gpio_set_value(struct udevice *dev, u32 offset, int > > value) > > +{ > > + struct sifive_gpio_platdata *plat = dev_get_platdata(dev); > > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); > > + > > + if (offset > uc_priv->gpio_count) > > + return -EINVAL; > > + > > + sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value); > > + > > + return 0; > > +} > > + > > +static int sifive_gpio_get_function(struct udevice *dev, unsigned int > > offset) > > +{ > > + struct sifive_gpio_platdata *plat = dev_get_platdata(dev); > > + u32 outdir, indir, val; > > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); > > + > > + if (offset > uc_priv->gpio_count) > > + return -1; > > + > > + /* Get direction of the pin */ > > + outdir = readl(plat->base + GPIO_OUTPUT_EN) & BIT(offset); > > + indir = readl(plat->base + GPIO_INPUT_EN) & BIT(offset); > > + > > + if (outdir) > > + /* Pin at specified offset is configured as output */ > > + val = GPIOF_OUTPUT; > > + else if (indir) > > + /* Pin at specified offset is configured as input */ > > + val = GPIOF_INPUT; > > + else > > + /*The requested GPIO is not set as input or output */ > > nits: need a space after /* > > > + val = GPIOF_UNUSED; > > + > > + return val; > > +} > > + > > +static const struct udevice_id sifive_gpio_match[] = { > > + { .compatible = "sifive,gpio0" }, > > + { } > > +}; > > + > > +static const struct dm_gpio_ops sifive_gpio_ops = { > > + .direction_input = sifive_gpio_direction_input, > > + .direction_output = sifive_gpio_direction_output, > > + .get_value = sifive_gpio_get_value, > > + .set_value = sifive_gpio_set_value, > > + .get_function = sifive_gpio_get_function, > > +}; > > + > > +static int sifive_gpio_ofdata_to_platdata(struct udevice *dev) > > +{ > > + struct sifive_gpio_platdata *plat = dev_get_platdata(dev); > > + fdt_addr_t addr; > > + > > + addr = devfdt_get_addr(dev); > > + if (addr == FDT_ADDR_T_NONE) > > + return -EINVAL; > > + > > + plat->base = (void *)addr; > > + return 0; > > +} > > + > > +U_BOOT_DRIVER(gpio_sifive) = { > > + .name = "gpio_sifive", > > + .id = UCLASS_GPIO, > > + .of_match = sifive_gpio_match, > > + .ofdata_to_platdata = of_match_ptr(sifive_gpio_ofdata_to_platdata), > > + .platdata_auto_alloc_size = sizeof(struct sifive_gpio_platdata), > > + .ops = &sifive_gpio_ops, > > + .probe = sifive_gpio_probe, > > +}; > > -- > > Other than above, > > Reviewed-by: Bin Meng <[email protected]>
Thanks for the review !! BR, Sagar Kadam _______________________________________________ U-Boot mailing list [email protected] https://lists.denx.de/listinfo/u-boot

