xref: /plan9/sys/src/9/omap/usbehciomap.c (revision 5bdeb9a20ca533546de47a1bc407975caf1023f5)
1 /*
2  * OMAP3-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 
18 static Ctlr* ctlrs[Nhcis];
19 
20 static void
ehcireset(Ctlr * ctlr)21 ehcireset(Ctlr *ctlr)
22 {
23 	Eopio *opio;
24 	int i;
25 
26 	ilock(ctlr);
27 	dprint("ehci %#p reset\n", ctlr->capio);
28 	opio = ctlr->opio;
29 
30 	/*
31 	 * Turn off legacy mode. Some controllers won't
32 	 * interrupt us as expected otherwise.
33 	 */
34 	ehcirun(ctlr, 0);
35 
36 	/* clear high 32 bits of address signals if it's 64 bits capable.
37 	 * This is probably not needed but it does not hurt and others do it.
38 	 */
39 	if((ctlr->capio->capparms & C64) != 0){
40 		dprint("ehci: 64 bits\n");
41 		opio->seg = 0;
42 	}
43 
44 	if(ehcidebugcapio != ctlr->capio){
45 		opio->cmd |= Chcreset;	/* controller reset */
46 		coherence();
47 		for(i = 0; i < 100; i++){
48 			if((opio->cmd & Chcreset) == 0)
49 				break;
50 			delay(1);
51 		}
52 		if(i == 100)
53 			print("ehci %#p controller reset timed out\n", ctlr->capio);
54 	}
55 
56 	/* requesting more interrupts per µframe may miss interrupts */
57 	opio->cmd &= ~Citcmask;
58 	opio->cmd |= 1 << Citcshift;		/* max of 1 intr. per 125 µs */
59 	coherence();
60 	switch(opio->cmd & Cflsmask){
61 	case Cfls1024:
62 		ctlr->nframes = 1024;
63 		break;
64 	case Cfls512:
65 		ctlr->nframes = 512;
66 		break;
67 	case Cfls256:
68 		ctlr->nframes = 256;
69 		break;
70 	default:
71 		panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
72 	}
73 	coherence();
74 	dprint("ehci: %d frames\n", ctlr->nframes);
75 	iunlock(ctlr);
76 }
77 
78 static void
setdebug(Hci *,int d)79 setdebug(Hci*, int d)
80 {
81 	ehcidebug = d;
82 }
83 
84 static void
shutdown(Hci * hp)85 shutdown(Hci *hp)
86 {
87 	int i;
88 	Ctlr *ctlr;
89 	Eopio *opio;
90 
91 	ctlr = hp->aux;
92 	ilock(ctlr);
93 	opio = ctlr->opio;
94 	opio->cmd |= Chcreset;		/* controller reset */
95 	coherence();
96 	for(i = 0; i < 100; i++){
97 		if((opio->cmd & Chcreset) == 0)
98 			break;
99 		delay(1);
100 	}
101 	if(i >= 100)
102 		print("ehci %#p controller reset timed out\n", ctlr->capio);
103 	delay(100);
104 	ehcirun(ctlr, 0);
105 	opio->frbase = 0;
106 	coherence();
107 	iunlock(ctlr);
108 }
109 
110 /*
111  * omap3-specific ehci code
112  */
113 
114 enum {
115 	/* opio->insn[5] bits */
116 	Control		= 1<<31,  /* set to start access, cleared when done */
117 	Write		= 2<<22,
118 	Read		= 3<<22,
119 	Portsh		= 24,
120 	Regaddrsh	= 16,		/* 0x2f means use extended reg addr */
121 	Eregaddrsh	= 8,
122 
123 	/* phy reg addresses */
124 	Funcctlreg	= 4,
125 	Ifcctlreg	= 7,
126 
127 	Phystppullupoff	= 0x90,		/* on is 0x10 */
128 
129 	Phyrstport2	= 147,		/* gpio # */
130 
131 };
132 
133 static void
wrulpi(Eopio * opio,int port,int reg,uchar data)134 wrulpi(Eopio *opio, int port, int reg, uchar data)
135 {
136 	opio->insn[5] = Control | port << Portsh | Write | reg << Regaddrsh |
137 		data;
138 	coherence();
139 	/*
140 	 * this seems contrary to the skimpy documentation in the manual
141 	 * but inverting the test hangs forever.
142 	 */
143 	while (!(opio->insn[5] & Control))
144 		;
145 }
146 
147 static int
reset(Hci * hp)148 reset(Hci *hp)
149 {
150 	Ctlr *ctlr;
151 	Ecapio *capio;
152 	Eopio *opio;
153 	Uhh *uhh;
154 	static int beenhere;
155 
156 	if (beenhere)
157 		return -1;
158 	beenhere = 1;
159 
160 	if(getconf("*nousbehci") != nil || probeaddr(PHYSEHCI) < 0)
161 		return -1;
162 
163 	ctlr = smalloc(sizeof(Ctlr));
164 	/*
165 	 * don't bother with vmap; i/o space is all mapped anyway,
166 	 * and a size less than 1MB will blow an assertion in mmukmap.
167 	 */
168 	ctlr->capio = capio = (Ecapio *)PHYSEHCI;
169 	ctlr->opio = opio = (Eopio*)((uintptr)capio + (capio->cap & 0xff));
170 
171 	hp->aux = ctlr;
172 	hp->port = (uintptr)ctlr->capio;
173 	hp->irq = 77;
174 	hp->nports = capio->parms & Cnports;
175 
176 	ddprint("echi: %s, ncc %lud npcc %lud\n",
177 		capio->parms & 0x10000 ? "leds" : "no leds",
178 		(capio->parms >> 12) & 0xf, (capio->parms >> 8) & 0xf);
179 	ddprint("ehci: routing %s, %sport power ctl, %d ports\n",
180 		capio->parms & 0x40 ? "explicit" : "automatic",
181 		capio->parms & 0x10 ? "" : "no ", hp->nports);
182 
183 	ehcireset(ctlr);
184 	ehcimeminit(ctlr);
185 
186 	/* omap35-specific set up */
187 	/* bit 5 `must be set to 1 for proper behavior', spruf98d §23.2.6.7.17 */
188 	opio->insn[4] |= 1<<5;
189 	coherence();
190 
191 	/* insn[5] is for both utmi and ulpi, depending on hostconfig mode */
192 	uhh = (Uhh *)PHYSUHH;
193 	if (uhh->hostconfig & P1ulpi_bypass) {		/* utmi port 1 active */
194 		/* not doing this */
195 		iprint("usbehci: bypassing ulpi on port 1!\n");
196 		opio->insn[5] &= ~(MASK(4) << 13);
197 		opio->insn[5] |= 1 << 13;		/* select port 1 */
198 		coherence();
199 	} else {					/* ulpi port 1 active */
200 		/* TODO may need to reset gpio port2 here */
201 
202 		/* disable integrated stp pull-up resistor */
203 		wrulpi(opio, 1, Ifcctlreg, Phystppullupoff);
204 
205 		/* force phy to `high-speed' */
206 		wrulpi(opio, 1, Funcctlreg, 0x40);
207 	}
208 
209 	/*
210 	 * Linkage to the generic HCI driver.
211 	 */
212 	ehcilinkage(hp);
213 	hp->shutdown = shutdown;
214 	hp->debug = setdebug;
215 
216 	intrenable(78, hp->interrupt, hp, UNKNOWN, "usbtll");
217 	intrenable(92, hp->interrupt, hp, UNKNOWN, "usb otg");
218 	intrenable(93, hp->interrupt, hp, UNKNOWN, "usb otg dma");
219 	return 0;
220 }
221 
222 void
usbehcilink(void)223 usbehcilink(void)
224 {
225 	addhcitype("ehci", reset);
226 }
227