Linux Audio

Check our new training course

Loading...
  1/*****************************************************************************
  2* Copyright 2004 - 2009 Broadcom Corporation.  All rights reserved.
  3*
  4* Unless you and Broadcom execute a separate written software license
  5* agreement governing use of this software, this software is licensed to you
  6* under the terms of the GNU General Public License version 2, available at
  7* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  8*
  9* Notwithstanding the above, under no circumstances may you combine this
 10* software in any way with any other Broadcom software provided under a
 11* license other than the GPL, without Broadcom's express prior written
 12* consent.
 13*****************************************************************************/
 14
 15/* ---- Include Files ---------------------------------------------------- */
 16#include "nand_bcm_umi.h"
 17
 18/* ---- External Variable Declarations ----------------------------------- */
 19/* ---- External Function Prototypes ------------------------------------- */
 20/* ---- Public Variables ------------------------------------------------- */
 21/* ---- Private Constants and Types -------------------------------------- */
 22
 23/* ---- Private Function Prototypes -------------------------------------- */
 24static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
 25	struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
 26static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
 27	struct nand_chip *chip, const uint8_t *buf, int oob_required);
 28
 29/* ---- Private Variables ------------------------------------------------ */
 30
 31/*
 32** nand_hw_eccoob
 33** New oob placement block for use with hardware ecc generation.
 34*/
 35static struct nand_ecclayout nand_hw_eccoob_512 = {
 36	/* Reserve 5 for BI indicator */
 37	.oobfree = {
 38#if (NAND_ECC_NUM_BYTES > 3)
 39		    {.offset = 0, .length = 2}
 40#else
 41		    {.offset = 0, .length = 5},
 42		    {.offset = 6, .length = 7}
 43#endif
 44		    }
 45};
 46
 47/*
 48** We treat the OOB for a 2K page as if it were 4 512 byte oobs,
 49** except the BI is at byte 0.
 50*/
 51static struct nand_ecclayout nand_hw_eccoob_2048 = {
 52	/* Reserve 0 as BI indicator */
 53	.oobfree = {
 54#if (NAND_ECC_NUM_BYTES > 10)
 55		    {.offset = 1, .length = 2},
 56#elif (NAND_ECC_NUM_BYTES > 7)
 57		    {.offset = 1, .length = 5},
 58		    {.offset = 16, .length = 6},
 59		    {.offset = 32, .length = 6},
 60		    {.offset = 48, .length = 6}
 61#else
 62		    {.offset = 1, .length = 8},
 63		    {.offset = 16, .length = 9},
 64		    {.offset = 32, .length = 9},
 65		    {.offset = 48, .length = 9}
 66#endif
 67		    }
 68};
 69
 70/* We treat the OOB for a 4K page as if it were 8 512 byte oobs,
 71 * except the BI is at byte 0. */
 72static struct nand_ecclayout nand_hw_eccoob_4096 = {
 73	/* Reserve 0 as BI indicator */
 74	.oobfree = {
 75#if (NAND_ECC_NUM_BYTES > 10)
 76		    {.offset = 1, .length = 2},
 77		    {.offset = 16, .length = 3},
 78		    {.offset = 32, .length = 3},
 79		    {.offset = 48, .length = 3},
 80		    {.offset = 64, .length = 3},
 81		    {.offset = 80, .length = 3},
 82		    {.offset = 96, .length = 3},
 83		    {.offset = 112, .length = 3}
 84#else
 85		    {.offset = 1, .length = 5},
 86		    {.offset = 16, .length = 6},
 87		    {.offset = 32, .length = 6},
 88		    {.offset = 48, .length = 6},
 89		    {.offset = 64, .length = 6},
 90		    {.offset = 80, .length = 6},
 91		    {.offset = 96, .length = 6},
 92		    {.offset = 112, .length = 6}
 93#endif
 94		    }
 95};
 96
 97/* ---- Private Functions ------------------------------------------------ */
 98/* ==== Public Functions ================================================= */
 99
