blob: be3cb3c601b0b3735a147de0d188243728ea65b5 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dirk Behme778933f2008-12-14 09:47:16 +01002/*
3 * (C) Copyright 2004-2008 Texas Instruments, <www.ti.com>
4 * Rohit Choraria <rohitkc@ti.com>
Dirk Behme778933f2008-12-14 09:47:16 +01005 */
6
7#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Dirk Behme778933f2008-12-14 09:47:16 +01009#include <asm/io.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090010#include <linux/errno.h>
Roger Quadros6550c622022-10-11 14:49:59 +030011
12#ifdef CONFIG_ARCH_OMAP2PLUS
Dirk Behme778933f2008-12-14 09:47:16 +010013#include <asm/arch/mem.h>
Roger Quadros6550c622022-10-11 14:49:59 +030014#endif
15
pekon gupta5bbb0992013-11-22 16:53:29 +053016#include <linux/mtd/omap_gpmc.h>
Dirk Behme778933f2008-12-14 09:47:16 +010017#include <linux/mtd/nand_ecc.h>
Tom Rini3bde7e22021-09-22 14:50:35 -040018#include <linux/mtd/rawnand.h>
Andreas Bießmann82a65472013-04-05 04:55:21 +000019#include <linux/bch.h>
Stefano Babicaade5792012-03-21 23:56:17 +000020#include <linux/compiler.h>
Dirk Behme778933f2008-12-14 09:47:16 +010021#include <nand.h>
pekon gupta7295fe82013-11-22 16:53:30 +053022#include <linux/mtd/omap_elm.h>
pekon gupta6bd91a82013-11-18 19:03:00 +053023
Roger Quadros6550c622022-10-11 14:49:59 +030024#ifndef GPMC_MAX_CS
25#define GPMC_MAX_CS 4
26#endif
27
pekon gupta6bd91a82013-11-18 19:03:00 +053028#define BADBLOCK_MARKER_LENGTH 2
29#define SECTOR_BYTES 512
pekon guptaeff10ee2013-11-19 11:02:15 +053030#define ECCCLEAR (0x1 << 8)
31#define ECCRESULTREG1 (0x1 << 0)
pekon guptab0f750a2013-11-19 11:02:17 +053032/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
33#define BCH4_BIT_PAD 4
34
pekon gupta03742c92013-11-19 11:02:16 +053035#ifdef CONFIG_BCH
36static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
37 0x97, 0x79, 0xe5, 0x24, 0xb5};
38#endif
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020039static uint8_t cs_next;
Dirk Behme778933f2008-12-14 09:47:16 +010040
Michal Sojka26160072015-02-17 17:08:37 +010041#if defined(CONFIG_NAND_OMAP_GPMC_WSCFG)
42static const int8_t wscfg[CONFIG_SYS_MAX_NAND_DEVICE] =
43 { CONFIG_NAND_OMAP_GPMC_WSCFG };
44#else
45/* wscfg is preset to zero since its a static variable */
46static const int8_t wscfg[CONFIG_SYS_MAX_NAND_DEVICE];
47#endif
48
Dirk Behme778933f2008-12-14 09:47:16 +010049/*
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020050 * Driver configurations
51 */
52struct omap_nand_info {
53 struct bch_control *control;
54 enum omap_ecc ecc_scheme;
Michal Sojka26160072015-02-17 17:08:37 +010055 uint8_t cs;
56 uint8_t ws; /* wait status pin (0,1) */
Roger Quadros3b7aaa52022-10-11 14:50:02 +030057 void __iomem *fifo;
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020058};
59
60/* We are wasting a bit of memory but al least we are safe */
61static struct omap_nand_info omap_nand_info[GPMC_MAX_CS];
62
63/*
Dirk Behme778933f2008-12-14 09:47:16 +010064 * omap_nand_hwcontrol - Set the address pointers corretly for the
65 * following address/data/command operation
66 */
67static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
68 uint32_t ctrl)
69{
Scott Wood17fed142016-05-30 13:57:56 -050070 register struct nand_chip *this = mtd_to_nand(mtd);
71 struct omap_nand_info *info = nand_get_controller_data(this);
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020072 int cs = info->cs;
Dirk Behme778933f2008-12-14 09:47:16 +010073
74 /*
75 * Point the IO_ADDR to DATA and ADDRESS registers instead
76 * of chip address
77 */
78 switch (ctrl) {
79 case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
Dirk Behmea4becd62009-08-08 09:30:22 +020080 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Dirk Behme778933f2008-12-14 09:47:16 +010081 break;
82 case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
Dirk Behmea4becd62009-08-08 09:30:22 +020083 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
Dirk Behme778933f2008-12-14 09:47:16 +010084 break;
85 case NAND_CTRL_CHANGE | NAND_NCE:
Dirk Behmea4becd62009-08-08 09:30:22 +020086 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
Dirk Behme778933f2008-12-14 09:47:16 +010087 break;
88 }
89
90 if (cmd != NAND_CMD_NONE)
91 writeb(cmd, this->IO_ADDR_W);
92}
93
Simon Schwarz4f62e982011-09-14 15:30:16 -040094/* Check wait pin as dev ready indicator */
Stefan Roesee05972f2014-11-13 03:43:39 +010095static int omap_dev_ready(struct mtd_info *mtd)
Simon Schwarz4f62e982011-09-14 15:30:16 -040096{
Scott Wood17fed142016-05-30 13:57:56 -050097 register struct nand_chip *this = mtd_to_nand(mtd);
98 struct omap_nand_info *info = nand_get_controller_data(this);
Michal Sojka26160072015-02-17 17:08:37 +010099 return gpmc_cfg->status & (1 << (8 + info->ws));
Simon Schwarz4f62e982011-09-14 15:30:16 -0400100}
Dirk Behme778933f2008-12-14 09:47:16 +0100101
102/*
103 * gen_true_ecc - This function will generate true ECC value, which
104 * can be used when correcting data read from NAND flash memory core
105 *
106 * @ecc_buf: buffer to store ecc code
107 *
108 * @return: re-formatted ECC value
109 */
110static uint32_t gen_true_ecc(uint8_t *ecc_buf)
111{
112 return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
113 ((ecc_buf[2] & 0x0F) << 8);
114}
115
116/*
117 * omap_correct_data - Compares the ecc read from nand spare area with ECC
Vagrant Cascadianedfdb992016-04-30 19:18:00 -0700118 * registers values and corrects one bit error if it has occurred
Dirk Behme778933f2008-12-14 09:47:16 +0100119 * Further details can be had from OMAP TRM and the following selected links:
120 * http://en.wikipedia.org/wiki/Hamming_code
121 * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf
122 *
123 * @mtd: MTD device structure
124 * @dat: page data
125 * @read_ecc: ecc read from nand flash
126 * @calc_ecc: ecc read from ECC registers
127 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100128 * Return: 0 if data is OK or corrected, else returns -1
Dirk Behme778933f2008-12-14 09:47:16 +0100129 */
Stefano Babicaade5792012-03-21 23:56:17 +0000130static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
Dirk Behme778933f2008-12-14 09:47:16 +0100131 uint8_t *read_ecc, uint8_t *calc_ecc)
132{
133 uint32_t orig_ecc, new_ecc, res, hm;
134 uint16_t parity_bits, byte;
135 uint8_t bit;
136
137 /* Regenerate the orginal ECC */
138 orig_ecc = gen_true_ecc(read_ecc);
139 new_ecc = gen_true_ecc(calc_ecc);
140 /* Get the XOR of real ecc */
141 res = orig_ecc ^ new_ecc;
142 if (res) {
143 /* Get the hamming width */
144 hm = hweight32(res);
145 /* Single bit errors can be corrected! */
146 if (hm == 12) {
147 /* Correctable data! */
148 parity_bits = res >> 16;
149 bit = (parity_bits & 0x7);
150 byte = (parity_bits >> 3) & 0x1FF;
151 /* Flip the bit to correct */
152 dat[byte] ^= (0x1 << bit);
153 } else if (hm == 1) {
154 printf("Error: Ecc is wrong\n");
155 /* ECC itself is corrupted */
156 return 2;
157 } else {
158 /*
159 * hm distance != parity pairs OR one, could mean 2 bit
160 * error OR potentially be on a blank page..
161 * orig_ecc: contains spare area data from nand flash.
162 * new_ecc: generated ecc while reading data area.
163 * Note: if the ecc = 0, all data bits from which it was
164 * generated are 0xFF.
165 * The 3 byte(24 bits) ecc is generated per 512byte
166 * chunk of a page. If orig_ecc(from spare area)
167 * is 0xFF && new_ecc(computed now from data area)=0x0,
168 * this means that data area is 0xFF and spare area is
169 * 0xFF. A sure sign of a erased page!
170 */
171 if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000))
172 return 0;
173 printf("Error: Bad compare! failed\n");
174 /* detected 2 bit error */
Scott Wood52ab7ce2016-05-30 13:57:58 -0500175 return -EBADMSG;
Dirk Behme778933f2008-12-14 09:47:16 +0100176 }
177 }
178 return 0;
179}
180
181/*
pekon guptaeff10ee2013-11-19 11:02:15 +0530182 * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write
Andreas Bießmann82a65472013-04-05 04:55:21 +0000183 * @mtd: MTD device structure
184 * @mode: Read/Write mode
185 */
186__maybe_unused
pekon guptaeff10ee2013-11-19 11:02:15 +0530187static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
Andreas Bießmann82a65472013-04-05 04:55:21 +0000188{
Scott Wood17fed142016-05-30 13:57:56 -0500189 struct nand_chip *nand = mtd_to_nand(mtd);
190 struct omap_nand_info *info = nand_get_controller_data(nand);
pekon guptaeff10ee2013-11-19 11:02:15 +0530191 unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0;
192 unsigned int ecc_algo = 0;
193 unsigned int bch_type = 0;
194 unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00;
195 u32 ecc_size_config_val = 0;
196 u32 ecc_config_val = 0;
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +0200197 int cs = info->cs;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000198
pekon guptaeff10ee2013-11-19 11:02:15 +0530199 /* configure GPMC for specific ecc-scheme */
pekon guptaaa168482014-04-11 12:55:33 +0530200 switch (info->ecc_scheme) {
pekon guptaeff10ee2013-11-19 11:02:15 +0530201 case OMAP_ECC_HAM1_CODE_SW:
202 return;
203 case OMAP_ECC_HAM1_CODE_HW:
204 ecc_algo = 0x0;
205 bch_type = 0x0;
206 bch_wrapmode = 0x00;
207 eccsize0 = 0xFF;
208 eccsize1 = 0xFF;
209 break;
210 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
211 case OMAP_ECC_BCH8_CODE_HW:
212 ecc_algo = 0x1;
213 bch_type = 0x1;
214 if (mode == NAND_ECC_WRITE) {
215 bch_wrapmode = 0x01;
216 eccsize0 = 0; /* extra bits in nibbles per sector */
217 eccsize1 = 28; /* OOB bits in nibbles per sector */
218 } else {
219 bch_wrapmode = 0x01;
220 eccsize0 = 26; /* ECC bits in nibbles per sector */
221 eccsize1 = 2; /* non-ECC bits in nibbles per sector */
Stefan Roese7a12cc62013-12-05 07:58:06 +0100222 }
pekon guptaeff10ee2013-11-19 11:02:15 +0530223 break;
pekon gupta046cf862014-06-02 17:14:42 +0530224 case OMAP_ECC_BCH16_CODE_HW:
225 ecc_algo = 0x1;
226 bch_type = 0x2;
227 if (mode == NAND_ECC_WRITE) {
228 bch_wrapmode = 0x01;
229 eccsize0 = 0; /* extra bits in nibbles per sector */
230 eccsize1 = 52; /* OOB bits in nibbles per sector */
231 } else {
232 bch_wrapmode = 0x01;
233 eccsize0 = 52; /* ECC bits in nibbles per sector */
234 eccsize1 = 0; /* non-ECC bits in nibbles per sector */
235 }
236 break;
pekon guptaeff10ee2013-11-19 11:02:15 +0530237 default:
238 return;
pekon gupta6bd91a82013-11-18 19:03:00 +0530239 }
pekon guptaeff10ee2013-11-19 11:02:15 +0530240 /* Clear ecc and enable bits */
241 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
242 /* Configure ecc size for BCH */
243 ecc_size_config_val = (eccsize1 << 22) | (eccsize0 << 12);
244 writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000245
pekon guptaeff10ee2013-11-19 11:02:15 +0530246 /* Configure device details for BCH engine */
247 ecc_config_val = ((ecc_algo << 16) | /* HAM1 | BCHx */
248 (bch_type << 12) | /* BCH4/BCH8/BCH16 */
249 (bch_wrapmode << 8) | /* wrap mode */
250 (dev_width << 7) | /* bus width */
251 (0x0 << 4) | /* number of sectors */
252 (cs << 1) | /* ECC CS */
253 (0x1)); /* enable ECC */
254 writel(ecc_config_val, &gpmc_cfg->ecc_config);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000255}
256
257/*
pekon gupta03742c92013-11-19 11:02:16 +0530258 * omap_calculate_ecc - Read ECC result
259 * @mtd: MTD structure
260 * @dat: unused
261 * @ecc_code: ecc_code buffer
262 * Using noninverted ECC can be considered ugly since writing a blank
263 * page ie. padding will clear the ECC bytes. This is no problem as
264 * long nobody is trying to write data on the seemingly unused page.
265 * Reading an erased page will produce an ECC mismatch between
266 * generated and read ECC bytes that has to be dealt with separately.
267 * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
268 * is used, the result of read will be 0x0 while the ECC offsets of the
269 * spare area will be 0xFF which will result in an ECC mismatch.
Mansoor Ahamede5612512012-11-06 13:06:33 +0000270 */
pekon gupta03742c92013-11-19 11:02:16 +0530271static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
Mansoor Ahamede5612512012-11-06 13:06:33 +0000272 uint8_t *ecc_code)
273{
Scott Wood17fed142016-05-30 13:57:56 -0500274 struct nand_chip *chip = mtd_to_nand(mtd);
275 struct omap_nand_info *info = nand_get_controller_data(chip);
Ladislav Michld5b1c272016-07-12 20:28:16 +0200276 const uint32_t *ptr;
277 uint32_t val = 0;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000278 int8_t i = 0, j;
279
pekon guptaaa168482014-04-11 12:55:33 +0530280 switch (info->ecc_scheme) {
pekon gupta03742c92013-11-19 11:02:16 +0530281 case OMAP_ECC_HAM1_CODE_HW:
282 val = readl(&gpmc_cfg->ecc1_result);
283 ecc_code[0] = val & 0xFF;
284 ecc_code[1] = (val >> 16) & 0xFF;
285 ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
286 break;
287#ifdef CONFIG_BCH
288 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
289#endif
290 case OMAP_ECC_BCH8_CODE_HW:
Mansoor Ahamede5612512012-11-06 13:06:33 +0000291 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
pekon gupta03742c92013-11-19 11:02:16 +0530292 val = readl(ptr);
293 ecc_code[i++] = (val >> 0) & 0xFF;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000294 ptr--;
295 for (j = 0; j < 3; j++) {
pekon gupta03742c92013-11-19 11:02:16 +0530296 val = readl(ptr);
297 ecc_code[i++] = (val >> 24) & 0xFF;
298 ecc_code[i++] = (val >> 16) & 0xFF;
299 ecc_code[i++] = (val >> 8) & 0xFF;
300 ecc_code[i++] = (val >> 0) & 0xFF;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000301 ptr--;
302 }
pekon gupta03742c92013-11-19 11:02:16 +0530303 break;
pekon gupta046cf862014-06-02 17:14:42 +0530304 case OMAP_ECC_BCH16_CODE_HW:
305 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]);
306 ecc_code[i++] = (val >> 8) & 0xFF;
307 ecc_code[i++] = (val >> 0) & 0xFF;
308 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]);
309 ecc_code[i++] = (val >> 24) & 0xFF;
310 ecc_code[i++] = (val >> 16) & 0xFF;
311 ecc_code[i++] = (val >> 8) & 0xFF;
312 ecc_code[i++] = (val >> 0) & 0xFF;
313 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]);
314 ecc_code[i++] = (val >> 24) & 0xFF;
315 ecc_code[i++] = (val >> 16) & 0xFF;
316 ecc_code[i++] = (val >> 8) & 0xFF;
317 ecc_code[i++] = (val >> 0) & 0xFF;
318 for (j = 3; j >= 0; j--) {
319 val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j]
320 );
321 ecc_code[i++] = (val >> 24) & 0xFF;
322 ecc_code[i++] = (val >> 16) & 0xFF;
323 ecc_code[i++] = (val >> 8) & 0xFF;
324 ecc_code[i++] = (val >> 0) & 0xFF;
325 }
326 break;
pekon gupta03742c92013-11-19 11:02:16 +0530327 default:
328 return -EINVAL;
329 }
330 /* ECC scheme specific syndrome customizations */
pekon guptaaa168482014-04-11 12:55:33 +0530331 switch (info->ecc_scheme) {
pekon gupta03742c92013-11-19 11:02:16 +0530332 case OMAP_ECC_HAM1_CODE_HW:
333 break;
334#ifdef CONFIG_BCH
335 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
336
337 for (i = 0; i < chip->ecc.bytes; i++)
338 *(ecc_code + i) = *(ecc_code + i) ^
339 bch8_polynomial[i];
340 break;
341#endif
342 case OMAP_ECC_BCH8_CODE_HW:
343 ecc_code[chip->ecc.bytes - 1] = 0x00;
344 break;
pekon gupta046cf862014-06-02 17:14:42 +0530345 case OMAP_ECC_BCH16_CODE_HW:
346 break;
pekon gupta03742c92013-11-19 11:02:16 +0530347 default:
348 return -EINVAL;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000349 }
pekon gupta03742c92013-11-19 11:02:16 +0530350 return 0;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000351}
352
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300353static inline void omap_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
354{
355 struct nand_chip *chip = mtd_to_nand(mtd);
356 struct omap_nand_info *info = nand_get_controller_data(chip);
357 u32 alignment = ((uintptr_t)buf | len) & 3;
358
359 if (alignment & 1)
360 readsb(info->fifo, buf, len);
361 else if (alignment & 3)
362 readsw(info->fifo, buf, len >> 1);
363 else
364 readsl(info->fifo, buf, len >> 2);
365}
366
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200367#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
368
369#define PREFETCH_CONFIG1_CS_SHIFT 24
370#define PREFETCH_FIFOTHRESHOLD_MAX 0x40
371#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8)
372#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
373#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
374#define ENABLE_PREFETCH (1 << 7)
375
376/**
377 * omap_prefetch_enable - configures and starts prefetch transfer
378 * @fifo_th: fifo threshold to be used for read/ write
379 * @count: number of bytes to be transferred
380 * @is_write: prefetch read(0) or write post(1) mode
381 * @cs: chip select to use
382 */
383static int omap_prefetch_enable(int fifo_th, unsigned int count, int is_write, int cs)
384{
385 uint32_t val;
386
387 if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
388 return -EINVAL;
389
390 if (readl(&gpmc_cfg->prefetch_control))
391 return -EBUSY;
392
393 /* Set the amount of bytes to be prefetched */
394 writel(count, &gpmc_cfg->prefetch_config2);
395
396 val = (cs << PREFETCH_CONFIG1_CS_SHIFT) | (is_write & 1) |
397 PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH;
398 writel(val, &gpmc_cfg->prefetch_config1);
399
400 /* Start the prefetch engine */
401 writel(1, &gpmc_cfg->prefetch_control);
402
403 return 0;
404}
405
406/**
407 * omap_prefetch_reset - disables and stops the prefetch engine
408 */
409static void omap_prefetch_reset(void)
410{
411 writel(0, &gpmc_cfg->prefetch_control);
412 writel(0, &gpmc_cfg->prefetch_config1);
413}
414
415static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int len)
416{
417 int ret;
418 uint32_t cnt;
Scott Wood17fed142016-05-30 13:57:56 -0500419 struct omap_nand_info *info = nand_get_controller_data(chip);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200420
421 ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0, info->cs);
422 if (ret < 0)
423 return ret;
424
425 do {
426 int i;
427
428 cnt = readl(&gpmc_cfg->prefetch_status);
429 cnt = PREFETCH_STATUS_FIFO_CNT(cnt);
430
431 for (i = 0; i < cnt / 4; i++) {
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300432 *buf++ = readl(info->fifo);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200433 len -= 4;
434 }
435 } while (len);
436
437 omap_prefetch_reset();
438
439 return 0;
440}
441
Jeroen Hofstee5e67ac72015-05-30 10:11:24 +0200442static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len)
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200443{
444 int ret;
Roger Quadros3068f0f2022-10-11 14:50:01 +0300445 uintptr_t head, tail;
Scott Wood17fed142016-05-30 13:57:56 -0500446 struct nand_chip *chip = mtd_to_nand(mtd);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200447
448 /*
449 * If the destination buffer is unaligned, start with reading
450 * the overlap byte-wise.
451 */
Roger Quadros3068f0f2022-10-11 14:50:01 +0300452 head = ((uintptr_t)buf) % 4;
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200453 if (head) {
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300454 omap_nand_read_buf(mtd, buf, head);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200455 buf += head;
456 len -= head;
457 }
458
459 /*
460 * Only transfer multiples of 4 bytes in a pre-fetched fashion.
461 * If there's a residue, care for it byte-wise afterwards.
462 */
463 tail = len % 4;
464
Jeroen Hofstee5e67ac72015-05-30 10:11:24 +0200465 ret = __read_prefetch_aligned(chip, (uint32_t *)buf, len - tail);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200466 if (ret < 0) {
467 /* fallback in case the prefetch engine is busy */
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300468 omap_nand_read_buf(mtd, buf, len);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200469 } else if (tail) {
470 buf += len - tail;
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300471 omap_nand_read_buf(mtd, buf, tail);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200472 }
473}
474#endif /* CONFIG_NAND_OMAP_GPMC_PREFETCH */
475
pekon gupta03742c92013-11-19 11:02:16 +0530476#ifdef CONFIG_NAND_OMAP_ELM
Mansoor Ahamede5612512012-11-06 13:06:33 +0000477/*
Jeroen Hofstee79369072014-10-08 22:57:42 +0200478 * omap_reverse_list - re-orders list elements in reverse order [internal]
479 * @list: pointer to start of list
480 * @length: length of list
481*/
482static void omap_reverse_list(u8 *list, unsigned int length)
483{
484 unsigned int i, j;
485 unsigned int half_length = length / 2;
486 u8 tmp;
487 for (i = 0, j = length - 1; i < half_length; i++, j--) {
488 tmp = list[i];
489 list[i] = list[j];
490 list[j] = tmp;
491 }
492}
493
494/*
Mansoor Ahamede5612512012-11-06 13:06:33 +0000495 * omap_correct_data_bch - Compares the ecc read from nand spare area
Vagrant Cascadianedfdb992016-04-30 19:18:00 -0700496 * with ECC registers values and corrects one bit error if it has occurred
Mansoor Ahamede5612512012-11-06 13:06:33 +0000497 *
498 * @mtd: MTD device structure
499 * @dat: page data
500 * @read_ecc: ecc read from nand flash (ignored)
501 * @calc_ecc: ecc read from ECC registers
502 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100503 * Return: 0 if data is OK or corrected, else returns -1
Mansoor Ahamede5612512012-11-06 13:06:33 +0000504 */
505static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
506 uint8_t *read_ecc, uint8_t *calc_ecc)
507{
Scott Wood17fed142016-05-30 13:57:56 -0500508 struct nand_chip *chip = mtd_to_nand(mtd);
509 struct omap_nand_info *info = nand_get_controller_data(chip);
pekon gupta3c43c5b2014-04-11 12:55:34 +0530510 struct nand_ecc_ctrl *ecc = &chip->ecc;
pekon guptab0f750a2013-11-19 11:02:17 +0530511 uint32_t error_count = 0, error_max;
pekon gupta046cf862014-06-02 17:14:42 +0530512 uint32_t error_loc[ELM_MAX_ERROR_COUNT];
pekon gupta9d4b7472014-04-11 12:55:32 +0530513 enum bch_level bch_type;
pekon guptab0f750a2013-11-19 11:02:17 +0530514 uint32_t i, ecc_flag = 0;
Guido Martínez20b27be2015-01-02 14:49:10 -0300515 uint8_t count;
pekon guptab0f750a2013-11-19 11:02:17 +0530516 uint32_t byte_pos, bit_pos;
Guido Martínez20b27be2015-01-02 14:49:10 -0300517 int err = 0;
pekon guptab0f750a2013-11-19 11:02:17 +0530518
519 /* check calculated ecc */
pekon gupta3c43c5b2014-04-11 12:55:34 +0530520 for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
pekon guptab0f750a2013-11-19 11:02:17 +0530521 if (calc_ecc[i] != 0x00)
David Rivshinefa78532021-11-18 13:25:24 -0500522 goto not_ecc_match;
pekon guptab0f750a2013-11-19 11:02:17 +0530523 }
David Rivshinefa78532021-11-18 13:25:24 -0500524 return 0;
525not_ecc_match:
Mansoor Ahamede5612512012-11-06 13:06:33 +0000526
David Rivshinefa78532021-11-18 13:25:24 -0500527 /* check for whether it's an erased-page */
528 for (i = 0; i < ecc->bytes; i++) {
Mansoor Ahamede5612512012-11-06 13:06:33 +0000529 if (read_ecc[i] != 0xff)
David Rivshinefa78532021-11-18 13:25:24 -0500530 goto not_erased;
pekon guptab0f750a2013-11-19 11:02:17 +0530531 }
David Rivshinefa78532021-11-18 13:25:24 -0500532 for (i = 0; i < SECTOR_BYTES; i++) {
533 if (dat[i] != 0xff)
534 goto not_erased;
535 }
536 return 0;
537not_erased:
538
539 /*
540 * Check for whether it's an erased page with a correctable
541 * number of bitflips. Erased pages have all 1's in the data,
542 * so we just compute the number of 0 bits in the data and
543 * see if it's under the correction threshold.
544 *
545 * NOTE: The check for a perfect erased page above is faster for
546 * the more common case, even though it's logically redundant.
547 */
548 for (i = 0; i < ecc->bytes; i++)
549 error_count += hweight8(~read_ecc[i]);
550
551 for (i = 0; i < SECTOR_BYTES; i++)
552 error_count += hweight8(~dat[i]);
553
554 if (error_count <= ecc->strength) {
555 memset(read_ecc, 0xFF, ecc->bytes);
556 memset(dat, 0xFF, SECTOR_BYTES);
557 debug("nand: %u bit-flip(s) corrected in erased page\n",
558 error_count);
559 return error_count;
560 }
Mansoor Ahamede5612512012-11-06 13:06:33 +0000561
Mansoor Ahamede5612512012-11-06 13:06:33 +0000562 /*
563 * while reading ECC result we read it in big endian.
564 * Hence while loading to ELM we have rotate to get the right endian.
565 */
pekon guptaaa168482014-04-11 12:55:33 +0530566 switch (info->ecc_scheme) {
pekon guptab0f750a2013-11-19 11:02:17 +0530567 case OMAP_ECC_BCH8_CODE_HW:
pekon gupta9d4b7472014-04-11 12:55:32 +0530568 bch_type = BCH_8_BIT;
pekon gupta3c43c5b2014-04-11 12:55:34 +0530569 omap_reverse_list(calc_ecc, ecc->bytes - 1);
pekon guptab0f750a2013-11-19 11:02:17 +0530570 break;
pekon gupta046cf862014-06-02 17:14:42 +0530571 case OMAP_ECC_BCH16_CODE_HW:
572 bch_type = BCH_16_BIT;
573 omap_reverse_list(calc_ecc, ecc->bytes);
574 break;
pekon guptab0f750a2013-11-19 11:02:17 +0530575 default:
576 return -EINVAL;
577 }
Mansoor Ahamede5612512012-11-06 13:06:33 +0000578 /* use elm module to check for errors */
pekon gupta9d4b7472014-04-11 12:55:32 +0530579 elm_config(bch_type);
David Rivshinefa78532021-11-18 13:25:24 -0500580 error_count = 0;
pekon guptacfe6b8a2014-04-11 12:55:35 +0530581 err = elm_check_error(calc_ecc, bch_type, &error_count, error_loc);
582 if (err)
583 return err;
584
Mansoor Ahamede5612512012-11-06 13:06:33 +0000585 /* correct bch error */
pekon guptab0f750a2013-11-19 11:02:17 +0530586 for (count = 0; count < error_count; count++) {
pekon guptaaa168482014-04-11 12:55:33 +0530587 switch (info->ecc_scheme) {
pekon gupta9d4b7472014-04-11 12:55:32 +0530588 case OMAP_ECC_BCH8_CODE_HW:
pekon guptab0f750a2013-11-19 11:02:17 +0530589 /* 14th byte in ECC is reserved to match ROM layout */
pekon gupta3c43c5b2014-04-11 12:55:34 +0530590 error_max = SECTOR_BYTES + (ecc->bytes - 1);
pekon guptab0f750a2013-11-19 11:02:17 +0530591 break;
pekon gupta046cf862014-06-02 17:14:42 +0530592 case OMAP_ECC_BCH16_CODE_HW:
593 error_max = SECTOR_BYTES + ecc->bytes;
594 break;
pekon guptab0f750a2013-11-19 11:02:17 +0530595 default:
596 return -EINVAL;
597 }
598 byte_pos = error_max - (error_loc[count] / 8) - 1;
599 bit_pos = error_loc[count] % 8;
600 if (byte_pos < SECTOR_BYTES) {
601 dat[byte_pos] ^= 1 << bit_pos;
Ezequiel García69cf8ad2015-10-04 18:34:42 -0300602 debug("nand: bit-flip corrected @data=%d\n", byte_pos);
pekon guptab0f750a2013-11-19 11:02:17 +0530603 } else if (byte_pos < error_max) {
Belisko Marek9ab54142014-04-25 12:00:07 +0200604 read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos;
Ezequiel García69cf8ad2015-10-04 18:34:42 -0300605 debug("nand: bit-flip corrected @oob=%d\n", byte_pos -
pekon guptab0f750a2013-11-19 11:02:17 +0530606 SECTOR_BYTES);
607 } else {
608 err = -EBADMSG;
609 printf("nand: error: invalid bit-flip location\n");
610 }
611 }
612 return (err) ? err : error_count;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000613}
Mansoor Ahamede5612512012-11-06 13:06:33 +0000614
615/**
616 * omap_read_page_bch - hardware ecc based page read function
617 * @mtd: mtd info structure
618 * @chip: nand chip info structure
619 * @buf: buffer to store read data
Sergey Lapin3a38a552013-01-14 03:46:50 +0000620 * @oob_required: caller expects OOB data read to chip->oob_poi
Mansoor Ahamede5612512012-11-06 13:06:33 +0000621 * @page: page number to read
622 *
623 */
624static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
Sergey Lapin3a38a552013-01-14 03:46:50 +0000625 uint8_t *buf, int oob_required, int page)
Mansoor Ahamede5612512012-11-06 13:06:33 +0000626{
627 int i, eccsize = chip->ecc.size;
628 int eccbytes = chip->ecc.bytes;
629 int eccsteps = chip->ecc.steps;
630 uint8_t *p = buf;
631 uint8_t *ecc_calc = chip->buffers->ecccalc;
632 uint8_t *ecc_code = chip->buffers->ecccode;
633 uint32_t *eccpos = chip->ecc.layout->eccpos;
634 uint8_t *oob = chip->oob_poi;
635 uint32_t data_pos;
636 uint32_t oob_pos;
637
638 data_pos = 0;
639 /* oob area start */
640 oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
641 oob += chip->ecc.layout->eccpos[0];
642
643 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
644 oob += eccbytes) {
645 chip->ecc.hwctl(mtd, NAND_ECC_READ);
646 /* read data */
Rostislav Lisovya9ee70a2014-09-02 17:00:30 +0200647 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1);
Mansoor Ahamede5612512012-11-06 13:06:33 +0000648 chip->read_buf(mtd, p, eccsize);
649
650 /* read respective ecc from oob area */
Rostislav Lisovya9ee70a2014-09-02 17:00:30 +0200651 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
Mansoor Ahamede5612512012-11-06 13:06:33 +0000652 chip->read_buf(mtd, oob, eccbytes);
653 /* read syndrome */
654 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
655
656 data_pos += eccsize;
657 oob_pos += eccbytes;
658 }
659
660 for (i = 0; i < chip->ecc.total; i++)
661 ecc_code[i] = chip->oob_poi[eccpos[i]];
662
663 eccsteps = chip->ecc.steps;
664 p = buf;
665
666 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
667 int stat;
668
669 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
670 if (stat < 0)
671 mtd->ecc_stats.failed++;
672 else
673 mtd->ecc_stats.corrected += stat;
674 }
675 return 0;
676}
pekon gupta6bd91a82013-11-18 19:03:00 +0530677#endif /* CONFIG_NAND_OMAP_ELM */
Mansoor Ahamede5612512012-11-06 13:06:33 +0000678
Andreas Bießmann82a65472013-04-05 04:55:21 +0000679/*
680 * OMAP3 BCH8 support (with BCH library)
681 */
pekon gupta6bd91a82013-11-18 19:03:00 +0530682#ifdef CONFIG_BCH
Andreas Bießmann82a65472013-04-05 04:55:21 +0000683/**
pekon gupta6bd91a82013-11-18 19:03:00 +0530684 * omap_correct_data_bch_sw - Decode received data and correct errors
Andreas Bießmann82a65472013-04-05 04:55:21 +0000685 * @mtd: MTD device structure
686 * @data: page data
687 * @read_ecc: ecc read from nand flash
688 * @calc_ecc: ecc read from HW ECC registers
689 */
pekon gupta6bd91a82013-11-18 19:03:00 +0530690static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data,
Andreas Bießmann82a65472013-04-05 04:55:21 +0000691 u_char *read_ecc, u_char *calc_ecc)
692{
693 int i, count;
694 /* cannot correct more than 8 errors */
695 unsigned int errloc[8];
Scott Wood17fed142016-05-30 13:57:56 -0500696 struct nand_chip *chip = mtd_to_nand(mtd);
697 struct omap_nand_info *info = nand_get_controller_data(chip);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000698
Ladislav Michl6cc51852017-01-09 11:15:14 +0100699 count = decode_bch(info->control, NULL, SECTOR_BYTES,
700 read_ecc, calc_ecc, NULL, errloc);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000701 if (count > 0) {
702 /* correct errors */
703 for (i = 0; i < count; i++) {
704 /* correct data only, not ecc bytes */
Ladislav Michl6cc51852017-01-09 11:15:14 +0100705 if (errloc[i] < SECTOR_BYTES << 3)
706 data[errloc[i] >> 3] ^= 1 << (errloc[i] & 7);
Ezequiel García69cf8ad2015-10-04 18:34:42 -0300707 debug("corrected bitflip %u\n", errloc[i]);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000708#ifdef DEBUG
709 puts("read_ecc: ");
710 /*
711 * BCH8 have 13 bytes of ECC; BCH4 needs adoption
712 * here!
713 */
714 for (i = 0; i < 13; i++)
715 printf("%02x ", read_ecc[i]);
716 puts("\n");
717 puts("calc_ecc: ");
718 for (i = 0; i < 13; i++)
719 printf("%02x ", calc_ecc[i]);
720 puts("\n");
721#endif
722 }
723 } else if (count < 0) {
724 puts("ecc unrecoverable error\n");
725 }
726 return count;
727}
728
729/**
730 * omap_free_bch - Release BCH ecc resources
731 * @mtd: MTD device structure
732 */
733static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
734{
Scott Wood17fed142016-05-30 13:57:56 -0500735 struct nand_chip *chip = mtd_to_nand(mtd);
736 struct omap_nand_info *info = nand_get_controller_data(chip);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000737
pekon guptaaa168482014-04-11 12:55:33 +0530738 if (info->control) {
739 free_bch(info->control);
740 info->control = NULL;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000741 }
742}
pekon gupta6bd91a82013-11-18 19:03:00 +0530743#endif /* CONFIG_BCH */
744
745/**
746 * omap_select_ecc_scheme - configures driver for particular ecc-scheme
747 * @nand: NAND chip device structure
748 * @ecc_scheme: ecc scheme to configure
749 * @pagesize: number of main-area bytes per page of NAND device
750 * @oobsize: number of OOB/spare bytes per page of NAND device
751 */
752static int omap_select_ecc_scheme(struct nand_chip *nand,
753 enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
Scott Wood17fed142016-05-30 13:57:56 -0500754 struct omap_nand_info *info = nand_get_controller_data(nand);
Roger Quadros224add22022-10-11 14:50:06 +0300755 struct nand_ecclayout *ecclayout = nand->ecc.layout;
pekon gupta6bd91a82013-11-18 19:03:00 +0530756 int eccsteps = pagesize / SECTOR_BYTES;
757 int i;
758
759 switch (ecc_scheme) {
760 case OMAP_ECC_HAM1_CODE_SW:
761 debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n");
762 /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are
763 * initialized in nand_scan_tail(), so just set ecc.mode */
pekon guptaaa168482014-04-11 12:55:33 +0530764 info->control = NULL;
pekon gupta6bd91a82013-11-18 19:03:00 +0530765 nand->ecc.mode = NAND_ECC_SOFT;
766 nand->ecc.layout = NULL;
Nikita Kiryanov4110c822013-12-12 15:19:31 +0200767 nand->ecc.size = 0;
pekon gupta6bd91a82013-11-18 19:03:00 +0530768 break;
769
770 case OMAP_ECC_HAM1_CODE_HW:
771 debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n");
772 /* check ecc-scheme requirements before updating ecc info */
773 if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
774 printf("nand: error: insufficient OOB: require=%d\n", (
775 (3 * eccsteps) + BADBLOCK_MARKER_LENGTH));
776 return -EINVAL;
777 }
pekon guptaaa168482014-04-11 12:55:33 +0530778 info->control = NULL;
pekon gupta6bd91a82013-11-18 19:03:00 +0530779 /* populate ecc specific fields */
Nikita Kiryanov2e18ff22013-12-17 15:18:01 +0200780 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
pekon gupta6bd91a82013-11-18 19:03:00 +0530781 nand->ecc.mode = NAND_ECC_HW;
782 nand->ecc.strength = 1;
783 nand->ecc.size = SECTOR_BYTES;
784 nand->ecc.bytes = 3;
785 nand->ecc.hwctl = omap_enable_hwecc;
786 nand->ecc.correct = omap_correct_data;
787 nand->ecc.calculate = omap_calculate_ecc;
788 /* define ecc-layout */
789 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
pekon guptaf0aff022013-12-05 17:54:21 +0530790 for (i = 0; i < ecclayout->eccbytes; i++) {
791 if (nand->options & NAND_BUSWIDTH_16)
792 ecclayout->eccpos[i] = i + 2;
793 else
794 ecclayout->eccpos[i] = i + 1;
795 }
pekon gupta6bd91a82013-11-18 19:03:00 +0530796 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
797 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
798 BADBLOCK_MARKER_LENGTH;
pekon gupta6bd91a82013-11-18 19:03:00 +0530799 break;
800
801 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
802#ifdef CONFIG_BCH
803 debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
804 /* check ecc-scheme requirements before updating ecc info */
805 if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
806 printf("nand: error: insufficient OOB: require=%d\n", (
807 (13 * eccsteps) + BADBLOCK_MARKER_LENGTH));
808 return -EINVAL;
809 }
810 /* check if BCH S/W library can be used for error detection */
pekon guptaaa168482014-04-11 12:55:33 +0530811 info->control = init_bch(13, 8, 0x201b);
812 if (!info->control) {
pekon gupta6bd91a82013-11-18 19:03:00 +0530813 printf("nand: error: could not init_bch()\n");
814 return -ENODEV;
815 }
pekon gupta6bd91a82013-11-18 19:03:00 +0530816 /* populate ecc specific fields */
Nikita Kiryanov2e18ff22013-12-17 15:18:01 +0200817 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
pekon gupta6bd91a82013-11-18 19:03:00 +0530818 nand->ecc.mode = NAND_ECC_HW;
819 nand->ecc.strength = 8;
820 nand->ecc.size = SECTOR_BYTES;
821 nand->ecc.bytes = 13;
pekon guptaeff10ee2013-11-19 11:02:15 +0530822 nand->ecc.hwctl = omap_enable_hwecc;
pekon gupta6bd91a82013-11-18 19:03:00 +0530823 nand->ecc.correct = omap_correct_data_bch_sw;
pekon gupta03742c92013-11-19 11:02:16 +0530824 nand->ecc.calculate = omap_calculate_ecc;
pekon gupta6bd91a82013-11-18 19:03:00 +0530825 /* define ecc-layout */
826 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
827 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
828 for (i = 1; i < ecclayout->eccbytes; i++) {
829 if (i % nand->ecc.bytes)
830 ecclayout->eccpos[i] =
831 ecclayout->eccpos[i - 1] + 1;
832 else
833 ecclayout->eccpos[i] =
834 ecclayout->eccpos[i - 1] + 2;
835 }
836 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
837 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
838 BADBLOCK_MARKER_LENGTH;
pekon gupta6bd91a82013-11-18 19:03:00 +0530839 break;
840#else
841 printf("nand: error: CONFIG_BCH required for ECC\n");
842 return -EINVAL;
843#endif
844
845 case OMAP_ECC_BCH8_CODE_HW:
846#ifdef CONFIG_NAND_OMAP_ELM
847 debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n");
848 /* check ecc-scheme requirements before updating ecc info */
849 if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
850 printf("nand: error: insufficient OOB: require=%d\n", (
851 (14 * eccsteps) + BADBLOCK_MARKER_LENGTH));
852 return -EINVAL;
853 }
854 /* intialize ELM for ECC error detection */
855 elm_init();
pekon guptaaa168482014-04-11 12:55:33 +0530856 info->control = NULL;
pekon gupta6bd91a82013-11-18 19:03:00 +0530857 /* populate ecc specific fields */
Nikita Kiryanov2e18ff22013-12-17 15:18:01 +0200858 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
pekon gupta6bd91a82013-11-18 19:03:00 +0530859 nand->ecc.mode = NAND_ECC_HW;
860 nand->ecc.strength = 8;
861 nand->ecc.size = SECTOR_BYTES;
862 nand->ecc.bytes = 14;
pekon guptaeff10ee2013-11-19 11:02:15 +0530863 nand->ecc.hwctl = omap_enable_hwecc;
pekon gupta6bd91a82013-11-18 19:03:00 +0530864 nand->ecc.correct = omap_correct_data_bch;
pekon gupta03742c92013-11-19 11:02:16 +0530865 nand->ecc.calculate = omap_calculate_ecc;
pekon gupta6bd91a82013-11-18 19:03:00 +0530866 nand->ecc.read_page = omap_read_page_bch;
867 /* define ecc-layout */
868 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
869 for (i = 0; i < ecclayout->eccbytes; i++)
870 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
871 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
872 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
873 BADBLOCK_MARKER_LENGTH;
pekon gupta6bd91a82013-11-18 19:03:00 +0530874 break;
875#else
876 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
877 return -EINVAL;
878#endif
879
pekon gupta046cf862014-06-02 17:14:42 +0530880 case OMAP_ECC_BCH16_CODE_HW:
881#ifdef CONFIG_NAND_OMAP_ELM
882 debug("nand: using OMAP_ECC_BCH16_CODE_HW\n");
883 /* check ecc-scheme requirements before updating ecc info */
884 if ((26 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
885 printf("nand: error: insufficient OOB: require=%d\n", (
886 (26 * eccsteps) + BADBLOCK_MARKER_LENGTH));
887 return -EINVAL;
888 }
889 /* intialize ELM for ECC error detection */
890 elm_init();
891 /* populate ecc specific fields */
892 nand->ecc.mode = NAND_ECC_HW;
893 nand->ecc.size = SECTOR_BYTES;
894 nand->ecc.bytes = 26;
895 nand->ecc.strength = 16;
896 nand->ecc.hwctl = omap_enable_hwecc;
897 nand->ecc.correct = omap_correct_data_bch;
898 nand->ecc.calculate = omap_calculate_ecc;
899 nand->ecc.read_page = omap_read_page_bch;
900 /* define ecc-layout */
901 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
902 for (i = 0; i < ecclayout->eccbytes; i++)
903 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
904 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
905 ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes -
906 BADBLOCK_MARKER_LENGTH;
907 break;
908#else
909 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
910 return -EINVAL;
911#endif
pekon gupta6bd91a82013-11-18 19:03:00 +0530912 default:
913 debug("nand: error: ecc scheme not enabled or supported\n");
914 return -EINVAL;
915 }
Nikita Kiryanove8167892013-12-16 19:19:01 +0200916
917 /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */
918 if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW)
919 nand->ecc.layout = ecclayout;
920
pekon guptaaa168482014-04-11 12:55:33 +0530921 info->ecc_scheme = ecc_scheme;
pekon gupta6bd91a82013-11-18 19:03:00 +0530922 return 0;
923}
Andreas Bießmann82a65472013-04-05 04:55:21 +0000924
Simon Schwarz4f62e982011-09-14 15:30:16 -0400925#ifndef CONFIG_SPL_BUILD
Dirk Behme778933f2008-12-14 09:47:16 +0100926/*
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000927 * omap_nand_switch_ecc - switch the ECC operation between different engines
928 * (h/w and s/w) and different algorithms (hamming and BCHx)
Dirk Behme778933f2008-12-14 09:47:16 +0100929 *
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000930 * @hardware - true if one of the HW engines should be used
931 * @eccstrength - the number of bits that could be corrected
932 * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16)
Dirk Behme778933f2008-12-14 09:47:16 +0100933 */
pekon gupta6bd91a82013-11-18 19:03:00 +0530934int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
Dirk Behme778933f2008-12-14 09:47:16 +0100935{
936 struct nand_chip *nand;
Mugunthan V N7b670cc2017-06-26 19:12:51 -0500937 struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device);
pekon gupta6bd91a82013-11-18 19:03:00 +0530938 int err = 0;
Dirk Behme778933f2008-12-14 09:47:16 +0100939
Mugunthan V N7b670cc2017-06-26 19:12:51 -0500940 if (!mtd) {
pekon gupta6bd91a82013-11-18 19:03:00 +0530941 printf("nand: error: no NAND devices found\n");
942 return -ENODEV;
Dirk Behme778933f2008-12-14 09:47:16 +0100943 }
944
Scott Wood17fed142016-05-30 13:57:56 -0500945 nand = mtd_to_nand(mtd);
Dirk Behme778933f2008-12-14 09:47:16 +0100946 nand->options |= NAND_OWN_BUFFERS;
Jeroen Hofstee96306f22014-01-15 17:58:54 +0100947 nand->options &= ~NAND_SUBPAGE_READ;
Dirk Behme778933f2008-12-14 09:47:16 +0100948 /* Setup the ecc configurations again */
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000949 if (hardware) {
950 if (eccstrength == 1) {
pekon gupta6bd91a82013-11-18 19:03:00 +0530951 err = omap_select_ecc_scheme(nand,
952 OMAP_ECC_HAM1_CODE_HW,
953 mtd->writesize, mtd->oobsize);
954 } else if (eccstrength == 8) {
955 err = omap_select_ecc_scheme(nand,
956 OMAP_ECC_BCH8_CODE_HW,
957 mtd->writesize, mtd->oobsize);
Heiko Schocher5bf904c2016-06-07 08:55:42 +0200958 } else if (eccstrength == 16) {
959 err = omap_select_ecc_scheme(nand,
960 OMAP_ECC_BCH16_CODE_HW,
961 mtd->writesize, mtd->oobsize);
pekon gupta6bd91a82013-11-18 19:03:00 +0530962 } else {
963 printf("nand: error: unsupported ECC scheme\n");
964 return -EINVAL;
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000965 }
Dirk Behme778933f2008-12-14 09:47:16 +0100966 } else {
Ash Charles4a5faa82015-02-18 11:25:11 -0800967 if (eccstrength == 1) {
968 err = omap_select_ecc_scheme(nand,
969 OMAP_ECC_HAM1_CODE_SW,
970 mtd->writesize, mtd->oobsize);
971 } else if (eccstrength == 8) {
972 err = omap_select_ecc_scheme(nand,
973 OMAP_ECC_BCH8_CODE_HW_DETECTION_SW,
pekon gupta6bd91a82013-11-18 19:03:00 +0530974 mtd->writesize, mtd->oobsize);
Ash Charles4a5faa82015-02-18 11:25:11 -0800975 } else {
976 printf("nand: error: unsupported ECC scheme\n");
977 return -EINVAL;
978 }
Dirk Behme778933f2008-12-14 09:47:16 +0100979 }
980
981 /* Update NAND handling after ECC mode switch */
pekon gupta6bd91a82013-11-18 19:03:00 +0530982 if (!err)
983 err = nand_scan_tail(mtd);
984 return err;
Dirk Behme778933f2008-12-14 09:47:16 +0100985}
Simon Schwarz4f62e982011-09-14 15:30:16 -0400986#endif /* CONFIG_SPL_BUILD */
Dirk Behme778933f2008-12-14 09:47:16 +0100987
988/*
989 * Board-specific NAND initialization. The following members of the
990 * argument are board-specific:
991 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
992 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
993 * - cmd_ctrl: hardwarespecific function for accesing control-lines
994 * - waitfunc: hardwarespecific function for accesing device ready/busy line
995 * - ecc.hwctl: function to enable (reset) hardware ecc generator
996 * - ecc.mode: mode of ecc, see defines
997 * - chip_delay: chip dependent delay for transfering data from array to
998 * read regs (tR)
999 * - options: various chip options. They can partly be set to inform
1000 * nand_scan about special functionality. See the defines for further
1001 * explanation
1002 */
1003int board_nand_init(struct nand_chip *nand)
1004{
1005 int32_t gpmc_config = 0;
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +02001006 int cs = cs_next++;
pekon gupta6bd91a82013-11-18 19:03:00 +05301007 int err = 0;
Roger Quadros3b7aaa52022-10-11 14:50:02 +03001008 struct omap_nand_info *info;
1009
Dirk Behme778933f2008-12-14 09:47:16 +01001010 /*
1011 * xloader/Uboot's gpmc configuration would have configured GPMC for
1012 * nand type of memory. The following logic scans and latches on to the
1013 * first CS with NAND type memory.
1014 * TBD: need to make this logic generic to handle multiple CS NAND
1015 * devices.
1016 */
1017 while (cs < GPMC_MAX_CS) {
Dirk Behme778933f2008-12-14 09:47:16 +01001018 /* Check if NAND type is set */
Dirk Behmea4becd62009-08-08 09:30:22 +02001019 if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
Dirk Behme778933f2008-12-14 09:47:16 +01001020 /* Found it!! */
1021 break;
1022 }
1023 cs++;
1024 }
1025 if (cs >= GPMC_MAX_CS) {
pekon gupta6bd91a82013-11-18 19:03:00 +05301026 printf("nand: error: Unable to find NAND settings in "
Dirk Behme778933f2008-12-14 09:47:16 +01001027 "GPMC Configuration - quitting\n");
1028 return -ENODEV;
1029 }
1030
Dirk Behmea4becd62009-08-08 09:30:22 +02001031 gpmc_config = readl(&gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +01001032 /* Disable Write protect */
1033 gpmc_config |= 0x10;
Dirk Behmea4becd62009-08-08 09:30:22 +02001034 writel(gpmc_config, &gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +01001035
Dirk Behmea4becd62009-08-08 09:30:22 +02001036 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
1037 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Roger Quadros3b7aaa52022-10-11 14:50:02 +03001038
1039 info = &omap_nand_info[cs];
1040 info->control = NULL;
1041 info->cs = cs;
1042 info->ws = wscfg[cs];
Tom Rinia63bea92022-12-19 09:29:55 -05001043 info->fifo = (void __iomem *)CFG_SYS_NAND_BASE;
Scott Wood17fed142016-05-30 13:57:56 -05001044 nand_set_controller_data(nand, &omap_nand_info[cs]);
pekon gupta6bd91a82013-11-18 19:03:00 +05301045 nand->cmd_ctrl = omap_nand_hwcontrol;
1046 nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
Dirk Behme778933f2008-12-14 09:47:16 +01001047 nand->chip_delay = 100;
Roger Quadros224add22022-10-11 14:50:06 +03001048 nand->ecc.layout = kzalloc(sizeof(*nand->ecc.layout), GFP_KERNEL);
1049 if (!nand->ecc.layout)
1050 return -ENOMEM;
Mansoor Ahamede5612512012-11-06 13:06:33 +00001051
pekon gupta6250faf2014-05-06 00:46:19 +05301052 /* configure driver and controller based on NAND device bus-width */
1053 gpmc_config = readl(&gpmc_cfg->cs[cs].config1);
1054#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT)
1055 nand->options |= NAND_BUSWIDTH_16;
1056 writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1);
1057#else
1058 nand->options &= ~NAND_BUSWIDTH_16;
1059 writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1);
1060#endif
pekon gupta6bd91a82013-11-18 19:03:00 +05301061 /* select ECC scheme */
pekon gupta3ef49732013-11-18 19:03:01 +05301062#if defined(CONFIG_NAND_OMAP_ECCSCHEME)
1063 err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME,
pekon gupta6bd91a82013-11-18 19:03:00 +05301064 CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
pekon gupta3ef49732013-11-18 19:03:01 +05301065#else
1066 /* pagesize and oobsize are not required to configure sw ecc-scheme */
pekon gupta6bd91a82013-11-18 19:03:00 +05301067 err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
1068 0, 0);
Mansoor Ahamede5612512012-11-06 13:06:33 +00001069#endif
pekon gupta6bd91a82013-11-18 19:03:00 +05301070 if (err)
1071 return err;
Simon Schwarz4f62e982011-09-14 15:30:16 -04001072
Egli, Samuel8645fd92015-02-13 15:47:10 +01001073#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
Jeroen Hofstee5e67ac72015-05-30 10:11:24 +02001074 nand->read_buf = omap_nand_read_prefetch;
Egli, Samuel8645fd92015-02-13 15:47:10 +01001075#else
Roger Quadros3b7aaa52022-10-11 14:50:02 +03001076 nand->read_buf = omap_nand_read_buf;
Simon Schwarz4f62e982011-09-14 15:30:16 -04001077#endif
Stefan Roesee05972f2014-11-13 03:43:39 +01001078
1079 nand->dev_ready = omap_dev_ready;
1080
Dirk Behme778933f2008-12-14 09:47:16 +01001081 return 0;
1082}