summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nand_mxs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/nand_mxs.c')
-rw-r--r--drivers/mtd/nand/nand_mxs.c172
1 files changed, 85 insertions, 87 deletions
diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c
index e2b6e21620..9f7ab14426 100644
--- a/drivers/mtd/nand/nand_mxs.c
+++ b/drivers/mtd/nand/nand_mxs.c
@@ -20,6 +20,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
+#include <linux/mtd/rawnand.h>
#include <linux/mtd/nand_mxs.h>
#include <linux/types.h>
#include <linux/clk.h>
@@ -235,8 +236,6 @@ struct mxs_nand_info {
int bb_mark_bit_offset;
};
-static struct nand_ecclayout fake_ecc_layout;
-
static inline int mxs_nand_is_imx6(struct mxs_nand_info *info)
{
return info->type == GPMI_IMX6;
@@ -330,16 +329,14 @@ static uint32_t mxs_nand_get_mark_offset(struct mtd_info *mtd)
return block_mark_bit_offset;
}
-static int mxs_nand_calc_geo(struct mtd_info *mtd)
+static int mxs_nand_calc_geo(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
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. */
@@ -420,9 +417,8 @@ static int mxs_nand_wait_for_bch_complete(struct mxs_nand_info *nand_info)
* ignore the chip enable bit and concentrate only on sending bytes to the NAND
* Flash.
*/
-static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
+static void mxs_nand_cmd_ctrl(struct nand_chip *chip, int data, unsigned int ctrl)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
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;
@@ -496,9 +492,8 @@ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
/*
* Test if the NAND flash is ready.
*/
-static int mxs_nand_device_ready(struct mtd_info *mtd)
+static int mxs_nand_device_ready(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct mxs_nand_info *nand_info = chip->priv;
void __iomem *gpmi_regs = nand_info->io_base;
uint32_t tmp;
@@ -522,9 +517,8 @@ 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 chipnum)
+static void mxs_nand_select_chip(struct nand_chip *chip, int chipnum)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct mxs_nand_info *nand_info = chip->priv;
nand_info->cur_chip = chipnum;
@@ -537,10 +531,9 @@ static void mxs_nand_select_chip(struct mtd_info *mtd, int chipnum)
* swapping the block mark, or swapping it *back* -- but it doesn't matter
* because the the operation is the same.
*/
-static void mxs_nand_swap_block_mark(struct mtd_info *mtd,
+static void mxs_nand_swap_block_mark(struct nand_chip *chip,
uint8_t *data_buf, uint8_t *oob_buf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct mxs_nand_info *nand_info = chip->priv;
uint32_t bit_offset;
@@ -579,9 +572,8 @@ static void mxs_nand_swap_block_mark(struct mtd_info *mtd,
/*
* Read data from NAND.
*/
-static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length)
+static void mxs_nand_read_buf(struct nand_chip *chip, uint8_t *buf, int length)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
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;
@@ -656,10 +648,9 @@ rtn:
/*
* Write data to NAND.
*/
-static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+static void mxs_nand_write_buf(struct nand_chip *chip, const uint8_t *buf,
int length)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
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;
@@ -707,16 +698,15 @@ static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
/*
* Read a single byte from NAND.
*/
-static uint8_t mxs_nand_read_byte(struct mtd_info *mtd)
+static uint8_t mxs_nand_read_byte(struct nand_chip *chip)
{
uint8_t buf;
- mxs_nand_read_buf(mtd, &buf, 1);
+ mxs_nand_read_buf(chip, &buf, 1);
return buf;
}
-static void mxs_nand_config_bch(struct mtd_info *mtd, int readlen)
+static void mxs_nand_config_bch(struct nand_chip *chip, int readlen)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct mxs_nand_info *nand_info = chip->priv;
int chunk_size;
void __iomem *bch_regs = nand_info->bch_base;
@@ -744,10 +734,11 @@ 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 *chip,
+static int __mxs_nand_ecc_read_page(struct nand_chip *chip,
uint8_t *buf, int oob_required, int page,
int readlen)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
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;
@@ -756,13 +747,15 @@ static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip
unsigned int max_bitflips = 0;
int i, ret, readtotal, nchunks;
+ nand_read_page_op(chip, page, 0, NULL, 0);
+
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 * chip->ecc.strength * nchunks, 8);
- mxs_nand_config_bch(mtd, readtotal);
+ mxs_nand_config_bch(chip, readtotal);
/* Compile the DMA descriptor - wait for ready. */
d = mxs_nand_get_dma_desc(nand_info);
@@ -850,7 +843,7 @@ static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip
}
/* Read DMA completed, now do the mark swapping. */
- mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf);
+ mxs_nand_swap_block_mark(chip, nand_info->data_buf, nand_info->oob_buf);
memcpy(buf, nand_info->data_buf, readlen);
@@ -931,19 +924,21 @@ static int __mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip
rtn:
mxs_nand_return_dma_descs(nand_info);
- mxs_nand_config_bch(mtd, mtd->writesize + mtd->oobsize);
+ mxs_nand_config_bch(chip, mtd->writesize + mtd->oobsize);
return ret ? ret : max_bitflips;
}
-static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int mxs_nand_ecc_read_page(struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- return __mxs_nand_ecc_read_page(mtd, chip, buf, oob_required, page,
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
+ return __mxs_nand_ecc_read_page(chip, buf, oob_required, page,
mtd->writesize);
}
-static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+static int gpmi_ecc_read_subpage(struct nand_chip *chip,
uint32_t offs, uint32_t len, uint8_t *buf, int page)
{
/*
@@ -956,26 +951,28 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
offs = 0;
}
- return __mxs_nand_ecc_read_page(mtd, chip, buf, 0, page, len);
+ return __mxs_nand_ecc_read_page(chip, buf, 0, page, len);
}
/*
* Write a page to NAND.
*/
-static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf,
- int oob_required)
+static int mxs_nand_ecc_write_page(struct nand_chip *chip, const uint8_t *buf,
+ int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
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;
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+
memcpy(nand_info->data_buf, buf, mtd->writesize);
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);
+ mxs_nand_swap_block_mark(chip, nand_info->data_buf, nand_info->oob_buf);
/* Compile the DMA descriptor - write data. */
d = mxs_nand_get_dma_desc(nand_info);
@@ -1018,7 +1015,10 @@ static int mxs_nand_ecc_write_page(struct mtd_info *mtd,
rtn:
mxs_nand_return_dma_descs(nand_info);
- return ret;
+ if (ret)
+ return ret;
+
+ return nand_prog_page_end_op(chip);
}
/*
@@ -1136,9 +1136,9 @@ 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 *chip,
- int page)
+static int mxs_nand_ecc_read_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mxs_nand_info *nand_info = chip->priv;
int column;
@@ -1152,8 +1152,8 @@ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
* If control arrives here, we're doing a "raw" read. Send the
* command to read the conventional OOB and read it.
*/
- chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READ0, mtd->writesize, page);
+ chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize);
} else {
/*
* If control arrives here, we're not doing a "raw" read. Fill
@@ -1162,8 +1162,8 @@ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
memset(chip->oob_poi, 0xff, mtd->oobsize);
column = nand_info->version == GPMI_VERSION_TYPE_MX23 ? 0 : mtd->writesize;
- chip->cmdfunc(mtd, NAND_CMD_READ0, column, page);
- mxs_nand_read_buf(mtd, chip->oob_poi, 1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_READ0, column, page);
+ mxs_nand_read_buf(chip, chip->oob_poi, 1);
}
return 0;
@@ -1173,9 +1173,9 @@ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
/*
* Write OOB data to NAND.
*/
-static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
+static int mxs_nand_ecc_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mxs_nand_info *nand_info = chip->priv;
int column;
uint8_t block_mark = 0;
@@ -1196,12 +1196,12 @@ static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
column = nand_info->version == GPMI_VERSION_TYPE_MX23 ? 0 : mtd->writesize;
/* Write the block mark. */
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
- chip->write_buf(mtd, &block_mark, 1);
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_SEQIN, column, page);
+ chip->legacy.write_buf(chip, &block_mark, 1);
+ chip->legacy.cmdfunc(chip, NAND_CMD_PAGEPROG, -1, -1);
/* Check if it worked. */
- if (chip->waitfunc(mtd, chip) & NAND_STATUS_FAIL)
+ if (chip->legacy.waitfunc(chip) & NAND_STATUS_FAIL)
return -EIO;
return 0;
@@ -1220,7 +1220,7 @@ static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
* Thus, this function is only called when we want *all* blocks to look good,
* so it *always* return success.
*/
-static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int mxs_nand_block_bad(struct nand_chip *chip , loff_t ofs)
{
return 0;
}
@@ -1239,9 +1239,9 @@ static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
* call to nand_scan(). Anything other than zero will cause this driver to
* tear everything down and declare failure.
*/
-static int mxs_nand_scan_bbt(struct mtd_info *mtd)
+static int mxs_nand_scan_bbt(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_info *mtd = nand_to_mtd(chip);
struct mxs_nand_info *nand_info = chip->priv;
void __iomem *bch_regs = nand_info->bch_base;
int ret;
@@ -1252,7 +1252,7 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)
if (ret)
return ret;
- mxs_nand_config_bch(mtd, mtd->writesize + mtd->oobsize);
+ mxs_nand_config_bch(chip, mtd->writesize + mtd->oobsize);
/* Set *all* chip selects to use layout 0 */
writel(0, bch_regs + BCH_LAYOUTSELECT);
@@ -1261,23 +1261,23 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)
writel(BCH_CTRL_COMPLETE_IRQ_EN, bch_regs + BCH_CTRL + STMP_OFFSET_REG_SET);
/* Hook some operations at the MTD level. */
- if (mtd->read_oob != mxs_nand_hook_read_oob) {
- nand_info->hooked_read_oob = mtd->read_oob;
- mtd->read_oob = mxs_nand_hook_read_oob;
+ if (mtd->_read_oob != mxs_nand_hook_read_oob) {
+ nand_info->hooked_read_oob = mtd->_read_oob;
+ mtd->_read_oob = mxs_nand_hook_read_oob;
}
- if (mtd->write_oob != mxs_nand_hook_write_oob) {
- nand_info->hooked_write_oob = mtd->write_oob;
- mtd->write_oob = mxs_nand_hook_write_oob;
+ if (mtd->_write_oob != mxs_nand_hook_write_oob) {
+ nand_info->hooked_write_oob = mtd->_write_oob;
+ mtd->_write_oob = mxs_nand_hook_write_oob;
}
- if (mtd->block_markbad != mxs_nand_hook_block_markbad) {
- nand_info->hooked_block_markbad = mtd->block_markbad;
- mtd->block_markbad = mxs_nand_hook_block_markbad;
+ if (mtd->_block_markbad != mxs_nand_hook_block_markbad) {
+ nand_info->hooked_block_markbad = mtd->_block_markbad;
+ mtd->_block_markbad = mxs_nand_hook_block_markbad;
}
/* We use the reference implementation for bad block management. */
- return nand_default_bbt(mtd);
+ return nand_create_bbt(chip);
}
/*
@@ -1478,11 +1478,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 (chip->numchips > 2) {
+ if (nanddev_ntargets(&chip->base) > 2) {
target.data_setup_in_ns += 10;
target.data_hold_in_ns += 10;
target.address_setup_in_ns += 10;
- } else if (chip->numchips > 1) {
+ } else if (nanddev_ntargets(&chip->base) > 1) {
target.data_setup_in_ns += 5;
target.data_hold_in_ns += 5;
target.address_setup_in_ns += 5;
@@ -2029,14 +2029,13 @@ 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 *chip = &info->nand_chip;
- struct mtd_info *mtd = &chip->mtd;
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
int ret, mode;
if (!mxs_nand_is_imx6(info))
return -ENODEV;
- if (!chip->onfi_version)
+ if (!chip->parameters.onfi)
return -ENOENT;
mode = onfi_get_async_timing_mode(chip);
@@ -2049,27 +2048,26 @@ static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info)
else
return -EINVAL;
- chip->select_chip(mtd, 0);
+ chip->legacy.select_chip(chip, 0);
- if (le16_to_cpu(chip->onfi_params.opt_cmd)
- & ONFI_OPT_CMD_SET_GET_FEATURES) {
+ if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) {
/* [1] send SET FEATURE commond to NAND */
feature[0] = mode;
- ret = chip->onfi_set_features(mtd, chip,
+ ret = chip->legacy.set_features(chip,
ONFI_FEATURE_ADDR_TIMING_MODE, feature);
if (ret)
goto err_out;
/* [2] send GET FEATURE command to double-check the timing mode */
- ret = chip->onfi_get_features(mtd, chip,
+ ret = chip->legacy.get_features(chip,
ONFI_FEATURE_ADDR_TIMING_MODE, feature);
if (ret || feature[0] != mode)
goto err_out;
}
- chip->select_chip(mtd, -1);
+ chip->legacy.select_chip(chip, -1);
/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
clk_disable(info->clk);
@@ -2081,7 +2079,7 @@ static int mxs_nand_enable_edo_mode(struct mxs_nand_info *info)
return mode;
err_out:
- chip->select_chip(mtd, -1);
+ chip->legacy.select_chip(chip, -1);
return -EINVAL;
}
@@ -2193,37 +2191,35 @@ static int mxs_nand_probe(struct device_d *dev)
/* structures must be linked */
chip = &nand_info->nand_chip;
- mtd = &nand_info->nand_chip.mtd;
- mtd->parent = dev;
+ mtd = nand_to_mtd(chip);
+ mtd->dev.parent = dev;
chip->priv = nand_info;
- chip->cmd_ctrl = mxs_nand_cmd_ctrl;
+ chip->legacy.cmd_ctrl = mxs_nand_cmd_ctrl;
- 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;
+ chip->legacy.dev_ready = mxs_nand_device_ready;
+ chip->legacy.select_chip = mxs_nand_select_chip;
+ chip->legacy.block_bad = mxs_nand_block_bad;
- chip->read_byte = mxs_nand_read_byte;
+ chip->legacy.read_byte = mxs_nand_read_byte;
- chip->read_buf = mxs_nand_read_buf;
- chip->write_buf = mxs_nand_write_buf;
+ chip->legacy.read_buf = mxs_nand_read_buf;
+ chip->legacy.write_buf = mxs_nand_write_buf;
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;
- 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);
+ err = nand_scan_ident(chip, 4, NULL);
if (err)
goto err2;
- err = mxs_nand_calc_geo(mtd);
+ err = mxs_nand_calc_geo(chip);
if (err)
goto err2;
@@ -2232,15 +2228,17 @@ static int mxs_nand_probe(struct device_d *dev)
chip->options |= NAND_SUBPAGE_READ;
}
- chip->options |= NAND_NO_SUBPAGE_WRITE;
+ chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_SKIP_BBTSCAN;
mxs_nand_setup_timing(nand_info);
/* second phase scan */
- err = nand_scan_tail(mtd);
+ err = nand_scan_tail(chip);
if (err)
goto err2;
+ mxs_nand_scan_bbt(chip);
+
err = add_mtd_nand_device(mtd, "nand");
if (err)
goto err2;