Index: head/sys/arm/mv/gpio.c =================================================================== --- head/sys/arm/mv/gpio.c (revision 332023) +++ head/sys/arm/mv/gpio.c (revision 332024) @@ -1,1106 +1,1127 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Benno Rice. * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. * Copyright (c) 2017 Semihalf. * All rights reserved. * * Adapted and extended for Marvell SoCs by 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 ``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 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. * * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_gpio.c, rev 1 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define GPIO_MAX_INTR_COUNT 8 #define GPIO_PINS_PER_REG 32 #define DEBOUNCE_CHECK_MS 1 #define DEBOUNCE_LO_HI_MS 2 #define DEBOUNCE_HI_LO_MS 2 #define DEBOUNCE_CHECK_TICKS ((hz / 1000) * DEBOUNCE_CHECK_MS) struct mv_gpio_softc { struct resource * mem_res; int mem_rid; struct resource * irq_res[GPIO_MAX_INTR_COUNT]; int irq_rid[GPIO_MAX_INTR_COUNT]; + struct intr_event * gpio_events[MV_GPIO_MAX_NPINS]; void *ih_cookie[GPIO_MAX_INTR_COUNT]; bus_space_tag_t bst; bus_space_handle_t bsh; struct mtx mutex; uint8_t pin_num; /* number of GPIO pins */ uint8_t irq_num; /* number of real IRQs occupied by GPIO controller */ - uint8_t use_high; + struct gpio_pin gpio_setup[MV_GPIO_MAX_NPINS]; /* Used for debouncing. */ uint32_t debounced_state_lo; uint32_t debounced_state_hi; struct callout **debounce_callouts; int *debounce_counters; }; -static struct mv_gpio_softc *mv_gpio_softc = NULL; -static uint32_t gpio_setup[MV_GPIO_MAX_NPINS]; +struct mv_gpio_pindev { + device_t dev; + int pin; +}; static int mv_gpio_probe(device_t); static int mv_gpio_attach(device_t); -static int mv_gpio_intr(void *); -static int mv_gpio_init(void); +static int mv_gpio_intr(device_t, void *); +static int mv_gpio_init(device_t); -static void mv_gpio_double_edge_init(int pin); +static void mv_gpio_double_edge_init(device_t, int); -static int mv_gpio_debounce_setup(int pin); -static int mv_gpio_debounce_init(int pin); -static void mv_gpio_debounce_start(int pin); -static int mv_gpio_debounce_prepare(int pin); -static void mv_gpio_debounce(void *arg); -static void mv_gpio_debounced_state_set(int pin, uint8_t new_state); -static uint32_t mv_gpio_debounced_state_get(int pin); +static int mv_gpio_debounce_setup(device_t, int); +static int mv_gpio_debounce_prepare(device_t, int); +static int mv_gpio_debounce_init(device_t, int); +static void mv_gpio_debounce_start(device_t, int); +static void mv_gpio_debounce(void *); +static void mv_gpio_debounced_state_set(device_t, int, uint8_t); +static uint32_t mv_gpio_debounced_state_get(device_t, int); -static void mv_gpio_exec_intr_handlers(uint32_t status, int high); -static void mv_gpio_intr_handler(int pin); -static uint32_t mv_gpio_reg_read(uint32_t reg); -static void mv_gpio_reg_write(uint32_t reg, uint32_t val); -static void mv_gpio_reg_set(uint32_t reg, uint32_t val); -static void mv_gpio_reg_clear(uint32_t reg, uint32_t val); +static void mv_gpio_exec_intr_handlers(device_t, uint32_t, int); +static void mv_gpio_intr_handler(device_t, int); +static uint32_t mv_gpio_reg_read(device_t, uint32_t); +static void mv_gpio_reg_write(device_t, uint32_t, uint32_t); +static void mv_gpio_reg_set(device_t, uint32_t, uint32_t); +static void mv_gpio_reg_clear(device_t, uint32_t, uint32_t); -static void mv_gpio_blink(uint32_t pin, uint8_t enable); -static void mv_gpio_polarity(uint32_t pin, uint8_t enable, uint8_t toggle); -static void mv_gpio_level(uint32_t pin, uint8_t enable); -static void mv_gpio_edge(uint32_t pin, uint8_t enable); -static void mv_gpio_out_en(uint32_t pin, uint8_t enable); -static void mv_gpio_int_ack(uint32_t pin); -static void mv_gpio_value_set(uint32_t pin, uint8_t val); -static uint32_t mv_gpio_value_get(uint32_t pin, uint8_t exclude_polar); +static void mv_gpio_blink(device_t, uint32_t, uint8_t); +static void mv_gpio_polarity(device_t, uint32_t, uint8_t, uint8_t); +static void mv_gpio_level(device_t, uint32_t, uint8_t); +static void mv_gpio_edge(device_t, uint32_t, uint8_t); +static void mv_gpio_out_en(device_t, uint32_t, uint8_t); +static void mv_gpio_int_ack(struct mv_gpio_pindev *); +static void mv_gpio_value_set(device_t, uint32_t, uint8_t); +static uint32_t mv_gpio_value_get(device_t, uint32_t, uint8_t); -static void mv_gpio_intr_mask(int pin); -static void mv_gpio_intr_unmask(int pin); -int mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt, - void (*hand)(void *), void *arg, int pin, int flags, void **cookiep); +static void mv_gpio_intr_mask(struct mv_gpio_pindev *); +static void mv_gpio_intr_unmask(struct mv_gpio_pindev *); -int mv_gpio_configure(uint32_t pin, uint32_t flags, uint32_t mask); -void mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable); -uint8_t mv_gpio_in(uint32_t pin); +void mv_gpio_finish_intrhandler(struct mv_gpio_pindev *); +int mv_gpio_setup_intrhandler(device_t, const char *, + driver_filter_t *, void (*)(void *), void *, + int, int, void **); +int mv_gpio_configure(device_t, uint32_t, uint32_t, uint32_t); +void mv_gpio_out(device_t, uint32_t, uint8_t, uint8_t); +uint8_t mv_gpio_in(device_t, uint32_t); -#define MV_GPIO_LOCK() mtx_lock_spin(&mv_gpio_softc->mutex) -#define MV_GPIO_UNLOCK() mtx_unlock_spin(&mv_gpio_softc->mutex) -#define MV_GPIO_ASSERT_LOCKED() mtx_assert(&mv_gpio_softc->mutex, MA_OWNED) +#define MV_GPIO_LOCK() mtx_lock_spin(&sc->mutex) +#define MV_GPIO_UNLOCK() mtx_unlock_spin(&sc->mutex) +#define MV_GPIO_ASSERT_LOCKED() mtx_assert(&sc->mutex, MA_OWNED) static device_method_t mv_gpio_methods[] = { DEVMETHOD(device_probe, mv_gpio_probe), DEVMETHOD(device_attach, mv_gpio_attach), { 0, 0 } }; static driver_t mv_gpio_driver = { "gpio", mv_gpio_methods, sizeof(struct mv_gpio_softc), }; static devclass_t mv_gpio_devclass; DRIVER_MODULE(gpio, simplebus, mv_gpio_driver, mv_gpio_devclass, 0, 0); -typedef int (*gpios_phandler_t)(phandle_t, pcell_t *, int); +typedef int (*gpios_phandler_t)(device_t, phandle_t, pcell_t *, int); struct gpio_ctrl_entry { const char *compat; gpios_phandler_t handler; }; -static int mv_handle_gpios_prop(phandle_t ctrl, pcell_t *gpios, int len); +static int mv_handle_gpios_prop(device_t, phandle_t, pcell_t *, int); int gpio_get_config_from_dt(void); struct gpio_ctrl_entry gpio_controllers[] = { { "mrvl,gpio", &mv_handle_gpios_prop }, { NULL, NULL } }; static int mv_gpio_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "mrvl,gpio")) return (ENXIO); device_set_desc(dev, "Marvell Integrated GPIO Controller"); return (0); } static int mv_gpio_attach(device_t dev) { int error, i, size; struct mv_gpio_softc *sc; uint32_t dev_id, rev_id; pcell_t pincnt = 0; pcell_t irq_cells = 0; phandle_t iparent; sc = (struct mv_gpio_softc *)device_get_softc(dev); if (sc == NULL) return (ENXIO); - if (mv_gpio_softc != NULL) - return (ENXIO); - mv_gpio_softc = sc; - /* Get chip id and revision */ soc_id(&dev_id, &rev_id); if (dev_id == MV_DEV_88F5182 || dev_id == MV_DEV_88F5281 || dev_id == MV_DEV_MV78100 || dev_id == MV_DEV_MV78100_Z0 ) { sc->pin_num = 32; sc->irq_num = 4; - sc->use_high = 0; } else if (dev_id == MV_DEV_88F6281 || dev_id == MV_DEV_88F6282) { sc->pin_num = 50; sc->irq_num = 7; - sc->use_high = 1; } else { if (OF_getencprop(ofw_bus_get_node(dev), "pin-count", &pincnt, sizeof(pcell_t)) >= 0 || OF_getencprop(ofw_bus_get_node(dev), "ngpios", &pincnt, sizeof(pcell_t)) >= 0) { sc->pin_num = pincnt; device_printf(dev, "%d pins available\n", sc->pin_num); } else { device_printf(dev, "ERROR: no pin-count entry found!\n"); return (ENXIO); } } /* Find root interrupt controller */ iparent = ofw_bus_find_iparent(ofw_bus_get_node(dev)); if (iparent == 0) { device_printf(dev, "No interrupt-parrent found. " "Error in DTB\n"); return (ENXIO); } else { /* While at parent - store interrupt cells prop */ if (OF_searchencprop(OF_node_from_xref(iparent), "#interrupt-cells", &irq_cells, sizeof(irq_cells)) == -1) { device_printf(dev, "DTB: Missing #interrupt-cells " "property in interrupt parent node\n"); return (ENXIO); } } size = OF_getproplen(ofw_bus_get_node(dev), "interrupts"); if (size != -1) { size = size / sizeof(pcell_t); size = size / irq_cells; sc->irq_num = size; device_printf(dev, "%d IRQs available\n", sc->irq_num); } else { device_printf(dev, "ERROR: no interrupts entry found!\n"); return (ENXIO); } sc->debounce_callouts = (struct callout **)malloc(sc->pin_num * sizeof(struct callout *), M_DEVBUF, M_WAITOK | M_ZERO); if (sc->debounce_callouts == NULL) return (ENOMEM); sc->debounce_counters = (int *)malloc(sc->pin_num * sizeof(int), M_DEVBUF, M_WAITOK); if (sc->debounce_counters == NULL) return (ENOMEM); mtx_init(&sc->mutex, device_get_nameunit(dev), NULL, MTX_SPIN); sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (!sc->mem_res) { mtx_destroy(&sc->mutex); device_printf(dev, "could not allocate memory window\n"); return (ENXIO); } sc->bst = rman_get_bustag(sc->mem_res); sc->bsh = rman_get_bushandle(sc->mem_res); for (i = 0; i < sc->irq_num; i++) { sc->irq_rid[i] = i; sc->irq_res[i] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid[i], RF_ACTIVE); if (!sc->irq_res[i]) { mtx_destroy(&sc->mutex); device_printf(dev, "could not allocate gpio%d interrupt\n", i+1); return (ENXIO); } } /* Disable all interrupts */ bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_EDGE_MASK, 0); bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_LEV_MASK, 0); - if (sc->use_high) { - bus_space_write_4(sc->bst, sc->bsh, - GPIO_HI_INT_EDGE_MASK, 0); - bus_space_write_4(sc->bst, sc->bsh, - GPIO_HI_INT_LEV_MASK, 0); - bus_space_write_4(sc->bst, sc->bsh, - GPIO_HI_INT_CAUSE, 0); - } - for (i = 0; i < sc->irq_num; i++) { if (bus_setup_intr(dev, sc->irq_res[i], INTR_TYPE_MISC, (driver_filter_t *)mv_gpio_intr, NULL, sc, &sc->ih_cookie[i]) != 0) { mtx_destroy(&sc->mutex); bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid[i], sc->irq_res[i]); device_printf(dev, "could not set up intr %d\n", i); return (ENXIO); } } - error = mv_gpio_init(); + error = mv_gpio_init(dev); if (error) { device_printf(dev, "WARNING: failed to initialize GPIO pins, " "error = %d\n", error); } /* Clear interrupt status. */ bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_CAUSE, 0); + device_add_child(dev, "gpioc", device_get_unit(dev)); + device_add_child(dev, "gpiobus", device_get_unit(dev)); + return (0); } static int -mv_gpio_intr(void *arg) +mv_gpio_intr(device_t dev, void *arg) { uint32_t int_cause, gpio_val; - uint32_t int_cause_hi, gpio_val_hi; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_LOCK(); /* * According to documentation, edge sensitive interrupts are asserted * when unmasked GPIO_INT_CAUSE register bits are set. */ - int_cause = mv_gpio_reg_read(GPIO_INT_CAUSE); - int_cause &= mv_gpio_reg_read(GPIO_INT_EDGE_MASK); + int_cause = mv_gpio_reg_read(dev, GPIO_INT_CAUSE); + int_cause &= mv_gpio_reg_read(dev, GPIO_INT_EDGE_MASK); /* * Level sensitive interrupts are asserted when unmasked GPIO_DATA_IN * register bits are set. */ - gpio_val = mv_gpio_reg_read(GPIO_DATA_IN); - gpio_val &= mv_gpio_reg_read(GPIO_INT_LEV_MASK); + gpio_val = mv_gpio_reg_read(dev, GPIO_DATA_IN); + gpio_val &= mv_gpio_reg_read(dev, GPIO_INT_LEV_MASK); - int_cause_hi = 0; - gpio_val_hi = 0; - if (mv_gpio_softc->use_high) { - int_cause_hi = mv_gpio_reg_read(GPIO_HI_INT_CAUSE); - int_cause_hi &= mv_gpio_reg_read(GPIO_HI_INT_EDGE_MASK); + mv_gpio_exec_intr_handlers(dev, int_cause | gpio_val, 0); - gpio_val_hi = mv_gpio_reg_read(GPIO_HI_DATA_IN); - gpio_val_hi &= mv_gpio_reg_read(GPIO_HI_INT_LEV_MASK); - } - - mv_gpio_exec_intr_handlers(int_cause | gpio_val, 0); - - if (mv_gpio_softc->use_high) - mv_gpio_exec_intr_handlers(int_cause_hi | gpio_val_hi, 1); - MV_GPIO_UNLOCK(); return (FILTER_HANDLED); } /* * GPIO interrupt handling */ -static struct intr_event *gpio_events[MV_GPIO_MAX_NPINS]; +void +mv_gpio_finish_intrhandler(struct mv_gpio_pindev *s) +{ + /* When we acheive full interrupt support + * This function will be opposite to + * mv_gpio_setup_intrhandler + */ + /* Now it exists only to remind that + * there should be place to free mv_gpio_pindev + * allocated by mv_gpio_setup_intrhandler + */ + free(s, M_DEVBUF); +} + int -mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt, +mv_gpio_setup_intrhandler(device_t dev, const char *name, driver_filter_t *filt, void (*hand)(void *), void *arg, int pin, int flags, void **cookiep) { struct intr_event *event; int error; + struct mv_gpio_pindev *s; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); + s = malloc(sizeof(struct mv_gpio_pindev), M_DEVBUF, M_NOWAIT | M_ZERO); - if (pin < 0 || pin >= mv_gpio_softc->pin_num) + if (pin < 0 || pin >= sc->pin_num) return (ENXIO); - event = gpio_events[pin]; + event = sc->gpio_events[pin]; if (event == NULL) { MV_GPIO_LOCK(); - if (gpio_setup[pin] & MV_GPIO_IN_DEBOUNCE) { - error = mv_gpio_debounce_init(pin); + if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_DEBOUNCE) { + error = mv_gpio_debounce_init(dev, pin); if (error != 0) { MV_GPIO_UNLOCK(); return (error); } - } else if (gpio_setup[pin] & MV_GPIO_IN_IRQ_DOUBLE_EDGE) - mv_gpio_double_edge_init(pin); + } else if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_IRQ_DOUBLE_EDGE) + mv_gpio_double_edge_init(dev, pin); MV_GPIO_UNLOCK(); - - error = intr_event_create(&event, (void *)pin, 0, pin, + error = intr_event_create(&event, (void *)s, 0, pin, (void (*)(void *))mv_gpio_intr_mask, (void (*)(void *))mv_gpio_intr_unmask, (void (*)(void *))mv_gpio_int_ack, NULL, "gpio%d:", pin); if (error != 0) return (error); - gpio_events[pin] = event; + sc->gpio_events[pin] = event; } intr_event_add_handler(event, name, filt, hand, arg, intr_priority(flags), flags, cookiep); return (0); } -void -mv_gpio_intr_mask(int pin) +static void +mv_gpio_intr_mask(struct mv_gpio_pindev *s) { + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(s->dev); - if (pin >= mv_gpio_softc->pin_num) + if (s->pin >= sc->pin_num) return; MV_GPIO_LOCK(); - if (gpio_setup[pin] & (MV_GPIO_IN_IRQ_EDGE | MV_GPIO_IN_IRQ_DOUBLE_EDGE)) - mv_gpio_edge(pin, 0); + if (sc->gpio_setup[s->pin].gp_flags & (MV_GPIO_IN_IRQ_EDGE | + MV_GPIO_IN_IRQ_DOUBLE_EDGE)) + mv_gpio_edge(s->dev, s->pin, 0); else - mv_gpio_level(pin, 0); + mv_gpio_level(s->dev, s->pin, 0); /* * The interrupt has to be acknowledged before scheduling an interrupt * thread. This way we allow for interrupt source to trigger again * (which can happen with shared IRQs e.g. PCI) while processing the * current event. */ - mv_gpio_int_ack(pin); + mv_gpio_int_ack(s); MV_GPIO_UNLOCK(); + + return; } -void -mv_gpio_intr_unmask(int pin) +static void +mv_gpio_intr_unmask(struct mv_gpio_pindev *s) { + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(s->dev); - if (pin >= mv_gpio_softc->pin_num) + if (s->pin >= sc->pin_num) return; MV_GPIO_LOCK(); - if (gpio_setup[pin] & (MV_GPIO_IN_IRQ_EDGE | MV_GPIO_IN_IRQ_DOUBLE_EDGE)) - mv_gpio_edge(pin, 1); + if (sc->gpio_setup[s->pin].gp_flags & (MV_GPIO_IN_IRQ_EDGE | + MV_GPIO_IN_IRQ_DOUBLE_EDGE)) + mv_gpio_edge(s->dev, s->pin, 1); else - mv_gpio_level(pin, 1); + mv_gpio_level(s->dev, s->pin, 1); MV_GPIO_UNLOCK(); + + return; } static void -mv_gpio_exec_intr_handlers(uint32_t status, int high) +mv_gpio_exec_intr_handlers(device_t dev, uint32_t status, int high) { int i, pin; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_ASSERT_LOCKED(); i = 0; while (status != 0) { if (status & 1) { pin = (high ? (i + GPIO_PINS_PER_REG) : i); - if (gpio_setup[pin] & MV_GPIO_IN_DEBOUNCE) - mv_gpio_debounce_start(pin); - else if (gpio_setup[pin] & MV_GPIO_IN_IRQ_DOUBLE_EDGE) { - mv_gpio_polarity(pin, 0, 1); - mv_gpio_intr_handler(pin); + if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_DEBOUNCE) + mv_gpio_debounce_start(dev, pin); + else if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_IRQ_DOUBLE_EDGE) { + mv_gpio_polarity(dev, pin, 0, 1); + mv_gpio_intr_handler(dev, pin); } else - mv_gpio_intr_handler(pin); + mv_gpio_intr_handler(dev, pin); } status >>= 1; i++; } } static void -mv_gpio_intr_handler(int pin) +mv_gpio_intr_handler(device_t dev, int pin) { #ifdef INTRNG struct intr_irqsrc isrc; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_ASSERT_LOCKED(); #ifdef INTR_SOLO isrc.isrc_filter = NULL; #endif - isrc.isrc_event = gpio_events[pin]; + isrc.isrc_event = sc->gpio_events[pin]; if (isrc.isrc_event == NULL || TAILQ_EMPTY(&isrc.isrc_event->ie_handlers)) return; intr_isrc_dispatch(&isrc, NULL); #endif } int -mv_gpio_configure(uint32_t pin, uint32_t flags, uint32_t mask) +mv_gpio_configure(device_t dev, uint32_t pin, uint32_t flags, uint32_t mask) { int error; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); + error = 0; - if (pin >= mv_gpio_softc->pin_num) + if (pin >= sc->pin_num) return (EINVAL); /* check flags consistency */ if (((flags & mask) & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) return (EINVAL); if (mask & MV_GPIO_IN_DEBOUNCE) { - error = mv_gpio_debounce_prepare(pin); + error = mv_gpio_debounce_prepare(dev, pin); if (error != 0) return (error); } MV_GPIO_LOCK(); if (mask & MV_GPIO_OUT_BLINK) - mv_gpio_blink(pin, flags & MV_GPIO_OUT_BLINK); + mv_gpio_blink(dev, pin, flags & MV_GPIO_OUT_BLINK); if (mask & MV_GPIO_IN_POL_LOW) - mv_gpio_polarity(pin, flags & MV_GPIO_IN_POL_LOW, 0); + mv_gpio_polarity(dev, pin, flags & MV_GPIO_IN_POL_LOW, 0); if (mask & MV_GPIO_IN_DEBOUNCE) { - error = mv_gpio_debounce_setup(pin); + error = mv_gpio_debounce_setup(dev, pin); if (error) { MV_GPIO_UNLOCK(); return (error); } } - gpio_setup[pin] &= ~(mask); - gpio_setup[pin] |= (flags & mask); + sc->gpio_setup[pin].gp_flags &= ~(mask); + sc->gpio_setup[pin].gp_flags |= (flags & mask); MV_GPIO_UNLOCK(); return (0); } static void -mv_gpio_double_edge_init(int pin) +mv_gpio_double_edge_init(device_t dev, int pin) { uint8_t raw_read; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_ASSERT_LOCKED(); - raw_read = (mv_gpio_value_get(pin, 1) ? 1 : 0); + raw_read = (mv_gpio_value_get(dev, pin, 1) ? 1 : 0); if (raw_read) - mv_gpio_polarity(pin, 1, 0); + mv_gpio_polarity(dev, pin, 1, 0); else - mv_gpio_polarity(pin, 0, 0); + mv_gpio_polarity(dev, pin, 0, 0); } static int -mv_gpio_debounce_setup(int pin) +mv_gpio_debounce_setup(device_t dev, int pin) { struct callout *c; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); + MV_GPIO_ASSERT_LOCKED(); - c = mv_gpio_softc->debounce_callouts[pin]; + c = sc->debounce_callouts[pin]; if (c == NULL) return (ENXIO); if (callout_active(c)) callout_deactivate(c); callout_stop(c); return (0); } static int -mv_gpio_debounce_prepare(int pin) +mv_gpio_debounce_prepare(device_t dev, int pin) { struct callout *c; struct mv_gpio_softc *sc; - sc = (struct mv_gpio_softc *)mv_gpio_softc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); c = sc->debounce_callouts[pin]; if (c == NULL) { c = (struct callout *)malloc(sizeof(struct callout), M_DEVBUF, M_WAITOK); sc->debounce_callouts[pin] = c; if (c == NULL) return (ENOMEM); callout_init(c, 1); } return (0); } static int -mv_gpio_debounce_init(int pin) +mv_gpio_debounce_init(device_t dev, int pin) { uint8_t raw_read; int *cnt; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); + MV_GPIO_ASSERT_LOCKED(); - cnt = &mv_gpio_softc->debounce_counters[pin]; - - raw_read = (mv_gpio_value_get(pin, 1) ? 1 : 0); + cnt = &sc->debounce_counters[pin]; + raw_read = (mv_gpio_value_get(dev, pin, 1) ? 1 : 0); if (raw_read) { - mv_gpio_polarity(pin, 1, 0); + mv_gpio_polarity(dev, pin, 1, 0); *cnt = DEBOUNCE_HI_LO_MS / DEBOUNCE_CHECK_MS; } else { - mv_gpio_polarity(pin, 0, 0); + mv_gpio_polarity(dev, pin, 0, 0); *cnt = DEBOUNCE_LO_HI_MS / DEBOUNCE_CHECK_MS; } - mv_gpio_debounced_state_set(pin, raw_read); + mv_gpio_debounced_state_set(dev, pin, raw_read); return (0); } static void -mv_gpio_debounce_start(int pin) +mv_gpio_debounce_start(device_t dev, int pin) { struct callout *c; - int *debounced_pin; + struct mv_gpio_pindev s = {dev, pin}; + struct mv_gpio_pindev *sd; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_ASSERT_LOCKED(); - c = mv_gpio_softc->debounce_callouts[pin]; + c = sc->debounce_callouts[pin]; if (c == NULL) { - mv_gpio_int_ack(pin); + mv_gpio_int_ack(&s); return; } if (callout_pending(c) || callout_active(c)) { - mv_gpio_int_ack(pin); + mv_gpio_int_ack(&s); return; } - debounced_pin = (int *)malloc(sizeof(int), M_DEVBUF, - M_WAITOK); - if (debounced_pin == NULL) { - mv_gpio_int_ack(pin); + sd = (struct mv_gpio_pindev *)malloc(sizeof(struct mv_gpio_pindev), + M_DEVBUF, M_WAITOK); + if (sd == NULL) { + mv_gpio_int_ack(&s); return; } - *debounced_pin = pin; + sd->pin = pin; + sd->dev = dev; - callout_reset(c, DEBOUNCE_CHECK_TICKS, mv_gpio_debounce, - debounced_pin); + callout_reset(c, DEBOUNCE_CHECK_TICKS, mv_gpio_debounce, sd); } static void mv_gpio_debounce(void *arg) { uint8_t raw_read, last_state; int pin; + device_t dev; int *debounce_counter; + struct mv_gpio_softc *sc; + struct mv_gpio_pindev *s; - pin = *((int *)arg); + s = (struct mv_gpio_pindev *)arg; + dev = s->dev; + pin = s->pin; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_LOCK(); - raw_read = (mv_gpio_value_get(pin, 1) ? 1 : 0); - last_state = (mv_gpio_debounced_state_get(pin) ? 1 : 0); - debounce_counter = &mv_gpio_softc->debounce_counters[pin]; + raw_read = (mv_gpio_value_get(dev, pin, 1) ? 1 : 0); + last_state = (mv_gpio_debounced_state_get(dev, pin) ? 1 : 0); + debounce_counter = &sc->debounce_counters[pin]; if (raw_read == last_state) { if (last_state) *debounce_counter = DEBOUNCE_HI_LO_MS / DEBOUNCE_CHECK_MS; else *debounce_counter = DEBOUNCE_LO_HI_MS / DEBOUNCE_CHECK_MS; - callout_reset(mv_gpio_softc->debounce_callouts[pin], + callout_reset(sc->debounce_callouts[pin], DEBOUNCE_CHECK_TICKS, mv_gpio_debounce, arg); } else { *debounce_counter = *debounce_counter - 1; if (*debounce_counter != 0) - callout_reset(mv_gpio_softc->debounce_callouts[pin], + callout_reset(sc->debounce_callouts[pin], DEBOUNCE_CHECK_TICKS, mv_gpio_debounce, arg); else { - mv_gpio_debounced_state_set(pin, raw_read); + mv_gpio_debounced_state_set(dev, pin, raw_read); if (last_state) *debounce_counter = DEBOUNCE_HI_LO_MS / DEBOUNCE_CHECK_MS; else *debounce_counter = DEBOUNCE_LO_HI_MS / DEBOUNCE_CHECK_MS; - if (((gpio_setup[pin] & MV_GPIO_IN_POL_LOW) && + if (((sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_POL_LOW) && (raw_read == 0)) || - (((gpio_setup[pin] & MV_GPIO_IN_POL_LOW) == 0) && + (((sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_POL_LOW) == 0) && raw_read) || - (gpio_setup[pin] & MV_GPIO_IN_IRQ_DOUBLE_EDGE)) - mv_gpio_intr_handler(pin); + (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_IRQ_DOUBLE_EDGE)) + mv_gpio_intr_handler(dev, pin); /* Toggle polarity for next edge. */ - mv_gpio_polarity(pin, 0, 1); + mv_gpio_polarity(dev, pin, 0, 1); free(arg, M_DEVBUF); - callout_deactivate(mv_gpio_softc-> - debounce_callouts[pin]); + callout_deactivate(sc->debounce_callouts[pin]); } } MV_GPIO_UNLOCK(); } static void -mv_gpio_debounced_state_set(int pin, uint8_t new_state) +mv_gpio_debounced_state_set(device_t dev, int pin, uint8_t new_state) { uint32_t *old_state; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_ASSERT_LOCKED(); if (pin >= GPIO_PINS_PER_REG) { - old_state = &mv_gpio_softc->debounced_state_hi; + old_state = &sc->debounced_state_hi; pin -= GPIO_PINS_PER_REG; } else - old_state = &mv_gpio_softc->debounced_state_lo; + old_state = &sc->debounced_state_lo; if (new_state) *old_state |= (1 << pin); else *old_state &= ~(1 << pin); } static uint32_t -mv_gpio_debounced_state_get(int pin) +mv_gpio_debounced_state_get(device_t dev, int pin) { uint32_t *state; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_ASSERT_LOCKED(); if (pin >= GPIO_PINS_PER_REG) { - state = &mv_gpio_softc->debounced_state_hi; + state = &sc->debounced_state_hi; pin -= GPIO_PINS_PER_REG; } else - state = &mv_gpio_softc->debounced_state_lo; + state = &sc->debounced_state_lo; return (*state & (1 << pin)); } void -mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable) +mv_gpio_out(device_t dev, uint32_t pin, uint8_t val, uint8_t enable) { + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_LOCK(); - mv_gpio_value_set(pin, val); - mv_gpio_out_en(pin, enable); + mv_gpio_value_set(dev, pin, val); + mv_gpio_out_en(dev, pin, enable); MV_GPIO_UNLOCK(); } uint8_t -mv_gpio_in(uint32_t pin) +mv_gpio_in(device_t dev, uint32_t pin) { uint8_t state; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); MV_GPIO_LOCK(); - if (gpio_setup[pin] & MV_GPIO_IN_DEBOUNCE) { - if (gpio_setup[pin] & MV_GPIO_IN_POL_LOW) - state = (mv_gpio_debounced_state_get(pin) ? 0 : 1); + if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_DEBOUNCE) { + if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_POL_LOW) + state = (mv_gpio_debounced_state_get(dev, pin) ? 0 : 1); else - state = (mv_gpio_debounced_state_get(pin) ? 1 : 0); - } else if (gpio_setup[pin] & MV_GPIO_IN_IRQ_DOUBLE_EDGE) { - if (gpio_setup[pin] & MV_GPIO_IN_POL_LOW) - state = (mv_gpio_value_get(pin, 1) ? 0 : 1); + state = (mv_gpio_debounced_state_get(dev, pin) ? 1 : 0); + } else if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_IRQ_DOUBLE_EDGE) { + if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_POL_LOW) + state = (mv_gpio_value_get(dev, pin, 1) ? 0 : 1); else - state = (mv_gpio_value_get(pin, 1) ? 1 : 0); + state = (mv_gpio_value_get(dev, pin, 1) ? 1 : 0); } else - state = (mv_gpio_value_get(pin, 0) ? 1 : 0); + state = (mv_gpio_value_get(dev, pin, 0) ? 1 : 0); - MV_GPIO_UNLOCK(); return (state); } static uint32_t -mv_gpio_reg_read(uint32_t reg) +mv_gpio_reg_read(device_t dev, uint32_t reg) { + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); - return (bus_space_read_4(mv_gpio_softc->bst, - mv_gpio_softc->bsh, reg)); + return (bus_space_read_4(sc->bst, sc->bsh, reg)); } static void -mv_gpio_reg_write(uint32_t reg, uint32_t val) +mv_gpio_reg_write(device_t dev, uint32_t reg, uint32_t val) { + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); - bus_space_write_4(mv_gpio_softc->bst, - mv_gpio_softc->bsh, reg, val); + bus_space_write_4(sc->bst, sc->bsh, reg, val); } static void -mv_gpio_reg_set(uint32_t reg, uint32_t pin) +mv_gpio_reg_set(device_t dev, uint32_t reg, uint32_t pin) { uint32_t reg_val; - reg_val = mv_gpio_reg_read(reg); + reg_val = mv_gpio_reg_read(dev, reg); reg_val |= GPIO(pin); - mv_gpio_reg_write(reg, reg_val); + mv_gpio_reg_write(dev, reg, reg_val); } static void -mv_gpio_reg_clear(uint32_t reg, uint32_t pin) +mv_gpio_reg_clear(device_t dev, uint32_t reg, uint32_t pin) { uint32_t reg_val; - reg_val = mv_gpio_reg_read(reg); + reg_val = mv_gpio_reg_read(dev, reg); reg_val &= ~(GPIO(pin)); - mv_gpio_reg_write(reg, reg_val); + mv_gpio_reg_write(dev, reg, reg_val); } static void -mv_gpio_out_en(uint32_t pin, uint8_t enable) +mv_gpio_out_en(device_t dev, uint32_t pin, uint8_t enable) { uint32_t reg; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); - if (pin >= mv_gpio_softc->pin_num) + if (pin >= sc->pin_num) return; - if (pin >= GPIO_PINS_PER_REG) { - reg = GPIO_HI_DATA_OUT_EN_CTRL; - pin -= GPIO_PINS_PER_REG; - } else - reg = GPIO_DATA_OUT_EN_CTRL; + reg = GPIO_DATA_OUT_EN_CTRL; if (enable) - mv_gpio_reg_clear(reg, pin); + mv_gpio_reg_clear(dev, reg, pin); else - mv_gpio_reg_set(reg, pin); + mv_gpio_reg_set(dev, reg, pin); } static void -mv_gpio_blink(uint32_t pin, uint8_t enable) +mv_gpio_blink(device_t dev, uint32_t pin, uint8_t enable) { uint32_t reg; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); - if (pin >= mv_gpio_softc->pin_num) + if (pin >= sc->pin_num) return; - if (pin >= GPIO_PINS_PER_REG) { - reg = GPIO_HI_BLINK_EN; - pin -= GPIO_PINS_PER_REG; - } else - reg = GPIO_BLINK_EN; + reg = GPIO_BLINK_EN; if (enable) - mv_gpio_reg_set(reg, pin); + mv_gpio_reg_set(dev, reg, pin); else - mv_gpio_reg_clear(reg, pin); + mv_gpio_reg_clear(dev, reg, pin); } static void -mv_gpio_polarity(uint32_t pin, uint8_t enable, uint8_t toggle) +mv_gpio_polarity(device_t dev, uint32_t pin, uint8_t enable, uint8_t toggle) { uint32_t reg, reg_val; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); - if (pin >= mv_gpio_softc->pin_num) + if (pin >= sc->pin_num) return; - if (pin >= GPIO_PINS_PER_REG) { - reg = GPIO_HI_DATA_IN_POLAR; - pin -= GPIO_PINS_PER_REG; - } else - reg = GPIO_DATA_IN_POLAR; + reg = GPIO_DATA_IN_POLAR; if (toggle) { - reg_val = mv_gpio_reg_read(reg) & GPIO(pin); + reg_val = mv_gpio_reg_read(dev, reg) & GPIO(pin); if (reg_val) - mv_gpio_reg_clear(reg, pin); + mv_gpio_reg_clear(dev, reg, pin); else - mv_gpio_reg_set(reg, pin); + mv_gpio_reg_set(dev, reg, pin); } else if (enable) - mv_gpio_reg_set(reg, pin); + mv_gpio_reg_set(dev, reg, pin); else - mv_gpio_reg_clear(reg, pin); + mv_gpio_reg_clear(dev, reg, pin); } static void -mv_gpio_level(uint32_t pin, uint8_t enable) +mv_gpio_level(device_t dev, uint32_t pin, uint8_t enable) { uint32_t reg; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); - if (pin >= mv_gpio_softc->pin_num) + if (pin >= sc->pin_num) return; - if (pin >= GPIO_PINS_PER_REG) { - reg = GPIO_HI_INT_LEV_MASK; - pin -= GPIO_PINS_PER_REG; - } else - reg = GPIO_INT_LEV_MASK; + reg = GPIO_INT_LEV_MASK; if (enable) - mv_gpio_reg_set(reg, pin); + mv_gpio_reg_set(dev, reg, pin); else - mv_gpio_reg_clear(reg, pin); + mv_gpio_reg_clear(dev, reg, pin); } static void -mv_gpio_edge(uint32_t pin, uint8_t enable) +mv_gpio_edge(device_t dev, uint32_t pin, uint8_t enable) { uint32_t reg; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); - if (pin >= mv_gpio_softc->pin_num) + if (pin >= sc->pin_num) return; - if (pin >= GPIO_PINS_PER_REG) { - reg = GPIO_HI_INT_EDGE_MASK; - pin -= GPIO_PINS_PER_REG; - } else - reg = GPIO_INT_EDGE_MASK; + reg = GPIO_INT_EDGE_MASK; if (enable) - mv_gpio_reg_set(reg, pin); + mv_gpio_reg_set(dev, reg, pin); else - mv_gpio_reg_clear(reg, pin); + mv_gpio_reg_clear(dev, reg, pin); } static void -mv_gpio_int_ack(uint32_t pin) +mv_gpio_int_ack(struct mv_gpio_pindev *s) { - uint32_t reg; + uint32_t reg, pin; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(s->dev); + pin = s->pin; - if (pin >= mv_gpio_softc->pin_num) + if (pin >= sc->pin_num) return; - if (pin >= GPIO_PINS_PER_REG) { - reg = GPIO_HI_INT_CAUSE; - pin -= GPIO_PINS_PER_REG; - } else - reg = GPIO_INT_CAUSE; + reg = GPIO_INT_CAUSE; - mv_gpio_reg_clear(reg, pin); + mv_gpio_reg_clear(s->dev, reg, pin); } static uint32_t -mv_gpio_value_get(uint32_t pin, uint8_t exclude_polar) +mv_gpio_value_get(device_t dev, uint32_t pin, uint8_t exclude_polar) { uint32_t reg, polar_reg, reg_val, polar_reg_val; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); - if (pin >= mv_gpio_softc->pin_num) + if (pin >= sc->pin_num) return (0); - if (pin >= GPIO_PINS_PER_REG) { - reg = GPIO_HI_DATA_IN; - pin -= GPIO_PINS_PER_REG; - polar_reg = GPIO_HI_DATA_IN_POLAR; - } else { - reg = GPIO_DATA_IN; - polar_reg = GPIO_DATA_IN_POLAR; - } + reg = GPIO_DATA_IN; + polar_reg = GPIO_DATA_IN_POLAR; - reg_val = mv_gpio_reg_read(reg); + reg_val = mv_gpio_reg_read(dev, reg); if (exclude_polar) { - polar_reg_val = mv_gpio_reg_read(polar_reg); + polar_reg_val = mv_gpio_reg_read(dev, polar_reg); return ((reg_val & GPIO(pin)) ^ (polar_reg_val & GPIO(pin))); } else return (reg_val & GPIO(pin)); } static void -mv_gpio_value_set(uint32_t pin, uint8_t val) +mv_gpio_value_set(device_t dev, uint32_t pin, uint8_t val) { uint32_t reg; + struct mv_gpio_softc *sc; + sc = (struct mv_gpio_softc *)device_get_softc(dev); - if (pin >= mv_gpio_softc->pin_num) + if (pin >= sc->pin_num) return; - if (pin >= GPIO_PINS_PER_REG) { - reg = GPIO_HI_DATA_OUT; - pin -= GPIO_PINS_PER_REG; - } else - reg = GPIO_DATA_OUT; + reg = GPIO_DATA_OUT; if (val) - mv_gpio_reg_set(reg, pin); + mv_gpio_reg_set(dev, reg, pin); else - mv_gpio_reg_clear(reg, pin); + mv_gpio_reg_clear(dev, reg, pin); } static int -mv_handle_gpios_prop(phandle_t ctrl, pcell_t *gpios, int len) +mv_handle_gpios_prop(device_t dev, phandle_t ctrl, pcell_t *gpios, int len) { pcell_t gpio_cells, pincnt; int inc, t, tuples, tuple_size; int dir, flags, pin; u_long gpio_ctrl, size; struct mv_gpio_softc sc; pincnt = 0; if (!OF_hasprop(ctrl, "gpio-controller")) /* Node is not a GPIO controller. */ return (ENXIO); if (OF_getencprop(ctrl, "#gpio-cells", &gpio_cells, sizeof(pcell_t)) < 0) return (ENXIO); if (gpio_cells != 3) return (ENXIO); tuple_size = gpio_cells * sizeof(pcell_t) + sizeof(phandle_t); tuples = len / tuple_size; if (fdt_regsize(ctrl, &gpio_ctrl, &size)) return (ENXIO); if (OF_getencprop(ctrl, "pin-count", &pincnt, sizeof(pcell_t)) < 0) return (ENXIO); sc.pin_num = pincnt; /* * Skip controller reference, since controller's phandle is given * explicitly (in a function argument). */ inc = sizeof(ihandle_t) / sizeof(pcell_t); gpios += inc; for (t = 0; t < tuples; t++) { pin = gpios[0]; dir = gpios[1]; flags = gpios[2]; - mv_gpio_configure(pin, flags, ~0); + mv_gpio_configure(dev, pin, flags, ~0); if (dir == 1) /* Input. */ - mv_gpio_out_en(pin, 0); + mv_gpio_out_en(dev, pin, 0); else { /* Output. */ if (flags & MV_GPIO_OUT_OPEN_DRAIN) - mv_gpio_out(pin, 0, 1); + mv_gpio_out(dev, pin, 0, 1); if (flags & MV_GPIO_OUT_OPEN_SRC) - mv_gpio_out(pin, 1, 1); + mv_gpio_out(dev, pin, 1, 1); } gpios += gpio_cells + inc; } return (0); } #define MAX_PINS_PER_NODE 5 #define GPIOS_PROP_CELLS 4 static int -mv_gpio_init(void) +mv_gpio_init(device_t dev) { phandle_t child, parent, root, ctrl; pcell_t gpios[MAX_PINS_PER_NODE * GPIOS_PROP_CELLS]; struct gpio_ctrl_entry *e; int len, rv; root = OF_finddevice("/"); len = 0; parent = root; /* Traverse through entire tree to find nodes with 'gpios' prop */ for (child = OF_child(parent); child != 0; child = OF_peer(child)) { /* Find a 'leaf'. Start the search from this node. */ while (OF_child(child)) { parent = child; child = OF_child(child); } if ((len = OF_getproplen(child, "gpios")) > 0) { if (len > sizeof(gpios)) return (ENXIO); /* Get 'gpios' property. */ OF_getencprop(child, "gpios", gpios, len); e = (struct gpio_ctrl_entry *)&gpio_controllers; /* Find and call a handler. */ for (; e->compat; e++) { /* * First cell of 'gpios' property should * contain a ref. to a node defining GPIO * controller. */ ctrl = OF_node_from_xref(gpios[0]); if (ofw_bus_node_is_compatible(ctrl, e->compat)) /* Call a handler. */ - if ((rv = e->handler(ctrl, + if ((rv = e->handler(dev, ctrl, (pcell_t *)&gpios, len))) return (rv); } } if (OF_peer(child) == 0) { /* No more siblings. */ child = parent; parent = OF_parent(child); } } return (0); } Index: head/sys/arm/mv/mvreg.h =================================================================== --- head/sys/arm/mv/mvreg.h (revision 332023) +++ head/sys/arm/mv/mvreg.h (revision 332024) @@ -1,452 +1,443 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Developed by 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. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY 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 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. * * $FreeBSD$ */ #ifndef _MVREG_H_ #define _MVREG_H_ #include #if defined(SOC_MV_DISCOVERY) #define IRQ_CAUSE_ERROR 0x0 #define IRQ_CAUSE 0x4 #define IRQ_CAUSE_HI 0x8 #define IRQ_MASK_ERROR 0xC #define IRQ_MASK 0x10 #define IRQ_MASK_HI 0x14 #define IRQ_CAUSE_SELECT 0x18 #define FIQ_MASK_ERROR 0x1C #define FIQ_MASK 0x20 #define FIQ_MASK_HI 0x24 #define FIQ_CAUSE_SELECT 0x28 #define ENDPOINT_IRQ_MASK_ERROR(n) 0x2C #define ENDPOINT_IRQ_MASK(n) 0x30 #define ENDPOINT_IRQ_MASK_HI(n) 0x34 #define ENDPOINT_IRQ_CAUSE_SELECT 0x38 #else #define IRQ_CAUSE 0x0 #define IRQ_MASK 0x4 #define FIQ_MASK 0x8 #define ENDPOINT_IRQ_MASK(n) 0xC #define IRQ_CAUSE_HI 0x10 #define IRQ_MASK_HI 0x14 #define FIQ_MASK_HI 0x18 #define ENDPOINT_IRQ_MASK_HI(n) 0x1C #define ENDPOINT_IRQ_MASK_ERROR(n) (-1) #define IRQ_CAUSE_ERROR (-1) /* Fake defines for unified */ #define IRQ_MASK_ERROR (-1) /* interrupt controller code */ #endif #define MAIN_IRQ_NUM 116 #define ERR_IRQ_NUM 32 #define ERR_IRQ (MAIN_IRQ_NUM) #define MSI_IRQ (ERR_IRQ + ERR_IRQ_NUM) #define MSI_IRQ_NUM 32 #define IRQ_CPU_SELF 0x00000001 #define BRIDGE_IRQ_CAUSE_ARMADAXP 0x68 #define IRQ_TIMER0_ARMADAXP 0x00000001 #define IRQ_TIMER1_ARMADAXP 0x00000002 #define IRQ_TIMER_WD_ARMADAXP 0x00000004 #define BRIDGE_IRQ_CAUSE 0x10 #define IRQ_CPU_SELF 0x00000001 #define IRQ_TIMER0 0x00000002 #define IRQ_TIMER1 0x00000004 #define IRQ_TIMER_WD 0x00000008 #define BRIDGE_IRQ_MASK 0x14 #define IRQ_CPU_MASK 0x00000001 #define IRQ_TIMER0_MASK 0x00000002 #define IRQ_TIMER1_MASK 0x00000004 #define IRQ_TIMER_WD_MASK 0x00000008 #define IRQ_CPU_SELF_CLR (~IRQ_CPU_SELF) #define IRQ_TIMER0_CLR (~IRQ_TIMER0) #define IRQ_TIMER_WD_CLR (~IRQ_TIMER_WD) #define IRQ_TIMER0_CLR_ARMADAXP (~IRQ_TIMER0_ARMADAXP) #define IRQ_TIMER_WD_CLR_ARMADAXP (~IRQ_TIMER_WD_ARMADAXP) /* * System reset */ #define RSTOUTn_MASK_ARMV7 0x60 #define SYSTEM_SOFT_RESET_ARMV7 0x64 #define SOFT_RST_OUT_EN_ARMV7 0x00000001 #define SYS_SOFT_RST_ARMV7 0x00000001 #define RSTOUTn_MASK 0x8 #define SOFT_RST_OUT_EN 0x00000004 #define SYSTEM_SOFT_RESET 0xc #define SYS_SOFT_RST 0x00000001 #define RSTOUTn_MASK_WD 0x400 #define WD_RSTOUTn_MASK 0x4 #define WD_GLOBAL_MASK 0x00000100 #define WD_CPU0_MASK 0x00000001 #define WD_RST_OUT_EN 0x00000002 /* * Power Control */ #if defined(SOC_MV_KIRKWOOD) #define CPU_PM_CTRL 0x18 #else #define CPU_PM_CTRL 0x1C #endif #define CPU_PM_CTRL_NONE 0 #define CPU_PM_CTRL_ALL ~0x0 #if defined(SOC_MV_KIRKWOOD) #define CPU_PM_CTRL_GE0 (1 << 0) #define CPU_PM_CTRL_PEX0_PHY (1 << 1) #define CPU_PM_CTRL_PEX0 (1 << 2) #define CPU_PM_CTRL_USB0 (1 << 3) #define CPU_PM_CTRL_SDIO (1 << 4) #define CPU_PM_CTRL_TSU (1 << 5) #define CPU_PM_CTRL_DUNIT (1 << 6) #define CPU_PM_CTRL_RUNIT (1 << 7) #define CPU_PM_CTRL_XOR0 (1 << 8) #define CPU_PM_CTRL_AUDIO (1 << 9) #define CPU_PM_CTRL_SATA0 (1 << 14) #define CPU_PM_CTRL_SATA1 (1 << 15) #define CPU_PM_CTRL_XOR1 (1 << 16) #define CPU_PM_CTRL_CRYPTO (1 << 17) #define CPU_PM_CTRL_GE1 (1 << 19) #define CPU_PM_CTRL_TDM (1 << 20) #define CPU_PM_CTRL_XOR (CPU_PM_CTRL_XOR0 | CPU_PM_CTRL_XOR1) #define CPU_PM_CTRL_USB(u) (CPU_PM_CTRL_USB0) #define CPU_PM_CTRL_SATA (CPU_PM_CTRL_SATA0 | CPU_PM_CTRL_SATA1) #define CPU_PM_CTRL_GE(u) (CPU_PM_CTRL_GE1 * (u) | CPU_PM_CTRL_GE0 * \ (1 - (u))) #define CPU_PM_CTRL_IDMA (CPU_PM_CTRL_NONE) #elif defined(SOC_MV_DISCOVERY) #define CPU_PM_CTRL_GE0 (1 << 1) #define CPU_PM_CTRL_GE1 (1 << 2) #define CPU_PM_CTRL_PEX00 (1 << 5) #define CPU_PM_CTRL_PEX01 (1 << 6) #define CPU_PM_CTRL_PEX02 (1 << 7) #define CPU_PM_CTRL_PEX03 (1 << 8) #define CPU_PM_CTRL_PEX10 (1 << 9) #define CPU_PM_CTRL_PEX11 (1 << 10) #define CPU_PM_CTRL_PEX12 (1 << 11) #define CPU_PM_CTRL_PEX13 (1 << 12) #define CPU_PM_CTRL_SATA0_PHY (1 << 13) #define CPU_PM_CTRL_SATA0 (1 << 14) #define CPU_PM_CTRL_SATA1_PHY (1 << 15) #define CPU_PM_CTRL_SATA1 (1 << 16) #define CPU_PM_CTRL_USB0 (1 << 17) #define CPU_PM_CTRL_USB1 (1 << 18) #define CPU_PM_CTRL_USB2 (1 << 19) #define CPU_PM_CTRL_IDMA (1 << 20) #define CPU_PM_CTRL_XOR (1 << 21) #define CPU_PM_CTRL_CRYPTO (1 << 22) #define CPU_PM_CTRL_DEVICE (1 << 23) #define CPU_PM_CTRL_USB(u) (1 << (17 + (u))) #define CPU_PM_CTRL_SATA (CPU_PM_CTRL_SATA0 | CPU_PM_CTRL_SATA1) #define CPU_PM_CTRL_GE(u) (CPU_PM_CTRL_GE1 * (u) | CPU_PM_CTRL_GE0 * \ (1 - (u))) #else #define CPU_PM_CTRL_CRYPTO (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_IDMA (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_XOR (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_SATA (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_USB(u) (CPU_PM_CTRL_NONE) #define CPU_PM_CTRL_GE(u) (CPU_PM_CTRL_NONE) #endif /* * Timers */ #define CPU_TIMERS_BASE 0x300 #define CPU_TIMER_CONTROL 0x0 #define CPU_TIMER0_EN 0x00000001 #define CPU_TIMER0_AUTO 0x00000002 #define CPU_TIMER1_EN 0x00000004 #define CPU_TIMER1_AUTO 0x00000008 #define CPU_TIMER2_EN 0x00000010 #define CPU_TIMER2_AUTO 0x00000020 #define CPU_TIMER_WD_EN 0x00000100 #define CPU_TIMER_WD_AUTO 0x00000200 /* 25MHz mode is Armada XP - specific */ #define CPU_TIMER_WD_25MHZ_EN 0x00000400 #define CPU_TIMER0_25MHZ_EN 0x00000800 #define CPU_TIMER1_25MHZ_EN 0x00001000 #define CPU_TIMER0_REL 0x10 #define CPU_TIMER0 0x14 /* * SATA */ #define SATA_CHAN_NUM 2 #define EDMA_REGISTERS_OFFSET 0x2000 #define EDMA_REGISTERS_SIZE 0x2000 #define SATA_EDMA_BASE(ch) (EDMA_REGISTERS_OFFSET + \ ((ch) * EDMA_REGISTERS_SIZE)) /* SATAHC registers */ #define SATA_CR 0x000 /* Configuration Reg. */ #define SATA_CR_NODMABS (1 << 8) #define SATA_CR_NOEDMABS (1 << 9) #define SATA_CR_NOPRDPBS (1 << 10) #define SATA_CR_COALDIS(ch) (1 << (24 + ch)) /* Interrupt Coalescing Threshold Reg. */ #define SATA_ICTR 0x00C #define SATA_ICTR_MAX ((1 << 8) - 1) /* Interrupt Time Threshold Reg. */ #define SATA_ITTR 0x010 #define SATA_ITTR_MAX ((1 << 24) - 1) #define SATA_ICR 0x014 /* Interrupt Cause Reg. */ #define SATA_ICR_DMADONE(ch) (1 << (ch)) #define SATA_ICR_COAL (1 << 4) #define SATA_ICR_DEV(ch) (1 << (8 + ch)) #define SATA_MICR 0x020 /* Main Interrupt Cause Reg. */ #define SATA_MICR_ERR(ch) (1 << (2 * ch)) #define SATA_MICR_DONE(ch) (1 << ((2 * ch) + 1)) #define SATA_MICR_DMADONE(ch) (1 << (4 + ch)) #define SATA_MICR_COAL (1 << 8) #define SATA_MIMR 0x024 /* Main Interrupt Mask Reg. */ /* Shadow registers */ #define SATA_SHADOWR_BASE(ch) (SATA_EDMA_BASE(ch) + 0x100) #define SATA_SHADOWR_CONTROL(ch) (SATA_EDMA_BASE(ch) + 0x120) /* SATA registers */ #define SATA_SATA_SSTATUS(ch) (SATA_EDMA_BASE(ch) + 0x300) #define SATA_SATA_SERROR(ch) (SATA_EDMA_BASE(ch) + 0x304) #define SATA_SATA_SCONTROL(ch) (SATA_EDMA_BASE(ch) + 0x308) #define SATA_SATA_FISICR(ch) (SATA_EDMA_BASE(ch) + 0x364) /* EDMA registers */ #define SATA_EDMA_CFG(ch) (SATA_EDMA_BASE(ch) + 0x000) #define SATA_EDMA_CFG_QL128 (1 << 19) #define SATA_EDMA_CFG_HQCACHE (1 << 22) #define SATA_EDMA_IECR(ch) (SATA_EDMA_BASE(ch) + 0x008) #define SATA_EDMA_IEMR(ch) (SATA_EDMA_BASE(ch) + 0x00C) #define SATA_EDMA_REQBAHR(ch) (SATA_EDMA_BASE(ch) + 0x010) #define SATA_EDMA_REQIPR(ch) (SATA_EDMA_BASE(ch) + 0x014) #define SATA_EDMA_REQOPR(ch) (SATA_EDMA_BASE(ch) + 0x018) #define SATA_EDMA_RESBAHR(ch) (SATA_EDMA_BASE(ch) + 0x01C) #define SATA_EDMA_RESIPR(ch) (SATA_EDMA_BASE(ch) + 0x020) #define SATA_EDMA_RESOPR(ch) (SATA_EDMA_BASE(ch) + 0x024) #define SATA_EDMA_CMD(ch) (SATA_EDMA_BASE(ch) + 0x028) #define SATA_EDMA_CMD_ENABLE (1 << 0) #define SATA_EDMA_CMD_DISABLE (1 << 1) #define SATA_EDMA_CMD_RESET (1 << 2) #define SATA_EDMA_STATUS(ch) (SATA_EDMA_BASE(ch) + 0x030) #define SATA_EDMA_STATUS_IDLE (1 << 7) /* Offset to extract input slot from REQIPR register */ #define SATA_EDMA_REQIS_OFS 5 /* Offset to extract input slot from RESOPR register */ #define SATA_EDMA_RESOS_OFS 3 /* * GPIO */ #define GPIO_DATA_OUT 0x00 #define GPIO_DATA_OUT_EN_CTRL 0x04 #define GPIO_BLINK_EN 0x08 #define GPIO_DATA_IN_POLAR 0x0c #define GPIO_DATA_IN 0x10 #define GPIO_INT_CAUSE 0x14 #define GPIO_INT_EDGE_MASK 0x18 #define GPIO_INT_LEV_MASK 0x1c -#define GPIO_HI_DATA_OUT 0x40 -#define GPIO_HI_DATA_OUT_EN_CTRL 0x44 -#define GPIO_HI_BLINK_EN 0x48 -#define GPIO_HI_DATA_IN_POLAR 0x4c -#define GPIO_HI_DATA_IN 0x50 -#define GPIO_HI_INT_CAUSE 0x54 -#define GPIO_HI_INT_EDGE_MASK 0x58 -#define GPIO_HI_INT_LEV_MASK 0x5c - #define GPIO(n) (1 << (n)) #define MV_GPIO_MAX_NPINS 64 #define MV_GPIO_IN_NONE 0x0 #define MV_GPIO_IN_POL_LOW (1 << 16) #define MV_GPIO_IN_IRQ_EDGE (2 << 16) #define MV_GPIO_IN_IRQ_LEVEL (4 << 16) #define MV_GPIO_IN_IRQ_DOUBLE_EDGE (8 << 16) #define MV_GPIO_IN_DEBOUNCE (16 << 16) #define MV_GPIO_OUT_NONE 0x0 #define MV_GPIO_OUT_BLINK 0x1 #define MV_GPIO_OUT_OPEN_DRAIN 0x2 #define MV_GPIO_OUT_OPEN_SRC 0x4 #define IS_GPIO_IRQ(irq) ((irq) >= NIRQ && (irq) < NIRQ + MV_GPIO_MAX_NPINS) #define GPIO2IRQ(gpio) ((gpio) + NIRQ) #define IRQ2GPIO(irq) ((irq) - NIRQ) #if defined(SOC_MV_ORION) #define SAMPLE_AT_RESET 0x10 #elif defined(SOC_MV_KIRKWOOD) #define SAMPLE_AT_RESET 0x30 #endif #define SAMPLE_AT_RESET_ARMADA38X 0x400 #define SAMPLE_AT_RESET_LO 0x30 #define SAMPLE_AT_RESET_HI 0x34 /* * Clocks */ #if defined(SOC_MV_ORION) #define TCLK_MASK 0x00000300 #define TCLK_SHIFT 0x08 #elif defined(SOC_MV_DISCOVERY) #define TCLK_MASK 0x00000180 #define TCLK_SHIFT 0x07 #endif #define TCLK_MASK_ARMADA38X 0x00008000 #define TCLK_SHIFT_ARMADA38X 15 #define TCLK_100MHZ 100000000 #define TCLK_125MHZ 125000000 #define TCLK_133MHZ 133333333 #define TCLK_150MHZ 150000000 #define TCLK_166MHZ 166666667 #define TCLK_200MHZ 200000000 #define TCLK_250MHZ 250000000 #define TCLK_300MHZ 300000000 #define TCLK_667MHZ 667000000 #define A38X_CPU_DDR_CLK_MASK 0x00007c00 #define A38X_CPU_DDR_CLK_SHIFT 10 /* * CPU Cache Configuration */ #define CPU_CONFIG 0x00000000 #define CPU_CONFIG_IC_PREF 0x00010000 #define CPU_CONFIG_DC_PREF 0x00020000 #define CPU_CONTROL 0x00000004 #define CPU_CONTROL_L2_SIZE 0x00200000 /* Only on Discovery */ #define CPU_CONTROL_L2_MODE 0x00020000 /* Only on Discovery */ #define CPU_L2_CONFIG 0x00000028 /* Only on Kirkwood */ #define CPU_L2_CONFIG_MODE 0x00000010 /* Only on Kirkwood */ /* * PCI Express port control (CPU Control registers) */ #define CPU_CONTROL_PCIE_DISABLE(n) (1 << (3 * (n))) /* * Vendor ID */ #define PCI_VENDORID_MRVL 0x11AB #define PCI_VENDORID_MRVL2 0x1B4B /* * Chip ID */ #define MV_DEV_88F5181 0x5181 #define MV_DEV_88F5182 0x5182 #define MV_DEV_88F5281 0x5281 #define MV_DEV_88F6281 0x6281 #define MV_DEV_88F6282 0x6282 #define MV_DEV_88F6781 0x6781 #define MV_DEV_88F6828 0x6828 #define MV_DEV_88F6820 0x6820 #define MV_DEV_88F6810 0x6810 #define MV_DEV_MV78100_Z0 0x6381 #define MV_DEV_MV78100 0x7810 #define MV_DEV_MV78130 0x7813 #define MV_DEV_MV78160 0x7816 #define MV_DEV_MV78230 0x7823 #define MV_DEV_MV78260 0x7826 #define MV_DEV_MV78460 0x7846 #define MV_DEV_88RC8180 0x8180 #define MV_DEV_88RC9480 0x9480 #define MV_DEV_88RC9580 0x9580 #define MV_DEV_FAMILY_MASK 0xff00 #define MV_DEV_DISCOVERY 0x7800 #define MV_DEV_ARMADA38X 0x6800 /* * Doorbell register control */ #define MV_DRBL_PCIE_TO_CPU 0 #define MV_DRBL_CPU_TO_PCIE 1 #define MV_DRBL_CAUSE(d,u) (0x10 * (u) + 0x8 * (d)) #define MV_DRBL_MASK(d,u) (0x10 * (u) + 0x8 * (d) + 0x4) #define MV_DRBL_MSG(m,d,u) (0x10 * (u) + 0x8 * (d) + 0x4 * (m) + 0x30) /* * SCU */ #define MV_SCU_BASE (MV_BASE + 0xc000) #define MV_SCU_REGS_LEN 0x100 #define MV_SCU_REG_CTRL 0x00 #define MV_SCU_REG_CONFIG 0x04 #define MV_SCU_ENABLE (1 << 0) #define MV_SCU_SL_L2_ENABLE (1 << 3) #define SCU_CFG_REG_NCPU_MASK 0x3 /* * PMSU */ #define MV_PMSU_BASE (MV_BASE + 0x22000) #define MV_PMSU_REGS_LEN 0x1000 #define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) (((cpu) * 0x100) + 0x124) /* * CPU RESET */ #define MV_CPU_RESET_BASE (MV_BASE + 0x20800) #define MV_CPU_RESET_REGS_LEN 0x8 #define CPU_RESET_OFFSET(cpu) ((cpu) * 0x8) #define CPU_RESET_ASSERT 0x1 #define MV_MBUS_CTRL_BASE (MV_BASE + 0x20420) #define MV_MBUS_CTRL_REGS_LEN 0x10 #endif /* _MVREG_H_ */