static inline void s3c_ep0_complete_out(void) { u32 ep_ctrl; DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n", __func__, readl(®->in_endp[EP0_CON].diepctl)); DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n", __func__, readl(®->out_endp[EP0_CON].doepctl)); DEBUG_IN_EP("%s : Prepare Complete Out packet.\n", __func__); writel((1 << 19) | sizeof(struct usb_ctrlrequest), ®->out_endp[EP0_CON].doeptsiz); writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma); ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, ®->out_endp[EP0_CON].doepctl); DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n", __func__, readl(®->in_endp[EP0_CON].diepctl)); DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n", __func__, readl(®->out_endp[EP0_CON].doepctl)); }
static int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl = 0; u32 length, pktcnt; u32 ep_num = ep_index(ep); struct device *dev = &the_controller->dev->dev; buf = req->req.buf + req->req.actual; prefetch(buf); length = req->req.length - req->req.actual; if (ep_num == EP0_CON) length = min(length, (u32)ep_maxpacket(ep)); req->req.actual += length; req->req.dma = dma_map_single(dev, buf, length, DMA_TO_DEVICE); req->mapped = 1; if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; #ifdef DED_TX_FIFO /* Flush the endpoint's Tx FIFO */ writel(ep_num<<6, S3C_UDC_OTG_GRSTCTL); writel((ep_num<<6)|0x20, S3C_UDC_OTG_GRSTCTL); while (readl(S3C_UDC_OTG_GRSTCTL) & 0x20) ; /* Write the FIFO number to be used for this endpoint */ ctrl = readl(S3C_UDC_OTG_DIEPCTL(ep_num)); ctrl &= ~DEPCTL_TXFNUM_MASK;; ctrl |= (ep_num << DEPCTL_TXFNUM_BIT); writel(ctrl , S3C_UDC_OTG_DIEPCTL(ep_num)); #endif writel(virt_to_phys(buf), S3C_UDC_OTG_DIEPDMA(ep_num)); writel((pktcnt<<19)|(length<<0), S3C_UDC_OTG_DIEPTSIZ(ep_num)); ctrl = readl(S3C_UDC_OTG_DIEPCTL(ep_num)); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, S3C_UDC_OTG_DIEPCTL(ep_num)); #ifndef DED_TX_FIFO ctrl = readl(S3C_UDC_OTG_DIEPCTL(EP0_CON)); ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT))|(ep_num<<DEPCTL_NEXT_EP_BIT); writel(ctrl, S3C_UDC_OTG_DIEPCTL(EP0_CON)); #endif DEBUG_IN_EP("%s:EP%d TX DMA start : DIEPDMA0 = 0x%x, DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, readl(S3C_UDC_OTG_DIEPDMA(ep_num)), readl(S3C_UDC_OTG_DIEPTSIZ(ep_num)), readl(S3C_UDC_OTG_DIEPCTL(ep_num)), buf, pktcnt, length); return length; }
//set ep_num's DIEPCTLn.nextep 4 bits next_ep for EP_IN static void s3c_set_next_ep(u8 ep_num, u8 next_ep) { u32 ctrl; ctrl = readl(S3C_UDC_OTG_DIEPCTL0+DEP_OFFSET*ep_num); //DIEPCTLn.nextep 4bits ctrl &= ~(0xf<<DIEPCTL_NEXT_EP_BIT); writel(next_ep<<DIEPCTL_NEXT_EP_BIT |ctrl, S3C_UDC_OTG_DIEPCTL0+DEP_OFFSET*ep_num); DEBUG_IN_EP("[%s] : set EP[%d].nextep => EP[%d]\n", __FUNCTION__, ep_num, next_ep); }
static inline void s3c_udc_pre_setup(void) { u32 ep_ctrl; DEBUG_IN_EP("%s : Prepare Setup packets.\n", __func__); writel((1 << 19)|sizeof(struct usb_ctrlrequest), S3C_UDC_OTG_DOEPTSIZ(EP0_CON)); writel(virt_to_phys(&usb_ctrl), S3C_UDC_OTG_DOEPDMA(EP0_CON)); ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL(EP0_CON)); writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, S3C_UDC_OTG_DOEPCTL(EP0_CON)); }
static inline void s3c_udc_pre_setup(struct s3c_udc *dev) { u32 ep_ctrl; DEBUG_IN_EP("%s : Prepare Setup packets.\n", __func__); __raw_writel((3<<29) | (1<<19) | sizeof(struct usb_ctrlrequest), dev->regs + S3C_UDC_OTG_DOEPTSIZ(EP0_CON)); __raw_writel(dev->usb_ctrl_dma, dev->regs + S3C_UDC_OTG_DOEPDMA(EP0_CON)); ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DOEPCTL(EP0_CON)); __raw_writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, dev->regs + S3C_UDC_OTG_DOEPCTL(EP0_CON)); }
static int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl = 0; u32 length, pktcnt; u32 ep_num = ep_index(ep); buf = req->req.buf + req->req.actual; prefetch(buf); length = req->req.length - req->req.actual; if (ep_num == EP0_CON) { length = min(length, (u32)ep_maxpacket(ep)); } req->req.actual += length; dma_cache_maint(buf, length, DMA_TO_DEVICE); if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; #ifdef DED_TX_FIFO /* Write the FIFO number to be used for this endpoint */ ctrl = readl(S3C_UDC_OTG_DIEPCTL(ep_num)); ctrl &= ~DEPCTL_TXFNUM_MASK;; ctrl |= (ep_num << DEPCTL_TXFNUM_BIT); writel(ctrl , S3C_UDC_OTG_DIEPCTL(ep_num)); #endif writel(virt_to_phys(buf), S3C_UDC_OTG_DIEPDMA(ep_num)); writel((pktcnt<<19)|(length<<0), S3C_UDC_OTG_DIEPTSIZ(ep_num)); ctrl = readl(S3C_UDC_OTG_DIEPCTL(ep_num)); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, S3C_UDC_OTG_DIEPCTL(ep_num)); ctrl = readl(S3C_UDC_OTG_DIEPCTL(EP0_CON)); ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT))|(ep_num<<DEPCTL_NEXT_EP_BIT); writel(ctrl, S3C_UDC_OTG_DIEPCTL(EP0_CON)); DEBUG_IN_EP("%s:EP%d TX DMA start : DIEPDMA0 = 0x%x, DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, readl(S3C_UDC_OTG_DIEPDMA(ep_num)), readl(S3C_UDC_OTG_DIEPTSIZ(ep_num)), readl(S3C_UDC_OTG_DIEPCTL(ep_num)), buf, pktcnt, length); return length; }
/** Write request to FIFO (max write == maxp size) * Return: 0 = still running, 1 = completed, negative = errno */ static int write_fifo(struct s3c_ep *ep, struct s3c_request *req) { u32 max, gintmsk; unsigned count; int is_last = 0, is_short = 0; gintmsk = readl(S3C_UDC_OTG_GINTMSK); max = le16_to_cpu(ep->desc->wMaxPacketSize); count = write_packet(ep, req, max); /* last packet is usually short (or a zlp) */ if (unlikely(count != max)) is_last = is_short = 1; else { if (likely(req->req.length != req->req.actual) || req->req.zero) is_last = 0; else is_last = 1; /* interrupt/iso maxpacket may not fill the fifo */ is_short = unlikely(max < ep_maxpacket(ep)); } DEBUG_IN_EP("%s: wrote %s %d bytes%s%s req %p %d/%d\n", __FUNCTION__, ep->ep.name, count, is_last ? "/L" : "", is_short ? "/S" : "", req, req->req.actual, req->req.length); /* requests complete when all IN data is in the FIFO */ if (is_last) { if(!ep_index(ep)){ printk("%s: --> Error EP0 must not come here!\n", __FUNCTION__); BUG(); } writel(gintmsk&(~INT_NP_TX_FIFO_EMPTY), S3C_UDC_OTG_GINTMSK); done(ep, req, 0); return 1; } /* Unmask USB OTG 2.0 interrupt source : INT_NP_TX_FIFO_EMPTY */ writel(gintmsk | INT_NP_TX_FIFO_EMPTY, S3C_UDC_OTG_GINTMSK); return 0; }
/** * s3c_in_epn - handle IN interrupt */ static void s3c_in_epn(struct s3c_udc *dev, u32 ep_idx) { struct s3c_ep *ep = &dev->ep[ep_idx]; struct s3c_request *req; if (list_empty(&ep->queue)) req = 0; else req = list_entry(ep->queue.next, struct s3c_request, queue); if (unlikely(!req)) { DEBUG_IN_EP("%s: NULL REQ on IN EP-%d\n", __FUNCTION__, ep_idx); return; } else { write_fifo(ep, req); } }
static inline void s3c_udc_pre_setup(void) { u32 ep_ctrl; DEBUG_IN_EP("%s : Prepare Setup packets.\n", __func__); writel((1 << 19) | sizeof(struct usb_ctrlrequest), ®->out_endp[EP0_CON].doeptsiz); writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma); ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); writel(ep_ctrl|DEPCTL_EPENA, ®->out_endp[EP0_CON].doepctl); DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n", __func__, readl(®->in_endp[EP0_CON].diepctl)); DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n", __func__, readl(®->out_endp[EP0_CON].doepctl)); }
/* Inline code */ static __inline__ int write_packet(struct s3c_ep *ep, struct s3c_request *req, int max) { u32 *buf; int length, count; u32 fifo = ep->fifo, in_ctrl; buf = req->req.buf + req->req.actual; prefetch(buf); length = req->req.length - req->req.actual; length = min(length, max); req->req.actual += length; DEBUG("%s: Write %d (max %d), fifo=0x%x\n", __FUNCTION__, length, max, fifo); if(ep_index(ep) == EP0_CON) { writel((1<<19)|(length<<0), (u32) S3C_UDC_OTG_DIEPTSIZ0); in_ctrl = readl(S3C_UDC_OTG_DIEPCTL0); writel(DEPCTL_EPENA|DEPCTL_CNAK|(EP2_IN<<11)| in_ctrl, (u32) S3C_UDC_OTG_DIEPCTL0); DEBUG_EP0("%s:(DIEPTSIZ0):0x%x, (DIEPCTL0):0x%x, (GNPTXSTS):0x%x\n", __FUNCTION__, readl(S3C_UDC_OTG_DIEPTSIZ0),readl(S3C_UDC_OTG_DIEPCTL0), readl(S3C_UDC_OTG_GNPTXSTS)); udelay(30); } else if ((ep_index(ep) == EP2_IN)) { writel((1<<19)|(length<<0), S3C_UDC_OTG_DIEPTSIZ2); in_ctrl = readl(S3C_UDC_OTG_DIEPCTL2); writel(DEPCTL_EPENA|DEPCTL_CNAK|(EP2_IN<<11)| in_ctrl, (u32) S3C_UDC_OTG_DIEPCTL2); DEBUG_IN_EP("%s:(DIEPTSIZ2):0x%x, (DIEPCTL2):0x%x, (GNPTXSTS):0x%x\n", __FUNCTION__, readl(S3C_UDC_OTG_DIEPTSIZ2),readl(S3C_UDC_OTG_DIEPCTL2), readl(S3C_UDC_OTG_GNPTXSTS)); udelay(30); } else if ((ep_index(ep) == EP3_IN)) { if (set_interface_first == 1) { DEBUG_IN_EP("%s: first packet write skipped after set_interface\n", __FUNCTION__); set_interface_first = 0; return length; } writel((1<<19)|(length<<0), S3C_UDC_OTG_DIEPTSIZ3); in_ctrl = readl(S3C_UDC_OTG_DIEPCTL3); writel(DEPCTL_EPENA|DEPCTL_CNAK|(EP2_IN<<11)| in_ctrl, (u32) S3C_UDC_OTG_DIEPCTL3); DEBUG_IN_EP("%s:(DIEPTSIZ3):0x%x, (DIEPCTL3):0x%x, (GNPTXSTS):0x%x\n", __FUNCTION__, readl(S3C_UDC_OTG_DIEPTSIZ3),readl(S3C_UDC_OTG_DIEPCTL3), readl(S3C_UDC_OTG_GNPTXSTS)); udelay(30); } else { printk("%s: --> Error Unused Endpoint!!\n", __FUNCTION__); BUG(); } for (count = 0; count < length; count += 4) writel(*buf++, fifo); return length; }
static int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl = 0; u32 length, pktcnt; u32 ep_num = ep_index(ep); struct s3c_udc *udc = ep->dev; struct device *dev = &udc->dev->dev; aligned_map_buf(req, ep_is_in(ep)); buf = req->req.buf + req->req.actual; prefetch(buf); length = req->req.length - req->req.actual; if (ep_num == EP0_CON) length = min_t(u32, length, (u32)ep_maxpacket(ep)); req->req.actual += length; req->req.dma = dma_map_single(dev, buf, length, DMA_TO_DEVICE); req->mapped = 1; if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; #ifdef DED_TX_FIFO /* Write the FIFO number to be used for this endpoint */ ctrl = __raw_readl(udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num)); ctrl &= ~DEPCTL_TXFNUM_MASK; ctrl |= (ep_num << DEPCTL_TXFNUM_BIT); __raw_writel(ctrl , udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num)); #endif __raw_writel(virt_to_phys(buf), udc->regs + S3C_UDC_OTG_DIEPDMA(ep_num)); __raw_writel((pktcnt<<19)|(length<<0), udc->regs + S3C_UDC_OTG_DIEPTSIZ(ep_num)); ctrl = __raw_readl(udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num)); if ((ctrl & DEPCTL_TYPE_MASK) == DEPCTL_ISO_TYPE) { if (ctrl & DEPCTL_EO_FRNUM) ctrl |= DEPCTL_SETD0PID; else ctrl |= DEPCTL_SETD1PID; } __raw_writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num)); #ifndef DED_TX_FIFO ctrl = __raw_readl(udc->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON)); ctrl = (ctrl & ~(EP_MASK<<DEPCTL_NEXT_EP_BIT)) | (ep_num<<DEPCTL_NEXT_EP_BIT); __raw_writel(ctrl, udc->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON)); #endif DEBUG_IN_EP("%s:EP%d TX DMA start : DIEPDMA0 = 0x%x," "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, __raw_readl(udc->regs + S3C_UDC_OTG_DIEPDMA(ep_num)), __raw_readl(udc->regs + S3C_UDC_OTG_DIEPTSIZ(ep_num)), __raw_readl(udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num)), buf, pktcnt, length); req->written_bytes = length; return length; }
static int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl = 0; u32 length, pktcnt; u32 ep_num = ep_index(ep); u32 *p = the_controller->dma_buf[ep_index(ep)+1]; buf = req->req.buf + req->req.actual; length = req->req.length - req->req.actual; if (ep_num == EP0_CON) length = min(length, (u32)ep_maxpacket(ep)); ep->len = length; ep->dma_buf = buf; memcpy(p, ep->dma_buf, length); if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; #if 0 /* Flush the endpoint's Tx FIFO */ writel(ep->fifo_num<<6, ®->grstctl); writel((ep->fifo_num<<6)|0x20, ®->grstctl); while (readl(®->grstctl) & 0x20) ; /* Write the FIFO number to be used for this endpoint */ ctrl = readl(®->in_endp[ep_num].diepctl); ctrl &= ~(0xF << 22); ctrl |= (ep_num << 22); writel(ctrl , ®->in_endp[ep_num].diepctl); #endif ctrl = readl(®->in_endp[ep_num].diepctl); DEBUG_IN_EP("%s: epindex %d setting diepdma to 0x%x\n",__func__,ep_index(ep),the_controller->dma_addr[ep_index(ep)+1]); writel(the_controller->dma_addr[ep_index(ep)+1], ®->in_endp[ep_num].diepdma); writel((pktcnt<<19)|(length<<0), ®->in_endp[ep_num].dieptsiz); /* Clear reserved (Next EP) bits */ ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT)); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->in_endp[ep_num].diepctl); ctrl = readl(®->in_endp[EP0_CON].diepctl); ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT))|(ep_num<<11); writel(ctrl, ®->in_endp[EP0_CON].diepctl); DEBUG_IN_EP("%s:EP%d TX DMA start : DIEPDMA0 = 0x%x," "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, readl(®->in_endp[ep_num].diepdma), readl(®->in_endp[ep_num].dieptsiz), readl(®->in_endp[ep_num].diepctl), buf, pktcnt, length); return length; }