[U-Boot] [U-BOOT PATCH v1 1/2] gpio: fu540: add support for DM based gpio driver for FU540-SoC
Sagar Kadam
sagar.kadam at sifive.com
Wed Sep 25 17:58:30 UTC 2019
Hi Bin,
On Wed, Sep 18, 2019 at 3:09 PM Bin Meng <bmeng.cn at gmail.com> wrote:
>
> Hi Sagar,
>
> On Tue, Sep 10, 2019 at 11:44 PM Sagar Shrikant Kadam
> <sagar.kadam at sifive.com> 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 <wesley at sifive.com> and/or Atish Patra
> > <atish.patra at wdc.com> (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 <sagar.kadam at sifive.com>
> > ---
> > arch/riscv/include/asm/arch-generic/gpio.h | 35 +++++++
> > arch/riscv/include/asm/gpio.h | 6 ++
> > drivers/gpio/Kconfig | 8 ++
> > drivers/gpio/Makefile | 1 +
> > drivers/gpio/sifive-gpio.c | 143 +++++++++++++++++++++++++++++
> > 5 files changed, 193 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..7287298
> > --- /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_FU540_H
>
> _GPIO_SIFIVE_H
>
> > +#define _GPIO_FU540_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 fu540_gpio_platdata {
>
> sifive_gpio_platdata
>
Ok.
> > + void *base; /* address of registers in physical memory */
> > +};
> > +
> > +#endif /* _GPIO_FU540_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..ec48f26 100644
> > --- a/drivers/gpio/Kconfig
> > +++ b/drivers/gpio/Kconfig
> > @@ -285,6 +285,14 @@ config STM32_GPIO
> > usable on many stm32 families like stm32f4/f7/h7 and stm32mp1.
> > Tested on STM32F7.
> >
> > +config SIFIVE_GPIO
> > + bool "SiFive FU540 GPIO driver"
>
> just "SiFive GPIO driver"?
>
Ok. Will exclude FU540 from above.
> > + depends on DM_GPIO
> > + help
> > + Device model driver for GPIO controller present in FU540 SoC. This
>
> present in SiFive FU540 SoC
>
> > + driver enables GPIO interface on HiFive Unleashed A00 board a board
>
> remove "a board"
OK.
>
> > + from SiFive Inc. having FU540-C000 SoC.
>
> remove this line
>
Ok
> > +
> > 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..4bf8acf
> > --- /dev/null
> > +++ b/drivers/gpio/sifive-gpio.c
> > @@ -0,0 +1,143 @@
> > +// 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 fu540_gpio_probe(struct udevice *dev)
>
> Please rename all function names to have "sifive_" prefix.
>
Ok. I will update with all of the above changes and resend a v2.
Thanks & BR,
Sagar Kadam
> > +{
> > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
> > +
> > + uc_priv->bank_name = dev->name;
> > +
> > + /*
> > + * 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 fu540_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 fu540_gpio_direction_input(struct udevice *dev, u32 offset)
> > +{
> > + struct fu540_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 */
> > + fu540_update_gpio_reg(plat->base + GPIO_INPUT_EN, offset, true);
> > + fu540_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, false);
> > +
> > + return 0;
> > +}
> > +
> > +static int fu540_gpio_direction_output(struct udevice *dev, u32 offset,
> > + int value)
> > +{
> > + struct fu540_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 */
> > + fu540_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, true);
> > + fu540_update_gpio_reg(plat->base + GPIO_INPUT_EN, offset, false);
> > +
> > + /* Set the Output state of the PIN */
> > + fu540_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value);
> > +
> > + return 0;
> > +}
> > +
> > +static int fu540_gpio_get_value(struct udevice *dev, u32 offset)
> > +{
> > + struct fu540_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 OUTPUT=0 INPUT=1 */
> > + 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 fu540_gpio_set_value(struct udevice *dev, u32 offset, int value)
> > +{
> > + struct fu540_gpio_platdata *plat = dev_get_platdata(dev);
> > +
> > + if (offset > NR_GPIOS)
> > + return -EINVAL;
> > +
> > + fu540_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value);
> > +
> > + return 0;
> > +}
> > +
> > +static const struct udevice_id fu540_gpio_match[] = {
> > + { .compatible = "sifive,gpio0" },
> > + { }
> > +};
> > +
> > +static const struct dm_gpio_ops gpio_sifive_ops = {
> > + .direction_input = fu540_gpio_direction_input,
> > + .direction_output = fu540_gpio_direction_output,
> > + .get_value = fu540_gpio_get_value,
> > + .set_value = fu540_gpio_set_value,
> > +};
> > +
> > +static int fu540_gpio_ofdata_to_platdata(struct udevice *dev)
> > +{
> > + struct fu540_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 = fu540_gpio_match,
> > + .ofdata_to_platdata = of_match_ptr(fu540_gpio_ofdata_to_platdata),
> > + .platdata_auto_alloc_size = sizeof(struct fu540_gpio_platdata),
> > + .ops = &gpio_sifive_ops,
> > + .probe = fu540_gpio_probe,
> > +};
> > --
>
> Regards,
> Bin
More information about the U-Boot
mailing list