Commit | Line | Data |
---|---|---|
e8d548d5 KM |
1 | /* |
2 | * Renesas USB driver | |
3 | * | |
4 | * Copyright (C) 2011 Renesas Solutions Corp. | |
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * GNU General Public License for more details. | |
11 | * | |
12 | * You should have received a copy of the GNU General Public License | |
13 | * along with this program; if not, write to the Free Software | |
14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
15 | * | |
16 | */ | |
17 | #include <linux/delay.h> | |
18 | #include <linux/io.h> | |
9c646cfc | 19 | #include <linux/scatterlist.h> |
cc502bb7 PB |
20 | #include "common.h" |
21 | #include "pipe.h" | |
e8d548d5 | 22 | |
d3af90a5 | 23 | #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) |
e73a9891 KM |
24 | #define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo)) |
25 | #define usbhsf_get_d1fifo(p) (&((p)->fifo_info.d1fifo)) | |
5ea43994 | 26 | #define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f) |
d3af90a5 | 27 | |
d77e3f4e KM |
28 | #define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ |
29 | ||
4bd04811 | 30 | /* |
233f519d KM |
31 | * packet initialize |
32 | */ | |
33 | void usbhs_pkt_init(struct usbhs_pkt *pkt) | |
34 | { | |
233f519d KM |
35 | INIT_LIST_HEAD(&pkt->node); |
36 | } | |
37 | ||
38 | /* | |
39 | * packet control function | |
4bd04811 | 40 | */ |
97664a20 | 41 | static int usbhsf_null_handle(struct usbhs_pkt *pkt, int *is_done) |
dad67397 KM |
42 | { |
43 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); | |
44 | struct device *dev = usbhs_priv_to_dev(priv); | |
45 | ||
46 | dev_err(dev, "null handler\n"); | |
47 | ||
48 | return -EINVAL; | |
49 | } | |
50 | ||
51 | static struct usbhs_pkt_handle usbhsf_null_handler = { | |
52 | .prepare = usbhsf_null_handle, | |
53 | .try_run = usbhsf_null_handle, | |
54 | }; | |
55 | ||
659d4954 | 56 | void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, |
b331872b KM |
57 | void (*done)(struct usbhs_priv *priv, |
58 | struct usbhs_pkt *pkt), | |
3edeee38 | 59 | void *buf, int len, int zero, int sequence) |
6acb95d4 | 60 | { |
dad67397 KM |
61 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
62 | struct device *dev = usbhs_priv_to_dev(priv); | |
97664a20 KM |
63 | unsigned long flags; |
64 | ||
b331872b KM |
65 | if (!done) { |
66 | dev_err(dev, "no done function\n"); | |
67 | return; | |
68 | } | |
69 | ||
a2c76b83 KM |
70 | /******************** spin lock ********************/ |
71 | usbhs_lock(priv, flags); | |
72 | ||
0c6ef985 | 73 | if (!pipe->handler) { |
dad67397 | 74 | dev_err(dev, "no handler function\n"); |
0c6ef985 | 75 | pipe->handler = &usbhsf_null_handler; |
dad67397 KM |
76 | } |
77 | ||
d5261286 | 78 | list_move_tail(&pkt->node, &pipe->list); |
6acb95d4 | 79 | |
0c6ef985 KM |
80 | /* |
81 | * each pkt must hold own handler. | |
82 | * because handler might be changed by its situation. | |
83 | * dma handler -> pio handler. | |
84 | */ | |
659d4954 KM |
85 | pkt->pipe = pipe; |
86 | pkt->buf = buf; | |
0c6ef985 | 87 | pkt->handler = pipe->handler; |
659d4954 KM |
88 | pkt->length = len; |
89 | pkt->zero = zero; | |
90 | pkt->actual = 0; | |
b331872b | 91 | pkt->done = done; |
3edeee38 | 92 | pkt->sequence = sequence; |
97664a20 KM |
93 | |
94 | usbhs_unlock(priv, flags); | |
95 | /******************** spin unlock ******************/ | |
6acb95d4 KM |
96 | } |
97 | ||
97664a20 | 98 | static void __usbhsf_pkt_del(struct usbhs_pkt *pkt) |
6acb95d4 KM |
99 | { |
100 | list_del_init(&pkt->node); | |
101 | } | |
102 | ||
97664a20 | 103 | static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) |
6acb95d4 KM |
104 | { |
105 | if (list_empty(&pipe->list)) | |
106 | return NULL; | |
107 | ||
d5261286 | 108 | return list_first_entry(&pipe->list, struct usbhs_pkt, node); |
6acb95d4 KM |
109 | } |
110 | ||
97664a20 KM |
111 | struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt) |
112 | { | |
113 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
114 | unsigned long flags; | |
115 | ||
116 | /******************** spin lock ********************/ | |
117 | usbhs_lock(priv, flags); | |
118 | ||
119 | if (!pkt) | |
120 | pkt = __usbhsf_pkt_get(pipe); | |
121 | ||
122 | if (pkt) | |
123 | __usbhsf_pkt_del(pkt); | |
124 | ||
125 | usbhs_unlock(priv, flags); | |
126 | /******************** spin unlock ******************/ | |
127 | ||
128 | return pkt; | |
129 | } | |
130 | ||
51b8a021 KM |
131 | enum { |
132 | USBHSF_PKT_PREPARE, | |
133 | USBHSF_PKT_TRY_RUN, | |
134 | USBHSF_PKT_DMA_DONE, | |
135 | }; | |
136 | ||
137 | static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type) | |
97664a20 KM |
138 | { |
139 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
97664a20 KM |
140 | struct usbhs_pkt *pkt; |
141 | struct device *dev = usbhs_priv_to_dev(priv); | |
142 | int (*func)(struct usbhs_pkt *pkt, int *is_done); | |
143 | unsigned long flags; | |
144 | int ret = 0; | |
145 | int is_done = 0; | |
146 | ||
147 | /******************** spin lock ********************/ | |
148 | usbhs_lock(priv, flags); | |
149 | ||
150 | pkt = __usbhsf_pkt_get(pipe); | |
151 | if (!pkt) | |
152 | goto __usbhs_pkt_handler_end; | |
153 | ||
154 | switch (type) { | |
155 | case USBHSF_PKT_PREPARE: | |
156 | func = pkt->handler->prepare; | |
157 | break; | |
158 | case USBHSF_PKT_TRY_RUN: | |
159 | func = pkt->handler->try_run; | |
160 | break; | |
e73a9891 KM |
161 | case USBHSF_PKT_DMA_DONE: |
162 | func = pkt->handler->dma_done; | |
163 | break; | |
97664a20 | 164 | default: |
984e833c | 165 | dev_err(dev, "unknown pkt handler\n"); |
97664a20 KM |
166 | goto __usbhs_pkt_handler_end; |
167 | } | |
168 | ||
169 | ret = func(pkt, &is_done); | |
170 | ||
171 | if (is_done) | |
172 | __usbhsf_pkt_del(pkt); | |
173 | ||
174 | __usbhs_pkt_handler_end: | |
175 | usbhs_unlock(priv, flags); | |
176 | /******************** spin unlock ******************/ | |
177 | ||
0432eed0 | 178 | if (is_done) { |
b331872b | 179 | pkt->done(priv, pkt); |
0432eed0 KM |
180 | usbhs_pkt_start(pipe); |
181 | } | |
97664a20 KM |
182 | |
183 | return ret; | |
184 | } | |
185 | ||
51b8a021 KM |
186 | void usbhs_pkt_start(struct usbhs_pipe *pipe) |
187 | { | |
188 | usbhsf_pkt_handler(pipe, USBHSF_PKT_PREPARE); | |
189 | } | |
190 | ||
659d4954 KM |
191 | /* |
192 | * irq enable/disable function | |
193 | */ | |
3192fcb2 KM |
194 | #define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_bempsts, e) |
195 | #define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_brdysts, e) | |
659d4954 KM |
196 | #define usbhsf_irq_callback_ctrl(pipe, status, enable) \ |
197 | ({ \ | |
198 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); \ | |
199 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); \ | |
200 | u16 status = (1 << usbhs_pipe_number(pipe)); \ | |
201 | if (!mod) \ | |
202 | return; \ | |
203 | if (enable) \ | |
3192fcb2 | 204 | mod->status |= status; \ |
659d4954 | 205 | else \ |
3192fcb2 | 206 | mod->status &= ~status; \ |
659d4954 KM |
207 | usbhs_irq_callback_update(priv, mod); \ |
208 | }) | |
209 | ||
210 | static void usbhsf_tx_irq_ctrl(struct usbhs_pipe *pipe, int enable) | |
211 | { | |
212 | /* | |
213 | * And DCP pipe can NOT use "ready interrupt" for "send" | |
214 | * it should use "empty" interrupt. | |
215 | * see | |
216 | * "Operation" - "Interrupt Function" - "BRDY Interrupt" | |
217 | * | |
218 | * on the other hand, normal pipe can use "ready interrupt" for "send" | |
219 | * even though it is single/double buffer | |
220 | */ | |
221 | if (usbhs_pipe_is_dcp(pipe)) | |
222 | usbhsf_irq_empty_ctrl(pipe, enable); | |
223 | else | |
224 | usbhsf_irq_ready_ctrl(pipe, enable); | |
225 | } | |
226 | ||
227 | static void usbhsf_rx_irq_ctrl(struct usbhs_pipe *pipe, int enable) | |
228 | { | |
229 | usbhsf_irq_ready_ctrl(pipe, enable); | |
230 | } | |
231 | ||
e8d548d5 KM |
232 | /* |
233 | * FIFO ctrl | |
234 | */ | |
d3af90a5 KM |
235 | static void usbhsf_send_terminator(struct usbhs_pipe *pipe, |
236 | struct usbhs_fifo *fifo) | |
e8d548d5 KM |
237 | { |
238 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
239 | ||
d3af90a5 | 240 | usbhs_bset(priv, fifo->ctr, BVAL, BVAL); |
e8d548d5 KM |
241 | } |
242 | ||
d3af90a5 KM |
243 | static int usbhsf_fifo_barrier(struct usbhs_priv *priv, |
244 | struct usbhs_fifo *fifo) | |
e8d548d5 KM |
245 | { |
246 | int timeout = 1024; | |
247 | ||
248 | do { | |
249 | /* The FIFO port is accessible */ | |
d3af90a5 | 250 | if (usbhs_read(priv, fifo->ctr) & FRDY) |
e8d548d5 KM |
251 | return 0; |
252 | ||
253 | udelay(10); | |
254 | } while (timeout--); | |
255 | ||
256 | return -EBUSY; | |
257 | } | |
258 | ||
d3af90a5 KM |
259 | static void usbhsf_fifo_clear(struct usbhs_pipe *pipe, |
260 | struct usbhs_fifo *fifo) | |
e8d548d5 KM |
261 | { |
262 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
263 | ||
264 | if (!usbhs_pipe_is_dcp(pipe)) | |
d3af90a5 | 265 | usbhsf_fifo_barrier(priv, fifo); |
e8d548d5 | 266 | |
d3af90a5 | 267 | usbhs_write(priv, fifo->ctr, BCLR); |
e8d548d5 KM |
268 | } |
269 | ||
d3af90a5 KM |
270 | static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv, |
271 | struct usbhs_fifo *fifo) | |
e8d548d5 | 272 | { |
d3af90a5 | 273 | return usbhs_read(priv, fifo->ctr) & DTLN_MASK; |
e8d548d5 KM |
274 | } |
275 | ||
d77e3f4e KM |
276 | static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe, |
277 | struct usbhs_fifo *fifo) | |
278 | { | |
279 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
280 | ||
281 | usbhs_pipe_select_fifo(pipe, NULL); | |
282 | usbhs_write(priv, fifo->sel, 0); | |
283 | } | |
284 | ||
d3af90a5 KM |
285 | static int usbhsf_fifo_select(struct usbhs_pipe *pipe, |
286 | struct usbhs_fifo *fifo, | |
287 | int write) | |
e8d548d5 KM |
288 | { |
289 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
290 | struct device *dev = usbhs_priv_to_dev(priv); | |
291 | int timeout = 1024; | |
292 | u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */ | |
293 | u16 base = usbhs_pipe_number(pipe); /* CURPIPE */ | |
294 | ||
d77e3f4e KM |
295 | if (usbhs_pipe_is_busy(pipe) || |
296 | usbhsf_fifo_is_busy(fifo)) | |
297 | return -EBUSY; | |
298 | ||
92352071 | 299 | if (usbhs_pipe_is_dcp(pipe)) { |
e8d548d5 KM |
300 | base |= (1 == write) << 5; /* ISEL */ |
301 | ||
92352071 KM |
302 | if (usbhs_mod_is_host(priv)) |
303 | usbhs_dcp_dir_for_host(pipe, write); | |
304 | } | |
305 | ||
e8d548d5 | 306 | /* "base" will be used below */ |
5ea43994 SY |
307 | if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo)) |
308 | usbhs_write(priv, fifo->sel, base); | |
309 | else | |
310 | usbhs_write(priv, fifo->sel, base | MBW_32); | |
e8d548d5 KM |
311 | |
312 | /* check ISEL and CURPIPE value */ | |
313 | while (timeout--) { | |
d77e3f4e KM |
314 | if (base == (mask & usbhs_read(priv, fifo->sel))) { |
315 | usbhs_pipe_select_fifo(pipe, fifo); | |
e8d548d5 | 316 | return 0; |
d77e3f4e | 317 | } |
e8d548d5 KM |
318 | udelay(10); |
319 | } | |
320 | ||
321 | dev_err(dev, "fifo select error\n"); | |
322 | ||
323 | return -EIO; | |
324 | } | |
325 | ||
9e74d601 KM |
326 | /* |
327 | * DCP status stage | |
328 | */ | |
329 | static int usbhs_dcp_dir_switch_to_write(struct usbhs_pkt *pkt, int *is_done) | |
330 | { | |
331 | struct usbhs_pipe *pipe = pkt->pipe; | |
332 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
333 | struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ | |
334 | struct device *dev = usbhs_priv_to_dev(priv); | |
335 | int ret; | |
336 | ||
337 | usbhs_pipe_disable(pipe); | |
338 | ||
339 | ret = usbhsf_fifo_select(pipe, fifo, 1); | |
340 | if (ret < 0) { | |
341 | dev_err(dev, "%s() faile\n", __func__); | |
342 | return ret; | |
343 | } | |
344 | ||
345 | usbhs_pipe_sequence_data1(pipe); /* DATA1 */ | |
346 | ||
347 | usbhsf_fifo_clear(pipe, fifo); | |
348 | usbhsf_send_terminator(pipe, fifo); | |
349 | ||
350 | usbhsf_fifo_unselect(pipe, fifo); | |
351 | ||
352 | usbhsf_tx_irq_ctrl(pipe, 1); | |
353 | usbhs_pipe_enable(pipe); | |
354 | ||
355 | return ret; | |
356 | } | |
357 | ||
358 | static int usbhs_dcp_dir_switch_to_read(struct usbhs_pkt *pkt, int *is_done) | |
359 | { | |
360 | struct usbhs_pipe *pipe = pkt->pipe; | |
361 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
362 | struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ | |
363 | struct device *dev = usbhs_priv_to_dev(priv); | |
364 | int ret; | |
365 | ||
366 | usbhs_pipe_disable(pipe); | |
367 | ||
368 | ret = usbhsf_fifo_select(pipe, fifo, 0); | |
369 | if (ret < 0) { | |
370 | dev_err(dev, "%s() fail\n", __func__); | |
371 | return ret; | |
372 | } | |
373 | ||
374 | usbhs_pipe_sequence_data1(pipe); /* DATA1 */ | |
375 | usbhsf_fifo_clear(pipe, fifo); | |
376 | ||
377 | usbhsf_fifo_unselect(pipe, fifo); | |
378 | ||
379 | usbhsf_rx_irq_ctrl(pipe, 1); | |
380 | usbhs_pipe_enable(pipe); | |
381 | ||
382 | return ret; | |
383 | ||
384 | } | |
385 | ||
386 | static int usbhs_dcp_dir_switch_done(struct usbhs_pkt *pkt, int *is_done) | |
387 | { | |
388 | struct usbhs_pipe *pipe = pkt->pipe; | |
389 | ||
390 | if (pkt->handler == &usbhs_dcp_status_stage_in_handler) | |
391 | usbhsf_tx_irq_ctrl(pipe, 0); | |
392 | else | |
393 | usbhsf_rx_irq_ctrl(pipe, 0); | |
394 | ||
395 | pkt->actual = pkt->length; | |
396 | *is_done = 1; | |
397 | ||
398 | return 0; | |
399 | } | |
400 | ||
401 | struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler = { | |
402 | .prepare = usbhs_dcp_dir_switch_to_write, | |
403 | .try_run = usbhs_dcp_dir_switch_done, | |
404 | }; | |
405 | ||
406 | struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler = { | |
407 | .prepare = usbhs_dcp_dir_switch_to_read, | |
408 | .try_run = usbhs_dcp_dir_switch_done, | |
409 | }; | |
410 | ||
411 | /* | |
412 | * DCP data stage (push) | |
413 | */ | |
414 | static int usbhsf_dcp_data_stage_try_push(struct usbhs_pkt *pkt, int *is_done) | |
415 | { | |
416 | struct usbhs_pipe *pipe = pkt->pipe; | |
417 | ||
418 | usbhs_pipe_sequence_data1(pipe); /* DATA1 */ | |
419 | ||
420 | /* | |
421 | * change handler to PIO push | |
422 | */ | |
423 | pkt->handler = &usbhs_fifo_pio_push_handler; | |
424 | ||
425 | return pkt->handler->prepare(pkt, is_done); | |
426 | } | |
427 | ||
428 | struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler = { | |
429 | .prepare = usbhsf_dcp_data_stage_try_push, | |
430 | }; | |
431 | ||
432 | /* | |
433 | * DCP data stage (pop) | |
434 | */ | |
435 | static int usbhsf_dcp_data_stage_prepare_pop(struct usbhs_pkt *pkt, | |
436 | int *is_done) | |
437 | { | |
438 | struct usbhs_pipe *pipe = pkt->pipe; | |
439 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
440 | struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); | |
441 | ||
442 | if (usbhs_pipe_is_busy(pipe)) | |
443 | return 0; | |
444 | ||
445 | /* | |
446 | * prepare pop for DCP should | |
447 | * - change DCP direction, | |
448 | * - clear fifo | |
449 | * - DATA1 | |
450 | */ | |
451 | usbhs_pipe_disable(pipe); | |
452 | ||
453 | usbhs_pipe_sequence_data1(pipe); /* DATA1 */ | |
454 | ||
455 | usbhsf_fifo_select(pipe, fifo, 0); | |
456 | usbhsf_fifo_clear(pipe, fifo); | |
457 | usbhsf_fifo_unselect(pipe, fifo); | |
458 | ||
459 | /* | |
460 | * change handler to PIO pop | |
461 | */ | |
462 | pkt->handler = &usbhs_fifo_pio_pop_handler; | |
463 | ||
464 | return pkt->handler->prepare(pkt, is_done); | |
465 | } | |
466 | ||
467 | struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler = { | |
468 | .prepare = usbhsf_dcp_data_stage_prepare_pop, | |
469 | }; | |
470 | ||
e8d548d5 | 471 | /* |
233f519d | 472 | * PIO push handler |
e8d548d5 | 473 | */ |
0cb7e61d | 474 | static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) |
e8d548d5 | 475 | { |
4bd04811 | 476 | struct usbhs_pipe *pipe = pkt->pipe; |
e8d548d5 | 477 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
659d4954 | 478 | struct device *dev = usbhs_priv_to_dev(priv); |
d3af90a5 KM |
479 | struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ |
480 | void __iomem *addr = priv->base + fifo->port; | |
659d4954 | 481 | u8 *buf; |
e8d548d5 KM |
482 | int maxp = usbhs_pipe_get_maxpacket(pipe); |
483 | int total_len; | |
4bd04811 | 484 | int i, ret, len; |
97664a20 | 485 | int is_short; |
e8d548d5 | 486 | |
3edeee38 KM |
487 | usbhs_pipe_data_sequence(pipe, pkt->sequence); |
488 | pkt->sequence = -1; /* -1 sequence will be ignored */ | |
489 | ||
1c90ee0b KM |
490 | usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); |
491 | ||
d3af90a5 | 492 | ret = usbhsf_fifo_select(pipe, fifo, 1); |
e8d548d5 | 493 | if (ret < 0) |
d77e3f4e | 494 | return 0; |
e8d548d5 | 495 | |
dad67397 | 496 | ret = usbhs_pipe_is_accessible(pipe); |
4ef85e0f KM |
497 | if (ret < 0) { |
498 | /* inaccessible pipe is not an error */ | |
499 | ret = 0; | |
659d4954 | 500 | goto usbhs_fifo_write_busy; |
4ef85e0f | 501 | } |
e8d548d5 | 502 | |
d3af90a5 | 503 | ret = usbhsf_fifo_barrier(priv, fifo); |
e8d548d5 | 504 | if (ret < 0) |
659d4954 | 505 | goto usbhs_fifo_write_busy; |
e8d548d5 | 506 | |
659d4954 KM |
507 | buf = pkt->buf + pkt->actual; |
508 | len = pkt->length - pkt->actual; | |
509 | len = min(len, maxp); | |
510 | total_len = len; | |
511 | is_short = total_len < maxp; | |
e8d548d5 KM |
512 | |
513 | /* | |
514 | * FIXME | |
515 | * | |
516 | * 32-bit access only | |
517 | */ | |
659d4954 | 518 | if (len >= 4 && !((unsigned long)buf & 0x03)) { |
e8d548d5 KM |
519 | iowrite32_rep(addr, buf, len / 4); |
520 | len %= 4; | |
521 | buf += total_len - len; | |
522 | } | |
523 | ||
524 | /* the rest operation */ | |
525 | for (i = 0; i < len; i++) | |
526 | iowrite8(buf[i], addr + (0x03 - (i & 0x03))); | |
527 | ||
659d4954 KM |
528 | /* |
529 | * variable update | |
530 | */ | |
531 | pkt->actual += total_len; | |
532 | ||
533 | if (pkt->actual < pkt->length) | |
97664a20 | 534 | *is_done = 0; /* there are remainder data */ |
659d4954 | 535 | else if (is_short) |
97664a20 | 536 | *is_done = 1; /* short packet */ |
659d4954 | 537 | else |
97664a20 | 538 | *is_done = !pkt->zero; /* send zero packet ? */ |
659d4954 KM |
539 | |
540 | /* | |
541 | * pipe/irq handling | |
542 | */ | |
543 | if (is_short) | |
d3af90a5 | 544 | usbhsf_send_terminator(pipe, fifo); |
e8d548d5 | 545 | |
97664a20 | 546 | usbhsf_tx_irq_ctrl(pipe, !*is_done); |
4bd04811 KM |
547 | usbhs_pipe_enable(pipe); |
548 | ||
659d4954 KM |
549 | dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n", |
550 | usbhs_pipe_number(pipe), | |
97664a20 | 551 | pkt->length, pkt->actual, *is_done, pkt->zero); |
659d4954 KM |
552 | |
553 | /* | |
554 | * Transmission end | |
555 | */ | |
97664a20 | 556 | if (*is_done) { |
659d4954 KM |
557 | if (usbhs_pipe_is_dcp(pipe)) |
558 | usbhs_dcp_control_transfer_done(pipe); | |
4bd04811 KM |
559 | } |
560 | ||
d77e3f4e KM |
561 | usbhsf_fifo_unselect(pipe, fifo); |
562 | ||
4bd04811 | 563 | return 0; |
659d4954 KM |
564 | |
565 | usbhs_fifo_write_busy: | |
d77e3f4e KM |
566 | usbhsf_fifo_unselect(pipe, fifo); |
567 | ||
659d4954 KM |
568 | /* |
569 | * pipe is busy. | |
570 | * retry in interrupt | |
571 | */ | |
572 | usbhsf_tx_irq_ctrl(pipe, 1); | |
573 | ||
574 | return ret; | |
e8d548d5 KM |
575 | } |
576 | ||
0cb7e61d KM |
577 | struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = { |
578 | .prepare = usbhsf_pio_try_push, | |
579 | .try_run = usbhsf_pio_try_push, | |
dad67397 KM |
580 | }; |
581 | ||
233f519d KM |
582 | /* |
583 | * PIO pop handler | |
584 | */ | |
97664a20 | 585 | static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) |
e8d548d5 | 586 | { |
dad67397 | 587 | struct usbhs_pipe *pipe = pkt->pipe; |
d77e3f4e KM |
588 | |
589 | if (usbhs_pipe_is_busy(pipe)) | |
590 | return 0; | |
e8d548d5 KM |
591 | |
592 | /* | |
d77e3f4e | 593 | * pipe enable to prepare packet receive |
e8d548d5 | 594 | */ |
3edeee38 KM |
595 | usbhs_pipe_data_sequence(pipe, pkt->sequence); |
596 | pkt->sequence = -1; /* -1 sequence will be ignored */ | |
e8d548d5 | 597 | |
1c90ee0b | 598 | usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); |
e8d548d5 | 599 | usbhs_pipe_enable(pipe); |
659d4954 | 600 | usbhsf_rx_irq_ctrl(pipe, 1); |
e8d548d5 | 601 | |
d3af90a5 | 602 | return 0; |
e8d548d5 KM |
603 | } |
604 | ||
0cb7e61d | 605 | static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done) |
e8d548d5 | 606 | { |
4bd04811 | 607 | struct usbhs_pipe *pipe = pkt->pipe; |
e8d548d5 | 608 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
659d4954 | 609 | struct device *dev = usbhs_priv_to_dev(priv); |
d3af90a5 KM |
610 | struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ |
611 | void __iomem *addr = priv->base + fifo->port; | |
659d4954 KM |
612 | u8 *buf; |
613 | u32 data = 0; | |
614 | int maxp = usbhs_pipe_get_maxpacket(pipe); | |
4bd04811 | 615 | int rcv_len, len; |
e8d548d5 | 616 | int i, ret; |
4bd04811 | 617 | int total_len = 0; |
e8d548d5 | 618 | |
d3af90a5 | 619 | ret = usbhsf_fifo_select(pipe, fifo, 0); |
e8d548d5 | 620 | if (ret < 0) |
d77e3f4e | 621 | return 0; |
e8d548d5 | 622 | |
d3af90a5 | 623 | ret = usbhsf_fifo_barrier(priv, fifo); |
e8d548d5 | 624 | if (ret < 0) |
d77e3f4e | 625 | goto usbhs_fifo_read_busy; |
e8d548d5 | 626 | |
d3af90a5 | 627 | rcv_len = usbhsf_fifo_rcv_len(priv, fifo); |
e8d548d5 | 628 | |
659d4954 KM |
629 | buf = pkt->buf + pkt->actual; |
630 | len = pkt->length - pkt->actual; | |
631 | len = min(len, rcv_len); | |
632 | total_len = len; | |
633 | ||
6ff5d09b KM |
634 | /* |
635 | * update actual length first here to decide disable pipe. | |
636 | * if this pipe keeps BUF status and all data were popped, | |
637 | * then, next interrupt/token will be issued again | |
638 | */ | |
639 | pkt->actual += total_len; | |
640 | ||
641 | if ((pkt->actual == pkt->length) || /* receive all data */ | |
642 | (total_len < maxp)) { /* short packet */ | |
643 | *is_done = 1; | |
644 | usbhsf_rx_irq_ctrl(pipe, 0); | |
645 | usbhs_pipe_disable(pipe); /* disable pipe first */ | |
646 | } | |
647 | ||
e8d548d5 KM |
648 | /* |
649 | * Buffer clear if Zero-Length packet | |
650 | * | |
651 | * see | |
652 | * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function" | |
653 | */ | |
654 | if (0 == rcv_len) { | |
3edeee38 | 655 | pkt->zero = 1; |
d3af90a5 | 656 | usbhsf_fifo_clear(pipe, fifo); |
4bd04811 | 657 | goto usbhs_fifo_read_end; |
e8d548d5 KM |
658 | } |
659 | ||
e8d548d5 KM |
660 | /* |
661 | * FIXME | |
662 | * | |
663 | * 32-bit access only | |
664 | */ | |
659d4954 | 665 | if (len >= 4 && !((unsigned long)buf & 0x03)) { |
e8d548d5 KM |
666 | ioread32_rep(addr, buf, len / 4); |
667 | len %= 4; | |
659d4954 | 668 | buf += total_len - len; |
e8d548d5 KM |
669 | } |
670 | ||
671 | /* the rest operation */ | |
672 | for (i = 0; i < len; i++) { | |
673 | if (!(i & 0x03)) | |
674 | data = ioread32(addr); | |
675 | ||
676 | buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; | |
677 | } | |
678 | ||
4bd04811 | 679 | usbhs_fifo_read_end: |
97664a20 KM |
680 | dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d)\n", |
681 | usbhs_pipe_number(pipe), | |
682 | pkt->length, pkt->actual, *is_done, pkt->zero); | |
683 | ||
d77e3f4e KM |
684 | usbhs_fifo_read_busy: |
685 | usbhsf_fifo_unselect(pipe, fifo); | |
686 | ||
687 | return ret; | |
e8d548d5 | 688 | } |
dad67397 | 689 | |
0cb7e61d | 690 | struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler = { |
dad67397 | 691 | .prepare = usbhsf_prepare_pop, |
0cb7e61d | 692 | .try_run = usbhsf_pio_try_pop, |
dad67397 KM |
693 | }; |
694 | ||
695 | /* | |
233f519d | 696 | * DCP ctrol statge handler |
dad67397 | 697 | */ |
97664a20 | 698 | static int usbhsf_ctrl_stage_end(struct usbhs_pkt *pkt, int *is_done) |
dad67397 | 699 | { |
97664a20 | 700 | usbhs_dcp_control_transfer_done(pkt->pipe); |
dad67397 | 701 | |
97664a20 | 702 | *is_done = 1; |
dad67397 KM |
703 | |
704 | return 0; | |
705 | } | |
706 | ||
707 | struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler = { | |
708 | .prepare = usbhsf_ctrl_stage_end, | |
709 | .try_run = usbhsf_ctrl_stage_end, | |
710 | }; | |
711 | ||
e73a9891 KM |
712 | /* |
713 | * DMA fifo functions | |
714 | */ | |
715 | static struct dma_chan *usbhsf_dma_chan_get(struct usbhs_fifo *fifo, | |
716 | struct usbhs_pkt *pkt) | |
717 | { | |
718 | if (&usbhs_fifo_dma_push_handler == pkt->handler) | |
719 | return fifo->tx_chan; | |
720 | ||
721 | if (&usbhs_fifo_dma_pop_handler == pkt->handler) | |
722 | return fifo->rx_chan; | |
723 | ||
724 | return NULL; | |
725 | } | |
726 | ||
727 | static struct usbhs_fifo *usbhsf_get_dma_fifo(struct usbhs_priv *priv, | |
728 | struct usbhs_pkt *pkt) | |
729 | { | |
730 | struct usbhs_fifo *fifo; | |
731 | ||
732 | /* DMA :: D0FIFO */ | |
733 | fifo = usbhsf_get_d0fifo(priv); | |
734 | if (usbhsf_dma_chan_get(fifo, pkt) && | |
735 | !usbhsf_fifo_is_busy(fifo)) | |
736 | return fifo; | |
737 | ||
738 | /* DMA :: D1FIFO */ | |
739 | fifo = usbhsf_get_d1fifo(priv); | |
740 | if (usbhsf_dma_chan_get(fifo, pkt) && | |
741 | !usbhsf_fifo_is_busy(fifo)) | |
742 | return fifo; | |
743 | ||
744 | return NULL; | |
745 | } | |
746 | ||
747 | #define usbhsf_dma_start(p, f) __usbhsf_dma_ctrl(p, f, DREQE) | |
748 | #define usbhsf_dma_stop(p, f) __usbhsf_dma_ctrl(p, f, 0) | |
749 | static void __usbhsf_dma_ctrl(struct usbhs_pipe *pipe, | |
750 | struct usbhs_fifo *fifo, | |
751 | u16 dreqe) | |
752 | { | |
753 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
754 | ||
755 | usbhs_bset(priv, fifo->sel, DREQE, dreqe); | |
756 | } | |
757 | ||
758 | #define usbhsf_dma_map(p) __usbhsf_dma_map_ctrl(p, 1) | |
759 | #define usbhsf_dma_unmap(p) __usbhsf_dma_map_ctrl(p, 0) | |
760 | static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) | |
761 | { | |
762 | struct usbhs_pipe *pipe = pkt->pipe; | |
763 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
764 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); | |
765 | ||
766 | return info->dma_map_ctrl(pkt, map); | |
767 | } | |
768 | ||
769 | static void usbhsf_dma_complete(void *arg); | |
6e4b74e4 | 770 | static void xfer_work(struct work_struct *work) |
e73a9891 | 771 | { |
6e4b74e4 | 772 | struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work); |
e73a9891 KM |
773 | struct usbhs_pipe *pipe = pkt->pipe; |
774 | struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); | |
775 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
e73a9891 KM |
776 | struct dma_async_tx_descriptor *desc; |
777 | struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); | |
778 | struct device *dev = usbhs_priv_to_dev(priv); | |
55ba4e5e | 779 | enum dma_transfer_direction dir; |
e73a9891 | 780 | |
55ba4e5e | 781 | dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; |
e73a9891 | 782 | |
2f0de9d8 KM |
783 | desc = dmaengine_prep_slave_single(chan, pkt->dma + pkt->actual, |
784 | pkt->trans, dir, | |
16052827 | 785 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
e73a9891 KM |
786 | if (!desc) |
787 | return; | |
788 | ||
789 | desc->callback = usbhsf_dma_complete; | |
790 | desc->callback_param = pipe; | |
791 | ||
2f0de9d8 | 792 | if (dmaengine_submit(desc) < 0) { |
e73a9891 KM |
793 | dev_err(dev, "Failed to submit dma descriptor\n"); |
794 | return; | |
795 | } | |
796 | ||
797 | dev_dbg(dev, " %s %d (%d/ %d)\n", | |
798 | fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero); | |
799 | ||
1c90ee0b | 800 | usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans); |
1cb60156 | 801 | usbhs_pipe_enable(pipe); |
e73a9891 KM |
802 | usbhsf_dma_start(pipe, fifo); |
803 | dma_async_issue_pending(chan); | |
804 | } | |
805 | ||
233f519d KM |
806 | /* |
807 | * DMA push handler | |
808 | */ | |
e73a9891 KM |
809 | static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) |
810 | { | |
811 | struct usbhs_pipe *pipe = pkt->pipe; | |
812 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
813 | struct usbhs_fifo *fifo; | |
814 | int len = pkt->length - pkt->actual; | |
815 | int ret; | |
816 | ||
817 | if (usbhs_pipe_is_busy(pipe)) | |
818 | return 0; | |
819 | ||
820 | /* use PIO if packet is less than pio_dma_border or pipe is DCP */ | |
821 | if ((len < usbhs_get_dparam(priv, pio_dma_border)) || | |
822 | usbhs_pipe_is_dcp(pipe)) | |
823 | goto usbhsf_pio_prepare_push; | |
824 | ||
77975eec | 825 | if (len & 0x7) /* 8byte alignment */ |
e73a9891 KM |
826 | goto usbhsf_pio_prepare_push; |
827 | ||
c9ae0c91 | 828 | if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ |
9a12d097 KM |
829 | goto usbhsf_pio_prepare_push; |
830 | ||
e73a9891 KM |
831 | /* get enable DMA fifo */ |
832 | fifo = usbhsf_get_dma_fifo(priv, pkt); | |
833 | if (!fifo) | |
834 | goto usbhsf_pio_prepare_push; | |
835 | ||
836 | if (usbhsf_dma_map(pkt) < 0) | |
837 | goto usbhsf_pio_prepare_push; | |
838 | ||
839 | ret = usbhsf_fifo_select(pipe, fifo, 0); | |
840 | if (ret < 0) | |
841 | goto usbhsf_pio_prepare_push_unmap; | |
842 | ||
843 | pkt->trans = len; | |
844 | ||
6e4b74e4 GL |
845 | INIT_WORK(&pkt->work, xfer_work); |
846 | schedule_work(&pkt->work); | |
e73a9891 KM |
847 | |
848 | return 0; | |
849 | ||
850 | usbhsf_pio_prepare_push_unmap: | |
851 | usbhsf_dma_unmap(pkt); | |
852 | usbhsf_pio_prepare_push: | |
853 | /* | |
854 | * change handler to PIO | |
855 | */ | |
856 | pkt->handler = &usbhs_fifo_pio_push_handler; | |
857 | ||
858 | return pkt->handler->prepare(pkt, is_done); | |
859 | } | |
860 | ||
861 | static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done) | |
862 | { | |
863 | struct usbhs_pipe *pipe = pkt->pipe; | |
864 | ||
865 | pkt->actual = pkt->trans; | |
866 | ||
867 | *is_done = !pkt->zero; /* send zero packet ? */ | |
868 | ||
869 | usbhsf_dma_stop(pipe, pipe->fifo); | |
870 | usbhsf_dma_unmap(pkt); | |
871 | usbhsf_fifo_unselect(pipe, pipe->fifo); | |
872 | ||
873 | return 0; | |
874 | } | |
875 | ||
876 | struct usbhs_pkt_handle usbhs_fifo_dma_push_handler = { | |
877 | .prepare = usbhsf_dma_prepare_push, | |
878 | .dma_done = usbhsf_dma_push_done, | |
879 | }; | |
880 | ||
233f519d KM |
881 | /* |
882 | * DMA pop handler | |
883 | */ | |
e73a9891 KM |
884 | static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) |
885 | { | |
886 | struct usbhs_pipe *pipe = pkt->pipe; | |
887 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
888 | struct usbhs_fifo *fifo; | |
889 | int len, ret; | |
890 | ||
891 | if (usbhs_pipe_is_busy(pipe)) | |
892 | return 0; | |
893 | ||
894 | if (usbhs_pipe_is_dcp(pipe)) | |
895 | goto usbhsf_pio_prepare_pop; | |
896 | ||
897 | /* get enable DMA fifo */ | |
898 | fifo = usbhsf_get_dma_fifo(priv, pkt); | |
899 | if (!fifo) | |
900 | goto usbhsf_pio_prepare_pop; | |
901 | ||
c9ae0c91 | 902 | if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ |
9a12d097 KM |
903 | goto usbhsf_pio_prepare_pop; |
904 | ||
e73a9891 KM |
905 | ret = usbhsf_fifo_select(pipe, fifo, 0); |
906 | if (ret < 0) | |
907 | goto usbhsf_pio_prepare_pop; | |
908 | ||
909 | /* use PIO if packet is less than pio_dma_border */ | |
910 | len = usbhsf_fifo_rcv_len(priv, fifo); | |
911 | len = min(pkt->length - pkt->actual, len); | |
77975eec | 912 | if (len & 0x7) /* 8byte alignment */ |
e73a9891 KM |
913 | goto usbhsf_pio_prepare_pop_unselect; |
914 | ||
915 | if (len < usbhs_get_dparam(priv, pio_dma_border)) | |
916 | goto usbhsf_pio_prepare_pop_unselect; | |
917 | ||
918 | ret = usbhsf_fifo_barrier(priv, fifo); | |
919 | if (ret < 0) | |
920 | goto usbhsf_pio_prepare_pop_unselect; | |
921 | ||
922 | if (usbhsf_dma_map(pkt) < 0) | |
923 | goto usbhsf_pio_prepare_pop_unselect; | |
924 | ||
925 | /* DMA */ | |
926 | ||
927 | /* | |
928 | * usbhs_fifo_dma_pop_handler :: prepare | |
929 | * enabled irq to come here. | |
930 | * but it is no longer needed for DMA. disable it. | |
931 | */ | |
932 | usbhsf_rx_irq_ctrl(pipe, 0); | |
933 | ||
934 | pkt->trans = len; | |
935 | ||
6e4b74e4 GL |
936 | INIT_WORK(&pkt->work, xfer_work); |
937 | schedule_work(&pkt->work); | |
e73a9891 KM |
938 | |
939 | return 0; | |
940 | ||
941 | usbhsf_pio_prepare_pop_unselect: | |
942 | usbhsf_fifo_unselect(pipe, fifo); | |
943 | usbhsf_pio_prepare_pop: | |
944 | ||
945 | /* | |
946 | * change handler to PIO | |
947 | */ | |
948 | pkt->handler = &usbhs_fifo_pio_pop_handler; | |
949 | ||
950 | return pkt->handler->try_run(pkt, is_done); | |
951 | } | |
952 | ||
953 | static int usbhsf_dma_pop_done(struct usbhs_pkt *pkt, int *is_done) | |
954 | { | |
955 | struct usbhs_pipe *pipe = pkt->pipe; | |
956 | int maxp = usbhs_pipe_get_maxpacket(pipe); | |
957 | ||
958 | usbhsf_dma_stop(pipe, pipe->fifo); | |
959 | usbhsf_dma_unmap(pkt); | |
960 | usbhsf_fifo_unselect(pipe, pipe->fifo); | |
961 | ||
962 | pkt->actual += pkt->trans; | |
963 | ||
964 | if ((pkt->actual == pkt->length) || /* receive all data */ | |
965 | (pkt->trans < maxp)) { /* short packet */ | |
966 | *is_done = 1; | |
967 | } else { | |
968 | /* re-enable */ | |
969 | usbhsf_prepare_pop(pkt, is_done); | |
970 | } | |
971 | ||
972 | return 0; | |
973 | } | |
974 | ||
975 | struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler = { | |
976 | .prepare = usbhsf_prepare_pop, | |
977 | .try_run = usbhsf_dma_try_pop, | |
978 | .dma_done = usbhsf_dma_pop_done | |
979 | }; | |
980 | ||
981 | /* | |
982 | * DMA setting | |
983 | */ | |
984 | static bool usbhsf_dma_filter(struct dma_chan *chan, void *param) | |
985 | { | |
986 | struct sh_dmae_slave *slave = param; | |
987 | ||
988 | /* | |
989 | * FIXME | |
990 | * | |
991 | * usbhs doesn't recognize id = 0 as valid DMA | |
992 | */ | |
f19b7e0d | 993 | if (0 == slave->shdma_slave.slave_id) |
e73a9891 KM |
994 | return false; |
995 | ||
996 | chan->private = slave; | |
997 | ||
998 | return true; | |
999 | } | |
1000 | ||
1001 | static void usbhsf_dma_quit(struct usbhs_priv *priv, struct usbhs_fifo *fifo) | |
1002 | { | |
1003 | if (fifo->tx_chan) | |
1004 | dma_release_channel(fifo->tx_chan); | |
1005 | if (fifo->rx_chan) | |
1006 | dma_release_channel(fifo->rx_chan); | |
1007 | ||
1008 | fifo->tx_chan = NULL; | |
1009 | fifo->rx_chan = NULL; | |
1010 | } | |
1011 | ||
1012 | static void usbhsf_dma_init(struct usbhs_priv *priv, | |
1013 | struct usbhs_fifo *fifo) | |
1014 | { | |
1015 | struct device *dev = usbhs_priv_to_dev(priv); | |
1016 | dma_cap_mask_t mask; | |
1017 | ||
1018 | dma_cap_zero(mask); | |
1019 | dma_cap_set(DMA_SLAVE, mask); | |
1020 | fifo->tx_chan = dma_request_channel(mask, usbhsf_dma_filter, | |
1021 | &fifo->tx_slave); | |
1022 | ||
1023 | dma_cap_zero(mask); | |
1024 | dma_cap_set(DMA_SLAVE, mask); | |
1025 | fifo->rx_chan = dma_request_channel(mask, usbhsf_dma_filter, | |
1026 | &fifo->rx_slave); | |
1027 | ||
1028 | if (fifo->tx_chan || fifo->rx_chan) | |
4ce68805 | 1029 | dev_dbg(dev, "enable DMAEngine (%s%s%s)\n", |
e73a9891 KM |
1030 | fifo->name, |
1031 | fifo->tx_chan ? "[TX]" : " ", | |
1032 | fifo->rx_chan ? "[RX]" : " "); | |
1033 | } | |
1034 | ||
dad67397 KM |
1035 | /* |
1036 | * irq functions | |
1037 | */ | |
1038 | static int usbhsf_irq_empty(struct usbhs_priv *priv, | |
1039 | struct usbhs_irq_state *irq_state) | |
1040 | { | |
1041 | struct usbhs_pipe *pipe; | |
dad67397 KM |
1042 | struct device *dev = usbhs_priv_to_dev(priv); |
1043 | int i, ret; | |
1044 | ||
1045 | if (!irq_state->bempsts) { | |
1046 | dev_err(dev, "debug %s !!\n", __func__); | |
1047 | return -EIO; | |
1048 | } | |
1049 | ||
1050 | dev_dbg(dev, "irq empty [0x%04x]\n", irq_state->bempsts); | |
1051 | ||
1052 | /* | |
1053 | * search interrupted "pipe" | |
1054 | * not "uep". | |
1055 | */ | |
1056 | usbhs_for_each_pipe_with_dcp(pipe, priv, i) { | |
1057 | if (!(irq_state->bempsts & (1 << i))) | |
1058 | continue; | |
1059 | ||
51b8a021 | 1060 | ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN); |
dad67397 KM |
1061 | if (ret < 0) |
1062 | dev_err(dev, "irq_empty run_error %d : %d\n", i, ret); | |
1063 | } | |
1064 | ||
1065 | return 0; | |
1066 | } | |
1067 | ||
1068 | static int usbhsf_irq_ready(struct usbhs_priv *priv, | |
1069 | struct usbhs_irq_state *irq_state) | |
1070 | { | |
1071 | struct usbhs_pipe *pipe; | |
dad67397 KM |
1072 | struct device *dev = usbhs_priv_to_dev(priv); |
1073 | int i, ret; | |
1074 | ||
1075 | if (!irq_state->brdysts) { | |
1076 | dev_err(dev, "debug %s !!\n", __func__); | |
1077 | return -EIO; | |
1078 | } | |
1079 | ||
1080 | dev_dbg(dev, "irq ready [0x%04x]\n", irq_state->brdysts); | |
1081 | ||
1082 | /* | |
1083 | * search interrupted "pipe" | |
1084 | * not "uep". | |
1085 | */ | |
1086 | usbhs_for_each_pipe_with_dcp(pipe, priv, i) { | |
1087 | if (!(irq_state->brdysts & (1 << i))) | |
1088 | continue; | |
1089 | ||
51b8a021 | 1090 | ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN); |
dad67397 KM |
1091 | if (ret < 0) |
1092 | dev_err(dev, "irq_ready run_error %d : %d\n", i, ret); | |
1093 | } | |
1094 | ||
1095 | return 0; | |
1096 | } | |
1097 | ||
e73a9891 KM |
1098 | static void usbhsf_dma_complete(void *arg) |
1099 | { | |
1100 | struct usbhs_pipe *pipe = arg; | |
1101 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
1102 | struct device *dev = usbhs_priv_to_dev(priv); | |
1103 | int ret; | |
1104 | ||
51b8a021 | 1105 | ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_DMA_DONE); |
e73a9891 KM |
1106 | if (ret < 0) |
1107 | dev_err(dev, "dma_complete run_error %d : %d\n", | |
1108 | usbhs_pipe_number(pipe), ret); | |
1109 | } | |
1110 | ||
dad67397 KM |
1111 | /* |
1112 | * fifo init | |
1113 | */ | |
1114 | void usbhs_fifo_init(struct usbhs_priv *priv) | |
1115 | { | |
1116 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); | |
d77e3f4e | 1117 | struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv); |
e73a9891 KM |
1118 | struct usbhs_fifo *d0fifo = usbhsf_get_d0fifo(priv); |
1119 | struct usbhs_fifo *d1fifo = usbhsf_get_d1fifo(priv); | |
dad67397 KM |
1120 | |
1121 | mod->irq_empty = usbhsf_irq_empty; | |
1122 | mod->irq_ready = usbhsf_irq_ready; | |
1123 | mod->irq_bempsts = 0; | |
1124 | mod->irq_brdysts = 0; | |
d77e3f4e KM |
1125 | |
1126 | cfifo->pipe = NULL; | |
e73a9891 | 1127 | d0fifo->pipe = NULL; |
e73a9891 | 1128 | d1fifo->pipe = NULL; |
dad67397 KM |
1129 | } |
1130 | ||
1131 | void usbhs_fifo_quit(struct usbhs_priv *priv) | |
1132 | { | |
1133 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); | |
1134 | ||
1135 | mod->irq_empty = NULL; | |
1136 | mod->irq_ready = NULL; | |
1137 | mod->irq_bempsts = 0; | |
1138 | mod->irq_brdysts = 0; | |
1139 | } | |
d3af90a5 KM |
1140 | |
1141 | int usbhs_fifo_probe(struct usbhs_priv *priv) | |
1142 | { | |
1143 | struct usbhs_fifo *fifo; | |
1144 | ||
1145 | /* CFIFO */ | |
1146 | fifo = usbhsf_get_cfifo(priv); | |
e73a9891 | 1147 | fifo->name = "CFIFO"; |
d3af90a5 KM |
1148 | fifo->port = CFIFO; |
1149 | fifo->sel = CFIFOSEL; | |
1150 | fifo->ctr = CFIFOCTR; | |
1151 | ||
e73a9891 KM |
1152 | /* D0FIFO */ |
1153 | fifo = usbhsf_get_d0fifo(priv); | |
1154 | fifo->name = "D0FIFO"; | |
1155 | fifo->port = D0FIFO; | |
1156 | fifo->sel = D0FIFOSEL; | |
1157 | fifo->ctr = D0FIFOCTR; | |
f19b7e0d GL |
1158 | fifo->tx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id); |
1159 | fifo->rx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id); | |
1b2e21b0 | 1160 | usbhsf_dma_init(priv, fifo); |
e73a9891 KM |
1161 | |
1162 | /* D1FIFO */ | |
1163 | fifo = usbhsf_get_d1fifo(priv); | |
1164 | fifo->name = "D1FIFO"; | |
1165 | fifo->port = D1FIFO; | |
1166 | fifo->sel = D1FIFOSEL; | |
1167 | fifo->ctr = D1FIFOCTR; | |
f19b7e0d GL |
1168 | fifo->tx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id); |
1169 | fifo->rx_slave.shdma_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id); | |
1b2e21b0 | 1170 | usbhsf_dma_init(priv, fifo); |
e73a9891 | 1171 | |
d3af90a5 KM |
1172 | return 0; |
1173 | } | |
1174 | ||
1175 | void usbhs_fifo_remove(struct usbhs_priv *priv) | |
1176 | { | |
1b2e21b0 KM |
1177 | usbhsf_dma_quit(priv, usbhsf_get_d0fifo(priv)); |
1178 | usbhsf_dma_quit(priv, usbhsf_get_d1fifo(priv)); | |
d3af90a5 | 1179 | } |