/* * ------------------------------------------------------------------ Copyright (c) 2023 by Lattice Semiconductor Corporation ALL RIGHTS RESERVED ------------------------------------------------------------------ DISCLAIMER: LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. LATTICE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE 'S REQUIREMENTS, OR THAT LICENSEE' S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS HEREIN WILL BE CORRECTED. LICENSEE ASSUMES RESPONSIBILITY FOR SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM. LICENSEE ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE SOFTWARE. IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE 'S SOLE LIABILITY, AND LICENSEE' S SOLE REMEDY, IS SET FORTH ABOVE. LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY RIGHTS, INCLUDING ANY PATENT. IT IS THE USER' S RESPONSIBILITY TO VERIFY THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE USE OF FORMAL SOFTWARE VALIDATION METHODS. ------------------------------------------------------------------ * */ #include "request_fifo.h" #include #include device_descriptor device_descriptor_data = {0}; bos_descriptor bos_descriptor_data = {0}; usb_2_0_extension_descriptor usb_2_0_extension_descriptor_data = {0}; ss_usb_device_capability_descriptor \ ss_usb_device_capability_descriptor_data = {0}; config_descriptor config_descriptor_data = {0}; interface_descriptor interface_descriptor_data = {0}; endpoint_descriptor endpoint_descriptor_bin_1_data = {0}; endpoint_descriptor endpoint_descriptor_bout_1_data = {0}; endpoint_descriptor endpoint_descriptor_iin_5_data = {0}; endpoint_descriptor endpoint_descriptor_iout_5_data = {0}; ss_endpoint_companion_descriptor \ ss_endpoint_companion_descriptor_bulk_data = {0}; ss_endpoint_companion_descriptor \ ss_endpoint_companion_descriptor_interrupt_data = {0}; device_qualifier_descriptor device_qualifier_descriptor_data = {0}; other_speed_configuration_descriptor \ other_speed_configuration_descriptor_data = {0}; string_language_descriptor string_language_descriptor_data = {0}; uint8_t string_descriptor_manufacturer_id[256]; uint8_t string_descriptor_product_id[256]; uint8_t string_descriptor_serial_id[256]; uint32_t string_descriptor_manufacturer_id_len; uint32_t string_descriptor_product_id_len; uint32_t string_descriptor_serial_id_len; uint32_t g_uart_enable; uint32_t g_usb_speed; uint32_t g_bconfiguration_value; uint32_t g_request_interrupt_flag; uint32_t g_event_interrupt_flag; uint32_t g_initiate_remote_wakeup; uint32_t g_clear_remote_wakeup; int ltcusb_request_fifo_read (uint32_t* request_data_lower, uint32_t* request_data_higher) { if(ltcusb_fifo_read(REQ_FIFO_ADDR_RV, request_data_lower) != 0) { return -1; } if(ltcusb_fifo_read(REQ_FIFO_ADDR_RV, request_data_higher) != 0) { return -2; } return 0; } int usb_enumeration() { uint32_t data_higher; uint32_t data_lower; uint32_t descriptor_type; uint32_t descriptor_index; uint32_t descriptor_length; uint32_t wlength; if(ltcusb_request_fifo_read(&data_lower,&data_higher)!=0) { return -1; } /* Get Descriptor Request */ if ((data_lower & (0x0000FFFF)) == (0x00000680)) { descriptor_type = (data_lower & (0xff000000)); descriptor_index = (data_lower & (0x00ff0000)); descriptor_length = (data_higher & (0xffff0000)); if(event_while(ep_event_XferNotReady,0,0x1)!=0) { return -2; } /* Device Descriptor */ if (descriptor_type == 0x01000000) { if(get_device_descriptor()!=0) { return -3; } /* wait for XferNotReady EP0 */ if(event_while(ep_event_XferNotReady,0,0x0)!=0) { return -11; } if(TRB_control_status3(0x0)!=0) { return -12; } if(event_while(ep_event_XferComplete,0,0x0)!=0) { return -13; } if(g_uart_enable) { printf("1"); } } /* Configuartion Descriptor */ else if (descriptor_type == 0x02000000) { /* Configuration descriptor -- * If Descriptor Length is 9 or 255 */ if ((descriptor_length == 0x00090000) | (descriptor_length == 0x00ff0000)) { if(get_config_descriptor()!=0) { return -4; } if(g_uart_enable) { printf("2"); } } /* Configuration & Interface & Endpoint descriptor * -- If Descriptor Length is not 9 */ else { if(g_connect_speed == super_speed_usb) { if(get_config_interface_endpoint_ss_descriptor()!=0) { return -22; } } else { if(get_config_interface_endpoint_descriptor()!=0) { return -5; } } if(g_uart_enable) { printf("3"); } } /* wait for XferNotReady EP0 */ if(event_while(ep_event_XferNotReady,0,0x0)!=0) { return -11; } if(TRB_control_status3(0x0)!=0) { return -12; } if(event_while(ep_event_XferComplete,0,0x0)!=0) { return -13; } } /* Other Speed Configuartion Descriptor */ else if (descriptor_type == 0x07000000) { /* Other Speed Configuration descriptor -- * If Descriptor Length is 9 or 255 */ if ((descriptor_length == 0x00090000) | (descriptor_length == 0x00ff0000)) { if(get_other_speed_config_descriptor()!=0) { return -4; } if(g_uart_enable) { printf("Y"); } } /* Other Speed Configuration & Interface & Endpoint descriptor -- * If Descriptor Length is not 9 */ else { if(get_other_speed_config_interface_endpoint_descriptor()!=0) { return -4; } if(g_uart_enable) { printf("Z"); } } /* wait for XferNotReady EP0 */ if(event_while(ep_event_XferNotReady,0,0x0)!=0) { return -11; } if(TRB_control_status3(0x0)!=0) { return -12; } if(event_while(ep_event_XferComplete,0,0x0)!=0) { return -13; } } /* Device Qualifier Descriptor */ else if (descriptor_type == 0x06000000) { if(get_device_qualifier_descriptor()!=0) { return -6; } if(g_uart_enable) { printf("Q"); } /* wait for XferNotReady EP0 */ if(event_while(ep_event_XferNotReady,0,0x0)!=0) { return -11; } if(TRB_control_status3(0x0)!=0) { return -12; } if(event_while(ep_event_XferComplete,0,0x0)!=0) { return -13; } } /* String Descriptor */ else if (descriptor_type == 0x03000000) { /* String - language descriptor */ if (descriptor_index == 0x00000000) { if(get_string_language_descriptor()!=0) { return -7; } if(g_uart_enable) { printf("5"); } } /* String - index 1 descriptor */ else if (descriptor_index == 0x00010000) { if(get_string_index1_descriptor3 (string_descriptor_manufacturer_id, string_descriptor_manufacturer_id_len) != 0) { return -8; } if(g_uart_enable) { printf("7"); } } /* String - index 2 descriptor */ else if (descriptor_index == 0x00020000) { if(get_string_index1_descriptor3(string_descriptor_product_id, string_descriptor_product_id_len)!=0) { return -9; } if(g_uart_enable) { printf("6"); } } /* String - index 3 descriptor */ else { if(get_string_index1_descriptor3(string_descriptor_serial_id, string_descriptor_serial_id_len)!=0) { return -10; } if(g_uart_enable) { printf("4"); } } /* wait for XferNotReady EP0 */ if(event_while(ep_event_XferNotReady,0,0x0)!=0) { return -11; } if(TRB_control_status3(0x0)!=0) { return -12; } if(event_while(ep_event_XferComplete,0,0x0)!=0) { return -13; } } /*BOS descriptor */ else if (descriptor_type == 0x0f000000) { if ((descriptor_length == 0x00050000) | (descriptor_length == 0x00ff0000)) { if(get_bos_descriptor()!= 0) { return -66; } /* wait for XferNotReady EP0 */ if(event_while(ep_event_XferNotReady,0,0x0)!=0) { return -11; } if(TRB_control_status3(0x0)!=0) { return -12; } if(event_while(ep_event_XferComplete,0,0x0)!=0) { return -13; } if(g_uart_enable) { printf("8"); } /* Device Capability Descriptor */ } else if (descriptor_length == 0x00160000) { if(get_bos_device_capability_descriptor() != 0) { return -67; } /* wait for XferNotReady EP0 */ if(event_while(ep_event_XferNotReady,0,0x0)!=0) { return -11; } if(TRB_control_status3(0x0)!=0) { return -12; } if(event_while(ep_event_XferComplete,0,0x0)!=0) { return -13; } if(g_uart_enable) { printf("9"); } } /* Stall */ else { if(event_while(ep_event_XferNotReady,0,0x1)!=0) { return -19; } if(DEPSSTALL_cmd(0x0)!=0) { return -20; } if(g_uart_enable) { printf("STALL"); } } } /* Stall */ else { if(event_while(ep_event_XferNotReady,0,0x1)!=0) { return -19; } if(DEPSSTALL_cmd(0x0)!=0) { return -20; } if(g_uart_enable) { printf("STALL"); } } } /* Set Address Request */ else if ((data_lower & (0x0000FFFF)) == (0x00000500)) { if(ltcusb_set_address_request(data_lower)!=0) { return -14; } if(g_uart_enable) { printf("A"); } } /* Set Configuartion Request */ else if ((data_lower & (0x0000FFFF)) == (0x00000900)) { g_bconfiguration_value = (data_lower & (0xffff0000)); if(Initialization_on_SetConfiguration()!=0) { return -15; } if(event_while(ep_event_XferComplete,0,0x1)!=0) { return -16; } if(g_uart_enable) { printf("P"); } } /* Control OUT */ else if ((data_lower & (0x000000FF)) == (0x00000040)) { wlength = (data_higher & (0xffff0000)); if(wlength == 0x00000000) { if(ltcusb_2_stage_control_out_request()!=0) { return -17; } } else { if(ltcusb_3_stage_control_out_request(&data_lower,&data_higher)!=0) { return -18; } } if(g_uart_enable) { printf("CO"); } } /* Control IN */ else if ((data_lower & (0x000000FF)) == (0x000000C0)) { if(ltcusb_control_in_request(data_higher)!=0) { return -18; } if(g_uart_enable) { printf("CI"); } } /* Get Configuration Request 0 before set_configuration 1 after set_configuration */ else if ((data_lower & (0x0000FFFF)) == (0x00000880)) { if(ltcusb_get_config_request()!= 0) { return -1; } if(g_uart_enable) { printf("GC"); } } /* get status -- Recipient Device self powered(D0 -- 1) following can be modified by set_feature & clear_feature 2.0 -- Remote_Wakeup(D1) 3.2 -- U1_Enable(D2) -- U2_Enable(D3) -- LTM Enable(D4) */ else if ((data_lower & (0x0000FFFF)) == (0x00000080)) { if(ltcusb_get_status_request()!= 0) { return -1; } if(g_uart_enable) { printf("GS"); } } /* set_feature -- Recipient Device */ else if ((data_lower & (0x0000FFFF)) == (0x00000300)) { if(ltcusb_set_feature_request()!= 0) { return -1; } if(g_uart_enable) { printf("SF"); } } /* clear_feature - device remote-wakeup */ else if ((data_lower & (0x000FFFFF)) == (0x00010100)) { if(ltcusb_clear_feature_request()!= 0) { return -1; } if(g_uart_enable) { printf("CF"); } } /* set SEL */ else if ((data_lower & (0x0000FFFF)) == (0x00003000)) { if(ltcusb_set_sel_request(&data_lower,&data_higher)!= 0) { return -1; } if(g_uart_enable) { printf("SEL"); } } /* Stall */ else { if(event_while(ep_event_XferNotReady,0,0x1)!=0) { return -19; } if(DEPSSTALL_cmd(0x0)!=0) { return -20; } } /* For New packet */ if(TRB_control_setup()!=0) { return -21; } return 0; } int get_device_descriptor() { if(TRB_control_data2(device_descriptor_data.bLength, sizeof(device_descriptor_data), (uint32_t*)&device_descriptor_data) != 0) { return -1; } return 0; } int get_bos_descriptor() { if(TRB_control_data2(bos_descriptor_data.bLength, sizeof(bos_descriptor_data), (uint32_t*)&bos_descriptor_data) != 0) { return -1; } return 0; } int get_config_descriptor() { if(TRB_control_data2(config_descriptor_data.bLength, sizeof(config_descriptor_data), (uint32_t*)&config_descriptor_data) != 0) { return -1; } return 0; } int get_other_speed_config_descriptor() { if(TRB_control_data2(other_speed_configuration_descriptor_data.bLength, sizeof(other_speed_configuration_descriptor_data), (uint32_t*)&other_speed_configuration_descriptor_data) != 0) { return -1; } return 0; } static int data_cpy(void* dst, void* src, uint32_t len) { uint8_t* local_dst = (uint8_t*)dst; uint8_t* local_src = (uint8_t*)src; for(uint32_t i=0;i> 16); /* * Program device speed [2:0] bits and periodic frame interval * DCFG.DEVSPD=3'b000: High-speed * DCFG.DEVSPD=3'b001: Full-speed * DCFG.DEVSPD=3'b100: Super-speed */ DCFG_data *dcfg = dcfg_setup(); /* * Device Address. */ dcfg ->DEVADDR = (dev_addr & 0x7F); /* * Device Speed. */ dcfg ->DEVSPD = (g_usb_speed & 0x7); dcfg ->reserved_11_10 = 0x2; /* * Refer Table number 1-78 for more information. */ dcfg ->NUMP = 0x4; if(dcfg_write() != 0) { return -1; } if(event_while(ep_event_XferNotReady,0,0x1) != 0) { return -2; } if(TRB_control_status2()!=0) { return -3; } if(event_while(ep_event_XferComplete,0,0x1) != 0) { return -4; } return 0; } int ltcusb_2_stage_control_out_request() { if(event_while(ep_event_XferNotReady,0,0x1) != 0) { return -1; } if(TRB_control_status2() != 0 ) { return -2; } if(event_while(ep_event_XferComplete,0,0x1) != 0) { return -3; } return 0; } int ltcusb_3_stage_control_out_request(uint32_t* data_lower, uint32_t* data_higher) { g_request_interrupt_flag = 0; if(TRB_control_setup() != 0) { return -1; } if(event_while(ep_event_XferComplete,0,0x0) != 0) { return -2; } while(g_request_interrupt_flag == 0) { rv_delay_us(1); } if(ltcusb_request_fifo_read(data_lower,data_higher)!=0) { return -3; } if(event_while(ep_event_XferNotReady,0,0x1) != 0) { return -4; } if(TRB_control_status3(0x1) != 0 ) { return -5; } if(event_while(ep_event_XferComplete,0,0x1) != 0) { return -6; } return 0; } int ltcusb_control_in_request(uint32_t request_data_higher) { uint32_t control_in_address = (request_data_higher & (0x0000FFFF)); if(event_while(ep_event_XferNotReady,0,0x1) != 0) { return -1; } LtcUSB_TRB control_data_trb = {0}; control_data_trb.BPTRL = (CONTROL_ADDRESS_USB23 | control_in_address); control_data_trb.BUFSIZE = 0x00000008; control_data_trb.HWO = 1; control_data_trb.LST = 1; control_data_trb.TRBCTL = control_data_trbctl; control_data_trb.IOC = 1; if(ltcusb_trb_write(&control_data_trb) !=0 ) { return -2; } DEPSTRTXFER_Par1 Depstrtxfer_par1_data = {0}; Depstrtxfer_par1_data.TDAddr_Low = TRB_FIFO_ADDR_USB23; DEPSTRTXFER_Par0 Depstrtxfer_par0_data = {0}; Depstrtxfer_par0_data.TDAddr_High = 0; if(DEPSTRTXFER_cmd(0x1, &Depstrtxfer_par1_data, &Depstrtxfer_par0_data) != 0) { return -3; } if(event_while(ep_event_XferNotReady,0,0x0) != 0) { return -4; } /* TRB Control Status for 3 stages */ if(TRB_control_status3(0x0) != 0 ) { return -5; } if(event_while(ep_event_XferComplete,0,0x0) != 0) { return -6; } return 0; } int ltcusb_get_config_request() { /* wait for XferNotReady EP1 */ if(event_while(ep_event_XferNotReady,0,0x1)!=0) { return -1; } uint32_t configuration_value[] = {0,0}; if(g_bconfiguration_value == 0x00010000) configuration_value[0] = 0x00000001; if(TRB_control_data2(0x1,0x1,(uint32_t*)&configuration_value) != 0) { return -2; } /* wait for XferNotReady EP0 */ if(event_while(ep_event_XferNotReady,0,0x0)!=0) { return -3; } if(TRB_control_status3(0x0)!=0) { return -4; } if(event_while(ep_event_XferComplete,0,0x0)!=0) { return -5; } return 0; } int ltcusb_get_status_request() { /* wait for XferNotReady EP1 */ if(event_while(ep_event_XferNotReady,0,0x1)!=0) { return -1; } uint32_t status[] = {0x00000001,0x00000000}; if(TRB_control_data2(0x2,0x2,(uint32_t*)&status) != 0) { return -2; } /* wait for XferNotReady EP0 */ if(event_while(ep_event_XferNotReady,0,0x0)!=0) { return -3; } if(TRB_control_status3(0x0)!=0) { return -4; } if(event_while(ep_event_XferComplete,0,0x0)!=0) { return -5; } return 0; } int ltcusb_set_feature_request() { /* wait for XferNotReady EP1 */ if(event_while(ep_event_XferNotReady,0,0x1) != 0) { return -1; } if(TRB_control_status2() != 0 ) { return -2; } /* wait for XferComplete EP1 */ if(event_while(ep_event_XferComplete,0,0x1) != 0) { return -3; } g_initiate_remote_wakeup = 0x1; return 0; } int ltcusb_clear_feature_request() { g_clear_remote_wakeup = 1; if(event_while(ep_event_XferNotReady,0,0x1) != 0) { return -1; } if(TRB_control_status2() != 0 ) { return -2; } /* wait for XferComplete EP1 */ if(event_while(ep_event_XferComplete,0,0x1) != 0) { return -3; } g_initiate_remote_wakeup = 0x0; return 0; } int ltcusb_set_sel_request(uint32_t* data_lower, uint32_t* data_higher) { g_request_interrupt_flag = 0; if(TRB_control_setup() != 0) { return -1; } /* wait for XferComplete EP1 */ if(event_while(ep_event_XferComplete,0,0x0) != 0) { return -2; } while(g_request_interrupt_flag == 0) { rv_delay_us(1); } if(ltcusb_request_fifo_read(data_lower,data_higher)!=0) { return -3; } if(event_while(ep_event_XferNotReady,0,0x1) != 0) { return -4; } if(TRB_control_status3(0x1) != 0 ) { return -5; } /* wait for XferComplete EP1 */ if(event_while(ep_event_XferComplete,0,0x1) != 0) { return -6; } return 0; }