summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrent Kowal <[email protected]>2024-07-25 09:08:37 -0400
committerBrent Kowal <[email protected]>2024-07-25 09:08:37 -0400
commit5122d6d109f8c4b31b6cbe29c685fad30a8961fe (patch)
treef45efc716882a885d776a30f79c11fef9e41735f
parent13f5f20c981cc54baa8438e275524db03fb79e94 (diff)
Combined DCD MUSB implementations
Combined the new MAX32 MUSB implementation with the existing (TI) implementation to provide generic code base for working the MUSB DCD peripheral. - Added abstraction calls for FIFO setup, EP registers, Ctrl registers and interrupt setup. - Combined TM4C and MSP432E into a single header file. - Created musb_max32.h, and removed the MAX32 specific C implementation. - Updated MAX32 build system to use dcd_musb.c. - Added MAX32 conditions for cdc_dual_ports example descriptors missed during first testing.
-rw-r--r--examples/device/cdc_dual_ports/src/usb_descriptors.c12
-rw-r--r--hw/bsp/max32650/family.cmake2
-rw-r--r--hw/bsp/max32650/family.mk2
-rw-r--r--hw/bsp/max32666/family.cmake2
-rw-r--r--hw/bsp/max32666/family.mk2
-rw-r--r--hw/bsp/max32690/family.cmake2
-rw-r--r--hw/bsp/max32690/family.mk2
-rw-r--r--hw/bsp/max78002/family.cmake2
-rw-r--r--hw/bsp/max78002/family.mk2
-rw-r--r--src/portable/analog/max32/dcd_max32.c811
-rw-r--r--src/portable/mentor/musb/dcd_musb.c436
-rw-r--r--src/portable/mentor/musb/hcd_musb.c12
-rw-r--r--src/portable/mentor/musb/musb_max32.h221
-rw-r--r--src/portable/mentor/musb/musb_msp432e.h40
-rw-r--r--src/portable/mentor/musb/musb_ti.h285
-rw-r--r--src/portable/mentor/musb/musb_tm4c.h45
-rw-r--r--src/portable/mentor/musb/musb_type.h33
17 files changed, 711 insertions, 1200 deletions
diff --git a/examples/device/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c
index de2505c07..808d78411 100644
--- a/examples/device/cdc_dual_ports/src/usb_descriptors.c
+++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c
@@ -120,6 +120,18 @@ enum
#define EPNUM_CDC_1_OUT 0x05
#define EPNUM_CDC_1_IN 0x86
+#elif CFG_TUSB_MCU == OPT_MCU_MAX32690 || CFG_TUSB_MCU == OPT_MCU_MAX32650 || \
+ CFG_TUSB_MCU == OPT_MCU_MAX32666 || CFG_TUSB_MCU == OPT_MCU_MAX78002
+ // MAX32 doesn't support a same endpoint number with different direction IN and OUT
+ // e.g EP1 OUT & EP1 IN cannot exist together
+ #define EPNUM_CDC_0_NOTIF 0x81
+ #define EPNUM_CDC_0_OUT 0x02
+ #define EPNUM_CDC_0_IN 0x83
+
+ #define EPNUM_CDC_1_NOTIF 0x84
+ #define EPNUM_CDC_1_OUT 0x05
+ #define EPNUM_CDC_1_IN 0x86
+
#else
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
diff --git a/hw/bsp/max32650/family.cmake b/hw/bsp/max32650/family.cmake
index 129d99af8..92b68a1cd 100644
--- a/hw/bsp/max32650/family.cmake
+++ b/hw/bsp/max32650/family.cmake
@@ -132,7 +132,7 @@ function(family_configure_example TARGET RTOS)
# Add TinyUSB target and port source
family_add_tinyusb(${TARGET} OPT_MCU_MAX32650 ${RTOS})
target_sources(${TARGET}-tinyusb PUBLIC
- ${TOP}/src/portable/analog/max32/dcd_max32.c
+ ${TOP}/src/portable/mentor/musb/dcd_musb.c
)
target_compile_options(${TARGET} PRIVATE
-Wno-error=strict-prototypes
diff --git a/hw/bsp/max32650/family.mk b/hw/bsp/max32650/family.mk
index 0718523c3..359261216 100644
--- a/hw/bsp/max32650/family.mk
+++ b/hw/bsp/max32650/family.mk
@@ -62,7 +62,7 @@ flash: $(DEFAULT_FLASH)
# -----------------
PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source
SRC_C += \
- src/portable/analog/max32/dcd_max32.c \
+ src/portable/mentor/musb/dcd_musb.c \
$(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/heap.c \
$(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/system_max32650.c \
$(MAX32_CMSIS)/Device/Maxim/MAX32650/Source/header_MAX32650.c \
diff --git a/hw/bsp/max32666/family.cmake b/hw/bsp/max32666/family.cmake
index ef2a2bb63..eb9d2175f 100644
--- a/hw/bsp/max32666/family.cmake
+++ b/hw/bsp/max32666/family.cmake
@@ -127,7 +127,7 @@ function(family_configure_example TARGET RTOS)
# Add TinyUSB target and port source
family_add_tinyusb(${TARGET} OPT_MCU_MAX32666 ${RTOS})
target_sources(${TARGET}-tinyusb PUBLIC
- ${TOP}/src/portable/analog/max32/dcd_max32.c
+ ${TOP}/src/portable/mentor/musb/dcd_musb.c
)
target_compile_options(${TARGET} PRIVATE
-Wno-error=strict-prototypes
diff --git a/hw/bsp/max32666/family.mk b/hw/bsp/max32666/family.mk
index 31f81f014..720d994ef 100644
--- a/hw/bsp/max32666/family.mk
+++ b/hw/bsp/max32666/family.mk
@@ -57,7 +57,7 @@ flash-msdk: $(BUILD)/$(PROJECT).elf
# -----------------
PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source
SRC_C += \
- src/portable/analog/max32/dcd_max32.c \
+ src/portable/mentor/musb/dcd_musb.c \
$(MAX32_CMSIS)/Device/Maxim/MAX32665/Source/heap.c \
$(MAX32_CMSIS)/Device/Maxim/MAX32665/Source/system_max32665.c \
$(PERIPH_SRC)/SYS/mxc_assert.c \
diff --git a/hw/bsp/max32690/family.cmake b/hw/bsp/max32690/family.cmake
index d7a562956..2a9422dbe 100644
--- a/hw/bsp/max32690/family.cmake
+++ b/hw/bsp/max32690/family.cmake
@@ -132,7 +132,7 @@ function(family_configure_example TARGET RTOS)
# Add TinyUSB target and port source
family_add_tinyusb(${TARGET} OPT_MCU_MAX32690 ${RTOS})
target_sources(${TARGET}-tinyusb PUBLIC
- ${TOP}/src/portable/analog/max32/dcd_max32.c
+ ${TOP}/src/portable/mentor/musb/dcd_musb.c
)
target_compile_options(${TARGET} PRIVATE
-Wno-error=strict-prototypes
diff --git a/hw/bsp/max32690/family.mk b/hw/bsp/max32690/family.mk
index 9360a07c6..c533cf4a4 100644
--- a/hw/bsp/max32690/family.mk
+++ b/hw/bsp/max32690/family.mk
@@ -64,7 +64,7 @@ flash-msdk: $(BUILD)/$(PROJECT).elf
# -----------------
PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source
SRC_C += \
- src/portable/analog/max32/dcd_max32.c \
+ src/portable/mentor/musb/dcd_musb.c \
$(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/heap.c \
$(MAX32_CMSIS)/Device/Maxim/MAX32690/Source/system_max32690.c \
$(PERIPH_SRC)/SYS/mxc_assert.c \
diff --git a/hw/bsp/max78002/family.cmake b/hw/bsp/max78002/family.cmake
index 83fd3007f..090f1da43 100644
--- a/hw/bsp/max78002/family.cmake
+++ b/hw/bsp/max78002/family.cmake
@@ -137,7 +137,7 @@ function(family_configure_example TARGET RTOS)
# Add TinyUSB target and port source
family_add_tinyusb(${TARGET} OPT_MCU_MAX78002 ${RTOS})
target_sources(${TARGET}-tinyusb PUBLIC
- ${TOP}/src/portable/analog/max32/dcd_max32.c
+ ${TOP}/src/portable/mentor/musb/dcd_musb.c
)
target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD})
target_compile_options(${TARGET}-tinyusb PRIVATE
diff --git a/hw/bsp/max78002/family.mk b/hw/bsp/max78002/family.mk
index 8df8517da..5297815de 100644
--- a/hw/bsp/max78002/family.mk
+++ b/hw/bsp/max78002/family.mk
@@ -60,7 +60,7 @@ flash-msdk: $(BUILD)/$(PROJECT).elf
# -----------------
PERIPH_SRC = $(TOP)/$(MAX32_PERIPH)/Source
SRC_C += \
- src/portable/analog/max32/dcd_max32.c \
+ src/portable/mentor/musb/dcd_musb.c \
$(MAX32_CMSIS)/Device/Maxim/MAX78002/Source/heap.c \
$(MAX32_CMSIS)/Device/Maxim/MAX78002/Source/system_max78002.c \
$(PERIPH_SRC)/SYS/mxc_assert.c \
diff --git a/src/portable/analog/max32/dcd_max32.c b/src/portable/analog/max32/dcd_max32.c
deleted file mode 100644
index df616120a..000000000
--- a/src/portable/analog/max32/dcd_max32.c
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2021 Koji KITAYAMA
- * Copyright (c) 2024 Brent Kowal (Analog Devices, Inc)
- *
- * 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 && \
- TU_CHECK_MCU(OPT_MCU_MAX32690, OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX78002)
-
- #if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
-/* GCC warns that an address may be unaligned, even though
- * the target CPU has the capability for unaligned memory access. */
-_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
- #endif
-
- #include "device/dcd.h"
-
- #include "mxc_delay.h"
- #include "mxc_device.h"
- #include "mxc_sys.h"
- #include "nvic_table.h"
- #include "usbhs_regs.h"
-
- #define USBHS_M31_CLOCK_RECOVERY
-
- /*------------------------------------------------------------------
- * MACRO TYPEDEF CONSTANT ENUM DECLARATION
- *------------------------------------------------------------------*/
- #define REQUEST_TYPE_INVALID (0xFFu)
-
-
-typedef union {
- uint8_t u8;
- uint16_t u16;
- uint32_t u32;
-} hw_fifo_t;
-
-typedef struct TU_ATTR_PACKED {
- void *buf; /* the start address of a transfer data buffer */
- uint16_t length; /* the number of bytes in the buffer */
- uint16_t remaining; /* the number of bytes remaining in the buffer */
-} pipe_state_t;
-
-typedef struct
-{
- tusb_control_request_t setup_packet;
- uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
- int8_t status_out;
- pipe_state_t pipe0;
- pipe_state_t pipe[2][TUP_DCD_ENDPOINT_MAX - 1]; /* pipe[direction][endpoint number - 1] */
- uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */
-} dcd_data_t;
-
-/*------------------------------------------------------------------
- * INTERNAL OBJECT & FUNCTION DECLARATION
- *------------------------------------------------------------------*/
-static dcd_data_t _dcd;
-
-
-static volatile void *edpt_get_fifo_ptr(unsigned epnum) {
- volatile uint32_t *ptr;
-
- ptr = &MXC_USBHS->fifo0;
- ptr += epnum; /* Pointer math: multiplies ep by sizeof(uint32_t) */
-
- return (volatile void *) ptr;
-}
-
-static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len) {
- volatile hw_fifo_t *reg = (volatile hw_fifo_t *) fifo;
- uintptr_t addr = (uintptr_t) buf;
- while (len >= 4) {
- reg->u32 = *(uint32_t const *) addr;
- addr += 4;
- len -= 4;
- }
- if (len >= 2) {
- reg->u16 = *(uint16_t const *) addr;
- addr += 2;
- len -= 2;
- }
- if (len) {
- reg->u8 = *(uint8_t const *) addr;
- }
-}
-
-static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len) {
- volatile hw_fifo_t *reg = (volatile hw_fifo_t *) fifo;
- uintptr_t addr = (uintptr_t) buf;
- while (len >= 4) {
- *(uint32_t *) addr = reg->u32;
- addr += 4;
- len -= 4;
- }
- if (len >= 2) {
- *(uint16_t *) addr = reg->u16;
- addr += 2;
- len -= 2;
- }
- if (len) {
- *(uint8_t *) addr = reg->u8;
- }
-}
-
-static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir) {
- static const struct {
- void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
- void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n);
- void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len);
- } ops[] = {
- /* OUT */ {tu_fifo_get_write_info, tu_fifo_advance_write_pointer, pipe_read_packet},
- /* IN */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet},
- };
- tu_fifo_buffer_info_t info;
- ops[dir].tu_fifo_get_info(f, &info);
- unsigned total_len = len;
- len = TU_MIN(total_len, info.len_lin);
- ops[dir].pipe_read_write(info.ptr_lin, fifo, len);
- unsigned rem = total_len - len;
- if (rem) {
- len = TU_MIN(rem, info.len_wrap);
- ops[dir].pipe_read_write(info.ptr_wrap, fifo, len);
- rem -= len;
- }
- ops[dir].tu_fifo_advance(f, total_len - rem);
-}
-
-static void process_setup_packet(uint8_t rhport) {
- uint32_t *p = (void *) &_dcd.setup_packet;
- p[0] = MXC_USBHS->fifo0;
- p[1] = MXC_USBHS->fifo0;
-
- _dcd.pipe0.buf = NULL;
- _dcd.pipe0.length = 0;
- _dcd.pipe0.remaining = 0;
- dcd_event_setup_received(rhport, (const uint8_t *) (uintptr_t) &_dcd.setup_packet, true);
-
- const unsigned len = _dcd.setup_packet.wLength;
- _dcd.remaining_ctrl = len;
- const unsigned dir_in = tu_edpt_dir(_dcd.setup_packet.bmRequestType);
- /* Clear RX FIFO and reverse the transaction direction */
- if (len && dir_in) {
- MXC_USBHS->index = 0;
- MXC_USBHS->csr0 = MXC_F_USBHS_CSR0_SERV_OUTPKTRDY;
- }
-}
-
-static bool handle_xfer_in(uint_fast8_t ep_addr) {
- unsigned epnum = tu_edpt_number(ep_addr);
- unsigned epnum_minus1 = epnum - 1;
- pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
- const unsigned rem = pipe->remaining;
-
- //This function should not be for ep0
- TU_ASSERT(epnum);
-
- if (!rem) {
- pipe->buf = NULL;
- return true;
- }
-
- MXC_USBHS->index = epnum;
- const unsigned mps = MXC_USBHS->inmaxp;
- const unsigned len = TU_MIN(mps, rem);
- void *buf = pipe->buf;
- volatile void *fifo_ptr = edpt_get_fifo_ptr(epnum);
- if (len) {
- if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_IN);
- } else {
- pipe_write_packet(buf, fifo_ptr, len);
- pipe->buf = buf + len;
- }
- pipe->remaining = rem - len;
- }
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_INPKTRDY;//TODO: Verify a | isn't needed
-
- return false;
-}
-
-static bool handle_xfer_out(uint_fast8_t ep_addr) {
- unsigned epnum = tu_edpt_number(ep_addr);
- unsigned epnum_minus1 = epnum - 1;
- pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
-
- //This function should not be for ep0
- TU_ASSERT(epnum);
-
- MXC_USBHS->index = epnum;
-
- TU_ASSERT(MXC_USBHS->outcsrl & MXC_F_USBHS_OUTCSRL_OUTPKTRDY);
-
- const unsigned mps = MXC_USBHS->outmaxp;
- const unsigned rem = pipe->remaining;
- const unsigned vld = MXC_USBHS->outcount;
- const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
- void *buf = pipe->buf;
- volatile void *fifo_ptr = edpt_get_fifo_ptr(epnum);
- if (len) {
- if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_OUT);
- } else {
- pipe_read_packet(buf, fifo_ptr, len);
- pipe->buf = buf + len;
- }
- pipe->remaining = rem - len;
- }
- if ((len < mps) || (rem == len)) {
- pipe->buf = NULL;
- return NULL != buf;
- }
- MXC_USBHS->outcsrl = 0; /* Clear RXRDY bit *///TODO: Verify just setting to 0 is ok
- return false;
-}
-
-static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
- (void) rhport;
-
- unsigned epnum = tu_edpt_number(ep_addr);
- unsigned epnum_minus1 = epnum - 1;
- unsigned dir_in = tu_edpt_dir(ep_addr);
-
- pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1];
- pipe->buf = buffer;
- pipe->length = total_bytes;
- pipe->remaining = total_bytes;
-
- if (dir_in) {
- handle_xfer_in(ep_addr);
- } else {
- MXC_USBHS->index = epnum;
- if (MXC_USBHS->outcsrl & MXC_F_USBHS_OUTCSRL_OUTPKTRDY) {
- MXC_USBHS->outcsrl = 0;//TODO: Verify just setting to 0 is ok
- }
- }
- return true;
-}
-
-static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
- (void) rhport;
- TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */
-
- const unsigned req = _dcd.setup_packet.bmRequestType;
- TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0);
-
- if (req == REQUEST_TYPE_INVALID || _dcd.status_out) {
- /* STATUS OUT stage.
- * MUSB controller automatically handles STATUS OUT packets without
- * software helps. We do not have to do anything. And STATUS stage
- * may have already finished and received the next setup packet
- * without calling this function, so we have no choice but to
- * invoke the callback function of status packet here. */
- _dcd.status_out = 0;
- if (req == REQUEST_TYPE_INVALID) {
- dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
- } else {
- /* The next setup packet has already been received, it aborts
- * invoking callback function to avoid confusing TUSB stack. */
- TU_LOG1("Drop CONTROL_STAGE_ACK\r\n");
- }
- return true;
- }
- const unsigned dir_in = tu_edpt_dir(ep_addr);
- MXC_USBHS->index = 0;
- if (tu_edpt_dir(req) == dir_in) { /* DATA stage */
- TU_ASSERT(total_bytes <= _dcd.remaining_ctrl);
- const unsigned rem = _dcd.remaining_ctrl;
- const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
- volatile void *fifo_ptr = edpt_get_fifo_ptr(0);
- if (dir_in) {
- pipe_write_packet(buffer, fifo_ptr, len);
-
- _dcd.pipe0.buf = buffer + len;
- _dcd.pipe0.length = len;
- _dcd.pipe0.remaining = 0;
-
- _dcd.remaining_ctrl = rem - len;
- if ((len < 64) || (rem == len)) {
- _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; /* Change to STATUS/SETUP stage */
- _dcd.status_out = 1;
- /* Flush TX FIFO and reverse the transaction direction. */
- MXC_USBHS->csr0 = MXC_F_USBHS_CSR0_INPKTRDY | MXC_F_USBHS_CSR0_DATA_END;
- } else {
- MXC_USBHS->csr0 = MXC_F_USBHS_CSR0_INPKTRDY; /* Flush TX FIFO to return ACK. */
- }
- } else {
- _dcd.pipe0.buf = buffer;
- _dcd.pipe0.length = len;
- _dcd.pipe0.remaining = len;
- MXC_USBHS->csr0 = MXC_F_USBHS_CSR0_SERV_OUTPKTRDY; /* Clear RX FIFO to return ACK. */
- }
- } else if (dir_in) {
- _dcd.pipe0.buf = NULL;
- _dcd.pipe0.length = 0;
- _dcd.pipe0.remaining = 0;
- /* Clear RX FIFO and reverse the transaction direction */
- MXC_USBHS->csr0 = MXC_F_USBHS_CSR0_SERV_OUTPKTRDY | MXC_F_USBHS_CSR0_DATA_END;
- }
- return true;
-}
-
-static void process_ep0(uint8_t rhport) {
- MXC_USBHS->index = 0;
- uint_fast8_t csrl = MXC_USBHS->csr0;
-
- if (csrl & MXC_F_USBHS_CSR0_SENT_STALL) {
- /* Returned STALL packet to HOST. */
- MXC_USBHS->csr0 = 0; /* Clear STALL */
- return;
- }
-
- unsigned req = _dcd.setup_packet.bmRequestType;
- if (csrl & MXC_F_USBHS_CSR0_SETUP_END) {
- TU_LOG1(" ABORT by the next packets\r\n");
- MXC_USBHS->csr0 = MXC_F_USBHS_CSR0_SERV_SETUP_END;
- if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) {
- /* DATA stage was aborted by receiving STATUS or SETUP packet. */
- _dcd.pipe0.buf = NULL;
- _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
- dcd_event_xfer_complete(rhport,
- req & TUSB_DIR_IN_MASK,
- _dcd.pipe0.length - _dcd.pipe0.remaining,
- XFER_RESULT_SUCCESS, true);
- }
- req = REQUEST_TYPE_INVALID;
- if (!(csrl & MXC_F_USBHS_CSR0_OUTPKTRDY)) return; /* Received SETUP packet */
- }
-
- if (csrl & MXC_F_USBHS_CSR0_OUTPKTRDY) {
- /* Received SETUP or DATA OUT packet */
- if (req == REQUEST_TYPE_INVALID) {
- /* SETUP */
- TU_ASSERT(sizeof(tusb_control_request_t) == MXC_USBHS->count0, );
- process_setup_packet(rhport);
- return;
- }
- if (_dcd.pipe0.buf) {
- /* DATA OUT */
- const unsigned vld = MXC_USBHS->count0;
- const unsigned rem = _dcd.pipe0.remaining;
- const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
- volatile void *fifo_ptr = edpt_get_fifo_ptr(0);
- pipe_read_packet(_dcd.pipe0.buf, fifo_ptr, len);
-
- _dcd.pipe0.remaining = rem - len;
- _dcd.remaining_ctrl -= len;
-
- _dcd.pipe0.buf = NULL;
- dcd_event_xfer_complete(rhport,
- tu_edpt_addr(0, TUSB_DIR_OUT),
- _dcd.pipe0.length - _dcd.pipe0.remaining,
- XFER_RESULT_SUCCESS, true);
- }
- return;
- }
-
- /* When CSRL0 is zero, it means that completion of sending a any length packet
- * or receiving a zero length packet. */
- if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir(req)) {
- /* STATUS IN */
- if (*(const uint16_t *) (uintptr_t) &_dcd.setup_packet == 0x0500) {
- /* The address must be changed on completion of the control transfer. */
- MXC_USBHS->faddr = (uint8_t) _dcd.setup_packet.wValue;
- }
- _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
- dcd_event_xfer_complete(rhport,
- tu_edpt_addr(0, TUSB_DIR_IN),
- _dcd.pipe0.length - _dcd.pipe0.remaining,
- XFER_RESULT_SUCCESS, true);
- return;
- }
- if (_dcd.pipe0.buf) {
- /* DATA IN */
- _dcd.pipe0.buf = NULL;
- dcd_event_xfer_complete(rhport,
- tu_edpt_addr(0, TUSB_DIR_IN),
- _dcd.pipe0.length - _dcd.pipe0.remaining,
- XFER_RESULT_SUCCESS, true);
- }
-}
-
-static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr) {
- bool completed;
- const unsigned dir_in = tu_edpt_dir(ep_addr);
- const unsigned epnum = tu_edpt_number(ep_addr);
-
- MXC_USBHS->index = epnum;
-
- if (dir_in) {
- if (MXC_USBHS->incsrl & MXC_F_USBHS_INCSRL_SENTSTALL) {
- MXC_USBHS->incsrl &= ~(MXC_F_USBHS_INCSRL_SENTSTALL | MXC_F_USBHS_INCSRL_UNDERRUN);
- return;
- }
- completed = handle_xfer_in(ep_addr);
- } else {
- if (MXC_USBHS->outcsrl & MXC_F_USBHS_OUTCSRL_SENTSTALL) {
- MXC_USBHS->outcsrl &= ~(MXC_F_USBHS_OUTCSRL_SENTSTALL | MXC_F_USBHS_OUTCSRL_OVERRUN);
- return;
- }
- completed = handle_xfer_out(ep_addr);
- }
-
- if (completed) {
- pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1];
- dcd_event_xfer_complete(rhport, ep_addr,
- pipe->length - pipe->remaining,
- XFER_RESULT_SUCCESS, true);
- }
-}
-
-static void process_bus_reset(uint8_t rhport) {
- (void) rhport;
- /* When bmRequestType is REQUEST_TYPE_INVALID(0xFF),
- * a control transfer state is SETUP or STATUS stage. */
- _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
- _dcd.status_out = 0;
- /* When pipe0.buf has not NULL, DATA stage works in progress. */
- _dcd.pipe0.buf = NULL;
-
- MXC_USBHS->intrinen = 1; /* Enable only EP0 */
- MXC_USBHS->introuten = 0;
-
-
- /* Clear FIFO settings */
- for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
- MXC_USBHS->index = i;
- if (MXC_USBHS->incsrl & MXC_F_USBHS_INCSRL_INPKTRDY) {
- /* Per musbhsfc_pg, only flush FIFO if IN packet loaded */
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_FLUSHFIFO;
- }
-
- if (MXC_USBHS->outcsrl & MXC_F_USBHS_OUTCSRL_OUTPKTRDY) {
- /* Per musbhsfc_pg, only flush FIFO if OUT packet is ready */
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_FLUSHFIFO;
- }
- }
- dcd_event_bus_reset(0, (MXC_USBHS->power & MXC_F_USBHS_POWER_HS_MODE) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true);
-}
-
-/*------------------------------------------------------------------
- * Device API
- *------------------------------------------------------------------*/
-
-void dcd_init(uint8_t rhport) {
- (void) rhport;
- MXC_USBHS->intrusben |= MXC_F_USBHS_INTRUSBEN_SUSPEND_INT_EN;
-
- //Interrupt for VBUS disconnect
- MXC_USBHS->mxm_int_en |= MXC_F_USBHS_MXM_INT_EN_NOVBUS;
-
- NVIC_ClearPendingIRQ(USB_IRQn);
- dcd_edpt_close_all(rhport);
-
- //Unsuspend the MAC
- MXC_USBHS->mxm_suspend = 0;
-
- /* Configure PHY */
- MXC_USBHS->m31_phy_xcfgi_31_0 = (0x1 << 3) | (0x1 << 11);
- MXC_USBHS->m31_phy_xcfgi_63_32 = 0;
- MXC_USBHS->m31_phy_xcfgi_95_64 = 0x1 << (72 - 64);
- MXC_USBHS->m31_phy_xcfgi_127_96 = 0;
-
-
- #ifdef USBHS_M31_CLOCK_RECOVERY
- MXC_USBHS->m31_phy_noncry_rstb = 1;
- MXC_USBHS->m31_phy_noncry_en = 1;
- MXC_USBHS->m31_phy_outclksel = 0;
- MXC_USBHS->m31_phy_coreclkin = 0;
- MXC_USBHS->m31_phy_xtlsel = 2; /* Select 25 MHz clock */
- #else
- /* Use this option to feed the PHY a 30 MHz clock, which is them used as a PLL reference */
- /* As it depends on the system core clock, this should probably be done at the SYS level */
- MXC_USBHS->m31_phy_noncry_rstb = 0;
- MXC_USBHS->m31_phy_noncry_en = 0;
- MXC_USBHS->m31_phy_outclksel = 1;
- MXC_USBHS->m31_phy_coreclkin = 1;
- MXC_USBHS->m31_phy_xtlsel = 3; /* Select 30 MHz clock */
- #endif
- MXC_USBHS->m31_phy_pll_en = 1;
- MXC_USBHS->m31_phy_oscouten = 1;
-
- /* Reset PHY */
- MXC_USBHS->m31_phy_ponrst = 0;
- MXC_USBHS->m31_phy_ponrst = 1;
-
- dcd_connect(rhport);
-}
-
-void dcd_int_enable(uint8_t rhport) {
- (void) rhport;
- NVIC_EnableIRQ(USB_IRQn);
-}
-
-void dcd_int_disable(uint8_t rhport) {
- (void) rhport;
- NVIC_DisableIRQ(USB_IRQn);
-}
-
-// Receive Set Address request, mcu port must also include status IN response
-void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
- (void) rhport;
- (void) dev_addr;
- _dcd.pipe0.buf = NULL;
- _dcd.pipe0.length = 0;
- _dcd.pipe0.remaining = 0;
- /* Clear RX FIFO to return ACK. */
- MXC_USBHS->index = 0;
- MXC_USBHS->csr0 = MXC_F_USBHS_CSR0_SERV_OUTPKTRDY | MXC_F_USBHS_CSR0_DATA_END;
-}
-
-// Wake up host
-void dcd_remote_wakeup(uint8_t rhport) {
- (void) rhport;
- MXC_USBHS->power |= MXC_F_USBHS_POWER_RESUME;
-
- #if CFG_TUSB_OS != OPT_OS_NONE
- osal_task_delay(10);
- #else
- MXC_Delay(MXC_DELAY_MSEC(10));
- #endif
-
- MXC_USBHS->power &= ~MXC_F_USBHS_POWER_RESUME;
-}
-
-// Connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(uint8_t rhport) {
- (void) rhport;
- MXC_USBHS->power |= TUD_OPT_HIGH_SPEED ? MXC_F_USBHS_POWER_HS_ENABLE : 0;
- MXC_USBHS->power |= MXC_F_USBHS_POWER_SOFTCONN;
-}
-
-// Disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport) {
- (void) rhport;
- MXC_USBHS->power &= ~MXC_F_USBHS_POWER_SOFTCONN;
-}
-
-void dcd_sof_enable(uint8_t rhport, bool en) {
- (void) rhport;
- (void) en;
-
- // TODO implement later
-}
-
-//--------------------------------------------------------------------+
-// Endpoint API
-//--------------------------------------------------------------------+
-
-// Configure endpoint's registers according to descriptor
-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_in = tu_edpt_dir(ep_addr);
- const unsigned xfer = ep_desc->bmAttributes.xfer;
- const unsigned mps = tu_edpt_packet_size(ep_desc);
-
- TU_ASSERT(epn < TUP_DCD_ENDPOINT_MAX);
-
- pipe_state_t *pipe = &_dcd.pipe[dir_in][epn - 1];
- pipe->buf = NULL;
- pipe->length = 0;
- pipe->remaining = 0;
-
- MXC_USBHS->index = epn;
-
- if (dir_in) {
- MXC_USBHS->inmaxp = mps;
- MXC_USBHS->incsru = (MXC_F_USBHS_INCSRU_DPKTBUFDIS | MXC_F_USBHS_INCSRU_MODE) | ((xfer == TUSB_XFER_ISOCHRONOUS) ? MXC_F_USBHS_INCSRU_ISO : 0);
- if (MXC_USBHS->incsrl & MXC_F_USBHS_INCSRL_INPKTRDY) {
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_CLRDATATOG | MXC_F_USBHS_INCSRL_FLUSHFIFO;
- } else {
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_CLRDATATOG;
- }
- MXC_USBHS->intrinen |= TU_BIT(epn);
- } else {
- MXC_USBHS->outmaxp = mps;
- MXC_USBHS->outcsru = (MXC_F_USBHS_OUTCSRU_DPKTBUFDIS) | ((xfer == TUSB_XFER_ISOCHRONOUS) ? MXC_F_USBHS_OUTCSRU_ISO : 0);
- if (MXC_USBHS->outcsrl & MXC_F_USBHS_OUTCSRL_OUTPKTRDY) {
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_CLRDATATOG | MXC_F_USBHS_OUTCSRL_FLUSHFIFO;
- } else {
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_CLRDATATOG;
- }
- MXC_USBHS->introuten |= TU_BIT(epn);
- }
-
- return true;
-}
-
-void dcd_edpt_close_all(uint8_t rhport) {
- (void) rhport;
-
- MXC_SYS_Crit_Enter();
- MXC_USBHS->intrinen = 1; /* Enable only EP0 */
- MXC_USBHS->introuten = 0;
-
- for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
- MXC_USBHS->index = i;
- MXC_USBHS->inmaxp = 0;
- MXC_USBHS->incsru = MXC_F_USBHS_INCSRU_DPKTBUFDIS;
-
- if (MXC_USBHS->incsrl & MXC_F_USBHS_INCSRL_INPKTRDY) {
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_CLRDATATOG | MXC_F_USBHS_INCSRL_FLUSHFIFO;
- } else {
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_CLRDATATOG;
- }
-
- MXC_USBHS->outmaxp = 0;
- MXC_USBHS->outcsru = MXC_F_USBHS_OUTCSRU_DPKTBUFDIS;
-
- if (MXC_USBHS->outcsrl & MXC_F_USBHS_OUTCSRL_OUTPKTRDY) {
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_CLRDATATOG | MXC_F_USBHS_OUTCSRL_FLUSHFIFO;
- } else {
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_CLRDATATOG;
- }
- }
- MXC_SYS_Crit_Exit();
-}
-
-void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
- (void) rhport;
- unsigned const epn = tu_edpt_number(ep_addr);
- unsigned const dir_in = tu_edpt_dir(ep_addr);
-
- MXC_SYS_Crit_Enter();
- MXC_USBHS->index = epn;
- if (dir_in) {
- MXC_USBHS->intrinen &= ~TU_BIT(epn);
- MXC_USBHS->inmaxp = 0;
- MXC_USBHS->incsru = MXC_F_USBHS_INCSRU_DPKTBUFDIS;
- if (MXC_USBHS->incsrl & MXC_F_USBHS_INCSRL_INPKTRDY) {
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_CLRDATATOG | MXC_F_USBHS_INCSRL_FLUSHFIFO;
- } else {
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_CLRDATATOG;
- }
- } else {
- MXC_USBHS->introuten &= ~TU_BIT(epn);
- MXC_USBHS->outmaxp = 0;
- MXC_USBHS->outcsru = MXC_F_USBHS_OUTCSRU_DPKTBUFDIS;
- if (MXC_USBHS->outcsrl & MXC_F_USBHS_OUTCSRL_OUTPKTRDY) {
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_CLRDATATOG | MXC_F_USBHS_OUTCSRL_FLUSHFIFO;
- } else {
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_CLRDATATOG;
- }
- }
- MXC_SYS_Crit_Exit();
-}
-
-// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
- (void) rhport;
- bool ret;
- unsigned const epnum = tu_edpt_number(ep_addr);
- MXC_SYS_Crit_Enter();
- if (epnum) {
- _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1);
- ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes);
- } else
- ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
- MXC_SYS_Crit_Exit();
- return ret;
-}
-
-// Submit a transfer where is managed by FIFO, When complete dcd_event_xfer_complete() is invoked to notify the stack - optional, however, must be listed in usbd.c
-bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) {
- (void) rhport;
- bool ret;
- unsigned const epnum = tu_edpt_number(ep_addr);
- TU_ASSERT(epnum);
- MXC_SYS_Crit_Enter();
- _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1);
- ret = edpt_n_xfer(rhport, ep_addr, (uint8_t *) ff, total_bytes);
- MXC_SYS_Crit_Exit();
- return ret;
-}
-
-// Stall endpoint
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
- (void) rhport;
- unsigned const epn = tu_edpt_number(ep_addr);
- MXC_SYS_Crit_Enter();
- MXC_USBHS->index = epn;
- if (0 == epn) {
- if (!ep_addr) { /* Ignore EP80 */
- _dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
- _dcd.pipe0.buf = NULL;
- MXC_USBHS->csr0 = MXC_F_USBHS_CSR0_SEND_STALL;
- }
- } else {
- if (tu_edpt_dir(ep_addr)) { /* IN */
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_SENDSTALL;
- } else { /* OUT */
- TU_ASSERT(!(MXC_USBHS->outcsrl & MXC_F_USBHS_OUTCSRL_OUTPKTRDY), );
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_SENDSTALL;
- }
- }
- MXC_SYS_Crit_Exit();
-}
-
-// clear stall, data toggle is also reset to DATA0
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
- (void) rhport;
- unsigned const epn = tu_edpt_number(ep_addr);
- MXC_SYS_Crit_Enter();
- MXC_USBHS->index = epn;
- if (tu_edpt_dir(ep_addr)) { /* IN */
- /* IN endpoint */
- if (MXC_USBHS->incsrl & MXC_F_USBHS_INCSRL_INPKTRDY) {
- /* Per musbhsfc_pg, only flush FIFO if IN packet loaded */
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_CLRDATATOG | MXC_F_USBHS_INCSRL_FLUSHFIFO;
- } else {
- MXC_USBHS->incsrl = MXC_F_USBHS_INCSRL_CLRDATATOG;
- }
- } else { /* OUT */
- /* Otherwise, must be OUT endpoint */
- if (MXC_USBHS->outcsrl & MXC_F_USBHS_OUTCSRL_OUTPKTRDY) {
- /* Per musbhsfc_pg, only flush FIFO if OUT packet is ready */
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_CLRDATATOG | MXC_F_USBHS_OUTCSRL_FLUSHFIFO;
- } else {
- MXC_USBHS->outcsrl = MXC_F_USBHS_OUTCSRL_CLRDATATOG;
- }
- }
- MXC_SYS_Crit_Exit();
-}
-
-/*-------------------------------------------------------------------
- * ISR
- *-------------------------------------------------------------------*/
-void dcd_int_handler(uint8_t rhport) {
- uint_fast8_t is, txis, rxis;
- uint32_t mxm_int, mxm_int_en, mxm_is;
- uint32_t saved_index;
-
- /* Save current index register */
- saved_index = MXC_USBHS->index;
-
- is = MXC_USBHS->intrusb; /* read and clear interrupt status */
- txis = MXC_USBHS->intrin; /* read and clear interrupt status */
- rxis = MXC_USBHS->introut; /* read and clear interrupt status */
-
- /* These USB interrupt flags are W1C. */
- /* Order of volatile accesses must be separated for IAR */
- mxm_int = MXC_USBHS->mxm_int;
- mxm_int_en = MXC_USBHS->mxm_int_en;
- mxm_is = mxm_int & mxm_int_en;
- MXC_USBHS->mxm_int = mxm_is;
-
- is &= MXC_USBHS->intrusben; /* Clear disabled interrupts */
-
- if (mxm_is & MXC_F_USBHS_MXM_INT_NOVBUS) {
- dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
- }
- if (is & MXC_F_USBHS_INTRUSB_SOF_INT) {
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
- }
- if (is & MXC_F_USBHS_INTRUSB_RESET_INT) {
- process_bus_reset(rhport);
- }
- if (is & MXC_F_USBHS_INTRUSB_RESUME_INT) {
- dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
- }
- if (is & MXC_F_USBHS_INTRUSB_SUSPEND_INT) {
- dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
- }
-
- txis &= MXC_USBHS->intrinen; /* Clear disabled interrupts */
- if (txis & MXC_F_USBHS_INTRIN_EP0_IN_INT) {
- process_ep0(rhport);
- txis &= ~TU_BIT(0);
- }
- while (txis) {
- unsigned const num = __builtin_ctz(txis);
- process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN));
- txis &= ~TU_BIT(num);
- }
- rxis &= MXC_USBHS->introuten; /* Clear disabled interrupts */
- while (rxis) {
- unsigned const num = __builtin_ctz(rxis);
- process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT));
- rxis &= ~TU_BIT(num);
- }
-
- /* Restore register index before exiting ISR */
- MXC_USBHS->index = saved_index;
-}
-
-#endif
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
index a817c5d6e..ee36656fd 100644
--- a/src/portable/mentor/musb/dcd_musb.c
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2021 Koji KITAYAMA
+ * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,8 +27,7 @@
#include "tusb_option.h"
-#if CFG_TUD_ENABLED && \
- TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+#if CFG_TUD_ENABLED
#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
/* GCC warns that an address may be unaligned, even though
@@ -35,43 +35,30 @@
_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
#endif
+#include "musb_type.h"
#include "device/dcd.h"
-#if TU_CHECK_MCU(OPT_MCU_MSP432E4)
- #include "musb_msp432e.h"
-
-#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129)
- #include "musb_tm4c.h"
-
- // HACK generalize later
- #include "musb_type.h"
- #define FIFO0_WORD FIFO0
- #define FIFO1_WORD FIFO1
-
+// Following symbols must be defined by port header
+// - musb_dcd_int_enable/disable/clear/get_enable
+// - musb_dcd_int_handler_enter/exit
+// - musb_dcd_epn_regs: Get memory mapped struct of end point registers
+// - musb_dcd_ep0_regs: Get memory mapped struct of EP0 registers
+// - musb_dcd_ctl_regs: Get memory mapped struct of control registers
+// - musb_dcd_ep_get_fifo_ptr: Gets the address of the provided EP's FIFO
+// - musb_dcd_setup_fifo/reset_fifo: Configuration of the EP's FIFO
+#if TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #include "musb_ti.h"
+#elif TU_CHECK_MCU(OPT_MCU_MAX32690, OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX78002)
+ #include "musb_max32.h"
#else
- #error "Unsupported MCUs"
+ #error "Unsupported MCU"
#endif
/*------------------------------------------------------------------
* MACRO TYPEDEF CONSTANT ENUM DECLARATION
*------------------------------------------------------------------*/
-#define REQUEST_TYPE_INVALID (0xFFu)
-
-typedef struct {
- uint_fast16_t beg; /* offset of including first element */
- uint_fast16_t end; /* offset of excluding the last element */
-} free_block_t;
-typedef struct TU_ATTR_PACKED {
- uint16_t TXMAXP;
- uint8_t TXCSRL;
- uint8_t TXCSRH;
- uint16_t RXMAXP;
- uint8_t RXCSRL;
- uint8_t RXCSRH;
- uint16_t RXCOUNT;
- uint16_t RESERVED[3];
-} hw_endpoint_t;
+#define REQUEST_TYPE_INVALID (0xFFu)
typedef union {
uint8_t u8;
@@ -92,7 +79,7 @@ typedef struct
uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
int8_t status_out;
pipe_state_t pipe0;
- pipe_state_t pipe[2][7]; /* pipe[direction][endpoint number - 1] */
+ pipe_state_t pipe[2][TUP_DCD_ENDPOINT_MAX-1]; /* pipe[direction][endpoint number - 1] */
uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */
} dcd_data_t;
@@ -102,126 +89,6 @@ typedef struct
static dcd_data_t _dcd;
-static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
-{
- free_block_t *cur = beg;
- for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
- return cur;
-}
-
-static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
-{
- free_block_t *p = find_containing_block(blks, blks + num, addr);
- TU_ASSERT(p != blks + num, -2);
- if (p->beg == addr) {
- /* Shrink block */
- p->beg = addr + size;
- if (p->beg != p->end) return 0;
- /* remove block */
- free_block_t *end = blks + num;
- while (p + 1 < end) {
- *p = *(p + 1);
- ++p;
- }
- return -1;
- } else {
- /* Split into 2 blocks */
- free_block_t tmp = {
- .beg = addr + size,
- .end = p->end
- };
- p->end = addr;
- if (p->beg == p->end) {
- if (tmp.beg != tmp.end) {
- *p = tmp;
- return 0;
- }
- /* remove block */
- free_block_t *end = blks + num;
- while (p + 1 < end) {
- *p = *(p + 1);
- ++p;
- }
- return -1;
- }
- if (tmp.beg == tmp.end) return 0;
- blks[num] = tmp;
- return 1;
- }
-}
-
-static inline unsigned free_block_size(free_block_t const *blk)
-{
- return blk->end - blk->beg;
-}
-
-#if 0
-static inline void print_block_list(free_block_t const *blk, unsigned num)
-{
- TU_LOG1("*************\r\n");
- for (unsigned i = 0; i < num; ++i) {
- TU_LOG1(" Blk%u %u %u\r\n", i, blk->beg, blk->end);
- ++blk;
- }
-}
-#else
-#define print_block_list(a,b)
-#endif
-
-static unsigned find_free_memory(uint_fast16_t size_in_log2_minus3)
-{
- free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)];
- unsigned num_blocks = 1;
-
- /* Initialize free memory block list */
- free_blocks[0].beg = 64 / 8;
- free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */
- for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
- uint_fast16_t addr;
- int num;
- USB0->EPIDX = i;
- addr = USB0->TXFIFOADD;
- if (addr) {
- unsigned sz = USB0->TXFIFOSZ;
- unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
- num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
- TU_ASSERT(-2 < num, 0);
- num_blocks += num;
- print_block_list(free_blocks, num_blocks);
- }
- addr = USB0->RXFIFOADD;
- if (addr) {
- unsigned sz = USB0->RXFIFOSZ;
- unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
- num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
- TU_ASSERT(-2 < num, 0);
- num_blocks += num;
- print_block_list(free_blocks, num_blocks);
- }
- }
- print_block_list(free_blocks, num_blocks);
-
- /* Find the best fit memory block */
- uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
- free_block_t const *min = NULL;
- uint_fast16_t min_sz = 0xFFFFu;
- free_block_t const *end = &free_blocks[num_blocks];
- for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
- uint_fast16_t sz = free_block_size(cur);
- if (sz < size_in_8byte_unit) continue;
- if (size_in_8byte_unit == sz) return cur->beg;
- if (sz < min_sz) min = cur;
- }
- TU_ASSERT(min, 0);
- return min->beg;
-}
-
-static inline volatile hw_endpoint_t* edpt_regs(unsigned epnum_minus1)
-{
- volatile hw_endpoint_t *regs = (volatile hw_endpoint_t*)((uintptr_t)&USB0->TXMAXP1);
- return regs + epnum_minus1;
-}
-
static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
{
volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
@@ -287,8 +154,10 @@ static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigne
static void process_setup_packet(uint8_t rhport)
{
uint32_t *p = (void*)&_dcd.setup_packet;
- p[0] = USB0->FIFO0_WORD;
- p[1] = USB0->FIFO0_WORD;
+ volatile uint32_t *fifo_ptr = musb_dcd_ep_get_fifo_ptr(rhport, 0);
+ volatile musb_dcd_ep0_regs_t* ep0_regs = musb_dcd_ep0_regs(rhport);
+ p[0] = *fifo_ptr;
+ p[1] = *fifo_ptr;
_dcd.pipe0.buf = NULL;
_dcd.pipe0.length = 0;
@@ -299,12 +168,13 @@ static void process_setup_packet(uint8_t rhport)
_dcd.remaining_ctrl = len;
const unsigned dir_in = tu_edpt_dir(_dcd.setup_packet.bmRequestType);
/* Clear RX FIFO and reverse the transaction direction */
- if (len && dir_in) USB0->CSRL0 = USB_CSRL0_RXRDYC;
+ if (len && dir_in) ep0_regs->CSRL0 = USB_CSRL0_RXRDYC;
}
-static bool handle_xfer_in(uint_fast8_t ep_addr)
+static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr)
{
- unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ unsigned epnum = tu_edpt_number(ep_addr);
+ unsigned epnum_minus1 = epnum - 1;
pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
const unsigned rem = pipe->remaining;
@@ -313,30 +183,32 @@ static bool handle_xfer_in(uint_fast8_t ep_addr)
return true;
}
- volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
+ volatile musb_dcd_epn_regs_t *regs = musb_dcd_epn_regs(rhport, epnum);
const unsigned mps = regs->TXMAXP;
const unsigned len = TU_MIN(mps, rem);
void *buf = pipe->buf;
+ volatile void *fifo_ptr = musb_dcd_ep_get_fifo_ptr(rhport, epnum);
// TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem);
if (len) {
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_IN);
+ pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_IN);
} else {
- pipe_write_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len);
+ pipe_write_packet(buf, fifo_ptr, len);
pipe->buf = buf + len;
}
pipe->remaining = rem - len;
}
regs->TXCSRL = USB_TXCSRL1_TXRDY;
- // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum_minus1 + 1, regs->TXCSRL, rem - len);
+ // TU_LOG1(" TXCSRL%d = %x %d\r\n", epnum, regs->TXCSRL, rem - len);
return false;
}
-static bool handle_xfer_out(uint_fast8_t ep_addr)
+static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr)
{
- unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ unsigned epnum = tu_edpt_number(ep_addr);
+ unsigned epnum_minus1 = epnum - 1;
pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
- volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
+ volatile musb_dcd_epn_regs_t *regs = musb_dcd_epn_regs(rhport, epnum);
// TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, regs->RXCSRL);
TU_ASSERT(regs->RXCSRL & USB_RXCSRL1_RXRDY);
@@ -346,11 +218,12 @@ static bool handle_xfer_out(uint_fast8_t ep_addr)
const unsigned vld = regs->RXCOUNT;
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
void *buf = pipe->buf;
+ volatile void *fifo_ptr = musb_dcd_ep_get_fifo_ptr(rhport, epnum);
if (len) {
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff(buf, &USB0->FIFO1_WORD + epnum_minus1, len, TUSB_DIR_OUT);
+ pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_OUT);
} else {
- pipe_read_packet(buf, &USB0->FIFO1_WORD + epnum_minus1, len);
+ pipe_read_packet(buf, fifo_ptr, len);
pipe->buf = buf + len;
}
pipe->remaining = rem - len;
@@ -365,9 +238,8 @@ static bool handle_xfer_out(uint_fast8_t ep_addr)
static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
{
- (void)rhport;
-
- unsigned epnum_minus1 = tu_edpt_number(ep_addr) - 1;
+ unsigned epnum = tu_edpt_number(ep_addr);
+ unsigned epnum_minus1 = epnum - 1;
unsigned dir_in = tu_edpt_dir(ep_addr);
pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1];
@@ -376,9 +248,9 @@ static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16
pipe->remaining = total_bytes;
if (dir_in) {
- handle_xfer_in(ep_addr);
+ handle_xfer_in(rhport, ep_addr);
} else {
- volatile hw_endpoint_t *regs = edpt_regs(epnum_minus1);
+ volatile musb_dcd_epn_regs_t *regs = musb_dcd_epn_regs(rhport, epnum);
if (regs->RXCSRL & USB_RXCSRL1_RXRDY) regs->RXCSRL = 0;
}
return true;
@@ -388,7 +260,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
{
(void)rhport;
TU_ASSERT(total_bytes <= 64); /* Current implementation supports for only up to 64 bytes. */
-
+ volatile musb_dcd_ep0_regs_t* ep0_regs = musb_dcd_ep0_regs(rhport);
const unsigned req = _dcd.setup_packet.bmRequestType;
TU_ASSERT(req != REQUEST_TYPE_INVALID || total_bytes == 0);
@@ -399,7 +271,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
* may have already finished and received the next setup packet
* without calling this function, so we have no choice but to
* invoke the callback function of status packet here. */
- // TU_LOG1(" STATUS OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ // TU_LOG1(" STATUS OUT ep0_regs->CSRL0 = %x\r\n", ep0_regs->CSRL0);
_dcd.status_out = 0;
if (req == REQUEST_TYPE_INVALID) {
dcd_event_xfer_complete(rhport, ep_addr, total_bytes, XFER_RESULT_SUCCESS, false);
@@ -415,8 +287,9 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
TU_ASSERT(total_bytes <= _dcd.remaining_ctrl);
const unsigned rem = _dcd.remaining_ctrl;
const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
+ volatile void *fifo_ptr = musb_dcd_ep_get_fifo_ptr(rhport, 0);
if (dir_in) {
- pipe_write_packet(buffer, &USB0->FIFO0_WORD, len);
+ pipe_write_packet(buffer, fifo_ptr, len);
_dcd.pipe0.buf = buffer + len;
_dcd.pipe0.length = len;
@@ -427,45 +300,46 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
_dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID; /* Change to STATUS/SETUP stage */
_dcd.status_out = 1;
/* Flush TX FIFO and reverse the transaction direction. */
- USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
+ ep0_regs->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
} else {
- USB0->CSRL0 = USB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */
+ ep0_regs->CSRL0 = USB_CSRL0_TXRDY; /* Flush TX FIFO to return ACK. */
}
- // TU_LOG1(" IN USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ // TU_LOG1(" IN ep0_regs->CSRL0 = %x\r\n", ep0_regs->CSRL0);
} else {
- // TU_LOG1(" OUT USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ // TU_LOG1(" OUT ep0_regs->CSRL0 = %x\r\n", ep0_regs->CSRL0);
_dcd.pipe0.buf = buffer;
_dcd.pipe0.length = len;
_dcd.pipe0.remaining = len;
- USB0->CSRL0 = USB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */
+ ep0_regs->CSRL0 = USB_CSRL0_RXRDYC; /* Clear RX FIFO to return ACK. */
}
} else if (dir_in) {
- // TU_LOG1(" STATUS IN USB0->CSRL0 = %x\r\n", USB0->CSRL0);
+ // TU_LOG1(" STATUS IN ep0_regs->CSRL0 = %x\r\n", ep0_regs->CSRL0);
_dcd.pipe0.buf = NULL;
_dcd.pipe0.length = 0;
_dcd.pipe0.remaining = 0;
/* Clear RX FIFO and reverse the transaction direction */
- USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND;
+ ep0_regs->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND;
}
return true;
}
static void process_ep0(uint8_t rhport)
{
- uint_fast8_t csrl = USB0->CSRL0;
+ volatile musb_dcd_ep0_regs_t* ep0_regs = musb_dcd_ep0_regs(rhport);
+ uint_fast8_t csrl = ep0_regs->CSRL0;
- // TU_LOG1(" EP0 USB0->CSRL0 = %x\r\n", csrl);
+ // TU_LOG1(" EP0 ep0_regs->CSRL0 = %x\r\n", csrl);
if (csrl & USB_CSRL0_STALLED) {
/* Returned STALL packet to HOST. */
- USB0->CSRL0 = 0; /* Clear STALL */
+ ep0_regs->CSRL0 = 0; /* Clear STALL */
return;
}
unsigned req = _dcd.setup_packet.bmRequestType;
if (csrl & USB_CSRL0_SETEND) {
TU_LOG1(" ABORT by the next packets\r\n");
- USB0->CSRL0 = USB_CSRL0_SETENDC;
+ ep0_regs->CSRL0 = USB_CSRL0_SETENDC;
if (req != REQUEST_TYPE_INVALID && _dcd.pipe0.buf) {
/* DATA stage was aborted by receiving STATUS or SETUP packet. */
_dcd.pipe0.buf = NULL;
@@ -483,16 +357,17 @@ static void process_ep0(uint8_t rhport)
/* Received SETUP or DATA OUT packet */
if (req == REQUEST_TYPE_INVALID) {
/* SETUP */
- TU_ASSERT(sizeof(tusb_control_request_t) == USB0->COUNT0,);
+ TU_ASSERT(sizeof(tusb_control_request_t) == ep0_regs->COUNT0,);
process_setup_packet(rhport);
return;
}
if (_dcd.pipe0.buf) {
/* DATA OUT */
- const unsigned vld = USB0->COUNT0;
+ const unsigned vld = ep0_regs->COUNT0;
const unsigned rem = _dcd.pipe0.remaining;
const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
- pipe_read_packet(_dcd.pipe0.buf, &USB0->FIFO0_WORD, len);
+ volatile void *fifo_ptr = musb_dcd_ep_get_fifo_ptr(rhport, 0);
+ pipe_read_packet(_dcd.pipe0.buf, fifo_ptr, len);
_dcd.pipe0.remaining = rem - len;
_dcd.remaining_ctrl -= len;
@@ -506,13 +381,15 @@ static void process_ep0(uint8_t rhport)
return;
}
+ volatile musb_dcd_ctl_regs_t *ctrl_regs = musb_dcd_ctl_regs(rhport);
+
/* When CSRL0 is zero, it means that completion of sending a any length packet
* or receiving a zero length packet. */
if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir(req)) {
/* STATUS IN */
if (*(const uint16_t*)(uintptr_t)&_dcd.setup_packet == 0x0500) {
/* The address must be changed on completion of the control transfer. */
- USB0->FADDR = (uint8_t)_dcd.setup_packet.wValue;
+ ctrl_regs->FADDR = (uint8_t)_dcd.setup_packet.wValue;
}
_dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
dcd_event_xfer_complete(rhport,
@@ -535,27 +412,28 @@ static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr)
{
bool completed;
const unsigned dir_in = tu_edpt_dir(ep_addr);
- const unsigned epn_minus1 = tu_edpt_number(ep_addr) - 1;
+ const unsigned epn = tu_edpt_number(ep_addr);
+ const unsigned epn_minus1 = epn - 1;
- volatile hw_endpoint_t *regs = edpt_regs(epn_minus1);
+ volatile musb_dcd_epn_regs_t *regs = musb_dcd_epn_regs(rhport, epn);
if (dir_in) {
- // TU_LOG1(" TXCSRL%d = %x\r\n", epn_minus1 + 1, regs->TXCSRL);
+ // TU_LOG1(" TXCSRL%d = %x\r\n", epn, regs->TXCSRL);
if (regs->TXCSRL & USB_TXCSRL1_STALLED) {
regs->TXCSRL &= ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_UNDRN);
return;
}
- completed = handle_xfer_in(ep_addr);
+ completed = handle_xfer_in(rhport, ep_addr);
} else {
- // TU_LOG1(" RXCSRL%d = %x\r\n", epn_minus1 + 1, regs->RXCSRL);
+ // TU_LOG1(" RXCSRL%d = %x\r\n", epn, regs->RXCSRL);
if (regs->RXCSRL & USB_RXCSRL1_STALLED) {
regs->RXCSRL &= ~(USB_RXCSRL1_STALLED | USB_RXCSRL1_OVER);
return;
}
- completed = handle_xfer_out(ep_addr);
+ completed = handle_xfer_out(rhport, ep_addr);
}
if (completed) {
- pipe_state_t *pipe = &_dcd.pipe[dir_in][tu_edpt_number(ep_addr) - 1];
+ pipe_state_t *pipe = &_dcd.pipe[dir_in][epn_minus1];
dcd_event_xfer_complete(rhport, ep_addr,
pipe->length - pipe->remaining,
XFER_RESULT_SUCCESS, true);
@@ -564,6 +442,7 @@ static void process_edpt_n(uint8_t rhport, uint_fast8_t ep_addr)
static void process_bus_reset(uint8_t rhport)
{
+ volatile musb_dcd_ctl_regs_t *ctrl_regs = musb_dcd_ctl_regs(rhport);
/* When bmRequestType is REQUEST_TYPE_INVALID(0xFF),
* a control transfer state is SETUP or STATUS stage. */
_dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
@@ -571,18 +450,15 @@ static void process_bus_reset(uint8_t rhport)
/* When pipe0.buf has not NULL, DATA stage works in progress. */
_dcd.pipe0.buf = NULL;
- USB0->TXIE = 1; /* Enable only EP0 */
- USB0->RXIE = 0;
+ ctrl_regs->TXIE = 1; /* Enable only EP0 */
+ ctrl_regs->RXIE = 0;
/* Clear FIFO settings */
for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
- USB0->EPIDX = i;
- USB0->TXFIFOSZ = 0;
- USB0->TXFIFOADD = 0;
- USB0->RXFIFOSZ = 0;
- USB0->RXFIFOADD = 0;
+ musb_dcd_reset_fifo(rhport, i, 0);
+ musb_dcd_reset_fifo(rhport, i, 1);
}
- dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+ dcd_event_bus_reset(rhport, (ctrl_regs->POWER & USB_POWER_HSMODE) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true);
}
/*------------------------------------------------------------------
@@ -591,61 +467,60 @@ static void process_bus_reset(uint8_t rhport)
void dcd_init(uint8_t rhport)
{
- (void)rhport;
- USB0->IE |= USB_IE_SUSPND;
- NVIC_ClearPendingIRQ(USB0_IRQn);
-
+ volatile musb_dcd_ctl_regs_t *ctrl_regs = musb_dcd_ctl_regs(rhport);
+ ctrl_regs->IE |= USB_IE_SUSPND;
+ musb_dcd_int_clear(rhport);
+ musb_dcd_phy_init(rhport);
dcd_connect(rhport);
}
void dcd_int_enable(uint8_t rhport)
{
- (void)rhport;
- NVIC_EnableIRQ(USB0_IRQn);
+ musb_dcd_int_enable(rhport);
}
void dcd_int_disable(uint8_t rhport)
{
- (void)rhport;
- NVIC_DisableIRQ(USB0_IRQn);
+ musb_dcd_int_disable(rhport);
}
// Receive Set Address request, mcu port must also include status IN response
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
- (void)rhport;
(void)dev_addr;
+ volatile musb_dcd_ep0_regs_t* ep0_regs = musb_dcd_ep0_regs(rhport);
_dcd.pipe0.buf = NULL;
_dcd.pipe0.length = 0;
_dcd.pipe0.remaining = 0;
/* Clear RX FIFO to return ACK. */
- USB0->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND;
+ ep0_regs->CSRL0 = USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND;
}
// Wake up host
void dcd_remote_wakeup(uint8_t rhport)
{
- (void)rhport;
- USB0->POWER |= USB_POWER_RESUME;
+ volatile musb_dcd_ctl_regs_t *ctrl_regs = musb_dcd_ctl_regs(rhport);
+ ctrl_regs->POWER |= USB_POWER_RESUME;
unsigned cnt = SystemCoreClock / 1000;
while (cnt--) __NOP();
- USB0->POWER &= ~USB_POWER_RESUME;
+ ctrl_regs->POWER &= ~USB_POWER_RESUME;
}
// Connect by enabling internal pull-up resistor on D+/D-
void dcd_connect(uint8_t rhport)
{
- (void)rhport;
- USB0->POWER |= USB_POWER_SOFTCONN;
+ volatile musb_dcd_ctl_regs_t *ctrl_regs = musb_dcd_ctl_regs(rhport);
+ ctrl_regs->POWER |= TUD_OPT_HIGH_SPEED ? USB_POWER_HSENAB : 0;
+ ctrl_regs->POWER |= USB_POWER_SOFTCONN;
}
// Disconnect by disabling internal pull-up resistor on D+/D-
void dcd_disconnect(uint8_t rhport)
{
- (void)rhport;
- USB0->POWER &= ~USB_POWER_SOFTCONN;
+ volatile musb_dcd_ctl_regs_t *ctrl_regs = musb_dcd_ctl_regs(rhport);
+ ctrl_regs->POWER &= ~USB_POWER_SOFTCONN;
}
void dcd_sof_enable(uint8_t rhport, bool en)
@@ -663,8 +538,6 @@ void dcd_sof_enable(uint8_t rhport, bool en)
// Configure endpoint's registers according to descriptor
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_in = tu_edpt_dir(ep_addr);
@@ -678,7 +551,8 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
pipe->length = 0;
pipe->remaining = 0;
- volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+ volatile musb_dcd_epn_regs_t *regs = musb_dcd_epn_regs(rhport, epn);
+ volatile musb_dcd_ctl_regs_t *ctrl_regs = musb_dcd_ctl_regs(rhport);
if (dir_in) {
regs->TXMAXP = mps;
regs->TXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_TXCSRH1_ISO : 0;
@@ -686,7 +560,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
else
regs->TXCSRL = USB_TXCSRL1_CLRDT;
- USB0->TXIE |= TU_BIT(epn);
+ ctrl_regs->TXIE |= TU_BIT(epn);
} else {
regs->RXMAXP = mps;
regs->RXCSRH = (xfer == TUSB_XFER_ISOCHRONOUS) ? USB_RXCSRH1_ISO : 0;
@@ -694,36 +568,25 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
else
regs->RXCSRL = USB_RXCSRL1_CLRDT;
- USB0->RXIE |= TU_BIT(epn);
+ ctrl_regs->RXIE |= TU_BIT(epn);
}
/* Setup FIFO */
- int size_in_log2_minus3 = 28 - TU_MIN(28, __CLZ((uint32_t)mps));
- if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
- unsigned addr = find_free_memory(size_in_log2_minus3);
- TU_ASSERT(addr);
-
- USB0->EPIDX = epn;
- if (dir_in) {
- USB0->TXFIFOADD = addr;
- USB0->TXFIFOSZ = size_in_log2_minus3;
- } else {
- USB0->RXFIFOADD = addr;
- USB0->RXFIFOSZ = size_in_log2_minus3;
- }
+ musb_dcd_setup_fifo(rhport, epn, dir_in, mps);
return true;
}
void dcd_edpt_close_all(uint8_t rhport)
{
- (void) rhport;
- volatile hw_endpoint_t *regs = (volatile hw_endpoint_t *)(uintptr_t)&USB0->TXMAXP1;
- unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
- NVIC_DisableIRQ(USB0_IRQn);
- USB0->TXIE = 1; /* Enable only EP0 */
- USB0->RXIE = 0;
+ volatile musb_dcd_epn_regs_t *regs;
+ volatile musb_dcd_ctl_regs_t *ctrl_regs = musb_dcd_ctl_regs(rhport);
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
+ ctrl_regs->TXIE = 1; /* Enable only EP0 */
+ ctrl_regs->RXIE = 0;
for (unsigned i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ regs = musb_dcd_epn_regs(rhport, i);
regs->TXMAXP = 0;
regs->TXCSRH = 0;
if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
@@ -738,50 +601,41 @@ void dcd_edpt_close_all(uint8_t rhport)
else
regs->RXCSRL = USB_RXCSRL1_CLRDT;
- USB0->EPIDX = i;
- USB0->TXFIFOSZ = 0;
- USB0->TXFIFOADD = 0;
- USB0->RXFIFOSZ = 0;
- USB0->RXFIFOADD = 0;
+ musb_dcd_reset_fifo(rhport, i, 0);
+ musb_dcd_reset_fifo(rhport, i, 1);
+
}
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ if (ie) musb_dcd_int_enable(rhport);
}
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
{
- (void)rhport;
unsigned const epn = tu_edpt_number(ep_addr);
unsigned const dir_in = tu_edpt_dir(ep_addr);
- hw_endpoint_t volatile *regs = edpt_regs(epn - 1);
- unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
- NVIC_DisableIRQ(USB0_IRQn);
+ volatile musb_dcd_epn_regs_t *regs = musb_dcd_epn_regs(rhport, epn);
+ volatile musb_dcd_ctl_regs_t *ctrl_regs = musb_dcd_ctl_regs(rhport);
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
if (dir_in) {
- USB0->TXIE &= ~TU_BIT(epn);
+ ctrl_regs->TXIE &= ~TU_BIT(epn);
regs->TXMAXP = 0;
regs->TXCSRH = 0;
if (regs->TXCSRL & USB_TXCSRL1_TXRDY)
regs->TXCSRL = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH;
else
regs->TXCSRL = USB_TXCSRL1_CLRDT;
-
- USB0->EPIDX = epn;
- USB0->TXFIFOSZ = 0;
- USB0->TXFIFOADD = 0;
} else {
- USB0->RXIE &= ~TU_BIT(epn);
+ ctrl_regs->RXIE &= ~TU_BIT(epn);
regs->RXMAXP = 0;
regs->RXCSRH = 0;
if (regs->RXCSRL & USB_RXCSRL1_RXRDY)
regs->RXCSRL = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH;
else
regs->RXCSRL = USB_RXCSRL1_CLRDT;
-
- USB0->EPIDX = epn;
- USB0->RXFIFOSZ = 0;
- USB0->RXFIFOADD = 0;
}
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ musb_dcd_reset_fifo(rhport, epn, dir_in);
+ if (ie) musb_dcd_int_enable(rhport);
}
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
@@ -791,14 +645,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
bool ret;
// TU_LOG1("X %x %d\r\n", ep_addr, total_bytes);
unsigned const epnum = tu_edpt_number(ep_addr);
- unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
- NVIC_DisableIRQ(USB0_IRQn);
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
if (epnum) {
_dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1);
ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes);
} else
ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ if (ie) musb_dcd_int_enable(rhport);
return ret;
}
@@ -810,29 +664,29 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
// TU_LOG1("X %x %d\r\n", ep_addr, total_bytes);
unsigned const epnum = tu_edpt_number(ep_addr);
TU_ASSERT(epnum);
- unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
- NVIC_DisableIRQ(USB0_IRQn);
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
_dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1);
ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes);
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ if (ie) musb_dcd_int_enable(rhport);
return ret;
}
// Stall endpoint
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
- (void)rhport;
unsigned const epn = tu_edpt_number(ep_addr);
- unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
- NVIC_DisableIRQ(USB0_IRQn);
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
if (0 == epn) {
+ volatile musb_dcd_ep0_regs_t* ep0_regs = musb_dcd_ep0_regs(rhport);
if (!ep_addr) { /* Ignore EP80 */
_dcd.setup_packet.bmRequestType = REQUEST_TYPE_INVALID;
_dcd.pipe0.buf = NULL;
- USB0->CSRL0 = USB_CSRL0_STALL;
+ ep0_regs->CSRL0 = USB_CSRL0_STALL;
}
} else {
- volatile hw_endpoint_t *regs = edpt_regs(epn - 1);
+ volatile musb_dcd_epn_regs_t *regs = musb_dcd_epn_regs(rhport, epn);
if (tu_edpt_dir(ep_addr)) { /* IN */
regs->TXCSRL = USB_TXCSRL1_STALL;
} else { /* OUT */
@@ -840,7 +694,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
regs->RXCSRL = USB_RXCSRL1_STALL;
}
}
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ if (ie) musb_dcd_int_enable(rhport);
}
// clear stall, data toggle is also reset to DATA0
@@ -848,15 +702,15 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
unsigned const epn = tu_edpt_number(ep_addr);
- hw_endpoint_t volatile *regs = edpt_regs(epn - 1);
- unsigned const ie = NVIC_GetEnableIRQ(USB0_IRQn);
- NVIC_DisableIRQ(USB0_IRQn);
+ musb_dcd_epn_regs_t volatile *regs = musb_dcd_epn_regs(rhport, epn);
+ unsigned const ie = musb_dcd_get_int_enable(rhport);
+ musb_dcd_int_disable(rhport);
if (tu_edpt_dir(ep_addr)) { /* IN */
regs->TXCSRL = USB_TXCSRL1_CLRDT;
} else { /* OUT */
regs->RXCSRL = USB_RXCSRL1_CLRDT;
}
- if (ie) NVIC_EnableIRQ(USB0_IRQn);
+ if (ie) musb_dcd_int_enable(rhport);
}
/*-------------------------------------------------------------------
@@ -865,13 +719,18 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
void dcd_int_handler(uint8_t rhport)
{
uint_fast8_t is, txis, rxis;
+ volatile musb_dcd_ctl_regs_t *ctrl_regs;
- is = USB0->IS; /* read and clear interrupt status */
- txis = USB0->TXIS; /* read and clear interrupt status */
- rxis = USB0->RXIS; /* read and clear interrupt status */
+ //Part specific ISR setup/entry
+ musb_dcd_int_handler_enter(rhport);
+
+ ctrl_regs = musb_dcd_ctl_regs(rhport);
+ is = ctrl_regs->IS; /* read and clear interrupt status */
+ txis = ctrl_regs->TXIS; /* read and clear interrupt status */
+ rxis = ctrl_regs->RXIS; /* read and clear interrupt status */
// TU_LOG1("D%2x T%2x R%2x\r\n", is, txis, rxis);
- is &= USB0->IE; /* Clear disabled interrupts */
+ is &= ctrl_regs->IE; /* Clear disabled interrupts */
if (is & USB_IS_DISCON) {
}
if (is & USB_IS_SOF) {
@@ -887,7 +746,7 @@ void dcd_int_handler(uint8_t rhport)
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
}
- txis &= USB0->TXIE; /* Clear disabled interrupts */
+ txis &= ctrl_regs->TXIE; /* Clear disabled interrupts */
if (txis & USB_TXIE_EP0) {
process_ep0(rhport);
txis &= ~TU_BIT(0);
@@ -897,12 +756,15 @@ void dcd_int_handler(uint8_t rhport)
process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_IN));
txis &= ~TU_BIT(num);
}
- rxis &= USB0->RXIE; /* Clear disabled interrupts */
+ rxis &= ctrl_regs->RXIE; /* Clear disabled interrupts */
while (rxis) {
unsigned const num = __builtin_ctz(rxis);
process_edpt_n(rhport, tu_edpt_addr(num, TUSB_DIR_OUT));
rxis &= ~TU_BIT(num);
}
+
+ //Part specific ISR exit
+ musb_dcd_int_handler_exit(rhport);
}
#endif
diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c
index 5312c2812..8fc225676 100644
--- a/src/portable/mentor/musb/hcd_musb.c
+++ b/src/portable/mentor/musb/hcd_musb.c
@@ -37,16 +37,10 @@ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
#include "host/hcd.h"
-#if TU_CHECK_MCU(OPT_MCU_MSP432E4)
- #include "musb_msp432e.h"
-
-#elif TU_CHECK_MCU(OPT_MCU_TM4C123, OPT_MCU_TM4C129)
- #include "musb_tm4c.h"
-
- // HACK generalize later
- #include "musb_type.h"
- #define FIFO0_WORD FIFO0
+#include "musb_type.h"
+#if TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #include "musb_ti.h"
#else
#error "Unsupported MCUs"
#endif
diff --git a/src/portable/mentor/musb/musb_max32.h b/src/portable/mentor/musb/musb_max32.h
new file mode 100644
index 000000000..297a695f8
--- /dev/null
+++ b/src/portable/mentor/musb/musb_max32.h
@@ -0,0 +1,221 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc)
+ *
+ * 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_MUSB_MAX32_H_
+#define _TUSB_MUSB_MAX32_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#if TU_CHECK_MCU(OPT_MCU_MAX32690, OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX78002)
+ #include "mxc_device.h"
+ #include "usbhs_regs.h"
+#else
+ #error "Unsupported MCUs"
+#endif
+
+
+#if CFG_TUD_ENABLED
+#define USBHS_M31_CLOCK_RECOVERY
+
+// Mapping of peripheral instances to port. Currently just 1.
+static mxc_usbhs_regs_t* const musb_periph_inst[] = {
+ MXC_USBHS
+};
+
+// Mapping of IRQ numbers to port. Currently just 1.
+static const IRQn_Type musb_irqs[] = {
+ USB_IRQn
+};
+
+TU_ATTR_ALWAYS_INLINE
+static inline void musb_dcd_int_enable(uint8_t rhport)
+{
+ NVIC_EnableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void musb_dcd_int_disable(uint8_t rhport)
+{
+ NVIC_DisableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline unsigned musb_dcd_get_int_enable(uint8_t rhport)
+{
+ return NVIC_GetEnableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void musb_dcd_int_clear(uint8_t rhport)
+{
+ NVIC_ClearPendingIRQ(musb_irqs[rhport]);
+}
+
+//Used to save and restore user's register map when interrupt occurs
+static volatile unsigned isr_saved_index = 0;
+
+static inline void musb_dcd_int_handler_enter(uint8_t rhport)
+{
+ uint32_t mxm_int, mxm_int_en, mxm_is;
+
+ //save current register index
+ isr_saved_index = musb_periph_inst[rhport]->index;
+
+ //Handle PHY specific events
+ mxm_int = musb_periph_inst[rhport]->mxm_int;
+ mxm_int_en = musb_periph_inst[rhport]->mxm_int_en;
+ mxm_is = mxm_int & mxm_int_en;
+ musb_periph_inst[rhport]->mxm_int = mxm_is;
+
+ if (mxm_is & MXC_F_USBHS_MXM_INT_NOVBUS) {
+ dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
+ }
+}
+
+static inline void musb_dcd_int_handler_exit(uint8_t rhport)
+{
+ //restore register index
+ musb_periph_inst[rhport]->index = isr_saved_index;
+}
+
+static inline void musb_dcd_phy_init(uint8_t rhport)
+{
+ //Interrupt for VBUS disconnect
+ musb_periph_inst[rhport]->mxm_int_en |= MXC_F_USBHS_MXM_INT_EN_NOVBUS;
+
+ musb_dcd_int_clear(rhport);
+
+ //Unsuspend the MAC
+ musb_periph_inst[rhport]->mxm_suspend = 0;
+
+ // Configure PHY
+ musb_periph_inst[rhport]->m31_phy_xcfgi_31_0 = (0x1 << 3) | (0x1 << 11);
+ musb_periph_inst[rhport]->m31_phy_xcfgi_63_32 = 0;
+ musb_periph_inst[rhport]->m31_phy_xcfgi_95_64 = 0x1 << (72 - 64);
+ musb_periph_inst[rhport]->m31_phy_xcfgi_127_96 = 0;
+
+
+ #ifdef USBHS_M31_CLOCK_RECOVERY
+ musb_periph_inst[rhport]->m31_phy_noncry_rstb = 1;
+ musb_periph_inst[rhport]->m31_phy_noncry_en = 1;
+ musb_periph_inst[rhport]->m31_phy_outclksel = 0;
+ musb_periph_inst[rhport]->m31_phy_coreclkin = 0;
+ musb_periph_inst[rhport]->m31_phy_xtlsel = 2; /* Select 25 MHz clock */
+ #else
+ musb_periph_inst[rhport]->m31_phy_noncry_rstb = 0;
+ musb_periph_inst[rhport]->m31_phy_noncry_en = 0;
+ musb_periph_inst[rhport]->m31_phy_outclksel = 1;
+ musb_periph_inst[rhport]->m31_phy_coreclkin = 1;
+ musb_periph_inst[rhport]->m31_phy_xtlsel = 3; /* Select 30 MHz clock */
+ #endif
+ musb_periph_inst[rhport]->m31_phy_pll_en = 1;
+ musb_periph_inst[rhport]->m31_phy_oscouten = 1;
+
+ /* Reset PHY */
+ musb_periph_inst[rhport]->m31_phy_ponrst = 0;
+ musb_periph_inst[rhport]->m31_phy_ponrst = 1;
+}
+
+static inline volatile musb_dcd_ctl_regs_t* musb_dcd_ctl_regs(uint8_t rhport)
+{
+ volatile musb_dcd_ctl_regs_t *regs = (volatile musb_dcd_ctl_regs_t*)((uintptr_t)&(musb_periph_inst[rhport]->faddr));
+ return regs;
+}
+
+static inline volatile musb_dcd_epn_regs_t* musb_dcd_epn_regs(uint8_t rhport, unsigned epnum)
+{
+ //Need to set index to map EP registers
+ musb_periph_inst[rhport]->index = epnum;
+ volatile musb_dcd_epn_regs_t *regs = (volatile musb_dcd_epn_regs_t*)((uintptr_t)&(musb_periph_inst[rhport]->inmaxp));
+ return regs;
+}
+
+static inline volatile musb_dcd_ep0_regs_t* musb_dcd_ep0_regs(uint8_t rhport)
+{
+ //Need to set index to map EP0 registers
+ musb_periph_inst[rhport]->index = 0;
+ volatile musb_dcd_ep0_regs_t *regs = (volatile musb_dcd_ep0_regs_t*)((uintptr_t)&(musb_periph_inst[rhport]->csr0));
+ return regs;
+}
+
+static volatile void *musb_dcd_ep_get_fifo_ptr(uint8_t rhport, unsigned epnum)
+{
+ volatile uint32_t *ptr;
+
+ ptr = &(musb_periph_inst[rhport]->fifo0);
+ ptr += epnum;
+
+ return (volatile void *) ptr;
+}
+
+
+static inline void musb_dcd_setup_fifo(uint8_t rhport, unsigned epnum, unsigned dir_in, unsigned mps)
+{
+ (void)mps;
+
+ //Most likely the caller has already grabbed the right register block. But
+ //as a precaution save and restore the register bank anyways
+ unsigned saved_index = musb_periph_inst[rhport]->index;
+
+ musb_periph_inst[rhport]->index = epnum;
+
+ //Disable double buffering
+ if(dir_in) {
+ musb_periph_inst[rhport]->incsru |= (MXC_F_USBHS_INCSRU_DPKTBUFDIS | MXC_F_USBHS_INCSRU_MODE);
+ } else {
+ musb_periph_inst[rhport]->outcsru |= (MXC_F_USBHS_OUTCSRU_DPKTBUFDIS);
+ }
+
+ musb_periph_inst[rhport]->index = saved_index;
+}
+
+static inline void musb_dcd_reset_fifo(uint8_t rhport, unsigned epnum, unsigned dir_in)
+{
+ //Most likely the caller has already grabbed the right register block. But
+ //as a precaution save and restore the register bank anyways
+ unsigned saved_index = musb_periph_inst[rhport]->index;
+
+ musb_periph_inst[rhport]->index = epnum;
+
+ //Disable double buffering
+ if(dir_in) {
+ musb_periph_inst[rhport]->incsru |= (MXC_F_USBHS_INCSRU_DPKTBUFDIS);
+ } else {
+ musb_periph_inst[rhport]->outcsru |= (MXC_F_USBHS_OUTCSRU_DPKTBUFDIS);
+ }
+
+ musb_periph_inst[rhport]->index = saved_index;
+}
+
+#endif // CFG_TUD_ENABLED
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // _TUSB_MUSB_MAX32_H_
diff --git a/src/portable/mentor/musb/musb_msp432e.h b/src/portable/mentor/musb/musb_msp432e.h
deleted file mode 100644
index fce21de88..000000000
--- a/src/portable/mentor/musb/musb_msp432e.h
+++ /dev/null
@@ -1,40 +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 _TUSB_MUSB_MSP432E_H_
-#define _TUSB_MUSB_MSP432E_H_
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#include "msp.h"
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif
diff --git a/src/portable/mentor/musb/musb_ti.h b/src/portable/mentor/musb/musb_ti.h
new file mode 100644
index 000000000..dbf82f391
--- /dev/null
+++ b/src/portable/mentor/musb/musb_ti.h
@@ -0,0 +1,285 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024, Brent Kowal (Analog Devices, Inc)
+ *
+ * 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_MUSB_TI_H_
+#define _TUSB_MUSB_TI_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_TM4C123
+ #include "TM4C123.h"
+ #define FIFO0_WORD FIFO0
+ #define FIFO1_WORD FIFO1
+//#elif CFG_TUSB_MCU == OPT_MCU_TM4C129
+#elif CFG_TUSB_MCU == OPT_MCU_MSP432E4
+ #include "msp.h"
+#else
+ #error "Unsupported MCUs"
+#endif
+
+
+// Header supports both device and host modes. Only include whats necessary
+#if CFG_TUD_ENABLED
+
+// Mapping of peripheral instances to port. Currently just 1.
+static USB0_Type* const musb_periph_inst[] = {
+ USB0
+};
+
+// Mapping of IRQ numbers to port. Currently just 1.
+static const IRQn_Type musb_irqs[] = {
+ USB0_IRQn
+};
+
+static inline void musb_dcd_phy_init(uint8_t rhport){
+ (void)rhport;
+ //Nothing to do for this part
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void musb_dcd_int_enable(uint8_t rhport)
+{
+ NVIC_EnableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void musb_dcd_int_disable(uint8_t rhport)
+{
+ NVIC_DisableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline unsigned musb_dcd_get_int_enable(uint8_t rhport)
+{
+ return NVIC_GetEnableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE
+static inline void musb_dcd_int_clear(uint8_t rhport)
+{
+ NVIC_ClearPendingIRQ(musb_irqs[rhport]);
+}
+
+static inline void musb_dcd_int_handler_enter(uint8_t rhport){
+ (void)rhport;
+ //Nothing to do for this part
+}
+
+static inline void musb_dcd_int_handler_exit(uint8_t rhport){
+ (void)rhport;
+ //Nothing to do for this part
+}
+
+static inline volatile musb_dcd_ctl_regs_t* musb_dcd_ctl_regs(uint8_t rhport)
+{
+ volatile musb_dcd_ctl_regs_t *regs = (volatile musb_dcd_ctl_regs_t*)((uintptr_t)&(musb_periph_inst[rhport]->FADDR));
+ return regs;
+}
+
+static inline volatile musb_dcd_epn_regs_t* musb_dcd_epn_regs(uint8_t rhport, unsigned epnum)
+{
+ uintptr_t baseptr = (uintptr_t)&(musb_periph_inst[rhport]->TXMAXP1);
+
+ //On the TI parts, the epn registers are 16-bytes apart. The core regs defined
+ //by musb_dcd_epn_regs and 6 reserved/other use bytes
+ volatile musb_dcd_epn_regs_t *regs = (volatile musb_dcd_epn_regs_t*)(baseptr + ((epnum - 1)*16));
+ return regs;
+}
+
+static inline volatile musb_dcd_ep0_regs_t* musb_dcd_ep0_regs(uint8_t rhport)
+{
+ volatile musb_dcd_ep0_regs_t *regs = (volatile musb_dcd_ep0_regs_t*)((uintptr_t)&(musb_periph_inst[rhport]->CSRL0));
+ return regs;
+}
+
+static volatile void *musb_dcd_ep_get_fifo_ptr(uint8_t rhport, unsigned epnum)
+{
+ if(epnum){
+ return (volatile void *)(&(musb_periph_inst[rhport]->FIFO1_WORD) + (epnum - 1));
+ } else {
+ return (volatile void *)&(musb_periph_inst[rhport]->FIFO0_WORD);
+ }
+}
+
+
+typedef struct {
+ uint_fast16_t beg; /* offset of including first element */
+ uint_fast16_t end; /* offset of excluding the last element */
+} free_block_t;
+
+static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
+{
+ free_block_t *cur = beg;
+ for (; cur < end && ((addr < cur->beg) || (cur->end <= addr)); ++cur) ;
+ return cur;
+}
+
+static inline int update_free_block_list(free_block_t *blks, unsigned num, uint_fast16_t addr, uint_fast16_t size)
+{
+ free_block_t *p = find_containing_block(blks, blks + num, addr);
+ TU_ASSERT(p != blks + num, -2);
+ if (p->beg == addr) {
+ /* Shrink block */
+ p->beg = addr + size;
+ if (p->beg != p->end) return 0;
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ } else {
+ /* Split into 2 blocks */
+ free_block_t tmp = {
+ .beg = addr + size,
+ .end = p->end
+ };
+ p->end = addr;
+ if (p->beg == p->end) {
+ if (tmp.beg != tmp.end) {
+ *p = tmp;
+ return 0;
+ }
+ /* remove block */
+ free_block_t *end = blks + num;
+ while (p + 1 < end) {
+ *p = *(p + 1);
+ ++p;
+ }
+ return -1;
+ }
+ if (tmp.beg == tmp.end) return 0;
+ blks[num] = tmp;
+ return 1;
+ }
+}
+
+static inline unsigned free_block_size(free_block_t const *blk)
+{
+ return blk->end - blk->beg;
+}
+
+#if 0
+static inline void print_block_list(free_block_t const *blk, unsigned num)
+{
+ TU_LOG1("*************\r\n");
+ for (unsigned i = 0; i < num; ++i) {
+ TU_LOG1(" Blk%u %u %u\r\n", i, blk->beg, blk->end);
+ ++blk;
+ }
+}
+#else
+#define print_block_list(a,b)
+#endif
+
+static unsigned find_free_memory(uint8_t rhport, uint_fast16_t size_in_log2_minus3)
+{
+ free_block_t free_blocks[2 * (TUP_DCD_ENDPOINT_MAX - 1)];
+ unsigned num_blocks = 1;
+
+ /* Initialize free memory block list */
+ free_blocks[0].beg = 64 / 8;
+ free_blocks[0].end = (4 << 10) / 8; /* 4KiB / 8 bytes */
+ for (int i = 1; i < TUP_DCD_ENDPOINT_MAX; ++i) {
+ uint_fast16_t addr;
+ int num;
+ musb_periph_inst[rhport]->EPIDX = i;
+ addr = musb_periph_inst[rhport]->TXFIFOADD;
+ if (addr) {
+ unsigned sz = musb_periph_inst[rhport]->TXFIFOSZ;
+ unsigned sft = (sz & USB_TXFIFOSZ_SIZE_M) + ((sz & USB_TXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ addr = musb_periph_inst[rhport]->RXFIFOADD;
+ if (addr) {
+ unsigned sz = musb_periph_inst[rhport]->RXFIFOSZ;
+ unsigned sft = (sz & USB_RXFIFOSZ_SIZE_M) + ((sz & USB_RXFIFOSZ_DPB) ? 1: 0);
+ num = update_free_block_list(free_blocks, num_blocks, addr, 1 << sft);
+ TU_ASSERT(-2 < num, 0);
+ num_blocks += num;
+ print_block_list(free_blocks, num_blocks);
+ }
+ }
+ print_block_list(free_blocks, num_blocks);
+
+ /* Find the best fit memory block */
+ uint_fast16_t size_in_8byte_unit = 1 << size_in_log2_minus3;
+ free_block_t const *min = NULL;
+ uint_fast16_t min_sz = 0xFFFFu;
+ free_block_t const *end = &free_blocks[num_blocks];
+ for (free_block_t const *cur = &free_blocks[0]; cur < end; ++cur) {
+ uint_fast16_t sz = free_block_size(cur);
+ if (sz < size_in_8byte_unit) continue;
+ if (size_in_8byte_unit == sz) return cur->beg;
+ if (sz < min_sz) min = cur;
+ }
+ TU_ASSERT(min, 0);
+ return min->beg;
+}
+
+
+static inline void musb_dcd_setup_fifo(uint8_t rhport, unsigned epnum, unsigned dir_in, unsigned mps)
+{
+ int size_in_log2_minus3 = 28 - TU_MIN(28, __CLZ((uint32_t)mps));
+ if ((8u << size_in_log2_minus3) < mps) ++size_in_log2_minus3;
+ unsigned addr = find_free_memory(rhport, size_in_log2_minus3);
+ TU_ASSERT(addr,);
+
+ musb_periph_inst[rhport]->EPIDX = epnum;
+ if (dir_in) {
+ musb_periph_inst[rhport]->TXFIFOADD = addr;
+ musb_periph_inst[rhport]->TXFIFOSZ = size_in_log2_minus3;
+ } else {
+ musb_periph_inst[rhport]->RXFIFOADD = addr;
+ musb_periph_inst[rhport]->RXFIFOSZ = size_in_log2_minus3;
+ }
+}
+
+static inline void musb_dcd_reset_fifo(uint8_t rhport, unsigned epnum, unsigned dir_in)
+{
+ musb_periph_inst[rhport]->EPIDX = epnum;
+ if (dir_in) {
+ musb_periph_inst[rhport]->TXFIFOADD = 0;
+ musb_periph_inst[rhport]->TXFIFOSZ = 0;
+ } else {
+ musb_periph_inst[rhport]->RXFIFOADD = 0;
+ musb_periph_inst[rhport]->RXFIFOSZ = 0;
+ }
+}
+
+#endif // CFG_TUD_ENABLED
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // _TUSB_MUSB_TI_H_
diff --git a/src/portable/mentor/musb/musb_tm4c.h b/src/portable/mentor/musb/musb_tm4c.h
deleted file mode 100644
index 65a1751b0..000000000
--- a/src/portable/mentor/musb/musb_tm4c.h
+++ /dev/null
@@ -1,45 +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 _TUSB_MUSB_TM4C_H_
-#define _TUSB_MUSB_TM4C_H_
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-#if CFG_TUSB_MCU == OPT_MCU_TM4C123
- #include "TM4C123.h"
-//#elif CFG_TUSB_MCU == OPT_MCU_TM4C129
-#else
- #error "Unsupported MCUs"
-#endif
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif
diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h
index 8f83305a5..e8af8f19b 100644
--- a/src/portable/mentor/musb/musb_type.h
+++ b/src/portable/mentor/musb/musb_type.h
@@ -35,10 +35,43 @@
#ifndef _TUSB_MUSB_TYPE_H_
#define _TUSB_MUSB_TYPE_H_
+#include "stdint.h"
+
#ifdef __cplusplus
extern "C" {
#endif
+// Endpoint register mapping. Non-zero end points.
+typedef struct TU_ATTR_PACKED {
+ uint16_t TXMAXP;
+ uint8_t TXCSRL;
+ uint8_t TXCSRH;
+ uint16_t RXMAXP;
+ uint8_t RXCSRL;
+ uint8_t RXCSRH;
+ uint16_t RXCOUNT;
+} musb_dcd_epn_regs_t;
+
+// Endpoint 0 register mapping.
+typedef struct TU_ATTR_PACKED {
+ uint8_t CSRL0;
+ uint8_t CSRH0;
+ uint32_t RESERVED;
+ uint8_t COUNT0;
+} musb_dcd_ep0_regs_t;
+
+// Control register mapping
+typedef struct TU_ATTR_PACKED {
+ uint8_t FADDR;
+ uint8_t POWER;
+ uint16_t TXIS;
+ uint16_t RXIS;
+ uint16_t TXIE;
+ uint16_t RXIE;
+ uint8_t IS;
+ uint8_t IE;
+} musb_dcd_ctl_regs_t;
+
//*****************************************************************************
//
// The following are defines for the bit fields in the USB_O_FADDR register.