Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115026669
D24353.id71201.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D24353.id71201.diff
View Options
Index: sys/arm64/qoriq/ls1046_gpio.c
===================================================================
--- /dev/null
+++ sys/arm64/qoriq/ls1046_gpio.c
@@ -0,0 +1,492 @@
+/*-
+ * 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];
+ uint32_t offset;
+ 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 int 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_reg_set(device_t, uint32_t, uint32_t);
+static void qoriq_gpio_reg_clear(device_t, uint32_t, uint32_t);
+static void qoriq_gpio_out_en(device_t, uint32_t, uint8_t);
+static void qoriq_gpio_value_set(device_t, uint32_t, uint8_t);
+static uint32_t qoriq_gpio_value_get(device_t, uint32_t);
+static void qoriq_gpio_open_drain_set(device_t, uint32_t, uint8_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 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_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 int
+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);
+
+ if(out->mem_res == NULL) {
+ return (1);
+ } else {
+ return (0);
+ }
+}
+
+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, sc->offset + 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);
+ uint32_t offset;
+
+ QORIQ_GPIO_ASSERT_LOCKED(sc);
+ offset = sc->offset + reg;
+ val = htobe32(val);
+
+ bus_write_4(sc->res.mem_res, offset, val);
+ bus_barrier(sc->res.mem_res, offset, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+}
+
+static void
+qoriq_gpio_reg_set(device_t dev, uint32_t reg, uint32_t pin)
+{
+ uint32_t reg_val;
+
+ reg_val = qoriq_gpio_reg_read(dev, reg);
+ reg_val |= GPIO(pin);
+ qoriq_gpio_reg_write(dev, reg, reg_val);
+}
+
+static void
+qoriq_gpio_reg_clear(device_t dev, uint32_t reg, uint32_t pin)
+{
+ uint32_t reg_val;
+
+ reg_val = qoriq_gpio_reg_read(dev, reg);
+ reg_val &= ~(GPIO(pin));
+ qoriq_gpio_reg_write(dev, reg, reg_val);
+}
+
+static void
+qoriq_gpio_out_en(device_t dev, uint32_t pin, uint8_t enable)
+{
+
+ if (pin >= PIN_COUNT)
+ return;
+
+ if (enable) {
+ qoriq_gpio_reg_set(dev, DIRECTION, pin);
+ } else {
+ qoriq_gpio_reg_clear(dev, DIRECTION, pin);
+ }
+}
+
+static void
+qoriq_gpio_value_set(device_t dev, uint32_t pin, uint8_t val)
+{
+
+ if (pin >= PIN_COUNT)
+ return;
+
+ if (val) {
+ qoriq_gpio_reg_set(dev, DATA, pin);
+ } else {
+ qoriq_gpio_reg_clear(dev, DATA, pin);
+ }
+}
+
+static uint32_t
+qoriq_gpio_value_get(device_t dev, uint32_t pin)
+{
+ uint32_t reg_val;
+
+ if (pin >= PIN_COUNT)
+ return (0);
+
+ reg_val = qoriq_gpio_reg_read(dev, DATA);
+ return ((reg_val & GPIO(pin)) == 0 ? 0 : 1);
+}
+
+static void
+qoriq_gpio_open_drain_set(device_t dev, uint32_t pin, uint8_t val)
+{
+
+ if (pin >= PIN_COUNT) {
+ return;
+ }
+
+ if (val) {
+ qoriq_gpio_reg_set(dev, OPEN_DRAIN, pin);
+ } else {
+ qoriq_gpio_reg_clear(dev, OPEN_DRAIN, pin);
+ }
+}
+
+static int
+qoriq_gpio_configure(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct gpio_softc *sc = device_get_softc(dev);
+
+ if (pin >= PIN_COUNT ||
+ ((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) {
+ qoriq_gpio_out_en(dev, pin, 0);
+ }
+
+ if (flags & GPIO_PIN_OUTPUT) {
+ qoriq_gpio_out_en(dev, pin, 1);
+
+ if (flags & GPIO_PIN_OPENDRAIN) {
+ qoriq_gpio_open_drain_set(dev, pin, 1);
+ } else {
+ qoriq_gpio_open_drain_set(dev, pin, 0);
+ }
+ }
+
+ sc->setup[pin].gp_flags = 0;
+ sc->setup[pin].gp_flags |= flags;
+
+ 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 (0);
+}
+
+static int
+qoriq_gpio_attach(device_t dev)
+{
+ struct gpio_softc *sc = device_get_softc(dev);
+ phandle_t node;
+ int err, i;
+
+ if(qoriq_make_gpio_res(dev, &sc->res) != 0) {
+ return (ENXIO);
+ }
+
+ node = ofw_bus_get_node(dev);
+ err = OF_getencprop(node, "offset", &sc->offset, sizeof(sc->offset));
+ if (err == -1) {
+ sc->offset = 0;
+ }
+
+ 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);
+ }
+
+ *name = '\0';
+ 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_value_get(dev, pin);
+ 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_value_set(dev, pin, value);
+ QORIQ_GPIO_UNLOCK(sc);
+ return (0);
+}
+
+static int
+qoriq_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ uint32_t value;
+
+ if (pin >= PIN_COUNT) {
+ return (EINVAL);
+ }
+
+ qoriq_gpio_pin_get(dev, pin, &value);
+ value = (~value) & 1;
+ qoriq_gpio_pin_set(dev, pin, value);
+
+ 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) {
+ *pin = gpios[0];
+ *flags = gpios[1];
+ }
+
+ return (err);
+}
Index: sys/conf/files.arm64
===================================================================
--- sys/conf/files.arm64
+++ sys/conf/files.arm64
@@ -193,6 +193,7 @@
arm64/intel/firmware.c optional soc_intel_stratix10
arm64/intel/stratix10-soc-fpga-mgr.c optional soc_intel_stratix10
arm64/intel/stratix10-svc.c optional soc_intel_stratix10
+arm64/qoriq/ls1046_gpio.c optional gpio fdt SOC_NXP_LS1046A
arm64/qoriq/clk/ls1046a_clkgen.c optional clk SOC_NXP_LS1046A
arm64/qoriq/clk/qoriq_clk_pll.c optional clk SOC_NXP_LS1046A
arm64/qoriq/clk/qoriq_clkgen.c optional clk SOC_NXP_LS1046A
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 20, 6:38 PM (7 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17648519
Default Alt Text
D24353.id71201.diff (12 KB)
Attached To
Mode
D24353: Add GPIO support for QorIQ boards.
Attached
Detach File
Event Timeline
Log In to Comment