]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/pmmc.c
pmmc: remove unsued initfreq vairables
[plan9front.git] / sys / src / 9 / pc / pmmc.c
1 /*
2  * pci mmc controller.
3  *
4  * initially written for X230 Ricoh MMC controller.
5  * cmdinfo[] table stolen from bcm/emmc.c, thanks richard.
6  *
7  * for sdhc documentation see: https://www.sdcard.org/
8  */
9 #include "u.h"
10 #include "../port/lib.h"
11 #include "../port/error.h"
12 #include "mem.h"
13 #include "dat.h"
14 #include "fns.h"
15 #include "io.h"
16 #include "../port/sd.h"
17
18 /* registers */
19 enum {
20         Rsdma   = 0x00,
21         Rbsize  = 0x04,
22         Rbcount = 0x06,
23         Rarg    = 0x08,
24         Rmode   = 0x0C,
25         Rcmd    = 0x0E,
26         Rresp0  = 0x10,
27         Rresp1  = 0x14,
28         Rresp2  = 0x18,
29         Rresp3  = 0x1C,
30         Rdat0   = 0x20,
31         Rdat1   = 0x22,
32         Rpres   = 0x24,
33         Rhc     = 0x28,
34         Rpwr    = 0x29,
35         Rbgc    = 0x2A,
36         Rwkc    = 0x2B,
37         Rclc    = 0x2C,
38         Rtmc    = 0x2E,
39         Rsrst   = 0x2F,
40         Rnis    = 0x30,
41         Reis    = 0x32,
42         Rnie    = 0x34,
43         Reie    = 0x36,
44         Rnise   = 0x38,
45         Reise   = 0x3A,
46         Ra12    = 0x3C,
47         Rcap    = 0x40,
48         Rrcap   = 0x44,
49         Rxcap   = 0x48,
50         Rrxcap  = 0x4C,
51         Rfea12  = 0x50,
52         Rfeei   = 0x52,
53         Radmasr = 0x54,
54         Radmaba = 0x58,
55         Rsists  = 0xFC,
56         Rhcver  = 0xFE,
57 };
58
59 /* sts bits */
60 enum {
61         Seint   = 1<<15,
62         Snint   = 1<<8,
63         Srem    = 1<<7,
64         Sins    = 1<<6,
65         Srrdy   = 1<<5,
66         Swrdy   = 1<<4,
67         Sdint   = 1<<3,
68         Sbge    = 1<<2,
69         Strac   = 1<<1,
70         Scmdc   = 1<<0,
71
72         Smask   = 0x81ff,
73 };
74
75 /* err bits */
76 enum {
77         Ea12    = 1<<8,
78         Elimit  = 1<<7,
79         Edebit  = 1<<6,
80         Edcrc   = 1<<5,
81         Edtmo   = 1<<4,
82         Ecidx   = 1<<3,
83         Ecebit  = 1<<2,
84         Eccrc   = 1<<1,
85         Ectmo   = 1<<0,
86
87         Emask   = 0x1ff,
88 };
89
90 /* present bits */
91 enum {
92         Plsig   = 1<<24,
93         Pldat3  = 1<<23,
94         Pldat2  = 1<<22,
95         Pldat1  = 1<<21,
96         Pldat0  = 1<<20,
97
98         Ppswit  = 1<<19,
99         Pcrddt  = 1<<18,
100         Pcrdst  = 1<<17,
101         Pcrdin  = 1<<16,
102
103         Pbufrd  = 1<<11,
104         Pbufwr  = 1<<10,
105         Ptrard  = 1<<9,
106         Ptrawr  = 1<<8,
107         Pdat    = 1<<2,
108
109         Pinhbc  = 1<<1,
110         Pinhbd  = 1<<0,
111 };
112
113 /* Rmode bits */
114 enum {
115         Mblk    = 1<<5,
116         Mrd     = 1<<4,
117         Mwr     = 0<<4,
118         Ma12    = 1<<2,
119         Mcnt    = 1<<1,
120         Mdma    = 1<<0,
121 };
122
123 /* command bits */
124 enum {
125         Abort           = 3<<6,
126         Isdata          = 1<<5,
127         Ixchken         = 1<<4,
128         Crcchken        = 1<<3,
129
130         Respmask        = 3,
131         Respnone        = 0,
132         Resp48busy      = 3,
133         Resp48          = 2,
134         Resp136         = 1,
135 };
136
137 /* fake for cmdinfo */
138 enum {
139         Blkcnten        = Mblk << 8,
140         Multiblock      = Mcnt << 8,
141         Card2host       = Mrd << 8,
142         Host2card       = Mwr << 8,
143 };
144
145 int cmdinfo[64] = {
146 [0]  Ixchken,
147 [2]  Resp136,
148 [3]  Resp48 | Ixchken | Crcchken,
149 [6]  Resp48 | Ixchken | Crcchken,
150 [7]  Resp48busy | Ixchken | Crcchken,
151 [8]  Resp48 | Ixchken | Crcchken,
152 [9]  Resp136,
153 [12] Resp48busy | Ixchken | Crcchken,
154 [13] Resp48 | Ixchken | Crcchken,
155 [16] Resp48,
156 [17] Resp48 | Isdata | Card2host | Ixchken | Crcchken,
157 [18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken,
158 [24] Resp48 | Isdata | Host2card | Ixchken | Crcchken,
159 [25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken,
160 [41] Resp48,
161 [55] Resp48 | Ixchken | Crcchken,
162 };
163
164 typedef struct Ctlr Ctlr;
165 struct Ctlr {
166         Lock;
167
168         Pcidev  *pdev;
169         u8int   *mmio;
170
171         int     change;
172
173         u32int  waitsts;
174         u32int  waitmsk;
175         Rendez  r;
176
177         struct {
178                 int     bcount;
179                 int     bsize;
180         } io;
181 };
182
183 static Ctlr pmmc[1];
184
185 #define CR8(c, off)     *((u8int*)(c->mmio + off))
186 #define CR16(c, off)    *((u16int*)(c->mmio + off))
187 #define CR32(c, off)    *((u32int*)(c->mmio + off))
188
189 static void
190 mmcinterrupt(Ureg*, void *arg)
191 {
192         u16int nis, eis;
193         Ctlr *c;
194
195         c = arg;
196         nis = CR16(c, Rnis);
197         if((nis & Smask) == 0)
198                 return;         /* not for us */
199
200         CR16(c, Rnis) = nis;    /* ack */
201         ilock(c);
202         eis = 0;
203         if((nis & Seint) != 0){
204                 eis = CR16(c, Reis);
205                 CR16(c, Reis) = eis;    /* ack */
206         }
207         if((nis & Snint) != 0)
208                 CR16(c, Rnie) |= Snint; /* ack */
209         if((nis & (Srem|Sins)) != 0)
210                 c->change = 1;
211         c->waitsts |= nis | (eis << 16);
212         if((c->waitsts & c->waitmsk) != 0)
213                 wakeup(&c->r);
214         iunlock(c);
215 }
216
217 static int
218 pmmcinit(void)
219 {
220         Pcidev *p;
221
222         p = nil;
223         while((p = pcimatch(p, 0, 0)) != nil){
224                 if(p->vid == 0x1180 && p->did == 0xe823)        /* Ricoh */
225                         break;
226         }
227
228         if(p == nil || p->mem[0].size < 256)
229                 return -1;
230
231         if(p->did == 0x1180 && p->vid == 0xe823){       /* Ricoh */
232                 /* Enable SD2.0 mode. */
233                 pcicfgw8(p, 0xf9, 0xfc);
234                 pcicfgw8(p, 0x150, 0x10);
235                 pcicfgw8(p, 0xf9, 0x00);
236
237                 /*
238                  * Some SD/MMC cards don't work with the default base
239                  * clock frequency of 200MHz.  Lower it to 50Hz.
240                  */
241                 pcicfgw8(p, 0xfc, 0x01);
242                 pcicfgw8(p, 0xe1, 50);
243                 pcicfgw8(p, 0xfc, 0x00);
244         }
245
246         pmmc->mmio = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
247         if(pmmc->mmio == nil)
248                 return -1;
249         pmmc->pdev = p;
250         return 0;
251 }
252
253 static int
254 pmmcinquiry(char *inquiry, int inqlen)
255 {
256         return snprint(inquiry, inqlen, "MMC Host Controller");
257 }
258
259 static void
260 softreset(Ctlr *c, int all)
261 {
262         int i, m;
263
264         m = all ? 1 : 6;
265         CR8(c, Rsrst) = m;
266         for(i=10; i>=0; i--){
267                 if((CR8(c, Rsrst) & m) == 0)
268                         break;
269                 delay(10);
270                 CR8(c, Rsrst) = 0;
271         }
272         if(i < 0) iprint("mmc: didnt reset\n");
273 }
274
275 static void
276 setpower(Ctlr *c, int on)
277 {
278         enum {
279                 Vcap18  = 1<<26,        Vset18  = 0x05,
280                 Vcap30  = 1<<25,        Vset30  = 0x06,
281                 Vcap33  = 1<<24,        Vset33  = 0x07,
282         };
283         u32int cap, v;
284
285         cap = CR32(c, Rcap);
286         v = Vset18;
287         if(cap & Vcap30)
288                 v = Vset30;
289         if(cap & Vcap33)
290                 v = Vset33;
291         CR8(c, Rpwr) = on ? ((v<<1) | 1) : 0;
292 }
293
294 static void
295 setclkfreq(Ctlr *c, int khz)
296 {
297         u32int caps, intfreq;
298         int i, div;
299
300         if(khz == 0){
301                 CR16(c, Rclc) |= ~4;    /* sd clock disable */
302                 return;
303         }
304
305         caps = CR32(c, Rcap);
306         intfreq = 1000*((caps >> 8) & 0x3f);
307         for(div = 1; div <= 256; div <<= 1){
308                 if((intfreq / div) <= khz){
309                         div >>= 1;
310                         break;
311                 }
312         }
313         CR16(c, Rclc) = 0;
314         CR16(c, Rclc) = div<<8;
315         CR16(c, Rclc) |= 1;     /* int clock enable */
316         for(i=1000; i>=0; i--){
317                 if(CR16(c, Rclc) & 2)   /* int clock stable */
318                         break;
319                 delay(10);
320         }
321         if(i < 0) iprint("mmc: clock didnt stabilize\n");
322         CR16(c, Rclc) |= 4;     /* sd clock enable */
323 }
324
325 static void
326 resetctlr(Ctlr *c)
327 {
328         u32int m;
329
330         ilock(c);
331         CR16(c, Rnise) = 0;     /* interrupts off */
332
333         c->change = 0;
334         c->waitmsk = c->waitsts = 0;
335         softreset(c, 1);
336
337         /* set timeout */
338         CR8(c, Rtmc) = 0x0e;
339
340         m = Srem | Sins | Srrdy | Swrdy | Sdint | Sbge | Strac | Scmdc;
341         CR16(c, Rnie) = m;
342         CR16(c, Reie) = Emask;
343         CR16(c, Rnise) = m;
344         CR16(c, Reise) = Emask;
345
346         setpower(c, 1); 
347         setclkfreq(c, 400);
348         iunlock(c);
349 }
350
351 static int
352 waitcond(void *arg)
353 {
354         Ctlr *c;
355
356         c = arg;
357         return (c->waitsts & c->waitmsk) != 0;
358 }
359
360 static u32int
361 intrwait(Ctlr *c, u32int mask, int tmo)
362 {
363         u32int status;
364
365         c->waitmsk = Seint | mask;
366         do {
367                 if(!waserror()){
368                         tsleep(&c->r, waitcond, c, 100);
369                         poperror();
370                 }
371                 mmcinterrupt(nil, c);
372                 if(waitcond(c))
373                         break;
374                 tmo -= 100;
375         } while(tmo > 0);
376
377         ilock(c);
378         status = c->waitsts;
379         c->waitsts &= ~(status & mask);
380         c->waitmsk = 0;
381         if((status & mask) == 0 || (status & Seint) != 0){
382                 /* abort command on timeout/error interrupt */
383                 softreset(c, 0);
384                 c->waitsts = 0;
385                 status = 0;
386         }
387         iunlock(c);
388
389         return status;
390 }
391
392
393 static void
394 pmmcenable(void)
395 {
396         Pcidev *p;
397         Ctlr *c;
398
399         c = pmmc;
400         p = c->pdev;
401         resetctlr(c);
402         intrenable(p->intl, mmcinterrupt, c, p->tbdf, "mmc");
403 }
404
405 static int
406 pmmccmd(u32int cmd, u32int arg, u32int *resp)
407 {
408         u32int status;
409         int i, mode;
410         Ctlr *c;
411
412         if(cmd >= nelem(cmdinfo) || cmdinfo[cmd] == 0)
413                 error(Egreg);
414         mode = cmdinfo[cmd] >> 8;
415         cmd = (cmd << 8) | (cmdinfo[cmd] & 0xFF);
416
417         c = pmmc;
418
419         if(c->change)
420                 resetctlr(c);
421         if((CR32(c, Rpres) & Pcrdin) == 0)
422                 error("no card");
423
424         status = Pinhbc;
425         if((cmd & Isdata) != 0 || (cmd & Respmask) == Resp48busy)
426                 status |= Pinhbd;
427         for(i=1000; (CR32(c, Rpres) & status) != 0 && i>=0; i--)
428                 delay(1);
429         if(i < 0)
430                 error(Eio);
431
432         ilock(c);
433         if((mode & (Mcnt|Mblk)) == (Mcnt|Mblk)){
434                 CR16(c, Rbsize)  = c->io.bsize;
435                 CR16(c, Rbcount) = c->io.bcount;
436         }
437         CR32(c, Rarg) = arg;
438         CR16(c, Rmode) = mode;
439         CR16(c, Rcmd) = cmd;
440         iunlock(c);
441
442         if(!intrwait(c, Scmdc, 1000))
443                 error(Eio);
444
445         switch(cmd & Respmask){
446         case Resp48busy:
447                 resp[0] = CR32(c, Rresp0);
448                 if(!intrwait(c, Strac, 3000))
449                         error(Eio);
450                 break;
451         case Resp48:
452                 resp[0] = CR32(c, Rresp0);
453                 break;
454         case Resp136:
455                 resp[0] = CR32(c, Rresp0)<<8;
456                 resp[1] = CR32(c, Rresp0)>>24 | CR32(c, Rresp1)<<8;
457                 resp[2] = CR32(c, Rresp1)>>24 | CR32(c, Rresp2)<<8;
458                 resp[3] = CR32(c, Rresp2)>>24 | CR32(c, Rresp3)<<8;
459                 break;
460         case Respnone:
461                 resp[0] = 0;
462                 break;
463         }
464
465         cmd >>= 8;
466         if(cmd == 0x06){        /* buswidth */
467                 switch(arg){
468                 case 0:
469                         CR8(c, Rhc) &= ~2;
470                         break;
471                 case 2:
472                         CR8(c, Rhc) |= 2;
473                         break;
474                 }
475         }
476
477         return 0;
478 }
479
480 static void
481 pmmciosetup(int write, void *buf, int bsize, int bcount)
482 {
483         Ctlr *c;
484
485         USED(write);
486         USED(buf);
487
488         if(bsize == 0 || (bsize & 3) != 0)
489                 error(Egreg);
490
491         c = pmmc;
492         c->io.bsize = bsize;
493         c->io.bcount = bcount;
494 }
495
496 static void
497 readblock(Ctlr *c, uchar *buf, int len)
498 {
499         for(len >>= 2; len > 0; len--){
500                 *((u32int*)buf) = CR32(c, Rdat0);
501                 buf += 4;
502         }
503 }
504
505 static void
506 writeblock(Ctlr *c, uchar *buf, int len)
507 {
508         for(len >>= 2; len > 0; len--){
509                 CR32(c, Rdat0) = *((u32int*)buf);
510                 buf += 4;
511         }
512 }
513
514 static void
515 pmmcio(int write, uchar *buf, int len)
516 {
517         Ctlr *c;
518         int n;
519
520         c = pmmc;
521         if(len != c->io.bsize*c->io.bcount)
522                 error(Egreg);
523         while(len > 0){
524                 if(!intrwait(c, write ? Swrdy : Srrdy, 3000))
525                         error(Eio);
526                 n = len;
527                 if(n > c->io.bsize)
528                         n = c->io.bsize;
529                 if(write)
530                         writeblock(c, buf, n);
531                 else
532                         readblock(c, buf, n);
533                 len -= n;
534                 buf += n;
535         }
536         if(!intrwait(c, Strac, 1000))
537                 error(Eio);
538 }
539
540 SDio sdio = {
541         "pmmc",
542         pmmcinit,
543         pmmcenable,
544         pmmcinquiry,
545         pmmccmd,
546         pmmciosetup,
547         pmmcio,
548 };