platform: msm_shared: Add support for usb electrical and ch9 testing
This change adds support for usb electrical test mode support and
protocol test framework for hsusb & ssusb.
For supporting hsusb protocol testing add support for device qualifier,
other speed configuration support, end point halt and support for
interface set/get features.
For SSUSB add support for end point halt, function suspend, u1/u2 link
mode support, isochronous delay and update the usb2.0 version number to
0x201 for ss capable device.
Change-Id: I937a561862e5083b9c604b42090bb81ac81a09fe
diff --git a/include/dev/udc.h b/include/dev/udc.h
index 31d9755..7dc16c0 100644
--- a/include/dev/udc.h
+++ b/include/dev/udc.h
@@ -102,12 +102,15 @@
#define SET_INTERFACE 11
#define SYNCH_FRAME 12
#define SET_SEL 48
+#define SET_ISOCH_DELAY 49
#define TYPE_DEVICE 1
#define TYPE_CONFIGURATION 2
#define TYPE_STRING 3
#define TYPE_INTERFACE 4
#define TYPE_ENDPOINT 5
+#define TYPE_DEVICE_QUALIFIER 6
+#define TYPE_OTHER_SPEED_CONFIG 7
#define TYPE_BOS 15
#define TYPE_DEVICE_CAP 16
#define TYPE_SS_EP_COMP 48
@@ -118,9 +121,14 @@
#define INTERFACE_WRITE 0x01
#define ENDPOINT_READ 0x82
#define ENDPOINT_WRITE 0x02
+#define TEST_MODE 0x02
+#define TEST_J 0x0100
+#define TEST_K 0x0200
#define TEST_SE0_NAK 0x0300
#define TEST_PACKET 0x0400
+#define TEST_FORCE_ENABLE 0x0500
+
#define PORTSC_PTC (0xF << 16)
#define PORTSC_PTC_SE0_NAK (0x03 << 16)
#define PORTSC_PTC_TST_PKT (0x4 << 16)
diff --git a/platform/msm_shared/usb30_dwc.c b/platform/msm_shared/usb30_dwc.c
index 9e4a59a..564d1c9 100644
--- a/platform/msm_shared/usb30_dwc.c
+++ b/platform/msm_shared/usb30_dwc.c
@@ -1056,6 +1056,13 @@
* something wrong in fsm implementation.
*/
ASSERT(ep->state == EP_STATE_XFER_IN_PROG);
+ if (dev->is_test_mode)
+ {
+ /* Write DCTL register with test mode value */
+ dwc_device_enter_test_mode(dev);
+ dprintf(INFO, "Device entered test mode, please reset the device once testing is finished\n");
+ break;
+ }
ep->state = EP_STATE_INACTIVE;
diff --git a/platform/msm_shared/usb30_dwc.h b/platform/msm_shared/usb30_dwc.h
index 14402e7..5b5fc70 100644
--- a/platform/msm_shared/usb30_dwc.h
+++ b/platform/msm_shared/usb30_dwc.h
@@ -410,6 +410,8 @@
/* callback into client to process the setup msgs. */
void *setup_context;
int (*setup_handler)(void* context, uint8_t* data);
+ bool is_test_mode;
+ uint16_t test_mode;
} dwc_dev_t;
diff --git a/platform/msm_shared/usb30_dwc_hw.c b/platform/msm_shared/usb30_dwc_hw.c
index 7b69bbb..2ca1a54 100644
--- a/platform/msm_shared/usb30_dwc_hw.c
+++ b/platform/msm_shared/usb30_dwc_hw.c
@@ -383,6 +383,45 @@
return REG_READ_FIELD(dev, DCTL, RUN_STOP);
}
+void dwc_device_enter_test_mode(dwc_dev_t *dev)
+{
+ REG_WRITE_FIELD(dev, DCTL, TSTCTL, dev->test_mode);
+}
+
+void dwc_device_enable_u1(dwc_dev_t *dev, uint8_t val)
+{
+ REG_WRITE_FIELD(dev, DCTL, INITU1ENA, val);
+}
+
+void dwc_device_enable_u2(dwc_dev_t *dev, uint8_t val)
+{
+ REG_WRITE_FIELD(dev, DCTL, INITU2ENA, val);
+}
+
+void dwc_device_accept_u1u2(dwc_dev_t *dev)
+{
+ REG_WRITE_FIELD(dev, DCTL, ACCEPTU1ENA, 1);
+ REG_WRITE_FIELD(dev, DCTL, ACCEPTU2ENA, 1);
+}
+
+bool dwc_device_u1_enabled(dwc_dev_t *dev)
+{
+ uint32_t val;
+
+ val = REG_READ(dev, DCTL);
+
+ return val & (1 << 10) ? true : false;
+}
+
+bool dwc_device_u2_enabled(dwc_dev_t *dev)
+{
+ uint32_t val;
+
+ val = REG_READ(dev, DCTL);
+
+ return val & (1 << 12) ? true : false;
+}
+
/******************** Managing various events *********************************/
/* event init:
program event buffer address, size and reset event count to 0.
diff --git a/platform/msm_shared/usb30_dwc_hw.h b/platform/msm_shared/usb30_dwc_hw.h
index 56b32ba..119bf20 100644
--- a/platform/msm_shared/usb30_dwc_hw.h
+++ b/platform/msm_shared/usb30_dwc_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013,2015 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -51,4 +51,10 @@
uint8_t dwc_device_run_status(dwc_dev_t *dev);
void dwc_gctl_init(dwc_dev_t *dev);
void dwc_axi_master_config(dwc_dev_t *dev);
+void dwc_device_enter_test_mode(dwc_dev_t *dev);
+void dwc_device_enable_u1(dwc_dev_t *dev, uint8_t val);
+void dwc_device_enable_u2(dwc_dev_t *dev, uint8_t val);
+void dwc_device_accept_u1u2(dwc_dev_t *dev);
+bool dwc_device_u1_enabled(dwc_dev_t *dev);
+bool dwc_device_u2_enabled(dwc_dev_t *dev);
#endif
diff --git a/platform/msm_shared/usb30_udc.c b/platform/msm_shared/usb30_udc.c
index d9d18a2..49d47d1 100644
--- a/platform/msm_shared/usb30_udc.c
+++ b/platform/msm_shared/usb30_udc.c
@@ -47,6 +47,7 @@
#include <board.h>
#include <platform/timer.h>
#include <qmp_phy.h>
+#include <usb30_dwc_hw.h>
//#define DEBUG_USB
@@ -90,14 +91,17 @@
static void udc_register_bos_desc(udc_t *udc);
static void udc_register_device_desc_usb_20(udc_t *udc, struct udc_device *dev_info);
static void udc_register_device_desc_usb_30(udc_t *udc, struct udc_device *dev_info);
-static void udc_register_config_desc_usb20(udc_t *udc, struct udc_gadget *gadget);
+static void udc_register_config_desc_usb20(udc_t *udc, struct udc_gadget *gadget, uint8_t type);
static void udc_register_config_desc_usb30(udc_t *udc, struct udc_gadget *gadget);
-static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data);
+static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data, uint8_t type);
static void udc_ept_comp_desc_fill(struct udc_endpoint *ept, uint8_t *data);
static void udc_dwc_notify(void *context, dwc_notify_event_t event);
static int udc_handle_setup(void *context, uint8_t *data);
+static bool stall_ep;
+static bool udc_other_speed_cfg;
+static bool udc_ss_capable;
/* TODO: This must be the only global var in this file, for now.
* Ideally, all APIs should be sending
@@ -341,7 +345,7 @@
}
/* create our configuration descriptors based on this gadget data */
- udc_register_config_desc_usb20(udc_dev, gadget);
+ udc_register_config_desc_usb20(udc_dev, gadget, TYPE_CONFIGURATION);
udc_register_config_desc_usb30(udc_dev, gadget);
/* save the gadget */
@@ -434,18 +438,28 @@
switch (SETUP(s.type, s.request))
{
+ case SETUP(ENDPOINT_READ, GET_STATUS):
+ case SETUP(INTERFACE_READ, GET_STATUS):
case SETUP(DEVICE_READ, GET_STATUS):
{
- DBG("\n DEVICE_READ : GET_STATUS: value = %d index = %d"
- " length = %d", s.value, s.index, s.length);
-
if (s.length == 2) {
- uint16_t zero = 0;
+ uint16_t status = 0;
+ if (s.type == DEVICE_READ || (s.type == ENDPOINT_READ && stall_ep == true))
+ status = 1; /* Self-powered is set for device read and Halt bit set for end point read */
+
len = 2;
+ if (udc->usb_state == UDC_CONFIGURED_STATE && udc->speed == UDC_SPEED_SS)
+ {
+ if (s.type == DEVICE_READ && dwc_device_u1_enabled(dwc))
+ status |= (1 << 2); /* Set D2 to indicate U1 is enabled */
+ if (s.type == DEVICE_READ && dwc_device_u2_enabled(dwc))
+ status |= (1 << 3); /* Set D3 to indicate U3 is enabled */
+ }
+
/* copy to tx buffer */
- memcpy(udc->ctrl_tx_buf, &zero, len);
+ memcpy(udc->ctrl_tx_buf, &status, len);
/* flush buffer to main memory before queueing the request */
arch_clean_invalidate_cache_range((addr_t) udc->ctrl_tx_buf, len);
@@ -464,10 +478,53 @@
break;
case SETUP(DEVICE_READ, GET_DESCRIPTOR):
{
- DBG("\n DEVICE_READ : GET_DESCRIPTOR: value = %d", s.value);
+ DBG("\n DEVICE_READ : GET_DESCRIPTOR: value = %x\n", s.value);
/* setup usb ep0-IN to send our device descriptor */
struct udc_descriptor *desc;
+ /* Device Qualifier */
+ if (((s.value >> 8) == TYPE_DEVICE_QUALIFIER) && (udc->speed != UDC_SPEED_SS))
+ {
+ struct usb_qualifier_desc qual = {0};
+ qual.bLength = sizeof(qual);
+ qual.bDescriptorType = TYPE_DEVICE_QUALIFIER;
+ qual.bcdUSB = 0x0200; /* USB2.0 version */
+ qual.bDeviceClass = udc_dev->gadget->ifc_class;
+ qual.bDeviceSubClass = udc_dev->gadget->ifc_subclass;
+ qual.bDeviceProtocol = udc_dev->gadget->ifc_protocol;
+ qual.bMaxPacketSize0 = (udc_dev->speed == UDC_SPEED_HS) ? 64 : 512;
+ qual.bNumConfigurations = 1;
+ qual.bReserved = 0;
+
+ if (sizeof(qual) > s.length)
+ len = s.length;
+ else
+ len = sizeof(qual);
+
+ /* copy to tx buffer */
+ memcpy(udc->ctrl_tx_buf, (void *)&qual, len);
+
+ /* flush buffer to main memory before queueing the request */
+ arch_clean_invalidate_cache_range((addr_t) udc->ctrl_tx_buf, len);
+
+ dwc_transfer_request(udc->dwc,
+ 0,
+ DWC_EP_DIRECTION_IN,
+ udc->ctrl_tx_buf,
+ len,
+ NULL,
+ NULL);
+
+ return DWC_SETUP_3_STAGE;
+ }
+ if (((s.value >> 8) == TYPE_OTHER_SPEED_CONFIG) && (udc->speed != UDC_SPEED_SS)) /* Other speed config */
+ {
+ if (!udc_other_speed_cfg)
+ {
+ udc_register_config_desc_usb20(udc, udc->gadget, TYPE_OTHER_SPEED_CONFIG);
+ udc_other_speed_cfg = true;
+ }
+ }
for (desc = udc->desc_list; desc; desc = desc->next)
{
@@ -540,7 +597,10 @@
DBG("\n DEVICE_WRITE : SET_CONFIGURATION");
/* select configuration 1 */
- if (s.value == 1) {
+ /* Return the config if configuration value is not 0 and move the state to
+ * configured state
+ */
+ if (s.value) {
struct udc_endpoint *ept;
/* enable endpoints */
for (ept = udc->ept_list; ept; ept = ept->next) {
@@ -562,7 +622,7 @@
ep->type = ept->type;
ep->max_pkt_size = ept->maxpkt;
ep->burst_size = ept->maxburst;
- ep->zlp = 0; /* TODO: zlp could be made part of ept */
+ ep->zlp = 0;
ep->trb_count = ept->trb_count;
ep->trb = ept->trb;
@@ -575,12 +635,14 @@
/* now that we have saved the non-control EP details, set config */
dwc_device_set_configuration(dwc);
+ if (udc->speed == UDC_SPEED_SS)
+ dwc_device_accept_u1u2(dwc);
/* inform client that we are configured. */
udc->gadget->notify(udc_dev->gadget, UDC_EVENT_ONLINE);
udc->config_selected = 1;
-
+ udc->usb_state = UDC_CONFIGURED_STATE;
return DWC_SETUP_2_STAGE;
}
else if (s.value == 0)
@@ -588,13 +650,9 @@
/* 0 == de-configure. */
udc->config_selected = 0;
DBG("\n\n CONFIG = 0 !!!!!!!!!\n\n");
+ /* If config value is '0' change the state to addressed state */
+ udc->usb_state = UDC_ADDRESSED_STATE;
return DWC_SETUP_2_STAGE;
- /* TODO: do proper handling for de-config */
- }
- else
- {
- ERR("\n CONFIG = %d not supported\n", s.value);
- ASSERT(0);
}
}
break;
@@ -603,26 +661,107 @@
DBG("\n DEVICE_WRITE : SET_ADDRESS");
dwc_device_set_addr(dwc, s.value);
+ udc->usb_state = UDC_ADDRESSED_STATE;
return DWC_SETUP_2_STAGE;
}
break;
case SETUP(INTERFACE_WRITE, SET_INTERFACE):
{
- DBG("\n DEVICE_WRITE : SET_INTERFACE");
+ DBG("\n INTERFACE_WRITE : SET_INTERFACE");
/* if we ack this everything hangs */
/* per spec, STALL is valid if there is not alt func */
goto stall;
}
break;
+ case SETUP(INTERFACE_WRITE, SET_FEATURE):
+ {
+ DBG("\n INTERFACE_WRITE : SET_FEATURE");
+ if (s.value == FUNCTION_SUSPEND && udc->speed == UDC_SPEED_SS)
+ return DWC_SETUP_2_STAGE;
+ }
+ break;
+ case SETUP(INTERFACE_READ, GET_INTERFACE):
+ {
+ DBG("\n INTERFACE_READ : GET_INTERFACE");
+ /* per spec, STALL is valid if there is not alt func */
+ goto stall;
+ }
+ break;
+ case SETUP(ENDPOINT_WRITE, SET_FEATURE):
+ {
+ DBG("\n ENDPOINT_WRITE : SET_FEATURE");
+ if (s.value == ENDPOINT_HALT)
+ {
+ uint8_t usb_epnum;
+ uint8_t dir;
+
+ usb_epnum = (s.index & USB_EP_NUM_MASK);
+ dir = ((s.index & USB_EP_DIR_MASK) == USB_EP_DIR_IN) ? 0x1 : 0x0;
+ dwc_ep_cmd_stall(dwc, DWC_EP_PHY_NUM(usb_epnum, dir));
+ stall_ep = true;
+ return DWC_SETUP_2_STAGE;
+ }
+ else
+ goto stall;
+ }
case SETUP(DEVICE_WRITE, SET_FEATURE):
{
DBG("\n DEVICE_WRITE : SET_FEATURE");
+
+ if (s.value == TEST_MODE)
+ {
+ dwc->test_mode = s.index;
+
+ switch(dwc->test_mode)
+ {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_ENABLE:
+ /* Upper byte of Windex contain test mode */
+ dwc->test_mode >>= 8;
+ dwc->is_test_mode = true;
+ break;
+ default:
+ DBG("\n Unknown test mode: %x\n", dwc->test_mode);
+ }
+ return DWC_SETUP_2_STAGE;
+ }
+ if (udc->usb_state == UDC_CONFIGURED_STATE && udc->speed == UDC_SPEED_SS)
+ {
+ /* Set U1 & U2 only in configured state */
+ if (s.value == U1_ENABLE)
+ {
+ dwc_device_enable_u1(dwc, 1);
+ return DWC_SETUP_2_STAGE;
+ }
+ if (s.value == U2_ENABLE)
+ {
+ dwc_device_enable_u2(dwc, 1);
+ return DWC_SETUP_2_STAGE;
+ }
+ }
goto stall;
}
break;
case SETUP(DEVICE_WRITE, CLEAR_FEATURE):
{
DBG("\n DEVICE_WRITE : CLEAR_FEATURE");
+ /* Clear U1 & U2 only in configured state */
+ if (udc->usb_state == UDC_CONFIGURED_STATE && udc->speed == UDC_SPEED_SS)
+ {
+ if (s.value == U1_ENABLE)
+ {
+ dwc_device_enable_u1(dwc, 0);
+ return DWC_SETUP_2_STAGE;
+ }
+ if (s.value == U2_ENABLE)
+ {
+ dwc_device_enable_u2(dwc, 0);
+ return DWC_SETUP_2_STAGE;
+ }
+ }
goto stall;
}
break;
@@ -660,6 +799,7 @@
* physical ep 31 --> logical ep 15 IN
*/
dwc_ep_cmd_clear_stall(dwc, DWC_EP_PHY_NUM(usb_epnum, dir));
+ stall_ep = false;
return DWC_SETUP_2_STAGE;
}
@@ -686,7 +826,12 @@
}
}
break;
-
+ case SETUP(DEVICE_WRITE, SET_ISOCH_DELAY):
+ {
+ DBG("\n DEVICE_WRITE: SET_ISOCH_DELAY\n");
+ return DWC_SETUP_2_STAGE;
+ }
+ break;
default:
/* some of the requests from host are not handled, add a debug
* for the command not being handled, this is not fatal
@@ -764,6 +909,23 @@
return ret;
}
+/* For HS device should have the version number as 0x0200.
+ * Update the minor version to 0x00 when we receive the connect
+ * event with HS or FS mode
+ */
+static void udc_update_usb20_desc(udc_t *udc)
+{
+ struct udc_descriptor *desc= NULL;
+ if (udc_ss_capable)
+ return;
+
+ for (desc = udc->desc_list; desc; desc = desc->next)
+ {
+ if (desc->spec == UDC_DESC_SPEC_20 && desc->data[1] == TYPE_DEVICE)
+ desc->data[2] = 0x00; /* usb spec minor rev */
+ }
+}
+
static void udc_update_ep_desc(udc_t *udc, uint16_t max_pkt_sz_bulk)
{
struct udc_descriptor *desc= NULL;
@@ -815,6 +977,8 @@
*/
max_pkt_size = 64;
udc_update_ep_desc(udc, max_pkt_size);
+ /* Update the spec version for FS */
+ udc_update_usb20_desc(udc);
break;
case DWC_NOTIFY_EVENT_CONNECTED_HS:
udc->speed = UDC_SPEED_HS;
@@ -823,6 +987,8 @@
*/
max_pkt_size = 512;
udc_update_ep_desc(udc, max_pkt_size);
+ /* Update the spec version for HS */
+ udc_update_usb20_desc(udc);
break;
case DWC_NOTIFY_EVENT_CONNECTED_SS:
udc->speed = UDC_SPEED_SS;
@@ -830,6 +996,7 @@
* with SS max packet size
*/
max_pkt_size = 1024;
+ udc_ss_capable = true;
udc_update_ep_desc(udc, max_pkt_size);
break;
case DWC_NOTIFY_EVENT_DISCONNECTED:
@@ -912,7 +1079,7 @@
/* create config + interface + ep desc for 2.0 */
static void udc_register_config_desc_usb20(udc_t *udc,
- struct udc_gadget *gadget)
+ struct udc_gadget *gadget, uint8_t type)
{
uint8_t *data;
uint16_t size;
@@ -928,13 +1095,13 @@
UDC_DESC_SIZE_INTERFACE +
(gadget->ifc_endpoints*UDC_DESC_SIZE_ENDPOINT);
- desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size, UDC_DESC_SPEC_20);
+ desc = udc_descriptor_alloc(type, 0, size, UDC_DESC_SPEC_20);
data = desc->data;
/* Config desc */
data[0] = 0x09;
- data[1] = TYPE_CONFIGURATION;
+ data[1] = type;
data[2] = size;
data[3] = size >> 8;
data[4] = 0x01; /* number of interfaces */
@@ -957,7 +1124,7 @@
data += 9;
for (uint8_t n = 0; n < gadget->ifc_endpoints; n++) {
- udc_ept_desc_fill(gadget->ept[n], data);
+ udc_ept_desc_fill(gadget->ept[n], data, type);
data += UDC_DESC_SIZE_ENDPOINT;
}
@@ -1013,7 +1180,7 @@
for (uint8_t n = 0; n < gadget->ifc_endpoints; n++)
{
/* fill EP desc */
- udc_ept_desc_fill(gadget->ept[n], data);
+ udc_ept_desc_fill(gadget->ept[n], data, 0);
data += UDC_DESC_SIZE_ENDPOINT;
/* fill EP companion desc */
@@ -1038,7 +1205,7 @@
/* data 0 and 1 is filled by descriptor alloc routine.
* fill in the remaining entries.
*/
- data[2] = 0x00; /* usb spec minor rev */
+ data[2] = 0x10; /* usb spec minor rev */
data[3] = 0x02; /* usb spec major rev */
data[4] = 0x00; /* class */
data[5] = 0x00; /* subclass */
@@ -1092,7 +1259,7 @@
struct udc_descriptor *desc;
/* create our device descriptor */
- desc = udc_descriptor_alloc(TYPE_BOS, 0, 15, UDC_DESC_SPEC_30); /* 15 is total length of bos + other descriptors inside it */
+ desc = udc_descriptor_alloc(TYPE_BOS, 0, 0x16, UDC_DESC_SPEC_30); /* 22 is total length of bos + other descriptors inside it */
data = desc->data;
/* data 0 and 1 is filled by descriptor alloc routine.
@@ -1100,20 +1267,30 @@
*/
data[0] = 0x05; /* BOS desc len */
data[1] = TYPE_BOS; /* BOS desc type */
- data[2] = 0x0F; /* total len of bos desc and its sub desc */
+ data[2] = 0x16; /* total len of bos desc and its sub desc */
data[3] = 0x00; /* total len of bos desc and its sub desc */
- data[4] = 0x01; /* num of sub desc inside bos */
+ data[4] = 0x02; /* num of sub desc inside bos */
- data[5] = 0x0A; /* desc len */
- data[6] = 0x10; /* Device Capability desc */
- data[7] = 0x03; /* 3 == SuperSpeed capable */
- data[8] = 0x00; /* Attribute: latency tolerance msg: No */
- data[9] = 0x0F; /* Supported Speeds (bit mask): LS, FS, HS, SS */
- data[10] = 0x00; /* Reserved part of supported wSupportedSpeeds */
- data[11] = 0x01; /* lowest supported speed with full functionality: FS */
- data[12] = 0x00; /* U1 device exit latency */
- data[13] = 0x00; /* U2 device exit latency (lsb) */
- data[14] = 0x00; /* U2 device exit latency (msb) */
+ /* USB2.0 extension Descriptor */
+ data[5] = 0x07; /* Size of USB2.0 extension desc */
+ data[6] = 0x10; /* Device capability desc */
+ data[7] = 0x02; /* USB2.0 extension descriptor */
+ data[8] = 0x02; /* LPM mode */
+ data[9] = 0x00; /* Reserved */
+ data[10] = 0x00; /* Reserved */
+ data[11] = 0x00; /* Reserved */
+
+ /* Super Speed device capability */
+ data[12] = 0x0A; /* desc len */
+ data[13] = 0x10; /* Device Capability desc */
+ data[14] = 0x03; /* 3 == SuperSpeed capable */
+ data[15] = 0x00; /* Attribute: latency tolerance msg: No */
+ data[16] = 0x0F; /* Supported Speeds (bit mask): LS, FS, HS, SS */
+ data[17] = 0x00; /* Reserved part of supported wSupportedSpeeds */
+ data[18] = 0x01; /* lowest supported speed with full functionality: FS */
+ data[19] = 0x00; /* U1 device exit latency */
+ data[20] = 0x00; /* U2 device exit latency (lsb) */
+ data[21] = 0x00; /* U2 device exit latency (msb) */
udc_descriptor_register(udc, desc);
}
@@ -1131,14 +1308,25 @@
udc_descriptor_register(udc, desc);
}
-static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data)
+static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data, uint8_t type)
{
+ uint16_t max_pkt_sz = 0;
+
+ /* For other speed configuration, populate the max packet size for the other speed
+ * mode. For eg: if currently host is operating in HS mode, return the configuration
+ * for FS mode
+ */
+ if (type == TYPE_OTHER_SPEED_CONFIG && udc_dev->speed != UDC_SPEED_SS)
+ max_pkt_sz = (udc_dev->speed == UDC_SPEED_FS) ? 512 : 64;
+ else
+ max_pkt_sz = ept->maxpkt;
+
data[0] = 7;
data[1] = TYPE_ENDPOINT;
data[2] = ept->num | (ept->in ? 0x80 : 0x00);
data[3] = 0x02; /* bulk -- the only kind we support */
- data[4] = ept->maxpkt;
- data[5] = ept->maxpkt >> 8;
+ data[4] = max_pkt_sz;
+ data[5] = max_pkt_sz >> 8;
data[6] = 0; /* bInterval: must be 0 for bulk. */
}
diff --git a/platform/msm_shared/usb30_udc.h b/platform/msm_shared/usb30_udc.h
index 97ef7e8..56a2b10 100644
--- a/platform/msm_shared/usb30_udc.h
+++ b/platform/msm_shared/usb30_udc.h
@@ -39,6 +39,22 @@
typedef enum
{
+ UDC_DEFAULT_STATE,
+ UDC_ADDRESSED_STATE,
+ UDC_CONFIGURED_STATE,
+} usb_state_t;
+
+typedef enum
+{
+ ENDPOINT_HALT = 0,
+ FUNCTION_SUSPEND = 0,
+ U1_ENABLE = 48,
+ U2_ENABLE = 49,
+ LTM_ENABLE = 50,
+} udc_feature_select_t;
+
+typedef enum
+{
UDC_DESC_SPEC_20 = BIT(0),
UDC_DESC_SPEC_30 = BIT(1),
} udc_desc_spec_t;
@@ -69,6 +85,7 @@
uint8_t config_selected; /* keeps track of the selected configuration */
struct udc_request *queued_req; /* pointer to the currently queued request. NULL indicates no request is queued. */
+ usb_state_t usb_state; /* USB state, default, addressed & configured */
} udc_t;
@@ -93,6 +110,18 @@
uint32_t trb_count; /* size of TRB chain. */
};
+struct usb_qualifier_desc {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint8_t bNumConfigurations;
+ uint8_t bReserved;
+}__PACKED;
+
struct udc_request *usb30_udc_request_alloc(void);
struct udc_endpoint *usb30_udc_endpoint_alloc(unsigned type, unsigned maxpkt);
void usb30_udc_request_free(struct udc_request *req);