Home | History | Annotate | Line # | Download | only in amlogic
      1 /* $NetBSD: mesong12_usb3pciephy.c,v 1.3 2024/02/07 04:20:26 msaitoh Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2021 Ryo Shimizu
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: mesong12_usb3pciephy.c,v 1.3 2024/02/07 04:20:26 msaitoh Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/types.h>
     34 #include <sys/bus.h>
     35 #include <sys/device.h>
     36 
     37 #include <dev/fdt/fdtvar.h>
     38 
     39 #define USB3PCIEPHY_R0_REG				0x00
     40 #define  USB3PCIEPHY_R0_PCIE_USB3_SWITCH		__BITS(6,5)
     41 #define  USB3PCIEPHY_R0_PCIE_POWER_STATE		__BITS(4,0)
     42 #define USB3PCIEPHY_R1_REG				0x04
     43 #define  USB3PCIEPHY_R1_PHY_MPLL_MULTIPLIER		__BITS(31,25)
     44 #define  USB3PCIEPHY_R1_PHY_REF_CLKDIV2			__BIT(24)
     45 #define  USB3PCIEPHY_R1_PHY_LOS_BIAS			__BITS(23,21)
     46 #define  USB3PCIEPHY_R1_PHY_LOS_LEVEL			__BITS(20,16)
     47 #define  USB3PCIEPHY_R1_PHY_RX0_EQ			__BITS(15,13)
     48 #define  USB3PCIEPHY_R1_PHY_RX1_EQ			__BITS(12,10)
     49 #define  USB3PCIEPHY_R1_PHY_TX0_TERM_OFFSET		__BITS(9,5)
     50 #define  USB3PCIEPHY_R1_PHY_TX1_TERM_OFFSET		__BITS(4,0)
     51 #define USB3PCIEPHY_R2_REG				0x08
     52 #define  USB3PCIEPHY_R2_PHY_TX_VBOOST_LVL		__BITS(20,18)
     53 #define  USB3PCIEPHY_R2_PCS_TX_DEEMPH_GEN1		__BITS(17,12)
     54 #define  USB3PCIEPHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB	__BITS(11,6)
     55 #define  USB3PCIEPHY_R2_PCS_TX_DEEMPH_GEN2_6DB		__BITS(5,0)
     56 #define USB3PCIEPHY_R4_REG				0x10
     57 #define  USB3PCIEPHY_R4_PHY_CR_CAP_ADDR			__BIT(19)
     58 #define  USB3PCIEPHY_R4_PHY_CR_CAP_DATA			__BIT(18)
     59 #define  USB3PCIEPHY_R4_PHY_CR_DATA_IN			__BITS(17,2)
     60 #define  USB3PCIEPHY_R4_PHY_CR_READ			__BIT(1)
     61 #define  USB3PCIEPHY_R4_PHY_CR_WRITE			__BIT(0)
     62 #define USB3PCIEPHY_R5_REG				0x14
     63 #define  USB3PCIEPHY_R5_PHY_BS_OUT			__BIT(17)
     64 #define  USB3PCIEPHY_R5_PHY_CR_ACK			__BIT(16)
     65 #define  USB3PCIEPHY_R5_PHY_CR_DATA_OUT			__BITS(15,0)
     66 
     67 #define PHY_READ_REG(sc, reg)	\
     68 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
     69 #define PHY_WRITE_REG(sc, reg, val)	\
     70 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
     71 
     72 
     73 /* The values must be matched to those in dt-bindings/phy/phy.h */
     74 #define PHY_NONE	0
     75 #define PHY_TYPE_PCIE	2
     76 #define PHY_TYPE_USB3	4
     77 
     78 struct mesong12_usb3pciephy_softc {
     79 	device_t sc_dev;
     80 	bus_space_tag_t sc_bst;
     81 	bus_space_handle_t sc_bsh;
     82 	struct clk *sc_clk;
     83 	struct fdtbus_reset *sc_reset;
     84 	struct fdtbus_regulator *sc_supply;
     85 	int sc_phandle;
     86 	int sc_phy_type;
     87 };
     88 
     89 static void *
     90 mesong12_usb3pciephy_acquire(device_t dev, const void *data, size_t len)
     91 {
     92 	struct mesong12_usb3pciephy_softc * const sc = device_private(dev);
     93 	const uint32_t *p = data;
     94 
     95 	/* already acquired? */
     96 	if (sc->sc_phy_type != PHY_NONE)
     97 		return NULL;
     98 
     99 	if (len != sizeof(uint32_t))
    100 		return NULL;
    101 
    102 	switch (be32toh(p[0])) {
    103 	case PHY_TYPE_USB3:
    104 		sc->sc_phy_type = PHY_TYPE_USB3;
    105 		break;
    106 	case PHY_TYPE_PCIE:
    107 		return NULL;	/* PCIe mode is not supported */
    108 	default:
    109 		return NULL;
    110 	}
    111 
    112 	return sc;
    113 }
    114 
    115 static void
    116 mesong12_usb3pciephy_release(device_t dev, void *priv)
    117 {
    118 	struct mesong12_usb3pciephy_softc * const sc = device_private(dev);
    119 
    120 	sc->sc_phy_type = PHY_NONE;
    121 }
    122 
    123 static inline int
    124 mesong12_usb3pciephy_ack(struct mesong12_usb3pciephy_softc *sc, bool ack,
    125     const char *str)
    126 {
    127 	int timeout;
    128 	uint32_t val;
    129 
    130 	for (timeout = 1000; timeout > 0; timeout--) {
    131 		val = PHY_READ_REG(sc, USB3PCIEPHY_R5_REG);
    132 		if (!(val & USB3PCIEPHY_R5_PHY_CR_ACK) == !ack)
    133 			return 0;
    134 		delay(5);
    135 	}
    136 	device_printf(sc->sc_dev, "phy %s %s timeout\n",
    137 	    str, ack ? "ack" : "nack");
    138 	return ETIMEDOUT;
    139 }
    140 
    141 static void
    142 mesong12_usb3pciephy_addr(struct mesong12_usb3pciephy_softc *sc,
    143     bus_addr_t addr)
    144 {
    145 	uint32_t val;
    146 
    147 	val = __SHIFTIN(addr, USB3PCIEPHY_R4_PHY_CR_DATA_IN);
    148 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
    149 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
    150 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val |
    151 	    USB3PCIEPHY_R4_PHY_CR_CAP_ADDR);
    152 	if (mesong12_usb3pciephy_ack(sc, true, "addr") != 0)
    153 		return;
    154 
    155 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
    156 	mesong12_usb3pciephy_ack(sc, false, "addr");
    157 }
    158 
    159 static uint16_t
    160 mesong12_usb3pciephy_read(struct mesong12_usb3pciephy_softc *sc,
    161     bus_addr_t addr)
    162 {
    163 	uint32_t val;
    164 
    165 	mesong12_usb3pciephy_addr(sc, addr);
    166 
    167 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, 0);
    168 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, USB3PCIEPHY_R4_PHY_CR_READ);
    169 	if (mesong12_usb3pciephy_ack(sc, true, "read data") != 0)
    170 		return 0;
    171 
    172 	val = PHY_READ_REG(sc, USB3PCIEPHY_R5_REG);
    173 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, 0);
    174 	if (mesong12_usb3pciephy_ack(sc, false, "read data") != 0)
    175 		return 0;
    176 
    177 	return __SHIFTOUT(val, USB3PCIEPHY_R5_PHY_CR_DATA_OUT);
    178 }
    179 
    180 static void
    181 mesong12_usb3pciephy_write(struct mesong12_usb3pciephy_softc *sc,
    182     bus_addr_t addr, uint16_t data)
    183 {
    184 	uint32_t val;
    185 
    186 	mesong12_usb3pciephy_addr(sc, addr);
    187 
    188 	val = __SHIFTIN(addr, USB3PCIEPHY_R4_PHY_CR_DATA_IN);
    189 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
    190 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
    191 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val |
    192 	    USB3PCIEPHY_R4_PHY_CR_CAP_DATA);
    193 	if (mesong12_usb3pciephy_ack(sc, true, "write addr") != 0)
    194 		return;
    195 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
    196 	if (mesong12_usb3pciephy_ack(sc, false, "write addr") != 0)
    197 		return;
    198 
    199 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
    200 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val |
    201 	    USB3PCIEPHY_R4_PHY_CR_WRITE);
    202 	if (mesong12_usb3pciephy_ack(sc, true, "write data") != 0)
    203 		return;
    204 	PHY_WRITE_REG(sc, USB3PCIEPHY_R4_REG, val);
    205 	if (mesong12_usb3pciephy_ack(sc, false, "write data") != 0)
    206 		return;
    207 }
    208 
    209 static int
    210 mesong12_usb3pciephy_enable(device_t dev, void *priv, bool enable)
    211 {
    212 	struct mesong12_usb3pciephy_softc * const sc = device_private(dev);
    213 	uint32_t val;
    214 
    215 	fdtbus_clock_assign(sc->sc_phandle);
    216 	if (sc->sc_reset != NULL) {
    217 		fdtbus_reset_assert(sc->sc_reset);
    218 		delay(10);
    219 		fdtbus_reset_deassert(sc->sc_reset);
    220 	}
    221 
    222 	if (!enable)
    223 		return 0;
    224 
    225 	/* switch to USB3.0 */
    226 	val = PHY_READ_REG(sc, USB3PCIEPHY_R0_REG);
    227 	val &= ~USB3PCIEPHY_R0_PCIE_USB3_SWITCH;
    228 	val |= __SHIFTIN(3, USB3PCIEPHY_R0_PCIE_USB3_SWITCH);
    229 	PHY_WRITE_REG(sc, USB3PCIEPHY_R0_REG, val);
    230 	delay(10);
    231 
    232 #if 0 /* XXX: doesn't work? */
    233 	/* workaround for SSPHY(SuperSpeedPHY) suspend bug */
    234 	val = mesong12_usb3pciephy_read(sc, 0x102d);
    235 	val |= __BIT(7);
    236 	mesong12_usb3pciephy_write(sc, 0x102d, val);
    237 #endif
    238 
    239 	val = mesong12_usb3pciephy_read(sc, 0x1010);
    240 	val &= ~__BITS(11,4);
    241 	val |= __SHIFTIN(2, __BITS(11,4));
    242 	mesong12_usb3pciephy_write(sc, 0x1010, val);
    243 
    244 #if 0 /* XXX: doesn't work? */
    245 	/* Rx equalization magic */
    246 	val = mesong12_usb3pciephy_read(sc, 0x1006);
    247 	val &= ~__BITS(7,6);
    248 	val |= __SHIFTIN(2, __BITS(7,6));
    249 	val &= ~__BITS(10,8);
    250 	val |= __SHIFTIN(3, __BITS(10,8));
    251 	val |= __BIT(11);
    252 	mesong12_usb3pciephy_write(sc, 0x1006, val);
    253 #endif
    254 
    255 	/* Tx equalization magic */
    256 	val = mesong12_usb3pciephy_read(sc, 0x1002);
    257 	val &= ~__BITS(13,7);
    258 	val |= __SHIFTIN(0x16, __BITS(13,7));
    259 	val &= ~__BITS(6,0);
    260 	val |= __SHIFTIN(0x7f, __BITS(6,0));
    261 	val |= __BIT(14);
    262 	mesong12_usb3pciephy_write(sc, 0x1002, val);
    263 
    264 	/* MPLL loop magic */
    265 	val = mesong12_usb3pciephy_read(sc, 0x30);
    266 	val &= ~__BITS(7,4);
    267 	val |= __SHIFTIN(8, __BITS(7,4));
    268 	mesong12_usb3pciephy_write(sc, 0x30, val);
    269 
    270 
    271 	val = PHY_READ_REG(sc, USB3PCIEPHY_R2_REG);
    272 	val &= ~USB3PCIEPHY_R2_PHY_TX_VBOOST_LVL;
    273 	val |= __SHIFTIN(4, USB3PCIEPHY_R2_PHY_TX_VBOOST_LVL);
    274 	PHY_WRITE_REG(sc, USB3PCIEPHY_R2_REG, val);
    275 
    276 	val = PHY_READ_REG(sc, USB3PCIEPHY_R1_REG);
    277 	val &= ~USB3PCIEPHY_R1_PHY_LOS_BIAS;
    278 	val |= __SHIFTIN(4, USB3PCIEPHY_R1_PHY_LOS_BIAS);
    279 	val &= ~USB3PCIEPHY_R1_PHY_LOS_LEVEL;
    280 	val |= __SHIFTIN(9, USB3PCIEPHY_R1_PHY_LOS_LEVEL);
    281 	PHY_WRITE_REG(sc, USB3PCIEPHY_R1_REG, val);
    282 
    283 	return 0;
    284 }
    285 
    286 static const struct device_compatible_entry compat_data[] = {
    287 	{ .compat = "amlogic,g12a-usb3-pcie-phy" },
    288 	DEVICE_COMPAT_EOL
    289 };
    290 
    291 static int
    292 mesong12_usb3pciephy_match(device_t parent, cfdata_t cf, void *aux)
    293 {
    294 	struct fdt_attach_args * const faa = aux;
    295 
    296 	return of_compatible_match(faa->faa_phandle, compat_data);
    297 }
    298 
    299 static const struct fdtbus_phy_controller_func mesong12_usb3pciephy_funcs = {
    300 	.acquire = mesong12_usb3pciephy_acquire,
    301 	.release = mesong12_usb3pciephy_release,
    302 	.enable = mesong12_usb3pciephy_enable
    303 };
    304 
    305 static void
    306 mesong12_usb3pciephy_attach(device_t parent, device_t self, void *aux)
    307 {
    308 	struct mesong12_usb3pciephy_softc * const sc = device_private(self);
    309 	struct fdt_attach_args * const faa = aux;
    310 	const int phandle = faa->faa_phandle;
    311 	bus_addr_t addr;
    312 	bus_size_t size;
    313 
    314 	sc->sc_dev = self;
    315 	sc->sc_bst = faa->faa_bst;
    316 	sc->sc_phandle = phandle;
    317 
    318 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    319 		aprint_error(": couldn't get registers\n");
    320 		return;
    321 	}
    322 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
    323 		aprint_error(": couldn't map registers\n");
    324 		return;
    325 	}
    326 
    327 	sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
    328 	if (sc->sc_clk == NULL) {
    329 		aprint_error(": couldn't get clock\n");
    330 		goto attach_failure;
    331 	}
    332 	if (clk_enable(sc->sc_clk) != 0) {
    333 		aprint_error(": couldn't enable clock\n");
    334 		goto attach_failure;
    335 	}
    336 
    337 	sc->sc_reset = fdtbus_reset_get_index(phandle, 0);
    338 	sc->sc_supply = fdtbus_regulator_acquire(phandle, "phy-supply");
    339 	if (sc->sc_supply != NULL)
    340 		fdtbus_regulator_enable(sc->sc_supply);
    341 
    342 	aprint_naive("\n");
    343 	aprint_normal(": USB3 PCIe PHY\n");
    344 
    345 	fdtbus_register_phy_controller(self, phandle,
    346 	    &mesong12_usb3pciephy_funcs);
    347 	return;
    348 
    349  attach_failure:
    350 	bus_space_unmap(sc->sc_bst, sc->sc_bsh, size);
    351 	return;
    352 }
    353 
    354 CFATTACH_DECL_NEW(mesong12_usb3pciephy,
    355     sizeof(struct mesong12_usb3pciephy_softc),
    356     mesong12_usb3pciephy_match, mesong12_usb3pciephy_attach, NULL, NULL);
    357