changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/bcm/emmc.c

changeset 7249: 3d3af63a444a
parent: 1bb543d577e1
child: 4dbf2522f668
author: cinap_lenrek@felloff.net
date: Sun, 19 May 2019 16:54:50 +0200
permissions: -rw-r--r--
description: bcm, bcm64: fix cache operations for dma and emmc

always clean AND invalidate caches before dma read,
never just invalidate as the buffer might not be
aligned to cache lines...

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