]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/emmc.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / zynq / emmc.c
1 /*
2  * external mass media controller (mmc / sd host interface)
3  *
4  * derived from Richard Miller's bcm/emmc.c
5  */
6
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "../port/error.h"
10 #include "mem.h"
11 #include "dat.h"
12 #include "fns.h"
13 #include "io.h"
14 #include "../port/sd.h"
15
16 enum {
17         Initfreq        = 400000,       /* initialisation frequency for MMC */
18         SDfreq          = 25000000,     /* standard SD frequency */
19         DTO             = 14,           /* data timeout exponent (guesswork) */
20
21         MMCSelect       = 7,            /* mmc/sd card select command */
22         Setbuswidth     = 6,            /* mmc/sd set bus width command */
23 };
24
25 enum {
26         /* Controller registers */
27         Sysaddr                 = 0x00>>2,
28         Blksizecnt              = 0x04>>2,
29         Arg1                    = 0x08>>2,
30         Cmdtm                   = 0x0c>>2,
31         Resp0                   = 0x10>>2,
32         Resp1                   = 0x14>>2,
33         Resp2                   = 0x18>>2,
34         Resp3                   = 0x1c>>2,
35         Data                    = 0x20>>2,
36         Status                  = 0x24>>2,
37         Control0                = 0x28>>2,
38         Control1                = 0x2c>>2,
39         Interrupt               = 0x30>>2,
40         Irptmask                = 0x34>>2,
41         Irpten                  = 0x38>>2,
42         Capabilites             = 0x40>>2,
43         Forceirpt               = 0x50>>2,
44         Boottimeout             = 0x60>>2,
45         Dbgsel                  = 0x64>>2,
46         Spiintspt               = 0xf0>>2,
47         Slotisrver              = 0xfc>>2,
48
49         /* Control0 */
50         Dwidth4                 = 1<<1,
51         Dwidth1                 = 0<<1,
52
53         /* Control1 */
54         Srstdata                = 1<<26,        /* reset data circuit */
55         Srstcmd                 = 1<<25,        /* reset command circuit */
56         Srsthc                  = 1<<24,        /* reset complete host controller */
57         Datatoshift             = 16,           /* data timeout unit exponent */
58         Datatomask              = 0xF0000,
59         Clkfreq8shift           = 8,            /* SD clock base divider LSBs */
60         Clkfreq8mask            = 0xFF00,
61         Clkfreqms2shift         = 6,            /* SD clock base divider MSBs */
62         Clkfreqms2mask          = 0xC0,
63         Clkgendiv               = 0<<5,         /* SD clock divided */
64         Clkgenprog              = 1<<5,         /* SD clock programmable */
65         Clken                   = 1<<2,         /* SD clock enable */
66         Clkstable               = 1<<1, 
67         Clkintlen               = 1<<0,         /* enable internal EMMC clocks */
68
69         /* Cmdtm */
70         Indexshift              = 24,
71         Suspend                 = 1<<22,
72         Resume                  = 2<<22,
73         Abort                   = 3<<22,
74         Isdata                  = 1<<21,
75         Ixchken                 = 1<<20,
76         Crcchken                = 1<<19,
77         Respmask                = 3<<16,
78         Respnone                = 0<<16,
79         Resp136                 = 1<<16,
80         Resp48                  = 2<<16,
81         Resp48busy              = 3<<16,
82         Multiblock              = 1<<5,
83         Host2card               = 0<<4,
84         Card2host               = 1<<4,
85         Autocmd12               = 1<<2,
86         Autocmd23               = 2<<2,
87         Blkcnten                = 1<<1,
88         Dmaen                   = 1<<0,
89
90         /* Interrupt */
91         Acmderr         = 1<<24,
92         Denderr         = 1<<22,
93         Dcrcerr         = 1<<21,
94         Dtoerr          = 1<<20,
95         Cbaderr         = 1<<19,
96         Cenderr         = 1<<18,
97         Ccrcerr         = 1<<17,
98         Ctoerr          = 1<<16,
99         Err             = 1<<15,
100         Cardintr        = 1<<8,
101         Cardinsert      = 1<<6,
102         Readrdy         = 1<<5,
103         Writerdy        = 1<<4,
104         Dmaintr         = 1<<3,
105         Datadone        = 1<<1,
106         Cmddone         = 1<<0,
107
108         /* Status */
109         Present         = 1<<18,
110         Bufread         = 1<<11,
111         Bufwrite        = 1<<10,
112         Readtrans       = 1<<9,
113         Writetrans      = 1<<8,
114         Datactive       = 1<<2,
115         Datinhibit      = 1<<1,
116         Cmdinhibit      = 1<<0,
117 };
118
119 static int cmdinfo[64] = {
120 [0]  Ixchken,
121 [2]  Resp136,
122 [3]  Resp48 | Ixchken | Crcchken,
123 [6]  Resp48 | Ixchken | Crcchken,
124 [7]  Resp48busy | Ixchken | Crcchken,
125 [8]  Resp48 | Ixchken | Crcchken,
126 [9]  Resp136,
127 [12] Resp48busy | Ixchken | Crcchken,
128 [13] Resp48 | Ixchken | Crcchken,
129 [16] Resp48,
130 [17] Resp48 | Isdata | Card2host | Ixchken | Crcchken | Dmaen,
131 [18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken | Dmaen,
132 [24] Resp48 | Isdata | Host2card | Ixchken | Crcchken | Dmaen,
133 [25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken | Dmaen,
134 [41] Resp48,
135 [55] Resp48 | Ixchken | Crcchken,
136 };
137
138 typedef struct Ctlr Ctlr;
139 struct Ctlr {
140         Rendez  r;
141         u32int  *regs;
142         int     datadone;
143         int     fastclock;
144         ulong   extclk;
145         int     irq;
146 };
147
148 static Ctlr emmc;
149
150 static uint
151 clkdiv(uint d)
152 {
153         uint v;
154
155         assert(d < 1<<10);
156         v = (d << Clkfreq8shift) & Clkfreq8mask;
157         v |= ((d >> 8) << Clkfreqms2shift) & Clkfreqms2mask;
158         return v;
159 }
160
161 static void
162 interrupt(Ureg*, void*)
163 {       
164         u32int *r;
165         int i;
166
167         r = emmc.regs;
168         i = r[Interrupt];
169         r[Interrupt] = i & (Datadone|Err);
170         emmc.datadone = i;
171         wakeup(&emmc.r);
172 }
173
174 static int
175 datadone(void*)
176 {
177         return emmc.datadone;
178 }
179
180 static int
181 emmcinit(void)
182 {
183         u32int *r;
184         int i;
185
186         emmc.extclk = 100000000;
187         emmc.irq = SDIO1IRQ;
188         r = vmap(SDIO_BASE, 0x100);
189         emmc.regs = r;
190         r[Control1] = Srsthc;
191         for(i = 0; i < 100; i++){
192                 delay(10);
193                 if((r[Control1] & Srsthc) == 0)
194                         return 0;
195         }
196         print("emmc: reset timeout!\n");
197         return -1;
198 }
199
200 static int
201 emmcinquiry(char *inquiry, int inqlen)
202 {
203         uint ver;
204
205         ver = emmc.regs[Slotisrver] >> 16;
206         return snprint(inquiry, inqlen,
207                 "eMMC SD Host Controller %2.2x Version %2.2x",
208                 ver&0xFF, ver>>8);
209 }
210
211 static void
212 emmcenable(void)
213 {
214         int i;
215
216         emmc.regs[Control1] = clkdiv(emmc.extclk / Initfreq - 1) | DTO << Datatoshift |
217                 Clkgendiv | Clken | Clkintlen;
218         for(i = 0; i < 1000; i++){
219                 delay(1);
220                 if(emmc.regs[Control1] & Clkstable)
221                         break;
222         }
223         if(i == 1000)
224                 print("SD clock won't initialise!\n");
225         emmc.regs[Irptmask] = ~(Dtoerr|Cardintr|Dmaintr);
226         intrenable(emmc.irq, interrupt, nil, LEVEL, sdio.name);
227 }
228
229 static int
230 emmccmd(u32int cmd, u32int arg, u32int *resp)
231 {
232         ulong now;
233         u32int *r;
234         u32int c;
235         int i;
236
237         assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
238         c = (cmd << Indexshift) | cmdinfo[cmd];
239
240         r = emmc.regs;
241         if(r[Status] & Cmdinhibit){
242                 print("emmccmd: need to reset Cmdinhibit intr %ux stat %ux\n",
243                         r[Interrupt], r[Status]);
244                 r[Control1] |= Srstcmd;
245                 while(r[Control1] & Srstcmd)
246                         ;
247                 while(r[Status] & Cmdinhibit)
248                         ;
249         }
250         if((c & Isdata || (c & Respmask) == Resp48busy) &&
251             r[Status] & Datinhibit){
252                 print("emmccmd: need to reset Datinhibit intr %ux stat %ux\n",
253                         r[Interrupt], r[Status]);
254                 r[Control1] |= Srstdata;
255                 while(r[Control1] & Srstdata)
256                         ;
257                 while(r[Status] & Datinhibit)
258                         ;
259         }
260         r[Arg1] = arg;
261         if((i = r[Interrupt]) != 0){
262                 if(i != Cardinsert)
263                         print("emmc: before command, intr was %ux\n", i);
264                 r[Interrupt] = i;
265         }
266         r[Cmdtm] = c;
267         now = m->ticks;
268         while(((i=r[Interrupt])&(Cmddone|Err)) == 0)
269                 if((long)(m->ticks-now) > HZ)
270                         break;
271         if((i&(Cmddone|Err)) != Cmddone){
272                 if((i&~Err) != Ctoerr)
273                         print("emmc: cmd %ux error intr %ux stat %ux\n", c, i, r[Status]);
274                 r[Interrupt] = i;
275                 if(r[Status]&Cmdinhibit){
276                         r[Control1] |= Srstcmd;
277                         while(r[Control1]&Srstcmd)
278                                 ;
279                 }
280                 error(Eio);
281         }
282         r[Interrupt] = i & ~(Datadone|Readrdy|Writerdy);
283         switch(c & Respmask){
284         case Resp136:
285                 resp[0] = r[Resp0]<<8;
286                 resp[1] = r[Resp0]>>24 | r[Resp1]<<8;
287                 resp[2] = r[Resp1]>>24 | r[Resp2]<<8;
288                 resp[3] = r[Resp2]>>24 | r[Resp3]<<8;
289                 break;
290         case Resp48:
291         case Resp48busy:
292                 resp[0] = r[Resp0];
293                 break;
294         case Respnone:
295                 resp[0] = 0;
296                 break;
297         }
298         if((c & Respmask) == Resp48busy){
299                 r[Irpten] = Datadone|Err;
300                 tsleep(&emmc.r, datadone, 0, 3000);
301                 i = emmc.datadone;
302                 emmc.datadone = 0;
303                 r[Irpten] = 0;
304                 if((i & Datadone) == 0)
305                         print("emmcio: no Datadone after CMD%d\n", cmd);
306                 if(i & Err)
307                         print("emmcio: CMD%d error interrupt %ux\n",
308                                 cmd, r[Interrupt]);
309                 r[Interrupt] = i;
310         }
311         /*
312          * Once card is selected, use faster clock
313          */
314         if(cmd == MMCSelect){
315                 delay(10);
316                 r[Control1] = clkdiv(emmc.extclk / SDfreq - 1) |
317                         DTO << Datatoshift | Clkgendiv | Clken | Clkintlen;
318                 for(i = 0; i < 1000; i++){
319                         delay(1);
320                         if(r[Control1] & Clkstable)
321                                 break;
322                 }
323                 delay(10);
324                 emmc.fastclock = 1;
325         }
326         /*
327          * If card bus width changes, change host bus width
328          */
329         if(cmd == Setbuswidth)
330                 switch(arg){
331                 case 0:
332                         r[Control0] &= ~Dwidth4;
333                         break;
334                 case 2:
335                         r[Control0] |= Dwidth4;
336                         break;
337                 }
338         return 0;
339 }
340
341 static void
342 emmciosetup(int, void *buf, int bsize, int bcount)
343 {
344         u32int *r;
345         uintptr pa;
346         int len;
347
348         len = bsize*bcount;
349         if(len > (0x1000<<7))
350                 error(Etoobig);
351
352         pa = PADDR(buf);
353         cleandse((uchar*)buf, (uchar*)buf+len);
354         clean2pa(pa, pa+len);
355
356         r = emmc.regs;
357         r[Sysaddr] = pa;
358         r[Blksizecnt] = 7<<12 | bcount<<16 | bsize;
359         r[Irpten] = Datadone|Err;
360 }
361
362 static void
363 emmcio(int write, uchar *buf, int len)
364 {
365         u32int *r;
366         int i;
367
368         tsleep(&emmc.r, datadone, 0, 3000);
369         i = emmc.datadone;
370         emmc.datadone = 0;
371
372         r = emmc.regs;
373         r[Irpten] = 0;
374         if((i & Datadone) == 0){
375                 print("emmcio: %d timeout intr %ux stat %ux\n",
376                         write, i, r[Status]);
377                 r[Interrupt] = i;
378                 error(Eio);
379         }
380         if(i & Err){
381                 print("emmcio: %d error intr %ux stat %ux\n",
382                         write, r[Interrupt], r[Status]);
383                 r[Interrupt] = i;
384                 error(Eio);
385         }
386         if(i)
387                 r[Interrupt] = i;
388
389         if(!write){
390                 uintptr pa = PADDR(buf);
391                 invaldse((uchar*)buf, (uchar*)buf+len);
392                 inval2pa(pa, pa+len);
393         }
394 }
395
396 SDio sdio = {
397         "emmc",
398         emmcinit,
399         emmcenable,
400         emmcinquiry,
401         emmccmd,
402         emmciosetup,
403         emmcio,
404 };