From: Jon Hunter <jonathanh@nvidia.com>
To: Wei-Cheng Chen <weichengc@nvidia.com>,
jckuo@nvidia.com, vkoul@kernel.org, neil.armstrong@linaro.org,
thierry.reding@gmail.com
Cc: linux-phy@lists.infradead.org, linux-tegra@vger.kernel.org,
linux-kernel@vger.kernel.org, waynec@nvidia.com,
wtsai@nvidia.com
Subject: Re: [PATCH] phy: tegra: xusb: Fix per-pad high-speed termination calibration
Date: Fri, 17 Apr 2026 09:23:15 +0100 [thread overview]
Message-ID: <fde997f6-c0a8-430b-8e45-38a490e683ad@nvidia.com> (raw)
In-Reply-To: <82f3ca77-7b8f-41b8-85fb-c502bc343778@nvidia.com>
Hi Vinod,
On 24/03/2026 09:11, Jon Hunter wrote:
>
> On 04/03/2026 10:26, Wei-Cheng Chen wrote:
>> From: Wayne Chang <waynec@nvidia.com>
>>
>> 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: 1ef535c6ba8e ("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>
>> ---
>> drivers/phy/tegra/xusb-tegra186.c | 33 ++++++++++++++++++++++++-------
>> drivers/phy/tegra/xusb.h | 1 +
>> 2 files changed, 27 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/
>> xusb-tegra186.c
>> index bec9616c4a2..4452e73fb82 100644
>> --- a/drivers/phy/tegra/xusb-tegra186.c
>> +++ b/drivers/phy/tegra/xusb-tegra186.c
>> @@ -20,8 +20,8 @@
>> /* FUSE USB_CALIB registers */
>> #define HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? (11 + (x - 1) * 6) : 0)
>> #define HS_CURR_LEVEL_PAD_MASK 0x3f
>> -#define HS_TERM_RANGE_ADJ_SHIFT 7
>> -#define HS_TERM_RANGE_ADJ_MASK 0xf
>> +#define HS_TERM_RANGE_ADJ_PADX_SHIFT(x) ((x) ? (5 + (x - 1) * 4) : 7)
>> +#define HS_TERM_RANGE_ADJ_PAD_MASK 0xf
>> #define HS_SQUELCH_SHIFT 29
>> #define HS_SQUELCH_MASK 0x7
>> @@ -253,7 +253,7 @@
>> struct tegra_xusb_fuse_calibration {
>> u32 *hs_curr_level;
>> u32 hs_squelch;
>> - u32 hs_term_range_adj;
>> + u32 *hs_term_range_adj;
>> 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 &= ~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(priv->calib.rpd_ctrl);
>> padctl_writel(padctl, value,
>> XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
>> @@ -1464,17 +1464,23 @@ static const char * const
>> tegra186_usb3_functions[] = {
>> static int
>> 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;
>> unsigned int i, count;
>> u32 value, *level;
>> + u32 *hs_term_range_adj;
>> int err;
>> - count = padctl->base.soc->ports.usb2.count;
>> + count = soc->ports.usb2.count;
>> level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL);
>> if (!level)
>> 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);
>> if (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) &
>> HS_SQUELCH_MASK;
>> - padctl->calib.hs_term_range_adj = (value >>
>> HS_TERM_RANGE_ADJ_SHIFT) &
>> - HS_TERM_RANGE_ADJ_MASK;
>> + hs_term_range_adj[0] = (value >> HS_TERM_RANGE_ADJ_PADX_SHIFT(0)) &
>> + HS_TERM_RANGE_ADJ_PAD_MASK;
>> err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value);
>> 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;
>> + 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;
>> }
>> @@ -1708,6 +1725,7 @@ const struct tegra_xusb_padctl_soc
>> tegra194_xusb_padctl_soc = {
>> .num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
>> .supports_gen2 = true,
>> .poll_trk_completed = true,
>> + .has_per_pad_term = true,
>> };
>> 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_update_on_idle = true,
>> .supports_lp_cfg_en = true,
>> + .has_per_pad_term = true,
>> };
>> EXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc);
>> #endif
>> diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
>> index d2b5f956513..810b410672f 100644
>> --- a/drivers/phy/tegra/xusb.h
>> +++ b/drivers/phy/tegra/xusb.h
>> @@ -436,6 +436,7 @@ struct tegra_xusb_padctl_soc {
>> bool trk_hw_mode;
>> bool trk_update_on_idle;
>> bool supports_lp_cfg_en;
>> + bool has_per_pad_term;
>> };
>> struct tegra_xusb_padctl {
>
> Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
> Tested-by: Jon Hunter <jonathanh@nvidia.com>
I guess this was missed for Linux v7.1. If you don't have any concerns
can you pick this up for v7.2 once v7.1-rc1 is out?
Thanks!
Jon
--
nvpublic
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
prev parent reply other threads:[~2026-04-17 8:23 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-04 10:26 [PATCH] phy: tegra: xusb: Fix per-pad high-speed termination calibration Wei-Cheng Chen
2026-03-24 9:11 ` Jon Hunter
2026-04-17 8:23 ` Jon Hunter [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fde997f6-c0a8-430b-8e45-38a490e683ad@nvidia.com \
--to=jonathanh@nvidia.com \
--cc=jckuo@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-phy@lists.infradead.org \
--cc=linux-tegra@vger.kernel.org \
--cc=neil.armstrong@linaro.org \
--cc=thierry.reding@gmail.com \
--cc=vkoul@kernel.org \
--cc=waynec@nvidia.com \
--cc=weichengc@nvidia.com \
--cc=wtsai@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox