svn commit: r308390 - head/sys/arm/nvidia/tegra124

Michal Meloun mmel at FreeBSD.org
Mon Nov 7 05:34:45 UTC 2016


Author: mmel
Date: Mon Nov  7 05:34:44 2016
New Revision: 308390
URL: https://svnweb.freebsd.org/changeset/base/308390

Log:
  Rework NVIDIA Tegra124 XUSBPAD driver.
   - Adapt it for new, incompatible, DT bindings introduced by r306197.
   - Add support for USB super speed pads/ports.
  
  MFC after: 3 weeks

Modified:
  head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c

Modified: head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c
==============================================================================
--- head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c	Sun Nov  6 23:13:13 2016	(r308389)
+++ head/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c	Mon Nov  7 05:34:44 2016	(r308390)
@@ -39,26 +39,57 @@
 
 #include <dev/extres/hwreset/hwreset.h>
 #include <dev/extres/phy/phy.h>
+#include <dev/extres/regulator/regulator.h>
 #include <dev/fdt/fdt_common.h>
 #include <dev/fdt/fdt_pinctrl.h>
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
+#include <arm/nvidia/tegra_efuse.h>
+
 #include <gnu/dts/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
 
 #include "phy_if.h"
 
+/* FUSE calibration data. */
+#define	FUSE_XUSB_CALIB				0x0F0
+#define	  FUSE_XUSB_CALIB_HS_CURR_LEVEL_123(x)		(((x) >> 15) & 0x3F);
+#define	  FUSE_XUSB_CALIB_HS_IREF_CAP(x)		(((x) >> 13) & 0x03);
+#define	  FUSE_XUSB_CALIB_HS_SQUELCH_LEVEL(x)		(((x) >> 11) & 0x03);
+#define	  FUSE_XUSB_CALIB_HS_TERM_RANGE_ADJ(x)		(((x) >>  7) & 0x0F);
+#define	  FUSE_XUSB_CALIB_HS_CURR_LEVEL_0(x)		(((x) >>  0) & 0x3F);
+
+
+/* Registers. */
 #define	XUSB_PADCTL_USB2_PAD_MUX		0x004
 
+#define	XUSB_PADCTL_USB2_PORT_CAP		0x008
+#define	 USB2_PORT_CAP_ULPI_PORT_INTERNAL		(1 << 25)
+#define	 USB2_PORT_CAP_ULPI_PORT_CAP			(1 << 24)
+#define	 USB2_PORT_CAP_PORT_REVERSE_ID(p)		(1 << (3 + (p) * 4))
+#define	 USB2_PORT_CAP_PORT_INTERNAL(p)			(1 << (2 + (p) * 4))
+#define	 USB2_PORT_CAP_PORT_CAP(p, x)			(((x) & 3) << ((p) * 4))
+#define	  USB2_PORT_CAP_PORT_CAP_OTG			0x3
+#define	  USB2_PORT_CAP_PORT_CAP_DEVICE			0x2
+#define	  USB2_PORT_CAP_PORT_CAP_HOST			0x1
+#define	  USB2_PORT_CAP_PORT_CAP_DISABLED		0x0
+
+#define	XUSB_PADCTL_SS_PORT_MAP			0x014
+#define	 SS_PORT_MAP_PORT_INTERNAL(p)			(1 << (3 + (p) * 4))
+#define	 SS_PORT_MAP_PORT_MAP(p, x)			(((x) & 7) << ((p) * 4))
+
 #define	XUSB_PADCTL_ELPG_PROGRAM		0x01C
 #define	 ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN		(1 << 26)
 #define	 ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY	(1 << 25)
 #define	 ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN		(1 << 24)
+#define	 ELPG_PROGRAM_SSP_ELPG_VCORE_DOWN(x) 		(1 << (18 + (x) * 4))
+#define	 ELPG_PROGRAM_SSP_ELPG_CLAMP_EN_EARLY(x) 	(1 << (17 + (x) * 4))
+#define	 ELPG_PROGRAM_SSP_ELPG_CLAMP_EN(x)		(1 << (16 + (x) * 4))
 
 #define	XUSB_PADCTL_IOPHY_PLL_P0_CTL1		0x040
 #define	 IOPHY_PLL_P0_CTL1_PLL0_LOCKDET			(1 << 19)
-#define	 IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK		(0xf<< 12)
+#define	 IOPHY_PLL_P0_CTL1_REFCLK_SEL(x)		(((x) & 0xF) << 12)
 #define	 IOPHY_PLL_P0_CTL1_PLL_RST			(1 << 1)
 
 #define	XUSB_PADCTL_IOPHY_PLL_P0_CTL2		0x044
