1919#include "pbdrvconfig.h"
2020
2121#include <tiam1808/armv5/am1808/interrupt.h>
22+ #include <tiam1808/cppi41dma.h>
2223#include <tiam1808/hw/hw_types.h>
2324#include <tiam1808/hw/hw_usbOtg_AM1808.h>
2425#include <tiam1808/hw/hw_syscfg0_AM1808.h>
@@ -224,6 +225,105 @@ static uint32_t setup_misc_tx_byte;
224225// Whether the device is using USB high-speed mode or not
225226static int is_usb_hs ;
226227
228+ // Buffers, used for different logical flows on the data endpoint
229+ static uint8_t ep1_rx_buf [PYBRICKS_EP_PKT_SZ_HS ];
230+ static uint8_t ep1_tx_response_buf [PYBRICKS_EP_PKT_SZ_HS ];
231+ static uint8_t ep1_tx_status_buf [PYBRICKS_EP_PKT_SZ_HS ];
232+ static uint8_t ep1_tx_stdout_buf [PYBRICKS_EP_PKT_SZ_HS ];
233+
234+ // Buffer status flags
235+ static volatile int usb_rx_is_ready ;
236+ static volatile int usb_tx_response_is_not_ready ;
237+ static volatile int usb_tx_status_is_not_ready ;
238+ static volatile int usb_tx_stdout_is_not_ready ;
239+
240+ // CPPI DMA support code
241+
242+ // Host Packet Descriptor
243+ // The TI support library has hardcoded assumptions about the layout of these structures,
244+ // so we declare it ourselves here in order to control it as we wish.
245+ typedef struct {
246+ hPDWord0 word0 ;
247+ hPDWord1 word1 ;
248+ hPDWord2 word2 ;
249+ uint32_t buf_len ;
250+ void * buf_ptr ;
251+ void * next_desc_ptr ;
252+ uint32_t orig_buf_len ;
253+ void * orig_buf_ptr ;
254+ } __attribute__((aligned (32 ))) usb_cppi_hpd ;
255+
256+ // We only use a hardcoded descriptor for each logical flow,
257+ // rather than dynamically allocating them as needed
258+ enum {
259+ CPPI_DESC_RX ,
260+ CPPI_DESC_TX_RESPONSE ,
261+ CPPI_DESC_TX_STATUS ,
262+ CPPI_DESC_TX_STDOUT ,
263+ // the minimum number of descriptors we can allocate is 32,
264+ // even though we do not use nearly all of them
265+ CPPI_DESC_COUNT = 32 ,
266+ };
267+
268+ enum {
269+ CPPI_RX_SUBMIT_QUEUE = 0 ,
270+ };
271+
272+ // CPPI memory
273+ usb_cppi_hpd cppi_descriptors [CPPI_DESC_COUNT ];
274+ uint32_t cppi_linking_ram [CPPI_DESC_COUNT ];
275+
276+ // Fill in the CPPI DMA descriptor to receive a packet
277+ static void usb_setup_rx_dma_desc () {
278+ cppi_descriptors [CPPI_DESC_RX ] = (usb_cppi_hpd ) {
279+ .word0 = {
280+ .hostPktType = 0x10 ,
281+ },
282+ .word1 = {},
283+ .word2 = {
284+ .pktRetQueue = RX_COMPQ1 ,
285+ },
286+ .buf_len = PYBRICKS_EP_PKT_SZ_HS ,
287+ .buf_ptr = ep1_rx_buf ,
288+ .next_desc_ptr = 0 ,
289+ .orig_buf_len = PYBRICKS_EP_PKT_SZ_HS ,
290+ .orig_buf_ptr = ep1_rx_buf ,
291+ };
292+
293+ __asm__ volatile ("" ::: "memory" );
294+
295+ HWREG (USB_0_OTGBASE + CPDMA_QUEUE_REGISTER_D + CPPI_RX_SUBMIT_QUEUE * 16 ) =
296+ (uint32_t )(& cppi_descriptors [CPPI_DESC_RX ]) | 2 ;
297+ }
298+
299+
300+ // Fill in the CPPI DMA descriptor to send a packet
301+ static void usb_setup_tx_dma_desc (int tx_type , void * buf , uint32_t buf_len ) {
302+ cppi_descriptors [tx_type ] = (usb_cppi_hpd ) {
303+ .word0 = {
304+ .hostPktType = 0x10 ,
305+ .pktLength = buf_len ,
306+ },
307+ .word1 = {
308+ .srcPrtNum = 1 , // port is EP1
309+ },
310+ .word2 = {
311+ .pktType = 5 , // USB packet type
312+ .pktRetQueue = TX_COMPQ1 ,
313+ },
314+ .buf_len = buf_len ,
315+ .buf_ptr = buf ,
316+ .next_desc_ptr = 0 ,
317+ .orig_buf_len = buf_len ,
318+ .orig_buf_ptr = buf ,
319+ };
320+
321+ __asm__ volatile ("" ::: "memory" );
322+
323+ HWREG (USB_0_OTGBASE + CPDMA_QUEUE_REGISTER_D + TX_SUBMITQ1 * 16 ) =
324+ (uint32_t )(& cppi_descriptors [tx_type ]) | 2 ;
325+ }
326+
227327// Helper function for dividing up buffers for EP0 and feeding the FIFO
228328static void usb_setup_send_chunk () {
229329 unsigned int this_chunk_sz = setup_data_to_send_sz ;
@@ -265,7 +365,64 @@ static void usb_device_intr() {
265365 is_usb_hs = 0 ;
266366 }
267367
268- // TODO: More tasks in the future
368+ // Set up the FIFOs
369+ // We use a hardcoded address allocation as follows
370+ // @ 0 ==> EP0
371+ // @ 64 ==> EP1 IN (device to host, tx)
372+ // @ 64+512 ==> EP1 OUT (host to device, rx)
373+ HWREGB (USB0_BASE + USB_O_EPIDX ) = 1 ;
374+ if (is_usb_hs ) {
375+ HWREGB (USB0_BASE + USB_O_TXFIFOSZ ) = USB_TXFIFOSZ_SIZE_512 ;
376+ HWREGB (USB0_BASE + USB_O_RXFIFOSZ ) = USB_RXFIFOSZ_SIZE_512 ;
377+ HWREGH (USB0_BASE + USB_O_TXMAXP1 ) = 512 ;
378+ HWREGH (USB0_BASE + USB_O_RXMAXP1 ) = 512 ;
379+ } else {
380+ HWREGB (USB0_BASE + USB_O_TXFIFOSZ ) = USB_TXFIFOSZ_SIZE_64 ;
381+ HWREGB (USB0_BASE + USB_O_RXFIFOSZ ) = USB_RXFIFOSZ_SIZE_64 ;
382+ HWREGH (USB0_BASE + USB_O_TXMAXP1 ) = 64 ;
383+ HWREGH (USB0_BASE + USB_O_RXMAXP1 ) = 64 ;
384+ }
385+ HWREGH (USB0_BASE + USB_O_TXFIFOADD ) = 64 / 8 ;
386+ HWREGH (USB0_BASE + USB_O_RXFIFOADD ) = (64 + 512 ) / 8 ;
387+
388+ // Set up the TX fifo for DMA and a stall condition
389+ HWREGH (USB0_BASE + USB_O_TXCSRL1 ) = ((USB_TXCSRH1_AUTOSET | USB_TXCSRH1_MODE | USB_TXCSRH1_DMAEN | USB_TXCSRH1_DMAMOD ) << 8 ) | USB_TXCSRL1_STALL ;
390+ // Set up the RX fifo for DMA and a stall condition
391+ HWREGH (USB0_BASE + USB_O_RXCSRL1 ) = ((USB_RXCSRH1_AUTOCL | USB_RXCSRH1_DMAEN ) << 8 ) | USB_RXCSRL1_STALL ;
392+
393+ // Set up CPPI DMA
394+ HWREG (USB_0_OTGBASE + CPDMA_LRAM_0_BASE ) = (uint32_t )cppi_linking_ram ;
395+ HWREG (USB_0_OTGBASE + CPDMA_LRAM_0_SIZE ) = CPPI_DESC_COUNT ;
396+ HWREG (USB_0_OTGBASE + CPDMA_LRAM_1_BASE ) = 0 ;
397+
398+ HWREG (USB_0_OTGBASE + CPDMA_QUEUEMGR_REGION_0 ) = (uint32_t )cppi_descriptors ;
399+ // 32 descriptors of 32 bytes each
400+ HWREG (USB_0_OTGBASE + CPDMA_QUEUEMGR_REGION_0_CONTROL ) = 0 ;
401+
402+ // scheduler table: RX on 0, TX on 0
403+ HWREG (USB_0_OTGBASE + CPDMA_SCHED_TABLE_0 ) = 0x0080 ;
404+ HWREG (USB_0_OTGBASE + CPDMA_SCHED_CONTROL_REG ) = (1 << SCHEDULER_ENABLE_SHFT ) | (2 - 1 );
405+
406+ // CPPI RX
407+ HWREG (USB_0_OTGBASE + CPDMA_RX_CHANNEL_REG_A ) =
408+ (CPPI_RX_SUBMIT_QUEUE << 0 ) |
409+ (CPPI_RX_SUBMIT_QUEUE << 16 );
410+ HWREG (USB_0_OTGBASE + CPDMA_RX_CHANNEL_REG_B ) =
411+ (CPPI_RX_SUBMIT_QUEUE << 0 ) |
412+ (CPPI_RX_SUBMIT_QUEUE << 16 );
413+ HWREG (USB_0_OTGBASE + CPDMA_RX_CHANNEL_CONFIG_REG ) =
414+ (1 << 31 ) | // enable
415+ (1 << 24 ) | // starvation = retry
416+ (1 << 14 ) | // "host" descriptors (the only valid type)
417+ RX_COMPQ1 ;
418+
419+ // CPPI TX
420+ HWREG (USB_0_OTGBASE + CPDMA_TX_CHANNEL_CONFIG_REG ) =
421+ (1 << 31 ) | // enable
422+ TX_COMPQ1 ;
423+
424+ // queue RX descriptor
425+ usb_setup_rx_dma_desc ();
269426 }
270427
271428 if (intr_src & (1 << 0 )) {
@@ -312,11 +469,15 @@ static void usb_device_intr() {
312469 if (usb_config == 1 ) {
313470 // configuring
314471
315- // TODO: Handle configuring
472+ // Reset data toggle, clear stall, flush fifo
473+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) = USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH ;
474+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) = USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH ;
316475 } else {
317476 // deconfiguring
318477
319- // TODO: Handle deconfiguring
478+ // Set stall condition
479+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) = USB_TXCSRL1_STALL ;
480+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) = USB_RXCSRL1_STALL ;
320481 }
321482 handled = 1 ;
322483 }
@@ -421,6 +582,38 @@ static void usb_device_intr() {
421582 handled = 1 ;
422583 }
423584 }
585+ } else if (((setup_pkt .s .bmRequestType & BM_REQ_TYPE_MASK ) == BM_REQ_TYPE_STANDARD ) &&
586+ ((setup_pkt .s .bmRequestType & BM_REQ_RECIP_MASK ) == BM_REQ_RECIP_EP )) {
587+
588+ if (setup_pkt .s .bRequest == GET_STATUS ) {
589+ if (setup_pkt .s .wIndex == 1 ) {
590+ setup_misc_tx_byte = !!(HWREGB (USB0_BASE + USB_O_RXCSRL1 ) & USB_RXCSRL1_STALL );
591+ setup_data_to_send = & setup_misc_tx_byte ;
592+ setup_data_to_send_sz = 2 ;
593+ handled = 1 ;
594+ } else if (setup_pkt .s .wIndex == 0x81 ) {
595+ setup_misc_tx_byte = !!(HWREGB (USB0_BASE + USB_O_TXCSRL1 ) & USB_TXCSRL1_STALL );
596+ setup_data_to_send = & setup_misc_tx_byte ;
597+ setup_data_to_send_sz = 2 ;
598+ handled = 1 ;
599+ }
600+ } else if (setup_pkt .s .bRequest == CLEAR_FEATURE && setup_pkt .s .wValue == 0 ) {
601+ if (setup_pkt .s .wIndex == 1 ) {
602+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) &= ~USB_RXCSRL1_STALL ;
603+ handled = 1 ;
604+ } else if (setup_pkt .s .wIndex == 0x81 ) {
605+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) &= ~USB_TXCSRL1_STALL ;
606+ handled = 1 ;
607+ }
608+ } else if (setup_pkt .s .bRequest == SET_FEATURE && setup_pkt .s .wValue == 0 ) {
609+ if (setup_pkt .s .wIndex == 1 ) {
610+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) |= USB_RXCSRL1_STALL ;
611+ handled = 1 ;
612+ } else if (setup_pkt .s .wIndex == 0x81 ) {
613+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) |= USB_TXCSRL1_STALL ;
614+ handled = 1 ;
615+ }
616+ }
424617 }
425618
426619 if (!handled ) {
@@ -459,6 +652,61 @@ static void usb_device_intr() {
459652 }
460653 }
461654
655+ // EP1 interrupts, which only trigger on error conditions since we use DMA
656+
657+ if (intr_src & (1 << 9 )) {
658+ // EP 1 OUT, host to device, rx
659+ uint8_t rxcsr = HWREGB (USB0_BASE + USB_O_RXCSRL1 );
660+
661+ // Clear error bits
662+ rxcsr &= ~USB_RXCSRL1_STALLED ;
663+
664+ HWREGB (USB0_BASE + USB_O_RXCSRL1 ) = rxcsr ;
665+ }
666+
667+ if (intr_src & (1 << 1 )) {
668+ // EP 1 IN, device to host, tx
669+ uint8_t txcsr = HWREGB (USB0_BASE + USB_O_TXCSRL1 );
670+
671+ // Clear error bits
672+ txcsr &= ~(USB_TXCSRL1_STALLED | USB_TXCSRL1_UNDRN | USB_TXCSRL1_FIFONE );
673+
674+ HWREGB (USB0_BASE + USB_O_TXCSRL1 ) = txcsr ;
675+ }
676+
677+ // Check for DMA completions
678+ uint32_t dma_q_pend_0 = HWREG (USB_0_OTGBASE + CPDMA_PEND_0_REGISTER );
679+
680+ if (dma_q_pend_0 & (1 << RX_COMPQ1 )) {
681+ // DMA for EP 1 OUT is done
682+
683+ // Pop the descriptor from the queue
684+ uint32_t qctrld = HWREG (USB_0_OTGBASE + CPDMA_QUEUE_REGISTER_D + RX_COMPQ1 * 16 );
685+ (void )qctrld ;
686+
687+ // Signal the main loop that we have something
688+ usb_rx_is_ready = 1 ;
689+ pbio_os_request_poll ();
690+ }
691+
692+ if (dma_q_pend_0 & (1 << TX_COMPQ1 )) {
693+ // DMA for EP 1 IN is done
694+
695+ // Pop the descriptor from the queue
696+ uint32_t qctrld = HWREG (USB_0_OTGBASE + CPDMA_QUEUE_REGISTER_D + TX_COMPQ1 * 16 ) & ~0x1f ;
697+
698+ if (qctrld == (uint32_t )(& cppi_descriptors [CPPI_DESC_TX_RESPONSE ])) {
699+ usb_tx_response_is_not_ready = 0 ;
700+ pbio_os_request_poll ();
701+ } else if (qctrld == (uint32_t )(& cppi_descriptors [CPPI_DESC_TX_STATUS ])) {
702+ usb_tx_status_is_not_ready = 0 ;
703+ pbio_os_request_poll ();
704+ } else if (qctrld == (uint32_t )(& cppi_descriptors [CPPI_DESC_TX_STDOUT ])) {
705+ usb_tx_stdout_is_not_ready = 0 ;
706+ pbio_os_request_poll ();
707+ }
708+ }
709+
462710 HWREG (USB_0_OTGBASE + USB_0_INTR_SRC_CLEAR ) = intr_src ;
463711 HWREG (USB_0_OTGBASE + USB_0_END_OF_INTR ) = 0 ;
464712}
@@ -468,6 +716,38 @@ static pbio_os_process_t pbdrv_usb_ev3_process;
468716pbio_error_t pbdrv_usb_ev3_process_thread (pbio_os_state_t * state , void * context ) {
469717 PBIO_OS_ASYNC_BEGIN (state );
470718
719+ for (;;) {
720+ PBIO_OS_AWAIT_UNTIL (state , usb_rx_is_ready );
721+
722+ if (usb_rx_is_ready ) {
723+ __asm__ volatile ("" ::: "memory" );
724+
725+ uint32_t usb_rx_sz = cppi_descriptors [CPPI_DESC_RX ].word0 .pktLength ;
726+
727+ // TODO: Remove this echo test
728+ unsigned int i ;
729+ for (i = 0 ; i < usb_rx_sz ; i ++ ) {
730+ ep1_tx_response_buf [i ] = ep1_rx_buf [i ] + 1 ;
731+ }
732+ for (; i < 512 ; i ++ ) {
733+ ep1_tx_response_buf [i ] = 0xaa ;
734+ }
735+
736+ (void )ep1_tx_status_buf ;
737+ (void )ep1_tx_stdout_buf ;
738+
739+ unsigned int tx_sz = is_usb_hs ? PYBRICKS_EP_PKT_SZ_HS : PYBRICKS_EP_PKT_SZ_FS ;
740+ if (!usb_tx_response_is_not_ready ) {
741+ usb_tx_response_is_not_ready = 1 ;
742+ usb_setup_tx_dma_desc (CPPI_DESC_TX_RESPONSE , ep1_tx_response_buf , tx_sz );
743+ }
744+
745+ // Re-queue RX buffer after processing is complete
746+ usb_rx_is_ready = 0 ;
747+ usb_setup_rx_dma_desc ();
748+ }
749+ }
750+
471751 PBIO_OS_ASYNC_END (PBIO_SUCCESS );
472752}
473753
0 commit comments