phy: tegra: xusb: Fix per-pad high-speed termination calibration
The existing code reads a single hs_term_range_adj value from bit field
[10:7] of FUSE_SKU_CALIB_0 and applies it to all USB2 pads uniformly.
However, on SoCs that support per-pad termination, each pad has its own
hs_term_range_adj field: pad 0 in FUSE_SKU_CALIB_0[10:7], and pads 1-3
in FUSE_USB_CALIB_EXT_0 at bit offsets [8:5], [12:9], and [16:13]
respectively.
Fix the calibration by reading per-pad values from the appropriate fuse
registers. For SoCs that do not support per-pad termination, replicate
pad 0's value to all pads to maintain existing behavior.
Add a has_per_pad_term flag to the SoC data to indicate whether per-pad
termination values are available in FUSE_USB_CALIB_EXT_0.
Fixes: 1ef535c6ba ("phy: tegra: xusb: Add Tegra194 support")
Cc: stable@vger.kernel.org
Signed-off-by: Wayne Chang <waynec@nvidia.com>
Signed-off-by: Wei-Cheng Chen <weichengc@nvidia.com>
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Link: https://patch.msgid.link/20260504033305.2283145-1-weichengc@nvidia.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
master
parent
91ddf6f722
commit
da110228b5
|
|
@ -20,8 +20,8 @@
|
||||||
/* FUSE USB_CALIB registers */
|
/* FUSE USB_CALIB registers */
|
||||||
#define HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? (11 + (x - 1) * 6) : 0)
|
#define HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? (11 + (x - 1) * 6) : 0)
|
||||||
#define HS_CURR_LEVEL_PAD_MASK 0x3f
|
#define HS_CURR_LEVEL_PAD_MASK 0x3f
|
||||||
#define HS_TERM_RANGE_ADJ_SHIFT 7
|
#define HS_TERM_RANGE_ADJ_PADX_SHIFT(x) ((x) ? (5 + (x - 1) * 4) : 7)
|
||||||
#define HS_TERM_RANGE_ADJ_MASK 0xf
|
#define HS_TERM_RANGE_ADJ_PAD_MASK 0xf
|
||||||
#define HS_SQUELCH_SHIFT 29
|
#define HS_SQUELCH_SHIFT 29
|
||||||
#define HS_SQUELCH_MASK 0x7
|
#define HS_SQUELCH_MASK 0x7
|
||||||
|
|
||||||
|
|
@ -253,7 +253,7 @@
|
||||||
struct tegra_xusb_fuse_calibration {
|
struct tegra_xusb_fuse_calibration {
|
||||||
u32 *hs_curr_level;
|
u32 *hs_curr_level;
|
||||||
u32 hs_squelch;
|
u32 hs_squelch;
|
||||||
u32 hs_term_range_adj;
|
u32 *hs_term_range_adj;
|
||||||
u32 rpd_ctrl;
|
u32 rpd_ctrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -930,7 +930,7 @@ static int tegra186_utmi_phy_power_on(struct phy *phy)
|
||||||
|
|
||||||
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
|
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
|
||||||
value &= ~TERM_RANGE_ADJ(~0);
|
value &= ~TERM_RANGE_ADJ(~0);
|
||||||
value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj);
|
value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj[index]);
|
||||||
value &= ~RPD_CTRL(~0);
|
value &= ~RPD_CTRL(~0);
|
||||||
value |= RPD_CTRL(priv->calib.rpd_ctrl);
|
value |= RPD_CTRL(priv->calib.rpd_ctrl);
|
||||||
padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
|
padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
|
||||||
|
|
@ -1464,17 +1464,23 @@ static const char * const tegra186_usb3_functions[] = {
|
||||||
static int
|
static int
|
||||||
tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
|
tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
|
||||||
{
|
{
|
||||||
|
const struct tegra_xusb_padctl_soc *soc = padctl->base.soc;
|
||||||
struct device *dev = padctl->base.dev;
|
struct device *dev = padctl->base.dev;
|
||||||
unsigned int i, count;
|
unsigned int i, count;
|
||||||
u32 value, *level;
|
u32 value, *level;
|
||||||
|
u32 *hs_term_range_adj;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
count = padctl->base.soc->ports.usb2.count;
|
count = soc->ports.usb2.count;
|
||||||
|
|
||||||
level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL);
|
level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL);
|
||||||
if (!level)
|
if (!level)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
hs_term_range_adj = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL);
|
||||||
|
if (!hs_term_range_adj)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
|
err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
|
||||||
if (err)
|
if (err)
|
||||||
return dev_err_probe(dev, err,
|
return dev_err_probe(dev, err,
|
||||||
|
|
@ -1490,8 +1496,8 @@ tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
|
||||||
|
|
||||||
padctl->calib.hs_squelch = (value >> HS_SQUELCH_SHIFT) &
|
padctl->calib.hs_squelch = (value >> HS_SQUELCH_SHIFT) &
|
||||||
HS_SQUELCH_MASK;
|
HS_SQUELCH_MASK;
|
||||||
padctl->calib.hs_term_range_adj = (value >> HS_TERM_RANGE_ADJ_SHIFT) &
|
hs_term_range_adj[0] = (value >> HS_TERM_RANGE_ADJ_PADX_SHIFT(0)) &
|
||||||
HS_TERM_RANGE_ADJ_MASK;
|
HS_TERM_RANGE_ADJ_PAD_MASK;
|
||||||
|
|
||||||
err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value);
|
err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -1503,6 +1509,17 @@ tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
|
||||||
|
|
||||||
padctl->calib.rpd_ctrl = (value >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK;
|
padctl->calib.rpd_ctrl = (value >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK;
|
||||||
|
|
||||||
|
for (i = 1; i < count; i++) {
|
||||||
|
if (soc->has_per_pad_term)
|
||||||
|
hs_term_range_adj[i] =
|
||||||
|
(value >> HS_TERM_RANGE_ADJ_PADX_SHIFT(i)) &
|
||||||
|
HS_TERM_RANGE_ADJ_PAD_MASK;
|
||||||
|
else
|
||||||
|
hs_term_range_adj[i] = hs_term_range_adj[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
padctl->calib.hs_term_range_adj = hs_term_range_adj;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1708,6 +1725,7 @@ const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc = {
|
||||||
.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
|
.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
|
||||||
.supports_gen2 = true,
|
.supports_gen2 = true,
|
||||||
.poll_trk_completed = true,
|
.poll_trk_completed = true,
|
||||||
|
.has_per_pad_term = true,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
|
EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
|
||||||
|
|
||||||
|
|
@ -1732,6 +1750,7 @@ const struct tegra_xusb_padctl_soc tegra234_xusb_padctl_soc = {
|
||||||
.trk_hw_mode = false,
|
.trk_hw_mode = false,
|
||||||
.trk_update_on_idle = true,
|
.trk_update_on_idle = true,
|
||||||
.supports_lp_cfg_en = true,
|
.supports_lp_cfg_en = true,
|
||||||
|
.has_per_pad_term = true,
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc);
|
EXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -435,6 +435,7 @@ struct tegra_xusb_padctl_soc {
|
||||||
bool trk_hw_mode;
|
bool trk_hw_mode;
|
||||||
bool trk_update_on_idle;
|
bool trk_update_on_idle;
|
||||||
bool supports_lp_cfg_en;
|
bool supports_lp_cfg_en;
|
||||||
|
bool has_per_pad_term;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tegra_xusb_padctl {
|
struct tegra_xusb_padctl {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue