diff options
author | Boris Brezillon <boris.brezillon@bootlin.com> | 2018-08-11 13:19:35 +0300 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@bootlin.com> | 2018-08-11 13:19:35 +0300 |
commit | d0eea5d8db42a9fbf89943253908579865a3eaad (patch) | |
tree | bdc3d032b9107242508d91c513212150ce058b3e | |
parent | da86748bf60068e0d6ad56e5c919ca7e6782c4ba (diff) | |
parent | bb276262e88dae52cc717bb636b7468f66bb234e (diff) | |
download | linux-d0eea5d8db42a9fbf89943253908579865a3eaad.tar.xz |
Merge tag 'spi-nor/for-4.19' of git://git.infradead.org/linux-mtd into mtd/next
Pull SPI NOR updates from Boris Brezillon:
"
Core changes:
- Apply reset hacks only when reset is explicitly marked as broken in
the DT
Driver changes:
- Minor cleanup/fixes in the m25p80 driver
- Release flash_np in the nxp-spifi driver
- Add suspend/resume hooks to the atmel-quadspi driver
- Include gpio/consumer.h instead of gpio.h in the atmel-quadspi driver
- Use %pK instead of %p in the stm32-quadspi driver
- Improve timeout handling in the cadence-quadspi driver
- Use mtd_device_register() instead of mtd_device_parse_register() in
the intel-spi driver
"
-rw-r--r-- | Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt | 9 | ||||
-rw-r--r-- | drivers/mtd/devices/m25p80.c | 5 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/atmel-quadspi.c | 23 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/cadence-quadspi.c | 20 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/intel-spi.c | 2 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/nxp-spifi.c | 1 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 18 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/stm32-quadspi.c | 6 | ||||
-rw-r--r-- | include/linux/mtd/spi-nor.h | 1 |
9 files changed, 62 insertions, 23 deletions
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/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index e84563d2067f..fe260ccb2d7d 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -28,11 +28,9 @@ #include <linux/spi/flash.h> #include <linux/mtd/spi-nor.h> -#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) @@ -70,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; @@ -78,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) diff --git a/drivers/mtd/spi-nor/atmel-quadspi.c b/drivers/mtd/spi-nor/atmel-quadspi.c index 6c5708bacad8..820048726b4f 100644 --- a/drivers/mtd/spi-nor/atmel-quadspi.c +++ b/drivers/mtd/spi-nor/atmel-quadspi.c @@ -34,7 +34,7 @@ #include <linux/of.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> /* QSPI register offsets */ #define QSPI_CR 0x0000 /* Control Register */ @@ -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, 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; 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); 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; 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/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)); 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), }; /** |