@@ -66,8 +97,59 @@
 #define	 IOPHY_PLL_P0_CTL2_TXCLKREF_EN			(1 << 5)
 #define	 IOPHY_PLL_P0_CTL2_TXCLKREF_SEL			(1 << 4)
 
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(x) 	(0x058 + (x) * 4)
+#define	 IOPHY_USB3_PAD_CTL2_CDR_CNTL(x)		(((x) & 0x00FF) <<  4)
+#define	 IOPHY_USB3_PAD_CTL2_RX_EQ(x)			(((x) & 0xFFFF) <<  8)
+#define	 IOPHY_USB3_PAD_CTL2_RX_WANDER(x)		(((x) & 0x000F) <<  4)
+#define	 IOPHY_USB3_PAD_CTL2_RX_TERM_CNTL(x)		(((x) & 0x0003) <<  2)
+#define	 IOPHY_USB3_PAD_CTL2_TX_TERM_CNTL(x)		(((x) & 0x0003) <<  0)
+
+
+#define	XUSB_PADCTL_IOPHY_USB3_PAD_CTL4(x)	(0x068 + (x) * 4)
+
+#define	XUSB_PADCTL_USB2_OTG_PAD_CTL0(x) 	(0x0A0 + (x) * 4)
+#define	 USB2_OTG_PAD_CTL0_LSBIAS_SEL			(1 << 23)
+#define	 USB2_OTG_PAD_CTL0_DISCON_DETECT_METHOD		(1 << 22)
+#define	 USB2_OTG_PAD_CTL0_PD_ZI			(1 << 21)
+#define	 USB2_OTG_PAD_CTL0_PD2				(1 << 20)
+#define	 USB2_OTG_PAD_CTL0_PD				(1 << 19)
+#define	 USB2_OTG_PAD_CTL0_TERM_EN			(1 << 18)
+#define	 USB2_OTG_PAD_CTL0_LS_LS_FSLEW(x)		(((x) & 0x03) << 16)
+#define	 USB2_OTG_PAD_CTL0_LS_RSLEW(x)			(((x) & 0x03) << 14)
+#define	 USB2_OTG_PAD_CTL0_FS_SLEW(x)			(((x) & 0x03) << 12)
+#define	 USB2_OTG_PAD_CTL0_HS_SLEW(x)			(((x) & 0x3F) <<  6)
+#define	 USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(x)		(((x) & 0x3F) <<  0)
+
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1(x) 	(0x0AC + (x) * 4)
+#define	 USB2_OTG_PAD_CTL1_RPU_RANGE_ADJ(x)		(((x) & 0x3) << 11)
+#define	 USB2_OTG_PAD_CTL1_HS_IREF_CAP(x)		(((x) & 0x3) <<  9)
+#define	 USB2_OTG_PAD_CTL1_SPARE(x)			(((x) & 0x3) <<  7)
+#define	 USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(x)		(((x) & 0xF) <<  3)
+#define	 USB2_OTG_PAD_CTL1_PD_DR			(1 <<  2)
+#define	 USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP	(1 <<  1)
+#define	 USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP	(1 <<  0)
+
+#define	XUSB_PADCTL_USB2_BIAS_PAD_CTL0		0x0B8
+#define	 USB2_BIAS_PAD_CTL0_ADJRPU(x)			(((x) & 0x7) << 14)
+#define	 USB2_BIAS_PAD_CTL0_PD_TRK			(1 << 13)
+#define	 USB2_BIAS_PAD_CTL0_PD				(1 << 12)
+#define	 USB2_BIAS_PAD_CTL0_TERM_OFFSETL(x)		(((x) & 0x3) <<  9)
+#define	 USB2_BIAS_PAD_CTL0_VBUS_LEVEL(x)		(((x) & 0x3) <<  7)
+#define	 USB2_BIAS_PAD_CTL0_HS_CHIRP_LEVEL(x)		(((x) & 0x3) <<  5)
+#define	 USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(x)		(((x) & 0x7) <<  2)
+#define	 USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(x)		(((x) & 0x3) <<  0)
+
+#define	XUSB_PADCTL_HSIC_PAD0_CTL0		0x0C8
+#define	 HSIC_PAD0_CTL0_HSIC_OPT(x)			(((x) & 0xF) << 16)
+#define	 HSIC_PAD0_CTL0_TX_SLEWN(x)			(((x) & 0xF) << 12)
+#define	 HSIC_PAD0_CTL0_TX_SLEWP(x)			(((x) & 0xF) <<  8)
+#define	 HSIC_PAD0_CTL0_TX_RTUNEN(x)			(((x) & 0xF) <<  4)
+#define	 HSIC_PAD0_CTL0_TX_RTUNEP(x)			(((x) & 0xF) <<  0)
 
 #define	XUSB_PADCTL_USB3_PAD_MUX		0x134
+#define	 USB3_PAD_MUX_PCIE_IDDQ_DISABLE(x) 		(1 << (1 + (x)))
+#define	 USB3_PAD_MUX_SATA_IDDQ_DISABLE 		(1 << 6)
+
 
 #define	XUSB_PADCTL_IOPHY_PLL_S0_CTL1		0x138
 #define	 IOPHY_PLL_S0_CTL1_PLL1_LOCKDET			(1 << 27)
@@ -90,17 +172,25 @@
 #define	XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5	0x158
 #define	XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6	0x15C
 
-struct lane_cfg {
-	char	*function;
-	char 	**lanes;
-	int 	iddq;
-};
 
