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