1 /*
2 * PC-specific code for
3 * USB Enhanced Host Controller Interface (EHCI) driver
4 * High speed USB 2.0.
5 */
6
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "mem.h"
10 #include "dat.h"
11 #include "fns.h"
12 #include "io.h"
13 #include "../port/error.h"
14 #include "../port/usb.h"
15 #include "../port/portusbehci.h"
16 #include "usbehci.h"
17
18 static Ctlr* ctlrs[Nhcis];
19 static int maxehci = Nhcis;
20
21 /* Isn't this cap list search in a helper function? */
22 static void
getehci(Ctlr * ctlr)23 getehci(Ctlr* ctlr)
24 {
25 int i, ptr, cap, sem;
26
27 ptr = (ctlr->capio->capparms >> Ceecpshift) & Ceecpmask;
28 for(; ptr != 0; ptr = pcicfgr8(ctlr->pcidev, ptr+1)){
29 if(ptr < 0x40 || (ptr & ~0xFC))
30 break;
31 cap = pcicfgr8(ctlr->pcidev, ptr);
32 if(cap != Clegacy)
33 continue;
34 sem = pcicfgr8(ctlr->pcidev, ptr+CLbiossem);
35 if(sem == 0)
36 continue;
37 pcicfgw8(ctlr->pcidev, ptr+CLossem, 1);
38 for(i = 0; i < 100; i++){
39 if(pcicfgr8(ctlr->pcidev, ptr+CLbiossem) == 0)
40 break;
41 delay(10);
42 }
43 if(i == 100)
44 dprint("ehci %#p: bios timed out\n", ctlr->capio);
45 pcicfgw32(ctlr->pcidev, ptr+CLcontrol, 0); /* no SMIs */
46 ctlr->opio->config = 0;
47 coherence();
48 return;
49 }
50 }
51
52 static void
ehcireset(Ctlr * ctlr)53 ehcireset(Ctlr *ctlr)
54 {
55 Eopio *opio;
56 int i;
57
58 ilock(ctlr);
59 dprint("ehci %#p reset\n", ctlr->capio);
60 opio = ctlr->opio;
61
62 /*
63 * Turn off legacy mode. Some controllers won't
64 * interrupt us as expected otherwise.
65 */
66 ehcirun(ctlr, 0);
67 pcicfgw16(ctlr->pcidev, 0xc0, 0x2000);
68
69 /*
70 * reclaim from bios
71 */
72 getehci(ctlr);
73
74 /* clear high 32 bits of address signals if it's 64 bits capable.
75 * This is probably not needed but it does not hurt and others do it.
76 */
77 if((ctlr->capio->capparms & C64) != 0){
78 dprint("ehci: 64 bits\n");
79 opio->seg = 0;
80 coherence();
81 }
82
83 if(ehcidebugcapio != ctlr->capio){
84 opio->cmd |= Chcreset; /* controller reset */
85 coherence();
86 for(i = 0; i < 100; i++){
87 if((opio->cmd & Chcreset) == 0)
88 break;
89 delay(1);
90 }
91 if(i == 100)
92 print("ehci %#p controller reset timed out\n", ctlr->capio);
93 }
94
95 /* requesting more interrupts per µframe may miss interrupts */
96 opio->cmd &= ~Citcmask;
97 opio->cmd |= 1 << Citcshift; /* max of 1 intr. per 125 µs */
98 coherence();
99 switch(opio->cmd & Cflsmask){
100 case Cfls1024:
101 ctlr->nframes = 1024;
102 break;
103 case Cfls512:
104 ctlr->nframes = 512;
105 break;
106 case Cfls256:
107 ctlr->nframes = 256;
108 break;
109 default:
110 panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
111 }
112 dprint("ehci: %d frames\n", ctlr->nframes);
113 iunlock(ctlr);
114 }
115
116 static void
setdebug(Hci *,int d)117 setdebug(Hci*, int d)
118 {
119 ehcidebug = d;
120 }
121
122 static void
shutdown(Hci * hp)123 shutdown(Hci *hp)
124 {
125 int i;
126 Ctlr *ctlr;
127 Eopio *opio;
128
129 ctlr = hp->aux;
130 ilock(ctlr);
131 opio = ctlr->opio;
132 opio->cmd |= Chcreset; /* controller reset */
133 coherence();
134 for(i = 0; i < 100; i++){
135 if((opio->cmd & Chcreset) == 0)
136 break;
137 delay(1);
138 }
139 if(i >= 100)
140 print("ehci %#p controller reset timed out\n", ctlr->capio);
141 delay(100);
142 ehcirun(ctlr, 0);
143 opio->frbase = 0;
144 iunlock(ctlr);
145 }
146
147 static void
scanpci(void)148 scanpci(void)
149 {
150 static int already = 0;
151 int i;
152 ulong io;
153 Ctlr *ctlr;
154 Pcidev *p;
155 Ecapio *capio;
156
157 if(already)
158 return;
159 already = 1;
160 p = nil;
161 while ((p = pcimatch(p, 0, 0)) != nil) {
162 /*
163 * Find EHCI controllers (Programming Interface = 0x20).
164 */
165 if(p->ccrb != Pcibcserial || p->ccru != Pciscusb)
166 continue;
167 switch(p->ccrp){
168 case 0x20:
169 io = p->mem[0].bar & ~0x0f;
170 break;
171 default:
172 continue;
173 }
174 if(0 && p->vid == Vintel && p->did == 0x3b34) {
175 print("usbehci: ignoring known bad ctlr %#ux/%#ux\n",
176 p->vid, p->did);
177 continue;
178 }
179 if(io == 0){
180 print("usbehci: %x %x: failed to map registers\n",
181 p->vid, p->did);
182 continue;
183 }
184 if(p->intl == 0xff || p->intl == 0) {
185 print("usbehci: no irq assigned for port %#lux\n", io);
186 continue;
187 }
188 dprint("usbehci: %#x %#x: port %#lux size %#x irq %d\n",
189 p->vid, p->did, io, p->mem[0].size, p->intl);
190
191 ctlr = malloc(sizeof(Ctlr));
192 if (ctlr == nil)
193 panic("usbehci: out of memory");
194 ctlr->pcidev = p;
195 capio = ctlr->capio = vmap(io, p->mem[0].size);
196 ctlr->opio = (Eopio*)((uintptr)capio + (capio->cap & 0xff));
197 pcisetbme(p);
198 pcisetpms(p, 0);
199 for(i = 0; i < Nhcis; i++)
200 if(ctlrs[i] == nil){
201 ctlrs[i] = ctlr;
202 break;
203 }
204 if(i >= Nhcis)
205 print("ehci: bug: more than %d controllers\n", Nhcis);
206
207 /*
208 * currently, if we enable a second ehci controller on zt
209 * systems w x58m motherboard, we'll wedge solid after iunlock
210 * in init for the second one.
211 */
212 if (i >= maxehci) {
213 print("usbehci: ignoring controllers after first %d, "
214 "at %#p\n", maxehci, io);
215 ctlrs[i] = nil;
216 }
217 }
218 }
219
220 static int
reset(Hci * hp)221 reset(Hci *hp)
222 {
223 int i;
224 char *s;
225 Ctlr *ctlr;
226 Ecapio *capio;
227 Pcidev *p;
228 static Lock resetlck;
229
230 s = getconf("*maxehci");
231 if (s != nil && s[0] >= '0' && s[0] <= '9')
232 maxehci = atoi(s);
233 if(maxehci == 0 || getconf("*nousbehci"))
234 return -1;
235
236 ilock(&resetlck);
237 scanpci();
238
239 /*
240 * Any adapter matches if no hp->port is supplied,
241 * otherwise the ports must match.
242 */
243 ctlr = nil;
244 for(i = 0; i < Nhcis && ctlrs[i] != nil; i++){
245 ctlr = ctlrs[i];
246 if(ctlr->active == 0)
247 if(hp->port == 0 || hp->port == (uintptr)ctlr->capio){
248 ctlr->active = 1;
249 break;
250 }
251 }
252 iunlock(&resetlck);
253 if(i >= Nhcis || ctlrs[i] == nil)
254 return -1;
255
256 p = ctlr->pcidev;
257 hp->aux = ctlr;
258 hp->port = (uintptr)ctlr->capio;
259 hp->irq = p->intl;
260 hp->tbdf = p->tbdf;
261
262 capio = ctlr->capio;
263 hp->nports = capio->parms & Cnports;
264
265 ddprint("echi: %s, ncc %lud npcc %lud\n",
266 capio->parms & 0x10000 ? "leds" : "no leds",
267 (capio->parms >> 12) & 0xf, (capio->parms >> 8) & 0xf);
268 ddprint("ehci: routing %s, %sport power ctl, %d ports\n",
269 capio->parms & 0x40 ? "explicit" : "automatic",
270 capio->parms & 0x10 ? "" : "no ", hp->nports);
271
272 ehcireset(ctlr);
273 ehcimeminit(ctlr);
274
275 /*
276 * Linkage to the generic HCI driver.
277 */
278 ehcilinkage(hp);
279 hp->shutdown = shutdown;
280 hp->debug = setdebug;
281 return 0;
282 }
283
284 void
usbehcilink(void)285 usbehcilink(void)
286 {
287 addhcitype("ehci", reset);
288 }
289