> Date: Thu, 17 Feb 2022 16:16:30 +0000
> From: Visa Hankala <[email protected]>
>
> On Thu, Feb 17, 2022 at 03:38:05PM +0100, Mark Kettenis wrote:
> > > Date: Thu, 17 Feb 2022 13:52:39 +0000
> > > From: Visa Hankala <[email protected]>
> > >
> > > This patch adds a driver for the PolarFire SoC MSS GPIO controller.
> > >
> > > The driver provides a gpio(4) interface, so the patch also enables
> > > gpioctl(8) on riscv64. The MAKEDEV script already creates gpio nodes.
> > >
> > > OK?
> >
> > So on arm64 I've been trying to build in protection against userland
> > access to GPIOs used by kernel drivers. See for example bcmgpio(4) or
> > sxipio(4). I think it would be good if we did the same thing on
> > riscv64.
>
> Sure, here is a revised diff. Now the driver tracks which pins get
> configured. The pins that were claimed during autoconfiguration are
> skipped when setting up gpio(4).
Yes I think that's better.
ok kettenis@
> Index: share/man/man4/gpio.4
> ===================================================================
> RCS file: src/share/man/man4/gpio.4,v
> retrieving revision 1.27
> diff -u -p -r1.27 gpio.4
> --- share/man/man4/gpio.4 16 May 2020 16:37:49 -0000 1.27
> +++ share/man/man4/gpio.4 17 Feb 2022 15:45:40 -0000
> @@ -27,6 +27,7 @@
> .Cd "gpio* at glxpcib?" Pq i386
> .Cd "gpio* at gscpcib?" Pq i386
> .Cd "gpio* at isagpio?"
> +.Cd "gpio* at mpfgpio?" Pq riscv64
> .Cd "gpio* at nsclpcsio?"
> .Cd "gpio* at omgpio?" Pq armv7
> .Cd "gpio* at pcagpio?"
> Index: share/man/man4/man4.riscv64/Makefile
> ===================================================================
> RCS file: src/share/man/man4/man4.riscv64/Makefile,v
> retrieving revision 1.5
> diff -u -p -r1.5 Makefile
> --- share/man/man4/man4.riscv64/Makefile 16 Feb 2022 13:07:36 -0000
> 1.5
> +++ share/man/man4/man4.riscv64/Makefile 17 Feb 2022 15:45:40 -0000
> @@ -1,6 +1,6 @@
> # $OpenBSD: Makefile,v 1.5 2022/02/16 13:07:36 visa Exp $
>
> -MAN= intro.4 mpfclock.4 mpfiic.4 plic.4 sfcc.4 sfclock.4 sfuart.4
> +MAN= intro.4 mpfclock.4 mpfgpio.4 mpfiic.4 plic.4 sfcc.4 sfclock.4 sfuart.4
>
> MANSUBDIR=riscv64
>
> Index: share/man/man4/man4.riscv64/mpfgpio.4
> ===================================================================
> RCS file: share/man/man4/man4.riscv64/mpfgpio.4
> diff -N share/man/man4/man4.riscv64/mpfgpio.4
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ share/man/man4/man4.riscv64/mpfgpio.4 17 Feb 2022 15:45:40 -0000
> @@ -0,0 +1,55 @@
> +.\" $OpenBSD$
> +.\"
> +.\" Copyright (c) 2022 Visa Hankala
> +.\"
> +.\" Permission to use, copy, modify, and distribute this software for any
> +.\" purpose with or without fee is hereby granted, provided that the above
> +.\" copyright notice and this permission notice appear in all copies.
> +.\"
> +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> +.\"
> +.Dd $Mdocdate$
> +.Dt MPFGPIO 4 riscv64
> +.Os
> +.Sh NAME
> +.Nm mpfgpio
> +.Nd Microchip PolarFire SoC MSS GPIO controller
> +.Sh SYNOPSIS
> +.Cd "mpfgpio* at fdt?"
> +.Cd "gpio* at mpfgpio?"
> +.Sh DESCRIPTION
> +The
> +.Nm
> +driver provides support for the Microchip PolarFire SoC MSS GPIO controller.
> +.Pp
> +The PolarFire SoC MSS has three GPIO units:
> +.Dv GPIO_0 ,
> +.Dv GPIO_1
> +and
> +.Dv GPIO_2 .
> +.Dv GPIO_0
> +and
> +.Dv GPIO_1
> +control up to 14 and 24 IOs, respectively.
> +These IOs are routed through IOMUXes.
> +.Dv GPIO_2
> +controls up to 32 IOs through the FPGA fabric.
> +.Pp
> +The IOs can be configured as either inputs or outputs,
> +and accessed using
> +.Xr gpioctl 8 .
> +.Sh SEE ALSO
> +.Xr gpio 4 ,
> +.Xr intro 4 ,
> +.Xr gpioctl 8
> +.Sh HISTORY
> +The
> +.Nm
> +driver first appeared in
> +.Ox 7.1 .
> Index: sys/arch/riscv64/conf/GENERIC
> ===================================================================
> RCS file: src/sys/arch/riscv64/conf/GENERIC,v
> retrieving revision 1.34
> diff -u -p -r1.34 GENERIC
> --- sys/arch/riscv64/conf/GENERIC 16 Feb 2022 13:07:36 -0000 1.34
> +++ sys/arch/riscv64/conf/GENERIC 17 Feb 2022 15:45:40 -0000
> @@ -48,6 +48,8 @@ com* at fdt?
> cdsdhc* at fdt?
> sdmmc* at cdsdhc?
> mpfclock* at fdt? early 1
> +mpfgpio* at fdt?
> +gpio* at mpfgpio?
> mpfiic* at fdt?
> iic* at mpfiic?
>
> Index: sys/arch/riscv64/conf/RAMDISK
> ===================================================================
> RCS file: src/sys/arch/riscv64/conf/RAMDISK,v
> retrieving revision 1.30
> diff -u -p -r1.30 RAMDISK
> --- sys/arch/riscv64/conf/RAMDISK 16 Feb 2022 13:07:36 -0000 1.30
> +++ sys/arch/riscv64/conf/RAMDISK 17 Feb 2022 15:45:40 -0000
> @@ -39,6 +39,8 @@ com* at fdt?
> cdsdhc* at fdt?
> sdmmc* at cdsdhc?
> mpfclock* at fdt? early 1
> +mpfgpio* at fdt?
> +gpio* at mpfgpio?
> mpfiic* at fdt?
> iic* at mpfiic?
>
> Index: sys/arch/riscv64/conf/files.riscv64
> ===================================================================
> RCS file: src/sys/arch/riscv64/conf/files.riscv64,v
> retrieving revision 1.19
> diff -u -p -r1.19 files.riscv64
> --- sys/arch/riscv64/conf/files.riscv64 16 Feb 2022 13:07:36 -0000
> 1.19
> +++ sys/arch/riscv64/conf/files.riscv64 17 Feb 2022 15:45:40 -0000
> @@ -89,6 +89,11 @@ device mpfclock
> attach mpfclock at fdt
> file arch/riscv64/dev/mpfclock.c mpfclock
>
> +# PolarFire SoC MSS GPIO controller
> +device mpfgpio: gpiobus
> +attach mpfgpio at fdt
> +file arch/riscv64/dev/mpfgpio.c mpfgpio
> +
> # PolarFire SoC MSS I2C controller
> device mpfiic: i2cbus
> attach mpfiic at fdt
> @@ -134,6 +139,9 @@ include "dev/ofw/files.ofw"
> # Machine-independent FDT drivers
> include "dev/fdt/files.fdt"
>
> +# Machine-independent GPIO drivers
> +include "dev/gpio/files.gpio"
> +
> # Machine-independent SCSI drivers
> include "scsi/files.scsi"
>
> Index: sys/arch/riscv64/dev/mpfgpio.c
> ===================================================================
> RCS file: sys/arch/riscv64/dev/mpfgpio.c
> diff -N sys/arch/riscv64/dev/mpfgpio.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ sys/arch/riscv64/dev/mpfgpio.c 17 Feb 2022 15:45:40 -0000
> @@ -0,0 +1,294 @@
> +/* $OpenBSD$ */
> +
> +/*
> + * Copyright (c) 2022 Visa Hankala
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +/*
> + * Driver for PolarFire SoC MSS GPIO controller.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/device.h>
> +#include <sys/gpio.h>
> +
> +#include <machine/bus.h>
> +#include <machine/fdt.h>
> +
> +#include <dev/gpio/gpiovar.h>
> +
> +#include <dev/ofw/fdt.h>
> +#include <dev/ofw/openfirm.h>
> +#include <dev/ofw/ofw_clock.h>
> +#include <dev/ofw/ofw_gpio.h>
> +
> +#include "gpio.h"
> +
> +#define MPFGPIO_CONFIG(i) (0x0000 + (i) * 4)
> +#define MPFGPIO_CONFIG_EN_INT (1 << 3)
> +#define MPFGPIO_CONFIG_EN_OE_BUF (1 << 2)
> +#define MPFGPIO_CONFIG_EN_IN (1 << 1)
> +#define MPFGPIO_CONFIG_EN_OUT (1 << 0)
> +#define MPFGPIO_GPIN 0x0084
> +#define MPFGPIO_GPOUT 0x0088
> +#define MPFGPIO_CLEAR_BITS 0x00a0
> +#define MPFGPIO_SET_BITS 0x00a4
> +
> +#define MPFGPIO_MAX_PINS 32
> +
> +struct mpfgpio_softc {
> + struct device sc_dev;
> + bus_space_tag_t sc_iot;
> + bus_space_handle_t sc_ioh;
> + uint32_t sc_npins;
> +
> + struct gpio_controller sc_gc;
> +
> + struct gpio_chipset_tag sc_gpio_tag;
> + gpio_pin_t sc_gpio_pins[MPFGPIO_MAX_PINS];
> + uint8_t sc_gpio_claimed[MPFGPIO_MAX_PINS];
> +};
> +
> +#define HREAD4(sc, reg) \
> + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
> +#define HWRITE4(sc, reg, val) \
> + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
> +
> +int mpfgpio_match(struct device *, void *, void*);
> +void mpfgpio_attach(struct device *, struct device *, void *);
> +
> +void mpfgpio_config_pin(void *, uint32_t *, int);
> +int mpfgpio_get_pin(void *, uint32_t *);
> +void mpfgpio_set_pin(void *, uint32_t *, int);
> +
> +int mpfgpio_pin_read(void *, int);
> +void mpfgpio_pin_write(void *, int, int);
> +void mpfgpio_pin_ctl(void *, int, int);
> +void mpfgpio_attach_gpio(struct device *);
> +
> +const struct cfattach mpfgpio_ca = {
> + sizeof(struct mpfgpio_softc), mpfgpio_match, mpfgpio_attach
> +};
> +
> +struct cfdriver mpfgpio_cd = {
> + NULL, "mpfgpio", DV_DULL
> +};
> +
> +int
> +mpfgpio_match(struct device *parent, void *match, void *aux)
> +{
> + struct fdt_attach_args *faa = aux;
> +
> + if (faa->fa_nreg < 1)
> + return 0;
> + return OF_is_compatible(faa->fa_node, "microchip,mpfs-gpio");
> +}
> +
> +void
> +mpfgpio_attach(struct device *parent, struct device *self, void *aux)
> +{
> + struct fdt_attach_args *faa = aux;
> + struct mpfgpio_softc *sc = (struct mpfgpio_softc *)self;
> + unsigned int unit;
> +
> + sc->sc_iot = faa->fa_iot;
> +
> + unit = (faa->fa_reg[0].addr >> 12) & 0x3;
> + switch (unit) {
> + case 0:
> + sc->sc_npins = 14;
> + break;
> + case 1:
> + sc->sc_npins = 24;
> + break;
> + case 2:
> + sc->sc_npins = 32;
> + break;
> + default:
> + printf(": unexpected GPIO unit %u\n", unit);
> + return;
> + }
> + KASSERT(sc->sc_npins <= MPFGPIO_MAX_PINS);
> +
> + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
> + 0, &sc->sc_ioh) != 0) {
> + printf(": can't map registers\n");
> + return;
> + }
> +
> + clock_enable_all(faa->fa_node);
> +
> + printf(": unit %u\n", unit);
> +
> + sc->sc_gc.gc_node = faa->fa_node;
> + sc->sc_gc.gc_cookie = sc;
> + sc->sc_gc.gc_config_pin = mpfgpio_config_pin;
> + sc->sc_gc.gc_get_pin = mpfgpio_get_pin;
> + sc->sc_gc.gc_set_pin = mpfgpio_set_pin;
> + gpio_controller_register(&sc->sc_gc);
> +
> +#if NGPIO > 0
> + config_mountroot(self, mpfgpio_attach_gpio);
> +#endif
> +}
> +
> +void
> +mpfgpio_config_pin(void *cookie, uint32_t *cells, int config)
> +{
> + struct mpfgpio_softc *sc = cookie;
> + uint32_t pin = cells[0];
> + uint32_t val;
> +
> + if (pin >= sc->sc_npins)
> + return;
> +
> + val = HREAD4(sc, MPFGPIO_CONFIG(pin));
> + if (config & GPIO_CONFIG_OUTPUT) {
> + val &= ~MPFGPIO_CONFIG_EN_IN;
> + val |= MPFGPIO_CONFIG_EN_OUT;
> + } else {
> + val |= MPFGPIO_CONFIG_EN_IN;
> + val &= ~MPFGPIO_CONFIG_EN_OUT;
> + }
> + val &= ~MPFGPIO_CONFIG_EN_INT;
> + HWRITE4(sc, MPFGPIO_CONFIG(pin), val);
> +
> + sc->sc_gpio_claimed[pin] = 1;
> +}
> +
> +int
> +mpfgpio_get_pin(void *cookie, uint32_t *cells)
> +{
> + struct mpfgpio_softc *sc = cookie;
> + uint32_t pin = cells[0];
> + uint32_t flags = cells[1];
> + int val;
> +
> + if (pin >= sc->sc_npins)
> + return 0;
> +
> + val = (HREAD4(sc, MPFGPIO_GPIN) >> pin) & 1;
> + if (flags & GPIO_ACTIVE_LOW)
> + val = !val;
> + return val;
> +}
> +
> +void
> +mpfgpio_set_pin(void *cookie, uint32_t *cells, int val)
> +{
> + struct mpfgpio_softc *sc = cookie;
> + uint32_t pin = cells[0];
> + uint32_t flags = cells[1];
> +
> + if (pin >= sc->sc_npins)
> + return;
> +
> + if (flags & GPIO_ACTIVE_LOW)
> + val = !val;
> + if (val)
> + HWRITE4(sc, MPFGPIO_SET_BITS, (1U << (pin % 32)));
> + else
> + HWRITE4(sc, MPFGPIO_CLEAR_BITS, (1U << (pin % 32)));
> +}
> +
> +#if NGPIO > 0
> +int
> +mpfgpio_pin_read(void *cookie, int pin)
> +{
> + struct mpfgpio_softc *sc = cookie;
> + uint32_t cells[2];
> +
> + cells[0] = pin;
> + cells[1] = 0;
> +
> + return mpfgpio_get_pin(sc, cells) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
> +}
> +
> +void
> +mpfgpio_pin_write(void *cookie, int pin, int val)
> +{
> + struct mpfgpio_softc *sc = cookie;
> + uint32_t cells[2];
> +
> + cells[0] = pin;
> + cells[1] = 0;
> +
> + mpfgpio_set_pin(sc, cells, val);
> +}
> +
> +void
> +mpfgpio_pin_ctl(void *cookie, int pin, int flags)
> +{
> + struct mpfgpio_softc *sc = cookie;
> + uint32_t cells[2];
> + uint32_t config = 0;
> +
> + cells[0] = pin;
> + cells[1] = 0;
> +
> + if (flags & GPIO_PIN_OUTPUT)
> + config |= GPIO_CONFIG_OUTPUT;
> +
> + mpfgpio_config_pin(sc, cells, config);
> +}
> +
> +static const struct gpio_chipset_tag mpfgpio_gpio_tag = {
> + .gp_pin_read = mpfgpio_pin_read,
> + .gp_pin_write = mpfgpio_pin_write,
> + .gp_pin_ctl = mpfgpio_pin_ctl,
> +};
> +
> +void
> +mpfgpio_attach_gpio(struct device *parent)
> +{
> + struct gpiobus_attach_args gba;
> + struct mpfgpio_softc *sc = (struct mpfgpio_softc *)parent;
> + uint32_t cfgreg, pin;
> + int flags, state;
> +
> + for (pin = 0; pin < sc->sc_npins; pin++) {
> + /* Skip pins claimed by other devices. */
> + if (sc->sc_gpio_claimed[pin])
> + continue;
> +
> + cfgreg = HREAD4(sc, MPFGPIO_CONFIG(pin));
> + if (cfgreg & MPFGPIO_CONFIG_EN_OUT)
> + flags = GPIO_PIN_SET | GPIO_PIN_OUTPUT;
> + else if (cfgreg & MPFGPIO_CONFIG_EN_IN)
> + flags = GPIO_PIN_SET | GPIO_PIN_INPUT;
> + else
> + flags = GPIO_PIN_SET;
> +
> + state = (HREAD4(sc, MPFGPIO_GPIN) >> pin) & 1;
> +
> + sc->sc_gpio_pins[pin].pin_caps =
> + GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
> + sc->sc_gpio_pins[pin].pin_flags = flags;
> + sc->sc_gpio_pins[pin].pin_state = state;
> + sc->sc_gpio_pins[pin].pin_num = pin;
> + }
> +
> + sc->sc_gpio_tag = mpfgpio_gpio_tag;
> + sc->sc_gpio_tag.gp_cookie = sc;
> +
> + gba.gba_name = "gpio";
> + gba.gba_gc = &sc->sc_gpio_tag;
> + gba.gba_pins = sc->sc_gpio_pins;
> + gba.gba_npins = sc->sc_npins;
> +
> + config_found(&sc->sc_dev, &gba, gpiobus_print);
> +}
> +#endif
> Index: sys/arch/riscv64/riscv64/conf.c
> ===================================================================
> RCS file: src/sys/arch/riscv64/riscv64/conf.c,v
> retrieving revision 1.13
> diff -u -p -r1.13 conf.c
> --- sys/arch/riscv64/riscv64/conf.c 30 Nov 2021 02:13:57 -0000 1.13
> +++ sys/arch/riscv64/riscv64/conf.c 17 Feb 2022 15:45:41 -0000
> @@ -111,6 +111,7 @@ cdev_decl(pci);
> #include "pppx.h"
> #include "fuse.h"
> #include "openprom.h"
> +#include "gpio.h"
> #include "ipmi.h"
>
> struct cdevsw cdevsw[] =
> @@ -211,7 +212,7 @@ struct cdevsw cdevsw[] =
> cdev_notdef(), /* 85 */
> cdev_notdef(), /* 86 */
> cdev_drm_init(NDRM,drm), /* 87: drm */
> - cdev_notdef(), /* 88: GPIO interface */
> + cdev_gpio_init(NGPIO,gpio), /* 88: GPIO interface */
> cdev_vscsi_init(NVSCSI,vscsi), /* 89: vscsi */
> cdev_disk_init(1,diskmap), /* 90: disk mapper */
> cdev_pppx_init(NPPPX,pppx), /* 91: pppx */
> Index: usr.sbin/gpioctl/Makefile
> ===================================================================
> RCS file: src/usr.sbin/gpioctl/Makefile,v
> retrieving revision 1.9
> diff -u -p -r1.9 Makefile
> --- usr.sbin/gpioctl/Makefile 16 May 2020 16:37:50 -0000 1.9
> +++ usr.sbin/gpioctl/Makefile 17 Feb 2022 15:45:41 -0000
> @@ -2,7 +2,7 @@
>
> .if ${MACHINE} == "amd64" || ${MACHINE} == "arm64" || \
> ${MACHINE} == "armv7" || ${MACHINE} == "i386" || \
> - ${MACHINE} == "macppc"
> + ${MACHINE} == "macppc" || ${MACHINE} == "riscv64"
>
> PROG= gpioctl
> SRCS= gpioctl.c
> @@ -19,6 +19,6 @@ NOPROG= yes
> .endif
>
> MAN= gpioctl.8
> -MANSUBDIR=i386 macppc amd64 armv7 arm64
> +MANSUBDIR=amd64 arm64 armv7 i386 macppc riscv64
>
> .include <bsd.prog.mk>
>