summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/raw/marvell_nand.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-10-23 01:09:22 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-23 01:09:22 +0100
commita36cf6865120d7534fcb132d311f03e5159f2da7 (patch)
tree1c9beded305965ce4493502e9873ffb43bf04880 /drivers/mtd/nand/raw/marvell_nand.c
parentb8e445b6895cfe76c5959a7135a3216703fe32d4 (diff)
parent042c1a5a6021f73c10dc84958c287eb2a2a26f7c (diff)
Merge tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd
Pull mtd updates from Boris Brezillon: "SPI NOR core changes: - Support non-uniform erase size - Support controllers with limited TX fifo size Driver changes: - m25p80: Re-issue a WREN command after each write access - cadence: Pass a proper dir value to dma_[un]map_single() - fsl-qspi: Check fsl_qspi_get_seqid() return val make sure 4B addressing opcodes are properly handled - intel-spi: Add a new PCI entry for Ice Lake Raw NAND core changes: - Two batchs of cleanups of the NAND API, including: * Deprecating a lot of interfaces (now replaced by ->exec_op()). * Moving code in separate drivers (JEDEC, ONFI), in private files (internals), in platform drivers, etc. * Functions/structures reordering. * Exclusive use of the nand_chip structure instead of the MTD one all across the subsystem. - Addition of the nand_wait_readrdy/rdy_op() helpers. Raw NAND controllers drivers changes: - Various coccinelle patches. - Marvell: * Use regmap_update_bits() for syscon access. * More documentation. * BCH failure path rework. * More layouts to be supported. * IRQ handler complete() condition fixed. - Fsl_ifc: * SRAM initialization fixed for newer controller versions. - Denali: * Fix licenses mismatch and use a SPDX tag. * Set SPARE_AREA_SKIP_BYTES register to 8 if unset. - Qualcomm: * Do not include dma-direct.h. - Docg4: * Removed. - Ams-delta: * Use of a GPIO lookup table * Internal machinery changes. Raw NAND chip drivers changes: - Toshiba: * Add support for Toshiba memory BENAND * Pass a single nand_chip object to the status helper. - ESMT: * New driver to retrieve the ECC requirements from the 5th ID byte. MTD changes: - physmap cleanups/fixe - gpio-addr-flash cleanups/fixes" * tag 'mtd/for-4.20' of git://git.infradead.org/linux-mtd: (93 commits) jffs2: free jffs2_sb_info through jffs2_kill_sb() mtd: spi-nor: fsl-quadspi: fix read error for flash size larger than 16MB mtd: spi-nor: intel-spi: Add support for Intel Ice Lake SPI serial flash mtd: maps: gpio-addr-flash: Convert to gpiod mtd: maps: gpio-addr-flash: Replace array with an integer mtd: maps: gpio-addr-flash: Use order instead of size mtd: spi-nor: fsl-quadspi: Don't let -EINVAL on the bus mtd: devices: m25p80: Make sure WRITE_EN is issued before each write mtd: spi-nor: Support controllers with limited TX FIFO size mtd: spi-nor: cadence-quadspi: Use proper enum for dma_[un]map_single mtd: spi-nor: parse SFDP Sector Map Parameter Table mtd: spi-nor: add support to non-uniform SFDP SPI NOR flash memories mtd: rawnand: marvell: fix the IRQ handler complete() condition mtd: rawnand: denali: set SPARE_AREA_SKIP_BYTES register to 8 if unset mtd: rawnand: r852: fix spelling mistake "card_registred" -> "card_registered" mtd: rawnand: toshiba: Pass a single nand_chip object to the status helper mtd: maps: gpio-addr-flash: Use devm_* functions mtd: maps: gpio-addr-flash: Fix ioremapped size mtd: maps: gpio-addr-flash: Replace custom printk mtd: physmap_of: Release resources on error ...
Diffstat (limited to 'drivers/mtd/nand/raw/marvell_nand.c')
-rw-r--r--drivers/mtd/nand/raw/marvell_nand.c275
1 files changed, 187 insertions, 88 deletions
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c
index bc2ef5209783..650f2b490a05 100644
--- a/drivers/mtd/nand/raw/marvell_nand.c
+++ b/drivers/mtd/nand/raw/marvell_nand.c
@@ -5,6 +5,73 @@
* Copyright (C) 2017 Marvell
* Author: Miquel RAYNAL <miquel.raynal@free-electrons.com>
*
+ *
+ * This NAND controller driver handles two versions of the hardware,
+ * one is called NFCv1 and is available on PXA SoCs and the other is
+ * called NFCv2 and is available on Armada SoCs.
+ *
+ * The main visible difference is that NFCv1 only has Hamming ECC
+ * capabilities, while NFCv2 also embeds a BCH ECC engine. Also, DMA
+ * is not used with NFCv2.
+ *
+ * The ECC layouts are depicted in details in Marvell AN-379, but here
+ * is a brief description.
+ *
+ * When using Hamming, the data is split in 512B chunks (either 1, 2
+ * or 4) and each chunk will have its own ECC "digest" of 6B at the
+ * beginning of the OOB area and eventually the remaining free OOB
+ * bytes (also called "spare" bytes in the driver). This engine
+ * corrects up to 1 bit per chunk and detects reliably an error if
+ * there are at most 2 bitflips. Here is the page layout used by the
+ * controller when Hamming is chosen:
+ *
+ * +-------------------------------------------------------------+
+ * | Data 1 | ... | Data N | ECC 1 | ... | ECCN | Free OOB bytes |
+ * +-------------------------------------------------------------+
+ *
+ * When using the BCH engine, there are N identical (data + free OOB +
+ * ECC) sections and potentially an extra one to deal with
+ * configurations where the chosen (data + free OOB + ECC) sizes do
+ * not align with the page (data + OOB) size. ECC bytes are always
+ * 30B per ECC chunk. Here is the page layout used by the controller
+ * when BCH is chosen:
+ *
+ * +-----------------------------------------
+ * | Data 1 | Free OOB bytes 1 | ECC 1 | ...
+ * +-----------------------------------------
+ *
+ * -------------------------------------------
+ * ... | Data N | Free OOB bytes N | ECC N |
+ * -------------------------------------------
+ *
+ * --------------------------------------------+
+ * Last Data | Last Free OOB bytes | Last ECC |
+ * --------------------------------------------+
+ *
+ * In both cases, the layout seen by the user is always: all data
+ * first, then all free OOB bytes and finally all ECC bytes. With BCH,
+ * ECC bytes are 30B long and are padded with 0xFF to align on 32
+ * bytes.
+ *
+ * The controller has certain limitations that are handled by the
+ * driver:
+ * - It can only read 2k at a time. To overcome this limitation, the
+ * driver issues data cycles on the bus, without issuing new
+ * CMD + ADDR cycles. The Marvell term is "naked" operations.
+ * - The ECC strength in BCH mode cannot be tuned. It is fixed 16
+ * bits. What can be tuned is the ECC block size as long as it
+ * stays between 512B and 2kiB. It's usually chosen based on the
+ * chip ECC requirements. For instance, using 2kiB ECC chunks
+ * provides 4b/512B correctability.
+ * - The controller will always treat data bytes, free OOB bytes
+ * and ECC bytes in that order, no matter what the real layout is
+ * (which is usually all data then all OOB bytes). The
+ * marvell_nfc_layouts array below contains the currently
+ * supported layouts.
+ * - Because of these weird layouts, the Bad Block Markers can be
+ * located in data section. In this case, the NAND_BBT_NO_OOB_BBM
+ * option must be set to prevent scanning/writing bad block
+ * markers.
*/
#include <linux/module.h>
@@ -217,8 +284,11 @@ static const struct marvell_hw_ecc_layout marvell_nfc_layouts[] = {
MARVELL_LAYOUT( 512, 512, 1, 1, 1, 512, 8, 8, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 1, 1, 1, 2048, 40, 24, 0, 0, 0),
MARVELL_LAYOUT( 2048, 512, 4, 1, 1, 2048, 32, 30, 0, 0, 0),
+ MARVELL_LAYOUT( 2048, 512, 8, 2, 1, 1024, 0, 30,1024,32, 30),
MARVELL_LAYOUT( 4096, 512, 4, 2, 2, 2048, 32, 30, 0, 0, 0),
MARVELL_LAYOUT( 4096, 512, 8, 5, 4, 1024, 0, 30, 0, 64, 30),
+ MARVELL_LAYOUT( 8192, 512, 4, 4, 4, 2048, 0, 30, 0, 0, 0),
+ MARVELL_LAYOUT( 8192, 512, 8, 9, 8, 1024, 0, 30, 0, 160, 30),
};
/**
@@ -634,9 +704,8 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms)
return 0;
}
-static void marvell_nfc_select_chip(struct mtd_info *mtd, int die_nr)
+static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
u32 ndcr_generic;
@@ -686,7 +755,7 @@ static irqreturn_t marvell_nfc_isr(int irq, void *dev_id)
marvell_nfc_disable_int(nfc, st & NDCR_ALL_INT);
- if (!(st & (NDSR_RDDREQ | NDSR_WRDREQ | NDSR_WRCMDREQ)))
+ if (st & (NDSR_RDY(0) | NDSR_RDY(1)))
complete(&nfc->complete);
return IRQ_HANDLED;
@@ -959,18 +1028,15 @@ static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip,
return ret;
}
-static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi,
true, page);
}
-static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
- struct nand_chip *chip,
- u8 *buf, int oob_required,
- int page)
+static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf,
+ int oob_required, int page)
{
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
unsigned int full_sz = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
@@ -1008,8 +1074,7 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct mtd_info *mtd,
* it appears before the ECC bytes when reading), the ->read_oob_raw() function
* also stands for ->read_oob().
*/
-static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
@@ -1073,8 +1138,7 @@ static int marvell_nfc_hw_ecc_hmg_do_write_page(struct nand_chip *chip,
return ret;
}
-static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1082,8 +1146,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct mtd_info *mtd,
true, page);
}
-static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1102,10 +1165,11 @@ static int marvell_nfc_hw_ecc_hmg_write_page(struct mtd_info *mtd,
* it appears before the ECC bytes when reading), the ->write_oob_raw() function
* also stands for ->write_oob().
*/
-static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Invalidate page cache */
chip->pagebuf = -1;
@@ -1116,10 +1180,10 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct mtd_info *mtd,
}
/* BCH read helpers */
-static int marvell_nfc_hw_ecc_bch_read_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip, u8 *buf,
+static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
u8 *oob = chip->oob_poi;
int chunk_size = lt->data_bytes + lt->spare_bytes + lt->ecc_bytes;
@@ -1228,17 +1292,17 @@ static void marvell_nfc_hw_ecc_bch_read_chunk(struct nand_chip *chip, int chunk,
}
}
-static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip,
u8 *buf, int oob_required,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
- int data_len = lt->data_bytes, spare_len = lt->spare_bytes, ecc_len;
- u8 *data = buf, *spare = chip->oob_poi, *ecc;
+ int data_len = lt->data_bytes, spare_len = lt->spare_bytes;
+ u8 *data = buf, *spare = chip->oob_poi;
int max_bitflips = 0;
u32 failure_mask = 0;
- int chunk, ecc_offset_in_page, ret;
+ int chunk, ret;
/*
* With BCH, OOB is not fully used (and thus not read entirely), not
@@ -1279,73 +1343,98 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct mtd_info *mtd,
* the controller in normal mode and must be re-read in raw mode. To
* avoid dropping the performances, we prefer not to include them. The
* user should re-read the page in raw mode if ECC bytes are required.
+ */
+
+ /*
+ * In case there is any subpage read error reported by ->correct(), we
+ * usually re-read only ECC bytes in raw mode and check if the whole
+ * page is empty. In this case, it is normal that the ECC check failed
+ * and we just ignore the error.
*
- * However, for any subpage read error reported by ->correct(), the ECC
- * bytes must be read in raw mode and the full subpage must be checked
- * to see if it is entirely empty of if there was an actual error.
+ * However, it has been empirically observed that for some layouts (e.g
+ * 2k page, 8b strength per 512B chunk), the controller tries to correct
+ * bits and may create itself bitflips in the erased area. To overcome
+ * this strange behavior, the whole page is re-read in raw mode, not
+ * only the ECC bytes.
*/
for (chunk = 0; chunk < lt->nchunks; chunk++) {
+ int data_off_in_page, spare_off_in_page, ecc_off_in_page;
+ int data_off, spare_off, ecc_off;
+ int data_len, spare_len, ecc_len;
+
/* No failure reported for this chunk, move to the next one */
if (!(failure_mask & BIT(chunk)))
continue;
- /* Derive ECC bytes positions (in page/buffer) and length */
- ecc = chip->oob_poi +
- (lt->full_chunk_cnt * lt->spare_bytes) +
- lt->last_spare_bytes +
- (chunk * ALIGN(lt->ecc_bytes, 32));
- ecc_offset_in_page =
- (chunk * (lt->data_bytes + lt->spare_bytes +
- lt->ecc_bytes)) +
- (chunk < lt->full_chunk_cnt ?
- lt->data_bytes + lt->spare_bytes :
- lt->last_data_bytes + lt->last_spare_bytes);
- ecc_len = chunk < lt->full_chunk_cnt ?
- lt->ecc_bytes : lt->last_ecc_bytes;
-
- /* Do the actual raw read of the ECC bytes */
- nand_change_read_column_op(chip, ecc_offset_in_page,
- ecc, ecc_len, false);
-
- /* Derive data/spare bytes positions (in buffer) and length */
- data = buf + (chunk * lt->data_bytes);
- data_len = chunk < lt->full_chunk_cnt ?
- lt->data_bytes : lt->last_data_bytes;
- spare = chip->oob_poi + (chunk * (lt->spare_bytes +
- lt->ecc_bytes));
- spare_len = chunk < lt->full_chunk_cnt ?
- lt->spare_bytes : lt->last_spare_bytes;
+ data_off_in_page = chunk * (lt->data_bytes + lt->spare_bytes +
+ lt->ecc_bytes);
+ spare_off_in_page = data_off_in_page +
+ (chunk < lt->full_chunk_cnt ? lt->data_bytes :
+ lt->last_data_bytes);
+ ecc_off_in_page = spare_off_in_page +
+ (chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+ lt->last_spare_bytes);
+
+ data_off = chunk * lt->data_bytes;
+ spare_off = chunk * lt->spare_bytes;
+ ecc_off = (lt->full_chunk_cnt * lt->spare_bytes) +
+ lt->last_spare_bytes +
+ (chunk * (lt->ecc_bytes + 2));
+
+ data_len = chunk < lt->full_chunk_cnt ? lt->data_bytes :
+ lt->last_data_bytes;
+ spare_len = chunk < lt->full_chunk_cnt ? lt->spare_bytes :
+ lt->last_spare_bytes;
+ ecc_len = chunk < lt->full_chunk_cnt ? lt->ecc_bytes :
+ lt->last_ecc_bytes;
+
+ /*
+ * Only re-read the ECC bytes, unless we are using the 2k/8b
+ * layout which is buggy in the sense that the ECC engine will
+ * try to correct data bytes anyway, creating bitflips. In this
+ * case, re-read the entire page.
+ */
+ if (lt->writesize == 2048 && lt->strength == 8) {
+ nand_change_read_column_op(chip, data_off_in_page,
+ buf + data_off, data_len,
+ false);
+ nand_change_read_column_op(chip, spare_off_in_page,
+ chip->oob_poi + spare_off, spare_len,
+ false);
+ }
+
+ nand_change_read_column_op(chip, ecc_off_in_page,
+ chip->oob_poi + ecc_off, ecc_len,
+ false);
/* Check the entire chunk (data + spare + ecc) for emptyness */
- marvell_nfc_check_empty_chunk(chip, data, data_len, spare,
- spare_len, ecc, ecc_len,
+ marvell_nfc_check_empty_chunk(chip, buf + data_off, data_len,
+ chip->oob_poi + spare_off, spare_len,
+ chip->oob_poi + ecc_off, ecc_len,
&max_bitflips);
}
return max_bitflips;
}
-static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_read_oob_raw(struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
- return chip->ecc.read_page_raw(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.read_page_raw(chip, chip->data_buf, true, page);
}
-static int marvell_nfc_hw_ecc_bch_read_oob(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_read_oob(struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
- return chip->ecc.read_page(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.read_page(chip, chip->data_buf, true, page);
}
/* BCH write helpers */
-static int marvell_nfc_hw_ecc_bch_write_page_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
@@ -1458,11 +1547,11 @@ marvell_nfc_hw_ecc_bch_write_chunk(struct nand_chip *chip, int chunk,
return 0;
}
-static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip,
const u8 *buf,
int oob_required, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
const struct marvell_hw_ecc_layout *lt = to_marvell_nand(chip)->layout;
const u8 *data = buf;
const u8 *spare = chip->oob_poi;
@@ -1507,27 +1596,29 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct mtd_info *mtd,
return 0;
}
-static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct mtd_info *mtd,
- struct nand_chip *chip,
+static int marvell_nfc_hw_ecc_bch_write_oob_raw(struct nand_chip *chip,
int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Invalidate page cache */
chip->pagebuf = -1;
memset(chip->data_buf, 0xFF, mtd->writesize);
- return chip->ecc.write_page_raw(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.write_page_raw(chip, chip->data_buf, true, page);
}
-static int marvell_nfc_hw_ecc_bch_write_oob(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
+static int marvell_nfc_hw_ecc_bch_write_oob(struct nand_chip *chip, int page)
{
+ struct mtd_info *mtd = nand_to_mtd(chip);
+
/* Invalidate page cache */
chip->pagebuf = -1;
memset(chip->data_buf, 0xFF, mtd->writesize);
- return chip->ecc.write_page(mtd, chip, chip->data_buf, true, page);
+ return chip->ecc.write_page(chip, chip->data_buf, true, page);
}
/* NAND framework ->exec_op() hooks and related helpers */
@@ -2097,6 +2188,16 @@ static int marvell_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
return -ENOTSUPP;
}
+ /* Special care for the layout 2k/8-bit/512B */
+ if (l->writesize == 2048 && l->strength == 8) {
+ if (mtd->oobsize < 128) {
+ dev_err(nfc->dev, "Requested layout needs at least 128 OOB bytes\n");
+ return -ENOTSUPP;
+ } else {
+ chip->bbt_options |= NAND_BBT_NO_OOB_BBM;
+ }
+ }
+
mtd_set_ooblayout(mtd, &marvell_nand_ooblayout_ops);
ecc->steps = l->nchunks;
ecc->size = l->data_bytes;
@@ -2192,11 +2293,10 @@ static struct nand_bbt_descr bbt_mirror_descr = {
.pattern = bbt_mirror_pattern
};
-static int marvell_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr,
+static int marvell_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface
*conf)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip);
struct marvell_nfc *nfc = to_marvell_nfc(chip->controller);
unsigned int period_ns = 1000000000 / clk_get_rate(nfc->core_clk) * 2;
@@ -2540,7 +2640,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
chip->options |= NAND_BUSWIDTH_AUTO;
- ret = nand_scan(mtd, marvell_nand->nsels);
+ ret = nand_scan(chip, marvell_nand->nsels);
if (ret) {
dev_err(dev, "could not scan the nand chip\n");
return ret;
@@ -2553,7 +2653,7 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
ret = mtd_device_register(mtd, NULL, 0);
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
- nand_release(mtd);
+ nand_release(chip);
return ret;
}
@@ -2608,7 +2708,7 @@ static void marvell_nand_chips_cleanup(struct marvell_nfc *nfc)
struct marvell_nand_chip *entry, *temp;
list_for_each_entry_safe(entry, temp, &nfc->chips, node) {
- nand_release(nand_to_mtd(&entry->chip));
+ nand_release(&entry->chip);
list_del(&entry->node);
}
}
@@ -2699,24 +2799,23 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
struct regmap *sysctrl_base =
syscon_regmap_lookup_by_phandle(np,
"marvell,system-controller");
- u32 reg;
if (IS_ERR(sysctrl_base))
return PTR_ERR(sysctrl_base);
- reg = GENCONF_SOC_DEVICE_MUX_NFC_EN |
- GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
- GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
- GENCONF_SOC_DEVICE_MUX_NFC_INT_EN;
- regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
+ regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX,
+ GENCONF_SOC_DEVICE_MUX_NFC_EN |
+ GENCONF_SOC_DEVICE_MUX_ECC_CLK_RST |
+ GENCONF_SOC_DEVICE_MUX_ECC_CORE_RST |
+ GENCONF_SOC_DEVICE_MUX_NFC_INT_EN);
- regmap_read(sysctrl_base, GENCONF_CLK_GATING_CTRL, &reg);
- reg |= GENCONF_CLK_GATING_CTRL_ND_GATE;
- regmap_write(sysctrl_base, GENCONF_CLK_GATING_CTRL, reg);
+ regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
+ GENCONF_CLK_GATING_CTRL_ND_GATE,
+ GENCONF_CLK_GATING_CTRL_ND_GATE);
- regmap_read(sysctrl_base, GENCONF_ND_CLK_CTRL, &reg);
- reg |= GENCONF_ND_CLK_CTRL_EN;
- regmap_write(sysctrl_base, GENCONF_ND_CLK_CTRL, reg);
+ regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL,
+ GENCONF_ND_CLK_CTRL_EN,
+ GENCONF_ND_CLK_CTRL_EN);
}
/* Configure the DMA if appropriate */