-struct xusbpadctl_softc {
+#define	WR4(_sc, _r, _v)	bus_write_4((_sc)->mem_res, (_r), (_v))
+#define	RD4(_sc, _r)		bus_read_4((_sc)->mem_res, (_r))
+
+
+struct padctl_softc {
 	device_t	dev;
 	struct resource	*mem_res;
-	hwreset_t		rst;
+	hwreset_t	rst;
 	int		phy_ena_cnt;
+
+	/* Fuses calibration data */
+	uint32_t	hs_curr_level_0;
+	uint32_t	hs_curr_level_123;
+	uint32_t	hs_iref_cap;
+	uint32_t	hs_term_range_adj;
+	uint32_t	hs_squelch_level;
+
+	uint32_t	hs_curr_level_offset;
 };
 
 static struct ofw_compat_data compat_data[] = {
@@ -108,274 +198,295 @@ static struct ofw_compat_data compat_dat
 	{NULL,				0},
 };
 
-struct padctl_lane {
-	const char *name;
-	bus_size_t reg;
-	uint32_t shift;
-	uint32_t mask;
-	int iddq;
-	char **mux;
-	int nmux;
+/* Ports. */
+enum padctl_port_type {
+	PADCTL_PORT_USB2,
+	PADCTL_PORT_ULPI,
+	PADCTL_PORT_HSIC,
+	PADCTL_PORT_USB3,
 };
 
-static char *otg_mux[] = {"snps", "xusb", "uart", "rsvd"};
-static char *usb_mux[] = {"snps", "xusb"};
-static char *pci_mux[] = {"pcie", "usb3", "sata", "rsvd"};
-
-#define	LANE(n, r, s, m, i, mx)					\
-{								\
-	.name = n,						\
-	.reg = r,						\
-	.shift = s,						\
-	.mask = m,						\
-	.iddq = i,						\
-	.mux = mx,						\
-	.nmux = nitems(mx),					\
-}
-
-static const struct padctl_lane lanes_tbl[] = {
-	LANE("otg-0",  XUSB_PADCTL_USB2_PAD_MUX,  0, 0x3, -1, otg_mux),
-	LANE("otg-1",  XUSB_PADCTL_USB2_PAD_MUX,  2, 0x3, -1, otg_mux),
-	LANE("otg-2",  XUSB_PADCTL_USB2_PAD_MUX,  4, 0x3, -1, otg_mux),
-	LANE("ulpi-0", XUSB_PADCTL_USB2_PAD_MUX, 12, 0x1, -1, usb_mux),
-	LANE("hsic-0", XUSB_PADCTL_USB2_PAD_MUX, 14, 0x1, -1, usb_mux),
-	LANE("hsic-1", XUSB_PADCTL_USB2_PAD_MUX, 15, 0x1, -1, usb_mux),
-	LANE("pcie-0", XUSB_PADCTL_USB3_PAD_MUX, 16, 0x3,  1, pci_mux),
-	LANE("pcie-1", XUSB_PADCTL_USB3_PAD_MUX, 18, 0x3,  2, pci_mux),
-	LANE("pcie-2", XUSB_PADCTL_USB3_PAD_MUX, 20, 0x3,  3, pci_mux),
-	LANE("pcie-3", XUSB_PADCTL_USB3_PAD_MUX, 22, 0x3,  4, pci_mux),
-	LANE("pcie-4", XUSB_PADCTL_USB3_PAD_MUX, 24, 0x3,  5, pci_mux),
-	LANE("sata-0", XUSB_PADCTL_USB3_PAD_MUX, 26, 0x3,  6, pci_mux),
+struct padctl_lane;
+struct padctl_port {
+	enum padctl_port_type	type;
+	const char		*name;
+	const char		*base_name;
+	int			idx;
+	int			(*init)(struct padctl_softc *sc,
+				    struct padctl_port *port);
+
+	/* Runtime data. */
+	phandle_t		xref;
+	bool			enabled;
+	regulator_t		supply_vbus;	/* USB2, USB3 */
+	bool			internal;	/* ULPI, USB2, USB3 */
+	uint32_t		companion;	/* USB3 */
+	struct padctl_lane	*lane;
 };
 
-static int
-xusbpadctl_mux_function(const struct padctl_lane *lane, char *fnc_name)
-{
-	int i;
-
-	for (i = 0; i < lane->nmux; i++) {
-		if (strcmp(fnc_name, lane->mux[i]) == 0)
-			return 	(i);
-	}
+static int usb3_port_init(struct padctl_softc *sc, struct padctl_port *port);
 
-	return (-1);
+#define	PORT(t, n, p, i) {						\
+	.type = t,							\
+	.name = n "-" #p,						\
+	.base_name = n,							\
+	.idx = p,							\
+	.init = i,							\
 }
+static struct padctl_port ports_tbl[] = {
+	PORT(PADCTL_PORT_USB2, "usb2", 0, NULL),
+	PORT(PADCTL_PORT_USB2, "usb2", 1, NULL),
+	PORT(PADCTL_PORT_USB2, "usb2", 2, NULL),
+	PORT(PADCTL_PORT_ULPI, "ulpi", 0, NULL),
+	PORT(PADCTL_PORT_HSIC, "hsic", 0, NULL),
+	PORT(PADCTL_PORT_HSIC, "hsic", 1, NULL),
+	PORT(PADCTL_PORT_USB3, "usb3", 0, usb3_port_init),
+	PORT(PADCTL_PORT_USB3, "usb3", 1, usb3_port_init),
+};
 
-static int
-xusbpadctl_config_lane(struct xusbpadctl_softc *sc, char *lane_name,
-    const struct padctl_lane *lane, struct lane_cfg *cfg)
-{
-
-	int tmp;
-	uint32_t reg;
+/* Pads - a group of lannes. */
+enum padctl_pad_type {
+	PADCTL_PAD_USB2,
+	PADCTL_PAD_ULPI,
+	PADCTL_PAD_HSIC,
+	PADCTL_PAD_PCIE,
+	PADCTL_PAD_SATA,
+};
 
-	reg = bus_read_4(sc->mem_res, lane->reg);
-	if (cfg->function != NULL) {
-		tmp = xusbpadctl_mux_function(lane, cfg->function);
-		if (tmp == -1) {
-			device_printf(sc->dev,
-			    "Unknown function %s for lane %s\n", cfg->function,
-			    lane_name);
-			return (EINVAL);
-		}
-		reg &= ~(lane->mask << lane->shift);
-		reg |=  (tmp & lane->mask) << lane->shift;
-	}
-	if (cfg->iddq != -1) {
-		if (lane->iddq == -1) {
-			device_printf(sc->dev, "Invalid IDDQ for lane %s\n",
-			lane_name);
-			return (EINVAL);
-		}
-		if (cfg->iddq != 0)
-			reg &= ~(1 << lane->iddq);
-		else
-			reg |= 1 << lane->iddq;
-	}
+struct padctl_lane;
+struct padctl_pad {
+	const char		*name;
+	enum padctl_pad_type	type;
+	int			(*powerup)(struct padctl_softc *sc,
+				    struct padctl_lane *lane);
+	int			(*powerdown)(struct padctl_softc *sc,
+				    struct padctl_lane *lane);
+	/* Runtime data. */
+	bool			enabled;
+	struct padctl_lane	*lanes[8]; 	/* Safe maximum value. */
+	int			nlanes;
+};
 
-	bus_write_4(sc->mem_res, lane->reg, reg);
-	return (0);
+static int usb2_powerup(struct padctl_softc *sc, struct padctl_lane *lane);
+static int usb2_powerdown(struct padctl_softc *sc, struct padctl_lane *lane);
+static int pcie_powerup(struct padctl_softc *sc, struct padctl_lane *lane);
+static int pcie_powerdown(struct padctl_softc *sc, struct padctl_lane *lane);
+static int sata_powerup(struct padctl_softc *sc, struct padctl_lane *lane);
+static int sata_powerdown(struct padctl_softc *sc, struct padctl_lane *lane);
+
+#define	PAD(n, t, u, d) {						\
+	.name = n,							\
+	.type = t,							\
+	.powerup = u,							\
+	.powerdown = d,							\
 }
+static struct padctl_pad pads_tbl[] = {
+	PAD("usb2", PADCTL_PAD_USB2, usb2_powerup, usb2_powerdown),
+	PAD("ulpi", PADCTL_PAD_ULPI, NULL, NULL),
+	PAD("hsic", PADCTL_PAD_HSIC, NULL, NULL),
+	PAD("pcie", PADCTL_PAD_PCIE, pcie_powerup, pcie_powerdown),
+	PAD("sata", PADCTL_PAD_SATA, sata_powerup, sata_powerdown),
+};
 
-static const struct padctl_lane *
-xusbpadctl_search_lane(char *lane_name)
-{
-	int i;
-
-	for (i = 0; i < nitems(lanes_tbl); i++) {
-		if (strcmp(lane_name, lanes_tbl[i].name) == 0)
-			return 	(&lanes_tbl[i]);
-	}
+/* Lanes. */
+static char *otg_mux[] = {"snps", "xusb", "uart", "rsvd"};
+static char *usb_mux[] = {"snps", "xusb"};
+static char *pci_mux[] = {"pcie", "usb3-ss", "sata", "rsvd"};
 
-	return (NULL);
-}
+struct padctl_lane {
+	const char		*name;
+	int			idx;
+	bus_size_t		reg;
+	uint32_t		shift;
+	uint32_t		mask;
+	char			**mux;
+	int			nmux;
+	/* Runtime data. */
+	bool			enabled;
+	phandle_t		xref;
+	struct padctl_pad	*pad;
+	struct padctl_port	*port;
+	int			mux_idx;
 
-static int
-xusbpadctl_config_node(struct xusbpadctl_softc *sc, char *lane_name,
-    struct lane_cfg *cfg)
-{
-	const struct padctl_lane *lane;
-	int rv;
+};
 
-	lane = xusbpadctl_search_lane(lane_name);
-	if (lane == NULL) {
-		device_printf(sc->dev, "Unknown lane: %s\n", lane_name);
-		return (ENXIO);
-	}
-	rv = xusbpadctl_config_lane(sc, lane_name, lane, cfg);
-	return (rv);
+#define	LANE(n, p, r, s, m, mx) {					\
+	.name = n "-" #p,						\
+	.idx = p,							\
+	.reg = r,							\
+	.shift = s,							\
+	.mask = m,							\
+	.mux = mx,							\
+	.nmux = nitems(mx),						\
 }
+static struct padctl_lane lanes_tbl[] = {
+	LANE("usb2", 0, XUSB_PADCTL_USB2_PAD_MUX,  0, 0x3, otg_mux),
+	LANE("usb2", 1, XUSB_PADCTL_USB2_PAD_MUX,  2, 0x3, otg_mux),
+	LANE("usb2", 2, XUSB_PADCTL_USB2_PAD_MUX,  4, 0x3, otg_mux),
+	LANE("ulpi", 0, XUSB_PADCTL_USB2_PAD_MUX, 12, 0x1, usb_mux),
+	LANE("hsic", 0, XUSB_PADCTL_USB2_PAD_MUX, 14, 0x1, usb_mux),
+	LANE("hsic", 1, XUSB_PADCTL_USB2_PAD_MUX, 15, 0x1, usb_mux),
+	LANE("pcie", 0, XUSB_PADCTL_USB3_PAD_MUX, 16, 0x3, pci_mux),
+	LANE("pcie", 1, XUSB_PADCTL_USB3_PAD_MUX, 18, 0x3, pci_mux),
+	LANE("pcie", 2, XUSB_PADCTL_USB3_PAD_MUX, 20, 0x3, pci_mux),
+	LANE("pcie", 3, XUSB_PADCTL_USB3_PAD_MUX, 22, 0x3, pci_mux),
+	LANE("pcie", 4, XUSB_PADCTL_USB3_PAD_MUX, 24, 0x3, pci_mux),
+	LANE("sata", 0, XUSB_PADCTL_USB3_PAD_MUX, 26, 0x3, pci_mux),
+};
 
-static int
-xusbpadctl_read_node(struct xusbpadctl_softc *sc, phandle_t node,
-    struct lane_cfg *cfg, char **lanes, int *llanes)
-{
-	int rv;
-
-	*llanes = OF_getprop_alloc(node, "nvidia,lanes", 1, (void **)lanes);
-	if (*llanes <= 0)
-		return (ENOENT);
+/* Define all possible mappings for USB3 port lanes */
+struct padctl_lane_map {
+	int			port_idx;
+	enum padctl_pad_type	pad_type;
+	int			lane_idx;
+};
 
-	/* Read function (mux) settings. */
-	rv = OF_getprop_alloc(node, "nvidia,function", 1,
-	    (void **)&cfg->function);
-	if (rv <= 0)
-		cfg->function = NULL;
-	/* Read numeric properties. */
-	rv = OF_getencprop(node, "nvidia,iddq", &cfg->iddq,
-	    sizeof(cfg->iddq));
-	if (rv <= 0)
-		cfg->iddq = -1;
-	return (0);
+#define	LANE_MAP(pi, pt, li) {						\
+	.port_idx = pi,							\
+	.pad_type = pt,							\
+	.lane_idx = li,							\
 }
+static struct padctl_lane_map lane_map_tbl[] = {
+	LANE_MAP(0, PADCTL_PAD_PCIE, 0), 	/* port USB3-0 -> lane PCIE-0 */
+	LANE_MAP(1, PADCTL_PAD_PCIE, 1), 	/* port USB3-1 -> lane PCIE-1 */
+						/* -- or -- */
+	LANE_MAP(1, PADCTL_PAD_SATA, 0), 	/* port USB3-1 -> lane SATA-0 */
+};
 
+static struct padctl_port *search_lane_port(struct padctl_softc *sc,
+    struct padctl_lane *lane);
+/* -------------------------------------------------------------------------
+ *
+ *   PHY functions
+ */
 static int
-xusbpadctl_process_node(struct xusbpadctl_softc *sc, phandle_t node)
+usb3_port_init(struct padctl_softc *sc, struct padctl_port *port)
 {
-	struct lane_cfg cfg;
-	char *lanes, *lname;
-	int i, len, llanes, rv;
-
-	rv = xusbpadctl_read_node(sc, node, &cfg, &lanes, &llanes);
-	if (rv != 0)
-		return (rv);
-
-	len = 0;
-	lname = lanes;
-	do {
-		i = strlen(lname) + 1;
-		rv = xusbpadctl_config_node(sc, lname, &cfg);
-		if (rv != 0)
-			device_printf(sc->dev,
-			    "Cannot configure lane: %s: %d\n", lname, rv);
-
-		len += i;
-		lname += i;
-	} while (len < llanes);
-
-	if (lanes != NULL)
-		OF_prop_free(lanes);
-	if (cfg.function != NULL)
-		OF_prop_free(cfg.function);
-	return (rv);
-}
-
+	uint32_t reg;
 
-static int
-xusbpadctl_pinctrl_cfg(device_t dev, phandle_t cfgxref)
-{
-	struct xusbpadctl_softc *sc;
-	phandle_t node, cfgnode;
-	int rv;
+	reg = RD4(sc, XUSB_PADCTL_SS_PORT_MAP);
+	if (port->internal)
+		reg &= ~SS_PORT_MAP_PORT_INTERNAL(port->idx);
+	else
+		reg |= SS_PORT_MAP_PORT_INTERNAL(port->idx);
+	reg &= ~SS_PORT_MAP_PORT_MAP(port->idx, ~0);
+	reg |= SS_PORT_MAP_PORT_MAP(port->idx, port->companion);
+	WR4(sc, XUSB_PADCTL_SS_PORT_MAP, reg);
+
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(port->idx));
+	reg &= ~IOPHY_USB3_PAD_CTL2_CDR_CNTL(~0);
+	reg &= ~IOPHY_USB3_PAD_CTL2_RX_EQ(~0);
+	reg &= ~IOPHY_USB3_PAD_CTL2_RX_WANDER(~0);
+	reg |= IOPHY_USB3_PAD_CTL2_CDR_CNTL(0x24);
+	reg |= IOPHY_USB3_PAD_CTL2_RX_EQ(0xF070);
+	reg |= IOPHY_USB3_PAD_CTL2_RX_WANDER(0xF);
+	WR4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL2(port->idx), reg);
+
+	WR4(sc, XUSB_PADCTL_IOPHY_USB3_PAD_CTL4(port->idx),
+	    0x002008EE);
+
+	reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM);
+	reg &= ~ELPG_PROGRAM_SSP_ELPG_VCORE_DOWN(port->idx);
+	WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg);
+	DELAY(100);
 
