]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/kw/usbehcikw.c
merge
[plan9front.git] / sys / src / 9 / kw / usbehcikw.c
1 /*
2  * Kirkwood-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 //#include      "uncached.h"
17
18 #define WINTARG(ctl)    (((ctl) >> 4) & 017)
19 #define WINATTR(ctl)    (((ctl) >> 8) & 0377)
20 #define WIN64KSIZE(ctl) (((ctl) >> 16) + 1)
21
22 #define SIZETO64KSIZE(size) ((size) / (64*1024) - 1)
23
24 enum {
25         Debug = 0,
26 };
27
28 typedef struct Kwusb Kwusb;
29 typedef struct Kwusbtt Kwusbtt;
30 typedef struct Usbwin Usbwin;
31
32 /* kirkwood usb transaction translator registers? (undocumented) */
33 struct Kwusbtt {                /* at soc.ehci */
34         ulong   id;
35         ulong   hwgeneral;
36         ulong   hwhost;
37         ulong   hwdevice;
38         ulong   hwtxbuf;
39         ulong   hwrxbuf;
40         ulong   hwtttxbuf;
41         ulong   hwttrxbuf;
42 };
43
44 /* kirkwood usb bridge & phy registers */
45 struct Kwusb {                  /* at offset 0x300 from soc.ehci */
46         ulong   bcs;            /* bridge ctl & sts */
47         uchar   _pad0[0x310-0x304];
48
49         ulong   bic;            /* bridge intr. cause */
50         ulong   bim;            /* bridge intr. mask */
51         ulong   _pad1;
52         ulong   bea;            /* bridge error addr. */
53         struct Usbwin {
54                 ulong   ctl;    /* see Winenable in io.h */
55                 ulong   base;
56                 ulong   _pad2[2];
57         } win[4];
58         ulong   phycfg;         /* phy config. */
59         uchar   _pad3[0x400-0x364];
60
61         ulong   pwrctl;         /* power control */
62         uchar   _pad4[0x410-0x404];
63         ulong   phypll;         /* phy pll control */
64         uchar   _pad5[0x420-0x414];
65         ulong   phytxctl;       /* phy transmit control */
66         uchar   _pad6[0x430-0x424];
67         ulong   phyrxctl;       /* phy receive control */
68         uchar   _pad7[0x440-0x434];
69         ulong   phyivref;       /* phy ivref control */
70 };
71
72 static Ctlr* ctlrs[Nhcis];
73
74 static void
75 addrmapdump(void)
76 {
77         int i;
78         ulong ctl, targ, attr, size64k;
79         Kwusb *map;
80         Usbwin *win;
81
82         if (!Debug)
83                 return;
84         map = (Kwusb *)(soc.ehci + 0x300);
85         for (i = 0; i < nelem(map->win); i++) {
86                 win = &map->win[i];
87                 ctl = win->ctl;
88                 if (ctl & Winenable) {
89                         targ = WINTARG(ctl);
90                         attr = WINATTR(ctl);
91                         size64k = WIN64KSIZE(ctl);
92                         print("usbehci: address map window %d: "
93                                 "targ %ld attr %#lux size %,ld addr %#lux\n",
94                                 i, targ, attr, size64k * 64*1024, win->base);
95                 }
96         }
97 }
98
99 /* assumes ctlr is ilocked */
100 static void
101 ctlrreset(Ctlr *ctlr)
102 {
103         int i;
104         Eopio *opio;
105
106         opio = ctlr->opio;
107         opio->cmd |= Chcreset;
108         coherence();
109         /* wait for it to come out of reset */
110         for(i = 0; i < 100 && opio->cmd & Chcreset; i++)
111                 delay(1);
112         if(i >= 100)
113                 print("ehci %#p controller reset timed out\n", ctlr->capio);
114         /*
115          * Marvell errata FE-USB-340 workaround: 1 << 4 magic:
116          * disable streaming.  Magic 3 (usb host mode) from the linux driver
117          * makes it work.  Ick.
118          */
119         opio->usbmode |= 1 << 4 | 3;
120         coherence();
121 }
122
123 /*
124  * configure window `win' as 256MB dram with attribute `attr' and
125  * base address
126  */
127 static void
128 setaddrwin(Kwusb *kw, int win, int attr, ulong base)
129 {
130         kw->win[win].ctl = Winenable | Targdram << 4 | attr << 8 |
131                 SIZETO64KSIZE(256*MB) << 16;
132         kw->win[win].base = base;
133 }
134
135 static void
136 ehcireset(Ctlr *ctlr)
137 {
138         int i, amp, txvdd;
139         ulong v;
140         Eopio *opio;
141         Kwusb *kw;
142
143         ilock(ctlr);
144         dprint("ehci %#p reset\n", ctlr->capio);
145         opio = ctlr->opio;
146
147         kw = (Kwusb *)(soc.ehci + 0x300);
148         kw->bic = 0;
149         kw->bim = (1<<4) - 1;           /* enable all defined intrs */
150         ctlrreset(ctlr);
151
152         /*
153          * clear high 32 bits of address signals if it's 64 bits capable.
154          * This is probably not needed but it does not hurt and others do it.
155          */
156         if((ctlr->capio->capparms & C64) != 0){
157                 dprint("ehci: 64 bits\n");
158                 opio->seg = 0;
159         }
160
161         /* requesting more interrupts per µframe may miss interrupts */
162         opio->cmd |= Citc8;             /* 1 intr. per ms */
163         switch(opio->cmd & Cflsmask){
164         case Cfls1024:
165                 ctlr->nframes = 1024;
166                 break;
167         case Cfls512:
168                 ctlr->nframes = 512;
169                 break;
170         case Cfls256:
171                 ctlr->nframes = 256;
172                 break;
173         default:
174                 panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
175         }
176         dprint("ehci: %d frames\n", ctlr->nframes);
177
178         /*
179          * set up the USB address map (bridge address decoding)
180          */
181         for (i = 0; i < nelem(kw->win); i++)
182                 kw->win[i].ctl = kw->win[i].base = 0;
183         coherence();
184
185         setaddrwin(kw, 0, Attrcs0, 0);
186         setaddrwin(kw, 1, Attrcs1, 256*MB);
187         coherence();
188
189         if (Debug)
190                 if (kw->bcs & (1 << 4))
191                         print("usbehci: not swapping bytes\n");
192                 else
193                         print("usbehci: swapping bytes\n");
194         addrmapdump();                          /* verify sanity */
195
196         kw->pwrctl |= 1 << 0 | 1 << 1;          /* Pu | PuPll */
197         coherence();
198
199         /*
200          * Marvell guideline GL-USB-160.
201          */
202         kw->phypll |= 1 << 21;          /* VCOCAL_START: PLL calibration */
203         coherence();
204         microdelay(100);
205         kw->phypll &= ~(1 << 21);
206
207         v = kw->phytxctl & ~(017 << 27 | 7);    /* REG_EXT_FS_RCALL & AMP_2_0 */
208         switch (m->socrev) {
209         default:
210                 print("usbehci: bad 6281 soc rev %d\n", m->socrev);
211                 /* fall through */
212         case Socreva0:
213                 amp = 4;
214                 txvdd = 1;
215                 break;
216         case Socreva1:
217                 amp = 3;
218                 txvdd = 3;
219                 break;
220         }
221         /* REG_EXT_FS_RCALL_EN | REG_RCAL_START | AMP_2_0 */
222         kw->phytxctl = v | 1 << 26 | 1 << 12 | amp;
223         coherence();
224         microdelay(100);
225         kw->phytxctl &= ~(1 << 12);
226
227         v = kw->phyrxctl & ~(3 << 2 | 017 << 4); /* LPF_COEF_1_0 & SQ_THRESH_3_0 */
228         kw->phyrxctl = v | 1 << 2 | 8 << 4;
229
230         v = kw->phyivref & ~(3 << 8);           /* TXVDD12 */
231         kw->phyivref = v | txvdd << 8;
232         coherence();
233
234         ehcirun(ctlr, 0);
235         ctlrreset(ctlr);
236
237         iunlock(ctlr);
238 }
239
240 static void
241 setdebug(Hci*, int d)
242 {
243         ehcidebug = d;
244 }
245
246 static void
247 shutdown(Hci *hp)
248 {
249         Ctlr *ctlr;
250         Eopio *opio;
251
252         ctlr = hp->aux;
253         ilock(ctlr);
254         ctlrreset(ctlr);
255
256         delay(100);
257         ehcirun(ctlr, 0);
258
259         opio = ctlr->opio;
260         opio->frbase = 0;
261         coherence();
262         iunlock(ctlr);
263 }
264
265 static void
266 findehcis(void)         /* actually just use fixed addresses on sheeva */
267 {
268         int i;
269         Ctlr *ctlr;
270         static int already = 0;
271
272         if(already)
273                 return;
274         already = 1;
275
276         ctlr = smalloc(sizeof(Ctlr));
277         /* the sheeva's usb 2.0 otg uses a superset of the ehci registers */
278         ctlr->capio = (Ecapio *)(soc.ehci + 0x100);
279         ctlr->opio  = (Eopio *) (soc.ehci + 0x140);
280         dprint("usbehci: port %#p\n", ctlr->capio);
281
282         for(i = 0; i < Nhcis; i++)
283                 if(ctlrs[i] == nil){
284                         ctlrs[i] = ctlr;
285                         break;
286                 }
287         if(i == Nhcis)
288                 print("ehci: bug: more than %d controllers\n", Nhcis);
289 }
290
291 static int
292 reset(Hci *hp)
293 {
294         static Lock resetlck;
295         int i;
296         Ctlr *ctlr;
297         Ecapio *capio;
298
299         ilock(&resetlck);
300         findehcis();
301
302         /*
303          * Any adapter matches if no hp->port is supplied,
304          * otherwise the ports must match.
305          */
306         ctlr = nil;
307         for(i = 0; i < Nhcis && ctlrs[i] != nil; i++){
308                 ctlr = ctlrs[i];
309                 if(ctlr->active == 0)
310                 if(hp->port == 0 || hp->port == (uintptr)ctlr->capio){
311                         ctlr->active = 1;
312                         break;
313                 }
314         }
315         iunlock(&resetlck);
316         if(ctlrs[i] == nil || i == Nhcis)
317                 return -1;
318
319         hp->aux = ctlr;
320         hp->port = (uintptr)ctlr->capio;
321         hp->irq = IRQ0usb0;
322         hp->tbdf = 0;
323
324         capio = ctlr->capio;
325         hp->nports = capio->parms & Cnports;
326
327         ddprint("echi: %s, ncc %lud npcc %lud\n",
328                 capio->parms & 0x10000 ? "leds" : "no leds",
329                 (capio->parms >> 12) & 0xf, (capio->parms >> 8) & 0xf);
330         ddprint("ehci: routing %s, %sport power ctl, %d ports\n",
331                 capio->parms & 0x40 ? "explicit" : "automatic",
332                 capio->parms & 0x10 ? "" : "no ", hp->nports);
333
334         ehcireset(ctlr);
335         ehcimeminit(ctlr);
336
337         /*
338          * Linkage to the generic HCI driver.
339          */
340         ehcilinkage(hp);
341         hp->shutdown = shutdown;
342         hp->debug = setdebug;
343
344         intrenable(Irqlo, hp->irq, hp->interrupt, hp, hp->type);
345
346         return 0;
347 }
348
349 void
350 usbehcilink(void)
351 {
352         addhcitype("ehci", reset);
353 }