first commit for chrg

This commit is contained in:
wmano
2025-08-16 22:58:22 +08:00
commit 52a3ed5862
2306 changed files with 1021208 additions and 0 deletions
@@ -0,0 +1,38 @@
# Note
## Support Chip List
### BouffaloLab
- BouffaloLab BL616/BL808 (bouffalolab + EHCI)
### HPMicro
- HPM all series (hpmicro + EHCI)
### AllwinnerTech
- F133/T113
### Nuvoton
- Nuvoton all series
### Artinchip
- d13x, d21x
### NXP
Modify USB_NOCACHE_RAM_SECTION
```
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".NonCacheable")))
```
- IMRT10XX/IMRT11XX (chipidea + EHCI)
- MCXN9XX/MCXN236 (chipidea + EHCI)
### Intel
- Intel 6 Series Chipset and Intel C200 Series Chipset
@@ -0,0 +1,393 @@
/****************************************************************************
* include/nuttx/usb/ehci.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/*
* Copyright 2022 sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __INCLUDE_NUTTX_USB_EHCI_H
#define __INCLUDE_NUTTX_USB_EHCI_H
#define EHCI_FULL_SPEED (0) /* Full-Speed (12Mbs) */
#define EHCI_LOW_SPEED (1) /* Low-Speed (1.5Mbs) */
#define EHCI_HIGH_SPEED (2) /* High-Speed (480 Mb/s) */
/* Host Controller Capability Register Bit Definitions **********************/
/* Structural Parameters. Paragraph 2.2.3 */
#define EHCI_HCSPARAMS_NPORTS_SHIFT (0) /* Bit 0-3: Number of physical downstream ports */
#define EHCI_HCSPARAMS_NPORTS_MASK (15 << EHCI_HCSPARAMS_NPORTS_SHIFT)
#define EHCI_HCSPARAMS_PPC (1 << 4) /* Bit 4: Port Power Control */
#define EHCI_HCSPARAMS_PRR (1 << 7) /* Bit 7: Port Routing Rules */
#define EHCI_HCSPARAMS_NPCC_SHIFT (8) /* Bit 8-11: Number of Ports per Companion Controller */
#define EHCI_HCSPARAMS_NPCC_MASK (15 << EHCI_HCSPARAMS_NPCC_SHIFT)
#define EHCI_HCSPARAMS_NCC_SHIFT (12) /* Bit 12-15: Number of Companion Controllers */
#define EHCI_HCSPARAMS_NCC_MASK (15 << EHCI_HCSPARAMS_NCC_SHIFT)
#define EHCI_HCSPARAMS_PIND (1 << 16) /* Bit 16: Port Indicators */
#define EHCI_HCSPARAMS_DBGPORT_SHIFT (20) /* Bit 20-23: Debug Port Number */
#define EHCI_HCSPARAMS_DBGPORT_MASK (15 << EHCI_HCSPARAMS_DBGPORT_SHIFT)
/* Capability Parameters. Paragraph 2.2.4 */
#define EHCI_HCCPARAMS_64BIT (1 << 0) /* Bit 0: 64-bit Addressing Capability */
#define EHCI_HCCPARAMS_PFLF (1 << 1) /* Bit 1: Programmable Frame List Flag */
#define EHCI_HCCPARAMS_ASPC (1 << 2) /* Bit 2: Asynchronous Schedule Park Capability */
#define EHCI_HCCPARAMS_IST_SHIFT (4) /* Bits 4-7: Isochronous Scheduling Threshold */
#define EHCI_HCCPARAMS_IST_MASK (15 << EHCI_HCCPARAMS_IST_SHIFT)
#define EHCI_HCCPARAMS_EECP_SHIFT (8) /* Bits 8-15: EHCI Extended Capabilities Pointer */
#define EHCI_HCCPARAMS_EECP_MASK (0xff << EHCI_HCCPARAMS_EECP_SHIFT)
/* Host Controller Operational Register Bit Definitions *********************/
/* USB Command. Paragraph 2.3.1 */
#define EHCI_USBCMD_RUN (1 << 0) /* Bit 0: Run/Stop */
#define EHCI_USBCMD_HCRESET (1 << 1) /* Bit 1: Host Controller Reset */
#define EHCI_USBCMD_FLSIZE_SHIFT (2) /* Bits 2-3: Frame List Size */
#define EHCI_USBCMD_FLSIZE_MASK (3 << EHCI_USBCMD_FLSIZE_SHIFT)
#define EHCI_USBCMD_FLSIZE_1024 (0 << EHCI_USBCMD_FLSIZE_SHIFT) /* 1024 elements (4096 bytes) */
#define EHCI_USBCMD_FLSIZE_512 (1 << EHCI_USBCMD_FLSIZE_SHIFT) /* 512 elements (2048 bytes) */
#define EHCI_USBCMD_FLSIZE_256 (2 << EHCI_USBCMD_FLSIZE_SHIFT) /* 256 elements (1024 bytes) */
#define EHCI_USBCMD_PSEN (1 << 4) /* Bit 4: Periodic Schedule Enable */
#define EHCI_USBCMD_ASEN (1 << 5) /* Bit 5: Asynchronous Schedule Enable */
#define EHCI_USBCMD_IAAD (1 << 6) /* Bit 6: Interrupt on Async Advance Doorbell */
#define EHCI_USBCMD_LRESET (1 << 7) /* Bit 7: Light Host Controller Reset */
#define EHCI_USBCMD_ASYNC_PARKCNT_SHIFT (8) /* Bits 8-9: Asynchronous Schedule Park Mode Count */
#define EHCI_USBCMD_ASYNC_PARKCNT_MASK (3 << EHCI_USBCMD_ASYNC_PARKCNT_SHIFT)
#define EHCI_USBCMD_ASYNC_PARK (1 << 11) /* Bit 11: Asynchronous Schedule Park Mode Enable */
#define EHCI_USBCMD_ITHRE_SHIFT (16) /* Bits 16-23: Interrupt Threshold Control */
#define EHCI_USBCMD_ITHRE_MASK (0xff << EHCI_USBCMD_ITHRE_SHIFT)
#define EHCI_USBCMD_ITHRE_1MF (0x01 << EHCI_USBCMD_ITHRE_SHIFT) /* 1 micro-frame */
#define EHCI_USBCMD_ITHRE_2MF (0x02 << EHCI_USBCMD_ITHRE_SHIFT) /* 2 micro-frames */
#define EHCI_USBCMD_ITHRE_4MF (0x04 << EHCI_USBCMD_ITHRE_SHIFT) /* 4 micro-frames */
#define EHCI_USBCMD_ITHRE_8MF (0x08 << EHCI_USBCMD_ITHRE_SHIFT) /* 8 micro-frames (default, 1 ms) */
#define EHCI_USBCMD_ITHRE_16MF (0x10 << EHCI_USBCMD_ITHRE_SHIFT) /* 16 micro-frames (2 ms) */
#define EHCI_USBCMD_ITHRE_32MF (0x20 << EHCI_USBCMD_ITHRE_SHIFT) /* 32 micro-frames (4 ms) */
#define EHCI_USBCMD_ITHRE_64MF (0x40 << EHCI_USBCMD_ITHRE_SHIFT) /* 64 micro-frames (8 ms) */
/* USB Status. Paragraph 2.3.2 */
#define EHCI_USBSTS_INT (1 << 0) /* Bit 0: USB Interrupt */
#define EHCI_USBSTS_ERR (1 << 1) /* Bit 1: USB Error Interrupt */
#define EHCI_USBSTS_PCD (1 << 2) /* Bit 2: Port Change Detect */
#define EHCI_USBSTS_FLR (1 << 3) /* Bit 3: Frame List Rollover */
#define EHCI_USBSTS_FATAL (1 << 4) /* Bit 4: Host System Error */
#define EHCI_USBSTS_IAA (1 << 5) /* Bit 5: Interrupt on Async Advance */
#define EHCI_USBSTS_HALTED (1 << 12) /* Bit 12: HC Halted */
#define EHCI_USBSTS_RECLAM (1 << 13) /* Bit 13: Reclamation */
#define EHCI_USBSTS_PSS (1 << 14) /* Bit 14: Periodic Schedule Status */
#define EHCI_USBSTS_ASS (1 << 15) /* Bit 15: Asynchronous Schedule Status */
/* Bits 16-31: Reserved */
/* USB Interrupt Enable. Paragraph 2.3.3 */
#define EHCI_USBIE_INT (1 << 0) /* Bit 0: USB Interrupt */
#define EHCI_USBIE_ERR (1 << 1) /* Bit 1: USB Error Interrupt */
#define EHCI_USBIE_PCD (1 << 2) /* Bit 2: Port Change Detect */
#define EHCI_USBIE_FLROLL (1 << 3) /* Bit 3: Frame List Rollover */
#define EHCI_USBIE_FATAL (1 << 4) /* Bit 4: Host System Error */
#define EHCI_USBIE_IAA (1 << 5) /* Bit 5: Interrupt on Async Advance */
#define EHCI_USBIE_ALLINTS (0x3f) /* Bits 0-5: All interrupts */
/* USB Frame Index. Paragraph 2.3.4 */
#define EHCI_FRINDEX_MASK (0x3fff) /* Bits 0-13: Frame index */
/* 4G Segment Selector.
* Paragraph 2.3.5, Bits[64:32] of data structure addresses
*/
/* Frame List Base Address. Paragraph 2.3.6 */
#define EHCI_PERIODICLISTBASE_MASK (0xfffff000) /* Bits 12-31: Base Address (Low) */
/* Next Asynchronous List Address. Paragraph 2.3.7 */
#define EHCI_ASYNCLISTADDR_MASK (0xffffffe0) /* Bits 5-31: Link Pointer Low (LPL) */
/* Configured Flag Register. Paragraph 2.3.8 */
#define EHCI_CONFIGFLAG (1 << 0) /* Bit 0: Configure Flag */
/* Port Status/Control, Port 1-n. Paragraph 2.3.9 */
#define EHCI_PORTSC_CCS (1 << 0) /* Bit 0: Current Connect Status */
#define EHCI_PORTSC_CSC (1 << 1) /* Bit 1: Connect Status Change */
#define EHCI_PORTSC_PE (1 << 2) /* Bit 2: Port Enable */
#define EHCI_PORTSC_PEC (1 << 3) /* Bit 3: Port Enable/Disable Change */
#define EHCI_PORTSC_OCA (1 << 4) /* Bit 4: Over-current Active */
#define EHCI_PORTSC_OCC (1 << 5) /* Bit 5: Over-current Change */
#define EHCI_PORTSC_RESUME (1 << 6) /* Bit 6: Force Port Resume */
#define EHCI_PORTSC_SUSPEND (1 << 7) /* Bit 7: Suspend */
#define EHCI_PORTSC_RESET (1 << 8) /* Bit 8: Port Reset */
#define EHCI_PORTSC_LSTATUS_SHIFT (10) /* Bits 10-11: Line Status */
#define EHCI_PORTSC_LSTATUS_MASK (3 << EHCI_PORTSC_LSTATUS_SHIFT)
#define EHCI_PORTSC_LSTATUS_SE0 (0 << EHCI_PORTSC_LSTATUS_SHIFT) /* SE0 Not Low-speed device, perform EHCI reset */
#define EHCI_PORTSC_LSTATUS_KSTATE (1 << EHCI_PORTSC_LSTATUS_SHIFT) /* K-state Low-speed device, release ownership of port */
#define EHCI_PORTSC_LSTATUS_JSTATE (2 << EHCI_PORTSC_LSTATUS_SHIFT) /* J-state Not Low-speed device, perform EHCI reset */
#define EHCI_PORTSC_PP (1 << 12) /* Bit 12: Port Power */
#define EHCI_PORTSC_OWNER (1 << 13) /* Bit 13: Port Owner */
#define EHCI_PORTSC_PIC_SHIFT (14) /* Bits 14-15: Port Indicator Control */
#define EHCI_PORTSC_PIC_MASK (3 << EHCI_PORTSC_PIC_SHIFT)
#define EHCI_PORTSC_PIC_OFF (0 << EHCI_PORTSC_PIC_SHIFT) /* Port indicators are off */
#define EHCI_PORTSC_PIC_AMBER (1 << EHCI_PORTSC_PIC_SHIFT) /* Amber */
#define EHCI_PORTSC_PIC_GREEN (2 << EHCI_PORTSC_PIC_SHIFT) /* Green */
#define EHCI_PORTSC_PTC_SHIFT (16) /* Bits 16-19: Port Test Control */
#define EHCI_PORTSC_PTC_MASK (15 << EHCI_PORTSC_PTC_SHIFT)
#define EHCI_PORTSC_PTC_DISABLED (0 << EHCI_PORTSC_PTC_SHIFT) /* Test mode not enabled */
#define EHCI_PORTSC_PTC_JSTATE (1 << EHCI_PORTSC_PTC_SHIFT) /* Test J_STATE */
#define EHCI_PORTSC_PTC_KSTATE (2 << EHCI_PORTSC_PTC_SHIFT) /* Test K_STATE */
#define EHCI_PORTSC_PTC_SE0NAK (3 << EHCI_PORTSC_PTC_SHIFT) /* Test SE0_NAK */
#define EHCI_PORTSC_PTC_PACKET (4 << EHCI_PORTSC_PTC_SHIFT) /* Test Packet */
#define EHCI_PORTSC_PTC_ENABLE (5 << EHCI_PORTSC_PTC_SHIFT) /* Test FORCE_ENABLE */
#define EHCI_PORTSC_WKCCNTE (1 << 20) /* Bit 20: Wake on Connect Enable */
#define EHCI_PORTSC_WKDSCNNTE (1 << 21) /* Bit 21: Wake on Disconnect Enable */
#define EHCI_PORTSC_WKOCE (1 << 22) /* Bit 22: Wake on Over-current Enable */
/* Bits 23-31: Reserved */
#define EHCI_PORTSC_ALLINTS (EHCI_PORTSC_CSC | EHCI_PORTSC_PEC | \
EHCI_PORTSC_OCC | EHCI_PORTSC_RESUME)
/* Queue Head. Paragraph 3.6 */
/* Queue Head Horizontal Link Pointer: Queue Head DWord 0. Table 3-19 */
#define QH_HLP_END 0x1
#define QH_HLP_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0) /* Isochronous Transfer Descriptor */
#define QH_HLP_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2) /* Queue Head */
#define QH_HLP_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4) /* Split Transaction Isochronous Transfer Descriptor */
#define QH_HLP_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6) /* Frame Span Traversal Node */
/* Endpoint Characteristics: Queue Head DWord 1. Table 3-19 */
#define QH_EPCHAR_DEVADDR_SHIFT (0) /* Bitx 0-6: Device Address */
#define QH_EPCHAR_DEVADDR_MASK (0x7f << QH_EPCHAR_DEVADDR_SHIFT)
#define QH_EPCHAR_I (1 << 7) /* Bit 7: Inactivate on Next Transaction */
#define QH_EPCHAR_ENDPT_SHIFT (8) /* Bitx 8-11: Endpoint Number */
#define QH_EPCHAR_ENDPT_MASK (15 << QH_EPCHAR_ENDPT_SHIFT)
#define QH_EPCHAR_EPS_SHIFT (12) /* Bitx 12-13: Endpoint Speed */
#define QH_EPCHAR_EPS_MASK (3 << QH_EPCHAR_EPS_SHIFT)
#define QH_EPCHAR_EPS_FULL (0 << QH_EPCHAR_EPS_SHIFT) /* Full-Speed (12Mbs) */
#define QH_EPCHAR_EPS_LOW (1 << QH_EPCHAR_EPS_SHIFT) /* Low-Speed (1.5Mbs) */
#define QH_EPCHAR_EPS_HIGH (2 << QH_EPCHAR_EPS_SHIFT) /* High-Speed (480 Mb/s) */
#define QH_EPCHAR_DTC (1 << 14) /* Bit 14: Data Toggle Control */
#define QH_EPCHAR_H (1 << 15) /* Bit 15: Head of Reclamation List Flag */
#define QH_EPCHAR_MAXPKT_SHIFT (16) /* Bitx 16-26: Maximum Packet Length */
#define QH_EPCHAR_MAXPKT_MASK (0x7ff << QH_EPCHAR_MAXPKT_SHIFT)
#define QH_EPCHAR_C (1 << 27) /* Bit 27: Control Endpoint Flag */
#define QH_EPCHAR_RL_SHIFT (28) /* Bitx 28-31: Nak Count Reload */
#define QH_EPCHAR_RL_MASK (15 << QH_EPCHAR_RL_SHIFT)
/* Endpoint Capabilities: Queue Head DWord 2. Table 3-20 */
#define QH_EPCAPS_SSMASK_SHIFT (0) /* Bitx 0-7: Interrupt Schedule Mask (Frame S-mask) */
#define QH_EPCAPS_SSMASK_MASK (0xff << QH_EPCAPS_SSMASK_SHIFT)
#define QH_EPCAPS_SSMASK(n) ((n) << QH_EPCAPS_SSMASK_SHIFT)
#define QH_EPCAPS_SCMASK_SHIFT (8) /* Bitx 8-15: Split Completion Mask (Frame C-Mask) */
#define QH_EPCAPS_SCMASK_MASK (0xff << QH_EPCAPS_SCMASK_SHIFT)
#define QH_EPCAPS_SCMASK(n) ((n) << QH_EPCAPS_SCMASK_SHIFT)
#define QH_EPCAPS_HUBADDR_SHIFT (16) /* Bitx 16-22: Hub Address */
#define QH_EPCAPS_HUBADDR_MASK (0x7f << QH_EPCAPS_HUBADDR_SHIFT)
#define QH_EPCAPS_HUBADDR(n) ((n) << QH_EPCAPS_HUBADDR_SHIFT)
#define QH_EPCAPS_PORT_SHIFT (23) /* Bit 23-29: Port Number */
#define QH_EPCAPS_PORT_MASK (0x7f << QH_EPCAPS_PORT_SHIFT)
#define QH_EPCAPS_PORT(n) ((n) << QH_EPCAPS_PORT_SHIFT)
#define QH_EPCAPS_MULT_SHIFT (30) /* Bit 30-31: High-Bandwidth Pipe Multiplier */
#define QH_EPCAPS_MULT_MASK (3 << QH_EPCAPS_MULT_SHIFT)
#define QH_EPCAPS_MULT(n) ((n) << QH_EPCAPS_MULT_SHIFT)
/* qTD Token. Paragraph 3.5.3 */
#define QTD_LIST_END 1
#define QTD_TOKEN_STATUS_SHIFT (0) /* Bits 0-7: Status */
#define QTD_TOKEN_STATUS_MASK (0xff << QTD_TOKEN_STATUS_SHIFT)
#define QTD_TOKEN_STATUS_PINGSTATE (1 << 0) /* Bit 0 Ping State */
#define QTD_TOKEN_STATUS_ERR (1 << 0) /* Bit 0 Error */
#define QTD_TOKEN_STATUS_SPLITXSTATE (1 << 1) /* Bit 1 Split Transaction State */
#define QTD_TOKEN_STATUS_MMF (1 << 2) /* Bit 2 Missed Micro-Frame */
#define QTD_TOKEN_STATUS_XACTERR (1 << 3) /* Bit 3 Transaction Error */
#define QTD_TOKEN_STATUS_BABBLE (1 << 4) /* Bit 4 Babble Detected */
#define QTD_TOKEN_STATUS_DBERR (1 << 5) /* Bit 5 Data Buffer Error */
#define QTD_TOKEN_STATUS_HALTED (1 << 6) /* Bit 6 Halted */
#define QTD_TOKEN_STATUS_ACTIVE (1 << 7) /* Bit 7 Active */
#define QTD_TOKEN_STATUS_ERRORS (0x78 << QTD_TOKEN_STATUS_SHIFT)
#define QTD_TOKEN_PID_SHIFT (8) /* Bits 8-9: PID Code */
#define QTD_TOKEN_PID_MASK (3 << QTD_TOKEN_PID_SHIFT)
#define QTD_TOKEN_PID_OUT (0 << QTD_TOKEN_PID_SHIFT) /* OUT Token generates token (E1H) */
#define QTD_TOKEN_PID_IN (1 << QTD_TOKEN_PID_SHIFT) /* IN Token generates token (69H) */
#define QTD_TOKEN_PID_SETUP (2 << QTD_TOKEN_PID_SHIFT) /* SETUP Token generates token (2DH) */
#define QTD_TOKEN_CERR_SHIFT (10) /* Bits 10-11: Error Counter */
#define QTD_TOKEN_CERR_MASK (3 << QTD_TOKEN_CERR_SHIFT)
#define QTD_TOKEN_CPAGE_SHIFT (12) /* Bits 12-14: Current Page */
#define QTD_TOKEN_CPAGE_MASK (7 << QTD_TOKEN_CPAGE_SHIFT)
#define QTD_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */
#define QTD_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */
#define QTD_TOKEN_NBYTES_MASK (0x7fff << QTD_TOKEN_NBYTES_SHIFT)
#define QTD_TOKEN_TOGGLE (1 << 31) /* Bit 31: Data Toggle */
/* Isochronous (High-Speed) Transfer Descriptor (iTD). Paragraph 3.3 */
/* iTD Next Link Pointer. Paragraph 3.3.1 */
#define ITD_NLP_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0)
#define ITD_NLP_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2)
#define ITD_NLP_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4)
#define ITD_NLP_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6)
/* iTD Transaction Status and Control List. Paragraph 3.3.2 */
#define ITD_TSCL_XOFFS_SHIFT (0) /* Bits 0-11: Transaction X offset */
#define ITD_TSCL_XOFFS_MASK (0xfff << ITD_TSCL_XOFFS_SHIFT)
#define ITD_TSCL_PG_SHIFT (12) /* Bits 12-14: Page select */
#define ITD_TSCL_PG_MASK (7 << ITD_TSCL_PG_SHIFT)
#define ITD_TSCL_IOC (1 << 15) /* Bit 15: Interrupt On Comp */
#define ITD_TSCL_LENGTH_SHIFT (16) /* Bits 16-27: Transaction length */
#define ITD_TSCL_LENGTH_MASK (0xfff << ITD_TSCL_LENGTH_SHIFT)
#define ITD_TSCL_STATUS_SHIFT (28) /* Bits 28-31: Transaction status */
#define ITD_TSCL_STATUS_MASK (15 << ITD_TSCL_STATUS_SHIFT)
#define ITD_TSCL_STATUS_XACTERR (1 << 28) /* Bit 28: Transaction error */
#define ITD_TSCL_STATUS_BABBLE (1 << 29) /* Bit 29: Babble Detected */
#define ITD_TSCL_STATUS_DBERROR (1 << 30) /* Bit 30: Data Buffer Error */
#define ITD_TSCL_STATUS_ACTIVE (1 << 31) /* Bit 31: Active error */
/* iTD Buffer Page Pointer List. Paragraph 3.3.4 */
/* iTD Buffer Pointer Page 0. Table 3-4 */
#define ITD_BUFPTR0_DEVADDR_SHIFT (0) /* Bits 0-6: Device Address */
#define ITD_BUFPTR0_DEVADDR_MASK (0x7f << ITD_BUFPTR0_DEVADDR_SHIFT)
#define ITD_BUFPTR0_ENDPT_SHIFT (8) /* Bits 8-11: Endpoint Number */
#define ITD_BUFPTR0_ENDPT_MASK (15 << ITD_BUFPTR0_ENDPT_SHIFT)
/* iTD Buffer Pointer Page 1. Table 3-5 */
#define ITD_BUFPTR1_MAXPKT_SHIFT (0) /* Bits 0-10: Maximum Packet Size */
#define ITD_BUFPTR1_MAXPKT_MASK (0x7ff << ITD_BUFPTR1_MAXPKT_SHIFT)
#define ITD_BUFPTR1_DIRIN (1 << 11) /* Bit 11: Direction 1=IN */
#define ITD_BUFPTR1_DIROUT (0) /* Bit 11: Direction 0=OUT */
/* iTD Buffer Pointer Page 2. Table 3-6 */
#define ITD_BUFPTR2_MULTI_SHIFT (0) /* Bits 0-1: Multi */
#define ITD_BUFPTR2_MULTI_MASK (3 << ITD_BUFPTR2_MULTI_SHIFT)
#define ITD_BUFPTR2_MULTI_1 (1 << ITD_BUFPTR2_MULTI_SHIFT) /* One transaction per micro-frame */
#define ITD_BUFPTR2_MULTI_2 (2 << ITD_BUFPTR2_MULTI_SHIFT) /* Two transactions per micro-frame */
#define ITD_BUFPTR2_MULTI_3 (3 << ITD_BUFPTR2_MULTI_SHIFT) /* Three transactions per micro-frame */
/* Registers ****************************************************************/
/* Host Controller Capability Registers.
* This register block must be positioned at a well known address.
*/
struct ehci_hccr {
volatile uint8_t caplength; /* 0x00: Capability Register Length */
volatile uint8_t reserved; /* 0x01: reserved */
volatile uint16_t hciversion; /* 0x02: Interface Version Number */
volatile uint32_t hcsparams; /* 0x04: Structural Parameters */
volatile uint32_t hccparams; /* 0x08: Capability Parameters */
volatile uint8_t hcspportroute[8]; /* 0x0c: Companion Port Route Description */
};
/* Host Controller Operational Registers.
* This register block is positioned at an offset of 'caplength' from the
* beginning of the Host Controller Capability Registers.
*/
struct ehci_hcor {
volatile uint32_t usbcmd; /* 0x00: USB Command */
volatile uint32_t usbsts; /* 0x04: USB Status */
volatile uint32_t usbintr; /* 0x08: USB Interrupt Enable */
volatile uint32_t frindex; /* 0x0c: USB Frame Index */
volatile uint32_t ctrldssegment; /* 0x10: 4G Segment Selector */
volatile uint32_t periodiclistbase; /* 0x14: Frame List Base Address */
volatile uint32_t asynclistaddr; /* 0x18: Next Asynchronous List Address */
#ifndef CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
uint32_t reserved[9];
#endif
volatile uint32_t configflag; /* 0x40: Configured Flag Register */
volatile uint32_t portsc[15]; /* 0x44: Port Status/Control */
};
/* USB2 Debug Port Register Interface.
* This register block is normally found via the PCI capabalities.
* In non-PCI implementions, you need apriori information about the
* location of these registers.
*/
struct ehci_debug {
uint32_t psc; /* 0x00: Debug Port Control/Status Register */
uint32_t pids; /* 0x04: Debug USB PIDs Register */
uint32_t data[2]; /* 0x08: Debug Data buffer Registers */
uint32_t addr; /* 0x10: Device Address Register */
};
/* Data Structures **********************************************************/
/* Queue Element Transfer Descriptor (qTD). Paragraph 3.5 */
struct ehci_qtd {
uint32_t next_qtd; /* 0x00-0x03: Next qTD Pointer */
uint32_t alt_next_qtd; /* 0x04-0x07: Alternate Next qTD Pointer */
uint32_t token; /* 0x08-0x0b: qTD Token */
uint32_t bpl[5]; /* 0x0c-0x1c: Buffer Page Pointer List */
};
#define SIZEOF_EHCI_QTD (32) /* 8*sizeof(uint32_t) */
/* Queue Head. Paragraph 3.6 */
struct ehci_qh {
uint32_t hlp; /* 0x00-0x03: Queue Head Horizontal Link Pointer */
uint32_t epchar; /* 0x04-0x07: Endpoint Characteristics */
uint32_t epcap; /* 0x08-0x0b: Endpoint Capabilities */
uint32_t curr_qtd; /* 0x0c-0x0f: Current qTD Pointer */
struct ehci_qtd overlay; /* 0x10-0x2c: Transfer overlay */
};
#define SIZEOF_EHCI_QH (48) /* 4*sizeof(uint32_t) + 32 */
/* Isochronous (High-Speed) Transfer Descriptor (iTD).
* Paragraph 3.3. Must be aligned to 32-byte boundaries.
*/
struct ehci_itd {
uint32_t nlp; /* 0x00-0x03: Next link pointer */
uint32_t tscl[8]; /* 0x04-0x23: Transaction Status and Control List */
uint32_t bpl[7]; /* 0x24-0x3c: Buffer Page Pointer List */
};
#define SIZEOF_EHCI_ITD (64) /* 16*sizeof(uint32_t) */
/* Split Transaction Isochronous Transfer Descriptor (siTD). Paragraph 3.4 */
struct ehci_sitd {
uint32_t nlp; /* 0x00-0x03: Next link pointer */
uint32_t epchar; /* 0x04-0x07: Endpoint and Transaction Translator Characteristics */
uint32_t mfsc; /* 0x08-0x0b: Micro-frame Schedule Control */
uint32_t tsc; /* 0x0c-0x0f: Transfer Status and Control */
uint32_t bpl[2]; /* 0x10-0x17: Buffer Pointer List */
uint32_t blp; /* 0x18-0x1b: Back link pointer */
};
#define SIZEOF_EHCI_SITD (28) /* 7*sizeof(uint32_t) */
#endif /* __INCLUDE_NUTTX_USB_EHCI_H */
@@ -0,0 +1,179 @@
/*
* Copyright (c) 2022, Artinchip Technology Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <aic_core.h>
#include <aic_hal.h>
#include <hal_syscfg.h>
#include "usbh_core.h"
#include "usb_hc_ehci.h"
#include "usb_hc_ohci.h"
#if !defined(CONFIG_USB_EHCI_CONFIGFLAG)
#error "aic ehci must define CONFIG_USB_EHCI_CONFIGFLAG"
#endif
#if !defined(CONFIG_USB_EHCI_WITH_OHCI)
#error "aic must define CONFIG_USB_EHCI_WITH_OHCI for ls/fs device"
#endif
#if CONFIG_USB_OHCI_HCOR_OFFSET != 0x400
#error "aic CONFIG_USB_OHCI_HCOR_OFFSET must be 0x400"
#endif
extern void USBH_IRQHandler(uint8_t busid);
static void aic_ehci_isr(int vector, void *arg)
{
struct usbh_bus *bus = (struct usbh_bus *)arg;
extern void USBH_IRQHandler(uint8_t busid);
USBH_IRQHandler(bus->hcd.hcd_id);
}
static void aic_ohci_isr(int vector, void *arg)
{
struct usbh_bus *bus = (struct usbh_bus *)arg;
extern void OHCI_IRQHandler(uint8_t busid);
OHCI_IRQHandler(bus->hcd.hcd_id);
}
typedef struct aic_ehci_config {
uint32_t base_addr;
uint32_t clk_id;
uint32_t rst_id;
uint32_t phy_clk_id;
uint32_t phy_rst_id;
uint32_t irq_num;
}aic_ehci_config_t;
aic_ehci_config_t config[] = {
#ifdef AIC_USING_USB0_HOST
{
USB_HOST0_BASE,
CLK_USBH0,
RESET_USBH0,
CLK_USB_PHY0,
RESET_USBPHY0,
USB_HOST0_EHCI_IRQn
},
#else
{
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF
},
#endif
#ifdef AIC_USING_USB1_HOST
{
USB_HOST1_BASE,
CLK_USBH1,
RESET_USBH1,
CLK_USB_PHY1,
RESET_USBPHY1,
USB_HOST1_EHCI_IRQn
}
#endif
};
void usb_hc_low_level_init(struct usbh_bus *bus)
{
uint32_t val;
int i = 0;
for (i=0; i<sizeof(config)/sizeof(aic_ehci_config_t); i++) {
if (bus->hcd.reg_base == config[i].base_addr)
break;
}
if (i == sizeof(config)/sizeof(aic_ehci_config_t))
return;
/* set usb0 phy switch: Host/Device */
if (i == 0)
syscfg_usb_phy0_sw_host(1);
/* enable clock */
hal_clk_enable(config[i].phy_clk_id);
hal_clk_enable(config[i].clk_id);
aicos_udelay(300);
hal_reset_assert(config[i].phy_rst_id);
hal_reset_assert(config[i].rst_id);
aicos_udelay(300);
hal_reset_deassert(config[i].phy_rst_id);
hal_reset_deassert(config[i].rst_id);
aicos_udelay(300);
/* set phy type: UTMI/ULPI */
val = readl((volatile void *)(unsigned long)(config[i].base_addr+0x800));
#ifdef FPGA_BOARD_ARTINCHIP
/* fpga phy type = ULPI */
writel((val & ~0x1U), (volatile void *)(unsigned long)(config[i].base_addr+0x800));
#else
/* board phy type = UTMI */
writel((val | 0x1), (volatile void *)(unsigned long)(config[i].base_addr+0x800));
#endif
/* Set AHB2STBUS_INSREG01
Set EHCI packet buffer IN/OUT threshold (in DWORDs)
Must increase the OUT threshold to avoid underrun. (FIFO size - 4)
*/
writel((32 | (127 << 16)), (volatile void *)(unsigned long)(config[i].base_addr+0x94));
/* register interrupt callback */
aicos_request_irq(config[i].irq_num, (irq_handler_t)aic_ehci_isr,
0, "usb_host_ehci", bus);
aicos_request_irq(config[i].irq_num + 1, (irq_handler_t)aic_ohci_isr,
0, "usb_host_ohci", bus);
aicos_irq_enable(config[i].irq_num);
aicos_irq_enable(config[i].irq_num + 1);
}
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
{
return USB_SPEED_HIGH;
}
void usb_ehci_dcache_clean(uintptr_t addr, uint32_t len)
{
aicos_dcache_clean_range((size_t *)addr, len);
}
void usb_ehci_dcache_invalidate(uintptr_t addr, uint32_t len)
{
aicos_dcache_invalid_range((size_t *)addr, len);
}
void usb_ehci_dcache_clean_invalidate(uintptr_t addr, uint32_t len)
{
aicos_dcache_clean_invalid_range((size_t *)addr, len);
}
int __usbh_init(void)
{
#if defined(AIC_USING_USB0_HOST) || defined(AIC_USING_USB1_HOST)
int bus_id = 0;
#endif
#ifdef AIC_USING_USB0_HOST
usbh_initialize(bus_id, USB_HOST0_BASE);
bus_id++;
#endif
#ifdef AIC_USING_USB1_HOST
usbh_initialize(bus_id, USB_HOST1_BASE);
bus_id++;
#endif
return 0;
}
#if defined(KERNEL_RTTHREAD)
#include <rtthread.h>
#include <rtdevice.h>
INIT_ENV_EXPORT(__usbh_init);
#endif
@@ -0,0 +1,161 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "bflb_core.h"
#include "bflb_l1c.h"
#include "usbh_core.h"
#include "hardware/usb_v2_reg.h"
#ifndef CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
#error "usb host must enable CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE"
#endif
#define BLFB_USB_BASE ((uint32_t)0x20072000)
#define BFLB_PDS_BASE ((uint32_t)0x2000e000)
#define PDS_USB_CTL_OFFSET (0x500) /* usb_ctl */
#define PDS_USB_PHY_CTRL_OFFSET (0x504) /* usb_phy_ctrl */
/* 0x500 : usb_ctl */
#define PDS_REG_USB_SW_RST_N (1 << 0U)
#define PDS_REG_USB_EXT_SUSP_N (1 << 1U)
#define PDS_REG_USB_WAKEUP (1 << 2U)
#define PDS_REG_USB_L1_WAKEUP (1 << 3U)
#define PDS_REG_USB_DRVBUS_POL (1 << 4U)
#define PDS_REG_USB_IDDIG (1 << 5U)
/* 0x504 : usb_phy_ctrl */
#define PDS_REG_USB_PHY_PONRST (1 << 0U)
#define PDS_REG_USB_PHY_OSCOUTEN (1 << 1U)
#define PDS_REG_USB_PHY_XTLSEL_SHIFT (2U)
#define PDS_REG_USB_PHY_XTLSEL_MASK (0x3 << PDS_REG_USB_PHY_XTLSEL_SHIFT)
#define PDS_REG_USB_PHY_OUTCLKSEL (1 << 4U)
#define PDS_REG_USB_PHY_PLLALIV (1 << 5U)
#define PDS_REG_PU_USB20_PSW (1 << 6U)
#define USB_SOF_TIMER_MASK_AFTER_RESET_HS (0x44C)
#define USB_SOF_TIMER_MASK_AFTER_RESET_FS (0x2710)
extern void USBH_IRQHandler(uint8_t busid);
void USBH_IRQ(int irq, void *arg) {
USBH_IRQHandler(0);
}
static void bflb_usb_phy_init(void)
{
uint32_t regval;
/* USB_PHY_CTRL[3:2] reg_usb_phy_xtlsel=0 */
/* 2000e504 = 0x40; #100; USB_PHY_CTRL[6] reg_pu_usb20_psw=1 (VCC33A) */
/* 2000e504 = 0x41; #500; USB_PHY_CTRL[0] reg_usb_phy_ponrst=1 */
/* 2000e500 = 0x20; #100; USB_CTL[0] reg_usb_sw_rst_n=0 */
/* 2000e500 = 0x22; #500; USB_CTL[1] reg_usb_ext_susp_n=1 */
/* 2000e500 = 0x23; #100; USB_CTL[0] reg_usb_sw_rst_n=1 */
/* #1.2ms; wait UCLK */
/* wait(soc616_b0.usb_uclk); */
regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
regval &= ~PDS_REG_USB_PHY_XTLSEL_MASK;
putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
regval |= PDS_REG_PU_USB20_PSW;
putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
regval |= PDS_REG_USB_PHY_PONRST;
putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
/* greater than 5T */
bflb_mtimer_delay_us(1);
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
regval &= ~PDS_REG_USB_SW_RST_N;
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
/* greater than 5T */
bflb_mtimer_delay_us(1);
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
regval |= PDS_REG_USB_EXT_SUSP_N;
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
/* wait UCLK 1.2ms */
bflb_mtimer_delay_ms(3);
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
regval |= PDS_REG_USB_SW_RST_N;
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
bflb_mtimer_delay_ms(2);
}
void usb_hc_low_level_init(struct usbh_bus *bus)
{
uint32_t regval;
bflb_usb_phy_init();
bflb_irq_attach(37, USBH_IRQ, NULL);
bflb_irq_enable(37);
/* enable device-A for host */
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
regval &= ~PDS_REG_USB_IDDIG;
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
regval = getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
regval |= USB_A_BUS_DROP_HOV;
regval &= ~USB_A_BUS_REQ_HOV;
putreg32(regval, BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
bflb_mtimer_delay_ms(10);
/* enable vbus and bus control */
regval = getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
regval &= ~USB_A_BUS_DROP_HOV;
regval |= USB_A_BUS_REQ_HOV;
putreg32(regval, BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
regval = getreg32(BLFB_USB_BASE + USB_GLB_INT_OFFSET);
regval |= USB_MDEV_INT;
regval |= USB_MOTG_INT;
regval &= ~USB_MHC_INT;
putreg32(regval, BLFB_USB_BASE + USB_GLB_INT_OFFSET);
}
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
{
uint8_t speed = 3;
speed = (getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET) & USB_SPD_TYP_HOV_POV_MASK) >> USB_SPD_TYP_HOV_POV_SHIFT;
if (speed == 0) {
return USB_SPEED_FULL;
} else if (speed == 1) {
return USB_SPEED_LOW;
} else if (speed == 2) {
return USB_SPEED_HIGH;
}
return USB_SPEED_HIGH;
}
#ifdef CONFIG_USB_DCACHE_ENABLE
void usb_dcache_clean(uintptr_t addr, size_t size)
{
bflb_l1c_dcache_clean_range((void *)addr, size);
}
void usb_dcache_invalidate(uintptr_t addr, size_t size)
{
bflb_l1c_dcache_invalidate_range((void *)addr, size);
}
void usb_dcache_flush(uintptr_t addr, size_t size)
{
bflb_l1c_dcache_clean_invalidate_range((void *)addr, size);
}
#endif
@@ -0,0 +1,55 @@
#ifdef __rtems__
#include <rtems.h>
#include <rtems/pci.h>
#include <bsp/irq.h>
#include "usbh_core.h"
uint32_t echi_base;
static int ehci_bus;
static int ehci_slot;
static int ehci_function;
static int ehci_vector;
extern void USBH_IRQHandler(uint8_t busid);
void ehci_pci_scan(int bus, int slot, int fun, int vector)
{
ehci_bus = bus;
ehci_slot = slot;
ehci_function = fun;
ehci_vector = vector;
pci_read_config_dword(bus, slot, fun, PCI_BASE_ADDRESS_0, &echi_base);
}
void usb_hc_low_level_init(struct usbh_bus *bus)
{
//set software own ehci
uint32_t legacy_val;
pci_write_config_dword(ehci_bus, ehci_slot, ehci_function, 0x68, 1 << 24);
pci_read_config_dword(ehci_bus, ehci_slot, ehci_function, 0x68, &legacy_val);
if ((legacy_val & 0x01010000) == 0x01000000)
printf("OS owned echi\n");
else
printf("BIOS owned echi\n");
rtems_status_code sc;
sc = rtems_interrupt_handler_install(
ehci_vector,
"USBirq",
RTEMS_INTERRUPT_SHARED,
USBH_IRQHandler,
(void *)0);
if (sc != RTEMS_SUCCESSFUL) {
printf("USB install isr falied,%s\n", rtems_status_text(sc));
return;
}
}
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
{
printf("USB_SPEED_HIGH present\n");
return USB_SPEED_HIGH;
}
#endif
@@ -0,0 +1,117 @@
/**************************************************************************/ /**
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-8-8 Wayne First version
*
******************************************************************************/
#include "rtthread.h"
#include "NuMicro.h"
#include "rthw.h"
#include "drv_sys.h"
#define LOG_TAG "drv.cherry"
#define DBG_ENABLE
#define DBG_SECTION_NAME LOG_TAG
#define DBG_LEVEL DBG_LOG
#define DBG_COLOR
#include <rtdbg.h>
#if defined(PKG_CHERRYUSB_HOST)
#include "usbh_core.h"
static void nu_echi_isr(int vector, void *param)
{
uint8_t busid = (uint8_t)param;
extern void USBH_IRQHandler(uint8_t busid);
USBH_IRQHandler(busid);
}
static void nu_ochi_isr(int vector, void *param)
{
}
void usb_hc_low_level_init(struct usbh_bus *bus)
{
int timeout = 100;
if (bus->hcd.reg_base == HSUSBH0_BASE) {
/* Enable USBH clock */
CLK_EnableModuleClock(HUSBH0_MODULE);
SYS_ResetModule(HSUSBH0_RST);
/* Clock engine clock Configuration */
SYS->USBPMISCR &= ~(SYS_USBPMISCR_PHY0POR_Msk | SYS_USBPMISCR_PHY0COMN_Msk);
rt_thread_mdelay(20);
SYS->USBPMISCR |= SYS_USBPMISCR_PHY0SUSPEND_Msk | SYS_USBPMISCR_PHY0COMN_Msk;
/* set UHOVRCURH(SYS_MISCFCR0[12]) 1 => USBH Host over-current detect is high-active */
/* 0 => USBH Host over-current detect is low-active */
//SYS->MISCFCR0 |= SYS_MISCFCR0_UHOVRCURH_Msk;
SYS->MISCFCR0 &= ~SYS_MISCFCR0_UHOVRCURH_Msk;
while (1) {
rt_thread_mdelay(1);
if (SYS->USBPMISCR & SYS_USBPMISCR_PHY0HSTCKSTB_Msk)
break; /* both USB PHY0 and PHY1 clock 60MHz UTMI clock stable */
timeout--;
if (timeout == 0) {
rt_kprintf("USB PHY reset failed. USBPMISCR = 0x%08x\n", SYS->USBPMISCR);
return;
}
}
/* Register interrupt service routine. */
rt_hw_interrupt_install(HSUSBH0_IRQn, nu_echi_isr, (void *)bus->hcd.hcd_id, "ehci0");
/* Enable interrupt */
rt_hw_interrupt_umask(HSUSBH0_IRQn);
} else if (bus->hcd.reg_base == HSUSBH1_BASE) {
/* Enable USBH clock */
CLK_EnableModuleClock(HUSBH1_MODULE);
SYS_ResetModule(HSUSBH1_RST);
/* Clock engine clock Configuration */
SYS->USBPMISCR &= ~(SYS_USBPMISCR_PHY1POR_Msk | SYS_USBPMISCR_PHY1COMN_Msk);
rt_thread_mdelay(20);
SYS->USBPMISCR |= SYS_USBPMISCR_PHY1SUSPEND_Msk | SYS_USBPMISCR_PHY1COMN_Msk;
/* set UHOVRCURH(SYS_MISCFCR0[12]) 1 => USBH Host over-current detect is high-active */
/* 0 => USBH Host over-current detect is low-active */
//SYS->MISCFCR0 |= SYS_MISCFCR0_UHOVRCURH_Msk;
SYS->MISCFCR0 &= ~SYS_MISCFCR0_UHOVRCURH_Msk;
while (1) {
rt_thread_mdelay(1);
if (SYS->USBPMISCR & SYS_USBPMISCR_PHY1HSTCKSTB_Msk)
break; /* both USB PHY0 and PHY1 clock 60MHz UTMI clock stable */
timeout--;
if (timeout == 0) {
rt_kprintf("USB PHY reset failed. USBPMISCR = 0x%08x\n", SYS->USBPMISCR);
return;
}
}
/* Register interrupt service routine. */
rt_hw_interrupt_install(HSUSBH1_IRQn, nu_echi_isr, (void *)bus->hcd.hcd_id, "ehci1");
/* Enable interrupt */
rt_hw_interrupt_umask(HSUSBH1_IRQn);
}
}
void usb_hc_low_level2_init(struct usbh_bus *bus)
{
}
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
{
return USB_SPEED_HIGH;
}
#endif
@@ -0,0 +1,62 @@
/**************************************************************************/ /**
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-8-8 Wayne First version
*
******************************************************************************/
#include "rtthread.h"
#include "NuMicro.h"
#include "rthw.h"
#include "drv_sys.h"
#define LOG_TAG "drv.cherry"
#define DBG_ENABLE
#define DBG_SECTION_NAME LOG_TAG
#define DBG_LEVEL DBG_LOG
#define DBG_COLOR
#include <rtdbg.h>
#if defined(PKG_CHERRYUSB_HOST)
#include "usbh_core.h"
static void nu_ehci_isr(int vector, void *param)
{
extern void USBH_IRQHandler(uint8_t busid);
USBH_IRQHandler(0);
}
void usb_hc_low_level_init(struct usbh_bus *bus)
{
LOG_D("%s %d", __FUNCTION__, __LINE__);
rt_hw_interrupt_mask(IRQ_EHCI);
/* Enable USBH clock */
nu_sys_ipclk_enable(USBHCKEN);
nu_sys_ip_reset(USBHRST);
outpw(0xB0015000 + 0xC4, 0x160); //HSUSBH->USBPCR0 = 0x160; /* enable PHY 0 */
outpw(0xB0015000 + 0xC8, 0x520); //HSUSBH->USBPCR1 = 0x520; /* enable PHY 1 */
//USBH->HcMiscControl |= USBH_HcMiscControl_OCAL_Msk; /* Over-current active low */
//outpw(0xB0017000 + 0x204, inpw(0xB0017000 + 0x204) | (0x1ul << 3));
//USBH->HcMiscControl &= ~USBH_HcMiscControl_OCAL_Msk; /* Over-current active high */
outpw(0xB0017000 + 0x204, inpw(0xB0017000 + 0x204) & (~(0x1ul << 3)));
rt_hw_interrupt_install(IRQ_EHCI, nu_ehci_isr, NULL, "ehci-1");
rt_hw_interrupt_set_priority(IRQ_EHCI, IRQ_LEVEL_1);
rt_hw_interrupt_umask(IRQ_EHCI);
}
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
{
return USB_SPEED_HIGH;
}
#endif
@@ -0,0 +1,203 @@
/*
* Copyright (c) 2025, YC113
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usb_hc_ehci.h"
#ifdef CONFIG_USB_EHCI_WITH_OHCI
#include "usb_hc_ohci.h"
#endif
#include "interrupt.h"
#include "drv_reg_base.h"
#include "drv_clock.h"
#if CONFIG_USBHOST_MAX_BUS != 2
#error "t113 has 2 usb host controller"
#endif
#if CONFIG_USB_OHCI_HCOR_OFFSET != 0x400
#error "t113 CONFIG_USB_OHCI_HCOR_OFFSET must be 0x400"
#endif
#if defined(CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE)
#error "t113 usb ehci register need reserved"
#endif
#if !defined(CONFIG_USB_EHCI_CONFIGFLAG)
#error "t113 usb ehci has configflag register"
#endif
#if defined(CONFIG_USB_EHCI_ISO)
#error "t113 usb ehci no iso register"
#endif
void usb_select_phyTohci(void)
{
*(volatile rt_uint32_t *)(USB0_OTG_BASE_ADDR + 0x420) &= ~(1 << 0);
}
void usb_gate_open(rt_uint8_t busid)
{
rt_uint32_t addr;
addr = (rt_uint32_t)&CCU->usb0_clk + busid * 4;
if(busid == 0) {
/* otg gate open*/
CCU->usb_bgr |= 1 << 8;
/* otg bus reset */
CCU->usb_bgr &= ~(1 << 24);
sdelay(10);
CCU->usb_bgr |= (1 << 24);
sdelay(10);
}
/* ehci gate open */
CCU->usb_bgr |= (1 << 4) << busid;
/* ehci bus reset */
CCU->usb_bgr &= ~((1 << 20) << busid);
sdelay(10);
CCU->usb_bgr |= (1 << 20) << busid;
sdelay(10);
/* ohci gate open */
CCU->usb_bgr |= 1 << busid;
/* ohci bus reset */
CCU->usb_bgr &= ~((1 << 16) << busid);
sdelay(10);
CCU->usb_bgr |= (1 << 16) << busid;
sdelay(10);
sdelay(10);
/* clock enable */
*(volatile rt_uint32_t *)addr &= ~(3 << 24);
*(volatile rt_uint32_t *)addr |= (1 << 31) | (1 << 24);
/* reset phy */
*(volatile rt_uint32_t *)addr &= ~(1 << 30);
sdelay(10);
*(volatile rt_uint32_t *)addr |= 1 << 30;
sdelay(10);
/* otg phy select */
if(busid == 0) usb_select_phyTohci();
USB_LOG_DBG("usb%d gate : %X, clock : %X\n", busid, CCU->usb_bgr, *(volatile rt_uint32_t *)addr);
}
void usb_clean_siddp(struct usbh_bus *bus)
{
*(volatile rt_uint32_t *)(bus->hcd.reg_base + 0x810) &= ~(1 << 3);
}
void usb_hci_set_passby(struct usbh_bus *bus)
{
/* AHB Master interface INCR16 enable */
/* AHB Master interface INCR8 enable */
/* AHB Master interface burst type INCR4 enable */
/* AHB Master interface INCRX align enable */
/* ULPI bypass enable */
*(volatile rt_uint32_t *)(bus->hcd.reg_base + 0x800) |= (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 0);
}
void t113_ehci_isr(int vector, void *arg)
{
rt_interrupt_enter();
struct usbh_bus *bus = (struct usbh_bus *)arg;
USB_LOG_DBG("t113_ehci_isr");
extern void USBH_IRQHandler(uint8_t busid);
USBH_IRQHandler(bus->hcd.hcd_id);
rt_interrupt_leave();
}
#ifdef CONFIG_USB_EHCI_WITH_OHCI
void t113_ohci_isr(int vector, void *arg)
{
rt_interrupt_enter();
struct usbh_bus *bus = (struct usbh_bus *)arg;
USB_LOG_DBG("t113_ohci_isr");
extern void OHCI_IRQHandler(uint8_t busid);
OHCI_IRQHandler(bus->hcd.hcd_id);
rt_interrupt_leave();
}
#endif
void usb_hc_low_level_init(struct usbh_bus *bus)
{
int vector;
RT_ASSERT(bus->busid <= 1);
usb_gate_open(bus->busid);
usb_clean_siddp(bus);
usb_hci_set_passby(bus);
/* register EHCI interrupt callback */
vector = T113_IRQ_USB0_EHCI + (bus->busid > 0 ? 3 : 0);
rt_hw_interrupt_install(vector, t113_ehci_isr, bus, RT_NULL);
rt_hw_interrupt_umask(vector);
/* register OHCI interrupt callback */
#ifdef CONFIG_USB_EHCI_WITH_OHCI
rt_hw_interrupt_install(vector + 1, t113_ohci_isr, bus, RT_NULL);
rt_hw_interrupt_set_priority(vector, 11 << 4);
rt_hw_interrupt_umask(vector + 1);
#endif
USB_LOG_DBG("usb%d vector : %d, phy : %X\n", bus->busid, vector, *(volatile rt_uint32_t *)(bus->hcd.reg_base + 0x810));
USB_LOG_DBG("usb%d hc low level init success\n", bus->busid);
}
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
{
/* Defined by individual manufacturers */
uint32_t regval;
regval = EHCI_HCOR->portsc[port - 1];
if ((regval & EHCI_PORTSC_LSTATUS_MASK) == EHCI_PORTSC_LSTATUS_KSTATE)
return USB_SPEED_LOW;
if (regval & EHCI_PORTSC_PE)
return USB_SPEED_HIGH;
else
return USB_SPEED_FULL;
}
int __usbh_init(void)
{
#ifdef T113_USING_USB0_HOST
/* USB0 MSC test OK */
usbh_initialize(0, USB0_BASE_ADDR);
#endif
#ifdef T113_USING_USB1_HOST
/* USB1 MSC test OK */
usbh_initialize(1, USB1_BASE_ADDR);
#endif
return 0;
}
#ifdef PKG_CHERRYUSB_HOST
#include <rtthread.h>
#include <rtdevice.h>
INIT_ENV_EXPORT(__usbh_init);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _USB_EHCI_PRIV_H
#define _USB_EHCI_PRIV_H
#include "usbh_core.h"
#include "usbh_hub.h"
#include "usb_ehci_reg.h"
#define EHCI_HCCR ((struct ehci_hccr *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_EHCI_HCCR_OFFSET))
#define EHCI_HCOR ((struct ehci_hcor *)(uintptr_t)(bus->hcd.reg_base + CONFIG_USB_EHCI_HCCR_OFFSET + g_ehci_hcd[bus->hcd.hcd_id].hcor_offset))
#define EHCI_PTR2ADDR(x) ((uint32_t)(uintptr_t)(x) & ~0x1F)
#define EHCI_ADDR2QH(x) ((struct ehci_qh_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F))
#define EHCI_ADDR2QTD(x) ((struct ehci_qtd_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F))
#define EHCI_ADDR2ITD(x) ((struct ehci_itd_hw *)(uintptr_t)((uint32_t)(x) & ~0x1F))
#ifndef CONFIG_USB_EHCI_QH_NUM
#define CONFIG_USB_EHCI_QH_NUM 10
#endif
#ifndef CONFIG_USB_EHCI_QTD_NUM
#define CONFIG_USB_EHCI_QTD_NUM (CONFIG_USB_EHCI_QH_NUM * 3)
#endif
#ifndef CONFIG_USB_EHCI_ITD_NUM
#define CONFIG_USB_EHCI_ITD_NUM 5
#endif
#ifndef CONFIG_USB_EHCI_ISO_NUM
#define CONFIG_USB_EHCI_ISO_NUM 4
#endif
#if CONFIG_USB_ALIGN_SIZE <= 32
#define CONFIG_USB_EHCI_ALIGN_SIZE 32
#elif CONFIG_USB_ALIGN_SIZE <= 64
#define CONFIG_USB_EHCI_ALIGN_SIZE 64
#else
#error "CONFIG_USB_ALIGN_SIZE must be 32 or 64"
#endif
#if CONFIG_USB_EHCI_QTD_NUM < 9
#error CONFIG_USB_EHCI_QTD_NUM is too small, recommand CONFIG_USB_EHCI_QH_NUM * 3
#endif
struct ehci_qtd_hw {
struct ehci_qtd hw;
#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE) && (CONFIG_USB_ALIGN_SIZE == 64)
uint8_t pad[32];
#endif
bool inuse;
struct usbh_urb *urb;
uintptr_t bufaddr;
uint32_t length;
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
struct ehci_qh_hw {
struct ehci_qh hw;
#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE)
uint16_t pad[16];
#endif
bool inuse;
uint32_t first_qtd;
struct usbh_urb *urb;
usb_osal_sem_t waitsem;
uint8_t remove_in_iaad;
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
struct ehci_itd_hw {
struct ehci_itd hw;
struct usbh_urb *urb;
uint16_t start_frame;
uint8_t mf_unmask;
uint8_t mf_valid;
uint32_t pkt_idx[8];
bool dir_in;
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
struct ehci_iso_hw {
struct ehci_itd_hw itd_pool[CONFIG_USB_EHCI_ITD_NUM];
uint32_t itd_num;
};
struct ehci_hcd {
bool ehci_iso_used[CONFIG_USB_EHCI_ISO_NUM];
bool ppc; /* Port Power Control */
bool has_tt; /* if use tt instead of Companion Controller */
uint8_t n_cc; /* Number of Companion Controller */
uint8_t n_pcc; /* Number of ports supported per companion host controller */
uint8_t n_ports;
uint8_t hcor_offset;
};
extern struct ehci_hcd g_ehci_hcd[CONFIG_USBHOST_MAX_BUS];
extern uint32_t g_framelist[CONFIG_USBHOST_MAX_BUS][USB_ALIGN_UP(CONFIG_USB_EHCI_FRAME_LIST_SIZE, 1024)];
extern uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port);
int ehci_iso_urb_init(struct usbh_bus *bus, struct usbh_urb *urb);
void ehci_kill_iso_urb(struct usbh_bus *bus, struct usbh_urb *urb);
void ehci_scan_isochronous_list(struct usbh_bus *bus);
#endif