12d2a0852SEmmanuel Vadot /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
32d2a0852SEmmanuel Vadot *
42d2a0852SEmmanuel Vadot * Copyright (c) 2018 Rubicon Communications, LLC (Netgate)
52d2a0852SEmmanuel Vadot *
62d2a0852SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without
72d2a0852SEmmanuel Vadot * modification, are permitted provided that the following conditions
82d2a0852SEmmanuel Vadot * are met:
92d2a0852SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright
102d2a0852SEmmanuel Vadot * notice, this list of conditions and the following disclaimer.
112d2a0852SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright
122d2a0852SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the
132d2a0852SEmmanuel Vadot * documentation and/or other materials provided with the distribution.
142d2a0852SEmmanuel Vadot *
152d2a0852SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
162d2a0852SEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
172d2a0852SEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
182d2a0852SEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
192d2a0852SEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
202d2a0852SEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
212d2a0852SEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
222d2a0852SEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
232d2a0852SEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
242d2a0852SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
252d2a0852SEmmanuel Vadot * SUCH DAMAGE.
262d2a0852SEmmanuel Vadot */
272d2a0852SEmmanuel Vadot
282d2a0852SEmmanuel Vadot #include <sys/param.h>
292d2a0852SEmmanuel Vadot #include <sys/systm.h>
302d2a0852SEmmanuel Vadot #include <sys/bus.h>
312d2a0852SEmmanuel Vadot
322d2a0852SEmmanuel Vadot #include <sys/kernel.h>
332d2a0852SEmmanuel Vadot #include <sys/module.h>
342d2a0852SEmmanuel Vadot #include <sys/rman.h>
352d2a0852SEmmanuel Vadot #include <sys/lock.h>
362d2a0852SEmmanuel Vadot #include <sys/mutex.h>
372d2a0852SEmmanuel Vadot
382d2a0852SEmmanuel Vadot #include <machine/bus.h>
392d2a0852SEmmanuel Vadot #include <machine/resource.h>
402d2a0852SEmmanuel Vadot #include <machine/intr.h>
412d2a0852SEmmanuel Vadot
42*62e8ccc3SEmmanuel Vadot #include <dev/syscon/syscon.h>
434b84206bSMichal Meloun
444b84206bSMichal Meloun #include <dev/fdt/fdt_pinctrl.h>
452d2a0852SEmmanuel Vadot
462d2a0852SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
472d2a0852SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
482d2a0852SEmmanuel Vadot
494b84206bSMichal Meloun #include "syscon_if.h"
502d2a0852SEmmanuel Vadot
512d2a0852SEmmanuel Vadot #define PINS_PER_REG 8
522d2a0852SEmmanuel Vadot #define BITS_PER_PIN 4
532d2a0852SEmmanuel Vadot #define PINS_MASK 0xf
542d2a0852SEmmanuel Vadot #define MAX_PIN_FUNC 5
552d2a0852SEmmanuel Vadot
562d2a0852SEmmanuel Vadot struct mv_pins {
572d2a0852SEmmanuel Vadot const char *name;
582d2a0852SEmmanuel Vadot const char *functions[MAX_PIN_FUNC];
592d2a0852SEmmanuel Vadot };
602d2a0852SEmmanuel Vadot
612d2a0852SEmmanuel Vadot struct mv_padconf {
622d2a0852SEmmanuel Vadot const struct mv_pins *pins;
632d2a0852SEmmanuel Vadot size_t npins;
642d2a0852SEmmanuel Vadot };
652d2a0852SEmmanuel Vadot
662d2a0852SEmmanuel Vadot const static struct mv_pins ap806_pins[] = {
672d2a0852SEmmanuel Vadot {"mpp0", {"gpio", "sdio", NULL, "spi0"}},
682d2a0852SEmmanuel Vadot {"mpp1", {"gpio", "sdio", NULL, "spi0"}},
692d2a0852SEmmanuel Vadot {"mpp2", {"gpio", "sdio", NULL, "spi0"}},
702d2a0852SEmmanuel Vadot {"mpp3", {"gpio", "sdio", NULL, "spi0"}},
712d2a0852SEmmanuel Vadot {"mpp4", {"gpio", "sdio", NULL, "i2c0"}},
722d2a0852SEmmanuel Vadot {"mpp5", {"gpio", "sdio", NULL, "i2c0"}},
732d2a0852SEmmanuel Vadot {"mpp6", {"gpio", "sdio", NULL, NULL}},
742d2a0852SEmmanuel Vadot {"mpp7", {"gpio", "sdio", NULL, "uart1"}},
752d2a0852SEmmanuel Vadot {"mpp8", {"gpio", "sdio", NULL, "uart1"}},
762d2a0852SEmmanuel Vadot {"mpp9", {"gpio", "sdio", NULL, "spi0"}},
772d2a0852SEmmanuel Vadot {"mpp10", {"gpio", "sdio", NULL, NULL}},
782d2a0852SEmmanuel Vadot {"mpp11", {"gpio", NULL, NULL, "uart0"}},
792d2a0852SEmmanuel Vadot {"mpp12", {"gpio", "sdio", "sdio", NULL}},
802d2a0852SEmmanuel Vadot {"mpp13", {"gpio", NULL, NULL}},
812d2a0852SEmmanuel Vadot {"mpp14", {"gpio", NULL, NULL}},
822d2a0852SEmmanuel Vadot {"mpp15", {"gpio", NULL, NULL}},
832d2a0852SEmmanuel Vadot {"mpp16", {"gpio", NULL, NULL}},
842d2a0852SEmmanuel Vadot {"mpp17", {"gpio", NULL, NULL}},
852d2a0852SEmmanuel Vadot {"mpp18", {"gpio", NULL, NULL}},
862d2a0852SEmmanuel Vadot {"mpp19", {"gpio", NULL, NULL, "uart0", "sdio"}},
872d2a0852SEmmanuel Vadot };
882d2a0852SEmmanuel Vadot
892d2a0852SEmmanuel Vadot const struct mv_padconf ap806_padconf = {
902d2a0852SEmmanuel Vadot .npins = nitems(ap806_pins),
912d2a0852SEmmanuel Vadot .pins = ap806_pins,
922d2a0852SEmmanuel Vadot };
932d2a0852SEmmanuel Vadot
942d2a0852SEmmanuel Vadot struct mv_pinctrl_softc {
952d2a0852SEmmanuel Vadot device_t dev;
964b84206bSMichal Meloun struct syscon *syscon;
972d2a0852SEmmanuel Vadot
982d2a0852SEmmanuel Vadot struct mv_padconf *padconf;
992d2a0852SEmmanuel Vadot };
1002d2a0852SEmmanuel Vadot
1012d2a0852SEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
1022d2a0852SEmmanuel Vadot {"marvell,ap806-pinctrl", (uintptr_t)&ap806_padconf},
1032d2a0852SEmmanuel Vadot {NULL, 0}
1042d2a0852SEmmanuel Vadot };
1052d2a0852SEmmanuel Vadot
1064b84206bSMichal Meloun #define RD4(sc, reg) SYSCON_READ_4((sc)->syscon, (reg))
1074b84206bSMichal Meloun #define WR4(sc, reg, val) SYSCON_WRITE_4((sc)->syscon, (reg), (val))
1082d2a0852SEmmanuel Vadot
1092d2a0852SEmmanuel Vadot static void
mv_pinctrl_configure_pin(struct mv_pinctrl_softc * sc,uint32_t pin,uint32_t function)1102d2a0852SEmmanuel Vadot mv_pinctrl_configure_pin(struct mv_pinctrl_softc *sc, uint32_t pin,
1112d2a0852SEmmanuel Vadot uint32_t function)
1122d2a0852SEmmanuel Vadot {
1132d2a0852SEmmanuel Vadot uint32_t offset, shift, reg;
1142d2a0852SEmmanuel Vadot
1152d2a0852SEmmanuel Vadot offset = (pin / PINS_PER_REG) * BITS_PER_PIN;
1162d2a0852SEmmanuel Vadot shift = (pin % PINS_PER_REG) * BITS_PER_PIN;
1172d2a0852SEmmanuel Vadot reg = RD4(sc, offset);
1182d2a0852SEmmanuel Vadot reg &= ~(PINS_MASK << shift);
1192d2a0852SEmmanuel Vadot reg |= function << shift;
1202d2a0852SEmmanuel Vadot WR4(sc, offset, reg);
1212d2a0852SEmmanuel Vadot }
1222d2a0852SEmmanuel Vadot
1232d2a0852SEmmanuel Vadot static int
mv_pinctrl_configure_pins(device_t dev,phandle_t cfgxref)1242d2a0852SEmmanuel Vadot mv_pinctrl_configure_pins(device_t dev, phandle_t cfgxref)
1252d2a0852SEmmanuel Vadot {
1262d2a0852SEmmanuel Vadot struct mv_pinctrl_softc *sc;
1272d2a0852SEmmanuel Vadot phandle_t node;
1282d2a0852SEmmanuel Vadot char *function;
1292d2a0852SEmmanuel Vadot const char **pins;
1302d2a0852SEmmanuel Vadot int i, pin_num, pin_func, npins;
1312d2a0852SEmmanuel Vadot
1322d2a0852SEmmanuel Vadot sc = device_get_softc(dev);
1332d2a0852SEmmanuel Vadot node = OF_node_from_xref(cfgxref);
1342d2a0852SEmmanuel Vadot
1352d2a0852SEmmanuel Vadot if (OF_getprop_alloc(node, "marvell,function",
1362d2a0852SEmmanuel Vadot (void **)&function) == -1)
1372d2a0852SEmmanuel Vadot return (ENOMEM);
1382d2a0852SEmmanuel Vadot
1392d2a0852SEmmanuel Vadot npins = ofw_bus_string_list_to_array(node, "marvell,pins", &pins);
1402d2a0852SEmmanuel Vadot if (npins == -1)
1412d2a0852SEmmanuel Vadot return (ENOMEM);
1422d2a0852SEmmanuel Vadot
1432d2a0852SEmmanuel Vadot for (i = 0; i < npins; i++) {
1442d2a0852SEmmanuel Vadot for (pin_num = 0; pin_num < sc->padconf->npins; pin_num++) {
1452d2a0852SEmmanuel Vadot if (strcmp(pins[i], sc->padconf->pins[pin_num].name) == 0)
1462d2a0852SEmmanuel Vadot break;
1472d2a0852SEmmanuel Vadot }
1482d2a0852SEmmanuel Vadot if (pin_num == sc->padconf->npins)
1492d2a0852SEmmanuel Vadot continue;
1502d2a0852SEmmanuel Vadot
1512d2a0852SEmmanuel Vadot for (pin_func = 0; pin_func < MAX_PIN_FUNC; pin_func++)
1522d2a0852SEmmanuel Vadot if (sc->padconf->pins[pin_num].functions[pin_func] &&
1532d2a0852SEmmanuel Vadot strcmp(function, sc->padconf->pins[pin_num].functions[pin_func]) == 0)
1542d2a0852SEmmanuel Vadot break;
1552d2a0852SEmmanuel Vadot
1562d2a0852SEmmanuel Vadot if (pin_func == MAX_PIN_FUNC)
1572d2a0852SEmmanuel Vadot continue;
1582d2a0852SEmmanuel Vadot
1592d2a0852SEmmanuel Vadot mv_pinctrl_configure_pin(sc, pin_num, pin_func);
1602d2a0852SEmmanuel Vadot }
1612d2a0852SEmmanuel Vadot
1622d2a0852SEmmanuel Vadot OF_prop_free(pins);
1632d2a0852SEmmanuel Vadot
1642d2a0852SEmmanuel Vadot return (0);
1652d2a0852SEmmanuel Vadot }
1662d2a0852SEmmanuel Vadot
1672d2a0852SEmmanuel Vadot static int
mv_pinctrl_probe(device_t dev)1682d2a0852SEmmanuel Vadot mv_pinctrl_probe(device_t dev)
1692d2a0852SEmmanuel Vadot {
1702d2a0852SEmmanuel Vadot
1712d2a0852SEmmanuel Vadot if (!ofw_bus_status_okay(dev))
1722d2a0852SEmmanuel Vadot return (ENXIO);
1732d2a0852SEmmanuel Vadot
1742d2a0852SEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
1752d2a0852SEmmanuel Vadot return (ENXIO);
1762d2a0852SEmmanuel Vadot
1772d2a0852SEmmanuel Vadot device_set_desc(dev, "Marvell Pinctrl controller");
1782d2a0852SEmmanuel Vadot return (BUS_PROBE_DEFAULT);
1792d2a0852SEmmanuel Vadot }
1802d2a0852SEmmanuel Vadot
1812d2a0852SEmmanuel Vadot static int
mv_pinctrl_attach(device_t dev)1822d2a0852SEmmanuel Vadot mv_pinctrl_attach(device_t dev)
1832d2a0852SEmmanuel Vadot {
1842d2a0852SEmmanuel Vadot struct mv_pinctrl_softc *sc;
1852d2a0852SEmmanuel Vadot
1862d2a0852SEmmanuel Vadot sc = device_get_softc(dev);
1872d2a0852SEmmanuel Vadot sc->dev = dev;
1884b84206bSMichal Meloun sc->padconf = (struct mv_padconf *)
1894b84206bSMichal Meloun ofw_bus_search_compatible(dev,compat_data)->ocd_data;
1902d2a0852SEmmanuel Vadot
1914b84206bSMichal Meloun if (SYSCON_GET_HANDLE(sc->dev, &sc->syscon) != 0 ||
1924b84206bSMichal Meloun sc->syscon == NULL) {
1934b84206bSMichal Meloun device_printf(dev, "cannot get syscon for device\n");
1942d2a0852SEmmanuel Vadot return (ENXIO);
1952d2a0852SEmmanuel Vadot }
1962d2a0852SEmmanuel Vadot
1972d2a0852SEmmanuel Vadot fdt_pinctrl_register(dev, "marvell,pins");
1982d2a0852SEmmanuel Vadot fdt_pinctrl_configure_tree(dev);
1992d2a0852SEmmanuel Vadot
2002d2a0852SEmmanuel Vadot return (0);
2012d2a0852SEmmanuel Vadot }
2022d2a0852SEmmanuel Vadot
2032d2a0852SEmmanuel Vadot static int
mv_pinctrl_detach(device_t dev)2042d2a0852SEmmanuel Vadot mv_pinctrl_detach(device_t dev)
2052d2a0852SEmmanuel Vadot {
2062d2a0852SEmmanuel Vadot
2072d2a0852SEmmanuel Vadot return (EBUSY);
2082d2a0852SEmmanuel Vadot }
2092d2a0852SEmmanuel Vadot
2102d2a0852SEmmanuel Vadot static device_method_t mv_pinctrl_methods[] = {
2112d2a0852SEmmanuel Vadot /* Device interface */
2122d2a0852SEmmanuel Vadot DEVMETHOD(device_probe, mv_pinctrl_probe),
2132d2a0852SEmmanuel Vadot DEVMETHOD(device_attach, mv_pinctrl_attach),
2142d2a0852SEmmanuel Vadot DEVMETHOD(device_detach, mv_pinctrl_detach),
2152d2a0852SEmmanuel Vadot
2162d2a0852SEmmanuel Vadot /* fdt_pinctrl interface */
2172d2a0852SEmmanuel Vadot DEVMETHOD(fdt_pinctrl_configure,mv_pinctrl_configure_pins),
2182d2a0852SEmmanuel Vadot
2192d2a0852SEmmanuel Vadot DEVMETHOD_END
2202d2a0852SEmmanuel Vadot };
2212d2a0852SEmmanuel Vadot
2222d2a0852SEmmanuel Vadot static driver_t mv_pinctrl_driver = {
2232d2a0852SEmmanuel Vadot "mv_pinctrl",
2242d2a0852SEmmanuel Vadot mv_pinctrl_methods,
2252d2a0852SEmmanuel Vadot sizeof(struct mv_pinctrl_softc),
2262d2a0852SEmmanuel Vadot };
2272d2a0852SEmmanuel Vadot
228a3b866cbSJohn Baldwin EARLY_DRIVER_MODULE(mv_pinctrl, simplebus, mv_pinctrl_driver, 0, 0,
229a3b866cbSJohn Baldwin BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
230