Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rp2040 - ISO API to make Audio work / Merge to master #2847

Merged
merged 4 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/class/video/video_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -1307,7 +1307,7 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
#ifdef TUP_DCD_EDPT_ISO_ALLOC
/* Allocate ISO endpoints */
uint16_t ep_size = 0;
uint16_t ep_addr = 0;
uint8_t ep_addr = 0;
uint8_t const *p_desc = (uint8_t const*)itf_desc + stm->desc.beg;
uint8_t const *p_desc_end = (uint8_t const*)itf_desc + stm->desc.end;
while (p_desc < p_desc_end) {
Expand Down
1 change: 1 addition & 0 deletions src/common/tusb_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned64(uint64_t value) { retur

//------------- Mathematics -------------//
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return TU_DIV_CEIL(v, d); }
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_round_up(uint32_t v, uint32_t f) { return tu_div_ceil(v, f) * f; }

// log2 of a value is its MSB's position
// TODO use clz TODO remove
Expand Down
1 change: 1 addition & 0 deletions src/common/tusb_mcu.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@
// Raspberry Pi
//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_RP2040)
#define TUP_DCD_EDPT_ISO_ALLOC
#define TUP_DCD_ENDPOINT_MAX 16

#define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
Expand Down
108 changes: 54 additions & 54 deletions src/portable/raspberrypi/rp2040/dcd_rp2040.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
/*------------------------------------------------------------------*/
/* Low level controller
*------------------------------------------------------------------*/

// Init these in dcd_init
static uint8_t* next_buffer_ptr;

Expand All @@ -66,58 +65,31 @@ TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_addr(
return hw_endpoint_get_by_num(num, dir);
}

static void _hw_endpoint_alloc(struct hw_endpoint* ep, uint8_t transfer_type) {
// size must be multiple of 64
uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
// Allocate from the USB buffer space (max 3840 bytes)
static void hw_endpoint_alloc(struct hw_endpoint* ep, size_t size) {
// round up size to multiple of 64
size = tu_round_up(ep->wMaxPacketSize, 64);

// double buffered Bulk endpoint
if (transfer_type == TUSB_XFER_BULK) {
if (ep->transfer_type == TUSB_XFER_BULK) {
size *= 2u;
}

// assign buffer
ep->hw_data_buf = next_buffer_ptr;
next_buffer_ptr += size;

assert(((uintptr_t) next_buffer_ptr & 0b111111u) == 0);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);

pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);

// Fill in endpoint control register with buffer offset
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;

*ep->endpoint_control = reg;
}

static void _hw_endpoint_close(struct hw_endpoint* ep) {
// Clear hardware registers and then zero the struct
// Clears endpoint enable
*ep->endpoint_control = 0;
// Clears buffer available, etc
*ep->buffer_control = 0;
// Clear any endpoint state
memset(ep, 0, sizeof(struct hw_endpoint));

// Reclaim buffer space if all endpoints are closed
bool reclaim_buffers = true;
for (uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++) {
if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL ||
hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL) {
reclaim_buffers = false;
break;
}
}
if (reclaim_buffers) {
next_buffer_ptr = &usb_dpram->epx_data[0];
}
hard_assert(next_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data));
pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf);
}

static void hw_endpoint_close(uint8_t ep_addr) {
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
_hw_endpoint_close(ep);
// Enable endpoint
TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_enable(struct hw_endpoint* ep) {
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf);
*ep->endpoint_control = reg;
}

// main processing for dcd_edpt_iso_activate
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);

Expand Down Expand Up @@ -156,9 +128,18 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
} else {
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
}
}
}

// alloc a buffer and fill in endpoint control register
_hw_endpoint_alloc(ep, transfer_type);
// Init, allocate buffer and enable endpoint
static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
hw_endpoint_init(ep_addr, wMaxPacketSize, transfer_type);
const uint8_t num = tu_edpt_number(ep_addr);
if (num != 0) {
// EP0 is already enabled
hw_endpoint_alloc(ep, ep->wMaxPacketSize);
hw_endpoint_enable(ep);
}
}

Expand Down Expand Up @@ -387,8 +368,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {

// Init control endpoints
tu_memclr(hw_endpoints[0], 2 * sizeof(hw_endpoint_t));
hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
hw_endpoint_open(0x0, 64, TUSB_XFER_CONTROL);
hw_endpoint_open(0x80, 64, TUSB_XFER_CONTROL);

// Init non-control endpoints
reset_non_control_endpoints();
Expand Down Expand Up @@ -493,9 +474,34 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req
}
}

bool dcd_edpt_open(__unused uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
assert(rhport == 0);
hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
(void) rhport;
const uint8_t xfer_type = desc_edpt->bmAttributes.xfer;
TU_VERIFY(xfer_type != TUSB_XFER_ISOCHRONOUS);
hw_endpoint_open(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), xfer_type);
return true;
}

// New API: Allocate packet buffer used by ISO endpoints
// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
(void) rhport;
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
hw_endpoint_init(ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS);
hw_endpoint_alloc(ep, largest_packet_size);
return true;
}

// New API: Configure and enable an ISO endpoint according to descriptor
bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
(void) rhport;
const uint8_t ep_addr = ep_desc->bEndpointAddress;
// Fill in endpoint control register with buffer offset
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and buffer allocated
ep->wMaxPacketSize = ep_desc->wMaxPacketSize;

hw_endpoint_enable(ep);
return true;
}

Expand Down Expand Up @@ -540,12 +546,6 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
}
}

void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
(void) rhport;
pico_trace("dcd_edpt_close %02x\r\n", ep_addr);
hw_endpoint_close(ep_addr);
}

void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport) {
(void) rhport;
dcd_rp2040_irq();
Expand Down
Loading