From 7954d9cb4c486b263bed8984b7dd7553092150f9 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 31 Jul 2024 18:15:22 +0700 Subject: rename to fsdev_type.h, use FSDDEV_REG instead of USB --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 57 ++--- src/portable/st/stm32_fsdev/fsdev_common.h | 289 -------------------------- src/portable/st/stm32_fsdev/fsdev_stm32.h | 2 + src/portable/st/stm32_fsdev/fsdev_type.h | 286 +++++++++++++++++++++++++ 4 files changed, 317 insertions(+), 317 deletions(-) delete mode 100644 src/portable/st/stm32_fsdev/fsdev_common.h create mode 100644 src/portable/st/stm32_fsdev/fsdev_type.h diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index d0a51d48e..29e1ca111 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -123,7 +123,7 @@ #error "Unknown USB IP" #endif -#include "fsdev_common.h" +#include "fsdev_type.h" //--------------------------------------------------------------------+ // Configuration @@ -197,25 +197,25 @@ void dcd_init(uint8_t rhport) { } // Perform USB peripheral reset - USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; + FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } - USB->CNTR &= ~USB_CNTR_PDWN; + FSDEV_REG->CNTR &= ~USB_CNTR_PDWN; // Wait startup time, for F042 and F070, this is <= 1 us. for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us asm("NOP"); } - USB->CNTR = 0; // Enable USB + FSDEV_REG->CNTR = 0; // Enable USB -#if !defined(STM32G0) && !defined(STM32H5) && !defined(STM32U5) - // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address - USB->BTABLE = FSDEV_BTABLE_BASE; +#if !defined(FSDEV_BUS_32BIT) + // BTABLE register does not exist any more on 32-bit bus devices + FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE; #endif - USB->ISTR = 0; // Clear pending interrupts + FSDEV_REG->ISTR = 0; // Clear pending interrupts // Reset endpoints to disabled for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { @@ -223,7 +223,7 @@ void dcd_init(uint8_t rhport) { ep_write(i, 0u); } - USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; + FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; handle_bus_reset(rhport); // Enable pull-up if supported @@ -234,9 +234,9 @@ void dcd_sof_enable(uint8_t rhport, bool en) { (void)rhport; if (en) { - USB->CNTR |= USB_CNTR_SOFM; + FSDEV_REG->CNTR |= USB_CNTR_SOFM; } else { - USB->CNTR &= ~USB_CNTR_SOFM; + FSDEV_REG->CNTR &= ~USB_CNTR_SOFM; } } @@ -254,12 +254,12 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { void dcd_remote_wakeup(uint8_t rhport) { (void)rhport; - USB->CNTR |= USB_CNTR_RESUME; + FSDEV_REG->CNTR |= USB_CNTR_RESUME; remoteWakeCountdown = 4u; // required to be 1 to 15 ms, ESOF should trigger every 1ms. } static void handle_bus_reset(uint8_t rhport) { - USB->DADDR = 0u; // disable USB Function + FSDEV_REG->DADDR = 0u; // disable USB Function for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { // Clear EP allocation status @@ -274,7 +274,7 @@ static void handle_bus_reset(uint8_t rhport) { edpt0_open(rhport); // open control endpoint (both IN & OUT) - USB->DADDR = USB_DADDR_EF; // Enable USB Function + FSDEV_REG->DADDR = USB_DADDR_EF; // Enable USB Function } // Handle CTR interrupt for the TX/IN direction @@ -410,7 +410,7 @@ static void handle_ctr_rx(uint32_t ep_id) { } void dcd_int_handler(uint8_t rhport) { - uint32_t int_status = USB->ISTR; + uint32_t int_status = FSDEV_REG->ISTR; // const uint32_t handled_ints = USB_ISTR_CTR | USB_ISTR_RESET | USB_ISTR_WKUP // | USB_ISTR_SUSP | USB_ISTR_SOF | USB_ISTR_ESOF; // unused IRQs: (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_L1REQ ) @@ -421,23 +421,23 @@ void dcd_int_handler(uint8_t rhport) { /* Put SOF flag at the beginning of ISR in case to get least amount of jitter if it is used for timing purposes */ if (int_status & USB_ISTR_SOF) { - USB->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; - dcd_event_sof(0, USB->FNR & USB_FNR_FN, true); + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; + dcd_event_sof(0, FSDEV_REG->FNR & USB_FNR_FN, true); } if (int_status & USB_ISTR_RESET) { // USBRST is start of reset. - USB->ISTR = (fsdev_bus_t)~USB_ISTR_RESET; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_RESET; handle_bus_reset(rhport); dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); return; // Don't do the rest of the things here; perhaps they've been cleared? } if (int_status & USB_ISTR_WKUP) { - USB->CNTR &= ~USB_CNTR_LPMODE; - USB->CNTR &= ~USB_CNTR_FSUSP; + FSDEV_REG->CNTR &= ~USB_CNTR_LPMODE; + FSDEV_REG->CNTR &= ~USB_CNTR_FSUSP; - USB->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_WKUP; dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); } @@ -446,22 +446,22 @@ void dcd_int_handler(uint8_t rhport) { * these events cannot be differentiated, so we only trigger suspend. */ /* Force low-power mode in the macrocell */ - USB->CNTR |= USB_CNTR_FSUSP; - USB->CNTR |= USB_CNTR_LPMODE; + FSDEV_REG->CNTR |= USB_CNTR_FSUSP; + FSDEV_REG->CNTR |= USB_CNTR_LPMODE; /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - USB->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SUSP; dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); } if (int_status & USB_ISTR_ESOF) { if (remoteWakeCountdown == 1u) { - USB->CNTR &= ~USB_CNTR_RESUME; + FSDEV_REG->CNTR &= ~USB_CNTR_RESUME; } if (remoteWakeCountdown > 0u) { remoteWakeCountdown--; } - USB->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_ESOF; } // loop to handle all pending CTR interrupts @@ -474,7 +474,7 @@ void dcd_int_handler(uint8_t rhport) { handle_ctr_rx(ep_id); // RX/OUT or both (RX/TX !!) } - int_status = USB->ISTR; + int_status = FSDEV_REG->ISTR; } } @@ -488,10 +488,11 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *req (void)rhport; if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { uint8_t const dev_addr = (uint8_t)request->wValue; - USB->DADDR = (USB_DADDR_EF | dev_addr); + FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr); } } diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h deleted file mode 100644 index dd030652b..000000000 --- a/src/portable/st/stm32_fsdev/fsdev_common.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright(c) 2016 STMicroelectronics - * Copyright(c) N Conrad - * Copyright (c) 2024, hathach (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. - * - */ - -#ifndef TUSB_FSDEV_COMMON_H -#define TUSB_FSDEV_COMMON_H - -#ifdef __cplusplus - extern "C" { -#endif - -#include "stdint.h" - -// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it -// Both of these MUST be a multiple of 2, and are in byte units. -#ifndef FSDEV_BTABLE_BASE -#define FSDEV_BTABLE_BASE 0U -#endif - -TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes"); - -// FSDEV_PMA_SIZE is PMA buffer size in bytes. -// - 512-byte devices, access with a stride of two words (use every other 16-bit address) -// - 1024-byte devices, access with a stride of one word (use every 16-bit address) -// - 2048-byte devices, access with 32-bit address - -// For purposes of accessing the packet -#if FSDEV_PMA_SIZE == 512 - #define FSDEV_PMA_STRIDE (2u) // 1x16 bit access scheme - #define pma_aligned TU_ATTR_ALIGNED(4) -#elif FSDEV_PMA_SIZE == 1024 - #define FSDEV_PMA_STRIDE (1u) // 2x16 bit access scheme - #define pma_aligned -#elif FSDEV_PMA_SIZE == 2048 - #ifndef FSDEV_BUS_32BIT - #warning "FSDEV_PMA_SIZE is 2048, but FSDEV_BUS_32BIT is not defined" - #endif - #define FSDEV_PMA_STRIDE (1u) // 32 bit access scheme - #define pma_aligned -#endif - -enum { - BTABLE_BUF_TX = 0, - BTABLE_BUF_RX = 1 -}; - -// hardware limit endpoint -#define FSDEV_EP_COUNT 8 - -// Buffer Table is located in Packet Memory Area (PMA) and therefore its address access is forced to either -// 16-bit or 32-bit depending on FSDEV_BUS_32BIT. -typedef struct { - union { - // 0: TX (IN), 1: RX (OUT) - - // strictly 16-bit access (could be 32-bit aligned) - struct { - volatile pma_aligned uint16_t addr; - volatile pma_aligned uint16_t count; - } ep16[FSDEV_EP_COUNT][2]; - - // strictly 32-bit access - struct { - volatile uint32_t count_addr; - } ep32[FSDEV_EP_COUNT][2]; - }; -} fsdev_btable_t; - -TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT*8*FSDEV_PMA_STRIDE, "size is not correct"); -TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT*8 <= FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM"); - - -#define FSDEV_BTABLE ((volatile fsdev_btable_t*) (USB_PMAADDR+FSDEV_BTABLE_BASE)) - -// volatile 32-bit aligned -#define _va32 volatile TU_ATTR_ALIGNED(4) - -// The fsdev_bus_t type can be used for both register and PMA access necessities -// For type-safety create a new macro for the volatile address of PMAADDR -// The compiler should warn us if we cast it to a non-volatile type? -#ifdef FSDEV_BUS_32BIT -typedef uint32_t fsdev_bus_t; -static volatile uint32_t * const pma32 = (volatile uint32_t*)USB_PMAADDR; - -#else -typedef uint16_t fsdev_bus_t; -// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) -static volatile uint16_t * const pma = (volatile uint16_t*)USB_PMAADDR; -#endif - -typedef struct { - struct { - _va32 fsdev_bus_t reg; - }ep[FSDEV_EP_COUNT]; - - _va32 uint32_t RESERVED7[8]; // Reserved - _va32 fsdev_bus_t CNTR; // 40: Control register - _va32 fsdev_bus_t ISTR; // 44: Interrupt status register - _va32 fsdev_bus_t FNR; // 48: Frame number register - _va32 fsdev_bus_t DADDR; // 4C: Device address register - _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only) - _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only) - _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only) -} fsdev_regs_t; - -TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset"); -TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct"); - -#define FSDEV_REG ((fsdev_regs_t*) FSDEV_REG_BASE) - - -#ifndef USB_EPTX_STAT -#define USB_EPTX_STAT 0x0030U -#endif - -#ifndef USB_EPRX_STAT -#define USB_EPRX_STAT 0x3000U -#endif - -#ifndef USB_EPTX_STAT_Pos -#define USB_EPTX_STAT_Pos 4u -#endif - -#ifndef USB_EP_DTOG_TX_Pos -#define USB_EP_DTOG_TX_Pos 6u -#endif - -#ifndef USB_EP_CTR_TX_Pos -#define USB_EP_CTR_TX_Pos 7u -#endif - - -#define EP_CTR_TXRX (USB_EP_CTR_TX | USB_EP_CTR_RX) - -typedef enum { - EP_STAT_DISABLED = 0, - EP_STAT_STALL = 1, - EP_STAT_NAK = 2, - EP_STAT_VALID = 3 -}ep_stat_t; - -#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) -#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) - -//--------------------------------------------------------------------+ -// Endpoint -// - CTR is write 0 to clear -// - DTOG and STAT are write 1 to toggle -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value) { - FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value; -} - -// write ep register with clear CTR_RX and CTR_TX mask (0 is no clear) -//TU_ATTR_ALWAYS_INLINE static inline void ep_write_with_clear_ctr(uint32_t ep_id, uint32_t value, uint32_t clear_ctr_mask) { -// value |= USB_EP_CTR_RX | USB_EP_CTR_TX; -// if (clear_ctr_mask) { -// value &= ~clear_ctr_mask; -// } -// FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value; -//} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_read(uint32_t ep_id) { - return FSDEV_REG->ep[ep_id].reg; -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_add_status(uint32_t reg, tusb_dir_t dir, ep_stat_t state) { - return reg ^ (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_add_dtog(uint32_t reg, tusb_dir_t dir, uint8_t state) { - return reg ^ (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_clear_ctr(uint32_t reg, tusb_dir_t dir) { - return reg & ~(1 << (USB_EP_CTR_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); -} - -TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(uint32_t reg) { - return (reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS; -} - -//--------------------------------------------------------------------+ -// BTable -//--------------------------------------------------------------------+ - -TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uint8_t buf_id) { -#ifdef FSDEV_BUS_32BIT - return FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr & 0x0000FFFFu; -#else - return FSDEV_BTABLE->ep16[ep_id][buf_id].addr; -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) { -#ifdef FSDEV_BUS_32BIT - uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; - count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu); - FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; -#else - FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr; -#endif -} - -TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_count(uint32_t ep_id, uint8_t buf_id) { - uint16_t count; -#ifdef FSDEV_BUS_32BIT - count = (FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr >> 16); -#else - count = FSDEV_BTABLE->ep16[ep_id][buf_id].count; -#endif - return count & 0x3FFU; -} - -TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) { -#ifdef FSDEV_BUS_32BIT - uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; - count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16); - FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; -#else - uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count; - cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU); - FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt; -#endif -} - -/* Aligned buffer size according to hardware */ -TU_ATTR_ALWAYS_INLINE static inline uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) { - /* The STM32 full speed USB peripheral supports only a limited set of - * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ - uint16_t block_in_bytes; - if (size > 62) { - block_in_bytes = 32; - *blsize = 1; - } else { - block_in_bytes = 2; - *blsize = 0; - } - - *num_block = tu_div_ceil(size, block_in_bytes); - - return (*num_block) * block_in_bytes; -} - -TU_ATTR_ALWAYS_INLINE static inline void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint32_t wCount) { - uint8_t blsize, num_block; - (void) pma_align_buffer_size(wCount, &blsize, &num_block); - - /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ - uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10); - -#ifdef FSDEV_BUS_32BIT - uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; - count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu); - FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; -#else - FSDEV_BTABLE->ep16[ep_id][buf_id].count = bl_nb; -#endif -} - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h index f20505f28..bb2c72fd1 100644 --- a/src/portable/st/stm32_fsdev/fsdev_stm32.h +++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h @@ -198,6 +198,8 @@ #define FSDEV_REG_BASE USB_BASE #elif defined(USB_DRD_BASE) #define FSDEV_REG_BASE USB_DRD_BASE +#elif defined(USB_DRD_FS_BASE) + #define FSDEV_REG_BASE USB_DRD_FS_BASE #else #error "FSDEV_REG_BASE not defined" #endif diff --git a/src/portable/st/stm32_fsdev/fsdev_type.h b/src/portable/st/stm32_fsdev/fsdev_type.h new file mode 100644 index 000000000..116017f63 --- /dev/null +++ b/src/portable/st/stm32_fsdev/fsdev_type.h @@ -0,0 +1,286 @@ +/* + * The MIT License (MIT) + * + * Copyright(c) 2016 STMicroelectronics + * Copyright(c) N Conrad + * Copyright (c) 2024, hathach (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. + * + */ + +#ifndef TUSB_FSDEV_TYPE_H +#define TUSB_FSDEV_TYPE_H + +#ifdef __cplusplus + extern "C" { +#endif + +#include "stdint.h" + +// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it +// Both of these MUST be a multiple of 2, and are in byte units. +#ifndef FSDEV_BTABLE_BASE +#define FSDEV_BTABLE_BASE 0U +#endif + +TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes"); + +// FSDEV_PMA_SIZE is PMA buffer size in bytes. +// - 512-byte devices, access with a stride of two words (use every other 16-bit address) +// - 1024-byte devices, access with a stride of one word (use every 16-bit address) +// - 2048-byte devices, access with 32-bit address + +// For purposes of accessing the packet +#if FSDEV_PMA_SIZE == 512 + #define FSDEV_PMA_STRIDE (2u) // 1x16 bit access scheme + #define pma_aligned TU_ATTR_ALIGNED(4) +#elif FSDEV_PMA_SIZE == 1024 + #define FSDEV_PMA_STRIDE (1u) // 2x16 bit access scheme + #define pma_aligned +#elif FSDEV_PMA_SIZE == 2048 + #ifndef FSDEV_BUS_32BIT + #warning "FSDEV_PMA_SIZE is 2048, but FSDEV_BUS_32BIT is not defined" + #endif + #define FSDEV_PMA_STRIDE (1u) // 32 bit access scheme + #define pma_aligned +#endif + +//--------------------------------------------------------------------+ +// BTable Typedef +//--------------------------------------------------------------------+ +enum { + BTABLE_BUF_TX = 0, + BTABLE_BUF_RX = 1 +}; + +// hardware limit endpoint +#define FSDEV_EP_COUNT 8 + +// Buffer Table is located in Packet Memory Area (PMA) and therefore its address access is forced to either +// 16-bit or 32-bit depending on FSDEV_BUS_32BIT. +typedef struct { + union { + // 0: TX (IN), 1: RX (OUT) + + // strictly 16-bit access (could be 32-bit aligned) + struct { + volatile pma_aligned uint16_t addr; + volatile pma_aligned uint16_t count; + } ep16[FSDEV_EP_COUNT][2]; + + // strictly 32-bit access + struct { + volatile uint32_t count_addr; + } ep32[FSDEV_EP_COUNT][2]; + }; +} fsdev_btable_t; + +TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT*8*FSDEV_PMA_STRIDE, "size is not correct"); +TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT*8 <= FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM"); + +#define FSDEV_BTABLE ((volatile fsdev_btable_t*) (USB_PMAADDR+FSDEV_BTABLE_BASE)) + +//--------------------------------------------------------------------+ +// Registers Typedef +//--------------------------------------------------------------------+ + +// volatile 32-bit aligned +#define _va32 volatile TU_ATTR_ALIGNED(4) + +// The fsdev_bus_t type can be used for both register and PMA access necessities +// For type-safety create a new macro for the volatile address of PMAADDR +// The compiler should warn us if we cast it to a non-volatile type? +#ifdef FSDEV_BUS_32BIT +typedef uint32_t fsdev_bus_t; +static volatile uint32_t * const pma32 = (volatile uint32_t*)USB_PMAADDR; + +#else +typedef uint16_t fsdev_bus_t; +// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden) +static volatile uint16_t * const pma = (volatile uint16_t*)USB_PMAADDR; +#endif + +typedef struct { + struct { + _va32 fsdev_bus_t reg; + }ep[FSDEV_EP_COUNT]; + + _va32 uint32_t RESERVED7[8]; // Reserved + _va32 fsdev_bus_t CNTR; // 40: Control register + _va32 fsdev_bus_t ISTR; // 44: Interrupt status register + _va32 fsdev_bus_t FNR; // 48: Frame number register + _va32 fsdev_bus_t DADDR; // 4C: Device address register + _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only) + _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only) + _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only) +} fsdev_regs_t; + +TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset"); +TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct"); + +#define FSDEV_REG ((fsdev_regs_t*) FSDEV_REG_BASE) + + +#ifndef USB_EPTX_STAT +#define USB_EPTX_STAT 0x0030U +#endif + +#ifndef USB_EPRX_STAT +#define USB_EPRX_STAT 0x3000U +#endif + +#ifndef USB_EPTX_STAT_Pos +#define USB_EPTX_STAT_Pos 4u +#endif + +#ifndef USB_EP_DTOG_TX_Pos +#define USB_EP_DTOG_TX_Pos 6u +#endif + +#ifndef USB_EP_CTR_TX_Pos +#define USB_EP_CTR_TX_Pos 7u +#endif + + +#define EP_CTR_TXRX (USB_EP_CTR_TX | USB_EP_CTR_RX) + +typedef enum { + EP_STAT_DISABLED = 0, + EP_STAT_STALL = 1, + EP_STAT_NAK = 2, + EP_STAT_VALID = 3 +}ep_stat_t; + +#define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) +#define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) + +//--------------------------------------------------------------------+ +// Endpoint Helper +// - CTR is write 0 to clear +// - DTOG and STAT are write 1 to toggle +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value) { + FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value; +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_read(uint32_t ep_id) { + return FSDEV_REG->ep[ep_id].reg; +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_add_status(uint32_t reg, tusb_dir_t dir, ep_stat_t state) { + return reg ^ (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_add_dtog(uint32_t reg, tusb_dir_t dir, uint8_t state) { + return reg ^ (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_clear_ctr(uint32_t reg, tusb_dir_t dir) { + return reg & ~(1 << (USB_EP_CTR_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8))); +} + +TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(uint32_t reg) { + return (reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS; +} + +//--------------------------------------------------------------------+ +// BTable Helper +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uint8_t buf_id) { +#ifdef FSDEV_BUS_32BIT + return FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr & 0x0000FFFFu; +#else + return FSDEV_BTABLE->ep16[ep_id][buf_id].addr; +#endif +} + +TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) { +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr; +#endif +} + +TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_count(uint32_t ep_id, uint8_t buf_id) { + uint16_t count; +#ifdef FSDEV_BUS_32BIT + count = (FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr >> 16); +#else + count = FSDEV_BTABLE->ep16[ep_id][buf_id].count; +#endif + return count & 0x3FFU; +} + +TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) { +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count; + cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU); + FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt; +#endif +} + +/* Aligned buffer size according to hardware */ +TU_ATTR_ALWAYS_INLINE static inline uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) { + /* The STM32 full speed USB peripheral supports only a limited set of + * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ + uint16_t block_in_bytes; + if (size > 62) { + block_in_bytes = 32; + *blsize = 1; + } else { + block_in_bytes = 2; + *blsize = 0; + } + + *num_block = tu_div_ceil(size, block_in_bytes); + + return (*num_block) * block_in_bytes; +} + +TU_ATTR_ALWAYS_INLINE static inline void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint32_t wCount) { + uint8_t blsize, num_block; + (void) pma_align_buffer_size(wCount, &blsize, &num_block); + + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ + uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10); + +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + FSDEV_BTABLE->ep16[ep_id][buf_id].count = bl_nb; +#endif +} + +#ifdef __cplusplus + } +#endif + +#endif -- cgit v1.3.1