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