summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorRakesh Bodla <rbodla@nvidia.com>2011-09-14 15:20:33 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-09-14 16:50:52 -0700
commit4687d225987942d3b7ea11b687f1a84359ae0ffb (patch)
tree5d5b5e5fb8d603037c8e3f8ded6f9bf284f12977 /arch
parent17efce7b49626cde29af8db695b18d4ab3db9099 (diff)
tegra: usb: phy: support for adding usb calib offset
Adding software programmability to add appropriate offset for usb calibration. Bug 867817 Change-Id: I06ba74036a54b9283c58bfab35410d95b8fccf12 Reviewed-on: http://git-master/r/51573 Reviewed-by: Rakesh Bodla <rbodla@nvidia.com> Tested-by: Rakesh Bodla <rbodla@nvidia.com> Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/include/mach/usb_phy.h2
-rw-r--r--arch/arm/mach-tegra/usb_phy.c59
2 files changed, 51 insertions, 10 deletions
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h
index 9d28b6e861b2..342d6c2bce43 100644
--- a/arch/arm/mach-tegra/include/mach/usb_phy.h
+++ b/arch/arm/mach-tegra/include/mach/usb_phy.h
@@ -29,6 +29,8 @@ struct tegra_utmip_config {
u8 idle_wait_delay;
u8 term_range_adj;
u8 xcvr_setup;
+ u8 xcvr_setup_offset;
+ u8 xcvr_use_fuses;
u8 xcvr_lsfslew;
u8 xcvr_lsrslew;
};
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index 15977a3868a0..56819103ffeb 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -109,8 +109,13 @@
#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
+#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22)
#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
+#define UTMIP_XCVR_MAX_OFFSET 2
+#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f
+#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4)
+
#define UTMIP_BIAS_CFG0 0x80c
#define UTMIP_OTGPD (1 << 11)
#define UTMIP_BIASPD (1 << 10)
@@ -255,8 +260,13 @@
#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
+#define UTMIP_XCVR_SETUP_MSB(x) (((x) & 0x7) << 22)
#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
+#define UTMIP_XCVR_MAX_OFFSET 5
+#define UTMIP_XCVR_SETUP_MAX_VALUE 0x7f
+#define XCVR_SETUP_MSB_CALIB(x) ((x) >> 4)
+
#define UTMIP_BIAS_CFG0 0x80c
#define UTMIP_OTGPD (1 << 11)
#define UTMIP_BIASPD (1 << 10)
@@ -525,6 +535,9 @@
#define FUSE_SETUP_SEL (1 << 3)
#define FUSE_ATERM_SEL (1 << 4)
+#define FUSE_USB_CALIB_0 0x1F0
+#define FUSE_USB_CALIB_XCVR_SETUP(x) (((x) & 0x7F) << 0)
+
#define UHSIC_PLL_CFG0 0x800
#define UHSIC_TX_CFG0 0x810
@@ -629,6 +642,8 @@ static struct tegra_utmip_config utmip_default[] = {
.elastic_limit = 16,
.term_range_adj = 6,
.xcvr_setup = 9,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
.xcvr_lsfslew = 2,
.xcvr_lsrslew = 2,
},
@@ -637,6 +652,8 @@ static struct tegra_utmip_config utmip_default[] = {
.idle_wait_delay = 17,
.elastic_limit = 16,
.term_range_adj = 6,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
.xcvr_setup = 9,
.xcvr_lsfslew = 2,
.xcvr_lsrslew = 2,
@@ -852,10 +869,33 @@ static void vbus_disable(struct tegra_usb_phy *phy)
#endif
}
+static unsigned int tegra_phy_xcvr_setup_value(struct tegra_utmip_config *cfg)
+{
+ unsigned long val;
+
+ if (cfg->xcvr_use_fuses) {
+ val = FUSE_USB_CALIB_XCVR_SETUP(
+ tegra_fuse_readl(FUSE_USB_CALIB_0));
+ if (cfg->xcvr_setup_offset <= UTMIP_XCVR_MAX_OFFSET)
+ val = val + cfg->xcvr_setup_offset;
+
+ if (val > UTMIP_XCVR_SETUP_MAX_VALUE) {
+ val = UTMIP_XCVR_SETUP_MAX_VALUE;
+ pr_info("%s: reset XCVR_SETUP to max value\n",
+ __func__);
+ }
+ } else {
+ val = cfg->xcvr_setup;
+ }
+
+ return val;
+}
+
static int utmi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
{
unsigned long val;
void __iomem *base = phy->regs;
+ unsigned int xcvr_setup_value;
struct tegra_utmip_config *config = phy->config;
val = readl(base + USB_SUSP_CTRL);
@@ -916,12 +956,15 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
utmip_pad_power_on(phy);
+ xcvr_setup_value = tegra_phy_xcvr_setup_value(config);
+
val = readl(base + UTMIP_XCVR_CFG0);
val &= ~(UTMIP_XCVR_LSBIAS_SEL | UTMIP_FORCE_PD_POWERDOWN |
UTMIP_FORCE_PD2_POWERDOWN |UTMIP_FORCE_PDZI_POWERDOWN |
UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_LSFSLEW(~0) |
UTMIP_XCVR_LSRSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
- val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+ val |= UTMIP_XCVR_SETUP(xcvr_setup_value);
+ val |= UTMIP_XCVR_SETUP_MSB(XCVR_SETUP_MSB_CALIB(xcvr_setup_value));
val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
@@ -948,14 +991,9 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
writel(val, base + UTMIP_BIAS_CFG1);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- if (phy->instance == 0) {
- val = readl(base + UTMIP_SPARE_CFG0);
- if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
- val &= ~FUSE_SETUP_SEL;
- else
- val |= FUSE_SETUP_SEL;
- writel(val, base + UTMIP_SPARE_CFG0);
- }
+ val = readl(base + UTMIP_SPARE_CFG0);
+ val &= ~FUSE_SETUP_SEL;
+ writel(val, base + UTMIP_SPARE_CFG0);
if (phy->instance == 2) {
val = readl(base + UTMIP_SPARE_CFG0);
@@ -968,7 +1006,8 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd)
}
#else
val = readl(base + UTMIP_SPARE_CFG0);
- val |= FUSE_SETUP_SEL | FUSE_ATERM_SEL;
+ val &= ~FUSE_SETUP_SEL;
+ val |= FUSE_ATERM_SEL;
writel(val, base + UTMIP_SPARE_CFG0);
val = readl(base + USB_SUSP_CTRL);