Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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*
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*
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
192
flashstat(Chan *c, uchar *dp, int n)
193
{
194
	return devstat(c, dp, n, nil, 0, flashgen);
195
}
196
 
197
static Chan*
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	 
212
flashclose(Chan*)
213
{
214
}
215
 
216
static long	 
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	 
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*
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
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*
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
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
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
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
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
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
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
}