From: Thierry Reding <thierry.reding@gmail.com>
To: Dmitry Osipenko <digetx@gmail.com>
Cc: Jonathan Hunter <jonathanh@nvidia.com>,
Peter Chen <Peter.Chen@nxp.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Alan Stern <stern@rowland.harvard.edu>,
Felipe Balbi <balbi@kernel.org>,
Matt Merhar <mattmerhar@protonmail.com>,
Nicolas Chauvet <kwizart@gmail.com>,
Peter Geis <pgwipeout@gmail.com>, Ion Agorria <ion@agorria.com>,
linux-tegra@vger.kernel.org, linux-usb@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 2/8] usb: phy: tegra: Support waking up from a low power mode
Date: Thu, 17 Dec 2020 14:33:56 +0100 [thread overview]
Message-ID: <X9teRPo/MadN79NI@ulmo> (raw)
In-Reply-To: <20201217094007.19336-3-digetx@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 7005 bytes --]
On Thu, Dec 17, 2020 at 12:40:01PM +0300, Dmitry Osipenko wrote:
> Support programming of waking up from a low power mode by implementing the
> generic set_wakeup() callback of the USB PHY API.
>
> Tested-by: Matt Merhar <mattmerhar@protonmail.com>
> Tested-by: Nicolas Chauvet <kwizart@gmail.com>
> Tested-by: Peter Geis <pgwipeout@gmail.com>
> Tested-by: Ion Agorria <ion@agorria.com>
> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> ---
> drivers/usb/phy/phy-tegra-usb.c | 94 +++++++++++++++++++++++++++++--
> include/linux/usb/tegra_usb_phy.h | 2 +
> 2 files changed, 90 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
> index 1296524e1bee..46a1f61877ad 100644
> --- a/drivers/usb/phy/phy-tegra-usb.c
> +++ b/drivers/usb/phy/phy-tegra-usb.c
> @@ -45,6 +45,7 @@
> #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
>
> #define USB_SUSP_CTRL 0x400
> +#define USB_WAKE_ON_RESUME_EN BIT(2)
> #define USB_WAKE_ON_CNNT_EN_DEV BIT(3)
> #define USB_WAKE_ON_DISCON_EN_DEV BIT(4)
> #define USB_SUSP_CLR BIT(5)
> @@ -56,6 +57,15 @@
> #define USB_SUSP_SET BIT(14)
> #define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
>
> +#define USB_PHY_VBUS_SENSORS 0x404
> +#define B_SESS_VLD_WAKEUP_EN BIT(6)
> +#define B_VBUS_VLD_WAKEUP_EN BIT(14)
> +#define A_SESS_VLD_WAKEUP_EN BIT(22)
> +#define A_VBUS_VLD_WAKEUP_EN BIT(30)
> +
> +#define USB_PHY_VBUS_WAKEUP_ID 0x408
> +#define VBUS_WAKEUP_WAKEUP_EN BIT(30)
> +
> #define USB1_LEGACY_CTRL 0x410
> #define USB1_NO_LEGACY_MODE BIT(0)
> #define USB1_VBUS_SENSE_CTL_MASK (3 << 1)
> @@ -334,6 +344,11 @@ static int utmip_pad_power_on(struct tegra_usb_phy *phy)
> writel_relaxed(val, base + UTMIP_BIAS_CFG0);
> }
>
> + if (phy->pad_wakeup) {
> + phy->pad_wakeup = false;
> + utmip_pad_count--;
> + }
> +
> spin_unlock(&utmip_pad_lock);
>
> clk_disable_unprepare(phy->pad_clk);
> @@ -359,6 +374,17 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy)
> goto ulock;
> }
>
> + /*
> + * In accordance to TRM, OTG and Bias pad circuits could be turned off
> + * to save power if wake is enabled, but the VBUS-change detection
> + * method is board-specific and these circuits may need to be enabled
> + * to generate wakeup event, hence we will just keep them both enabled.
> + */
> + if (phy->wakeup_enabled) {
> + phy->pad_wakeup = true;
> + utmip_pad_count++;
> + }
> +
> if (--utmip_pad_count == 0) {
> val = readl_relaxed(base + UTMIP_BIAS_CFG0);
> val |= UTMIP_OTGPD | UTMIP_BIASPD;
> @@ -503,11 +529,24 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
> writel_relaxed(val, base + UTMIP_PLL_CFG1);
> }
>
> + val = readl_relaxed(base + USB_SUSP_CTRL);
> + val &= ~USB_WAKE_ON_RESUME_EN;
> + writel_relaxed(val, base + USB_SUSP_CTRL);
> +
> if (phy->mode == USB_DR_MODE_PERIPHERAL) {
> val = readl_relaxed(base + USB_SUSP_CTRL);
> val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
> writel_relaxed(val, base + USB_SUSP_CTRL);
>
> + val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID);
> + val &= ~VBUS_WAKEUP_WAKEUP_EN;
> + writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID);
> +
> + val = readl_relaxed(base + USB_PHY_VBUS_SENSORS);
> + val &= ~(A_VBUS_VLD_WAKEUP_EN | A_SESS_VLD_WAKEUP_EN);
> + val &= ~(B_VBUS_VLD_WAKEUP_EN | B_SESS_VLD_WAKEUP_EN);
> + writel_relaxed(val, base + USB_PHY_VBUS_SENSORS);
> +
> val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0);
> val &= ~UTMIP_PD_CHRG;
> writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0);
> @@ -605,31 +644,55 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
>
> utmi_phy_clk_disable(phy);
>
> - if (phy->mode == USB_DR_MODE_PERIPHERAL) {
> - val = readl_relaxed(base + USB_SUSP_CTRL);
> - val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
> - val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
> - writel_relaxed(val, base + USB_SUSP_CTRL);
> - }
> + /* PHY won't resume if reset is asserted */
> + if (phy->wakeup_enabled)
> + goto chrg_cfg0;
>
> val = readl_relaxed(base + USB_SUSP_CTRL);
> val |= UTMIP_RESET;
> writel_relaxed(val, base + USB_SUSP_CTRL);
>
> +chrg_cfg0:
I found this diffcult to read until I realized that it was basically
just the equivalent of this:
if (!phy->wakeup_enabled) {
val = readl_relaxed(base + USB_SUSP_CTRL);
val |= UTMIP_RESET;
writel_relaxed(val, base + USB_SUSP_CTRL);
}
> val = readl_relaxed(base + UTMIP_BAT_CHRG_CFG0);
> val |= UTMIP_PD_CHRG;
> writel_relaxed(val, base + UTMIP_BAT_CHRG_CFG0);
>
> + if (phy->wakeup_enabled)
> + goto xcvr_cfg1;
> +
> val = readl_relaxed(base + UTMIP_XCVR_CFG0);
> val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
> UTMIP_FORCE_PDZI_POWERDOWN;
> writel_relaxed(val, base + UTMIP_XCVR_CFG0);
>
> +xcvr_cfg1:
Similarly, I think this is more readable as:
if (!phy->wakeup_enabled) {
val = readl_relaxed(base + UTMIP_XCVR_CFG0);
val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
UTMIP_FORCE_PDZI_POWERDOWN;
writel_relaxed(val, base + UTMIP_XCVR_CFG0);
}
> val = readl_relaxed(base + UTMIP_XCVR_CFG1);
> val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
> UTMIP_FORCE_PDDR_POWERDOWN;
> writel_relaxed(val, base + UTMIP_XCVR_CFG1);
>
> + if (phy->wakeup_enabled) {
Which then also matches the style of this conditional here.
> + val = readl_relaxed(base + USB_SUSP_CTRL);
> + val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
> + val |= USB_WAKEUP_DEBOUNCE_COUNT(5);
> + val |= USB_WAKE_ON_RESUME_EN;
> + writel_relaxed(val, base + USB_SUSP_CTRL);
> +
> + /*
> + * Ask VBUS sensor to generate wake event once cable is
> + * connected.
> + */
> + if (phy->mode == USB_DR_MODE_PERIPHERAL) {
> + val = readl_relaxed(base + USB_PHY_VBUS_WAKEUP_ID);
> + val |= VBUS_WAKEUP_WAKEUP_EN;
> + writel_relaxed(val, base + USB_PHY_VBUS_WAKEUP_ID);
> +
> + val = readl_relaxed(base + USB_PHY_VBUS_SENSORS);
> + val |= A_VBUS_VLD_WAKEUP_EN;
> + writel_relaxed(val, base + USB_PHY_VBUS_SENSORS);
> + }
> + }
> +
> return utmip_pad_power_off(phy);
> }
>
> @@ -765,6 +828,15 @@ static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
> usleep_range(5000, 6000);
> clk_disable_unprepare(phy->clk);
>
> + /*
> + * Wakeup currently unimplemented for ULPI, thus PHY needs to be
> + * force-resumed.
> + */
> + if (WARN_ON_ONCE(phy->wakeup_enabled)) {
> + ulpi_phy_power_on(phy);
> + return -EOPNOTSUPP;
> + }
How do we control phy->wakeup_enabled? Is this something that we can set
in device tree, for example? I hope so, because otherwise this would
cause a nasty splat every time we try to power-off a ULPI PHY.
Thierry
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2020-12-17 13:34 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-17 9:39 [PATCH v2 0/8] Support Runtime PM and host mode by Tegra ChipIdea USB driver Dmitry Osipenko
2020-12-17 9:40 ` [PATCH v2 1/8] usb: phy: tegra: Add delay after power up Dmitry Osipenko
2020-12-17 13:25 ` Thierry Reding
2020-12-17 9:40 ` [PATCH v2 2/8] usb: phy: tegra: Support waking up from a low power mode Dmitry Osipenko
2020-12-17 13:33 ` Thierry Reding [this message]
2020-12-17 13:47 ` Dmitry Osipenko
2020-12-17 15:04 ` Thierry Reding
2020-12-17 9:40 ` [PATCH v2 3/8] usb: chipidea: tegra: Remove MODULE_ALIAS Dmitry Osipenko
2020-12-17 9:40 ` [PATCH v2 4/8] usb: chipidea: tegra: Rename UDC to USB Dmitry Osipenko
2020-12-17 13:36 ` Thierry Reding
2020-12-17 14:00 ` Dmitry Osipenko
2020-12-17 9:40 ` [PATCH v2 5/8] usb: chipidea: tegra: Support host mode Dmitry Osipenko
2020-12-17 13:40 ` Thierry Reding
2020-12-17 9:40 ` [PATCH v2 6/8] usb: chipidea: tegra: Support runtime PM Dmitry Osipenko
2020-12-17 13:41 ` Thierry Reding
2020-12-17 13:45 ` Dmitry Osipenko
2020-12-17 15:02 ` Thierry Reding
2020-12-17 19:51 ` Dmitry Osipenko
2020-12-17 15:02 ` Thierry Reding
2020-12-17 9:40 ` [PATCH v2 7/8] usb: host: ehci-tegra: Remove the driver Dmitry Osipenko
2020-12-17 13:42 ` Thierry Reding
2020-12-17 15:50 ` Alan Stern
2020-12-17 19:43 ` Dmitry Osipenko
2020-12-17 9:40 ` [PATCH v2 8/8] ARM: tegra_defconfig: Enable USB_CHIPIDEA and remove USB_EHCI_TEGRA Dmitry Osipenko
2020-12-17 13:45 ` Thierry Reding
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=X9teRPo/MadN79NI@ulmo \
--to=thierry.reding@gmail.com \
--cc=Peter.Chen@nxp.com \
--cc=balbi@kernel.org \
--cc=digetx@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=ion@agorria.com \
--cc=jonathanh@nvidia.com \
--cc=kwizart@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=mattmerhar@protonmail.com \
--cc=pgwipeout@gmail.com \
--cc=stern@rowland.harvard.edu \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.