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 -----BEGIN PGP SIGNATURE----- iQI5BAABCAAjBQJbYWD3HBxib3Jpcy5icmV6aWxsb25AYm9vdGxpbi5jb20ACgkQ Ze02AX4ItwB4lxAAivl1dYSu+tRtQsV6RGnl3mB8RmYF6sIAhwu+cRJLis9ekedA AlCk/MQP1UPsY2MmiVD3akjsVXatm7DZW7SU/lADY5ua0ATQ1BYdQT9GJgFkymwb fvrNd2YsgQgteKiQrt1HpGxT1mP1140G7SuwZPOMcvbECRZ4lES/kSAiRst+2aWN 6Aj+EFcHZWNVz2bHqfzgunV6H/B8o8TghwMk/hlfgNcq17eWMrZhNWRlMRaCdKxK vNwP9E+mVxiudb4BNylkyH2k8+NcPePUCXzOdjC5ePMDjKAD1OOizo+tc63oZb9k DCRP/qodOLKjTFqsxeyET8YEgYQJIEyy+1WVF2PPF2zQewono9zxWpe1yN5dRwG6 MhKuufvzVrAiL/xSYWbmHE4y42MyWF/KrXUN/0zSSrcUCkrA5SyafehBDyJZbLVv +rtr+cjFVYqssIPYq9GmYlPxuyX4kwxAS337hJ00A+NbvB6h7uo+qvHyBR+XZ2YZ mYhrOQCamVoHAt2POZOQqc0692KjaS4naryiuCUwyqnp89HZkUxEDOYlYRCNZz8u SF/uG4obU4En1Lo+JqrBijYQ1qn1FvSGiilagbFnutyZmgTdohi67ImX8tGsgvSN pVc16KiNKVhiiywpUeIQWXUzzqWBKtmU+f3d2eQ+iX/oKZOYtDZneE4nov0= =uNJl -----END PGP SIGNATURE----- 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 "
This commit is contained in:
commit
d0eea5d8db
@ -69,6 +69,15 @@ Optional properties:
|
|||||||
all chips and support for it can not be detected at runtime.
|
all chips and support for it can not be detected at runtime.
|
||||||
Refer to your chips' datasheet to check if this is supported
|
Refer to your chips' datasheet to check if this is supported
|
||||||
by your chip.
|
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:
|
Example:
|
||||||
|
|
||||||
|
@ -28,11 +28,9 @@
|
|||||||
#include <linux/spi/flash.h>
|
#include <linux/spi/flash.h>
|
||||||
#include <linux/mtd/spi-nor.h>
|
#include <linux/mtd/spi-nor.h>
|
||||||
|
|
||||||
#define MAX_CMD_SIZE 6
|
|
||||||
struct m25p {
|
struct m25p {
|
||||||
struct spi_mem *spimem;
|
struct spi_mem *spimem;
|
||||||
struct spi_nor spi_nor;
|
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)
|
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 =
|
struct spi_mem_op op =
|
||||||
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
|
SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
|
||||||
SPI_MEM_OP_ADDR(nor->addr_width, to, 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));
|
SPI_MEM_OP_DATA_OUT(len, buf, 1));
|
||||||
size_t remaining = len;
|
size_t remaining = len;
|
||||||
int ret;
|
int ret;
|
||||||
@ -78,7 +76,6 @@ static ssize_t m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
|
|||||||
/* get transfer protocols. */
|
/* get transfer protocols. */
|
||||||
op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
|
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.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);
|
op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
|
||||||
|
|
||||||
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
|
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
/* QSPI register offsets */
|
/* QSPI register offsets */
|
||||||
#define QSPI_CR 0x0000 /* Control Register */
|
#define QSPI_CR 0x0000 /* Control Register */
|
||||||
@ -737,6 +737,26 @@ static int atmel_qspi_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
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[] = {
|
static const struct of_device_id atmel_qspi_dt_ids[] = {
|
||||||
{ .compatible = "atmel,sama5d2-qspi" },
|
{ .compatible = "atmel,sama5d2-qspi" },
|
||||||
@ -749,6 +769,7 @@ static struct platform_driver atmel_qspi_driver = {
|
|||||||
.driver = {
|
.driver = {
|
||||||
.name = "atmel_qspi",
|
.name = "atmel_qspi",
|
||||||
.of_match_table = atmel_qspi_dt_ids,
|
.of_match_table = atmel_qspi_dt_ids,
|
||||||
|
.pm = &atmel_qspi_pm_ops,
|
||||||
},
|
},
|
||||||
.probe = atmel_qspi_probe,
|
.probe = atmel_qspi_probe,
|
||||||
.remove = atmel_qspi_remove,
|
.remove = atmel_qspi_remove,
|
||||||
|
@ -525,15 +525,14 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, u8 *rxbuf,
|
|||||||
reg_base + CQSPI_REG_INDIRECTRD);
|
reg_base + CQSPI_REG_INDIRECTRD);
|
||||||
|
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
ret = wait_for_completion_timeout(&cqspi->transfer_complete,
|
if (!wait_for_completion_timeout(&cqspi->transfer_complete,
|
||||||
msecs_to_jiffies
|
msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS)))
|
||||||
(CQSPI_READ_TIMEOUT_MS));
|
ret = -ETIMEDOUT;
|
||||||
|
|
||||||
bytes_to_read = cqspi_get_rd_sram_level(cqspi);
|
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");
|
dev_err(nor->dev, "Indirect read timeout, no bytes\n");
|
||||||
ret = -ETIMEDOUT;
|
|
||||||
goto failrd;
|
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,
|
iowrite32_rep(cqspi->ahb_base, txbuf,
|
||||||
DIV_ROUND_UP(write_bytes, 4));
|
DIV_ROUND_UP(write_bytes, 4));
|
||||||
|
|
||||||
ret = wait_for_completion_timeout(&cqspi->transfer_complete,
|
if (!wait_for_completion_timeout(&cqspi->transfer_complete,
|
||||||
msecs_to_jiffies
|
msecs_to_jiffies(CQSPI_TIMEOUT_MS))) {
|
||||||
(CQSPI_TIMEOUT_MS));
|
|
||||||
if (!ret) {
|
|
||||||
dev_err(nor->dev, "Indirect write timeout\n");
|
dev_err(nor->dev, "Indirect write timeout\n");
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
goto failwr;
|
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);
|
dma_async_issue_pending(cqspi->rx_chan);
|
||||||
ret = wait_for_completion_timeout(&cqspi->rx_dma_complete,
|
if (!wait_for_completion_timeout(&cqspi->rx_dma_complete,
|
||||||
msecs_to_jiffies(len));
|
msecs_to_jiffies(len))) {
|
||||||
if (ret <= 0) {
|
|
||||||
dmaengine_terminate_sync(cqspi->rx_chan);
|
dmaengine_terminate_sync(cqspi->rx_chan);
|
||||||
dev_err(nor->dev, "DMA wait_for_completion_timeout\n");
|
dev_err(nor->dev, "DMA wait_for_completion_timeout\n");
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
|
@ -908,7 +908,7 @@ struct intel_spi *intel_spi_probe(struct device *dev,
|
|||||||
if (!ispi->writeable || !writeable)
|
if (!ispi->writeable || !writeable)
|
||||||
ispi->nor.mtd.flags &= ~MTD_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)
|
if (ret)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
@ -436,6 +436,7 @@ static int nxp_spifi_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = nxp_spifi_setup_flash(spifi, flash_np);
|
ret = nxp_spifi_setup_flash(spifi, flash_np);
|
||||||
|
of_node_put(flash_np);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "unable to setup flash chip\n");
|
dev_err(&pdev->dev, "unable to setup flash chip\n");
|
||||||
goto dis_clks;
|
goto dis_clks;
|
||||||
|
@ -2757,8 +2757,18 @@ static int spi_nor_init(struct spi_nor *nor)
|
|||||||
|
|
||||||
if ((nor->addr_width == 4) &&
|
if ((nor->addr_width == 4) &&
|
||||||
(JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
|
(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);
|
set_4byte(nor, nor->info, 1);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2781,7 +2791,8 @@ void spi_nor_restore(struct spi_nor *nor)
|
|||||||
/* restore the addressing mode */
|
/* restore the addressing mode */
|
||||||
if ((nor->addr_width == 4) &&
|
if ((nor->addr_width == 4) &&
|
||||||
(JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
|
(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);
|
set_4byte(nor, nor->info, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_nor_restore);
|
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;
|
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 */
|
/* Some devices cannot do fast-read, no matter what DT tells us */
|
||||||
if (info->flags & SPI_NOR_NO_FR)
|
if (info->flags & SPI_NOR_NO_FR)
|
||||||
params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
|
params.hwcaps.mask &= ~SNOR_HWCAPS_READ_FAST;
|
||||||
|
@ -355,7 +355,7 @@ static int stm32_qspi_read_reg(struct spi_nor *nor,
|
|||||||
struct device *dev = flash->qspi->dev;
|
struct device *dev = flash->qspi->dev;
|
||||||
struct stm32_qspi_cmd cmd;
|
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));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.opcode = opcode;
|
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 device *dev = flash->qspi->dev;
|
||||||
struct stm32_qspi_cmd cmd;
|
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));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
cmd.opcode = opcode;
|
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;
|
struct stm32_qspi_cmd cmd;
|
||||||
int err;
|
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);
|
nor->read_opcode, buf, (u32)from, len);
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
@ -235,6 +235,7 @@ enum spi_nor_option_flags {
|
|||||||
SNOR_F_S3AN_ADDR_DEFAULT = BIT(3),
|
SNOR_F_S3AN_ADDR_DEFAULT = BIT(3),
|
||||||
SNOR_F_READY_XSR_RDY = BIT(4),
|
SNOR_F_READY_XSR_RDY = BIT(4),
|
||||||
SNOR_F_USE_CLSR = BIT(5),
|
SNOR_F_USE_CLSR = BIT(5),
|
||||||
|
SNOR_F_BROKEN_RESET = BIT(6),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user