From 00a5762b45250ebde8920d3cf68ca3974a0253b2 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 1 Jun 2018 12:03:24 +0200 Subject: mtd: m25p80: Remove unneeded m25p->command field The ->command field is no longer used, remove it. Signed-off-by: Boris Brezillon Acked-by: Marek Vasut --- drivers/mtd/devices/m25p80.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index e84563d2067f..3fc5ef4ebb16 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -28,11 +28,9 @@ #include #include -#define MAX_CMD_SIZE 6 struct m25p { struct spi_mem *spimem; struct spi_nor spi_nor; - u8 command[MAX_CMD_SIZE]; }; static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len) -- cgit v1.2.3 From 9882b5375df532acb2c2399a90d882461112e612 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 1 Jun 2018 12:03:25 +0200 Subject: mtd: m25p80: Use SPI_MEM_OP_NO_DUMMY instead of SPI_MEM_OP_DUMMY(0, x) SPI_MEM_OP_DUMMY(0, x) means there's 0 dummy bytes to send, which is similar to SPI_MEM_OP_NO_DUMMY except it's less clear. Use SPI_MEM_OP_NO_DUMMY instead of SPI_MEM_OP_DUMMY(0, x) in m25p80_write(). Also stop updating op.dummy.buswidth since this value is only meaningful if you have dummy bytes. Reported-by: Cyrille Pitchen Signed-off-by: Boris Brezillon Acked-by: Marek Vasut --- drivers/mtd/devices/m25p80.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 3fc5ef4ebb16..fe260ccb2d7d 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -68,7 +68,7 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1), SPI_MEM_OP_ADDR(nor->addr_width, to, 1), - SPI_MEM_OP_DUMMY(0, 1), + SPI_MEM_OP_NO_DUMMY, SPI_MEM_OP_DATA_OUT(len, buf, 1)); size_t remaining = len; int ret; @@ -76,7 +76,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len, /* get transfer protocols. */ op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto); op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto); - op.dummy.buswidth = op.addr.buswidth; op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto); if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second) -- cgit v1.2.3 From 38ebbe2b7282e985a7acc862892564e8fbbde866 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Wed, 9 May 2018 18:11:20 +0300 Subject: mtd: spi-nor: nxp-spifi: release flash_np in nxp_spifi_probe() nxp_spifi_probe() increments refcnt of SPI flash device node by of_get_next_available_child() and leaves it undecremented on both successful and error paths. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/nxp-spifi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/nxp-spifi.c b/drivers/mtd/spi-nor/nxp-spifi.c index 15374216d4d9..0c9094ec5966 100644 --- a/drivers/mtd/spi-nor/nxp-spifi.c +++ b/drivers/mtd/spi-nor/nxp-spifi.c @@ -436,6 +436,7 @@ static int nxp_spifi_probe(struct platform_device *pdev) } ret = nxp_spifi_setup_flash(spifi, flash_np); + of_node_put(flash_np); if (ret) { dev_err(&pdev->dev, "unable to setup flash chip\n"); goto dis_clks; -- cgit v1.2.3 From de217c1cca435a39f79cf9cb9279764688fc1cc4 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Mon, 4 Jun 2018 11:46:33 +0300 Subject: mtd: spi-nor: atmel-quadspi: add suspend/resume hooks Implement suspend/resume hooks. Signed-off-by: Claudiu Beznea Reviewed-by: Tudor Ambarus Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/atmel-quadspi.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/atmel-quadspi.c b/drivers/mtd/spi-nor/atmel-quadspi.c index 6c5708bacad8..ceaaef47f02e 100644 --- a/drivers/mtd/spi-nor/atmel-quadspi.c +++ b/drivers/mtd/spi-nor/atmel-quadspi.c @@ -737,6 +737,26 @@ static int atmel_qspi_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused atmel_qspi_suspend(struct device *dev) +{ + struct atmel_qspi *aq = dev_get_drvdata(dev); + + clk_disable_unprepare(aq->clk); + + return 0; +} + +static int __maybe_unused atmel_qspi_resume(struct device *dev) +{ + struct atmel_qspi *aq = dev_get_drvdata(dev); + + clk_prepare_enable(aq->clk); + + return atmel_qspi_init(aq); +} + +static SIMPLE_DEV_PM_OPS(atmel_qspi_pm_ops, atmel_qspi_suspend, + atmel_qspi_resume); static const struct of_device_id atmel_qspi_dt_ids[] = { { .compatible = "atmel,sama5d2-qspi" }, @@ -749,6 +769,7 @@ static struct platform_driver atmel_qspi_driver = { .driver = { .name = "atmel_qspi", .of_match_table = atmel_qspi_dt_ids, + .pm = &atmel_qspi_pm_ops, }, .probe = atmel_qspi_probe, .remove = atmel_qspi_remove, -- cgit v1.2.3 From 5f0d02270d0a7a71dde2d4be3566733bba4d951e Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Fri, 6 Jul 2018 15:05:25 +0200 Subject: mtd: spi-nor: stm32-quadspi: replace "%p" with "%pK" The format specifier "%p" can leak kernel addresses. Use "%pK" instead. Signed-off-by: Benjamin Gaignard Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/stm32-quadspi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index 72553506a00b..13e9fc961d3b 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -355,7 +355,7 @@ static int stm32_qspi_read_reg(struct spi_nor *nor, struct device *dev = flash->qspi->dev; struct stm32_qspi_cmd cmd; - dev_dbg(dev, "read_reg: cmd:%#.2x buf:%p len:%#x\n", opcode, buf, len); + dev_dbg(dev, "read_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = opcode; @@ -376,7 +376,7 @@ static int stm32_qspi_write_reg(struct spi_nor *nor, u8 opcode, struct device *dev = flash->qspi->dev; struct stm32_qspi_cmd cmd; - dev_dbg(dev, "write_reg: cmd:%#.2x buf:%p len:%#x\n", opcode, buf, len); + dev_dbg(dev, "write_reg: cmd:%#.2x buf:%pK len:%#x\n", opcode, buf, len); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = opcode; @@ -398,7 +398,7 @@ static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len, struct stm32_qspi_cmd cmd; int err; - dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#zx\n", + dev_dbg(qspi->dev, "read(%#.2x): buf:%pK from:%#.8x len:%#zx\n", nor->read_opcode, buf, (u32)from, len); memset(&cmd, 0, sizeof(cmd)); -- cgit v1.2.3 From 11edc1133e3023e6452d6934c3f22d65a9c05fe8 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Sat, 21 Jul 2018 13:55:10 +0200 Subject: mtd: spi-nor: intel-spi: use mtd_device_register() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver doesn't specify parsers so it can use that little helper. Signed-off-by: Rafał Miłecki Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/intel-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c index d2cbfc27826e..af0a22019516 100644 --- a/drivers/mtd/spi-nor/intel-spi.c +++ b/drivers/mtd/spi-nor/intel-spi.c @@ -908,7 +908,7 @@ struct intel_spi *intel_spi_probe(struct device *dev, if (!ispi->writeable || !writeable) ispi->nor.mtd.flags &= ~MTD_WRITEABLE; - ret = mtd_device_parse_register(&ispi->nor.mtd, NULL, NULL, &part, 1); + ret = mtd_device_register(&ispi->nor.mtd, &part, 1); if (ret) return ERR_PTR(ret); -- cgit v1.2.3 From 261b354caf299a3ff54ba5b35636687c857a0075 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 20 Jul 2018 11:57:41 +0200 Subject: mtd: spi-nor: atmel-quadspi: Include gpio/consumer.h instead of gpio.h GPIO consumers now include instead of if they can. Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/atmel-quadspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/atmel-quadspi.c b/drivers/mtd/spi-nor/atmel-quadspi.c index ceaaef47f02e..820048726b4f 100644 --- a/drivers/mtd/spi-nor/atmel-quadspi.c +++ b/drivers/mtd/spi-nor/atmel-quadspi.c @@ -34,7 +34,7 @@ #include #include -#include +#include /* QSPI register offsets */ #define QSPI_CR 0x0000 /* Control Register */ -- cgit v1.2.3 From 3938c0d4cf60477ec776c9a7751226b06bb3c3c0 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 21 Jul 2018 16:21:51 +0200 Subject: mtd: spi-nor: cadence-quadspi: fix timeout handling wait_for_completion_timeout returns an unsigned long not an int, so let's check its return value directly instead of storing it in ret, and avoid checking for negative values since this cannot happen. Signed-off-by: Nicholas Mc Guire Signed-off-by: Boris Brezillon --- drivers/mtd/spi-nor/cadence-quadspi.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index c3f7aaa5d18f..7a19dae717fa 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -525,15 +525,14 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, u8 *rxbuf, reg_base + CQSPI_REG_INDIRECTRD); while (remaining > 0) { - ret = wait_for_completion_timeout(&cqspi->transfer_complete, - msecs_to_jiffies - (CQSPI_READ_TIMEOUT_MS)); + if (!wait_for_completion_timeout(&cqspi->transfer_complete, + msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) + ret = -ETIMEDOUT; bytes_to_read = cqspi_get_rd_sram_level(cqspi); - if (!ret && bytes_to_read == 0) { + if (ret && bytes_to_read == 0) { dev_err(nor->dev, "Indirect read timeout, no bytes\n"); - ret = -ETIMEDOUT; goto failrd; } @@ -649,10 +648,8 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr, iowrite32_rep(cqspi->ahb_base, txbuf, DIV_ROUND_UP(write_bytes, 4)); - ret = wait_for_completion_timeout(&cqspi->transfer_complete, - msecs_to_jiffies - (CQSPI_TIMEOUT_MS)); - if (!ret) { + if (!wait_for_completion_timeout(&cqspi->transfer_complete, + msecs_to_jiffies(CQSPI_TIMEOUT_MS))) { dev_err(nor->dev, "Indirect write timeout\n"); ret = -ETIMEDOUT; goto failwr; @@ -986,9 +983,8 @@ static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf, } dma_async_issue_pending(cqspi->rx_chan); - ret = wait_for_completion_timeout(&cqspi->rx_dma_complete, - msecs_to_jiffies(len)); - if (ret <= 0) { + if (!wait_for_completion_timeout(&cqspi->rx_dma_complete, + msecs_to_jiffies(len))) { dmaengine_terminate_sync(cqspi->rx_chan); dev_err(nor->dev, "DMA wait_for_completion_timeout\n"); ret = -ETIMEDOUT; -- cgit v1.2.3 From bb276262e88dae52cc717bb636b7468f66bb234e Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 27 Jul 2018 11:33:13 -0700 Subject: mtd: spi-nor: only apply reset hacks to broken hardware Commit 59b356ffd0b0 ("mtd: m25p80: restore the status of SPI flash when exiting") is the latest from a long history of attempts to add reboot handling to handle stateful addressing modes on SPI flash. Some prior mostly-related discussions: http://lists.infradead.org/pipermail/linux-mtd/2013-March/046343.html [PATCH 1/3] mtd: m25p80: utilize dedicated 4-byte addressing commands http://lists.infradead.org/pipermail/barebox/2014-September/020682.html [RFC] MTD m25p80 3-byte addressing and boot problem http://lists.infradead.org/pipermail/linux-mtd/2015-February/057683.html [PATCH 2/2] m25p80: if supported put chip to deep power down if not used Previously, attempts to add reboot-time software reset handling were rejected, but the latest attempt was not. Quick summary of the problem: Some systems (e.g., boot ROM or bootloader) assume that they can read initial boot code from their SPI flash using 3-byte addressing. If the flash is left in 4-byte mode after reset, these systems won't boot. The above patch provided a shutdown/remove hook to attempt to reset the addressing mode before we reboot. Notably, this patch misses out on huge classes of unexpected reboots (e.g., crashes, watchdog resets). Unfortunately, it is essentially impossible to solve this problem 100%: if your system doesn't know how to reset the SPI flash to power-on defaults at initialization time, no amount of software can really rescue you -- there will always be a chance of some unexpected reset that leaves your flash in an addressing mode that your boot sequence didn't expect. While it is not directly harmful to perform hacks like the aforementioned commit on all 4-byte addressing flash, a properly-designed system should not need the hack -- and in fact, providing this hack may mask the fact that a given system is indeed broken. So this patch attempts to apply this unsound hack more narrowly, providing a strong suggestion to developers and system designers that this is truly a hack. With luck, system designers can catch their errors early on in their development cycle, rather than applying this hack long term. But apparently enough systems are out in the wild that we still have to provide this hack. Document a new device tree property to denote systems that do not have a proper hardware (or software) reset mechanism, and apply the hack (with a loud warning) only in this case. Signed-off-by: Brian Norris Reviewed-by: Guenter Roeck Signed-off-by: Boris Brezillon --- .../devicetree/bindings/mtd/jedec,spi-nor.txt | 9 +++++++++ drivers/mtd/spi-nor/spi-nor.c | 18 ++++++++++++++++-- include/linux/mtd/spi-nor.h | 1 + 3 files changed, 26 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt index 956bb046e599..f03be904d3c2 100644 --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt @@ -69,6 +69,15 @@ Optional properties: all chips and support for it can not be detected at runtime. Refer to your chips' datasheet to check if this is supported by your chip. +- broken-flash-reset : Some flash devices utilize stateful addressing modes + (e.g., for 32-bit addressing) which need to be managed + carefully by a system. Because these sorts of flash don't + have a standardized software reset command, and because some + systems don't toggle the flash RESET# pin upon system reset + (if the pin even exists at all), there are systems which + cannot reboot properly if the flash is left in the "wrong" + state. This boolean flag can be used on such systems, to + denote the absence of a reliable reset mechanism. Example: diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d9c368c44194..f028277fb1ce 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -2757,8 +2757,18 @@ static int spi_nor_init(struct spi_nor *nor) if ((nor->addr_width == 4) && (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) && - !(nor->info->flags & SPI_NOR_4B_OPCODES)) + !(nor->info->flags & SPI_NOR_4B_OPCODES)) { + /* + * If the RESET# pin isn't hooked up properly, or the system + * otherwise doesn't perform a reset command in the boot + * sequence, it's impossible to 100% protect against unexpected + * reboots (e.g., crashes). Warn the user (or hopefully, system + * designer) that this is bad. + */ + WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET, + "enabling reset hack; may not recover from unexpected reboots\n"); set_4byte(nor, nor->info, 1); + } return 0; } @@ -2781,7 +2791,8 @@ void spi_nor_restore(struct spi_nor *nor) /* restore the addressing mode */ if ((nor->addr_width == 4) && (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) && - !(nor->info->flags & SPI_NOR_4B_OPCODES)) + !(nor->info->flags & SPI_NOR_4B_OPCODES) && + (nor->flags & SNOR_F_BROKEN_RESET)) set_4byte(nor, nor->info, 0); } EXPORT_SYMBOL_GPL(spi_nor_restore); @@ -2911,6 +2922,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, params.hwcaps.mask |= SNOR_HWCAPS_READ_FAST; } + if (of_property_read_bool(np, "broken-flash-reset")) + nor->flags |= SNOR_F_BROKEN_RESET; + /* Some devices cannot do fast-read, no matter what DT tells us */ if (info->flags & SPI_NOR_NO_FR) params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index e60da0d34cc1..c922e97f205a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -235,6 +235,7 @@ enum spi_nor_option_flags { SNOR_F_S3AN_ADDR_DEFAULT = BIT(3), SNOR_F_READY_XSR_RDY = BIT(4), SNOR_F_USE_CLSR = BIT(5), + SNOR_F_BROKEN_RESET = BIT(6), }; /** -- cgit v1.2.3