~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/u-boot/drivers/mtd/nand/omap_gpmc.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * (C) Copyright 2004-2008 Texas Instruments, <www.ti.com>
 
3
 * Rohit Choraria <rohitkc@ti.com>
 
4
 *
 
5
 * SPDX-License-Identifier:     GPL-2.0+
 
6
 */
 
7
 
 
8
#include <common.h>
 
9
#include <asm/io.h>
 
10
#include <asm/errno.h>
 
11
#include <asm/arch/mem.h>
 
12
#include <linux/mtd/omap_gpmc.h>
 
13
#include <linux/mtd/nand_ecc.h>
 
14
#include <linux/bch.h>
 
15
#include <linux/compiler.h>
 
16
#include <nand.h>
 
17
#include <linux/mtd/omap_elm.h>
 
18
 
 
19
#define BADBLOCK_MARKER_LENGTH  2
 
20
#define SECTOR_BYTES            512
 
21
#define ECCCLEAR                (0x1 << 8)
 
22
#define ECCRESULTREG1           (0x1 << 0)
 
23
/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
 
24
#define BCH4_BIT_PAD            4
 
25
 
 
26
#ifdef CONFIG_BCH
 
27
static u8  bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
 
28
                                0x97, 0x79, 0xe5, 0x24, 0xb5};
 
29
#endif
 
30
static uint8_t cs;
 
31
static __maybe_unused struct nand_ecclayout omap_ecclayout;
 
32
 
 
33
/*
 
34
 * omap_nand_hwcontrol - Set the address pointers corretly for the
 
35
 *                      following address/data/command operation
 
36
 */
 
37
static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
 
38
                                uint32_t ctrl)
 
39
{
 
40
        register struct nand_chip *this = mtd->priv;
 
41
 
 
42
        /*
 
43
         * Point the IO_ADDR to DATA and ADDRESS registers instead
 
44
         * of chip address
 
45
         */
 
46
        switch (ctrl) {
 
47
        case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
 
48
                this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
 
49
                break;
 
50
        case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
 
51
                this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
 
52
                break;
 
53
        case NAND_CTRL_CHANGE | NAND_NCE:
 
54
                this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
 
55
                break;
 
56
        }
 
57
 
 
58
        if (cmd != NAND_CMD_NONE)
 
59
                writeb(cmd, this->IO_ADDR_W);
 
60
}
 
61
 
 
62
#ifdef CONFIG_SPL_BUILD
 
63
/* Check wait pin as dev ready indicator */
 
64
int omap_spl_dev_ready(struct mtd_info *mtd)
 
65
{
 
66
        return gpmc_cfg->status & (1 << 8);
 
67
}
 
68
#endif
 
69
 
 
70
 
 
71
/*
 
72
 * gen_true_ecc - This function will generate true ECC value, which
 
73
 * can be used when correcting data read from NAND flash memory core
 
74
 *
 
75
 * @ecc_buf:    buffer to store ecc code
 
76
 *
 
77
 * @return:     re-formatted ECC value
 
78
 */
 
79
static uint32_t gen_true_ecc(uint8_t *ecc_buf)
 
80
{
 
81
        return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
 
82
                ((ecc_buf[2] & 0x0F) << 8);
 
83
}
 
84
 
 
85
/*
 
86
 * omap_correct_data - Compares the ecc read from nand spare area with ECC
 
87
 * registers values and corrects one bit error if it has occured
 
88
 * Further details can be had from OMAP TRM and the following selected links:
 
89
 * http://en.wikipedia.org/wiki/Hamming_code
 
90
 * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf
 
91
 *
 
92
 * @mtd:                 MTD device structure
 
93
 * @dat:                 page data
 
94
 * @read_ecc:            ecc read from nand flash
 
95
 * @calc_ecc:            ecc read from ECC registers
 
96
 *
 
97
 * @return 0 if data is OK or corrected, else returns -1
 
98
 */
 
99
static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
 
100
                                uint8_t *read_ecc, uint8_t *calc_ecc)
 
