Path: blob/main/sys/arm/freescale/imx/imx6_usbphy.c
39536 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2013 Ian Lepore <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/cdefs.h>29/*30* USBPHY driver for Freescale i.MX6 family of SoCs.31*/3233#include "opt_bus.h"3435#include <sys/param.h>36#include <sys/systm.h>37#include <sys/kernel.h>38#include <sys/module.h>39#include <sys/bus.h>40#include <sys/rman.h>4142#include <dev/ofw/ofw_bus.h>43#include <dev/ofw/ofw_bus_subr.h>4445#include <machine/bus.h>4647#include <arm/freescale/imx/imx_ccmvar.h>48#include <arm/freescale/imx/imx6_anatopreg.h>49#include <arm/freescale/imx/imx6_anatopvar.h>5051/*52* Hardware register defines.53*/54#define PWD_REG 0x000055#define CTRL_STATUS_REG 0x003056#define CTRL_SET_REG 0x003457#define CTRL_CLR_REG 0x003858#define CTRL_TOGGLE_REG 0x003c59#define CTRL_SFTRST (1U << 31)60#define CTRL_CLKGATE (1 << 30)61#define CTRL_ENUTMILEVEL3 (1 << 15)62#define CTRL_ENUTMILEVEL2 (1 << 14)6364struct usbphy_softc {65device_t dev;66struct resource *mem_res;67u_int phy_num;68};6970static struct ofw_compat_data compat_data[] = {71{"fsl,imx6q-usbphy", true},72{"fsl,imx6ul-usbphy", true},73{NULL, false}74};7576static int77usbphy_detach(device_t dev)78{79struct usbphy_softc *sc;8081sc = device_get_softc(dev);8283if (sc->mem_res != NULL)84bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);8586return (0);87}8889static int90usbphy_attach(device_t dev)91{92struct usbphy_softc *sc;93int err, regoff, rid;9495sc = device_get_softc(dev);96err = 0;9798/* Allocate bus_space resources. */99rid = 0;100sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,101RF_ACTIVE);102if (sc->mem_res == NULL) {103device_printf(dev, "Cannot allocate memory resources\n");104err = ENXIO;105goto out;106}107108/*109* XXX Totally lame way to get the unit number (but not quite as lame as110* adding an ad-hoc property to the fdt data). This works as long as111* this driver is used for imx6 only.112*/113const uint32_t PWD_PHY1_REG_PHYSADDR = 0x020c9000;114if (BUS_SPACE_PHYSADDR(sc->mem_res, 0) == PWD_PHY1_REG_PHYSADDR) {115sc->phy_num = 0;116regoff = 0;117} else {118sc->phy_num = 1;119regoff = 0x60;120}121122/*123* Based on a note in the u-boot source code, disable charger detection124* to avoid degrading the differential signaling on the DP line. Note125* that this disables (by design) both charger detection and contact126* detection, because of the screwball mix of active-high and active-low127* bits in this register.128*/129imx6_anatop_write_4(IMX6_ANALOG_USB1_CHRG_DETECT + regoff,130IMX6_ANALOG_USB_CHRG_DETECT_N_ENABLE |131IMX6_ANALOG_USB_CHRG_DETECT_N_CHK_CHRG);132133imx6_anatop_write_4(IMX6_ANALOG_USB1_CHRG_DETECT + regoff,134IMX6_ANALOG_USB_CHRG_DETECT_N_ENABLE |135IMX6_ANALOG_USB_CHRG_DETECT_N_CHK_CHRG);136137/* XXX Configure the overcurrent detection here. */138139/*140* Turn on the phy clocks.141*/142imx_ccm_usbphy_enable(dev);143144/*145* Set the software reset bit, then clear both it and the clock gate bit146* to bring the device out of reset with the clock running.147*/148bus_write_4(sc->mem_res, CTRL_SET_REG, CTRL_SFTRST);149bus_write_4(sc->mem_res, CTRL_CLR_REG, CTRL_SFTRST | CTRL_CLKGATE);150151/* Set UTMI+ level 2+3 bits to enable low and full speed devices. */152bus_write_4(sc->mem_res, CTRL_SET_REG,153CTRL_ENUTMILEVEL2 | CTRL_ENUTMILEVEL3);154155/* Power up: clear all bits in the powerdown register. */156bus_write_4(sc->mem_res, PWD_REG, 0);157158err = 0;159160out:161162if (err != 0)163usbphy_detach(dev);164165return (err);166}167168static int169usbphy_probe(device_t dev)170{171172if (!ofw_bus_status_okay(dev))173return (ENXIO);174175if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)176return (ENXIO);177178device_set_desc(dev, "Freescale i.MX6 USB PHY");179180return (BUS_PROBE_DEFAULT);181}182183static device_method_t usbphy_methods[] = {184/* Device interface */185DEVMETHOD(device_probe, usbphy_probe),186DEVMETHOD(device_attach, usbphy_attach),187DEVMETHOD(device_detach, usbphy_detach),188189DEVMETHOD_END190};191192static driver_t usbphy_driver = {193"usbphy",194usbphy_methods,195sizeof(struct usbphy_softc)196};197198/*199* This driver needs to start before the ehci driver, but later than the usual200* "special" drivers like clocks and cpu. Ehci starts at DEFAULT so SUPPORTDEV201* is where this driver fits most.202*/203EARLY_DRIVER_MODULE(usbphy, simplebus, usbphy_driver, 0, 0,204BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);205206207