828507baa4199626f64d2753297f5c18df4e5f14
[seabios.git] / src / usb-ohci.c
1 // Code for handling OHCI USB controllers.
2 //
3 // Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "util.h" // dprintf
8 #include "pci.h" // pci_bdf_to_bus
9 #include "config.h" // CONFIG_*
10 #include "usb-ohci.h" // struct ohci_hcca
11 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
12 #include "usb.h" // struct usb_s
13 #include "farptr.h" // GET_FLATPTR
14
15 #define FIT                     (1 << 31)
16
17
18 /****************************************************************
19  * Setup
20  ****************************************************************/
21
22 static int
23 start_ohci(struct usb_s *cntl, struct ohci_hcca *hcca)
24 {
25     u32 oldfminterval = readl(&cntl->ohci.regs->fminterval);
26     u32 oldrwc = readl(&cntl->ohci.regs->control) & OHCI_CTRL_RWC;
27
28     // XXX - check if already running?
29
30     // Do reset
31     writel(&cntl->ohci.regs->control, OHCI_USB_RESET | oldrwc);
32     readl(&cntl->ohci.regs->control); // flush writes
33     msleep(USB_TIME_DRSTR);
34
35     // Do software init (min 10us, max 2ms)
36     u64 end = calc_future_tsc_usec(10);
37     writel(&cntl->ohci.regs->cmdstatus, OHCI_HCR);
38     for (;;) {
39         u32 status = readl(&cntl->ohci.regs->cmdstatus);
40         if (! status & OHCI_HCR)
41             break;
42         if (check_time(end)) {
43             warn_timeout();
44             return -1;
45         }
46     }
47
48     // Init memory
49     writel(&cntl->ohci.regs->ed_controlhead, 0);
50     writel(&cntl->ohci.regs->ed_bulkhead, 0);
51     writel(&cntl->ohci.regs->hcca, (u32)hcca);
52
53     // Init fminterval
54     u32 fi = oldfminterval & 0x3fff;
55     writel(&cntl->ohci.regs->fminterval
56            , (((oldfminterval & FIT) ^ FIT)
57               | fi | (((6 * (fi - 210)) / 7) << 16)));
58     writel(&cntl->ohci.regs->periodicstart, ((9 * fi) / 10) & 0x3fff);
59     readl(&cntl->ohci.regs->control); // flush writes
60
61     // XXX - verify that fminterval was setup correctly.
62
63     // Go into operational state
64     writel(&cntl->ohci.regs->control
65            , (OHCI_CTRL_CBSR | OHCI_CTRL_CLE | OHCI_CTRL_PLE
66               | OHCI_USB_OPER | oldrwc));
67     readl(&cntl->ohci.regs->control); // flush writes
68
69     return 0;
70 }
71
72 static void
73 stop_ohci(struct usb_s *cntl)
74 {
75     u32 oldrwc = readl(&cntl->ohci.regs->control) & OHCI_CTRL_RWC;
76     writel(&cntl->ohci.regs->control, oldrwc);
77     readl(&cntl->ohci.regs->control); // flush writes
78 }
79
80 // Find any devices connected to the root hub.
81 static int
82 check_ohci_ports(struct usb_s *cntl)
83 {
84     // Turn on power for all devices on roothub.
85     u32 rha = readl(&cntl->ohci.regs->roothub_a);
86     rha &= ~(RH_A_PSM | RH_A_OCPM);
87     writel(&cntl->ohci.regs->roothub_status, RH_HS_LPSC);
88     writel(&cntl->ohci.regs->roothub_b, RH_B_PPCM);
89     msleep((rha >> 24) * 2);
90     // XXX - need to sleep for USB_TIME_SIGATT if just powered up?
91
92     // Count and reset connected devices
93     int ports = rha & RH_A_NDP;
94     int totalcount = 0;
95     int i;
96     for (i=0; i<ports; i++) {
97         u32 sts = readl(&cntl->ohci.regs->roothub_portstatus[i]);
98         if (!(sts & RH_PS_CCS))
99             continue;
100         // XXX - need to wait for USB_TIME_ATTDB if just powered up?
101         writel(&cntl->ohci.regs->roothub_portstatus[i], RH_PS_PRS);
102         u64 end = calc_future_tsc(USB_TIME_DRSTR * 2);
103         for (;;) {
104             sts = readl(&cntl->ohci.regs->roothub_portstatus[i]);
105             if (!(sts & RH_PS_PRS))
106                 // XXX - need to ensure USB_TIME_DRSTR time in reset?
107                 break;
108             if (check_time(end)) {
109                 // Timeout.
110                 warn_timeout();
111                 goto shutdown;
112             }
113             yield();
114         }
115
116         if ((sts & (RH_PS_CCS|RH_PS_PES)) != (RH_PS_CCS|RH_PS_PES))
117             // Device no longer present
118             continue;
119
120         msleep(USB_TIME_RSTRCY);
121
122         // XXX - should try to parallelize configuration.
123         int count = configure_usb_device(cntl, !!(sts & RH_PS_LSDA));
124         if (! count)
125             // Shutdown port
126             writel(&cntl->ohci.regs->roothub_portstatus[i]
127                    , RH_PS_CCS|RH_PS_LSDA);
128         totalcount += count;
129     }
130     if (!totalcount)
131         // No devices connected
132         goto shutdown;
133     return totalcount;
134
135 shutdown:
136     // Turn off power to all ports
137     writel(&cntl->ohci.regs->roothub_status, RH_HS_LPS);
138     return 0;
139 }
140
141 void
142 ohci_init(void *data)
143 {
144     if (! CONFIG_USB_OHCI)
145         return;
146     struct usb_s *cntl = data;
147
148     // XXX - don't call pci_config_XXX from a thread
149     cntl->type = USB_TYPE_OHCI;
150     u32 baseaddr = pci_config_readl(cntl->bdf, PCI_BASE_ADDRESS_0);
151     cntl->ohci.regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
152
153     dprintf(3, "OHCI init on dev %02x:%02x.%x (regs=%p)\n"
154             , pci_bdf_to_bus(cntl->bdf), pci_bdf_to_dev(cntl->bdf)
155             , pci_bdf_to_fn(cntl->bdf), cntl->ohci.regs);
156
157     // Enable bus mastering and memory access.
158     pci_config_maskw(cntl->bdf, PCI_COMMAND
159                      , 0, PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY);
160
161     // XXX - check for and disable SMM control?
162
163     // Disable interrupts
164     writel(&cntl->ohci.regs->intrdisable, ~0);
165     writel(&cntl->ohci.regs->intrstatus, ~0);
166
167     // Allocate memory
168     struct ohci_hcca *hcca = memalign_high(256, sizeof(*hcca));
169     struct ohci_ed *intr_ed = malloc_high(sizeof(*intr_ed));
170     if (!hcca || !intr_ed) {
171         warn_noalloc();
172         goto free;
173     }
174     memset(hcca, 0, sizeof(*hcca));
175     memset(intr_ed, 0, sizeof(*intr_ed));
176     intr_ed->hwINFO = ED_SKIP;
177     int i;
178     for (i=0; i<ARRAY_SIZE(hcca->int_table); i++)
179         hcca->int_table[i] = (u32)intr_ed;
180
181     int ret = start_ohci(cntl, hcca);
182     if (ret)
183         goto err;
184
185     int count = check_ohci_ports(cntl);
186     free_pipe(cntl->defaultpipe);
187     if (! count)
188         goto err;
189     return;
190
191 err:
192     stop_ohci(cntl);
193 free:
194     free(hcca);
195     free(intr_ed);
196 }
197
198
199 /****************************************************************
200  * End point communication
201  ****************************************************************/
202
203 static int
204 wait_ed(struct ohci_ed *ed)
205 {
206     // XXX - 500ms just a guess
207     u64 end = calc_future_tsc(500);
208     for (;;) {
209         if (ed->hwHeadP == ed->hwTailP)
210             return 0;
211         if (check_time(end)) {
212             warn_timeout();
213             return -1;
214         }
215         yield();
216     }
217 }
218
219 // Wait for next USB frame to start - for ensuring safe memory release.
220 static void
221 ohci_waittick(struct usb_s *cntl)
222 {
223     barrier();
224     struct ohci_hcca *hcca = (void*)cntl->ohci.regs->hcca;
225     u32 startframe = hcca->frame_no;
226     u64 end = calc_future_tsc(1000 * 5);
227     for (;;) {
228         if (hcca->frame_no != startframe)
229             break;
230         if (check_time(end)) {
231             warn_timeout();
232             return;
233         }
234         yield();
235     }
236 }
237
238 static void
239 signal_freelist(struct usb_s *cntl)
240 {
241     u32 v = readl(&cntl->ohci.regs->control);
242     if (v & OHCI_CTRL_CLE) {
243         writel(&cntl->ohci.regs->control, v & ~(OHCI_CTRL_CLE|OHCI_CTRL_BLE));
244         ohci_waittick(cntl);
245         writel(&cntl->ohci.regs->ed_controlcurrent, 0);
246         writel(&cntl->ohci.regs->ed_bulkcurrent, 0);
247         writel(&cntl->ohci.regs->control, v);
248     } else {
249         ohci_waittick(cntl);
250     }
251 }
252
253 struct ohci_pipe {
254     struct ohci_ed ed;
255     struct usb_pipe pipe;
256     void *data;
257     int count;
258     struct ohci_td *tds;
259 };
260
261 void
262 ohci_free_pipe(struct usb_pipe *p)
263 {
264     if (! CONFIG_USB_OHCI)
265         return;
266     struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
267     u32 endp = pipe->pipe.endp;
268     dprintf(7, "ohci_free_pipe %x\n", endp);
269     struct usb_s *cntl = endp2cntl(endp);
270
271     u32 *pos = &cntl->ohci.regs->ed_controlhead;
272     for (;;) {
273         struct ohci_ed *next = (void*)*pos;
274         if (!next) {
275             // Not found?!  Exit without freeing.
276             warn_internalerror();
277             return;
278         }
279         if (next == &pipe->ed) {
280             *pos = next->hwNextED;
281             signal_freelist(cntl);
282             free(pipe);
283             return;
284         }
285         pos = &next->hwNextED;
286     }
287 }
288
289 struct usb_pipe *
290 ohci_alloc_control_pipe(u32 endp)
291 {
292     if (! CONFIG_USB_OHCI)
293         return NULL;
294     struct usb_s *cntl = endp2cntl(endp);
295     dprintf(7, "ohci_alloc_control_pipe %x\n", endp);
296
297     // Allocate a queue head.
298     struct ohci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
299     if (!pipe) {
300         warn_noalloc();
301         return NULL;
302     }
303     memset(pipe, 0, sizeof(*pipe));
304     pipe->ed.hwINFO = ED_SKIP;
305     pipe->pipe.endp = endp;
306
307     // Add queue head to controller list.
308     pipe->ed.hwNextED = cntl->ohci.regs->ed_controlhead;
309     barrier();
310     cntl->ohci.regs->ed_controlhead = (u32)&pipe->ed;
311     return &pipe->pipe;
312 }
313
314 int
315 ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
316              , void *data, int datasize)
317 {
318     if (! CONFIG_USB_OHCI)
319         return -1;
320     if (datasize > 4096) {
321         // XXX - should support larger sizes.
322         warn_noalloc();
323         return -1;
324     }
325     struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
326     u32 endp = pipe->pipe.endp;
327     dprintf(5, "ohci_control %x\n", endp);
328     struct usb_s *cntl = endp2cntl(endp);
329     int maxpacket = endp2maxsize(endp);
330     int lowspeed = endp2speed(endp);
331     int devaddr = endp2devaddr(endp) | (endp2ep(endp) << 7);
332
333     // Setup transfer descriptors
334     struct ohci_td *tds = malloc_tmphigh(sizeof(*tds) * 3);
335     tds[0].hwINFO = TD_DP_SETUP | TD_T_DATA0 | TD_CC;
336     tds[0].hwCBP = (u32)cmd;
337     tds[0].hwNextTD = (u32)&tds[1];
338     tds[0].hwBE = (u32)cmd + cmdsize - 1;
339     tds[1].hwINFO = (dir ? TD_DP_IN : TD_DP_OUT) | TD_T_DATA1 | TD_CC;
340     tds[1].hwCBP = datasize ? (u32)data : 0;
341     tds[1].hwNextTD = (u32)&tds[2];
342     tds[1].hwBE = (u32)data + datasize - 1;
343     tds[2].hwINFO = (dir ? TD_DP_OUT : TD_DP_IN) | TD_T_DATA1 | TD_CC;
344     tds[2].hwCBP = 0;
345     tds[2].hwNextTD = (u32)&tds[3];
346     tds[2].hwBE = 0;
347
348     // Transfer data
349     pipe->ed.hwINFO = ED_SKIP;
350     barrier();
351     pipe->ed.hwHeadP = (u32)&tds[0];
352     pipe->ed.hwTailP = (u32)&tds[3];
353     barrier();
354     pipe->ed.hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
355     writel(&cntl->ohci.regs->cmdstatus, OHCI_CLF);
356
357     int ret = wait_ed(&pipe->ed);
358     pipe->ed.hwINFO = ED_SKIP;
359     if (ret)
360         ohci_waittick(cntl);
361     free(tds);
362     return ret;
363 }
364
365 struct usb_pipe *
366 ohci_alloc_intr_pipe(u32 endp, int frameexp)
367 {
368     if (! CONFIG_USB_OHCI)
369         return NULL;
370
371     dprintf(7, "ohci_alloc_intr_pipe %x %d\n", endp, frameexp);
372     if (frameexp > 5)
373         frameexp = 5;
374     struct usb_s *cntl = endp2cntl(endp);
375     int maxpacket = endp2maxsize(endp);
376     int lowspeed = endp2speed(endp);
377     int devaddr = endp2devaddr(endp) | (endp2ep(endp) << 7);
378     // Determine number of entries needed for 2 timer ticks.
379     int ms = 1<<frameexp;
380     int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms);
381     struct ohci_pipe *pipe = malloc_low(sizeof(*pipe));
382     struct ohci_td *tds = malloc_low(sizeof(*tds) * count);
383     void *data = malloc_low(maxpacket * count);
384     if (!pipe || !tds || !data)
385         goto err;
386
387     struct ohci_ed *ed = &pipe->ed;
388     ed->hwHeadP = (u32)&tds[0];
389     ed->hwTailP = (u32)&tds[count-1];
390     ed->hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
391
392     int i;
393     for (i=0; i<count-1; i++) {
394         tds[i].hwINFO = TD_DP_IN | TD_T_TOGGLE | TD_CC;
395         tds[i].hwCBP = (u32)data + maxpacket * i;
396         tds[i].hwNextTD = (u32)&tds[i+1];
397         tds[i].hwBE = tds[i].hwCBP + maxpacket - 1;
398     }
399
400     // Add to interrupt schedule.
401     barrier();
402     struct ohci_hcca *hcca = (void*)cntl->ohci.regs->hcca;
403     if (frameexp == 0) {
404         // Add to existing interrupt entry.
405         struct ohci_ed *intr_ed = (void*)hcca->int_table[0];
406         ed->hwNextED = intr_ed->hwNextED;
407         intr_ed->hwNextED = (u32)ed;
408     } else {
409         int startpos = 1<<(frameexp-1);
410         ed->hwNextED = hcca->int_table[startpos];
411         for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms)
412             hcca->int_table[i] = (u32)ed;
413     }
414
415     pipe->data = data;
416     pipe->count = count;
417     pipe->tds = tds;
418     pipe->pipe.endp = endp;
419     return &pipe->pipe;
420
421 err:
422     free(pipe);
423     free(tds);
424     free(data);
425     return NULL;
426 }
427
428 int
429 ohci_poll_intr(struct usb_pipe *p, void *data)
430 {
431     ASSERT16();
432     if (! CONFIG_USB_OHCI)
433         return -1;
434
435     struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
436     struct ohci_td *tds = GET_FLATPTR(pipe->tds);
437     struct ohci_td *head = (void*)GET_FLATPTR(pipe->ed.hwHeadP);
438     struct ohci_td *tail = (void*)GET_FLATPTR(pipe->ed.hwTailP);
439     int count = GET_FLATPTR(pipe->count);
440     int pos = (tail - tds + 1) % count;
441     struct ohci_td *next = &tds[pos];
442     if (head == next)
443         // No intrs found.
444         return -1;
445     // XXX - check for errors.
446
447     // Copy data.
448     u32 endp = GET_FLATPTR(pipe->pipe.endp);
449     int maxpacket = endp2maxsize(endp);
450     void *pipedata = GET_FLATPTR(pipe->data);
451     void *intrdata = pipedata + maxpacket * pos;
452     memcpy_far(GET_SEG(SS), data
453                , FLATPTR_TO_SEG(intrdata), (void*)FLATPTR_TO_OFFSET(intrdata)
454                , maxpacket);
455
456     // Reenable this td.
457     SET_FLATPTR(tail->hwINFO, TD_DP_IN | TD_T_TOGGLE | TD_CC);
458     intrdata = pipedata + maxpacket * (tail-tds);
459     SET_FLATPTR(tail->hwCBP, (u32)intrdata);
460     SET_FLATPTR(tail->hwNextTD, (u32)next);
461     SET_FLATPTR(tail->hwBE, (u32)intrdata + maxpacket - 1);
462
463     SET_FLATPTR(pipe->ed.hwTailP, (u32)next);
464
465     return 0;
466 }