From: Neill Kapron <nkapron@google.com>
To: RD Babiera <rdbabiera@google.com>
Cc: vkoul@kernel.org, peter.griffin@linaro.org,
andre.draszik@linaro.org, tudor.ambarus@linaro.org,
p.zabel@pengutronix.de, neil.armstrong@linaro.org,
badhri@google.com, linux-arm-kernel@lists.infradead.org,
linux-samsung-soc@vger.kernel.org, linux-phy@lists.infradead.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v7] phy: Add USB3 PHY support to Google Tensor SoC USB PHY driver
Date: Mon, 21 Sep 2026 18:29:19 +0000 [thread overview]
Message-ID: <arF3fynAGG5khe3B@google.com> (raw)
In-Reply-To: <20260918222513.2633456-2-rdbabiera@google.com>
Hi RD,
Thanks for sending v7. I've reviewed the changes and identified a few
functional issues, and a couple minor items as seen below:
On Fri, Sep 18, 2026 at 10:25:14PM +0000, RD Babiera wrote:
> Add USB3 PHY support for the Google Tensor G5 USB PHY driver.
...
> --- a/drivers/phy/phy-google-usb.c
> +++ b/drivers/phy/phy-google-usb.c
> @@ -20,6 +20,7 @@
> #include <linux/reset.h>
> #include <linux/usb/typec_mux.h>
The driver is now using readl_poll_timeout() and
pm_runtime_get_if_active(), we should be including linux/iopoll.h and
linux/pm_runtime.h explicitly.
> +#define TCA_CTRLSYNCMODE_CFG1_XA_TIMEOUT_VAL_100MS 0x1e85
> +#define TCA_PSTATE_0_OFFSET 0x50
> +#define TCA_PSTATE_0_UPCS_LANE0_PHYSTATUS BIT(8)
> +
> +#define GPHY_TCA_DELAY_US 10
> +#define GPHY_TCA_TIMEOUT_US 100000
With the addition of TCA_CTRLSYNCMODE_CFG1_XA_TIMEOUT_VAL_100MS, we
should consider bumping GPHY_TCA_TIMEOUT_US to be slightly larger (e.g.
110000us) to ensure the hardware timeout is guaranteed to expire before
the software poll timeout.
> +static const char * const u2phy_clk_names[] = {
> + "usb2",
> + "usb2_apb",
> +};
> +static const char * const u3phy_clk_names[] = {
> + "usb3"
> +};
> +static const char * const u2phy_rst_names[] = {
> + "usb2",
> + "usb2_apb",
> +};
> +static const char * const u3phy_rst_names[] = {
> + "usb3"
> +};
nit: checkpatch.pl --strict flags missing blank lines between these
array declarations (and the inline helper functions + DEFINE__FREE
macros below).
> +
> +static const struct google_usb_phy_config phy_configs[GOOGLE_USB_PHY_NUM] = {
> + [GOOGLE_USB2_PHY] = {
> + .clk_names = u2phy_clk_names,
> + .num_clks = ARRAY_SIZE(u2phy_clk_names),
> + .rst_names = u2phy_rst_names,
> + .num_rsts = ARRAY_SIZE(u2phy_rst_names),
> + },
> + [GOOGLE_USB3_PHY] = {
> + .clk_names = u3phy_clk_names,
> + .num_clks = ARRAY_SIZE(u3phy_clk_names),
> + .rst_names = u3phy_rst_names,
> + .num_rsts = ARRAY_SIZE(u3phy_rst_names),
> + },
> +};
> +
> +static inline void google_usb_phy_clk_disable(struct google_usb_phy_instance *inst)
> +{
> + clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
> +}
> +DEFINE_FREE(inst_clk_disable, struct google_usb_phy_instance *,
> + if (_T) google_usb_phy_clk_disable(_T))
> +
> +static inline void google_usb_phy_rst_disable(struct google_usb_phy_instance *inst)
> +{
> + reset_control_bulk_assert(inst->num_rsts, inst->rsts);
> +}
> +DEFINE_FREE(inst_rst_disable, struct google_usb_phy_instance *,
> + if (_T) google_usb_phy_rst_disable(_T))
> +
...
>
> static int google_usb_set_orientation(struct typec_switch_dev *sw,
> enum typec_orientation orientation)
> {
> struct google_usb_phy *gphy = typec_switch_get_drvdata(sw);
> + int ret = 0;
>
> dev_dbg(gphy->dev, "set orientation %d\n", orientation);
>
> - gphy->orientation = orientation;
> + guard(mutex)(&gphy->phy_mutex);
>
> - if (pm_runtime_suspended(gphy->dev))
> - return 0;
> + gphy->orientation = orientation;
>
> - guard(mutex)(&gphy->phy_mutex);
> + if (IS_ENABLED(CONFIG_PM)) {
> + if (pm_runtime_get_if_active(gphy->dev) <= 0)
> + return 0;
> + }
>
> set_vbus_valid(gphy);
>
> - return 0;
> + if (gphy->phy_state == COMBO_PHY_TCA_READY && orientation != TYPEC_ORIENTATION_NONE)
> + ret = program_tca_locked(gphy);
> +
> + pm_runtime_put(gphy->dev);
> +
> + return ret;
> }
Previously, sashiko recommended moving to pm_runtime_get_if_active(),
which was done in v6. However I think this may have changed the behavior
of google_usb_set_orientation() and potentially introduced a regression
due to the pre-existing ordering of calls in gooogle_usb_phy_probe(),
causing this function to always take the early 'return 0' path.
In google_usb_phy_probe(), we call devm_phy_create() prior to calling
pm_runtime_enable(dev).
In drivers/phy/phy-core.c, devm_phy_create() calls phy_create(), which
has the following check:
if (pm_runtime_enabled(dev)) {
pm_runtime_enable(&phy->dev);
pm_runtime_no_callbacks(&phy->dev);
}
Therefore, the phy device never has pm_runtime_enabled, causing this
call to pm_runtime_get_if_active() to always return 0, and the function
exits prior to calling `set_vbus_valid()`.
I think moving the pm_runtime_enable(dev) call prior to
devm_phy_create() will resolve the issue, but we should audit power
managment in this driver to verify.
>
> +static int google_usb3_phy_init(struct phy *_phy)
> +{
> + struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
> + struct google_usb_phy *gphy = inst->parent;
> + int ret = 0;
> + u32 reg;
> +
> + dev_dbg(gphy->dev, "initializing usb3 phy\n");
> +
> + guard(mutex)(&gphy->phy_mutex);
> +
> + if (gphy->phy_state != COMBO_PHY_IDLE) {
> + dev_warn(gphy->dev, "usb3 phy init called when combo phy state is not idle\n");
> + return 0;
> + }
> +
> + reg = readl(gphy->usb3_tca_base + TCA_CTRLSYNCMODE_CFG1_OFFSET);
> + reg &= ~TCA_CTRLSYNCMODE_CFG1_XA_TIMEOUT_VAL;
> + reg |= FIELD_PREP(TCA_CTRLSYNCMODE_CFG1_XA_TIMEOUT_VAL,
> + TCA_CTRLSYNCMODE_CFG1_XA_TIMEOUT_VAL_100MS);
> + writel(reg, gphy->usb3_tca_base + TCA_CTRLSYNCMODE_CFG1_OFFSET);
I think this introduces a regression between v6 and v7, as usb3_tca_base
may be accessed prior to the 'usb3' clock being enabled, and
furthermore, the call to reset_control_bulk_deassert() will clear this
value.
Therefore, I think we need to this after the call to
reset_control_bulk_deassert().
> +
> + reg = readl(gphy->usbdp_top_base + PHY_POWER_CONFIG_REG1_OFFSET);
> + reg |= PHY_POWER_CONFIG_REG1_PG_MODE_EN;
> + reg &= ~PHY_POWER_CONFIG_REG1_UPCS_PIPE_CONFIG;
> + reg |= FIELD_PREP(PHY_POWER_CONFIG_REG1_UPCS_PIPE_CONFIG,
> + (UPCS_PIPE_CONFIG_ISO_CPM |
> + UPCS_PIPE_CONFIG_PG_MODE_STATIC |
> + UPCS_PIPE_CONFIG_LANE_RESET_NO_PG_EXIT));
> + writel(reg, gphy->usbdp_top_base + PHY_POWER_CONFIG_REG1_OFFSET);
> +
> + set_vbus_valid(gphy);
> +
> + reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> + reg |= USBCS_PHY_CFG1_PHY0_MPLLA_SSC_EN;
> + writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
> +
> + set_sram_bypass(gphy, SRAM_BYPASS_MODE_BYPASS_FIRMWARE |
> + SRAM_BYPASS_MODE_BYPASS_CONTEXT);
> + set_pmgt_ref_clk_req_n(gphy, true);
> + struct google_usb_phy *pmgt_ref_clk_req_dev __free(pmgt_ref_clk_req_n) = gphy;
> +
> + ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
> + if (ret)
> + return ret;
> + struct google_usb_phy_instance *clk_dev __free(inst_clk_disable) = inst;
> +
> + ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
> + if (ret)
> + return ret;
> + struct google_usb_phy_instance *rst_dev __free(inst_rst_disable) = inst;
> +
> + ret = readl_poll_timeout(gphy->usb3_tca_base + TCA_PSTATE_0_OFFSET,
> + reg, !(reg & TCA_PSTATE_0_UPCS_LANE0_PHYSTATUS),
> + GPHY_TCA_DELAY_US, GPHY_TCA_TIMEOUT_US);
> + if (ret) {
> + dev_err(gphy->dev, "wait for lane0 phystatus timed out\n");
> + return ret;
> + }
> +
> + gphy->phy_state = COMBO_PHY_INIT_DONE;
> +
> + retain_and_null_ptr(rst_dev);
> + retain_and_null_ptr(clk_dev);
> + retain_and_null_ptr(pmgt_ref_clk_req_dev);
> +
> + return 0;
> +}
> +
>
>
Thanks,
Neill
prev parent reply other threads:[~2026-09-21 18:29 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-18 22:25 RD Babiera
2026-09-21 18:29 ` Neill Kapron [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=arF3fynAGG5khe3B@google.com \
--to=nkapron@google.com \
--cc=andre.draszik@linaro.org \
--cc=badhri@google.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-phy@lists.infradead.org \
--cc=linux-samsung-soc@vger.kernel.org \
--cc=neil.armstrong@linaro.org \
--cc=p.zabel@pengutronix.de \
--cc=peter.griffin@linaro.org \
--cc=rdbabiera@google.com \
--cc=tudor.ambarus@linaro.org \
--cc=vkoul@kernel.org \
/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
all inboxes | Powered by JetHome®