mesong12_usb3pciephy.c revision 1.2
11.2Sthorpej/* $NetBSD: mesong12_usb3pciephy.c,v 1.2 2021/01/27 03:10:18 thorpej Exp $ */ 21.1Sryo 31.1Sryo/* 41.1Sryo * Copyright (c) 2021 Ryo Shimizu <ryo@nerv.org> 51.1Sryo * All rights reserved. 61.1Sryo * 71.1Sryo * Redistribution and use in source and binary forms, with or without 81.1Sryo * modification, are permitted provided that the following conditions 91.1Sryo * are met: 101.1Sryo * 1. Redistributions of source code must retain the above copyright 111.1Sryo * notice, this list of conditions and the following disclaimer. 121.1Sryo * 2. Redistributions in binary form must reproduce the above copyright 131.1Sryo * notice, this list of conditions and the following disclaimer in the 141.1Sryo * documentation and/or other materials provided with the distribution. 151.1Sryo * 161.1Sryo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 171.1Sryo * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 181.1Sryo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191.1Sryo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 201.1Sryo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 211.1Sryo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 221.1Sryo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231.1Sryo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 241.1Sryo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 251.1Sryo * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 261.1Sryo * POSSIBILITY OF SUCH DAMAGE. 271.1Sryo */ 281.1Sryo 291.1Sryo#include <sys/cdefs.h> 301.2Sthorpej__KERNEL_RCSID(0, "$NetBSD: mesong12_usb3pciephy.c,v 1.2 2021/01/27 03:10:18 thorpej Exp $"); 311.1Sryo 321.1Sryo#include <sys/param.h> 331.1Sryo#include <sys/types.h> 341.1Sryo#include <sys/bus.h> 351.1Sryo#include <sys/device.h> 361.1Sryo 371.1Sryo#include <dev/fdt/fdtvar.h> 381.1Sryo 391.1Sryo#define USB3PCIEPHY_R0_REG 0x00 401.1Sryo#define USB3PCIEPHY_R0_PCIE_USB3_SWITCH __BITS(6,5) 411.1Sryo#define USB3PCIEPHY_R0_PCIE_POWER_STATE __BITS(4,0) 421.1Sryo#define USB3PCIEPHY_R1_REG 0x04 431.1Sryo#define USB3PCIEPHY_R1_PHY_MPLL_MULTIPLIER __BITS(31,25) 441.1Sryo#define USB3PCIEPHY_R1_PHY_REF_CLKDIV2 __BIT(24) 451.1Sryo#define USB3PCIEPHY_R1_PHY_LOS_BIAS __BITS(23,21) 461.1Sryo#define USB3PCIEPHY_R1_PHY_LOS_LEVEL __BITS(20,16) 471.1Sryo#define USB3PCIEPHY_R1_PHY_RX0_EQ __BITS(15,13) 481.1Sryo#define USB3PCIEPHY_R1_PHY_RX1_EQ __BITS(12,10) 491.1Sryo#define USB3PCIEPHY_R1_PHY_TX0_TERM_OFFSET __BITS(9,5) 501.1Sryo#define USB3PCIEPHY_R1_PHY_TX1_TERM_OFFSET __BITS(4,0) 511.1Sryo#define USB3PCIEPHY_R2_REG 0x08 521.1Sryo#define USB3PCIEPHY_R2_PHY_TX_VBOOST_LVL __BITS(20,18) 531.1Sryo#define USB3PCIEPHY_R2_PCS_TX_DEEMPH_GEN1 __BITS(17,12) 541.1Sryo#define USB3PCIEPHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB __BITS(11,6) 551.1Sryo#define USB3PCIEPHY_R2_PCS_TX_DEEMPH_GEN2_6DB __BITS(5,0) 561.1Sryo#define USB3PCIEPHY_R4_REG 0x10 571.1Sryo#define USB3PCIEPHY_R4_PHY_CR_CAP_ADDR __BIT(19) 581.1Sryo#define USB3PCIEPHY_R4_PHY_CR_CAP_DATA __BIT(18) 591.1Sryo#define USB3PCIEPHY_R4_PHY_CR_DATA_IN __BITS(17,2) 601.1Sryo#define USB3PCIEPHY_R4_PHY_CR_READ __BIT(1) 611.1Sryo#define USB3PCIEPHY_R4_PHY_CR_WRITE __BIT(0) 621.1Sryo#define USB3PCIEPHY_R5_REG 0x14 631.1Sryo#define USB3PCIEPHY_R5_PHY_BS_OUT __BIT(17) 641.1Sryo#define USB3PCIEPHY_R5_PHY_CR_ACK __BIT(16) 651.1Sryo#define USB3PCIEPHY_R5_PHY_CR_DATA_OUT __BITS(15,0) 661.1Sryo 671.1Sryo#define PHY_READ_REG(sc, reg) \ 681.1Sryo bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 691.1Sryo#define PHY_WRITE_REG(sc, reg, val) \ 701.1Sryo bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 711.1Sryo 721.1Sryo 731.1Sryo/* The values must be matched to those in dt-bindings/phy/phy.h */ 741.1Sryo#define PHY_NONE 0 751.1Sryo#define PHY_TYPE_PCIE 2 761.1Sryo#define PHY_TYPE_USB3 4 771.1Sryo 781.1Sryostruct mesong12_usb3pciephy_softc { 791.1Sryo device_t sc_dev; 801.1Sryo bus_space_tag_t sc_bst; 811.1Sryo bus_space_handle_t sc_bsh; 821.1Sryo struct clk *sc_clk; 831.1Sryo struct fdtbus_reset *sc_reset; 841.1Sryo struct fdtbus_regulator *sc_supply; 851.1Sryo int sc_phandle; 861.1Sryo int sc_phy_type; 871.1Sryo}; 881.1Sryo 891.1Sryostatic void * 901.1Sryomesong12_usb3pciephy_acquire(device_t dev, const void *data, size_t len) 911.1Sryo{ 921.1Sryo struct mesong12_usb3pciephy_softc * const sc = device_private(dev); 931.1Sryo const uint32_t *p = data; 941.1Sryo 951.1Sryo /* already acquired? */ 961.1Sryo if (sc->sc_phy_type != PHY_NONE) 971.1Sryo return NULL; 981.1Sryo 991.1Sryo if (len != sizeof(uint32_t)) 1001.1Sryo return NULL; 1011.1Sryo 1021.1Sryo switch (be32toh(p[0])) { 1031.1Sryo case PHY_TYPE_USB3: 1041.1Sryo sc->sc_phy_type = PHY_TYPE_USB3; 1051.1Sryo break; 1061.1Sryo case PHY_TYPE_PCIE: 1071.1Sryo return NULL; /* PCIe mode is not supported */ 1081.1Sryo default: 1091.1Sryo return NULL; 1101.1Sryo } 1111.1Sryo 1121.1Sryo return sc; 1131.1Sryo} 1141.1Sryo 1151.1Sryostatic void 1161.1Sryomesong12_usb3pciephy_release(device_t dev, void *priv) 1171.1Sryo{ 1181.1Sryo struct mesong12_usb3pciephy_softc * const sc = device_private(dev); 1191.1Sryo 1201.1Sryo sc->sc_phy_type = PHY_NONE; 1211.1Sryo} 1221.1Sryo 1231.1Sryostatic inline int 1241.1Sryomesong12_usb3pciephy_ack(struct mesong12_usb3pciephy_softc *sc, bool ack, 1251.1Sryo const char *str) 1261.1Sryo{ 1271.1Sryo int timeout; 1281.1Sryo uint32_t val; 1291.1Sryo 1301.1Sryo for (timeout = 1000; timeout > 0; timeout--) { 1311.1Sryo val = PHY_READ_REG(sc, USB3PCIEPHY_R5_REG); 1321.1Sryo if (!(val & USB3PCIEPHY_R5_PHY_CR_ACK) == !ack) 1331.1Sryo return 0; 1341.1Sryo delay(5); 1351.1Sryo } 1361.1Sryo device_printf(sc->sc_dev, "phy %s %s timeout\n", 1371.1Sryo str, ack ? "ack" : "nack"); 1381.1Sryo return ETIMEDOUT; 1391.1Sryo} 1401.1Sryo 1411.1Sryostatic void 1421.1Sryomesong12_usb3pciephy_addr(struct mesong12_usb3pciephy_softc *sc, 1431.1Sryo bus_addr_t addr) 1441.1Sryo{ 1451.1Sryo uint32_t val; 1461.1Sryo 1471.1Sryo val = __SHIFTIN(addr, USB3PCIEPHY_R4_PHY_CR_DATA_IN); 1481.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val); 1491.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val); 1501.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val | 1511.1Sryo USB3PCIEPHY_R4_PHY_CR_CAP_ADDR); 1521.1Sryo if (mesong12_usb3pciephy_ack(sc, true, "addr") != 0) 1531.1Sryo return; 1541.1Sryo 1551.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val); 1561.1Sryo mesong12_usb3pciephy_ack(sc, false, "addr"); 1571.1Sryo} 1581.1Sryo 1591.1Sryostatic uint16_t 1601.1Sryomesong12_usb3pciephy_read(struct mesong12_usb3pciephy_softc *sc, 1611.1Sryo bus_addr_t addr) 1621.1Sryo{ 1631.1Sryo uint32_t val; 1641.1Sryo 1651.1Sryo mesong12_usb3pciephy_addr(sc, addr); 1661.1Sryo 1671.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, 0); 1681.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, USB3PCIEPHY_R4_PHY_CR_READ); 1691.1Sryo if (mesong12_usb3pciephy_ack(sc, true, "read data") != 0) 1701.1Sryo return 0; 1711.1Sryo 1721.1Sryo val = PHY_READ_REG(sc, USB3PCIEPHY_R5_REG); 1731.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, 0); 1741.1Sryo if (mesong12_usb3pciephy_ack(sc, false, "read data") != 0) 1751.1Sryo return 0; 1761.1Sryo 1771.1Sryo return __SHIFTOUT(val, USB3PCIEPHY_R5_PHY_CR_DATA_OUT); 1781.1Sryo} 1791.1Sryo 1801.1Sryostatic void 1811.1Sryomesong12_usb3pciephy_write(struct mesong12_usb3pciephy_softc *sc, 1821.1Sryo bus_addr_t addr, uint16_t data) 1831.1Sryo{ 1841.1Sryo uint32_t val; 1851.1Sryo 1861.1Sryo mesong12_usb3pciephy_addr(sc, addr); 1871.1Sryo 1881.1Sryo val = __SHIFTIN(addr, USB3PCIEPHY_R4_PHY_CR_DATA_IN); 1891.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val); 1901.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val); 1911.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val | 1921.1Sryo USB3PCIEPHY_R4_PHY_CR_CAP_DATA); 1931.1Sryo if (mesong12_usb3pciephy_ack(sc, true, "write addr") != 0) 1941.1Sryo return; 1951.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val); 1961.1Sryo if (mesong12_usb3pciephy_ack(sc, false, "write addr") != 0) 1971.1Sryo return; 1981.1Sryo 1991.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val); 2001.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val | 2011.1Sryo USB3PCIEPHY_R4_PHY_CR_WRITE); 2021.1Sryo if (mesong12_usb3pciephy_ack(sc, true, "write data") != 0) 2031.1Sryo return; 2041.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val); 2051.1Sryo if (mesong12_usb3pciephy_ack(sc, false, "write data") != 0) 2061.1Sryo return; 2071.1Sryo} 2081.1Sryo 2091.1Sryostatic int 2101.1Sryomesong12_usb3pciephy_enable(device_t dev, void *priv, bool enable) 2111.1Sryo{ 2121.1Sryo struct mesong12_usb3pciephy_softc * const sc = device_private(dev); 2131.1Sryo uint32_t val; 2141.1Sryo 2151.1Sryo fdtbus_clock_assign(sc->sc_phandle); 2161.1Sryo if (sc->sc_reset != NULL) { 2171.1Sryo fdtbus_reset_assert(sc->sc_reset); 2181.1Sryo delay(10); 2191.1Sryo fdtbus_reset_deassert(sc->sc_reset); 2201.1Sryo } 2211.1Sryo 2221.1Sryo if (!enable) 2231.1Sryo return 0; 2241.1Sryo 2251.1Sryo /* switch to USB3.0 */ 2261.1Sryo val = PHY_READ_REG(sc, USB3PCIEPHY_R0_REG); 2271.1Sryo val &= ~USB3PCIEPHY_R0_PCIE_USB3_SWITCH; 2281.1Sryo val |= __SHIFTIN(3, USB3PCIEPHY_R0_PCIE_USB3_SWITCH); 2291.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R0_REG, val); 2301.1Sryo delay(10); 2311.1Sryo 2321.1Sryo#if 0 /* XXX: doesn't work? */ 2331.1Sryo /* workaround for SSPHY(SuperSpeedPHY) suspend bug */ 2341.1Sryo val = mesong12_usb3pciephy_read(sc, 0x102d); 2351.1Sryo val |= __BIT(7); 2361.1Sryo mesong12_usb3pciephy_write(sc, 0x102d, val); 2371.1Sryo#endif 2381.1Sryo 2391.1Sryo val = mesong12_usb3pciephy_read(sc, 0x1010); 2401.1Sryo val &= ~__BITS(11,4); 2411.1Sryo val |= __SHIFTIN(2, __BITS(11,4)); 2421.1Sryo mesong12_usb3pciephy_write(sc, 0x1010, val); 2431.1Sryo 2441.1Sryo#if 0 /* XXX: doesn't work? */ 2451.1Sryo /* Rx equalization magic */ 2461.1Sryo val = mesong12_usb3pciephy_read(sc, 0x1006); 2471.1Sryo val &= ~__BITS(7,6); 2481.1Sryo val |= __SHIFTIN(2, __BITS(7,6)); 2491.1Sryo val &= ~__BITS(10,8); 2501.1Sryo val |= __SHIFTIN(3, __BITS(10,8)); 2511.1Sryo val |= __BIT(11); 2521.1Sryo mesong12_usb3pciephy_write(sc, 0x1006, val); 2531.1Sryo#endif 2541.1Sryo 2551.1Sryo /* Tx equalization magic */ 2561.1Sryo val = mesong12_usb3pciephy_read(sc, 0x1002); 2571.1Sryo val &= ~__BITS(13,7); 2581.1Sryo val |= __SHIFTIN(0x16, __BITS(13,7)); 2591.1Sryo val &= ~__BITS(6,0); 2601.1Sryo val |= __SHIFTIN(0x7f, __BITS(6,0)); 2611.1Sryo val |= __BIT(14); 2621.1Sryo mesong12_usb3pciephy_write(sc, 0x1002, val); 2631.1Sryo 2641.1Sryo /* MPLL loop magic */ 2651.1Sryo val = mesong12_usb3pciephy_read(sc, 0x30); 2661.1Sryo val &= ~__BITS(7,4); 2671.1Sryo val |= __SHIFTIN(8, __BITS(7,4)); 2681.1Sryo mesong12_usb3pciephy_write(sc, 0x30, val); 2691.1Sryo 2701.1Sryo 2711.1Sryo val = PHY_READ_REG(sc, USB3PCIEPHY_R2_REG); 2721.1Sryo val &= ~USB3PCIEPHY_R2_PHY_TX_VBOOST_LVL; 2731.1Sryo val |= __SHIFTIN(4, USB3PCIEPHY_R2_PHY_TX_VBOOST_LVL); 2741.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R2_REG, val); 2751.1Sryo 2761.1Sryo val = PHY_READ_REG(sc, USB3PCIEPHY_R1_REG); 2771.1Sryo val &= ~USB3PCIEPHY_R1_PHY_LOS_BIAS; 2781.1Sryo val |= __SHIFTIN(4, USB3PCIEPHY_R1_PHY_LOS_BIAS); 2791.1Sryo val &= ~USB3PCIEPHY_R1_PHY_LOS_LEVEL; 2801.1Sryo val |= __SHIFTIN(9, USB3PCIEPHY_R1_PHY_LOS_LEVEL); 2811.1Sryo PHY_WRITE_REG(sc, USB3PCIEPHY_R1_REG, val); 2821.1Sryo 2831.1Sryo return 0; 2841.1Sryo} 2851.1Sryo 2861.2Sthorpejstatic const struct device_compatible_entry compat_data[] = { 2871.2Sthorpej { .compat = "amlogic,g12a-usb3-pcie-phy" }, 2881.2Sthorpej DEVICE_COMPAT_EOL 2891.1Sryo}; 2901.1Sryo 2911.1Sryostatic int 2921.1Sryomesong12_usb3pciephy_match(device_t parent, cfdata_t cf, void *aux) 2931.1Sryo{ 2941.1Sryo struct fdt_attach_args * const faa = aux; 2951.1Sryo 2961.2Sthorpej return of_compatible_match(faa->faa_phandle, compat_data); 2971.1Sryo} 2981.1Sryo 2991.1Sryostatic const struct fdtbus_phy_controller_func mesong12_usb3pciephy_funcs = { 3001.1Sryo .acquire = mesong12_usb3pciephy_acquire, 3011.1Sryo .release = mesong12_usb3pciephy_release, 3021.1Sryo .enable = mesong12_usb3pciephy_enable 3031.1Sryo}; 3041.1Sryo 3051.1Sryostatic void 3061.1Sryomesong12_usb3pciephy_attach(device_t parent, device_t self, void *aux) 3071.1Sryo{ 3081.1Sryo struct mesong12_usb3pciephy_softc * const sc = device_private(self); 3091.1Sryo struct fdt_attach_args * const faa = aux; 3101.1Sryo const int phandle = faa->faa_phandle; 3111.1Sryo bus_addr_t addr; 3121.1Sryo bus_size_t size; 3131.1Sryo 3141.1Sryo sc->sc_dev = self; 3151.1Sryo sc->sc_bst = faa->faa_bst; 3161.1Sryo sc->sc_phandle = phandle; 3171.1Sryo 3181.1Sryo if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 3191.1Sryo aprint_error(": couldn't get registers\n"); 3201.1Sryo return; 3211.1Sryo } 3221.1Sryo if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 3231.1Sryo aprint_error(": couldn't map registers\n"); 3241.1Sryo return; 3251.1Sryo } 3261.1Sryo 3271.1Sryo sc->sc_clk = fdtbus_clock_get_index(phandle, 0); 3281.1Sryo if (sc->sc_clk == NULL) { 3291.1Sryo aprint_error(": couldn't get clock\n"); 3301.1Sryo goto attach_failure; 3311.1Sryo } 3321.1Sryo if (clk_enable(sc->sc_clk) != 0) { 3331.1Sryo aprint_error(": couldn't enable clock\n"); 3341.1Sryo goto attach_failure; 3351.1Sryo } 3361.1Sryo 3371.1Sryo sc->sc_reset = fdtbus_reset_get_index(phandle, 0); 3381.1Sryo sc->sc_supply = fdtbus_regulator_acquire(phandle, "phy-supply"); 3391.1Sryo if (sc->sc_supply != NULL) 3401.1Sryo fdtbus_regulator_enable(sc->sc_supply); 3411.1Sryo 3421.1Sryo aprint_naive("\n"); 3431.1Sryo aprint_normal(": USB3 PCIe PHY\n"); 3441.1Sryo 3451.1Sryo fdtbus_register_phy_controller(self, phandle, 3461.1Sryo &mesong12_usb3pciephy_funcs); 3471.1Sryo return; 3481.1Sryo 3491.1Sryo attach_failure: 3501.1Sryo bus_space_unmap(sc->sc_bst, sc->sc_bsh, size); 3511.1Sryo return; 3521.1Sryo} 3531.1Sryo 3541.1SryoCFATTACH_DECL_NEW(mesong12_usb3pciephy, 3551.1Sryo sizeof(struct mesong12_usb3pciephy_softc), 3561.1Sryo mesong12_usb3pciephy_match, mesong12_usb3pciephy_attach, NULL, NULL); 357