usb: host: tegra: get usb phy configuration from phy node

Obtain USB phy configuration from phy node if such exists
and is enabled. If no, set default values.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 343893b..7c73eb6 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -66,9 +66,24 @@
 	USB_CTRL_COUNT,
 };
 
+struct tegra_utmip_config {
+	u32 hssync_start_delay;
+	u32 elastic_limit;
+	u32 idle_wait_delay;
+	u32 term_range_adj;
+	bool xcvr_setup_use_fuses;
+	u32 xcvr_setup;
+	u32 xcvr_lsfslew;
+	u32 xcvr_lsrslew;
+	u32 xcvr_hsslew;
+	u32 hssquelch_level;
+	u32 hsdiscon_level;
+};
+
 /* Information about a USB port */
 struct fdt_usb {
 	struct ehci_ctrl ehci;
+	struct tegra_utmip_config utmip_config;
 	struct usb_ctlr *reg;	/* address of registers in physical memory */
 	unsigned utmi:1;	/* 1 if port has external tranceiver, else 0 */
 	unsigned ulpi:1;	/* 1 if port has external ULPI transceiver */
@@ -192,15 +207,6 @@
 	{ 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  65000,  5 }
 };
 
-/* UTMIP Idle Wait Delay */
-static const u8 utmip_idle_wait_delay = 17;
-
-/* UTMIP Elastic limit */
-static const u8 utmip_elastic_limit = 16;
-
-/* UTMIP High Speed Sync Start Delay */
-static const u8 utmip_hs_sync_start_delay = 9;
-
 struct fdt_usb_controller {
 	/* flag to determine whether controller supports hostpc register */
 	u32 has_hostpc:1;
@@ -377,6 +383,7 @@
 	u32 b_sess_valid_mask, val;
 	int loop_count;
 	const unsigned *timing;
+	struct tegra_utmip_config *utmip_config = &config->utmip_config;
 	struct usb_ctlr *usbctlr = config->reg;
 	struct clk_rst_ctlr *clkrst;
 	struct usb_ctlr *usb1ctlr;
@@ -463,16 +470,29 @@
 
 		/* Recommended PHY settings for EYE diagram */
 		val = readl(&usbctlr->utmip_xcvr_cfg0);
-		clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MASK,
-				0x4 << UTMIP_XCVR_SETUP_SHIFT);
-		clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MSB_MASK,
-				0x3 << UTMIP_XCVR_SETUP_MSB_SHIFT);
-		clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW_MSB_MASK,
-				0x8 << UTMIP_XCVR_HSSLEW_MSB_SHIFT);
+
+		if (!utmip_config->xcvr_setup_use_fuses) {
+			clrsetbits_le32(&val, UTMIP_XCVR_SETUP(~0),
+					UTMIP_XCVR_SETUP(utmip_config->xcvr_setup));
+			clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MSB(~0),
+					UTMIP_XCVR_SETUP_MSB(utmip_config->xcvr_setup));
+		}
+
+		clrsetbits_le32(&val, UTMIP_XCVR_LSFSLEW(~0),
+				UTMIP_XCVR_LSFSLEW(utmip_config->xcvr_lsfslew));
+		clrsetbits_le32(&val, UTMIP_XCVR_LSRSLEW(~0),
+				UTMIP_XCVR_LSRSLEW(utmip_config->xcvr_lsrslew));
+
+		clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW(~0),
+				UTMIP_XCVR_HSSLEW(utmip_config->xcvr_hsslew));
+		clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW_MSB(~0),
+				UTMIP_XCVR_HSSLEW_MSB(utmip_config->xcvr_hsslew));
 		writel(val, &usbctlr->utmip_xcvr_cfg0);
+
 		clrsetbits_le32(&usbctlr->utmip_xcvr_cfg1,
 				UTMIP_XCVR_TERM_RANGE_ADJ_MASK,
-				0x7 << UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT);
+				utmip_config->term_range_adj <<
+				UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT);
 
 		/* Some registers can be controlled from USB1 only. */
 		if (config->periph_id != PERIPH_ID_USBD) {
@@ -485,9 +505,11 @@
 		val = readl(&usb1ctlr->utmip_bias_cfg0);
 		setbits_le32(&val, UTMIP_HSDISCON_LEVEL_MSB);
 		clrsetbits_le32(&val, UTMIP_HSDISCON_LEVEL_MASK,
-				0x1 << UTMIP_HSDISCON_LEVEL_SHIFT);
+				utmip_config->hsdiscon_level <<
+				UTMIP_HSDISCON_LEVEL_SHIFT);
 		clrsetbits_le32(&val, UTMIP_HSSQUELCH_LEVEL_MASK,
-				0x2 << UTMIP_HSSQUELCH_LEVEL_SHIFT);
+				utmip_config->hssquelch_level <<
+				UTMIP_HSSQUELCH_LEVEL_SHIFT);
 		writel(val, &usb1ctlr->utmip_bias_cfg0);
 
 		/* Miscellaneous setting mentioned in Programming Guide */