-	sc = device_get_softc(dev);
-	cfgnode = OF_node_from_xref(cfgxref);
+	reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM);
+	reg &= ~ELPG_PROGRAM_SSP_ELPG_CLAMP_EN_EARLY(port->idx);
+	WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg);
+	DELAY(100);
 
-	rv = 0;
-	for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {
-		if (!fdt_is_enabled(node))
-			continue;
-		rv = xusbpadctl_process_node(sc, node);
-		if (rv != 0)
-			return (rv);
-	}
+	reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM);
+	reg &= ~ELPG_PROGRAM_SSP_ELPG_CLAMP_EN(port->idx);
+	WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg);
+	DELAY(100);
 
-	return (rv);
+	return (0);
 }
 
 static int
-xusbpadctl_phy_pcie_powerup(struct xusbpadctl_softc *sc)
+pcie_powerup(struct padctl_softc *sc, struct padctl_lane *lane)
 {
 	uint32_t reg;
 	int i;
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
-	reg &= ~IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	reg &= ~IOPHY_PLL_P0_CTL1_REFCLK_SEL(~0);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg);
 	DELAY(100);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
 	reg |= IOPHY_PLL_P0_CTL2_REFCLKBUF_EN;
 	reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_EN;
 	reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_SEL;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL2, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL2, reg);
 	DELAY(100);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 	reg |= IOPHY_PLL_P0_CTL1_PLL_RST;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg);
 	DELAY(100);
 
