summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDave Nadler <[email protected]>2023-06-24 11:53:24 -0400
committerGitHub <[email protected]>2023-06-24 11:53:24 -0400
commitbd897d9c14b289861150456cb5538aac42ecc69e (patch)
tree84c67dee042b7dfadd8fbe0745c5f44f39ee9e2f /src
parente8b7f21af6e5e994ece7c989202767732f23809e (diff)
parent50e61e0e16122a2466536d77b858cb228d60d0c2 (diff)
Merge branch 'hathach:master' into master
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/class/audio/audio_device.c4
-rw-r--r--src/class/video/video.h4
-rw-r--r--src/class/video/video_device.c85
-rw-r--r--src/common/tusb_mcu.h15
-rw-r--r--src/common/tusb_types.h10
-rw-r--r--src/device/dcd.h7
-rw-r--r--src/device/usbd.c10
-rw-r--r--src/device/usbd.h10
-rw-r--r--src/host/hcd.h6
-rw-r--r--src/host/usbh.c14
-rw-r--r--src/portable/chipidea/ci_fs/ci_fs_kinetis.h51
-rw-r--r--src/portable/chipidea/ci_fs/ci_fs_mcx.h47
-rw-r--r--src/portable/chipidea/ci_fs/ci_fs_type.h118
-rw-r--r--src/portable/chipidea/ci_fs/dcd_ci_fs.c555
-rw-r--r--src/portable/chipidea/ci_hs/ci_hs_imxrt.h23
-rw-r--r--src/portable/chipidea/ci_hs/dcd_ci_hs.c14
-rw-r--r--src/portable/chipidea/ci_hs/hcd_ci_hs.c11
-rw-r--r--src/portable/ehci/ehci.c8
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c14
-rw-r--r--src/portable/nxp/transdimension/common_transdimension.h136
-rw-r--r--src/portable/nxp/transdimension/dcd_transdimension.c672
-rw-r--r--src/portable/nxp/transdimension/hcd_transdimension.c119
-rw-r--r--src/portable/renesas/rusb2/rusb2_type.h147
-rw-r--r--src/portable/st/typec/typec_stm32.c372
-rw-r--r--src/tusb.h5
-rw-r--r--src/tusb_option.h16
-rw-r--r--src/typec/pd_types.h237
-rw-r--r--src/typec/tcd.h143
-rw-r--r--src/typec/usbc.c219
-rw-r--r--src/typec/usbc.h91
31 files changed, 2090 insertions, 1077 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 396737ed5..b99c7be6e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -32,6 +32,8 @@ function(add_tinyusb TARGET)
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/hid/hid_host.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/msc/msc_host.c
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/vendor/vendor_host.c
+ # typec
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/typec/usbc.c
)
target_include_directories(${TARGET} PUBLIC
${CMAKE_CURRENT_FUNCTION_LIST_DIR}
@@ -65,6 +67,8 @@ function(add_tinyusb TARGET)
-Wreturn-type
-Wredundant-decls
)
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+
endif ()
endfunction()
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index f487fe60e..e5dbe988a 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -66,7 +66,7 @@
// Use ring buffer if it's available, some MCUs need extra RAM requirements
#ifndef TUD_AUDIO_PREFER_RING_BUFFER
- #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT
+ #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
#define TUD_AUDIO_PREFER_RING_BUFFER 0
#else
#define TUD_AUDIO_PREFER_RING_BUFFER 1
@@ -85,7 +85,7 @@
CFG_TUSB_MCU == OPT_MCU_RX72N || \
CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
CFG_TUSB_MCU == OPT_MCU_LPC43XX || \
- CFG_TUSB_MCU == OPT_MCU_MIMXRT || \
+ CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX || \
CFG_TUSB_MCU == OPT_MCU_MSP432E4
#if TUD_AUDIO_PREFER_RING_BUFFER
#define USE_LINEAR_BUFFER 0
diff --git a/src/class/video/video.h b/src/class/video/video.h
index c0088c4f6..d9880c291 100644
--- a/src/class/video/video.h
+++ b/src/class/video/video.h
@@ -448,9 +448,9 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
#define TUD_VIDEO_GUID_M420 0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
#define TUD_VIDEO_GUID_I420 0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
-#define TUD_VIDEO_DESC_IAD(_firstitfs, _nitfs, _stridx) \
+#define TUD_VIDEO_DESC_IAD(_firstitf, _nitfs, _stridx) \
TUD_VIDEO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, \
- _firstitfs, _nitfs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_INTERFACE_COLLECTION, \
+ _firstitf, _nitfs, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_INTERFACE_COLLECTION, \
VIDEO_ITF_PROTOCOL_UNDEFINED, _stridx
#define TUD_VIDEO_DESC_STD_VC(_itfnum, _nEPs, _stridx) \
diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c
index d6e98602b..91f452afc 100644
--- a/src/class/video/video_device.c
+++ b/src/class/video/video_device.c
@@ -37,6 +37,10 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
+#define VS_STATE_PROBING 0 /* Configuration in progress */
+#define VS_STATE_COMMITTED 1 /* Ready for streaming or Streaming via bulk endpoint */
+#define VS_STATE_STREAMING 2 /* Streaming via isochronous endpoint */
+
typedef struct {
tusb_desc_interface_t std;
tusb_desc_cs_video_ctl_itf_hdr_t ctl;
@@ -102,6 +106,7 @@ typedef struct TU_ATTR_PACKED {
uint32_t offset; /* offset for the next payload transfer */
uint32_t max_payload_transfer_size;
uint8_t error_code;/* error code */
+ uint8_t state; /* 0:probing 1:committed 2:streaming */
/*------------- From this point, data is not cleared by bus reset -------------*/
CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */
} videod_streaming_interface_t;
@@ -639,6 +644,17 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t
return true;
}
+static bool _init_vs_configuration(videod_streaming_interface_t *stm)
+{
+ /* initialize streaming settings */
+ stm->state = VS_STATE_PROBING;
+ stm->max_payload_transfer_size = 0;
+ video_probe_and_commit_control_t *param =
+ (video_probe_and_commit_control_t *)&stm->ep_buf;
+ tu_memclr(param, sizeof(*param));
+ return _update_streaming_parameters(stm, param);
+}
+
/** Set the alternate setting to own video streaming interface.
*
* @param[in,out] stm Streaming interface context.
@@ -672,42 +688,32 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints;
TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep));
- stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */
- if (!altnum) {
- /* initialize streaming settings */
- stm->max_payload_transfer_size = 0;
- video_probe_and_commit_control_t *param =
- (video_probe_and_commit_control_t *)&stm->ep_buf;
- tu_memclr(param, sizeof(*param));
- TU_LOG2(" done 0\n");
- return _update_streaming_parameters(stm, param);
+ stm->desc.cur = (uint16_t)(cur - desc); /* Save the offset of the new settings */
+ if (!altnum && (VS_STATE_COMMITTED != stm->state)) {
+ TU_VERIFY(_init_vs_configuration(stm));
}
- /* Open endpoints of the new settings. */
+ /* Open bulk or isochronous endpoints of the new settings. */
for (i = 0, cur = tu_desc_next(cur); i < numeps; ++i, cur = tu_desc_next(cur)) {
cur = _find_desc_ep(cur, end);
TU_ASSERT(cur < end);
tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur;
- if (!stm->max_payload_transfer_size) {
- video_probe_and_commit_control_t const *param = (video_probe_and_commit_control_t const*)&stm->ep_buf;
- uint_fast32_t max_size = param->dwMaxPayloadTransferSize;
+ uint_fast32_t max_size = stm->max_payload_transfer_size;
+ if (altnum) {
if ((TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer) &&
- (tu_edpt_packet_size(ep) < max_size))
- {
+ (tu_edpt_packet_size(ep) < max_size)) {
/* FS must be less than or equal to max packet size */
return false;
}
- /* Set the negotiated value */
- stm->max_payload_transfer_size = max_size;
+ } else {
+ TU_VERIFY(TUSB_XFER_BULK == ep->bmAttributes.xfer);
}
TU_ASSERT(usbd_edpt_open(rhport, ep));
stm->desc.ep[i] = (uint16_t) (cur - desc);
TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur));
}
- /* initialize payload header */
- tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf;
- hdr->bHeaderLength = sizeof(*hdr);
- hdr->bmHeaderInfo = 0;
-
+ if (altnum) {
+ stm->state = VS_STATE_STREAMING;
+ }
TU_LOG2(" done\n");
return true;
}
@@ -920,6 +926,10 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
break;
case VIDEO_VS_CTL_PROBE:
+ if (self->state != VS_STATE_PROBING) {
+ self->state = VS_STATE_PROBING;
+ _init_vs_configuration(self);
+ }
switch (request->bRequest) {
case VIDEO_REQUEST_SET_CUR:
if (stage == CONTROL_STAGE_SETUP) {
@@ -982,9 +992,23 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
} else if (stage == CONTROL_STAGE_DATA) {
- TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
+ video_probe_and_commit_control_t *param = (video_probe_and_commit_control_t*)self->ep_buf;
+ TU_VERIFY(_update_streaming_parameters(self, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
+ /* Set the negotiated value */
+ self->max_payload_transfer_size = param->dwMaxPayloadTransferSize;
+ int ret = VIDEO_ERROR_NONE;
if (tud_video_commit_cb) {
- return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf);
+ ret = tud_video_commit_cb(self->index_vc, self->index_vs, param);
+ }
+ if (VIDEO_ERROR_NONE == ret) {
+ self->state = VS_STATE_COMMITTED;
+ self->buffer = NULL;
+ self->bufsize = 0;
+ self->offset = 0;
+ /* initialize payload header */
+ tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)self->ep_buf;
+ hdr->bHeaderLength = sizeof(*hdr);
+ hdr->bmHeaderInfo = 0;
}
}
return VIDEO_ERROR_NONE;
@@ -1069,6 +1093,7 @@ bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx);
if (!stm || !stm->desc.ep[0]) return false;
+ if (stm->state == VS_STATE_PROBING) return false;
return true;
}
@@ -1079,6 +1104,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
if (!buffer || !bufsize) return false;
videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx);
if (!stm || !stm->desc.ep[0] || stm->buffer) return false;
+ if (stm->state == VS_STATE_PROBING) return false;
/* Find EP address */
uint8_t const *desc = _videod_itf[stm->index_vc].beg;
@@ -1174,6 +1200,16 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
stm->desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
cur = _next_desc_itf(cur, end);
stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
+ stm->state = VS_STATE_PROBING;
+ if (0 == stm_idx && 1 == bInCollection) {
+ /* If there is only one streaming interface and no alternate settings,
+ * host may not issue set_interface so open the streaming interface here. */
+ uint8_t const *sbeg = (uint8_t const*)itf_desc + stm->desc.beg;
+ uint8_t const *send = (uint8_t const*)itf_desc + stm->desc.end;
+ if (end == _find_desc_itf(sbeg, send, _desc_itfnum(sbeg), 1)) {
+ TU_VERIFY(_open_vs_itf(rhport, stm, 0), 0);
+ }
+ }
}
self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
@@ -1187,7 +1223,6 @@ bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_
int err;
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
uint_fast8_t itfnum = tu_u16_low(request->wIndex);
-
/* Identify which control interface to use */
uint_fast8_t itf;
for (itf = 0; itf < CFG_TUD_VIDEO; ++itf) {
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 48f765674..56525725e 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -79,14 +79,18 @@
#define TUP_RHPORT_HIGHSPEED 1
#elif TU_CHECK_MCU(OPT_MCU_MCXN9)
- // NOTE: MCXN943 port 1 use chipidea HS, port 0 use chipidea FS
+ // USB0 is chipidea FS
+ #define TUP_USBIP_CHIPIDEA_FS
+ #define TUP_USBIP_CHIPIDEA_FS_MCX
+
+ // USB1 is chipidea HS
#define TUP_USBIP_CHIPIDEA_HS
#define TUP_USBIP_EHCI
#define TUP_DCD_ENDPOINT_MAX 8
#define TUP_RHPORT_HIGHSPEED 1
-#elif TU_CHECK_MCU(OPT_MCU_MIMXRT)
+#elif TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX)
#define TUP_USBIP_CHIPIDEA_HS
#define TUP_USBIP_EHCI
@@ -197,10 +201,17 @@
#define TUP_DCD_ENDPOINT_MAX 9
#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
+ // Device controller
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
+
+ // TypeC controller
+ #define TUP_USBIP_TYPEC_STM32
+
#define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_TYPEC_RHPORTS_NUM 1
+
#elif TU_CHECK_MCU(OPT_MCU_STM32G0)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
index 39a2d4564..fab680989 100644
--- a/src/common/tusb_types.h
+++ b/src/common/tusb_types.h
@@ -232,6 +232,9 @@ enum {
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
typedef enum
{
XFER_RESULT_SUCCESS = 0,
@@ -474,9 +477,10 @@ typedef struct TU_ATTR_PACKED
uint16_t bcdDFUVersion;
} tusb_desc_dfu_functional_t;
-/*------------------------------------------------------------------*/
-/* Types
- *------------------------------------------------------------------*/
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
typedef struct TU_ATTR_PACKED{
union {
struct TU_ATTR_PACKED {
diff --git a/src/device/dcd.h b/src/device/dcd.h
index f82b8633d..18a708347 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -108,15 +108,15 @@ typedef struct TU_ATTR_ALIGNED(4)
// clean/flush data cache: write cache -> memory.
// Required before an DMA TX transfer to make sure data is in memory
-void dcd_dcache_clean(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+void dcd_dcache_clean(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
// invalidate data cache: mark cache as invalid, next read will read from memory
// Required BOTH before and after an DMA RX transfer
-void dcd_dcache_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+void dcd_dcache_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
// clean and invalidate data cache
// Required before an DMA transfer where memory is both read/write by DMA
-void dcd_dcache_clean_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
//--------------------------------------------------------------------+
// Controller API
@@ -189,6 +189,7 @@ TU_ATTR_WEAK bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t l
// Configure and enable an ISO endpoint according to descriptor
TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
+
//--------------------------------------------------------------------+
// Event API (implemented by stack)
//--------------------------------------------------------------------+
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 409a5ec10..44c2530ce 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -252,9 +252,19 @@ static inline usbd_class_driver_t const * get_driver(uint8_t drvid)
drvid -= _app_driver_count;
}
+ // when there is no built-in drivers BUILTIN_DRIVER_COUNT = 0 will cause -Wtype-limits warning
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
// Built-in drivers
if (drvid < BUILTIN_DRIVER_COUNT) return &_usbd_driver[drvid];
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
return NULL;
}
diff --git a/src/device/usbd.h b/src/device/usbd.h
index 255e5a844..b11c1a09d 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -347,8 +347,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Standard Interface Association Descriptor (IAD) */
#define TUD_AUDIO_DESC_IAD_LEN 8
-#define TUD_AUDIO_DESC_IAD(_firstitfs, _nitfs, _stridx) \
- TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx
+#define TUD_AUDIO_DESC_IAD(_firstitf, _nitfs, _stridx) \
+ TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitf, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx
/* Standard AC Interface Descriptor(4.7.1) */
#define TUD_AUDIO_DESC_STD_AC_LEN 9
@@ -443,7 +443,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
#define TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \
/* Standard Interface Association Descriptor (IAD) */\
- TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
+ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
@@ -492,7 +492,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
#define TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \
/* Standard Interface Association Descriptor (IAD) */\
- TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
+ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
@@ -540,7 +540,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \
/* Standard Interface Association Descriptor (IAD) */\
- TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
+ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
diff --git a/src/host/hcd.h b/src/host/hcd.h
index 5a3b0a087..3355c18b2 100644
--- a/src/host/hcd.h
+++ b/src/host/hcd.h
@@ -110,15 +110,15 @@ typedef struct
// clean/flush data cache: write cache -> memory.
// Required before an DMA TX transfer to make sure data is in memory
-void hcd_dcache_clean(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+void hcd_dcache_clean(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
// invalidate data cache: mark cache as invalid, next read will read from memory
// Required BOTH before and after an DMA RX transfer
-void hcd_dcache_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+void hcd_dcache_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
// clean and invalidate data cache
// Required before an DMA transfer where memory is both read/write by DMA
-void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) TU_ATTR_WEAK;
+void hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
//--------------------------------------------------------------------+
// Controller API
diff --git a/src/host/usbh.c b/src/host/usbh.c
index 6159044ab..f3e9d3858 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -411,7 +411,14 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
if ( _dev0.enumerating )
{
TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
+
+ bool is_empty = osal_queue_empty(_usbh_q);
osal_queue_send(_usbh_q, &event, in_isr);
+
+ if (is_empty) {
+ // Exit if this is the only event in the queue, otherwise we may loop forever
+ return;
+ }
}else
{
TU_LOG_USBH("[%u:] USBH DEVICE ATTACH\r\n", event.rhport);
@@ -724,7 +731,7 @@ uint8_t* usbh_get_enum_buf(void)
void usbh_int_set(bool enabled)
{
- // TODO all host controller if multiple is used
+ // TODO all host controller if multiple are used since they shared the same event queue
if (enabled)
{
hcd_int_enable(_usbh_controller);
@@ -1461,7 +1468,10 @@ static bool enum_new_device(hcd_event_t* event)
hcd_port_reset_end( _dev0.rhport);
// device unplugged while delaying
- if ( !hcd_port_connect_status(_dev0.rhport) ) return true;
+ if ( !hcd_port_connect_status(_dev0.rhport) ) {
+ enum_full_complete();
+ return true;
+ }
_dev0.speed = hcd_port_speed_get(_dev0.rhport );
TU_LOG_USBH("%s Speed\r\n", tu_str_speed[_dev0.speed]);
diff --git a/src/portable/chipidea/ci_fs/ci_fs_kinetis.h b/src/portable/chipidea/ci_fs/ci_fs_kinetis.h
new file mode 100644
index 000000000..cd21af1c7
--- /dev/null
+++ b/src/portable/chipidea/ci_fs/ci_fs_kinetis.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef _CI_FS_KINETIS_H
+#define _CI_FS_KINETIS_H
+
+#include "fsl_device_registers.h"
+
+//static const ci_fs_controller_t _ci_controller[] = {
+// {.reg_base = USB0_BASE, .irqnum = USB0_IRQn}
+//};
+
+#define CI_FS_REG(_port) ((ci_fs_regs_t*) USB0_BASE)
+#define CI_REG CI_FS_REG(0)
+
+void dcd_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+ NVIC_EnableIRQ(USB0_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+ NVIC_DisableIRQ(USB0_IRQn);
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_fs/ci_fs_mcx.h b/src/portable/chipidea/ci_fs/ci_fs_mcx.h
new file mode 100644
index 000000000..3bfcd398e
--- /dev/null
+++ b/src/portable/chipidea/ci_fs/ci_fs_mcx.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef _CI_FS_MCX_H
+#define _CI_FS_MCX_H
+
+#include "fsl_device_registers.h"
+
+#define CI_FS_REG(_port) ((ci_fs_regs_t*) USBFS0_BASE)
+#define CI_REG CI_FS_REG(0)
+
+void dcd_int_enable(uint8_t rhport)
+{
+ (void) rhport;
+ NVIC_EnableIRQ(USB0_FS_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+ (void) rhport;
+ NVIC_DisableIRQ(USB0_FS_IRQn);
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_fs/ci_fs_type.h b/src/portable/chipidea/ci_fs/ci_fs_type.h
new file mode 100644
index 000000000..5a5e53fb0
--- /dev/null
+++ b/src/portable/chipidea/ci_fs/ci_fs_type.h
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#ifndef _CI_FS_TYPE_H
+#define _CI_FS_TYPE_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+// Note: some MCUs can only access these registers in 8-bit mode
+// align 4 is used to get rid of reserved fields
+#define _va32 volatile TU_ATTR_ALIGNED(4)
+
+typedef struct {
+ _va32 uint8_t PER_ID; // [00] Peripheral ID register
+ _va32 uint8_t ID_COMP; // [04] Peripheral ID complement register
+ _va32 uint8_t REV; // [08] Peripheral revision register
+ _va32 uint8_t ADD_INFO; // [0C] Peripheral additional info register
+ _va32 uint8_t OTG_ISTAT; // [10] OTG Interrupt Status Register
+ _va32 uint8_t OTG_ICTRL; // [14] OTG Interrupt Control Register
+ _va32 uint8_t OTG_STAT; // [18] OTG Status Register
+ _va32 uint8_t OTG_CTRL; // [1C] OTG Control register
+ uint32_t reserved_20[24]; // [20]
+ _va32 uint8_t INT_STAT; // [80] Interrupt status register
+ _va32 uint8_t INT_EN; // [84] Interrupt enable register
+ _va32 uint8_t ERR_STAT; // [88] Error interrupt status register
+ _va32 uint8_t ERR_ENB; // [8C] Error interrupt enable register
+ _va32 uint8_t STAT; // [90] Status register
+ _va32 uint8_t CTL; // [94] Control register
+ _va32 uint8_t ADDR; // [98] Address register
+ _va32 uint8_t BDT_PAGE1; // [9C] BDT page register 1
+ _va32 uint8_t FRM_NUML; // [A0] Frame number register
+ _va32 uint8_t FRM_NUMH; // [A4] Frame number register
+ _va32 uint8_t TOKEN; // [A8] Token register
+ _va32 uint8_t SOF_THLD; // [AC] SOF threshold register
+ _va32 uint8_t BDT_PAGE2; // [B0] BDT page register 2
+ _va32 uint8_t BDT_PAGE3; // [B4] BDT page register 3
+
+ uint32_t reserved_b8; // [B8]
+ uint32_t reserved_bc; // [BC]
+
+ struct {
+ _va32 uint8_t CTL;
+ }EP[16]; // [C0] Endpoint control register
+
+ //----- Following is only found available in NXP Kinetis
+ _va32 uint8_t USBCTRL; // [100] USB Control register,
+ _va32 uint8_t OBSERVE; // [104] USB OTG Observe register,
+ _va32 uint8_t CONTROL; // [108] USB OTG Control register,
+ _va32 uint8_t USBTRC0; // [10C] USB Transceiver Control Register 0,
+ uint32_t reserved_110; // [110]
+ _va32 uint8_t USBFRMADJUST; // [114] Frame Adjust Register,
+
+ //----- Following is only found available in NXP MCX
+ uint32_t reserved_118[3]; // [118]
+ _va32 uint8_t KEEP_ALIVE_CTRL; // [124] Keep Alive Mode Control,
+ _va32 uint8_t KEEP_ALIVE_WKCTRL; // [128] Keep Alive Mode Wakeup Control,
+ _va32 uint8_t MISCCTRL; // [12C] Miscellaneous Control,
+ _va32 uint8_t STALL_IL_DIS; // [130] Peripheral Mode Stall Disable for Endpoints[ 7..0] IN
+ _va32 uint8_t STALL_IH_DIS; // [134] Peripheral Mode Stall Disable for Endpoints[15..8] IN
+ _va32 uint8_t STALL_OL_DIS; // [138] Peripheral Mode Stall Disable for Endpoints[ 7..0] OUT
+ _va32 uint8_t STALL_OH_DIS; // [13C] Peripheral Mode Stall Disable for Endpoints[15..8] OUT
+ _va32 uint8_t CLK_RECOVER_CTRL; // [140] USB Clock Recovery Control,
+ _va32 uint8_t CLK_RECOVER_IRC_EN; // [144] FIRC Oscillator Enable,
+ uint32_t reserved_148[3]; // [148]
+ _va32 uint8_t CLK_RECOVER_INT_EN; // [154] Clock Recovery Combined Interrupt Enable,
+ uint32_t reserved_158; // [158]
+ _va32 uint8_t CLK_RECOVER_INT_STATUS; // [15C] Clock Recovery Separated Interrupt Status,
+} ci_fs_regs_t;
+
+TU_VERIFY_STATIC(sizeof(ci_fs_regs_t) == 0x160, "Size is not correct");
+
+typedef struct
+{
+ uint32_t reg_base;
+ uint32_t irqnum;
+} ci_fs_controller_t;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/src/portable/chipidea/ci_fs/dcd_ci_fs.c b/src/portable/chipidea/ci_fs/dcd_ci_fs.c
new file mode 100644
index 000000000..37265df8b
--- /dev/null
+++ b/src/portable/chipidea/ci_fs/dcd_ci_fs.c
@@ -0,0 +1,555 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Koji Kitayama
+ *
+ * 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 CFG_TUD_ENABLED && defined(TUP_USBIP_CHIPIDEA_FS)
+
+#include "device/dcd.h"
+#include "ci_fs_type.h"
+
+#if defined(TUP_USBIP_CHIPIDEA_FS_KINETIS)
+ #include "ci_fs_kinetis.h"
+#elif defined(TUP_USBIP_CHIPIDEA_FS_MCX)
+ #include "ci_fs_mcx.h"
+#else
+ #error "MCU is not supported"
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+ TOK_PID_OUT = 0x1u,
+ TOK_PID_IN = 0x9u,
+ TOK_PID_SETUP = 0xDu,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t head;
+ struct {
+ union {
+ struct {
+ uint16_t : 2;
+ __IO uint16_t tok_pid : 4;
+ uint16_t data : 1;
+ __IO uint16_t own : 1;
+ uint16_t : 8;
+ };
+ struct {
+ uint16_t : 2;
+ uint16_t bdt_stall : 1;
+ uint16_t dts : 1;
+ uint16_t ninc : 1;
+ uint16_t keep : 1;
+ uint16_t : 10;
+ };
+ };
+ __IO uint16_t bc : 10;
+ uint16_t : 6;
+ };
+ };
+ uint8_t *addr;
+}buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+
+typedef struct TU_ATTR_PACKED
+{
+ union {
+ uint32_t state;
+ struct {
+ uint32_t max_packet_size :11;
+ uint32_t : 5;
+ uint32_t odd : 1;
+ uint32_t :15;
+ };
+ };
+ uint16_t length;
+ uint16_t remaining;
+}endpoint_state_t;
+
+TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" );
+
+typedef struct
+{
+ union {
+ /* [#EP][OUT,IN][EVEN,ODD] */
+ buffer_descriptor_t bdt[16][2][2];
+ uint16_t bda[512];
+ };
+ TU_ATTR_ALIGNED(4) union {
+ endpoint_state_t endpoint[16][2];
+ endpoint_state_t endpoint_unified[16 * 2];
+ };
+ uint8_t setup_packet[8];
+ uint8_t addr;
+}dcd_data_t;
+
+//--------------------------------------------------------------------+
+// 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;
+
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
+
+static void prepare_next_setup_packet(uint8_t rhport)
+{
+ const unsigned out_odd = _dcd.endpoint[0][0].odd;
+ const unsigned in_odd = _dcd.endpoint[0][1].odd;
+ TU_ASSERT(0 == _dcd.bdt[0][0][out_odd].own, );
+
+ _dcd.bdt[0][0][out_odd].data = 0;
+ _dcd.bdt[0][0][out_odd ^ 1].data = 1;
+ _dcd.bdt[0][1][in_odd].data = 1;
+ _dcd.bdt[0][1][in_odd ^ 1].data = 0;
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT),
+ _dcd.setup_packet, sizeof(_dcd.setup_packet));
+}
+
+static void process_stall(uint8_t rhport)
+{
+ for (int i = 0; i < 16; ++i) {
+ uint32_t const ep_ctl = CI_REG->EP[i].CTL;
+
+ if (ep_ctl & USB_ENDPT_EPSTALL_MASK) {
+ // prepare next setup if endpoint0
+ if ( i == 0 ) prepare_next_setup_packet(rhport);
+
+ // clear stall bit
+ CI_REG->EP[i].CTL = ep_ctl & ~USB_ENDPT_EPSTALL_MASK;
+ }
+ }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+ const unsigned s = CI_REG->STAT;
+ CI_REG->INT_STAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+
+ uint8_t const epnum = (s >> USB_STAT_ENDP_SHIFT);
+ uint8_t const dir = (s & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT;
+ unsigned const odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
+ buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
+ endpoint_state_t *ep = &_dcd.endpoint_unified[s >> 3];
+
+ /* fetch pid before discarded by the next steps */
+ const unsigned pid = bd->tok_pid;
+
+ /* reset values for a next transfer */
+ bd->bdt_stall = 0;
+ bd->dts = 1;
+ bd->ninc = 0;
+ bd->keep = 0;
+ /* update the odd variable to prepare for the next transfer */
+ ep->odd = odd ^ 1;
+ if (pid == TOK_PID_SETUP) {
+ dcd_event_setup_received(rhport, bd->addr, true);
+ CI_REG->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
+ return;
+ }
+
+ const unsigned bc = bd->bc;
+ const unsigned remaining = ep->remaining - bc;
+ if (remaining && bc == ep->max_packet_size) {
+ /* continue the transferring consecutive data */
+ ep->remaining = remaining;
+ const int next_remaining = remaining - ep->max_packet_size;
+ if (next_remaining > 0) {
+ /* prepare to the after next transfer */
+ bd->addr += ep->max_packet_size * 2;
+ bd->bc = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining;
+ __DSB();
+ bd->own = 1; /* the own bit must set after addr */
+ }
+ return;
+ }
+ const unsigned length = ep->length;
+ dcd_event_xfer_complete(rhport,
+ tu_edpt_addr(epnum, dir),
+ length - remaining, XFER_RESULT_SUCCESS, true);
+ if (0 == epnum && 0 == length) {
+ /* After completion a ZLP of control transfer,
+ * it prepares for the next steup transfer. */
+ if (_dcd.addr) {
+ /* When the transfer was the SetAddress,
+ * the device address should be updated here. */
+ CI_REG->ADDR = _dcd.addr;
+ _dcd.addr = 0;
+ }
+ prepare_next_setup_packet(rhport);
+ }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+ CI_REG->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+ CI_REG->CTL |= USB_CTL_ODDRST_MASK;
+ CI_REG->ADDR = 0;
+ CI_REG->INT_EN = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK | USB_INTEN_SLEEPEN_MASK |
+ USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
+
+ CI_REG->EP[0].CTL = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+ for (unsigned i = 1; i < 16; ++i) {
+ CI_REG->EP[i].CTL = 0;
+ }
+ buffer_descriptor_t *bd = _dcd.bdt[0][0];
+ for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+ const endpoint_state_t ep0 = {
+ .max_packet_size = CFG_TUD_ENDPOINT0_SIZE,
+ .odd = 0,
+ .length = 0,
+ .remaining = 0,
+ };
+ _dcd.endpoint[0][0] = ep0;
+ _dcd.endpoint[0][1] = ep0;
+ tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0]));
+ _dcd.addr = 0;
+ prepare_next_setup_packet(rhport);
+ CI_REG->CTL &= ~USB_CTL_ODDRST_MASK;
+ dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_bus_sleep(uint8_t rhport)
+{
+ // Enable resume & disable suspend interrupt
+ const unsigned inten = CI_REG->INT_EN;
+
+ CI_REG->INT_EN = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
+ CI_REG->USBTRC0 |= USB_USBTRC0_USBRESMEN_MASK;
+ CI_REG->USBCTRL |= USB_USBCTRL_SUSP_MASK;
+
+ dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+}
+
+static void process_bus_resume(uint8_t rhport)
+{
+ // Enable suspend & disable resume interrupt
+ const unsigned inten = CI_REG->INT_EN;
+
+ CI_REG->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; // will also clear USB_USBTRC0_USB_RESUME_INT_MASK
+ CI_REG->USBTRC0 &= ~USB_USBTRC0_USBRESMEN_MASK;
+ CI_REG->INT_EN = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+
+ dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+ (void) rhport;
+
+ CI_REG->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+ while (CI_REG->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+ tu_memclr(&_dcd, sizeof(_dcd));
+ CI_REG->USBTRC0 |= TU_BIT(6); /* software must set this bit to 1 */
+ CI_REG->BDT_PAGE1 = (uint8_t)((uintptr_t)_dcd.bdt >> 8);
+ CI_REG->BDT_PAGE2 = (uint8_t)((uintptr_t)_dcd.bdt >> 16);
+ CI_REG->BDT_PAGE3 = (uint8_t)((uintptr_t)_dcd.bdt >> 24);
+
+ CI_REG->INT_EN = USB_INTEN_USBRSTEN_MASK;
+
+ dcd_connect(rhport);
+ // NVIC_ClearPendingIRQ(USB0_IRQn);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+ _dcd.addr = dev_addr & 0x7F;
+ /* Response with status first before changing device address */
+ dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+
+void dcd_remote_wakeup(uint8_t rhport)
+{
+ (void) rhport;
+
+ CI_REG->CTL |= USB_CTL_RESUME_MASK;
+
+ unsigned cnt = SystemCoreClock / 1000;
+ while (cnt--) __NOP();
+
+ CI_REG->CTL &= ~USB_CTL_RESUME_MASK;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+ (void) rhport;
+ CI_REG->USBCTRL = 0;
+ CI_REG->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK;
+ CI_REG->CTL |= USB_CTL_USBENSOFEN_MASK;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+ (void) rhport;
+ CI_REG->CTL = 0;
+ CI_REG->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en)
+{
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+ (void) rhport;
+
+ const unsigned ep_addr = ep_desc->bEndpointAddress;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned xfer = ep_desc->bmAttributes.xfer;
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ const unsigned odd = ep->odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+
+ /* No support for control transfer */
+ TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
+
+ ep->max_packet_size = tu_edpt_packet_size(ep_desc);
+ unsigned val = USB_ENDPT_EPCTLDIS_MASK;
+ val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK: 0;
+ val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+ CI_REG->EP[epn].CTL |= val;
+
+ if (xfer != TUSB_XFER_ISOCHRONOUS) {
+ bd[odd].dts = 1;
+ bd[odd].data = 0;
+ bd[odd ^ 1].dts = 1;
+ bd[odd ^ 1].data = 1;
+ }
+
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport)
+{
+ dcd_int_disable(rhport);
+
+ for (unsigned i = 1; i < 16; ++i) {
+ CI_REG->EP[i].CTL = 0;
+ }
+
+ dcd_int_enable(rhport);
+
+ buffer_descriptor_t *bd = _dcd.bdt[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+ bd->head = 0;
+ }
+
+ endpoint_state_t *ep = &_dcd.endpoint[1][0];
+ for (unsigned i = 2; i < sizeof(_dcd.endpoint)/sizeof(*ep); ++i, ++ep) {
+ /* Clear except the odd */
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ }
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ const unsigned msk = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+
+ dcd_int_disable(rhport);
+
+ CI_REG->EP[epn].CTL &= ~msk;
+ ep->max_packet_size = 0;
+ ep->length = 0;
+ ep->remaining = 0;
+ bd[0].head = 0;
+ bd[1].head = 0;
+
+ dcd_int_enable(rhport);
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ endpoint_state_t *ep = &_dcd.endpoint[epn][dir];
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
+ TU_ASSERT(0 == bd->own);
+
+ dcd_int_disable(rhport);
+
+ ep->length = total_bytes;
+ ep->remaining = total_bytes;
+
+ const unsigned mps = ep->max_packet_size;
+ if (total_bytes > mps) {
+ buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1;
+ /* When total_bytes is greater than the max packet size,
+ * it prepares to the next transfer to avoid NAK in advance. */
+ next->bc = total_bytes >= 2 * mps ? mps: total_bytes - mps;
+ next->addr = buffer + mps;
+ next->own = 1;
+ }
+ bd->bc = total_bytes >= mps ? mps: total_bytes;
+ bd->addr = buffer;
+ __DSB();
+ bd->own = 1; /* This bit must be set last */
+
+ dcd_int_enable(rhport);
+
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ (void) rhport;
+ const unsigned epn = tu_edpt_number(ep_addr);
+
+ if (0 == epn) {
+ CI_REG->EP[epn].CTL |= USB_ENDPT_EPSTALL_MASK;
+ } else {
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][odd];
+ TU_ASSERT(0 == bd->own,);
+
+ dcd_int_disable(rhport);
+
+ bd->bdt_stall = 1;
+ __DSB();
+ bd->own = 1; /* This bit must be set last */
+
+ dcd_int_enable(rhport);
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+ const unsigned epn = tu_edpt_number(ep_addr);
+ TU_VERIFY(epn,);
+ const unsigned dir = tu_edpt_dir(ep_addr);
+ const unsigned odd = _dcd.endpoint[epn][dir].odd;
+ buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+ TU_VERIFY(bd[odd].own,);
+
+ dcd_int_disable(rhport);
+
+ bd[odd].own = 0;
+ __DSB();
+
+ // clear stall
+ bd[odd].bdt_stall = 0;
+
+ // Reset data toggle
+ bd[odd ].data = 0;
+ bd[odd ^ 1].data = 1;
+
+ // We already cleared this in ISR, but just clear it here to be safe
+ const uint32_t ep_ctl = CI_REG->EP[epn].CTL;
+ if (ep_ctl & USB_ENDPT_EPSTALL_MASK) {
+ CI_REG->EP[epn].CTL = ep_ctl & ~USB_ENDPT_EPSTALL_MASK;
+ }
+
+ dcd_int_enable(rhport);
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+ uint32_t is = CI_REG->INT_STAT;
+ uint32_t msk = CI_REG->INT_EN;
+
+ // clear non-enabled interrupts
+ CI_REG->INT_STAT = is & ~msk;
+ is &= msk;
+
+ if (is & USB_ISTAT_ERROR_MASK) {
+ /* TODO: */
+ uint32_t es = CI_REG->ERR_STAT;
+ CI_REG->ERR_STAT = es;
+ CI_REG->INT_STAT = is; /* discard any pending events */
+ }
+
+ if (is & USB_ISTAT_USBRST_MASK) {
+ CI_REG->INT_STAT = is; /* discard any pending events */
+ process_bus_reset(rhport);
+ }
+
+ if (is & USB_ISTAT_SLEEP_MASK) {
+ // TU_LOG2("Suspend: "); TU_LOG2_HEX(is);
+
+ // Note Host usually has extra delay after bus reset (without SOF), which could falsely
+ // detected as Sleep event. Though usbd has debouncing logic so we are good
+ CI_REG->INT_STAT = USB_ISTAT_SLEEP_MASK;
+ process_bus_sleep(rhport);
+ }
+
+#if 0 // ISTAT_RESUME never trigger, probably for host mode ?
+ if (is & USB_ISTAT_RESUME_MASK) {
+ // TU_LOG2("ISTAT Resume: "); TU_LOG2_HEX(is);
+ KHCI->ISTAT = USB_ISTAT_RESUME_MASK;
+ process_bus_resume(rhport);
+ }
+#endif
+
+ if (CI_REG->USBTRC0 & USB_USBTRC0_USB_RESUME_INT_MASK) {
+ // TU_LOG2("USBTRC0 Resume: "); TU_LOG2_HEX(is); TU_LOG2_HEX(KHCI->USBTRC0);
+ process_bus_resume(rhport);
+ }
+
+ if (is & USB_ISTAT_SOFTOK_MASK) {
+ CI_REG->INT_STAT = USB_ISTAT_SOFTOK_MASK;
+ dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ }
+
+ if (is & USB_ISTAT_STALL_MASK) {
+ CI_REG->INT_STAT = USB_ISTAT_STALL_MASK;
+ process_stall(rhport);
+ }
+
+ if (is & USB_ISTAT_TOKDNE_MASK) {
+ process_tokdne(rhport);
+ }
+}
+
+#endif
diff --git a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
index ceff893bd..c14f00431 100644
--- a/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
+++ b/src/portable/chipidea/ci_hs/ci_hs_imxrt.h
@@ -64,25 +64,28 @@ static const ci_hs_controller_t _ci_controller[] =
#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) {
+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* 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_clean(void const* addr, uint32_t data_size) {
+ const uintptr_t addr32 = (uintptr_t) addr;
+ if (imxrt_is_cache_mem(addr32)) {
+ SCB_CleanDCache_by_Addr((uint32_t *) addr32, (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_invalidate(void const* addr, uint32_t data_size) {
+ const uintptr_t addr32 = (uintptr_t) addr;
+ if (imxrt_is_cache_mem(addr32)) {
+ SCB_InvalidateDCache_by_Addr((void*) addr32, (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);
+TU_ATTR_ALWAYS_INLINE static inline void imxrt_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
+ const uintptr_t addr32 = (uintptr_t) addr;
+ if (imxrt_is_cache_mem(addr32)) {
+ SCB_CleanInvalidateDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size);
}
}
diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
index 850c82e43..f50550d33 100644
--- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -31,18 +31,18 @@
#include "device/dcd.h"
#include "ci_hs_type.h"
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
#include "ci_hs_imxrt.h"
- void dcd_dcache_clean(void* addr, uint32_t data_size) {
+ void dcd_dcache_clean(void const* addr, uint32_t data_size) {
imxrt_dcache_clean(addr, data_size);
}
- void dcd_dcache_invalidate(void* addr, uint32_t data_size) {
+ void dcd_dcache_invalidate(void const* addr, uint32_t data_size) {
imxrt_dcache_invalidate(addr, data_size);
}
- void dcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
+ void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
imxrt_dcache_clean_invalidate(addr, data_size);
}
@@ -58,15 +58,15 @@
#error "Unsupported MCUs"
#endif
- TU_ATTR_WEAK void dcd_dcache_clean(void* addr, uint32_t data_size) {
+ TU_ATTR_WEAK void dcd_dcache_clean(void const* addr, uint32_t data_size) {
(void) addr; (void) data_size;
}
- TU_ATTR_WEAK void dcd_dcache_invalidate(void* addr, uint32_t data_size) {
+ TU_ATTR_WEAK void dcd_dcache_invalidate(void const* addr, uint32_t data_size) {
(void) addr; (void) data_size;
}
- TU_ATTR_WEAK void dcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
+ TU_ATTR_WEAK void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
(void) addr; (void) data_size;
}
#endif
diff --git a/src/portable/chipidea/ci_hs/hcd_ci_hs.c b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
index 8c27abbf6..56167b8f6 100644
--- a/src/portable/chipidea/ci_hs/hcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/hcd_ci_hs.c
@@ -28,8 +28,7 @@
// Chipidea Highspeed USB IP implement EHCI for host functionality
-#if CFG_TUH_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT)
+#if CFG_TUH_ENABLED && defined(TUP_USBIP_EHCI)
//--------------------------------------------------------------------+
// INCLUDE
@@ -39,18 +38,18 @@
#include "portable/ehci/ehci_api.h"
#include "ci_hs_type.h"
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
+#if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
#include "ci_hs_imxrt.h"
- void hcd_dcache_clean(void* addr, uint32_t data_size) {
+ void hcd_dcache_clean(void const* addr, uint32_t data_size) {
imxrt_dcache_clean(addr, data_size);
}
- void hcd_dcache_invalidate(void* addr, uint32_t data_size) {
+ void hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
imxrt_dcache_invalidate(addr, data_size);
}
- void hcd_dcache_clean_invalidate(void* addr, uint32_t data_size) {
+ void hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
imxrt_dcache_clean_invalidate(addr, data_size);
}
diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c
index 2b25eee9d..38711e382 100644
--- a/src/portable/ehci/ehci.c
+++ b/src/portable/ehci/ehci.c
@@ -162,15 +162,15 @@ 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_WEAK void hcd_dcache_clean(void* addr, uint32_t data_size) {
+TU_ATTR_WEAK void hcd_dcache_clean(void const* addr, uint32_t data_size) {
(void) addr; (void) data_size;
}
-TU_ATTR_WEAK void hcd_dcache_invalidate(void* addr, uint32_t data_size) {
+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* addr, uint32_t data_size) {
+TU_ATTR_WEAK void hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
(void) addr; (void) data_size;
}
@@ -461,7 +461,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
qtd_init(td, setup_packet, 8);
td->pid = EHCI_PID_SETUP;
- hcd_dcache_clean((void *) setup_packet, 8);
+ hcd_dcache_clean(setup_packet, 8);
// attach TD to QHD -> start transferring
qhd_attach_qtd(qhd, td);
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index eee5686f4..acc967bb3 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -29,10 +29,24 @@
#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_NRF5X
#include <stdatomic.h>
+
+// Suppress warning caused by nrfx driver
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#pragma GCC diagnostic ignored "-Wcast-align"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
#include "nrf.h"
#include "nrf_clock.h"
#include "nrf_power.h"
#include "nrfx_usbd_errata.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
#include "device/dcd.h"
// TODO remove later
diff --git a/src/portable/nxp/transdimension/common_transdimension.h b/src/portable/nxp/transdimension/common_transdimension.h
deleted file mode 100644
index 95ae1903e..000000000
--- a/src/portable/nxp/transdimension/common_transdimension.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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 COMMON_TRANSDIMENSION_H_
-#define COMMON_TRANSDIMENSION_H_
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-// 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) endpoint’s linked list. This bit is set and cleared by software during the process of adding a new dTD
-// Interrupt Threshold bit 23:16
-};
-
-// PORTSC1
-#define PORTSC1_PORT_SPEED_POS 26
-
-enum {
- PORTSC1_CURRENT_CONNECT_STATUS = TU_BIT(0),
- PORTSC1_FORCE_PORT_RESUME = TU_BIT(6),
- PORTSC1_SUSPEND = TU_BIT(7),
- PORTSC1_FORCE_FULL_SPEED = TU_BIT(24),
- PORTSC1_PORT_SPEED = TU_BIT(26) | TU_BIT(27)
-};
-
-// OTGSC
-enum {
- OTGSC_VBUS_DISCHARGE = TU_BIT(0),
- OTGSC_VBUS_CHARGE = TU_BIT(1),
-// OTGSC_HWASSIST_AUTORESET = TU_BIT(2),
- OTGSC_OTG_TERMINATION = TU_BIT(3), ///< Must set to 1 when OTG go to device mode
- OTGSC_DATA_PULSING = TU_BIT(4),
- OTGSC_ID_PULLUP = TU_BIT(5),
-// OTGSC_HWASSIT_DATA_PULSE = TU_BIT(6),
-// OTGSC_HWASSIT_BDIS_ACONN = TU_BIT(7),
- OTGSC_ID = TU_BIT(8), ///< 0 = A device, 1 = B Device
- OTGSC_A_VBUS_VALID = TU_BIT(9),
- OTGSC_A_SESSION_VALID = TU_BIT(10),
- OTGSC_B_SESSION_VALID = TU_BIT(11),
- OTGSC_B_SESSION_END = TU_BIT(12),
- OTGSC_1MS_TOGGLE = TU_BIT(13),
- OTGSC_DATA_BUS_PULSING_STATUS = TU_BIT(14),
-};
-
-// USBMode
-enum {
- USBMODE_CM_DEVICE = 2,
- USBMODE_CM_HOST = 3,
-
- USBMODE_SLOM = TU_BIT(3),
- USBMODE_SDIS = TU_BIT(4),
-
- USBMODE_VBUS_POWER_SELECT = TU_BIT(5), // Need to be enabled for LPC18XX/43XX in host mode
-};
-
-// Device Registers
-typedef struct
-{
- //------------- ID + HW Parameter Registers-------------//
- __I uint32_t TU_RESERVED[64]; ///< For iMX RT10xx, but not used by LPC18XX/LPC43XX
-
- //------------- Capability Registers-------------//
- __I uint8_t CAPLENGTH; ///< Capability Registers Length
- __I uint8_t TU_RESERVED[1];
- __I uint16_t HCIVERSION; ///< Host Controller Interface Version
-
- __I uint32_t HCSPARAMS; ///< Host Controller Structural Parameters
- __I uint32_t HCCPARAMS; ///< Host Controller Capability Parameters
- __I uint32_t TU_RESERVED[5];
-
- __I uint16_t DCIVERSION; ///< Device Controller Interface Version
- __I uint8_t TU_RESERVED[2];
-
- __I uint32_t DCCPARAMS; ///< Device Controller Capability Parameters
- __I uint32_t TU_RESERVED[6];
-
- //------------- Operational Registers -------------//
- __IO uint32_t USBCMD; ///< USB Command Register
- __IO uint32_t USBSTS; ///< USB Status Register
- __IO uint32_t USBINTR; ///< Interrupt Enable Register
- __IO uint32_t FRINDEX; ///< USB Frame Index
- __I uint32_t TU_RESERVED;
- __IO uint32_t DEVICEADDR; ///< Device Address
- __IO uint32_t ENDPTLISTADDR; ///< Endpoint List Address
- __I uint32_t TU_RESERVED;
- __IO uint32_t BURSTSIZE; ///< Programmable Burst Size
- __IO uint32_t TXFILLTUNING; ///< TX FIFO Fill Tuning
- uint32_t TU_RESERVED[4];
- __IO uint32_t ENDPTNAK; ///< Endpoint NAK
- __IO uint32_t ENDPTNAKEN; ///< Endpoint NAK Enable
- __I uint32_t TU_RESERVED;
- __IO uint32_t PORTSC1; ///< Port Status & Control
- __I uint32_t TU_RESERVED[7];
- __IO uint32_t OTGSC; ///< On-The-Go Status & control
- __IO uint32_t USBMODE; ///< USB Device Mode
- __IO uint32_t ENDPTSETUPSTAT; ///< Endpoint Setup Status
- __IO uint32_t ENDPTPRIME; ///< Endpoint Prime
- __IO uint32_t ENDPTFLUSH; ///< Endpoint Flush
- __I uint32_t ENDPTSTAT; ///< Endpoint Status
- __IO uint32_t ENDPTCOMPLETE; ///< Endpoint Complete
- __IO uint32_t ENDPTCTRL[8]; ///< Endpoint Control 0 - 7
-} dcd_registers_t, hcd_registers_t;
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif /* COMMON_TRANSDIMENSION_H_ */
diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c
deleted file mode 100644
index 983d7cfcf..000000000
--- a/src/portable/nxp/transdimension/dcd_transdimension.c
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 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 CFG_TUD_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT)
-
-#warning "transdimenion is renamed to chipidea (portable/chipidea/ci_hs) to match other opensource naming convention such as linux. This file will be removed in the future, please update your makefile accordingly"
-
-//--------------------------------------------------------------------+
-// INCLUDE
-//--------------------------------------------------------------------+
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
- #include "fsl_device_registers.h"
- #define INCLUDE_FSL_DEVICE_REGISTERS
-#else
- // LPCOpen for 18xx & 43xx
- #include "chip.h"
-#endif
-
-#include "common/tusb_common.h"
-#include "device/dcd.h"
-#include "common_transdimension.h"
-
-#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
-
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
-//--------------------------------------------------------------------+
-
-// ENDPTCTRL
-enum {
- ENDPTCTRL_STALL = TU_BIT(0),
- ENDPTCTRL_TOGGLE_INHIBIT = TU_BIT(5), // used for test only
- ENDPTCTRL_TOGGLE_RESET = TU_BIT(6),
- ENDPTCTRL_ENABLE = TU_BIT(7)
-};
-
-enum {
- ENDPTCTRL_TYPE_POS = 2, // Endpoint type is 2-bit field
-};
-
-// USBSTS, USBINTR
-enum {
- INTR_USB = TU_BIT(0),
- INTR_ERROR = TU_BIT(1),
- INTR_PORT_CHANGE = TU_BIT(2),
- INTR_RESET = TU_BIT(6),
- INTR_SOF = TU_BIT(7),
- INTR_SUSPEND = TU_BIT(8),
- INTR_NAK = TU_BIT(16)
-};
-
-// Queue Transfer Descriptor
-typedef struct
-{
- // Word 0: Next QTD Pointer
- uint32_t next; ///< Next link pointer This field contains the physical memory address of the next dTD to be processed
-
- // Word 1: qTQ Token
- uint32_t : 3 ;
- volatile uint32_t xact_err : 1 ;
- uint32_t : 1 ;
- volatile uint32_t buffer_err : 1 ;
- volatile uint32_t halted : 1 ;
- volatile uint32_t active : 1 ;
- uint32_t : 2 ;
- uint32_t iso_mult_override : 2 ; ///< This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO.
- uint32_t : 3 ;
- uint32_t int_on_complete : 1 ;
- volatile uint32_t total_bytes : 15 ;
- uint32_t : 1 ;
-
- // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page
- uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous
-
- //--------------------------------------------------------------------+
- // TD is 32 bytes aligned but occupies only 28 bytes
- // Therefore there are 4 bytes padding that we can use.
- //--------------------------------------------------------------------+
- uint16_t expected_bytes;
- uint8_t reserved[2];
-} dcd_qtd_t;
-
-TU_VERIFY_STATIC( sizeof(dcd_qtd_t) == 32, "size is not correct");
-
-// Queue Head
-typedef struct
-{
- // Word 0: Capabilities and Characteristics
- uint32_t : 15 ; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed.
- uint32_t int_on_setup : 1 ; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received.
- uint32_t max_packet_size : 11 ; ///< Endpoint's wMaxPacketSize
- uint32_t : 2 ;
- uint32_t zero_length_termination : 1 ; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length.
- uint32_t iso_mult : 2 ; ///<
-
- // Word 1: Current qTD Pointer
- volatile uint32_t qtd_addr;
-
- // Word 2-9: Transfer Overlay
- volatile dcd_qtd_t qtd_overlay;
-
- // Word 10-11: Setup request (control OUT only)
- volatile tusb_control_request_t setup_request;
-
- //--------------------------------------------------------------------+
- // QHD is 64 bytes aligned but occupies only 48 bytes
- // Therefore there are 16 bytes padding that we can use.
- //--------------------------------------------------------------------+
- tu_fifo_t * ff;
- uint8_t reserved[12];
-} dcd_qhd_t;
-
-TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
-
-//--------------------------------------------------------------------+
-// Variables
-//--------------------------------------------------------------------+
-
-typedef struct
-{
- dcd_registers_t* regs; // registers
- const IRQn_Type irqnum; // IRQ number
- const uint8_t ep_count; // Max bi-directional Endpoints
-}dcd_controller_t;
-
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
- static const dcd_controller_t _dcd_controller[] =
- {
- // RT1010 and RT1020 only has 1 USB controller
- #if FSL_FEATURE_SOC_USBHS_COUNT == 1
- { .regs = (dcd_registers_t*) USB_BASE , .irqnum = USB_OTG1_IRQn, .ep_count = 8 }
- #else
- { .regs = (dcd_registers_t*) USB1_BASE, .irqnum = USB_OTG1_IRQn, .ep_count = 8 },
- { .regs = (dcd_registers_t*) USB2_BASE, .irqnum = USB_OTG2_IRQn, .ep_count = 8 }
- #endif
- };
-
-#else
- static const dcd_controller_t _dcd_controller[] =
- {
- { .regs = (dcd_registers_t*) LPC_USB0_BASE, .irqnum = USB0_IRQn, .ep_count = 6 },
- { .regs = (dcd_registers_t*) LPC_USB1_BASE, .irqnum = USB1_IRQn, .ep_count = 4 }
- };
-#endif
-
-#define QTD_NEXT_INVALID 0x01
-
-typedef struct {
- // Must be at 2K alignment
- // Each endpoint with direction (IN/OUT) occupies a queue head
- // for portability, TinyUSB only queue 1 TD for each Qhd
- dcd_qhd_t qhd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64);
- dcd_qtd_t qtd[TUP_DCD_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32);
-}dcd_data_t;
-
-CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048)
-static dcd_data_t _dcd_data;
-
-//--------------------------------------------------------------------+
-// Controller API
-//--------------------------------------------------------------------+
-
-/// follows LPC43xx User Manual 23.10.3
-static void bus_reset(uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
-
- // The reset value for all endpoint types is the control endpoint. If one endpoint
- // direction is enabled and the paired endpoint of opposite direction is disabled, then the
- // endpoint type of the unused direction must be changed from the control type to any other
- // type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
- // for the data PID tracking on the active endpoint.
- for( uint8_t i=1; i < _dcd_controller[rhport].ep_count; i++)
- {
- dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
- }
-
- //------------- Clear All Registers -------------//
- dcd_reg->ENDPTNAK = dcd_reg->ENDPTNAK;
- dcd_reg->ENDPTNAKEN = 0;
- dcd_reg->USBSTS = dcd_reg->USBSTS;
- dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
- dcd_reg->ENDPTCOMPLETE = dcd_reg->ENDPTCOMPLETE;
-
- while (dcd_reg->ENDPTPRIME) {}
- dcd_reg->ENDPTFLUSH = 0xFFFFFFFF;
- while (dcd_reg->ENDPTFLUSH) {}
-
- // read reset bit in portsc
-
- //------------- Queue Head & Queue TD -------------//
- tu_memclr(&_dcd_data, sizeof(dcd_data_t));
-
- //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------//
- _dcd_data.qhd[0][0].zero_length_termination = _dcd_data.qhd[0][1].zero_length_termination = 1;
- _dcd_data.qhd[0][0].max_packet_size = _dcd_data.qhd[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
- _dcd_data.qhd[0][0].qtd_overlay.next = _dcd_data.qhd[0][1].qtd_overlay.next = QTD_NEXT_INVALID;
-
- _dcd_data.qhd[0][0].int_on_setup = 1; // OUT only
-}
-
-void dcd_init(uint8_t rhport)
-{
- tu_memclr(&_dcd_data, sizeof(dcd_data_t));
-
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
-
- // 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;
- 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_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
-}
-
-void dcd_int_enable(uint8_t rhport)
-{
- NVIC_EnableIRQ(_dcd_controller[rhport].irqnum);
-}
-
-void dcd_int_disable(uint8_t rhport)
-{
- NVIC_DisableIRQ(_dcd_controller[rhport].irqnum);
-}
-
-void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
-{
- // Response with status first before changing device address
- dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
-
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->DEVICEADDR = (dev_addr << 25) | TU_BIT(24);
-}
-
-void dcd_remote_wakeup(uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->PORTSC1 |= PORTSC1_FORCE_PORT_RESUME;
-}
-
-void dcd_connect(uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->USBCMD |= USBCMD_RUN_STOP;
-}
-
-void dcd_disconnect(uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->USBCMD &= ~USBCMD_RUN_STOP;
-}
-
-void dcd_sof_enable(uint8_t rhport, bool en)
-{
- (void) rhport;
- (void) en;
-
- // TODO implement later
-}
-
-//--------------------------------------------------------------------+
-// HELPER
-//--------------------------------------------------------------------+
-
-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);
-
- tu_memclr(p_qtd, sizeof(dcd_qtd_t));
-
- p_qtd->next = QTD_NEXT_INVALID;
- p_qtd->active = 1;
- p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
- p_qtd->int_on_complete = true;
-
- if (data_ptr != NULL)
- {
- p_qtd->buffer[0] = (uint32_t) data_ptr;
-
- uint32_t const bufend = p_qtd->buffer[0] + total_bytes;
- for(uint8_t i=1; i<5; i++)
- {
- uint32_t const next_page = tu_align4k( p_qtd->buffer[i-1] ) + 4096;
- if ( bufend <= next_page ) break;
-
- p_qtd->buffer[i] = next_page;
-
- // TODO page[1] FRAME_N for ISO transfer
- }
- }
-}
-
-//--------------------------------------------------------------------+
-// DCD Endpoint Port
-//--------------------------------------------------------------------+
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
-
- // flush to abort any primed buffer
- dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
-}
-
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- // data toggle also need to be reset
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << ( dir ? 16 : 0 );
- dcd_reg->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << ( dir ? 16 : 0));
-}
-
-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);
-
- // Must not exceed max endpoint number
- TU_ASSERT( epnum < _dcd_controller[rhport].ep_count );
-
- //------------- Prepare Queue Head -------------//
- dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
- tu_memclr(p_qhd, sizeof(dcd_qhd_t));
-
- p_qhd->zero_length_termination = 1;
- p_qhd->max_packet_size = tu_edpt_packet_size(p_endpoint_desc);
- if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
- {
- p_qhd->iso_mult = 1;
- }
-
- p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
-
- CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
-
- // Enable EP Control
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
-
- uint32_t const epctrl = (p_endpoint_desc->bmAttributes.xfer << ENDPTCTRL_TYPE_POS) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET;
-
- if ( dir == TUSB_DIR_OUT )
- {
- dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0xFFFF0000u) | epctrl;
- }else
- {
- dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0x0000FFFFu) | (epctrl << 16);
- }
-
- return true;
-}
-
-void dcd_edpt_close_all (uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
-
- // Disable all non-control endpoints
- for( uint8_t epnum=1; epnum < _dcd_controller[rhport].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;
-
- dcd_reg->ENDPTFLUSH = TU_BIT(epnum) | TU_BIT(epnum+16);
- dcd_reg->ENDPTCTRL[epnum] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS));
- }
-}
-
-void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
-
- _dcd_data.qhd[epnum][dir].qtd_overlay.halted = 1;
-
- // Flush EP
- uint32_t const flush_mask = TU_BIT(epnum + (dir ? 16 : 0));
- dcd_reg->ENDPTFLUSH = flush_mask;
- while(dcd_reg->ENDPTFLUSH & flush_mask);
-
- // Clear EP enable
- dcd_reg->ENDPTCTRL[epnum] &=~(ENDPTCTRL_ENABLE << (dir ? 16 : 0));
-}
-
-static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
- dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
-
- p_qhd->qtd_overlay.halted = false; // clear any previous error
- 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));
-
- if ( epnum == 0 )
- {
- // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
- // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
- while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
- }
-
- // start transfer
- dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0));
-}
-
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
- dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
-
- // Prepare qtd
- qtd_init(p_qtd, buffer, total_bytes);
-
- // Start qhd transfer
- p_qhd->ff = NULL;
- qhd_start_xfer(rhport, epnum, dir);
-
- return true;
-}
-
-// fifo has to be aligned to 4k boundary
-bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
- dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
-
- tu_fifo_buffer_info_t fifo_info;
-
- if (dir)
- {
- tu_fifo_get_read_info(ff, &fifo_info);
- } else
- {
- tu_fifo_get_write_info(ff, &fifo_info);
- }
-
- if ( fifo_info.len_lin >= total_bytes )
- {
- // Linear length is enough for this transfer
- qtd_init(p_qtd, fifo_info.ptr_lin, total_bytes);
- }
- else
- {
- // linear part is not enough
-
- // prepare TD up to linear length
- qtd_init(p_qtd, fifo_info.ptr_lin, fifo_info.len_lin);
-
- if ( !tu_offset4k((uint32_t) fifo_info.ptr_wrap) && !tu_offset4k(tu_fifo_depth(ff)) )
- {
- // If buffer is aligned to 4K & buffer size is multiple of 4K
- // We can make use of buffer page array to also combine the linear + wrapped length
- p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
-
- for(uint8_t i = 1, page = 0; i < 5; i++)
- {
- // pick up buffer array where linear ends
- if (p_qtd->buffer[i] == 0)
- {
- p_qtd->buffer[i] = (uint32_t) fifo_info.ptr_wrap + 4096 * page;
- page++;
- }
- }
-
- CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
- }
- else
- {
- // TODO we may need to carry the wrapped length after the linear part complete
- // for now only transfer up to linear part
- }
- }
-
- // Start qhd transfer
- p_qhd->ff = ff;
- qhd_start_xfer(rhport, epnum, dir);
-
- return true;
-}
-
-//--------------------------------------------------------------------+
-// ISR
-//--------------------------------------------------------------------+
-
-static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir)
-{
- dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
- dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
-
- uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
- ( p_qtd->xact_err || p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS;
-
- if ( result != XFER_RESULT_SUCCESS )
- {
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
- // flush to abort error buffer
- dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
- }
-
- uint16_t const xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes;
-
- if (p_qhd->ff)
- {
- if (dir == TUSB_DIR_IN)
- {
- tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes);
- } else
- {
- tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes);
- }
- }
-
- // only number of bytes in the IOC qtd
- dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true);
-}
-
-void dcd_int_handler(uint8_t rhport)
-{
- dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
-
- uint32_t const int_enable = dcd_reg->USBINTR;
- uint32_t const int_status = dcd_reg->USBSTS & int_enable;
- dcd_reg->USBSTS = int_status; // Acknowledge handled interrupt
-
- // disabled interrupt sources
- if (int_status == 0) return;
-
- // Set if the port controller enters the full or high-speed operational state.
- // either from Bus Reset or Suspended state
- if (int_status & INTR_PORT_CHANGE)
- {
- // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1);
-
- // Reset interrupt is not enabled, we manually check if Port Change is due
- // to connection / disconnection
- if ( dcd_reg->USBSTS & INTR_RESET )
- {
- dcd_reg->USBSTS = INTR_RESET;
-
- if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS)
- {
- uint32_t const speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS;
- bus_reset(rhport);
- dcd_event_bus_reset(rhport, (tusb_speed_t) speed, true);
- }else
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
- }
- }
- else
- {
- // Triggered by resuming from suspended state
- if ( !(dcd_reg->PORTSC1 & PORTSC1_SUSPEND) )
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
- }
- }
- }
-
- if (int_status & INTR_SUSPEND)
- {
- // TU_LOG2("Suspend %08lx\r\n", dcd_reg->PORTSC1);
-
- if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND)
- {
- // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
- // Skip suspend event if we are not addressed
- if ((dcd_reg->DEVICEADDR >> 25) & 0x0f)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
- }
- }
-
- 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));
-
- uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE;
- dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge
-
- if (dcd_reg->ENDPTSETUPSTAT)
- {
- //------------- Set up Received -------------//
- // 23.10.10.2 Operational model for setup transfers
- dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;
-
- dcd_event_setup_received(rhport, (uint8_t*)(uintptr_t) &_dcd_data.qhd[0][0].setup_request, true);
- }
-
- // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set
- // nothing to do, we will submit xfer as error to usbd
- // if (int_status & INTR_ERROR) { }
-
- if ( edpt_complete )
- {
- for(uint8_t epnum = 0; epnum < TUP_DCD_ENDPOINT_MAX; epnum++)
- {
- if ( tu_bit_test(edpt_complete, epnum) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT);
- if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN);
- }
- }
- }
-
- if (int_status & INTR_SOF)
- {
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
- }
-}
-
-#endif
diff --git a/src/portable/nxp/transdimension/hcd_transdimension.c b/src/portable/nxp/transdimension/hcd_transdimension.c
deleted file mode 100644
index 0b3e9e4ef..000000000
--- a/src/portable/nxp/transdimension/hcd_transdimension.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 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"
-
-// NXP Trans-Dimension USB IP implement EHCI for host functionality
-
-#if CFG_TUH_ENABLED && \
- (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT)
-
-#warning "transdimenion is renamed to chipidea (portable/chipidea/ci_hs) to match other opensource naming convention such as linux. This file will be removed in the future, please update your makefile accordingly"
-
-//--------------------------------------------------------------------+
-// INCLUDE
-//--------------------------------------------------------------------+
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
- #include "fsl_device_registers.h"
-#else
- // LPCOpen for 18xx & 43xx
- #include "chip.h"
-#endif
-
-#include "common/tusb_common.h"
-#include "common_transdimension.h"
-#include "portable/ehci/ehci_api.h"
-
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
-//--------------------------------------------------------------------+
-
-// TODO can be merged with dcd_controller_t
-typedef struct
-{
- uint32_t regs_base; // registers base
- const IRQn_Type irqnum; // IRQ number
-}hcd_controller_t;
-
-#if CFG_TUSB_MCU == OPT_MCU_MIMXRT
- static const hcd_controller_t _hcd_controller[] =
- {
- // RT1010 and RT1020 only has 1 USB controller
- #if FSL_FEATURE_SOC_USBHS_COUNT == 1
- { .regs_base = USB_BASE , .irqnum = USB_OTG1_IRQn }
- #else
- { .regs_base = USB1_BASE, .irqnum = USB_OTG1_IRQn },
- { .regs_base = USB2_BASE, .irqnum = USB_OTG2_IRQn }
- #endif
- };
-
-#else
- static const hcd_controller_t _hcd_controller[] =
- {
- { .regs_base = LPC_USB0_BASE, .irqnum = USB0_IRQn },
- { .regs_base = LPC_USB1_BASE, .irqnum = USB1_IRQn }
- };
-#endif
-
-//--------------------------------------------------------------------+
-// Controller API
-//--------------------------------------------------------------------+
-
-bool hcd_init(uint8_t rhport)
-{
- hcd_registers_t* hcd_reg = (hcd_registers_t*) _hcd_controller[rhport].regs_base;
-
- // Reset controller
- hcd_reg->USBCMD |= USBCMD_RESET;
- while( hcd_reg->USBCMD & USBCMD_RESET ) {}
-
- // Set mode to device, must be set immediately after reset
-#if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX
- // LPC18XX/43XX need to set VBUS Power Select to HIGH
- // RHPORT1 is fullspeed only (need external PHY for Highspeed)
- hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
- if (rhport == 1) hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
-#else
- hcd_reg->USBMODE = USBMODE_CM_HOST;
-#endif
-
- // FIXME force full speed, still have issue with Highspeed enumeration
- hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
-
- return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD);
-}
-
-void hcd_int_enable(uint8_t rhport)
-{
- NVIC_EnableIRQ(_hcd_controller[rhport].irqnum);
-}
-
-void hcd_int_disable(uint8_t rhport)
-{
- NVIC_DisableIRQ(_hcd_controller[rhport].irqnum);
-}
-
-#endif
diff --git a/src/portable/renesas/rusb2/rusb2_type.h b/src/portable/renesas/rusb2/rusb2_type.h
index 7a2898366..90ba4f012 100644
--- a/src/portable/renesas/rusb2/rusb2_type.h
+++ b/src/portable/renesas/rusb2/rusb2_type.h
@@ -41,11 +41,11 @@ extern "C" {
TU_ATTR_PACKED_BEGIN
TU_ATTR_BIT_FIELD_ORDER_BEGIN
-typedef struct TU_ATTR_PACKED {
+typedef struct {
union {
volatile uint16_t E; /* (@ 0x00000000) Pipe Transaction Counter Enable Register */
- struct {
+ struct TU_ATTR_PACKED {
uint16_t : 8;
volatile uint16_t TRCLR : 1; /* [8..8] Transaction Counter Clear */
volatile uint16_t TRENB : 1; /* [9..9] Transaction Counter Enable */
@@ -56,18 +56,18 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t N; /* (@ 0x00000002) Pipe Transaction Counter Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t TRNCNT : 16; /* [15..0] Transaction Counter */
} N_b;
};
} RUSB2_PIPE_TR_t; /* Size = 4 (0x4) */
/* LINK_REG Structure */
-typedef struct TU_ATTR_PACKED {
+typedef struct {
union {
volatile uint16_t SYSCFG; /* (@ 0x00000000) System Configuration Control Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t USBE : 1; /* [0..0] USB Operation Enable */
uint16_t : 2;
volatile uint16_t DMRPU : 1; /* [3..3] D- Line Resistor Control */
@@ -85,7 +85,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t BUSWAIT; /* (@ 0x00000002) CPU Bus Wait Register */
- 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;
} BUSWAIT_b;
@@ -94,7 +94,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile const uint16_t SYSSTS0; /* (@ 0x00000004) System Configuration Status Register 0 */
- struct {
+ struct TU_ATTR_PACKED {
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;
@@ -109,7 +109,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile const uint16_t PLLSTA; /* (@ 0x00000006) PLL Status Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t PLLLOCK : 1; /* [0..0] PLL Lock Flag */
uint16_t : 15;
} PLLSTA_b;
@@ -118,7 +118,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t DVSTCTR0; /* (@ 0x00000008) Device State Control Register 0 */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t RHST : 3; /* [2..0] USB Bus Reset Status */
uint16_t : 1;
volatile uint16_t UACT : 1; /* [4..4] USB Bus Enable */
@@ -137,7 +137,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t TESTMODE; /* (@ 0x0000000C) USB Test Mode Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t UTST : 4; /* [3..0] Test Mode */
uint16_t : 12;
} TESTMODE_b;
@@ -148,7 +148,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint32_t CFIFO; /* (@ 0x00000014) CFIFO Port Register */
- struct {
+ struct TU_ATTR_PACKED {
union {
volatile uint16_t CFIFOL; /* (@ 0x00000014) CFIFO Port Register L */
volatile uint8_t CFIFOLL; /* (@ 0x00000014) CFIFO Port Register LL */
@@ -157,7 +157,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t CFIFOH; /* (@ 0x00000016) CFIFO Port Register H */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint8_t RESERVED3;
volatile uint8_t CFIFOHH; /* (@ 0x00000017) CFIFO Port Register HH */
};
@@ -168,7 +168,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint32_t D0FIFO; /* (@ 0x00000018) D0FIFO Port Register */
- struct {
+ struct TU_ATTR_PACKED {
union {
volatile uint16_t D0FIFOL; /* (@ 0x00000018) D0FIFO Port Register L */
volatile uint8_t D0FIFOLL; /* (@ 0x00000018) D0FIFO Port Register LL */
@@ -177,7 +177,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t D0FIFOH; /* (@ 0x0000001A) D0FIFO Port Register H */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint8_t RESERVED4;
volatile uint8_t D0FIFOHH; /* (@ 0x0000001B) D0FIFO Port Register HH */
};
@@ -188,7 +188,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint32_t D1FIFO; /* (@ 0x0000001C) D1FIFO Port Register */
- struct {
+ struct TU_ATTR_PACKED {
union {
volatile uint16_t D1FIFOL; /* (@ 0x0000001C) D1FIFO Port Register L */
volatile uint8_t D1FIFOLL; /* (@ 0x0000001C) D1FIFO Port Register LL */
@@ -197,7 +197,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t D1FIFOH; /* (@ 0x0000001E) D1FIFO Port Register H */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint8_t RESERVED5;
volatile uint8_t D1FIFOHH; /* (@ 0x0000001F) D1FIFO Port Register HH */
};
@@ -208,7 +208,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t CFIFOSEL; /* (@ 0x00000020) CFIFO Port Select Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t CURPIPE : 4; /* [3..0] CFIFO Port Access Pipe Specification */
uint16_t : 1;
volatile uint16_t ISEL : 1; /* [5..5] CFIFO Port Access Direction When DCP is Selected */
@@ -225,12 +225,12 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t CFIFOCTR; /* (@ 0x00000022) CFIFO Port Control Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t DTLN : 12; /* [11..0] Receive Data LengthIndicates the length of the receive data. */
uint16_t : 1;
volatile const uint16_t FRDY : 1; /* [13..13] FIFO Port Ready */
- volatile uint16_t BCLR : 1; /* [14..14] CPU Buffer ClearNote: Only 0 can be read. */
- volatile uint16_t BVAL : 1; /* [15..15] Buffer Memory Valid Flag */
+ volatile uint16_t BCLR : 1; /* [14..14] CPU Buffer ClearNote: Only 0 can be read. */
+ volatile uint16_t BVAL : 1; /* [15..15] Buffer Memory Valid Flag */
} CFIFOCTR_b;
};
volatile const uint32_t RESERVED6;
@@ -238,7 +238,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t D0FIFOSEL; /* (@ 0x00000028) D0FIFO Port Select Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t CURPIPE : 4; /* [3..0] FIFO Port Access Pipe Specification */
uint16_t : 4;
volatile uint16_t BIGEND : 1; /* [8..8] FIFO Port Endian Control */
@@ -254,19 +254,19 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t D0FIFOCTR; /* (@ 0x0000002A) D0FIFO Port Control Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t DTLN : 12; /* [11..0] Receive Data LengthIndicates the length of the receive data. */
uint16_t : 1;
volatile const uint16_t FRDY : 1; /* [13..13] FIFO Port Ready */
- volatile uint16_t BCLR : 1; /* [14..14] CPU Buffer ClearNote: Only 0 can be read. */
- volatile uint16_t BVAL : 1; /* [15..15] Buffer Memory Valid Flag */
+ volatile uint16_t BCLR : 1; /* [14..14] CPU Buffer ClearNote: Only 0 can be read. */
+ volatile uint16_t BVAL : 1; /* [15..15] Buffer Memory Valid Flag */
} D0FIFOCTR_b;
};
union {
volatile uint16_t D1FIFOSEL; /* (@ 0x0000002C) D1FIFO Port Select Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t CURPIPE : 4; /* [3..0] FIFO Port Access Pipe Specification */
uint16_t : 4;
volatile uint16_t BIGEND : 1; /* [8..8] FIFO Port Endian Control */
@@ -282,7 +282,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t D1FIFOCTR; /* (@ 0x0000002E) D1FIFO Port Control Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t DTLN : 12; /* [11..0] Receive Data LengthIndicates the length of the receive data. */
uint16_t : 1;
volatile const uint16_t FRDY : 1; /* [13..13] FIFO Port Ready */
@@ -294,7 +294,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t INTENB0; /* (@ 0x00000030) Interrupt Enable Register 0 */
- struct {
+ struct TU_ATTR_PACKED {
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 */
@@ -310,7 +310,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t INTENB1; /* (@ 0x00000032) Interrupt Enable Register 1 */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PDDETINTE0 : 1; /* [0..0] PDDETINT0 Detection Interrupt Enable */
uint16_t : 3;
volatile uint16_t SACKE : 1; /* [4..4] Setup Transaction Normal Response Interrupt Enable */
@@ -329,7 +329,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t BRDYENB; /* (@ 0x00000036) BRDY Interrupt Enable Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PIPE0BRDYE : 1; /* [0..0] BRDY Interrupt Enable for PIPE */
volatile uint16_t PIPE1BRDYE : 1; /* [1..1] BRDY Interrupt Enable for PIPE */
volatile uint16_t PIPE2BRDYE : 1; /* [2..2] BRDY Interrupt Enable for PIPE */
@@ -347,7 +347,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t NRDYENB; /* (@ 0x00000038) NRDY Interrupt Enable Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PIPE0NRDYE : 1; /* [0..0] NRDY Interrupt Enable for PIPE */
volatile uint16_t PIPE1NRDYE : 1; /* [1..1] NRDY Interrupt Enable for PIPE */
volatile uint16_t PIPE2NRDYE : 1; /* [2..2] NRDY Interrupt Enable for PIPE */
@@ -365,7 +365,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t BEMPENB; /* (@ 0x0000003A) BEMP Interrupt Enable Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PIPE0BEMPE : 1; /* [0..0] BEMP Interrupt Enable for PIPE */
volatile uint16_t PIPE1BEMPE : 1; /* [1..1] BEMP Interrupt Enable for PIPE */
volatile uint16_t PIPE2BEMPE : 1; /* [2..2] BEMP Interrupt Enable for PIPE */
@@ -383,7 +383,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t SOFCFG; /* (@ 0x0000003C) SOF Output Configuration Register */
- struct {
+ struct TU_ATTR_PACKED {
uint16_t : 4;
volatile const uint16_t EDGESTS : 1; /* [4..4] Edge Interrupt Output Status Monitor */
volatile uint16_t INTL : 1; /* [5..5] Interrupt Output Sense Select */
@@ -397,7 +397,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t PHYSET; /* (@ 0x0000003E) PHY Setting Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t DIRPD : 1; /* [0..0] Power-Down Control */
volatile uint16_t PLLRESET : 1; /* [1..1] PLL Reset Control */
uint16_t : 1;
@@ -415,7 +415,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t INTSTS0; /* (@ 0x00000040) Interrupt Status Register 0 */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t CTSQ : 3; /* [2..0] Control Transfer Stage */
volatile uint16_t VALID : 1; /* [3..3] USB Request Reception */
volatile const uint16_t DVSQ : 3; /* [6..4] Device State */
@@ -434,7 +434,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t INTSTS1; /* (@ 0x00000042) Interrupt Status Register 1 */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PDDETINT0 : 1; /* [0..0] PDDET0 Detection Interrupt Status */
uint16_t : 3;
volatile uint16_t SACK : 1; /* [4..4] Setup Transaction Normal Response Interrupt Status */
@@ -456,7 +456,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t BRDYSTS; /* (@ 0x00000046) BRDY Interrupt Status Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PIPE0BRDY : 1; /* [0..0] BRDY Interrupt Status for PIPE */
volatile uint16_t PIPE1BRDY : 1; /* [1..1] BRDY Interrupt Status for PIPE */
volatile uint16_t PIPE2BRDY : 1; /* [2..2] BRDY Interrupt Status for PIPE */
@@ -474,7 +474,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t NRDYSTS; /* (@ 0x00000048) NRDY Interrupt Status Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PIPE0NRDY : 1; /* [0..0] NRDY Interrupt Status for PIPE */
volatile uint16_t PIPE1NRDY : 1; /* [1..1] NRDY Interrupt Status for PIPE */
volatile uint16_t PIPE2NRDY : 1; /* [2..2] NRDY Interrupt Status for PIPE */
@@ -492,7 +492,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t BEMPSTS; /* (@ 0x0000004A) BEMP Interrupt Status Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PIPE0BEMP : 1; /* [0..0] BEMP Interrupt Status for PIPE */
volatile uint16_t PIPE1BEMP : 1; /* [1..1] BEMP Interrupt Status for PIPE */
volatile uint16_t PIPE2BEMP : 1; /* [2..2] BEMP Interrupt Status for PIPE */
@@ -510,7 +510,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t FRMNUM; /* (@ 0x0000004C) Frame Number Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t FRNM : 11; /* [10..0] Frame NumberLatest frame number */
uint16_t : 3;
volatile uint16_t CRCE : 1; /* [14..14] Receive Data Error */
@@ -521,7 +521,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t UFRMNUM; /* (@ 0x0000004E) uFrame Number Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t UFRNM : 3; /* [2..0] MicroframeIndicate the microframe number. */
uint16_t : 12;
volatile uint16_t DVCHG : 1; /* [15..15] Device State Change */
@@ -531,7 +531,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t USBADDR; /* (@ 0x00000050) USB Address Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t USBADDR : 7; /* [6..0] USB Address In device controller mode */
uint16_t : 1;
volatile uint16_t STSRECOV0 : 3; /* [10..8] Status Recovery */
@@ -543,7 +543,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t USBREQ; /* (@ 0x00000054) USB Request Type Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t BMREQUESTTYPE : 8; /* [7..0] Request TypeThese bits store the USB request bmRequestType value. */
volatile uint16_t BREQUEST : 8; /* [15..8] RequestThese bits store the USB request bRequest value. */
} USBREQ_b;
@@ -552,7 +552,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t USBVAL; /* (@ 0x00000056) USB Request Value Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t WVALUE : 16; /* [15..0] ValueThese bits store the USB request Value value. */
} USBVAL_b;
};
@@ -560,7 +560,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t USBINDX; /* (@ 0x00000058) USB Request Index Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t WINDEX : 16; /* [15..0] IndexThese bits store the USB request wIndex value. */
} USBINDX_b;
};
@@ -568,7 +568,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t USBLENG; /* (@ 0x0000005A) USB Request Length Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t WLENGTH : 16; /* [15..0] LengthThese bits store the USB request wLength value. */
} USBLENG_b;
};
@@ -576,7 +576,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t DCPCFG; /* (@ 0x0000005C) DCP Configuration Register */
- struct {
+ struct TU_ATTR_PACKED {
uint16_t : 4;
volatile uint16_t DIR : 1; /* [4..4] Transfer Direction */
uint16_t : 2;
@@ -589,7 +589,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t DCPMAXP; /* (@ 0x0000005E) DCP Maximum Packet Size Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t MXPS : 7; /* [6..0] Maximum Packet Size */
uint16_t : 5;
volatile uint16_t DEVSEL : 4; /* [15..12] Device Select */
@@ -599,7 +599,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t DCPCTR; /* (@ 0x00000060) DCP Control Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PID : 2; /* [1..0] Response PID */
volatile uint16_t CCPL : 1; /* [2..2] Control Transfer End Enable */
uint16_t : 2;
@@ -619,7 +619,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t PIPESEL; /* (@ 0x00000064) Pipe Window Select Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PIPESEL : 4; /* [3..0] Pipe Window Select */
uint16_t : 12;
} PIPESEL_b;
@@ -629,7 +629,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t PIPECFG; /* (@ 0x00000068) Pipe Configuration Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t EPNUM : 4; /* [3..0] Endpoint Number */
volatile uint16_t DIR : 1; /* [4..4] Transfer Direction */
uint16_t : 2;
@@ -646,7 +646,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t PIPEMAXP; /* (@ 0x0000006C) Pipe Maximum Packet Size Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t MXPS : 9; /* [8..0] Maximum Packet Size */
uint16_t : 3;
volatile uint16_t DEVSEL : 4; /* [15..12] Device Select */
@@ -656,7 +656,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t PIPEPERI; /* (@ 0x0000006E) Pipe Cycle Control Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t IITV : 3; /* [2..0] Interval Error Detection Interval */
uint16_t : 9;
volatile uint16_t IFIS : 1; /* [12..12] Isochronous IN Buffer Flush */
@@ -667,7 +667,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t PIPE_CTR[9]; /* (@ 0x00000070) Pipe [0..8] Control Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t PID : 2; /* [1..0] Response PID */
uint16_t : 3;
volatile const uint16_t PBUSY : 1; /* [5..5] Pipe Busy */
@@ -691,7 +691,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t USBBCCTRL0; /* (@ 0x000000B0) BC Control Register 0 */
- 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
@@ -713,7 +713,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t UCKSEL; /* (@ 0x000000C4) USB Clock Selection Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t UCKSELC : 1; /* [0..0] USB Clock Selection */
uint16_t : 15;
} UCKSEL_b;
@@ -724,7 +724,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t USBMC; /* (@ 0x000000CC) USB Module Control Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t VDDUSBE : 1; /* [0..0] USB Reference Power Supply Circuit On/Off Control */
uint16_t : 6;
volatile uint16_t VDCEN : 1; /* [7..7] USB Regulator On/Off Control */
@@ -736,7 +736,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t DEVADD[10]; /* (@ 0x000000D0) Device Address Configuration Register */
- struct {
+ struct TU_ATTR_PACKED {
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 */
@@ -749,7 +749,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint32_t PHYSLEW; /* (@ 0x000000F0) PHY Cross Point Adjustment Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint32_t SLEWR00 : 1; /* [0..0] Receiver Cross Point Adjustment 00 */
volatile uint32_t SLEWR01 : 1; /* [1..1] Receiver Cross Point Adjustment 01 */
volatile uint32_t SLEWF00 : 1; /* [2..2] Receiver Cross Point Adjustment 00 */
@@ -762,7 +762,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t LPCTRL; /* (@ 0x00000100) Low Power Control Register */
- struct {
+ struct TU_ATTR_PACKED {
uint16_t : 7;
volatile uint16_t HWUPM : 1; /* [7..7] Resume Return Mode Setting */
uint16_t : 8;
@@ -772,7 +772,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t LPSTS; /* (@ 0x00000102) Low Power Status Register */
- struct {
+ struct TU_ATTR_PACKED {
uint16_t : 14;
volatile uint16_t SUSPENDM : 1; /* [14..14] UTMI SuspendM Control */
uint16_t : 1;
@@ -783,7 +783,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t BCCTRL; /* (@ 0x00000140) Battery Charging Control Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t IDPSRCE : 1; /* [0..0] IDPSRC Control */
volatile uint16_t IDMSINKE : 1; /* [1..1] IDMSINK Control */
volatile uint16_t VDPSRCE : 1; /* [2..2] VDPSRC Control */
@@ -801,7 +801,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t PL1CTRL1; /* (@ 0x00000144) Function L1 Control Register 1 */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t L1RESPEN : 1; /* [0..0] L1 Response Enable */
volatile uint16_t L1RESPMD : 2; /* [2..1] L1 Response Mode */
volatile uint16_t L1NEGOMD : 1; /* [3..3] L1 Response Negotiation Control. */
@@ -816,7 +816,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t PL1CTRL2; /* (@ 0x00000146) Function L1 Control Register 2 */
- struct {
+ struct TU_ATTR_PACKED {
uint16_t : 8;
volatile uint16_t HIRDMON : 4; /* [11..8] HIRD Value Monitor */
volatile uint16_t RWEMON : 1; /* [12..12] RWE Value Monitor */
@@ -827,8 +827,8 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t HL1CTRL1; /* (@ 0x00000148) Host L1 Control Register 1 */
- struct {
- volatile uint16_t L1REQ : 1; /* [0..0] L1 Transition Request */
+ 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;
} HL1CTRL1_b;
@@ -837,7 +837,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t HL1CTRL2; /* (@ 0x0000014A) Host L1 Control Register 2 */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint16_t L1ADDR : 4; /* [3..0] LPM Token DeviceAddress */
uint16_t : 4;
volatile uint16_t HIRD : 4; /* [11..8] LPM Token HIRD */
@@ -851,7 +851,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile const uint32_t DPUSR0R; /* (@ 0x00000160) Deep Standby USB Transceiver Control/Pin Monitor Register */
- struct {
+ struct TU_ATTR_PACKED {
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. */
@@ -864,7 +864,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint32_t DPUSR1R; /* (@ 0x00000164) Deep Standby USB Suspend/Resume Interrupt Register */
- struct {
+ struct TU_ATTR_PACKED {
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 */
@@ -882,7 +882,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t DPUSR2R; /* (@ 0x00000168) Deep Standby USB Suspend/Resume Interrupt Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile const uint16_t DPINT : 1; /* [0..0] Indication of Return from DP Interrupt Source */
volatile const uint16_t DMINT : 1; /* [1..1] Indication of Return from DM Interrupt Source */
uint16_t : 2;
@@ -898,8 +898,8 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint16_t DPUSRCR; /* (@ 0x0000016A) Deep Standby USB Suspend/Resume Command Register */
- struct {
- volatile uint16_t FIXPHY : 1; /* [0..0] USB Transceiver Control Fix */
+ 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;
} DPUSRCR_b;
@@ -910,7 +910,7 @@ typedef struct TU_ATTR_PACKED {
volatile uint32_t
DPUSR0R_FS; /* (@ 0x00000400) Deep Software Standby USB Transceiver Control/Pin Monitor Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint32_t SRPC0 : 1; /* [0..0] USB Single End Receiver Control */
volatile uint32_t RPUE0 : 1; /* [1..1] DP Pull-Up Resistor Control */
uint32_t : 1;
@@ -931,7 +931,7 @@ typedef struct TU_ATTR_PACKED {
union {
volatile uint32_t DPUSR1R_FS; /* (@ 0x00000404) Deep Software Standby USB Suspend/Resume Interrupt Register */
- struct {
+ struct TU_ATTR_PACKED {
volatile uint32_t DPINTE0 : 1; /* [0..0] USB DP Interrupt Enable/Clear */
volatile uint32_t DMINTE0 : 1; /* [1..1] USB DM Interrupt Enable/Clear */
uint32_t : 2;
@@ -1599,6 +1599,7 @@ 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(offsetof(RUSB2_REG_t, SYSCFG ) == 0x00000000, "incorrect offset");
TU_VERIFY_STATIC(offsetof(RUSB2_REG_t, BUSWAIT ) == 0x00000002, "incorrect offset");
diff --git a/src/portable/st/typec/typec_stm32.c b/src/portable/st/typec/typec_stm32.c
new file mode 100644
index 000000000..bf8b660f0
--- /dev/null
+++ b/src/portable/st/typec/typec_stm32.c
@@ -0,0 +1,372 @@
+/*
+ * 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.
+ */
+
+#include "tusb_option.h"
+#include "typec/tcd.h"
+
+#if CFG_TUC_ENABLED && defined(TUP_USBIP_TYPEC_STM32)
+
+#include "common/tusb_common.h"
+
+#if CFG_TUSB_MCU == OPT_MCU_STM32G4
+ #include "stm32g4xx.h"
+ #include "stm32g4xx_ll_dma.h" // for UCPD REQID
+#else
+ #error "Unsupported STM32 family"
+#endif
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+enum {
+ IMR_ATTACHED = UCPD_IMR_TXMSGDISCIE | UCPD_IMR_TXMSGSENTIE | UCPD_IMR_TXMSGABTIE | UCPD_IMR_TXUNDIE |
+ UCPD_IMR_RXHRSTDETIE | UCPD_IMR_RXOVRIE | UCPD_IMR_RXMSGENDIE | UCPD_IMR_RXORDDETIE |
+ UCPD_IMR_HRSTDISCIE | UCPD_IMR_HRSTSENTIE | UCPD_IMR_FRSEVTIE
+};
+
+#define PHY_SYNC1 0x18u
+#define PHY_SYNC2 0x11u
+#define PHY_SYNC3 0x06u
+#define PHY_RST1 0x07u
+#define PHY_RST2 0x19u
+#define PHY_EOP 0x0Du
+
+#define PHY_ORDERED_SET_SOP (PHY_SYNC1 | (PHY_SYNC1<<5u) | (PHY_SYNC1<<10u) | (PHY_SYNC2<<15u)) // SOP Ordered set coding
+#define PHY_ORDERED_SET_SOP_P (PHY_SYNC1 | (PHY_SYNC1<<5u) | (PHY_SYNC3<<10u) | (PHY_SYNC3<<15u)) // SOP' Ordered set coding
+#define PHY_ORDERED_SET_SOP_PP (PHY_SYNC1 | (PHY_SYNC3<<5u) | (PHY_SYNC1<<10u) | (PHY_SYNC3<<15u)) // SOP'' Ordered set coding
+#define PHY_ORDERED_SET_HARD_RESET (PHY_RST1 | (PHY_RST1<<5u) | (PHY_RST1<<10u) | (PHY_RST2<<15u )) // Hard Reset Ordered set coding
+#define PHY_ORDERED_SET_CABLE_RESET (PHY_RST1 | (PHY_SYNC1<<5u) | (PHY_RST1<<10u) | (PHY_SYNC3<<15u)) // Cable Reset Ordered set coding
+#define PHY_ORDERED_SET_SOP_P_DEBUG (PHY_SYNC1 | (PHY_RST2<<5u) | (PHY_RST2<<10u) | (PHY_SYNC3<<15u)) // SOP' Debug Ordered set coding
+#define PHY_ORDERED_SET_SOP_PP_DEBUG (PHY_SYNC1 | (PHY_RST2<<5u) | (PHY_SYNC3<<10u) | (PHY_SYNC2<<15u)) // SOP'' Debug Ordered set coding
+
+
+static uint8_t const* _rx_buf;
+static uint8_t const* _tx_pending_buf;
+static uint16_t _tx_pending_bytes;
+static uint16_t _tx_xferring_bytes;
+
+static pd_header_t _good_crc = {
+ .msg_type = PD_CTRL_GOOD_CRC,
+ .data_role = 0, // UFP
+ .specs_rev = PD_REV_20,
+ .power_role = 0, // Sink
+ .msg_id = 0,
+ .n_data_obj = 0,
+ .extended = 0
+};
+
+// address of DMA channel rx, tx for each port
+#define CFG_TUC_STM32_DMA { { DMA1_Channel1_BASE, DMA1_Channel2_BASE } }
+
+//--------------------------------------------------------------------+
+// DMA
+//--------------------------------------------------------------------+
+
+static const uint32_t _dma_addr_arr[TUP_TYPEC_RHPORTS_NUM][2] = CFG_TUC_STM32_DMA;
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t dma_get_addr(uint8_t rhport, bool is_rx) {
+ return _dma_addr_arr[rhport][is_rx ? 0 : 1];
+}
+
+static void dma_init(uint8_t rhport, bool is_rx) {
+ uint32_t dma_addr = dma_get_addr(rhport, is_rx);
+ DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_addr;
+ uint32_t req_id;
+
+ if (is_rx) {
+ // Peripheral -> Memory, Memory inc, 8-bit, High priority
+ dma_ch->CCR = DMA_CCR_MINC | DMA_CCR_PL_1;
+ dma_ch->CPAR = (uint32_t) &UCPD1->RXDR;
+
+ req_id = LL_DMAMUX_REQ_UCPD1_RX;
+ } else {
+ // Memory -> Peripheral, Memory inc, 8-bit, High priority
+ dma_ch->CCR = DMA_CCR_MINC | DMA_CCR_PL_1 | DMA_CCR_DIR;
+ dma_ch->CPAR = (uint32_t) &UCPD1->TXDR;
+
+ req_id = LL_DMAMUX_REQ_UCPD1_TX;
+ }
+
+ // find and set up mux channel TODO support mcu with multiple DMAMUXs
+ enum {
+ CH_DIFF = DMA1_Channel2_BASE - DMA1_Channel1_BASE
+ };
+ uint32_t mux_ch_num;
+
+ #ifdef DMA2_BASE
+ if (dma_addr > DMA2_BASE) {
+ mux_ch_num = 8 * ((dma_addr - DMA2_Channel1_BASE) / CH_DIFF);
+ } else
+ #endif
+ {
+ mux_ch_num = (dma_addr - DMA1_Channel1_BASE) / CH_DIFF;
+ }
+
+ DMAMUX_Channel_TypeDef* mux_ch = DMAMUX1_Channel0 + mux_ch_num;
+
+ uint32_t mux_ccr = mux_ch->CCR & ~(DMAMUX_CxCR_DMAREQ_ID);
+ mux_ccr |= req_id;
+ mux_ch->CCR = mux_ccr;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dma_start(uint8_t rhport, bool is_rx, void const* buf, uint16_t len) {
+ DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_get_addr(rhport, is_rx);
+
+ dma_ch->CMAR = (uint32_t) buf;
+ dma_ch->CNDTR = len;
+ dma_ch->CCR |= DMA_CCR_EN;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dma_stop(uint8_t rhport, bool is_rx) {
+ DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_get_addr(rhport, is_rx);
+ dma_ch->CCR &= ~DMA_CCR_EN;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool dma_enabled(uint8_t rhport, bool is_rx) {
+ DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_get_addr(rhport, is_rx);
+ return dma_ch->CCR & DMA_CCR_EN;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dma_tx_start(uint8_t rhport, void const* buf, uint16_t len) {
+ UCPD1->TX_ORDSET = PHY_ORDERED_SET_SOP;
+ UCPD1->TX_PAYSZ = len;
+ dma_start(rhport, false, buf, len);
+ UCPD1->CR |= UCPD_CR_TXSEND;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void dma_tx_stop(uint8_t rhport) {
+ dma_stop(rhport, false);
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+bool tcd_init(uint8_t rhport, uint32_t port_type) {
+ (void) rhport;
+
+ // Init DMA for RX, TX
+ dma_init(rhport, true);
+ dma_init(rhport, false);
+
+ // Initialization phase: CFG1, detect all SOPs
+ UCPD1->CFG1 = (0x0d << UCPD_CFG1_HBITCLKDIV_Pos) | (0x10 << UCPD_CFG1_IFRGAP_Pos) | (0x07 << UCPD_CFG1_TRANSWIN_Pos) |
+ (0x01 << UCPD_CFG1_PSC_UCPDCLK_Pos) | (0x1f << UCPD_CFG1_RXORDSETEN_Pos);
+ UCPD1->CFG1 |= UCPD_CFG1_UCPDEN;
+
+ // General programming sequence (with UCPD configured then enabled)
+ if (port_type == TUSB_TYPEC_PORT_SNK) {
+ // Set analog mode enable both CC Phy
+ UCPD1->CR = (0x01 << UCPD_CR_ANAMODE_Pos) | (UCPD_CR_CCENABLE_0 | UCPD_CR_CCENABLE_1);
+
+ // Read Voltage State on CC1 & CC2 fore initial state
+ uint32_t v_cc[2];
+ (void) v_cc;
+ v_cc[0] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC1_Pos) & 0x03;
+ v_cc[1] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC2_Pos) & 0x03;
+ TU_LOG1("Initial VState CC1 = %lu, CC2 = %lu\r\n", v_cc[0], v_cc[1]);
+
+ // Enable CC1 & CC2 Interrupt
+ UCPD1->IMR = UCPD_IMR_TYPECEVT1IE | UCPD_IMR_TYPECEVT2IE;
+ }
+
+ // Disable dead battery in PWR's CR3
+ PWR->CR3 |= PWR_CR3_UCPD_DBDIS;
+
+ return true;
+}
+
+// Enable interrupt
+void tcd_int_enable (uint8_t rhport) {
+ (void) rhport;
+ NVIC_EnableIRQ(UCPD1_IRQn);
+}
+
+// Disable interrupt
+void tcd_int_disable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_DisableIRQ(UCPD1_IRQn);
+}
+
+bool tcd_msg_receive(uint8_t rhport, uint8_t* buffer, uint16_t total_bytes) {
+ _rx_buf = buffer;
+ dma_start(rhport, true, buffer, total_bytes);
+ return true;
+}
+
+bool tcd_msg_send(uint8_t rhport, uint8_t const* buffer, uint16_t total_bytes) {
+ (void) rhport;
+
+ if (dma_enabled(rhport, false)) {
+ // DMA is busy, probably sending GoodCRC, save as pending TX
+ _tx_pending_buf = buffer;
+ _tx_pending_bytes = total_bytes;
+ }else {
+ // DMA is free, start sending
+ _tx_pending_buf = NULL;
+ _tx_pending_bytes = 0;
+
+ _tx_xferring_bytes = total_bytes;
+ dma_tx_start(rhport, buffer, total_bytes);
+ }
+
+ return true;
+}
+
+void tcd_int_handler(uint8_t rhport) {
+ (void) rhport;
+
+ uint32_t sr = UCPD1->SR;
+ sr &= UCPD1->IMR;
+
+ if (sr & (UCPD_SR_TYPECEVT1 | UCPD_SR_TYPECEVT2)) {
+ uint32_t v_cc[2];
+ v_cc[0] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC1_Pos) & 0x03;
+ v_cc[1] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC2_Pos) & 0x03;
+
+ TU_LOG3("VState CC1 = %lu, CC2 = %lu\n", v_cc[0], v_cc[1]);
+
+ uint32_t cr = UCPD1->CR;
+
+ // TODO only support SNK for now, required highest voltage for now
+ // Enable PHY on active CC and disable Rd on other CC
+ // FIXME somehow CC2 is vstate is not correct, always 1 even not attached.
+ // on DPOW1 board, it is connected to PA10 (USBPD_DBCC2), we probably miss something.
+ if ((sr & UCPD_SR_TYPECEVT1) && (v_cc[0] == 3)) {
+ TU_LOG3("Attach CC1\n");
+ cr &= ~(UCPD_CR_PHYCCSEL | UCPD_CR_CCENABLE);
+ cr |= UCPD_CR_PHYRXEN | UCPD_CR_CCENABLE_0;
+ } else if ((sr & UCPD_SR_TYPECEVT2) && (v_cc[1] == 3)) {
+ TU_LOG3("Attach CC2\n");
+ cr &= ~UCPD_CR_CCENABLE;
+ cr |= (UCPD_CR_PHYCCSEL | UCPD_CR_PHYRXEN | UCPD_CR_CCENABLE_1);
+ } else {
+ TU_LOG3("Detach\n");
+ cr &= ~UCPD_CR_PHYRXEN;
+ cr |= UCPD_CR_CCENABLE_0 | UCPD_CR_CCENABLE_1;
+ }
+
+ if (cr & UCPD_CR_PHYRXEN) {
+ // Attached
+ UCPD1->IMR |= IMR_ATTACHED;
+ UCPD1->CFG1 |= UCPD_CFG1_RXDMAEN | UCPD_CFG1_TXDMAEN;
+ }else {
+ // Detached
+ UCPD1->CFG1 &= ~(UCPD_CFG1_RXDMAEN | UCPD_CFG1_TXDMAEN);
+ UCPD1->IMR &= ~IMR_ATTACHED;
+ }
+
+ // notify stack
+ tcd_event_cc_changed(rhport, v_cc[0], v_cc[1], true);
+
+ UCPD1->CR = cr;
+
+ // ack
+ UCPD1->ICR = UCPD_ICR_TYPECEVT1CF | UCPD_ICR_TYPECEVT2CF;
+ }
+
+ //------------- RX -------------//
+ if (sr & UCPD_SR_RXORDDET) {
+ // SOP: Start of Packet.
+ TU_LOG3("SOP\n");
+ // UCPD1->RX_ORDSET & UCPD_RX_ORDSET_RXORDSET_Msk;
+
+ // ack
+ UCPD1->ICR = UCPD_ICR_RXORDDETCF;
+ }
+
+ // Received full message
+ if (sr & UCPD_SR_RXMSGEND) {
+ TU_LOG3("RX MSG END\n");
+
+ // stop TX
+ dma_stop(rhport, true);
+
+ uint8_t result;
+
+ if (!(sr & UCPD_SR_RXERR)) {
+ // response with good crc
+ // TODO move this to usbc stack
+ if (_rx_buf) {
+ _good_crc.msg_id = ((pd_header_t const *) _rx_buf)->msg_id;
+ dma_tx_start(rhport, &_good_crc, 2);
+ }
+
+ result = XFER_RESULT_SUCCESS;
+ }else {
+ // CRC failed
+ result = XFER_RESULT_FAILED;
+ }
+
+ // notify stack
+ tcd_event_rx_complete(rhport, UCPD1->RX_PAYSZ, result, true);
+
+ // ack
+ UCPD1->ICR = UCPD_ICR_RXMSGENDCF;
+ }
+
+ if (sr & UCPD_SR_RXOVR) {
+ TU_LOG3("RXOVR\n");
+ // ack
+ UCPD1->ICR = UCPD_ICR_RXOVRCF;
+ }
+
+ //------------- TX -------------//
+ // All tx events: complete and error
+ if (sr & (UCPD_SR_TXMSGSENT | (UCPD_SR_TXMSGDISC | UCPD_SR_TXMSGABT | UCPD_SR_TXUND))) {
+ // force TX stop
+ dma_tx_stop(rhport);
+
+ uint16_t const xferred_bytes = _tx_xferring_bytes - UCPD1->TX_PAYSZ;
+ uint8_t result;
+
+ if ( sr & UCPD_SR_TXMSGSENT ) {
+ TU_LOG3("TX MSG SENT\n");
+ result = XFER_RESULT_SUCCESS;
+ // ack
+ UCPD1->ICR = UCPD_ICR_TXMSGSENTCF;
+ }else {
+ TU_LOG3("TX Error\n");
+ result = XFER_RESULT_FAILED;
+ // ack
+ UCPD1->ICR = UCPD_SR_TXMSGDISC | UCPD_SR_TXMSGABT | UCPD_SR_TXUND;
+ }
+
+ // start pending TX if any
+ if (_tx_pending_buf && _tx_pending_bytes ) {
+ // Start the pending TX
+ dma_tx_start(rhport, _tx_pending_buf, _tx_pending_bytes);
+
+ // clear pending
+ _tx_pending_buf = NULL;
+ _tx_pending_bytes = 0;
+ }
+
+ // notify stack
+ tcd_event_tx_complete(rhport, xferred_bytes, result, true);
+ }
+}
+
+#endif
diff --git a/src/tusb.h b/src/tusb.h
index b776d7d01..37a521fa8 100644
--- a/src/tusb.h
+++ b/src/tusb.h
@@ -40,6 +40,11 @@
#include "class/hid/hid.h"
+//------------- TypeC -------------//
+#if CFG_TUC_ENABLED
+ #include "typec/usbc.h"
+#endif
+
//------------- HOST -------------//
#if CFG_TUH_ENABLED
#include "host/usbh.h"
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 948c9edf3..43e67cf64 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -97,9 +97,9 @@
#define OPT_MCU_VALENTYUSB_EPTRI 600 ///< Fomu eptri config
// NXP iMX RT
-#define OPT_MCU_MIMXRT 700 ///< NXP iMX RT Series
-#define OPT_MCU_MIMXRT10XX OPT_MCU_MIMXRT ///< RT10xx
-#define OPT_MCU_MIMXRT11XX OPT_MCU_MIMXRT ///< RT11xx
+#define OPT_MCU_MIMXRT1XXX 700 ///< NXP iMX RT1xxx Series
+#define OPT_MCU_MIMXRT10XX OPT_MCU_MIMXRT1XXX ///< RT10xx
+#define OPT_MCU_MIMXRT11XX OPT_MCU_MIMXRT1XXX ///< RT11xx
// Nuvoton
#define OPT_MCU_NUC121 800
@@ -483,6 +483,16 @@
#endif
+//--------------------------------------------------------------------+
+// TypeC Options (Default)
+//--------------------------------------------------------------------+
+
+#ifndef CFG_TUC_ENABLED
+#define CFG_TUC_ENABLED 0
+
+#define tuc_int_handler(_p)
+#endif
+
//------------------------------------------------------------------
// Configuration Validation
//------------------------------------------------------------------
diff --git a/src/typec/pd_types.h b/src/typec/pd_types.h
new file mode 100644
index 000000000..1b2968f65
--- /dev/null
+++ b/src/typec/pd_types.h
@@ -0,0 +1,237 @@
+/*
+ * 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.
+ */
+
+#ifndef _TUSB_PD_TYPES_H_
+#define _TUSB_PD_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "common/tusb_compiler.h"
+
+// Start of all packed definitions for compiler without per-type packed
+TU_ATTR_PACKED_BEGIN
+TU_ATTR_BIT_FIELD_ORDER_BEGIN
+
+//--------------------------------------------------------------------+
+// TYPE-C
+//--------------------------------------------------------------------+
+
+typedef enum {
+ TUSB_TYPEC_PORT_SRC,
+ TUSB_TYPEC_PORT_SNK,
+ TUSB_TYPEC_PORT_DRP
+} tusb_typec_port_type_t;
+
+enum {
+ PD_CTRL_RESERVED = 0, // 0b00000: 0
+ PD_CTRL_GOOD_CRC, // 0b00001: 1
+ PD_CTRL_GO_TO_MIN, // 0b00010: 2
+ PD_CTRL_ACCEPT, // 0b00011: 3
+ PD_CTRL_REJECT, // 0b00100: 4
+ PD_CTRL_PING, // 0b00101: 5
+ PD_CTRL_PS_READY, // 0b00110: 6
+ PD_CTRL_GET_SOURCE_CAP, // 0b00111: 7
+ PD_CTRL_GET_SINK_CAP, // 0b01000: 8
+ PD_CTRL_DR_SWAP, // 0b01001: 9
+ PD_CTRL_PR_SWAP, // 0b01010: 10
+ PD_CTRL_VCONN_SWAP, // 0b01011: 11
+ PD_CTRL_WAIT, // 0b01100: 12
+ PD_CTRL_SOFT_RESET, // 0b01101: 13
+ PD_CTRL_DATA_RESET, // 0b01110: 14
+ PD_CTRL_DATA_RESET_COMPLETE, // 0b01111: 15
+ PD_CTRL_NOT_SUPPORTED, // 0b10000: 16
+ PD_CTRL_GET_SOURCE_CAP_EXTENDED, // 0b10001: 17
+ PD_CTRL_GET_STATUS, // 0b10010: 18
+ PD_CTRL_FR_SWAP, // 0b10011: 19
+ PD_CTRL_GET_PPS_STATUS, // 0b10100: 20
+ PD_CTRL_GET_COUNTRY_CODES, // 0b10101: 21
+ PD_CTRL_GET_SINK_CAP_EXTENDED, // 0b10110: 22
+ PD_CTRL_GET_SOURCE_INFO, // 0b10111: 23
+ PD_CTRL_REVISION, // 0b11000: 24
+};
+
+enum {
+ PD_DATA_RESERVED = 0, // 0b00000: 0
+ PD_DATA_SOURCE_CAP, // 0b00001: 1
+ PD_DATA_REQUEST, // 0b00010: 2
+ PD_DATA_BIST, // 0b00011: 3
+ PD_DATA_SINK_CAP, // 0b00100: 4
+ PD_DATA_BATTERY_STATUS, // 0b00101: 5
+ PD_DATA_ALERT, // 0b00110: 6
+ PD_DATA_GET_COUNTRY_INFO, // 0b00111: 7
+ PD_DATA_ENTER_USB, // 0b01000: 8
+ PD_DATA_EPR_REQUEST, // 0b01001: 9
+ PD_DATA_EPR_MODE, // 0b01010: 10
+ PD_DATA_SRC_INFO, // 0b01011: 11
+ PD_DATA_REVISION, // 0b01100: 12
+ PD_DATA_RESERVED_13, // 0b01101: 13
+ PD_DATA_RESERVED_14, // 0b01110: 14
+ PD_DATA_VENDOR_DEFINED, // 0b01111: 15
+};
+
+enum {
+ PD_REV_10 = 0x0,
+ PD_REV_20 = 0x1,
+ PD_REV_30 = 0x2,
+};
+
+enum {
+ PD_DATA_ROLE_UFP = 0x0,
+ PD_DATA_ROLE_DFP = 0x1,
+};
+
+enum {
+ PD_POWER_ROLE_SINK = 0x0,
+ PD_POWER_ROLE_SOURCE = 0x1,
+};
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t msg_type : 5; // [0:4]
+ uint16_t data_role : 1; // [5] SOP only: 0 UFP, 1 DFP
+ uint16_t specs_rev : 2; // [6:7]
+ uint16_t power_role : 1; // [8] SOP only: 0 Sink, 1 Source
+ uint16_t msg_id : 3; // [9:11]
+ uint16_t n_data_obj : 3; // [12:14]
+ uint16_t extended : 1; // [15]
+} pd_header_t;
+TU_VERIFY_STATIC(sizeof(pd_header_t) == 2, "size is not correct");
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t data_size : 9; // [0:8]
+ uint16_t reserved : 1; // [9]
+ uint16_t request_chunk : 1; // [10]
+ uint16_t chunk_number : 4; // [11:14]
+ uint16_t chunked : 1; // [15]
+} pd_header_extended_t;
+TU_VERIFY_STATIC(sizeof(pd_header_extended_t) == 2, "size is not correct");
+
+//--------------------------------------------------------------------+
+// Source Capability
+//--------------------------------------------------------------------+
+
+// All table references are from USBPD Specification rev3.1 version 1.8
+enum {
+ PD_PDO_TYPE_FIXED = 0, // Vmin = Vmax
+ PD_PDO_TYPE_BATTERY,
+ PD_PDO_TYPE_VARIABLE, // non-battery
+ PD_PDO_TYPE_APDO, // Augmented Power Data Object
+};
+
+// Fixed Power Data Object (PDO) table 6-9
+typedef struct TU_ATTR_PACKED {
+ uint32_t current_max_10ma : 10; // [9..0] Max current in 10mA unit
+ uint32_t voltage_50mv : 10; // [19..10] Voltage in 50mV unit
+ uint32_t current_peak : 2; // [21..20] Peak current
+ uint32_t reserved : 1; // [22] Reserved
+ uint32_t epr_mode_capable : 1; // [23] epr_mode_capable
+ uint32_t unchunked_ext_msg_support : 1; // [24] UnChunked Extended Message Supported
+ uint32_t dual_role_data : 1; // [25] Dual Role Data
+ uint32_t usb_comm_capable : 1; // [26] USB Communications Capable
+ uint32_t unconstrained_power : 1; // [27] Unconstrained Power
+ uint32_t usb_suspend_supported : 1; // [28] USB Suspend Supported
+ uint32_t dual_role_power : 1; // [29] Dual Role Power
+ uint32_t type : 2; // [30] Fixed Supply type = PD_PDO_TYPE_FIXED
+} pd_pdo_fixed_t;
+TU_VERIFY_STATIC(sizeof(pd_pdo_fixed_t) == 4, "Invalid size");
+
+// Battery Power Data Object (PDO) table 6-12
+typedef struct TU_ATTR_PACKED {
+ uint32_t power_max_250mw : 10; // [9..0] Max allowable power in 250mW unit
+ uint32_t voltage_min_50mv : 10; // [19..10] Minimum voltage in 50mV unit
+ uint32_t voltage_max_50mv : 10; // [29..20] Maximum voltage in 50mV unit
+ uint32_t type : 2; // [31..30] Battery type = PD_PDO_TYPE_BATTERY
+} pd_pdo_battery_t;
+TU_VERIFY_STATIC(sizeof(pd_pdo_battery_t) == 4, "Invalid size");
+
+// Variable Power Data Object (PDO) table 6-11
+typedef struct TU_ATTR_PACKED {
+ uint32_t current_max_10ma : 10; // [9..0] Max current in 10mA unit
+ uint32_t voltage_min_50mv : 10; // [19..10] Minimum voltage in 50mV unit
+ uint32_t voltage_max_50mv : 10; // [29..20] Maximum voltage in 50mV unit
+ uint32_t type : 2; // [31..30] Variable Supply type = PD_PDO_TYPE_VARIABLE
+} pd_pdo_variable_t;
+TU_VERIFY_STATIC(sizeof(pd_pdo_variable_t) == 4, "Invalid size");
+
+// Augmented Power Data Object (PDO) table 6-13
+typedef struct TU_ATTR_PACKED {
+ uint32_t current_max_50ma : 7; // [6..0] Max current in 50mA unit
+ uint32_t reserved1 : 1; // [7] Reserved
+ uint32_t voltage_min_100mv : 8; // [15..8] Minimum Voltage in 100mV unit
+ uint32_t reserved2 : 1; // [16] Reserved
+ uint32_t voltage_max_100mv : 8; // [24..17] Maximum Voltage in 100mV unit
+ uint32_t reserved3 : 2; // [26..25] Reserved
+ uint32_t pps_power_limited : 1; // [27] PPS Power Limited
+ uint32_t spr_programmable : 2; // [29..28] SPR Programmable Power Supply
+ uint32_t type : 2; // [31..30] Augmented Power Data Object = PD_PDO_TYPE_APDO
+} pd_pdo_apdo_t;
+TU_VERIFY_STATIC(sizeof(pd_pdo_apdo_t) == 4, "Invalid size");
+
+//--------------------------------------------------------------------+
+// Request
+//--------------------------------------------------------------------+
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t current_extremum_10ma : 10; // [9..0] Max (give back = 0) or Min (give back = 1) current in 10mA unit
+ uint32_t current_operate_10ma : 10; // [19..10] Operating current in 10mA unit
+ uint32_t reserved : 2; // [21..20] Reserved
+ uint32_t epr_mode_capable : 1; // [22] EPR mode capable
+ uint32_t unchunked_ext_msg_support : 1; // [23] UnChunked Extended Message Supported
+ uint32_t no_usb_suspend : 1; // [24] No USB Suspend
+ uint32_t usb_comm_capable : 1; // [25] USB Communications Capable
+ uint32_t capability_mismatch : 1; // [26] Capability Mismatch
+ uint32_t give_back_flag : 1; // [27] GiveBack Flag: 0 = Max, 1 = Min
+ uint32_t object_position : 4; // [31..28] Object Position
+} pd_rdo_fixed_variable_t;
+TU_VERIFY_STATIC(sizeof(pd_rdo_fixed_variable_t) == 4, "Invalid size");
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t power_extremum_250mw : 10; // [9..0] Max (give back = 0) or Min (give back = 1) operating power in 250mW unit
+ uint32_t power_operate_250mw : 10; // [19..10] Operating power in 250mW unit
+ uint32_t reserved : 2; // [21..20] Reserved
+ uint32_t epr_mode_capable : 1; // [22] EPR mode capable
+ uint32_t unchunked_ext_msg_support : 1; // [23] UnChunked Extended Message Supported
+ uint32_t no_usb_suspend : 1; // [24] No USB Suspend
+ uint32_t usb_comm_capable : 1; // [25] USB Communications Capable
+ uint32_t capability_mismatch : 1; // [26] Capability Mismatch
+ uint32_t give_back_flag : 1; // [27] GiveBack Flag: 0 = Max, 1 = Min
+ uint32_t object_position : 4; // [31..28] Object Position
+} pd_rdo_battery_t;
+TU_VERIFY_STATIC(sizeof(pd_rdo_battery_t) == 4, "Invalid size");
+
+
+TU_ATTR_PACKED_END // End of all packed definitions
+TU_ATTR_BIT_FIELD_ORDER_END
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/typec/tcd.h b/src/typec/tcd.h
new file mode 100644
index 000000000..86499c951
--- /dev/null
+++ b/src/typec/tcd.h
@@ -0,0 +1,143 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach ([email protected]) for Adafruit Industries
+ *
+ * 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 _TUSB_TCD_H_
+#define _TUSB_TCD_H_
+
+#include "common/tusb_common.h"
+#include "pd_types.h"
+
+#include "osal/osal.h"
+#include "common/tusb_fifo.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+enum {
+ TCD_EVENT_INVALID = 0,
+ TCD_EVENT_CC_CHANGED,
+ TCD_EVENT_RX_COMPLETE,
+ TCD_EVENT_TX_COMPLETE,
+};
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t rhport;
+ uint8_t event_id;
+
+ union {
+ struct {
+ uint8_t cc_state[2];
+ } cc_changed;
+
+ struct TU_ATTR_PACKED {
+ uint16_t result : 2;
+ uint16_t xferred_bytes : 14;
+ } xfer_complete;
+ };
+
+} tcd_event_t;;
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+// Initialize controller
+bool tcd_init(uint8_t rhport, uint32_t port_type);
+
+// Enable interrupt
+void tcd_int_enable (uint8_t rhport);
+
+// Disable interrupt
+void tcd_int_disable(uint8_t rhport);
+
+// Interrupt Handler
+void tcd_int_handler(uint8_t rhport);
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+bool tcd_msg_receive(uint8_t rhport, uint8_t* buffer, uint16_t total_bytes);
+bool tcd_msg_send(uint8_t rhport, uint8_t const* buffer, uint16_t total_bytes);
+
+//--------------------------------------------------------------------+
+// Event API (implemented by stack)
+// Called by TCD to notify stack
+//--------------------------------------------------------------------+
+
+extern void tcd_event_handler(tcd_event_t const * event, bool in_isr);
+
+TU_ATTR_ALWAYS_INLINE static inline
+void tcd_event_cc_changed(uint8_t rhport, uint8_t cc1, uint8_t cc2, bool in_isr) {
+ tcd_event_t event = {
+ .rhport = rhport,
+ .event_id = TCD_EVENT_CC_CHANGED,
+ .cc_changed = {
+ .cc_state = {cc1, cc2 }
+ }
+ };
+
+ tcd_event_handler(&event, in_isr);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline
+void tcd_event_rx_complete(uint8_t rhport, uint16_t xferred_bytes, uint8_t result, bool in_isr) {
+ tcd_event_t event = {
+ .rhport = rhport,
+ .event_id = TCD_EVENT_RX_COMPLETE,
+ .xfer_complete = {
+ .xferred_bytes = xferred_bytes,
+ .result = result
+ }
+ };
+
+ tcd_event_handler(&event, in_isr);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline
+void tcd_event_tx_complete(uint8_t rhport, uint16_t xferred_bytes, uint8_t result, bool in_isr) {
+ tcd_event_t event = {
+ .rhport = rhport,
+ .event_id = TCD_EVENT_TX_COMPLETE,
+ .xfer_complete = {
+ .xferred_bytes = xferred_bytes,
+ .result = result
+ }
+ };
+
+ tcd_event_handler(&event, in_isr);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/typec/usbc.c b/src/typec/usbc.c
new file mode 100644
index 000000000..fdf2a0cd6
--- /dev/null
+++ b/src/typec/usbc.c
@@ -0,0 +1,219 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Ha Thach ([email protected])
+ *
+ * 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 CFG_TUC_ENABLED
+
+#include "tcd.h"
+#include "usbc.h"
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+// Debug level of USBD
+#define USBC_DEBUG 2
+#define TU_LOG_USBC(...) TU_LOG(USBC_DEBUG, __VA_ARGS__)
+
+// Event queue
+// usbc_int_set() is used as mutex in OS NONE config
+void usbc_int_set(bool enabled);
+OSAL_QUEUE_DEF(usbc_int_set, _usbc_qdef, CFG_TUC_TASK_QUEUE_SZ, tcd_event_t);
+tu_static osal_queue_t _usbc_q;
+
+// if stack is initialized
+static bool _usbc_inited = false;
+
+// if port is initialized
+static bool _port_inited[TUP_TYPEC_RHPORTS_NUM];
+
+// Max possible PD size is 262 bytes
+static uint8_t _rx_buf[64] TU_ATTR_ALIGNED(4);
+static uint8_t _tx_buf[64] TU_ATTR_ALIGNED(4);
+
+bool usbc_msg_send(uint8_t rhport, pd_header_t const* header, void const* data);
+bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end);
+bool parse_msg_control(uint8_t rhport, pd_header_t const* header);
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+bool tuc_inited(uint8_t rhport) {
+ return _usbc_inited && _port_inited[rhport];
+}
+
+bool tuc_init(uint8_t rhport, uint32_t port_type) {
+ // Initialize stack
+ if (!_usbc_inited) {
+ tu_memclr(_port_inited, sizeof(_port_inited));
+
+ _usbc_q = osal_queue_create(&_usbc_qdef);
+ TU_ASSERT(_usbc_q != NULL);
+
+ _usbc_inited = true;
+ }
+
+ // skip if port already initialized
+ if ( _port_inited[rhport] ) {
+ return true;
+ }
+
+ TU_LOG_USBC("USBC init on port %u\r\n", rhport);
+ TU_LOG_INT(USBC_DEBUG, sizeof(tcd_event_t));
+
+ TU_ASSERT(tcd_init(rhport, port_type));
+ tcd_int_enable(rhport);
+
+ _port_inited[rhport] = true;
+ return true;
+}
+
+void tuc_task_ext(uint32_t timeout_ms, bool in_isr) {
+ (void) in_isr; // not implemented yet
+
+ // Skip if stack is not initialized
+ if (!_usbc_inited) return;
+
+ // Loop until there is no more events in the queue
+ while (1) {
+ tcd_event_t event;
+ if (!osal_queue_receive(_usbc_q, &event, timeout_ms)) return;
+
+ switch (event.event_id) {
+ case TCD_EVENT_CC_CHANGED:
+ break;
+
+ case TCD_EVENT_RX_COMPLETE:
+ // TODO process message here in ISR, move to thread later
+ if (event.xfer_complete.result == XFER_RESULT_SUCCESS) {
+ pd_header_t const* header = (pd_header_t const*) _rx_buf;
+
+ if (header->n_data_obj == 0) {
+ parse_msg_control(event.rhport, header);
+
+ }else {
+ uint8_t const* p_end = _rx_buf + event.xfer_complete.xferred_bytes;
+ uint8_t const * dobj = _rx_buf + sizeof(pd_header_t);
+
+ parse_msg_data(event.rhport, header, dobj, p_end);
+ }
+ }
+
+ // prepare for next message
+ tcd_msg_receive(event.rhport, _rx_buf, sizeof(_rx_buf));
+ break;
+
+ case TCD_EVENT_TX_COMPLETE:
+ break;
+
+ default: break;
+ }
+ }
+}
+
+bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) {
+ if (tuc_pd_data_received_cb) {
+ tuc_pd_data_received_cb(rhport, header, dobj, p_end);
+ }
+
+ return true;
+}
+
+bool parse_msg_control(uint8_t rhport, pd_header_t const* header) {
+ if (tuc_pd_control_received_cb) {
+ tuc_pd_control_received_cb(rhport, header);
+ }
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+bool usbc_msg_send(uint8_t rhport, pd_header_t const* header, void const* data) {
+ // copy header
+ memcpy(_tx_buf, header, sizeof(pd_header_t));
+
+ // copy data objcet if available
+ uint16_t const n_data_obj = header->n_data_obj;
+ if (n_data_obj > 0) {
+ memcpy(_tx_buf + sizeof(pd_header_t), data, n_data_obj * 4);
+ }
+
+ return tcd_msg_send(rhport, _tx_buf, sizeof(pd_header_t) + n_data_obj * 4);
+}
+
+bool tuc_msg_request(uint8_t rhport, void const* rdo) {
+ pd_header_t const header = {
+ .msg_type = PD_DATA_REQUEST,
+ .data_role = PD_DATA_ROLE_UFP,
+ .specs_rev = PD_REV_30,
+ .power_role = PD_POWER_ROLE_SINK,
+ .msg_id = 0,
+ .n_data_obj = 1,
+ .extended = 0,
+ };
+
+ return usbc_msg_send(rhport, &header, rdo);
+}
+
+void tcd_event_handler(tcd_event_t const * event, bool in_isr) {
+ (void) in_isr;
+ switch(event->event_id) {
+ case TCD_EVENT_CC_CHANGED:
+ if (event->cc_changed.cc_state[0] || event->cc_changed.cc_state[1]) {
+ // Attach, start receiving
+ tcd_msg_receive(event->rhport, _rx_buf, sizeof(_rx_buf));
+ }else {
+ // Detach
+ }
+ break;
+
+ default: break;
+ }
+
+ osal_queue_send(_usbc_q, event, in_isr);
+}
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+void usbc_int_set(bool enabled) {
+ // Disable all controllers since they shared the same event queue
+ for (uint8_t p = 0; p < TUP_TYPEC_RHPORTS_NUM; p++) {
+ if ( _port_inited[p] ) {
+ if (enabled) {
+ tcd_int_enable(p);
+ }else {
+ tcd_int_disable(p);
+ }
+ }
+ }
+}
+
+#endif
diff --git a/src/typec/usbc.h b/src/typec/usbc.h
new file mode 100644
index 000000000..9fbff9bc6
--- /dev/null
+++ b/src/typec/usbc.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#ifndef _TUSB_UTCD_H_
+#define _TUSB_UTCD_H_
+
+#include "common/tusb_common.h"
+#include "pd_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TypeC Configuration
+//--------------------------------------------------------------------+
+
+#ifndef CFG_TUC_TASK_QUEUE_SZ
+#define CFG_TUC_TASK_QUEUE_SZ 8
+#endif
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
+// Init typec stack on a port
+bool tuc_init(uint8_t rhport, uint32_t port_type);
+
+// Check if typec port is initialized
+bool tuc_inited(uint8_t rhport);
+
+// Task function should be called in main/rtos loop, extended version of tud_task()
+// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever
+// - in_isr: if function is called in ISR
+void tuc_task_ext(uint32_t timeout_ms, bool in_isr);
+
+// Task function should be called in main/rtos loop
+TU_ATTR_ALWAYS_INLINE static inline
+void tuc_task (void) {
+ tuc_task_ext(UINT32_MAX, false);
+}
+
+#ifndef _TUSB_TCD_H_
+extern void tcd_int_handler(uint8_t rhport);
+#endif
+
+// Interrupt handler, name alias to TCD
+#define tuc_int_handler tcd_int_handler
+
+//--------------------------------------------------------------------+
+// Callbacks
+//--------------------------------------------------------------------+
+
+TU_ATTR_WEAK bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end);
+TU_ATTR_WEAK bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header);
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+bool tuc_msg_request(uint8_t rhport, void const* rdo);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif