aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2011-12-08 21:28:54 -0500
committerFelipe Balbi <balbi@ti.com>2011-12-13 06:06:26 -0500
commit3edeee3893b107364fe4ed8535245773b1e1e72b (patch)
treec2207d91e769635857b8f9b14e36ed686a6e8a32 /drivers
parente5679d07a6ca5512070fb5e65dcc66eeb5087d0d (diff)
usb: renesas_usbhs: care pipe sequence
driver has to re-use the limited pipe for each device/endpoint when it is USB host hub mode, since number of pipe has limitation. Then, each pipe should care own pipe sequence for next packet. This patch adds sequence control. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c9
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h3
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c2
-rw-r--r--drivers/usb/renesas_usbhs/mod_host.c71
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c21
5 files changed, 86 insertions, 20 deletions
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index ffdf5d15085e..b51fcd80d244 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -56,7 +56,7 @@ static struct usbhs_pkt_handle usbhsf_null_handler = {
56void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, 56void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
57 void (*done)(struct usbhs_priv *priv, 57 void (*done)(struct usbhs_priv *priv,
58 struct usbhs_pkt *pkt), 58 struct usbhs_pkt *pkt),
59 void *buf, int len, int zero) 59 void *buf, int len, int zero, int sequence)
60{ 60{
61 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); 61 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
62 struct device *dev = usbhs_priv_to_dev(priv); 62 struct device *dev = usbhs_priv_to_dev(priv);
@@ -90,6 +90,7 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
90 pkt->zero = zero; 90 pkt->zero = zero;
91 pkt->actual = 0; 91 pkt->actual = 0;
92 pkt->done = done; 92 pkt->done = done;
93 pkt->sequence = sequence;
93 94
94 usbhs_unlock(priv, flags); 95 usbhs_unlock(priv, flags);
95 /******************** spin unlock ******************/ 96 /******************** spin unlock ******************/
@@ -481,6 +482,9 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
481 int i, ret, len; 482 int i, ret, len;
482 int is_short; 483 int is_short;
483 484
485 usbhs_pipe_data_sequence(pipe, pkt->sequence);
486 pkt->sequence = -1; /* -1 sequence will be ignored */
487
484 ret = usbhsf_fifo_select(pipe, fifo, 1); 488 ret = usbhsf_fifo_select(pipe, fifo, 1);
485 if (ret < 0) 489 if (ret < 0)
486 return 0; 490 return 0;
@@ -584,6 +588,8 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
584 /* 588 /*
585 * pipe enable to prepare packet receive 589 * pipe enable to prepare packet receive
586 */ 590 */
591 usbhs_pipe_data_sequence(pipe, pkt->sequence);
592 pkt->sequence = -1; /* -1 sequence will be ignored */
587 593
588 usbhs_pipe_enable(pipe); 594 usbhs_pipe_enable(pipe);
589 usbhsf_rx_irq_ctrl(pipe, 1); 595 usbhsf_rx_irq_ctrl(pipe, 1);
@@ -641,6 +647,7 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)
641 * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function" 647 * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
642 */ 648 */
643 if (0 == rcv_len) { 649 if (0 == rcv_len) {
650 pkt->zero = 1;
644 usbhsf_fifo_clear(pipe, fifo); 651 usbhsf_fifo_clear(pipe, fifo);
645 goto usbhs_fifo_read_end; 652 goto usbhs_fifo_read_end;
646 } 653 }
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index 32a7b246b28d..f68609c0f489 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -59,6 +59,7 @@ struct usbhs_pkt {
59 int trans; 59 int trans;
60 int actual; 60 int actual;
61 int zero; 61 int zero;
62 int sequence;
62}; 63};
63 64
64struct usbhs_pkt_handle { 65struct usbhs_pkt_handle {
@@ -95,7 +96,7 @@ void usbhs_pkt_init(struct usbhs_pkt *pkt);
95void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, 96void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
96 void (*done)(struct usbhs_priv *priv, 97 void (*done)(struct usbhs_priv *priv,
97 struct usbhs_pkt *pkt), 98 struct usbhs_pkt *pkt),
98 void *buf, int len, int zero); 99 void *buf, int len, int zero, int sequence);
99struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt); 100struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
100void usbhs_pkt_start(struct usbhs_pipe *pipe); 101void usbhs_pkt_start(struct usbhs_pipe *pipe);
101 102
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index cf3141c330a3..db2a1c6a0866 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -154,7 +154,7 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep,
154 req->actual = 0; 154 req->actual = 0;
155 req->status = -EINPROGRESS; 155 req->status = -EINPROGRESS;
156 usbhs_pkt_push(pipe, pkt, usbhsg_queue_done, 156 usbhs_pkt_push(pipe, pkt, usbhsg_queue_done,
157 req->buf, req->length, req->zero); 157 req->buf, req->length, req->zero, -1);
158 usbhs_pkt_start(pipe); 158 usbhs_pkt_start(pipe);
159 159
160 dev_dbg(dev, "pipe %d : queue push (%d)\n", 160 dev_dbg(dev, "pipe %d : queue push (%d)\n",
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index c7f9be9f5c17..72ee8e55e717 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -193,6 +193,48 @@ static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv,
193/* 193/*
194 * pipe control 194 * pipe control
195 */ 195 */
196static void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv,
197 struct urb *urb,
198 struct usbhs_pkt *pkt)
199{
200 int len = urb->actual_length;
201 int maxp = usb_endpoint_maxp(&urb->ep->desc);
202 int t = 0;
203
204 /* DCP is out of sequence control */
205 if (usb_pipecontrol(urb->pipe))
206 return;
207
208 /*
209 * renesas_usbhs pipe has a limitation in a number.
210 * So, driver should re-use the limited pipe for each device/endpoint.
211 * DATA0/1 sequence should be saved for it.
212 * see [image of mod_host]
213 * [HARDWARE LIMITATION]
214 */
215
216 /*
217 * next sequence depends on actual_length
218 *
219 * ex) actual_length = 1147, maxp = 512
220 * data0 : 512
221 * data1 : 512
222 * data0 : 123
223 * data1 is the next sequence
224 */
225 t = len / maxp;
226 if (len % maxp)
227 t++;
228 if (pkt->zero)
229 t++;
230 t %= 2;
231
232 if (t)
233 usb_dotoggle(urb->dev,
234 usb_pipeendpoint(urb->pipe),
235 usb_pipeout(urb->pipe));
236}
237
196static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, 238static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv,
197 struct urb *urb); 239 struct urb *urb);
198 240
@@ -247,15 +289,6 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv,
247 usbhsh_uep_to_pipe(uep) = pipe; 289 usbhsh_uep_to_pipe(uep) = pipe;
248 usbhsh_pipe_to_uep(pipe) = uep; 290 usbhsh_pipe_to_uep(pipe) = uep;
249 291
250 if (!usb_gettoggle(urb->dev,
251 usb_pipeendpoint(urb->pipe),
252 usb_pipeout(urb->pipe))) {
253 usbhs_pipe_sequence_data0(pipe);
254 usb_settoggle(urb->dev,
255 usb_pipeendpoint(urb->pipe),
256 usb_pipeout(urb->pipe), 1);
257 }
258
259 usbhs_pipe_config_update(pipe, 292 usbhs_pipe_config_update(pipe,
260 usbhsh_device_number(hpriv, udev), 293 usbhsh_device_number(hpriv, udev),
261 usb_endpoint_num(desc), 294 usb_endpoint_num(desc),
@@ -598,10 +631,11 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
598 urb->actual_length = pkt->actual; 631 urb->actual_length = pkt->actual;
599 usbhsh_ureq_free(hpriv, ureq); 632 usbhsh_ureq_free(hpriv, ureq);
600 633
634 usbhsh_endpoint_sequence_save(hpriv, urb, pkt);
635 usbhsh_pipe_detach(hpriv, uep);
636
601 usb_hcd_unlink_urb_from_ep(hcd, urb); 637 usb_hcd_unlink_urb_from_ep(hcd, urb);
602 usb_hcd_giveback_urb(hcd, urb, 0); 638 usb_hcd_giveback_urb(hcd, urb, 0);
603
604 usbhsh_pipe_detach(hpriv, uep);
605} 639}
606 640
607static int usbhsh_queue_push(struct usb_hcd *hcd, 641static int usbhsh_queue_push(struct usb_hcd *hcd,
@@ -614,7 +648,7 @@ static int usbhsh_queue_push(struct usb_hcd *hcd,
614 struct device *dev = usbhsh_hcd_to_dev(hcd); 648 struct device *dev = usbhsh_hcd_to_dev(hcd);
615 struct usbhsh_request *ureq; 649 struct usbhsh_request *ureq;
616 void *buf; 650 void *buf;
617 int len; 651 int len, sequence;
618 652
619 if (usb_pipeisoc(urb->pipe)) { 653 if (usb_pipeisoc(urb->pipe)) {
620 dev_err(dev, "pipe iso is not supported now\n"); 654 dev_err(dev, "pipe iso is not supported now\n");
@@ -636,9 +670,15 @@ static int usbhsh_queue_push(struct usb_hcd *hcd,
636 buf = (void *)(urb->transfer_buffer + urb->actual_length); 670 buf = (void *)(urb->transfer_buffer + urb->actual_length);
637 len = urb->transfer_buffer_length - urb->actual_length; 671 len = urb->transfer_buffer_length - urb->actual_length;
638 672
673 sequence = usb_gettoggle(urb->dev,
674 usb_pipeendpoint(urb->pipe),
675 usb_pipeout(urb->pipe));
676
639 dev_dbg(dev, "%s\n", __func__); 677 dev_dbg(dev, "%s\n", __func__);
640 usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done, 678 usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done,
641 buf, len, (urb->transfer_flags & URB_ZERO_PACKET)); 679 buf, len, (urb->transfer_flags & URB_ZERO_PACKET),
680 sequence);
681
642 usbhs_pkt_start(pipe); 682 usbhs_pkt_start(pipe);
643 683
644 return 0; 684 return 0;
@@ -741,7 +781,8 @@ static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv,
741 usbhsh_data_stage_packet_done, 781 usbhsh_data_stage_packet_done,
742 urb->transfer_buffer, 782 urb->transfer_buffer,
743 urb->transfer_buffer_length, 783 urb->transfer_buffer_length,
744 (urb->transfer_flags & URB_ZERO_PACKET)); 784 (urb->transfer_flags & URB_ZERO_PACKET),
785 -1);
745 786
746 return 0; 787 return 0;
747} 788}
@@ -770,7 +811,7 @@ static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv,
770 usbhsh_queue_done, 811 usbhsh_queue_done,
771 NULL, 812 NULL,
772 urb->transfer_buffer_length, 813 urb->transfer_buffer_length,
773 0); 814 0, -1);
774 815
775 return 0; 816 return 0;
776} 817}
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index c36ad4c3a259..c2559e80d41f 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -478,10 +478,27 @@ int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe)
478 return usbhsp_flags_has(pipe, IS_DIR_HOST); 478 return usbhsp_flags_has(pipe, IS_DIR_HOST);
479} 479}
480 480
481void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data) 481void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)
482{ 482{
483 u16 mask = (SQCLR | SQSET); 483 u16 mask = (SQCLR | SQSET);
484 u16 val = (data) ? SQSET : SQCLR; 484 u16 val;
485
486 /*
487 * sequence
488 * 0 : data0
489 * 1 : data1
490 * -1 : no change
491 */
492 switch (sequence) {
493 case 0:
494 val = SQCLR;
495 break;
496 case 1:
497 val = SQSET;
498 break;
499 default:
500 return;
501 }
485 502
486 usbhsp_pipectrl_set(pipe, mask, val); 503 usbhsp_pipectrl_set(pipe, mask, val);
487} 504}