1193323Sed/*- 2193323Sed * Copyright (c) 2013 Ian Lepore <ian@freebsd.org> 3193323Sed * All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8193323Sed * 1. Redistributions of source code must retain the above copyright 9193323Sed * notice, this list of conditions and the following disclaimer. 10193323Sed * 2. Redistributions in binary form must reproduce the above copyright 11193323Sed * notice, this list of conditions and the following disclaimer in the 12193323Sed * documentation and/or other materials provided with the distribution. 13193323Sed * 14193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24193323Sed * SUCH DAMAGE. 25193323Sed */ 26193323Sed 27193323Sed#include <sys/cdefs.h> 28193323Sed__FBSDID("$FreeBSD$"); 29193323Sed 30193323Sed/* 31193323Sed * USBPHY driver for Freescale i.MX6 family of SoCs. 32193323Sed */ 33193323Sed 34193323Sed#include "opt_bus.h" 35193323Sed 36193323Sed#include <sys/param.h> 37193323Sed#include <sys/systm.h> 38193323Sed#include <sys/kernel.h> 39193323Sed#include <sys/module.h> 40193323Sed#include <sys/bus.h> 41193323Sed#include <sys/rman.h> 42193323Sed 43193323Sed#include <dev/ofw/ofw_bus.h> 44193323Sed#include <dev/ofw/ofw_bus_subr.h> 45193323Sed 46193323Sed#include <machine/bus.h> 47193323Sed 48193323Sed#include <arm/freescale/imx/imx_ccmvar.h> 49193323Sed#include <arm/freescale/imx/imx6_anatopreg.h> 50193323Sed#include <arm/freescale/imx/imx6_anatopvar.h> 51193323Sed 52193323Sed/* 53193323Sed * Hardware register defines. 54193323Sed */ 55193323Sed#define PWD_REG 0x0000 56193323Sed#define CTRL_STATUS_REG 0x0030 57193323Sed#define CTRL_SET_REG 0x0034 58193323Sed#define CTRL_CLR_REG 0x0038 59193323Sed#define CTRL_TOGGLE_REG 0x003c 60193323Sed#define CTRL_SFTRST (1U << 31) 61193323Sed#define CTRL_CLKGATE (1 << 30) 62193323Sed#define CTRL_ENUTMILEVEL3 (1 << 15) 63193323Sed#define CTRL_ENUTMILEVEL2 (1 << 14) 64193323Sed 65193323Sedstruct usbphy_softc { 66193323Sed device_t dev; 67193323Sed struct resource *mem_res; 68193323Sed u_int phy_num; 69193323Sed}; 70193323Sed 71193323Sedstatic int 72193323Sedusbphy_detach(device_t dev) 73193323Sed{ 74193323Sed struct usbphy_softc *sc; 75193323Sed 76193323Sed sc = device_get_softc(dev); 77193323Sed 78193323Sed if (sc->mem_res != NULL) 79193323Sed bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 80193323Sed 81193323Sed return (0); 82193323Sed} 83193323Sed 84193323Sedstatic int 85193323Sedusbphy_attach(device_t dev) 86193323Sed{ 87193323Sed struct usbphy_softc *sc; 88193323Sed int err, regoff, rid; 89193323Sed 90193323Sed sc = device_get_softc(dev); 91193323Sed err = 0; 92193323Sed 93193323Sed /* Allocate bus_space resources. */ 94193323Sed rid = 0; 95193323Sed sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 96193323Sed RF_ACTIVE); 97193323Sed if (sc->mem_res == NULL) { 98193323Sed device_printf(dev, "Cannot allocate memory resources\n"); 99193323Sed err = ENXIO; 100193323Sed goto out; 101193323Sed } 102193323Sed 103193323Sed /* 104193323Sed * XXX Totally lame way to get the unit number (but not quite as lame as 105193323Sed * adding an ad-hoc property to the fdt data). This works as long as 106193323Sed * this driver is used for imx6 only. 107193323Sed */ 108193323Sed const uint32_t PWD_PHY1_REG_PHYSADDR = 0x020c9000; 109193323Sed if (BUS_SPACE_PHYSADDR(sc->mem_res, 0) == PWD_PHY1_REG_PHYSADDR) { 110193323Sed sc->phy_num = 0; 111193323Sed regoff = 0; 112193323Sed } else { 113193323Sed sc->phy_num = 1; 114193323Sed regoff = 0x60; 115193323Sed } 116193323Sed 117193323Sed /* 118193323Sed * Based on a note in the u-boot source code, disable charger detection 119193323Sed * to avoid degrading the differential signaling on the DP line. Note 120193323Sed * that this disables (by design) both charger detection and contact 121193323Sed * detection, because of the screwball mix of active-high and active-low 122193323Sed * bits in this register. 123193323Sed */ 124193323Sed imx6_anatop_write_4(IMX6_ANALOG_USB1_CHRG_DETECT + regoff, 125193323Sed IMX6_ANALOG_USB_CHRG_DETECT_N_ENABLE | 126193323Sed IMX6_ANALOG_USB_CHRG_DETECT_N_CHK_CHRG); 127193323Sed 128193323Sed imx6_anatop_write_4(IMX6_ANALOG_USB1_CHRG_DETECT + regoff, 129193323Sed IMX6_ANALOG_USB_CHRG_DETECT_N_ENABLE | 130193323Sed IMX6_ANALOG_USB_CHRG_DETECT_N_CHK_CHRG); 131193323Sed 132193323Sed /* XXX Configure the overcurrent detection here. */ 133193323Sed 134193323Sed /* 135193323Sed * Turn on the phy clocks. 136193323Sed */ 137193323Sed imx_ccm_usbphy_enable(dev); 138193323Sed 139193323Sed /* 140193323Sed * Set the software reset bit, then clear both it and the clock gate bit 141193323Sed * to bring the device out of reset with the clock running. 142193323Sed */ 143193323Sed bus_write_4(sc->mem_res, CTRL_SET_REG, CTRL_SFTRST); 144193323Sed bus_write_4(sc->mem_res, CTRL_CLR_REG, CTRL_SFTRST | CTRL_CLKGATE); 145193323Sed 146193323Sed /* Power up: clear all bits in the powerdown register. */ 147193323Sed bus_write_4(sc->mem_res, PWD_REG, 0); 148193323Sed 149193323Sed err = 0; 150193323Sed 151out: 152 153 if (err != 0) 154 usbphy_detach(dev); 155 156 return (err); 157} 158 159static int 160usbphy_probe(device_t dev) 161{ 162 163 if (!ofw_bus_status_okay(dev)) 164 return (ENXIO); 165 166 if (ofw_bus_is_compatible(dev, "fsl,imx6q-usbphy") == 0) 167 return (ENXIO); 168 169 device_set_desc(dev, "Freescale i.MX6 USB PHY"); 170 171 return (BUS_PROBE_DEFAULT); 172} 173 174static device_method_t usbphy_methods[] = { 175 /* Device interface */ 176 DEVMETHOD(device_probe, usbphy_probe), 177 DEVMETHOD(device_attach, usbphy_attach), 178 DEVMETHOD(device_detach, usbphy_detach), 179 180 DEVMETHOD_END 181}; 182 183static driver_t usbphy_driver = { 184 "usbphy", 185 usbphy_methods, 186 sizeof(struct usbphy_softc) 187}; 188 189static devclass_t usbphy_devclass; 190 191DRIVER_MODULE(usbphy, simplebus, usbphy_driver, usbphy_devclass, 0, 0); 192 193