Merge branch 'master' into master
This commit is contained in:
@@ -51,7 +51,7 @@ extern int8_t board_ft9xx_vbus(void);
|
||||
extern int board_uart_write(void const *buf, int len);
|
||||
|
||||
// Static array to store an incoming SETUP request for processing by tinyusb.
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN
|
||||
static uint8_t _ft9xx_setup_packet[8];
|
||||
|
||||
struct ft9xx_xfer_state
|
||||
|
||||
@@ -116,7 +116,7 @@ typedef struct
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// BDT(Buffer Descriptor Table) must be 256-byte aligned
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
|
||||
|
||||
|
||||
@@ -68,25 +68,34 @@ TU_ATTR_ALWAYS_INLINE static inline bool imxrt_is_cache_mem(uintptr_t addr) {
|
||||
return !(0x20000000 <= addr && addr < 0x20100000);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
const uintptr_t addr32 = (uintptr_t) addr;
|
||||
if (imxrt_is_cache_mem(addr32)) {
|
||||
TU_ASSERT(tu_is_aligned32(addr32));
|
||||
SCB_CleanDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
const uintptr_t addr32 = (uintptr_t) addr;
|
||||
if (imxrt_is_cache_mem(addr32)) {
|
||||
// Invalidating does not push cached changes back to RAM so we need to be
|
||||
// *very* careful when we do it. If we're not aligned, then we risk resetting
|
||||
// values back to their RAM state.
|
||||
TU_ASSERT(tu_is_aligned32(addr32));
|
||||
SCB_InvalidateDCache_by_Addr((void*) addr32, (int32_t) data_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool imxrt_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
const uintptr_t addr32 = (uintptr_t) addr;
|
||||
if (imxrt_is_cache_mem(addr32)) {
|
||||
TU_ASSERT(tu_is_aligned32(addr32));
|
||||
SCB_CleanInvalidateDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,9 +27,18 @@
|
||||
#ifndef _CI_HS_LPC18_43_H_
|
||||
#define _CI_HS_LPC18_43_H_
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#endif
|
||||
|
||||
// LPCOpen for 18xx & 43xx
|
||||
#include "chip.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
static const ci_hs_controller_t _ci_controller[] =
|
||||
{
|
||||
{ .reg_base = LPC_USB0_BASE, .irqnum = USB0_IRQn },
|
||||
|
||||
@@ -175,7 +175,7 @@ typedef struct {
|
||||
dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
|
||||
}dcd_data_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(2048)
|
||||
static dcd_data_t _dcd_data;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
@@ -41,16 +41,16 @@
|
||||
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
|
||||
#include "ci_hs_imxrt.h"
|
||||
|
||||
void hcd_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
imxrt_dcache_clean(addr, data_size);
|
||||
bool hcd_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
return imxrt_dcache_clean(addr, data_size);
|
||||
}
|
||||
|
||||
void hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
imxrt_dcache_invalidate(addr, data_size);
|
||||
bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
return imxrt_dcache_invalidate(addr, data_size);
|
||||
}
|
||||
|
||||
void hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
imxrt_dcache_clean_invalidate(addr, data_size);
|
||||
bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
return imxrt_dcache_clean_invalidate(addr, data_size);
|
||||
}
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
#ifdef TUP_USBIP_CHIPIDEA_HS
|
||||
// NXP Transdimension: 8 elements
|
||||
#define FRAMELIST_SIZE_BIT_VALUE 7u
|
||||
#define FRAMELIST_SIZE_USBCMD_VALUE (((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_POS_FRAMELIST_SIZE) | \
|
||||
((FRAMELIST_SIZE_BIT_VALUE >> 2) << EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB))
|
||||
#define FRAMELIST_SIZE_USBCMD_VALUE (((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_FRAMELIST_SIZE_SHIFT) | \
|
||||
((FRAMELIST_SIZE_BIT_VALUE >> 2) << EHCI_USBCMD_CHIPIDEA_FRAMELIST_SIZE_MSB_SHIFT))
|
||||
#else
|
||||
// STD EHCI: 256 elements
|
||||
#define FRAMELIST_SIZE_BIT_VALUE 2u
|
||||
@@ -126,52 +126,50 @@ static inline void print_intr(uint32_t intr) {
|
||||
//--------------------------------------------------------------------+
|
||||
// PROTOTYPE
|
||||
//--------------------------------------------------------------------+
|
||||
static inline ehci_link_t* get_period_head(uint8_t rhport, uint32_t interval_ms)
|
||||
{
|
||||
(void) rhport;
|
||||
return (ehci_link_t*) &ehci_data.period_head_arr[ tu_log2( tu_min32(FRAMELIST_SIZE, interval_ms) ) ];
|
||||
}
|
||||
|
||||
static inline ehci_qhd_t* qhd_control(uint8_t dev_addr)
|
||||
{
|
||||
return &ehci_data.control[dev_addr].qhd;
|
||||
}
|
||||
// weak dcache for non-cacheable MCU
|
||||
TU_ATTR_WEAK bool hcd_dcache_clean(void const* addr, uint32_t data_size) { (void) addr; (void) data_size; return true; }
|
||||
TU_ATTR_WEAK bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) { (void) addr; (void) data_size; return true; }
|
||||
TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) { (void) addr; (void) data_size; return true; }
|
||||
|
||||
static inline ehci_qhd_t* qhd_async_head(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
// control qhd of dev0 is used as async head
|
||||
return qhd_control(0);
|
||||
}
|
||||
|
||||
static inline ehci_qtd_t* qtd_control(uint8_t dev_addr)
|
||||
{
|
||||
return &ehci_data.control[dev_addr].qtd;
|
||||
}
|
||||
|
||||
|
||||
static inline ehci_qhd_t* qhd_next (ehci_qhd_t const * p_qhd);
|
||||
static inline ehci_qhd_t* qhd_find_free (void);
|
||||
static inline ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_control(uint8_t dev_addr);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_next (ehci_qhd_t const * p_qhd);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_find_free (void);
|
||||
static ehci_qhd_t* qhd_get_from_addr (uint8_t dev_addr, uint8_t ep_addr);
|
||||
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
|
||||
static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd);
|
||||
static void qhd_remove_qtd(ehci_qhd_t *qhd);
|
||||
|
||||
static inline ehci_qtd_t* qtd_find_free (void);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_control(uint8_t dev_addr);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_find_free (void);
|
||||
static void qtd_init (ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes);
|
||||
|
||||
static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
|
||||
static inline ehci_link_t* list_next (ehci_link_t const *p_link);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_get_period_head(uint8_t rhport, uint32_t interval_ms);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* list_get_async_head(uint8_t rhport);
|
||||
TU_ATTR_ALWAYS_INLINE static inline void list_insert (ehci_link_t *current, ehci_link_t *new, uint8_t new_type);
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_next (ehci_link_t const *p_link);
|
||||
static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr);
|
||||
|
||||
TU_ATTR_WEAK void hcd_dcache_clean(void const* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
static void ehci_disable_schedule(ehci_registers_t* regs, bool is_period) {
|
||||
// maybe have a timeout for status
|
||||
if (is_period) {
|
||||
regs->command_bm.periodic_enable = 0;
|
||||
while(regs->status_bm.periodic_status) {}
|
||||
} else {
|
||||
regs->command_bm.async_enable = 0;
|
||||
while(regs->status_bm.async_status) {} // should have a timeout
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_WEAK void hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
}
|
||||
|
||||
TU_ATTR_WEAK void hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
static void ehci_enable_schedule(ehci_registers_t* regs, bool is_period) {
|
||||
// maybe have a timeout for status
|
||||
if (is_period) {
|
||||
regs->command_bm.periodic_enable = 1;
|
||||
while ( 0 == regs->status_bm.periodic_status ) {}
|
||||
} else {
|
||||
regs->command_bm.async_enable = 1;
|
||||
while( 0 == regs->status_bm.async_status ) {}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -228,43 +226,6 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport)
|
||||
return (tusb_speed_t) ehci_data.regs->portsc_bm.nxp_port_speed; // NXP specific port speed
|
||||
}
|
||||
|
||||
static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr) {
|
||||
ehci_link_t* prev = list_head;
|
||||
|
||||
while (prev && !prev->terminate) {
|
||||
ehci_qhd_t* qhd = (ehci_qhd_t*) (uintptr_t) list_next(prev);
|
||||
|
||||
// done if loop back to head
|
||||
if ( (uintptr_t) qhd == (uintptr_t) list_head) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( qhd->dev_addr == dev_addr ) {
|
||||
// TODO deactivate all TD, wait for QHD to inactive before removal
|
||||
prev->address = qhd->next.address;
|
||||
|
||||
// EHCI 4.8.2 link the removed qhd's next to async head (which always reachable by Host Controller)
|
||||
qhd->next.address = ((uint32_t) list_head) | (EHCI_QTYPE_QHD << 1);
|
||||
|
||||
if ( qhd->int_smask )
|
||||
{
|
||||
// period list queue element is guarantee to be free in the next frame (1 ms)
|
||||
qhd->used = 0;
|
||||
}else
|
||||
{
|
||||
// async list use async advance handshake
|
||||
// mark as removing, will completely re-usable when async advance isr occurs
|
||||
qhd->removing = 1;
|
||||
}
|
||||
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
hcd_dcache_clean(prev, sizeof(ehci_qhd_t));
|
||||
}else {
|
||||
prev = list_next(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close all opened endpoint belong to this device
|
||||
void hcd_device_close(uint8_t rhport, uint8_t daddr)
|
||||
{
|
||||
@@ -274,7 +235,7 @@ void hcd_device_close(uint8_t rhport, uint8_t daddr)
|
||||
}
|
||||
|
||||
// Remove from async list
|
||||
list_remove_qhd_by_daddr((ehci_link_t *) qhd_async_head(rhport), daddr);
|
||||
list_remove_qhd_by_daddr((ehci_link_t *) list_get_async_head(rhport), daddr);
|
||||
|
||||
// Remove from all interval period list
|
||||
for(uint8_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++) {
|
||||
@@ -286,37 +247,42 @@ void hcd_device_close(uint8_t rhport, uint8_t daddr)
|
||||
}
|
||||
|
||||
static void init_periodic_list(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
|
||||
// Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only
|
||||
for ( uint32_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++ ) {
|
||||
ehci_data.period_head_arr[i].int_smask = 1; // queue head in period list must have smask non-zero
|
||||
ehci_data.period_head_arr[i].qtd_overlay.halted = 1; // dummy node, always inactive
|
||||
}
|
||||
|
||||
ehci_link_t * const framelist = ehci_data.period_framelist;
|
||||
ehci_link_t * const period_1ms = get_period_head(rhport, 1u);
|
||||
|
||||
// TODO EHCI_FRAMELIST_SIZE with other size than 8
|
||||
// all links --> period_head_arr[0] (1ms)
|
||||
// 0, 2, 4, 6 etc --> period_head_arr[1] (2ms)
|
||||
// 1, 5 --> period_head_arr[2] (4ms)
|
||||
// 3 --> period_head_arr[3] (8ms)
|
||||
|
||||
// TODO EHCI_FRAMELIST_SIZE with other size than 8
|
||||
ehci_link_t * const framelist = ehci_data.period_framelist;
|
||||
ehci_link_t * const head_1ms = (ehci_link_t *) &ehci_data.period_head_arr[0];
|
||||
ehci_link_t * const head_2ms = (ehci_link_t *) &ehci_data.period_head_arr[1];
|
||||
ehci_link_t * const head_4ms = (ehci_link_t *) &ehci_data.period_head_arr[2];
|
||||
ehci_link_t * const head_8ms = (ehci_link_t *) &ehci_data.period_head_arr[3];
|
||||
|
||||
for (uint32_t i = 0; i < FRAMELIST_SIZE; i++) {
|
||||
framelist[i].address = (uint32_t) period_1ms;
|
||||
framelist[i].address = (uint32_t) head_1ms;
|
||||
framelist[i].type = EHCI_QTYPE_QHD;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < FRAMELIST_SIZE; i += 2) {
|
||||
list_insert(framelist + i, get_period_head(rhport, 2u), EHCI_QTYPE_QHD);
|
||||
list_insert(framelist + i, head_2ms, EHCI_QTYPE_QHD);
|
||||
}
|
||||
|
||||
for (uint32_t i = 1; i < FRAMELIST_SIZE; i += 4) {
|
||||
list_insert(framelist + i, get_period_head(rhport, 4u), EHCI_QTYPE_QHD);
|
||||
list_insert(framelist + i, head_4ms, EHCI_QTYPE_QHD);
|
||||
}
|
||||
|
||||
list_insert(framelist + 3, get_period_head(rhport, 8u), EHCI_QTYPE_QHD);
|
||||
list_insert(framelist + 3, head_8ms, EHCI_QTYPE_QHD);
|
||||
|
||||
period_1ms->terminate = 1;
|
||||
head_1ms->terminate = 1;
|
||||
}
|
||||
|
||||
bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
|
||||
@@ -341,18 +307,18 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
|
||||
regs->status = (EHCI_INT_MASK_ALL & ~EHCI_INT_MASK_PORT_CHANGE);
|
||||
|
||||
// Enable interrupts
|
||||
regs->inten = EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE | EHCI_INT_MASK_ASYNC_ADVANCE |
|
||||
EHCI_INT_MASK_NXP_PERIODIC | EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
|
||||
regs->inten = EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
|
||||
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_FRAMELIST_ROLLOVER;
|
||||
|
||||
//------------- Asynchronous List -------------//
|
||||
ehci_qhd_t * const async_head = qhd_async_head(rhport);
|
||||
ehci_qhd_t * const async_head = list_get_async_head(rhport);
|
||||
tu_memclr(async_head, sizeof(ehci_qhd_t));
|
||||
|
||||
async_head->next.address = (uint32_t) async_head; // circular list, next is itself
|
||||
async_head->next.type = EHCI_QTYPE_QHD;
|
||||
async_head->head_list_flag = 1;
|
||||
async_head->qtd_overlay.halted = 1; // inactive most of time
|
||||
async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified
|
||||
async_head->next.address = (uint32_t) async_head; // circular list, next is itself
|
||||
async_head->next.type = EHCI_QTYPE_QHD;
|
||||
async_head->head_list_flag = 1;
|
||||
async_head->qtd_overlay.halted = 1; // inactive most of time
|
||||
async_head->qtd_overlay.next.terminate = 1; // TODO removed if verified
|
||||
|
||||
regs->async_list_addr = (uint32_t) async_head;
|
||||
|
||||
@@ -366,8 +332,7 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
|
||||
regs->nxp_tt_control = 0;
|
||||
|
||||
//------------- USB CMD Register -------------//
|
||||
regs->command |= TU_BIT(EHCI_USBCMD_POS_RUN_STOP) | TU_BIT(EHCI_USBCMD_POS_ASYNC_ENABLE) |
|
||||
TU_BIT(EHCI_USBCMD_POS_PERIOD_ENABLE) | // TODO enable period list only there is int/iso endpoint
|
||||
regs->command |= EHCI_USBCMD_RUN_STOP | EHCI_USBCMD_PERIOD_SCHEDULE_ENABLE | EHCI_USBCMD_ASYNC_SCHEDULE_ENABLE |
|
||||
FRAMELIST_SIZE_USBCMD_VALUE;
|
||||
|
||||
//------------- ConfigFlag Register (skip) -------------//
|
||||
@@ -377,7 +342,7 @@ bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
|
||||
if (ehci_data.cap_regs->hcsparams_bm.port_power_control) {
|
||||
// mask out all change bits since they are Write 1 to clear
|
||||
uint32_t portsc = (regs->portsc & ~EHCI_PORTSC_MASK_W1C);
|
||||
portsc |= ECHI_PORTSC_MASK_PORT_POWER;
|
||||
portsc |= EHCI_PORTSC_MASK_PORT_POWER;
|
||||
|
||||
regs->portsc = portsc;
|
||||
}
|
||||
@@ -426,11 +391,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
|
||||
{
|
||||
case TUSB_XFER_CONTROL:
|
||||
case TUSB_XFER_BULK:
|
||||
list_head = (ehci_link_t*) qhd_async_head(rhport);
|
||||
list_head = (ehci_link_t*) list_get_async_head(rhport);
|
||||
break;
|
||||
|
||||
case TUSB_XFER_INTERRUPT:
|
||||
list_head = get_period_head(rhport, p_qhd->interval_ms);
|
||||
list_head = list_get_period_head(rhport, p_qhd->interval_ms);
|
||||
break;
|
||||
|
||||
case TUSB_XFER_ISOCHRONOUS:
|
||||
@@ -439,10 +404,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
TU_ASSERT(list_head);
|
||||
|
||||
// TODO might need to disable async/period list
|
||||
list_insert(list_head, (ehci_link_t*) p_qhd, EHCI_QTYPE_QHD);
|
||||
|
||||
hcd_dcache_clean(p_qhd, sizeof(ehci_qhd_t));
|
||||
@@ -476,20 +439,25 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
ehci_qhd_t* qhd;
|
||||
ehci_qhd_t* qhd = qhd_get_from_addr(dev_addr, ep_addr);
|
||||
ehci_qtd_t* qtd;
|
||||
|
||||
if (epnum == 0) {
|
||||
qhd = qhd_control(dev_addr);
|
||||
qtd = qtd_control(dev_addr);
|
||||
// Control endpoint never be stalled. Skip reset Data Toggle since it is fixed per stage
|
||||
if (qhd->qtd_overlay.halted) {
|
||||
qhd->qtd_overlay.halted = false;
|
||||
}
|
||||
|
||||
qtd = qtd_control(dev_addr);
|
||||
qtd_init(qtd, buffer, buflen);
|
||||
|
||||
// first data toggle is always 1 (data & setup stage)
|
||||
qtd->data_toggle = 1;
|
||||
qtd->pid = dir ? EHCI_PID_IN : EHCI_PID_OUT;
|
||||
} else {
|
||||
qhd = qhd_get_from_addr(dev_addr, ep_addr);
|
||||
// skip if endpoint is halted
|
||||
TU_VERIFY(!qhd->qtd_overlay.halted);
|
||||
|
||||
qtd = qtd_find_free();
|
||||
TU_ASSERT(qtd);
|
||||
|
||||
@@ -510,12 +478,45 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t daddr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
|
||||
// TODO ISO not supported yet
|
||||
ehci_qhd_t* qhd = qhd_get_from_addr(dev_addr, ep_addr);
|
||||
ehci_qtd_t * volatile qtd = qhd->attached_qtd;
|
||||
TU_VERIFY(qtd != NULL); // no queued transfer
|
||||
|
||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
||||
TU_VERIFY(qtd->active); // transfer is already complete
|
||||
|
||||
// HC is still processing, disable HC list schedule before making changes
|
||||
bool const is_period = (qhd->interval_ms > 0);
|
||||
|
||||
ehci_disable_schedule(ehci_data.regs, is_period);
|
||||
|
||||
// check active bit again just in case HC has just processed the TD
|
||||
bool const still_active = qtd->active;
|
||||
if (still_active) {
|
||||
// remove TD from QH overlay
|
||||
qhd->qtd_overlay.next.terminate = 1;
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
|
||||
// remove TD from QH software list
|
||||
qhd_remove_qtd(qhd);
|
||||
}
|
||||
|
||||
ehci_enable_schedule(ehci_data.regs, is_period);
|
||||
|
||||
return still_active; // true if removed an active transfer
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
ehci_qhd_t *qhd = qhd_get_from_addr(daddr, ep_addr);
|
||||
qhd->qtd_overlay.halted = 0;
|
||||
qhd->qtd_overlay.data_toggle = 0;
|
||||
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
|
||||
// TODO reset data toggle ?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -541,71 +542,77 @@ void async_advance_isr(uint8_t rhport)
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void port_connect_status_change_isr(uint8_t rhport)
|
||||
{
|
||||
void port_connect_status_change_isr(uint8_t rhport) {
|
||||
// NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
|
||||
if (ehci_data.regs->portsc_bm.current_connect_status)
|
||||
{
|
||||
if ( ehci_data.regs->portsc_bm.current_connect_status ) {
|
||||
hcd_port_reset(rhport);
|
||||
hcd_event_device_attach(rhport, true);
|
||||
}else // device unplugged
|
||||
} else // device unplugged
|
||||
{
|
||||
hcd_event_device_remove(rhport, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Check queue head for potential transfer complete (successful or error)
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void qhd_xfer_complete_isr(ehci_qhd_t * qhd) {
|
||||
// examine TD attached to queue head
|
||||
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) qhd->attached_qtd;
|
||||
if (qtd == NULL) return; // no TD attached
|
||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
||||
hcd_dcache_invalidate(qhd, sizeof(ehci_qhd_t)); // HC may have updated the overlay
|
||||
volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
|
||||
|
||||
// TD is still active, no need to process
|
||||
if (qtd->active) {
|
||||
return;
|
||||
}
|
||||
// process non-active (completed) QHD with attached (scheduled) TD
|
||||
if ( !qtd_overlay->active && qhd->attached_qtd != NULL ) {
|
||||
xfer_result_t xfer_result;
|
||||
|
||||
uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
||||
|
||||
// invalidate dcache if IN transfer
|
||||
if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
|
||||
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
||||
}
|
||||
|
||||
// remove and free TD before invoking callback
|
||||
qhd->attached_qtd = NULL;
|
||||
qhd->attached_buffer = 0;
|
||||
qtd->used = 0; // free QTD
|
||||
|
||||
// notify usbh
|
||||
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
||||
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
|
||||
{
|
||||
ehci_qhd_t *p_qhd = async_head;
|
||||
do
|
||||
{
|
||||
hcd_dcache_invalidate(p_qhd, sizeof(ehci_qhd_t));
|
||||
|
||||
// halted or error is processed in error isr
|
||||
if ( !p_qhd->qtd_overlay.halted ) {
|
||||
qhd_xfer_complete_isr(p_qhd);
|
||||
if ( qtd_overlay->halted ) {
|
||||
if (qtd_overlay->xact_err || qtd_overlay->err_count == 0 || qtd_overlay->buffer_err || qtd_overlay->babble_err) {
|
||||
// Error count = 0 often occurs when device disconnected, or other bus-related error
|
||||
xfer_result = XFER_RESULT_FAILED;
|
||||
TU_LOG3(" QHD xfer err count: %d\n", qtd_overlay->err_count);
|
||||
// TU_BREAKPOINT(); // TODO skip unplugged device
|
||||
}else {
|
||||
// no error bits are set, endpoint is halted due to STALL
|
||||
xfer_result = XFER_RESULT_STALLED;
|
||||
}
|
||||
} else {
|
||||
xfer_result = XFER_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
p_qhd = qhd_next(p_qhd);
|
||||
}while(p_qhd != async_head); // async list traversal, stop if loop around
|
||||
ehci_qtd_t * volatile qtd = qhd->attached_qtd;
|
||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t)); // HC may have written back TD
|
||||
|
||||
uint8_t const dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
||||
|
||||
// invalidate dcache if IN transfer with data
|
||||
if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
|
||||
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
||||
}
|
||||
|
||||
// remove and free TD before invoking callback
|
||||
qhd_remove_qtd(qhd);
|
||||
|
||||
// notify usbh
|
||||
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
||||
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
||||
void proccess_async_xfer_isr(ehci_qhd_t * const list_head)
|
||||
{
|
||||
uint32_t const period_1ms_addr = (uint32_t) get_period_head(rhport, 1u);
|
||||
ehci_link_t next_link = * get_period_head(rhport, interval_ms);
|
||||
ehci_qhd_t *qhd = list_head;
|
||||
|
||||
do {
|
||||
qhd_xfer_complete_isr(qhd);
|
||||
qhd = qhd_next(qhd);
|
||||
} while ( qhd != list_head ); // async list traversal, stop if loop around
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms)
|
||||
{
|
||||
uint32_t const period_1ms_addr = (uint32_t) list_get_period_head(rhport, 1u);
|
||||
ehci_link_t next_link = *list_get_period_head(rhport, interval_ms);
|
||||
|
||||
while (!next_link.terminate) {
|
||||
if (interval_ms > 1 && period_1ms_addr == tu_align32(next_link.address)) {
|
||||
@@ -618,22 +625,13 @@ void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
||||
switch (next_link.type) {
|
||||
case EHCI_QTYPE_QHD: {
|
||||
ehci_qhd_t *qhd = (ehci_qhd_t *) entry_addr;
|
||||
hcd_dcache_invalidate(qhd, sizeof(ehci_qhd_t));
|
||||
|
||||
if (!qhd->qtd_overlay.halted) {
|
||||
qhd_xfer_complete_isr(qhd);
|
||||
}
|
||||
qhd_xfer_complete_isr(qhd);
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO support hs/fs ISO
|
||||
case EHCI_QTYPE_ITD:
|
||||
// TODO support hs ISO
|
||||
break;
|
||||
|
||||
case EHCI_QTYPE_SITD:
|
||||
// TODO support split ISO
|
||||
break;
|
||||
|
||||
case EHCI_QTYPE_FSTN:
|
||||
default:
|
||||
break;
|
||||
@@ -643,108 +641,6 @@ void period_list_xfer_complete_isr(uint8_t rhport, uint32_t interval_ms)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO merge with qhd_xfer_complete_isr()
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void qhd_xfer_error_isr(ehci_qhd_t * qhd)
|
||||
{
|
||||
volatile ehci_qtd_t *qtd_overlay = &qhd->qtd_overlay;
|
||||
|
||||
// TD has error
|
||||
if (qtd_overlay->halted) {
|
||||
xfer_result_t xfer_result;
|
||||
|
||||
if (qtd_overlay->xact_err || qtd_overlay->err_count == 0 || qtd_overlay->buffer_err || qtd_overlay->babble_err) {
|
||||
// Error count = 0 often occurs when device disconnected, or other bus-related error
|
||||
xfer_result = XFER_RESULT_FAILED;
|
||||
}else {
|
||||
// no error bits are set, endpoint is halted due to STALL
|
||||
xfer_result = XFER_RESULT_STALLED;
|
||||
}
|
||||
|
||||
// if (XFER_RESULT_FAILED == xfer_result ) {
|
||||
// TU_LOG1(" QHD xfer err count: %d\n", qtd_overlay->err_count);
|
||||
// TU_BREAKPOINT(); // TODO skip unplugged device
|
||||
// }
|
||||
|
||||
ehci_qtd_t * volatile qtd = (ehci_qtd_t * volatile) qhd->attached_qtd;
|
||||
TU_ASSERT(qtd, ); // No TD yet, probably a race condition or cache issue !?
|
||||
|
||||
hcd_dcache_invalidate(qtd, sizeof(ehci_qtd_t));
|
||||
|
||||
uint8_t dir = (qtd->pid == EHCI_PID_IN) ? 1 : 0;
|
||||
uint32_t const xferred_bytes = qtd->expected_bytes - qtd->total_bytes;
|
||||
|
||||
// invalidate dcache if IN transfer
|
||||
if (dir == 1 && qhd->attached_buffer != 0 && xferred_bytes > 0) {
|
||||
hcd_dcache_invalidate((void*) qhd->attached_buffer, xferred_bytes);
|
||||
}
|
||||
|
||||
// remove and free TD before invoking callback
|
||||
qhd->attached_qtd = NULL;
|
||||
qhd->attached_buffer = 0;
|
||||
qtd->used = 0; // free QTD
|
||||
|
||||
if (0 == qhd->ep_number ) {
|
||||
// control cannot be halted
|
||||
qhd->qtd_overlay.next.terminate = 1;
|
||||
qhd->qtd_overlay.alternate.terminate = 1;
|
||||
qhd->qtd_overlay.halted = 0;
|
||||
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
}
|
||||
|
||||
// notify usbh
|
||||
uint8_t const ep_addr = tu_edpt_addr(qhd->ep_number, dir);
|
||||
hcd_event_xfer_complete(qhd->dev_addr, ep_addr, xferred_bytes, xfer_result, true);
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void xfer_error_isr(uint8_t rhport)
|
||||
{
|
||||
//------------- async list -------------//
|
||||
ehci_qhd_t * const async_head = qhd_async_head(rhport);
|
||||
ehci_qhd_t *p_qhd = async_head;
|
||||
do
|
||||
{
|
||||
hcd_dcache_invalidate(p_qhd, sizeof(ehci_qhd_t));
|
||||
qhd_xfer_error_isr( p_qhd );
|
||||
p_qhd = qhd_next(p_qhd);
|
||||
}while(p_qhd != async_head); // async list traversal, stop if loop around
|
||||
|
||||
//------------- TODO refractor period list -------------//
|
||||
uint32_t const period_1ms_addr = (uint32_t) get_period_head(rhport, 1u);
|
||||
for (uint32_t interval_ms=1; interval_ms <= FRAMELIST_SIZE; interval_ms *= 2)
|
||||
{
|
||||
ehci_link_t next_item = * get_period_head(rhport, interval_ms);
|
||||
|
||||
// TODO abstract max loop guard for period
|
||||
while( !next_item.terminate &&
|
||||
!(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) )
|
||||
{
|
||||
switch ( next_item.type )
|
||||
{
|
||||
case EHCI_QTYPE_QHD:
|
||||
{
|
||||
ehci_qhd_t *p_qhd_int = (ehci_qhd_t *) tu_align32(next_item.address);
|
||||
hcd_dcache_invalidate(p_qhd_int, sizeof(ehci_qhd_t));
|
||||
|
||||
qhd_xfer_error_isr(p_qhd_int);
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO support hs/fs ISO
|
||||
case EHCI_QTYPE_ITD:
|
||||
case EHCI_QTYPE_SITD:
|
||||
case EHCI_QTYPE_FSTN:
|
||||
default: break;
|
||||
}
|
||||
|
||||
next_item = *list_next(&next_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------- Host Controller Driver's Interrupt Handler -------------//
|
||||
void hcd_int_handler(uint8_t rhport)
|
||||
{
|
||||
@@ -776,29 +672,16 @@ void hcd_int_handler(uint8_t rhport)
|
||||
regs->status = EHCI_INT_MASK_PORT_CHANGE; // Acknowledge
|
||||
}
|
||||
|
||||
if (int_status & EHCI_INT_MASK_ERROR) {
|
||||
xfer_error_isr(rhport);
|
||||
regs->status = EHCI_INT_MASK_ERROR; // Acknowledge
|
||||
}
|
||||
// A USB transfer is completed (OK or error)
|
||||
uint32_t const usb_int = int_status & (EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR);
|
||||
if (usb_int) {
|
||||
proccess_async_xfer_isr(list_get_async_head(rhport));
|
||||
|
||||
//------------- some QTD/SITD/ITD with IOC set is completed -------------//
|
||||
if (int_status & EHCI_INT_MASK_NXP_ASYNC) {
|
||||
async_list_xfer_complete_isr(qhd_async_head(rhport));
|
||||
regs->status = EHCI_INT_MASK_NXP_ASYNC; // Acknowledge
|
||||
}
|
||||
|
||||
if (int_status & EHCI_INT_MASK_NXP_PERIODIC)
|
||||
{
|
||||
for (uint32_t i=1; i <= FRAMELIST_SIZE; i *= 2)
|
||||
{
|
||||
period_list_xfer_complete_isr(rhport, i);
|
||||
for ( uint32_t i = 1; i <= FRAMELIST_SIZE; i *= 2 ) {
|
||||
process_period_xfer_isr(rhport, i);
|
||||
}
|
||||
regs->status = EHCI_INT_MASK_NXP_PERIODIC; // Acknowledge
|
||||
}
|
||||
|
||||
if (int_status & EHCI_INT_MASK_USB) {
|
||||
// TODO standard EHCI xfer complete
|
||||
regs->status = EHCI_INT_MASK_USB; // Acknowledge
|
||||
regs->status = usb_int; // Acknowledge
|
||||
}
|
||||
|
||||
//------------- There is some removed async previously -------------//
|
||||
@@ -810,35 +693,103 @@ void hcd_int_handler(uint8_t rhport)
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HELPER
|
||||
// List Managing Helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get head of periodic list
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_get_period_head(uint8_t rhport, uint32_t interval_ms) {
|
||||
(void) rhport;
|
||||
return (ehci_link_t*) &ehci_data.period_head_arr[ tu_log2( tu_min32(FRAMELIST_SIZE, interval_ms) ) ];
|
||||
}
|
||||
|
||||
//------------- queue head helper -------------//
|
||||
static inline ehci_qhd_t* qhd_find_free (void)
|
||||
// Get head of async list
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* list_get_async_head(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
return qhd_control(0); // control qhd of dev0 is used as async head
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_link_t* list_next(ehci_link_t const *p_link) {
|
||||
return (ehci_link_t*) tu_align32(p_link->address);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
|
||||
{
|
||||
for (uint32_t i=0; i<QHD_MAX; i++)
|
||||
{
|
||||
new->address = current->address;
|
||||
current->address = ((uint32_t) new) | (new_type << 1);
|
||||
}
|
||||
|
||||
// Remove all queue head belong to this device address
|
||||
static void list_remove_qhd_by_daddr(ehci_link_t* list_head, uint8_t dev_addr) {
|
||||
ehci_link_t* prev = list_head;
|
||||
|
||||
while (prev && !prev->terminate) {
|
||||
ehci_qhd_t* qhd = (ehci_qhd_t*) (uintptr_t) list_next(prev);
|
||||
|
||||
// done if loop back to head
|
||||
if ( (uintptr_t) qhd == (uintptr_t) list_head) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( qhd->dev_addr == dev_addr ) {
|
||||
// TODO deactivate all TD, wait for QHD to inactive before removal
|
||||
prev->address = qhd->next.address;
|
||||
|
||||
// EHCI 4.8.2 link the removed qhd's next to async head (which always reachable by Host Controller)
|
||||
qhd->next.address = ((uint32_t) list_head) | (EHCI_QTYPE_QHD << 1);
|
||||
|
||||
if ( qhd->int_smask )
|
||||
{
|
||||
// period list queue element is guarantee to be free in the next frame (1 ms)
|
||||
qhd->used = 0;
|
||||
}else
|
||||
{
|
||||
// async list use async advance handshake
|
||||
// mark as removing, will completely re-usable when async advance isr occurs
|
||||
qhd->removing = 1;
|
||||
}
|
||||
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
hcd_dcache_clean(prev, sizeof(ehci_qhd_t));
|
||||
}else {
|
||||
prev = list_next(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Queue Header helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get queue head for control transfer (always available)
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t* qhd_control(uint8_t dev_addr) {
|
||||
return &ehci_data.control[dev_addr].qhd;
|
||||
}
|
||||
|
||||
// Find a free queue head
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t *qhd_find_free(void) {
|
||||
for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
|
||||
if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline ehci_qhd_t* qhd_next(ehci_qhd_t const * p_qhd)
|
||||
{
|
||||
return (ehci_qhd_t*) tu_align32(p_qhd->next.address);
|
||||
// Next queue head link
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qhd_t *qhd_next(ehci_qhd_t const *p_qhd) {
|
||||
return (ehci_qhd_t *) tu_align32(p_qhd->next.address);
|
||||
}
|
||||
|
||||
static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
|
||||
// Get queue head from device + endpoint address
|
||||
static ehci_qhd_t *qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr) {
|
||||
if ( 0 == tu_edpt_number(ep_addr) ) {
|
||||
return qhd_control(dev_addr);
|
||||
}
|
||||
|
||||
for(uint32_t i=0; i<QHD_MAX; i++)
|
||||
{
|
||||
ehci_qhd_t *qhd_pool = ehci_data.qhd_pool;
|
||||
|
||||
for ( uint32_t i = 0; i < QHD_MAX; i++ ) {
|
||||
if ( (qhd_pool[i].dev_addr == dev_addr) &&
|
||||
ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) )
|
||||
{
|
||||
ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) ) {
|
||||
return &qhd_pool[i];
|
||||
}
|
||||
}
|
||||
@@ -846,6 +797,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Init queue head with endpoint descriptor
|
||||
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
|
||||
{
|
||||
// address 0 is used as async head, which always on the list --> cannot be cleared (ehci halted otherwise)
|
||||
@@ -920,6 +872,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
|
||||
}
|
||||
}
|
||||
|
||||
// Attach a TD to queue head
|
||||
static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd) {
|
||||
qhd->attached_qtd = qtd;
|
||||
qhd->attached_buffer = qtd->buffer[0];
|
||||
@@ -931,17 +884,35 @@ static void qhd_attach_qtd(ehci_qhd_t *qhd, ehci_qtd_t *qtd) {
|
||||
hcd_dcache_clean_invalidate(qhd, sizeof(ehci_qhd_t));
|
||||
}
|
||||
|
||||
// Remove an attached TD from queue head
|
||||
static void qhd_remove_qtd(ehci_qhd_t *qhd) {
|
||||
ehci_qtd_t * volatile qtd = qhd->attached_qtd;
|
||||
|
||||
//------------- TD helper -------------//
|
||||
static inline ehci_qtd_t *qtd_find_free(void) {
|
||||
qhd->attached_qtd = NULL;
|
||||
qhd->attached_buffer = 0;
|
||||
hcd_dcache_clean(qhd, sizeof(ehci_qhd_t));
|
||||
|
||||
qtd->used = 0; // free QTD
|
||||
hcd_dcache_clean(qtd, sizeof(ehci_qtd_t));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Queue TD helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get TD for control transfer (always available)
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t* qtd_control(uint8_t dev_addr) {
|
||||
return &ehci_data.control[dev_addr].qtd;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline ehci_qtd_t *qtd_find_free(void) {
|
||||
for (uint32_t i = 0; i < QTD_MAX; i++) {
|
||||
if (!ehci_data.qtd_pool[i].used) return &ehci_data.qtd_pool[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
|
||||
{
|
||||
static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes) {
|
||||
tu_memclr(qtd, sizeof(ehci_qtd_t));
|
||||
qtd->used = 1;
|
||||
|
||||
@@ -955,24 +926,9 @@ static void qtd_init(ehci_qtd_t* qtd, void const* buffer, uint16_t total_bytes)
|
||||
qtd->expected_bytes = total_bytes;
|
||||
|
||||
qtd->buffer[0] = (uint32_t) buffer;
|
||||
for(uint8_t i=1; i<5; i++)
|
||||
{
|
||||
for(uint8_t i=1; i<5; i++) {
|
||||
qtd->buffer[i] |= tu_align4k(qtd->buffer[i - 1] ) + 4096;
|
||||
}
|
||||
}
|
||||
|
||||
//------------- List Managing Helper -------------//
|
||||
|
||||
// insert at head
|
||||
static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type)
|
||||
{
|
||||
new->address = current->address;
|
||||
current->address = ((uint32_t) new) | (new_type << 1);
|
||||
}
|
||||
|
||||
static inline ehci_link_t* list_next(ehci_link_t const *p_link)
|
||||
{
|
||||
return (ehci_link_t*) tu_align32(p_link->address);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -278,23 +278,24 @@ enum {
|
||||
EHCI_INT_MASK_PERIODIC_SCHED_STATUS = TU_BIT(14),
|
||||
EHCI_INT_MASK_ASYNC_SCHED_STATUS = TU_BIT(15),
|
||||
|
||||
EHCI_INT_MASK_NXP_ASYNC = TU_BIT(18),
|
||||
EHCI_INT_MASK_NXP_PERIODIC = TU_BIT(19),
|
||||
|
||||
EHCI_INT_MASK_ALL =
|
||||
EHCI_INT_MASK_USB | EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE |
|
||||
EHCI_INT_MASK_FRAMELIST_ROLLOVER | EHCI_INT_MASK_PCI_HOST_SYSTEM_ERROR |
|
||||
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF |
|
||||
EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC
|
||||
EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_SOF
|
||||
};
|
||||
|
||||
enum {
|
||||
EHCI_USBCMD_POS_RUN_STOP = 0,
|
||||
EHCI_USBCMD_POS_FRAMELIST_SIZE = 2,
|
||||
EHCI_USBCMD_POS_PERIOD_ENABLE = 4,
|
||||
EHCI_USBCMD_POS_ASYNC_ENABLE = 5,
|
||||
EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB = 15,
|
||||
EHCI_USBCMD_POS_INTERRUPT_THRESHOLD = 16
|
||||
EHCI_USBCMD_FRAMELIST_SIZE_SHIFT = 2, // [2..3]
|
||||
EHCI_USBCMD_CHIPIDEA_FRAMELIST_SIZE_MSB_SHIFT = 15,
|
||||
EHCI_USBCMD_INTERRUPT_THRESHOLD_SHIFT = 16
|
||||
};
|
||||
|
||||
enum {
|
||||
EHCI_USBCMD_RUN_STOP = TU_BIT(0), // [0..0] 1 = Run, 0 = Stop
|
||||
EHCI_USBCMD_HCRESET = TU_BIT(1), // [1..1] SW write 1 to reset HC, clear by HC when complete
|
||||
EHCI_USBCMD_PERIOD_SCHEDULE_ENABLE = TU_BIT(4), // [4..4] Enable periodic schedule
|
||||
EHCI_USBCMD_ASYNC_SCHEDULE_ENABLE = TU_BIT(5), // [5..5] Enable async schedule
|
||||
EHCI_USBCMD_INTR_ON_ASYNC_ADVANCE_DOORBELL = TU_BIT(6), // [6..6] Tell HC to interrupt next time it advances async list. Clear by HC
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -306,7 +307,7 @@ enum {
|
||||
EHCI_PORTSC_MASK_FORCE_RESUME = TU_BIT(6),
|
||||
EHCI_PORTSC_MASK_PORT_SUSPEND = TU_BIT(7),
|
||||
EHCI_PORTSC_MASK_PORT_RESET = TU_BIT(8),
|
||||
ECHI_PORTSC_MASK_PORT_POWER = TU_BIT(12),
|
||||
EHCI_PORTSC_MASK_PORT_POWER = TU_BIT(12),
|
||||
|
||||
EHCI_PORTSC_MASK_W1C =
|
||||
EHCI_PORTSC_MASK_CONNECT_STATUS_CHANGE |
|
||||
|
||||
@@ -822,9 +822,17 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear stall, data toggle is also reset to DATA0
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
unsigned const pipenum = find_pipe(dev_addr, ep_addr);
|
||||
if (!pipenum) return false;
|
||||
hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1);
|
||||
|
||||
@@ -189,7 +189,7 @@ typedef struct
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// BDT(Buffer Descriptor Table) must be 256-byte aligned
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) volatile static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) volatile static dcd_data_t _dcd;
|
||||
|
||||
#if TU_PIC_INT_SIZE == 4
|
||||
TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
|
||||
|
||||
@@ -77,7 +77,7 @@ static tusb_speed_t get_speed(void);
|
||||
static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix);
|
||||
|
||||
// DMA descriptors shouldn't be placed in ITCM !
|
||||
CFG_TUSB_MEM_SECTION static dma_desc_t dma_desc[6];
|
||||
CFG_TUD_MEM_SECTION static dma_desc_t dma_desc[6];
|
||||
|
||||
static xfer_ctl_t xfer_status[EP_MAX];
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ typedef struct
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// BDT(Buffer Descriptor Table) must be 256-byte aligned
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ typedef struct
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// BDT(Buffer Descriptor Table) must be 256-byte aligned
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
|
||||
|
||||
|
||||
@@ -562,8 +562,16 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
if (!tu_edpt_number(ep_addr)) return true;
|
||||
int num = find_pipe(dev_addr, ep_addr);
|
||||
if (num < 0) return false;
|
||||
|
||||
@@ -92,7 +92,7 @@ typedef struct
|
||||
|
||||
} dcd_data_t;
|
||||
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(128) static dcd_data_t _dcd;
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(128) static dcd_data_t _dcd;
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
@@ -176,11 +176,11 @@ typedef struct
|
||||
// EP list must be 256-byte aligned
|
||||
// Some MCU controller may require this variable to be placed in specific SRAM region.
|
||||
// For example: LPC55s69 port1 Highspeed must be USB_RAM (0x40100000)
|
||||
// Use CFG_TUSB_MEM_SECTION to place it accordingly.
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
|
||||
// Use CFG_TUD_MEM_SECTION to place it accordingly.
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(256) static dcd_data_t _dcd;
|
||||
|
||||
// Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug)
|
||||
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
|
||||
CFG_TUD_MEM_SECTION TU_ATTR_ALIGNED(64) static uint8_t dummy[8];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Multiple Controllers
|
||||
|
||||
@@ -341,19 +341,24 @@ static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t
|
||||
p_ed->is_interrupt_xfer = (xfer_type == TUSB_XFER_INTERRUPT ? 1 : 0);
|
||||
}
|
||||
|
||||
static void gtd_init(ohci_gtd_t* p_td, uint8_t* data_ptr, uint16_t total_bytes)
|
||||
{
|
||||
static void gtd_init(ohci_gtd_t *p_td, uint8_t *data_ptr, uint16_t total_bytes) {
|
||||
tu_memclr(p_td, sizeof(ohci_gtd_t));
|
||||
|
||||
p_td->used = 1;
|
||||
p_td->expected_bytes = total_bytes;
|
||||
p_td->used = 1;
|
||||
p_td->expected_bytes = total_bytes;
|
||||
|
||||
p_td->buffer_rounding = 1; // less than queued length is not a error
|
||||
p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO;
|
||||
p_td->condition_code = OHCI_CCODE_NOT_ACCESSED;
|
||||
p_td->buffer_rounding = 1; // less than queued length is not a error
|
||||
p_td->delay_interrupt = OHCI_INT_ON_COMPLETE_NO;
|
||||
p_td->condition_code = OHCI_CCODE_NOT_ACCESSED;
|
||||
|
||||
p_td->current_buffer_pointer = _phys_addr(data_ptr);
|
||||
p_td->buffer_end = total_bytes ? (_phys_addr(data_ptr + total_bytes - 1)) : (uint8_t *)p_td->current_buffer_pointer;
|
||||
uint8_t *cbp = (uint8_t *) _phys_addr(data_ptr);
|
||||
|
||||
p_td->current_buffer_pointer = cbp;
|
||||
if ( total_bytes ) {
|
||||
p_td->buffer_end = _phys_addr(data_ptr + total_bytes - 1);
|
||||
} else {
|
||||
p_td->buffer_end = cbp;
|
||||
}
|
||||
}
|
||||
|
||||
static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
|
||||
@@ -487,7 +492,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
|
||||
ohci_ed_t* ed = &ohci_data.control[dev_addr].ed;
|
||||
ohci_gtd_t *qtd = &ohci_data.control[dev_addr].gtd;
|
||||
|
||||
gtd_init(qtd, (uint8_t*) setup_packet, 8);
|
||||
gtd_init(qtd, (uint8_t*)(uintptr_t) setup_packet, 8);
|
||||
qtd->index = dev_addr;
|
||||
qtd->pid = PID_SETUP;
|
||||
qtd->data_toggle = GTD_DT_DATA0;
|
||||
@@ -543,8 +548,16 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
ohci_ed_t * const p_ed = ed_from_addr(dev_addr, ep_addr);
|
||||
|
||||
p_ed->is_stalled = 0;
|
||||
|
||||
@@ -138,6 +138,11 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return pio_usb_host_endpoint_transfer(pio_rhport, dev_addr, ep_addr, buffer, buflen);
|
||||
}
|
||||
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
uint8_t const pio_rhport = RHPORT_PIO(rhport);
|
||||
return pio_usb_host_endpoint_abort_transfer(pio_rhport, dev_addr, ep_addr);
|
||||
}
|
||||
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
|
||||
{
|
||||
uint8_t const pio_rhport = RHPORT_PIO(rhport);
|
||||
@@ -158,8 +163,8 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
|
||||
// return busy;
|
||||
//}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
|
||||
|
||||
@@ -576,6 +576,14 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
|
||||
{
|
||||
(void) rhport;
|
||||
@@ -617,8 +625,8 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,8 +27,7 @@
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUH_ENABLED && (TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N) || \
|
||||
TU_CHECK_MCU(OPT_MCU_RAXXX))
|
||||
#if CFG_TUH_ENABLED && defined(TUP_USBIP_RUSB2)
|
||||
|
||||
#include "host/hcd.h"
|
||||
#include "rusb2_type.h"
|
||||
@@ -41,33 +40,15 @@
|
||||
#error "Unsupported MCU"
|
||||
#endif
|
||||
|
||||
#define TU_RUSB2_HCD_DBG 2
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/* LINK core registers */
|
||||
#if defined(__CCRX__)
|
||||
#define RUSB2 ((RUSB2_REG_t __evenaccess*) RUSB2_REG_BASE)
|
||||
#else
|
||||
#define RUSB2 ((RUSB2_REG_t*) RUSB2_REG_BASE)
|
||||
#endif
|
||||
|
||||
TU_ATTR_PACKED_BEGIN
|
||||
TU_ATTR_BIT_FIELD_ORDER_BEGIN
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
union {
|
||||
struct {
|
||||
uint16_t : 8;
|
||||
uint16_t TRCLR: 1;
|
||||
uint16_t TRENB: 1;
|
||||
uint16_t : 0;
|
||||
};
|
||||
uint16_t TRE;
|
||||
};
|
||||
uint16_t TRN;
|
||||
} reg_pipetre_t;
|
||||
|
||||
typedef union TU_ATTR_PACKED {
|
||||
struct {
|
||||
volatile uint16_t u8: 8;
|
||||
@@ -104,83 +85,102 @@ typedef struct
|
||||
//--------------------------------------------------------------------+
|
||||
static hcd_data_t _hcd;
|
||||
|
||||
static unsigned find_pipe(unsigned xfer)
|
||||
{
|
||||
switch (xfer) {
|
||||
case TUSB_XFER_ISOCHRONOUS:
|
||||
for (int i = 1; i <= 2; ++i) {
|
||||
if (0 == _hcd.pipe[i].ep) return i;
|
||||
}
|
||||
break;
|
||||
case TUSB_XFER_BULK:
|
||||
for (int i = 3; i <= 5; ++i) {
|
||||
if (0 == _hcd.pipe[i].ep) return i;
|
||||
}
|
||||
for (int i = 1; i <= 1; ++i) {
|
||||
if (0 == _hcd.pipe[i].ep) return i;
|
||||
}
|
||||
break;
|
||||
case TUSB_XFER_INTERRUPT:
|
||||
for (int i = 6; i <= 9; ++i) {
|
||||
if (0 == _hcd.pipe[i].ep) return i;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* No support for control transfer */
|
||||
break;
|
||||
// TODO merged with DCD
|
||||
// Transfer conditions specifiable for each pipe:
|
||||
// - Pipe 0: Control transfer with 64-byte single buffer
|
||||
// - Pipes 1 and 2: Bulk isochronous transfer continuous transfer mode with programmable buffer size up
|
||||
// to 2 KB and optional double buffer
|
||||
// - Pipes 3 to 5: Bulk transfer continuous transfer mode with programmable buffer size up to 2 KB and
|
||||
// optional double buffer
|
||||
// - Pipes 6 to 9: Interrupt transfer with 64-byte single buffer
|
||||
enum {
|
||||
PIPE_1ST_BULK = 3,
|
||||
PIPE_1ST_INTERRUPT = 6,
|
||||
PIPE_COUNT = 10,
|
||||
};
|
||||
|
||||
static unsigned find_pipe(unsigned xfer) {
|
||||
switch ( xfer ) {
|
||||
case TUSB_XFER_ISOCHRONOUS:
|
||||
for (int i = 1; i < PIPE_1ST_BULK; ++i) {
|
||||
if ( 0 == _hcd.pipe[i].ep ) return i;
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_XFER_BULK:
|
||||
for (int i = PIPE_1ST_BULK; i < PIPE_1ST_INTERRUPT; ++i) {
|
||||
if ( 0 == _hcd.pipe[i].ep ) return i;
|
||||
}
|
||||
for (int i = 1; i < PIPE_1ST_BULK; ++i) {
|
||||
if ( 0 == _hcd.pipe[i].ep ) return i;
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_XFER_INTERRUPT:
|
||||
for (int i = PIPE_1ST_INTERRUPT; i < PIPE_COUNT; ++i) {
|
||||
if ( 0 == _hcd.pipe[i].ep ) return i;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* No support for control transfer */
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static volatile uint16_t* get_pipectr(unsigned num)
|
||||
static volatile uint16_t* get_pipectr(rusb2_reg_t *rusb, unsigned num)
|
||||
{
|
||||
if (num) {
|
||||
return (volatile uint16_t*)&(RUSB2->PIPE_CTR[num - 1]);
|
||||
return (volatile uint16_t*)&(rusb->PIPE_CTR[num - 1]);
|
||||
} else {
|
||||
return (volatile uint16_t*)&(RUSB2->DCPCTR);
|
||||
return (volatile uint16_t*)&(rusb->DCPCTR);
|
||||
}
|
||||
}
|
||||
|
||||
static volatile reg_pipetre_t* get_pipetre(unsigned num)
|
||||
static volatile reg_pipetre_t* get_pipetre(rusb2_reg_t *rusb, unsigned num)
|
||||
{
|
||||
volatile reg_pipetre_t* tre = NULL;
|
||||
if ((1 <= num) && (num <= 5)) {
|
||||
tre = (volatile reg_pipetre_t*)&(RUSB2->PIPE_TR[num - 1].E);
|
||||
tre = (volatile reg_pipetre_t*)&(rusb->PIPE_TR[num - 1].E);
|
||||
}
|
||||
return tre;
|
||||
}
|
||||
|
||||
static volatile uint16_t* addr_to_pipectr(uint8_t dev_addr, unsigned ep_addr)
|
||||
static volatile uint16_t* addr_to_pipectr(uint8_t rhport, uint8_t dev_addr, unsigned ep_addr)
|
||||
{
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
const unsigned epn = tu_edpt_number(ep_addr);
|
||||
|
||||
if (epn) {
|
||||
const unsigned dir_in = tu_edpt_dir(ep_addr);
|
||||
const unsigned num = _hcd.ep[dev_addr][dir_in][epn - 1];
|
||||
return get_pipectr(num);
|
||||
return get_pipectr(rusb, num);
|
||||
} else {
|
||||
return get_pipectr(0);
|
||||
return get_pipectr(rusb, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned edpt0_max_packet_size(void)
|
||||
static uint16_t edpt0_max_packet_size(rusb2_reg_t* rusb)
|
||||
{
|
||||
return RUSB2->DCPMAXP_b.MXPS;
|
||||
return rusb->DCPMAXP_b.MXPS;
|
||||
}
|
||||
|
||||
static unsigned edpt_max_packet_size(unsigned num)
|
||||
static uint16_t edpt_max_packet_size(rusb2_reg_t *rusb, unsigned num)
|
||||
{
|
||||
RUSB2->PIPESEL = num;
|
||||
return RUSB2->PIPEMAXP_b.MXPS;
|
||||
rusb->PIPESEL = num;
|
||||
return rusb->PIPEMAXP_b.MXPS;
|
||||
}
|
||||
|
||||
static inline void pipe_wait_for_ready(unsigned num)
|
||||
static inline void pipe_wait_for_ready(rusb2_reg_t* rusb, unsigned num)
|
||||
{
|
||||
while (RUSB2->D0FIFOSEL_b.CURPIPE != num) ;
|
||||
while (!RUSB2->D0FIFOCTR_b.FRDY) ;
|
||||
while (rusb->D0FIFOSEL_b.CURPIPE != num) ;
|
||||
while (!rusb->D0FIFOCTR_b.FRDY) {}
|
||||
}
|
||||
|
||||
static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
|
||||
{
|
||||
// NOTE: unlike DCD, Highspeed 32-bit FIFO does not need to adjust the fifo address
|
||||
volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
|
||||
uintptr_t addr = (uintptr_t)buf;
|
||||
while (len >= 2) {
|
||||
@@ -201,33 +201,33 @@ static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
|
||||
while (len--) *p++ = *reg;
|
||||
}
|
||||
|
||||
static bool pipe0_xfer_in(void)
|
||||
static bool pipe0_xfer_in(rusb2_reg_t* rusb)
|
||||
{
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
const unsigned rem = pipe->remaining;
|
||||
|
||||
const unsigned mps = edpt0_max_packet_size();
|
||||
const unsigned vld = RUSB2->CFIFOCTR_b.DTLN;
|
||||
const unsigned mps = edpt0_max_packet_size(rusb);
|
||||
const unsigned vld = rusb->CFIFOCTR_b.DTLN;
|
||||
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
RUSB2->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
pipe_read_packet(buf, (volatile void*)&RUSB2->CFIFO, len);
|
||||
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) {
|
||||
RUSB2->CFIFOCTR = RUSB2_CFIFOCTR_BCLR_Msk;
|
||||
rusb->CFIFOCTR = RUSB2_CFIFOCTR_BCLR_Msk;
|
||||
}
|
||||
pipe->remaining = rem - len;
|
||||
if ((len < mps) || (rem == len)) {
|
||||
pipe->buf = NULL;
|
||||
return true;
|
||||
}
|
||||
RUSB2->DCPCTR = RUSB2_PIPE_CTR_PID_BUF;
|
||||
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_BUF;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool pipe0_xfer_out(void)
|
||||
static bool pipe0_xfer_out(rusb2_reg_t* rusb)
|
||||
{
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
const unsigned rem = pipe->remaining;
|
||||
@@ -235,40 +235,40 @@ static bool pipe0_xfer_out(void)
|
||||
pipe->buf = NULL;
|
||||
return true;
|
||||
}
|
||||
const unsigned mps = edpt0_max_packet_size();
|
||||
const unsigned mps = edpt0_max_packet_size(rusb);
|
||||
const unsigned len = TU_MIN(mps, rem);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
pipe_write_packet(buf, (volatile void*)&RUSB2->CFIFO, len);
|
||||
pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) {
|
||||
RUSB2->CFIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
|
||||
rusb->CFIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
|
||||
}
|
||||
pipe->remaining = rem - len;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool pipe_xfer_in(unsigned num)
|
||||
static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
|
||||
{
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
const unsigned rem = pipe->remaining;
|
||||
|
||||
RUSB2->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
|
||||
const unsigned mps = edpt_max_packet_size(num);
|
||||
pipe_wait_for_ready(num);
|
||||
const unsigned vld = RUSB2->D0FIFOCTR_b.DTLN;
|
||||
rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
|
||||
const unsigned mps = edpt_max_packet_size(rusb, num);
|
||||
pipe_wait_for_ready(rusb, num);
|
||||
const unsigned vld = rusb->D0FIFOCTR_b.DTLN;
|
||||
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
pipe_read_packet(buf, (volatile void*)&RUSB2->D0FIFO, len);
|
||||
pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps) {
|
||||
RUSB2->D0FIFOCTR = RUSB2_CFIFOCTR_BCLR_Msk;
|
||||
rusb->D0FIFOCTR = RUSB2_CFIFOCTR_BCLR_Msk;
|
||||
}
|
||||
RUSB2->D0FIFOSEL = 0;
|
||||
while (RUSB2->D0FIFOSEL_b.CURPIPE) ; /* if CURPIPE bits changes, check written value */
|
||||
rusb->D0FIFOSEL = 0;
|
||||
while (rusb->D0FIFOSEL_b.CURPIPE) ; /* if CURPIPE bits changes, check written value */
|
||||
pipe->remaining = rem - len;
|
||||
if ((len < mps) || (rem == len)) {
|
||||
pipe->buf = NULL;
|
||||
@@ -277,7 +277,7 @@ static bool pipe_xfer_in(unsigned num)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool pipe_xfer_out(unsigned num)
|
||||
static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
|
||||
{
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
const unsigned rem = pipe->remaining;
|
||||
@@ -287,36 +287,39 @@ static bool pipe_xfer_out(unsigned num)
|
||||
return true;
|
||||
}
|
||||
|
||||
RUSB2->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
|
||||
const unsigned mps = edpt_max_packet_size(num);
|
||||
pipe_wait_for_ready(num);
|
||||
rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
|
||||
const unsigned mps = edpt_max_packet_size(rusb, num);
|
||||
pipe_wait_for_ready(rusb, num);
|
||||
const unsigned len = TU_MIN(rem, mps);
|
||||
void *buf = pipe->buf;
|
||||
if (len) {
|
||||
pipe_write_packet(buf, (volatile void*)&RUSB2->D0FIFO, len);
|
||||
pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len);
|
||||
pipe->buf = (uint8_t*)buf + len;
|
||||
}
|
||||
if (len < mps)
|
||||
RUSB2->D0FIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
|
||||
RUSB2->D0FIFOSEL = 0;
|
||||
while (RUSB2->D0FIFOSEL_b.CURPIPE) ; /* if CURPIPE bits changes, check written value */
|
||||
if (len < mps) {
|
||||
rusb->D0FIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
|
||||
}
|
||||
rusb->D0FIFOSEL = 0;
|
||||
while (rusb->D0FIFOSEL_b.CURPIPE) ; /* if CURPIPE bits changes, check written value */
|
||||
pipe->remaining = rem - len;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool process_pipe0_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
|
||||
static bool process_pipe0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
|
||||
{
|
||||
(void)dev_addr;
|
||||
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
const unsigned dir_in = tu_edpt_dir(ep_addr);
|
||||
|
||||
/* configure fifo direction and access unit settings */
|
||||
if (dir_in) { /* IN, a byte */
|
||||
RUSB2->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
|
||||
while (RUSB2->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ;
|
||||
rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
|
||||
while (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ;
|
||||
} else { /* OUT, 2 bytes */
|
||||
RUSB2->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
|
||||
rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
|
||||
(TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
|
||||
while (!(RUSB2->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) ;
|
||||
while (!(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) ;
|
||||
}
|
||||
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
@@ -326,26 +329,28 @@ static bool process_pipe0_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer,
|
||||
if (buflen) {
|
||||
pipe->buf = buffer;
|
||||
if (!dir_in) { /* OUT */
|
||||
TU_ASSERT(RUSB2->DCPCTR_b.BSTS && (RUSB2->USBREQ & 0x80));
|
||||
pipe0_xfer_out();
|
||||
TU_ASSERT(rusb->DCPCTR_b.BSTS && (rusb->USBREQ & 0x80));
|
||||
pipe0_xfer_out(rusb);
|
||||
}
|
||||
} else { /* ZLP */
|
||||
pipe->buf = NULL;
|
||||
if (!dir_in) { /* OUT */
|
||||
RUSB2->CFIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
|
||||
rusb->CFIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
|
||||
}
|
||||
if (dir_in == RUSB2->DCPCFG_b.DIR) {
|
||||
TU_ASSERT(RUSB2_PIPE_CTR_PID_NAK == RUSB2->DCPCTR_b.PID);
|
||||
RUSB2->DCPCTR_b.SQSET = 1;
|
||||
RUSB2->DCPCFG_b.DIR = dir_in ^ 1;
|
||||
if (dir_in == rusb->DCPCFG_b.DIR) {
|
||||
TU_ASSERT(RUSB2_PIPE_CTR_PID_NAK == rusb->DCPCTR_b.PID);
|
||||
rusb->DCPCTR_b.SQSET = 1;
|
||||
rusb->DCPCFG_b.DIR = dir_in ^ 1;
|
||||
}
|
||||
}
|
||||
RUSB2->DCPCTR = RUSB2_PIPE_CTR_PID_BUF;
|
||||
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_BUF;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool process_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, void *buffer, uint16_t buflen)
|
||||
static bool process_pipe_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void *buffer, uint16_t buflen)
|
||||
{
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
|
||||
const unsigned epn = tu_edpt_number(ep_addr);
|
||||
const unsigned dir_in = tu_edpt_dir(ep_addr);
|
||||
const unsigned num = _hcd.ep[dev_addr - 1][dir_in][epn - 1];
|
||||
@@ -358,19 +363,19 @@ static bool process_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, void *buffer, u
|
||||
pipe->remaining = buflen;
|
||||
if (!dir_in) { /* OUT */
|
||||
if (buflen) {
|
||||
pipe_xfer_out(num);
|
||||
pipe_xfer_out(rusb, num);
|
||||
} else { /* ZLP */
|
||||
RUSB2->D0FIFOSEL = num;
|
||||
pipe_wait_for_ready(num);
|
||||
RUSB2->D0FIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
|
||||
RUSB2->D0FIFOSEL = 0;
|
||||
while (RUSB2->D0FIFOSEL_b.CURPIPE) {} /* if CURPIPE bits changes, check written value */
|
||||
rusb->D0FIFOSEL = num;
|
||||
pipe_wait_for_ready(rusb, num);
|
||||
rusb->D0FIFOCTR = RUSB2_CFIFOCTR_BVAL_Msk;
|
||||
rusb->D0FIFOSEL = 0;
|
||||
while (rusb->D0FIFOSEL_b.CURPIPE) {} /* if CURPIPE bits changes, check written value */
|
||||
}
|
||||
} else {
|
||||
volatile uint16_t *ctr = get_pipectr(num);
|
||||
volatile reg_pipetre_t *pt = get_pipetre(num);
|
||||
volatile uint16_t *ctr = get_pipectr(rusb, num);
|
||||
volatile reg_pipetre_t *pt = get_pipetre(rusb, num);
|
||||
if (pt) {
|
||||
const unsigned mps = edpt_max_packet_size(num);
|
||||
const unsigned mps = edpt_max_packet_size(rusb, num);
|
||||
if (*ctr & 0x3) *ctr = RUSB2_PIPE_CTR_PID_NAK;
|
||||
pt->TRE = TU_BIT(8);
|
||||
pt->TRN = (buflen + mps - 1) / mps;
|
||||
@@ -381,20 +386,20 @@ static bool process_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, void *buffer, u
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool process_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
|
||||
static bool process_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
|
||||
{
|
||||
const unsigned epn = tu_edpt_number(ep_addr);
|
||||
if (0 == epn) {
|
||||
return process_pipe0_xfer(dev_addr, ep_addr, buffer, buflen);
|
||||
return process_pipe0_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
|
||||
} else {
|
||||
return process_pipe_xfer(dev_addr, ep_addr, buffer, buflen);
|
||||
return process_pipe_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_pipe0_bemp(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
bool completed = pipe0_xfer_out();
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
bool completed = pipe0_xfer_out(rusb);
|
||||
if (completed) {
|
||||
pipe_state_t *pipe = &_hcd.pipe[0];
|
||||
hcd_event_xfer_complete(pipe->dev,
|
||||
@@ -406,13 +411,14 @@ static void process_pipe0_bemp(uint8_t rhport)
|
||||
|
||||
static void process_pipe_nrdy(uint8_t rhport, unsigned num)
|
||||
{
|
||||
(void)rhport;
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
xfer_result_t result;
|
||||
uint16_t volatile *ctr = get_pipectr(num);
|
||||
// TU_LOG1("NRDY %d %x\r\n", num, *ctr);
|
||||
uint16_t volatile *ctr = get_pipectr(rusb, num);
|
||||
TU_LOG(TU_RUSB2_HCD_DBG, "NRDY %d %x\r\n", num, *ctr);
|
||||
switch (*ctr & RUSB2_PIPE_CTR_PID_Msk) {
|
||||
default: return;
|
||||
case RUSB2_PIPE_CTR_PID_STALL: result = XFER_RESULT_STALLED; break;
|
||||
case RUSB2_PIPE_CTR_PID_STALL2: result = XFER_RESULT_STALLED; break;
|
||||
case RUSB2_PIPE_CTR_PID_NAK: result = XFER_RESULT_FAILED; break;
|
||||
}
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
@@ -423,25 +429,25 @@ static void process_pipe_nrdy(uint8_t rhport, unsigned num)
|
||||
|
||||
static void process_pipe_brdy(uint8_t rhport, unsigned num)
|
||||
{
|
||||
(void)rhport;
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
pipe_state_t *pipe = &_hcd.pipe[num];
|
||||
const unsigned dir_in = tu_edpt_dir(pipe->ep);
|
||||
bool completed;
|
||||
|
||||
if (dir_in) { /* IN */
|
||||
if (num) {
|
||||
completed = pipe_xfer_in(num);
|
||||
completed = pipe_xfer_in(rusb, num);
|
||||
} else {
|
||||
completed = pipe0_xfer_in();
|
||||
completed = pipe0_xfer_in(rusb);
|
||||
}
|
||||
} else {
|
||||
completed = pipe_xfer_out(num);
|
||||
completed = pipe_xfer_out(rusb, num);
|
||||
}
|
||||
if (completed) {
|
||||
hcd_event_xfer_complete(pipe->dev, pipe->ep,
|
||||
pipe->length - pipe->remaining,
|
||||
XFER_RESULT_SUCCESS, true);
|
||||
// TU_LOG1("C %d %d\r\n", num, pipe->length - pipe->remaining);
|
||||
TU_LOG(TU_RUSB2_HCD_DBG, "C %d %d\r\n", num, pipe->length - pipe->remaining);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,126 +481,146 @@ static void enable_interrupt(uint32_t pswi)
|
||||
|
||||
bool hcd_init(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
rusb2_module_start(rhport, true);
|
||||
|
||||
#if 0 // previously present in the rx driver before generalization
|
||||
uint32_t pswi = disable_interrupt();
|
||||
SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1;
|
||||
MSTP(USB0) = 0;
|
||||
SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY;
|
||||
enable_interrupt(pswi);
|
||||
#ifdef RUSB2_SUPPORT_HIGHSPEED
|
||||
if (rusb2_is_highspeed_rhport(rhport) ) {
|
||||
rusb->SYSCFG_b.HSE = 1;
|
||||
rusb->PHYSET_b.HSEB = 0;
|
||||
rusb->PHYSET_b.DIRPD = 0;
|
||||
R_BSP_SoftwareDelay((uint32_t) 1, BSP_DELAY_UNITS_MILLISECONDS);
|
||||
rusb->PHYSET_b.PLLRESET = 0;
|
||||
rusb->LPSTS_b.SUSPENDM = 1;
|
||||
while ( !rusb->PLLSTA_b.PLLLOCK );
|
||||
rusb->SYSCFG_b.DRPD = 1;
|
||||
rusb->SYSCFG_b.DCFM = 1;
|
||||
rusb->SYSCFG_b.DPRPU = 0;
|
||||
rusb->SYSCFG_b.CNEN = 1;
|
||||
rusb->BUSWAIT |= 0x0F00U;
|
||||
rusb->SOFCFG_b.INTL = 1;
|
||||
rusb->DVSTCTR0_b.VBUSEN = 1;
|
||||
rusb->CFIFOSEL_b.MBW = 1;
|
||||
rusb->D0FIFOSEL_b.MBW = 1;
|
||||
rusb->D1FIFOSEL_b.MBW = 1;
|
||||
rusb->INTSTS0 = 0;
|
||||
for ( volatile int i = 0; i < 30000; ++i );
|
||||
rusb->SYSCFG_b.USBE = 1;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
rusb->SYSCFG_b.SCKE = 1;
|
||||
while ( !rusb->SYSCFG_b.SCKE ) {}
|
||||
rusb->SYSCFG_b.DCFM = 1; // Host function
|
||||
rusb->SYSCFG_b.DPRPU = 0; // Disable D+ pull up
|
||||
rusb->SYSCFG_b.DRPD = 1; // Enable D+/D- pull down
|
||||
|
||||
RUSB2->SYSCFG_b.SCKE = 1;
|
||||
while (!RUSB2->SYSCFG_b.SCKE) ;
|
||||
RUSB2->SYSCFG_b.DPRPU = 0;
|
||||
RUSB2->SYSCFG_b.DRPD = 0;
|
||||
RUSB2->SYSCFG_b.DCFM = 1;
|
||||
rusb->DVSTCTR0_b.VBUSEN = 1;
|
||||
for ( volatile int i = 0; i < 30000; ++i ) {} // FIXME do we need to wait here? how long ?
|
||||
//R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
|
||||
rusb->SYSCFG_b.USBE = 1;
|
||||
|
||||
RUSB2->DVSTCTR0_b.VBUSEN = 1;
|
||||
// MCU specific PHY init
|
||||
rusb2_phy_init();
|
||||
|
||||
RUSB2->SYSCFG_b.DRPD = 1;
|
||||
for (volatile int i = 0; i < 30000; ++i) ;
|
||||
RUSB2->SYSCFG_b.USBE = 1;
|
||||
|
||||
// MCU specific PHY init
|
||||
rusb2_phy_init();
|
||||
|
||||
RUSB2->PHYSLEW = 0x5;
|
||||
RUSB2->DPUSR0R_FS_b.FIXPHY0 = 0u; /* Transceiver Output fixed */
|
||||
rusb->PHYSLEW = 0x5;
|
||||
rusb->DPUSR0R_FS_b.FIXPHY0 = 0u; /* Transceiver Output fixed */
|
||||
}
|
||||
|
||||
/* Setup default control pipe */
|
||||
RUSB2->DCPCFG = RUSB2_PIPECFG_SHTNAK_Msk;
|
||||
RUSB2->DCPMAXP = 64;
|
||||
RUSB2->INTENB0 = RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_NRDY_Msk | RUSB2_INTSTS0_BEMP_Msk;
|
||||
RUSB2->INTENB1 = RUSB2_INTSTS1_SACK_Msk | RUSB2_INTSTS1_SIGN_Msk | RUSB2_INTSTS1_ATTCH_Msk | RUSB2_INTSTS1_DTCH_Msk;
|
||||
RUSB2->BEMPENB = 1;
|
||||
RUSB2->NRDYENB = 1;
|
||||
RUSB2->BRDYENB = 1;
|
||||
rusb->DCPCFG = RUSB2_PIPECFG_SHTNAK_Msk;
|
||||
rusb->DCPMAXP = 64;
|
||||
rusb->INTENB0 = RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_NRDY_Msk | RUSB2_INTSTS0_BEMP_Msk;
|
||||
rusb->INTENB1 = RUSB2_INTSTS1_SACK_Msk | RUSB2_INTSTS1_SIGN_Msk | RUSB2_INTSTS1_ATTCH_Msk | RUSB2_INTSTS1_DTCH_Msk;
|
||||
rusb->BEMPENB = 1;
|
||||
rusb->NRDYENB = 1;
|
||||
rusb->BRDYENB = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void hcd_int_enable(uint8_t rhport)
|
||||
{
|
||||
void hcd_int_enable(uint8_t rhport) {
|
||||
rusb2_int_enable(rhport);
|
||||
}
|
||||
|
||||
void hcd_int_disable(uint8_t rhport)
|
||||
{
|
||||
void hcd_int_disable(uint8_t rhport) {
|
||||
rusb2_int_disable(rhport);
|
||||
}
|
||||
|
||||
uint32_t hcd_frame_number(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
|
||||
/* The device must be reset at least once after connection
|
||||
* in order to start the frame counter. */
|
||||
if (_hcd.need_reset) hcd_port_reset(rhport);
|
||||
return RUSB2->FRMNUM_b.FRNM;
|
||||
return rusb->FRMNUM_b.FRNM;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------+
|
||||
* Port API
|
||||
*--------------------------------------------------------------------+*/
|
||||
bool hcd_port_connect_status(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
return RUSB2->INTSTS1_b.ATTCH ? true : false;
|
||||
bool hcd_port_connect_status(uint8_t rhport) {
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
return rusb->INTSTS1_b.ATTCH ? true : false;
|
||||
}
|
||||
|
||||
void hcd_port_reset(uint8_t rhport)
|
||||
{
|
||||
RUSB2->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
while (RUSB2->DCPCTR_b.PBUSY) ;
|
||||
void hcd_port_reset(uint8_t rhport) {
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
while (rusb->DCPCTR_b.PBUSY) {}
|
||||
|
||||
hcd_int_disable(rhport);
|
||||
RUSB2->DVSTCTR0_b.UACT = 0;
|
||||
if (RUSB2->DCPCTR_b.SUREQ) {
|
||||
RUSB2->DCPCTR_b.SUREQCLR = 1;
|
||||
rusb->DVSTCTR0_b.UACT = 0;
|
||||
if (rusb->DCPCTR_b.SUREQ) {
|
||||
rusb->DCPCTR_b.SUREQCLR = 1;
|
||||
}
|
||||
hcd_int_enable(rhport);
|
||||
|
||||
/* Reset should be asserted 10-20ms. */
|
||||
RUSB2->DVSTCTR0_b.USBRST = 1;
|
||||
for (volatile int i = 0; i < 2400000; ++i) ;
|
||||
RUSB2->DVSTCTR0_b.USBRST = 0;
|
||||
RUSB2->DVSTCTR0_b.UACT = 1;
|
||||
rusb->DVSTCTR0_b.USBRST = 1;
|
||||
for (volatile int i = 0; i < 2400000; ++i) {}
|
||||
rusb->DVSTCTR0_b.USBRST = 0;
|
||||
|
||||
rusb->DVSTCTR0_b.UACT = 1;
|
||||
_hcd.need_reset = false;
|
||||
}
|
||||
|
||||
void hcd_port_reset_end(uint8_t rhport)
|
||||
{
|
||||
void hcd_port_reset_end(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
}
|
||||
|
||||
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
switch (RUSB2->DVSTCTR0_b.RHST) {
|
||||
default: return TUSB_SPEED_INVALID;
|
||||
tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
switch (rusb->DVSTCTR0_b.RHST) {
|
||||
case RUSB2_DVSTCTR0_RHST_HS: return TUSB_SPEED_HIGH;
|
||||
case RUSB2_DVSTCTR0_RHST_FS: return TUSB_SPEED_FULL;
|
||||
case RUSB2_DVSTCTR0_RHST_LS: return TUSB_SPEED_LOW;
|
||||
case RUSB2_DVSTCTR0_RHST_LS: return TUSB_SPEED_LOW;
|
||||
default: return TUSB_SPEED_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
(void)rhport;
|
||||
void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
uint16_t volatile *ctr;
|
||||
|
||||
TU_ASSERT(dev_addr < 6,); /* USBa can only handle addresses from 0 to 5. */
|
||||
if (!dev_addr) return;
|
||||
|
||||
_hcd.ctl_mps[dev_addr] = 0;
|
||||
uint8_t *ep = &_hcd.ep[dev_addr - 1][0][0];
|
||||
|
||||
for (int i = 0; i < 2 * 15; ++i, ++ep) {
|
||||
unsigned num = *ep;
|
||||
if (!num || dev_addr != _hcd.pipe[num].dev) continue;
|
||||
if (!num || (dev_addr != _hcd.pipe[num].dev)) continue;
|
||||
|
||||
ctr = (uint16_t volatile*)&RUSB2->PIPE_CTR[num - 1];
|
||||
ctr = (uint16_t volatile*)&rusb->PIPE_CTR[num - 1];
|
||||
*ctr = 0;
|
||||
RUSB2->NRDYENB &= ~TU_BIT(num);
|
||||
RUSB2->BRDYENB &= ~TU_BIT(num);
|
||||
RUSB2->PIPESEL = num;
|
||||
RUSB2->PIPECFG = 0;
|
||||
RUSB2->PIPEMAXP = 0;
|
||||
rusb->NRDYENB &= ~TU_BIT(num);
|
||||
rusb->BRDYENB &= ~TU_BIT(num);
|
||||
rusb->PIPESEL = num;
|
||||
rusb->PIPECFG = 0;
|
||||
rusb->PIPEMAXP = 0;
|
||||
|
||||
_hcd.pipe[num].ep = 0;
|
||||
_hcd.pipe[num].dev = 0;
|
||||
@@ -607,52 +633,54 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
|
||||
*--------------------------------------------------------------------+*/
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
|
||||
{
|
||||
(void)rhport;
|
||||
// TU_LOG1("S %d %x\r\n", dev_addr, RUSB2->DCPCTR);
|
||||
|
||||
TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
|
||||
TU_ASSERT(0 == RUSB2->DCPCTR_b.SUREQ);
|
||||
|
||||
RUSB2->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
TU_LOG(TU_RUSB2_HCD_DBG, "S %d %x\r\n", dev_addr, rusb->DCPCTR);
|
||||
|
||||
TU_ASSERT(0 == rusb->DCPCTR_b.SUREQ);
|
||||
|
||||
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
|
||||
_hcd.pipe[0].buf = NULL;
|
||||
_hcd.pipe[0].length = 8;
|
||||
_hcd.pipe[0].remaining = 0;
|
||||
_hcd.pipe[0].dev = dev_addr;
|
||||
|
||||
while (RUSB2->DCPCTR_b.PBUSY) ;
|
||||
RUSB2->DCPMAXP = (dev_addr << 12) | _hcd.ctl_mps[dev_addr];
|
||||
while (rusb->DCPCTR_b.PBUSY) ;
|
||||
rusb->DCPMAXP = (dev_addr << 12) | _hcd.ctl_mps[dev_addr];
|
||||
|
||||
/* Set direction in advance for DATA stage */
|
||||
uint8_t const bmRequesttype = setup_packet[0];
|
||||
RUSB2->DCPCFG_b.DIR = tu_edpt_dir(bmRequesttype) ? 0: 1;
|
||||
rusb->DCPCFG_b.DIR = tu_edpt_dir(bmRequesttype) ? 0: 1;
|
||||
|
||||
uint16_t const* p = (uint16_t const*)(uintptr_t)&setup_packet[0];
|
||||
RUSB2->USBREQ = tu_htole16(p[0]);
|
||||
RUSB2->USBVAL = p[1];
|
||||
RUSB2->USBINDX = p[2];
|
||||
RUSB2->USBLENG = p[3];
|
||||
rusb->USBREQ = tu_htole16(p[0]);
|
||||
rusb->USBVAL = p[1];
|
||||
rusb->USBINDX = p[2];
|
||||
rusb->USBLENG = p[3];
|
||||
|
||||
RUSB2->DCPCTR_b.SUREQ = 1;
|
||||
rusb->DCPCTR_b.SUREQ = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc)
|
||||
{
|
||||
(void)rhport;
|
||||
TU_ASSERT(dev_addr < 6); /* USBa can only handle addresses from 0 to 5. */
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
|
||||
const unsigned ep_addr = ep_desc->bEndpointAddress;
|
||||
const unsigned epn = tu_edpt_number(ep_addr);
|
||||
const unsigned mps = tu_edpt_packet_size(ep_desc);
|
||||
|
||||
if (0 == epn) {
|
||||
RUSB2->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
|
||||
hcd_devtree_info_t devtree;
|
||||
hcd_devtree_get_info(dev_addr, &devtree);
|
||||
uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t) &RUSB2->DEVADD[0];
|
||||
uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t) &rusb->DEVADD[0];
|
||||
devadd += dev_addr;
|
||||
while (RUSB2->DCPCTR_b.PBUSY) ;
|
||||
RUSB2->DCPMAXP = (dev_addr << 12) | mps;
|
||||
while (rusb->DCPCTR_b.PBUSY) {}
|
||||
rusb->DCPMAXP = (dev_addr << 12) | mps;
|
||||
*devadd = (TUSB_SPEED_FULL == devtree.speed) ? RUSB2_DEVADD_USBSPD_FS : RUSB2_DEVADD_USBSPD_LS;
|
||||
_hcd.ctl_mps[dev_addr] = mps;
|
||||
return true;
|
||||
@@ -666,17 +694,20 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
|
||||
}
|
||||
const unsigned num = find_pipe(xfer);
|
||||
if (!num) return false;
|
||||
|
||||
_hcd.pipe[num].dev = dev_addr;
|
||||
_hcd.pipe[num].ep = ep_addr;
|
||||
_hcd.ep[dev_addr - 1][dir_in][epn - 1] = num;
|
||||
|
||||
/* setup pipe */
|
||||
hcd_int_disable(rhport);
|
||||
RUSB2->PIPESEL = num;
|
||||
RUSB2->PIPEMAXP = (dev_addr << 12) | mps;
|
||||
volatile uint16_t *ctr = get_pipectr(num);
|
||||
|
||||
rusb->PIPESEL = num;
|
||||
rusb->PIPEMAXP = (dev_addr << 12) | mps;
|
||||
volatile uint16_t *ctr = get_pipectr(rusb, num);
|
||||
*ctr = RUSB2_PIPE_CTR_ACLRM_Msk | RUSB2_PIPE_CTR_SQCLR_Msk;
|
||||
*ctr = 0;
|
||||
|
||||
unsigned cfg = ((1 ^ dir_in) << 4) | epn;
|
||||
if (xfer == TUSB_XFER_BULK) {
|
||||
cfg |= RUSB2_PIPECFG_TYPE_BULK | RUSB2_PIPECFG_SHTNAK_Msk | RUSB2_PIPECFG_DBLB_Msk;
|
||||
@@ -685,13 +716,16 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
|
||||
} else {
|
||||
cfg |= RUSB2_PIPECFG_TYPE_ISO | RUSB2_PIPECFG_DBLB_Msk;
|
||||
}
|
||||
RUSB2->PIPECFG = cfg;
|
||||
RUSB2->BRDYSTS = 0x1FFu ^ TU_BIT(num);
|
||||
RUSB2->NRDYENB |= TU_BIT(num);
|
||||
RUSB2->BRDYENB |= TU_BIT(num);
|
||||
|
||||
rusb->PIPECFG = cfg;
|
||||
rusb->BRDYSTS = 0x1FFu ^ TU_BIT(num);
|
||||
rusb->NRDYENB |= TU_BIT(num);
|
||||
rusb->BRDYENB |= TU_BIT(num);
|
||||
|
||||
if (!dir_in) {
|
||||
*ctr = RUSB2_PIPE_CTR_PID_BUF;
|
||||
}
|
||||
|
||||
hcd_int_enable(rhport);
|
||||
|
||||
return true;
|
||||
@@ -701,15 +735,22 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b
|
||||
{
|
||||
bool r;
|
||||
hcd_int_disable(rhport);
|
||||
// TU_LOG1("X %d %x %u\r\n", dev_addr, ep_addr, buflen);
|
||||
r = process_edpt_xfer(dev_addr, ep_addr, buffer, buflen);
|
||||
TU_LOG(TU_RUSB2_HCD_DBG, "X %d %x %u\r\n", dev_addr, ep_addr, buflen);
|
||||
r = process_edpt_xfer(rhport, dev_addr, ep_addr, buffer, buflen);
|
||||
hcd_int_enable(rhport);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint16_t volatile *ctr = addr_to_pipectr(dev_addr, ep_addr);
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) ep_addr;
|
||||
// TODO not implemented yet
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
uint16_t volatile *ctr = addr_to_pipectr(rhport, dev_addr, ep_addr);
|
||||
TU_ASSERT(ctr);
|
||||
|
||||
const uint32_t pid = *ctr & 0x3;
|
||||
@@ -732,7 +773,52 @@ bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
|
||||
//--------------------------------------------------------------------+
|
||||
void hcd_int_handler(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
unsigned is0 = rusb->INTSTS0;
|
||||
unsigned is1 = rusb->INTSTS1;
|
||||
|
||||
/* clear active bits except VALID (don't write 0 to already cleared bits according to the HW manual) */
|
||||
rusb->INTSTS1 = ~((RUSB2_INTSTS1_SACK_Msk | RUSB2_INTSTS1_SIGN_Msk | RUSB2_INTSTS1_ATTCH_Msk | RUSB2_INTSTS1_DTCH_Msk) & is1);
|
||||
rusb->INTSTS0 = ~((RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_NRDY_Msk | RUSB2_INTSTS0_BEMP_Msk) & is0);
|
||||
|
||||
TU_LOG3("IS %04x %04x\r\n", is0, is1);
|
||||
is1 &= rusb->INTENB1;
|
||||
is0 &= rusb->INTENB0;
|
||||
|
||||
if (is1 & RUSB2_INTSTS1_SACK_Msk) {
|
||||
/* Set DATA1 in advance for the next transfer. */
|
||||
rusb->DCPCTR_b.SQSET = 1;
|
||||
hcd_event_xfer_complete(rusb->DCPMAXP_b.DEVSEL, tu_edpt_addr(0, TUSB_DIR_OUT), 8, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
|
||||
if (is1 & RUSB2_INTSTS1_SIGN_Msk) {
|
||||
hcd_event_xfer_complete(rusb->DCPMAXP_b.DEVSEL, tu_edpt_addr(0, TUSB_DIR_OUT), 8, XFER_RESULT_FAILED, true);
|
||||
}
|
||||
|
||||
if (is1 & RUSB2_INTSTS1_ATTCH_Msk) {
|
||||
rusb->DVSTCTR0_b.UACT = 1;
|
||||
_hcd.need_reset = true;
|
||||
rusb->INTENB1 = (rusb->INTENB1 & ~RUSB2_INTSTS1_ATTCH_Msk) | RUSB2_INTSTS1_DTCH_Msk;
|
||||
hcd_event_device_attach(rhport, true);
|
||||
}
|
||||
|
||||
if (is1 & RUSB2_INTSTS1_DTCH_Msk) {
|
||||
rusb->DVSTCTR0_b.UACT = 0;
|
||||
if (rusb->DCPCTR_b.SUREQ) {
|
||||
rusb->DCPCTR_b.SUREQCLR = 1;
|
||||
}
|
||||
rusb->INTENB1 = (rusb->INTENB1 & ~RUSB2_INTSTS1_DTCH_Msk) | RUSB2_INTSTS1_ATTCH_Msk;
|
||||
hcd_event_device_remove(rhport, true);
|
||||
}
|
||||
|
||||
if (is0 & RUSB2_INTSTS0_BEMP_Msk) {
|
||||
const unsigned s = rusb->BEMPSTS;
|
||||
rusb->BEMPSTS = 0;
|
||||
if (s & 1) {
|
||||
process_pipe0_bemp(rhport);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__CCRX__)
|
||||
static const int Mod37BitPosition[] = {
|
||||
-1, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
|
||||
@@ -740,49 +826,10 @@ void hcd_int_handler(uint8_t rhport)
|
||||
20, 8, 19, 18};
|
||||
#endif
|
||||
|
||||
unsigned is1 = RUSB2->INTSTS1;
|
||||
unsigned is0 = RUSB2->INTSTS0;
|
||||
/* clear active bits except VALID (don't write 0 to already cleared bits according to the HW manual) */
|
||||
RUSB2->INTSTS1 = ~((RUSB2_INTSTS1_SACK_Msk | RUSB2_INTSTS1_SIGN_Msk | RUSB2_INTSTS1_ATTCH_Msk | RUSB2_INTSTS1_DTCH_Msk) & is1);
|
||||
RUSB2->INTSTS0 = ~((RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_NRDY_Msk | RUSB2_INTSTS0_BEMP_Msk) & is0);
|
||||
// TU_LOG1("IS %04x %04x\r\n", is0, is1);
|
||||
is1 &= RUSB2->INTENB1;
|
||||
is0 &= RUSB2->INTENB0;
|
||||
|
||||
if (is1 & RUSB2_INTSTS1_SACK_Msk) {
|
||||
/* Set DATA1 in advance for the next transfer. */
|
||||
RUSB2->DCPCTR_b.SQSET = 1;
|
||||
hcd_event_xfer_complete(RUSB2->DCPMAXP_b.DEVSEL, tu_edpt_addr(0, TUSB_DIR_OUT), 8, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
if (is1 & RUSB2_INTSTS1_SIGN_Msk) {
|
||||
hcd_event_xfer_complete(RUSB2->DCPMAXP_b.DEVSEL, tu_edpt_addr(0, TUSB_DIR_OUT), 8, XFER_RESULT_FAILED, true);
|
||||
}
|
||||
if (is1 & RUSB2_INTSTS1_ATTCH_Msk) {
|
||||
RUSB2->DVSTCTR0_b.UACT = 1;
|
||||
_hcd.need_reset = true;
|
||||
RUSB2->INTENB1 = (RUSB2->INTENB1 & ~RUSB2_INTSTS1_ATTCH_Msk) | RUSB2_INTSTS1_DTCH_Msk;
|
||||
hcd_event_device_attach(rhport, true);
|
||||
}
|
||||
if (is1 & RUSB2_INTSTS1_DTCH_Msk) {
|
||||
RUSB2->DVSTCTR0_b.UACT = 0;
|
||||
if (RUSB2->DCPCTR_b.SUREQ) {
|
||||
RUSB2->DCPCTR_b.SUREQCLR = 1;
|
||||
}
|
||||
RUSB2->INTENB1 = (RUSB2->INTENB1 & ~RUSB2_INTSTS1_DTCH_Msk) | RUSB2_INTSTS1_ATTCH_Msk;
|
||||
hcd_event_device_remove(rhport, true);
|
||||
}
|
||||
|
||||
if (is0 & RUSB2_INTSTS0_BEMP_Msk) {
|
||||
const unsigned s = RUSB2->BEMPSTS;
|
||||
RUSB2->BEMPSTS = 0;
|
||||
if (s & 1) {
|
||||
process_pipe0_bemp(rhport);
|
||||
}
|
||||
}
|
||||
if (is0 & RUSB2_INTSTS0_NRDY_Msk) {
|
||||
const unsigned m = RUSB2->NRDYENB;
|
||||
unsigned s = RUSB2->NRDYSTS & m;
|
||||
RUSB2->NRDYSTS = ~s;
|
||||
const unsigned m = rusb->NRDYENB;
|
||||
unsigned s = rusb->NRDYSTS & m;
|
||||
rusb->NRDYSTS = ~s;
|
||||
while (s) {
|
||||
#if defined(__CCRX__)
|
||||
const unsigned num = Mod37BitPosition[(-s & s) % 37];
|
||||
@@ -794,10 +841,10 @@ void hcd_int_handler(uint8_t rhport)
|
||||
}
|
||||
}
|
||||
if (is0 & RUSB2_INTSTS0_BRDY_Msk) {
|
||||
const unsigned m = RUSB2->BRDYENB;
|
||||
unsigned s = RUSB2->BRDYSTS & m;
|
||||
const unsigned m = rusb->BRDYENB;
|
||||
unsigned s = rusb->BRDYSTS & m;
|
||||
/* clear active bits (don't write 0 to already cleared bits according to the HW manual) */
|
||||
RUSB2->BRDYSTS = ~s;
|
||||
rusb->BRDYSTS = ~s;
|
||||
while (s) {
|
||||
#if defined(__CCRX__)
|
||||
const unsigned num = Mod37BitPosition[(-s & s) % 37];
|
||||
|
||||
61
src/portable/renesas/rusb2/rusb2_common.c
Normal file
61
src/portable/renesas/rusb2/rusb2_common.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if defined(TUP_USBIP_RUSB2) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED)
|
||||
|
||||
#include "rusb2_type.h"
|
||||
|
||||
#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
|
||||
#include "rusb2_rx.h"
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
|
||||
#include "rusb2_ra.h"
|
||||
|
||||
// USBFS_INT_IRQn and USBHS_USB_INT_RESUME_IRQn are generated by FSP
|
||||
rusb2_controller_t rusb2_controller[] = {
|
||||
{ .reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn },
|
||||
#ifdef RUSB2_SUPPORT_HIGHSPEED
|
||||
{ .reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn },
|
||||
#endif
|
||||
};
|
||||
|
||||
// Application API for setting IRQ number. May throw warnings for missing prototypes.
|
||||
void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum) {
|
||||
rusb2_controller[rhport].irqnum = irqnum;
|
||||
}
|
||||
|
||||
// void osal_task_delay(uint32_t msec) {
|
||||
// R_BSP_SoftwareDelay(msec, BSP_DELAY_UNITS_MILLISECONDS);
|
||||
// }
|
||||
|
||||
#else
|
||||
#error "Unsupported MCU"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -31,30 +31,75 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
#pragma GCC diagnostic ignored "-Wundef"
|
||||
|
||||
// extra push due to https://github.com/renesas/fsp/pull/278
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
|
||||
/* renesas fsp api */
|
||||
#include "bsp_api.h"
|
||||
|
||||
#define RUSB2_REG_BASE (0x40090000)
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
#define __builtin_ctz(x) __iar_builtin_CLZ(__iar_builtin_RBIT(x))
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
NVIC_EnableIRQ(TU_IRQn);
|
||||
// IAR does not have __builtin_ctz
|
||||
#if defined(__ICCARM__)
|
||||
#define __builtin_ctz(x) __iar_builtin_CLZ(__iar_builtin_RBIT(x))
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
typedef struct {
|
||||
uint32_t reg_base;
|
||||
int32_t irqnum;
|
||||
}rusb2_controller_t;
|
||||
|
||||
#if defined(BSP_MCU_GROUP_RA6M5) || defined(BSP_MCU_GROUP_RA6M3) || (BSP_CFG_MCU_PART_SERIES == 8)
|
||||
#define RUSB2_SUPPORT_HIGHSPEED
|
||||
#define RUSB2_CONTROLLER_COUNT 2
|
||||
|
||||
#define rusb2_is_highspeed_rhport(_p) (_p == 1)
|
||||
#define rusb2_is_highspeed_reg(_reg) (_reg == RUSB2_REG(1))
|
||||
#else
|
||||
#define RUSB2_CONTROLLER_COUNT 1
|
||||
|
||||
#define rusb2_is_highspeed_rhport(_p) (false)
|
||||
#define rusb2_is_highspeed_reg(_reg) (false)
|
||||
#endif
|
||||
|
||||
extern rusb2_controller_t rusb2_controller[];
|
||||
#define RUSB2_REG(_p) ((rusb2_reg_t*) rusb2_controller[_p].reg_base)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// RUSB2 API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void rusb2_module_start(uint8_t rhport, bool start) {
|
||||
uint32_t const mask = 1U << (11+rhport);
|
||||
if (start) {
|
||||
R_MSTP->MSTPCRB &= ~mask;
|
||||
}else {
|
||||
R_MSTP->MSTPCRB |= mask;
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_disable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
NVIC_DisableIRQ(TU_IRQn);
|
||||
TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_enable(uint8_t rhport) {
|
||||
NVIC_EnableIRQ(rusb2_controller[rhport].irqnum);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_disable(uint8_t rhport) {
|
||||
NVIC_DisableIRQ(rusb2_controller[rhport].irqnum);
|
||||
}
|
||||
|
||||
// MCU specific PHY init
|
||||
TU_ATTR_ALWAYS_INLINE static inline void rusb2_phy_init(void)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline void rusb2_phy_init(void) {
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -37,6 +37,26 @@ extern "C" {
|
||||
|
||||
#define RUSB2_REG_BASE (0x000A0000)
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline rusb2_reg_t* RUSB2_REG(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
return (rusb2_reg_t *) RUSB2_REG_BASE;
|
||||
}
|
||||
|
||||
|
||||
#define rusb2_is_highspeed_rhport(_p) (false)
|
||||
#define rusb2_is_highspeed_reg(_reg) (false)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
// Start/Stop MSTP TODO implement later
|
||||
TU_ATTR_ALWAYS_INLINE static inline void rusb2_module_start(uint8_t rhport, bool start) {
|
||||
(void) rhport;
|
||||
(void) start;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void rusb2_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
@@ -28,11 +28,19 @@
|
||||
#define _TUSB_RUSB2_TYPE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// CCRX specific attribute to generate a Code that Accesses Variables in the Declared Size
|
||||
#ifdef __CCRX__
|
||||
#define _ccrx_evenaccess __evenaccess
|
||||
#else
|
||||
#define _ccrx_evenaccess
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/* Register Definitions */
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -41,15 +49,29 @@ extern "C" {
|
||||
TU_ATTR_PACKED_BEGIN
|
||||
TU_ATTR_BIT_FIELD_ORDER_BEGIN
|
||||
|
||||
// TODO same as RUSB2_PIPE_TR_t
|
||||
typedef struct TU_ATTR_PACKED _ccrx_evenaccess {
|
||||
union {
|
||||
struct {
|
||||
uint16_t : 8;
|
||||
uint16_t TRCLR: 1;
|
||||
uint16_t TRENB: 1;
|
||||
uint16_t : 0;
|
||||
};
|
||||
uint16_t TRE;
|
||||
};
|
||||
uint16_t TRN;
|
||||
} reg_pipetre_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
volatile uint16_t E; /* (@ 0x00000000) Pipe Transaction Counter Enable Register */
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t : 8;
|
||||
uint16_t : 8;
|
||||
volatile uint16_t TRCLR : 1; /* [8..8] Transaction Counter Clear */
|
||||
volatile uint16_t TRENB : 1; /* [9..9] Transaction Counter Enable */
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
} E_b;
|
||||
};
|
||||
|
||||
@@ -62,8 +84,9 @@ typedef struct {
|
||||
};
|
||||
} RUSB2_PIPE_TR_t; /* Size = 4 (0x4) */
|
||||
|
||||
/* LINK_REG Structure */
|
||||
typedef struct {
|
||||
|
||||
/* RUSB2 Registers Structure */
|
||||
typedef struct _ccrx_evenaccess {
|
||||
union {
|
||||
volatile uint16_t SYSCFG; /* (@ 0x00000000) System Configuration Control Register */
|
||||
|
||||
@@ -74,7 +97,7 @@ typedef struct {
|
||||
volatile uint16_t DPRPU : 1; /* [4..4] D+ Line Resistor Control */
|
||||
volatile uint16_t DRPD : 1; /* [5..5] D+/D- Line Resistor Control */
|
||||
volatile uint16_t DCFM : 1; /* [6..6] Controller Function Select */
|
||||
uint16_t : 1;
|
||||
volatile uint16_t HSE : 1; // [7..7] High-Speed Operation Enable
|
||||
volatile uint16_t CNEN : 1; /* [8..8] CNEN Single End Receiver Enable */
|
||||
uint16_t : 1;
|
||||
volatile uint16_t SCKE : 1; /* [10..10] USB Clock Enable */
|
||||
@@ -87,7 +110,7 @@ typedef struct {
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile uint16_t BWAIT : 4; /* [3..0] CPU Bus Access Wait Specification BWAIT waits (BWAIT+2 access cycles) */
|
||||
uint16_t : 12;
|
||||
uint16_t : 12;
|
||||
} BUSWAIT_b;
|
||||
};
|
||||
|
||||
@@ -98,8 +121,7 @@ typedef struct {
|
||||
volatile const uint16_t LNST : 2; /* [1..0] USB Data Line Status Monitor */
|
||||
volatile const uint16_t IDMON : 1; /* [2..2] External ID0 Input Pin Monitor */
|
||||
uint16_t : 2;
|
||||
volatile const uint16_t
|
||||
SOFEA : 1; /* [5..5] SOF Active Monitor While Host Controller Function is Selected. */
|
||||
volatile const uint16_t SOFEA : 1; /* [5..5] SOF Active Monitor While Host Controller Function is Selected. */
|
||||
volatile const uint16_t HTACT : 1; /* [6..6] USB Host Sequencer Status Monitor */
|
||||
uint16_t : 7;
|
||||
volatile const uint16_t OVCMON : 2; /* [15..14] External USB0_OVRCURA/ USB0_OVRCURB Input Pin Monitor */
|
||||
@@ -111,7 +133,7 @@ typedef struct {
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile const uint16_t PLLLOCK : 1; /* [0..0] PLL Lock Flag */
|
||||
uint16_t : 15;
|
||||
uint16_t : 15;
|
||||
} PLLSTA_b;
|
||||
};
|
||||
|
||||
@@ -139,7 +161,7 @@ typedef struct {
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile uint16_t UTST : 4; /* [3..0] Test Mode */
|
||||
uint16_t : 12;
|
||||
uint16_t : 12;
|
||||
} TESTMODE_b;
|
||||
};
|
||||
volatile const uint16_t RESERVED1;
|
||||
@@ -295,7 +317,7 @@ typedef struct {
|
||||
volatile uint16_t INTENB0; /* (@ 0x00000030) Interrupt Enable Register 0 */
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t : 8;
|
||||
uint16_t : 8;
|
||||
volatile uint16_t BRDYE : 1; /* [8..8] Buffer Ready Interrupt Enable */
|
||||
volatile uint16_t NRDYE : 1; /* [9..9] Buffer Not Ready Response Interrupt Enable */
|
||||
volatile uint16_t BEMPE : 1; /* [10..10] Buffer Empty Interrupt Enable */
|
||||
@@ -316,7 +338,10 @@ typedef struct {
|
||||
volatile uint16_t SACKE : 1; /* [4..4] Setup Transaction Normal Response Interrupt Enable */
|
||||
volatile uint16_t SIGNE : 1; /* [5..5] Setup Transaction Error Interrupt Enable */
|
||||
volatile uint16_t EOFERRE : 1; /* [6..6] EOF Error Detection Interrupt Enable */
|
||||
uint16_t : 4;
|
||||
uint16_t : 1;
|
||||
volatile uint16_t LPMENDE : 1; /*!< [8..8] LPM Transaction End Interrupt Enable */
|
||||
volatile uint16_t L1RSMENDE : 1; /*!< [9..9] L1 Resume End Interrupt Enable */
|
||||
uint16_t : 1;
|
||||
volatile uint16_t ATTCHE : 1; /* [11..11] Connection Detection Interrupt Enable */
|
||||
volatile uint16_t DTCHE : 1; /* [12..12] Disconnection Detection Interrupt Enable */
|
||||
uint16_t : 1;
|
||||
@@ -340,7 +365,7 @@ typedef struct {
|
||||
volatile uint16_t PIPE7BRDYE : 1; /* [7..7] BRDY Interrupt Enable for PIPE */
|
||||
volatile uint16_t PIPE8BRDYE : 1; /* [8..8] BRDY Interrupt Enable for PIPE */
|
||||
volatile uint16_t PIPE9BRDYE : 1; /* [9..9] BRDY Interrupt Enable for PIPE */
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
} BRDYENB_b;
|
||||
};
|
||||
|
||||
@@ -358,7 +383,7 @@ typedef struct {
|
||||
volatile uint16_t PIPE7NRDYE : 1; /* [7..7] NRDY Interrupt Enable for PIPE */
|
||||
volatile uint16_t PIPE8NRDYE : 1; /* [8..8] NRDY Interrupt Enable for PIPE */
|
||||
volatile uint16_t PIPE9NRDYE : 1; /* [9..9] NRDY Interrupt Enable for PIPE */
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
} NRDYENB_b;
|
||||
};
|
||||
|
||||
@@ -376,7 +401,7 @@ typedef struct {
|
||||
volatile uint16_t PIPE7BEMPE : 1; /* [7..7] BEMP Interrupt Enable for PIPE */
|
||||
volatile uint16_t PIPE8BEMPE : 1; /* [8..8] BEMP Interrupt Enable for PIPE */
|
||||
volatile uint16_t PIPE9BEMPE : 1; /* [9..9] BEMP Interrupt Enable for PIPE */
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
} BEMPENB_b;
|
||||
};
|
||||
|
||||
@@ -390,7 +415,7 @@ typedef struct {
|
||||
volatile uint16_t BRDYM : 1; /* [6..6] BRDY Interrupt Status Clear Timing */
|
||||
uint16_t : 1;
|
||||
volatile uint16_t TRNENSEL : 1; /* [8..8] Transaction-Enabled Time Select */
|
||||
uint16_t : 7;
|
||||
uint16_t : 7;
|
||||
} SOFCFG_b;
|
||||
};
|
||||
|
||||
@@ -467,7 +492,7 @@ typedef struct {
|
||||
volatile uint16_t PIPE7BRDY : 1; /* [7..7] BRDY Interrupt Status for PIPE */
|
||||
volatile uint16_t PIPE8BRDY : 1; /* [8..8] BRDY Interrupt Status for PIPE */
|
||||
volatile uint16_t PIPE9BRDY : 1; /* [9..9] BRDY Interrupt Status for PIPE */
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
} BRDYSTS_b;
|
||||
};
|
||||
|
||||
@@ -485,7 +510,7 @@ typedef struct {
|
||||
volatile uint16_t PIPE7NRDY : 1; /* [7..7] NRDY Interrupt Status for PIPE */
|
||||
volatile uint16_t PIPE8NRDY : 1; /* [8..8] NRDY Interrupt Status for PIPE */
|
||||
volatile uint16_t PIPE9NRDY : 1; /* [9..9] NRDY Interrupt Status for PIPE */
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
} NRDYSTS_b;
|
||||
};
|
||||
|
||||
@@ -503,7 +528,7 @@ typedef struct {
|
||||
volatile uint16_t PIPE7BEMP : 1; /* [7..7] BEMP Interrupt Status for PIPE */
|
||||
volatile uint16_t PIPE8BEMP : 1; /* [8..8] BEMP Interrupt Status for PIPE */
|
||||
volatile uint16_t PIPE9BEMP : 1; /* [9..9] BEMP Interrupt Status for PIPE */
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
} BEMPSTS_b;
|
||||
};
|
||||
|
||||
@@ -609,7 +634,8 @@ typedef struct {
|
||||
volatile uint16_t SQCLR : 1; /* [8..8] Sequence Toggle Bit Clear */
|
||||
uint16_t : 2;
|
||||
volatile uint16_t SUREQCLR : 1; /* [11..11] SUREQ Bit Clear */
|
||||
uint16_t : 2;
|
||||
volatile uint16_t CSSTS : 1; /* [12..12] Split Transaction COMPLETE SPLIT(CSPLIT) Status */
|
||||
volatile uint16_t CSCLR : 1; /* [13..13] Split Transaction CSPLIT Status Clear */
|
||||
volatile uint16_t SUREQ : 1; /* [14..14] Setup Token Transmission */
|
||||
volatile const uint16_t BSTS : 1; /* [15..15] Buffer Status */
|
||||
} DCPCTR_b;
|
||||
@@ -621,7 +647,7 @@ typedef struct {
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile uint16_t PIPESEL : 4; /* [3..0] Pipe Window Select */
|
||||
uint16_t : 12;
|
||||
uint16_t : 12;
|
||||
} PIPESEL_b;
|
||||
};
|
||||
volatile const uint16_t RESERVED11;
|
||||
@@ -634,21 +660,31 @@ typedef struct {
|
||||
volatile uint16_t DIR : 1; /* [4..4] Transfer Direction */
|
||||
uint16_t : 2;
|
||||
volatile uint16_t SHTNAK : 1; /* [7..7] Pipe Disabled at End of Transfer */
|
||||
uint16_t : 1;
|
||||
volatile uint16_t CNTMD : 1; /* [8..8] Continuous Transfer Mode */
|
||||
volatile uint16_t DBLB : 1; /* [9..9] Double Buffer Mode */
|
||||
volatile uint16_t BFRE : 1; /* [10..10] BRDY Interrupt Operation Specification */
|
||||
uint16_t : 3;
|
||||
volatile uint16_t TYPE : 2; /* [15..14] Transfer Type */
|
||||
} PIPECFG_b;
|
||||
};
|
||||
volatile const uint16_t RESERVED12;
|
||||
|
||||
union {
|
||||
volatile uint16_t PIPEBUF; /*!< (@ 0x0000006A) Pipe Buffer Register */
|
||||
|
||||
struct {
|
||||
volatile uint16_t BUFNMB : 8; // [7..0] Buffer NumberThese bits specify the FIFO buffer number of the selected pipe (04h to 87h)
|
||||
uint16_t : 2;
|
||||
volatile uint16_t BUFSIZE : 5; /*!< [14..10] Buffer Size 00h: 64 bytes 01h: 128 bytes : 1Fh: 2 Kbytes */
|
||||
uint16_t : 1;
|
||||
} PIPEBUF_b;
|
||||
};
|
||||
|
||||
union {
|
||||
volatile uint16_t PIPEMAXP; /* (@ 0x0000006C) Pipe Maximum Packet Size Register */
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile uint16_t MXPS : 9; /* [8..0] Maximum Packet Size */
|
||||
uint16_t : 3;
|
||||
volatile uint16_t MXPS : 11; /* [10..0] Maximum Packet Size */
|
||||
uint16_t : 1;
|
||||
volatile uint16_t DEVSEL : 4; /* [15..12] Device Select */
|
||||
} PIPEMAXP_b;
|
||||
};
|
||||
@@ -694,11 +730,9 @@ typedef struct {
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile uint16_t RPDME0 : 1; /* [0..0] D- Pin Pull-Down Control */
|
||||
volatile uint16_t IDPSRCE0 : 1; /* [1..1] D+ Pin IDPSRC Output Control */
|
||||
volatile uint16_t
|
||||
IDMSINKE0 : 1; /* [2..2] D- Pin 0.6 V Input Detection (Comparator and Sink) Control */
|
||||
volatile uint16_t IDMSINKE0 : 1; /* [2..2] D- Pin 0.6 V Input Detection (Comparator and Sink) Control */
|
||||
volatile uint16_t VDPSRCE0 : 1; /* [3..3] D+ Pin VDPSRC (0.6 V) Output Control */
|
||||
volatile uint16_t
|
||||
IDPSINKE0 : 1; /* [4..4] D+ Pin 0.6 V Input Detection (Comparator and Sink) Control */
|
||||
volatile uint16_t IDPSINKE0 : 1; /* [4..4] D+ Pin 0.6 V Input Detection (Comparator and Sink) Control */
|
||||
volatile uint16_t VDMSRCE0 : 1; /* [5..5] D- Pin VDMSRC (0.6 V) Output Control */
|
||||
uint16_t : 1;
|
||||
volatile uint16_t BATCHGE0 : 1; /* [7..7] BC (Battery Charger) Function Ch0 General Enable Control */
|
||||
@@ -715,7 +749,7 @@ typedef struct {
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile uint16_t UCKSELC : 1; /* [0..0] USB Clock Selection */
|
||||
uint16_t : 15;
|
||||
uint16_t : 15;
|
||||
} UCKSEL_b;
|
||||
};
|
||||
volatile const uint16_t RESERVED18;
|
||||
@@ -737,11 +771,11 @@ typedef struct {
|
||||
volatile uint16_t DEVADD[10]; /* (@ 0x000000D0) Device Address Configuration Register */
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
volatile uint16_t USBSPD : 2; /* [7..6] Transfer Speed of Communication Target Device */
|
||||
volatile uint16_t HUBPORT : 3; /* [10..8] Communication Target Connecting Hub Port */
|
||||
volatile uint16_t UPPHUB : 4; /* [14..11] Communication Target Connecting Hub Register */
|
||||
uint16_t : 1;
|
||||
uint16_t : 1;
|
||||
} DEVADD_b[10];
|
||||
};
|
||||
volatile const uint32_t RESERVED21[3];
|
||||
@@ -754,7 +788,7 @@ typedef struct {
|
||||
volatile uint32_t SLEWR01 : 1; /* [1..1] Receiver Cross Point Adjustment 01 */
|
||||
volatile uint32_t SLEWF00 : 1; /* [2..2] Receiver Cross Point Adjustment 00 */
|
||||
volatile uint32_t SLEWF01 : 1; /* [3..3] Receiver Cross Point Adjustment 01 */
|
||||
uint32_t : 28;
|
||||
uint32_t : 28;
|
||||
} PHYSLEW_b;
|
||||
};
|
||||
volatile const uint32_t RESERVED22[3];
|
||||
@@ -763,9 +797,9 @@ typedef struct {
|
||||
volatile uint16_t LPCTRL; /* (@ 0x00000100) Low Power Control Register */
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t : 7;
|
||||
uint16_t : 7;
|
||||
volatile uint16_t HWUPM : 1; /* [7..7] Resume Return Mode Setting */
|
||||
uint16_t : 8;
|
||||
uint16_t : 8;
|
||||
} LPCTRL_b;
|
||||
};
|
||||
|
||||
@@ -773,9 +807,9 @@ typedef struct {
|
||||
volatile uint16_t LPSTS; /* (@ 0x00000102) Low Power Status Register */
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t : 14;
|
||||
uint16_t : 14;
|
||||
volatile uint16_t SUSPENDM : 1; /* [14..14] UTMI SuspendM Control */
|
||||
uint16_t : 1;
|
||||
uint16_t : 1;
|
||||
} LPSTS_b;
|
||||
};
|
||||
volatile const uint32_t RESERVED23[15];
|
||||
@@ -793,7 +827,7 @@ typedef struct {
|
||||
uint16_t : 2;
|
||||
volatile const uint16_t CHGDETSTS : 1; /* [8..8] CHGDET Status */
|
||||
volatile const uint16_t PDDETSTS : 1; /* [9..9] PDDET Status */
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
} BCCTRL_b;
|
||||
};
|
||||
volatile const uint16_t RESERVED24;
|
||||
@@ -809,7 +843,7 @@ typedef struct {
|
||||
volatile uint16_t HIRDTHR : 4; /* [11..8] L1 Response Negotiation Threshold Value */
|
||||
uint16_t : 2;
|
||||
volatile uint16_t L1EXTMD : 1; /* [14..14] PHY Control Mode at L1 Return */
|
||||
uint16_t : 1;
|
||||
uint16_t : 1;
|
||||
} PL1CTRL1_b;
|
||||
};
|
||||
|
||||
@@ -817,10 +851,10 @@ typedef struct {
|
||||
volatile uint16_t PL1CTRL2; /* (@ 0x00000146) Function L1 Control Register 2 */
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t : 8;
|
||||
uint16_t : 8;
|
||||
volatile uint16_t HIRDMON : 4; /* [11..8] HIRD Value Monitor */
|
||||
volatile uint16_t RWEMON : 1; /* [12..12] RWE Value Monitor */
|
||||
uint16_t : 3;
|
||||
uint16_t : 3;
|
||||
} PL1CTRL2_b;
|
||||
};
|
||||
|
||||
@@ -830,7 +864,7 @@ typedef struct {
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile uint16_t L1REQ : 1; /* [0..0] L1 Transition Request */
|
||||
volatile const uint16_t L1STATUS : 2; /* [2..1] L1 Request Completion Status */
|
||||
uint16_t : 13;
|
||||
uint16_t : 13;
|
||||
} HL1CTRL1_b;
|
||||
};
|
||||
|
||||
@@ -846,18 +880,48 @@ typedef struct {
|
||||
volatile uint16_t BESL : 1; /* [15..15] BESL & Alternate HIRD */
|
||||
} HL1CTRL2_b;
|
||||
};
|
||||
volatile const uint32_t RESERVED25[5];
|
||||
|
||||
volatile uint32_t RESERVED25_1;
|
||||
|
||||
union {
|
||||
volatile uint16_t PHYTRIM1; /*!< (@ 0x00000150) PHY Timing Register 1 */
|
||||
|
||||
struct {
|
||||
volatile uint16_t DRISE : 2; /*!< [1..0] FS/LS Rising-Edge Output Waveform Adjustment Function */
|
||||
volatile uint16_t DFALL : 2; /*!< [3..2] FS/LS Falling-Edge Output Waveform Adjustment Function */
|
||||
uint16_t : 3;
|
||||
volatile uint16_t PCOMPENB : 1; /*!< [7..7] PVDD Start-up Detection */
|
||||
volatile uint16_t HSIUP : 4; /*!< [11..8] HS Output Level Setting */
|
||||
volatile uint16_t IMPOFFSET : 3; /*!< [14..12] terminating resistance offset value setting.Offset value for adjusting the terminating resistance. */
|
||||
uint16_t : 1;
|
||||
} PHYTRIM1_b;
|
||||
};
|
||||
|
||||
union {
|
||||
volatile uint16_t PHYTRIM2; /*!< (@ 0x00000152) PHY Timing Register 2 */
|
||||
|
||||
struct {
|
||||
volatile uint16_t SQU : 4; /*!< [3..0] Squelch Detection Level */
|
||||
uint16_t : 3;
|
||||
volatile uint16_t HSRXENMO : 1; /*!< [7..7] HS Receive Enable Control Mode */
|
||||
volatile uint16_t PDR : 2; /*!< [9..8] HS Output Adjustment Function */
|
||||
uint16_t : 2;
|
||||
volatile uint16_t DIS : 3; /*!< [14..12] Disconnect Detection Level */
|
||||
uint16_t : 1;
|
||||
} PHYTRIM2_b;
|
||||
};
|
||||
volatile uint32_t RESERVED25_2[3];
|
||||
|
||||
union {
|
||||
volatile const uint32_t DPUSR0R; /* (@ 0x00000160) Deep Standby USB Transceiver Control/Pin Monitor Register */
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint32_t : 20;
|
||||
uint32_t : 20;
|
||||
volatile const uint32_t DOVCAHM : 1; /* [20..20] OVRCURA InputIndicates OVRCURA input signal on the HS side of USB port. */
|
||||
volatile const uint32_t DOVCBHM : 1; /* [21..21] OVRCURB InputIndicates OVRCURB input signal on the HS side of USB port. */
|
||||
uint32_t : 1;
|
||||
volatile const uint32_t DVBSTSHM : 1; /* [23..23] VBUS InputIndicates VBUS input signal on the HS side of USB port. */
|
||||
uint32_t : 8;
|
||||
uint32_t : 8;
|
||||
} DPUSR0R_b;
|
||||
};
|
||||
|
||||
@@ -865,7 +929,7 @@ typedef struct {
|
||||
volatile uint32_t DPUSR1R; /* (@ 0x00000164) Deep Standby USB Suspend/Resume Interrupt Register */
|
||||
|
||||
struct TU_ATTR_PACKED {
|
||||
uint32_t : 4;
|
||||
uint32_t : 4;
|
||||
volatile uint32_t DOVCAHE : 1; /* [4..4] OVRCURA Interrupt Enable Clear */
|
||||
volatile uint32_t DOVCBHE : 1; /* [5..5] OVRCURB Interrupt Enable Clear */
|
||||
uint32_t : 1;
|
||||
@@ -875,7 +939,7 @@ typedef struct {
|
||||
volatile const uint32_t DOVCBH : 1; /* [21..21] Indication of Return from OVRCURB Interrupt Source */
|
||||
uint32_t : 1;
|
||||
volatile const uint32_t DVBSTSH : 1; /* [23..23] Indication of Return from VBUS Interrupt Source */
|
||||
uint32_t : 8;
|
||||
uint32_t : 8;
|
||||
} DPUSR1R_b;
|
||||
};
|
||||
|
||||
@@ -891,7 +955,7 @@ typedef struct {
|
||||
uint16_t : 2;
|
||||
volatile uint16_t DPINTE : 1; /* [8..8] DP Interrupt Enable Clear */
|
||||
volatile uint16_t DMINTE : 1; /* [9..9] DM Interrupt Enable Clear */
|
||||
uint16_t : 6;
|
||||
uint16_t : 6;
|
||||
} DPUSR2R_b;
|
||||
};
|
||||
|
||||
@@ -901,7 +965,7 @@ typedef struct {
|
||||
struct TU_ATTR_PACKED {
|
||||
volatile uint16_t FIXPHY : 1; /* [0..0] USB Transceiver Control Fix */
|
||||
volatile uint16_t FIXPHYPD : 1; /* [1..1] USB Transceiver Control Fix for PLL */
|
||||
uint16_t : 14;
|
||||
uint16_t : 14;
|
||||
} DPUSRCR_b;
|
||||
};
|
||||
volatile const uint32_t RESERVED26[165];
|
||||
@@ -924,7 +988,7 @@ typedef struct {
|
||||
volatile const uint32_t DOVCB0 : 1; /* [21..21] USB OVRCURB InputIndicates the OVRCURB input signal of the USB. */
|
||||
uint32_t : 1;
|
||||
volatile const uint32_t DVBSTS0 : 1; /* [23..23] USB VBUS InputIndicates the VBUS input signal of the USB. */
|
||||
uint32_t : 8;
|
||||
uint32_t : 8;
|
||||
} DPUSR0R_FS_b;
|
||||
};
|
||||
|
||||
@@ -947,10 +1011,10 @@ typedef struct {
|
||||
volatile const uint32_t DOVRCRB0 : 1; /* [21..21] USB OVRCURB Interrupt Source Recovery */
|
||||
uint32_t : 1;
|
||||
volatile const uint32_t DVBINT0 : 1; /* [23..23] USB VBUS Interrupt Source Recovery */
|
||||
uint32_t : 8;
|
||||
uint32_t : 8;
|
||||
} DPUSR1R_FS_b;
|
||||
};
|
||||
} RUSB2_REG_t; /* Size = 1032 (0x408) */
|
||||
} rusb2_reg_t; /* Size = 1032 (0x408) */
|
||||
|
||||
TU_ATTR_PACKED_END /* End of definition of packed structs (used by the CCRX toolchain) */
|
||||
TU_ATTR_BIT_FIELD_ORDER_END
|
||||
@@ -970,13 +1034,15 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
#define RUSB2_PIPE_TR_N_TRNCNT_Pos (0UL) /* TRNCNT (Bit 0) */
|
||||
#define RUSB2_PIPE_TR_N_TRNCNT_Msk (0xffffUL) /* TRNCNT (Bitfield-Mask: 0xffff) */
|
||||
|
||||
// LINK_REG
|
||||
// Core Registers
|
||||
|
||||
// SYSCFG
|
||||
#define RUSB2_SYSCFG_SCKE_Pos (10UL) /* SCKE (Bit 10) */
|
||||
#define RUSB2_SYSCFG_SCKE_Msk (0x400UL) /* SCKE (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_SYSCFG_CNEN_Pos (8UL) /* CNEN (Bit 8) */
|
||||
#define RUSB2_SYSCFG_CNEN_Msk (0x100UL) /* CNEN (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_SYSCFG_HSE_Pos (7UL) /*!< HSE (Bit 7) */
|
||||
#define RUSB2_SYSCFG_HSE_Msk (0x80UL) /*!< HSE (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_SYSCFG_DCFM_Pos (6UL) /* DCFM (Bit 6) */
|
||||
#define RUSB2_SYSCFG_DCFM_Msk (0x40UL) /* DCFM (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_SYSCFG_DRPD_Pos (5UL) /* DRPD (Bit 5) */
|
||||
@@ -1135,6 +1201,10 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
#define RUSB2_INTENB1_DTCHE_Msk (0x1000UL) /* DTCHE (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_INTENB1_ATTCHE_Pos (11UL) /* ATTCHE (Bit 11) */
|
||||
#define RUSB2_INTENB1_ATTCHE_Msk (0x800UL) /* ATTCHE (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_INTENB1_L1RSMENDE_Pos (9UL) /*!< L1RSMENDE (Bit 9) */
|
||||
#define RUSB2_INTENB1_L1RSMENDE_Msk (0x200UL) /*!< L1RSMENDE (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_INTENB1_LPMENDE_Pos (8UL) /*!< LPMENDE (Bit 8) */
|
||||
#define RUSB2_INTENB1_LPMENDE_Msk (0x100UL) /*!< LPMENDE (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_INTENB1_EOFERRE_Pos (6UL) /* EOFERRE (Bit 6) */
|
||||
#define RUSB2_INTENB1_EOFERRE_Msk (0x40UL) /* EOFERRE (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_INTENB1_SIGNE_Pos (5UL) /* SIGNE (Bit 5) */
|
||||
@@ -1299,6 +1369,10 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
#define RUSB2_DCPCTR_BSTS_Msk (0x8000UL) /* BSTS (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_DCPCTR_SUREQ_Pos (14UL) /* SUREQ (Bit 14) */
|
||||
#define RUSB2_DCPCTR_SUREQ_Msk (0x4000UL) /* SUREQ (Bitfield-Mask: 0x01) */
|
||||
#define R_USB_HS0_DCPCTR_CSCLR_Pos (13UL) /*!< CSCLR (Bit 13) */
|
||||
#define RUSB2_DCPCTR_CSCLR_Msk (0x2000UL) /*!< CSCLR (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_DCPCTR_CSSTS_Pos (12UL) /*!< CSSTS (Bit 12) */
|
||||
#define RUSB2_DCPCTR_CSSTS_Msk (0x1000UL) /*!< CSSTS (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_DCPCTR_SUREQCLR_Pos (11UL) /* SUREQCLR (Bit 11) */
|
||||
#define RUSB2_DCPCTR_SUREQCLR_Msk (0x800UL) /* SUREQCLR (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_DCPCTR_SQCLR_Pos (8UL) /* SQCLR (Bit 8) */
|
||||
@@ -1325,6 +1399,8 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
#define RUSB2_PIPECFG_BFRE_Msk (0x400UL) /* BFRE (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_PIPECFG_DBLB_Pos (9UL) /* DBLB (Bit 9) */
|
||||
#define RUSB2_PIPECFG_DBLB_Msk (0x200UL) /* DBLB (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_PIPECFG_CNTMD_Pos (8UL) /*!< CNTMD (Bit 8) */
|
||||
#define RUSB2_PIPECFG_CNTMD_Msk (0x100UL) /*!< CNTMD (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_PIPECFG_SHTNAK_Pos (7UL) /* SHTNAK (Bit 7) */
|
||||
#define RUSB2_PIPECFG_SHTNAK_Msk (0x80UL) /* SHTNAK (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_PIPECFG_DIR_Pos (4UL) /* DIR (Bit 4) */
|
||||
@@ -1332,6 +1408,12 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
#define RUSB2_PIPECFG_EPNUM_Pos (0UL) /* EPNUM (Bit 0) */
|
||||
#define RUSB2_PIPECFG_EPNUM_Msk (0xfUL) /* EPNUM (Bitfield-Mask: 0x0f) */
|
||||
|
||||
// PIPEBUF
|
||||
#define RUSB2_PIPEBUF_BUFSIZE_Pos (10UL) /*!< BUFSIZE (Bit 10) */
|
||||
#define RUSB2_PIPEBUF_BUFSIZE_Msk (0x7c00UL) /*!< BUFSIZE (Bitfield-Mask: 0x1f) */
|
||||
#define RUSB2_PIPEBUF_BUFNMB_Pos (0UL) /*!< BUFNMB (Bit 0) */
|
||||
#define RUSB2_PIPEBUF_BUFNMB_Msk (0xffUL) /*!< BUFNMB (Bitfield-Mask: 0xff) */
|
||||
|
||||
// PIPEMAXP
|
||||
#define RUSB2_PIPEMAXP_DEVSEL_Pos (12UL) /* DEVSEL (Bit 12) */
|
||||
#define RUSB2_PIPEMAXP_DEVSEL_Msk (0xf000UL) /* DEVSEL (Bitfield-Mask: 0x0f) */
|
||||
@@ -1478,6 +1560,28 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
#define RUSB2_HL1CTRL2_L1ADDR_Pos (0UL) /* L1ADDR (Bit 0) */
|
||||
#define RUSB2_HL1CTRL2_L1ADDR_Msk (0xfUL) /* L1ADDR (Bitfield-Mask: 0x0f) */
|
||||
|
||||
// PHYTRIM1
|
||||
#define RUSB2_PHYTRIM1_IMPOFFSET_Pos (12UL) /*!< IMPOFFSET (Bit 12) */
|
||||
#define RUSB2_PHYTRIM1_IMPOFFSET_Msk (0x7000UL) /*!< IMPOFFSET (Bitfield-Mask: 0x07) */
|
||||
#define RUSB2_PHYTRIM1_HSIUP_Pos (8UL) /*!< HSIUP (Bit 8) */
|
||||
#define RUSB2_PHYTRIM1_HSIUP_Msk (0xf00UL) /*!< HSIUP (Bitfield-Mask: 0x0f) */
|
||||
#define RUSB2_PHYTRIM1_PCOMPENB_Pos (7UL) /*!< PCOMPENB (Bit 7) */
|
||||
#define RUSB2_PHYTRIM1_PCOMPENB_Msk (0x80UL) /*!< PCOMPENB (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_PHYTRIM1_DFALL_Pos (2UL) /*!< DFALL (Bit 2) */
|
||||
#define RUSB2_PHYTRIM1_DFALL_Msk (0xcUL) /*!< DFALL (Bitfield-Mask: 0x03) */
|
||||
#define RUSB2_PHYTRIM1_DRISE_Pos (0UL) /*!< DRISE (Bit 0) */
|
||||
#define RUSB2_PHYTRIM1_DRISE_Msk (0x3UL) /*!< DRISE (Bitfield-Mask: 0x03) */
|
||||
|
||||
// PHYTRIM2
|
||||
#define RUSB2_PHYTRIM2_DIS_Pos (12UL) /*!< DIS (Bit 12) */
|
||||
#define RUSB2_PHYTRIM2_DIS_Msk (0x7000UL) /*!< DIS (Bitfield-Mask: 0x07) */
|
||||
#define RUSB2_PHYTRIM2_PDR_Pos (8UL) /*!< PDR (Bit 8) */
|
||||
#define RUSB2_PHYTRIM2_PDR_Msk (0x300UL) /*!< PDR (Bitfield-Mask: 0x03) */
|
||||
#define RUSB2_PHYTRIM2_HSRXENMO_Pos (7UL) /*!< HSRXENMO (Bit 7) */
|
||||
#define RUSB2_PHYTRIM2_HSRXENMO_Msk (0x80UL) /*!< HSRXENMO (Bitfield-Mask: 0x01) */
|
||||
#define RUSB2_PHYTRIM2_SQU_Pos (0UL) /*!< SQU (Bit 0) */
|
||||
#define RUSB2_PHYTRIM2_SQU_Msk (0xfUL) /*!< SQU (Bitfield-Mask: 0x0f) */
|
||||
|
||||
// DPUSR0R
|
||||
#define RUSB2_DPUSR0R_DVBSTSHM_Pos (23UL) /* DVBSTSHM (Bit 23) */
|
||||
#define RUSB2_DPUSR0R_DVBSTSHM_Msk (0x800000UL) /* DVBSTSHM (Bitfield-Mask: 0x01) */
|
||||
@@ -1568,9 +1672,11 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
|
||||
#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
|
||||
#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
|
||||
#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
|
||||
|
||||
#define RUSB2_DVSTCTR0_RHST_LS (1U << RUSB2_DVSTCTR0_RHST_Pos) /* Low-speed connection */
|
||||
#define RUSB2_DVSTCTR0_RHST_FS (2U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
|
||||
#define RUSB2_DVSTCTR0_RHST_HS (3U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
|
||||
|
||||
#define RUSB2_DEVADD_USBSPD_LS (1U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Low-speed */
|
||||
#define RUSB2_DEVADD_USBSPD_FS (2U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Full-speed */
|
||||
@@ -1580,6 +1686,7 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
#define RUSB2_FIFOSEL_BIGEND (1U << RUSB2_CFIFOSEL_BIGEND_Pos) /* FIFO Big Endian */
|
||||
#define RUSB2_FIFOSEL_MBW_8BIT (0U << RUSB2_CFIFOSEL_MBW_Pos) /* 8-bit width */
|
||||
#define RUSB2_FIFOSEL_MBW_16BIT (1U << RUSB2_CFIFOSEL_MBW_Pos) /* 16-bit width */
|
||||
#define RUSB2_FIFOSEL_MBW_32BIT (2U << RUSB2_CFIFOSEL_MBW_Pos) /* 32-bit width */
|
||||
|
||||
#define RUSB2_INTSTS0_CTSQ_CTRL_RDATA (1U << RUSB2_INTSTS0_CTSQ_Pos)
|
||||
|
||||
@@ -1599,69 +1706,72 @@ TU_ATTR_BIT_FIELD_ORDER_END
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(RUSB2_PIPE_TR_t) == 4, "incorrect size");
|
||||
TU_VERIFY_STATIC(sizeof(RUSB2_REG_t) == 1032, "incorrect size");
|
||||
TU_VERIFY_STATIC(sizeof(rusb2_reg_t) == 1032, "incorrect size");
|
||||
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, SYSCFG ) == 0x00000000, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, BUSWAIT ) == 0x00000002, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, SYSSTS0 ) == 0x00000004, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PLLSTA ) == 0x00000006, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DVSTCTR0 ) == 0x00000008, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, TESTMODE ) == 0x0000000C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, CFIFO ) == 0x00000014, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, D0FIFO ) == 0x00000018, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, D1FIFO ) == 0x0000001C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, CFIFOSEL ) == 0x00000020, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, CFIFOCTR ) == 0x00000022, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, D0FIFOSEL ) == 0x00000028, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, D0FIFOCTR ) == 0x0000002A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, D1FIFOSEL ) == 0x0000002C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, D1FIFOCTR ) == 0x0000002E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, INTENB0 ) == 0x00000030, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, INTENB1 ) == 0x00000032, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, BRDYENB ) == 0x00000036, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, NRDYENB ) == 0x00000038, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, BEMPENB ) == 0x0000003A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, SOFCFG ) == 0x0000003C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PHYSET ) == 0x0000003E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, INTSTS0 ) == 0x00000040, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, INTSTS1 ) == 0x00000042, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, BRDYSTS ) == 0x00000046, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, NRDYSTS ) == 0x00000048, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, BEMPSTS ) == 0x0000004A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, FRMNUM ) == 0x0000004C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, UFRMNUM ) == 0x0000004E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, USBADDR ) == 0x00000050, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, USBREQ ) == 0x00000054, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, USBVAL ) == 0x00000056, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, USBINDX ) == 0x00000058, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, USBLENG ) == 0x0000005A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DCPCFG ) == 0x0000005C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DCPMAXP ) == 0x0000005E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DCPCTR ) == 0x00000060, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PIPESEL ) == 0x00000064, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PIPECFG ) == 0x00000068, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PIPEMAXP ) == 0x0000006C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PIPEPERI ) == 0x0000006E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PIPE_CTR ) == 0x00000070, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PIPE_TR ) == 0x00000090, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, USBBCCTRL0 ) == 0x000000B0, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, UCKSEL ) == 0x000000C4, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, USBMC ) == 0x000000CC, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DEVADD ) == 0x000000D0, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PHYSLEW ) == 0x000000F0, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, LPCTRL ) == 0x00000100, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, LPSTS ) == 0x00000102, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, BCCTRL ) == 0x00000140, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PL1CTRL1 ) == 0x00000144, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, PL1CTRL2 ) == 0x00000146, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, HL1CTRL1 ) == 0x00000148, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, HL1CTRL2 ) == 0x0000014A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DPUSR0R ) == 0x00000160, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DPUSR1R ) == 0x00000164, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DPUSR2R ) == 0x00000168, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DPUSRCR ) == 0x0000016A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DPUSR0R_FS ) == 0x00000400, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, DPUSR1R_FS ) == 0x00000404, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, SYSCFG ) == 0x0000, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BUSWAIT ) == 0x0002, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, SYSSTS0 ) == 0x0004, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PLLSTA ) == 0x0006, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DVSTCTR0 ) == 0x0008, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, TESTMODE ) == 0x000C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, CFIFO ) == 0x0014, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D0FIFO ) == 0x0018, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D1FIFO ) == 0x001C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, CFIFOSEL ) == 0x0020, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, CFIFOCTR ) == 0x0022, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D0FIFOSEL ) == 0x0028, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D0FIFOCTR ) == 0x002A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D1FIFOSEL ) == 0x002C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, D1FIFOCTR ) == 0x002E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, INTENB0 ) == 0x0030, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, INTENB1 ) == 0x0032, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BRDYENB ) == 0x0036, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, NRDYENB ) == 0x0038, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BEMPENB ) == 0x003A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, SOFCFG ) == 0x003C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PHYSET ) == 0x003E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, INTSTS0 ) == 0x0040, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, INTSTS1 ) == 0x0042, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BRDYSTS ) == 0x0046, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, NRDYSTS ) == 0x0048, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BEMPSTS ) == 0x004A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, FRMNUM ) == 0x004C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, UFRMNUM ) == 0x004E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBADDR ) == 0x0050, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBREQ ) == 0x0054, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBVAL ) == 0x0056, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBINDX ) == 0x0058, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBLENG ) == 0x005A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DCPCFG ) == 0x005C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DCPMAXP ) == 0x005E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DCPCTR ) == 0x0060, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPESEL ) == 0x0064, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPECFG ) == 0x0068, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPEBUF ) == 0x006A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPEMAXP ) == 0x006C, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPEPERI ) == 0x006E, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPE_CTR ) == 0x0070, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PIPE_TR ) == 0x0090, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBBCCTRL0 ) == 0x00B0, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, UCKSEL ) == 0x00C4, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, USBMC ) == 0x00CC, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DEVADD ) == 0x00D0, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PHYSLEW ) == 0x00F0, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, LPCTRL ) == 0x0100, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, LPSTS ) == 0x0102, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, BCCTRL ) == 0x0140, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PL1CTRL1 ) == 0x0144, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PL1CTRL2 ) == 0x0146, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, HL1CTRL1 ) == 0x0148, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, HL1CTRL2 ) == 0x014A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PHYTRIM1 ) == 0x0150, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, PHYTRIM2 ) == 0x0152, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR0R ) == 0x0160, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR1R ) == 0x0164, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR2R ) == 0x0168, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSRCR ) == 0x016A, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR0R_FS ) == 0x0400, "incorrect offset");
|
||||
TU_VERIFY_STATIC(offsetof(rusb2_reg_t, DPUSR1R_FS ) == 0x0404, "incorrect offset");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user