Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: arc: implement batched request api

Change-Id: I9d677286589a336d7258cf2c9d3c7d2847243dfa

mojyack 03060090 f84003fa

+197 -5
+4
firmware/export/config.h
··· 1362 1362 //#define USB_HAS_INTERRUPT -- seems to be broken 1363 1363 #endif /* CONFIG_USBOTG */ 1364 1364 1365 + #if CONFIG_USBOTG == USBOTG_ARC 1366 + #define USB_BATCH_SLOTS 16 1367 + #else 1365 1368 #define USB_BATCH_NON_NATIVE 1366 1369 #define USB_BATCH_SLOTS 1 1370 + #endif 1367 1371 1368 1372 /* define the class drivers to enable */ 1369 1373 #ifdef BOOTLOADER
+193 -5
firmware/target/arm/usb-drv-arc.c
··· 362 362 /*-------------------------------------------------------------------------*/ 363 363 static void transfer_completed(void); 364 364 static void control_received(void); 365 + static void sof_received(void); 365 366 static int prime_transfer(int ep_num, void* ptr, int len, bool send, bool wait); 366 367 static void prepare_td(struct transfer_descriptor* td, 367 368 struct transfer_descriptor* previous_td, void *ptr, int len,int pipe); ··· 413 414 outl(inl(0x70000028) & ~0x800, 0x70000028); 414 415 while ((inl(0x70000028) & 0x80) == 0); 415 416 #endif 417 + } 418 + 419 + static void td_set_buf_ptr(struct transfer_descriptor* td, const void* ptr){ 420 + td->buff_ptr0 = (unsigned int)ptr; 421 + td->buff_ptr1 = ((unsigned int)ptr & 0xfffff000) + 0x1000; 422 + td->buff_ptr2 = ((unsigned int)ptr & 0xfffff000) + 0x2000; 423 + td->buff_ptr3 = ((unsigned int)ptr & 0xfffff000) + 0x3000; 424 + td->buff_ptr4 = ((unsigned int)ptr & 0xfffff000) + 0x4000; 416 425 } 417 426 418 427 /* One-time driver startup init */ ··· 544 553 if (status & USBSTS_PORT_CHANGE) { 545 554 REG_USBSTS = USBSTS_PORT_CHANGE; 546 555 } 556 + 557 + /* sof */ 558 + if (status & USBSTS_SOF) { 559 + REG_USBSTS = USBSTS_SOF; 560 + sof_received(); 561 + } 547 562 } 548 563 549 564 bool usb_drv_stalled(int endpoint,bool in) ··· 664 679 REG_USBCMD |= USBCMD_RUN; 665 680 } 666 681 682 + /* batched request api */ 683 + static struct transfer_descriptor batch_td_array[USB_BATCH_SLOTS] USB_DEVBSS_ATTR __attribute__((aligned(32))); 684 + 685 + static uint8_t batch_ep = 0; 686 + static uint8_t batch_write_cursor; 687 + static bool batch_stopped; 688 + static usb_drv_batch_get_more batch_get_more; 689 + 690 + static int ep_to_pipe_index(uint8_t ep) { 691 + const int ep_num = EP_NUM(ep); 692 + const int ep_dir = EP_DIR(ep); 693 + const int pipe = ep_num * 2 + (ep_dir == DIR_IN ? 1 : 0); 694 + return pipe; 695 + } 696 + 697 + int usb_drv_batch_init(int ep, usb_drv_batch_get_more get_more) { 698 + logf("batch init"); 699 + if(batch_ep != 0) { 700 + logf("batch function not available"); 701 + return -1; 702 + } 703 + batch_ep = ep; 704 + batch_get_more = get_more; 705 + return 0; 706 + } 707 + 708 + int usb_drv_batch_deinit() { 709 + logf("batch deinit"); 710 + usb_drv_batch_stop(); 711 + batch_ep = 0; 712 + return 0; 713 + } 714 + 715 + /* returns whether priming is needed */ 716 + static bool batch_fill_tds(void) { 717 + while(!(batch_td_array[batch_write_cursor].size_ioc_sts & DTD_STATUS_ACTIVE)) { 718 + /* batch_get_more may call batch_stop() through: 719 + * - batch_get_more() 720 + * - pcm_play_dma_complete_callback() 721 + * - sink_stop() 722 + * - usb_drv_batch_stop() */ 723 + const void* ptr; 724 + size_t len; 725 + batch_get_more(&ptr, &len); 726 + if(len == 0 || batch_stopped) { 727 + return false; 728 + } 729 + 730 + struct transfer_descriptor* td = &batch_td_array[batch_write_cursor]; 731 + td_set_buf_ptr(td, ptr); 732 + td->size_ioc_sts = (len << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE; 733 + batch_write_cursor = (batch_write_cursor + 1) % USB_BATCH_SLOTS; 734 + } 735 + return true; 736 + } 737 + 738 + int usb_drv_batch_start(void) { 739 + logf("batch start"); 740 + 741 + /* reset variables */ 742 + batch_write_cursor = 0; 743 + batch_stopped = false; 744 + 745 + /* chain tds */ 746 + memset(batch_td_array, 0, sizeof(struct transfer_descriptor) * USB_BATCH_SLOTS); 747 + for(int i = 0; i < USB_BATCH_SLOTS; i += 1) { 748 + struct transfer_descriptor* td = &batch_td_array[i]; 749 + td->next_td_ptr = (unsigned int)&batch_td_array[(i + 1) % USB_BATCH_SLOTS]; 750 + } 751 + 752 + /* configure queue head */ 753 + const int pipe = ep_to_pipe_index(batch_ep); 754 + struct queue_head* const qh = &qh_array[pipe]; 755 + 756 + qh->curr_dtd_ptr = (unsigned int)&batch_td_array[0]; /* or error check in sof_received may read random location */ 757 + qh->dtd.next_td_ptr = (unsigned int)&batch_td_array[0]; 758 + qh->dtd.size_ioc_sts = 0; 759 + 760 + /* pull initial buffers */ 761 + batch_fill_tds(); 762 + 763 + /* monitor sof */ 764 + REG_USBINTR |= USBINTR_SOF_EN; 765 + return 0; 766 + } 767 + 768 + int usb_drv_batch_stop(void) { 769 + batch_stopped = true; 770 + 771 + /* disable sof interrupt */ 772 + REG_USBINTR &= ~USBINTR_SOF_EN; 773 + 774 + /* break the chain */ 775 + /* terminating qh->dtd.next_td_ptr is not reliable */ 776 + for(int i = 0; i < USB_BATCH_SLOTS; i += 1) { 777 + struct transfer_descriptor* td = &batch_td_array[i]; 778 + td->next_td_ptr = DTD_NEXT_TERMINATE; 779 + } 780 + 781 + /* flush endpoint */ 782 + const int pipe = ep_to_pipe_index(batch_ep); 783 + const unsigned int mask = pipe2mask[pipe]; 784 + 785 + REG_ENDPTFLUSH = mask; 786 + while (REG_ENDPTFLUSH & mask); 787 + 788 + return 0; 789 + } 790 + 791 + #if defined(LOGF_ENABLE) && defined(ROCKBOX_HAS_LOGF) 792 + void usb_drv_dump_regs(void) { 793 + logf("==== register dump %ld ====", current_tick); 794 + logf("USBSTS 0x%08X", REG_USBSTS); 795 + logf("ENDPTSETUPSTAT 0x%08X", REG_ENDPTSETUPSTAT); 796 + logf("ENDPTPRIME 0x%08X", REG_ENDPTPRIME); 797 + logf("ENDPTFLUSH 0x%08X", REG_ENDPTFLUSH); 798 + logf("ENDPTSTATUS 0x%08X", REG_ENDPTSTATUS); 799 + logf("ENDPTCOMPLETE 0x%08X", REG_ENDPTCOMPLETE); 800 + logf("ENDPTCTRL0 0x%08X", REG_ENDPTCTRL0); 801 + logf("ENDPTCTRL1 0x%08X", REG_ENDPTCTRL1); 802 + logf("ENDPTCTRL2 0x%08X", REG_ENDPTCTRL2); 803 + } 804 + 805 + static void dump_td_array(struct queue_head* qh, struct transfer_descriptor* tds, size_t size) { 806 + void* current = (void*)qh->curr_dtd_ptr; 807 + void* next = (void*)qh->dtd.next_td_ptr; 808 + 809 + logf("==== td dump %ld n=%p c=%p ====", current_tick, next, current); 810 + for(int i = 0; i < size; i += 1) { 811 + int len = (tds[i].size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS; 812 + char sts[] = { 813 + &tds[i] == current ? 'c' : ' ', 814 + &tds[i] == next ? 'n' : ' ', 815 + i == batch_write_cursor ? 'w' : ' ', 816 + '\0', 817 + }; 818 + logf("%s td[%02d] status=0x%08X len=%d", sts, i, tds[i].size_ioc_sts, len); 819 + } 820 + } 821 + 822 + void usb_drv_dump_tds(int ep) { 823 + const int pipe = ep_to_pipe_index(ep); 824 + struct queue_head* const qh = &qh_array[pipe]; 825 + dump_td_array(qh, &td_array[pipe * NUM_TDS_PER_EP], NUM_TDS_PER_EP); 826 + } 827 + 828 + void usb_drv_batch_dump_tds(void) { 829 + const int pipe = ep_to_pipe_index(batch_ep); 830 + struct queue_head* const qh = &qh_array[pipe]; 831 + dump_td_array(qh, batch_td_array, USB_BATCH_SLOTS); 832 + } 833 + #endif 834 + 835 + static void sof_received(void) { 836 + if(batch_ep == 0) { 837 + /* should not happen */ 838 + return; 839 + } 840 + 841 + /* error recovery */ 842 + const int pipe = ep_to_pipe_index(batch_ep); 843 + const unsigned int mask = pipe2mask[pipe]; 844 + struct queue_head* const qh = &qh_array[pipe]; 845 + struct transfer_descriptor* const td = (void*)qh->curr_dtd_ptr; 846 + if(td->size_ioc_sts & DTD_ERROR_MASK) { 847 + logf("td error status=0x%08X", td->size_ioc_sts); 848 + REG_ENDPTPRIME |= mask; 849 + } 850 + 851 + /* do refill */ 852 + if(batch_fill_tds()) { 853 + const int pipe = ep_to_pipe_index(batch_ep); 854 + const unsigned int mask = pipe2mask[pipe]; 855 + REG_ENDPTPRIME |= mask; 856 + } 857 + } 858 + 667 859 /*-------------------------------------------------------------------------*/ 668 860 669 861 /* manual: 32.14.5.2 */ ··· 854 1046 td->next_td_ptr = DTD_NEXT_TERMINATE; 855 1047 td->size_ioc_sts = (len<< DTD_LENGTH_BIT_POS) | 856 1048 DTD_STATUS_ACTIVE | DTD_IOC; 857 - td->buff_ptr0 = (unsigned int)ptr; 858 - td->buff_ptr1 = ((unsigned int)ptr & 0xfffff000) + 0x1000; 859 - td->buff_ptr2 = ((unsigned int)ptr & 0xfffff000) + 0x2000; 860 - td->buff_ptr3 = ((unsigned int)ptr & 0xfffff000) + 0x3000; 861 - td->buff_ptr4 = ((unsigned int)ptr & 0xfffff000) + 0x4000; 1049 + td_set_buf_ptr(td, ptr); 862 1050 td->reserved |= DTD_RESERVED_LENGTH_MASK & len; 863 1051 td->reserved |= DTD_RESERVED_IN_USE; 864 1052 td->reserved |= (pipe << DTD_RESERVED_PIPE_OFFSET);