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,44 +35,31 @@ _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; - typedef union { uint8_t u8; uint16_t u16; @@ -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.