Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
243
setdebug(Hci*, int d)
244
{
245
	ehcidebug = d;
246
}
247
 
248
static void
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
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
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
351
usbehcilink(void)
352
{
353
	addhcitype("ehci", reset);
354
}