Commit 20b2fc79 authored by Richard Weinberger's avatar Richard Weinberger

Merge tag 'spi-nor/for-4.15' of git://git.infradead.org/l2-mtd

This pull-request contains the following notable changes:

From Cyrille:
"
Core changes:
* Introduce system power management support.
* New mechanism to select the proper .quad_enable() hook by JEDEC ID,
  when needed, instead of only by manufacturer ID.
* Add support to new memory parts from Gigadevice, Winbond, Macronix and
  Everspin.

Driver changes:
* Maintainance for Cadence, Intel, Mediatek and STM32 drivers.
"
parents 0b07194b ec0a9f62
* Cadence Quad SPI controller * Cadence Quad SPI controller
Required properties: Required properties:
- compatible : Should be "cdns,qspi-nor". - compatible : should be one of the following:
Generic default - "cdns,qspi-nor".
For TI 66AK2G SoC - "ti,k2g-qspi", "cdns,qspi-nor".
- reg : Contains two entries, each of which is a tuple consisting of a - reg : Contains two entries, each of which is a tuple consisting of a
physical address and length. The first entry is the address and physical address and length. The first entry is the address and
length of the controller register set. The second entry is the length of the controller register set. The second entry is the
...@@ -14,6 +16,9 @@ Required properties: ...@@ -14,6 +16,9 @@ Required properties:
Optional properties: Optional properties:
- cdns,is-decoded-cs : Flag to indicate whether decoder is used or not. - cdns,is-decoded-cs : Flag to indicate whether decoder is used or not.
- cdns,rclk-en : Flag to indicate that QSPI return clock is used to latch
the read data rather than the QSPI clock. Make sure that QSPI return
clock is populated on the board before using this property.
Optional subnodes: Optional subnodes:
Subnodes of the Cadence Quad SPI controller are spi slave nodes with additional Subnodes of the Cadence Quad SPI controller are spi slave nodes with additional
......
...@@ -13,6 +13,7 @@ Required properties: ...@@ -13,6 +13,7 @@ Required properties:
at25df321a at25df321a
at25df641 at25df641
at26df081a at26df081a
mr25h128
mr25h256 mr25h256
mr25h10 mr25h10
mr25h40 mr25h40
......
* Serial NOR flash controller for MTK MT81xx (and similar) * Serial NOR flash controller for MTK MT81xx (and similar)
Required properties: Required properties:
- compatible: The possible values are: - compatible: For mt8173, compatible should be "mediatek,mt8173-nor",
"mediatek,mt2701-nor" and it's the fallback compatible for other Soc.
"mediatek,mt7623-nor" For every other SoC, should contain both the SoC-specific compatible
string and "mediatek,mt8173-nor".
The possible values are:
"mediatek,mt2701-nor", "mediatek,mt8173-nor"
"mediatek,mt2712-nor", "mediatek,mt8173-nor"
"mediatek,mt7622-nor", "mediatek,mt8173-nor"
"mediatek,mt7623-nor", "mediatek,mt8173-nor"
"mediatek,mt8173-nor" "mediatek,mt8173-nor"
For mt8173, compatible should be "mediatek,mt8173-nor".
For every other SoC, should contain both the SoC-specific compatible string
and "mediatek,mt8173-nor".
- reg: physical base address and length of the controller's register - reg: physical base address and length of the controller's register
- clocks: the phandle of the clocks needed by the nor controller - clocks: the phandle of the clocks needed by the nor controller
- clock-names: the names of the clocks - clock-names: the names of the clocks
......
...@@ -359,6 +359,7 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -359,6 +359,7 @@ static const struct spi_device_id m25p_ids[] = {
{"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"},
/* Everspin MRAMs (non-JEDEC) */ /* Everspin MRAMs (non-JEDEC) */
{ "mr25h128" }, /* 128 Kib, 40 MHz */
{ "mr25h256" }, /* 256 Kib, 40 MHz */ { "mr25h256" }, /* 256 Kib, 40 MHz */
{ "mr25h10" }, /* 1 Mib, 40 MHz */ { "mr25h10" }, /* 1 Mib, 40 MHz */
{ "mr25h40" }, /* 4 Mib, 40 MHz */ { "mr25h40" }, /* 4 Mib, 40 MHz */
......
...@@ -50,7 +50,7 @@ config SPI_ATMEL_QUADSPI ...@@ -50,7 +50,7 @@ config SPI_ATMEL_QUADSPI
config SPI_CADENCE_QUADSPI config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller" tristate "Cadence Quad SPI controller"
depends on OF && (ARM || COMPILE_TEST) depends on OF && (ARM || ARM64 || COMPILE_TEST)
help help
Enable support for the Cadence Quad SPI Flash controller. Enable support for the Cadence Quad SPI Flash controller.
...@@ -90,7 +90,7 @@ config SPI_INTEL_SPI ...@@ -90,7 +90,7 @@ config SPI_INTEL_SPI
tristate tristate
config SPI_INTEL_SPI_PCI config SPI_INTEL_SPI_PCI
tristate "Intel PCH/PCU SPI flash PCI driver" if EXPERT tristate "Intel PCH/PCU SPI flash PCI driver"
depends on X86 && PCI depends on X86 && PCI
select SPI_INTEL_SPI select SPI_INTEL_SPI
help help
...@@ -106,7 +106,7 @@ config SPI_INTEL_SPI_PCI ...@@ -106,7 +106,7 @@ config SPI_INTEL_SPI_PCI
will be called intel-spi-pci. will be called intel-spi-pci.
config SPI_INTEL_SPI_PLATFORM config SPI_INTEL_SPI_PLATFORM
tristate "Intel PCH/PCU SPI flash platform driver" if EXPERT tristate "Intel PCH/PCU SPI flash platform driver"
depends on X86 depends on X86
select SPI_INTEL_SPI select SPI_INTEL_SPI
help help
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/timer.h> #include <linux/timer.h>
...@@ -38,6 +39,9 @@ ...@@ -38,6 +39,9 @@
#define CQSPI_NAME "cadence-qspi" #define CQSPI_NAME "cadence-qspi"
#define CQSPI_MAX_CHIPSELECT 16 #define CQSPI_MAX_CHIPSELECT 16
/* Quirks */
#define CQSPI_NEEDS_WR_DELAY BIT(0)
struct cqspi_st; struct cqspi_st;
struct cqspi_flash_pdata { struct cqspi_flash_pdata {
...@@ -75,7 +79,9 @@ struct cqspi_st { ...@@ -75,7 +79,9 @@ struct cqspi_st {
bool is_decoded_cs; bool is_decoded_cs;
u32 fifo_depth; u32 fifo_depth;
u32 fifo_width; u32 fifo_width;
bool rclk_en;
u32 trigger_address; u32 trigger_address;
u32 wr_delay;
struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT]; struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
}; };
...@@ -608,6 +614,15 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, ...@@ -608,6 +614,15 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor,
reinit_completion(&cqspi->transfer_complete); reinit_completion(&cqspi->transfer_complete);
writel(CQSPI_REG_INDIRECTWR_START_MASK, writel(CQSPI_REG_INDIRECTWR_START_MASK,
reg_base + CQSPI_REG_INDIRECTWR); reg_base + CQSPI_REG_INDIRECTWR);
/*
* As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access
* Controller programming sequence, couple of cycles of
* QSPI_REF_CLK delay is required for the above bit to
* be internally synchronized by the QSPI module. Provide 5
* cycles of delay.
*/
if (cqspi->wr_delay)
ndelay(cqspi->wr_delay);
while (remaining > 0) { while (remaining > 0) {
write_bytes = remaining > page_size ? page_size : remaining; write_bytes = remaining > page_size ? page_size : remaining;
...@@ -775,7 +790,7 @@ static void cqspi_config_baudrate_div(struct cqspi_st *cqspi) ...@@ -775,7 +790,7 @@ static void cqspi_config_baudrate_div(struct cqspi_st *cqspi)
} }
static void cqspi_readdata_capture(struct cqspi_st *cqspi, static void cqspi_readdata_capture(struct cqspi_st *cqspi,
const unsigned int bypass, const bool bypass,
const unsigned int delay) const unsigned int delay)
{ {
void __iomem *reg_base = cqspi->iobase; void __iomem *reg_base = cqspi->iobase;
...@@ -839,7 +854,8 @@ static void cqspi_configure(struct spi_nor *nor) ...@@ -839,7 +854,8 @@ static void cqspi_configure(struct spi_nor *nor)
cqspi->sclk = sclk; cqspi->sclk = sclk;
cqspi_config_baudrate_div(cqspi); cqspi_config_baudrate_div(cqspi);
cqspi_delay(nor); cqspi_delay(nor);
cqspi_readdata_capture(cqspi, 1, f_pdata->read_delay); cqspi_readdata_capture(cqspi, !cqspi->rclk_en,
f_pdata->read_delay);
} }
if (switch_cs || switch_ck) if (switch_cs || switch_ck)
...@@ -1036,6 +1052,8 @@ static int cqspi_of_get_pdata(struct platform_device *pdev) ...@@ -1036,6 +1052,8 @@ static int cqspi_of_get_pdata(struct platform_device *pdev)
return -ENXIO; return -ENXIO;
} }
cqspi->rclk_en = of_property_read_bool(np, "cdns,rclk-en");
return 0; return 0;
} }
...@@ -1156,6 +1174,7 @@ static int cqspi_probe(struct platform_device *pdev) ...@@ -1156,6 +1174,7 @@ static int cqspi_probe(struct platform_device *pdev)
struct cqspi_st *cqspi; struct cqspi_st *cqspi;
struct resource *res; struct resource *res;
struct resource *res_ahb; struct resource *res_ahb;
unsigned long data;
int ret; int ret;
int irq; int irq;
...@@ -1206,13 +1225,24 @@ static int cqspi_probe(struct platform_device *pdev) ...@@ -1206,13 +1225,24 @@ static int cqspi_probe(struct platform_device *pdev)
return -ENXIO; return -ENXIO;
} }
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put_noidle(dev);
return ret;
}
ret = clk_prepare_enable(cqspi->clk); ret = clk_prepare_enable(cqspi->clk);
if (ret) { if (ret) {
dev_err(dev, "Cannot enable QSPI clock.\n"); dev_err(dev, "Cannot enable QSPI clock.\n");
return ret; goto probe_clk_failed;
} }
cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk); cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
data = (unsigned long)of_device_get_match_data(dev);
if (data & CQSPI_NEEDS_WR_DELAY)
cqspi->wr_delay = 5 * DIV_ROUND_UP(NSEC_PER_SEC,
cqspi->master_ref_clk_hz);
ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0, ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
pdev->name, cqspi); pdev->name, cqspi);
...@@ -1233,10 +1263,13 @@ static int cqspi_probe(struct platform_device *pdev) ...@@ -1233,10 +1263,13 @@ static int cqspi_probe(struct platform_device *pdev)
} }
return ret; return ret;
probe_irq_failed:
cqspi_controller_enable(cqspi, 0);
probe_setup_failed: probe_setup_failed:
cqspi_controller_enable(cqspi, 0);
probe_irq_failed:
clk_disable_unprepare(cqspi->clk); clk_disable_unprepare(cqspi->clk);
probe_clk_failed:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
return ret; return ret;
} }
...@@ -1253,6 +1286,9 @@ static int cqspi_remove(struct platform_device *pdev) ...@@ -1253,6 +1286,9 @@ static int cqspi_remove(struct platform_device *pdev)
clk_disable_unprepare(cqspi->clk); clk_disable_unprepare(cqspi->clk);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0; return 0;
} }
...@@ -1284,7 +1320,14 @@ static const struct dev_pm_ops cqspi__dev_pm_ops = { ...@@ -1284,7 +1320,14 @@ static const struct dev_pm_ops cqspi__dev_pm_ops = {
#endif #endif
static const struct of_device_id cqspi_dt_ids[] = { static const struct of_device_id cqspi_dt_ids[] = {
{.compatible = "cdns,qspi-nor",}, {
.compatible = "cdns,qspi-nor",
.data = (void *)0,
},
{
.compatible = "ti,k2g-qspi",
.data = (void *)CQSPI_NEEDS_WR_DELAY,
},
{ /* end of table */ } { /* end of table */ }
}; };
......
...@@ -63,7 +63,10 @@ static void intel_spi_pci_remove(struct pci_dev *pdev) ...@@ -63,7 +63,10 @@ static void intel_spi_pci_remove(struct pci_dev *pdev)
} }
static const struct pci_device_id intel_spi_pci_ids[] = { static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
{ }, { },
}; };
MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
......
This diff is collapsed.
...@@ -404,6 +404,29 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, ...@@ -404,6 +404,29 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
return ret; return ret;
} }
static void mt8173_nor_disable_clk(struct mt8173_nor *mt8173_nor)
{
clk_disable_unprepare(mt8173_nor->spi_clk);
clk_disable_unprepare(mt8173_nor->nor_clk);
}
static int mt8173_nor_enable_clk(struct mt8173_nor *mt8173_nor)
{
int ret;
ret = clk_prepare_enable(mt8173_nor->spi_clk);
if (ret)
return ret;
ret = clk_prepare_enable(mt8173_nor->nor_clk);
if (ret) {
clk_disable_unprepare(mt8173_nor->spi_clk);
return ret;
}
return 0;
}
static int mtk_nor_init(struct mt8173_nor *mt8173_nor, static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
struct device_node *flash_node) struct device_node *flash_node)
{ {
...@@ -468,15 +491,11 @@ static int mtk_nor_drv_probe(struct platform_device *pdev) ...@@ -468,15 +491,11 @@ static int mtk_nor_drv_probe(struct platform_device *pdev)
return PTR_ERR(mt8173_nor->nor_clk); return PTR_ERR(mt8173_nor->nor_clk);
mt8173_nor->dev = &pdev->dev; mt8173_nor->dev = &pdev->dev;
ret = clk_prepare_enable(mt8173_nor->spi_clk);
ret = mt8173_nor_enable_clk(mt8173_nor);
if (ret) if (ret)
return ret; return ret;
ret = clk_prepare_enable(mt8173_nor->nor_clk);
if (ret) {
clk_disable_unprepare(mt8173_nor->spi_clk);
return ret;
}
/* only support one attached flash */ /* only support one attached flash */
flash_np = of_get_next_available_child(pdev->dev.of_node, NULL); flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
if (!flash_np) { if (!flash_np) {
...@@ -487,10 +506,9 @@ static int mtk_nor_drv_probe(struct platform_device *pdev) ...@@ -487,10 +506,9 @@ static int mtk_nor_drv_probe(struct platform_device *pdev)
ret = mtk_nor_init(mt8173_nor, flash_np); ret = mtk_nor_init(mt8173_nor, flash_np);
nor_free: nor_free:
if (ret) { if (ret)
clk_disable_unprepare(mt8173_nor->spi_clk); mt8173_nor_disable_clk(mt8173_nor);
clk_disable_unprepare(mt8173_nor->nor_clk);
}
return ret; return ret;
} }
...@@ -498,11 +516,38 @@ static int mtk_nor_drv_remove(struct platform_device *pdev) ...@@ -498,11 +516,38 @@ static int mtk_nor_drv_remove(struct platform_device *pdev)
{ {
struct mt8173_nor *mt8173_nor = platform_get_drvdata(pdev); struct mt8173_nor *mt8173_nor = platform_get_drvdata(pdev);
clk_disable_unprepare(mt8173_nor->spi_clk); mt8173_nor_disable_clk(mt8173_nor);
clk_disable_unprepare(mt8173_nor->nor_clk);
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP
static int mtk_nor_suspend(struct device *dev)
{
struct mt8173_nor *mt8173_nor = dev_get_drvdata(dev);
mt8173_nor_disable_clk(mt8173_nor);
return 0;
}
static int mtk_nor_resume(struct device *dev)
{
struct mt8173_nor *mt8173_nor = dev_get_drvdata(dev);
return mt8173_nor_enable_clk(mt8173_nor);
}
static const struct dev_pm_ops mtk_nor_dev_pm_ops = {
.suspend = mtk_nor_suspend,
.resume = mtk_nor_resume,
};
#define MTK_NOR_DEV_PM_OPS (&mtk_nor_dev_pm_ops)
#else
#define MTK_NOR_DEV_PM_OPS NULL
#endif
static const struct of_device_id mtk_nor_of_ids[] = { static const struct of_device_id mtk_nor_of_ids[] = {
{ .compatible = "mediatek,mt8173-nor"}, { .compatible = "mediatek,mt8173-nor"},
{ /* sentinel */ } { /* sentinel */ }
...@@ -514,6 +559,7 @@ static struct platform_driver mtk_nor_driver = { ...@@ -514,6 +559,7 @@ static struct platform_driver mtk_nor_driver = {
.remove = mtk_nor_drv_remove, .remove = mtk_nor_drv_remove,
.driver = { .driver = {
.name = "mtk-nor", .name = "mtk-nor",
.pm = MTK_NOR_DEV_PM_OPS,
.of_match_table = mtk_nor_of_ids, .of_match_table = mtk_nor_of_ids,
}, },
}; };
......
...@@ -89,6 +89,8 @@ struct flash_info { ...@@ -89,6 +89,8 @@ struct flash_info {
#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ #define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
#define USE_CLSR BIT(14) /* use CLSR command */ #define USE_CLSR BIT(14) /* use CLSR command */
int (*quad_enable)(struct spi_nor *nor);
}; };
#define JEDEC_MFR(info) ((info)->id[0]) #define JEDEC_MFR(info) ((info)->id[0])
...@@ -870,6 +872,8 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -870,6 +872,8 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
return ret; return ret;
} }
static int macronix_quad_enable(struct spi_nor *nor);
/* Used when the "_ext_id" is two bytes at most */ /* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
.id = { \ .id = { \
...@@ -964,6 +968,7 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -964,6 +968,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_LOCK) }, { "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_LOCK) },
/* Everspin */ /* Everspin */
{ "mr25h128", CAT25_INFO( 16 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "mr25h40", CAT25_INFO(512 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "mr25h40", CAT25_INFO(512 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
...@@ -982,6 +987,11 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -982,6 +987,11 @@ static const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
}, },
{
"gd25lq32", INFO(0xc86016, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{ {
"gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
...@@ -997,6 +1007,12 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -997,6 +1007,12 @@ static const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
}, },
{
"gd25q256", INFO(0xc84019, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
.quad_enable = macronix_quad_enable,
},
/* Intel/Numonyx -- xxxs33b */ /* Intel/Numonyx -- xxxs33b */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
...@@ -1024,7 +1040,7 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -1024,7 +1040,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ "mx66l1g45g", INFO(0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "mx66l1g45g", INFO(0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
...@@ -1137,6 +1153,11 @@ static const struct flash_info spi_nor_ids[] = { ...@@ -1137,6 +1153,11 @@ static const struct flash_info spi_nor_ids[] = {
{ "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) },
{ "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) },
{
"w25q16dw", INFO(0xef6015, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{ "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) }, { "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) },
{ "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) }, { "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) },
...@@ -2288,8 +2309,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, ...@@ -2288,8 +2309,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
/* Check the SFDP header version. */ /* Check the SFDP header version. */
if (le32_to_cpu(header.signature) != SFDP_SIGNATURE || if (le32_to_cpu(header.signature) != SFDP_SIGNATURE ||
header.major != SFDP_JESD216_MAJOR || header.major != SFDP_JESD216_MAJOR)
header.minor < SFDP_JESD216_MINOR)
return -EINVAL; return -EINVAL;
/* /*
...@@ -2427,6 +2447,15 @@ static int spi_nor_init_params(struct spi_nor *nor, ...@@ -2427,6 +2447,15 @@ static int spi_nor_init_params(struct spi_nor *nor,
params->quad_enable = spansion_quad_enable; params->quad_enable = spansion_quad_enable;
break; break;
} }
/*
* Some manufacturer like GigaDevice may use different
* bit to set QE on different memories, so the MFR can't
* indicate the quad_enable method for this case, we need
* set it in flash info list.
*/
if (info->quad_enable)
params->quad_enable = info->quad_enable;
} }
/* Override the parameters with data read from SFDP tables. */ /* Override the parameters with data read from SFDP tables. */
...@@ -2630,17 +2659,60 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, ...@@ -2630,17 +2659,60 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
/* Enable Quad I/O if needed. */ /* Enable Quad I/O if needed. */
enable_quad_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 || enable_quad_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 ||
spi_nor_get_protocol_width(nor->write_proto) == 4); spi_nor_get_protocol_width(nor->write_proto) == 4);
if (enable_quad_io && params->quad_enable) { if (enable_quad_io && params->quad_enable)
err = params->quad_enable(nor); nor->quad_enable = params->quad_enable;
else
nor->quad_enable = NULL;
return 0;
}
static int spi_nor_init(struct spi_nor *nor)
{
int err;
/*
* Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
* with the software protection bits set
*/
if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL ||
JEDEC_MFR(nor->info) == SNOR_MFR_INTEL ||
JEDEC_MFR(nor->info) == SNOR_MFR_SST ||
nor->info->flags & SPI_NOR_HAS_LOCK) {
write_enable(nor);
write_sr(nor, 0);
spi_nor_wait_till_ready(nor);
}
if (nor->quad_enable) {
err = nor->quad_enable(nor);
if (err) { if (err) {
dev_err(nor->dev, "quad mode not supported\n"); dev_err(nor->dev, "quad mode not supported\n");
return err; return err;
} }
} }
if ((nor->addr_width == 4) &&
(JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
!(nor->info->flags & SPI_NOR_4B_OPCODES))
set_4byte(nor, nor->info, 1);
return 0; return 0;
} }
/* mtd resume handler */
static void spi_nor_resume(struct mtd_info *mtd)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
struct device *dev = nor->dev;
int ret;
/* re-initialize the nor chip */
ret = spi_nor_init(nor);
if (ret)
dev_err(dev, "resume() failed\n");
}
int spi_nor_scan(struct spi_nor *nor, const char *name, int spi_nor_scan(struct spi_nor *nor, const char *name,
const struct spi_nor_hwcaps *hwcaps) const struct spi_nor_hwcaps *hwcaps)
{ {
...@@ -2708,20 +2780,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, ...@@ -2708,20 +2780,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (ret) if (ret)
return ret; return ret;
/*
* Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
* with the software protection bits set
*/
if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
JEDEC_MFR(info) == SNOR_MFR_INTEL ||
JEDEC_MFR(info) == SNOR_MFR_SST ||
info->flags & SPI_NOR_HAS_LOCK) {
write_enable(nor);
write_sr(nor, 0);
spi_nor_wait_till_ready(nor);
}
if (!mtd->name) if (!mtd->name)
mtd->name = dev_name(dev); mtd->name = dev_name(dev);
mtd->priv = nor; mtd->priv = nor;
...@@ -2731,6 +2789,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, ...@@ -2731,6 +2789,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
mtd->size = params.size; mtd->size = params.size;
mtd->_erase = spi_nor_erase; mtd->_erase = spi_nor_erase;
mtd->_read = spi_nor_read; mtd->_read = spi_nor_read;
mtd->_resume = spi_nor_resume;
/* NOR protection support for STmicro/Micron chips and similar */ /* NOR protection support for STmicro/Micron chips and similar */
if (JEDEC_MFR(info) == SNOR_MFR_MICRON || if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
...@@ -2804,8 +2863,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, ...@@ -2804,8 +2863,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
info->flags & SPI_NOR_4B_OPCODES) info->flags & SPI_NOR_4B_OPCODES)
spi_nor_set_4byte_opcodes(nor, info); spi_nor_set_4byte_opcodes(nor, info);
else
set_4byte(nor, info, 1);
} else { } else {
nor->addr_width = 3; nor->addr_width = 3;
} }
...@@ -2822,6 +2879,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, ...@@ -2822,6 +2879,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
return ret; return ret;
} }
/* Send all the required SPI flash commands to initialize device */
nor->info = info;
ret = spi_nor_init(nor);
if (ret)
return ret;
dev_info(dev, "%s (%lld Kbytes)\n", info->name, dev_info(dev, "%s (%lld Kbytes)\n", info->name,
(long long)mtd->size >> 10); (long long)mtd->size >> 10);
......
/* /*
* stm32_quadspi.c * Driver for stm32 quadspi controller
* *
* Copyright (C) 2017, Ludovic Barre * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
* Author(s): Ludovic Barre author <ludovic.barre@st.com>.
* *
* License terms: GNU General Public License (GPL), version 2 * License terms: GPL V2.0.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* This program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -113,6 +126,7 @@ ...@@ -113,6 +126,7 @@
#define STM32_MAX_MMAP_SZ SZ_256M #define STM32_MAX_MMAP_SZ SZ_256M
#define STM32_MAX_NORCHIP 2 #define STM32_MAX_NORCHIP 2
#define STM32_QSPI_FIFO_SZ 32
#define STM32_QSPI_FIFO_TIMEOUT_US 30000 #define STM32_QSPI_FIFO_TIMEOUT_US 30000
#define STM32_QSPI_BUSY_TIMEOUT_US 100000 #define STM32_QSPI_BUSY_TIMEOUT_US 100000
...@@ -124,6 +138,7 @@ struct stm32_qspi_flash { ...@@ -124,6 +138,7 @@ struct stm32_qspi_flash {
u32 presc; u32 presc;
u32 read_mode; u32 read_mode;
bool registered; bool registered;
u32 prefetch_limit;
}; };
struct stm32_qspi { struct stm32_qspi {
...@@ -240,12 +255,12 @@ static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, ...@@ -240,12 +255,12 @@ static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
STM32_QSPI_FIFO_TIMEOUT_US); STM32_QSPI_FIFO_TIMEOUT_US);
if (ret) { if (ret) {
dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr); dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr);
break; return ret;
} }
tx_fifo(buf++, qspi->io_base + QUADSPI_DR); tx_fifo(buf++, qspi->io_base + QUADSPI_DR);
} }
return ret; return 0;
} }
static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, static int stm32_qspi_tx_mm(struct stm32_qspi *qspi,
...@@ -272,6 +287,7 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash, ...@@ -272,6 +287,7 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash,
{ {
struct stm32_qspi *qspi = flash->qspi; struct stm32_qspi *qspi = flash->qspi;
u32 ccr, dcr, cr; u32 ccr, dcr, cr;
u32 last_byte;
int err; int err;
err = stm32_qspi_wait_nobusy(qspi); err = stm32_qspi_wait_nobusy(qspi);
...@@ -314,6 +330,10 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash, ...@@ -314,6 +330,10 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash,
if (err) if (err)
goto abort; goto abort;
writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR); writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR);
} else {
last_byte = cmd->addr + cmd->len;
if (last_byte > flash->prefetch_limit)
goto abort;
} }
return err; return err;
...@@ -322,7 +342,9 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash, ...@@ -322,7 +342,9 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash,
cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT; cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT;
writel_relaxed(cr, qspi->io_base + QUADSPI_CR); writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
if (err)
dev_err(qspi->dev, "%s abort err:%d\n", __func__, err); dev_err(qspi->dev, "%s abort err:%d\n", __func__, err);
return err; return err;
} }
...@@ -550,6 +572,7 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi, ...@@ -550,6 +572,7 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
} }
flash->fsize = FSIZE_VAL(mtd->size); flash->fsize = FSIZE_VAL(mtd->size);
flash->prefetch_limit = mtd->size - STM32_QSPI_FIFO_SZ;
flash->read_mode = CCR_FMODE_MM; flash->read_mode = CCR_FMODE_MM;
if (mtd->size > qspi->mm_size) if (mtd->size > qspi->mm_size)
......
...@@ -231,11 +231,18 @@ enum spi_nor_option_flags { ...@@ -231,11 +231,18 @@ enum spi_nor_option_flags {
SNOR_F_USE_CLSR = BIT(5), SNOR_F_USE_CLSR = BIT(5),
}; };
/**
* struct flash_info - Forward declaration of a structure used internally by
* spi_nor_scan()
*/
struct flash_info;
/** /**
* struct spi_nor - Structure for defining a the SPI NOR layer * struct spi_nor - Structure for defining a the SPI NOR layer
* @mtd: point to a mtd_info structure * @mtd: point to a mtd_info structure
* @lock: the lock for the read/write/erase/lock/unlock operations * @lock: the lock for the read/write/erase/lock/unlock operations
* @dev: point to a spi device, or a spi nor controller device. * @dev: point to a spi device, or a spi nor controller device.
* @info: spi-nor part JDEC MFR id and other info
* @page_size: the page size of the SPI NOR * @page_size: the page size of the SPI NOR
* @addr_width: number of address bytes * @addr_width: number of address bytes
* @erase_opcode: the opcode for erasing a sector * @erase_opcode: the opcode for erasing a sector
...@@ -262,6 +269,7 @@ enum spi_nor_option_flags { ...@@ -262,6 +269,7 @@ enum spi_nor_option_flags {
* @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR * @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
* @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
* @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode
* completely locked * completely locked
* @priv: the private data * @priv: the private data
*/ */
...@@ -269,6 +277,7 @@ struct spi_nor { ...@@ -269,6 +277,7 @@ struct spi_nor {
struct mtd_info mtd; struct mtd_info mtd;
struct mutex lock; struct mutex lock;
struct device *dev; struct device *dev;
const struct flash_info *info;
u32 page_size; u32 page_size;
u8 addr_width; u8 addr_width;
u8 erase_opcode; u8 erase_opcode;
...@@ -296,6 +305,7 @@ struct spi_nor { ...@@ -296,6 +305,7 @@ struct spi_nor {
int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len); int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len); int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len); int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*quad_enable)(struct spi_nor *nor);
void *priv; void *priv;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment