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