mtk_usb_phy.c revision 297715
1297670Ssgalabov/*- 2297670Ssgalabov * Copyright (c) 2016 Stanislav Galabov. 3297670Ssgalabov * All rights reserved. 4297670Ssgalabov * 5297670Ssgalabov * Redistribution and use in source and binary forms, with or without 6297670Ssgalabov * modification, are permitted provided that the following conditions 7297670Ssgalabov * are met: 8297670Ssgalabov * 1. Redistributions of source code must retain the above copyright 9297670Ssgalabov * notice, this list of conditions and the following disclaimer. 10297670Ssgalabov * 2. Redistributions in binary form must reproduce the above copyright 11297670Ssgalabov * notice, this list of conditions and the following disclaimer in the 12297670Ssgalabov * documentation and/or other materials provided with the distribution. 13297670Ssgalabov * 14297670Ssgalabov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15297670Ssgalabov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16297670Ssgalabov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17297670Ssgalabov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18297670Ssgalabov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19297670Ssgalabov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20297670Ssgalabov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21297670Ssgalabov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22297670Ssgalabov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23297670Ssgalabov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24297670Ssgalabov */ 25297670Ssgalabov 26297670Ssgalabov#include <sys/cdefs.h> 27297670Ssgalabov__FBSDID("$FreeBSD: head/sys/mips/mediatek/mtk_usb_phy.c 297715 2016-04-08 15:20:58Z sgalabov $"); 28297670Ssgalabov 29297670Ssgalabov#include <sys/stddef.h> 30297670Ssgalabov#include <sys/param.h> 31297670Ssgalabov#include <sys/types.h> 32297670Ssgalabov#include <sys/kernel.h> 33297670Ssgalabov#include <sys/bus.h> 34297670Ssgalabov#include <sys/module.h> 35297670Ssgalabov 36297670Ssgalabov#include <machine/bus.h> 37297670Ssgalabov 38297670Ssgalabov#include <dev/fdt/fdt_common.h> 39297670Ssgalabov#include <dev/fdt/fdt_clock.h> 40297670Ssgalabov#include <mips/mediatek/fdt_reset.h> 41297670Ssgalabov#include <dev/ofw/ofw_bus.h> 42297670Ssgalabov#include <dev/ofw/ofw_bus_subr.h> 43297670Ssgalabov 44297670Ssgalabov#include <mips/mediatek/mtk_sysctl.h> 45297670Ssgalabov#include <mips/mediatek/mtk_soc.h> 46297670Ssgalabov#include <mips/mediatek/mtk_usb_phy.h> 47297670Ssgalabov 48297670Ssgalabov#define RESET_ASSERT_DELAY 1000 49297670Ssgalabov#define RESET_DEASSERT_DELAY 10000 50297670Ssgalabov 51297670Ssgalabovstruct mtk_usb_phy_softc { 52297670Ssgalabov device_t dev; 53297670Ssgalabov struct resource * res; 54297670Ssgalabov uint32_t fm_base; 55297670Ssgalabov uint32_t u2_base; 56297670Ssgalabov uint32_t sr_coef; 57297670Ssgalabov uint32_t socid; 58297670Ssgalabov}; 59297670Ssgalabov 60297670Ssgalabov#define USB_PHY_READ(_sc, _off) bus_read_4((_sc)->res, (_off)) 61297670Ssgalabov#define USB_PHY_WRITE(_sc, _off, _val) bus_write_4((_sc)->res, (_off), (_val)) 62297670Ssgalabov#define USB_PHY_CLR_SET(_sc, _off, _clr, _set) \ 63297670Ssgalabov USB_PHY_WRITE(_sc, _off, ((USB_PHY_READ(_sc, _off) & ~(_clr)) | (_set))) 64297670Ssgalabov 65297670Ssgalabov#define USB_PHY_READ_U2(_sc, _off) \ 66297670Ssgalabov USB_PHY_READ((_sc), ((_sc)->u2_base + (_off))) 67297670Ssgalabov#define USB_PHY_WRITE_U2(_sc, _off, _val) \ 68297670Ssgalabov USB_PHY_WRITE((_sc), ((_sc)->u2_base + (_off)), (_val)) 69297670Ssgalabov#define USB_PHY_CLR_SET_U2(_sc, _off, _clr, _set) \ 70297670Ssgalabov USB_PHY_WRITE_U2((_sc), (_off), ((USB_PHY_READ_U2((_sc), (_off)) & \ 71297670Ssgalabov ~(_clr)) | (_set))) 72297670Ssgalabov#define USB_PHY_BARRIER(_sc) bus_barrier((_sc)->res, 0, 0, \ 73297670Ssgalabov BUS_SPACE_BARRIER_WRITE | BUS_SPACE_BARRIER_READ) 74297670Ssgalabov 75297670Ssgalabov#define USB_PHY_READ_FM(_sc, _off) \ 76297670Ssgalabov USB_PHY_READ((_sc), ((_sc)->fm_base + (_off))) 77297670Ssgalabov#define USB_PHY_WRITE_FM(_sc, _off) \ 78297670Ssgalabov USB_PHY_WRITE((_sc), ((_sc)->fm_base + (_off)), (_val)) 79297670Ssgalabov#define USB_PHY_CLR_SET_FM(_sc, _off, _clr, _set) \ 80297670Ssgalabov USB_PHY_WRITE_U2((_sc), (_off), ((USB_PHY_READ_U2((_sc), (_off)) & \ 81297670Ssgalabov ~(_clr)) | (_set))) 82297670Ssgalabov 83297670Ssgalabovstatic void mtk_usb_phy_mt7621_init(device_t); 84297670Ssgalabovstatic void mtk_usb_phy_mt7628_init(device_t); 85297670Ssgalabov 86297670Ssgalabovstatic struct ofw_compat_data compat_data[] = { 87297670Ssgalabov { "ralink,mt7620a-usbphy", MTK_SOC_MT7620A }, 88297670Ssgalabov { "ralink,mt7628an-usbphy", MTK_SOC_MT7628 }, 89297670Ssgalabov { "ralink,rt3xxx-usbphy", MTK_SOC_RT3352 }, 90297670Ssgalabov { NULL, MTK_SOC_UNKNOWN } 91297670Ssgalabov}; 92297670Ssgalabov 93297670Ssgalabovstatic int 94297670Ssgalabovmtk_usb_phy_probe(device_t dev) 95297670Ssgalabov{ 96297670Ssgalabov struct mtk_usb_phy_softc *sc = device_get_softc(dev); 97297670Ssgalabov 98297670Ssgalabov if (!ofw_bus_status_okay(dev)) 99297670Ssgalabov return (ENXIO); 100297670Ssgalabov if ((sc->socid = 101297670Ssgalabov ofw_bus_search_compatible(dev, compat_data)->ocd_data) == 102297670Ssgalabov MTK_SOC_UNKNOWN) 103297670Ssgalabov return (ENXIO); 104297670Ssgalabov 105297670Ssgalabov device_set_desc(dev, "MTK USB PHY"); 106297670Ssgalabov 107297670Ssgalabov return (0); 108297670Ssgalabov} 109297670Ssgalabov 110297670Ssgalabovstatic int 111297670Ssgalabovmtk_usb_phy_attach(device_t dev) 112297670Ssgalabov{ 113297670Ssgalabov struct mtk_usb_phy_softc * sc = device_get_softc(dev); 114297670Ssgalabov phandle_t node; 115297670Ssgalabov uint32_t val; 116297670Ssgalabov int rid; 117297670Ssgalabov 118297670Ssgalabov sc->dev = dev; 119297670Ssgalabov 120297670Ssgalabov /* Get our FDT node and SoC id */ 121297670Ssgalabov node = ofw_bus_get_node(dev); 122297670Ssgalabov 123297670Ssgalabov /* Now let's see about setting USB to host or device mode */ 124297670Ssgalabov /* XXX: is it the same for all SoCs? */ 125297670Ssgalabov val = mtk_sysctl_get(SYSCTL_SYSCFG1); 126297670Ssgalabov if (OF_hasprop(node, "mtk,usb-device")) 127297670Ssgalabov val &= ~SYSCFG1_USB_HOST_MODE; 128297670Ssgalabov else 129297670Ssgalabov val |= SYSCFG1_USB_HOST_MODE; 130297670Ssgalabov mtk_sysctl_set(SYSCTL_SYSCFG1, val); 131297670Ssgalabov 132297670Ssgalabov /* If we have clocks defined - enable them */ 133297670Ssgalabov if (OF_hasprop(node, "clocks")) 134297670Ssgalabov fdt_clock_enable_all(dev); 135297670Ssgalabov 136297670Ssgalabov /* If we have resets defined - perform a reset sequence */ 137297670Ssgalabov if (OF_hasprop(node, "resets")) { 138297670Ssgalabov fdt_reset_assert_all(dev); 139297670Ssgalabov DELAY(RESET_ASSERT_DELAY); 140297670Ssgalabov fdt_reset_deassert_all(dev); 141297670Ssgalabov DELAY(RESET_DEASSERT_DELAY); 142297670Ssgalabov } 143297670Ssgalabov 144297670Ssgalabov /* Careful, some devices actually require resources */ 145297670Ssgalabov if (OF_hasprop(node, "reg")) { 146297670Ssgalabov rid = 0; 147297670Ssgalabov sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 148297670Ssgalabov RF_ACTIVE); 149297670Ssgalabov if (sc->res == NULL) { 150297670Ssgalabov device_printf(dev, "could not map memory\n"); 151297670Ssgalabov return (ENXIO); 152297670Ssgalabov } 153297670Ssgalabov } else { 154297670Ssgalabov sc->res = NULL; 155297670Ssgalabov } 156297670Ssgalabov 157297670Ssgalabov /* Some SoCs require specific USB PHY init... handle these */ 158297670Ssgalabov switch (sc->socid) { 159297670Ssgalabov case MTK_SOC_MT7628: /* Fallthrough */ 160297670Ssgalabov case MTK_SOC_MT7688: 161297670Ssgalabov if (sc->res == NULL) 162297670Ssgalabov return (ENXIO); 163297670Ssgalabov sc->fm_base = MT7628_FM_FEG_BASE; 164297670Ssgalabov sc->u2_base = MT7628_U2_BASE; 165297670Ssgalabov sc->sr_coef = MT7628_SR_COEF; 166297670Ssgalabov mtk_usb_phy_mt7628_init(dev); 167297670Ssgalabov break; 168297670Ssgalabov case MTK_SOC_MT7621: 169297670Ssgalabov if (sc->res == NULL) 170297670Ssgalabov return (ENXIO); 171297670Ssgalabov sc->fm_base = MT7621_FM_FEG_BASE; 172297670Ssgalabov sc->u2_base = MT7621_U2_BASE; 173297670Ssgalabov sc->sr_coef = MT7621_SR_COEF; 174297670Ssgalabov mtk_usb_phy_mt7621_init(dev); 175297670Ssgalabov break; 176297670Ssgalabov } 177297670Ssgalabov 178297670Ssgalabov /* We no longer need the resources, release them */ 179297670Ssgalabov if (sc->res != NULL) 180297670Ssgalabov bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res); 181297670Ssgalabov 182297670Ssgalabov return (0); 183297670Ssgalabov} 184297670Ssgalabov 185297670Ssgalabovstatic int 186297670Ssgalabovmtk_usb_phy_detach(device_t dev) 187297670Ssgalabov{ 188297670Ssgalabov struct mtk_usb_phy_softc *sc = device_get_softc(dev); 189297670Ssgalabov phandle_t node; 190297670Ssgalabov 191297670Ssgalabov /* Get our FDT node */ 192297670Ssgalabov node = ofw_bus_get_node(dev); 193297670Ssgalabov 194297670Ssgalabov /* If we have resets defined - assert them */ 195297670Ssgalabov if (OF_hasprop(node, "resets")) 196297670Ssgalabov fdt_reset_assert_all(dev); 197297670Ssgalabov 198297670Ssgalabov /* If we have clocks defined - disable them */ 199297670Ssgalabov if (OF_hasprop(node, "clocks")) 200297670Ssgalabov fdt_clock_disable_all(dev); 201297670Ssgalabov 202297670Ssgalabov /* Finally, release resources, if any were allocated */ 203297670Ssgalabov if (sc->res != NULL) 204297670Ssgalabov bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res); 205297670Ssgalabov 206297670Ssgalabov return (0); 207297670Ssgalabov} 208297670Ssgalabov 209297715Ssgalabov/* 210297715Ssgalabov * Things currently seem to work a lot better without slew rate calibration 211297715Ssgalabov * both on MT7621 and MT7688, so we leave it out for now. 212297715Ssgalabov */ 213297715Ssgalabov#ifdef notyet 214297670Ssgalabovstatic void 215297670Ssgalabovmtk_usb_phy_slew_rate_calibration(struct mtk_usb_phy_softc *sc) 216297670Ssgalabov{ 217297670Ssgalabov uint32_t val; 218297670Ssgalabov int i; 219297670Ssgalabov 220297670Ssgalabov USB_PHY_CLR_SET_U2(sc, U2_PHY_ACR0, 0, SRCAL_EN); 221297670Ssgalabov USB_PHY_BARRIER(sc); 222297670Ssgalabov DELAY(1000); 223297670Ssgalabov 224297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMMONR1, 0, FRCK_EN); 225297670Ssgalabov USB_PHY_BARRIER(sc); 226297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMCR0, CYCLECNT, 0x400); 227297670Ssgalabov USB_PHY_BARRIER(sc); 228297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMCR0, 0, FDET_EN); 229297670Ssgalabov USB_PHY_BARRIER(sc); 230297670Ssgalabov 231297670Ssgalabov for (i = 0; i < 1000; i++) { 232297670Ssgalabov if ((val = USB_PHY_READ_FM(sc, U2_PHY_FMMONR0)) != 0) { 233297670Ssgalabov device_printf(sc->dev, "DONE with FDET\n"); 234297670Ssgalabov break; 235297670Ssgalabov } 236297670Ssgalabov DELAY(10000); 237297670Ssgalabov } 238297670Ssgalabov device_printf(sc->dev, "After FDET\n"); 239297670Ssgalabov 240297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMCR0, FDET_EN, 0); 241297670Ssgalabov USB_PHY_BARRIER(sc); 242297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMMONR1, FRCK_EN, 0); 243297670Ssgalabov USB_PHY_BARRIER(sc); 244297670Ssgalabov USB_PHY_CLR_SET_U2(sc, U2_PHY_ACR0, SRCAL_EN, 0); 245297670Ssgalabov USB_PHY_BARRIER(sc); 246297670Ssgalabov DELAY(1000); 247297670Ssgalabov 248297670Ssgalabov if (val == 0) { 249297670Ssgalabov USB_PHY_CLR_SET_U2(sc, U2_PHY_ACR0, SRCTRL, 0x4 << SRCTRL_OFF); 250297670Ssgalabov USB_PHY_BARRIER(sc); 251297670Ssgalabov } else { 252297670Ssgalabov val = ((((1024 * 25 * sc->sr_coef) / val) + 500) / 1000) & 253297670Ssgalabov SRCTRL_MSK; 254297670Ssgalabov USB_PHY_CLR_SET_U2(sc, U2_PHY_ACR0, SRCTRL, val << SRCTRL_OFF); 255297670Ssgalabov USB_PHY_BARRIER(sc); 256297670Ssgalabov } 257297670Ssgalabov} 258297715Ssgalabov#endif 259297670Ssgalabov 260297670Ssgalabovstatic void 261297670Ssgalabovmtk_usb_phy_mt7621_init(device_t dev) 262297670Ssgalabov{ 263297715Ssgalabov#ifdef notyet 264297670Ssgalabov struct mtk_usb_phy_softc *sc = device_get_softc(dev); 265297670Ssgalabov 266297670Ssgalabov /* Slew rate calibration only, but for 2 ports */ 267297670Ssgalabov mtk_usb_phy_slew_rate_calibration(sc); 268297670Ssgalabov 269297670Ssgalabov sc->u2_base = MT7621_U2_BASE_P1; 270297670Ssgalabov mtk_usb_phy_slew_rate_calibration(sc); 271297715Ssgalabov#endif 272297670Ssgalabov} 273297670Ssgalabov 274297670Ssgalabovstatic void 275297670Ssgalabovmtk_usb_phy_mt7628_init(device_t dev) 276297670Ssgalabov{ 277297670Ssgalabov struct mtk_usb_phy_softc *sc = device_get_softc(dev); 278297670Ssgalabov 279297670Ssgalabov /* XXX: possibly add barriers between the next writes? */ 280297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DCR0, 0x00ffff02); 281297670Ssgalabov USB_PHY_BARRIER(sc); 282297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DCR0, 0x00555502); 283297670Ssgalabov USB_PHY_BARRIER(sc); 284297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DCR0, 0x00aaaa02); 285297670Ssgalabov USB_PHY_BARRIER(sc); 286297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DCR0, 0x00000402); 287297670Ssgalabov USB_PHY_BARRIER(sc); 288297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_AC0, 0x0048086a); 289297670Ssgalabov USB_PHY_BARRIER(sc); 290297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_AC1, 0x4400001c); 291297670Ssgalabov USB_PHY_BARRIER(sc); 292297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_ACR3, 0xc0200000); 293297670Ssgalabov USB_PHY_BARRIER(sc); 294297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DTM0, 0x02000000); 295297670Ssgalabov USB_PHY_BARRIER(sc); 296297670Ssgalabov 297297715Ssgalabov#ifdef notyet 298297670Ssgalabov /* Slew rate calibration */ 299297715Ssgalabov mtk_usb_phy_slew_rate_calibration(sc); 300297715Ssgalabov#endif 301297670Ssgalabov} 302297670Ssgalabov 303297670Ssgalabovstatic device_method_t mtk_usb_phy_methods[] = { 304297670Ssgalabov /* Device interface */ 305297670Ssgalabov DEVMETHOD(device_probe, mtk_usb_phy_probe), 306297670Ssgalabov DEVMETHOD(device_attach, mtk_usb_phy_attach), 307297670Ssgalabov DEVMETHOD(device_detach, mtk_usb_phy_detach), 308297670Ssgalabov DEVMETHOD(device_suspend, bus_generic_suspend), 309297670Ssgalabov DEVMETHOD(device_resume, bus_generic_resume), 310297670Ssgalabov DEVMETHOD(device_shutdown, bus_generic_shutdown), 311297670Ssgalabov 312297670Ssgalabov DEVMETHOD_END 313297670Ssgalabov}; 314297670Ssgalabov 315297670Ssgalabovstatic driver_t mtk_usb_phy_driver = { 316297670Ssgalabov .name = "usbphy", 317297670Ssgalabov .methods = mtk_usb_phy_methods, 318297670Ssgalabov .size = sizeof(struct mtk_usb_phy_softc), 319297670Ssgalabov}; 320297670Ssgalabov 321297670Ssgalabovstatic devclass_t mtk_usb_phy_devclass; 322297670Ssgalabov 323297670SsgalabovDRIVER_MODULE(usbphy, simplebus, mtk_usb_phy_driver, mtk_usb_phy_devclass, 0, 324297670Ssgalabov 0); 325