1 /* ehci.c - EHCI Support. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2011 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
23 #include <grub/usbtrans.h>
24 #include <grub/misc.h>
25 #include <grub/time.h>
26 #include <grub/loader.h>
27 #include <grub/disk.h>
29 #include <grub/cache.h>
31 GRUB_MOD_LICENSE ("GPLv3+");
33 /* This simple GRUB implementation of EHCI driver:
35 * - is not supporting isochronous transfers (iTD, siTD)
36 * - is not supporting interrupt transfers
39 /* Capability registers offsets */
42 GRUB_EHCI_EHCC_CAPLEN = 0x00, /* byte */
43 GRUB_EHCI_EHCC_VERSION = 0x02, /* word */
44 GRUB_EHCI_EHCC_SPARAMS = 0x04, /* dword */
45 GRUB_EHCI_EHCC_CPARAMS = 0x08, /* dword */
46 GRUB_EHCI_EHCC_PROUTE = 0x0c, /* 60 bits */
49 #define GRUB_EHCI_EECP_MASK (0xff << 8)
50 #define GRUB_EHCI_EECP_SHIFT 8
52 #define GRUB_EHCI_POINTER_MASK (~0x1f)
54 /* Capability register SPARAMS bits */
57 GRUB_EHCI_SPARAMS_N_PORTS = (0xf << 0),
58 GRUB_EHCI_SPARAMS_PPC = (1 << 4), /* Power port control */
59 GRUB_EHCI_SPARAMS_PRR = (1 << 7), /* Port routing rules */
60 GRUB_EHCI_SPARAMS_N_PCC = (0xf << 8), /* No of ports per comp. */
61 GRUB_EHCI_SPARAMS_NCC = (0xf << 12), /* No of com. controllers */
62 GRUB_EHCI_SPARAMS_P_IND = (1 << 16), /* Port indicators present */
63 GRUB_EHCI_SPARAMS_DEBUG_P = (0xf << 20) /* Debug port */
66 #define GRUB_EHCI_MAX_N_PORTS 15 /* Max. number of ports */
68 /* Capability register CPARAMS bits */
71 GRUB_EHCI_CPARAMS_64BIT = (1 << 0),
72 GRUB_EHCI_CPARAMS_PROG_FRAMELIST = (1 << 1),
73 GRUB_EHCI_CPARAMS_PARK_CAP = (1 << 2)
76 #define GRUB_EHCI_N_FRAMELIST 1024
77 #define GRUB_EHCI_N_QH 256
78 #define GRUB_EHCI_N_TD 640
80 #define GRUB_EHCI_QH_EMPTY 1
82 /* Operational registers offsets */
85 GRUB_EHCI_COMMAND = 0x00,
86 GRUB_EHCI_STATUS = 0x04,
87 GRUB_EHCI_INTERRUPT = 0x08,
88 GRUB_EHCI_FRAME_INDEX = 0x0c,
89 GRUB_EHCI_64BIT_SEL = 0x10,
90 GRUB_EHCI_FL_BASE = 0x14,
91 GRUB_EHCI_CUR_AL_ADDR = 0x18,
92 GRUB_EHCI_CONFIG_FLAG = 0x40,
93 GRUB_EHCI_PORT_STAT_CMD = 0x44
96 /* Operational register COMMAND bits */
99 GRUB_EHCI_CMD_RUNSTOP = (1 << 0),
100 GRUB_EHCI_CMD_HC_RESET = (1 << 1),
101 GRUB_EHCI_CMD_FL_SIZE = (3 << 2),
102 GRUB_EHCI_CMD_PS_ENABL = (1 << 4),
103 GRUB_EHCI_CMD_AS_ENABL = (1 << 5),
104 GRUB_EHCI_CMD_AS_ADV_D = (1 << 6),
105 GRUB_EHCI_CMD_L_HC_RES = (1 << 7),
106 GRUB_EHCI_CMD_AS_PARKM = (3 << 8),
107 GRUB_EHCI_CMD_AS_PARKE = (1 << 11),
108 GRUB_EHCI_CMD_INT_THRS = (0xff << 16)
111 /* Operational register STATUS bits */
114 GRUB_EHCI_ST_INTERRUPT = (1 << 0),
115 GRUB_EHCI_ST_ERROR_INT = (1 << 1),
116 GRUB_EHCI_ST_PORT_CHG = (1 << 2),
117 GRUB_EHCI_ST_FL_ROLLOVR = (1 << 3),
118 GRUB_EHCI_ST_HS_ERROR = (1 << 4),
119 GRUB_EHCI_ST_AS_ADVANCE = (1 << 5),
120 GRUB_EHCI_ST_HC_HALTED = (1 << 12),
121 GRUB_EHCI_ST_RECLAM = (1 << 13),
122 GRUB_EHCI_ST_PS_STATUS = (1 << 14),
123 GRUB_EHCI_ST_AS_STATUS = (1 << 15)
126 /* Operational register PORT_STAT_CMD bits */
129 GRUB_EHCI_PORT_CONNECT = (1 << 0),
130 GRUB_EHCI_PORT_CONNECT_CH = (1 << 1),
131 GRUB_EHCI_PORT_ENABLED = (1 << 2),
132 GRUB_EHCI_PORT_ENABLED_CH = (1 << 3),
133 GRUB_EHCI_PORT_OVERCUR = (1 << 4),
134 GRUB_EHCI_PORT_OVERCUR_CH = (1 << 5),
135 GRUB_EHCI_PORT_RESUME = (1 << 6),
136 GRUB_EHCI_PORT_SUSPEND = (1 << 7),
137 GRUB_EHCI_PORT_RESET = (1 << 8),
138 GRUB_EHCI_PORT_LINE_STAT = (3 << 10),
139 GRUB_EHCI_PORT_POWER = (1 << 12),
140 GRUB_EHCI_PORT_OWNER = (1 << 13),
141 GRUB_EHCI_PORT_INDICATOR = (3 << 14),
142 GRUB_EHCI_PORT_TEST = (0xf << 16),
143 GRUB_EHCI_PORT_WON_CONN_E = (1 << 20),
144 GRUB_EHCI_PORT_WON_DISC_E = (1 << 21),
145 GRUB_EHCI_PORT_WON_OVER_E = (1 << 22),
147 GRUB_EHCI_PORT_LINE_SE0 = (0 << 10),
148 GRUB_EHCI_PORT_LINE_K = (1 << 10),
149 GRUB_EHCI_PORT_LINE_J = (2 << 10),
150 GRUB_EHCI_PORT_LINE_UNDEF = (3 << 10),
151 GRUB_EHCI_PORT_LINE_LOWSP = GRUB_EHCI_PORT_LINE_K, /* K state means low speed */
152 GRUB_EHCI_PORT_WMASK = ~(GRUB_EHCI_PORT_CONNECT_CH
153 | GRUB_EHCI_PORT_ENABLED_CH
154 | GRUB_EHCI_PORT_OVERCUR_CH)
157 /* Operational register CONFIGFLAGS bits */
160 GRUB_EHCI_CF_EHCI_OWNER = (1 << 0)
163 /* Queue Head & Transfer Descriptor constants */
164 #define GRUB_EHCI_HPTR_OFF 5 /* Horiz. pointer bit offset */
167 GRUB_EHCI_HPTR_TYPE_MASK = (3 << 1),
168 GRUB_EHCI_HPTR_TYPE_ITD = (0 << 1),
169 GRUB_EHCI_HPTR_TYPE_QH = (1 << 1),
170 GRUB_EHCI_HPTR_TYPE_SITD = (2 << 1),
171 GRUB_EHCI_HPTR_TYPE_FSTN = (3 << 1)
176 GRUB_EHCI_C = (1 << 27),
177 GRUB_EHCI_MAXPLEN_MASK = (0x7ff << 16),
178 GRUB_EHCI_H = (1 << 15),
179 GRUB_EHCI_DTC = (1 << 14),
180 GRUB_EHCI_SPEED_MASK = (3 << 12),
181 GRUB_EHCI_SPEED_FULL = (0 << 12),
182 GRUB_EHCI_SPEED_LOW = (1 << 12),
183 GRUB_EHCI_SPEED_HIGH = (2 << 12),
184 GRUB_EHCI_SPEED_RESERVED = (3 << 12),
185 GRUB_EHCI_EP_NUM_MASK = (0xf << 8),
186 GRUB_EHCI_DEVADDR_MASK = 0x7f,
187 GRUB_EHCI_TARGET_MASK = (GRUB_EHCI_EP_NUM_MASK | GRUB_EHCI_DEVADDR_MASK)
192 GRUB_EHCI_MAXPLEN_OFF = 16,
193 GRUB_EHCI_SPEED_OFF = 12,
194 GRUB_EHCI_EP_NUM_OFF = 8
199 GRUB_EHCI_MULT_MASK = (3 << 30),
200 GRUB_EHCI_MULT_RESERVED = (0 << 30),
201 GRUB_EHCI_MULT_ONE = (1 << 30),
202 GRUB_EHCI_MULT_TWO = (2 << 30),
203 GRUB_EHCI_MULT_THREE = (3 << 30),
204 GRUB_EHCI_DEVPORT_MASK = (0x7f << 23),
205 GRUB_EHCI_HUBADDR_MASK = (0x7f << 16),
206 GRUB_EHCI_CMASK_MASK = (0xff << 8),
207 GRUB_EHCI_SMASK_MASK = (0xff << 0),
212 GRUB_EHCI_MULT_OFF = 30,
213 GRUB_EHCI_DEVPORT_OFF = 23,
214 GRUB_EHCI_HUBADDR_OFF = 16,
215 GRUB_EHCI_CMASK_OFF = 8,
216 GRUB_EHCI_SMASK_OFF = 0,
219 #define GRUB_EHCI_TERMINATE (1<<0)
221 #define GRUB_EHCI_TOGGLE (1<<31)
225 GRUB_EHCI_TOTAL_MASK = (0x7fff << 16),
226 GRUB_EHCI_CERR_MASK = (3 << 10),
227 GRUB_EHCI_CERR_0 = (0 << 10),
228 GRUB_EHCI_CERR_1 = (1 << 10),
229 GRUB_EHCI_CERR_2 = (2 << 10),
230 GRUB_EHCI_CERR_3 = (3 << 10),
231 GRUB_EHCI_PIDCODE_OUT = (0 << 8),
232 GRUB_EHCI_PIDCODE_IN = (1 << 8),
233 GRUB_EHCI_PIDCODE_SETUP = (2 << 8),
234 GRUB_EHCI_STATUS_MASK = 0xff,
235 GRUB_EHCI_STATUS_ACTIVE = (1 << 7),
236 GRUB_EHCI_STATUS_HALTED = (1 << 6),
237 GRUB_EHCI_STATUS_BUFERR = (1 << 5),
238 GRUB_EHCI_STATUS_BABBLE = (1 << 4),
239 GRUB_EHCI_STATUS_TRANERR = (1 << 3),
240 GRUB_EHCI_STATUS_MISSDMF = (1 << 2),
241 GRUB_EHCI_STATUS_SPLITST = (1 << 1),
242 GRUB_EHCI_STATUS_PINGERR = (1 << 0)
247 GRUB_EHCI_TOTAL_OFF = 16,
248 GRUB_EHCI_CERR_OFF = 10
251 #define GRUB_EHCI_BUFPTR_MASK (0xfffff<<12)
252 #define GRUB_EHCI_QHTDPTR_MASK 0xffffffe0
254 #define GRUB_EHCI_TD_BUF_PAGES 5
256 #define GRUB_EHCI_BUFPAGELEN 0x1000
257 #define GRUB_EHCI_MAXBUFLEN 0x5000
261 typedef volatile struct grub_ehci_td *grub_ehci_td_t;
262 typedef volatile struct grub_ehci_qh *grub_ehci_qh_t;
264 /* EHCI Isochronous Transfer Descriptor */
265 /* Currently not supported */
267 /* EHCI Split Transaction Isochronous Transfer Descriptor */
268 /* Currently not supported */
270 /* EHCI Queue Element Transfer Descriptor (qTD) */
271 /* Align to 32-byte boundaries */
275 grub_uint32_t next_td; /* Pointer to next qTD */
276 grub_uint32_t alt_next_td; /* Pointer to alternate next qTD */
277 grub_uint32_t token; /* Toggle, Len, Interrupt, Page, Error, PID, Status */
278 grub_uint32_t buffer_page[GRUB_EHCI_TD_BUF_PAGES]; /* Buffer pointer (+ cur. offset in page 0 */
280 grub_uint32_t buffer_page_high[GRUB_EHCI_TD_BUF_PAGES];
281 /* EHCI driver part */
282 grub_uint32_t link_td; /* pointer to next free/chained TD */
284 grub_uint32_t pad[1]; /* padding to some multiple of 32 bytes */
287 /* EHCI Queue Head */
288 /* Align to 32-byte boundaries */
289 /* QH allocation is made in the similar/same way as in OHCI driver,
290 * because unlninking QH from the Asynchronous list is not so
291 * trivial as on UHCI (at least it is time consuming) */
295 grub_uint32_t qh_hptr; /* Horiz. pointer & Terminate */
296 grub_uint32_t ep_char; /* EP characteristics */
297 grub_uint32_t ep_cap; /* EP capabilities */
298 grub_uint32_t td_current; /* current TD link pointer */
299 struct grub_ehci_td td_overlay; /* TD overlay area = 64 bytes */
300 /* EHCI driver part */
301 grub_uint32_t pad[4]; /* padding to some multiple of 32 bytes */
304 /* EHCI Periodic Frame Span Traversal Node */
305 /* Currently not supported */
309 volatile grub_uint32_t *iobase_ehcc; /* Capability registers */
310 volatile grub_uint32_t *iobase; /* Operational registers */
311 struct grub_pci_dma_chunk *framelist_chunk; /* Currently not used */
312 volatile grub_uint32_t *framelist_virt;
313 grub_uint32_t framelist_phys;
314 struct grub_pci_dma_chunk *qh_chunk; /* GRUB_EHCI_N_QH Queue Heads */
315 grub_ehci_qh_t qh_virt;
316 grub_uint32_t qh_phys;
317 struct grub_pci_dma_chunk *td_chunk; /* GRUB_EHCI_N_TD Transfer Descriptors */
318 grub_ehci_td_t td_virt;
319 grub_uint32_t td_phys;
320 grub_ehci_td_t tdfree_virt; /* Free Transfer Descriptors */
322 grub_uint32_t reset; /* bits 1-15 are flags if port was reset from connected time or not */
323 struct grub_ehci *next;
326 static struct grub_ehci *ehci;
329 sync_all_caches (struct grub_ehci *e)
334 grub_arch_sync_dma_caches (e->td_virt, sizeof (struct grub_ehci_td) *
337 grub_arch_sync_dma_caches (e->qh_virt, sizeof (struct grub_ehci_qh) *
339 if (e->framelist_virt)
340 grub_arch_sync_dma_caches (e->framelist_virt, 4096);
343 /* EHCC registers access functions */
344 static inline grub_uint32_t
345 grub_ehci_ehcc_read32 (struct grub_ehci *e, grub_uint32_t addr)
348 grub_le_to_cpu32 (*((volatile grub_uint32_t *) e->iobase_ehcc +
349 (addr / sizeof (grub_uint32_t))));
352 static inline grub_uint16_t
353 grub_ehci_ehcc_read16 (struct grub_ehci *e, grub_uint32_t addr)
356 grub_le_to_cpu16 (*((volatile grub_uint16_t *) e->iobase_ehcc +
357 (addr / sizeof (grub_uint16_t))));
360 static inline grub_uint8_t
361 grub_ehci_ehcc_read8 (struct grub_ehci *e, grub_uint32_t addr)
363 return *((volatile grub_uint8_t *) e->iobase_ehcc + addr);
366 /* Operational registers access functions */
367 static inline grub_uint32_t
368 grub_ehci_oper_read32 (struct grub_ehci *e, grub_uint32_t addr)
372 ((volatile grub_uint32_t *) e->iobase +
373 (addr / sizeof (grub_uint32_t))));
377 grub_ehci_oper_write32 (struct grub_ehci *e, grub_uint32_t addr,
380 *((volatile grub_uint32_t *) e->iobase + (addr / sizeof (grub_uint32_t))) =
381 grub_cpu_to_le32 (value);
384 static inline grub_uint32_t
385 grub_ehci_port_read (struct grub_ehci *e, grub_uint32_t port)
387 return grub_ehci_oper_read32 (e, GRUB_EHCI_PORT_STAT_CMD + port * 4);
391 grub_ehci_port_resbits (struct grub_ehci *e, grub_uint32_t port,
394 grub_ehci_oper_write32 (e, GRUB_EHCI_PORT_STAT_CMD + port * 4,
395 grub_ehci_port_read (e,
396 port) & GRUB_EHCI_PORT_WMASK &
398 grub_ehci_port_read (e, port);
402 grub_ehci_port_setbits (struct grub_ehci *e, grub_uint32_t port,
405 grub_ehci_oper_write32 (e, GRUB_EHCI_PORT_STAT_CMD + port * 4,
406 (grub_ehci_port_read (e, port) &
407 GRUB_EHCI_PORT_WMASK) | bits);
408 grub_ehci_port_read (e, port);
411 /* Halt if EHCI HC not halted */
412 static grub_usb_err_t
413 grub_ehci_halt (struct grub_ehci *e)
415 grub_uint64_t maxtime;
417 if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) & GRUB_EHCI_ST_HC_HALTED) == 0) /* EHCI is not halted */
420 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
421 ~GRUB_EHCI_CMD_RUNSTOP
422 & grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
423 /* Ensure command is written */
424 grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND);
425 maxtime = grub_get_time_ms () + 1000; /* Fix: Should be 2ms ! */
426 while (((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)
427 & GRUB_EHCI_ST_HC_HALTED) == 0)
428 && (grub_get_time_ms () < maxtime));
429 if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)
430 & GRUB_EHCI_ST_HC_HALTED) == 0)
431 return GRUB_USB_ERR_TIMEOUT;
434 return GRUB_USB_ERR_NONE;
438 static grub_usb_err_t
439 grub_ehci_reset (struct grub_ehci *e)
441 grub_uint64_t maxtime;
445 grub_dprintf ("ehci", "reset\n");
447 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
448 GRUB_EHCI_CMD_HC_RESET);
449 /* Ensure command is written */
450 grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND);
451 /* XXX: How long time could take reset of HC ? */
452 maxtime = grub_get_time_ms () + 1000;
453 while (((grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)
454 & GRUB_EHCI_CMD_HC_RESET) != 0)
455 && (grub_get_time_ms () < maxtime));
456 if ((grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND)
457 & GRUB_EHCI_CMD_HC_RESET) != 0)
458 return GRUB_USB_ERR_TIMEOUT;
460 return GRUB_USB_ERR_NONE;
463 /* PCI iteration function... */
465 grub_ehci_init_device (volatile void *regs)
470 grub_uint32_t n_ports;
473 /* Allocate memory for the controller and fill basic values. */
474 e = grub_zalloc (sizeof (*e));
477 e->framelist_chunk = NULL;
480 e->iobase_ehcc = regs;
482 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CAPLEN: %02x\n",
483 grub_ehci_ehcc_read8 (e, GRUB_EHCI_EHCC_CAPLEN));
484 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: VERSION: %04x\n",
485 grub_ehci_ehcc_read16 (e, GRUB_EHCI_EHCC_VERSION));
486 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: SPARAMS: %08x\n",
487 grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS));
488 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CPARAMS: %08x\n",
489 grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_CPARAMS));
491 /* Determine base address of EHCI operational registers */
492 caplen = grub_ehci_ehcc_read8 (e, GRUB_EHCI_EHCC_CAPLEN);
493 #ifndef GRUB_HAVE_UNALIGNED_ACCESS
494 if (caplen & (sizeof (grub_uint32_t) - 1))
496 grub_dprintf ("ehci", "Unaligned caplen\n");
499 e->iobase = ((volatile grub_uint32_t *) e->iobase_ehcc
500 + (caplen / sizeof (grub_uint32_t)));
502 e->iobase = (volatile grub_uint32_t *)
503 ((grub_uint8_t *) e->iobase_ehcc + caplen);
506 grub_dprintf ("ehci",
507 "EHCI grub_ehci_pci_iter: iobase of oper. regs: %08x\n",
508 (grub_addr_t) e->iobase_ehcc + caplen);
509 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: COMMAND: %08x\n",
510 grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
511 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: STATUS: %08x\n",
512 grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS));
513 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: INTERRUPT: %08x\n",
514 grub_ehci_oper_read32 (e, GRUB_EHCI_INTERRUPT));
515 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: FRAME_INDEX: %08x\n",
516 grub_ehci_oper_read32 (e, GRUB_EHCI_FRAME_INDEX));
517 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: FL_BASE: %08x\n",
518 grub_ehci_oper_read32 (e, GRUB_EHCI_FL_BASE));
519 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CUR_AL_ADDR: %08x\n",
520 grub_ehci_oper_read32 (e, GRUB_EHCI_CUR_AL_ADDR));
521 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CONFIG_FLAG: %08x\n",
522 grub_ehci_oper_read32 (e, GRUB_EHCI_CONFIG_FLAG));
524 /* Check format of data structures requested by EHCI */
525 /* XXX: In fact it is not used at any place, it is prepared for future
526 * This implementation uses 32-bits pointers only */
527 e->flag64 = ((grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_CPARAMS)
528 & GRUB_EHCI_CPARAMS_64BIT) != 0);
530 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: flag64=%d\n", e->flag64);
532 /* Reserve a page for the frame list - it is accurate for max.
533 * possible size of framelist. But currently it is not used. */
534 e->framelist_chunk = grub_memalign_dma32 (4096, 4096);
535 if (!e->framelist_chunk)
537 e->framelist_virt = grub_dma_get_virt (e->framelist_chunk);
538 e->framelist_phys = grub_dma_get_phys (e->framelist_chunk);
539 grub_memset ((void *) e->framelist_virt, 0, 4096);
541 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: framelist mem=%p. OK\n",
544 /* Allocate memory for the QHs and register it in "e". */
545 e->qh_chunk = grub_memalign_dma32 (4096,
546 sizeof (struct grub_ehci_qh) *
550 e->qh_virt = (grub_ehci_qh_t) grub_dma_get_virt (e->qh_chunk);
551 e->qh_phys = grub_dma_get_phys (e->qh_chunk);
552 grub_memset ((void *) e->qh_virt, 0,
553 sizeof (struct grub_ehci_qh) * GRUB_EHCI_N_QH);
555 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: QH mem=%p. OK\n",
558 /* Allocate memory for the TDs and register it in "e". */
559 e->td_chunk = grub_memalign_dma32 (4096,
560 sizeof (struct grub_ehci_td) *
564 e->td_virt = (grub_ehci_td_t) grub_dma_get_virt (e->td_chunk);
565 e->td_phys = grub_dma_get_phys (e->td_chunk);
566 grub_memset ((void *) e->td_virt, 0,
567 sizeof (struct grub_ehci_td) * GRUB_EHCI_N_TD);
569 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: TD mem=%p. OK\n",
572 /* Setup all frame list pointers. Since no isochronous transfers
573 are supported, they all point to the (same!) queue
574 head with index 0. */
575 fp = grub_cpu_to_le32 ((e->qh_phys & GRUB_EHCI_POINTER_MASK)
576 | GRUB_EHCI_HPTR_TYPE_QH);
577 for (i = 0; i < GRUB_EHCI_N_FRAMELIST; i++)
578 e->framelist_virt[i] = fp;
579 /* Prepare chain of all TDs and set Terminate in all TDs */
580 for (i = 0; i < (GRUB_EHCI_N_TD - 1); i++)
582 e->td_virt[i].link_td = e->td_phys + (i + 1) * sizeof (struct grub_ehci_td);
583 e->td_virt[i].next_td = grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
584 e->td_virt[i].alt_next_td = grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
586 e->td_virt[GRUB_EHCI_N_TD - 1].next_td =
587 grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
588 e->td_virt[GRUB_EHCI_N_TD - 1].alt_next_td =
589 grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
590 e->tdfree_virt = e->td_virt;
591 /* Set Terminate in first QH, which is used in framelist */
592 e->qh_virt[0].qh_hptr = grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE | GRUB_EHCI_HPTR_TYPE_QH);
593 e->qh_virt[0].td_overlay.next_td = grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
594 e->qh_virt[0].td_overlay.alt_next_td =
595 grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
596 /* Also set Halted bit in token */
597 e->qh_virt[0].td_overlay.token = grub_cpu_to_le32_compile_time (GRUB_EHCI_STATUS_HALTED);
598 /* Set the H bit in first QH used for AL */
599 e->qh_virt[1].ep_char = grub_cpu_to_le32_compile_time (GRUB_EHCI_H);
600 /* Set Terminate into TD in rest of QHs and set horizontal link
601 * pointer to itself - these QHs will be used for asynchronous
602 * schedule and they should have valid value in horiz. link */
603 for (i = 1; i < GRUB_EHCI_N_QH; i++)
605 e->qh_virt[i].qh_hptr =
606 grub_cpu_to_le32 ((grub_dma_virt2phys (&e->qh_virt[i],
608 GRUB_EHCI_POINTER_MASK) | GRUB_EHCI_HPTR_TYPE_QH);
609 e->qh_virt[i].td_overlay.next_td =
610 grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
611 e->qh_virt[i].td_overlay.alt_next_td =
612 grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
613 /* Also set Halted bit in token */
614 e->qh_virt[i].td_overlay.token =
615 grub_cpu_to_le32_compile_time (GRUB_EHCI_STATUS_HALTED);
618 /* Note: QH 0 and QH 1 are reserved and must not be used anywhere.
619 * QH 0 is used as empty QH for framelist
620 * QH 1 is used as starting empty QH for asynchronous schedule
621 * QH 1 must exist at any time because at least one QH linked to
622 * itself must exist in asynchronous schedule
623 * QH 1 has the H flag set to one */
625 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: QH/TD init. OK\n");
627 /* Now we can setup EHCI (maybe...) */
629 /* Check if EHCI is halted and halt it if not */
630 if (grub_ehci_halt (e) != GRUB_USB_ERR_NONE)
632 grub_error (GRUB_ERR_TIMEOUT,
633 "EHCI grub_ehci_pci_iter: EHCI halt timeout");
637 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: halted OK\n");
640 if (grub_ehci_reset (e) != GRUB_USB_ERR_NONE)
642 grub_error (GRUB_ERR_TIMEOUT,
643 "EHCI grub_ehci_pci_iter: EHCI reset timeout");
647 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: reset OK\n");
649 /* Setup list address registers */
650 grub_ehci_oper_write32 (e, GRUB_EHCI_FL_BASE, e->framelist_phys);
651 grub_ehci_oper_write32 (e, GRUB_EHCI_CUR_AL_ADDR,
652 grub_dma_virt2phys (&e->qh_virt[1],
655 /* Set ownership of root hub ports to EHCI */
656 grub_ehci_oper_write32 (e, GRUB_EHCI_CONFIG_FLAG, GRUB_EHCI_CF_EHCI_OWNER);
658 /* Enable both lists */
659 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
660 GRUB_EHCI_CMD_AS_ENABL
661 | GRUB_EHCI_CMD_PS_ENABL
662 | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
664 /* Now should be possible to power-up and enumerate ports etc. */
665 if ((grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS)
666 & GRUB_EHCI_SPARAMS_PPC) != 0)
667 { /* EHCI has port powering control */
668 /* Power on all ports */
669 n_ports = grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS)
670 & GRUB_EHCI_SPARAMS_N_PORTS;
671 for (i = 0; i < (int) n_ports; i++)
672 grub_ehci_oper_write32 (e, GRUB_EHCI_PORT_STAT_CMD + i * 4,
674 | grub_ehci_oper_read32 (e,
675 GRUB_EHCI_PORT_STAT_CMD
679 /* Ensure all commands are written */
680 grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND);
683 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
684 GRUB_EHCI_CMD_RUNSTOP
685 | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
687 /* Ensure command is written */
688 grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND);
690 /* Link to ehci now that initialisation is successful. */
696 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: OK at all\n");
698 grub_dprintf ("ehci",
699 "EHCI grub_ehci_pci_iter: iobase of oper. regs: %08x\n",
701 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: COMMAND: %08x\n",
702 grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
703 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: STATUS: %08x\n",
704 grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS));
705 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: INTERRUPT: %08x\n",
706 grub_ehci_oper_read32 (e, GRUB_EHCI_INTERRUPT));
707 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: FRAME_INDEX: %08x\n",
708 grub_ehci_oper_read32 (e, GRUB_EHCI_FRAME_INDEX));
709 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: FL_BASE: %08x\n",
710 grub_ehci_oper_read32 (e, GRUB_EHCI_FL_BASE));
711 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CUR_AL_ADDR: %08x\n",
712 grub_ehci_oper_read32 (e, GRUB_EHCI_CUR_AL_ADDR));
713 grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CONFIG_FLAG: %08x\n",
714 grub_ehci_oper_read32 (e, GRUB_EHCI_CONFIG_FLAG));
722 grub_dma_free ((void *) e->td_chunk);
724 grub_dma_free ((void *) e->qh_chunk);
725 if (e->framelist_chunk)
726 grub_dma_free (e->framelist_chunk);
734 grub_ehci_iterate (grub_usb_controller_iterate_hook_t hook, void *hook_data)
737 struct grub_usb_controller dev;
739 for (e = ehci; e; e = e->next)
742 if (hook (&dev, hook_data))
750 grub_ehci_setup_qh (grub_ehci_qh_t qh, grub_usb_transfer_t transfer)
752 grub_uint32_t ep_char = 0;
753 grub_uint32_t ep_cap = 0;
755 /* Note: Another part of code is responsible to this QH is
756 * Halted ! But it can be linked in AL, so we cannot erase or
757 * change qh_hptr ! */
758 /* We will not change any TD field because they should/must be
759 * in safe state from previous use. */
761 /* EP characteristic setup */
762 /* Currently not used NAK counter (RL=0),
763 * C bit set if EP is not HIGH speed and is control,
764 * Max Packet Length is taken from transfer structure,
765 * H bit = 0 (because QH[1] has this bit set),
766 * DTC bit set to 1 because we are using our own toggle bit control,
767 * SPEED is selected according to value from transfer structure,
768 * EP number is taken from transfer structure
769 * "I" bit must not be set,
770 * Device Address is taken from transfer structure
772 if ((transfer->dev->speed != GRUB_USB_SPEED_HIGH)
773 && (transfer->type == GRUB_USB_TRANSACTION_TYPE_CONTROL))
774 ep_char |= GRUB_EHCI_C;
775 ep_char |= (transfer->max << GRUB_EHCI_MAXPLEN_OFF)
776 & GRUB_EHCI_MAXPLEN_MASK;
777 ep_char |= GRUB_EHCI_DTC;
778 switch (transfer->dev->speed)
780 case GRUB_USB_SPEED_LOW:
781 ep_char |= GRUB_EHCI_SPEED_LOW;
783 case GRUB_USB_SPEED_FULL:
784 ep_char |= GRUB_EHCI_SPEED_FULL;
786 case GRUB_USB_SPEED_HIGH:
788 ep_char |= GRUB_EHCI_SPEED_HIGH;
789 /* XXX: How we will handle unknown value of speed? */
791 ep_char |= (transfer->endpoint << GRUB_EHCI_EP_NUM_OFF)
792 & GRUB_EHCI_EP_NUM_MASK;
793 ep_char |= transfer->devaddr & GRUB_EHCI_DEVADDR_MASK;
794 qh->ep_char = grub_cpu_to_le32 (ep_char);
795 /* EP capabilities setup */
796 /* MULT field - we try to use max. number
797 * PortNumber - included now in device structure referenced
798 * inside transfer structure
799 * HubAddress - included now in device structure referenced
800 * inside transfer structure
801 * SplitCompletionMask - AFAIK it is ignored in asynchronous list,
802 * InterruptScheduleMask - AFAIK it should be zero in async. list */
803 ep_cap |= GRUB_EHCI_MULT_THREE;
804 ep_cap |= (transfer->dev->split_hubport << GRUB_EHCI_DEVPORT_OFF)
805 & GRUB_EHCI_DEVPORT_MASK;
806 ep_cap |= (transfer->dev->split_hubaddr << GRUB_EHCI_HUBADDR_OFF)
807 & GRUB_EHCI_HUBADDR_MASK;
808 if (transfer->dev->speed == GRUB_USB_SPEED_LOW
809 && transfer->type != GRUB_USB_TRANSACTION_TYPE_CONTROL)
811 ep_cap |= (1<<0) << GRUB_EHCI_SMASK_OFF;
812 ep_cap |= (7<<2) << GRUB_EHCI_CMASK_OFF;
814 qh->ep_cap = grub_cpu_to_le32 (ep_cap);
816 grub_dprintf ("ehci", "setup_qh: qh=%p, not changed: qh_hptr=%08x\n",
817 qh, grub_le_to_cpu32 (qh->qh_hptr));
818 grub_dprintf ("ehci", "setup_qh: ep_char=%08x, ep_cap=%08x\n",
820 grub_dprintf ("ehci", "setup_qh: end\n");
821 grub_dprintf ("ehci", "setup_qh: not changed: td_current=%08x\n",
822 grub_le_to_cpu32 (qh->td_current));
823 grub_dprintf ("ehci", "setup_qh: not changed: next_td=%08x\n",
824 grub_le_to_cpu32 (qh->td_overlay.next_td));
825 grub_dprintf ("ehci", "setup_qh: not changed: alt_next_td=%08x\n",
826 grub_le_to_cpu32 (qh->td_overlay.alt_next_td));
827 grub_dprintf ("ehci", "setup_qh: not changed: token=%08x\n",
828 grub_le_to_cpu32 (qh->td_overlay.token));
831 static grub_ehci_qh_t
832 grub_ehci_find_qh (struct grub_ehci *e, grub_usb_transfer_t transfer)
834 grub_uint32_t target, mask;
836 grub_ehci_qh_t qh = e->qh_virt;
838 grub_uint32_t qh_phys;
839 grub_uint32_t qh_terminate =
840 GRUB_EHCI_TERMINATE | GRUB_EHCI_HPTR_TYPE_QH;
841 grub_ehci_qh_t qh_iter;
843 /* Prepare part of EP Characteristic to find existing QH */
844 target = ((transfer->endpoint << GRUB_EHCI_EP_NUM_OFF) |
845 transfer->devaddr) & GRUB_EHCI_TARGET_MASK;
846 target = grub_cpu_to_le32 (target);
847 mask = grub_cpu_to_le32_compile_time (GRUB_EHCI_TARGET_MASK);
849 /* low speed interrupt transfers are linked to the periodic */
850 /* schedule, everything else to the asynchronous schedule */
851 if (transfer->dev->speed == GRUB_USB_SPEED_LOW
852 && transfer->type != GRUB_USB_TRANSACTION_TYPE_CONTROL)
857 /* First try to find existing QH with proper target in proper list */
858 qh_phys = grub_le_to_cpu32( head->qh_hptr );
859 if (qh_phys != qh_terminate)
860 qh_iter = grub_dma_phys2virt ( qh_phys & GRUB_EHCI_QHTDPTR_MASK,
867 (qh_phys != qh_terminate) && (qh_iter != NULL) &&
868 (qh_iter != head) && (i < GRUB_EHCI_N_QH);
871 if (target == (qh_iter->ep_char & mask))
873 /* Found proper existing (and linked) QH, do setup of QH */
874 grub_dprintf ("ehci", "find_qh: found, QH=%p\n", qh_iter);
875 grub_ehci_setup_qh (qh_iter, transfer);
880 qh_phys = grub_le_to_cpu32( qh_iter->qh_hptr );
881 if (qh_phys != qh_terminate)
882 qh_iter = grub_dma_phys2virt ( qh_phys & GRUB_EHCI_QHTDPTR_MASK,
888 /* variable "i" should be never equal to GRUB_EHCI_N_QH here */
889 if (i >= GRUB_EHCI_N_QH)
890 { /* Something very bad happened in QH list(s) ! */
891 grub_dprintf ("ehci", "find_qh: Mismatch in QH list! head=%p\n",
895 /* QH with target_addr does not exist, we have to find and add it */
896 for (i = 2; i < GRUB_EHCI_N_QH; i++) /* We ignore zero and first QH */
899 break; /* Found first not-allocated QH, finish */
902 /* Have we any free QH in array ? */
903 if (i >= GRUB_EHCI_N_QH) /* No. */
905 grub_dprintf ("ehci", "find_qh: end - no free QH\n");
908 grub_dprintf ("ehci", "find_qh: new, i=%d, QH=%p\n",
910 /* Currently we simply take next (current) QH in array, no allocation
911 * function is used. It should be no problem until we will need to
912 * de-allocate QHs of unplugged devices. */
913 /* We should preset new QH and link it into AL */
914 grub_ehci_setup_qh (&qh[i], transfer);
916 /* Linking - this new (last) QH will copy the QH from the head QH */
917 qh[i].qh_hptr = head->qh_hptr;
918 /* Linking - the head QH will point to this new QH */
919 head->qh_hptr = grub_cpu_to_le32 (GRUB_EHCI_HPTR_TYPE_QH
920 | grub_dma_virt2phys (&qh[i],
926 static grub_ehci_td_t
927 grub_ehci_alloc_td (struct grub_ehci *e)
931 /* Check if there is a Transfer Descriptor available. */
934 grub_dprintf ("ehci", "alloc_td: end - no free TD\n");
938 ret = e->tdfree_virt; /* Take current free TD */
939 /* Advance to next free TD in chain */
941 e->tdfree_virt = grub_dma_phys2virt (ret->link_td, e->td_chunk);
943 e->tdfree_virt = NULL;
944 ret->link_td = 0; /* Reset link_td in allocated TD */
949 grub_ehci_free_td (struct grub_ehci *e, grub_ehci_td_t td)
951 /* Chain new free TD & rest */
953 td->link_td = grub_dma_virt2phys (e->tdfree_virt, e->td_chunk);
956 e->tdfree_virt = td; /* Change address of first free TD */
960 grub_ehci_free_tds (struct grub_ehci *e, grub_ehci_td_t td,
961 grub_usb_transfer_t transfer, grub_size_t * actual)
963 int i; /* Index of TD in transfer */
964 grub_uint32_t token, to_transfer;
966 /* Note: Another part of code is responsible to this QH is
970 /* Free the TDs in this queue and set last_trans. */
973 grub_ehci_td_t tdprev;
975 token = grub_le_to_cpu32 (td->token);
976 to_transfer = (token & GRUB_EHCI_TOTAL_MASK) >> GRUB_EHCI_TOTAL_OFF;
978 /* Check state of TD - if it did not transfer
979 * whole data then set last_trans - it should be last executed TD
980 * in case when something went wrong. */
981 if (transfer && (td->size != to_transfer))
982 transfer->last_trans = i;
984 *actual += td->size - to_transfer;
989 td = grub_dma_phys2virt (td->link_td, e->td_chunk);
994 grub_ehci_free_td (e, tdprev);
997 /* Check if last_trans was set. If not and something was
998 * transferred (it should be all data in this case), set it
999 * to index of last TD, i.e. i-1 */
1000 if (transfer && (transfer->last_trans < 0) && (*actual != 0))
1001 transfer->last_trans = i - 1;
1003 /* XXX: Fix it: last_trans may be set to bad index.
1004 * Probably we should test more error flags to distinguish
1005 * if TD was at least partialy executed or not at all.
1006 * Generaly, we still could have problem with toggling because
1007 * EHCI can probably split transactions into smaller parts then
1008 * we defined in transaction even if we did not exceed MaxFrame
1009 * length - it probably could happen at the end of microframe (?)
1010 * and if the buffer is crossing page boundary (?). */
1013 static grub_ehci_td_t
1014 grub_ehci_transaction (struct grub_ehci *e,
1015 grub_transfer_type_t type,
1016 unsigned int toggle, grub_size_t size,
1017 grub_uint32_t data, grub_ehci_td_t td_alt)
1020 grub_uint32_t token;
1021 grub_uint32_t bufadr;
1024 /* Test of transfer size, it can be:
1025 * <= GRUB_EHCI_MAXBUFLEN if data aligned to page boundary
1026 * <= GRUB_EHCI_MAXBUFLEN - GRUB_EHCI_BUFPAGELEN if not aligned
1029 if ((((data % GRUB_EHCI_BUFPAGELEN) == 0)
1030 && (size > GRUB_EHCI_MAXBUFLEN))
1032 (((data % GRUB_EHCI_BUFPAGELEN) != 0)
1033 && (size > (GRUB_EHCI_MAXBUFLEN - GRUB_EHCI_BUFPAGELEN))))
1035 grub_error (GRUB_ERR_OUT_OF_MEMORY,
1036 "too long data buffer for EHCI transaction");
1040 /* Grab a free Transfer Descriptor and initialize it. */
1041 td = grub_ehci_alloc_td (e);
1044 grub_error (GRUB_ERR_OUT_OF_MEMORY,
1045 "no transfer descriptors available for EHCI transfer");
1049 grub_dprintf ("ehci",
1050 "transaction: type=%d, toggle=%d, size=%lu data=0x%x td=%p\n",
1051 type, toggle, (unsigned long) size, data, td);
1053 /* Fill whole TD by zeros */
1054 grub_memset ((void *) td, 0, sizeof (struct grub_ehci_td));
1056 /* Don't point to any TD yet, just terminate. */
1057 td->next_td = grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
1058 /* Set alternate pointer. When short packet occurs, alternate TD
1059 * will not be really fetched because it is not active. But don't
1060 * forget, EHCI will try to fetch alternate TD every scan of AL
1061 * until QH is halted. */
1062 td->alt_next_td = grub_cpu_to_le32 (grub_dma_virt2phys (td_alt,
1065 * TOGGLE - according to toggle
1067 * Interrupt On Complete = FALSE, we don't need IRQ
1069 * Error Counter = max. value = 3
1070 * PID Code - according to type
1072 * ACTIVE bit should be set to one
1073 * SPLIT TRANS. STATE bit should be zero. It is ignored
1074 * in HIGH speed transaction, and should be zero for LOW/FULL
1075 * speed to indicate state Do Split Transaction */
1076 token = toggle ? GRUB_EHCI_TOGGLE : 0;
1077 token |= (size << GRUB_EHCI_TOTAL_OFF) & GRUB_EHCI_TOTAL_MASK;
1078 token |= GRUB_EHCI_CERR_3;
1081 case GRUB_USB_TRANSFER_TYPE_IN:
1082 token |= GRUB_EHCI_PIDCODE_IN;
1084 case GRUB_USB_TRANSFER_TYPE_OUT:
1085 token |= GRUB_EHCI_PIDCODE_OUT;
1087 case GRUB_USB_TRANSFER_TYPE_SETUP:
1088 token |= GRUB_EHCI_PIDCODE_SETUP;
1090 default: /* XXX: Should not happen, but what to do if it does ? */
1093 token |= GRUB_EHCI_STATUS_ACTIVE;
1094 td->token = grub_cpu_to_le32 (token);
1096 /* Fill buffer pointers according to size */
1098 td->buffer_page[0] = grub_cpu_to_le32 (bufadr);
1099 bufadr = ((bufadr / GRUB_EHCI_BUFPAGELEN) + 1) * GRUB_EHCI_BUFPAGELEN;
1100 for (i = 1; ((bufadr - data) < size) && (i < GRUB_EHCI_TD_BUF_PAGES); i++)
1102 td->buffer_page[i] = grub_cpu_to_le32 (bufadr & GRUB_EHCI_BUFPTR_MASK);
1103 bufadr = ((bufadr / GRUB_EHCI_BUFPAGELEN) + 1) * GRUB_EHCI_BUFPAGELEN;
1106 /* Remember data size for future use... */
1107 td->size = (grub_uint32_t) size;
1109 grub_dprintf ("ehci", "td=%p\n", td);
1110 grub_dprintf ("ehci", "HW: next_td=%08x, alt_next_td=%08x\n",
1111 grub_le_to_cpu32 (td->next_td),
1112 grub_le_to_cpu32 (td->alt_next_td));
1113 grub_dprintf ("ehci", "HW: token=%08x, buffer[0]=%08x\n",
1114 grub_le_to_cpu32 (td->token),
1115 grub_le_to_cpu32 (td->buffer_page[0]));
1116 grub_dprintf ("ehci", "HW: buffer[1]=%08x, buffer[2]=%08x\n",
1117 grub_le_to_cpu32 (td->buffer_page[1]),
1118 grub_le_to_cpu32 (td->buffer_page[2]));
1119 grub_dprintf ("ehci", "HW: buffer[3]=%08x, buffer[4]=%08x\n",
1120 grub_le_to_cpu32 (td->buffer_page[3]),
1121 grub_le_to_cpu32 (td->buffer_page[4]));
1122 grub_dprintf ("ehci", "link_td=%08x, size=%08x\n",
1123 td->link_td, td->size);
1128 struct grub_ehci_transfer_controller_data
1130 grub_ehci_qh_t qh_virt;
1131 grub_ehci_td_t td_first_virt;
1132 grub_ehci_td_t td_alt_virt;
1133 grub_ehci_td_t td_last_virt;
1134 grub_uint32_t td_last_phys;
1137 static grub_usb_err_t
1138 grub_ehci_setup_transfer (grub_usb_controller_t dev,
1139 grub_usb_transfer_t transfer)
1141 struct grub_ehci *e = (struct grub_ehci *) dev->data;
1142 grub_ehci_td_t td = NULL;
1143 grub_ehci_td_t td_prev = NULL;
1145 struct grub_ehci_transfer_controller_data *cdata;
1146 grub_uint32_t status;
1148 sync_all_caches (e);
1150 /* Check if EHCI is running and AL is enabled */
1151 status = grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS);
1152 if ((status & GRUB_EHCI_ST_HC_HALTED) != 0)
1153 /* XXX: Fix it: Currently we don't do anything to restart EHCI */
1155 grub_dprintf ("ehci", "setup_transfer: halted, status = 0x%x\n",
1157 return GRUB_USB_ERR_INTERNAL;
1159 status = grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS);
1161 & (GRUB_EHCI_ST_AS_STATUS | GRUB_EHCI_ST_PS_STATUS)) == 0)
1162 /* XXX: Fix it: Currently we don't do anything to restart EHCI */
1164 grub_dprintf ("ehci", "setup_transfer: no AS/PS, status = 0x%x\n",
1166 return GRUB_USB_ERR_INTERNAL;
1169 /* Allocate memory for controller transfer data. */
1170 cdata = grub_malloc (sizeof (*cdata));
1172 return GRUB_USB_ERR_INTERNAL;
1173 cdata->td_first_virt = NULL;
1175 /* Allocate a queue head for the transfer queue. */
1176 cdata->qh_virt = grub_ehci_find_qh (e, transfer);
1177 if (!cdata->qh_virt)
1179 grub_dprintf ("ehci", "setup_transfer: no QH\n");
1181 return GRUB_USB_ERR_INTERNAL;
1184 /* To detect short packet we need some additional "alternate" TD,
1185 * allocate it first. */
1186 cdata->td_alt_virt = grub_ehci_alloc_td (e);
1187 if (!cdata->td_alt_virt)
1189 grub_dprintf ("ehci", "setup_transfer: no TDs\n");
1191 return GRUB_USB_ERR_INTERNAL;
1193 /* Fill whole alternate TD by zeros (= inactive) and set
1194 * Terminate bits and Halt bit */
1195 grub_memset ((void *) cdata->td_alt_virt, 0, sizeof (struct grub_ehci_td));
1196 cdata->td_alt_virt->next_td = grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
1197 cdata->td_alt_virt->alt_next_td = grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
1198 cdata->td_alt_virt->token = grub_cpu_to_le32_compile_time (GRUB_EHCI_STATUS_HALTED);
1200 /* Allocate appropriate number of TDs and set */
1201 for (i = 0; i < transfer->transcnt; i++)
1203 grub_usb_transaction_t tr = &transfer->transactions[i];
1205 td = grub_ehci_transaction (e, tr->pid, tr->toggle, tr->size,
1206 tr->data, cdata->td_alt_virt);
1208 if (!td) /* de-allocate and free all */
1210 grub_size_t actual = 0;
1212 if (cdata->td_first_virt)
1213 grub_ehci_free_tds (e, cdata->td_first_virt, NULL, &actual);
1216 grub_dprintf ("ehci", "setup_transfer: no TD\n");
1217 return GRUB_USB_ERR_INTERNAL;
1220 /* Register new TD in cdata or previous TD */
1221 if (!cdata->td_first_virt)
1222 cdata->td_first_virt = td;
1225 td_prev->link_td = grub_dma_virt2phys (td, e->td_chunk);
1227 grub_cpu_to_le32 (grub_dma_virt2phys (td, e->td_chunk));
1232 /* Remember last TD */
1233 cdata->td_last_virt = td;
1234 cdata->td_last_phys = grub_dma_virt2phys (td, e->td_chunk);
1235 /* Last TD should not have set alternate TD */
1236 cdata->td_last_virt->alt_next_td = grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
1238 grub_dprintf ("ehci", "setup_transfer: cdata=%p, qh=%p\n",
1239 cdata,cdata->qh_virt);
1240 grub_dprintf ("ehci", "setup_transfer: td_first=%p, td_alt=%p\n",
1241 cdata->td_first_virt,
1242 cdata->td_alt_virt);
1243 grub_dprintf ("ehci", "setup_transfer: td_last=%p\n",
1244 cdata->td_last_virt);
1246 /* Start transfer: */
1247 /* Unlink possible alternate pointer in QH */
1248 cdata->qh_virt->td_overlay.alt_next_td =
1249 grub_cpu_to_le32_compile_time (GRUB_EHCI_TERMINATE);
1250 /* Link new TDs with QH via next_td */
1251 cdata->qh_virt->td_overlay.next_td =
1252 grub_cpu_to_le32 (grub_dma_virt2phys
1253 (cdata->td_first_virt, e->td_chunk));
1254 /* Reset Active and Halted bits in QH to activate Advance Queue,
1255 * i.e. reset token */
1256 cdata->qh_virt->td_overlay.token = grub_cpu_to_le32_compile_time (0);
1258 sync_all_caches (e);
1261 transfer->controller_data = cdata;
1263 return GRUB_USB_ERR_NONE;
1266 /* This function expects QH is not active.
1267 * Function set Halt bit in QH TD overlay and possibly prints
1268 * necessary debug information. */
1270 grub_ehci_pre_finish_transfer (grub_usb_transfer_t transfer)
1272 struct grub_ehci_transfer_controller_data *cdata =
1273 transfer->controller_data;
1275 /* Collect debug data here if necessary */
1277 /* Set Halt bit in not active QH. AL will not attempt to do
1278 * Advance Queue on QH with Halt bit set, i.e., we can then
1279 * safely manipulate with QH TD part. */
1280 cdata->qh_virt->td_overlay.token = (cdata->qh_virt->td_overlay.token
1282 grub_cpu_to_le32_compile_time
1283 (GRUB_EHCI_STATUS_HALTED)) &
1284 grub_cpu_to_le32_compile_time (~GRUB_EHCI_STATUS_ACTIVE);
1286 /* Print debug data here if necessary */
1290 static grub_usb_err_t
1291 grub_ehci_parse_notrun (grub_usb_controller_t dev,
1292 grub_usb_transfer_t transfer, grub_size_t * actual)
1294 struct grub_ehci *e = dev->data;
1295 struct grub_ehci_transfer_controller_data *cdata =
1296 transfer->controller_data;
1298 grub_dprintf ("ehci", "parse_notrun: info\n");
1300 /* QH can be in any state in this case. */
1301 /* But EHCI or AL is not running, so QH is surely not active
1302 * even if it has Active bit set... */
1303 grub_ehci_pre_finish_transfer (transfer);
1304 grub_ehci_free_tds (e, cdata->td_first_virt, transfer, actual);
1305 grub_ehci_free_td (e, cdata->td_alt_virt);
1308 sync_all_caches (e);
1310 /* Additionally, do something with EHCI to make it running (what?) */
1311 /* Try enable EHCI and AL */
1312 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
1313 GRUB_EHCI_CMD_RUNSTOP | GRUB_EHCI_CMD_AS_ENABL
1314 | GRUB_EHCI_CMD_PS_ENABL
1315 | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
1316 /* Ensure command is written */
1317 grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND);
1319 return GRUB_USB_ERR_UNRECOVERABLE;
1322 static grub_usb_err_t
1323 grub_ehci_parse_halt (grub_usb_controller_t dev,
1324 grub_usb_transfer_t transfer, grub_size_t * actual)
1326 struct grub_ehci *e = dev->data;
1327 struct grub_ehci_transfer_controller_data *cdata =
1328 transfer->controller_data;
1329 grub_uint32_t token;
1330 grub_usb_err_t err = GRUB_USB_ERR_NAK;
1332 /* QH should be halted and not active in this case. */
1334 grub_dprintf ("ehci", "parse_halt: info\n");
1336 /* Remember token before call pre-finish function */
1337 token = grub_le_to_cpu32 (cdata->qh_virt->td_overlay.token);
1339 /* Do things like in normal finish */
1340 grub_ehci_pre_finish_transfer (transfer);
1341 grub_ehci_free_tds (e, cdata->td_first_virt, transfer, actual);
1342 grub_ehci_free_td (e, cdata->td_alt_virt);
1345 sync_all_caches (e);
1347 /* Evaluation of error code - currently we don't have GRUB USB error
1348 * codes for some EHCI states, GRUB_USB_ERR_DATA is used for them.
1349 * Order of evaluation is critical, specially bubble/stall. */
1350 if ((token & GRUB_EHCI_STATUS_BABBLE) != 0)
1351 err = GRUB_USB_ERR_BABBLE;
1352 else if ((token & GRUB_EHCI_CERR_MASK) != 0)
1353 err = GRUB_USB_ERR_STALL;
1354 else if ((token & GRUB_EHCI_STATUS_TRANERR) != 0)
1355 err = GRUB_USB_ERR_DATA;
1356 else if ((token & GRUB_EHCI_STATUS_BUFERR) != 0)
1357 err = GRUB_USB_ERR_DATA;
1358 else if ((token & GRUB_EHCI_STATUS_MISSDMF) != 0)
1359 err = GRUB_USB_ERR_DATA;
1364 static grub_usb_err_t
1365 grub_ehci_parse_success (grub_usb_controller_t dev,
1366 grub_usb_transfer_t transfer, grub_size_t * actual)
1368 struct grub_ehci *e = dev->data;
1369 struct grub_ehci_transfer_controller_data *cdata =
1370 transfer->controller_data;
1372 grub_dprintf ("ehci", "parse_success: info\n");
1374 /* QH should be not active in this case, but it is not halted. */
1375 grub_ehci_pre_finish_transfer (transfer);
1376 grub_ehci_free_tds (e, cdata->td_first_virt, transfer, actual);
1377 grub_ehci_free_td (e, cdata->td_alt_virt);
1380 sync_all_caches (e);
1382 return GRUB_USB_ERR_NONE;
1386 static grub_usb_err_t
1387 grub_ehci_check_transfer (grub_usb_controller_t dev,
1388 grub_usb_transfer_t transfer, grub_size_t * actual)
1390 struct grub_ehci *e = dev->data;
1391 struct grub_ehci_transfer_controller_data *cdata =
1392 transfer->controller_data;
1393 grub_uint32_t token, token_ftd;
1395 sync_all_caches (e);
1397 grub_dprintf ("ehci",
1398 "check_transfer: EHCI STATUS=%08x, cdata=%p, qh=%p\n",
1399 grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS),
1400 cdata, cdata->qh_virt);
1401 grub_dprintf ("ehci", "check_transfer: qh_hptr=%08x, ep_char=%08x\n",
1402 grub_le_to_cpu32 (cdata->qh_virt->qh_hptr),
1403 grub_le_to_cpu32 (cdata->qh_virt->ep_char));
1404 grub_dprintf ("ehci", "check_transfer: ep_cap=%08x, td_current=%08x\n",
1405 grub_le_to_cpu32 (cdata->qh_virt->ep_cap),
1406 grub_le_to_cpu32 (cdata->qh_virt->td_current));
1407 grub_dprintf ("ehci", "check_transfer: next_td=%08x, alt_next_td=%08x\n",
1408 grub_le_to_cpu32 (cdata->qh_virt->td_overlay.next_td),
1409 grub_le_to_cpu32 (cdata->qh_virt->td_overlay.alt_next_td));
1410 grub_dprintf ("ehci", "check_transfer: token=%08x, buffer[0]=%08x\n",
1411 grub_le_to_cpu32 (cdata->qh_virt->td_overlay.token),
1412 grub_le_to_cpu32 (cdata->qh_virt->td_overlay.buffer_page[0]));
1414 /* Check if EHCI is running and AL is enabled */
1415 if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)
1416 & GRUB_EHCI_ST_HC_HALTED) != 0)
1417 return grub_ehci_parse_notrun (dev, transfer, actual);
1418 if ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)
1419 & (GRUB_EHCI_ST_AS_STATUS | GRUB_EHCI_ST_PS_STATUS)) == 0)
1420 return grub_ehci_parse_notrun (dev, transfer, actual);
1422 token = grub_le_to_cpu32 (cdata->qh_virt->td_overlay.token);
1423 /* If the transfer consist from only one TD, we should check */
1424 /* if the TD was really executed and deactivated - to prevent */
1425 /* false detection of transfer finish. */
1426 token_ftd = grub_le_to_cpu32 (cdata->td_first_virt->token);
1428 /* Detect QH halted */
1429 if ((token & GRUB_EHCI_STATUS_HALTED) != 0)
1430 return grub_ehci_parse_halt (dev, transfer, actual);
1432 /* Detect QH not active - QH is not active and no next TD */
1433 if (token && ((token & GRUB_EHCI_STATUS_ACTIVE) == 0)
1434 && ((token_ftd & GRUB_EHCI_STATUS_ACTIVE) == 0))
1436 /* It could be finish at all or short packet condition */
1437 if ((grub_le_to_cpu32 (cdata->qh_virt->td_overlay.next_td)
1438 & GRUB_EHCI_TERMINATE) &&
1439 ((grub_le_to_cpu32 (cdata->qh_virt->td_current)
1440 & GRUB_EHCI_QHTDPTR_MASK) == cdata->td_last_phys))
1442 return grub_ehci_parse_success (dev, transfer, actual);
1443 else if ((token & GRUB_EHCI_TOTAL_MASK) != 0)
1444 /* Short packet condition */
1445 /* But currently we don't handle it - higher level will do it */
1446 return grub_ehci_parse_success (dev, transfer, actual);
1449 return GRUB_USB_ERR_WAIT;
1452 static grub_usb_err_t
1453 grub_ehci_cancel_transfer (grub_usb_controller_t dev,
1454 grub_usb_transfer_t transfer)
1456 struct grub_ehci *e = dev->data;
1457 struct grub_ehci_transfer_controller_data *cdata =
1458 transfer->controller_data;
1461 grub_uint64_t maxtime;
1462 grub_uint32_t qh_phys;
1464 sync_all_caches (e);
1466 grub_uint32_t interrupt =
1467 cdata->qh_virt->ep_cap & GRUB_EHCI_SMASK_MASK;
1469 /* QH can be active and should be de-activated and halted */
1471 grub_dprintf ("ehci", "cancel_transfer: begin\n");
1473 /* First check if EHCI is running - if not, there is no problem */
1474 /* to cancel any transfer. Or, if transfer is asynchronous, check */
1475 /* if AL is enabled - if not, transfer can be canceled also. */
1476 if (((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) &
1477 GRUB_EHCI_ST_HC_HALTED) != 0) ||
1478 (!interrupt && ((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS) &
1479 (GRUB_EHCI_ST_AS_STATUS | GRUB_EHCI_ST_PS_STATUS)) == 0)))
1481 grub_ehci_pre_finish_transfer (transfer);
1482 grub_ehci_free_tds (e, cdata->td_first_virt, transfer, &actual);
1483 grub_ehci_free_td (e, cdata->td_alt_virt);
1485 sync_all_caches (e);
1486 grub_dprintf ("ehci", "cancel_transfer: end - EHCI not running\n");
1487 return GRUB_USB_ERR_NONE;
1490 /* EHCI and (AL or SL) are running. What to do? */
1491 /* Try to Halt QH via de-scheduling QH. */
1492 /* Find index of previous QH */
1493 qh_phys = grub_dma_virt2phys(cdata->qh_virt, e->qh_chunk);
1494 for (i = 0; i < GRUB_EHCI_N_QH; i++)
1496 if ((grub_le_to_cpu32(e->qh_virt[i].qh_hptr)
1497 & GRUB_EHCI_QHTDPTR_MASK) == qh_phys)
1500 if (i == GRUB_EHCI_N_QH)
1502 grub_printf ("%s: prev not found, queues are corrupt\n", __func__);
1503 return GRUB_USB_ERR_UNRECOVERABLE;
1505 /* Unlink QH from AL */
1506 e->qh_virt[i].qh_hptr = cdata->qh_virt->qh_hptr;
1508 sync_all_caches (e);
1510 /* If this is an interrupt transfer, we just wait for the periodic
1511 * schedule to advance a few times and then assume that the EHCI
1512 * controller has read the updated QH. */
1513 if (cdata->qh_virt->ep_cap & GRUB_EHCI_SMASK_MASK)
1515 grub_millisleep(20);
1519 /* For the asynchronous schedule we use the advance doorbell to find
1520 * out when the EHCI controller has read the updated QH. */
1522 /* Ring the doorbell */
1523 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
1524 GRUB_EHCI_CMD_AS_ADV_D
1525 | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
1526 /* Ensure command is written */
1527 grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND);
1528 /* Wait answer with timeout */
1529 maxtime = grub_get_time_ms () + 2;
1530 while (((grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS)
1531 & GRUB_EHCI_ST_AS_ADVANCE) == 0)
1532 && (grub_get_time_ms () < maxtime));
1534 /* We do not detect the timeout because if timeout occurs, it most
1535 * probably means something wrong with EHCI - maybe stopped etc. */
1537 /* Shut up the doorbell */
1538 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
1539 ~GRUB_EHCI_CMD_AS_ADV_D
1540 & grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
1541 grub_ehci_oper_write32 (e, GRUB_EHCI_STATUS,
1542 GRUB_EHCI_ST_AS_ADVANCE
1543 | grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS));
1544 /* Ensure command is written */
1545 grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS);
1548 /* Now is QH out of AL and we can do anything with it... */
1549 grub_ehci_pre_finish_transfer (transfer);
1550 grub_ehci_free_tds (e, cdata->td_first_virt, transfer, &actual);
1551 grub_ehci_free_td (e, cdata->td_alt_virt);
1553 /* "Free" the QH - link it to itself */
1554 cdata->qh_virt->ep_char = 0;
1555 cdata->qh_virt->qh_hptr =
1556 grub_cpu_to_le32 ((grub_dma_virt2phys (cdata->qh_virt,
1558 & GRUB_EHCI_POINTER_MASK) | GRUB_EHCI_HPTR_TYPE_QH);
1562 grub_dprintf ("ehci", "cancel_transfer: end\n");
1564 sync_all_caches (e);
1566 return GRUB_USB_ERR_NONE;
1570 grub_ehci_hubports (grub_usb_controller_t dev)
1572 struct grub_ehci *e = (struct grub_ehci *) dev->data;
1573 grub_uint32_t portinfo;
1575 portinfo = grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS)
1576 & GRUB_EHCI_SPARAMS_N_PORTS;
1577 grub_dprintf ("ehci", "root hub ports=%d\n", portinfo);
1581 static grub_usb_err_t
1582 grub_ehci_portstatus (grub_usb_controller_t dev,
1583 unsigned int port, unsigned int enable)
1585 struct grub_ehci *e = (struct grub_ehci *) dev->data;
1586 grub_uint64_t endtime;
1588 grub_dprintf ("ehci", "portstatus: EHCI STATUS: %08x\n",
1589 grub_ehci_oper_read32 (e, GRUB_EHCI_STATUS));
1590 grub_dprintf ("ehci",
1591 "portstatus: begin, iobase=%p, port=%d, status=0x%02x\n",
1592 e->iobase, port, grub_ehci_port_read (e, port));
1594 /* In any case we need to disable port:
1595 * - if enable==false - we should disable port
1596 * - if enable==true we will do the reset and the specification says
1597 * PortEnable should be FALSE in such case */
1598 /* Disable the port and wait for it. */
1599 grub_ehci_port_resbits (e, port, GRUB_EHCI_PORT_ENABLED);
1600 endtime = grub_get_time_ms () + 1000;
1601 while (grub_ehci_port_read (e, port) & GRUB_EHCI_PORT_ENABLED)
1602 if (grub_get_time_ms () > endtime)
1603 return GRUB_USB_ERR_TIMEOUT;
1605 if (!enable) /* We don't need reset port */
1607 grub_dprintf ("ehci", "portstatus: Disabled.\n");
1608 grub_dprintf ("ehci", "portstatus: end, status=0x%02x\n",
1609 grub_ehci_port_read (e, port));
1610 return GRUB_USB_ERR_NONE;
1613 grub_dprintf ("ehci", "portstatus: enable\n");
1615 grub_boot_time ("Resetting port %d", port);
1617 /* Now we will do reset - if HIGH speed device connected, it will
1618 * result in Enabled state, otherwise port remains disabled. */
1619 /* Set RESET bit for 50ms */
1620 grub_ehci_port_setbits (e, port, GRUB_EHCI_PORT_RESET);
1621 grub_millisleep (50);
1623 /* Reset RESET bit and wait for the end of reset */
1624 grub_ehci_port_resbits (e, port, GRUB_EHCI_PORT_RESET);
1625 endtime = grub_get_time_ms () + 1000;
1626 while (grub_ehci_port_read (e, port) & GRUB_EHCI_PORT_RESET)
1627 if (grub_get_time_ms () > endtime)
1628 return GRUB_USB_ERR_TIMEOUT;
1629 grub_boot_time ("Port %d reset", port);
1630 /* Remember "we did the reset" - needed by detect_dev */
1631 e->reset |= (1 << port);
1632 /* Test if port enabled, i.e. HIGH speed device connected */
1633 if ((grub_ehci_port_read (e, port) & GRUB_EHCI_PORT_ENABLED) != 0) /* yes! */
1635 grub_dprintf ("ehci", "portstatus: Enabled!\n");
1636 /* "Reset recovery time" (USB spec.) */
1637 grub_millisleep (10);
1641 /* FULL speed device connected - change port ownership.
1642 * It results in disconnected state of this EHCI port. */
1643 grub_ehci_port_setbits (e, port, GRUB_EHCI_PORT_OWNER);
1644 return GRUB_USB_ERR_BADDEVICE;
1647 /* XXX: Fix it! There is possible problem - we can say to calling
1648 * function that we lost device if it is FULL speed onlu via
1649 * return value <> GRUB_ERR_NONE. It (maybe) displays also error
1650 * message on screen - but this situation is not error, it is normal
1653 grub_dprintf ("ehci", "portstatus: end, status=0x%02x\n",
1654 grub_ehci_port_read (e, port));
1656 return GRUB_USB_ERR_NONE;
1659 static grub_usb_speed_t
1660 grub_ehci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
1662 struct grub_ehci *e = (struct grub_ehci *) dev->data;
1663 grub_uint32_t status, line_state;
1665 status = grub_ehci_port_read (e, port);
1667 /* Connect Status Change bit - it detects change of connection */
1668 if (status & GRUB_EHCI_PORT_CONNECT_CH)
1671 /* Reset bit Connect Status Change */
1672 grub_ehci_port_setbits (e, port, GRUB_EHCI_PORT_CONNECT_CH);
1677 if (!(status & GRUB_EHCI_PORT_CONNECT))
1678 { /* We should reset related "reset" flag in not connected state */
1679 e->reset &= ~(1 << port);
1680 return GRUB_USB_SPEED_NONE;
1682 /* Detected connected state, so we should return speed.
1683 * But we can detect only LOW speed device and only at connection
1684 * time when PortEnabled=FALSE. FULL / HIGH speed detection is made
1685 * later by EHCI-specific reset procedure.
1686 * Another thing - if detected speed is LOW at connection time,
1687 * we should change port ownership to companion controller.
1689 * 1. If we detect connected and enabled and EHCI-owned port,
1690 * we can say it is HIGH speed.
1691 * 2. If we detect connected and not EHCI-owned port, we can say
1692 * NONE speed, because such devices are not handled by EHCI.
1693 * 3. If we detect connected, not enabled but reset port, we can say
1694 * NONE speed, because it means FULL device connected to port and
1695 * such devices are not handled by EHCI.
1696 * 4. If we detect connected, not enabled and not reset port, which
1697 * has line state != "K", we will say HIGH - it could be FULL or HIGH
1698 * device, we will see it later after end of EHCI-specific reset
1700 * 5. If we detect connected, not enabled and not reset port, which
1701 * has line state == "K", we can say NONE speed, because LOW speed
1702 * device is connected and we should change port ownership. */
1703 if ((status & GRUB_EHCI_PORT_ENABLED) != 0) /* Port already enabled, return high speed. */
1704 return GRUB_USB_SPEED_HIGH;
1705 if ((status & GRUB_EHCI_PORT_OWNER) != 0) /* EHCI is not port owner */
1706 return GRUB_USB_SPEED_NONE; /* EHCI driver is ignoring this port. */
1707 if ((e->reset & (1 << port)) != 0) /* Port reset was done = FULL speed */
1708 return GRUB_USB_SPEED_NONE; /* EHCI driver is ignoring this port. */
1709 else /* Port connected but not enabled - test port speed. */
1711 line_state = status & GRUB_EHCI_PORT_LINE_STAT;
1712 if (line_state != GRUB_EHCI_PORT_LINE_LOWSP)
1713 return GRUB_USB_SPEED_HIGH;
1714 /* Detected LOW speed device, we should change
1716 * XXX: Fix it!: There should be test if related companion
1717 * controler is available ! And what to do if it does not exist ? */
1718 grub_ehci_port_setbits (e, port, GRUB_EHCI_PORT_OWNER);
1719 return GRUB_USB_SPEED_NONE; /* Ignore this port */
1720 /* Note: Reset of PORT_OWNER bit is done by EHCI HW when
1721 * device is really disconnected from port.
1722 * Don't do PORT_OWNER bit reset by SW when not connected signal
1723 * is detected in port register ! */
1728 grub_ehci_restore_hw (void)
1730 struct grub_ehci *e;
1731 grub_uint32_t n_ports;
1734 /* We should re-enable all EHCI HW similarly as on inithw */
1735 for (e = ehci; e; e = e->next)
1737 /* Check if EHCI is halted and halt it if not */
1738 if (grub_ehci_halt (e) != GRUB_USB_ERR_NONE)
1739 grub_error (GRUB_ERR_TIMEOUT, "restore_hw: EHCI halt timeout");
1742 if (grub_ehci_reset (e) != GRUB_USB_ERR_NONE)
1743 grub_error (GRUB_ERR_TIMEOUT, "restore_hw: EHCI reset timeout");
1745 /* Setup some EHCI registers and enable EHCI */
1746 grub_ehci_oper_write32 (e, GRUB_EHCI_FL_BASE, e->framelist_phys);
1747 grub_ehci_oper_write32 (e, GRUB_EHCI_CUR_AL_ADDR,
1748 grub_dma_virt2phys (&e->qh_virt[1],
1750 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
1751 GRUB_EHCI_CMD_RUNSTOP |
1752 grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
1754 /* Set ownership of root hub ports to EHCI */
1755 grub_ehci_oper_write32 (e, GRUB_EHCI_CONFIG_FLAG,
1756 GRUB_EHCI_CF_EHCI_OWNER);
1758 /* Enable asynchronous list */
1759 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
1760 GRUB_EHCI_CMD_AS_ENABL
1761 | GRUB_EHCI_CMD_PS_ENABL
1762 | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
1764 /* Now should be possible to power-up and enumerate ports etc. */
1765 if ((grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS)
1766 & GRUB_EHCI_SPARAMS_PPC) != 0)
1767 { /* EHCI has port powering control */
1768 /* Power on all ports */
1769 n_ports = grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_SPARAMS)
1770 & GRUB_EHCI_SPARAMS_N_PORTS;
1771 for (i = 0; i < (int) n_ports; i++)
1772 grub_ehci_oper_write32 (e, GRUB_EHCI_PORT_STAT_CMD + i * 4,
1773 GRUB_EHCI_PORT_POWER
1774 | grub_ehci_oper_read32 (e,
1775 GRUB_EHCI_PORT_STAT_CMD
1780 return GRUB_ERR_NONE;
1784 grub_ehci_fini_hw (int noreturn __attribute__ ((unused)))
1786 struct grub_ehci *e;
1788 /* We should disable all EHCI HW to prevent any DMA access etc. */
1789 for (e = ehci; e; e = e->next)
1791 /* Disable both lists */
1792 grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
1793 ~(GRUB_EHCI_CMD_AS_ENABL | GRUB_EHCI_CMD_PS_ENABL)
1794 & grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
1796 /* Check if EHCI is halted and halt it if not */
1800 grub_ehci_reset (e);
1803 return GRUB_ERR_NONE;
1806 static struct grub_usb_controller_dev usb_controller = {
1808 .iterate = grub_ehci_iterate,
1809 .setup_transfer = grub_ehci_setup_transfer,
1810 .check_transfer = grub_ehci_check_transfer,
1811 .cancel_transfer = grub_ehci_cancel_transfer,
1812 .hubports = grub_ehci_hubports,
1813 .portstatus = grub_ehci_portstatus,
1814 .detect_dev = grub_ehci_detect_dev,
1815 /* estimated max. count of TDs for one bulk transfer */
1816 .max_bulk_tds = GRUB_EHCI_N_TD * 3 / 4
1819 GRUB_MOD_INIT (ehci)
1821 COMPILE_TIME_ASSERT (sizeof (struct grub_ehci_td) == 64);
1822 COMPILE_TIME_ASSERT (sizeof (struct grub_ehci_qh) == 96);
1824 grub_stop_disk_firmware ();
1826 grub_boot_time ("Initing EHCI hardware");
1827 grub_ehci_pci_scan ();
1828 grub_boot_time ("Registering EHCI driver");
1829 grub_usb_controller_dev_register (&usb_controller);
1830 grub_boot_time ("EHCI driver registered");
1831 grub_loader_register_preboot_hook (grub_ehci_fini_hw, grub_ehci_restore_hw,
1832 GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
1835 GRUB_MOD_FINI (ehci)
1837 grub_ehci_fini_hw (0);
1838 grub_usb_controller_dev_unregister (&usb_controller);