101
{
 
102
        uint32_t orig_ecc, new_ecc, res, hm;
 
103
        uint16_t parity_bits, byte;
 
104
        uint8_t bit;
 
105
 
 
106
        /* Regenerate the orginal ECC */
 
107
        orig_ecc = gen_true_ecc(read_ecc);
 
108
        new_ecc = gen_true_ecc(calc_ecc);
 
109
        /* Get the XOR of real ecc */
 
110
        res = orig_ecc ^ new_ecc;
 
111
        if (res) {
 
112
                /* Get the hamming width */
 
113
                hm = hweight32(res);
 
114
                /* Single bit errors can be corrected! */
 
115
                if (hm == 12) {
 
116
                        /* Correctable data! */
 
117
                        parity_bits = res >> 16;
 
118
                        bit = (parity_bits & 0x7);
 
119
                        byte = (parity_bits >> 3) & 0x1FF;
 
120
                        /* Flip the bit to correct */
 
121
                        dat[byte] ^= (0x1 << bit);
 
122
                } else if (hm == 1) {
 
123
                        printf("Error: Ecc is wrong\n");
 
124
                        /* ECC itself is corrupted */
 
125
                        return 2;
 
126
                } else {
 
127
                        /*
 
128
                         * hm distance != parity pairs OR one, could mean 2 bit
 
129
                         * error OR potentially be on a blank page..
 
130
                         * orig_ecc: contains spare area data from nand flash.
 
131
                         * new_ecc: generated ecc while reading data area.
 
132
                         * Note: if the ecc = 0, all data bits from which it was
 
133
                         * generated are 0xFF.
 
134
                         * The 3 byte(24 bits) ecc is generated per 512byte
 
135
                         * chunk of a page. If orig_ecc(from spare area)
 
136
                         * is 0xFF && new_ecc(computed now from data area)=0x0,
 
137
                         * this means that data area is 0xFF and spare area is
 
138
                         * 0xFF. A sure sign of a erased page!
 
139
                         */
 
140
                        if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000))
 
141
                                return 0;
 
142
                        printf("Error: Bad compare! failed\n");
 
143
                        /* detected 2 bit error */
 
144
                        return -1;
 
145
                }
 
146
        }
 
147
        return 0;
 
148
}
 
149
 
 
150
/*
 
151
 * Generic BCH interface
 
152
 */
 
153
struct nand_bch_priv {
 
154
        uint8_t mode;
 
155
        uint8_t type;
 
156
        uint8_t nibbles;
 
157
        struct bch_control *control;
 
158
        enum omap_ecc ecc_scheme;
 
159
};
 
160
 
 
161
/* bch types */
 
162
#define ECC_BCH4        0
 
163
#define ECC_BCH8        1
 
164
#define ECC_BCH16       2
 
165
 
 
166
/* BCH nibbles for diff bch levels */
 
167
#define ECC_BCH4_NIBBLES        13
 
168
#define ECC_BCH8_NIBBLES        26
 
169
#define ECC_BCH16_NIBBLES       52
 
170
 
 
171
/*
 
172
 * This can be a single instance cause all current users have only one NAND
 
173
 * with nearly the same setup (BCH8, some with ELM and others with sw BCH
 
174
 * library).
 
175
 * When some users with other BCH strength will exists this have to change!
 
176
 */
 
177
static __maybe_unused struct nand_bch_priv bch_priv = {
 
178
        .type = ECC_BCH8,
 
179
        .nibbles = ECC_BCH8_NIBBLES,
 
180
        .control = NULL
 
181
};
 
182
 
 
183
/*
 
184
 * omap_reverse_list - re-orders list elements in reverse order [internal]
 
185
 * @list:       pointer to start of list
 
186
 * @length:     length of list
 
187
*/
 
188
void omap_reverse_list(u8 *list, unsigned int length)
 
189
{
 
190
        unsigned int i, j;
 
191
        unsigned int half_length = length / 2;
 
192
        u8 tmp;
 
193
        for (i = 0, j = length - 1; i < half_length; i++, j--) {
 
194
                tmp = list[i];
 
195
                list[i] = list[j];
 
196
                list[j] = tmp;
 
197
        }
 
198
}
 
199
 
 
200
/*
 
201
 * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write
 
202
 * @mtd:        MTD device structure
 
203
 * @mode:       Read/Write mode
 
204
 */
 
205
__maybe_unused
 
206
static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
 
