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