summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2019-08-15 10:58:11 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2019-08-15 10:58:11 +0200
commita6aab0ebab471e91beb4e14c2d305b326ac18928 (patch)
tree44411e6dbed5e1c1f9999ae9827d678a5a88cdcb /drivers/mtd/nand
parenta0b3119905e16d7610f950d0fd04a8689979be2e (diff)
parent6b309a2f91dca742a05a53922ff70970f28b428d (diff)
downloadbarebox-a6aab0ebab471e91beb4e14c2d305b326ac18928.tar.gz
barebox-a6aab0ebab471e91beb4e14c2d305b326ac18928.tar.xz
Merge branch 'for-next/mtd-gpmi-nand'
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/nand_base.c27
-rw-r--r--drivers/mtd/nand/nand_mxs.c273
2 files changed, 182 insertions, 118 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 5474d0db3c..9c0c01694a 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -43,6 +43,7 @@
#include <io.h>
#include <malloc.h>
#include <module.h>
+#include <of_mtd.h>
/* Define default oob placement schemes for large and small page devices */
static struct nand_ecclayout nand_oob_8 = {
@@ -3507,6 +3508,32 @@ ident_done:
}
/**
+ * nand_of_parse_node - parse generic NAND properties
+ * @mtd: MTD device structure
+ * @np: Device node to read information from
+ *
+ * This parses device tree properties generic to NAND controllers and fills in
+ * the various fields in struct nand_chip.
+ */
+void nand_of_parse_node(struct mtd_info *mtd, struct device_node *np)
+{
+ struct nand_chip *chip = mtd->priv;
+ int ecc_strength, ecc_size;
+
+ if (!IS_ENABLED(CONFIG_OFDEVICE))
+ return;
+
+ ecc_strength = of_get_nand_ecc_strength(np);
+ ecc_size = of_get_nand_ecc_step_size(np);
+
+ if (ecc_strength >= 0)
+ chip->ecc.strength = ecc_strength;
+
+ if (ecc_size >= 0)
+ chip->ecc.size = ecc_size;
+}
+
+/**
* nand_scan_ident - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
* @maxchips: number of chips to scan for
diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c
index c3b07aa3f6..b016c5bff0 100644
--- a/drivers/mtd/nand/nand_mxs.c
+++ b/drivers/mtd/nand/nand_mxs.c
@@ -232,9 +232,11 @@ struct mxs_nand_info {
#define GPMI_TIMING_INIT_OK (1 << 1)
unsigned flags;
struct nand_timing timing;
+
+ int bb_mark_bit_offset;
};
-struct nand_ecclayout fake_ecc_layout;
+static struct nand_ecclayout fake_ecc_layout;
static inline int mxs_nand_is_imx6(struct mxs_nand_info *info)
{
@@ -275,33 +277,14 @@ static uint32_t mxs_nand_ecc_chunk_cnt(uint32_t page_data_size)
return page_data_size / MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
}
-static uint32_t mxs_nand_ecc_size_in_bits(uint32_t ecc_strength)
-{
- return ecc_strength * 13;
-}
-
static uint32_t mxs_nand_aux_status_offset(void)
{
return (MXS_NAND_METADATA_SIZE + 0x3) & ~0x3;
}
-uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size,
- uint32_t page_oob_size)
-{
- int ecc_chunk_count = mxs_nand_ecc_chunk_cnt(page_data_size);
- int ecc_strength = 0;
- int gf_len = 13; /* length of Galois Field for non-DDR nand */
-
- ecc_strength = ((page_oob_size - MXS_NAND_METADATA_SIZE) * 8)
- / (gf_len * ecc_chunk_count);
-
- /* We need the minor even number. */
- return rounddown(ecc_strength, 2);
-}
-
-static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size,
- uint32_t ecc_strength)
+static uint32_t mxs_nand_get_mark_offset(struct mtd_info *mtd)
{
+ struct nand_chip *chip = mtd->priv;
uint32_t chunk_data_size_in_bits;
uint32_t chunk_ecc_size_in_bits;
uint32_t chunk_total_size_in_bits;
@@ -310,13 +293,13 @@ static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size,
uint32_t block_mark_bit_offset;
chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8;
- chunk_ecc_size_in_bits = mxs_nand_ecc_size_in_bits(ecc_strength);
+ chunk_ecc_size_in_bits = chip->ecc.strength * 13;
chunk_total_size_in_bits =
chunk_data_size_in_bits + chunk_ecc_size_in_bits;
/* Compute the bit offset of the block mark within the physical page. */
- block_mark_bit_offset = page_data_size * 8;
+ block_mark_bit_offset = mtd->writesize * 8;
/* Subtract the metadata bits. */
block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8;
@@ -348,18 +331,62 @@ static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size,
return block_mark_bit_offset;
}
-uint32_t mxs_nand_mark_byte_offset(struct mtd_info *mtd)
+static int mxs_nand_calc_geo(struct mtd_info *mtd)
{
- uint32_t ecc_strength;
- ecc_strength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize);
- return mxs_nand_get_mark_offset(mtd->writesize, ecc_strength) >> 3;
+ struct nand_chip *chip = mtd->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
+ int ecc_chunk_count = mxs_nand_ecc_chunk_cnt(mtd->writesize);
+ int gf_len = 13; /* length of Galois Field for non-DDR nand */
+ int max_ecc_strength;
+
+ nand_of_parse_node(mtd, mtd->parent->device_node);
+
+ max_ecc_strength = ((mtd->oobsize - MXS_NAND_METADATA_SIZE) * 8)
+ / (gf_len * ecc_chunk_count);
+ /* We need the minor even number. */
+ max_ecc_strength = rounddown(max_ecc_strength, 2);
+
+ if (chip->ecc.strength) {
+ if (chip->ecc.strength > max_ecc_strength) {
+ dev_err(nand_info->dev, "invalid ecc strength %d (maximum %d)\n",
+ chip->ecc.strength, max_ecc_strength);
+ return -EINVAL;
+ }
+ } else {
+ chip->ecc.strength = max_ecc_strength;
+ }
+
+ if (chip->ecc.size && chip->ecc.size != MXS_NAND_CHUNK_DATA_CHUNK_SIZE) {
+ dev_err(nand_info->dev, "invalid ecc size %d, this driver only supports %d\n",
+ chip->ecc.size, MXS_NAND_CHUNK_DATA_CHUNK_SIZE);
+ return -EINVAL;
+ }
+
+ chip->ecc.bytes = DIV_ROUND_UP(13 * chip->ecc.strength, 8);
+ chip->ecc.size = MXS_NAND_CHUNK_DATA_CHUNK_SIZE;
+
+ nand_info->bb_mark_bit_offset = mxs_nand_get_mark_offset(mtd);
+
+ return 0;
}
-uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd)
+static struct mtd_info *mxs_nand_mtd;
+
+int mxs_nand_get_geo(int *ecc_strength, int *bb_mark_bit_offset)
{
- uint32_t ecc_strength;
- ecc_strength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize);
- return mxs_nand_get_mark_offset(mtd->writesize, ecc_strength) & 0x7;
+ struct nand_chip *chip;
+ struct mxs_nand_info *nand_info;
+
+ if (!mxs_nand_mtd)
+ return -ENODEV;
+
+ chip = mxs_nand_mtd->priv;
+ nand_info = chip->priv;
+
+ *ecc_strength = chip->ecc.strength;
+ *bb_mark_bit_offset = nand_info->bb_mark_bit_offset;
+
+ return 0;
}
/*
@@ -396,8 +423,8 @@ static int mxs_nand_wait_for_bch_complete(struct mxs_nand_info *nand_info)
*/
static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
{
- struct nand_chip *nand = mtd->priv;
- struct mxs_nand_info *nand_info = nand->priv;
+ struct nand_chip *chip = mtd->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
struct mxs_dma_desc *d;
uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip;
int ret;
@@ -496,12 +523,12 @@ static int mxs_nand_device_ready(struct mtd_info *mtd)
/*
* Select the NAND chip.
*/
-static void mxs_nand_select_chip(struct mtd_info *mtd, int chip)
+static void mxs_nand_select_chip(struct mtd_info *mtd, int chipnum)
{
- struct nand_chip *nand = mtd->priv;
- struct mxs_nand_info *nand_info = nand->priv;
+ struct nand_chip *chip = mtd->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
- nand_info->cur_chip = chip;
+ nand_info->cur_chip = chipnum;
}
/*
@@ -527,8 +554,8 @@ static void mxs_nand_swap_block_mark(struct mtd_info *mtd,
if (nand_info->version == GPMI_VERSION_TYPE_MX23)
return;
- bit_offset = mxs_nand_mark_bit_offset(mtd);
- buf_offset = mxs_nand_mark_byte_offset(mtd);
+ bit_offset = nand_info->bb_mark_bit_offset & 0x7;
+ buf_offset = nand_info->bb_mark_bit_offset >> 3;
/*
* Get the byte from the data area that overlays the block mark. Since
@@ -555,8 +582,8 @@ static void mxs_nand_swap_block_mark(struct mtd_info *mtd,
*/
static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length)
{
- struct nand_chip *nand = mtd->priv;
- struct mxs_nand_info *nand_info = nand->priv;
+ struct nand_chip *chip = mtd->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
struct mxs_dma_desc *d;
uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip;
int ret;
@@ -633,8 +660,8 @@ rtn:
static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
int length)
{
- struct nand_chip *nand = mtd->priv;
- struct mxs_nand_info *nand_info = nand->priv;
+ struct nand_chip *chip = mtd->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
struct mxs_dma_desc *d;
uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip;
int ret;
@@ -690,8 +717,8 @@ static uint8_t mxs_nand_read_byte(struct mtd_info *mtd)
static void mxs_nand_config_bch(struct mtd_info *mtd, int readlen)
{
- struct nand_chip *nand = mtd->priv;
- struct mxs_nand_info *nand_info = nand->priv;
+ struct nand_chip *chip = mtd->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
int chunk_size;
void __iomem *bch_regs = nand_info->bch_base;
@@ -703,13 +730,13 @@ static void mxs_nand_config_bch(struct mtd_info *mtd, int readlen)
writel((mxs_nand_ecc_chunk_cnt(readlen) - 1)
<< BCH_FLASHLAYOUT0_NBLOCKS_OFFSET |
MXS_NAND_METADATA_SIZE << BCH_FLASHLAYOUT0_META_SIZE_OFFSET |
- (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
+ (chip->ecc.strength >> 1)
<< IMX6_BCH_FLASHLAYOUT0_ECC0_OFFSET |
chunk_size,
bch_regs + BCH_FLASH0LAYOUT0);
writel(readlen << BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET |
- (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1)
+ (chip->ecc.strength >> 1)
<< IMX6_BCH_FLASHLAYOUT1_ECCN_OFFSET |
chunk_size,
bch_regs + BCH_FLASH0LAYOUT1);
@@ -718,25 +745,23 @@ static void mxs_nand_config_bch(struct mtd_info *mtd, int readlen)
/*
* Read a page from NAND.
*/
-static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
+static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page,
int readlen)
{
- struct mxs_nand_info *nand_info = nand->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
struct mxs_dma_desc *d;
uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip;
uint32_t corrected = 0, failed = 0;
uint8_t *status;
unsigned int max_bitflips = 0;
- int i, ret, readtotal, nchunks, eccstrength;
-
- eccstrength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize);
+ int i, ret, readtotal, nchunks;
readlen = roundup(readlen, MXS_NAND_CHUNK_DATA_CHUNK_SIZE);
nchunks = mxs_nand_ecc_chunk_cnt(readlen);
readtotal = MXS_NAND_METADATA_SIZE;
readtotal += MXS_NAND_CHUNK_DATA_CHUNK_SIZE * nchunks;
- readtotal += DIV_ROUND_UP(13 * eccstrength * nchunks, 8);
+ readtotal += DIV_ROUND_UP(13 * chip->ecc.strength * nchunks, 8);
mxs_nand_config_bch(mtd, readtotal);
@@ -899,9 +924,9 @@ static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand
* necessary, it has already been done, so we can rely on the first
* byte of the auxiliary buffer to contain the block mark.
*/
- memset(nand->oob_poi, 0xff, mtd->oobsize);
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
- nand->oob_poi[0] = nand_info->oob_buf[0];
+ chip->oob_poi[0] = nand_info->oob_buf[0];
ret = 0;
rtn:
@@ -912,10 +937,10 @@ rtn:
return ret ? ret : max_bitflips;
}
-static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
+static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- return __mxs_nand_ecc_read_page(mtd, nand, buf, oob_required, page,
+ return __mxs_nand_ecc_read_page(mtd, chip, buf, oob_required, page,
mtd->writesize);
}
@@ -939,16 +964,16 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
* Write a page to NAND.
*/
static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
- struct nand_chip *nand, const uint8_t *buf,
+ struct nand_chip *chip, const uint8_t *buf,
int oob_required)
{
- struct mxs_nand_info *nand_info = nand->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
struct mxs_dma_desc *d;
uint32_t channel = nand_info->dma_channel_base + nand_info->cur_chip;
int ret = 0;
memcpy(nand_info->data_buf, buf, mtd->writesize);
- memcpy(nand_info->oob_buf, nand->oob_poi, mtd->oobsize);
+ memcpy(nand_info->oob_buf, chip->oob_poi, mtd->oobsize);
/* Handle block mark swapping. */
mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf);
@@ -1112,10 +1137,10 @@ static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs)
* raw_oob_mode field so that, when control finally arrives here, we'll know
* what to do.
*/
-static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
+static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
- struct mxs_nand_info *nand_info = nand->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
int column;
/*
@@ -1128,18 +1153,18 @@ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
* If control arrives here, we're doing a "raw" read. Send the
* command to read the conventional OOB and read it.
*/
- nand->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
- nand->read_buf(mtd, nand->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
} else {
/*
* If control arrives here, we're not doing a "raw" read. Fill
* the OOB buffer with set bits and correct the block mark.
*/
- memset(nand->oob_poi, 0xff, mtd->oobsize);
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
column = nand_info->version == GPMI_VERSION_TYPE_MX23 ? 0 : mtd->writesize;
- nand->cmdfunc(mtd, NAND_CMD_READ0, column, page);
- mxs_nand_read_buf(mtd, nand->oob_poi, 1);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, column, page);
+ mxs_nand_read_buf(mtd, chip->oob_poi, 1);
}
return 0;
@@ -1149,10 +1174,10 @@ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
/*
* Write OOB data to NAND.
*/
-static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
+static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
- struct mxs_nand_info *nand_info = nand->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
int column;
uint8_t block_mark = 0;
@@ -1172,12 +1197,12 @@ static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
column = nand_info->version == GPMI_VERSION_TYPE_MX23 ? 0 : mtd->writesize;
/* Write the block mark. */
- nand->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
- nand->write_buf(mtd, &block_mark, 1);
- nand->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
+ chip->write_buf(mtd, &block_mark, 1);
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
/* Check if it worked. */
- if (nand->waitfunc(mtd, nand) & NAND_STATUS_FAIL)
+ if (chip->waitfunc(mtd, chip) & NAND_STATUS_FAIL)
return -EIO;
return 0;
@@ -1217,8 +1242,8 @@ static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
*/
static int mxs_nand_scan_bbt(struct mtd_info *mtd)
{
- struct nand_chip *nand = mtd->priv;
- struct mxs_nand_info *nand_info = nand->priv;
+ struct nand_chip *chip = mtd->priv;
+ struct mxs_nand_info *nand_info = chip->priv;
void __iomem *bch_regs = nand_info->bch_base;
int ret;
@@ -1346,13 +1371,13 @@ err1:
static void mxs_nand_probe_dt(struct device_d *dev, struct mxs_nand_info *nand_info)
{
- struct nand_chip *nand = &nand_info->nand_chip;
+ struct nand_chip *chip = &nand_info->nand_chip;
if (!IS_ENABLED(CONFIG_OFTREE))
return;
if (of_get_nand_on_flash_bbt(dev->device_node))
- nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
+ chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
}
/**
@@ -1433,7 +1458,7 @@ static int mxs_nand_compute_hardware_timing(struct mxs_nand_info *info,
struct gpmi_nfc_hardware_timing *hw)
{
struct timing_threshold *nfc = &timing_default_threshold;
- struct nand_chip *nand = &info->nand_chip;
+ struct nand_chip *chip = &info->nand_chip;
struct nand_timing target = info->timing;
unsigned long clock_frequency_in_hz;
unsigned int clock_period_in_ns;
@@ -1454,11 +1479,11 @@ static int mxs_nand_compute_hardware_timing(struct mxs_nand_info *info,
* If there are multiple chips, we need to relax the timings to allow
* for signal distortion due to higher capacitance.
*/
- if (nand->numchips > 2) {
+ if (chip->numchips > 2) {
target.data_setup_in_ns += 10;
target.data_hold_in_ns += 10;
target.address_setup_in_ns += 10;
- } else if (nand->numchips > 1) {
+ } else if (chip->numchips > 1) {
target.data_setup_in_ns += 5;
target.data_hold_in_ns += 5;
target.address_setup_in_ns += 5;
@@ -2004,7 +2029,7 @@ static void mxs_nand_compute_edo_timing(struct mxs_nand_info *info,
static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info)
{
- struct nand_chip *nand = &info->nand_chip;
+ struct nand_chip *chip = &info->nand_chip;
struct mtd_info *mtd = &info->mtd;
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
int ret, mode;
@@ -2012,10 +2037,10 @@ static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info)
if (!mxs_nand_is_imx6(info))
return -ENODEV;
- if (!nand->onfi_version)
+ if (!chip->onfi_version)
return -ENOENT;
- mode = onfi_get_async_timing_mode(nand);
+ mode = onfi_get_async_timing_mode(chip);
/* We only support the timing mode 4 and mode 5. */
if (mode & ONFI_TIMING_MODE_5)
@@ -2025,27 +2050,27 @@ static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info)
else
return -EINVAL;
- nand->select_chip(mtd, 0);
+ chip->select_chip(mtd, 0);
- if (le16_to_cpu(nand->onfi_params.opt_cmd)
+ if (le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES) {
/* [1] send SET FEATURE commond to NAND */
feature[0] = mode;
- ret = nand->onfi_set_features(mtd, nand,
+ ret = chip->onfi_set_features(mtd, chip,
ONFI_FEATURE_ADDR_TIMING_MODE, feature);
if (ret)
goto err_out;
/* [2] send GET FEATURE command to double-check the timing mode */
- ret = nand->onfi_get_features(mtd, nand,
+ ret = chip->onfi_get_features(mtd, chip,
ONFI_FEATURE_ADDR_TIMING_MODE, feature);
if (ret || feature[0] != mode)
goto err_out;
}
- nand->select_chip(mtd, -1);
+ chip->select_chip(mtd, -1);
/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
clk_disable(info->clk);
@@ -2057,7 +2082,7 @@ static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info)
return mode;
err_out:
- nand->select_chip(mtd, -1);
+ chip->select_chip(mtd, -1);
return -EINVAL;
}
@@ -2112,11 +2137,15 @@ static int mxs_nand_probe(struct device_d *dev)
{
struct resource *iores;
struct mxs_nand_info *nand_info;
- struct nand_chip *nand;
+ struct nand_chip *chip;
struct mtd_info *mtd;
enum gpmi_type type;
int err;
+ /* We expect only one */
+ if (mxs_nand_mtd)
+ return -EBUSY;
+
err = dev_get_drvdata(dev, (const void **)&type);
if (err)
type = GPMI_MXS;
@@ -2165,50 +2194,49 @@ static int mxs_nand_probe(struct device_d *dev)
if (err)
goto err2;
- memset(&fake_ecc_layout, 0, sizeof(fake_ecc_layout));
-
/* structures must be linked */
- nand = &nand_info->nand_chip;
+ chip = &nand_info->nand_chip;
mtd = &nand_info->mtd;
- mtd->priv = nand;
+ mtd->priv = chip;
mtd->parent = dev;
- nand->priv = nand_info;
+ chip->priv = nand_info;
- nand->cmd_ctrl = mxs_nand_cmd_ctrl;
+ chip->cmd_ctrl = mxs_nand_cmd_ctrl;
- nand->dev_ready = mxs_nand_device_ready;
- nand->select_chip = mxs_nand_select_chip;
- nand->block_bad = mxs_nand_block_bad;
- nand->scan_bbt = mxs_nand_scan_bbt;
+ chip->dev_ready = mxs_nand_device_ready;
+ chip->select_chip = mxs_nand_select_chip;
+ chip->block_bad = mxs_nand_block_bad;
+ chip->scan_bbt = mxs_nand_scan_bbt;
- nand->read_byte = mxs_nand_read_byte;
+ chip->read_byte = mxs_nand_read_byte;
- nand->read_buf = mxs_nand_read_buf;
- nand->write_buf = mxs_nand_write_buf;
+ chip->read_buf = mxs_nand_read_buf;
+ chip->write_buf = mxs_nand_write_buf;
- nand->ecc.read_page = mxs_nand_ecc_read_page;
- nand->ecc.write_page = mxs_nand_ecc_write_page;
- nand->ecc.read_oob = mxs_nand_ecc_read_oob;
- nand->ecc.write_oob = mxs_nand_ecc_write_oob;
+ chip->ecc.read_page = mxs_nand_ecc_read_page;
+ chip->ecc.write_page = mxs_nand_ecc_write_page;
+ chip->ecc.read_oob = mxs_nand_ecc_read_oob;
+ chip->ecc.write_oob = mxs_nand_ecc_write_oob;
- nand->ecc.layout = &fake_ecc_layout;
- nand->ecc.mode = NAND_ECC_HW;
- nand->ecc.bytes = 9;
- nand->ecc.size = 512;
- nand->ecc.strength = 8;
+ chip->ecc.layout = &fake_ecc_layout;
+ chip->ecc.mode = NAND_ECC_HW;
/* first scan to find the device and get the page size */
err = nand_scan_ident(mtd, 4, NULL);
if (err)
goto err2;
- if ((13 * mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) % 8) == 0) {
- nand->ecc.read_subpage = gpmi_ecc_read_subpage;
- nand->options |= NAND_SUBPAGE_READ;
+ err = mxs_nand_calc_geo(mtd);
+ if (err)
+ goto err2;
+
+ if ((13 * chip->ecc.strength % 8) == 0) {
+ chip->ecc.read_subpage = gpmi_ecc_read_subpage;
+ chip->options |= NAND_SUBPAGE_READ;
}
- nand->options |= NAND_NO_SUBPAGE_WRITE;
+ chip->options |= NAND_NO_SUBPAGE_WRITE;
mxs_nand_setup_timing(nand_info);
@@ -2217,12 +2245,21 @@ static int mxs_nand_probe(struct device_d *dev)
if (err)
goto err2;
- return add_mtd_nand_device(mtd, "nand");
+ err = add_mtd_nand_device(mtd, "nand");
+ if (err)
+ goto err2;
+
+ mxs_nand_mtd = mtd;
+
+ return 0;
err2:
free(nand_info->data_buf);
free(nand_info->cmd_buf);
err1:
free(nand_info);
+
+ mxs_nand_mtd = NULL;
+
return err;
}