imx_iomux.c revision 271591
1271550Sian/*- 2271550Sian * Copyright (c) 2014 Ian Lepore 3271550Sian * All rights reserved. 4271550Sian * 5271550Sian * Redistribution and use in source and binary forms, with or without 6271550Sian * modification, are permitted provided that the following conditions 7271550Sian * are met: 8271550Sian * 1. Redistributions of source code must retain the above copyright 9271550Sian * notice, this list of conditions and the following disclaimer. 10271550Sian * 2. Redistributions in binary form must reproduce the above copyright 11271550Sian * notice, this list of conditions and the following disclaimer in the 12271550Sian * documentation and/or other materials provided with the distribution. 13271550Sian * 14271550Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15271550Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16271550Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17271550Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18271550Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19271550Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20271550Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21271550Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22271550Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23271550Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24271550Sian * SUCH DAMAGE. 25271550Sian * 26271550Sian * $FreeBSD: head/sys/arm/freescale/imx/imx_iomux.c 271591 2014-09-14 16:12:43Z ian $ 27271550Sian */ 28271550Sian 29271591Sian/* 30271591Sian * Pin mux and pad control driver for imx5 and imx6. 31271591Sian * 32271591Sian * This driver implements the fdt_pinctrl interface for configuring the gpio and 33271591Sian * peripheral pins based on fdt configuration data. 34271591Sian * 35271591Sian * When the driver attaches, it walks the entire fdt tree and automatically 36271591Sian * configures the pins for each device which has a pinctrl-0 property and whose 37271591Sian * status is "okay". In addition it implements the fdt_pinctrl_configure() 38271591Sian * method which any other driver can call at any time to reconfigure its pins. 39271591Sian * 40271591Sian * The nature of the fsl,pins property in fdt data makes this driver's job very 41271591Sian * easy. Instead of representing each pin and pad configuration using symbolic 42271591Sian * properties such as pullup-enable="true" and so on, the data simply contains 43271591Sian * the addresses of the registers that control the pins, and the raw values to 44271591Sian * store in those registers. 45271591Sian * 46271591Sian * The imx5 and imx6 SoCs also have a small number of "general purpose 47271591Sian * registers" in the iomuxc device which are used to control an assortment 48271591Sian * of completely unrelated aspects of SoC behavior. This driver provides other 49271591Sian * drivers with direct access to those registers via simple accessor functions. 50271591Sian */ 51271591Sian 52271550Sian#include <sys/param.h> 53271550Sian#include <sys/systm.h> 54271550Sian#include <sys/bus.h> 55271550Sian#include <sys/kernel.h> 56271550Sian#include <sys/module.h> 57271550Sian#include <sys/malloc.h> 58271550Sian#include <sys/rman.h> 59271550Sian 60271550Sian#include <machine/bus.h> 61271550Sian#include <machine/fdt.h> 62271550Sian 63271550Sian#include <dev/fdt/fdt_common.h> 64271550Sian#include <dev/fdt/fdt_pinctrl.h> 65271550Sian#include <dev/ofw/openfirm.h> 66271550Sian#include <dev/ofw/ofw_bus.h> 67271550Sian#include <dev/ofw/ofw_bus_subr.h> 68271550Sian 69271550Sian#include <arm/freescale/imx/imx_iomuxvar.h> 70271550Sian#include <arm/freescale/imx/imx_machdep.h> 71271550Sian 72271550Sianstruct iomux_softc { 73271550Sian device_t dev; 74271550Sian struct resource *mem_res; 75271550Sian u_int last_gpreg; 76271550Sian}; 77271550Sian 78271550Sianstatic struct iomux_softc *iomux_sc; 79271550Sian 80271550Sianstatic struct ofw_compat_data compat_data[] = { 81271550Sian {"fsl,imx6dl-iomuxc", true}, 82271550Sian {"fsl,imx6q-iomuxc", true}, 83271550Sian {"fsl,imx6sl-iomuxc", true}, 84271550Sian {"fsl,imx6sx-iomuxc", true}, 85271550Sian {"fsl,imx53-iomuxc", true}, 86271550Sian {"fsl,imx51-iomuxc", true}, 87271550Sian {NULL, false}, 88271550Sian}; 89271550Sian 90271550Sian/* 91271550Sian * Each tuple in an fsl,pins property contains these fields. 92271550Sian */ 93271550Sianstruct pincfg { 94271550Sian uint32_t mux_reg; 95271550Sian uint32_t padconf_reg; 96271550Sian uint32_t input_reg; 97271550Sian uint32_t mux_val; 98271550Sian uint32_t input_val; 99271550Sian uint32_t padconf_val; 100271550Sian}; 101271550Sian 102271550Sianstatic inline uint32_t 103271550SianRD4(struct iomux_softc *sc, bus_size_t off) 104271550Sian{ 105271550Sian 106271550Sian return (bus_read_4(sc->mem_res, off)); 107271550Sian} 108271550Sian 109271550Sianstatic inline void 110271550SianWR4(struct iomux_softc *sc, bus_size_t off, uint32_t val) 111271550Sian{ 112271550Sian 113271550Sian bus_write_4(sc->mem_res, off, val); 114271550Sian} 115271550Sian 116271550Sianstatic int 117271550Sianiomux_configure_pins(device_t dev, phandle_t cfgxref) 118271550Sian{ 119271550Sian struct iomux_softc * sc; 120271550Sian struct pincfg *cfgtuples, *cfg; 121271550Sian phandle_t cfgnode; 122271550Sian int i, ntuples; 123271550Sian 124271550Sian sc = device_get_softc(dev); 125271550Sian cfgnode = OF_node_from_xref(cfgxref); 126271550Sian ntuples = OF_getencprop_alloc(cfgnode, "fsl,pins", sizeof(*cfgtuples), 127271550Sian (void **)&cfgtuples); 128271550Sian if (ntuples < 0) 129271550Sian return (ENOENT); 130271550Sian if (ntuples == 0) 131271550Sian return (0); /* Empty property is not an error. */ 132271550Sian for (i = 0, cfg = cfgtuples; i < ntuples; i++, cfg++) { 133271550Sian WR4(sc, cfg->mux_reg, cfg->mux_val); 134271550Sian WR4(sc, cfg->input_reg, cfg->input_val); 135271550Sian WR4(sc, cfg->padconf_reg, cfg->padconf_val); 136271550Sian } 137271550Sian free(cfgtuples, M_OFWPROP); 138271550Sian return (0); 139271550Sian} 140271550Sian 141271550Sianstatic int 142271550Sianiomux_probe(device_t dev) 143271550Sian{ 144271550Sian 145271550Sian if (!ofw_bus_status_okay(dev)) 146271550Sian return (ENXIO); 147271550Sian 148271550Sian if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 149271550Sian return (ENXIO); 150271550Sian 151271550Sian device_set_desc(dev, "Freescale i.MX pin configuration"); 152271550Sian return (BUS_PROBE_DEFAULT); 153271550Sian} 154271550Sian 155271550Sianstatic int 156271550Sianiomux_detach(device_t dev) 157271550Sian{ 158271550Sian 159271550Sian /* This device is always present. */ 160271550Sian return (EBUSY); 161271550Sian} 162271550Sian 163271550Sianstatic int 164271550Sianiomux_attach(device_t dev) 165271550Sian{ 166271550Sian struct iomux_softc * sc; 167271550Sian int rid; 168271550Sian 169271550Sian sc = device_get_softc(dev); 170271550Sian sc->dev = dev; 171271550Sian 172271550Sian switch (imx_soc_type()) { 173271550Sian case IMXSOC_51: 174271550Sian sc->last_gpreg = 1; 175271550Sian break; 176271550Sian case IMXSOC_53: 177271550Sian sc->last_gpreg = 2; 178271550Sian break; 179271550Sian case IMXSOC_6DL: 180271550Sian case IMXSOC_6S: 181271550Sian case IMXSOC_6SL: 182271550Sian case IMXSOC_6Q: 183271550Sian sc->last_gpreg = 13; 184271550Sian break; 185271550Sian default: 186271550Sian device_printf(dev, "Unknown SoC type\n"); 187271550Sian return (ENXIO); 188271550Sian } 189271550Sian 190271550Sian rid = 0; 191271550Sian sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 192271550Sian RF_ACTIVE); 193271550Sian if (sc->mem_res == NULL) { 194271550Sian device_printf(dev, "Cannot allocate memory resources\n"); 195271550Sian return (ENXIO); 196271550Sian } 197271550Sian 198271550Sian iomux_sc = sc; 199271550Sian 200271550Sian /* 201271550Sian * Register as a pinctrl device, and call the convenience function that 202271550Sian * walks the entire device tree invoking FDT_PINCTRL_CONFIGURE() on any 203271550Sian * pinctrl-0 property cells whose xref phandle refers to a configuration 204271550Sian * that is a child node of our node in the tree. 205271550Sian * 206271550Sian * The pinctrl bindings documentation specifically mentions that the 207271550Sian * pinctrl device itself may have a pinctrl-0 property which contains 208271550Sian * static configuration to be applied at device init time. The tree 209271550Sian * walk will automatically handle this for us when it passes through our 210271550Sian * node in the tree. 211271550Sian */ 212271550Sian fdt_pinctrl_register(dev, "fsl,pins"); 213271550Sian fdt_pinctrl_configure_tree(dev); 214271550Sian 215271550Sian return (0); 216271550Sian} 217271550Sian 218271550Sianuint32_t 219271550Sianimx_iomux_gpr_get(u_int regnum) 220271550Sian{ 221271550Sian struct iomux_softc * sc; 222271550Sian 223271550Sian sc = iomux_sc; 224271550Sian KASSERT(sc != NULL, ("%s called before attach", __FUNCTION__)); 225271550Sian KASSERT(regnum >= 0 && regnum <= sc->last_gpreg, 226271550Sian ("%s bad regnum %u, max %u", __FUNCTION__, regnum, sc->last_gpreg)); 227271550Sian 228271550Sian return (RD4(iomux_sc, regnum * 4)); 229271550Sian} 230271550Sian 231271550Sianvoid 232271550Sianimx_iomux_gpr_set(u_int regnum, uint32_t val) 233271550Sian{ 234271550Sian struct iomux_softc * sc; 235271550Sian 236271550Sian sc = iomux_sc; 237271550Sian KASSERT(sc != NULL, ("%s called before attach", __FUNCTION__)); 238271550Sian KASSERT(regnum >= 0 && regnum <= sc->last_gpreg, 239271550Sian ("%s bad regnum %u, max %u", __FUNCTION__, regnum, sc->last_gpreg)); 240271550Sian 241271550Sian WR4(iomux_sc, regnum * 4, val); 242271550Sian} 243271550Sian 244271550Sianvoid 245271550Sianimx_iomux_gpr_set_masked(u_int regnum, uint32_t clrbits, uint32_t setbits) 246271550Sian{ 247271550Sian struct iomux_softc * sc; 248271550Sian uint32_t val; 249271550Sian 250271550Sian sc = iomux_sc; 251271550Sian KASSERT(sc != NULL, ("%s called before attach", __FUNCTION__)); 252271550Sian KASSERT(regnum >= 0 && regnum <= sc->last_gpreg, 253271550Sian ("%s bad regnum %u, max %u", __FUNCTION__, regnum, sc->last_gpreg)); 254271550Sian 255271550Sian val = RD4(iomux_sc, regnum * 4); 256271550Sian val = (val & ~clrbits) | setbits; 257271550Sian WR4(iomux_sc, regnum * 4, val); 258271550Sian} 259271550Sian 260271550Sianstatic device_method_t imx_iomux_methods[] = { 261271550Sian /* Device interface */ 262271550Sian DEVMETHOD(device_probe, iomux_probe), 263271550Sian DEVMETHOD(device_attach, iomux_attach), 264271550Sian DEVMETHOD(device_detach, iomux_detach), 265271550Sian 266271550Sian /* fdt_pinctrl interface */ 267271550Sian DEVMETHOD(fdt_pinctrl_configure,iomux_configure_pins), 268271550Sian 269271550Sian DEVMETHOD_END 270271550Sian}; 271271550Sian 272271550Sianstatic driver_t imx_iomux_driver = { 273271550Sian "imx_iomux", 274271550Sian imx_iomux_methods, 275271550Sian sizeof(struct iomux_softc), 276271550Sian}; 277271550Sian 278271550Sianstatic devclass_t imx_iomux_devclass; 279271550Sian 280271550SianEARLY_DRIVER_MODULE(imx_iomux, simplebus, imx_iomux_driver, 281271550Sian imx_iomux_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_LATE); 282271550Sian 283