From 5657b2a0287a6d63055f5dfd204253a3aac4b1ae Mon Sep 17 00:00:00 2001 From: sakimisu <1203593632@qq.com> Date: Fri, 21 Apr 2023 23:43:59 +0800 Subject: [PATCH] update hub process for usb3.0, update xhci driver --- class/hub/usb_hub.h | 4 +- class/hub/usbh_hub.c | 88 ++++++++++++++++++++++++- common/usb_def.h | 3 + core/usbh_core.c | 14 +++- core/usbh_core.h | 3 + port/xhci/usb_hc_xhci.c | 8 +++ port/xhci/xhci.c | 141 ++++++++++++++++++++++++++++++---------- 7 files changed, 219 insertions(+), 42 deletions(-) diff --git a/class/hub/usb_hub.h b/class/hub/usb_hub.h index 022ca2a0..7956b163 100644 --- a/class/hub/usb_hub.h +++ b/class/hub/usb_hub.h @@ -7,7 +7,8 @@ #define USB_HUB_H /* HUB Class Descriptor Types */ -#define HUB_DESCRIPTOR_TYPE_HUB 0x29 +#define HUB_DESCRIPTOR_TYPE_HUB 0x29 +#define HUB_DESCRIPTOR_TYPE_HUB3 0x2A /* Hub class requests */ #define HUB_REQUEST_GET_STATUS USB_REQUEST_GET_STATUS @@ -19,6 +20,7 @@ #define HUB_REQUEST_RESET_TT (0x09) #define HUB_REQUEST_GET_TT_STATE (0x0a) #define HUB_REQUEST_STOP_TT (0x0b) +#define HUB_REQUEST_SET_HUB_DEPTH (0x0C) /* Hub class features */ #define HUB_FEATURE_HUB_C_LOCALPOWER (0x0) diff --git a/class/hub/usbh_hub.c b/class/hub/usbh_hub.c index 931deea6..3db343f2 100644 --- a/class/hub/usbh_hub.c +++ b/class/hub/usbh_hub.c @@ -38,6 +38,13 @@ static void usbh_hub_thread_wakeup(struct usbh_hub *hub); static const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" }; +#ifdef CONFIG_USBHOST_XHCI +struct usbh_hubport *usbh_get_roothub_port(unsigned int port) +{ + return &roothub.child[port - 1]; +} +#endif + #if CONFIG_USBHOST_MAX_EXTHUBS > 0 static int usbh_hub_devno_alloc(void) { @@ -82,7 +89,16 @@ static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer) setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE; setup->bRequest = USB_REQUEST_GET_DESCRIPTOR; - setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8; + + /* TODO: hub descriptor has some difference between USB 2.0 and USB 3.x, + and we havn't handle the difference here */ + if ((hub->parent->speed == USB_SPEED_SUPER) || + (hub->parent->speed == USB_SPEED_SUPER_PLUS)) { + setup->wValue = HUB_DESCRIPTOR_TYPE_HUB3 << 8; + } else { + setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8; + } + setup->wIndex = 0; setup->wLength = USB_SIZEOF_HUB_DESC; @@ -167,6 +183,21 @@ static int _usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t f return usbh_control_transfer(hub->parent->ep0, setup, NULL); } +static int _usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth) +{ + struct usb_setup_packet *setup; + + setup = hub->parent->setup; + + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE; + setup->bRequest = HUB_REQUEST_SET_HUB_DEPTH; + setup->wValue = depth; + setup->wIndex = 0; + setup->wLength = 0; + + return usbh_control_transfer(hub->parent->ep0, setup, NULL); +} + #if CONFIG_USBHOST_MAX_EXTHUBS > 0 static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length) { @@ -245,6 +276,24 @@ static int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t fe } } +static int usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth) +{ + struct usb_setup_packet roothub_setup; + struct usb_setup_packet *setup; + + if (hub->is_roothub) { + setup = &roothub_setup; + setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE; + setup->bRequest = HUB_REQUEST_SET_HUB_DEPTH; + setup->wValue = depth; + setup->wIndex = 0; + setup->wLength = 0; + return usbh_roothub_control(setup, NULL); + } else { + return _usbh_hub_set_depth(hub, depth); + } +} + #if CONFIG_USBHOST_MAX_EXTHUBS > 0 static void hub_int_complete_callback(void *arg, int nbytes) { @@ -297,6 +346,20 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf) return -1; } + if (hport->speed == USB_SPEED_SUPER) { + uint16_t depth = 0; + struct usbh_hubport *parent = hport->parent->parent; + while (parent) { + depth++; + parent = parent->parent->parent; + } + + ret = usbh_hub_set_depth(hub, depth); + if (ret < 0) { + return ret; + } + } + for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) { ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_POWER); if (ret < 0) { @@ -502,9 +565,26 @@ static void usbh_hub_events(struct usbh_hub *hub) speed = USB_SPEED_HIGH; } else if (portstatus & HUB_PORT_STATUS_LOW_SPEED) { speed = USB_SPEED_LOW; - } else { + } +#ifdef CONFIG_USBHOST_XHCI + extern uint8_t usbh_get_port_speed(struct usbh_hub * hub, const uint8_t port); + + /* USB3.0 speed cannot get from portstatus, checkout port speed instead */ + else + { + uint8_t super_speed = usbh_get_port_speed(hub, port + 1); + if (super_speed > USB_SPEED_HIGH) { + /* assert that when using USB 3.0 ports, attached device must also be USB 3.0 speed */ + speed = super_speed; + } else { + speed = USB_SPEED_FULL; + } + } +#else + else { speed = USB_SPEED_FULL; } +#endif child = &hub->child[port]; /** release child sources first */ @@ -530,7 +610,9 @@ static void usbh_hub_events(struct usbh_hub *hub) child = &hub->child[port]; /** release child sources */ usbh_hubport_release(child); - USB_LOG_ERR("Failed to enable port %u\r\n", port + 1); + + /** some USB 3.0 ip may failed to enable USB 2.0 port for USB 3.0 device */ + USB_LOG_WRN("Failed to enable port %u\r\n", port + 1); continue; } diff --git a/common/usb_def.h b/common/usb_def.h index b48c9464..5bd9228d 100644 --- a/common/usb_def.h +++ b/common/usb_def.h @@ -11,6 +11,9 @@ #define USB_2_0 0x0200 /* Set USB version to 2.1 so that the host will request the BOS descriptor */ #define USB_2_1 0x0210 +#define USB_3_0 0x0300 +#define USB_3_1 0x0310 +#define USB_3_2 0x0320 /* Device speeds */ #define USB_SPEED_UNKNOWN 0 /* Transfer rate not yet set */ diff --git a/core/usbh_core.c b/core/usbh_core.c index 712429e2..46e27390 100644 --- a/core/usbh_core.c +++ b/core/usbh_core.c @@ -412,6 +412,7 @@ int usbh_enumerate(struct usbh_hubport *hport) { struct usb_interface_descriptor *intf_desc; struct usb_setup_packet *setup; + struct usb_device_descriptor *dev_desc; int dev_addr; uint16_t ep_mps; int ret; @@ -435,7 +436,16 @@ int usbh_enumerate(struct usbh_hubport *hport) parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_request_buffer, 8); /* Extract the correct max packetsize from the device descriptor */ - ep_mps = ((struct usb_device_descriptor *)ep0_request_buffer)->bMaxPacketSize0; + dev_desc = (struct usb_device_descriptor *)ep0_request_buffer; + if (dev_desc->bcdUSB >= USB_3_0) { + ep_mps = 1 << dev_desc->bMaxPacketSize0; + } else { + ep_mps = dev_desc->bMaxPacketSize0; + } + + USB_LOG_DBG("Device rev=%04x cls=%02x sub=%02x proto=%02x size=%d\r\n", + dev_desc->bcdUSB, dev_desc->bDeviceClass, dev_desc->bDeviceSubClass, + dev_desc->bDeviceProtocol, ep_mps); /* Reconfigure EP0 with the correct maximum packet size */ usbh_ep_pipe_reconfigure(hport->ep0, 0, ep_mps, 0); @@ -791,4 +801,4 @@ int lsusb(int argc, char **argv) } return 0; -} \ No newline at end of file +} diff --git a/core/usbh_core.h b/core/usbh_core.h index 9d033ab9..9b17aacb 100644 --- a/core/usbh_core.h +++ b/core/usbh_core.h @@ -149,6 +149,9 @@ struct usbh_hubport { uint8_t *raw_config_desc; struct usb_setup_packet *setup; struct usbh_hub *parent; +#ifdef CONFIG_USBHOST_XHCI + uint32_t protocol; /* port protocol, for xhci, some ports are USB2.0, others are USB3.0 */ +#endif }; struct usbh_hub { diff --git a/port/xhci/usb_hc_xhci.c b/port/xhci/usb_hc_xhci.c index 43c62f54..44b71ed7 100644 --- a/port/xhci/usb_hc_xhci.c +++ b/port/xhci/usb_hc_xhci.c @@ -62,6 +62,14 @@ __WEAK unsigned long usb_hc_get_register_base(void) return 0U; } +/** + * Get USB root hub port + * + * @v hport Hub port of USB device + * @ret port Root hub port + */ +extern struct usbh_hubport *usbh_root_hub_port(struct usbh_hubport *hport); + static struct xhci_host xhci_host; /* xhci hardware init */ diff --git a/port/xhci/xhci.c b/port/xhci/xhci.c index 21c62f01..7af03a37 100644 --- a/port/xhci/xhci.c +++ b/port/xhci/xhci.c @@ -29,6 +29,75 @@ #include "xhci_reg.h" #include "xhci.h" +extern struct usbh_hubport *usbh_get_roothub_port(unsigned int port); + +/** + * Get USB transaction translator + * + * @v hport Hub port of USB device + * @ret port Transaction translator port, or NULL + */ +struct usbh_hubport *usbh_transaction_translator(struct usbh_hubport *hport) +{ + struct usbh_hubport *parent; + + if (hport->parent->is_roothub) { + return NULL; + } + + /* Navigate up to root hub. If we find a low-speed or + * full-speed device with a higher-speed parent hub, then that + * device's port is the transaction translator. + */ + for (; (parent = hport->parent->parent); hport = parent) { + if ((hport->speed <= USB_SPEED_FULL) && + (parent->speed > USB_SPEED_FULL)) { + return hport; + } + } + + return NULL; +} + +/** + * Get USB route string + * + * @v hport Hub Port of USB device + * @ret route USB route string + */ +unsigned int usbh_route_string(struct usbh_hubport *hport) +{ + struct usbh_hubport *parent; + unsigned int route; + + /* Navigate up to root hub, constructing route string as we go */ + for (route = 0; (parent = hport->parent->parent); hport = parent) { + route <<= 4; + route |= ((hport->dev_addr > 0xf) ? + 0xf : + hport->dev_addr); + } + + return route; +} + +/** + * Get USB root hub port + * + * @v usb Hub port of USB device + * @ret port Root hub port + */ +struct usbh_hubport *usbh_root_hub_port(struct usbh_hubport *hport) +{ + struct usbh_hubport *parent; + + /* Navigate up to root hub */ + while (parent = hport->parent->parent) { + hport = parent; + } + + return hport; +} /** @file * @@ -485,7 +554,7 @@ static unsigned int xhci_port_protocol ( struct xhci_host *xhci, protocol = XHCI_SUPPORTED_REVISION_VER ( revision ); /* Describe port protocol */ -#if XHCI_DUMP +#if XHCI_DUMP { name.raw = CPU_TO_LE32 ( readl ( xhci->cap + supported + XHCI_SUPPORTED_NAME ) ); @@ -798,7 +867,7 @@ static void xhci_run ( struct xhci_host *xhci ) { * @v xhci xHCI device */ static void xhci_event_free ( struct xhci_host *xhci ) { - + /* Clear event ring registers */ writel ( 0, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) ); xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) ); @@ -1029,12 +1098,12 @@ int xhci_port_enable(struct xhci_host *xhci, uint32_t port) { /** * Convert USB Speed to PSI * - * @v speed USB speed + * @v speed USB speed * @ret psi USB speed in PSI */ static unsigned int xhci_speed_to_psi(int speed) { unsigned int psi = USB_SPEED_UNKNOWN; - + switch (speed) { case USB_SPEED_LOW: psi = XCHI_PSI_LOW; @@ -1056,12 +1125,12 @@ static unsigned int xhci_speed_to_psi(int speed) { /** * Convert USB PSI to Speed * - * @v psi USB speed in PSI - * @ret speed USB speed + * @v psi USB speed in PSI + * @ret speed USB speed */ static int xhci_psi_to_speed(int psi) { int speed = USB_SPEED_UNKNOWN; - + switch (psi) { case XCHI_PSI_LOW: speed = USB_SPEED_LOW; @@ -1221,7 +1290,7 @@ uint32_t xhci_root_speed ( struct xhci_host *xhci, uint8_t port ) { csc = ( portsc & XHCI_PORTSC_CSC ); psiv = XHCI_PORTSC_PSIV ( portsc ); - USB_LOG_DBG("XHCI %s port-%d ccs: %d, ped: %d, csc: %d, psiv: 0x%x\n", + USB_LOG_DBG("XHCI %s port-%d ccs: %d, ped: %d, csc: %d, psiv: 0x%x\n", xhci->name, port, !!ccs, !!ped, !!csc, psiv); /* Port speed is not valid unless port is connected */ @@ -1348,7 +1417,7 @@ static void xhci_abort ( struct xhci_host *xhci ) { /* Consume (and ignore) any final command status */ int cc = xhci_event_wait(xhci, xhci->cur_cmd_pipe, xhci->cmds); if (XHCI_CMPLT_SUCCESS != cc) { - USB_LOG_ERR("XHCI %s abort command failed, cc %d\n", xhci->name, cc); + USB_LOG_ERR("XHCI %s abort command failed, cc %d\n", xhci->name, cc); } /* Reset the command ring control register */ @@ -1364,7 +1433,7 @@ static void xhci_abort ( struct xhci_host *xhci ) { * @ trb Command TRB to be sent */ static int xhci_cmd_submit(struct xhci_host *xhci, struct xhci_endpoint *ep, union xhci_trb *trb) { - + int rc = 0; usb_osal_mutex_take(xhci->cmds->lock); /* handle command one by one */ @@ -1382,7 +1451,7 @@ static int xhci_cmd_submit(struct xhci_host *xhci, struct xhci_endpoint *ep, uni if (XHCI_CMPLT_SUCCESS != cc) { USB_LOG_ERR("XHCI %s cmd failed, cc %d\n", xhci->name, cc); xhci_abort(xhci); /* Abort command */ - rc = -ENOTSUP; + rc = -ENOTSUP; } usb_osal_mutex_give(xhci->cmds->lock); @@ -1528,7 +1597,7 @@ static int xhci_context ( struct xhci_host *xhci, struct xhci_slot *slot, err_command: usb_free ( input ); err_alloc: - return rc; + return rc; } /** @@ -1548,7 +1617,7 @@ static void xhci_address_device_input ( struct xhci_host *xhci, struct xhci_endpoint_context *ep_ctx; /* Sanity checks */ - USB_ASSERT ( endpoint->ctx == XHCI_CTX_EP0 ); + USB_ASSERT ( endpoint->ctx == XHCI_CTX_EP0 ); /* Populate control context, add slot context and ep context */ control_ctx = input; @@ -1585,7 +1654,7 @@ static void xhci_address_device_input ( struct xhci_host *xhci, * @v slot Device slot * @ret rc Return status code */ -static inline int xhci_address_device ( struct xhci_host *xhci, +static inline int xhci_address_device ( struct xhci_host *xhci, struct xhci_endpoint *ep, struct xhci_slot *slot ) { struct xhci_slot_context *slot_ctx; @@ -1595,7 +1664,7 @@ static inline int xhci_address_device ( struct xhci_host *xhci, if ( ( rc = xhci_context ( xhci, slot, slot->endpoint[XHCI_CTX_EP0], XHCI_TRB_ADDRESS_DEVICE, xhci_address_device_input ) ) != 0 ) - + USB_LOG_DBG("XHCI %s slot ctx 0x%x\n", xhci->name, slot->context); /* Get assigned address for check */ @@ -1604,7 +1673,7 @@ static inline int xhci_address_device ( struct xhci_host *xhci, USB_LOG_DBG("XHCI %s slot ctx 0x%x assigned address 0x%x\n", xhci->name, slot_ctx, slot_ctx->address ); - return rc; + return rc; } /** @@ -1701,12 +1770,12 @@ static int xhci_port_slot_type ( struct xhci_host *xhci, unsigned int port ) { * * @v xhci XHCI device * @v ep Endpoint - * @ret slot_id Return device slot id + * @ret slot_id Return device slot id * @ret rc Return status code */ int xhci_device_open ( struct xhci_host *xhci, struct xhci_endpoint *ep, int *slot_id ) { struct usbh_hubport *hport = ep->hport; - struct usbh_hubport *tt = usbh_transaction_translator(hport); + struct usbh_hubport *tt = usbh_transaction_translator(hport); struct xhci_slot *slot; struct xhci_slot *tt_slot; int type; @@ -1774,7 +1843,7 @@ err_alloc_context: xhci->slot[id] = NULL; usb_free ( slot ); err_alloc: - xhci_disable_slot ( xhci, ep, id ); + xhci_disable_slot ( xhci, ep, id ); err_enable_slot: err_type: return rc; @@ -1903,7 +1972,7 @@ static void xhci_configure_endpoint_input ( struct xhci_host *xhci, ep_ctx->burst = endpoint->burst; ep_ctx->mtu = CPU_TO_LE16 ( endpoint->mtu ); /* bit[31:16] max packet size */ ep_ctx->dequeue = CPU_TO_LE64 ( (uint64_t)( &(endpoint->reqs.ring[0]) ) | XHCI_EP_DCS ); - + /* TODO: endpoint attached on hub may need different setting here */ if (endpoint->ep_type == USB_ENDPOINT_TYPE_BULK) { ep_ctx->trb_len = CPU_TO_LE16 ( 256U ); /* bit[15:0] average trb length */ @@ -1933,7 +2002,7 @@ static inline int xhci_configure_endpoint ( struct xhci_host *xhci, XHCI_TRB_CONFIGURE_ENDPOINT, xhci_configure_endpoint_input ) ) != 0 ){ USB_LOG_ERR("XHCI %s slot %d ctx %d configure failed, error %d !!!\n", - xhci->name, slot->id, endpoint->ctx, rc ); + xhci->name, slot->id, endpoint->ctx, rc ); return rc; } @@ -1943,7 +2012,7 @@ static inline int xhci_configure_endpoint ( struct xhci_host *xhci, xhci_dump_slot_ctx(endpoint->slot->context); xhci_dump_ep_ctx(endpoint->context); USB_LOG_ERR("XHCI %s slot %d ctx %d configure failed !!!\n", - xhci->name, slot->id, endpoint->ctx ); + xhci->name, slot->id, endpoint->ctx ); return -1; } @@ -2035,7 +2104,7 @@ int xhci_ctrl_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, st ep->reqs.cs = 1; /* cycle state = 1 */ USB_LOG_DBG("XHCI %s slot %d endpoint 0x%x ep type %d xhci ep type 0x%x\n", - xhci->name, slot->id, ep->address, ep->ep_type, + xhci->name, slot->id, ep->address, ep->ep_type, (ep->ctx_type >> 3) ); USB_LOG_DBG("XHCI %s slot %d ctx %d ring [%08lx,%08lx)\n", @@ -2090,7 +2159,7 @@ int xhci_work_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, st ep->xhci = xhci; ep->slot = slot; ep->ctx = ctx; - + /* Calculate interval */ if ( ctx_type & XHCI_EP_TYPE_PERIODIC ) { ep->interval = ( fls ( ep->interval ) - 1 ); @@ -2102,7 +2171,7 @@ int xhci_work_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, st ep->reqs.cs = 1; /* cycle state = 1 */ USB_LOG_DBG("XHCI %s slot %d endpoint 0x%x ep type %d xhci ep type 0x%x\n", - xhci->name, slot->id, ep->address, ep->ep_type, + xhci->name, slot->id, ep->address, ep->ep_type, (ep->ctx_type >> 3) ); /* Configure endpoint */ @@ -2136,7 +2205,7 @@ void xhci_endpoint_close ( struct xhci_endpoint *ep ) { (void)xhci_deconfigure_endpoint ( xhci, slot, ep ); slot->endpoint[ctx] = NULL; - usb_free(ep); + usb_free(ep); } /*********************************************************************/ @@ -2150,9 +2219,9 @@ void xhci_endpoint_close ( struct xhci_endpoint *ep ) { * @v datalen Data length * @ret rc Return status code */ -void xhci_endpoint_message ( struct xhci_endpoint *ep, +void xhci_endpoint_message ( struct xhci_endpoint *ep, struct usb_setup_packet *packet, - void *data_buff, + void *data_buff, int datalen ) { struct xhci_host *xhci = ep->xhci; struct xhci_slot *slot = ep->slot; @@ -2219,8 +2288,8 @@ void xhci_endpoint_message ( struct xhci_endpoint *ep, * @v datalen Data length * @ret rc Return status code */ -void xhci_endpoint_stream ( struct xhci_endpoint *ep, - void *data_buff, +void xhci_endpoint_stream ( struct xhci_endpoint *ep, + void *data_buff, int datalen ) { struct xhci_host *xhci = ep->xhci; struct xhci_slot *slot = ep->slot; @@ -2254,7 +2323,7 @@ void xhci_endpoint_stream ( struct xhci_endpoint *ep, xhci_doorbell(xhci, slot->id, ep->ctx); err_enqueue: - return; + return; } /*********************************************************************/ @@ -2357,7 +2426,7 @@ static void xhci_port_status ( struct xhci_host *xhci, if (portsc & XHCI_PORTSC_CSC) { /* Report port status change */ usbh_roothub_thread_wakeup ( trb->port ); - } + } } /** @@ -2369,11 +2438,11 @@ static void xhci_port_status ( struct xhci_host *xhci, static void xhci_transfer ( struct xhci_host *xhci, struct xhci_trb_transfer *trb ) { struct xhci_slot *slot; - struct xhci_endpoint *endpoint; + struct xhci_endpoint *endpoint; union xhci_trb *trans_trb = (void *)(uintptr_t)(trb->transfer); struct xhci_ring *trans_ring = XHCI_RING(trans_trb); /* to align addr is ring base */ union xhci_trb *pending = &trans_ring->evt; /* preserve event trb pending to handle */ - uint32_t eidx = trans_trb - trans_ring->ring + 1; /* calculate current evt trb index */ + uint32_t eidx = trans_trb - trans_ring->ring + 1; /* calculate current evt trb index */ int rc; /* Identify slot */ @@ -2434,7 +2503,7 @@ static void xhci_transfer ( struct xhci_host *xhci, } } - return; + return; } /** @@ -2559,5 +2628,5 @@ struct xhci_endpoint *xhci_event_process(struct xhci_host *xhci) { xhci->run + XHCI_RUN_ERDP ( 0 ) ); } - return work_pipe; + return work_pipe; } \ No newline at end of file