Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: phy: tegra: Program new PHY parameters

The Tegra30 TRM recommends configuration of certain PHY parameters for
optimal quality. Program the following registers based on device tree
parameters:

- UTMIP_XCVR_HSSLEW: HS slew rate control.
- UTMIP_HSSQUELCH_LEVEL: HS squelch detector level
- UTMIP_HSDISCON_LEVEL: HS disconnect detector level.

These registers exist in Tegra20, but programming them hasn't been
necessary, so these parameters won't be set on Tegra20 to keep the
device trees backward compatible.

Additionally, the UTMIP_XCVR_SETUP parameter can be set from fuses
instead of a software-programmed value, as the optimal value can
vary between invidual boards. The boolean property
nvidia,xcvr-setup-use-fuses can be used to enable this behaviour.

Signed-off-by: Tuomas Tynkkynen <ttynkkynen@nvidia.com>
Tested-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>

authored by

Tuomas Tynkkynen and committed by
Felipe Balbi
e497a24d 91e66700

+67 -18
+63 -18
drivers/usb/phy/phy-tegra-usb.c
··· 99 99 #define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) 100 100 #define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) 101 101 #define UTMIP_XCVR_LSBIAS_SEL (1 << 21) 102 - #define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25) 102 + #define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4) 103 + #define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25) 103 104 104 105 #define UTMIP_BIAS_CFG0 0x80c 105 106 #define UTMIP_OTGPD (1 << 11) 106 107 #define UTMIP_BIASPD (1 << 10) 108 + #define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0) 109 + #define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2) 110 + #define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24) 107 111 108 112 #define UTMIP_HSRX_CFG0 0x810 109 113 #define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) ··· 259 255 { 260 256 unsigned long val, flags; 261 257 void __iomem *base = phy->pad_regs; 258 + struct tegra_utmip_config *config = phy->config; 262 259 263 260 clk_prepare_enable(phy->pad_clk); 264 261 ··· 268 263 if (utmip_pad_count++ == 0) { 269 264 val = readl(base + UTMIP_BIAS_CFG0); 270 265 val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); 266 + 267 + if (phy->soc_config->requires_extra_tuning_parameters) { 268 + val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | 269 + UTMIP_HSDISCON_LEVEL(~0) | 270 + UTMIP_HSDISCON_LEVEL_MSB(~0)); 271 + 272 + val |= UTMIP_HSSQUELCH_LEVEL(config->hssquelch_level); 273 + val |= UTMIP_HSDISCON_LEVEL(config->hsdiscon_level); 274 + val |= UTMIP_HSDISCON_LEVEL_MSB(config->hsdiscon_level); 275 + } 271 276 writel(val, base + UTMIP_BIAS_CFG0); 272 277 } 273 278 ··· 446 431 val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | 447 432 UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL | 448 433 UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) | 449 - UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) | 450 - UTMIP_XCVR_HSSLEW_MSB(~0)); 451 - val |= UTMIP_XCVR_SETUP(config->xcvr_setup); 452 - val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup); 434 + UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0)); 435 + 436 + if (!config->xcvr_setup_use_fuses) { 437 + val |= UTMIP_XCVR_SETUP(config->xcvr_setup); 438 + val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup); 439 + } 453 440 val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew); 454 441 val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew); 442 + 443 + if (phy->soc_config->requires_extra_tuning_parameters) { 444 + val &= ~(UTMIP_XCVR_HSSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0)); 445 + val |= UTMIP_XCVR_HSSLEW(config->xcvr_hsslew); 446 + val |= UTMIP_XCVR_HSSLEW_MSB(config->xcvr_hsslew); 447 + } 455 448 writel(val, base + UTMIP_XCVR_CFG0); 456 449 457 450 val = readl(base + UTMIP_XCVR_CFG1); ··· 473 450 val |= UTMIP_BIAS_PDTRK_COUNT(0x5); 474 451 writel(val, base + UTMIP_BIAS_CFG1); 475 452 476 - if (phy->is_legacy_phy) { 477 - val = readl(base + UTMIP_SPARE_CFG0); 478 - if (phy->mode == USB_DR_MODE_PERIPHERAL) 479 - val &= ~FUSE_SETUP_SEL; 480 - else 481 - val |= FUSE_SETUP_SEL; 482 - writel(val, base + UTMIP_SPARE_CFG0); 483 - } else { 453 + val = readl(base + UTMIP_SPARE_CFG0); 454 + if (config->xcvr_setup_use_fuses) 455 + val |= FUSE_SETUP_SEL; 456 + else 457 + val &= ~FUSE_SETUP_SEL; 458 + writel(val, base + UTMIP_SPARE_CFG0); 459 + 460 + if (!phy->is_legacy_phy) { 484 461 val = readl(base + USB_SUSP_CTRL); 485 462 val |= UTMIP_PHY_ENABLE; 486 463 writel(val, base + USB_SUSP_CTRL); ··· 911 888 if (err < 0) 912 889 return err; 913 890 914 - err = read_utmi_param(pdev, "nvidia,xcvr-setup", 915 - &config->xcvr_setup); 916 - if (err < 0) 917 - return err; 918 - 919 891 err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew", 920 892 &config->xcvr_lsfslew); 921 893 if (err < 0) ··· 920 902 &config->xcvr_lsrslew); 921 903 if (err < 0) 922 904 return err; 905 + 906 + if (tegra_phy->soc_config->requires_extra_tuning_parameters) { 907 + err = read_utmi_param(pdev, "nvidia,xcvr-hsslew", 908 + &config->xcvr_hsslew); 909 + if (err < 0) 910 + return err; 911 + 912 + err = read_utmi_param(pdev, "nvidia,hssquelch-level", 913 + &config->hssquelch_level); 914 + if (err < 0) 915 + return err; 916 + 917 + err = read_utmi_param(pdev, "nvidia,hsdiscon-level", 918 + &config->hsdiscon_level); 919 + if (err < 0) 920 + return err; 921 + } 922 + 923 + config->xcvr_setup_use_fuses = of_property_read_bool( 924 + pdev->dev.of_node, "nvidia,xcvr-setup-use-fuses"); 925 + 926 + if (!config->xcvr_setup_use_fuses) { 927 + err = read_utmi_param(pdev, "nvidia,xcvr-setup", 928 + &config->xcvr_setup); 929 + if (err < 0) 930 + return err; 931 + } 923 932 924 933 return 0; 925 934 }
+4
include/linux/usb/tegra_usb_phy.h
··· 41 41 u8 elastic_limit; 42 42 u8 idle_wait_delay; 43 43 u8 term_range_adj; 44 + bool xcvr_setup_use_fuses; 44 45 u8 xcvr_setup; 45 46 u8 xcvr_lsfslew; 46 47 u8 xcvr_lsrslew; 48 + u8 xcvr_hsslew; 49 + u8 hssquelch_level; 50 + u8 hsdiscon_level; 47 51 }; 48 52 49 53 enum tegra_usb_phy_port_speed {