blob: 0e25bd5dc28f71b93398a05d440c31d7e1af4eaf [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>
Sean Anderson11a4c702023-11-04 16:37:41 -04009#include <system-constants.h>
Dirk Behme778933f2008-12-14 09:47:16 +010010#include <asm/io.h>
Roger Quadros80cf6372022-12-20 12:21:59 +020011#include <dm/uclass.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090012#include <linux/errno.h>
Roger Quadros6550c622022-10-11 14:49:59 +030013
14#ifdef CONFIG_ARCH_OMAP2PLUS
Dirk Behme778933f2008-12-14 09:47:16 +010015#include <asm/arch/mem.h>
Roger Quadros6550c622022-10-11 14:49:59 +030016#endif
17
pekon gupta5bbb0992013-11-22 16:53:29 +053018#include <linux/mtd/omap_gpmc.h>
Dirk Behme778933f2008-12-14 09:47:16 +010019#include <linux/mtd/nand_ecc.h>
Tom Rini3bde7e22021-09-22 14:50:35 -040020#include <linux/mtd/rawnand.h>
Andreas Bießmann82a65472013-04-05 04:55:21 +000021#include <linux/bch.h>
Stefano Babicaade5792012-03-21 23:56:17 +000022#include <linux/compiler.h>
Dirk Behme778933f2008-12-14 09:47:16 +010023#include <nand.h>
Roger Quadrosa42b7702022-12-20 12:22:03 +020024
25#include "omap_elm.h"
pekon gupta6bd91a82013-11-18 19:03:00 +053026
Roger Quadros6550c622022-10-11 14:49:59 +030027#ifndef GPMC_MAX_CS
28#define GPMC_MAX_CS 4
29#endif
30
pekon gupta6bd91a82013-11-18 19:03:00 +053031#define BADBLOCK_MARKER_LENGTH 2
32#define SECTOR_BYTES 512
Roger Quadrosaa418fb2022-12-20 12:21:56 +020033#define ECCSIZE0_SHIFT 12
34#define ECCSIZE1_SHIFT 22
35#define ECC1RESULTSIZE 0x1
pekon guptaeff10ee2013-11-19 11:02:15 +053036#define ECCCLEAR (0x1 << 8)
37#define ECCRESULTREG1 (0x1 << 0)
pekon guptab0f750a2013-11-19 11:02:17 +053038/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
39#define BCH4_BIT_PAD 4
40
pekon gupta03742c92013-11-19 11:02:16 +053041#ifdef CONFIG_BCH
42static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
43 0x97, 0x79, 0xe5, 0x24, 0xb5};
44#endif
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020045static uint8_t cs_next;
Dirk Behme778933f2008-12-14 09:47:16 +010046
Michal Sojka26160072015-02-17 17:08:37 +010047#if defined(CONFIG_NAND_OMAP_GPMC_WSCFG)
48static const int8_t wscfg[CONFIG_SYS_MAX_NAND_DEVICE] =
49 { CONFIG_NAND_OMAP_GPMC_WSCFG };
50#else
51/* wscfg is preset to zero since its a static variable */
52static const int8_t wscfg[CONFIG_SYS_MAX_NAND_DEVICE];
53#endif
54
Dirk Behme778933f2008-12-14 09:47:16 +010055/*
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020056 * Driver configurations
57 */
58struct omap_nand_info {
59 struct bch_control *control;
60 enum omap_ecc ecc_scheme;
Michal Sojka26160072015-02-17 17:08:37 +010061 uint8_t cs;
62 uint8_t ws; /* wait status pin (0,1) */
Roger Quadros3b7aaa52022-10-11 14:50:02 +030063 void __iomem *fifo;
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020064};
65
66/* We are wasting a bit of memory but al least we are safe */
67static struct omap_nand_info omap_nand_info[GPMC_MAX_CS];
68
69/*
Dirk Behme778933f2008-12-14 09:47:16 +010070 * omap_nand_hwcontrol - Set the address pointers corretly for the
71 * following address/data/command operation
72 */
73static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
74 uint32_t ctrl)
75{
Scott Wood17fed142016-05-30 13:57:56 -050076 register struct nand_chip *this = mtd_to_nand(mtd);
77 struct omap_nand_info *info = nand_get_controller_data(this);
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +020078 int cs = info->cs;
Dirk Behme778933f2008-12-14 09:47:16 +010079
80 /*
81 * Point the IO_ADDR to DATA and ADDRESS registers instead
82 * of chip address
83 */
84 switch (ctrl) {
85 case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
Dirk Behmea4becd62009-08-08 09:30:22 +020086 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Dirk Behme778933f2008-12-14 09:47:16 +010087 break;
88 case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
Dirk Behmea4becd62009-08-08 09:30:22 +020089 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
Dirk Behme778933f2008-12-14 09:47:16 +010090 break;
91 case NAND_CTRL_CHANGE | NAND_NCE:
Dirk Behmea4becd62009-08-08 09:30:22 +020092 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
Dirk Behme778933f2008-12-14 09:47:16 +010093 break;
94 }
95
96 if (cmd != NAND_CMD_NONE)
97 writeb(cmd, this->IO_ADDR_W);
98}
99
Simon Schwarz4f62e982011-09-14 15:30:16 -0400100/* Check wait pin as dev ready indicator */
Stefan Roesee05972f2014-11-13 03:43:39 +0100101static int omap_dev_ready(struct mtd_info *mtd)
Simon Schwarz4f62e982011-09-14 15:30:16 -0400102{
Scott Wood17fed142016-05-30 13:57:56 -0500103 register struct nand_chip *this = mtd_to_nand(mtd);
104 struct omap_nand_info *info = nand_get_controller_data(this);
Michal Sojka26160072015-02-17 17:08:37 +0100105 return gpmc_cfg->status & (1 << (8 + info->ws));
Simon Schwarz4f62e982011-09-14 15:30:16 -0400106}
Dirk Behme778933f2008-12-14 09:47:16 +0100107
108/*
109 * gen_true_ecc - This function will generate true ECC value, which
110 * can be used when correcting data read from NAND flash memory core
111 *
112 * @ecc_buf: buffer to store ecc code
113 *
114 * @return: re-formatted ECC value
115 */
116static uint32_t gen_true_ecc(uint8_t *ecc_buf)
117{
118 return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
119 ((ecc_buf[2] & 0x0F) << 8);
120}
121
122/*
123 * omap_correct_data - Compares the ecc read from nand spare area with ECC
Vagrant Cascadianedfdb992016-04-30 19:18:00 -0700124 * registers values and corrects one bit error if it has occurred
Dirk Behme778933f2008-12-14 09:47:16 +0100125 * Further details can be had from OMAP TRM and the following selected links:
126 * http://en.wikipedia.org/wiki/Hamming_code
127 * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf
128 *
129 * @mtd: MTD device structure
130 * @dat: page data
131 * @read_ecc: ecc read from nand flash
132 * @calc_ecc: ecc read from ECC registers
133 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100134 * Return: 0 if data is OK or corrected, else returns -1
Dirk Behme778933f2008-12-14 09:47:16 +0100135 */
Stefano Babicaade5792012-03-21 23:56:17 +0000136static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
Dirk Behme778933f2008-12-14 09:47:16 +0100137 uint8_t *read_ecc, uint8_t *calc_ecc)
138{
139 uint32_t orig_ecc, new_ecc, res, hm;
140 uint16_t parity_bits, byte;
141 uint8_t bit;
142
143 /* Regenerate the orginal ECC */
144 orig_ecc = gen_true_ecc(read_ecc);
145 new_ecc = gen_true_ecc(calc_ecc);
146 /* Get the XOR of real ecc */
147 res = orig_ecc ^ new_ecc;
148 if (res) {
149 /* Get the hamming width */
150 hm = hweight32(res);
151 /* Single bit errors can be corrected! */
152 if (hm == 12) {
153 /* Correctable data! */
154 parity_bits = res >> 16;
155 bit = (parity_bits & 0x7);
156 byte = (parity_bits >> 3) & 0x1FF;
157 /* Flip the bit to correct */
158 dat[byte] ^= (0x1 << bit);
159 } else if (hm == 1) {
160 printf("Error: Ecc is wrong\n");
161 /* ECC itself is corrupted */
162 return 2;
163 } else {
164 /*
165 * hm distance != parity pairs OR one, could mean 2 bit
166 * error OR potentially be on a blank page..
167 * orig_ecc: contains spare area data from nand flash.
168 * new_ecc: generated ecc while reading data area.
169 * Note: if the ecc = 0, all data bits from which it was
170 * generated are 0xFF.
171 * The 3 byte(24 bits) ecc is generated per 512byte
172 * chunk of a page. If orig_ecc(from spare area)
173 * is 0xFF && new_ecc(computed now from data area)=0x0,
174 * this means that data area is 0xFF and spare area is
175 * 0xFF. A sure sign of a erased page!
176 */
177 if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000))
178 return 0;
179 printf("Error: Bad compare! failed\n");
180 /* detected 2 bit error */
Scott Wood52ab7ce2016-05-30 13:57:58 -0500181 return -EBADMSG;
Dirk Behme778933f2008-12-14 09:47:16 +0100182 }
183 }
184 return 0;
185}
186
187/*
pekon guptaeff10ee2013-11-19 11:02:15 +0530188 * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write
Andreas Bießmann82a65472013-04-05 04:55:21 +0000189 * @mtd: MTD device structure
190 * @mode: Read/Write mode
191 */
192__maybe_unused
pekon guptaeff10ee2013-11-19 11:02:15 +0530193static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
Andreas Bießmann82a65472013-04-05 04:55:21 +0000194{
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200195 struct nand_chip *nand = mtd_to_nand(mtd);
196 struct omap_nand_info *info = nand_get_controller_data(nand);
pekon guptaeff10ee2013-11-19 11:02:15 +0530197 unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0;
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200198 u32 val;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000199
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200200 /* Clear ecc and enable bits */
201 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
202
203 /* program ecc and result sizes */
204 val = ((((nand->ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) |
205 ECC1RESULTSIZE);
206 writel(val, &gpmc_cfg->ecc_size_config);
207
208 switch (mode) {
209 case NAND_ECC_READ:
210 case NAND_ECC_WRITE:
211 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
pekon guptaeff10ee2013-11-19 11:02:15 +0530212 break;
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200213 case NAND_ECC_READSYN:
214 writel(ECCCLEAR, &gpmc_cfg->ecc_control);
pekon gupta046cf862014-06-02 17:14:42 +0530215 break;
pekon guptaeff10ee2013-11-19 11:02:15 +0530216 default:
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200217 printf("%s: error: unrecognized Mode[%d]!\n", __func__, mode);
218 break;
pekon gupta6bd91a82013-11-18 19:03:00 +0530219 }
Andreas Bießmann82a65472013-04-05 04:55:21 +0000220
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200221 /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
222 val = (dev_width << 7) | (info->cs << 1) | (0x1);
223 writel(val, &gpmc_cfg->ecc_config);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000224}
225
226/*
pekon gupta03742c92013-11-19 11:02:16 +0530227 * omap_calculate_ecc - Read ECC result
228 * @mtd: MTD structure
229 * @dat: unused
230 * @ecc_code: ecc_code buffer
231 * Using noninverted ECC can be considered ugly since writing a blank
232 * page ie. padding will clear the ECC bytes. This is no problem as
233 * long nobody is trying to write data on the seemingly unused page.
234 * Reading an erased page will produce an ECC mismatch between
235 * generated and read ECC bytes that has to be dealt with separately.
236 * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
237 * is used, the result of read will be 0x0 while the ECC offsets of the
238 * spare area will be 0xFF which will result in an ECC mismatch.
Mansoor Ahamede5612512012-11-06 13:06:33 +0000239 */
pekon gupta03742c92013-11-19 11:02:16 +0530240static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
Mansoor Ahamede5612512012-11-06 13:06:33 +0000241 uint8_t *ecc_code)
242{
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200243 u32 val;
244
245 val = readl(&gpmc_cfg->ecc1_result);
246 ecc_code[0] = val & 0xFF;
247 ecc_code[1] = (val >> 16) & 0xFF;
248 ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
249
250 return 0;
251}
252
253/* GPMC ecc engine settings for read */
254#define BCH_WRAPMODE_1 1 /* BCH wrap mode 1 */
255#define BCH8R_ECC_SIZE0 0x1a /* ecc_size0 = 26 */
256#define BCH8R_ECC_SIZE1 0x2 /* ecc_size1 = 2 */
257#define BCH4R_ECC_SIZE0 0xd /* ecc_size0 = 13 */
258#define BCH4R_ECC_SIZE1 0x3 /* ecc_size1 = 3 */
259
260/* GPMC ecc engine settings for write */
261#define BCH_WRAPMODE_6 6 /* BCH wrap mode 6 */
262#define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */
263#define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */
264
265/**
266 * omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation
267 * @mtd: MTD device structure
268 * @mode: Read/Write mode
269 *
270 * When using BCH with SW correction (i.e. no ELM), sector size is set
271 * to 512 bytes and we use BCH_WRAPMODE_6 wrapping mode
272 * for both reading and writing with:
273 * eccsize0 = 0 (no additional protected byte in spare area)
274 * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
275 */
276static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd,
277 int mode)
278{
279 unsigned int bch_type;
280 unsigned int dev_width, nsectors;
Scott Wood17fed142016-05-30 13:57:56 -0500281 struct nand_chip *chip = mtd_to_nand(mtd);
282 struct omap_nand_info *info = nand_get_controller_data(chip);
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200283 u32 val, wr_mode;
284 unsigned int ecc_size1, ecc_size0;
285
286 /* GPMC configurations for calculating ECC */
287 switch (info->ecc_scheme) {
288 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
289 bch_type = 1;
290 nsectors = 1;
291 wr_mode = BCH_WRAPMODE_6;
292 ecc_size0 = BCH_ECC_SIZE0;
293 ecc_size1 = BCH_ECC_SIZE1;
294 break;
295 case OMAP_ECC_BCH8_CODE_HW:
296 bch_type = 1;
297 nsectors = chip->ecc.steps;
298 if (mode == NAND_ECC_READ) {
299 wr_mode = BCH_WRAPMODE_1;
300 ecc_size0 = BCH8R_ECC_SIZE0;
301 ecc_size1 = BCH8R_ECC_SIZE1;
302 } else {
303 wr_mode = BCH_WRAPMODE_6;
304 ecc_size0 = BCH_ECC_SIZE0;
305 ecc_size1 = BCH_ECC_SIZE1;
306 }
307 break;
308 case OMAP_ECC_BCH16_CODE_HW:
309 bch_type = 0x2;
310 nsectors = chip->ecc.steps;
311 if (mode == NAND_ECC_READ) {
312 wr_mode = 0x01;
313 ecc_size0 = 52; /* ECC bits in nibbles per sector */
314 ecc_size1 = 0; /* non-ECC bits in nibbles per sector */
315 } else {
316 wr_mode = 0x01;
317 ecc_size0 = 0; /* extra bits in nibbles per sector */
318 ecc_size1 = 52; /* OOB bits in nibbles per sector */
319 }
320 break;
321 default:
322 return;
323 }
324
325 writel(ECCRESULTREG1, &gpmc_cfg->ecc_control);
326
327 /* Configure ecc size for BCH */
328 val = (ecc_size1 << ECCSIZE1_SHIFT) | (ecc_size0 << ECCSIZE0_SHIFT);
329 writel(val, &gpmc_cfg->ecc_size_config);
330
331 dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
332
333 /* BCH configuration */
334 val = ((1 << 16) | /* enable BCH */
335 (bch_type << 12) | /* BCH4/BCH8/BCH16 */
336 (wr_mode << 8) | /* wrap mode */
337 (dev_width << 7) | /* bus width */
338 (((nsectors - 1) & 0x7) << 4) | /* number of sectors */
339 (info->cs << 1) | /* ECC CS */
340 (0x1)); /* enable ECC */
341
342 writel(val, &gpmc_cfg->ecc_config);
343
344 /* Clear ecc and enable bits */
345 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
346}
347
348/**
349 * _omap_calculate_ecc_bch - Generate BCH ECC bytes for one sector
350 * @mtd: MTD device structure
351 * @dat: The pointer to data on which ecc is computed
352 * @ecc_code: The ecc_code buffer
353 * @sector: The sector number (for a multi sector page)
354 *
355 * Support calculating of BCH4/8/16 ECC vectors for one sector
356 * within a page. Sector number is in @sector.
357 */
358static int _omap_calculate_ecc_bch(struct mtd_info *mtd, const u8 *dat,
359 u8 *ecc_code, int sector)
360{
361 struct nand_chip *chip = mtd_to_nand(mtd);
362 struct omap_nand_info *info = nand_get_controller_data(chip);
Ladislav Michld5b1c272016-07-12 20:28:16 +0200363 const uint32_t *ptr;
364 uint32_t val = 0;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000365 int8_t i = 0, j;
366
pekon guptaaa168482014-04-11 12:55:33 +0530367 switch (info->ecc_scheme) {
pekon gupta03742c92013-11-19 11:02:16 +0530368#ifdef CONFIG_BCH
369 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
370#endif
371 case OMAP_ECC_BCH8_CODE_HW:
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200372 ptr = &gpmc_cfg->bch_result_0_3[sector].bch_result_x[3];
pekon gupta03742c92013-11-19 11:02:16 +0530373 val = readl(ptr);
374 ecc_code[i++] = (val >> 0) & 0xFF;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000375 ptr--;
376 for (j = 0; j < 3; j++) {
pekon gupta03742c92013-11-19 11:02:16 +0530377 val = readl(ptr);
378 ecc_code[i++] = (val >> 24) & 0xFF;
379 ecc_code[i++] = (val >> 16) & 0xFF;
380 ecc_code[i++] = (val >> 8) & 0xFF;
381 ecc_code[i++] = (val >> 0) & 0xFF;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000382 ptr--;
383 }
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200384
pekon gupta03742c92013-11-19 11:02:16 +0530385 break;
pekon gupta046cf862014-06-02 17:14:42 +0530386 case OMAP_ECC_BCH16_CODE_HW:
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200387 val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[2]);
pekon gupta046cf862014-06-02 17:14:42 +0530388 ecc_code[i++] = (val >> 8) & 0xFF;
389 ecc_code[i++] = (val >> 0) & 0xFF;
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200390 val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[1]);
pekon gupta046cf862014-06-02 17:14:42 +0530391 ecc_code[i++] = (val >> 24) & 0xFF;
392 ecc_code[i++] = (val >> 16) & 0xFF;
393 ecc_code[i++] = (val >> 8) & 0xFF;
394 ecc_code[i++] = (val >> 0) & 0xFF;
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200395 val = readl(&gpmc_cfg->bch_result_4_6[sector].bch_result_x[0]);
pekon gupta046cf862014-06-02 17:14:42 +0530396 ecc_code[i++] = (val >> 24) & 0xFF;
397 ecc_code[i++] = (val >> 16) & 0xFF;
398 ecc_code[i++] = (val >> 8) & 0xFF;
399 ecc_code[i++] = (val >> 0) & 0xFF;
400 for (j = 3; j >= 0; j--) {
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200401 val = readl(&gpmc_cfg->bch_result_0_3[sector].bch_result_x[j]
pekon gupta046cf862014-06-02 17:14:42 +0530402 );
403 ecc_code[i++] = (val >> 24) & 0xFF;
404 ecc_code[i++] = (val >> 16) & 0xFF;
405 ecc_code[i++] = (val >> 8) & 0xFF;
406 ecc_code[i++] = (val >> 0) & 0xFF;
407 }
408 break;
pekon gupta03742c92013-11-19 11:02:16 +0530409 default:
410 return -EINVAL;
411 }
412 /* ECC scheme specific syndrome customizations */
pekon guptaaa168482014-04-11 12:55:33 +0530413 switch (info->ecc_scheme) {
pekon gupta03742c92013-11-19 11:02:16 +0530414#ifdef CONFIG_BCH
415 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200416 /* Add constant polynomial to remainder, so that
417 * ECC of blank pages results in 0x0 on reading back
418 */
pekon gupta03742c92013-11-19 11:02:16 +0530419 for (i = 0; i < chip->ecc.bytes; i++)
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200420 ecc_code[i] ^= bch8_polynomial[i];
pekon gupta03742c92013-11-19 11:02:16 +0530421 break;
422#endif
423 case OMAP_ECC_BCH8_CODE_HW:
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200424 /* Set 14th ECC byte as 0x0 for ROM compatibility */
425 ecc_code[chip->ecc.bytes - 1] = 0x0;
pekon gupta03742c92013-11-19 11:02:16 +0530426 break;
pekon gupta046cf862014-06-02 17:14:42 +0530427 case OMAP_ECC_BCH16_CODE_HW:
428 break;
pekon gupta03742c92013-11-19 11:02:16 +0530429 default:
430 return -EINVAL;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000431 }
pekon gupta03742c92013-11-19 11:02:16 +0530432 return 0;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000433}
434
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200435/**
436 * omap_calculate_ecc_bch - ECC generator for 1 sector
437 * @mtd: MTD device structure
438 * @dat: The pointer to data on which ecc is computed
439 * @ecc_code: The ecc_code buffer
440 *
441 * Support calculating of BCH4/8/16 ECC vectors for one sector. This is used
442 * when SW based correction is required as ECC is required for one sector
443 * at a time.
444 */
445static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd,
446 const u_char *dat, u_char *ecc_calc)
447{
448 return _omap_calculate_ecc_bch(mtd, dat, ecc_calc, 0);
449}
450
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300451static inline void omap_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
452{
453 struct nand_chip *chip = mtd_to_nand(mtd);
454 struct omap_nand_info *info = nand_get_controller_data(chip);
455 u32 alignment = ((uintptr_t)buf | len) & 3;
456
457 if (alignment & 1)
458 readsb(info->fifo, buf, len);
459 else if (alignment & 3)
460 readsw(info->fifo, buf, len >> 1);
461 else
462 readsl(info->fifo, buf, len >> 2);
463}
464
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200465#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
466
467#define PREFETCH_CONFIG1_CS_SHIFT 24
468#define PREFETCH_FIFOTHRESHOLD_MAX 0x40
469#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8)
470#define PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
471#define PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
472#define ENABLE_PREFETCH (1 << 7)
473
474/**
475 * omap_prefetch_enable - configures and starts prefetch transfer
476 * @fifo_th: fifo threshold to be used for read/ write
477 * @count: number of bytes to be transferred
478 * @is_write: prefetch read(0) or write post(1) mode
479 * @cs: chip select to use
480 */
481static int omap_prefetch_enable(int fifo_th, unsigned int count, int is_write, int cs)
482{
483 uint32_t val;
484
485 if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
486 return -EINVAL;
487
488 if (readl(&gpmc_cfg->prefetch_control))
489 return -EBUSY;
490
491 /* Set the amount of bytes to be prefetched */
492 writel(count, &gpmc_cfg->prefetch_config2);
493
494 val = (cs << PREFETCH_CONFIG1_CS_SHIFT) | (is_write & 1) |
495 PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH;
496 writel(val, &gpmc_cfg->prefetch_config1);
497
498 /* Start the prefetch engine */
499 writel(1, &gpmc_cfg->prefetch_control);
500
501 return 0;
502}
503
504/**
505 * omap_prefetch_reset - disables and stops the prefetch engine
506 */
507static void omap_prefetch_reset(void)
508{
509 writel(0, &gpmc_cfg->prefetch_control);
510 writel(0, &gpmc_cfg->prefetch_config1);
511}
512
513static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int len)
514{
515 int ret;
516 uint32_t cnt;
Scott Wood17fed142016-05-30 13:57:56 -0500517 struct omap_nand_info *info = nand_get_controller_data(chip);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200518
519 ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0, info->cs);
520 if (ret < 0)
521 return ret;
522
523 do {
524 int i;
525
526 cnt = readl(&gpmc_cfg->prefetch_status);
527 cnt = PREFETCH_STATUS_FIFO_CNT(cnt);
528
529 for (i = 0; i < cnt / 4; i++) {
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300530 *buf++ = readl(info->fifo);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200531 len -= 4;
532 }
533 } while (len);
534
535 omap_prefetch_reset();
536
537 return 0;
538}
539
Jeroen Hofstee5e67ac72015-05-30 10:11:24 +0200540static void omap_nand_read_prefetch(struct mtd_info *mtd, uint8_t *buf, int len)
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200541{
542 int ret;
Roger Quadros3068f0f2022-10-11 14:50:01 +0300543 uintptr_t head, tail;
Scott Wood17fed142016-05-30 13:57:56 -0500544 struct nand_chip *chip = mtd_to_nand(mtd);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200545
546 /*
547 * If the destination buffer is unaligned, start with reading
548 * the overlap byte-wise.
549 */
Roger Quadros3068f0f2022-10-11 14:50:01 +0300550 head = ((uintptr_t)buf) % 4;
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200551 if (head) {
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300552 omap_nand_read_buf(mtd, buf, head);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200553 buf += head;
554 len -= head;
555 }
556
557 /*
558 * Only transfer multiples of 4 bytes in a pre-fetched fashion.
559 * If there's a residue, care for it byte-wise afterwards.
560 */
561 tail = len % 4;
562
Jeroen Hofstee5e67ac72015-05-30 10:11:24 +0200563 ret = __read_prefetch_aligned(chip, (uint32_t *)buf, len - tail);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200564 if (ret < 0) {
565 /* fallback in case the prefetch engine is busy */
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300566 omap_nand_read_buf(mtd, buf, len);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200567 } else if (tail) {
568 buf += len - tail;
Roger Quadros3b7aaa52022-10-11 14:50:02 +0300569 omap_nand_read_buf(mtd, buf, tail);
Jeroen Hofsteef2bf5712015-05-30 10:11:23 +0200570 }
571}
572#endif /* CONFIG_NAND_OMAP_GPMC_PREFETCH */
573
pekon gupta03742c92013-11-19 11:02:16 +0530574#ifdef CONFIG_NAND_OMAP_ELM
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200575
576/**
577 * omap_calculate_ecc_bch_multi - Generate ECC for multiple sectors
578 * @mtd: MTD device structure
579 * @dat: The pointer to data on which ecc is computed
580 * @ecc_code: The ecc_code buffer
581 *
582 * Support calculating of BCH4/8/16 ecc vectors for the entire page in one go.
583 */
584static int omap_calculate_ecc_bch_multi(struct mtd_info *mtd,
585 const u_char *dat, u_char *ecc_calc)
586{
587 struct nand_chip *chip = mtd_to_nand(mtd);
588 int eccbytes = chip->ecc.bytes;
589 unsigned long nsectors;
590 int i, ret;
591
592 nsectors = ((readl(&gpmc_cfg->ecc_config) >> 4) & 0x7) + 1;
593 for (i = 0; i < nsectors; i++) {
594 ret = _omap_calculate_ecc_bch(mtd, dat, ecc_calc, i);
595 if (ret)
596 return ret;
597
598 ecc_calc += eccbytes;
599 }
600
601 return 0;
602}
603
Mansoor Ahamede5612512012-11-06 13:06:33 +0000604/*
Jeroen Hofstee79369072014-10-08 22:57:42 +0200605 * omap_reverse_list - re-orders list elements in reverse order [internal]
606 * @list: pointer to start of list
607 * @length: length of list
608*/
609static void omap_reverse_list(u8 *list, unsigned int length)
610{
611 unsigned int i, j;
612 unsigned int half_length = length / 2;
613 u8 tmp;
614 for (i = 0, j = length - 1; i < half_length; i++, j--) {
615 tmp = list[i];
616 list[i] = list[j];
617 list[j] = tmp;
618 }
619}
620
621/*
Mansoor Ahamede5612512012-11-06 13:06:33 +0000622 * omap_correct_data_bch - Compares the ecc read from nand spare area
Vagrant Cascadianedfdb992016-04-30 19:18:00 -0700623 * with ECC registers values and corrects one bit error if it has occurred
Mansoor Ahamede5612512012-11-06 13:06:33 +0000624 *
625 * @mtd: MTD device structure
626 * @dat: page data
627 * @read_ecc: ecc read from nand flash (ignored)
628 * @calc_ecc: ecc read from ECC registers
629 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100630 * Return: 0 if data is OK or corrected, else returns -1
Mansoor Ahamede5612512012-11-06 13:06:33 +0000631 */
632static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
633 uint8_t *read_ecc, uint8_t *calc_ecc)
634{
Scott Wood17fed142016-05-30 13:57:56 -0500635 struct nand_chip *chip = mtd_to_nand(mtd);
636 struct omap_nand_info *info = nand_get_controller_data(chip);
pekon gupta3c43c5b2014-04-11 12:55:34 +0530637 struct nand_ecc_ctrl *ecc = &chip->ecc;
pekon guptab0f750a2013-11-19 11:02:17 +0530638 uint32_t error_count = 0, error_max;
pekon gupta046cf862014-06-02 17:14:42 +0530639 uint32_t error_loc[ELM_MAX_ERROR_COUNT];
pekon gupta9d4b7472014-04-11 12:55:32 +0530640 enum bch_level bch_type;
pekon guptab0f750a2013-11-19 11:02:17 +0530641 uint32_t i, ecc_flag = 0;
Guido Martínez20b27be2015-01-02 14:49:10 -0300642 uint8_t count;
pekon guptab0f750a2013-11-19 11:02:17 +0530643 uint32_t byte_pos, bit_pos;
Guido Martínez20b27be2015-01-02 14:49:10 -0300644 int err = 0;
pekon guptab0f750a2013-11-19 11:02:17 +0530645
646 /* check calculated ecc */
pekon gupta3c43c5b2014-04-11 12:55:34 +0530647 for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
pekon guptab0f750a2013-11-19 11:02:17 +0530648 if (calc_ecc[i] != 0x00)
David Rivshinefa78532021-11-18 13:25:24 -0500649 goto not_ecc_match;
pekon guptab0f750a2013-11-19 11:02:17 +0530650 }
David Rivshinefa78532021-11-18 13:25:24 -0500651 return 0;
652not_ecc_match:
Mansoor Ahamede5612512012-11-06 13:06:33 +0000653
David Rivshinefa78532021-11-18 13:25:24 -0500654 /* check for whether it's an erased-page */
655 for (i = 0; i < ecc->bytes; i++) {
Mansoor Ahamede5612512012-11-06 13:06:33 +0000656 if (read_ecc[i] != 0xff)
David Rivshinefa78532021-11-18 13:25:24 -0500657 goto not_erased;
pekon guptab0f750a2013-11-19 11:02:17 +0530658 }
David Rivshinefa78532021-11-18 13:25:24 -0500659 for (i = 0; i < SECTOR_BYTES; i++) {
660 if (dat[i] != 0xff)
661 goto not_erased;
662 }
663 return 0;
664not_erased:
665
666 /*
667 * Check for whether it's an erased page with a correctable
668 * number of bitflips. Erased pages have all 1's in the data,
669 * so we just compute the number of 0 bits in the data and
670 * see if it's under the correction threshold.
671 *
672 * NOTE: The check for a perfect erased page above is faster for
673 * the more common case, even though it's logically redundant.
674 */
675 for (i = 0; i < ecc->bytes; i++)
676 error_count += hweight8(~read_ecc[i]);
677
678 for (i = 0; i < SECTOR_BYTES; i++)
679 error_count += hweight8(~dat[i]);
680
681 if (error_count <= ecc->strength) {
682 memset(read_ecc, 0xFF, ecc->bytes);
683 memset(dat, 0xFF, SECTOR_BYTES);
684 debug("nand: %u bit-flip(s) corrected in erased page\n",
685 error_count);
686 return error_count;
687 }
Mansoor Ahamede5612512012-11-06 13:06:33 +0000688
Mansoor Ahamede5612512012-11-06 13:06:33 +0000689 /*
690 * while reading ECC result we read it in big endian.
691 * Hence while loading to ELM we have rotate to get the right endian.
692 */
pekon guptaaa168482014-04-11 12:55:33 +0530693 switch (info->ecc_scheme) {
pekon guptab0f750a2013-11-19 11:02:17 +0530694 case OMAP_ECC_BCH8_CODE_HW:
pekon gupta9d4b7472014-04-11 12:55:32 +0530695 bch_type = BCH_8_BIT;
pekon gupta3c43c5b2014-04-11 12:55:34 +0530696 omap_reverse_list(calc_ecc, ecc->bytes - 1);
pekon guptab0f750a2013-11-19 11:02:17 +0530697 break;
pekon gupta046cf862014-06-02 17:14:42 +0530698 case OMAP_ECC_BCH16_CODE_HW:
699 bch_type = BCH_16_BIT;
700 omap_reverse_list(calc_ecc, ecc->bytes);
701 break;
pekon guptab0f750a2013-11-19 11:02:17 +0530702 default:
703 return -EINVAL;
704 }
Mansoor Ahamede5612512012-11-06 13:06:33 +0000705 /* use elm module to check for errors */
pekon gupta9d4b7472014-04-11 12:55:32 +0530706 elm_config(bch_type);
David Rivshinefa78532021-11-18 13:25:24 -0500707 error_count = 0;
pekon guptacfe6b8a2014-04-11 12:55:35 +0530708 err = elm_check_error(calc_ecc, bch_type, &error_count, error_loc);
709 if (err)
710 return err;
711
Mansoor Ahamede5612512012-11-06 13:06:33 +0000712 /* correct bch error */
pekon guptab0f750a2013-11-19 11:02:17 +0530713 for (count = 0; count < error_count; count++) {
pekon guptaaa168482014-04-11 12:55:33 +0530714 switch (info->ecc_scheme) {
pekon gupta9d4b7472014-04-11 12:55:32 +0530715 case OMAP_ECC_BCH8_CODE_HW:
pekon guptab0f750a2013-11-19 11:02:17 +0530716 /* 14th byte in ECC is reserved to match ROM layout */
pekon gupta3c43c5b2014-04-11 12:55:34 +0530717 error_max = SECTOR_BYTES + (ecc->bytes - 1);
pekon guptab0f750a2013-11-19 11:02:17 +0530718 break;
pekon gupta046cf862014-06-02 17:14:42 +0530719 case OMAP_ECC_BCH16_CODE_HW:
720 error_max = SECTOR_BYTES + ecc->bytes;
721 break;
pekon guptab0f750a2013-11-19 11:02:17 +0530722 default:
723 return -EINVAL;
724 }
725 byte_pos = error_max - (error_loc[count] / 8) - 1;
726 bit_pos = error_loc[count] % 8;
727 if (byte_pos < SECTOR_BYTES) {
728 dat[byte_pos] ^= 1 << bit_pos;
Ezequiel García69cf8ad2015-10-04 18:34:42 -0300729 debug("nand: bit-flip corrected @data=%d\n", byte_pos);
pekon guptab0f750a2013-11-19 11:02:17 +0530730 } else if (byte_pos < error_max) {
Belisko Marek9ab54142014-04-25 12:00:07 +0200731 read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos;
Ezequiel García69cf8ad2015-10-04 18:34:42 -0300732 debug("nand: bit-flip corrected @oob=%d\n", byte_pos -
pekon guptab0f750a2013-11-19 11:02:17 +0530733 SECTOR_BYTES);
734 } else {
735 err = -EBADMSG;
736 printf("nand: error: invalid bit-flip location\n");
737 }
738 }
739 return (err) ? err : error_count;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000740}
Mansoor Ahamede5612512012-11-06 13:06:33 +0000741
742/**
743 * omap_read_page_bch - hardware ecc based page read function
744 * @mtd: mtd info structure
745 * @chip: nand chip info structure
746 * @buf: buffer to store read data
Sergey Lapin3a38a552013-01-14 03:46:50 +0000747 * @oob_required: caller expects OOB data read to chip->oob_poi
Mansoor Ahamede5612512012-11-06 13:06:33 +0000748 * @page: page number to read
749 *
750 */
751static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
Sergey Lapin3a38a552013-01-14 03:46:50 +0000752 uint8_t *buf, int oob_required, int page)
Mansoor Ahamede5612512012-11-06 13:06:33 +0000753{
754 int i, eccsize = chip->ecc.size;
755 int eccbytes = chip->ecc.bytes;
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200756 int ecctotal = chip->ecc.total;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000757 int eccsteps = chip->ecc.steps;
758 uint8_t *p = buf;
759 uint8_t *ecc_calc = chip->buffers->ecccalc;
760 uint8_t *ecc_code = chip->buffers->ecccode;
761 uint32_t *eccpos = chip->ecc.layout->eccpos;
762 uint8_t *oob = chip->oob_poi;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000763 uint32_t oob_pos;
764
Mansoor Ahamede5612512012-11-06 13:06:33 +0000765 /* oob area start */
766 oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
767 oob += chip->ecc.layout->eccpos[0];
768
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200769 /* Enable ECC engine */
770 chip->ecc.hwctl(mtd, NAND_ECC_READ);
Mansoor Ahamede5612512012-11-06 13:06:33 +0000771
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200772 /* read entire page */
773 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
774 chip->read_buf(mtd, buf, mtd->writesize);
Mansoor Ahamede5612512012-11-06 13:06:33 +0000775
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200776 /* read all ecc bytes from oob area */
777 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
778 chip->read_buf(mtd, oob, ecctotal);
779
780 /* Calculate ecc bytes */
781 omap_calculate_ecc_bch_multi(mtd, buf, ecc_calc);
Mansoor Ahamede5612512012-11-06 13:06:33 +0000782
783 for (i = 0; i < chip->ecc.total; i++)
784 ecc_code[i] = chip->oob_poi[eccpos[i]];
785
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200786 /* error detect & correct */
Mansoor Ahamede5612512012-11-06 13:06:33 +0000787 eccsteps = chip->ecc.steps;
788 p = buf;
789
790 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
791 int stat;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000792 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
793 if (stat < 0)
794 mtd->ecc_stats.failed++;
795 else
796 mtd->ecc_stats.corrected += stat;
797 }
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200798
Mansoor Ahamede5612512012-11-06 13:06:33 +0000799 return 0;
800}
pekon gupta6bd91a82013-11-18 19:03:00 +0530801#endif /* CONFIG_NAND_OMAP_ELM */
Mansoor Ahamede5612512012-11-06 13:06:33 +0000802
Andreas Bießmann82a65472013-04-05 04:55:21 +0000803/*
804 * OMAP3 BCH8 support (with BCH library)
805 */
pekon gupta6bd91a82013-11-18 19:03:00 +0530806#ifdef CONFIG_BCH
Andreas Bießmann82a65472013-04-05 04:55:21 +0000807/**
pekon gupta6bd91a82013-11-18 19:03:00 +0530808 * omap_correct_data_bch_sw - Decode received data and correct errors
Andreas Bießmann82a65472013-04-05 04:55:21 +0000809 * @mtd: MTD device structure
810 * @data: page data
811 * @read_ecc: ecc read from nand flash
812 * @calc_ecc: ecc read from HW ECC registers
813 */
pekon gupta6bd91a82013-11-18 19:03:00 +0530814static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data,
Andreas Bießmann82a65472013-04-05 04:55:21 +0000815 u_char *read_ecc, u_char *calc_ecc)
816{
817 int i, count;
818 /* cannot correct more than 8 errors */
819 unsigned int errloc[8];
Scott Wood17fed142016-05-30 13:57:56 -0500820 struct nand_chip *chip = mtd_to_nand(mtd);
821 struct omap_nand_info *info = nand_get_controller_data(chip);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000822
Ladislav Michl6cc51852017-01-09 11:15:14 +0100823 count = decode_bch(info->control, NULL, SECTOR_BYTES,
824 read_ecc, calc_ecc, NULL, errloc);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000825 if (count > 0) {
826 /* correct errors */
827 for (i = 0; i < count; i++) {
828 /* correct data only, not ecc bytes */
Ladislav Michl6cc51852017-01-09 11:15:14 +0100829 if (errloc[i] < SECTOR_BYTES << 3)
830 data[errloc[i] >> 3] ^= 1 << (errloc[i] & 7);
Ezequiel García69cf8ad2015-10-04 18:34:42 -0300831 debug("corrected bitflip %u\n", errloc[i]);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000832#ifdef DEBUG
833 puts("read_ecc: ");
834 /*
835 * BCH8 have 13 bytes of ECC; BCH4 needs adoption
836 * here!
837 */
838 for (i = 0; i < 13; i++)
839 printf("%02x ", read_ecc[i]);
840 puts("\n");
841 puts("calc_ecc: ");
842 for (i = 0; i < 13; i++)
843 printf("%02x ", calc_ecc[i]);
844 puts("\n");
845#endif
846 }
847 } else if (count < 0) {
848 puts("ecc unrecoverable error\n");
849 }
850 return count;
851}
852
853/**
854 * omap_free_bch - Release BCH ecc resources
855 * @mtd: MTD device structure
856 */
857static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
858{
Scott Wood17fed142016-05-30 13:57:56 -0500859 struct nand_chip *chip = mtd_to_nand(mtd);
860 struct omap_nand_info *info = nand_get_controller_data(chip);
Andreas Bießmann82a65472013-04-05 04:55:21 +0000861
pekon guptaaa168482014-04-11 12:55:33 +0530862 if (info->control) {
863 free_bch(info->control);
864 info->control = NULL;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000865 }
866}
pekon gupta6bd91a82013-11-18 19:03:00 +0530867#endif /* CONFIG_BCH */
868
869/**
870 * omap_select_ecc_scheme - configures driver for particular ecc-scheme
871 * @nand: NAND chip device structure
872 * @ecc_scheme: ecc scheme to configure
873 * @pagesize: number of main-area bytes per page of NAND device
874 * @oobsize: number of OOB/spare bytes per page of NAND device
875 */
876static int omap_select_ecc_scheme(struct nand_chip *nand,
877 enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
Scott Wood17fed142016-05-30 13:57:56 -0500878 struct omap_nand_info *info = nand_get_controller_data(nand);
Roger Quadros224add22022-10-11 14:50:06 +0300879 struct nand_ecclayout *ecclayout = nand->ecc.layout;
pekon gupta6bd91a82013-11-18 19:03:00 +0530880 int eccsteps = pagesize / SECTOR_BYTES;
881 int i;
882
883 switch (ecc_scheme) {
884 case OMAP_ECC_HAM1_CODE_SW:
885 debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n");
886 /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are
887 * initialized in nand_scan_tail(), so just set ecc.mode */
pekon guptaaa168482014-04-11 12:55:33 +0530888 info->control = NULL;
pekon gupta6bd91a82013-11-18 19:03:00 +0530889 nand->ecc.mode = NAND_ECC_SOFT;
890 nand->ecc.layout = NULL;
Nikita Kiryanov4110c822013-12-12 15:19:31 +0200891 nand->ecc.size = 0;
pekon gupta6bd91a82013-11-18 19:03:00 +0530892 break;
893
894 case OMAP_ECC_HAM1_CODE_HW:
895 debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n");
896 /* check ecc-scheme requirements before updating ecc info */
897 if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
898 printf("nand: error: insufficient OOB: require=%d\n", (
899 (3 * eccsteps) + BADBLOCK_MARKER_LENGTH));
900 return -EINVAL;
901 }
pekon guptaaa168482014-04-11 12:55:33 +0530902 info->control = NULL;
pekon gupta6bd91a82013-11-18 19:03:00 +0530903 /* populate ecc specific fields */
Nikita Kiryanov2e18ff22013-12-17 15:18:01 +0200904 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
pekon gupta6bd91a82013-11-18 19:03:00 +0530905 nand->ecc.mode = NAND_ECC_HW;
906 nand->ecc.strength = 1;
907 nand->ecc.size = SECTOR_BYTES;
908 nand->ecc.bytes = 3;
909 nand->ecc.hwctl = omap_enable_hwecc;
910 nand->ecc.correct = omap_correct_data;
911 nand->ecc.calculate = omap_calculate_ecc;
912 /* define ecc-layout */
913 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
pekon guptaf0aff022013-12-05 17:54:21 +0530914 for (i = 0; i < ecclayout->eccbytes; i++) {
915 if (nand->options & NAND_BUSWIDTH_16)
916 ecclayout->eccpos[i] = i + 2;
917 else
918 ecclayout->eccpos[i] = i + 1;
919 }
pekon gupta6bd91a82013-11-18 19:03:00 +0530920 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
921 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
922 BADBLOCK_MARKER_LENGTH;
pekon gupta6bd91a82013-11-18 19:03:00 +0530923 break;
924
925 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
926#ifdef CONFIG_BCH
927 debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
928 /* check ecc-scheme requirements before updating ecc info */
929 if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
930 printf("nand: error: insufficient OOB: require=%d\n", (
931 (13 * eccsteps) + BADBLOCK_MARKER_LENGTH));
932 return -EINVAL;
933 }
934 /* check if BCH S/W library can be used for error detection */
pekon guptaaa168482014-04-11 12:55:33 +0530935 info->control = init_bch(13, 8, 0x201b);
936 if (!info->control) {
pekon gupta6bd91a82013-11-18 19:03:00 +0530937 printf("nand: error: could not init_bch()\n");
938 return -ENODEV;
939 }
pekon gupta6bd91a82013-11-18 19:03:00 +0530940 /* populate ecc specific fields */
Nikita Kiryanov2e18ff22013-12-17 15:18:01 +0200941 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
pekon gupta6bd91a82013-11-18 19:03:00 +0530942 nand->ecc.mode = NAND_ECC_HW;
943 nand->ecc.strength = 8;
944 nand->ecc.size = SECTOR_BYTES;
945 nand->ecc.bytes = 13;
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200946 nand->ecc.hwctl = omap_enable_hwecc_bch;
pekon gupta6bd91a82013-11-18 19:03:00 +0530947 nand->ecc.correct = omap_correct_data_bch_sw;
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200948 nand->ecc.calculate = omap_calculate_ecc_bch;
pekon gupta6bd91a82013-11-18 19:03:00 +0530949 /* define ecc-layout */
950 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
951 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
952 for (i = 1; i < ecclayout->eccbytes; i++) {
953 if (i % nand->ecc.bytes)
954 ecclayout->eccpos[i] =
955 ecclayout->eccpos[i - 1] + 1;
956 else
957 ecclayout->eccpos[i] =
958 ecclayout->eccpos[i - 1] + 2;
959 }
960 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
961 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
962 BADBLOCK_MARKER_LENGTH;
pekon gupta6bd91a82013-11-18 19:03:00 +0530963 break;
964#else
965 printf("nand: error: CONFIG_BCH required for ECC\n");
966 return -EINVAL;
967#endif
968
969 case OMAP_ECC_BCH8_CODE_HW:
970#ifdef CONFIG_NAND_OMAP_ELM
971 debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n");
972 /* check ecc-scheme requirements before updating ecc info */
973 if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
974 printf("nand: error: insufficient OOB: require=%d\n", (
975 (14 * eccsteps) + BADBLOCK_MARKER_LENGTH));
976 return -EINVAL;
977 }
978 /* intialize ELM for ECC error detection */
979 elm_init();
pekon guptaaa168482014-04-11 12:55:33 +0530980 info->control = NULL;
pekon gupta6bd91a82013-11-18 19:03:00 +0530981 /* populate ecc specific fields */
Nikita Kiryanov2e18ff22013-12-17 15:18:01 +0200982 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
pekon gupta6bd91a82013-11-18 19:03:00 +0530983 nand->ecc.mode = NAND_ECC_HW;
984 nand->ecc.strength = 8;
985 nand->ecc.size = SECTOR_BYTES;
986 nand->ecc.bytes = 14;
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200987 nand->ecc.hwctl = omap_enable_hwecc_bch;
pekon gupta6bd91a82013-11-18 19:03:00 +0530988 nand->ecc.correct = omap_correct_data_bch;
Roger Quadrosaa418fb2022-12-20 12:21:56 +0200989 nand->ecc.calculate = omap_calculate_ecc_bch;
pekon gupta6bd91a82013-11-18 19:03:00 +0530990 nand->ecc.read_page = omap_read_page_bch;
991 /* define ecc-layout */
992 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
993 for (i = 0; i < ecclayout->eccbytes; i++)
994 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
995 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
996 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
997 BADBLOCK_MARKER_LENGTH;
pekon gupta6bd91a82013-11-18 19:03:00 +0530998 break;
999#else
1000 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
1001 return -EINVAL;
1002#endif
1003
pekon gupta046cf862014-06-02 17:14:42 +05301004 case OMAP_ECC_BCH16_CODE_HW:
1005#ifdef CONFIG_NAND_OMAP_ELM
1006 debug("nand: using OMAP_ECC_BCH16_CODE_HW\n");
1007 /* check ecc-scheme requirements before updating ecc info */
1008 if ((26 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
1009 printf("nand: error: insufficient OOB: require=%d\n", (
1010 (26 * eccsteps) + BADBLOCK_MARKER_LENGTH));
1011 return -EINVAL;
1012 }
1013 /* intialize ELM for ECC error detection */
1014 elm_init();
1015 /* populate ecc specific fields */
1016 nand->ecc.mode = NAND_ECC_HW;
1017 nand->ecc.size = SECTOR_BYTES;
1018 nand->ecc.bytes = 26;
1019 nand->ecc.strength = 16;
Roger Quadrosaa418fb2022-12-20 12:21:56 +02001020 nand->ecc.hwctl = omap_enable_hwecc_bch;
pekon gupta046cf862014-06-02 17:14:42 +05301021 nand->ecc.correct = omap_correct_data_bch;
Roger Quadrosaa418fb2022-12-20 12:21:56 +02001022 nand->ecc.calculate = omap_calculate_ecc_bch;
pekon gupta046cf862014-06-02 17:14:42 +05301023 nand->ecc.read_page = omap_read_page_bch;
1024 /* define ecc-layout */
1025 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
1026 for (i = 0; i < ecclayout->eccbytes; i++)
1027 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
1028 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
1029 ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes -
1030 BADBLOCK_MARKER_LENGTH;
1031 break;
1032#else
1033 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
1034 return -EINVAL;
1035#endif
pekon gupta6bd91a82013-11-18 19:03:00 +05301036 default:
1037 debug("nand: error: ecc scheme not enabled or supported\n");
1038 return -EINVAL;
1039 }
Nikita Kiryanove8167892013-12-16 19:19:01 +02001040
1041 /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */
1042 if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW)
1043 nand->ecc.layout = ecclayout;
1044
pekon guptaaa168482014-04-11 12:55:33 +05301045 info->ecc_scheme = ecc_scheme;
pekon gupta6bd91a82013-11-18 19:03:00 +05301046 return 0;
1047}
Andreas Bießmann82a65472013-04-05 04:55:21 +00001048
Simon Schwarz4f62e982011-09-14 15:30:16 -04001049#ifndef CONFIG_SPL_BUILD
Dirk Behme778933f2008-12-14 09:47:16 +01001050/*
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +00001051 * omap_nand_switch_ecc - switch the ECC operation between different engines
1052 * (h/w and s/w) and different algorithms (hamming and BCHx)
Dirk Behme778933f2008-12-14 09:47:16 +01001053 *
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +00001054 * @hardware - true if one of the HW engines should be used
1055 * @eccstrength - the number of bits that could be corrected
1056 * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16)
Dirk Behme778933f2008-12-14 09:47:16 +01001057 */
pekon gupta6bd91a82013-11-18 19:03:00 +05301058int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
Dirk Behme778933f2008-12-14 09:47:16 +01001059{
1060 struct nand_chip *nand;
Mugunthan V N7b670cc2017-06-26 19:12:51 -05001061 struct mtd_info *mtd = get_nand_dev_by_index(nand_curr_device);
pekon gupta6bd91a82013-11-18 19:03:00 +05301062 int err = 0;
Dirk Behme778933f2008-12-14 09:47:16 +01001063
Mugunthan V N7b670cc2017-06-26 19:12:51 -05001064 if (!mtd) {
pekon gupta6bd91a82013-11-18 19:03:00 +05301065 printf("nand: error: no NAND devices found\n");
1066 return -ENODEV;
Dirk Behme778933f2008-12-14 09:47:16 +01001067 }
1068
Scott Wood17fed142016-05-30 13:57:56 -05001069 nand = mtd_to_nand(mtd);
Dirk Behme778933f2008-12-14 09:47:16 +01001070 nand->options |= NAND_OWN_BUFFERS;
Jeroen Hofstee96306f22014-01-15 17:58:54 +01001071 nand->options &= ~NAND_SUBPAGE_READ;
Dirk Behme778933f2008-12-14 09:47:16 +01001072 /* Setup the ecc configurations again */
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +00001073 if (hardware) {
1074 if (eccstrength == 1) {
pekon gupta6bd91a82013-11-18 19:03:00 +05301075 err = omap_select_ecc_scheme(nand,
1076 OMAP_ECC_HAM1_CODE_HW,
1077 mtd->writesize, mtd->oobsize);
1078 } else if (eccstrength == 8) {
1079 err = omap_select_ecc_scheme(nand,
1080 OMAP_ECC_BCH8_CODE_HW,
1081 mtd->writesize, mtd->oobsize);
Heiko Schocher5bf904c2016-06-07 08:55:42 +02001082 } else if (eccstrength == 16) {
1083 err = omap_select_ecc_scheme(nand,
1084 OMAP_ECC_BCH16_CODE_HW,
1085 mtd->writesize, mtd->oobsize);
pekon gupta6bd91a82013-11-18 19:03:00 +05301086 } else {
1087 printf("nand: error: unsupported ECC scheme\n");
1088 return -EINVAL;
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +00001089 }
Dirk Behme778933f2008-12-14 09:47:16 +01001090 } else {
Ash Charles4a5faa82015-02-18 11:25:11 -08001091 if (eccstrength == 1) {
1092 err = omap_select_ecc_scheme(nand,
1093 OMAP_ECC_HAM1_CODE_SW,
1094 mtd->writesize, mtd->oobsize);
1095 } else if (eccstrength == 8) {
1096 err = omap_select_ecc_scheme(nand,
1097 OMAP_ECC_BCH8_CODE_HW_DETECTION_SW,
pekon gupta6bd91a82013-11-18 19:03:00 +05301098 mtd->writesize, mtd->oobsize);
Ash Charles4a5faa82015-02-18 11:25:11 -08001099 } else {
1100 printf("nand: error: unsupported ECC scheme\n");
1101 return -EINVAL;
1102 }
Dirk Behme778933f2008-12-14 09:47:16 +01001103 }
1104
1105 /* Update NAND handling after ECC mode switch */
pekon gupta6bd91a82013-11-18 19:03:00 +05301106 if (!err)
1107 err = nand_scan_tail(mtd);
1108 return err;
Dirk Behme778933f2008-12-14 09:47:16 +01001109}
Simon Schwarz4f62e982011-09-14 15:30:16 -04001110#endif /* CONFIG_SPL_BUILD */
Dirk Behme778933f2008-12-14 09:47:16 +01001111
1112/*
1113 * Board-specific NAND initialization. The following members of the
1114 * argument are board-specific:
1115 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
1116 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
1117 * - cmd_ctrl: hardwarespecific function for accesing control-lines
1118 * - waitfunc: hardwarespecific function for accesing device ready/busy line
1119 * - ecc.hwctl: function to enable (reset) hardware ecc generator
1120 * - ecc.mode: mode of ecc, see defines
1121 * - chip_delay: chip dependent delay for transfering data from array to
1122 * read regs (tR)
1123 * - options: various chip options. They can partly be set to inform
1124 * nand_scan about special functionality. See the defines for further
1125 * explanation
1126 */
Roger Quadros80cf6372022-12-20 12:21:59 +02001127int gpmc_nand_init(struct nand_chip *nand)
Dirk Behme778933f2008-12-14 09:47:16 +01001128{
1129 int32_t gpmc_config = 0;
Rostislav Lisovy77cdf8a2014-09-02 16:23:58 +02001130 int cs = cs_next++;
pekon gupta6bd91a82013-11-18 19:03:00 +05301131 int err = 0;
Roger Quadros3b7aaa52022-10-11 14:50:02 +03001132 struct omap_nand_info *info;
1133
Dirk Behme778933f2008-12-14 09:47:16 +01001134 /*
1135 * xloader/Uboot's gpmc configuration would have configured GPMC for
1136 * nand type of memory. The following logic scans and latches on to the
1137 * first CS with NAND type memory.
1138 * TBD: need to make this logic generic to handle multiple CS NAND
1139 * devices.
1140 */
1141 while (cs < GPMC_MAX_CS) {
Dirk Behme778933f2008-12-14 09:47:16 +01001142 /* Check if NAND type is set */
Dirk Behmea4becd62009-08-08 09:30:22 +02001143 if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
Dirk Behme778933f2008-12-14 09:47:16 +01001144 /* Found it!! */
1145 break;
1146 }
1147 cs++;
1148 }
1149 if (cs >= GPMC_MAX_CS) {
pekon gupta6bd91a82013-11-18 19:03:00 +05301150 printf("nand: error: Unable to find NAND settings in "
Dirk Behme778933f2008-12-14 09:47:16 +01001151 "GPMC Configuration - quitting\n");
1152 return -ENODEV;
1153 }
1154
Dirk Behmea4becd62009-08-08 09:30:22 +02001155 gpmc_config = readl(&gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +01001156 /* Disable Write protect */
1157 gpmc_config |= 0x10;
Dirk Behmea4becd62009-08-08 09:30:22 +02001158 writel(gpmc_config, &gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +01001159
Dirk Behmea4becd62009-08-08 09:30:22 +02001160 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
1161 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Roger Quadros3b7aaa52022-10-11 14:50:02 +03001162
1163 info = &omap_nand_info[cs];
1164 info->control = NULL;
1165 info->cs = cs;
1166 info->ws = wscfg[cs];
Tom Rinia63bea92022-12-19 09:29:55 -05001167 info->fifo = (void __iomem *)CFG_SYS_NAND_BASE;
Scott Wood17fed142016-05-30 13:57:56 -05001168 nand_set_controller_data(nand, &omap_nand_info[cs]);
pekon gupta6bd91a82013-11-18 19:03:00 +05301169 nand->cmd_ctrl = omap_nand_hwcontrol;
1170 nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
Dirk Behme778933f2008-12-14 09:47:16 +01001171 nand->chip_delay = 100;
Roger Quadros224add22022-10-11 14:50:06 +03001172 nand->ecc.layout = kzalloc(sizeof(*nand->ecc.layout), GFP_KERNEL);
1173 if (!nand->ecc.layout)
1174 return -ENOMEM;
Mansoor Ahamede5612512012-11-06 13:06:33 +00001175
pekon gupta6250faf2014-05-06 00:46:19 +05301176 /* configure driver and controller based on NAND device bus-width */
1177 gpmc_config = readl(&gpmc_cfg->cs[cs].config1);
1178#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT)
1179 nand->options |= NAND_BUSWIDTH_16;
1180 writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1);
1181#else
1182 nand->options &= ~NAND_BUSWIDTH_16;
1183 writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1);
1184#endif
pekon gupta6bd91a82013-11-18 19:03:00 +05301185 /* select ECC scheme */
pekon gupta3ef49732013-11-18 19:03:01 +05301186#if defined(CONFIG_NAND_OMAP_ECCSCHEME)
1187 err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME,
pekon gupta6bd91a82013-11-18 19:03:00 +05301188 CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
pekon gupta3ef49732013-11-18 19:03:01 +05301189#else
1190 /* pagesize and oobsize are not required to configure sw ecc-scheme */
pekon gupta6bd91a82013-11-18 19:03:00 +05301191 err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
1192 0, 0);
Mansoor Ahamede5612512012-11-06 13:06:33 +00001193#endif
pekon gupta6bd91a82013-11-18 19:03:00 +05301194 if (err)
1195 return err;
Simon Schwarz4f62e982011-09-14 15:30:16 -04001196
Egli, Samuel8645fd92015-02-13 15:47:10 +01001197#ifdef CONFIG_NAND_OMAP_GPMC_PREFETCH
Jeroen Hofstee5e67ac72015-05-30 10:11:24 +02001198 nand->read_buf = omap_nand_read_prefetch;
Egli, Samuel8645fd92015-02-13 15:47:10 +01001199#else
Roger Quadros3b7aaa52022-10-11 14:50:02 +03001200 nand->read_buf = omap_nand_read_buf;
Simon Schwarz4f62e982011-09-14 15:30:16 -04001201#endif
Stefan Roesee05972f2014-11-13 03:43:39 +01001202
1203 nand->dev_ready = omap_dev_ready;
1204
Dirk Behme778933f2008-12-14 09:47:16 +01001205 return 0;
1206}
Roger Quadros80cf6372022-12-20 12:21:59 +02001207
1208/* First NAND chip for SPL use only */
1209static __maybe_unused struct nand_chip *nand_chip;
1210
1211#if CONFIG_IS_ENABLED(SYS_NAND_SELF_INIT)
1212
1213static int gpmc_nand_probe(struct udevice *dev)
1214{
1215 struct nand_chip *nand = dev_get_priv(dev);
1216 struct mtd_info *mtd = nand_to_mtd(nand);
1217 int ret;
1218
1219 gpmc_nand_init(nand);
1220
1221 ret = nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS);
1222 if (ret)
1223 return ret;
1224
1225 ret = nand_register(0, mtd);
1226 if (ret)
1227 return ret;
1228
1229 if (!nand_chip)
1230 nand_chip = nand;
1231
1232 return 0;
1233}
1234
1235static const struct udevice_id gpmc_nand_ids[] = {
1236 { .compatible = "ti,am64-nand" },
1237 { .compatible = "ti,omap2-nand" },
1238 { }
1239};
1240
1241U_BOOT_DRIVER(gpmc_nand) = {
1242 .name = "gpmc-nand",
1243 .id = UCLASS_MTD,
1244 .of_match = gpmc_nand_ids,
1245 .probe = gpmc_nand_probe,
1246 .priv_auto = sizeof(struct nand_chip),
1247};
1248
1249void board_nand_init(void)
1250{
1251 struct udevice *dev;
1252 int ret;
1253
Roger Quadrosa42b7702022-12-20 12:22:03 +02001254#ifdef CONFIG_NAND_OMAP_ELM
1255 ret = uclass_get_device_by_driver(UCLASS_MTD,
1256 DM_DRIVER_GET(gpmc_elm), &dev);
1257 if (ret && ret != -ENODEV) {
1258 pr_err("%s: Failed to get ELM device: %d\n", __func__, ret);
1259 return;
1260 }
1261#endif
1262
Roger Quadros80cf6372022-12-20 12:21:59 +02001263 ret = uclass_get_device_by_driver(UCLASS_MTD,
1264 DM_DRIVER_GET(gpmc_nand), &dev);
1265 if (ret && ret != -ENODEV)
1266 pr_err("%s: Failed to get GPMC device: %d\n", __func__, ret);
1267}
1268
1269#else
1270
1271int board_nand_init(struct nand_chip *nand)
1272{
1273 return gpmc_nand_init(nand);
1274}
1275
1276#endif /* CONFIG_SYS_NAND_SELF_INIT */
Roger Quadros685c4282022-12-20 12:22:00 +02001277
1278#if defined(CONFIG_SPL_NAND_INIT)
1279
1280/* nand_init() is provided by nand.c */
1281
1282/* Unselect after operation */
1283void nand_deselect(void)
1284{
1285 struct mtd_info *mtd = nand_to_mtd(nand_chip);
1286
1287 if (nand_chip->select_chip)
1288 nand_chip->select_chip(mtd, -1);
1289}
1290
1291static int nand_is_bad_block(int block)
1292{
1293 struct mtd_info *mtd = nand_to_mtd(nand_chip);
1294
1295 loff_t ofs = block * CONFIG_SYS_NAND_BLOCK_SIZE;
1296
1297 return nand_chip->block_bad(mtd, ofs);
1298}
1299
1300static int nand_read_page(int block, int page, uchar *dst)
1301{
Sean Anderson11a4c702023-11-04 16:37:41 -04001302 int page_addr = block * SYS_NAND_BLOCK_PAGES + page;
Roger Quadros685c4282022-12-20 12:22:00 +02001303 loff_t ofs = page_addr * CONFIG_SYS_NAND_PAGE_SIZE;
1304 int ret;
1305 size_t len = CONFIG_SYS_NAND_PAGE_SIZE;
1306 struct mtd_info *mtd = nand_to_mtd(nand_chip);
1307
1308 ret = nand_read(mtd, ofs, &len, dst);
1309 if (ret)
1310 printf("nand_read failed %d\n", ret);
1311
1312 return ret;
1313}
1314
1315#include "nand_spl_loaders.c"
1316#endif /* CONFIG_SPL_NAND_INIT */