xref: /plan9/sys/src/9/kw/flashkw.c (revision b649930dd34d6bab2bb3fa27632347c57745aead)
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
nandcmd(Flash * f,uchar b)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
nandaddr(Flash * f,uchar b)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
nandread(Flash * f)145 nandread(Flash *f)
146 {
147 	return *(uchar *)f->addr;
148 }
149 
150 static void
nandreadn(Flash * f,uchar * buf,long n)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
nandwrite(Flash * f,uchar b)160 nandwrite(Flash *f, uchar b)
161 {
162 	*(uchar *)f->addr = b;
163 	coherence();
164 }
165 
166 static void
nandwriten(Flash * f,uchar * buf,long n)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
nandclaim(Flash *)177 nandclaim(Flash*)
178 {
179 	Nandreg *nand = (Nandreg*)soc.nand;
180 
181 	nand->ctl |= NandActCEBoot;
182 	coherence();
183 }
184 
185 static void
nandunclaim(Flash *)186 nandunclaim(Flash*)
187 {
188 	Nandreg *nand = (Nandreg*)soc.nand;
189 
190 	nand->ctl &= ~NandActCEBoot;
191 	coherence();
192 }
193 
194 
195 Nandtab *
findflash(Flash * f,uintptr pa,uchar * id4p)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
flashat(Flash * f,uintptr pa)250 flashat(Flash *f, uintptr pa)
251 {
252 	return findflash(f, pa, nil) != nil;
253 }
254 
255 static int
idchip(Flash * f)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
ctlrwait(Flash * f)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
erasezone(Flash * f,Flashregion * r,ulong offset)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
flcachepage(Flash * f,ulong page,uchar * buf)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
write1page(Flash * f,ulong offset,void * buf)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
read1page(Flash * f,ulong offset,void * buf)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
rewrite(Flash * f,ulong offset,ulong pagoff,void * buf,ulong size)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
write(Flash * f,ulong offset,void * buf,long n)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
read(Flash * f,ulong offset,void * buf,long n)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
reset(Flash * f)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
flashkwlink(void)670 flashkwlink(void)
671 {
672 	addflashcard("nand", reset);
673 }
674