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