207
{
 
208
        struct nand_chip        *nand   = mtd->priv;
 
209
        struct nand_bch_priv    *bch    = nand->priv;
 
210
        unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0;
 
211
        unsigned int ecc_algo = 0;
 
212
        unsigned int bch_type = 0;
 
213
        unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00;
 
214
        u32 ecc_size_config_val = 0;
 
215
        u32 ecc_config_val = 0;
 
216
 
 
217
        /* configure GPMC for specific ecc-scheme */
 
218
        switch (bch->ecc_scheme) {
 
219
        case OMAP_ECC_HAM1_CODE_SW:
 
220
                return;
 
221
        case OMAP_ECC_HAM1_CODE_HW:
 
222
                ecc_algo = 0x0;
 
223
                bch_type = 0x0;
 
224
                bch_wrapmode = 0x00;
 
225
                eccsize0 = 0xFF;
 
226
                eccsize1 = 0xFF;
 
227
                break;
 
228
        case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
 
229
        case OMAP_ECC_BCH8_CODE_HW:
 
230
                ecc_algo = 0x1;
 
231
                bch_type = 0x1;
 
232
                if (mode == NAND_ECC_WRITE) {
 
233
                        bch_wrapmode = 0x01;
 
234
                        eccsize0 = 0;  /* extra bits in nibbles per sector */
 
235
                        eccsize1 = 28; /* OOB bits in nibbles per sector */
 
236
                } else {
 
237
                        bch_wrapmode = 0x01;
 
238
                        eccsize0 = 26; /* ECC bits in nibbles per sector */
 
239
                        eccsize1 = 2;  /* non-ECC bits in nibbles per sector */
 
240
                }
 
241
                break;
 
242
        default:
 
243
                return;
 
244
        }
 
245
        /* Clear ecc and enable bits */
 
246
        writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
 
247
        /* Configure ecc size for BCH */
 
248
        ecc_size_config_val = (eccsize1 << 22) | (eccsize0 << 12);
 
249
        writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config);
 
250
 
 
251
        /* Configure device details for BCH engine */
 
252
        ecc_config_val = ((ecc_algo << 16)      | /* HAM1 | BCHx */
 
253
                        (bch_type << 12)        | /* BCH4/BCH8/BCH16 */
 
254
                        (bch_wrapmode << 8)     | /* wrap mode */
 
255
                        (dev_width << 7)        | /* bus width */
 
256
                        (0x0 << 4)              | /* number of sectors */
 
257
                        (cs <<  1)              | /* ECC CS */
 
258
                        (0x1));                   /* enable ECC */
 
259
        writel(ecc_config_val, &gpmc_cfg->ecc_config);
 
260
}
 
261
 
 
262
/*
 
263
 *  omap_calculate_ecc - Read ECC result
 
264
 *  @mtd:       MTD structure
 
265
 *  @dat:       unused
 
266
 *  @ecc_code:  ecc_code buffer
 
267
 *  Using noninverted ECC can be considered ugly since writing a blank
 
268
 *  page ie. padding will clear the ECC bytes. This is no problem as
 
269
 *  long nobody is trying to write data on the seemingly unused page.
 
270
 *  Reading an erased page will produce an ECC mismatch between
 
271
 *  generated and read ECC bytes that has to be dealt with separately.
 
272
 *  E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
 
273
 *  is used, the result of read will be 0x0 while the ECC offsets of the
 
274
 *  spare area will be 0xFF which will result in an ECC mismatch.
 
275
 */
 
276
static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
 
277
                                uint8_t *ecc_code)
 
278
{
 
279
        struct nand_chip *chip = mtd->priv;
 
280
        struct nand_bch_priv *bch = chip->priv;
 
281
        uint32_t *ptr, val = 0;
 
282
        int8_t i = 0, j;
 
283
 
 
284
        switch (bch->ecc_scheme) {
 
285
        case OMAP_ECC_HAM1_CODE_HW:
 
286
                val = readl(&gpmc_cfg->ecc1_result);
 
287
                ecc_code[0] = val & 0xFF;
 
288
                ecc_code[1] = (val >> 16) & 0xFF;
 
289
                ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
 
290
                break;
 
291
#ifdef CONFIG_BCH
 
292
        case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
 
293
#endif
 
294
        case OMAP_ECC_BCH8_CODE_HW:
 
295
                ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
 
296
                val = readl(ptr);
 
297
                ecc_code[i++] = (val >>  0) & 0xFF;
 
298
                ptr--;
 
299
                for (j = 0; j < 3; j++) {
 
300
                        val = readl(ptr);
 
301
                        ecc_code[i++] = (val >> 24) & 0xFF;
 
302
                        ecc_code[i++] = (val >> 16) & 0xFF;
 
303
                        ecc_code[i++] = (val >>  8) & 0xFF;
 
304
                        ecc_code[i++] = (val >>  0) & 0xFF;
 
305
                        ptr--;
 
306
                }
 
307
                break;
 
308
        default:
 
309
                return -EINVAL;
 
310
        }
 
311
        /* ECC scheme specific syndrome customizations */
 
312
        switch (bch->ecc_scheme) {
 
313
        case OMAP_ECC_HAM1_CODE_HW:
 
314
                break;
 
315
#ifdef CONFIG_BCH
 
316
        case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
 
317
 
 
318
                for (i = 0; i < chip->ecc.bytes; i++)
 
319
                        *(ecc_code + i) = *(ecc_code + i) ^
 
320
                                                bch8_polynomial[i];
 
321
                break;
 
322
#endif
 
323
        case OMAP_ECC_BCH8_CODE_HW:
 
324
                ecc_code[chip->ecc.bytes - 1] = 0x00;
 
325
                break;
 
326
        default:
 
327
                return -EINVAL;
 
328
        }
 
329
        return 0;
 
330
}
 
