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

#include <stdint.h>

#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/st/usb_dwc2.h>

static usb_dwc2_t dwc2_handle;

static const usb_driver_t usb_dwc2driver = {
	.disable_int = usb_dwc2_disable_int,
	.ep0_out_start = usb_dwc2_ep0_out_start,
	.ep_start_xfer = usb_dwc2_ep_start_xfer,
	.ep0_start_xfer = usb_dwc2_ep0_start_xfer,
	.write_packet = usb_dwc2_write_packet,
	.read_packet = usb_dwc2_read_packet,
	.ep_set_stall = usb_dwc2_ep_set_stall,
	.stop_device = usb_dwc2_stop_device,
	.set_address = usb_dwc2_set_address,
	.dev_disconnect = usb_dwc2_dev_disconnect,
	.write_empty_tx_fifo = usb_dwc2_write_empty_tx_fifo,
	.it_handler = usb_dwc2_it_handler
};

/*
 * USB_OTG_FlushTxFifo : Flush a Tx FIFO
 * USBx : Selected device
 * num : FIFO number
 *       This parameter can be a value from 1 to 15
 *       15 means Flush all Tx FIFOs
 * return : status
 */
static usb_status_t usb_dwc2_flush_tx_fifo(usb_dwc2_global_t *usbx,
					   uint32_t num)
{
	uint32_t count = 0;

	usbx->grstctl = (USB_OTG_GRSTCTL_TXFFLSH | (uint32_t)(num << 6));

	do {
		if (++count > 200000)
			return USBD_TIMEOUT;
	} while ((usbx->grstctl & USB_OTG_GRSTCTL_TXFFLSH) ==
		 USB_OTG_GRSTCTL_TXFFLSH);

	return USBD_OK;
}

/*
 * USB_FlushRxFifo : Flush Rx FIFO
 * param : USBx : Selected device
 * return : status
 */
static usb_status_t usb_dwc2_flush_rx_fifo(usb_dwc2_global_t *usbx)
{
	uint32_t count = 0;

	usbx->grstctl = USB_OTG_GRSTCTL_RXFFLSH;

	do {
		if (++count > 200000)
			return USBD_TIMEOUT;
	} while ((usbx->grstctl & USB_OTG_GRSTCTL_RXFFLSH) ==
		  USB_OTG_GRSTCTL_RXFFLSH);

	return USBD_OK;
}

/*
 * USB_ReadInterrupts: return the global USB interrupt status
 * param  USBx : Selected device
 * return : interrupt register value
 */
static uint32_t usb_dwc2_read_int(usb_dwc2_global_t *usbx)
{
	uint32_t v = 0;

	v = usbx->gintsts;
	v &= usbx->gintmsk;

	return v;
}

/*
 * usb_dwc2_all_out_ep_int : return the USB device OUT endpoints interrupt
 * param : USBx : Selected device
 * return : device OUT endpoint interrupts
 */
static uint32_t usb_dwc2_all_out_ep_int(usb_dwc2_global_t *usbx)
{
	uint32_t v = 0;

	v  = dwc2_handle.usb_device->daint;
	v &= dwc2_handle.usb_device->daintmsk;

	return ((v & 0xffff0000) >> 16);
}

/*
 * usb_dwc2_all_in_ep_int: return the USB device IN endpoints interrupt
 * param : USBx : Selected device
 * return : device IN endpoint interrupts
 */
static uint32_t usb_dwc2_all_in_ep_int(usb_dwc2_global_t *usbx)
{
	uint32_t v = 0;

	v  = dwc2_handle.usb_device->daint;
	v &= dwc2_handle.usb_device->daintmsk;

	return ((v & 0xFFFF));
}

/*
 * usb_dwc2_out_ep_int : returns Device OUT EP Interrupt register
 * USBx : Selected device
 * epnum : endpoint number
 *         This parameter can be a value from 0 to 15
 * return : Device OUT EP Interrupt register
 */
static uint32_t usb_dwc2_out_ep_int(usb_dwc2_global_t *usbx, uint8_t epnum)
{
	uint32_t v = 0;

	v  = dwc2_handle.usb_out_endpoint[epnum]->epint;
	v &= dwc2_handle.usb_device->doepmsk;

	return v;
}

/*
 * usb_dwc2_in_ep_int : Returns Device IN EP Interrupt register
 * param : USBx : Selected device
 * param : epnum : endpoint number
 *         This parameter can be a value from 0 to 15
 * return : Device IN EP Interrupt register
 */
