[coreboot-gerrit] New patch to review for coreboot: libpayload: add UDC driver for Designware controller

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Mon Jun 29 16:41:14 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10689

-gerrit

commit 37738995da8e88d9158870e1db158d5323bae27e
Author: huang lin <hl at rock-chips.com>
Date:   Wed May 20 17:27:10 2015 +0800

    libpayload: add UDC driver for Designware controller
    
    Found in rockchips rk3288 as used in google/veyron.
    
    BUG=None
    TEST=None
    BRANCH=None
    
    Change-Id: I2f2c36c5bea3986a8a37f84c75608b838a8782ae
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: 59a0bcd97e8d0f5ce5ac1301910e11b01e2d24b1
    Original-Change-Id: Ic89ed54c48d6f9ce125a93caf96471abc6e8cd9d
    Original-Signed-off-by: Yunzhi Li <lyz at rock-chips.com>
    Original-Reviewed-on: https://chromium-review.googlesource.com/272108
    Original-Reviewed-by: Julius Werner <jwerner at chromium.org>
    Original-Commit-Queue: Lin Huang <hl at rock-chips.com>
    Original-Tested-by: Lin Huang <hl at rock-chips.com>
---
 payloads/libpayload/Kconfig                      |   8 +
 payloads/libpayload/drivers/Makefile.inc         |   1 +
 payloads/libpayload/drivers/udc/dwc2.c           | 937 +++++++++++++++++++++++
 payloads/libpayload/drivers/udc/dwc2_priv.h      |  65 ++
 payloads/libpayload/drivers/usb/dwc2_private.h   | 616 +--------------
 payloads/libpayload/include/udc/dwc2_udc.h       |  27 +
 payloads/libpayload/include/usb/dwc2_registers.h | 802 +++++++++++++++++++
 7 files changed, 1841 insertions(+), 615 deletions(-)

diff --git a/payloads/libpayload/Kconfig b/payloads/libpayload/Kconfig
index 5c40170..77d4f6b 100644
--- a/payloads/libpayload/Kconfig
+++ b/payloads/libpayload/Kconfig
@@ -555,6 +555,14 @@ config UDC_CI
 	  Select this option to add the driver for ChipIdea
 	  USB device controller.
 
+config UDC_DWC2
+	bool "Designware driver for USB device mode"
+	depends on UDC
+	default n
+	help
+	  Select this option to add the driver for Designware
+	  USB device controller.
+
 endmenu
 
 menu "Debugging"
diff --git a/payloads/libpayload/drivers/Makefile.inc b/payloads/libpayload/drivers/Makefile.inc
index 57a82ac..25ff4fe 100644
--- a/payloads/libpayload/drivers/Makefile.inc
+++ b/payloads/libpayload/drivers/Makefile.inc
@@ -108,6 +108,7 @@ libc-$(CONFIG_LP_USB_DWC2) += usb/dwc2_rh.c
 # USB device stack
 libc-$(CONFIG_LP_UDC) += udc/udc.c
 libc-$(CONFIG_LP_UDC_CI) += udc/chipidea.c
+libc-$(CONFIG_LP_UDC_DWC2) += udc/dwc2.c
 
 # used by both USB HID and keyboard
 libc-y += hid.c