331
 
 
332
#ifdef CONFIG_NAND_OMAP_ELM
 
333
/*
 
334
 * omap_correct_data_bch - Compares the ecc read from nand spare area
 
335
 * with ECC registers values and corrects one bit error if it has occured
 
336
 *
 
337
 * @mtd:        MTD device structure
 
338
 * @dat:        page data
 
339
 * @read_ecc:   ecc read from nand flash (ignored)
 
340
 * @calc_ecc:   ecc read from ECC registers
 
341
 *
 
342
 * @return 0 if data is OK or corrected, else returns -1
 
343
 */
 
344
static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
 
345
                                uint8_t *read_ecc, uint8_t *calc_ecc)
 
346
{
 
347
        struct nand_chip *chip = mtd->priv;
 
348
        struct nand_bch_priv *bch = chip->priv;
 
349
        uint32_t eccbytes = chip->ecc.bytes;
 
350
        uint32_t error_count = 0, error_max;
 
351
        uint32_t error_loc[8];
 
352
        uint32_t i, ecc_flag = 0;
 
353
        uint8_t count, err = 0;
 
354
        uint32_t byte_pos, bit_pos;
 
355
 
 
356
        /* check calculated ecc */
 
357
        for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) {
 
358
                if (calc_ecc[i] != 0x00)
 
359
                        ecc_flag = 1;
 
360
        }
 
361
        if (!ecc_flag)
 
362
                return 0;
 
363
 
 
364
        /* check for whether its a erased-page */
 
365
        ecc_flag = 0;
 
366
        for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) {
 
367
                if (read_ecc[i] != 0xff)
 
368
                        ecc_flag = 1;
 
369
        }
 
370
        if (!ecc_flag)
 
371
                return 0;
 
372
 
 
373
        /*
 
374
         * while reading ECC result we read it in big endian.
 
375
         * Hence while loading to ELM we have rotate to get the right endian.
 
376
         */
 
377
        switch (bch->ecc_scheme) {
 
378
        case OMAP_ECC_BCH8_CODE_HW:
 
379
                omap_reverse_list(calc_ecc, eccbytes - 1);
 
380
                break;
 
381
        default:
 
382
                return -EINVAL;
 
383
        }
 
384
        /* use elm module to check for errors */
 
385
        elm_config((enum bch_level)(bch->type));
 
386
        if (elm_check_error(calc_ecc, bch->nibbles, &error_count, error_loc)) {
 
387
                printf("nand: error: uncorrectable ECC errors\n");
 
388
                return -EINVAL;
 
389
        }
 
390
        /* correct bch error */
 
391
        for (count = 0; count < error_count; count++) {
 
392
                switch (bch->type) {
 
393
                case ECC_BCH8:
 
394
                        /* 14th byte in ECC is reserved to match ROM layout */
 
395
                        error_max = SECTOR_BYTES + (eccbytes - 1);
 
396
                        break;
 
397
                default:
 
398
                        return -EINVAL;
 
399
                }
 
400
                byte_pos = error_max - (error_loc[count] / 8) - 1;
 
401
                bit_pos  = error_loc[count] % 8;
 
402
                if (byte_pos < SECTOR_BYTES) {
 
403
                        dat[byte_pos] ^= 1 << bit_pos;
 
404
                        printf("nand: bit-flip corrected @data=%d\n", byte_pos);
 
405
                } else if (byte_pos < error_max) {
 
406
                        read_ecc[byte_pos - SECTOR_BYTES] = 1 << bit_pos;
 
407
                        printf("nand: bit-flip corrected @oob=%d\n", byte_pos -
 
408
                                                                SECTOR_BYTES);
 
409
                } else {
 
410
                        err = -EBADMSG;
 
411
                        printf("nand: error: invalid bit-flip location\n");
 
412
                }
 
413
        }
 
414
        return (err) ? err : error_count;
 
415
}
 
