1
/* uhci.c - UHCI Support. */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2008 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/>.
22
#include <grub/misc.h>
24
#include <grub/usbtrans.h>
26
#include <grub/i386/io.h>
27
#include <grub/time.h>
29
#define GRUB_UHCI_IOMASK (0x7FF << 5)
36
GRUB_UHCI_REG_USBCMD = 0x00,
37
GRUB_UHCI_REG_FLBASEADD = 0x08,
38
GRUB_UHCI_REG_PORTSC1 = 0x10,
39
GRUB_UHCI_REG_PORTSC2 = 0x12
42
#define GRUB_UHCI_LINK_TERMINATE 1
43
#define GRUB_UHCI_LINK_QUEUE_HEAD 2
47
GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED = 0x0002,
48
GRUB_UHCI_REG_PORTSC_PORT_ENABLED = 0x0004,
49
GRUB_UHCI_REG_PORTSC_RESUME = 0x0040,
50
GRUB_UHCI_REG_PORTSC_RESET = 0x0200,
51
GRUB_UHCI_REG_PORTSC_SUSPEND = 0x1000,
52
GRUB_UHCI_REG_PORTSC_RW = GRUB_UHCI_REG_PORTSC_PORT_ENABLED
53
| GRUB_UHCI_REG_PORTSC_RESUME | GRUB_UHCI_REG_PORTSC_RESET
54
| GRUB_UHCI_REG_PORTSC_SUSPEND,
55
/* These bits should not be written as 1 unless we really need it */
56
GRUB_UHCI_PORTSC_RWC = ((1 << 1) | (1 << 3) | (1 << 11) | (3 << 13))
59
/* UHCI Queue Head. */
62
/* Queue head link pointer which points to the next queue head. */
63
grub_uint32_t linkptr;
65
/* Queue element link pointer which points to the first data object
67
grub_uint32_t elinkptr;
69
/* Queue heads are aligned on 16 bytes, pad so a queue head is 16
70
bytes so we can store many in a 4K page. */
72
} __attribute__ ((packed));
74
/* UHCI Transfer Descriptor. */
77
/* Pointer to the next TD in the list. */
78
grub_uint32_t linkptr;
80
/* Control and status bits. */
81
grub_uint32_t ctrl_status;
83
/* All information required to transfer the Token packet. */
86
/* A pointer to the data buffer, UHCI requires this pointer to be 32
90
/* Another linkptr that is not overwritten by the Host Controller.
91
This is GRUB specific. */
92
grub_uint32_t linkptr2;
94
/* 3 additional 32 bits words reserved for the Host Controller Driver. */
95
grub_uint32_t data[3];
96
} __attribute__ ((packed));
98
typedef volatile struct grub_uhci_td *grub_uhci_td_t;
99
typedef volatile struct grub_uhci_qh *grub_uhci_qh_t;
104
grub_uint32_t *framelist;
106
/* N_QH Queue Heads. */
109
/* N_TD Transfer Descriptors. */
112
/* Free Transfer Descriptors. */
113
grub_uhci_td_t tdfree;
117
struct grub_uhci *next;
120
static struct grub_uhci *uhci;
123
grub_uhci_readreg16 (struct grub_uhci *u, grub_uhci_reg_t reg)
125
return grub_inw (u->iobase + reg);
130
grub_uhci_readreg32 (struct grub_uhci *u, grub_uhci_reg_t reg)
132
return grub_inl (u->iobase + reg);
137
grub_uhci_writereg16 (struct grub_uhci *u,
138
grub_uhci_reg_t reg, grub_uint16_t val)
140
grub_outw (val, u->iobase + reg);
144
grub_uhci_writereg32 (struct grub_uhci *u,
145
grub_uhci_reg_t reg, grub_uint32_t val)
147
grub_outl (val, u->iobase + reg);
151
grub_uhci_portstatus (grub_usb_controller_t dev,
152
unsigned int port, unsigned int enable);
155
/* Iterate over all PCI devices. Determine if a device is an UHCI
156
controller. If this is the case, initialize it. */
157
static int NESTED_FUNC_ATTR
158
grub_uhci_pci_iter (grub_pci_device_t dev,
159
grub_pci_id_t pciid __attribute__((unused)))
161
grub_uint32_t class_code;
163
grub_uint32_t subclass;
164
grub_uint32_t interf;
167
grub_pci_address_t addr;
171
addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
172
class_code = grub_pci_read (addr) >> 8;
174
interf = class_code & 0xFF;
175
subclass = (class_code >> 8) & 0xFF;
176
class = class_code >> 16;
178
/* If this is not an UHCI controller, just return. */
179
if (class != 0x0c || subclass != 0x03 || interf != 0x00)
182
/* Determine IO base address. */
183
addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4);
184
base = grub_pci_read (addr);
185
/* Stop if there is no IO space base address defined. */
189
/* Allocate memory for the controller and register it. */
190
u = grub_zalloc (sizeof (*u));
194
u->iobase = base & GRUB_UHCI_IOMASK;
196
/* Reserve a page for the frame list. */
197
u->framelist = grub_memalign (4096, 4096);
201
grub_dprintf ("uhci", "class=0x%02x 0x%02x interface 0x%02x base=0x%x framelist=%p\n",
202
class, subclass, interf, u->iobase, u->framelist);
204
/* The framelist pointer of UHCI is only 32 bits, make sure this
205
code works on on 64 bits architectures. */
206
#if GRUB_CPU_SIZEOF_VOID_P == 8
207
if ((grub_uint64_t) u->framelist >> 32)
209
grub_error (GRUB_ERR_OUT_OF_MEMORY,
210
"allocated frame list memory not <4GB");
215
/* The QH pointer of UHCI is only 32 bits, make sure this
216
code works on on 64 bits architectures. */
217
u->qh = (grub_uhci_qh_t) grub_memalign (4096, sizeof(struct grub_uhci_qh)*N_QH);
221
#if GRUB_CPU_SIZEOF_VOID_P == 8
222
if ((grub_uint64_t) u->qh >> 32)
224
grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated QH memory not <4GB");
229
/* The TD pointer of UHCI is only 32 bits, make sure this
230
code works on on 64 bits architectures. */
231
u->td = (grub_uhci_td_t) grub_memalign (4096, sizeof(struct grub_uhci_td)*N_TD);
235
#if GRUB_CPU_SIZEOF_VOID_P == 8
236
if ((grub_uint64_t) u->td >> 32)
238
grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated TD memory not <4GB");
243
grub_dprintf ("uhci", "QH=%p, TD=%p\n",
246
/* Link all Transfer Descriptors in a list of available Transfer
248
for (i = 0; i < N_TD; i++)
249
u->td[i].linkptr = (grub_uint32_t) (grub_addr_t) &u->td[i + 1];
250
u->td[N_TD - 2].linkptr = 0;
253
/* Make sure UHCI is disabled! */
254
grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
256
/* Setup the frame list pointers. Since no isochronous transfers
257
are and will be supported, they all point to the (same!) queue
259
fp = (grub_uint32_t) (grub_addr_t) u->qh & (~15);
260
/* Mark this as a queue head. */
262
for (i = 0; i < 1024; i++)
263
u->framelist[i] = fp;
264
/* Program the framelist address into the UHCI controller. */
265
grub_uhci_writereg32 (u, GRUB_UHCI_REG_FLBASEADD,
266
(grub_uint32_t) (grub_addr_t) u->framelist);
268
/* Make the Queue Heads point to each other. */
269
for (i = 0; i < N_QH; i++)
271
/* Point to the next QH. */
272
u->qh[i].linkptr = (grub_uint32_t) (grub_addr_t) (&u->qh[i + 1]) & (~15);
275
u->qh[i].linkptr |= GRUB_UHCI_LINK_QUEUE_HEAD;
277
/* For the moment, do not point to a Transfer Descriptor. These
278
are set at transfer time, so just terminate it. */
279
u->qh[i].elinkptr = 1;
282
/* The last Queue Head should terminate. */
283
u->qh[N_QH - 1].linkptr = 1;
285
/* Enable UHCI again. */
286
grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 1 | (1 << 7));
288
/* UHCI is initialized and ready for transfers. */
289
grub_dprintf ("uhci", "UHCI initialized\n");
295
for (i = 0; i < 10; i++)
299
frnum = grub_uhci_readreg16 (u, 6);
300
grub_dprintf ("uhci", "Framenum=%d\n", frnum);
301
grub_millisleep (100);
306
/* Link to uhci now that initialisation is successful. */
315
grub_free ((void *) u->qh);
316
grub_free (u->framelist);
324
grub_uhci_inithw (void)
326
grub_pci_iterate (grub_uhci_pci_iter);
329
static grub_uhci_td_t
330
grub_alloc_td (struct grub_uhci *u)
334
/* Check if there is a Transfer Descriptor available. */
339
u->tdfree = (grub_uhci_td_t) (grub_addr_t) u->tdfree->linkptr;
345
grub_free_td (struct grub_uhci *u, grub_uhci_td_t td)
347
td->linkptr = (grub_uint32_t) (grub_addr_t) u->tdfree;
352
grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td,
353
grub_usb_transfer_t transfer, grub_size_t *actual)
355
int i; /* Index of TD in transfer */
357
u->qh_busy[qh - u->qh] = 0;
361
/* Free the TDs in this queue and set last_trans. */
364
grub_uhci_td_t tdprev;
366
/* Check state of TD and possibly set last_trans */
367
if (transfer && (td->linkptr & 1))
368
transfer->last_trans = i;
370
*actual += (td->ctrl_status + 1) & 0x7ff;
372
/* Unlink the queue. */
374
td = (grub_uhci_td_t) (grub_addr_t) td->linkptr2;
377
grub_free_td (u, tdprev);
381
static grub_uhci_qh_t
382
grub_alloc_qh (struct grub_uhci *u,
383
grub_transaction_type_t tr __attribute__((unused)))
388
/* Look for a Queue Head for this transfer. Skip the first QH if
389
this is a Interrupt Transfer. */
391
if (tr == GRUB_USB_TRANSACTION_TYPE_INTERRUPT)
397
for (; i < N_QH; i++)
405
grub_error (GRUB_ERR_OUT_OF_MEMORY,
406
"no free queue heads available");
410
u->qh_busy[qh - u->qh] = 1;
415
static grub_uhci_td_t
416
grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
417
grub_transfer_type_t type, unsigned int addr,
418
unsigned int toggle, grub_size_t size,
419
grub_uint32_t data, grub_usb_speed_t speed)
422
static const unsigned int tf[] = { 0x69, 0xE1, 0x2D };
424
/* XXX: Check if data is <4GB. If it isn't, just copy stuff around.
425
This is only relevant for 64 bits architectures. */
427
/* Grab a free Transfer Descriptor and initialize it. */
428
td = grub_alloc_td (u);
431
grub_error (GRUB_ERR_OUT_OF_MEMORY,
432
"no transfer descriptors available for UHCI transfer");
436
grub_dprintf ("uhci",
437
"transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%lu data=0x%x td=%p\n",
438
endp, type, addr, toggle, (unsigned long) size, data, td);
440
/* Don't point to any TD, just terminate. */
443
/* Active! Only retry a transfer 3 times. */
444
td->ctrl_status = (1 << 23) | (3 << 27) |
445
((speed == GRUB_USB_SPEED_LOW) ? (1 << 26) : 0);
447
/* If zero bytes are transmitted, size is 0x7FF. Otherwise size is
454
/* Setup whatever is required for the token packet. */
455
td->token = ((size << 21) | (toggle << 19) | (endp << 15)
456
| (addr << 8) | tf[type]);
463
struct grub_uhci_transfer_controller_data
466
grub_uhci_td_t td_first;
469
static grub_usb_err_t
470
grub_uhci_setup_transfer (grub_usb_controller_t dev,
471
grub_usb_transfer_t transfer)
473
struct grub_uhci *u = (struct grub_uhci *) dev->data;
475
grub_uhci_td_t td_prev = NULL;
477
struct grub_uhci_transfer_controller_data *cdata;
479
cdata = grub_malloc (sizeof (*cdata));
481
return GRUB_USB_ERR_INTERNAL;
483
cdata->td_first = NULL;
485
/* Allocate a queue head for the transfer queue. */
486
cdata->qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
490
return GRUB_USB_ERR_INTERNAL;
493
grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase);
495
for (i = 0; i < transfer->transcnt; i++)
497
grub_usb_transaction_t tr = &transfer->transactions[i];
499
td = grub_uhci_transaction (u, transfer->endpoint & 15, tr->pid,
500
transfer->devaddr, tr->toggle,
502
transfer->dev->speed);
505
grub_size_t actual = 0;
506
/* Terminate and free. */
507
td_prev->linkptr2 = 0;
508
td_prev->linkptr = 1;
511
grub_free_queue (u, cdata->qh, cdata->td_first, NULL, &actual);
514
return GRUB_USB_ERR_INTERNAL;
517
if (! cdata->td_first)
518
cdata->td_first = td;
521
td_prev->linkptr2 = (grub_uint32_t) (grub_addr_t) td;
522
td_prev->linkptr = (grub_uint32_t) (grub_addr_t) td;
523
td_prev->linkptr |= 4;
527
td_prev->linkptr2 = 0;
528
td_prev->linkptr = 1;
530
grub_dprintf ("uhci", "setup transaction %d\n", transfer->type);
532
/* Link it into the queue and terminate. Now the transaction can
534
cdata->qh->elinkptr = (grub_uint32_t) (grub_addr_t) cdata->td_first;
536
grub_dprintf ("uhci", "initiate transaction\n");
538
transfer->controller_data = cdata;
540
return GRUB_USB_ERR_NONE;
543
static grub_usb_err_t
544
grub_uhci_check_transfer (grub_usb_controller_t dev,
545
grub_usb_transfer_t transfer,
548
struct grub_uhci *u = (struct grub_uhci *) dev->data;
549
grub_uhci_td_t errtd;
550
struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data;
554
errtd = (grub_uhci_td_t) (grub_addr_t) (cdata->qh->elinkptr & ~0x0f);
556
grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n",
557
errtd->ctrl_status, errtd->buffer & (~15), errtd);
559
/* Check if the transaction completed. */
560
if (cdata->qh->elinkptr & 1)
562
grub_dprintf ("uhci", "transaction complete\n");
564
/* Place the QH back in the free list and deallocate the associated
566
cdata->qh->elinkptr = 1;
567
grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual);
569
return GRUB_USB_ERR_NONE;
572
grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status);
574
if (!(errtd->ctrl_status & (1 << 23)))
576
grub_usb_err_t err = GRUB_USB_ERR_NONE;
578
/* Check if the endpoint is stalled. */
579
if (errtd->ctrl_status & (1 << 22))
580
err = GRUB_USB_ERR_STALL;
582
/* Check if an error related to the data buffer occurred. */
583
else if (errtd->ctrl_status & (1 << 21))
584
err = GRUB_USB_ERR_DATA;
586
/* Check if a babble error occurred. */
587
else if (errtd->ctrl_status & (1 << 20))
588
err = GRUB_USB_ERR_BABBLE;
590
/* Check if a NAK occurred. */
591
else if (errtd->ctrl_status & (1 << 19))
592
err = GRUB_USB_ERR_NAK;
594
/* Check if a timeout occurred. */
595
else if (errtd->ctrl_status & (1 << 18))
596
err = GRUB_USB_ERR_TIMEOUT;
598
/* Check if a bitstuff error occurred. */
599
else if (errtd->ctrl_status & (1 << 17))
600
err = GRUB_USB_ERR_BITSTUFF;
604
grub_dprintf ("uhci", "transaction failed\n");
606
/* Place the QH back in the free list and deallocate the associated
608
cdata->qh->elinkptr = 1;
609
grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual);
616
/* Fall through, no errors occurred, so the QH might be
618
grub_dprintf ("uhci", "transaction fallthrough\n");
620
return GRUB_USB_ERR_WAIT;
623
static grub_usb_err_t
624
grub_uhci_cancel_transfer (grub_usb_controller_t dev,
625
grub_usb_transfer_t transfer)
627
struct grub_uhci *u = (struct grub_uhci *) dev->data;
629
struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data;
631
grub_dprintf ("uhci", "transaction cancel\n");
633
/* Place the QH back in the free list and deallocate the associated
635
cdata->qh->elinkptr = 1;
636
grub_free_queue (u, cdata->qh, cdata->td_first, transfer, &actual);
639
return GRUB_USB_ERR_NONE;
643
grub_uhci_iterate (int (*hook) (grub_usb_controller_t dev))
646
struct grub_usb_controller dev;
648
for (u = uhci; u; u = u->next)
659
grub_uhci_portstatus (grub_usb_controller_t dev,
660
unsigned int port, unsigned int enable)
662
struct grub_uhci *u = (struct grub_uhci *) dev->data;
665
grub_uint64_t endtime;
667
grub_dprintf ("uhci", "portstatus, iobase:%08x\n", u->iobase);
669
grub_dprintf ("uhci", "enable=%d port=%d\n", enable, port);
672
reg = GRUB_UHCI_REG_PORTSC1;
674
reg = GRUB_UHCI_REG_PORTSC2;
676
return grub_error (GRUB_ERR_OUT_OF_RANGE,
677
"UHCI Root Hub port does not exist");
679
status = grub_uhci_readreg16 (u, reg);
680
grub_dprintf ("uhci", "detect=0x%02x\n", status);
682
if (!enable) /* We don't need reset port */
684
/* Disable the port. */
685
grub_uhci_writereg16 (u, reg, 0 << 2);
686
grub_dprintf ("uhci", "waiting for the port to be disabled\n");
687
endtime = grub_get_time_ms () + 1000;
688
while ((grub_uhci_readreg16 (u, reg) & (1 << 2)))
689
if (grub_get_time_ms () > endtime)
690
return grub_error (GRUB_ERR_IO, "UHCI Timed out - disable");
692
status = grub_uhci_readreg16 (u, reg);
693
grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
694
return GRUB_ERR_NONE;
697
/* Reset the port. */
698
status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
699
grub_uhci_writereg16 (u, reg, status | (1 << 9));
700
grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
702
/* Wait for the reset to complete. XXX: How long exactly? */
703
grub_millisleep (50); /* For root hub should be nominaly 50ms */
704
status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
705
grub_uhci_writereg16 (u, reg, status & ~(1 << 9));
706
grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
708
/* Note: some debug prints were removed because they affected reset/enable timing. */
710
grub_millisleep (1); /* Probably not needed at all or only few microsecs. */
712
/* Reset bits Connect & Enable Status Change */
713
status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
714
grub_uhci_writereg16 (u, reg, status | (1 << 3) | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED);
715
grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
717
/* Enable the port. */
718
status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
719
grub_uhci_writereg16 (u, reg, status | (1 << 2));
720
grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
722
endtime = grub_get_time_ms () + 1000;
723
while (! ((status = grub_uhci_readreg16 (u, reg)) & (1 << 2)))
724
if (grub_get_time_ms () > endtime)
725
return grub_error (GRUB_ERR_IO, "UHCI Timed out - enable");
727
/* Reset recovery time */
728
grub_millisleep (10);
730
/* Read final port status */
731
status = grub_uhci_readreg16 (u, reg);
732
grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
735
return GRUB_ERR_NONE;
738
static grub_usb_speed_t
739
grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
741
struct grub_uhci *u = (struct grub_uhci *) dev->data;
745
grub_dprintf ("uhci", "detect_dev, iobase:%08x\n", u->iobase);
748
reg = GRUB_UHCI_REG_PORTSC1;
750
reg = GRUB_UHCI_REG_PORTSC2;
752
return grub_error (GRUB_ERR_OUT_OF_RANGE,
753
"UHCI Root Hub port does not exist");
755
status = grub_uhci_readreg16 (u, reg);
757
grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port);
759
/* Connect Status Change bit - it detects change of connection */
760
if (status & (1 << 1))
763
/* Reset bit Connect Status Change */
764
grub_uhci_writereg16 (u, reg, (status & GRUB_UHCI_REG_PORTSC_RW)
765
| GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED);
771
return GRUB_USB_SPEED_NONE;
772
else if (status & (1 << 8))
773
return GRUB_USB_SPEED_LOW;
775
return GRUB_USB_SPEED_FULL;
779
grub_uhci_hubports (grub_usb_controller_t dev __attribute__((unused)))
781
/* The root hub has exactly two ports. */
786
static struct grub_usb_controller_dev usb_controller =
789
.iterate = grub_uhci_iterate,
790
.setup_transfer = grub_uhci_setup_transfer,
791
.check_transfer = grub_uhci_check_transfer,
792
.cancel_transfer = grub_uhci_cancel_transfer,
793
.hubports = grub_uhci_hubports,
794
.portstatus = grub_uhci_portstatus,
795
.detect_dev = grub_uhci_detect_dev
801
grub_usb_controller_dev_register (&usb_controller);
802
grub_dprintf ("uhci", "registered\n");
809
/* Disable all UHCI controllers. */
810
for (u = uhci; u; u = u->next)
811
grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
813
/* Unregister the controller. */
814
grub_usb_controller_dev_unregister (&usb_controller);