]>
Commit | Line | Data |
---|---|---|
aaf098cf MT |
1 | /*- |
2 | * Copyright (c) 2007-2008, Juniper Networks, Inc. | |
db63299b | 3 | * Copyright (c) 2008, Excito Elektronik i Skåne AB |
c0d722fe RB |
4 | * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it> |
5 | * | |
aaf098cf MT |
6 | * All rights reserved. |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation version 2 of | |
11 | * the License. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | */ | |
aaf098cf | 23 | #include <common.h> |
8f62ca64 | 24 | #include <errno.h> |
db63299b | 25 | #include <asm/byteorder.h> |
93ad908c | 26 | #include <asm/unaligned.h> |
aaf098cf MT |
27 | #include <usb.h> |
28 | #include <asm/io.h> | |
db63299b | 29 | #include <malloc.h> |
67333f76 | 30 | #include <watchdog.h> |
8f62ca64 | 31 | #include <linux/compiler.h> |
2731b9a8 JCPV |
32 | |
33 | #include "ehci.h" | |
aaf098cf | 34 | |
676ae068 LS |
35 | #ifndef CONFIG_USB_MAX_CONTROLLER_COUNT |
36 | #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 | |
37 | #endif | |
aaf098cf | 38 | |
676ae068 LS |
39 | static struct ehci_ctrl { |
40 | struct ehci_hccr *hccr; /* R/O registers, not need for volatile */ | |
41 | struct ehci_hcor *hcor; | |
42 | int rootdev; | |
43 | uint16_t portreset; | |
8f62ca64 PG |
44 | struct QH qh_list __aligned(USB_DMA_MINALIGN); |
45 | struct QH periodic_queue __aligned(USB_DMA_MINALIGN); | |
46 | uint32_t *periodic_list; | |
47 | int ntds; | |
676ae068 | 48 | } ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT]; |
71c5de4f TR |
49 | |
50 | #define ALIGN_END_ADDR(type, ptr, size) \ | |
51 | ((uint32_t)(ptr) + roundup((size) * sizeof(type), USB_DMA_MINALIGN)) | |
aaf098cf | 52 | |
db63299b | 53 | static struct descriptor { |
54 | struct usb_hub_descriptor hub; | |
55 | struct usb_device_descriptor device; | |
56 | struct usb_linux_config_descriptor config; | |
57 | struct usb_linux_interface_descriptor interface; | |
58 | struct usb_endpoint_descriptor endpoint; | |
59 | } __attribute__ ((packed)) descriptor = { | |
60 | { | |
61 | 0x8, /* bDescLength */ | |
62 | 0x29, /* bDescriptorType: hub descriptor */ | |
63 | 2, /* bNrPorts -- runtime modified */ | |
64 | 0, /* wHubCharacteristics */ | |
5f4b4f2f | 65 | 10, /* bPwrOn2PwrGood */ |
db63299b | 66 | 0, /* bHubCntrCurrent */ |
67 | {}, /* Device removable */ | |
68 | {} /* at most 7 ports! XXX */ | |
69 | }, | |
70 | { | |
71 | 0x12, /* bLength */ | |
72 | 1, /* bDescriptorType: UDESC_DEVICE */ | |
6d313c84 | 73 | cpu_to_le16(0x0200), /* bcdUSB: v2.0 */ |
db63299b | 74 | 9, /* bDeviceClass: UDCLASS_HUB */ |
75 | 0, /* bDeviceSubClass: UDSUBCLASS_HUB */ | |
76 | 1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */ | |
77 | 64, /* bMaxPacketSize: 64 bytes */ | |
78 | 0x0000, /* idVendor */ | |
79 | 0x0000, /* idProduct */ | |
6d313c84 | 80 | cpu_to_le16(0x0100), /* bcdDevice */ |
db63299b | 81 | 1, /* iManufacturer */ |
82 | 2, /* iProduct */ | |
83 | 0, /* iSerialNumber */ | |
84 | 1 /* bNumConfigurations: 1 */ | |
85 | }, | |
86 | { | |
87 | 0x9, | |
88 | 2, /* bDescriptorType: UDESC_CONFIG */ | |
89 | cpu_to_le16(0x19), | |
90 | 1, /* bNumInterface */ | |
91 | 1, /* bConfigurationValue */ | |
92 | 0, /* iConfiguration */ | |
93 | 0x40, /* bmAttributes: UC_SELF_POWER */ | |
94 | 0 /* bMaxPower */ | |
95 | }, | |
96 | { | |
97 | 0x9, /* bLength */ | |
98 | 4, /* bDescriptorType: UDESC_INTERFACE */ | |
99 | 0, /* bInterfaceNumber */ | |
100 | 0, /* bAlternateSetting */ | |
101 | 1, /* bNumEndpoints */ | |
102 | 9, /* bInterfaceClass: UICLASS_HUB */ | |
103 | 0, /* bInterfaceSubClass: UISUBCLASS_HUB */ | |
104 | 0, /* bInterfaceProtocol: UIPROTO_HSHUBSTT */ | |
105 | 0 /* iInterface */ | |
106 | }, | |
107 | { | |
108 | 0x7, /* bLength */ | |
109 | 5, /* bDescriptorType: UDESC_ENDPOINT */ | |
110 | 0x81, /* bEndpointAddress: | |
111 | * UE_DIR_IN | EHCI_INTR_ENDPT | |
112 | */ | |
113 | 3, /* bmAttributes: UE_INTERRUPT */ | |
8f8bd565 | 114 | 8, /* wMaxPacketSize */ |
db63299b | 115 | 255 /* bInterval */ |
116 | }, | |
aaf098cf MT |
117 | }; |
118 | ||
c0d722fe RB |
119 | #if defined(CONFIG_EHCI_IS_TDI) |
120 | #define ehci_is_TDI() (1) | |
121 | #else | |
122 | #define ehci_is_TDI() (0) | |
123 | #endif | |
124 | ||
b068deb3 JL |
125 | int __ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg) |
126 | { | |
127 | return PORTSC_PSPD(reg); | |
128 | } | |
129 | ||
130 | int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg) | |
131 | __attribute__((weak, alias("__ehci_get_port_speed"))); | |
132 | ||
133 | void __ehci_set_usbmode(int index) | |
134 | { | |
135 | uint32_t tmp; | |
136 | uint32_t *reg_ptr; | |
137 | ||
138 | reg_ptr = (uint32_t *)((u8 *)&ehcic[index].hcor->or_usbcmd + USBMODE); | |
139 | tmp = ehci_readl(reg_ptr); | |
140 | tmp |= USBMODE_CM_HC; | |
141 | #if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN) | |
142 | tmp |= USBMODE_BE; | |
143 | #endif | |
144 | ehci_writel(reg_ptr, tmp); | |
145 | } | |
146 | ||
147 | void ehci_set_usbmode(int index) | |
148 | __attribute__((weak, alias("__ehci_set_usbmode"))); | |
149 | ||
3874b6d6 MV |
150 | void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg) |
151 | { | |
152 | mdelay(50); | |
153 | } | |
154 | ||
155 | void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg) | |
156 | __attribute__((weak, alias("__ehci_powerup_fixup"))); | |
157 | ||
1ed9f9ad | 158 | static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec) |
db63299b | 159 | { |
51ab142b | 160 | uint32_t result; |
161 | do { | |
162 | result = ehci_readl(ptr); | |
09c83a45 | 163 | udelay(5); |
51ab142b | 164 | if (result == ~(uint32_t)0) |
165 | return -1; | |
166 | result &= mask; | |
167 | if (result == done) | |
168 | return 0; | |
1ed9f9ad MT |
169 | usec--; |
170 | } while (usec > 0); | |
51ab142b | 171 | return -1; |
172 | } | |
173 | ||
676ae068 | 174 | static int ehci_reset(int index) |
51ab142b | 175 | { |
176 | uint32_t cmd; | |
51ab142b | 177 | int ret = 0; |
178 | ||
676ae068 | 179 | cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd); |
273d7204 | 180 | cmd = (cmd & ~CMD_RUN) | CMD_RESET; |
676ae068 LS |
181 | ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd); |
182 | ret = handshake((uint32_t *)&ehcic[index].hcor->or_usbcmd, | |
183 | CMD_RESET, 0, 250 * 1000); | |
51ab142b | 184 | if (ret < 0) { |
185 | printf("EHCI fail to reset\n"); | |
186 | goto out; | |
187 | } | |
188 | ||
b068deb3 JL |
189 | if (ehci_is_TDI()) |
190 | ehci_set_usbmode(index); | |
9ab4ce22 SG |
191 | |
192 | #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH | |
676ae068 | 193 | cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning); |
14eb79b7 | 194 | cmd &= ~TXFIFO_THRESH_MASK; |
9ab4ce22 | 195 | cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH); |
676ae068 | 196 | ehci_writel(&ehcic[index].hcor->or_txfilltuning, cmd); |
9ab4ce22 | 197 | #endif |
51ab142b | 198 | out: |
199 | return ret; | |
db63299b | 200 | } |
aaf098cf | 201 | |
aaf098cf MT |
202 | static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) |
203 | { | |
b8adb120 MV |
204 | uint32_t delta, next; |
205 | uint32_t addr = (uint32_t)buf; | |
aaf098cf MT |
206 | int idx; |
207 | ||
189a6956 | 208 | if (addr != ALIGN(addr, ARCH_DMA_MINALIGN)) |
b8adb120 MV |
209 | debug("EHCI-HCD: Misaligned buffer address (%p)\n", buf); |
210 | ||
189a6956 IY |
211 | flush_dcache_range(addr, ALIGN(addr + sz, ARCH_DMA_MINALIGN)); |
212 | ||
aaf098cf | 213 | idx = 0; |
cdeb9161 | 214 | while (idx < QT_BUFFER_CNT) { |
db63299b | 215 | td->qt_buffer[idx] = cpu_to_hc32(addr); |
3ed16071 | 216 | td->qt_buffer_hi[idx] = 0; |
14eb79b7 | 217 | next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1); |
aaf098cf MT |
218 | delta = next - addr; |
219 | if (delta >= sz) | |
220 | break; | |
221 | sz -= delta; | |
222 | addr = next; | |
223 | idx++; | |
224 | } | |
225 | ||
cdeb9161 | 226 | if (idx == QT_BUFFER_CNT) { |
2af16f85 | 227 | printf("out of buffer pointers (%u bytes left)\n", sz); |
aaf098cf MT |
228 | return -1; |
229 | } | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
c60795f4 IY |
234 | static inline u8 ehci_encode_speed(enum usb_device_speed speed) |
235 | { | |
236 | #define QH_HIGH_SPEED 2 | |
237 | #define QH_FULL_SPEED 0 | |
238 | #define QH_LOW_SPEED 1 | |
239 | if (speed == USB_SPEED_HIGH) | |
240 | return QH_HIGH_SPEED; | |
241 | if (speed == USB_SPEED_LOW) | |
242 | return QH_LOW_SPEED; | |
243 | return QH_FULL_SPEED; | |
244 | } | |
245 | ||
aaf098cf MT |
246 | static int |
247 | ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, | |
248 | int length, struct devrequest *req) | |
249 | { | |
71c5de4f | 250 | ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN); |
5cec214e BT |
251 | struct qTD *qtd; |
252 | int qtd_count = 0; | |
de98e8b2 | 253 | int qtd_counter = 0; |
aaf098cf MT |
254 | volatile struct qTD *vtd; |
255 | unsigned long ts; | |
256 | uint32_t *tdp; | |
db191346 | 257 | uint32_t endpt, maxpacket, token, usbsts; |
aaf098cf | 258 | uint32_t c, toggle; |
db63299b | 259 | uint32_t cmd; |
96820a35 | 260 | int timeout; |
1ed9f9ad | 261 | int ret = 0; |
676ae068 | 262 | struct ehci_ctrl *ctrl = dev->controller; |
aaf098cf | 263 | |
db63299b | 264 | debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe, |
aaf098cf MT |
265 | buffer, length, req); |
266 | if (req != NULL) | |
db63299b | 267 | debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n", |
aaf098cf MT |
268 | req->request, req->request, |
269 | req->requesttype, req->requesttype, | |
270 | le16_to_cpu(req->value), le16_to_cpu(req->value), | |
db63299b | 271 | le16_to_cpu(req->index)); |
aaf098cf | 272 | |
db191346 | 273 | #define PKT_ALIGN 512 |
5cec214e BT |
274 | /* |
275 | * The USB transfer is split into qTD transfers. Eeach qTD transfer is | |
276 | * described by a transfer descriptor (the qTD). The qTDs form a linked | |
277 | * list with a queue head (QH). | |
278 | * | |
279 | * Each qTD transfer starts with a new USB packet, i.e. a packet cannot | |
280 | * have its beginning in a qTD transfer and its end in the following | |
281 | * one, so the qTD transfer lengths have to be chosen accordingly. | |
282 | * | |
283 | * Each qTD transfer uses up to QT_BUFFER_CNT data buffers, mapped to | |
284 | * single pages. The first data buffer can start at any offset within a | |
285 | * page (not considering the cache-line alignment issues), while the | |
286 | * following buffers must be page-aligned. There is no alignment | |
287 | * constraint on the size of a qTD transfer. | |
288 | */ | |
289 | if (req != NULL) | |
290 | /* 1 qTD will be needed for SETUP, and 1 for ACK. */ | |
291 | qtd_count += 1 + 1; | |
292 | if (length > 0 || req == NULL) { | |
293 | /* | |
294 | * Determine the qTD transfer size that will be used for the | |
db191346 BT |
295 | * data payload (not considering the first qTD transfer, which |
296 | * may be longer or shorter, and the final one, which may be | |
297 | * shorter). | |
5cec214e BT |
298 | * |
299 | * In order to keep each packet within a qTD transfer, the qTD | |
db191346 BT |
300 | * transfer size is aligned to PKT_ALIGN, which is a multiple of |
301 | * wMaxPacketSize (except in some cases for interrupt transfers, | |
302 | * see comment in submit_int_msg()). | |
5cec214e | 303 | * |
db191346 | 304 | * By default, i.e. if the input buffer is aligned to PKT_ALIGN, |
5cec214e BT |
305 | * QT_BUFFER_CNT full pages will be used. |
306 | */ | |
307 | int xfr_sz = QT_BUFFER_CNT; | |
308 | /* | |
db191346 BT |
309 | * However, if the input buffer is not aligned to PKT_ALIGN, the |
310 | * qTD transfer size will be one page shorter, and the first qTD | |
5cec214e BT |
311 | * data buffer of each transfer will be page-unaligned. |
312 | */ | |
db191346 | 313 | if ((uint32_t)buffer & (PKT_ALIGN - 1)) |
5cec214e BT |
314 | xfr_sz--; |
315 | /* Convert the qTD transfer size to bytes. */ | |
316 | xfr_sz *= EHCI_PAGE_SIZE; | |
317 | /* | |
db191346 BT |
318 | * Approximate by excess the number of qTDs that will be |
319 | * required for the data payload. The exact formula is way more | |
320 | * complicated and saves at most 2 qTDs, i.e. a total of 128 | |
321 | * bytes. | |
5cec214e | 322 | */ |
db191346 | 323 | qtd_count += 2 + length / xfr_sz; |
5cec214e BT |
324 | } |
325 | /* | |
db191346 BT |
326 | * Threshold value based on the worst-case total size of the allocated qTDs for |
327 | * a mass-storage transfer of 65535 blocks of 512 bytes. | |
5cec214e | 328 | */ |
db191346 | 329 | #if CONFIG_SYS_MALLOC_LEN <= 64 + 128 * 1024 |
5cec214e BT |
330 | #warning CONFIG_SYS_MALLOC_LEN may be too small for EHCI |
331 | #endif | |
332 | qtd = memalign(USB_DMA_MINALIGN, qtd_count * sizeof(struct qTD)); | |
333 | if (qtd == NULL) { | |
334 | printf("unable to allocate TDs\n"); | |
335 | return -1; | |
336 | } | |
337 | ||
71c5de4f | 338 | memset(qh, 0, sizeof(struct QH)); |
5cec214e | 339 | memset(qtd, 0, qtd_count * sizeof(*qtd)); |
de98e8b2 | 340 | |
b8adb120 MV |
341 | toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); |
342 | ||
41b1f0ac MV |
343 | /* |
344 | * Setup QH (3.6 in ehci-r10.pdf) | |
345 | * | |
346 | * qh_link ................. 03-00 H | |
347 | * qh_endpt1 ............... 07-04 H | |
348 | * qh_endpt2 ............... 0B-08 H | |
349 | * - qh_curtd | |
350 | * qh_overlay.qt_next ...... 13-10 H | |
351 | * - qh_overlay.qt_altnext | |
352 | */ | |
676ae068 | 353 | qh->qh_link = cpu_to_hc32((uint32_t)&ctrl->qh_list | QH_LINK_TYPE_QH); |
c60795f4 | 354 | c = (dev->speed != USB_SPEED_HIGH) && !usb_pipeendpoint(pipe); |
db191346 | 355 | maxpacket = usb_maxpacket(dev, pipe); |
14eb79b7 | 356 | endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) | |
db191346 | 357 | QH_ENDPT1_MAXPKTLEN(maxpacket) | QH_ENDPT1_H(0) | |
14eb79b7 | 358 | QH_ENDPT1_DTC(QH_ENDPT1_DTC_DT_FROM_QTD) | |
c60795f4 | 359 | QH_ENDPT1_EPS(ehci_encode_speed(dev->speed)) | |
14eb79b7 BT |
360 | QH_ENDPT1_ENDPT(usb_pipeendpoint(pipe)) | QH_ENDPT1_I(0) | |
361 | QH_ENDPT1_DEVADDR(usb_pipedevice(pipe)); | |
71c5de4f | 362 | qh->qh_endpt1 = cpu_to_hc32(endpt); |
14eb79b7 BT |
363 | endpt = QH_ENDPT2_MULT(1) | QH_ENDPT2_PORTNUM(dev->portnr) | |
364 | QH_ENDPT2_HUBADDR(dev->parent->devnum) | | |
365 | QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0); | |
71c5de4f TR |
366 | qh->qh_endpt2 = cpu_to_hc32(endpt); |
367 | qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); | |
aaf098cf | 368 | |
71c5de4f | 369 | tdp = &qh->qh_overlay.qt_next; |
aaf098cf | 370 | |
aaf098cf | 371 | if (req != NULL) { |
41b1f0ac MV |
372 | /* |
373 | * Setup request qTD (3.5 in ehci-r10.pdf) | |
374 | * | |
375 | * qt_next ................ 03-00 H | |
376 | * qt_altnext ............. 07-04 H | |
377 | * qt_token ............... 0B-08 H | |
378 | * | |
379 | * [ buffer, buffer_hi ] loaded with "req". | |
380 | */ | |
de98e8b2 MV |
381 | qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); |
382 | qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); | |
14eb79b7 BT |
383 | token = QT_TOKEN_DT(0) | QT_TOKEN_TOTALBYTES(sizeof(*req)) | |
384 | QT_TOKEN_IOC(0) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) | | |
385 | QT_TOKEN_PID(QT_TOKEN_PID_SETUP) | | |
386 | QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE); | |
de98e8b2 | 387 | qtd[qtd_counter].qt_token = cpu_to_hc32(token); |
14eb79b7 BT |
388 | if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req))) { |
389 | printf("unable to construct SETUP TD\n"); | |
aaf098cf MT |
390 | goto fail; |
391 | } | |
41b1f0ac | 392 | /* Update previous qTD! */ |
de98e8b2 MV |
393 | *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); |
394 | tdp = &qtd[qtd_counter++].qt_next; | |
aaf098cf MT |
395 | toggle = 1; |
396 | } | |
397 | ||
398 | if (length > 0 || req == NULL) { | |
5cec214e BT |
399 | uint8_t *buf_ptr = buffer; |
400 | int left_length = length; | |
401 | ||
402 | do { | |
403 | /* | |
404 | * Determine the size of this qTD transfer. By default, | |
405 | * QT_BUFFER_CNT full pages can be used. | |
406 | */ | |
407 | int xfr_bytes = QT_BUFFER_CNT * EHCI_PAGE_SIZE; | |
408 | /* | |
409 | * However, if the input buffer is not page-aligned, the | |
410 | * portion of the first page before the buffer start | |
411 | * offset within that page is unusable. | |
412 | */ | |
413 | xfr_bytes -= (uint32_t)buf_ptr & (EHCI_PAGE_SIZE - 1); | |
414 | /* | |
415 | * In order to keep each packet within a qTD transfer, | |
db191346 | 416 | * align the qTD transfer size to PKT_ALIGN. |
5cec214e | 417 | */ |
db191346 | 418 | xfr_bytes &= ~(PKT_ALIGN - 1); |
5cec214e BT |
419 | /* |
420 | * This transfer may be shorter than the available qTD | |
421 | * transfer size that has just been computed. | |
422 | */ | |
423 | xfr_bytes = min(xfr_bytes, left_length); | |
424 | ||
425 | /* | |
426 | * Setup request qTD (3.5 in ehci-r10.pdf) | |
427 | * | |
428 | * qt_next ................ 03-00 H | |
429 | * qt_altnext ............. 07-04 H | |
430 | * qt_token ............... 0B-08 H | |
431 | * | |
432 | * [ buffer, buffer_hi ] loaded with "buffer". | |
433 | */ | |
434 | qtd[qtd_counter].qt_next = | |
435 | cpu_to_hc32(QT_NEXT_TERMINATE); | |
436 | qtd[qtd_counter].qt_altnext = | |
437 | cpu_to_hc32(QT_NEXT_TERMINATE); | |
438 | token = QT_TOKEN_DT(toggle) | | |
439 | QT_TOKEN_TOTALBYTES(xfr_bytes) | | |
440 | QT_TOKEN_IOC(req == NULL) | QT_TOKEN_CPAGE(0) | | |
441 | QT_TOKEN_CERR(3) | | |
442 | QT_TOKEN_PID(usb_pipein(pipe) ? | |
443 | QT_TOKEN_PID_IN : QT_TOKEN_PID_OUT) | | |
444 | QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE); | |
445 | qtd[qtd_counter].qt_token = cpu_to_hc32(token); | |
446 | if (ehci_td_buffer(&qtd[qtd_counter], buf_ptr, | |
447 | xfr_bytes)) { | |
448 | printf("unable to construct DATA TD\n"); | |
449 | goto fail; | |
450 | } | |
451 | /* Update previous qTD! */ | |
452 | *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); | |
453 | tdp = &qtd[qtd_counter++].qt_next; | |
db191346 BT |
454 | /* |
455 | * Data toggle has to be adjusted since the qTD transfer | |
456 | * size is not always an even multiple of | |
457 | * wMaxPacketSize. | |
458 | */ | |
459 | if ((xfr_bytes / maxpacket) & 1) | |
460 | toggle ^= 1; | |
5cec214e BT |
461 | buf_ptr += xfr_bytes; |
462 | left_length -= xfr_bytes; | |
463 | } while (left_length > 0); | |
aaf098cf MT |
464 | } |
465 | ||
466 | if (req != NULL) { | |
41b1f0ac MV |
467 | /* |
468 | * Setup request qTD (3.5 in ehci-r10.pdf) | |
469 | * | |
470 | * qt_next ................ 03-00 H | |
471 | * qt_altnext ............. 07-04 H | |
472 | * qt_token ............... 0B-08 H | |
473 | */ | |
de98e8b2 MV |
474 | qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); |
475 | qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); | |
db191346 | 476 | token = QT_TOKEN_DT(1) | QT_TOKEN_TOTALBYTES(0) | |
14eb79b7 BT |
477 | QT_TOKEN_IOC(1) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) | |
478 | QT_TOKEN_PID(usb_pipein(pipe) ? | |
479 | QT_TOKEN_PID_OUT : QT_TOKEN_PID_IN) | | |
480 | QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE); | |
de98e8b2 | 481 | qtd[qtd_counter].qt_token = cpu_to_hc32(token); |
41b1f0ac | 482 | /* Update previous qTD! */ |
de98e8b2 MV |
483 | *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); |
484 | tdp = &qtd[qtd_counter++].qt_next; | |
aaf098cf MT |
485 | } |
486 | ||
676ae068 | 487 | ctrl->qh_list.qh_link = cpu_to_hc32((uint32_t)qh | QH_LINK_TYPE_QH); |
aaf098cf | 488 | |
daa2dafb | 489 | /* Flush dcache */ |
676ae068 LS |
490 | flush_dcache_range((uint32_t)&ctrl->qh_list, |
491 | ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1)); | |
71c5de4f | 492 | flush_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1)); |
14eb79b7 | 493 | flush_dcache_range((uint32_t)qtd, |
5cec214e | 494 | ALIGN_END_ADDR(struct qTD, qtd, qtd_count)); |
daa2dafb | 495 | |
c7701af5 | 496 | /* Set async. queue head pointer. */ |
676ae068 | 497 | ehci_writel(&ctrl->hcor->or_asynclistaddr, (uint32_t)&ctrl->qh_list); |
c7701af5 | 498 | |
676ae068 LS |
499 | usbsts = ehci_readl(&ctrl->hcor->or_usbsts); |
500 | ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f)); | |
aaf098cf MT |
501 | |
502 | /* Enable async. schedule. */ | |
676ae068 | 503 | cmd = ehci_readl(&ctrl->hcor->or_usbcmd); |
51ab142b | 504 | cmd |= CMD_ASE; |
676ae068 | 505 | ehci_writel(&ctrl->hcor->or_usbcmd, cmd); |
51ab142b | 506 | |
676ae068 | 507 | ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, STS_ASS, |
1ed9f9ad MT |
508 | 100 * 1000); |
509 | if (ret < 0) { | |
14eb79b7 | 510 | printf("EHCI fail timeout STS_ASS set\n"); |
1ed9f9ad | 511 | goto fail; |
51ab142b | 512 | } |
aaf098cf MT |
513 | |
514 | /* Wait for TDs to be processed. */ | |
515 | ts = get_timer(0); | |
de98e8b2 | 516 | vtd = &qtd[qtd_counter - 1]; |
96820a35 | 517 | timeout = USB_TIMEOUT_MS(pipe); |
aaf098cf | 518 | do { |
daa2dafb | 519 | /* Invalidate dcache */ |
676ae068 LS |
520 | invalidate_dcache_range((uint32_t)&ctrl->qh_list, |
521 | ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1)); | |
71c5de4f TR |
522 | invalidate_dcache_range((uint32_t)qh, |
523 | ALIGN_END_ADDR(struct QH, qh, 1)); | |
b8adb120 | 524 | invalidate_dcache_range((uint32_t)qtd, |
5cec214e | 525 | ALIGN_END_ADDR(struct qTD, qtd, qtd_count)); |
b8adb120 | 526 | |
db63299b | 527 | token = hc32_to_cpu(vtd->qt_token); |
14eb79b7 | 528 | if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)) |
aaf098cf | 529 | break; |
67333f76 | 530 | WATCHDOG_RESET(); |
96820a35 SG |
531 | } while (get_timer(ts) < timeout); |
532 | ||
189a6956 IY |
533 | /* |
534 | * Invalidate the memory area occupied by buffer | |
535 | * Don't try to fix the buffer alignment, if it isn't properly | |
536 | * aligned it's upper layer's fault so let invalidate_dcache_range() | |
537 | * vow about it. But we have to fix the length as it's actual | |
538 | * transfer length and can be unaligned. This is potentially | |
539 | * dangerous operation, it's responsibility of the calling | |
540 | * code to make sure enough space is reserved. | |
541 | */ | |
542 | invalidate_dcache_range((uint32_t)buffer, | |
543 | ALIGN((uint32_t)buffer + length, ARCH_DMA_MINALIGN)); | |
b8adb120 | 544 | |
96820a35 | 545 | /* Check that the TD processing happened */ |
14eb79b7 | 546 | if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) |
96820a35 | 547 | printf("EHCI timed out on TD - token=%#x\n", token); |
aaf098cf MT |
548 | |
549 | /* Disable async schedule. */ | |
676ae068 | 550 | cmd = ehci_readl(&ctrl->hcor->or_usbcmd); |
db63299b | 551 | cmd &= ~CMD_ASE; |
676ae068 | 552 | ehci_writel(&ctrl->hcor->or_usbcmd, cmd); |
51ab142b | 553 | |
676ae068 | 554 | ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, 0, |
1ed9f9ad MT |
555 | 100 * 1000); |
556 | if (ret < 0) { | |
14eb79b7 | 557 | printf("EHCI fail timeout STS_ASS reset\n"); |
1ed9f9ad | 558 | goto fail; |
51ab142b | 559 | } |
aaf098cf | 560 | |
71c5de4f | 561 | token = hc32_to_cpu(qh->qh_overlay.qt_token); |
14eb79b7 | 562 | if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)) { |
db63299b | 563 | debug("TOKEN=%#x\n", token); |
14eb79b7 BT |
564 | switch (QT_TOKEN_GET_STATUS(token) & |
565 | ~(QT_TOKEN_STATUS_SPLITXSTATE | QT_TOKEN_STATUS_PERR)) { | |
aaf098cf | 566 | case 0: |
14eb79b7 | 567 | toggle = QT_TOKEN_GET_DT(token); |
aaf098cf MT |
568 | usb_settoggle(dev, usb_pipeendpoint(pipe), |
569 | usb_pipeout(pipe), toggle); | |
570 | dev->status = 0; | |
571 | break; | |
14eb79b7 | 572 | case QT_TOKEN_STATUS_HALTED: |
aaf098cf MT |
573 | dev->status = USB_ST_STALLED; |
574 | break; | |
14eb79b7 BT |
575 | case QT_TOKEN_STATUS_ACTIVE | QT_TOKEN_STATUS_DATBUFERR: |
576 | case QT_TOKEN_STATUS_DATBUFERR: | |
aaf098cf MT |
577 | dev->status = USB_ST_BUF_ERR; |
578 | break; | |
14eb79b7 BT |
579 | case QT_TOKEN_STATUS_HALTED | QT_TOKEN_STATUS_BABBLEDET: |
580 | case QT_TOKEN_STATUS_BABBLEDET: | |
aaf098cf MT |
581 | dev->status = USB_ST_BABBLE_DET; |
582 | break; | |
583 | default: | |
584 | dev->status = USB_ST_CRC_ERR; | |
14eb79b7 | 585 | if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_HALTED) |
222d6dff | 586 | dev->status |= USB_ST_STALLED; |
aaf098cf MT |
587 | break; |
588 | } | |
14eb79b7 | 589 | dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token); |
aaf098cf MT |
590 | } else { |
591 | dev->act_len = 0; | |
e82a316d | 592 | #ifndef CONFIG_USB_EHCI_FARADAY |
db63299b | 593 | debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n", |
676ae068 LS |
594 | dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts), |
595 | ehci_readl(&ctrl->hcor->or_portsc[0]), | |
596 | ehci_readl(&ctrl->hcor->or_portsc[1])); | |
e82a316d | 597 | #endif |
aaf098cf MT |
598 | } |
599 | ||
5cec214e | 600 | free(qtd); |
aaf098cf MT |
601 | return (dev->status != USB_ST_NOT_PROC) ? 0 : -1; |
602 | ||
603 | fail: | |
5cec214e | 604 | free(qtd); |
aaf098cf MT |
605 | return -1; |
606 | } | |
607 | ||
1dde1423 KJS |
608 | __weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port) |
609 | { | |
610 | if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { | |
611 | /* Printing the message would cause a scan failure! */ | |
612 | debug("The request port(%u) is not configured\n", port); | |
613 | return NULL; | |
614 | } | |
615 | ||
616 | return (uint32_t *)&hcor->or_portsc[port]; | |
617 | } | |
618 | ||
db63299b | 619 | int |
aaf098cf MT |
620 | ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, |
621 | int length, struct devrequest *req) | |
622 | { | |
623 | uint8_t tmpbuf[4]; | |
624 | u16 typeReq; | |
db63299b | 625 | void *srcptr = NULL; |
aaf098cf MT |
626 | int len, srclen; |
627 | uint32_t reg; | |
c0d722fe | 628 | uint32_t *status_reg; |
7d9aa8fd | 629 | int port = le16_to_cpu(req->index) & 0xff; |
676ae068 | 630 | struct ehci_ctrl *ctrl = dev->controller; |
aaf098cf MT |
631 | |
632 | srclen = 0; | |
aaf098cf | 633 | |
db63299b | 634 | debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n", |
aaf098cf MT |
635 | req->request, req->request, |
636 | req->requesttype, req->requesttype, | |
637 | le16_to_cpu(req->value), le16_to_cpu(req->index)); | |
638 | ||
44259bb9 | 639 | typeReq = req->request | req->requesttype << 8; |
aaf098cf | 640 | |
9c6a9d7c KJS |
641 | switch (typeReq) { |
642 | case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8): | |
643 | case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): | |
644 | case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): | |
1dde1423 KJS |
645 | status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1); |
646 | if (!status_reg) | |
9c6a9d7c | 647 | return -1; |
9c6a9d7c KJS |
648 | break; |
649 | default: | |
650 | status_reg = NULL; | |
651 | break; | |
652 | } | |
653 | ||
44259bb9 | 654 | switch (typeReq) { |
aaf098cf MT |
655 | case DeviceRequest | USB_REQ_GET_DESCRIPTOR: |
656 | switch (le16_to_cpu(req->value) >> 8) { | |
657 | case USB_DT_DEVICE: | |
db63299b | 658 | debug("USB_DT_DEVICE request\n"); |
659 | srcptr = &descriptor.device; | |
14eb79b7 | 660 | srclen = descriptor.device.bLength; |
aaf098cf MT |
661 | break; |
662 | case USB_DT_CONFIG: | |
db63299b | 663 | debug("USB_DT_CONFIG config\n"); |
664 | srcptr = &descriptor.config; | |
14eb79b7 BT |
665 | srclen = descriptor.config.bLength + |
666 | descriptor.interface.bLength + | |
667 | descriptor.endpoint.bLength; | |
aaf098cf MT |
668 | break; |
669 | case USB_DT_STRING: | |
db63299b | 670 | debug("USB_DT_STRING config\n"); |
aaf098cf MT |
671 | switch (le16_to_cpu(req->value) & 0xff) { |
672 | case 0: /* Language */ | |
673 | srcptr = "\4\3\1\0"; | |
674 | srclen = 4; | |
675 | break; | |
676 | case 1: /* Vendor */ | |
677 | srcptr = "\16\3u\0-\0b\0o\0o\0t\0"; | |
678 | srclen = 14; | |
679 | break; | |
680 | case 2: /* Product */ | |
681 | srcptr = "\52\3E\0H\0C\0I\0 " | |
682 | "\0H\0o\0s\0t\0 " | |
683 | "\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0"; | |
684 | srclen = 42; | |
685 | break; | |
686 | default: | |
db63299b | 687 | debug("unknown value DT_STRING %x\n", |
688 | le16_to_cpu(req->value)); | |
aaf098cf MT |
689 | goto unknown; |
690 | } | |
691 | break; | |
692 | default: | |
db63299b | 693 | debug("unknown value %x\n", le16_to_cpu(req->value)); |
aaf098cf MT |
694 | goto unknown; |
695 | } | |
696 | break; | |
697 | case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8): | |
698 | switch (le16_to_cpu(req->value) >> 8) { | |
699 | case USB_DT_HUB: | |
db63299b | 700 | debug("USB_DT_HUB config\n"); |
701 | srcptr = &descriptor.hub; | |
14eb79b7 | 702 | srclen = descriptor.hub.bLength; |
aaf098cf MT |
703 | break; |
704 | default: | |
db63299b | 705 | debug("unknown value %x\n", le16_to_cpu(req->value)); |
aaf098cf MT |
706 | goto unknown; |
707 | } | |
708 | break; | |
709 | case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8): | |
db63299b | 710 | debug("USB_REQ_SET_ADDRESS\n"); |
676ae068 | 711 | ctrl->rootdev = le16_to_cpu(req->value); |
aaf098cf MT |
712 | break; |
713 | case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: | |
db63299b | 714 | debug("USB_REQ_SET_CONFIGURATION\n"); |
aaf098cf MT |
715 | /* Nothing to do */ |
716 | break; | |
717 | case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8): | |
718 | tmpbuf[0] = 1; /* USB_STATUS_SELFPOWERED */ | |
719 | tmpbuf[1] = 0; | |
720 | srcptr = tmpbuf; | |
721 | srclen = 2; | |
722 | break; | |
db63299b | 723 | case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8): |
aaf098cf | 724 | memset(tmpbuf, 0, 4); |
c0d722fe | 725 | reg = ehci_readl(status_reg); |
aaf098cf MT |
726 | if (reg & EHCI_PS_CS) |
727 | tmpbuf[0] |= USB_PORT_STAT_CONNECTION; | |
728 | if (reg & EHCI_PS_PE) | |
729 | tmpbuf[0] |= USB_PORT_STAT_ENABLE; | |
730 | if (reg & EHCI_PS_SUSP) | |
731 | tmpbuf[0] |= USB_PORT_STAT_SUSPEND; | |
732 | if (reg & EHCI_PS_OCA) | |
733 | tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT; | |
c8b2d1dc SS |
734 | if (reg & EHCI_PS_PR) |
735 | tmpbuf[0] |= USB_PORT_STAT_RESET; | |
aaf098cf MT |
736 | if (reg & EHCI_PS_PP) |
737 | tmpbuf[1] |= USB_PORT_STAT_POWER >> 8; | |
597eb28b SR |
738 | |
739 | if (ehci_is_TDI()) { | |
b068deb3 | 740 | switch (ehci_get_port_speed(ctrl->hcor, reg)) { |
14eb79b7 | 741 | case PORTSC_PSPD_FS: |
597eb28b | 742 | break; |
14eb79b7 | 743 | case PORTSC_PSPD_LS: |
597eb28b SR |
744 | tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8; |
745 | break; | |
14eb79b7 | 746 | case PORTSC_PSPD_HS: |
597eb28b SR |
747 | default: |
748 | tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8; | |
749 | break; | |
750 | } | |
751 | } else { | |
752 | tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8; | |
753 | } | |
aaf098cf MT |
754 | |
755 | if (reg & EHCI_PS_CSC) | |
756 | tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION; | |
757 | if (reg & EHCI_PS_PEC) | |
758 | tmpbuf[2] |= USB_PORT_STAT_C_ENABLE; | |
759 | if (reg & EHCI_PS_OCC) | |
760 | tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT; | |
7d9aa8fd | 761 | if (ctrl->portreset & (1 << port)) |
aaf098cf | 762 | tmpbuf[2] |= USB_PORT_STAT_C_RESET; |
c0d722fe | 763 | |
aaf098cf MT |
764 | srcptr = tmpbuf; |
765 | srclen = 4; | |
766 | break; | |
db63299b | 767 | case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): |
c0d722fe | 768 | reg = ehci_readl(status_reg); |
aaf098cf MT |
769 | reg &= ~EHCI_PS_CLEAR; |
770 | switch (le16_to_cpu(req->value)) { | |
51ab142b | 771 | case USB_PORT_FEAT_ENABLE: |
772 | reg |= EHCI_PS_PE; | |
c0d722fe | 773 | ehci_writel(status_reg, reg); |
51ab142b | 774 | break; |
aaf098cf | 775 | case USB_PORT_FEAT_POWER: |
676ae068 | 776 | if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams))) { |
c0d722fe RB |
777 | reg |= EHCI_PS_PP; |
778 | ehci_writel(status_reg, reg); | |
779 | } | |
aaf098cf MT |
780 | break; |
781 | case USB_PORT_FEAT_RESET: | |
c0d722fe RB |
782 | if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS && |
783 | !ehci_is_TDI() && | |
784 | EHCI_PS_IS_LOWSPEED(reg)) { | |
aaf098cf | 785 | /* Low speed device, give up ownership. */ |
c0d722fe | 786 | debug("port %d low speed --> companion\n", |
7d9aa8fd | 787 | port - 1); |
aaf098cf | 788 | reg |= EHCI_PS_PO; |
c0d722fe | 789 | ehci_writel(status_reg, reg); |
aaf098cf | 790 | break; |
c0d722fe | 791 | } else { |
c8b2d1dc SS |
792 | int ret; |
793 | ||
c0d722fe RB |
794 | reg |= EHCI_PS_PR; |
795 | reg &= ~EHCI_PS_PE; | |
796 | ehci_writel(status_reg, reg); | |
797 | /* | |
798 | * caller must wait, then call GetPortStatus | |
799 | * usb 2.0 specification say 50 ms resets on | |
800 | * root | |
801 | */ | |
3874b6d6 MV |
802 | ehci_powerup_fixup(status_reg, ®); |
803 | ||
b416191a | 804 | ehci_writel(status_reg, reg & ~EHCI_PS_PR); |
c8b2d1dc SS |
805 | /* |
806 | * A host controller must terminate the reset | |
807 | * and stabilize the state of the port within | |
808 | * 2 milliseconds | |
809 | */ | |
810 | ret = handshake(status_reg, EHCI_PS_PR, 0, | |
811 | 2 * 1000); | |
812 | if (!ret) | |
7d9aa8fd | 813 | ctrl->portreset |= 1 << port; |
c8b2d1dc SS |
814 | else |
815 | printf("port(%d) reset error\n", | |
7d9aa8fd | 816 | port - 1); |
aaf098cf | 817 | } |
aaf098cf | 818 | break; |
7d9aa8fd JW |
819 | case USB_PORT_FEAT_TEST: |
820 | reg &= ~(0xf << 16); | |
821 | reg |= ((le16_to_cpu(req->index) >> 8) & 0xf) << 16; | |
822 | ehci_writel(status_reg, reg); | |
823 | break; | |
aaf098cf | 824 | default: |
db63299b | 825 | debug("unknown feature %x\n", le16_to_cpu(req->value)); |
aaf098cf MT |
826 | goto unknown; |
827 | } | |
c0d722fe | 828 | /* unblock posted writes */ |
676ae068 | 829 | (void) ehci_readl(&ctrl->hcor->or_usbcmd); |
aaf098cf | 830 | break; |
db63299b | 831 | case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): |
c0d722fe | 832 | reg = ehci_readl(status_reg); |
ed10e66a | 833 | reg &= ~EHCI_PS_CLEAR; |
aaf098cf MT |
834 | switch (le16_to_cpu(req->value)) { |
835 | case USB_PORT_FEAT_ENABLE: | |
836 | reg &= ~EHCI_PS_PE; | |
837 | break; | |
c0d722fe | 838 | case USB_PORT_FEAT_C_ENABLE: |
ed10e66a | 839 | reg |= EHCI_PS_PE; |
c0d722fe RB |
840 | break; |
841 | case USB_PORT_FEAT_POWER: | |
676ae068 | 842 | if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams))) |
ed10e66a SG |
843 | reg &= ~EHCI_PS_PP; |
844 | break; | |
aaf098cf | 845 | case USB_PORT_FEAT_C_CONNECTION: |
ed10e66a | 846 | reg |= EHCI_PS_CSC; |
aaf098cf | 847 | break; |
51ab142b | 848 | case USB_PORT_FEAT_OVER_CURRENT: |
ed10e66a | 849 | reg |= EHCI_PS_OCC; |
51ab142b | 850 | break; |
aaf098cf | 851 | case USB_PORT_FEAT_C_RESET: |
7d9aa8fd | 852 | ctrl->portreset &= ~(1 << port); |
aaf098cf MT |
853 | break; |
854 | default: | |
db63299b | 855 | debug("unknown feature %x\n", le16_to_cpu(req->value)); |
aaf098cf MT |
856 | goto unknown; |
857 | } | |
c0d722fe RB |
858 | ehci_writel(status_reg, reg); |
859 | /* unblock posted write */ | |
676ae068 | 860 | (void) ehci_readl(&ctrl->hcor->or_usbcmd); |
aaf098cf MT |
861 | break; |
862 | default: | |
db63299b | 863 | debug("Unknown request\n"); |
aaf098cf MT |
864 | goto unknown; |
865 | } | |
866 | ||
5b84dd67 | 867 | mdelay(1); |
aaf098cf MT |
868 | len = min3(srclen, le16_to_cpu(req->length), length); |
869 | if (srcptr != NULL && len > 0) | |
870 | memcpy(buffer, srcptr, len); | |
db63299b | 871 | else |
872 | debug("Len is 0\n"); | |
873 | ||
aaf098cf MT |
874 | dev->act_len = len; |
875 | dev->status = 0; | |
876 | return 0; | |
877 | ||
878 | unknown: | |
db63299b | 879 | debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n", |
aaf098cf MT |
880 | req->requesttype, req->request, le16_to_cpu(req->value), |
881 | le16_to_cpu(req->index), le16_to_cpu(req->length)); | |
882 | ||
883 | dev->act_len = 0; | |
884 | dev->status = USB_ST_STALLED; | |
885 | return -1; | |
886 | } | |
887 | ||
c7e3b2b5 | 888 | int usb_lowlevel_stop(int index) |
aaf098cf | 889 | { |
676ae068 | 890 | return ehci_hcd_stop(index); |
aaf098cf MT |
891 | } |
892 | ||
c7e3b2b5 | 893 | int usb_lowlevel_init(int index, void **controller) |
aaf098cf MT |
894 | { |
895 | uint32_t reg; | |
db63299b | 896 | uint32_t cmd; |
676ae068 | 897 | struct QH *qh_list; |
8f62ca64 PG |
898 | struct QH *periodic; |
899 | int i; | |
aaf098cf | 900 | |
676ae068 | 901 | if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor)) |
aaf098cf MT |
902 | return -1; |
903 | ||
51ab142b | 904 | /* EHCI spec section 4.1 */ |
676ae068 | 905 | if (ehci_reset(index)) |
51ab142b | 906 | return -1; |
907 | ||
832e6141 | 908 | #if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET) |
676ae068 | 909 | if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor)) |
832e6141 SR |
910 | return -1; |
911 | #endif | |
2982837e VP |
912 | /* Set the high address word (aka segment) for 64-bit controller */ |
913 | if (ehci_readl(&ehcic[index].hccr->cr_hccparams) & 1) | |
914 | ehci_writel(ehcic[index].hcor->or_ctrldssegment, 0); | |
832e6141 | 915 | |
676ae068 LS |
916 | qh_list = &ehcic[index].qh_list; |
917 | ||
aaf098cf | 918 | /* Set head of reclaim list */ |
71c5de4f TR |
919 | memset(qh_list, 0, sizeof(*qh_list)); |
920 | qh_list->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH); | |
14eb79b7 BT |
921 | qh_list->qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) | |
922 | QH_ENDPT1_EPS(USB_SPEED_HIGH)); | |
71c5de4f TR |
923 | qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE); |
924 | qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); | |
925 | qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); | |
14eb79b7 BT |
926 | qh_list->qh_overlay.qt_token = |
927 | cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED)); | |
aaf098cf | 928 | |
d3e07478 SW |
929 | flush_dcache_range((uint32_t)qh_list, |
930 | ALIGN_END_ADDR(struct QH, qh_list, 1)); | |
931 | ||
8f62ca64 PG |
932 | /* Set async. queue head pointer. */ |
933 | ehci_writel(&ehcic[index].hcor->or_asynclistaddr, (uint32_t)qh_list); | |
934 | ||
935 | /* | |
936 | * Set up periodic list | |
937 | * Step 1: Parent QH for all periodic transfers. | |
938 | */ | |
939 | periodic = &ehcic[index].periodic_queue; | |
940 | memset(periodic, 0, sizeof(*periodic)); | |
941 | periodic->qh_link = cpu_to_hc32(QH_LINK_TERMINATE); | |
942 | periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); | |
943 | periodic->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); | |
944 | ||
d3e07478 SW |
945 | flush_dcache_range((uint32_t)periodic, |
946 | ALIGN_END_ADDR(struct QH, periodic, 1)); | |
947 | ||
8f62ca64 PG |
948 | /* |
949 | * Step 2: Setup frame-list: Every microframe, USB tries the same list. | |
950 | * In particular, device specifications on polling frequency | |
951 | * are disregarded. Keyboards seem to send NAK/NYet reliably | |
952 | * when polled with an empty buffer. | |
953 | * | |
954 | * Split Transactions will be spread across microframes using | |
955 | * S-mask and C-mask. | |
956 | */ | |
957 | ehcic[index].periodic_list = memalign(4096, 1024*4); | |
958 | if (!ehcic[index].periodic_list) | |
959 | return -ENOMEM; | |
960 | for (i = 0; i < 1024; i++) { | |
961 | ehcic[index].periodic_list[i] = (uint32_t)periodic | |
962 | | QH_LINK_TYPE_QH; | |
963 | } | |
964 | ||
d3e07478 SW |
965 | flush_dcache_range((uint32_t)ehcic[index].periodic_list, |
966 | ALIGN_END_ADDR(uint32_t, ehcic[index].periodic_list, | |
967 | 1024)); | |
968 | ||
8f62ca64 PG |
969 | /* Set periodic list base address */ |
970 | ehci_writel(&ehcic[index].hcor->or_periodiclistbase, | |
971 | (uint32_t)ehcic[index].periodic_list); | |
972 | ||
676ae068 | 973 | reg = ehci_readl(&ehcic[index].hccr->cr_hcsparams); |
51ab142b | 974 | descriptor.hub.bNbrPorts = HCS_N_PORTS(reg); |
7a46b2c7 | 975 | debug("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts); |
c0d722fe RB |
976 | /* Port Indicators */ |
977 | if (HCS_INDICATOR(reg)) | |
93ad908c LS |
978 | put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics) |
979 | | 0x80, &descriptor.hub.wHubCharacteristics); | |
c0d722fe RB |
980 | /* Port Power Control */ |
981 | if (HCS_PPC(reg)) | |
93ad908c LS |
982 | put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics) |
983 | | 0x01, &descriptor.hub.wHubCharacteristics); | |
aaf098cf | 984 | |
aaf098cf | 985 | /* Start the host controller. */ |
676ae068 | 986 | cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd); |
f15c6515 WD |
987 | /* |
988 | * Philips, Intel, and maybe others need CMD_RUN before the | |
989 | * root hub will detect new devices (why?); NEC doesn't | |
990 | */ | |
51ab142b | 991 | cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); |
992 | cmd |= CMD_RUN; | |
676ae068 | 993 | ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd); |
51ab142b | 994 | |
e82a316d | 995 | #ifndef CONFIG_USB_EHCI_FARADAY |
51ab142b | 996 | /* take control over the ports */ |
676ae068 | 997 | cmd = ehci_readl(&ehcic[index].hcor->or_configflag); |
51ab142b | 998 | cmd |= FLAG_CF; |
676ae068 | 999 | ehci_writel(&ehcic[index].hcor->or_configflag, cmd); |
e82a316d KJS |
1000 | #endif |
1001 | ||
c0d722fe | 1002 | /* unblock posted write */ |
676ae068 | 1003 | cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd); |
5b84dd67 | 1004 | mdelay(5); |
676ae068 | 1005 | reg = HC_VERSION(ehci_readl(&ehcic[index].hccr->cr_capbase)); |
c0d722fe | 1006 | printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff); |
aaf098cf | 1007 | |
676ae068 | 1008 | ehcic[index].rootdev = 0; |
aaf098cf | 1009 | |
676ae068 | 1010 | *controller = &ehcic[index]; |
aaf098cf MT |
1011 | return 0; |
1012 | } | |
1013 | ||
1014 | int | |
1015 | submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, | |
1016 | int length) | |
1017 | { | |
1018 | ||
1019 | if (usb_pipetype(pipe) != PIPE_BULK) { | |
1020 | debug("non-bulk pipe (type=%lu)", usb_pipetype(pipe)); | |
1021 | return -1; | |
1022 | } | |
1023 | return ehci_submit_async(dev, pipe, buffer, length, NULL); | |
1024 | } | |
1025 | ||
1026 | int | |
1027 | submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, | |
1028 | int length, struct devrequest *setup) | |
1029 | { | |
676ae068 | 1030 | struct ehci_ctrl *ctrl = dev->controller; |
aaf098cf MT |
1031 | |
1032 | if (usb_pipetype(pipe) != PIPE_CONTROL) { | |
1033 | debug("non-control pipe (type=%lu)", usb_pipetype(pipe)); | |
1034 | return -1; | |
1035 | } | |
1036 | ||
676ae068 LS |
1037 | if (usb_pipedevice(pipe) == ctrl->rootdev) { |
1038 | if (!ctrl->rootdev) | |
aaf098cf MT |
1039 | dev->speed = USB_SPEED_HIGH; |
1040 | return ehci_submit_root(dev, pipe, buffer, length, setup); | |
1041 | } | |
1042 | return ehci_submit_async(dev, pipe, buffer, length, setup); | |
1043 | } | |
1044 | ||
8f62ca64 PG |
1045 | struct int_queue { |
1046 | struct QH *first; | |
1047 | struct QH *current; | |
1048 | struct QH *last; | |
1049 | struct qTD *tds; | |
1050 | }; | |
1051 | ||
1052 | #define NEXT_QH(qh) (struct QH *)((qh)->qh_link & ~0x1f) | |
1053 | ||
1054 | static int | |
1055 | enable_periodic(struct ehci_ctrl *ctrl) | |
1056 | { | |
1057 | uint32_t cmd; | |
1058 | struct ehci_hcor *hcor = ctrl->hcor; | |
1059 | int ret; | |
1060 | ||
1061 | cmd = ehci_readl(&hcor->or_usbcmd); | |
1062 | cmd |= CMD_PSE; | |
1063 | ehci_writel(&hcor->or_usbcmd, cmd); | |
1064 | ||
1065 | ret = handshake((uint32_t *)&hcor->or_usbsts, | |
1066 | STS_PSS, STS_PSS, 100 * 1000); | |
1067 | if (ret < 0) { | |
1068 | printf("EHCI failed: timeout when enabling periodic list\n"); | |
1069 | return -ETIMEDOUT; | |
1070 | } | |
1071 | udelay(1000); | |
1072 | return 0; | |
1073 | } | |
1074 | ||
1075 | static int | |
1076 | disable_periodic(struct ehci_ctrl *ctrl) | |
1077 | { | |
1078 | uint32_t cmd; | |
1079 | struct ehci_hcor *hcor = ctrl->hcor; | |
1080 | int ret; | |
1081 | ||
1082 | cmd = ehci_readl(&hcor->or_usbcmd); | |
1083 | cmd &= ~CMD_PSE; | |
1084 | ehci_writel(&hcor->or_usbcmd, cmd); | |
1085 | ||
1086 | ret = handshake((uint32_t *)&hcor->or_usbsts, | |
1087 | STS_PSS, 0, 100 * 1000); | |
1088 | if (ret < 0) { | |
1089 | printf("EHCI failed: timeout when disabling periodic list\n"); | |
1090 | return -ETIMEDOUT; | |
1091 | } | |
1092 | return 0; | |
1093 | } | |
1094 | ||
1095 | static int periodic_schedules; | |
1096 | ||
1097 | struct int_queue * | |
1098 | create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, | |
1099 | int elementsize, void *buffer) | |
1100 | { | |
1101 | struct ehci_ctrl *ctrl = dev->controller; | |
1102 | struct int_queue *result = NULL; | |
1103 | int i; | |
1104 | ||
1105 | debug("Enter create_int_queue\n"); | |
1106 | if (usb_pipetype(pipe) != PIPE_INTERRUPT) { | |
1107 | debug("non-interrupt pipe (type=%lu)", usb_pipetype(pipe)); | |
1108 | return NULL; | |
1109 | } | |
1110 | ||
1111 | /* limit to 4 full pages worth of data - | |
1112 | * we can safely fit them in a single TD, | |
1113 | * no matter the alignment | |
1114 | */ | |
1115 | if (elementsize >= 16384) { | |
1116 | debug("too large elements for interrupt transfers\n"); | |
1117 | return NULL; | |
1118 | } | |
1119 | ||
1120 | result = malloc(sizeof(*result)); | |
1121 | if (!result) { | |
1122 | debug("ehci intr queue: out of memory\n"); | |
1123 | goto fail1; | |
1124 | } | |
1125 | result->first = memalign(32, sizeof(struct QH) * queuesize); | |
1126 | if (!result->first) { | |
1127 | debug("ehci intr queue: out of memory\n"); | |
1128 | goto fail2; | |
1129 | } | |
1130 | result->current = result->first; | |
1131 | result->last = result->first + queuesize - 1; | |
1132 | result->tds = memalign(32, sizeof(struct qTD) * queuesize); | |
1133 | if (!result->tds) { | |
1134 | debug("ehci intr queue: out of memory\n"); | |
1135 | goto fail3; | |
1136 | } | |
1137 | memset(result->first, 0, sizeof(struct QH) * queuesize); | |
1138 | memset(result->tds, 0, sizeof(struct qTD) * queuesize); | |
1139 | ||
1140 | for (i = 0; i < queuesize; i++) { | |
1141 | struct QH *qh = result->first + i; | |
1142 | struct qTD *td = result->tds + i; | |
1143 | void **buf = &qh->buffer; | |
1144 | ||
1145 | qh->qh_link = (uint32_t)(qh+1) | QH_LINK_TYPE_QH; | |
1146 | if (i == queuesize - 1) | |
1147 | qh->qh_link = QH_LINK_TERMINATE; | |
1148 | ||
1149 | qh->qh_overlay.qt_next = (uint32_t)td; | |
1150 | qh->qh_endpt1 = (0 << 28) | /* No NAK reload (ehci 4.9) */ | |
1151 | (usb_maxpacket(dev, pipe) << 16) | /* MPS */ | |
1152 | (1 << 14) | | |
1153 | QH_ENDPT1_EPS(ehci_encode_speed(dev->speed)) | | |
1154 | (usb_pipeendpoint(pipe) << 8) | /* Endpoint Number */ | |
1155 | (usb_pipedevice(pipe) << 0); | |
1156 | qh->qh_endpt2 = (1 << 30) | /* 1 Tx per mframe */ | |
1157 | (1 << 0); /* S-mask: microframe 0 */ | |
1158 | if (dev->speed == USB_SPEED_LOW || | |
1159 | dev->speed == USB_SPEED_FULL) { | |
1160 | debug("TT: port: %d, hub address: %d\n", | |
1161 | dev->portnr, dev->parent->devnum); | |
1162 | qh->qh_endpt2 |= (dev->portnr << 23) | | |
1163 | (dev->parent->devnum << 16) | | |
1164 | (0x1c << 8); /* C-mask: microframes 2-4 */ | |
1165 | } | |
1166 | ||
1167 | td->qt_next = QT_NEXT_TERMINATE; | |
1168 | td->qt_altnext = QT_NEXT_TERMINATE; | |
1169 | debug("communication direction is '%s'\n", | |
1170 | usb_pipein(pipe) ? "in" : "out"); | |
1171 | td->qt_token = (elementsize << 16) | | |
1172 | ((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */ | |
1173 | 0x80; /* active */ | |
1174 | td->qt_buffer[0] = (uint32_t)buffer + i * elementsize; | |
1175 | td->qt_buffer[1] = (td->qt_buffer[0] + 0x1000) & ~0xfff; | |
1176 | td->qt_buffer[2] = (td->qt_buffer[0] + 0x2000) & ~0xfff; | |
1177 | td->qt_buffer[3] = (td->qt_buffer[0] + 0x3000) & ~0xfff; | |
1178 | td->qt_buffer[4] = (td->qt_buffer[0] + 0x4000) & ~0xfff; | |
1179 | ||
1180 | *buf = buffer + i * elementsize; | |
1181 | } | |
1182 | ||
d3e07478 SW |
1183 | flush_dcache_range((uint32_t)buffer, |
1184 | ALIGN_END_ADDR(char, buffer, | |
1185 | queuesize * elementsize)); | |
1186 | flush_dcache_range((uint32_t)result->first, | |
1187 | ALIGN_END_ADDR(struct QH, result->first, | |
1188 | queuesize)); | |
1189 | flush_dcache_range((uint32_t)result->tds, | |
1190 | ALIGN_END_ADDR(struct qTD, result->tds, | |
1191 | queuesize)); | |
1192 | ||
8f62ca64 PG |
1193 | if (disable_periodic(ctrl) < 0) { |
1194 | debug("FATAL: periodic should never fail, but did"); | |
1195 | goto fail3; | |
1196 | } | |
1197 | ||
1198 | /* hook up to periodic list */ | |
1199 | struct QH *list = &ctrl->periodic_queue; | |
1200 | result->last->qh_link = list->qh_link; | |
1201 | list->qh_link = (uint32_t)result->first | QH_LINK_TYPE_QH; | |
1202 | ||
d3e07478 SW |
1203 | flush_dcache_range((uint32_t)result->last, |
1204 | ALIGN_END_ADDR(struct QH, result->last, 1)); | |
1205 | flush_dcache_range((uint32_t)list, | |
1206 | ALIGN_END_ADDR(struct QH, list, 1)); | |
1207 | ||
8f62ca64 PG |
1208 | if (enable_periodic(ctrl) < 0) { |
1209 | debug("FATAL: periodic should never fail, but did"); | |
1210 | goto fail3; | |
1211 | } | |
1212 | periodic_schedules++; | |
1213 | ||
1214 | debug("Exit create_int_queue\n"); | |
1215 | return result; | |
1216 | fail3: | |
1217 | if (result->tds) | |
1218 | free(result->tds); | |
1219 | fail2: | |
1220 | if (result->first) | |
1221 | free(result->first); | |
1222 | if (result) | |
1223 | free(result); | |
1224 | fail1: | |
1225 | return NULL; | |
1226 | } | |
1227 | ||
1228 | void *poll_int_queue(struct usb_device *dev, struct int_queue *queue) | |
1229 | { | |
1230 | struct QH *cur = queue->current; | |
1231 | ||
1232 | /* depleted queue */ | |
1233 | if (cur == NULL) { | |
1234 | debug("Exit poll_int_queue with completed queue\n"); | |
1235 | return NULL; | |
1236 | } | |
1237 | /* still active */ | |
d3e07478 SW |
1238 | invalidate_dcache_range((uint32_t)cur, |
1239 | ALIGN_END_ADDR(struct QH, cur, 1)); | |
8f62ca64 PG |
1240 | if (cur->qh_overlay.qt_token & 0x80) { |
1241 | debug("Exit poll_int_queue with no completed intr transfer. " | |
1242 | "token is %x\n", cur->qh_overlay.qt_token); | |
1243 | return NULL; | |
1244 | } | |
1245 | if (!(cur->qh_link & QH_LINK_TERMINATE)) | |
1246 | queue->current++; | |
1247 | else | |
1248 | queue->current = NULL; | |
1249 | debug("Exit poll_int_queue with completed intr transfer. " | |
1250 | "token is %x at %p (first at %p)\n", cur->qh_overlay.qt_token, | |
1251 | &cur->qh_overlay.qt_token, queue->first); | |
1252 | return cur->buffer; | |
1253 | } | |
1254 | ||
1255 | /* Do not free buffers associated with QHs, they're owned by someone else */ | |
1256 | int | |
1257 | destroy_int_queue(struct usb_device *dev, struct int_queue *queue) | |
1258 | { | |
1259 | struct ehci_ctrl *ctrl = dev->controller; | |
1260 | int result = -1; | |
1261 | unsigned long timeout; | |
1262 | ||
1263 | if (disable_periodic(ctrl) < 0) { | |
1264 | debug("FATAL: periodic should never fail, but did"); | |
1265 | goto out; | |
1266 | } | |
1267 | periodic_schedules--; | |
1268 | ||
1269 | struct QH *cur = &ctrl->periodic_queue; | |
1270 | timeout = get_timer(0) + 500; /* abort after 500ms */ | |
1271 | while (!(cur->qh_link & QH_LINK_TERMINATE)) { | |
1272 | debug("considering %p, with qh_link %x\n", cur, cur->qh_link); | |
1273 | if (NEXT_QH(cur) == queue->first) { | |
1274 | debug("found candidate. removing from chain\n"); | |
1275 | cur->qh_link = queue->last->qh_link; | |
1276 | result = 0; | |
1277 | break; | |
1278 | } | |
1279 | cur = NEXT_QH(cur); | |
1280 | if (get_timer(0) > timeout) { | |
1281 | printf("Timeout destroying interrupt endpoint queue\n"); | |
1282 | result = -1; | |
1283 | goto out; | |
1284 | } | |
1285 | } | |
1286 | ||
1287 | if (periodic_schedules > 0) { | |
1288 | result = enable_periodic(ctrl); | |
1289 | if (result < 0) | |
1290 | debug("FATAL: periodic should never fail, but did"); | |
1291 | } | |
1292 | ||
1293 | out: | |
1294 | free(queue->tds); | |
1295 | free(queue->first); | |
1296 | free(queue); | |
1297 | ||
1298 | return result; | |
1299 | } | |
1300 | ||
aaf098cf MT |
1301 | int |
1302 | submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, | |
1303 | int length, int interval) | |
1304 | { | |
8f62ca64 PG |
1305 | void *backbuffer; |
1306 | struct int_queue *queue; | |
1307 | unsigned long timeout; | |
1308 | int result = 0, ret; | |
1309 | ||
aaf098cf MT |
1310 | debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d", |
1311 | dev, pipe, buffer, length, interval); | |
44ae0be7 BT |
1312 | |
1313 | /* | |
1314 | * Interrupt transfers requiring several transactions are not supported | |
1315 | * because bInterval is ignored. | |
5cec214e BT |
1316 | * |
1317 | * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2 | |
db191346 BT |
1318 | * <= PKT_ALIGN if several qTDs are required, while the USB |
1319 | * specification does not constrain this for interrupt transfers. That | |
1320 | * means that ehci_submit_async() would support interrupt transfers | |
1321 | * requiring several transactions only as long as the transfer size does | |
1322 | * not require more than a single qTD. | |
44ae0be7 BT |
1323 | */ |
1324 | if (length > usb_maxpacket(dev, pipe)) { | |
8f62ca64 PG |
1325 | printf("%s: Interrupt transfers requiring several " |
1326 | "transactions are not supported.\n", __func__); | |
44ae0be7 BT |
1327 | return -1; |
1328 | } | |
8f62ca64 PG |
1329 | |
1330 | queue = create_int_queue(dev, pipe, 1, length, buffer); | |
1331 | ||
1332 | timeout = get_timer(0) + USB_TIMEOUT_MS(pipe); | |
1333 | while ((backbuffer = poll_int_queue(dev, queue)) == NULL) | |
1334 | if (get_timer(0) > timeout) { | |
1335 | printf("Timeout poll on interrupt endpoint\n"); | |
1336 | result = -ETIMEDOUT; | |
1337 | break; | |
1338 | } | |
1339 | ||
1340 | if (backbuffer != buffer) { | |
1341 | debug("got wrong buffer back (%x instead of %x)\n", | |
1342 | (uint32_t)backbuffer, (uint32_t)buffer); | |
1343 | return -EINVAL; | |
1344 | } | |
1345 | ||
d3e07478 SW |
1346 | invalidate_dcache_range((uint32_t)buffer, |
1347 | ALIGN_END_ADDR(char, buffer, length)); | |
1348 | ||
8f62ca64 PG |
1349 | ret = destroy_int_queue(dev, queue); |
1350 | if (ret < 0) | |
1351 | return ret; | |
1352 | ||
1353 | /* everything worked out fine */ | |
1354 | return result; | |
7555d5ec | 1355 | } |