416
 
 
417
/**
 
418
 * omap_read_page_bch - hardware ecc based page read function
 
419
 * @mtd:        mtd info structure
 
420
 * @chip:       nand chip info structure
 
421
 * @buf:        buffer to store read data
 
422
 * @oob_required: caller expects OOB data read to chip->oob_poi
 
423
 * @page:       page number to read
 
424
 *
 
425
 */
 
426
static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 
427
                                uint8_t *buf, int oob_required, int page)
 
428
{
 
429
        int i, eccsize = chip->ecc.size;
 
430
        int eccbytes = chip->ecc.bytes;
 
431
        int eccsteps = chip->ecc.steps;
 
432
        uint8_t *p = buf;
 
433
        uint8_t *ecc_calc = chip->buffers->ecccalc;
 
434
        uint8_t *ecc_code = chip->buffers->ecccode;
 
435
        uint32_t *eccpos = chip->ecc.layout->eccpos;
 
436
        uint8_t *oob = chip->oob_poi;
 
437
        uint32_t data_pos;
 
438
        uint32_t oob_pos;
 
439
 
 
440
        data_pos = 0;
 
441
        /* oob area start */
 
442
        oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
 
443
        oob += chip->ecc.layout->eccpos[0];
 
444
 
 
445
        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
 
446
                                oob += eccbytes) {
 
447
                chip->ecc.hwctl(mtd, NAND_ECC_READ);
 
448
                /* read data */
 
449
                chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, page);
 
450
                chip->read_buf(mtd, p, eccsize);
 
451
 
 
452
                /* read respective ecc from oob area */
 
453
                chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, page);
 
454
                chip->read_buf(mtd, oob, eccbytes);
 
455
                /* read syndrome */
 
456
                chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 
457
 
 
458
                data_pos += eccsize;
 
459
                oob_pos += eccbytes;
 
460
        }
 
461
 
 
462
        for (i = 0; i < chip->ecc.total; i++)
 
463
                ecc_code[i] = chip->oob_poi[eccpos[i]];
 
464
 
 
465
        eccsteps = chip->ecc.steps;
 
466
        p = buf;
 
467
 
 
468
        for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 
469
                int stat;
 
470
 
 
471
                stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
 
472
                if (stat < 0)
 
473
                        mtd->ecc_stats.failed++;
 
474
                else
 
475
                        mtd->ecc_stats.corrected += stat;
 
476
        }
 
477
        return 0;
 
478
}
 
479
#endif /* CONFIG_NAND_OMAP_ELM */
 
480
 
 
481
/*
 
482
 * OMAP3 BCH8 support (with BCH library)
 
483
 */
 
484
#ifdef CONFIG_BCH
 
485
/**
 
486
 * omap_correct_data_bch_sw - Decode received data and correct errors
 
487
 * @mtd: MTD device structure
 
488
 * @data: page data
 
489
 * @read_ecc: ecc read from nand flash
 
490
 * @calc_ecc: ecc read from HW ECC registers
 
491
 */
 
492
static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data,
 
493
                                 u_char *read_ecc, u_char *calc_ecc)
 
494
{
 
495
        int i, count;
 
496
        /* cannot correct more than 8 errors */
 
497
        unsigned int errloc[8];
 
498
        struct nand_chip *chip = mtd->priv;
 
499
        struct nand_bch_priv *chip_priv = chip->priv;
 
500
        struct bch_control *bch = chip_priv->control;
 
501
 
 
502
        count = decode_bch(bch, NULL, 512, read_ecc, calc_ecc, NULL, errloc);
 
503
        if (count > 0) {
 
504
                /* correct errors */
 
505
                for (i = 0; i < count; i++) {
 
506
                        /* correct data only, not ecc bytes */
 
507
                        if (errloc[i] < 8*512)
 
508
                                data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
 
509
                        printf("corrected bitflip %u\n", errloc[i]);
 
510
#ifdef DEBUG
 
511
                        puts("read_ecc: ");
 
512
                        /*
 
513
                         * BCH8 have 13 bytes of ECC; BCH4 needs adoption
 
514
                         * here!
 
515
                         */
 
516
                        for (i = 0; i < 13; i++)
 
517
                                printf("%02x ", read_ecc[i]);
 
518
                        puts("\n");
 
519
                        puts("calc_ecc: ");
 
520
                        for (i = 0; i < 13; i++)
 
521
                                printf("%02x ", calc_ecc[i]);
 
522
                        puts("\n");
 
523
#endif
 
524
                }
 
525
        } else if (count < 0) {
 
526
                puts("ecc unrecoverable error\n");
 
527
        }
 
528
        return count;
 
529
}
 
530
 
 
531
/**
 
532
 * omap_free_bch - Release BCH ecc resources
 
533
 * @mtd: MTD device structure
 
534
 */
 
