1458db832SDavid du Colombier #include "u.h"
2458db832SDavid du Colombier #include "../port/lib.h"
3458db832SDavid du Colombier #include "mem.h"
4458db832SDavid du Colombier #include "dat.h"
5458db832SDavid du Colombier #include "fns.h"
6458db832SDavid du Colombier #include "../port/error.h"
7458db832SDavid du Colombier
8458db832SDavid du Colombier enum {
9458db832SDavid du Colombier Nflash = 2,
10458db832SDavid du Colombier Maxwchunk= 1024, /* maximum chunk written by one call to falg->write */
11458db832SDavid du Colombier };
12458db832SDavid du Colombier
13458db832SDavid du Colombier
14458db832SDavid du Colombier /*
15458db832SDavid du Colombier * Flashes are either 8 or 16 bits wide. On some installations (e.g., the
16458db832SDavid du Colombier * bitsy, they are interleaved: address 0 is in the first chip, address 2
17458db832SDavid du Colombier * on the second, address 4 on the first, etc.
18458db832SDavid du Colombier * We define Funit as the unit that matches the width of a single flash chip,
19458db832SDavid du Colombier * so Funit is either `uchar' or `ushort' (I haven't seen 32-bit wide flashes),
20458db832SDavid du Colombier * and we define Fword as the unit that matches a set of interleaved Funits.
21458db832SDavid du Colombier * We access interleaved flashes simultaneously, by doing single reads and
22458db832SDavid du Colombier * writes to both. The macro `mirror' takes a command and replicates it for
23458db832SDavid du Colombier * this purpose.
24458db832SDavid du Colombier * The Blast board has a non-interleaved 16-bit wide flash. When doing
25458db832SDavid du Colombier * writes to it, we must swap bytes.
26458db832SDavid du Colombier */
27458db832SDavid du Colombier
28458db832SDavid du Colombier typedef struct FlashAlg FlashAlg;
29458db832SDavid du Colombier typedef struct Flash Flash;
30458db832SDavid du Colombier typedef struct FlashRegion FlashRegion;
31458db832SDavid du Colombier
32458db832SDavid du Colombier #ifdef WIDTH8
33458db832SDavid du Colombier typedef uchar Funit; /* Width of the flash (uchar or ushort) */
34458db832SDavid du Colombier # define toendian(x) (x) /* Little or big endianness */
35458db832SDavid du Colombier # define fromendian(x) (x)
36458db832SDavid du Colombier # define reg(x) ((x)<<1)
37458db832SDavid du Colombier # ifdef INTERLEAVED
38458db832SDavid du Colombier # define mirror(x) ((x)<<8|(x)) /* Double query for interleaved flashes */
39458db832SDavid du Colombier typedef ushort Fword; /* Width after interleaving */
40458db832SDavid du Colombier # define Wshift 1
41458db832SDavid du Colombier # else
42458db832SDavid du Colombier # define mirror(x) (x)
43458db832SDavid du Colombier typedef uchar Fword;
44458db832SDavid du Colombier # define Wshift 0
45458db832SDavid du Colombier # endif
46458db832SDavid du Colombier #else
47458db832SDavid du Colombier typedef ushort Funit;
48458db832SDavid du Colombier # define toendian(x) ((x)<<8)
49458db832SDavid du Colombier # define fromendian(x) ((x)>>8)
50458db832SDavid du Colombier # define reg(x) (x)
51458db832SDavid du Colombier # ifdef INTERLEAVED
52458db832SDavid du Colombier # define mirror(x) (toendian(x)<<16|toendian(x))
53458db832SDavid du Colombier typedef ulong Fword;
54458db832SDavid du Colombier # define Wshift 2
55458db832SDavid du Colombier # else
56458db832SDavid du Colombier # define mirror(x) toendian(x)
57458db832SDavid du Colombier typedef ushort Fword;
58458db832SDavid du Colombier # define Wshift 1
59458db832SDavid du Colombier # endif
60458db832SDavid du Colombier #endif
61458db832SDavid du Colombier
62458db832SDavid du Colombier /* this defines a contiguous set of erase blocks of one size */
63458db832SDavid du Colombier struct FlashRegion
64458db832SDavid du Colombier {
65458db832SDavid du Colombier ulong addr; /* start of region */
66458db832SDavid du Colombier ulong end; /* end of region + 1 */
67458db832SDavid du Colombier ulong n; /* number of blocks */
68458db832SDavid du Colombier ulong size; /* size of each block */
69458db832SDavid du Colombier };
70458db832SDavid du Colombier
71458db832SDavid du Colombier struct Flash
72458db832SDavid du Colombier {
73458db832SDavid du Colombier ISAConf; /* contains size */
74458db832SDavid du Colombier RWlock;
75458db832SDavid du Colombier Fword *p;
76458db832SDavid du Colombier ushort algid; /* access algorithm */
77458db832SDavid du Colombier FlashAlg *alg;
78458db832SDavid du Colombier ushort manid; /* manufacturer id */
79458db832SDavid du Colombier ushort devid; /* device id */
80458db832SDavid du Colombier int wbsize; /* size of write buffer */
81458db832SDavid du Colombier ulong nr; /* number of regions */
82458db832SDavid du Colombier uchar bootprotect;
83458db832SDavid du Colombier ulong offset; /* beginning offset of this flash */
84458db832SDavid du Colombier FlashRegion r[32];
85458db832SDavid du Colombier };
86458db832SDavid du Colombier
87458db832SDavid du Colombier /* this defines a particular access algorithm */
88458db832SDavid du Colombier struct FlashAlg
89458db832SDavid du Colombier {
90458db832SDavid du Colombier int id;
91458db832SDavid du Colombier char *name;
92458db832SDavid du Colombier void (*identify)(Flash*); /* identify device */
93458db832SDavid du Colombier void (*erase)(Flash*, ulong); /* erase a region */
94458db832SDavid du Colombier void (*write)(Flash*, void*, long, ulong); /* write a region */
95458db832SDavid du Colombier };
96458db832SDavid du Colombier
97458db832SDavid du Colombier static void ise_id(Flash*);
98458db832SDavid du Colombier static void ise_erase(Flash*, ulong);
99458db832SDavid du Colombier static void ise_write(Flash*, void*, long, ulong);
100458db832SDavid du Colombier
101458db832SDavid du Colombier static void afs_id(Flash*);
102458db832SDavid du Colombier static void afs_erase(Flash*, ulong);
103458db832SDavid du Colombier static void afs_write(Flash*, void*, long, ulong);
104458db832SDavid du Colombier
105458db832SDavid du Colombier static ulong blockstart(Flash*, ulong);
106458db832SDavid du Colombier static ulong blockend(Flash*, ulong);
107458db832SDavid du Colombier
108458db832SDavid du Colombier FlashAlg falg[] =
109458db832SDavid du Colombier {
110458db832SDavid du Colombier { 1, "Intel/Sharp Extended", ise_id, ise_erase, ise_write },
111458db832SDavid du Colombier { 2, "AMD/Fujitsu Standard", afs_id, afs_erase, afs_write },
112458db832SDavid du Colombier };
113458db832SDavid du Colombier
114458db832SDavid du Colombier Flash flashes[Nflash];
115458db832SDavid du Colombier
116458db832SDavid du Colombier /*
117458db832SDavid du Colombier * common flash interface
118458db832SDavid du Colombier */
119458db832SDavid du Colombier static uchar
cfigetc(Flash * flash,int off)120458db832SDavid du Colombier cfigetc(Flash *flash, int off)
121458db832SDavid du Colombier {
122458db832SDavid du Colombier uchar rv;
123458db832SDavid du Colombier
124458db832SDavid du Colombier flash->p[reg(0x55)] = mirror(0x98);
125458db832SDavid du Colombier rv = fromendian(flash->p[reg(off)]);
126458db832SDavid du Colombier flash->p[reg(0x55)] = mirror(0xFF);
127458db832SDavid du Colombier return rv;
128458db832SDavid du Colombier }
129458db832SDavid du Colombier
130458db832SDavid du Colombier static ushort
cfigets(Flash * flash,int off)131458db832SDavid du Colombier cfigets(Flash *flash, int off)
132458db832SDavid du Colombier {
133458db832SDavid du Colombier return (cfigetc(flash, off+1)<<8)|cfigetc(flash, off);
134458db832SDavid du Colombier }
135458db832SDavid du Colombier
136458db832SDavid du Colombier static ulong
cfigetl(Flash * flash,int off)137458db832SDavid du Colombier cfigetl(Flash *flash, int off)
138458db832SDavid du Colombier {
139458db832SDavid du Colombier return (cfigetc(flash, off+3)<<24)|(cfigetc(flash, off+2)<<16)|
140458db832SDavid du Colombier (cfigetc(flash, off+1)<<8)|cfigetc(flash, off);
141458db832SDavid du Colombier }
142458db832SDavid du Colombier
143458db832SDavid du Colombier static void
cfiquery(Flash * flash)144458db832SDavid du Colombier cfiquery(Flash *flash)
145458db832SDavid du Colombier {
146458db832SDavid du Colombier uchar q, r, y;
147458db832SDavid du Colombier ulong x, addr;
148458db832SDavid du Colombier
149458db832SDavid du Colombier q = cfigetc(flash, 0x10);
150458db832SDavid du Colombier r = cfigetc(flash, 0x11);
151458db832SDavid du Colombier y = cfigetc(flash, 0x12);
152458db832SDavid du Colombier if(q != 'Q' || r != 'R' || y != 'Y'){
153458db832SDavid du Colombier print("cfi query failed: %ux %ux %ux\n", q, r, y);
154458db832SDavid du Colombier return;
155458db832SDavid du Colombier }
156458db832SDavid du Colombier flash->algid = cfigetc(flash, 0x13);
157458db832SDavid du Colombier flash->size = (sizeof(Fword)/sizeof(Funit)) * (1<<(cfigetc(flash, 0x27)));
158458db832SDavid du Colombier flash->wbsize = (sizeof(Fword)/sizeof(Funit)) * (1<<(cfigetc(flash, 0x2a)));
159458db832SDavid du Colombier flash->nr = cfigetc(flash, 0x2c);
160458db832SDavid du Colombier if(flash->nr > nelem(flash->r)){
161458db832SDavid du Colombier print("cfi reports > %d regions\n", nelem(flash->r));
162458db832SDavid du Colombier flash->nr = nelem(flash->r);
163458db832SDavid du Colombier }
164458db832SDavid du Colombier addr = 0;
165458db832SDavid du Colombier for(q = 0; q < flash->nr; q++){
166458db832SDavid du Colombier x = cfigetl(flash, q+0x2d);
167458db832SDavid du Colombier flash->r[q].size = (sizeof(Fword)/sizeof(Funit)) * 256 * (x>>16);
168458db832SDavid du Colombier flash->r[q].n = (x&0xffff)+1;
169458db832SDavid du Colombier flash->r[q].addr = addr;
170458db832SDavid du Colombier addr += flash->r[q].size*flash->r[q].n;
171458db832SDavid du Colombier flash->r[q].end = addr;
172458db832SDavid du Colombier }
173458db832SDavid du Colombier }
174458db832SDavid du Colombier
175458db832SDavid du Colombier /*
176458db832SDavid du Colombier * flash device interface
177458db832SDavid du Colombier */
178458db832SDavid du Colombier
179458db832SDavid du Colombier enum
180458db832SDavid du Colombier {
181458db832SDavid du Colombier Qtopdir,
182458db832SDavid du Colombier Q2nddir,
183458db832SDavid du Colombier Qfctl,
184458db832SDavid du Colombier Qfdata,
185458db832SDavid du Colombier
186458db832SDavid du Colombier Maxpart= 8,
187458db832SDavid du Colombier };
188458db832SDavid du Colombier
189458db832SDavid du Colombier
190458db832SDavid du Colombier typedef struct FPart FPart;
191458db832SDavid du Colombier struct FPart
192458db832SDavid du Colombier {
193458db832SDavid du Colombier Flash *flash;
194458db832SDavid du Colombier char *name;
195458db832SDavid du Colombier char *ctlname;
196458db832SDavid du Colombier ulong start;
197458db832SDavid du Colombier ulong end;
198458db832SDavid du Colombier };
199458db832SDavid du Colombier static FPart part[Maxpart];
200458db832SDavid du Colombier
201458db832SDavid du Colombier #define FQID(p,q) ((p)<<8|(q))
202458db832SDavid du Colombier #define FTYPE(q) ((q) & 0xff)
203458db832SDavid du Colombier #define FPART(q) (&part[(q) >>8])
204458db832SDavid du Colombier
205458db832SDavid du Colombier static int
gen(Chan * c,char *,Dirtab *,int,int i,Dir * dp)206458db832SDavid du Colombier gen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
207458db832SDavid du Colombier {
208458db832SDavid du Colombier Qid q;
209458db832SDavid du Colombier FPart *fp;
210458db832SDavid du Colombier
211458db832SDavid du Colombier q.vers = 0;
212458db832SDavid du Colombier
213458db832SDavid du Colombier /* top level directory contains the name of the network */
214458db832SDavid du Colombier if(c->qid.path == Qtopdir){
215458db832SDavid du Colombier switch(i){
216458db832SDavid du Colombier case DEVDOTDOT:
217458db832SDavid du Colombier q.path = Qtopdir;
218458db832SDavid du Colombier q.type = QTDIR;
219458db832SDavid du Colombier devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
220458db832SDavid du Colombier break;
221458db832SDavid du Colombier case 0:
222458db832SDavid du Colombier q.path = Q2nddir;
223458db832SDavid du Colombier q.type = QTDIR;
224458db832SDavid du Colombier devdir(c, q, "flash", 0, eve, DMDIR|0555, dp);
225458db832SDavid du Colombier break;
226458db832SDavid du Colombier default:
227458db832SDavid du Colombier return -1;
228458db832SDavid du Colombier }
229458db832SDavid du Colombier return 1;
230458db832SDavid du Colombier }
231458db832SDavid du Colombier
232458db832SDavid du Colombier /* second level contains all partitions and their control files */
233458db832SDavid du Colombier switch(i) {
234458db832SDavid du Colombier case DEVDOTDOT:
235458db832SDavid du Colombier q.path = Qtopdir;
236458db832SDavid du Colombier q.type = QTDIR;
237458db832SDavid du Colombier devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);
238458db832SDavid du Colombier break;
239458db832SDavid du Colombier default:
240458db832SDavid du Colombier if(i >= 2*Maxpart)
241458db832SDavid du Colombier return -1;
242458db832SDavid du Colombier fp = &part[i>>1];
243458db832SDavid du Colombier if(fp->name == nil)
244458db832SDavid du Colombier return 0;
245458db832SDavid du Colombier if(i & 1){
246458db832SDavid du Colombier q.path = FQID(i>>1, Qfdata);
247458db832SDavid du Colombier q.type = QTFILE;
248458db832SDavid du Colombier devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);
249458db832SDavid du Colombier } else {
250458db832SDavid du Colombier q.path = FQID(i>>1, Qfctl);
251458db832SDavid du Colombier q.type = QTFILE;
252458db832SDavid du Colombier devdir(c, q, fp->ctlname, 0, eve, 0660, dp);
253458db832SDavid du Colombier }
254458db832SDavid du Colombier break;
255458db832SDavid du Colombier }
256458db832SDavid du Colombier return 1;
257458db832SDavid du Colombier }
258458db832SDavid du Colombier
259458db832SDavid du Colombier static Flash *
findflash(ulong addr)260458db832SDavid du Colombier findflash(ulong addr)
261458db832SDavid du Colombier {
262458db832SDavid du Colombier Flash *flash;
263458db832SDavid du Colombier
264458db832SDavid du Colombier for (flash = flashes; flash < flashes + Nflash; flash++)
265458db832SDavid du Colombier if(addr >= flash->offset && addr < flash->offset + flash->size)
266458db832SDavid du Colombier return flash;
267458db832SDavid du Colombier return nil;
268458db832SDavid du Colombier }
269458db832SDavid du Colombier
270458db832SDavid du Colombier static FPart*
findpart(char * name)271458db832SDavid du Colombier findpart(char *name)
272458db832SDavid du Colombier {
273458db832SDavid du Colombier int i;
274458db832SDavid du Colombier
275458db832SDavid du Colombier for(i = 0; i < Maxpart; i++)
276458db832SDavid du Colombier if(part[i].name != nil && strcmp(name, part[i].name) == 0)
277458db832SDavid du Colombier break;
278458db832SDavid du Colombier if(i >= Maxpart)
279458db832SDavid du Colombier return nil;
280458db832SDavid du Colombier return &part[i];
281458db832SDavid du Colombier }
282458db832SDavid du Colombier
283458db832SDavid du Colombier static void
addpart(FPart * fp,char * name,ulong start,ulong end)284458db832SDavid du Colombier addpart(FPart *fp, char *name, ulong start, ulong end)
285458db832SDavid du Colombier {
286458db832SDavid du Colombier int i;
287458db832SDavid du Colombier char ctlname[64];
288458db832SDavid du Colombier Flash *flash;
289458db832SDavid du Colombier if (start > end)
290458db832SDavid du Colombier error(Ebadarg);
291458db832SDavid du Colombier if(fp == nil){
292458db832SDavid du Colombier flash = findflash(start);
293458db832SDavid du Colombier if (flash == nil || end > flash->offset + flash->size)
294458db832SDavid du Colombier error(Ebadarg);
295458db832SDavid du Colombier start -= flash->offset;
296458db832SDavid du Colombier end -= flash->offset;
297458db832SDavid du Colombier } else {
298458db832SDavid du Colombier start += fp->start;
299458db832SDavid du Colombier end += fp->start;
300458db832SDavid du Colombier if(start >= fp->end || end > fp->end){
301458db832SDavid du Colombier error(Ebadarg);
302458db832SDavid du Colombier }
303458db832SDavid du Colombier flash = fp->flash;
304458db832SDavid du Colombier }
305458db832SDavid du Colombier if(blockstart(flash, start) != start)
306458db832SDavid du Colombier error("must start on erase boundary");
307458db832SDavid du Colombier if(blockstart(flash, end) != end && end != flash->size)
308458db832SDavid du Colombier error("must end on erase boundary");
309458db832SDavid du Colombier
310458db832SDavid du Colombier fp = findpart(name);
311458db832SDavid du Colombier if(fp != nil)
312458db832SDavid du Colombier error(Eexist);
313458db832SDavid du Colombier for(i = 0; i < Maxpart; i++)
314458db832SDavid du Colombier if(part[i].name == nil)
315458db832SDavid du Colombier break;
316458db832SDavid du Colombier if(i == Maxpart)
317458db832SDavid du Colombier error("no more partitions");
318458db832SDavid du Colombier fp = &part[i];
319458db832SDavid du Colombier kstrdup(&fp->name, name);
320458db832SDavid du Colombier snprint(ctlname, sizeof ctlname, "%sctl", name);
321458db832SDavid du Colombier kstrdup(&fp->ctlname, ctlname);
322458db832SDavid du Colombier fp->flash = flash;
323458db832SDavid du Colombier fp->start = start;
324458db832SDavid du Colombier fp->end = end;
325458db832SDavid du Colombier }
326458db832SDavid du Colombier
327458db832SDavid du Colombier static void
rempart(FPart * fp)328458db832SDavid du Colombier rempart(FPart *fp)
329458db832SDavid du Colombier {
330458db832SDavid du Colombier char *p, *cp;
331458db832SDavid du Colombier
332458db832SDavid du Colombier p = fp->name;
333458db832SDavid du Colombier fp->name = nil;
334458db832SDavid du Colombier cp = fp->ctlname;
335458db832SDavid du Colombier fp->ctlname = nil;
336458db832SDavid du Colombier free(p);
337458db832SDavid du Colombier free(cp);
338458db832SDavid du Colombier }
339458db832SDavid du Colombier
340458db832SDavid du Colombier void
flashinit(void)341458db832SDavid du Colombier flashinit(void)
342458db832SDavid du Colombier {
343458db832SDavid du Colombier int i, ctlrno;
344458db832SDavid du Colombier char *fname;
345458db832SDavid du Colombier ulong offset;
346458db832SDavid du Colombier Flash *flash;
347458db832SDavid du Colombier
348458db832SDavid du Colombier offset = 0;
349458db832SDavid du Colombier for (ctlrno = 0; ctlrno < Nflash; ctlrno++){
350458db832SDavid du Colombier flash = flashes + ctlrno;
351458db832SDavid du Colombier if(isaconfig("flash", ctlrno, flash) == 0)
352458db832SDavid du Colombier continue;
353458db832SDavid du Colombier flash->p = (Fword*)flash->mem;
354458db832SDavid du Colombier cfiquery(flash);
355458db832SDavid du Colombier for(i = 0; i < nelem(falg); i++)
356458db832SDavid du Colombier if(flash->algid == falg[i].id){
357458db832SDavid du Colombier flash->alg = &falg[i];
358458db832SDavid du Colombier (*flash->alg->identify)(flash);
359458db832SDavid du Colombier break;
360458db832SDavid du Colombier }
361458db832SDavid du Colombier flash->bootprotect = 1;
362458db832SDavid du Colombier flash->offset = offset;
363458db832SDavid du Colombier fname = malloc(8);
364458db832SDavid du Colombier sprint(fname, "flash%d", ctlrno);
365458db832SDavid du Colombier addpart(nil, fname, offset, offset + flash->size);
366458db832SDavid du Colombier offset += flash->size;
367458db832SDavid du Colombier }
368458db832SDavid du Colombier }
369458db832SDavid du Colombier
370458db832SDavid du Colombier static Chan*
flashattach(char * spec)371458db832SDavid du Colombier flashattach(char* spec)
372458db832SDavid du Colombier {
373458db832SDavid du Colombier return devattach('F', spec);
374458db832SDavid du Colombier }
375458db832SDavid du Colombier
376458db832SDavid du Colombier static Walkqid*
flashwalk(Chan * c,Chan * nc,char ** name,int nname)377458db832SDavid du Colombier flashwalk(Chan *c, Chan *nc, char **name, int nname)
378458db832SDavid du Colombier {
379458db832SDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, gen);
380458db832SDavid du Colombier }
381458db832SDavid du Colombier
382458db832SDavid du Colombier static int
flashstat(Chan * c,uchar * db,int n)383458db832SDavid du Colombier flashstat(Chan *c, uchar *db, int n)
384458db832SDavid du Colombier {
385458db832SDavid du Colombier return devstat(c, db, n, nil, 0, gen);
386458db832SDavid du Colombier }
387458db832SDavid du Colombier
388458db832SDavid du Colombier static Chan*
flashopen(Chan * c,int omode)389458db832SDavid du Colombier flashopen(Chan* c, int omode)
390458db832SDavid du Colombier {
391458db832SDavid du Colombier omode = openmode(omode);
392458db832SDavid du Colombier if(strcmp(up->user, eve)!=0)
393458db832SDavid du Colombier error(Eperm);
394458db832SDavid du Colombier return devopen(c, omode, nil, 0, gen);
395458db832SDavid du Colombier }
396458db832SDavid du Colombier
397458db832SDavid du Colombier static void
flashclose(Chan *)398458db832SDavid du Colombier flashclose(Chan*)
399458db832SDavid du Colombier {
400458db832SDavid du Colombier }
401458db832SDavid du Colombier
402458db832SDavid du Colombier static long
flashctlread(FPart * fp,void * a,long n,vlong off)403458db832SDavid du Colombier flashctlread(FPart *fp, void* a, long n, vlong off)
404458db832SDavid du Colombier {
405458db832SDavid du Colombier char *buf, *p, *e;
406458db832SDavid du Colombier int i;
407458db832SDavid du Colombier ulong addr, end;
408458db832SDavid du Colombier Flash *flash;
409458db832SDavid du Colombier
410458db832SDavid du Colombier flash = fp->flash;
411458db832SDavid du Colombier buf = smalloc(1024);
412458db832SDavid du Colombier e = buf + 1024;
413458db832SDavid du Colombier p = seprint(buf, e, "0x%-9lux 0x%-9lux 0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n",
414458db832SDavid du Colombier flash->offset, fp->start, fp->end-fp->start, flash->wbsize, flash->manid, flash->devid);
415458db832SDavid du Colombier addr = fp->start;
416458db832SDavid du Colombier for(i = 0; i < flash->nr && addr < fp->end; i++)
417458db832SDavid du Colombier if(flash->r[i].addr <= addr && flash->r[i].end > addr){
418458db832SDavid du Colombier if(fp->end <= flash->r[i].end)
419458db832SDavid du Colombier end = fp->end;
420458db832SDavid du Colombier else
421458db832SDavid du Colombier end = flash->r[i].end;
422458db832SDavid du Colombier p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr,
423458db832SDavid du Colombier (end-addr)/flash->r[i].size, flash->r[i].size);
424458db832SDavid du Colombier addr = end;
425458db832SDavid du Colombier }
426458db832SDavid du Colombier n = readstr(off, a, n, buf);
427458db832SDavid du Colombier free(buf);
428458db832SDavid du Colombier return n;
429458db832SDavid du Colombier }
430458db832SDavid du Colombier
431458db832SDavid du Colombier static long
flashdataread(FPart * fp,void * a,long n,vlong off)432458db832SDavid du Colombier flashdataread(FPart *fp, void* a, long n, vlong off)
433458db832SDavid du Colombier {
434458db832SDavid du Colombier Flash *flash;
435458db832SDavid du Colombier
436458db832SDavid du Colombier flash = fp->flash;
437458db832SDavid du Colombier rlock(flash);
438458db832SDavid du Colombier if(waserror()){
439458db832SDavid du Colombier runlock(flash);
440458db832SDavid du Colombier nexterror();
441458db832SDavid du Colombier }
442458db832SDavid du Colombier if(fp->name == nil)
443458db832SDavid du Colombier error("partition vanished");
444458db832SDavid du Colombier if(!iseve())
445458db832SDavid du Colombier error(Eperm);
446458db832SDavid du Colombier off += fp->start;
447458db832SDavid du Colombier if(off >= fp->end)
448458db832SDavid du Colombier n = 0;
449458db832SDavid du Colombier if(off+n >= fp->end)
450458db832SDavid du Colombier n = fp->end - off;
451458db832SDavid du Colombier if(n > 0)
452458db832SDavid du Colombier memmove(a, ((uchar*)flash->mem)+off, n);
453458db832SDavid du Colombier runlock(flash);
454458db832SDavid du Colombier poperror();
455458db832SDavid du Colombier
456458db832SDavid du Colombier return n;
457458db832SDavid du Colombier }
458458db832SDavid du Colombier
459458db832SDavid du Colombier static long
flashread(Chan * c,void * a,long n,vlong off)460458db832SDavid du Colombier flashread(Chan* c, void* a, long n, vlong off)
461458db832SDavid du Colombier {
462458db832SDavid du Colombier int t;
463458db832SDavid du Colombier
464458db832SDavid du Colombier if(c->qid.type == QTDIR)
465458db832SDavid du Colombier return devdirread(c, a, n, nil, 0, gen);
466458db832SDavid du Colombier t = FTYPE(c->qid.path);
467458db832SDavid du Colombier switch(t){
468458db832SDavid du Colombier default:
469458db832SDavid du Colombier error(Eperm);
470458db832SDavid du Colombier case Qfctl:
471458db832SDavid du Colombier n = flashctlread(FPART(c->qid.path), a, n, off);
472458db832SDavid du Colombier break;
473458db832SDavid du Colombier case Qfdata:
474458db832SDavid du Colombier n = flashdataread(FPART(c->qid.path), a, n, off);
475458db832SDavid du Colombier break;
476458db832SDavid du Colombier }
477458db832SDavid du Colombier return n;
478458db832SDavid du Colombier }
479458db832SDavid du Colombier
480458db832SDavid du Colombier static void
bootprotect(ulong addr)481458db832SDavid du Colombier bootprotect(ulong addr)
482458db832SDavid du Colombier {
483458db832SDavid du Colombier FlashRegion *r;
484458db832SDavid du Colombier Flash *flash;
485458db832SDavid du Colombier
486458db832SDavid du Colombier flash = findflash(addr);
487458db832SDavid du Colombier if (flash == nil)
488458db832SDavid du Colombier error(Ebadarg);
489458db832SDavid du Colombier if(flash->bootprotect == 0)
490458db832SDavid du Colombier return;
491458db832SDavid du Colombier if(flash->nr == 0)
492458db832SDavid du Colombier error("writing over boot loader disallowed");
493458db832SDavid du Colombier r = flash->r;
494458db832SDavid du Colombier if(addr >= r->addr && addr < r->addr + r->size)
495458db832SDavid du Colombier error("writing over boot loader disallowed");
496458db832SDavid du Colombier }
497458db832SDavid du Colombier
498458db832SDavid du Colombier static ulong
blockstart(Flash * flash,ulong addr)499458db832SDavid du Colombier blockstart(Flash *flash, ulong addr)
500458db832SDavid du Colombier {
501458db832SDavid du Colombier FlashRegion *r, *e;
502458db832SDavid du Colombier ulong x;
503458db832SDavid du Colombier
504458db832SDavid du Colombier r = flash->r;
505458db832SDavid du Colombier for(e = &flash->r[flash->nr]; r < e; r++){
506458db832SDavid du Colombier if(addr >= r->addr && addr < r->end){
507458db832SDavid du Colombier x = addr - r->addr;
508458db832SDavid du Colombier x /= r->size;
509458db832SDavid du Colombier return r->addr + x*r->size;
510458db832SDavid du Colombier }
511458db832SDavid du Colombier }
512458db832SDavid du Colombier
513458db832SDavid du Colombier return (ulong)-1;
514458db832SDavid du Colombier }
515458db832SDavid du Colombier
516458db832SDavid du Colombier static ulong
blockend(Flash * flash,ulong addr)517458db832SDavid du Colombier blockend(Flash *flash, ulong addr)
518458db832SDavid du Colombier {
519458db832SDavid du Colombier FlashRegion *r, *e;
520458db832SDavid du Colombier ulong x;
521458db832SDavid du Colombier
522458db832SDavid du Colombier r = flash->r;
523458db832SDavid du Colombier for(e = &flash->r[flash->nr]; r < e; r++)
524458db832SDavid du Colombier if(addr >= r->addr && addr < r->end){
525458db832SDavid du Colombier x = addr - r->addr;
526458db832SDavid du Colombier x /= r->size;
527458db832SDavid du Colombier return r->addr + (x+1)*r->size;
528458db832SDavid du Colombier }
529458db832SDavid du Colombier
530458db832SDavid du Colombier return (ulong)-1;
531458db832SDavid du Colombier }
532458db832SDavid du Colombier
533458db832SDavid du Colombier static long
flashctlwrite(FPart * fp,char * p,long n)534458db832SDavid du Colombier flashctlwrite(FPart *fp, char *p, long n)
535458db832SDavid du Colombier {
536458db832SDavid du Colombier Cmdbuf *cmd;
537458db832SDavid du Colombier ulong off;
538458db832SDavid du Colombier Flash *flash;
539458db832SDavid du Colombier
540458db832SDavid du Colombier if(fp == nil)
541458db832SDavid du Colombier panic("flashctlwrite");
542458db832SDavid du Colombier
543458db832SDavid du Colombier flash = fp->flash;
544458db832SDavid du Colombier cmd = parsecmd(p, n);
545458db832SDavid du Colombier wlock(flash);
546458db832SDavid du Colombier if(waserror()){
547458db832SDavid du Colombier wunlock(flash);
548458db832SDavid du Colombier nexterror();
549458db832SDavid du Colombier }
550458db832SDavid du Colombier if(strcmp(cmd->f[0], "erase") == 0){
551458db832SDavid du Colombier switch(cmd->nf){
552458db832SDavid du Colombier case 2:
553458db832SDavid du Colombier /* erase a single block in the partition */
554458db832SDavid du Colombier off = atoi(cmd->f[1]);
555458db832SDavid du Colombier off += fp->start;
556458db832SDavid du Colombier if(off >= fp->end)
557458db832SDavid du Colombier error("region not in partition");
558458db832SDavid du Colombier if(off != blockstart(flash, off))
559458db832SDavid du Colombier error("erase must be a block boundary");
560458db832SDavid du Colombier bootprotect(off);
561458db832SDavid du Colombier (*flash->alg->erase)(flash, off);
562458db832SDavid du Colombier break;
563458db832SDavid du Colombier case 1:
564458db832SDavid du Colombier /* erase the whole partition */
565458db832SDavid du Colombier bootprotect(fp->start);
566458db832SDavid du Colombier for(off = fp->start; off < fp->end; off = blockend(flash, off))
567458db832SDavid du Colombier (*flash->alg->erase)(flash, off);
568458db832SDavid du Colombier break;
569458db832SDavid du Colombier default:
570458db832SDavid du Colombier error(Ebadarg);
571458db832SDavid du Colombier }
572458db832SDavid du Colombier } else if(strcmp(cmd->f[0], "add") == 0){
573458db832SDavid du Colombier if(cmd->nf != 4)
574458db832SDavid du Colombier error(Ebadarg);
575458db832SDavid du Colombier addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0));
576458db832SDavid du Colombier } else if(strcmp(cmd->f[0], "remove") == 0){
577458db832SDavid du Colombier rempart(fp);
578458db832SDavid du Colombier } else if(strcmp(cmd->f[0], "protectboot") == 0){
579458db832SDavid du Colombier if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0)
580458db832SDavid du Colombier flash->bootprotect = 1;
581458db832SDavid du Colombier else
582458db832SDavid du Colombier flash->bootprotect = 0;
583458db832SDavid du Colombier } else
584458db832SDavid du Colombier error(Ebadarg);
585458db832SDavid du Colombier poperror();
586458db832SDavid du Colombier wunlock(flash);
587458db832SDavid du Colombier free(cmd);
588458db832SDavid du Colombier
589458db832SDavid du Colombier return n;
590458db832SDavid du Colombier }
591458db832SDavid du Colombier
592458db832SDavid du Colombier static long
flashdatawrite(FPart * fp,uchar * p,long n,long off)593458db832SDavid du Colombier flashdatawrite(FPart *fp, uchar *p, long n, long off)
594458db832SDavid du Colombier {
595458db832SDavid du Colombier uchar *end;
596458db832SDavid du Colombier int m;
597458db832SDavid du Colombier int on;
598458db832SDavid du Colombier long ooff;
599458db832SDavid du Colombier uchar *buf;
600458db832SDavid du Colombier Flash *flash;
601458db832SDavid du Colombier
602458db832SDavid du Colombier if(fp == nil)
603458db832SDavid du Colombier panic("flashdatawrite");
604458db832SDavid du Colombier
605458db832SDavid du Colombier flash = fp->flash;
606458db832SDavid du Colombier buf = nil;
607458db832SDavid du Colombier wlock(flash);
608458db832SDavid du Colombier if(waserror()){
609458db832SDavid du Colombier wunlock(flash);
610458db832SDavid du Colombier if(buf != nil)
611458db832SDavid du Colombier free(buf);
612458db832SDavid du Colombier nexterror();
613458db832SDavid du Colombier }
614458db832SDavid du Colombier
615458db832SDavid du Colombier if(fp->name == nil)
616458db832SDavid du Colombier error("partition vanished");
617458db832SDavid du Colombier if(!iseve())
618458db832SDavid du Colombier error(Eperm);
619458db832SDavid du Colombier
620458db832SDavid du Colombier /* can't cross partition boundaries */
621458db832SDavid du Colombier off += fp->start;
622458db832SDavid du Colombier if(off >= fp->end || off+n > fp->end || n <= 0)
623458db832SDavid du Colombier error(Ebadarg);
624458db832SDavid du Colombier
625458db832SDavid du Colombier /* make sure we're not writing the boot sector */
626458db832SDavid du Colombier bootprotect(off);
627458db832SDavid du Colombier
628458db832SDavid du Colombier on = n;
629458db832SDavid du Colombier
630458db832SDavid du Colombier /*
631458db832SDavid du Colombier * get the data into kernel memory to avoid faults during writing.
632458db832SDavid du Colombier * if write is not on a quad boundary or not a multiple of 4 bytes,
633458db832SDavid du Colombier * extend with data already in flash.
634458db832SDavid du Colombier */
635458db832SDavid du Colombier buf = smalloc(n+8);
636458db832SDavid du Colombier m = off & 3;
637458db832SDavid du Colombier if(m){
638458db832SDavid du Colombier *(ulong*)buf = flash->p[off>>Wshift];
639458db832SDavid du Colombier n += m;
640458db832SDavid du Colombier off -= m;
641458db832SDavid du Colombier }
642458db832SDavid du Colombier if(n & 3){
643458db832SDavid du Colombier n -= n & 3;
644458db832SDavid du Colombier *(ulong*)(&buf[n]) = flash->p[(off+n)>>Wshift];
645458db832SDavid du Colombier n += 4;
646458db832SDavid du Colombier }
647458db832SDavid du Colombier memmove(&buf[m], p, on);
648458db832SDavid du Colombier
649458db832SDavid du Colombier /* (*flash->alg->write) can't cross blocks */
650458db832SDavid du Colombier ooff = off;
651458db832SDavid du Colombier p = buf;
652458db832SDavid du Colombier for(end = p + n; p < end; p += m){
653458db832SDavid du Colombier m = blockend(flash, off) - off;
654458db832SDavid du Colombier if(m > end - p)
655458db832SDavid du Colombier m = end - p;
656458db832SDavid du Colombier if(m > Maxwchunk)
657458db832SDavid du Colombier m = Maxwchunk;
658458db832SDavid du Colombier (*flash->alg->write)(flash, p, m, off);
659458db832SDavid du Colombier off += m;
660458db832SDavid du Colombier }
661458db832SDavid du Colombier
662458db832SDavid du Colombier /* make sure write succeeded */
663458db832SDavid du Colombier if(memcmp(buf, &flash->p[ooff>>Wshift], n) != 0)
664458db832SDavid du Colombier error("written bytes don't match");
665458db832SDavid du Colombier
666458db832SDavid du Colombier wunlock(flash);
667458db832SDavid du Colombier free(buf);
668458db832SDavid du Colombier poperror();
669458db832SDavid du Colombier
670458db832SDavid du Colombier return on;
671458db832SDavid du Colombier }
672458db832SDavid du Colombier
673458db832SDavid du Colombier static long
flashwrite(Chan * c,void * a,long n,vlong off)674458db832SDavid du Colombier flashwrite(Chan* c, void* a, long n, vlong off)
675458db832SDavid du Colombier {
676458db832SDavid du Colombier int t;
677458db832SDavid du Colombier
678458db832SDavid du Colombier if(c->qid.type == QTDIR)
679458db832SDavid du Colombier error(Eperm);
680458db832SDavid du Colombier
681458db832SDavid du Colombier if(!iseve())
682458db832SDavid du Colombier error(Eperm);
683458db832SDavid du Colombier
684458db832SDavid du Colombier t = FTYPE(c->qid.path);
685458db832SDavid du Colombier switch(t){
686458db832SDavid du Colombier default:
687458db832SDavid du Colombier panic("flashwrite");
688458db832SDavid du Colombier case Qfctl:
689458db832SDavid du Colombier n = flashctlwrite(FPART(c->qid.path), a, n);
690458db832SDavid du Colombier break;
691458db832SDavid du Colombier case Qfdata:
692458db832SDavid du Colombier n = flashdatawrite(FPART(c->qid.path), a, n, off);
693458db832SDavid du Colombier break;
694458db832SDavid du Colombier }
695458db832SDavid du Colombier return n;
696458db832SDavid du Colombier }
697458db832SDavid du Colombier
698458db832SDavid du Colombier Dev flashdevtab = {
699458db832SDavid du Colombier 'F',
700458db832SDavid du Colombier "flash",
701458db832SDavid du Colombier
702458db832SDavid du Colombier devreset,
703458db832SDavid du Colombier flashinit,
704458db832SDavid du Colombier devshutdown,
705458db832SDavid du Colombier flashattach,
706458db832SDavid du Colombier flashwalk,
707458db832SDavid du Colombier flashstat,
708458db832SDavid du Colombier flashopen,
709458db832SDavid du Colombier devcreate,
710458db832SDavid du Colombier flashclose,
711458db832SDavid du Colombier flashread,
712458db832SDavid du Colombier devbread,
713458db832SDavid du Colombier flashwrite,
714458db832SDavid du Colombier devbwrite,
715458db832SDavid du Colombier devremove,
716458db832SDavid du Colombier devwstat,
717458db832SDavid du Colombier };
718458db832SDavid du Colombier
719458db832SDavid du Colombier enum
720458db832SDavid du Colombier {
721458db832SDavid du Colombier /* status register */
722458db832SDavid du Colombier ISEs_lockerr= 1<<1,
723458db832SDavid du Colombier ISEs_powererr= 1<<3,
724458db832SDavid du Colombier ISEs_progerr= 1<<4,
725458db832SDavid du Colombier ISEs_eraseerr= 1<<5,
726458db832SDavid du Colombier ISEs_ready= 1<<7,
727458db832SDavid du Colombier ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr),
728458db832SDavid du Colombier
729458db832SDavid du Colombier /* extended status register */
730458db832SDavid du Colombier ISExs_bufavail= 1<<7,
731458db832SDavid du Colombier };
732458db832SDavid du Colombier
733458db832SDavid du Colombier /* intel/sharp extended command set */
734458db832SDavid du Colombier static void
ise_reset(Flash * flash)735458db832SDavid du Colombier ise_reset(Flash* flash)
736458db832SDavid du Colombier {
737458db832SDavid du Colombier flash->p[reg(0xaa)] = mirror(0xff); /* reset */
738458db832SDavid du Colombier }
739458db832SDavid du Colombier
740458db832SDavid du Colombier static void
ise_id(Flash * flash)741458db832SDavid du Colombier ise_id(Flash* flash)
742458db832SDavid du Colombier {
743458db832SDavid du Colombier ise_reset(flash);
744458db832SDavid du Colombier flash->p[reg(0xaaa)] = mirror(0x90); /* uncover vendor info */
745458db832SDavid du Colombier flash->manid = fromendian(flash->p[reg(0x0)]);
746458db832SDavid du Colombier flash->devid = fromendian(flash->p[reg(0x1)]);
747458db832SDavid du Colombier ise_reset(flash);
748458db832SDavid du Colombier }
749458db832SDavid du Colombier
750458db832SDavid du Colombier static void
ise_clearerror(Flash * flash)751458db832SDavid du Colombier ise_clearerror(Flash* flash)
752458db832SDavid du Colombier {
753458db832SDavid du Colombier flash->p[reg(0x200)] = mirror(0x50);
754458db832SDavid du Colombier
755458db832SDavid du Colombier }
756458db832SDavid du Colombier
757458db832SDavid du Colombier static void
ise_error(int bank,ulong status)758458db832SDavid du Colombier ise_error(int bank, ulong status)
759458db832SDavid du Colombier {
760458db832SDavid du Colombier char err[64];
761458db832SDavid du Colombier
762458db832SDavid du Colombier if(status & (ISEs_lockerr)){
763458db832SDavid du Colombier sprint(err, "flash%d: block locked %lux", bank, status);
764458db832SDavid du Colombier error(err);
765458db832SDavid du Colombier }
766458db832SDavid du Colombier if(status & (ISEs_powererr)){
767458db832SDavid du Colombier sprint(err, "flash%d: low prog voltage %lux", bank, status);
768458db832SDavid du Colombier error(err);
769458db832SDavid du Colombier }
770458db832SDavid du Colombier if(status & (ISEs_progerr|ISEs_eraseerr)){
771458db832SDavid du Colombier sprint(err, "flash%d: i/o error %lux", bank, status);
772458db832SDavid du Colombier error(err);
773458db832SDavid du Colombier }
774458db832SDavid du Colombier }
775458db832SDavid du Colombier static void
ise_erase(Flash * flash,ulong addr)776458db832SDavid du Colombier ise_erase(Flash *flash, ulong addr)
777458db832SDavid du Colombier {
778458db832SDavid du Colombier ulong start;
779458db832SDavid du Colombier ulong x;
780458db832SDavid du Colombier
781458db832SDavid du Colombier addr >>= Wshift;
782458db832SDavid du Colombier
783458db832SDavid du Colombier flashprogpower(1);
784458db832SDavid du Colombier flash->p[addr] = mirror(0x20);
785458db832SDavid du Colombier flash->p[addr] = mirror(0xd0);
786458db832SDavid du Colombier start = m->ticks;
787458db832SDavid du Colombier do {
788458db832SDavid du Colombier x = fromendian(flash->p[addr]);
789458db832SDavid du Colombier if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
790458db832SDavid du Colombier break;
791458db832SDavid du Colombier } while(TK2MS(m->ticks-start) < 1500);
792458db832SDavid du Colombier flashprogpower(0);
793458db832SDavid du Colombier
794458db832SDavid du Colombier ise_clearerror(flash);
795458db832SDavid du Colombier ise_error(0, x);
796458db832SDavid du Colombier ise_error(1, x>>16);
797458db832SDavid du Colombier
798458db832SDavid du Colombier ise_reset(flash);
799458db832SDavid du Colombier }
800458db832SDavid du Colombier /*
801458db832SDavid du Colombier * the flash spec claimes writing goes faster if we use
802458db832SDavid du Colombier * the write buffer. We fill the write buffer and then
803458db832SDavid du Colombier * issue the write request. After the write request,
804458db832SDavid du Colombier * subsequent reads will yield the status register.
805458db832SDavid du Colombier *
806458db832SDavid du Colombier * returns the status, even on timeouts.
807458db832SDavid du Colombier *
808458db832SDavid du Colombier * NOTE: I tried starting back to back buffered writes
809458db832SDavid du Colombier * without reading the status in between, as the
810458db832SDavid du Colombier * flowchart in the intel data sheet suggests.
811458db832SDavid du Colombier * However, it always responded with an illegal
812458db832SDavid du Colombier * command sequence, so I must be missing something.
813458db832SDavid du Colombier * If someone learns better, please email me, though
814458db832SDavid du Colombier * I doubt it will be much faster. - presotto@bell-labs.com
815458db832SDavid du Colombier */
816*2cca75a1SDavid du Colombier static long
ise_wbwrite(Flash * flash,Fword * p,int n,ulong off,ulong baddr,ulong * status)817458db832SDavid du Colombier ise_wbwrite(Flash *flash, Fword *p, int n, ulong off, ulong baddr, ulong *status)
818458db832SDavid du Colombier {
819458db832SDavid du Colombier Fword x;
820458db832SDavid du Colombier ulong start;
821458db832SDavid du Colombier int i;
822458db832SDavid du Colombier int s;
823458db832SDavid du Colombier
824458db832SDavid du Colombier /* put flash into write buffer mode */
825458db832SDavid du Colombier start = m->ticks;
826458db832SDavid du Colombier for(;;) {
827458db832SDavid du Colombier s = splhi();
828458db832SDavid du Colombier /* request write buffer mode */
829458db832SDavid du Colombier flash->p[baddr] = mirror(0xe8);
830458db832SDavid du Colombier
831458db832SDavid du Colombier /* look at extended status reg for status */
832458db832SDavid du Colombier if((flash->p[baddr] & mirror(1<<7)) == mirror(1<<7))
833458db832SDavid du Colombier break;
834458db832SDavid du Colombier splx(s);
835458db832SDavid du Colombier
836458db832SDavid du Colombier /* didn't work, keep trying for 2 secs */
837458db832SDavid du Colombier if(TK2MS(m->ticks-start) > 2000){
838458db832SDavid du Colombier /* set up to read status */
839458db832SDavid du Colombier flash->p[baddr] = mirror(0x70);
840458db832SDavid du Colombier *status = fromendian(flash->p[baddr]);
841458db832SDavid du Colombier pprint("write buffered cmd timed out\n");
842458db832SDavid du Colombier return -1;
843458db832SDavid du Colombier }
844458db832SDavid du Colombier }
845458db832SDavid du Colombier
846458db832SDavid du Colombier /* fill write buffer */
847458db832SDavid du Colombier flash->p[baddr] = mirror(n-1);
848458db832SDavid du Colombier for(i = 0; i < n; i++)
849458db832SDavid du Colombier flash->p[off+i] = *p++;
850458db832SDavid du Colombier
851458db832SDavid du Colombier /* program from buffer */
852458db832SDavid du Colombier flash->p[baddr] = mirror(0xd0);
853458db832SDavid du Colombier splx(s);
854458db832SDavid du Colombier
855458db832SDavid du Colombier /* wait till the programming is done */
856458db832SDavid du Colombier start = m->ticks;
857458db832SDavid du Colombier for(;;) {
858458db832SDavid du Colombier x = flash->p[baddr]; /* read status register */
859458db832SDavid du Colombier *status = fromendian(x);
860458db832SDavid du Colombier if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))
861458db832SDavid du Colombier break;
862458db832SDavid du Colombier if(TK2MS(m->ticks-start) > 2000){
863458db832SDavid du Colombier pprint("read status timed out\n");
864458db832SDavid du Colombier return -1;
865458db832SDavid du Colombier }
866458db832SDavid du Colombier }
867458db832SDavid du Colombier if(x & mirror(ISEs_err))
868458db832SDavid du Colombier return -1;
869458db832SDavid du Colombier
870458db832SDavid du Colombier return n;
871458db832SDavid du Colombier }
872458db832SDavid du Colombier
873458db832SDavid du Colombier static void
ise_write(Flash * flash,void * a,long n,ulong off)874458db832SDavid du Colombier ise_write(Flash *flash, void *a, long n, ulong off)
875458db832SDavid du Colombier {
876458db832SDavid du Colombier Fword *p, *end;
877458db832SDavid du Colombier int i, wbsize;
878458db832SDavid du Colombier ulong x, baddr;
879458db832SDavid du Colombier
880458db832SDavid du Colombier /* everything in terms of Fwords */
881458db832SDavid du Colombier wbsize = flash->wbsize >> Wshift;
882458db832SDavid du Colombier baddr = blockstart(flash, off) >> Wshift;
883458db832SDavid du Colombier off >>= Wshift;
884458db832SDavid du Colombier n >>= Wshift;
885458db832SDavid du Colombier p = a;
886458db832SDavid du Colombier
887458db832SDavid du Colombier /* first see if write will succeed */
888458db832SDavid du Colombier for(i = 0; i < n; i++)
889458db832SDavid du Colombier if((p[i] & flash->p[off+i]) != p[i])
890458db832SDavid du Colombier error("flash needs erase");
891458db832SDavid du Colombier
892458db832SDavid du Colombier if(waserror()){
893458db832SDavid du Colombier ise_reset(flash);
894458db832SDavid du Colombier flashprogpower(0);
895458db832SDavid du Colombier nexterror();
896458db832SDavid du Colombier }
897458db832SDavid du Colombier flashprogpower(1);
898458db832SDavid du Colombier
899458db832SDavid du Colombier /*
900458db832SDavid du Colombier * use the first write to reach
901458db832SDavid du Colombier * a write buffer boundary. the intel maunal
902458db832SDavid du Colombier * says writes starting at wb boundaries
903458db832SDavid du Colombier * maximize speed.
904458db832SDavid du Colombier */
905458db832SDavid du Colombier i = wbsize - (off & (wbsize-1));
906458db832SDavid du Colombier for(end = p + n; p < end;){
907458db832SDavid du Colombier if(i > end - p)
908458db832SDavid du Colombier i = end - p;
909458db832SDavid du Colombier
910458db832SDavid du Colombier if(ise_wbwrite(flash, p, i, off, baddr, &x) < 0)
911458db832SDavid du Colombier break;
912458db832SDavid du Colombier
913458db832SDavid du Colombier off += i;
914458db832SDavid du Colombier p += i;
915458db832SDavid du Colombier i = wbsize;
916458db832SDavid du Colombier }
917458db832SDavid du Colombier
918458db832SDavid du Colombier ise_clearerror(flash);
919458db832SDavid du Colombier ise_error(0, x);
920458db832SDavid du Colombier ise_error(1, x>>16);
921458db832SDavid du Colombier
922458db832SDavid du Colombier ise_reset(flash);
923458db832SDavid du Colombier flashprogpower(0);
924458db832SDavid du Colombier poperror();
925458db832SDavid du Colombier }
926458db832SDavid du Colombier
927458db832SDavid du Colombier /* amd/fujitsu standard command set
928458db832SDavid du Colombier * I don't have an amd chipset to work with
929458db832SDavid du Colombier * so I'm loathe to write this yet. If someone
930458db832SDavid du Colombier * else does, please send it to me and I'll
931458db832SDavid du Colombier * incorporate it -- presotto@bell-labs.com
932458db832SDavid du Colombier */
933458db832SDavid du Colombier static void
afs_reset(Flash * flash)934458db832SDavid du Colombier afs_reset(Flash *flash)
935458db832SDavid du Colombier {
936458db832SDavid du Colombier flash->p[reg(0xaa)] = mirror(0xf0); /* reset */
937458db832SDavid du Colombier }
938458db832SDavid du Colombier static void
afs_id(Flash * flash)939458db832SDavid du Colombier afs_id(Flash *flash)
940458db832SDavid du Colombier {
941458db832SDavid du Colombier afs_reset(flash);
942458db832SDavid du Colombier flash->p[reg(0xaa)] = mirror(0xf0); /* reset */
943458db832SDavid du Colombier flash->p[reg(0xaaa)] = mirror(0xaa); /* query vendor block */
944458db832SDavid du Colombier flash->p[reg(0x554)] = mirror(0x55);
945458db832SDavid du Colombier flash->p[reg(0xaaa)] = mirror(0x90);
946458db832SDavid du Colombier flash->manid = fromendian(flash->p[reg(0x00)]);
947458db832SDavid du Colombier afs_reset(flash);
948458db832SDavid du Colombier flash->p[reg(0xaaa)] = mirror(0xaa); /* query vendor block */
949458db832SDavid du Colombier flash->p[reg(0x554)] = mirror(0x55);
950458db832SDavid du Colombier flash->p[reg(0xaaa)] = mirror(0x90);
951458db832SDavid du Colombier flash->devid = fromendian(flash->p[reg(0x02)]);
952458db832SDavid du Colombier afs_reset(flash);
953458db832SDavid du Colombier }
954458db832SDavid du Colombier static void
afs_erase(Flash *,ulong)955458db832SDavid du Colombier afs_erase(Flash*, ulong)
956458db832SDavid du Colombier {
957458db832SDavid du Colombier error("amd/fujistsu erase not implemented");
958458db832SDavid du Colombier }
959458db832SDavid du Colombier static void
afs_write(Flash *,void *,long,ulong)960458db832SDavid du Colombier afs_write(Flash*, void*, long, ulong)
961458db832SDavid du Colombier {
962458db832SDavid du Colombier error("amd/fujistsu write not implemented");
963458db832SDavid du Colombier }
964