-	for (i = 0; i < 100; i++) {
-		reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	for (i = 100; i > 0; i--) {
+		reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 		if (reg & IOPHY_PLL_P0_CTL1_PLL0_LOCKDET)
-			return (0);
+			break;
 		DELAY(10);
 	}
+	if (i <= 0) {
+		device_printf(sc->dev, "Failed to power up PCIe phy\n");
+		return (ETIMEDOUT);
+	}
+	reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX);
+	reg |= USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx);
+	WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg);
 
-	return (ETIMEDOUT);
+	return (0);
 }
 
-
 static int
-xusbpadctl_phy_pcie_powerdown(struct xusbpadctl_softc *sc)
+pcie_powerdown(struct padctl_softc *sc, struct padctl_lane *lane)
 {
 	uint32_t reg;
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX);
+	reg &= ~USB3_PAD_MUX_PCIE_IDDQ_DISABLE(lane->idx);
+	WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg);
+
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
 	reg &= ~IOPHY_PLL_P0_CTL1_PLL_RST;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg);
 	DELAY(100);
+
 	return (0);
 
 }
 
 static int
-xusbpadctl_phy_sata_powerup(struct xusbpadctl_softc *sc)
+sata_powerup(struct padctl_softc *sc, struct padctl_lane *lane)
 {
 	uint32_t reg;
 	int i;
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
 	reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
 	reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 	reg &= ~IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
 	reg &= ~IOPHY_PLL_S0_CTL1_PLL_IDDQ;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 	reg |= IOPHY_PLL_S0_CTL1_PLL1_MODE;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 	reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
 
 	for (i = 100; i >= 0; i--) {
-		reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+		reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 		if (reg & IOPHY_PLL_S0_CTL1_PLL1_LOCKDET)
 			break;
 		DELAY(100);
@@ -384,81 +495,188 @@ xusbpadctl_phy_sata_powerup(struct xusbp
 		device_printf(sc->dev, "Failed to power up SATA phy\n");
 		return (ETIMEDOUT);
 	}
+	reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX);
+	reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L;
+	WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg);
+
+	reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX);
+	reg |= USB3_PAD_MUX_SATA_IDDQ_DISABLE;
+	WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg);
 
 	return (0);
 }
 
 static int