535
static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
 
536
{
 
537
        struct nand_chip *chip = mtd->priv;
 
538
        struct nand_bch_priv *chip_priv = chip->priv;
 
539
        struct bch_control *bch = NULL;
 
540
 
 
541
        if (chip_priv)
 
542
                bch = chip_priv->control;
 
543
 
 
544
        if (bch) {
 
545
                free_bch(bch);
 
546
                chip_priv->control = NULL;
 
547
        }
 
548
}
 
549
#endif /* CONFIG_BCH */
 
550
 
 
551
/**
 
552
 * omap_select_ecc_scheme - configures driver for particular ecc-scheme
 
553
 * @nand: NAND chip device structure
 
554
 * @ecc_scheme: ecc scheme to configure
 
555
 * @pagesize: number of main-area bytes per page of NAND device
 
556
 * @oobsize: number of OOB/spare bytes per page of NAND device
 
557
 */
 
558
static int omap_select_ecc_scheme(struct nand_chip *nand,
 
559
        enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
 
560
        struct nand_bch_priv    *bch            = nand->priv;
 
561
        struct nand_ecclayout   *ecclayout      = &omap_ecclayout;
 
562
        int eccsteps = pagesize / SECTOR_BYTES;
 
563
        int i;
 
564
 
 
565
        switch (ecc_scheme) {
 
566
        case OMAP_ECC_HAM1_CODE_SW:
 
567
                debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n");
 
568
                /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are
 
569
                 * initialized in nand_scan_tail(), so just set ecc.mode */
 
570
                bch_priv.control        = NULL;
 
571
                bch_priv.type           = 0;
 
572
                nand->ecc.mode          = NAND_ECC_SOFT;
 
573
                nand->ecc.layout        = NULL;
 
574
                nand->ecc.size          = 0;
 
575
                bch->ecc_scheme         = OMAP_ECC_HAM1_CODE_SW;
 
576
                break;
 
577
 
 
578
        case OMAP_ECC_HAM1_CODE_HW:
 
579
                debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n");
 
580
                /* check ecc-scheme requirements before updating ecc info */
 
581
                if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
 
582
                        printf("nand: error: insufficient OOB: require=%d\n", (
 
583
                                (3 * eccsteps) + BADBLOCK_MARKER_LENGTH));
 
584
                        return -EINVAL;
 
585
                }
 
586
                bch_priv.control        = NULL;
 
587
                bch_priv.type           = 0;
 
588
                /* populate ecc specific fields */
 
589
                memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
 
590
                nand->ecc.mode          = NAND_ECC_HW;
 
591
                nand->ecc.strength      = 1;
 
592
                nand->ecc.size          = SECTOR_BYTES;
 
593
                nand->ecc.bytes         = 3;
 
594
                nand->ecc.hwctl         = omap_enable_hwecc;
 
595
                nand->ecc.correct       = omap_correct_data;
 
596
                nand->ecc.calculate     = omap_calculate_ecc;
 
597
                /* define ecc-layout */
 
598
                ecclayout->eccbytes     = nand->ecc.bytes * eccsteps;
 
599
                for (i = 0; i < ecclayout->eccbytes; i++) {
 
600
                        if (nand->options & NAND_BUSWIDTH_16)
 
601
                                ecclayout->eccpos[i] = i + 2;
 
602
                        else
 
603
                                ecclayout->eccpos[i] = i + 1;
 
604
                }
 
605
                ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
 
606
                ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
 
607
                                                BADBLOCK_MARKER_LENGTH;
 
608
                bch->ecc_scheme         = OMAP_ECC_HAM1_CODE_HW;
 
609
                break;
 
610
 
 
611
        case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
 
612
#ifdef CONFIG_BCH
 
613
                debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
 
614
                /* check ecc-scheme requirements before updating ecc info */
 
615
                if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
 
616
                        printf("nand: error: insufficient OOB: require=%d\n", (
 
617
                                (13 * eccsteps) + BADBLOCK_MARKER_LENGTH));
 
618
                        return -EINVAL;
 
619
                }
 
620
                /* check if BCH S/W library can be used for error detection */
 
621
                bch_priv.control = init_bch(13, 8, 0x201b);
 
622
                if (!bch_priv.control) {
 
623
                        printf("nand: error: could not init_bch()\n");
 
624
                        return -ENODEV;
 
625
                }
 
626
                bch_priv.type = ECC_BCH8;
 
627
                /* populate ecc specific fields */
 
628
                memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
 
