From 7e8a004da6971de32aa6a4c0c8f5d374e66955ff Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 18 Aug 2024 20:38:57 +0200 Subject: [PATCH 1/4] cpu/rpxx0xx: add periph_usbus support --- cpu/rpx0xx/Makefile.features | 1 + cpu/rpx0xx/clock.c | 8 + cpu/rpx0xx/cpu.c | 11 +- cpu/rpx0xx/include/periph_cpu.h | 8 + cpu/rpx0xx/periph/usbdev.c | 746 ++++++++++++++++++++++++++++++++ 5 files changed, 772 insertions(+), 2 deletions(-) create mode 100644 cpu/rpx0xx/periph/usbdev.c diff --git a/cpu/rpx0xx/Makefile.features b/cpu/rpx0xx/Makefile.features index c5898736565e..47d7833ed7f4 100644 --- a/cpu/rpx0xx/Makefile.features +++ b/cpu/rpx0xx/Makefile.features @@ -9,4 +9,5 @@ FEATURES_PROVIDED += periph_pio FEATURES_PROVIDED += periph_timer_periodic FEATURES_PROVIDED += periph_uart_reconfigure FEATURES_PROVIDED += periph_uart_modecfg +FEATURES_PROVIDED += periph_usbdev FEATURES_PROVIDED += pio_i2c diff --git a/cpu/rpx0xx/clock.c b/cpu/rpx0xx/clock.c index 3af4252951ab..05e65473f35c 100644 --- a/cpu/rpx0xx/clock.c +++ b/cpu/rpx0xx/clock.c @@ -130,6 +130,14 @@ void clock_periph_configure(CLOCKS_CLK_PERI_CTRL_AUXSRC_Enum aux) io_reg_atomic_set(&CLOCKS->CLK_PERI_CTRL, (1u << CLOCKS_CLK_PERI_CTRL_ENABLE_Pos)); } +void clock_usb_configure(CLOCKS_CLK_USB_CTRL_AUXSRC_Enum aux) +{ + io_reg_atomic_clear(&CLOCKS->CLK_USB_CTRL, (1u << CLOCKS_CLK_USB_CTRL_ENABLE_Pos)); + io_reg_write_dont_corrupt(&CLOCKS->CLK_USB_CTRL, aux << CLOCKS_CLK_USB_CTRL_AUXSRC_Pos, + CLOCKS_CLK_USB_CTRL_AUXSRC_Msk); + io_reg_atomic_set(&CLOCKS->CLK_USB_CTRL, (1u << CLOCKS_CLK_USB_CTRL_ENABLE_Pos)); +} + void clock_gpout0_configure(uint32_t f_in, uint32_t f_out, CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_Enum aux) { assert(f_out <= f_in); diff --git a/cpu/rpx0xx/cpu.c b/cpu/rpx0xx/cpu.c index 6fa88532d563..c7ba0ad3302c 100644 --- a/cpu/rpx0xx/cpu.c +++ b/cpu/rpx0xx/cpu.c @@ -66,6 +66,11 @@ static void _cpu_reset(void) pll_reset_sys(); /* start the system PLL (typically takes the 12 MHz XOSC to generate 125 MHz) */ pll_start_sys(PLL_SYS_REF_DIV, PLL_SYS_VCO_FEEDBACK_SCALE, PLL_SYS_POSTDIV1, PLL_SYS_POSTDIV2); + /* start usb PLL if necessary */ + if (IS_USED(MODULE_USBUS) || IS_USED(MODULE_PERIPH_ADC)) { + pll_start_usb(PLL_USB_REF_DIV, PLL_USB_VCO_FEEDBACK_SCALE, + PLL_USB_POSTDIV1, PLL_USB_POSTDIV2); + } /* configure reference clock to run from XOSC (typically 12 MHz) */ clock_ref_configure_source(CLOCK_XOSC, CLOCK_XOSC, CLOCKS_CLK_REF_CTRL_SRC_xosc_clksrc); @@ -74,6 +79,10 @@ static void _cpu_reset(void) CLOCKS_CLK_SYS_CTRL_AUXSRC_clksrc_pll_sys); /* configure the peripheral clock to run from the system clock */ clock_periph_configure(CLOCK_PERIPH_SOURCE); + /* configure the usb clock */ + if (IS_USED(MODULE_USBUS)) { + clock_usb_configure(CLOCKS_CLK_USB_CTRL_AUXSRC_clksrc_pll_usb); + } if (IS_USED(ENABLE_DEBUG)) { /* check clk_ref with logic analyzer */ clock_gpout0_configure(CLOCK_XOSC, CLOCK_XOSC, @@ -82,8 +91,6 @@ static void _cpu_reset(void) /* Configure USB PLL to deliver 48MHz needed by ADC */ if (IS_USED(MODULE_PERIPH_ADC)) { - pll_start_usb(PLL_USB_REF_DIV, PLL_USB_VCO_FEEDBACK_SCALE, - PLL_USB_POSTDIV1, PLL_USB_POSTDIV2); clock_adc_configure(CLOCKS_CLK_ADC_CTRL_AUXSRC_clksrc_pll_usb); } } diff --git a/cpu/rpx0xx/include/periph_cpu.h b/cpu/rpx0xx/include/periph_cpu.h index 4aeb36fef6ce..459f0eb22034 100644 --- a/cpu/rpx0xx/include/periph_cpu.h +++ b/cpu/rpx0xx/include/periph_cpu.h @@ -621,6 +621,14 @@ void clock_ref_configure_aux_source(uint32_t f_in, uint32_t f_out, */ void clock_periph_configure(CLOCKS_CLK_PERI_CTRL_AUXSRC_Enum aux); +/** + * @brief Configure the usb clock to run from a dedicated auxiliary + * clock source + * + * @param aux Auxiliary clock source + */ +void clock_usb_configure(CLOCKS_CLK_USB_CTRL_AUXSRC_Enum aux); + /** * @brief Configure gpio21 as clock output pin * diff --git a/cpu/rpx0xx/periph/usbdev.c b/cpu/rpx0xx/periph/usbdev.c new file mode 100644 index 000000000000..80e63ce888fa --- /dev/null +++ b/cpu/rpx0xx/periph/usbdev.c @@ -0,0 +1,746 @@ +/* + * Copyright (C) 2024 Frank engelhardt + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_rpx0xx + * @{ + * @file + * @brief Low level USB interface for rpx0xx cpu family + * + * @author Frank engelhardt + * @} + */ + +#include +#include +#include +#include +#include +#include "architecture.h" +#include "cpu.h" +#include "periph/gpio.h" +#include "periph/usbdev.h" +#include "bitarithm.h" +#include "panic.h" + +#include "cpu_conf.h" + +#define ENABLE_DEBUG 1 +#include "debug.h" + +#define USB_BUFFER_SPACE_START ((uint8_t*) USBCTRL_DPRAM + 0x180u) +#define USB_BUFFER_SPACE_END ((uint8_t*) USBCTRL_DPRAM + 0x1000u) + +typedef struct rpx0xx_usb_ep { + uint8_t *dpram_buf; + size_t dpram_bufsize; + usbdev_ep_t ep; +} rpx0xx_usb_ep_t; + +typedef struct rpx0xx_usb_dev { + /* Information about each allocated endpoint. */ + rpx0xx_usb_ep_t hw_ep[2 * USBDEV_NUM_ENDPOINTS]; + usbdev_t dev; + bool suspended; + bool connected; +} rpx0xx_usb_dev_t; + +/* Forward declaration for the usb device driver. */ +const usbdev_driver_t driver; + +/* There is only one usb device. */ +static rpx0xx_usb_dev_t _hw_usb_dev; + +static uint8_t *_dpram_next_buf_ptr = (uint8_t*) USB_BUFFER_SPACE_START; + +static inline __IOM uint32_t * _get_ep_out_ctrl_reg(uint8_t ep_num) +{ + assert(ep_num >= 1 && ep_num < 16); + __IOM uint32_t * reg_map[] = { + &USBCTRL_DPRAM->EP1_OUT_CONTROL, + &USBCTRL_DPRAM->EP2_OUT_CONTROL, + &USBCTRL_DPRAM->EP3_OUT_CONTROL, + &USBCTRL_DPRAM->EP4_OUT_CONTROL, + &USBCTRL_DPRAM->EP5_OUT_CONTROL, + &USBCTRL_DPRAM->EP6_OUT_CONTROL, + &USBCTRL_DPRAM->EP7_OUT_CONTROL, + &USBCTRL_DPRAM->EP8_OUT_CONTROL, + &USBCTRL_DPRAM->EP9_OUT_CONTROL, + &USBCTRL_DPRAM->EP10_OUT_CONTROL, + &USBCTRL_DPRAM->EP11_OUT_CONTROL, + &USBCTRL_DPRAM->EP12_OUT_CONTROL, + &USBCTRL_DPRAM->EP13_OUT_CONTROL, + &USBCTRL_DPRAM->EP14_OUT_CONTROL, + &USBCTRL_DPRAM->EP15_OUT_CONTROL, + }; + return reg_map[ep_num-1]; +} + +static inline __IOM uint32_t * _get_ep_in_ctrl_reg(uint8_t ep_num) +{ + assert(ep_num >= 1 && ep_num < 16); + __IOM uint32_t * reg_map[] = { + &USBCTRL_DPRAM->EP1_IN_CONTROL, + &USBCTRL_DPRAM->EP2_IN_CONTROL, + &USBCTRL_DPRAM->EP3_IN_CONTROL, + &USBCTRL_DPRAM->EP4_IN_CONTROL, + &USBCTRL_DPRAM->EP5_IN_CONTROL, + &USBCTRL_DPRAM->EP6_IN_CONTROL, + &USBCTRL_DPRAM->EP7_IN_CONTROL, + &USBCTRL_DPRAM->EP8_IN_CONTROL, + &USBCTRL_DPRAM->EP9_IN_CONTROL, + &USBCTRL_DPRAM->EP10_IN_CONTROL, + &USBCTRL_DPRAM->EP11_IN_CONTROL, + &USBCTRL_DPRAM->EP12_IN_CONTROL, + &USBCTRL_DPRAM->EP13_IN_CONTROL, + &USBCTRL_DPRAM->EP14_IN_CONTROL, + &USBCTRL_DPRAM->EP15_IN_CONTROL, + }; + return reg_map[ep_num-1]; +} + +static inline __IOM uint32_t * _get_ep_out_buf_ctrl_reg(uint8_t ep_num) +{ + assert(ep_num < 16); + __IOM uint32_t * reg_map[] = { + &USBCTRL_DPRAM->EP0_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP1_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP2_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP3_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP4_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP5_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP6_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP7_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP8_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP9_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP10_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP11_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP12_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP13_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP14_OUT_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP15_OUT_BUFFER_CONTROL, + }; + return reg_map[ep_num]; +} + +static inline __IOM uint32_t * _get_ep_in_buf_ctrl_reg(uint8_t ep_num) +{ + assert(ep_num < 16); + __IOM uint32_t * reg_map[] = { + &USBCTRL_DPRAM->EP0_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP1_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP2_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP3_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP4_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP5_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP6_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP7_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP8_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP9_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP10_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP11_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP12_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP13_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP14_IN_BUFFER_CONTROL, + &USBCTRL_DPRAM->EP15_IN_BUFFER_CONTROL, + }; + return reg_map[ep_num]; +} + +/* Read the ep-related bit from a status register. */ +static inline bool _reg_get_flag_for_ep(__IOM uint32_t *reg, usbdev_ep_t *ep) +{ + uint32_t val = *reg; + return val & 1 << (2 * ep->num + (ep->dir == USB_EP_DIR_IN ? 0 : 1)); +} + +/* Clear the ep-related bit from a status register. */ +static inline void _reg_clear_flag_for_ep(__IOM uint32_t *reg, usbdev_ep_t *ep) +{ + io_reg_atomic_clear(reg, + 1 << (2 * ep->num + (ep->dir == USB_EP_DIR_IN ? 0 : 1))); +} + +static inline __IOM uint32_t * _get_ep_buf_ctrl_reg(uint8_t ep_num, + usb_ep_dir_t dir) +{ + if (dir == USB_EP_DIR_IN) { + return _get_ep_in_buf_ctrl_reg(ep_num); + } else { + return _get_ep_out_buf_ctrl_reg(ep_num); + } +} + +static inline __IOM uint32_t * _get_ep_ctrl_reg(uint8_t ep_num, + usb_ep_dir_t dir) +{ + if (dir == USB_EP_DIR_IN) { + return _get_ep_in_ctrl_reg(ep_num); + } else { + return _get_ep_out_ctrl_reg(ep_num); + } +} + +/** See @io_reg_write_dont_corrupt() */ +static inline void _ep_ctrl_reg_write(uint8_t ep_num, usb_ep_dir_t dir, + uint32_t value, uint32_t mask) +{ + __IOM uint32_t *reg = _get_ep_ctrl_reg(ep_num, dir); + io_reg_write_dont_corrupt(reg, value, mask); +} + +/** See @io_reg_write_dont_corrupt() */ +static inline void _ep_buf_ctrl_reg_write(uint8_t ep_num, usb_ep_dir_t dir, + uint32_t value, uint32_t mask) +{ + __IOM uint32_t *reg = _get_ep_buf_ctrl_reg(ep_num, dir); + io_reg_write_dont_corrupt(reg, value, mask); +} + +/* Get DPRAM buffer offset. */ +static inline uintptr_t _dpram_offset(uint8_t *buf) +{ + return (uintptr_t) buf ^ (uintptr_t) USBCTRL_DPRAM_BASE; +} + +static rpx0xx_usb_ep_t *_get_ep(uint8_t ep_num, usb_ep_dir_t dir) +{ + return &_hw_usb_dev.hw_ep[2 * ep_num + (dir == USB_EP_DIR_OUT ? 0 : 1)]; +} + +static void _poweron(void) +{ + periph_reset(RESETS_RESET_usbctrl_Msk); + periph_reset_done(RESETS_RESET_usbctrl_Msk); + io_reg_atomic_set(&USBCTRL_REGS->MAIN_CTRL, + USBCTRL_REGS_MAIN_CTRL_CONTROLLER_EN_Msk); + io_reg_atomic_set(&USBCTRL_REGS->USB_MUXING, + USBCTRL_REGS_USB_MUXING_TO_PHY_Msk); +} + +/* +static void _poweroff(void) +{ + io_reg_atomic_set(&USBCTRL_REGS->MAIN_CTRL, 0); + periph_reset(RESETS_RESET_usbctrl_Msk); +} +*/ + +void usbdev_init_lowlevel(void) +{ + DEBUG("[rpx0xx usb] Call usbdev_init_lowlevel()\n"); + memset(&_hw_usb_dev, 0, sizeof(rpx0xx_usb_dev_t)); + _hw_usb_dev.dev.driver = &driver; +} + +usbdev_t *usbdev_get_ctx(unsigned num) +{ + (void)num; + return &_hw_usb_dev.dev; +} + +static void _enable_irq(void) { + io_reg_atomic_set(&USBCTRL_REGS->INTE, + USBCTRL_REGS_INTE_BUS_RESET_Msk | + USBCTRL_REGS_INTE_DEV_SUSPEND_Msk | + USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk); + io_reg_atomic_set(&USBCTRL_REGS->SIE_CTRL, + USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF_Msk); +} + +static void _disable_irq(void) { + io_reg_atomic_clear(&USBCTRL_REGS->INTE, + USBCTRL_REGS_INTE_BUS_RESET_Msk | + USBCTRL_REGS_INTE_DEV_SUSPEND_Msk | + USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk); + io_reg_atomic_clear(&USBCTRL_REGS->SIE_CTRL, + USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF_Msk); +} + +static void _usbdev_init(usbdev_t *dev) +{ + (void)dev; + DEBUG("[rpx0xx usb] Call _usbdev_init()\n"); + + memset(USBCTRL_DPRAM, 0, sizeof(USBCTRL_DPRAM_Type)); + memset(USBCTRL_REGS, 0, sizeof(USBCTRL_REGS_Type)); + + _poweron(); + + _enable_irq(); +} + +static int _usbdev_get(usbdev_t *dev, usbopt_t opt, + void *value, size_t max_len) +{ + (void)dev; + (void)max_len; + + int res = -ENOTSUP; + + switch (opt) { + case USBOPT_MAX_VERSION: + assert(max_len == sizeof(usb_version_t)); + *(usb_version_t *)value = USB_VERSION_20; + res = sizeof(usb_version_t); + break; + case USBOPT_MAX_SPEED: + assert(max_len == sizeof(usb_speed_t)); + *(usb_speed_t *)value = USB_SPEED_FULL; + res = sizeof(usb_speed_t); + break; + default: + DEBUG("[rpx0xx usb] Unhandled get call: 0x%x\n", opt); + break; + } + return res; +} + +static void _set_address(uint8_t addr) +{ + DEBUG("[rpx0xx usb] Call _set_address(addr = %hhx)\n", addr); + io_reg_atomic_set(&USBCTRL_REGS->ADDR_ENDP, + addr & USBCTRL_REGS_ADDR_ENDP_ADDRESS_Msk); +} + +static void _usb_attach(void) +{ + DEBUG("[rpx0xx usb] Attaching to host\n"); + io_reg_atomic_set(&USBCTRL_REGS->SIE_CTRL, + USBCTRL_REGS_SIE_CTRL_PULLUP_EN_Msk); +} + +static void _usb_detach(void) +{ + DEBUG("[rpx0xx usb] Detaching from host\n"); + io_reg_atomic_clear(&USBCTRL_REGS->SIE_CTRL, + USBCTRL_REGS_SIE_CTRL_PULLUP_EN_Msk); +} + +static int _usbdev_set(usbdev_t *dev, usbopt_t opt, + const void *value, size_t value_len) +{ + (void)dev; + (void)opt; + (void)value_len; + + int res = -ENOTSUP; + + switch (opt) { + case USBOPT_ADDRESS: + assert(value_len == sizeof(uint8_t)); + uint8_t addr = (*((uint8_t *)value)); + _set_address(addr); + break; + case USBOPT_ATTACH: + assert(value_len == sizeof(usbopt_enable_t)); + if (*((usbopt_enable_t *)value)) { + _usb_attach(); + } + else { + _usb_detach(); + } + res = sizeof(usbopt_enable_t); + break; + default: + DEBUG("[rpx0xx usb] Unhandled set call: 0x%x\n", opt); + break; + } + + return res; +} + +/* This mechanic of DPRAM allocation is taken from the TinyUSB reference implementation. */ +static void _ep_dpram_alloc(rpx0xx_usb_ep_t *ep, size_t size) +{ + uint32_t transfer_type = 0; + + /* Buffer length must be multiple of 64 bytes. */ + assert(size % 64 == 0); + + if (ep->ep.num != 0) { + assert(ep->ep.type != USB_EP_TYPE_CONTROL); + + ep->dpram_buf = _dpram_next_buf_ptr; + _dpram_next_buf_ptr += size; + + assert(((uintptr_t) _dpram_next_buf_ptr & 0b111111u) == 0); + size_t dpram_offset = _dpram_offset(ep->dpram_buf); + + if (_dpram_next_buf_ptr > USB_BUFFER_SPACE_END) { + core_panic(PANIC_MEM_MANAGE, "[rpx0xx usb] available DPRAM space exceeded"); + } + + DEBUG("[rpx0xx usb] Allocated %d bytes at offset 0x%x (0x%p)\n", + size, dpram_offset, ep->dpram_buf); + + switch (ep->ep.type) { + case USB_EP_TYPE_INTERRUPT: + transfer_type = USBCTRL_DPRAM_EP1_IN_CONTROL_ENDPOINT_TYPE_Interrupt; + break; + case USB_EP_TYPE_BULK: + transfer_type = USBCTRL_DPRAM_EP1_IN_CONTROL_ENDPOINT_TYPE_Bulk; + break; + case USB_EP_TYPE_ISOCHRONOUS: + transfer_type = USBCTRL_DPRAM_EP1_IN_CONTROL_ENDPOINT_TYPE_Isochronous; + break; + default: + core_panic(PANIC_GENERAL_ERROR, "[rpx0xx usb] illegal endpoint type"); + } + + const uint32_t reg = transfer_type | dpram_offset; + + _ep_buf_ctrl_reg_write(ep->ep.num, ep->ep.dir, reg, ~0UL); + } else { + assert(ep->ep.type = USB_EP_TYPE_CONTROL); + assert(size == 64); + + ep->dpram_buf = (uint8_t *)(USBCTRL_DPRAM_BASE + 0x100UL); + } + ep->dpram_bufsize = size; +} + +static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, + usb_ep_dir_t dir, size_t size) +{ + rpx0xx_usb_ep_t *hw_ep = NULL; + + DEBUG("[rpx0xx usb] Call _usbdev_new_ep(dev = ..., type = %d," + "dir = %d, size = %u)\n", type, dir, size); + + /* Always return endpoint 0 for control types */ + if (type == USB_EP_TYPE_CONTROL) { + hw_ep = _get_ep(0, dir); + hw_ep->ep.num = 0; + } + else { + /* Find the first unassigned ep with proper dir */ + for (unsigned i = 1; i < USBDEV_NUM_ENDPOINTS; i++) { + hw_ep = _get_ep(i, dir); + if (hw_ep->ep.type == USB_EP_TYPE_NONE) { + hw_ep->ep.num = i; + break; + } + } + } + if (hw_ep) { + hw_ep->ep.dev = dev; + hw_ep->ep.dir = dir; + hw_ep->ep.type = type; + hw_ep->ep.len = size; + } + + return &hw_ep->ep; +} + +static void _enable_ep_irq(usbdev_ep_t *ep) { + if (ep->num != 0) { + uint32_t flags = USBCTRL_DPRAM_EP1_IN_CONTROL_INTERRUPT_PER_BUFF_Msk + | USBCTRL_DPRAM_EP1_IN_CONTROL_INTERRUPT_ON_STALL_Msk; + _ep_ctrl_reg_write(ep->num, ep->dir, flags, flags); + } else { + uint32_t flags = USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF_Msk + | USBCTRL_REGS_SIE_CTRL_EP0_INT_STALL_Msk; + io_reg_atomic_set(&USBCTRL_REGS->SIE_CTRL, flags); + } +} + +static void _disable_ep_irq(usbdev_ep_t *ep) { + if (ep->num != 0) { + uint32_t flags = USBCTRL_DPRAM_EP1_IN_CONTROL_INTERRUPT_PER_BUFF_Msk + | USBCTRL_DPRAM_EP1_IN_CONTROL_INTERRUPT_ON_STALL_Msk; + _ep_ctrl_reg_write(ep->num, ep->dir, 0, flags); + } else { + uint32_t flags = USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF_Msk + | USBCTRL_REGS_SIE_CTRL_EP0_INT_STALL_Msk; + io_reg_atomic_clear(&USBCTRL_REGS->SIE_CTRL, flags); + } +} + +static void _usbdev_ep_init(usbdev_ep_t *ep) +{ + rpx0xx_usb_ep_t *hw_ep = _get_ep(ep->num, ep->dir); + + DEBUG("[rpx0xx usb] Call _usbdev_ep_init(ep.num = %d," + "ep.dir = %d)\n", ep->num, ep->dir); + + _ep_dpram_alloc(hw_ep, ep->len); + + _enable_ep_irq(ep); +} + +static void _ep_enable(usbdev_ep_t *ep) { + if (ep->num != 0) { + _ep_ctrl_reg_write(ep->num, ep->dir, + USBCTRL_DPRAM_EP1_IN_CONTROL_ENABLE_Msk, + USBCTRL_DPRAM_EP1_IN_CONTROL_ENABLE_Msk); + } +} + +static void _ep_disable(usbdev_ep_t *ep) { + if (ep->num != 0) { + _ep_ctrl_reg_write(ep->num, ep->dir, 0, + USBCTRL_DPRAM_EP1_IN_CONTROL_ENABLE_Msk); + } +} + +static void _ep_set_stall(usbdev_ep_t *ep, usbopt_enable_t enable) +{ + (void)ep; + (void)enable; + if (ep->num == 0) { + uint32_t bit = (ep->dir == USB_EP_DIR_IN) ? + USBCTRL_REGS_EP_STALL_ARM_EP0_IN_Msk + : USBCTRL_REGS_EP_STALL_ARM_EP0_OUT_Msk; + if (enable) { + io_reg_atomic_set(&USBCTRL_REGS->EP_STALL_ARM, bit); + } else { + io_reg_atomic_clear(&USBCTRL_REGS->EP_STALL_ARM, bit); + } + } + uint32_t bit = (enable) ? USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_STALL_Msk : 0; + _ep_buf_ctrl_reg_write(ep->num, ep->dir, bit, + USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_STALL_Msk); +} + +static void _usbdev_ep0_stall(usbdev_t *dev) +{ + (void)dev; + _ep_set_stall(&_get_ep(0, USB_EP_DIR_IN)->ep, USBOPT_ENABLE); + _ep_set_stall(&_get_ep(0, USB_EP_DIR_OUT)->ep, USBOPT_ENABLE); +} + +usbopt_enable_t _ep_get_stall(usbdev_ep_t *ep) +{ + __IOM uint32_t reg = *_get_ep_buf_ctrl_reg(ep->num, ep->dir); + return reg | USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_STALL_Msk; +} + +static void _usbdev_ep_stall(usbdev_ep_t *ep, bool enable) +{ + _ep_set_stall(ep, enable); +} + +/* available: is the processor in control of the buffer? */ +static bool _ep_buf_is_available(usbdev_ep_t *ep) +{ + __IOM uint32_t buf_ctrl_reg = *_get_ep_buf_ctrl_reg(ep->num, ep->dir); + return !(buf_ctrl_reg & USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Msk); +} + +static bool _ep_buf_is_full(usbdev_ep_t *ep) +{ + __IOM uint32_t buf_ctrl_reg = *_get_ep_buf_ctrl_reg(ep->num, ep->dir); + return buf_ctrl_reg & USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_FULL_0_Msk; +} + + +static size_t _ep_get_available(usbdev_ep_t *ep) +{ + if (_ep_buf_is_available(ep)) { + if (ep->dir == USB_EP_DIR_IN) { + rpx0xx_usb_ep_t *hw_ep = _get_ep(ep->num, ep->dir); + return hw_ep->dpram_bufsize; + } else if(_ep_buf_is_full(ep)) { + __IOM uint32_t *reg = _get_ep_buf_ctrl_reg(ep->num, ep->dir); + return *reg | USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_LENGTH_0_Msk; + } + } + return 0UL; +} + +static int _usbdev_ep_get(usbdev_ep_t *ep, usbopt_ep_t opt, + void *value, size_t max_len) +{ + (void)max_len; + int ret = -ENOTSUP; + + switch (opt) { + case USBOPT_EP_STALL: + assert(max_len == sizeof(usbopt_enable_t)); + *(usbopt_enable_t *)value = _ep_get_stall(ep); + ret = sizeof(usbopt_enable_t); + break; + case USBOPT_EP_AVAILABLE: + assert(max_len == sizeof(size_t)); + *(size_t *)value = _ep_get_available(ep); + ret = sizeof(size_t); + break; + default: + DEBUG("[rpx0xx usb]: Unhandled get call: 0x%x\n", opt); + break; + } + return ret; +} + +static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, + const void *value, size_t value_len) +{ + (void)value_len; + int ret = -ENOTSUP; + + switch (opt) { + case USBOPT_EP_ENABLE: + assert(value_len == sizeof(usbopt_enable_t)); + if (*((usbopt_enable_t *)value)) { + _ep_enable(ep); + } + else { + _ep_disable(ep); + } + ret = sizeof(usbopt_enable_t); + break; + case USBOPT_EP_STALL: + assert(value_len == sizeof(usbopt_enable_t)); + _ep_set_stall(ep, *(usbopt_enable_t *)value); + ret = sizeof(usbopt_enable_t); + break; + default: + DEBUG("[rpx0xx usb]: Unhandled set call: 0x%x\n", opt); + break; + } + return ret; +} + +static void _mark_ep_buf_ready(usbdev_ep_t *ep) +{ + uint32_t buf_filled_bit = 0UL; + if (ep->dir == USB_EP_DIR_IN) { + buf_filled_bit = USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_FULL_0_Msk; + } + _ep_buf_ctrl_reg_write(ep->num, ep->dir, + USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_FULL_0_Pos, + buf_filled_bit); + _ep_buf_ctrl_reg_write(ep->num, ep->dir, + USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Pos, + USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Msk); +} + +static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) +{ + rpx0xx_usb_ep_t *hw_ep = _get_ep(ep->num, ep->dir); + + assert(_ep_buf_is_available(ep)); + + size_t available_len = _ep_get_available(ep); + + if (available_len < len) { + len = available_len; + } + + if (ep->dir == USB_EP_DIR_IN) { + memcpy(hw_ep->dpram_buf, buf, len); + } else { + memcpy(buf, hw_ep->dpram_buf, len); + } + _ep_set_stall(ep, 0); + _mark_ep_buf_ready(ep); + + return len; +} + +static void _usbdev_esr(usbdev_t *dev) +{ + (void)dev; + uint32_t status = USBCTRL_REGS->INTS; + + if (status & USBCTRL_REGS_INTS_DEV_SOF_Msk) { + /* Start of frame received */ + uint32_t frame_number = USBCTRL_REGS->SOF_RD; + /* we have to read the frame number to reset the interrupt, + but do not need it */ + (void) frame_number; + _hw_usb_dev.dev.cb(dev, USBDEV_EVENT_SOF); + } + if (status & USBCTRL_REGS_INTS_BUS_RESET_Msk) { + /* Bus reset received */ + _hw_usb_dev.dev.cb(dev, USBDEV_EVENT_RESET); + io_reg_atomic_clear(&USBCTRL_REGS->SIE_STATUS, + USBCTRL_REGS_SIE_STATUS_BUS_RESET_Msk); + } + if (status & USBCTRL_REGS_INTS_DEV_SUSPEND_Msk) { + /* Bus suspend state has changed */ + if (_hw_usb_dev.suspended) { + _hw_usb_dev.suspended = false; + _hw_usb_dev.dev.cb(dev, USBDEV_EVENT_RESUME); + /* TODO: pm_block() for MODULE_PM_LAYERED */ + } else { + _hw_usb_dev.suspended = true; + _hw_usb_dev.dev.cb(dev, USBDEV_EVENT_SUSPEND); + /* TODO: pm_unblock() for MODULE_PM_LAYERED */ + } + io_reg_atomic_clear(&USBCTRL_REGS->SIE_STATUS, + USBCTRL_REGS_SIE_STATUS_SUSPENDED_Msk); + } + if (status & USBCTRL_REGS_INTS_DEV_CONN_DIS_Msk) { + /* Host connected or disconnected */ + if (_hw_usb_dev.connected) { + _hw_usb_dev.connected = false; + _hw_usb_dev.dev.cb(dev, USBDEV_EVENT_HOST_DISCONNECT); + } else { + _hw_usb_dev.connected = true; + _hw_usb_dev.dev.cb(dev, USBDEV_EVENT_HOST_CONNECT); + } + io_reg_atomic_clear(&USBCTRL_REGS->SIE_STATUS, + USBCTRL_REGS_SIE_STATUS_CONNECTED_Msk); + } + /* all interrupts should be now cleared */ + status = USBCTRL_REGS->INTS; + if (status) { + DEBUG("[rpx0xx usb] Unhandled interrupt, INTS=%lx", status); + } + _enable_irq(); +} + +static void _usbdev_ep_esr(usbdev_ep_t *ep) +{ + if (_reg_get_flag_for_ep(&USBCTRL_REGS->BUFF_STATUS, ep)) { + _reg_clear_flag_for_ep(&USBCTRL_REGS->BUFF_STATUS, ep); + ep->dev->epcb(ep, USBDEV_EVENT_TR_COMPLETE); + } + if (_reg_get_flag_for_ep(&USBCTRL_REGS->EP_STATUS_STALL_NAK, ep)) { + _reg_clear_flag_for_ep(&USBCTRL_REGS->EP_STATUS_STALL_NAK, ep); + ep->dev->epcb(ep, USBDEV_EVENT_TR_STALL); + } + _enable_ep_irq(ep); +} + +void isr_usbctrl(void) +{ + if (USBCTRL_REGS->BUFF_STATUS) { + /* Endpoint specific interrupt */ + for (uint8_t i = 0; i < USBDEV_NUM_ENDPOINTS * 2; i++) { + rpx0xx_usb_ep_t* hw_ep = _hw_usb_dev.hw_ep; + if (_reg_get_flag_for_ep(&USBCTRL_REGS->BUFF_STATUS, &hw_ep->ep)) { + _disable_ep_irq(&hw_ep->ep); + _hw_usb_dev.dev.epcb(&hw_ep->ep, USBDEV_EVENT_ESR); + } + } + } + if (USBCTRL_REGS->INTS) { + /* Device specific interrupt */ + _disable_irq(); + _hw_usb_dev.dev.cb(&_hw_usb_dev.dev, USBDEV_EVENT_ESR); + } + cortexm_isr_end(); +} + +const usbdev_driver_t driver = { + .init = _usbdev_init, + .new_ep = _usbdev_new_ep, + .get = _usbdev_get, + .set = _usbdev_set, + .esr = _usbdev_esr, + .ep0_stall = _usbdev_ep0_stall, + .ep_init = _usbdev_ep_init, + .ep_stall = _usbdev_ep_stall, + .ep_get = _usbdev_ep_get, + .ep_set = _usbdev_ep_set, + .ep_esr = _usbdev_ep_esr, + .xmit = _usbdev_ep_xmit, +}; From 40ceaaa2c2e8d6a1e4a9c7b23963bb65ee93259e Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 31 Aug 2024 14:22:30 +0200 Subject: [PATCH 2/4] fixup! cpu/rpxx0xx: add periph_usbus support --- cpu/rpx0xx/periph/usbdev.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/cpu/rpx0xx/periph/usbdev.c b/cpu/rpx0xx/periph/usbdev.c index 80e63ce888fa..551a61df6bb2 100644 --- a/cpu/rpx0xx/periph/usbdev.c +++ b/cpu/rpx0xx/periph/usbdev.c @@ -46,6 +46,7 @@ typedef struct rpx0xx_usb_dev { /* Information about each allocated endpoint. */ rpx0xx_usb_ep_t hw_ep[2 * USBDEV_NUM_ENDPOINTS]; usbdev_t dev; + uint32_t int_status; bool suspended; bool connected; } rpx0xx_usb_dev_t; @@ -220,7 +221,11 @@ static void _poweron(void) io_reg_atomic_set(&USBCTRL_REGS->MAIN_CTRL, USBCTRL_REGS_MAIN_CTRL_CONTROLLER_EN_Msk); io_reg_atomic_set(&USBCTRL_REGS->USB_MUXING, - USBCTRL_REGS_USB_MUXING_TO_PHY_Msk); + USBCTRL_REGS_USB_MUXING_TO_PHY_Msk /*| + USBCTRL_REGS_USB_MUXING_SOFTCON_Msk*/); + io_reg_atomic_set(&USBCTRL_REGS->USB_PWR, + USBCTRL_REGS_USB_PWR_VBUS_DETECT_Msk | + USBCTRL_REGS_USB_PWR_VBUS_DETECT_OVERRIDE_EN_Msk); } /* @@ -248,16 +253,19 @@ static void _enable_irq(void) { io_reg_atomic_set(&USBCTRL_REGS->INTE, USBCTRL_REGS_INTE_BUS_RESET_Msk | USBCTRL_REGS_INTE_DEV_SUSPEND_Msk | - USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk); + USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk | + USBCTRL_REGS_INTE_BUFF_STATUS_Msk); io_reg_atomic_set(&USBCTRL_REGS->SIE_CTRL, USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF_Msk); + NVIC_EnableIRQ(USBCTRL_IRQ_IRQn); } static void _disable_irq(void) { io_reg_atomic_clear(&USBCTRL_REGS->INTE, USBCTRL_REGS_INTE_BUS_RESET_Msk | USBCTRL_REGS_INTE_DEV_SUSPEND_Msk | - USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk); + USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk | + USBCTRL_REGS_INTE_BUFF_STATUS_Msk); io_reg_atomic_clear(&USBCTRL_REGS->SIE_CTRL, USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF_Msk); } @@ -397,7 +405,7 @@ static void _ep_dpram_alloc(rpx0xx_usb_ep_t *ep, size_t size) _ep_buf_ctrl_reg_write(ep->ep.num, ep->ep.dir, reg, ~0UL); } else { - assert(ep->ep.type = USB_EP_TYPE_CONTROL); + assert(ep->ep.type == USB_EP_TYPE_CONTROL); assert(size == 64); ep->dpram_buf = (uint8_t *)(USBCTRL_DPRAM_BASE + 0x100UL); @@ -433,6 +441,7 @@ static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, hw_ep->ep.dir = dir; hw_ep->ep.type = type; hw_ep->ep.len = size; + _ep_dpram_alloc(hw_ep, size); } return &hw_ep->ep; @@ -464,13 +473,9 @@ static void _disable_ep_irq(usbdev_ep_t *ep) { static void _usbdev_ep_init(usbdev_ep_t *ep) { - rpx0xx_usb_ep_t *hw_ep = _get_ep(ep->num, ep->dir); - DEBUG("[rpx0xx usb] Call _usbdev_ep_init(ep.num = %d," "ep.dir = %d)\n", ep->num, ep->dir); - _ep_dpram_alloc(hw_ep, ep->len); - _enable_ep_irq(ep); } @@ -647,9 +652,8 @@ static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) static void _usbdev_esr(usbdev_t *dev) { (void)dev; - uint32_t status = USBCTRL_REGS->INTS; - if (status & USBCTRL_REGS_INTS_DEV_SOF_Msk) { + if (_hw_usb_dev.int_status & USBCTRL_REGS_INTS_DEV_SOF_Msk) { /* Start of frame received */ uint32_t frame_number = USBCTRL_REGS->SOF_RD; /* we have to read the frame number to reset the interrupt, @@ -657,13 +661,13 @@ static void _usbdev_esr(usbdev_t *dev) (void) frame_number; _hw_usb_dev.dev.cb(dev, USBDEV_EVENT_SOF); } - if (status & USBCTRL_REGS_INTS_BUS_RESET_Msk) { + if (_hw_usb_dev.int_status & USBCTRL_REGS_INTS_BUS_RESET_Msk) { /* Bus reset received */ _hw_usb_dev.dev.cb(dev, USBDEV_EVENT_RESET); io_reg_atomic_clear(&USBCTRL_REGS->SIE_STATUS, USBCTRL_REGS_SIE_STATUS_BUS_RESET_Msk); } - if (status & USBCTRL_REGS_INTS_DEV_SUSPEND_Msk) { + if (_hw_usb_dev.int_status & USBCTRL_REGS_INTS_DEV_SUSPEND_Msk) { /* Bus suspend state has changed */ if (_hw_usb_dev.suspended) { _hw_usb_dev.suspended = false; @@ -677,7 +681,7 @@ static void _usbdev_esr(usbdev_t *dev) io_reg_atomic_clear(&USBCTRL_REGS->SIE_STATUS, USBCTRL_REGS_SIE_STATUS_SUSPENDED_Msk); } - if (status & USBCTRL_REGS_INTS_DEV_CONN_DIS_Msk) { + if (_hw_usb_dev.int_status & USBCTRL_REGS_INTS_DEV_CONN_DIS_Msk) { /* Host connected or disconnected */ if (_hw_usb_dev.connected) { _hw_usb_dev.connected = false; @@ -690,9 +694,9 @@ static void _usbdev_esr(usbdev_t *dev) USBCTRL_REGS_SIE_STATUS_CONNECTED_Msk); } /* all interrupts should be now cleared */ - status = USBCTRL_REGS->INTS; - if (status) { - DEBUG("[rpx0xx usb] Unhandled interrupt, INTS=%lx", status); + _hw_usb_dev.int_status = USBCTRL_REGS->INTS; + if (_hw_usb_dev.int_status) { + DEBUG("[rpx0xx usb] Unhandled interrupt, INTS=%lx", _hw_usb_dev.int_status); } _enable_irq(); } @@ -724,6 +728,7 @@ void isr_usbctrl(void) } if (USBCTRL_REGS->INTS) { /* Device specific interrupt */ + _hw_usb_dev.int_status = USBCTRL_REGS->INTS; _disable_irq(); _hw_usb_dev.dev.cb(&_hw_usb_dev.dev, USBDEV_EVENT_ESR); } From a37688e7f92015c91914cf986624cc10edaf81e0 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 1 Sep 2024 12:13:52 +0200 Subject: [PATCH 3/4] fixup! fixup! cpu/rpxx0xx: add periph_usbus support --- cpu/rpx0xx/periph/usbdev.c | 27 +++++++++++++++++++++------ sys/usb/usbus/usbus.c | 2 +- sys/usb/usbus/usbus_control.c | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/cpu/rpx0xx/periph/usbdev.c b/cpu/rpx0xx/periph/usbdev.c index 551a61df6bb2..63d834a71fc9 100644 --- a/cpu/rpx0xx/periph/usbdev.c +++ b/cpu/rpx0xx/periph/usbdev.c @@ -253,8 +253,10 @@ static void _enable_irq(void) { io_reg_atomic_set(&USBCTRL_REGS->INTE, USBCTRL_REGS_INTE_BUS_RESET_Msk | USBCTRL_REGS_INTE_DEV_SUSPEND_Msk | - USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk | - USBCTRL_REGS_INTE_BUFF_STATUS_Msk); + USBCTRL_REGS_INTE_SETUP_REQ_Msk | + /*USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk |*/ + USBCTRL_REGS_INTE_BUFF_STATUS_Msk/* | + USBCTRL_REGS_INTE_DEV_SOF_Msk*/); io_reg_atomic_set(&USBCTRL_REGS->SIE_CTRL, USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF_Msk); NVIC_EnableIRQ(USBCTRL_IRQ_IRQn); @@ -264,8 +266,10 @@ static void _disable_irq(void) { io_reg_atomic_clear(&USBCTRL_REGS->INTE, USBCTRL_REGS_INTE_BUS_RESET_Msk | USBCTRL_REGS_INTE_DEV_SUSPEND_Msk | - USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk | - USBCTRL_REGS_INTE_BUFF_STATUS_Msk); + USBCTRL_REGS_INTE_SETUP_REQ_Msk | + /*USBCTRL_REGS_INTE_DEV_CONN_DIS_Msk |*/ + USBCTRL_REGS_INTE_BUFF_STATUS_Msk/* | + USBCTRL_REGS_INTE_DEV_SOF_Msk*/); io_reg_atomic_clear(&USBCTRL_REGS->SIE_CTRL, USBCTRL_REGS_SIE_CTRL_EP0_INT_1BUF_Msk); } @@ -538,12 +542,13 @@ static bool _ep_buf_is_available(usbdev_ep_t *ep) return !(buf_ctrl_reg & USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Msk); } +/* static bool _ep_buf_is_full(usbdev_ep_t *ep) { __IOM uint32_t buf_ctrl_reg = *_get_ep_buf_ctrl_reg(ep->num, ep->dir); return buf_ctrl_reg & USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_FULL_0_Msk; } - +*/ static size_t _ep_get_available(usbdev_ep_t *ep) { @@ -551,7 +556,7 @@ static size_t _ep_get_available(usbdev_ep_t *ep) if (ep->dir == USB_EP_DIR_IN) { rpx0xx_usb_ep_t *hw_ep = _get_ep(ep->num, ep->dir); return hw_ep->dpram_bufsize; - } else if(_ep_buf_is_full(ep)) { + } else { __IOM uint32_t *reg = _get_ep_buf_ctrl_reg(ep->num, ep->dir); return *reg | USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_LENGTH_0_Msk; } @@ -634,6 +639,9 @@ static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) size_t available_len = _ep_get_available(ep); + DEBUG("[rpx0xx usb] call _usbdev_ep_xmit(ep.num=%d, ep.dir=%d, len=%d), available=%d ", + ep->num, ep->dir, len, available_len); + if (available_len < len) { len = available_len; } @@ -693,6 +701,13 @@ static void _usbdev_esr(usbdev_t *dev) io_reg_atomic_clear(&USBCTRL_REGS->SIE_STATUS, USBCTRL_REGS_SIE_STATUS_CONNECTED_Msk); } + if (_hw_usb_dev.int_status & USBCTRL_REGS_INTS_SETUP_REQ_Msk) { + /* Setup Request received on EP0 */ + _hw_usb_dev.dev.epcb(&_get_ep(0, USB_EP_DIR_OUT)->ep, + USBDEV_EVENT_TR_COMPLETE); + io_reg_atomic_clear(&USBCTRL_REGS->SIE_STATUS, + USBCTRL_REGS_SIE_STATUS_SETUP_REC_Msk); + } /* all interrupts should be now cleared */ _hw_usb_dev.int_status = USBCTRL_REGS->INTS; if (_hw_usb_dev.int_status) { diff --git a/sys/usb/usbus/usbus.c b/sys/usb/usbus/usbus.c index db38ca923edd..a21ad7cecd37 100644 --- a/sys/usb/usbus/usbus.c +++ b/sys/usb/usbus/usbus.c @@ -40,7 +40,7 @@ #include #include -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG 1 #include "debug.h" #define _USBUS_MSG_QUEUE_SIZE (16) diff --git a/sys/usb/usbus/usbus_control.c b/sys/usb/usbus/usbus_control.c index 98e1dbba8f8e..ca5d278892ec 100644 --- a/sys/usb/usbus/usbus_control.c +++ b/sys/usb/usbus/usbus_control.c @@ -28,7 +28,7 @@ #include #include -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG 1 #include "debug.h" static void _init(usbus_t *usbus, usbus_handler_t *handler); From a178b9fc22044de86ea78da48e5d89c8fd3e7f3a Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 12 Sep 2024 20:30:22 +0200 Subject: [PATCH 4/4] fixup! cpu/rpxx0xx: add periph_usbus support --- cpu/rpx0xx/periph/usbdev.c | 88 +++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/cpu/rpx0xx/periph/usbdev.c b/cpu/rpx0xx/periph/usbdev.c index 63d834a71fc9..b16a04cc395b 100644 --- a/cpu/rpx0xx/periph/usbdev.c +++ b/cpu/rpx0xx/periph/usbdev.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Frank engelhardt + * Copyright (C) 2024 Frank Engelhardt * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -33,13 +33,17 @@ #define ENABLE_DEBUG 1 #include "debug.h" -#define USB_BUFFER_SPACE_START ((uint8_t*) USBCTRL_DPRAM + 0x180u) -#define USB_BUFFER_SPACE_END ((uint8_t*) USBCTRL_DPRAM + 0x1000u) +#define USB_SETUP_PKT_LEN 8 + +#define USB_BUFFER_SETUP_PKT_START ((uint8_t*) USBCTRL_DPRAM + 0x0u) +#define USB_BUFFER_SPACE_START ((uint8_t*) USBCTRL_DPRAM + 0x180u) +#define USB_BUFFER_SPACE_END ((uint8_t*) USBCTRL_DPRAM + 0x1000u) typedef struct rpx0xx_usb_ep { uint8_t *dpram_buf; size_t dpram_bufsize; usbdev_ep_t ep; + bool next_pid; } rpx0xx_usb_ep_t; typedef struct rpx0xx_usb_dev { @@ -49,6 +53,7 @@ typedef struct rpx0xx_usb_dev { uint32_t int_status; bool suspended; bool connected; + bool setup_req_recvd; } rpx0xx_usb_dev_t; /* Forward declaration for the usb device driver. */ @@ -59,6 +64,8 @@ static rpx0xx_usb_dev_t _hw_usb_dev; static uint8_t *_dpram_next_buf_ptr = (uint8_t*) USB_BUFFER_SPACE_START; +static void _mark_ep_buf_ready(usbdev_ep_t *ep, size_t len); + static inline __IOM uint32_t * _get_ep_out_ctrl_reg(uint8_t ep_num) { assert(ep_num >= 1 && ep_num < 16); @@ -527,7 +534,7 @@ static void _usbdev_ep0_stall(usbdev_t *dev) usbopt_enable_t _ep_get_stall(usbdev_ep_t *ep) { __IOM uint32_t reg = *_get_ep_buf_ctrl_reg(ep->num, ep->dir); - return reg | USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_STALL_Msk; + return reg & USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_STALL_Msk; } static void _usbdev_ep_stall(usbdev_ep_t *ep, bool enable) @@ -538,8 +545,8 @@ static void _usbdev_ep_stall(usbdev_ep_t *ep, bool enable) /* available: is the processor in control of the buffer? */ static bool _ep_buf_is_available(usbdev_ep_t *ep) { - __IOM uint32_t buf_ctrl_reg = *_get_ep_buf_ctrl_reg(ep->num, ep->dir); - return !(buf_ctrl_reg & USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Msk); + uint32_t reg = *_get_ep_buf_ctrl_reg(ep->num, ep->dir); + return !(reg & USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Msk); } /* @@ -552,13 +559,16 @@ static bool _ep_buf_is_full(usbdev_ep_t *ep) static size_t _ep_get_available(usbdev_ep_t *ep) { - if (_ep_buf_is_available(ep)) { + if (ep->num == 0 && ep->dir == USB_EP_DIR_OUT && _hw_usb_dev.setup_req_recvd) { + return USB_SETUP_PKT_LEN; + } + else if (_ep_buf_is_available(ep)) { if (ep->dir == USB_EP_DIR_IN) { rpx0xx_usb_ep_t *hw_ep = _get_ep(ep->num, ep->dir); return hw_ep->dpram_bufsize; } else { - __IOM uint32_t *reg = _get_ep_buf_ctrl_reg(ep->num, ep->dir); - return *reg | USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_LENGTH_0_Msk; + uint32_t reg = *_get_ep_buf_ctrl_reg(ep->num, ep->dir); + return reg & USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_LENGTH_0_Msk; } } return 0UL; @@ -617,43 +627,78 @@ static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, return ret; } -static void _mark_ep_buf_ready(usbdev_ep_t *ep) +static void _mark_ep_buf_ready(usbdev_ep_t *ep, size_t len) { uint32_t buf_filled_bit = 0UL; if (ep->dir == USB_EP_DIR_IN) { buf_filled_bit = USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_FULL_0_Msk; } _ep_buf_ctrl_reg_write(ep->num, ep->dir, - USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_FULL_0_Pos, + USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_FULL_0_Msk, buf_filled_bit); _ep_buf_ctrl_reg_write(ep->num, ep->dir, - USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Pos, + USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Msk, USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_Msk); + _ep_buf_ctrl_reg_write(ep->num, ep->dir, len, + USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_LENGTH_0_Msk); } -static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) +static int _usbdev_ep_xmit_setup_req(uint8_t *buf, size_t len) { - rpx0xx_usb_ep_t *hw_ep = _get_ep(ep->num, ep->dir); + DEBUG("[rpx0xx usb] call _usbdev_ep_xmit_setup_req(len=%d)", len); + assert(len >= USB_SETUP_PKT_LEN); + len = USB_SETUP_PKT_LEN; + memcpy(buf, USB_BUFFER_SETUP_PKT_START, USB_SETUP_PKT_LEN); + _hw_usb_dev.setup_req_recvd = false; + return len; +} + +static void _set_pid(rpx0xx_usb_ep_t *hw_ep) +{ + uint32_t bit = hw_ep->next_pid ? USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_PID_0_Msk : 0; + _ep_buf_ctrl_reg_write(hw_ep->ep.num, hw_ep->ep.dir, bit, + USBCTRL_DPRAM_EP0_IN_BUFFER_CONTROL_PID_0_Msk); + hw_ep->next_pid = !hw_ep->next_pid; +} - assert(_ep_buf_is_available(ep)); +static int _usbdev_ep_xmit_regular(rpx0xx_usb_ep_t *hw_ep, uint8_t *buf, size_t len) +{ + assert(_ep_buf_is_available(&hw_ep->ep)); - size_t available_len = _ep_get_available(ep); + size_t available_len = _ep_get_available(&hw_ep->ep); - DEBUG("[rpx0xx usb] call _usbdev_ep_xmit(ep.num=%d, ep.dir=%d, len=%d), available=%d ", - ep->num, ep->dir, len, available_len); + DEBUG("[rpx0xx usb] call _usbdev_ep_xmit_regular(ep.num=%d, ep.dir=%d, len=%d), available=%d ", + hw_ep->ep.num, hw_ep->ep.dir, len, available_len); + + if (available_len == 0) { + _mark_ep_buf_ready(&hw_ep->ep, 0); + return 0UL; + } if (available_len < len) { len = available_len; } - if (ep->dir == USB_EP_DIR_IN) { + if (hw_ep->ep.dir == USB_EP_DIR_IN) { memcpy(hw_ep->dpram_buf, buf, len); } else { memcpy(buf, hw_ep->dpram_buf, len); } - _ep_set_stall(ep, 0); - _mark_ep_buf_ready(ep); + _set_pid(hw_ep); + _mark_ep_buf_ready(&hw_ep->ep, len); + + return len; +} +static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) +{ + rpx0xx_usb_ep_t *hw_ep = _get_ep(ep->num, ep->dir); + if (ep->num == 0 && ep->dir == USB_EP_DIR_OUT && _hw_usb_dev.setup_req_recvd) { + len = _usbdev_ep_xmit_setup_req(buf, len); + } else { + len = _usbdev_ep_xmit_regular(hw_ep, buf, len); + } + _ep_set_stall(ep, 0); return len; } @@ -703,6 +748,7 @@ static void _usbdev_esr(usbdev_t *dev) } if (_hw_usb_dev.int_status & USBCTRL_REGS_INTS_SETUP_REQ_Msk) { /* Setup Request received on EP0 */ + _hw_usb_dev.setup_req_recvd = true; _hw_usb_dev.dev.epcb(&_get_ep(0, USB_EP_DIR_OUT)->ep, USBDEV_EVENT_TR_COMPLETE); io_reg_atomic_clear(&USBCTRL_REGS->SIE_STATUS,