]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Apr 2024 10:18:16 +0000 (12:18 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Apr 2024 10:18:16 +0000 (12:18 +0200)
added patches:
usb-dwc2-gadget-lpm-flow-fix.patch
usb-dwc2-host-fix-hibernation-flow.patch
usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch
usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch
usb-typec-ucsi-ack-unsupported-commands.patch
usb-typec-ucsi-check-for-notifications-after-init.patch
usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch
usb-udc-remove-warning-when-queue-disabled-ep.patch

queue-5.10/series
queue-5.10/usb-dwc2-gadget-lpm-flow-fix.patch [new file with mode: 0644]
queue-5.10/usb-dwc2-host-fix-hibernation-flow.patch [new file with mode: 0644]
queue-5.10/usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch [new file with mode: 0644]
queue-5.10/usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch [new file with mode: 0644]
queue-5.10/usb-typec-ucsi-ack-unsupported-commands.patch [new file with mode: 0644]
queue-5.10/usb-typec-ucsi-check-for-notifications-after-init.patch [new file with mode: 0644]
queue-5.10/usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch [new file with mode: 0644]
queue-5.10/usb-udc-remove-warning-when-queue-disabled-ep.patch [new file with mode: 0644]

index bd47cf122e636efc668ea89d19b59f39ec7ae141..ee707a4bfec883abd77480bbd8883e63a425232e 100644 (file)
@@ -165,3 +165,11 @@ scsi-core-fix-unremoved-procfs-host-directory-regression.patch
 staging-vc04_services-changen-strncpy-to-strscpy_pad.patch
 staging-vc04_services-fix-information-leak-in-create_component.patch
 usb-core-add-hub_get-and-hub_put-routines.patch
+usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch
+usb-dwc2-host-fix-hibernation-flow.patch
+usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch
+usb-dwc2-gadget-lpm-flow-fix.patch
+usb-udc-remove-warning-when-queue-disabled-ep.patch
+usb-typec-ucsi-check-for-notifications-after-init.patch
+usb-typec-ucsi-ack-unsupported-commands.patch
+usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch
diff --git a/queue-5.10/usb-dwc2-gadget-lpm-flow-fix.patch b/queue-5.10/usb-dwc2-gadget-lpm-flow-fix.patch
new file mode 100644 (file)
index 0000000..6e51d31
--- /dev/null
@@ -0,0 +1,150 @@
+From 5d69a3b54e5a630c90d82a4c2bdce3d53dc78710 Mon Sep 17 00:00:00 2001
+From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+Date: Wed, 13 Mar 2024 09:22:13 +0000
+Subject: usb: dwc2: gadget: LPM flow fix
+
+From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+
+commit 5d69a3b54e5a630c90d82a4c2bdce3d53dc78710 upstream.
+
+Added functionality to exit from L1 state by device initiation
+using remote wakeup signaling, in case when function driver queuing
+request while core in L1 state.
+
+Fixes: 273d576c4d41 ("usb: dwc2: gadget: Add functionality to exit from LPM L1 state")
+Fixes: 88b02f2cb1e1 ("usb: dwc2: Add core state checking")
+CC: stable@vger.kernel.org
+Signed-off-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+Link: https://lore.kernel.org/r/b4d9de5382375dddbf7ef6049d9a82066ad87d5d.1710166393.git.Minas.Harutyunyan@synopsys.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc2/core.h      |    1 
+ drivers/usb/dwc2/core_intr.c |   65 ++++++++++++++++++++++++++++---------------
+ drivers/usb/dwc2/gadget.c    |    4 ++
+ 3 files changed, 48 insertions(+), 22 deletions(-)
+
+--- a/drivers/usb/dwc2/core.h
++++ b/drivers/usb/dwc2/core.h
+@@ -1348,6 +1348,7 @@ int dwc2_backup_global_registers(struct
+ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg);
+ void dwc2_enable_acg(struct dwc2_hsotg *hsotg);
++void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg, bool remotewakeup);
+ /* This function should be called on every hardware interrupt. */
+ irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
+--- a/drivers/usb/dwc2/core_intr.c
++++ b/drivers/usb/dwc2/core_intr.c
+@@ -344,10 +344,11 @@ static void dwc2_handle_session_req_intr
+  * @hsotg: Programming view of DWC_otg controller
+  *
+  */
+-static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg)
++void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg, bool remotewakeup)
+ {
+       u32 glpmcfg;
+-      u32 i = 0;
++      u32 pcgctl;
++      u32 dctl;
+       if (hsotg->lx_state != DWC2_L1) {
+               dev_err(hsotg->dev, "Core isn't in DWC2_L1 state\n");
+@@ -356,37 +357,57 @@ static void dwc2_wakeup_from_lpm_l1(stru
+       glpmcfg = dwc2_readl(hsotg, GLPMCFG);
+       if (dwc2_is_device_mode(hsotg)) {
+-              dev_dbg(hsotg->dev, "Exit from L1 state\n");
++              dev_dbg(hsotg->dev, "Exit from L1 state, remotewakeup=%d\n", remotewakeup);
+               glpmcfg &= ~GLPMCFG_ENBLSLPM;
+-              glpmcfg &= ~GLPMCFG_HIRD_THRES_EN;
++              glpmcfg &= ~GLPMCFG_HIRD_THRES_MASK;
+               dwc2_writel(hsotg, glpmcfg, GLPMCFG);
+-              do {
+-                      glpmcfg = dwc2_readl(hsotg, GLPMCFG);
+-
+-                      if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK |
+-                                       GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS)))
+-                              break;
++              pcgctl = dwc2_readl(hsotg, PCGCTL);
++              pcgctl &= ~PCGCTL_ENBL_SLEEP_GATING;
++              dwc2_writel(hsotg, pcgctl, PCGCTL);
++
++              glpmcfg = dwc2_readl(hsotg, GLPMCFG);
++              if (glpmcfg & GLPMCFG_ENBESL) {
++                      glpmcfg |= GLPMCFG_RSTRSLPSTS;
++                      dwc2_writel(hsotg, glpmcfg, GLPMCFG);
++              }
+-                      udelay(1);
+-              } while (++i < 200);
++              if (remotewakeup) {
++                      if (dwc2_hsotg_wait_bit_set(hsotg, GLPMCFG, GLPMCFG_L1RESUMEOK, 1000)) {
++                              dev_warn(hsotg->dev, "%s: timeout GLPMCFG_L1RESUMEOK\n", __func__);
++                              goto fail;
++                              return;
++                      }
++
++                      dctl = dwc2_readl(hsotg, DCTL);
++                      dctl |= DCTL_RMTWKUPSIG;
++                      dwc2_writel(hsotg, dctl, DCTL);
++
++                      if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, GINTSTS_WKUPINT, 1000)) {
++                              dev_warn(hsotg->dev, "%s: timeout GINTSTS_WKUPINT\n", __func__);
++                              goto fail;
++                              return;
++                      }
++              }
+-              if (i == 200) {
+-                      dev_err(hsotg->dev, "Failed to exit L1 sleep state in 200us.\n");
++              glpmcfg = dwc2_readl(hsotg, GLPMCFG);
++              if (glpmcfg & GLPMCFG_COREL1RES_MASK || glpmcfg & GLPMCFG_SLPSTS ||
++                  glpmcfg & GLPMCFG_L1RESUMEOK) {
++                      goto fail;
+                       return;
+               }
+-              dwc2_gadget_init_lpm(hsotg);
++
++              /* Inform gadget to exit from L1 */
++              call_gadget(hsotg, resume);
++              /* Change to L0 state */
++              hsotg->lx_state = DWC2_L0;
++              hsotg->bus_suspended = false;
++fail:         dwc2_gadget_init_lpm(hsotg);
+       } else {
+               /* TODO */
+               dev_err(hsotg->dev, "Host side LPM is not supported.\n");
+               return;
+       }
+-
+-      /* Change to L0 state */
+-      hsotg->lx_state = DWC2_L0;
+-
+-      /* Inform gadget to exit from L1 */
+-      call_gadget(hsotg, resume);
+ }
+ /*
+@@ -407,7 +428,7 @@ static void dwc2_handle_wakeup_detected_
+       dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
+       if (hsotg->lx_state == DWC2_L1) {
+-              dwc2_wakeup_from_lpm_l1(hsotg);
++              dwc2_wakeup_from_lpm_l1(hsotg, false);
+               return;
+       }
+--- a/drivers/usb/dwc2/gadget.c
++++ b/drivers/usb/dwc2/gadget.c
+@@ -1416,6 +1416,10 @@ static int dwc2_hsotg_ep_queue(struct us
+               ep->name, req, req->length, req->buf, req->no_interrupt,
+               req->zero, req->short_not_ok);
++      if (hs->lx_state == DWC2_L1) {
++              dwc2_wakeup_from_lpm_l1(hs, true);
++      }
++
+       /* Prevent new request submission when controller is suspended */
+       if (hs->lx_state != DWC2_L0) {
+               dev_dbg(hs->dev, "%s: submit request only in active state\n",
diff --git a/queue-5.10/usb-dwc2-host-fix-hibernation-flow.patch b/queue-5.10/usb-dwc2-host-fix-hibernation-flow.patch
new file mode 100644 (file)
index 0000000..cb8b938
--- /dev/null
@@ -0,0 +1,94 @@
+From 3c7b9856a82227db01a20171d2e24c7ce305d59b Mon Sep 17 00:00:00 2001
+From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+Date: Wed, 13 Mar 2024 09:21:11 +0000
+Subject: usb: dwc2: host: Fix hibernation flow
+
+From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+
+commit 3c7b9856a82227db01a20171d2e24c7ce305d59b upstream.
+
+Added to backup/restore registers HFLBADDR, HCCHARi, HCSPLTi,
+HCTSIZi, HCDMAi and HCDMABi.
+
+Fixes: 58e52ff6a6c3 ("usb: dwc2: Move register save and restore functions")
+Fixes: d17ee77b3044 ("usb: dwc2: add controller hibernation support")
+CC: stable@vger.kernel.org
+Signed-off-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+Link: https://lore.kernel.org/r/c2d10ee6098b9b009a8e94191e046004747d3bdd.1708945444.git.Minas.Harutyunyan@synopsys.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc2/core.h |   12 ++++++++++++
+ drivers/usb/dwc2/hcd.c  |   18 ++++++++++++++++--
+ 2 files changed, 28 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/dwc2/core.h
++++ b/drivers/usb/dwc2/core.h
+@@ -748,8 +748,14 @@ struct dwc2_dregs_backup {
+  * struct dwc2_hregs_backup - Holds host registers state before
+  * entering partial power down
+  * @hcfg:             Backup of HCFG register
++ * @hflbaddr:         Backup of HFLBADDR register
+  * @haintmsk:         Backup of HAINTMSK register
++ * @hcchar:           Backup of HCCHAR register
++ * @hcsplt:           Backup of HCSPLT register
+  * @hcintmsk:         Backup of HCINTMSK register
++ * @hctsiz:           Backup of HCTSIZ register
++ * @hdma:             Backup of HCDMA register
++ * @hcdmab:           Backup of HCDMAB register
+  * @hprt0:            Backup of HPTR0 register
+  * @hfir:             Backup of HFIR register
+  * @hptxfsiz:         Backup of HPTXFSIZ register
+@@ -757,8 +763,14 @@ struct dwc2_dregs_backup {
+  */
+ struct dwc2_hregs_backup {
+       u32 hcfg;
++      u32 hflbaddr;
+       u32 haintmsk;
++      u32 hcchar[MAX_EPS_CHANNELS];
++      u32 hcsplt[MAX_EPS_CHANNELS];
+       u32 hcintmsk[MAX_EPS_CHANNELS];
++      u32 hctsiz[MAX_EPS_CHANNELS];
++      u32 hcidma[MAX_EPS_CHANNELS];
++      u32 hcidmab[MAX_EPS_CHANNELS];
+       u32 hprt0;
+       u32 hfir;
+       u32 hptxfsiz;
+--- a/drivers/usb/dwc2/hcd.c
++++ b/drivers/usb/dwc2/hcd.c
+@@ -5319,9 +5319,16 @@ int dwc2_backup_host_registers(struct dw
+       /* Backup Host regs */
+       hr = &hsotg->hr_backup;
+       hr->hcfg = dwc2_readl(hsotg, HCFG);
++      hr->hflbaddr = dwc2_readl(hsotg, HFLBADDR);
+       hr->haintmsk = dwc2_readl(hsotg, HAINTMSK);
+-      for (i = 0; i < hsotg->params.host_channels; ++i)
++      for (i = 0; i < hsotg->params.host_channels; ++i) {
++              hr->hcchar[i] = dwc2_readl(hsotg, HCCHAR(i));
++              hr->hcsplt[i] = dwc2_readl(hsotg, HCSPLT(i));
+               hr->hcintmsk[i] = dwc2_readl(hsotg, HCINTMSK(i));
++              hr->hctsiz[i] = dwc2_readl(hsotg, HCTSIZ(i));
++              hr->hcidma[i] = dwc2_readl(hsotg, HCDMA(i));
++              hr->hcidmab[i] = dwc2_readl(hsotg, HCDMAB(i));
++      }
+       hr->hprt0 = dwc2_read_hprt0(hsotg);
+       hr->hfir = dwc2_readl(hsotg, HFIR);
+@@ -5355,10 +5362,17 @@ int dwc2_restore_host_registers(struct d
+       hr->valid = false;
+       dwc2_writel(hsotg, hr->hcfg, HCFG);
++      dwc2_writel(hsotg, hr->hflbaddr, HFLBADDR);
+       dwc2_writel(hsotg, hr->haintmsk, HAINTMSK);
+-      for (i = 0; i < hsotg->params.host_channels; ++i)
++      for (i = 0; i < hsotg->params.host_channels; ++i) {
++              dwc2_writel(hsotg, hr->hcchar[i], HCCHAR(i));
++              dwc2_writel(hsotg, hr->hcsplt[i], HCSPLT(i));
+               dwc2_writel(hsotg, hr->hcintmsk[i], HCINTMSK(i));
++              dwc2_writel(hsotg, hr->hctsiz[i], HCTSIZ(i));
++              dwc2_writel(hsotg, hr->hcidma[i], HCDMA(i));
++              dwc2_writel(hsotg, hr->hcidmab[i], HCDMAB(i));
++      }
+       dwc2_writel(hsotg, hr->hprt0, HPRT0);
+       dwc2_writel(hsotg, hr->hfir, HFIR);
diff --git a/queue-5.10/usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch b/queue-5.10/usb-dwc2-host-fix-isoc-flow-in-ddma-mode.patch
new file mode 100644 (file)
index 0000000..69efda5
--- /dev/null
@@ -0,0 +1,134 @@
+From b258e42688501cadb1a6dd658d6f015df9f32d8f Mon Sep 17 00:00:00 2001
+From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+Date: Wed, 13 Mar 2024 09:21:32 +0000
+Subject: usb: dwc2: host: Fix ISOC flow in DDMA mode
+
+From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+
+commit b258e42688501cadb1a6dd658d6f015df9f32d8f upstream.
+
+Fixed ISOC completion flow in DDMA mode. Added isoc
+descriptor actual length value and update urb's start_frame
+value.
+Fixed initialization of ISOC DMA descriptors flow.
+
+Fixes: 56f5b1cff22a ("staging: Core files for the DWC2 driver")
+Fixes: 20f2eb9c4cf8 ("staging: dwc2: add microframe scheduler from downstream Pi kernel")
+Fixes: c17b337c1ea4 ("usb: dwc2: host: program descriptor for next frame")
+Fixes: dc4c76e7b22c ("staging: HCD descriptor DMA support for the DWC2 driver")
+Fixes: 762d3a1a9cd7 ("usb: dwc2: host: process all completed urbs")
+CC: stable@vger.kernel.org
+Signed-off-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+Link: https://lore.kernel.org/r/a8b1e1711cc6cabfb45d92ede12e35445c66f06c.1708944698.git.Minas.Harutyunyan@synopsys.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc2/hcd.c      |   12 ++++++++++--
+ drivers/usb/dwc2/hcd_ddma.c |   17 +++++++++++------
+ drivers/usb/dwc2/hw.h       |    2 +-
+ 3 files changed, 22 insertions(+), 9 deletions(-)
+
+--- a/drivers/usb/dwc2/hcd.c
++++ b/drivers/usb/dwc2/hcd.c
+@@ -2736,8 +2736,11 @@ enum dwc2_transaction_type dwc2_hcd_sele
+                       hsotg->available_host_channels--;
+               }
+               qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
+-              if (dwc2_assign_and_init_hc(hsotg, qh))
++              if (dwc2_assign_and_init_hc(hsotg, qh)) {
++                      if (hsotg->params.uframe_sched)
++                              hsotg->available_host_channels++;
+                       break;
++              }
+               /*
+                * Move the QH from the periodic ready schedule to the
+@@ -2770,8 +2773,11 @@ enum dwc2_transaction_type dwc2_hcd_sele
+                       hsotg->available_host_channels--;
+               }
+-              if (dwc2_assign_and_init_hc(hsotg, qh))
++              if (dwc2_assign_and_init_hc(hsotg, qh)) {
++                      if (hsotg->params.uframe_sched)
++                              hsotg->available_host_channels++;
+                       break;
++              }
+               /*
+                * Move the QH from the non-periodic inactive schedule to the
+@@ -4125,6 +4131,8 @@ void dwc2_host_complete(struct dwc2_hsot
+                        urb->actual_length);
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
++              if (!hsotg->params.dma_desc_enable)
++                      urb->start_frame = qtd->qh->start_active_frame;
+               urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb);
+               for (i = 0; i < urb->number_of_packets; ++i) {
+                       urb->iso_frame_desc[i].actual_length =
+--- a/drivers/usb/dwc2/hcd_ddma.c
++++ b/drivers/usb/dwc2/hcd_ddma.c
+@@ -589,7 +589,7 @@ static void dwc2_init_isoc_dma_desc(stru
+       idx = qh->td_last;
+       inc = qh->host_interval;
+       hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
+-      cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
++      cur_idx = idx;
+       next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed);
+       /*
+@@ -896,6 +896,8 @@ static int dwc2_cmpl_host_isoc_dma_desc(
+ {
+       struct dwc2_dma_desc *dma_desc;
+       struct dwc2_hcd_iso_packet_desc *frame_desc;
++      u16 frame_desc_idx;
++      struct urb *usb_urb = qtd->urb->priv;
+       u16 remain = 0;
+       int rc = 0;
+@@ -908,8 +910,11 @@ static int dwc2_cmpl_host_isoc_dma_desc(
+                               DMA_FROM_DEVICE);
+       dma_desc = &qh->desc_list[idx];
++      frame_desc_idx = (idx - qtd->isoc_td_first) & (usb_urb->number_of_packets - 1);
+-      frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
++      frame_desc = &qtd->urb->iso_descs[frame_desc_idx];
++      if (idx == qtd->isoc_td_first)
++              usb_urb->start_frame = dwc2_hcd_get_frame_number(hsotg);
+       dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
+       if (chan->ep_is_in)
+               remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >>
+@@ -930,7 +935,7 @@ static int dwc2_cmpl_host_isoc_dma_desc(
+               frame_desc->status = 0;
+       }
+-      if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
++      if (++qtd->isoc_frame_index == usb_urb->number_of_packets) {
+               /*
+                * urb->status is not used for isoc transfers here. The
+                * individual frame_desc status are used instead.
+@@ -1035,11 +1040,11 @@ static void dwc2_complete_isoc_xfer_ddma
+                               return;
+                       idx = dwc2_desclist_idx_inc(idx, qh->host_interval,
+                                                   chan->speed);
+-                      if (!rc)
++                      if (rc == 0)
+                               continue;
+-                      if (rc == DWC2_CMPL_DONE)
+-                              break;
++                      if (rc == DWC2_CMPL_DONE || rc == DWC2_CMPL_STOP)
++                              goto stop_scan;
+                       /* rc == DWC2_CMPL_STOP */
+--- a/drivers/usb/dwc2/hw.h
++++ b/drivers/usb/dwc2/hw.h
+@@ -727,7 +727,7 @@
+ #define TXSTS_QTOP_TOKEN_MASK         (0x3 << 25)
+ #define TXSTS_QTOP_TOKEN_SHIFT                25
+ #define TXSTS_QTOP_TERMINATE          BIT(24)
+-#define TXSTS_QSPCAVAIL_MASK          (0xff << 16)
++#define TXSTS_QSPCAVAIL_MASK          (0x7f << 16)
+ #define TXSTS_QSPCAVAIL_SHIFT         16
+ #define TXSTS_FSPCAVAIL_MASK          (0xffff << 0)
+ #define TXSTS_FSPCAVAIL_SHIFT         0
diff --git a/queue-5.10/usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch b/queue-5.10/usb-dwc2-host-fix-remote-wakeup-from-hibernation.patch
new file mode 100644 (file)
index 0000000..558abcf
--- /dev/null
@@ -0,0 +1,66 @@
+From bae2bc73a59c200db53b6c15fb26bb758e2c6108 Mon Sep 17 00:00:00 2001
+From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+Date: Wed, 13 Mar 2024 09:21:21 +0000
+Subject: usb: dwc2: host: Fix remote wakeup from hibernation
+
+From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+
+commit bae2bc73a59c200db53b6c15fb26bb758e2c6108 upstream.
+
+Starting from core v4.30a changed order of programming
+GPWRDN_PMUACTV to 0 in case of exit from hibernation on
+remote wakeup signaling from device.
+
+Fixes: c5c403dc4336 ("usb: dwc2: Add host/device hibernation functions")
+CC: stable@vger.kernel.org
+Signed-off-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
+Link: https://lore.kernel.org/r/99385ec55ce73445b6fbd0f471c9bd40eb1c9b9e.1708939799.git.Minas.Harutyunyan@synopsys.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc2/core.h |    1 +
+ drivers/usb/dwc2/hcd.c  |   17 +++++++++++++----
+ 2 files changed, 14 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/dwc2/core.h
++++ b/drivers/usb/dwc2/core.h
+@@ -1097,6 +1097,7 @@ struct dwc2_hsotg {
+       bool needs_byte_swap;
+       /* DWC OTG HW Release versions */
++#define DWC2_CORE_REV_4_30a   0x4f54430a
+ #define DWC2_CORE_REV_2_71a   0x4f54271a
+ #define DWC2_CORE_REV_2_72a     0x4f54272a
+ #define DWC2_CORE_REV_2_80a   0x4f54280a
+--- a/drivers/usb/dwc2/hcd.c
++++ b/drivers/usb/dwc2/hcd.c
+@@ -5523,10 +5523,12 @@ int dwc2_host_exit_hibernation(struct dw
+       dwc2_writel(hsotg, hr->hcfg, HCFG);
+       /* De-assert Wakeup Logic */
+-      gpwrdn = dwc2_readl(hsotg, GPWRDN);
+-      gpwrdn &= ~GPWRDN_PMUACTV;
+-      dwc2_writel(hsotg, gpwrdn, GPWRDN);
+-      udelay(10);
++      if (!(rem_wakeup && hsotg->hw_params.snpsid >= DWC2_CORE_REV_4_30a)) {
++              gpwrdn = dwc2_readl(hsotg, GPWRDN);
++              gpwrdn &= ~GPWRDN_PMUACTV;
++              dwc2_writel(hsotg, gpwrdn, GPWRDN);
++              udelay(10);
++      }
+       hprt0 = hr->hprt0;
+       hprt0 |= HPRT0_PWR;
+@@ -5551,6 +5553,13 @@ int dwc2_host_exit_hibernation(struct dw
+               hprt0 |= HPRT0_RES;
+               dwc2_writel(hsotg, hprt0, HPRT0);
++              /* De-assert Wakeup Logic */
++              if ((rem_wakeup && hsotg->hw_params.snpsid >= DWC2_CORE_REV_4_30a)) {
++                      gpwrdn = dwc2_readl(hsotg, GPWRDN);
++                      gpwrdn &= ~GPWRDN_PMUACTV;
++                      dwc2_writel(hsotg, gpwrdn, GPWRDN);
++                      udelay(10);
++              }
+               /* Wait for Resume time and then program HPRT again */
+               mdelay(100);
+               hprt0 &= ~HPRT0_RES;
diff --git a/queue-5.10/usb-typec-ucsi-ack-unsupported-commands.patch b/queue-5.10/usb-typec-ucsi-ack-unsupported-commands.patch
new file mode 100644 (file)
index 0000000..68ecbb1
--- /dev/null
@@ -0,0 +1,40 @@
+From 6b5c85ddeea77d18c4b69e3bda60e9374a20c304 Mon Sep 17 00:00:00 2001
+From: "Christian A. Ehrhardt" <lk@c--e.de>
+Date: Wed, 20 Mar 2024 08:39:24 +0100
+Subject: usb: typec: ucsi: Ack unsupported commands
+
+From: Christian A. Ehrhardt <lk@c--e.de>
+
+commit 6b5c85ddeea77d18c4b69e3bda60e9374a20c304 upstream.
+
+If a command completes the OPM must send an ack. This applies
+to unsupported commands, too.
+
+Send the required ACK for unsupported commands.
+
+Signed-off-by: Christian A. Ehrhardt <lk@c--e.de>
+Cc: stable <stable@kernel.org>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
+Link: https://lore.kernel.org/r/20240320073927.1641788-4-lk@c--e.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -138,8 +138,12 @@ static int ucsi_exec_command(struct ucsi
+       if (!(cci & UCSI_CCI_COMMAND_COMPLETE))
+               return -EIO;
+-      if (cci & UCSI_CCI_NOT_SUPPORTED)
++      if (cci & UCSI_CCI_NOT_SUPPORTED) {
++              if (ucsi_acknowledge_command(ucsi) < 0)
++                      dev_err(ucsi->dev,
++                              "ACK of unsupported command failed\n");
+               return -EOPNOTSUPP;
++      }
+       if (cci & UCSI_CCI_ERROR) {
+               if (cmd == UCSI_GET_ERROR_STATUS)
diff --git a/queue-5.10/usb-typec-ucsi-check-for-notifications-after-init.patch b/queue-5.10/usb-typec-ucsi-check-for-notifications-after-init.patch
new file mode 100644 (file)
index 0000000..ac424d2
--- /dev/null
@@ -0,0 +1,64 @@
+From 808a8b9e0b87bbc72bcc1f7ddfe5d04746e7ce56 Mon Sep 17 00:00:00 2001
+From: "Christian A. Ehrhardt" <lk@c--e.de>
+Date: Wed, 20 Mar 2024 08:39:23 +0100
+Subject: usb: typec: ucsi: Check for notifications after init
+
+From: Christian A. Ehrhardt <lk@c--e.de>
+
+commit 808a8b9e0b87bbc72bcc1f7ddfe5d04746e7ce56 upstream.
+
+The completion notification for the final SET_NOTIFICATION_ENABLE
+command during initialization can include a connector change
+notification.  However, at the time this completion notification is
+processed, the ucsi struct is not ready to handle this notification.
+As a result the notification is ignored and the controller
+never sends an interrupt again.
+
+Re-check CCI for a pending connector state change after
+initialization is complete. Adjust the corresponding debug
+message accordingly.
+
+Fixes: 71a1fa0df2a3 ("usb: typec: ucsi: Store the notification mask")
+Cc: stable@vger.kernel.org
+Signed-off-by: Christian A. Ehrhardt <lk@c--e.de>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
+Link: https://lore.kernel.org/r/20240320073927.1641788-3-lk@c--e.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -823,7 +823,7 @@ void ucsi_connector_change(struct ucsi *
+       struct ucsi_connector *con = &ucsi->connector[num - 1];
+       if (!(ucsi->ntfy & UCSI_ENABLE_NTFY_CONNECTOR_CHANGE)) {
+-              dev_dbg(ucsi->dev, "Bogus connector change event\n");
++              dev_dbg(ucsi->dev, "Early connector change event\n");
+               return;
+       }
+@@ -1153,6 +1153,7 @@ static int ucsi_init(struct ucsi *ucsi)
+ {
+       struct ucsi_connector *con;
+       u64 command, ntfy;
++      u32 cci;
+       int ret;
+       int i;
+@@ -1204,6 +1205,13 @@ static int ucsi_init(struct ucsi *ucsi)
+               goto err_unregister;
+       ucsi->ntfy = ntfy;
++
++      ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci));
++      if (ret)
++              return ret;
++      if (UCSI_CCI_CONNECTOR(READ_ONCE(cci)))
++              ucsi_connector_change(ucsi, cci);
++
+       return 0;
+ err_unregister:
diff --git a/queue-5.10/usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch b/queue-5.10/usb-typec-ucsi-clear-ucsi_cci_reset_complete-before-reset.patch
new file mode 100644 (file)
index 0000000..0daf290
--- /dev/null
@@ -0,0 +1,74 @@
+From 3de4f996a0b5412aa451729008130a488f71563e Mon Sep 17 00:00:00 2001
+From: "Christian A. Ehrhardt" <lk@c--e.de>
+Date: Wed, 20 Mar 2024 08:39:26 +0100
+Subject: usb: typec: ucsi: Clear UCSI_CCI_RESET_COMPLETE before reset
+
+From: Christian A. Ehrhardt <lk@c--e.de>
+
+commit 3de4f996a0b5412aa451729008130a488f71563e upstream.
+
+Check the UCSI_CCI_RESET_COMPLETE complete flag before starting
+another reset. Use a UCSI_SET_NOTIFICATION_ENABLE command to clear
+the flag if it is set.
+
+Signed-off-by: Christian A. Ehrhardt <lk@c--e.de>
+Cc: stable <stable@kernel.org>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
+Link: https://lore.kernel.org/r/20240320073927.1641788-6-lk@c--e.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/typec/ucsi/ucsi.c |   36 +++++++++++++++++++++++++++++++++++-
+ 1 file changed, 35 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -852,13 +852,47 @@ static int ucsi_reset_connector(struct u
+ static int ucsi_reset_ppm(struct ucsi *ucsi)
+ {
+-      u64 command = UCSI_PPM_RESET;
++      u64 command;
+       unsigned long tmo;
+       u32 cci;
+       int ret;
+       mutex_lock(&ucsi->ppm_lock);
++      ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci));
++      if (ret < 0)
++              goto out;
++
++      /*
++       * If UCSI_CCI_RESET_COMPLETE is already set we must clear
++       * the flag before we start another reset. Send a
++       * UCSI_SET_NOTIFICATION_ENABLE command to achieve this.
++       * Ignore a timeout and try the reset anyway if this fails.
++       */
++      if (cci & UCSI_CCI_RESET_COMPLETE) {
++              command = UCSI_SET_NOTIFICATION_ENABLE;
++              ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command,
++                                           sizeof(command));
++              if (ret < 0)
++                      goto out;
++
++              tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
++              do {
++                      ret = ucsi->ops->read(ucsi, UCSI_CCI,
++                                            &cci, sizeof(cci));
++                      if (ret < 0)
++                              goto out;
++                      if (cci & UCSI_CCI_COMMAND_COMPLETE)
++                              break;
++                      if (time_is_before_jiffies(tmo))
++                              break;
++                      msleep(20);
++              } while (1);
++
++              WARN_ON(cci & UCSI_CCI_RESET_COMPLETE);
++      }
++
++      command = UCSI_PPM_RESET;
+       ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command,
+                                    sizeof(command));
+       if (ret < 0)
diff --git a/queue-5.10/usb-udc-remove-warning-when-queue-disabled-ep.patch b/queue-5.10/usb-udc-remove-warning-when-queue-disabled-ep.patch
new file mode 100644 (file)
index 0000000..5fc90e1
--- /dev/null
@@ -0,0 +1,44 @@
+From 2a587a035214fa1b5ef598aea0b81848c5b72e5e Mon Sep 17 00:00:00 2001
+From: yuan linyu <yuanlinyu@hihonor.com>
+Date: Fri, 15 Mar 2024 10:01:44 +0800
+Subject: usb: udc: remove warning when queue disabled ep
+
+From: yuan linyu <yuanlinyu@hihonor.com>
+
+commit 2a587a035214fa1b5ef598aea0b81848c5b72e5e upstream.
+
+It is possible trigger below warning message from mass storage function,
+
+WARNING: CPU: 6 PID: 3839 at drivers/usb/gadget/udc/core.c:294 usb_ep_queue+0x7c/0x104
+pc : usb_ep_queue+0x7c/0x104
+lr : fsg_main_thread+0x494/0x1b3c
+
+Root cause is mass storage function try to queue request from main thread,
+but other thread may already disable ep when function disable.
+
+As there is no function failure in the driver, in order to avoid effort
+to fix warning, change WARN_ON_ONCE() in usb_ep_queue() to pr_debug().
+
+Suggested-by: Alan Stern <stern@rowland.harvard.edu>
+Cc: stable@vger.kernel.org
+Signed-off-by: yuan linyu <yuanlinyu@hihonor.com>
+Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://lore.kernel.org/r/20240315020144.2715575-1-yuanlinyu@hihonor.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/udc/core.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/udc/core.c
++++ b/drivers/usb/gadget/udc/core.c
+@@ -273,7 +273,9 @@ int usb_ep_queue(struct usb_ep *ep,
+ {
+       int ret = 0;
+-      if (WARN_ON_ONCE(!ep->enabled && ep->address)) {
++      if (!ep->enabled && ep->address) {
++              pr_debug("USB gadget: queue request to disabled ep 0x%x (%s)\n",
++                               ep->address, ep->name);
+               ret = -ESHUTDOWN;
+               goto out;
+       }