uboot/drivers/mtd/nand/omap_gpmc.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2004-2008 Texas Instruments, <www.ti.com>
   3 * Rohit Choraria <rohitkc@ti.com>
   4 *
   5 * See file CREDITS for list of people who contributed to this
   6 * project.
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 * MA 02111-1307 USA
  22 */
  23
  24#include <common.h>
  25#include <asm/io.h>
  26#include <asm/errno.h>
  27#include <asm/arch/mem.h>
  28#include <asm/arch/omap_gpmc.h>
  29#include <linux/mtd/nand_ecc.h>
  30#include <linux/compiler.h>
  31#include <nand.h>
  32#ifdef CONFIG_AM33XX
  33#include <asm/arch/elm.h>
  34#endif
  35
  36static uint8_t cs;
  37static __maybe_unused struct nand_ecclayout hw_nand_oob =
  38        GPMC_NAND_HW_ECC_LAYOUT;
  39
  40/*
  41 * omap_nand_hwcontrol - Set the address pointers corretly for the
  42 *                      following address/data/command operation
  43 */
  44static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
  45                                uint32_t ctrl)
  46{
  47        register struct nand_chip *this = mtd->priv;
  48
  49        /*
  50         * Point the IO_ADDR to DATA and ADDRESS registers instead
  51         * of chip address
  52         */
  53        switch (ctrl) {
  54        case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
  55                this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
  56                break;
  57        case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
  58                this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
  59                break;
  60        case NAND_CTRL_CHANGE | NAND_NCE:
  61                this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
  62                break;
  63        }
  64
  65        if (cmd != NAND_CMD_NONE)
  66                writeb(cmd, this->IO_ADDR_W);
  67}
  68
  69#ifdef CONFIG_SPL_BUILD
  70/* Check wait pin as dev ready indicator */
  71int omap_spl_dev_ready(struct mtd_info *mtd)
  72{
  73        return gpmc_cfg->status & (1 << 8);
  74}
  75#endif
  76
  77/*
  78 * omap_hwecc_init - Initialize the Hardware ECC for NAND flash in
  79 *                   GPMC controller
  80 * @mtd:        MTD device structure
  81 *
  82 */
  83static void __maybe_unused omap_hwecc_init(struct nand_chip *chip)
  84{
  85        /*
  86         * Init ECC Control Register
  87         * Clear all ECC | Enable Reg1
  88         */
  89        writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
  90        writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL, &gpmc_cfg->ecc_size_config);
  91}
  92
  93/*
  94 * gen_true_ecc - This function will generate true ECC value, which
  95 * can be used when correcting data read from NAND flash memory core
  96 *
  97 * @ecc_buf:    buffer to store ecc code
  98 *
  99 * @return:     re-formatted ECC value
 100 */
 101static uint32_t gen_true_ecc(uint8_t *ecc_buf)
 102{
 103        return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
 104                ((ecc_buf[2] & 0x0F) << 8);
 105}
 106
 107/*
 108 * omap_correct_data - Compares the ecc read from nand spare area with ECC
 109 * registers values and corrects one bit error if it has occured
 110 * Further details can be had from OMAP TRM and the following selected links:
 111 * http://en.wikipedia.org/wiki/Hamming_code
 112 * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf
 113 *
 114 * @mtd:                 MTD device structure
 115 * @dat:                 page data
 116 * @read_ecc:            ecc read from nand flash
 117 * @calc_ecc:            ecc read from ECC registers
 118 *
 119 * @return 0 if data is OK or corrected, else returns -1
 120 */
 121static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
 122                                uint8_t *read_ecc, uint8_t *calc_ecc)
 123{
 124        uint32_t orig_ecc, new_ecc, res, hm;
 125        uint16_t parity_bits, byte;
 126        uint8_t bit;
 127
 128        /* Regenerate the orginal ECC */
 129        orig_ecc = gen_true_ecc(read_ecc);
 130        new_ecc = gen_true_ecc(calc_ecc);
 131        /* Get the XOR of real ecc */
 132        res = orig_ecc ^ new_ecc;
 133        if (res) {
 134                /* Get the hamming width */
 135                hm = hweight32(res);
 136                /* Single bit errors can be corrected! */
 137                if (hm == 12) {
 138                        /* Correctable data! */
 139                        parity_bits = res >> 16;
 140                        bit = (parity_bits & 0x7);
 141                        byte = (parity_bits >> 3) & 0x1FF;
 142                        /* Flip the bit to correct */
 143                        dat[byte] ^= (0x1 << bit);
 144                } else if (hm == 1) {
 145                        printf("Error: Ecc is wrong\n");
 146                        /* ECC itself is corrupted */
 147                        return 2;
 148                } else {
 149                        /*
 150                         * hm distance != parity pairs OR one, could mean 2 bit
 151                         * error OR potentially be on a blank page..
 152                         * orig_ecc: contains spare area data from nand flash.
 153                         * new_ecc: generated ecc while reading data area.
 154                         * Note: if the ecc = 0, all data bits from which it was
 155                         * generated are 0xFF.
 156                         * The 3 byte(24 bits) ecc is generated per 512byte
 157                         * chunk of a page. If orig_ecc(from spare area)
 158                         * is 0xFF && new_ecc(computed now from data area)=0x0,
 159                         * this means that data area is 0xFF and spare area is
 160                         * 0xFF. A sure sign of a erased page!
 161                         */
 162                        if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000))
 163                                return 0;
 164                        printf("Error: Bad compare! failed\n");
 165                        /* detected 2 bit error */
 166                        return -1;
 167                }
 168        }
 169        return 0;
 170}
 171
 172/*
 173 *  omap_calculate_ecc - Generate non-inverted ECC bytes.
 174 *
 175 *  Using noninverted ECC can be considered ugly since writing a blank
 176 *  page ie. padding will clear the ECC bytes. This is no problem as
 177 *  long nobody is trying to write data on the seemingly unused page.
 178 *  Reading an erased page will produce an ECC mismatch between
 179 *  generated and read ECC bytes that has to be dealt with separately.
 180 *  E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
 181 *  is used, the result of read will be 0x0 while the ECC offsets of the
 182 *  spare area will be 0xFF which will result in an ECC mismatch.
 183 *  @mtd:       MTD structure
 184 *  @dat:       unused
 185 *  @ecc_code:  ecc_code buffer
 186 */
 187static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd,
 188                const uint8_t *dat, uint8_t *ecc_code)
 189{
 190        u_int32_t val;
 191
 192        /* Start Reading from HW ECC1_Result = 0x200 */
 193        val = readl(&gpmc_cfg->ecc1_result);
 194
 195        ecc_code[0] = val & 0xFF;
 196        ecc_code[1] = (val >> 16) & 0xFF;
 197        ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
 198
 199        /*
 200         * Stop reading anymore ECC vals and clear old results
 201         * enable will be called if more reads are required
 202         */
 203        writel(0x000, &gpmc_cfg->ecc_config);
 204
 205        return 0;
 206}
 207
 208/*
 209 * omap_enable_ecc - This function enables the hardware ecc functionality
 210 * @mtd:        MTD device structure
 211 * @mode:       Read/Write mode
 212 */
 213static void __maybe_unused omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
 214{
 215        struct nand_chip *chip = mtd->priv;
 216        uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
 217
 218        switch (mode) {
 219        case NAND_ECC_READ:
 220        case NAND_ECC_WRITE:
 221                /* Clear the ecc result registers, select ecc reg as 1 */
 222                writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
 223
 224                /*
 225                 * Size 0 = 0xFF, Size1 is 0xFF - both are 512 bytes
 226                 * tell all regs to generate size0 sized regs
 227                 * we just have a single ECC engine for all CS
 228                 */
 229                writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL,
 230                        &gpmc_cfg->ecc_size_config);
 231                val = (dev_width << 7) | (cs << 1) | (0x1);
 232                writel(val, &gpmc_cfg->ecc_config);
 233                break;
 234        default:
 235                printf("Error: Unrecognized Mode[%d]!\n", mode);
 236                break;
 237        }
 238}
 239
 240/*
 241 * BCH8 support (needs ELM and thus AM33xx-only)
 242 */
 243#ifdef CONFIG_AM33XX
 244struct nand_bch_priv {
 245        uint8_t mode;
 246        uint8_t type;
 247        uint8_t nibbles;
 248};
 249
 250/* bch types */
 251#define ECC_BCH4        0
 252#define ECC_BCH8        1
 253#define ECC_BCH16       2
 254
 255/* BCH nibbles for diff bch levels */
 256#define NAND_ECC_HW_BCH ((uint8_t)(NAND_ECC_HW_OOB_FIRST) + 1)
 257#define ECC_BCH4_NIBBLES        13
 258#define ECC_BCH8_NIBBLES        26
 259#define ECC_BCH16_NIBBLES       52
 260
 261static struct nand_ecclayout hw_bch8_nand_oob = GPMC_NAND_HW_BCH8_ECC_LAYOUT;
 262
 263static struct nand_bch_priv bch_priv = {
 264        .mode = NAND_ECC_HW_BCH,
 265        .type = ECC_BCH8,
 266        .nibbles = ECC_BCH8_NIBBLES
 267};
 268
 269/*
 270 * omap_read_bch8_result - Read BCH result for BCH8 level
 271 *
 272 * @mtd:        MTD device structure
 273 * @big_endian: When set read register 3 first
 274 * @ecc_code:   Read syndrome from BCH result registers
 275 */
 276static void omap_read_bch8_result(struct mtd_info *mtd, uint8_t big_endian,
 277                                uint8_t *ecc_code)
 278{
 279        uint32_t *ptr;
 280        int8_t i = 0, j;
 281
 282        if (big_endian) {
 283                ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
 284                ecc_code[i++] = readl(ptr) & 0xFF;
 285                ptr--;
 286                for (j = 0; j < 3; j++) {
 287                        ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
 288                        ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
 289                        ecc_code[i++] = (readl(ptr) >>  8) & 0xFF;
 290                        ecc_code[i++] = readl(ptr) & 0xFF;
 291                        ptr--;
 292                }
 293        } else {
 294                ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[0];
 295                for (j = 0; j < 3; j++) {
 296                        ecc_code[i++] = readl(ptr) & 0xFF;
 297                        ecc_code[i++] = (readl(ptr) >>  8) & 0xFF;
 298                        ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
 299                        ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
 300                        ptr++;
 301                }
 302                ecc_code[i++] = readl(ptr) & 0xFF;
 303                ecc_code[i++] = 0;      /* 14th byte is always zero */
 304        }
 305}
 306
 307/*
 308 * omap_ecc_disable - Disable H/W ECC calculation
 309 *
 310 * @mtd:        MTD device structure
 311 *
 312 */
 313static void omap_ecc_disable(struct mtd_info *mtd)
 314{
 315        writel((readl(&gpmc_cfg->ecc_config) & ~0x1),
 316                &gpmc_cfg->ecc_config);
 317}
 318
 319/*
 320 * omap_rotate_ecc_bch - Rotate the syndrome bytes
 321 *
 322 * @mtd:        MTD device structure
 323 * @calc_ecc:   ECC read from ECC registers
 324 * @syndrome:   Rotated syndrome will be retuned in this array
 325 *
 326 */
 327static void omap_rotate_ecc_bch(struct mtd_info *mtd, uint8_t *calc_ecc,
 328                uint8_t *syndrome)
 329{
 330        struct nand_chip *chip = mtd->priv;
 331        struct nand_bch_priv *bch = chip->priv;
 332        uint8_t n_bytes = 0;
 333        int8_t i, j;
 334
 335        switch (bch->type) {
 336        case ECC_BCH4:
 337                n_bytes = 8;
 338                break;
 339
 340        case ECC_BCH16:
 341                n_bytes = 28;
 342                break;
 343
 344        case ECC_BCH8:
 345        default:
 346                n_bytes = 13;
 347                break;
 348        }
 349
 350        for (i = 0, j = (n_bytes-1); i < n_bytes; i++, j--)
 351                syndrome[i] =  calc_ecc[j];
 352}
 353
 354/*
 355 *  omap_calculate_ecc_bch - Read BCH ECC result
 356 *
 357 *  @mtd:       MTD structure
 358 *  @dat:       unused
 359 *  @ecc_code:  ecc_code buffer
 360 */
 361static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
 362                                uint8_t *ecc_code)
 363{
 364        struct nand_chip *chip = mtd->priv;
 365        struct nand_bch_priv *bch = chip->priv;
 366        uint8_t big_endian = 1;
 367        int8_t ret = 0;
 368
 369        if (bch->type == ECC_BCH8)
 370                omap_read_bch8_result(mtd, big_endian, ecc_code);
 371        else /* BCH4 and BCH16 currently not supported */
 372                ret = -1;
 373
 374        /*
 375         * Stop reading anymore ECC vals and clear old results
 376         * enable will be called if more reads are required
 377         */
 378        omap_ecc_disable(mtd);
 379
 380        return ret;
 381}
 382
 383/*
 384 * omap_fix_errors_bch - Correct bch error in the data
 385 *
 386 * @mtd:        MTD device structure
 387 * @data:       Data read from flash
 388 * @error_count:Number of errors in data
 389 * @error_loc:  Locations of errors in the data
 390 *
 391 */
 392static void omap_fix_errors_bch(struct mtd_info *mtd, uint8_t *data,
 393                uint32_t error_count, uint32_t *error_loc)
 394{
 395        struct nand_chip *chip = mtd->priv;
 396        struct nand_bch_priv *bch = chip->priv;
 397        uint8_t count = 0;
 398        uint32_t error_byte_pos;
 399        uint32_t error_bit_mask;
 400        uint32_t last_bit = (bch->nibbles * 4) - 1;
 401
 402        /* Flip all bits as specified by the error location array. */
 403        /* FOR( each found error location flip the bit ) */
 404        for (count = 0; count < error_count; count++) {
 405                if (error_loc[count] > last_bit) {
 406                        /* Remove the ECC spare bits from correction. */
 407                        error_loc[count] -= (last_bit + 1);
 408                        /* Offset bit in data region */
 409                        error_byte_pos = ((512 * 8) -
 410                                        (error_loc[count]) - 1) / 8;
 411                        /* Error Bit mask */
 412                        error_bit_mask = 0x1 << (error_loc[count] % 8);
 413                        /* Toggle the error bit to make the correction. */
 414                        data[error_byte_pos] ^= error_bit_mask;
 415                }
 416        }
 417}
 418
 419/*
 420 * omap_correct_data_bch - Compares the ecc read from nand spare area
 421 * with ECC registers values and corrects one bit error if it has occured
 422 *
 423 * @mtd:        MTD device structure
 424 * @dat:        page data
 425 * @read_ecc:   ecc read from nand flash (ignored)
 426 * @calc_ecc:   ecc read from ECC registers
 427 *
 428 * @return 0 if data is OK or corrected, else returns -1
 429 */
 430static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
 431                                uint8_t *read_ecc, uint8_t *calc_ecc)
 432{
 433        struct nand_chip *chip = mtd->priv;
 434        struct nand_bch_priv *bch = chip->priv;
 435        uint8_t syndrome[28];
 436        uint32_t error_count = 0;
 437        uint32_t error_loc[8];
 438        uint32_t i, ecc_flag;
 439
 440        ecc_flag = 0;
 441        for (i = 0; i < chip->ecc.bytes; i++)
 442                if (read_ecc[i] != 0xff)
 443                        ecc_flag = 1;
 444
 445        if (!ecc_flag)
 446                return 0;
 447
 448        elm_reset();
 449        elm_config((enum bch_level)(bch->type));
 450
 451        /*
 452         * while reading ECC result we read it in big endian.
 453         * Hence while loading to ELM we have rotate to get the right endian.
 454         */
 455        omap_rotate_ecc_bch(mtd, calc_ecc, syndrome);
 456
 457        /* use elm module to check for errors */
 458        if (elm_check_error(syndrome, bch->nibbles, &error_count,
 459                                error_loc) != 0) {
 460                printf("ECC: uncorrectable.\n");
 461                return -1;
 462        }
 463
 464        /* correct bch error */
 465        if (error_count > 0)
 466                omap_fix_errors_bch(mtd, dat, error_count, error_loc);
 467
 468        return 0;
 469}
 470/*
 471 * omap_hwecc_init_bch - Initialize the BCH Hardware ECC for NAND flash in
 472 *                              GPMC controller
 473 * @mtd:       MTD device structure
 474 * @mode:       Read/Write mode
 475 */
 476static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
 477{
 478        uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
 479        uint32_t unused_length = 0;
 480        struct nand_bch_priv *bch = chip->priv;
 481
 482        switch (bch->nibbles) {
 483        case ECC_BCH4_NIBBLES:
 484                unused_length = 3;
 485                break;
 486        case ECC_BCH8_NIBBLES:
 487                unused_length = 2;
 488                break;
 489        case ECC_BCH16_NIBBLES:
 490                unused_length = 0;
 491                break;
 492        }
 493
 494        /* Clear the ecc result registers, select ecc reg as 1 */
 495        writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
 496
 497        switch (mode) {
 498        case NAND_ECC_WRITE:
 499                /* eccsize1 config */
 500                val = ((unused_length + bch->nibbles) << 22);
 501                break;
 502
 503        case NAND_ECC_READ:
 504        default:
 505                /* by default eccsize0 selected for ecc1resultsize */
 506                /* eccsize0 config */
 507                val  = (bch->nibbles << 12);
 508                /* eccsize1 config */
 509                val |= (unused_length << 22);
 510                break;
 511        }
 512        /* ecc size configuration */
 513        writel(val, &gpmc_cfg->ecc_size_config);
 514        /* by default 512bytes sector page is selected */
 515        /* set bch mode */
 516        val  = (1 << 16);
 517        /* bch4 / bch8 / bch16 */
 518        val |= (bch->type << 12);
 519        /* set wrap mode to 1 */
 520        val |= (1 << 8);
 521        val |= (dev_width << 7);
 522        val |= (cs << 1);
 523        writel(val, &gpmc_cfg->ecc_config);
 524}
 525
 526/*
 527 * omap_enable_ecc_bch- This function enables the bch h/w ecc functionality
 528 * @mtd:        MTD device structure
 529 * @mode:       Read/Write mode
 530 *
 531 */
 532static void omap_enable_ecc_bch(struct mtd_info *mtd, int32_t mode)
 533{
 534        struct nand_chip *chip = mtd->priv;
 535
 536        omap_hwecc_init_bch(chip, mode);
 537        /* enable ecc */
 538        writel((readl(&gpmc_cfg->ecc_config) | 0x1), &gpmc_cfg->ecc_config);
 539}
 540
 541/**
 542 * omap_read_page_bch - hardware ecc based page read function
 543 * @mtd:        mtd info structure
 544 * @chip:       nand chip info structure
 545 * @buf:        buffer to store read data
 546 * @page:       page number to read
 547 *
 548 */
 549static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
 550                                uint8_t *buf, int page)
 551{
 552        int i, eccsize = chip->ecc.size;
 553        int eccbytes = chip->ecc.bytes;
 554        int eccsteps = chip->ecc.steps;
 555        uint8_t *p = buf;
 556        uint8_t *ecc_calc = chip->buffers->ecccalc;
 557        uint8_t *ecc_code = chip->buffers->ecccode;
 558        uint32_t *eccpos = chip->ecc.layout->eccpos;
 559        uint8_t *oob = chip->oob_poi;
 560        uint32_t data_pos;
 561        uint32_t oob_pos;
 562
 563        data_pos = 0;
 564        /* oob area start */
 565        oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
 566        oob += chip->ecc.layout->eccpos[0];
 567
 568        for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
 569                                oob += eccbytes) {
 570                chip->ecc.hwctl(mtd, NAND_ECC_READ);
 571                /* read data */
 572                chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, page);
 573                chip->read_buf(mtd, p, eccsize);
 574
 575                /* read respective ecc from oob area */
 576                chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, page);
 577                chip->read_buf(mtd, oob, eccbytes);
 578                /* read syndrome */
 579                chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 580
 581                data_pos += eccsize;
 582                oob_pos += eccbytes;
 583        }
 584
 585        for (i = 0; i < chip->ecc.total; i++)
 586                ecc_code[i] = chip->oob_poi[eccpos[i]];
 587
 588        eccsteps = chip->ecc.steps;
 589        p = buf;
 590
 591        for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 592                int stat;
 593
 594                stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
 595                if (stat < 0)
 596                        mtd->ecc_stats.failed++;
 597                else
 598                        mtd->ecc_stats.corrected += stat;
 599        }
 600        return 0;
 601}
 602#endif /* CONFIG_AM33XX */
 603
 604#ifndef CONFIG_SPL_BUILD
 605/*
 606 * omap_nand_switch_ecc - switch the ECC operation b/w h/w ecc and s/w ecc.
 607 * The default is to come up on s/w ecc
 608 *
 609 * @hardware - 1 -switch to h/w ecc, 0 - s/w ecc
 610 *
 611 */
 612void omap_nand_switch_ecc(int32_t hardware)
 613{
 614        struct nand_chip *nand;
 615        struct mtd_info *mtd;
 616
 617        if (nand_curr_device < 0 ||
 618            nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
 619            !nand_info[nand_curr_device].name) {
 620                printf("Error: Can't switch ecc, no devices available\n");
 621                return;
 622        }
 623
 624        mtd = &nand_info[nand_curr_device];
 625        nand = mtd->priv;
 626
 627        nand->options |= NAND_OWN_BUFFERS;
 628
 629        /* Reset ecc interface */
 630        nand->ecc.read_page = NULL;
 631        nand->ecc.write_page = NULL;
 632        nand->ecc.read_oob = NULL;
 633        nand->ecc.write_oob = NULL;
 634        nand->ecc.hwctl = NULL;
 635        nand->ecc.correct = NULL;
 636        nand->ecc.calculate = NULL;
 637
 638        /* Setup the ecc configurations again */
 639        if (hardware == 1) {
 640                nand->ecc.mode = NAND_ECC_HW;
 641                nand->ecc.layout = &hw_nand_oob;
 642                nand->ecc.size = 512;
 643                nand->ecc.bytes = 3;
 644                nand->ecc.hwctl = omap_enable_hwecc;
 645                nand->ecc.correct = omap_correct_data;
 646                nand->ecc.calculate = omap_calculate_ecc;
 647                omap_hwecc_init(nand);
 648                printf("HW ECC selected\n");
 649#ifdef CONFIG_AM33XX
 650        } else if (hardware == 2) {
 651                nand->ecc.mode = NAND_ECC_HW;
 652                nand->ecc.layout = &hw_bch8_nand_oob;
 653                nand->ecc.size = 512;
 654                nand->ecc.bytes = 14;
 655                nand->ecc.read_page = omap_read_page_bch;
 656                nand->ecc.hwctl = omap_enable_ecc_bch;
 657                nand->ecc.correct = omap_correct_data_bch;
 658                nand->ecc.calculate = omap_calculate_ecc_bch;
 659                omap_hwecc_init_bch(nand, NAND_ECC_READ);
 660                printf("HW BCH8 selected\n");
 661#endif
 662        } else {
 663                nand->ecc.mode = NAND_ECC_SOFT;
 664                /* Use mtd default settings */
 665                nand->ecc.layout = NULL;
 666                nand->ecc.size = 0;
 667                printf("SW ECC selected\n");
 668        }
 669
 670        /* Update NAND handling after ECC mode switch */
 671        nand_scan_tail(mtd);
 672
 673        nand->options &= ~NAND_OWN_BUFFERS;
 674}
 675#endif /* CONFIG_SPL_BUILD */
 676
 677/*
 678 * Board-specific NAND initialization. The following members of the
 679 * argument are board-specific:
 680 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
 681 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
 682 * - cmd_ctrl: hardwarespecific function for accesing control-lines
 683 * - waitfunc: hardwarespecific function for accesing device ready/busy line
 684 * - ecc.hwctl: function to enable (reset) hardware ecc generator
 685 * - ecc.mode: mode of ecc, see defines
 686 * - chip_delay: chip dependent delay for transfering data from array to
 687 *   read regs (tR)
 688 * - options: various chip options. They can partly be set to inform
 689 *   nand_scan about special functionality. See the defines for further
 690 *   explanation
 691 */
 692int board_nand_init(struct nand_chip *nand)
 693{
 694        int32_t gpmc_config = 0;
 695        cs = 0;
 696
 697        /*
 698         * xloader/Uboot's gpmc configuration would have configured GPMC for
 699         * nand type of memory. The following logic scans and latches on to the
 700         * first CS with NAND type memory.
 701         * TBD: need to make this logic generic to handle multiple CS NAND
 702         * devices.
 703         */
 704        while (cs < GPMC_MAX_CS) {
 705                /* Check if NAND type is set */
 706                if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
 707                        /* Found it!! */
 708                        break;
 709                }
 710                cs++;
 711        }
 712        if (cs >= GPMC_MAX_CS) {
 713                printf("NAND: Unable to find NAND settings in "
 714                        "GPMC Configuration - quitting\n");
 715                return -ENODEV;
 716        }
 717
 718        gpmc_config = readl(&gpmc_cfg->config);
 719        /* Disable Write protect */
 720        gpmc_config |= 0x10;
 721        writel(gpmc_config, &gpmc_cfg->config);
 722
 723        nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
 724        nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
 725
 726        nand->cmd_ctrl = omap_nand_hwcontrol;
 727        nand->options = NAND_NO_PADDING | NAND_CACHEPRG | NAND_NO_AUTOINCR;
 728        /* If we are 16 bit dev, our gpmc config tells us that */
 729        if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
 730                nand->options |= NAND_BUSWIDTH_16;
 731
 732        nand->chip_delay = 100;
 733
 734#ifdef CONFIG_AM33XX
 735        /* required in case of BCH */
 736        elm_init();
 737
 738        /* BCH info that will be correct for SPL or overridden otherwise. */
 739        nand->priv = &bch_priv;
 740#endif
 741
 742        /* Default ECC mode */
 743#ifdef CONFIG_AM33XX
 744        nand->ecc.mode = NAND_ECC_HW;
 745        nand->ecc.layout = &hw_bch8_nand_oob;
 746        nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
 747        nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
 748        nand->ecc.hwctl = omap_enable_ecc_bch;
 749        nand->ecc.correct = omap_correct_data_bch;
 750        nand->ecc.calculate = omap_calculate_ecc_bch;
 751        nand->ecc.read_page = omap_read_page_bch;
 752        omap_hwecc_init_bch(nand, NAND_ECC_READ);
 753#else
 754#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC)
 755        nand->ecc.mode = NAND_ECC_SOFT;
 756#else
 757        nand->ecc.mode = NAND_ECC_HW;
 758        nand->ecc.layout = &hw_nand_oob;
 759        nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
 760        nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
 761        nand->ecc.hwctl = omap_enable_hwecc;
 762        nand->ecc.correct = omap_correct_data;
 763        nand->ecc.calculate = omap_calculate_ecc;
 764        omap_hwecc_init(nand);
 765#endif
 766#endif
 767
 768#ifdef CONFIG_SPL_BUILD
 769        if (nand->options & NAND_BUSWIDTH_16)
 770                nand->read_buf = nand_read_buf16;
 771        else
 772                nand->read_buf = nand_read_buf;
 773        nand->dev_ready = omap_spl_dev_ready;
 774#endif
 775
 776        return 0;
 777}
 778