]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/emmc.c
audiohda: fix syntax error
[plan9front.git] / sys / src / 9 / bcm / emmc.c
1 /*
2  * bcm2835 external mass media controller (mmc / sd host interface)
3  *
4  * Copyright © 2012 Richard Miller <r.miller@acm.org>
5  */
6
7 /*
8         Not officially documented: emmc can be connected to different gpio pins
9                 48-53 (SD card)
10                 22-27 (P1 header)
11                 34-39 (wifi - pi3 only)
12         using ALT3 function to activate the required routing
13 */
14
15 #include "u.h"
16 #include "../port/lib.h"
17 #include "../port/error.h"
18 #include "mem.h"
19 #include "dat.h"
20 #include "fns.h"
21 #include "io.h"
22 #include "../port/sd.h"
23
24 #define EMMCREGS        (VIRTIO+0x300000)
25
26 enum {
27         Extfreq         = 100*Mhz,      /* guess external clock frequency if */
28                                         /* not available from vcore */
29         Initfreq        = 400000,       /* initialisation frequency for MMC */
30         SDfreq          = 25*Mhz,       /* standard SD frequency */
31         SDfreqhs        = 50*Mhz,       /* high speed frequency */
32         DTO             = 14,           /* data timeout exponent (guesswork) */
33
34         GoIdle          = 0,            /* mmc/sdio go idle state */
35         MMCSelect       = 7,            /* mmc/sd card select command */
36         Setbuswidth     = 6,            /* mmc/sd set bus width command */
37
38         Switchfunc      = 6,            /* mmc/sd switch function command */
39         Voltageswitch   = 11,           /* md/sdio switch to 1.8V */
40         IORWdirect      = 52,           /* sdio read/write direct command */
41         IORWextended    = 53,           /* sdio read/write extended command */
42         Appcmd          = 55,           /* mmc/sd application command prefix */
43 };
44
45 enum {
46         /* Controller registers */
47         Arg2                    = 0x00>>2,
48         Blksizecnt              = 0x04>>2,
49         Arg1                    = 0x08>>2,
50         Cmdtm                   = 0x0c>>2,
51         Resp0                   = 0x10>>2,
52         Resp1                   = 0x14>>2,
53         Resp2                   = 0x18>>2,
54         Resp3                   = 0x1c>>2,
55         Data                    = 0x20>>2,
56         Status                  = 0x24>>2,
57         Control0                = 0x28>>2,
58         Control1                = 0x2c>>2,
59         Interrupt               = 0x30>>2,
60         Irptmask                = 0x34>>2,
61         Irpten                  = 0x38>>2,
62         Control2                = 0x3c>>2,
63         Forceirpt               = 0x50>>2,
64         Boottimeout             = 0x70>>2,
65         Dbgsel                  = 0x74>>2,
66         Exrdfifocfg             = 0x80>>2,
67         Exrdfifoen              = 0x84>>2,
68         Tunestep                = 0x88>>2,
69         Tunestepsstd            = 0x8c>>2,
70         Tunestepsddr            = 0x90>>2,
71         Spiintspt               = 0xf0>>2,
72         Slotisrver              = 0xfc>>2,
73
74         /* Control0 */
75         Hispeed                 = 1<<2, 
76         Dwidth4                 = 1<<1,
77         Dwidth1                 = 0<<1,
78
79         /* Control1 */
80         Srstdata                = 1<<26,        /* reset data circuit */
81         Srstcmd                 = 1<<25,        /* reset command circuit */
82         Srsthc                  = 1<<24,        /* reset complete host controller */
83         Datatoshift             = 16,           /* data timeout unit exponent */
84         Datatomask              = 0xF0000,
85         Clkfreq8shift           = 8,            /* SD clock base divider LSBs */
86         Clkfreq8mask            = 0xFF00,
87         Clkfreqms2shift         = 6,            /* SD clock base divider MSBs */
88         Clkfreqms2mask          = 0xC0,
89         Clkgendiv               = 0<<5,         /* SD clock divided */
90         Clkgenprog              = 1<<5,         /* SD clock programmable */
91         Clken                   = 1<<2,         /* SD clock enable */
92         Clkstable               = 1<<1, 
93         Clkintlen               = 1<<0,         /* enable internal EMMC clocks */
94
95         /* Cmdtm */
96         Indexshift              = 24,
97         Suspend                 = 1<<22,
98         Resume                  = 2<<22,
99         Abort                   = 3<<22,
100         Isdata                  = 1<<21,
101         Ixchken                 = 1<<20,
102         Crcchken                = 1<<19,
103         Respmask                = 3<<16,
104         Respnone                = 0<<16,
105         Resp136                 = 1<<16,
106         Resp48                  = 2<<16,
107         Resp48busy              = 3<<16,
108         Multiblock              = 1<<5,
109         Host2card               = 0<<4,
110         Card2host               = 1<<4,
111         Autocmd12               = 1<<2,
112         Autocmd23               = 2<<2,
113         Blkcnten                = 1<<1,
114
115         /* Interrupt */
116         Acmderr         = 1<<24,
117         Denderr         = 1<<22,
118         Dcrcerr         = 1<<21,
119         Dtoerr          = 1<<20,
120         Cbaderr         = 1<<19,
121         Cenderr         = 1<<18,
122         Ccrcerr         = 1<<17,
123         Ctoerr          = 1<<16,
124         Err             = 1<<15,
125         Cardintr        = 1<<8,         /* not in Broadcom datasheet */
126         Cardinsert      = 1<<6,         /* not in Broadcom datasheet */
127         Readrdy         = 1<<5,
128         Writerdy        = 1<<4,
129         Datadone        = 1<<1,
130         Cmddone         = 1<<0,
131
132         /* Status */
133         Bufread         = 1<<11,        /* not in Broadcom datasheet */
134         Bufwrite        = 1<<10,        /* not in Broadcom datasheet */
135         Readtrans       = 1<<9,
136         Writetrans      = 1<<8,
137         Datactive       = 1<<2,
138         Datinhibit      = 1<<1,
139         Cmdinhibit      = 1<<0,
140 };
141
142 static int cmdinfo[64] = {
143 [0]  Ixchken,
144 [2]  Resp136,
145 [3]  Resp48 | Ixchken | Crcchken,
146 [5]  Resp48,
147 [6]  Resp48 | Ixchken | Crcchken,
148 [7]  Resp48busy | Ixchken | Crcchken,
149 [8]  Resp48 | Ixchken | Crcchken,
150 [9]  Resp136,
151 [11] Resp48 | Ixchken | Crcchken,
152 [12] Resp48busy | Ixchken | Crcchken,
153 [13] Resp48 | Ixchken | Crcchken,
154 [16] Resp48,
155 [17] Resp48 | Isdata | Card2host | Ixchken | Crcchken,
156 [18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken,
157 [24] Resp48 | Isdata | Host2card | Ixchken | Crcchken,
158 [25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken,
159 [41] Resp48,
160 [52] Resp48 | Ixchken | Crcchken,
161 [53] Resp48 | Ixchken | Crcchken | Isdata,
162 [55] Resp48 | Ixchken | Crcchken,
163 };
164
165 typedef struct Ctlr Ctlr;
166
167 struct Ctlr {
168         Rendez  r;
169         Rendez  cardr;
170         int     fastclock;
171         ulong   extclk;
172         int     appcmd;
173 };
174
175 static Ctlr emmc;
176
177 static void mmcinterrupt(Ureg*, void*);
178
179 static void
180 WR(int reg, u32int val)
181 {
182         u32int *r = (u32int*)EMMCREGS;
183
184         if(0)print("WR %2.2ux %ux\n", reg<<2, val);
185         microdelay(emmc.fastclock ? 2: 20);
186         coherence();
187         r[reg] = val;
188 }
189
190 static uint
191 clkdiv(uint d)
192 {
193         uint v;
194
195         assert(d < 1<<10);
196         v = (d << Clkfreq8shift) & Clkfreq8mask;
197         v |= ((d >> 8) << Clkfreqms2shift) & Clkfreqms2mask;
198         return v;
199 }
200
201 static void
202 emmcclk(uint freq)
203 {
204         u32int *r;
205         uint div;
206         int i;
207
208         r = (u32int*)EMMCREGS;
209         div = emmc.extclk / (freq<<1);
210         if(emmc.extclk / (div<<1) > freq)
211                 div++;
212         WR(Control1, clkdiv(div) |
213                 DTO<<Datatoshift | Clkgendiv | Clken | Clkintlen);
214         for(i = 0; i < 1000; i++){
215                 delay(1);
216                 if(r[Control1] & Clkstable)
217                         break;
218         }
219         if(i == 1000)
220                 print("emmc: can't set clock to %ud\n", freq);
221 }
222
223 static int
224 datadone(void*)
225 {
226         int i;
227
228         u32int *r = (u32int*)EMMCREGS;
229         i = r[Interrupt];
230         return i & (Datadone|Err);
231 }
232
233 static int
234 cardintready(void*)
235 {
236         int i;
237
238         u32int *r = (u32int*)EMMCREGS;
239         i = r[Interrupt];
240         return i & Cardintr;
241 }
242
243 static int
244 emmcinit(void)
245 {
246         u32int *r;
247         ulong clk;
248
249         clk = getclkrate(ClkEmmc);
250         if(clk == 0){
251                 clk = Extfreq;
252                 print("emmc: assuming external clock %lud Mhz\n", clk/1000000);
253         }
254         emmc.extclk = clk;
255         r = (u32int*)EMMCREGS;
256         if(0)print("emmc control %8.8ux %8.8ux %8.8ux\n",
257                 r[Control0], r[Control1], r[Control2]);
258         WR(Control1, Srsthc);
259         delay(10);
260         while(r[Control1] & Srsthc)
261                 ;
262         WR(Control1, Srstdata);
263         delay(10);
264         WR(Control1, 0);
265         return 0;
266 }
267
268 static int
269 emmcinquiry(char *inquiry, int inqlen)
270 {
271         u32int *r;
272         uint ver;
273
274         r = (u32int*)EMMCREGS;
275         ver = r[Slotisrver] >> 16;
276         return snprint(inquiry, inqlen,
277                 "Arasan eMMC SD Host Controller %2.2x Version %2.2x",
278                 ver&0xFF, ver>>8);
279 }
280
281 static void
282 emmcenable(void)
283 {
284         emmcclk(Initfreq);
285         WR(Irpten, 0);
286         WR(Irptmask, ~0);
287         WR(Interrupt, ~0);
288         intrenable(IRQmmc, mmcinterrupt, nil, BUSUNKNOWN, "mmc");
289 }
290
291 static int
292 emmccmd(u32int cmd, u32int arg, u32int *resp)
293 {
294         u32int *r;
295         u32int c;
296         int i;
297         ulong now;
298
299         r = (u32int*)EMMCREGS;
300         assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
301         c = (cmd << Indexshift) | cmdinfo[cmd];
302         /*
303          * CMD6 may be Setbuswidth or Switchfunc depending on Appcmd prefix
304          */
305         if(cmd == Switchfunc && !emmc.appcmd)
306                 c |= Isdata|Card2host;
307         if(cmd == IORWextended){
308                 if(arg & (1<<31))
309                         c |= Host2card;
310                 else
311                         c |= Card2host;
312                 if((r[Blksizecnt]&0xFFFF0000) != 0x10000)
313                         c |= Multiblock | Blkcnten;
314         }
315         /*
316          * GoIdle indicates new card insertion: reset bus width & speed
317          */
318         if(cmd == GoIdle){
319                 WR(Control0, r[Control0] & ~(Dwidth4|Hispeed));
320                 emmcclk(Initfreq);
321         }
322         if((r[Status] & Datinhibit) &&
323            ((c & Isdata) || (c & Respmask) == Resp48busy)){
324                 print("emmccmd: need to reset Cmdinhibit intr %ux stat %ux\n",
325                         r[Interrupt], r[Status]);
326                 WR(Control1, r[Control1] | Srstcmd);
327                 while(r[Control1] & Srstcmd)
328                         ;
329                 while(r[Status] & Cmdinhibit)
330                         ;
331         }
332         if((c & Isdata || (c & Respmask) == Resp48busy) &&
333             r[Status] & Datinhibit){
334                 print("emmccmd: need to reset Datinhibit intr %ux stat %ux\n",
335                         r[Interrupt], r[Status]);
336                 WR(Control1, r[Control1] | Srstdata);
337                 while(r[Control1] & Srstdata)
338                         ;
339                 while(r[Status] & Datinhibit)
340                         ;
341         }
342         WR(Arg1, arg);
343         if((i = (r[Interrupt] & ~Cardintr)) != 0){
344                 if(i != Cardinsert)
345                         print("emmc: before command, intr was %ux\n", i);
346                 WR(Interrupt, i);
347         }
348         WR(Cmdtm, c);
349         now = m->ticks;
350         while(((i=r[Interrupt])&(Cmddone|Err)) == 0)
351                 if(m->ticks-now > HZ)
352                         break;
353         if((i&(Cmddone|Err)) != Cmddone){
354                 if((i&~(Err|Cardintr)) != Ctoerr)
355                         print("emmc: cmd %ux arg %ux error intr %ux stat %ux\n", c, arg, i, r[Status]);
356                 WR(Interrupt, i);
357                 if(r[Status]&Cmdinhibit){
358                         WR(Control1, r[Control1]|Srstcmd);
359                         while(r[Control1]&Srstcmd)
360                                 ;
361                 }
362                 error(Eio);
363         }
364         WR(Interrupt, i & ~(Datadone|Readrdy|Writerdy));
365         switch(c & Respmask){
366         case Resp136:
367                 resp[0] = r[Resp0]<<8;
368                 resp[1] = r[Resp0]>>24 | r[Resp1]<<8;
369                 resp[2] = r[Resp1]>>24 | r[Resp2]<<8;
370                 resp[3] = r[Resp2]>>24 | r[Resp3]<<8;
371                 break;
372         case Resp48:
373         case Resp48busy:
374                 resp[0] = r[Resp0];
375                 break;
376         case Respnone:
377                 resp[0] = 0;
378                 break;
379         }
380         if((c & Respmask) == Resp48busy){
381                 WR(Irpten, r[Irpten]|Datadone|Err);
382                 tsleep(&emmc.r, datadone, 0, 3000);
383                 i = r[Interrupt];
384                 if((i & Datadone) == 0)
385                         print("emmcio: no Datadone after CMD%d\n", cmd);
386                 if(i & Err)
387                         print("emmcio: CMD%d error interrupt %ux\n",
388                                 cmd, r[Interrupt]);
389                 WR(Interrupt, i);
390         }
391         /*
392          * Once card is selected, use faster clock
393          */
394         if(cmd == MMCSelect){
395                 delay(1);
396                 emmcclk(SDfreq);
397                 delay(1);
398                 emmc.fastclock = 1;
399         }
400         if(cmd == Setbuswidth){
401                 if(emmc.appcmd){
402                         /*
403                          * If card bus width changes, change host bus width
404                          */
405                         switch(arg){
406                         case 0:
407                                 WR(Control0, r[Control0] & ~Dwidth4);
408                                 break;
409                         case 2:
410                                 WR(Control0, r[Control0] | Dwidth4);
411                                 break;
412                         }
413                 }else{
414                         /*
415                          * If card switched into high speed mode, increase clock speed
416                          */
417                         if((arg&0x8000000F) == 0x80000001){
418                                 delay(1);
419                                 emmcclk(SDfreqhs);
420                                 delay(1);
421                         }
422                 }
423         }else if(cmd == IORWdirect && (arg & ~0xFF) == (1<<31|0<<28|7<<9)){
424                 switch(arg & 0x3){
425                 case 0:
426                         WR(Control0, r[Control0] & ~Dwidth4);
427                         break;
428                 case 2:
429                         WR(Control0, r[Control0] | Dwidth4);
430                         //WR(Control0, r[Control0] | Hispeed);
431                         break;
432                 }
433         }
434         emmc.appcmd = (cmd == Appcmd);
435         return 0;
436 }
437
438 static void
439 emmciosetup(int write, void *buf, int bsize, int bcount)
440 {
441         USED(write);
442         USED(buf);
443         WR(Blksizecnt, bcount<<16 | bsize);
444 }
445
446 static void
447 emmcio(int write, uchar *buf, int len)
448 {
449         u32int *r;
450         int i;
451
452         r = (u32int*)EMMCREGS;
453         assert((len&3) == 0);
454         okay(1);
455         if(waserror()){
456                 okay(0);
457                 nexterror();
458         }
459         if(write)
460                 dmastart(DmaChanEmmc, DmaDevEmmc, DmaM2D,
461                         buf, &r[Data], len);
462         else
463                 dmastart(DmaChanEmmc, DmaDevEmmc, DmaD2M,
464                         &r[Data], buf, len);
465         if(dmawait(DmaChanEmmc) < 0)
466                 error(Eio);
467         WR(Irpten, r[Irpten]|Datadone|Err);
468         tsleep(&emmc.r, datadone, 0, 3000);
469         i = r[Interrupt]&~Cardintr;
470         if((i & Datadone) == 0){
471                 print("emmcio: %d timeout intr %ux stat %ux\n",
472                         write, i, r[Status]);
473                 WR(Interrupt, i);
474                 error(Eio);
475         }
476         if(i & Err){
477                 print("emmcio: %d error intr %ux stat %ux\n",
478                         write, r[Interrupt], r[Status]);
479                 WR(Interrupt, i);
480                 error(Eio);
481         }
482         if(i)
483                 WR(Interrupt, i);
484         poperror();
485         okay(0);
486 }
487
488 static void
489 mmcinterrupt(Ureg*, void*)
490 {       
491         u32int *r;
492         int i;
493
494         r = (u32int*)EMMCREGS;
495         i = r[Interrupt];
496         if(i&(Datadone|Err))
497                 wakeup(&emmc.r);
498         if(i&Cardintr)
499                 wakeup(&emmc.cardr);
500         WR(Irpten, r[Irpten] & ~i);
501 }
502
503 SDio sdio = {
504         "emmc",
505         emmcinit,
506         emmcenable,
507         emmcinquiry,
508         emmccmd,
509         emmciosetup,
510         emmcio,
511         .highspeed = 1,
512 };