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