Newer
Older
arm-trusted-firmware / plat / st / stm32mp1 / stm32mp1_usb_desc.c
/*
 * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <string.h>

#include <platform_def.h>

#include <common/debug.h>
#include <drivers/st/bsec.h>
#include <lib/usb/usb_core.h>
#include <lib/usb/usb_st_dfu.h>

#include <stm32mp1_usb_desc.h>

/* 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);
}