@@ -521,7 +543,11 @@
 	setbits_le32(&usbctlr->utmip_bat_chrg_cfg0, UTMIP_PD_CHRG);
 
 	clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_XCVR_LSBIAS_SE);
-	setbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL);
+
+	if (utmip_config->xcvr_setup_use_fuses)
+		setbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL);
+	else
+		clrbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL);
 
 	/*
 	 * Configure the UTMIP_IDLE_WAIT and UTMIP_ELASTIC_LIMIT
@@ -535,15 +561,16 @@
 	/* Set PLL enable delay count and Crystal frequency count */
 	val = readl(&usbctlr->utmip_hsrx_cfg0);
 	clrsetbits_le32(&val, UTMIP_IDLE_WAIT_MASK,
-		utmip_idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT);
+		utmip_config->idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT);
 	clrsetbits_le32(&val, UTMIP_ELASTIC_LIMIT_MASK,
-		utmip_elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT);
+		utmip_config->elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT);
 	writel(val, &usbctlr->utmip_hsrx_cfg0);
 
 	/* Configure the UTMIP_HS_SYNC_START_DLY */
 	clrsetbits_le32(&usbctlr->utmip_hsrx_cfg1,
 		UTMIP_HS_SYNC_START_DLY_MASK,
-		utmip_hs_sync_start_delay << UTMIP_HS_SYNC_START_DLY_SHIFT);
+		utmip_config->hssync_start_delay <<
+		UTMIP_HS_SYNC_START_DLY_SHIFT);
 
 	/* Preceed the crystal clock disable by >100ns delay. */
 	udelay(1);
@@ -763,6 +790,69 @@
 	return 0;
 }
 
+static void fdt_decode_usb_phy(struct udevice *dev)
+{
+	struct fdt_usb *priv = dev_get_priv(dev);
+	struct tegra_utmip_config *utmip_config = &priv->utmip_config;
+	u32 usb_phy_phandle;
+	ofnode usb_phy_node;
+	int ret;
+
+	ret = ofnode_read_u32(dev_ofnode(dev), "nvidia,phy", &usb_phy_phandle);
+	if (ret)
+		log_debug("%s: required usb phy node isn't provided\n", __func__);
+
+	usb_phy_node = ofnode_get_by_phandle(usb_phy_phandle);
+	if (!ofnode_valid(usb_phy_node) || !ofnode_is_enabled(usb_phy_node)) {
+		log_debug("%s: failed to find usb phy node or it is disabled\n", __func__);
+		utmip_config->xcvr_setup_use_fuses = true;
+	} else {
+		utmip_config->xcvr_setup_use_fuses =
+			ofnode_read_bool(usb_phy_node, "nvidia,xcvr-setup-use-fuses");
+	}
+
+	utmip_config->hssync_start_delay =
+		ofnode_read_u32_default(usb_phy_node,
+					"nvidia,hssync-start-delay", 0x9);
+
+	utmip_config->elastic_limit =
+		ofnode_read_u32_default(usb_phy_node,
+					"nvidia,elastic-limit", 0x10);
+
+	utmip_config->idle_wait_delay =
+		ofnode_read_u32_default(usb_phy_node,
+					"nvidia,idle-wait-delay", 0x11);
+
+	utmip_config->term_range_adj =
+		ofnode_read_u32_default(usb_phy_node,
+					"nvidia,term-range-adj", 0x7);
+
+	utmip_config->xcvr_lsfslew =
+		ofnode_read_u32_default(usb_phy_node,
+					"nvidia,xcvr-lsfslew", 0x0);
+
+	utmip_config->xcvr_lsrslew =
+		ofnode_read_u32_default(usb_phy_node,
+					"nvidia,xcvr-lsrslew", 0x3);
+
+	utmip_config->xcvr_hsslew =
+		ofnode_read_u32_default(usb_phy_node,
+					"nvidia,xcvr-hsslew", 0x8);
+
+	utmip_config->hssquelch_level =
+		ofnode_read_u32_default(usb_phy_node,
+					"nvidia,hssquelch-level", 0x2);
+
+	utmip_config->hsdiscon_level =
+		ofnode_read_u32_default(usb_phy_node,
+					"nvidia,hsdiscon-level", 0x1);
+
+	if (!utmip_config->xcvr_setup_use_fuses) {
+		ofnode_read_u32(usb_phy_node, "nvidia,xcvr-setup",
+				&utmip_config->xcvr_setup);
+	}
+}
+
 int usb_common_init(struct fdt_usb *config, enum usb_init_type init)
 {
 	int ret = 0;
@@ -850,6 +940,8 @@
 
 	priv->type = dev_get_driver_data(dev);
 
+	fdt_decode_usb_phy(dev);
+
 	return 0;
 }