diff --git a/payloads/libpayload/drivers/udc/dwc2.c b/payloads/libpayload/drivers/udc/dwc2.c
new file mode 100644
index 0000000..99ee0b3
--- /dev/null
+++ b/payloads/libpayload/drivers/udc/dwc2.c
@@ -0,0 +1,937 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Rockchip Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <libpayload.h>
+#include <assert.h>
+#include <limits.h>
+
+#include <udc/dwc2_udc.h>
+#include "dwc2_priv.h"
+
+static int get_mps(dwc2_ep_t *ep)
+{
+	dwc2_ep_reg_t *ep_reg = ep->ep_regs;
+	depctl_t depctl;
+	uint16_t mps = 0;
+
+	depctl.d32 = readl(&ep_reg->depctl);
+	if (ep->ep_num == 0) {
+		switch (depctl.mps) {
+		case D0EPCTL_MPS_64:
+			mps = 64;
+			break;
+		case D0EPCTL_MPS_32:
+			mps = 32;
+			break;
+		case D0EPCTL_MPS_16:
+			mps = 16;
+			break;
+		case D0EPCTL_MPS_8:
+			mps = 8;
+			break;
+		default:
+			usb_debug("get mps error\n");
+		}
+	} else {
+		mps = depctl.mps;
+	}
+
+	return mps;
+}
+
+static void dwc2_process_ep(dwc2_ep_t *ep, int len, void *buf)
+{
+	depctl_t depctl;
+	depsiz_t depsiz;
+	uint16_t pkt_cnt;
+	uint16_t mps;
+	int max_transfer_size;
+	dwc2_ep_reg_t *ep_reg = ep->ep_regs;
+
+	if (ep->ep_num == 0)
+		max_transfer_size = EP0_MAXLEN;
+	else
+		max_transfer_size = EP_MAXLEN;
+	assert(len <= max_transfer_size);
+
+	mps = get_mps(ep);
+
+	pkt_cnt = ALIGN_UP(len, mps) / mps;
+	if (pkt_cnt == 0)
+		pkt_cnt = 1;
+
+	depsiz.pktcnt = pkt_cnt;
+	depsiz.xfersize = len;
+	writel(depsiz.d32, &ep_reg->deptsiz);
+
+	writel((uint32_t)buf, &ep_reg->depdma);
+
+	depctl.d32 = readl(&ep_reg->depctl);
+
+	if (ep->ep_num != 0) {
+		if (depctl.dpid == 0)
+			depctl.setd0pid = 1;
+		else
+			depctl.setd1pid = 1;
+	}
+	depctl.cnak = 1;
+	depctl.epena = 1;
+	writel(depctl.d32, &ep_reg->depctl);
+
+}
+
+static void dwc2_write_ep(dwc2_ep_t *ep, int len, void *buf)
+{
+	dwc2_process_ep(ep, len, buf);
+}
+
+static void dwc2_read_ep(dwc2_ep_t *ep, int len, void *buf)
+{
+	dwc2_process_ep(ep, len, buf);
+}
+
+static void dwc2_connect(struct usbdev_ctrl *this, int connect)
+{
+	/* Turn on the USB connection by enabling the pullup resistor */
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	dctl_t dctl;
+
+	usb_debug("DwcUdcConnect\n");
+
+	dctl.d32 = readl(&p->regs->device.dctl);
+
+	if (connect)
+		/* Connect */
+		dctl.sftdiscon = 0;
+	else
+		/* Disconnect */
+		dctl.sftdiscon = 1;
+
+	writel(dctl.d32, &p->regs->device.dctl);
+}
+
+static void dwc2_bus_reset(struct usbdev_ctrl *this)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	dcfg_t dcfg;
+	dctl_t dctl;
+
+	if (this->initialized)
+		this->initialized = 0;
+
+	/* Reset device addr */
+	dcfg.d32 = readl(&p->regs->device.dcfg);
+	dcfg.devaddr = 0;
+	writel(dcfg.d32, &p->regs->device.dcfg);
+
+	dctl.d32 = readl(&p->regs->device.dctl);
+	dctl.rmtwkupsig = 0;
+	writel(dctl.d32, &p->regs->device.dctl);
+}
+
+static void dwc2_enum_done(struct usbdev_ctrl *this)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+
+	dctl_t dctl;
+	dsts_t dsts;
+
+	usb_debug("dwc2_enum_done\n");
+
+	dsts.d32 = readl(&p->regs->device.dsts);
+
+	switch (dsts.enumspd) {
+	case 0:
+		this->ep_mps[0][0] = 64;
+		this->ep_mps[0][1] = 64;
+		usb_debug("HighSpeed Enum Done\n");
+		break;
+	default:
+		usb_debug("EnumSpeed Error\n");
+		return;
+	}
+
+	/* Clear global IN Nak */
+	dctl.d32 = readl(&p->regs->device.dctl);
+	dctl.cgnpinnak = 1;
+	writel(dctl.d32, &p->regs->device.dctl);
+}
+
+static void dwc2_tx_fifo_flush(struct usbdev_ctrl *this, unsigned int idx)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	grstctl_t grstctl;
+	int timeout = 100;
+
+	grstctl.d32 = readl(&p->regs->core.grstctl);
+	grstctl.txfflsh = 1;
+	grstctl.txfnum = idx;
+	writel(grstctl.d32, &p->regs->core.grstctl);
+
+	/* wait until the fifo is flushed */
+	do {
+		udelay(1);
+		grstctl.d32 = readl(&p->regs->core.grstctl);
+
+		if (--timeout < 0) {
+			usb_debug("timeout flushing Tx fifo %x\n", idx);
+			break;
+		}
+	} while (grstctl.txfflsh);
+}
+
+static void dwc2_rx_fifo_flush(struct usbdev_ctrl *this,  unsigned int idx)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	grstctl_t grstctl;
+	int timeout = 100;
+
+	grstctl.d32 = readl(&p->regs->core.grstctl);
+	grstctl.rxfflsh = 1;
+	writel(grstctl.d32, &p->regs->core.grstctl);
+
+	/* wait until the fifo is flushed */
+	do {
+		udelay(1);
+		grstctl.d32 = readl(&p->regs->core.grstctl);
+
+		if (--timeout < 0) {
+			usb_debug("timeout flushing Rx fifo %x\n", idx);
+			break;
+		}
+	} while (grstctl.rxfflsh);
+}
+
+static void dwc2_disable_ep(dwc2_ep_reg_t *ep_reg)
+{
+	depctl_t depctl;
+	depint_t depint;
+
+	/* Disable the required IN/OUT endpoint */
+	depctl.d32 = readl(&ep_reg->depctl);
+
+	/* Already disabled */
+	if (depctl.epena == 0)
+		return;
+	depctl.epdis = 1;
+	depctl.snak = 1;
+	writel(depctl.d32, &ep_reg->depctl);
+
+	/* Wait for the DEPINTn.EPDisabled interrupt */
+	do {
+		depint.d32 = readl(&ep_reg->depint);
+	} while (!depint.epdisbld);
+
+	/* Clear DEPINTn.EPDisabled */
+	writel(depint.d32, &ep_reg->depint);
+
+	depctl.d32 = readl(&ep_reg->depctl);
+	depctl.epena = 0;
+	depctl.epdis = 0;
+	writel(depctl.d32, &ep_reg->depctl);
+}
+
+static void dwc2_halt_ep(struct usbdev_ctrl *this, int ep, int in_dir)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	dwc2_ep_reg_t *ep_reg = p->eps[ep][in_dir].ep_regs;
+	depctl_t depctl;
+	dctl_t dctl;
+	gintsts_t gintsts;
+
+	usb_debug("dwc2_halt_ep ep %d-%d\n", ep, in_dir);
+	depctl.d32 = readl(&ep_reg->depctl);
+	/*Alread disabled*/
+	if (!depctl.epena)
+		return;
+	/* First step: disable EP */
+	if (in_dir) {
+		/* Only support Non-Periodic IN Endpoints */
+		dctl.d32 = readl(&p->regs->device.dctl);
+		dctl.sgnpinnak = 1;
+		writel(dctl.d32, &p->regs->device.dctl);
+
+		/* Wait for the GINTSTS.Global IN NP NAK Effective interrupt */
+		do {
+			gintsts.d32 = readl(&p->regs->core.gintsts);
+		} while (!gintsts.ginnakeff);
+
+		/* Clear GINTSTS.Global IN NP NAK Effective interrupt */
+		writel(gintsts.d32, &p->regs->core.gintsts);
+		dwc2_disable_ep(ep_reg);
+
+		/* Flush Tx Fifo */
+		dwc2_tx_fifo_flush(this, p->eps[ep][in_dir].txfifo);
+
+	} else {
+		/* Enable Global OUT NAK mode */
+		dctl.d32 = readl(&p->regs->device.dctl);
+		dctl.sgoutnak = 1;
+		writel(dctl.d32, &p->regs->device.dctl);
+
+		/* Wait for the GINTSTS.GOUTNakEff interrupt */
+		do {
+			gintsts.d32 = readl(&p->regs->core.gintsts);
+		} while (!gintsts.goutnakeff);
+
+		/* Clear GINTSTS.GOUTNakEff */
+		writel(gintsts.d32, &p->regs->core.gintsts);
+
+		dwc2_disable_ep(ep_reg);
+
+		dctl.d32 = readl(&p->regs->device.dctl);
+		dctl.cgoutnak = 1;
+		dctl.sgoutnak = 0;
+		writel(dctl.d32, &p->regs->device.dctl);
+	}
+
+	/* Second step: clear job queue */
+	while (!SIMPLEQ_EMPTY(&p->eps[ep][in_dir].job_queue)) {
+		struct job *job = SIMPLEQ_FIRST(&p->eps[ep][in_dir].job_queue);
+
+		if (job->autofree)
+			free(job->data);
+
+		SIMPLEQ_REMOVE_HEAD(&p->eps[ep][in_dir].job_queue, queue);
+	}
+}
+
+static int find_tx_fifo(struct usbdev_ctrl *this, uint32_t mps)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	uint32_t fifo_index = 0;
+	uint32_t fifo_size = UINT_MAX;
+	gnptxfsiz_t gnptxfsiz;
+	int i, val;
+
+	for (i = 1; i < MAX_EPS_CHANNELS - 1; i++) {
+		if (p->fifo_map & (1<<i))
+			continue;
+		gnptxfsiz.d32 = readl(&p->regs->core.dptxfsiz_dieptxf[i]);
+		val = gnptxfsiz.nptxfdep * 4;
+
+		if (val < mps)
+			continue;
+		/* Search for smallest acceptable fifo */
+		if (val < fifo_size) {
+			fifo_size = val;
+			fifo_index = i;
+		}
+	}
+
+	if (!fifo_index)
+		fatal("find_tx_fifo no suitable fifo found\n");
+
+	p->fifo_map |= 1 << fifo_index;
+
+	return fifo_index;
+
+}
+
+static void dwc2_start_ep0(struct usbdev_ctrl *this)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	depctl_t depctl = { .d32 = 0 };
+	depint_t depint = { .d32 = 0xff };
+
+	usb_debug("dwc2_start_ep0\n");
+
+	/* Enable endpoint, reset data toggle */
+	depctl.mps = 0;
+	depctl.usbactep = 1;
+	depctl.snak = 1;
+	depctl.epdis = 1;
+
+	writel(depctl.d32, &p->regs->device.inep[0].depctl);
+	writel(depint.d32, &p->regs->device.inep[0].depint);
+	writel(depctl.d32, &p->regs->device.outep[0].depctl);
+	writel(depint.d32, &p->regs->device.outep[0].depint);
+
+	p->eps[0][0].busy = 0;
+	p->eps[0][1].busy = 0;
+	this->ep_mps[0][0] = 64;
+	this->ep_mps[0][1] = 64;
+}
+
+static void dwc2_start_ep(struct usbdev_ctrl *this,
+			int ep, int in_dir, int ep_type, int mps)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	dwc2_ep_reg_t *ep_reg = p->eps[ep][in_dir].ep_regs;
+	depctl_t depctl = { .d32 = 0 };
+
+	assert((ep < 16) && (ep > 0));
+	usb_debug("dwc2_start_ep %d-%d (type %d)\n", ep, in_dir, ep_type);
+
+	in_dir = in_dir ? 1 : 0;
+
+	/* Enable endpoint, reset data toggle */
+	depctl.setd0pid = 1;
+	depctl.mps = mps & 0x3ff;
+	depctl.usbactep = 1;
+
+	/* ep type 0:ctrl 1:isoc 2:bulk 3:intr */
+	depctl.eptype = ep_type;
+	depctl.snak = 1;
+	if (in_dir) {
+		/* Allocate Tx FIFO */
+		p->eps[ep][in_dir].txfifo = find_tx_fifo(this, mps);
+	}
+	writel(depctl.d32, &ep_reg->depctl);
+
+	p->eps[ep][in_dir].busy = 0;
+	this->ep_mps[ep][in_dir] = mps;
+}
+
+static void continue_ep_transfer(dwc2_pdata_t *p,
+				 int endpoint, int in_dir)
+{
+	int max_transfer_size = (endpoint == 0) ? EP0_MAXLEN : EP_MAXLEN;
+	int mps;
+	uint32_t remind_length;
+	void *data_buf;
+
+	if (SIMPLEQ_EMPTY(&p->eps[endpoint][in_dir].job_queue))
+		return;
+
+	struct job *job = SIMPLEQ_FIRST(&p->eps[endpoint][in_dir].job_queue);
+
+	remind_length = job->length - job->xfered_length;
+
+	job->xfer_length = (remind_length > max_transfer_size) ?
+			    max_transfer_size : remind_length;
+	data_buf = job->data + job->xfered_length;
+
+	if ((((uint32_t)data_buf & 3) != 0) && (job->xfer_length > 0))
+		usb_debug("Un-aligned buffer address\n");
+
+	if (in_dir) {
+		dwc2_write_ep(&p->eps[endpoint][in_dir],
+			    job->xfer_length, data_buf);
+	} else {
+		mps = get_mps(&p->eps[endpoint][in_dir]);
+		job->xfer_length = ALIGN_UP(job->xfer_length, mps);
+		dwc2_read_ep(&p->eps[endpoint][0], job->xfer_length, data_buf);
+	}
+}
+
+static void start_ep_transfer(dwc2_pdata_t *p,
+			      int endpoint, int in_dir)
+{
+	int max_transfer_size = (endpoint == 0) ? EP0_MAXLEN : EP_MAXLEN;
+	int mps;
+
+	if (p->eps[endpoint][in_dir].busy) {
+		usb_debug("ep %d-%d busy\n", endpoint, in_dir);
+		return;
+	}
+
+	if (SIMPLEQ_EMPTY(&p->eps[endpoint][in_dir].job_queue)) {
+		usb_debug("ep %d-%d empty\n", endpoint, in_dir);
+		return;
+	}
+
+	struct job *job = SIMPLEQ_FIRST(&p->eps[endpoint][in_dir].job_queue);
+
+	job->xfer_length = (job->length > max_transfer_size) ?
+			    max_transfer_size : job->length;
+
+	if (in_dir) {
+		dwc2_write_ep(&p->eps[endpoint][1], job->xfer_length, job->data);
+	} else {
+		mps = get_mps(&p->eps[endpoint][0]);
+		job->xfer_length = ALIGN_UP(job->xfer_length, mps);
+		/* BUG */
+		if ((endpoint == 0) && (job->length == 0))
+			job->data = p->setup_buf;
+		dwc2_read_ep(&p->eps[endpoint][0], job->xfer_length, job->data);
+	}
+
+	usb_debug("start EP %d-%d with %zx bytes starting at %p\n", endpoint,
+	      in_dir, job->length, job->data);
+
+	p->eps[endpoint][in_dir].busy = 1;
+}
+
+static void dwc2_enqueue_packet(struct usbdev_ctrl *this, int endpoint,
+	int in_dir, void *data, int len, int zlp, int autofree)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	struct job *job = xzalloc(sizeof(*job));
+
+	job->data = data;
+	job->length = len;
+	job->zlp = zlp;
+	job->autofree = autofree;
+
+	usb_debug("adding job %d bytes to EP %d-%d\n", len, endpoint, in_dir);
+	SIMPLEQ_INSERT_TAIL(&p->eps[endpoint][in_dir].job_queue, job, queue);
+
+	if ((endpoint == 0) || (this->initialized))
+		start_ep_transfer(p, endpoint, in_dir);
+}
+
+static void complete_ep_transfer(struct usbdev_ctrl *this, int endpoint,
+				 int in_dir, int xfer_result)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	struct job *job = SIMPLEQ_FIRST(&p->eps[endpoint][in_dir].job_queue);
+	int mps = this->ep_mps[endpoint][in_dir];
+
+	if (in_dir) {
+		job->xfered_length += job->xfer_length - xfer_result;
+		if (job->xfered_length < job->length ||
+		    (job->xfered_length == job->length &&
+		     job->xfered_length % mps == 0 && job->xfer_length)) {
+			continue_ep_transfer(p, endpoint, in_dir);
+			return;
+		}
+	} else {
+		job->xfered_length += job->xfer_length - xfer_result;
+	}
+	SIMPLEQ_REMOVE_HEAD(&p->eps[endpoint][in_dir].job_queue, queue);
+
+	usb_debug("%d-%d: scheduled %zd, now %d bytes\n", endpoint, in_dir,
+	      job->length, job->xfered_length);
+
+	if (this->current_config &&
+	    this->current_config->interfaces[0].handle_packet)
+		this->current_config->interfaces[0].handle_packet(this,
+			endpoint, in_dir, job->data, job->xfered_length);
+
+	if (job->autofree)
+		free(job->data);
+	free(job);
+
+	p->eps[endpoint][in_dir].busy = 0;
+
+	if (endpoint == 0 && job->xfered_length == 0)
+		dwc2_enqueue_packet(this, 0, 0, p->setup_buf, 8, 0, 0);
+
+	start_ep_transfer(p, endpoint, in_dir);
+}
+
+static void dwc2_outep_intr(struct usbdev_ctrl *this, dwc2_ep_t *ep)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	depint_t depint;
+	depsiz_t depsiz;
+
+	depint.d32 = readl(&ep->ep_regs->depint) &
+		     readl(&p->regs->device.doepmsk);
+
+	/* Don't process XferCompl interrupt if it is a setup packet */
+	if ((ep->ep_num == 0) && (depint.setup || depint.stuppktrcvd))
+		depint.xfercompl = 0;
+
+	/* Transfer completed */
+	if (depint.xfercompl) {
+		usb_debug("DOEPINT_XFERCOMPL\n");
+		writel(DXEPINT_XFERCOMPL, &ep->ep_regs->depint);
+		depsiz.d32 = readl(&ep->ep_regs->deptsiz);
+
+		if (ep->ep_num == 0)
+			depsiz.xfersize &= 0x7f;
+
+		complete_ep_transfer(this, ep->ep_num, 0, depsiz.xfersize);
+	}
+	/* Endpoint disable */
+	if (depint.epdisbld) {
+		usb_debug("DEPINT_EPDISBLD\n");
+		writel(DXEPINT_EPDISBLD, &ep->ep_regs->depint);
+	}
+	/* AHB Error */
+	if (depint.ahberr) {
+		usb_debug("DEPINT_AHBERR\n");
+		writel(DXEPINT_AHBERR, &ep->ep_regs->depint);
+	}
+
+	/* Handle Setup Phase Done (Contorl Ep) */
+	if (depint.setup) {
+		usb_debug("DEPINT_SETUP\n");
+		writel(DXEPINT_SETUP, &ep->ep_regs->depint);
+#ifdef USB_DEBUG
+		hexdump((unsigned int)p->setup_buf, sizeof(dev_req_t));
+#endif
+		SIMPLEQ_REMOVE_HEAD(&p->eps[0][0].job_queue, queue);
+		p->eps[0][0].busy = 0;
+
+		udc_handle_setup(this, ep->ep_num, (dev_req_t *)p->setup_buf);
+	}
+}
+
+static void dwc2_inep_intr(struct usbdev_ctrl *this, dwc2_ep_t *ep)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	depint_t depint;
+	depsiz_t depsiz;
+
+	depint.d32 = readl(&ep->ep_regs->depint) &
+		     readl(&p->regs->device.doepmsk);
+
+	/* Don't process XferCompl interrupt if it is a setup packet */
+	if ((ep->ep_num == 0) && (depint.setup)) {
+		usb_debug("IN ep timeout\n");
+		writel(DXEPINT_TIMEOUT, &ep->ep_regs->depint);
+	}
+
+	/* Transfer completed */
+	if (depint.xfercompl) {
+		usb_debug("DIEPINT_XFERCOMPL\n");
+		writel(DXEPINT_XFERCOMPL, &ep->ep_regs->depint);
+		depsiz.d32 = readl(&ep->ep_regs->deptsiz);
+
+		if (ep->ep_num == 0)
+			depsiz.xfersize &= 0x7f;
+
+		complete_ep_transfer(this, ep->ep_num, 1, depsiz.xfersize);
+	}
+	/* Endpoint disable */
+	if (depint.epdisbld) {
+		usb_debug("DEPINT_EPDISBLD\n");
+		writel(DXEPINT_EPDISBLD, &ep->ep_regs->depint);
+	}
+	/* AHB Error */
+	if (depint.ahberr) {
+		usb_debug("DEPINT_AHBERR\n");
+		writel(DXEPINT_AHBERR, &ep->ep_regs->depint);
+	}
+}
+
+static int dwc2_check_irq(struct usbdev_ctrl *this)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	gintsts_t gintsts;
+	uint32_t daint, daint_out, daint_in, ep;
+
+	gintsts.d32 = readl(&p->regs->core.gintsts) &
+		      readl(&p->regs->core.gintmsk);
+
+	if (gintsts.d32 == 0)
+		return 1;
+
+	/* EP INTR */
+	if (gintsts.oepint || gintsts.iepint) {
+
+		daint = readl(&p->regs->device.daint) &
+			readl(&p->regs->device.daintmsk);
+
+		daint_out = daint >> DAINT_OUTEP_SHIFT;
+		daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT);
+
+		for (ep = 0; ep < MAX_EPS_CHANNELS; ep++, daint_in >>= 1) {
+			if (daint_in & 1)
+				dwc2_inep_intr(this, &p->eps[ep][1]);
+		}
+
+		for (ep = 0; ep < MAX_EPS_CHANNELS; ep++, daint_out >>= 1) {
+			if (daint_out & 1)
+				dwc2_outep_intr(this, &p->eps[ep][0]);
+		}
+	}
+
+	/* USB Bus Suspend */
+	if (gintsts.usbsusp) {
+		usb_debug("GINTSTS_ERLYSUSP\n");
+		writel(GINTSTS_USBSUSP, &p->regs->core.gintsts);
+	}
+	/* USB Bus Reset */
+	if (gintsts.usbrst) {
+		usb_debug("GINTSTS_USBRST\n");
+		dwc2_bus_reset(this);
+		writel(GINTSTS_USBRST, &p->regs->core.gintsts);
+	}
+	/* Enumeration done */
+	if (gintsts.enumdone) {
+		usb_debug("GINTSTS_ENUMDONE\n");
+		dwc2_enum_done(this);
+		writel(GINTSTS_ENUMDONE, &p->regs->core.gintsts);
+	}
+	if (gintsts.sessreqint) {
+		usb_debug("GINTSTS_SESSREQINT\n");
+		writel(GINTSTS_SESSREQINT, &p->regs->core.gintsts);
+	}
+	if (gintsts.wkupint) {
+		usb_debug("GINTSTS_WKUPINT\n");
+		writel(GINTSTS_WKUPINT, &p->regs->core.gintsts);
+	}
+
+	return 1;
+}
+
+static void dwc2_shutdown(struct usbdev_ctrl *this)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	int i, j;
+	int is_empty = 0;
+	gusbcfg_t gusbcfg;
+
+	while (!is_empty) {
+		is_empty = 1;
+		this->poll(this);
+		for (i = 0; i < 16; i++)
+			for (j = 0; j < 2; j++)
+				if (!SIMPLEQ_EMPTY(&p->eps[i][j].job_queue))
+					is_empty = 0;
+	}
+
+	/* Disconnect */
+	dwc2_connect(this, 0);
+
+	/* Back to normal otg mode */
+	gusbcfg.d32 = readl(&p->regs->core.gusbcfg);
+	gusbcfg.forcehstmode = 0;
+	gusbcfg.forcedevmode = 0;
+	writel(gusbcfg.d32, &p->regs->core.gusbcfg);
+
+	free(p);
+	free(this);
+}
+
+static void dwc2_set_address(struct usbdev_ctrl *this, int address)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	dcfg_t dcfg;
+
+	dcfg.d32 = readl(&p->regs->device.dcfg);
+	dcfg.devaddr = address;
+	writel(dcfg.d32, &p->regs->device.dcfg);
+}
+
+static void dwc2_stall(struct usbdev_ctrl *this,
+			     uint8_t ep, int in_dir, int set)
+{
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	dwc2_ep_reg_t *ep_reg = p->eps[ep][in_dir].ep_regs;
+	depctl_t depctl;
+
+	usb_debug("dwc2_stall\n");
+	depctl.d32 = readl(&ep_reg->depctl);
+
+	in_dir = in_dir ? 1 : 0;
+
+	if (set) {
+		depctl.stall = 1;
+		depctl.setd0pid = 1;
+		writel(depctl.d32, &ep_reg->depctl);
+	} else {
+		/* STALL bit will be clear by core */
+	}
+	this->ep_halted[ep][in_dir] = set;
+}
+
+static void *dwc2_malloc(size_t size)
+{
+	return dma_memalign(4096, size);
+}
+
+static void dwc2_free(void *ptr)
+{
+	free(ptr);
+}
+
+static int dwc2_reinit_udc(struct usbdev_ctrl *this, void *_opreg,
+			 const device_descriptor_t *dd)
+{
+	grstctl_t grstctl = { .d32 = 0 };
+	gintmsk_t gintmsk = { .d32 = 0 };
+	gahbcfg_t gahbcfg = { .d32 = 0 };
+	gusbcfg_t gusbcfg = { .d32 = 0 };
+	grxfsiz_t grxfsiz = { .d32 = 0 };
+	dtxfsiz_t dtxfsiz0 = { .d32 = 0 };
+	dtxfsiz_t dtxfsiz1 = { .d32 = 0 };
+	dtxfsiz_t dtxfsiz2 = { .d32 = 0 };
+	depint_t depint_msk = { .d32 = 0 };
+	dcfg_t dcfg = { .d32 = 0 };
+	dwc2_reg_t *regs = (dwc2_reg_t *)_opreg;
+	dwc2_pdata_t *p = DWC2_PDATA(this);
+	const int timeout = 10000;
+	int i;
+
+	p->regs = phys_to_virt(regs);
+	p->fifo_map = 0;
+	p->setup_buf = dma_memalign(4, 64);
+
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		/* Init OUT EPs */
+		p->eps[i][0].ep_num = i;
+		p->eps[i][0].ep_regs = &regs->device.outep[i];
+		SIMPLEQ_INIT(&p->eps[i][0].job_queue);
+
+		/* Init IN EPs */
+		p->eps[i][1].ep_num = i;
+		p->eps[i][1].ep_regs = &regs->device.inep[i];
+		SIMPLEQ_INIT(&p->eps[i][1].job_queue);
+	}
+
+	usb_debug("dwc2_hw_init\n");
+
+	/* Wait for AHB idle */
+	for (i = 0; i < timeout; i++) {
+		udelay(1);
+		grstctl.d32 = readl(&regs->core.grstctl);
+		if (grstctl.ahbidle)
+			break;
+	}
+	if (i == timeout) {
+		usb_debug("DWC2 Init error AHB Idle\n");
+		return 0;
+	}
+
+	/* Restart the Phy Clock */
+	/* Core soft reset */
+	grstctl.csftrst = 1;
+	writel(grstctl.d32, &regs->core.grstctl);
+	for (i = 0; i <= timeout; i++) {
+		udelay(1);
+		grstctl.d32 = readl(&regs->core.grstctl);
+		if (!grstctl.csftrst)
+			break;
+
+	if (i == timeout) {
+		usb_debug("DWC2 Init error reset fail\n");
+		return 0;
+		}
+	}
+
+	/* Restart the Phy Clock */
+	writel(0x0, &regs->pcgr.pcgcctl);
+
+	/* Set 16bit PHY if & Force host mode */
+	gusbcfg.d32 = readl(&regs->core.gusbcfg);
+	gusbcfg.phyif = 1;
+	gusbcfg.forcehstmode = 0;
+	gusbcfg.forcedevmode = 1;
+	writel(gusbcfg.d32, &regs->core.gusbcfg);
+
+	dcfg.d32 = readl(&regs->device.dcfg);
+	/* reset device addr */
+	dcfg.devaddr = 0;
+	/* enable HS */
+	dcfg.devspd = 0;
+	writel(dcfg.d32, &regs->device.dcfg);
+
+	dwc2_tx_fifo_flush(this, 0x10);
+	dwc2_rx_fifo_flush(this, 0);
+
+	grxfsiz.rxfdep = RX_FIFO_SIZE;
+	writel(grxfsiz.d32, &regs->core.grxfsiz);
+
+	dtxfsiz0.dtxfdep = DTX_FIFO_SIZE_0;
+	dtxfsiz0.dtxfstaddr = DTX_FIFO_SIZE_0_OFFSET;
+	writel(dtxfsiz0.d32, &regs->core.gnptxfsiz);
+
+	dtxfsiz1.dtxfdep = DTX_FIFO_SIZE_1;
+	dtxfsiz1.dtxfstaddr = DTX_FIFO_SIZE_1_OFFSET;
+	writel(dtxfsiz1.d32, &regs->core.dptxfsiz_dieptxf[0]);
+
+	dtxfsiz2.dtxfdep = DTX_FIFO_SIZE_2;
+	dtxfsiz2.dtxfstaddr = DTX_FIFO_SIZE_2_OFFSET;
+	writel(dtxfsiz2.d32, &regs->core.dptxfsiz_dieptxf[1]);
+
+	/* Config Ep0 */
+	dwc2_start_ep0(this);
+
+	dwc2_enqueue_packet(this, 0, 0, p->setup_buf, 8, 0, 0);
+
+	depint_msk.xfercompl = 1;
+	depint_msk.epdisbld = 1;
+	depint_msk.ahberr = 1;
+	depint_msk.setup = 1;
+
+	/* device IN interrupt mask */
+	writel(depint_msk.d32, &regs->device.diepmsk);
+	/* device OUT interrupt mask */
+	writel(depint_msk.d32, &regs->device.doepmsk);
+
+	/* Clear all pending interrupt */
+	writel(0xffffffff, &regs->device.daint);
+
+	/* Config core interface regs */
+	writel(0xffffffff, &regs->core.gintsts);
+	writel(0xffffffff, &regs->core.gotgint);
+
+	/* Enable device endpoint interrupt */
+	writel(0xffffffff, &regs->device.daintmsk);
+
+	gintmsk.usbsusp = 1;
+	gintmsk.usbrst = 1;
+	gintmsk.enumdone = 1;
+	gintmsk.sessreqint = 1;
+	gintmsk.iepint = 1;
+	gintmsk.oepint = 1;
+	writel(gintmsk.d32, &regs->core.gintmsk);
+
+	gahbcfg.d32 = readl(&regs->core.gahbcfg);
+	gahbcfg.dmaen = 1;
+	gahbcfg.glblintrmsk = 1;
+	gahbcfg.hbstlen = DMA_BURST_INCR16;
+	writel(gahbcfg.d32, &regs->core.gahbcfg);
+
+	dwc2_connect(this, 1);
+
+	return 1;
+
+}
+
+struct usbdev_ctrl *dwc2_udc_init(device_descriptor_t *dd)
+{
+	struct usbdev_ctrl *ctrl = calloc(1, sizeof(*ctrl));
+	int i;
+
+	usb_debug("dwc2_udc_init\n");
+	if (ctrl == NULL)
+		return NULL;
+
+	ctrl->pdata = calloc(1, sizeof(dwc2_pdata_t));
+	if (ctrl->pdata == NULL) {
+		free(ctrl);
+		return NULL;
+	}
+	memcpy(&ctrl->device_descriptor, dd, sizeof(*dd));
+	SLIST_INIT(&ctrl->configs);
+
+	ctrl->poll = dwc2_check_irq;
+	ctrl->add_gadget = udc_add_gadget;
+	ctrl->enqueue_packet = dwc2_enqueue_packet;
+	ctrl->shutdown = dwc2_shutdown;
+	ctrl->set_address = dwc2_set_address;
+	ctrl->stall = dwc2_stall;
+	ctrl->halt_ep = dwc2_halt_ep;
+	ctrl->start_ep = dwc2_start_ep;
+	ctrl->alloc_data = dwc2_malloc;
+	ctrl->free_data = dwc2_free;
+	ctrl->initialized = 0;
+
+	ctrl->ep_mps[0][0] = 64;
+	ctrl->ep_mps[0][1] = 64;
+	for (i = 1; i < 16; i++) {
+		ctrl->ep_mps[i][0] = 512;
+		ctrl->ep_mps[i][1] = 512;
+	}
+
+	if (!dwc2_reinit_udc(ctrl, (void *)0xff580000, dd)) {
+		free(ctrl->pdata);
+		free(ctrl);
+		return NULL;
+	}
+
+	return ctrl;
+}
+
diff --git a/payloads/libpayload/drivers/udc/dwc2_priv.h b/payloads/libpayload/drivers/udc/dwc2_priv.h
new file mode 100644
index 0000000..8ea4c3a
--- /dev/null
+++ b/payloads/libpayload/drivers/udc/dwc2_priv.h
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Rockchip Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DWC2_PRIV_H__
+#define __DWC2_PRIV_H__
+#include <usb/dwc2_registers.h>
+
+#define EP_MAXLEN	(64 * 1024)
+#define EP0_MAXLEN	64
+
+#define RX_FIFO_SIZE			0x210
+#define DTX_FIFO_SIZE_0_OFFSET		RX_FIFO_SIZE
+#define DTX_FIFO_SIZE_0			0x10
+#define DTX_FIFO_SIZE_1_OFFSET		(DTX_FIFO_SIZE_0_OFFSET +\
+					 DTX_FIFO_SIZE_0)
+#define DTX_FIFO_SIZE_1			0x100
+#define DTX_FIFO_SIZE_2_OFFSET		(DTX_FIFO_SIZE_1_OFFSET +\
+					 DTX_FIFO_SIZE_1)
+#define DTX_FIFO_SIZE_2			0x10
+
+struct job {
+	SIMPLEQ_ENTRY(job) queue; // linkage
+	void *data;
+	size_t length;
+	size_t xfered_length;
+	size_t xfer_length;
+	int zlp; // append zero length packet?
+	int autofree; // free after processing?
+};
+SIMPLEQ_HEAD(job_queue, job);
+
+typedef struct dwc2_ep {
+	dwc2_ep_reg_t *ep_regs;
+	struct job_queue job_queue;
+	unsigned txfifo:5;
+	unsigned busy:1;
+	unsigned ep_num:8;
+} dwc2_ep_t;
+
+typedef struct dwc2_pdata {
+	dwc2_reg_t *regs;
+	dwc2_ep_t eps[MAX_EPS_CHANNELS][2];
+	uint32_t fifo_map;
+	void *setup_buf;
+} dwc2_pdata_t;
+
+#define DWC2_PDATA(ctrl) ((dwc2_pdata_t *)((ctrl)->pdata))
+
+#endif
diff --git a/payloads/libpayload/drivers/usb/dwc2_private.h b/payloads/libpayload/drivers/usb/dwc2_private.h
index fa65f8b..7e6621d 100644
--- a/payloads/libpayload/drivers/usb/dwc2_private.h
+++ b/payloads/libpayload/drivers/usb/dwc2_private.h
@@ -19,621 +19,7 @@
 
 #ifndef __DWC2_REGS_H__
 #define __DWC2_REGS_H__
