Dear Amit Virdi, > From: Pratyush Anand <pratyush.an...@st.com> > > Driver for designware otg device only implements device functionality > and is meant to be used with usbtty interface. > This driver will work mainly for Control and Bulk endpoints. Periodic > transfer has not been verified using these drivers. > > Signed-off-by: Pratyush Anand <pratyush.an...@st.com> > Signed-off-by: Amit Virdi <amit.vi...@st.com> > --- > drivers/serial/usbtty.h | 2 + > drivers/usb/gadget/Makefile | 1 + > drivers/usb/gadget/designware_otg.c | 1064 > +++++++++++++++++++++++++++++++++++ include/usb/designware_otg.h | > 527 +++++++++++++++++ > 4 files changed, 1594 insertions(+), 0 deletions(-) > create mode 100644 drivers/usb/gadget/designware_otg.c > create mode 100644 include/usb/designware_otg.h > > diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h > index 60347d7..6731c38 100644 > --- a/drivers/serial/usbtty.h > +++ b/drivers/serial/usbtty.h > @@ -35,6 +35,8 @@ > #include <usb/pxa27x_udc.h> > #elif defined(CONFIG_DW_UDC) > #include <usb/designware_udc.h> > +#elif defined(CONFIG_DW_OTG) > +#include <usb/designware_otg.h> > #endif > > #include <version.h> > diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile > index 87d1918..ede367e 100644 > --- a/drivers/usb/gadget/Makefile > +++ b/drivers/usb/gadget/Makefile > @@ -40,6 +40,7 @@ ifdef CONFIG_USB_DEVICE > COBJS-y += core.o > COBJS-y += ep0.o > COBJS-$(CONFIG_DW_UDC) += designware_udc.o > +COBJS-$(CONFIG_DW_OTG) += designware_otg.o > COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o > COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o > COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o > diff --git a/drivers/usb/gadget/designware_otg.c > b/drivers/usb/gadget/designware_otg.c new file mode 100644 > index 0000000..b5dd898 > --- /dev/null > +++ b/drivers/usb/gadget/designware_otg.c > @@ -0,0 +1,1064 @@ > +/* > + * Based on drivers/usb/gadget/designware_otg.c > + * Synopsys DW OTG Device bus interface driver > + * > + * (C) Copyright 2011 > + * Pratyush Anand, ST Micoelectronics, pratyush.an...@st.com. > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * 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; either version 2 of > + * the License, or (at your option) any later version. > + * > + * 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., 59 Temple Place, Suite 330, Boston, > + * MA 02111-1307 USA > + */ > +/* temp def: will be removed TBD*/
temp remove ;-) > +#undef APG_BOARD 1 > + > +#ifndef APG_BOARD dead code? > +#include <common.h> > +#include <asm/io.h> > +#include <usbdevice.h> > +#include "ep0.h" > +#include <usb/designware_otg.h> > +#include <asm/arch/hardware.h> > +#else > +#include "types.h" > +#include <designware_otg.h> > +#include <usbdevice.h> > +#endif > + > +#define UDC_INIT_MDELAY 80 /* Device settle delay */ > + > +/* Some kind of debugging output... */ > +#ifndef DEBUG_DWUSBTTY > +#define UDCDBG(str) > +#define UDCDBGA(fmt, args...) > +#else > +#define UDCDBG(str) serial_printf(str "\n") > +#define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args) > +#endif debug() > + > +static struct urb *ep0_urb; > +static struct usb_device_instance *udc_device; > + > +static struct device_if device_if_mem; > +static struct device_if *dev_if = &device_if_mem; > +#if defined(CONFIG_USBD_HS) > +#define CONFIG_USBD_SERIAL_BULK_PKTSIZE UDC_BULK_HS_PACKET_SIZE > +#endif > + > +static struct usb_endpoint_instance *dw_find_ep(int ep) > +{ > + int i; > + > + for (i = 0; i < udc_device->bus->max_endpoints; i++) { > + if ((udc_device->bus->endpoint_array[i].endpoint_address & > + USB_ENDPOINT_NUMBER_MASK) == ep) > + return &udc_device->bus->endpoint_array[i]; > + } > + return NULL; > +} > + > +/* > + * This function reads a packet from the Rx FIFO into the destination > buffer. + * To read SETUP data use dwc_otg_read_setup_packet. > + */ > +void dwc_otg_read_packet(struct dwc_ep *ep, u16 _bytes) > +{ > + u32 i; > + int word_count = (_bytes + 3) / 4; > + u32 *fifo = dev_if->data_fifo[0]; > + u32 *data_buff = (u32 *) ep->xfer_buff; > + u32 unaligned; > + /* > + * This requires reading data from the FIFO into a u32 temp buffer, > + * then moving it into the data buffer. > + */ > + if ((_bytes < 4) && (_bytes > 0)) { rename _bytes to bytes, fix globally > + unaligned = readl(fifo); > + memcpy(data_buff, &unaligned, _bytes); > + } else { > + for (i = 0; i < word_count; i++, data_buff++) > + *data_buff = readl(fifo); > + } > +} > + > +/* Handle RX transaction on non-ISO endpoint. */ > +static void dw_udc_epn_rx(struct dwc_ep *ep, int bcnt) > +{ > + struct urb *urb; > + struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num); > + > + if (endpoint) { > + urb = endpoint->rcv_urb; > + > + if (urb) { > + ep->xfer_buff = urb->buffer + urb->actual_length; > + dwc_otg_read_packet(ep, bcnt); > + usbd_rcv_complete(endpoint, bcnt, 0); > + } > + } > +} > + > +/* > + * This function writes a packet into the Tx FIFO associated with the EP. > + * The buffer is padded to DWORD on a per packet basis in > + * slave/dma mode if the MPS is not DWORD aligned. The last packet, if > + * short, is also padded to a multiple of DWORD. > + * > + * ep->xfer_buff always starts DWORD aligned in memory and is a > + * multiple of DWORD in length > + * > + * ep->xfer_len can be any number of bytes > + * > + * FIFO access is DWORD > + */ > +static void dwc_otg_ep_write_packet(struct dwc_ep *ep) > +{ > + u32 i; > + u32 dword_count; > + u32 *fifo; > + u32 *data_buff = (u32 *) ep->xfer_buff; > + u32 temp, unaligned; > + struct device_in_ep_regs *in_ep_regs = dev_if->in_ep_regs[ep->num]; > + struct core_global_regs *core_global_regs = dev_if->core_global_regs; > + > + /* > + * Find the DWORD length, padded by extra bytes as neccessary if MPS > + * is not a multiple of DWORD > + */ > + dword_count = (ep->xfer_len + 3) / 4; > + fifo = dev_if->data_fifo[ep->num]; > + > + /* program pkt count */ > + temp = ep->xfer_len; > + temp |= (1 << PKTCNT_SHIFT); > + writel(temp, &in_ep_regs->dieptsiz); > + > + /* enable EP*/ > + temp = readl(&in_ep_regs->diepctl); > + temp |= (EPENA | CNAK); > + writel(temp, &in_ep_regs->diepctl); > + > + /* clear TX Fifo Empty intr*/ > + writel(NPTXFEMPTY, &core_global_regs->gintsts); > + > + temp = readl(&core_global_regs->gintmsk); > + temp |= NPTXFEMPTY; > + writel(temp, &core_global_regs->gintmsk); > + > + while (!(readl(&core_global_regs->gintsts) & NPTXFEMPTY)) > + ; No endless loops please > + > + /* write to fifo */ > + if ((ep->xfer_len < 4) && (ep->xfer_len > 0)) { > + memcpy(&unaligned, data_buff, ep->xfer_len); > + *fifo = unaligned; > + } else { > + for (i = 0; i < dword_count; i++, data_buff++) > + *fifo = *data_buff; > + } > + > + writel(NPTXFEMPTY, &core_global_regs->gintsts); > + > + /* check for transfer completion*/ > + while (!(readl(&in_ep_regs->diepint) & XFERCOMPL)) > + ; dtto > + > + writel(XFERCOMPL, &in_ep_regs->diepint); > + > + temp = readl(&core_global_regs->gintmsk); > + temp &= ~NPTXFEMPTY; > + writel(temp, &core_global_regs->gintmsk); Use clrsetbits_le32() and friends in cases like that > +} > + > +/* Handle TX transaction on non-ISO endpoint. */ > +static void dw_udc_epn_tx(struct dwc_ep *ep) > +{ > + struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num); > + struct urb *urb = endpoint->tx_urb; > + int align; > + > + if (!endpoint) > + return; > + > + /* > + * We need to transmit a terminating zero-length packet now if > + * we have sent all of the data in this URB and the transfer > + * size was an exact multiple of the packet size. > + */ > + if (urb && (endpoint->last == endpoint->tx_packetSize) && > + (urb->actual_length - endpoint->sent - > + endpoint->last == 0)) { > + /* handle zero length packet here */ > + ep->xfer_len = 0; > + dwc_otg_ep_write_packet(ep); > + } > + > + if (urb && urb->actual_length) { > + /* retire the data that was just sent */ > + usbd_tx_complete(endpoint); > + /* > + * Check to see if we have more data ready to transmit > + * now. > + */ > + if (urb && urb->actual_length) { > + /* write data to FIFO */ > + ep->xfer_len = MIN(urb->actual_length - endpoint->sent, > + endpoint->tx_packetSize); > + > + if (ep->xfer_len) { > + ep->xfer_buff = urb->buffer + endpoint->sent; > + > + /* > + * This ensures that USBD packet fifo is > + * accessed through word aligned pointer or > + * through non word aligned pointer but only > + * with a max length to make the next packet > + * word aligned > + */ > + > + align = ((ulong)ep->xfer_buff % sizeof(int)); > + if (align) > + ep->xfer_len = MIN(ep->xfer_len, > + sizeof(int) - align); > + > + dwc_otg_ep_write_packet(ep); > + } > + endpoint->last = ep->xfer_len; > + > + } else if (urb && (urb->actual_length == 0)) { > + /* udc_set_nak(ep); */ remove deadcode please > + } > + } > +} > + > +/* This function returns pointer to out ep struct with number num */ > +struct dwc_ep *get_out_ep(u32 num) > +{ > + u32 i; > + int num_out_eps = MAX_EPS_CHANNELS; > + struct dwc_pcd *pcd = &dev_if->pcd; > + > + if (num == 0) { > + return &pcd->ep0; You don't need the else branch below, it'll make code more readable: if (num == 0) return; ... code ... > + } else { > + for (i = 0; i < num_out_eps; ++i) { > + if (pcd->out_ep[i].num == num) > + return &pcd->out_ep[i]; > + } > + } > + return 0; > +} > + > +/* This function returns pointer to in ep struct with number num */ > +struct dwc_ep *get_in_ep(u32 num) > +{ > + u32 i; > + int num_out_eps = MAX_EPS_CHANNELS; > + struct dwc_pcd *pcd = &dev_if->pcd; > + > + if (num == 0) { > + return &pcd->ep0; > + } else { > + for (i = 0; i < num_out_eps; ++i) { > + if (pcd->in_ep[i].num == num) > + return &pcd->in_ep[i]; > + } > + } > + return 0; > +} > + > +/* > + * This function reads the 8 bytes of the setup packet from the Rx FIFO > into the + * destination buffer. It is called from the Rx Status Queue > Level (RxStsQLvl) + * interrupt routine when a SETUP packet has been > received in Slave mode. + */ > +static void dwc_otg_read_setup_packet(u32 *dest) > +{ > + dest[0] = readl(dev_if->data_fifo[0]); > + dest[1] = readl(dev_if->data_fifo[0]); > +} > + > +/* > + * This function handles the Rx Status Queue Level Interrupt, which > + * indicates that there is a least one packet in the Rx FIFO. The > + * packets are moved from the FIFO to memory, where they will be > + * processed when the Endpoint Interrupt Register indicates Transfer > + * Complete or SETUP Phase Done. > + * > + * Repeat the following until the Rx Status Queue is empty: > + * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet > + * info > + * -# If Receive FIFO is empty then skip to step Clear the interrupt > + * and exit > + * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the > + * SETUP data to the buffer > + * -# If OUT Data Packet call dwc_otg_read_packet to copy the data > + * to the destination buffer > + */ > +static int dwc_otg_pcd_handle_rx_status_q_level_intr(void) > +{ > + struct core_global_regs *global_regs = dev_if->core_global_regs; > + struct dwc_pcd *pcd = &dev_if->pcd; > + u32 gintmsk; > + u32 status; > + struct dwc_ep *ep; > + u32 bcnt; > + > + /* Disable the Rx Status Queue Level interrupt */ > + gintmsk = readl(&global_regs->gintmsk); > + gintmsk &= ~RXSTSQLVL; > + writel(gintmsk, &global_regs->gintmsk); > + > + /* Get the Status from the top of the FIFO */ > + status = readl(&global_regs->grxstsp); > + /* Get pointer to EP structure */ > + ep = get_out_ep((status & EPNUMMSK) >> EPNUM_SHIFT); > + bcnt = (status & BCNTMSK) >> BCNT_SHIFT; > + > + switch ((status & PKTSTSMSK) >> PKTSTS_SHIFT) { > + case DWC_DSTS_GOUT_NAK: > + break; > + case DWC_STS_DATA_UPDT: > + if (bcnt) > + dw_udc_epn_rx(ep, bcnt); > + break; > + case DWC_STS_XFER_COMP: > + break; > + case DWC_DSTS_SETUP_COMP: > + break; > + case DWC_DSTS_SETUP_UPDT: > + dwc_otg_read_setup_packet((u32 *)pcd->req); > + break; > + default: > + break; > + } > + > + /* Enable the Rx Status Queue Level interrupt */ > + gintmsk = readl(&global_regs->gintmsk); > + gintmsk |= RXSTSQLVL; > + writel(gintmsk, &global_regs->gintmsk); > + > + /* Clear interrupt */ > + writel(RXSTSQLVL, &global_regs->gintsts); > + > + return 1; > +} > + > +/* > + * This function starts the Zero-Length Packet for the IN status phase > + * of a 2 stage control transfer. > + */ > +static void do_setup_in_status_phase(struct device_if *dev_if) > +{ > + struct device_out_ep_regs *out_regs = > + dev_if->out_ep_regs[0]; > + u32 doepctl, doeptsiz; > + doeptsiz = 0; > + doeptsiz |= (1 << PKTCNT_SHIFT); > + writel(doeptsiz, &out_regs->doeptsiz); > + doepctl = readl(&out_regs->doepctl); > + doepctl |= (CNAK | EPENA); > + writel(doepctl, &out_regs->doepctl); clrsetbits_le32 ... fix globally please. > +} > + > +static void udc_set_stall(int epid, int dir) > +{ if (dir) reg = ... else reg = ... writel(readl(reg) | ..., reg); might be more readable ;-) > + if (dir) > + writel(readl(&dev_if->in_ep_regs[epid]->diepctl) | SSTALL, > + &dev_if->in_ep_regs[epid]->diepctl); > + else > + writel(readl(&dev_if->out_ep_regs[epid]->doepctl) | SSTALL, > + &dev_if->out_ep_regs[epid]->doepctl); > +} > +/* > + * This function handles EP0 Control transfers. > + * > + * The state of the control tranfers are tracked in ep0state > + * > + * A flag set indicates that it is not the first packet, so do not > + * process setup data now. it has alreday been processed, just send the > + * next data packet > + */ > +void handle_ep0(int in_flag) > +{ > + struct dwc_pcd *pcd = &dev_if->pcd; > + struct dwc_ep *ep0 = &pcd->ep0; > + struct usb_device_request *ctrl = pcd->req; > + > + /* handle inepint, only when more than 64 bytes to transfer*/ > + if (in_flag & !ep0_urb->actual_length) > + return; > + > + if (!ep0_urb->actual_length) { > + if (ep0_recv_setup(ep0_urb)) { > + udc_set_stall(0, ctrl->bmRequestType & USB_DIR_IN); > + return; > + } > + ep0->xfer_buff = (u8 *)ep0_urb->buffer; > + } else > + ep0->xfer_buff += EP0_MAX_PACKET_SIZE; > + > + if (ep0_urb->actual_length <= EP0_MAX_PACKET_SIZE) { > + ep0->xfer_len = ep0_urb->actual_length; > + ep0_urb->actual_length = 0; > + } else { > + ep0->xfer_len = EP0_MAX_PACKET_SIZE; > + ep0_urb->actual_length -= EP0_MAX_PACKET_SIZE; > + } > + > + if (ctrl->bmRequestType & USB_DIR_IN) { > + dwc_otg_ep_write_packet(ep0); > + if (!ep0_urb->actual_length) > + do_setup_in_status_phase(dev_if); > + } else { > + if (!ctrl->wLength) > + dwc_otg_ep_write_packet(ep0); > + else > + udc_set_stall(0, ctrl->bmRequestType & USB_DIR_OUT); > + } > +} > + > +/* > + * This function reads the Device All Endpoints Interrupt register and > + * returns the OUT endpoint interrupt bits. > + */ > +static u32 dwc_otg_read_dev_all_out_ep_intr(void) > +{ > + u32 v; > + > + v = readl(&dev_if->dev_global_regs->daint) & > + readl(&dev_if->dev_global_regs->daintmsk); > + return (v & 0xffff0000) >> 16; simple return v >> 16 doesn't work? > +} > + > +/* > + * This function reads the Device All Endpoints Interrupt register and > + * returns the IN endpoint interrupt bits. > + */ > +static u32 dwc_otg_read_dev_all_in_ep_intr(void) > +{ > + u32 v; > + > + v = readl(&dev_if->dev_global_regs->daint) & > + readl(&dev_if->dev_global_regs->daintmsk); > + return v & 0xffff; > +} > + > +/* This function returns the Device OUT EP Interrupt register */ > +static u32 dwc_otg_read_doep_intr(struct dwc_ep *ep) > +{ > + u32 v; > + > + v = readl(&dev_if->out_ep_regs[ep->num]->doepint) & > + readl(&dev_if->dev_global_regs->doepmsk); > + return v; > +} > + > +/*This function returns the Device IN EP Interrupt register */ > +static u32 dwc_otg_read_diep_intr(struct dwc_ep *ep) > +{ > + u32 v; > + > + v = readl(&dev_if->in_ep_regs[ep->num]->diepint) & > + readl(&dev_if->dev_global_regs->diepmsk); > + return v; > +} > + > +/* > + * This function configures EPO to receive SETUP packets. > + * > + * Program the following fields in the endpoint specific registers for > Control + * OUT EP 0, in order to receive a setup packet: > + * > + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back setup > packets) + * > + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back to back > setup + * packets) > + * > + * In DMA mode, DOEPDMA0 Register with a memory address to store any setup > + * packets received > + */ > +static void ep0_out_start(void) > +{ > + u32 temp; > + > + /* program transfer size*/ > + temp = 8 * 3; > + /* program packet count*/ > + temp |= PKTCNT; > + /* program setup packet count */ > + temp |= (3 << SUPCNT_SHIFT); > + writel(temp, &dev_if->out_ep_regs[0]->doeptsiz); > +} > + > +/* should be called after set address is received */ > +void udc_set_address_controller(u32 address) > +{ > + u32 dcfg; > + > + dcfg = readl(&dev_if->dev_global_regs->dcfg); > + dcfg &= ~DEVADDRMSK; > + dcfg |= address << DEVADDR_SHIFT; > + writel(dcfg, &dev_if->dev_global_regs->dcfg); > + > + usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); > +} > + > +/* should be called after set configuration is received */ > +static void dwc_otg_bulk_out_activate(void) > +{ > + struct device_out_ep_regs *out_regs = > + dev_if->out_ep_regs[UDC_OUT_ENDPOINT]; > + struct device_global_regs *dev_global_regs > + = dev_if->dev_global_regs; > + u32 doepctl, doeptsiz, daint; > + > + daint = readl(&dev_global_regs->daintmsk); > + daint |= 1 << (UDC_OUT_ENDPOINT + DAINTMASK_OUT_SHIFT); > + writel(daint, &dev_global_regs->daintmsk); > + doeptsiz = CONFIG_USBD_SERIAL_BULK_PKTSIZE; > + doeptsiz |= (1 << PKTCNT_SHIFT); > + writel(doeptsiz, &out_regs->doeptsiz); > + doepctl = readl(&out_regs->doepctl); > + doepctl &= ~DOEPCTL_MPSMSK; > + doepctl &= ~EPTYPEMSK; > + doepctl |= (CONFIG_USBD_SERIAL_BULK_PKTSIZE | > + CNAK | EPENA | USBACTEP | DATA0PID > + | (EPTYPE_BULK << EPTYPE_SHIFT)); > + writel(doepctl, &out_regs->doepctl); > +} > + > +/* should be called after set configuration is received */ > +static void dwc_otg_bulk_in_activate(void) > +{ > + struct device_in_ep_regs *in_regs = > + dev_if->in_ep_regs[UDC_IN_ENDPOINT]; > + struct device_global_regs *dev_global_regs > + = dev_if->dev_global_regs; > + u32 diepctl, daint; > + > + daint = readl(&dev_global_regs->daintmsk); > + daint |= 1 << (UDC_IN_ENDPOINT + DAINTMASK_IN_SHIFT); > + writel(daint, &dev_global_regs->daintmsk); > + > + diepctl = readl(&in_regs->diepctl); > + diepctl &= ~DIEPCTL_MPSMSK; > + diepctl &= ~EPTYPEMSK; > + diepctl |= (CONFIG_USBD_SERIAL_BULK_PKTSIZE > + | USBACTEP | DATA0PID > + | (EPTYPE_BULK << EPTYPE_SHIFT)); > + writel(diepctl, &in_regs->diepctl); > +} > + > +static void dwc_otg_int_in_activate(void) > +{ > + struct device_in_ep_regs *in_regs = > + dev_if->in_ep_regs[UDC_INT_ENDPOINT]; > + struct device_global_regs *dev_global_regs > + = dev_if->dev_global_regs; > + u32 diepctl, daint; > + > + daint = readl(&dev_global_regs->daintmsk); > + daint |= 1 << (UDC_INT_ENDPOINT + DAINTMASK_IN_SHIFT); > + writel(daint, &dev_global_regs->daintmsk); > + > + diepctl = readl(&in_regs->diepctl); > + diepctl &= ~DIEPCTL_MPSMSK; > + diepctl &= ~EPTYPEMSK; > + diepctl |= (UDC_INT_PACKET_SIZE > + | USBACTEP | DATA0PID > + | (EPTYPE_INT << EPTYPE_SHIFT)); > + writel(diepctl, &in_regs->diepctl); lot of clrsetbits_le32 will appear in these parts ;-) > +} > + > +/* should be called after set configuration is received */ > +void udc_set_configuration_controller(u32 config) > +{ > + dwc_otg_bulk_out_activate(); > + dwc_otg_bulk_in_activate(); > + dwc_otg_int_in_activate(); > + usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); > +} > + > +/* should be called to receive next packet */ > +static void dwc_otg_bulk_out_enable(void) > +{ > + struct device_out_ep_regs *out_regs = > + dev_if->out_ep_regs[UDC_OUT_ENDPOINT]; > + u32 doepctl, doeptsiz; > + > + doeptsiz = CONFIG_USBD_SERIAL_BULK_PKTSIZE; > + doeptsiz |= (1 << PKTCNT_SHIFT); > + writel(doeptsiz, &out_regs->doeptsiz); > + doepctl = readl(&out_regs->doepctl); > + doepctl |= CNAK | EPENA; > + writel(doepctl, &out_regs->doepctl); > +} > + > +/* This interrupt indicates that an OUT EP has a pending Interrupt. */ > + > +static int dwc_otg_pcd_handle_out_ep_intr(void) > +{ > + u32 ep_intr; > + u32 doepint; > + u32 epnum = 0; > + struct dwc_ep *dwc_ep; > + struct device_out_ep_regs **out_ep_regs > + = dev_if->out_ep_regs; > + > + /* Read in the device interrupt bits */ > + ep_intr = dwc_otg_read_dev_all_out_ep_intr(); > + while (ep_intr) { > + if (ep_intr & 0x1) { > + dwc_ep = get_out_ep(epnum); do you even use this variable? Don't you get gcc4.6 warnings ? > + doepint = dwc_otg_read_doep_intr(dwc_ep); > + > + /* Transfer complete */ > + if (doepint & XFERCOMPL) { > + /* Clear xfercompl */ > + writel(XFERCOMPL, &out_ep_regs[epnum]->doepint); > + if (!epnum) > + ep0_out_start(); > + else if (epnum == UDC_OUT_ENDPOINT) > + dwc_otg_bulk_out_enable(); > + } > + /* Setup Phase Done (control EPs) */ > + if (doepint & SETUP) { > + writel(SETUP, &out_ep_regs[epnum]->doepint); > + handle_ep0(0); > + } > + } > + epnum++; > + ep_intr >>= 1; > + } > + return 1; > +} > + > +/* This interrupt indicates that an IN EP has a pending Interrupt. */ > + > +static int dwc_otg_pcd_handle_in_ep_intr(void) > +{ > + u32 ep_intr; > + u32 diepint; > + u32 epnum = 0; > + struct dwc_ep *dwc_ep; > + struct device_in_ep_regs **in_ep_regs > + = dev_if->in_ep_regs; > + > + /* Read in the device interrupt bits */ > + ep_intr = dwc_otg_read_dev_all_in_ep_intr(); > + while (ep_intr) { > + if (ep_intr & 0x1) { if (!...) continue; ... code ... Lessers the depth of code. > + dwc_ep = get_in_ep(epnum); > + diepint = dwc_otg_read_diep_intr(dwc_ep); > + > + /* IN token received when txfifo empty */ > + if (diepint & INTKNTXFEMP) { > + /* Clear xfercompl */ > + writel(INTKNTXFEMP, > + &in_ep_regs[epnum]->diepint); > + if (!epnum) > + handle_ep0(1); > + else if (epnum == UDC_IN_ENDPOINT) > + dw_udc_epn_tx(dwc_ep); > + } > + } > + epnum++; > + ep_intr >>= 1; > + } > + return 1; > +} > + > +static void dwc_otg_flush_tx_fifo(const int num) > +{ > + struct core_global_regs *global_regs = dev_if->core_global_regs; > + u32 val = 0; > + int count = 0; > + > + val = readl(&global_regs->grstctl); > + val |= TXFFLSH; > + val &= ~TXFNUM; > + val |= (num << TXFNUM_SHIFT); > + writel(val, &global_regs->grstctl); > + > + do { > + val = readl(&global_regs->grstctl); > + if (++count > 10000) > + break; > + udelay(1); > + } while (val & TXFFLSH); > + > + /* Wait for 3 PHY Clocks */ > + udelay(1); > +} > + > +static void dwc_otg_flush_rx_fifo(void) > +{ > + struct core_global_regs *global_regs = dev_if->core_global_regs; > + int count = 0; > + u32 val = 0; > + > + val = readl(&global_regs->grstctl); > + val |= RXFFLSH; > + writel(val, &global_regs->grstctl); > + > + do { > + val = readl(&global_regs->grstctl); > + if (++count > 10000) > + break; > + udelay(1); WATCHDOG_RESET() instead of udelay() also, call the variable count "timeout" and make it count down, it'll be more readable (nitpick) > + } while (val & RXFFLSH); > + > + /* Wait for 3 PHY Clocks */ > + udelay(1); > +} > + > +/* > + * This interrupt occurs when a USB Reset is detected. When the USB Reset > + * Interrupt occurs the device state is set to DEFAULT and the EP0 state > is set + * to IDLE. > + * > + */ > +static int dwc_otg_pcd_handle_usb_reset_intr(void) > +{ > + u32 temp; > + u32 i; > + u32 gintmsk; > + struct device_out_ep_regs **out_ep_regs > + = dev_if->out_ep_regs; > + struct device_global_regs *dev_global_regs > + = dev_if->dev_global_regs; > + struct core_global_regs *core_global_regs > + = dev_if->core_global_regs; > + /* Set NAK for all OUT EPs */ > + for (i = 0; i < MAX_EPS_CHANNELS; i++) { > + temp = readl(&out_ep_regs[i]->doepctl); > + temp |= SNAK; > + writel(temp, &out_ep_regs[i]->doepctl); > + } > + > + /* Flush the NP Tx FIFO */ > + dwc_otg_flush_tx_fifo(DWC_GRSTCTL_TXFNUM_ALL); > + dwc_otg_flush_rx_fifo(); > + writel((1 << (DAINTMASK_IN_SHIFT + 0)) > + | (1 << (DAINTMASK_OUT_SHIFT + 0)), > + &dev_global_regs->daintmsk); > + > + writel(SETUPMSK | XFERCOMPLMSK | AHBERRMSK | EPDISABLEDMSK, > + &dev_global_regs->doepmsk); > + > + writel(INTKNTXFEMP, &dev_global_regs->diepmsk); > + > + gintmsk = readl(&core_global_regs->gintmsk); > + gintmsk |= GOUTNAKEFF; > + writel(gintmsk, &core_global_regs->gintmsk); > + > + /* program fifo size for ep0 */ > + > + writel(0x200, &core_global_regs->grxfsiz); > + > + temp = readl(&dev_if->in_ep_regs[0]->diepctl); > + temp &= 0xFFC3FFFF; /* TxFNumBF = 0, bits 25:22 */ > + writel(temp, &dev_if->in_ep_regs[0]->diepctl); > + > + temp = readl(&core_global_regs->gnptxfsiz); > + > + writel(0x2000000, &core_global_regs->gnptxfsiz); Magic value? > + > + /* Reset Device Address */ > + temp = readl(&dev_global_regs->dcfg); > + temp &= ~DEVADDRMSK; > + writel(temp, &dev_global_regs->dcfg); > + > + /* setup EP0 to receive SETUP packets */ > + ep0_out_start(); > + > + /* Clear interrupt */ > + writel(USBRESET, &core_global_regs->gintsts); > + > + UDCDBG("device reset in progess"); > + usbd_device_event_irq(udc_device, DEVICE_HUB_CONFIGURED, 0); > + > + return 1; > +} > + > +/* > + * This function enables EP0 OUT to receive SETUP packets and configures > EP0 + * IN for transmitting packets. It is normally called when the > "Enumeration + * Done" interrupt occurs. > + */ > +static void dwc_otg_ep0_activate(void) > +{ > + u32 temp; > + struct device_in_ep_regs *in_ep_regs = dev_if->in_ep_regs[0]; > + struct device_out_ep_regs *out_ep_regs = dev_if->out_ep_regs[0]; > + > + /* Read the Device Status and Endpoint 0 Control registers */ > + temp = readl(&in_ep_regs->diepctl); > + temp &= ~MPSMSK0; > + temp |= DWC_DEP0CTL_MPS_64; > + writel(temp, &in_ep_regs->diepctl); > + > + temp = readl(&out_ep_regs->doepctl); > + /* Enable OUT EP for receive */ > + temp |= EPENA; > + writel(temp, &out_ep_regs->doepctl); > +} > + > +/* > + * Read the device status register and set the device speed in the > + * data structure. > + * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate. > + */ > +static int dwc_otg_pcd_handle_enum_done_intr(void) > +{ > + u32 gusbcfg; > + struct core_global_regs *global_regs = dev_if->core_global_regs; > + dwc_otg_ep0_activate(); > + > + gusbcfg = readl(&global_regs->gusbcfg); > + gusbcfg &= ~USBTRDTIMMSK; > + gusbcfg |= PHYIF_16BIT; > + gusbcfg |= (9 << USBTRDTIM_SHIFT); Magic? > + writel(gusbcfg, &global_regs->gusbcfg); > + /* Clear interrupt */ > + writel(ENUMDONE, &global_regs->gintsts); > + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); > + return 1; > +} > + > +static u32 dwc_otg_read_core_intr(void) > +{ > + return readl(&dev_if->core_global_regs->gintsts) & > + readl(&dev_if->core_global_regs->gintmsk); > +} > + > +static void dwc_otg_init(const void *reg_base) > +{ > + struct dwc_pcd *pcd = &dev_if->pcd; > + u32 offset; > + u32 i; > + > + dev_if->core_global_regs = (struct core_global_regs *) reg_base; > + dev_if->dev_global_regs = (struct device_global_regs *) ((u32)reg_base + > + DWC_DEV_GLOBAL_REG_OFFSET); > + > + for (i = 0; i < MAX_EPS_CHANNELS; i++) { > + offset = i * DWC_EP_REG_OFFSET; > + > + dev_if->in_ep_regs[i] = (struct device_in_ep_regs *) > + ((u32)reg_base + DWC_DEV_IN_EP_REG_OFFSET + offset); > + > + dev_if->out_ep_regs[i] = (struct device_out_ep_regs *) > + ((u32)reg_base + DWC_DEV_OUT_EP_REG_OFFSET + offset); > + } > + > + for (i = 0; i < MAX_EPS_CHANNELS; i++) { > + dev_if->data_fifo[i] = > + (u32 *) ((u32)reg_base + DWC_OTG_DATA_FIFO_OFFSET + > + (i * DWC_OTG_DATA_FIFO_SIZE)); > + } > + > + dev_if->speed = 0; /* unknown */ > + for (i = 0; i < MAX_EPS_CHANNELS; i++) { > + pcd->in_ep[i].num = i; > + pcd->out_ep[i].num = i; > + } > +} > + > +/* > + * This function initializes the DWC_otg controller registers and prepares > the + * core for device mode > + */ > +static void dwc_otg_core_init(void) > +{ > + struct core_global_regs *global_regs = dev_if->core_global_regs; > + u32 ahbcfg, gintmsk, usbcfg; > + /* Step 1: Program the GAHBCFG Register. */ > + ahbcfg = DWC_NPTXEMPTYLVL_EMPTY | DWC_PTXEMPTYLVL_EMPTY; > + writel(ahbcfg, &global_regs->gahbcfg); > + > + /* Step 2: write usbcfg regs*/ > + usbcfg = readl(&global_regs->gusbcfg); > + usbcfg |= SRPCAP | HNPCAP; > + writel(usbcfg, &global_regs->gusbcfg); > + > + /* step3: write int_msk reg*/ > + gintmsk = USBRESET | ENUMDONE | RXSTSQLVL | OUTEPINTR | INEPINTR; > + writel(gintmsk, &global_regs->gintmsk); > +} > + > +/* Switch on the UDC */ > +static void usbotg_init(void) > +{ > + udc_device = NULL; > +#ifdef APG_BOARD > + dwc_otg_init((void *)0x11000000); What the heck ? :-O Dead code ? > +#else > + dwc_otg_init((void *)CONFIG_SYS_USBD_BASE); > +#endif > + > + /* Initialize the DWC_otg core. */ > + dwc_otg_core_init(); > + > +} > + > +void udc_irq(void) > +{ > + u32 status; > + > + status = dwc_otg_read_core_intr(); > + while (status) { > + if (status & USBRESET) > + dwc_otg_pcd_handle_usb_reset_intr(); > + if (status & ENUMDONE) > + dwc_otg_pcd_handle_enum_done_intr(); > + if (status & RXSTSQLVL) > + dwc_otg_pcd_handle_rx_status_q_level_intr(); > + if (status & OUTEPINTR) > + dwc_otg_pcd_handle_out_ep_intr(); > + if (status & INEPINTR) > + dwc_otg_pcd_handle_in_ep_intr(); > + status = dwc_otg_read_core_intr(); > + } > + > +} > + > +void udc_set_nak(int epid) > +{ > + writel(readl(&dev_if->out_ep_regs[epid]->doepctl) | SNAK, > + &dev_if->out_ep_regs[epid]->doepctl); > + writel(readl(&dev_if->in_ep_regs[epid]->diepctl) | SNAK, > + &dev_if->in_ep_regs[epid]->diepctl); Shouldn't you put this together with previous such code that operated with exeactly the same registers ? maybe even merge these three functions together. And(!) make everything that you don't need outside static please. > +} > + > +void udc_unset_nak(int epid) > +{ > + writel(readl(&dev_if->out_ep_regs[epid]->doepctl) | CNAK, > + &dev_if->out_ep_regs[epid]->doepctl); > + writel(readl(&dev_if->in_ep_regs[epid]->diepctl) | CNAK, > + &dev_if->in_ep_regs[epid]->diepctl); > +} > + > +int udc_endpoint_write(struct usb_endpoint_instance *endpoint) > +{ > + udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK); > + return 0; > +} > + > +static void udc_enable(struct usb_device_instance *device) > +{ > + struct dwc_pcd *pcd = &dev_if->pcd; > + > + UDCDBGA("enable device %p, status %d", device, device->status); > + > + /* Save the device structure pointer */ > + udc_device = device; > + > + /* Setup ep0 urb */ > + if (!ep0_urb) { > + ep0_urb = > + usbd_alloc_urb(udc_device, > + udc_device->bus->endpoint_array); > + pcd->req = > + (struct usb_device_request *)&ep0_urb->device_request; > + pcd->ep0.xfer_buff = (u8 *)ep0_urb->buffer; > + } else { > +#ifndef APG_BOARD > + serial_printf("udc_enable: ep0_urb already allocated %p\n", > + ep0_urb); Use printf(), not serial_printf(), globally > +#endif > + } > +} > + > +void udc_connect(void) > +{ > + struct device_global_regs *dev_regs = dev_if->dev_global_regs; > + u32 dcfg; > + > + /* remove soft disconnect */ > + dcfg = readl(&dev_regs->dctl); > + dcfg &= ~SFTDISCON; > + writel(dcfg, &dev_regs->dctl); > +} > + > +void udc_disconnect(void) > +{ > + struct device_global_regs *dev_regs = dev_if->dev_global_regs; > + u32 dcfg; > + > + /* soft disconnect */ > + dcfg = readl(&dev_regs->dctl); > + dcfg |= SFTDISCON; > + writel(dcfg, &dev_regs->dctl); > + udelay(150); > +} > + > +void udc_startup_events(struct usb_device_instance *device) > +{ > + /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ > + usbd_device_event_irq(device, DEVICE_INIT, 0); > + > + /* > + * The DEVICE_CREATE event puts the USB device in the state > + * STATE_ATTACHED. > + */ > + usbd_device_event_irq(device, DEVICE_CREATE, 0); > + > + /* > + * Some USB controller driver implementations signal > + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. > + * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, > + * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. > + * The DW USB client controller has the capability to detect when the > + * USB cable is connected to a powered USB bus, so we will defer the > + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later. > + */ > + > + udc_enable(device); > + > +} > + > +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, > + struct usb_endpoint_instance *endpoint) > +{ > + /* > + * Nothing to do here. Hob of this function has laready been > + * done during init. > + */ > +} > + > +int is_usbd_high_speed(void) > +{ > + struct device_global_regs *dev_regs = dev_if->dev_global_regs; > + u32 dsts; > + > + dsts = readl(&dev_regs->dsts); > + dsts &= ENUMSPDMSK; > + if (dsts == DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ) > + return 1; > + else > + return 0; > +} > + > +int udc_init(void) > +{ > + phy_init(); > + udc_disconnect(); > + usbotg_init(); > + return 0; > +} > diff --git a/include/usb/designware_otg.h b/include/usb/designware_otg.h > new file mode 100644 > index 0000000..d7b686b > --- /dev/null > +++ b/include/usb/designware_otg.h > @@ -0,0 +1,527 @@ > +/* > + * (C) Copyright 2011 > + * Pratyush Anand, ST Micoelectronics, pratyush.an...@st.com. > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * 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; either version 2 of > + * the License, or (at your option) any later version. > + * > + * 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., 59 Temple Place, Suite 330, Boston, > + * MA 02111-1307 USA > + */ > + > +#ifndef __DW_OTG_H > +#define __DW_OTG_H > +/* temp def: will be removed TBD */ > +#undef APH_BOARD 1 > +#ifdef APG_BOARD > +#include "types.h" > +#define CONFIG_USBD_HS > +#define CONFIG_DW_OTG > +#endif > + > +#include "usbdevice.h" > +/* USBTTY definitions */ > +#define EP0_MAX_PACKET_SIZE 64 > +#define UDC_INT_ENDPOINT 1 > +#define UDC_INT_PACKET_SIZE 64 > +#define UDC_OUT_ENDPOINT 2 > +#define UDC_BULK_PACKET_SIZE 512 > +#if defined(CONFIG_USBD_HS) > +#define UDC_BULK_HS_PACKET_SIZE 512 > +#endif > +#define UDC_IN_ENDPOINT 3 > +#define UDC_OUT_PACKET_SIZE 64 > +#define UDC_IN_PACKET_SIZE 64 > + > +/* UDC endpoint definitions */ > +#define UDC_EP0 0 > +#define UDC_EP1 1 > +#define UDC_EP2 2 > +#define UDC_EP3 3 > + > +#define CMD_SIZE 12 > +/* OTG Register Definitions */ > + > +/* > + * The application interfaces with the HS OTG core by reading from and > + * writing to the Control and Status Register (CSR) space through the > + * AHB Slave interface. These registers are 32 bits wide, and the > + * addresses are 32-bit-block aligned. > + * CSRs are classified as follows: > + * - Core Global Registers > + * - Device Mode Registers > + * - Device Global Registers > + * - Device Endpoint Specific Registers > + * - Host Mode Registers > + * - Host Global Registers > + * - Host Port CSRs > + * - Host Channel Specific Registers > + * > + * Only the Core Global registers can be accessed in both Device and > + * Host modes. When the HS OTG core is operating in one mode, either > + * Device or Host, the application must not access registers from the > + * other mode. When the core switches from one mode to another, the > + * registers in the new mode of operation must be reprogrammed as they > + * would be after a power-on reset. > + */ > + > +/* > + * DWC_otg Core registers. The core_global_regs structure defines the > + * size and relative field offsets for the Core Global registers. > + */ > +struct core_global_regs { > + /* OTG Control and Status Register. Offset: 000h */ > + u32 gotgctl; > + /* OTG Interrupt Register. Offset: 004h */ > + u32 gotgint; > + /* Core AHB Configuration Register. Offset: 008h */ > + u32 gahbcfg; > + > +#define DWC_GLBINTRMASK 0x0001 > +#define DWC_DMAENABLE 0x0020 > +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080 > +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000 > +#define DWC_PTXEMPTYLVL_EMPTY 0x0100 > +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000 > + > + /* Core USB Configuration Register. Offset: 00Ch */ > + u32 gusbcfg; > +#define PHYIF_16BIT (1 << 3) > +#define SRPCAP (1 << 8) > +#define HNPCAP (1 << 9) > +#define TERM_SEL_DL_PULSE (1 << 22) > +#define USBTRDTIM_SHIFT 10 > +#define USBTRDTIMMSK (0xF << USBTRDTIM_SHIFT) > + /* Core Reset Register. Offset: 010h */ > + u32 grstctl; > +#define DWC_GRSTCTL_TXFNUM_ALL 0x10 > +#define CSFTRST (1 << 0) > +#define INTKNQFLSH (1 << 3) > +#define RXFFLSH (1 << 4) > +#define TXFFLSH (1 << 5) Fix indent ... here and everywhere please > +#define TXFNUM_SHIFT 6 > +#define TXFNUM (0x1F << TXFNUM_SHIFT) > +#define AHBIDLE ((u32)1 << 31) > + /* Core Interrupt Register. Offset: 014h */ > + u32 gintsts; > +#define RXSTSQLVL (1 << 4) > +#define NPTXFEMPTY (1 << 5) > +#define GOUTNAKEFF (1 << 7) > +#define USBRESET (1 << 12) > +#define ENUMDONE (1 << 13) > +#define INEPINTR (1 << 18) > +#define OUTEPINTR (1 << 19) > + /* Core Interrupt Mask Register. Offset: 018h */ > + u32 gintmsk; > + /* > + * Receive Status Queue Read Register > + * (Read Only) Offset: 01Ch > + */ > + u32 grxstsr; > + /* > + * Receive Status Queue Read & POP Register > + * (Read Only) Offset: 020h > + */ > + u32 grxstsp; > +#define DWC_STS_DATA_UPDT 0x2 /* OUT Data Packet */ > +#define DWC_STS_XFER_COMP 0x3 /* OUT Data Transfer Complete */ > +#define DWC_DSTS_GOUT_NAK 0x1 /* Global OUT NAK */ > +#define DWC_DSTS_SETUP_COMP 0x4 /* Setup Phase Complete */ > +#define DWC_DSTS_SETUP_UPDT 0x6 /* SETUP Packet */ > +#define EPNUM_SHIFT 0 > +#define EPNUMMSK (0xF << EPNUM_SHIFT) > +#define BCNT_SHIFT 4 > +#define BCNTMSK (0x7FF << BCNT_SHIFT) > +#define PKTSTS_SHIFT 17 > +#define PKTSTSMSK (0xF << PKTSTS_SHIFT) > + /* Receive FIFO Size Register. Offset: 024h */ > + u32 grxfsiz; > +#define dwc_param_dev_rx_fifo_size_default 1064 > + /* Non Periodic Transmit FIFO Size Register. Offset: 028h */ > + u32 gnptxfsiz; > +#define dwc_param_dev_nperio_tx_fifo_size_default 1024 > + /* > + * Non Periodic Transmit FIFO/Queue Status Register > + * (Read Only). Offset: 02Ch > + */ > + u32 gnptxsts; > +#define NPTXQSPCAVAIL_SHIFT 16 > +#define NPTXQSPCAVAILMSK (0xFF << NPTXQSPCAVAIL_SHIFT) > +#define NPTXFSPCAVAIL_SHIFT 0 > +#define NPTXFSPCAVAILMSK (0xFFFF << NPTXFSPCAVAIL_SHIFT) > + /* I2C Access Register. Offset: 030h */ > + u32 gi2cctl; > + /* PHY Vendor Control Register. Offset: 034h */ > + u32 gpvndctl; > + /* General Purpose Input/Output Register. Offset: 038h */ > + u32 ggpio; > + /* User ID Register. Offset: 03Ch */ > + u32 guid; > + /* Synopsys ID Register (Read Only). Offset: 040h */ > + u32 gsnpsid; > + /* User HW Config1 Register (Read Only). Offset: 044h */ > + u32 ghwcfg1; > + /* User HW Config2 Register (Read Only). Offset: 048h */ > + > + u32 ghwcfg2; > +#define DWC_SLAVE_ONLY_ARCH 0 > +#define DWC_EXT_DMA_ARCH 1 > +#define DWC_INT_DMA_ARCH 2 > + > +#define DWC_MODE_HNP_SRP_CAPABLE 0 > +#define DWC_MODE_SRP_ONLY_CAPABLE 1 > +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2 > +#define DWC_MODE_SRP_CAPABLE_DEVICE 3 > +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4 > +#define DWC_MODE_SRP_CAPABLE_HOST 5 > +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6 > +#define DYNAMIC_FIFO (1 << 19) > +#define NUM_DEV_EP_SHIFT 10 > +#define NUM_DEV_EP (0xF << NUM_DEV_EP_SHIFT) > +#define HSPHYTYPE_SHIFT 6 > +#define HSPHYTYPEMSK (3 << HSPHYTYPE_SHIFT) > +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 > +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1 > +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2 > +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 > +#define TKNQDEPTH_SHIFT 26 > +#define TKNQDEPTHMSK (0x1F << TKNQDEPTH_SHIFT) > + > + /* User HW Config3 Register (Read Only). Offset: 04Ch */ > + u32 ghwcfg3; > +#define DFIFO_DEPTH_SHIFT 16 > +#define DFIFO_DEPTH ((u32)0xFFFF << DFIFO_DEPTH_SHIFT) > + /* User HW Config4 Register (Read Only). Offset: 050h */ > + u32 ghwcfg4; > +#define NUM_DEV_PERIO_IN_EP_SHIFT 0 > +#define NUM_DEV_PERIO_IN_EP (0xF << NUM_DEV_PERIO_IN_EP_SHIFT) > +#define DED_FIFO_EN (1 << 25) > +#define NUM_IN_EPS_SHIFT 26 > +#define NUM_IN_EPS (0xF << NUM_IN_EPS_SHIFT) > +#define UTMI_PHY_DATA_WIDTH_SHIFT 14 > +#define UTMI_PHY_DATA_WIDTH (0x3 << UTMI_PHY_DATA_WIDTH_SHIFT) > + /* Reserved Offset: 054h-0FFh */ > + u32 reserved[43]; > + /* Host Periodic Transmit FIFO Size Register. Offset: 100h */ > + u32 hptxfsiz; > + > + /* > + * Device Periodic Transmit FIFO#n Register, if dedicated fifos are > + * disabled. Otherwise Device Transmit FIFO#n Register. > + * > + * Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15) > + */ > + u32 dptxfsiz_dieptxf[15]; > +#define dwc_param_dev_tx_fifo_size_default 256 > +#define dwc_param_dev_perio_tx_fifo_size_default 256 > +}; > + > +/* > + * Device Global Registers. Offsets 800h-BFFh > + * > + * The following structures define the size and relative field offsets for > the + * Device Mode Registers. > + * > + * These registers are visible only in Device mode and must not be > accessed in + * Host mode, as the results are unknown. > + */ > +struct device_global_regs { /* CONFIG_DWC_OTG_REG_LE */ > + /* Device Configuration Register. Offset: 800h */ > + u32 dcfg; > +#define DWC_DCFG_FRAME_INTERVAL_80 0 > +#define DWC_DCFG_FRAME_INTERVAL_85 1 > +#define DWC_DCFG_FRAME_INTERVAL_90 2 > +#define DWC_DCFG_FRAME_INTERVAL_95 3 > +#define DWC_DCFG_FRAME_INTERVAL_MASK 3 > +#define PERFRINT_SHIFT 11 > +#define DEVSPDMSK (0x3 << 0) > +#define DEVADDR_SHIFT 4 > +#define DEVADDRMSK (0x7F << DEVADDR_SHIFT) > +#define NZSTSOUTHSHK (1 << 2) > + /* Device Control Register. Offset: 804h */ > + u32 dctl; > +#define RMTWKUPSIG (1 << 0) > +#define SFTDISCON (1 << 1) > +#define CGNPINNAK (1 << 7) > + /* Device Status Register (Read Only). Offset: 808h */ > + u32 dsts; > +#define ENUMSPD_SHIFT 1 > +#define ENUMSPDMSK (3 << ENUMSPD_SHIFT) > +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 > +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 > +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2 > +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3 > + /* Reserved. Offset: 80Ch */ > + u32 unused; > + /* Device IN Endpoint Common Interrupt Mask Register. Offset: 810h */ > + u32 diepmsk; > +#define TIMEOUTMSK (1 << 3) > +#define INTKNTXFEMP (1 << 4) > +#define INTKNEPMISMSK (1 << 5) > +#define INEPNAKEFFMSK (1 << 6) > +#define TXFIFOUNDRN (1 << 8) > + /* Device OUT Endpoint Common Interrupt Mask Register. Offset: 814h */ > + u32 doepmsk; > +#define XFERCOMPLMSK (1 << 0) > +#define EPDISABLEDMSK (1 << 1) > +#define AHBERRMSK (1 << 2) > +#define SETUPMSK (1 << 3) > +#define INTKNTXFEMPMSK (1 << 4) > + /* Device All Endpoints Interrupt Register. Offset: 818h */ > + u32 daint; > + /* Device All Endpoints Interrupt Mask Register. Offset: 81Ch */ > + u32 daintmsk; > +#define DAINTMASK_IN_SHIFT 0 > +#define DAINTMASK_OUT_SHIFT 16 > + /* Device IN Token Queue Read Register-1 (Read Only). Offset: 820h */ > + u32 dtknqr1; > +#define EPTK0_5_SHIFT 8 > +#define EPTK0_5MSK ((u32)0xFFFFFF << EPTK0_5_SHIFT) > +#define INTKNWPTR_SHIFT 0 > +#define INTKNWPTRMSK ((u32)0x1F << INTKNWPTR_SHIFT) > + /* Device IN Token Queue Read Register-2 (Read Only). Offset: 824h */ > + u32 dtknqr2; > + /* Device VBUS discharge Register. Offset: 828h */ > + u32 dvbusdis; > + /* Device VBUS Pulse Register. Offset: 82Ch */ > + u32 dvbuspulse; > + /* Device IN Token Queue Read Register-3 (Read Only). Offset: 830h */ > + u32 dtknqr3_dthrctl; > + /* Device IN Token Queue Read Register-4 (Read Only). Offset: 834h */ > + u32 dtknqr4_fifoemptymsk; > +}; > +/* > + * Device Logical IN Endpoint-Specific Registers. Offsets 900h-AFCh > + * > + * There will be one set of endpoint registers per logical endpoint > implemented. + * > + * These registers are visible only in Device mode and must not be > accessed in + * Host mode, as the results are unknown. > + */ > +struct device_in_ep_regs { > + /* > + * Device IN Endpoint Control Register. > + * Offset:900h + (ep_num * 20h) + 00h > + */ > + u32 diepctl; > +#define EPENA ((u32)1 << 31) > +#define EPDIS (1 << 30) > +#define SNAK (1 << 27) > +#define CNAK (1 << 26) > +#define SSTALL (1 << 21) > +#define MPS_SHIFT 0 > +#define MPSMSK0 (3 << MPS_SHIFT) > +#define DWC_DEP0CTL_MPS_64 0 > +#define DWC_DEP0CTL_MPS_32 1 > +#define DWC_DEP0CTL_MPS_16 2 > +#define DWC_DEP0CTL_MPS_8 3 > +#define DIEPCTL_MPSMSK (0x7FF << MPS_SHIFT) > + /* Reserved. Offset:900h + (ep_num * 20h) + 04h */ > + u32 reserved04; > + /* > + * Device IN Endpoint Interrupt Register. > + * Offset:900h + (ep_num * 20h) + 08h > + */ > + u32 diepint; > +#define TXFEMP (1 << 7) > +#define INTKNTXFEMP (1 << 4) > +#define XFERCOMPL (1 << 0) > + /* Reserved. Offset:900h + (ep_num * 20h) + 0Ch */ > + u32 reserved0C; > + /* Device IN Endpoint Transfer Size Register. > + * Offset:900h + (ep_num * 20h) + 10h > + */ > + u32 dieptsiz; > +#define PKTCNT_SHIFT 19 > + /* > + * Device IN Endpoint DMA Address Register. > + * Offset:900h + (ep_num * 20h) + 14h > + */ > + u32 diepdma; > + /* Reserved. > + * Offset:900h + (ep_num * 20h) + 18h - 900h + (ep_num * 20h) + 1Ch > + */ > + u32 dtxfsts; > + /* > + * Reserved. > + * Offset:900h + (ep_num * 20h) + 1Ch - 900h + (ep_num * 20h) + 1Ch > + */ > + u32 reserved18; > +}; > + > +/* > + * Device Logical OUT Endpoint-Specific Registers. Offsets: B00h-CFCh > + * > + * There will be one set of endpoint registers per logical endpoint > implemented. + * > + * These registers are visible only in Device mode and must not be > accessed in + * Host mode, as the results are unknown. > + */ > +struct device_out_ep_regs { > + /* > + * Device OUT Endpoint Control Register. > + * Offset:B00h + (ep_num * 20h) + 00h > + */ > + u32 doepctl; > +#define DOEPCTL_MPSMSK 0x7FF > +#define USBACTEP (1 << 15) > +#define EPTYPE_SHIFT 18 > +#define EPTYPEMSK (0x3 << EPTYPE_SHIFT) > +#define EPTYPE_BULK 0x2 > +#define EPTYPE_INT 0x3 > +#define DATA0PID (1 << 28) > +#define DATA1PID (1 << 29) > +#define DPIDMSK (1 << 16) > + /* > + * Device OUT Endpoint Frame number Register. > + * Offset: B00h + (ep_num * 20h) + 04h > + */ > + u32 doepfn; > + /* > + * Device OUT Endpoint Interrupt Register. > + * Offset:B00h + (ep_num * 20h) + 08h > + */ > + u32 doepint; > +#define XFERCOMPL (1 << 0) > +#define EPDISBLD (1 << 1) > +#define AHBERR (1 << 2) > +#define SETUP (1 << 3) > + /* Reserved. Offset:B00h + (ep_num * 20h) + 0Ch */ > + u32 reserved0C; > + /* > + * Device OUT Endpoint Transfer Size Register. > + * Offset: B00h + (ep_num * 20h) + 10h > + */ > + u32 doeptsiz; > +#define XFERSIZE_SHIFT 0 > +#define XFERSIZEMSK 0x3F > +#define PKTCNT_SHIFT 19 > +#define PKTCNT (3 << 19) > +#define SUPCNT_SHIFT 29 > +#define SUPCNTMSK (3 << SUPCNT_SHIFT) > + /* > + * Device OUT Endpoint DMA Address Register. > + * Offset:B00h + (ep_num * 20h) + 14h > + */ > + u32 doepdma; > + /* > + * Reserved. > + * Offset:B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch > + */ > + u32 unused[2]; > +}; > +#define MAX_EPS_CHANNELS 4 > + > +/* > + * The dwc_ep structure represents the state of a single endpoint when > acting in + * device mode. It contains the data items needed for an > endpoint to be + * activated and transfer packets. > + */ > +struct dwc_ep { > + /* EP number used for register address lookup */ > + u8 num; > + /* EP direction 0 = OUT */ > +#if 0 > + u8 is_in; > +#endif > + /* pointer to the transfer buffer */ > + u8 *xfer_buff; > + /* Number of bytes to transfer */ > + u32 xfer_len; > +}; > + > +/* > + * DWC_otg PCD Structure. > + * This structure encapsulates the data for the dwc_otg PCD. > + */ > +struct dwc_pcd { > +#if 0 > + /* USB gadget */ > + /* Current configuration */ > + u8 configuration; > + /* Current interface */ > + u8 interface; > + /* Current alternate settinng */ > + u8 alternate; indent > + /* Current Address */ > + u16 address; > + /* device state */ > +/* usb_device_state_t device_state; */ /* current USB Device state */ > + /* > + * SETUP packet for EP0. This structure is allocated as a DMA buffer on > + * PCD initialization with enough space for up to 3 setup packets. > + */ > +#endif > + struct usb_device_request *req; > + /* Array of EPs. */ > + struct dwc_ep ep0; > + /* Array of IN EPs. */ > + struct dwc_ep in_ep[MAX_EPS_CHANNELS - 1]; > + /* Array of OUT EPs. */ > + struct dwc_ep out_ep[MAX_EPS_CHANNELS - 1]; > +}; > + > +/* > + * The device_if structure contains information needed to manage the > DWC_otg + * controller acting in device mode. It represents the > programming view of the + * device-specific aspects of the controller. > + */ > +struct device_if { > + struct core_global_regs *core_global_regs; > + /* Common configuration information */ > + > + /* Device Global Registers starting at offset 800h */ > + struct device_global_regs *dev_global_regs; > +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800 > + > + /* Device Logical IN Endpoint-Specific Registers 900h-AFCh */ > + struct device_in_ep_regs *in_ep_regs[MAX_EPS_CHANNELS]; > +#define DWC_DEV_IN_EP_REG_OFFSET 0x900 > +#define DWC_EP_REG_OFFSET 0x20 > + > + /* Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ > + struct device_out_ep_regs *out_ep_regs[MAX_EPS_CHANNELS]; > +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00 > + > + /* Push/pop addresses for endpoints or host channels.*/ > + u32 *data_fifo[MAX_EPS_CHANNELS]; > +#define DWC_OTG_DATA_FIFO_OFFSET 0x1000 > +#define DWC_OTG_DATA_FIFO_SIZE 0x1000 > + > + struct dwc_pcd pcd; > + int speed; > +}; > + > + > +/* Function declarations */ > + > +void phy_init(void); > +void udc_irq(void); > + > +void udc_set_nak(int epid); > +void udc_unset_nak(int epid); > +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); > +int udc_init(void); > +/* void udc_enable(struct usb_device_instance *device);*/ > +void udc_disable(void); > +void udc_connect(void); > +void udc_disconnect(void); > +void udc_startup_events(struct usb_device_instance *device); > +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, > + struct usb_endpoint_instance *endpoint); > +void udc_set_configuration_controller(u32); > +void udc_set_address_controller(u32); > + > +#endif /* __DW_UDC_H */ Thanks for your good work so far, keep it up ! :-) _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot