devflash.c 16 KB

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