The bcm283x phys_to_bus() helper applies the 0xC0000000 VideoCore alias
unconditionally. On BCM2712 the OTG controller sits under the axi bus
with identity dma-ranges, so the alias points DMA at nothing and the
host sees 'device descriptor read/64, error -71' during enumeration.
Use the DT-aware dev_phys_to_bus() like macb/sdhci/nvme already do; on
BCM2711 the soc node's dma-ranges still yields the alias.

Tested on a Raspberry Pi CM5 Lite (BCM2712): the CDC-ACM gadget
enumerates and works as a U-Boot console. Also tested on a Compute
Module 4 (BCM2711) to confirm no regression: the gadget still
enumerates cleanly there.

This is my first contribution to u-boot, let me know if I am not following
process and I can adjust. My hope would be to do any testing you
need on this patch so it can land, and I can stop patching 20 machines
 in my talos cluster with my own sketchy patch.

Signed-off-by: Levi Tomes <[email protected]>
---

Notes for reviewers.

How this was tested:

 - BCM2712 (CM5 Lite): with the fix, the CDC-ACM gadget enumerates on
   the OTG port and serves a working U-Boot console. Without it,
   enumeration fails with "device descriptor read/64, error -71" as
   described above.

 - BCM2711 (CM4): regression check. U-Boot built from rpi_4_defconfig
   plus USB_GADGET_DWC2_OTG/USB_FUNCTION_ACM, loaded over USB with
   rpiboot; the gadget enumerates cleanly (0525:a4a7, cdc_acm bound, no
   descriptor errors). rpi_4_defconfig also builds clean with the
   change.

Note on the BCM2712 side: Raspberry Pi 5 / CM5 support is not upstream
yet, so that testing used an out-of-tree Pi5 patch stack. The change
itself is independent of Pi5 support -- it only swaps phys_to_bus() for
the DT-aware dev_phys_to_bus() in the dwc2 gadget, the same pattern
macb, sdhci and nvme already use.

 drivers/usb/gadget/dwc2_udc_otg.c          | 10 ++++++++++
 drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c | 14 ++++++++------
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/dwc2_udc_otg.c
b/drivers/usb/gadget/dwc2_udc_otg.c
index e475b14b9a..3835244cca 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -168,6 +168,15 @@ __weak void otg_phy_off(struct dwc2_udc *dev) {}

 /***********************************************************/

+/* udevice of the probed controller, for DT-aware DMA address translation */
+static struct udevice *dwc2_udc_udev;
+static inline unsigned long dwc2_phys_to_bus(unsigned long addr)
+{
+ if (dwc2_udc_udev)
+ return dev_phys_to_bus(dwc2_udc_udev, addr);
+ return phys_to_bus(addr);
+}
+
 #include "dwc2_udc_otg_xfer_dma.c"

 /*
@@ -1073,6 +1082,7 @@ static int dwc2_udc_otg_clk_init(struct udevice *dev,

 static int dwc2_udc_otg_probe(struct udevice *dev)
 {
+ dwc2_udc_udev = dev;
  struct dwc2_plat_otg_data *plat = dev_get_plat(dev);
  struct dwc2_priv_data *priv = dev_get_priv(dev);
  struct dwc2_core_regs *usbotg_reg =
diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
index 5a7f50ebaa..04c0485ae9 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
+++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c
@@ -31,7 +31,7 @@ int clear_feature_flag;

 static inline void dwc2_udc_ep0_zlp(struct dwc2_udc *dev)
 {
- writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr),
+ writel(dwc2_phys_to_bus((unsigned long)usb_ctrl_dma_addr),
        &reg->device_regs.in_endp[EP0_CON].diepdma);
  writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1),
&reg->device_regs.in_endp[EP0_CON].dieptsiz);

@@ -49,7 +49,7 @@ static void dwc2_udc_pre_setup(void)

  writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1) | sizeof(struct usb_ctrlrequest),
        &reg->device_regs.out_endp[EP0_CON].doeptsiz);
- writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr),
+ writel(dwc2_phys_to_bus((unsigned long)usb_ctrl_dma_addr),
        &reg->device_regs.out_endp[EP0_CON].doepdma);

  setbits_le32(&reg->device_regs.out_endp[EP0_CON].doepctl, DXEPCTL_EPENA);
@@ -72,7 +72,7 @@ static inline void dwc2_ep0_complete_out(void)

  writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1) | sizeof(struct usb_ctrlrequest),
        &reg->device_regs.out_endp[EP0_CON].doeptsiz);
- writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr),
+ writel(dwc2_phys_to_bus((unsigned long)usb_ctrl_dma_addr),
        &reg->device_regs.out_endp[EP0_CON].doepdma);

  setbits_le32(&reg->device_regs.out_endp[EP0_CON].doepctl,
DXEPCTL_EPENA | DXEPCTL_CNAK);
@@ -107,7 +107,8 @@ static int setdma_rx(struct dwc2_ep *ep, struct
dwc2_request *req)
  (unsigned long) ep->dma_buf +
  ROUND(ep->len, CONFIG_SYS_CACHELINE_SIZE));

- writel(phys_to_bus((unsigned long)ep->dma_buf),
&reg->device_regs.out_endp[ep_num].doepdma);
+ writel(dwc2_phys_to_bus((unsigned long)ep->dma_buf),
+       &reg->device_regs.out_endp[ep_num].doepdma);
  writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, pktcnt) |
        FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, length),
        &reg->device_regs.out_endp[ep_num].doeptsiz);
@@ -152,7 +153,8 @@ static int setdma_tx(struct dwc2_ep *ep, struct
dwc2_request *req)
  /* Flush the endpoint's Tx FIFO */
  dwc2_flush_tx_fifo(reg, ep->fifo_num);

- writel(phys_to_bus((unsigned long)ep->dma_buf),
&reg->device_regs.in_endp[ep_num].diepdma);
+ writel(dwc2_phys_to_bus((unsigned long)ep->dma_buf),
+       &reg->device_regs.in_endp[ep_num].diepdma);
  writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, pktcnt) |
        FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, length),
        &reg->device_regs.in_endp[ep_num].dieptsiz);
@@ -913,7 +915,7 @@ static int dwc2_udc_get_status(struct dwc2_udc *dev,
    (unsigned long) usb_ctrl +
    ROUND(sizeof(g_status), CONFIG_SYS_CACHELINE_SIZE));

- writel(phys_to_bus(usb_ctrl_dma_addr),
&reg->device_regs.in_endp[EP0_CON].diepdma);
+ writel(dwc2_phys_to_bus(usb_ctrl_dma_addr),
&reg->device_regs.in_endp[EP0_CON].diepdma);
  writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1) |
FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, 2),
        &reg->device_regs.in_endp[EP0_CON].dieptsiz);

-- 
2.54.0

Reply via email to