1 | // SPDX-License-Identifier: GPL-1.0+ |
2 | /* |
3 | * Renesas USB driver |
4 | * |
5 | * Copyright (C) 2011 Renesas Solutions Corp. |
6 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
7 | */ |
8 | #include <linux/delay.h> |
9 | #include <linux/slab.h> |
10 | #include "common.h" |
11 | #include "pipe.h" |
12 | |
13 | /* |
14 | * macros |
15 | */ |
16 | #define usbhsp_addr_offset(p) ((usbhs_pipe_number(p) - 1) * 2) |
17 | |
18 | #define usbhsp_flags_set(p, f) ((p)->flags |= USBHS_PIPE_FLAGS_##f) |
19 | #define usbhsp_flags_clr(p, f) ((p)->flags &= ~USBHS_PIPE_FLAGS_##f) |
20 | #define usbhsp_flags_has(p, f) ((p)->flags & USBHS_PIPE_FLAGS_##f) |
21 | #define usbhsp_flags_init(p) do {(p)->flags = 0; } while (0) |
22 | |
23 | /* |
24 | * for debug |
25 | */ |
26 | static char *usbhsp_pipe_name[] = { |
27 | [USB_ENDPOINT_XFER_CONTROL] = "DCP" , |
28 | [USB_ENDPOINT_XFER_BULK] = "BULK" , |
29 | [USB_ENDPOINT_XFER_INT] = "INT" , |
30 | [USB_ENDPOINT_XFER_ISOC] = "ISO" , |
31 | }; |
32 | |
33 | char *usbhs_pipe_name(struct usbhs_pipe *pipe) |
34 | { |
35 | return usbhsp_pipe_name[usbhs_pipe_type(pipe)]; |
36 | } |
37 | |
38 | static struct renesas_usbhs_driver_pipe_config |
39 | *usbhsp_get_pipe_config(struct usbhs_priv *priv, int pipe_num) |
40 | { |
41 | struct renesas_usbhs_driver_pipe_config *pipe_configs = |
42 | usbhs_get_dparam(priv, pipe_configs); |
43 | |
44 | return &pipe_configs[pipe_num]; |
45 | } |
46 | |
47 | /* |
48 | * DCPCTR/PIPEnCTR functions |
49 | */ |
50 | static void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val) |
51 | { |
52 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
53 | int offset = usbhsp_addr_offset(pipe); |
54 | |
55 | if (usbhs_pipe_is_dcp(pipe)) |
56 | usbhs_bset(priv, DCPCTR, mask, data: val); |
57 | else |
58 | usbhs_bset(priv, PIPEnCTR + offset, mask, data: val); |
59 | } |
60 | |
61 | static u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe) |
62 | { |
63 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
64 | int offset = usbhsp_addr_offset(pipe); |
65 | |
66 | if (usbhs_pipe_is_dcp(pipe)) |
67 | return usbhs_read(priv, DCPCTR); |
68 | else |
69 | return usbhs_read(priv, PIPEnCTR + offset); |
70 | } |
71 | |
72 | /* |
73 | * DCP/PIPE functions |
74 | */ |
75 | static void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe, |
76 | u16 dcp_reg, u16 pipe_reg, |
77 | u16 mask, u16 val) |
78 | { |
79 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
80 | |
81 | if (usbhs_pipe_is_dcp(pipe)) |
82 | usbhs_bset(priv, reg: dcp_reg, mask, data: val); |
83 | else |
84 | usbhs_bset(priv, reg: pipe_reg, mask, data: val); |
85 | } |
86 | |
87 | static u16 __usbhsp_pipe_xxx_get(struct usbhs_pipe *pipe, |
88 | u16 dcp_reg, u16 pipe_reg) |
89 | { |
90 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
91 | |
92 | if (usbhs_pipe_is_dcp(pipe)) |
93 | return usbhs_read(priv, reg: dcp_reg); |
94 | else |
95 | return usbhs_read(priv, reg: pipe_reg); |
96 | } |
97 | |
98 | /* |
99 | * DCPCFG/PIPECFG functions |
100 | */ |
101 | static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val) |
102 | { |
103 | __usbhsp_pipe_xxx_set(pipe, DCPCFG, PIPECFG, mask, val); |
104 | } |
105 | |
106 | static u16 usbhsp_pipe_cfg_get(struct usbhs_pipe *pipe) |
107 | { |
108 | return __usbhsp_pipe_xxx_get(pipe, DCPCFG, PIPECFG); |
109 | } |
110 | |
111 | /* |
112 | * PIPEnTRN/PIPEnTRE functions |
113 | */ |
114 | static void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val) |
115 | { |
116 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
117 | struct device *dev = usbhs_priv_to_dev(priv); |
118 | int num = usbhs_pipe_number(pipe); |
119 | u16 reg; |
120 | |
121 | /* |
122 | * It is impossible to calculate address, |
123 | * since PIPEnTRN addresses were mapped randomly. |
124 | */ |
125 | #define CASE_PIPExTRN(a) \ |
126 | case 0x ## a: \ |
127 | reg = PIPE ## a ## TRN; \ |
128 | break; |
129 | |
130 | switch (num) { |
131 | CASE_PIPExTRN(1); |
132 | CASE_PIPExTRN(2); |
133 | CASE_PIPExTRN(3); |
134 | CASE_PIPExTRN(4); |
135 | CASE_PIPExTRN(5); |
136 | CASE_PIPExTRN(B); |
137 | CASE_PIPExTRN(C); |
138 | CASE_PIPExTRN(D); |
139 | CASE_PIPExTRN(E); |
140 | CASE_PIPExTRN(F); |
141 | CASE_PIPExTRN(9); |
142 | CASE_PIPExTRN(A); |
143 | default: |
144 | dev_err(dev, "unknown pipe (%d)\n" , num); |
145 | return; |
146 | } |
147 | __usbhsp_pipe_xxx_set(pipe, dcp_reg: 0, pipe_reg: reg, mask, val); |
148 | } |
149 | |
150 | static void usbhsp_pipe_tre_set(struct usbhs_pipe *pipe, u16 mask, u16 val) |
151 | { |
152 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
153 | struct device *dev = usbhs_priv_to_dev(priv); |
154 | int num = usbhs_pipe_number(pipe); |
155 | u16 reg; |
156 | |
157 | /* |
158 | * It is impossible to calculate address, |
159 | * since PIPEnTRE addresses were mapped randomly. |
160 | */ |
161 | #define CASE_PIPExTRE(a) \ |
162 | case 0x ## a: \ |
163 | reg = PIPE ## a ## TRE; \ |
164 | break; |
165 | |
166 | switch (num) { |
167 | CASE_PIPExTRE(1); |
168 | CASE_PIPExTRE(2); |
169 | CASE_PIPExTRE(3); |
170 | CASE_PIPExTRE(4); |
171 | CASE_PIPExTRE(5); |
172 | CASE_PIPExTRE(B); |
173 | CASE_PIPExTRE(C); |
174 | CASE_PIPExTRE(D); |
175 | CASE_PIPExTRE(E); |
176 | CASE_PIPExTRE(F); |
177 | CASE_PIPExTRE(9); |
178 | CASE_PIPExTRE(A); |
179 | default: |
180 | dev_err(dev, "unknown pipe (%d)\n" , num); |
181 | return; |
182 | } |
183 | |
184 | __usbhsp_pipe_xxx_set(pipe, dcp_reg: 0, pipe_reg: reg, mask, val); |
185 | } |
186 | |
187 | /* |
188 | * PIPEBUF |
189 | */ |
190 | static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) |
191 | { |
192 | if (usbhs_pipe_is_dcp(pipe)) |
193 | return; |
194 | |
195 | __usbhsp_pipe_xxx_set(pipe, dcp_reg: 0, PIPEBUF, mask, val); |
196 | } |
197 | |
198 | /* |
199 | * DCPMAXP/PIPEMAXP |
200 | */ |
201 | static void usbhsp_pipe_maxp_set(struct usbhs_pipe *pipe, u16 mask, u16 val) |
202 | { |
203 | __usbhsp_pipe_xxx_set(pipe, DCPMAXP, PIPEMAXP, mask, val); |
204 | } |
205 | |
206 | /* |
207 | * pipe control functions |
208 | */ |
209 | static void usbhsp_pipe_select(struct usbhs_pipe *pipe) |
210 | { |
211 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
212 | |
213 | /* |
214 | * On pipe, this is necessary before |
215 | * accesses to below registers. |
216 | * |
217 | * PIPESEL : usbhsp_pipe_select |
218 | * PIPECFG : usbhsp_pipe_cfg_xxx |
219 | * PIPEBUF : usbhsp_pipe_buf_xxx |
220 | * PIPEMAXP : usbhsp_pipe_maxp_xxx |
221 | * PIPEPERI |
222 | */ |
223 | |
224 | /* |
225 | * if pipe is dcp, no pipe is selected. |
226 | * it is no problem, because dcp have its register |
227 | */ |
228 | usbhs_write(priv, PIPESEL, data: 0xF & usbhs_pipe_number(pipe)); |
229 | } |
230 | |
231 | static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) |
232 | { |
233 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
234 | int timeout = 1024; |
235 | u16 mask = usbhs_mod_is_host(priv) ? (CSSTS | PID_MASK) : PID_MASK; |
236 | |
237 | /* |
238 | * make sure.... |
239 | * |
240 | * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is |
241 | * specified by the CURPIPE bits. |
242 | * When changing the setting of this bit after changing |
243 | * the PID bits for the selected pipe from BUF to NAK, |
244 | * check that CSSTS = 0 and PBUSY = 0. |
245 | */ |
246 | |
247 | /* |
248 | * CURPIPE bit = 0 |
249 | * |
250 | * see also |
251 | * "Operation" |
252 | * - "Pipe Control" |
253 | * - "Pipe Control Registers Switching Procedure" |
254 | */ |
255 | usbhs_write(priv, CFIFOSEL, data: 0); |
256 | usbhs_pipe_disable(pipe); |
257 | |
258 | do { |
259 | if (!(usbhsp_pipectrl_get(pipe) & mask)) |
260 | return 0; |
261 | |
262 | udelay(10); |
263 | |
264 | } while (timeout--); |
265 | |
266 | return -EBUSY; |
267 | } |
268 | |
269 | int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe) |
270 | { |
271 | u16 val; |
272 | |
273 | val = usbhsp_pipectrl_get(pipe); |
274 | if (val & BSTS) |
275 | return 0; |
276 | |
277 | return -EBUSY; |
278 | } |
279 | |
280 | bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe) |
281 | { |
282 | u16 val; |
283 | |
284 | /* Do not support for DCP pipe */ |
285 | if (usbhs_pipe_is_dcp(pipe)) |
286 | return false; |
287 | |
288 | val = usbhsp_pipectrl_get(pipe); |
289 | if (val & INBUFM) |
290 | return true; |
291 | |
292 | return false; |
293 | } |
294 | |
295 | /* |
296 | * PID ctrl |
297 | */ |
298 | static void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe) |
299 | { |
300 | u16 pid = usbhsp_pipectrl_get(pipe); |
301 | |
302 | pid &= PID_MASK; |
303 | |
304 | /* |
305 | * see |
306 | * "Pipe n Control Register" - "PID" |
307 | */ |
308 | switch (pid) { |
309 | case PID_STALL11: |
310 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); |
311 | fallthrough; |
312 | case PID_STALL10: |
313 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); |
314 | } |
315 | } |
316 | |
317 | void usbhs_pipe_disable(struct usbhs_pipe *pipe) |
318 | { |
319 | int timeout = 1024; |
320 | u16 val; |
321 | |
322 | /* see "Pipe n Control Register" - "PID" */ |
323 | __usbhsp_pid_try_nak_if_stall(pipe); |
324 | |
325 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); |
326 | |
327 | do { |
328 | val = usbhsp_pipectrl_get(pipe); |
329 | val &= PBUSY; |
330 | if (!val) |
331 | break; |
332 | |
333 | udelay(10); |
334 | } while (timeout--); |
335 | } |
336 | |
337 | void usbhs_pipe_enable(struct usbhs_pipe *pipe) |
338 | { |
339 | /* see "Pipe n Control Register" - "PID" */ |
340 | __usbhsp_pid_try_nak_if_stall(pipe); |
341 | |
342 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_BUF); |
343 | } |
344 | |
345 | void usbhs_pipe_stall(struct usbhs_pipe *pipe) |
346 | { |
347 | u16 pid = usbhsp_pipectrl_get(pipe); |
348 | |
349 | pid &= PID_MASK; |
350 | |
351 | /* |
352 | * see |
353 | * "Pipe n Control Register" - "PID" |
354 | */ |
355 | switch (pid) { |
356 | case PID_NAK: |
357 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); |
358 | break; |
359 | case PID_BUF: |
360 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL11); |
361 | break; |
362 | } |
363 | } |
364 | |
365 | int usbhs_pipe_is_stall(struct usbhs_pipe *pipe) |
366 | { |
367 | u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK; |
368 | |
369 | return (int)(pid == PID_STALL10 || pid == PID_STALL11); |
370 | } |
371 | |
372 | void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len) |
373 | { |
374 | if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) |
375 | return; |
376 | |
377 | /* |
378 | * clear and disable transfer counter for IN/OUT pipe |
379 | */ |
380 | usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR); |
381 | |
382 | /* |
383 | * Only IN direction bulk pipe can use transfer count. |
384 | * Without using this function, |
385 | * received data will break if it was large data size. |
386 | * see PIPEnTRN/PIPEnTRE for detail |
387 | */ |
388 | if (usbhs_pipe_is_dir_in(pipe)) { |
389 | int maxp = usbhs_pipe_get_maxpacket(pipe); |
390 | |
391 | usbhsp_pipe_trn_set(pipe, mask: 0xffff, DIV_ROUND_UP(len, maxp)); |
392 | usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */ |
393 | } |
394 | } |
395 | |
396 | |
397 | /* |
398 | * pipe setup |
399 | */ |
400 | static int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host, |
401 | int dir_in, u16 *pipecfg) |
402 | { |
403 | u16 type = 0; |
404 | u16 bfre = 0; |
405 | u16 dblb = 0; |
406 | u16 cntmd = 0; |
407 | u16 dir = 0; |
408 | u16 epnum = 0; |
409 | u16 shtnak = 0; |
410 | static const u16 type_array[] = { |
411 | [USB_ENDPOINT_XFER_BULK] = TYPE_BULK, |
412 | [USB_ENDPOINT_XFER_INT] = TYPE_INT, |
413 | [USB_ENDPOINT_XFER_ISOC] = TYPE_ISO, |
414 | }; |
415 | |
416 | if (usbhs_pipe_is_dcp(pipe)) |
417 | return -EINVAL; |
418 | |
419 | /* |
420 | * PIPECFG |
421 | * |
422 | * see |
423 | * - "Register Descriptions" - "PIPECFG" register |
424 | * - "Features" - "Pipe configuration" |
425 | * - "Operation" - "Pipe Control" |
426 | */ |
427 | |
428 | /* TYPE */ |
429 | type = type_array[usbhs_pipe_type(pipe)]; |
430 | |
431 | /* BFRE */ |
432 | if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) || |
433 | usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) |
434 | bfre = 0; /* FIXME */ |
435 | |
436 | /* DBLB: see usbhs_pipe_config_update() */ |
437 | |
438 | /* CNTMD */ |
439 | if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) |
440 | cntmd = 0; /* FIXME */ |
441 | |
442 | /* DIR */ |
443 | if (dir_in) |
444 | usbhsp_flags_set(pipe, IS_DIR_HOST); |
445 | |
446 | if (!!is_host ^ !!dir_in) |
447 | dir |= DIR_OUT; |
448 | |
449 | if (!dir) |
450 | usbhsp_flags_set(pipe, IS_DIR_IN); |
451 | |
452 | /* SHTNAK */ |
453 | if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) && |
454 | !dir) |
455 | shtnak = SHTNAK; |
456 | |
457 | /* EPNUM */ |
458 | epnum = 0; /* see usbhs_pipe_config_update() */ |
459 | *pipecfg = type | |
460 | bfre | |
461 | dblb | |
462 | cntmd | |
463 | dir | |
464 | shtnak | |
465 | epnum; |
466 | return 0; |
467 | } |
468 | |
469 | static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe) |
470 | { |
471 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
472 | struct device *dev = usbhs_priv_to_dev(priv); |
473 | int pipe_num = usbhs_pipe_number(pipe); |
474 | u16 buff_size; |
475 | u16 bufnmb; |
476 | u16 bufnmb_cnt; |
477 | struct renesas_usbhs_driver_pipe_config *pipe_config = |
478 | usbhsp_get_pipe_config(priv, pipe_num); |
479 | |
480 | /* |
481 | * PIPEBUF |
482 | * |
483 | * see |
484 | * - "Register Descriptions" - "PIPEBUF" register |
485 | * - "Features" - "Pipe configuration" |
486 | * - "Operation" - "FIFO Buffer Memory" |
487 | * - "Operation" - "Pipe Control" |
488 | */ |
489 | buff_size = pipe_config->bufsize; |
490 | bufnmb = pipe_config->bufnum; |
491 | |
492 | /* change buff_size to register value */ |
493 | bufnmb_cnt = (buff_size / 64) - 1; |
494 | |
495 | dev_dbg(dev, "pipe : %d : buff_size 0x%x: bufnmb 0x%x\n" , |
496 | pipe_num, buff_size, bufnmb); |
497 | |
498 | return (0x1f & bufnmb_cnt) << 10 | |
499 | (0xff & bufnmb) << 0; |
500 | } |
501 | |
502 | void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, |
503 | u16 epnum, u16 maxp) |
504 | { |
505 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
506 | int pipe_num = usbhs_pipe_number(pipe); |
507 | struct renesas_usbhs_driver_pipe_config *pipe_config = |
508 | usbhsp_get_pipe_config(priv, pipe_num); |
509 | u16 dblb = pipe_config->double_buf ? DBLB : 0; |
510 | |
511 | if (devsel > 0xA) { |
512 | struct device *dev = usbhs_priv_to_dev(priv); |
513 | |
514 | dev_err(dev, "devsel error %d\n" , devsel); |
515 | |
516 | devsel = 0; |
517 | } |
518 | |
519 | usbhsp_pipe_barrier(pipe); |
520 | |
521 | pipe->maxp = maxp; |
522 | |
523 | usbhsp_pipe_select(pipe); |
524 | usbhsp_pipe_maxp_set(pipe, mask: 0xFFFF, |
525 | val: (devsel << 12) | |
526 | maxp); |
527 | |
528 | if (!usbhs_pipe_is_dcp(pipe)) |
529 | usbhsp_pipe_cfg_set(pipe, mask: 0x000F | DBLB, val: epnum | dblb); |
530 | } |
531 | |
532 | /* |
533 | * pipe control |
534 | */ |
535 | int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe) |
536 | { |
537 | /* |
538 | * see |
539 | * usbhs_pipe_config_update() |
540 | * usbhs_dcp_malloc() |
541 | */ |
542 | return pipe->maxp; |
543 | } |
544 | |
545 | int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe) |
546 | { |
547 | return usbhsp_flags_has(pipe, IS_DIR_IN); |
548 | } |
549 | |
550 | int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe) |
551 | { |
552 | return usbhsp_flags_has(pipe, IS_DIR_HOST); |
553 | } |
554 | |
555 | int usbhs_pipe_is_running(struct usbhs_pipe *pipe) |
556 | { |
557 | return usbhsp_flags_has(pipe, IS_RUNNING); |
558 | } |
559 | |
560 | void usbhs_pipe_running(struct usbhs_pipe *pipe, int running) |
561 | { |
562 | if (running) |
563 | usbhsp_flags_set(pipe, IS_RUNNING); |
564 | else |
565 | usbhsp_flags_clr(pipe, IS_RUNNING); |
566 | } |
567 | |
568 | void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence) |
569 | { |
570 | u16 mask = (SQCLR | SQSET); |
571 | u16 val; |
572 | |
573 | /* |
574 | * sequence |
575 | * 0 : data0 |
576 | * 1 : data1 |
577 | * -1 : no change |
578 | */ |
579 | switch (sequence) { |
580 | case 0: |
581 | val = SQCLR; |
582 | break; |
583 | case 1: |
584 | val = SQSET; |
585 | break; |
586 | default: |
587 | return; |
588 | } |
589 | |
590 | usbhsp_pipectrl_set(pipe, mask, val); |
591 | } |
592 | |
593 | static int usbhs_pipe_get_data_sequence(struct usbhs_pipe *pipe) |
594 | { |
595 | return !!(usbhsp_pipectrl_get(pipe) & SQMON); |
596 | } |
597 | |
598 | void usbhs_pipe_clear(struct usbhs_pipe *pipe) |
599 | { |
600 | if (usbhs_pipe_is_dcp(pipe)) { |
601 | usbhs_fifo_clear_dcp(pipe); |
602 | } else { |
603 | usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); |
604 | usbhsp_pipectrl_set(pipe, ACLRM, val: 0); |
605 | } |
606 | } |
607 | |
608 | /* Should call usbhsp_pipe_select() before */ |
609 | void usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe, |
610 | int needs_bfre, int bfre_enable) |
611 | { |
612 | int sequence; |
613 | |
614 | usbhsp_pipe_select(pipe); |
615 | sequence = usbhs_pipe_get_data_sequence(pipe); |
616 | if (needs_bfre) |
617 | usbhsp_pipe_cfg_set(pipe, BFRE, val: bfre_enable ? BFRE : 0); |
618 | usbhs_pipe_clear(pipe); |
619 | usbhs_pipe_data_sequence(pipe, sequence); |
620 | } |
621 | |
622 | void usbhs_pipe_config_change_bfre(struct usbhs_pipe *pipe, int enable) |
623 | { |
624 | if (usbhs_pipe_is_dcp(pipe)) |
625 | return; |
626 | |
627 | usbhsp_pipe_select(pipe); |
628 | /* check if the driver needs to change the BFRE value */ |
629 | if (!(enable ^ !!(usbhsp_pipe_cfg_get(pipe) & BFRE))) |
630 | return; |
631 | |
632 | usbhs_pipe_clear_without_sequence(pipe, needs_bfre: 1, bfre_enable: enable); |
633 | } |
634 | |
635 | static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) |
636 | { |
637 | struct usbhs_pipe *pos, *pipe; |
638 | int i; |
639 | |
640 | /* |
641 | * find target pipe |
642 | */ |
643 | pipe = NULL; |
644 | usbhs_for_each_pipe_with_dcp(pos, priv, i) { |
645 | if (!usbhs_pipe_type_is(pos, type)) |
646 | continue; |
647 | if (usbhsp_flags_has(pos, IS_USED)) |
648 | continue; |
649 | |
650 | pipe = pos; |
651 | break; |
652 | } |
653 | |
654 | if (!pipe) |
655 | return NULL; |
656 | |
657 | /* |
658 | * initialize pipe flags |
659 | */ |
660 | usbhsp_flags_init(pipe); |
661 | usbhsp_flags_set(pipe, IS_USED); |
662 | |
663 | return pipe; |
664 | } |
665 | |
666 | static void usbhsp_put_pipe(struct usbhs_pipe *pipe) |
667 | { |
668 | usbhsp_flags_init(pipe); |
669 | } |
670 | |
671 | void usbhs_pipe_init(struct usbhs_priv *priv, |
672 | int (*dma_map_ctrl)(struct device *dma_dev, |
673 | struct usbhs_pkt *pkt, int map)) |
674 | { |
675 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); |
676 | struct usbhs_pipe *pipe; |
677 | int i; |
678 | |
679 | usbhs_for_each_pipe_with_dcp(pipe, priv, i) { |
680 | usbhsp_flags_init(pipe); |
681 | pipe->fifo = NULL; |
682 | pipe->mod_private = NULL; |
683 | INIT_LIST_HEAD(list: &pipe->list); |
684 | |
685 | /* pipe force init */ |
686 | usbhs_pipe_clear(pipe); |
687 | } |
688 | |
689 | info->dma_map_ctrl = dma_map_ctrl; |
690 | } |
691 | |
692 | struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, |
693 | int endpoint_type, |
694 | int dir_in) |
695 | { |
696 | struct device *dev = usbhs_priv_to_dev(priv); |
697 | struct usbhs_pipe *pipe; |
698 | int is_host = usbhs_mod_is_host(priv); |
699 | int ret; |
700 | u16 pipecfg, pipebuf; |
701 | |
702 | pipe = usbhsp_get_pipe(priv, type: endpoint_type); |
703 | if (!pipe) { |
704 | dev_err(dev, "can't get pipe (%s)\n" , |
705 | usbhsp_pipe_name[endpoint_type]); |
706 | return NULL; |
707 | } |
708 | |
709 | INIT_LIST_HEAD(list: &pipe->list); |
710 | |
711 | usbhs_pipe_disable(pipe); |
712 | |
713 | /* make sure pipe is not busy */ |
714 | ret = usbhsp_pipe_barrier(pipe); |
715 | if (ret < 0) { |
716 | dev_err(dev, "pipe setup failed %d\n" , usbhs_pipe_number(pipe)); |
717 | return NULL; |
718 | } |
719 | |
720 | if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, pipecfg: &pipecfg)) { |
721 | dev_err(dev, "can't setup pipe\n" ); |
722 | return NULL; |
723 | } |
724 | |
725 | pipebuf = usbhsp_setup_pipebuff(pipe); |
726 | |
727 | usbhsp_pipe_select(pipe); |
728 | usbhsp_pipe_cfg_set(pipe, mask: 0xFFFF, val: pipecfg); |
729 | usbhsp_pipe_buf_set(pipe, mask: 0xFFFF, val: pipebuf); |
730 | usbhs_pipe_clear(pipe); |
731 | |
732 | usbhs_pipe_sequence_data0(pipe); |
733 | |
734 | dev_dbg(dev, "enable pipe %d : %s (%s)\n" , |
735 | usbhs_pipe_number(pipe), |
736 | usbhs_pipe_name(pipe), |
737 | usbhs_pipe_is_dir_in(pipe) ? "in" : "out" ); |
738 | |
739 | /* |
740 | * epnum / maxp are still not set to this pipe. |
741 | * call usbhs_pipe_config_update() after this function !! |
742 | */ |
743 | |
744 | return pipe; |
745 | } |
746 | |
747 | void usbhs_pipe_free(struct usbhs_pipe *pipe) |
748 | { |
749 | usbhsp_pipe_select(pipe); |
750 | usbhsp_pipe_cfg_set(pipe, mask: 0xFFFF, val: 0); |
751 | usbhsp_put_pipe(pipe); |
752 | } |
753 | |
754 | void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) |
755 | { |
756 | if (pipe->fifo) |
757 | pipe->fifo->pipe = NULL; |
758 | |
759 | pipe->fifo = fifo; |
760 | |
761 | if (fifo) |
762 | fifo->pipe = pipe; |
763 | } |
764 | |
765 | |
766 | /* |
767 | * dcp control |
768 | */ |
769 | struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv) |
770 | { |
771 | struct usbhs_pipe *pipe; |
772 | |
773 | pipe = usbhsp_get_pipe(priv, USB_ENDPOINT_XFER_CONTROL); |
774 | if (!pipe) |
775 | return NULL; |
776 | |
777 | INIT_LIST_HEAD(list: &pipe->list); |
778 | |
779 | /* |
780 | * call usbhs_pipe_config_update() after this function !! |
781 | */ |
782 | |
783 | return pipe; |
784 | } |
785 | |
786 | void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe) |
787 | { |
788 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
789 | |
790 | WARN_ON(!usbhs_pipe_is_dcp(pipe)); |
791 | |
792 | usbhs_pipe_enable(pipe); |
793 | |
794 | if (!usbhs_mod_is_host(priv)) /* funconly */ |
795 | usbhsp_pipectrl_set(pipe, CCPL, CCPL); |
796 | } |
797 | |
798 | void usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out) |
799 | { |
800 | usbhsp_pipe_cfg_set(pipe, DIR_OUT, |
801 | val: dir_out ? DIR_OUT : 0); |
802 | } |
803 | |
804 | /* |
805 | * pipe module function |
806 | */ |
807 | int usbhs_pipe_probe(struct usbhs_priv *priv) |
808 | { |
809 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); |
810 | struct usbhs_pipe *pipe; |
811 | struct device *dev = usbhs_priv_to_dev(priv); |
812 | struct renesas_usbhs_driver_pipe_config *pipe_configs = |
813 | usbhs_get_dparam(priv, pipe_configs); |
814 | int pipe_size = usbhs_get_dparam(priv, pipe_size); |
815 | int i; |
816 | |
817 | /* This driver expects 1st pipe is DCP */ |
818 | if (pipe_configs[0].type != USB_ENDPOINT_XFER_CONTROL) { |
819 | dev_err(dev, "1st PIPE is not DCP\n" ); |
820 | return -EINVAL; |
821 | } |
822 | |
823 | info->pipe = kcalloc(n: pipe_size, size: sizeof(struct usbhs_pipe), |
824 | GFP_KERNEL); |
825 | if (!info->pipe) |
826 | return -ENOMEM; |
827 | |
828 | info->size = pipe_size; |
829 | |
830 | /* |
831 | * init pipe |
832 | */ |
833 | usbhs_for_each_pipe_with_dcp(pipe, priv, i) { |
834 | pipe->priv = priv; |
835 | |
836 | usbhs_pipe_type(pipe) = |
837 | pipe_configs[i].type & USB_ENDPOINT_XFERTYPE_MASK; |
838 | |
839 | dev_dbg(dev, "pipe %x\t: %s\n" , |
840 | i, usbhsp_pipe_name[pipe_configs[i].type]); |
841 | } |
842 | |
843 | return 0; |
844 | } |
845 | |
846 | void usbhs_pipe_remove(struct usbhs_priv *priv) |
847 | { |
848 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); |
849 | |
850 | kfree(objp: info->pipe); |
851 | } |
852 | |