88
99#if PBDRV_CONFIG_USB_EV3
1010
11+ #include <assert.h>
1112#include <stdint.h>
1213
1314#include <pbdrv/usb.h>
1920#include "pbdrvconfig.h"
2021
2122#include <tiam1808/armv5/am1808/interrupt.h>
23+ #include <tiam1808/cppi41dma.h>
2224#include <tiam1808/hw/hw_types.h>
2325#include <tiam1808/hw/hw_usbOtg_AM1808.h>
2426#include <tiam1808/hw/hw_syscfg0_AM1808.h>
@@ -225,6 +227,115 @@ static uint32_t setup_misc_tx_byte;
225227// Whether the device is using USB high-speed mode or not
226228static bool is_usb_hs ;
227229
230+ // Buffers, used for different logical flows on the data endpoint
231+ static uint8_t ep1_rx_buf [PYBRICKS_EP_PKT_SZ_HS ];
232+ static uint8_t ep1_tx_response_buf [PYBRICKS_EP_PKT_SZ_HS ];
233+ static uint8_t ep1_tx_status_buf [PYBRICKS_EP_PKT_SZ_HS ];
234+ static uint8_t ep1_tx_stdout_buf [PYBRICKS_EP_PKT_SZ_HS ];
235+
236+ // Buffer status flags
237+ static volatile bool usb_rx_is_ready ;
238+ static volatile bool usb_tx_response_is_not_ready ;
239+ static volatile bool usb_tx_status_is_not_ready ;
240+ static volatile bool usb_tx_stdout_is_not_ready ;
241+
242+ // CPPI DMA support code
243+
244+ // Descriptors must be aligned to a power of 2 greater than or equal to their size.
245+ // We are using a descriptor of 32 bytes which is also the required alignment.
246+ #define CPPI_DESCRIPTOR_ALIGN 32
247+
248+ // Host Packet Descriptor
249+ // The TI support library has hardcoded assumptions about the layout of these structures,
250+ // so we declare it ourselves here in order to control it as we wish.
251+ typedef struct {
252+ hPDWord0 word0 ;
253+ hPDWord1 word1 ;
254+ hPDWord2 word2 ;
255+ uint32_t buf_len ;
256+ void * buf_ptr ;
257+ void * next_desc_ptr ;
258+ uint32_t orig_buf_len ;
259+ void * orig_buf_ptr ;
260+ } __attribute__((aligned (CPPI_DESCRIPTOR_ALIGN ))) usb_cppi_hpd_t ;
261+ _Static_assert (sizeof (usb_cppi_hpd_t ) <= CPPI_DESCRIPTOR_ALIGN );
262+
263+ // This goes into the lower bits of the queue CTRLD register
264+ #define CPPI_DESCRIPTOR_SIZE_BITS ((sizeof(usb_cppi_hpd_t) - 24) / 4)
265+
266+ // We only use a hardcoded descriptor for each logical flow,
267+ // rather than dynamically allocating them as needed
268+ enum {
269+ CPPI_DESC_RX ,
270+ CPPI_DESC_TX_RESPONSE ,
271+ CPPI_DESC_TX_STATUS ,
272+ CPPI_DESC_TX_STDOUT ,
273+ // the minimum number of descriptors we can allocate is 32,
274+ // even though we do not use nearly all of them
275+ CPPI_DESC_COUNT = 32 ,
276+ };
277+
278+ enum {
279+ // Documenting explicitly that we only use RX queue 0
280+ // (out of 16 total which are supported by the hardware)
281+ CPPI_RX_SUBMIT_QUEUE = 0 ,
282+ };
283+
284+ // CPPI memory
285+ static usb_cppi_hpd_t cppi_descriptors [CPPI_DESC_COUNT ];
286+ static uint32_t cppi_linking_ram [CPPI_DESC_COUNT ];
287+
288+ // Fill in the CPPI DMA descriptor to receive a packet
289+ static void usb_setup_rx_dma_desc (void ) {
290+ cppi_descriptors [CPPI_DESC_RX ] = (usb_cppi_hpd_t ) {
291+ .word0 = {
292+ .hostPktType = 0x10 ,
293+ },
294+ .word1 = {},
295+ .word2 = {
296+ .pktRetQueue = RX_COMPQ1 ,
297+ },
298+ .buf_len = PYBRICKS_EP_PKT_SZ_HS ,
299+ .buf_ptr = ep1_rx_buf ,
300+ .next_desc_ptr = 0 ,
301+ .orig_buf_len = PYBRICKS_EP_PKT_SZ_HS ,
302+ .orig_buf_ptr = ep1_rx_buf ,
303+ };
304+
305+ __asm__ volatile ("" ::: "memory" );
306+
307+ HWREG (USB_0_OTGBASE + CPDMA_QUEUE_REGISTER_D + CPPI_RX_SUBMIT_QUEUE * 16 ) =
308+ (uint32_t )(& cppi_descriptors [CPPI_DESC_RX ]) | CPPI_DESCRIPTOR_SIZE_BITS ;
309+ }
310+
311+
312+ // Fill in the CPPI DMA descriptor to send a packet
313+ static void usb_setup_tx_dma_desc (int tx_type , void * buf , uint32_t buf_len ) {
314+ cppi_descriptors [tx_type ] = (usb_cppi_hpd_t ) {
315+ .word0 = {
316+ .hostPktType = 0x10 ,
317+ .pktLength = buf_len ,
318+ },
319+ .word1 = {
320+ .srcPrtNum = 1 , // port is EP1
321+ },
322+ .word2 = {
323+ .pktType = 5 , // USB packet type
324+ .pktRetQueue = TX_COMPQ1 ,
325+ },
326+ .buf_len = buf_len ,
327+ .buf_ptr = buf ,
328+ .next_desc_ptr = 0 ,
329+ .orig_buf_len = buf_len ,
330+ .orig_buf_ptr = buf ,
331+ };
332+
333+ __asm__ volatile ("" ::: "memory" );
334+
335+ HWREG (USB_0_OTGBASE + CPDMA_QUEUE_REGISTER_D + TX_SUBMITQ1 * 16 ) =
336+ (uint32_t )(& cppi_descriptors [tx_type ]) | CPPI_DESCRIPTOR_SIZE_BITS ;
337+ }
338+
228339// Helper function for dividing up buffers for EP0 and feeding the FIFO
229340static void usb_setup_send_chunk (void ) {
230341 unsigned int this_chunk_sz = setup_data_to_send_sz ;
@@ -266,7 +377,64 @@ static void usb_device_intr(void) {
266377 is_usb_hs = false;
267378 }
268379
269- // TODO: More tasks in the future
380+ // Set up the FIFOs
381+ // We use a hardcoded address allocation as follows
382+ // @ 0 ==> EP0
383+ // @ 64 ==> EP1 IN (device to host, tx)
384+ // @ 64+512 ==> EP1 OUT (host to device, rx)
385+ HWREGB (USB0_BASE + USB_O_EPIDX ) = 1 ;
386+ if (is_usb_hs ) {
387+ HWREGB (USB0_BASE + USB_O_TXFIFOSZ ) = USB_TXFIFOSZ_SIZE_512 ;
388+ HWREGB (USB0_BASE + USB_O_RXFIFOSZ ) = USB_RXFIFOSZ_SIZE_512 ;
389+ HWREGH (USB0_BASE + USB_O_TXMAXP1 ) = PYBRICKS_EP_PKT_SZ_HS ;
390+ HWREGH (USB0_BASE + USB_O_RXMAXP1 ) = PYBRICKS_EP_PKT_SZ_HS ;
391+ } else {
392+ HWREGB (USB0_BASE + USB_O_TXFIFOSZ ) = USB_TXFIFOSZ_SIZE_64 ;
393+ HWREGB (USB0_BASE + USB_O_RXFIFOSZ ) = USB_RXFIFOSZ_SIZE_64 ;
394+ HWREGH (USB0_BASE + USB_O_TXMAXP1 ) = PYBRICKS_EP_PKT_SZ_FS ;
395+ HWREGH (USB0_BASE + USB_O_RXMAXP1 ) = PYBRICKS_EP_PKT_SZ_FS ;
396+ }
397+ HWREGH (USB0_BASE + USB_O_TXFIFOADD ) = EP0_BUF_SZ / 8 ;
398+ HWREGH (USB0_BASE + USB_O_RXFIFOADD ) = (EP0_BUF_SZ + PYBRICKS_EP_PKT_SZ_HS ) / 8 ;
399+
400+ // Set up the TX fifo for DMA and a stall condition
401+ HWREGH (USB0_BASE + USB_O_TXCSRL1 ) = ((USB_TXCSRH1_AUTOSET | USB_TXCSRH1_MODE | USB_TXCSRH1_DMAEN | USB_TXCSRH1_DMAMOD ) << 8 ) | USB_TXCSRL1_STALL ;
402+ // Set up the RX fifo for DMA and a stall condition
403+ HWREGH (USB0_BASE + USB_O_RXCSRL1 ) = ((USB_RXCSRH1_AUTOCL | USB_RXCSRH1_DMAEN ) << 8 ) | USB_RXCSRL1_STALL ;
404+
405+ // Set up CPPI DMA
406+ HWREG (USB_0_OTGBASE + CPDMA_LRAM_0_BASE ) = (uint32_t )cppi_linking_ram ;
407+ HWREG (USB_0_OTGBASE + CPDMA_LRAM_0_SIZE ) = CPPI_DESC_COUNT ;
408+ HWREG (USB_0_OTGBASE + CPDMA_LRAM_1_BASE ) = 0 ;
409+
410+ HWREG (USB_0_OTGBASE + CPDMA_QUEUEMGR_REGION_0 ) = (uint32_t )cppi_descriptors ;
411+ // 32 descriptors of 32 bytes each
412+ HWREG (USB_0_OTGBASE + CPDMA_QUEUEMGR_REGION_0_CONTROL ) = 0 ;
413+
414+ // scheduler table: RX on 0, TX on 0
415+ HWREG (USB_0_OTGBASE + CPDMA_SCHED_TABLE_0 ) = 0x0080 ;
416+ HWREG (USB_0_OTGBASE + CPDMA_SCHED_CONTROL_REG ) = (1 << SCHEDULER_ENABLE_SHFT ) | (2 - 1 );
417+
418+ // CPPI RX
419+ HWREG (USB_0_OTGBASE + CPDMA_RX_CHANNEL_REG_A ) =
420+ (CPPI_RX_SUBMIT_QUEUE << 0 ) |
421+ (CPPI_RX_SUBMIT_QUEUE << 16 );
422+ HWREG (USB_0_OTGBASE + CPDMA_RX_CHANNEL_REG_B ) =
423+ (CPPI_RX_SUBMIT_QUEUE << 0 ) |
424+ (CPPI_RX_SUBMIT_QUEUE << 16 );
425+ HWREG (USB_0_OTGBASE + CPDMA_RX_CHANNEL_CONFIG_REG ) =
426+ (1 << 31 ) | // enable
427+ (1 << 24 ) | // starvation = retry
428+ (1 << 14 ) | // "host" descriptors (the only valid type)
429+ RX_COMPQ1 ;
430+
431+ // CPPI TX
432+ HWREG (USB_0_OTGBASE + CPDMA_TX_CHANNEL_CONFIG_REG ) =
433+ (1 << 31 ) | // enable
434+ TX_COMPQ1 ;
435+
436+ // queue RX descriptor
437+ usb_setup_rx_dma_desc ();
270438 }
271439
272440 if (intr_src & INTR_BIT_EP0 ) {
@@ -313,11 +481,15 @@ static void usb_device_intr(void) {
313481 if (usb_config == 1 ) {
314482 // configuring
315483
316- // TODO: Handle configuring
484+ // Reset data toggle, clear stall, flush fifo
485+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH ;
486+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH ;
317487 } else {
318488 // deconfiguring
319489
320- // TODO: Handle deconfiguring
490+ // Set stall condition
491+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) = USB_TXCSRL1_STALL ;
492+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) = USB_RXCSRL1_STALL ;
321493 }
322494 handled = 1 ;
323495 }
@@ -422,6 +594,38 @@ static void usb_device_intr(void) {
422594 handled = 1 ;
423595 }
424596 }
597+ } else if (((setup_pkt .s .bmRequestType & BM_REQ_TYPE_MASK ) == BM_REQ_TYPE_STANDARD ) &&
598+ ((setup_pkt .s .bmRequestType & BM_REQ_RECIP_MASK ) == BM_REQ_RECIP_EP )) {
599+
600+ if (setup_pkt .s .bRequest == GET_STATUS ) {
601+ if (setup_pkt .s .wIndex == 1 ) {
602+ setup_misc_tx_byte = !!(HWREGB (USB0_BASE + USB_O_RXCSRL1 ) & USB_RXCSRL1_STALL );
603+ setup_data_to_send = & setup_misc_tx_byte ;
604+ setup_data_to_send_sz = 2 ;
605+ handled = 1 ;
606+ } else if (setup_pkt .s .wIndex == 0x81 ) {
607+ setup_misc_tx_byte = !!(HWREGB (USB0_BASE + USB_O_TXCSRL1 ) & USB_TXCSRL1_STALL );
608+ setup_data_to_send = & setup_misc_tx_byte ;
609+ setup_data_to_send_sz = 2 ;
610+ handled = 1 ;
611+ }
612+ } else if (setup_pkt .s .bRequest == CLEAR_FEATURE && setup_pkt .s .wValue == 0 ) {
613+ if (setup_pkt .s .wIndex == 1 ) {
614+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) &= ~USB_RXCSRL1_STALL ;
615+ handled = 1 ;
616+ } else if (setup_pkt .s .wIndex == 0x81 ) {
617+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) &= ~USB_TXCSRL1_STALL ;
618+ handled = 1 ;
619+ }
620+ } else if (setup_pkt .s .bRequest == SET_FEATURE && setup_pkt .s .wValue == 0 ) {
621+ if (setup_pkt .s .wIndex == 1 ) {
622+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) |= USB_RXCSRL1_STALL ;
623+ handled = 1 ;
624+ } else if (setup_pkt .s .wIndex == 0x81 ) {
625+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) |= USB_TXCSRL1_STALL ;
626+ handled = 1 ;
627+ }
628+ }
425629 }
426630
427631 if (!handled ) {
@@ -460,6 +664,61 @@ static void usb_device_intr(void) {
460664 }
461665 }
462666
667+ // EP1 interrupts, which only trigger on error conditions since we use DMA
668+
669+ if (intr_src & INTR_BIT_EP1_OUT ) {
670+ // EP 1 OUT, host to device, rx
671+ uint8_t rxcsr = HWREGB (USB0_BASE + USB_O_RXCSRL1 );
672+
673+ // Clear error bits
674+ rxcsr &= ~USB_RXCSRL1_STALLED ;
675+
676+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) = rxcsr ;
677+ }
678+
679+ if (intr_src & INTR_BIT_EP1_IN ) {
680+ // EP 1 IN, device to host, tx
681+ uint8_t txcsr = HWREGB (USB0_BASE + USB_O_TXCSRL1 );
682+
683+ // Clear error bits
684+ txcsr &= ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_UNDRN | USB_TXCSRL1_FIFONE );
685+
686+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) = txcsr ;
687+ }
688+
689+ // Check for DMA completions
690+ uint32_t dma_q_pend_0 = HWREG (USB_0_OTGBASE + CPDMA_PEND_0_REGISTER );
691+
692+ if (dma_q_pend_0 & (1 << RX_COMPQ1 )) {
693+ // DMA for EP 1 OUT is done
694+
695+ // Pop the descriptor from the queue
696+ uint32_t qctrld = HWREG (USB_0_OTGBASE + CPDMA_QUEUE_REGISTER_D + RX_COMPQ1 * 16 );
697+ (void )qctrld ;
698+
699+ // Signal the main loop that we have something
700+ usb_rx_is_ready = true;
701+ pbio_os_request_poll ();
702+ }
703+
704+ if (dma_q_pend_0 & (1 << TX_COMPQ1 )) {
705+ // DMA for EP 1 IN is done
706+
707+ // Pop the descriptor from the queue
708+ uint32_t qctrld = HWREG (USB_0_OTGBASE + CPDMA_QUEUE_REGISTER_D + TX_COMPQ1 * 16 ) & ~0x1f ;
709+
710+ if (qctrld == (uint32_t )(& cppi_descriptors [CPPI_DESC_TX_RESPONSE ])) {
711+ usb_tx_response_is_not_ready = false;
712+ pbio_os_request_poll ();
713+ } else if (qctrld == (uint32_t )(& cppi_descriptors [CPPI_DESC_TX_STATUS ])) {
714+ usb_tx_status_is_not_ready = false;
715+ pbio_os_request_poll ();
716+ } else if (qctrld == (uint32_t )(& cppi_descriptors [CPPI_DESC_TX_STDOUT ])) {
717+ usb_tx_stdout_is_not_ready = false;
718+ pbio_os_request_poll ();
719+ }
720+ }
721+
463722 HWREG (USB_0_OTGBASE + USB_0_INTR_SRC_CLEAR ) = intr_src ;
464723 HWREG (USB_0_OTGBASE + USB_0_END_OF_INTR ) = 0 ;
465724}
@@ -469,6 +728,38 @@ static pbio_os_process_t pbdrv_usb_ev3_process;
469728static pbio_error_t pbdrv_usb_ev3_process_thread (pbio_os_state_t * state , void * context ) {
470729 PBIO_OS_ASYNC_BEGIN (state );
471730
731+ for (;;) {
732+ PBIO_OS_AWAIT_UNTIL (state , usb_rx_is_ready );
733+
734+ if (usb_rx_is_ready ) {
735+ __asm__ volatile ("" ::: "memory" );
736+
737+ uint32_t usb_rx_sz = cppi_descriptors [CPPI_DESC_RX ].word0 .pktLength ;
738+
739+ // TODO: Remove this echo test
740+ unsigned int i ;
741+ for (i = 0 ; i < usb_rx_sz ; i ++ ) {
742+ ep1_tx_response_buf [i ] = ep1_rx_buf [i ] + 1 ;
743+ }
744+ for (; i < 512 ; i ++ ) {
745+ ep1_tx_response_buf [i ] = 0xaa ;
746+ }
747+
748+ (void )ep1_tx_status_buf ;
749+ (void )ep1_tx_stdout_buf ;
750+
751+ unsigned int tx_sz = is_usb_hs ? PYBRICKS_EP_PKT_SZ_HS : PYBRICKS_EP_PKT_SZ_FS ;
752+ if (!usb_tx_response_is_not_ready ) {
753+ usb_tx_response_is_not_ready = true;
754+ usb_setup_tx_dma_desc (CPPI_DESC_TX_RESPONSE , ep1_tx_response_buf , tx_sz );
755+ }
756+
757+ // Re-queue RX buffer after processing is complete
758+ usb_rx_is_ready = false;
759+ usb_setup_rx_dma_desc ();
760+ }
761+ }
762+
472763 PBIO_OS_ASYNC_END (PBIO_SUCCESS );
473764}
474765
0 commit comments