mtk_usb_phy.c revision 298059
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 298059 2016-04-15 15:24:42Z 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[] = { 87298059Ssgalabov { "ralink,mt7620-usbphy", MTK_SOC_MT7620A }, 88297670Ssgalabov { "ralink,mt7628an-usbphy", MTK_SOC_MT7628 }, 89298059Ssgalabov { "ralink,rt3352-usbphy", MTK_SOC_RT3352 }, 90298059Ssgalabov { "ralink,rt3050-usbphy", MTK_SOC_RT3050 }, 91297670Ssgalabov { NULL, MTK_SOC_UNKNOWN } 92297670Ssgalabov}; 93297670Ssgalabov 94297670Ssgalabovstatic int 95297670Ssgalabovmtk_usb_phy_probe(device_t dev) 96297670Ssgalabov{ 97297670Ssgalabov struct mtk_usb_phy_softc *sc = device_get_softc(dev); 98297670Ssgalabov 99297670Ssgalabov if (!ofw_bus_status_okay(dev)) 100297670Ssgalabov return (ENXIO); 101297670Ssgalabov if ((sc->socid = 102297670Ssgalabov ofw_bus_search_compatible(dev, compat_data)->ocd_data) == 103297670Ssgalabov MTK_SOC_UNKNOWN) 104297670Ssgalabov return (ENXIO); 105297670Ssgalabov 106297670Ssgalabov device_set_desc(dev, "MTK USB PHY"); 107297670Ssgalabov 108297670Ssgalabov return (0); 109297670Ssgalabov} 110297670Ssgalabov 111297670Ssgalabovstatic int 112297670Ssgalabovmtk_usb_phy_attach(device_t dev) 113297670Ssgalabov{ 114297670Ssgalabov struct mtk_usb_phy_softc * sc = device_get_softc(dev); 115297670Ssgalabov phandle_t node; 116297670Ssgalabov uint32_t val; 117297670Ssgalabov int rid; 118297670Ssgalabov 119297670Ssgalabov sc->dev = dev; 120297670Ssgalabov 121297670Ssgalabov /* Get our FDT node and SoC id */ 122297670Ssgalabov node = ofw_bus_get_node(dev); 123297670Ssgalabov 124297670Ssgalabov /* Now let's see about setting USB to host or device mode */ 125297670Ssgalabov /* XXX: is it the same for all SoCs? */ 126297670Ssgalabov val = mtk_sysctl_get(SYSCTL_SYSCFG1); 127297670Ssgalabov if (OF_hasprop(node, "mtk,usb-device")) 128297670Ssgalabov val &= ~SYSCFG1_USB_HOST_MODE; 129297670Ssgalabov else 130297670Ssgalabov val |= SYSCFG1_USB_HOST_MODE; 131297670Ssgalabov mtk_sysctl_set(SYSCTL_SYSCFG1, val); 132297670Ssgalabov 133297670Ssgalabov /* If we have clocks defined - enable them */ 134297670Ssgalabov if (OF_hasprop(node, "clocks")) 135297670Ssgalabov fdt_clock_enable_all(dev); 136297670Ssgalabov 137297670Ssgalabov /* If we have resets defined - perform a reset sequence */ 138297670Ssgalabov if (OF_hasprop(node, "resets")) { 139297670Ssgalabov fdt_reset_assert_all(dev); 140297670Ssgalabov DELAY(RESET_ASSERT_DELAY); 141297670Ssgalabov fdt_reset_deassert_all(dev); 142297670Ssgalabov DELAY(RESET_DEASSERT_DELAY); 143297670Ssgalabov } 144297670Ssgalabov 145297670Ssgalabov /* Careful, some devices actually require resources */ 146297670Ssgalabov if (OF_hasprop(node, "reg")) { 147297670Ssgalabov rid = 0; 148297670Ssgalabov sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 149297670Ssgalabov RF_ACTIVE); 150297670Ssgalabov if (sc->res == NULL) { 151297670Ssgalabov device_printf(dev, "could not map memory\n"); 152297670Ssgalabov return (ENXIO); 153297670Ssgalabov } 154297670Ssgalabov } else { 155297670Ssgalabov sc->res = NULL; 156297670Ssgalabov } 157297670Ssgalabov 158297670Ssgalabov /* Some SoCs require specific USB PHY init... handle these */ 159297670Ssgalabov switch (sc->socid) { 160297670Ssgalabov case MTK_SOC_MT7628: /* Fallthrough */ 161297670Ssgalabov case MTK_SOC_MT7688: 162297670Ssgalabov if (sc->res == NULL) 163297670Ssgalabov return (ENXIO); 164297670Ssgalabov sc->fm_base = MT7628_FM_FEG_BASE; 165297670Ssgalabov sc->u2_base = MT7628_U2_BASE; 166297670Ssgalabov sc->sr_coef = MT7628_SR_COEF; 167297670Ssgalabov mtk_usb_phy_mt7628_init(dev); 168297670Ssgalabov break; 169297670Ssgalabov case MTK_SOC_MT7621: 170297670Ssgalabov if (sc->res == NULL) 171297670Ssgalabov return (ENXIO); 172297670Ssgalabov sc->fm_base = MT7621_FM_FEG_BASE; 173297670Ssgalabov sc->u2_base = MT7621_U2_BASE; 174297670Ssgalabov sc->sr_coef = MT7621_SR_COEF; 175297670Ssgalabov mtk_usb_phy_mt7621_init(dev); 176297670Ssgalabov break; 177297670Ssgalabov } 178297670Ssgalabov 179297670Ssgalabov /* We no longer need the resources, release them */ 180297670Ssgalabov if (sc->res != NULL) 181297670Ssgalabov bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res); 182297670Ssgalabov 183297670Ssgalabov return (0); 184297670Ssgalabov} 185297670Ssgalabov 186297670Ssgalabovstatic int 187297670Ssgalabovmtk_usb_phy_detach(device_t dev) 188297670Ssgalabov{ 189297670Ssgalabov struct mtk_usb_phy_softc *sc = device_get_softc(dev); 190297670Ssgalabov phandle_t node; 191297670Ssgalabov 192297670Ssgalabov /* Get our FDT node */ 193297670Ssgalabov node = ofw_bus_get_node(dev); 194297670Ssgalabov 195297670Ssgalabov /* If we have resets defined - assert them */ 196297670Ssgalabov if (OF_hasprop(node, "resets")) 197297670Ssgalabov fdt_reset_assert_all(dev); 198297670Ssgalabov 199297670Ssgalabov /* If we have clocks defined - disable them */ 200297670Ssgalabov if (OF_hasprop(node, "clocks")) 201297670Ssgalabov fdt_clock_disable_all(dev); 202297670Ssgalabov 203297670Ssgalabov /* Finally, release resources, if any were allocated */ 204297670Ssgalabov if (sc->res != NULL) 205297670Ssgalabov bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->res); 206297670Ssgalabov 207297670Ssgalabov return (0); 208297670Ssgalabov} 209297670Ssgalabov 210297715Ssgalabov/* 211297715Ssgalabov * Things currently seem to work a lot better without slew rate calibration 212297715Ssgalabov * both on MT7621 and MT7688, so we leave it out for now. 213297715Ssgalabov */ 214297715Ssgalabov#ifdef notyet 215297670Ssgalabovstatic void 216297670Ssgalabovmtk_usb_phy_slew_rate_calibration(struct mtk_usb_phy_softc *sc) 217297670Ssgalabov{ 218297670Ssgalabov uint32_t val; 219297670Ssgalabov int i; 220297670Ssgalabov 221297670Ssgalabov USB_PHY_CLR_SET_U2(sc, U2_PHY_ACR0, 0, SRCAL_EN); 222297670Ssgalabov USB_PHY_BARRIER(sc); 223297670Ssgalabov DELAY(1000); 224297670Ssgalabov 225297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMMONR1, 0, FRCK_EN); 226297670Ssgalabov USB_PHY_BARRIER(sc); 227297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMCR0, CYCLECNT, 0x400); 228297670Ssgalabov USB_PHY_BARRIER(sc); 229297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMCR0, 0, FDET_EN); 230297670Ssgalabov USB_PHY_BARRIER(sc); 231297670Ssgalabov 232297670Ssgalabov for (i = 0; i < 1000; i++) { 233297670Ssgalabov if ((val = USB_PHY_READ_FM(sc, U2_PHY_FMMONR0)) != 0) { 234297670Ssgalabov device_printf(sc->dev, "DONE with FDET\n"); 235297670Ssgalabov break; 236297670Ssgalabov } 237297670Ssgalabov DELAY(10000); 238297670Ssgalabov } 239297670Ssgalabov device_printf(sc->dev, "After FDET\n"); 240297670Ssgalabov 241297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMCR0, FDET_EN, 0); 242297670Ssgalabov USB_PHY_BARRIER(sc); 243297670Ssgalabov USB_PHY_CLR_SET_FM(sc, U2_PHY_FMMONR1, FRCK_EN, 0); 244297670Ssgalabov USB_PHY_BARRIER(sc); 245297670Ssgalabov USB_PHY_CLR_SET_U2(sc, U2_PHY_ACR0, SRCAL_EN, 0); 246297670Ssgalabov USB_PHY_BARRIER(sc); 247297670Ssgalabov DELAY(1000); 248297670Ssgalabov 249297670Ssgalabov if (val == 0) { 250297670Ssgalabov USB_PHY_CLR_SET_U2(sc, U2_PHY_ACR0, SRCTRL, 0x4 << SRCTRL_OFF); 251297670Ssgalabov USB_PHY_BARRIER(sc); 252297670Ssgalabov } else { 253297670Ssgalabov val = ((((1024 * 25 * sc->sr_coef) / val) + 500) / 1000) & 254297670Ssgalabov SRCTRL_MSK; 255297670Ssgalabov USB_PHY_CLR_SET_U2(sc, U2_PHY_ACR0, SRCTRL, val << SRCTRL_OFF); 256297670Ssgalabov USB_PHY_BARRIER(sc); 257297670Ssgalabov } 258297670Ssgalabov} 259297715Ssgalabov#endif 260297670Ssgalabov 261297670Ssgalabovstatic void 262297670Ssgalabovmtk_usb_phy_mt7621_init(device_t dev) 263297670Ssgalabov{ 264297715Ssgalabov#ifdef notyet 265297670Ssgalabov struct mtk_usb_phy_softc *sc = device_get_softc(dev); 266297670Ssgalabov 267297670Ssgalabov /* Slew rate calibration only, but for 2 ports */ 268297670Ssgalabov mtk_usb_phy_slew_rate_calibration(sc); 269297670Ssgalabov 270297670Ssgalabov sc->u2_base = MT7621_U2_BASE_P1; 271297670Ssgalabov mtk_usb_phy_slew_rate_calibration(sc); 272297715Ssgalabov#endif 273297670Ssgalabov} 274297670Ssgalabov 275297670Ssgalabovstatic void 276297670Ssgalabovmtk_usb_phy_mt7628_init(device_t dev) 277297670Ssgalabov{ 278297670Ssgalabov struct mtk_usb_phy_softc *sc = device_get_softc(dev); 279297670Ssgalabov 280297670Ssgalabov /* XXX: possibly add barriers between the next writes? */ 281297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DCR0, 0x00ffff02); 282297670Ssgalabov USB_PHY_BARRIER(sc); 283297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DCR0, 0x00555502); 284297670Ssgalabov USB_PHY_BARRIER(sc); 285297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DCR0, 0x00aaaa02); 286297670Ssgalabov USB_PHY_BARRIER(sc); 287297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DCR0, 0x00000402); 288297670Ssgalabov USB_PHY_BARRIER(sc); 289297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_AC0, 0x0048086a); 290297670Ssgalabov USB_PHY_BARRIER(sc); 291297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_AC1, 0x4400001c); 292297670Ssgalabov USB_PHY_BARRIER(sc); 293297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_ACR3, 0xc0200000); 294297670Ssgalabov USB_PHY_BARRIER(sc); 295297670Ssgalabov USB_PHY_WRITE_U2(sc, U2_PHY_DTM0, 0x02000000); 296297670Ssgalabov USB_PHY_BARRIER(sc); 297297670Ssgalabov 298297715Ssgalabov#ifdef notyet 299297670Ssgalabov /* Slew rate calibration */ 300297715Ssgalabov mtk_usb_phy_slew_rate_calibration(sc); 301297715Ssgalabov#endif 302297670Ssgalabov} 303297670Ssgalabov 304297670Ssgalabovstatic device_method_t mtk_usb_phy_methods[] = { 305297670Ssgalabov /* Device interface */ 306297670Ssgalabov DEVMETHOD(device_probe, mtk_usb_phy_probe), 307297670Ssgalabov DEVMETHOD(device_attach, mtk_usb_phy_attach), 308297670Ssgalabov DEVMETHOD(device_detach, mtk_usb_phy_detach), 309297670Ssgalabov DEVMETHOD(device_suspend, bus_generic_suspend), 310297670Ssgalabov DEVMETHOD(device_resume, bus_generic_resume), 311297670Ssgalabov DEVMETHOD(device_shutdown, bus_generic_shutdown), 312297670Ssgalabov 313297670Ssgalabov DEVMETHOD_END 314297670Ssgalabov}; 315297670Ssgalabov 316297670Ssgalabovstatic driver_t mtk_usb_phy_driver = { 317297670Ssgalabov .name = "usbphy", 318297670Ssgalabov .methods = mtk_usb_phy_methods, 319297670Ssgalabov .size = sizeof(struct mtk_usb_phy_softc), 320297670Ssgalabov}; 321297670Ssgalabov 322297670Ssgalabovstatic devclass_t mtk_usb_phy_devclass; 323297670Ssgalabov 324297670SsgalabovDRIVER_MODULE(usbphy, simplebus, mtk_usb_phy_driver, mtk_usb_phy_devclass, 0, 325297670Ssgalabov 0); 326