629
                nand->ecc.mode          = NAND_ECC_HW;
 
630
                nand->ecc.strength      = 8;
 
631
                nand->ecc.size          = SECTOR_BYTES;
 
632
                nand->ecc.bytes         = 13;
 
633
                nand->ecc.hwctl         = omap_enable_hwecc;
 
634
                nand->ecc.correct       = omap_correct_data_bch_sw;
 
635
                nand->ecc.calculate     = omap_calculate_ecc;
 
636
                /* define ecc-layout */
 
637
                ecclayout->eccbytes     = nand->ecc.bytes * eccsteps;
 
638
                ecclayout->eccpos[0]    = BADBLOCK_MARKER_LENGTH;
 
639
                for (i = 1; i < ecclayout->eccbytes; i++) {
 
640
                        if (i % nand->ecc.bytes)
 
641
                                ecclayout->eccpos[i] =
 
642
                                                ecclayout->eccpos[i - 1] + 1;
 
643
                        else
 
644
                                ecclayout->eccpos[i] =
 
645
                                                ecclayout->eccpos[i - 1] + 2;
 
646
                }
 
647
                ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
 
648
                ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
 
649
                                                BADBLOCK_MARKER_LENGTH;
 
650
                bch->ecc_scheme         = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
 
651
                break;
 
652
#else
 
653
                printf("nand: error: CONFIG_BCH required for ECC\n");
 
654
                return -EINVAL;
 
655
#endif
 
656
 
 
657
        case OMAP_ECC_BCH8_CODE_HW:
 
658
#ifdef CONFIG_NAND_OMAP_ELM
 
659
                debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n");
 
660
                /* check ecc-scheme requirements before updating ecc info */
 
661
                if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
 
662
                        printf("nand: error: insufficient OOB: require=%d\n", (
 
663
                                (14 * eccsteps) + BADBLOCK_MARKER_LENGTH));
 
664
                        return -EINVAL;
 
665
                }
 
666
                /* intialize ELM for ECC error detection */
 
667
                elm_init();
 
668
                bch_priv.type           = ECC_BCH8;
 
669
                /* populate ecc specific fields */
 
670
                memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
 
671
                nand->ecc.mode          = NAND_ECC_HW;
 
672
                nand->ecc.strength      = 8;
 
673
                nand->ecc.size          = SECTOR_BYTES;
 
674
                nand->ecc.bytes         = 14;
 
675
                nand->ecc.hwctl         = omap_enable_hwecc;
 
676
                nand->ecc.correct       = omap_correct_data_bch;
 
677
                nand->ecc.calculate     = omap_calculate_ecc;
 
678
                nand->ecc.read_page     = omap_read_page_bch;
 
679
                /* define ecc-layout */
 
680
                ecclayout->eccbytes     = nand->ecc.bytes * eccsteps;
 
681
                for (i = 0; i < ecclayout->eccbytes; i++)
 
682
                        ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
 
683
                ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
 
684
                ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
 
685
                                                BADBLOCK_MARKER_LENGTH;
 
686
                bch->ecc_scheme         = OMAP_ECC_BCH8_CODE_HW;
 
687
                break;
 
688
#else
 
689
                printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
 
690
                return -EINVAL;
 
691
#endif
 
692
 
 
693
        default:
 
694
                debug("nand: error: ecc scheme not enabled or supported\n");
 
695
                return -EINVAL;
 
696
        }
 
697
 
 
698
        /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */
 
699
        if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW)
 
700
                nand->ecc.layout = ecclayout;
 
701
 
 
702
        return 0;
 
703
}
 
704
 
 
705
#ifndef CONFIG_SPL_BUILD
 
706
/*
 
707
 * omap_nand_switch_ecc - switch the ECC operation between different engines
 
708
 * (h/w and s/w) and different algorithms (hamming and BCHx)
 
709
 *
 
710
 * @hardware            - true if one of the HW engines should be used
 
711
 * @eccstrength         - the number of bits that could be corrected
 
712
 *                        (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16)
 
713
 */
 
714
int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
 
