1258057Sbr/*- 2266146Sian * Copyright (c) 2013-2014 Ruslan Bukin <br@bsdpad.com> 3258057Sbr * All rights reserved. 4258057Sbr * 5258057Sbr * Redistribution and use in source and binary forms, with or without 6258057Sbr * modification, are permitted provided that the following conditions 7258057Sbr * are met: 8258057Sbr * 1. Redistributions of source code must retain the above copyright 9258057Sbr * notice, this list of conditions and the following disclaimer. 10258057Sbr * 2. Redistributions in binary form must reproduce the above copyright 11258057Sbr * notice, this list of conditions and the following disclaimer in the 12258057Sbr * documentation and/or other materials provided with the distribution. 13258057Sbr * 14258057Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15258057Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16258057Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17258057Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18258057Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19258057Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20258057Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21258057Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22258057Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23258057Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24258057Sbr * SUCH DAMAGE. 25258057Sbr */ 26258057Sbr 27258057Sbr/* 28258057Sbr * Vybrid Family Input/Output Multiplexer Controller (IOMUXC) 29258057Sbr * Chapter 5, Vybrid Reference Manual, Rev. 5, 07/2013 30258057Sbr */ 31258057Sbr 32258057Sbr#include <sys/cdefs.h> 33258057Sbr__FBSDID("$FreeBSD$"); 34258057Sbr 35258057Sbr#include <sys/param.h> 36258057Sbr#include <sys/systm.h> 37258057Sbr#include <sys/bus.h> 38258057Sbr#include <sys/kernel.h> 39258057Sbr#include <sys/module.h> 40258057Sbr#include <sys/malloc.h> 41258057Sbr#include <sys/rman.h> 42258057Sbr#include <sys/timeet.h> 43258057Sbr#include <sys/timetc.h> 44258057Sbr#include <sys/watchdog.h> 45258057Sbr 46258057Sbr#include <dev/fdt/fdt_common.h> 47258057Sbr#include <dev/ofw/openfirm.h> 48258057Sbr#include <dev/ofw/ofw_bus.h> 49258057Sbr#include <dev/ofw/ofw_bus_subr.h> 50258057Sbr 51258057Sbr#include <machine/bus.h> 52258057Sbr#include <machine/fdt.h> 53258057Sbr#include <machine/cpu.h> 54258057Sbr#include <machine/intr.h> 55258057Sbr 56258057Sbr#include <arm/freescale/vybrid/vf_iomuxc.h> 57258057Sbr#include <arm/freescale/vybrid/vf_common.h> 58258057Sbr 59258057Sbr#define MUX_MODE_MASK 7 60258057Sbr#define MUX_MODE_SHIFT 20 61258057Sbr#define MUX_MODE_GPIO 0 62258057Sbr#define MUX_MODE_VBUS_EN_OTG 2 63258057Sbr 64266203Sian#define IBE (1 << 0) /* Input Buffer Enable Field */ 65266203Sian#define OBE (1 << 1) /* Output Buffer Enable Field. */ 66266203Sian#define PUE (1 << 2) /* Pull / Keep Select Field. */ 67266203Sian#define PKE (1 << 3) /* Pull / Keep Enable Field. */ 68266203Sian#define HYS (1 << 9) /* Hysteresis Enable Field */ 69266203Sian#define ODE (1 << 10) /* Open Drain Enable Field. */ 70266203Sian#define SRE (1 << 11) /* Slew Rate Field. */ 71258057Sbr 72266203Sian#define SPEED_SHIFT 12 73266203Sian#define SPEED_MASK 0x3 74266203Sian#define SPEED_LOW 0 /* 50 MHz */ 75266203Sian#define SPEED_MEDIUM 0x1 /* 100 MHz */ 76266203Sian#define SPEED_HIGH 0x3 /* 200 MHz */ 77266203Sian 78266203Sian#define PUS_SHIFT 4 /* Pull Up / Down Config Field Shift */ 79266203Sian#define PUS_MASK 0x3 80266203Sian#define PUS_100_KOHM_PULL_DOWN 0 81266203Sian#define PUS_47_KOHM_PULL_UP 0x1 82266203Sian#define PUS_100_KOHM_PULL_UP 0x2 83266203Sian#define PUS_22_KOHM_PULL_UP 0x3 84266203Sian 85266203Sian#define DSE_SHIFT 6 /* Drive Strength Field Shift */ 86266203Sian#define DSE_MASK 0x7 87266203Sian#define DSE_DISABLED 0 /* Output driver disabled */ 88266203Sian#define DSE_150_OHM 0x1 89266203Sian#define DSE_75_OHM 0x2 90266203Sian#define DSE_50_OHM 0x3 91266203Sian#define DSE_37_OHM 0x4 92266203Sian#define DSE_30_OHM 0x5 93266203Sian#define DSE_25_OHM 0x6 94266203Sian#define DSE_20_OHM 0x7 95266203Sian 96266146Sian#define MAX_MUX_LEN 1024 97258057Sbr 98258057Sbrstruct iomuxc_softc { 99258057Sbr struct resource *tmr_res[1]; 100258057Sbr bus_space_tag_t bst; 101258057Sbr bus_space_handle_t bsh; 102258057Sbr device_t dev; 103258057Sbr}; 104258057Sbr 105258057Sbrstatic struct resource_spec iomuxc_spec[] = { 106258057Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 107258057Sbr { -1, 0 } 108258057Sbr}; 109258057Sbr 110258057Sbrstatic int 111258057Sbriomuxc_probe(device_t dev) 112258057Sbr{ 113258057Sbr 114266152Sian if (!ofw_bus_status_okay(dev)) 115266152Sian return (ENXIO); 116266152Sian 117258057Sbr if (!ofw_bus_is_compatible(dev, "fsl,mvf600-iomuxc")) 118258057Sbr return (ENXIO); 119258057Sbr 120258057Sbr device_set_desc(dev, "Vybrid Family IOMUXC Unit"); 121258057Sbr return (BUS_PROBE_DEFAULT); 122258057Sbr} 123258057Sbr 124258057Sbrstatic int 125266146Sianpinmux_set(struct iomuxc_softc *sc) 126266146Sian{ 127266146Sian phandle_t child, parent, root; 128266146Sian pcell_t iomux_config[MAX_MUX_LEN]; 129266146Sian int len; 130266146Sian int values; 131266146Sian int pin; 132266203Sian int pin_cfg; 133266146Sian int i; 134266146Sian 135266146Sian root = OF_finddevice("/"); 136266146Sian len = 0; 137266146Sian parent = root; 138266146Sian 139266146Sian /* Find 'iomux_config' prop in the nodes */ 140266146Sian for (child = OF_child(parent); child != 0; child = OF_peer(child)) { 141266146Sian 142266146Sian /* Find a 'leaf'. Start the search from this node. */ 143266146Sian while (OF_child(child)) { 144266146Sian parent = child; 145266146Sian child = OF_child(child); 146266146Sian } 147266146Sian 148266146Sian if (!fdt_is_enabled(child)) 149266146Sian continue; 150266146Sian 151266146Sian if ((len = OF_getproplen(child, "iomux_config")) > 0) { 152266146Sian OF_getprop(child, "iomux_config", &iomux_config, len); 153266146Sian 154266146Sian values = len / (sizeof(uint32_t)); 155266146Sian for (i = 0; i < values; i += 2) { 156266146Sian pin = fdt32_to_cpu(iomux_config[i]); 157266203Sian pin_cfg = fdt32_to_cpu(iomux_config[i+1]); 158266146Sian#if 0 159266203Sian device_printf(sc->dev, "Set pin %d to 0x%08x\n", 160266203Sian pin, pin_cfg); 161266146Sian#endif 162266203Sian WRITE4(sc, IOMUXC(pin), pin_cfg); 163266146Sian } 164266146Sian } 165266146Sian 166266146Sian if (OF_peer(child) == 0) { 167266146Sian /* No more siblings. */ 168266146Sian child = parent; 169266146Sian parent = OF_parent(child); 170266146Sian } 171266146Sian } 172266146Sian 173266146Sian return (0); 174266146Sian} 175266146Sian 176266146Sianstatic int 177258057Sbriomuxc_attach(device_t dev) 178258057Sbr{ 179258057Sbr struct iomuxc_softc *sc; 180258057Sbr 181258057Sbr sc = device_get_softc(dev); 182258057Sbr sc->dev = dev; 183258057Sbr 184258057Sbr if (bus_alloc_resources(dev, iomuxc_spec, sc->tmr_res)) { 185258057Sbr device_printf(dev, "could not allocate resources\n"); 186258057Sbr return (ENXIO); 187258057Sbr } 188258057Sbr 189258057Sbr /* Memory interface */ 190258057Sbr sc->bst = rman_get_bustag(sc->tmr_res[0]); 191258057Sbr sc->bsh = rman_get_bushandle(sc->tmr_res[0]); 192258057Sbr 193266146Sian pinmux_set(sc); 194258057Sbr 195258057Sbr return (0); 196258057Sbr} 197258057Sbr 198258057Sbrstatic device_method_t iomuxc_methods[] = { 199258057Sbr DEVMETHOD(device_probe, iomuxc_probe), 200258057Sbr DEVMETHOD(device_attach, iomuxc_attach), 201258057Sbr { 0, 0 } 202258057Sbr}; 203258057Sbr 204258057Sbrstatic driver_t iomuxc_driver = { 205258057Sbr "iomuxc", 206258057Sbr iomuxc_methods, 207258057Sbr sizeof(struct iomuxc_softc), 208258057Sbr}; 209258057Sbr 210258057Sbrstatic devclass_t iomuxc_devclass; 211258057Sbr 212258057SbrDRIVER_MODULE(iomuxc, simplebus, iomuxc_driver, iomuxc_devclass, 0, 0); 213