From mboxrd@z Thu Jan 1 00:00:00 1970 From: Pratyush Anand Date: Fri, 9 Mar 2012 09:30:17 +0530 Subject: [U-Boot] [PATCH] USB:gadget:designware USB OTG implementation In-Reply-To: <201203071342.07098.marex@denx.de> References: <1331121424-19508-1-git-send-email-amit.virdi@st.com> <201203071342.07098.marex@denx.de> Message-ID: <4F598051.9080502@st.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On 3/7/2012 6:12 PM, Marek Vasut wrote: > Dear Amit Virdi, > >> From: Pratyush Anand >> >> 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 >> Signed-off-by: Amit Virdi >> --- >> 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 >> #elif defined(CONFIG_DW_UDC) >> #include >> +#elif defined(CONFIG_DW_OTG) >> +#include >> #endif >> >> #include >> 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.anand at 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 ;-) > will correct.. >> +#undef APG_BOARD 1 >> + >> +#ifndef APG_BOARD > > dead code? > ohh, its there...will correct it. >> +#include >> +#include >> +#include >> +#include "ep0.h" >> +#include >> +#include >> +#else >> +#include "types.h" >> +#include >> +#include >> +#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() all the else part will vanish. this was just to test on another environment. will correct it. Sorry. > >> + >> +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 ok.. > >> + 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 ok..will provide timeout. > >> + >> + /* 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 ok.. > >> + >> + 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 ok.. > >> +} >> + >> +/* 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 ok.. > >> + } >> + } >> +} >> + >> +/* 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: ok.. > > 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 ;-) both are not writing to the same register. if is diepctl and else is doepctl. > >> + 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? should 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 ;-) ok. > >> +} >> + >> +/* 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 ? did not get warning, will cross check. > >> + 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. ok.. > >> + 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? Ok, will define it properly. > >> + >> + /* 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? will define this value. > >> + 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 ? Sorry, ifdef APG_BOARD was completely local. will correct all these. > >> +#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. ok.. > >> +} >> + >> +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 ok.. > >> +#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.anand at 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 ok.. > >> +#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 pk.. > >> + /* 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 ! :-) > . >