summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhugengyu <[email protected]>2022-09-21 08:57:41 +0800
committersakumisu <[email protected]>2022-09-22 22:12:09 +0800
commite2a4fb11d8e3d9146e0cbc711ddf1d4e43856b37 (patch)
treed3c3fd575ebb2448e5d39e88c786d60b1e8ad319
parent7837e34f7588d92ea9f8b5d15f1a2fd1a7ff02b5 (diff)
update
-rw-r--r--common/usb_mem.h16
-rw-r--r--core/usbh_core.c38
-rw-r--r--demo/phytium-e2000/usbhost/Kconfig19
-rw-r--r--demo/phytium-e2000/usbhost/README.md3
-rw-r--r--demo/phytium-e2000/usbhost/inc/usb_host.h50
-rw-r--r--demo/phytium-e2000/usbhost/main.c43
-rw-r--r--demo/phytium-e2000/usbhost/makefile29
-rw-r--r--demo/phytium-e2000/usbhost/sdkconfig223
-rw-r--r--demo/phytium-e2000/usbhost/sdkconfig.h200
-rw-r--r--demo/phytium-e2000/usbhost/sdkconfig.old225
-rw-r--r--demo/phytium-e2000/usbhost/src/cmd_usb.c55
-rw-r--r--demo/phytium-e2000/usbhost/src/usb_host.c149
-rw-r--r--port/xhci/usb_config.h143
-rw-r--r--port/xhci/usb_hc_xhci.c1218
-rw-r--r--port/xhci/usb_hc_xhci.h175
-rw-r--r--port/xhci/xhci_reg.h528
16 files changed, 3114 insertions, 0 deletions
diff --git a/common/usb_mem.h b/common/usb_mem.h
index 3e9180cc..3377ba62 100644
--- a/common/usb_mem.h
+++ b/common/usb_mem.h
@@ -6,9 +6,25 @@
#ifndef USB_MEM_H
#define USB_MEM_H
+#include "usb_config.h"
+
+#ifdef CONFIG_USBHOST_XHCI
+
+void *usb_hc_malloc(size_t size);
+void usb_hc_free();
+void *usb_hc_malloc_align(size_t align, size_t size);
+
+#define usb_malloc(size) usb_hc_malloc(size)
+#define usb_free(ptr) usb_hc_free(ptr)
+#define usb_align(align, size) usb_hc_malloc_align(align, size)
+
+#else
+
#define usb_malloc(size) malloc(size)
#define usb_free(ptr) free(ptr)
+#endif
+
#ifndef CONFIG_USB_ALIGN_SIZE
#define CONFIG_USB_ALIGN_SIZE 4
#endif
diff --git a/core/usbh_core.c b/core/usbh_core.c
index ea36721e..7feaed03 100644
--- a/core/usbh_core.c
+++ b/core/usbh_core.c
@@ -408,6 +408,42 @@ int usbh_enumerate(struct usbh_hubport *hport)
descsize = 8;
}
+#ifdef CONFIG_USBHOST_XHCI
+
+ extern int usbh_get_xhci_devaddr(usbh_pipe_t * pipe);
+
+ /* Read the first 8 bytes of the device descriptor */
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
+ setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+ setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_DEVICE << 8) | 0);
+ setup->wIndex = 0;
+ setup->wLength = descsize;
+
+ ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
+ if (ret < 0) {
+ USB_LOG_ERR("Failed to get device descriptor,errorcode:%d\r\n", ret);
+ goto errout;
+ }
+
+ parse_device_descriptor(hport, (struct usb_device_descriptor *)ep0_request_buffer, descsize);
+
+ /* Extract the correct max packetsize from the device descriptor */
+ ep_mps = ((struct usb_device_descriptor *)ep0_request_buffer)->bMaxPacketSize0;
+
+ /* And reconfigure EP0 with the correct maximum packet size */
+ usbh_ep0_pipe_reconfigure(hport->ep0, 0, ep_mps, hport->speed);
+
+ dev_addr = usbh_get_xhci_devaddr(hport->ep0);
+ if (dev_addr < 0) {
+ USB_LOG_ERR("Failed to allocate devaddr,errorcode:%d\r\n", ret);
+ goto errout;
+ }
+
+ /* Assign the function address to the port */
+ hport->dev_addr = dev_addr;
+
+#else
+
/* Configure EP0 with the initial maximum packet size */
usbh_ep0_pipe_reconfigure(hport->ep0, 0, ep_mps, hport->speed);
@@ -461,6 +497,8 @@ int usbh_enumerate(struct usbh_hubport *hport)
/* And reconfigure EP0 with the correct address */
usbh_ep0_pipe_reconfigure(hport->ep0, dev_addr, ep_mps, hport->speed);
+#endif
+
/* Read the full device descriptor */
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
diff --git a/demo/phytium-e2000/usbhost/Kconfig b/demo/phytium-e2000/usbhost/Kconfig
new file mode 100644
index 00000000..a4938ffb
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/Kconfig
@@ -0,0 +1,19 @@
+#
+# For a description of the syntax of this configuration file,
+# see tools/kconfiglib/kconfig-language.txt.
+#
+
+
+mainmenu "Phytium Freertos Configuration"
+
+menu "Freertos Configuration"
+ config TARGET_NAME
+ string "Build Target Name"
+ default "freertos"
+ help
+ Build Target name for the demo
+
+endmenu
+
+source "$(FREERTOS_SDK_ROOT)/Kconfig"
+
diff --git a/demo/phytium-e2000/usbhost/README.md b/demo/phytium-e2000/usbhost/README.md
new file mode 100644
index 00000000..bbbc6a1f
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/README.md
@@ -0,0 +1,3 @@
+# how to use
+1. install [Phytium FreeRTOS SDK](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)
+2. make and flash image to Phytium-E2000-Dev Board \ No newline at end of file
diff --git a/demo/phytium-e2000/usbhost/inc/usb_host.h b/demo/phytium-e2000/usbhost/inc/usb_host.h
new file mode 100644
index 00000000..11aaab8e
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/inc/usb_host.h
@@ -0,0 +1,50 @@
+/*
+ * 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_host.h
+ * Date: 2022-07-19 09:26:25
+ * LastEditTime: 2022-07-19 09:26:25
+ * Description:  This files is for
+ *
+ * Modify History:
+ * Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ */
+#ifndef EXAMPLE_USB_HOST_H
+#define EXAMPLE_USB_HOST_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/***************************** Include Files *********************************/
+
+/************************** Constant Definitions *****************************/
+
+/************************** Variable Definitions *****************************/
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Function Prototypes ******************************/
+
+/*****************************************************************************/
+BaseType_t FFreeRTOSInitUsb(void);
+BaseType_t FFreeRTOSWriteReadUsbDisk(void);
+BaseType_t FFreeRTOSRecvHidInput(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/demo/phytium-e2000/usbhost/main.c b/demo/phytium-e2000/usbhost/main.c
new file mode 100644
index 00000000..8fba640d
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/main.c
@@ -0,0 +1,43 @@
+/*
+ * 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: main.c
+ * Date: 2022-06-17 08:17:59
+ * LastEditTime: 2022-06-17 08:17:59
+ * Description: This file is for c main entry
+ *
+ * Modify History:
+ * Ver Who Date Changes
+ * ----- ------ -------- --------------------------------------
+ * 1.0 zhugengyu 2022/9/20 init commit
+ */
+
+#include "shell.h"
+#include "shell_port.h"
+#include <stdio.h>
+
+int main(void)
+{
+ BaseType_t ret;
+
+ ret = LSUserShellTask();
+ if(ret != pdPASS)
+ goto FAIL_EXIT;
+
+ vTaskStartScheduler(); /* 启动任务,开启调度 */
+ while (1); /* 正常不会执行到这里 */
+
+FAIL_EXIT:
+ printf("failed 0x%x \r\n", ret);
+ return 0;
+}
diff --git a/demo/phytium-e2000/usbhost/makefile b/demo/phytium-e2000/usbhost/makefile
new file mode 100644
index 00000000..d5622739
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/makefile
@@ -0,0 +1,29 @@
+export PROJECT_DIR ?= $(shell pwd)
+
+export USR_SRC_DIR = $(PROJECT_DIR) \
+ ./src
+export USR_INC_DIR = $(PROJECT_DIR) \
+ ./inc
+
+# 用户定义的编译目标文件上传路径
+ifeq ($(OS),Windows_NT)
+ USR_BOOT_DIR ?= $(subst \,/, $(PHYTIUM_DEV_PATH))/tftp
+else
+ USR_BOOT_DIR ?= /mnt/d/tftboot
+endif
+
+
+# 设置启动镜像名
+BOOT_IMG_NAME ?= freertos
+
+# 指定编译freertos项目使用的makefile
+include $(FREERTOS_SDK_ROOT)/make/build_freertos.mk
+
+# 完成编译
+boot:
+ make -j
+ @cp ./$(CONFIG_TARGET_NAME).elf $(USR_BOOT_DIR)/$(BOOT_IMG_NAME).elf
+ @cp ./$(CONFIG_TARGET_NAME).bin $(USR_BOOT_DIR)/$(BOOT_IMG_NAME).bin
+ @ls -l $(USR_BOOT_DIR)/$(BOOT_IMG_NAME).*
+
+
diff --git a/demo/phytium-e2000/usbhost/sdkconfig b/demo/phytium-e2000/usbhost/sdkconfig
new file mode 100644
index 00000000..51d47a84
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/sdkconfig
@@ -0,0 +1,223 @@
+
+#
+# Freertos Configuration
+#
+CONFIG_TARGET_NAME="e2000d_freertos_a64"
+# end of Freertos Configuration
+
+#
+# Standalone Setting
+#
+CONFIG_USE_FREERTOS=y
+
+#
+# Arch Configuration
+#
+# CONFIG_TARGET_ARMV8_AARCH32 is not set
+CONFIG_TARGET_ARMV8_AARCH64=y
+CONFIG_USE_CACHE=y
+CONFIG_USE_MMU=y
+CONFIG_USE_SYS_TICK=y
+# CONFIG_MMU_DEBUG_PRINTS is not set
+# end of Arch Configuration
+
+#
+# Board Configuration
+#
+# CONFIG_TARGET_F2000_4 is not set
+# CONFIG_TARGET_D2000 is not set
+# CONFIG_TARGET_E2000Q is not set
+CONFIG_TARGET_E2000D=y
+# CONFIG_TARGET_E2000S is not set
+CONFIG_TARGET_E2000=y
+CONFIG_DEFAULT_DEBUG_PRINT_UART1=y
+# CONFIG_DEFAULT_DEBUG_PRINT_UART0 is not set
+# CONFIG_DEFAULT_DEBUG_PRINT_UART2 is not set
+# end of Board Configuration
+
+#
+# Components Configuration
+#
+CONFIG_USE_SPI=y
+CONFIG_USE_FSPIM=y
+# CONFIG_USE_QSPI is not set
+CONFIG_USE_GIC=y
+CONFIG_ENABLE_GICV3=y
+CONFIG_USE_SERIAL=y
+
+#
+# Usart Configuration
+#
+CONFIG_ENABLE_Pl011_UART=y
+# end of Usart Configuration
+
+# CONFIG_USE_GPIO is not set
+# CONFIG_USE_ETH is not set
+# CONFIG_USE_CAN is not set
+# CONFIG_USE_I2C is not set
+# CONFIG_USE_TIMER is not set
+# CONFIG_USE_MIO is not set
+# CONFIG_USE_SDMMC is not set
+# CONFIG_USE_PCIE is not set
+# CONFIG_USE_WDT is not set
+CONFIG_USE_DMA=y
+# CONFIG_ENABLE_FGDMA is not set
+CONFIG_ENABLE_FDDMA=y
+# CONFIG_USE_NAND is not set
+# CONFIG_USE_RTC is not set
+# CONFIG_USE_SATA is not set
+# CONFIG_USE_USB is not set
+# CONFIG_USE_ADC is not set
+# CONFIG_USE_PWM is not set
+# CONFIG_USE_IPC is not set
+# end of Components Configuration
+
+CONFIG_USE_NEW_LIBC=y
+# end of Standalone Setting
+
+#
+# Building Option
+#
+# CONFIG_LOG_VERBOS is not set
+CONFIG_LOG_DEBUG=y
+# CONFIG_LOG_INFO is not set
+# CONFIG_LOG_WARN is not set
+# CONFIG_LOG_ERROR is not set
+# CONFIG_LOG_NONE is not set
+CONFIG_USE_DEFAULT_INTERRUPT_CONFIG=y
+CONFIG_INTERRUPT_ROLE_MASTER=y
+# CONFIG_INTERRUPT_ROLE_SLAVE is not set
+CONFIG_LOG_EXTRA_INFO=y
+# CONFIG_BOOTUP_DEBUG_PRINTS is not set
+
+#
+# Linker Options
+#
+# CONFIG_AARCH32_RAM_LD is not set
+CONFIG_AARCH64_RAM_LD=y
+# CONFIG_USER_DEFINED_LD is not set
+CONFIG_LINK_SCRIPT_ROM=y
+CONFIG_ROM_START_UP_ADDR=0x80100000
+CONFIG_ROM_SIZE_MB=1
+CONFIG_LINK_SCRIPT_RAM=y
+CONFIG_RAM_START_UP_ADDR=0x81000000
+CONFIG_RAM_SIZE_MB=64
+CONFIG_HEAP_SIZE=1
+CONFIG_STACK_SIZE=0x100000
+CONFIG_FPU_STACK_SIZE=0x1000
+# end of Linker Options
+
+#
+# Compiler Options
+#
+CONFIG_OUTPUT_BINARY=y
+# end of Compiler Options
+# end of Building Option
+
+#
+# Component Configuration
+#
+
+#
+# Freertos Uart Drivers
+#
+CONFIG_FREERTOS_USE_UART=y
+# end of Freertos Uart Drivers
+
+#
+# Freertos Pwm Drivers
+#
+# CONFIG_FREERTOS_USE_PWM is not set
+# end of Freertos Pwm Drivers
+
+#
+# Freertos Qspi Drivers
+#
+# CONFIG_FREERTOS_USE_QSPI is not set
+# end of Freertos Qspi Drivers
+
+#
+# Freertos Wdt Drivers
+#
+# CONFIG_FREERTOS_USE_WDT is not set
+# end of Freertos Wdt Drivers
+
+#
+# Freertos Eth Drivers
+#
+# CONFIG_FREERTOS_USE_XMAC is not set
+# end of Freertos Eth Drivers
+
+#
+# Freertos Gpio Drivers
+#
+# CONFIG_FREERTOS_USE_GPIO is not set
+# end of Freertos Gpio Drivers
+
+#
+# Freertos Spim Drivers
+#
+CONFIG_FREERTOS_USE_FSPIM=y
+# end of Freertos Spim Drivers
+
+#
+# Freertos DMA Drivers
+#
+CONFIG_FREERTOS_USE_FDDMA=y
+# CONFIG_FREERTOS_USE_FGDMA is not set
+# end of Freertos DMA Drivers
+
+#
+# Freertos MMC Drivers
+#
+# CONFIG_FREERTOS_USE_FSDIO is not set
+# end of Freertos MMC Drivers
+
+#
+# Freertos Adc Drivers
+#
+# CONFIG_FREERTOS_USE_ADC is not set
+# end of Freertos Adc Drivers
+# end of Component Configuration
+
+#
+# FreeRTOS Setting
+#
+# CONFIG_USE_LWIP is not set
+CONFIG_USE_BACKTRACE=y
+# CONFIG_USE_FATFS is not set
+# CONFIG_USE_SFUD is not set
+# CONFIG_USE_SPIFFS is not set
+# CONFIG_USE_AMP is not set
+CONFIG_USE_LETTER_SHELL=y
+
+#
+# Letter Shell Configuration
+#
+CONFIG_LS_PL011_UART=y
+CONFIG_DEFAULT_LETTER_SHELL_USE_UART1=y
+# CONFIG_DEFAULT_LETTER_SHELL_USE_UART0 is not set
+# CONFIG_DEFAULT_LETTER_SHELL_USE_UART2 is not set
+# end of Letter Shell Configuration
+
+CONFIG_USE_TLSF=y
+# CONFIG_USE_SDMMC_CMD is not set
+CONFIG_USE_CHERRY_USB=y
+
+#
+# CherryUSB Configuration
+#
+CONFIG_CHERRY_USB_PORT_XHCI=y
+# CONFIG_CHERRY_USB_PORT_PHYTIUM_OTG is not set
+CONFIG_CHERRYUSB_HOST=y
+# CONFIG_CHERRYUSB_DEVICE is not set
+CONFIG_CHERRY_USB_HOST_HUB=y
+CONFIG_CHERRY_USB_HOST_MSC=y
+CONFIG_CHERRY_USB_HOST_HID=y
+# CONFIG_CHERRY_USB_HOST_MTP is not set
+# CONFIG_CHERRY_USB_HOST_CDC is not set
+# CONFIG_CHERRY_USB_HOST_PRINTER is not set
+# CONFIG_CHERRY_USB_HOST_AXU_NET is not set
+# CONFIG_CHERRY_USB_HOST_RNDIS_WIRELESS is not set
+# end of CherryUSB Configuration
+# end of FreeRTOS Setting
diff --git a/demo/phytium-e2000/usbhost/sdkconfig.h b/demo/phytium-e2000/usbhost/sdkconfig.h
new file mode 100644
index 00000000..6ed02741
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/sdkconfig.h
@@ -0,0 +1,200 @@
+#ifndef SDK_CONFIG_H__
+#define SDK_CONFIG_H__
+
+/* Freertos Configuration */
+
+#define CONFIG_TARGET_NAME "e2000d_freertos_a64"
+/* end of Freertos Configuration */
+
+/* Standalone Setting */
+
+#define CONFIG_USE_FREERTOS
+
+/* Arch Configuration */
+
+/* CONFIG_TARGET_ARMV8_AARCH32 is not set */
+#define CONFIG_TARGET_ARMV8_AARCH64
+#define CONFIG_USE_CACHE
+#define CONFIG_USE_MMU
+#define CONFIG_USE_SYS_TICK
+/* CONFIG_MMU_DEBUG_PRINTS is not set */
+/* end of Arch Configuration */
+
+/* Board Configuration */
+
+/* CONFIG_TARGET_F2000_4 is not set */
+/* CONFIG_TARGET_D2000 is not set */
+/* CONFIG_TARGET_E2000Q is not set */
+#define CONFIG_TARGET_E2000D
+/* CONFIG_TARGET_E2000S is not set */
+#define CONFIG_TARGET_E2000
+#define CONFIG_DEFAULT_DEBUG_PRINT_UART1
+/* CONFIG_DEFAULT_DEBUG_PRINT_UART0 is not set */
+/* CONFIG_DEFAULT_DEBUG_PRINT_UART2 is not set */
+/* end of Board Configuration */
+
+/* Components Configuration */
+
+#define CONFIG_USE_SPI
+#define CONFIG_USE_FSPIM
+/* CONFIG_USE_QSPI is not set */
+#define CONFIG_USE_GIC
+#define CONFIG_ENABLE_GICV3
+#define CONFIG_USE_SERIAL
+
+/* Usart Configuration */
+
+#define CONFIG_ENABLE_Pl011_UART
+/* end of Usart Configuration */
+/* CONFIG_USE_GPIO is not set */
+/* CONFIG_USE_ETH is not set */
+/* CONFIG_USE_CAN is not set */
+/* CONFIG_USE_I2C is not set */
+/* CONFIG_USE_TIMER is not set */
+/* CONFIG_USE_MIO is not set */
+/* CONFIG_USE_SDMMC is not set */
+/* CONFIG_USE_PCIE is not set */
+/* CONFIG_USE_WDT is not set */
+#define CONFIG_USE_DMA
+/* CONFIG_ENABLE_FGDMA is not set */
+#define CONFIG_ENABLE_FDDMA
+/* CONFIG_USE_NAND is not set */
+/* CONFIG_USE_RTC is not set */
+/* CONFIG_USE_SATA is not set */
+/* CONFIG_USE_USB is not set */
+/* CONFIG_USE_ADC is not set */
+/* CONFIG_USE_PWM is not set */
+/* CONFIG_USE_IPC is not set */
+/* end of Components Configuration */
+#define CONFIG_USE_NEW_LIBC
+/* end of Standalone Setting */
+
+/* Building Option */
+
+/* CONFIG_LOG_VERBOS is not set */
+#define CONFIG_LOG_DEBUG
+/* CONFIG_LOG_INFO is not set */
+/* CONFIG_LOG_WARN is not set */
+/* CONFIG_LOG_ERROR is not set */
+/* CONFIG_LOG_NONE is not set */
+#define CONFIG_USE_DEFAULT_INTERRUPT_CONFIG
+#define CONFIG_INTERRUPT_ROLE_MASTER
+/* CONFIG_INTERRUPT_ROLE_SLAVE is not set */
+#define CONFIG_LOG_EXTRA_INFO
+/* CONFIG_BOOTUP_DEBUG_PRINTS is not set */
+
+/* Linker Options */
+
+/* CONFIG_AARCH32_RAM_LD is not set */
+#define CONFIG_AARCH64_RAM_LD
+/* CONFIG_USER_DEFINED_LD is not set */
+#define CONFIG_LINK_SCRIPT_ROM
+#define CONFIG_ROM_START_UP_ADDR 0x80100000
+#define CONFIG_ROM_SIZE_MB 1
+#define CONFIG_LINK_SCRIPT_RAM
+#define CONFIG_RAM_START_UP_ADDR 0x81000000
+#define CONFIG_RAM_SIZE_MB 64
+#define CONFIG_HEAP_SIZE 1
+#define CONFIG_STACK_SIZE 0x100000
+#define CONFIG_FPU_STACK_SIZE 0x1000
+/* end of Linker Options */
+
+/* Compiler Options */
+
+#define CONFIG_OUTPUT_BINARY
+/* end of Compiler Options */
+/* end of Building Option */
+
+/* Component Configuration */
+
+/* Freertos Uart Drivers */
+
+#define CONFIG_FREERTOS_USE_UART
+/* end of Freertos Uart Drivers */
+
+/* Freertos Pwm Drivers */
+
+/* CONFIG_FREERTOS_USE_PWM is not set */
+/* end of Freertos Pwm Drivers */
+
+/* Freertos Qspi Drivers */
+
+/* CONFIG_FREERTOS_USE_QSPI is not set */
+/* end of Freertos Qspi Drivers */
+
+/* Freertos Wdt Drivers */
+
+/* CONFIG_FREERTOS_USE_WDT is not set */
+/* end of Freertos Wdt Drivers */
+
+/* Freertos Eth Drivers */
+
+/* CONFIG_FREERTOS_USE_XMAC is not set */
+/* end of Freertos Eth Drivers */
+
+/* Freertos Gpio Drivers */
+
+/* CONFIG_FREERTOS_USE_GPIO is not set */
+/* end of Freertos Gpio Drivers */
+
+/* Freertos Spim Drivers */
+
+#define CONFIG_FREERTOS_USE_FSPIM
+/* end of Freertos Spim Drivers */
+
+/* Freertos DMA Drivers */
+
+#define CONFIG_FREERTOS_USE_FDDMA
+/* CONFIG_FREERTOS_USE_FGDMA is not set */
+/* end of Freertos DMA Drivers */
+
+/* Freertos MMC Drivers */
+
+/* CONFIG_FREERTOS_USE_FSDIO is not set */
+/* end of Freertos MMC Drivers */
+
+/* Freertos Adc Drivers */
+
+/* CONFIG_FREERTOS_USE_ADC is not set */
+/* end of Freertos Adc Drivers */
+/* end of Component Configuration */
+
+/* FreeRTOS Setting */
+
+/* CONFIG_USE_LWIP is not set */
+#define CONFIG_USE_BACKTRACE
+/* CONFIG_USE_FATFS is not set */
+/* CONFIG_USE_SFUD is not set */
+/* CONFIG_USE_SPIFFS is not set */
+/* CONFIG_USE_AMP is not set */
+#define CONFIG_USE_LETTER_SHELL
+
+/* Letter Shell Configuration */
+
+#define CONFIG_LS_PL011_UART
+#define CONFIG_DEFAULT_LETTER_SHELL_USE_UART1
+/* CONFIG_DEFAULT_LETTER_SHELL_USE_UART0 is not set */
+/* CONFIG_DEFAULT_LETTER_SHELL_USE_UART2 is not set */
+/* end of Letter Shell Configuration */
+#define CONFIG_USE_TLSF
+/* CONFIG_USE_SDMMC_CMD is not set */
+#define CONFIG_USE_CHERRY_USB
+
+/* CherryUSB Configuration */
+
+#define CONFIG_CHERRY_USB_PORT_XHCI
+/* CONFIG_CHERRY_USB_PORT_PHYTIUM_OTG is not set */
+#define CONFIG_CHERRYUSB_HOST
+/* CONFIG_CHERRYUSB_DEVICE is not set */
+#define CONFIG_CHERRY_USB_HOST_HUB
+#define CONFIG_CHERRY_USB_HOST_MSC
+#define CONFIG_CHERRY_USB_HOST_HID
+/* CONFIG_CHERRY_USB_HOST_MTP is not set */
+/* CONFIG_CHERRY_USB_HOST_CDC is not set */
+/* CONFIG_CHERRY_USB_HOST_PRINTER is not set */
+/* CONFIG_CHERRY_USB_HOST_AXU_NET is not set */
+/* CONFIG_CHERRY_USB_HOST_RNDIS_WIRELESS is not set */
+/* end of CherryUSB Configuration */
+/* end of FreeRTOS Setting */
+
+#endif
diff --git a/demo/phytium-e2000/usbhost/sdkconfig.old b/demo/phytium-e2000/usbhost/sdkconfig.old
new file mode 100644
index 00000000..ac6ed6ab
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/sdkconfig.old
@@ -0,0 +1,225 @@
+
+#
+# Freertos Configuration
+#
+CONFIG_TARGET_NAME="e2000d_freertos_a64"
+CONFIG_XHCI_HOST_INSTANCE_0=y
+# CONFIG_XHCI_HOST_INSTANCE_1 is not set
+# end of Freertos Configuration
+
+#
+# Standalone Setting
+#
+CONFIG_USE_FREERTOS=y
+
+#
+# Arch Configuration
+#
+# CONFIG_TARGET_ARMV8_AARCH32 is not set
+CONFIG_TARGET_ARMV8_AARCH64=y
+CONFIG_USE_CACHE=y
+CONFIG_USE_MMU=y
+CONFIG_USE_SYS_TICK=y
+# CONFIG_MMU_DEBUG_PRINTS is not set
+# end of Arch Configuration
+
+#
+# Board Configuration
+#
+# CONFIG_TARGET_F2000_4 is not set
+# CONFIG_TARGET_D2000 is not set
+# CONFIG_TARGET_E2000Q is not set
+CONFIG_TARGET_E2000D=y
+# CONFIG_TARGET_E2000S is not set
+CONFIG_TARGET_E2000=y
+CONFIG_DEFAULT_DEBUG_PRINT_UART1=y
+# CONFIG_DEFAULT_DEBUG_PRINT_UART0 is not set
+# CONFIG_DEFAULT_DEBUG_PRINT_UART2 is not set
+# end of Board Configuration
+
+#
+# Components Configuration
+#
+CONFIG_USE_SPI=y
+CONFIG_USE_FSPIM=y
+# CONFIG_USE_QSPI is not set
+CONFIG_USE_GIC=y
+CONFIG_ENABLE_GICV3=y
+CONFIG_USE_SERIAL=y
+
+#
+# Usart Configuration
+#
+CONFIG_ENABLE_Pl011_UART=y
+# end of Usart Configuration
+
+# CONFIG_USE_GPIO is not set
+# CONFIG_USE_ETH is not set
+# CONFIG_USE_CAN is not set
+# CONFIG_USE_I2C is not set
+# CONFIG_USE_TIMER is not set
+# CONFIG_USE_MIO is not set
+# CONFIG_USE_SDMMC is not set
+# CONFIG_USE_PCIE is not set
+# CONFIG_USE_WDT is not set
+CONFIG_USE_DMA=y
+# CONFIG_ENABLE_FGDMA is not set
+CONFIG_ENABLE_FDDMA=y
+# CONFIG_USE_NAND is not set
+# CONFIG_USE_RTC is not set
+# CONFIG_USE_SATA is not set
+# CONFIG_USE_USB is not set
+# CONFIG_USE_ADC is not set
+# CONFIG_USE_PWM is not set
+# CONFIG_USE_IPC is not set
+# end of Components Configuration
+
+CONFIG_USE_NEW_LIBC=y
+# end of Standalone Setting
+
+#
+# Building Option
+#
+# CONFIG_LOG_VERBOS is not set
+CONFIG_LOG_DEBUG=y
+# CONFIG_LOG_INFO is not set
+# CONFIG_LOG_WARN is not set
+# CONFIG_LOG_ERROR is not set
+# CONFIG_LOG_NONE is not set
+CONFIG_USE_DEFAULT_INTERRUPT_CONFIG=y
+CONFIG_INTERRUPT_ROLE_MASTER=y
+# CONFIG_INTERRUPT_ROLE_SLAVE is not set
+CONFIG_LOG_EXTRA_INFO=y
+# CONFIG_BOOTUP_DEBUG_PRINTS is not set
+
+#
+# Linker Options
+#
+# CONFIG_AARCH32_RAM_LD is not set
+CONFIG_AARCH64_RAM_LD=y
+# CONFIG_USER_DEFINED_LD is not set
+CONFIG_LINK_SCRIPT_ROM=y
+CONFIG_ROM_START_UP_ADDR=0x80100000
+CONFIG_ROM_SIZE_MB=1
+CONFIG_LINK_SCRIPT_RAM=y
+CONFIG_RAM_START_UP_ADDR=0x81000000
+CONFIG_RAM_SIZE_MB=64
+CONFIG_HEAP_SIZE=1
+CONFIG_STACK_SIZE=0x100000
+CONFIG_FPU_STACK_SIZE=0x1000
+# end of Linker Options
+
+#
+# Compiler Options
+#
+CONFIG_OUTPUT_BINARY=y
+# end of Compiler Options
+# end of Building Option
+
+#
+# Component Configuration
+#
+
+#
+# Freertos Uart Drivers
+#
+CONFIG_FREERTOS_USE_UART=y
+# end of Freertos Uart Drivers
+
+#
+# Freertos Pwm Drivers
+#
+# CONFIG_FREERTOS_USE_PWM is not set
+# end of Freertos Pwm Drivers
+
+#
+# Freertos Qspi Drivers
+#
+# CONFIG_FREERTOS_USE_QSPI is not set
+# end of Freertos Qspi Drivers
+
+#
+# Freertos Wdt Drivers
+#
+# CONFIG_FREERTOS_USE_WDT is not set
+# end of Freertos Wdt Drivers
+
+#
+# Freertos Eth Drivers
+#
+# CONFIG_FREERTOS_USE_XMAC is not set
+# end of Freertos Eth Drivers
+
+#
+# Freertos Gpio Drivers
+#
+# CONFIG_FREERTOS_USE_GPIO is not set
+# end of Freertos Gpio Drivers
+
+#
+# Freertos Spim Drivers
+#
+CONFIG_FREERTOS_USE_FSPIM=y
+# end of Freertos Spim Drivers
+
+#
+# Freertos DMA Drivers
+#
+CONFIG_FREERTOS_USE_FDDMA=y
+# CONFIG_FREERTOS_USE_FGDMA is not set
+# end of Freertos DMA Drivers
+
+#
+# Freertos MMC Drivers
+#
+# CONFIG_FREERTOS_USE_FSDIO is not set
+# end of Freertos MMC Drivers
+
+#
+# Freertos Adc Drivers
+#
+# CONFIG_FREERTOS_USE_ADC is not set
+# end of Freertos Adc Drivers
+# end of Component Configuration
+
+#
+# FreeRTOS Setting
+#
+# CONFIG_USE_LWIP is not set
+CONFIG_USE_BACKTRACE=y
+# CONFIG_USE_FATFS is not set
+# CONFIG_USE_SFUD is not set
+# CONFIG_USE_SPIFFS is not set
+# CONFIG_USE_AMP is not set
+CONFIG_USE_LETTER_SHELL=y
+
+#
+# Letter Shell Configuration
+#
+CONFIG_LS_PL011_UART=y
+CONFIG_DEFAULT_LETTER_SHELL_USE_UART1=y
+# CONFIG_DEFAULT_LETTER_SHELL_USE_UART0 is not set
+# CONFIG_DEFAULT_LETTER_SHELL_USE_UART2 is not set
+# end of Letter Shell Configuration
+
+CONFIG_USE_TLSF=y
+# CONFIG_USE_SDMMC_CMD is not set
+CONFIG_USE_CHERRY_USB=y
+
+#
+# CherryUSB Configuration
+#
+CONFIG_CHERRY_USB_PORT_XHCI=y
+# CONFIG_CHERRY_USB_PORT_PHYTIUM_OTG is not set
+CONFIG_CHERRYUSB_HOST=y
+# CONFIG_CHERRYUSB_DEVICE is not set
+CONFIG_CHERRY_USB_HOST_HUB=y
+CONFIG_CHERRY_USB_HOST_MSC=y
+CONFIG_CHERRY_USB_HOST_HID=y
+# CONFIG_CHERRY_USB_HOST_MTP is not set
+# CONFIG_CHERRY_USB_HOST_CDC is not set
+# CONFIG_CHERRY_USB_HOST_PRINTER is not set
+# CONFIG_CHERRY_USB_HOST_AXU_NET is not set
+# CONFIG_CHERRY_USB_HOST_RNDIS_WIRELESS is not set
+# end of CherryUSB Configuration
+# end of FreeRTOS Setting
diff --git a/demo/phytium-e2000/usbhost/src/cmd_usb.c b/demo/phytium-e2000/usbhost/src/cmd_usb.c
new file mode 100644
index 00000000..09e8ffd4
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/src/cmd_usb.c
@@ -0,0 +1,55 @@
+/*
+ * 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: cmd_usb.c
+ * Date: 2022-09-19 14:34:44
+ * LastEditTime: 2022-09-19 14:34:45
+ * Description:  This files is for letter shell command implmentation
+ *
+ * Modify History:
+ * Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0 zhugengyu 2022/9/20 init commit
+ */
+#include <string.h>
+#include <stdio.h>
+#include "strto.h"
+#include "sdkconfig.h"
+
+#include "FreeRTOS.h"
+
+#include "../src/shell.h"
+#include "usb_host.h"
+
+static int USBCmdEntry(int argc, char *argv[])
+{
+ int ret = 0;
+ u32 bytes = 32;
+ u32 usb_id = 0U;
+
+ if (!strcmp(argv[1], "init"))
+ {
+ ret = FFreeRTOSInitUsb();
+ }
+ else if (!strcmp(argv[1], "disk"))
+ {
+
+ }
+ else if (!strcmp(argv[1], "hid"))
+ {
+
+ }
+
+ return ret;
+}
+SHELL_EXPORT_CMD(SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), usb, USBCmdEntry, test freertos usb driver); \ No newline at end of file
diff --git a/demo/phytium-e2000/usbhost/src/usb_host.c b/demo/phytium-e2000/usbhost/src/usb_host.c
new file mode 100644
index 00000000..7ac40c4e
--- /dev/null
+++ b/demo/phytium-e2000/usbhost/src/usb_host.c
@@ -0,0 +1,149 @@
+/*
+ * 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_host.c
+ * Date: 2022-07-22 13:57:42
+ * LastEditTime: 2022-07-22 13:57:43
+ * Description:  This files is for cherry usb host function implementation
+ *
+ * Modify History:
+ * Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0 zhugengyu 2022/9/20 init commit
+ */
+/***************************** Include Files *********************************/
+#include <stdio.h>
+#include <string.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "ft_assert.h"
+#include "interrupt.h"
+#include "cpu_info.h"
+#include "ft_debug.h"
+
+#include "usbh_core.h"
+
+#include "fmemory_pool.h"
+/************************** Constant Definitions *****************************/
+#define FUSB_MEMP_TOTAL_SIZE SZ_1M
+
+/**************************** Type Definitions *******************************/
+
+/************************** Variable Definitions *****************************/
+static FMemp memp;
+static u8 memp_buf[FUSB_MEMP_TOTAL_SIZE];
+
+/***************** Macros (Inline Functions) Definitions *********************/
+#define FUSB_DEBUG_TAG "USB-HC"
+#define FUSB_ERROR(format, ...) FT_DEBUG_PRINT_E(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
+#define FUSB_WARN(format, ...) FT_DEBUG_PRINT_W(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
+#define FUSB_INFO(format, ...) FT_DEBUG_PRINT_I(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
+#define FUSB_DEBUG(format, ...) FT_DEBUG_PRINT_D(FUSB_DEBUG_TAG, format, ##__VA_ARGS__)
+
+/************************** Function Prototypes ******************************/
+extern void USBH_IRQHandler(void);
+
+/*****************************************************************************/
+static void UsbHcInterrruptHandler(s32 vector, void *param)
+{
+ USBH_IRQHandler();
+}
+
+static void UsbHcSetupInterrupt(void)
+{
+ u32 cpu_id;
+ u32 irq_num = CONFIG_XHCI_IRQ_NUM;
+ u32 irq_priority = 13U;
+
+ GetCpuId(&cpu_id);
+ InterruptSetTargetCpus(irq_num, cpu_id);
+
+ InterruptSetPriority(irq_num, irq_priority);
+
+ /* register intr callback */
+ InterruptInstall(irq_num,
+ UsbHcInterrruptHandler,
+ NULL,
+ NULL);
+
+ /* enable irq */
+ InterruptUmask(irq_num);
+}
+
+void UsbHcSetupMemp(void)
+{
+ if (FT_COMPONENT_IS_READY != memp.is_ready)
+ {
+ USB_ASSERT(FT_SUCCESS == FMempInit(&memp, &memp_buf[0], &memp_buf[0] + FUSB_MEMP_TOTAL_SIZE));
+ }
+}
+
+/* implement cherryusb */
+void usb_hc_low_level_init(void)
+{
+ UsbHcSetupMemp();
+ UsbHcSetupInterrupt();
+}
+
+void *usb_hc_malloc(size_t size)
+{
+ return usb_hc_malloc_align(sizeof(void *), size);
+}
+
+void *usb_hc_malloc_align(size_t align, size_t size)
+{
+ void *result = FMempMallocAlign(&memp, size, align);
+
+ if (result)
+ memset(result, 0U, size);
+
+ return result;
+}
+
+void usb_hc_free(void *ptr)
+{
+ if (NULL != ptr)
+ FMempFree(&memp, ptr);
+}
+
+void usb_assert(const char *filename, int linenum)
+{
+ FAssert(filename, linenum, 0xff);
+}
+
+static void UsbInitTask(void * args)
+{
+ usbh_initialize();
+ vTaskDelete(NULL);
+}
+
+BaseType_t FFreeRTOSInitUsb(void)
+{
+ BaseType_t ret = pdPASS;
+
+ taskENTER_CRITICAL(); /* no schedule when create task */
+
+ ret = xTaskCreate((TaskFunction_t )UsbInitTask,
+ (const char* )"UsbInitTask",
+ (uint16_t )2048,
+ NULL,
+ (UBaseType_t )configMAX_PRIORITIES - 1,
+ NULL);
+ FASSERT_MSG(pdPASS == ret, "create task failed");
+
+ taskEXIT_CRITICAL(); /* allow schedule since task created */
+
+ return ret;
+} \ No newline at end of file
diff --git a/port/xhci/usb_config.h b/port/xhci/usb_config.h
new file mode 100644
index 00000000..92cc24b5
--- /dev/null
+++ b/port/xhci/usb_config.h
@@ -0,0 +1,143 @@
+/*
+ * 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_config.h
+ * Date: 2022-09-19 17:28:44
+ * LastEditTime: 2022-09-19 17:28:45
+ * Description:  This files is for usb hc xhci configuration
+ *
+ * Modify History:
+ * Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0 zhugengyu 2022/9/19 init commit
+ */
+
+#ifndef CHERRYUSB_CONFIG_H
+#define CHERRYUSB_CONFIG_H
+
+
+/* ================ USB common Configuration ================ */
+
+#ifndef CONFIG_USB_DBG_LEVEL
+#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
+#endif
+
+#ifndef CONFIG_USB_PRINTF
+#define CONFIG_USB_PRINTF printf
+#endif
+
+/* Enable print with color */
+#define CONFIG_USB_PRINTF_COLOR_ENABLE
+
+/* data align size when use dma */
+#ifndef CONFIG_USB_ALIGN_SIZE
+#define CONFIG_USB_ALIGN_SIZE 4
+#endif
+
+/* attribute data into no cache ram */
+#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
+
+/* ================= USB Device Stack Configuration ================ */
+
+/* Ep0 max transfer buffer, specially for receiving data from ep0 out */
+#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 256
+
+
+#ifndef CONFIG_USBDEV_MSC_BLOCK_SIZE
+#define CONFIG_USBDEV_MSC_BLOCK_SIZE 512
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
+#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
+#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
+#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
+#endif
+
+#define CONFIG_USBHOST_GET_STRING_DESC
+
+// #define CONFIG_USBDEV_MSC_THREAD
+
+#ifdef CONFIG_USBDEV_MSC_THREAD
+#ifndef CONFIG_USBDEV_MSC_STACKSIZE
+#define CONFIG_USBDEV_MSC_STACKSIZE 2048
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_PRIO
+#define CONFIG_USBDEV_MSC_PRIO 4
+#endif
+#endif
+
+#ifndef CONFIG_USBDEV_AUDIO_VERSION
+#define CONFIG_USBDEV_AUDIO_VERSION 0x0100
+#endif
+
+#ifndef CONFIG_USBDEV_AUDIO_MAX_CHANNEL
+#define CONFIG_USBDEV_AUDIO_MAX_CHANNEL 8
+#endif
+
+/* ================ USB HOST Stack Configuration ================== */
+
+#define CONFIG_USBHOST_MAX_RHPORTS 1
+#define CONFIG_USBHOST_MAX_EXTHUBS 1
+#define CONFIG_USBHOST_MAX_EHPORTS 4
+#define CONFIG_USBHOST_MAX_INTERFACES 6
+#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 1
+#define CONFIG_USBHOST_MAX_ENDPOINTS 4
+
+#define CONFIG_USBHOST_DEV_NAMELEN 16
+
+#ifndef CONFIG_USBHOST_PSC_PRIO
+#define CONFIG_USBHOST_PSC_PRIO 4
+#endif
+#ifndef CONFIG_USBHOST_PSC_STACKSIZE
+#define CONFIG_USBHOST_PSC_STACKSIZE 2048
+#endif
+
+/* Ep0 max transfer buffer */
+#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
+
+#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
+#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
+#endif
+
+#ifndef CONFIG_USBHOST_MSC_TIMEOUT
+#define CONFIG_USBHOST_MSC_TIMEOUT 5000
+#endif
+
+/* ================ USB Device Port Configuration ================*/
+
+/* Phytium-E2000 instance-0 */
+#define CONFIG_XHCI_BASE_ADDR 0x31A08000U
+#define CONFIG_XHCI_IRQ_NUM 48U
+
+/* Phytium-E2000 instance-1 */
+// #define CONFIG_XHCI_BASE_ADDR 0x31A28000U
+// #define CONFIG_XHCI_IRQ_NUM 49U
+
+#define CONFIG_XHCI_PAGE_SIZE 4096U
+#define CONFIG_XHCI_PAGE_SHIFT 12U
+
+/* ================ USB Host Port Configuration ==================*/
+
+#define CONFIG_USBHOST_PIPE_NUM 10
+
+/* ================ XHCI Configuration ================ */
+#define CONFIG_USBHOST_XHCI
+
+#endif
diff --git a/port/xhci/usb_hc_xhci.c b/port/xhci/usb_hc_xhci.c
new file mode 100644
index 00000000..da07da8d
--- /dev/null
+++ b/port/xhci/usb_hc_xhci.c
@@ -0,0 +1,1218 @@
+/*
+ * 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 files is for xhci function implementation
+ *
+ * Modify History:
+ * Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0 zhugengyu 2022/9/19 init commit
+ */
+
+/***************************** Include Files *********************************/
+#include "usbh_core.h"
+#include "usbh_hub.h"
+#include "xhci_reg.h"
+#include "usb_hc_xhci.h"
+
+/************************** Constant Definitions *****************************/
+
+/************************** Variable Definitions *****************************/
+/* input is xhci speed */
+static const char *speed_name[16] = {
+ [ 0 ] = " - ",
+ [ 1 ] = "Full",
+ [ 2 ] = "Low",
+ [ 3 ] = "High",
+ [ 4 ] = "Super",
+};
+
+static const int speed_from_xhci[16] = {
+ [ 0 ] = -1,
+ [ 1 ] = USB_SPEED_FULL,
+ [ 2 ] = USB_SPEED_LOW,
+ [ 3 ] = USB_SPEED_HIGH,
+ [ 4 ] = USB_SPEED_SUPER,
+ [ 5 ... 15 ] = -1,
+};
+
+static const int speed_to_xhci[] = {
+ [ USB_SPEED_FULL ] = 1,
+ [ USB_SPEED_LOW ] = 2,
+ [ USB_SPEED_HIGH ] = 3,
+ [ USB_SPEED_SUPER ] = 4,
+};
+
+static volatile struct xhci_pipe *cur_cmd_pipe = NULL; /* pass current command pipe to interrupt */
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Function Prototypes ******************************/
+
+/*****************************************************************************/
+/* Wait until bit = value or timeout */
+static int wait_bit(unsigned long reg_off, uint32_t mask, uint32_t value, uint32_t timeout)
+{
+ uint32_t delay = 0U; /* calc wait end time */
+
+ while ((readl(reg_off) & mask) != value) {
+ if (++delay > timeout) { /* check if timeout */
+ USB_LOG_ERR("wait timeout !!!\n");
+ return -1;
+ }
+ usb_osal_msleep(1U);
+ }
+ return 0;
+}
+
+/* Check if device attached to port */
+static void xhci_print_port_state(const char *prefix, uint32_t port, uint32_t portsc)
+{
+ uint32_t pls = XHCI_REG_OP_PORTS_PORTSC_PLS_GET(portsc);
+ uint32_t speed = XHCI_REG_OP_PORTS_PORTSC_PORT_SPEED_GET(portsc);
+
+ USB_LOG_DBG("%s port #%d: 0x%08x,%s%s pls %d, speed %d [%s]\n",
+ prefix, port + 1, portsc,
+ (portsc & XHCI_REG_OP_PORTS_PORTSC_PP) ? " powered," : "",
+ (portsc & XHCI_REG_OP_PORTS_PORTSC_PED) ? " enabled," : "",
+ pls, speed, speed_name[speed]);
+}
+
+static inline uint32_t xhci_readl_port(struct xhci_s *xhci, uint32_t port, uint32_t offset)
+{
+ /* Operational Base + (400h + (10h * (n–1))) */
+ return readl(xhci->pr + port * XHCI_REG_OP_PORTS_SIZE + offset);
+}
+
+static inline void xhci_writel_port(struct xhci_s *xhci, uint32_t port, uint32_t offset, uint32_t val)
+{
+ /* Operational Base + (400h + (10h * (n–1))) */
+ return writel(xhci->pr + port * XHCI_REG_OP_PORTS_SIZE + offset, val);
+}
+
+static void xhci_setup_mmio(struct xhci_s *xhci, unsigned long base_addr)
+{
+ xhci->base = base_addr;
+ xhci->caps = xhci->base;
+
+ /* add to register base to find the beginning of the Operational Register Space */
+ xhci->op = xhci->base + readb(xhci->caps + XHCI_REG_CAP_CAPLENGTH);
+ xhci->db = xhci->base + XHCI_REG_CAP_DBOFF_GET(readl(xhci->caps + XHCI_REG_CAP_DBOFF));
+ xhci->ir = xhci->base + XHCI_REG_CAP_RTSOFF_GET(readl(xhci->caps + XHCI_REG_CAP_RTSOFF)) +
+ XHCI_REG_RT_IR0;
+ xhci->pr = xhci->op + XHCI_REG_OP_PORTS_BASE;
+
+ /* cache static information of CAP_HCSPARAMS */
+ xhci->hcs[0] = readl(xhci->caps + XHCI_REG_CAP_HCS1);
+ xhci->hcs[1] = readl(xhci->caps + XHCI_REG_CAP_HCS2);
+ xhci->hcs[2] = readl(xhci->caps + XHCI_REG_CAP_HCS3);
+ xhci->hcc = readl(xhci->caps + XHCI_REG_CAP_HCC);
+
+ /* avoid access XHCI_REG_CAP_HCIVERSION = 0x2, unaligned memory */
+ xhci->version = ((readl(xhci->caps + XHCI_REG_CAP_CAPLENGTH) >> 16) & 0xffff);
+
+ xhci->ports = XHCI_REG_CAP_HCS1_MAX_PORTS_GET(xhci->hcs[0]); /* bit[31:24] max ports */
+ xhci->slots = XHCI_REG_CAP_HCS1_MAX_SLOTS_GET(xhci->hcs[0]); /* bit[7:0] max device slots */
+
+ /* For example, using the offset of Base is 1000h and the xECP value of 0068h, we can calculated
+ the following effective address of the first extended capability:
+ 1000h + (0068h << 2) -> 1000h + 01A0h -> 11A0h */
+ xhci->xcap = XHCI_REG_CAP_HCC_XECP_GET(xhci->hcc) << 2; /* bit[31:16] xHCI extended cap pointer */
+ xhci->context64 = (XHCI_REG_CAP_HCC_CSZ & xhci->hcc) ? true : false;
+
+ USB_LOG_INFO(" hc version: 0x%x\n", xhci->version);
+ USB_LOG_INFO(" mmio base: 0x%x\n", xhci->base);
+ USB_LOG_INFO(" oper base: 0x%x\n", xhci->op);
+ USB_LOG_INFO(" doorbell base: 0x%x\n", xhci->db);
+ USB_LOG_INFO(" runtime base: 0x%x\n", xhci->ir);
+ USB_LOG_INFO(" port base: 0x%x\n", xhci->pr);
+ USB_LOG_INFO(" xcap base: 0x%x\n", xhci->xcap);
+
+ USB_LOG_INFO(" slot num: 0x%x\n", xhci->slots);
+ USB_LOG_INFO(" port num: 0x%x\n", xhci->ports);
+ USB_LOG_INFO(" context: %d bit\n", xhci->context64 ? 64 : 32);
+}
+
+
+/* Reset device on port */
+static int xhci_hub_reset(struct xhci_s *xhci, uint32_t port)
+{
+ uint32_t portsc = xhci_readl_port(xhci, port, XHCI_REG_OP_PORTS_PORTSC);
+ if (!(portsc & XHCI_REG_OP_PORTS_PORTSC_CCS)) /* double check if connected */
+ /* Device no longer connected?! */
+ return -1;
+
+ switch (XHCI_REG_OP_PORTS_PORTSC_PLS_GET(portsc)) {
+ case PLS_U0:
+ /* A USB3 port - controller automatically performs reset */
+ break;
+ case PLS_POLLING:
+ /* A USB2 port - perform device reset */
+ xhci_print_port_state(__func__, port, portsc);
+ xhci_writel_port(xhci, port, XHCI_REG_OP_PORTS_PORTSC,
+ portsc | XHCI_REG_OP_PORTS_PORTSC_PR); /* reset port */
+ break;
+ default:
+ return -1;
+ }
+
+ // Wait for device to complete reset and be enabled
+ uint32_t end = 1000U, start = 0U;
+ for (;;) {
+ portsc = xhci_readl_port(xhci, port, XHCI_REG_OP_PORTS_PORTSC);
+ if (!(portsc & XHCI_REG_OP_PORTS_PORTSC_CCS))
+ /* Device disconnected during reset */
+ return -1;
+
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_PED) /* check if port enabled */
+ /* Reset complete */
+ break;
+
+ if (++start > end) {
+ USB_LOG_ERR("wait timeout, portsc=0x%x!!!\n", portsc);
+ return -1;
+ }
+
+ usb_osal_msleep(1);
+ }
+
+ int rc = speed_from_xhci[XHCI_REG_OP_PORTS_PORTSC_PORT_SPEED_GET(portsc)];
+ xhci_print_port_state("XHCI", port, portsc);
+ return rc;
+}
+
+/* Add a TRB to the given ring */
+static void xhci_trb_fill(struct xhci_ring *ring, void *data, uint32_t xferlen, uint32_t flags)
+{
+ struct xhci_trb *dst = &ring->ring[ring->nidx];
+ if (flags & TRB_TR_IDT) {
+ memcpy(&dst->ptr_low, data, xferlen);
+ } else {
+ dst->ptr_low = (uint32_t)(unsigned long)data;
+#ifdef XHCI_AARCH64
+ dst->ptr_high = (uint32_t)((uint64_t)data >> 32U);
+#else
+ dst->ptr_high = 0U;
+#endif
+ }
+ dst->status = xferlen;
+ /* cycle bit */
+ dst->control = flags | (ring->cs ? TRB_C : 0);
+}
+
+/* Queue a TRB onto a ring, wrapping ring as needed */
+static void xhci_trb_queue(struct xhci_ring *ring, void *data, uint32_t xferlen, uint32_t flags)
+{
+ if (ring->nidx >= ARRAY_SIZE(ring->ring) - 1) { /* if it is the last trb in the list */
+ /* indicate the end of ring, bit[1], toggle cycle = 1, xHc shall toggle cycle bit interpretation */
+ xhci_trb_fill(ring, ring->ring, 0, (TR_LINK << 10) | TRB_LK_TC);
+ ring->nidx = 0; /* adjust dequeue index to 0 */
+ ring->cs ^= 1; /* toggle cycle interpretation of sw */
+ }
+
+ xhci_trb_fill(ring, data, xferlen, flags);
+ ring->nidx++; /* ahead dequeue index */
+}
+
+/* Signal the hardware to process events on a TRB ring */
+static void xhci_doorbell(struct xhci_s *xhci, uint32_t slotid, uint32_t value)
+{
+ writel(xhci->db + slotid * XHCI_REG_DB_SIZE, value); /* bit[7:0] db target, is ep_id */
+}
+
+/* Wait for a ring to empty (all TRBs processed by hardware) */
+static int xhci_event_wait(struct xhci_s *xhci,
+ struct xhci_pipe *pipe,
+ struct xhci_ring *ring)
+{
+ int ret = CC_SUCCESS;
+
+ if (pipe->timeout > 0){
+ ret = usb_osal_sem_take(pipe->waitsem, pipe->timeout);
+ if (ret < 0) {
+ ret = CC_TIMEOUT;
+ } else {
+ ret = TRB_CC_GET(ring->evt.status); /* bit[31:24] completion code */
+ }
+ }
+
+ return ret;
+}
+
+/* Submit a command to the xhci controller ring */
+static int xhci_cmd_submit(struct xhci_s *xhci, struct xhci_inctx *inctx,
+ struct xhci_pipe *pipe, uint32_t flags)
+{
+ if (inctx) {
+ struct xhci_slotctx *slot = (void*)&inctx[1 << xhci->context64];
+ uint32_t port = XHCI_SLOTCTX_1_ROOT_PORT_GET(slot->ctx[1]) - 1;
+ USB_LOG_DBG("port=%d\n", port);
+ uint32_t portsc = xhci_readl_port(xhci, port, XHCI_REG_OP_PORTS_PORTSC);
+ if (!(portsc & XHCI_REG_OP_PORTS_PORTSC_CCS)) {
+ /* Device no longer connected?! */
+ xhci_print_port_state(__func__, port, portsc);
+ return CC_DISCONNECTED;
+ }
+ }
+
+ usb_osal_mutex_take(xhci->cmds->lock); /* handle command one by one */
+
+ pipe->timeout = 5000;
+ pipe->waiter = true;
+ cur_cmd_pipe = pipe;
+
+ xhci_trb_queue(xhci->cmds, inctx, 0, flags);
+
+ /* pass command trb to hardware */
+ DSB();
+
+ xhci_doorbell(xhci, 0, 0); /* 0 = db host controller, 0 = db targe hc command */
+ int rc = xhci_event_wait(xhci, pipe, xhci->cmds);
+
+ usb_osal_mutex_give(xhci->cmds->lock);
+
+ return rc;
+}
+
+static int xhci_cmd_nop(struct xhci_s *xhci, struct xhci_pipe *pipe)
+{
+ USB_LOG_DBG("%s\n", __func__);
+ return xhci_cmd_submit(xhci, NULL, pipe, TRB_TYPE_SET(CR_NOOP));
+}
+
+static int xhci_cmd_enable_slot(struct xhci_s *xhci, struct xhci_pipe *pipe)
+{
+ int cc = xhci_cmd_submit(xhci, NULL, pipe, TRB_TYPE_SET(CR_ENABLE_SLOT));
+ if (cc != CC_SUCCESS)
+ return cc;
+
+ struct xhci_trb *evt = &(xhci->cmds->evt);
+ return TRB_CR_SLOTID_GET(evt->control); /* bit [31:24] slot id */
+}
+
+static int xhci_cmd_disable_slot(struct xhci_s *xhci, struct xhci_pipe *pipe)
+{
+ USB_LOG_DBG("%s: slotid %d\n", __func__, pipe->slotid);
+ return xhci_cmd_submit(xhci, NULL, pipe, TRB_TYPE_SET(CR_DISABLE_SLOT) | TRB_CR_SLOTID_SET(pipe->slotid));
+}
+
+static int xhci_cmd_address_device(struct xhci_s *xhci, struct xhci_pipe *pipe, struct xhci_inctx *inctx)
+{
+ USB_LOG_DBG("%s: slotid %d\n", __func__, pipe->slotid);
+ return xhci_cmd_submit(xhci, inctx, pipe, TRB_TYPE_SET(CR_ADDRESS_DEVICE) | TRB_CR_SLOTID_SET(pipe->slotid));
+}
+
+static int xhci_cmd_configure_endpoint(struct xhci_s *xhci, struct xhci_pipe *pipe, struct xhci_inctx *inctx)
+{
+ USB_LOG_DBG("%s: slotid %d\n", __func__, pipe->slotid);
+ return xhci_cmd_submit(xhci, inctx, pipe, TRB_TYPE_SET(CR_CONFIGURE_ENDPOINT) | TRB_CR_SLOTID_SET(pipe->slotid));
+}
+
+static int xhci_cmd_evaluate_context(struct xhci_s *xhci, struct xhci_pipe *pipe, struct xhci_inctx *inctx)
+{
+ USB_LOG_DBG("%s: slotid %d\n", __func__, pipe->slotid);
+ /* bit[15:10] TRB type, bit[31:24] Slot id */
+ return xhci_cmd_submit(xhci, inctx, pipe, TRB_TYPE_SET(CR_EVALUATE_CONTEXT) | TRB_CR_SLOTID_SET(pipe->slotid));
+}
+
+static int xhci_controller_configure(struct xhci_s *xhci)
+{
+ uint32_t reg;
+
+ /* trbs */
+ xhci->devs = usb_align(XHCI_ALIGMENT, sizeof(*xhci->devs) * (xhci->slots + 1)); /* device slot */
+ xhci->eseg = usb_align(XHCI_ALIGMENT, sizeof(*xhci->eseg)); /* event segment */
+ xhci->cmds = usb_align(XHCI_RING_SIZE, sizeof(*xhci->cmds)); /* command ring */
+ xhci->evts = usb_align(XHCI_RING_SIZE, sizeof(*xhci->evts)); /* event ring */
+
+ if (!xhci->devs || !xhci->cmds || !xhci->evts || !xhci->eseg) {
+ USB_LOG_ERR("allocate memory failed !!!\n");
+ goto fail;
+ }
+
+ memset(xhci->devs, 0U, sizeof(*xhci->devs) * (xhci->slots + 1));
+ memset(xhci->cmds, 0U, sizeof(*xhci->cmds));
+ memset(xhci->evts, 0U, sizeof(*xhci->evts));
+ memset(xhci->eseg, 0U, sizeof(*xhci->eseg));
+
+ xhci->cmds->lock = usb_osal_mutex_create();
+ USB_ASSERT(xhci->cmds->lock);
+
+ reg = readl(xhci->op + XHCI_REG_OP_USBCMD);
+ if (reg & XHCI_REG_OP_USBCMD_RUN_STOP) { /* if xHc running, stop it first */
+ reg &= ~XHCI_REG_OP_USBCMD_RUN_STOP;
+ writel(xhci->op + XHCI_REG_OP_USBCMD, reg); /* stop xHc */
+
+ if (wait_bit(xhci->op + XHCI_REG_OP_USBSTS,
+ XHCI_REG_OP_USBSTS_HCH, XHCI_REG_OP_USBSTS_HCH, 32) != 0) /* wait xHc halt */
+ goto fail;
+ }
+
+ USB_LOG_DBG("%s: resetting\n", __func__);
+
+ writel(xhci->op + XHCI_REG_OP_USBCMD, XHCI_REG_OP_USBCMD_HCRST); /* reset xHc */
+ if (wait_bit(xhci->op + XHCI_REG_OP_USBCMD, XHCI_REG_OP_USBCMD_HCRST, 0, 1000) != 0) /* wait reset process done */
+ goto fail;
+
+ if (wait_bit(xhci->op + XHCI_REG_OP_USBSTS, XHCI_REG_OP_USBSTS_CNR, 0, 1000) != 0) /* wait until xHc ready */
+ goto fail;
+
+ writel(xhci->op + XHCI_REG_OP_CONFIG, xhci->slots); /* bit[7:0], set max num of device slot enabled */
+ writeq(xhci->op + XHCI_REG_OP_DCBAAP, (uint64_t)xhci->devs); /* bit[63:6] device context base address array pointer */
+ writeq(xhci->op + XHCI_REG_OP_CRCR, (uint64_t)xhci->cmds | 1); /* command ring pointer, cycle state = 1 */
+ xhci->cmds->cs = 1; /* cycle state = 1 */
+
+ xhci->eseg->ptr_low = (uint32_t)((unsigned long)xhci->evts); /* event ring pointer */
+#ifdef XHCI_AARCH64
+ xhci->eseg->ptr_high = (uint32_t)((unsigned long)xhci->evts >> 32U);
+#else
+ xhci->eseg->ptr_high = 0U;
+#endif
+
+ xhci->eseg->size = XHCI_RING_ITEMS; /* items of event ring TRB */
+ writel(xhci->ir + XHCI_REG_RT_IR_ERSTSZ, 1); /* bit[15:0] event ring segment table size */
+ writeq(xhci->ir + XHCI_REG_RT_IR_ERDP, (uint64_t)xhci->evts); /* bit[63:4] event ring dequeue pointer */
+ writeq(xhci->ir + XHCI_REG_RT_IR_ERSTBA, (uint64_t)xhci->eseg); /* bit[63:6] event ring segment table base addr */
+ xhci->evts->cs = 1; /* cycle state = 1 */
+
+ reg = xhci->hcs[1];
+ uint32_t spb = XHCI_REG_CAP_HCS2_MAX_SCRATCHPAD_BUFS_GET(reg); /* bit [25:21] | bit [31:27] max scratchpad buffers */
+ if (spb) {
+ /* reserve scratchpad buffers for xHc */
+ USB_LOG_DBG("%s: setup %d scratch pad buffers\n", __func__, spb);
+ uint64_t *spba = usb_align(XHCI_ALIGMENT, sizeof(*spba) * spb); /* base addr of scratchpad buffers */
+ void *pad = usb_align(CONFIG_XHCI_PAGE_SIZE, CONFIG_XHCI_PAGE_SIZE * spb); /* the whole scratchpad buffers */
+ if (!spba || !pad) {
+ USB_LOG_ERR("allocate memory failed !!!\n");
+ usb_free(spba);
+ usb_free(pad);
+ goto fail;
+ }
+ for (uint32_t i = 0; i < spb; i++)
+ spba[i] = (uint64_t)(pad + (i * CONFIG_XHCI_PAGE_SIZE)); /* assign base addr for each pad */
+ xhci->devs[0].ptr_low = (uint32_t)((unsigned long)spba); /* bit[63:6] scratchpad buffers base addr */
+#ifdef XHCI_AARCH64
+ xhci->devs[0].ptr_high = (uint32_t)((uint64_t)spba >> 32U);
+#else
+ xhci->devs[0].ptr_high = 0U;
+#endif
+ }
+
+ /* enable port interrupt */
+ writel(xhci->ir + XHCI_REG_RT_IR_IMOD, 500U);
+ reg = readl(xhci->ir + XHCI_REG_RT_IR_IMAN);
+ reg |= XHCI_REG_RT_IR_IMAN_IE;
+ writel(xhci->ir + + XHCI_REG_RT_IR_IMAN, reg);
+
+ reg = readl(xhci->op + XHCI_REG_OP_USBCMD);
+ reg |= XHCI_REG_OP_USBCMD_INTE; /* enable interrupt */
+ writel(xhci->op + XHCI_REG_OP_USBCMD, reg);
+
+ USB_LOG_DBG("Start xHc ....\n");
+
+ reg = readl(xhci->op + XHCI_REG_OP_USBCMD);
+ reg |= XHCI_REG_OP_USBCMD_RUN_STOP; /* start xHc */
+ writel(xhci->op + XHCI_REG_OP_USBCMD, reg);
+
+ return 0U; /* Success */
+fail:
+ USB_LOG_ERR("Configure Roothub failed !!!\n");
+ usb_free(xhci->eseg);
+ usb_free(xhci->evts);
+ usb_free(xhci->cmds);
+ usb_free(xhci->devs);
+ return -1; /* Failed */
+}
+
+static void xhci_check_xcap(struct xhci_s *xhci)
+{
+ if (xhci->xcap) { /* read Extended Capabilities */
+ uint32_t off;
+ unsigned long addr = xhci->base + xhci->xcap; /* start read ext-cap */
+
+ do {
+ unsigned long xcap = addr;
+ uint32_t ports, name, cap = readl(xcap + XHCI_REG_EXT_CAP_USBSPCF_OFFSET);
+ switch (XHCI_REG_EXT_CAP_CAP_ID_GET(cap)) {
+ case XHCI_EXT_CAP_ID_SUPPORT_PROTOCOL: /* 0x2, supported protocol */
+ name = readl(xcap + XHCI_REG_EXT_CAP_USBSPCFDEF_OFFSET);
+ ports = readl(xcap + XHCI_REG_EXT_CAP_USBSPCFDEF2_OFFSET);
+ uint8_t major = XHCI_USBSPCF_MAJOR_REVERSION_GET(cap);
+ uint8_t minor = XHCI_USBSPCF_MINOR_REVERSION_GET(cap);
+ uint8_t count = XHCI_USBSPCFDEF2_COMPATIBLE_PORT_CNT_GET(ports);
+ uint8_t start = XHCI_USBSPCFDEF2_COMPATIBLE_PORT_OFF_GET(ports);
+ USB_LOG_INFO("XHCI protocol %c%c%c%c %x.%02x"
+ ", %d ports (offset %d), def %x\n"
+ , (name >> 0) & 0xff
+ , (name >> 8) & 0xff
+ , (name >> 16) & 0xff
+ , (name >> 24) & 0xff /* Print string 'USB' */
+ , major, minor
+ , count, start
+ , ports >> 16);
+ if (name == XHCI_USBSPCFDEF_NAME_STRING_USB /* ASCII "USB " */) {
+ if (major == 2) {
+ xhci->usb2.start = start; /* USB 2.0 port range */
+ xhci->usb2.count = count;
+ }
+ if (major == 3) {
+ xhci->usb3.start = start; /* USB 3.0 port range */
+ xhci->usb3.count = count;
+ }
+ }
+ break;
+ default:
+ USB_LOG_INFO("XHCI extcap 0x%x @ %p\n",
+ XHCI_REG_EXT_CAP_CAP_ID_GET(cap), addr);
+ break;
+ }
+ off = XHCI_REG_EXT_NEXT_CAP_PTR_GET(cap);
+ addr += off << 2; /* addr of next ext-cap */
+ } while (off > 0);
+ }
+}
+
+static int xhci_controller_setup(struct xhci_s *xhci, unsigned long baseaddr)
+{
+ USB_LOG_INFO("%s@0x%x\n", __func__, baseaddr);
+
+ /* get register offset */
+ xhci_setup_mmio(xhci, baseaddr);
+ if (xhci->version < 0x96 || xhci->version > 0x120) {
+ USB_LOG_ERR("xHCI-0x%x not support\n", xhci->version);
+ return -1;
+ }
+
+ xhci_check_xcap(xhci);
+
+ uint32_t pagesize = readl(xhci->op + XHCI_REG_OP_PAGESIZE); /* get page-size */
+ USB_LOG_INFO("XHCI page size %d \n", (pagesize << CONFIG_XHCI_PAGE_SHIFT));
+ if (CONFIG_XHCI_PAGE_SIZE != (pagesize << CONFIG_XHCI_PAGE_SHIFT)) {
+ USB_LOG_ERR("XHCI driver does not support page size code %d\n"
+ , pagesize << CONFIG_XHCI_PAGE_SHIFT);
+ return -1;
+ }
+
+ USB_LOG_INFO("config XHCI ....\n");
+ if (xhci_controller_configure(xhci)) {
+ USB_LOG_ERR("init XHCI failed !!!\n");
+ return -1;
+ } else {
+ USB_LOG_INFO("init XHCI success !!!\n");
+ }
+
+ return 0;
+}
+
+static struct xhci_inctx *xhci_alloc_inctx(struct xhci_s *xhci, struct usbh_hubport *hport, int maxepid)
+{
+ USB_ASSERT(xhci && hport);
+
+ int size = (sizeof(struct xhci_inctx) * XHCI_INCTX_ENTRY_NUM) << xhci->context64;
+ struct xhci_inctx *in = usb_align(XHCI_INCTX_ALIGMENT << xhci->context64, size);
+ int devport = hport->port;
+
+ if (!in) {
+ USB_LOG_ERR("allocate memory failed !!!\n");
+ return NULL;
+ }
+ memset(in, 0, size);
+
+ struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64]; /* slot context */
+ slot->ctx[0] |= XHCI_SLOTCTX_0_MAX_EPID_SET(maxepid); /* bit[31:27] index of the last valid ep context */
+ slot->ctx[0] |= XHCI_SLOTCTX_0_SPEED_SET(speed_to_xhci[hport->speed]); /* bit[23:20] speed of this device */
+
+ /* Set high-speed hub flags. */
+ struct usbh_hub *hubdev = hport->parent;
+ USB_ASSERT(hubdev);
+ if (!hubdev->is_roothub) { /* if device is not under roothub */
+ struct usbh_hubport *hub_port = hubdev->parent;
+ if (hport->speed == USB_SPEED_LOW || hport->speed == USB_SPEED_FULL) {
+ if (hub_port->speed == USB_SPEED_HIGH) {
+ slot->ctx[2] |= XHCI_SLOTCTX_2_HUB_SLOT_SET(hub_port->dev_addr); /* bit[7:0] parent hub slot id */
+ slot->ctx[2] |= XHCI_SLOTCTX_2_HUB_PORT_SET(hport->port); /* bit[15:8] parent port num */
+ } else {
+ struct xhci_slotctx *hslot = (void*)(unsigned long)xhci->devs[hub_port->dev_addr].ptr_low;
+ slot->ctx[2] = hslot->ctx[2]; /* 08h, copy hub slot context */
+ }
+ }
+
+ uint32_t route = 0U;
+ do {
+ route <<= 4;
+ route |= (hport->port) & 0xf; /* record port for each tire */
+
+ hport = hubdev->parent;
+ hubdev = hport->parent;
+ } while ((!hubdev) || (!hubdev->is_roothub));
+
+ slot->ctx[0] |= XHCI_SLOTCTX_0_ROUTE_SET(route); /* bit[19:0] route string, max 5 tires */
+ }
+
+ /* refer to spec. Ports are numbered from 1 to MaxPorts. */
+ slot->ctx[1] |= XHCI_SLOTCTX_1_ROOT_PORT_SET(hport->port); /* bit[23:16] root hub port number */
+
+ return in;
+}
+
+
+// Submit a USB "setup" message request to the pipe's ring
+static void xhci_xfer_setup(struct xhci_s *xhci, struct xhci_pipe *pipe,
+ bool dir_in, void *cmd, void *data, int datalen)
+{
+ /* SETUP TRB ctrl, bit[15:10] trb type
+ bit[6] Immediate Data (IDT), parameters take effect
+ bit[17:16] Transfer type, 2 = OUT Data, 3 = IN Data */
+ uint32_t trans_type = (datalen > 0) ? (dir_in ? TRB_TR_IN_DATA : TRB_TR_OUT_DATA): TRB_TR_NO_DATA;
+ xhci_trb_queue(&pipe->reqs, cmd, USB_SIZEOF_SETUP_PACKET,
+ TRB_TYPE_SET(TR_SETUP) | TRB_TR_IDT | TRB_TR_TYPE_SET(trans_type));
+
+ /* DATA TRB ctrl, bit[15:10] trb type
+ bit[16] Direction, 0 = OUT, 1 = IN */
+ if (datalen) {
+ xhci_trb_queue(&pipe->reqs, data, datalen,
+ TRB_TYPE_SET(TR_DATA) | (dir_in ? TRB_TR_DIR : 0));
+ }
+
+ /* STATUS TRB ctrl, bit[5] Interrupt On Completion (IOC).
+ bit[16] Direction, 0 = OUT, 1 = IN */
+ xhci_trb_queue(&pipe->reqs, NULL, 0,
+ TRB_TYPE_SET(TR_STATUS) | TRB_TR_IOC | ((dir_in ? 0 : TRB_TR_DIR)));
+
+ /* pass command trb to hardware */
+ DSB();
+
+ /* notfiy xHc that device slot - epid */
+ xhci_doorbell(xhci, pipe->slotid, pipe->epid);
+}
+
+/* Submit a USB transfer request to the pipe's ring */
+static void xhci_xfer_normal(struct xhci_s *xhci, struct xhci_pipe *pipe,
+ void *data, int datalen)
+{
+ /* Normal trb, used in bulk and interrupt transfer */
+ xhci_trb_queue(&pipe->reqs, data, datalen, TRB_TYPE_SET(TR_NORMAL) | TRB_TR_IOC);
+
+ /* pass command trb to hardware */
+ DSB();
+
+ xhci_doorbell(xhci, pipe->slotid, pipe->epid);
+}
+
+/* -------------------------------------------------------------- */
+/* port functions */
+static struct xhci_s xhci_host;
+
+__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()
+{
+}
+
+int usb_hc_init(void)
+{
+ usb_hc_low_level_init();
+
+ memset(&xhci_host, 0, sizeof(xhci_host));
+ if (xhci_controller_setup(&xhci_host, CONFIG_XHCI_BASE_ADDR))
+ return -1;
+
+ return 0;
+}
+
+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_s *xhci = &xhci_host;
+
+ nports = CONFIG_USBHOST_MAX_RHPORTS;
+
+ port = setup->wIndex;
+ if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) {
+ switch (setup->bRequest) {
+ case HUB_REQUEST_CLEAR_FEATURE:
+ switch (setup->wValue) {
+ case HUB_FEATURE_HUB_C_LOCALPOWER:
+ break;
+ case HUB_FEATURE_HUB_C_OVERCURRENT:
+ break;
+ default:
+ return -EPIPE;
+ }
+ break;
+ case HUB_REQUEST_SET_FEATURE:
+ switch (setup->wValue) {
+ case HUB_FEATURE_HUB_C_LOCALPOWER:
+ break;
+ case HUB_FEATURE_HUB_C_OVERCURRENT:
+ break;
+ default:
+ return -EPIPE;
+ }
+ break;
+ case HUB_REQUEST_GET_DESCRIPTOR:
+ break;
+ case HUB_REQUEST_GET_STATUS:
+ 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 = xhci_readl_port(xhci, port - 1, XHCI_REG_OP_PORTS_PORTSC);
+
+ 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_REG_OP_PORTS_PORTSC_CSC;
+ break;
+ case HUB_PORT_FEATURE_C_ENABLE:
+ portsc |= XHCI_REG_OP_PORTS_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_REG_OP_PORTS_PORTSC_RW_MASK;
+ xhci_writel_port(xhci, port - 1, XHCI_REG_OP_PORTS_PORTSC, pclear); /* clear port status */
+
+ 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_hub_reset(xhci, port - 1);
+ break;
+
+ default:
+ return -EPIPE;
+ }
+ break;
+ case HUB_REQUEST_GET_STATUS:
+ if (!port || port > nports) {
+ return -EPIPE;
+ }
+
+ portsc = xhci_readl_port(xhci, port - 1, XHCI_REG_OP_PORTS_PORTSC);
+
+ status = 0;
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_CSC) {
+ /* Port connection status changed */
+ status |= (1 << HUB_PORT_FEATURE_C_CONNECTION);
+ }
+
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_PEC) {
+ /* Port enabled status changed */
+ status |= (1 << HUB_PORT_FEATURE_C_ENABLE);
+ }
+
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_OCC) {
+ /* Port status changed due to over-current */
+ status |= (1 << HUB_PORT_FEATURE_C_OVER_CURREN);
+ }
+
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_CCS) {
+ /* Port connected */
+ status |= (1 << HUB_PORT_FEATURE_CONNECTION);
+ }
+
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_PED) {
+ /* Port enabled */
+ status |= (1 << HUB_PORT_FEATURE_ENABLE);
+
+ const int speed = speed_from_xhci[XHCI_REG_OP_PORTS_PORTSC_PORT_SPEED_GET(portsc)];
+ if (speed == USB_SPEED_LOW) {
+ status |= (1 << HUB_PORT_FEATURE_LOWSPEED);
+ } else if ((speed == USB_SPEED_HIGH) || (speed == USB_SPEED_SUPER) ||
+ (speed == USB_SPEED_FULL)) {
+ status |= (1 << HUB_PORT_FEATURE_HIGHSPEED);
+ }
+ }
+
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_OCA) {
+ /* Over-current condition */
+ status |= (1 << HUB_PORT_FEATURE_OVERCURRENT);
+ }
+
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_PR) {
+ /* Reset is in progress */
+ status |= (1 << HUB_PORT_FEATURE_RESET);
+ }
+
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_PP) {
+ /* Port is not power off */
+ status |= (1 << HUB_PORT_FEATURE_POWER);
+ }
+ memcpy(buf, &status, 4);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int usbh_get_xhci_devaddr(usbh_pipe_t *pipe)
+{
+ struct xhci_pipe *ppipe = (struct xhci_pipe *)pipe;
+ return ppipe->slotid;
+}
+
+int usbh_ep0_pipe_reconfigure(usbh_pipe_t pipe, uint8_t dev_addr, uint8_t ep_mps, uint8_t speed)
+{
+ int ret = 0;
+ struct xhci_s *xhci = &xhci_host;
+ struct xhci_pipe *ppipe = (struct xhci_pipe *)pipe;
+ int oldmaxpacket = ppipe->maxpacket; /* original max packetsz */
+
+ if (ep_mps != oldmaxpacket) {
+ /* maxpacket has changed on control endpoint - update controller. */
+ struct xhci_inctx *in = xhci_alloc_inctx(xhci, ppipe->hport, 1); /* allocate input context */
+ if (!in)
+ return -1;
+
+ in->add = (1 << 1); /* update ep0 context */
+
+ /*
+ input ctrl context
+ slot
+ ep-0 context, offset = 2 * xhci->context64, e.g, for 64 bit (0x40), offset = 0x80
+ */
+ struct xhci_epctx *ep = (void*)&in[2 << xhci->context64]; /* ep context */
+ ep->ctx[1] |= XHCI_EPCTX_1_MPS_SET(ppipe->maxpacket); /* bit[31:16] update maxpacket size */
+ int cc = xhci_cmd_evaluate_context(xhci, ppipe, in);
+ if (cc != CC_SUCCESS) {
+ USB_LOG_ERR("%s: reconf ctl endpoint: failed (cc %d)\n",
+ __func__, cc);
+ ret = -1;
+ } else {
+ ppipe->maxpacket = ep_mps; /* mps update success */
+ }
+
+ usb_free(in);
+ }
+
+ return ret;
+}
+
+static int usbh_get_period(int speed, int interval)
+{
+ if (speed != USB_SPEED_HIGH){
+ /* fls - find last (most-significant) bit set */
+ return (interval <= 4) ? 0 : fls(interval);
+ }
+
+ return (interval <= 4) ? 0 : interval - 4;
+}
+
+int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg)
+{
+ int ret = 0;
+ struct xhci_s *xhci = &xhci_host;
+ struct xhci_pipe *ppipe = usb_align(XHCI_RING_SIZE, sizeof(struct xhci_pipe));
+ struct usbh_hubport *hport = ep_cfg->hport;
+
+ uint32_t epid = 0U;
+ uint8_t eptype = 0U;
+
+ if (ppipe == NULL) {
+ return -ENOMEM;
+ }
+
+ memset(ppipe, 0, sizeof(struct xhci_pipe));
+
+ ppipe->epaddr = ep_cfg->ep_addr;
+ if (ep_cfg->ep_addr == 0) {
+ epid = 1; /* ep0, ep_id = 1 */
+ } else {
+ /* refer to spec. Figure 4-4: Endpoint Context Addressing
+ ep0 = 1, ep1-out = 2, ep1-in = 3, ... ep15-out = 30, ep15-in = 31 */
+ epid = (ep_cfg->ep_addr & 0x0f) * 2;
+ epid += (ep_cfg->ep_addr & USB_EP_DIR_IN) ? 1 : 0;
+ }
+ ppipe->epid = epid;
+ eptype = ep_cfg->ep_type;
+ ppipe->eptype = eptype;
+ ppipe->maxpacket = ep_cfg->ep_mps;
+ ppipe->interval = ep_cfg->ep_interval;
+ ppipe->speed = ep_cfg->hport->speed;
+ ppipe->hport = ep_cfg->hport;
+ ppipe->waitsem = usb_osal_sem_create(0);
+ ppipe->waiter = false;
+ ppipe->urb = NULL;
+
+ USB_LOG_DBG("%s epid = %d, eptype = %d, mps = %d, speed = %d, urb = %p\n",
+ __func__, ppipe->epid, ppipe->eptype, ppipe->maxpacket,
+ ppipe->speed, ppipe->urb);
+
+ ppipe->reqs.cs = 1; /* cycle state = 1 */
+
+ /* Allocate input context and initialize endpoint info. */
+ struct xhci_inctx *in = xhci_alloc_inctx(xhci, hport, epid);
+ if (!in){
+ ret = -1;
+ goto fail;
+ }
+
+ /* add slot context and ep context */
+ in->add = 0x01 /* Slot Context */ | (1 << epid); /* EP Context */
+ struct xhci_epctx *ep = (void*)&in[(ppipe->epid+1) << xhci->context64];
+ if (eptype == USB_ENDPOINT_TYPE_INTERRUPT)
+ ep->ctx[0] = XHCI_EPCTX_0_INTERVAL_SET(usbh_get_period(ppipe->speed, ppipe->interval) + 3); /* 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[1] |= eptype << 3; /* bit[5:3] endpoint type */
+ if (ppipe->epaddr & USB_EP_DIR_IN || eptype == USB_ENDPOINT_TYPE_CONTROL)
+ ep->ctx[1] |= 1 << 5; /* ep_type 4 ~ 7 */
+
+ ep->ctx[1] |= XHCI_EPCTX_1_MPS_SET(ppipe->maxpacket); /* bit[31:16] max packet size */
+ ep->deq_low = (uint32_t)((unsigned long)&ppipe->reqs.ring[0]); /* bit[63:4] tr dequeue pointer */
+ ep->deq_low |= 1; /* bit[0] dequeue cycle state */
+#ifdef XHCI_AARCH64
+ ep->deq_high = (uint32_t)((uint64_t)&ppipe->reqs.ring[0] >> 32U);
+#else
+ ep->deq_high = 0U;
+#endif
+ ep->length = XHCI_EPCTX_AVE_TRB_LEN_SET(ppipe->maxpacket); /* bit[15:0] average trb length */
+
+ if (ppipe->epid == 1) { /* when allocate ep-0, allocate device first */
+ struct usbh_hub *hubdev = hport->parent;
+ if (!hubdev->is_roothub){
+ /* make sure parent hub has been configured */
+ struct usbh_hubport *hubport = hubdev->parent;
+ struct xhci_pipe *hubep0 = (struct xhci_pipe *)hubport->ep0;
+ struct xhci_slotctx *hdslot = (void*)(unsigned long)xhci->devs[hubep0->slotid].ptr_low;
+ if (XHCI_SLOTCTX_3_SLOT_STATE_GET(hdslot->ctx[3]) != XHCI_SLOT_CONFIG) { /* bit [31:27] slot state, 3 means configured */
+ USB_LOG_ERR("%s parent hub-%d not yet configured\n", __func__, hubep0->slotid);
+ ret = -1;
+ goto fail;
+ }
+ }
+
+ /* enable slot. */
+ size_t size = (sizeof(struct xhci_slotctx) * XHCI_SLOTCTX_ENTRY_NUM) << xhci->context64;
+ struct xhci_slotctx *dev = usb_align(XHCI_SLOTCTX_ALIGMENT << xhci->context64, size);
+ if (!dev) {
+ USB_LOG_ERR("allocate memory failed !!!\n");
+ ret = -1;
+ goto fail;
+ }
+
+ /* send nop command to test if command ring ok */
+ for (int i = 0 ; i < 3; ++i) {
+ int cc = xhci_cmd_nop(xhci, ppipe);
+ if (cc != CC_SUCCESS) {
+ USB_LOG_ERR("%s: nop: failed\n", __func__);
+ usb_free(dev);
+ ret = -1;
+ goto fail;
+ }
+ }
+
+ int slotid = xhci_cmd_enable_slot(xhci, ppipe); /* get slot-id */
+ if (slotid < 0) {
+ USB_LOG_ERR("%s: enable slot: failed\n", __func__);
+ usb_free(dev);
+ ret = -1;
+ goto fail;
+ }
+
+ ppipe->slotid = slotid;
+ USB_LOG_DBG("%s: enable slot: got slotid %d\n", __func__, ppipe->slotid);
+ memset(dev, 0, size);
+ xhci->devs[slotid].ptr_low = (uint32_t)(unsigned long)dev; /* DCBAA */
+#ifdef XHCI_AARCH64
+ xhci->devs[slotid].ptr_high = (uint32_t)((uint64_t)dev >> 32U);
+#else
+ xhci->devs[slotid].ptr_high = 0;
+#endif
+
+ /* Send set_address command. */
+ int cc = xhci_cmd_address_device(xhci, ppipe, in);
+ if (cc != CC_SUCCESS) {
+ USB_LOG_ERR("%s: address device: failed (cc %d)\n", __func__, cc);
+ cc = xhci_cmd_disable_slot(xhci, ppipe);
+ if (cc != CC_SUCCESS) {
+ USB_LOG_ERR("%s: disable failed (cc %d)\n", __func__, cc);
+ ret = -1;
+ goto fail;
+ }
+
+ xhci->devs[slotid].ptr_low = 0; /* free DCBAA */
+ xhci->devs[slotid].ptr_high = 0;
+ usb_free(dev);
+
+ ret = -1;
+ goto fail;
+ }
+ } else { /* when allocate other ep, config ep */
+ struct xhci_pipe *defpipe = (struct xhci_pipe *)hport->ep0;
+ ppipe->slotid = defpipe->slotid;
+
+ /* Send configure command. */
+ int cc = xhci_cmd_configure_endpoint(xhci, defpipe, in);
+ if (cc != CC_SUCCESS) {
+ USB_LOG_ERR("%s: configure endpoint: failed (cc %d)\n", __func__, cc);
+ goto fail;
+ ret = -1;
+ }
+ }
+
+ *pipe = (usbh_pipe_t)ppipe;
+
+fail:
+ usb_free(in);
+ return ret;
+}
+
+int usbh_pipe_free(usbh_pipe_t pipe)
+{
+ int ret = 0;
+ struct xhci_s *xhci = &xhci_host;
+ struct xhci_pipe *ppipe = (struct xhci_pipe *)pipe;
+
+ if (!ppipe) {
+ return -EINVAL;
+ }
+
+ struct usbh_urb *urb = ppipe->urb;
+
+ if (urb) {
+ usbh_kill_urb(urb);
+ }
+
+ return -1;
+}
+
+int usbh_submit_urb(struct usbh_urb *urb)
+{
+ int ret = 0;
+ if (!urb || !urb->pipe) {
+ return -EINVAL;
+ }
+
+ struct xhci_s *xhci = &xhci_host;
+ struct xhci_pipe *ppipe = urb->pipe;
+ struct usb_setup_packet *setup = urb->setup;
+ size_t flags;
+
+ flags = usb_osal_enter_critical_section();
+
+ ppipe->waiter = false;
+ ppipe->urb = urb;
+ ppipe->timeout = urb->timeout;
+
+ if (ppipe->timeout > 0) {
+ ppipe->waiter = true;
+ }
+
+ usb_osal_leave_critical_section(flags);
+ switch (ppipe->eptype){
+ 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;
+ }
+
+ /* send setup in/out for command */
+ xhci_xfer_setup(xhci, ppipe, setup->bmRequestType & USB_EP_DIR_IN, (void*)setup,
+ urb->transfer_buffer, urb->transfer_buffer_length);
+ break;
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ case USB_ENDPOINT_TYPE_BULK:
+ xhci_xfer_normal(xhci, 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 != CC_SUCCESS) {
+ 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)
+{
+ uint32_t reg, status;
+ struct xhci_s *xhci = &xhci_host;
+ struct xhci_ring *evts = xhci->evts;
+ struct xhci_pipe *work_pipe = NULL;
+
+ USB_LOG_DBG("%s\n", __func__);
+
+ status = readl(xhci->op + XHCI_REG_OP_USBSTS);
+ status |= XHCI_REG_OP_USBSTS_EINT; /* clear interrupt status */
+ writel(xhci->op + XHCI_REG_OP_USBSTS, status);
+
+ reg = readl(xhci->ir + XHCI_REG_RT_IR_IMAN);
+ reg |= XHCI_REG_RT_IR_IMAN_IP; /* ack interrupt */
+ writel(xhci->ir + XHCI_REG_RT_IR_IMAN, reg);
+
+ /* check and ack event */
+ for (;;) {
+ uint32_t nidx = evts->nidx; /* index of dequeue trb */
+ uint32_t cs = evts->cs; /* cycle state toggle by xHc */
+ struct xhci_trb *etrb = evts->ring + nidx; /* current trb */
+ uint32_t control = etrb->control; /* trb control field */
+
+ if ((control & TRB_C) != (cs ? 1 : 0)) /* if cycle state not toggle, no events need to handle */
+ break;
+
+ /* process event on etrb */
+ uint32_t evt_type = TRB_TYPE_GET(control);
+ uint32_t evt_cc = TRB_CC_GET(etrb->status); /* bit[31:24] completion code */
+
+ if (ER_PORT_STATUS_CHANGE == evt_type) {
+ /* bit[31:24] port id, the port num of root hub port that generated this event */
+ uint32_t port = TRB_PORT_ID_GET(etrb->ptr_low) - 1;
+ uint32_t portsc = xhci_readl_port(xhci, port, XHCI_REG_OP_PORTS_PORTSC); /* Read status */
+
+ xhci_print_port_state(__func__, port, portsc);
+ if (portsc & XHCI_REG_OP_PORTS_PORTSC_CSC) {
+ usbh_roothub_thread_wakeup(port + 1); /* wakeup when connection status changed */
+ }
+ } else if ((ER_COMMAND_COMPLETE == evt_type) || (ER_TRANSFER_COMPLETE == evt_type)) {
+ struct xhci_trb *rtrb = (void*)(unsigned long)etrb->ptr_low;
+ struct xhci_ring *ring = XHCI_RING(rtrb); /* to align addr is ring base */
+ struct xhci_trb *evt = &ring->evt; /* first event trb */
+ uint32_t eidx = rtrb - ring->ring + 1; /* calculate current evt trb index */
+
+ memcpy(evt, etrb, sizeof(*etrb)); /* copy current trb to cmd/transfer ring */
+ ring->eidx = eidx;
+
+ if (ER_COMMAND_COMPLETE == evt_type) {
+ work_pipe = (struct xhci_pipe *)cur_cmd_pipe;
+ } else if (ER_TRANSFER_COMPLETE == evt_type) {
+ /* xhci_pipe begin with reqs ring, therefore we get pipe instance from reqs ring */
+ work_pipe = (struct xhci_pipe *)(void *)ring;
+ }
+
+ if (work_pipe) {
+ if (work_pipe->waiter) {
+ work_pipe->waiter = false;
+ usb_osal_sem_give(work_pipe->waitsem);
+ }
+
+ if (work_pipe->urb) {
+ struct usbh_urb *cur_urb = work_pipe->urb;
+ cur_urb->errorcode = evt_cc;
+ /* 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 -
+ (evt->status) & 0xffffff; /* bit [23:0] */
+ }
+ }
+ } else {
+ USB_LOG_ERR("%s: unknown event, type %d, cc %d\n",
+ __func__, evt_type, evt_cc);
+ }
+
+ /* 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;
+ uint64_t erdp = (uint64_t)(evts->ring + nidx);
+ writeq(xhci->ir + XHCI_REG_RT_IR_ERDP, erdp | XHCI_REG_RT_IR_ERDP_EHB); /* bit[63:4] update current event ring dequeue pointer */
+ }
+
+ /* handle callbacks in interrupt */
+ if ((work_pipe) && (work_pipe->urb)) {
+ struct usbh_urb *cur_urb = work_pipe->urb;
+ 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;
+} \ No newline at end of file
diff --git a/port/xhci/usb_hc_xhci.h b/port/xhci/usb_hc_xhci.h
new file mode 100644
index 00000000..a86b4a9b
--- /dev/null
+++ b/port/xhci/usb_hc_xhci.h
@@ -0,0 +1,175 @@
+/*
+ * 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 files is for xhci data structure definition
+ *
+ * Modify History:
+ * Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0 zhugengyu 2022/9/19 init commit
+ */
+#ifndef USB_HC_XHCI_H
+#define USB_HC_XHCI_H
+
+/***************************** Include Files *********************************/
+#include "usbh_core.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/************************** Constant Definitions *****************************/
+
+/************************** Type Definitions *****************************/
+/* slot context */
+struct xhci_slotctx {
+ uint32_t ctx[4];
+#define XHCI_SLOTCTX_0_MAX_EPID_SET(maxid) XHCI32_SET_BITS(maxid, 31, 27)
+#define XHCI_SLOTCTX_0_SPEED_SET(speed) XHCI32_SET_BITS(speed, 23, 20)
+#define XHCI_SLOTCTX_1_ROOT_PORT_GET(val) XHCI32_GET_BITS(val, 23, 16)
+#define XHCI_SLOTCTX_1_ROOT_PORT_SET(port) XHCI32_SET_BITS(port, 23, 16)
+#define XHCI_SLOTCTX_0_ROUTE_SET(route) XHCI32_SET_BITS(route, 19, 0)
+#define XHCI_SLOTCTX_2_HUB_SLOT_SET(slot) XHCI32_SET_BITS(slot, 7, 0)
+#define XHCI_SLOTCTX_2_HUB_PORT_SET(port) XHCI32_SET_BITS(port, 15, 8)
+#define XHCI_SLOTCTX_3_SLOT_STATE_GET(ctx) XHCI32_GET_BITS(ctx, 31, 27)
+ uint32_t reserved_01[4];
+#define XHCI_SLOTCTX_ENTRY_NUM 32U
+#define XHCI_SLOTCTX_ALIGMENT 1024U
+} __PACKED;
+
+enum xhci_slot_state {
+ XHCI_SLOT_DEFAULT = 1,
+ XHCI_SLOT_ADDRESS = 2,
+ XHCI_SLOT_CONFIG = 3
+};
+
+/* endpoint context */
+struct xhci_epctx {
+ uint32_t ctx[2];
+#define XHCI_EPCTX_0_INTERVAL_SET(interval) XHCI32_SET_BITS(interval, 23, 16)
+#define XHCI_EPCTX_1_MPS_SET(mps) XHCI32_SET_BITS(mps, 31, 16)
+ uint32_t deq_low;
+ uint32_t deq_high;
+ uint32_t length;
+#define XHCI_EPCTX_AVE_TRB_LEN_SET(len) XHCI32_SET_BITS(len, 15, 0)
+ uint32_t reserved_01[3];
+} __PACKED;
+
+/* device context array element */
+struct xhci_devlist {
+ uint32_t ptr_low;
+ uint32_t ptr_high;
+} __PACKED;
+
+/* input context */
+struct xhci_inctx {
+ uint32_t del;
+ uint32_t add;
+ uint32_t reserved_01[6];
+/* refer to spec. The Input Context is an array of up to 33 context data structure entries */
+#define XHCI_INCTX_ENTRY_NUM 33U
+#define XHCI_INCTX_ALIGMENT 2048
+} __PACKED;
+
+/* transfer block (ring element) */
+struct xhci_trb {
+ uint32_t ptr_low;
+ uint32_t ptr_high;
+ uint32_t status;
+ uint32_t control;
+} __PACKED;
+
+/* event ring segment */
+struct xhci_er_seg {
+ uint32_t ptr_low;
+ uint32_t ptr_high;
+ uint32_t size;
+ uint32_t reserved_01;
+} __PACKED;
+
+struct xhci_portmap {
+ uint8_t start;
+ uint8_t count;
+};
+
+struct xhci_ring {
+ struct xhci_trb ring[XHCI_RING_ITEMS];
+ struct xhci_trb evt;
+ uint32_t eidx;
+ uint32_t nidx;
+ uint32_t cs;
+ usb_osal_mutex_t lock;
+};
+
+struct xhci_pipe {
+ struct xhci_ring reqs; /* DO NOT MOVE reqs from structure beg */
+ uint8_t epaddr;
+ uint8_t speed;
+ uint8_t interval;
+ uint8_t eptype;
+ uint16_t maxpacket;
+ uint32_t slotid;
+ uint32_t epid;
+
+ /* 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 */
+};
+
+struct xhci_s {
+ /* devinfo */
+ uint32_t ports;
+ uint32_t slots;
+ bool context64;
+ struct xhci_portmap usb2;
+ struct xhci_portmap usb3;
+
+ /* xhci registers base addr */
+ unsigned long base; /* register base */
+ unsigned long caps; /* capability register base */
+ unsigned long op; /* operational register base */
+ unsigned long pr; /* port register base */
+ unsigned long ir; /* interrupt runtime register base */
+ unsigned long db; /* doorbell register base */
+ unsigned long xcap; /* extended capability */
+ uint32_t hcs[3]; /* capability cache */
+ uint32_t hcc;
+ uint16_t version; /* xhci version */
+
+ /* xhci data structures */
+ struct xhci_devlist *devs;
+ struct xhci_ring *cmds;
+ struct xhci_ring *evts;
+ struct xhci_er_seg *eseg;
+};
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Function Prototypes ******************************/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/port/xhci/xhci_reg.h b/port/xhci/xhci_reg.h
new file mode 100644
index 00000000..7b087409
--- /dev/null
+++ b/port/xhci/xhci_reg.h
@@ -0,0 +1,528 @@
+/*
+ * 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 files is for xhci register definition
+ *
+ * Modify History:
+ * Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0 zhugengyu 2022/9/19 init commit
+ */
+#ifndef XHCI_REG_H
+#define XHCI_REG_H
+
+/***************************** Include Files *********************************/
+#include "usbh_core.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/************************** Constant Definitions *****************************/
+#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))
+
+/** @name Register Map
+ *
+ * Register offsets from the base address of an XHCI device.
+ * @{
+ */
+#define XHCI_REG_CAP_CAPLENGTH 0x00 /* specify the limits, restrictions and capabilities */
+#define XHCI_REG_CAP_HCIVERSION 0x02 /* Interface Version Number */
+#define XHCI_REG_CAP_HCS1 0x04 /* Host Controller Structural Parameters 1 */
+#define XHCI_REG_CAP_HCS2 0x08 /* Host Controller Structural Parameters 2 */
+#define XHCI_REG_CAP_HCS3 0x0C /* Host Controller Structural Parameters 3 */
+#define XHCI_REG_CAP_HCC 0x10 /* Capability Parameters 1 */
+#define XHCI_REG_CAP_DBOFF 0x14 /* Doorbell Offset Register */
+#define XHCI_REG_CAP_RTSOFF 0x18 /* Runtime Register Space Offset Register */
+
+/***************** Host Controller Operational Registers ***********************/
+#define XHCI_REG_OP_USBCMD 0x00 /* USB Command Register */
+#define XHCI_REG_OP_USBSTS 0x04 /* USB Status Register */
+#define XHCI_REG_OP_PAGESIZE 0x08 /* Page Size Register */
+#define XHCI_REG_OP_DNCTRL 0x14 /* Device Notification Control Register */
+#define XHCI_REG_OP_CRCR 0x18 /* Command Ring Control Register */
+#define XHCI_REG_OP_DCBAAP 0x30 /* Device Context Base Address Array Pointer Register */
+#define XHCI_REG_OP_CONFIG 0x38 /* Configure Register */
+
+/* Port Status and Ctrl Register : OP Base + (400h + (10h * (n–1))) 'n' is port num */
+#define XHCI_REG_OP_PORTS_BASE 0x400 /* Port Status and Control Register Base */
+#define XHCI_REG_OP_PORTS_SIZE 0x10 /* Size of one Port SC Register */
+#define XHCI_REG_OP_PORTS_OFF(port, off) ((port) * XHCI_REG_OP_PORTS_SIZE + offset)
+
+#define XHCI_REG_OP_PORTS_PORTSC 0x00 /* Port Status and Control Register */
+#define XHCI_REG_OP_PORTS_PORTPMSC 0x04 /* USB3 Port Power Management Status and Control Register */
+#define XHCI_REG_OP_PORTS_PORTLI 0x08 /* Port Link Info Register */
+
+/***************** Host Controller Runtime Registers ***********************/
+#define XHCI_REG_RT_MFINDEX 0x00 /* Microframe Index */
+#define XHCI_REG_RT_IR0 0x20 /* Interrupter Register Set 0 */
+#define XHCI_REG_RT_IR1023 0x8000 /* Interrupter Register Set 1023 */
+
+/* Interrupter Register Set : RT Base + 020h + (32 * Interrupter) */
+#define XHCI_REG_RT_IR_IMAN 0x00 /* Interrupter Management Register */
+#define XHCI_REG_RT_IR_IMOD 0x04 /* Interrupter Moderation Register */
+#define XHCI_REG_RT_IR_ERSTSZ 0x08 /* Event Ring Segment Table Size Register */
+#define XHCI_REG_RT_IR_ERSTBA 0x10 /* Event Ring Segment Table Base Address Register */
+#define XHCI_REG_RT_IR_ERDP 0x18 /* Event Ring Dequeue Pointer Register */
+#define XHCI_REG_RT_IR_SIZE 0x20 /* Size of one IR Register */
+
+/***************** Doorbell Register ***********************/
+#define XHCI_REG_DB_SIZE 4 /* Doorbell registers are 32 bits in length */
+
+/***************** eXtensible Host Controller Capability Registers ***********************/
+
+/** @name XHCI_REG_CAP_HCS1 Register
+ */
+#define XHCI_REG_CAP_HCS1_MAX_SLOTS_GET(x) XHCI32_GET_BITS(x, 7, 0) /* Number of Device Slots (MaxSlots) */
+#define XHCI_REG_CAP_HCS1_MAX_INTRS_GET(x) XHCI32_GET_BITS(x, 18, 8) /* Number of Interrupters (MaxIntrs) */
+#define XHCI_REG_CAP_HCS1_MAX_PORTS_GET(x) XHCI32_GET_BITS(x, 31, 24) /* Number of Ports (MaxPorts) */
+
+/** @name XHCI_REG_CAP_HCS2 Register
+ */
+#define XHCI_REG_CAP_HCS2_IST_GET(x) XHCI32_GET_BITS(x, 3, 0) /* Isochronous Scheduling Threshold (IST) */
+#define XHCI_REG_CAP_HCS2_ERST_MAX_GET(x) XHCI32_GET_BITS(x, 7, 4) /* Event Ring Segment Table Max (ERST Max) */
+#define XHCI_REG_CAP_HCS2_SPR (1 << 26) /* Scratchpad Restore (SPR) */
+#define XHCI_REG_CAP_HCS2_MAX_SCRATCHPAD_BUFS_GET(x) XHCI32_GET_BITS(x, 25, 21) | XHCI32_GET_BITS(x, 31, 27) /* Max Scratchpad Buffers (Max Scratchpad Bufs) */
+
+/** @name XHCI_REG_CAP_HCS3 Register
+ */
+#define XHCI_REG_CAP_HCS3_U1_DEV_EXIT_LATENCY_GET(x) XHCI32_GET_BITS(x, 7, 0) /* U1 Device Exit Latency */
+#define XHCI_REG_CAP_HCS3_U2_DEV_EXIT_LATENCY_GET(x) XHCI32_GET_BITS(x, 31, 16) /* U2 Device Exit Latency */
+
+/** @name XHCI_REG_CAP_HCC Register
+ */
+#define XHCI_REG_CAP_HCC_AC64 (1 << 0) /* 64-bit Addressing Capabilitya 1: 64-bit */
+#define XHCI_REG_CAP_HCC_BNC (1 << 1) /* BW Negotiation Capability (BNC) 1: support */
+#define XHCI_REG_CAP_HCC_CSZ (1 << 2) /* Context Size (CSZ) 1: 64 byte context data */
+#define XHCI_REG_CAP_HCC_PPC (1 << 3) /* Port Power Control (PPC) 1: support */
+#define XHCI_REG_CAP_HCC_PIND (1 << 4) /* Port Indicators (PIND) 1: support */
+#define XHCI_REG_CAP_HCC_LHRC (1 << 5) /* Light HC Reset Capability (LHRC) 1: support */
+#define XHCI_REG_CAP_HCC_LTC (1 << 6) /* Latency Tolerance Messaging Capability (LTC) */
+#define XHCI_REG_CAP_HCC_NSS (1 << 7) /* No Secondary SID Support (NSS) */
+#define XHCI_REG_CAP_HCC_MAX_PSA_SIZE_GET(x) XHCI32_GET_BITS(x, 15, 12) /* Maximum Primary Stream Array Size (MaxPSASize) */
+#define XHCI_REG_CAP_HCC_XECP_GET(x) XHCI32_GET_BITS(x, 31, 16) /* xHCI Extended Capabilities Pointer (xECP) */
+
+/** @name XHCI_REG_CAP_DBOFF Register
+ */
+#define XHCI_REG_CAP_DBOFF_GET(x) ((x) & XHCI_GENMASK(31, 2)) /* 32-byte offset of the Doorbell Array base address from the Base */
+
+/** @name XHCI_REG_CAP_RTSOFF Register
+ */
+#define XHCI_REG_CAP_RTSOFF_GET(x) ((x) & XHCI_GENMASK(31, 5)) /* 32-byte offset of the xHCI Runtime Registers */
+
+
+/***************** Host Controller Operational Registers ***********************/
+
+/** @name XHCI_REG_OP_USBCMD Register
+ */
+#define XHCI_REG_OP_USBCMD_RUN_STOP (1 << 0) /* Run/Stop (R/S) 1: RUN, 0: STOP - RW */
+#define XHCI_REG_OP_USBCMD_HCRST (1 << 1) /* Host Controller Reset (HCRST) 1: RESET - RW */
+#define XHCI_REG_OP_USBCMD_INTE (1 << 2) /* Interrupter Enable (INTE) 1: enabled - RW */
+#define XHCI_REG_OP_USBCMD_HSEE (1 << 3) /* Host System Error Enable (HSEE) - RW */
+#define XHCI_REG_OP_USBCMD_LHCRST (1 << 7) /* Light Host Controller Reset (LHCRST) - RW */
+#define XHCI_REG_OP_USBCMD_CSS (1 << 8) /* Controller Save State (CSS) - RW */
+#define XHCI_REG_OP_USBCMD_CRS (1 << 9) /* Controller Restore State (CRS) - RW */
+#define XHCI_REG_OP_USBCMD_EWE (1 << 10) /* Enable Wrap Event (EWE) - RW */
+#define XHCI_REG_OP_USBCMD_EU3S (1 << 11) /* Enable U3 MFINDEX Stop (EU3S) - RW */
+
+/** @name XHCI_REG_OP_USBSTS Register
+ */
+#define XHCI_REG_OP_USBSTS_HCH (1 << 0) /* 1: Stopped executing */
+#define XHCI_REG_OP_USBSTS_HSE (1 << 2) /* 1: Serious error detected */
+#define XHCI_REG_OP_USBSTS_EINT (1 << 3) /* 1: Interrupt Pending (IP) */
+#define XHCI_REG_OP_USBSTS_PCD (1 << 4) /* 1: Port Change Detect */
+#define XHCI_REG_OP_USBSTS_SSS (1 << 8) /* remain 1 while the xHC saves its internal state */
+#define XHCI_REG_OP_USBSTS_RSS (1 << 9) /* remain 1 while the xHC restores its internal state */
+#define XHCI_REG_OP_USBSTS_SRE (1 << 10) /* if error occurs during a Save or Restore operation this bit shall be set to ‘1’. */
+#define XHCI_REG_OP_USBSTS_CNR (1 << 11) /* 1: Controller Not Ready */
+#define XHCI_REG_OP_USBSTS_HCE (1 << 12) /* 1: Internal xHC error condition */
+#define XHCI_REG_OP_USBSTS_PRSRV_MASK ((1 << 1) | 0xffffe000) /* Rsvd bits */
+
+
+/** @name XHCI_REG_OP_PAGESIZE Register
+ */
+/* This xHC supports a page size of 2^(n+12) if bit n is Set */
+#define XHCI_REG_OP_PAGESIZE_4K (1 << 0) /* if bit 0 is Set, the xHC supports 4k byte page sizes */
+
+/** @name XHCI_REG_OP_CRCR Register
+ */
+#define XHCI_REG_OP_CRCR_RCS (1 << 0) /* Ring Cycle State, value of the xHC Consumer Cycle State (CCS) flag */
+#define XHCI_REG_OP_CRCR_CS (1 << 1) /* Command Stop, 1 */
+#define XHCI_REG_OP_CRCR_CA (1 << 2) /* Command Abort, 1 */
+#define XHCI_REG_OP_CRCR_CRR (1 << 3) /* Command Ring Running */
+#define XHCI_REG_OP_CRCR_CR_PTR_MASK XHCI_GENMASK_ULL(63, 6) /* Command Ring Pointer, Dequeue Ptr of Command Ring */
+
+/** @name XHCI_REG_OP_DCBAAP Register
+ */
+#define XHCI_REG_OP_DCBAAP_MASK XHCI_GENMASK_ULL(63, 6) /* bit[31:6] Ptr of DCBAA */
+
+/** @name XHCI_REG_OP_CONFIG Register
+ */
+#define XHCI_REG_OP_CONFIG_MAX_SLOTS_EN_MASK XHCI_GENMASK(7, 0) /* Max Device Slots Enabled (MaxSlotsEn) – RW */
+#define XHCI_REG_OP_CONFIG_MAX_SLOTS_EN_SET(x) XHCI32_SET_BITS(x, 7, 0) /* bit[7:0] Max Device Slots Enabled */
+#define XHCI_REG_OP_CONFIG_MAX_SLOTS_EN_GET(x) XHCI32_GET_BITS(x, 7, 0)
+
+/** @name XHCI_REG_OP_PORTS_PORTSC Register
+ */
+#define XHCI_REG_OP_PORTS_PORTSC_CCS (1 << 0) /* Current Connect Status (CCS) – ROS */
+#define XHCI_REG_OP_PORTS_PORTSC_PED (1 << 1) /* Port Enabled/Disabled (PED) – RW1CS */
+#define XHCI_REG_OP_PORTS_PORTSC_OCA (1 << 3) /* Over-current Active (OCA) – RO */
+#define XHCI_REG_OP_PORTS_PORTSC_PR (1 << 4) /* Port Reset (PR) – RW1S */
+#define XHCI_REG_OP_PORTS_PORTSC_PLS_GET(x) XHCI32_GET_BITS(x, 8, 5) /* Port Link State (PLS) – RWS */
+#define XHCI_REG_OP_PORTS_PORTSC_PLS_SET(x) XHCI32_SET_BITS(x, 8, 5)
+#define XHCI_REG_OP_PORTS_PORTSC_PLS_MASK XHCI_GENMASK(8, 5)
+#define XHCI_REG_OP_PORTS_PORTSC_PLS(x) (x << 5)
+#define XHCI_REG_OP_PORTS_PORTSC_PLS_SET(x) XHCI32_SET_BITS(x, 8, 5)
+
+enum PLSStatus{
+ PLS_U0 = 0,
+ PLS_U1 = 1,
+ PLS_U2 = 2,
+ PLS_U3 = 3,
+ PLS_DISABLED = 4,
+ PLS_RX_DETECT = 5,
+ PLS_INACTIVE = 6,
+ PLS_POLLING = 7,
+ PLS_RECOVERY = 8,
+ PLS_HOT_RESET = 9,
+ PLS_COMPILANCE_MODE = 10,
+ PLS_TEST_MODE = 11,
+ PLS_RESUME = 15,
+}; /* Port status type */
+
+#define XHCI_REG_OP_PORTS_PORTSC_PP (1 << 9) /* Port Power (PP) – RWS */
+#define XHCI_REG_OP_PORTS_PORTSC_PORT_SPEED_GET(x) XHCI32_GET_BITS(x, 13, 10) /* Port Speed (Port Speed) – ROS */
+
+/* Protocol Speed ID (PSI) */
+#define XHCI_PORT_SPEED_UNKOWN 0U
+#define XHCI_PORT_SPEED_FULL 1U
+#define XHCI_PORT_SPEED_LOW 2U
+#define XHCI_PORT_SPEED_HIGH 3U
+#define XHCI_PORT_SPEED_SUPER 4U
+
+#define XHCI_REG_OP_PORTS_PORTSC_PIC_SET(x) XHCI32_SET_BITS(x, 15, 14)
+#define XHCI_REG_OP_PORTS_PORTSC_PIC_MASK XHCI_GENMASK(15, 14)
+
+#define XHCI_REG_OP_PORTS_PORTSC_LWS (1 << 16) /* Port Link State Write Strobe (LWS) */
+#define XHCI_REG_OP_PORTS_PORTSC_CSC (1 << 17) /* Connect Status Change (CSC) */
+#define XHCI_REG_OP_PORTS_PORTSC_PEC (1 << 18) /* Port Enabled/Disabled Change (PEC) 1: clear PED */
+#define XHCI_REG_OP_PORTS_PORTSC_WRC (1 << 19) /* Warm Port Reset Change 1: Warm Reset complete */
+#define XHCI_REG_OP_PORTS_PORTSC_OCC (1 << 20) /* Over-current Change 1: Over-current Active */
+#define XHCI_REG_OP_PORTS_PORTSC_PRC (1 << 21) /* Port Reset Change 1: Transition of Port Reset */
+#define XHCI_REG_OP_PORTS_PORTSC_PLC (1 << 22) /* Port Link State Change 1: PLS transition */
+#define XHCI_REG_OP_PORTS_PORTSC_CEC (1 << 23) /* Port Config Error Change 1: Port Config Error detected */
+#define XHCI_REG_OP_PORTS_PORTSC_CAS (1 << 24) /* Cold Attach Status 1: Far-end Receiver Terminations were detected */
+#define XHCI_REG_OP_PORTS_PORTSC_WCE (1 << 25) /* Wake on Connect Enable 1: enable port to be sensitive to device connects */
+#define XHCI_REG_OP_PORTS_PORTSC_WDE (1 << 26) /* Wake on Disconnect Enable 1: enable port to be sensitive to device disconnects */
+#define XHCI_REG_OP_PORTS_PORTSC_WOE (1 << 27) /* Wake on Over-current Enable 1: enable port to be sensitive to over-current conditions */
+#define XHCI_REG_OP_PORTS_PORTSC_DR (1 << 30) /* Device Removable, 0: Device is removable. 1: Device is non-removable */
+#define XHCI_REG_OP_PORTS_PORTSC_WPR (1 << 31) /* Warm Port Reset 1: follow Warm Reset sequence */
+#define XHCI_REG_OP_PORTS_PORTSC_RW_MASK (XHCI_REG_OP_PORTS_PORTSC_PR | XHCI_REG_OP_PORTS_PORTSC_PLS_MASK | XHCI_REG_OP_PORTS_PORTSC_PP \
+ | XHCI_REG_OP_PORTS_PORTSC_PIC_MASK | XHCI_REG_OP_PORTS_PORTSC_LWS | XHCI_REG_OP_PORTS_PORTSC_WCE \
+ | XHCI_REG_OP_PORTS_PORTSC_WDE | XHCI_REG_OP_PORTS_PORTSC_WOE)
+
+
+/***************** Host Controller Runtime Registers ***********************/
+
+/** @name XHCI_REG_RT_IR_IMAN Register
+ */
+#define XHCI_REG_RT_IR_IMAN_IP (1 << 0) /* Interrupt Pending, 1: an interrupt is pending for this Interrupter */
+#define XHCI_REG_RT_IR_IMAN_IE (1 << 1) /* Interrupt Enable, 1: capable of generating an interrupt. */
+
+/** @name XHCI_REG_RT_IR_IMOD Register
+ */
+#define XHCI_REG_RT_IR_IMOD_IMODI_MASK XHCI_GENMASK(15, 0) /* bit[15:0] Interrupt Moderation Interval default 4000 ==> 1ms */
+#define XHCI_REG_RT_IR_IMOD_IMODC_MASK XHCI_GENMASK(31, 16) /* bit[31:16] Interrupt Moderation Counter(Down counter) */
+
+/** @name XHCI_REG_RT_IR_ERSTSZ Register
+ */
+#define XHCI_REG_RT_IR_ERSTSZ_MASK XHCI_GENMASK(15, 0) /* bit[15:0] the number of valid Event Ring Segment Table entries */
+
+/** @name XHCI_REG_RT_IR_ERSTBA Register
+ */
+#define XHCI_REG_RT_IR_ERSTBA_MASK XHCI_GENMASK_ULL(63, 6) /* Event Ring Segment Table Base Address */
+
+/** @name XHCI_REG_RT_IR_ERDP Register
+ */
+#define XHCI_REG_RT_IR_ERDP_DESI_MASK XHCI_GENMASK_ULL(2, 0) /* bit[2:0] Dequeue ERST Segment Index */
+#define XHCI_REG_RT_IR_ERDP_EHB (1 << 3) /* Event Handler Busy */
+#define XHCI_REG_RT_IR_ERDP_MASK XHCI_GENMASK_ULL(63, 4) /* Event Ring Dequeue Pointer */
+
+/***************** Doorbell Register ***********************/
+#define XHCI_REG_DB_TARGET_HC_COMMAND 0 /* Host Controller Doorbell (0) Command Doorbell */
+#define XHCI_REG_DB_TARGET_EP0 1 /* Device Context Doorbells Control EP 0 Enqueue Pointer Update */
+#define XHCI_REG_DB_TARGET_EP1_OUT 2 /* EP 1 OUT Enqueue Pointer Update */
+#define XHCI_REG_DB_TARGET_EP1_IN 3 /* EP 1 IN Enqueue Pointer Update */
+#define XHCI_REG_DB_TARGET_EP15_OUT 30 /* EP 15 OUT Enqueue Pointer Update */
+#define XHCI_REG_DB_TARGET_EP15_IN 31 /* EP 15 IN Enqueue Pointer Update */
+
+/***************** xHCI Extended Capabilities Registers ***********************/
+#define XHCI_REG_EXT_CAP_USBSPCF_OFFSET 0x0
+#define XHCI_REG_EXT_CAP_CAP_ID_GET(x) XHCI32_GET_BITS(x, 7, 0)
+#define XHCI_REG_EXT_NEXT_CAP_PTR_GET(x) XHCI32_GET_BITS(x, 15, 8)
+/* refer to 'Table 138: xHCI Extended Capability Codes' for more details */
+enum
+{
+ XHCI_EXT_CAP_ID_USB_LEGACY_SUPPORT = 1,
+ XHCI_EXT_CAP_ID_SUPPORT_PROTOCOL = 2,
+ XHCI_EXT_CAP_ID_EXTEND_POWER_MANAGEMENT = 3,
+ XHCI_EXT_CAP_ID_IO_VIRTUALIZATION = 4,
+ XHCI_EXT_CAP_ID_MESSAGE_INTERRUPT = 5,
+ XHCI_EXT_CAP_ID_LOCAL_MEMORY = 6,
+ XHCI_EXT_CAP_ID_USB_DEBUG_CAPABILITY = 10,
+ XHCI_EXT_CAP_ID_EXT_MESSAGE_INTERRUPT = 17,
+
+ XHCI_EXT_CAP_ID_VENDOR_DEFINED_MIN = 192,
+ XHCI_EXT_CAP_ID_VENDOR_DEFINED_MAX = 255
+};
+
+/* xHCI Supported Protocol Capability */
+#define XHCI_REG_EXT_CAP_USBSPCFDEF_OFFSET 0x4
+
+#define XHCI_USBSPCF_MINOR_REVERSION_GET(x) XHCI32_GET_BITS(x, 23, 16)
+#define XHCI_USBSPCF_MAJOR_REVERSION_GET(x) XHCI32_GET_BITS(x, 31, 24)
+
+#define XHCI_USBSPCFDEF_NAME_STRING_GET(x) XHCI32_GET_BITS(x, 31, 0) /* four ASCII characters may be defined */
+#define XHCI_USBSPCFDEF_NAME_STRING_USB 0x20425355 /* ASCII = "USB" */
+
+#define XHCI_REG_EXT_CAP_USBSPCFDEF2_OFFSET 0x8
+#define XHCI_USBSPCFDEF2_COMPATIBLE_PORT_OFF_GET(x) XHCI32_GET_BITS(x, 7, 0)
+#define XHCI_USBSPCFDEF2_COMPATIBLE_PORT_CNT_GET(x) XHCI32_GET_BITS(x, 15, 8)
+#define XHCI_USBSPCFDEF2_PROTOCOL_DEFINED_GET(x) XHCI32_GET_BITS(x, 27, 16)
+
+/* trb bit definitions */
+
+/* configuration */
+#define XHCI_RING_ITEMS 16U
+#define XHCI_ALIGMENT 64U
+#define XHCI_RING_SIZE (XHCI_RING_ITEMS*sizeof(struct xhci_trb))
+
+#define TRB_C (1<<0)
+#define TRB_TYPE_SHIFT 10
+#define TRB_TYPE_MASK 0x3f
+#define TRB_TYPE_GET(val) XHCI32_GET_BITS(val, 15, 10)
+#define TRB_TYPE_SET(t) XHCI32_SET_BITS(t, 15, 10)
+
+#define TRB_EV_ED (1<<2)
+
+#define TRB_TR_ENT (1<<1)
+#define TRB_TR_ISP (1<<2)
+#define TRB_TR_NS (1<<3)
+#define TRB_TR_CH (1<<4)
+#define TRB_TR_IOC (1<<5)
+#define TRB_TR_IDT (1<<6)
+#define TRB_TR_TBC_SHIFT 7
+#define TRB_TR_TBC_MASK 0x3
+#define TRB_TR_BEI (1<<9)
+#define TRB_TR_TLBPC_SHIFT 16
+#define TRB_TR_TLBPC_MASK 0xf
+#define TRB_TR_FRAMEID_SHIFT 20
+#define TRB_TR_FRAMEID_MASK 0x7ff
+#define TRB_TR_SIA (1<<31)
+
+#define TRB_TR_DIR (1<<16)
+#define TRB_TR_TYPE_SET(t) XHCI32_SET_BITS(t, 17, 16)
+#define TRB_TR_NO_DATA 0U
+#define TRB_TR_OUT_DATA 2U
+#define TRB_TR_IN_DATA 3U
+
+#define TRB_CC_GET(val) XHCI32_GET_BITS(val, 31, 24)
+#define TRB_PORT_ID_GET(val) XHCI32_GET_BITS(val, 31, 24)
+
+
+#define TRB_CR_SLOTID_SHIFT 24
+#define TRB_CR_SLOTID_MASK 0xff
+#define TRB_CR_SLOTID_SET(id) XHCI32_SET_BITS(id, 31, 24)
+#define TRB_CR_SLOTID_GET(val) XHCI32_GET_BITS(val, 31, 24)
+
+#define TRB_CR_EPID_SHIFT 16
+#define TRB_CR_EPID_MASK 0x1f
+
+#define TRB_CR_BSR (1<<9)
+#define TRB_CR_DC (1<<9)
+
+#define TRB_LK_TC (1<<1)
+
+#define TRB_INTR_SHIFT 22
+#define TRB_INTR_MASK 0x3ff
+#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK)
+
+/************************** Type Definitions *********************************/
+enum TRBType {
+ TRB_RESERVED = 0,
+ TR_NORMAL,
+ TR_SETUP,
+ TR_DATA,
+ TR_STATUS,
+ TR_ISOCH,
+ TR_LINK,
+ TR_EVDATA,
+ TR_NOOP,
+ CR_ENABLE_SLOT,
+ CR_DISABLE_SLOT,
+ CR_ADDRESS_DEVICE,
+ CR_CONFIGURE_ENDPOINT,
+ CR_EVALUATE_CONTEXT,
+ CR_RESET_ENDPOINT,
+ CR_STOP_ENDPOINT,
+ CR_SET_TR_DEQUEUE,
+ CR_RESET_DEVICE,
+ CR_FORCE_EVENT,
+ CR_NEGOTIATE_BW,
+ CR_SET_LATENCY_TOLERANCE,
+ CR_GET_PORT_BANDWIDTH,
+ CR_FORCE_HEADER,
+ CR_NOOP,
+ ER_TRANSFER_COMPLETE = 32,
+ ER_COMMAND_COMPLETE,
+ ER_PORT_STATUS_CHANGE,
+ ER_BANDWIDTH_REQUEST,
+ ER_DOORBELL,
+ ER_HOST_CONTROLLER,
+ ER_DEVICE_NOTIFICATION,
+ ER_MFINDEX_WRAP,
+};
+
+enum TRBCCode {
+ CC_DISCONNECTED = -2,
+ CC_TIMEOUT = -1,
+ CC_INVALID = 0,
+ CC_SUCCESS,
+ CC_DATA_BUFFER_ERROR,
+ CC_BABBLE_DETECTED,
+ CC_USB_TRANSACTION_ERROR,
+ CC_TRB_ERROR,
+ CC_STALL_ERROR,
+ CC_RESOURCE_ERROR,
+ CC_BANDWIDTH_ERROR,
+ CC_NO_SLOTS_ERROR,
+ CC_INVALID_STREAM_TYPE_ERROR,
+ CC_SLOT_NOT_ENABLED_ERROR,
+ CC_EP_NOT_ENABLED_ERROR,
+ CC_SHORT_PACKET,
+ CC_RING_UNDERRUN,
+ CC_RING_OVERRUN,
+ CC_VF_ER_FULL,
+ CC_PARAMETER_ERROR,
+ CC_BANDWIDTH_OVERRUN,
+ CC_CONTEXT_STATE_ERROR,
+ CC_NO_PING_RESPONSE_ERROR,
+ CC_EVENT_RING_FULL_ERROR,
+ CC_INCOMPATIBLE_DEVICE_ERROR,
+ CC_MISSED_SERVICE_ERROR,
+ CC_COMMAND_RING_STOPPED,
+ CC_COMMAND_ABORTED,
+ CC_STOPPED,
+ CC_STOPPED_LENGTH_INVALID,
+ CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29,
+ CC_ISOCH_BUFFER_OVERRUN = 31,
+ CC_EVENT_LOST_ERROR,
+ CC_UNDEFINED_ERROR,
+ CC_INVALID_STREAM_ID_ERROR,
+ CC_SECONDARY_BANDWIDTH_ERROR,
+ CC_SPLIT_TRANSACTION_ERROR
+};
+
+/***************** Macros (Inline Functions) Definitions *********************/
+/*
+ * 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)))
+
+#define XHCI_GET_FIELD(data, field) \
+ (((data) >> field##_SHIFT) & field##_MASK)
+
+#define BARRIER() __asm__ __volatile__("": : :"memory")
+
+#ifdef XHCI_AARCH64
+#define DSB() __asm__ __volatile__("dsb sy": : : "memory")
+#else
+#define DSB() __asm__ __volatile__("dsb": : : "memory")
+#endif
+
+/************************** Function Prototypes ******************************/
+
+/*****************************************************************************/
+static inline void writeq(unsigned long addr, uint64_t val) {
+ BARRIER();
+ *(volatile uint64_t *)addr = val;
+}
+
+static inline void writel(unsigned long addr, uint32_t val) {
+ BARRIER();
+ *(volatile uint32_t *)addr = val;
+}
+
+static inline void writew(unsigned long addr, uint16_t val) {
+ BARRIER();
+ *(volatile uint16_t *)addr = val;
+}
+
+static inline void writeb(unsigned long addr, uint8_t val) {
+ BARRIER();
+ *(volatile uint8_t *)addr = val;
+}
+
+static inline uint64_t readq(unsigned long addr) {
+ uint64_t val = *(volatile const uint64_t *)addr;
+ BARRIER();
+ return val;
+}
+
+static inline uint32_t readl(unsigned long addr) {
+ uint32_t val = *(volatile const uint32_t *)addr;
+ BARRIER();
+ return val;
+}
+
+static inline uint16_t readw(unsigned long addr) {
+ uint16_t val = *(volatile const uint16_t *)addr;
+ BARRIER();
+ return val;
+}
+
+static inline uint8_t readb(unsigned long addr) {
+ uint8_t val = *(volatile const uint8_t *)addr;
+ BARRIER();
+ return val;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file