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
 * sheevaplug nand flash driver
3
 *
4
 * for now separate from (inferno's) os/port/flashnand.c because the flash
5
 * seems newer, and has different commands, but that is nand-chip specific,
6
 * not sheevaplug-specific.  they should be merged in future.
7
 *
8
 * the sheevaplug has a hynix 4gbit flash chip: hy27uf084g2m.
9
 * 2048 byte pages, with 64 spare bytes each; erase block size is 128k.
10
 *
11
 * it has a "glueless" interface, at 0xf9000000.  that's the address
12
 * of the data register.  the command and address registers are those
13
 * or'ed with 1 and 2 respectively.
14
 *
15
 * linux uses this layout for the nand flash (from address 0 onwards):
16
 *	1mb for u-boot
17
 *	4mb for kernel
18
 *	507mb for file system
19
 *
20
 * this is not so relevant here except for ecc.  the first two areas
21
 * (u-boot and kernel) are expected to have 4-bit ecc per 512 bytes
22
 * (but calculated from last byte to first), bad erase blocks skipped.
23
 * the file system area has 1-bit ecc per 256 bytes.
24
 */
25
 
26
#include	"u.h"
27
#include	"../port/lib.h"
28
#include	"mem.h"
29
#include	"dat.h"
30
#include	"fns.h"
31
#include	"io.h"
32
#include	"../port/error.h"
33
 
34
#include	"../port/flashif.h"
35
#include	"../port/nandecc.h"
36
 
37
enum {
38
	Debug		= 0,
39
 
40
	Nopage		= ~0ul,		/* cache is empty */
41
 
42
	/* vendors */
43
	Hynix		= 0xad,
44
	Samsung		= 0xec,
45
 
46
	/* chips */
47
	Hy27UF084G2M	= 0xdc,
48
 
49
	NandActCEBoot	= 1<<1,
50
};
51
 
52
typedef struct Nandreg Nandreg;
53
typedef struct Nandtab Nandtab;
54
typedef struct Cache Cache;
55
 
56
struct Nandreg {			/* hw registers */
57
	ulong	rdparms;
58
	ulong	wrparms;
59
	uchar	_pad0[0x70 - 0x20];
60
	ulong	ctl;
61
};
62
 
63
struct Nandtab {
64
	int	vid;
65
	int	did;
66
	vlong	size;
67
	char*	name;
68
};
69
 
70
struct Cache {
71
	Flash	*flif;
72
	ulong	pageno;
73
	ulong	pgsize;			/* r->pagesize */
74
	char	*page;			/* of pgsize bytes */
75
};
76
 
77
enum {
78
	/* commands */
79
	Readstatus	= 0x70,
80
	Readid		= 0x90,	/* needs 1 0-address write */
81
	Resetf		= 0xff,
82
 
83
	/*
84
	 * needs 5 address writes followed by Readstart,
85
	 * Readstartcache or Restartcopy.
86
	 */
87
	Read		= 0x00,
88
	Readstart	= 0x30,
89
	Readstartcache	= 0x31,
90
	Readstartcopy	= 0x35,
91
	/* after Readstartcache, to stop reading next pages */
92
	Readstopcache	= 0x34,
93
 
94
	/* needs 5 address writes, the data, and -start or -cache */
95
	Program		= 0x80,
96
	Programstart	= 0x10,
97
	Programcache	= 0x15,
98
 
99
	Copyback	= 0x85,	/* followed by Programstart */
100
 
101
	/* 3 address writes for block followed by Erasestart */
102
	Erase		= 0x60,
103
	Erasestart	= 0xd0,
104
 
105
	Randomread	= 0x85,
106
	Randomwrite	= 0x05,
107
	Randomwritestart= 0xe0,
108
 
109
	/* status bits */
110
	SFail		= 1<<0,
111
	SCachefail	= 1<<1,
112
	SIdle		= 1<<5,		/* doesn't seem to come on ever */
113
	SReady		= 1<<6,
114
	SNotprotected	= 1<<7,
115
 
116
	Srdymask	= SReady,	/* was SIdle|SReady */
117
};
118
 
119
Nandtab nandtab[] = {
120
	{Hynix,		Hy27UF084G2M,	512*MB,	"Hy27UF084G2M"},
121
	{Samsung,	0xdc,		512*MB,	"Samsung 2Gb"},
122
};
123
 
124
static Cache cache;
125
 
126
static void
127
nandcmd(Flash *f, uchar b)
128
{
129
	uchar *p = (uchar *)((ulong)f->addr|1);
130
 
131
	*p = b;
132
	coherence();
133
}
134
 
135
static void
136
nandaddr(Flash *f, uchar b)
137
{
138
	uchar *p = (uchar *)((ulong)f->addr|2);
139
 
140
	*p = b;
141
	coherence();
142
}
143
 
144
static uchar
145
nandread(Flash *f)
146
{
147
	return *(uchar *)f->addr;
148
}
149
 
150
static void
151
nandreadn(Flash *f, uchar *buf, long n)
152
{
153
	uchar *p = f->addr;
154
 
155
	while(n-- > 0)
156
		*buf++ = *p;
157
}
158
 
159
static void
160
nandwrite(Flash *f, uchar b)
161
{
162
	*(uchar *)f->addr = b;
163
	coherence();
164
}
165
 
166
static void
167
nandwriten(Flash *f, uchar *buf, long n)
168
{
169
	uchar *p = f->addr;
170
 
171
	while(n-- > 0)
172
		*p = *buf++;
173
	coherence();
174
}
175
 
176
static void
177
nandclaim(Flash*)
178
{
179
	Nandreg *nand = (Nandreg*)soc.nand;
180
 
181
	nand->ctl |= NandActCEBoot;
182
	coherence();
183
}
184
 
185
static void
186
nandunclaim(Flash*)
187
{
188
	Nandreg *nand = (Nandreg*)soc.nand;
189
 
190
	nand->ctl &= ~NandActCEBoot;
191
	coherence();
192
}
193
 
194
 
195
Nandtab *
196
findflash(Flash *f, uintptr pa, uchar *id4p)
197
{
198
	int i;
199
	ulong sts;
200
	uchar maker, device, id3, id4;
201
	Nandtab *chip;
202
 
203
	mmuidmap(pa, 16);
204
	f->addr = (void *)pa;
205
 
206
	/* make sure controller is idle */
207
	nandclaim(f);
208
	nandcmd(f, Resetf);
209
	nandunclaim(f);
210
 
211
	nandclaim(f);
212
	nandcmd(f, Readstatus);
213
	sts = nandread(f);
214
	nandunclaim(f);
215
	for (i = 10; i > 0 && !(sts & SReady); i--) {
216
		delay(50);
217
		nandclaim(f);
218
		nandcmd(f, Readstatus);
219
		sts = nandread(f);
220
		nandunclaim(f);
221
	}
222
	if(!(sts & SReady)) {
223
		if (Debug)
224
			print("flashkw: ctlr %#p not ready\n", pa);
225
		return nil;
226
	}
227
 
228
	nandclaim(f);
229
	nandcmd(f, Readid);
230
	nandaddr(f, 0);
231
	maker = nandread(f);
232
	device = nandread(f);
233
	id3 = nandread(f);
234
	USED(id3);
235
	id4 = nandread(f);
236
	nandunclaim(f);
237
	if (id4p)
238
		*id4p = id4;
239
 
240
	for(i = 0; i < nelem(nandtab); i++) {
241
		chip = &nandtab[i];
242
		if(chip->vid == maker && chip->did == device)
243
			return chip;
244
	}
245
	print("flashkw: unknown chip: vid %#ux did %#ux\n", maker, device);
246
	return nil;
247
}
248
 
249
int
250
flashat(Flash *f, uintptr pa)
251
{
252
	return findflash(f, pa, nil) != nil;
253
}
254
 
255
static int
256
idchip(Flash *f)
257
{
258
	uchar id4;
259
	Flashregion *r;
260
	Nandtab *chip;
261
	static int blocksizes[4] = { 64*1024, 128*1024, 256*1024, 0 };
262
	static int pagesizes[4] = { 1024, 2*1024, 0, 0 };
263
	static int spares[2] = { 8, 16 };		/* per 512 bytes */
264
 
265
	f->id = 0;
266
	f->devid = 0;
267
	f->width = 1;
268
	chip = findflash(f, (uintptr)f->addr, &id4);
269
	if (chip == nil)
270
		return -1;
271
	f->id = chip->vid;
272
	f->devid = chip->did;
273
	f->size = chip->size;
274
	f->width = 1;
275
	f->nr = 1;
276
 
277
	r = &f->regions[0];
278
	r->pagesize = pagesizes[id4 & MASK(2)];
279
	r->erasesize = blocksizes[(id4 >> 4) & MASK(2)];
280
	if (r->pagesize == 0 || r->erasesize == 0) {
281
		iprint("flashkw: bogus flash sizes\n");
282
		return -1;
283
	}
284
	r->n = f->size / r->erasesize;
285
	r->start = 0;
286
	r->end = f->size;
287
	assert(ispow2(r->pagesize));
288
	r->pageshift = log2(r->pagesize);
289
	assert(ispow2(r->erasesize));
290
	r->eraseshift = log2(r->erasesize);
291
	assert(r->eraseshift >= r->pageshift);
292
	if (cache.page == nil) {
293
		cache.pgsize = r->pagesize;
294
		cache.page = smalloc(r->pagesize);
295
	}
296
 
297
	r->spares = r->pagesize / 512 * spares[(id4 >> 2) & 1];
298
	print("#F0: kwnand: %s %,lud bytes pagesize %lud erasesize %,lud"
299
		" spares per page %lud\n", chip->name, f->size, r->pagesize,
300
		r->erasesize, r->spares);
301
	return 0;
302
}
303
 
304
static int
305
ctlrwait(Flash *f)
306
{
307
	int sts, cnt;
308
 
309
	nandclaim(f);
310
	for (;;) {
311
		nandcmd(f, Readstatus);
312
		for(cnt = 100; cnt > 0 && (nandread(f) & Srdymask) != Srdymask;
313
		    cnt--)
314
			microdelay(50);
315
		nandcmd(f, Readstatus);
316
		sts = nandread(f);
317
		if((sts & Srdymask) == Srdymask)
318
			break;
319
		print("flashkw: flash ctlr busy, sts %#ux: resetting\n", sts);
320
		nandcmd(f, Resetf);
321
	}
322
	nandunclaim(f);
323
	return 0;
324
}
325
 
326
static int
327
erasezone(Flash *f, Flashregion *r, ulong offset)
328
{
329
	int i;
330
	ulong page, block;
331
	uchar s;
332
 
333
	if (Debug) {
334
		print("flashkw: erasezone: offset %#lux, region nblocks %d,"
335
			" start %#lux, end %#lux\n", offset, r->n, r->start,
336
			r->end);
337
		print(" erasesize %lud, pagesize %lud\n",
338
			r->erasesize, r->pagesize);
339
	}
340
	assert(r->erasesize != 0);
341
	if(offset & (r->erasesize - 1)) {
342
		print("flashkw: erase offset %lud not block aligned\n", offset);
343
		return -1;
344
	}
345
	page = offset >> r->pageshift;
346
	block = page >> (r->eraseshift - r->pageshift);
347
	if (Debug)
348
		print("flashkw: erase: block %#lux\n", block);
349
 
350
	/* make sure controller is idle */
351
	if(ctlrwait(f) < 0) {
352
		print("flashkw: erase: flash busy\n");
353
		return -1;
354
	}
355
 
356
	/* start erasing */
357
	nandclaim(f);
358
	nandcmd(f, Erase);
359
	nandaddr(f, page>>0);
360
	nandaddr(f, page>>8);
361
	nandaddr(f, page>>16);
362
	nandcmd(f, Erasestart);
363
 
364
	/* invalidate cache on any erasure (slight overkill) */
365
	cache.pageno = Nopage;
366
 
367
	/* have to wait until flash is done.  typically ~2ms */
368
	delay(1);
369
	nandcmd(f, Readstatus);
370
	for(i = 0; i < 100; i++) {
371
		s = nandread(f);
372
		if(s & SReady) {
373
			nandunclaim(f);
374
			if(s & SFail) {
375
				print("flashkw: erase: failed, block %#lux\n",
376
					block);
377
				return -1;
378
			}
379
			return 0;
380
		}
381
		microdelay(50);
382
	}
383
	print("flashkw: erase timeout, block %#lux\n", block);
384
	nandunclaim(f);
385
	return -1;
386
}
387
 
388
static void
389
flcachepage(Flash *f, ulong page, uchar *buf)
390
{
391
	Flashregion *r = &f->regions[0];
392
 
393
	assert(cache.pgsize == r->pagesize);
394
	cache.flif = f;
395
	cache.pageno = page;
396
	/* permit i/o directly to or from the cache */
397
	if (buf != (uchar *)cache.page)
398
		memmove(cache.page, buf, cache.pgsize);
399
}
400
 
401
static int
402
write1page(Flash *f, ulong offset, void *buf)
403
{
404
	int i;
405
	ulong page, v;
406
	uchar s;
407
	uchar *eccp, *p;
408
	Flashregion *r = &f->regions[0];
409
	static uchar *oob;
410
 
411
	if (oob == nil)
412
		oob = smalloc(r->spares);
413
 
414
	page = offset >> r->pageshift;
415
	if (Debug)
416
		print("flashkw: write nand offset %#lux page %#lux\n",
417
			offset, page);
418
 
419
	if(offset & (r->pagesize - 1)) {
420
		print("flashkw: write offset %lud not page aligned\n", offset);
421
		return -1;
422
	}
423
 
424
	p = buf;
425
	memset(oob, 0xff, r->spares);
426
	assert(r->spares >= 24);
427
	eccp = oob + r->spares - 24;
428
	for(i = 0; i < r->pagesize / 256; i++) {
429
		v = nandecc(p);
430
		*eccp++ = v>>8;
431
		*eccp++ = v>>0;
432
		*eccp++ = v>>16;
433
		p += 256;
434
	}
435
 
436
	if(ctlrwait(f) < 0) {
437
		print("flashkw: write: nand not ready & idle\n");
438
		return -1;
439
	}
440
 
441
	/* write, only whole pages for now, no sub-pages */
442
	nandclaim(f);
443
	nandcmd(f, Program);
444
	nandaddr(f, 0);
445
	nandaddr(f, 0);
446
	nandaddr(f, page>>0);
447
	nandaddr(f, page>>8);
448
	nandaddr(f, page>>16);
449
	nandwriten(f, buf, r->pagesize);
450
	nandwriten(f, oob, r->spares);
451
	nandcmd(f, Programstart);
452
 
453
	microdelay(100);
454
	nandcmd(f, Readstatus);
455
	for(i = 0; i < 100; i++) {
456
		s = nandread(f);
457
		if(s & SReady) {
458
			nandunclaim(f);
459
			if(s & SFail) {
460
				print("flashkw: write failed, page %#lux\n",
461
					page);
462
				return -1;
463
			}
464
			return 0;
465
		}
466
		microdelay(10);
467
	}
468
 
469
	nandunclaim(f);
470
	flcachepage(f, page, buf);
471
	print("flashkw: write timeout for page %#lux\n", page);
472
	return -1;
473
}
474
 
475
static int
476
read1page(Flash *f, ulong offset, void *buf)
477
{
478
	int i;
479
	ulong addr, page, w;
480
	uchar *eccp, *p;
481
	Flashregion *r = &f->regions[0];
482
	static uchar *oob;
483
 
484
	if (oob == nil)
485
		oob = smalloc(r->spares);
486
 
487
	assert(r->pagesize != 0);
488
	addr = offset & (r->pagesize - 1);
489
	page = offset >> r->pageshift;
490
	if(addr != 0) {
491
		print("flashkw: read1page: read addr %#lux:"
492
			" must read aligned page\n", addr);
493
		return -1;
494
	}
495
 
496
	/* satisfy request from cache if possible */
497
	if (f == cache.flif && page == cache.pageno &&
498
	    r->pagesize == cache.pgsize) {
499
		memmove(buf, cache.page, r->pagesize);
500
		return 0;
501
	}
502
 
503
	if (Debug)
504
		print("flashkw: read offset %#lux addr %#lux page %#lux\n",
505
			offset, addr, page);
506
 
507
	nandclaim(f);
508
	nandcmd(f, Read);
509
	nandaddr(f, addr>>0);
510
	nandaddr(f, addr>>8);
511
	nandaddr(f, page>>0);
512
	nandaddr(f, page>>8);
513
	nandaddr(f, page>>16);
514
	nandcmd(f, Readstart);
515
 
516
	microdelay(50);
517
 
518
	nandreadn(f, buf, r->pagesize);
519
	nandreadn(f, oob, r->spares);
520
 
521
	nandunclaim(f);
522
 
523
	/* verify/correct data. last 8*3 bytes is ecc, per 256 bytes. */
524
	p = buf;
525
	assert(r->spares >= 24);
526
	eccp = oob + r->spares - 24;
527
	for(i = 0; i < r->pagesize / 256; i++) {
528
		w = eccp[0] << 8 | eccp[1] << 0 | eccp[2] << 16;
529
		eccp += 3;
530
		switch(nandecccorrect(p, nandecc(p), &w, 1)) {
531
		case NandEccErrorBad:
532
			print("(page %d)\n", i);
533
			return -1;
534
		case NandEccErrorOneBit:
535
		case NandEccErrorOneBitInEcc:
536
			print("(page %d)\n", i);
537
			/* fall through */
538
		case NandEccErrorGood:
539
			break;
540
		}
541
		p += 256;
542
	}
543
 
544
	flcachepage(f, page, buf);
545
	return 0;
546
}
547
 
548
/*
549
 * read a page at offset into cache, copy fragment from buf into it
550
 * at pagoff, and rewrite that page.
551
 */
552
static int
553
rewrite(Flash *f, ulong offset, ulong pagoff, void *buf, ulong size)
554
{
555
	if (read1page(f, offset, cache.page) < 0)
556
		return -1;
557
	memmove(&cache.page[pagoff], buf, size);
558
	return write1page(f, offset, cache.page);
559
}
560
 
561
/* there are no alignment constraints on offset, buf, nor n */
562
static int
563
write(Flash *f, ulong offset, void *buf, long n)
564
{
565
	uint un, frag, pagoff;
566
	ulong pgsize;
567
	uchar *p;
568
	Flashregion *r = &f->regions[0];
569
 
570
	if(n <= 0)
571
		panic("flashkw: write: non-positive count %ld", n);
572
	un = n;
573
	assert(r->pagesize != 0);
574
	pgsize = r->pagesize;
575
 
576
	/* if a partial first page exists, update the first page with it. */
577
	p = buf;
578
	pagoff = offset % pgsize;
579
	if (pagoff != 0) {
580
		frag = pgsize - pagoff;
581
		if (frag > un)		/* might not extend to end of page */
582
			frag = un;
583
		if (rewrite(f, offset - pagoff, pagoff, p, frag) < 0)
584
			return -1;
585
		offset += frag;
586
		p  += frag;
587
		un -= frag;
588
	}
589
 
590
	/* copy whole pages */
591
	while (un >= pgsize) {
592
		if (write1page(f, offset, p) < 0)
593
			return -1;
594
		offset += pgsize;
595
		p  += pgsize;
596
		un -= pgsize;
597
	}
598
 
599
	/* if a partial last page exists, update the last page with it. */
600
	if (un > 0)
601
		return rewrite(f, offset, 0, p, un);
602
	return 0;
603
}
604
 
605
/* there are no alignment constraints on offset, buf, nor n */
606
static int
607
read(Flash *f, ulong offset, void *buf, long n)
608
{
609
	uint un, frag, pagoff;
610
	ulong pgsize;
611
	uchar *p;
612
	Flashregion *r = &f->regions[0];
613
 
614
	if(n <= 0)
615
		panic("flashkw: read: non-positive count %ld", n);
616
	un = n;
617
	assert(r->pagesize != 0);
618
	pgsize = r->pagesize;
619
 
620
	/* if partial 1st page, read it into cache & copy fragment to buf */
621
	p = buf;
622
	pagoff = offset % pgsize;
623
	if (pagoff != 0) {
624
		frag = pgsize - pagoff;
625
		if (frag > un)		/* might not extend to end of page */
626
			frag = un;
627
		if (read1page(f, offset - pagoff, cache.page) < 0)
628
			return -1;
629
		offset += frag;
630
		memmove(p, &cache.page[pagoff], frag);
631
		p  += frag;
632
		un -= frag;
633
	}
634
 
635
	/* copy whole pages */
636
	while (un >= pgsize) {
637
		if (read1page(f, offset, p) < 0)
638
			return -1;
639
		offset += pgsize;
640
		p  += pgsize;
641
		un -= pgsize;
642
	}
643
 
644
	/* if partial last page, read into cache & copy initial fragment to buf */
645
	if (un > 0) {
646
		if (read1page(f, offset, cache.page) < 0)
647
			return -1;
648
		memmove(p, cache.page, un);
649
	}
650
	return 0;
651
}
652
 
653
static int
654
reset(Flash *f)
655
{
656
	if(f->data != nil)
657
		return 1;
658
	f->write = write;
659
 	f->read = read;
660
	f->eraseall = nil;
661
	f->erasezone = erasezone;
662
	f->suspend = nil;
663
	f->resume = nil;
664
	f->sort = "nand";
665
	cache.pageno = Nopage;
666
	return idchip(f);
667
}
668
 
669
void
670
flashkwlink(void)
671
{
672
	addflashcard("nand", reset);
673
}