From 43800d7f6d7e38ecfd12889276851b1d1a9fc07f Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Thu, 17 Aug 2023 20:15:18 +0300 Subject: [PATCH] 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 --- arch/arm/include/asm/arch-tegra/usb.h | 11 ++- drivers/usb/host/ehci-tegra.c | 136 +++++++++++++++++++++----- 2 files changed, 121 insertions(+), 26 deletions(-) diff --git a/arch/arm/include/asm/arch-tegra/usb.h b/arch/arm/include/asm/arch-tegra/usb.h index 6e6ea1443c..2ae109ab6c 100644 --- a/arch/arm/include/asm/arch-tegra/usb.h +++ b/arch/arm/include/asm/arch-tegra/usb.h @@ -336,10 +336,13 @@ struct usb_ctlr { #define UTMIP_XCVR_HSSLEW_MSB_SHIFT 25 #define UTMIP_XCVR_HSSLEW_MSB_MASK \ (0x7f << UTMIP_XCVR_HSSLEW_MSB_SHIFT) -#define UTMIP_XCVR_SETUP_MSB_SHIFT 22 -#define UTMIP_XCVR_SETUP_MSB_MASK (0x7 << UTMIP_XCVR_SETUP_MSB_SHIFT) -#define UTMIP_XCVR_SETUP_SHIFT 0 -#define UTMIP_XCVR_SETUP_MASK (0xf << UTMIP_XCVR_SETUP_SHIFT) + +#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) +#define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22) +#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) +#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) +#define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4) +#define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25) /* USBx_UTMIP_XCVR_CFG1_0 */ #define UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT 18 diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 343893b9f1..7c73eb66b6 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -66,9 +66,24 @@ enum usb_ctlr_type { 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 @@ static const unsigned T210_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = { { 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 @@ static int init_utmi_usb_controller(struct fdt_usb *config, 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 @@ static int init_utmi_usb_controller(struct fdt_usb *config, /* 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 @@ static int init_utmi_usb_controller(struct fdt_usb *config, 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 @@ static int init_utmi_usb_controller(struct fdt_usb *config, 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 @@ static int init_utmi_usb_controller(struct fdt_usb *config, /* 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 @@ static int fdt_decode_usb(struct udevice *dev, struct fdt_usb *config) 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 @@ static int ehci_usb_of_to_plat(struct udevice *dev) priv->type = dev_get_driver_data(dev); + fdt_decode_usb_phy(dev); + return 0; } -- 2.39.5