blob: 459904d81c21a2356e353c642ef065151006c257 [file] [log] [blame]
Dirk Behme778933f2008-12-14 09:47:16 +01001/*
2 * (C) Copyright 2004-2008 Texas Instruments, <www.ti.com>
3 * Rohit Choraria <rohitkc@ti.com>
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
Dirk Behme778933f2008-12-14 09:47:16 +01006 */
7
8#include <common.h>
9#include <asm/io.h>
10#include <asm/errno.h>
11#include <asm/arch/mem.h>
pekon gupta5bbb0992013-11-22 16:53:29 +053012#include <linux/mtd/omap_gpmc.h>
Dirk Behme778933f2008-12-14 09:47:16 +010013#include <linux/mtd/nand_ecc.h>
Andreas Bießmann82a65472013-04-05 04:55:21 +000014#include <linux/bch.h>
Stefano Babicaade5792012-03-21 23:56:17 +000015#include <linux/compiler.h>
Dirk Behme778933f2008-12-14 09:47:16 +010016#include <nand.h>
pekon gupta7295fe82013-11-22 16:53:30 +053017#include <linux/mtd/omap_elm.h>
pekon gupta6bd91a82013-11-18 19:03:00 +053018
19#define BADBLOCK_MARKER_LENGTH 2
20#define SECTOR_BYTES 512
pekon guptaeff10ee2013-11-19 11:02:15 +053021#define ECCCLEAR (0x1 << 8)
22#define ECCRESULTREG1 (0x1 << 0)
pekon guptab0f750a2013-11-19 11:02:17 +053023/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
24#define BCH4_BIT_PAD 4
25
pekon gupta03742c92013-11-19 11:02:16 +053026#ifdef CONFIG_BCH
27static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
28 0x97, 0x79, 0xe5, 0x24, 0xb5};
29#endif
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020030static uint8_t cs_next;
pekon gupta6bd91a82013-11-18 19:03:00 +053031static __maybe_unused struct nand_ecclayout omap_ecclayout;
Dirk Behme778933f2008-12-14 09:47:16 +010032
33/*
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020034 * Driver configurations
35 */
36struct omap_nand_info {
37 struct bch_control *control;
38 enum omap_ecc ecc_scheme;
39 int cs;
40};
41
42/* We are wasting a bit of memory but al least we are safe */
43static struct omap_nand_info omap_nand_info[GPMC_MAX_CS];
44
45/*
Dirk Behme778933f2008-12-14 09:47:16 +010046 * omap_nand_hwcontrol - Set the address pointers corretly for the
47 * following address/data/command operation
48 */
49static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
50 uint32_t ctrl)
51{
52 register struct nand_chip *this = mtd->priv;
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020053 struct omap_nand_info *info = this->priv;
54 int cs = info->cs;
Dirk Behme778933f2008-12-14 09:47:16 +010055
56 /*
57 * Point the IO_ADDR to DATA and ADDRESS registers instead
58 * of chip address
59 */
60 switch (ctrl) {
61 case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
Dirk Behmea4becd62009-08-08 09:30:22 +020062 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Dirk Behme778933f2008-12-14 09:47:16 +010063 break;
64 case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
Dirk Behmea4becd62009-08-08 09:30:22 +020065 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
Dirk Behme778933f2008-12-14 09:47:16 +010066 break;
67 case NAND_CTRL_CHANGE | NAND_NCE:
Dirk Behmea4becd62009-08-08 09:30:22 +020068 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
Dirk Behme778933f2008-12-14 09:47:16 +010069 break;
70 }
71
72 if (cmd != NAND_CMD_NONE)
73 writeb(cmd, this->IO_ADDR_W);
74}
75
Simon Schwarz4f62e982011-09-14 15:30:16 -040076/* Check wait pin as dev ready indicator */
Stefan Roesee05972f2014-11-13 03:43:39 +010077static int omap_dev_ready(struct mtd_info *mtd)
Simon Schwarz4f62e982011-09-14 15:30:16 -040078{
79 return gpmc_cfg->status & (1 << 8);
80}
Dirk Behme778933f2008-12-14 09:47:16 +010081
82/*
83 * gen_true_ecc - This function will generate true ECC value, which
84 * can be used when correcting data read from NAND flash memory core
85 *
86 * @ecc_buf: buffer to store ecc code
87 *
88 * @return: re-formatted ECC value
89 */
90static uint32_t gen_true_ecc(uint8_t *ecc_buf)
91{
92 return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
93 ((ecc_buf[2] & 0x0F) << 8);
94}
95
96/*
97 * omap_correct_data - Compares the ecc read from nand spare area with ECC
98 * registers values and corrects one bit error if it has occured
99 * Further details can be had from OMAP TRM and the following selected links:
100 * http://en.wikipedia.org/wiki/Hamming_code
101 * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf
102 *
103 * @mtd: MTD device structure
104 * @dat: page data
105 * @read_ecc: ecc read from nand flash
106 * @calc_ecc: ecc read from ECC registers
107 *
108 * @return 0 if data is OK or corrected, else returns -1
109 */
Stefano Babicaade5792012-03-21 23:56:17 +0000110static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
Dirk Behme778933f2008-12-14 09:47:16 +0100111 uint8_t *read_ecc, uint8_t *calc_ecc)
112{
113 uint32_t orig_ecc, new_ecc, res, hm;
114 uint16_t parity_bits, byte;
115 uint8_t bit;
116
117 /* Regenerate the orginal ECC */
118 orig_ecc = gen_true_ecc(read_ecc);
119 new_ecc = gen_true_ecc(calc_ecc);
120 /* Get the XOR of real ecc */
121 res = orig_ecc ^ new_ecc;
122 if (res) {
123 /* Get the hamming width */
124 hm = hweight32(res);
125 /* Single bit errors can be corrected! */
126 if (hm == 12) {
127 /* Correctable data! */
128 parity_bits = res >> 16;
129 bit = (parity_bits & 0x7);
130 byte = (parity_bits >> 3) & 0x1FF;
131 /* Flip the bit to correct */
132 dat[byte] ^= (0x1 << bit);
133 } else if (hm == 1) {
134 printf("Error: Ecc is wrong\n");
135 /* ECC itself is corrupted */
136 return 2;
137 } else {
138 /*
139 * hm distance != parity pairs OR one, could mean 2 bit
140 * error OR potentially be on a blank page..
141 * orig_ecc: contains spare area data from nand flash.
142 * new_ecc: generated ecc while reading data area.
143 * Note: if the ecc = 0, all data bits from which it was
144 * generated are 0xFF.
145 * The 3 byte(24 bits) ecc is generated per 512byte
146 * chunk of a page. If orig_ecc(from spare area)
147 * is 0xFF && new_ecc(computed now from data area)=0x0,
148 * this means that data area is 0xFF and spare area is
149 * 0xFF. A sure sign of a erased page!
150 */
151 if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000))
152 return 0;
153 printf("Error: Bad compare! failed\n");
154 /* detected 2 bit error */
155 return -1;
156 }
157 }
158 return 0;
159}
160
161/*
pekon guptaeff10ee2013-11-19 11:02:15 +0530162 * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write
Andreas Bießmann82a65472013-04-05 04:55:21 +0000163 * @mtd: MTD device structure
164 * @mode: Read/Write mode
165 */
166__maybe_unused
pekon guptaeff10ee2013-11-19 11:02:15 +0530167static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
Andreas Bießmann82a65472013-04-05 04:55:21 +0000168{
pekon guptaeff10ee2013-11-19 11:02:15 +0530169 struct nand_chip *nand = mtd->priv;
pekon guptaaa168482014-04-11 12:55:33 +0530170 struct omap_nand_info *info = nand->priv;
pekon guptaeff10ee2013-11-19 11:02:15 +0530171 unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0;
172 unsigned int ecc_algo = 0;
173 unsigned int bch_type = 0;
174 unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00;
175 u32 ecc_size_config_val = 0;
176 u32 ecc_config_val = 0;
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +0200177 int cs = info->cs;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000178
pekon guptaeff10ee2013-11-19 11:02:15 +0530179 /* configure GPMC for specific ecc-scheme */
pekon guptaaa168482014-04-11 12:55:33 +0530180 switch (info->ecc_scheme) {
pekon guptaeff10ee2013-11-19 11:02:15 +0530181 case OMAP_ECC_HAM1_CODE_SW:
182 return;
183 case OMAP_ECC_HAM1_CODE_HW:
184 ecc_algo = 0x0;
185 bch_type = 0x0;
186 bch_wrapmode = 0x00;
187 eccsize0 = 0xFF;
188 eccsize1 = 0xFF;
189 break;
190 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
191 case OMAP_ECC_BCH8_CODE_HW:
192 ecc_algo = 0x1;
193 bch_type = 0x1;
194 if (mode == NAND_ECC_WRITE) {
195 bch_wrapmode = 0x01;
196 eccsize0 = 0; /* extra bits in nibbles per sector */
197 eccsize1 = 28; /* OOB bits in nibbles per sector */
198 } else {
199 bch_wrapmode = 0x01;
200 eccsize0 = 26; /* ECC bits in nibbles per sector */
201 eccsize1 = 2; /* non-ECC bits in nibbles per sector */
Stefan Roese7a12cc62013-12-05 07:58:06 +0100202 }
pekon guptaeff10ee2013-11-19 11:02:15 +0530203 break;
pekon gupta046cf862014-06-02 17:14:42 +0530204 case OMAP_ECC_BCH16_CODE_HW:
205 ecc_algo = 0x1;
206 bch_type = 0x2;
207 if (mode == NAND_ECC_WRITE) {
208 bch_wrapmode = 0x01;
209 eccsize0 = 0; /* extra bits in nibbles per sector */
210 eccsize1 = 52; /* OOB bits in nibbles per sector */
211 } else {
212 bch_wrapmode = 0x01;
213 eccsize0 = 52; /* ECC bits in nibbles per sector */
214 eccsize1 = 0; /* non-ECC bits in nibbles per sector */
215 }
216 break;
pekon guptaeff10ee2013-11-19 11:02:15 +0530217 default:
218 return;
pekon gupta6bd91a82013-11-18 19:03:00 +0530219 }
pekon guptaeff10ee2013-11-19 11:02:15 +0530220 /* Clear ecc and enable bits */
221 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
222 /* Configure ecc size for BCH */
223 ecc_size_config_val = (eccsize1 << 22) | (eccsize0 << 12);
224 writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000225
pekon guptaeff10ee2013-11-19 11:02:15 +0530226 /* Configure device details for BCH engine */
227 ecc_config_val = ((ecc_algo << 16) | /* HAM1 | BCHx */
228 (bch_type << 12) | /* BCH4/BCH8/BCH16 */
229 (bch_wrapmode << 8) | /* wrap mode */
230 (dev_width << 7) | /* bus width */
231 (0x0 << 4) | /* number of sectors */
232 (cs << 1) | /* ECC CS */
233 (0x1)); /* enable ECC */
234 writel(ecc_config_val, &gpmc_cfg->ecc_config);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000235}
236
237/*
pekon gupta03742c92013-11-19 11:02:16 +0530238 * omap_calculate_ecc - Read ECC result
239 * @mtd: MTD structure
240 * @dat: unused
241 * @ecc_code: ecc_code buffer
242 * Using noninverted ECC can be considered ugly since writing a blank
243 * page ie. padding will clear the ECC bytes. This is no problem as
244 * long nobody is trying to write data on the seemingly unused page.
245 * Reading an erased page will produce an ECC mismatch between
246 * generated and read ECC bytes that has to be dealt with separately.
247 * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
248 * is used, the result of read will be 0x0 while the ECC offsets of the
249 * spare area will be 0xFF which will result in an ECC mismatch.
Mansoor Ahamede5612512012-11-06 13:06:33 +0000250 */
pekon gupta03742c92013-11-19 11:02:16 +0530251static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
Mansoor Ahamede5612512012-11-06 13:06:33 +0000252 uint8_t *ecc_code)
253{
pekon gupta03742c92013-11-19 11:02:16 +0530254 struct nand_chip *chip = mtd->priv;
pekon guptaaa168482014-04-11 12:55:33 +0530255 struct omap_nand_info *info = chip->priv;
pekon gupta03742c92013-11-19 11:02:16 +0530256 uint32_t *ptr, val = 0;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000257 int8_t i = 0, j;
258
pekon guptaaa168482014-04-11 12:55:33 +0530259 switch (info->ecc_scheme) {
pekon gupta03742c92013-11-19 11:02:16 +0530260 case OMAP_ECC_HAM1_CODE_HW:
261 val = readl(&gpmc_cfg->ecc1_result);
262 ecc_code[0] = val & 0xFF;
263 ecc_code[1] = (val >> 16) & 0xFF;
264 ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
265 break;
266#ifdef CONFIG_BCH
267 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
268#endif
269 case OMAP_ECC_BCH8_CODE_HW:
Mansoor Ahamede5612512012-11-06 13:06:33 +0000270 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
pekon gupta03742c92013-11-19 11:02:16 +0530271 val = readl(ptr);
272 ecc_code[i++] = (val >> 0) & 0xFF;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000273 ptr--;
274 for (j = 0; j < 3; j++) {
pekon gupta03742c92013-11-19 11:02:16 +0530275 val = readl(ptr);
276 ecc_code[i++] = (val >> 24) & 0xFF;
277 ecc_code[i++] = (val >> 16) & 0xFF;
278 ecc_code[i++] = (val >> 8) & 0xFF;
279 ecc_code[i++] = (val >> 0) & 0xFF;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000280 ptr--;
281 }
pekon gupta03742c92013-11-19 11:02:16 +0530282 break;
pekon gupta046cf862014-06-02 17:14:42 +0530283 case OMAP_ECC_BCH16_CODE_HW:
284 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]);
285 ecc_code[i++] = (val >> 8) & 0xFF;
286 ecc_code[i++] = (val >> 0) & 0xFF;
287 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]);
288 ecc_code[i++] = (val >> 24) & 0xFF;
289 ecc_code[i++] = (val >> 16) & 0xFF;
290 ecc_code[i++] = (val >> 8) & 0xFF;
291 ecc_code[i++] = (val >> 0) & 0xFF;
292 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]);
293 ecc_code[i++] = (val >> 24) & 0xFF;
294 ecc_code[i++] = (val >> 16) & 0xFF;
295 ecc_code[i++] = (val >> 8) & 0xFF;
296 ecc_code[i++] = (val >> 0) & 0xFF;
297 for (j = 3; j >= 0; j--) {
298 val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j]
299 );
300 ecc_code[i++] = (val >> 24) & 0xFF;
301 ecc_code[i++] = (val >> 16) & 0xFF;
302 ecc_code[i++] = (val >> 8) & 0xFF;
303 ecc_code[i++] = (val >> 0) & 0xFF;
304 }
305 break;
pekon gupta03742c92013-11-19 11:02:16 +0530306 default:
307 return -EINVAL;
308 }
309 /* ECC scheme specific syndrome customizations */
pekon guptaaa168482014-04-11 12:55:33 +0530310 switch (info->ecc_scheme) {
pekon gupta03742c92013-11-19 11:02:16 +0530311 case OMAP_ECC_HAM1_CODE_HW:
312 break;
313#ifdef CONFIG_BCH
314 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
315
316 for (i = 0; i < chip->ecc.bytes; i++)
317 *(ecc_code + i) = *(ecc_code + i) ^
318 bch8_polynomial[i];
319 break;
320#endif
321 case OMAP_ECC_BCH8_CODE_HW:
322 ecc_code[chip->ecc.bytes - 1] = 0x00;
323 break;
pekon gupta046cf862014-06-02 17:14:42 +0530324 case OMAP_ECC_BCH16_CODE_HW:
325 break;
pekon gupta03742c92013-11-19 11:02:16 +0530326 default:
327 return -EINVAL;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000328 }
pekon gupta03742c92013-11-19 11:02:16 +0530329 return 0;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000330}
331
pekon gupta03742c92013-11-19 11:02:16 +0530332#ifdef CONFIG_NAND_OMAP_ELM
Mansoor Ahamede5612512012-11-06 13:06:33 +0000333/*
Jeroen Hofstee79369072014-10-08 22:57:42 +0200334 * omap_reverse_list - re-orders list elements in reverse order [internal]
335 * @list: pointer to start of list
336 * @length: length of list
337*/
338static void omap_reverse_list(u8 *list, unsigned int length)
339{
340 unsigned int i, j;
341 unsigned int half_length = length / 2;
342 u8 tmp;
343 for (i = 0, j = length - 1; i < half_length; i++, j--) {
344 tmp = list[i];
345 list[i] = list[j];
346 list[j] = tmp;
347 }
348}
349
350/*
Mansoor Ahamede5612512012-11-06 13:06:33 +0000351 * omap_correct_data_bch - Compares the ecc read from nand spare area
352 * with ECC registers values and corrects one bit error if it has occured
353 *
354 * @mtd: MTD device structure
355 * @dat: page data
356 * @read_ecc: ecc read from nand flash (ignored)
357 * @calc_ecc: ecc read from ECC registers
358 *
359 * @return 0 if data is OK or corrected, else returns -1
360 */
361static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
362 uint8_t *read_ecc, uint8_t *calc_ecc)
363{
364 struct nand_chip *chip = mtd->priv;
pekon guptaaa168482014-04-11 12:55:33 +0530365 struct omap_nand_info *info = chip->priv;
pekon gupta3c43c5b2014-04-11 12:55:34 +0530366 struct nand_ecc_ctrl *ecc = &chip->ecc;
pekon guptab0f750a2013-11-19 11:02:17 +0530367 uint32_t error_count = 0, error_max;
pekon gupta046cf862014-06-02 17:14:42 +0530368 uint32_t error_loc[ELM_MAX_ERROR_COUNT];
pekon gupta9d4b7472014-04-11 12:55:32 +0530369 enum bch_level bch_type;
pekon guptab0f750a2013-11-19 11:02:17 +0530370 uint32_t i, ecc_flag = 0;
Guido Martínez20b27be2015-01-02 14:49:10 -0300371 uint8_t count;
pekon guptab0f750a2013-11-19 11:02:17 +0530372 uint32_t byte_pos, bit_pos;
Guido Martínez20b27be2015-01-02 14:49:10 -0300373 int err = 0;
pekon guptab0f750a2013-11-19 11:02:17 +0530374
375 /* check calculated ecc */
pekon gupta3c43c5b2014-04-11 12:55:34 +0530376 for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
pekon guptab0f750a2013-11-19 11:02:17 +0530377 if (calc_ecc[i] != 0x00)
378 ecc_flag = 1;
379 }
380 if (!ecc_flag)
381 return 0;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000382
pekon guptab0f750a2013-11-19 11:02:17 +0530383 /* check for whether its a erased-page */
Mansoor Ahamede5612512012-11-06 13:06:33 +0000384 ecc_flag = 0;
pekon gupta3c43c5b2014-04-11 12:55:34 +0530385 for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
Mansoor Ahamede5612512012-11-06 13:06:33 +0000386 if (read_ecc[i] != 0xff)
387 ecc_flag = 1;
pekon guptab0f750a2013-11-19 11:02:17 +0530388 }
Mansoor Ahamede5612512012-11-06 13:06:33 +0000389 if (!ecc_flag)
390 return 0;
391
Mansoor Ahamede5612512012-11-06 13:06:33 +0000392 /*
393 * while reading ECC result we read it in big endian.
394 * Hence while loading to ELM we have rotate to get the right endian.
395 */
pekon guptaaa168482014-04-11 12:55:33 +0530396 switch (info->ecc_scheme) {
pekon guptab0f750a2013-11-19 11:02:17 +0530397 case OMAP_ECC_BCH8_CODE_HW:
pekon gupta9d4b7472014-04-11 12:55:32 +0530398 bch_type = BCH_8_BIT;
pekon gupta3c43c5b2014-04-11 12:55:34 +0530399 omap_reverse_list(calc_ecc, ecc->bytes - 1);
pekon guptab0f750a2013-11-19 11:02:17 +0530400 break;
pekon gupta046cf862014-06-02 17:14:42 +0530401 case OMAP_ECC_BCH16_CODE_HW:
402 bch_type = BCH_16_BIT;
403 omap_reverse_list(calc_ecc, ecc->bytes);
404 break;
pekon guptab0f750a2013-11-19 11:02:17 +0530405 default:
406 return -EINVAL;
407 }
Mansoor Ahamede5612512012-11-06 13:06:33 +0000408 /* use elm module to check for errors */
pekon gupta9d4b7472014-04-11 12:55:32 +0530409 elm_config(bch_type);
pekon guptacfe6b8a2014-04-11 12:55:35 +0530410 err = elm_check_error(calc_ecc, bch_type, &error_count, error_loc);
411 if (err)
412 return err;
413
Mansoor Ahamede5612512012-11-06 13:06:33 +0000414 /* correct bch error */
pekon guptab0f750a2013-11-19 11:02:17 +0530415 for (count = 0; count < error_count; count++) {
pekon guptaaa168482014-04-11 12:55:33 +0530416 switch (info->ecc_scheme) {
pekon gupta9d4b7472014-04-11 12:55:32 +0530417 case OMAP_ECC_BCH8_CODE_HW:
pekon guptab0f750a2013-11-19 11:02:17 +0530418 /* 14th byte in ECC is reserved to match ROM layout */
pekon gupta3c43c5b2014-04-11 12:55:34 +0530419 error_max = SECTOR_BYTES + (ecc->bytes - 1);
pekon guptab0f750a2013-11-19 11:02:17 +0530420 break;
pekon gupta046cf862014-06-02 17:14:42 +0530421 case OMAP_ECC_BCH16_CODE_HW:
422 error_max = SECTOR_BYTES + ecc->bytes;
423 break;
pekon guptab0f750a2013-11-19 11:02:17 +0530424 default:
425 return -EINVAL;
426 }
427 byte_pos = error_max - (error_loc[count] / 8) - 1;
428 bit_pos = error_loc[count] % 8;
429 if (byte_pos < SECTOR_BYTES) {
430 dat[byte_pos] ^= 1 << bit_pos;
431 printf("nand: bit-flip corrected @data=%d\n", byte_pos);
432 } else if (byte_pos < error_max) {
Belisko Marek9ab54142014-04-25 12:00:07 +0200433 read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos;
pekon guptab0f750a2013-11-19 11:02:17 +0530434 printf("nand: bit-flip corrected @oob=%d\n", byte_pos -
435 SECTOR_BYTES);
436 } else {
437 err = -EBADMSG;
438 printf("nand: error: invalid bit-flip location\n");
439 }
440 }
441 return (err) ? err : error_count;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000442}
Mansoor Ahamede5612512012-11-06 13:06:33 +0000443
444/**
445 * omap_read_page_bch - hardware ecc based page read function
446 * @mtd: mtd info structure
447 * @chip: nand chip info structure
448 * @buf: buffer to store read data
Sergey Lapin3a38a552013-01-14 03:46:50 +0000449 * @oob_required: caller expects OOB data read to chip->oob_poi
Mansoor Ahamede5612512012-11-06 13:06:33 +0000450 * @page: page number to read
451 *
452 */
453static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
Sergey Lapin3a38a552013-01-14 03:46:50 +0000454 uint8_t *buf, int oob_required, int page)
Mansoor Ahamede5612512012-11-06 13:06:33 +0000455{
456 int i, eccsize = chip->ecc.size;
457 int eccbytes = chip->ecc.bytes;
458 int eccsteps = chip->ecc.steps;
459 uint8_t *p = buf;
460 uint8_t *ecc_calc = chip->buffers->ecccalc;
461 uint8_t *ecc_code = chip->buffers->ecccode;
462 uint32_t *eccpos = chip->ecc.layout->eccpos;
463 uint8_t *oob = chip->oob_poi;
464 uint32_t data_pos;
465 uint32_t oob_pos;
466
467 data_pos = 0;
468 /* oob area start */
469 oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
470 oob += chip->ecc.layout->eccpos[0];
471
472 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
473 oob += eccbytes) {
474 chip->ecc.hwctl(mtd, NAND_ECC_READ);
475 /* read data */
Rostislav Lisovya9ee70a2014-09-02 17:00:30 +0200476 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1);
Mansoor Ahamede5612512012-11-06 13:06:33 +0000477 chip->read_buf(mtd, p, eccsize);
478
479 /* read respective ecc from oob area */
Rostislav Lisovya9ee70a2014-09-02 17:00:30 +0200480 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
Mansoor Ahamede5612512012-11-06 13:06:33 +0000481 chip->read_buf(mtd, oob, eccbytes);
482 /* read syndrome */
483 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
484
485 data_pos += eccsize;
486 oob_pos += eccbytes;
487 }
488
489 for (i = 0; i < chip->ecc.total; i++)
490 ecc_code[i] = chip->oob_poi[eccpos[i]];
491
492 eccsteps = chip->ecc.steps;
493 p = buf;
494
495 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
496 int stat;
497
498 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
499 if (stat < 0)
500 mtd->ecc_stats.failed++;
501 else
502 mtd->ecc_stats.corrected += stat;
503 }
504 return 0;
505}
pekon gupta6bd91a82013-11-18 19:03:00 +0530506#endif /* CONFIG_NAND_OMAP_ELM */
Mansoor Ahamede5612512012-11-06 13:06:33 +0000507
Andreas Bießmann82a65472013-04-05 04:55:21 +0000508/*
509 * OMAP3 BCH8 support (with BCH library)
510 */
pekon gupta6bd91a82013-11-18 19:03:00 +0530511#ifdef CONFIG_BCH
Andreas Bießmann82a65472013-04-05 04:55:21 +0000512/**
pekon gupta6bd91a82013-11-18 19:03:00 +0530513 * omap_correct_data_bch_sw - Decode received data and correct errors
Andreas Bießmann82a65472013-04-05 04:55:21 +0000514 * @mtd: MTD device structure
515 * @data: page data
516 * @read_ecc: ecc read from nand flash
517 * @calc_ecc: ecc read from HW ECC registers
518 */
pekon gupta6bd91a82013-11-18 19:03:00 +0530519static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data,
Andreas Bießmann82a65472013-04-05 04:55:21 +0000520 u_char *read_ecc, u_char *calc_ecc)
521{
522 int i, count;
523 /* cannot correct more than 8 errors */
524 unsigned int errloc[8];
525 struct nand_chip *chip = mtd->priv;
pekon guptaaa168482014-04-11 12:55:33 +0530526 struct omap_nand_info *info = chip->priv;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000527
pekon guptaaa168482014-04-11 12:55:33 +0530528 count = decode_bch(info->control, NULL, 512, read_ecc, calc_ecc,
529 NULL, errloc);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000530 if (count > 0) {
531 /* correct errors */
532 for (i = 0; i < count; i++) {
533 /* correct data only, not ecc bytes */
534 if (errloc[i] < 8*512)
535 data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
536 printf("corrected bitflip %u\n", errloc[i]);
537#ifdef DEBUG
538 puts("read_ecc: ");
539 /*
540 * BCH8 have 13 bytes of ECC; BCH4 needs adoption
541 * here!
542 */
543 for (i = 0; i < 13; i++)
544 printf("%02x ", read_ecc[i]);
545 puts("\n");
546 puts("calc_ecc: ");
547 for (i = 0; i < 13; i++)
548 printf("%02x ", calc_ecc[i]);
549 puts("\n");
550#endif
551 }
552 } else if (count < 0) {
553 puts("ecc unrecoverable error\n");
554 }
555 return count;
556}
557
558/**
559 * omap_free_bch - Release BCH ecc resources
560 * @mtd: MTD device structure
561 */
562static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
563{
564 struct nand_chip *chip = mtd->priv;
pekon guptaaa168482014-04-11 12:55:33 +0530565 struct omap_nand_info *info = chip->priv;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000566
pekon guptaaa168482014-04-11 12:55:33 +0530567 if (info->control) {
568 free_bch(info->control);
569 info->control = NULL;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000570 }
571}
pekon gupta6bd91a82013-11-18 19:03:00 +0530572#endif /* CONFIG_BCH */
573
574/**
575 * omap_select_ecc_scheme - configures driver for particular ecc-scheme
576 * @nand: NAND chip device structure
577 * @ecc_scheme: ecc scheme to configure
578 * @pagesize: number of main-area bytes per page of NAND device
579 * @oobsize: number of OOB/spare bytes per page of NAND device
580 */
581static int omap_select_ecc_scheme(struct nand_chip *nand,
582 enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
pekon guptaaa168482014-04-11 12:55:33 +0530583 struct omap_nand_info *info = nand->priv;
Nikita Kiryanove8167892013-12-16 19:19:01 +0200584 struct nand_ecclayout *ecclayout = &omap_ecclayout;
pekon gupta6bd91a82013-11-18 19:03:00 +0530585 int eccsteps = pagesize / SECTOR_BYTES;
586 int i;
587
588 switch (ecc_scheme) {
589 case OMAP_ECC_HAM1_CODE_SW:
590 debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n");
591 /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are
592 * initialized in nand_scan_tail(), so just set ecc.mode */
pekon guptaaa168482014-04-11 12:55:33 +0530593 info->control = NULL;
pekon gupta6bd91a82013-11-18 19:03:00 +0530594 nand->ecc.mode = NAND_ECC_SOFT;
595 nand->ecc.layout = NULL;
Nikita Kiryanov4110c822013-12-12 15:19:31 +0200596 nand->ecc.size = 0;
pekon gupta6bd91a82013-11-18 19:03:00 +0530597 break;
598
599 case OMAP_ECC_HAM1_CODE_HW:
600 debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n");
601 /* check ecc-scheme requirements before updating ecc info */
602 if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
603 printf("nand: error: insufficient OOB: require=%d\n", (
604 (3 * eccsteps) + BADBLOCK_MARKER_LENGTH));
605 return -EINVAL;
606 }
pekon guptaaa168482014-04-11 12:55:33 +0530607 info->control = NULL;
pekon gupta6bd91a82013-11-18 19:03:00 +0530608 /* populate ecc specific fields */
Nikita Kiryanov2e18ff22013-12-17 15:18:01 +0200609 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
pekon gupta6bd91a82013-11-18 19:03:00 +0530610 nand->ecc.mode = NAND_ECC_HW;
611 nand->ecc.strength = 1;
612 nand->ecc.size = SECTOR_BYTES;
613 nand->ecc.bytes = 3;
614 nand->ecc.hwctl = omap_enable_hwecc;
615 nand->ecc.correct = omap_correct_data;
616 nand->ecc.calculate = omap_calculate_ecc;
617 /* define ecc-layout */
618 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
pekon guptaf0aff022013-12-05 17:54:21 +0530619 for (i = 0; i < ecclayout->eccbytes; i++) {
620 if (nand->options & NAND_BUSWIDTH_16)
621 ecclayout->eccpos[i] = i + 2;
622 else
623 ecclayout->eccpos[i] = i + 1;
624 }
pekon gupta6bd91a82013-11-18 19:03:00 +0530625 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
626 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
627 BADBLOCK_MARKER_LENGTH;
pekon gupta6bd91a82013-11-18 19:03:00 +0530628 break;
629
630 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
631#ifdef CONFIG_BCH
632 debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
633 /* check ecc-scheme requirements before updating ecc info */
634 if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
635 printf("nand: error: insufficient OOB: require=%d\n", (
636 (13 * eccsteps) + BADBLOCK_MARKER_LENGTH));
637 return -EINVAL;
638 }
639 /* check if BCH S/W library can be used for error detection */
pekon guptaaa168482014-04-11 12:55:33 +0530640 info->control = init_bch(13, 8, 0x201b);
641 if (!info->control) {
pekon gupta6bd91a82013-11-18 19:03:00 +0530642 printf("nand: error: could not init_bch()\n");
643 return -ENODEV;
644 }
pekon gupta6bd91a82013-11-18 19:03:00 +0530645 /* populate ecc specific fields */
Nikita Kiryanov2e18ff22013-12-17 15:18:01 +0200646 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
pekon gupta6bd91a82013-11-18 19:03:00 +0530647 nand->ecc.mode = NAND_ECC_HW;
648 nand->ecc.strength = 8;
649 nand->ecc.size = SECTOR_BYTES;
650 nand->ecc.bytes = 13;
pekon guptaeff10ee2013-11-19 11:02:15 +0530651 nand->ecc.hwctl = omap_enable_hwecc;
pekon gupta6bd91a82013-11-18 19:03:00 +0530652 nand->ecc.correct = omap_correct_data_bch_sw;
pekon gupta03742c92013-11-19 11:02:16 +0530653 nand->ecc.calculate = omap_calculate_ecc;
pekon gupta6bd91a82013-11-18 19:03:00 +0530654 /* define ecc-layout */
655 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
656 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
657 for (i = 1; i < ecclayout->eccbytes; i++) {
658 if (i % nand->ecc.bytes)
659 ecclayout->eccpos[i] =
660 ecclayout->eccpos[i - 1] + 1;
661 else
662 ecclayout->eccpos[i] =
663 ecclayout->eccpos[i - 1] + 2;
664 }
665 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
666 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
667 BADBLOCK_MARKER_LENGTH;
pekon gupta6bd91a82013-11-18 19:03:00 +0530668 break;
669#else
670 printf("nand: error: CONFIG_BCH required for ECC\n");
671 return -EINVAL;
672#endif
673
674 case OMAP_ECC_BCH8_CODE_HW:
675#ifdef CONFIG_NAND_OMAP_ELM
676 debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n");
677 /* check ecc-scheme requirements before updating ecc info */
678 if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
679 printf("nand: error: insufficient OOB: require=%d\n", (
680 (14 * eccsteps) + BADBLOCK_MARKER_LENGTH));
681 return -EINVAL;
682 }
683 /* intialize ELM for ECC error detection */
684 elm_init();
pekon guptaaa168482014-04-11 12:55:33 +0530685 info->control = NULL;
pekon gupta6bd91a82013-11-18 19:03:00 +0530686 /* populate ecc specific fields */
Nikita Kiryanov2e18ff22013-12-17 15:18:01 +0200687 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
pekon gupta6bd91a82013-11-18 19:03:00 +0530688 nand->ecc.mode = NAND_ECC_HW;
689 nand->ecc.strength = 8;
690 nand->ecc.size = SECTOR_BYTES;
691 nand->ecc.bytes = 14;
pekon guptaeff10ee2013-11-19 11:02:15 +0530692 nand->ecc.hwctl = omap_enable_hwecc;
pekon gupta6bd91a82013-11-18 19:03:00 +0530693 nand->ecc.correct = omap_correct_data_bch;
pekon gupta03742c92013-11-19 11:02:16 +0530694 nand->ecc.calculate = omap_calculate_ecc;
pekon gupta6bd91a82013-11-18 19:03:00 +0530695 nand->ecc.read_page = omap_read_page_bch;
696 /* define ecc-layout */
697 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
698 for (i = 0; i < ecclayout->eccbytes; i++)
699 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
700 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
701 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
702 BADBLOCK_MARKER_LENGTH;
pekon gupta6bd91a82013-11-18 19:03:00 +0530703 break;
704#else
705 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
706 return -EINVAL;
707#endif
708
pekon gupta046cf862014-06-02 17:14:42 +0530709 case OMAP_ECC_BCH16_CODE_HW:
710#ifdef CONFIG_NAND_OMAP_ELM
711 debug("nand: using OMAP_ECC_BCH16_CODE_HW\n");
712 /* check ecc-scheme requirements before updating ecc info */
713 if ((26 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
714 printf("nand: error: insufficient OOB: require=%d\n", (
715 (26 * eccsteps) + BADBLOCK_MARKER_LENGTH));
716 return -EINVAL;
717 }
718 /* intialize ELM for ECC error detection */
719 elm_init();
720 /* populate ecc specific fields */
721 nand->ecc.mode = NAND_ECC_HW;
722 nand->ecc.size = SECTOR_BYTES;
723 nand->ecc.bytes = 26;
724 nand->ecc.strength = 16;
725 nand->ecc.hwctl = omap_enable_hwecc;
726 nand->ecc.correct = omap_correct_data_bch;
727 nand->ecc.calculate = omap_calculate_ecc;
728 nand->ecc.read_page = omap_read_page_bch;
729 /* define ecc-layout */
730 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
731 for (i = 0; i < ecclayout->eccbytes; i++)
732 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
733 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
734 ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes -
735 BADBLOCK_MARKER_LENGTH;
736 break;
737#else
738 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
739 return -EINVAL;
740#endif
pekon gupta6bd91a82013-11-18 19:03:00 +0530741 default:
742 debug("nand: error: ecc scheme not enabled or supported\n");
743 return -EINVAL;
744 }
Nikita Kiryanove8167892013-12-16 19:19:01 +0200745
746 /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */
747 if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW)
748 nand->ecc.layout = ecclayout;
749
pekon guptaaa168482014-04-11 12:55:33 +0530750 info->ecc_scheme = ecc_scheme;
pekon gupta6bd91a82013-11-18 19:03:00 +0530751 return 0;
752}
Andreas Bießmann82a65472013-04-05 04:55:21 +0000753
Simon Schwarz4f62e982011-09-14 15:30:16 -0400754#ifndef CONFIG_SPL_BUILD
Dirk Behme778933f2008-12-14 09:47:16 +0100755/*
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000756 * omap_nand_switch_ecc - switch the ECC operation between different engines
757 * (h/w and s/w) and different algorithms (hamming and BCHx)
Dirk Behme778933f2008-12-14 09:47:16 +0100758 *
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000759 * @hardware - true if one of the HW engines should be used
760 * @eccstrength - the number of bits that could be corrected
761 * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16)
Dirk Behme778933f2008-12-14 09:47:16 +0100762 */
pekon gupta6bd91a82013-11-18 19:03:00 +0530763int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
Dirk Behme778933f2008-12-14 09:47:16 +0100764{
765 struct nand_chip *nand;
766 struct mtd_info *mtd;
pekon gupta6bd91a82013-11-18 19:03:00 +0530767 int err = 0;
Dirk Behme778933f2008-12-14 09:47:16 +0100768
769 if (nand_curr_device < 0 ||
770 nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
771 !nand_info[nand_curr_device].name) {
pekon gupta6bd91a82013-11-18 19:03:00 +0530772 printf("nand: error: no NAND devices found\n");
773 return -ENODEV;
Dirk Behme778933f2008-12-14 09:47:16 +0100774 }
775
776 mtd = &nand_info[nand_curr_device];
777 nand = mtd->priv;
Dirk Behme778933f2008-12-14 09:47:16 +0100778 nand->options |= NAND_OWN_BUFFERS;
Jeroen Hofstee96306f22014-01-15 17:58:54 +0100779 nand->options &= ~NAND_SUBPAGE_READ;
Dirk Behme778933f2008-12-14 09:47:16 +0100780 /* Setup the ecc configurations again */
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000781 if (hardware) {
782 if (eccstrength == 1) {
pekon gupta6bd91a82013-11-18 19:03:00 +0530783 err = omap_select_ecc_scheme(nand,
784 OMAP_ECC_HAM1_CODE_HW,
785 mtd->writesize, mtd->oobsize);
786 } else if (eccstrength == 8) {
787 err = omap_select_ecc_scheme(nand,
788 OMAP_ECC_BCH8_CODE_HW,
789 mtd->writesize, mtd->oobsize);
790 } else {
791 printf("nand: error: unsupported ECC scheme\n");
792 return -EINVAL;
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000793 }
Dirk Behme778933f2008-12-14 09:47:16 +0100794 } else {
pekon gupta6bd91a82013-11-18 19:03:00 +0530795 err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
796 mtd->writesize, mtd->oobsize);
Dirk Behme778933f2008-12-14 09:47:16 +0100797 }
798
799 /* Update NAND handling after ECC mode switch */
pekon gupta6bd91a82013-11-18 19:03:00 +0530800 if (!err)
801 err = nand_scan_tail(mtd);
802 return err;
Dirk Behme778933f2008-12-14 09:47:16 +0100803}
Simon Schwarz4f62e982011-09-14 15:30:16 -0400804#endif /* CONFIG_SPL_BUILD */
Dirk Behme778933f2008-12-14 09:47:16 +0100805
806/*
807 * Board-specific NAND initialization. The following members of the
808 * argument are board-specific:
809 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
810 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
811 * - cmd_ctrl: hardwarespecific function for accesing control-lines
812 * - waitfunc: hardwarespecific function for accesing device ready/busy line
813 * - ecc.hwctl: function to enable (reset) hardware ecc generator
814 * - ecc.mode: mode of ecc, see defines
815 * - chip_delay: chip dependent delay for transfering data from array to
816 * read regs (tR)
817 * - options: various chip options. They can partly be set to inform
818 * nand_scan about special functionality. See the defines for further
819 * explanation
820 */
821int board_nand_init(struct nand_chip *nand)
822{
823 int32_t gpmc_config = 0;
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +0200824 int cs = cs_next++;
pekon gupta6bd91a82013-11-18 19:03:00 +0530825 int err = 0;
Dirk Behme778933f2008-12-14 09:47:16 +0100826 /*
827 * xloader/Uboot's gpmc configuration would have configured GPMC for
828 * nand type of memory. The following logic scans and latches on to the
829 * first CS with NAND type memory.
830 * TBD: need to make this logic generic to handle multiple CS NAND
831 * devices.
832 */
833 while (cs < GPMC_MAX_CS) {
Dirk Behme778933f2008-12-14 09:47:16 +0100834 /* Check if NAND type is set */
Dirk Behmea4becd62009-08-08 09:30:22 +0200835 if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
Dirk Behme778933f2008-12-14 09:47:16 +0100836 /* Found it!! */
837 break;
838 }
839 cs++;
840 }
841 if (cs >= GPMC_MAX_CS) {
pekon gupta6bd91a82013-11-18 19:03:00 +0530842 printf("nand: error: Unable to find NAND settings in "
Dirk Behme778933f2008-12-14 09:47:16 +0100843 "GPMC Configuration - quitting\n");
844 return -ENODEV;
845 }
846
Dirk Behmea4becd62009-08-08 09:30:22 +0200847 gpmc_config = readl(&gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +0100848 /* Disable Write protect */
849 gpmc_config |= 0x10;
Dirk Behmea4becd62009-08-08 09:30:22 +0200850 writel(gpmc_config, &gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +0100851
Dirk Behmea4becd62009-08-08 09:30:22 +0200852 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
853 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +0200854 omap_nand_info[cs].control = NULL;
855 omap_nand_info[cs].cs = cs;
856 nand->priv = &omap_nand_info[cs];
pekon gupta6bd91a82013-11-18 19:03:00 +0530857 nand->cmd_ctrl = omap_nand_hwcontrol;
858 nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
Dirk Behme778933f2008-12-14 09:47:16 +0100859 nand->chip_delay = 100;
pekon gupta6bd91a82013-11-18 19:03:00 +0530860 nand->ecc.layout = &omap_ecclayout;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000861
pekon gupta6250faf2014-05-06 00:46:19 +0530862 /* configure driver and controller based on NAND device bus-width */
863 gpmc_config = readl(&gpmc_cfg->cs[cs].config1);
864#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT)
865 nand->options |= NAND_BUSWIDTH_16;
866 writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1);
867#else
868 nand->options &= ~NAND_BUSWIDTH_16;
869 writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1);
870#endif
pekon gupta6bd91a82013-11-18 19:03:00 +0530871 /* select ECC scheme */
pekon gupta3ef49732013-11-18 19:03:01 +0530872#if defined(CONFIG_NAND_OMAP_ECCSCHEME)
873 err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME,
pekon gupta6bd91a82013-11-18 19:03:00 +0530874 CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
pekon gupta3ef49732013-11-18 19:03:01 +0530875#else
876 /* pagesize and oobsize are not required to configure sw ecc-scheme */
pekon gupta6bd91a82013-11-18 19:03:00 +0530877 err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
878 0, 0);
Mansoor Ahamede5612512012-11-06 13:06:33 +0000879#endif
pekon gupta6bd91a82013-11-18 19:03:00 +0530880 if (err)
881 return err;
Simon Schwarz4f62e982011-09-14 15:30:16 -0400882
Ilya Yanokd7bca052011-11-28 06:37:38 +0000883#ifdef CONFIG_SPL_BUILD
Simon Schwarz4f62e982011-09-14 15:30:16 -0400884 if (nand->options & NAND_BUSWIDTH_16)
885 nand->read_buf = nand_read_buf16;
886 else
887 nand->read_buf = nand_read_buf;
Simon Schwarz4f62e982011-09-14 15:30:16 -0400888#endif
Stefan Roesee05972f2014-11-13 03:43:39 +0100889
890 nand->dev_ready = omap_dev_ready;
891
Dirk Behme778933f2008-12-14 09:47:16 +0100892 return 0;
893}