diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c index 564bd87..8da62d8 100644 --- a/drivers/st/clk/stm32mp1_clk.c +++ b/drivers/st/clk/stm32mp1_clk.c @@ -1740,6 +1740,9 @@ return false; } + int stgen_p = stm32mp1_clk_get_parent((int)STGEN_K); + int usbphy_p = stm32mp1_clk_get_parent((int)USBPHY_K); + /* Check status field to disable security */ if (!fdt_get_rcc_secure_status()) { mmio_write_32(rcc_base + RCC_TZCR, 0); @@ -1834,6 +1837,12 @@ pllcfg[_PLL4], plloff[_PLL4]); } + /* Don't initialize PLL4, when used by BOOTROM */ + if ((get_boot_device() == BOOT_DEVICE_USB) && + ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) { + pll4_bootrom = true; + pll4_preserve = true; + } for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { if (((i == _PLL3) && pll3_preserve) || @@ -1985,6 +1994,11 @@ if (pkcs_cell != NULL) { bool ckper_disabled = false; uint32_t j; + uint32_t usbreg_bootrom = 0U; + + if (pll4_bootrom) { + usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR); + } for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); @@ -2005,6 +2019,25 @@ if (ckper_disabled) { stm32mp1_pkcs_config(CLK_CKPER_DISABLED); } + + if (pll4_bootrom) { + uint32_t usbreg_value, usbreg_mask; + const struct stm32mp1_clk_sel *sel; + + sel = clk_sel_ref(_USBPHY_SEL); + usbreg_mask = (uint32_t)sel->msk << sel->src; + sel = clk_sel_ref(_USBO_SEL); + usbreg_mask |= (uint32_t)sel->msk << sel->src; + + usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) & + usbreg_mask; + usbreg_bootrom &= usbreg_mask; + if (usbreg_bootrom != usbreg_value) { + VERBOSE("forbidden new USB clk path\n"); + VERBOSE("vs bootrom on USB boot\n"); + return -FDT_ERR_BADVALUE; + } + } } /* Switch OFF HSI if not found in device-tree */ diff --git a/drivers/st/io/io_programmer_st_usb.c b/drivers/st/io/io_programmer_st_usb.c new file mode 100644 index 0000000..089de42 --- /dev/null +++ b/drivers/st/io/io_programmer_st_usb.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USB_STATE_READY 0 +#define USB_STATE_WRITTEN 1 + +#define IO_USB_TIMEOUT_10_SEC U(10000000) +#define DETACH_TIMEOUT U(0x100) +#define USB_DFU_MAX_XFER_SIZE 1024 + +static uint8_t first_usb_buffer[USB_DFU_MAX_XFER_SIZE + 1] __aligned(4); +static usb_dfu_media_t usb_dfu_fops; +static uint8_t checksum_is_wrong; +static uint8_t usb_status; + +/* usb device functions */ +static int usb_dev_open(const uintptr_t init_params, + io_dev_info_t **dev_info); +static int usb_block_open(io_dev_info_t *dev_info, const uintptr_t spec, + io_entity_t *entity); +static int usb_dev_init(io_dev_info_t *dev_info, + const uintptr_t init_params); +static int usb_partition_size(io_entity_t *entity, size_t *length); +static int usb_block_seek(io_entity_t *entity, int mode, + signed long long offset); +static int usb_block_read(io_entity_t *entity, uintptr_t buffer, + size_t length, size_t *length_read); +static int usb_block_close(io_entity_t *entity); +static int usb_dev_close(io_dev_info_t *dev_info); +static io_type_t device_type_usb(void); + +static const io_dev_connector_t usb_dev_connector = { + .dev_open = usb_dev_open +}; + +static const io_dev_funcs_t usb_dev_funcs = { + .type = device_type_usb, + .open = usb_block_open, + .seek = usb_block_seek, + .size = usb_partition_size, + .read = usb_block_read, + .write = NULL, + .close = usb_block_close, + .dev_init = usb_dev_init, + .dev_close = usb_dev_close, +}; + +static io_dev_info_t usb_dev_info = { + .funcs = &usb_dev_funcs, + .info = (uintptr_t)0, +}; + +/* Identify the device type as usb */ +static io_type_t device_type_usb(void) +{ + return IO_TYPE_USB; +} + +/* Callback to notify that data has been written in memory + * ( set by USBD_DFU_SetDownloadAddr) + */ +static uint16_t usb_callback_write_done(uint32_t *written_in, uint32_t len) +{ + VERBOSE("%s Written_in 0x%lx len %i\n", __func__, (uintptr_t)written_in, + len); + + /* Update SRAM state machine when block writing is finished */ + usb_status = USB_STATE_WRITTEN; + + return 0; +} + +/* Call back to notify that a read memory is requested */ +static uint8_t *usb_callback_read(uint8_t *src, uint8_t *dest, uint32_t len) +{ + ERROR("%s read is not supported src 0x%lx dest 0x%lx len %i\n", + __func__, (uintptr_t)src, (uintptr_t)dest, len); + + /* Return a valid address to avoid HardFault */ + return (uint8_t *)(dest); +} + +/* Get the status to know if written operation has been checked */ +static uint16_t usb_callback_get_status(void) +{ + uint16_t status; + + /* According to SRAM state machine */ + switch (usb_status) { + case USB_STATE_WRITTEN: + /* The SRAM bloc writing has been done, change state machine + * to set SRAM in SRAM_STATE_READY + */ + usb_status = USB_STATE_READY; + + /* Notice caller that SRAM block writing is finished */ + status = DFU_MEDIA_STATE_WRITTEN; + + /* Checks checksum calculation result */ + if (checksum_is_wrong == 1) { + status = DFU_MEDIA_STATE_ERROR; + checksum_is_wrong = 0; + } + break; + + case USB_STATE_READY: + /* Notice caller that SRAM is ready to be written */ + status = DFU_MEDIA_STATE_READY; + break; + + default: + status = DFU_MEDIA_STATE_ERROR; + ERROR("USB unknown state\n"); + break; + } + VERBOSE("usb_callback_GetStatus status : %i\n", status); + return status; +} + +/* Open a connection to the usb device */ +static int usb_dev_open(const uintptr_t init_params, + io_dev_info_t **dev_info) +{ + usb_handle_t *usb_core_handle = (usb_handle_t *)init_params; + + assert(dev_info); + *dev_info = &usb_dev_info; + + usb_dfu_fops.write_done = usb_callback_write_done; + usb_dfu_fops.read = usb_callback_read; + usb_dfu_fops.get_status = usb_callback_get_status; + usb_status = USB_STATE_READY; + checksum_is_wrong = 0; + + usb_core_handle->user_data = &usb_dfu_fops; + + usb_dev_info.info = (uintptr_t)usb_core_handle; + + return 0; +} + +static int usb_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) +{ + return 0; +} + +/* Close a connection to the usb device */ +static int usb_dev_close(io_dev_info_t *dev_info) +{ + return 0; +} + +/* Open a file on the usb device */ +static int usb_block_open(io_dev_info_t *dev_info, const uintptr_t spec, + io_entity_t *entity) +{ + int result; + uint32_t length = 0; + boot_api_image_header_t *header = + (boot_api_image_header_t *)first_usb_buffer; + + const struct stm32image_part_info *partition_spec = + (struct stm32image_part_info *)spec; + + /* Use PHASE_FSBL1 like init value*/ + if (current_phase.phase_id == PHASE_FSBL1) { + assert(partition_spec); + assert(entity); + + current_phase.current_packet = 0; + + if (!strcmp(partition_spec->name, BL33_IMAGE_NAME)) { + /* read flash layout first for U-boot */ + current_phase.phase_id = PHASE_FLASHLAYOUT; + current_phase.keep_header = 1; + + usb_dfu_set_phase_id(PHASE_FLASHLAYOUT); + usb_dfu_set_download_addr((uintptr_t) + &first_usb_buffer[0]); + + header->magic = 0; + + while (((header->magic != + BOOT_API_IMAGE_HEADER_MAGIC_NB) || + usb_dfu_get_current_req() == DFU_DNLOAD)) { + usb_core_handle_it((usb_handle_t *) + usb_dev_info.info); + } + result = usb_block_read(NULL, + FLASHLAYOUT_BASE, + 0, + &length); + if (result != 0) { + return result; + } + + flush_dcache_range((unsigned long)FLASHLAYOUT_BASE, + header->image_length + + sizeof(boot_api_image_header_t)); + + current_phase.current_packet = 0; + current_phase.keep_header = 0; + current_phase.phase_id = PHASE_SSBL; + current_phase.max_size = dt_get_ddr_size(); + } + entity->info = (uintptr_t)¤t_phase; + result = 0; + } else { + WARN("A UART device is already active. Close first.\n"); + result = -EIO; + } + + return result; +} + +/* Return the size of a partition */ +static int usb_partition_size(io_entity_t *entity, size_t *length) +{ + boot_api_image_header_t *header = + (boot_api_image_header_t *)first_usb_buffer; + int result = 0; + + usb_dfu_set_phase_id(current_phase.phase_id); + usb_dfu_set_download_addr((uintptr_t)&first_usb_buffer[0]); + + header->magic = 0; + + while ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) || + (usb_dfu_get_current_req() == DFU_DNLOAD)) { + usb_core_handle_it((usb_handle_t *)usb_dev_info.info); + } + + if (header->image_length > current_phase.max_size) + result = -EIO; + else + *length = header->image_length; + + INFO("%s: partition size : 0x%x\n", __func__, + header->image_length); + + return result; +} + +/* Seek to a particular file offset on the usb device */ +static int usb_block_seek(io_entity_t *entity, int mode, + signed long long offset) +{ + return 0; +} + +/* Read data from a file on the usb device */ +static int usb_block_read(io_entity_t *entity, uintptr_t buffer, + size_t length, size_t *length_read) +{ + uint8_t *local_ptr = (uint8_t *)buffer; + int result = 0; + boot_api_image_header_t *header = + (boot_api_image_header_t *)first_usb_buffer; + + INFO("Start Download partition %i to address 0x%lx length %i\n", + current_phase.phase_id, buffer, length); + + if (current_phase.keep_header) { + memcpy((uint8_t *)local_ptr, + (uint8_t *)&first_usb_buffer[0], + USB_DFU_MAX_XFER_SIZE); + + usb_dfu_set_download_addr((uintptr_t) + &local_ptr[USB_DFU_MAX_XFER_SIZE]); + } else { + memcpy((uint8_t *)local_ptr, + (uint8_t *) + &first_usb_buffer[sizeof(boot_api_image_header_t)], + USB_DFU_MAX_XFER_SIZE - + sizeof(boot_api_image_header_t)); + + usb_dfu_set_download_addr((uintptr_t) + &local_ptr[USB_DFU_MAX_XFER_SIZE - + sizeof(boot_api_image_header_t)]); + } + + while (!usb_dfu_download_is_completed()) { + /* Reload watchdog */ + stm32_iwdg_refresh(); + + usb_core_handle_it((usb_handle_t *)usb_dev_info.info); + } + + usb_core_handle_it((usb_handle_t *)usb_dev_info.info); + usb_core_handle_it((usb_handle_t *)usb_dev_info.info); + + if (current_phase.keep_header) + local_ptr += sizeof(boot_api_image_header_t); + + /* Verify header and checksum payload */ + result = stm32mp_check_header(header, (uintptr_t)local_ptr); + if (result) { + ERROR("Header check failed\n"); + return result; + } + + if (current_phase.phase_id != PHASE_FLASHLAYOUT) { + result = stm32mp_auth_image(header, (uintptr_t)local_ptr); + if (result != 0) { + ERROR("Authentication failed\n"); + return result; + } + } + + /* Wait Detach in case of bl33 */ + if (current_phase.phase_id == PHASE_SSBL) { + uint64_t timeout; + uint32_t detach_timeout = DETACH_TIMEOUT; + + usb_dfu_set_phase_id(0x0); + usb_dfu_set_download_addr(UNDEFINE_DOWN_ADDR); + usb_dfu_request_detach(); + timeout = timeout_init_us(IO_USB_TIMEOUT_10_SEC); + + while (detach_timeout != 0U) { + usb_core_handle_it((usb_handle_t *) + usb_dev_info.info); + + if (usb_dfu_detach_req() == 0U) { + /* + * Continue to handle usb core IT to assure + * complete data transmission + */ + detach_timeout--; + } + + if (timeout_elapsed(timeout)) { + return -EIO; + } + } + + /* STOP the USB Handler */ + usb_core_stop((usb_handle_t *)usb_dev_info.info); + } + + *length_read = length; + + return 0; +} + +/* Close a file on the usb device */ +static int usb_block_close(io_entity_t *entity) +{ + current_phase.phase_id = PHASE_FSBL1; + + return 0; +} + +/* Exported functions */ + +/* Register the usb driver with the IO abstraction */ +int register_io_dev_usb(const io_dev_connector_t **dev_con) +{ + int result; + + assert(dev_con); + + result = io_register_device(&usb_dev_info); + if (!result) + *dev_con = &usb_dev_connector; + + return result; +} diff --git a/drivers/st/usb_dwc2/usb_dwc2.c b/drivers/st/usb_dwc2/usb_dwc2.c new file mode 100644 index 0000000..fc0b862 --- /dev/null +++ b/drivers/st/usb_dwc2/usb_dwc2.c @@ -0,0 +1,859 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include + +static usb_dwc2_t dwc2_handle; + +static const usb_driver_t usb_dwc2driver = { + .disable_int = usb_dwc2_disable_int, + .ep0_out_start = usb_dwc2_ep0_out_start, + .ep_start_xfer = usb_dwc2_ep_start_xfer, + .ep0_start_xfer = usb_dwc2_ep0_start_xfer, + .write_packet = usb_dwc2_write_packet, + .read_packet = usb_dwc2_read_packet, + .ep_set_stall = usb_dwc2_ep_set_stall, + .stop_device = usb_dwc2_stop_device, + .set_address = usb_dwc2_set_address, + .dev_disconnect = usb_dwc2_dev_disconnect, + .write_empty_tx_fifo = usb_dwc2_write_empty_tx_fifo, + .it_handler = usb_dwc2_it_handler +}; + +/* + * USB_OTG_FlushTxFifo : Flush a Tx FIFO + * USBx : Selected device + * num : FIFO number + * This parameter can be a value from 1 to 15 + * 15 means Flush all Tx FIFOs + * return : status + */ +static usb_status_t usb_dwc2_flush_tx_fifo(usb_dwc2_global_t *usbx, + uint32_t num) +{ + uint32_t count = 0; + + usbx->grstctl = (USB_OTG_GRSTCTL_TXFFLSH | (uint32_t)(num << 6)); + + do { + if (++count > 200000) + return USBD_TIMEOUT; + } while ((usbx->grstctl & USB_OTG_GRSTCTL_TXFFLSH) == + USB_OTG_GRSTCTL_TXFFLSH); + + return USBD_OK; +} + +/* + * USB_FlushRxFifo : Flush Rx FIFO + * param : USBx : Selected device + * return : status + */ +static usb_status_t usb_dwc2_flush_rx_fifo(usb_dwc2_global_t *usbx) +{ + uint32_t count = 0; + + usbx->grstctl = USB_OTG_GRSTCTL_RXFFLSH; + + do { + if (++count > 200000) + return USBD_TIMEOUT; + } while ((usbx->grstctl & USB_OTG_GRSTCTL_RXFFLSH) == + USB_OTG_GRSTCTL_RXFFLSH); + + return USBD_OK; +} + +/* + * USB_ReadInterrupts: return the global USB interrupt status + * param USBx : Selected device + * return : interrupt register value + */ +static uint32_t usb_dwc2_read_int(usb_dwc2_global_t *usbx) +{ + uint32_t v = 0; + + v = usbx->gintsts; + v &= usbx->gintmsk; + + return v; +} + +/* + * usb_dwc2_all_out_ep_int : return the USB device OUT endpoints interrupt + * param : USBx : Selected device + * return : device OUT endpoint interrupts + */ +static uint32_t usb_dwc2_all_out_ep_int(usb_dwc2_global_t *usbx) +{ + uint32_t v = 0; + + v = dwc2_handle.usb_device->daint; + v &= dwc2_handle.usb_device->daintmsk; + + return ((v & 0xffff0000) >> 16); +} + +/* + * usb_dwc2_all_in_ep_int: return the USB device IN endpoints interrupt + * param : USBx : Selected device + * return : device IN endpoint interrupts + */ +static uint32_t usb_dwc2_all_in_ep_int(usb_dwc2_global_t *usbx) +{ + uint32_t v = 0; + + v = dwc2_handle.usb_device->daint; + v &= dwc2_handle.usb_device->daintmsk; + + return ((v & 0xFFFF)); +} + +/* + * usb_dwc2_out_ep_int : returns Device OUT EP Interrupt register + * USBx : Selected device + * epnum : endpoint number + * This parameter can be a value from 0 to 15 + * return : Device OUT EP Interrupt register + */ +static uint32_t usb_dwc2_out_ep_int(usb_dwc2_global_t *usbx, uint8_t epnum) +{ + uint32_t v = 0; + + v = dwc2_handle.usb_out_endpoint[epnum]->epint; + v &= dwc2_handle.usb_device->doepmsk; + + return v; +} + +/* + * usb_dwc2_in_ep_int : Returns Device IN EP Interrupt register + * param : USBx : Selected device + * param : epnum : endpoint number + * This parameter can be a value from 0 to 15 + * return : Device IN EP Interrupt register + */ +static uint32_t usb_dwc2_in_ep_int(usb_dwc2_global_t *usbx, uint8_t epnum) +{ + uint32_t msk, emp; + + msk = dwc2_handle.usb_device->diepmsk; + emp = dwc2_handle.usb_device->diepempmsk; + msk |= ((emp >> epnum) & 0x1) << 7; + + return (dwc2_handle.usb_in_endpoint[epnum]->epint & msk); +} + +/* + * usb_dwc2_get_mode : Returns USB core mode + * param : USBx : Selected device + * return : core mode : Host or Device + * This parameter can be one of the these values: + * 0 : Host + * 1 : Device + */ +static uint32_t usb_dwc2_get_mode(usb_dwc2_global_t *usbx) +{ + return ((usbx->gintsts) & 0x1); +} + +/* + * usb_dwc2_activate_setup : Activate EP0 for Setup transactions + * param : USBx : Selected device + * return : status + */ +static usb_status_t usb_dwc2_activate_setup(usb_dwc2_global_t *usbx) +{ + /* Set the MPS of the IN EP based on the enumeration speed */ + dwc2_handle.usb_in_endpoint[0]->epctl &= ~USB_OTG_DIEPCTL_MPSIZ; + + if ((dwc2_handle.usb_device->dsts & USB_OTG_DSTS_ENUMSPD) == + DSTS_ENUMSPD_LS_PHY_6MHZ) + dwc2_handle.usb_in_endpoint[0]->epctl |= 3; + + dwc2_handle.usb_device->dctl |= USB_OTG_DCTL_CGINAK; + + return USBD_OK; +} + +/* + * usb_dwc2_disable_int : + * Disable the controller's Global Int in the AHB Config reg + * param : handle : Selected device + * return : status + */ +usb_status_t usb_dwc2_disable_int(void *handle) +{ + usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; + + usbx->gahbcfg &= ~USB_OTG_GAHBCFG_GINT; + return USBD_OK; +} + +/* + * usb_dwc2_ep0_out_start : Prepare the EP0 to start the first control setup + * param : handle : Selected device + * return : status + */ +usb_status_t usb_dwc2_ep0_out_start(void *handle) +{ + /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ + + dwc2_handle.usb_out_endpoint[0]->eptsiz = 0; + dwc2_handle.usb_out_endpoint[0]->eptsiz |= (USB_OTG_DOEPTSIZ_PKTCNT & + (1 << 19)); + dwc2_handle.usb_out_endpoint[0]->eptsiz |= (3 * 8); + dwc2_handle.usb_out_endpoint[0]->eptsiz |= USB_OTG_DOEPTSIZ_STUPCNT; + + return USBD_OK; +} + +/* + * usb_dwc2_ep_start_xfer : setup and starts a transfer over an EP + * param : handle : Selected device + * param : ep: pointer to endpoint structure + * return : status + */ +usb_status_t usb_dwc2_ep_start_xfer(void *handle, usb_otg_ep_t *ep) +{ + usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; + + /* IN endpoint */ + if (ep->is_in == 1) { + /* Zero Length Packet? */ + if (ep->xfer_len == 0) { + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DIEPTSIZ_PKTCNT); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= + (USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19)); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DIEPTSIZ_XFRSIZ); + } else { + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DIEPTSIZ_XFRSIZ); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DIEPTSIZ_PKTCNT); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= + (USB_OTG_DIEPTSIZ_PKTCNT & + (((ep->xfer_len + ep->maxpacket - 1) / + ep->maxpacket) << 19)); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= + (USB_OTG_DIEPTSIZ_XFRSIZ & + ep->xfer_len); + + if (ep->type == EP_TYPE_ISOC) { + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DIEPTSIZ_MULCNT); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= + (USB_OTG_DIEPTSIZ_MULCNT & + (1 << 29)); + } + } + + if (ep->type != EP_TYPE_ISOC) { + /* Enable the Tx FIFO Empty Interrupt for this EP */ + if (ep->xfer_len > 0) + dwc2_handle.usb_device->diepempmsk |= + 1 << ep->num; + } + + if (ep->type == EP_TYPE_ISOC) { + if ((dwc2_handle.usb_device->dsts & (1 << 8)) == 0) { + dwc2_handle.usb_in_endpoint[ep->num]->epctl |= + USB_OTG_DIEPCTL_SODDFRM; + } else { + dwc2_handle.usb_in_endpoint[ep->num]->epctl |= + USB_OTG_DIEPCTL_SD0PID_SEVNFRM; + } + } + + /* EP enable, IN data in FIFO */ + dwc2_handle.usb_in_endpoint[ep->num]->epctl |= + (USB_OTG_DIEPCTL_CNAK | + USB_OTG_DIEPCTL_EPENA); + + if (ep->type == EP_TYPE_ISOC) + usb_dwc2_write_packet(usbx, ep->xfer_buff, + ep->num, ep->xfer_len); + } else { + /* Program the transfer size and packet count as follows: + * pktcnt = N + * xfersize = N * maxpacket + */ + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DOEPTSIZ_XFRSIZ); + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DOEPTSIZ_PKTCNT); + + if (ep->xfer_len == 0) { + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= + (USB_OTG_DOEPTSIZ_XFRSIZ & + ep->maxpacket); + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= + (USB_OTG_DOEPTSIZ_PKTCNT & (1 << 19)); + } else { + uint16_t pktcnt = (ep->xfer_len + ep->maxpacket - 1) / + ep->maxpacket; + + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= + (USB_OTG_DOEPTSIZ_PKTCNT & + (pktcnt << 19)); + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= + (USB_OTG_DOEPTSIZ_XFRSIZ & + (ep->maxpacket * pktcnt)); + } + + if (ep->type == EP_TYPE_ISOC) { + if ((dwc2_handle.usb_device->dsts & (1 << 8)) == 0) + dwc2_handle.usb_out_endpoint[ep->num]->epctl |= + USB_OTG_DOEPCTL_SODDFRM; + else + dwc2_handle.usb_out_endpoint[ep->num]->epctl |= + USB_OTG_DOEPCTL_SD0PID_SEVNFRM; + } + /* EP enable */ + dwc2_handle.usb_out_endpoint[ep->num]->epctl |= + (USB_OTG_DOEPCTL_CNAK | USB_OTG_DOEPCTL_EPENA); + } + return USBD_OK; +} + +/* + * usb_dwc2_ep0_start_xfer : setup and starts a transfer over the EP 0 + * param : handle : Selected device + * param : ep: pointer to endpoint structure + * return : status + */ +usb_status_t usb_dwc2_ep0_start_xfer(void *handle, usb_otg_ep_t *ep) +{ + /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ + + /* IN endpoint */ + if (ep->is_in == 1) { + /* Zero Length Packet? */ + if (ep->xfer_len == 0) { + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DIEPTSIZ_PKTCNT); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= + (USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19)); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DIEPTSIZ_XFRSIZ); + } else { + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DIEPTSIZ_XFRSIZ); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DIEPTSIZ_PKTCNT); + + if (ep->xfer_len > ep->maxpacket) + ep->xfer_len = ep->maxpacket; + + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= + (USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19)); + dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= + (USB_OTG_DIEPTSIZ_XFRSIZ & + ep->xfer_len); + } + + /* Enable the Tx FIFO Empty Interrupt for this EP */ + if (ep->xfer_len > 0) + dwc2_handle.usb_device->diepempmsk |= 1 << (ep->num); + + /* EP enable, IN data in FIFO */ + dwc2_handle.usb_in_endpoint[ep->num]->epctl |= + (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA); + } else { + /* Program the transfer size and packet count as follows: + * pktcnt = N + * xfersize = N * maxpacket + */ + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DOEPTSIZ_XFRSIZ); + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &= + ~(USB_OTG_DOEPTSIZ_PKTCNT); + + if (ep->xfer_len > 0) + ep->xfer_len = ep->maxpacket; + + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= + (USB_OTG_DOEPTSIZ_PKTCNT & + (1 << 19)); + dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= + (USB_OTG_DOEPTSIZ_XFRSIZ & + (ep->maxpacket)); + + /* EP enable */ + dwc2_handle.usb_out_endpoint[ep->num]->epctl |= + (USB_OTG_DOEPCTL_CNAK | + USB_OTG_DOEPCTL_EPENA); + } + return USBD_OK; +} + +/* + * usb_dwc2_write_packet : Writes a packet into the Tx FIFO associated + * with the EP/channel + * param : handle : Selected device + * param : src : pointer to source buffer + * param : ch_ep_num : endpoint or host channel number + * param : len : Number of bytes to write + * return : status + */ +usb_status_t usb_dwc2_write_packet(void *handle, uint8_t *src, + uint8_t ch_ep_num, uint16_t len) +{ + uint32_t count32b, i, j; + /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ + + count32b = (len + 3) / 4; + for (i = 0; i < count32b; i++, src += 4) { + uint32_t src_copy = 0; + + /* Data written to fifo need to be 4 bytes aligned */ + for (j = 0; j < 4; j++) + src_copy += (*(src + j)) << (8 * j); + + *dwc2_handle.usb_fifo[ch_ep_num] = src_copy; + } + + return USBD_OK; +} + +/* + * usb_dwc2_read_packet : read a packet from the Tx FIFO associated + * with the EP/channel + * param : handle : Selected device + * param : src : source pointer + * param : ch_ep_num : endpoint or host channel number + * param : len : Number of bytes to read + * return : pointer to destination buffer + */ +void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len) +{ + uint32_t i = 0; + uint32_t count32b = (len + 3) / 4; + /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ + + VERBOSE("read packet length %i to 0x%lx\n", len, (uintptr_t)dest); + + for (i = 0; i < count32b; i++, dest += 4) { + *(uint32_t *)dest = *dwc2_handle.usb_fifo[0]; + dsb(); + } + + return ((void *)dest); +} + +/* + * usb_dwc2_EPSetStall : set a stall condition over an EP + * param : handle : Selected device + * param : ep: pointer to endpoint structure + * return : status + */ +usb_status_t usb_dwc2_ep_set_stall(void *handle, usb_otg_ep_t *ep) +{ + /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ + if (ep->is_in == 1) { + if ((dwc2_handle.usb_in_endpoint[ep->num]->epctl & + USB_OTG_DIEPCTL_EPENA) == 0) + dwc2_handle.usb_in_endpoint[ep->num]->epctl &= + ~(USB_OTG_DIEPCTL_EPDIS); + dwc2_handle.usb_in_endpoint[ep->num]->epctl |= + USB_OTG_DIEPCTL_STALL; + } else { + if ((dwc2_handle.usb_out_endpoint[ep->num]->epctl & + USB_OTG_DOEPCTL_EPENA) == 0) + dwc2_handle.usb_out_endpoint[ep->num]->epctl &= + ~(USB_OTG_DOEPCTL_EPDIS); + dwc2_handle.usb_out_endpoint[ep->num]->epctl |= + USB_OTG_DOEPCTL_STALL; + } + return USBD_OK; +} + +/* + * usb_dwc2_stop_device : Stop the usb device mode + * param : handle : Selected device + * return : status + */ +usb_status_t usb_dwc2_stop_device(void *handle) +{ + uint32_t i = 0; + usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; + + /* Clear Pending interrupt */ + for (i = 0; i < 15 ; i++) { + dwc2_handle.usb_in_endpoint[i]->epint = 0xFF; + dwc2_handle.usb_out_endpoint[i]->epint = 0xFF; + } + dwc2_handle.usb_device->daint = 0xFFFFFFFF; + + /* Clear interrupt masks */ + dwc2_handle.usb_device->diepmsk = 0; + dwc2_handle.usb_device->doepmsk = 0; + dwc2_handle.usb_device->daintmsk = 0; + + /* Flush the FIFO */ + usb_dwc2_flush_rx_fifo(usbx); + usb_dwc2_flush_tx_fifo(usbx, 0x10); + + return USBD_OK; +} + +/* + * usb_dwc2_set_address : Stop the usb device mode + * param : handle : Selected device + * param : address : new device address to be assigned + * This parameter can be a value from 0 to 255 + * return : status + */ +usb_status_t usb_dwc2_set_address(void *handle, uint8_t address) +{ + /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ + + dwc2_handle.usb_device->dcfg &= ~(USB_OTG_DCFG_DAD); + dwc2_handle.usb_device->dcfg |= (address << 4) & USB_OTG_DCFG_DAD; + + return USBD_OK; +} + +/* + * usb_dwc2_dev_disconnect : + * Disconnect the USB device by disabling the pull-up/pull-down + * param : handle : Selected device + * return : status + */ +usb_status_t usb_dwc2_dev_disconnect(void *handle) +{ + /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ + + dwc2_handle.usb_device->dctl |= USB_OTG_DCTL_SDIS; + + return USBD_OK; +} + +/* + * usb_dwc2_write_empty_tx_fifo + * check FIFO for the next packet to be loaded + * param : handle : Selected device + * param : epnum : endpoint number + * param : xfer_len : block length + * param : xfer_count : number of block + * param : maxpacket : max packet length + * param : xfer_buff : buffer pointer + * retval : status + */ +usb_status_t usb_dwc2_write_empty_tx_fifo(void *handle, + uint32_t epnum, uint32_t xfer_len, + uint32_t *xfer_count, + uint32_t maxpacket, + uint8_t **xfer_buff) +{ + int32_t len = 0; + uint32_t len32b; + usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; + + len = xfer_len - *xfer_count; + + if ((len > 0) && ((uint32_t)len > maxpacket)) + len = maxpacket; + + len32b = (len + 3) / 4; + + while ((dwc2_handle.usb_in_endpoint[epnum]->txfsts & + USB_OTG_DTXFSTS_INEPTFSAV) > len32b && + (*xfer_count < xfer_len) && (xfer_len != 0)) { + /* Write the FIFO */ + len = xfer_len - *xfer_count; + + if ((len > 0) && ((uint32_t)len > maxpacket)) + len = maxpacket; + + len32b = (len + 3) / 4; + + usb_dwc2_write_packet(usbx, *xfer_buff, epnum, len); + + *xfer_buff += len; + *xfer_count += len; + } + + if (len <= 0) { + uint32_t fifoemptymsk = 0x1 << epnum; + + dwc2_handle.usb_device->diepempmsk &= ~fifoemptymsk; + } + + return USBD_OK; +} + +/* + * @brief This function handles PCD interrupt request. + * @param hpcd: PCD handle + * @retval HAL status + */ +usb_action_t usb_dwc2_it_handler(void *handle, uint32_t *param) +{ + usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; + uint32_t ep_intr, epint, epnum = 0; + uint32_t temp; + + /* ensure that we are in device mode */ + if (usb_dwc2_get_mode(usbx) != USB_OTG_MODE_DEVICE) + return USB_NOTHING; + + /* avoid spurious interrupt */ + if (!usb_dwc2_read_int(usbx)) + return USB_NOTHING; + + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_MMIS) + /* incorrect mode, acknowledge the interrupt */ + usbx->gintsts = USB_OTG_GINTSTS_MMIS; + + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_OEPINT) { + /* Read in the device interrupt bits */ + ep_intr = usb_dwc2_all_out_ep_int(usbx); + + while (!(ep_intr & 1)) { + epnum++; + ep_intr >>= 1; + } + + if (ep_intr & 1) { + epint = usb_dwc2_out_ep_int(usbx, epnum); + + if ((epint & USB_OTG_DOEPINT_XFRC) == + USB_OTG_DOEPINT_XFRC) { + dwc2_handle.usb_out_endpoint[epnum]->epint = + USB_OTG_DOEPINT_XFRC; + *param = epnum; + return USB_DATA_OUT; + } + if ((epint & USB_OTG_DOEPINT_STUP) == + USB_OTG_DOEPINT_STUP) { + /* Inform the upper layer that a setup packet + * is available + */ + dwc2_handle.usb_out_endpoint[epnum]->epint = + USB_OTG_DOEPINT_STUP; + return USB_SETUP; + } + if ((epint & USB_OTG_DOEPINT_OTEPDIS) == + USB_OTG_DOEPINT_OTEPDIS) + dwc2_handle.usb_out_endpoint[epnum]->epint = + USB_OTG_DOEPINT_OTEPDIS; + } + } + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_IEPINT) { + /* Read in the device interrupt bits */ + ep_intr = usb_dwc2_all_in_ep_int(usbx); + + while (!(ep_intr & 1)) { + epnum++; + ep_intr >>= 1; + } + /* In ITR */ + if (ep_intr & 0x1) { + epint = usb_dwc2_in_ep_int(usbx, epnum); + + if ((epint & USB_OTG_DIEPINT_XFRC) == + USB_OTG_DIEPINT_XFRC) { + uint32_t fifoemptymsk = 0x1 << epnum; + + dwc2_handle.usb_device->diepempmsk &= + ~fifoemptymsk; + + dwc2_handle.usb_in_endpoint[epnum]->epint = + USB_OTG_DIEPINT_XFRC; + + *param = epnum; + return USB_DATA_IN; + } + if ((epint & USB_OTG_DIEPINT_TOC) == + USB_OTG_DIEPINT_TOC) + dwc2_handle.usb_in_endpoint[epnum]->epint = + USB_OTG_DIEPINT_TOC; + + if ((epint & USB_OTG_DIEPINT_ITTXFE) == + USB_OTG_DIEPINT_ITTXFE) + dwc2_handle.usb_in_endpoint[epnum]->epint = + USB_OTG_DIEPINT_ITTXFE; + + if ((epint & USB_OTG_DIEPINT_INEPNE) == + USB_OTG_DIEPINT_INEPNE) + dwc2_handle.usb_in_endpoint[epnum]->epint = + USB_OTG_DIEPINT_INEPNE; + + if ((epint & USB_OTG_DIEPINT_EPDISD) == + USB_OTG_DIEPINT_EPDISD) + dwc2_handle.usb_in_endpoint[epnum]->epint = + USB_OTG_DIEPINT_EPDISD; + + if ((epint & USB_OTG_DIEPINT_TXFE) == + USB_OTG_DIEPINT_TXFE) { + *param = epnum; + return USB_WRITE_EMPTY; + } + } + } + + /* Handle Resume Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_WKUINT) { + INFO("handle USB : Resume\n"); + /* Clear the Remote Wake-up Signaling */ + dwc2_handle.usb_device->dctl &= ~USB_OTG_DCTL_RWUSIG; + usbx->gintsts = USB_OTG_GINTSTS_WKUINT; + return USB_RESUME; + } + + /* Handle Suspend Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_USBSUSP) { + INFO("handle USB : Suspend int\n"); + usbx->gintsts = USB_OTG_GINTSTS_USBSUSP; + if ((dwc2_handle.usb_device->dsts & USB_OTG_DSTS_SUSPSTS) == + USB_OTG_DSTS_SUSPSTS){ + return USB_SUSPEND; + } + } + + /* Handle LPM Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_LPMINT) { + INFO("handle USB : LPM int enter in suspend\n"); + usbx->gintsts = USB_OTG_GINTSTS_LPMINT; + *param = (usbx->glpmcfg & USB_OTG_GLPMCFG_BESL) >> 2; + return USB_LPM; + } + + /* Handle Reset Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_USBRST) { + INFO("handle USB : Reset\n"); + dwc2_handle.usb_device->dctl &= ~USB_OTG_DCTL_RWUSIG; + usb_dwc2_flush_tx_fifo(usbx, 0); + + dwc2_handle.usb_device->daint = 0xFFFFFFFF; + dwc2_handle.usb_device->daintmsk |= 0x10001; + + dwc2_handle.usb_device->doepmsk |= (USB_OTG_DOEPMSK_STUPM | + USB_OTG_DOEPMSK_XFRCM | + USB_OTG_DOEPMSK_EPDM); + dwc2_handle.usb_device->diepmsk |= (USB_OTG_DIEPMSK_TOM | + USB_OTG_DIEPMSK_XFRCM | + USB_OTG_DIEPMSK_EPDM); + + /* Set Default Address to 0 */ + dwc2_handle.usb_device->dcfg &= ~USB_OTG_DCFG_DAD; + + /* setup EP0 to receive SETUP packets */ + usb_dwc2_ep0_out_start(usbx); + + usbx->gintsts = USB_OTG_GINTSTS_USBRST; + } + + /* Handle Enumeration done Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_ENUMDNE) { + usb_dwc2_activate_setup(usbx); + usbx->gusbcfg &= ~USB_OTG_GUSBCFG_TRDT; + + usbx->gusbcfg |= (uint32_t)((USBD_HS_TRDT_VALUE << 10) & + USB_OTG_GUSBCFG_TRDT); + + usbx->gintsts = USB_OTG_GINTSTS_ENUMDNE; + return USB_ENUM_DONE; + } + + /* Handle RxQLevel Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_RXFLVL) { + usbx->gintmsk &= ~USB_OTG_GINTSTS_RXFLVL; + temp = usbx->grxstsp; + *param = (temp & USB_OTG_GRXSTSP_EPNUM); + *param |= ((temp & USB_OTG_GRXSTSP_BCNT) << 0xC); + + if (((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_DATA_UPDT) { + if ((temp & USB_OTG_GRXSTSP_BCNT) != 0) { + usbx->gintmsk |= USB_OTG_GINTSTS_RXFLVL; + return USB_READ_DATA_PACKET; + } + } else if (((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17) == + STS_SETUP_UPDT) { + usbx->gintmsk |= USB_OTG_GINTSTS_RXFLVL; + return USB_READ_SETUP_PACKET; + } + usbx->gintmsk |= USB_OTG_GINTSTS_RXFLVL; + } + + /* Handle SOF Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_SOF) { + INFO("handle USB : SOF\n"); + usbx->gintsts = USB_OTG_GINTSTS_SOF; + return USB_SOF; + } + + /* Handle Incomplete ISO IN Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_IISOIXFR) { + INFO("handle USB : ISO IN\n"); + usbx->gintsts = USB_OTG_GINTSTS_IISOIXFR; + } + + /* Handle Incomplete ISO OUT Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_PXFR_INCOMPISOOUT) { + INFO("handle USB : ISO OUT\n"); + usbx->gintsts = USB_OTG_GINTSTS_PXFR_INCOMPISOOUT; + } + + /* Handle Connection event Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_SRQINT) { + INFO("handle USB : Connect\n"); + usbx->gintsts = USB_OTG_GINTSTS_SRQINT; + } + + /* Handle Disconnection event Interrupt */ + if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_OTGINT) { + INFO("handle USB : Disconnect\n"); + temp = usbx->gotgint; + if ((temp & USB_OTG_GOTGINT_SEDET) == USB_OTG_GOTGINT_SEDET) + return USB_DISCONNECT; + } + return USB_NOTHING; +} + +void usb_dwc2_init_driver(usb_handle_t *usb_core_handle, + uint32_t *base_register) +{ + uint32_t i = 0; + uintptr_t base = (uintptr_t)base_register; + + dwc2_handle.usb_global = (usb_dwc2_global_t *)base; + + dwc2_handle.usb_device = (usb_dwc2_device_t *) + (base + USB_OTG_DEVICE_BASE); + + for (i = 0; i < USB_MAX_ENDPOINT_NB; i++) { + dwc2_handle.usb_in_endpoint[i] = (usb_dwc2_endpoint_t *) + (base + USB_OTG_IN_ENDPOINT_BASE + + (i * sizeof(usb_dwc2_endpoint_t))); + dwc2_handle.usb_out_endpoint[i] = (usb_dwc2_endpoint_t *) + (base + USB_OTG_OUT_ENDPOINT_BASE + + (i * sizeof(usb_dwc2_endpoint_t))); + dwc2_handle.usb_fifo[i] = (uint32_t *)(base + + USB_OTG_FIFO_BASE + + (i * USB_OTG_FIFO_SIZE)); + } + + register_usb_driver(usb_core_handle, &usb_dwc2driver, + (void *)&dwc2_handle); +} diff --git a/fdts/stm32mp15xx-dkx.dtsi b/fdts/stm32mp15xx-dkx.dtsi index ec075f6..82b602d 100644 --- a/fdts/stm32mp15xx-dkx.dtsi +++ b/fdts/stm32mp15xx-dkx.dtsi @@ -60,6 +60,7 @@ interrupt-controller; #interrupt-cells = <2>; status = "okay"; + secure-status = "disabled"; regulators { compatible = "st,stpmic1-regulators"; diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h index f2d641c..b8f1c59 100644 --- a/include/drivers/io/io_storage.h +++ b/include/drivers/io/io_storage.h @@ -26,6 +26,7 @@ IO_TYPE_MMC, IO_TYPE_STM32IMAGE, IO_TYPE_ENCRYPTED, + IO_TYPE_USB, IO_TYPE_MAX } io_type_t; diff --git a/include/drivers/st/io_programmer.h b/include/drivers/st/io_programmer.h new file mode 100644 index 0000000..c6c2de1 --- /dev/null +++ b/include/drivers/st/io_programmer.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __IO_PROGRAMMER_H__ +#define __IO_PROGRAMMER_H__ + +/* Phase definition */ +#define PHASE_FLASHLAYOUT 0 +#define PHASE_FSBL1 1 +#define PHASE_FSBL2 2 +#define PHASE_SSBL 3 + +/* Command definition */ +#define GET_CMD_COMMAND 0x00 +#define GET_VER_COMMAND 0x01 +#define GET_ID_COMMAND 0x02 +#define PHASE_COMMAND 0x03 +#define START_COMMAND 0x21 +#define DOWNLOAD_COMMAND 0x31 + +/* Answer defines */ +#define INIT_BYTE 0x7F +#define ACK_BYTE 0x79 +#define NACK_BYTE 0x1F +#define ABORT 0x5F + +#define PROGRAMMER_TIMEOUT 0xFFFFFFFE + +#define DEVICE_ID_BYTE1 0x05 +#define DEVICE_ID_BYTE2 0x00 + +/* phase structure */ +struct phase_struct { + uint32_t keep_header; + uint32_t current_packet; + size_t max_size; + uint8_t phase_id; +}; + +/* current phase struct variable */ +static struct phase_struct current_phase = { + .phase_id = PHASE_FSBL1, + .max_size = 0, + .keep_header = 0, + .current_packet = 0, +}; + +#endif /* __IO_PROGRAMMER_H__ */ diff --git a/include/drivers/st/io_programmer_st_usb.h b/include/drivers/st/io_programmer_st_usb.h new file mode 100644 index 0000000..79effad --- /dev/null +++ b/include/drivers/st/io_programmer_st_usb.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __IO_USB_H__ +#define __IO_USB_H__ + +int register_io_dev_usb(const io_dev_connector_t **dev_con); + +#endif /* __IO_USB_H__ */ diff --git a/include/drivers/st/usb_dwc2.h b/include/drivers/st/usb_dwc2.h new file mode 100644 index 0000000..caff546 --- /dev/null +++ b/include/drivers/st/usb_dwc2.h @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_DWC2_H +#define __USB_DWC2_H + +#include + +/* define value use in register */ + +#define USB_OTG_MODE_DEVICE 0 +#define USB_OTG_MODE_HOST 1 +#define USB_OTG_MODE_DRD 2 + +#define DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ (0 << 1) +#define DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ (1 << 1) +#define DSTS_ENUMSPD_LS_PHY_6MHZ (2 << 1) +#define DSTS_ENUMSPD_FS_PHY_48MHZ (3 << 1) + +#define EP_TYPE_CTRL 0 +#define EP_TYPE_ISOC 1 +#define EP_TYPE_BULK 2 +#define EP_TYPE_INTR 3 + +#define STS_GOUT_NAK 1 +#define STS_DATA_UPDT 2 +#define STS_XFER_COMP 3 +#define STS_SETUP_COMP 4 +#define STS_SETUP_UPDT 6 + +#define USBD_HS_TRDT_VALUE 9 + +#define USB_OTG_DEVICE_BASE ((uint32_t)0x800) +#define USB_OTG_IN_ENDPOINT_BASE ((uint32_t)0x900) +#define USB_OTG_OUT_ENDPOINT_BASE ((uint32_t)0xB00) +#define USB_OTG_FIFO_BASE ((uint32_t)0x1000) +#define USB_OTG_FIFO_SIZE ((uint32_t)0x1000) +#define USB_MAX_ENDPOINT_NB 0x10 + +/* Bit definition for register */ +/* USB_OTG_GRSTCTL register */ +/* Core soft reset */ +#define USB_OTG_GRSTCTL_CSRST ((uint32_t)0x00000001) +/* HCLK soft reset */ +#define USB_OTG_GRSTCTL_HSRST ((uint32_t)0x00000002) +/* Host frame counter reset */ +#define USB_OTG_GRSTCTL_FCRST ((uint32_t)0x00000004) +/* RxFIFOflush */ +#define USB_OTG_GRSTCTL_RXFFLSH ((uint32_t)0x00000010) +/* TxFIFOflush */ +#define USB_OTG_GRSTCTL_TXFFLSH ((uint32_t)0x00000020) + +/* USB_OTG_DIEPCTLregister */ +/* Maximum packet size */ +#define USB_OTG_DIEPCTL_MPSIZ ((uint32_t)0x000007FF) +/* USB active endpoint */ +#define USB_OTG_DIEPCTL_USBAEP ((uint32_t)0x00008000) +/* Even/odd frame */ +#define USB_OTG_DIEPCTL_EONUM_DPID ((uint32_t)0x00010000) +/* NAK status */ +#define USB_OTG_DIEPCTL_NAKSTS ((uint32_t)0x00020000) +/* Endpoint type */ +#define USB_OTG_DIEPCTL_EPTYP ((uint32_t)0x000C0000) +/* Bit0 */ +#define USB_OTG_DIEPCTL_EPTYP_0 ((uint32_t)0x00040000) +/* Bit1 */ +#define USB_OTG_DIEPCTL_EPTYP_1 ((uint32_t)0x00080000) +/* STALL handshake */ +#define USB_OTG_DIEPCTL_STALL ((uint32_t)0x00200000) +/* TxFIFO number */ +#define USB_OTG_DIEPCTL_TXFNUM ((uint32_t)0x03C00000) +/* Bit0 */ +#define USB_OTG_DIEPCTL_TXFNUM_0 ((uint32_t)0x00400000) +/* Bit1 */ +#define USB_OTG_DIEPCTL_TXFNUM_1 ((uint32_t)0x00800000) +/* Bit2 */ +#define USB_OTG_DIEPCTL_TXFNUM_2 ((uint32_t)0x01000000) +/* Bit3 */ +#define USB_OTG_DIEPCTL_TXFNUM_3 ((uint32_t)0x02000000) +/* Clear NAK */ +#define USB_OTG_DIEPCTL_CNAK ((uint32_t)0x04000000) +/* Set NAK */ +#define USB_OTG_DIEPCTL_SNAK ((uint32_t)0x08000000) +/* Set DATA0 PID */ +#define USB_OTG_DIEPCTL_SD0PID_SEVNFRM ((uint32_t)0x10000000) +/* Set odd frame */ +#define USB_OTG_DIEPCTL_SODDFRM ((uint32_t)0x20000000) +/* Endpoint disable */ +#define USB_OTG_DIEPCTL_EPDIS ((uint32_t)0x40000000) +/* Endpoint enable */ +#define USB_OTG_DIEPCTL_EPENA ((uint32_t)0x80000000) + +/* USB_OTG_DOEPCTL register */ +/* Maximum packet size */ +#define USB_OTG_DOEPCTL_MPSIZ ((uint32_t)0x000007FF) +/* USB active endpoint */ +#define USB_OTG_DOEPCTL_USBAEP ((uint32_t)0x00008000) +/* NAK status */ +#define USB_OTG_DOEPCTL_NAKSTS ((uint32_t)0x00020000) +/* Set DATA0 PID */ +#define USB_OTG_DOEPCTL_SD0PID_SEVNFRM ((uint32_t)0x10000000) +/* Set odd frame */ +#define USB_OTG_DOEPCTL_SODDFRM ((uint32_t)0x20000000) +/* Endpoint type */ +#define USB_OTG_DOEPCTL_EPTYP ((uint32_t)0x000C0000) +/* Bit0 */ +#define USB_OTG_DOEPCTL_EPTYP_0 ((uint32_t)0x00040000) +/* Bit1 */ +#define USB_OTG_DOEPCTL_EPTYP_1 ((uint32_t)0x00080000) +/* Snoop mode */ +#define USB_OTG_DOEPCTL_SNPM ((uint32_t)0x00100000) +/* STALL handshake */ +#define USB_OTG_DOEPCTL_STALL ((uint32_t)0x00200000) +/* Clear NAK */ +#define USB_OTG_DOEPCTL_CNAK ((uint32_t)0x04000000) +/* Set NAK */ +#define USB_OTG_DOEPCTL_SNAK ((uint32_t)0x08000000) +/* Endpoint disable */ +#define USB_OTG_DOEPCTL_EPDIS ((uint32_t)0x40000000) +/* Endpoint enable */ +#define USB_OTG_DOEPCTL_EPENA ((uint32_t)0x80000000) + +/* USB_OTG_DSTSregister */ +/* Suspend status */ +#define USB_OTG_DSTS_SUSPSTS ((uint32_t)0x00000001) +/* Enumerated speed */ +#define USB_OTG_DSTS_ENUMSPD ((uint32_t)0x00000006) +/* Bit0 */ +#define USB_OTG_DSTS_ENUMSPD_0 ((uint32_t)0x00000002) +/* Bit1 */ +#define USB_OTG_DSTS_ENUMSPD_1 ((uint32_t)0x00000004) +/* Erratic error */ +#define USB_OTG_DSTS_EERR ((uint32_t)0x00000008) +/* Frame number of the received SOF */ +#define USB_OTG_DSTS_FNSOF ((uint32_t)0x003FFF00) + +/* USB_OTG_DCTLregister */ +/* Remote wakeup signaling */ +#define USB_OTG_DCTL_RWUSIG ((uint32_t)0x00000001) +/* Soft disconnect */ +#define USB_OTG_DCTL_SDIS ((uint32_t)0x00000002) +/* Global IN NAK status */ +#define USB_OTG_DCTL_GINSTS ((uint32_t)0x00000004) +/* Global OUT NAK status */ +#define USB_OTG_DCTL_GONSTS ((uint32_t)0x00000008) +/* Test control */ +#define USB_OTG_DCTL_TCTL ((uint32_t)0x00000070) +/* Bit0 */ +#define USB_OTG_DCTL_TCTL_0 ((uint32_t)0x00000010) +/* Bit1 */ +#define USB_OTG_DCTL_TCTL_1 ((uint32_t)0x00000020) +/* Bit2 */ +#define USB_OTG_DCTL_TCTL_2 ((uint32_t)0x00000040) +/* Set global IN NAK */ +#define USB_OTG_DCTL_SGINAK ((uint32_t)0x00000080) +/* Clear global IN NAK */ +#define USB_OTG_DCTL_CGINAK ((uint32_t)0x00000100) +/* Set global OUT NAK */ +#define USB_OTG_DCTL_SGONAK ((uint32_t)0x00000200) +/* Clear global OUT NAK */ +#define USB_OTG_DCTL_CGONAK ((uint32_t)0x00000400) +/* Power-on programming done */ +#define USB_OTG_DCTL_POPRGDNE ((uint32_t)0x00000800) + +/* USB_OTG_GAHBCFG register */ +/* Global interrupt mask */ +#define USB_OTG_GAHBCFG_GINT ((uint32_t)0x00000001) + +/* USB_OTG_DOEPTSIZr egister */ +/* Transfer size */ +#define USB_OTG_DOEPTSIZ_XFRSIZ ((uint32_t)0x0007FFFF) +/* Packet count */ +#define USB_OTG_DOEPTSIZ_PKTCNT ((uint32_t)0x1FF80000) +/* SETUP packet count */ +#define USB_OTG_DOEPTSIZ_STUPCNT ((uint32_t)0x60000000) +/* Bit0 */ +#define USB_OTG_DOEPTSIZ_STUPCNT_0 ((uint32_t)0x20000000) +/* Bit1 */ +#define USB_OTG_DOEPTSIZ_STUPCNT_1 ((uint32_t)0x40000000) + +/* USB_OTG_DIEPTSIZ register */ +/* Transfer size */ +#define USB_OTG_DIEPTSIZ_XFRSIZ ((uint32_t)0x0007FFFF) +/* Packet count */ +#define USB_OTG_DIEPTSIZ_PKTCNT ((uint32_t)0x1FF80000) +/* Packet count */ +#define USB_OTG_DIEPTSIZ_MULCNT ((uint32_t)0x60000000) + +/* USB_OTG_DCFG register */ +/* Device address */ +#define USB_OTG_DCFG_DAD ((uint32_t)0x000007F0) + +/* USB_OTG_DTXFSTS register */ +/* IN endpoint Tx FIFO space available */ +#define USB_OTG_DTXFSTS_INEPTFSAV ((uint32_t)0x0000FFFF) + +/* USB_OTG_GINTSTS register */ +/* Current mode of operation */ +#define USB_OTG_GINTSTS_CMOD ((uint32_t)0x00000001) +/* Modem is match interrupt */ +#define USB_OTG_GINTSTS_MMIS ((uint32_t)0x00000002) +/* OTG interrupt */ +#define USB_OTG_GINTSTS_OTGINT ((uint32_t)0x00000004) +/* Start offrame */ +#define USB_OTG_GINTSTS_SOF ((uint32_t)0x00000008) +/* Rx FIFO nonempty */ +#define USB_OTG_GINTSTS_RXFLVL ((uint32_t)0x00000010) +/* Non periodic Tx FIFO empty */ +#define USB_OTG_GINTSTS_NPTXFE ((uint32_t)0x00000020) +/* Global IN non periodic NAK effective */ +#define USB_OTG_GINTSTS_GINAKEFF ((uint32_t)0x00000040) +/* Global OUT NAK effective */ +#define USB_OTG_GINTSTS_BOUTNAKEFF ((uint32_t)0x00000080) +/* Early suspend */ +#define USB_OTG_GINTSTS_ESUSP ((uint32_t)0x00000400) +/* USB suspend */ +#define USB_OTG_GINTSTS_USBSUSP ((uint32_t)0x00000800) +/* USB reset */ +#define USB_OTG_GINTSTS_USBRST ((uint32_t)0x00001000) +/* Enumeration done */ +#define USB_OTG_GINTSTS_ENUMDNE ((uint32_t)0x00002000) +/* Isochronous OUT packet dropped interrupt */ +#define USB_OTG_GINTSTS_ISOODRP ((uint32_t)0x00004000) +/* End of periodic frame interrupt */ +#define USB_OTG_GINTSTS_EOPF ((uint32_t)0x00008000) +/* IN endpoint interrupt */ +#define USB_OTG_GINTSTS_IEPINT ((uint32_t)0x00040000) +/* OUT endpoint interrupt */ +#define USB_OTG_GINTSTS_OEPINT ((uint32_t)0x00080000) +/* Incomplete isochronous IN transfer */ +#define USB_OTG_GINTSTS_IISOIXFR ((uint32_t)0x00100000) +/* Incomplete periodic transfer */ +#define USB_OTG_GINTSTS_PXFR_INCOMPISOOUT ((uint32_t)0x00200000) +/* Data fetch suspended */ +#define USB_OTG_GINTSTS_DATAFSUSP ((uint32_t)0x00400000) +/* Reset detected interrupt */ +#define USB_OTG_GINTSTS_RSTDET ((uint32_t)0x00800000) +/* Host port interrupt */ +#define USB_OTG_GINTSTS_HPRTINT ((uint32_t)0x01000000) +/* Host channels interrupt */ +#define USB_OTG_GINTSTS_HCINT ((uint32_t)0x02000000) +/* Periodic Tx FIFO empty */ +#define USB_OTG_GINTSTS_PTXFE ((uint32_t)0x04000000) +/* LPM interrupt */ +#define USB_OTG_GINTSTS_LPMINT ((uint32_t)0x08000000) +/* Connector ID status change */ +#define USB_OTG_GINTSTS_CIDSCHG ((uint32_t)0x10000000) +/* Disconnect detected interrupt */ +#define USB_OTG_GINTSTS_DISCINT ((uint32_t)0x20000000) +/* Session request/new session detected interrupt */ +#define USB_OTG_GINTSTS_SRQINT ((uint32_t)0x40000000) +/* Resume/remote wakeup detected interrupt */ +#define USB_OTG_GINTSTS_WKUINT ((uint32_t)0x80000000) + +/* USB_OTG_DOEPINT register */ +/* Transfer completed interrupt */ +#define USB_OTG_DOEPINT_XFRC ((uint32_t)0x00000001) +/* Endpoint disabled interrupt */ +#define USB_OTG_DOEPINT_EPDISD ((uint32_t)0x00000002) +/* SETUP phase done */ +#define USB_OTG_DOEPINT_STUP ((uint32_t)0x00000008) +/* OUT token received when endpoint disabled */ +#define USB_OTG_DOEPINT_OTEPDIS ((uint32_t)0x00000010) +/* Back-to-back SETUP packets received */ +#define USB_OTG_DOEPINT_B2BSTUP ((uint32_t)0x00000040) +/* NYET interrupt */ +#define USB_OTG_DOEPINT_NYET ((uint32_t)0x00004000) + +/* USB_OTG_DIEPINTregister */ +/* Transfer completed interrupt */ +#define USB_OTG_DIEPINT_XFRC ((uint32_t)0x00000001) +/* Endpoint disabled interrupt */ +#define USB_OTG_DIEPINT_EPDISD ((uint32_t)0x00000002) +/* Timeout condition */ +#define USB_OTG_DIEPINT_TOC ((uint32_t)0x00000008) +/* IN token received when Tx FIFO is empty */ +#define USB_OTG_DIEPINT_ITTXFE ((uint32_t)0x00000010) +/* IN endpoint NAK effective */ +#define USB_OTG_DIEPINT_INEPNE ((uint32_t)0x00000040) +/* Transmit Fifo empty */ +#define USB_OTG_DIEPINT_TXFE ((uint32_t)0x00000080) +/* Transmit Fifo Underrun */ +#define USB_OTG_DIEPINT_TXFIFOUDRN ((uint32_t)0x00000100) +/* Buffer not available interrupt */ +#define USB_OTG_DIEPINT_BNA ((uint32_t)0x00000200) +/* Packet dropped status */ +#define USB_OTG_DIEPINT_PKTDRPSTS ((uint32_t)0x00000800) +/* Babble error interrupt */ +#define USB_OTG_DIEPINT_BERR ((uint32_t)0x00001000) +/* NAK interrupt */ +#define USB_OTG_DIEPINT_NAK ((uint32_t)0x00002000) + +/* USB_OTG_GLPMCFG register */ +/* BESL value received with last ACKed LPM Token */ +#define USB_OTG_GLPMCFG_BESL ((uint32_t)0x0000003C) + +/* USB_OTG_GOTGINT register */ +/* Session end detected */ +#define USB_OTG_GOTGINT_SEDET ((uint32_t)0x00000004) + +/* USB_OTG_GRXSTSP register */ +/* IN EP interrupt mask bits */ +#define USB_OTG_GRXSTSP_EPNUM ((uint32_t)0x0000000F) +/* OUT EP interrupt mask bits */ +#define USB_OTG_GRXSTSP_BCNT ((uint32_t)0x00007FF0) +/* OUT EP interrupt mask bits */ +#define USB_OTG_GRXSTSP_DPID ((uint32_t)0x00018000) +/* OUT EP interrupt mask bits */ +#define USB_OTG_GRXSTSP_PKTSTS ((uint32_t)0x001E0000) + +/* USB_OTG_GUSBCFG register */ +/* USB turn around time */ +#define USB_OTG_GUSBCFG_TRDT ((uint32_t)0x00003C00) + +/* USB_OTG_DOEPMSK register */ +/* Transfer completed interrupt mask */ +#define USB_OTG_DOEPMSK_XFRCM ((uint32_t)0x00000001) +/* Endpoint disabled interrupt mask */ +#define USB_OTG_DOEPMSK_EPDM ((uint32_t)0x00000002) +/* SETUP phase done mask */ +#define USB_OTG_DOEPMSK_STUPM ((uint32_t)0x00000008) +/* OUT token received when endpoint disabled mask */ +#define USB_OTG_DOEPMSK_OTEPDM ((uint32_t)0x00000010) +/* Back-to-back SETUP packets received mask */ +#define USB_OTG_DOEPMSK_B2BSTUP ((uint32_t)0x00000040) +/* OUT packet error mask */ +#define USB_OTG_DOEPMSK_OPEM ((uint32_t)0x00000100) +/* BNA interrupt mask */ +#define USB_OTG_DOEPMSK_BOIM ((uint32_t)0x00000200) + +/* USB_OTG_DIEPMSK register */ +/* Transfer completed interrupt mask */ +#define USB_OTG_DIEPMSK_XFRCM ((uint32_t)0x00000001) +/* Endpoint disabled interrupt mask */ +#define USB_OTG_DIEPMSK_EPDM ((uint32_t)0x00000002) +/* Timeout condition mask(non isochronous endpoints) */ +#define USB_OTG_DIEPMSK_TOM ((uint32_t)0x00000008) +/* IN token received when Tx FIFO empty mask */ +#define USB_OTG_DIEPMSK_ITTXFEMSK ((uint32_t)0x00000010) +/* IN token received with EP mismatch mask */ +#define USB_OTG_DIEPMSK_INEPNMM ((uint32_t)0x00000020) +/* IN endpoint NAK effective mask */ +#define USB_OTG_DIEPMSK_INEPNEM ((uint32_t)0x00000040) +/* FIFO under run mask */ +#define USB_OTG_DIEPMSK_TXFURM ((uint32_t)0x00000100) +/* BNA interrupt mask */ +#define USB_OTG_DIEPMSK_BIM ((uint32_t)0x00000200) + +typedef struct { + uint32_t dcfg;/* dev Configuration Register */ + uint32_t dctl;/* dev Control Register */ + uint32_t dsts;/* dev Status Register(RO) */ + uint32_t reserved1;/* reserved */ + uint32_t diepmsk;/* dev IN Endpoint Mask */ + uint32_t doepmsk;/* dev OUT Endpoint Mask */ + uint32_t daint;/* dev All Endpoints Itr Reg */ + uint32_t daintmsk;/* dev All Endpoints Itr Mask */ + uint32_t reserved2;/* reserved */ + uint32_t reserved3;/* reserved */ + uint32_t dvbusdis;/* dev VBUS discharge Register */ + uint32_t dvbuspulse;/* dev VBUS Pulse Register */ + uint32_t dthrctl;/* dev threshold */ + uint32_t diepempmsk;/* dev empty msk */ + uint32_t deachint;/* dedicated EP interrupt */ + uint32_t deachmsk;/* dedicated EP msk */ + uint32_t reserved4;/* dedicated EP mask */ + uint32_t dinep1msk;/* dedicated EP mask */ + uint32_t reserved5[15];/* reserved */ + uint32_t doutep1msk;/* dedicated EP msk */ +} usb_dwc2_device_t; + +typedef struct { + uint32_t epctl;/* dev IN Endpoint Control Reg */ + uint32_t reserved1;/* reserved */ + uint32_t epint;/* dev IN Endpoint Itr Reg */ + uint32_t reserved2;/* reserved*/ + uint32_t eptsiz;/* IN Endpoint Txfer Size */ + uint32_t epdma;/* IN Endpoint DMA Address Reg */ + uint32_t txfsts;/* IN Endpoint Tx FIFO Status Reg */ + uint32_t reserved3;/* reserved */ +} usb_dwc2_endpoint_t; + +typedef struct { + uint32_t gotgctl;/* USB_OTG Control and Status Register */ + uint32_t gotgint;/* USB_OTG Interrupt Register */ + uint32_t gahbcfg;/* Core AHB Configuration Register */ + uint32_t gusbcfg;/* Core USB Configuration Register */ + uint32_t grstctl;/* Core Reset Register */ + uint32_t gintsts;/* Core Interrupt Register */ + uint32_t gintmsk;/* Core Interrupt Mask Register */ + uint32_t grxstsr;/* Receive StsQ Read Register */ + uint32_t grxstsp;/* Receive StsQ Read & POP Register */ + uint32_t grxfsiz;/* Receive FIFO SizeRegister */ + uint32_t dieptxfo;/* EP0/Non Periodic Tx FIFO Size Reg */ + uint32_t hnptxsts;/* Non Periodic Tx FIFO / Queue Sts reg */ + uint32_t reserved1[2];/* reserved */ + uint32_t gccfg;/* General Purpose IO Register */ + uint32_t cid;/* User ID Register */ + uint32_t reserved2[3];/* reserved */ + uint32_t ghwcfg3;/* User HW config */ + uint32_t reserved3;/* reserved */ + uint32_t glpmcfg;/* LPM Register */ + uint32_t gpwrdn;/* Power Down Register */ + uint32_t gdfifocfg;/* DFIFO Software Config Register */ + uint32_t gadpctl;/* ADPTimer, Control and Status Register */ + uint32_t reserved4[39];/* reserved */ + uint32_t hptxfsiz;/* Host Periodic Tx FIFO Size Reg */ + uint32_t dieptxf[0x0F];/* dev Periodic Transmit FIFO */ +} usb_dwc2_global_t; + +typedef struct { + usb_dwc2_global_t *usb_global; + usb_dwc2_device_t *usb_device; + usb_dwc2_endpoint_t *usb_in_endpoint[USB_MAX_ENDPOINT_NB]; + usb_dwc2_endpoint_t *usb_out_endpoint[USB_MAX_ENDPOINT_NB]; + uint32_t *usb_fifo[USB_MAX_ENDPOINT_NB]; +} usb_dwc2_t; + +usb_status_t usb_dwc2_disable_int(void *handle); +usb_status_t usb_dwc2_ep0_out_start(void *handle); +usb_status_t usb_dwc2_ep_start_xfer(void *handle, usb_otg_ep_t *ep); +usb_status_t usb_dwc2_ep0_start_xfer(void *handle, usb_otg_ep_t *ep); +usb_status_t usb_dwc2_write_packet(void *handle, uint8_t *src, + uint8_t ch_ep_num, uint16_t len); +void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len); +usb_status_t usb_dwc2_ep_set_stall(void *handle, usb_otg_ep_t *ep); +usb_status_t usb_dwc2_stop_device(void *handle); +usb_status_t usb_dwc2_set_address(void *handle, uint8_t address); +usb_status_t usb_dwc2_dev_disconnect(void *handle); +usb_status_t usb_dwc2_write_empty_tx_fifo(void *handle, uint32_t epnum, + uint32_t xfer_len, + uint32_t *xfer_count, + uint32_t maxpacket, + uint8_t **xfer_buff); +usb_action_t usb_dwc2_it_handler(void *handle, uint32_t *param); +void usb_dwc2_init_driver(usb_handle_t *usb_core_handle, + uint32_t *base_register); + +#endif /* __USB_DWC2_H */ + diff --git a/include/lib/usb/usb_core.h b/include/lib/usb/usb_core.h new file mode 100644 index 0000000..e4dd438 --- /dev/null +++ b/include/lib/usb/usb_core.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef USB_CORE_H +#define USB_CORE_H + +#include + +#include + +#define USBD_MAX_NUM_INTERFACES 1 +#define USBD_MAX_NUM_CONFIGURATION 1 + +#define USB_LEN_DEV_QUALIFIER_DESC 0x0A +#define USB_LEN_DEV_DESC 0x12 +#define USB_LEN_CFG_DESC 0x09 +#define USB_LEN_IF_DESC 0x09 +#define USB_LEN_EP_DESC 0x07 +#define USB_LEN_OTG_DESC 0x03 +#define USB_LEN_LANGID_STR_DESC 0x04 +#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09 + +#define USBD_IDX_LANGID_STR 0x00 +#define USBD_IDX_MFC_STR 0x01 +#define USBD_IDX_PRODUCT_STR 0x02 +#define USBD_IDX_SERIAL_STR 0x03 +#define USBD_IDX_CONFIG_STR 0x04 +#define USBD_IDX_INTERFACE_STR 0x05 + +#define USB_REQ_TYPE_STANDARD 0x00 +#define USB_REQ_TYPE_CLASS 0x20 +#define USB_REQ_TYPE_VENDOR 0x40 +#define USB_REQ_TYPE_MASK 0x60 + +#define USB_REQ_RECIPIENT_DEVICE 0x00 +#define USB_REQ_RECIPIENT_INTERFACE 0x01 +#define USB_REQ_RECIPIENT_ENDPOINT 0x02 +#define USB_REQ_RECIPIENT_MASK 0x03 + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_DESC_TYPE_DEVICE 0x01 +#define USB_DESC_TYPE_CONFIGURATION 0x02 +#define USB_DESC_TYPE_STRING 0x03 +#define USB_DESC_TYPE_INTERFACE 0x04 +#define USB_DESC_TYPE_ENDPOINT 0x05 +#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06 +#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07 +#define USB_DESC_TYPE_BOS 0x0F + +#define USB_CONFIG_REMOTE_WAKEUP 2 +#define USB_CONFIG_SELF_POWERED 1 + +#define USB_FEATURE_EP_HALT 0 +#define USB_FEATURE_REMOTE_WAKEUP 1 +#define USB_FEATURE_TEST_MODE 2 + +#define USB_DEVICE_CAPABITY_TYPE 0x10 + +#define USB_HS_MAX_PACKET_SIZE 512 +#define USB_FS_MAX_PACKET_SIZE 64 +#define USB_MAX_EP0_SIZE 64 + +/* Device Status */ +#define USBD_STATE_DEFAULT 1 +#define USBD_STATE_ADDRESSED 2 +#define USBD_STATE_CONFIGURED 3 +#define USBD_STATE_SUSPENDED 4 + +/* EP0 State */ +#define USBD_EP0_IDLE 0 +#define USBD_EP0_SETUP 1 +#define USBD_EP0_DATA_IN 2 +#define USBD_EP0_DATA_OUT 3 +#define USBD_EP0_STATUS_IN 4 +#define USBD_EP0_STATUS_OUT 5 +#define USBD_EP0_STALL 6 + +#define USBD_EP_TYPE_CTRL 0 +#define USBD_EP_TYPE_ISOC 1 +#define USBD_EP_TYPE_BULK 2 +#define USBD_EP_TYPE_INTR 3 + +#define USB_OTG_SPEED_HIGH 0 +#define USB_OTG_SPEED_HIGH_IN_FULL 1 +#define USB_OTG_SPEED_LOW 2 +#define USB_OTG_SPEED_FULL 3 + +#define USB_OTG_HS_MAX_PACKET_SIZE 512 +#define USB_OTG_FS_MAX_PACKET_SIZE 64 +#define USB_OTG_MAX_EP0_SIZE 64 + +#define USB_OTG_OUT_EPNUM_MASK 0x0000FFFF +#define USB_OTG_OUT_COUNT_MASK 0xFFFF0000 + +#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \ + (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8)) + +#define LOBYTE(x) ((uint8_t)((x) & 0x00FF)) +#define HIBYTE(x) ((uint8_t)(((x) & 0xFF00) >> 8)) + +typedef struct { + uint8_t bm_request; + uint8_t b_request; + uint16_t value; + uint16_t index; + uint16_t length; +} usb_setup_req_t; + +struct usb_handle; + +typedef struct { + uint8_t (*init)(struct usb_handle *pdev, uint8_t cfgidx); + uint8_t (*de_init)(struct usb_handle *pdev, uint8_t cfgidx); + /* Control Endpoints*/ + uint8_t (*setup)(struct usb_handle *pdev, usb_setup_req_t *req); + uint8_t (*ep0_tx_sent)(struct usb_handle *pdev); + uint8_t (*ep0_rx_ready)(struct usb_handle *pdev); + /* Class Specific Endpoints*/ + uint8_t (*data_in)(struct usb_handle *pdev, uint8_t epnum); + uint8_t (*data_out)(struct usb_handle *pdev, uint8_t epnum); + uint8_t (*sof)(struct usb_handle *pdev); + uint8_t (*iso_in_incomplete)(struct usb_handle *pdev, uint8_t epnum); + uint8_t (*iso_out_incomplete)(struct usb_handle *pdev, uint8_t epnum); + uint32_t reserved; +} usb_class_t; + +/* Following USB Device status */ +typedef enum { + USBD_OK = 0, + USBD_BUSY, + USBD_FAIL, + USBD_TIMEOUT +} usb_status_t; + +/* Action to do after IT handling */ +typedef enum { + USB_NOTHING = 0, + USB_DATA_OUT, + USB_DATA_IN, + USB_SETUP, + USB_ENUM_DONE, + USB_READ_DATA_PACKET, + USB_READ_SETUP_PACKET, + USB_RESUME, + USB_SUSPEND, + USB_LPM, + USB_SOF, + USB_DISCONNECT, + USB_WRITE_EMPTY +} usb_action_t; + +/* USB Device descriptors structure */ +typedef struct { + uint8_t *(*get_device_desc)(uint16_t *length); + uint8_t *(*get_lang_id_desc)(uint16_t *length); + uint8_t *(*get_manufacturer_desc)(uint16_t *length); + uint8_t *(*get_product_desc)(uint16_t *length); + uint8_t *(*get_serial_desc)(uint16_t *length); + uint8_t *(*get_configuration_desc)(uint16_t *length); + uint8_t *(*get_interface_desc)(uint16_t *length); + uint8_t *(*get_usr_desc)(uint8_t index, uint16_t *length); + uint8_t *(*get_hs_config_desc)(uint16_t *length); + uint8_t *(*get_fs_config_desc)(uint16_t *length); + uint8_t *(*get_other_speed_config_desc)(uint16_t *length); + uint8_t *(*get_device_qualifier_desc)(uint16_t *length); + uint8_t *(*get_dfu_desc)(uint16_t *length); +} usb_desc_t; + +/* USB Device handle structure */ +typedef struct { + uint32_t status; + uint32_t total_length; + uint32_t rem_length; + uint32_t maxpacket; +} usb_endpoint_t; + +typedef struct { + uint32_t dev_endpoints; /* Device Endpoints number. + * This parameter depends on the used USB core. + * This This parameter must be a number between + * This Min_Data = 1 and Max_Data = 15 + */ + uint32_t host_channels; /* Host Channels number. + * This parameter Depends on the used USB core. + * This parameter must be a number between + * Min_Data = 1 and Max_Data = 15 + */ + uint32_t speed; /* USB Core speed. */ + uint32_t can_be_deleted; /* Enable or disable of the + * USB embedded DMA. + */ + uint32_t ep0_mps; /* Set the Endpoint 0 Max Packet size. */ + uint32_t phy_itface; /* Select the used PHY interface. */ + uint32_t sof_enable; /* Enable or disable the output of + * the SOF signal. + */ + uint32_t low_power_enable; /* Enable or disable the low power mode. */ + uint32_t lpm_enable; /* Enable or disable Link Power Management.*/ + uint32_t vbus_sensing_enable; /* Enable or disable the VBUS + * Sensing feature. + */ + uint32_t use_dedicated_ep1; /* Enable or disable the use of the + * dedicated EP1 interrupt. + */ + uint32_t use_external_vbus; /* Enable or disable the use of + * the external VBUS. + */ +} usb_otg_cfg_t; + +typedef struct { + uint8_t num;/* Endpoint number + * This parameter must be a number between Min_Data = 1 + * and Max_Data = 15 + */ + uint8_t is_in; /* Endpoint direction + * This parameter must be a number between + * Min_Data = 0 and Max_Data = 1 + */ + uint8_t is_stall; /* Endpoint stall condition + * This parameter must be a number between + * Min_Data = 0 and Max_Data = 1 + */ + uint8_t type; /* Endpoint type */ + uint8_t data_pid_start; /* Initial data PID + * This parameter must be a number between + * Min_Data = 0 and Max_Data = 1 + */ + uint8_t even_odd_frame; /* IFrame parity + * This parameter must be a number between + * Min_Data = 0 and Max_Data = 1 + */ + uint16_t tx_fifo_num; /* Transmission FIFO number + * This parameter must be a number between + * Min_Data = 1 and Max_Data = 15 + */ + uint32_t maxpacket; /* Endpoint Max packet size + * This parameter must be a number between + * Min_Data = 0 and Max_Data = 64KB + */ + uint8_t *xfer_buff; /* Pointer to transfer buffer */ + uint32_t dma_addr; /* 32 bits aligned transfer buffer address */ + uint32_t xfer_len; /* Current transfer length */ + uint32_t xfer_count; /* Partial transfer length in case of multi + * packet transfer + */ +} usb_otg_ep_t; + +typedef enum { + HAL_PCD_STATE_RESET = 0x00, + HAL_PCD_STATE_READY = 0x01, + HAL_PCD_STATE_ERROR = 0x02, + HAL_PCD_STATE_BUSY = 0x03, + HAL_PCD_STATE_TIMEOUT = 0x04 +} pcd_state_t; + +typedef enum { + LPM_L0 = 0x00, /* on */ + LPM_L1 = 0x01, /* LPM L1 sleep */ + LPM_L2 = 0x02, /* suspend */ + LPM_L3 = 0x03, /* off */ +} pcd_lpm_state_t; + +/* USB Device descriptors structure */ +typedef struct { + usb_status_t (*disable_int)(void *handle); + usb_status_t (*ep0_out_start)(void *handle); + usb_status_t (*ep_start_xfer)(void *handle, usb_otg_ep_t *ep); + usb_status_t (*ep0_start_xfer)(void *handle, usb_otg_ep_t *ep); + usb_status_t (*write_packet)(void *handle, uint8_t *src, + uint8_t ch_ep_num, uint16_t len); + void * (*read_packet)(void *handle, uint8_t *dest, uint16_t len); + usb_status_t (*ep_set_stall)(void *handle, usb_otg_ep_t *ep); + usb_status_t (*stop_device)(void *handle); + usb_status_t (*set_address)(void *handle, uint8_t address); + usb_status_t (*dev_disconnect)(void *handle); + usb_status_t (*write_empty_tx_fifo)(void *handle, + uint32_t epnum, uint32_t xfer_len, + uint32_t *xfer_count, + uint32_t maxpacket, + uint8_t **xfer_buff); + usb_action_t (*it_handler)(void *handle, uint32_t *param); +} usb_driver_t; + +typedef struct { + void *instance; /* Register base address */ + usb_otg_cfg_t init; /* PCD required parameters */ + usb_otg_ep_t in_ep[15]; /* IN endpoint parameters */ + usb_otg_ep_t out_ep[15]; /* OUT endpoint parameters */ + pcd_state_t state; /* PCD communication state */ + uint32_t setup[12]; /* Setup packet buffer */ + pcd_lpm_state_t lpm_state; /* LPM State */ + uint32_t besl; + uint32_t lpm_active; /* Enable or disable the Link Power Management. + * This parameter can be set to ENABLE or DISABLE + */ + void *p_data; /* Pointer to upper stack Handler*/ + uint32_t RESERVED[4]; /* For future use */ +} pcd_handle_t; + +/* USB Device handle structure */ +typedef struct usb_handle { + uint8_t id; + uint32_t dev_config; + uint32_t dev_default_config; + uint32_t dev_config_status; + uint32_t dev_speed; + usb_endpoint_t ep_in[15]; + usb_endpoint_t ep_out[15]; + uint32_t ep0_state; + uint32_t ep0_data_len; + uint8_t dev_state; + uint8_t dev_old_state; + uint8_t dev_address; + uint8_t dev_connection_status; + uint8_t dev_test_mode; + uint32_t dev_remote_wakeup; + usb_setup_req_t request; + const usb_desc_t *desc; + usb_class_t *class; + void *class_data; + void *user_data; + pcd_handle_t *data; + const usb_driver_t *driver; + uint32_t RESERVED[3]; +} usb_handle_t; + +usb_status_t usb_core_handle_it(usb_handle_t *pdev); +usb_status_t usb_core_receive(usb_handle_t *pdev, uint8_t ep_addr, + uint8_t *p_buf, uint32_t len); +usb_status_t usb_core_transmit(usb_handle_t *pdev, uint8_t ep_addr, + uint8_t *p_buf, uint32_t len); +void usb_core_ctl_error(usb_handle_t *pdev); +usb_status_t usb_core_stop(usb_handle_t *pdev); +usb_status_t register_usb_driver(usb_handle_t *pdev, const usb_driver_t *driver, + void *driver_handle); +usb_status_t register_platform(usb_handle_t *pdev, + const usb_desc_t *plat_call_back); + +#endif /* USB_CORE_H */ diff --git a/include/lib/usb/usb_st_dfu.h b/include/lib/usb/usb_st_dfu.h new file mode 100644 index 0000000..8a3a5a5 --- /dev/null +++ b/include/lib/usb/usb_st_dfu.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef USB_ST_DFU_H +#define USB_ST_DFU_H + +#include + +#include + +#define DFU_DESCRIPTOR_TYPE 0x21 + +/* bmAttribute : + * bitCanDnload = 1(bit 0) + * bitCanUpload = 1(bit 1) + * bitManifestationTolerant = 1 (bit 2) + * bitWillDetach = 1(bit 3) + * Reserved (bit4-6) + * bitAcceleratedST = 0(bit 7) + */ +#define DFU_BM_ATTRIBUTE 0x0F + +#define DFU_GET_PHASE 0x5 + +/* DFU Requests DFU states */ +#define APP_STATE_IDLE 0 +#define APP_STATE_DETACH 1 +#define DFU_STATE_IDLE 2 +#define DFU_STATE_DNLOAD_SYNC 3 +#define DFU_STATE_DNLOAD_BUSY 4 +#define DFU_STATE_DNLOAD_IDLE 5 +#define DFU_STATE_MANIFEST_SYNC 6 +#define DFU_STATE_MANIFEST 7 +#define DFU_STATE_MANIFEST_WAIT_RESET 8 +#define DFU_STATE_UPLOAD_IDLE 9 +#define DFU_STATE_ERROR 10 + +/* DFU errors */ +#define DFU_ERROR_NONE 0x00 +#define DFU_ERROR_TARGET 0x01 +#define DFU_ERROR_FILE 0x02 +#define DFU_ERROR_WRITE 0x03 +#define DFU_ERROR_ERASE 0x04 +#define DFU_ERROR_CHECK_ERASED 0x05 +#define DFU_ERROR_PROG 0x06 +#define DFU_ERROR_VERIFY 0x07 +#define DFU_ERROR_ADDRESS 0x08 +#define DFU_ERROR_NOTDONE 0x09 +#define DFU_ERROR_FIRMWARE 0x0A +#define DFU_ERROR_VENDOR 0x0B +#define DFU_ERROR_USB 0x0C +#define DFU_ERROR_POR 0x0D +#define DFU_ERROR_UNKNOWN 0x0E +#define DFU_ERROR_STALLEDPKT 0x0F + +/* DFU Manifestation State */ +#define DFU_MANIFEST_COMPLETE 0x00 +#define DFU_MANIFEST_IN_PROGRESS 0x01 + +/* Special Commands with Download Request */ +#define DFU_CMD_GETCOMMANDS 0x00 +#define DFU_CMD_SETADDRESSPOINTER 0x21 +#define DFU_CMD_ERASE 0x41 + +#define DFU_MEDIA_STATE_READY 0x00 +#define DFU_MEDIA_STATE_WRITTEN 0x01 +#define DFU_MEDIA_STATE_ERROR 0x02 + +/* Bit Detach capable = bit 3 in bmAttributes field */ +#define DFU_DETACH_MASK (uint8_t)(1 << 4) +#define DFU_STATUS_DEPTH (6) + +/* Undefined download address */ +#define UNDEFINE_DOWN_ADDR 0xFFFFFFFF + +typedef enum { + DFU_DETACH = 0, + DFU_DNLOAD, + DFU_UPLOAD, + DFU_GETSTATUS, + DFU_CLRSTATUS, + DFU_GETSTATE, + DFU_ABORT +} dfu_request_t; + +typedef void (*p_function)(void); + +typedef struct { + uint8_t buffer[10]; + uint8_t dev_state; + uint8_t dev_status[DFU_STATUS_DEPTH]; + uint8_t manif_state; + uint32_t wblock_num; + uint32_t wlength; + uintptr_t data_ptr; + uint32_t alt_setting; +} usb_dfu_handle_t; + +typedef struct { + uint16_t (*write_done)(uint32_t *written_in, uint32_t len); + uint8_t* (*read)(uint8_t *src, uint8_t *dest, uint32_t len); + uint16_t (*get_status)(void); +} usb_dfu_media_t; + +void usb_dfu_register_callback(usb_handle_t *pdev); +void usb_dfu_set_phase_id(uint32_t phase_id); +void usb_dfu_set_download_addr(uintptr_t addr); +uint32_t usb_dfu_download_is_completed(void); +uint32_t usb_dfu_get_current_req(void); +uint32_t usb_dfu_detach_req(void); +void usb_dfu_request_detach(void); + +#endif /* USB_ST_DFU_H */ diff --git a/lib/usb/usb_core.c b/lib/usb/usb_core.c new file mode 100644 index 0000000..fd0f204 --- /dev/null +++ b/lib/usb/usb_core.c @@ -0,0 +1,733 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include + +/* + * @brief Set a STALL condition over an endpoint + * @param hpcd: PCD handle + * @param ep_addr: endpoint address + * @retval HAL status + */ +static usb_status_t usb_core_set_stall(usb_handle_t *pdev, uint8_t ep_addr) +{ + usb_otg_ep_t *ep; + pcd_handle_t *hpcd = (pcd_handle_t *)pdev->data; + + if ((0x80 & ep_addr) == 0x80) + ep = &hpcd->in_ep[ep_addr & 0x7F]; + else + ep = &hpcd->out_ep[ep_addr]; + + ep->is_stall = 1; + ep->num = ep_addr & 0x7F; + ep->is_in = ((ep_addr & 0x80) == 0x80); + + pdev->driver->ep_set_stall(hpcd->instance, ep); + if ((ep_addr & 0x7F) == 0) + pdev->driver->ep0_out_start(hpcd->instance); + + return USBD_OK; +} + +/* + * usb_core_get_desc + * Handle Get Descriptor requests + * pdev : device instance + * req : usb request + * return : status + */ +static void usb_core_get_desc(usb_handle_t *pdev, + usb_setup_req_t *req) +{ + uint16_t len; + uint8_t *pbuf; + + switch (req->value >> 8) { + case USB_DESC_TYPE_DEVICE: + pbuf = pdev->desc->get_device_desc(&len); + break; + + case USB_DESC_TYPE_CONFIGURATION: + pbuf = (uint8_t *)pdev->desc->get_hs_config_desc(&len); + pbuf[1] = USB_DESC_TYPE_CONFIGURATION; + break; + + case USB_DESC_TYPE_STRING: + switch ((uint8_t)(req->value)) { + case USBD_IDX_LANGID_STR: + pbuf = pdev->desc->get_lang_id_desc(&len); + break; + + case USBD_IDX_MFC_STR: + pbuf = pdev->desc->get_manufacturer_desc(&len); + break; + + case USBD_IDX_PRODUCT_STR: + pbuf = pdev->desc->get_product_desc(&len); + break; + + case USBD_IDX_SERIAL_STR: + pbuf = pdev->desc->get_serial_desc(&len); + break; + + case USBD_IDX_CONFIG_STR: + pbuf = pdev->desc->get_configuration_desc(&len); + break; + + case USBD_IDX_INTERFACE_STR: + pbuf = pdev->desc->get_interface_desc(&len); + break; + + default: + pbuf = pdev->desc->get_usr_desc(req->value, &len); + break; + } + break; + + case USB_DESC_TYPE_DEVICE_QUALIFIER: + pbuf = (uint8_t *)pdev->desc->get_device_qualifier_desc(&len); + break; + + case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: + pbuf = (uint8_t *)pdev->desc->get_other_speed_config_desc(&len); + pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION; + break; + + default: + ERROR("Unknown request %i\n", req->value >> 8); + usb_core_ctl_error(pdev); + return; + } + + if ((len != 0) && (req->length != 0)) { + len = MIN(len, req->length); + + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_DATA_IN; + pdev->ep_in[0].total_length = len; + pdev->ep_in[0].rem_length = len; + /* Start the transfer */ + usb_core_transmit(pdev, 0x00, pbuf, len); + } +} + +/* + * usb_core_set_config + * Handle Set device configuration request + * pdev : device instance + * req : usb request + * return : status + */ +static void usb_core_set_config(usb_handle_t *pdev, usb_setup_req_t *req) +{ + static uint8_t cfgidx; + + cfgidx = (uint8_t)(req->value); + + if (cfgidx > USBD_MAX_NUM_CONFIGURATION) { + usb_core_ctl_error(pdev); + } else { + switch (pdev->dev_state) { + case USBD_STATE_ADDRESSED: + if (cfgidx) { + pdev->dev_config = cfgidx; + pdev->dev_state = USBD_STATE_CONFIGURED; + if (!pdev->class) { + usb_core_ctl_error(pdev); + return; + } + /* Set configuration and Start the Class*/ + if (pdev->class->init(pdev, cfgidx) != 0) { + usb_core_ctl_error(pdev); + return; + } + } + break; + + case USBD_STATE_CONFIGURED: + if (cfgidx == 0) { + pdev->dev_state = USBD_STATE_ADDRESSED; + pdev->dev_config = cfgidx; + pdev->class->de_init(pdev, cfgidx); + } else if (cfgidx != pdev->dev_config) { + if (!pdev->class) { + usb_core_ctl_error(pdev); + return; + } + /* Clear old configuration */ + pdev->class->de_init(pdev, pdev->dev_config); + + /* set new configuration */ + pdev->dev_config = cfgidx; + /* Set configuration and Start the Class*/ + if (pdev->class->init(pdev, cfgidx) != 0) { + usb_core_ctl_error(pdev); + return; + } + } + break; + + default: + usb_core_ctl_error(pdev); + return; + } + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_IN; + + /* Send status */ + usb_core_transmit(pdev, 0, NULL, 0); + } +} + +/* + * usb_core_get_status + * Handle Get Status request + * pdev : device instance + * req : usb request + * return : status + */ +static void usb_core_get_status(usb_handle_t *pdev, usb_setup_req_t *req) +{ + if ((pdev->dev_state == USBD_STATE_ADDRESSED) || + (pdev->dev_state == USBD_STATE_CONFIGURED)) { + pdev->dev_config_status = USB_CONFIG_SELF_POWERED; + + if (pdev->dev_remote_wakeup) + pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP; + + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_DATA_IN; + pdev->ep_in[0].total_length = 2; + pdev->ep_in[0].rem_length = 2; + /* Start the transfer */ + usb_core_transmit(pdev, 0x00, + (uint8_t *)&pdev->dev_config_status, 2); + return; + } + + usb_core_ctl_error(pdev); +} + +/* + * usb_core_set_address + * Set device address + * pdev : device instance + * req : usb request + * return : status + */ +static void usb_core_set_address(usb_handle_t *pdev, usb_setup_req_t *req) +{ + if ((req->index == 0) && (req->length == 0)) { + uint8_t dev_addr = (uint8_t)(req->value) & 0x7F; + + if (pdev->dev_state == USBD_STATE_CONFIGURED) { + usb_core_ctl_error(pdev); + } else { + pdev->dev_address = dev_addr; + pdev->driver->set_address(((pcd_handle_t *) + (pdev->data))->instance, + dev_addr); + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_IN; + + /* Send status */ + usb_core_transmit(pdev, 0, NULL, 0); + + if (dev_addr != 0) + pdev->dev_state = USBD_STATE_ADDRESSED; + else + pdev->dev_state = USBD_STATE_DEFAULT; + } + } else { + usb_core_ctl_error(pdev); + } +} + +/* + * usb_core_dev_req + * Handle standard usb device requests + * pdev : device instance + * req : usb request + * return : status + */ +static usb_status_t usb_core_dev_req(usb_handle_t *pdev, usb_setup_req_t *req) +{ + INFO("receive request %i\n", req->b_request); + switch (req->b_request) { + case USB_REQ_GET_DESCRIPTOR: + usb_core_get_desc(pdev, req); + break; + + case USB_REQ_SET_CONFIGURATION: + usb_core_set_config(pdev, req); + break; + + case USB_REQ_GET_STATUS: + usb_core_get_status(pdev, req); + break; + case USB_REQ_SET_ADDRESS: + usb_core_set_address(pdev, req); + break; + case USB_REQ_GET_CONFIGURATION: + case USB_REQ_SET_FEATURE: + case USB_REQ_CLEAR_FEATURE: + default: + ERROR("NOT SUPPORTED %i\n", req->b_request); + usb_core_ctl_error(pdev); + break; + } + + return USBD_OK; +} + +/* + * usb_core_itf_req + * Handle standard usb interface requests + * pdev : device instance + * req : usb request + * return : status + */ +static usb_status_t usb_core_itf_req(usb_handle_t *pdev, usb_setup_req_t *req) +{ + switch (pdev->dev_state) { + case USBD_STATE_CONFIGURED: + if (LOBYTE(req->index) <= USBD_MAX_NUM_INTERFACES) { + pdev->class->setup(pdev, req); + + if (req->length == 0) { + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_IN; + + usb_core_transmit(pdev, 0, NULL, 0); + } + } else { + usb_core_ctl_error(pdev); + } + break; + + default: + usb_core_ctl_error(pdev); + break; + } + return USBD_OK; +} + +/* + * @brief USBD_ParseSetupRequest + * Copy buffer into setup structure + * @param pdev: device instance + * @param req: usb request + * @retval None + */ +static void usb_core_parse_req(usb_setup_req_t *req, uint8_t *pdata) +{ + req->bm_request = *(uint8_t *)(pdata); + req->b_request = *(uint8_t *)(pdata + 1); + req->value = SWAPBYTE(pdata + 2); + req->index = SWAPBYTE(pdata + 4); + req->length = SWAPBYTE(pdata + 6); +} + +/* + * usb_core_setup_stage + * Handle the setup stage + * pdev: device instance + * return : status + */ +static usb_status_t usb_core_setup_stage(usb_handle_t *pdev, uint8_t *psetup) +{ + usb_core_parse_req(&pdev->request, psetup); + + pdev->ep0_state = USBD_EP0_SETUP; + pdev->ep0_data_len = pdev->request.length; + + switch (pdev->request.bm_request & 0x1F) { + case USB_REQ_RECIPIENT_DEVICE: + usb_core_dev_req(pdev, &pdev->request); + break; + + case USB_REQ_RECIPIENT_INTERFACE: + usb_core_itf_req(pdev, &pdev->request); + break; + + case USB_REQ_RECIPIENT_ENDPOINT: + default: + ERROR("receive unsupported request %i", + pdev->request.bm_request & 0x1F); + usb_core_set_stall(pdev, pdev->request.bm_request & 0x80); + return USBD_FAIL; + } + return USBD_OK; +} + +/* + * usb_core_data_out + * Handle data OUT stage + * pdev: device instance + * epnum: endpoint index + * return : status + */ +static usb_status_t usb_core_data_out(usb_handle_t *pdev, uint8_t epnum, + uint8_t *pdata) +{ + usb_endpoint_t *pep; + + if (epnum == 0) { + pep = &pdev->ep_out[0]; + if (pdev->ep0_state == USBD_EP0_DATA_OUT) { + if (pep->rem_length > pep->maxpacket) { + pep->rem_length -= pep->maxpacket; + + usb_core_receive(pdev, 0, pdata, + MIN(pep->rem_length, + pep->maxpacket)); + } else { + if (pdev->class->ep0_rx_ready && + (pdev->dev_state == USBD_STATE_CONFIGURED)) + pdev->class->ep0_rx_ready(pdev); + + pdev->ep0_state = USBD_EP0_STATUS_IN; + usb_core_transmit(pdev, 0x00, NULL, 0); + } + } + } else if (pdev->class->data_out && + (pdev->dev_state == USBD_STATE_CONFIGURED)) + pdev->class->data_out(pdev, epnum); + + return USBD_OK; +} + +/* + * usb_core_data_in + * Handle data in stage + * pdev: device instance + * epnum: endpoint index + * return : status + */ +static usb_status_t usb_core_data_in(usb_handle_t *pdev, uint8_t epnum, + uint8_t *pdata) +{ + if (epnum == 0) { + usb_endpoint_t *pep = &pdev->ep_in[0]; + + if (pdev->ep0_state == USBD_EP0_DATA_IN) { + if (pep->rem_length > pep->maxpacket) { + pep->rem_length -= pep->maxpacket; + + usb_core_transmit(pdev, 0, pdata, + pep->rem_length); + + /* Prepare endpoint for premature + * end of transfer + */ + usb_core_receive(pdev, 0, NULL, 0); + } else { + /* last packet is MPS multiple, + * so send ZLP packet + */ + if ((pep->total_length % pep->maxpacket == 0) && + (pep->total_length >= pep->maxpacket) && + (pep->total_length < pdev->ep0_data_len)) { + usb_core_transmit(pdev, 0, NULL, 0); + + pdev->ep0_data_len = 0; + + /* Prepare endpoint for premature + * end of transfer + */ + usb_core_receive(pdev, 0, NULL, 0); + } else { + if (pdev->class->ep0_tx_sent && + (pdev->dev_state == + USBD_STATE_CONFIGURED)) + pdev->class->ep0_tx_sent(pdev); + + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_STATUS_OUT; + + /* Start the transfer */ + usb_core_receive(pdev, 0, NULL, 0); + } + } + } + if (pdev->dev_test_mode == 1) { + ERROR("Not supported"); + pdev->dev_test_mode = 0; + return USBD_FAIL; + } + } else if (pdev->class->data_in && + (pdev->dev_state == USBD_STATE_CONFIGURED)) { + pdev->class->data_in(pdev, epnum); + } + return USBD_OK; +} + +/* + * usb_core_Suspend + * Handle Suspend event + * pdev : device instance + * return : status + */ + +static usb_status_t usb_core_suspend(usb_handle_t *pdev) +{ + INFO("USB Suspend mode\n"); + + pdev->dev_old_state = pdev->dev_state; + pdev->dev_state = USBD_STATE_SUSPENDED; + + return USBD_OK; +} + +/* + * usb_core_resume + * Handle Resume event + * pdev : device instance + * return : status + */ + +static usb_status_t usb_core_resume(usb_handle_t *pdev) +{ + INFO("USB Resume\n"); + pdev->dev_state = pdev->dev_old_state; + + return USBD_OK; +} + +/* + * usb_core_sof + * Handle SOF event + * pdev : device instance + * return : status + */ + +static usb_status_t usb_core_sof(usb_handle_t *pdev) +{ + if (pdev->dev_state == USBD_STATE_CONFIGURED) { + if (pdev->class->sof) + pdev->class->sof(pdev); + } + + return USBD_OK; +} + +/* + * usb_core_DevDisconnected + * Handle device disconnection event + * pdev : device instance + * return : status + */ +static usb_status_t usb_core_disconnect(usb_handle_t *pdev) +{ + /* Free Class Resources */ + pdev->dev_state = USBD_STATE_DEFAULT; + pdev->class->de_init(pdev, pdev->dev_config); + + return USBD_OK; +} + +usb_status_t usb_core_handle_it(usb_handle_t *pdev) +{ + uint32_t param = 0; + uint32_t len = 0; + usb_otg_ep_t *ep; + + switch (pdev->driver->it_handler(pdev->data->instance, ¶m)) { + case USB_DATA_OUT: + usb_core_data_out(pdev, param, + pdev->data->out_ep[param].xfer_buff); + break; + case USB_DATA_IN: + usb_core_data_in(pdev, param, + pdev->data->in_ep[param].xfer_buff); + break; + case USB_SETUP: + usb_core_setup_stage(pdev, (uint8_t *)pdev->data->setup); + break; + case USB_ENUM_DONE: + pdev->data->init.speed = USB_OTG_SPEED_HIGH; + pdev->data->init.ep0_mps = USB_OTG_HS_MAX_PACKET_SIZE; + break; + case USB_READ_DATA_PACKET: + ep = &pdev->data->out_ep[param & USB_OTG_OUT_EPNUM_MASK]; + len = (param & USB_OTG_OUT_COUNT_MASK) >> 0x10; + pdev->driver->read_packet(pdev->data->instance, + ep->xfer_buff, len); + ep->xfer_buff += len; + ep->xfer_count += len; + break; + case USB_READ_SETUP_PACKET: + ep = &pdev->data->out_ep[param & USB_OTG_OUT_EPNUM_MASK]; + len = (param & USB_OTG_OUT_COUNT_MASK) >> 0x10; + pdev->driver->read_packet(pdev->data->instance, + (uint8_t *)pdev->data->setup, 8); + ep->xfer_count += len; + break; + case USB_RESUME: + if (pdev->data->lpm_state == LPM_L1) + pdev->data->lpm_state = LPM_L0; + else + usb_core_resume(pdev); + break; + case USB_SUSPEND: + usb_core_suspend(pdev); + break; + case USB_LPM: + if (pdev->data->lpm_state == LPM_L0) { + pdev->data->lpm_state = LPM_L1; + pdev->data->besl = param; + } else { + usb_core_suspend(pdev); + } + break; + case USB_SOF: + usb_core_sof(pdev); + break; + case USB_DISCONNECT: + usb_core_disconnect(pdev); + break; + case USB_WRITE_EMPTY: + pdev->driver->write_empty_tx_fifo(pdev->data->instance, param, + pdev->data->in_ep[param].xfer_len, + (uint32_t *) + &pdev->data->in_ep[param].xfer_count, + pdev->data->in_ep[param].maxpacket, + &pdev->data->in_ep[param].xfer_buff); + break; + case USB_NOTHING: + default: + break; + } + return USBD_OK; +} + +/** + * @brief Receive an amount of data + * @param hpcd: PCD handle + * @param ep_addr: endpoint address + * @param pBuf: pointer to the reception buffer + * @param len: amount of data to be received + * @retval HAL status + */ +usb_status_t usb_core_receive(usb_handle_t *pdev, uint8_t ep_addr, + uint8_t *buf, uint32_t len) +{ + usb_otg_ep_t *ep; + pcd_handle_t *hpcd = (pcd_handle_t *)pdev->data; + + ep = &hpcd->out_ep[ep_addr & 0x7F]; + + /*setup and start the Xfer */ + ep->xfer_buff = buf; + ep->xfer_len = len; + ep->xfer_count = 0; + ep->is_in = 0; + ep->num = ep_addr & 0x7F; + + if ((ep_addr & 0x7F) == 0) + pdev->driver->ep0_start_xfer(hpcd->instance, ep); + else + pdev->driver->ep_start_xfer(hpcd->instance, ep); + + return USBD_OK; +} + +/* + * @brief Send an amount of data + * @param hpcd: PCD handle + * @param ep_addr: endpoint address + * @param pBuf: pointer to the transmission buffer + * @param len: amount of data to be sent + * @retval HAL status + */ +usb_status_t usb_core_transmit(usb_handle_t *pdev, uint8_t ep_addr, + uint8_t *buf, uint32_t len) +{ + usb_otg_ep_t *ep; + pcd_handle_t *hpcd = (pcd_handle_t *)pdev->data; + + ep = &hpcd->in_ep[ep_addr & 0x7F]; + + /*setup and start the Xfer */ + ep->xfer_buff = buf; + ep->xfer_len = len; + ep->xfer_count = 0; + ep->is_in = 1; + ep->num = ep_addr & 0x7F; + + if ((ep_addr & 0x7F) == 0) + pdev->driver->ep0_start_xfer(hpcd->instance, ep); + else + pdev->driver->ep_start_xfer(hpcd->instance, ep); + + return USBD_OK; +} + +/* + * @brief usb_core_ctl_error + * Handle USB low level Error + * @param pdev: device instance + * @param req: usb request + * @retval None + */ + +void usb_core_ctl_error(usb_handle_t *pdev) +{ + ERROR("%s : Send an ERROR\n", __func__); + usb_core_set_stall(pdev, 0x80); + usb_core_set_stall(pdev, 0); +} + +/* + * usb_core_stop + * Stop the USB Device Core. + * pdev: Device Handle + * return : USBD Status + */ +usb_status_t usb_core_stop(usb_handle_t *pdev) +{ + /* Free Class Resources */ + pdev->class->de_init(pdev, pdev->dev_config); + + /* Stop the low level driver */ + pdev->driver->disable_int(pdev->data->instance); + pdev->driver->stop_device(pdev->data->instance); + pdev->driver->dev_disconnect(pdev->data->instance); + return USBD_OK; +} + +/* + * usb_core_stop + * Stop the USB Device Core. + * pdev: Device Handle + * return : USBD Status + */ +usb_status_t register_usb_driver(usb_handle_t *pdev, const usb_driver_t *driver, + void *driver_handle) +{ + /* Free Class Resources */ + pdev->driver = driver; + pdev->data->instance = driver_handle; + return USBD_OK; +} + +/* + * usb_core_stop + * Stop the USB Device Core. + * pdev: Device Handle + * return : USBD Status + */ +usb_status_t register_platform(usb_handle_t *pdev, + const usb_desc_t *plat_call_back) +{ + /* Free Class Resources */ + pdev->desc = plat_call_back; + return USBD_OK; +} diff --git a/lib/usb/usb_st_dfu.c b/lib/usb/usb_st_dfu.c new file mode 100644 index 0000000..8a17f87 --- /dev/null +++ b/lib/usb/usb_st_dfu.c @@ -0,0 +1,865 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include + +#include +#include + +static uintptr_t usbd_dfu_download_address; +static uint32_t usbd_dfu_phase_id; +static uint32_t usbd_dfu_operation_complete; +static uint32_t usbd_dfu_current_req; +static uint32_t usbd_detach_req; + +/* + * @brief USBD_DFU_Init + * Initialize the DFU interface + * @param pdev: device instance + * @param cfgidx: Configuration index + * @retval status + */ +static uint8_t usb_dfu_init(usb_handle_t *pdev, uint8_t cfgidx) +{ + /* Nothing to do in this stage */ + return USBD_OK; +} + +/** + * @brief USBD_DFU_Init + * De-Initialize the DFU layer + * @param pdev: device instance + * @param cfgidx: Configuration index + * @retval status + */ +static uint8_t usb_dfu_de_init(usb_handle_t *pdev, uint8_t cfgidx) +{ + /* Nothing to do in this stage */ + return USBD_OK; +} + +/* + * @brief USBD_DFU_DataIn + * handle data IN Stage + * @param pdev: device instance + * @param epnum: endpoint index + * @retval status + */ +static uint8_t usb_dfu_data_in(usb_handle_t *pdev, uint8_t epnum) +{ + (void)pdev; + (void)epnum; + + return USBD_OK; +} + +/* + * @brief DFU_Leave + * Handles the sub-protocol DFU leave DFU mode request (leaves DFU mode + * and resets device to jump to user loaded code). + * @param pdev: device instance + * @retval None + */ +static void usb_dfu_leave(usb_handle_t *pdev) +{ + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + + hdfu->manif_state = DFU_MANIFEST_COMPLETE; + + if (DFU_BM_ATTRIBUTE & 0x04) { + hdfu->dev_state = DFU_STATE_MANIFEST_SYNC; + + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + } else { + hdfu->dev_state = DFU_STATE_MANIFEST_WAIT_RESET; + + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + + /* Disconnect the USB device */ + usb_core_stop(pdev); + } +} + +/* + * @brief USBD_DFU_EP0_RxReady + * handle EP0 Rx Ready event + * @param pdev: device instance + * @retval status + */ +static uint8_t usb_dfu_ep0_rx_ready(usb_handle_t *pdev) +{ + (void)pdev; + + return USBD_OK; +} + +/* + * @brief USBD_DFU_EP0_TxReady + * handle EP0 TRx Ready event + * @param pdev: device instance + * @retval status + */ +static uint8_t usb_dfu_ep0_tx_ready(usb_handle_t *pdev) +{ + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + uint16_t len, dfu_version = 0; + uint8_t *serial = pdev->desc->get_dfu_desc(&len); + + dfu_version = serial[len - 1] << 8 | serial[len - 2]; + + if (hdfu->dev_state == DFU_STATE_DNLOAD_BUSY) { + if (dfu_version == 0x011a) { + /* Decode the Special Command*/ + if (hdfu->wblock_num == 0) { + if (hdfu->buffer[0] == + DFU_CMD_SETADDRESSPOINTER && + hdfu->wlength == 5) { + hdfu->data_ptr = hdfu->buffer[1]; + hdfu->data_ptr += + hdfu->buffer[2] << 8; + hdfu->data_ptr += + hdfu->buffer[3] << 16; + hdfu->data_ptr += + hdfu->buffer[4] << 24; + } else if (hdfu->buffer[0] == + DFU_CMD_ERASE && + hdfu->wlength == 5) { + hdfu->data_ptr = hdfu->buffer[1]; + hdfu->data_ptr += + hdfu->buffer[2] << 8; + hdfu->data_ptr += + hdfu->buffer[3] << 16; + hdfu->data_ptr += + hdfu->buffer[4] << 24; + } else { + /* Reset the global length and block number */ + hdfu->wlength = 0; + hdfu->wblock_num = 0; + /* Call the error management function + * (command will be nacked) + */ + usb_core_ctl_error(pdev); + } + } + } + if ((hdfu->wblock_num > 1 && dfu_version == 0x011a) || + dfu_version != 0x011a) { + /* Perform the write operation */ + if (((usb_dfu_media_t *) + pdev->user_data)->write_done((uint32_t *) + hdfu->data_ptr, + hdfu->wlength) + != USBD_OK) + return USBD_FAIL; + } + + /* Reset the global length and block number */ + hdfu->wlength = 0; + hdfu->wblock_num = 0; + + /* Update the state machine */ + hdfu->dev_state = DFU_STATE_DNLOAD_SYNC; + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + return USBD_OK; + } else if (hdfu->dev_state == DFU_STATE_MANIFEST) { + /* Manifestation in progress*/ + /* Start leaving DFU mode */ + usb_dfu_leave(pdev); + } + + return USBD_OK; +} + +/* + * @brief USBD_DFU_SOF + * handle SOF event + * @param pdev: device instance + * @retval status + */ +static uint8_t usb_dfu_sof(usb_handle_t *pdev) +{ + (void)pdev; + + return USBD_OK; +} + +/* + * @brief USBD_DFU_IsoINIncomplete + * handle data ISO IN Incomplete event + * @param pdev: device instance + * @param epnum: endpoint index + * @retval status + */ +static uint8_t usb_dfu_iso_in_incomplete(usb_handle_t *pdev, uint8_t epnum) +{ + (void)pdev; + (void)epnum; + return USBD_OK; +} + +/* + * @brief USBD_DFU_IsoOutIncomplete + * handle data ISO OUT Incomplete event + * @param pdev: device instance + * @param epnum: endpoint index + * @retval status + */ +static uint8_t usb_dfu_iso_out_incomplete(usb_handle_t *pdev, uint8_t epnum) +{ + (void)pdev; + (void)epnum; + return USBD_OK; +} + +/* + * @brief USBD_DFU_DataOut + * handle data OUT Stage + * @param pdev: device instance + * @param epnum: endpoint index + * @retval status + */ +static uint8_t usb_dfu_data_out(usb_handle_t *pdev, uint8_t epnum) +{ + (void)pdev; + (void)epnum; + return USBD_OK; +} + +/* + * @brief DFU_Detach + * Handles the DFU DETACH request. + * @param pdev: device instance + * @param req: pointer to the request structure. + * @retval None. + */ +static void usb_dfu_detach(usb_handle_t *pdev, usb_setup_req_t *req) +{ + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + + INFO("Receive Detach\n"); + + if (hdfu->dev_state == DFU_STATE_IDLE || + hdfu->dev_state == DFU_STATE_DNLOAD_SYNC || + hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || + hdfu->dev_state == DFU_STATE_MANIFEST_SYNC || + hdfu->dev_state == DFU_STATE_UPLOAD_IDLE) { + /* Update the state machine */ + hdfu->dev_state = DFU_STATE_IDLE; + hdfu->dev_status[0] = DFU_ERROR_NONE; + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/ + hdfu->dev_status[4] = hdfu->dev_state; + hdfu->dev_status[5] = 0; /*iString*/ + hdfu->wblock_num = 0; + } + hdfu->wlength = 0; + + usbd_detach_req = 0; +} + +/* + * @brief DFU_Download + * Handles the DFU DNLOAD request. + * @param pdev: device instance + * @param req: pointer to the request structure + * @retval None + */ +static void usb_dfu_download(usb_handle_t *pdev, usb_setup_req_t *req) +{ + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + + /* Data setup request */ + if (req->length > 0) { + if ((hdfu->dev_state == DFU_STATE_IDLE) || + (hdfu->dev_state == DFU_STATE_DNLOAD_IDLE)) { + /* Update the global length and block number */ + hdfu->wblock_num = req->value; + hdfu->wlength = req->length; + + /* Update the data address */ + hdfu->data_ptr = usbd_dfu_download_address; + + /* Update the state machine */ + hdfu->dev_state = DFU_STATE_DNLOAD_SYNC; + hdfu->dev_status[4] = hdfu->dev_state; + + /* Prepare the reception of the buffer over EP0 */ + /* Set EP0 State */ + pdev->ep0_state = USBD_EP0_DATA_OUT; + pdev->ep_out[0].total_length = hdfu->wlength; + pdev->ep_out[0].rem_length = hdfu->wlength; + + /* Start the transfer */ + usb_core_receive(pdev, + 0, + (uint8_t *)usbd_dfu_download_address, + hdfu->wlength); + + usbd_dfu_download_address += hdfu->wlength; + } else { + /* Unsupported state */ + /* Call the error management function + * (command will be nacked) + */ + usb_core_ctl_error(pdev); + } + } else { + /* End of DNLOAD operation*/ + if (hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || + hdfu->dev_state == DFU_STATE_IDLE) { + hdfu->manif_state = DFU_MANIFEST_IN_PROGRESS; + hdfu->dev_state = DFU_STATE_MANIFEST_SYNC; + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + } else { + /* Call the error management function + * (command will be nacked) + */ + usb_core_ctl_error(pdev); + } + } +} + +/* + * @brief DFU_Upload + * Handles the DFU UPLOAD request. + * @param pdev: instance + * @param req: pointer to the request structure + * @retval status + */ +static void usb_dfu_upload(usb_handle_t *pdev, usb_setup_req_t *req) +{ + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + + /* Data setup request */ + if (req->length > 0) { + if ((hdfu->dev_state == DFU_STATE_IDLE) || + (hdfu->dev_state == DFU_STATE_UPLOAD_IDLE)) { + /* Update the global length and block number */ + hdfu->wblock_num = req->value; + hdfu->wlength = req->length; + + /* DFU GetPhase Command */ + if (hdfu->wblock_num == 0) { + /* Update the state machine */ + hdfu->dev_state = (hdfu->wlength > 3) ? + DFU_STATE_IDLE : + DFU_STATE_UPLOAD_IDLE; + + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + + INFO("UPLOAD :\n"); + INFO("\t\tPhase ID : %i\n", usbd_dfu_phase_id); + INFO("\t\taddress 0x%lx\n", + usbd_dfu_download_address); + + hdfu->buffer[0] = usbd_dfu_phase_id; + hdfu->buffer[1] = (uint8_t) + (usbd_dfu_download_address); + hdfu->buffer[2] = (uint8_t) + (usbd_dfu_download_address >> + 8); + hdfu->buffer[3] = (uint8_t) + (usbd_dfu_download_address >> + 16); + hdfu->buffer[4] = (uint8_t) + (usbd_dfu_download_address >> + 24); + + hdfu->buffer[5] = 0x00; + hdfu->buffer[6] = 0x00; + hdfu->buffer[7] = 0x00; + hdfu->buffer[8] = 0x00; + + if ((usbd_dfu_download_address == + UNDEFINE_DOWN_ADDR) && + (usbd_detach_req)) { + INFO("Send detach request\n"); + hdfu->buffer[9] = 0x01; + pdev->ep_in[0].total_length = 10; + pdev->ep_in[0].rem_length = 10; + } else { + pdev->ep_in[0].total_length = 9; + pdev->ep_in[0].rem_length = 9; + } + + /* Send the status data over EP0 */ + pdev->ep0_state = USBD_EP0_DATA_IN; + /* Start the transfer */ + usb_core_transmit(pdev, 0x00, + (uint8_t *)&hdfu->buffer[0], + pdev->ep_in[0].total_length); + } else { + /* unsupported hdfu->wblock_num */ + ERROR("UPLOAD : Unsupported block : %i\n", + hdfu->wblock_num); + + hdfu->dev_state = DFU_ERROR_STALLEDPKT; + + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + + /* Call the error management function + * (command will be nacked + */ + usb_core_ctl_error(pdev); + } + } else { + /* Unsupported state */ + ERROR("UPLOAD : Unsupported State\n"); + + hdfu->wlength = 0; + hdfu->wblock_num = 0; + /* Call the error management function + * (command will be nacked + */ + usb_core_ctl_error(pdev); + } + } else { + /* No Data setup request */ + INFO("USB : DFU : Nothing to do\n"); + hdfu->dev_state = DFU_STATE_IDLE; + + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + } +} + +/* + * @brief DFU_GetStatus + * Handles the DFU GETSTATUS request. + * @param pdev: instance + * @retval status + */ +static void usb_dfu_get_status(usb_handle_t *pdev) +{ + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + uint16_t status; + uint8_t dfu_bm_attribute = DFU_BM_ATTRIBUTE; + + switch (hdfu->dev_state) { + case DFU_STATE_DNLOAD_SYNC: + status = ((usb_dfu_media_t *)pdev->user_data)->get_status(); + + switch (status) { + case DFU_MEDIA_STATE_WRITTEN: + /* SRAM block writing is finished, checks if checksum + * error has been detected + */ + hdfu->dev_state = DFU_STATE_DNLOAD_IDLE; + break; + + case DFU_MEDIA_STATE_ERROR: + hdfu->dev_state = DFU_STATE_ERROR; + break; + + case DFU_MEDIA_STATE_READY: + default: + /* SRAM is ready to be written */ + hdfu->dev_state = DFU_STATE_DNLOAD_BUSY; + break; + } + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + break; + + case DFU_STATE_MANIFEST_SYNC: + if (hdfu->manif_state == DFU_MANIFEST_IN_PROGRESS) { + hdfu->dev_state = DFU_STATE_MANIFEST; + + hdfu->dev_status[1] = 1;/*bwPollTimeout = 1ms*/ + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + } else if ((hdfu->manif_state == DFU_MANIFEST_COMPLETE) && + (dfu_bm_attribute & 0x04)) { + INFO("USB : DFU : end of download partition : %i\n", + hdfu->alt_setting); + hdfu->dev_state = DFU_STATE_IDLE; + usbd_dfu_operation_complete = 1; + + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; + hdfu->dev_status[4] = hdfu->dev_state; + } + break; + + default: + break; + } + + /* Send the status data over EP0 */ + pdev->ep0_state = USBD_EP0_DATA_IN; + pdev->ep_in[0].total_length = 6; + pdev->ep_in[0].rem_length = 6; + /* Start the transfer */ + usb_core_transmit(pdev, 0x00, (uint8_t *)&hdfu->dev_status[0], 6); +} + +/* + * @brief DFU_ClearStatus + * Handles the DFU CLRSTATUS request. + * @param pdev: device instance + * @retval status + */ +static void usb_dfu_clear_status(usb_handle_t *pdev) +{ + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + + if (hdfu->dev_state == DFU_STATE_ERROR) { + hdfu->dev_state = DFU_STATE_IDLE; + hdfu->dev_status[0] = DFU_ERROR_NONE;/*bStatus*/ + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/ + hdfu->dev_status[4] = hdfu->dev_state;/*bState*/ + hdfu->dev_status[5] = 0;/*iString*/ + } else { + /*State Error*/ + hdfu->dev_state = DFU_STATE_ERROR; + hdfu->dev_status[0] = DFU_ERROR_UNKNOWN;/*bStatus*/ + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/ + hdfu->dev_status[4] = hdfu->dev_state;/*bState*/ + hdfu->dev_status[5] = 0;/*iString*/ + } +} + +/* + * @brief DFU_GetState + * Handles the DFU GETSTATE request. + * @param pdev: device instance + * @retval None + */ +static void usb_dfu_get_state(usb_handle_t *pdev) +{ + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + + /* Return the current state of the DFU interface */ + /* Send the status data over EP0 */ + pdev->ep0_state = USBD_EP0_DATA_IN; + pdev->ep_in[0].total_length = 1; + pdev->ep_in[0].rem_length = 1; + + /* Start the transfer */ + usb_core_transmit(pdev, 0x00, &hdfu->dev_state, 1); +} + +/* + * @brief DFU_Abort + * Handles the DFU ABORT request. + * @param pdev: device instance + * @retval None + */ +static void usb_dfu_abort(usb_handle_t *pdev) +{ + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + + if (hdfu->dev_state == DFU_STATE_IDLE || + hdfu->dev_state == DFU_STATE_DNLOAD_SYNC || + hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || + hdfu->dev_state == DFU_STATE_MANIFEST_SYNC || + hdfu->dev_state == DFU_STATE_UPLOAD_IDLE) { + hdfu->dev_state = DFU_STATE_IDLE; + hdfu->dev_status[0] = DFU_ERROR_NONE; + hdfu->dev_status[1] = 0; + hdfu->dev_status[2] = 0; + hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/ + hdfu->dev_status[4] = hdfu->dev_state; + hdfu->dev_status[5] = 0; /*iString*/ + hdfu->wblock_num = 0; + hdfu->wlength = 0; + } +} + +/* + * @brief USBD_DFU_Setup + * Handle the DFU specific requests + * @param pdev: instance + * @param req: usb requests + * @retval status + */ +static uint8_t usb_dfu_setup(usb_handle_t *pdev, usb_setup_req_t *req) +{ + uint8_t *pbuf = NULL; + uint16_t len = 0; + uint8_t ret = USBD_OK; + usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; + + VERBOSE("alt_setting %i, bmRequest : 0x%x, brequest : 0x%x\n", + hdfu->alt_setting, req->bm_request & USB_REQ_TYPE_MASK, + req->b_request); + switch (req->bm_request & USB_REQ_TYPE_MASK) { + case USB_REQ_TYPE_CLASS: + usbd_dfu_current_req = req->b_request; + if (hdfu->alt_setting == usbd_dfu_phase_id) { + switch (req->b_request) { + case DFU_DNLOAD: + usb_dfu_download(pdev, req); + break; + + case DFU_UPLOAD: + usb_dfu_upload(pdev, req); + break; + + case DFU_GETSTATUS: + usb_dfu_get_status(pdev); + break; + + case DFU_CLRSTATUS: + usb_dfu_clear_status(pdev); + break; + + case DFU_GETSTATE: + usb_dfu_get_state(pdev); + break; + + case DFU_ABORT: + usb_dfu_abort(pdev); + break; + + case DFU_DETACH: + usb_dfu_detach(pdev, req); + break; + + default: + ERROR("phase ID :%i\n", usbd_dfu_phase_id); + usb_core_ctl_error(pdev); + ret = USBD_FAIL; + break; + } + } else if (hdfu->alt_setting == DFU_GET_PHASE) { + switch (req->b_request) { + case DFU_UPLOAD: + usb_dfu_upload(pdev, req); + break; + + case DFU_GETSTATUS: + INFO("GETSTATUS :\n"); + usb_dfu_get_status(pdev); + + switch (hdfu->dev_state) { + case APP_STATE_IDLE: + INFO("\t\tAPP_STATE_IDLE\n"); + break; + case APP_STATE_DETACH: + INFO("\t\tAPP_STATE_DETACH\n"); + break; + case DFU_STATE_IDLE: + INFO("\t\tDFU_STATE_IDLE\n"); + break; + case DFU_STATE_DNLOAD_SYNC: + INFO("\t\tDFU_STATE_DNLOAD_SYNC\n"); + break; + case DFU_STATE_DNLOAD_BUSY: + INFO("\t\tDFU_STATE_DNLOAD_BUSY\n"); + break; + case DFU_STATE_DNLOAD_IDLE: + INFO("\t\tDFU_STATE_DNLOAD_IDLE\n"); + break; + case DFU_STATE_MANIFEST_SYNC: + INFO("\t\tDFU_STATE_MANIFEST_SYNC\n"); + break; + case DFU_STATE_MANIFEST: + INFO("\t\tDFU_STATE_MANIFEST\n"); + break; + case DFU_STATE_MANIFEST_WAIT_RESET: + INFO("\t\tDFU_STATE_MANIFEST_WAIT_RESET\n"); + break; + case DFU_STATE_UPLOAD_IDLE: + INFO("\t\tDFU_STATE_UPLOAD_IDLE\n"); + break; + case DFU_STATE_ERROR: + ERROR("\t\tDFU_STATE_ERROR\n"); + break; + default: + break; + } + break; + + case DFU_CLRSTATUS: + INFO("Receive DFU clear status\n"); + usb_dfu_clear_status(pdev); + break; + + case DFU_GETSTATE: + INFO("GETSTATE :\n"); + usb_dfu_get_state(pdev); + + switch (hdfu->dev_state) { + case APP_STATE_IDLE: + INFO("\t\tAPP_STATE_IDLE\n"); + break; + case APP_STATE_DETACH: + INFO("\t\tAPP_STATE_DETACH\n"); + break; + case DFU_STATE_IDLE: + INFO("\t\tDFU_STATE_IDLE\n"); + break; + case DFU_STATE_DNLOAD_SYNC: + INFO("\t\tDFU_STATE_DNLOAD_SYNC\n"); + break; + case DFU_STATE_DNLOAD_BUSY: + INFO("\t\tDFU_STATE_DNLOAD_BUSY\n"); + break; + case DFU_STATE_DNLOAD_IDLE: + INFO("\t\tDFU_STATE_DNLOAD_IDLE\n"); + break; + case DFU_STATE_MANIFEST_SYNC: + INFO("\t\tDFU_STATE_MANIFEST_SYNC\n"); + break; + case DFU_STATE_MANIFEST: + INFO("\t\tDFU_STATE_MANIFEST\n"); + break; + case DFU_STATE_MANIFEST_WAIT_RESET: + INFO("\t\tDFU_STATE_MANIFEST_WAIT_RESET\n"); + break; + case DFU_STATE_UPLOAD_IDLE: + INFO("\t\tDFU_STATE_UPLOAD_IDLE\n"); + break; + case DFU_STATE_ERROR: + ERROR("\t\tDFU_STATE_ERROR\n"); + break; + default: + break; + } + break; + + case DFU_ABORT: + INFO("Receive DFU abort\n"); + usb_dfu_abort(pdev); + break; + + case DFU_DETACH: + INFO("Receive DFU detach\n"); + break; + + default: + ERROR("phase ID :%i\n", DFU_GET_PHASE); + usb_core_ctl_error(pdev); + ret = USBD_FAIL; + break; + } + } else { + ERROR("Unknown alternate : %i\n", hdfu->alt_setting); + ret = USBD_FAIL; + } + break; + case USB_REQ_TYPE_STANDARD: + switch (req->b_request) { + case USB_REQ_GET_DESCRIPTOR: + if ((req->value >> 8) == DFU_DESCRIPTOR_TYPE) { + pbuf = pdev->desc->get_dfu_desc(&len); + len = MIN(len, req->length); + } + + pdev->ep0_state = USBD_EP0_DATA_IN; + pdev->ep_in[0].total_length = len; + pdev->ep_in[0].rem_length = len; + /* Start the transfer */ + usb_core_transmit(pdev, 0x00, pbuf, len); + + break; + + case USB_REQ_GET_INTERFACE: + pdev->ep0_state = USBD_EP0_DATA_IN; + pdev->ep_in[0].total_length = 1; + pdev->ep_in[0].rem_length = 1; + /* Start the transfer */ + usb_core_transmit(pdev, 0x00, + (uint8_t *)&hdfu->alt_setting, 1); + break; + + case USB_REQ_SET_INTERFACE: + hdfu->alt_setting = (uint8_t)(req->value); + break; + + default: + usb_core_ctl_error(pdev); + ret = USBD_FAIL; + break; + } + default: + break; + } + + return ret; +} + +static const usb_class_t USBD_DFU_initvalue = { + usb_dfu_init, + usb_dfu_de_init, + usb_dfu_setup, + usb_dfu_ep0_tx_ready, + usb_dfu_ep0_rx_ready, + usb_dfu_data_in, + usb_dfu_data_out, + usb_dfu_sof, + usb_dfu_iso_in_incomplete, + usb_dfu_iso_out_incomplete, + 0 +}; + +void usb_dfu_register_callback(usb_handle_t *pdev) +{ + pdev->class = (usb_class_t *)&USBD_DFU_initvalue; +} + +void usb_dfu_set_phase_id(uint32_t phase_id) +{ + usbd_dfu_phase_id = phase_id; + usbd_dfu_operation_complete = 0; +} + +void usb_dfu_set_download_addr(uintptr_t addr) +{ + usbd_dfu_download_address = addr; +} + +uint32_t usb_dfu_download_is_completed(void) +{ + return usbd_dfu_operation_complete; +} + +uint32_t usb_dfu_get_current_req(void) +{ + return usbd_dfu_current_req; +} + +uint32_t usb_dfu_detach_req(void) +{ + return usbd_detach_req; +} + +void usb_dfu_request_detach(void) +{ + usbd_detach_req = 1; +} diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c index 3ec7d40..e04c325 100644 --- a/plat/st/common/bl2_io_storage.c +++ b/plat/st/common/bl2_io_storage.c @@ -30,6 +30,14 @@ #include #include +#if STM32MP_USB_PROGRAMMER +#include +#include +#include +#include +#include +#endif + /* IO devices */ static const io_dev_connector_t *dummy_dev_con; static uintptr_t dummy_dev_handle; @@ -95,6 +103,13 @@ static const io_dev_connector_t *spi_dev_con; #endif +#if STM32MP_USB_PROGRAMMER +static usb_handle_t usb_core_handle; +static usb_dfu_handle_t usb_dfu_handle; +static pcd_handle_t pcd_handle; +static const io_dev_connector_t *usb_dev_con; +#endif /* STM32MP_USB_PROGRAMMER */ + #ifdef AARCH32_SP_OPTEE static const struct stm32image_part_info optee_header_partition_spec = { .name = OPTEE_HEADER_IMAGE_NAME, @@ -257,6 +272,9 @@ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI: INFO("Using SPI NAND\n"); break; + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: + INFO("Using USB\n"); + break; default: ERROR("Boot interface not found\n"); panic(); @@ -520,6 +538,54 @@ } #endif /* STM32MP_SPI_NAND */ +#if STM32MP_USB_PROGRAMMER +static void flash_usb(struct usb_ctx *usb_context) +{ + int io_result __unused; + + pcd_handle.in_ep[0].maxpacket = 0x40; + pcd_handle.out_ep[0].maxpacket = 0x40; + + pcd_handle.state = HAL_PCD_STATE_READY; + + usb_core_handle.data = &pcd_handle; + + usb_dwc2_init_driver(&usb_core_handle, + (uint32_t *)USB_OTG_BASE); + + usb_dfu_register_callback(&usb_core_handle); + + stm32mp_usb_init_desc(&usb_core_handle); + + usb_core_handle.ep_in[0].maxpacket = 0x40; + usb_core_handle.ep_out[0].maxpacket = 0x40; + + usb_core_handle.ep0_state = + usb_context->pusbd_device_ctx->ep0_state; + usb_core_handle.dev_state = USBD_STATE_CONFIGURED; + + usb_core_handle.class_data = &usb_dfu_handle; + + usb_dfu_handle.dev_state = DFU_STATE_IDLE; + usb_dfu_handle.dev_status[1] = 0; + usb_dfu_handle.dev_status[2] = 0; + usb_dfu_handle.dev_status[3] = 0; + usb_dfu_handle.dev_status[4] = usb_dfu_handle.dev_state; + usb_dfu_handle.dev_status[5] = 0; + + /* Register the IO devices on this platform */ + io_result = register_io_dev_usb(&usb_dev_con); + assert(io_result == 0); + + /* Open connections to devices */ + io_result = io_dev_open(usb_dev_con, + (uintptr_t)&usb_core_handle, + &image_dev_handle); + + assert(io_result == 0); +} +#endif + void stm32mp_io_setup(void) { int io_result __unused; @@ -572,6 +638,12 @@ boot_spi_nand(boot_context); break; #endif +#if STM32MP_USB_PROGRAMMER + case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: + dmbsy(); + flash_usb((struct usb_ctx *)boot_context->usb_context); + break; +#endif default: ERROR("Boot interface %d not supported\n", diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c index e09ce63..9002638 100644 --- a/plat/st/stm32mp1/bl2_plat_setup.c +++ b/plat/st/stm32mp1/bl2_plat_setup.c @@ -34,6 +34,7 @@ #define RESET_TIMEOUT_US_1MS 1000U static console_t console; +static enum boot_device_e boot_device = BOOT_DEVICE_BOARD; static struct stm32mp_auth_ops stm32mp1_auth_ops; static void print_reset_reason(void) @@ -121,6 +122,11 @@ ERROR(" Unidentified reset reason\n"); } +enum boot_device_e get_boot_device(void) +{ + return boot_device; +} + void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1 __unused, u_register_t arg2 __unused, @@ -240,6 +246,13 @@ generic_delay_timer_init(); +#if STM32MP_USB_PROGRAMMER + if (boot_context->boot_interface_selected == + BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) { + boot_device = BOOT_DEVICE_USB; + } +#endif + if (stm32mp1_clk_probe() < 0) { panic(); } diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h index c16639a..8175fb2 100644 --- a/plat/st/stm32mp1/include/boot_api.h +++ b/plat/st/stm32mp1/include/boot_api.h @@ -39,6 +39,9 @@ /* Boot occurred on QSPI NOR */ #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI 0x4U +/* Boot occurred on USB */ +#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB 0x6U + /* Boot occurred on QSPI NAND */ #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI 0x7U @@ -151,7 +154,8 @@ */ uint16_t boot_interface_selected; uint16_t boot_interface_instance; - uint32_t reserved1[13]; + uint32_t reserved1[12]; + uint32_t usb_context; uint32_t otp_afmux_values[3]; uint32_t reserved[5]; uint32_t auth_status; diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h index 7076a71..0a90eca 100644 --- a/plat/st/stm32mp1/include/platform_def.h +++ b/plat/st/stm32mp1/include/platform_def.h @@ -78,6 +78,10 @@ ******************************************************************************/ #define BL33_BASE STM32MP_BL33_BASE +/* need by flash programmer */ +#define FLASHLAYOUT_BASE STM32MP_DDR_BASE +#define FLASHLAYOUT_LIMIT STM32MP_BL33_BASE + /* * Load address of BL33 for this platform port */ diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h index b6cb91e..c76240d 100644 --- a/plat/st/stm32mp1/include/stm32mp1_private.h +++ b/plat/st/stm32mp1/include/stm32mp1_private.h @@ -9,11 +9,18 @@ #include +enum boot_device_e { + BOOT_DEVICE_USB, + BOOT_DEVICE_BOARD +}; + void configure_mmu(void); void stm32mp1_arch_security_setup(void); void stm32mp1_security_setup(void); +enum boot_device_e get_boot_device(void); + void stm32mp1_gic_pcpu_init(void); void stm32mp1_gic_init(void); diff --git a/plat/st/stm32mp1/include/stm32mp1_usb_desc.h b/plat/st/stm32mp1/include/stm32mp1_usb_desc.h new file mode 100644 index 0000000..cb514b2 --- /dev/null +++ b/plat/st/stm32mp1/include/stm32mp1_usb_desc.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP1_USB_DESC_H +#define STM32MP1_USB_DESC_H + +#include + +/* Max DFU Packet Size = 1024 bytes */ +#define USBD_DFU_XFER_SIZE 1024 + +#define TRANSFER_SIZE_BYTES(size) \ + ((uint8_t)((size) & 0xFF)), /* XFERSIZEB0 */\ + ((uint8_t)((size) >> 8)) /* XFERSIZEB1 */ + +/* Descriptor of DFU interface 0 Alternate setting n */ +#define USBD_DFU_IF_DESC(n) 0x09, /* Interface Descriptor size */\ + USB_DESC_TYPE_INTERFACE, /* descriptor type */\ + 0x00, /* Number of Interface */\ + (n), /* Alternate setting */\ + 0x00, /* bNumEndpoints*/\ + 0xFE, /* Application Specific Class Code */\ + 0x01, /* Device Firmware Upgrade Code */\ + 0x02, /* DFU mode protocol */ \ + USBD_IDX_INTERFACE_STR + (n) + 1 /* iInterface: + * Index of + * string + * descriptor + */ +/* DFU1.1 Standard only supported */ +#define USB_DFU_VERSION 0x0110 +#define USBD_DESC_MAX_ITF_NUM 0x6 +#define USB_DFU_CONFIG_DESC_SIZ 72 +#define USB_DFU_DESC_SIZ 9 +/* String size (1 byte) + type (1 byte) + 24 UTF16 characters */ +/* (2 bytes per character) */ +#define USB_SIZ_STRING_SERIAL (1 + 1 + (24 * 2)) +#define USBD_MAX_STR_DESC_SIZ 0x100 +#define USBD_VID 0x0483 +#define USBD_PID 0xDF11 +#define USBD_LANGID_STRING 0x409 +#define USBD_MANUFACTURER_STRING "STMicroelectronics" +#define USBD_PRODUCT_HS_STRING "DFU in HS Mode @Device ID /0x500, @Revision ID /0x0000" +#define USBD_PRODUCT_FS_STRING "DFU in FS Mode @Device ID /0x500, @Revision ID /0x0000" +#define USBD_CONFIGURATION_HS_STRING "DFU Config" +#define USBD_INTERFACE_HS_STRING "DFU Interface" +#define USBD_CONFIGURATION_FS_STRING "DFU Config" +#define USBD_INTERFACE_FS_STRING "DFU Interface" + +void stm32mp_usb_init_desc(usb_handle_t *pdev); + +#endif /* STM32MP1_USB_DESC_H */ diff --git a/plat/st/stm32mp1/include/usb_ctx.h b/plat/st/stm32mp1/include/usb_ctx.h new file mode 100644 index 0000000..95ffa4d --- /dev/null +++ b/plat/st/stm32mp1/include/usb_ctx.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef USB_CTX_H +#define USB_CTX_H + +#include + +struct usb_ctx { + usb_handle_t *pusbd_device_ctx; + pcd_handle_t *phpcd_ctx; +}; + +#endif /* USB_CTX_H */ diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk index 3595819..fbc74b4 100644 --- a/plat/st/stm32mp1/platform.mk +++ b/plat/st/stm32mp1/platform.mk @@ -41,8 +41,11 @@ STM32MP_SPI_NAND ?= 0 STM32MP_SPI_NOR ?= 0 +# Serial boot devices +STM32MP_USB_PROGRAMMER ?= 0 + ifeq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC} ${STM32MP_RAW_NAND} \ - ${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),) + ${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR} ${STM32MP_USB_PROGRAMMER}),) $(error "No boot device driver is enabled") endif @@ -75,6 +78,7 @@ STM32MP_RAW_NAND \ STM32MP_SPI_NAND \ STM32MP_SPI_NOR \ + STM32MP_USB_PROGRAMMER \ PLAT_XLAT_TABLES_DYNAMIC \ ))) @@ -91,6 +95,7 @@ STM32MP_RAW_NAND \ STM32MP_SPI_NAND \ STM32MP_SPI_NOR \ + STM32MP_USB_PROGRAMMER \ PLAT_XLAT_TABLES_DYNAMIC \ STM32_TF_A_COPIES \ PLAT_PARTITION_MAX_ENTRIES \ @@ -189,6 +194,14 @@ plat/st/stm32mp1/plat_bl2_mem_params_desc.c \ plat/st/stm32mp1/plat_image_load.c +ifeq (${STM32MP_USB_PROGRAMMER},1) +BL2_SOURCES += drivers/st/io/io_programmer_st_usb.c \ + drivers/st/usb_dwc2/usb_dwc2.c \ + lib/usb/usb_core.c \ + lib/usb/usb_st_dfu.c \ + plat/st/stm32mp1/stm32mp1_usb_desc.c +endif + ifeq ($(AARCH32_SP),optee) BL2_SOURCES += lib/optee/optee_utils.c endif diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h index ee04a23..0a80d3a 100644 --- a/plat/st/stm32mp1/stm32mp1_def.h +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include #endif /******************************************************************************* @@ -64,6 +66,10 @@ #define STM32MP_SYSRAM_BASE U(0x2FFC0000) #define STM32MP_SYSRAM_SIZE U(0x00040000) +/* 384 KB (128 x 3) Non secure from MCU available for TF*/ +#define STM32MP_SRAM_MCU_BASE U(0x30000000) +#define STM32MP_SRAM_MCU_SIZE U(0x00060000) + #define STM32MP_NS_SYSRAM_SIZE PAGE_SIZE #define STM32MP_NS_SYSRAM_BASE (STM32MP_SYSRAM_BASE + \ STM32MP_SYSRAM_SIZE - \ @@ -153,7 +159,11 @@ * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup */ #if defined(IMAGE_BL2) + #if STM32MP_USB_PROGRAMMER + #define MAX_MMAP_REGIONS 12 + #else #define MAX_MMAP_REGIONS 11 + #endif #endif #if defined(IMAGE_BL32) #define MAX_MMAP_REGIONS 6 @@ -408,6 +418,9 @@ #define DATA0_OTP U(0) #define PART_NUMBER_OTP U(1) #define NAND_OTP U(9) +#define UID0_OTP U(13) +#define UID1_OTP U(14) +#define UID2_OTP U(15) #define PACKAGE_OTP U(16) #define HW2_OTP U(18) @@ -484,6 +497,11 @@ #endif /******************************************************************************* + * STM32MP1 USB + ******************************************************************************/ +#define USB_OTG_BASE U(0x49000000) + +/******************************************************************************* * STM32MP1 DDRCTRL ******************************************************************************/ #define DDRCTRL_BASE U(0x5A003000) diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c index bc77ee3..31cb895 100644 --- a/plat/st/stm32mp1/stm32mp1_private.c +++ b/plat/st/stm32mp1/stm32mp1_private.c @@ -58,6 +58,13 @@ MT_EXECUTE_NEVER) #endif +#define MAP_SRAM_MCU MAP_REGION_FLAT(STM32MP_SRAM_MCU_BASE, \ + STM32MP_SRAM_MCU_SIZE, \ + MT_DEVICE | \ + MT_RW | \ + MT_NS | \ + MT_EXECUTE_NEVER) + #define MAP_DEVICE1 MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \ STM32MP1_DEVICE1_SIZE, \ MT_DEVICE | \ @@ -75,6 +82,9 @@ #if defined(IMAGE_BL2) static const mmap_region_t stm32mp1_mmap[] = { MAP_SEC_SYSRAM, +#if STM32MP_USB_PROGRAMMER + MAP_SRAM_MCU, +#endif MAP_DEVICE1, MAP_DEVICE2, {0} @@ -84,6 +94,9 @@ static const mmap_region_t stm32mp1_mmap[] = { MAP_SEC_SYSRAM, MAP_NS_SYSRAM, +#if STM32MP_USB_PROGRAMMER + MAP_SRAM_MCU, +#endif MAP_DEVICE1, MAP_DEVICE2, {0} diff --git a/plat/st/stm32mp1/stm32mp1_usb_desc.c b/plat/st/stm32mp1/stm32mp1_usb_desc.c new file mode 100644 index 0000000..18cb356 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_usb_desc.c @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include + +#include +#include +#include +#include + +#include + +/* USB Standard Device Descriptor */ +static const uint8_t usb_stm32mp1_desc[USB_LEN_DEV_DESC] = { + USB_LEN_DEV_DESC, /* bLength */ + USB_DESC_TYPE_DEVICE, /* bDescriptorType */ + 0x00, /* bcdUSB */ + 0x02, /* version */ + 0x00, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + USB_MAX_EP0_SIZE, /* bMaxPacketSize */ + LOBYTE(USBD_VID), /* idVendor */ + HIBYTE(USBD_VID), /* idVendor */ + LOBYTE(USBD_PID), /* idVendor */ + HIBYTE(USBD_PID), /* idVendor */ + 0x00, /* bcdDevice rel. 2.00 */ + 0x02, + USBD_IDX_MFC_STR, /* Index of manufacturer string */ + USBD_IDX_PRODUCT_STR, /* Index of product string */ + USBD_IDX_SERIAL_STR, /* Index of serial number string */ + USBD_MAX_NUM_CONFIGURATION /* bNumConfigurations */ +}; /* USB_DeviceDescriptor */ + +/* USB Standard String Descriptor */ +static const uint8_t usb_stm32mp1_lang_id_desc[USB_LEN_LANGID_STR_DESC] = { + USB_LEN_LANGID_STR_DESC, + USB_DESC_TYPE_STRING, + LOBYTE(USBD_LANGID_STRING), + HIBYTE(USBD_LANGID_STRING), +}; + +/* USB Standard Device Descriptor */ +static const uint8_t +usbd_stm32mp1_qualifier_desc[USB_LEN_DEV_QUALIFIER_DESC] = { + USB_LEN_DEV_QUALIFIER_DESC, + USB_DESC_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, + 0x01, + 0x00, +}; + +static uint8_t usb_stm32mp1_serial[USB_SIZ_STRING_SERIAL + 1] = { + USB_SIZ_STRING_SERIAL, + USB_DESC_TYPE_STRING, +}; + +/* USB DFU device Configuration Descriptor */ +static uint8_t usb_stm32mp1_config_desc[USB_DFU_CONFIG_DESC_SIZ] = { + 0x09, /* bLength: Configuration Descriptor size */ + USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ + USB_DFU_CONFIG_DESC_SIZ, + /* wTotalLength: Bytes returned */ + 0x00, + 0x01,/* bNumInterfaces: 1 interface*/ + 0x01,/* bConfigurationValue: Configuration value*/ + 0x02,/* iConfiguration: Index of string descriptor + * describing the configuration + */ + 0xC0,/* bmAttributes: bus powered and Supprts Remote Wakeup */ + 0x32,/* MaxPower 100 mA: this current is used for detecting Vbus */ + /* 09 */ + + /* Descriptor of DFU interface 0 Alternate setting 0 */ + USBD_DFU_IF_DESC(0), /* This interface is mandatory for all devices */ + + /* Descriptor of DFU interface 0 Alternate setting 1 */ + USBD_DFU_IF_DESC(1), + + /* Descriptor of DFU interface 0 Alternate setting 2 */ + USBD_DFU_IF_DESC(2), + + /* Descriptor of DFU interface 0 Alternate setting 3 */ + USBD_DFU_IF_DESC(3), + + /* Descriptor of DFU interface 0 Alternate setting 4 */ + USBD_DFU_IF_DESC(4), + + /* Descriptor of DFU interface 0 Alternate setting 5 */ + USBD_DFU_IF_DESC(5), + + /* DFU Functional Descriptor */ + 0x09,/* blength = 9 Bytes */ + DFU_DESCRIPTOR_TYPE,/* DFU Functional Descriptor*/ + DFU_BM_ATTRIBUTE,/* bmAttribute + * bitCanDnload = 1 (bit 0) + * bitCanUpload = 1 (bit 1) + * bitManifestationTolerant = 1 (bit 2) + * bitWillDetach = 1 (bit 3) + * Reserved (bit4-6) + * bitAcceleratedST = 0 (bit 7) + */ + 0xFF,/* DetachTimeOut = 255 ms */ + 0x00, + /* WARNING: In DMA mode the multiple MPS packets feature + * is still not supported ==> In this case, + * when using DMA USBD_DFU_XFER_SIZE should be set + * to 64 in usbd_conf.h + */ + TRANSFER_SIZE_BYTES(USBD_DFU_XFER_SIZE),/* TransferSize = 1024 Byte*/ + ((USB_DFU_VERSION >> 0) & 0xFF), /* bcdDFUVersion*/ + ((USB_DFU_VERSION >> 8) & 0xFF) +}; + +static uint8_t usb_local_string_dec[USBD_MAX_STR_DESC_SIZ]; + +/* + * Convert Hex 32Bits value into char + * value: value to convert + * pbuf: pointer to the buffer + * len: buffer length + */ +static void int_to_unicode(uint32_t value, uint8_t *pbuf, uint8_t len) +{ + uint8_t idx = 0; + + for (idx = 0; idx < len; idx++) { + if (((value >> 28)) < 0xA) + pbuf[2 * idx] = (value >> 28) + '0'; + else + pbuf[2 * idx] = (value >> 28) + 'A' - 10; + value = value << 4; + pbuf[(2 * idx) + 1] = 0; + } +} + +/* + * Create the serial number string descriptor + */ +static void update_serial_num_string(void) +{ + /* serial number is set to 0*/ + uint8_t i; + uint32_t deviceserial[3] = {0, 0, 0}; + + for (i = 0; i < 3; i++) { + if (bsec_shadow_read_otp(&deviceserial[i], i + UID0_OTP) != + BSEC_OK) { + ERROR("BSEC: UID%d Error\n", i); + return; + } + } + + int_to_unicode(deviceserial[0], (uint8_t *)&usb_stm32mp1_serial[2], 8); + int_to_unicode(deviceserial[1], (uint8_t *)&usb_stm32mp1_serial[18], 8); + int_to_unicode(deviceserial[2], (uint8_t *)&usb_stm32mp1_serial[34], 8); +} + +/* + * usb_get_qualifier_desc + * return Device Qualifier descriptor + * param : length : pointer data length + * return : pointer to descriptor buffer + */ +static uint8_t *stm32mp1_get_qualifier_desc(uint16_t *length) +{ + *length = sizeof(usbd_stm32mp1_qualifier_desc); + return (uint8_t *)usbd_stm32mp1_qualifier_desc; +} + +/* + * stm32mp1_get_dfu_desc + * return Device Qualifier descriptor + * param : length : pointer data length + * return : pointer to descriptor buffer + */ +static uint8_t *stm32mp1_get_dfu_desc(uint16_t *len) +{ + *len = USB_DFU_DESC_SIZ; + return ((uint8_t *)usb_stm32mp1_config_desc + (9 * 7)); +} + +/* + * stm32mp1_get_config_desc + * return configuration descriptor + * param : speed : current device speed + * param : length : pointer data length + * return : pointer to descriptor buffer + */ +static uint8_t *stm32mp1_get_config_desc(uint16_t *length) +{ + *length = sizeof(usb_stm32mp1_config_desc); + return (uint8_t *)usb_stm32mp1_config_desc; +} + +/* + * stm32mp1_get_string + * Convert Ascii string into unicode one + * param : desc : descriptor buffer + * param : unicode : Formatted string buffer (unicode) + * param : len : descriptor length + * return : None + */ +static void stm32mp1_get_string(uint8_t *desc, uint8_t *unicode, uint16_t *len) +{ + uint8_t idx = 0; + + if (!desc) + return; + + *len = strlen((char *)desc) * 2 + 2; + unicode[idx++] = *len; + unicode[idx++] = USB_DESC_TYPE_STRING; + + while (*desc != '\0') { + unicode[idx++] = *desc++; + unicode[idx++] = 0x00; + } +} + +/* + * stm32mp1_device_desc + * Returns the device descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_device_desc(uint16_t *length) +{ + *length = sizeof(usb_stm32mp1_desc); + return (uint8_t *)usb_stm32mp1_desc; +} + +/* + * stm32mp1_lang_id_desc + * Returns the LangID string descriptor. + * speed: Current device speed + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_lang_id_desc(uint16_t *length) +{ + *length = sizeof(usb_stm32mp1_lang_id_desc); + + return (uint8_t *)usb_stm32mp1_lang_id_desc; +} + +/* + * stm32mp1_product_desc + * Returns the product string descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_product_desc(uint16_t *length) +{ + stm32mp1_get_string((uint8_t *)USBD_PRODUCT_HS_STRING, + usb_local_string_dec, length); + + return usb_local_string_dec; +} + +/* + * stm32mp1_manufacturer_desc + * Returns the manufacturer string descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_manufacturer_desc(uint16_t *length) +{ + stm32mp1_get_string((uint8_t *)USBD_MANUFACTURER_STRING, + usb_local_string_dec, length); + + return usb_local_string_dec; +} + +/* + * stm32mp1_serial_desc + * Returns the serial number string descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_serial_desc(uint16_t *length) +{ + *length = USB_SIZ_STRING_SERIAL; + + /* Update the serial number string descriptor + * with the data from the unique ID + */ + update_serial_num_string(); + + return (uint8_t *)usb_stm32mp1_serial; +} + +/* + * stm32mp1_Config_desc + * Returns the configuration string descriptor. + * length: Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_config_desc(uint16_t *length) +{ + stm32mp1_get_string((uint8_t *)USBD_CONFIGURATION_HS_STRING, + usb_local_string_dec, length); + + return usb_local_string_dec; +} + +/* + * stm32mp1_interface_desc + * Returns the interface string descriptor. + * length : Pointer to data length variable + * return : Pointer to descriptor buffer + */ +static uint8_t *stm32mp1_interface_desc(uint16_t *length) +{ + stm32mp1_get_string((uint8_t *)USBD_INTERFACE_HS_STRING, + usb_local_string_dec, length); + + return usb_local_string_dec; +} + +/* + * stm32mp1_get_usr_desc + * Manages the transfer of memory interfaces string descriptors. + * param : index: descriptor index + * param : length : pointer data length + * return : pointer to the descriptor table or NULL if the descriptor + * is not supported. + */ +static uint8_t *stm32mp1_get_usr_desc(uint8_t index, uint16_t *length) +{ + uint8_t *ret; + + if (index > (USBD_IDX_INTERFACE_STR + USBD_DESC_MAX_ITF_NUM)) + return NULL; + + switch (index) { + case 6: + stm32mp1_get_string((uint8_t *)"@Partition0 /0x00/1*256Ke", + usb_local_string_dec, length); + ret = usb_local_string_dec; + break; + case 7: + stm32mp1_get_string((uint8_t *)"@FSBL /0x01/1*1Me", + usb_local_string_dec, length); + ret = usb_local_string_dec; + break; + case 8: + stm32mp1_get_string((uint8_t *)"@Partition2 /0x02/1*1Me", + usb_local_string_dec, length); + ret = usb_local_string_dec; + break; + case 9: + stm32mp1_get_string((uint8_t *)"@Partition3 /0x03/1*16Me", + usb_local_string_dec, length); + ret = usb_local_string_dec; + break; + case 10: + stm32mp1_get_string((uint8_t *)"@Partition4 /0x04/1*16Me", + usb_local_string_dec, length); + ret = usb_local_string_dec; + break; + case 11: + stm32mp1_get_string((uint8_t *)"@virtual /0xF1/1*512Ba", + usb_local_string_dec, length); + ret = usb_local_string_dec; + break; + default: + ret = NULL; + break; + } + + return ret; +} + +static const usb_desc_t dfu_desc = { + .get_device_desc = stm32mp1_device_desc, + .get_lang_id_desc = stm32mp1_lang_id_desc, + .get_manufacturer_desc = stm32mp1_manufacturer_desc, + .get_product_desc = stm32mp1_product_desc, + .get_configuration_desc = stm32mp1_config_desc, + .get_serial_desc = stm32mp1_serial_desc, + .get_interface_desc = stm32mp1_interface_desc, + .get_usr_desc = stm32mp1_get_usr_desc, + .get_hs_config_desc = stm32mp1_get_config_desc, + .get_fs_config_desc = stm32mp1_get_config_desc, + .get_other_speed_config_desc = stm32mp1_get_config_desc, + .get_device_qualifier_desc = stm32mp1_get_qualifier_desc, + .get_dfu_desc = stm32mp1_get_dfu_desc +}; + +void stm32mp_usb_init_desc(usb_handle_t *pdev) +{ + register_platform(pdev, &dfu_desc); +}