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