100/****************************************************************************
101*
102*  bcm_umi_bch_read_page_hwecc - hardware ecc based page read function
103*  @mtd:	mtd info structure
104*  @chip:	nand chip info structure
105*  @buf:	buffer to store read data
106*  @oob_required:	caller expects OOB data read to chip->oob_poi
107*
108***************************************************************************/
109static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
110				       struct nand_chip *chip, uint8_t * buf,
111				       int oob_required, int page)
112{
113	int sectorIdx = 0;
114	int eccsize = chip->ecc.size;
115	int eccsteps = chip->ecc.steps;
116	uint8_t *datap = buf;
117	uint8_t eccCalc[NAND_ECC_NUM_BYTES];
118	int sectorOobSize = mtd->oobsize / eccsteps;
119	int stat;
120	unsigned int max_bitflips = 0;
121
122	for (sectorIdx = 0; sectorIdx < eccsteps;
123			sectorIdx++, datap += eccsize) {
124		if (sectorIdx > 0) {
125			/* Seek to page location within sector */
126			chip->cmdfunc(mtd, NAND_CMD_RNDOUT, sectorIdx * eccsize,
127				      -1);
128		}
129
130		/* Enable hardware ECC before reading the buf */
131		nand_bcm_umi_bch_enable_read_hwecc();
132
133		/* Read in data */
134		bcm_umi_nand_read_buf(mtd, datap, eccsize);
135
136		/* Pause hardware ECC after reading the buf */
137		nand_bcm_umi_bch_pause_read_ecc_calc();
138
139		/* Read the OOB ECC */
140		chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
141			      mtd->writesize + sectorIdx * sectorOobSize, -1);
142		nand_bcm_umi_bch_read_oobEcc(mtd->writesize, eccCalc,
143					     NAND_ECC_NUM_BYTES,
144					     chip->oob_poi +
145					     sectorIdx * sectorOobSize);
146
147		/* Correct any ECC detected errors */
148		stat =
149		    nand_bcm_umi_bch_correct_page(datap, eccCalc,
150						  NAND_ECC_NUM_BYTES);
151
152		/* Update Stats */
153		if (stat < 0) {
154#if defined(NAND_BCM_UMI_DEBUG)
155			printk(KERN_WARNING "%s uncorr_err sectorIdx=%d\n",
156			       __func__, sectorIdx);
157			printk(KERN_WARNING
158			       "%s data %02x %02x %02x %02x "
159					 "%02x %02x %02x %02x\n",
160			       __func__, datap[0], datap[1], datap[2], datap[3],
161			       datap[4], datap[5], datap[6], datap[7]);
162			printk(KERN_WARNING
163			       "%s ecc  %02x %02x %02x %02x "
164					 "%02x %02x %02x %02x %02x %02x "
165					 "%02x %02x %02x\n",
166			       __func__, eccCalc[0], eccCalc[1], eccCalc[2],
167			       eccCalc[3], eccCalc[4], eccCalc[5], eccCalc[6],
168			       eccCalc[7], eccCalc[8], eccCalc[9], eccCalc[10],
169			       eccCalc[11], eccCalc[12]);
170			BUG();
171#endif
172			mtd->ecc_stats.failed++;
173		} else {
174#if defined(NAND_BCM_UMI_DEBUG)
175			if (stat > 0) {
176				printk(KERN_INFO
177				       "%s %d correctable_errors detected\n",
178				       __func__, stat);
179			}
180#endif
181			mtd->ecc_stats.corrected += stat;
182			max_bitflips = max_t(unsigned int, max_bitflips, stat);
183		}
184	}
185	return max_bitflips;
186}
187
188/****************************************************************************
189*
190*  bcm_umi_bch_write_page_hwecc - hardware ecc based page write function
191*  @mtd:	mtd info structure
192*  @chip:	nand chip info structure
193*  @buf:	data buffer
194*  @oob_required:	must write chip->oob_poi to OOB
195*
196***************************************************************************/
197static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
198	struct nand_chip *chip, const uint8_t *buf, int oob_required)
199{
200	int sectorIdx = 0;
201	int eccsize = chip->ecc.size;
202	int eccsteps = chip->ecc.steps;
203	const uint8_t *datap = buf;
204	uint8_t *oobp = chip->oob_poi;
205	int sectorOobSize = mtd->oobsize / eccsteps;
206
207	for (sectorIdx = 0; sectorIdx < eccsteps;
208	     sectorIdx++, datap += eccsize, oobp += sectorOobSize) {
209		/* Enable hardware ECC before writing the buf */
210		nand_bcm_umi_bch_enable_write_hwecc();
211		bcm_umi_nand_write_buf(mtd, datap, eccsize);
212		nand_bcm_umi_bch_write_oobEcc(mtd->writesize, oobp,
213					      NAND_ECC_NUM_BYTES);
214	}
215
216	bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
217}