rtt更新
This commit is contained in:
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
Reference in New Issue
Block a user