1*34bd263dSskrll /* $NetBSD: imx6_iomux.c,v 1.4 2025/01/19 07:13:20 skrll Exp $ */ 28644267aSskrll 38644267aSskrll /*- 48644267aSskrll * Copyright (c) 2019 Genetec Corporation. All rights reserved. 58644267aSskrll * Written by Hashimoto Kenichi for Genetec Corporation. 68644267aSskrll * 78644267aSskrll * Redistribution and use in source and binary forms, with or without 88644267aSskrll * modification, are permitted provided that the following conditions 98644267aSskrll * are met: 108644267aSskrll * 1. Redistributions of source code must retain the above copyright 118644267aSskrll * notice, this list of conditions and the following disclaimer. 128644267aSskrll * 2. Redistributions in binary form must reproduce the above copyright 138644267aSskrll * notice, this list of conditions and the following disclaimer in the 148644267aSskrll * documentation and/or other materials provided with the distribution. 158644267aSskrll * 168644267aSskrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 178644267aSskrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 188644267aSskrll * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 198644267aSskrll * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 208644267aSskrll * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 218644267aSskrll * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 228644267aSskrll * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 238644267aSskrll * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 248644267aSskrll * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 258644267aSskrll * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 268644267aSskrll * SUCH DAMAGE. 278644267aSskrll */ 288644267aSskrll 298644267aSskrll #include <sys/cdefs.h> 30*34bd263dSskrll __KERNEL_RCSID(0, "$NetBSD: imx6_iomux.c,v 1.4 2025/01/19 07:13:20 skrll Exp $"); 318644267aSskrll 328644267aSskrll #include "opt_fdt.h" 338644267aSskrll 348644267aSskrll #include <sys/param.h> 358644267aSskrll #include <sys/bus.h> 368644267aSskrll #include <sys/device.h> 378644267aSskrll 388644267aSskrll #include <arm/nxp/imx6_iomuxreg.h> 398644267aSskrll 408644267aSskrll #include <dev/fdt/fdtvar.h> 418644267aSskrll 428644267aSskrll struct imxiomux_softc { 438644267aSskrll device_t sc_dev; 448644267aSskrll 458644267aSskrll bus_space_tag_t sc_iot; 468644267aSskrll bus_space_handle_t sc_ioh; 478644267aSskrll 488644267aSskrll int sc_phandle; 498644267aSskrll }; 508644267aSskrll 518644267aSskrll #define CONFIG_NO_PAD_CTL __BIT(31) 528644267aSskrll #define CONFIG_SION __BIT(30) 538644267aSskrll 548644267aSskrll static int 558644267aSskrll imx6_pinctrl_set_config(device_t dev, const void *data, size_t len) 568644267aSskrll { 578644267aSskrll struct imxiomux_softc * const sc = device_private(dev); 588644267aSskrll int pins_len; 598644267aSskrll uint32_t reg; 608644267aSskrll 618644267aSskrll if (len != 4) 628644267aSskrll return -1; 638644267aSskrll 648644267aSskrll const int phandle = fdtbus_get_phandle_from_native(be32dec(data)); 658644267aSskrll const u_int *pins = fdtbus_get_prop(phandle, "fsl,pins", &pins_len); 668644267aSskrll 678644267aSskrll aprint_debug_dev(sc->sc_dev, "name %s\n", fdtbus_get_string(phandle, "name")); 688644267aSskrll while (pins_len >= 24) { 698644267aSskrll u_int mux_reg = be32toh(pins[0]); 708644267aSskrll u_int conf_reg = be32toh(pins[1]); 718644267aSskrll u_int input_reg = be32toh(pins[2]); 728644267aSskrll u_int mux_mode = be32toh(pins[3]); 738644267aSskrll u_int input_val = be32toh(pins[4]); 748644267aSskrll u_int config = be32toh(pins[5]); 758644267aSskrll 768644267aSskrll if (config & CONFIG_SION) 778644267aSskrll mux_mode |= IOMUX_CONFIG_SION; 788644267aSskrll config &= ~CONFIG_SION; 798644267aSskrll 808644267aSskrll reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, mux_reg); 818644267aSskrll bus_space_write_4(sc->sc_iot, sc->sc_ioh, mux_reg, mux_mode); 828644267aSskrll aprint_debug_dev(sc->sc_dev, 838644267aSskrll "mux offset 0x%08x, val 0x%08x -> 0x%08x\n", 848644267aSskrll mux_reg, reg, mux_mode); 858644267aSskrll 868644267aSskrll if (!(config & CONFIG_NO_PAD_CTL)) { 878644267aSskrll reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, conf_reg); 888644267aSskrll bus_space_write_4(sc->sc_iot, sc->sc_ioh, conf_reg, config); 898644267aSskrll aprint_debug_dev(sc->sc_dev, 908644267aSskrll "config offset 0x%08x, val 0x%08x -> 0x%08x\n", 918644267aSskrll conf_reg, reg, config); 928644267aSskrll } 938644267aSskrll 948644267aSskrll if (__SHIFTOUT(input_val, __BITS(31, 24)) == 0xff) { 958644267aSskrll uint8_t sel = __SHIFTOUT(input_val, __BITS(7, 0)); 968644267aSskrll uint8_t width = __SHIFTOUT(input_val, __BITS(15, 8)); 978644267aSskrll uint8_t shift = __SHIFTOUT(input_val, __BITS(23, 16)); 988644267aSskrll uint32_t mask = __BITS(shift + (width - 1), shift); 998644267aSskrll 1008644267aSskrll reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, input_reg); 1018644267aSskrll reg &= ~mask; 1028644267aSskrll reg |= __SHIFTIN(sel, mask); 1038644267aSskrll bus_space_write_4(sc->sc_iot, sc->sc_ioh, input_reg, reg); 1048644267aSskrll aprint_debug_dev(sc->sc_dev, 1058644267aSskrll "+input offset 0x%08x, val 0x%08x\n", 1068644267aSskrll input_reg, reg); 1078644267aSskrll } else if (input_reg != 0) { 1088644267aSskrll reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, input_reg); 1098644267aSskrll bus_space_write_4(sc->sc_iot, sc->sc_ioh, input_reg, input_val); 1108644267aSskrll aprint_debug_dev(sc->sc_dev, 1118644267aSskrll "input offset 0x%08x, val 0x%08x -> 0x%08x\n", 1128644267aSskrll input_reg, reg, input_val); 1138644267aSskrll } 1148644267aSskrll 1158644267aSskrll pins_len -= 24; 1168644267aSskrll pins += 6; 1178644267aSskrll } 1188644267aSskrll 1198644267aSskrll return 0; 1208644267aSskrll } 1218644267aSskrll 1228644267aSskrll static struct fdtbus_pinctrl_controller_func imx6_pinctrl_funcs = { 1238644267aSskrll .set_config = imx6_pinctrl_set_config, 1248644267aSskrll }; 1258644267aSskrll 1268644267aSskrll static int imxiomux_match(device_t, struct cfdata *, void *); 1278644267aSskrll static void imxiomux_attach(device_t, device_t, void *); 1288644267aSskrll 1298644267aSskrll CFATTACH_DECL_NEW(imxiomux, sizeof(struct imxiomux_softc), 1308644267aSskrll imxiomux_match, imxiomux_attach, NULL, NULL); 1318644267aSskrll 1326e54367aSthorpej static const struct device_compatible_entry compat_data[] = { 133*34bd263dSskrll { .compat = "fsl,imx6dl-iomuxc" }, 1346e54367aSthorpej { .compat = "fsl,imx6q-iomuxc" }, 135a33a6c43Sbouyer { .compat = "fsl,imx6sx-iomuxc" }, 1366e54367aSthorpej { .compat = "fsl,imx7d-iomuxc" }, 1376e54367aSthorpej { .compat = "fsl,imx8mq-iomuxc" }, 1386e54367aSthorpej DEVICE_COMPAT_EOL 1396e54367aSthorpej }; 1406e54367aSthorpej 1418644267aSskrll static int 1428644267aSskrll imxiomux_match(device_t parent, cfdata_t cf, void *aux) 1438644267aSskrll { 1448644267aSskrll struct fdt_attach_args * const faa = aux; 1458644267aSskrll 1466e54367aSthorpej return of_compatible_match(faa->faa_phandle, compat_data); 1478644267aSskrll } 1488644267aSskrll 1498644267aSskrll static void 1508644267aSskrll imxiomux_attach(device_t parent, device_t self, void *aux) 1518644267aSskrll { 1528644267aSskrll struct imxiomux_softc * const sc = device_private(self); 1538644267aSskrll struct fdt_attach_args * const faa = aux; 1548644267aSskrll const int phandle = faa->faa_phandle; 1558644267aSskrll bus_addr_t addr; 1568644267aSskrll bus_size_t size; 1578644267aSskrll int error; 1588644267aSskrll 1598644267aSskrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 1608644267aSskrll aprint_error(": couldn't get iomux registers\n"); 1618644267aSskrll return; 1628644267aSskrll } 1638644267aSskrll 1648644267aSskrll sc->sc_dev = self; 1658644267aSskrll sc->sc_iot = faa->faa_bst; 1668644267aSskrll 1678644267aSskrll error = bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh); 1688644267aSskrll if (error) { 1698644267aSskrll aprint_error(": couldn't map iomux registers: %d\n", error); 1708644267aSskrll return; 1718644267aSskrll } 1728644267aSskrll 1738644267aSskrll aprint_naive("\n"); 1748644267aSskrll aprint_normal(": IOMUX Controller\n"); 1758644267aSskrll 1768644267aSskrll for (int child = OF_child(phandle); child; child = OF_peer(child)) { 1778644267aSskrll if (of_hasprop(child, "fsl,pins")) { 1788644267aSskrll fdtbus_register_pinctrl_config(self, child, &imx6_pinctrl_funcs); 1798644267aSskrll } else { 1808644267aSskrll for (int sub = OF_child(child); sub; sub = OF_peer(sub)) { 1818644267aSskrll if (!of_hasprop(sub, "fsl,pins")) 1828644267aSskrll continue; 1838644267aSskrll fdtbus_register_pinctrl_config(self, sub, &imx6_pinctrl_funcs); 1848644267aSskrll } 1858644267aSskrll } 1868644267aSskrll } 1878644267aSskrll } 1888644267aSskrll 189