]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/usbehciomap.c
pc, pc64: warn when running out of conf.mem[] entries in meminit()
[plan9front.git] / sys / src / 9 / omap / usbehciomap.c
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        "usbehci.h"
16
17 static Ctlr* ctlrs[Nhcis];
18
19 static void
20 ehcireset(Ctlr *ctlr)
21 {
22         Eopio *opio;
23         int i;
24
25         ilock(ctlr);
26         dprint("ehci %#p reset\n", ctlr->capio);
27         opio = ctlr->opio;
28
29         /*
30          * Turn off legacy mode. Some controllers won't
31          * interrupt us as expected otherwise.
32          */
33         ehcirun(ctlr, 0);
34
35         /* clear high 32 bits of address signals if it's 64 bits capable.
36          * This is probably not needed but it does not hurt and others do it.
37          */
38         if((ctlr->capio->capparms & C64) != 0){
39                 dprint("ehci: 64 bits\n");
40                 opio->seg = 0;
41         }
42
43         opio->cmd |= Chcreset;  /* controller reset */
44         coherence();
45         for(i = 0; i < 100; i++){
46                 if((opio->cmd & Chcreset) == 0)
47                         break;
48                 delay(1);
49         }
50         if(i == 100)
51                 print("ehci %#p controller reset timed out\n", ctlr->capio);
52
53         /* requesting more interrupts per µframe may miss interrupts */
54         opio->cmd |= 0x10000;           /* 1 intr. per ms */
55         coherence();
56         switch(opio->cmd & Cflsmask){
57         case Cfls1024:
58                 ctlr->nframes = 1024;
59                 break;
60         case Cfls512:
61                 ctlr->nframes = 512;
62                 break;
63         case Cfls256:
64                 ctlr->nframes = 256;
65                 break;
66         default:
67                 panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
68         }
69         coherence();
70         dprint("ehci: %d frames\n", ctlr->nframes);
71         iunlock(ctlr);
72 }
73
74 static void
75 setdebug(Hci*, int d)
76 {
77         ehcidebug = d;
78 }
79
80 static void
81 shutdown(Hci *hp)
82 {
83         int i;
84         Ctlr *ctlr;
85         Eopio *opio;
86
87         ctlr = hp->aux;
88         ilock(ctlr);
89         opio = ctlr->opio;
90         opio->cmd |= Chcreset;          /* controller reset */
91         coherence();
92         for(i = 0; i < 100; i++){
93                 if((opio->cmd & Chcreset) == 0)
94                         break;
95                 delay(1);
96         }
97         if(i >= 100)
98                 print("ehci %#p controller reset timed out\n", ctlr->capio);
99         delay(100);
100         ehcirun(ctlr, 0);
101         opio->frbase = 0;
102         coherence();
103         iunlock(ctlr);
104 }
105
106 /*
107  * omap3-specific ehci code
108  */
109
110 enum {
111         /* opio->insn[5] bits */
112         Control         = 1<<31,  /* set to start access, cleared when done */
113         Write           = 2<<22,
114         Read            = 3<<22,
115         Portsh          = 24,
116         Regaddrsh       = 16,           /* 0x2f means use extended reg addr */
117         Eregaddrsh      = 8,
118
119         /* phy reg addresses */
120         Funcctlreg      = 4,
121         Ifcctlreg       = 7,
122
123         Phystppullupoff = 0x90,         /* on is 0x10 */
124
125         Phyrstport2     = 147,          /* gpio # */
126
127 };
128
129 static void
130 wrulpi(Eopio *opio, int port, int reg, uchar data)
131 {
132         opio->insn[5] = Control | port << Portsh | Write | reg << Regaddrsh |
133                 data;
134         coherence();
135         /*
136          * this seems contrary to the skimpy documentation in the manual
137          * but inverting the test hangs forever.
138          */
139         while (!(opio->insn[5] & Control))
140                 ;
141 }
142
143 static int
144 reset(Hci *hp)
145 {
146         Ctlr *ctlr;
147         Ecapio *capio;
148         Eopio *opio;
149         Uhh *uhh;
150         static int beenhere;
151
152         if (beenhere)
153                 return -1;
154         beenhere = 1;
155
156         if(getconf("*nousbehci") != nil || probeaddr(PHYSEHCI) < 0)
157                 return -1;
158
159         ctlr = smalloc(sizeof(Ctlr));
160         /*
161          * don't bother with vmap; i/o space is all mapped anyway,
162          * and a size less than 1MB will blow an assertion in mmukmap.
163          */
164         ctlr->capio = capio = (Ecapio *)PHYSEHCI;
165         ctlr->opio = opio = (Eopio*)((uintptr)capio + (capio->cap & 0xff));
166
167         hp->aux = ctlr;
168         hp->port = (uintptr)ctlr->capio;
169         hp->irq = 77;
170         hp->nports = capio->parms & Cnports;
171
172         ddprint("echi: %s, ncc %lud npcc %lud\n",
173                 capio->parms & 0x10000 ? "leds" : "no leds",
174                 (capio->parms >> 12) & 0xf, (capio->parms >> 8) & 0xf);
175         ddprint("ehci: routing %s, %sport power ctl, %d ports\n",
176                 capio->parms & 0x40 ? "explicit" : "automatic",
177                 capio->parms & 0x10 ? "" : "no ", hp->nports);
178
179         ctlr->tdalloc = ucallocalign;
180         ctlr->dmaalloc = ucalloc;
181         ctlr->dmafree = ucfree;
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
220         intrenable(hp->irq, hp->interrupt, hp, UNKNOWN, hp->type);
221
222         return 0;
223 }
224
225 void
226 usbehcilink(void)
227 {
228         addhcitype("ehci", reset);
229 }