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