|
@@ -182,14 +182,29 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
|
|
|
|
|
|
/* start at the end of the GNPTXFSIZ, rounded up */
|
|
|
addr = 2048 + 1024;
|
|
|
- size = 768;
|
|
|
|
|
|
/*
|
|
|
- * currently we allocate TX FIFOs for all possible endpoints,
|
|
|
- * and assume that they are all the same size.
|
|
|
+ * Because we have not enough memory to have each TX FIFO of size at
|
|
|
+ * least 3072 bytes (the maximum single packet size), we create four
|
|
|
+ * FIFOs of lenght 1024, and four of length 3072 bytes, and assing
|
|
|
+ * them to endpoints dynamically according to maxpacket size value of
|
|
|
+ * given endpoint.
|
|
|
*/
|
|
|
|
|
|
- for (ep = 1; ep <= 15; ep++) {
|
|
|
+ /* 256*4=1024 bytes FIFO length */
|
|
|
+ size = 256;
|
|
|
+ for (ep = 1; ep <= 4; ep++) {
|
|
|
+ val = addr;
|
|
|
+ val |= size << FIFOSIZE_DEPTH_SHIFT;
|
|
|
+ WARN_ONCE(addr + size > hsotg->fifo_mem,
|
|
|
+ "insufficient fifo memory");
|
|
|
+ addr += size;
|
|
|
+
|
|
|
+ writel(val, hsotg->regs + DPTXFSIZN(ep));
|
|
|
+ }
|
|
|
+ /* 768*4=3072 bytes FIFO length */
|
|
|
+ size = 768;
|
|
|
+ for (ep = 5; ep <= 8; ep++) {
|
|
|
val = addr;
|
|
|
val |= size << FIFOSIZE_DEPTH_SHIFT;
|
|
|
WARN_ONCE(addr + size > hsotg->fifo_mem,
|
|
@@ -1834,7 +1849,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
|
|
|
if (dir_in) {
|
|
|
int epctl = readl(hsotg->regs + epctl_reg);
|
|
|
|
|
|
- s3c_hsotg_txfifo_flush(hsotg, idx);
|
|
|
+ s3c_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
|
|
|
|
|
|
if ((epctl & DXEPCTL_STALL) &&
|
|
|
(epctl & DXEPCTL_EPTYPE_BULK)) {
|
|
@@ -1983,6 +1998,7 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
|
|
|
int result, bool force)
|
|
|
{
|
|
|
struct s3c_hsotg_req *req, *treq;
|
|
|
+ unsigned size;
|
|
|
|
|
|
list_for_each_entry_safe(req, treq, &ep->queue, queue) {
|
|
|
/*
|
|
@@ -1996,9 +2012,11 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
|
|
|
s3c_hsotg_complete_request(hsotg, ep, req,
|
|
|
result);
|
|
|
}
|
|
|
- if (hsotg->dedicated_fifos)
|
|
|
- if ((readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4 < 3072)
|
|
|
- s3c_hsotg_txfifo_flush(hsotg, ep->index);
|
|
|
+ if (!hsotg->dedicated_fifos)
|
|
|
+ return;
|
|
|
+ size = (readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4;
|
|
|
+ if (size < ep->fifo_size)
|
|
|
+ s3c_hsotg_txfifo_flush(hsotg, ep->fifo_index);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -2439,6 +2457,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
|
|
|
u32 epctrl;
|
|
|
u32 mps;
|
|
|
int dir_in;
|
|
|
+ int i, val, size;
|
|
|
int ret = 0;
|
|
|
|
|
|
dev_dbg(hsotg->dev,
|
|
@@ -2511,17 +2530,8 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
|
|
|
break;
|
|
|
|
|
|
case USB_ENDPOINT_XFER_INT:
|
|
|
- if (dir_in) {
|
|
|
- /*
|
|
|
- * Allocate our TxFNum by simply using the index
|
|
|
- * of the endpoint for the moment. We could do
|
|
|
- * something better if the host indicates how
|
|
|
- * many FIFOs we are expecting to use.
|
|
|
- */
|
|
|
-
|
|
|
+ if (dir_in)
|
|
|
hs_ep->periodic = 1;
|
|
|
- epctrl |= DXEPCTL_TXFNUM(index);
|
|
|
- }
|
|
|
|
|
|
epctrl |= DXEPCTL_EPTYPE_INTERRUPT;
|
|
|
break;
|
|
@@ -2535,8 +2545,25 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
|
|
|
* if the hardware has dedicated fifos, we must give each IN EP
|
|
|
* a unique tx-fifo even if it is non-periodic.
|
|
|
*/
|
|
|
- if (dir_in && hsotg->dedicated_fifos)
|
|
|
- epctrl |= DXEPCTL_TXFNUM(index);
|
|
|
+ if (dir_in && hsotg->dedicated_fifos) {
|
|
|
+ size = hs_ep->ep.maxpacket*hs_ep->mc;
|
|
|
+ for (i = 1; i <= 8; ++i) {
|
|
|
+ if (hsotg->fifo_map & (1<<i))
|
|
|
+ continue;
|
|
|
+ val = readl(hsotg->regs + DPTXFSIZN(i));
|
|
|
+ val = (val >> FIFOSIZE_DEPTH_SHIFT)*4;
|
|
|
+ if (val < size)
|
|
|
+ continue;
|
|
|
+ hsotg->fifo_map |= 1<<i;
|
|
|
+
|
|
|
+ epctrl |= DXEPCTL_TXFNUM(i);
|
|
|
+ hs_ep->fifo_index = i;
|
|
|
+ hs_ep->fifo_size = val;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (i == 8)
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
|
|
|
/* for non control endpoints, set PID to D0 */
|
|
|
if (index)
|
|
@@ -2583,6 +2610,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
|
|
|
/* terminate all requests with shutdown */
|
|
|
kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
|
|
|
|
|
|
+ hsotg->fifo_map &= ~(1<<hs_ep->fifo_index);
|
|
|
+ hs_ep->fifo_index = 0;
|
|
|
+ hs_ep->fifo_size = 0;
|
|
|
|
|
|
ctrl = readl(hsotg->regs + epctrl_reg);
|
|
|
ctrl &= ~DXEPCTL_EPENA;
|
|
@@ -2974,7 +3004,6 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
|
|
|
struct s3c_hsotg_ep *hs_ep,
|
|
|
int epnum)
|
|
|
{
|
|
|
- u32 ptxfifo;
|
|
|
char *dir;
|
|
|
|
|
|
if (epnum == 0)
|
|
@@ -3002,15 +3031,6 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
|
|
|
usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT);
|
|
|
hs_ep->ep.ops = &s3c_hsotg_ep_ops;
|
|
|
|
|
|
- /*
|
|
|
- * Read the FIFO size for the Periodic TX FIFO, even if we're
|
|
|
- * an OUT endpoint, we may as well do this if in future the
|
|
|
- * code is changed to make each endpoint's direction changeable.
|
|
|
- */
|
|
|
-
|
|
|
- ptxfifo = readl(hsotg->regs + DPTXFSIZN(epnum));
|
|
|
- hs_ep->fifo_size = FIFOSIZE_DEPTH_GET(ptxfifo) * 4;
|
|
|
-
|
|
|
/*
|
|
|
* if we're using dma, we need to set the next-endpoint pointer
|
|
|
* to be something valid.
|