diff --git a/firmware/common/cpld_jtag.c b/firmware/common/cpld_jtag.c index ddeb13d9..50430fee 100644 --- a/firmware/common/cpld_jtag.c +++ b/firmware/common/cpld_jtag.c @@ -26,8 +26,9 @@ #include #include -uint32_t xsvf_len; -unsigned char* xsvf_data; +static refill_buffer_cb refill_buffer; +static uint32_t xsvf_buffer_len, xsvf_pos; +static unsigned char* xsvf_buffer; void cpld_jtag_setup(void) { scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); @@ -58,11 +59,16 @@ void cpld_jtag_release(void) { } /* return 0 if success else return error code see xsvfExecute() */ -int cpld_jtag_program(const uint32_t len, unsigned char* const data) { +int cpld_jtag_program( + const uint32_t buffer_length, + unsigned char* const buffer, + refill_buffer_cb refill +) { int error; cpld_jtag_setup(); - xsvf_data = data; - xsvf_len = len; + xsvf_buffer = buffer; + xsvf_buffer_len = buffer_length; + refill_buffer = refill; error = xsvfExecute(); cpld_jtag_release(); @@ -71,12 +77,12 @@ int cpld_jtag_program(const uint32_t len, unsigned char* const data) { /* this gets called by the XAPP058 code */ unsigned char cpld_jtag_get_next_byte(void) { - unsigned char byte = *xsvf_data; - - if (xsvf_len > 1) { - xsvf_data++; - xsvf_len--; - } + if (xsvf_pos == xsvf_buffer_len) { + refill_buffer(); + xsvf_pos = 0; + } + unsigned char byte = xsvf_buffer[xsvf_pos]; + xsvf_pos++; return byte; } diff --git a/firmware/common/cpld_jtag.h b/firmware/common/cpld_jtag.h index ed42d782..56f55a2a 100644 --- a/firmware/common/cpld_jtag.h +++ b/firmware/common/cpld_jtag.h @@ -24,9 +24,20 @@ #include +typedef void (*refill_buffer_cb)(void); + void cpld_jtag_release(void); -/* return 0 if success else return error code see xsvfExecute() see micro.h */ -int cpld_jtag_program(const uint32_t len, unsigned char* const data); + +/* Return 0 if success else return error code see xsvfExecute() see micro.h. + * + * We expect the buffer to be initially full of data. After the entire + * contents of the buffer has been streamed to the CPLD the given + * refill_buffer callback will be called. */ +int cpld_jtag_program( + const uint32_t buffer_length, + unsigned char* const buffer, + refill_buffer_cb refill +); unsigned char cpld_jtag_get_next_byte(void); #endif//__CPLD_JTAG_H__ diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index f077a014..2a14b5e8 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -50,10 +50,11 @@ uint8_t* const usb_bulk_buffer = (uint8_t*)0x20004000; static volatile uint32_t usb_bulk_buffer_offset = 0; static const uint32_t usb_bulk_buffer_mask = 32768 - 1; -/* TODO remove this big buffer and use streaming for CPLD */ -#define CPLD_XSVF_MAX_LEN (65536) -uint8_t cpld_xsvf_buffer[CPLD_XSVF_MAX_LEN]; -uint16_t write_cpld_idx = 0; +usb_transfer_descriptor_t usb_td_bulk[2] ATTR_ALIGNED(64); +const uint_fast8_t usb_td_bulk_count = sizeof(usb_td_bulk) / sizeof(usb_td_bulk[0]); + +uint8_t cpld_xsvf_buffer[512]; +volatile bool cpld_wait = false; uint8_t spiflash_buffer[W25Q80BV_PAGE_LEN]; char version_string[] = VERSION_STRING; @@ -191,9 +192,23 @@ usb_configuration_t usb_configuration_full_speed = { .descriptor = usb_descriptor_configuration_full_speed, }; +usb_configuration_t usb_configuration_cpld_update_full_speed = { + .number = 2, + .speed = USB_SPEED_FULL, + .descriptor = usb_descriptor_configuration_cpld_update_full_speed, +}; + +usb_configuration_t usb_configuration_cpld_update_high_speed = { + .number = 2, + .speed = USB_SPEED_HIGH, + .descriptor = usb_descriptor_configuration_cpld_update_high_speed, +}; + usb_configuration_t* usb_configurations[] = { &usb_configuration_high_speed, &usb_configuration_full_speed, + &usb_configuration_cpld_update_full_speed, + &usb_configuration_cpld_update_high_speed, 0, }; @@ -549,69 +564,6 @@ usb_request_status_t usb_vendor_request_read_spiflash( } } -usb_request_status_t usb_vendor_request_write_cpld( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage) -{ - int error, i; - uint16_t total_len; - uint16_t len; - #define WAIT_LOOP_DELAY (6000000) - #define ALL_LEDS (PIN_LED1|PIN_LED2|PIN_LED3) - - if (stage == USB_TRANSFER_STAGE_SETUP) - { - // len is limited to 64KB 16bits no overflow can happen - total_len = endpoint->setup.value; - len = endpoint->setup.length; - usb_transfer_schedule_block(endpoint->out, &cpld_xsvf_buffer[write_cpld_idx], len, - NULL, NULL); - return USB_REQUEST_STATUS_OK; - } else if (stage == USB_TRANSFER_STAGE_DATA) - { - // len is limited to 64KB 16bits no overflow can happen - total_len = endpoint->setup.value; - len = endpoint->setup.length; - write_cpld_idx = write_cpld_idx + len; - // Check if all bytes received and write CPLD - if(write_cpld_idx == total_len) - { - write_cpld_idx = 0; - error = cpld_jtag_program(total_len, &cpld_xsvf_buffer[write_cpld_idx]); - // TO FIX ACK shall be not delayed so much as cpld prog can take up to 5s. - if(error == 0) - { - usb_transfer_schedule_ack(endpoint->in); - - /* blink LED1, LED2, and LED3 on success */ - while (1) - { - gpio_set(PORT_LED1_3, ALL_LEDS); /* LEDs on */ - for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ - __asm__("nop"); - gpio_clear(PORT_LED1_3, ALL_LEDS); /* LEDs off */ - for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ - __asm__("nop"); - } - return USB_REQUEST_STATUS_OK; - }else - { - /* LED3 (Red) steady on error */ - gpio_set(PORT_LED1_3, PIN_LED3); /* LEDs on */ - while (1); - return USB_REQUEST_STATUS_STALL; - } - }else - { - usb_transfer_schedule_ack(endpoint->in); - return USB_REQUEST_STATUS_OK; - } - } else - { - return USB_REQUEST_STATUS_OK; - } -} - usb_request_status_t usb_vendor_request_read_board_id( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { @@ -815,7 +767,7 @@ static const usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_erase_spiflash, usb_vendor_request_write_spiflash, usb_vendor_request_read_spiflash, - usb_vendor_request_write_cpld, + NULL, // used to be write_cpld usb_vendor_request_read_board_id, usb_vendor_request_read_version_string, usb_vendor_request_set_freq, @@ -853,13 +805,72 @@ const usb_request_handlers_t usb_request_handlers = { .reserved = 0, }; +static void cpld_buffer_refilled(void* user_data, unsigned int length) +{ + cpld_wait = false; +} + +static void refill_cpld_buffer(void) +{ + cpld_wait = true; + usb_transfer_schedule( + &usb_endpoint_bulk_out, + cpld_xsvf_buffer, + sizeof(cpld_xsvf_buffer), + cpld_buffer_refilled, + NULL + ); + + // Wait until transfer finishes + while (cpld_wait); +} + +static void cpld_update(void) +{ + #define WAIT_LOOP_DELAY (6000000) + #define ALL_LEDS (PIN_LED1|PIN_LED2|PIN_LED3) + int i; + int error; + + usb_queue_flush_endpoint(&usb_endpoint_bulk_in); + usb_queue_flush_endpoint(&usb_endpoint_bulk_out); + + refill_cpld_buffer(); + + error = cpld_jtag_program(sizeof(cpld_xsvf_buffer), + cpld_xsvf_buffer, + refill_cpld_buffer); + if(error == 0) + { + /* blink LED1, LED2, and LED3 on success */ + while (1) + { + gpio_set(PORT_LED1_3, ALL_LEDS); /* LEDs on */ + for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ + __asm__("nop"); + gpio_clear(PORT_LED1_3, ALL_LEDS); /* LEDs off */ + for (i = 0; i < WAIT_LOOP_DELAY; i++) /* Wait a bit. */ + __asm__("nop"); + } + }else + { + /* LED3 (Red) steady on error */ + gpio_set(PORT_LED1_3, PIN_LED3); /* LEDs on */ + while (1); + } +} + void usb_configuration_changed( usb_device_t* const device ) { set_transceiver_mode(transceiver_mode); - if( device->configuration->number ) { + if( device->configuration->number == 1 ) { + // transceiver mode gpio_set(PORT_LED1_3, PIN_LED1); + } else if( device->configuration->number == 2 ) { + // CPLD update mode + cpld_update(); } else { gpio_clear(PORT_LED1_3, PIN_LED1); } diff --git a/firmware/hackrf_usb/usb_descriptor.c b/firmware/hackrf_usb/usb_descriptor.c index c9f26ce7..d97e1973 100644 --- a/firmware/hackrf_usb/usb_descriptor.c +++ b/firmware/hackrf_usb/usb_descriptor.c @@ -51,7 +51,7 @@ uint8_t usb_descriptor_device[] = { 0x01, // iManufacturer 0x02, // iProduct 0x00, // iSerialNumber - 0x01 // bNumConfigurations + 0x02 // bNumConfigurations }; uint8_t usb_descriptor_device_qualifier[] = { @@ -62,7 +62,7 @@ uint8_t usb_descriptor_device_qualifier[] = { 0x00, // bDeviceSubClass 0x00, // bDeviceProtocol 64, // bMaxPacketSize0 - 0x01, // bNumOtherSpeedConfigurations + 0x02, // bNumOtherSpeedConfigurations 0x00 // bReserved }; @@ -140,6 +140,80 @@ uint8_t usb_descriptor_configuration_high_speed[] = { 0, // TERMINATOR }; +uint8_t usb_descriptor_configuration_cpld_update_full_speed[] = { + 9, // bLength + USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType + USB_WORD(32), // wTotalLength + 0x01, // bNumInterfaces + 0x02, // bConfigurationValue + 0x04, // iConfiguration + 0x80, // bmAttributes: USB-powered + 250, // bMaxPower: 500mA + + 9, // bLength + USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0xFF, // bInterfaceClass: vendor-specific + 0xFF, // bInterfaceSubClass + 0xFF, // bInterfaceProtocol: vendor-specific + 0x00, // iInterface + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_IN_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_OUT_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_FS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 0, // TERMINATOR +}; + +uint8_t usb_descriptor_configuration_cpld_update_high_speed[] = { + 9, // bLength + USB_DESCRIPTOR_TYPE_CONFIGURATION, // bDescriptorType + USB_WORD(32), // wTotalLength + 0x01, // bNumInterfaces + 0x02, // bConfigurationValue + 0x04, // iConfiguration + 0x80, // bmAttributes: USB-powered + 250, // bMaxPower: 500mA + + 9, // bLength + USB_DESCRIPTOR_TYPE_INTERFACE, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0xFF, // bInterfaceClass: vendor-specific + 0xFF, // bInterfaceSubClass + 0xFF, // bInterfaceProtocol: vendor-specific + 0x00, // iInterface + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_IN_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 7, // bLength + USB_DESCRIPTOR_TYPE_ENDPOINT, // bDescriptorType + USB_BULK_OUT_EP_ADDR, // bEndpointAddress + 0x02, // bmAttributes: BULK + USB_WORD(USB_MAX_PACKET_BULK_HS), // wMaxPacketSize + 0x00, // bInterval: no NAK + + 0, // TERMINATOR +}; + uint8_t usb_descriptor_string_languages[] = { 0x04, // bLength USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType @@ -197,11 +271,28 @@ uint8_t usb_descriptor_string_config1_description[] = { 'r', 0x00, }; +uint8_t usb_descriptor_string_config2_description[] = { + 24, // bLength + USB_DESCRIPTOR_TYPE_STRING, // bDescriptorType + 'C', 0x00, + 'P', 0x00, + 'L', 0x00, + 'D', 0x00, + ' ', 0x00, + 'u', 0x00, + 'p', 0x00, + 'd', 0x00, + 'a', 0x00, + 't', 0x00, + 'e', 0x00, +}; + uint8_t* const usb_descriptor_strings[] = { usb_descriptor_string_languages, usb_descriptor_string_manufacturer, usb_descriptor_string_product, usb_descriptor_string_config1_description, + usb_descriptor_string_config2_description, 0, // TERMINATOR }; diff --git a/firmware/hackrf_usb/usb_descriptor.h b/firmware/hackrf_usb/usb_descriptor.h index a1676f04..11e274a7 100644 --- a/firmware/hackrf_usb/usb_descriptor.h +++ b/firmware/hackrf_usb/usb_descriptor.h @@ -25,6 +25,8 @@ extern uint8_t usb_descriptor_device[]; extern uint8_t usb_descriptor_device_qualifier[]; extern uint8_t usb_descriptor_configuration_full_speed[]; extern uint8_t usb_descriptor_configuration_high_speed[]; +extern uint8_t usb_descriptor_configuration_cpld_update_full_speed[]; +extern uint8_t usb_descriptor_configuration_cpld_update_high_speed[]; extern uint8_t usb_descriptor_string_languages[]; extern uint8_t usb_descriptor_string_manufacturer[]; extern uint8_t usb_descriptor_string_product[];