[U-Boot] [PATCH 2/4] usb: add 'bcm_udc_otg' support

Steve Rae srae at broadcom.com
Tue Jan 20 23:42:08 CET 2015


Implement the UDC support for the USB OTG interface.

Signed-off-by: Steve Rae <srae at broadcom.com>
---
This commit is not checkpatch clean - however, there seems to be
no way to remove this warning:
    "warning: drivers/usb/gadget/bcm_udc_otg.c,97:
        Adding new packed members is to be done with care"

 drivers/usb/gadget/bcm_udc_otg.c | 1193 ++++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/bcm_udc_otg.h |   19 +
 2 files changed, 1212 insertions(+)
 create mode 100644 drivers/usb/gadget/bcm_udc_otg.c
 create mode 100644 drivers/usb/gadget/bcm_udc_otg.h

diff --git a/drivers/usb/gadget/bcm_udc_otg.c b/drivers/usb/gadget/bcm_udc_otg.c
new file mode 100644
index 0000000..706e003
--- /dev/null
+++ b/drivers/usb/gadget/bcm_udc_otg.c
@@ -0,0 +1,1193 @@
+/*
+ * Copyright 2015 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/io.h>
+#include <asm/arch/sysmap.h>
+#include <asm/kona-common/clk.h>
+#include "bcm_udc_otg.h"
+
+#ifdef CONFIG_CMD_SERIALNO
+#include "serial_no.h"
+#endif
+
+#include <usbdevice.h>
+
+#define DEVICE_STRING_LANGUAGE_ID_INDEX		0
+#define DEVICE_STRING_PRODUCT_INDEX		1
+#define DEVICE_STRING_SERIAL_NUMBER_INDEX	2
+#define DEVICE_STRING_CONFIG_INDEX		3
+#define DEVICE_STRING_INTERFACE_INDEX		4
+#define DEVICE_STRING_MANUFACTURER_INDEX	5
+#define DEVICE_STRING_MAX_INDEX		DEVICE_STRING_MANUFACTURER_INDEX
+
+#define FASTBOOT_INTERFACE_CLASS	0xff
+#define FASTBOOT_INTERFACE_SUB_CLASS	0x42
+#define FASTBOOT_INTERFACE_PROTOCOL	0x03
+
+#define wfld_set(addr, fld_val, fld_mask) \
+		(writel(((readl(addr) & ~(fld_mask)) | (fld_val)), (addr)))
+#define wfld_clear(addr, fld_mask) \
+		(writel((readl(addr) & ~(fld_mask)), (addr)))
+
+#define DEVICE_STRING_LANGUAGE_ID	0x0409 /* English (United States) */
+
+/*
+ * In high speed mode rx packets are 512
+ * In full speed mode rx packets are 64
+ */
+#define RX_ENDPOINT_MAXIMUM_PACKET_SIZE		(0x0200)
+#define TX_ENDPOINT_MAXIMUM_PACKET_SIZE		(0x0040)
+
+#ifndef CONFIG_USB_BOARDNAME
+#define CONFIG_USB_BOARDNAME "Board"
+#endif
+
+#ifndef CONFIG_USB_CONFIGURATION
+#define CONFIG_USB_CONFIGURATION "Fastboot"
+#endif
+
+#ifndef CONFIG_USB_INTERFACE
+#define CONFIG_USB_INTERFACE "Fastboot"
+#endif
+
+#ifndef CONFIG_USB_SERIALNO
+#define CONFIG_USB_SERIALNO "1234567890"
+#endif
+
+#ifndef CONFIG_USBID_ADDR
+#error	CONFIG_USBID_ADDR must be defined!
+#endif
+
+static char *usb_device_strings[DEVICE_STRING_MANUFACTURER_INDEX + 1] = {
+	/* Language =		*/	"",
+	/* Product =		*/	CONFIG_USB_BOARDNAME,
+	/* Serial =		*/	CONFIG_USB_SERIALNO,
+	/* Config =		*/	CONFIG_USB_CONFIGURATION,
+	/* Interface =		*/	CONFIG_USB_INTERFACE,
+	/* Manufacturer =	*/	CONFIG_G_DNL_MANUFACTURER,
+};
+
+static struct usb_device_descriptor dfu_dev_descriptor
+				__aligned(4) = {
+	.bLength			= 0x12,
+	.bDescriptorType		= USB_DT_DEVICE,
+	.bcdUSB				= 0x100,
+	.bDeviceClass			= 0xff,
+	.bDeviceSubClass		= 0xff,
+	.bDeviceProtocol		= 0xff,
+	.bMaxPacketSize0		= 64,	/* depends on enum speed */
+	.idVendor			= CONFIG_G_DNL_VENDOR_NUM,
+	.idProduct			= CONFIG_G_DNL_PRODUCT_NUM,
+	.bcdDevice			= 0x0001,
+	.iManufacturer			= DEVICE_STRING_MANUFACTURER_INDEX,
+	.iProduct			= DEVICE_STRING_PRODUCT_INDEX,
+	.iSerialNumber			= DEVICE_STRING_SERIAL_NUMBER_INDEX,
+	.bNumConfigurations		= 0x1,
+};
+
+struct full_configuration_descriptor {
+	struct usb_configuration_descriptor c;
+	struct usb_interface_descriptor i;
+	struct usb_endpoint_descriptor e1;
+	struct usb_endpoint_descriptor e2;
+} __packed;
+
+static struct full_configuration_descriptor full_desc
+				__aligned(4) = {
+.c = {
+	.bLength		= 0x9,
+	.bDescriptorType	= USB_DT_CONFIG,
+	.wTotalLength		= sizeof(struct usb_configuration_descriptor) +
+				  sizeof(struct usb_interface_descriptor) +
+				  sizeof(struct usb_endpoint_descriptor) +
+				  sizeof(struct usb_endpoint_descriptor),
+	.bNumInterfaces		= 1,
+	.bConfigurationValue	= 1,
+	.iConfiguration		= DEVICE_STRING_CONFIG_INDEX,
+	.bmAttributes		= BMATTRIBUTE_RESERVED |
+				  BMATTRIBUTE_SELF_POWERED,
+	.bMaxPower		= 0,
+},
+.i = {
+	.bLength		= 0x9,
+	.bDescriptorType	= USB_DT_INTERFACE,
+	.bInterfaceNumber	= 0x0,
+	.bAlternateSetting	= 0x0,	/* CheckMe */
+	.bNumEndpoints		= 0x2,
+	.bInterfaceClass	= FASTBOOT_INTERFACE_CLASS,
+	.bInterfaceSubClass	= FASTBOOT_INTERFACE_SUB_CLASS,
+	.bInterfaceProtocol	= FASTBOOT_INTERFACE_PROTOCOL,
+	.iInterface		= DEVICE_STRING_INTERFACE_INDEX,
+},
+.e1 = {
+	.bLength		= sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_IN | 1,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= TX_ENDPOINT_MAXIMUM_PACKET_SIZE,
+	.bInterval		= 0x00,
+},
+.e2 = {
+	.bLength		= sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType	= USB_DT_ENDPOINT,
+	.bEndpointAddress	= USB_DIR_OUT | 1,
+	.bmAttributes		= USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize		= RX_ENDPOINT_MAXIMUM_PACKET_SIZE,
+	.bInterval		= 0x00,
+},
+};
+
+static rx_type rx_callback;
+
+#define EP0_SETUP_BUF_SIZE		16	/* hold 2 setup packets */
+#define EP0_IN_BUF_SIZE			128
+#define EP0_OUT_BUF_SIZE		16
+
+#define RX_FIFO_SIZE			512		/* 512 x 4 bytes */
+#define TX_FIFO_SIZE			256		/* 256 x 4 bytes */
+#define TX_FIFO_OFFSET			RX_FIFO_SIZE
+#define TX_FIFO1_SIZE			256		/* 256 x 4 bytes */
+#define TX_FIFO1_OFFSET			(TX_FIFO_SIZE + TX_FIFO_OFFSET)
+
+#define TURN_AROUND_TIME		9
+
+#define EP_MISMATCH_CNT			1
+#define PERIODIC_FRM_INTERVAL		1
+#define BC11_CFG_VDP_OFF		0x55570000
+
+#define EP1_IN_BUF_SIZE			512
+#define EP1_OUT_BUF_SIZE		512
+
+#define HSOTG_CTRL_STATUS_OFFSET HSOTG_CTRL_BC_STATUS_OFFSET
+#define HSOTG_CTRL_STATUS_SHP_MASK HSOTG_CTRL_BC_STATUS_SDP_MASK
+#define HSOTG_CTRL_CFG_OFFSET HSOTG_CTRL_BC_CFG_OFFSET
+#define HSOTG_CTRL_CFG_OVWR_KEY_MASK HSOTG_CTRL_BC_CFG_BC_OVWR_KEY_MASK
+#define HSOTG_CTRL_CFG_SW_OVWR_EN_MASK HSOTG_CTRL_BC_CFG_SW_OVWR_EN_MASK
+#define HSOTG_CTRL_CFG_OVWR_SET_M0_MASK HSOTG_CTRL_BC_CFG_BC_OVWR_SET_M0_MASK
+#define HSOTG_CTRL_CFG_OVWR_SET_P0_MASK HSOTG_CTRL_BC_CFG_BC_OVWR_SET_P0_MASK
+
+/* Align buffers to 32 bytes so cache invalidate/flush routines work. */
+static uint32_t ep0_setup_buf[EP0_SETUP_BUF_SIZE]	__aligned(32);
+static uint32_t ep0_out_buf[EP0_OUT_BUF_SIZE]		__aligned(32);
+static uint32_t ep0_in_buf[EP0_IN_BUF_SIZE]		__aligned(32);
+
+static uint8_t ep1_out_buf[2][EP1_OUT_BUF_SIZE]		__aligned(32);
+static uint8_t ep1_in_buf[EP1_IN_BUF_SIZE]		__aligned(32);
+
+static int ep1_out_buf_sel;
+static uint32_t usb_speed;
+
+/**
+ * @brief: usb_soft_reset - Soft Reset USB Core.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_soft_reset(void)
+{
+	uint32_t val;
+
+	/* Add hclk soft reset after interface setting */
+	writel(HSOTG_RSTCTL_CSFTRST_MASK,
+	       HSOTG_BASE_ADDR + HSOTG_RSTCTL_OFFSET);
+
+	udelay(1000);
+
+	/* Poll until Reset complete and AHB idle */
+	do {
+		val = readl(HSOTG_BASE_ADDR + HSOTG_RSTCTL_OFFSET);
+	} while ((val & HSOTG_RSTCTL_CSFTRST_MASK) ||
+		 (!(val & HSOTG_RSTCTL_AHBIDLE_MASK)));
+
+	return 0;
+}
+
+/**
+ * @brief: setup_device_fifo - Configure USB FIFO.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: none
+ */
+static void setup_device_fifo(void)
+{
+	/* Receive FIFO size register;
+512*4bytes, number is in terms of 32bits */
+	writel((RX_FIFO_SIZE << HSOTG_RXFSIZ_RXFDEP_SHIFT),
+	       HSOTG_BASE_ADDR + HSOTG_RXFSIZ_OFFSET);
+
+	/*
+	 * Receive FIFO size register
+	 *  256*4bytes -- Tx FIFO depth
+	 *  512*4bytes -- TX RAM start address
+	 *  (number is in terms of 32bits)
+	 */
+	writel((TX_FIFO_SIZE << HSOTG_NPTXFSIZ_NPTXFDEP_SHIFT) |
+	       (TX_FIFO_OFFSET << HSOTG_NPTXFSIZ_NPTXFSTADDR_SHIFT),
+	       HSOTG_BASE_ADDR + HSOTG_NPTXFSIZ_OFFSET);
+
+	writel((TX_FIFO1_SIZE << HSOTG_DIEPTXF1_INEPNTXFDEP_SHIFT) |
+	       (TX_FIFO1_OFFSET << HSOTG_DIEPTXF1_INEPNTXFSTADDR_SHIFT),
+	       HSOTG_BASE_ADDR + HSOTG_DIEPTXF1_OFFSET);
+}
+
+/**
+ * @brief: dfu_setup_device_mode - Configure USB device mode.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0 or ERROR ID
+ */
+static int dfu_setup_device_mode(void)
+{
+	setup_device_fifo();
+
+	writel(HSOTG_AHBCFG_NPTXFEMPLVL_MASK |
+				/* int indicates TXFIFO empty */
+	       HSOTG_AHBCFG_DMAEN_MASK |
+				/* DMA mode */
+	       HSOTG_AHBCFG_GLBLINTRMSK_MASK,
+				/* Unmask the interrupt assertion */
+	       HSOTG_BASE_ADDR + HSOTG_AHBCFG_OFFSET);
+
+	writel(TURN_AROUND_TIME << HSOTG_CFG_USBTRDTIM_SHIFT,
+	       HSOTG_BASE_ADDR + HSOTG_CFG_OFFSET);
+
+	/* UTMI+ 8bit interface */
+	wfld_clear(HSOTG_BASE_ADDR + HSOTG_CFG_OFFSET,
+		   HSOTG_CFG_ULPI_UTMI_SEL_MASK);
+
+	writel((EP_MISMATCH_CNT << HSOTG_DCFG_EPMISCNT_SHIFT) |
+				/* IN Mismatch Cnt */
+	       (PERIODIC_FRM_INTERVAL << HSOTG_DCFG_PERFRINT_SHIFT),
+				/* Frame Interval */
+	       HSOTG_BASE_ADDR + HSOTG_DCFG_OFFSET);
+
+	/* check if OTG is in device mode */
+	if (readl(HSOTG_BASE_ADDR + HSOTG_INTSTS_OFFSET) &
+		  HSOTG_INTSTS_CURMOD_MASK) {
+		error("Not in device mode");
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * @brief: usb_clr_interrupt - Clear USB interrupt.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_clr_interrupt(void)
+{
+	/* clear all interrupts */
+	writel(0xffffffff, HSOTG_BASE_ADDR + HSOTG_INTSTS_OFFSET);
+	return 0;
+}
+
+/**
+ * @brief: usb_phy_connect - Connect USB Phy to host.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_phy_connect(void)
+{
+	/* set Phy to driving mode */
+	wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
+		   HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK);
+
+	udelay(100);
+
+	/* Clear Soft Disconnect */
+	wfld_clear(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET,
+		   HSOTG_DCTL_SFTDISCON_MASK);
+
+	/* software reset Phy, active low */
+	wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
+		   HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK);
+
+	udelay(10000);
+
+	/* */
+	wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
+		 HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK,
+		 HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK);
+
+	return 0;
+}
+
+/**
+ * @brief: usb_phy_disconnect - disconnect USB Phy from Host.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_phy_disconnect(void)
+{
+	/* Soft Disconnect */
+	wfld_set(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET,
+		 HSOTG_DCTL_SFTDISCON_MASK,
+		 HSOTG_DCTL_SFTDISCON_MASK);
+
+	/* set Phy to non-driving (reset) mode */
+	wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET,
+		 HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK,
+		 HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK);
+	return 0;
+}
+
+/**
+ * @brief: usb_wait_for_vbus - wait for vbus turning 5.0v by polling STAT2.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: none
+ */
+static void usb_wait_for_vbus(void)
+{
+	uint32_t val;
+
+	/*
+	 * If there is no PMU, then the VBUS signal from the connector will
+	 * not necessarily be connected to STAT2. We can get around this by
+	 * telling the usb core to proceed irregardless by triggering the
+	 * core with internal STAT1/STAT2 signals in software.
+	 */
+	val = readl(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_USBOTGCONTROL_OFFSET);
+	val |= (HSOTG_CTRL_USBOTGCONTROL_REG_OTGSTAT2_MASK |
+		HSOTG_CTRL_USBOTGCONTROL_REG_OTGSTAT1_MASK |
+		HSOTG_CTRL_USBOTGCONTROL_OTGSTAT_CTRL_MASK);
+	writel(val, HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_USBOTGCONTROL_OFFSET);
+}
+
+/**
+ * @brief: usb_turn_off_vdp - disable vdp.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: none
+ */
+static void usb_turn_off_vdp(void)
+{
+	/* Check if it is standard host port (SHP) */
+	if (readl(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_STATUS_OFFSET) &
+			HSOTG_CTRL_STATUS_SHP_MASK) {
+		udelay(60000);	/* 50 ms + 20 % */
+
+		/*
+		 * force turn off VDP, enable sw_ovwr_set to take over the
+		 * bc11 switches directly
+		 */
+		wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_CFG_OFFSET,
+			 BC11_CFG_VDP_OFF,
+			 HSOTG_CTRL_CFG_OVWR_KEY_MASK |
+			 HSOTG_CTRL_CFG_SW_OVWR_EN_MASK |
+			 HSOTG_CTRL_CFG_OVWR_SET_M0_MASK |
+			 HSOTG_CTRL_CFG_OVWR_SET_P0_MASK);
+
+		udelay(160);	/* Allow time for switches to disengage */
+	} else {
+		udelay(120000);	/* 100 ms + 20 % */
+	}
+}
+
+/**
+ * @brief: usb_ep0_setup_prime - Prepare receiving EP0 Setup packet.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_ep0_setup_prime(void)
+{
+	uint32_t mask;
+
+	invalidate_dcache_range((uint32_t)ep0_setup_buf,
+				((uint32_t)ep0_setup_buf +
+				 sizeof(ep0_setup_buf)));
+
+	/* Device OUT Endpoint 0 DMA Address Register */
+	writel((uint32_t)ep0_setup_buf,
+	       HSOTG_BASE_ADDR + HSOTG_DOEPDMA0_OFFSET);
+
+	/* Device OUT Endpoint 0 Transfer Size Register */
+	writel((0x3 << HSOTG_DOEPTSIZ0_SUPCNT_SHIFT) |	/* 3 SUPCnt */
+	       (0x3 << HSOTG_DOEPTSIZ0_PKTCNT_SHIFT) |	/* 3 PktCnt */
+	       (0x8 << HSOTG_DOEPTSIZ0_XFERSIZE_SHIFT),	/* XferSize 8 bytes */
+	       HSOTG_BASE_ADDR + HSOTG_DOEPTSIZ0_OFFSET);
+
+	/* Device OUT Endpoint 0 Control Register */
+	mask =	HSOTG_DOEPCTL0_EPENA_MASK |		/* Endpoint Enable */
+		HSOTG_DOEPCTL0_CNAK_MASK;		/* clear NAK bit */
+	wfld_set(HSOTG_BASE_ADDR + HSOTG_DOEPCTL0_OFFSET, mask, mask);
+
+	return 0;
+}
+
+/**
+ * @brief: usb_ep0_recv_data - Receive packet on EP0-OUT endpoint.
+ * @param[in]:	uint8_t *data_buf - Data packet buffer
+ * @param[in]:	uint32_t cnt - Number of bytes to receive
+ * @param[out]:	none
+ * @return: 0 or ERROR ID
+ */
+static int usb_ep0_recv_data(uint8_t *data_buf, uint32_t cnt)
+{
+	uint32_t mask;
+
+	if (cnt > sizeof(ep0_out_buf)) {
+		printf("EP0_OUT overflow\n");
+		return 1;
+	}
+
+	invalidate_dcache_range((uint32_t)ep0_out_buf,
+				(uint32_t)ep0_out_buf + sizeof(ep0_out_buf));
+
+	/* Device OUT Endpoint 0 DMA Address Register */
+	writel((uint32_t)ep0_out_buf,
+	       HSOTG_BASE_ADDR + HSOTG_DOEPDMA0_OFFSET);
+
+	/* Device OUT Endpoint 0 Transfer Size Register */
+	writel((1 << HSOTG_DOEPTSIZ0_PKTCNT_SHIFT) | cnt,
+	       HSOTG_BASE_ADDR + HSOTG_DOEPTSIZ0_OFFSET);
+
+	/* Device OUT Endpoint 0 Control Register */
+	mask =	HSOTG_DOEPCTL0_EPENA_MASK |		/* Endpoint Enable */
+		HSOTG_DOEPCTL0_CNAK_MASK;		/* clear NAK bit */
+	wfld_set(HSOTG_BASE_ADDR + HSOTG_DOEPCTL0_OFFSET, mask, mask);
+
+	if (cnt > 0)
+		memcpy(data_buf, ep0_out_buf, cnt);
+
+	return 0;
+}
+
+/**
+ * @brief: usb_ep0_recv_zlp - Receive zero length packet on EP0-OUT endpoint.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_ep0_recv_zlp(void)
+{
+	usb_ep0_recv_data(NULL, 0);
+	return 0;
+}
+
+/**
+ * @brief: usb_ep0_send_data - Send packet on EP0-IN endpoint.
+ * @param[in]:	uint8_t *data_buf - Data packet to send
+ * @param[in]:	uint32_t cnt - Number of bytes to send
+ * @param[out]:	none
+ * @return: 0 or ERROR ID
+ */
+static int usb_ep0_send_data(uint8_t *data_buf, uint32_t cnt)
+{
+	if (cnt > sizeof(ep0_in_buf)) {
+		printf("EP0_IN overflow\n");
+		return 1;
+	} else if (cnt > 0) {
+		/* use local DMA buffer */
+		memcpy(ep0_in_buf, data_buf, cnt);
+	}
+
+	flush_dcache_range((uint32_t)ep0_in_buf,
+			   (uint32_t)ep0_in_buf + sizeof(ep0_in_buf));
+
+	/* Device IN Endpoint 0 DMA Address Register */
+	writel((uint32_t)ep0_in_buf,
+	       HSOTG_BASE_ADDR + HSOTG_DIEPDMA0_OFFSET);
+
+	/* Device IN Endpoint 0 Transfer Size Register */
+	writel((1 << HSOTG_DIEPTSIZ0_PKTCNT_SHIFT) |	/* 1 pakcnt */
+	       (cnt << HSOTG_DIEPTSIZ0_XFERSIZE_SHIFT),	/* XferSize cnt */
+	       HSOTG_BASE_ADDR + HSOTG_DIEPTSIZ0_OFFSET);
+
+	/* Device IN Endpoint 0 Control Register */
+	writel(HSOTG_DIEPCTL0_EPENA_MASK |		/* Endpoint Enable */
+	       HSOTG_DIEPCTL0_CNAK_MASK |		/* clear NAK BIT */
+	       HSOTG_DIEPCTL0_USBACTEP_MASK |		/* USB ACTIVE EP */
+	       (0 << HSOTG_DIEPCTL0_NEXTEP_SHIFT),	/* next EP */
+	       HSOTG_BASE_ADDR + HSOTG_DIEPCTL0_OFFSET);
+
+	return 0;
+}
+
+/**
+ * @brief: usb_ep0_send_zlp - Send zero length packet on EP0-IN endpoint.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_ep0_send_zlp(void)
+{
+	usb_ep0_send_data(NULL, 0);
+	return 0;
+}
+
+/**
+ * @brief: usb_ep0_send_stall - Send STALL condition on EP0-IN endpoint.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_ep0_send_stall(void)
+{
+	/* Device Control IN Endpoint 0 Control Register */
+	wfld_set(HSOTG_BASE_ADDR + HSOTG_DIEPCTL0_OFFSET,
+		 HSOTG_DIEPCTL0_STALL_MASK, HSOTG_DIEPCTL0_STALL_MASK);
+	usb_ep0_setup_prime();
+	return 0;
+}
+
+/**
+ * @brief: usb_ep1_out_prime - Prepare receiving EP1-OUT packet.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_ep1_out_prime(void)
+{
+	/* toggle which buffer is used */
+	ep1_out_buf_sel = ep1_out_buf_sel ? 0 : 1;
+
+	invalidate_dcache_range((uint32_t)ep1_out_buf[ep1_out_buf_sel],
+				(uint32_t)ep1_out_buf[ep1_out_buf_sel] +
+				sizeof(ep1_out_buf[ep1_out_buf_sel]));
+
+	/* Device OUT Endpoint 1 DMA Address Register */
+	writel((uint32_t)ep1_out_buf[ep1_out_buf_sel],
+	       HSOTG_BASE_ADDR + HSOTG_DOEPDMA1_OFFSET);
+
+	/* Device OUT Endpoint 1 Transfer Size Register */
+	writel((0x1 << HSOTG_DOEPTSIZ1_PKTCNT_SHIFT) |
+				/* 1 PktCnt */
+	       (EP1_OUT_BUF_SIZE << HSOTG_DOEPTSIZ1_XFERSIZE_SHIFT),
+				/* XferSize */
+	       HSOTG_BASE_ADDR + HSOTG_DOEPTSIZ1_OFFSET);
+
+	/* Device OUT Endpoint 1 Control Register */
+	writel((1 << HSOTG_DOEPCTL1_EPENA_SHIFT) |	/* Endpoint Enable */
+	       (2 << HSOTG_DOEPCTL1_EPTYPE_SHIFT) |	/* Bulk Endpoint */
+	       (1 << HSOTG_DOEPCTL1_CNAK_SHIFT) |	/* clear NAK bit */
+	       (1 << HSOTG_DOEPCTL1_USBACTEP_SHIFT) |	/* USB ACTIVE EP */
+	       (RX_ENDPOINT_MAXIMUM_PACKET_SIZE << HSOTG_DOEPCTL1_MPS_SHIFT),
+	       HSOTG_BASE_ADDR + HSOTG_DOEPCTL1_OFFSET);
+
+	/* */
+	writel(0x00030003, HSOTG_BASE_ADDR + HSOTG_DAINTMSK_OFFSET);
+
+	return 0;
+}
+
+/**
+ * @brief: usb_ep1_in_prime - Prepare for sending EP1-IN packet.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_ep1_in_prime(void)
+{
+	/* Device Control IN Endpoint 1 Control Register */
+	writel((2 << HSOTG_DIEPCTL1_EPTYPE_SHIFT) |	/* Bulk Endpoint */
+	       (1 << HSOTG_DIEPCTL1_CNAK_SHIFT) |	/* clear NAK BIT */
+	       (1 << HSOTG_DIEPCTL1_USBACTEP_SHIFT) |	/* USB ACTIVE EP */
+	       (1 << HSOTG_DIEPCTL1_NEXTEP_SHIFT) |	/* next EP */
+	       (1 << HSOTG_DIEPCTL1_TXFNUM_SHIFT) |	/* use FIFO1 for ep1 */
+	       (TX_ENDPOINT_MAXIMUM_PACKET_SIZE << HSOTG_DIEPCTL1_MPS_SHIFT),
+	       HSOTG_BASE_ADDR + HSOTG_DIEPCTL1_OFFSET);
+
+	return 0;
+}
+
+/**
+ * @brief: usb_send_data_ep1_in - Send packet on EP1-IN endpoint.
+ * @param[in]:	uint8_t *data_buf - Data packet to send
+ * @param[in]:	uint32_t cnt - Number of bytes to send
+ * @param[out]:	none
+ * @return: 0 or ERROR ID
+ */
+static int usb_send_data_ep1_in(uint8_t *data_buf, uint32_t cnt)
+{
+	if (cnt > sizeof(ep1_in_buf)) {
+		printf("EP1_IN overflow\n");
+		return 1;
+	} else if (cnt > 0) {
+		/* use local DMA buffer */
+		memcpy(ep1_in_buf, data_buf, cnt);
+	}
+
+	flush_dcache_range((uint32_t)ep1_in_buf,
+			   (uint32_t)ep1_in_buf + sizeof(ep1_in_buf));
+
+	/* Device IN Endpoint 1 DMA Address Register */
+	writel((uint32_t)ep1_in_buf,
+	       HSOTG_BASE_ADDR + HSOTG_DIEPDMA1_OFFSET);
+
+	/* Device IN Endpoint 1 Transfer Size Register */
+	writel((1 << HSOTG_DIEPTSIZ1_PKTCNT_SHIFT) |	/* 1 pakcnt */
+	       (cnt << HSOTG_DIEPTSIZ1_XFERSIZE_SHIFT),	/* XferSize cnt */
+	       HSOTG_BASE_ADDR + HSOTG_DIEPTSIZ1_OFFSET);
+
+	/* Device IN Endpoint 1 Control Register */
+	writel((1 << HSOTG_DIEPCTL1_EPENA_SHIFT) |	/* Enable EP */
+	       (2 << HSOTG_DIEPCTL1_EPTYPE_SHIFT) |	/* Bulk Endpoint */
+	       (1 << HSOTG_DIEPCTL1_CNAK_SHIFT) |	/* clear NAK BIT */
+	       (1 << HSOTG_DIEPCTL1_USBACTEP_SHIFT) |	/* USB ACTIVE EP */
+	       (1 << HSOTG_DIEPCTL1_NEXTEP_SHIFT) |	/* next EP */
+	       (1 << HSOTG_DIEPCTL1_TXFNUM_SHIFT) |	/* use FIFO1 for ep1 */
+	       (TX_ENDPOINT_MAXIMUM_PACKET_SIZE << HSOTG_DIEPCTL1_MPS_SHIFT),
+	       HSOTG_BASE_ADDR + HSOTG_DIEPCTL1_OFFSET);
+
+	return 0;
+}
+
+static void process_usb_req_get_descriptor(uint16_t desc_type,
+		uint16_t desc_index, uint16_t wLength)
+{
+	switch (desc_type) {
+	case USB_DT_DEVICE:
+		/* Reply Device Descriptor */
+		debug("DEVICE DESC\n");
+		usb_ep0_send_data((uint8_t *)&dfu_dev_descriptor,
+				  min(sizeof(dfu_dev_descriptor),
+				      (size_t)wLength));
+		usb_ep0_recv_zlp();
+		break;
+	case USB_DT_CONFIG:
+		/* Reply Configuration Descriptor */
+		debug("CONFIG DESC\n");
+		usb_ep0_send_data((uint8_t *)&full_desc,
+				  min(sizeof(full_desc),
+				      (size_t)wLength));
+		usb_ep0_recv_zlp();
+		break;
+	case USB_DT_STRING:
+		debug("STRING DESC\n");
+		if (desc_index == DEVICE_STRING_LANGUAGE_ID_INDEX) {
+			uint8_t temp[100];
+			temp[0] = 4;
+			temp[1] = USB_DT_STRING;
+			temp[2] = DEVICE_STRING_LANGUAGE_ID & 0xFF;
+			temp[3] = DEVICE_STRING_LANGUAGE_ID >> 8;
+
+			usb_ep0_send_data(temp, 4);
+			usb_ep0_recv_zlp();
+		} else if (desc_index <= DEVICE_STRING_MAX_INDEX) {
+			int index;
+			int sl = strlen(&usb_device_strings[desc_index][0]);
+			uint8_t temp[100];
+			temp[0] = 2 + (2*sl);
+			temp[1] = USB_DT_STRING;
+
+			for (index = 0; index < sl; index++) {
+				int i = 2 + (2*index);
+				temp[i] = usb_device_strings[desc_index][index];
+				temp[i + 1] = 0;
+			}
+
+			usb_ep0_send_data(temp, 2 + (2*sl));
+			usb_ep0_recv_zlp();
+		} else if (desc_index == 238) {
+			debug("string index [%d] is ignored\n", desc_index);
+			usb_ep0_send_stall();
+		} else {
+			error("bad string index [%d]", desc_index);
+			usb_ep0_send_stall();
+		}
+		break;
+	default:
+		error("bad descriptor request");
+		usb_ep0_send_stall();
+		break;
+	}
+}
+
+static int process_usb_set_addr(uint32_t dev_addr)
+{
+	/* Device Configuration Register */
+	writel((EP_MISMATCH_CNT << HSOTG_DCFG_EPMISCNT_SHIFT) |
+				/* IN Mismatch Cnt */
+	       (PERIODIC_FRM_INTERVAL << HSOTG_DCFG_PERFRINT_SHIFT) |
+				/* Frame Interval */
+	       (dev_addr << HSOTG_DCFG_DEVADDR_SHIFT),
+				/* Device Address */
+	       HSOTG_BASE_ADDR + HSOTG_DCFG_OFFSET);
+
+	return 0;
+}
+
+/**
+ * @brief: dfu_ep0_handler - Decode EP0 setup commands and process CH9 requests.
+ * @param[in]:	uint8_t *setup_buf - EP0 packet buffer.
+ * @param[out]:	none
+ * @return: none
+ */
+static void dfu_ep0_handler(u8 *setup_buf)
+{
+	uint16_t wLength;
+	uint16_t desc_type;
+	uint16_t desc_index;
+	struct usb_device_request ctrl;
+
+	memcpy(&ctrl, setup_buf, sizeof(ctrl));
+
+	wLength = ctrl.wLength;
+
+	if (ctrl.bmRequestType & USB_TYPE_VENDOR) {
+		debug("USB_TYPE_VENDOR\n");
+		if (ctrl.bmRequestType & 0x80) {
+			/* VENDOR_REQ_GET_USBID */
+			if (ctrl.bRequest == 0x3) {
+				u8 temp[2];
+				memcpy(temp, (void *)CONFIG_USBID_ADDR, 2);
+				usb_ep0_send_data(temp, 2);
+				usb_ep0_recv_zlp();
+			} else {
+				u8 temp = 0;
+				usb_ep0_send_data(&temp, 1);
+				usb_ep0_recv_zlp();
+			}
+		} else {
+			usb_ep0_setup_prime();
+			usb_ep0_send_zlp();
+		}
+	} else if (ctrl.bmRequestType & USB_TYPE_CLASS) {
+		debug("USB_TYPE_CLASS\n");
+		usb_ep0_send_stall();
+	} else {
+		/* CH9 command */
+		switch (ctrl.bRequest) {
+		case USB_REQ_SET_ADDRESS:
+			debug("SET_ADDR = %d\n", ctrl.wValue);
+			process_usb_set_addr(ctrl.wValue);
+			usb_ep0_setup_prime();
+			usb_ep0_send_zlp();
+			return;
+
+		case USB_REQ_CLEAR_FEATURE:
+		case USB_REQ_SET_FEATURE:
+			debug("USB_SET/CLR_FEATURE\n");
+			if (ctrl.wValue == USB_TEST_MODE) {
+				unsigned int testctl = ctrl.wIndex >> 8;
+
+				usb_ep0_setup_prime();
+				usb_ep0_send_zlp();
+
+				/*
+				 * Wait till after status phase to set test mode
+				 */
+				wfld_set(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET,
+					 testctl, HSOTG_DCTL_TSTCTL_MASK);
+			} else {
+				usb_ep0_setup_prime();
+				usb_ep0_send_zlp();
+			}
+			return;
+
+		case USB_REQ_GET_CONFIGURATION:
+			debug("GET_CONFIG\n");
+			usb_ep0_setup_prime();
+			usb_ep0_send_zlp();
+			break;
+
+		case USB_REQ_SET_CONFIGURATION:
+			debug("SET_CONFIG\n");
+			usb_ep0_setup_prime();
+			usb_ep1_out_prime();
+			usb_ep1_in_prime();
+			usb_ep0_send_zlp();
+			break;
+
+		case USB_REQ_GET_DESCRIPTOR:
+			debug("GET_DESC -> ");
+			desc_type = ctrl.wValue >> 8;
+			desc_index = ctrl.wValue & 0xff;
+			process_usb_req_get_descriptor(desc_type,
+						       desc_index,
+						       wLength);
+			break;
+
+		case USB_REQ_SET_INTERFACE:
+		case USB_REQ_GET_INTERFACE:
+			debug("USB_SET/GET_INTERFACE\n");
+			usb_ep0_setup_prime();
+			usb_ep0_send_zlp();
+			break;
+
+		case USB_REQ_GET_STATUS:
+		case USB_REQ_SET_DESCRIPTOR:
+		case USB_REQ_SYNCH_FRAME:
+			debug("USB misc CH9 cmd: ignore\n");
+			usb_ep0_setup_prime();
+			usb_ep0_send_zlp();
+			break;
+
+		default:
+			error("Unknown EP0 cmd");
+			usb_ep0_send_stall();
+			break;
+		}
+	}
+}
+
+/**
+ * @brief: usb_handle_ep0_in_int - Process USB EP0-IN interrupt.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_handle_ep0_in_int(void)
+{
+	uint32_t diep0int;
+
+	/* clear Device IN Endpoint 0 Interrupt Register */
+	diep0int = readl(HSOTG_BASE_ADDR + HSOTG_DIEPINT0_OFFSET);
+	writel(diep0int, HSOTG_BASE_ADDR + HSOTG_DIEPINT0_OFFSET);
+
+	return 0;
+}
+
+/**
+ * @brief: usb_handle_ep1_in_int - Process USB EP1-IN interrupt.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static int usb_handle_ep1_in_int(void)
+{
+	uint32_t diep1int;
+
+	/* clear Device IN Endpoint 1 Interrupt Register */
+	diep1int = readl(HSOTG_BASE_ADDR + HSOTG_DIEPINT1_OFFSET);
+	writel(diep1int, HSOTG_BASE_ADDR + HSOTG_DIEPINT1_OFFSET);
+
+	return 0;
+}
+
+/**
+ * @brief: usb_handle_ep0_out_int - Process USB EP0-OUT interrupt.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0 or ERROR ID
+ */
+static int usb_handle_ep0_out_int(void)
+{
+	uint32_t doep0int;
+
+	/* clear Device OUT Endpoint 0 Interrupt Register */
+	doep0int = readl(HSOTG_BASE_ADDR + HSOTG_DOEPINT0_OFFSET);
+	writel(doep0int, HSOTG_BASE_ADDR + HSOTG_DOEPINT0_OFFSET);
+
+	if (doep0int & HSOTG_DOEPINT0_TIMEOUT_MASK) {
+		/* Timeout Condition */
+		debug("timeout\n");
+
+		/* Reset EP0 buffer */
+		dfu_ep0_handler((uint8_t *)ep0_setup_buf);
+	} else if (doep0int & HSOTG_DOEPINT0_XFERCOMPL_MASK) {
+		/* Transfer Completed Interrupt */
+
+		/* re-arm EP0-Setup */
+		usb_ep0_setup_prime();
+	} else {
+		debug(" ... not timeout or transfer complete?\n");
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ * @brief: usb_handle_ep1_out_int - Process USB EP1-OUT interrupt.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0 or ERROR ID
+ */
+static int usb_handle_ep1_out_int(void)
+{
+	uint32_t doepint1;
+
+	/* clear Device OUT Endpoint 1 Interrupt Register */
+	doepint1 = readl(HSOTG_BASE_ADDR + HSOTG_DOEPINT1_OFFSET);
+	writel(doepint1, HSOTG_BASE_ADDR + HSOTG_DOEPINT1_OFFSET);
+
+	if (doepint1 & HSOTG_DOEPINT1_TIMEOUT_MASK) {
+		/* Timeout Condition */
+		debug("timeout\n");
+	} else if (doepint1 & HSOTG_DOEPINT1_XFERCOMPL_MASK) {
+		/* Transfer Completed Interrupt */
+
+		/* Get pointer to current buffer */
+		uint8_t *buffer = ep1_out_buf[ep1_out_buf_sel];
+
+		/* Compute size of transfer */
+		int transfer_size = EP1_OUT_BUF_SIZE -
+			(readl(HSOTG_BASE_ADDR + HSOTG_DOEPTSIZ1_OFFSET) &
+			       HSOTG_DOEPTSIZ1_XFERSIZE_MASK);
+
+		/* Stuff a NULL in to help terminate command strings */
+		if (transfer_size != EP1_OUT_BUF_SIZE)
+			buffer[transfer_size] = 0;
+
+		/*
+		 * Before processing received data, re-arm EP1-OUT
+		 * (toggles active buffer)
+		 */
+		usb_ep1_out_prime();
+
+		/* Now, process data */
+		if (rx_callback)
+			rx_callback(buffer, transfer_size);
+
+	} else {
+		debug(" ... not timeout or transfer complete?\n");
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ * @brief: usb_chirp_enum - Perform USB CHIRP.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: 0
+ */
+static inline int usb_chirp_enum(void)
+{
+	/*
+	 * Enumerated Speed:
+	 *	00: High speed (PHY clock is running at 30 or 60 MHz)
+	 *	01: Full speed (PHY clock is running at 30 or 60 MHz)
+	 *	10: Low speed  (PHY clock is running at 6 MHz)
+	 *	11: Full speed (PHY clock is running at 48 MHz)
+	 */
+	usb_speed = readl(HSOTG_BASE_ADDR + HSOTG_DSTS_OFFSET);
+	usb_speed = ((usb_speed & HSOTG_DSTS_ENUMSPD_MASK) >>
+		     HSOTG_DSTS_ENUMSPD_SHIFT);
+
+	printf("USB speed: %s\n", (usb_speed == 0) ? "High" : "Full/Low");
+
+	return 0;
+}
+
+/**
+ * @brief: usb_power_up - Power-up USB.
+ * @param[in]:	none
+ * @param[out]:	none
+ * @return: none
+ */
+static inline void usb_power_up(void)
+{
+	/* clear "stop PHY clock" */
+	writel((0 << HSOTG_PCGCR_STOPPCLK_SHIFT),
+	       HSOTG_BASE_ADDR + HSOTG_PCGCR_OFFSET);
+	printf("Enable USB PHY clock!\n");
+}
+
+/*
+ * UDC interface
+ */
+
+int usb_init_otg(rx_type rx)
+{
+	uint32_t mask;
+
+	rx_callback = rx;
+
+	clk_usb_otg_enable((void *)HSOTG_BASE_ADDR);
+
+#ifdef CONFIG_CMD_SERIALNO
+	if (get_serial_no())
+		usb_device_strings[DEVICE_STRING_SERIAL_NUMBER_INDEX] =
+				(char *)get_serial_no();
+#endif
+
+	mask =	HSOTG_CTRL_USBOTGCONTROL_UTMIOTG_IDDIG_SW_MASK |
+			/* SW sets device mode bit 26 */
+		HSOTG_CTRL_USBOTGCONTROL_USB_ON_MASK |
+			/* turn on OTG core */
+		HSOTG_CTRL_USBOTGCONTROL_USB_ON_IS_HCLK_EN_MASK |
+			/* use usb_on as source of AHB clock enable */
+		HSOTG_CTRL_USBOTGCONTROL_USB_HCLK_EN_DIRECT_MASK;
+			/* explicit source of AHB clock enable */
+
+	wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_USBOTGCONTROL_OFFSET,
+		 mask, mask);
+
+	udelay(1000);
+	usb_soft_reset();
+	udelay(1000);
+
+	/* Initialize OTG device core */
+	if (dfu_setup_device_mode()) {
+		usb_phy_disconnect();
+		return 1;
+	}
+
+	/* Device All Endpoints Interrupt Mask Register */
+	writel(HSOTG_INTMSK_WKUPINTMSK_MASK |
+			/* Resume/Remote Wakeup Detected */
+	       HSOTG_INTMSK_DISCONNINTMSK_MASK |
+			/* Disconnect Detected */
+	       HSOTG_INTMSK_OEPINTMSK_MASK |	/* OUT Endpoints */
+	       HSOTG_INTMSK_INEPINTMSK_MASK |	/* IN Endpoints */
+	       HSOTG_INTMSK_ENUMDONEMSK_MASK |	/* Enumeration Done */
+	       HSOTG_INTMSK_USBRSTMSK_MASK |	/* USB Reset */
+	       HSOTG_INTMSK_USBSUSPMSK_MASK |	/* USB Suspend */
+	       HSOTG_INTMSK_ERLYSUSPMSK_MASK |	/* Early Suspend */
+	       HSOTG_INTMSK_OTGINTMSK_MASK,	/* OTG Interrupt */
+	       HSOTG_BASE_ADDR + HSOTG_INTMSK_OFFSET);
+
+	/* Device IN Endpoint Common Interrupt Mask Register */
+	writel(HSOTG_DIEPMSK_TIMEOUTMSK_MASK |	/* Timeout Condition */
+	       HSOTG_DIEPMSK_AHBERRMSK_MASK |	/* AHB Error */
+	       HSOTG_DIEPMSK_EPDISBLDMSK_MASK |	/* Endpoint Disabled */
+	       HSOTG_DIEPMSK_XFERCOMPLMSK_MASK,	/* Transfer Completed */
+	       HSOTG_BASE_ADDR + HSOTG_DIEPMSK_OFFSET);
+
+	/* Device OUT Endpoint Common Interrupt Mask Register */
+	writel(HSOTG_DOEPMSK_SETUPMSK_MASK |	/* SETUP Phase Done */
+	       HSOTG_DOEPMSK_AHBERRMSK_MASK |	/* AHB Error */
+	       HSOTG_DOEPMSK_EPDISBLDMSK_MASK |	/* Endpoint Disabled */
+	       HSOTG_DOEPMSK_XFERCOMPLMSK_MASK,	/* Transfer Completed */
+	       HSOTG_BASE_ADDR + HSOTG_DOEPMSK_OFFSET);
+
+	memset(ep0_setup_buf, 0, sizeof(ep0_setup_buf));
+
+	usb_ep0_setup_prime();
+	usb_clr_interrupt();
+
+	usb_phy_connect();
+
+	/* dataline or Vbus Pulsing */
+	mask =	HSOTG_CFG_SRPCAP_MASK |		/* SRP-Capable */
+		HSOTG_CFG_HNPCAP_MASK;		/* HNP-Capable */
+	wfld_set(HSOTG_BASE_ADDR + HSOTG_CFG_OFFSET, mask, mask);
+
+	mask =	HSOTG_OTGCTL_SESREQ_MASK;
+	wfld_set(HSOTG_BASE_ADDR + HSOTG_OTGCTL_OFFSET, mask, mask);
+
+	usb_speed = 0;
+
+	return 0;
+}
+
+void usb_handle_ints_otg(void)
+{
+	uint32_t regval;
+	uint32_t intsts;
+
+	intsts = readl(HSOTG_BASE_ADDR + HSOTG_INTSTS_OFFSET);
+
+	if (intsts) {
+		/* IN Endpoints Interrupt */
+		if (intsts & HSOTG_INTSTS_IEPINT_MASK) {
+			uint32_t daint = readl(HSOTG_BASE_ADDR +
+					       HSOTG_DAINT_OFFSET);
+
+#ifdef CONFIG_DEBUG_IEPINT
+			debug("daint = 0x%08X - I\n", daint);
+#endif
+
+			if (daint & (1 << (0 + HSOTG_DAINTMSK_INEPMSK_SHIFT)))
+				usb_handle_ep0_in_int();
+			if (daint & (1 << (1 + HSOTG_DAINTMSK_INEPMSK_SHIFT)))
+				usb_handle_ep1_in_int();
+		}
+
+		/* OUT Endpoints Interrupt */
+		if (intsts & HSOTG_INTSTS_OEPINT_MASK) {
+			uint32_t daint = readl(HSOTG_BASE_ADDR +
+					       HSOTG_DAINT_OFFSET);
+
+#ifdef CONFIG_DEBUG_OEPINT
+			debug("daint = 0x%08X - O\n", daint);
+#endif
+
+			if (daint & (1 << (0 + HSOTG_DAINTMSK_OUTEPMSK_SHIFT)))
+				usb_handle_ep0_out_int();
+			if (daint & (1 << (1 + HSOTG_DAINTMSK_OUTEPMSK_SHIFT)))
+				usb_handle_ep1_out_int();
+		}
+
+		/* OTG Interrupt */
+		if (intsts & HSOTG_INTSTS_OTGINT_MASK) {
+			debug("G\n");
+			/* clear OTG Interrupt Register */
+			regval = readl(HSOTG_BASE_ADDR + HSOTG_OTGINT_OFFSET);
+			writel(regval, HSOTG_BASE_ADDR + HSOTG_OTGINT_OFFSET);
+			debug("OTG: 0x%08X\n", regval);
+
+			/* Session Request Success Status Change */
+			if (regval & HSOTG_OTGINT_SESREQSUCSTSCHNG_MASK)
+				debug("r\n");
+
+			/* Session End Detected */
+			if (regval & HSOTG_OTGINT_SESENDDET_MASK) {
+				debug("e\n");
+				udelay(2500);
+				wfld_set(HSOTG_BASE_ADDR + HSOTG_OTGCTL_OFFSET,
+					 HSOTG_OTGCTL_SESREQ_MASK,
+					 HSOTG_OTGCTL_SESREQ_MASK);
+			}
+
+			/* Debounce Done */
+			if (regval & HSOTG_OTGINT_DBNCEDONE_MASK)
+				debug("d\n");
+
+			/* A-Device Timeout Change */
+			if (regval & HSOTG_OTGINT_ADEVTOUTCHG_MASK)
+				debug("a\n");
+		}
+
+		/* Enumeration Done */
+		if (intsts & HSOTG_INTSTS_ENUMDONE_MASK) {
+			debug("E\n");
+			usb_chirp_enum();
+			writel(HSOTG_INTSTS_ENUMDONE_MASK,
+			       HSOTG_BASE_ADDR + HSOTG_INTSTS_OFFSET);
+		}
+
+		/* Early Suspend */
+		if (intsts & HSOTG_INTSTS_ERLYSUSP_MASK) {
+			debug("eS\n");
+			writel(HSOTG_INTSTS_ERLYSUSP_MASK,
+			       HSOTG_BASE_ADDR + HSOTG_INTSTS_OFFSET);
+		}
+
+		/* USB Suspend */
+		if (intsts & HSOTG_INTSTS_USBSUSP_MASK) {
+			debug("Su\n");
+			writel(HSOTG_INTSTS_USBSUSP_MASK,
+			       HSOTG_BASE_ADDR + HSOTG_INTSTS_OFFSET);
+		}
+
+		/* Wake Up */
+		if (intsts & HSOTG_INTSTS_WKUPINT_MASK) {
+			usb_power_up();
+			debug("Rm\n");
+			writel(HSOTG_INTSTS_WKUPINT_MASK,
+			       HSOTG_BASE_ADDR + HSOTG_INTSTS_OFFSET);
+		}
+	}
+}
+
+int usb_send_bulk_otg(uint8_t *buffer, uint32_t len)
+{
+	return usb_send_data_ep1_in(buffer, len);
+}
+
+void usb_shutdown_otg(void)
+{
+	/* */
+	writel(0x04008C4C, HSOTG_CTRL_BASE_ADDR +
+			   HSOTG_CTRL_USBOTGCONTROL_OFFSET);
+
+	/* wait for clock to settle down before checking vbus */
+	udelay(32);
+
+	usb_wait_for_vbus();
+
+	usb_turn_off_vdp();
+}
diff --git a/drivers/usb/gadget/bcm_udc_otg.h b/drivers/usb/gadget/bcm_udc_otg.h
new file mode 100644
index 0000000..d5b1805
--- /dev/null
+++ b/drivers/usb/gadget/bcm_udc_otg.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2015 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __BCM_UDC_OTG_H
+#define __BCM_UDC_OTG_H
+
+#include <linux/types.h>
+
+typedef int (*rx_type)(const unsigned char *buffer, unsigned int buffer_size);
+
+int usb_init_otg(rx_type rx);
+void usb_handle_ints_otg(void);
+int usb_send_bulk_otg(uint8_t *buffer, uint32_t len);
+void usb_shutdown_otg(void);
+
+#endif
-- 
1.8.5



More information about the U-Boot mailing list