[PATCH 09/11] phy: tegra: xusb: Add Tegra234 support

Wayne Chang waynec at nvidia.com
Thu Nov 3 04:42:51 PDT 2022



On 10/28/22 20:56, Thierry Reding wrote:
> On Mon, Oct 24, 2022 at 03:41:26PM +0800, Wayne Chang wrote:
>> From: Sing-Han Chen<singhanc at nvidia.com>
>>
>> Add support for the XUSB pad controller found on Tegra234 SoCs. It is
>> mostly similar to the same IP found on Tegra194, because most of
>> the Tegra234 XUSB PADCTL registers definition and programming sequence
>> are the same as Tegra194, Tegra234 XUSB PADCTL can share the same
>> driver with Tegra186 and Tegra194 XUSB PADCTL.
>>
>> Introduce a new feature, USB2 HW tracking, for Tegra234.
>> The feature is to enable HW periodical PAD tracking which measure
>> and capture the electric parameters of USB2.0 PAD.
>>
>> Signed-off-by: Sing-Han Chen<singhanc at nvidia.com>
>> Co-developed-by: Wayne Chang<waynec at nvidia.com>
>> Signed-off-by: Wayne Chang<waynec at nvidia.com>
>> ---
>>   drivers/phy/tegra/Makefile        |  1 +
>>   drivers/phy/tegra/xusb-tegra186.c | 65 +++++++++++++++++++++++++++++--
>>   drivers/phy/tegra/xusb.c          |  6 +++
>>   drivers/phy/tegra/xusb.h          | 23 +++++++++++
>>   4 files changed, 92 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/phy/tegra/Makefile b/drivers/phy/tegra/Makefile
>> index 89b84067cb4c..eeeea72de117 100644
>> --- a/drivers/phy/tegra/Makefile
>> +++ b/drivers/phy/tegra/Makefile
>> @@ -7,4 +7,5 @@ phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o
>>   phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o
>>   phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o
>>   phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_194_SOC) += xusb-tegra186.o
>> +phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_234_SOC) += xusb-tegra186.o
>>   obj-$(CONFIG_PHY_TEGRA194_P2U) += phy-tegra194-p2u.o
>> diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c
>> index f121b4ffbbfd..cc02cea65a21 100644
>> --- a/drivers/phy/tegra/xusb-tegra186.c
>> +++ b/drivers/phy/tegra/xusb-tegra186.c
>> @@ -89,6 +89,11 @@
>>   #define  USB2_TRK_START_TIMER(x)		(((x) & 0x7f) << 12)
>>   #define  USB2_TRK_DONE_RESET_TIMER(x)		(((x) & 0x7f) << 19)
>>   #define  USB2_PD_TRK				BIT(26)
>> +#define  USB2_TRK_COMPLETED			BIT(31)
>> +
>> +#define XUSB_PADCTL_USB2_BIAS_PAD_CTL2		0x28c
>> +#define  USB2_TRK_HW_MODE			BIT(0)
>> +#define  CYA_TRK_CODE_UPDATE_ON_IDLE		BIT(31)
>>   
>>   #define XUSB_PADCTL_HSIC_PADX_CTL0(x)		(0x300 + (x) * 0x20)
>>   #define  HSIC_PD_TX_DATA0			BIT(1)
>> @@ -609,9 +614,32 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl)
>>   	value &= ~USB2_PD_TRK;
>>   	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
>>   
>> -	udelay(100);
>> +	if (padctl->soc->poll_trk_completed) {
>> +		err = padctl_readl_poll(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1,
>> +					USB2_TRK_COMPLETED, USB2_TRK_COMPLETED, 100);
>> +		if (err) {
>> +			/* The failure with polling on trk complete will not
>> +			 * cause the failure of powering on the bias pad.
>> +			 */
>> +			dev_warn(dev, "failed to poll USB2 trk completed: %d\n",
>> +				err);
>> +		}
>>   
>> -	clk_disable_unprepare(priv->usb2_trk_clk);
>> +		value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
>> +		value |= USB2_TRK_COMPLETED;
>> +		padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
>> +	} else {
>> +		udelay(100);
>> +	}
>> +
>> +	if (padctl->soc->trk_hw_mode) {
>> +		value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
>> +		value |= USB2_TRK_HW_MODE;
>> +		value &= ~CYA_TRK_CODE_UPDATE_ON_IDLE;
>> +		padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
>> +	} else {
>> +		clk_disable_unprepare(priv->usb2_trk_clk);
>> +	}
>>   
>>   	mutex_unlock(&padctl->lock);
>>   }
>> @@ -637,6 +665,13 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
>>   	value |= USB2_PD_TRK;
>>   	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
>>   
>> +	if (padctl->soc->trk_hw_mode) {
>> +		value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
>> +		value &= ~USB2_TRK_HW_MODE;
>> +		padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
>> +		clk_disable_unprepare(priv->usb2_trk_clk);
>> +	}
>> +
>>   	mutex_unlock(&padctl->lock);
>>   }
>>   
>> @@ -1560,7 +1595,8 @@ const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
>>   EXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc);
>>   #endif
>>   
>> -#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
>> +#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \
>> +	IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
>>   static const char * const tegra194_xusb_padctl_supply_names[] = {
>>   	"avdd-usb",
>>   	"vclamp-usb",
>> @@ -1616,8 +1652,31 @@ const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc = {
>>   	.supply_names = tegra194_xusb_padctl_supply_names,
>>   	.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
>>   	.supports_gen2 = true,
>> +	.poll_trk_completed = true,
>>   };
>>   EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
>> +
>> +const struct tegra_xusb_padctl_soc tegra234_xusb_padctl_soc = {
>> +	.num_pads = ARRAY_SIZE(tegra194_pads),
>> +	.pads = tegra194_pads,
>> +	.ports = {
>> +		.usb2 = {
>> +			.ops = &tegra186_usb2_port_ops,
>> +			.count = 4,
>> +		},
>> +		.usb3 = {
>> +			.ops = &tegra186_usb3_port_ops,
>> +			.count = 4,
>> +		},
>> +	},
>> +	.ops = &tegra186_xusb_padctl_ops,
>> +	.supply_names = tegra194_xusb_padctl_supply_names,
>> +	.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
>> +	.supports_gen2 = true,
>> +	.poll_trk_completed = true,
>> +	.trk_hw_mode = true,
>> +};
>> +EXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc);
> I'm beginning to wonder if we perhaps went a bit overboard with this.
> These symbols are used exclusively by drivers/phy/tegra/xusb.c, which
> ends up in the same link unit as xusb-tegra186.c, so the export should
> not be necessary.
> 
> Not necessarily something that needs fixing right now, but certainly
> something to circle back to eventually.

