diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-10 13:15:17 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-10 13:15:17 -0700 |
commit | 6f51ab9440d131ae424cce27e3170746219f5142 (patch) | |
tree | e198f70fb53214ca67db8ffb76cafc29852c05df /drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c | |
parent | 6f630784cc0d92fb58ea326e2bc01aa056279ecb (diff) | |
parent | 5788ccf3c84f5587418a80128a3653aa35abf00b (diff) |
Merge tag 'mtd/for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull MTD updates from Richard Weinberger:
"MTD core changes:
- partition parser: Support MTD names containing one or more colons.
- mtdblock: clear cache_state to avoid writing to bad blocks
repeatedly.
Raw NAND core changes:
- Stop using nand_release(), patched all drivers.
- Give more information about the ECC weakness when not matching the
chip's requirement.
- MAINTAINERS updates.
- Support emulated SLC mode on MLC NANDs.
- Support "constrained" controllers, adapt the core and ONFI/JEDEC
table parsing and Micron's code.
- Take check_only into account.
- Add an invalid ECC mode to discriminate with valid ones.
- Return an enum from of_get_nand_ecc_algo().
- Drop OOB_FIRST placement scheme.
- Introduce nand_extract_bits().
- Ensure a consistent bitflips numbering.
- BCH lib:
- Allow easy bit swapping.
- Rework a little bit the exported function names.
- Fix nand_gpio_waitrdy().
- Propage CS selection to sub operations.
- Add a NAND_NO_BBM_QUIRK flag.
- Give the possibility to verify a read operation is supported.
- Add a helper to check supported operations.
- Avoid indirect access to ->data_buf().
- Rename the use_bufpoi variables.
- Fix comments about the use of bufpoi.
- Rename a NAND chip option.
- Reorder the nand_chip->options flags.
- Translate obscure bitfields into readable macros.
- Timings:
- Fix default values.
- Add mode information to the timings structure.
Raw NAND controller driver changes:
- Fixed many error paths.
- Arasan
- New driver
- Au1550nd:
- Various cleanups
- Migration to ->exec_op()
- brcmnand:
- Misc cleanup.
- Support v2.1-v2.2 controllers.
- Remove unused including <linux/version.h>.
- Correctly verify erased pages.
- Fix Hamming OOB layout.
- Cadence
- Make cadence_nand_attach_chip static.
- Cafe:
- Set the NAND_NO_BBM_QUIRK flag
- cmx270:
- Remove this controller driver.
- cs553x:
- Misc cleanup
- Migration to ->exec_op()
- Davinci:
- Misc cleanup.
- Migration to ->exec_op()
- Denali:
- Add more delays before latching incoming data
- Diskonchip:
- Misc cleanup
- Migration to ->exec_op()
- Fsmc:
- Change to non-atomic bit operations.
- GPMI:
- Use nand_extract_bits()
- Fix runtime PM imbalance.
- Ingenic:
- Migration to exec_op()
- Fix the RB gpio active-high property on qi, lb60
- Make qi_lb60_ooblayout_ops static.
- Marvell:
- Misc cleanup and small fixes
- Nandsim:
- Fix the error paths, driver wide.
- Omap_elm:
- Fix runtime PM imbalance.
- STM32_FMC2:
- Misc cleanups (error cases, comments, timeout valus, cosmetic
changes).
SPI NOR core changes:
- Add, update support and fix few flashes.
- Prepare BFPT parsing for JESD216 rev D.
- Kernel doc fixes.
CFI changes:
- Support the absence of protection registers for Intel CFI flashes.
- Replace zero-length array with flexible-arrays"
* tag 'mtd/for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (208 commits)
mtd: clear cache_state to avoid writing to bad blocks repeatedly
mtd: parser: cmdline: Support MTD names containing one or more colons
mtd: physmap_of_gemini: remove defined but not used symbol 'syscon_match'
mtd: rawnand: Add an invalid ECC mode to discriminate with valid ones
mtd: rawnand: Return an enum from of_get_nand_ecc_algo()
mtd: rawnand: Drop OOB_FIRST placement scheme
mtd: rawnand: Avoid a typedef
mtd: Fix typo in mtd_ooblayout_set_databytes() description
mtd: rawnand: Stop using nand_release()
mtd: rawnand: nandsim: Reorganize ns_cleanup_module()
mtd: rawnand: nandsim: Rename a label in ns_init_module()
mtd: rawnand: nandsim: Manage lists on error in ns_init_module()
mtd: rawnand: nandsim: Fix the label pointing on nand_cleanup()
mtd: rawnand: nandsim: Free erase_block_wear on error
mtd: rawnand: nandsim: Use an additional label when freeing the nandsim object
mtd: rawnand: nandsim: Stop using nand_release()
mtd: rawnand: nandsim: Free the partition names in ns_free()
mtd: rawnand: nandsim: Free the allocated device on error in ns_init()
mtd: rawnand: nandsim: Free partition names on error in ns_init()
mtd: rawnand: nandsim: Fix the two ns_alloc_device() error paths
...
Diffstat (limited to 'drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c')
-rw-r--r-- | drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c | 170 |
1 files changed, 107 insertions, 63 deletions
diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c index 935c4902ada7..69423bb29adb 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c @@ -27,9 +27,6 @@ #define DRV_NAME "ingenic-nand" -/* Command delay when there is no R/B pin. */ -#define RB_DELAY_US 100 - struct jz_soc_info { unsigned long data_offset; unsigned long addr_offset; @@ -49,7 +46,6 @@ struct ingenic_nfc { struct nand_controller controller; unsigned int num_banks; struct list_head chips; - int selected; struct ingenic_nand_cs cs[]; }; @@ -102,7 +98,7 @@ static int qi_lb60_ooblayout_free(struct mtd_info *mtd, int section, return 0; } -const struct mtd_ooblayout_ops qi_lb60_ooblayout_ops = { +static const struct mtd_ooblayout_ops qi_lb60_ooblayout_ops = { .ecc = qi_lb60_ooblayout_ecc, .free = qi_lb60_ooblayout_free, }; @@ -142,51 +138,6 @@ static const struct mtd_ooblayout_ops jz4725b_ooblayout_ops = { .free = jz4725b_ooblayout_free, }; -static void ingenic_nand_select_chip(struct nand_chip *chip, int chipnr) -{ - struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); - struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); - struct ingenic_nand_cs *cs; - - /* Ensure the currently selected chip is deasserted. */ - if (chipnr == -1 && nfc->selected >= 0) { - cs = &nfc->cs[nfc->selected]; - jz4780_nemc_assert(nfc->dev, cs->bank, false); - } - - nfc->selected = chipnr; -} - -static void ingenic_nand_cmd_ctrl(struct nand_chip *chip, int cmd, - unsigned int ctrl) -{ - struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); - struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); - struct ingenic_nand_cs *cs; - - if (WARN_ON(nfc->selected < 0)) - return; - - cs = &nfc->cs[nfc->selected]; - - jz4780_nemc_assert(nfc->dev, cs->bank, ctrl & NAND_NCE); - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_ALE) - writeb(cmd, cs->base + nfc->soc_info->addr_offset); - else if (ctrl & NAND_CLE) - writeb(cmd, cs->base + nfc->soc_info->cmd_offset); -} - -static int ingenic_nand_dev_ready(struct nand_chip *chip) -{ - struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); - - return !gpiod_get_value_cansleep(nand->busy_gpio); -} - static void ingenic_nand_ecc_hwctl(struct nand_chip *chip, int mode) { struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); @@ -298,8 +249,91 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) return 0; } +static int ingenic_nand_exec_instr(struct nand_chip *chip, + struct ingenic_nand_cs *cs, + const struct nand_op_instr *instr) +{ + struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); + struct ingenic_nfc *nfc = to_ingenic_nfc(chip->controller); + unsigned int i; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + writeb(instr->ctx.cmd.opcode, + cs->base + nfc->soc_info->cmd_offset); + return 0; + case NAND_OP_ADDR_INSTR: + for (i = 0; i < instr->ctx.addr.naddrs; i++) + writeb(instr->ctx.addr.addrs[i], + cs->base + nfc->soc_info->addr_offset); + return 0; + case NAND_OP_DATA_IN_INSTR: + if (instr->ctx.data.force_8bit || + !(chip->options & NAND_BUSWIDTH_16)) + ioread8_rep(cs->base + nfc->soc_info->data_offset, + instr->ctx.data.buf.in, + instr->ctx.data.len); + else + ioread16_rep(cs->base + nfc->soc_info->data_offset, + instr->ctx.data.buf.in, + instr->ctx.data.len); + return 0; + case NAND_OP_DATA_OUT_INSTR: + if (instr->ctx.data.force_8bit || + !(chip->options & NAND_BUSWIDTH_16)) + iowrite8_rep(cs->base + nfc->soc_info->data_offset, + instr->ctx.data.buf.out, + instr->ctx.data.len); + else + iowrite16_rep(cs->base + nfc->soc_info->data_offset, + instr->ctx.data.buf.out, + instr->ctx.data.len); + return 0; + case NAND_OP_WAITRDY_INSTR: + if (!nand->busy_gpio) + return nand_soft_waitrdy(chip, + instr->ctx.waitrdy.timeout_ms); + + return nand_gpio_waitrdy(chip, nand->busy_gpio, + instr->ctx.waitrdy.timeout_ms); + default: + break; + } + + return -EINVAL; +} + +static int ingenic_nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) +{ + struct ingenic_nand *nand = to_ingenic_nand(nand_to_mtd(chip)); + struct ingenic_nfc *nfc = to_ingenic_nfc(nand->chip.controller); + struct ingenic_nand_cs *cs; + unsigned int i; + int ret = 0; + + if (check_only) + return 0; + + cs = &nfc->cs[op->cs]; + jz4780_nemc_assert(nfc->dev, cs->bank, true); + for (i = 0; i < op->ninstrs; i++) { + ret = ingenic_nand_exec_instr(chip, cs, &op->instrs[i]); + if (ret) + break; + + if (op->instrs[i].delay_ns) + ndelay(op->instrs[i].delay_ns); + } + jz4780_nemc_assert(nfc->dev, cs->bank, false); + + return ret; +} + static const struct nand_controller_ops ingenic_nand_controller_ops = { .attach_chip = ingenic_nand_attach_chip, + .exec_op = ingenic_nand_exec_op, }; static int ingenic_nand_init_chip(struct platform_device *pdev, @@ -339,10 +373,20 @@ static int ingenic_nand_init_chip(struct platform_device *pdev, ret = PTR_ERR(nand->busy_gpio); dev_err(dev, "failed to request busy GPIO: %d\n", ret); return ret; - } else if (nand->busy_gpio) { - nand->chip.legacy.dev_ready = ingenic_nand_dev_ready; } + /* + * The rb-gpios semantics was undocumented and qi,lb60 (along with + * the ingenic driver) got it wrong. The active state encodes the + * NAND ready state, which is high level. Since there's no signal + * inverter on this board, it should be active-high. Let's fix that + * here for older DTs so we can re-use the generic nand_gpio_waitrdy() + * helper, and be consistent with what other drivers do. + */ + if (of_machine_is_compatible("qi,lb60") && + gpiod_is_active_low(nand->busy_gpio)) + gpiod_toggle_active_low(nand->busy_gpio); + nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW); if (IS_ERR(nand->wp_gpio)) { @@ -359,12 +403,7 @@ static int ingenic_nand_init_chip(struct platform_device *pdev, return -ENOMEM; mtd->dev.parent = dev; - chip->legacy.IO_ADDR_R = cs->base + nfc->soc_info->data_offset; - chip->legacy.IO_ADDR_W = cs->base + nfc->soc_info->data_offset; - chip->legacy.chip_delay = RB_DELAY_US; chip->options = NAND_NO_SUBPAGE_WRITE; - chip->legacy.select_chip = ingenic_nand_select_chip; - chip->legacy.cmd_ctrl = ingenic_nand_cmd_ctrl; chip->ecc.mode = NAND_ECC_HW; chip->controller = &nfc->controller; nand_set_flash_node(chip, np); @@ -376,7 +415,7 @@ static int ingenic_nand_init_chip(struct platform_device *pdev, ret = mtd_device_register(mtd, NULL, 0); if (ret) { - nand_release(chip); + nand_cleanup(chip); return ret; } @@ -387,13 +426,18 @@ static int ingenic_nand_init_chip(struct platform_device *pdev, static void ingenic_nand_cleanup_chips(struct ingenic_nfc *nfc) { - struct ingenic_nand *chip; + struct ingenic_nand *ingenic_chip; + struct nand_chip *chip; + int ret; while (!list_empty(&nfc->chips)) { - chip = list_first_entry(&nfc->chips, - struct ingenic_nand, chip_list); - nand_release(&chip->chip); - list_del(&chip->chip_list); + ingenic_chip = list_first_entry(&nfc->chips, + struct ingenic_nand, chip_list); + chip = &ingenic_chip->chip; + ret = mtd_device_unregister(nand_to_mtd(chip)); + WARN_ON(ret); + nand_cleanup(chip); + list_del(&ingenic_chip->chip_list); } } |