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> | |
19 | #include "./common.h" | |
20 | #include "./pipe.h" | |
21 | ||
d3af90a5 | 22 | #define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) |
e73a9891 KM |
23 | #define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo)) |
24 | #define usbhsf_get_d1fifo(p) (&((p)->fifo_info.d1fifo)) | |
d3af90a5 | 25 | |
d77e3f4e KM |
26 | #define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ |
27 | ||
4bd04811 | 28 | /* |
233f519d KM |
29 | * packet initialize |
30 | */ | |
31 | void usbhs_pkt_init(struct usbhs_pkt *pkt) | |
32 | { | |
33 | pkt->dma = DMA_ADDR_INVALID; | |
34 | INIT_LIST_HEAD(&pkt->node); | |
35 | } | |
36 | ||
37 | /* | |
38 | * packet control function | |
4bd04811 | 39 | */ |
97664a20 | 40 | static int usbhsf_null_handle(struct usbhs_pkt *pkt, int *is_done) |
dad67397 KM |
41 | { |
42 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); | |
43 | struct device *dev = usbhs_priv_to_dev(priv); | |
44 | ||
45 | dev_err(dev, "null handler\n"); | |
46 | ||
47 | return -EINVAL; | |
48 | } | |
49 | ||
50 | static struct usbhs_pkt_handle usbhsf_null_handler = { | |
51 | .prepare = usbhsf_null_handle, | |
52 | .try_run = usbhsf_null_handle, | |
53 | }; | |
54 | ||
659d4954 | 55 | void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, |
dad67397 | 56 | struct usbhs_pkt_handle *handler, |
659d4954 | 57 | void *buf, int len, int zero) |
6acb95d4 | 58 | { |
dad67397 KM |
59 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
60 | struct device *dev = usbhs_priv_to_dev(priv); | |
97664a20 KM |
61 | unsigned long flags; |
62 | ||
63 | /******************** spin lock ********************/ | |
64 | usbhs_lock(priv, flags); | |
dad67397 KM |
65 | |
66 | if (!handler) { | |
67 | dev_err(dev, "no handler function\n"); | |
68 | handler = &usbhsf_null_handler; | |
69 | } | |
70 | ||
6acb95d4 KM |
71 | list_del_init(&pkt->node); |
72 | list_add_tail(&pkt->node, &pipe->list); | |
73 | ||
659d4954 KM |
74 | pkt->pipe = pipe; |
75 | pkt->buf = buf; | |
dad67397 | 76 | pkt->handler = handler; |
659d4954 KM |
77 | pkt->length = len; |
78 | pkt->zero = zero; | |
79 | pkt->actual = 0; | |
97664a20 KM |
80 | |
81 | usbhs_unlock(priv, flags); | |
82 | /******************** spin unlock ******************/ | |
0432eed0 KM |
83 | |
84 | usbhs_pkt_start(pipe); | |
6acb95d4 KM |
85 | } |
86 | ||
97664a20 | 87 | static void __usbhsf_pkt_del(struct usbhs_pkt *pkt) |
6acb95d4 KM |
88 | { |
89 | list_del_init(&pkt->node); | |
90 | } | |
91 | ||
97664a20 | 92 | static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) |
6acb95d4 KM |
93 | { |
94 | if (list_empty(&pipe->list)) | |
95 | return NULL; | |
96 | ||
97 | return list_entry(pipe->list.next, struct usbhs_pkt, node); | |
98 | } | |
99 | ||
97664a20 KM |
100 | struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt) |
101 | { | |
102 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
103 | unsigned long flags; | |
104 | ||
105 | /******************** spin lock ********************/ | |
106 | usbhs_lock(priv, flags); | |
107 | ||
108 | if (!pkt) | |
109 | pkt = __usbhsf_pkt_get(pipe); | |
110 | ||
111 | if (pkt) | |
112 | __usbhsf_pkt_del(pkt); | |
113 | ||
114 | usbhs_unlock(priv, flags); | |
115 | /******************** spin unlock ******************/ | |
116 | ||
117 | return pkt; | |
118 | } | |
119 | ||
120 | int __usbhs_pkt_handler(struct usbhs_pipe *pipe, int type) | |
121 | { | |
122 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
123 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); | |
124 | struct usbhs_pkt *pkt; | |
125 | struct device *dev = usbhs_priv_to_dev(priv); | |
126 | int (*func)(struct usbhs_pkt *pkt, int *is_done); | |
127 | unsigned long flags; | |
128 | int ret = 0; | |
129 | int is_done = 0; | |
130 | ||
131 | /******************** spin lock ********************/ | |
132 | usbhs_lock(priv, flags); | |
133 | ||
134 | pkt = __usbhsf_pkt_get(pipe); | |
135 | if (!pkt) | |
136 | goto __usbhs_pkt_handler_end; | |
137 | ||
138 | switch (type) { | |
139 | case USBHSF_PKT_PREPARE: | |
140 | func = pkt->handler->prepare; | |
141 | break; | |
142 | case USBHSF_PKT_TRY_RUN: | |
143 | func = pkt->handler->try_run; | |
144 | break; | |
e73a9891 KM |
145 | case USBHSF_PKT_DMA_DONE: |
146 | func = pkt->handler->dma_done; | |
147 | break; | |
97664a20 KM |
148 | default: |
149 | dev_err(dev, "unknown pkt hander\n"); | |
150 | goto __usbhs_pkt_handler_end; | |
151 | } | |
152 | ||
153 | ret = func(pkt, &is_done); | |
154 | ||
155 | if (is_done) | |
156 | __usbhsf_pkt_del(pkt); | |
157 | ||
158 | __usbhs_pkt_handler_end: | |
159 | usbhs_unlock(priv, flags); | |
160 | /******************** spin unlock ******************/ | |
161 | ||
0432eed0 | 162 | if (is_done) { |
97664a20 | 163 | info->done(pkt); |
0432eed0 KM |
164 | usbhs_pkt_start(pipe); |
165 | } | |
97664a20 KM |
166 | |
167 | return ret; | |
168 | } | |
169 | ||
659d4954 KM |
170 | /* |
171 | * irq enable/disable function | |
172 | */ | |
173 | #define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, bempsts, e) | |
174 | #define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, brdysts, e) | |
175 | #define usbhsf_irq_callback_ctrl(pipe, status, enable) \ | |
176 | ({ \ | |
177 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); \ | |
178 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); \ | |
179 | u16 status = (1 << usbhs_pipe_number(pipe)); \ | |
180 | if (!mod) \ | |
181 | return; \ | |
182 | if (enable) \ | |
183 | mod->irq_##status |= status; \ | |
184 | else \ | |
185 | mod->irq_##status &= ~status; \ | |
186 | usbhs_irq_callback_update(priv, mod); \ | |
187 | }) | |
188 | ||
189 | static void usbhsf_tx_irq_ctrl(struct usbhs_pipe *pipe, int enable) | |
190 | { | |
191 | /* | |
192 | * And DCP pipe can NOT use "ready interrupt" for "send" | |
193 | * it should use "empty" interrupt. | |
194 | * see | |
195 | * "Operation" - "Interrupt Function" - "BRDY Interrupt" | |
196 | * | |
197 | * on the other hand, normal pipe can use "ready interrupt" for "send" | |
198 | * even though it is single/double buffer | |
199 | */ | |
200 | if (usbhs_pipe_is_dcp(pipe)) | |
201 | usbhsf_irq_empty_ctrl(pipe, enable); | |
202 | else | |
203 | usbhsf_irq_ready_ctrl(pipe, enable); | |
204 | } | |
205 | ||
206 | static void usbhsf_rx_irq_ctrl(struct usbhs_pipe *pipe, int enable) | |
207 | { | |
208 | usbhsf_irq_ready_ctrl(pipe, enable); | |
209 | } | |
210 | ||
e8d548d5 KM |
211 | /* |
212 | * FIFO ctrl | |
213 | */ | |
d3af90a5 KM |
214 | static void usbhsf_send_terminator(struct usbhs_pipe *pipe, |
215 | struct usbhs_fifo *fifo) | |
e8d548d5 KM |
216 | { |
217 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
218 | ||
d3af90a5 | 219 | usbhs_bset(priv, fifo->ctr, BVAL, BVAL); |
e8d548d5 KM |
220 | } |
221 | ||
d3af90a5 KM |
222 | static int usbhsf_fifo_barrier(struct usbhs_priv *priv, |
223 | struct usbhs_fifo *fifo) | |
e8d548d5 KM |
224 | { |
225 | int timeout = 1024; | |
226 | ||
227 | do { | |
228 | /* The FIFO port is accessible */ | |
d3af90a5 | 229 | if (usbhs_read(priv, fifo->ctr) & FRDY) |
e8d548d5 KM |
230 | return 0; |
231 | ||
232 | udelay(10); | |
233 | } while (timeout--); | |
234 | ||
235 | return -EBUSY; | |
236 | } | |
237 | ||
d3af90a5 KM |
238 | static void usbhsf_fifo_clear(struct usbhs_pipe *pipe, |
239 | struct usbhs_fifo *fifo) | |
e8d548d5 KM |
240 | { |
241 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
242 | ||
243 | if (!usbhs_pipe_is_dcp(pipe)) | |
d3af90a5 | 244 | usbhsf_fifo_barrier(priv, fifo); |
e8d548d5 | 245 | |
d3af90a5 | 246 | usbhs_write(priv, fifo->ctr, BCLR); |
e8d548d5 KM |
247 | } |
248 | ||
d3af90a5 KM |
249 | static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv, |
250 | struct usbhs_fifo *fifo) | |
e8d548d5 | 251 | { |
d3af90a5 | 252 | return usbhs_read(priv, fifo->ctr) & DTLN_MASK; |
e8d548d5 KM |
253 | } |
254 | ||
d77e3f4e KM |
255 | static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe, |
256 | struct usbhs_fifo *fifo) | |
257 | { | |
258 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
259 | ||
260 | usbhs_pipe_select_fifo(pipe, NULL); | |
261 | usbhs_write(priv, fifo->sel, 0); | |
262 | } | |
263 | ||
d3af90a5 KM |
264 | static int usbhsf_fifo_select(struct usbhs_pipe *pipe, |
265 | struct usbhs_fifo *fifo, | |
266 | int write) | |
e8d548d5 KM |
267 | { |
268 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
269 | struct device *dev = usbhs_priv_to_dev(priv); | |
270 | int timeout = 1024; | |
271 | u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */ | |
272 | u16 base = usbhs_pipe_number(pipe); /* CURPIPE */ | |
273 | ||
d77e3f4e KM |
274 | if (usbhs_pipe_is_busy(pipe) || |
275 | usbhsf_fifo_is_busy(fifo)) | |
276 | return -EBUSY; | |
277 | ||
e8d548d5 KM |
278 | if (usbhs_pipe_is_dcp(pipe)) |
279 | base |= (1 == write) << 5; /* ISEL */ | |
280 | ||
281 | /* "base" will be used below */ | |
d3af90a5 | 282 | usbhs_write(priv, fifo->sel, base | MBW_32); |
e8d548d5 KM |
283 | |
284 | /* check ISEL and CURPIPE value */ | |
285 | while (timeout--) { | |
d77e3f4e KM |
286 | if (base == (mask & usbhs_read(priv, fifo->sel))) { |
287 | usbhs_pipe_select_fifo(pipe, fifo); | |
e8d548d5 | 288 | return 0; |
d77e3f4e | 289 | } |
e8d548d5 KM |
290 | udelay(10); |
291 | } | |
292 | ||
293 | dev_err(dev, "fifo select error\n"); | |
294 | ||
295 | return -EIO; | |
296 | } | |
297 | ||
298 | /* | |
233f519d | 299 | * PIO push handler |
e8d548d5 | 300 | */ |
0cb7e61d | 301 | static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) |
e8d548d5 | 302 | { |
4bd04811 | 303 | struct usbhs_pipe *pipe = pkt->pipe; |
e8d548d5 | 304 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
659d4954 | 305 | struct device *dev = usbhs_priv_to_dev(priv); |
d3af90a5 KM |
306 | struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ |
307 | void __iomem *addr = priv->base + fifo->port; | |
659d4954 | 308 | u8 *buf; |
e8d548d5 KM |
309 | int maxp = usbhs_pipe_get_maxpacket(pipe); |
310 | int total_len; | |
4bd04811 | 311 | int i, ret, len; |
97664a20 | 312 | int is_short; |
e8d548d5 | 313 | |
d3af90a5 | 314 | ret = usbhsf_fifo_select(pipe, fifo, 1); |
e8d548d5 | 315 | if (ret < 0) |
d77e3f4e | 316 | return 0; |
e8d548d5 | 317 | |
dad67397 | 318 | ret = usbhs_pipe_is_accessible(pipe); |
e8d548d5 | 319 | if (ret < 0) |
659d4954 | 320 | goto usbhs_fifo_write_busy; |
e8d548d5 | 321 | |
d3af90a5 | 322 | ret = usbhsf_fifo_barrier(priv, fifo); |
e8d548d5 | 323 | if (ret < 0) |
659d4954 | 324 | goto usbhs_fifo_write_busy; |
e8d548d5 | 325 | |
659d4954 KM |
326 | buf = pkt->buf + pkt->actual; |
327 | len = pkt->length - pkt->actual; | |
328 | len = min(len, maxp); | |
329 | total_len = len; | |
330 | is_short = total_len < maxp; | |
e8d548d5 KM |
331 | |
332 | /* | |
333 | * FIXME | |
334 | * | |
335 | * 32-bit access only | |
336 | */ | |
659d4954 | 337 | if (len >= 4 && !((unsigned long)buf & 0x03)) { |
e8d548d5 KM |
338 | iowrite32_rep(addr, buf, len / 4); |
339 | len %= 4; | |
340 | buf += total_len - len; | |
341 | } | |
342 | ||
343 | /* the rest operation */ | |
344 | for (i = 0; i < len; i++) | |
345 | iowrite8(buf[i], addr + (0x03 - (i & 0x03))); | |
346 | ||
659d4954 KM |
347 | /* |
348 | * variable update | |
349 | */ | |
350 | pkt->actual += total_len; | |
351 | ||
352 | if (pkt->actual < pkt->length) | |
97664a20 | 353 | *is_done = 0; /* there are remainder data */ |
659d4954 | 354 | else if (is_short) |
97664a20 | 355 | *is_done = 1; /* short packet */ |
659d4954 | 356 | else |
97664a20 | 357 | *is_done = !pkt->zero; /* send zero packet ? */ |
659d4954 KM |
358 | |
359 | /* | |
360 | * pipe/irq handling | |
361 | */ | |
362 | if (is_short) | |
d3af90a5 | 363 | usbhsf_send_terminator(pipe, fifo); |
e8d548d5 | 364 | |
97664a20 | 365 | usbhsf_tx_irq_ctrl(pipe, !*is_done); |
4bd04811 KM |
366 | usbhs_pipe_enable(pipe); |
367 | ||
659d4954 KM |
368 | dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n", |
369 | usbhs_pipe_number(pipe), | |
97664a20 | 370 | pkt->length, pkt->actual, *is_done, pkt->zero); |
659d4954 KM |
371 | |
372 | /* | |
373 | * Transmission end | |
374 | */ | |
97664a20 | 375 | if (*is_done) { |
659d4954 KM |
376 | if (usbhs_pipe_is_dcp(pipe)) |
377 | usbhs_dcp_control_transfer_done(pipe); | |
4bd04811 KM |
378 | } |
379 | ||
d77e3f4e KM |
380 | usbhsf_fifo_unselect(pipe, fifo); |
381 | ||
4bd04811 | 382 | return 0; |
659d4954 KM |
383 | |
384 | usbhs_fifo_write_busy: | |
d77e3f4e KM |
385 | usbhsf_fifo_unselect(pipe, fifo); |
386 | ||
659d4954 KM |
387 | /* |
388 | * pipe is busy. | |
389 | * retry in interrupt | |
390 | */ | |
391 | usbhsf_tx_irq_ctrl(pipe, 1); | |
392 | ||
393 | return ret; | |
e8d548d5 KM |
394 | } |
395 | ||
0cb7e61d KM |
396 | struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = { |
397 | .prepare = usbhsf_pio_try_push, | |
398 | .try_run = usbhsf_pio_try_push, | |
dad67397 KM |
399 | }; |
400 | ||
233f519d KM |
401 | /* |
402 | * PIO pop handler | |
403 | */ | |
97664a20 | 404 | static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) |
e8d548d5 | 405 | { |
dad67397 | 406 | struct usbhs_pipe *pipe = pkt->pipe; |
d77e3f4e KM |
407 | |
408 | if (usbhs_pipe_is_busy(pipe)) | |
409 | return 0; | |
e8d548d5 KM |
410 | |
411 | /* | |
d77e3f4e | 412 | * pipe enable to prepare packet receive |
e8d548d5 | 413 | */ |
e8d548d5 KM |
414 | |
415 | usbhs_pipe_enable(pipe); | |
659d4954 | 416 | usbhsf_rx_irq_ctrl(pipe, 1); |
e8d548d5 | 417 | |
d3af90a5 | 418 | return 0; |
e8d548d5 KM |
419 | } |
420 | ||
0cb7e61d | 421 | static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done) |
e8d548d5 | 422 | { |
4bd04811 | 423 | struct usbhs_pipe *pipe = pkt->pipe; |
e8d548d5 | 424 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
659d4954 | 425 | struct device *dev = usbhs_priv_to_dev(priv); |
d3af90a5 KM |
426 | struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ |
427 | void __iomem *addr = priv->base + fifo->port; | |
659d4954 KM |
428 | u8 *buf; |
429 | u32 data = 0; | |
430 | int maxp = usbhs_pipe_get_maxpacket(pipe); | |
4bd04811 | 431 | int rcv_len, len; |
e8d548d5 | 432 | int i, ret; |
4bd04811 | 433 | int total_len = 0; |
e8d548d5 | 434 | |
d3af90a5 | 435 | ret = usbhsf_fifo_select(pipe, fifo, 0); |
e8d548d5 | 436 | if (ret < 0) |
d77e3f4e | 437 | return 0; |
e8d548d5 | 438 | |
d3af90a5 | 439 | ret = usbhsf_fifo_barrier(priv, fifo); |
e8d548d5 | 440 | if (ret < 0) |
d77e3f4e | 441 | goto usbhs_fifo_read_busy; |
e8d548d5 | 442 | |
d3af90a5 | 443 | rcv_len = usbhsf_fifo_rcv_len(priv, fifo); |
e8d548d5 | 444 | |
659d4954 KM |
445 | buf = pkt->buf + pkt->actual; |
446 | len = pkt->length - pkt->actual; | |
447 | len = min(len, rcv_len); | |
448 | total_len = len; | |
449 | ||
e8d548d5 KM |
450 | /* |
451 | * Buffer clear if Zero-Length packet | |
452 | * | |
453 | * see | |
454 | * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function" | |
455 | */ | |
456 | if (0 == rcv_len) { | |
d3af90a5 | 457 | usbhsf_fifo_clear(pipe, fifo); |
4bd04811 | 458 | goto usbhs_fifo_read_end; |
e8d548d5 KM |
459 | } |
460 | ||
e8d548d5 KM |
461 | /* |
462 | * FIXME | |
463 | * | |
464 | * 32-bit access only | |
465 | */ | |
659d4954 | 466 | if (len >= 4 && !((unsigned long)buf & 0x03)) { |
e8d548d5 KM |
467 | ioread32_rep(addr, buf, len / 4); |
468 | len %= 4; | |
659d4954 | 469 | buf += total_len - len; |
e8d548d5 KM |
470 | } |
471 | ||
472 | /* the rest operation */ | |
473 | for (i = 0; i < len; i++) { | |
474 | if (!(i & 0x03)) | |
475 | data = ioread32(addr); | |
476 | ||
477 | buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; | |
478 | } | |
479 | ||
659d4954 KM |
480 | pkt->actual += total_len; |
481 | ||
4bd04811 | 482 | usbhs_fifo_read_end: |
659d4954 | 483 | if ((pkt->actual == pkt->length) || /* receive all data */ |
97664a20 KM |
484 | (total_len < maxp)) { /* short packet */ |
485 | *is_done = 1; | |
659d4954 KM |
486 | usbhsf_rx_irq_ctrl(pipe, 0); |
487 | usbhs_pipe_disable(pipe); | |
4bd04811 KM |
488 | } |
489 | ||
97664a20 KM |
490 | dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d)\n", |
491 | usbhs_pipe_number(pipe), | |
492 | pkt->length, pkt->actual, *is_done, pkt->zero); | |
493 | ||
d77e3f4e KM |
494 | usbhs_fifo_read_busy: |
495 | usbhsf_fifo_unselect(pipe, fifo); | |
496 | ||
497 | return ret; | |
e8d548d5 | 498 | } |
dad67397 | 499 | |
0cb7e61d | 500 | struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler = { |
dad67397 | 501 | .prepare = usbhsf_prepare_pop, |
0cb7e61d | 502 | .try_run = usbhsf_pio_try_pop, |
dad67397 KM |
503 | }; |
504 | ||
505 | /* | |
233f519d | 506 | * DCP ctrol statge handler |
dad67397 | 507 | */ |
97664a20 | 508 | static int usbhsf_ctrl_stage_end(struct usbhs_pkt *pkt, int *is_done) |
dad67397 | 509 | { |
97664a20 | 510 | usbhs_dcp_control_transfer_done(pkt->pipe); |
dad67397 | 511 | |
97664a20 | 512 | *is_done = 1; |
dad67397 KM |
513 | |
514 | return 0; | |
515 | } | |
516 | ||
517 | struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler = { | |
518 | .prepare = usbhsf_ctrl_stage_end, | |
519 | .try_run = usbhsf_ctrl_stage_end, | |
520 | }; | |
521 | ||
e73a9891 KM |
522 | /* |
523 | * DMA fifo functions | |
524 | */ | |
525 | static struct dma_chan *usbhsf_dma_chan_get(struct usbhs_fifo *fifo, | |
526 | struct usbhs_pkt *pkt) | |
527 | { | |
528 | if (&usbhs_fifo_dma_push_handler == pkt->handler) | |
529 | return fifo->tx_chan; | |
530 | ||
531 | if (&usbhs_fifo_dma_pop_handler == pkt->handler) | |
532 | return fifo->rx_chan; | |
533 | ||
534 | return NULL; | |
535 | } | |
536 | ||
537 | static struct usbhs_fifo *usbhsf_get_dma_fifo(struct usbhs_priv *priv, | |
538 | struct usbhs_pkt *pkt) | |
539 | { | |
540 | struct usbhs_fifo *fifo; | |
541 | ||
542 | /* DMA :: D0FIFO */ | |
543 | fifo = usbhsf_get_d0fifo(priv); | |
544 | if (usbhsf_dma_chan_get(fifo, pkt) && | |
545 | !usbhsf_fifo_is_busy(fifo)) | |
546 | return fifo; | |
547 | ||
548 | /* DMA :: D1FIFO */ | |
549 | fifo = usbhsf_get_d1fifo(priv); | |
550 | if (usbhsf_dma_chan_get(fifo, pkt) && | |
551 | !usbhsf_fifo_is_busy(fifo)) | |
552 | return fifo; | |
553 | ||
554 | return NULL; | |
555 | } | |
556 | ||
557 | #define usbhsf_dma_start(p, f) __usbhsf_dma_ctrl(p, f, DREQE) | |
558 | #define usbhsf_dma_stop(p, f) __usbhsf_dma_ctrl(p, f, 0) | |
559 | static void __usbhsf_dma_ctrl(struct usbhs_pipe *pipe, | |
560 | struct usbhs_fifo *fifo, | |
561 | u16 dreqe) | |
562 | { | |
563 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
564 | ||
565 | usbhs_bset(priv, fifo->sel, DREQE, dreqe); | |
566 | } | |
567 | ||
568 | #define usbhsf_dma_map(p) __usbhsf_dma_map_ctrl(p, 1) | |
569 | #define usbhsf_dma_unmap(p) __usbhsf_dma_map_ctrl(p, 0) | |
570 | static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) | |
571 | { | |
572 | struct usbhs_pipe *pipe = pkt->pipe; | |
573 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
574 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); | |
575 | ||
576 | return info->dma_map_ctrl(pkt, map); | |
577 | } | |
578 | ||
579 | static void usbhsf_dma_complete(void *arg); | |
580 | static void usbhsf_dma_prepare_tasklet(unsigned long data) | |
581 | { | |
582 | struct usbhs_pkt *pkt = (struct usbhs_pkt *)data; | |
583 | struct usbhs_pipe *pipe = pkt->pipe; | |
584 | struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); | |
585 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
586 | struct scatterlist sg; | |
587 | struct dma_async_tx_descriptor *desc; | |
588 | struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); | |
589 | struct device *dev = usbhs_priv_to_dev(priv); | |
590 | enum dma_data_direction dir; | |
591 | dma_cookie_t cookie; | |
592 | ||
593 | dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; | |
594 | ||
595 | sg_init_table(&sg, 1); | |
596 | sg_set_page(&sg, virt_to_page(pkt->dma), | |
597 | pkt->length, offset_in_page(pkt->dma)); | |
598 | sg_dma_address(&sg) = pkt->dma + pkt->actual; | |
599 | sg_dma_len(&sg) = pkt->trans; | |
600 | ||
601 | desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir, | |
602 | DMA_PREP_INTERRUPT | | |
603 | DMA_CTRL_ACK); | |
604 | if (!desc) | |
605 | return; | |
606 | ||
607 | desc->callback = usbhsf_dma_complete; | |
608 | desc->callback_param = pipe; | |
609 | ||
610 | cookie = desc->tx_submit(desc); | |
611 | if (cookie < 0) { | |
612 | dev_err(dev, "Failed to submit dma descriptor\n"); | |
613 | return; | |
614 | } | |
615 | ||
616 | dev_dbg(dev, " %s %d (%d/ %d)\n", | |
617 | fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero); | |
618 | ||
619 | usbhsf_dma_start(pipe, fifo); | |
620 | dma_async_issue_pending(chan); | |
621 | } | |
622 | ||
233f519d KM |
623 | /* |
624 | * DMA push handler | |
625 | */ | |
e73a9891 KM |
626 | static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) |
627 | { | |
628 | struct usbhs_pipe *pipe = pkt->pipe; | |
629 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
630 | struct usbhs_fifo *fifo; | |
631 | int len = pkt->length - pkt->actual; | |
632 | int ret; | |
633 | ||
634 | if (usbhs_pipe_is_busy(pipe)) | |
635 | return 0; | |
636 | ||
637 | /* use PIO if packet is less than pio_dma_border or pipe is DCP */ | |
638 | if ((len < usbhs_get_dparam(priv, pio_dma_border)) || | |
639 | usbhs_pipe_is_dcp(pipe)) | |
640 | goto usbhsf_pio_prepare_push; | |
641 | ||
642 | if (len % 4) /* 32bit alignment */ | |
643 | goto usbhsf_pio_prepare_push; | |
644 | ||
645 | /* get enable DMA fifo */ | |
646 | fifo = usbhsf_get_dma_fifo(priv, pkt); | |
647 | if (!fifo) | |
648 | goto usbhsf_pio_prepare_push; | |
649 | ||
650 | if (usbhsf_dma_map(pkt) < 0) | |
651 | goto usbhsf_pio_prepare_push; | |
652 | ||
653 | ret = usbhsf_fifo_select(pipe, fifo, 0); | |
654 | if (ret < 0) | |
655 | goto usbhsf_pio_prepare_push_unmap; | |
656 | ||
657 | pkt->trans = len; | |
658 | ||
659 | tasklet_init(&fifo->tasklet, | |
660 | usbhsf_dma_prepare_tasklet, | |
661 | (unsigned long)pkt); | |
662 | ||
663 | tasklet_schedule(&fifo->tasklet); | |
664 | ||
665 | return 0; | |
666 | ||
667 | usbhsf_pio_prepare_push_unmap: | |
668 | usbhsf_dma_unmap(pkt); | |
669 | usbhsf_pio_prepare_push: | |
670 | /* | |
671 | * change handler to PIO | |
672 | */ | |
673 | pkt->handler = &usbhs_fifo_pio_push_handler; | |
674 | ||
675 | return pkt->handler->prepare(pkt, is_done); | |
676 | } | |
677 | ||
678 | static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done) | |
679 | { | |
680 | struct usbhs_pipe *pipe = pkt->pipe; | |
681 | ||
682 | pkt->actual = pkt->trans; | |
683 | ||
684 | *is_done = !pkt->zero; /* send zero packet ? */ | |
685 | ||
686 | usbhsf_dma_stop(pipe, pipe->fifo); | |
687 | usbhsf_dma_unmap(pkt); | |
688 | usbhsf_fifo_unselect(pipe, pipe->fifo); | |
689 | ||
690 | return 0; | |
691 | } | |
692 | ||
693 | struct usbhs_pkt_handle usbhs_fifo_dma_push_handler = { | |
694 | .prepare = usbhsf_dma_prepare_push, | |
695 | .dma_done = usbhsf_dma_push_done, | |
696 | }; | |
697 | ||
233f519d KM |
698 | /* |
699 | * DMA pop handler | |
700 | */ | |
e73a9891 KM |
701 | static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) |
702 | { | |
703 | struct usbhs_pipe *pipe = pkt->pipe; | |
704 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
705 | struct usbhs_fifo *fifo; | |
706 | int len, ret; | |
707 | ||
708 | if (usbhs_pipe_is_busy(pipe)) | |
709 | return 0; | |
710 | ||
711 | if (usbhs_pipe_is_dcp(pipe)) | |
712 | goto usbhsf_pio_prepare_pop; | |
713 | ||
714 | /* get enable DMA fifo */ | |
715 | fifo = usbhsf_get_dma_fifo(priv, pkt); | |
716 | if (!fifo) | |
717 | goto usbhsf_pio_prepare_pop; | |
718 | ||
719 | ret = usbhsf_fifo_select(pipe, fifo, 0); | |
720 | if (ret < 0) | |
721 | goto usbhsf_pio_prepare_pop; | |
722 | ||
723 | /* use PIO if packet is less than pio_dma_border */ | |
724 | len = usbhsf_fifo_rcv_len(priv, fifo); | |
725 | len = min(pkt->length - pkt->actual, len); | |
726 | if (len % 4) /* 32bit alignment */ | |
727 | goto usbhsf_pio_prepare_pop_unselect; | |
728 | ||
729 | if (len < usbhs_get_dparam(priv, pio_dma_border)) | |
730 | goto usbhsf_pio_prepare_pop_unselect; | |
731 | ||
732 | ret = usbhsf_fifo_barrier(priv, fifo); | |
733 | if (ret < 0) | |
734 | goto usbhsf_pio_prepare_pop_unselect; | |
735 | ||
736 | if (usbhsf_dma_map(pkt) < 0) | |
737 | goto usbhsf_pio_prepare_pop_unselect; | |
738 | ||
739 | /* DMA */ | |
740 | ||
741 | /* | |
742 | * usbhs_fifo_dma_pop_handler :: prepare | |
743 | * enabled irq to come here. | |
744 | * but it is no longer needed for DMA. disable it. | |
745 | */ | |
746 | usbhsf_rx_irq_ctrl(pipe, 0); | |
747 | ||
748 | pkt->trans = len; | |
749 | ||
750 | tasklet_init(&fifo->tasklet, | |
751 | usbhsf_dma_prepare_tasklet, | |
752 | (unsigned long)pkt); | |
753 | ||
754 | tasklet_schedule(&fifo->tasklet); | |
755 | ||
756 | return 0; | |
757 | ||
758 | usbhsf_pio_prepare_pop_unselect: | |
759 | usbhsf_fifo_unselect(pipe, fifo); | |
760 | usbhsf_pio_prepare_pop: | |
761 | ||
762 | /* | |
763 | * change handler to PIO | |
764 | */ | |
765 | pkt->handler = &usbhs_fifo_pio_pop_handler; | |
766 | ||
767 | return pkt->handler->try_run(pkt, is_done); | |
768 | } | |
769 | ||
770 | static int usbhsf_dma_pop_done(struct usbhs_pkt *pkt, int *is_done) | |
771 | { | |
772 | struct usbhs_pipe *pipe = pkt->pipe; | |
773 | int maxp = usbhs_pipe_get_maxpacket(pipe); | |
774 | ||
775 | usbhsf_dma_stop(pipe, pipe->fifo); | |
776 | usbhsf_dma_unmap(pkt); | |
777 | usbhsf_fifo_unselect(pipe, pipe->fifo); | |
778 | ||
779 | pkt->actual += pkt->trans; | |
780 | ||
781 | if ((pkt->actual == pkt->length) || /* receive all data */ | |
782 | (pkt->trans < maxp)) { /* short packet */ | |
783 | *is_done = 1; | |
784 | } else { | |
785 | /* re-enable */ | |
786 | usbhsf_prepare_pop(pkt, is_done); | |
787 | } | |
788 | ||
789 | return 0; | |
790 | } | |
791 | ||
792 | struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler = { | |
793 | .prepare = usbhsf_prepare_pop, | |
794 | .try_run = usbhsf_dma_try_pop, | |
795 | .dma_done = usbhsf_dma_pop_done | |
796 | }; | |
797 | ||
798 | /* | |
799 | * DMA setting | |
800 | */ | |
801 | static bool usbhsf_dma_filter(struct dma_chan *chan, void *param) | |
802 | { | |
803 | struct sh_dmae_slave *slave = param; | |
804 | ||
805 | /* | |
806 | * FIXME | |
807 | * | |
808 | * usbhs doesn't recognize id = 0 as valid DMA | |
809 | */ | |
810 | if (0 == slave->slave_id) | |
811 | return false; | |
812 | ||
813 | chan->private = slave; | |
814 | ||
815 | return true; | |
816 | } | |
817 | ||
818 | static void usbhsf_dma_quit(struct usbhs_priv *priv, struct usbhs_fifo *fifo) | |
819 | { | |
820 | if (fifo->tx_chan) | |
821 | dma_release_channel(fifo->tx_chan); | |
822 | if (fifo->rx_chan) | |
823 | dma_release_channel(fifo->rx_chan); | |
824 | ||
825 | fifo->tx_chan = NULL; | |
826 | fifo->rx_chan = NULL; | |
827 | } | |
828 | ||
829 | static void usbhsf_dma_init(struct usbhs_priv *priv, | |
830 | struct usbhs_fifo *fifo) | |
831 | { | |
832 | struct device *dev = usbhs_priv_to_dev(priv); | |
833 | dma_cap_mask_t mask; | |
834 | ||
835 | dma_cap_zero(mask); | |
836 | dma_cap_set(DMA_SLAVE, mask); | |
837 | fifo->tx_chan = dma_request_channel(mask, usbhsf_dma_filter, | |
838 | &fifo->tx_slave); | |
839 | ||
840 | dma_cap_zero(mask); | |
841 | dma_cap_set(DMA_SLAVE, mask); | |
842 | fifo->rx_chan = dma_request_channel(mask, usbhsf_dma_filter, | |
843 | &fifo->rx_slave); | |
844 | ||
845 | if (fifo->tx_chan || fifo->rx_chan) | |
4ce68805 | 846 | dev_dbg(dev, "enable DMAEngine (%s%s%s)\n", |
e73a9891 KM |
847 | fifo->name, |
848 | fifo->tx_chan ? "[TX]" : " ", | |
849 | fifo->rx_chan ? "[RX]" : " "); | |
850 | } | |
851 | ||
dad67397 KM |
852 | /* |
853 | * irq functions | |
854 | */ | |
855 | static int usbhsf_irq_empty(struct usbhs_priv *priv, | |
856 | struct usbhs_irq_state *irq_state) | |
857 | { | |
858 | struct usbhs_pipe *pipe; | |
dad67397 KM |
859 | struct device *dev = usbhs_priv_to_dev(priv); |
860 | int i, ret; | |
861 | ||
862 | if (!irq_state->bempsts) { | |
863 | dev_err(dev, "debug %s !!\n", __func__); | |
864 | return -EIO; | |
865 | } | |
866 | ||
867 | dev_dbg(dev, "irq empty [0x%04x]\n", irq_state->bempsts); | |
868 | ||
869 | /* | |
870 | * search interrupted "pipe" | |
871 | * not "uep". | |
872 | */ | |
873 | usbhs_for_each_pipe_with_dcp(pipe, priv, i) { | |
874 | if (!(irq_state->bempsts & (1 << i))) | |
875 | continue; | |
876 | ||
97664a20 | 877 | ret = usbhs_pkt_run(pipe); |
dad67397 KM |
878 | if (ret < 0) |
879 | dev_err(dev, "irq_empty run_error %d : %d\n", i, ret); | |
880 | } | |
881 | ||
882 | return 0; | |
883 | } | |
884 | ||
885 | static int usbhsf_irq_ready(struct usbhs_priv *priv, | |
886 | struct usbhs_irq_state *irq_state) | |
887 | { | |
888 | struct usbhs_pipe *pipe; | |
dad67397 KM |
889 | struct device *dev = usbhs_priv_to_dev(priv); |
890 | int i, ret; | |
891 | ||
892 | if (!irq_state->brdysts) { | |
893 | dev_err(dev, "debug %s !!\n", __func__); | |
894 | return -EIO; | |
895 | } | |
896 | ||
897 | dev_dbg(dev, "irq ready [0x%04x]\n", irq_state->brdysts); | |
898 | ||
899 | /* | |
900 | * search interrupted "pipe" | |
901 | * not "uep". | |
902 | */ | |
903 | usbhs_for_each_pipe_with_dcp(pipe, priv, i) { | |
904 | if (!(irq_state->brdysts & (1 << i))) | |
905 | continue; | |
906 | ||
97664a20 | 907 | ret = usbhs_pkt_run(pipe); |
dad67397 KM |
908 | if (ret < 0) |
909 | dev_err(dev, "irq_ready run_error %d : %d\n", i, ret); | |
910 | } | |
911 | ||
912 | return 0; | |
913 | } | |
914 | ||
e73a9891 KM |
915 | static void usbhsf_dma_complete(void *arg) |
916 | { | |
917 | struct usbhs_pipe *pipe = arg; | |
918 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); | |
919 | struct device *dev = usbhs_priv_to_dev(priv); | |
920 | int ret; | |
921 | ||
922 | ret = usbhs_pkt_dmadone(pipe); | |
923 | if (ret < 0) | |
924 | dev_err(dev, "dma_complete run_error %d : %d\n", | |
925 | usbhs_pipe_number(pipe), ret); | |
926 | } | |
927 | ||
dad67397 KM |
928 | /* |
929 | * fifo init | |
930 | */ | |
931 | void usbhs_fifo_init(struct usbhs_priv *priv) | |
932 | { | |
933 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); | |
d77e3f4e | 934 | struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv); |
e73a9891 KM |
935 | struct usbhs_fifo *d0fifo = usbhsf_get_d0fifo(priv); |
936 | struct usbhs_fifo *d1fifo = usbhsf_get_d1fifo(priv); | |
dad67397 KM |
937 | |
938 | mod->irq_empty = usbhsf_irq_empty; | |
939 | mod->irq_ready = usbhsf_irq_ready; | |
940 | mod->irq_bempsts = 0; | |
941 | mod->irq_brdysts = 0; | |
d77e3f4e KM |
942 | |
943 | cfifo->pipe = NULL; | |
e73a9891 KM |
944 | cfifo->tx_chan = NULL; |
945 | cfifo->rx_chan = NULL; | |
946 | ||
947 | d0fifo->pipe = NULL; | |
948 | d0fifo->tx_chan = NULL; | |
949 | d0fifo->rx_chan = NULL; | |
950 | ||
951 | d1fifo->pipe = NULL; | |
952 | d1fifo->tx_chan = NULL; | |
953 | d1fifo->rx_chan = NULL; | |
954 | ||
955 | usbhsf_dma_init(priv, usbhsf_get_d0fifo(priv)); | |
956 | usbhsf_dma_init(priv, usbhsf_get_d1fifo(priv)); | |
dad67397 KM |
957 | } |
958 | ||
959 | void usbhs_fifo_quit(struct usbhs_priv *priv) | |
960 | { | |
961 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); | |
962 | ||
963 | mod->irq_empty = NULL; | |
964 | mod->irq_ready = NULL; | |
965 | mod->irq_bempsts = 0; | |
966 | mod->irq_brdysts = 0; | |
e73a9891 KM |
967 | |
968 | usbhsf_dma_quit(priv, usbhsf_get_d0fifo(priv)); | |
969 | usbhsf_dma_quit(priv, usbhsf_get_d1fifo(priv)); | |
dad67397 | 970 | } |
d3af90a5 KM |
971 | |
972 | int usbhs_fifo_probe(struct usbhs_priv *priv) | |
973 | { | |
974 | struct usbhs_fifo *fifo; | |
975 | ||
976 | /* CFIFO */ | |
977 | fifo = usbhsf_get_cfifo(priv); | |
e73a9891 | 978 | fifo->name = "CFIFO"; |
d3af90a5 KM |
979 | fifo->port = CFIFO; |
980 | fifo->sel = CFIFOSEL; | |
981 | fifo->ctr = CFIFOCTR; | |
982 | ||
e73a9891 KM |
983 | /* D0FIFO */ |
984 | fifo = usbhsf_get_d0fifo(priv); | |
985 | fifo->name = "D0FIFO"; | |
986 | fifo->port = D0FIFO; | |
987 | fifo->sel = D0FIFOSEL; | |
988 | fifo->ctr = D0FIFOCTR; | |
989 | fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id); | |
990 | fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id); | |
991 | ||
992 | /* D1FIFO */ | |
993 | fifo = usbhsf_get_d1fifo(priv); | |
994 | fifo->name = "D1FIFO"; | |
995 | fifo->port = D1FIFO; | |
996 | fifo->sel = D1FIFOSEL; | |
997 | fifo->ctr = D1FIFOCTR; | |
998 | fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id); | |
999 | fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id); | |
1000 | ||
d3af90a5 KM |
1001 | return 0; |
1002 | } | |
1003 | ||
1004 | void usbhs_fifo_remove(struct usbhs_priv *priv) | |
1005 | { | |
1006 | } |