Date: Mon, 5 Apr 2021 15:35:26 GMT From: Justin Hibbits <jhibbits@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 16e549ebe2ab - main - Merge the QorIQ GPIO drivers between arm and powerpc Message-ID: <202104051535.135FZQ9H070249@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by jhibbits: URL: https://cgit.FreeBSD.org/src/commit/?id=16e549ebe2ab5dbc43b78856ee9932f14867be20 commit 16e549ebe2ab5dbc43b78856ee9932f14867be20 Author: Justin Hibbits <jhibbits@FreeBSD.org> AuthorDate: 2021-04-05 15:35:15 +0000 Commit: Justin Hibbits <jhibbits@FreeBSD.org> CommitDate: 2021-04-05 15:35:15 +0000 Merge the QorIQ GPIO drivers between arm and powerpc Summary: They're nearly identical, so don't use two copies. Merge the newer driver into the older one, and move it to a common location. Add the Semihalf and associated copyrights in addition to mine, since it's a non-trivial amount of code merged. Reviewed By: mw Differential Revision: https://reviews.freebsd.org/D29520 --- sys/arm64/conf/GENERIC | 1 - sys/arm64/qoriq/ls1046_gpio.c | 498 ------------------------- sys/conf/files.arm64 | 2 +- sys/conf/files.powerpc | 2 +- sys/{powerpc/mpc85xx => dev/gpio}/qoriq_gpio.c | 153 +++++++- 5 files changed, 153 insertions(+), 503 deletions(-) diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC index bb790a1b6df9..cf137417fbc5 100644 --- a/sys/arm64/conf/GENERIC +++ b/sys/arm64/conf/GENERIC @@ -182,7 +182,6 @@ device gpio device gpioled device fdt_pinctrl device gpioregulator -device ls1046_gpio # LS1046A GPIO controller device mv_gpio # Marvell GPIO controller device mvebu_pinctrl # Marvell Pinmux Controller device pl061 # Arm PL061 GPIO controller diff --git a/sys/arm64/qoriq/ls1046_gpio.c b/sys/arm64/qoriq/ls1046_gpio.c deleted file mode 100644 index 4992d059a0ee..000000000000 --- a/sys/arm64/qoriq/ls1046_gpio.c +++ /dev/null @@ -1,498 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2020 Alstom Group. - * Copyright (c) 2020 Semihalf. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> - -#include <sys/bus.h> -#include <sys/endian.h> -#include <sys/gpio.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/mutex.h> - -#include <dev/gpio/gpiobusvar.h> -#include <dev/ofw/ofw_bus.h> -#include <machine/bus.h> - -#include "gpio_if.h" - -/* constants */ -enum { - DIRECTION = 0x0, - OPEN_DRAIN = 0x4, - DATA = 0x8, - INT_EV = 0xC, - INT_MASK = 0x10, - INT_CTRL = 0x14 -}; - -#define PIN_COUNT 32 -#define DEFAULT_CAPS \ - (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ - GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL) -#define GPIO(n) (1 << (31 - (n))) - -struct gpio_res { - int mem_rid; - struct resource *mem_res; -}; - -/* software context */ -struct gpio_softc { - device_t dev; - device_t busdev; - struct gpio_res res; - struct gpio_pin setup[PIN_COUNT]; - struct mtx mutex; -}; - -#define QORIQ_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->mutex) -#define QORIQ_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->mutex) -#define QORIQ_GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mutex, MA_OWNED) - -/* prototypes */ -/* helpers */ -static bool qoriq_make_gpio_res(device_t, struct gpio_res*); -static uint32_t qoriq_gpio_reg_read(device_t, uint32_t); -static void qoriq_gpio_reg_write(device_t, uint32_t, uint32_t); -static void qoriq_gpio_set(device_t, uint32_t, uint32_t, uint32_t); -static int qoriq_gpio_configure(device_t, uint32_t, uint32_t); - -/* GPIO API */ -static int qoriq_gpio_probe(device_t); -static int qoriq_gpio_attach(device_t); -static device_t qoriq_gpio_get_bus(device_t); -static int qoriq_gpio_pin_max(device_t, int*); -static int qoriq_gpio_pin_getname(device_t, uint32_t, char*); -static int qoriq_gpio_pin_getflags(device_t, uint32_t, uint32_t*); -static int qoriq_gpio_pin_setflags(device_t, uint32_t, uint32_t); -static int qoriq_gpio_pin_getcaps(device_t, uint32_t, uint32_t*); -static int qoriq_gpio_pin_get(device_t, uint32_t, uint32_t*); -static int qoriq_gpio_pin_set(device_t, uint32_t, uint32_t); -static int qoriq_gpio_pin_toggle(device_t, uint32_t); -static int qoriq_gpio_map_gpios(device_t, phandle_t, phandle_t, - int, pcell_t*, uint32_t*, uint32_t*); -static int qoriq_gpio_pin_access_32(device_t, uint32_t, uint32_t, uint32_t, - uint32_t*); -static int qoriq_gpio_pin_config_32(device_t, uint32_t, uint32_t, uint32_t*); - -static device_method_t qoriq_gpio_methods[] = { - DEVMETHOD(device_probe, qoriq_gpio_probe), - DEVMETHOD(device_attach, qoriq_gpio_attach), - - /* GPIO protocol */ - DEVMETHOD(gpio_get_bus, qoriq_gpio_get_bus), - DEVMETHOD(gpio_pin_max, qoriq_gpio_pin_max), - DEVMETHOD(gpio_pin_getname, qoriq_gpio_pin_getname), - DEVMETHOD(gpio_pin_getflags, qoriq_gpio_pin_getflags), - DEVMETHOD(gpio_pin_setflags, qoriq_gpio_pin_setflags), - DEVMETHOD(gpio_pin_getcaps, qoriq_gpio_pin_getcaps), - DEVMETHOD(gpio_pin_get, qoriq_gpio_pin_get), - DEVMETHOD(gpio_pin_set, qoriq_gpio_pin_set), - DEVMETHOD(gpio_pin_toggle, qoriq_gpio_pin_toggle), - DEVMETHOD(gpio_map_gpios, qoriq_gpio_map_gpios), - DEVMETHOD(gpio_pin_access_32, qoriq_gpio_pin_access_32), - DEVMETHOD(gpio_pin_config_32, qoriq_gpio_pin_config_32), - - DEVMETHOD_END -}; - -static driver_t gpio_driver = { - "gpio", - qoriq_gpio_methods, - sizeof(struct gpio_softc), -}; - -static devclass_t gpio_devclass; - -DRIVER_MODULE(gpio, simplebus, gpio_driver, gpio_devclass, 0, 0); -MODULE_VERSION(gpio, 1); - -/* - * helpers - */ -static bool -qoriq_make_gpio_res(device_t dev, struct gpio_res *out) -{ - - out->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &out->mem_rid, RF_ACTIVE | RF_SHAREABLE); - - return (out->mem_res == NULL); -} - -static uint32_t -qoriq_gpio_reg_read(device_t dev, uint32_t reg) -{ - struct gpio_softc *sc = device_get_softc(dev); - uint32_t result; - - QORIQ_GPIO_ASSERT_LOCKED(sc); - result = bus_read_4(sc->res.mem_res, reg); - - return be32toh(result); -} - -static void -qoriq_gpio_reg_write(device_t dev, uint32_t reg, uint32_t val) -{ - struct gpio_softc *sc = device_get_softc(dev); - - QORIQ_GPIO_ASSERT_LOCKED(sc); - val = htobe32(val); - - bus_write_4(sc->res.mem_res, reg, val); - bus_barrier(sc->res.mem_res, reg, 4, BUS_SPACE_BARRIER_READ | - BUS_SPACE_BARRIER_WRITE); -} - -static void -qoriq_gpio_set(device_t dev, uint32_t reg, uint32_t pin, uint32_t set) -{ - uint32_t val; - - set = set != 0; - val = (qoriq_gpio_reg_read(dev, reg) & ~(1U << pin)) | (set << pin); - qoriq_gpio_reg_write(dev, reg, val); -} - -static int -qoriq_gpio_configure(device_t dev, uint32_t pin, uint32_t flags) -{ - struct gpio_softc *sc = device_get_softc(dev); - uint32_t newflags; - - if (pin >= PIN_COUNT) - return (EINVAL); - - /* - * Pin cannot function as input and output at the same time. - * The same applies to open-drain and push-pull functionality. - */ - if (((flags & GPIO_PIN_INPUT) && (flags & GPIO_PIN_OUTPUT)) || - ((flags & GPIO_PIN_OPENDRAIN) && (flags & GPIO_PIN_PUSHPULL))) - return (EINVAL); - - QORIQ_GPIO_ASSERT_LOCKED(sc); - - if (flags & GPIO_PIN_INPUT) { - newflags = GPIO_PIN_INPUT; - qoriq_gpio_set(dev, DIRECTION, pin, 0); - } - - if (flags & GPIO_PIN_OUTPUT) { - newflags = GPIO_PIN_OUTPUT; - qoriq_gpio_set(dev, DIRECTION, pin, 1); - - if (flags & GPIO_PIN_OPENDRAIN) { - newflags |= GPIO_PIN_OPENDRAIN; - qoriq_gpio_set(dev, OPEN_DRAIN, pin, 1); - } else { - newflags |= GPIO_PIN_PUSHPULL; - qoriq_gpio_set(dev, OPEN_DRAIN, pin, 0); - } - } - - sc->setup[pin].gp_flags = newflags; - - return (0); -} - -/* GPIO API */ -static int -qoriq_gpio_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_is_compatible(dev, "fsl,qoriq-gpio")) - return (ENXIO); - - device_set_desc(dev, "Integrated GPIO Controller"); - - return (BUS_PROBE_DEFAULT); -} - -static int -qoriq_gpio_attach(device_t dev) -{ - struct gpio_softc *sc = device_get_softc(dev); - int i; - - if (qoriq_make_gpio_res(dev, &sc->res)) - return (ENXIO); - - for (i = 0; i < PIN_COUNT; i++) - sc->setup[i].gp_caps = DEFAULT_CAPS; - - sc->dev = dev; - - sc->busdev = gpiobus_attach_bus(dev); - if (sc->busdev == NULL) - return (ENXIO); - - return (0); -} - -static device_t -qoriq_gpio_get_bus(device_t dev) -{ - struct gpio_softc *softc = device_get_softc(dev); - - return (softc->busdev); -} - -static int -qoriq_gpio_pin_max(device_t dev, int *maxpin) -{ - - if (maxpin == NULL) - return (EINVAL); - - *maxpin = PIN_COUNT - 1; - - return (0); -} - -static int -qoriq_gpio_pin_getname(device_t dev, uint32_t pin, char *name) -{ - - if (name == NULL || pin >= PIN_COUNT) - return (EINVAL); - - snprintf(name, GPIOMAXNAME, "pin %d", pin); - - return (0); -} - -static int -qoriq_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *pflags) -{ - struct gpio_softc *sc = device_get_softc(dev); - - if (pflags == NULL || pin >= PIN_COUNT) - return (EINVAL); - - QORIQ_GPIO_LOCK(sc); - *pflags = sc->setup[pin].gp_flags; - QORIQ_GPIO_UNLOCK(sc); - - return (0); -} - -static int -qoriq_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) -{ - struct gpio_softc *sc = device_get_softc(dev); - int ret; - - if (pin >= PIN_COUNT) - return (EINVAL); - - /* Check for unwanted flags. */ - QORIQ_GPIO_LOCK(sc); - - if ((flags & sc->setup[pin].gp_caps) != flags) { - QORIQ_GPIO_UNLOCK(sc); - return (EINVAL); - } - - ret = qoriq_gpio_configure(dev, pin, flags); - - QORIQ_GPIO_UNLOCK(sc); - - return (ret); -} - -static int -qoriq_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) -{ - struct gpio_softc *sc = device_get_softc(dev); - - if (caps == NULL || pin >= PIN_COUNT) - return (EINVAL); - - QORIQ_GPIO_LOCK(sc); - *caps = sc->setup[pin].gp_caps; - QORIQ_GPIO_UNLOCK(sc); - - return (0); -} - -static int -qoriq_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *value) -{ - struct gpio_softc *sc = device_get_softc(dev); - - if (value == NULL || pin >= PIN_COUNT) - return (EINVAL); - - QORIQ_GPIO_LOCK(sc); - *value = (qoriq_gpio_reg_read(dev, DATA) & GPIO(pin)) != 0; - QORIQ_GPIO_UNLOCK(sc); - - return (0); -} - -static int -qoriq_gpio_pin_set(device_t dev, uint32_t pin, uint32_t value) -{ - struct gpio_softc *sc = device_get_softc(dev); - - if (pin >= PIN_COUNT) - return (EINVAL); - - QORIQ_GPIO_LOCK(sc); - qoriq_gpio_set(dev, DATA, pin, value); - QORIQ_GPIO_UNLOCK(sc); - - return (0); -} - -static int -qoriq_gpio_pin_toggle(device_t dev, uint32_t pin) -{ - struct gpio_softc *sc; - uint32_t value; - - if (pin >= PIN_COUNT) - return (EINVAL); - - sc = device_get_softc(dev); - - QORIQ_GPIO_LOCK(sc); - value = qoriq_gpio_reg_read(dev, DATA) ^ (1 << pin); - qoriq_gpio_reg_write(dev, DATA, value); - QORIQ_GPIO_UNLOCK(sc); - - return (0); -} - -static int -qoriq_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, - pcell_t *gpios, uint32_t *pin, uint32_t *flags) -{ - struct gpio_softc *sc = device_get_softc(bus); - int err; - - if (gpios[0] >= PIN_COUNT) - return (EINVAL); - - QORIQ_GPIO_LOCK(sc); - err = qoriq_gpio_configure(bus, gpios[0], gpios[1]); - QORIQ_GPIO_UNLOCK(sc); - - if (err != 0) - return (err); - - *pin = gpios[0]; - *flags = gpios[1]; - - return (0); -} - -static int -qoriq_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins, - uint32_t change_pins, uint32_t *orig_pins) -{ - struct gpio_softc *sc; - uint32_t hwstate; - - sc = device_get_softc(dev); - - if (first_pin != 0) - return (EINVAL); - - QORIQ_GPIO_LOCK(sc); - hwstate = qoriq_gpio_reg_read(dev, DATA); - qoriq_gpio_reg_write(dev, DATA, (hwstate & ~clear_pins) ^ change_pins); - QORIQ_GPIO_UNLOCK(sc); - - if (orig_pins != NULL) - *orig_pins = hwstate; - - return (0); -} - -static int -qoriq_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins, - uint32_t *pin_flags) -{ - uint32_t dir, odr, mask, reg; - struct gpio_softc *sc; - uint32_t newflags[32]; - int i; - - if (first_pin != 0 || num_pins > PIN_COUNT) - return (EINVAL); - - sc = device_get_softc(dev); - - dir = odr = mask = 0; - - for (i = 0; i < num_pins; i++) { - newflags[i] = 0; - mask |= (1 << i); - - if (pin_flags[i] & GPIO_PIN_INPUT) { - newflags[i] = GPIO_PIN_INPUT; - dir &= ~(1 << i); - } else { - newflags[i] = GPIO_PIN_OUTPUT; - dir |= (1 << i); - - if (pin_flags[i] & GPIO_PIN_OPENDRAIN) { - newflags[i] |= GPIO_PIN_OPENDRAIN; - odr |= (1 << i); - } else { - newflags[i] |= GPIO_PIN_PUSHPULL; - odr &= ~(1 << i); - } - } - } - - QORIQ_GPIO_LOCK(sc); - - reg = (qoriq_gpio_reg_read(dev, DIRECTION) & ~mask) | dir; - qoriq_gpio_reg_write(dev, DIRECTION, reg); - - reg = (qoriq_gpio_reg_read(dev, OPEN_DRAIN) & ~mask) | odr; - qoriq_gpio_reg_write(dev, OPEN_DRAIN, reg); - - for (i = 0; i < num_pins; i++) - sc->setup[i].gp_flags = newflags[i]; - - QORIQ_GPIO_UNLOCK(sc); - - return (0); -} diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index 4bf3350cac29..d7809bfb3d68 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -169,6 +169,7 @@ dev/dwc/if_dwc_if.m optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_ dev/gpio/pl061.c optional pl061 gpio dev/gpio/pl061_acpi.c optional pl061 gpio acpi dev/gpio/pl061_fdt.c optional pl061 gpio fdt +dev/gpio/qoriq_gpio.c optional SOC_NXP_LS gpio fdt dev/hwpmc/hwpmc_arm64.c optional hwpmc dev/hwpmc/hwpmc_arm64_md.c optional hwpmc @@ -494,7 +495,6 @@ tegra210_xusb.fw optional tegra210_xusb_fw \ # NXP arm/freescale/vybrid/vf_i2c.c optional vf_i2c iicbus SOC_NXP_LS -arm64/qoriq/ls1046_gpio.c optional ls1046_gpio gpio fdt SOC_NXP_LS arm64/qoriq/qoriq_dw_pci.c optional pci fdt SOC_NXP_LS arm64/qoriq/qoriq_therm.c optional pci fdt SOC_NXP_LS arm64/qoriq/qoriq_therm_if.m optional pci fdt SOC_NXP_LS diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index 347abee153d2..19c97c34fa86 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -24,6 +24,7 @@ dev/adb/adb_if.m optional adb dev/adb/adb_buttons.c optional adb dev/agp/agp_apple.c optional agp powermac dev/fb/fb.c optional sc +dev/gpio/qoriq_gpio.c optional mpc85xx gpio dev/hwpmc/hwpmc_e500.c optional hwpmc dev/hwpmc/hwpmc_mpc7xxx.c optional hwpmc dev/hwpmc/hwpmc_power8.c optional hwpmc @@ -186,7 +187,6 @@ powerpc/mpc85xx/mpc85xx_gpio.c optional mpc85xx gpio powerpc/mpc85xx/platform_mpc85xx.c optional mpc85xx powerpc/mpc85xx/pci_mpc85xx.c optional pci mpc85xx powerpc/mpc85xx/pci_mpc85xx_pcib.c optional pci mpc85xx -powerpc/mpc85xx/qoriq_gpio.c optional mpc85xx gpio powerpc/ofw/ofw_machdep.c standard powerpc/ofw/ofw_pcibus.c optional pci powerpc/ofw/ofw_pcib_pci.c optional pci diff --git a/sys/powerpc/mpc85xx/qoriq_gpio.c b/sys/dev/gpio/qoriq_gpio.c similarity index 68% rename from sys/powerpc/mpc85xx/qoriq_gpio.c rename to sys/dev/gpio/qoriq_gpio.c index 7abae276e8d1..82bd6cd9a72b 100644 --- a/sys/powerpc/mpc85xx/qoriq_gpio.c +++ b/sys/dev/gpio/qoriq_gpio.c @@ -1,4 +1,6 @@ /*- + * Copyright (c) 2020 Alstom Group. + * Copyright (c) 2020 Semihalf. * Copyright (c) 2015 Justin Hibbits * All rights reserved. * @@ -52,6 +54,8 @@ __FBSDID("$FreeBSD$"); #define MAXPIN (31) #define VALID_PIN(u) ((u) >= 0 && (u) <= MAXPIN) +#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ + GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL) #define GPIO_LOCK(sc) mtx_lock(&(sc)->sc_mtx) #define GPIO_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) @@ -66,12 +70,14 @@ __FBSDID("$FreeBSD$"); #define GPIO_GPIER 0xc #define GPIO_GPIMR 0x10 #define GPIO_GPICR 0x14 +#define GPIO_GPIBE 0x18 struct qoriq_gpio_softc { device_t dev; device_t busdev; struct mtx sc_mtx; struct resource *sc_mem; /* Memory resource */ + struct gpio_pin sc_pins[MAXPIN + 1]; }; static device_t @@ -96,11 +102,16 @@ qoriq_gpio_pin_max(device_t dev, int *maxpin) static int qoriq_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { + struct qoriq_gpio_softc *sc; + + sc = device_get_softc(dev); if (!VALID_PIN(pin)) return (EINVAL); - *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN); + GPIO_LOCK(sc); + *caps = sc->sc_pins[pin].gp_caps; + GPIO_UNLOCK(sc); return (0); } @@ -135,6 +146,11 @@ qoriq_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) return (EINVAL); GPIO_LOCK(sc); + if ((flags & sc->sc_pins[pin].gp_caps) != flags) { + GPIO_UNLOCK(sc); + return (EINVAL); + } + if (flags & GPIO_PIN_INPUT) { reg = bus_read_4(sc->sc_mem, GPIO_GPDIR); reg &= ~(1 << (31 - pin)); @@ -151,10 +167,28 @@ qoriq_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) reg &= ~(1 << (31 - pin)); bus_write_4(sc->sc_mem, GPIO_GPODR, reg); } + sc->sc_pins[pin].gp_flags = flags; GPIO_UNLOCK(sc); return (0); } +static int +qoriq_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *pflags) +{ + struct qoriq_gpio_softc *sc; + + if (!VALID_PIN(pin)) + return (EINVAL); + + sc = device_get_softc(dev); + + GPIO_LOCK(sc); + *pflags = sc->sc_pins[pin].gp_flags; + GPIO_UNLOCK(sc); + + return (0); +} + /* Set a specific output pin's value. */ static int qoriq_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) @@ -233,13 +267,113 @@ qoriq_gpio_probe(device_t dev) return (0); } +static int +qoriq_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins, + uint32_t change_pins, uint32_t *orig_pins) +{ + struct qoriq_gpio_softc *sc; + uint32_t hwstate; + + sc = device_get_softc(dev); + + if (first_pin != 0) + return (EINVAL); + + GPIO_LOCK(sc); + hwstate = bus_read_4(sc->sc_mem, GPIO_GPDAT); + bus_write_4(sc->sc_mem, GPIO_GPDAT, + (hwstate & ~clear_pins) ^ change_pins); + GPIO_UNLOCK(sc); + + if (orig_pins != NULL) + *orig_pins = hwstate; + + return (0); +} + +static int +qoriq_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins, + uint32_t *pin_flags) +{ + uint32_t dir, odr, mask, reg; + struct qoriq_gpio_softc *sc; + uint32_t newflags[32]; + int i; + + if (first_pin != 0 || !VALID_PIN(num_pins)) + return (EINVAL); + + sc = device_get_softc(dev); + + dir = odr = mask = 0; + + for (i = 0; i < num_pins; i++) { + newflags[i] = 0; + mask |= (1 << i); + + if (pin_flags[i] & GPIO_PIN_INPUT) { + newflags[i] = GPIO_PIN_INPUT; + dir &= ~(1 << i); + } else { + newflags[i] = GPIO_PIN_OUTPUT; + dir |= (1 << i); + + if (pin_flags[i] & GPIO_PIN_OPENDRAIN) { + newflags[i] |= GPIO_PIN_OPENDRAIN; + odr |= (1 << i); + } else { + newflags[i] |= GPIO_PIN_PUSHPULL; + odr &= ~(1 << i); + } + } + } + + GPIO_LOCK(sc); + + reg = (bus_read_4(sc->sc_mem, GPIO_GPDIR) & ~mask) | dir; + bus_write_4(sc->sc_mem, GPIO_GPDIR, reg); + + reg = (bus_read_4(sc->sc_mem, GPIO_GPODR) & ~mask) | odr; + bus_write_4(sc->sc_mem, GPIO_GPODR, reg); + + for (i = 0; i < num_pins; i++) + sc->sc_pins[i].gp_flags = newflags[i]; + + GPIO_UNLOCK(sc); + + return (0); +} + +static int +qoriq_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, + pcell_t *gpios, uint32_t *pin, uint32_t *flags) +{ + struct qoriq_gpio_softc *sc; + int err; + + if (!VALID_PIN(gpios[0])) + return (EINVAL); + + sc = device_get_softc(bus); + GPIO_LOCK(sc); + err = qoriq_gpio_pin_setflags(bus, gpios[0], gpios[1]); + GPIO_UNLOCK(sc); + + if (err == 0) { + *pin = gpios[0]; + *flags = gpios[1]; + } + + return (err); +} + static int qoriq_gpio_detach(device_t dev); static int qoriq_gpio_attach(device_t dev) { struct qoriq_gpio_softc *sc = device_get_softc(dev); - int rid; + int i, rid; sc->dev = dev; @@ -255,11 +389,21 @@ qoriq_gpio_attach(device_t dev) return (ENOMEM); } + for (i = 0; i <= MAXPIN; i++) + sc->sc_pins[i].gp_caps = DEFAULT_CAPS; + sc->busdev = gpiobus_attach_bus(dev); if (sc->busdev == NULL) { qoriq_gpio_detach(dev); return (ENOMEM); } + /* + * Enable the GPIO Input Buffer for all GPIOs. + * This is safe on devices without a GPIBE register, because those + * devices ignore writes and read 0's in undefined portions of the map. + */ + if (ofw_bus_is_compatible(dev, "fsl,qoriq-gpio")) + bus_write_4(sc->sc_mem, GPIO_GPIBE, 0xffffffff); OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); @@ -297,9 +441,14 @@ static device_method_t qoriq_gpio_methods[] = { DEVMETHOD(gpio_pin_getcaps, qoriq_gpio_pin_getcaps), DEVMETHOD(gpio_pin_get, qoriq_gpio_pin_get), DEVMETHOD(gpio_pin_set, qoriq_gpio_pin_set), + DEVMETHOD(gpio_pin_getflags, qoriq_gpio_pin_getflags), DEVMETHOD(gpio_pin_setflags, qoriq_gpio_pin_setflags), DEVMETHOD(gpio_pin_toggle, qoriq_gpio_pin_toggle), + DEVMETHOD(gpio_map_gpios, qoriq_gpio_map_gpios), + DEVMETHOD(gpio_pin_access_32, qoriq_gpio_pin_access_32), + DEVMETHOD(gpio_pin_config_32, qoriq_gpio_pin_config_32), + DEVMETHOD_END };
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202104051535.135FZQ9H070249>