Commit | Line | Data |
---|---|---|
f1407d5c 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> | |
f1407d5c KM |
18 | #include <linux/slab.h> |
19 | #include "./common.h" | |
20 | #include "./pipe.h" | |
21 | ||
22 | /* | |
23 | * macros | |
24 | */ | |
f1407d5c KM |
25 | #define usbhsp_addr_offset(p) ((usbhs_pipe_number(p) - 1) * 2) |
26 | ||
f1407d5c KM |
27 | #define usbhsp_flags_set(p, f) ((p)->flags |= USBHS_PIPE_FLAGS_##f) |
28 | #define usbhsp_flags_clr(p, f) ((p)->flags &= ~USBHS_PIPE_FLAGS_##f) | |
29 | #define usbhsp_flags_has(p, f) ((p)->flags & USBHS_PIPE_FLAGS_##f) | |
30 | #define usbhsp_flags_init(p) do {(p)->flags = 0; } while (0) | |
31 | ||
32 | #define usbhsp_type(p) ((p)->pipe_type) | |
33 | #define usbhsp_type_is(p, t) ((p)->pipe_type == t) | |
34 | ||
35 | /* | |
36 | * for debug | |
37 | */ | |
38 | static char *usbhsp_pipe_name[] = { | |
39 | [USB_ENDPOINT_XFER_CONTROL] = "DCP", | |
40 | [USB_ENDPOINT_XFER_BULK] = "BULK", | |
41 | [USB_ENDPOINT_XFER_INT] = "INT", | |
42 | [USB_ENDPOINT_XFER_ISOC] = "ISO", | |
43 | }; | |
44 | ||
45 | /* | |
46 | * usb request functions | |
47 | */ | |
48 | void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) | |
49 | { | |
50 | u16 val; | |
51 | ||
52 | val = usbhs_read(priv, USBREQ); | |
53 | req->bRequest = (val >> 8) & 0xFF; | |
54 | req->bRequestType = (val >> 0) & 0xFF; | |
55 | ||
56 | req->wValue = usbhs_read(priv, USBVAL); | |
57 | req->wIndex = usbhs_read(priv, USBINDX); | |
58 | req->wLength = usbhs_read(priv, USBLENG); | |
59 | } | |
60 | ||
61 | void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) | |
62 | { | |
63 | usbhs_write(priv, USBREQ, (req->bRequest << 8) | req->bRequestType); | |
64 | usbhs_write(priv, USBVAL, req->wValue); | |
65 | usbhs_write(priv, USBINDX, req->wIndex); | |
66 | usbhs_write(priv, USBLENG, req->wLength); | |
67 | } | |
68 | ||
69 | /* | |
70 | * DCPCTR/PIPEnCTR functions | |
71 | */ | |
72 | static void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val) | |
73 | { | |
e8d548d5 | 74 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
f1407d5c KM |
75 | int offset = usbhsp_addr_offset(pipe); |
76 | ||
e8d548d5 | 77 | if (usbhs_pipe_is_dcp(pipe)) |
f1407d5c KM |
78 | usbhs_bset(priv, DCPCTR, mask, val); |
79 | else | |
80 | usbhs_bset(priv, PIPEnCTR + offset, mask, val); | |
81 | } | |
82 | ||
83 | static u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe) | |
84 | { | |
e8d548d5 | 85 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
f1407d5c KM |
86 | int offset = usbhsp_addr_offset(pipe); |
87 | ||
e8d548d5 | 88 | if (usbhs_pipe_is_dcp(pipe)) |
f1407d5c KM |
89 | return usbhs_read(priv, DCPCTR); |
90 | else | |
91 | return usbhs_read(priv, PIPEnCTR + offset); | |
92 | } | |
93 | ||
94 | /* | |
95 | * DCP/PIPE functions | |
96 | */ | |
97 | static void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe, | |
98 | u16 dcp_reg, u16 pipe_reg, | |
99 | u16 mask, u16 val) | |
100 | { | |
e8d548d5 | 101 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
f1407d5c | 102 | |
e8d548d5 | 103 | if (usbhs_pipe_is_dcp(pipe)) |
f1407d5c KM |
104 | usbhs_bset(priv, dcp_reg, mask, val); |
105 | else | |
106 | usbhs_bset(priv, pipe_reg, mask, val); | |
107 | } | |
108 | ||
f1407d5c KM |
109 | /* |
110 | * DCPCFG/PIPECFG functions | |
111 | */ | |
112 | static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val) | |
113 | { | |
114 | __usbhsp_pipe_xxx_set(pipe, DCPCFG, PIPECFG, mask, val); | |
115 | } | |
116 | ||
117 | /* | |
118 | * PIPEBUF | |
119 | */ | |
120 | static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) | |
121 | { | |
e8d548d5 | 122 | if (usbhs_pipe_is_dcp(pipe)) |
f1407d5c KM |
123 | return; |
124 | ||
125 | __usbhsp_pipe_xxx_set(pipe, 0, PIPEBUF, mask, val); | |
126 | } | |
127 | ||
128 | /* | |
129 | * DCPMAXP/PIPEMAXP | |
130 | */ | |
131 | static void usbhsp_pipe_maxp_set(struct usbhs_pipe *pipe, u16 mask, u16 val) | |
132 | { | |
133 | __usbhsp_pipe_xxx_set(pipe, DCPMAXP, PIPEMAXP, mask, val); | |
134 | } | |
135 | ||
f1407d5c KM |
136 | /* |
137 | * pipe control functions | |
138 | */ | |
139 | static void usbhsp_pipe_select(struct usbhs_pipe *pipe) | |
140 | { | |
e8d548d5 | 141 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
f1407d5c KM |
142 | |
143 | /* | |
144 | * On pipe, this is necessary before | |
145 | * accesses to below registers. | |
146 | * | |
147 | * PIPESEL : usbhsp_pipe_select | |
148 | * PIPECFG : usbhsp_pipe_cfg_xxx | |
149 | * PIPEBUF : usbhsp_pipe_buf_xxx | |
150 | * PIPEMAXP : usbhsp_pipe_maxp_xxx | |
151 | * PIPEPERI | |
152 | */ | |
153 | ||
154 | /* | |
155 | * if pipe is dcp, no pipe is selected. | |
156 | * it is no problem, because dcp have its register | |
157 | */ | |
158 | usbhs_write(priv, PIPESEL, 0xF & usbhs_pipe_number(pipe)); | |
159 | } | |
160 | ||
161 | static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) | |
162 | { | |
e8d548d5 | 163 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
f1407d5c KM |
164 | int timeout = 1024; |
165 | u16 val; | |
166 | ||
167 | /* | |
168 | * make sure.... | |
169 | * | |
170 | * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is | |
171 | * specified by the CURPIPE bits. | |
172 | * When changing the setting of this bit after changing | |
173 | * the PID bits for the selected pipe from BUF to NAK, | |
174 | * check that CSSTS = 0 and PBUSY = 0. | |
175 | */ | |
176 | ||
177 | /* | |
178 | * CURPIPE bit = 0 | |
179 | * | |
180 | * see also | |
181 | * "Operation" | |
182 | * - "Pipe Control" | |
183 | * - "Pipe Control Registers Switching Procedure" | |
184 | */ | |
185 | usbhs_write(priv, CFIFOSEL, 0); | |
e8d548d5 | 186 | usbhs_pipe_disable(pipe); |
f1407d5c KM |
187 | |
188 | do { | |
189 | val = usbhsp_pipectrl_get(pipe); | |
190 | val &= CSSTS | PID_MASK; | |
191 | if (!val) | |
192 | return 0; | |
193 | ||
194 | udelay(10); | |
195 | ||
196 | } while (timeout--); | |
197 | ||
f1407d5c KM |
198 | return -EBUSY; |
199 | } | |
200 | ||
e8d548d5 | 201 | int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe) |
f1407d5c KM |
202 | { |
203 | u16 val; | |
204 | ||
205 | val = usbhsp_pipectrl_get(pipe); | |
206 | if (val & BSTS) | |
207 | return 0; | |
208 | ||
209 | return -EBUSY; | |
210 | } | |
211 | ||
212 | /* | |
213 | * PID ctrl | |
214 | */ | |
215 | static void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe) | |
216 | { | |
217 | u16 pid = usbhsp_pipectrl_get(pipe); | |
218 | ||
219 | pid &= PID_MASK; | |
220 | ||
221 | /* | |
222 | * see | |
223 | * "Pipe n Control Register" - "PID" | |
224 | */ | |
225 | switch (pid) { | |
226 | case PID_STALL11: | |
227 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); | |
228 | /* fall-through */ | |
229 | case PID_STALL10: | |
230 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); | |
231 | } | |
232 | } | |
233 | ||
e8d548d5 | 234 | void usbhs_pipe_disable(struct usbhs_pipe *pipe) |
f1407d5c | 235 | { |
c786e09c KM |
236 | int timeout = 1024; |
237 | u16 val; | |
238 | ||
f1407d5c KM |
239 | /* see "Pipe n Control Register" - "PID" */ |
240 | __usbhsp_pid_try_nak_if_stall(pipe); | |
241 | ||
242 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); | |
c786e09c KM |
243 | |
244 | do { | |
245 | val = usbhsp_pipectrl_get(pipe); | |
246 | val &= PBUSY; | |
247 | if (!val) | |
248 | break; | |
249 | ||
250 | udelay(10); | |
251 | } while (timeout--); | |
f1407d5c KM |
252 | } |
253 | ||
e8d548d5 | 254 | void usbhs_pipe_enable(struct usbhs_pipe *pipe) |
f1407d5c KM |
255 | { |
256 | /* see "Pipe n Control Register" - "PID" */ | |
257 | __usbhsp_pid_try_nak_if_stall(pipe); | |
258 | ||
259 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_BUF); | |
260 | } | |
261 | ||
e8d548d5 | 262 | void usbhs_pipe_stall(struct usbhs_pipe *pipe) |
f1407d5c KM |
263 | { |
264 | u16 pid = usbhsp_pipectrl_get(pipe); | |
265 | ||
266 | pid &= PID_MASK; | |
267 | ||
268 | /* | |
269 | * see | |
270 | * "Pipe n Control Register" - "PID" | |
271 | */ | |
272 | switch (pid) { | |
273 | case PID_NAK: | |
274 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); | |
275 | break; | |
276 | case PID_BUF: | |
277 | usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL11); | |
278 | break; | |
279 | } | |
280 | } | |
281 | ||
f1407d5c KM |
282 | /* |
283 | * pipe setup | |
284 | */ | |
285 | static int usbhsp_possible_double_buffer(struct usbhs_pipe *pipe) | |
286 | { | |
287 | /* | |
288 | * only ISO / BULK pipe can use double buffer | |
289 | */ | |
290 | if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK) || | |
291 | usbhsp_type_is(pipe, USB_ENDPOINT_XFER_ISOC)) | |
292 | return 1; | |
293 | ||
294 | return 0; | |
295 | } | |
296 | ||
297 | static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, | |
f5aa889f KM |
298 | int is_host, |
299 | int dir_in) | |
f1407d5c KM |
300 | { |
301 | u16 type = 0; | |
302 | u16 bfre = 0; | |
303 | u16 dblb = 0; | |
304 | u16 cntmd = 0; | |
305 | u16 dir = 0; | |
306 | u16 epnum = 0; | |
307 | u16 shtnak = 0; | |
308 | u16 type_array[] = { | |
309 | [USB_ENDPOINT_XFER_BULK] = TYPE_BULK, | |
310 | [USB_ENDPOINT_XFER_INT] = TYPE_INT, | |
311 | [USB_ENDPOINT_XFER_ISOC] = TYPE_ISO, | |
312 | }; | |
313 | int is_double = usbhsp_possible_double_buffer(pipe); | |
314 | ||
e8d548d5 | 315 | if (usbhs_pipe_is_dcp(pipe)) |
f1407d5c KM |
316 | return -EINVAL; |
317 | ||
318 | /* | |
319 | * PIPECFG | |
320 | * | |
321 | * see | |
322 | * - "Register Descriptions" - "PIPECFG" register | |
323 | * - "Features" - "Pipe configuration" | |
324 | * - "Operation" - "Pipe Control" | |
325 | */ | |
326 | ||
327 | /* TYPE */ | |
328 | type = type_array[usbhsp_type(pipe)]; | |
329 | ||
330 | /* BFRE */ | |
331 | if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_ISOC) || | |
332 | usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK)) | |
333 | bfre = 0; /* FIXME */ | |
334 | ||
335 | /* DBLB */ | |
336 | if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_ISOC) || | |
337 | usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK)) | |
338 | dblb = (is_double) ? DBLB : 0; | |
339 | ||
340 | /* CNTMD */ | |
341 | if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK)) | |
342 | cntmd = 0; /* FIXME */ | |
343 | ||
344 | /* DIR */ | |
f5aa889f | 345 | if (dir_in) |
ad6f2a8b | 346 | usbhsp_flags_set(pipe, IS_DIR_HOST); |
f1407d5c | 347 | |
f5aa889f KM |
348 | if ((is_host && !dir_in) || |
349 | (!is_host && dir_in)) | |
f1407d5c KM |
350 | dir |= DIR_OUT; |
351 | ||
ad6f2a8b KM |
352 | if (!dir) |
353 | usbhsp_flags_set(pipe, IS_DIR_IN); | |
354 | ||
f1407d5c KM |
355 | /* SHTNAK */ |
356 | if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK) && | |
357 | !dir) | |
358 | shtnak = SHTNAK; | |
359 | ||
360 | /* EPNUM */ | |
f5aa889f | 361 | epnum = 0; /* see usbhs_pipe_config_update() */ |
f1407d5c KM |
362 | |
363 | return type | | |
364 | bfre | | |
365 | dblb | | |
366 | cntmd | | |
367 | dir | | |
368 | shtnak | | |
369 | epnum; | |
370 | } | |
371 | ||
f5aa889f | 372 | static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe) |
f1407d5c | 373 | { |
e8d548d5 KM |
374 | struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); |
375 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); | |
f1407d5c KM |
376 | struct device *dev = usbhs_priv_to_dev(priv); |
377 | int pipe_num = usbhs_pipe_number(pipe); | |
378 | int is_double = usbhsp_possible_double_buffer(pipe); | |
379 | u16 buff_size; | |
380 | u16 bufnmb; | |
381 | u16 bufnmb_cnt; | |
382 | ||
383 | /* | |
384 | * PIPEBUF | |
385 | * | |
386 | * see | |
387 | * - "Register Descriptions" - "PIPEBUF" register | |
388 | * - "Features" - "Pipe configuration" | |
389 | * - "Operation" - "FIFO Buffer Memory" | |
390 | * - "Operation" - "Pipe Control" | |
391 | * | |
392 | * ex) if pipe6 - pipe9 are USB_ENDPOINT_XFER_INT (SH7724) | |
393 | * | |
394 | * BUFNMB: PIPE | |
395 | * 0: pipe0 (DCP 256byte) | |
396 | * 1: - | |
397 | * 2: - | |
398 | * 3: - | |
399 | * 4: pipe6 (INT 64byte) | |
400 | * 5: pipe7 (INT 64byte) | |
401 | * 6: pipe8 (INT 64byte) | |
402 | * 7: pipe9 (INT 64byte) | |
403 | * 8 - xx: free (for BULK, ISOC) | |
404 | */ | |
405 | ||
406 | /* | |
407 | * FIXME | |
408 | * | |
409 | * it doesn't have good buffer allocator | |
410 | * | |
411 | * DCP : 256 byte | |
412 | * BULK: 512 byte | |
413 | * INT : 64 byte | |
414 | * ISOC: 512 byte | |
415 | */ | |
416 | if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_CONTROL)) | |
417 | buff_size = 256; | |
418 | else if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_INT)) | |
419 | buff_size = 64; | |
420 | else | |
421 | buff_size = 512; | |
422 | ||
423 | /* change buff_size to register value */ | |
424 | bufnmb_cnt = (buff_size / 64) - 1; | |
425 | ||
426 | /* BUFNMB has been reserved for INT pipe | |
427 | * see above */ | |
428 | if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_INT)) { | |
429 | bufnmb = pipe_num - 2; | |
430 | } else { | |
431 | bufnmb = info->bufnmb_last; | |
432 | info->bufnmb_last += bufnmb_cnt + 1; | |
433 | ||
434 | /* | |
435 | * double buffer | |
436 | */ | |
437 | if (is_double) | |
438 | info->bufnmb_last += bufnmb_cnt + 1; | |
439 | } | |
440 | ||
441 | dev_dbg(dev, "pipe : %d : buff_size 0x%x: bufnmb 0x%x\n", | |
442 | pipe_num, buff_size, bufnmb); | |
443 | ||
444 | return (0x1f & bufnmb_cnt) << 10 | | |
445 | (0xff & bufnmb) << 0; | |
446 | } | |
447 | ||
f5aa889f KM |
448 | void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 epnum, u16 maxp) |
449 | { | |
450 | usbhsp_pipe_barrier(pipe); | |
451 | ||
7fd097e7 KM |
452 | pipe->maxp = maxp; |
453 | ||
f5aa889f KM |
454 | usbhsp_pipe_select(pipe); |
455 | usbhsp_pipe_maxp_set(pipe, 0xFFFF, maxp); | |
456 | ||
457 | if (!usbhs_pipe_is_dcp(pipe)) | |
458 | usbhsp_pipe_cfg_set(pipe, 0x000F, epnum); | |
459 | } | |
460 | ||
f1407d5c KM |
461 | /* |
462 | * pipe control | |
463 | */ | |
464 | int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe) | |
465 | { | |
7fd097e7 KM |
466 | /* |
467 | * see | |
468 | * usbhs_pipe_config_update() | |
469 | * usbhs_dcp_malloc() | |
470 | */ | |
471 | return pipe->maxp; | |
f1407d5c KM |
472 | } |
473 | ||
474 | int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe) | |
475 | { | |
476 | return usbhsp_flags_has(pipe, IS_DIR_IN); | |
477 | } | |
478 | ||
ad6f2a8b KM |
479 | int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe) |
480 | { | |
481 | return usbhsp_flags_has(pipe, IS_DIR_HOST); | |
482 | } | |
483 | ||
f1407d5c KM |
484 | void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe) |
485 | { | |
486 | usbhsp_pipectrl_set(pipe, SQCLR, SQCLR); | |
487 | } | |
488 | ||
08e6c611 KM |
489 | void usbhs_pipe_clear(struct usbhs_pipe *pipe) |
490 | { | |
491 | usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); | |
492 | usbhsp_pipectrl_set(pipe, ACLRM, 0); | |
493 | } | |
494 | ||
f1407d5c KM |
495 | static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) |
496 | { | |
497 | struct usbhs_pipe *pos, *pipe; | |
498 | int i; | |
499 | ||
500 | /* | |
501 | * find target pipe | |
502 | */ | |
503 | pipe = NULL; | |
504 | usbhs_for_each_pipe_with_dcp(pos, priv, i) { | |
505 | if (!usbhsp_type_is(pos, type)) | |
506 | continue; | |
507 | if (usbhsp_flags_has(pos, IS_USED)) | |
508 | continue; | |
509 | ||
510 | pipe = pos; | |
511 | break; | |
512 | } | |
513 | ||
514 | if (!pipe) | |
515 | return NULL; | |
516 | ||
517 | /* | |
518 | * initialize pipe flags | |
519 | */ | |
520 | usbhsp_flags_init(pipe); | |
521 | usbhsp_flags_set(pipe, IS_USED); | |
522 | ||
523 | return pipe; | |
524 | } | |
525 | ||
4bd04811 | 526 | void usbhs_pipe_init(struct usbhs_priv *priv, |
e73a9891 KM |
527 | void (*done)(struct usbhs_pkt *pkt), |
528 | int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)) | |
f1407d5c | 529 | { |
e8d548d5 | 530 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); |
dad67397 | 531 | struct device *dev = usbhs_priv_to_dev(priv); |
f1407d5c KM |
532 | struct usbhs_pipe *pipe; |
533 | int i; | |
534 | ||
dad67397 KM |
535 | if (!done) { |
536 | dev_err(dev, "no done function\n"); | |
537 | return; | |
538 | } | |
539 | ||
f1407d5c KM |
540 | /* |
541 | * FIXME | |
542 | * | |
543 | * driver needs good allocator. | |
544 | * | |
545 | * find first free buffer area (BULK, ISOC) | |
546 | * (DCP, INT area is fixed) | |
547 | * | |
548 | * buffer number 0 - 3 have been reserved for DCP | |
549 | * see | |
550 | * usbhsp_to_bufnmb | |
551 | */ | |
552 | info->bufnmb_last = 4; | |
553 | usbhs_for_each_pipe_with_dcp(pipe, priv, i) { | |
554 | if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_INT)) | |
555 | info->bufnmb_last++; | |
556 | ||
557 | usbhsp_flags_init(pipe); | |
d77e3f4e | 558 | pipe->fifo = NULL; |
f1407d5c | 559 | pipe->mod_private = NULL; |
6acb95d4 | 560 | INIT_LIST_HEAD(&pipe->list); |
45e13e6e | 561 | |
e8d548d5 | 562 | /* pipe force init */ |
08e6c611 | 563 | usbhs_pipe_clear(pipe); |
f1407d5c | 564 | } |
4bd04811 | 565 | |
dad67397 | 566 | info->done = done; |
e73a9891 | 567 | info->dma_map_ctrl = dma_map_ctrl; |
f1407d5c KM |
568 | } |
569 | ||
570 | struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, | |
f5aa889f KM |
571 | int endpoint_type, |
572 | int dir_in) | |
f1407d5c KM |
573 | { |
574 | struct device *dev = usbhs_priv_to_dev(priv); | |
575 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); | |
576 | struct usbhs_pipe *pipe; | |
577 | int is_host = usbhs_mod_is_host(priv, mod); | |
578 | int ret; | |
f5aa889f | 579 | u16 pipecfg, pipebuf; |
f1407d5c | 580 | |
f5aa889f | 581 | pipe = usbhsp_get_pipe(priv, endpoint_type); |
f429ea3f KM |
582 | if (!pipe) { |
583 | dev_err(dev, "can't get pipe (%s)\n", | |
f5aa889f | 584 | usbhsp_pipe_name[endpoint_type]); |
f1407d5c | 585 | return NULL; |
f429ea3f | 586 | } |
f1407d5c | 587 | |
6acb95d4 KM |
588 | INIT_LIST_HEAD(&pipe->list); |
589 | ||
e8d548d5 | 590 | usbhs_pipe_disable(pipe); |
f1407d5c KM |
591 | |
592 | /* make sure pipe is not busy */ | |
593 | ret = usbhsp_pipe_barrier(pipe); | |
594 | if (ret < 0) { | |
595 | dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe)); | |
596 | return NULL; | |
597 | } | |
598 | ||
f5aa889f KM |
599 | pipecfg = usbhsp_setup_pipecfg(pipe, is_host, dir_in); |
600 | pipebuf = usbhsp_setup_pipebuff(pipe); | |
f1407d5c | 601 | |
f1407d5c KM |
602 | usbhsp_pipe_select(pipe); |
603 | usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg); | |
604 | usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf); | |
f1407d5c KM |
605 | |
606 | usbhs_pipe_clear_sequence(pipe); | |
607 | ||
608 | dev_dbg(dev, "enable pipe %d : %s (%s)\n", | |
609 | usbhs_pipe_number(pipe), | |
f5aa889f | 610 | usbhsp_pipe_name[endpoint_type], |
f1407d5c KM |
611 | usbhs_pipe_is_dir_in(pipe) ? "in" : "out"); |
612 | ||
f5aa889f KM |
613 | /* |
614 | * epnum / maxp are still not set to this pipe. | |
615 | * call usbhs_pipe_config_update() after this function !! | |
616 | */ | |
617 | ||
f1407d5c KM |
618 | return pipe; |
619 | } | |
620 | ||
d77e3f4e KM |
621 | void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) |
622 | { | |
623 | if (pipe->fifo) | |
624 | pipe->fifo->pipe = NULL; | |
625 | ||
626 | pipe->fifo = fifo; | |
627 | ||
628 | if (fifo) | |
629 | fifo->pipe = pipe; | |
630 | } | |
631 | ||
632 | ||
f1407d5c KM |
633 | /* |
634 | * dcp control | |
635 | */ | |
636 | struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv) | |
637 | { | |
638 | struct usbhs_pipe *pipe; | |
639 | ||
640 | pipe = usbhsp_get_pipe(priv, USB_ENDPOINT_XFER_CONTROL); | |
641 | if (!pipe) | |
642 | return NULL; | |
643 | ||
f5aa889f KM |
644 | INIT_LIST_HEAD(&pipe->list); |
645 | ||
f1407d5c | 646 | /* |
f5aa889f | 647 | * call usbhs_pipe_config_update() after this function !! |
f1407d5c KM |
648 | */ |
649 | ||
f1407d5c KM |
650 | return pipe; |
651 | } | |
652 | ||
653 | void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe) | |
654 | { | |
e8d548d5 | 655 | WARN_ON(!usbhs_pipe_is_dcp(pipe)); |
f1407d5c | 656 | |
e8d548d5 | 657 | usbhs_pipe_enable(pipe); |
f1407d5c KM |
658 | usbhsp_pipectrl_set(pipe, CCPL, CCPL); |
659 | } | |
660 | ||
f1407d5c KM |
661 | /* |
662 | * pipe module function | |
663 | */ | |
664 | int usbhs_pipe_probe(struct usbhs_priv *priv) | |
665 | { | |
e8d548d5 | 666 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); |
f1407d5c KM |
667 | struct usbhs_pipe *pipe; |
668 | struct device *dev = usbhs_priv_to_dev(priv); | |
669 | u32 *pipe_type = usbhs_get_dparam(priv, pipe_type); | |
670 | int pipe_size = usbhs_get_dparam(priv, pipe_size); | |
671 | int i; | |
672 | ||
673 | /* This driver expects 1st pipe is DCP */ | |
674 | if (pipe_type[0] != USB_ENDPOINT_XFER_CONTROL) { | |
675 | dev_err(dev, "1st PIPE is not DCP\n"); | |
676 | return -EINVAL; | |
677 | } | |
678 | ||
679 | info->pipe = kzalloc(sizeof(struct usbhs_pipe) * pipe_size, GFP_KERNEL); | |
680 | if (!info->pipe) { | |
681 | dev_err(dev, "Could not allocate pipe\n"); | |
682 | return -ENOMEM; | |
683 | } | |
684 | ||
685 | info->size = pipe_size; | |
686 | ||
687 | /* | |
688 | * init pipe | |
689 | */ | |
690 | usbhs_for_each_pipe_with_dcp(pipe, priv, i) { | |
691 | pipe->priv = priv; | |
692 | usbhsp_type(pipe) = pipe_type[i] & USB_ENDPOINT_XFERTYPE_MASK; | |
693 | ||
694 | dev_dbg(dev, "pipe %x\t: %s\n", | |
695 | i, usbhsp_pipe_name[pipe_type[i]]); | |
696 | } | |
697 | ||
698 | return 0; | |
699 | } | |
700 | ||
701 | void usbhs_pipe_remove(struct usbhs_priv *priv) | |
702 | { | |
e8d548d5 | 703 | struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); |
f1407d5c KM |
704 | |
705 | kfree(info->pipe); | |
706 | } |