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); flush_dcache_range((unsigned long) p , (unsigned long) p + DMA_BUFFER_SIZE); if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; /* Flush the endpoint's Tx FIFO */ writel(TX_FIFO_NUMBER(ep->fifo_num), ®->grstctl); writel(TX_FIFO_NUMBER(ep->fifo_num) | TX_FIFO_FLUSH, ®->grstctl); while (readl(®->grstctl) & TX_FIFO_FLUSH) ; writel(the_controller->dma_addr[ep_index(ep)+1], ®->in_endp[ep_num].diepdma); writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length), ®->in_endp[ep_num].dieptsiz); ctrl = readl(®->in_endp[ep_num].diepctl); /* Write the FIFO number to be used for this endpoint */ ctrl &= DIEPCTL_TX_FIFO_NUM_MASK; ctrl |= DIEPCTL_TX_FIFO_NUM(ep->fifo_num); /* Clear reserved (Next EP) bits */ ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT)); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->in_endp[ep_num].diepctl); debug_cond(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; }
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; }
/** Write request to FIFO (max write == maxp size) * Return: 0 = still running, 1 = completed, negative = errno * NOTE: INDEX register must be set for EP */ static int write_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req) { u32 max; u32 csr; max = le16_to_cpu(ep->desc->wMaxPacketSize); csr = usb_read(ep->csr1); DEBUG("CSR: %x %d\n", csr, csr & USB_IN_CSR1_FIFO_NOT_EMPTY); if (!(csr & USB_IN_CSR1_FIFO_NOT_EMPTY)) { unsigned count; int is_last, is_short; count = write_packet(ep, req, max); usb_set(USB_IN_CSR1_IN_PKT_RDY, ep->csr1); /* 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("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, ep->ep.name, count, is_last ? "/L" : "", is_short ? "/S" : "", req->req.length - req->req.actual, req); /* requests complete when all IN data is in the FIFO */ if (is_last) { done(ep, req, 0); if (list_empty(&ep->queue)) { pio_irq_disable(ep_index(ep)); } return 1; } } else { DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); } return 0; }
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; }
/** Write request to FIFO (max write == maxp size) * Return: 0 = still running, 1 = completed, negative = errno */ static int write_fifo(struct elfin_ep *ep, struct elfin_request *req) { u32 max; unsigned count; int is_last, is_short; 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)); } /* requests complete when all IN data is in the FIFO */ if (is_last) { if(!ep_index(ep)){ // EP0 must not come here BUG(); //usb_set(S3C2410_UDC_EP0_CSR_IPKRDY | S3C2410_UDC_EP0_CSR_DE, // S3C2410_UDC_EP0_CSR_REG, 0); }else{ usb_set(S3C2410_UDC_ICSR1_PKTRDY, ep->csr1, ep_index(ep)); } done(ep, req, 0); return 1; } else{ usb_set(S3C2410_UDC_ICSR1_PKTRDY, ep->csr1, ep_index(ep)); } DEBUG_EP0("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, ep->ep.name, count, is_last ? "/L" : "", is_short ? "/S" : "", req->req.length - req->req.actual, req); return 0; }
/* until it's enabled, this UDC should be completely invisible * to any USB host. */ static void udc_enable(struct lh7a40x_udc *dev) { int ep; DEBUG("%s, %p\n", __FUNCTION__, dev); dev->gadget.speed = USB_SPEED_UNKNOWN; #ifdef CONFIG_ARCH_LH7A404 /* Set Port C bit 1 & 2 as output */ set_portc_ddr(1, 1); set_portc_ddr(2, 1); /* Enable USB power */ set_portc_dr(1, 0); #endif /* * C.f Chapter 18.1.3.1 Initializing the USB */ /* Disable the USB */ usb_clear(PM_USB_ENABLE, USB_PM); /* Reset APB & I/O sides of the USB */ usb_set(USB_RESET_APB | USB_RESET_IO, USB_RESET); mdelay(5); usb_clear(USB_RESET_APB | USB_RESET_IO, USB_RESET); /* Set MAXP values for each */ for (ep = 0; ep < UDC_MAX_ENDPOINTS; ep++) { struct lh7a40x_ep *ep_reg = &dev->ep[ep]; u32 csr; usb_set_index(ep); switch (ep_reg->ep_type) { case ep_bulk_in: case ep_interrupt: usb_clear(USB_IN_CSR2_USB_DMA_EN | USB_IN_CSR2_AUTO_SET, ep_reg->csr2); /* Fall through */ case ep_control: usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), USB_IN_MAXP); break; case ep_bulk_out: usb_clear(USB_OUT_CSR2_USB_DMA_EN | USB_OUT_CSR2_AUTO_CLR, ep_reg->csr2); usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), USB_OUT_MAXP); break; } /* Read & Write CSR1, just in case */ csr = usb_read(ep_reg->csr1); usb_write(csr, ep_reg->csr1); flush(ep_reg); } /* Disable interrupts */ usb_write(0, USB_IN_INT_EN); usb_write(0, USB_OUT_INT_EN); usb_write(0, USB_INT_EN); /* Enable interrupts */ usb_set(USB_IN_INT_EP0, USB_IN_INT_EN); usb_set(USB_INT_RESET_INT | USB_INT_RESUME_INT, USB_INT_EN); /* Dont enable rest of the interrupts */ /* usb_set(USB_IN_INT_EP3 | USB_IN_INT_EP1 | USB_IN_INT_EP0, USB_IN_INT_EN); usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); */ /* Enable SUSPEND */ usb_set(PM_ENABLE_SUSPEND, USB_PM); /* Enable the USB */ usb_set(PM_USB_ENABLE, USB_PM); #ifdef CONFIG_ARCH_LH7A404 /* NOTE: DOES NOT WORK! */ /* Let host detect UDC: * Software must write a 0 to the PMR:DCP_CTRL bit to turn this * transistor on and pull the USBDP pin HIGH. */ /* usb_clear(PM_USB_DCP, USB_PM); usb_set(PM_USB_DCP, USB_PM); */ #endif }
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; }