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