rtt更新

This commit is contained in:
2025-01-18 13:25:25 +08:00
parent c6a7554b51
commit d6009a0773
726 changed files with 103376 additions and 6270 deletions

View File

@@ -0,0 +1,14 @@
# Note
## Support Chip List
### NXP
Modify USB_NOCACHE_RAM_SECTION
```
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".NonCacheable")))
```
- IMRT10XX/IMRT11XX
- MCXN9XX/MCXN236

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,718 @@
/*
* Copyright (c) 2021-2024 HPMicro
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usb_chipidea_reg.h"
#define USB_OTG_DEV ((CHIPIDEA_TypeDef *)g_usbdev_bus[busid].reg_base)
#define CHIPIDEA_BITSMASK(val, offset) ((uint32_t)(val) << (offset))
#define QTD_COUNT_EACH_ENDPOINT (8U)
/* ENDPTCTRL */
enum {
ENDPTCTRL_STALL = CHIPIDEA_BITSMASK(1, 0),
ENDPTCTRL_TYPE = CHIPIDEA_BITSMASK(3, 2),
ENDPTCTRL_TOGGLE_INHIBIT = CHIPIDEA_BITSMASK(1, 5),
ENDPTCTRL_TOGGLE_RESET = CHIPIDEA_BITSMASK(1, 6),
ENDPTCTRL_ENABLE = CHIPIDEA_BITSMASK(1, 7),
};
/* USBSTS, USBINTR */
enum {
intr_usb = CHIPIDEA_BITSMASK(1, 0),
intr_error = CHIPIDEA_BITSMASK(1, 1),
intr_port_change = CHIPIDEA_BITSMASK(1, 2),
intr_reset = CHIPIDEA_BITSMASK(1, 6),
intr_sof = CHIPIDEA_BITSMASK(1, 7),
intr_suspend = CHIPIDEA_BITSMASK(1, 8),
intr_nak = CHIPIDEA_BITSMASK(1, 16)
};
/* Queue Transfer Descriptor */
typedef struct {
/* Word 0: Next QTD Pointer */
volatile uint32_t next; /* Next link pointer This field contains the physical memory address of the next dTD to be processed */
/* Word 1: qTQ Token */
volatile uint32_t : 3;
volatile uint32_t xact_err : 1;
volatile uint32_t : 1;
volatile uint32_t buffer_err : 1;
volatile uint32_t halted : 1;
volatile uint32_t active : 1;
volatile uint32_t : 2;
volatile uint32_t iso_mult_override : 2; /* This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO. */
volatile uint32_t : 3;
volatile uint32_t int_on_complete : 1;
volatile uint32_t total_bytes : 15;
volatile uint32_t : 0;
/* Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page */
volatile uint32_t buffer[5];
/*------------- DCD Area -------------*/
volatile uint16_t expected_bytes;
volatile uint8_t reserved[2];
} dcd_qtd_t;
/* Queue Head */
typedef struct {
/* Word 0: Capabilities and Characteristics */
volatile uint32_t : 15; /* Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed. */
volatile uint32_t int_on_setup : 1; /* Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received. */
volatile uint32_t max_packet_size : 11; /* This directly corresponds to the maximum packet size of the associated endpoint (wMaxPacketSize) */
volatile uint32_t : 2;
volatile uint32_t zero_length_termination : 1; /* This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length. */
volatile uint32_t iso_mult : 2;
volatile uint32_t : 0;
/* Word 1: Current qTD Pointer */
volatile uint32_t qtd_addr;
/* Word 2-9: Transfer Overlay */
volatile dcd_qtd_t qtd_overlay;
/* Word 10-11: Setup request (control OUT only) */
volatile struct usb_setup_packet setup_request;
/*--------------------------------------------------------------------
* Due to the fact QHD is 64 bytes aligned but occupies only 48 bytes
* thus there are 16 bytes padding free that we can make use of.
*--------------------------------------------------------------------
*/
volatile uint8_t reserved[16];
} dcd_qhd_t;
typedef struct {
dcd_qhd_t qhd[CONFIG_USBDEV_EP_NUM * 2];
dcd_qtd_t qtd[CONFIG_USBDEV_EP_NUM * 2 * QTD_COUNT_EACH_ENDPOINT];
} dcd_data_t;
/* Endpoint state */
struct chipidea_ep_state {
uint16_t ep_mps; /* Endpoint max packet size */
uint8_t ep_type; /* Endpoint type */
uint8_t ep_stalled; /* Endpoint stall flag */
uint8_t ep_enable; /* Endpoint enable */
uint8_t *xfer_buf;
uint32_t xfer_len;
uint32_t actual_xfer_len;
};
/* Driver state */
struct chipidea_udc {
dcd_data_t *dcd_data;
bool is_suspend;
struct chipidea_ep_state in_ep[CONFIG_USBDEV_EP_NUM]; /*!< IN endpoint parameters*/
struct chipidea_ep_state out_ep[CONFIG_USBDEV_EP_NUM]; /*!< OUT endpoint parameters */
} g_chipidea_udc[CONFIG_USBDEV_MAX_BUS];
static USB_NOCACHE_RAM_SECTION __attribute__((aligned(2048))) dcd_data_t _dcd_data0;
#if CONFIG_USBDEV_MAX_BUS == 2
static USB_NOCACHE_RAM_SECTION __attribute__((aligned(2048))) dcd_data_t _dcd_data1;
#endif
static dcd_data_t *g_dcd_data[CONFIG_USBDEV_MAX_BUS] = {
&_dcd_data0,
#if CONFIG_USBDEV_MAX_BUS == 2
&_dcd_data1
#endif
};
/* Index to bit position in register */
static inline uint8_t ep_idx2bit(uint8_t ep_idx)
{
return ep_idx / 2 + ((ep_idx % 2) ? 16 : 0);
}
static void __chipidea_bus_reset(CHIPIDEA_TypeDef *ptr)
{
/* The reset value for all endpoint types is the control endpoint. If one endpoint
* direction is enabled and the paired endpoint of opposite direction is disabled, then the
* endpoint type of the unused direction must be changed from the control type to any other
* type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
* for the data PID tracking on the active endpoint.
*/
for (uint32_t i = 1; i < CONFIG_USBDEV_EP_NUM; i++) {
ptr->ENDPTCTRL[i] = USB_ENDPTCTRL_TXT_SET(USB_ENDPOINT_TYPE_BULK) | USB_ENDPTCTRL_RXT_SET(USB_ENDPOINT_TYPE_BULK);
}
/* Clear All Registers */
ptr->ENDPTNAK = ptr->ENDPTNAK;
ptr->ENDPTNAKEN = 0;
ptr->USBSTS = ptr->USBSTS;
ptr->ENDPTSETUPSTAT = ptr->ENDPTSETUPSTAT;
ptr->ENDPTCOMPLETE = ptr->ENDPTCOMPLETE;
while (ptr->ENDPTPRIME) {
}
ptr->ENDPTFLUSH = 0xFFFFFFFF;
while (ptr->ENDPTFLUSH) {
}
}
static void chipidea_init(CHIPIDEA_TypeDef *ptr)
{
/* Reset controller */
ptr->USBCMD |= USB_USBCMD_RST_MASK;
while (USB_USBCMD_RST_GET(ptr->USBCMD)) {
}
/* Set mode to device, must be set immediately after reset */
ptr->USBMODE &= ~USB_USBMODE_CM_MASK;
ptr->USBMODE |= USB_USBMODE_CM_SET(2);
/* Disable setup lockout, please refer to "Control Endpoint Operation" section in RM. */
ptr->USBMODE &= ~USB_USBMODE_SLOM_MASK;
/* Set the endian */
ptr->USBMODE &= ~USB_USBMODE_ES_MASK;
/* Set parallel interface signal */
ptr->PORTSC1 &= ~USB_PORTSC1_STS_MASK;
/* Set parallel transceiver width */
ptr->PORTSC1 &= ~USB_PORTSC1_PTW_MASK;
/* Set usb forced to full speed mode */
//ptr->PORTSC1 |= USB_PORTSC1_PFSC_MASK;
/* Not use interrupt threshold. */
ptr->USBCMD &= ~USB_USBCMD_ITC_MASK;
/* Enable VBUS discharge */
ptr->OTGSC |= USB_OTGSC_VD_MASK;
}
static void chipidea_deinit(CHIPIDEA_TypeDef *ptr)
{
/* Stop */
ptr->USBCMD &= ~USB_USBCMD_RS_MASK;
/* Reset controller */
ptr->USBCMD |= USB_USBCMD_RST_MASK;
while (USB_USBCMD_RST_GET(ptr->USBCMD)) {
}
/* Reset endpoint list address register */
ptr->ENDPTLISTADDR = 0;
/* Reset status register */
ptr->USBSTS = ptr->USBSTS;
/* Reset interrupt enable register */
ptr->USBINTR = 0;
}
/*---------------------------------------------------------------------
* Endpoint API
*---------------------------------------------------------------------
*/
static void __chipidea_edpt_open(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr, uint8_t ep_type)
{
uint8_t const epnum = ep_addr & 0x0f;
uint8_t const dir = (ep_addr & 0x80) >> 7;
/* Enable EP Control */
uint32_t temp = ptr->ENDPTCTRL[epnum];
temp &= ~((0x03 << 2) << (dir ? 16 : 0));
temp |= ((ep_type << 2) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET) << (dir ? 16 : 0);
ptr->ENDPTCTRL[epnum] = temp;
}
static void chipidea_edpt_xfer(CHIPIDEA_TypeDef *ptr, uint8_t ep_idx)
{
uint32_t offset = ep_idx / 2 + ((ep_idx % 2) ? 16 : 0);
/* Start transfer */
ptr->ENDPTPRIME = 1 << offset;
}
static void chipidea_edpt_stall(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
{
uint8_t const epnum = ep_addr & 0x0f;
uint8_t const dir = (ep_addr & 0x80) >> 7;
ptr->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
}
static void chipidea_edpt_clear_stall(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
{
uint8_t const epnum = ep_addr & 0x0f;
uint8_t const dir = (ep_addr & 0x80) >> 7;
/* data toggle also need to be reset */
ptr->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << (dir ? 16 : 0);
ptr->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << (dir ? 16 : 0));
}
static bool chipidea_edpt_check_stall(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
{
uint8_t const epnum = ep_addr & 0x0f;
uint8_t const dir = (ep_addr & 0x80) >> 7;
return (ptr->ENDPTCTRL[epnum] & (ENDPTCTRL_STALL << (dir ? 16 : 0))) ? true : false;
}
static void chipidea_edpt_close(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
{
uint8_t const epnum = ep_addr & 0x0f;
uint8_t const dir = (ep_addr & 0x80) >> 7;
uint32_t primebit = CHIPIDEA_BITSMASK(1, epnum) << (dir ? 16 : 0);
/* Flush the endpoint to stop a transfer. */
do {
/* Set the corresponding bit(s) in the ENDPTFLUSH register */
ptr->ENDPTFLUSH |= primebit;
/* Wait until all bits in the ENDPTFLUSH register are cleared. */
while (0U != (ptr->ENDPTFLUSH & primebit)) {
}
/*
* Read the ENDPTSTAT register to ensure that for all endpoints
* commanded to be flushed, that the corresponding bits
* are now cleared.
*/
} while (0U != (ptr->ENDPTSTAT & primebit));
/* Disable the endpoint */
ptr->ENDPTCTRL[epnum] &= ~((ENDPTCTRL_TYPE | ENDPTCTRL_ENABLE | ENDPTCTRL_STALL) << (dir ? 16 : 0));
ptr->ENDPTCTRL[epnum] |= (USB_ENDPOINT_TYPE_BULK << 2) << (dir ? 16 : 0);
}
/* Initialize qtd */
static void usb_qtd_init(dcd_qtd_t *p_qtd, void *data_ptr, uint16_t total_bytes)
{
memset(p_qtd, 0, sizeof(dcd_qtd_t));
p_qtd->next = 1;
p_qtd->active = 1;
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
if (data_ptr != NULL) {
p_qtd->buffer[0] = (uint32_t)data_ptr;
for (uint8_t i = 1; i < 5; i++) {
p_qtd->buffer[i] |= ((p_qtd->buffer[i - 1]) & 0xFFFFF000UL) + 4096U;
}
}
}
static dcd_qhd_t *chipidea_qhd_get(uint8_t busid, uint8_t ep_idx)
{
dcd_data_t *dcd_data;
dcd_data = g_chipidea_udc[busid].dcd_data;
return &dcd_data->qhd[ep_idx];
}
static dcd_qtd_t *chipidea_qtd_get(uint8_t busid, uint8_t ep_idx)
{
dcd_data_t *dcd_data;
dcd_data = g_chipidea_udc[busid].dcd_data;
return &dcd_data->qtd[ep_idx * QTD_COUNT_EACH_ENDPOINT];
}
static void chipidea_bus_reset(uint8_t busid, uint16_t ep0_max_packet_size)
{
dcd_data_t *dcd_data;
dcd_data = g_chipidea_udc[busid].dcd_data;
__chipidea_bus_reset(USB_OTG_DEV);
/* Queue Head & Queue TD */
memset(dcd_data, 0, sizeof(dcd_data_t));
/* Set up Control Endpoints (0 OUT, 1 IN) */
dcd_data->qhd[0].zero_length_termination = dcd_data->qhd[1].zero_length_termination = 1;
dcd_data->qhd[0].max_packet_size = dcd_data->qhd[1].max_packet_size = ep0_max_packet_size;
dcd_data->qhd[0].qtd_overlay.next = dcd_data->qhd[1].qtd_overlay.next = 1;
/* OUT only */
dcd_data->qhd[0].int_on_setup = 1;
}
static void chipidea_edpt_open(uint8_t busid, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps)
{
uint8_t const epnum = ep_addr & 0x0f;
uint8_t const dir = (ep_addr & 0x80) >> 7;
uint8_t const ep_idx = 2 * epnum + dir;
dcd_data_t *dcd_data;
dcd_qhd_t *p_qhd;
/* Prepare Queue Head */
dcd_data = g_chipidea_udc[busid].dcd_data;
p_qhd = &dcd_data->qhd[ep_idx];
memset(p_qhd, 0, sizeof(dcd_qhd_t));
p_qhd->zero_length_termination = 1;
p_qhd->max_packet_size = ep_mps & 0x7FFu;
p_qhd->qtd_overlay.next = 1;
if (ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
p_qhd->iso_mult = ((ep_mps >> 11u) & 0x3u) + 1u;
}
__chipidea_edpt_open(USB_OTG_DEV, ep_addr, ep_type);
}
static bool chipidea_start_xfer(uint8_t busid, uint8_t ep_addr, uint8_t *buffer, uint32_t total_bytes)
{
uint8_t const epnum = ep_addr & 0x0f;
uint8_t const dir = (ep_addr & 0x80) >> 7;
uint8_t const ep_idx = 2 * epnum + dir;
uint8_t qtd_num;
uint8_t i;
uint32_t xfer_len;
dcd_qhd_t *p_qhd;
dcd_qtd_t *p_qtd;
dcd_qtd_t *first_p_qtd = NULL;
dcd_qtd_t *prev_p_qtd = NULL;
dcd_data_t *dcd_data;
dcd_data = g_chipidea_udc[busid].dcd_data;
if (epnum == 0) {
/* follows UM Setup packet handling using setup lockout mechanism
* wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
*/
while (USB_OTG_DEV->ENDPTSETUPSTAT & CHIPIDEA_BITSMASK(1, 0)) {
}
}
qtd_num = (total_bytes + 0x3fff) / 0x4000;
if (qtd_num > QTD_COUNT_EACH_ENDPOINT) {
return false;
}
if (buffer != NULL) {
buffer = (uint8_t *)buffer;
}
p_qhd = &dcd_data->qhd[ep_idx];
i = 0;
do {
p_qtd = &dcd_data->qtd[ep_idx * QTD_COUNT_EACH_ENDPOINT + i];
i++;
if (total_bytes > 0x4000) {
xfer_len = 0x4000;
total_bytes -= 0x4000;
} else {
xfer_len = total_bytes;
total_bytes = 0;
}
usb_qtd_init(p_qtd, (void *)buffer, xfer_len);
if (total_bytes == 0) {
p_qtd->int_on_complete = true;
}
buffer += xfer_len;
if (prev_p_qtd) {
prev_p_qtd->next = (uint32_t)p_qtd;
} else {
first_p_qtd = p_qtd;
}
prev_p_qtd = p_qtd;
} while (total_bytes > 0);
p_qhd->qtd_overlay.next = (uint32_t)first_p_qtd; /* link qtd to qhd */
chipidea_edpt_xfer(USB_OTG_DEV, ep_idx);
return true;
}
__WEAK void usb_dc_low_level_init(uint8_t busid)
{
}
__WEAK void usb_dc_low_level_deinit(uint8_t busid)
{
}
int usb_dc_init(uint8_t busid)
{
uint32_t int_mask;
int_mask = (USB_USBINTR_UE_MASK | USB_USBINTR_UEE_MASK | USB_USBINTR_SLE_MASK |
USB_USBINTR_PCE_MASK | USB_USBINTR_URE_MASK);
usb_dc_low_level_init(busid);
memset(&g_chipidea_udc[busid], 0, sizeof(struct chipidea_udc));
g_chipidea_udc[busid].dcd_data = g_dcd_data[busid];
memset(g_chipidea_udc[busid].dcd_data, 0, sizeof(dcd_data_t));
chipidea_init(USB_OTG_DEV);
/* Set endpoint list address */
USB_OTG_DEV->ENDPTLISTADDR = ((uint32_t)g_chipidea_udc[busid].dcd_data->qhd) & USB_ENDPTLISTADDR_EPBASE_MASK;
/* Clear status */
USB_OTG_DEV->USBSTS = USB_OTG_DEV->USBSTS;
/* Enable interrupt mask */
USB_OTG_DEV->USBINTR |= int_mask;
/* Connect by enabling internal pull-up resistor on D+/D- */
USB_OTG_DEV->USBCMD |= USB_USBCMD_RS_MASK;
return 0;
}
int usb_dc_deinit(uint8_t busid)
{
chipidea_deinit(USB_OTG_DEV);
for (uint32_t i = 0; i < CONFIG_USBDEV_EP_NUM; i++) {
chipidea_edpt_close(USB_OTG_DEV, (i | 0x80));
chipidea_edpt_close(USB_OTG_DEV, (i | 0x00));
}
usb_dc_low_level_deinit(busid);
return 0;
}
int usbd_set_address(uint8_t busid, const uint8_t addr)
{
USB_OTG_DEV->DEVICEADDR = USB_DEVICEADDR_USBADR_SET(addr) | USB_DEVICEADDR_USBADRA_MASK;
return 0;
}
int usbd_set_remote_wakeup(uint8_t busid)
{
if (!USB_PORTSC1_SUSP_GET(USB_OTG_DEV->PORTSC1)) {
return -1;
}
USB_OTG_DEV->PORTSC1 |= USB_PORTSC1_FPR_MASK;
while (USB_OTG_DEV->PORTSC1 & USB_PORTSC1_FPR_MASK) {
}
return 0;
}
uint8_t usbd_get_port_speed(uint8_t busid)
{
uint8_t speed;
speed = USB_PORTSC1_PSPD_GET(USB_OTG_DEV->PORTSC1);
if (speed == 0x00) {
return USB_SPEED_FULL;
}
if (speed == 0x01) {
return USB_SPEED_LOW;
}
if (speed == 0x02) {
return USB_SPEED_HIGH;
}
return 0;
}
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
{
uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
/* Must not exceed max endpoint number */
if (ep_idx >= CONFIG_USBDEV_EP_NUM) {
return -1;
}
chipidea_edpt_open(busid, ep->bEndpointAddress, USB_GET_ENDPOINT_TYPE(ep->bmAttributes), ep->wMaxPacketSize);
if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
g_chipidea_udc[busid].out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
g_chipidea_udc[busid].out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
g_chipidea_udc[busid].out_ep[ep_idx].ep_enable = true;
} else {
g_chipidea_udc[busid].in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
g_chipidea_udc[busid].in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
g_chipidea_udc[busid].in_ep[ep_idx].ep_enable = true;
}
return 0;
}
int usbd_ep_close(uint8_t busid, const uint8_t ep)
{
uint8_t ep_idx = USB_EP_GET_IDX(ep);
if (USB_EP_DIR_IS_OUT(ep)) {
g_chipidea_udc[busid].out_ep[ep_idx].ep_enable = false;
} else {
g_chipidea_udc[busid].in_ep[ep_idx].ep_enable = false;
}
chipidea_edpt_close(USB_OTG_DEV, ep);
return 0;
}
int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
{
chipidea_edpt_stall(USB_OTG_DEV, ep);
return 0;
}
int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
{
chipidea_edpt_clear_stall(USB_OTG_DEV, ep);
return 0;
}
int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
{
*stalled = chipidea_edpt_check_stall(USB_OTG_DEV, ep);
return 0;
}
int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
{
uint8_t ep_idx = USB_EP_GET_IDX(ep);
if (!data && data_len) {
return -1;
}
if (!g_chipidea_udc[busid].in_ep[ep_idx].ep_enable) {
return -2;
}
g_chipidea_udc[busid].in_ep[ep_idx].xfer_buf = (uint8_t *)data;
g_chipidea_udc[busid].in_ep[ep_idx].xfer_len = data_len;
g_chipidea_udc[busid].in_ep[ep_idx].actual_xfer_len = 0;
chipidea_start_xfer(busid, ep, (uint8_t *)data, data_len);
return 0;
}
int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len)
{
uint8_t ep_idx = USB_EP_GET_IDX(ep);
if (!data && data_len) {
return -1;
}
if (!g_chipidea_udc[busid].out_ep[ep_idx].ep_enable) {
return -2;
}
g_chipidea_udc[busid].out_ep[ep_idx].xfer_buf = (uint8_t *)data;
g_chipidea_udc[busid].out_ep[ep_idx].xfer_len = data_len;
g_chipidea_udc[busid].out_ep[ep_idx].actual_xfer_len = 0;
chipidea_start_xfer(busid, ep, data, data_len);
return 0;
}
void USBD_IRQHandler(uint8_t busid)
{
uint32_t int_status;
uint32_t transfer_len;
bool ep_cb_req;
/* Acknowledge handled interrupt */
int_status = USB_OTG_DEV->USBSTS;
int_status &= USB_OTG_DEV->USBINTR;
USB_OTG_DEV->USBSTS = int_status;
if (int_status & intr_error) {
USB_LOG_ERR("usbd intr error!\r\n");
}
if (int_status & intr_reset) {
g_chipidea_udc[busid].is_suspend = false;
memset(g_chipidea_udc[busid].in_ep, 0, sizeof(struct chipidea_ep_state) * CONFIG_USBDEV_EP_NUM);
memset(g_chipidea_udc[busid].out_ep, 0, sizeof(struct chipidea_ep_state) * CONFIG_USBDEV_EP_NUM);
usbd_event_reset_handler(busid);
chipidea_bus_reset(busid, 64);
}
if (int_status & intr_suspend) {
if (USB_PORTSC1_SUSP_GET(USB_OTG_DEV->PORTSC1)) {
/* Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. */
if (USB_DEVICEADDR_USBADR_GET(USB_OTG_DEV->DEVICEADDR)) {
g_chipidea_udc[busid].is_suspend = true;
usbd_event_suspend_handler(busid);
}
} else {
}
}
if (int_status & intr_port_change) {
if (!USB_PORTSC1_CCS_GET(USB_OTG_DEV->PORTSC1)) {
usbd_event_disconnect_handler(busid);
} else {
if (g_chipidea_udc[busid].is_suspend) {
g_chipidea_udc[busid].is_suspend = false;
usbd_event_resume_handler(busid);
}
usbd_event_connect_handler(busid);
}
}
if (int_status & intr_usb) {
uint32_t const edpt_complete = USB_OTG_DEV->ENDPTCOMPLETE;
USB_OTG_DEV->ENDPTCOMPLETE = edpt_complete;
uint32_t edpt_setup_status = USB_OTG_DEV->ENDPTSETUPSTAT;
if (edpt_setup_status) {
/*------------- Set up Received -------------*/
USB_OTG_DEV->ENDPTSETUPSTAT = edpt_setup_status;
dcd_qhd_t *qhd0 = chipidea_qhd_get(busid, 0);
usbd_event_ep0_setup_complete_handler(busid, (uint8_t *)&qhd0->setup_request);
}
if (edpt_complete) {
for (uint8_t ep_idx = 0; ep_idx < (CONFIG_USBDEV_EP_NUM * 2); ep_idx++) {
if (edpt_complete & (1 << ep_idx2bit(ep_idx))) {
transfer_len = 0;
ep_cb_req = true;
/* Failed QTD also get ENDPTCOMPLETE set */
dcd_qtd_t *p_qtd = chipidea_qtd_get(busid, ep_idx);
while (1) {
if (p_qtd->halted || p_qtd->xact_err || p_qtd->buffer_err) {
USB_LOG_ERR("usbd transfer error!\r\n");
ep_cb_req = false;
break;
} else if (p_qtd->active) {
ep_cb_req = false;
break;
} else {
transfer_len += p_qtd->expected_bytes - p_qtd->total_bytes;
}
if (p_qtd->next == 1) {
break;
} else {
p_qtd = (dcd_qtd_t *)p_qtd->next;
}
}
if (ep_cb_req) {
uint8_t const ep_addr = (ep_idx / 2) | ((ep_idx & 0x01) ? 0x80 : 0);
if (ep_addr & 0x80) {
usbd_event_ep_in_complete_handler(busid, ep_addr, transfer_len);
} else {
usbd_event_ep_out_complete_handler(busid, ep_addr, transfer_len);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "fsl_common.h"
/*! @brief USB controller ID */
typedef enum _usb_controller_index {
kUSB_ControllerKhci0 = 0U, /*!< KHCI 0U */
kUSB_ControllerKhci1 = 1U, /*!< KHCI 1U, Currently, there are no platforms which have two KHCI IPs, this is reserved
to be used in the future. */
kUSB_ControllerEhci0 = 2U, /*!< EHCI 0U */
kUSB_ControllerEhci1 = 3U, /*!< EHCI 1U */
} usb_controller_index_t;
#define USB_DEVICE_CONFIG_EHCI 1
/* USB PHY condfiguration */
#define BOARD_USB_PHY_D_CAL (0x04U)
#define BOARD_USB_PHY_TXCAL45DP (0x07U)
#define BOARD_USB_PHY_TXCAL45DM (0x07U)
#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U))
#include "usb_phy.h"
#endif
#if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U))
void USB1_HS_IRQHandler(void)
{
extern void USBD_IRQHandler(uint8_t busid);
USBD_IRQHandler(0);
}
#endif
void USB_ClockInit(void)
{
#if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)
usb_phy_config_struct_t phyConfig = {
BOARD_USB_PHY_D_CAL,
BOARD_USB_PHY_TXCAL45DP,
BOARD_USB_PHY_TXCAL45DM,
};
#endif
#if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)
SPC0->ACTIVE_VDELAY = 0x0500;
/* Change the power DCDC to 1.8v (By deafult, DCDC is 1.8V), CORELDO to 1.1v (By deafult, CORELDO is 1.0V) */
SPC0->ACTIVE_CFG &= ~SPC_ACTIVE_CFG_CORELDO_VDD_DS_MASK;
SPC0->ACTIVE_CFG |= SPC_ACTIVE_CFG_DCDC_VDD_LVL(0x3) | SPC_ACTIVE_CFG_CORELDO_VDD_LVL(0x3) |
SPC_ACTIVE_CFG_SYSLDO_VDD_DS_MASK | SPC_ACTIVE_CFG_DCDC_VDD_DS(0x2u);
/* Wait until it is done */
while (SPC0->SC & SPC_SC_BUSY_MASK)
;
if (0u == (SCG0->LDOCSR & SCG_LDOCSR_LDOEN_MASK)) {
SCG0->TRIM_LOCK = 0x5a5a0001U;
SCG0->LDOCSR |= SCG_LDOCSR_LDOEN_MASK;
/* wait LDO ready */
while (0U == (SCG0->LDOCSR & SCG_LDOCSR_VOUT_OK_MASK))
;
}
SYSCON->AHBCLKCTRLSET[2] |= SYSCON_AHBCLKCTRL2_USB_HS_MASK | SYSCON_AHBCLKCTRL2_USB_HS_PHY_MASK;
SCG0->SOSCCFG &= ~(SCG_SOSCCFG_RANGE_MASK | SCG_SOSCCFG_EREFS_MASK);
/* xtal = 20 ~ 30MHz */
SCG0->SOSCCFG = (1U << SCG_SOSCCFG_RANGE_SHIFT) | (1U << SCG_SOSCCFG_EREFS_SHIFT);
SCG0->SOSCCSR |= SCG_SOSCCSR_SOSCEN_MASK;
while (1) {
if (SCG0->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) {
break;
}
}
SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK | SYSCON_CLOCK_CTRL_CLKIN_ENA_FM_USBH_LPT_MASK;
CLOCK_EnableClock(kCLOCK_UsbHs);
CLOCK_EnableClock(kCLOCK_UsbHsPhy);
CLOCK_EnableUsbhsPhyPllClock(kCLOCK_Usbphy480M, 24000000U);
CLOCK_EnableUsbhsClock();
USB_EhciPhyInit(kUSB_ControllerEhci0, BOARD_XTAL0_CLK_HZ, &phyConfig);
#endif
#if defined(USB_DEVICE_CONFIG_KHCI) && (USB_DEVICE_CONFIG_KHCI > 0U)
CLOCK_AttachClk(kCLK_48M_to_USB0);
CLOCK_EnableClock(kCLOCK_Usb0Ram);
CLOCK_EnableClock(kCLOCK_Usb0Fs);
CLOCK_EnableUsbfsClock();
#endif
}
void usb_dc_low_level_init(uint8_t busid)
{
USB_ClockInit();
/* Install isr, set priority, and enable IRQ. */
NVIC_SetPriority((IRQn_Type)USB1_HS_IRQn, 3);
EnableIRQ((IRQn_Type)USB1_HS_IRQn);
}
void usb_dc_low_level_deinit(uint8_t busid)
{
DisableIRQ((IRQn_Type)USB1_HS_IRQn);
}