aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/renesas_usbhs
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2012-11-06 19:15:09 -0500
committerFelipe Balbi <balbi@ti.com>2012-11-08 08:46:06 -0500
commit1c90ee0b3e30235165180a1a8ee3fb3cbe47d295 (patch)
treeb1b820bf48e58064190d4b1d3fafba506358191b /drivers/usb/renesas_usbhs
parent7b332e5fef480ee14d133d9b83af22d03819368e (diff)
usb: renesas_usbhs: use transfer counter if IN direction bulk pipe
received data will break if it was bulk pipe and large data size, because pipe kept BUF PID even though it doesn't have enough buffer. To avoid this issue, renesas_usbhs can use transfer counter. Pipe PID will be NAK if it didn't have enough buffer by this patch. renesas_usbhs has strange address mapping. Thus, it is difficult to calculate transfer counter setting address. This patch use fixed table for it. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/renesas_usbhs')
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c4
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c101
-rw-r--r--drivers/usb/renesas_usbhs/pipe.h1
3 files changed, 106 insertions, 0 deletions
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 77f1adc2a4fc..72ad3758bd40 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -488,6 +488,8 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
488 usbhs_pipe_data_sequence(pipe, pkt->sequence); 488 usbhs_pipe_data_sequence(pipe, pkt->sequence);
489 pkt->sequence = -1; /* -1 sequence will be ignored */ 489 pkt->sequence = -1; /* -1 sequence will be ignored */
490 490
491 usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length);
492
491 ret = usbhsf_fifo_select(pipe, fifo, 1); 493 ret = usbhsf_fifo_select(pipe, fifo, 1);
492 if (ret < 0) 494 if (ret < 0)
493 return 0; 495 return 0;
@@ -594,6 +596,7 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
594 usbhs_pipe_data_sequence(pipe, pkt->sequence); 596 usbhs_pipe_data_sequence(pipe, pkt->sequence);
595 pkt->sequence = -1; /* -1 sequence will be ignored */ 597 pkt->sequence = -1; /* -1 sequence will be ignored */
596 598
599 usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length);
597 usbhs_pipe_enable(pipe); 600 usbhs_pipe_enable(pipe);
598 usbhsf_rx_irq_ctrl(pipe, 1); 601 usbhsf_rx_irq_ctrl(pipe, 1);
599 602
@@ -795,6 +798,7 @@ static void xfer_work(struct work_struct *work)
795 dev_dbg(dev, " %s %d (%d/ %d)\n", 798 dev_dbg(dev, " %s %d (%d/ %d)\n",
796 fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero); 799 fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero);
797 800
801 usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
798 usbhsf_dma_start(pipe, fifo); 802 usbhsf_dma_start(pipe, fifo);
799 dma_async_issue_pending(chan); 803 dma_async_issue_pending(chan);
800} 804}
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index 122526cfd32b..7926e1c700f1 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -93,6 +93,82 @@ static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
93} 93}
94 94
95/* 95/*
96 * PIPEnTRN/PIPEnTRE functions
97 */
98static void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
99{
100 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
101 struct device *dev = usbhs_priv_to_dev(priv);
102 int num = usbhs_pipe_number(pipe);
103 u16 reg;
104
105 /*
106 * It is impossible to calculate address,
107 * since PIPEnTRN addresses were mapped randomly.
108 */
109#define CASE_PIPExTRN(a) \
110 case 0x ## a: \
111 reg = PIPE ## a ## TRN; \
112 break;
113
114 switch (num) {
115 CASE_PIPExTRN(1);
116 CASE_PIPExTRN(2);
117 CASE_PIPExTRN(3);
118 CASE_PIPExTRN(4);
119 CASE_PIPExTRN(5);
120 CASE_PIPExTRN(B);
121 CASE_PIPExTRN(C);
122 CASE_PIPExTRN(D);
123 CASE_PIPExTRN(E);
124 CASE_PIPExTRN(F);
125 CASE_PIPExTRN(9);
126 CASE_PIPExTRN(A);
127 default:
128 dev_err(dev, "unknown pipe (%d)\n", num);
129 return;
130 }
131 __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val);
132}
133
134static void usbhsp_pipe_tre_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
135{
136 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
137 struct device *dev = usbhs_priv_to_dev(priv);
138 int num = usbhs_pipe_number(pipe);
139 u16 reg;
140
141 /*
142 * It is impossible to calculate address,
143 * since PIPEnTRE addresses were mapped randomly.
144 */
145#define CASE_PIPExTRE(a) \
146 case 0x ## a: \
147 reg = PIPE ## a ## TRE; \
148 break;
149
150 switch (num) {
151 CASE_PIPExTRE(1);
152 CASE_PIPExTRE(2);
153 CASE_PIPExTRE(3);
154 CASE_PIPExTRE(4);
155 CASE_PIPExTRE(5);
156 CASE_PIPExTRE(B);
157 CASE_PIPExTRE(C);
158 CASE_PIPExTRE(D);
159 CASE_PIPExTRE(E);
160 CASE_PIPExTRE(F);
161 CASE_PIPExTRE(9);
162 CASE_PIPExTRE(A);
163 default:
164 dev_err(dev, "unknown pipe (%d)\n", num);
165 return;
166 }
167
168 __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val);
169}
170
171/*
96 * PIPEBUF 172 * PIPEBUF
97 */ 173 */
98static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) 174static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
@@ -264,6 +340,31 @@ int usbhs_pipe_is_stall(struct usbhs_pipe *pipe)
264 return (int)(pid == PID_STALL10 || pid == PID_STALL11); 340 return (int)(pid == PID_STALL10 || pid == PID_STALL11);
265} 341}
266 342
343void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len)
344{
345 if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
346 return;
347
348 /*
349 * clear and disable transfer counter for IN/OUT pipe
350 */
351 usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR);
352
353 /*
354 * Only IN direction bulk pipe can use transfer count.
355 * Without using this function,
356 * received data will break if it was large data size.
357 * see PIPEnTRN/PIPEnTRE for detail
358 */
359 if (usbhs_pipe_is_dir_in(pipe)) {
360 int maxp = usbhs_pipe_get_maxpacket(pipe);
361
362 usbhsp_pipe_trn_set(pipe, 0xffff, DIV_ROUND_UP(len, maxp));
363 usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */
364 }
365}
366
367
267/* 368/*
268 * pipe setup 369 * pipe setup
269 */ 370 */
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index 08786c06dcf1..01b1820eccc5 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -88,6 +88,7 @@ void usbhs_pipe_enable(struct usbhs_pipe *pipe);
88void usbhs_pipe_disable(struct usbhs_pipe *pipe); 88void usbhs_pipe_disable(struct usbhs_pipe *pipe);
89void usbhs_pipe_stall(struct usbhs_pipe *pipe); 89void usbhs_pipe_stall(struct usbhs_pipe *pipe);
90int usbhs_pipe_is_stall(struct usbhs_pipe *pipe); 90int usbhs_pipe_is_stall(struct usbhs_pipe *pipe);
91void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len);
91void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo); 92void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo);
92void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, 93void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
93 u16 epnum, u16 maxp); 94 u16 epnum, u16 maxp);