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