11.3Smsaitoh/* $NetBSD: mesong12_usb3pciephy.c,v 1.3 2024/02/07 04:20:26 msaitoh Exp $ */
21.1Sryo
31.1Sryo/*
41.3Smsaitoh * Copyright (c) 2021 Ryo Shimizu
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.3Smsaitoh__KERNEL_RCSID(0, "$NetBSD: mesong12_usb3pciephy.c,v 1.3 2024/02/07 04:20:26 msaitoh 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