715
{
 
716
        struct nand_chip *nand;
 
717
        struct mtd_info *mtd;
 
718
        int err = 0;
 
719
 
 
720
        if (nand_curr_device < 0 ||
 
721
            nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
 
722
            !nand_info[nand_curr_device].name) {
 
723
                printf("nand: error: no NAND devices found\n");
 
724
                return -ENODEV;
 
725
        }
 
726
 
 
727
        mtd = &nand_info[nand_curr_device];
 
728
        nand = mtd->priv;
 
729
        nand->options |= NAND_OWN_BUFFERS;
 
730
        nand->options &= ~NAND_SUBPAGE_READ;
 
731
        /* Setup the ecc configurations again */
 
732
        if (hardware) {
 
733
                if (eccstrength == 1) {
 
734
                        err = omap_select_ecc_scheme(nand,
 
735
                                        OMAP_ECC_HAM1_CODE_HW,
 
736
                                        mtd->writesize, mtd->oobsize);
 
737
                } else if (eccstrength == 8) {
 
738
                        err = omap_select_ecc_scheme(nand,
 
739
                                        OMAP_ECC_BCH8_CODE_HW,
 
740
                                        mtd->writesize, mtd->oobsize);
 
741
                } else {
 
742
                        printf("nand: error: unsupported ECC scheme\n");
 
743
                        return -EINVAL;
 
744
                }
 
745
        } else {
 
746
                err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
 
747
                                        mtd->writesize, mtd->oobsize);
 
748
        }
 
749
 
 
750
        /* Update NAND handling after ECC mode switch */
 
751
        if (!err)
 
752
                err = nand_scan_tail(mtd);
 
753
        return err;
 
754
}
 
755
#endif /* CONFIG_SPL_BUILD */
 
756
 
 
757
/*
 
758
 * Board-specific NAND initialization. The following members of the
 
759
 * argument are board-specific:
 
760
 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
 
761
 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
 
762
 * - cmd_ctrl: hardwarespecific function for accesing control-lines
 
763
 * - waitfunc: hardwarespecific function for accesing device ready/busy line
 
764
 * - ecc.hwctl: function to enable (reset) hardware ecc generator
 
765
 * - ecc.mode: mode of ecc, see defines
 
766
 * - chip_delay: chip dependent delay for transfering data from array to
 
767
 *   read regs (tR)
 
768
 * - options: various chip options. They can partly be set to inform
 
769
 *   nand_scan about special functionality. See the defines for further
 
770
 *   explanation
 
771
 */
 
772
int board_nand_init(struct nand_chip *nand)
 
773
{
 
774
        int32_t gpmc_config = 0;
 
775
        cs = 0;
 
776
        int err = 0;
 
777
        /*
 
778
         * xloader/Uboot's gpmc configuration would have configured GPMC for
 
779
         * nand type of memory. The following logic scans and latches on to the
 
780
         * first CS with NAND type memory.
 
781
         * TBD: need to make this logic generic to handle multiple CS NAND
 
782
         * devices.
 
783
         */
 
784
        while (cs < GPMC_MAX_CS) {
 
785
                /* Check if NAND type is set */
 
786
                if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
 
787
                        /* Found it!! */
 
788
                        break;
 
789
                }
 
790
                cs++;
 
791
        }
 
792
        if (cs >= GPMC_MAX_CS) {
 
793
                printf("nand: error: Unable to find NAND settings in "
 
794
                        "GPMC Configuration - quitting\n");
 
795
                return -ENODEV;
 
796
        }
 
797
 
 
798
        gpmc_config = readl(&gpmc_cfg->config);
 
799
        /* Disable Write protect */
 
800
        gpmc_config |= 0x10;
 
801
        writel(gpmc_config, &gpmc_cfg->config);
 
802
 
 
803
        nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
 
804
        nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
 
805
        nand->priv      = &bch_priv;
 
806
        nand->cmd_ctrl  = omap_nand_hwcontrol;
 
807
        nand->options   |= NAND_NO_PADDING | NAND_CACHEPRG;
 
808
        /* If we are 16 bit dev, our gpmc config tells us that */
 
809
        if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
 
810
                nand->options |= NAND_BUSWIDTH_16;
 
811
 
 
812
        nand->chip_delay = 100;
 
813
        nand->ecc.layout = &omap_ecclayout;
 
814
 
 
815
        /* select ECC scheme */
 
816
#if defined(CONFIG_NAND_OMAP_ECCSCHEME)
 
817
        err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME,
 
818
                        CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
 
819
#else
 
820
        /* pagesize and oobsize are not required to configure sw ecc-scheme */
 
821
        err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
 
822
                        0, 0);
 
823
#endif
 
824
        if (err)
 
825
                return err;
 
826
 
 
827
#ifdef CONFIG_SPL_BUILD
 
828
        if (nand->options & NAND_BUSWIDTH_16)
 
829
                nand->read_buf = nand_read_buf16;
 
830
        else
 
831
                nand->read_buf = nand_read_buf;
 
832
        nand->dev_ready = omap_spl_dev_ready;
 
833
#endif
 
834
 
 
835
        return 0;
 
836
}