static uint32_t usb_dwc2_in_ep_int(usb_dwc2_global_t *usbx, uint8_t epnum)
{
	uint32_t msk, emp;

	msk = dwc2_handle.usb_device->diepmsk;
	emp = dwc2_handle.usb_device->diepempmsk;
	msk |= ((emp >> epnum) & 0x1) << 7;

	return (dwc2_handle.usb_in_endpoint[epnum]->epint & msk);
}

/*
 * usb_dwc2_get_mode : Returns USB core mode
 * param :  USBx : Selected device
 * return : core mode : Host or Device
 *          This parameter can be one of the these values:
 *           0 : Host
 *           1 : Device
 */
static uint32_t usb_dwc2_get_mode(usb_dwc2_global_t *usbx)
{
	return ((usbx->gintsts) & 0x1);
}

/*
 * usb_dwc2_activate_setup : Activate EP0 for Setup transactions
 * param : USBx : Selected device
 * return : status
 */
static usb_status_t usb_dwc2_activate_setup(usb_dwc2_global_t *usbx)
{
	/* Set the MPS of the IN EP based on the enumeration speed */
	dwc2_handle.usb_in_endpoint[0]->epctl &= ~USB_OTG_DIEPCTL_MPSIZ;

	if ((dwc2_handle.usb_device->dsts & USB_OTG_DSTS_ENUMSPD) ==
	   DSTS_ENUMSPD_LS_PHY_6MHZ)
		dwc2_handle.usb_in_endpoint[0]->epctl |= 3;

	dwc2_handle.usb_device->dctl |= USB_OTG_DCTL_CGINAK;

	return USBD_OK;
}

/*
 * usb_dwc2_disable_int :
 *         Disable the controller's Global Int in the AHB Config reg
 * param : handle : Selected device
 * return : status
 */
usb_status_t usb_dwc2_disable_int(void *handle)
{
	usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global;

	usbx->gahbcfg &= ~USB_OTG_GAHBCFG_GINT;
	return USBD_OK;
}

/*
 * usb_dwc2_ep0_out_start : Prepare the EP0 to start the first control setup
 * param : handle : Selected device
 * return : status
 */
