1/*
2 * Broadcom chipcommon NAND flash interface
3 *
4 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: nflash.c 501990 2014-09-11 10:54:46Z $
19 */
20
21#include <typedefs.h>
22#include <osl.h>
23#include <bcmutils.h>
24#include <siutils.h>
25#include <hndsoc.h>
26#include <sbhndcpu.h>
27#include <sbchipc.h>
28#include <bcmdevs.h>
29#include <nflash.h>
30#include <hndpmu.h>
31
32#ifdef BCMDBG
33#define	NFL_MSG(args)	printf args
34#else
35#define	NFL_MSG(args)
36#endif	/* BCMDBG */
37
38#define NF_RETRIES	1000000
39
40#define NF_SMALL_BADBLOCK_POS	5
41#define NF_LARGE_BADBLOCK_POS	0
42
43/* Private global state */
44static hndnand_t nflash;
45
46/* Private variables used for BCM4706 only */
47static uint32 nflash_col_mask;
48static uint32 nflash_row_shift;
49
50
51#undef DEBUG_GEN_1BIT_ERR
52/* 256 bytes for 3 bytes ecc. */
53#define SOFT_HAMMING_SECTOR_SIZE (256)
54#define SOFT_HAMMING_ECC_BYTES (3)
55
56#define MAX_SOFTECC_OOB_SZ (64)
57static uint8 tmp_page_oob[MAX_SOFTECC_OOB_SZ];
58
59#define SAME_ECC(recc, cecc) \
60				((recc[0] == cecc[0]) && \
61				(recc[1] == cecc[1]) && \
62				(recc[2] == cecc[2]))
63
64#if defined(_CFE_) || defined(CFE_FLASH_ERASE_FLASH_ENABLED)
65extern void hamming_compute_256(const uint8 *data, uint8 *code);
66extern int8 hamming_correct_256(uint8 *data, const uint8 *original_code,
67    const uint8 *computed_code);
68
69#define nand_calculate_ecc(mtd, data, ecc)\
70	hamming_compute_256(data, ecc)
71#define nand_correct_data(mtd, data, read_ecc, calc_ecc)\
72	hamming_correct_256(data, read_ecc, calc_ecc)
73
74int enable_ecc_correct = 1;
75#else
76extern int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
77extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
78int enable_ecc_correct = 0;
79#endif
80
81/* Redefine nand_ecclayout to same as mtd-abi.h */
82#ifdef CONFIG_BCM47XX
83#define MTD_MAX_OOBFREE_ENTRIES	16
84#else
85#define MTD_MAX_OOBFREE_ENTRIES	8
86#endif
87struct nand_oobfree {
88	uint32 offset;
89	uint32 length;
90};
91
92struct nand_ecclayout {
93	uint32 eccbytes;
94#ifdef CONFIG_BCM47XX
95	uint32 eccpos[128];
96#else
97	uint32 eccpos[64];
98#endif /* CONFIG_BCM47XX */
99	uint32 oobavail;
100	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
101};
102
103/* Define default oob placement schemes for large and small page devices */
104static struct nand_ecclayout brcmnand_swecc_nand_oob_8 = {
105	.eccbytes = 3,
106	.eccpos = {0, 1, 2},
107};
108
109static struct nand_ecclayout brcmnand_swecc_nand_oob_16 = {
110	.eccbytes = 6,
111	.eccpos = {0, 1, 2, 3, 6, 7},
112};
113
114static struct nand_ecclayout brcmnand_swecc_oob_64 = {
115	.eccbytes = 24,
116	.eccpos = {
117		   40, 41, 42, 43, 44, 45, 46, 47,
118		   48, 49, 50, 51, 52, 53, 54, 55,
119		   56, 57, 58, 59, 60, 61, 62, 63},
120};
121
122/* For softare ecc reference current layout. */
123static struct nand_ecclayout *curr_ecclayout = NULL;
124#ifdef DEBUG_GEN_1BIT_ERR
125int enable_inject_err_on_write = 1;
126#endif
127
128/* Prototype */
129static int nflash_poll(si_t *sih, chipcregs_t *cc);
130static int nflash_readst(si_t *sih, chipcregs_t *cc, uint8 *status);
131static int nflash_readoob(si_t *sih, chipcregs_t *cc, uint64 offset, uint len, uchar *buf);
132static int nflash_writeoob(si_t *sih, chipcregs_t *cc, uint64 offset, uint len, uchar *buf);
133
134hndnand_t *nflash_init(si_t *sih);
135static void nflash_enable(hndnand_t *nfl, int enable);
136static int nflash_read(hndnand_t *nfl, uint64 offset, uint len, uchar *buf);
137static int nflash_write(hndnand_t *nfl, uint64 offset, uint len, const uchar *buf);
138static int nflash_erase(hndnand_t *nfl, uint64 offset);
139static int nflash_checkbadb(hndnand_t *nfl, uint64 offset);
140static int nflash_mark_badb(hndnand_t *nfl, uint64 offset);
141
142
143static void
144nflash_enable(hndnand_t *nfl, int enable)
145{
146	si_t *sih = nfl->sih;
147
148	if (sih->ccrev == 38) {
149		/* BCM5357 NAND boot */
150		if ((sih->chipst & (1 << 4)) != 0)
151			return;
152
153		if (enable)
154			si_pmu_chipcontrol(sih, 1, CCTRL5357_NFLASH, CCTRL5357_NFLASH);
155		else
156			si_pmu_chipcontrol(sih, 1, CCTRL5357_NFLASH, 0);
157	}
158}
159
160/* Issue a nand flash control command; this is used for BCM4706 */
161static INLINE int
162nflash_ctrlcmd(osl_t *osh, chipcregs_t *cc, uint ctrlcode)
163{
164	int cnt = 0;
165
166	W_REG(osh, &cc->nflashctrl, ctrlcode | NFC_START);
167
168	while ((R_REG(osh, &cc->nflashctrl) & NFC_START) != 0) {
169		if (++cnt > NF_RETRIES) {
170			printf("nflash_ctrlcmd: not ready\n");
171			return -1;
172		}
173	}
174
175	return 0;
176}
177
178/* Issue a nand flash command */
179static INLINE void
180nflash_cmd(osl_t *osh, chipcregs_t *cc, uint opcode)
181{
182	W_REG(osh, &cc->nand_cmd_start, opcode);
183	/* read after write to flush the command */
184	R_REG(osh, &cc->nand_cmd_start);
185}
186
187static bool firsttime = TRUE;
188
189static char *
190nflash_check_id(uint8 *id)
191{
192	char *name = NULL;
193
194	switch (id[0]) {
195	case NFL_VENDOR_AMD:
196		name = "AMD";
197		break;
198	case NFL_VENDOR_NUMONYX:
199		name = "Numonyx";
200		break;
201	case NFL_VENDOR_MICRON:
202		name = "Micron";
203		break;
204	case NFL_VENDOR_TOSHIBA:
205		name = "Toshiba";
206		break;
207	case NFL_VENDOR_HYNIX:
208		name = "Hynix";
209		break;
210	case NFL_VENDOR_SAMSUNG:
211		name = "Samsung";
212		break;
213	case NFL_VENDOR_ESMT:
214		name = "Esmt";
215		break;
216	case NFL_VENDOR_MXIC:
217		name = "Mxic";
218		break;
219	case NFL_VENDOR_ZENTEL:
220		name = "Zentel";
221		break;
222	case NFL_VENDOR_WINBOND:
223		name = "Winbond";
224		break;
225	default:
226//		printf("No NAND flash type found\n");
227		name = "Unknown";
228		break;
229	}
230
231	return name;
232}
233
234/* Initialize nand flash access */
235hndnand_t *
236nflash_init(si_t *sih)
237{
238	chipcregs_t *cc;
239	uint32 id, id2;
240	char *name = "";
241	osl_t *osh;
242	int i;
243	uint32 ncf, val;
244	uint32 acc_control;
245
246	ASSERT(sih);
247
248	if ((cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX)) == NULL)
249		return NULL;
250
251	/* Only support chipcommon revision == 38 and BCM4706 for now */
252	if ((CHIPID(sih->chip) != BCM4706_CHIP_ID) && (sih->ccrev != 38))
253		return NULL;
254
255	/* Check if nand flash is mounted */
256	if ((sih->cccaps & CC_CAP_NFLASH) != CC_CAP_NFLASH)
257		return NULL;
258
259	if (!firsttime && nflash.size)
260		return &nflash;
261
262	osh = si_osh(sih);
263	bzero(&nflash, sizeof(nflash));
264
265	nflash.sih = sih;
266	nflash.core = (void *)cc;
267	nflash.enable = nflash_enable;
268	nflash.read = nflash_read;
269	nflash.write = nflash_write;
270	nflash.erase = nflash_erase;
271	nflash.checkbadb = nflash_checkbadb;
272	nflash.markbadb = nflash_mark_badb;
273
274	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
275	    uint32 cpu_freq, clk;
276		uint32 w0, w1, w2, w3, w4;
277		uint32 ctrlcode, val;
278		uint32 totbits = 0, colbits = 0, rowbits;
279		uint32 colbsize, rowbsize;
280		uint32 oobsz_per_sector, plane_sz, plane_num;
281
282		/* Enable nand flash interface of BCM4706 (usign CS1) */
283		val = R_REG(osh, &cc->eci.flashconf.flashstrconfig) | FLSTRCF4706_NF1;
284		W_REG(osh, &cc->eci.flashconf.flashstrconfig, val);
285
286		/* Configure nand flash bus timing */
287		if (R_REG(osh, &cc->chipstatus) & CST4706_PKG_OPTION) {
288			cpu_freq = (400000000 / 4);
289		} else {
290			/* Get N divider to determine CPU clock */
291			W_REG(osh, &cc->pllcontrol_addr, 4);
292			val = (R_REG(osh, &cc->pllcontrol_data) & 0xfff) >> 3;
293
294			/* Fixed reference clock 25MHz and m = 2 */
295			cpu_freq = (val * 25000000 / 2) / 4;
296		}
297
298		clk = cpu_freq / 1000000;
299
300		w0 = NFLASH_T_WP;
301		w1 = NFLASH_T_RR;
302		w2 = NFLASH_T_CS - NFLASH_T_WP;
303		w3 = NFLASH_T_WH;
304		w4 = NFLASH_T_WB;
305
306		w0 = nflash_ns_to_cycle(w0, clk);
307		w1 = nflash_ns_to_cycle(w1, clk);
308		w2 = nflash_ns_to_cycle(w2, clk);
309		w3 = nflash_ns_to_cycle(w3, clk);
310		w4 = nflash_ns_to_cycle(w4, clk) - 1;
311
312		val = (w4 << NFLASH_WAITCOUNT_W4_SHIFT) | (w3 << NFLASH_WAITCOUNT_W3_SHIFT)
313				| (w2 << NFLASH_WAITCOUNT_W2_SHIFT)
314				| (w1 << NFLASH_WAITCOUNT_W1_SHIFT)	| w0;
315		W_REG(osh, &cc->nflashwaitcnt0, val);
316
317		/* Read nand flash ID */
318		ctrlcode = NFC_CSA | NFC_SPECADDR | NFC_CMD1W | NFC_CMD0 | NFCTRL_ID;
319
320		if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
321			return NULL;
322
323		for (i = 0; i < 5; i++) {
324			if (i <= 4)
325				ctrlcode = (NFC_CSA | NFC_1BYTE | NFC_DREAD);
326			else
327				ctrlcode = (NFC_1BYTE | NFC_DREAD);
328
329			if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
330				return NULL;
331			else
332				nflash.id[i] = R_REG(osh, &cc->nflashdata) & 0xff;
333		}
334
335		name = nflash_check_id(nflash.id);
336		if (name == NULL) {
337			/* Disable nand flash interface of BCM4706 (usign CS1) */
338			val = R_REG(osh, &cc->eci.flashconf.flashstrconfig) & ~FLSTRCF4706_NF1;
339			W_REG(osh, &cc->eci.flashconf.flashstrconfig, val);
340
341			return NULL;
342		}
343		nflash.type = nflash.id[0];
344
345		/* In unit of bytes */
346		nflash.pagesize = 1024 << (nflash.id[3] & 0x3);
347		nflash.blocksize = (64 * 1024) << ((nflash.id[3] >> 4) & 0x3);
348
349		oobsz_per_sector = (8 << ((nflash.id[3] >> 2) & 0x1));
350		nflash.oobsize = oobsz_per_sector * (nflash.pagesize / NFL_SECTOR_SIZE);
351
352		/* In unit of MBytes */
353		plane_sz = (8 << ((nflash.id[4] >> 4) & 0x7));
354		plane_num = (1 << ((nflash.id[4] >> 2) & 0x3));
355		nflash.size = plane_sz * plane_num;
356
357		/* Spansion S34ML01G1 does not support id[4]. Override flash size to 128MB  */
358		if ((nflash.id[0] == NFL_VENDOR_AMD) &&
359			(nflash.id[1] == 0xf1) && (nflash.id[2] == 0x80) && (nflash.id[3] == 0x1d))
360			nflash.size = 128;
361
362		for (i = 0; i < 32; i++) {
363			if ((0x1 << i) == nflash.size) {
364				totbits = i + 20;
365				break;
366			}
367		}
368
369		if (totbits == 0) {
370#ifdef BCMDBG
371			NFL_MSG(("nflash_init: failed to find nflash total bits\n"));
372#endif
373			return NULL;
374		}
375
376		for (i = 0; i < 32; i++) {
377			if ((0x1 << i) == nflash.pagesize) {
378				colbits = i + 1;	/* including spare oob bytes */
379				break;
380			}
381		}
382
383		if (colbits == 0) {
384#ifdef BCMDBG
385			NFL_MSG(("nflash_init: failed to find nflash column address bits\n"));
386#endif
387			return NULL;
388		}
389
390		nflash_col_mask = (0x1 << colbits) - 1;
391		nflash_row_shift = colbits;
392
393		colbsize = (colbits + 7) / 8;
394
395		rowbits = totbits - colbits + 1;
396		rowbsize = (rowbits + 7) / 8;
397
398		val = ((rowbsize - 1) << NFCF_ROWSZ_SHIFT) | ((colbsize - 1) << NFCF_COLSZ_SHIFT)
399				| NFCF_DS_8 | NFCF_WE;
400
401		W_REG(osh, &cc->nflashconf, val);
402
403		switch (nflash.oobsize) {
404		case 64:
405			curr_ecclayout = &brcmnand_swecc_oob_64;
406			break;
407		case 16:
408			curr_ecclayout = &brcmnand_swecc_nand_oob_16;
409			break;
410		case 8:
411			curr_ecclayout = &brcmnand_swecc_nand_oob_8;
412			break;
413		default:
414			printf("unsupported oob size %d.\n", nflash.oobsize);
415			return NULL;
416		}
417	} else {
418		nflash_enable(&nflash, 1);
419		nflash_cmd(osh, cc, NCMD_ID_RD);
420		if (nflash_poll(sih, cc) < 0) {
421			nflash_enable(&nflash, 0);
422			return NULL;
423		}
424		nflash_enable(&nflash, 0);
425		id = R_REG(osh, &cc->nand_devid);
426		id2 = R_REG(osh, &cc->nand_devid_x);
427		for (i = 0; i < 5; i++) {
428			if (i < 4)
429				nflash.id[i] = (id >> (8*i)) & 0xff;
430			else
431				nflash.id[i] = id2 & 0xff;
432		}
433
434		name = nflash_check_id(nflash.id);
435		if (name == NULL)
436			return NULL;
437		nflash.type = nflash.id[0];
438
439		ncf = R_REG(osh, &cc->nand_config);
440		/*  Page size (# of bytes) */
441		val = (ncf & NCF_PAGE_SIZE_MASK) >> NCF_PAGE_SIZE_SHIFT;
442		switch (val) {
443		case 0:
444			nflash.pagesize = 512;
445			break;
446		case 1:
447			nflash.pagesize = (1 << 10) * 2;
448			break;
449			case 2:
450			nflash.pagesize = (1 << 10) * 4;
451			break;
452		case 3:
453			nflash.pagesize = (1 << 10) * 8;
454			break;
455		}
456		/* Block size (# of bytes) */
457		val = (ncf & NCF_BLOCK_SIZE_MASK) >> NCF_BLOCK_SIZE_SHIFT;
458		switch (val) {
459		case 0:
460			nflash.blocksize = (1 << 10) * 16;
461			break;
462		case 1:
463			nflash.blocksize = (1 << 10) * 128;
464			break;
465		case 2:
466			nflash.blocksize = (1 << 10) * 8;
467			break;
468		case 3:
469			nflash.blocksize = (1 << 10) * 512;
470			break;
471		case 4:
472			nflash.blocksize = (1 << 10) * 256;
473			break;
474		default:
475			printf("Unknown block size\n");
476			return NULL;
477		}
478		/* NAND flash size in MBytes */
479		val = (ncf & NCF_DEVICE_SIZE_MASK) >> NCF_DEVICE_SIZE_SHIFT;
480		if (val == 0) {
481			printf("Unknown flash size\n");
482			return NULL;
483		}
484		nflash.size = (1 << (val - 1)) * 8;
485
486		/* More attribues for ECC functions */
487		acc_control = R_REG(osh, &cc->nand_acc_control);
488		nflash.ecclevel = (acc_control & NAC_ECC_LEVEL_MASK) >> NAC_ECC_LEVEL_SHIFT;
489		nflash.ecclevel0 = (acc_control & NAC_ECC_LEVEL0_MASK) >> NAC_ECC_LEVEL0_SHIFT;
490		/* make sure that block-0 and block-n use the same ECC level */
491		if (nflash.ecclevel != nflash.ecclevel0) {
492			acc_control &= ~(NAC_ECC_LEVEL_MASK | NAC_ECC_LEVEL0_MASK);
493			acc_control |=
494				(nflash.ecclevel0 << NAC_ECC_LEVEL0_SHIFT) |
495				(nflash.ecclevel0 << NAC_ECC_LEVEL_SHIFT);
496			W_REG(osh, &cc->nand_acc_control, acc_control);
497			nflash.ecclevel = nflash.ecclevel0;
498		}
499		nflash.phybase = SI_FLASH1;
500	}
501
502	nflash.numblocks = (nflash.size * (1 << 10)) / (nflash.blocksize >> 10);
503	if (firsttime)
504		printf("Found a %s NAND flash with %uB pages or %dKB blocks; total size %dMB\n",
505		       name, nflash.pagesize, (nflash.blocksize >> 10), nflash.size);
506	firsttime = FALSE;
507	return nflash.size ? &nflash : NULL;
508}
509
510/* Read len bytes starting at offset into buf. Returns number of bytes read. */
511static int
512nflash_read(hndnand_t *nfl, uint64 offset, uint len, uchar *buf)
513{
514	si_t *sih = nfl->sih;
515	chipcregs_t *cc = (chipcregs_t *)nfl->core;
516	uint32 mask;
517	osl_t *osh;
518	int i;
519	uint32 *to;
520	uint32 val;
521	uint res;
522
523	ASSERT(sih);
524
525	mask = NFL_SECTOR_SIZE - 1;
526	if ((offset & mask) != 0 || (len & mask) != 0)
527		return 0;
528	if ((((offset + len) >> 20) > nflash.size) ||
529	    ((((offset + len) >> 20) == nflash.size) &&
530	     (((offset + len) & ((1 << 20) - 1)) != 0)))
531		return 0;
532	osh = si_osh(sih);
533	to = (uint32 *)buf;
534	res = len;
535
536	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
537		uint32 page_addr, page_offset;
538		uint32 ctrlcode;
539		int prev_page_start_offset = -1;
540		uint page_start_offset;
541		int sector_idx = 0, eccpos;
542		uint8 *pdata;
543		uint8 read_ecc[SOFT_HAMMING_ECC_BYTES];
544		uint8 calc_ecc[SOFT_HAMMING_ECC_BYTES];
545
546		/* 4706 only support SW 1-bit hamming ECC */
547		pdata = (uint8*)buf;
548		while (res > 0) {
549			page_offset = offset & (nflash.pagesize - 1);
550			page_addr = (offset & ~(nflash.pagesize - 1)) * 2;
551			page_addr += page_offset;
552
553			page_start_offset = (offset & ~(uint32)((uint32)nflash.pagesize-1));
554			if (page_start_offset != prev_page_start_offset) {
555				/* read oob only on new page to read. */
556				nflash_readoob(sih, cc, page_start_offset,
557					nflash.oobsize, tmp_page_oob);
558				prev_page_start_offset = page_start_offset;
559			}
560			W_REG(osh, &cc->nflashcoladdr, page_addr & nflash_col_mask);
561			W_REG(osh, &cc->nflashrowaddr, page_addr >> nflash_row_shift);
562
563			ctrlcode = NFC_CSA | NFC_CMD1W | NFC_ROW | NFC_COL | NFC_CMD0 | NFCTRL_READ;
564
565			if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
566				break;
567
568			if (nflash_poll(sih, cc) < 0)
569				break;
570
571			for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) {
572				if (i < NFL_SECTOR_SIZE - 4)
573					ctrlcode = (NFC_CSA | NFC_4BYTES | NFC_DREAD);
574				else
575					ctrlcode = (NFC_4BYTES | NFC_DREAD);
576
577				if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
578					return (len - res);
579
580				*to = R_REG(osh, &cc->nflashdata);
581			}
582
583			for (i = 0, sector_idx = (page_offset / SOFT_HAMMING_SECTOR_SIZE);
584				 i < (NFL_SECTOR_SIZE / SOFT_HAMMING_SECTOR_SIZE);
585				 i++, sector_idx++) {
586
587				/* find correct ecc position on page oob. */
588				eccpos = sector_idx * SOFT_HAMMING_ECC_BYTES;
589
590				read_ecc[0] = tmp_page_oob[curr_ecclayout->eccpos[eccpos + 0]];
591				read_ecc[1] = tmp_page_oob[curr_ecclayout->eccpos[eccpos + 1]];
592				read_ecc[2] = tmp_page_oob[curr_ecclayout->eccpos[eccpos + 2]];
593
594				nand_calculate_ecc(NULL, pdata, calc_ecc);
595
596				if (enable_ecc_correct && !SAME_ECC(read_ecc, calc_ecc) &&
597					nand_correct_data(NULL, pdata, read_ecc, calc_ecc) < 0) {
598						printf("nflash_read: cannot correct data !!\n");
599					}
600
601				pdata += SOFT_HAMMING_SECTOR_SIZE;
602			}
603
604			res -= NFL_SECTOR_SIZE;
605			offset += NFL_SECTOR_SIZE;
606		}
607	} else {
608		nflash_enable(nfl, 1);
609		while (res > 0) {
610			W_REG(osh, &cc->nand_cmd_addr, offset);
611			nflash_cmd(osh, cc, NCMD_PAGE_RD);
612			if (nflash_poll(sih, cc) < 0)
613				break;
614			if (((val = R_REG(osh, &cc->nand_intfc_status)) & NIST_CACHE_VALID) == 0)
615				break;
616			W_REG(osh, &cc->nand_cache_addr, 0);
617			for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) {
618				*to = R_REG(osh, &cc->nand_cache_data);
619			}
620
621			res -= NFL_SECTOR_SIZE;
622			offset += NFL_SECTOR_SIZE;
623		}
624		nflash_enable(nfl, 0);
625	}
626
627	return (len - res);
628}
629
630/* Poll for command completion. Returns zero when complete. */
631static int
632nflash_poll(si_t *sih, chipcregs_t *cc)
633{
634	osl_t *osh;
635	int i;
636	uint32 pollmask;
637
638	ASSERT(sih);
639	osh = si_osh(sih);
640
641	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
642		for (i = 0; i < NF_RETRIES; i++) {
643			if ((R_REG(osh, &cc->nflashctrl) & NFC_RDYBUSY) == NFC_RDYBUSY) {
644				if ((R_REG(osh, &cc->nflashctrl) & NFC_ERROR) == NFC_ERROR) {
645					printf("nflash_poll: error occurred\n");
646					return -1;
647				}
648				else
649					return 0;
650			}
651		}
652	} else {
653		pollmask = NIST_CTRL_READY|NIST_FLASH_READY;
654		for (i = 0; i < NF_RETRIES; i++) {
655			if ((R_REG(osh, &cc->nand_intfc_status) & pollmask) == pollmask) {
656				return 0;
657			}
658		}
659	}
660
661	printf("nflash_poll: not ready\n");
662	return -1;
663}
664
665/* Write len bytes starting at offset into buf. Returns number of bytes
666 * written.
667 */
668static int
669nflash_write(hndnand_t *nfl, uint64 offset, uint len, const uchar *buf)
670{
671	si_t *sih = nfl->sih;
672	chipcregs_t *cc = (chipcregs_t *)nfl->core;
673	uint32 mask;
674	osl_t *osh;
675	int i;
676	uint32 *from;
677	uint res;
678	uint32 reg;
679	int ret = 0;
680	uint8 status;
681
682	ASSERT(sih);
683	mask = nflash.pagesize - 1;
684	/* Check offset and length */
685	if ((offset & mask) != 0 || (len & mask) != 0)
686		return 0;
687	if ((((offset + len) >> 20) > nflash.size) ||
688	    ((((offset + len) >> 20) == nflash.size) &&
689	     (((offset + len) & ((1 << 20) - 1)) != 0)))
690		return 0;
691	osh = si_osh(sih);
692
693	from = (uint32 *)buf;
694	res = len;
695
696	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
697		uint32 page_addr;
698		uint32 ctrlcode;
699		uint8 *pdata;
700		int sector_idx, eccpos;
701		uint8 calc_ecc[SOFT_HAMMING_ECC_BYTES];
702
703		/* 4706 only support SW 1-bit hamming ECC */
704		pdata = (uint8 *)buf;
705
706		while (res > 0) {
707			nflash_readoob(sih, cc, offset, nflash.oobsize, tmp_page_oob);
708
709			for (i = 0, sector_idx = 0;
710				  i < (nflash.pagesize / SOFT_HAMMING_SECTOR_SIZE);
711				  i++, sector_idx++) {
712				eccpos = sector_idx * SOFT_HAMMING_ECC_BYTES;
713				nand_calculate_ecc(NULL, pdata, calc_ecc);
714
715				tmp_page_oob[curr_ecclayout->eccpos[eccpos + 0]] = calc_ecc[0];
716				tmp_page_oob[curr_ecclayout->eccpos[eccpos + 1]] = calc_ecc[1];
717				tmp_page_oob[curr_ecclayout->eccpos[eccpos + 2]] = calc_ecc[2];
718				pdata += SOFT_HAMMING_SECTOR_SIZE;
719			}
720
721			/* written a sector */
722			if (nflash_writeoob(sih, cc, offset,
723				nflash.oobsize, tmp_page_oob) < 0) {
724				printf("\nflash_write write oob fail, offset 0x%08x\n",
725					(uint32)offset);
726				return -1;
727			}
728
729#ifdef DEBUG_GEN_1BIT_ERR
730			for (i = 0; i < enable_inject_err_on_write; i++) {
731				int min_range = (res < nflash.pagesize)? res: nflash.pagesize;
732				min_range /= sizeof(uint32);
733				from[(from[i]%min_range)] ^= 0x04;
734			}
735#endif
736			page_addr = (offset & ~(nflash.pagesize - 1)) * 2;
737
738			W_REG(osh, &cc->nflashcoladdr, page_addr & nflash_col_mask);
739			W_REG(osh, &cc->nflashrowaddr, page_addr >> nflash_row_shift);
740
741			ctrlcode = NFC_CSA | NFC_ROW | NFC_COL | NFC_CMD0 | NFCTRL_PAGEPROG;
742
743			if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
744				return -1;
745
746			for (i = 0; i < nflash.pagesize; i += 4, from++) {
747				W_REG(osh, &cc->nflashdata, *from);
748
749				if (i < nflash.pagesize - 4)
750					ctrlcode = (NFC_CSA | NFC_4BYTES | NFC_DWRITE);
751				else
752					ctrlcode = (NFC_4BYTES | NFC_DWRITE);
753
754				if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
755					return (len - res);
756			}
757
758			if (nflash_ctrlcmd(osh, cc, (NFC_CMD0 | NFCTRL_PROGSTART)) != 0)
759				return -1;
760
761			if (nflash_poll(sih, cc) < 0)
762				return -1;
763
764			if (nflash_readst(sih, cc, &status) != 0)
765				return -1;
766
767			if (status & 1) {
768				printf("nflash_write: failed with status 0x%02x\n", status);
769				return -1;
770			}
771
772			res -= nflash.pagesize;
773			offset += nflash.pagesize;
774		}
775	} else {
776		nflash_enable(nfl, 1);
777		/* disable partial page enable */
778		reg = R_REG(osh, &cc->nand_acc_control);
779		reg &= ~NAC_PARTIAL_PAGE_EN;
780		W_REG(osh, &cc->nand_acc_control, reg);
781
782		while (res > 0) {
783			W_REG(osh, &cc->nand_cache_addr, 0);
784			for (i = 0; i < nflash.pagesize; i += 4, from++) {
785				if (i % 512 == 0)
786					W_REG(osh, &cc->nand_cmd_addr, i);
787				W_REG(osh, &cc->nand_cache_data, *from);
788			}
789			W_REG(osh, &cc->nand_cmd_addr, offset + nflash.pagesize - 512);
790			nflash_cmd(osh, cc, NCMD_PAGE_PROG);
791			if (nflash_poll(sih, cc) < 0)
792				break;
793
794			/* Check status */
795			W_REG(osh, &cc->nand_cmd_start, NCMD_STATUS_RD);
796			if (nflash_poll(sih, cc) < 0)
797				break;
798			status = R_REG(osh, &cc->nand_intfc_status) & NIST_STATUS;
799			if (status & 1) {
800				ret = -1;
801				break;
802			}
803			res -= nflash.pagesize;
804			offset += nflash.pagesize;
805		}
806
807		nflash_enable(nfl, 0);
808		if (ret)
809			return ret;
810	}
811
812	return (len - res);
813}
814
815/* Erase a region. Returns number of bytes scheduled for erasure.
816 * Caller should poll for completion.
817 */
818static int
819nflash_erase(hndnand_t *nfl, uint64 offset)
820{
821	si_t *sih = nfl->sih;
822	chipcregs_t *cc = (chipcregs_t *)nfl->core;
823	osl_t *osh;
824	int ret = 0;
825	uint8 status = 0;
826
827	ASSERT(sih);
828
829	osh = si_osh(sih);
830	if ((offset >> 20) >= nflash.size)
831		return -1;
832	if ((offset & (nflash.blocksize - 1)) != 0) {
833		return -1;
834	}
835
836	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
837		uint32 ctrlcode;
838		uint32 row_addr;
839
840		row_addr = (offset & ~(nflash.blocksize - 1)) * 2;
841
842		W_REG(osh, &cc->nflashrowaddr, row_addr >> nflash_row_shift);
843
844		ctrlcode = (NFC_CMD1W | NFC_ROW | NFC_CMD0 | NFCTRL_ERASE);
845
846		if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
847			return -1;
848
849		if (nflash_poll(sih, cc) < 0)
850			return -1;
851
852		if (nflash_readst(sih, cc, &status) != 0)
853			return -1;
854
855		if (status & 1) {
856			printf("nflash_erase: failed with status 0x%02x\n", status);
857			return -1;
858		}
859	} else {
860		nflash_enable(nfl, 1);
861		W_REG(osh, &cc->nand_cmd_addr, offset);
862		nflash_cmd(osh, cc, NCMD_BLOCK_ERASE);
863		if (nflash_poll(sih, cc) < 0) {
864			ret = -1;
865			goto err;
866		}
867		/* Check status */
868		W_REG(osh, &cc->nand_cmd_start, NCMD_STATUS_RD);
869		if (nflash_poll(sih, cc) < 0) {
870			ret = -1;
871			goto err;
872		}
873		status = R_REG(osh, &cc->nand_intfc_status) & NIST_STATUS;
874		if (status & 1)
875			ret = -1;
876err:
877		nflash_enable(nfl, 0);
878	}
879
880	return ret;
881}
882
883static int
884nflash_checkbadb(hndnand_t *nfl, uint64 offset)
885{
886	si_t *sih = nfl->sih;
887	chipcregs_t *cc = (chipcregs_t *)nfl->core;
888	osl_t *osh;
889	int i;
890	uint off;
891	uint32 nand_intfc_status;
892	int ret = 0;
893
894	ASSERT(sih);
895
896	osh = si_osh(sih);
897	if ((offset >> 20) >= nflash.size)
898		return -1;
899	if ((offset & (nflash.blocksize - 1)) != 0) {
900		return -1;
901	}
902
903	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
904		uint8 oob_buf1[8], oob_buf2[8];
905		uint sec_page_offset;
906		int status1, status2, badblk_pos;
907
908		status1 = nflash_readoob(sih, cc, offset, sizeof(oob_buf1), oob_buf1);
909
910		sec_page_offset = offset + nflash.pagesize;
911		status2 = nflash_readoob(sih, cc, sec_page_offset, sizeof(oob_buf2), oob_buf2);
912
913		if (status1 <= 0 || status2 <= 0)
914			return -1;
915
916		/* Set the bad block position */
917		if (nflash.pagesize > 512)
918			badblk_pos = NF_LARGE_BADBLOCK_POS;
919		else
920			badblk_pos = NF_SMALL_BADBLOCK_POS;
921
922		if (oob_buf1[badblk_pos] != 0xff || oob_buf2[badblk_pos] != 0xff)
923			return -1;
924		else
925			return 0;
926	} else {
927		nflash_enable(nfl, 1);
928		for (i = 0; i < 2; i++) {
929			off = offset + (nflash.pagesize * i);
930			W_REG(osh, &cc->nand_cmd_addr, off);
931			nflash_cmd(osh, cc, NCMD_SPARE_RD);
932			if (nflash_poll(sih, cc) < 0) {
933				ret = -1;
934				goto err;
935			}
936			nand_intfc_status = R_REG(osh, &cc->nand_intfc_status) & NIST_SPARE_VALID;
937			if (nand_intfc_status != NIST_SPARE_VALID) {
938				ret = -1;
939				goto err;
940			}
941			if ((R_REG(osh, &cc->nand_spare_rd0) & 0xff) != 0xff) {
942				ret = -1;
943				goto err;
944			}
945		}
946err:
947		nflash_enable(nfl, 0);
948		return ret;
949	}
950}
951
952static int
953nflash_mark_badb(hndnand_t *nfl, uint64 offset)
954{
955	si_t *sih = nfl->sih;
956	chipcregs_t *cc = (chipcregs_t *)nfl->core;
957	osl_t *osh;
958	uint off;
959	int i, ret = 0;
960	uint32 reg;
961
962	ASSERT(sih);
963
964	osh = si_osh(sih);
965	if ((offset >> 20) >= nflash.size)
966		return -1;
967	if ((offset & (nflash.blocksize - 1)) != 0) {
968		return -1;
969	}
970
971	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
972		unsigned char oob_buf[128];
973
974		/* Force OOB write even nflash_erase return failure */
975		nflash_erase(nfl, offset);
976
977		memset((void *)oob_buf, 0, nflash.oobsize);
978
979		if (nflash_writeoob(sih, cc, offset, nflash.oobsize, oob_buf) < 0)
980			return -1;
981
982		if (nflash_writeoob(sih, cc, offset + nflash.pagesize, nflash.oobsize, oob_buf) < 0)
983			return -1;
984	} else {
985		nflash_enable(nfl, 1);
986		/* Erase block */
987		W_REG(osh, &cc->nand_cmd_addr, offset);
988		nflash_cmd(osh, cc, NCMD_BLOCK_ERASE);
989		if (nflash_poll(sih, cc) < 0) {
990			ret = -1;
991			goto err;
992		}
993
994		/*
995		 * Enable partial page programming and disable ECC checkbit generation
996		 * for PROGRAM_SPARE_AREA
997		 */
998		reg = R_REG(osh, &cc->nand_acc_control);
999		reg |= NAC_PARTIAL_PAGE_EN;
1000		reg &= ~NAC_WR_ECC_EN;
1001		W_REG(osh, &cc->nand_acc_control, reg);
1002
1003		for (i = 0; i < 2; i++) {
1004			off = offset + (nflash.pagesize * i);
1005			W_REG(osh, &cc->nand_cmd_addr, off);
1006
1007			W_REG(osh, &cc->nand_spare_wr0, 0);
1008			W_REG(osh, &cc->nand_spare_wr4, 0);
1009			W_REG(osh, &cc->nand_spare_wr8, 0);
1010			W_REG(osh, &cc->nand_spare_wr12, 0);
1011
1012			nflash_cmd(osh, cc, NCMD_SPARE_PROG);
1013			if (nflash_poll(sih, cc) < 0) {
1014				ret = -1;
1015				goto err;
1016			}
1017		}
1018err:
1019		/* Restore the default value for spare area write registers */
1020		W_REG(osh, &cc->nand_spare_wr0, 0xffffffff);
1021		W_REG(osh, &cc->nand_spare_wr4, 0xffffffff);
1022		W_REG(osh, &cc->nand_spare_wr8, 0xffffffff);
1023		W_REG(osh, &cc->nand_spare_wr12, 0xffffffff);
1024
1025		/*
1026		 * Disable partial page programming and enable ECC checkbit generation
1027		 * for PROGRAM_SPARE_AREA
1028		 */
1029		reg = R_REG(osh, &cc->nand_acc_control);
1030		reg &= ~NAC_PARTIAL_PAGE_EN;
1031		reg |= NAC_WR_ECC_EN;
1032		W_REG(osh, &cc->nand_acc_control, reg);
1033
1034		nflash_enable(nfl, 0);
1035	}
1036	return ret;
1037}
1038
1039static int
1040nflash_readst(si_t *sih, chipcregs_t *cc, uint8 *status)
1041{
1042	osl_t *osh;
1043	int ret = 0;
1044
1045	ASSERT(sih);
1046
1047	osh = si_osh(sih);
1048
1049	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
1050		uint32 ctrlcode;
1051
1052		ctrlcode = (NFC_CSA | NFC_CMD0 | NFCTRL_STATUS);
1053
1054		if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
1055			return -1;
1056
1057		ctrlcode = (NFC_1BYTE | NFC_DREAD);
1058
1059		if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
1060			return -1;
1061
1062		*status = (uint8)(R_REG(osh, &cc->nflashdata) & 0xff);
1063
1064		return 0;
1065	} else {
1066		nflash_enable(&nflash, 1);
1067		W_REG(osh, &cc->nand_cmd_start, NCMD_STATUS_RD);
1068
1069		if (nflash_poll(sih, cc) < 0)
1070			ret = -1;
1071
1072		else
1073			*status = (uint8)(R_REG(osh, &cc->nand_intfc_status) & NIST_STATUS);
1074
1075		nflash_enable(&nflash, 0);
1076		return ret;
1077	}
1078}
1079
1080/* To read len bytes of oob data in the page specified in the page address offset */
1081static int
1082nflash_readoob(si_t *sih, chipcregs_t *cc, uint64 offset, uint len, uchar *buf)
1083{
1084	uint32 mask;
1085	osl_t *osh;
1086	int i;
1087	uint32 *to;
1088	uint res;
1089
1090	ASSERT(sih);
1091
1092	mask = nflash.pagesize - 1;
1093	if ((offset & mask) != 0 || (len > nflash.oobsize) || (len & 0x3) != 0)
1094		return -1;
1095
1096	osh = si_osh(sih);
1097	to = (uint32 *)buf;
1098	res = 0;
1099
1100	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
1101		uint32 page_addr, page_offset;
1102		uint32 ctrlcode;
1103
1104		page_addr = (offset & ~(nflash.pagesize - 1)) * 2;
1105		page_offset = nflash.pagesize;
1106		page_addr += page_offset;
1107
1108		W_REG(osh, &cc->nflashcoladdr, page_addr & nflash_col_mask);
1109		W_REG(osh, &cc->nflashrowaddr, page_addr >> nflash_row_shift);
1110
1111		ctrlcode = (NFC_CSA | NFC_CMD1W | NFC_ROW | NFC_COL | NFC_CMD0 | NFCTRL_READ);
1112
1113		if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
1114			return -1;
1115
1116		if (nflash_poll(sih, cc) < 0)
1117			return -1;
1118
1119		for (i = 0; i < len; i += 4, to++) {
1120			if (i < len - 4)
1121				ctrlcode = (NFC_CSA | NFC_4BYTES | NFC_DREAD);
1122			else
1123				ctrlcode = (NFC_4BYTES | NFC_DREAD);
1124
1125			if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
1126				return -1;
1127
1128			*to = R_REG(osh, &cc->nflashdata);
1129
1130			res += 4;
1131		}
1132	} else
1133		return -1;
1134
1135	return res;
1136}
1137
1138/* To write len bytes of oob data in the page specified in the page address offset */
1139static int
1140nflash_writeoob(si_t *sih, chipcregs_t *cc, uint64 offset, uint len, uchar *buf)
1141{
1142	uint32 mask;
1143	osl_t *osh;
1144	int i;
1145	uint32 *from;
1146	uint res;
1147
1148	ASSERT(sih);
1149
1150	mask = nflash.pagesize - 1;
1151	if ((offset & mask) != 0 || (len > nflash.oobsize) || (len & 0x3) != 0)
1152		return -1;
1153
1154	osh = si_osh(sih);
1155	from = (uint32 *)buf;
1156	res = 0;
1157
1158	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
1159		uint32 page_addr, page_offset;
1160		uint32 ctrlcode;
1161		uint8 status;
1162
1163		page_addr = (offset & ~(nflash.pagesize - 1)) * 2;
1164		page_offset = nflash.pagesize;
1165		page_addr += page_offset;
1166
1167		W_REG(osh, &cc->nflashcoladdr, page_addr & nflash_col_mask);
1168		W_REG(osh, &cc->nflashrowaddr, page_addr >> nflash_row_shift);
1169
1170		ctrlcode = (NFC_CSA | NFC_ROW | NFC_COL | NFC_CMD0 | NFCTRL_PAGEPROG);
1171
1172		if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
1173			return -1;
1174
1175		for (i = 0; i < len; i += 4, from++) {
1176			W_REG(osh, &cc->nflashdata, *from);
1177
1178			if (i < len - 4)
1179				ctrlcode = (NFC_CSA | NFC_4BYTES | NFC_DWRITE);
1180			else
1181				ctrlcode = (NFC_4BYTES | NFC_DWRITE);
1182
1183			if (nflash_ctrlcmd(osh, cc, ctrlcode) != 0)
1184				return -1;
1185
1186			res += 4;
1187		}
1188
1189		if (nflash_ctrlcmd(osh, cc, (NFC_CMD0 | NFCTRL_PROGSTART)) != 0)
1190			return -1;
1191
1192		if (nflash_poll(sih, cc) < 0)
1193			return -1;
1194
1195		if (nflash_readst(sih, cc, &status) != 0)
1196			return -1;
1197
1198		if (status & 1) {
1199			printf("nflash_writeoob: failed with status 0x%02x\n", status);
1200			return -1;
1201		}
1202
1203	} else
1204		return -1;
1205
1206	return res;
1207}
1208