-xusbpadctl_phy_sata_powerdown(struct xusbpadctl_softc *sc)
+sata_powerdown(struct padctl_softc *sc, struct padctl_lane *lane)
 {
 	uint32_t reg;
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_USB3_PAD_MUX);
+	reg &= ~USB3_PAD_MUX_SATA_IDDQ_DISABLE;
+	WR4(sc, XUSB_PADCTL_USB3_PAD_MUX, reg);
+
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 	reg &= ~IOPHY_PLL_S0_CTL1_PLL_RST_L;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
 	DELAY(100);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 	reg &= ~IOPHY_PLL_S0_CTL1_PLL1_MODE;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
 	DELAY(100);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
 	reg |= IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
 	reg |= IOPHY_PLL_S0_CTL1_PLL_IDDQ;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
 	DELAY(100);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+	reg = RD4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
 	reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
 	reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg);
+	WR4(sc, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg);
 	DELAY(100);
 
 	return (0);
 }
 
 static int
-xusbpadctl_phy_powerup(struct xusbpadctl_softc *sc)
+usb2_powerup(struct padctl_softc *sc, struct padctl_lane *lane)
 {
 	uint32_t reg;
+	struct padctl_port *port;
+	int rv;
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
-	reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+	port = search_lane_port(sc, lane);
+	if (port == NULL) {
+		device_printf(sc->dev, "Cannot find port for lane: %s\n",
+		    lane->name);
+	}
+	reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	reg &= ~USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(~0);
+	reg &= ~USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(~0);
+	reg |= USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL(sc->hs_squelch_level);
+	reg |= USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL(5);
+	WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg);
+
+	reg = RD4(sc, XUSB_PADCTL_USB2_PORT_CAP);
+	reg &= ~USB2_PORT_CAP_PORT_CAP(lane->idx, ~0);
+	reg |= USB2_PORT_CAP_PORT_CAP(lane->idx, USB2_PORT_CAP_PORT_CAP_HOST);
+	WR4(sc, XUSB_PADCTL_USB2_PORT_CAP, reg);
+
+	reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx));
+	reg &= ~USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(~0);
+	reg &= ~USB2_OTG_PAD_CTL0_HS_SLEW(~0);
+	reg &= ~USB2_OTG_PAD_CTL0_LS_RSLEW(~0);
+	reg &= ~USB2_OTG_PAD_CTL0_PD;
+	reg &= ~USB2_OTG_PAD_CTL0_PD2;
+	reg &= ~USB2_OTG_PAD_CTL0_PD_ZI;
+
+	reg |= USB2_OTG_PAD_CTL0_HS_SLEW(14);
+	if (lane->idx == 0) {
+		reg |= USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(sc->hs_curr_level_0);
+		reg |= USB2_OTG_PAD_CTL0_LS_RSLEW(3);
+	} else {
+		reg |= USB2_OTG_PAD_CTL0_HS_CURR_LEVEL(sc->hs_curr_level_123);
+		reg |= USB2_OTG_PAD_CTL0_LS_RSLEW(0);
+	}
+	WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL0(lane->idx), reg);
+
+	reg = RD4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx));
+	reg &= ~USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(~0);
+	reg &= ~USB2_OTG_PAD_CTL1_HS_IREF_CAP(~0);
+	reg &= ~USB2_OTG_PAD_CTL1_PD_DR;
+	reg &= ~USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP;
+	reg &= ~USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP;
+
+	reg |= USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ(sc->hs_term_range_adj);
+	reg |= USB2_OTG_PAD_CTL1_HS_IREF_CAP(sc->hs_iref_cap);
+	WR4(sc, XUSB_PADCTL_USB2_OTG_PAD_CTL1(lane->idx), reg);
+
+	if (port != NULL && port->supply_vbus != NULL) {
+		rv = regulator_enable(port->supply_vbus);
+		if (rv != 0) {
+			device_printf(sc->dev,
+			    "Cannot enable vbus regulator\n");
+			return (rv);
+		}
+	}
+	reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	reg &= ~USB2_BIAS_PAD_CTL0_PD;
+	WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg);
+
+	return (0);
+}
+
+static int
+usb2_powerdown(struct padctl_softc *sc, struct padctl_lane *lane)
+{
+	uint32_t reg;
+	struct padctl_port *port;
+	int rv;
+
+	port = search_lane_port(sc, lane);
+	if (port == NULL) {
+		device_printf(sc->dev, "Cannot find port for lane: %s\n",
+		    lane->name);
+	}
+	reg = RD4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	reg |= USB2_BIAS_PAD_CTL0_PD;
+	WR4(sc, XUSB_PADCTL_USB2_BIAS_PAD_CTL0, reg);
+
+	if (port != NULL && port->supply_vbus != NULL) {
+		rv = regulator_enable(port->supply_vbus);
+		if (rv != 0) {
+			device_printf(sc->dev,
+			    "Cannot disable vbus regulator\n");
+			return (rv);
+		}
+	}
+	return (0);
+}
+
+
+static int
+phy_powerup(struct padctl_softc *sc)
+{
+	uint32_t reg;
+
+	reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM);
+	reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
+	WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg);
 	DELAY(100);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