usb_status_t usb_dwc2_ep0_out_start(void *handle)
{
	/*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/

	dwc2_handle.usb_out_endpoint[0]->eptsiz = 0;
	dwc2_handle.usb_out_endpoint[0]->eptsiz |= (USB_OTG_DOEPTSIZ_PKTCNT &
						    (1 << 19));
	dwc2_handle.usb_out_endpoint[0]->eptsiz |= (3 * 8);
	dwc2_handle.usb_out_endpoint[0]->eptsiz |=  USB_OTG_DOEPTSIZ_STUPCNT;

	return USBD_OK;
}

/*
 * usb_dwc2_ep_start_xfer : setup and starts a transfer over an EP
 * param : handle : Selected device
 * param : ep: pointer to endpoint structure
 * return : status
 */
usb_status_t usb_dwc2_ep_start_xfer(void *handle, usb_otg_ep_t *ep)
{
	usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global;

	/* IN endpoint */
	if (ep->is_in == 1) {
		/* Zero Length Packet? */
		if (ep->xfer_len == 0) {
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &=
					~(USB_OTG_DIEPTSIZ_PKTCNT);
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19));
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &=
					~(USB_OTG_DIEPTSIZ_XFRSIZ);
		} else {
			/* Program the transfer size and packet count
			 * as follows: xfersize = N * maxpacket +
			 * short_packet pktcnt = N + (short_packet
			 * exist ? 1 : 0)
			 */
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &=
					~(USB_OTG_DIEPTSIZ_XFRSIZ);
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &=
					~(USB_OTG_DIEPTSIZ_PKTCNT);
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DIEPTSIZ_PKTCNT &
					 (((ep->xfer_len + ep->maxpacket - 1) /
					   ep->maxpacket) << 19));
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DIEPTSIZ_XFRSIZ &
					 ep->xfer_len);

			if (ep->type == EP_TYPE_ISOC) {
				dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &=
						~(USB_OTG_DIEPTSIZ_MULCNT);
				dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |=
						(USB_OTG_DIEPTSIZ_MULCNT &
						 (1 << 29));
			}
		}

		if (ep->type != EP_TYPE_ISOC) {
			/* Enable the Tx FIFO Empty Interrupt for this EP */
			if (ep->xfer_len > 0)
				dwc2_handle.usb_device->diepempmsk |=
								1 << ep->num;
		}

		if (ep->type == EP_TYPE_ISOC) {
			if ((dwc2_handle.usb_device->dsts & (1 << 8)) == 0) {
				dwc2_handle.usb_in_endpoint[ep->num]->epctl |=
						USB_OTG_DIEPCTL_SODDFRM;
			} else {
				dwc2_handle.usb_in_endpoint[ep->num]->epctl |=
						USB_OTG_DIEPCTL_SD0PID_SEVNFRM;
			}
		}

		/* EP enable, IN data in FIFO */
		dwc2_handle.usb_in_endpoint[ep->num]->epctl |=
						(USB_OTG_DIEPCTL_CNAK |
						USB_OTG_DIEPCTL_EPENA);

		if (ep->type == EP_TYPE_ISOC)
			usb_dwc2_write_packet(usbx, ep->xfer_buff,
					      ep->num, ep->xfer_len);
	} else {
		/* Program the transfer size and packet count as follows:
		 * pktcnt = N
		 * xfersize = N * maxpacket
		 */
		dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &=
						~(USB_OTG_DOEPTSIZ_XFRSIZ);
		dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &=
						~(USB_OTG_DOEPTSIZ_PKTCNT);

		if (ep->xfer_len == 0) {
			dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DOEPTSIZ_XFRSIZ &
					 ep->maxpacket);
			dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DOEPTSIZ_PKTCNT & (1 << 19));
		} else {
			uint16_t pktcnt = (ep->xfer_len + ep->maxpacket - 1) /
				ep->maxpacket;

			dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DOEPTSIZ_PKTCNT &
					 (pktcnt << 19));
			dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DOEPTSIZ_XFRSIZ &
					 (ep->maxpacket * pktcnt));
		}

		if (ep->type == EP_TYPE_ISOC) {
			if ((dwc2_handle.usb_device->dsts & (1 << 8)) == 0)
				dwc2_handle.usb_out_endpoint[ep->num]->epctl |=
						USB_OTG_DOEPCTL_SODDFRM;
			else
				dwc2_handle.usb_out_endpoint[ep->num]->epctl |=
						USB_OTG_DOEPCTL_SD0PID_SEVNFRM;
		}
		/* EP enable */
		dwc2_handle.usb_out_endpoint[ep->num]->epctl |=
				(USB_OTG_DOEPCTL_CNAK | USB_OTG_DOEPCTL_EPENA);
	}
	return USBD_OK;
}

/*
 * usb_dwc2_ep0_start_xfer : setup and starts a transfer over the EP  0
 * param : handle : Selected device
 * param : ep: pointer to endpoint structure
 * return : status
 */
usb_status_t usb_dwc2_ep0_start_xfer(void *handle, usb_otg_ep_t *ep)
{
	/*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/

	/* IN endpoint */
	if (ep->is_in == 1) {
		/* Zero Length Packet? */
		if (ep->xfer_len == 0) {
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &=
					~(USB_OTG_DIEPTSIZ_PKTCNT);
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19));
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &=
					~(USB_OTG_DIEPTSIZ_XFRSIZ);
		} else {
			/* Program the transfer size and packet count
			 * as follows: xfersize = N * maxpacket +
			 * short_packet pktcnt = N + (short_packet
			 * exist ? 1 : 0)
			 */
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &=
					~(USB_OTG_DIEPTSIZ_XFRSIZ);
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &=
					~(USB_OTG_DIEPTSIZ_PKTCNT);

			if (ep->xfer_len > ep->maxpacket)
				ep->xfer_len = ep->maxpacket;

			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19));
			dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |=
					(USB_OTG_DIEPTSIZ_XFRSIZ &
					 ep->xfer_len);
		}

		/* Enable the Tx FIFO Empty Interrupt for this EP */
		if (ep->xfer_len > 0)
			dwc2_handle.usb_device->diepempmsk |= 1 << (ep->num);

		/* EP enable, IN data in FIFO */
		dwc2_handle.usb_in_endpoint[ep->num]->epctl |=
				(USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA);
	} else {
		/* Program the transfer size and packet count as follows:
		 * pktcnt = N
		 * xfersize = N * maxpacket
		 */
		dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &=
						~(USB_OTG_DOEPTSIZ_XFRSIZ);
		dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &=
						~(USB_OTG_DOEPTSIZ_PKTCNT);

		if (ep->xfer_len > 0)
			ep->xfer_len = ep->maxpacket;

		dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |=
						(USB_OTG_DOEPTSIZ_PKTCNT &
						(1 << 19));
		dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |=
						(USB_OTG_DOEPTSIZ_XFRSIZ &
						(ep->maxpacket));

		/* EP enable */
		dwc2_handle.usb_out_endpoint[ep->num]->epctl |=
						(USB_OTG_DOEPCTL_CNAK |
						USB_OTG_DOEPCTL_EPENA);
	}
	return USBD_OK;
}

