1 /*
2 * flash memory
3 */
4
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "../port/error.h"
11
12 #include "../port/flashif.h"
13
14 typedef struct Flashtype Flashtype;
15 struct Flashtype {
16 char* name;
17 int (*reset)(Flash*);
18 Flashtype* next;
19 };
20
21 enum {
22 Nbanks = 2,
23 };
24
25 static struct
26 {
27 Flash* card[Nbanks]; /* actual card type, reset for access */
28 Flashtype* types; /* possible card types */
29 }flash;
30
31 enum{
32 Qtopdir,
33 Qflashdir,
34 Qdata,
35 Qctl,
36 };
37
38 #define TYPE(q) ((ulong)(q) & 0xFF)
39 #define PART(q) ((ulong)(q)>>8)
40 #define QID(p,t) (((p)<<8) | (t))
41
42 static Flashregion* flashregion(Flash*, ulong);
43 static char* flashnewpart(Flash*, char*, ulong, ulong);
44 static ulong flashaddr(Flash*, Flashpart*, char*);
45 static void protect(Flash*, ulong);
46 static void eraseflash(Flash*, Flashregion*, ulong);
47 static long readflash(Flash*, void*, long, int);
48 static long writeflash(Flash*, long, void*,int);
49
50 static char Eprotect[] = "flash region protected";
51
52 static int
flash2gen(Chan * c,ulong p,Dir * dp)53 flash2gen(Chan *c, ulong p, Dir *dp)
54 {
55 Flashpart *fp;
56 Flash *f;
57 Qid q;
58 int mode;
59
60 f = flash.card[c->dev];
61 fp = &f->part[PART(p)];
62 if(fp->name == nil)
63 return 0;
64 mkqid(&q, p, 0, QTFILE);
65 switch(TYPE(p)){
66 case Qdata:
67 mode = 0660;
68 if(f->write == nil)
69 mode = 0440;
70 devdir(c, q, fp->name, fp->end-fp->start, eve, mode, dp);
71 return 1;
72 case Qctl:
73 snprint(up->genbuf, sizeof(up->genbuf), "%sctl", fp->name);
74 /* no harm in letting everybody read the ctl files */
75 devdir(c, q, up->genbuf, 0, eve, 0664, dp);
76 return 1;
77 default:
78 return -1;
79 }
80 }
81
82 static int
flashgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)83 flashgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
84 {
85 Qid q;
86 char *n;
87
88 if(s == DEVDOTDOT){
89 mkqid(&q, QID(0, Qtopdir), 0, QTDIR);
90 n = "#F";
91 if(c->dev != 0){
92 snprint(up->genbuf, sizeof up->genbuf, "#F%ld", c->dev);
93 n = up->genbuf;
94 }
95 devdir(c, q, n, 0, eve, 0555, dp);
96 return 1;
97 }
98 switch(TYPE(c->qid.path)){
99 case Qtopdir:
100 if(s != 0)
101 break;
102 mkqid(&q, QID(0, Qflashdir), 0, QTDIR);
103 n = "flash";
104 if(c->dev != 0){
105 snprint(up->genbuf, sizeof up->genbuf, "flash%ld",
106 c->dev);
107 n = up->genbuf;
108 }
109 devdir(c, q, n, 0, eve, 0555, dp);
110 return 1;
111 case Qflashdir:
112 if(s >= 2*nelem(flash.card[c->dev]->part))
113 return -1;
114 return flash2gen(c, QID(s>>1, s&1?Qctl:Qdata), dp);
115 case Qctl:
116 case Qdata:
117 return flash2gen(c, (ulong)c->qid.path, dp);
118 }
119 return -1;
120 }
121
122 static void
flashreset(void)123 flashreset(void)
124 {
125 Flash *f;
126 Flashtype *t;
127 char *e;
128 int bank;
129
130 for(bank = 0; bank < Nbanks; bank++){
131 f = malloc(sizeof(*f));
132 if(f == nil){
133 print("#F%d: can't allocate Flash data\n", bank);
134 return;
135 }
136 f->cmask = ~(ulong)0;
137 if(archflashreset(bank, f) < 0 || f->type == nil ||
138 f->addr == nil){
139 free(f);
140 return;
141 }
142 for(t = flash.types; t != nil; t = t->next)
143 if(strcmp(f->type, t->name) == 0)
144 break;
145 if(t == nil){
146 iprint("#F%d: no flash driver for type %s (addr %p)\n",
147 bank, f->type, f->addr);
148 free(f);
149 return;
150 }
151 f->reset = t->reset;
152 f->protect = 1;
153 if(f->reset(f) == 0){
154 flash.card[bank] = f;
155 iprint("#F%d: %s addr %#p len %lud width %d interleave %d\n",
156 // bank, f->type, PADDR(f->addr), f->size,
157 bank, f->type, f->addr, f->size,
158 f->width, f->interleave);
159 e = flashnewpart(f, "flash", 0, f->size);
160 if(e != nil)
161 panic("#F%d: couldn't init table: %s", bank, e);
162 }else
163 iprint("#F%d: %#p: reset failed (%s)\n",
164 bank, f->addr, f->type);
165 }
166 }
167
168 static Chan*
flashattach(char * spec)169 flashattach(char *spec)
170 {
171 Flash *f;
172 int bank;
173 Chan *c;
174
175 bank = strtol(spec, nil, 0);
176 if(bank < 0 || bank >= Nbanks ||
177 (f = flash.card[bank]) == nil ||
178 f->attach != nil && f->attach(f) < 0)
179 error(Enodev);
180 c = devattach('F', spec);
181 c->dev = bank;
182 return c;
183 }
184
185 static Walkqid*
flashwalk(Chan * c,Chan * nc,char ** name,int nname)186 flashwalk(Chan *c, Chan *nc, char **name, int nname)
187 {
188 return devwalk(c, nc, name, nname, nil, 0, flashgen);
189 }
190
191 static int
flashstat(Chan * c,uchar * dp,int n)192 flashstat(Chan *c, uchar *dp, int n)
193 {
194 return devstat(c, dp, n, nil, 0, flashgen);
195 }
196
197 static Chan*
flashopen(Chan * c,int omode)198 flashopen(Chan *c, int omode)
199 {
200 omode = openmode(omode);
201 switch(TYPE(c->qid.path)){
202 case Qdata:
203 case Qctl:
204 if(flash.card[c->dev] == nil)
205 error(Enodev);
206 break;
207 }
208 return devopen(c, omode, nil, 0, flashgen);
209 }
210
211 static void
flashclose(Chan *)212 flashclose(Chan*)
213 {
214 }
215
216 static long
flashread(Chan * c,void * buf,long n,vlong offset)217 flashread(Chan *c, void *buf, long n, vlong offset)
218 {
219 Flash *f;
220 Flashpart *fp;
221 Flashregion *r;
222 int i;
223 ulong start, end;
224 char *s, *o;
225
226 if(c->qid.type & QTDIR)
227 return devdirread(c, buf, n, nil, 0, flashgen);
228
229 f = flash.card[c->dev];
230 fp = &f->part[PART(c->qid.path)];
231 if(fp->name == nil)
232 error(Egreg);
233 switch(TYPE(c->qid.path)){
234 case Qdata:
235 offset += fp->start;
236 if(offset >= fp->end)
237 return 0;
238 if(offset+n > fp->end)
239 n = fp->end - offset;
240 n = readflash(f, buf, offset, n);
241 if(n < 0)
242 error(Eio);
243 return n;
244 case Qctl:
245 s = malloc(READSTR);
246 if(s == nil)
247 error(Enomem);
248 if(waserror()){
249 free(s);
250 nexterror();
251 }
252 o = seprint(s, s+READSTR, "%#2.2ux %#4.4ux %d %q\n",
253 f->id, f->devid, f->width, f->sort!=nil? f->sort: "nor");
254 for(i=0; i<f->nr; i++){
255 r = &f->regions[i];
256 if(r->start < fp->end && fp->start < r->end){
257 start = r->start;
258 if(fp->start > start)
259 start = fp->start;
260 end = r->end;
261 if(fp->end < end)
262 end = fp->end;
263 o = seprint(o, s+READSTR, "%#8.8lux %#8.8lux %#8.8lux",
264 start, end, r->erasesize);
265 if(r->pagesize)
266 o = seprint(o, s+READSTR, " %#8.8lux",
267 r->pagesize);
268 o = seprint(o, s+READSTR, "\n");
269 }
270 }
271 n = readstr(offset, buf, n, s);
272 poperror();
273 free(s);
274 return n;
275 }
276 error(Egreg);
277 return 0; /* not reached */
278 }
279
280 enum {
281 CMerase,
282 CMadd,
283 CMremove,
284 CMsync,
285 CMprotectboot,
286 };
287
288 static Cmdtab flashcmds[] = {
289 {CMerase, "erase", 2},
290 {CMadd, "add", 0},
291 {CMremove, "remove", 2},
292 {CMsync, "sync", 0},
293 {CMprotectboot, "protectboot", 0},
294 };
295
296 static long
flashwrite(Chan * c,void * buf,long n,vlong offset)297 flashwrite(Chan *c, void *buf, long n, vlong offset)
298 {
299 Cmdbuf *cb;
300 Cmdtab *ct;
301 ulong addr, start, end;
302 char *e;
303 Flashpart *fp;
304 Flashregion *r;
305 Flash *f;
306
307 f = flash.card[c->dev];
308 fp = &f->part[PART(c->qid.path)];
309 if(fp->name == nil)
310 error(Egreg);
311 switch(TYPE(c->qid.path)){
312 case Qdata:
313 if(f->write == nil)
314 error(Eperm);
315 offset += fp->start;
316 if(offset >= fp->end)
317 return 0;
318 if(offset+n > fp->end)
319 n = fp->end - offset;
320 n = writeflash(f, offset, buf, n);
321 if(n < 0)
322 error(Eio);
323 return n;
324 case Qctl:
325 cb = parsecmd(buf, n);
326 if(waserror()){
327 free(cb);
328 nexterror();
329 }
330 ct = lookupcmd(cb, flashcmds, nelem(flashcmds));
331 switch(ct->index){
332 case CMerase:
333 if(strcmp(cb->f[1], "all") != 0){
334 addr = flashaddr(f, fp, cb->f[1]);
335 r = flashregion(f, addr);
336 if(r == nil)
337 error("nonexistent flash region");
338 if(addr%r->erasesize != 0)
339 error("invalid erase block address");
340 eraseflash(f, r, addr);
341 }else if(fp->start == 0 && fp->end == f->size &&
342 f->eraseall != nil){
343 eraseflash(f, nil, 0);
344 }else{
345 for(addr = fp->start; addr < fp->end;
346 addr += r->erasesize){
347 r = flashregion(f, addr);
348 if(r == nil)
349 error("nonexistent flash region");
350 if(addr%r->erasesize != 0)
351 error("invalid erase block address");
352 eraseflash(f, r, addr);
353 }
354 }
355 break;
356 case CMadd:
357 if(cb->nf < 3)
358 error(Ebadarg);
359 start = flashaddr(f, fp, cb->f[2]);
360 if(cb->nf > 3 && strcmp(cb->f[3], "end") != 0)
361 end = flashaddr(f, fp, cb->f[3]);
362 else
363 end = fp->end;
364 if(start > end || start >= fp->end || end > fp->end)
365 error(Ebadarg);
366 e = flashnewpart(f, cb->f[1], start, end);
367 if(e != nil)
368 error(e);
369 break;
370 case CMremove:
371 /* TO DO */
372 break;
373 case CMprotectboot:
374 if(cb->nf > 1 && strcmp(cb->f[1], "off") == 0)
375 f->protect = 0;
376 else
377 f->protect = 1;
378 break;
379 case CMsync:
380 /* TO DO? */
381 break;
382 default:
383 error(Ebadarg);
384 }
385 poperror();
386 free(cb);
387 return n;
388 }
389 error(Egreg);
390 return 0; /* not reached */
391 }
392
393 static char*
flashnewpart(Flash * f,char * name,ulong start,ulong end)394 flashnewpart(Flash *f, char *name, ulong start, ulong end)
395 {
396 Flashpart *fp, *empty;
397 int i;
398
399 empty = nil;
400 for(i = 0; i < nelem(f->part); i++){
401 fp = &f->part[i];
402 if(fp->name == nil){
403 if(empty == nil)
404 empty = fp;
405 }else if(strcmp(fp->name, name) == 0)
406 return Eexist;
407 }
408 if((fp = empty) == nil)
409 return "partition table full";
410 // fp->name = nil;
411 kstrdup(&fp->name, name);
412 if(fp->name == nil)
413 return Enomem;
414 fp->start = start;
415 fp->end = end;
416 return nil;
417 }
418
419 static ulong
flashaddr(Flash * f,Flashpart * fp,char * s)420 flashaddr(Flash *f, Flashpart *fp, char *s)
421 {
422 Flashregion *r;
423 ulong addr;
424
425 addr = strtoul(s, &s, 0);
426 if(*s)
427 error(Ebadarg);
428 if(fp->name == nil)
429 error("partition removed");
430 addr += fp->start;
431 r = flashregion(f, addr);
432 if(r != nil && addr%r->erasesize != 0)
433 error("invalid erase unit address");
434 if(addr < fp->start || addr > fp->end || addr > f->size)
435 error(Ebadarg);
436 return addr;
437 }
438
439 static Flashregion*
flashregion(Flash * f,ulong a)440 flashregion(Flash *f, ulong a)
441 {
442 int i;
443 Flashregion *r;
444
445 for(i=0; i<f->nr; i++){
446 r = &f->regions[i];
447 if(r->start <= a && a < r->end)
448 return r;
449 }
450 return nil;
451 }
452
453 Dev flashdevtab = {
454 'F',
455 "flash",
456
457 flashreset,
458 devinit,
459 devshutdown,
460 flashattach,
461 flashwalk,
462 flashstat,
463 flashopen,
464 devcreate,
465 flashclose,
466 flashread,
467 devbread,
468 flashwrite,
469 devbwrite,
470 devremove,
471 devwstat,
472 };
473
474 /*
475 * called by flash card types named in link section (eg, flashamd.c)
476 */
477 void
addflashcard(char * name,int (* reset)(Flash *))478 addflashcard(char *name, int (*reset)(Flash*))
479 {
480 Flashtype *f, **l;
481
482 f = (Flashtype*)malloc(sizeof(*f));
483 if(f == nil)
484 error(Enomem);
485 f->name = name;
486 f->reset = reset;
487 f->next = nil;
488 for(l = &flash.types; *l != nil; l = &(*l)->next)
489 ;
490 *l = f;
491 }
492
493 static long
readflash(Flash * f,void * buf,long offset,int n)494 readflash(Flash *f, void *buf, long offset, int n)
495 {
496 int r, width, wmask;
497 uchar tmp[16];
498 uchar *p;
499 ulong o;
500
501 if(offset < 0 || offset+n > f->size)
502 error(Ebadarg);
503 qlock(f);
504 if(waserror()){
505 qunlock(f);
506 nexterror();
507 }
508 if(f->read != nil){
509 width = f->width;
510 wmask = width-1;
511 p = buf;
512 if(offset & wmask) {
513 o = offset & ~wmask;
514 if(f->read(f, o, (ulong*)tmp, width) < 0)
515 error(Eio);
516 memmove(tmp, (uchar*)f->addr + o, width);
517 for(; n > 0 && offset & wmask; n--)
518 *p++ = tmp[offset++ & wmask];
519 }
520 r = n & wmask;
521 n &= ~wmask;
522 if(n){
523 if(f->read(f, offset, (ulong*)p, n) < 0)
524 error(Eio);
525 offset += n;
526 p += n;
527 }
528 if(r){
529 if(f->read(f, offset, (ulong*)tmp, width))
530 error(Eio);
531 memmove(p, tmp, r);
532 }
533 }else
534 /* assumes hardware supports byte access */
535 memmove(buf, (uchar*)f->addr+offset, n);
536 poperror();
537 qunlock(f);
538 return n;
539 }
540
541 static long
writeflash(Flash * f,long offset,void * buf,int n)542 writeflash(Flash *f, long offset, void *buf, int n)
543 {
544 uchar tmp[16];
545 uchar *p;
546 ulong o;
547 int r, width, wmask;
548 Flashregion *rg;
549
550 if(f->write == nil || offset < 0 || offset+n > f->size)
551 error(Ebadarg);
552 rg = flashregion(f, offset);
553 if(f->protect && rg != nil && rg->start == 0 && offset < rg->erasesize)
554 error(Eprotect);
555 width = f->width;
556 wmask = width-1;
557 qlock(f);
558 archflashwp(f, 0);
559 if(waserror()){
560 archflashwp(f, 1);
561 qunlock(f);
562 nexterror();
563 }
564 p = buf;
565 if(offset&wmask){
566 o = offset & ~wmask;
567 if(f->read != nil){
568 if(f->read(f, o, tmp, width) < 0)
569 error(Eio);
570 }else
571 memmove(tmp, (uchar*)f->addr+o, width);
572 for(; n > 0 && offset&wmask; n--)
573 tmp[offset++&wmask] = *p++;
574 if(f->write(f, o, tmp, width) < 0)
575 error(Eio);
576 }
577 r = n&wmask;
578 n &= ~wmask;
579 if(n){
580 if(f->write(f, offset, p, n) < 0)
581 error(Eio);
582 offset += n;
583 p += n;
584 }
585 if(r){
586 if(f->read != nil){
587 if(f->read(f, offset, tmp, width) < 0)
588 error(Eio);
589 }else
590 memmove(tmp, (uchar*)f->addr+offset, width);
591 memmove(tmp, p, r);
592 if(f->write(f, offset, tmp, width) < 0)
593 error(Eio);
594 }
595 poperror();
596 archflashwp(f, 1);
597 qunlock(f);
598 return n;
599 }
600
601 static void
eraseflash(Flash * f,Flashregion * r,ulong addr)602 eraseflash(Flash *f, Flashregion *r, ulong addr)
603 {
604 int rv;
605
606 if(f->protect && r != nil && r->start == 0 && addr < r->erasesize)
607 error(Eprotect);
608 qlock(f);
609 archflashwp(f, 0);
610 if(waserror()){
611 archflashwp(f, 1);
612 qunlock(f);
613 nexterror();
614 }
615 if(r == nil){
616 if(f->eraseall != nil)
617 rv = f->eraseall(f);
618 else
619 rv = -1;
620 }else
621 rv = f->erasezone(f, r, addr);
622 if(rv < 0)
623 error(Eio);
624 poperror();
625 archflashwp(f, 1);
626 qunlock(f);
627 }
628
629 /*
630 * flash access taking width and interleave into account
631 */
632 int
flashget(Flash * f,ulong a)633 flashget(Flash *f, ulong a)
634 {
635 switch(f->width){
636 default:
637 return ((uchar*)f->addr)[a<<f->bshift];
638 case 2:
639 return ((ushort*)f->addr)[a];
640 case 4:
641 return ((ulong*)f->addr)[a];
642 }
643 }
644
645 void
flashput(Flash * f,ulong a,int v)646 flashput(Flash *f, ulong a, int v)
647 {
648 switch(f->width){
649 default:
650 ((uchar*)f->addr)[a<<f->bshift] = v;
651 break;
652 case 2:
653 ((ushort*)f->addr)[a] = v;
654 break;
655 case 4:
656 ((ulong*)f->addr)[a] = v;
657 break;
658 }
659 coherence();
660 }
661