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