/*
 * usb_dwc2_write_packet : Writes a packet into the Tx FIFO associated
 *         with the EP/channel
 * param : handle : Selected device
 * param : src :  pointer to source buffer
 * param : ch_ep_num : endpoint or host channel number
 * param : len : Number of bytes to write
 * return : status
 */
usb_status_t usb_dwc2_write_packet(void *handle, uint8_t *src,
				   uint8_t ch_ep_num, uint16_t len)
{
	uint32_t count32b, i, j;
	/*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/

	count32b =  (len + 3) / 4;
	for (i = 0; i < count32b; i++, src += 4) {
		uint32_t src_copy = 0;

		/* Data written to fifo need to be 4 bytes aligned */
		for (j = 0; j < 4; j++)
			src_copy += (*(src + j)) << (8 * j);

		*dwc2_handle.usb_fifo[ch_ep_num] = src_copy;
	}

	return USBD_OK;
}

/*
 * usb_dwc2_read_packet : read a packet from the Tx FIFO associated
 *         with the EP/channel
 * param : handle : Selected device
 * param : src : source pointer
 * param : ch_ep_num : endpoint or host channel number
 * param : len : Number of bytes to read
 * return : pointer to destination buffer
 */
void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len)
{
	uint32_t i = 0;
	uint32_t count32b = (len + 3) / 4;
	/*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/

	VERBOSE("read packet length %i to 0x%lx\n", len, (uintptr_t)dest);

	for (i = 0; i < count32b; i++, dest += 4) {
		*(uint32_t *)dest = *dwc2_handle.usb_fifo[0];
		dsb();
	}

	return ((void *)dest);
}

/*
 * usb_dwc2_EPSetStall : set a stall condition over an EP
 * param : handle : Selected device
 * param : ep: pointer to endpoint structure
 * return : status
 */
usb_status_t usb_dwc2_ep_set_stall(void *handle, usb_otg_ep_t *ep)
{
	/*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/
	if (ep->is_in == 1) {
		if ((dwc2_handle.usb_in_endpoint[ep->num]->epctl &
						USB_OTG_DIEPCTL_EPENA) == 0)
			dwc2_handle.usb_in_endpoint[ep->num]->epctl &=
						~(USB_OTG_DIEPCTL_EPDIS);
		dwc2_handle.usb_in_endpoint[ep->num]->epctl |=
						USB_OTG_DIEPCTL_STALL;
	} else {
		if ((dwc2_handle.usb_out_endpoint[ep->num]->epctl &
						USB_OTG_DOEPCTL_EPENA) == 0)
			dwc2_handle.usb_out_endpoint[ep->num]->epctl &=
						~(USB_OTG_DOEPCTL_EPDIS);
		dwc2_handle.usb_out_endpoint[ep->num]->epctl |=
						USB_OTG_DOEPCTL_STALL;
	}
	return USBD_OK;
}

/*
 * usb_dwc2_stop_device : Stop the usb device mode
 * param : handle : Selected device
 * return : status
 */
usb_status_t usb_dwc2_stop_device(void *handle)
{
	uint32_t i = 0;
	usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global;

	/* Clear Pending interrupt */
	for (i = 0; i < 15 ; i++) {
		dwc2_handle.usb_in_endpoint[i]->epint = 0xFF;
		dwc2_handle.usb_out_endpoint[i]->epint = 0xFF;
	}
	dwc2_handle.usb_device->daint = 0xFFFFFFFF;

	/* Clear interrupt masks */
	dwc2_handle.usb_device->diepmsk  = 0;
	dwc2_handle.usb_device->doepmsk  = 0;
	dwc2_handle.usb_device->daintmsk = 0;

	/* Flush the FIFO */
	usb_dwc2_flush_rx_fifo(usbx);
	usb_dwc2_flush_tx_fifo(usbx, 0x10);

	return USBD_OK;
}

/*
 * usb_dwc2_set_address : Stop the usb device mode
 * param : handle : Selected device
 * param : address : new device address to be assigned
 *          This parameter can be a value from 0 to 255
 * return : status
 */
usb_status_t usb_dwc2_set_address(void *handle, uint8_t address)
{
	/*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/

	dwc2_handle.usb_device->dcfg &= ~(USB_OTG_DCFG_DAD);
	dwc2_handle.usb_device->dcfg |= (address << 4) & USB_OTG_DCFG_DAD;

	return USBD_OK;
}

/*
 * usb_dwc2_dev_disconnect :
 *	Disconnect the USB device by disabling the pull-up/pull-down
 * param : handle : Selected device
 * return : status
 */
usb_status_t usb_dwc2_dev_disconnect(void *handle)
{
	/*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/

	dwc2_handle.usb_device->dctl |= USB_OTG_DCTL_SDIS;

	return USBD_OK;
}

/*
 * usb_dwc2_write_empty_tx_fifo
 *         check FIFO for the next packet to be loaded
 * param : handle : Selected device
 * param : epnum : endpoint number
 * param : xfer_len : block length
 * param : xfer_count : number of block
 * param : maxpacket : max packet length
 * param : xfer_buff : buffer pointer
 * retval : status
 */
usb_status_t usb_dwc2_write_empty_tx_fifo(void *handle,
					  uint32_t epnum, uint32_t xfer_len,
					  uint32_t *xfer_count,
					  uint32_t maxpacket,
					  uint8_t **xfer_buff)
{
	int32_t len = 0;
	uint32_t len32b;
	usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global;

	len = xfer_len - *xfer_count;

	if ((len > 0) && ((uint32_t)len > maxpacket))
		len = maxpacket;

	len32b = (len + 3) / 4;

	while ((dwc2_handle.usb_in_endpoint[epnum]->txfsts &
		USB_OTG_DTXFSTS_INEPTFSAV) > len32b &&
		(*xfer_count < xfer_len) && (xfer_len != 0)) {
		/* Write the FIFO */
		len = xfer_len - *xfer_count;

		if ((len > 0) && ((uint32_t)len > maxpacket))
			len = maxpacket;

		len32b = (len + 3) / 4;

		usb_dwc2_write_packet(usbx, *xfer_buff, epnum, len);

		*xfer_buff  += len;
		*xfer_count += len;
	}

	if (len <= 0) {
		uint32_t fifoemptymsk = 0x1 << epnum;

		dwc2_handle.usb_device->diepempmsk &= ~fifoemptymsk;
	}

	return USBD_OK;
}

/*
 * @brief  This function handles PCD interrupt request.
 * @param  hpcd: PCD handle
 * @retval HAL status
 */
usb_action_t usb_dwc2_it_handler(void *handle, uint32_t *param)
{
	usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global;
	uint32_t ep_intr, epint, epnum = 0;
	uint32_t temp;

	/* ensure that we are in device mode */
	if (usb_dwc2_get_mode(usbx) != USB_OTG_MODE_DEVICE)
		return USB_NOTHING;

	/* avoid spurious interrupt */
	if (!usb_dwc2_read_int(usbx))
		return USB_NOTHING;

	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_MMIS)
		/* incorrect mode, acknowledge the interrupt */
		usbx->gintsts = USB_OTG_GINTSTS_MMIS;

	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_OEPINT) {
		/* Read in the device interrupt bits */
		ep_intr = usb_dwc2_all_out_ep_int(usbx);

		while (!(ep_intr & 1)) {
			epnum++;
			ep_intr >>= 1;
		}

		if (ep_intr & 1) {
			epint = usb_dwc2_out_ep_int(usbx, epnum);

			if ((epint & USB_OTG_DOEPINT_XFRC) ==
						USB_OTG_DOEPINT_XFRC) {
				dwc2_handle.usb_out_endpoint[epnum]->epint =
						USB_OTG_DOEPINT_XFRC;
				*param = epnum;
				return USB_DATA_OUT;
			}
			if ((epint & USB_OTG_DOEPINT_STUP) ==
						USB_OTG_DOEPINT_STUP) {
				/* Inform the upper layer that a setup packet
				 *  is available
				 */
				dwc2_handle.usb_out_endpoint[epnum]->epint =
						USB_OTG_DOEPINT_STUP;
				return USB_SETUP;
			}
			if ((epint & USB_OTG_DOEPINT_OTEPDIS) ==
						USB_OTG_DOEPINT_OTEPDIS)
				dwc2_handle.usb_out_endpoint[epnum]->epint =
						USB_OTG_DOEPINT_OTEPDIS;
		}
	}
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_IEPINT) {
		/* Read in the device interrupt bits */
		ep_intr = usb_dwc2_all_in_ep_int(usbx);

		while (!(ep_intr & 1)) {
			epnum++;
			ep_intr >>= 1;
		}
		/* In ITR */
		if (ep_intr & 0x1) {
			epint = usb_dwc2_in_ep_int(usbx, epnum);

			if ((epint & USB_OTG_DIEPINT_XFRC) ==
						USB_OTG_DIEPINT_XFRC) {
				uint32_t fifoemptymsk = 0x1 << epnum;

				dwc2_handle.usb_device->diepempmsk &=
						~fifoemptymsk;

				dwc2_handle.usb_in_endpoint[epnum]->epint =
						USB_OTG_DIEPINT_XFRC;

				*param = epnum;
				return USB_DATA_IN;
			}
			if ((epint & USB_OTG_DIEPINT_TOC) ==
						USB_OTG_DIEPINT_TOC)
				dwc2_handle.usb_in_endpoint[epnum]->epint =
						USB_OTG_DIEPINT_TOC;

			if ((epint & USB_OTG_DIEPINT_ITTXFE) ==
						USB_OTG_DIEPINT_ITTXFE)
				dwc2_handle.usb_in_endpoint[epnum]->epint =
						USB_OTG_DIEPINT_ITTXFE;

			if ((epint & USB_OTG_DIEPINT_INEPNE) ==
						USB_OTG_DIEPINT_INEPNE)
				dwc2_handle.usb_in_endpoint[epnum]->epint =
						USB_OTG_DIEPINT_INEPNE;

			if ((epint & USB_OTG_DIEPINT_EPDISD) ==
						USB_OTG_DIEPINT_EPDISD)
				dwc2_handle.usb_in_endpoint[epnum]->epint =
						USB_OTG_DIEPINT_EPDISD;

			if ((epint & USB_OTG_DIEPINT_TXFE) ==
						USB_OTG_DIEPINT_TXFE) {
				*param = epnum;
				return USB_WRITE_EMPTY;
			}
		}
	}

	/* Handle Resume Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_WKUINT) {
		INFO("handle USB : Resume\n");
		/* Clear the Remote Wake-up Signaling */
		dwc2_handle.usb_device->dctl &= ~USB_OTG_DCTL_RWUSIG;
		usbx->gintsts = USB_OTG_GINTSTS_WKUINT;
		return USB_RESUME;
	}

	/* Handle Suspend Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_USBSUSP) {
		INFO("handle USB : Suspend int\n");
		usbx->gintsts = USB_OTG_GINTSTS_USBSUSP;
		if ((dwc2_handle.usb_device->dsts & USB_OTG_DSTS_SUSPSTS) ==
				USB_OTG_DSTS_SUSPSTS){
			return USB_SUSPEND;
		}
	}

	/* Handle LPM Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_LPMINT) {
		INFO("handle USB : LPM int enter in suspend\n");
		usbx->gintsts = USB_OTG_GINTSTS_LPMINT;
		*param = (usbx->glpmcfg & USB_OTG_GLPMCFG_BESL) >> 2;
		return USB_LPM;
	}

	/* Handle Reset Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_USBRST) {
		INFO("handle USB : Reset\n");
		dwc2_handle.usb_device->dctl &= ~USB_OTG_DCTL_RWUSIG;
		usb_dwc2_flush_tx_fifo(usbx, 0);

		dwc2_handle.usb_device->daint = 0xFFFFFFFF;
		dwc2_handle.usb_device->daintmsk |= 0x10001;

		dwc2_handle.usb_device->doepmsk |= (USB_OTG_DOEPMSK_STUPM |
					 USB_OTG_DOEPMSK_XFRCM |
					 USB_OTG_DOEPMSK_EPDM);
		dwc2_handle.usb_device->diepmsk |= (USB_OTG_DIEPMSK_TOM |
					 USB_OTG_DIEPMSK_XFRCM |
					 USB_OTG_DIEPMSK_EPDM);

		/* Set Default Address to 0 */
		dwc2_handle.usb_device->dcfg &= ~USB_OTG_DCFG_DAD;

		/* setup EP0 to receive SETUP packets */
		usb_dwc2_ep0_out_start(usbx);

		usbx->gintsts = USB_OTG_GINTSTS_USBRST;
	}

	/* Handle Enumeration done Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_ENUMDNE) {
		usb_dwc2_activate_setup(usbx);
		usbx->gusbcfg &= ~USB_OTG_GUSBCFG_TRDT;

		usbx->gusbcfg |= (uint32_t)((USBD_HS_TRDT_VALUE << 10) &
					    USB_OTG_GUSBCFG_TRDT);

		usbx->gintsts = USB_OTG_GINTSTS_ENUMDNE;
		return USB_ENUM_DONE;
	}

	/* Handle RxQLevel Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_RXFLVL) {
		usbx->gintmsk &= ~USB_OTG_GINTSTS_RXFLVL;
		temp = usbx->grxstsp;
		*param = (temp & USB_OTG_GRXSTSP_EPNUM);
		*param |= ((temp & USB_OTG_GRXSTSP_BCNT) << 0xC);

		if (((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_DATA_UPDT) {
			if ((temp & USB_OTG_GRXSTSP_BCNT) != 0) {
				usbx->gintmsk |= USB_OTG_GINTSTS_RXFLVL;
				return USB_READ_DATA_PACKET;
			}
		} else if (((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17) ==
							STS_SETUP_UPDT) {
			usbx->gintmsk |= USB_OTG_GINTSTS_RXFLVL;
			return USB_READ_SETUP_PACKET;
		}
		usbx->gintmsk |= USB_OTG_GINTSTS_RXFLVL;
	}

	/* Handle SOF Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_SOF) {
		INFO("handle USB : SOF\n");
		usbx->gintsts = USB_OTG_GINTSTS_SOF;
		return USB_SOF;
	}

	/* Handle Incomplete ISO IN Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_IISOIXFR) {
		INFO("handle USB : ISO IN\n");
		usbx->gintsts = USB_OTG_GINTSTS_IISOIXFR;
	}

	/* Handle Incomplete ISO OUT Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_PXFR_INCOMPISOOUT) {
		INFO("handle USB : ISO OUT\n");
		usbx->gintsts = USB_OTG_GINTSTS_PXFR_INCOMPISOOUT;
	}

	/* Handle Connection event Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_SRQINT) {
		INFO("handle USB : Connect\n");
		usbx->gintsts = USB_OTG_GINTSTS_SRQINT;
	}

	/* Handle Disconnection event Interrupt */
	if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_OTGINT) {
		INFO("handle USB : Disconnect\n");
		temp = usbx->gotgint;
		if ((temp & USB_OTG_GOTGINT_SEDET) == USB_OTG_GOTGINT_SEDET)
			return USB_DISCONNECT;
	}
	return USB_NOTHING;
}

void usb_dwc2_init_driver(usb_handle_t *usb_core_handle,
			  uint32_t *base_register)
{
	uint32_t i = 0;
	uintptr_t base = (uintptr_t)base_register;

	dwc2_handle.usb_global = (usb_dwc2_global_t *)base;

	dwc2_handle.usb_device = (usb_dwc2_device_t *)
					(base + USB_OTG_DEVICE_BASE);

	for (i = 0; i < USB_MAX_ENDPOINT_NB; i++) {
		dwc2_handle.usb_in_endpoint[i] = (usb_dwc2_endpoint_t *)
					(base + USB_OTG_IN_ENDPOINT_BASE +
					 (i * sizeof(usb_dwc2_endpoint_t)));
		dwc2_handle.usb_out_endpoint[i] = (usb_dwc2_endpoint_t *)
					(base + USB_OTG_OUT_ENDPOINT_BASE +
					(i * sizeof(usb_dwc2_endpoint_t)));
		dwc2_handle.usb_fifo[i] = (uint32_t *)(base +
						       USB_OTG_FIFO_BASE +
						       (i * USB_OTG_FIFO_SIZE));
	}

	register_usb_driver(usb_core_handle, &usb_dwc2driver,
			    (void *)&dwc2_handle);
}