The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ppc/devflash.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "../port/error.h"
    7 
    8 enum {
    9         Nflash = 2,
   10         Maxwchunk=      1024,   /* maximum chunk written by one call to falg->write */
   11 };
   12 
   13 
   14 /*
   15  *  Flashes are either 8 or 16 bits wide.  On some installations (e.g., the
   16  *  bitsy, they are interleaved: address 0 is in the first chip, address 2
   17  *  on the second, address 4 on the first, etc.
   18  *  We define Funit as the unit that matches the width of a single flash chip,
   19  *  so Funit is either `uchar' or `ushort' (I haven't seen 32-bit wide flashes),
   20  *  and we define Fword as the unit that matches a set of interleaved Funits.
   21  *  We access interleaved flashes simultaneously, by doing single reads and
   22  *  writes to both.  The macro `mirror' takes a command and replicates it for
   23  *  this purpose.
   24  *  The Blast board has a non-interleaved 16-bit wide flash.  When doing
   25  *  writes to it, we must swap bytes.
   26  */
   27 
   28 typedef struct FlashAlg FlashAlg;
   29 typedef struct Flash Flash;
   30 typedef struct FlashRegion FlashRegion;
   31 
   32 #ifdef WIDTH8
   33         typedef         uchar           Funit;          /* Width of the flash (uchar or ushort) */
   34 #       define          toendian(x)     (x)                     /* Little or big endianness */
   35 #       define          fromendian(x)   (x)
   36 #       define          reg(x)          ((x)<<1)
   37 #       ifdef INTERLEAVED
   38 #               define  mirror(x)               ((x)<<8|(x))    /* Double query for interleaved flashes */
   39                 typedef ushort          Fword;          /* Width after interleaving */
   40 #               define  Wshift          1
   41 #       else
   42 #               define  mirror(x)               (x)
   43                 typedef uchar           Fword;
   44 #               define  Wshift          0
   45 #       endif
   46 #else
   47         typedef         ushort          Funit;
   48 #       define          toendian(x)     ((x)<<8)
   49 #       define          fromendian(x)   ((x)>>8)
   50 #       define          reg(x)          (x)
   51 #       ifdef INTERLEAVED
   52 #               define  mirror(x)               (toendian(x)<<16|toendian(x))
   53                 typedef ulong           Fword;
   54 #               define  Wshift          2
   55 #       else
   56 #               define mirror(x)                toendian(x)
   57                 typedef ushort          Fword;
   58 #               define  Wshift          1
   59 #       endif
   60 #endif
   61 
   62 /* this defines a contiguous set of erase blocks of one size */
   63 struct FlashRegion
   64 {
   65         ulong   addr;   /* start of region */
   66         ulong   end;            /* end of region + 1 */
   67         ulong   n;              /* number of blocks */
   68         ulong   size;           /* size of each block */
   69 };
   70 
   71 struct Flash
   72 {
   73         ISAConf;                                        /* contains size */
   74         RWlock;
   75         Fword           *p;
   76         ushort          algid;          /* access algorithm */
   77         FlashAlg                *alg;
   78         ushort          manid;          /* manufacturer id */
   79         ushort          devid;          /* device id */
   80         int                     wbsize;         /* size of write buffer */ 
   81         ulong           nr;                     /* number of regions */
   82         uchar           bootprotect;
   83         ulong           offset;         /* beginning offset of this flash */
   84         FlashRegion     r[32];
   85 };
   86 
   87 /* this defines a particular access algorithm */
   88 struct FlashAlg
   89 {
   90         int     id;
   91         char    *name;
   92         void    (*identify)(Flash*);    /* identify device */
   93         void    (*erase)(Flash*, ulong);        /* erase a region */
   94         void    (*write)(Flash*, void*, long, ulong);   /* write a region */
   95 };
   96 
   97 static void     ise_id(Flash*);
   98 static void     ise_erase(Flash*, ulong);
   99 static void     ise_write(Flash*, void*, long, ulong);
  100 
  101 static void     afs_id(Flash*);
  102 static void     afs_erase(Flash*, ulong);
  103 static void     afs_write(Flash*, void*, long, ulong);
  104 
  105 static ulong    blockstart(Flash*, ulong);
  106 static ulong    blockend(Flash*, ulong);
  107 
  108 FlashAlg falg[] =
  109 {
  110         { 1,    "Intel/Sharp Extended", ise_id, ise_erase, ise_write    },
  111         { 2,    "AMD/Fujitsu Standard", afs_id, afs_erase, afs_write    },
  112 };
  113 
  114 Flash flashes[Nflash];
  115 
  116 /*
  117  *  common flash interface
  118  */
  119 static uchar
  120 cfigetc(Flash *flash, int off)
  121 {
  122         uchar rv;
  123 
  124         flash->p[reg(0x55)] = mirror(0x98);
  125         rv = fromendian(flash->p[reg(off)]);
  126         flash->p[reg(0x55)] = mirror(0xFF);
  127         return rv;
  128 }
  129 
  130 static ushort
  131 cfigets(Flash *flash, int off)
  132 {
  133         return (cfigetc(flash, off+1)<<8)|cfigetc(flash, off);
  134 }
  135 
  136 static ulong
  137 cfigetl(Flash *flash, int off)
  138 {
  139         return (cfigetc(flash, off+3)<<24)|(cfigetc(flash, off+2)<<16)|
  140                 (cfigetc(flash, off+1)<<8)|cfigetc(flash, off);
  141 }
  142 
  143 static void
  144 cfiquery(Flash *flash)
  145 {
  146         uchar q, r, y;
  147         ulong x, addr;
  148 
  149         q = cfigetc(flash, 0x10);
  150         r = cfigetc(flash, 0x11);
  151         y = cfigetc(flash, 0x12);
  152         if(q != 'Q' || r != 'R' || y != 'Y'){
  153                 print("cfi query failed: %ux %ux %ux\n", q, r, y);
  154                 return;
  155         }
  156         flash->algid = cfigetc(flash, 0x13);
  157         flash->size = (sizeof(Fword)/sizeof(Funit)) * (1<<(cfigetc(flash, 0x27)));
  158         flash->wbsize = (sizeof(Fword)/sizeof(Funit)) * (1<<(cfigetc(flash, 0x2a)));
  159         flash->nr = cfigetc(flash, 0x2c);
  160         if(flash->nr > nelem(flash->r)){
  161                 print("cfi reports > %d regions\n", nelem(flash->r));
  162                 flash->nr = nelem(flash->r);
  163         }
  164         addr = 0;
  165         for(q = 0; q < flash->nr; q++){
  166                 x = cfigetl(flash, q+0x2d);
  167                 flash->r[q].size = (sizeof(Fword)/sizeof(Funit)) * 256 * (x>>16);
  168                 flash->r[q].n = (x&0xffff)+1;
  169                 flash->r[q].addr = addr;
  170                 addr += flash->r[q].size*flash->r[q].n;
  171                 flash->r[q].end = addr;
  172         }
  173 }
  174 
  175 /*
  176  *  flash device interface
  177  */
  178 
  179 enum
  180 {
  181         Qtopdir,
  182         Q2nddir,
  183         Qfctl,
  184         Qfdata,
  185 
  186         Maxpart= 8,
  187 };
  188 
  189 
  190 typedef struct FPart FPart;
  191 struct FPart
  192 {
  193         Flash   *flash;
  194         char            *name;
  195         char            *ctlname;
  196         ulong   start;
  197         ulong   end;
  198 };
  199 static FPart    part[Maxpart];
  200 
  201 #define FQID(p,q)       ((p)<<8|(q))
  202 #define FTYPE(q)        ((q) & 0xff)
  203 #define FPART(q)        (&part[(q) >>8])
  204 
  205 static int
  206 gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
  207 {
  208         Qid q;
  209         FPart *fp;
  210 
  211         q.vers = 0;
  212 
  213         /* top level directory contains the name of the network */
  214         if(c->qid.path == Qtopdir){
  215                 switch(i){
  216                 case DEVDOTDOT:
  217                         q.path = Qtopdir;
  218                         q.type = QTDIR;
  219                         devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
  220                         break;
  221                 case 0:
  222                         q.path = Q2nddir;
  223                         q.type = QTDIR;
  224                         devdir(c, q, "flash", 0, eve, DMDIR|0555, dp);
  225                         break;
  226                 default:
  227                         return -1;
  228                 }
  229                 return 1;
  230         }
  231 
  232         /* second level contains all partitions and their control files */
  233         switch(i) {
  234         case DEVDOTDOT:
  235                 q.path = Qtopdir;
  236                 q.type = QTDIR;
  237                 devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
  238                 break;
  239         default:
  240                 if(i >= 2*Maxpart)
  241                         return -1;
  242                 fp = &part[i>>1];
  243                 if(fp->name == nil)
  244                         return 0;
  245                 if(i & 1){
  246                         q.path = FQID(i>>1, Qfdata);
  247                         q.type = QTFILE;
  248                         devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);
  249                 } else {
  250                         q.path = FQID(i>>1, Qfctl);
  251                         q.type = QTFILE;
  252                         devdir(c, q, fp->ctlname, 0, eve, 0660, dp);
  253                 }
  254                 break;
  255         }
  256         return 1;
  257 }
  258 
  259 static Flash *
  260 findflash(ulong addr)
  261 {
  262         Flash *flash;
  263 
  264         for (flash = flashes; flash < flashes + Nflash; flash++)
  265                 if(addr >= flash->offset && addr < flash->offset + flash->size)
  266                         return flash;
  267         return nil;
  268 }
  269 
  270 static FPart*
  271 findpart(char *name)
  272 {
  273         int i;
  274 
  275         for(i = 0; i < Maxpart; i++)
  276                 if(part[i].name != nil && strcmp(name, part[i].name) == 0)
  277                         break;
  278         if(i >= Maxpart)
  279                 return nil;
  280         return &part[i];
  281 }
  282 
  283 static void
  284 addpart(FPart *fp, char *name, ulong start, ulong end)
  285 {
  286         int i;
  287         char ctlname[64];
  288         Flash *flash;
  289         if (start > end)
  290                 error(Ebadarg);
  291         if(fp == nil){
  292                 flash = findflash(start);
  293                 if (flash == nil || end > flash->offset + flash->size)
  294                         error(Ebadarg);
  295                 start -= flash->offset;
  296                 end -= flash->offset;
  297         } else {
  298                 start += fp->start;
  299                 end += fp->start;
  300                 if(start >= fp->end || end > fp->end){
  301                         error(Ebadarg);
  302                 }
  303                 flash = fp->flash;
  304         }
  305         if(blockstart(flash, start) != start)
  306                 error("must start on erase boundary");
  307         if(blockstart(flash, end) != end && end != flash->size)
  308                 error("must end on erase boundary");
  309 
  310         fp = findpart(name);
  311         if(fp != nil)
  312                 error(Eexist);
  313         for(i = 0; i < Maxpart; i++)
  314                 if(part[i].name == nil)
  315                         break;
  316         if(i == Maxpart)
  317                 error("no more partitions");
  318         fp = &part[i];
  319         kstrdup(&fp->name, name);
  320         snprint(ctlname, sizeof ctlname, "%sctl", name);
  321         kstrdup(&fp->ctlname, ctlname);
  322         fp->flash = flash;
  323         fp->start = start;
  324         fp->end = end;
  325 }
  326 
  327 static void
  328 rempart(FPart *fp)
  329 {
  330         char *p, *cp;
  331 
  332         p = fp->name;
  333         fp->name = nil;
  334         cp = fp->ctlname;
  335         fp->ctlname = nil;
  336         free(p);
  337         free(cp);
  338 }
  339 
  340 void
  341 flashinit(void)
  342 {
  343         int i, ctlrno;
  344         char *fname;
  345         ulong offset;
  346         Flash *flash;
  347 
  348         offset = 0;
  349         for (ctlrno = 0; ctlrno < Nflash; ctlrno++){
  350                 flash = flashes + ctlrno;
  351                 if(isaconfig("flash", ctlrno, flash) == 0)
  352                         continue;
  353                 flash->p = (Fword*)flash->mem;
  354                 cfiquery(flash);
  355                 for(i = 0; i < nelem(falg); i++)
  356                         if(flash->algid == falg[i].id){
  357                                 flash->alg = &falg[i];
  358                                 (*flash->alg->identify)(flash);
  359                                 break;
  360                         }
  361                 flash->bootprotect = 1;
  362                 flash->offset = offset;
  363                 fname = malloc(8);
  364                 sprint(fname, "flash%d", ctlrno);
  365                 addpart(nil, fname, offset, offset + flash->size);
  366                 offset += flash->size;
  367         }
  368 }
  369 
  370 static Chan*
  371 flashattach(char* spec)
  372 {
  373         return devattach('F', spec);
  374 }
  375 
  376 static Walkqid*
  377 flashwalk(Chan *c, Chan *nc, char **name, int nname)
  378 {
  379         return devwalk(c, nc, name, nname, nil, 0, gen);
  380 }
  381 
  382 static int       
  383 flashstat(Chan *c, uchar *db, int n)
  384 {
  385         return devstat(c, db, n, nil, 0, gen);
  386 }
  387 
  388 static Chan*
  389 flashopen(Chan* c, int omode)
  390 {
  391         omode = openmode(omode);
  392         if(strcmp(up->user, eve)!=0)
  393                 error(Eperm);
  394         return devopen(c, omode, nil, 0, gen);
  395 }
  396 
  397 static void      
  398 flashclose(Chan*)
  399 {
  400 }
  401 
  402 static long
  403 flashctlread(FPart *fp, void* a, long n, vlong off)
  404 {
  405         char *buf, *p, *e;
  406         int i;
  407         ulong addr, end;
  408         Flash *flash;
  409 
  410         flash = fp->flash;
  411         buf = smalloc(1024);
  412         e = buf + 1024;
  413         p = seprint(buf, e, "0x%-9lux 0x%-9lux 0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n",
  414                 flash->offset, fp->start, fp->end-fp->start, flash->wbsize, flash->manid, flash->devid);
  415         addr = fp->start;
  416         for(i = 0; i < flash->nr && addr < fp->end; i++)
  417                 if(flash->r[i].addr <= addr && flash->r[i].end > addr){
  418                         if(fp->end <= flash->r[i].end)
  419                                 end = fp->end;
  420                         else
  421                                 end = flash->r[i].end;
  422                         p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr,
  423                                 (end-addr)/flash->r[i].size, flash->r[i].size);
  424                         addr = end;
  425                 }
  426         n = readstr(off, a, n, buf);
  427         free(buf);
  428         return n;
  429 }
  430 
  431 static long
  432 flashdataread(FPart *fp, void* a, long n, vlong off)
  433 {
  434         Flash *flash;
  435 
  436         flash = fp->flash;
  437         rlock(flash);
  438         if(waserror()){
  439                 runlock(flash);
  440                 nexterror();
  441         }
  442         if(fp->name == nil)
  443                 error("partition vanished");
  444         if(!iseve())
  445                 error(Eperm);
  446         off += fp->start;
  447         if(off >= fp->end)
  448                 n = 0;
  449         if(off+n >= fp->end)
  450                 n = fp->end - off;
  451         if(n > 0)
  452                 memmove(a, ((uchar*)flash->mem)+off, n);
  453         runlock(flash);
  454         poperror();
  455 
  456         return n;
  457 }
  458 
  459 static long      
  460 flashread(Chan* c, void* a, long n, vlong off)
  461 {
  462         int t;
  463 
  464         if(c->qid.type == QTDIR)
  465                 return devdirread(c, a, n, nil, 0, gen);
  466         t = FTYPE(c->qid.path);
  467         switch(t){
  468         default:
  469                 error(Eperm);
  470         case Qfctl:
  471                 n = flashctlread(FPART(c->qid.path), a, n, off);
  472                 break;
  473         case Qfdata:
  474                 n = flashdataread(FPART(c->qid.path), a, n, off);
  475                 break;
  476         }
  477         return n;
  478 }
  479 
  480 static void
  481 bootprotect(ulong addr)
  482 {
  483         FlashRegion *r;
  484         Flash *flash;
  485 
  486         flash = findflash(addr);
  487         if (flash == nil)
  488                 error(Ebadarg);
  489         if(flash->bootprotect == 0)
  490                 return;
  491         if(flash->nr == 0)
  492                 error("writing over boot loader disallowed");
  493         r = flash->r;
  494         if(addr >= r->addr && addr < r->addr + r->size)
  495                 error("writing over boot loader disallowed");
  496 }
  497 
  498 static ulong
  499 blockstart(Flash *flash, ulong addr)
  500 {
  501         FlashRegion *r, *e;
  502         ulong x;
  503 
  504         r = flash->r;
  505         for(e = &flash->r[flash->nr]; r < e; r++){
  506                 if(addr >= r->addr && addr < r->end){
  507                         x = addr - r->addr;
  508                         x /= r->size;
  509                         return r->addr + x*r->size;
  510                 }
  511         }
  512                         
  513         return (ulong)-1;
  514 }
  515 
  516 static ulong
  517 blockend(Flash *flash, ulong addr)
  518 {
  519         FlashRegion *r, *e;
  520         ulong x;
  521 
  522         r = flash->r;
  523         for(e = &flash->r[flash->nr]; r < e; r++)
  524                 if(addr >= r->addr && addr < r->end){
  525                         x = addr - r->addr;
  526                         x /= r->size;
  527                         return r->addr + (x+1)*r->size;
  528                 }
  529                         
  530         return (ulong)-1;
  531 }
  532 
  533 static long
  534 flashctlwrite(FPart *fp, char *p, long n)
  535 {
  536         Cmdbuf *cmd;
  537         ulong off;
  538         Flash *flash;
  539 
  540         if(fp == nil)
  541                 panic("flashctlwrite");
  542 
  543         flash = fp->flash;
  544         cmd = parsecmd(p, n);
  545         wlock(flash);
  546         if(waserror()){
  547                 wunlock(flash);
  548                 nexterror();
  549         }
  550         if(strcmp(cmd->f[0], "erase") == 0){
  551                 switch(cmd->nf){
  552                 case 2:
  553                         /* erase a single block in the partition */
  554                         off = atoi(cmd->f[1]);
  555                         off += fp->start;
  556                         if(off >= fp->end)
  557                                 error("region not in partition");
  558                         if(off != blockstart(flash, off))
  559                                 error("erase must be a block boundary");
  560                         bootprotect(off);
  561                         (*flash->alg->erase)(flash, off);
  562                         break;
  563                 case 1:
  564                         /* erase the whole partition */
  565                         bootprotect(fp->start);
  566                         for(off = fp->start; off < fp->end; off = blockend(flash, off))
  567                                 (*flash->alg->erase)(flash, off);
  568                         break;
  569                 default:
  570                         error(Ebadarg);
  571                 }
  572         } else if(strcmp(cmd->f[0], "add") == 0){
  573                 if(cmd->nf != 4)
  574                         error(Ebadarg);
  575                 addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0));
  576         } else if(strcmp(cmd->f[0], "remove") == 0){
  577                 rempart(fp);
  578         } else if(strcmp(cmd->f[0], "protectboot") == 0){
  579                 if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0)
  580                         flash->bootprotect = 1;
  581                 else
  582                         flash->bootprotect = 0;
  583         } else
  584                 error(Ebadarg);
  585         poperror();
  586         wunlock(flash);
  587         free(cmd);
  588 
  589         return n;
  590 }
  591 
  592 static long
  593 flashdatawrite(FPart *fp, uchar *p, long n, long off)
  594 {
  595         uchar *end;
  596         int m;
  597         int on;
  598         long ooff;
  599         uchar *buf;
  600         Flash *flash;
  601 
  602         if(fp == nil)
  603                 panic("flashdatawrite");
  604 
  605         flash = fp->flash;
  606         buf = nil;
  607         wlock(flash);
  608         if(waserror()){
  609                 wunlock(flash);
  610                 if(buf != nil)
  611                         free(buf);
  612                 nexterror();
  613         }
  614 
  615         if(fp->name == nil)
  616                 error("partition vanished");
  617         if(!iseve())
  618                 error(Eperm);
  619 
  620         /* can't cross partition boundaries */
  621         off += fp->start;
  622         if(off >= fp->end || off+n > fp->end || n <= 0)
  623                 error(Ebadarg);
  624 
  625         /* make sure we're not writing the boot sector */
  626         bootprotect(off);
  627 
  628         on = n;
  629 
  630         /*
  631          *  get the data into kernel memory to avoid faults during writing.
  632          *  if write is not on a quad boundary or not a multiple of 4 bytes,
  633          *  extend with data already in flash.
  634          */
  635         buf = smalloc(n+8);
  636         m = off & 3;
  637         if(m){
  638                 *(ulong*)buf = flash->p[off>>Wshift];
  639                 n += m;
  640                 off -= m;
  641         }
  642         if(n & 3){
  643                 n -= n & 3;
  644                 *(ulong*)(&buf[n]) = flash->p[(off+n)>>Wshift];
  645                 n += 4;
  646         }
  647         memmove(&buf[m], p, on);
  648 
  649         /* (*flash->alg->write) can't cross blocks */
  650         ooff = off;
  651         p = buf;
  652         for(end = p + n; p < end; p += m){
  653                 m = blockend(flash, off) - off;
  654                 if(m > end - p)
  655                         m = end - p;
  656                 if(m > Maxwchunk)
  657                         m = Maxwchunk;
  658                 (*flash->alg->write)(flash, p, m, off);
  659                 off += m;
  660         }
  661 
  662         /* make sure write succeeded */
  663         if(memcmp(buf, &flash->p[ooff>>Wshift], n) != 0)
  664                 error("written bytes don't match");
  665 
  666         wunlock(flash);
  667         free(buf);
  668         poperror();
  669 
  670         return on;
  671 }
  672 
  673 static long      
  674 flashwrite(Chan* c, void* a, long n, vlong off)
  675 {
  676         int t;
  677 
  678         if(c->qid.type == QTDIR)
  679                 error(Eperm);
  680 
  681         if(!iseve())
  682                 error(Eperm);
  683 
  684         t = FTYPE(c->qid.path);
  685         switch(t){
  686         default:
  687                 panic("flashwrite");
  688         case Qfctl:
  689                 n = flashctlwrite(FPART(c->qid.path), a, n);
  690                 break;
  691         case Qfdata:
  692                 n = flashdatawrite(FPART(c->qid.path), a, n, off);
  693                 break;
  694         }
  695         return n;
  696 }
  697 
  698 Dev flashdevtab = {
  699         'F',
  700         "flash",
  701 
  702         devreset,
  703         flashinit,
  704         devshutdown,
  705         flashattach,
  706         flashwalk,
  707         flashstat,
  708         flashopen,
  709         devcreate,
  710         flashclose,
  711         flashread,
  712         devbread,
  713         flashwrite,
  714         devbwrite,
  715         devremove,
  716         devwstat,
  717 };
  718 
  719 enum
  720 {
  721         /* status register */
  722         ISEs_lockerr=           1<<1,
  723         ISEs_powererr=          1<<3,
  724         ISEs_progerr=           1<<4,
  725         ISEs_eraseerr=          1<<5,
  726         ISEs_ready=             1<<7,
  727         ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr),
  728 
  729         /* extended status register */
  730         ISExs_bufavail=         1<<7,
  731 };
  732 
  733 /* intel/sharp extended command set */
  734 static void
  735 ise_reset(Flash* flash)
  736 {
  737         flash->p[reg(0xaa)] = mirror(0xff);     /* reset */
  738 }
  739 
  740 static void
  741 ise_id(Flash* flash)
  742 {
  743         ise_reset(flash);
  744         flash->p[reg(0xaaa)] = mirror(0x90);    /* uncover vendor info */
  745         flash->manid = fromendian(flash->p[reg(0x0)]);
  746         flash->devid = fromendian(flash->p[reg(0x1)]);
  747         ise_reset(flash);
  748 }
  749 
  750 static void
  751 ise_clearerror(Flash* flash)
  752 {
  753         flash->p[reg(0x200)] = mirror(0x50);
  754 
  755 }
  756 
  757 static void
  758 ise_error(int bank, ulong status)
  759 {
  760         char err[64];
  761 
  762         if(status & (ISEs_lockerr)){
  763                 sprint(err, "flash%d: block locked %lux", bank, status);
  764                 error(err);
  765         }
  766         if(status & (ISEs_powererr)){
  767                 sprint(err, "flash%d: low prog voltage %lux", bank, status);
  768                 error(err);
  769         }
  770         if(status & (ISEs_progerr|ISEs_eraseerr)){
  771                 sprint(err, "flash%d: i/o error %lux", bank, status);
  772                 error(err);
  773         }
  774 }
  775 static void
  776 ise_erase(Flash *flash, ulong addr)
  777 {
  778         ulong start;
  779         ulong x;
  780 
  781         addr >>= Wshift;
  782 
  783         flashprogpower(1);
  784         flash->p[addr] = mirror(0x20);
  785         flash->p[addr] = mirror(0xd0);
  786         start = m->ticks;
  787         do {
  788                 x = fromendian(flash->p[addr]);
  789                 if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
  790                         break;
  791         } while(TK2MS(m->ticks-start) < 1500);
  792         flashprogpower(0);
  793 
  794         ise_clearerror(flash);
  795         ise_error(0, x);
  796         ise_error(1, x>>16);
  797 
  798         ise_reset(flash);
  799 }
  800 /*
  801  *  the flash spec claimes writing goes faster if we use
  802  *  the write buffer.  We fill the write buffer and then
  803  *  issue the write request.  After the write request,
  804  *  subsequent reads will yield the status register.
  805  *
  806  *  returns the status, even on timeouts.
  807  *
  808  *  NOTE: I tried starting back to back buffered writes
  809  *      without reading the status in between, as the
  810  *      flowchart in the intel data sheet suggests.
  811  *      However, it always responded with an illegal
  812  *      command sequence, so I must be missing something.
  813  *      If someone learns better, please email me, though
  814  *      I doubt it will be much faster. -  presotto@bell-labs.com
  815  */
  816 static long
  817 ise_wbwrite(Flash *flash, Fword *p, int n, ulong off, ulong baddr, ulong *status)
  818 {
  819         Fword x;
  820         ulong start;
  821         int i;
  822         int s;
  823 
  824         /* put flash into write buffer mode */
  825         start = m->ticks;
  826         for(;;) {
  827                 s = splhi();
  828                 /* request write buffer mode */
  829                 flash->p[baddr] = mirror(0xe8);
  830 
  831                 /* look at extended status reg for status */
  832                 if((flash->p[baddr] & mirror(1<<7)) == mirror(1<<7))
  833                         break;
  834                 splx(s);
  835 
  836                 /* didn't work, keep trying for 2 secs */
  837                 if(TK2MS(m->ticks-start) > 2000){
  838                         /* set up to read status */
  839                         flash->p[baddr] = mirror(0x70);
  840                         *status = fromendian(flash->p[baddr]);
  841                         pprint("write buffered cmd timed out\n");
  842                         return -1;
  843                 }
  844         }
  845 
  846         /* fill write buffer */
  847         flash->p[baddr] = mirror(n-1);
  848         for(i = 0; i < n; i++)
  849                 flash->p[off+i] = *p++;
  850 
  851         /* program from buffer */
  852         flash->p[baddr] = mirror(0xd0);
  853         splx(s);
  854 
  855         /* wait till the programming is done */
  856         start = m->ticks;
  857         for(;;) {
  858                 x = flash->p[baddr];    /* read status register */
  859                 *status = fromendian(x);
  860                 if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
  861                         break;
  862                 if(TK2MS(m->ticks-start) > 2000){
  863                         pprint("read status timed out\n");
  864                         return -1;
  865                 }
  866         }
  867         if(x & mirror(ISEs_err))
  868                 return -1;
  869 
  870         return n;
  871 }
  872 
  873 static void
  874 ise_write(Flash *flash, void *a, long n, ulong off)
  875 {
  876         Fword *p, *end;
  877         int i, wbsize;
  878         ulong x, baddr;
  879 
  880         /* everything in terms of Fwords */
  881         wbsize = flash->wbsize >> Wshift;
  882         baddr = blockstart(flash, off) >> Wshift;
  883         off >>= Wshift;
  884         n >>= Wshift;
  885         p = a;
  886 
  887         /* first see if write will succeed */
  888         for(i = 0; i < n; i++)
  889                 if((p[i] & flash->p[off+i]) != p[i])
  890                         error("flash needs erase");
  891 
  892         if(waserror()){
  893                 ise_reset(flash);
  894                 flashprogpower(0);
  895                 nexterror();
  896         }
  897         flashprogpower(1);
  898 
  899         /*
  900          *  use the first write to reach
  901          *  a write buffer boundary.  the intel maunal
  902          *  says writes starting at wb boundaries
  903          *  maximize speed.
  904          */
  905         i = wbsize - (off & (wbsize-1));
  906         for(end = p + n; p < end;){
  907                 if(i > end - p)
  908                         i = end - p;
  909 
  910                 if(ise_wbwrite(flash, p, i, off, baddr, &x) < 0)
  911                         break;
  912 
  913                 off += i;
  914                 p += i;
  915                 i = wbsize;
  916         }
  917 
  918         ise_clearerror(flash);
  919         ise_error(0, x);
  920         ise_error(1, x>>16);
  921 
  922         ise_reset(flash);
  923         flashprogpower(0);
  924         poperror();
  925 }
  926 
  927 /* amd/fujitsu standard command set
  928  *      I don't have an amd chipset to work with
  929  *      so I'm loathe to write this yet.  If someone
  930  *      else does, please send it to me and I'll
  931  *      incorporate it -- presotto@bell-labs.com
  932  */
  933 static void
  934 afs_reset(Flash *flash)
  935 {
  936         flash->p[reg(0xaa)] = mirror(0xf0);     /* reset */
  937 }
  938 static void
  939 afs_id(Flash *flash)
  940 {
  941         afs_reset(flash);
  942         flash->p[reg(0xaa)] = mirror(0xf0);     /* reset */
  943         flash->p[reg(0xaaa)] = mirror(0xaa);    /* query vendor block */
  944         flash->p[reg(0x554)] = mirror(0x55);
  945         flash->p[reg(0xaaa)] = mirror(0x90);
  946         flash->manid = fromendian(flash->p[reg(0x00)]);
  947         afs_reset(flash);
  948         flash->p[reg(0xaaa)] = mirror(0xaa);    /* query vendor block */
  949         flash->p[reg(0x554)] = mirror(0x55);
  950         flash->p[reg(0xaaa)] = mirror(0x90);
  951         flash->devid = fromendian(flash->p[reg(0x02)]);
  952         afs_reset(flash);
  953 }
  954 static void
  955 afs_erase(Flash*, ulong)
  956 {
  957         error("amd/fujistsu erase not implemented");
  958 }
  959 static void
  960 afs_write(Flash*, void*, long, ulong)
  961 {
  962         error("amd/fujistsu write not implemented");
  963 }

Cache object: 5cccb5f70bce46959f00af6259bcb311


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.