-	reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+	reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM);
+	reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
+	WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg);
 	DELAY(100);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
-	reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+	reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM);
+	reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
+	WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg);
 	DELAY(100);
 
 	return (0);
 }
 
 static int
-xusbpadctl_phy_powerdown(struct xusbpadctl_softc *sc)
+phy_powerdown(struct padctl_softc *sc)
 {
 	uint32_t reg;
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
-	reg |= ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
-	DELAY(100);
-
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
+	reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM);
 	reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+	WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg);
 	DELAY(100);
 
-	reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
+	reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM);
 	reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
-	bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+	WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg);
+	DELAY(100);
+
+	reg = RD4(sc, XUSB_PADCTL_ELPG_PROGRAM);
+	reg |= ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
+	WR4(sc, XUSB_PADCTL_ELPG_PROGRAM, reg);
 	DELAY(100);
 
 	return (0);
@@ -467,45 +685,43 @@ xusbpadctl_phy_powerdown(struct xusbpadc
 static int
 xusbpadctl_phy_enable(device_t dev, intptr_t id, bool enable)
 {
-	struct xusbpadctl_softc *sc;
+	struct padctl_softc *sc;
+	struct padctl_lane *lane;
+	struct padctl_pad *pad;
 	int rv;
 
 	sc = device_get_softc(dev);
 
-	if ((id != TEGRA_XUSB_PADCTL_PCIE) &&
-	    (id != TEGRA_XUSB_PADCTL_SATA)) {
+	if (id < 0 || id >= nitems(lanes_tbl)) {
 		device_printf(dev, "Unknown phy: %d\n", id);
 		return (ENXIO);
 	}
-
-	rv = 0;
+	lane = lanes_tbl + id;
+	if (!lane->enabled) {
+		device_printf(dev, "Lane is not enabled/configured: %s\n",
+		    lane->name);
+		return (ENXIO);
+	}
+	pad = lane->pad;
 	if (enable) {
 		if (sc->phy_ena_cnt == 0) {
-			rv = xusbpadctl_phy_powerup(sc);
+			rv = phy_powerup(sc);
 			if (rv != 0)
 				return (rv);
 		}
 		sc->phy_ena_cnt++;
 	}
 
-	if (id == TEGRA_XUSB_PADCTL_PCIE) {
-		if (enable)
-			rv = xusbpadctl_phy_pcie_powerup(sc);
-		else
-			rv = xusbpadctl_phy_pcie_powerdown(sc);
-		if (rv != 0)
-			return (rv);
-	} else if (id == TEGRA_XUSB_PADCTL_SATA) {
-		if (enable)
-			rv = xusbpadctl_phy_sata_powerup(sc);
-		else
-			rv = xusbpadctl_phy_sata_powerdown(sc);
-		if (rv != 0)
-			return (rv);
-	}
+	if (enable)
+		rv = pad->powerup(sc, lane);
+	else
+		rv = pad->powerdown(sc, lane);
+	if (rv != 0)
+		return (rv);
+
 	if (!enable) {
 		 if (sc->phy_ena_cnt == 1) {
-			rv = xusbpadctl_phy_powerdown(sc);
+			rv = phy_powerdown(sc);
 			if (rv != 0)
 				return (rv);
 		}
@@ -516,6 +732,387 @@ xusbpadctl_phy_enable(device_t dev, intp
 }
 
 static int
+xusbpadctl_phy_map(device_t provider, phandle_t xref, int ncells,
+    pcell_t *cells, intptr_t *id)
+{
+	int i;
+
+	if (ncells != 0)
+		return  (ERANGE);
+
+	for (i = 0; i < nitems(lanes_tbl); i++) {
+		if (lanes_tbl[i].xref == xref) {
+			*id = i;
+			return (0);
+		}
+	}
+	return (ENXIO);
+}
+
+/* -------------------------------------------------------------------------
+ *
+ *   FDT processing
+ */
+static struct padctl_port *
+search_port(struct padctl_softc *sc, char *port_name)
+{
+	int i;
+
+	for (i = 0; i < nitems(ports_tbl); i++) {
+		if (strcmp(port_name, ports_tbl[i].name) == 0)
+			return (&ports_tbl[i]);
+	}
+	return (NULL);
+}
+
+static struct padctl_port *
+search_lane_port(struct padctl_softc *sc, struct padctl_lane *lane)
+{
+	int i;
+
+	for (i = 0; i < nitems(ports_tbl); i++) {
+		if (!ports_tbl[i].enabled)
+			continue;
+		if (ports_tbl[i].lane == lane)
+			return (ports_tbl + i);
+	}
+	return (NULL);
+}
+
+static struct padctl_lane *
+search_lane(struct padctl_softc *sc, char *lane_name)
+{
+	int i;
+
+	for (i = 0; i < nitems(lanes_tbl); i++) {
+		if (strcmp(lane_name, lanes_tbl[i].name) == 0)
+			return 	(lanes_tbl + i);
+	}
+	return (NULL);
+}
+
+static struct padctl_lane *
+search_pad_lane(struct padctl_softc *sc, enum padctl_pad_type type, int idx)
+{
+	int i;
+
+	for (i = 0; i < nitems(lanes_tbl); i++) {
+		if (!lanes_tbl[i].enabled)
+			continue;
+		if (type == lanes_tbl[i].pad->type && idx == lanes_tbl[i].idx)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list