diff options
author | Tom Rini <trini@konsulko.com> | 2023-12-02 13:37:27 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-12-02 13:37:27 -0500 |
commit | b56d21f3bbc28f773536df282467833af6fdab1f (patch) | |
tree | 75761f4fe2a06aa22e0380b5d0e27fa68e810603 | |
parent | 43f2873fa98b1da6eb56d756315c7bd7db63db27 (diff) | |
parent | 493e0e2577bfe11b3065a30a6f5c827f95c1df94 (diff) | |
download | u-boot-b56d21f3bbc28f773536df282467833af6fdab1f.zip u-boot-b56d21f3bbc28f773536df282467833af6fdab1f.tar.gz u-boot-b56d21f3bbc28f773536df282467833af6fdab1f.tar.bz2 |
Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-usbWIP/02Dec2023
- USB XHCI fixes
-rw-r--r-- | common/usb_hub.c | 7 | ||||
-rw-r--r-- | common/usb_storage.c | 22 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-generic.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 72 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 9 | ||||
-rw-r--r-- | include/usb/xhci.h | 2 |
7 files changed, 90 insertions, 25 deletions
diff --git a/common/usb_hub.c b/common/usb_hub.c index 85c0822..70279f3 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -395,6 +395,13 @@ int usb_hub_port_connect_change(struct usb_device *dev, int port) break; } + /* + * USB 2.0 7.1.7.5: devices must be able to accept a SetAddress() + * request (refer to Section 11.24.2 and Section 9.4 respectively) + * after the reset recovery time 10 ms + */ + mdelay(10); + #if CONFIG_IS_ENABLED(DM_USB) struct udevice *child; diff --git a/common/usb_storage.c b/common/usb_storage.c index 35c656d..774d5bd 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -102,6 +102,7 @@ struct us_data { trans_reset transport_reset; /* reset routine */ trans_cmnd transport; /* transport routine */ unsigned short max_xfer_blk; /* maximum transfer blocks */ + bool cmd12; /* use 12-byte commands (RBC/UFI) */ }; #if !CONFIG_IS_ENABLED(BLK) @@ -359,7 +360,7 @@ static void usb_show_srb(struct scsi_cmd *pccb) { int i; printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen); - for (i = 0; i < 12; i++) + for (i = 0; i < pccb->cmdlen; i++) printf("%02X ", pccb->cmd[i]); printf("\n"); } @@ -898,7 +899,7 @@ do_retry: psrb->cmd[4] = 18; psrb->datalen = 18; psrb->pdata = &srb->sense_buf[0]; - psrb->cmdlen = 12; + psrb->cmdlen = us->cmd12 ? 12 : 6; /* issue the command */ result = usb_stor_CB_comdat(psrb, us); debug("auto request returned %d\n", result); @@ -999,7 +1000,7 @@ static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss) srb->cmd[1] = srb->lun << 5; srb->cmd[4] = 36; srb->datalen = 36; - srb->cmdlen = 12; + srb->cmdlen = ss->cmd12 ? 12 : 6; i = ss->transport(srb, ss); debug("inquiry returns %d\n", i); if (i == 0) @@ -1024,7 +1025,7 @@ static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss) srb->cmd[4] = 18; srb->datalen = 18; srb->pdata = &srb->sense_buf[0]; - srb->cmdlen = 12; + srb->cmdlen = ss->cmd12 ? 12 : 6; ss->transport(srb, ss); debug("Request Sense returned %02X %02X %02X\n", srb->sense_buf[2], srb->sense_buf[12], @@ -1042,7 +1043,7 @@ static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss) srb->cmd[0] = SCSI_TST_U_RDY; srb->cmd[1] = srb->lun << 5; srb->datalen = 0; - srb->cmdlen = 12; + srb->cmdlen = ss->cmd12 ? 12 : 6; if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) { ss->flags |= USB_READY; return 0; @@ -1074,7 +1075,7 @@ static int usb_read_capacity(struct scsi_cmd *srb, struct us_data *ss) srb->cmd[0] = SCSI_RD_CAPAC; srb->cmd[1] = srb->lun << 5; srb->datalen = 8; - srb->cmdlen = 12; + srb->cmdlen = ss->cmd12 ? 12 : 10; if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) return 0; } while (retry--); @@ -1094,7 +1095,7 @@ static int usb_read_10(struct scsi_cmd *srb, struct us_data *ss, srb->cmd[5] = ((unsigned char) (start)) & 0xff; srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff; srb->cmd[8] = (unsigned char) blocks & 0xff; - srb->cmdlen = 12; + srb->cmdlen = ss->cmd12 ? 12 : 10; debug("read10: start %lx blocks %x\n", start, blocks); return ss->transport(srb, ss); } @@ -1111,7 +1112,7 @@ static int usb_write_10(struct scsi_cmd *srb, struct us_data *ss, srb->cmd[5] = ((unsigned char) (start)) & 0xff; srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff; srb->cmd[8] = (unsigned char) blocks & 0xff; - srb->cmdlen = 12; + srb->cmdlen = ss->cmd12 ? 12 : 10; debug("write10: start %lx blocks %x\n", start, blocks); return ss->transport(srb, ss); } @@ -1417,6 +1418,11 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum, printf("Sorry, protocol %d not yet supported.\n", ss->subclass); return 0; } + + /* UFI uses 12-byte commands (like RBC, unlike SCSI) */ + if (ss->subclass == US_SC_UFI) + ss->cmd12 = true; + if (ss->ep_int) { /* we had found an interrupt endpoint, prepare irq pipe * set up the IRQ pipe and handler diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 744fde8..6fb2de8 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -610,6 +610,7 @@ static const struct udevice_id dwc3_glue_ids[] = { { .compatible = "rockchip,rk3328-dwc3", .data = (ulong)&rk_ops }, { .compatible = "rockchip,rk3399-dwc3" }, { .compatible = "rockchip,rk3568-dwc3", .data = (ulong)&rk_ops }, + { .compatible = "rockchip,rk3588-dwc3", .data = (ulong)&rk_ops }, { .compatible = "qcom,dwc3" }, { .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops }, { .compatible = "fsl,imx8mq-dwc3" }, diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index b501ea5..35610ff 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -90,7 +90,7 @@ config USB_XHCI_OMAP config USB_XHCI_PCI bool "Support for PCI-based xHCI USB controller" - depends on DM_USB + depends on DM_USB && PCI default y if X86 help Enables support for the PCI-based xHCI controller. diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index c8260cb..b60661f 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -202,6 +202,7 @@ static dma_addr_t queue_trb(struct xhci_ctrl *ctrl, struct xhci_ring *ring, bool more_trbs_coming, unsigned int *trb_fields) { struct xhci_generic_trb *trb; + dma_addr_t addr; int i; trb = &ring->enqueue->generic; @@ -211,9 +212,11 @@ static dma_addr_t queue_trb(struct xhci_ctrl *ctrl, struct xhci_ring *ring, xhci_flush_cache((uintptr_t)trb, sizeof(struct xhci_generic_trb)); + addr = xhci_trb_virt_to_dma(ring->enq_seg, (union xhci_trb *)trb); + inc_enq(ctrl, ring, more_trbs_coming); - return xhci_trb_virt_to_dma(ring->enq_seg, (union xhci_trb *)trb); + return addr; } /** @@ -243,7 +246,8 @@ static int prepare_ring(struct xhci_ctrl *ctrl, struct xhci_ring *ep_ring, puts("WARN waiting for error on ep to be cleared\n"); return -EINVAL; case EP_STATE_HALTED: - puts("WARN halted endpoint, queueing URB anyway.\n"); + puts("WARN endpoint is halted\n"); + return -EINVAL; case EP_STATE_STOPPED: case EP_STATE_RUNNING: debug("EP STATE RUNNING.\n"); @@ -466,7 +470,8 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected) continue; type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags)); - if (type == expected) + if (type == expected || + (expected == TRB_NONE && type != TRB_PORT_STATUS)) return event; if (type == TRB_PORT_STATUS) @@ -492,8 +497,9 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected) if (expected == TRB_TRANSFER) return NULL; - printf("XHCI timeout on event type %d... cannot recover.\n", expected); - BUG(); + printf("XHCI timeout on event type %d...\n", expected); + + return NULL; } /* @@ -511,6 +517,9 @@ static void reset_ep(struct usb_device *udev, int ep_index) printf("Resetting EP %d...\n", ep_index); xhci_queue_command(ctrl, 0, udev->slot_id, ep_index, TRB_RESET_EP); event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + if (!event) + return; + field = le32_to_cpu(event->trans_event.flags); BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id); xhci_acknowledge_event(ctrl); @@ -519,6 +528,9 @@ static void reset_ep(struct usb_device *udev, int ep_index) (void *)((uintptr_t)ring->enqueue | ring->cycle_state)); xhci_queue_command(ctrl, addr, udev->slot_id, ep_index, TRB_SET_DEQ); event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + if (!event) + return; + BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != udev->slot_id || GET_COMP_CODE(le32_to_cpu( event->event_cmd.status)) != COMP_SUCCESS); @@ -538,29 +550,49 @@ static void abort_td(struct usb_device *udev, int ep_index) struct xhci_ctrl *ctrl = xhci_get_ctrl(udev); struct xhci_ring *ring = ctrl->devs[udev->slot_id]->eps[ep_index].ring; union xhci_trb *event; + xhci_comp_code comp; + trb_type type; u64 addr; u32 field; xhci_queue_command(ctrl, 0, udev->slot_id, ep_index, TRB_STOP_RING); - event = xhci_wait_for_event(ctrl, TRB_TRANSFER); - field = le32_to_cpu(event->trans_event.flags); - BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id); - BUG_ON(TRB_TO_EP_INDEX(field) != ep_index); - BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len - != COMP_STOP))); - xhci_acknowledge_event(ctrl); + event = xhci_wait_for_event(ctrl, TRB_NONE); + if (!event) + return; - event = xhci_wait_for_event(ctrl, TRB_COMPLETION); - BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) - != udev->slot_id || GET_COMP_CODE(le32_to_cpu( - event->event_cmd.status)) != COMP_SUCCESS); + type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags)); + if (type == TRB_TRANSFER) { + field = le32_to_cpu(event->trans_event.flags); + BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id); + BUG_ON(TRB_TO_EP_INDEX(field) != ep_index); + BUG_ON(GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len + != COMP_STOP))); + xhci_acknowledge_event(ctrl); + + event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + if (!event) + return; + type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->event_cmd.flags)); + + } else { + printf("abort_td: Expected a TRB_TRANSFER TRB first\n"); + } + + comp = GET_COMP_CODE(le32_to_cpu(event->event_cmd.status)); + BUG_ON(type != TRB_COMPLETION || + TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) + != udev->slot_id || (comp != COMP_SUCCESS && comp + != COMP_CTX_STATE)); xhci_acknowledge_event(ctrl); addr = xhci_trb_virt_to_dma(ring->enq_seg, (void *)((uintptr_t)ring->enqueue | ring->cycle_state)); xhci_queue_command(ctrl, addr, udev->slot_id, ep_index, TRB_SET_DEQ); event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + if (!event) + return; + BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != udev->slot_id || GET_COMP_CODE(le32_to_cpu( event->event_cmd.status)) != COMP_SUCCESS); @@ -644,6 +676,14 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, ep_ctx = xhci_get_ep_ctx(ctrl, virt_dev->out_ctx, ep_index); + /* + * If the endpoint was halted due to a prior error, resume it before + * the next transfer. It is the responsibility of the upper layer to + * have dealt with whatever caused the error. + */ + if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == EP_STATE_HALTED) + reset_ep(udev, ep_index); + ring = virt_dev->eps[ep_index].ring; /* * How much data is (potentially) left before the 64KB boundary? diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5cacf07..d13cbff 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -451,6 +451,9 @@ static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change) xhci_queue_command(ctrl, in_ctx->dma, udev->slot_id, 0, ctx_change ? TRB_EVAL_CONTEXT : TRB_CONFIG_EP); event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + if (!event) + return -ETIMEDOUT; + BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != udev->slot_id); @@ -647,6 +650,9 @@ static int xhci_address_device(struct usb_device *udev, int root_portnr) xhci_queue_command(ctrl, virt_dev->in_ctx->dma, slot_id, 0, TRB_ADDR_DEV); event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + if (!event) + return -ETIMEDOUT; + BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags)) != slot_id); switch (GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))) { @@ -722,6 +728,9 @@ static int _xhci_alloc_device(struct usb_device *udev) xhci_queue_command(ctrl, 0, 0, 0, TRB_ENABLE_SLOT); event = xhci_wait_for_event(ctrl, TRB_COMPLETION); + if (!event) + return -ETIMEDOUT; + BUG_ON(GET_COMP_CODE(le32_to_cpu(event->event_cmd.status)) != COMP_SUCCESS); diff --git a/include/usb/xhci.h b/include/usb/xhci.h index 4a4ac10..04d16a2 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -901,6 +901,8 @@ union xhci_trb { /* TRB type IDs */ typedef enum { + /* reserved, used as a software sentinel */ + TRB_NONE = 0, /* bulk, interrupt, isoc scatter/gather, and control data stage */ TRB_NORMAL = 1, /* setup stage for control transfers */ |