From: Matthias Kaehlcke <mka@chromium.org>
To: Douglas Anderson <dianders@chromium.org>
Cc: Rob Herring <robh+dt@kernel.org>,
Minas Harutyunyan <hminas@synopsys.com>,
Heiko Stuebner <heiko@sntech.de>,
Felipe Balbi <felipe.balbi@linux.intel.com>,
amstan@chromium.org, linux-rockchip@lists.infradead.org,
linux-usb@vger.kernel.org, Randy Li <ayaka@soulik.info>,
ryandcase@chromium.org, jwerner@chromium.org,
Elaine Zhang <zhangqing@rock-chips.com>,
Yunzhi Li <lyz@rock-chips.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/4] usb: dwc2: optionally assert phy reset when waking up
Date: Fri, 12 Apr 2019 16:56:33 -0700 [thread overview]
Message-ID: <20190412235633.GY112750@google.com> (raw)
In-Reply-To: <20190412224149.106971-3-dianders@chromium.org>
On Fri, Apr 12, 2019 at 03:41:47PM -0700, Douglas Anderson wrote:
> On the rk3288 USB host-only port (the one that's not the OTG-enabled
> port) the PHY can get into a bad state when a wakeup is asserted (not
> just a wakeup from full system suspend but also a wakeup from
> autosuspend).
>
> We can get the PHY out of its bad state by asserting its "port reset",
> but unfortunately that seems to assert a reset onto the USB bus so it
> could confuse things if we don't actually deenumerate / reenumerate the
> device.
>
> We can also get the PHY out of its bad state by fully resetting it using
> the reset from the CRU (clock reset unit), which does a more full
> reset. The CRU-based reset appears to actually cause devices on the bus
> to be removed and reinserted, which fixes the problem (albeit in a hacky
> way).
>
> It's unfortunate that we need to do a full re-enumeration of devices at
> wakeup time, but this is better than alternative of letting the bus get
> wedged.
>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
> Signed-off-by: Yunzhi Li <lyz@rock-chips.com>
> ---
>
> drivers/usb/dwc2/core.h | 5 +++++
> drivers/usb/dwc2/core_intr.c | 12 ++++++++++++
> drivers/usb/dwc2/hcd.c | 16 +++++++++++++---
> drivers/usb/dwc2/platform.c | 9 +++++++++
> 4 files changed, 39 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
> index 30bab8463c96..f30748f4fe7e 100644
> --- a/drivers/usb/dwc2/core.h
> +++ b/drivers/usb/dwc2/core.h
> @@ -859,6 +859,8 @@ struct dwc2_hregs_backup {
> * @gadget_enabled: Peripheral mode sub-driver initialization indicator.
> * @ll_hw_enabled: Status of low-level hardware resources.
> * @hibernated: True if core is hibernated
> + * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
> + * remote wakeup.
> * @frame_number: Frame number read from the core. For both device
> * and host modes. The value ranges are from 0
> * to HFNUM_MAX_FRNUM.
> @@ -972,6 +974,7 @@ struct dwc2_hregs_backup {
> * @status_buf_dma: DMA address for status_buf
> * @start_work: Delayed work for handling host A-cable connection
> * @reset_work: Delayed work for handling a port reset
> + * @phy_reset_work: Work structure for doing a PHY reset
> * @otg_port: OTG port number
> * @frame_list: Frame list
> * @frame_list_dma: Frame list DMA address
> @@ -1045,6 +1048,7 @@ struct dwc2_hsotg {
> unsigned int gadget_enabled:1;
> unsigned int ll_hw_enabled:1;
> unsigned int hibernated:1;
> + unsigned int reset_phy_on_wake:1;
> u16 frame_number;
>
> struct phy *phy;
> @@ -1147,6 +1151,7 @@ struct dwc2_hsotg {
>
> struct delayed_work start_work;
> struct delayed_work reset_work;
> + struct work_struct phy_reset_work;
> u8 otg_port;
> u32 *frame_list;
> dma_addr_t frame_list_dma;
> diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
> index 19ae2595f1c3..16ff33574116 100644
> --- a/drivers/usb/dwc2/core_intr.c
> +++ b/drivers/usb/dwc2/core_intr.c
> @@ -435,6 +435,18 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
> /* Restart the Phy Clock */
> pcgcctl &= ~PCGCTL_STOPPCLK;
> dwc2_writel(hsotg, pcgcctl, PCGCTL);
> +
> + /*
> + * If we've got this quirk then the PHY is stuck upon
> + * wakeup. Assert reset. This will propagate out and
> + * eventually we'll re-enumerate the device. Not great
> + * but the best we can do. We can't call phy_reset()
> + * at interrupt time but there's no hurry, so we'll
> + * schedule it for later.
> + */
> + if (hsotg->reset_phy_on_wake)
> + schedule_work(&hsotg->phy_reset_work);
> +
> mod_timer(&hsotg->wkp_timer,
> jiffies + msecs_to_jiffies(71));
> } else {
> diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
> index 3f087962f498..332349148d3f 100644
> --- a/drivers/usb/dwc2/hcd.c
> +++ b/drivers/usb/dwc2/hcd.c
> @@ -4376,6 +4376,17 @@ static void dwc2_hcd_reset_func(struct work_struct *work)
> spin_unlock_irqrestore(&hsotg->lock, flags);
> }
>
> +static void dwc2_hcd_phy_reset_func(struct work_struct *work)
> +{
> + struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
> + phy_reset_work);
> + int ret;
> +
> + ret = phy_reset(hsotg->phy);
> + if (ret)
> + dev_warn(hsotg->dev, "PHY reset failed\n");
> +}
> +
> /*
> * =========================================================================
> * Linux HC Driver Functions
> @@ -5271,11 +5282,10 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
> hsotg->hc_ptr_array[i] = channel;
> }
>
> - /* Initialize hsotg start work */
> + /* Initialize work */
> INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func);
> -
> - /* Initialize port reset work */
> INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func);
> + INIT_WORK(&hsotg->phy_reset_work, dwc2_hcd_phy_reset_func);
You also want to make sure that the work is cancelled when the
controller is stopped/removed. It seems dwc2_hcd_stop() would be a
suitable place for that.
WARNING: multiple messages have this Message-ID (diff)
From: Matthias Kaehlcke <mka@chromium.org>
To: Douglas Anderson <dianders@chromium.org>
Cc: Rob Herring <robh+dt@kernel.org>,
Minas Harutyunyan <hminas@synopsys.com>,
Heiko Stuebner <heiko@sntech.de>,
Felipe Balbi <felipe.balbi@linux.intel.com>,
amstan@chromium.org, linux-rockchip@lists.infradead.org,
linux-usb@vger.kernel.org, Randy Li <ayaka@soulik.info>,
ryandcase@chromium.org, jwerner@chromium.org,
Elaine Zhang <zhangqing@rock-chips.com>,
Yunzhi Li <lyz@rock-chips.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-kernel@vger.kernel.org
Subject: [2/4] usb: dwc2: optionally assert phy reset when waking up
Date: Fri, 12 Apr 2019 16:56:33 -0700 [thread overview]
Message-ID: <20190412235633.GY112750@google.com> (raw)
On Fri, Apr 12, 2019 at 03:41:47PM -0700, Douglas Anderson wrote:
> On the rk3288 USB host-only port (the one that's not the OTG-enabled
> port) the PHY can get into a bad state when a wakeup is asserted (not
> just a wakeup from full system suspend but also a wakeup from
> autosuspend).
>
> We can get the PHY out of its bad state by asserting its "port reset",
> but unfortunately that seems to assert a reset onto the USB bus so it
> could confuse things if we don't actually deenumerate / reenumerate the
> device.
>
> We can also get the PHY out of its bad state by fully resetting it using
> the reset from the CRU (clock reset unit), which does a more full
> reset. The CRU-based reset appears to actually cause devices on the bus
> to be removed and reinserted, which fixes the problem (albeit in a hacky
> way).
>
> It's unfortunate that we need to do a full re-enumeration of devices at
> wakeup time, but this is better than alternative of letting the bus get
> wedged.
>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
> Signed-off-by: Yunzhi Li <lyz@rock-chips.com>
> ---
>
> drivers/usb/dwc2/core.h | 5 +++++
> drivers/usb/dwc2/core_intr.c | 12 ++++++++++++
> drivers/usb/dwc2/hcd.c | 16 +++++++++++++---
> drivers/usb/dwc2/platform.c | 9 +++++++++
> 4 files changed, 39 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
> index 30bab8463c96..f30748f4fe7e 100644
> --- a/drivers/usb/dwc2/core.h
> +++ b/drivers/usb/dwc2/core.h
> @@ -859,6 +859,8 @@ struct dwc2_hregs_backup {
> * @gadget_enabled: Peripheral mode sub-driver initialization indicator.
> * @ll_hw_enabled: Status of low-level hardware resources.
> * @hibernated: True if core is hibernated
> + * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a
> + * remote wakeup.
> * @frame_number: Frame number read from the core. For both device
> * and host modes. The value ranges are from 0
> * to HFNUM_MAX_FRNUM.
> @@ -972,6 +974,7 @@ struct dwc2_hregs_backup {
> * @status_buf_dma: DMA address for status_buf
> * @start_work: Delayed work for handling host A-cable connection
> * @reset_work: Delayed work for handling a port reset
> + * @phy_reset_work: Work structure for doing a PHY reset
> * @otg_port: OTG port number
> * @frame_list: Frame list
> * @frame_list_dma: Frame list DMA address
> @@ -1045,6 +1048,7 @@ struct dwc2_hsotg {
> unsigned int gadget_enabled:1;
> unsigned int ll_hw_enabled:1;
> unsigned int hibernated:1;
> + unsigned int reset_phy_on_wake:1;
> u16 frame_number;
>
> struct phy *phy;
> @@ -1147,6 +1151,7 @@ struct dwc2_hsotg {
>
> struct delayed_work start_work;
> struct delayed_work reset_work;
> + struct work_struct phy_reset_work;
> u8 otg_port;
> u32 *frame_list;
> dma_addr_t frame_list_dma;
> diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
> index 19ae2595f1c3..16ff33574116 100644
> --- a/drivers/usb/dwc2/core_intr.c
> +++ b/drivers/usb/dwc2/core_intr.c
> @@ -435,6 +435,18 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
> /* Restart the Phy Clock */
> pcgcctl &= ~PCGCTL_STOPPCLK;
> dwc2_writel(hsotg, pcgcctl, PCGCTL);
> +
> + /*
> + * If we've got this quirk then the PHY is stuck upon
> + * wakeup. Assert reset. This will propagate out and
> + * eventually we'll re-enumerate the device. Not great
> + * but the best we can do. We can't call phy_reset()
> + * at interrupt time but there's no hurry, so we'll
> + * schedule it for later.
> + */
> + if (hsotg->reset_phy_on_wake)
> + schedule_work(&hsotg->phy_reset_work);
> +
> mod_timer(&hsotg->wkp_timer,
> jiffies + msecs_to_jiffies(71));
> } else {
> diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
> index 3f087962f498..332349148d3f 100644
> --- a/drivers/usb/dwc2/hcd.c
> +++ b/drivers/usb/dwc2/hcd.c
> @@ -4376,6 +4376,17 @@ static void dwc2_hcd_reset_func(struct work_struct *work)
> spin_unlock_irqrestore(&hsotg->lock, flags);
> }
>
> +static void dwc2_hcd_phy_reset_func(struct work_struct *work)
> +{
> + struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
> + phy_reset_work);
> + int ret;
> +
> + ret = phy_reset(hsotg->phy);
> + if (ret)
> + dev_warn(hsotg->dev, "PHY reset failed\n");
> +}
> +
> /*
> * =========================================================================
> * Linux HC Driver Functions
> @@ -5271,11 +5282,10 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
> hsotg->hc_ptr_array[i] = channel;
> }
>
> - /* Initialize hsotg start work */
> + /* Initialize work */
> INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func);
> -
> - /* Initialize port reset work */
> INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func);
> + INIT_WORK(&hsotg->phy_reset_work, dwc2_hcd_phy_reset_func);
You also want to make sure that the work is cancelled when the
controller is stopped/removed. It seems dwc2_hcd_stop() would be a
suitable place for that.
next prev parent reply other threads:[~2019-04-12 23:56 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-12 22:41 [PATCH 0/4] usb: dwc2: Another attempt handling rk3288's remote wake quirk Douglas Anderson
2019-04-12 22:41 ` Douglas Anderson
2019-04-12 22:41 ` Douglas Anderson
2019-04-12 22:41 ` [PATCH 1/4] dt-bindings: usb: dwc2: Document quirk to reset PHY upon wakeup Douglas Anderson
2019-04-12 22:41 ` [1/4] " Doug Anderson
2019-04-12 23:42 ` [PATCH 1/4] " Matthias Kaehlcke
2019-04-12 23:42 ` [1/4] " Matthias Kaehlcke
2019-04-12 22:41 ` [PATCH 2/4] usb: dwc2: optionally assert phy reset when waking up Douglas Anderson
2019-04-12 22:41 ` [2/4] " Doug Anderson
2019-04-12 23:56 ` Matthias Kaehlcke [this message]
2019-04-12 23:56 ` Matthias Kaehlcke
2019-04-16 21:54 ` [PATCH 2/4] " Doug Anderson
2019-04-16 21:54 ` [2/4] " Doug Anderson
2019-04-12 22:41 ` [PATCH 3/4] ARM: dts: rockchip: Hook resets up to USB PHYs on rk3288 Douglas Anderson
2019-04-12 22:41 ` Douglas Anderson
2019-04-12 22:41 ` [3/4] " Doug Anderson
2019-04-13 0:00 ` [PATCH 3/4] " Matthias Kaehlcke
2019-04-13 0:00 ` Matthias Kaehlcke
2019-04-13 0:00 ` [3/4] " Matthias Kaehlcke
2019-04-12 22:41 ` [PATCH 4/4] ARM: dts: rockchip: Add quirk for resetting rk3288's dwc2 host on wakeup Douglas Anderson
2019-04-12 22:41 ` Douglas Anderson
2019-04-12 22:41 ` [4/4] " Doug Anderson
2019-04-12 23:57 ` [PATCH 4/4] " Matthias Kaehlcke
2019-04-12 23:57 ` Matthias Kaehlcke
2019-04-12 23:57 ` [4/4] " Matthias Kaehlcke
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=20190412235633.GY112750@google.com \
--to=mka@chromium.org \
--cc=amstan@chromium.org \
--cc=ayaka@soulik.info \
--cc=dianders@chromium.org \
--cc=felipe.balbi@linux.intel.com \
--cc=gregkh@linuxfoundation.org \
--cc=heiko@sntech.de \
--cc=hminas@synopsys.com \
--cc=jwerner@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=linux-usb@vger.kernel.org \
--cc=lyz@rock-chips.com \
--cc=robh+dt@kernel.org \
--cc=ryandcase@chromium.org \
--cc=zhangqing@rock-chips.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 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.