diff --git a/port/xhci/usb_hc_xhci.c b/port/xhci/usb_hc_xhci.c deleted file mode 100644 index 3af541b0..00000000 --- a/port/xhci/usb_hc_xhci.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright : (C) 2022 Phytium Information Technology, Inc. - * All Rights Reserved. - * - * This program is OPEN SOURCE software: you can redistribute it and/or modify it - * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, - * either version 1.0 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the Phytium Public License for more details. - * - * - * FilePath: usb_hc_xhci.c - * Date: 2022-09-19 17:24:36 - * LastEditTime: 2022-09-19 17:24:36 - * Description:  This file is for xhci function implementation. - * - * Modify History: - * Ver   Who        Date         Changes - * ----- ------     --------    -------------------------------------- - * 1.0 zhugengyu 2022/9/19 init commit - * 1.1 zhugengyu 2022/10/9 add dumpers and fix command abort - * 2.0 zhugengyu 2023/3/29 support usb3.0 device attached at roothub - */ - -/***************************** Include Files *********************************/ -#include "usbh_hub.h" - -#include "xhci.h" - -/************************** Constant Definitions *****************************/ - -/************************** Variable Definitions *****************************/ - -/***************** Macros (Inline Functions) Definitions *********************/ - -/************************** Function Prototypes ******************************/ - -/*****************************************************************************/ -__WEAK void usb_hc_low_level_init(void) -{ -} - -__WEAK void *usb_hc_malloc(size_t size) -{ - return NULL; -} - -__WEAK void *usb_hc_malloc_align(size_t align, size_t size) -{ - return NULL; -} - -__WEAK void usb_hc_free() -{ -} - -/* one may get xhci register base address by PCIe bus emuration */ -__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 */ -int usb_hc_init() -{ - int rc = 0; - struct xhci_host *xhci = &(xhci_host); - - size_t flag = usb_osal_enter_critical_section(); /* no interrupt when init hc */ - - usb_hc_low_level_init(); /* set gic and memp */ - - memset(xhci, 0, sizeof(*xhci)); - xhci->id = CONFIG_USBHOST_XHCI_ID; - if (rc = xhci_probe(xhci, usb_hc_get_register_base()) != 0) { - goto err_open; - } - - if (rc = xhci_open(xhci) != 0 ) { - goto err_open; - } - - err_open: - usb_osal_leave_critical_section(flag); - return rc; -} - -int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf) -{ - uint8_t nports; - uint8_t port; - uint32_t portsc; - uint32_t status; - int ret = 0; - struct xhci_host *xhci = &xhci_host; - nports = CONFIG_USBHOST_MAX_RHPORTS; - - port = setup->wIndex; - - /* - bmRequestType bit[4:0], define whether the request is directed to the device (0000b), - specific interface (00001b), endpoint (00010b), or other element (00011b) - bRequest, identifies the request - wValue, pass the request-specific info to the device - */ - if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) /* request is directed to device */ - { - switch (setup->bRequest) - { - case HUB_REQUEST_CLEAR_FEATURE: /* disable the feature */ - switch (setup->wValue) - { - case HUB_FEATURE_HUB_C_LOCALPOWER: - USB_LOG_ERR("HUB_FEATURE_HUB_C_LOCALPOWER not implmented.\n"); - break; - case HUB_FEATURE_HUB_C_OVERCURRENT: - USB_LOG_ERR("HUB_FEATURE_HUB_C_OVERCURRENT not implmented.\n"); - break; - default: - return -EPIPE; - } - break; - case HUB_REQUEST_SET_FEATURE: /* set a value reported in the hub status */ - switch (setup->wValue) - { - case HUB_FEATURE_HUB_C_LOCALPOWER: - USB_LOG_ERR("HUB_FEATURE_HUB_C_LOCALPOWER not implmented.\n"); - break; - case HUB_FEATURE_HUB_C_OVERCURRENT: - USB_LOG_ERR("HUB_FEATURE_HUB_C_OVERCURRENT not implmented.\n"); - break; - default: - return -EPIPE; - } - break; - case HUB_REQUEST_GET_DESCRIPTOR: - USB_LOG_ERR("HUB_REQUEST_GET_DESCRIPTOR not implmented.\n"); - break; - case HUB_REQUEST_GET_STATUS: - USB_ASSERT(buf); - memset(buf, 0, 4); - break; - default: - break; - } - } - else if (setup->bmRequestType & USB_REQUEST_RECIPIENT_OTHER) - { - switch (setup->bRequest) - { - case HUB_REQUEST_CLEAR_FEATURE: - if (!port || port > nports) - { - return -EPIPE; - } - - portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) ); - switch (setup->wValue) - { - case HUB_PORT_FEATURE_ENABLE: - break; - case HUB_PORT_FEATURE_SUSPEND: - case HUB_PORT_FEATURE_C_SUSPEND: - break; - case HUB_PORT_FEATURE_POWER: - break; - case HUB_PORT_FEATURE_C_CONNECTION: - portsc |= XHCI_PORTSC_CSC; - break; - case HUB_PORT_FEATURE_C_ENABLE: - portsc |= XHCI_PORTSC_PEC; - break; - case HUB_PORT_FEATURE_C_OVER_CURREN: - break; - case HUB_PORT_FEATURE_C_RESET: - break; - default: - return -EPIPE; - } - - uint32_t pclear = portsc & XHCI_PORTSC_RW_MASK; - /* clear port status */ - writel(pclear, xhci->op + XHCI_OP_PORTSC ( port )); - - break; - case HUB_REQUEST_SET_FEATURE: - if (!port || port > nports) - { - return -EPIPE; - } - - switch (setup->wValue) - { - case HUB_PORT_FEATURE_SUSPEND: - break; - case HUB_PORT_FEATURE_POWER: - break; - case HUB_PORT_FEATURE_RESET: - ret = xhci_port_enable(xhci, port); - break; - default: - return -EPIPE; - } - break; - case HUB_REQUEST_GET_STATUS: - if (!port || port > nports) - { - return -EPIPE; - } - - portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) ); - status = 0; - - if (portsc & XHCI_PORTSC_CSC) - { - /* Port connection status changed */ - status |= (1 << HUB_PORT_FEATURE_C_CONNECTION); - - /* always clear all the status change bits */ - uint32_t temp = portsc & ( XHCI_PORTSC_PRESERVE | XHCI_PORTSC_CHANGE ); - writel ( temp, xhci->op + XHCI_OP_PORTSC ( port ) ); - } - - if (portsc & XHCI_PORTSC_PEC) - { - /* Port enabled status changed */ - status |= (1 << HUB_PORT_FEATURE_C_ENABLE); - } - - if (portsc & XHCI_PORTSC_OCC) - { - /* Port status changed due to over-current */ - status |= (1 << HUB_PORT_FEATURE_C_OVER_CURREN); - } - - if (portsc & XHCI_PORTSC_CCS) - { - /* Port connected */ - status |= (1 << HUB_PORT_FEATURE_CONNECTION); - } - - if (portsc & XHCI_PORTSC_PED) - { - /* Port enabled */ - status |= (1 << HUB_PORT_FEATURE_ENABLE); - - const unsigned int speed = xhci_root_speed(xhci, port); - USB_LOG_DBG("Port-%d speed = %d \r\n", port, speed); - if (speed == USB_SPEED_LOW) - { - status |= (1 << HUB_PORT_FEATURE_LOWSPEED); - } - else if (speed == USB_SPEED_HIGH) - { - status |= (1 << HUB_PORT_FEATURE_HIGHSPEED); - } - /* else is full-speed */ - } - - if (portsc & XHCI_PORTSC_OCA) - { - /* Over-current condition */ - status |= (1 << HUB_PORT_FEATURE_OVERCURRENT); - } - - if (portsc & XHCI_PORTSC_PR) - { - /* Reset is in progress */ - status |= (1 << HUB_PORT_FEATURE_RESET); - } - - if (portsc & XHCI_PORTSC_PP) - { - /* Port is not power off */ - status |= (1 << HUB_PORT_FEATURE_POWER); - } - memcpy(buf, &status, 4); - break; - default: - break; - } - } - - return 0; -} - -uint8_t usbh_get_port_speed(struct usbh_hub *hub, const uint8_t port) -{ - USB_ASSERT(hub); - struct xhci_host *xhci = &(xhci_host); - - if (hub->is_roothub) { - return xhci_root_speed(xhci, port); - } else { - struct usbh_hubport *roothub_port = usbh_root_hub_port(&(hub->child[port])); - /* TODO, hanlde TT for low-speed device on high-speed hub, but it doesn't matter, since - we haven't well handle hub yet */ - USB_ASSERT(roothub_port); - return xhci_root_speed(xhci, roothub_port->port); - } -} - -int usbh_ep_pipe_reconfigure(usbh_pipe_t pipe, uint8_t dev_addr, uint8_t mtu, uint8_t speed) -{ - struct xhci_endpoint *ppipe = (struct xhci_endpoint *)pipe; - size_t old_mtu = ppipe->mtu; - int rc = 0; - - if (mtu != old_mtu) { - ppipe->mtu = mtu; - rc = xhci_endpoint_mtu(ppipe); - } - - return rc; -} - -int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg) -{ - int rc = 0; - int slot_id = 0; - struct xhci_host *xhci = &xhci_host; - struct usbh_hubport *hport = ep_cfg->hport; - struct xhci_endpoint *ppipe = usb_align(XHCI_RING_SIZE, sizeof(struct xhci_endpoint)); - struct xhci_slot *slot; - - if (NULL == ppipe) { - return -ENOMEM; - } - - memset(ppipe, 0, sizeof(struct xhci_endpoint)); - - ppipe->waitsem = usb_osal_sem_create(0); - ppipe->waiter = false; - ppipe->urb = NULL; - ppipe->hport = hport; - - ppipe->address = ep_cfg->ep_addr; - ppipe->mtu = ep_cfg->ep_mps; - ppipe->interval = ep_cfg->ep_interval; - ppipe->ep_type = ep_cfg->ep_type; - ppipe->burst = 0U; - - if (ppipe->address == 0) { /* if try to allocate ctrl ep, open device first */ - USB_LOG_DBG("allocate device for port-%d \r\n", hport->port); - rc = xhci_device_open(xhci, ppipe, &slot_id); - if (rc) { - goto failed; - } - - slot = xhci->slot[slot_id]; - USB_ASSERT(slot); - rc = xhci_ctrl_endpoint_open(xhci, slot, ppipe); - if (rc) { - goto failed; - } - - rc = xhci_device_address(xhci, slot, ppipe); - if (rc) { - goto failed; - } - } else { - slot_id = hport->dev_addr; - slot = xhci->slot[slot_id]; - - rc = xhci_work_endpoint_open(xhci, slot, ppipe); - if (rc) { - goto failed; - } - } - - *pipe = (usbh_pipe_t)ppipe; - return rc; -failed: - usb_free(ppipe); - *pipe = NULL; - return rc; -} - -int usbh_get_xhci_devaddr(usbh_pipe_t *pipe) -{ - struct xhci_endpoint *ppipe = (struct xhci_endpoint *)pipe; - USB_ASSERT(ppipe && (ppipe->slot)); - return ppipe->slot->id; -} - -int usbh_pipe_free(usbh_pipe_t pipe) -{ - int ret = 0; - struct xhci_endpoint *ppipe = (struct xhci_endpoint *)pipe; - - if (!ppipe) { - return -EINVAL; - } - - struct usbh_urb *urb = ppipe->urb; - if (urb) { - usbh_kill_urb(urb); - } - - size_t flags = usb_osal_enter_critical_section(); - xhci_endpoint_close(ppipe); - usb_osal_leave_critical_section(flags); - return 0; -} - -int usbh_submit_urb(struct usbh_urb *urb) -{ - int ret = 0; - if (!urb || !urb->pipe) { - return -EINVAL; - } - - struct xhci_endpoint *ppipe = (struct xhci_endpoint *)urb->pipe; - struct xhci_host *xhci = ppipe->xhci; - struct usb_setup_packet *setup = urb->setup; - size_t flags = usb_osal_enter_critical_section(); - - urb->errorcode = -EBUSY; - urb->actual_length = 0U; - - ppipe->urb = urb; - ppipe->timeout = urb->timeout; - if (ppipe->timeout > 0) { - ppipe->waiter = true; - } else { - ppipe->waiter = false; - } - - usb_osal_leave_critical_section(flags); - switch (ppipe->ep_type) { - case USB_ENDPOINT_TYPE_CONTROL: - USB_ASSERT(setup); - if (setup->bRequest == USB_REQUEST_SET_ADDRESS) { - /* Set address command sent during xhci_alloc_pipe. */ - goto skip_req; - } - - USB_LOG_DBG("%s request-%d.\n", __func__, setup->bRequest); - xhci_endpoint_message(ppipe, setup, urb->transfer_buffer, urb->transfer_buffer_length); - break; - case USB_ENDPOINT_TYPE_INTERRUPT: - case USB_ENDPOINT_TYPE_BULK: - xhci_endpoint_stream(ppipe, urb->transfer_buffer, urb->transfer_buffer_length); - break; - default: - USB_ASSERT(0U); - break; - } - - /* wait all ring handled by xHc */ - int cc = xhci_event_wait(xhci, ppipe, &ppipe->reqs); - if ((cc != XHCI_CMPLT_SUCCESS) && - !((cc == XHCI_CMPLT_TIMEOUT) && (ppipe->ep_type == USB_ENDPOINT_TYPE_INTERRUPT))) - { - /* ignore transfer timeout for interrupt type */ - USB_LOG_ERR("%s: xfer failed (cc %d).\n", __func__, cc); - ret = -1; - urb->errorcode = cc; - goto errout_timeout; - } - -skip_req: -errout_timeout: - /* Timeout will run here */ - usbh_kill_urb(urb); - return ret; -} - -int usbh_kill_urb(struct usbh_urb *urb) -{ - return 0; -} - -void USBH_IRQHandler(void *param) -{ - struct xhci_host *xhci = &xhci_host; - struct xhci_endpoint *work_pipe = NULL; - USB_ASSERT(xhci); - uint32_t usbsts; - uint32_t runtime; - - /* clear interrupt status */ - usbsts = readl ( xhci->op + XHCI_OP_USBSTS ); - usbsts |= XHCI_USBSTS_EINT; - writel(usbsts, xhci->op + XHCI_OP_USBSTS); - - /* ack interrupt */ - runtime = readl(xhci->run + XHCI_RUN_IR_IMAN ( 0 )); - runtime |= XHCI_RUN_IR_IMAN_IP; - writel (runtime, xhci->run + XHCI_RUN_IR_IMAN ( 0 )); - - work_pipe = xhci_event_process(xhci); -} \ No newline at end of file diff --git a/port/xhci/usb_hc_xhci.h b/port/xhci/usb_hc_xhci.h deleted file mode 100644 index 151b5bdc..00000000 --- a/port/xhci/usb_hc_xhci.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright : (C) 2022 Phytium Information Technology, Inc. - * All Rights Reserved. - * - * This program is OPEN SOURCE software: you can redistribute it and/or modify it - * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, - * either version 1.0 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the Phytium Public License for more details. - * - * - * FilePath: usb_hc_xhci.h - * Date: 2022-07-19 09:26:25 - * LastEditTime: 2022-07-19 09:26:25 - * Description:  This file is for xhci data structure definition. - * - * Modify History: - * Ver   Who        Date         Changes - * ----- ------     --------    -------------------------------------- - * 1.0 zhugengyu 2022/9/19 init commit - * 2.0 zhugengyu 2023/3/29 support usb3.0 device attached at roothub - */ - -#ifndef USB_HC_XHCI_H -#define USB_HC_XHCI_H - -/***************************** Include Files *********************************/ -#include "usbh_core.h" - -/************************** Constant Definitions *****************************/ - -/************************** Variable Definitions *****************************/ - -/***************** Macros (Inline Functions) Definitions *********************/ - -/************************** Function Prototypes ******************************/ diff --git a/port/xhci/xhci.c b/port/xhci/xhci.c deleted file mode 100644 index 0acf2bd4..00000000 --- a/port/xhci/xhci.c +++ /dev/null @@ -1,2667 +0,0 @@ -/* - * Copyright : (C) 2022 Phytium Information Technology, Inc. - * All Rights Reserved. - * - * This program is OPEN SOURCE software: you can redistribute it and/or modify it - * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, - * either version 1.0 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the Phytium Public License for more details. - * - * - * FilePath: xhci.c - * Date: 2022-07-19 09:26:25 - * LastEditTime: 2022-07-19 09:26:25 - * Description:  This file is for xhci functions implmentation. - * - * Modify History: - * Ver   Who        Date         Changes - * ----- ------     --------    -------------------------------------- - * 1.0 zhugengyu 2022/9/19 init commit - * 2.0 zhugengyu 2023/3/29 support usb3.0 device attached at roothub - */ - -#include - -#include "usbh_core.h" -#include "usbh_hub.h" - -#include "xhci_reg.h" -#include "xhci.h" - -extern struct usbh_hubport *usbh_get_roothub_port(unsigned int port); - -#ifdef __aarch64__ -/* find last 64bit set, binary search */ -int xhci_fls(unsigned long v) -{ - int n = 64; - - if (!v) return -1; - if (!(v & 0xFFFFFFFF00000000)) { v <<= 32; n -= 32; } - if (!(v & 0xFFFF000000000000)) { v <<= 16; n -= 16; } - if (!(v & 0xFF00000000000000)) { v <<= 8; n -= 8; } - if (!(v & 0xF000000000000000)) { v <<= 4; n -= 4; } - if (!(v & 0xC000000000000000)) { v <<= 2; n -= 2; } - if (!(v & 0x8000000000000000)) { v <<= 1; n -= 1; } - - return n - 1; -} -#else -/* find first bit set, binary search */ -int xhci_fls(unsigned int v) -{ - int n = 32; - - if (!v) return -1; - if (!(v & 0xFFFF0000)) { v <<= 16; n -= 16; } - if (!(v & 0xFF000000)) { v <<= 8; n -= 8; } - if (!(v & 0xF0000000)) { v <<= 4; n -= 4; } - if (!(v & 0xC0000000)) { v <<= 2; n -= 2; } - if (!(v & 0x80000000)) { v <<= 1; n -= 1; } - - return n - 1; -} -#endif - -/** - * 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 - * - * USB eXtensible Host Controller Interface (xHCI) driver - * - */ - -#define XHCI_DUMP 1 - -/** Define a XHCI speed in PSI - * - * @v mantissa Mantissa - * @v exponent Exponent (in engineering terms: 1=k, 2=M, 3=G) - * @ret speed USB speed - */ -#define XCHI_PSI( mantissa, exponent ) ( (exponent << 16) | (mantissa) ) - -/** USB device speeds */ -enum { - /** Not connected */ - XCHI_PSI_NONE = 0, - /** Low speed (1.5Mbps) */ - XCHI_PSI_LOW = XCHI_PSI ( 1500, 1 ), - /** Full speed (12Mbps) */ - XCHI_PSI_FULL = XCHI_PSI ( 12, 2 ), - /** High speed (480Mbps) */ - XCHI_PSI_HIGH = XCHI_PSI ( 480, 2 ), - /** Super speed (5Gbps) */ - XCHI_PSI_SUPER = XCHI_PSI ( 5, 3 ), -}; - - -/** - * Calculate buffer alignment - * - * @v len Length - * @ret align Buffer alignment - * - * Determine alignment required for a buffer which must be aligned to - * at least XHCI_MIN_ALIGN and which must not cross a page boundary. - */ -static inline size_t xhci_align ( size_t len ) { - size_t align; - - /* Align to own length (rounded up to a power of two) */ - align = ( 1 << xhci_fls ( len - 1 ) ); - - /* Round up to XHCI_MIN_ALIGN if needed */ - if ( align < XHCI_MIN_ALIGN ) - align = XHCI_MIN_ALIGN; - - return align; -} - -/** - * Write potentially 64-bit register - * - * @v xhci xHCI device - * @v value Value - * @v reg Register address - * @ret rc Return status code - */ -static inline int xhci_writeq ( struct xhci_host *xhci, uintptr_t value, void *reg ) { - - /* If this is a 32-bit build, then this can never fail - * (allowing the compiler to optimise out the error path). - */ - if ( sizeof ( value ) <= sizeof ( uint32_t ) ) { - writel ( value, reg ); - writel ( 0, ( reg + sizeof ( uint32_t ) ) ); - return 0; - } - - /* If the device does not support 64-bit addresses and this - * address is outside the 32-bit address space, then fail. - */ - if ( ( value & ~0xffffffffULL ) && ! xhci->addr64 ) { - USB_LOG_DBG("XHCI %s cannot access address %lx\n", - xhci->name, value ); - return -ENOTSUP; - } - - /* If this is a 64-bit build, then writeq() is available */ - writeq ( value, reg ); - return 0; -} - -/** - * Initialise device - * - * @v xhci xHCI device - * @v regs MMIO registers - */ -static void xhci_init ( struct xhci_host *xhci, void *regs ) { - uint32_t hcsparams1; - uint32_t hcsparams2; - uint32_t hccparams1; - uint32_t pagesize; - size_t caplength; - size_t rtsoff; - size_t dboff; - - /* Locate capability, operational, runtime, and doorbell registers */ - xhci->cap = regs; - caplength = readb ( xhci->cap + XHCI_CAP_CAPLENGTH ); - rtsoff = readl ( xhci->cap + XHCI_CAP_RTSOFF ); - dboff = readl ( xhci->cap + XHCI_CAP_DBOFF ); - xhci->op = ( xhci->cap + caplength ); - xhci->run = ( xhci->cap + rtsoff ); - xhci->db = ( xhci->cap + dboff ); - - /* avoid access XHCI_REG_CAP_HCIVERSION = 0x2, unaligned memory */ - xhci->version = ((readl ( xhci->cap + XHCI_CAP_CAPLENGTH ) >> 16) & 0xffff); - - USB_LOG_DBG("XHCI %s version %x cap %08lx op %08lx run %08lx db %08lx\n", - xhci->name, xhci->version, ( xhci->cap ), - ( xhci->op ), ( xhci->run ), - ( xhci->db ) ); - - if (xhci->version < 0x96 || xhci->version > 0x120) { - USB_LOG_WRN("XHCI %s not support.\n", xhci->name); - } - - /* Read structural parameters 1 */ - hcsparams1 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS1 ); - xhci->slots = XHCI_HCSPARAMS1_SLOTS ( hcsparams1 ); - xhci->intrs = XHCI_HCSPARAMS1_INTRS ( hcsparams1 ); - xhci->ports = XHCI_HCSPARAMS1_PORTS ( hcsparams1 ); - USB_LOG_DBG("XHCI %s has %d slots %d intrs %d ports\n", - xhci->name, xhci->slots, xhci->intrs, xhci->ports ); - - /* Read structural parameters 2 */ - hcsparams2 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS2 ); - xhci->scratch.count = XHCI_HCSPARAMS2_SCRATCHPADS ( hcsparams2 ); - USB_LOG_DBG("XHCI %s needs %d scratchpads\n", - xhci->name, xhci->scratch.count ); - - /* Read capability parameters 1 */ - hccparams1 = readl ( xhci->cap + XHCI_CAP_HCCPARAMS1 ); - xhci->addr64 = XHCI_HCCPARAMS1_ADDR64 ( hccparams1 ); - xhci->csz_shift = XHCI_HCCPARAMS1_CSZ_SHIFT ( hccparams1 ); - xhci->xecp = (XHCI_HCCPARAMS1_XECP ( hccparams1 )); - USB_LOG_DBG("XHCI %s context %d bit\n", - xhci->name, (xhci->addr64 ? 64 : 32) ); - - /* Read page size */ - pagesize = readl ( xhci->op + XHCI_OP_PAGESIZE ); - xhci->pagesize = XHCI_PAGESIZE ( pagesize ); - USB_ASSERT ( xhci->pagesize != 0 ); - USB_ASSERT ( ( ( xhci->pagesize ) & ( xhci->pagesize - 1 ) ) == 0 ); - USB_LOG_DBG("XHCI %s page size %zd bytes\n", - xhci->name, xhci->pagesize ); -} - -/** - * Find extended capability - * - * @v xhci xHCI device - * @v id Capability ID - * @v offset Offset to previous extended capability instance, or zero - * @ret offset Offset to extended capability, or zero if not found - */ -static unsigned int xhci_extended_capability ( struct xhci_host *xhci, - unsigned int id, - unsigned int offset ) { - uint32_t xecp; - unsigned int next; - - /* Locate the extended capability */ - while ( 1 ) { - - /* Locate first or next capability as applicable */ - if ( offset ) { - xecp = readl ( xhci->cap + offset ); - next = XHCI_XECP_NEXT ( xecp ); - } else { - next = xhci->xecp; - } - if ( ! next ) - return 0; - offset += next; - - /* Check if this is the requested capability */ - xecp = readl ( xhci->cap + offset ); - if ( XHCI_XECP_ID ( xecp ) == id ) - return offset; - } -} - -/** - * Initialise USB legacy support - * - * @v xhci xHCI device - */ -static void xhci_legacy_init ( struct xhci_host *xhci ) { - unsigned int legacy; - uint8_t bios; - - /* Locate USB legacy support capability (if present) */ - legacy = xhci_extended_capability ( xhci, XHCI_XECP_ID_LEGACY, 0 ); - if ( ! legacy ) { - /* Not an error; capability may not be present */ - USB_LOG_DBG("XHCI %s has no USB legacy support capability\n", - xhci->name ); - return; - } - - /* Check if legacy USB support is enabled */ - USB_LOG_DBG("XHCI %s bios offset 0x%x\n", xhci->name, (xhci->cap + legacy + XHCI_USBLEGSUP_BIOS)); - /* bios = readb ( xhci->cap + legacy + XHCI_USBLEGSUP_BIOS ); cannot access offset 0x2, work around */ - bios = readl ( xhci->cap + legacy ); - bios = (bios >> 16) & 0xffff; - if ( ! ( bios & XHCI_USBLEGSUP_BIOS_OWNED ) ) { - /* Not an error; already owned by OS */ - USB_LOG_DBG("XHCI %s USB legacy support already disabled\n", - xhci->name ); - return; - } - - /* Record presence of USB legacy support capability */ - xhci->legacy = legacy; -} - -/** - * Claim ownership from BIOS - * - * @v xhci xHCI device - */ -static void xhci_legacy_claim ( struct xhci_host *xhci ) { - uint32_t ctlsts; - uint8_t bios; - unsigned int i; - - /* Do nothing unless legacy support capability is present */ - if ( ! xhci->legacy ) - return; - - /* Claim ownership */ - writeb ( XHCI_USBLEGSUP_OS_OWNED, - xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS ); - - /* Wait for BIOS to release ownership */ - for ( i = 0 ; i < XHCI_USBLEGSUP_MAX_WAIT_MS ; i++ ) { - - /* Check if BIOS has released ownership */ - bios = readb ( xhci->cap + xhci->legacy + XHCI_USBLEGSUP_BIOS ); - if ( ! ( bios & XHCI_USBLEGSUP_BIOS_OWNED ) ) { - USB_LOG_DBG("XHCI %s claimed ownership from BIOS\n", - xhci->name ); - ctlsts = readl ( xhci->cap + xhci->legacy + - XHCI_USBLEGSUP_CTLSTS ); - if ( ctlsts ) { - USB_LOG_DBG("XHCI %s warning: BIOS retained " - "SMIs: %08x\n", xhci->name, ctlsts ); - } - return; - } - - /* Delay */ - usb_osal_msleep ( 1 ); - } - - /* BIOS did not release ownership. Claim it forcibly by - * disabling all SMIs. - */ - USB_LOG_DBG("XHCI %s could not claim ownership from BIOS: forcibly " - "disabling SMIs\n", xhci->name ); - writel ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_CTLSTS ); -} - -/** Prevent the release of ownership back to BIOS */ -static int xhci_legacy_prevent_release; - -/** - * Release ownership back to BIOS - * - * @v xhci xHCI device - */ -static void xhci_legacy_release ( struct xhci_host *xhci ) { - - /* Do nothing unless legacy support capability is present */ - if ( ! xhci->legacy ) - return; - - /* Do nothing if releasing ownership is prevented */ - if ( xhci_legacy_prevent_release ) { - USB_LOG_DBG("XHCI %s not releasing ownership to BIOS\n", - xhci->name ); - return; - } - - /* Release ownership */ - writeb ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS ); - USB_LOG_DBG("XHCI %s released ownership to BIOS\n", xhci->name ); -} - -/** - * Stop xHCI device - * - * @v xhci xHCI device - * @ret rc Return status code - */ -static int xhci_stop ( struct xhci_host *xhci ) { - uint32_t usbcmd; - uint32_t usbsts; - unsigned int i; - - /* Clear run/stop bit */ - usbcmd = readl ( xhci->op + XHCI_OP_USBCMD ); - usbcmd &= ~XHCI_USBCMD_RUN; - writel ( usbcmd, xhci->op + XHCI_OP_USBCMD ); - - /* Wait for device to stop */ - for ( i = 0 ; i < XHCI_STOP_MAX_WAIT_MS ; i++ ) { - - /* Check if device is stopped */ - usbsts = readl ( xhci->op + XHCI_OP_USBSTS ); - if ( usbsts & XHCI_USBSTS_HCH ) - return 0; - - /* Delay */ - usb_osal_msleep ( 1 ); - } - - USB_LOG_DBG("XHCI %s timed out waiting for stop\n", xhci->name ); - return -ETIMEDOUT; -} - -/** - * Reset xHCI device - * - * @v xhci xHCI device - * @ret rc Return status code - */ -static int xhci_reset ( struct xhci_host *xhci ) { - uint32_t usbcmd; - unsigned int i; - int rc; - - /* The xHCI specification states that resetting a running - * device may result in undefined behaviour, so try stopping - * it first. - */ - if ( ( rc = xhci_stop ( xhci ) ) != 0 ) { - /* Ignore errors and attempt to reset the device anyway */ - } - - /* Reset device */ - writel ( XHCI_USBCMD_HCRST, xhci->op + XHCI_OP_USBCMD ); - - /* Wait for reset to complete */ - for ( i = 0 ; i < XHCI_RESET_MAX_WAIT_MS ; i++ ) { - - /* Check if reset is complete */ - usbcmd = readl ( xhci->op + XHCI_OP_USBCMD ); - if ( ! ( usbcmd & XHCI_USBCMD_HCRST ) ) - return 0; - - /* Delay */ - usb_osal_msleep ( 1 ); - } - - USB_LOG_DBG("XHCI %s timed out waiting for reset\n", xhci->name ); - return -ETIMEDOUT; -} - - -/** - * Find supported protocol extended capability for a port - * - * @v xhci xHCI device - * @v port Port number - * @ret supported Offset to extended capability, or zero if not found - */ -static unsigned int xhci_supported_protocol ( struct xhci_host *xhci, - unsigned int port ) { - unsigned int supported = 0; - unsigned int offset; - unsigned int count; - uint32_t ports; - - /* Iterate over all supported protocol structures */ - while ( ( supported = xhci_extended_capability ( xhci, - XHCI_XECP_ID_SUPPORTED, - supported ) ) ) { - - /* Determine port range */ - ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS ); - offset = XHCI_SUPPORTED_PORTS_OFFSET ( ports ); - count = XHCI_SUPPORTED_PORTS_COUNT ( ports ); - - /* Check if port lies within this range */ - if ( ( port - offset ) < count ) - return supported; - } - - USB_LOG_DBG("XHCI %s Port-%d has no supported protocol\n", - xhci->name, port ); - return 0; -} - -/** - * Transcribe port speed (for debugging) - * - * @v psi Protocol speed ID - * @ret speed Transcribed speed - */ -static inline const char * xhci_speed_name ( uint32_t psi ) { - static const char *exponents[4] = { "", "k", "M", "G" }; - static char buf[ 10 /* "xxxxxXbps" + NUL */ ]; - unsigned int mantissa; - unsigned int exponent; - - /* Extract mantissa and exponent */ - mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi ); - exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi ); - - /* Transcribe speed */ - snprintf ( buf, sizeof ( buf ), "%d%sbps", - mantissa, exponents[exponent] ); - return buf; -} - -/** - * Find port protocol - * - * @v xhci xHCI device - * @v port Port number - * @ret protocol USB protocol, or zero if not found - */ -static unsigned int xhci_port_protocol ( struct xhci_host *xhci, - unsigned int port ) { - unsigned int supported = xhci_supported_protocol ( xhci, port ); - union { - uint32_t raw; - char text[5]; - } name; - unsigned int protocol; - unsigned int type; - unsigned int psic; - unsigned int psiv; - unsigned int i; - uint32_t revision; - uint32_t ports; - uint32_t slot; - uint32_t psi; - - /* Fail if there is no supported protocol */ - if ( ! supported ) - return 0; - - /* Determine protocol version */ - revision = readl ( xhci->cap + supported + XHCI_SUPPORTED_REVISION ); - protocol = XHCI_SUPPORTED_REVISION_VER ( revision ); - - /* Describe port protocol */ -#if XHCI_DUMP - { - name.raw = CPU_TO_LE32 ( readl ( xhci->cap + supported + - XHCI_SUPPORTED_NAME ) ); - name.text[4] = '\0'; - slot = readl ( xhci->cap + supported + XHCI_SUPPORTED_SLOT ); - type = XHCI_SUPPORTED_SLOT_TYPE ( slot ); - USB_LOG_DBG("XHCI %s-%d %sv%04x type %d \r\n", - xhci->name, port, name.text, protocol, type ); - ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS ); - psic = XHCI_SUPPORTED_PORTS_PSIC ( ports ); - if ( psic ) { - USB_LOG_DBG(" speeds \r\n" ); - for ( i = 0 ; i < psic ; i++ ) { - psi = readl ( xhci->cap + supported + - XHCI_SUPPORTED_PSI ( i ) ); - psiv = XHCI_SUPPORTED_PSI_VALUE ( psi ); - USB_LOG_DBG(" %d:%s \r\n", psiv, xhci_speed_name ( psi ) ); - } - } - } -#endif - - return protocol; -} - -/** - * Probe XCHI device - * - * @v xhci XCHI device - * @v baseaddr XHCI device register base address - * @ret rc Return status code - */ -int xhci_probe ( struct xhci_host *xhci, unsigned long baseaddr ) { - USB_ASSERT(xhci); - int error = 0; - struct usbh_hubport *port; - unsigned int i; - - xhci->base = (void *)baseaddr; - xhci->name[0] = '0' + xhci->id; /* Assert there are less than 10 xhci host */ - xhci->name[1] = '\0'; - - /* Initialise xHCI device */ - xhci_init ( xhci, xhci->base ); - - /* Initialise USB legacy support and claim ownership */ - xhci_legacy_init ( xhci ); - xhci_legacy_claim ( xhci ); - - /* Reset device */ - if ( ( error = xhci_reset ( xhci ) ) != 0 ) - goto err_reset; - - /* Set port protocols */ - for ( i = 1 ; i <= xhci->ports ; i++ ) { - port = usbh_get_roothub_port ( i ); - port->protocol = xhci_port_protocol ( xhci, i ); - } - - return error; - -err_reset: - xhci_legacy_release ( xhci ); - return -1; -} - -/*********************************************************************/ - -/** - * Allocate device context base address array - * - * @v xhci xHCI device - * @ret rc Return status code - */ -static int xhci_dcbaa_alloc ( struct xhci_host *xhci ) { - size_t len; - uintptr_t dcbaap; - int rc; - - /* Allocate and initialise structure. Must be at least - * 64-byte aligned and must not cross a page boundary, so - * align on its own size (rounded up to a power of two and - * with a minimum of 64 bytes). - */ - len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) ); - xhci->dcbaa.context = usb_align(xhci_align ( len ), len); - if ( ! xhci->dcbaa.context ) { - USB_LOG_ERR("XHCI %s could not allocate DCBAA\n", xhci->name ); - rc = -ENOMEM; - goto err_alloc; - } - memset ( xhci->dcbaa.context, 0, len ); - - /* Program DCBAA pointer */ - dcbaap = (uintptr_t)( xhci->dcbaa.context ); - if ( ( rc = xhci_writeq ( xhci, dcbaap, - xhci->op + XHCI_OP_DCBAAP ) ) != 0 ) - goto err_writeq; - - USB_LOG_DBG("XHCI %s DCBAA at [%08lx,%08lx)\n", xhci->name, - ( xhci->dcbaa.context ), - ( ( xhci->dcbaa.context ) + len ) ); - return 0; - - err_writeq: - usb_free ( xhci->dcbaa.context ); - err_alloc: - return rc; -} - - -/** - * Allocate scratchpad buffers - * - * @v xhci xHCI device - * @ret rc Return status code - */ -static int xhci_scratchpad_alloc ( struct xhci_host *xhci ) { - struct xhci_scratchpad *scratch = &xhci->scratch; - size_t buffer_len; - size_t array_len; - uintptr_t addr; - unsigned int i; - int rc; - - /* Do nothing if no scratchpad buffers are used */ - if ( ! scratch->count ) { - USB_LOG_INFO("XHCI %s no need to allocate scratchpad buffers\n", - xhci->name ); - return 0; - } - - /* Allocate scratchpad buffers */ - buffer_len = ( scratch->count * xhci->pagesize ); - scratch->buffer = (uintptr_t)usb_align ( xhci->pagesize, buffer_len ); - if ( ! scratch->buffer ) { - USB_LOG_ERR("XHCI %s could not allocate scratchpad buffers\n", - xhci->name ); - rc = -ENOMEM; - goto err_alloc; - } - memset ( (void *)scratch->buffer, 0, buffer_len ); - - /* Allocate scratchpad array */ - array_len = ( scratch->count * sizeof ( scratch->array[0] ) ); - scratch->array = usb_align(xhci_align ( array_len ), array_len); - if ( ! scratch->array ) { - USB_LOG_ERR("XHCI %s could not allocate scratchpad buffer " - "array\n", xhci->name ); - rc = -ENOMEM; - goto err_alloc_array; - } - - /* Populate scratchpad array */ - addr = ( scratch->buffer + 0 ); - for ( i = 0 ; i < scratch->count ; i++ ) { - scratch->array[i] = CPU_TO_LE64 ( addr ); - addr += xhci->pagesize; - } - - /* Set scratchpad array pointer */ - USB_ASSERT ( xhci->dcbaa.context != NULL ); - xhci->dcbaa.context[0] = CPU_TO_LE64 ( ( scratch->array ) ); - - USB_LOG_DBG("XHCI %s scratchpad [%08lx,%08lx) array [%08lx,%08lx)\n", - xhci->name, ( scratch->buffer, 0 ), - ( scratch->buffer, buffer_len ), - ( scratch->array ), - ( ( scratch->array ) + array_len ) ); - return 0; - - usb_free ( scratch->array ); - err_alloc_array: - usb_free ( scratch->buffer ); - err_alloc: - return rc; -} - -/** - * Allocate command ring - * - * @v xhci xHCI device - * @ret rc Return status code - */ -static int xhci_command_alloc ( struct xhci_host *xhci ) { - uintptr_t crp; - int rc; - - /* Allocate TRB ring */ - xhci->cmds = usb_align(XHCI_RING_SIZE, sizeof(*xhci->cmds)); /* command ring */ - if (! xhci->cmds) - goto err_ring_alloc; - - memset(xhci->cmds, 0U, sizeof(*xhci->cmds)); - - xhci->cmds->lock = usb_osal_mutex_create(); - USB_ASSERT(xhci->cmds->lock); - - xhci->cmds->cs = 1; /* cycle state = 1 */ - - /* Program command ring control register */ - crp = (uintptr_t)( xhci->cmds ); - if ( ( rc = xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ), - xhci->op + XHCI_OP_CRCR ) ) != 0 ) - goto err_writeq; - - USB_LOG_DBG("XHCI %s CRCR at [%08lx,%08lx)\n", xhci->name, - ( xhci->cmds->ring ), - ( ( xhci->cmds->ring ) + sizeof(xhci->cmds->ring) ) ); - return 0; - - err_writeq: - usb_free(xhci->cmds);; - err_ring_alloc: - return rc; -} - -/** - * Allocate event ring - * - * @v xhci xHCI device - * @ret rc Return status code - */ -static int xhci_event_alloc ( struct xhci_host *xhci ) { - unsigned int count; - size_t len; - int rc; - - /* Allocate event ring */ - xhci->evts = usb_align(XHCI_RING_SIZE, sizeof(*xhci->evts)); /* event ring */ - if ( ! xhci->evts ) { - rc = -ENOMEM; - goto err_alloc_trb; - } - - memset(xhci->evts, 0U, sizeof(*xhci->evts)); - - /* Allocate event ring segment table */ - xhci->eseg = usb_align(XHCI_ALIGMENT, sizeof(*xhci->eseg)); /* event segment */ - if ( ! xhci->eseg ) { - rc = -ENOMEM; - goto err_alloc_segment; - } - memset(xhci->eseg, 0U, sizeof(*xhci->eseg)); - xhci->eseg->base = CPU_TO_LE64 ( ( xhci->evts ) ); - xhci->eseg->count = XHCI_RING_ITEMS; /* items of event ring TRB */ - - /* Program event ring registers */ - writel ( 1, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) ); /* bit[15:0] event ring segment table size */ - if ( ( rc = xhci_writeq ( xhci, (uintptr_t)( xhci->evts ), - xhci->run + XHCI_RUN_ERDP ( 0 ) ) ) != 0 ) /* bit[63:4] event ring dequeue pointer */ - goto err_writeq_erdp; - if ( ( rc = xhci_writeq ( xhci, (uintptr_t)( xhci->eseg ), - xhci->run + XHCI_RUN_ERSTBA ( 0 ) ) ) != 0 ) /* bit[63:6] event ring segment table base addr */ - goto err_writeq_erstba; - - xhci->evts->cs = 1; /* cycle state = 1 */ - USB_LOG_DBG("XHCI %s event ring [%08lx,%08lx) table [%08lx,%08lx)\n", - xhci->name, ( xhci->evts->ring ), - ( ( xhci->evts->ring ) + sizeof(xhci->evts->ring) ), - ( xhci->eseg ), - ( ( xhci->eseg ) + - sizeof ( xhci->eseg[0] ) ) ); - return 0; - - xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) ); - err_writeq_erstba: - xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); - err_writeq_erdp: - usb_free ( xhci->eseg ); - err_alloc_segment: - usb_free ( xhci->evts ); - err_alloc_trb: - return rc; -} - -/** - * Start xHCI device - * - * @v xhci xHCI device - */ -static void xhci_run ( struct xhci_host *xhci ) { - uint32_t config; - uint32_t usbcmd; - uint32_t runtime; - - /* Configure number of device slots */ - config = readl ( xhci->op + XHCI_OP_CONFIG ); - config &= ~XHCI_CONFIG_MAX_SLOTS_EN_MASK; - config |= XHCI_CONFIG_MAX_SLOTS_EN ( xhci->slots ); - writel ( config, xhci->op + XHCI_OP_CONFIG ); - - /* Enable port interrupt */ - writel ( 500U, xhci->run + XHCI_RUN_IR_IMOD ( 0 ) ); - runtime = readl(xhci->run + XHCI_RUN_IR_IMAN ( 0 )); - runtime |= XHCI_RUN_IR_IMAN_IE; - writel (runtime, xhci->run + XHCI_RUN_IR_IMAN ( 0 )); - - /* Set run/stop bit and enable interrupt */ - usbcmd = readl ( xhci->op + XHCI_OP_USBCMD ); - usbcmd |= XHCI_USBCMD_RUN | XHCI_USBCMD_INTE; - writel ( usbcmd, xhci->op + XHCI_OP_USBCMD ); - - USB_LOG_DBG("XHCI %s start running\n", xhci->name ); -} - -/** - * Free event ring - * - * @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 ) ); - xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); - - /* Free event ring segment table */ - usb_free ( xhci->eseg ); - - /* Free event ring */ - usb_free ( xhci->evts ); -} - -/** - * Free command ring - * - * @v xhci xHCI device - */ -static void xhci_command_free ( struct xhci_host *xhci ) { - - /* Sanity check */ - USB_ASSERT ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 ); - - /* Clear command ring control register */ - xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_CRCR ); - - /* Free TRB ring */ - usb_free ( xhci->cmds ); -} - -/** - * Free scratchpad buffers - * - * @v xhci xHCI device - */ -static void xhci_scratchpad_free ( struct xhci_host *xhci ) { - struct xhci_scratchpad *scratch = &xhci->scratch; - size_t array_len; - size_t buffer_len; - - /* Do nothing if no scratchpad buffers are used */ - if ( ! scratch->count ) - return; - - /* Clear scratchpad array pointer */ - USB_ASSERT ( xhci->dcbaa.context != NULL ); - xhci->dcbaa.context[0] = 0; - - /* Free scratchpad array */ - array_len = ( scratch->count * sizeof ( scratch->array[0] ) ); - usb_free ( scratch->array ); - - /* Free scratchpad buffers */ - buffer_len = ( scratch->count * xhci->pagesize ); - usb_free ( scratch->buffer ); -} - -/** - * Free device context base address array - * - * @v xhci xHCI device - */ -static void xhci_dcbaa_free ( struct xhci_host *xhci ) { - size_t len; - unsigned int i; - - /* Sanity check */ - for ( i = 0 ; i <= xhci->slots ; i++ ) - USB_ASSERT ( xhci->dcbaa.context[i] == 0 ); - - /* Clear DCBAA pointer */ - xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_DCBAAP ); - - /* Free DCBAA */ - len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) ); - usb_free ( xhci->dcbaa.context ); -} - -/** - * Open XHCI device - * - * @v xhci XHCI device - * @ret rc Return status code - */ -int xhci_open ( struct xhci_host *xhci ) { - int rc; - - /* Allocate device slot array */ - xhci->slot = usb_malloc ( ( xhci->slots + 1 ) * sizeof ( xhci->slot[0] ) ); - if ( ! xhci->slot ) { - rc = -ENOMEM; - goto err_slot_alloc; - } - - /* Allocate device context base address array */ - if ( ( rc = xhci_dcbaa_alloc ( xhci ) ) != 0 ) - goto err_dcbaa_alloc; - - /* Allocate scratchpad buffers */ - if ( ( rc = xhci_scratchpad_alloc ( xhci ) ) != 0 ) - goto err_scratchpad_alloc; - - /* Allocate command ring */ - if ( ( rc = xhci_command_alloc ( xhci ) ) != 0 ) - goto err_command_alloc; - - /* Allocate event ring */ - if ( ( rc = xhci_event_alloc ( xhci ) ) != 0 ) - goto err_event_alloc; - - /* Start controller */ - xhci_run ( xhci ); - - return 0; - - xhci_stop ( xhci ); - xhci_event_free ( xhci ); - err_event_alloc: - xhci_command_free ( xhci ); - err_command_alloc: - xhci_scratchpad_free ( xhci ); - err_scratchpad_alloc: - xhci_dcbaa_free ( xhci ); - err_dcbaa_alloc: - usb_free ( xhci->slot ); - err_slot_alloc: - return rc; - -} - -/** - * Close XHCI device - * - * @v xhci XHCI Device - */ -void xhci_close ( struct xhci_host *xhci ) { - unsigned int i; - - /* Sanity checks */ - USB_ASSERT ( xhci->slot != NULL ); - for ( i = 0 ; i <= xhci->slots ; i++ ) - USB_ASSERT ( xhci->slot[i] == NULL ); - - xhci_stop ( xhci ); - usb_free (xhci->evts); - usb_free (xhci->eseg); - usb_free (xhci->cmds); - xhci_scratchpad_free ( xhci ); - xhci_dcbaa_free ( xhci ); - usb_free ( xhci->slot ); -} - -/** - * Remove XHCI device - * - * @v xhci XHCI device - */ -void xhci_remove ( struct xhci_host *xhci ) { - xhci_reset ( xhci ); - xhci_legacy_release ( xhci ); - usb_free ( xhci ); - - /* If we are shutting down to boot an OS, then prevent the - * release of ownership back to BIOS. - */ - xhci_legacy_prevent_release = 0; -} - -/*********************************************************************/ - -/** - * Enable port - * - * @v xhci XHCI device - * @v port Port number - * @ret rc Return status code - */ -int xhci_port_enable(struct xhci_host *xhci, uint32_t port) { - uint32_t portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) ); - - /* double check if connected */ - if (!(portsc & XHCI_PORTSC_CCS)) { - USB_LOG_ERR("device connectiong lost !!! \r\n"); - return -ENOENT; - } - - switch ( portsc & XHCI_PORTSC_PLS_MASK ) - { - case XHCI_PORTSC_PLS_U0: - /* A USB3 port - controller automatically performs reset */ - break; - case XHCI_PORTSC_PLS_POLLING: - /* A USB2 port - perform device reset */ - xhci_dump_port_status(port, portsc); - writel ((portsc | XHCI_PORTSC_PR), (xhci->op + XHCI_OP_PORTSC ( port ))); /* reset port */ - break; - default: - USB_LOG_ERR("PLS: %d \r\n", (portsc & XHCI_PORTSC_PLS_MASK)); - return -ENOENT; - } - - /* Wait for device to complete reset and be enabled */ - uint32_t end = 1000U, start = 0U; - for (;;) { - portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) ); - if (!(portsc & XHCI_PORTSC_CCS)) { - /* USB 2.0 port would be disconnected after reset */ - USB_LOG_INFO("USB 2.0 port disconnected during reset, need rescan \r\n"); - return 0; - } - - if (portsc & XHCI_PORTSC_PED) { /* check if port enabled */ - /* Reset complete */ - break; - } - - if (++start > end) { - USB_LOG_ERR("Wait timeout, portsc=0x%x !!!\n", portsc); - return -ENXIO; - } - - usb_osal_msleep(1); - } - - xhci_dump_port_status(port, portsc); - return 0; -} - -/** - * Convert USB Speed to PSI - * - * @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; - break; - case USB_SPEED_FULL: - psi = XCHI_PSI_FULL; - break; - case USB_SPEED_HIGH: - psi = XCHI_PSI_HIGH; - break; - case USB_SPEED_SUPER: - psi = XCHI_PSI_SUPER; - break; - } - - return psi; -} - -/** - * Convert USB PSI to 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; - break; - case XCHI_PSI_FULL: - speed = USB_SPEED_FULL; - break; - case XCHI_PSI_HIGH: - speed = USB_SPEED_HIGH; - break; - case XCHI_PSI_SUPER: - speed = USB_SPEED_SUPER; - break; - } - - return speed; -} - -/** - * Find port speed - * - * @v xhci xHCI device - * @v port Port number - * @v psiv Protocol speed ID value - * @ret speed Port speed, or negative error - */ -static int xhci_port_speed ( struct xhci_host *xhci, unsigned int port, - unsigned int psiv ) { - unsigned int supported = xhci_supported_protocol ( xhci, port ); - unsigned int psic; - unsigned int mantissa; - unsigned int exponent; - unsigned int speed; - unsigned int i; - uint32_t ports; - uint32_t psi; - - /* Fail if there is no supported protocol */ - if ( ! supported ) - return -ENOTSUP; - - /* Get protocol speed ID count */ - ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS ); - psic = XHCI_SUPPORTED_PORTS_PSIC ( ports ); - - /* Use protocol speed ID table unless device is known to be faulty */ - /* Iterate over PSI dwords looking for a match */ - for ( i = 0 ; i < psic ; i++ ) { - psi = readl ( xhci->cap + supported + - XHCI_SUPPORTED_PSI ( i ) ); - if ( psiv == XHCI_SUPPORTED_PSI_VALUE ( psi ) ) { - mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi ); - exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi ); - return xhci_psi_to_speed(XCHI_PSI ( mantissa, exponent )); - } - } - - /* Record device as faulty if no match is found */ - if ( psic != 0 ) { - USB_LOG_ERR("XHCI %s-%d spurious PSI value %d: " - "assuming PSI table is invalid\n", - xhci->name, port, psiv ); - } - - /* Use the default mappings */ - switch ( psiv ) { - case XHCI_SPEED_LOW : return USB_SPEED_LOW; - case XHCI_SPEED_FULL : return USB_SPEED_FULL; - case XHCI_SPEED_HIGH : return USB_SPEED_HIGH; - case XHCI_SPEED_SUPER : return USB_SPEED_SUPER; - default: - USB_LOG_ERR("XHCI %s-%d unrecognised PSI value %d\n", - xhci->name, port, psiv ); - return -ENOTSUP; - } -} - -/** - * Find protocol speed ID value - * - * @v xhci xHCI device - * @v port Port number - * @v speed USB speed - * @ret psiv Protocol speed ID value, or negative error - */ -static int xhci_port_psiv ( struct xhci_host *xhci, unsigned int port, - unsigned int speed ) { - unsigned int supported = xhci_supported_protocol ( xhci, port ); - unsigned int psic; - unsigned int mantissa; - unsigned int exponent; - unsigned int psiv; - unsigned int i; - uint32_t ports; - uint32_t psi; - - /* Fail if there is no supported protocol */ - if ( ! supported ) - return -ENOTSUP; - - /* Get protocol speed ID count */ - ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS ); - psic = XHCI_SUPPORTED_PORTS_PSIC ( ports ); - - /* Use the default mappings if applicable */ - if ( psic == 0 ) { - switch ( speed ) { - case USB_SPEED_LOW : return XHCI_SPEED_LOW; - case USB_SPEED_FULL : return XHCI_SPEED_FULL; - case USB_SPEED_HIGH : return XHCI_SPEED_HIGH; - case USB_SPEED_SUPER : return XHCI_SPEED_SUPER; - default: - USB_LOG_DBG("XHCI %s-%d non-standard speed %d\n", - xhci->name, port, speed ); - return -ENOTSUP; - } - } - - /* Iterate over PSI dwords looking for a match */ - for ( i = 0 ; i < psic ; i++ ) { - psi = readl ( xhci->cap + supported + XHCI_SUPPORTED_PSI ( i )); - mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi ); - exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi ); - if ( xhci_speed_to_psi(speed) == XCHI_PSI ( mantissa, exponent ) ) { - psiv = XHCI_SUPPORTED_PSI_VALUE ( psi ); - return psiv; - } - } - - USB_LOG_DBG("XHCI %s-%d unrepresentable speed %#x\n", - xhci->name, port, speed ); - return -ENOENT; -} - -/** - * Update root hub port speed - * - * @v xhci XHCI device - * @v port Port number - * @ret rc Return status code (speed) - */ -uint32_t xhci_root_speed ( struct xhci_host *xhci, uint8_t port ) { - uint32_t portsc; - unsigned int psiv; - int ccs; - int ped; - int csc; - int speed; - unsigned int protocol = xhci_port_protocol(xhci, port); - - /* Read port status */ - portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) ); - USB_LOG_DBG("XHCI %s-%d status is 0x%08x, protocol 0x%x\n", - xhci->name, port, portsc, protocol ); - ccs = ( portsc & XHCI_PORTSC_CCS ); - ped = ( portsc & XHCI_PORTSC_PED ); - 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", - xhci->name, port, !!ccs, !!ped, !!csc, psiv); - - /* Port speed is not valid unless port is connected */ - if ( ! ccs ) { - speed = USB_SPEED_UNKNOWN; - USB_LOG_ERR("XHCI %s port-%d speed unkown\n", xhci->name, port); - return speed; - } - - /* For USB2 ports, the PSIV field is not valid until the port - * completes reset and becomes enabled. - */ - if ( ( protocol < USB_3_0 ) && ! ped ) { - speed = USB_SPEED_FULL; - return speed; - } - - /* Get port speed and map to generic USB speed */ - speed = xhci_port_speed ( xhci, port, psiv ); - if ( speed < 0 ) { - return speed; - } - - return speed; -} - -/*********************************************************************/ -/** - * Add a TRB to the given ring - * - * @v ring XHCI TRB ring - * @v trb TRB content to be added - */ -static inline void xhci_trb_fill(struct xhci_ring *ring, union xhci_trb *trb) { - union xhci_trb *dst = &ring->ring[ring->nidx]; - memcpy((void *)dst, (void *)trb, sizeof(*trb)); - dst->template.control |= (ring->cs ? XHCI_TRB_C : 0); - xhci_dump_trbs(dst, 1); -} - -/** - * Queue a TRB onto a ring, wrapping ring as needed - * - * @v ring XHCI TRB ring - * @v trb TRB content to be added - */ -static void xhci_trb_queue(struct xhci_ring *ring, union xhci_trb *trb) { - - if (ring->nidx >= XHCI_RING_ITEMS - 1) { - /* if it is the last trb in the list, put a link trb in the end */ - union xhci_trb link_trb; - link_trb.link.type = XHCI_TRB_LINK; - link_trb.link.flags = XHCI_TRB_TC; - link_trb.link.next = CPU_TO_LE64((ring->ring)); - - xhci_trb_fill(ring, &link_trb); - - ring->nidx = 0; /* adjust dequeue index to 0 */ - ring->cs ^= 1; /* toggle cycle interpretation of sw */ - } - - xhci_trb_fill(ring, trb); - ring->nidx++; /* ahead dequeue index */ -} - -/** - * Wait for a ring to empty (all TRBs processed by hardware) - * - * @v xhci XHCI Device - * @v ep Owner Endpoint of current TRB ring - * @ ring XHCI TRB ring - */ -int xhci_event_wait(struct xhci_host *xhci, - struct xhci_endpoint *ep, - struct xhci_ring *ring) { - int cc = XHCI_CMPLT_SUCCESS; - - if (ep->timeout > 0) - { - if (usb_osal_sem_take(ep->waitsem, ep->timeout) < 0) - { - cc = XHCI_CMPLT_TIMEOUT; - } - else - { - cc = ring->evt.complete.code; /* bit[31:24] completion code */ - } - } - - return cc; -} - -/** - * Ring doorbell register - * - * @v xhci XHCI device - * @v slotid Slot id to ring - * @v value Value send to doorbell - */ -static inline void xhci_doorbell ( struct xhci_host *xhci, uint32_t slotid, uint32_t value ) { - - DSB(); - writel ( value, xhci->db + slotid * XHCI_REG_DB_SIZE ); /* bit[7:0] db target, is ep_id */ -} - -/** - * Abort command - * - * @v xhci xHCI device - */ -static void xhci_abort ( struct xhci_host *xhci ) { - uintptr_t crp; - - /* Abort the command */ - USB_LOG_WRN("XHCI %s aborting command\n", xhci->name ); - xhci_writeq ( xhci, XHCI_CRCR_CA, xhci->op + XHCI_OP_CRCR ); - - /* Allow time for command to abort */ - usb_osal_msleep ( XHCI_COMMAND_ABORT_DELAY_MS ); - - /* Sanity check */ - USB_ASSERT ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 ); - - /* 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); - } - - /* Reset the command ring control register */ - memset(xhci->cmds->ring, 0U, XHCI_RING_ITEMS * sizeof(union xhci_trb)); - xhci_writeq ( xhci, ( (uint64_t)(uintptr_t)xhci->cmds | xhci->cmds->cs ), xhci->op + XHCI_OP_CRCR ); -} - -/** - * Submit a command to the xhci controller ring - * - * @v xhci XHCI Device - * @v ep Owner Endpoint of current TRB ring - * @ 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 */ - - ep->timeout = 5000; - ep->waiter = true; - xhci->cur_cmd_pipe = ep; - - xhci_trb_queue(xhci->cmds, trb); - - /* pass command trb to hardware */ - DSB(); - - xhci_doorbell(xhci, 0, 0); /* 0 = db host controller, 0 = db targe hc command */ - int cc = xhci_event_wait(xhci, ep, xhci->cmds); - 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; - } - - usb_osal_mutex_give(xhci->cmds->lock); - xhci->cur_cmd_pipe = NULL; - return rc; -} - -/** - * Issue NOP and wait for completion - * - * @v xhci xHCI device - * @v ep Command Endpoint - * @ret rc Return status code - */ -static int xhci_nop ( struct xhci_host *xhci, struct xhci_endpoint *ep ) { - union xhci_trb trb; - struct xhci_trb_common *nop = &trb.common; - int rc; - - /* Construct command */ - memset ( nop, 0, sizeof ( *nop ) ); - nop->flags = XHCI_TRB_IOC; - nop->type = XHCI_TRB_NOP_CMD; - - /* Issue command and wait for completion */ - if ( ( rc = xhci_cmd_submit(xhci, ep, &trb ) ) != 0 ) - return rc; - - return 0; -} - -/** - * Issue Enable slot and wait for completion - * - * @v xhci xHCI device - * @v ep Command Endpoint - * @v type Type of Slot to be enabled - * @ret rc Return status code - */ -static int xhci_enable_slot(struct xhci_host *xhci, struct xhci_endpoint *ep, unsigned int type) { - union xhci_trb trb; - struct xhci_trb_enable_slot *enable = &trb.enable; - struct xhci_trb_complete *enabled; - unsigned int slot; - int rc; - - /* Construct command */ - memset ( enable, 0, sizeof ( *enable ) ); - enable->slot = type; - enable->type = XHCI_TRB_ENABLE_SLOT; - - /* Issue command and Wait for completion */ - if ( ( rc = xhci_cmd_submit(xhci, ep, &trb) ) != 0 ) { - USB_LOG_ERR("XHCI %s could not enable new slot, type %d\n", - xhci->name, type ); - return rc; - } - - /* Extract slot number */ - enabled = &(xhci->cmds->evt.complete); - slot = enabled->slot; - - USB_LOG_DBG("XHCI %s slot %d enabled\n", xhci->name, slot ); - return slot; -} - -/** - * Disable slot - * - * @v xhci xHCI device - * @v ep Command Endpoint - * @v slot Device slot - * @ret rc Return status code - */ -static int xhci_disable_slot ( struct xhci_host *xhci, struct xhci_endpoint *ep, - unsigned int slot ) { - union xhci_trb trb; - struct xhci_trb_disable_slot *disable = &trb.disable; - int rc; - - /* Construct command */ - memset ( disable, 0, sizeof ( *disable ) ); - disable->type = XHCI_TRB_DISABLE_SLOT; - disable->slot = slot; - - /* Issue command and wait for completion */ - if ( ( rc = xhci_cmd_submit ( xhci, ep, &trb ) ) != 0 ) { - USB_LOG_DBG("XHCI %s could not disable slot %d: %s\n", - xhci->name, slot, strerror ( rc ) ); - return rc; - } - - USB_LOG_DBG("XHCI %s slot %d disabled\n", xhci->name, slot ); - return 0; -} - -/** - * Issue context-based command and wait for completion - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @v type TRB type - * @v populate Input context populater - * @ret rc Return status code - */ -static int xhci_context ( struct xhci_host *xhci, struct xhci_slot *slot, - struct xhci_endpoint *ep, unsigned int type, - void ( * populate ) ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *ep, - void *input ) ) { - union xhci_trb trb; - struct xhci_trb_context *context = &trb.context; - size_t len; - void *input; - int rc; - - /* Allocate an input context */ - len = xhci_input_context_offset ( xhci, XHCI_CTX_END ); - input = usb_align(xhci_align ( len ), len); - if ( ! input ) { - rc = -ENOMEM; - goto err_alloc; - } - memset ( input, 0, len ); - - /* Populate input context */ - populate ( xhci, slot, ep, input ); - - /* Construct command */ - memset ( context, 0, sizeof ( *context ) ); - context->type = type; - context->input = CPU_TO_LE64 ( ( input ) ); - context->slot = slot->id; - - /* Issue command and wait for completion */ - if ( ( rc = xhci_cmd_submit ( xhci, ep, &trb ) ) != 0 ) { - xhci_dump_input_ctx(xhci, ep, input); - goto err_command; - } - - err_command: - usb_free ( input ); - err_alloc: - return rc; -} - -/** - * Populate address device input context - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @v input Input context - */ -static void xhci_address_device_input ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *endpoint, - void *input ) { - struct xhci_control_context *control_ctx; - struct xhci_slot_context *slot_ctx; - struct xhci_endpoint_context *ep_ctx; - - /* Sanity checks */ - USB_ASSERT ( endpoint->ctx == XHCI_CTX_EP0 ); - - /* Populate control context, add slot context and ep context */ - control_ctx = input; - control_ctx->add = CPU_TO_LE32 ( ( 1 << XHCI_CTX_SLOT ) | - ( 1 << XHCI_CTX_EP0 ) ); - - /* Populate slot context */ - slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT )); - slot_ctx->info = CPU_TO_LE32 ( XHCI_SLOT_INFO ( 1, 0, slot->psiv, - slot->route ) ); - slot_ctx->port = slot->port; - slot_ctx->tt_id = slot->tt_id; - slot_ctx->tt_port = slot->tt_port; - - /* Populate control endpoint context */ - ep_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_EP0 ) ); - ep_ctx->type = XHCI_EP_TYPE_CONTROL; /* bit[5:3] endpoint type */ - ep_ctx->burst = endpoint->burst; /* bit[16:8] max burst size */ - ep_ctx->mtu = CPU_TO_LE16 ( endpoint->mtu ); /* bit[31:16] max packet size */ - - /* - bit[63:4] tr dequeue pointer - bit[0] dequeue cycle state - */ - ep_ctx->dequeue = CPU_TO_LE64 ( (uint64_t)( &endpoint->reqs.ring[0] ) | XHCI_EP_DCS ); - ep_ctx->trb_len = CPU_TO_LE16 ( XHCI_EP0_TRB_LEN ); /* bit[15:0] average trb length */ -} - -/** - * Address device - * - * @v xhci xHCI device - * @v endpoint Endpoint - * @v slot Device slot - * @ret rc Return status code - */ -static inline int xhci_address_device ( struct xhci_host *xhci, - struct xhci_endpoint *ep, - struct xhci_slot *slot ) { - struct xhci_slot_context *slot_ctx; - int rc; - - /* Assign device address */ - 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 */ - slot_ctx = ( slot->context + - xhci_device_context_offset ( xhci, XHCI_CTX_SLOT ) ); - USB_LOG_DBG("XHCI %s slot ctx 0x%x assigned address 0x%x\n", - xhci->name, slot_ctx, slot_ctx->address ); - - return rc; -} - -/** - * Reset endpoint - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @ret rc Return status code - */ -int xhci_reset_endpoint ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *endpoint ) { - union xhci_trb trb; - struct xhci_trb_reset_endpoint *reset = &trb.reset; - int rc; - - /* Construct command */ - memset ( reset, 0, sizeof ( *reset ) ); - reset->slot = slot->id; - reset->endpoint = endpoint->ctx; - reset->type = XHCI_TRB_RESET_ENDPOINT; - - /* Issue command and wait for completion */ - if ( ( rc = xhci_cmd_submit ( xhci, endpoint, &trb ) ) != 0 ) { - USB_LOG_DBG("XHCI %s slot %d ctx %d could not reset endpoint " - "in state %d: %s\n", xhci->name, slot->id, endpoint->ctx, - endpoint->context->state, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Stop endpoint - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @ret rc Return status code - */ -static inline int xhci_stop_endpoint ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *endpoint ) { - union xhci_trb trb; - struct xhci_trb_stop_endpoint *stop = &trb.stop; - int rc; - - /* Construct command */ - memset ( stop, 0, sizeof ( *stop ) ); - stop->slot = slot->id; - stop->endpoint = endpoint->ctx; - stop->type = XHCI_TRB_STOP_ENDPOINT; - - /* Issue command and wait for completion */ - if ( ( rc = xhci_cmd_submit ( xhci, endpoint, &trb ) ) != 0 ) { - USB_LOG_DBG("XHCI %s slot %d ctx %d could not stop endpoint " - "in state %d: %s\n", xhci->name, slot->id, endpoint->ctx, - endpoint->context->state, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/*********************************************************************/ - -/** - * Find port slot type - * - * @v xhci xHCI device - * @v port Port number - * @ret type Slot type, or negative error - */ -static int xhci_port_slot_type ( struct xhci_host *xhci, unsigned int port ) { - unsigned int supported = xhci_supported_protocol ( xhci, port ); - unsigned int type; - uint32_t slot; - - /* Fail if there is no supported protocol */ - if ( ! supported ) - return -ENOTSUP; - - /* Get slot type */ - slot = readl ( xhci->cap + supported + XHCI_SUPPORTED_SLOT ); - type = XHCI_SUPPORTED_SLOT_TYPE ( slot ); - - return type; -} - -/** - * Open device - * - * @v xhci XHCI device - * @v ep Endpoint - * @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 xhci_slot *slot; - struct xhci_slot *tt_slot; - int type; - int rc; - int id; - size_t len; - - /* Determine applicable slot type */ - type = xhci_port_slot_type ( xhci, hport->port ); - if ( type < 0 ) { - rc = type; - USB_LOG_ERR("XHCI %s-%d has no slot type\n", - xhci->name, hport->port ); - goto err_type; - } - - /* Allocate a device slot number */ - id = xhci_enable_slot ( xhci, ep, type ); - if ( id < 0 ) { - rc = id; - goto err_enable_slot; - } - - USB_ASSERT ( ( id > 0 ) && ( ( unsigned int ) id <= xhci->slots ) ); - USB_ASSERT ( xhci->slot[id] == NULL ); - - /* Allocate and initialise structure */ - slot = usb_malloc ( sizeof ( *slot ) ); - if ( ! slot ) { - rc = -ENOMEM; - goto err_alloc; - } - slot->id = id; - xhci->slot[id] = slot; - slot->xhci = xhci; - if ( tt ) { - tt_slot = xhci->slot[tt->dev_addr]; - slot->tt_id = tt_slot->id; - slot->tt_port = tt->port; - } - - /* Allocate a device context */ - len = xhci_device_context_offset ( xhci, XHCI_CTX_END ); - slot->context = usb_align(xhci_align ( len ), len); - if ( ! slot->context ) { - rc = -ENOMEM; - goto err_alloc_context; - } - memset ( slot->context, 0, len ); - - /* Set device context base address */ - USB_ASSERT ( xhci->dcbaa.context[id] == 0 ); - xhci->dcbaa.context[id] = CPU_TO_LE64 ( ( slot->context ) ); - - USB_LOG_DBG("XHCI %s slot %d device context [%08lx,%08lx)\n", - xhci->name, slot->id, ( slot->context ), - ( ( slot->context ) + len ) ); - *slot_id = id; - return 0; - - xhci->dcbaa.context[id] = 0; - usb_free ( slot->context ); - -err_alloc_context: - xhci->slot[id] = NULL; - usb_free ( slot ); -err_alloc: - xhci_disable_slot ( xhci, ep, id ); -err_enable_slot: -err_type: - return rc; -} - -/*********************************************************************/ - -/** - * Assign device address - * - * @v xhci XHCI device - * @v slot Slot - * @v ep Endpoint - * @ret rc Return status code - */ -int xhci_device_address ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *ep ) { - USB_ASSERT((slot->xhci) && (ep->hport)); - struct usbh_hubport *hport = ep->hport; - int psiv; - int rc; - - /* Calculate route string */ - slot->route = usbh_route_string (hport); - - /* Calculate root hub port number */ - struct usbh_hubport *root_port = usbh_root_hub_port (hport); - slot->port = root_port->port; - - /* Calculate protocol speed ID */ - psiv = xhci_port_psiv ( xhci, slot->port, hport->speed ); - if ( psiv < 0 ) { - rc = psiv; - return rc; - } - slot->psiv = psiv; - - /* Address device */ - if ( ( rc = xhci_address_device ( xhci, ep, slot ) ) != 0 ) - return rc; - - return 0; -} - - -/** - * Close device - * - * @v slot Slot - */ -void xhci_device_close ( struct xhci_slot *slot ) { - struct xhci_host *xhci = slot->xhci; - size_t len = xhci_device_context_offset ( xhci, XHCI_CTX_END ); - unsigned int id = slot->id; - int rc; - - /* Disable slot */ - if ( ( rc = xhci_disable_slot ( xhci, slot->endpoint[0], id ) ) != 0 ) { - /* Slot is still enabled. Leak the slot context, - * since the controller may still write to this - * memory, and leave the DCBAA entry intact. - * - * If the controller later reports that this same slot - * has been re-enabled, then some assertions will be - * triggered. - */ - USB_LOG_DBG("XHCI %s slot %d leaking context memory\n", - xhci->name, slot->id ); - slot->context = NULL; - } - - /* Free slot */ - if ( slot->context ) { - usb_free ( slot->context ); - xhci->dcbaa.context[id] = 0; - } - xhci->slot[id] = NULL; - usb_free ( slot ); -} - - -/** - * Populate configure endpoint input context - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @v input Input context - */ -static void xhci_configure_endpoint_input ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *endpoint, - void *input ) { - struct xhci_control_context *control_ctx; - struct xhci_slot_context *slot_ctx; - struct xhci_endpoint_context *ep_ctx; - - xhci_dump_endpoint(endpoint); - - /* Populate control context */ - control_ctx = input; - control_ctx->add = CPU_TO_LE32 (( 1 << XHCI_CTX_SLOT ) | ( 1 << endpoint->ctx ) ); - control_ctx->drop = CPU_TO_LE32 (( 1 << XHCI_CTX_SLOT ) | ( 1 << endpoint->ctx ) ); - - /* Populate slot context */ - slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT )); - slot_ctx->info = CPU_TO_LE32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ), - ( slot->ports ? 1 : 0 ), - slot->psiv, 0 ) ); - slot_ctx->ports = slot->ports; - - /* Populate endpoint context */ - ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) ); - ep_ctx->interval = endpoint->interval; /* bit[23:16] for interrupt ep, set interval to control interrupt period */ - /* - Value Endpoint Type Direction - 0 Not Valid N/A - 1 Isoch Out - 2 Bulk Out - 3 Interrupt Out - 4 Control Bidirectional - 5 Isoch In - 6 Bulk In - 7 Interrupt In - */ - ep_ctx->type = endpoint->ctx_type; - 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 */ - } else if (endpoint->ep_type == USB_ENDPOINT_TYPE_INTERRUPT) { - ep_ctx->trb_len = CPU_TO_LE16 (16U); - ep_ctx->esit_low = CPU_TO_LE16 ( endpoint->mtu ); /* bit[31:16] max ESIT payload */ - } - - xhci_dump_input_ctx(xhci, endpoint, input); -} - -/** - * Configure endpoint - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @ret rc Return status code - */ -static inline int xhci_configure_endpoint ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *endpoint ){ - int rc; - - /* Configure endpoint */ - if ( ( rc = xhci_context ( xhci, slot, endpoint, - 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 ); - return rc; - } - - /* Sanity check */ - if ( ( endpoint->context->state & XHCI_ENDPOINT_STATE_MASK ) - != XHCI_ENDPOINT_RUNNING ){ - 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 ); - return -1; - } - - USB_LOG_DBG("XHCI %s slot %d ctx %d configured\n", - xhci->name, slot->id, endpoint->ctx ); - return 0; -} - -/** - * Populate deconfigure endpoint input context - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @v input Input context - */ -static void -xhci_deconfigure_endpoint_input ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *endpoint, - void *input ) { - struct xhci_control_context *control_ctx; - struct xhci_slot_context *slot_ctx; - - /* Populate control context */ - control_ctx = input; - control_ctx->add = CPU_TO_LE32 ( 1 << XHCI_CTX_SLOT ); - control_ctx->drop = CPU_TO_LE32 ( 1 << endpoint->ctx ); - - /* Populate slot context */ - slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT )); - slot_ctx->info = CPU_TO_LE32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ), - 0, 0, 0 ) ); -} - -/** - * Deconfigure endpoint - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @ret rc Return status code - */ -static inline int xhci_deconfigure_endpoint ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *endpoint ) { - int rc; - - /* Deconfigure endpoint */ - if ( ( rc = xhci_context ( xhci, slot, endpoint, - XHCI_TRB_CONFIGURE_ENDPOINT, - xhci_deconfigure_endpoint_input ) ) != 0 ) - return rc; - - USB_LOG_DBG("XHCI %s slot %d ctx %d deconfigured\n", - xhci->name, slot->id, endpoint->ctx ); - return 0; -} - -/*********************************************************************/ - -/** - * Open control endpoint - * - * @v xhci XHCI device - * @v slot Slot - * @v ep Endpoint - * @ret rc Return status code - */ -int xhci_ctrl_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *ep ) { - unsigned int ctx; - - /* Calculate context index */ - ctx = XHCI_CTX ( ep->address ); - USB_ASSERT ( slot->endpoint[ctx] == NULL ); - - if (USB_ENDPOINT_TYPE_CONTROL != ep->ep_type) { - return -EINVAL; - } - - /* initialise structure */ - slot->endpoint[ctx] = ep; - ep->xhci = xhci; - ep->slot = slot; - ep->ctx = ctx; - ep->ctx_type = XHCI_EP_TYPE_CONTROL; - ep->context = ( ( ( void * ) slot->context ) + - xhci_device_context_offset ( xhci, ctx ) ); - 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, - (ep->ctx_type >> 3) ); - - USB_LOG_DBG("XHCI %s slot %d ctx %d ring [%08lx,%08lx)\n", - xhci->name, slot->id, ctx, ( ep->reqs.ring ), - ( ( ep->reqs.ring ) + sizeof(ep->reqs.ring) ) ); - - return 0; -} - -/*********************************************************************/ - -/** - * Open work endpoint - * - * @v xhci XHCI device - * @v slot Slot - * @v ep USB endpoint - * @ret rc Return status code - */ -int xhci_work_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *ep ) { - unsigned int ctx; - unsigned int interval; - unsigned int ctx_type; - int rc; - - /* Calculate context index */ - ctx = XHCI_CTX ( ep->address ); - USB_ASSERT ( slot->endpoint[ctx] == NULL ); - - if (USB_ENDPOINT_TYPE_CONTROL == ep->ep_type) { - return -EINVAL; - } - - /* Calculate endpoint type */ - /* - Value Endpoint Type Direction, bit[5:3] - 0 Not Valid N/A - 1 Isoch Out - 2 Bulk Out - 3 Interrupt Out - 4 Control Bidirectional - 5 Isoch In - 6 Bulk In - 7 Interrupt In - */ - ctx_type = XHCI_EP_TYPE ( ep->ep_type ); - if ( ep->address & USB_EP_DIR_IN ) - ctx_type |= XHCI_EP_TYPE_IN; - - /* initialise structure */ - slot->endpoint[ctx] = ep; - ep->xhci = xhci; - ep->slot = slot; - ep->ctx = ctx; - - /* Calculate interval */ - if ( ctx_type & XHCI_EP_TYPE_PERIODIC ) { - ep->interval = ( xhci_fls ( ep->interval ) - 1 ); - } - - ep->ctx_type = ctx_type; - ep->context = ( ( ( void * ) slot->context ) + - xhci_device_context_offset ( xhci, ctx ) ); - 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, - (ep->ctx_type >> 3) ); - - /* Configure endpoint */ - if (( rc = xhci_configure_endpoint ( xhci, slot, ep ) ) != 0) { - goto err_configure_endpoint; - } - - USB_LOG_DBG("XHCI %s slot %d ctx %d ring [%08lx,%08lx)\n", - xhci->name, slot->id, ctx, ( ep->reqs.ring ), - ( ( ep->reqs.ring ) + sizeof(ep->reqs.ring) ) ); - - return 0; - err_configure_endpoint: - (void)xhci_deconfigure_endpoint ( xhci, slot, ep ); - slot->endpoint[ctx] = NULL; - return rc; -} - -/** - * Close endpoint - * - * @v ep USB endpoint - */ -void xhci_endpoint_close ( struct xhci_endpoint *ep ) { - struct xhci_slot *slot = ep->slot; - struct xhci_host *xhci = slot->xhci; - unsigned int ctx = ep->ctx; - - /* Deconfigure endpoint, if applicable */ - if ( ctx != XHCI_CTX_EP0 ) - (void)xhci_deconfigure_endpoint ( xhci, slot, ep ); - - slot->endpoint[ctx] = NULL; - usb_free(ep); -} - -/*********************************************************************/ - -/** - * Enqueue message transfer - * - * @v ep USB endpoint - * @v packet Setup packet buffer - * @v data_buff Data buffer - * @v datalen Data length - * @ret rc Return status code - */ -void xhci_endpoint_message ( struct xhci_endpoint *ep, - struct usb_setup_packet *packet, - void *data_buff, - int datalen ) { - struct xhci_host *xhci = ep->xhci; - struct xhci_slot *slot = ep->slot; - union xhci_trb trb; - struct xhci_trb_setup *setup; - struct xhci_trb_data *data; - struct xhci_trb_status *status; - unsigned int input; - - /* Construct setup stage TRB */ - setup = &(trb.setup); - memset ( setup, 0, sizeof ( *setup ) ); - - memcpy ( &setup->packet, packet, sizeof ( setup->packet ) ); - setup->len = CPU_TO_LE32 ( sizeof ( *packet ) ); /* bit[16:0] trb transfer length, always 8 */ - setup->flags = XHCI_TRB_IDT; /* bit[6] Immediate Data (IDT), parameters take effect */ - setup->type = XHCI_TRB_SETUP; /* bit[15:10] trb type */ - input = ( packet->bmRequestType & CPU_TO_LE16 ( USB_REQUEST_DIR_IN ) ); - if (datalen > 0) { - /* bit[17:16] Transfer type, 2 = OUT Data, 3 = IN Data */ - setup->direction = ( input ? XHCI_SETUP_IN : XHCI_SETUP_OUT ); - } - - xhci_trb_queue(&(ep->reqs), &trb); - - /* Construct data stage TRB, if applicable */ - if (datalen > 0) { - data = &(trb.data); - memset ( data, 0, sizeof ( *data ) ); - - data->data = CPU_TO_LE64 ( data_buff ); - data->len = CPU_TO_LE32 ( datalen ); - data->type = XHCI_TRB_DATA; /* bit[15:10] trb type */ - data->direction = ( input ? XHCI_DATA_IN : XHCI_DATA_OUT ); /* bit[16] Direction, 0 = OUT, 1 = IN */ - - xhci_trb_queue(&(ep->reqs), &trb); - } - - status = &(trb.status); - memset ( status, 0, sizeof ( *status ) ); - status->flags = XHCI_TRB_IOC; - status->type = XHCI_TRB_STATUS; - status->direction = - ( ( datalen && input ) ? XHCI_STATUS_OUT : XHCI_STATUS_IN ); - - xhci_trb_queue(&(ep->reqs), &trb); - - /* pass command trb to hardware */ - DSB(); - - USB_LOG_DBG("ring doorbell slot-%d ep-%d \r\n", slot->id, ep->ctx); - xhci_doorbell(xhci, slot->id, ep->ctx); /* 0 = db host controller, 0 = db targe hc command */ - - return; -} - -/*********************************************************************/ - -/** - * Enqueue stream transfer - * - * @v ep USB endpoint - * @v data_buff Data buffer - * @v datalen Data length - * @ret rc Return status code - */ -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; - union xhci_trb trbs; - union xhci_trb *trb = &trbs; - struct xhci_trb_normal *normal; - int trb_len; - - /* Calculate TRB length */ - trb_len = XHCI_MTU; - if ( trb_len > datalen ) { - trb_len = datalen; - } else { - USB_LOG_ERR("transfer length %d exceed MTU %d \r\n", datalen, trb_len); - goto err_enqueue; - } - - /* Construct normal TRBs */ - normal = &trb->normal; - memset ( normal, 0, sizeof ( *normal ) ); - normal->data = CPU_TO_LE64 ( (uintptr_t)data_buff ); - normal->len = CPU_TO_LE32 ( trb_len ); - normal->type = XHCI_TRB_NORMAL; - normal->flags = XHCI_TRB_IOC; - - xhci_trb_queue(&(ep->reqs), trb); - - /* pass command trb to hardware */ - DSB(); - - xhci_doorbell(xhci, slot->id, ep->ctx); - -err_enqueue: - return; -} - -/*********************************************************************/ - -/** - * Populate evaluate context input context - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @v input Input context - */ -static void xhci_evaluate_context_input ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *endpoint, - void *input ) { - struct xhci_control_context *control_ctx; - struct xhci_slot_context *slot_ctx; - struct xhci_endpoint_context *ep_ctx; - - /* Populate control context */ - control_ctx = input; - control_ctx->add = CPU_TO_LE32 ( ( 1 << XHCI_CTX_SLOT ) /*| - ( 1 << endpoint->ctx )*/ ); - control_ctx->drop = CPU_TO_LE32 ( ( 1 << XHCI_CTX_SLOT ) /* | - ( 1 << endpoint->ctx )*/ ); - - /* Populate slot context */ - slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT )); - slot_ctx->info = CPU_TO_LE32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ), - 0, 0, 0 ) ); - - /* Populate endpoint context */ - ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) ); - ep_ctx->mtu = CPU_TO_LE16 ( endpoint->mtu ); -} - -/** - * Evaluate context - * - * @v xhci xHCI device - * @v slot Device slot - * @v endpoint Endpoint - * @ret rc Return status code - */ -static inline int xhci_evaluate_context ( struct xhci_host *xhci, - struct xhci_slot *slot, - struct xhci_endpoint *endpoint ) { - int rc; - - /* Configure endpoint */ - if ( ( rc = xhci_context ( xhci, slot, endpoint, - XHCI_TRB_EVALUATE_CONTEXT, - xhci_evaluate_context_input ) ) != 0 ) - return rc; - - USB_LOG_DBG("XHCI %s slot %d ctx %d (re-)evaluated\n", - xhci->name, slot->id, endpoint->ctx ); - return 0; -} - -/** - * Update MTU - * - * @v ep USB endpoint - * @ret rc Return status code - */ -int xhci_endpoint_mtu ( struct xhci_endpoint *ep ) { - struct xhci_endpoint *endpoint = ( ep ); - struct xhci_slot *slot = endpoint->slot; - struct xhci_host *xhci = slot->xhci; - int rc; - - /* Evalulate context */ - if ( ( rc = xhci_evaluate_context ( xhci, slot, endpoint ) ) != 0 ) - return rc; - - return 0; -} - -/*********************************************************************/ - -/** - * Handle port status event - * - * @v xhci xHCI device - * @v trb Port status event - */ -static void xhci_port_status ( struct xhci_host *xhci, - struct xhci_trb_port_status *trb ) { - uint32_t portsc; - - /* Sanity check */ - USB_ASSERT ( ( trb->port > 0 ) && ( trb->port <= xhci->ports ) ); - - /* Record disconnections, changes flag will be cleared later */ - portsc = readl ( xhci->op + XHCI_OP_PORTSC ( trb->port ) ); - xhci_dump_port_status(trb->port, portsc); - - if (portsc & XHCI_PORTSC_CSC) { - /* Report port status change */ - usbh_roothub_thread_wakeup ( trb->port ); - } -} - -/** - * Handle transfer event - * - * @v xhci xHCI device - * @v trb Transfer event TRB - */ -static void xhci_transfer ( struct xhci_host *xhci, - struct xhci_trb_transfer *trb ) { - struct xhci_slot *slot; - 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 */ - int rc; - - /* Identify slot */ - if ( ( trb->slot > xhci->slots ) || - ( ( slot = xhci->slot[trb->slot] ) == NULL ) ) { - USB_LOG_DBG("XHCI %s transfer event invalid slot %d:\n", - xhci->name, trb->slot ); - return; - } - - /* Identify endpoint */ - if ( ( trb->endpoint >= XHCI_CTX_END ) || - ( ( endpoint = slot->endpoint[trb->endpoint] ) == NULL ) ) { - USB_LOG_DBG("XHCI %s slot %d transfer event invalid epid " - "%d:\n", xhci->name, slot->id, trb->endpoint ); - return; - } - - /* Record completion */ - memcpy(pending, trb, sizeof(*trb)); /* copy current trb to cmd/transfer ring */ - trans_ring->eidx = eidx; - - /* Check for errors */ - if ( ! ( ( trb->code == XHCI_CMPLT_SUCCESS ) || - ( trb->code == XHCI_CMPLT_SHORT ) ) ) { - USB_LOG_ERR("XHCI %s slot %d ctx %d failed (code %d)\n", - xhci->name, slot->id, endpoint->ctx, trb->code); - - /* Sanity check */ - USB_ASSERT ( ( endpoint->context->state & XHCI_ENDPOINT_STATE_MASK ) - != XHCI_ENDPOINT_RUNNING ); - - xhci_dump_ep_ctx(endpoint->context); - return; - } - - if (endpoint->waiter) { - endpoint->waiter = false; - usb_osal_sem_give(endpoint->waitsem); - } - - if (endpoint->urb) { - struct usbh_urb *cur_urb = endpoint->urb; - cur_urb->errorcode = trb->code; - /* bit [23:0] TRB Transfer length, residual number of bytes not transferred - for OUT, is the value of (len of trb) - (data bytes transmitted), '0' means successful - for IN, is the value of (len of trb) - (data bytes received), - if cc is Short Packet, value is the diff between expected trans size and actual recv bytes - if cc is other error, value is the diff between expected trans size and actual recv bytes */ - cur_urb->actual_length += cur_urb->transfer_buffer_length - trb->residual; /* bit [23:0] */ - - if (cur_urb->complete) { - if (cur_urb->errorcode < 0) { - cur_urb->complete(cur_urb->arg, cur_urb->errorcode); - } else { - cur_urb->complete(cur_urb->arg, cur_urb->actual_length); - } - } - } - - return; -} - -/** - * Handle command completion event - * - * @v xhci xHCI device - * @v trb Command completion event - */ -static void xhci_complete ( struct xhci_host *xhci, - struct xhci_trb_complete *trb ) { - int rc; - union xhci_trb *cmd_trb = (void *)(uintptr_t)(trb->command); - struct xhci_ring *cmd_ring = XHCI_RING(cmd_trb); /* to align addr is ring base */ - union xhci_trb *pending = &cmd_ring->evt; /* preserve event trb pending to handle */ - uint32_t eidx = cmd_trb - cmd_ring->ring + 1; /* calculate current evt trb index */ - struct xhci_endpoint *work_pipe = xhci->cur_cmd_pipe; - - /* Ignore "command ring stopped" notifications */ - if ( trb->code == XHCI_CMPLT_CMD_STOPPED ) { - USB_LOG_DBG("XHCI %s command ring stopped\n", xhci->name ); - return; - } - - /* Record completion */ - USB_LOG_DBG("command-0x%x completed !!! \r\n", pending); - memcpy(pending, trb, sizeof(*trb)); /* copy current trb to cmd/transfer ring */ - cmd_ring->eidx = eidx; - - USB_ASSERT(work_pipe); - if (work_pipe->waiter) - { - work_pipe->waiter = false; - usb_osal_sem_give(work_pipe->waitsem); - } -} - -/** - * Handle host controller event - * - * @v xhci xHCI device - * @v trb Host controller event - */ -static void xhci_host_controller ( struct xhci_host *xhci, - struct xhci_trb_host_controller *trb ) { - int rc; - - /* Construct error */ - rc = -( trb->code ); - USB_LOG_ERR("XHCI %s host controller event (code %d)\n", - xhci->name, trb->code ); -} - -/** - * Process event ring in interrupt - * - * @v xhci xHCI device - * @r workpip current work endpoint - */ -struct xhci_endpoint *xhci_event_process(struct xhci_host *xhci) { - struct xhci_endpoint *work_pipe = NULL; - struct xhci_ring *evts = xhci->evts; - unsigned int evt_type; - unsigned int evt_cc; - - /* check and ack event */ - for (;;) { - /* Stop if we reach an empty TRB */ - DSB(); - - uint32_t nidx = evts->nidx; /* index of dequeue trb */ - uint32_t cs = evts->cs; /* cycle state toggle by xHc */ - union xhci_trb *trb = evts->ring + nidx; /* current trb */ - uint32_t control = trb->common.flags; /* trb control field */ - - if ((control & XHCI_TRB_C) != (cs ? 1 : 0)) { /* if cycle state not toggle, no events need to handle */ - break; - } - - /* Handle TRB */ - evt_type = ( trb->common.type & XHCI_TRB_TYPE_MASK ); - switch ( evt_type ) { - - case XHCI_TRB_TRANSFER : - evt_cc = trb->transfer.code; - xhci_transfer ( xhci, &trb->transfer ); - break; - - case XHCI_TRB_COMPLETE : - evt_cc = trb->complete.code; - xhci_complete ( xhci, &trb->complete ); - break; - - case XHCI_TRB_PORT_STATUS: - evt_cc = trb->port.code; - xhci_port_status ( xhci, &trb->port ); - break; - - case XHCI_TRB_HOST_CONTROLLER: - evt_cc = trb->host.code; - xhci_host_controller ( xhci, &trb->host ); - break; - - default: - USB_LOG_DBG("XHCI %s unrecognised event type %d, cc %d\n:", - xhci->name, ( evt_type ) ); - break; - } - - /* move ring index, notify xhci */ - nidx++; /* head to next trb */ - if (nidx == XHCI_RING_ITEMS) - { - nidx = 0; /* roll-back if reach end of list */ - cs = cs ? 0 : 1; - evts->cs = cs; /* sw toggle cycle state */ - } - evts->nidx = nidx; - - /* Update dequeue pointer if applicable */ - uint64_t erdp = (uint64_t)(unsigned long)(evts->ring + nidx); - xhci_writeq ( xhci, (uintptr_t)( erdp ) | XHCI_RUN_ERDP_EHB, - xhci->run + XHCI_RUN_ERDP ( 0 ) ); - } - - return work_pipe; -} \ No newline at end of file diff --git a/port/xhci/xhci.h b/port/xhci/xhci.h deleted file mode 100644 index eafd5843..00000000 --- a/port/xhci/xhci.h +++ /dev/null @@ -1,940 +0,0 @@ -/* - * Copyright : (C) 2022 Phytium Information Technology, Inc. - * All Rights Reserved. - * - * This program is OPEN SOURCE software: you can redistribute it and/or modify it - * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, - * either version 1.0 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the Phytium Public License for more details. - * - * - * FilePath: xhci.h - * Date: 2022-07-19 09:26:25 - * LastEditTime: 2022-07-19 09:26:25 - * Description:  This file is for xhci register definition. - * - * Modify History: - * Ver   Who        Date         Changes - * ----- ------     --------    -------------------------------------- - * 1.0 zhugengyu 2022/9/19 init commit - * 2.0 zhugengyu 2023/3/29 support usb3.0 device attached at roothub - */ -#ifndef XHCI_H -#define XHCI_H - -#include "xhci_reg.h" - -#include "usbh_core.h" - -/** @file - * - * USB eXtensible Host Controller Interface (xHCI) driver - * - */ - -#define XHCI_RING_ITEMS 16U -#define XHCI_ALIGMENT 64U -#define XHCI_RING_SIZE (XHCI_RING_ITEMS * sizeof(union xhci_trb)) - -/* - * xhci_ring structs are allocated with XHCI_RING_SIZE alignment, - * then we can get it from a trb pointer (provided by evt ring). - */ -#define XHCI_RING(_trb) \ - ((struct xhci_ring*)((unsigned long)(_trb) & ~(XHCI_RING_SIZE-1))) - -/** Device context base address array */ -struct xhci_dcbaa { - /** Context base addresses */ - uint64_t *context; -}; - -/** Scratchpad buffer */ -struct xhci_scratchpad { - /** Number of page-sized scratchpad buffers */ - unsigned int count; - /** Scratchpad buffer area */ - uintptr_t buffer; - /** Scratchpad array */ - uint64_t *array; -}; - -/** An input control context */ -struct xhci_control_context { - /** Drop context flags */ - uint32_t drop; - /** Add context flags */ - uint32_t add; - /** Reserved */ - uint32_t reserved_a[5]; - /** Configuration value */ - uint8_t config; - /** Interface number */ - uint8_t intf; - /** Alternate setting */ - uint8_t alt; - /** Reserved */ - uint8_t reserved_b; -} __attribute__ (( packed )); - -/** A slot context */ -struct xhci_slot_context { - /** Device info 03-00h */ - uint32_t info; - /** Maximum exit latency */ - uint16_t latency; - /** Root hub port number */ - uint8_t port; - /** Number of downstream ports 07-04h */ - uint8_t ports; - /** TT hub slot ID */ - uint8_t tt_id; - /** TT port number */ - uint8_t tt_port; - /** Interrupter target 0b-08h */ - uint16_t intr; - /** USB address */ - uint8_t address; - /** Reserved */ - uint16_t reserved_a; - /** Slot state 0f-0ch */ - uint8_t state; - /** Reserved */ - uint32_t reserved_b[4]; -} __attribute__ (( packed )); - -/** Construct slot context device info */ -#define XHCI_SLOT_INFO( entries, hub, speed, route ) \ - ( ( (entries) << 27 ) | ( (hub) << 26 ) | ( (speed) << 20 ) | (route) ) - -/** An endpoint context */ -struct xhci_endpoint_context { - /** Endpoint state 03-00h*/ - uint8_t state; - /** Stream configuration */ - uint8_t stream; -#define XHCI_EPCTX_MULT_GET(stream) XHCI32_GET_BITS(stream, 1, 0) -#define XHCI_EPCTX_STREAM_GET(stream) XHCI32_GET_BITS(stream, 6, 2) -#define XHCI_EPCTX_LSA BIT(7) - /** Polling interval */ - uint8_t interval; - /** Max ESIT payload high */ - uint8_t esit_high; - /** Endpoint type 04-04h */ - uint8_t type; -#define XHCI_EPCTX_CERR_GET(type) XHCI32_GET_BITS(type, 2, 1) -#define XHCI_EPCTX_TYPE_GET(type) XHCI32_GET_BITS(type, 5, 3) -#define XHCI_EPCTX_HID BIT(7) - /** Maximum burst size */ - uint8_t burst; - /** Maximum packet size */ - uint16_t mtu; - /** Transfer ring dequeue pointer 0f-08h */ - uint64_t dequeue; -#define XHCI_EPCTX_DCS BIT(0) - /** Average TRB length 13-10h */ - uint16_t trb_len; - /** Max ESIT payload low */ - uint16_t esit_low; - /** Reserved */ - uint32_t reserved[3]; -} __attribute__ (( packed )); - -/** Endpoint states */ -enum { - /** Endpoint is disabled */ - XHCI_ENDPOINT_DISABLED = 0, - /** Endpoint is running */ - XHCI_ENDPOINT_RUNNING = 1, - /** Endpoint is halted due to a USB Halt condition */ - XHCI_ENDPOINT_HALTED = 2, - /** Endpoint is stopped */ - XHCI_ENDPOINT_STOPPED = 3, - /** Endpoint is halted due to a TRB error */ - XHCI_ENDPOINT_ERROR = 4, -}; - -/** Endpoint state mask */ -#define XHCI_ENDPOINT_STATE_MASK 0x07 - -/** Endpoint type */ -#define XHCI_EP_TYPE(type) ( (type) << 3 ) - -/** Control endpoint type */ -#define XHCI_EP_TYPE_CONTROL XHCI_EP_TYPE ( 4 ) - -/** Input endpoint type */ -#define XHCI_EP_TYPE_IN XHCI_EP_TYPE ( 4 ) - -/** Periodic endpoint type */ -#define XHCI_EP_TYPE_PERIODIC XHCI_EP_TYPE ( 1 ) - -/** Endpoint dequeue cycle state */ -#define XHCI_EP_DCS 0x00000001UL - -/** Control endpoint average TRB length */ -#define XHCI_EP0_TRB_LEN 8 - -/** - * Calculate doorbell register value - * - * @v target Doorbell target - * @v stream Doorbell stream ID - * @ret dbval Doorbell register value - */ -#define XHCI_DBVAL( target, stream ) ( (target) | ( (stream) << 16 ) ) - - -/** Slot context index */ -#define XHCI_CTX_SLOT 0 - -/** Calculate context index from USB endpoint address */ -/* refer to spec. Figure 4-4: Endpoint Context Addressing - ep0 = 1, ep1-out = 2, ep1-in = 3, ... ep15-out = 30, ep15-in = 31 */ -#define XHCI_CTX(address) \ - ( (address) ? ( ( ( (address) & 0x0f ) << 1 ) | \ - ( ( (address) & 0x80 ) >> 7 ) ) : 1 ) - -/** Endpoint zero context index */ -#define XHCI_CTX_EP0 XHCI_CTX ( 0x00 ) - -/** End of contexts */ -#define XHCI_CTX_END 32 - -/** Device context index */ -#define XHCI_DCI(ctx) ( (ctx) + 0 ) - -/** Input context index */ -#define XHCI_ICI(ctx) ( (ctx) + 1 ) - -/** Number of TRBs (excluding Link TRB) in the command ring - * - * This is a policy decision. - */ -#define XHCI_CMD_TRBS_LOG2 2 - -/** Number of TRBs in the event ring - * - * This is a policy decision. - */ -#define XHCI_EVENT_TRBS_LOG2 6 - -/** Number of TRBs in a transfer ring - * - * This is a policy decision. - */ -#define XHCI_TRANSFER_TRBS_LOG2 6 - -/** Maximum time to wait for BIOS to release ownership - * - * This is a policy decision. - */ -#define XHCI_USBLEGSUP_MAX_WAIT_MS 100 - -/** Maximum time to wait for host controller to stop - * - * This is a policy decision. - */ -#define XHCI_STOP_MAX_WAIT_MS 100 - -/** Maximum time to wait for reset to complete - * - * This is a policy decision. - */ -#define XHCI_RESET_MAX_WAIT_MS 500 - -/** Maximum time to wait for a command to complete - * - * The "address device" command involves waiting for a response to a - * USB control transaction, and so we must wait for up to the 5000ms - * that USB allows for devices to respond to control transactions. - */ -#define XHCI_COMMAND_MAX_WAIT_MS 5000 - -/** Time to delay after aborting a command - * - * This is a policy decision - */ -#define XHCI_COMMAND_ABORT_DELAY_MS 500 - -/** Maximum time to wait for a port reset to complete - * - * This is a policy decision. - */ -#define XHCI_PORT_RESET_MAX_WAIT_MS 500 - -/** A transfer request block template */ -struct xhci_trb_template { - /** Parameter */ - uint64_t parameter; - /** Status */ - uint32_t status; - /** Control */ - uint32_t control; -}; - -/** A transfer request block */ -struct xhci_trb_common { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved_c; -} __attribute__ (( packed )); - -/** Transfer request block cycle bit flag */ -#define XHCI_TRB_C 0x01 - -/** Transfer request block toggle cycle bit flag */ -#define XHCI_TRB_TC 0x02 - -/** Transfer request block chain flag */ -#define XHCI_TRB_CH 0x10 - -/** Transfer request block interrupt on completion flag */ -#define XHCI_TRB_IOC 0x20 - -/** Transfer request block immediate data flag */ -#define XHCI_TRB_IDT 0x40 - -/** Transfer request block type */ -#define XHCI_TRB_TYPE(type) ( (type) << 2 ) - -/** Transfer request block type mask */ -#define XHCI_TRB_TYPE_MASK XHCI_TRB_TYPE ( 0x3f ) - -/** A normal transfer request block */ -struct xhci_trb_normal { - /** Data buffer */ - uint64_t data; - /** Length */ - uint32_t len; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved; -} __attribute__ (( packed )); - -/** A normal transfer request block */ -#define XHCI_TRB_NORMAL XHCI_TRB_TYPE ( 1 ) - -/** Construct TD size field */ -#define XHCI_TD_SIZE(remaining) \ - ( ( ( (remaining) <= 0xf ) ? remaining : 0xf ) << 17 ) - -/** A setup stage transfer request block */ -struct xhci_trb_setup { - /** Setup packet, 04-00h sw will copy request content to this field */ - struct usb_setup_packet packet; - /** Length 08h */ - uint32_t len; - /** Flags 0ch */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Transfer direction */ - uint8_t direction; - /** Reserved */ - uint8_t reserved; -} __attribute__ (( packed )); - -/** A setup stage transfer request block */ -#define XHCI_TRB_SETUP XHCI_TRB_TYPE ( 2 ) - -/** Setup stage input data direction */ -#define XHCI_SETUP_IN 3 - -/** Setup stage output data direction */ -#define XHCI_SETUP_OUT 2 - -/** A data stage transfer request block */ -struct xhci_trb_data { - /** Data buffer */ - uint64_t data; - /** Length */ - uint32_t len; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Transfer direction */ - uint8_t direction; - /** Reserved */ - uint8_t reserved; -} __attribute__ (( packed )); - -/** A data stage transfer request block */ -#define XHCI_TRB_DATA XHCI_TRB_TYPE ( 3 ) - -/** Input data direction */ -#define XHCI_DATA_IN 0x01 - -/** Output data direction */ -#define XHCI_DATA_OUT 0x00 - -/** A status stage transfer request block */ -struct xhci_trb_status { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Direction */ - uint8_t direction; - /** Reserved */ - uint8_t reserved_c; -} __attribute__ (( packed )); - -/** A status stage transfer request block */ -#define XHCI_TRB_STATUS XHCI_TRB_TYPE ( 4 ) - -/** Input status direction */ -#define XHCI_STATUS_IN 0x01 - -/** Output status direction */ -#define XHCI_STATUS_OUT 0x00 - -/** A link transfer request block */ -struct xhci_trb_link { - /** Next ring segment */ - uint64_t next; - /** Reserved */ - uint32_t reserved_a; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved_c; -} __attribute__ (( packed )); - -/** A link transfer request block */ -#define XHCI_TRB_LINK XHCI_TRB_TYPE ( 6 ) - -/** A no-op transfer request block */ -#define XHCI_TRB_NOP XHCI_TRB_TYPE ( 8 ) - -/** An enable slot transfer request block */ -struct xhci_trb_enable_slot { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Slot type */ - uint8_t slot; - /** Reserved */ - uint8_t reserved_c; -} __attribute__ (( packed )); - -/** An enable slot transfer request block */ -#define XHCI_TRB_ENABLE_SLOT XHCI_TRB_TYPE ( 9 ) - -/** A disable slot transfer request block */ -struct xhci_trb_disable_slot { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint8_t reserved_c; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A disable slot transfer request block */ -#define XHCI_TRB_DISABLE_SLOT XHCI_TRB_TYPE ( 10 ) - -/** A context transfer request block */ -struct xhci_trb_context { - /** Input context */ - uint64_t input; - /** Reserved */ - uint32_t reserved_a; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint8_t reserved_b; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** An address device transfer request block */ -#define XHCI_TRB_ADDRESS_DEVICE XHCI_TRB_TYPE ( 11 ) - -/** A configure endpoint transfer request block */ -#define XHCI_TRB_CONFIGURE_ENDPOINT XHCI_TRB_TYPE ( 12 ) - -/** An evaluate context transfer request block */ -#define XHCI_TRB_EVALUATE_CONTEXT XHCI_TRB_TYPE ( 13 ) - -/** A reset endpoint transfer request block */ -struct xhci_trb_reset_endpoint { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Endpoint ID */ - uint8_t endpoint; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A reset endpoint transfer request block */ -#define XHCI_TRB_RESET_ENDPOINT XHCI_TRB_TYPE ( 14 ) - -/** A stop endpoint transfer request block */ -struct xhci_trb_stop_endpoint { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint32_t reserved_b; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Endpoint ID */ - uint8_t endpoint; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A stop endpoint transfer request block */ -#define XHCI_TRB_STOP_ENDPOINT XHCI_TRB_TYPE ( 15 ) - -/** A set transfer ring dequeue pointer transfer request block */ -struct xhci_trb_set_tr_dequeue_pointer { - /** Dequeue pointer */ - uint64_t dequeue; - /** Reserved */ - uint32_t reserved; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Endpoint ID */ - uint8_t endpoint; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A set transfer ring dequeue pointer transfer request block */ -#define XHCI_TRB_SET_TR_DEQUEUE_POINTER XHCI_TRB_TYPE ( 16 ) - -/** A no-op command transfer request block */ -#define XHCI_TRB_NOP_CMD XHCI_TRB_TYPE ( 23 ) - -/** A transfer event transfer request block */ -struct xhci_trb_transfer { - /** Transfer TRB pointer */ - uint64_t transfer; - /** Residual transfer length */ - uint16_t residual; - /** Reserved */ - uint8_t reserved; - /** Completion code */ - uint8_t code; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Endpoint ID */ - uint8_t endpoint; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A transfer event transfer request block */ -#define XHCI_TRB_TRANSFER XHCI_TRB_TYPE ( 32 ) - -/** A command completion event transfer request block */ -struct xhci_trb_complete { - /** Command TRB pointer */ - uint64_t command; - /** Parameter */ - uint8_t parameter[3]; - /** Completion code */ - uint8_t code; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Virtual function ID */ - uint8_t vf; - /** Slot ID */ - uint8_t slot; -} __attribute__ (( packed )); - -/** A command completion event transfer request block */ -#define XHCI_TRB_COMPLETE XHCI_TRB_TYPE ( 33 ) - -/** xHCI completion codes */ -enum xhci_completion_code { - /** Timeout */ - XHCI_CMPLT_TIMEOUT = -1, - /** Success */ - XHCI_CMPLT_SUCCESS = 1, - /** Stall Error */ - XHCI_CMPLT_STALL = 6, - /** Bandwidth Error */ - XHCI_CMPLT_BANDWIDTH = 8, - /** Endpoint Not Enabled Error */ - XHCI_CMPLT_ENDPOINT_NOT_ENABLED = 12, - /** Short packet */ - XHCI_CMPLT_SHORT = 13, - /** Parameter Error */ - XHCI_CMPLT_PARAMETER = 17, - /** Command ring stopped */ - XHCI_CMPLT_CMD_STOPPED = 24, -}; - -/** A port status change transfer request block */ -struct xhci_trb_port_status { - /** Reserved */ - uint8_t reserved_a[3]; - /** Port ID */ - uint8_t port; - /** Reserved */ - uint8_t reserved_b[7]; - /** Completion code */ - uint8_t code; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved_c; -} __attribute__ (( packed )); - -/** A port status change transfer request block */ -#define XHCI_TRB_PORT_STATUS XHCI_TRB_TYPE ( 34 ) - -/** A port status change transfer request block */ -struct xhci_trb_host_controller { - /** Reserved */ - uint64_t reserved_a; - /** Reserved */ - uint8_t reserved_b[3]; - /** Completion code */ - uint8_t code; - /** Flags */ - uint8_t flags; - /** Type */ - uint8_t type; - /** Reserved */ - uint16_t reserved_c; -} __attribute__ (( packed )); - -/** A port status change transfer request block */ -#define XHCI_TRB_HOST_CONTROLLER XHCI_TRB_TYPE ( 37 ) - -/** A transfer request block */ -union xhci_trb { - /** Template */ - struct xhci_trb_template template; - /** Common fields */ - struct xhci_trb_common common; - /** Normal TRB */ - struct xhci_trb_normal normal; - /** Setup stage TRB */ - struct xhci_trb_setup setup; - /** Data stage TRB */ - struct xhci_trb_data data; - /** Status stage TRB */ - struct xhci_trb_status status; - /** Link TRB */ - struct xhci_trb_link link; - /** Enable slot TRB */ - struct xhci_trb_enable_slot enable; - /** Disable slot TRB */ - struct xhci_trb_disable_slot disable; - /** Input context TRB */ - struct xhci_trb_context context; - /** Reset endpoint TRB */ - struct xhci_trb_reset_endpoint reset; - /** Stop endpoint TRB */ - struct xhci_trb_stop_endpoint stop; - /** Set transfer ring dequeue pointer TRB */ - struct xhci_trb_set_tr_dequeue_pointer dequeue; - /** Transfer event */ - struct xhci_trb_transfer transfer; - /** Command completion event */ - struct xhci_trb_complete complete; - /** Port status changed event */ - struct xhci_trb_port_status port; - /** Host controller event */ - struct xhci_trb_host_controller host; -} __attribute__ (( packed )); - -struct xhci_ring { - union xhci_trb ring[XHCI_RING_ITEMS]; - union xhci_trb evt; - uint32_t eidx; - uint32_t nidx; - uint32_t cs; - usb_osal_mutex_t lock; -}; - -/** An event ring segment */ -struct xhci_er_seg { - /** Base address */ - uint64_t base; - /** Number of TRBs */ - uint32_t count; - /** Reserved */ - uint32_t reserved; -} __attribute__ (( packed )); - -/** An xHCI endpoint */ -struct xhci_endpoint { - struct xhci_ring reqs; /* DO NOT MOVE reqs from structure beg */ - /** xHCI device */ - struct xhci_host *xhci; - /** xHCI slot */ - struct xhci_slot *slot; - /** Endpoint address */ - unsigned int address; - /** Context index */ - unsigned int ctx; - /** Endpoint type in USB definition */ - unsigned int ep_type; - /** Endpoint type in XHCI Endpoint context definition */ - unsigned int ctx_type; - - /** Maximum transfer size (Maximum packet size) */ - unsigned int mtu; - /** Maximum burst size */ - unsigned int burst; - /** Endpoint interval */ - unsigned int interval; - - /** Endpoint context */ - struct xhci_endpoint_context *context; - - /* command or transfer waiter */ - int timeout; /* = 0 no need to wait */ - bool waiter; - usb_osal_sem_t waitsem; - - /* handle urb */ - struct usbh_hubport *hport; - struct usbh_urb *urb; /* NULL if no active URB */ -}; - -/** An xHCI device slot */ -struct xhci_slot { - /** xHCI device */ - struct xhci_host *xhci; - /** Slot ID */ - unsigned int id; - /** Slot context */ - struct xhci_slot_context *context; - - /** Route string */ - unsigned int route; - /** Root hub port number */ - unsigned int port; - /** Protocol speed ID */ - unsigned int psiv; - /** Number of ports (if this device is a hub) */ - unsigned int ports; - /** Transaction translator slot ID */ - unsigned int tt_id; - /** Transaction translator port */ - unsigned int tt_port; - - /** Endpoints, indexed by context ID */ - struct xhci_endpoint *endpoint[XHCI_CTX_END]; -}; - -/** An xHCI device */ -struct xhci_host { - /** ID */ - uint32_t id; - /** Name */ - char name[4]; - - /* xhci registers base addr */ - /** Registers base */ - void *base; - /** Capability registers */ - void *cap; - /** Operational registers */ - void *op; - /** Runtime registers */ - void *run; - /** Doorbell registers */ - void *db; - /** extended capability */ - unsigned int xecp; - /** capability cache */ - uint32_t hcs[3]; - uint32_t hcc; - /** xhci version */ - uint16_t version; - - /** Number of device slots */ - unsigned int slots; - /** Number of interrupters */ - unsigned int intrs; - /** Number of ports */ - unsigned int ports; - - /** 64-bit addressing capability */ - int addr64; - /** Context size shift */ - unsigned int csz_shift; - /** Page size */ - size_t pagesize; - - /** USB legacy support capability (if present and enabled) */ - unsigned int legacy; - - /** Device context base address array */ - struct xhci_dcbaa dcbaa; - - /** Scratchpad buffer */ - struct xhci_scratchpad scratch; - - /** Device slots, indexed by slot ID */ - struct xhci_slot **slot; - - /** Command ring */ - struct xhci_ring *cmds; - /** Event ring */ - struct xhci_ring *evts; - struct xhci_er_seg *eseg; - - struct xhci_endpoint *cur_cmd_pipe; -}; - -/** - * Calculate input context offset - * - * @v xhci xHCI device - * @v ctx Context index - */ -static inline size_t xhci_input_context_offset ( struct xhci_host *xhci, - unsigned int ctx ) { - - return ( XHCI_ICI ( ctx ) << xhci->csz_shift ); -} - -/** - * Calculate device context offset - * - * @v xhci xHCI device - * @v ctx Context index - */ -static inline size_t xhci_device_context_offset ( struct xhci_host *xhci, - unsigned int ctx ) { - - return ( XHCI_DCI ( ctx ) << xhci->csz_shift ); -} - -/* Probe XCHI device */ -int xhci_probe ( struct xhci_host *xhci, unsigned long baseaddr ); - -/* Open XHCI device and start running */ -int xhci_open ( struct xhci_host *xhci ); - -/* Close XHCI device and stop running */ -void xhci_close ( struct xhci_host *xhci ); - -/* Remove XHCI device and free allocated memory */ -void xhci_remove ( struct xhci_host *xhci ); - -/* Enable port */ -int xhci_port_enable (struct xhci_host *xhci, uint32_t port); - -/* Get port speed */ -uint32_t xhci_root_speed ( struct xhci_host *xhci, uint8_t port ); - -/* Open and enable device */ -int xhci_device_open ( struct xhci_host *xhci, struct xhci_endpoint *pipe, int *slot_id ); - -/* Assign device address */ -int xhci_device_address ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *pipe ); - -/* Close device and free allocated memory */ -void xhci_device_close ( struct xhci_slot *slot ); - -/* Open control endpoint for slot */ -int xhci_ctrl_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *pipe ); - -/* Open work endpoint for slot */ -int xhci_work_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *pipe ); - -/* Close endpoint and free allocated memory */ -void xhci_endpoint_close ( struct xhci_endpoint *ep ); - -/* Update MTU (Max packet size) of endpoint */ -int xhci_endpoint_mtu ( struct xhci_endpoint *ep ); - -/* Enqueue message transfer, usually for control transfer */ -void xhci_endpoint_message ( struct xhci_endpoint *ep, struct usb_setup_packet *packet, - void *data_buff, int datalen ); - -/* Enqueue stream transfer, usually for bulk/interrupt transfer */ -void xhci_endpoint_stream ( struct xhci_endpoint *ep, void *data_buff, int datalen ); - -/* Process event ring in interrupt */ -struct xhci_endpoint *xhci_event_process(struct xhci_host *xhci); - -/* Wait for a ring to empty (all TRBs processed by hardware) */ -int xhci_event_wait(struct xhci_host *xhci, - struct xhci_endpoint *pipe, - struct xhci_ring *ring); - -/* Dump host controller registers */ -void xhci_dump(struct xhci_host *xhci); - -/* Dump port registers */ -void xhci_dump_port ( struct xhci_host *xhci, - unsigned int port ); - -/* Dump Port status */ -void xhci_dump_port_status(uint32_t port, uint32_t portsc); - -/* Dump input context */ -void xhci_dump_input_ctx( struct xhci_host *xhci, const struct xhci_endpoint *endpoint, const void *input); - -/* Dump Endpoint */ -void xhci_dump_endpoint(const struct xhci_endpoint *ep); - -/* Dump endpoint context */ -void xhci_dump_ep_ctx(const struct xhci_endpoint_context *ep); - -/* Dump TRB */ -void xhci_dump_trbs(const union xhci_trb *trbs, unsigned int count); - -/* Dump slot context */ -void xhci_dump_slot_ctx(const struct xhci_slot_context *const sc); - -#endif /* XHCI_H */ \ No newline at end of file diff --git a/port/xhci/xhci_dbg.c b/port/xhci/xhci_dbg.c deleted file mode 100644 index 61ca296f..00000000 --- a/port/xhci/xhci_dbg.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright : (C) 2022 Phytium Information Technology, Inc. - * All Rights Reserved. - * - * This program is OPEN SOURCE software: you can redistribute it and/or modify it - * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, - * either version 1.0 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the Phytium Public License for more details. - * - * - * FilePath: xhci_dbg.c - * Date: 2022-07-19 09:26:25 - * LastEditTime: 2022-07-19 09:26:25 - * Description:  This file is for implment xhci debug functions - * - * Modify History: - * Ver   Who        Date         Changes - * ----- ------     --------    -------------------------------------- - * 1.0 zhugengyu 2022/9/19 init commit - * 2.0 zhugengyu 2023/3/29 support usb3.0 device attached at roothub - */ -#include -#include -#include -#include -#include - -#include "usbh_core.h" - -#include "xhci.h" - -/* macro to enable dump */ -#define XHCI_DUMP 1 -#define XHCI_DUMP_PORT 1 -#define XHCI_DUMP_TRB 0 -#define XHCI_DUMP_SLOT 0 -#define XHCI_DUMP_EP_CTX 0 -#define XHCI_DUMP_INPUT_CTX 0 -#define XHCI_DUMP_ENDPOINT 0 -#define XHCI_DUMP_PORT_STATUS 0 - -/** - * Dump host controller registers - * - * @v xhci xHCI device - */ -void xhci_dump(struct xhci_host *xhci) { -#if XHCI_DUMP - uint32_t usbcmd; - uint32_t usbsts; - uint32_t pagesize; - uint32_t dnctrl; - uint32_t config; - - /* Dump USBCMD */ - usbcmd = readl ( xhci->op + XHCI_OP_USBCMD ); - USB_LOG_DBG ( "XHCI %s USBCMD %08x%s%s\n", xhci->name, usbcmd, - ( ( usbcmd & XHCI_USBCMD_RUN ) ? " run" : "" ), - ( ( usbcmd & XHCI_USBCMD_HCRST ) ? " hcrst" : "" ) ); - - /* Dump USBSTS */ - usbsts = readl ( xhci->op + XHCI_OP_USBSTS ); - USB_LOG_DBG ( "XHCI %s USBSTS %08x%s\n", xhci->name, usbsts, - ( ( usbsts & XHCI_USBSTS_HCH ) ? " hch" : "" ) ); - - /* Dump PAGESIZE */ - pagesize = readl ( xhci->op + XHCI_OP_PAGESIZE ); - USB_LOG_DBG ( "XHCI %s PAGESIZE %08x\n", xhci->name, pagesize ); - - /* Dump DNCTRL */ - dnctrl = readl ( xhci->op + XHCI_OP_DNCTRL ); - USB_LOG_DBG ( "XHCI %s DNCTRL %08x\n", xhci->name, dnctrl ); - - /* Dump CONFIG */ - config = readl ( xhci->op + XHCI_OP_CONFIG ); - USB_LOG_DBG ( "XHCI %s CONFIG %08x\n", xhci->name, config ); -#endif -} - -/** - * Dump port registers - * - * @v xhci xHCI device - * @v port Port number - */ -void xhci_dump_port ( struct xhci_host *xhci, - unsigned int port ) { -#if XHCI_DUMP_PORT - uint32_t portsc; - uint32_t portpmsc; - uint32_t portli; - uint32_t porthlpmc; - - /* Dump PORTSC */ - portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) ); - USB_LOG_DBG ( "XHCI %s-%d PORTSC %08x%s%s%s%s psiv=%d\n", - xhci->name, port, portsc, - ( ( portsc & XHCI_PORTSC_CCS ) ? " ccs" : "" ), - ( ( portsc & XHCI_PORTSC_PED ) ? " ped" : "" ), - ( ( portsc & XHCI_PORTSC_PR ) ? " pr" : "" ), - ( ( portsc & XHCI_PORTSC_PP ) ? " pp" : "" ), - XHCI_PORTSC_PSIV ( portsc ) ); - - /* Dump PORTPMSC */ - portpmsc = readl ( xhci->op + XHCI_OP_PORTPMSC ( port ) ); - USB_LOG_DBG ( "XHCI %s-%d PORTPMSC %08x\n", xhci->name, port, portpmsc ); - - /* Dump PORTLI */ - portli = readl ( xhci->op + XHCI_OP_PORTLI ( port ) ); - USB_LOG_DBG ( "XHCI %s-%d PORTLI %08x\n", xhci->name, port, portli ); - - /* Dump PORTHLPMC */ - porthlpmc = readl ( xhci->op + XHCI_OP_PORTHLPMC ( port ) ); - USB_LOG_DBG ( "XHCI %s-%d PORTHLPMC %08x\n", - xhci->name, port, porthlpmc ); -#endif -} - -/** - * Dump slot context - * - * @v sc Slot context - */ -void xhci_dump_slot_ctx(const struct xhci_slot_context *const sc) { -#if XHCI_DUMP_SLOT - const uint8_t *ctx = (uint8_t *)sc; - - USB_LOG_DBG("===== slot ctx ===== \r\n"); - USB_LOG_DBG("ctx[0]=0x%x\n", *((uint32_t*)ctx)); - USB_LOG_DBG(" info: 0x%x \r\n", sc->info); - USB_LOG_DBG("ctx[1]=0x%x\n", *((uint32_t*)ctx + 1)); - USB_LOG_DBG(" latency: 0x%x \r\n", sc->latency); - USB_LOG_DBG(" port: 0x%x \r\n", sc->port); - USB_LOG_DBG(" ports: 0x%x \r\n", sc->ports); - USB_LOG_DBG("ctx[2]=0x%x\n", *((uint32_t*)ctx + 2)); - USB_LOG_DBG(" tt_id: 0x%x \r\n", sc->tt_id); - USB_LOG_DBG(" tt_port: 0x%x \r\n", sc->tt_port); - USB_LOG_DBG("ctx[3]=0x%x\n", *((uint32_t*)ctx + 3)); - USB_LOG_DBG(" intr: 0x%x \r\n", sc->intr); - USB_LOG_DBG(" address: 0x%x \r\n", sc->address); - USB_LOG_DBG(" state: 0x%x \r\n", sc->state); - USB_LOG_DBG("=====+++++++++===== \r\n"); -#endif -} - -/** - * Dump endpoint context - * - * @v ep Endpoint context - */ -void xhci_dump_ep_ctx(const struct xhci_endpoint_context *ep) { -#if XHCI_DUMP_EP_CTX - const uint8_t *ctx = (uint8_t *)ep; - - USB_LOG_DBG("===== ep ctx ===== \r\n"); - USB_LOG_DBG("ctx[0]=0x%x\n", *((uint32_t*)ctx)); - USB_LOG_DBG(" ep_state: 0x%x \r\n", ep->state); - USB_LOG_DBG(" mult: 0x%x \r\n", XHCI_EPCTX_MULT_GET(ep->stream)); - USB_LOG_DBG(" stream: 0x%x \r\n", XHCI_EPCTX_STREAM_GET(ep->stream)); - USB_LOG_DBG(" lsa: 0x%x \r\n", !!(XHCI_EPCTX_LSA & (ep->stream))); - USB_LOG_DBG(" interval: 0x%x \r\n", ep->interval); - USB_LOG_DBG(" esit_high: 0x%x \r\n", ep->esit_high); - USB_LOG_DBG("ctx[1]=0x%x\n", *((uint32_t*)ctx + 1)); - USB_LOG_DBG(" cerr: 0x%x \r\n", XHCI_EPCTX_CERR_GET(ep->type)); - USB_LOG_DBG(" type: 0x%x \r\n", XHCI_EPCTX_TYPE_GET(ep->type)); - USB_LOG_DBG(" hid: 0x%x \r\n", !!(XHCI_EPCTX_HID & (ep->type))); - USB_LOG_DBG(" burst: 0x%x \r\n", ep->burst); - USB_LOG_DBG(" mtu: 0x%x \r\n", ep->mtu); - USB_LOG_DBG("ctx[2]=0x%x\n", *((uint32_t*)ctx + 2)); - USB_LOG_DBG("ctx[3]=0x%x\n", *((uint32_t*)ctx + 3)); - USB_LOG_DBG(" dequeue: 0x%lx \r\n", ep->dequeue); - USB_LOG_DBG(" dcs: 0x%lx \r\n", !!(XHCI_EPCTX_DCS & ep->dequeue)); - USB_LOG_DBG("ctx[4]=0x%x\n", *((uint32_t*)ctx + 4)); - USB_LOG_DBG(" trb_len: 0x%x \r\n", ep->trb_len); - USB_LOG_DBG(" esit_low: 0x%x \r\n", ep->esit_low); - USB_LOG_DBG("=====+++++++++===== \r\n"); -#endif -} - -/** - * Dump input context - * - * @v xhci XHCI device - * @v endpoint Endpoint - * @v input Input context - */ -void xhci_dump_input_ctx( struct xhci_host *xhci, const struct xhci_endpoint *endpoint, const void *input) { -#if XHCI_DUMP_INPUT_CTX - const struct xhci_control_context *control_ctx; - const struct xhci_slot_context *slot_ctx; - const struct xhci_endpoint_context *ep_ctx; - - control_ctx = input; - slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT )); - ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) ); - - USB_LOG_DBG("===input ctx====\n"); - USB_LOG_DBG("ctrl@%p=0x%x\n", control_ctx, *control_ctx); - USB_LOG_DBG("add=0x%x\n", control_ctx->add); - USB_LOG_DBG("del=0x%x\n", control_ctx->drop); - - USB_LOG_DBG("slot@%p\n", slot_ctx); - xhci_dump_slot_ctx(slot_ctx); - - USB_LOG_DBG("ep-%d@%p\n", endpoint->ctx, ep_ctx); - xhci_dump_ep_ctx(ep_ctx); - - USB_LOG_DBG("=====+++++++++===== \r\n"); -#endif -} - -/** - * Get next TRB in ring - * - * @v trbs TRB in ring - * @v trb Next TRB - */ -static const union xhci_trb * xhci_get_next_trb(const union xhci_trb *trbs) { - const struct xhci_trb_link *link = &(trbs->link); - if (link->type == XHCI_TRB_LINK) { - return (link->next) ? (const union xhci_trb *)(link->next) : NULL; - } else { - return trbs + 1; - } -} - -/** - * Dump TRB - * - * @v trbs TRB header - * @v count Number of TRB to dump - */ -void xhci_dump_trbs(const union xhci_trb *trbs, unsigned int count) { -#if XHCI_DUMP_TRB - const union xhci_trb *cur; - const struct xhci_trb_common *comm; - const uint8_t *dword; - - USB_LOG_DBG("===trbs ====\n"); - for (unsigned int i = 0; i < count; i++) { - cur = &(trbs[i]); - dword = (const uint8_t *)cur; - - comm = &(cur->common); - USB_LOG_DBG("[0x%x-0x%x-0x%x-0x%x]\n", - *((uint32_t *)dword), *((uint32_t *)dword + 1), - *((uint32_t *)dword + 2), *((uint32_t *)dword + 3)); - if (XHCI_TRB_SETUP == comm->type) { - const struct xhci_trb_setup *setup = (const struct xhci_trb_setup *)comm; - - USB_LOG_DBG("setup trb\n"); - USB_LOG_DBG(" packet=0x%x\n", setup->packet); - USB_LOG_DBG(" bmRequestType type=0x%x\n", setup->packet.bmRequestType); - USB_LOG_DBG(" bRequest=0x%x\n", setup->packet.bRequest); - USB_LOG_DBG(" wValue=0x%x\n", setup->packet.wValue); - USB_LOG_DBG(" wIndex=0x%x\n", setup->packet.wIndex); - USB_LOG_DBG(" wLength=0x%x\n", setup->packet.wLength); - USB_LOG_DBG(" trb_trans_len=%d\n", setup->len); - USB_LOG_DBG(" flags=0x%x\n", setup->flags); - USB_LOG_DBG(" direction=%d\n", setup->direction); - } else if (XHCI_TRB_DATA == comm->type) { - const struct xhci_trb_data *data = (const struct xhci_trb_data *)comm; - - USB_LOG_DBG("data trb......\n"); - USB_LOG_DBG(" data=0x%x\n", data->data); - USB_LOG_DBG(" len=%d\n", data->len); - USB_LOG_DBG(" direction=%d\n", data->direction); - } else if (XHCI_TRB_STATUS == comm->type) { - const struct xhci_trb_status *status = (const struct xhci_trb_status *)comm; - - USB_LOG_DBG("status trb......\n"); - USB_LOG_DBG(" direction=%d\n", status->direction); - } - } - USB_LOG_DBG("=====+++++++++===== \r\n"); -#endif -} - -static const char *xhci_endpoint_xhci_type (unsigned int ep_xhci_type) { - static const char *ep_names[] = {"not_valid", "isoc_out", "bulk_out", - "intr_out", "ctrl", "isoc_in", - "bulk_in", "intr_in"}; - unsigned int index = ep_xhci_type >> 3; - if (index < sizeof(ep_names)/sizeof(ep_names[0])) { - return ep_names[index]; - } - - return "unkown"; -} - -static const char *xhci_endpoint_type (unsigned int ep_type) { - const char *ep_name = "unkown"; - - switch (ep_type) - { - case USB_ENDPOINT_TYPE_CONTROL: - ep_name = "ctrl-ep"; - break; - case USB_ENDPOINT_TYPE_ISOCHRONOUS: - ep_name = "isoc-ep"; - break; - case USB_ENDPOINT_TYPE_BULK: - ep_name = "bulk-ep"; - break; - case USB_ENDPOINT_TYPE_INTERRUPT: - ep_name = "intr-ep"; - break; - default: - break; - } - - return ep_name; -} - -/** - * Dump Endpoint - * - * @v ep Endpoint - */ -void xhci_dump_endpoint(const struct xhci_endpoint *ep) { -#if XHCI_DUMP_ENDPOINT - USB_LOG_DBG("===endpoint====\n"); - USB_LOG_DBG("xhci=0x%x\n", ep->xhci); - USB_LOG_DBG("slot=0x%x\n", ep->slot); - USB_LOG_DBG("address=0x%x\n", ep->address); - USB_LOG_DBG("mtu=0x%x\n", ep->mtu); - USB_LOG_DBG("burst=0x%x\n", ep->burst); - USB_LOG_DBG("ctx=0x%x\n", ep->ctx); - USB_LOG_DBG("ep_type=%s\n", xhci_endpoint_type(ep->ep_type)); - USB_LOG_DBG("xhci_type=%s\n", xhci_endpoint_xhci_type(ep->ctx_type)); - USB_LOG_DBG("interval=0x%x\n", ep->interval); - USB_LOG_DBG("=====+++++++++===== \r\n"); -#endif -} - -/** - * Dump Port status - * - * @v port Port number - * @v portsc Port status - */ -void xhci_dump_port_status(uint32_t port, uint32_t portsc) { -#if XHCI_DUMP_PORT_STATUS - USB_LOG_DBG("====port-%d====\n"); - USB_LOG_DBG("connect=%d \n", !!(XHCI_PORTSC_CCS & port)); - USB_LOG_DBG("enabled=%d \n", !!(XHCI_PORTSC_PED & port)); - USB_LOG_DBG("powered=%d \n", !!(XHCI_PORTSC_PP & port)); - USB_LOG_DBG("=====+++++++++===== \r\n"); -#endif -} \ No newline at end of file diff --git a/port/xhci/xhci_reg.h b/port/xhci/xhci_reg.h deleted file mode 100644 index a981daa6..00000000 --- a/port/xhci/xhci_reg.h +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright : (C) 2022 Phytium Information Technology, Inc. - * All Rights Reserved. - * - * This program is OPEN SOURCE software: you can redistribute it and/or modify it - * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, - * either version 1.0 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the Phytium Public License for more details. - * - * - * FilePath: xhci_reg.h - * Date: 2022-07-19 09:26:25 - * LastEditTime: 2022-07-19 09:26:25 - * Description:  This file is for xhci register definition. - * - * Modify History: - * Ver   Who        Date         Changes - * ----- ------     --------    -------------------------------------- - * 1.0 zhugengyu 2022/9/19 init commit - * 2.0 zhugengyu 2023/3/29 support usb3.0 device attached at roothub - */ - -#ifndef XHCI_REG_H -#define XHCI_REG_H - -#if defined(__aarch64__) -#define BITS_PER_LONG 64U -#define XHCI_AARCH64 -#else -#define BITS_PER_LONG 32U -#define XHCI_AARCH32 -#endif - -#define XHCI_GENMASK(h, l) \ - (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) - -#define XHCI_GENMASK_ULL(h, l) \ - (((~0ULL) - (1ULL << (l)) + 1) & \ - (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) - -#define XHCI32_GET_BITS(x, a, b) (uint32_t)((((uint32_t)(x)) & XHCI_GENMASK(a, b)) >> b) -#define XHCI32_SET_BITS(x, a, b) (uint32_t)((((uint32_t)(x)) << b) & XHCI_GENMASK(a, b)) -#define XHCI64_GET_BITS(x, a, b) (uint64_t)((((uint64_t)(x)) & XHCI_GENMASK_ULL(a, b)) >> b) -#define XHCI64_SET_BITS(x, a, b) (uint64_t)((((uint64_t)(x)) << b) & XHCI_GENMASK_ULL(a, b)) - -/** Capability register length */ -#define XHCI_CAP_CAPLENGTH 0x00 - -/** Host controller interface version number */ -#define XHCI_CAP_HCIVERSION 0x02 - -/** Structural parameters 1 */ -#define XHCI_CAP_HCSPARAMS1 0x04 - -/** Number of device slots */ -#define XHCI_HCSPARAMS1_SLOTS(params) ( ( (params) >> 0 ) & 0xff ) - -/** Number of interrupters */ -#define XHCI_HCSPARAMS1_INTRS(params) ( ( (params) >> 8 ) & 0x3ff ) - -/** Number of ports */ -#define XHCI_HCSPARAMS1_PORTS(params) ( ( (params) >> 24 ) & 0xff ) - -/** Structural parameters 2 */ -#define XHCI_CAP_HCSPARAMS2 0x08 - -/** Number of page-sized scratchpad buffers */ -#define XHCI_HCSPARAMS2_SCRATCHPADS(params) \ - ( ( ( (params) >> 16 ) & 0x3e0 ) | ( ( (params) >> 27 ) & 0x1f ) ) - -/** Capability parameters */ -#define XHCI_CAP_HCCPARAMS1 0x10 - -/** 64-bit addressing capability */ -#define XHCI_HCCPARAMS1_ADDR64(params) ( ( (params) >> 0 ) & 0x1 ) - -/** Context size shift */ -#define XHCI_HCCPARAMS1_CSZ_SHIFT(params) ( 5 + ( ( (params) >> 2 ) & 0x1 ) ) - -/** xHCI extended capabilities pointer */ -#define XHCI_HCCPARAMS1_XECP(params) ( ( ( (params) >> 16 ) & 0xffff ) << 2 ) - -/** Doorbell offset */ -#define XHCI_CAP_DBOFF 0x14 - -/** Runtime register space offset */ -#define XHCI_CAP_RTSOFF 0x18 - -/** xHCI extended capability ID */ -#define XHCI_XECP_ID(xecp) ( ( (xecp) >> 0 ) & 0xff ) - -/** Next xHCI extended capability pointer */ -#define XHCI_XECP_NEXT(xecp) ( ( ( (xecp) >> 8 ) & 0xff ) << 2 ) - -/** USB legacy support extended capability */ -#define XHCI_XECP_ID_LEGACY 1 - -/** USB legacy support BIOS owned semaphore */ -#define XHCI_USBLEGSUP_BIOS 0x02 - -/** USB legacy support BIOS ownership flag */ -#define XHCI_USBLEGSUP_BIOS_OWNED 0x01 - -/** USB legacy support OS owned semaphore */ -#define XHCI_USBLEGSUP_OS 0x03 - -/** USB legacy support OS ownership flag */ -#define XHCI_USBLEGSUP_OS_OWNED 0x01 - -/** USB legacy support control/status */ -#define XHCI_USBLEGSUP_CTLSTS 0x04 - -/** Supported protocol extended capability */ -#define XHCI_XECP_ID_SUPPORTED 2 - -/** Supported protocol revision */ -#define XHCI_SUPPORTED_REVISION 0x00 - -/** Supported protocol minor revision */ -#define XHCI_SUPPORTED_REVISION_VER(revision) ( ( (revision) >> 16 ) & 0xffff ) - -/** Supported protocol name */ -#define XHCI_SUPPORTED_NAME 0x04 - -/** Supported protocol ports */ -#define XHCI_SUPPORTED_PORTS 0x08 - -/** Supported protocol port offset */ -#define XHCI_SUPPORTED_PORTS_OFFSET(ports) ( ( (ports) >> 0 ) & 0xff ) - -/** Supported protocol port count */ -#define XHCI_SUPPORTED_PORTS_COUNT(ports) ( ( (ports) >> 8 ) & 0xff ) - -/** Supported protocol PSI count */ -#define XHCI_SUPPORTED_PORTS_PSIC(ports) ( ( (ports) >> 28 ) & 0x0f ) - -/** Supported protocol slot */ -#define XHCI_SUPPORTED_SLOT 0x0c - -/** Supported protocol slot type */ -#define XHCI_SUPPORTED_SLOT_TYPE(slot) ( ( (slot) >> 0 ) & 0x1f ) - -/** Supported protocol PSI */ -#define XHCI_SUPPORTED_PSI(index) ( 0x10 + ( (index) * 4 ) ) - -/** Supported protocol PSI value */ -#define XHCI_SUPPORTED_PSI_VALUE(psi) ( ( (psi) >> 0 ) & 0x0f ) - -/** Supported protocol PSI mantissa */ -#define XHCI_SUPPORTED_PSI_MANTISSA(psi) ( ( (psi) >> 16 ) & 0xffff ) - -/** Supported protocol PSI exponent */ -#define XHCI_SUPPORTED_PSI_EXPONENT(psi) ( ( (psi) >> 4 ) & 0x03 ) - -/** Default PSI values */ -enum { - /** Full speed (12Mbps) */ - XHCI_SPEED_FULL = 1, - /** Low speed (1.5Mbps) */ - XHCI_SPEED_LOW = 2, - /** High speed (480Mbps) */ - XHCI_SPEED_HIGH = 3, - /** Super speed */ - XHCI_SPEED_SUPER = 4, -}; - -/** USB command register */ -#define XHCI_OP_USBCMD 0x00 - -/** Run/stop */ -#define XHCI_USBCMD_RUN 0x00000001UL - -/* Interrupter Enable (INTE) 1: enabled - RW */ -#define XHCI_USBCMD_INTE (1UL << 2) - -/** Host controller reset */ -#define XHCI_USBCMD_HCRST 0x00000002UL - -/** USB status register */ -#define XHCI_OP_USBSTS 0x04 - -/** Host controller halted */ -#define XHCI_USBSTS_HCH 0x00000001UL - -/** Interrupt Pending (IP) */ -#define XHCI_USBSTS_EINT (1UL << 3) - -/** Page size register */ -#define XHCI_OP_PAGESIZE 0x08 - -/** Page size */ -#define XHCI_PAGESIZE(pagesize) ( (pagesize) << 12 ) - -/** Device notifcation control register */ -#define XHCI_OP_DNCTRL 0x14 - -/** Command ring control register */ -#define XHCI_OP_CRCR 0x18 - -/** Command ring cycle state */ -#define XHCI_CRCR_RCS 0x00000001UL - -/** Command abort */ -#define XHCI_CRCR_CA 0x00000004UL - -/** Command ring running */ -#define XHCI_CRCR_CRR 0x00000008UL - -/** Device context base address array pointer */ -#define XHCI_OP_DCBAAP 0x30 - -/** Configure register */ -#define XHCI_OP_CONFIG 0x38 - -/** Maximum device slots enabled */ -#define XHCI_CONFIG_MAX_SLOTS_EN(slots) ( (slots) << 0 ) - -/** Maximum device slots enabled mask */ -#define XHCI_CONFIG_MAX_SLOTS_EN_MASK \ - XHCI_CONFIG_MAX_SLOTS_EN ( 0xff ) - -/** Port status and control register */ -#define XHCI_OP_PORTSC(port) ( 0x400 - 0x10 + ( (port) << 4 ) ) - -/** Current connect status */ -#define XHCI_PORTSC_CCS 0x00000001UL - -/** Port enabled */ -#define XHCI_PORTSC_PED 0x00000002UL - -#define XHCI_PORTSC_OCA (1 << 3) - -/** Port reset */ -#define XHCI_PORTSC_PR 0x00000010UL - -/** Port link state */ -#define XHCI_PORTSC_PLS(pls) ( (pls) << 5 ) - -/** U0 state */ -#define XHCI_PORTSC_PLS_U0 XHCI_PORTSC_PLS ( 0 ) - -/** Disabled port link state */ -#define XHCI_PORTSC_PLS_DISABLED XHCI_PORTSC_PLS ( 4 ) - -/** RxDetect port link state */ -#define XHCI_PORTSC_PLS_RXDETECT XHCI_PORTSC_PLS ( 5 ) - -/** Polling state */ -#define XHCI_PORTSC_PLS_POLLING XHCI_PORTSC_PLS ( 7 ) - -/** Port link state mask */ -#define XHCI_PORTSC_PLS_MASK XHCI_PORTSC_PLS ( 0xf ) - -/** Port power */ -#define XHCI_PORTSC_PP 0x00000200UL - -/** Time to delay after enabling power to a port */ -#define XHCI_PORT_POWER_DELAY_MS 20 - -/** Port speed ID value */ -#define XHCI_PORTSC_PSIV(portsc) ( ( (portsc) >> 10 ) & 0xf ) - -/** Port indicator control */ -#define XHCI_PORTSC_PIC(indicators) ( (indicators) << 14 ) - -/** Port indicator control mask */ -#define XHCI_PORTSC_PIC_MASK XHCI_PORTSC_PIC ( 3 ) - -/** Port link state write strobe */ -#define XHCI_PORTSC_LWS 0x00010000UL - -/** Time to delay after writing the port link state */ -#define XHCI_LINK_STATE_DELAY_MS 100 - -/** Connect status change */ -#define XHCI_PORTSC_CSC (1 << 17) - -/** Port enabled/disabled change */ -#define XHCI_PORTSC_PEC (1 << 18) - -/** Warm port reset change */ -#define XHCI_PORTSC_WRC (1 << 19) - -/** Over-current change */ -#define XHCI_PORTSC_OCC (1 << 20) - -/** Port reset change */ -#define XHCI_PORTSC_PRC (1 << 21) - -/** Port link state change */ -#define XHCI_PORTSC_PLC (1 << 22) - -/** Port config error change */ -#define XHCI_PORTSC_CEC (1 << 23) - -/* Cold Attach Status 1: Far-end Receiver Terminations were detected */ -#define XHCI_PORTSC_CAS (1 << 24) - -/* Wake on Connect Enable 1: enable port to be sensitive to device connects */ -#define XHCI_PORTSC_WCE (1 << 25) - -/* Wake on Disconnect Enable 1: enable port to be sensitive to device disconnects */ -#define XHCI_PORTSC_WDE (1 << 26) - -/* Wake on Over-current Enable 1: enable port to be sensitive to over-current conditions */ -#define XHCI_PORTSC_WOE (1 << 27) - -/* Device Removable, 0: Device is removable. 1: Device is non-removable */ -#define XHCI_PORTSC_DR (1 << 30) - -/* Warm Port Reset 1: follow Warm Reset sequence */ -#define XHCI_PORTSC_WPR (1 << 31) - -/** Port status change mask */ -#define XHCI_PORTSC_CHANGE \ - ( XHCI_PORTSC_CSC | XHCI_PORTSC_PEC | XHCI_PORTSC_WRC | \ - XHCI_PORTSC_OCC | XHCI_PORTSC_PRC | XHCI_PORTSC_PLC | \ - XHCI_PORTSC_CEC ) - -#define XHCI_PORTSC_RW_MASK (XHCI_PORTSC_PR | XHCI_PORTSC_PLS_MASK | XHCI_PORTSC_PP \ - | XHCI_PORTSC_PIC_MASK | XHCI_PORTSC_LWS | XHCI_PORTSC_WCE \ - | XHCI_PORTSC_WDE | XHCI_PORTSC_WOE) - -/** Port status and control bits which should be preserved - * - * The port status and control register is a horrendous mix of - * differing semantics. Some bits are written to only when a separate - * write strobe bit is set. Some bits should be preserved when - * modifying other bits. Some bits will be cleared if written back as - * a one. Most excitingly, the "port enabled" bit has the semantics - * that 1=enabled, 0=disabled, yet writing a 1 will disable the port. - */ -#define XHCI_PORTSC_PRESERVE ( XHCI_PORTSC_PP | XHCI_PORTSC_PIC_MASK ) - -/** Port power management status and control register */ -#define XHCI_OP_PORTPMSC(port) ( 0x404 - 0x10 + ( (port) << 4 ) ) - -/** Port link info register */ -#define XHCI_OP_PORTLI(port) ( 0x408 - 0x10 + ( (port) << 4 ) ) - -/** Port hardware link power management control register */ -#define XHCI_OP_PORTHLPMC(port) ( 0x40c - 0x10 + ( (port) << 4 ) ) - -/* Doorbell registers are 32 bits in length */ -#define XHCI_REG_DB_SIZE 4 - -/** Interrupter Management Register */ -#define XHCI_RUN_IR_IMAN(intr) ( 0x20 + ( (intr) << 5 ) ) - -/* Interrupt Pending, 1: an interrupt is pending for this Interrupter */ -#define XHCI_RUN_IR_IMAN_IP (1 << 0) - -/* Interrupt Enable, 1: capable of generating an interrupt. */ -#define XHCI_RUN_IR_IMAN_IE (1 << 1) - -/** Interrupter Moderation Register */ -#define XHCI_RUN_IR_IMOD(intr) ( 0x24 + ( (intr) << 5 ) ) - -/** Event ring segment table size register */ -#define XHCI_RUN_ERSTSZ(intr) ( 0x28 + ( (intr) << 5 ) ) - -/** Event ring segment table base address register */ -#define XHCI_RUN_ERSTBA(intr) ( 0x30 + ( (intr) << 5 ) ) - -/** Event ring dequeue pointer register */ -#define XHCI_RUN_ERDP(intr) ( 0x38 + ( (intr) << 5 ) ) - -/** Event Handler Busy */ -#define XHCI_RUN_ERDP_EHB (1 << 3) - -/** Minimum alignment required for data structures - * - * With the exception of the scratchpad buffer pages (which are - * page-aligned), data structures used by xHCI generally require from - * 16 to 64 byte alignment and must not cross an (xHCI) page boundary. - * We simplify this requirement by aligning each structure on its own - * size, with a minimum of a 64 byte alignment. - */ -#define XHCI_MIN_ALIGN 64 - -/** Maximum transfer size */ -#define XHCI_MTU 65536 - -/** Read/Write Data Barrier for ARM */ -#define BARRIER() __asm__ __volatile__("": : :"memory") - -#ifdef XHCI_AARCH64 -#define DSB() __asm__ __volatile__("dsb sy": : : "memory") -#else -#define DSB() __asm__ __volatile__("dsb": : : "memory") -#endif - -/** - * Read byte from memory-mapped device - * - * @v io_addr I/O address - * @ret data Value read - */ -static inline uint8_t readb(void *io_addr ) { - uint8_t val = *(volatile const uint8_t *)io_addr; - BARRIER(); - return val; -} - -/** - * Read 16-bit word from memory-mapped device - * - * @v io_addr I/O address - * @ret data Value read - */ -static inline uint16_t readw(void * io_addr ) { - uint16_t val = *(volatile const uint16_t *)io_addr; - BARRIER(); - return val; -} - -/** - * Read 32-bit dword from memory-mapped device - * - * @v io_addr I/O address - * @ret data Value read - */ -static inline uint32_t readl(void * io_addr ) { - uint32_t val = *(volatile const uint32_t *)io_addr; - BARRIER(); - return val; -} - -/** - * Read 64-bit qword from memory-mapped device - * - * @v io_addr I/O address - * @ret data Value read - */ -static inline uint64_t readq(void * io_addr ) { - uint64_t val = *(volatile const uint64_t *)io_addr; - BARRIER(); - return val; -} - -/** - * Write byte to memory-mapped device - * - * @v data Value to write - * @v io_addr I/O address - */ -static inline void writeb(uint8_t data, void * io_addr ) { - BARRIER(); - *(volatile uint8_t *)io_addr = data; -} - -/** - * Write 16-bit word to memory-mapped device - * - * @v data Value to write - * @v io_addr I/O address - */ -static inline void writew(uint16_t data, void * io_addr ) { - BARRIER(); - *(volatile uint16_t *)io_addr = data; -} - -/** - * Write 32-bit dword to memory-mapped device - * - * @v data Value to writed - * @v io_addr I/O address - */ -static inline void writel(uint32_t data, void * io_addr ) { - BARRIER(); - *(volatile uint32_t *)io_addr = data; -} - -/** - * Write 64-bit qword to memory-mapped device - * - * @v data Value to write - * @v io_addr I/O address - */ -static inline void writeq(uint64_t data, void * io_addr ) { - BARRIER(); - *(volatile uint64_t *)io_addr = data; -} - -/** - * Byte-order converter for ARM-Little-End - */ -#define CPU_TO_LE64(x) ((uint64_t)(x)) -#define LE64_to_CPU(x) ((uint64_t)(x)) -#define CPU_TO_LE32(x) ((uint32_t)(x)) -#define LE32_TO_CPU(x) ((uint32_t)(x)) -#define CPU_TO_LE16(x) ((uint16_t)(x)) -#define LE16_TO_CPU(x) ((uint16_t)(x)) - - -#endif /* XHCI_REG_H */ \ No newline at end of file