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), ®->device_regs.in_endp[EP0_CON].diepdma); writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1), ®->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), ®->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), ®->device_regs.out_endp[EP0_CON].doepdma); setbits_le32(®->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), ®->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), ®->device_regs.out_endp[EP0_CON].doepdma); setbits_le32(®->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), ®->device_regs.out_endp[ep_num].doepdma); + writel(dwc2_phys_to_bus((unsigned long)ep->dma_buf), + ®->device_regs.out_endp[ep_num].doepdma); writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, pktcnt) | FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, length), ®->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), ®->device_regs.in_endp[ep_num].diepdma); + writel(dwc2_phys_to_bus((unsigned long)ep->dma_buf), + ®->device_regs.in_endp[ep_num].diepdma); writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, pktcnt) | FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, length), ®->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), ®->device_regs.in_endp[EP0_CON].diepdma); + writel(dwc2_phys_to_bus(usb_ctrl_dma_addr), ®->device_regs.in_endp[EP0_CON].diepdma); writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1) | FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, 2), ®->device_regs.in_endp[EP0_CON].dieptsiz); -- 2.54.0