-#define MAX_EPS_CHANNELS 16
-
-typedef struct core_reg {
-	uint32_t gotgctl;
-	uint32_t gotgint;
-	uint32_t gahbcfg;
-	uint32_t gusbcfg;
-	uint32_t grstctl;
-	uint32_t gintsts;
-	uint32_t gintmsk;
-	uint32_t grxstsr;
-	uint32_t grxstsp;
-	uint32_t grxfsiz;
-	uint32_t gnptxfsiz;
-	uint32_t gnptxsts;
-	uint32_t gi2cctl;
-	uint32_t gpvndctl;
-	uint32_t ggpio;
-	uint32_t guid;
-	uint32_t gsnpsid;
-	uint32_t ghwcfg1;
-	uint32_t ghwcfg2;
-	uint32_t ghwcfg3;
-	uint32_t ghwcfg4;
-	uint32_t reserved1[(0x100 - 0x54) / 4];
-	uint32_t hptxfsiz;
-	uint32_t dptxfsiz_dieptxf[15];
-	uint32_t reserved2[(0x400 - 0x140) / 4];
-} core_reg_t;
-
-typedef struct hc_reg {
-	uint32_t hccharn;
-	uint32_t hcspltn;
-	uint32_t hcintn;
-	uint32_t hcintmaskn;
-	uint32_t hctsizn;
-	uint32_t hcdman;
-	uint32_t reserved[2];
-} hc_reg_t;
-
-/* Host Mode Register Structures */
-typedef struct host_reg {
-	uint32_t hcfg;
-	uint32_t hfir;
-	uint32_t hfnum;
-	uint32_t reserved0;
-	uint32_t hptxsts;
-	uint32_t haint;
-	uint32_t haintmsk;
-	uint32_t reserved1[(0x440 - 0x41c) / 4];
-	uint32_t hprt;
-	uint32_t reserved2[(0x500 - 0x444) / 4];
-	hc_reg_t hchn[MAX_EPS_CHANNELS];
-	uint32_t reserved3[(0x800 - 0x700) / 4];
-} host_reg_t;
-
-/* Device IN ep reg */
-typedef struct in_ep_reg {
-	uint32_t diepctl;
-	uint32_t reserved04;
-	uint32_t diepint;
-	uint32_t reserved0c;
-	uint32_t dieptsiz;
-	uint32_t diepdma;
-	uint32_t dtxfsts;
-	uint32_t diepdmab;
-} in_ep_reg_t;
-
-typedef struct out_ep_reg {
-	uint32_t doepctl;
-	uint32_t reserved04;
-	uint32_t doepint;
-	uint32_t reserved0c;
-	uint32_t doeptsiz;
-	uint32_t doepdma;
-	uint32_t reserved18;
-	uint32_t doepdmab;
-} out_ep_reg_t;
-
-/* Device Mode Registers Structures */
-typedef struct device_reg {
-	uint32_t dcfg;
-	uint32_t dctl;
-	uint32_t dsts;
-	uint32_t unused;
-	uint32_t diepmsk;
-	uint32_t doepmsk;
-	uint32_t daint;
-	uint32_t daintmsk;
-	uint32_t dtknqr1;
-	uint32_t dtknqr2;
-	uint32_t dvbusdis;
-	uint32_t dvbuspulse;
-	uint32_t dtknqr3_dthrctl;
-	uint32_t dtknqr4_fifoemptymsk;
-	uint32_t reserved1[(0x900 - 0x838) / 4];
-
-	in_ep_reg_t inep[MAX_EPS_CHANNELS];
-	out_ep_reg_t outep[MAX_EPS_CHANNELS];
-	uint32_t reserved8[(0xe00 - 0xd00) / 4];
-} device_reg_t;
-
-typedef struct pwr_clk_ctrl_reg {
-	uint32_t pcgcctl;
-	uint32_t reserved[(0x1000 - 0xe04) / 4];
-} pwr_clk_ctrl_reg_t;
-
-typedef struct data_fifo {
-	uint32_t dataport;
-	uint32_t reserved[(0x1000 - 0x004) / 4];
-} data_fifo_t;
-
-typedef struct dwc2_otg_reg {
-	core_reg_t core;
-	host_reg_t host;
-	device_reg_t device;
-	pwr_clk_ctrl_reg_t pcgr;
-	data_fifo_t dfifo[MAX_EPS_CHANNELS];
-	uint32_t reserved[(0x40000 - 0x11000) / 4];
-} dwc2_reg_t;
-
-/**
- * This union represents the bit fields of the Core AHB Configuration
- * Register (GAHBCFG).
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	struct {
-		unsigned glblintrmsk:1;
-#define GLBINT_ENABLE 1
-
-		unsigned hbstlen:4;
-#define DMA_BURST_SINGLE 0
-#define DMA_BURST_INCR 1
-#define DMA_BURST_INCR4 3
-#define DMA_BURST_INCR8 5
-#define DMA_BURST_INCR16 7
-
-		unsigned dmaen:1;
-		unsigned reserved:1;
-		unsigned nptxfemplvl:1;
-		unsigned ptxfemplvl:1;
-		unsigned reserved9_31:23;
-	};
-} gahbcfg_t;
-
-/**
- * This union represents the bit fields of the Core USB Configuration
- * Register (GUSBCFG).
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	struct {
-		unsigned toutcal:3;
-		unsigned phyif:1;
-		unsigned ulpiutmisel:1;
-		unsigned fsintf:1;
-		unsigned physel:1;
-		unsigned ddrsel:1;
-		unsigned srpcap:1;
-		unsigned hnpcap:1;
-		unsigned usbtrdtim:4;
-		unsigned reserved14:1;
-		unsigned phylpwrclksel:1;
-		unsigned otgi2csel:1;
-		unsigned ulpifsls:1;
-		unsigned ulpiautores:1;
-		unsigned ulpiclksusm:1;
-		unsigned ulpiextvbusdrv:1;
-		unsigned ulpiextvbusindicator:1;
-		unsigned termseldlpulse:1;
-		unsigned reserved23_28:6;
-		unsigned forcehstmode:1;
-		unsigned forcedevmode:1;
-		unsigned cortxpkt:1;
-	};
-} gusbcfg_t;
-
-/**
- * This union represents the bit fields of the Core Reset Register
- * (GRSTCTL).
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	struct {
-		/** Core Soft Reset (CSftRst) (Device and Host)
-		 *
-		 * The application can flush the control logic in the
-		 * entire core using this bit. This bit resets the
-		 * pipelines in the AHB Clock domain as well as the
-		 * PHY Clock domain.
-		 *
-		 * The state machines are reset to an IDLE state, the
-		 * control bits in the CSRs are cleared, all the
-		 * transmit FIFOs and the receive FIFO are flushed.
-		 *
-		 * The status mask bits that control the generation of
-		 * the interrupt, are cleared, to clear the
-		 * interrupt. The interrupt status bits are not
-		 * cleared, so the application can get the status of
-		 * any events that occurred in the core after it has
-		 * set this bit.
-		 *
-		 * Any transactions on the AHB are terminated as soon
-		 * as possible following the protocol. Any
-		 * transactions on the USB are terminated immediately.
-		 *
-		 * The configuration settings in the CSRs are
-		 * unchanged, so the software doesn't have to
-		 * reprogram these registers (Device
-		 * Configuration/Host Configuration/Core System
-		 * Configuration/Core PHY Configuration).
-		 *
-		 * The application can write to this bit, any time it
-		 * wants to reset the core. This is a self clearing
-		 * bit and the core clears this bit after all the
-		 * necessary logic is reset in the core, which may
-		 * take several clocks, depending on the current state
-		 * of the core.
-		 */
-		unsigned csftrst:1;
-		/** Hclk Soft Reset
-		 *
-		 * The application uses this bit to reset the control logic in
-		 * the AHB clock domain. Only AHB clock domain pipelines are
-		 * reset.
-		 */
-		unsigned hsftrst:1;
-		/** Host Frame Counter Reset (Host Only)<br>
-		 *
-		 * The application can reset the (micro)frame number
-		 * counter inside the core, using this bit. When the
-		 * (micro)frame counter is reset, the subsequent SOF
-		 * sent out by the core, will have a (micro)frame
-		 * number of 0.
-		 */
-		unsigned frmcntrrst:1;
-		/** In Token Sequence Learning Queue Flush
-		 * (INTknQFlsh) (Device Only)
-		 */
-		unsigned intknqflsh:1;
-		/** RxFIFO Flush (RxFFlsh) (Device and Host)
-		 *
-		 * The application can flush the entire Receive FIFO
-		 * using this bit.	<p>The application must first
-		 * ensure that the core is not in the middle of a
-		 * transaction.	 <p>The application should write into
-		 * this bit, only after making sure that neither the
-		 * DMA engine is reading from the RxFIFO nor the MAC
-		 * is writing the data in to the FIFO.	<p>The
-		 * application should wait until the bit is cleared
-		 * before performing any other operations. This bit
-		 * will takes 8 clocks (slowest of PHY or AHB clock)
-		 * to clear.
-		 */
-		unsigned rxfflsh:1;
-		/** TxFIFO Flush (TxFFlsh) (Device and Host).
-		 *
-		 * This bit is used to selectively flush a single or
-		 * all transmit FIFOs.	The application must first
-		 * ensure that the core is not in the middle of a
-		 * transaction.	 <p>The application should write into
-		 * this bit, only after making sure that neither the
-		 * DMA engine is writing into the TxFIFO nor the MAC
-		 * is reading the data out of the FIFO.	 <p>The
-		 * application should wait until the core clears this
-		 * bit, before performing any operations. This bit
-		 * will takes 8 clocks (slowest of PHY or AHB clock)
-		 * to clear.
-		 */
-		unsigned txfflsh:1;
-
-		/** TxFIFO Number (TxFNum) (Device and Host).
-		 *
-		 * This is the FIFO number which needs to be flushed,
-		 * using the TxFIFO Flush bit. This field should not
-		 * be changed until the TxFIFO Flush bit is cleared by
-		 * the core.
-		 *	 - 0x0 : Non Periodic TxFIFO Flush
-		 *	 - 0x1 : Periodic TxFIFO #1 Flush in device mode
-		 *	   or Periodic TxFIFO in host mode
-		 *	 - 0x2 : Periodic TxFIFO #2 Flush in device mode.
-		 *	 - ...
-		 *	 - 0xF : Periodic TxFIFO #15 Flush in device mode
-		 *	 - 0x10: Flush all the Transmit NonPeriodic and
-		 *	   Transmit Periodic FIFOs in the core
-		 */
-		unsigned txfnum:5;
-		/** Reserved */
-		unsigned reserved11_29:19;
-		/** DMA Request Signal.	 Indicated DMA request is in
-		 * probress.  Used for debug purpose. */
-		unsigned dmareq:1;
-		/** AHB Master Idle.  Indicates the AHB Master State
-		 * Machine is in IDLE condition. */
-		unsigned ahbidle:1;
-	} ;
-} grstctl_t;
-
-/**
- * This union represents the bit fields of the Core Interrupt Mask
- * Register (GINTMSK).
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	struct {
-		unsigned curmod:1;
-		unsigned modemis:1;
-		unsigned otgint:1;
-		unsigned sof:1;
-		unsigned rxflvl:1;
-		unsigned nptxfemp:1;
-		unsigned ginnakeff:1;
-		unsigned goutnakeff:1;
-		unsigned reserved8:1;
-		unsigned i2cint:1;
-		unsigned erlysusp:1;
-		unsigned usbsusp:1;
-		unsigned usbrst:1;
-		unsigned enumdone:1;
-		unsigned isooutdrop:1;
-		unsigned eopf:1;
-		unsigned reserved16_20:5;
-		unsigned incompip:1;
-		unsigned reserved22_23:2;
-		unsigned prtint:1;
-		unsigned hchint:1;
-		unsigned ptxfemp:1;
-		unsigned reserved27:1;
-		unsigned conidstschng:1;
-		unsigned disconnint:1;
-		unsigned sessreqint:1;
-		unsigned wkupint:1;
-	} ;
-} gintmsk_t;
-
-/**
-* This union represents the bit fields of the Core Non-Periodic
-* Transmit FIFO Size Register(GNPTXFSIZ).
-*/
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	struct {
-		unsigned nptxfstaddr:16;
-		unsigned nptxfdep:16;
-	};
-} gnptxfsiz_t;
-
-/**
- * This union represents the bit fields of the Core Receive FIFO Size
- * Register(GRXFSIZ).
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	/*The value in this fieles is in terms of 32-bit words size.
-	 */
-	struct {
-		unsigned rxfdep:16;
-		unsigned reserved:16;
-	};
-} grxfsiz_t;
-
-/**
- * This union represents the bit fields of the Core Interrupt Register
- * (GINTSTS).
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-#define SOF_INTR_MASK 0x0008
-	/* register bits */
-	struct {
-		unsigned curmod:1;
-#define HOST_MODE 1
-#define DEVICE_MODE 0
-		unsigned modemis:1;
-		unsigned otgint:1;
-		unsigned sof:1;
-		unsigned rxflvl:1;
-		unsigned nptxfemp:1;
-		unsigned ginnakeff:1;
-		unsigned goutnakeff:1;
-		unsigned reserved8:1;
-		unsigned i2cint:1;
-		unsigned erlysusp:1;
-		unsigned usbsusp:1;
-		unsigned usbrst:1;
-		unsigned enumdone:1;
-		unsigned isooutdrop:1;
-		unsigned eopf:1;
-		unsigned reserved16_20:5;
-		unsigned incompip:1;
-		unsigned reserved22_23:2;
-		unsigned prtint:1;
-		unsigned hchint:1;
-		unsigned ptxfemp:1;
-		unsigned reserved27:1;
-		unsigned conidstschng:1;
-		unsigned disconnint:1;
-		unsigned sessreqint:1;
-		unsigned wkupint:1;
-	};
-} gintsts_t;
-
-/**
- * This union represents the bit fields of the User HW Config3 Register
- * (GHWCFG3).
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	struct {
-		unsigned reserved:16;
-		unsigned dfifodepth:16;
-	};
-} ghwcfg3_t;
-
-/**
- * This union represents the bit fields in the Host Configuration Register.
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-
-	/* register bits */
-	struct {
-		/** FS/LS Phy Clock Select */
-		unsigned fslspclksel:2;
-#define PHYCLK_30_60_MHZ 0
-#define PHYCLK_48_MHZ 1
-#define PHYCLK_6_MHZ 2
-
-		/** FS/LS Only Support */
-		unsigned fslssupp:1;
-	};
-} hcfg_t;
-
-/**
- * This union represents the bit fields in the Host Port Control and status
- * Register.
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	struct {
-		unsigned prtconnsts:1;
-		unsigned prtconndet:1;
-		unsigned prtena:1;
-		unsigned prtenchng:1;
-		unsigned prtovrcurract:1;
-		unsigned prtovrcurrchng:1;
-		unsigned prtres:1;
-		unsigned prtsusp:1;
-		unsigned prtrst:1;
-		unsigned reserved9:1;
-		unsigned prtlnsts:2;
-		unsigned prtpwr:1;
-		unsigned prttstctl:4;
-		unsigned prtspd:2;
-#define PRTSPD_HIGH 0
-#define PRTSPD_FULL 1
-#define PRTSPD_LOW	2
-		unsigned reserved19_31:13;
-	};
-} hprt_t;
-/* Mask W1C bits */
-#define HPRT_W1C_MASK (~((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5)))
-
-/**
- * This union represents the bit fields in the Host Channel Characteristics
- * Register.
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-
-	/* register bits */
-	struct {
-		/** Maximum packet size in bytes */
-		unsigned mps:11;
-		/** Endpoint number */
-		unsigned epnum:4;
-		/** 0: OUT, 1: IN */
-		unsigned epdir:1;
-		unsigned reserved:1;
-		/** 0: Full/high speed device, 1: Low speed device */
-		unsigned lspddev:1;
-		/** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
-		unsigned eptype:2;
-		/** Packets per frame for periodic transfers. 0 is reserved. */
-		unsigned multicnt:2;
-		/** Device address */
-		unsigned devaddr:7;
-		/**
-		 * Frame to transmit periodic transaction.
-		 * 0: even, 1: odd
-		 */
-		unsigned oddfrm:1;
-		/** Channel disable */
-		unsigned chdis:1;
-		/** Channel enable */
-		unsigned chen:1;
-	};
-} hcchar_t;
-
-typedef enum {
-	EPDIR_OUT = 0,
-	EPDIR_IN,
-} ep_dir_t;
-
-/**
- * This union represents the bit fields in the Host All Interrupt
- * Register.
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	struct {
-		/** Transfer Complete */
-		unsigned xfercomp:1;
-		/** Channel Halted */
-		unsigned chhltd:1;
-		/** AHB Error */
-		unsigned ahberr:1;
-		/** STALL Response Received */
-		unsigned stall:1;
-		/** NAK Response Received */
-		unsigned nak:1;
-		/** ACK Response Received */
-		unsigned ack:1;
-		/** NYET Response Received */
-		unsigned nyet:1;
-		/** Transaction Err */
-		unsigned xacterr:1;
-		/** Babble Error */
-		unsigned bblerr:1;
-		/** Frame Overrun */
-		unsigned frmovrun:1;
-		/** Data Toggle Error */
-		unsigned datatglerr:1;
-		/** Reserved */
-		unsigned reserved:21;
-	};
-} hcint_t;
-
-/**
- * This union represents the bit fields in the Host Channel Transfer Size
- * Register.
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-
-	/* register bits */
-	struct {
-		/* Total transfer size in bytes */
-		unsigned xfersize:19;
-		/** Data packets to transfer */
-		unsigned pktcnt:10;
-		/**
-		 * Packet ID for next data packet
-		 * 0: DATA0
-		 * 1: DATA2
-		 * 2: DATA1
-		 * 3: MDATA (non-Control), SETUP (Control)
-		 */
-		unsigned pid:2;
-#define PID_DATA0 0
-#define PID_DATA1 2
-#define PID_DATA2 1
-#define PID_MDATA 3
-#define PID_SETUP 3
-		/* Do PING protocol when 1 */
-		unsigned dopng:1;
-	};
-} hctsiz_t;
-
-/**
- * This union represents the bit fields in the Host Channel Interrupt Mask
- * Register.
- */
-typedef union {
-	/* raw register data */
-	uint32_t d32;
-	/* register bits */
-	struct {
-		unsigned xfercomp:1;
-		unsigned chhltd:1;
-		unsigned ahberr:1;
-		unsigned stall:1;
-		unsigned nak:1;
-		unsigned ack:1;
-		unsigned nyet:1;
-		unsigned xacterr:1;
-		unsigned bblerr:1;
-		unsigned frmovrun:1;
-		unsigned datatglerr:1;
-		unsigned reserved:21;
-	};
-} hcintmsk_t;
+#include <usb/dwc2_registers.h>
 
 typedef struct dwc_ctrl {
 #define DMA_SIZE (64 * 1024)
diff --git a/payloads/libpayload/include/udc/dwc2_udc.h b/payloads/libpayload/include/udc/dwc2_udc.h
new file mode 100644
index 0000000..741a360
--- /dev/null
+++ b/payloads/libpayload/include/udc/dwc2_udc.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Rockchip Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __DESIGNWARE_H__
+#define __DESIGNWARE_H__
+
+#include "udc.h"
+
+struct usbdev_ctrl *dwc2_udc_init(device_descriptor_t *dd);
+
+#endif
diff --git a/payloads/libpayload/include/usb/dwc2_registers.h b/payloads/libpayload/include/usb/dwc2_registers.h
new file mode 100644
index 0000000..b6ae2ed
--- /dev/null
+++ b/payloads/libpayload/include/usb/dwc2_registers.h
@@ -0,0 +1,802 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Rockchip Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __DWC2_REGISTERS__
+#define __DWC2_REGISTERS__
+
+#define MAX_EPS_CHANNELS 16
+
+typedef struct core_reg {
+	uint32_t gotgctl;
+	uint32_t gotgint;
+	uint32_t gahbcfg;
+	uint32_t gusbcfg;
+	uint32_t grstctl;
+	uint32_t gintsts;
+	uint32_t gintmsk;
+	uint32_t grxstsr;
+	uint32_t grxstsp;
+	uint32_t grxfsiz;
+	uint32_t gnptxfsiz;
+	uint32_t gnptxsts;
+	uint32_t gi2cctl;
+	uint32_t gpvndctl;
+	uint32_t ggpio;
+	uint32_t guid;
+	uint32_t gsnpsid;
+	uint32_t ghwcfg1;
+	uint32_t ghwcfg2;
+	uint32_t ghwcfg3;
+	uint32_t ghwcfg4;
+	uint32_t reserved1[(0x100 - 0x54) / 4];
+	uint32_t hptxfsiz;
+	uint32_t dptxfsiz_dieptxf[MAX_EPS_CHANNELS - 1];
+	uint32_t reserved2[(0x400 - 0x140) / 4];
+} core_reg_t;
+
+typedef struct hc_reg {
+	uint32_t hccharn;
+	uint32_t hcspltn;
+	uint32_t hcintn;
+	uint32_t hcintmaskn;
+	uint32_t hctsizn;
+	uint32_t hcdman;
+	uint32_t reserved[2];
+} hc_reg_t;
+
+/* Host Mode Register Structures */
+typedef struct host_reg {
+	uint32_t hcfg;
+	uint32_t hfir;
+	uint32_t hfnum;
+	uint32_t reserved0;
+	uint32_t hptxsts;
+	uint32_t haint;
+	uint32_t haintmsk;
+	uint32_t reserved1[(0x440 - 0x41c) / 4];
+	uint32_t hprt;
+	uint32_t reserved2[(0x500 - 0x444) / 4];
+	hc_reg_t hchn[MAX_EPS_CHANNELS];
+	uint32_t reserved3[(0x800 - 0x700) / 4];
+} host_reg_t;
+
+typedef struct ep_reg {
+	uint32_t depctl;
+	uint32_t reserved04;
+	uint32_t depint;
+	uint32_t reserved0c;
+	uint32_t deptsiz;
+	uint32_t depdma;
+	uint32_t reserved18;
+	uint32_t depdmab;
+} dwc2_ep_reg_t;
+
+/* Device Mode Registers Structures */
+typedef struct device_reg {
+	uint32_t dcfg;
+	uint32_t dctl;
+	uint32_t dsts;
+	uint32_t unused;
+	uint32_t diepmsk;
+	uint32_t doepmsk;
+	uint32_t daint;
+	uint32_t daintmsk;
+	uint32_t dtknqr1;
+	uint32_t dtknqr2;
+	uint32_t dvbusdis;
+	uint32_t dvbuspulse;
+	uint32_t dtknqr3_dthrctl;
+	uint32_t dtknqr4_fifoemptymsk;
+	uint32_t reserved1[(0x900 - 0x838) / 4];
+
+	dwc2_ep_reg_t inep[MAX_EPS_CHANNELS];
+	dwc2_ep_reg_t outep[MAX_EPS_CHANNELS];
+	uint32_t reserved8[(0xe00 - 0xd00) / 4];
+} device_reg_t;
+
+typedef struct pwr_clk_ctrl_reg {
+	uint32_t pcgcctl;
+	uint32_t reserved[(0x1000 - 0xe04) / 4];
+} pwr_clk_ctrl_reg_t;
+
+typedef struct data_fifo {
+	uint32_t dataport;
+	uint32_t reserved[(0x1000 - 0x004) / 4];
+} data_fifo_t;
+
+typedef struct dwc2_otg_reg {
+	core_reg_t core;
+	host_reg_t host;
+	device_reg_t device;
+	pwr_clk_ctrl_reg_t pcgr;
+	data_fifo_t dfifo[MAX_EPS_CHANNELS];
+	uint32_t reserved[(0x40000 - 0x11000) / 4];
+} dwc2_reg_t;
+
+/**
+ * This union represents the bit fields of the Core AHB Configuration
+ * Register (GAHBCFG).
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned glblintrmsk:1;
+#define GLBINT_ENABLE 1
+
+		unsigned hbstlen:4;
+#define DMA_BURST_SINGLE 0
+#define DMA_BURST_INCR 1
+#define DMA_BURST_INCR4 3
+#define DMA_BURST_INCR8 5
+#define DMA_BURST_INCR16 7
+
+		unsigned dmaen:1;
+		unsigned reserved:1;
+		unsigned nptxfemplvl:1;
+		unsigned ptxfemplvl:1;
+		unsigned reserved9_31:23;
+	};
+} gahbcfg_t;
+
+/**
+ * This union represents the bit fields of the Core USB Configuration
+ * Register (GUSBCFG).
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned toutcal:3;
+		unsigned phyif:1;
+		unsigned ulpiutmisel:1;
+		unsigned fsintf:1;
+		unsigned physel:1;
+		unsigned ddrsel:1;
+		unsigned srpcap:1;
+		unsigned hnpcap:1;
+		unsigned usbtrdtim:4;
+		unsigned reserved14:1;
+		unsigned phylpwrclksel:1;
+		unsigned otgi2csel:1;
+		unsigned ulpifsls:1;
+		unsigned ulpiautores:1;
+		unsigned ulpiclksusm:1;
+		unsigned ulpiextvbusdrv:1;
+		unsigned ulpiextvbusindicator:1;
+		unsigned termseldlpulse:1;
+		unsigned reserved23_28:6;
+		unsigned forcehstmode:1;
+		unsigned forcedevmode:1;
+		unsigned cortxpkt:1;
+	};
+} gusbcfg_t;
+
+/**
+ * This union represents the bit fields of the Core Reset Register
+ * (GRSTCTL).
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		/** Core Soft Reset (CSftRst) (Device and Host)
+		 *
+		 * The application can flush the control logic in the
+		 * entire core using this bit. This bit resets the
+		 * pipelines in the AHB Clock domain as well as the
+		 * PHY Clock domain.
+		 *
+		 * The state machines are reset to an IDLE state, the
+		 * control bits in the CSRs are cleared, all the
+		 * transmit FIFOs and the receive FIFO are flushed.
+		 *
+		 * The status mask bits that control the generation of
+		 * the interrupt, are cleared, to clear the
+		 * interrupt. The interrupt status bits are not
+		 * cleared, so the application can get the status of
+		 * any events that occurred in the core after it has
+		 * set this bit.
+		 *
+		 * Any transactions on the AHB are terminated as soon
+		 * as possible following the protocol. Any
+		 * transactions on the USB are terminated immediately.
+		 *
+		 * The configuration settings in the CSRs are
+		 * unchanged, so the software doesn't have to
+		 * reprogram these registers (Device
+		 * Configuration/Host Configuration/Core System
+		 * Configuration/Core PHY Configuration).
+		 *
+		 * The application can write to this bit, any time it
+		 * wants to reset the core. This is a self clearing
+		 * bit and the core clears this bit after all the
+		 * necessary logic is reset in the core, which may
+		 * take several clocks, depending on the current state
+		 * of the core.
+		 */
+		unsigned csftrst:1;
+		/** Hclk Soft Reset
+		 *
+		 * The application uses this bit to reset the control logic in
+		 * the AHB clock domain. Only AHB clock domain pipelines are
+		 * reset.
+		 */
+		unsigned hsftrst:1;
+		/** Host Frame Counter Reset (Host Only)<br>
+		 *
+		 * The application can reset the (micro)frame number
+		 * counter inside the core, using this bit. When the
+		 * (micro)frame counter is reset, the subsequent SOF
+		 * sent out by the core, will have a (micro)frame
+		 * number of 0.
+		 */
+		unsigned frmcntrrst:1;
+		/** In Token Sequence Learning Queue Flush
+		 * (INTknQFlsh) (Device Only)
+		 */
+		unsigned intknqflsh:1;
+		/** RxFIFO Flush (RxFFlsh) (Device and Host)
+		 *
+		 * The application can flush the entire Receive FIFO
+		 * using this bit.	<p>The application must first
+		 * ensure that the core is not in the middle of a
+		 * transaction.	 <p>The application should write into
+		 * this bit, only after making sure that neither the
+		 * DMA engine is reading from the RxFIFO nor the MAC
+		 * is writing the data in to the FIFO.	<p>The
+		 * application should wait until the bit is cleared
+		 * before performing any other operations. This bit
+		 * will takes 8 clocks (slowest of PHY or AHB clock)
+		 * to clear.
+		 */
+		unsigned rxfflsh:1;
+		/** TxFIFO Flush (TxFFlsh) (Device and Host).
+		 *
+		 * This bit is used to selectively flush a single or
+		 * all transmit FIFOs.	The application must first
+		 * ensure that the core is not in the middle of a
+		 * transaction.	 <p>The application should write into
+		 * this bit, only after making sure that neither the
+		 * DMA engine is writing into the TxFIFO nor the MAC
+		 * is reading the data out of the FIFO.	 <p>The
+		 * application should wait until the core clears this
+		 * bit, before performing any operations. This bit
+		 * will takes 8 clocks (slowest of PHY or AHB clock)
+		 * to clear.
+		 */
+		unsigned txfflsh:1;
+
+		/** TxFIFO Number (TxFNum) (Device and Host).
+		 *
+		 * This is the FIFO number which needs to be flushed,
+		 * using the TxFIFO Flush bit. This field should not
+		 * be changed until the TxFIFO Flush bit is cleared by
+		 * the core.
+		 *	 - 0x0 : Non Periodic TxFIFO Flush
+		 *	 - 0x1 : Periodic TxFIFO #1 Flush in device mode
+		 *	   or Periodic TxFIFO in host mode
+		 *	 - 0x2 : Periodic TxFIFO #2 Flush in device mode.
+		 *	 - ...
+		 *	 - 0xF : Periodic TxFIFO #15 Flush in device mode
+		 *	 - 0x10: Flush all the Transmit NonPeriodic and
+		 *	   Transmit Periodic FIFOs in the core
+		 */
+		unsigned txfnum:5;
+		/** Reserved */
+		unsigned reserved11_29:19;
+		/** DMA Request Signal.	 Indicated DMA request is in
+		 * probress.  Used for debug purpose. */
+		unsigned dmareq:1;
+		/** AHB Master Idle.  Indicates the AHB Master State
+		 * Machine is in IDLE condition. */
+		unsigned ahbidle:1;
+	};
+} grstctl_t;
+
+/**
+ * This union represents the bit fields of the Core Interrupt Mask
+ * Register (GINTMSK).
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned curmod:1;
+		unsigned modemis:1;
+		unsigned otgint:1;
+		unsigned sof:1;
+		unsigned rxflvl:1;
+		unsigned nptxfemp:1;
+		unsigned ginnakeff:1;
+		unsigned goutnakeff:1;
+		unsigned reserved8:1;
+		unsigned i2cint:1;
+		unsigned erlysusp:1;
+		unsigned usbsusp:1;
+		unsigned usbrst:1;
+		unsigned enumdone:1;
+		unsigned isooutdrop:1;
+		unsigned eopf:1;
+		unsigned reserved16:1;
+		unsigned epmis:1;
+		unsigned iepint:1;
+		unsigned oepint:1;
+		unsigned incompisoin:1;
+		unsigned incompip:1;
+		unsigned reserved22_23:2;
+		unsigned prtint:1;
+		unsigned hchint:1;
+		unsigned ptxfemp:1;
+		unsigned reserved27:1;
+		unsigned conidstschng:1;
+		unsigned disconnint:1;
+		unsigned sessreqint:1;
+		unsigned wkupint:1;
+	};
+} gintmsk_t;
+
+/**
+* This union represents the bit fields of the Core Non-Periodic
+* Transmit FIFO Size Register(GNPTXFSIZ).
+*/
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned nptxfstaddr:16;
+		unsigned nptxfdep:16;
+	};
+} gnptxfsiz_t;
+
+/**
+ * This union represents the bit fields of the Core Receive FIFO Size
+ * Register(GRXFSIZ).
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	/*The value in this fieles is in terms of 32-bit words size.
+	 */
+	struct {
+		unsigned rxfdep:16;
+		unsigned reserved:16;
+	};
+} grxfsiz_t;
+
+/**
+* This union represents the bit fields of the Core Device
+* Transmit FIFO Size Register(GNPTXFSIZ).
+*/
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned dtxfstaddr:16;
+		unsigned dtxfdep:16;
+	};
+} dtxfsiz_t;
+
+/**
+ * This union represents the bit fields of the Core Interrupt Register
+ * (GINTSTS).
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+#define SOF_INTR_MASK 0x0008
+	/* register bits */
+	struct {
+		unsigned curmod:1;
+#define HOST_MODE 1
+#define DEVICE_MODE 0
+		unsigned modemis:1;
+		unsigned otgint:1;
+		unsigned sof:1;
+		unsigned rxflvl:1;
+		unsigned nptxfemp:1;
+		unsigned ginnakeff:1;
+		unsigned goutnakeff:1;
+		unsigned reserved8:1;
+		unsigned i2cint:1;
+		unsigned erlysusp:1;
+		unsigned usbsusp:1;
+		unsigned usbrst:1;
+		unsigned enumdone:1;
+		unsigned isooutdrop:1;
+		unsigned eopf:1;
+		unsigned reserved16_17:2;
+		unsigned iepint:1;
+		unsigned oepint:1;
+		unsigned reserved20:1;
+		unsigned incompip:1;
+		unsigned reserved22_23:2;
+		unsigned prtint:1;
+		unsigned hchint:1;
+		unsigned ptxfemp:1;
+		unsigned reserved27:1;
+		unsigned conidstschng:1;
+		unsigned disconnint:1;
+		unsigned sessreqint:1;
+		unsigned wkupint:1;
+	};
+} gintsts_t;
+
+#define GINTSTS_WKUPINT			(1 << 31)
+#define GINTSTS_SESSREQINT		(1 << 30)
+#define GINTSTS_DISCONNINT		(1 << 29)
+#define GINTSTS_CONIDSTSCHNG		(1 << 28)
+#define GINTSTS_LPMTRANRCVD		(1 << 27)
+#define GINTSTS_PTXFEMP			(1 << 26)
+#define GINTSTS_HCHINT			(1 << 25)
+#define GINTSTS_PRTINT			(1 << 24)
+#define GINTSTS_RESETDET		(1 << 23)
+#define GINTSTS_FET_SUSP		(1 << 22)
+#define GINTSTS_INCOMPL_IP		(1 << 21)
+#define GINTSTS_INCOMPL_SOIN		(1 << 20)
+#define GINTSTS_OEPINT			(1 << 19)
+#define GINTSTS_IEPINT			(1 << 18)
+#define GINTSTS_EPMIS			(1 << 17)
+#define GINTSTS_RESTOREDONE		(1 << 16)
+#define GINTSTS_EOPF			(1 << 15)
+#define GINTSTS_ISOUTDROP		(1 << 14)
+#define GINTSTS_ENUMDONE		(1 << 13)
+#define GINTSTS_USBRST			(1 << 12)
+#define GINTSTS_USBSUSP			(1 << 11)
+#define GINTSTS_ERLYSUSP		(1 << 10)
+#define GINTSTS_I2CINT			(1 << 9)
+#define GINTSTS_ULPI_CK_INT		(1 << 8)
+#define GINTSTS_GOUTNAKEFF		(1 << 7)
+#define GINTSTS_GINNAKEFF		(1 << 6)
+#define GINTSTS_NPTXFEMP		(1 << 5)
+#define GINTSTS_RXFLVL			(1 << 4)
+#define GINTSTS_SOF			(1 << 3)
+#define GINTSTS_OTGINT			(1 << 2)
+#define GINTSTS_MODEMIS			(1 << 1)
+#define GINTSTS_CURMODE_HOST		(1 << 0)
+
+/**
+ * This union represents the bit fields of the User HW Config3 Register
+ * (GHWCFG3).
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned reserved:16;
+		unsigned dfifodepth:16;
+	};
+} ghwcfg3_t;
+
+/**
+ * This union represents the bit fields in the Host Configuration Register.
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+
+	/* register bits */
+	struct {
+		/** FS/LS Phy Clock Select */
+		unsigned fslspclksel:2;
+#define PHYCLK_30_60_MHZ 0
+#define PHYCLK_48_MHZ 1
+#define PHYCLK_6_MHZ 2
+
+		/** FS/LS Only Support */
+		unsigned fslssupp:1;
+	};
+} hcfg_t;
+
+/**
+ * This union represents the bit fields in the Host Port Control and status
+ * Register.
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned prtconnsts:1;
+		unsigned prtconndet:1;
+		unsigned prtena:1;
+		unsigned prtenchng:1;
+		unsigned prtovrcurract:1;
+		unsigned prtovrcurrchng:1;
+		unsigned prtres:1;
+		unsigned prtsusp:1;
+		unsigned prtrst:1;
+		unsigned reserved9:1;
+		unsigned prtlnsts:2;
+		unsigned prtpwr:1;
+		unsigned prttstctl:4;
+		unsigned prtspd:2;
+#define PRTSPD_HIGH 0
+#define PRTSPD_FULL 1
+#define PRTSPD_LOW	2
+		unsigned reserved19_31:13;
+	};
+} hprt_t;
+/* Mask W1C bits */
+#define HPRT_W1C_MASK (~((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5)))
+
+/**
+ * This union represents the bit fields in the Host Channel Characteristics
+ * Register.
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+
+	/* register bits */
+	struct {
+		/** Maximum packet size in bytes */
+		unsigned mps:11;
+		/** Endpoint number */
+		unsigned epnum:4;
+		/** 0: OUT, 1: IN */
+		unsigned epdir:1;
+		unsigned reserved:1;
+		/** 0: Full/high speed device, 1: Low speed device */
+		unsigned lspddev:1;
+		/** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */
+		unsigned eptype:2;
+		/** Packets per frame for periodic transfers. 0 is reserved. */
+		unsigned multicnt:2;
+		/** Device address */
+		unsigned devaddr:7;
+		/**
+		 * Frame to transmit periodic transaction.
+		 * 0: even, 1: odd
+		 */
+		unsigned oddfrm:1;
+		/** Channel disable */
+		unsigned chdis:1;
+		/** Channel enable */
+		unsigned chen:1;
+	};
+} hcchar_t;
+
+typedef enum {
+	EPDIR_OUT = 0,
+	EPDIR_IN,
+} ep_dir_t;
+
+/**
+ * This union represents the bit fields in the Host All Interrupt
+ * Register.
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		/** Transfer Complete */
+		unsigned xfercomp:1;
+		/** Channel Halted */
+		unsigned chhltd:1;
+		/** AHB Error */
+		unsigned ahberr:1;
+		/** STALL Response Received */
+		unsigned stall:1;
+		/** NAK Response Received */
+		unsigned nak:1;
+		/** ACK Response Received */
+		unsigned ack:1;
+		/** NYET Response Received */
+		unsigned nyet:1;
+		/** Transaction Err */
+		unsigned xacterr:1;
+		/** Babble Error */
+		unsigned bblerr:1;
+		/** Frame Overrun */
+		unsigned frmovrun:1;
+		/** Data Toggle Error */
+		unsigned datatglerr:1;
+		/** Reserved */
+		unsigned reserved:21;
+	};
+} hcint_t;
+
+/**
+ * This union represents the bit fields in the Host Channel Transfer Size
+ * Register.
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+
+	/* register bits */
+	struct {
+		/* Total transfer size in bytes */
+		unsigned xfersize:19;
+		/** Data packets to transfer */
+		unsigned pktcnt:10;
+		/**
+		 * Packet ID for next data packet
+		 * 0: DATA0
+		 * 1: DATA2
+		 * 2: DATA1
+		 * 3: MDATA (non-Control), SETUP (Control)
+		 */
+		unsigned pid:2;
+#define PID_DATA0 0
+#define PID_DATA1 2
+#define PID_DATA2 1
+#define PID_MDATA 3
+#define PID_SETUP 3
+		/* Do PING protocol when 1 */
+		unsigned dopng:1;
+	};
+} hctsiz_t;
+
+/**
+ * This union represents the bit fields in the Host Channel Interrupt Mask
+ * Register.
+ */
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned xfercomp:1;
+		unsigned chhltd:1;
+		unsigned ahberr:1;
+		unsigned stall:1;
+		unsigned nak:1;
+		unsigned ack:1;
+		unsigned nyet:1;
+		unsigned xacterr:1;
+		unsigned bblerr:1;
+		unsigned frmovrun:1;
+		unsigned datatglerr:1;
+		unsigned reserved:21;
+	};
+} hcintmsk_t;
+
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned devspd:2;
+		unsigned nzstsouthshk:1;
+		unsigned ena32ksusp:1;
+		unsigned devaddr:7;
+		unsigned perfrint:2;
+		unsigned endevoutnak:1;
+		unsigned reservedi14_17:4;
+		unsigned epmiscnt:5;
+		unsigned reserved26_31:9;
+	};
+} dcfg_t;
+
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned suspsts:1;
+		unsigned enumspd:2;
+		unsigned errticerr:1;
+		unsigned reserved4_31:28;
+	};
+} dsts_t;
+
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned rmtwkupsig:1;
+		unsigned sftdiscon:1;
+		unsigned gnpinnaksts:1;
+		unsigned goutnaksts:1;
+		unsigned tstctl:3;
+		unsigned sgnpinnak:1;
+		unsigned cgnpinnak:1;
+		unsigned sgoutnak:1;
+		unsigned cgoutnak:1;
+		unsigned pwronprgdone:1;
+		unsigned reserved12:1;
+		unsigned gmc:2;
+		unsigned ignrfrmnum:1;
+		unsigned nakonbble:1;
+		unsigned encontbna:1;
+		unsigned reserved19_31:14;
+	};
+} dctl_t;
+
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+#define D0EPCTL_MPS_SHIFT		0
+#define D0EPCTL_MPS_64			0
+#define D0EPCTL_MPS_32			1
+#define D0EPCTL_MPS_16			2
+#define D0EPCTL_MPS_8			3
+		unsigned mps:11;
+		unsigned nextep:4;
+		unsigned usbactep:1;
+		unsigned dpid:1;
+		unsigned naksts:1;
+		unsigned eptype:2;
+		unsigned reserved20:1;
+		unsigned stall:1;
+		unsigned txfnum:4;
+		unsigned cnak:1;
+		unsigned snak:1;
+		unsigned setd0pid:1;
+		unsigned setd1pid:1;
+		unsigned epdis:1;
+		unsigned epena:1;
+	};
+} depctl_t;
+
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned xfercompl:1;
+		unsigned epdisbld:1;
+		unsigned ahberr:1;
+		unsigned setup:1;
+		unsigned reserved4_14:12;
+		unsigned stuppktrcvd:1;
+		unsigned reserved16_31:15;
+	};
+} depint_t;
+
+#define DXEPINT_SETUP_RCVD		(1 << 15)
+#define DXEPINT_INEPNAKEFF		(1 << 6)
+#define DXEPINT_BACK2BACKSETUP		(1 << 6)
+#define DXEPINT_INTKNEPMIS		(1 << 5)
+#define DXEPINT_INTKNTXFEMP		(1 << 4)
+#define DXEPINT_OUTTKNEPDIS		(1 << 4)
+#define DXEPINT_TIMEOUT			(1 << 3)
+#define DXEPINT_SETUP			(1 << 3)
+#define DXEPINT_AHBERR			(1 << 2)
+#define DXEPINT_EPDISBLD		(1 << 1)
+#define DXEPINT_XFERCOMPL		(1 << 0)
+
+typedef union {
+	/* raw register data */
+	uint32_t d32;
+	/* register bits */
+	struct {
+		unsigned xfersize:19;
+		unsigned pktcnt:10;
+		unsigned mc:2;
+		unsigned reserved31:1;
+	};
+} depsiz_t;
+
+#define DAINT_OUTEP_SHIFT	MAX_EPS_CHANNELS
+
+#endif



More information about the coreboot-gerrit mailing list