#include <asm/io.h>
#include <asm/errno.h>
#include <asm/arch/mem.h>
-#include <asm/arch/cpu.h>
-#include <asm/omap_gpmc.h>
+#include <linux/mtd/omap_gpmc.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/bch.h>
#include <linux/compiler.h>
#include <nand.h>
-#include <asm/omap_elm.h>
+#include <linux/mtd/omap_elm.h>
#define BADBLOCK_MARKER_LENGTH 2
#define SECTOR_BYTES 512
#define ECCCLEAR (0x1 << 8)
#define ECCRESULTREG1 (0x1 << 0)
+/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
+#define BCH4_BIT_PAD 4
+#ifdef CONFIG_BCH
+static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
+ 0x97, 0x79, 0xe5, 0x24, 0xb5};
+#endif
static uint8_t cs;
static __maybe_unused struct nand_ecclayout omap_ecclayout;
}
/*
- * omap_calculate_ecc - Generate non-inverted ECC bytes.
- *
- * Using noninverted ECC can be considered ugly since writing a blank
- * page ie. padding will clear the ECC bytes. This is no problem as
- * long nobody is trying to write data on the seemingly unused page.
- * Reading an erased page will produce an ECC mismatch between
- * generated and read ECC bytes that has to be dealt with separately.
- * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
- * is used, the result of read will be 0x0 while the ECC offsets of the
- * spare area will be 0xFF which will result in an ECC mismatch.
- * @mtd: MTD structure
- * @dat: unused
- * @ecc_code: ecc_code buffer
- */
-static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd,
- const uint8_t *dat, uint8_t *ecc_code)
-{
- u_int32_t val;
-
- /* Start Reading from HW ECC1_Result = 0x200 */
- val = readl(&gpmc_cfg->ecc1_result);
-
- ecc_code[0] = val & 0xFF;
- ecc_code[1] = (val >> 16) & 0xFF;
- ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
-
- /*
- * Stop reading anymore ECC vals and clear old results
- * enable will be called if more reads are required
- */
- writel(0x000, &gpmc_cfg->ecc_config);
-
- return 0;
-}
-
-/*
- * Generic BCH interface
+ * Driver configurations
*/
-struct nand_bch_priv {
- uint8_t mode;
- uint8_t type;
- uint8_t nibbles;
+struct omap_nand_info {
struct bch_control *control;
enum omap_ecc ecc_scheme;
};
-/* bch types */
-#define ECC_BCH4 0
-#define ECC_BCH8 1
-#define ECC_BCH16 2
-
-/* GPMC ecc engine settings */
-#define BCH_WRAPMODE_1 1 /* BCH wrap mode 1 */
-#define BCH_WRAPMODE_6 6 /* BCH wrap mode 6 */
-
-/* BCH nibbles for diff bch levels */
-#define NAND_ECC_HW_BCH ((uint8_t)(NAND_ECC_HW_OOB_FIRST) + 1)
-#define ECC_BCH4_NIBBLES 13
-#define ECC_BCH8_NIBBLES 26
-#define ECC_BCH16_NIBBLES 52
-
/*
* This can be a single instance cause all current users have only one NAND
* with nearly the same setup (BCH8, some with ELM and others with sw BCH
* library).
* When some users with other BCH strength will exists this have to change!
*/
-static __maybe_unused struct nand_bch_priv bch_priv = {
- .mode = NAND_ECC_HW_BCH,
- .type = ECC_BCH8,
- .nibbles = ECC_BCH8_NIBBLES,
+static __maybe_unused struct omap_nand_info omap_nand_info = {
.control = NULL
};
+/*
+ * omap_reverse_list - re-orders list elements in reverse order [internal]
+ * @list: pointer to start of list
+ * @length: length of list
+*/
+void omap_reverse_list(u8 *list, unsigned int length)
+{
+ unsigned int i, j;
+ unsigned int half_length = length / 2;
+ u8 tmp;
+ for (i = 0, j = length - 1; i < half_length; i++, j--) {
+ tmp = list[i];
+ list[i] = list[j];
+ list[j] = tmp;
+ }
+}
+
/*
* omap_enable_hwecc - configures GPMC as per ECC scheme before read/write
* @mtd: MTD device structure
static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
{
struct nand_chip *nand = mtd->priv;
- struct nand_bch_priv *bch = nand->priv;
+ struct omap_nand_info *info = nand->priv;
unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0;
unsigned int ecc_algo = 0;
unsigned int bch_type = 0;
u32 ecc_config_val = 0;
/* configure GPMC for specific ecc-scheme */
- switch (bch->ecc_scheme) {
+ switch (info->ecc_scheme) {
case OMAP_ECC_HAM1_CODE_SW:
return;
case OMAP_ECC_HAM1_CODE_HW:
}
/*
- * omap_ecc_disable - Disable H/W ECC calculation
- *
- * @mtd: MTD device structure
- */
-static void __maybe_unused omap_ecc_disable(struct mtd_info *mtd)
-{
- writel((readl(&gpmc_cfg->ecc_config) & ~0x1), &gpmc_cfg->ecc_config);
-}
-
-/*
- * BCH support using ELM module
- */
-#ifdef CONFIG_NAND_OMAP_ELM
-/*
- * omap_read_bch8_result - Read BCH result for BCH8 level
- *
- * @mtd: MTD device structure
- * @big_endian: When set read register 3 first
- * @ecc_code: Read syndrome from BCH result registers
+ * omap_calculate_ecc - Read ECC result
+ * @mtd: MTD structure
+ * @dat: unused
+ * @ecc_code: ecc_code buffer
+ * Using noninverted ECC can be considered ugly since writing a blank
+ * page ie. padding will clear the ECC bytes. This is no problem as
+ * long nobody is trying to write data on the seemingly unused page.
+ * Reading an erased page will produce an ECC mismatch between
+ * generated and read ECC bytes that has to be dealt with separately.
+ * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
+ * is used, the result of read will be 0x0 while the ECC offsets of the
+ * spare area will be 0xFF which will result in an ECC mismatch.
*/
-static void omap_read_bch8_result(struct mtd_info *mtd, uint8_t big_endian,
+static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
uint8_t *ecc_code)
{
- uint32_t *ptr;
+ struct nand_chip *chip = mtd->priv;
+ struct omap_nand_info *info = chip->priv;
+ uint32_t *ptr, val = 0;
int8_t i = 0, j;
- if (big_endian) {
+ switch (info->ecc_scheme) {
+ case OMAP_ECC_HAM1_CODE_HW:
+ val = readl(&gpmc_cfg->ecc1_result);
+ ecc_code[0] = val & 0xFF;
+ ecc_code[1] = (val >> 16) & 0xFF;
+ ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
+ break;
+#ifdef CONFIG_BCH
+ case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+#endif
+ case OMAP_ECC_BCH8_CODE_HW:
ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
- ecc_code[i++] = readl(ptr) & 0xFF;
+ val = readl(ptr);
+ ecc_code[i++] = (val >> 0) & 0xFF;
ptr--;
for (j = 0; j < 3; j++) {
- ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
- ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
- ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
- ecc_code[i++] = readl(ptr) & 0xFF;
+ val = readl(ptr);
+ ecc_code[i++] = (val >> 24) & 0xFF;
+ ecc_code[i++] = (val >> 16) & 0xFF;
+ ecc_code[i++] = (val >> 8) & 0xFF;
+ ecc_code[i++] = (val >> 0) & 0xFF;
ptr--;
}
- } else {
- ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[0];
- for (j = 0; j < 3; j++) {
- ecc_code[i++] = readl(ptr) & 0xFF;
- ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
- ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
- ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
- ptr++;
- }
- ecc_code[i++] = readl(ptr) & 0xFF;
- ecc_code[i++] = 0; /* 14th byte is always zero */
+ break;
+ default:
+ return -EINVAL;
}
-}
-
-/*
- * omap_rotate_ecc_bch - Rotate the syndrome bytes
- *
- * @mtd: MTD device structure
- * @calc_ecc: ECC read from ECC registers
- * @syndrome: Rotated syndrome will be retuned in this array
- *
- */
-static void omap_rotate_ecc_bch(struct mtd_info *mtd, uint8_t *calc_ecc,
- uint8_t *syndrome)
-{
- struct nand_chip *chip = mtd->priv;
- struct nand_bch_priv *bch = chip->priv;
- uint8_t n_bytes = 0;
- int8_t i, j;
-
- switch (bch->type) {
- case ECC_BCH4:
- n_bytes = 8;
+ /* ECC scheme specific syndrome customizations */
+ switch (info->ecc_scheme) {
+ case OMAP_ECC_HAM1_CODE_HW:
break;
+#ifdef CONFIG_BCH
+ case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
- case ECC_BCH16:
- n_bytes = 28;
+ for (i = 0; i < chip->ecc.bytes; i++)
+ *(ecc_code + i) = *(ecc_code + i) ^
+ bch8_polynomial[i];
break;
-
- case ECC_BCH8:
- default:
- n_bytes = 13;
+#endif
+ case OMAP_ECC_BCH8_CODE_HW:
+ ecc_code[chip->ecc.bytes - 1] = 0x00;
break;
+ default:
+ return -EINVAL;
}
-
- for (i = 0, j = (n_bytes-1); i < n_bytes; i++, j--)
- syndrome[i] = calc_ecc[j];
-}
-
-/*
- * omap_calculate_ecc_bch - Read BCH ECC result
- *
- * @mtd: MTD structure
- * @dat: unused
- * @ecc_code: ecc_code buffer
- */
-static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
- uint8_t *ecc_code)
-{
- struct nand_chip *chip = mtd->priv;
- struct nand_bch_priv *bch = chip->priv;
- uint8_t big_endian = 1;
- int8_t ret = 0;
-
- if (bch->type == ECC_BCH8)
- omap_read_bch8_result(mtd, big_endian, ecc_code);
- else /* BCH4 and BCH16 currently not supported */
- ret = -1;
-
- /*
- * Stop reading anymore ECC vals and clear old results
- * enable will be called if more reads are required
- */
- omap_ecc_disable(mtd);
-
- return ret;
-}
-
-/*
- * omap_fix_errors_bch - Correct bch error in the data
- *
- * @mtd: MTD device structure
- * @data: Data read from flash
- * @error_count:Number of errors in data
- * @error_loc: Locations of errors in the data
- *
- */
-static void omap_fix_errors_bch(struct mtd_info *mtd, uint8_t *data,
- uint32_t error_count, uint32_t *error_loc)
-{
- struct nand_chip *chip = mtd->priv;
- struct nand_bch_priv *bch = chip->priv;
- uint8_t count = 0;
- uint32_t error_byte_pos;
- uint32_t error_bit_mask;
- uint32_t last_bit = (bch->nibbles * 4) - 1;
-
- /* Flip all bits as specified by the error location array. */
- /* FOR( each found error location flip the bit ) */
- for (count = 0; count < error_count; count++) {
- if (error_loc[count] > last_bit) {
- /* Remove the ECC spare bits from correction. */
- error_loc[count] -= (last_bit + 1);
- /* Offset bit in data region */
- error_byte_pos = ((512 * 8) -
- (error_loc[count]) - 1) / 8;
- /* Error Bit mask */
- error_bit_mask = 0x1 << (error_loc[count] % 8);
- /* Toggle the error bit to make the correction. */
- data[error_byte_pos] ^= error_bit_mask;
- }
- }
+ return 0;
}
+#ifdef CONFIG_NAND_OMAP_ELM
/*
* omap_correct_data_bch - Compares the ecc read from nand spare area
* with ECC registers values and corrects one bit error if it has occured
uint8_t *read_ecc, uint8_t *calc_ecc)
{
struct nand_chip *chip = mtd->priv;
- struct nand_bch_priv *bch = chip->priv;
- uint8_t syndrome[28];
- uint32_t error_count = 0;
+ struct omap_nand_info *info = chip->priv;
+ uint32_t eccbytes = chip->ecc.bytes;
+ uint32_t error_count = 0, error_max;
uint32_t error_loc[8];
- uint32_t i, ecc_flag;
+ enum bch_level bch_type;
+ uint32_t i, ecc_flag = 0;
+ uint8_t count, err = 0;
+ uint32_t byte_pos, bit_pos;
+
+ /* check calculated ecc */
+ for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) {
+ if (calc_ecc[i] != 0x00)
+ ecc_flag = 1;
+ }
+ if (!ecc_flag)
+ return 0;
+ /* check for whether its a erased-page */
ecc_flag = 0;
- for (i = 0; i < chip->ecc.bytes; i++)
+ for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) {
if (read_ecc[i] != 0xff)
ecc_flag = 1;
-
+ }
if (!ecc_flag)
return 0;
- elm_reset();
- elm_config((enum bch_level)(bch->type));
-
/*
* while reading ECC result we read it in big endian.
* Hence while loading to ELM we have rotate to get the right endian.
*/
- omap_rotate_ecc_bch(mtd, calc_ecc, syndrome);
-
+ switch (info->ecc_scheme) {
+ case OMAP_ECC_BCH8_CODE_HW:
+ bch_type = BCH_8_BIT;
+ omap_reverse_list(calc_ecc, eccbytes - 1);
+ break;
+ default:
+ return -EINVAL;
+ }
/* use elm module to check for errors */
- if (elm_check_error(syndrome, bch->nibbles, &error_count,
- error_loc) != 0) {
- printf("ECC: uncorrectable.\n");
- return -1;
+ elm_config(bch_type);
+ if (elm_check_error(calc_ecc, bch_type, &error_count, error_loc)) {
+ printf("nand: error: uncorrectable ECC errors\n");
+ return -EINVAL;
}
-
/* correct bch error */
- if (error_count > 0)
- omap_fix_errors_bch(mtd, dat, error_count, error_loc);
-
- return 0;
+ for (count = 0; count < error_count; count++) {
+ switch (info->ecc_scheme) {
+ case OMAP_ECC_BCH8_CODE_HW:
+ /* 14th byte in ECC is reserved to match ROM layout */
+ error_max = SECTOR_BYTES + (eccbytes - 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ byte_pos = error_max - (error_loc[count] / 8) - 1;
+ bit_pos = error_loc[count] % 8;
+ if (byte_pos < SECTOR_BYTES) {
+ dat[byte_pos] ^= 1 << bit_pos;
+ printf("nand: bit-flip corrected @data=%d\n", byte_pos);
+ } else if (byte_pos < error_max) {
+ read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos;
+ printf("nand: bit-flip corrected @oob=%d\n", byte_pos -
+ SECTOR_BYTES);
+ } else {
+ err = -EBADMSG;
+ printf("nand: error: invalid bit-flip location\n");
+ }
+ }
+ return (err) ? err : error_count;
}
/**
* OMAP3 BCH8 support (with BCH library)
*/
#ifdef CONFIG_BCH
-/*
- * omap_calculate_ecc_bch_sw - Read BCH ECC result
- *
- * @mtd: MTD device structure
- * @dat: The pointer to data on which ecc is computed (unused here)
- * @ecc: The ECC output buffer
- */
-static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd, const uint8_t *dat,
- uint8_t *ecc)
-{
- int ret = 0;
- size_t i;
- unsigned long nsectors, val1, val2, val3, val4;
-
- nsectors = ((readl(&gpmc_cfg->ecc_config) >> 4) & 0x7) + 1;
-
- for (i = 0; i < nsectors; i++) {
- /* Read hw-computed remainder */
- val1 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[0]);
- val2 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[1]);
- val3 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[2]);
- val4 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[3]);
-
- /*
- * Add constant polynomial to remainder, in order to get an ecc
- * sequence of 0xFFs for a buffer filled with 0xFFs.
- */
- *ecc++ = 0xef ^ (val4 & 0xFF);
- *ecc++ = 0x51 ^ ((val3 >> 24) & 0xFF);
- *ecc++ = 0x2e ^ ((val3 >> 16) & 0xFF);
- *ecc++ = 0x09 ^ ((val3 >> 8) & 0xFF);
- *ecc++ = 0xed ^ (val3 & 0xFF);
- *ecc++ = 0x93 ^ ((val2 >> 24) & 0xFF);
- *ecc++ = 0x9a ^ ((val2 >> 16) & 0xFF);
- *ecc++ = 0xc2 ^ ((val2 >> 8) & 0xFF);
- *ecc++ = 0x97 ^ (val2 & 0xFF);
- *ecc++ = 0x79 ^ ((val1 >> 24) & 0xFF);
- *ecc++ = 0xe5 ^ ((val1 >> 16) & 0xFF);
- *ecc++ = 0x24 ^ ((val1 >> 8) & 0xFF);
- *ecc++ = 0xb5 ^ (val1 & 0xFF);
- }
-
- /*
- * Stop reading anymore ECC vals and clear old results
- * enable will be called if more reads are required
- */
- omap_ecc_disable(mtd);
-
- return ret;
-}
-
/**
* omap_correct_data_bch_sw - Decode received data and correct errors
* @mtd: MTD device structure
/* cannot correct more than 8 errors */
unsigned int errloc[8];
struct nand_chip *chip = mtd->priv;
- struct nand_bch_priv *chip_priv = chip->priv;
- struct bch_control *bch = chip_priv->control;
+ struct omap_nand_info *info = chip->priv;
- count = decode_bch(bch, NULL, 512, read_ecc, calc_ecc, NULL, errloc);
+ count = decode_bch(info->control, NULL, 512, read_ecc, calc_ecc,
+ NULL, errloc);
if (count > 0) {
/* correct errors */
for (i = 0; i < count; i++) {
static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
- struct nand_bch_priv *chip_priv = chip->priv;
- struct bch_control *bch = NULL;
-
- if (chip_priv)
- bch = chip_priv->control;
+ struct omap_nand_info *info = chip->priv;
- if (bch) {
- free_bch(bch);
- chip_priv->control = NULL;
+ if (info->control) {
+ free_bch(info->control);
+ info->control = NULL;
}
}
#endif /* CONFIG_BCH */
*/
static int omap_select_ecc_scheme(struct nand_chip *nand,
enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
- struct nand_bch_priv *bch = nand->priv;
+ struct omap_nand_info *info = nand->priv;
struct nand_ecclayout *ecclayout = &omap_ecclayout;
int eccsteps = pagesize / SECTOR_BYTES;
int i;
debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n");
/* For this ecc-scheme, ecc.bytes, ecc.layout, ... are
* initialized in nand_scan_tail(), so just set ecc.mode */
- bch_priv.control = NULL;
- bch_priv.type = 0;
+ info->control = NULL;
nand->ecc.mode = NAND_ECC_SOFT;
nand->ecc.layout = NULL;
nand->ecc.size = 0;
- bch->ecc_scheme = OMAP_ECC_HAM1_CODE_SW;
break;
case OMAP_ECC_HAM1_CODE_HW:
(3 * eccsteps) + BADBLOCK_MARKER_LENGTH));
return -EINVAL;
}
- bch_priv.control = NULL;
- bch_priv.type = 0;
+ info->control = NULL;
/* populate ecc specific fields */
memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
nand->ecc.mode = NAND_ECC_HW;
ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
BADBLOCK_MARKER_LENGTH;
- bch->ecc_scheme = OMAP_ECC_HAM1_CODE_HW;
break;
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
return -EINVAL;
}
/* check if BCH S/W library can be used for error detection */
- bch_priv.control = init_bch(13, 8, 0x201b);
- if (!bch_priv.control) {
+ info->control = init_bch(13, 8, 0x201b);
+ if (!info->control) {
printf("nand: error: could not init_bch()\n");
return -ENODEV;
}
- bch_priv.type = ECC_BCH8;
/* populate ecc specific fields */
memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.bytes = 13;
nand->ecc.hwctl = omap_enable_hwecc;
nand->ecc.correct = omap_correct_data_bch_sw;
- nand->ecc.calculate = omap_calculate_ecc_bch_sw;
+ nand->ecc.calculate = omap_calculate_ecc;
/* define ecc-layout */
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
BADBLOCK_MARKER_LENGTH;
- bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
break;
#else
printf("nand: error: CONFIG_BCH required for ECC\n");
}
/* intialize ELM for ECC error detection */
elm_init();
- bch_priv.type = ECC_BCH8;
+ info->control = NULL;
/* populate ecc specific fields */
memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
nand->ecc.mode = NAND_ECC_HW;
nand->ecc.bytes = 14;
nand->ecc.hwctl = omap_enable_hwecc;
nand->ecc.correct = omap_correct_data_bch;
- nand->ecc.calculate = omap_calculate_ecc_bch;
+ nand->ecc.calculate = omap_calculate_ecc;
nand->ecc.read_page = omap_read_page_bch;
/* define ecc-layout */
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
BADBLOCK_MARKER_LENGTH;
- bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW;
break;
#else
printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW)
nand->ecc.layout = ecclayout;
+ info->ecc_scheme = ecc_scheme;
return 0;
}
nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
- nand->priv = &bch_priv;
+ nand->priv = &omap_nand_info;
nand->cmd_ctrl = omap_nand_hwcontrol;
nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
/* If we are 16 bit dev, our gpmc config tells us that */