Yes, exactly.
OK. We will refactor it the next time.
Thanks for the review.

> 
>>   #endif
>>   
>>   MODULE_AUTHOR("JC Kuo<jckuo at nvidia.com>");
>> diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
>> index 95091876c422..23d179b1a5b5 100644
>> --- a/drivers/phy/tegra/xusb.c
>> +++ b/drivers/phy/tegra/xusb.c
>> @@ -71,6 +71,12 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = {
>>   		.compatible = "nvidia,tegra194-xusb-padctl",
>>   		.data = &tegra194_xusb_padctl_soc,
>>   	},
>> +#endif
>> +#if defined(CONFIG_ARCH_TEGRA_234_SOC)
>> +	{
>> +		.compatible = "nvidia,tegra234-xusb-padctl",
>> +		.data = &tegra234_xusb_padctl_soc,
>> +	},
>>   #endif
>>   	{ }
>>   };
>> diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
>> index 8cfbbdbd6e0c..ec0b5b023ad1 100644
>> --- a/drivers/phy/tegra/xusb.h
>> +++ b/drivers/phy/tegra/xusb.h
>> @@ -8,6 +8,7 @@
>>   #define __PHY_TEGRA_XUSB_H
>>   
>>   #include <linux/io.h>
>> +#include <linux/iopoll.h>
>>   #include <linux/mutex.h>
>>   #include <linux/workqueue.h>
>>   
>> @@ -433,6 +434,8 @@ struct tegra_xusb_padctl_soc {
>>   	unsigned int num_supplies;
>>   	bool supports_gen2;
>>   	bool need_fake_usb3_port;
>> +	bool poll_trk_completed;
>> +	bool trk_hw_mode;
>>   };
>>   
>>   struct tegra_xusb_padctl {
>> @@ -475,6 +478,23 @@ static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
>>   	return value;
>>   }
>>   
>> +static inline u32 padctl_readl_poll(struct tegra_xusb_padctl *padctl,
>> +	unsigned long offset, u32 val, u32 mask, int us)
>> +{
>> +	u32 regval;
>> +	int err;
>> +
>> +	err = readl_poll_timeout_atomic(padctl->regs + offset, regval,
>> +					 (regval & mask) == val, 1, us);
> Do we really need the atomic variant here? The function that calls this
> already uses a mutex for protection, so it can already sleep anyway.
> 

Thanks for the review. No, we don't need it to be atomic.
I'll update it in the next patch series.

> Also, do we really need the helper here? We use this exactly once and
> this doesn't make the invocation more readable, either.
>

Not at all. Removed. Thanks.


thanks,
Wayne.

> Thierry
> 
>> +	dev_dbg(padctl->dev, "%08lx poll > %08x\n", offset, regval);
>> +	if (err) {
>> +		dev_err(padctl->dev, "%08lx poll timeout > %08x\n", offset,
>> +			regval);
>> +	}
>> +
>> +	return err;
>> +}
>> +
>>   struct tegra_xusb_lane *tegra_xusb_find_lane(struct tegra_xusb_padctl *padctl,
>>   					     const char *name,
>>   					     unsigned int index);
>> @@ -491,5 +511,8 @@ extern const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc;
>>   #if defined(CONFIG_ARCH_TEGRA_194_SOC)
>>   extern const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc;
>>   #endif
>> +#if defined(CONFIG_ARCH_TEGRA_234_SOC)
>> +extern const struct tegra_xusb_padctl_soc tegra234_xusb_padctl_soc;
>> +#endif
>>   
>>   #endif /* __PHY_TEGRA_XUSB_H */
>> -- 
>> 2.25.1


More information about the linux-phy mailing list