Enhance chipidea (#2075)

* update chipidea dcd, remove manual ep_count and use DCCPARAMS to get number of endpoint instead
* add dcd dcache for chipidea
* add cmake for lpc18
* add makefile build for mcx
* use fork of mcu sdk
* fix ci build with nrf
* flash rp2040 with openocd
This commit is contained in:
Ha Thach
2023-05-23 21:45:00 +07:00
committed by GitHub
parent c998e9c60b
commit 1ef820ecfe
42 changed files with 1915 additions and 122 deletions

View File

@@ -46,18 +46,44 @@ static const ci_hs_controller_t _ci_controller[] =
{
// RT1010 and RT1020 only has 1 USB controller
#if FSL_FEATURE_SOC_USBHS_COUNT == 1
{ .reg_base = USB_BASE , .irqnum = USB_OTG1_IRQn, .ep_count = 8 }
{ .reg_base = USB_BASE , .irqnum = USB_OTG1_IRQn }
#else
{ .reg_base = USB1_BASE, .irqnum = USB_OTG1_IRQn, .ep_count = 8 },
{ .reg_base = USB2_BASE, .irqnum = USB_OTG2_IRQn, .ep_count = 8 }
{ .reg_base = USB1_BASE, .irqnum = USB_OTG1_IRQn},
{ .reg_base = USB2_BASE, .irqnum = USB_OTG2_IRQn}
#endif
};
#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
//------------- DCD -------------//
#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
//------------- HCD -------------//
#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
//------------- DCache -------------//
TU_ATTR_ALWAYS_INLINE static inline bool imxrt_is_cache_mem(uint32_t addr) {
return !(0x20000000 <= addr && addr < 0x20100000);
}
TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_clean(void* addr, uint32_t data_size) {
if (imxrt_is_cache_mem((uint32_t) addr)) {
SCB_CleanDCache_by_Addr((uint32_t *) addr, (int32_t) data_size);
}
}
TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_invalidate(void* addr, uint32_t data_size) {
if (imxrt_is_cache_mem((uint32_t) addr)) {
SCB_InvalidateDCache_by_Addr(addr, (int32_t) data_size);
}
}
TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_clean_invalidate(void* addr, uint32_t data_size) {
if (imxrt_is_cache_mem((uint32_t) addr)) {
SCB_CleanInvalidateDCache_by_Addr(addr, (int32_t) data_size);
}
}
#endif

View File

@@ -32,10 +32,12 @@
static const ci_hs_controller_t _ci_controller[] =
{
{ .reg_base = LPC_USB0_BASE, .irqnum = USB0_IRQn, .ep_count = 6 },
{ .reg_base = LPC_USB1_BASE, .irqnum = USB1_IRQn, .ep_count = 4 }
{ .reg_base = LPC_USB0_BASE, .irqnum = USB0_IRQn },
{ .reg_base = LPC_USB1_BASE, .irqnum = USB1_IRQn }
};
#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
#define CI_DCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
#define CI_DCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)

View File

@@ -0,0 +1,52 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021, 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.
*/
#ifndef _CI_HS_MCX_H_
#define _CI_HS_MCX_H_
#include "fsl_device_registers.h"
// NOTE: MCX N9 has 2 different USB Controller
// - USB0 is KHCI FullSpeed
// - USB1 is ChipIdea HighSpeed, therefore rhport = 1 is actually index 0
static const ci_hs_controller_t _ci_controller[] = {
{.reg_base = USBHS1__USBC_BASE, .irqnum = USB1_HS_IRQn}
};
TU_ATTR_ALWAYS_INLINE static inline ci_hs_regs_t* CI_HS_REG(uint8_t port) {
(void) port;
return ((ci_hs_regs_t*) _ci_controller[0].reg_base);
}
#define CI_DCD_INT_ENABLE(_p) do { (void) _p; NVIC_EnableIRQ (_ci_controller[0].irqnum); } while (0)
#define CI_DCD_INT_DISABLE(_p) do { (void) _p; NVIC_DisableIRQ(_ci_controller[0].irqnum); } while (0)
#define CI_HCD_INT_ENABLE(_p) NVIC_EnableIRQ (_ci_controller[_p].irqnum)
#define CI_HCD_INT_DISABLE(_p) NVIC_DisableIRQ(_ci_controller[_p].irqnum)
#endif

View File

@@ -31,13 +31,21 @@
extern "C" {
#endif
// DCCPARAMS
enum {
DCCPARAMS_DEN_MASK = 0x1Fu, ///< DEN bit 4:0
};
// USBCMD
enum {
USBCMD_RUN_STOP = TU_BIT(0),
USBCMD_RESET = TU_BIT(1),
USBCMD_SETUP_TRIPWIRE = TU_BIT(13),
USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoints linked list. This bit is set and cleared by software during the process of adding a new dTD
// Interrupt Threshold bit 23:16
USBCMD_ADD_QTD_TRIPWIRE = TU_BIT(14), // This bit is used as a semaphore to ensure the to proper addition of a
// new dTD to an active (primed) endpoints linked list. This bit is set and
// cleared by software during the process of adding a new dTD
USBCMD_INTR_THRESHOLD_MASK = 0x00FF0000u, // Interrupt Threshold bit 23:16
};
// PORTSC1
@@ -72,6 +80,7 @@ enum {
// USBMode
enum {
USBMOD_CM_MASK = TU_BIT(0) | TU_BIT(1),
USBMODE_CM_DEVICE = 2,
USBMODE_CM_HOST = 3,
@@ -134,7 +143,6 @@ typedef struct
{
uint32_t reg_base;
uint32_t irqnum;
uint8_t ep_count; // Max bi-directional Endpoints
}ci_hs_controller_t;
#ifdef __cplusplus

View File

@@ -28,35 +28,53 @@
#if CFG_TUD_ENABLED && defined(TUP_USBIP_CHIPIDEA_HS)
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "device/dcd.h"
#include "ci_hs_type.h"
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
#include "ci_hs_imxrt.h"
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
void dcd_dcache_clean(void* addr, uint32_t data_size) {
imxrt_dcache_clean(addr, data_size);
}
void dcd_dcache_invalidate(void* addr, uint32_t data_size) {
imxrt_dcache_invalidate(addr, data_size);
}
void dcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
imxrt_dcache_clean_invalidate(addr, data_size);
}
#else
#if TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
#include "ci_hs_lpc18_43.h"
#elif TU_CHECK_MCU(OPT_MCU_MCXN9)
// MCX N9 only port 1 use this controller
#include "ci_hs_mcx.h"
#else
#error "Unsupported MCUs"
#endif
TU_ATTR_WEAK void dcd_dcache_clean(void* addr, uint32_t data_size) {
(void) addr; (void) data_size;
}
TU_ATTR_WEAK void dcd_dcache_invalidate(void* addr, uint32_t data_size) {
(void) addr; (void) data_size;
}
TU_ATTR_WEAK void dcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
(void) addr; (void) data_size;
}
#endif
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
// Clean means to push any cached changes to RAM and invalidate "removes" the
// entry from the cache.
#if defined(__CORTEX_M) && __CORTEX_M == 7 && __DCACHE_PRESENT == 1
#define CleanInvalidateDCache_by_Addr SCB_CleanInvalidateDCache_by_Addr
#else
#define CleanInvalidateDCache_by_Addr(_addr, _dsize)
#endif
// ENDPTCTRL
enum {
ENDPTCTRL_STALL = TU_BIT(0),
@@ -160,6 +178,16 @@ typedef struct {
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
static dcd_data_t _dcd_data;
//--------------------------------------------------------------------+
// Prototypes and Helper Functions
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE
static inline uint8_t ci_ep_count(ci_hs_regs_t const* dcd_reg)
{
return dcd_reg->DCCPARAMS & DCCPARAMS_DEN_MASK;
}
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
@@ -174,7 +202,8 @@ static void bus_reset(uint8_t rhport)
// endpoint type of the unused direction must be changed from the control type to any other
// type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
// for the data PID tracking on the active endpoint.
for( uint8_t i=1; i < _ci_controller[rhport].ep_count; i++)
uint8_t const ep_count = ci_ep_count(dcd_reg);
for( uint8_t i=1; i < ep_count; i++)
{
dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
}
@@ -202,7 +231,7 @@ static void bus_reset(uint8_t rhport)
_dcd_data.qhd[0][0].int_on_setup = 1; // OUT only
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
}
void dcd_init(uint8_t rhport)
@@ -211,26 +240,34 @@ void dcd_init(uint8_t rhport)
ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
TU_ASSERT(ci_ep_count(dcd_reg) <= TUP_DCD_ENDPOINT_MAX, );
// Reset controller
dcd_reg->USBCMD |= USBCMD_RESET;
while( dcd_reg->USBCMD & USBCMD_RESET ) {}
// Set mode to device, must be set immediately after reset
dcd_reg->USBMODE = USBMODE_CM_DEVICE;
uint32_t usbmode = dcd_reg->USBMODE & ~USBMOD_CM_MASK;
usbmode |= USBMODE_CM_DEVICE;
dcd_reg->USBMODE = usbmode;
dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
#if !TUD_OPT_HIGH_SPEED
dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
#endif
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment
dcd_reg->USBSTS = dcd_reg->USBSTS;
dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND;
dcd_reg->USBCMD &= ~0x00FF0000; // Interrupt Threshold Interval = 0
dcd_reg->USBCMD |= USBCMD_RUN_STOP; // Connect
uint32_t usbcmd = dcd_reg->USBCMD;
usbcmd &= ~USBCMD_INTR_THRESHOLD_MASK; // Interrupt Threshold Interval = 0
usbcmd |= USBCMD_RUN_STOP; // run
dcd_reg->USBCMD = usbcmd;
}
void dcd_int_enable(uint8_t rhport)
@@ -286,7 +323,7 @@ static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
{
// Force the CPU to flush the buffer. We increase the size by 31 because the call aligns the
// address to 32-byte boundaries. Buffer must be word aligned
CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31);
dcd_dcache_clean_invalidate((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31);
tu_memclr(p_qtd, sizeof(dcd_qtd_t));
@@ -343,8 +380,10 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
// Must not exceed max endpoint number
TU_ASSERT( epnum < _ci_controller[rhport].ep_count );
TU_ASSERT(epnum < ci_ep_count(dcd_reg));
//------------- Prepare Queue Head -------------//
dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
@@ -359,11 +398,9 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
// Enable EP Control
ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
uint32_t const epctrl = (p_endpoint_desc->bmAttributes.xfer << ENDPTCTRL_TYPE_POS) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET;
if ( dir == TUSB_DIR_OUT )
@@ -382,7 +419,8 @@ void dcd_edpt_close_all (uint8_t rhport)
ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
// Disable all non-control endpoints
for( uint8_t epnum=1; epnum < _ci_controller[rhport].ep_count; epnum++)
uint8_t const ep_count = ci_ep_count(dcd_reg);
for (uint8_t epnum = 1; epnum < ep_count; epnum++)
{
_dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1;
_dcd_data.qhd[epnum][TUSB_DIR_IN ].qtd_overlay.halted = 1;
@@ -420,7 +458,7 @@ static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir)
p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd
// flush cache
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
if ( epnum == 0 )
{
@@ -498,7 +536,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
}
}
CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
dcd_dcache_clean_invalidate((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
}
else
{
@@ -611,7 +649,7 @@ void dcd_int_handler(uint8_t rhport)
if (int_status & INTR_USB)
{
// Make sure we read the latest version of _dcd_data.
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
dcd_dcache_clean_invalidate(&_dcd_data, sizeof(dcd_data_t));
uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE;
dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge

View File

@@ -42,28 +42,17 @@
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
#include "ci_hs_imxrt.h"
// check if memory is cacheable i.e not in DTCM
TU_ATTR_ALWAYS_INLINE static inline bool is_cache_mem(uint32_t addr) {
return !(0x20000000 <= addr && addr < 0x20100000);
}
void hcd_dcache_clean(void* addr, uint32_t data_size) {
if (is_cache_mem((uint32_t) addr)) {
SCB_CleanDCache_by_Addr((uint32_t *) addr, (int32_t) data_size);
}
imxrt_dcache_clean(addr, data_size);
}
void hcd_dcache_invalidate(void* addr, uint32_t data_size) {
if (is_cache_mem((uint32_t) addr)) {
SCB_InvalidateDCache_by_Addr(addr, (int32_t) data_size);
}
imxrt_dcache_invalidate(addr, data_size);
}
void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
if (is_cache_mem((uint32_t) addr)) {
SCB_CleanInvalidateDCache_by_Addr(addr, (int32_t) data_size);
void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
imxrt_dcache_clean_invalidate(addr, data_size);
}
}
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
#include "ci_hs_lpc18_43.h"
@@ -75,8 +64,6 @@ void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
#define CI_HS_REG(_port) ((ci_hs_regs_t*) _ci_controller[_port].reg_base)
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+