diff options
Diffstat (limited to 'drivers/mtd/nand/raw')
27 files changed, 978 insertions, 219 deletions
diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index 8312182088c1..d66dab25df20 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -19,15 +19,17 @@ #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/nand-gpio.h> #include <linux/mtd/rawnand.h> #include <linux/mtd/partitions.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/sizes.h> /* * MTD structure for E3 (Delta) */ -struct ams_delta_nand { +struct gpio_nand { struct nand_controller base; struct nand_chip nand_chip; struct gpio_desc *gpiod_rdy; @@ -39,41 +41,20 @@ struct ams_delta_nand { struct gpio_desc *gpiod_cle; struct gpio_descs *data_gpiods; bool data_in; + unsigned int tRP; + unsigned int tWP; + u8 (*io_read)(struct gpio_nand *this); + void (*io_write)(struct gpio_nand *this, u8 byte); }; -/* - * Define partitions for flash devices - */ - -static const struct mtd_partition partition_info[] = { - { .name = "Kernel", - .offset = 0, - .size = 3 * SZ_1M + SZ_512K }, - { .name = "u-boot", - .offset = 3 * SZ_1M + SZ_512K, - .size = SZ_256K }, - { .name = "u-boot params", - .offset = 3 * SZ_1M + SZ_512K + SZ_256K, - .size = SZ_256K }, - { .name = "Amstrad LDR", - .offset = 4 * SZ_1M, - .size = SZ_256K }, - { .name = "File system", - .offset = 4 * SZ_1M + 1 * SZ_256K, - .size = 27 * SZ_1M }, - { .name = "PBL reserved", - .offset = 32 * SZ_1M - 3 * SZ_256K, - .size = 3 * SZ_256K }, -}; - -static void ams_delta_write_commit(struct ams_delta_nand *priv) +static void gpio_nand_write_commit(struct gpio_nand *priv) { - gpiod_set_value(priv->gpiod_nwe, 0); - ndelay(40); gpiod_set_value(priv->gpiod_nwe, 1); + ndelay(priv->tWP); + gpiod_set_value(priv->gpiod_nwe, 0); } -static void ams_delta_io_write(struct ams_delta_nand *priv, u8 byte) +static void gpio_nand_io_write(struct gpio_nand *priv, u8 byte) { struct gpio_descs *data_gpiods = priv->data_gpiods; DECLARE_BITMAP(values, BITS_PER_TYPE(byte)) = { byte, }; @@ -81,10 +62,10 @@ static void ams_delta_io_write(struct ams_delta_nand *priv, u8 byte) gpiod_set_raw_array_value(data_gpiods->ndescs, data_gpiods->desc, data_gpiods->info, values); - ams_delta_write_commit(priv); + gpio_nand_write_commit(priv); } -static void ams_delta_dir_output(struct ams_delta_nand *priv, u8 byte) +static void gpio_nand_dir_output(struct gpio_nand *priv, u8 byte) { struct gpio_descs *data_gpiods = priv->data_gpiods; DECLARE_BITMAP(values, BITS_PER_TYPE(byte)) = { byte, }; @@ -94,30 +75,30 @@ static void ams_delta_dir_output(struct ams_delta_nand *priv, u8 byte) gpiod_direction_output_raw(data_gpiods->desc[i], test_bit(i, values)); - ams_delta_write_commit(priv); + gpio_nand_write_commit(priv); priv->data_in = false; } -static u8 ams_delta_io_read(struct ams_delta_nand *priv) +static u8 gpio_nand_io_read(struct gpio_nand *priv) { u8 res; struct gpio_descs *data_gpiods = priv->data_gpiods; DECLARE_BITMAP(values, BITS_PER_TYPE(res)) = { 0, }; - gpiod_set_value(priv->gpiod_nre, 0); - ndelay(40); + gpiod_set_value(priv->gpiod_nre, 1); + ndelay(priv->tRP); gpiod_get_raw_array_value(data_gpiods->ndescs, data_gpiods->desc, data_gpiods->info, values); - gpiod_set_value(priv->gpiod_nre, 1); + gpiod_set_value(priv->gpiod_nre, 0); res = values[0]; return res; } -static void ams_delta_dir_input(struct ams_delta_nand *priv) +static void gpio_nand_dir_input(struct gpio_nand *priv) { struct gpio_descs *data_gpiods = priv->data_gpiods; int i; @@ -128,68 +109,67 @@ static void ams_delta_dir_input(struct ams_delta_nand *priv) priv->data_in = true; } -static void ams_delta_write_buf(struct ams_delta_nand *priv, const u8 *buf, - int len) +static void gpio_nand_write_buf(struct gpio_nand *priv, const u8 *buf, int len) { int i = 0; if (len > 0 && priv->data_in) - ams_delta_dir_output(priv, buf[i++]); + gpio_nand_dir_output(priv, buf[i++]); while (i < len) - ams_delta_io_write(priv, buf[i++]); + priv->io_write(priv, buf[i++]); } -static void ams_delta_read_buf(struct ams_delta_nand *priv, u8 *buf, int len) +static void gpio_nand_read_buf(struct gpio_nand *priv, u8 *buf, int len) { int i; - if (!priv->data_in) - ams_delta_dir_input(priv); + if (priv->data_gpiods && !priv->data_in) + gpio_nand_dir_input(priv); for (i = 0; i < len; i++) - buf[i] = ams_delta_io_read(priv); + buf[i] = priv->io_read(priv); } -static void ams_delta_ctrl_cs(struct ams_delta_nand *priv, bool assert) +static void gpio_nand_ctrl_cs(struct gpio_nand *priv, bool assert) { - gpiod_set_value(priv->gpiod_nce, assert ? 0 : 1); + gpiod_set_value(priv->gpiod_nce, assert); } -static int ams_delta_exec_op(struct nand_chip *this, +static int gpio_nand_exec_op(struct nand_chip *this, const struct nand_operation *op, bool check_only) { - struct ams_delta_nand *priv = nand_get_controller_data(this); + struct gpio_nand *priv = nand_get_controller_data(this); const struct nand_op_instr *instr; int ret = 0; if (check_only) return 0; - ams_delta_ctrl_cs(priv, 1); + gpio_nand_ctrl_cs(priv, 1); for (instr = op->instrs; instr < op->instrs + op->ninstrs; instr++) { switch (instr->type) { case NAND_OP_CMD_INSTR: gpiod_set_value(priv->gpiod_cle, 1); - ams_delta_write_buf(priv, &instr->ctx.cmd.opcode, 1); + gpio_nand_write_buf(priv, &instr->ctx.cmd.opcode, 1); gpiod_set_value(priv->gpiod_cle, 0); break; case NAND_OP_ADDR_INSTR: gpiod_set_value(priv->gpiod_ale, 1); - ams_delta_write_buf(priv, instr->ctx.addr.addrs, + gpio_nand_write_buf(priv, instr->ctx.addr.addrs, instr->ctx.addr.naddrs); gpiod_set_value(priv->gpiod_ale, 0); break; case NAND_OP_DATA_IN_INSTR: - ams_delta_read_buf(priv, instr->ctx.data.buf.in, + gpio_nand_read_buf(priv, instr->ctx.data.buf.in, instr->ctx.data.len); break; case NAND_OP_DATA_OUT_INSTR: - ams_delta_write_buf(priv, instr->ctx.data.buf.out, + gpio_nand_write_buf(priv, instr->ctx.data.buf.out, instr->ctx.data.len); break; @@ -206,28 +186,61 @@ static int ams_delta_exec_op(struct nand_chip *this, break; } - ams_delta_ctrl_cs(priv, 0); + gpio_nand_ctrl_cs(priv, 0); return ret; } -static const struct nand_controller_ops ams_delta_ops = { - .exec_op = ams_delta_exec_op, +static int gpio_nand_setup_data_interface(struct nand_chip *this, int csline, + const struct nand_data_interface *cf) +{ + struct gpio_nand *priv = nand_get_controller_data(this); + const struct nand_sdr_timings *sdr = nand_get_sdr_timings(cf); + struct device *dev = &nand_to_mtd(this)->dev; + + if (IS_ERR(sdr)) + return PTR_ERR(sdr); + + if (csline == NAND_DATA_IFACE_CHECK_ONLY) + return 0; + + if (priv->gpiod_nre) { + priv->tRP = DIV_ROUND_UP(sdr->tRP_min, 1000); + dev_dbg(dev, "using %u ns read pulse width\n", priv->tRP); + } + + priv->tWP = DIV_ROUND_UP(sdr->tWP_min, 1000); + dev_dbg(dev, "using %u ns write pulse width\n", priv->tWP); + + return 0; +} + +static const struct nand_controller_ops gpio_nand_ops = { + .exec_op = gpio_nand_exec_op, + .setup_data_interface = gpio_nand_setup_data_interface, }; /* * Main initialization routine */ -static int ams_delta_init(struct platform_device *pdev) +static int gpio_nand_probe(struct platform_device *pdev) { - struct ams_delta_nand *priv; + struct gpio_nand_platdata *pdata = dev_get_platdata(&pdev->dev); + const struct mtd_partition *partitions = NULL; + int num_partitions = 0; + struct gpio_nand *priv; struct nand_chip *this; struct mtd_info *mtd; - struct gpio_descs *data_gpiods; + int (*probe)(struct platform_device *pdev, struct gpio_nand *priv); int err = 0; + if (pdata) { + partitions = pdata->parts; + num_partitions = pdata->num_parts; + } + /* Allocate memory for MTD device structure and private data */ - priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand), + priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_nand), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -238,6 +251,7 @@ static int ams_delta_init(struct platform_device *pdev) mtd->dev.parent = &pdev->dev; nand_set_controller_data(this, priv); + nand_set_flash_node(this, pdev->dev.of_node); priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN); if (IS_ERR(priv->gpiod_rdy)) { @@ -251,29 +265,33 @@ static int ams_delta_init(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - /* Set chip enabled, but */ - priv->gpiod_nwp = devm_gpiod_get(&pdev->dev, "nwp", GPIOD_OUT_HIGH); + /* Set chip enabled but write protected */ + priv->gpiod_nwp = devm_gpiod_get_optional(&pdev->dev, "nwp", + GPIOD_OUT_HIGH); if (IS_ERR(priv->gpiod_nwp)) { err = PTR_ERR(priv->gpiod_nwp); dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err); return err; } - priv->gpiod_nce = devm_gpiod_get(&pdev->dev, "nce", GPIOD_OUT_HIGH); + priv->gpiod_nce = devm_gpiod_get_optional(&pdev->dev, "nce", + GPIOD_OUT_LOW); if (IS_ERR(priv->gpiod_nce)) { err = PTR_ERR(priv->gpiod_nce); dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err); return err; } - priv->gpiod_nre = devm_gpiod_get(&pdev->dev, "nre", GPIOD_OUT_HIGH); + priv->gpiod_nre = devm_gpiod_get_optional(&pdev->dev, "nre", + GPIOD_OUT_LOW); if (IS_ERR(priv->gpiod_nre)) { err = PTR_ERR(priv->gpiod_nre); dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err); return err; } - priv->gpiod_nwe = devm_gpiod_get(&pdev->dev, "nwe", GPIOD_OUT_HIGH); + priv->gpiod_nwe = devm_gpiod_get_optional(&pdev->dev, "nwe", + GPIOD_OUT_LOW); if (IS_ERR(priv->gpiod_nwe)) { err = PTR_ERR(priv->gpiod_nwe); dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err); @@ -295,28 +313,62 @@ static int ams_delta_init(struct platform_device *pdev) } /* Request array of data pins, initialize them as input */ - data_gpiods = devm_gpiod_get_array(&pdev->dev, "data", GPIOD_IN); - if (IS_ERR(data_gpiods)) { - err = PTR_ERR(data_gpiods); + priv->data_gpiods = devm_gpiod_get_array_optional(&pdev->dev, "data", + GPIOD_IN); + if (IS_ERR(priv->data_gpiods)) { + err = PTR_ERR(priv->data_gpiods); dev_err(&pdev->dev, "data GPIO request failed: %d\n", err); return err; } - priv->data_gpiods = data_gpiods; - priv->data_in = true; + if (priv->data_gpiods) { + if (!priv->gpiod_nwe) { + dev_err(&pdev->dev, + "mandatory NWE pin not provided by platform\n"); + return -ENODEV; + } - /* Initialize the NAND controller object embedded in ams_delta_nand. */ - priv->base.ops = &ams_delta_ops; + priv->io_read = gpio_nand_io_read; + priv->io_write = gpio_nand_io_write; + priv->data_in = true; + } + + if (pdev->id_entry) + probe = (void *) pdev->id_entry->driver_data; + else + probe = of_device_get_match_data(&pdev->dev); + if (probe) + err = probe(pdev, priv); + if (err) + return err; + + if (!priv->io_read || !priv->io_write) { + dev_err(&pdev->dev, "incomplete device configuration\n"); + return -ENODEV; + } + + /* Initialize the NAND controller object embedded in gpio_nand. */ + priv->base.ops = &gpio_nand_ops; nand_controller_init(&priv->base); this->controller = &priv->base; + /* + * FIXME: We should release write protection only after nand_scan() to + * be on the safe side but we can't do that until we have a generic way + * to assert/deassert WP from the core. Even if the core shouldn't + * write things in the nand_scan() path, it should have control on this + * pin just in case we ever need to disable write protection during + * chip detection/initialization. + */ + /* Release write protection */ + gpiod_set_value(priv->gpiod_nwp, 0); + /* Scan to find existence of the device */ err = nand_scan(this, 1); if (err) return err; /* Register the partitions */ - err = mtd_device_register(mtd, partition_info, - ARRAY_SIZE(partition_info)); + err = mtd_device_register(mtd, partitions, num_partitions); if (err) goto err_nand_cleanup; @@ -331,26 +383,47 @@ err_nand_cleanup: /* * Clean up routine */ -static int ams_delta_cleanup(struct platform_device *pdev) +static int gpio_nand_remove(struct platform_device *pdev) { - struct ams_delta_nand *priv = platform_get_drvdata(pdev); + struct gpio_nand *priv = platform_get_drvdata(pdev); struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip); + /* Apply write protection */ + gpiod_set_value(priv->gpiod_nwp, 1); + /* Unregister device */ nand_release(mtd_to_nand(mtd)); return 0; } -static struct platform_driver ams_delta_nand_driver = { - .probe = ams_delta_init, - .remove = ams_delta_cleanup, +static const struct of_device_id gpio_nand_of_id_table[] = { + { + /* sentinel */ + }, +}; +MODULE_DEVICE_TABLE(of, gpio_nand_of_id_table); + +static const struct platform_device_id gpio_nand_plat_id_table[] = { + { + .name = "ams-delta-nand", + }, { + /* sentinel */ + }, +}; +MODULE_DEVICE_TABLE(platform, gpio_nand_plat_id_table); + +static struct platform_driver gpio_nand_driver = { + .probe = gpio_nand_probe, + .remove = gpio_nand_remove, + .id_table = gpio_nand_plat_id_table, .driver = { .name = "ams-delta-nand", + .of_match_table = of_match_ptr(gpio_nand_of_id_table), }, }; -module_platform_driver(ams_delta_nand_driver); +module_platform_driver(gpio_nand_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 44518dada75b..e4e3ceeac38f 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -102,6 +102,45 @@ struct brcm_nand_dma_desc { #define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY) #define NAND_POLL_STATUS_TIMEOUT_MS 100 +#define EDU_CMD_WRITE 0x00 +#define EDU_CMD_READ 0x01 +#define EDU_STATUS_ACTIVE BIT(0) +#define EDU_ERR_STATUS_ERRACK BIT(0) +#define EDU_DONE_MASK GENMASK(1, 0) + +#define EDU_CONFIG_MODE_NAND BIT(0) +#define EDU_CONFIG_SWAP_BYTE BIT(1) +#ifdef CONFIG_CPU_BIG_ENDIAN +#define EDU_CONFIG_SWAP_CFG EDU_CONFIG_SWAP_BYTE +#else +#define EDU_CONFIG_SWAP_CFG 0 +#endif + +/* edu registers */ +enum edu_reg { + EDU_CONFIG = 0, + EDU_DRAM_ADDR, + EDU_EXT_ADDR, + EDU_LENGTH, + EDU_CMD, + EDU_STOP, + EDU_STATUS, + EDU_DONE, + EDU_ERR_STATUS, +}; + +static const u16 edu_regs[] = { + [EDU_CONFIG] = 0x00, + [EDU_DRAM_ADDR] = 0x04, + [EDU_EXT_ADDR] = 0x08, + [EDU_LENGTH] = 0x0c, + [EDU_CMD] = 0x10, + [EDU_STOP] = 0x14, + [EDU_STATUS] = 0x18, + [EDU_DONE] = 0x1c, + [EDU_ERR_STATUS] = 0x20, +}; + /* flash_dma registers */ enum flash_dma_reg { FLASH_DMA_REVISION = 0, @@ -167,6 +206,8 @@ enum { BRCMNAND_HAS_WP = BIT(3), }; +struct brcmnand_host; + struct brcmnand_controller { struct device *dev; struct nand_controller controller; @@ -185,17 +226,32 @@ struct brcmnand_controller { int cmd_pending; bool dma_pending; + bool edu_pending; struct completion done; struct completion dma_done; + struct completion edu_done; /* List of NAND hosts (one for each chip-select) */ struct list_head host_list; + /* EDU info, per-transaction */ + const u16 *edu_offsets; + void __iomem *edu_base; + int edu_irq; + int edu_count; + u64 edu_dram_addr; + u32 edu_ext_addr; + u32 edu_cmd; + u32 edu_config; + /* flash_dma reg */ const u16 *flash_dma_offsets; struct brcm_nand_dma_desc *dma_desc; dma_addr_t dma_pa; + int (*dma_trans)(struct brcmnand_host *host, u64 addr, u32 *buf, + u32 len, u8 dma_cmd); + /* in-memory cache of the FLASH_CACHE, used only for some commands */ u8 flash_cache[FC_BYTES]; @@ -216,6 +272,7 @@ struct brcmnand_controller { u32 nand_cs_nand_xor; u32 corr_stat_threshold; u32 flash_dma_mode; + u32 flash_edu_mode; bool pio_poll_mode; }; @@ -657,6 +714,22 @@ static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl, __raw_writel(val, ctrl->nand_fc + word * 4); } +static inline void edu_writel(struct brcmnand_controller *ctrl, + enum edu_reg reg, u32 val) +{ + u16 offs = ctrl->edu_offsets[reg]; + + brcmnand_writel(val, ctrl->edu_base + offs); +} + +static inline u32 edu_readl(struct brcmnand_controller *ctrl, + enum edu_reg reg) +{ + u16 offs = ctrl->edu_offsets[reg]; + + return brcmnand_readl(ctrl->edu_base + offs); +} + static void brcmnand_clear_ecc_addr(struct brcmnand_controller *ctrl) { @@ -926,6 +999,16 @@ static inline bool has_flash_dma(struct brcmnand_controller *ctrl) return ctrl->flash_dma_base; } +static inline bool has_edu(struct brcmnand_controller *ctrl) +{ + return ctrl->edu_base; +} + +static inline bool use_dma(struct brcmnand_controller *ctrl) +{ + return has_flash_dma(ctrl) || has_edu(ctrl); +} + static inline void disable_ctrl_irqs(struct brcmnand_controller *ctrl) { if (ctrl->pio_poll_mode) @@ -1299,6 +1382,52 @@ static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i, return tbytes; } +static void brcmnand_edu_init(struct brcmnand_controller *ctrl) +{ + /* initialize edu */ + edu_writel(ctrl, EDU_ERR_STATUS, 0); + edu_readl(ctrl, EDU_ERR_STATUS); + edu_writel(ctrl, EDU_DONE, 0); + edu_writel(ctrl, EDU_DONE, 0); + edu_writel(ctrl, EDU_DONE, 0); + edu_writel(ctrl, EDU_DONE, 0); + edu_readl(ctrl, EDU_DONE); +} + +/* edu irq */ +static irqreturn_t brcmnand_edu_irq(int irq, void *data) +{ + struct brcmnand_controller *ctrl = data; + + if (ctrl->edu_count) { + ctrl->edu_count--; + while (!(edu_readl(ctrl, EDU_DONE) & EDU_DONE_MASK)) + udelay(1); + edu_writel(ctrl, EDU_DONE, 0); + edu_readl(ctrl, EDU_DONE); + } + + if (ctrl->edu_count) { + ctrl->edu_dram_addr += FC_BYTES; + ctrl->edu_ext_addr += FC_BYTES; + + edu_writel(ctrl, EDU_DRAM_ADDR, (u32)ctrl->edu_dram_addr); + edu_readl(ctrl, EDU_DRAM_ADDR); + edu_writel(ctrl, EDU_EXT_ADDR, ctrl->edu_ext_addr); + edu_readl(ctrl, EDU_EXT_ADDR); + + mb(); /* flush previous writes */ + edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd); + edu_readl(ctrl, EDU_CMD); + + return IRQ_HANDLED; + } + + complete(&ctrl->edu_done); + + return IRQ_HANDLED; +} + static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data) { struct brcmnand_controller *ctrl = data; @@ -1307,6 +1436,16 @@ static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data) if (ctrl->dma_pending) return IRQ_HANDLED; + /* check if you need to piggy back on the ctrlrdy irq */ + if (ctrl->edu_pending) { + if (irq == ctrl->irq && ((int)ctrl->edu_irq >= 0)) + /* Discard interrupts while using dedicated edu irq */ + return IRQ_HANDLED; + + /* no registered edu irq, call handler */ + return brcmnand_edu_irq(irq, data); + } + complete(&ctrl->done); return IRQ_HANDLED; } @@ -1645,6 +1784,81 @@ static void brcmnand_write_buf(struct nand_chip *chip, const uint8_t *buf, } /** + * Kick EDU engine + */ +static int brcmnand_edu_trans(struct brcmnand_host *host, u64 addr, u32 *buf, + u32 len, u8 cmd) +{ + struct brcmnand_controller *ctrl = host->ctrl; + unsigned long timeo = msecs_to_jiffies(200); + int ret = 0; + int dir = (cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + u8 edu_cmd = (cmd == CMD_PAGE_READ ? EDU_CMD_READ : EDU_CMD_WRITE); + unsigned int trans = len >> FC_SHIFT; + dma_addr_t pa; + + pa = dma_map_single(ctrl->dev, buf, len, dir); + if (dma_mapping_error(ctrl->dev, pa)) { + dev_err(ctrl->dev, "unable to map buffer for EDU DMA\n"); + return -ENOMEM; + } + + ctrl->edu_pending = true; + ctrl->edu_dram_addr = pa; + ctrl->edu_ext_addr = addr; + ctrl->edu_cmd = edu_cmd; + ctrl->edu_count = trans; + + edu_writel(ctrl, EDU_DRAM_ADDR, (u32)ctrl->edu_dram_addr); + edu_readl(ctrl, EDU_DRAM_ADDR); + edu_writel(ctrl, EDU_EXT_ADDR, ctrl->edu_ext_addr); + edu_readl(ctrl, EDU_EXT_ADDR); + edu_writel(ctrl, EDU_LENGTH, FC_BYTES); + edu_readl(ctrl, EDU_LENGTH); + + /* Start edu engine */ + mb(); /* flush previous writes */ + edu_writel(ctrl, EDU_CMD, ctrl->edu_cmd); + edu_readl(ctrl, EDU_CMD); + + if (wait_for_completion_timeout(&ctrl->edu_done, timeo) <= 0) { + dev_err(ctrl->dev, + "timeout waiting for EDU; status %#x, error status %#x\n", + edu_readl(ctrl, EDU_STATUS), + edu_readl(ctrl, EDU_ERR_STATUS)); + } + + dma_unmap_single(ctrl->dev, pa, len, dir); + + /* for program page check NAND status */ + if (((brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) & + INTFC_FLASH_STATUS) & NAND_STATUS_FAIL) && + edu_cmd == EDU_CMD_WRITE) { + dev_info(ctrl->dev, "program failed at %llx\n", + (unsigned long long)addr); + ret = -EIO; + } + + /* Make sure the EDU status is clean */ + if (edu_readl(ctrl, EDU_STATUS) & EDU_STATUS_ACTIVE) + dev_warn(ctrl->dev, "EDU still active: %#x\n", + edu_readl(ctrl, EDU_STATUS)); + + if (unlikely(edu_readl(ctrl, EDU_ERR_STATUS) & EDU_ERR_STATUS_ERRACK)) { + dev_warn(ctrl->dev, "EDU RBUS error at addr %llx\n", + (unsigned long long)addr); + ret = -EIO; + } + + ctrl->edu_pending = false; + brcmnand_edu_init(ctrl); + edu_writel(ctrl, EDU_STOP, 0); /* force stop */ + edu_readl(ctrl, EDU_STOP); + + return ret; +} + +/** * Construct a FLASH_DMA descriptor as part of a linked list. You must know the * following ahead of time: * - Is this descriptor the beginning or end of a linked list? @@ -1850,9 +2064,11 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, try_dmaread: brcmnand_clear_ecc_addr(ctrl); - if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) { - err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES, - CMD_PAGE_READ); + if (ctrl->dma_trans && !oob && flash_dma_buf_ok(buf)) { + err = ctrl->dma_trans(host, addr, buf, + trans * FC_BYTES, + CMD_PAGE_READ); + if (err) { if (mtd_is_bitflip_or_eccerr(err)) err_addr = addr; @@ -1988,10 +2204,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; i < ctrl->max_oob; i += 4) oob_reg_write(ctrl, i, 0xffffffff); - if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) { - if (brcmnand_dma_trans(host, addr, (u32 *)buf, - mtd->writesize, CMD_PROGRAM_PAGE)) + if (use_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) { + if (ctrl->dma_trans(host, addr, (u32 *)buf, mtd->writesize, + CMD_PROGRAM_PAGE)) + ret = -EIO; + goto out; } @@ -2494,6 +2712,8 @@ static int brcmnand_suspend(struct device *dev) if (has_flash_dma(ctrl)) ctrl->flash_dma_mode = flash_dma_readl(ctrl, FLASH_DMA_MODE); + else if (has_edu(ctrl)) + ctrl->edu_config = edu_readl(ctrl, EDU_CONFIG); return 0; } @@ -2508,6 +2728,14 @@ static int brcmnand_resume(struct device *dev) flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0); } + if (has_edu(ctrl)) + ctrl->edu_config = edu_readl(ctrl, EDU_CONFIG); + else { + edu_writel(ctrl, EDU_CONFIG, ctrl->edu_config); + edu_readl(ctrl, EDU_CONFIG); + brcmnand_edu_init(ctrl); + } + brcmnand_write_reg(ctrl, BRCMNAND_CS_SELECT, ctrl->nand_cs_nand_select); brcmnand_write_reg(ctrl, BRCMNAND_CS_XOR, ctrl->nand_cs_nand_xor); brcmnand_write_reg(ctrl, BRCMNAND_CORR_THRESHOLD, @@ -2553,6 +2781,49 @@ MODULE_DEVICE_TABLE(of, brcmnand_of_match); /*********************************************************************** * Platform driver setup (per controller) ***********************************************************************/ +static int brcmnand_edu_setup(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct brcmnand_controller *ctrl = dev_get_drvdata(&pdev->dev); + struct resource *res; + int ret; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-edu"); + if (res) { + ctrl->edu_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ctrl->edu_base)) + return PTR_ERR(ctrl->edu_base); + + ctrl->edu_offsets = edu_regs; + + edu_writel(ctrl, EDU_CONFIG, EDU_CONFIG_MODE_NAND | + EDU_CONFIG_SWAP_CFG); + edu_readl(ctrl, EDU_CONFIG); + + /* initialize edu */ + brcmnand_edu_init(ctrl); + + ctrl->edu_irq = platform_get_irq_optional(pdev, 1); + if (ctrl->edu_irq < 0) { + dev_warn(dev, + "FLASH EDU enabled, using ctlrdy irq\n"); + } else { + ret = devm_request_irq(dev, ctrl->edu_irq, + brcmnand_edu_irq, 0, + "brcmnand-edu", ctrl); + if (ret < 0) { + dev_err(ctrl->dev, "can't allocate IRQ %d: error %d\n", + ctrl->edu_irq, ret); + return ret; + } + + dev_info(dev, "FLASH EDU enabled using irq %u\n", + ctrl->edu_irq); + } + } + + return 0; +} int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) { @@ -2578,6 +2849,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) init_completion(&ctrl->done); init_completion(&ctrl->dma_done); + init_completion(&ctrl->edu_done); nand_controller_init(&ctrl->controller); ctrl->controller.ops = &brcmnand_controller_ops; INIT_LIST_HEAD(&ctrl->host_list); @@ -2675,6 +2947,15 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) } dev_info(dev, "enabling FLASH_DMA\n"); + /* set flash dma transfer function to call */ + ctrl->dma_trans = brcmnand_dma_trans; + } else { + ret = brcmnand_edu_setup(pdev); + if (ret < 0) + goto err; + + /* set edu transfer function to call */ + ctrl->dma_trans = brcmnand_edu_trans; } /* Disable automatic device ID config, direct addressing */ diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c index f6c7102a1e32..efddc5c68afb 100644 --- a/drivers/mtd/nand/raw/cadence-nand-controller.c +++ b/drivers/mtd/nand/raw/cadence-nand-controller.c @@ -30,7 +30,6 @@ * Generic mode is used for executing rest of commands. */ -#define MAX_OOB_SIZE_PER_SECTOR 32 #define MAX_ADDRESS_CYC 6 #define MAX_ERASE_ADDRESS_CYC 3 #define MAX_DATA_SIZE 0xFFFC @@ -190,6 +189,7 @@ /* BCH Engine identification register 3. */ #define BCH_CFG_3 0x844 +#define BCH_CFG_3_METADATA_SIZE GENMASK(23, 16) /* Ready/Busy# line status. */ #define RBN_SETINGS 0x1004 @@ -499,6 +499,7 @@ struct cdns_nand_ctrl { unsigned long assigned_cs; struct list_head chips; + u8 bch_metadata_size; }; struct cdns_nand_chip { @@ -997,6 +998,7 @@ static int cadence_nand_cdma_send(struct cdns_nand_ctrl *cdns_ctrl, return status; cadence_nand_reset_irq(cdns_ctrl); + reinit_completion(&cdns_ctrl->complete); writel_relaxed((u32)cdns_ctrl->dma_cdma_desc, cdns_ctrl->reg + CMD_REG2); @@ -1077,6 +1079,14 @@ static int cadence_nand_read_bch_caps(struct cdns_nand_ctrl *cdns_ctrl) int max_step_size = 0, nstrengths, i; u32 reg; + reg = readl_relaxed(cdns_ctrl->reg + BCH_CFG_3); + cdns_ctrl->bch_metadata_size = FIELD_GET(BCH_CFG_3_METADATA_SIZE, reg); + if (cdns_ctrl->bch_metadata_size < 4) { + dev_err(cdns_ctrl->dev, + "Driver needs at least 4 bytes of BCH meta data\n"); + return -EIO; + } + reg = readl_relaxed(cdns_ctrl->reg + BCH_CFG_0); cdns_ctrl->ecc_strengths[0] = FIELD_GET(BCH_CFG_0_CORR_CAP_0, reg); cdns_ctrl->ecc_strengths[1] = FIELD_GET(BCH_CFG_0_CORR_CAP_1, reg); @@ -1170,7 +1180,8 @@ static int cadence_nand_hw_init(struct cdns_nand_ctrl *cdns_ctrl) writel_relaxed(0xFFFFFFFF, cdns_ctrl->reg + INTR_STATUS); cadence_nand_get_caps(cdns_ctrl); - cadence_nand_read_bch_caps(cdns_ctrl); + if (cadence_nand_read_bch_caps(cdns_ctrl)) + return -EIO; /* * Set IO width access to 8. @@ -2585,9 +2596,8 @@ int cadence_nand_attach_chip(struct nand_chip *chip) { struct cdns_nand_ctrl *cdns_ctrl = to_cdns_nand_ctrl(chip->controller); struct cdns_nand_chip *cdns_chip = to_cdns_nand_chip(chip); - u32 ecc_size = cdns_chip->sector_count * chip->ecc.bytes; + u32 ecc_size; struct mtd_info *mtd = nand_to_mtd(chip); - u32 max_oob_data_size; int ret; if (chip->options & NAND_BUSWIDTH_16) { @@ -2603,12 +2613,9 @@ int cadence_nand_attach_chip(struct nand_chip *chip) chip->options |= NAND_NO_SUBPAGE_WRITE; cdns_chip->bbm_offs = chip->badblockpos; - if (chip->options & NAND_BUSWIDTH_16) { - cdns_chip->bbm_offs &= ~0x01; - cdns_chip->bbm_len = 2; - } else { - cdns_chip->bbm_len = 1; - } + cdns_chip->bbm_offs &= ~0x01; + /* this value should be even number */ + cdns_chip->bbm_len = 2; ret = nand_ecc_choose_conf(chip, &cdns_ctrl->ecc_caps, @@ -2625,13 +2632,12 @@ int cadence_nand_attach_chip(struct nand_chip *chip) /* Error correction configuration. */ cdns_chip->sector_size = chip->ecc.size; cdns_chip->sector_count = mtd->writesize / cdns_chip->sector_size; + ecc_size = cdns_chip->sector_count * chip->ecc.bytes; cdns_chip->avail_oob_size = mtd->oobsize - ecc_size; - max_oob_data_size = MAX_OOB_SIZE_PER_SECTOR; - - if (cdns_chip->avail_oob_size > max_oob_data_size) - cdns_chip->avail_oob_size = max_oob_data_size; + if (cdns_chip->avail_oob_size > cdns_ctrl->bch_metadata_size) + cdns_chip->avail_oob_size = cdns_ctrl->bch_metadata_size; if ((cdns_chip->avail_oob_size + cdns_chip->bbm_len + ecc_size) > mtd->oobsize) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index fafd0a0aa8e2..6a6c919b2569 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -1317,6 +1317,7 @@ int denali_init(struct denali_controller *denali) iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); iowrite32(ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); + iowrite32(WRITE_PROTECT__FLAG, denali->reg + WRITE_PROTECT); denali_clear_irq_all(denali); diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h index e5cdcda56d14..ac46eb7956ce 100644 --- a/drivers/mtd/nand/raw/denali.h +++ b/drivers/mtd/nand/raw/denali.h @@ -328,7 +328,7 @@ struct denali_chip { struct nand_chip chip; struct list_head node; unsigned int nsels; - struct denali_chip_sel sels[0]; + struct denali_chip_sel sels[]; }; /** diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index c0e1a8ebe820..c2a391ad2c35 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -1169,7 +1169,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti " NoOfBootImageBlocks = %d\n" " NoOfBinaryPartitions = %d\n" " NoOfBDTLPartitions = %d\n" - " BlockMultiplerBits = %d\n" + " BlockMultiplierBits = %d\n" " FormatFlgs = %d\n" " OsakVersion = %d.%d.%d.%d\n" " PercentUsed = %d\n", @@ -1482,7 +1482,7 @@ static int __init doc_probe(unsigned long physadr) break; case DOC_ChipID_DocMilPlus32: pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n"); - /* fall through */ + fallthrough; default: ret = -ENODEV; goto notfound; diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index 634c550db13a..e1dc675b12bb 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -324,8 +324,7 @@ static void fsl_elbc_cmdfunc(struct nand_chip *chip, unsigned int command, /* READ0 and READ1 read the entire buffer to use hardware ECC. */ case NAND_CMD_READ1: column += 256; - - /* fall-through */ + fallthrough; case NAND_CMD_READ0: dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index b9d5d55a5edb..53b00c841aec 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -1148,20 +1148,21 @@ static int acquire_dma_channels(struct gpmi_nand_data *this) { struct platform_device *pdev = this->pdev; struct dma_chan *dma_chan; + int ret = 0; /* request dma channel */ - dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx"); - if (!dma_chan) { - dev_err(this->dev, "Failed to request DMA channel.\n"); - goto acquire_err; + dma_chan = dma_request_chan(&pdev->dev, "rx-tx"); + if (IS_ERR(dma_chan)) { + ret = PTR_ERR(dma_chan); + if (ret != -EPROBE_DEFER) + dev_err(this->dev, "DMA channel request failed: %d\n", + ret); + release_dma_channels(this); + } else { + this->dma_chans[0] = dma_chan; } - this->dma_chans[0] = dma_chan; - return 0; - -acquire_err: - release_dma_channels(this); - return -EINVAL; + return ret; } static int gpmi_get_clks(struct gpmi_nand_data *this) diff --git a/drivers/mtd/nand/raw/ingenic/Kconfig b/drivers/mtd/nand/raw/ingenic/Kconfig index e30feb56b650..96c5ae8b1bbc 100644 --- a/drivers/mtd/nand/raw/ingenic/Kconfig +++ b/drivers/mtd/nand/raw/ingenic/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config MTD_NAND_JZ4780 tristate "JZ4780 NAND controller" + depends on MIPS || COMPILE_TEST depends on JZ4780_NEMC help Enables support for NAND Flash connected to the NEMC on JZ4780 SoC diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c index c954189606f6..8e22cd6ec71f 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_ecc.c @@ -124,7 +124,6 @@ int ingenic_ecc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ingenic_ecc *ecc; - struct resource *res; ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL); if (!ecc) @@ -134,8 +133,7 @@ int ingenic_ecc_probe(struct platform_device *pdev) if (!ecc->ops) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ecc->base = devm_ioremap_resource(dev, res); + ecc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ecc->base)) return PTR_ERR(ecc->base); diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c index 49afebee50db..935c4902ada7 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c @@ -253,7 +253,7 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) chip->ecc.hwctl = ingenic_nand_ecc_hwctl; chip->ecc.calculate = ingenic_nand_ecc_calculate; chip->ecc.correct = ingenic_nand_ecc_correct; - /* fall through */ + fallthrough; case NAND_ECC_SOFT: dev_info(nfc->dev, "using %s (strength %d, size %d, bytes %d)\n", (nfc->ecc) ? "hardware ECC" : "software ECC", diff --git a/drivers/mtd/nand/raw/ingenic/jz4725b_bch.c b/drivers/mtd/nand/raw/ingenic/jz4725b_bch.c index 6c852eae09cf..2d0e0a2192ae 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4725b_bch.c +++ b/drivers/mtd/nand/raw/ingenic/jz4725b_bch.c @@ -145,10 +145,10 @@ static void jz4725b_bch_read_parity(struct ingenic_ecc *bch, u8 *buf, switch (size8) { case 3: dest8[2] = (val >> 16) & 0xff; - /* fall-through */ + fallthrough; case 2: dest8[1] = (val >> 8) & 0xff; - /* fall-through */ + fallthrough; case 1: dest8[0] = val & 0xff; break; diff --git a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c index 079266a0d6cf..d67dbfff76cc 100644 --- a/drivers/mtd/nand/raw/ingenic/jz4780_bch.c +++ b/drivers/mtd/nand/raw/ingenic/jz4780_bch.c @@ -123,10 +123,10 @@ static void jz4780_bch_read_parity(struct ingenic_ecc *bch, void *buf, switch (size8) { case 3: dest8[2] = (val >> 16) & 0xff; - /* fall through */ + fallthrough; case 2: dest8[1] = (val >> 8) & 0xff; - /* fall through */ + fallthrough; case 1: dest8[0] = val & 0xff; break; diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index cba6fe7dd8c4..9d0caadf940e 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -30,6 +30,7 @@ #define NAND_MFR_SAMSUNG 0xec #define NAND_MFR_SANDISK 0x45 #define NAND_MFR_STMICRO 0x20 +/* Kioxia is new name of Toshiba memory. */ #define NAND_MFR_TOSHIBA 0x98 #define NAND_MFR_WINBOND 0xef diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index fb5abdcfb007..179f0ca585f8 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -334,7 +334,7 @@ struct marvell_nand_chip { int addr_cyc; int selected_die; unsigned int nsels; - struct marvell_nand_chip_sel sels[0]; + struct marvell_nand_chip_sel sels[]; }; static inline struct marvell_nand_chip *to_marvell_nand(struct nand_chip *chip) @@ -2743,16 +2743,21 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc) if (ret) return ret; - nfc->dma_chan = dma_request_slave_channel(nfc->dev, "data"); - if (!nfc->dma_chan) { - dev_err(nfc->dev, - "Unable to request data DMA channel\n"); - return -ENODEV; + nfc->dma_chan = dma_request_chan(nfc->dev, "data"); + if (IS_ERR(nfc->dma_chan)) { + ret = PTR_ERR(nfc->dma_chan); + nfc->dma_chan = NULL; + if (ret != -EPROBE_DEFER) + dev_err(nfc->dev, "DMA channel request failed: %d\n", + ret); + return ret; } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -ENXIO; + if (!r) { + ret = -ENXIO; + goto release_channel; + } config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -2763,7 +2768,7 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc) ret = dmaengine_slave_config(nfc->dma_chan, &config); if (ret < 0) { dev_err(nfc->dev, "Failed to configure DMA channel\n"); - return ret; + goto release_channel; } /* @@ -2773,12 +2778,20 @@ static int marvell_nfc_init_dma(struct marvell_nfc *nfc) * the provided buffer. */ nfc->dma_buf = kmalloc(MAX_CHUNK_SIZE, GFP_KERNEL | GFP_DMA); - if (!nfc->dma_buf) - return -ENOMEM; + if (!nfc->dma_buf) { + ret = -ENOMEM; + goto release_channel; + } nfc->use_dma = true; return 0; + +release_channel: + dma_release_channel(nfc->dma_chan); + nfc->dma_chan = NULL; + + return ret; } static void marvell_nfc_reset(struct marvell_nfc *nfc) @@ -2920,10 +2933,13 @@ static int marvell_nfc_probe(struct platform_device *pdev) ret = marvell_nand_chips_init(dev, nfc); if (ret) - goto unprepare_reg_clk; + goto release_dma; return 0; +release_dma: + if (nfc->use_dma) + dma_release_channel(nfc->dma_chan); unprepare_reg_clk: clk_disable_unprepare(nfc->reg_clk); unprepare_core_clk: diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 9f17b5b8efbf..f6fb5c0e6255 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -118,7 +118,7 @@ struct meson_nfc_nand_chip { u8 *data_buf; __le64 *info_buf; u32 nsels; - u8 sels[0]; + u8 sels[]; }; struct meson_nand_ecc { diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index b8305e39ab51..ef149e8b26d0 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -131,7 +131,7 @@ struct mtk_nfc_nand_chip { u32 spare_per_sector; int nsels; - u8 sels[0]; + u8 sels[]; /* nothing after this field */ }; diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index f64e3b6605c6..c24e5e2ba130 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -683,7 +683,12 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) if (ret) return ret; - timeout_ms = jiffies + msecs_to_jiffies(timeout_ms); + /* + * +1 below is necessary because if we are now in the last fraction + * of jiffy and msecs_to_jiffies is 1 then we will wait only that + * small jiffy fraction - possibly leading to false timeout + */ + timeout_ms = jiffies + msecs_to_jiffies(timeout_ms) + 1; do { ret = nand_read_data_op(chip, &status, sizeof(status), true); if (ret) @@ -4321,16 +4326,22 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) /** * nand_suspend - [MTD Interface] Suspend the NAND flash * @mtd: MTD device structure + * + * Returns 0 for success or negative error code otherwise. */ static int nand_suspend(struct mtd_info *mtd) { struct nand_chip *chip = mtd_to_nand(mtd); + int ret = 0; mutex_lock(&chip->lock); - chip->suspended = 1; + if (chip->suspend) + ret = chip->suspend(chip); + if (!ret) + chip->suspended = 1; mutex_unlock(&chip->lock); - return 0; + return ret; } /** @@ -4342,11 +4353,14 @@ static void nand_resume(struct mtd_info *mtd) struct nand_chip *chip = mtd_to_nand(mtd); mutex_lock(&chip->lock); - if (chip->suspended) + if (chip->suspended) { + if (chip->resume) + chip->resume(chip); chip->suspended = 0; - else + } else { pr_err("%s called for a chip which is not in suspended state\n", __func__); + } mutex_unlock(&chip->lock); } @@ -4360,6 +4374,38 @@ static void nand_shutdown(struct mtd_info *mtd) nand_suspend(mtd); } +/** + * nand_lock - [MTD Interface] Lock the NAND flash + * @mtd: MTD device structure + * @ofs: offset byte address + * @len: number of bytes to lock (must be a multiple of block/page size) + */ +static int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + if (!chip->lock_area) + return -ENOTSUPP; + + return chip->lock_area(chip, ofs, len); +} + +/** + * nand_unlock - [MTD Interface] Unlock the NAND flash + * @mtd: MTD device structure + * @ofs: offset byte address + * @len: number of bytes to unlock (must be a multiple of block/page size) + */ +static int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + + if (!chip->unlock_area) + return -ENOTSUPP; + + return chip->unlock_area(chip, ofs, len); +} + /* Set default functions */ static void nand_set_defaults(struct nand_chip *chip) { @@ -5591,8 +5637,7 @@ static int nand_scan_tail(struct nand_chip *chip) } if (!ecc->read_page) ecc->read_page = nand_read_page_hwecc_oob_first; - /* fall through */ - + fallthrough; case NAND_ECC_HW: /* Use standard hwecc read page function? */ if (!ecc->read_page) @@ -5611,8 +5656,7 @@ static int nand_scan_tail(struct nand_chip *chip) ecc->read_subpage = nand_read_subpage; if (!ecc->write_subpage && ecc->hwctl && ecc->calculate) ecc->write_subpage = nand_write_subpage_hwecc; - /* fall through */ - + fallthrough; case NAND_ECC_HW_SYNDROME: if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) && (!ecc->read_page || @@ -5649,8 +5693,7 @@ static int nand_scan_tail(struct nand_chip *chip) ecc->size, mtd->writesize); ecc->mode = NAND_ECC_SOFT; ecc->algo = NAND_ECC_HAMMING; - /* fall through */ - + fallthrough; case NAND_ECC_SOFT: ret = nand_set_ecc_soft_ops(chip); if (ret) { @@ -5786,8 +5829,8 @@ static int nand_scan_tail(struct nand_chip *chip) mtd->_read_oob = nand_read_oob; mtd->_write_oob = nand_write_oob; mtd->_sync = nand_sync; - mtd->_lock = NULL; - mtd->_unlock = NULL; + mtd->_lock = nand_lock; + mtd->_unlock = nand_unlock; mtd->_suspend = nand_suspend; mtd->_resume = nand_resume; mtd->_reboot = nand_shutdown; @@ -5907,6 +5950,8 @@ void nand_cleanup(struct nand_chip *chip) chip->ecc.algo == NAND_ECC_BCH) nand_bch_free((struct nand_bch_control *)chip->ecc.priv); + nanddev_cleanup(&chip->base); + /* Free bad block table memory */ kfree(chip->bbt); kfree(chip->data_buf); diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index 194e4227aefe..7caedaa5b9e5 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -26,7 +26,7 @@ struct hynix_read_retry { int nregs; const u8 *regs; - u8 values[0]; + u8 values[]; }; /** diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c index f2526ec616a6..f91e92e1b972 100644 --- a/drivers/mtd/nand/raw/nand_legacy.c +++ b/drivers/mtd/nand/raw/nand_legacy.c @@ -331,8 +331,7 @@ static void nand_command(struct nand_chip *chip, unsigned int command, */ if (column == -1 && page_addr == -1) return; - /* fall through */ - + fallthrough; default: /* * If we don't have access to the busy pin, we apply the given @@ -483,8 +482,7 @@ static void nand_command_lp(struct nand_chip *chip, unsigned int command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* fall through - This applies to read commands */ + fallthrough; /* This applies to read commands */ default: /* * If we don't have access to the busy pin, we apply the given diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 3ff7ce00cbdb..09c254c97b5c 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -6,11 +6,31 @@ * Author: Boris Brezillon <boris.brezillon@free-electrons.com> */ +#include "linux/delay.h" #include "internals.h" #define MACRONIX_READ_RETRY_BIT BIT(0) #define MACRONIX_NUM_READ_RETRY_MODES 6 +#define ONFI_FEATURE_ADDR_MXIC_PROTECTION 0xA0 +#define MXIC_BLOCK_PROTECTION_ALL_LOCK 0x38 +#define MXIC_BLOCK_PROTECTION_ALL_UNLOCK 0x0 + +#define ONFI_FEATURE_ADDR_MXIC_RANDOMIZER 0xB0 +#define MACRONIX_RANDOMIZER_BIT BIT(1) +#define MACRONIX_RANDOMIZER_ENPGM BIT(0) +#define MACRONIX_RANDOMIZER_RANDEN BIT(1) +#define MACRONIX_RANDOMIZER_RANDOPT BIT(2) +#define MACRONIX_RANDOMIZER_MODE_ENTER \ + (MACRONIX_RANDOMIZER_ENPGM | \ + MACRONIX_RANDOMIZER_RANDEN | \ + MACRONIX_RANDOMIZER_RANDOPT) +#define MACRONIX_RANDOMIZER_MODE_EXIT \ + (MACRONIX_RANDOMIZER_RANDEN | \ + MACRONIX_RANDOMIZER_RANDOPT) + +#define MXIC_CMD_POWER_DOWN 0xB9 + struct nand_onfi_vendor_macronix { u8 reserved; u8 reliability_func; @@ -29,15 +49,83 @@ static int macronix_nand_setup_read_retry(struct nand_chip *chip, int mode) return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature); } +static int macronix_nand_randomizer_check_enable(struct nand_chip *chip) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + int ret; + + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + if (ret < 0) + return ret; + + if (feature[0]) + return feature[0]; + + feature[0] = MACRONIX_RANDOMIZER_MODE_ENTER; + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + if (ret < 0) + return ret; + + /* RANDEN and RANDOPT OTP bits are programmed */ + feature[0] = 0x0; + ret = nand_prog_page_op(chip, 0, 0, feature, 1); + if (ret < 0) + return ret; + + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + if (ret < 0) + return ret; + + feature[0] &= MACRONIX_RANDOMIZER_MODE_EXIT; + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + feature); + if (ret < 0) + return ret; + + return 0; +} + static void macronix_nand_onfi_init(struct nand_chip *chip) { struct nand_parameters *p = &chip->parameters; struct nand_onfi_vendor_macronix *mxic; + struct device_node *dn = nand_get_flash_node(chip); + int rand_otp = 0; + int ret; if (!p->onfi) return; + if (of_find_property(dn, "mxic,enable-randomizer-otp", NULL)) + rand_otp = 1; + mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor; + /* Subpage write is prohibited in randomizer operatoin */ + if (rand_otp && chip->options & NAND_NO_SUBPAGE_WRITE && + mxic->reliability_func & MACRONIX_RANDOMIZER_BIT) { + if (p->supports_set_get_features) { + bitmap_set(p->set_feature_list, + ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 1); + bitmap_set(p->get_feature_list, + ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, 1); + ret = macronix_nand_randomizer_check_enable(chip); + if (ret < 0) { + bitmap_clear(p->set_feature_list, + ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + 1); + bitmap_clear(p->get_feature_list, + ONFI_FEATURE_ADDR_MXIC_RANDOMIZER, + 1); + pr_info("Macronix NAND randomizer failed\n"); + } else { + pr_info("Macronix NAND randomizer enabled\n"); + } + } + } + if ((mxic->reliability_func & MACRONIX_READ_RETRY_BIT) == 0) return; @@ -91,6 +179,143 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip) ONFI_FEATURE_ADDR_TIMING_MODE, 1); } +/* + * Macronix NAND supports Block Protection by Protectoin(PT) pin; + * active high at power-on which protects the entire chip even the #WP is + * disabled. Lock/unlock protection area can be partition according to + * protection bits, i.e. upper 1/2 locked, upper 1/4 locked and so on. + */ +static int mxic_nand_lock(struct nand_chip *chip, loff_t ofs, uint64_t len) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + int ret; + + feature[0] = MXIC_BLOCK_PROTECTION_ALL_LOCK; + nand_select_target(chip, 0); + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, + feature); + nand_deselect_target(chip); + if (ret) + pr_err("%s all blocks failed\n", __func__); + + return ret; +} + +static int mxic_nand_unlock(struct nand_chip *chip, loff_t ofs, uint64_t len) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + int ret; + + feature[0] = MXIC_BLOCK_PROTECTION_ALL_UNLOCK; + nand_select_target(chip, 0); + ret = nand_set_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, + feature); + nand_deselect_target(chip); + if (ret) + pr_err("%s all blocks failed\n", __func__); + + return ret; +} + +static void macronix_nand_block_protection_support(struct nand_chip *chip) +{ + u8 feature[ONFI_SUBFEATURE_PARAM_LEN]; + int ret; + + bitmap_set(chip->parameters.get_feature_list, + ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); + + feature[0] = MXIC_BLOCK_PROTECTION_ALL_UNLOCK; + nand_select_target(chip, 0); + ret = nand_get_features(chip, ONFI_FEATURE_ADDR_MXIC_PROTECTION, + feature); + nand_deselect_target(chip); + if (ret || feature[0] != MXIC_BLOCK_PROTECTION_ALL_LOCK) { + if (ret) + pr_err("Block protection check failed\n"); + + bitmap_clear(chip->parameters.get_feature_list, + ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); + return; + } + + bitmap_set(chip->parameters.set_feature_list, + ONFI_FEATURE_ADDR_MXIC_PROTECTION, 1); + + chip->lock_area = mxic_nand_lock; + chip->unlock_area = mxic_nand_unlock; +} + +static int nand_power_down_op(struct nand_chip *chip) +{ + int ret; + + if (nand_has_exec_op(chip)) { + struct nand_op_instr instrs[] = { + NAND_OP_CMD(MXIC_CMD_POWER_DOWN, 0), + }; + + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + ret = nand_exec_op(chip, &op); + if (ret) + return ret; + + } else { + chip->legacy.cmdfunc(chip, MXIC_CMD_POWER_DOWN, -1, -1); + } + + return 0; +} + +static int mxic_nand_suspend(struct nand_chip *chip) +{ + int ret; + + nand_select_target(chip, 0); + ret = nand_power_down_op(chip); + if (ret < 0) + pr_err("Suspending MXIC NAND chip failed (%d)\n", ret); + nand_deselect_target(chip); + + return ret; +} + +static void mxic_nand_resume(struct nand_chip *chip) +{ + /* + * Toggle #CS pin to resume NAND device and don't care + * of the others CLE, #WE, #RE pins status. + * A NAND controller ensure it is able to assert/de-assert #CS + * by sending any byte over the NAND bus. + * i.e., + * NAND power down command or reset command w/o R/B# status checking. + */ + nand_select_target(chip, 0); + nand_power_down_op(chip); + /* The minimum of a recovery time tRDP is 35 us */ + usleep_range(35, 100); + nand_deselect_target(chip); +} + +static void macronix_nand_deep_power_down_support(struct nand_chip *chip) +{ + int i; + static const char * const deep_power_down_dev[] = { + "MX30UF1G28AD", + "MX30UF2G28AD", + "MX30UF4G28AD", + }; + + i = match_string(deep_power_down_dev, ARRAY_SIZE(deep_power_down_dev), + chip->parameters.model); + if (i < 0) + return; + + chip->suspend = mxic_nand_suspend; + chip->resume = mxic_nand_resume; +} + static int macronix_nand_init(struct nand_chip *chip) { if (nand_is_slc(chip)) @@ -98,6 +323,8 @@ static int macronix_nand_init(struct nand_chip *chip) macronix_nand_fix_broken_get_timings(chip); macronix_nand_onfi_init(chip); + macronix_nand_block_protection_support(chip); + macronix_nand_deep_power_down_support(chip); return 0; } diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index 9c03fbb1f47d..f3dcd695b5db 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -14,14 +14,68 @@ /* Recommended to rewrite for BENAND */ #define TOSHIBA_NAND_STATUS_REWRITE_RECOMMENDED BIT(3) +/* ECC Status Read Command for BENAND */ +#define TOSHIBA_NAND_CMD_ECC_STATUS_READ 0x7A + +/* ECC Status Mask for BENAND */ +#define TOSHIBA_NAND_ECC_STATUS_MASK 0x0F + +/* Uncorrectable Error for BENAND */ +#define TOSHIBA_NAND_ECC_STATUS_UNCORR 0x0F + +/* Max ECC Steps for BENAND */ +#define TOSHIBA_NAND_MAX_ECC_STEPS 8 + +static int toshiba_nand_benand_read_eccstatus_op(struct nand_chip *chip, + u8 *buf) +{ + u8 *ecc_status = buf; + + if (nand_has_exec_op(chip)) { + const struct nand_sdr_timings *sdr = + nand_get_sdr_timings(&chip->data_interface); + struct nand_op_instr instrs[] = { + NAND_OP_CMD(TOSHIBA_NAND_CMD_ECC_STATUS_READ, + PSEC_TO_NSEC(sdr->tADL_min)), + NAND_OP_8BIT_DATA_IN(chip->ecc.steps, ecc_status, 0), + }; + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); + + return nand_exec_op(chip, &op); + } + + return -ENOTSUPP; +} + static int toshiba_nand_benand_eccstatus(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); int ret; unsigned int max_bitflips = 0; - u8 status; + u8 status, ecc_status[TOSHIBA_NAND_MAX_ECC_STEPS]; /* Check Status */ + ret = toshiba_nand_benand_read_eccstatus_op(chip, ecc_status); + if (!ret) { + unsigned int i, bitflips = 0; + + for (i = 0; i < chip->ecc.steps; i++) { + bitflips = ecc_status[i] & TOSHIBA_NAND_ECC_STATUS_MASK; + if (bitflips == TOSHIBA_NAND_ECC_STATUS_UNCORR) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += bitflips; + max_bitflips = max(max_bitflips, bitflips); + } + } + + return max_bitflips; + } + + /* + * Fallback to regular status check if + * toshiba_nand_benand_read_eccstatus_op() failed. + */ ret = nand_status_op(chip, &status); if (ret) return ret; @@ -108,7 +162,7 @@ static void toshiba_nand_decode_id(struct nand_chip *chip) */ if (chip->id.len >= 6 && nand_is_slc(chip) && (chip->id.data[5] & 0x7) == 0x6 /* 24nm */ && - !(chip->id.data[4] & 0x80) /* !BENAND */) { + !(chip->id.data[4] & TOSHIBA_NAND_ID4_IS_BENAND) /* !BENAND */) { memorg->oobsize = 32 * memorg->pagesize >> 9; mtd->oobsize = memorg->oobsize; } diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index 9a70754a61ef..1de03bb34e84 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -2251,10 +2251,10 @@ static int __init ns_init_module(void) switch (bbt) { case 2: chip->bbt_options |= NAND_BBT_NO_OOB; - /* fall through */ + fallthrough; case 1: chip->bbt_options |= NAND_BBT_USE_FLASH; - /* fall through */ + fallthrough; case 0: break; default: diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c index 5502ffbdd1e6..3fa0e2cbbe53 100644 --- a/drivers/mtd/nand/raw/omap_elm.c +++ b/drivers/mtd/nand/raw/omap_elm.c @@ -455,13 +455,13 @@ static int elm_context_save(struct elm_info *info) ELM_SYNDROME_FRAGMENT_5 + offset); regs->elm_syndrome_fragment_4[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset); - /* fall through */ + fallthrough; case BCH8_ECC: regs->elm_syndrome_fragment_3[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset); regs->elm_syndrome_fragment_2[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset); - /* fall through */ + fallthrough; case BCH4_ECC: regs->elm_syndrome_fragment_1[i] = elm_read_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset); @@ -503,13 +503,13 @@ static int elm_context_restore(struct elm_info *info) regs->elm_syndrome_fragment_5[i]); elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset, regs->elm_syndrome_fragment_4[i]); - /* fall through */ + fallthrough; case BCH8_ECC: elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset, regs->elm_syndrome_fragment_3[i]); elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset, regs->elm_syndrome_fragment_2[i]); - /* fall through */ + fallthrough; case BCH4_ECC: elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset, regs->elm_syndrome_fragment_1[i]); diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 7bb9a7e8e1e7..5b11c7061497 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2628,6 +2628,29 @@ static const struct nand_controller_ops qcom_nandc_ops = { .attach_chip = qcom_nand_attach_chip, }; +static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) +{ + if (nandc->props->is_bam) { + if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) + dma_unmap_single(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + + if (nandc->tx_chan) + dma_release_channel(nandc->tx_chan); + + if (nandc->rx_chan) + dma_release_channel(nandc->rx_chan); + + if (nandc->cmd_chan) + dma_release_channel(nandc->cmd_chan); + } else { + if (nandc->chan) + dma_release_channel(nandc->chan); + } +} + static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) { int ret; @@ -2673,22 +2696,37 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) return -EIO; } - nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx"); - if (!nandc->tx_chan) { - dev_err(nandc->dev, "failed to request tx channel\n"); - return -ENODEV; + nandc->tx_chan = dma_request_chan(nandc->dev, "tx"); + if (IS_ERR(nandc->tx_chan)) { + ret = PTR_ERR(nandc->tx_chan); + nandc->tx_chan = NULL; + if (ret != -EPROBE_DEFER) + dev_err(nandc->dev, + "tx DMA channel request failed: %d\n", + ret); + goto unalloc; } - nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx"); - if (!nandc->rx_chan) { - dev_err(nandc->dev, "failed to request rx channel\n"); - return -ENODEV; + nandc->rx_chan = dma_request_chan(nandc->dev, "rx"); + if (IS_ERR(nandc->rx_chan)) { + ret = PTR_ERR(nandc->rx_chan); + nandc->rx_chan = NULL; + if (ret != -EPROBE_DEFER) + dev_err(nandc->dev, + "rx DMA channel request failed: %d\n", + ret); + goto unalloc; } - nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd"); - if (!nandc->cmd_chan) { - dev_err(nandc->dev, "failed to request cmd channel\n"); - return -ENODEV; + nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd"); + if (IS_ERR(nandc->cmd_chan)) { + ret = PTR_ERR(nandc->cmd_chan); + nandc->cmd_chan = NULL; + if (ret != -EPROBE_DEFER) + dev_err(nandc->dev, + "cmd DMA channel request failed: %d\n", + ret); + goto unalloc; } /* @@ -2702,14 +2740,19 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) if (!nandc->bam_txn) { dev_err(nandc->dev, "failed to allocate bam transaction\n"); - return -ENOMEM; + ret = -ENOMEM; + goto unalloc; } } else { - nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx"); - if (!nandc->chan) { - dev_err(nandc->dev, - "failed to request slave channel\n"); - return -ENODEV; + nandc->chan = dma_request_chan(nandc->dev, "rxtx"); + if (IS_ERR(nandc->chan)) { + ret = PTR_ERR(nandc->chan); + nandc->chan = NULL; + if (ret != -EPROBE_DEFER) + dev_err(nandc->dev, + "rxtx DMA channel request failed: %d\n", + ret); + return ret; } } @@ -2720,29 +2763,9 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) nandc->controller.ops = &qcom_nandc_ops; return 0; -} - -static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) -{ - if (nandc->props->is_bam) { - if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) - dma_unmap_single(nandc->dev, nandc->reg_read_dma, - MAX_REG_RD * - sizeof(*nandc->reg_read_buf), - DMA_FROM_DEVICE); - - if (nandc->tx_chan) - dma_release_channel(nandc->tx_chan); - - if (nandc->rx_chan) - dma_release_channel(nandc->rx_chan); - - if (nandc->cmd_chan) - dma_release_channel(nandc->cmd_chan); - } else { - if (nandc->chan) - dma_release_channel(nandc->chan); - } +unalloc: + qcom_nandc_unalloc(nandc); + return ret; } /* one time setup of a few nand controller registers */ diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 3ba73f18841f..b6d45cd911ae 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -1606,15 +1606,36 @@ static int stm32_fmc2_setup_interface(struct nand_chip *chip, int chipnr, /* DMA configuration */ static int stm32_fmc2_dma_setup(struct stm32_fmc2_nfc *fmc2) { - int ret; + int ret = 0; - fmc2->dma_tx_ch = dma_request_slave_channel(fmc2->dev, "tx"); - fmc2->dma_rx_ch = dma_request_slave_channel(fmc2->dev, "rx"); - fmc2->dma_ecc_ch = dma_request_slave_channel(fmc2->dev, "ecc"); + fmc2->dma_tx_ch = dma_request_chan(fmc2->dev, "tx"); + if (IS_ERR(fmc2->dma_tx_ch)) { + ret = PTR_ERR(fmc2->dma_tx_ch); + if (ret != -ENODEV) + dev_err(fmc2->dev, + "failed to request tx DMA channel: %d\n", ret); + fmc2->dma_tx_ch = NULL; + goto err_dma; + } - if (!fmc2->dma_tx_ch || !fmc2->dma_rx_ch || !fmc2->dma_ecc_ch) { - dev_warn(fmc2->dev, "DMAs not defined in the device tree, polling mode is used\n"); - return 0; + fmc2->dma_rx_ch = dma_request_chan(fmc2->dev, "rx"); + if (IS_ERR(fmc2->dma_rx_ch)) { + ret = PTR_ERR(fmc2->dma_rx_ch); + if (ret != -ENODEV) + dev_err(fmc2->dev, + "failed to request rx DMA channel: %d\n", ret); + fmc2->dma_rx_ch = NULL; + goto err_dma; + } + + fmc2->dma_ecc_ch = dma_request_chan(fmc2->dev, "ecc"); + if (IS_ERR(fmc2->dma_ecc_ch)) { + ret = PTR_ERR(fmc2->dma_ecc_ch); + if (ret != -ENODEV) + dev_err(fmc2->dev, + "failed to request ecc DMA channel: %d\n", ret); + fmc2->dma_ecc_ch = NULL; + goto err_dma; } ret = sg_alloc_table(&fmc2->dma_ecc_sg, FMC2_MAX_SG, GFP_KERNEL); @@ -1635,6 +1656,15 @@ static int stm32_fmc2_dma_setup(struct stm32_fmc2_nfc *fmc2) init_completion(&fmc2->dma_ecc_complete); return 0; + +err_dma: + if (ret == -ENODEV) { + dev_warn(fmc2->dev, + "DMAs not defined in the DT, polling mode is used\n"); + ret = 0; + } + + return ret; } /* NAND callbacks setup */ diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 37a4ac0dd85b..5f3e40b79fb1 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -195,7 +195,7 @@ struct sunxi_nand_chip { u32 timing_cfg; u32 timing_ctl; int nsels; - struct sunxi_nand_chip_sel sels[0]; + struct sunxi_nand_chip_sel sels[]; }; static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) @@ -2123,8 +2123,16 @@ static int sunxi_nfc_probe(struct platform_device *pdev) if (ret) goto out_ahb_reset_reassert; - nfc->dmac = dma_request_slave_channel(dev, "rxtx"); - if (nfc->dmac) { + nfc->dmac = dma_request_chan(dev, "rxtx"); + if (IS_ERR(nfc->dmac)) { + ret = PTR_ERR(nfc->dmac); + if (ret == -EPROBE_DEFER) + goto out_ahb_reset_reassert; + + /* Ignore errors to fall back to PIO mode */ + dev_warn(dev, "failed to request rxtx DMA channel: %d\n", ret); + nfc->dmac = NULL; + } else { struct dma_slave_config dmac_cfg = { }; dmac_cfg.src_addr = r->start + nfc->caps->reg_io_data; @@ -2138,9 +2146,6 @@ static int sunxi_nfc_probe(struct platform_device *pdev) if (nfc->caps->extra_mbus_conf) writel(readl(nfc->regs + NFC_REG_CTL) | NFC_DMA_TYPE_NORMAL, nfc->regs + NFC_REG_CTL); - - } else { - dev_warn(dev, "failed to request rxtx DMA channel\n"); } platform_set_drvdata(pdev, nfc); |