diff options
Diffstat (limited to 'drivers/mtd/nand/raw/marvell_nand.c')
-rw-r--r-- | drivers/mtd/nand/raw/marvell_nand.c | 51 |
1 files changed, 36 insertions, 15 deletions
diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 650f2b490a05..84283c6bb0ff 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -378,7 +378,7 @@ struct marvell_nfc_caps { * @dev: Parent device (used to print error messages) * @regs: NAND controller registers * @core_clk: Core clock - * @reg_clk: Regiters clock + * @reg_clk: Registers clock * @complete: Completion object to wait for NAND controller events * @assigned_cs: Bitmask describing already assigned CS lines * @chips: List containing all the NAND chips attached to @@ -514,9 +514,14 @@ static void marvell_nfc_enable_int(struct marvell_nfc *nfc, u32 int_mask) writel_relaxed(reg & ~int_mask, nfc->regs + NDCR); } -static void marvell_nfc_clear_int(struct marvell_nfc *nfc, u32 int_mask) +static u32 marvell_nfc_clear_int(struct marvell_nfc *nfc, u32 int_mask) { + u32 reg; + + reg = readl_relaxed(nfc->regs + NDSR); writel_relaxed(int_mask, nfc->regs + NDSR); + + return reg & int_mask; } static void marvell_nfc_force_byte_access(struct nand_chip *chip, @@ -683,6 +688,7 @@ static int marvell_nfc_wait_cmdd(struct nand_chip *chip) static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms) { struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); + u32 pending; int ret; /* Timeout is expressed in ms */ @@ -695,8 +701,13 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms) ret = wait_for_completion_timeout(&nfc->complete, msecs_to_jiffies(timeout_ms)); marvell_nfc_disable_int(nfc, NDCR_RDYM); - marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1)); - if (!ret) { + pending = marvell_nfc_clear_int(nfc, NDSR_RDY(0) | NDSR_RDY(1)); + + /* + * In case the interrupt was not served in the required time frame, + * check if the ISR was not served or if something went actually wrong. + */ + if (ret && !pending) { dev_err(nfc->dev, "Timeout waiting for RB signal\n"); return -ETIMEDOUT; } @@ -704,7 +715,8 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms) return 0; } -static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr) +static void marvell_nfc_select_target(struct nand_chip *chip, + unsigned int die_nr) { struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip); struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); @@ -713,12 +725,6 @@ static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr) if (chip == nfc->selected_chip && die_nr == marvell_nand->selected_die) return; - if (die_nr < 0 || die_nr >= marvell_nand->nsels) { - nfc->selected_chip = NULL; - marvell_nand->selected_die = -1; - return; - } - writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0); writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1); @@ -1024,13 +1030,13 @@ static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip, } ret = marvell_nfc_wait_cmdd(chip); - return ret; } static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { + marvell_nfc_select_target(chip, chip->cur_cs); return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi, true, page); } @@ -1043,6 +1049,7 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf, int max_bitflips = 0, ret; u8 *raw_buf; + marvell_nfc_select_target(chip, chip->cur_cs); marvell_nfc_enable_hw_ecc(chip); marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi, false, page); @@ -1079,6 +1086,7 @@ static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page) /* Invalidate page cache */ chip->pagebuf = -1; + marvell_nfc_select_target(chip, chip->cur_cs); return marvell_nfc_hw_ecc_hmg_do_read_page(chip, chip->data_buf, chip->oob_poi, true, page); } @@ -1142,6 +1150,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { + marvell_nfc_select_target(chip, chip->cur_cs); return marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi, true, page); } @@ -1152,6 +1161,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip, { int ret; + marvell_nfc_select_target(chip, chip->cur_cs); marvell_nfc_enable_hw_ecc(chip); ret = marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi, false, page); @@ -1175,6 +1185,7 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip, memset(chip->data_buf, 0xFF, mtd->writesize); + marvell_nfc_select_target(chip, chip->cur_cs); return marvell_nfc_hw_ecc_hmg_do_write_page(chip, chip->data_buf, chip->oob_poi, true, page); } @@ -1194,6 +1205,8 @@ static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf, int ecc_len = lt->ecc_bytes; int chunk; + marvell_nfc_select_target(chip, chip->cur_cs); + if (oob_required) memset(chip->oob_poi, 0xFF, mtd->oobsize); @@ -1304,6 +1317,8 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip, u32 failure_mask = 0; int chunk, ret; + marvell_nfc_select_target(chip, chip->cur_cs); + /* * With BCH, OOB is not fully used (and thus not read entirely), not * expected bytes could show up at the end of the OOB buffer if not @@ -1448,6 +1463,8 @@ static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip, lt->last_spare_bytes; int chunk; + marvell_nfc_select_target(chip, chip->cur_cs); + nand_prog_page_begin_op(chip, page, 0, NULL, 0); for (chunk = 0; chunk < lt->nchunks; chunk++) { @@ -1559,6 +1576,8 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip, int spare_len = lt->spare_bytes; int chunk, ret; + marvell_nfc_select_target(chip, chip->cur_cs); + /* Spare data will be written anyway, so clear it to avoid garbage */ if (!oob_required) memset(chip->oob_poi, 0xFF, mtd->oobsize); @@ -2097,6 +2116,8 @@ static int marvell_nfc_exec_op(struct nand_chip *chip, { struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); + marvell_nfc_select_target(chip, op->cs); + if (nfc->caps->is_nfcv2) return nand_op_parser_exec_op(chip, &marvell_nfcv2_op_parser, op, check_only); @@ -2495,6 +2516,8 @@ static int marvell_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops marvell_nand_controller_ops = { .attach_chip = marvell_nand_attach_chip, + .exec_op = marvell_nfc_exec_op, + .setup_data_interface = marvell_nfc_setup_data_interface, }; static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, @@ -2617,10 +2640,8 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, chip->controller = &nfc->controller; nand_set_flash_node(chip, np); - chip->exec_op = marvell_nfc_exec_op; - chip->select_chip = marvell_nfc_select_chip; if (!of_property_read_bool(np, "marvell,nand-keep-config")) - chip->setup_data_interface = marvell_nfc_setup_data_interface; + chip->options |= NAND_KEEP_TIMINGS; mtd = nand_to_mtd(chip); mtd->dev.parent = dev; |