This pull-request contains the following notable changes:

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.
 -----BEGIN PGP SIGNATURE-----
 
 iQI4BAABCAAiBQJZ+eGDGxxjeXJpbGxlLnBpdGNoZW5Ad2VkZXY0dS5mcgAKCRDn
 4OgLHRpJcozND/wK57QO0ZQXU42j6fMk5BM6Aj/YoKJC1jDsX7rRIjUifiydKQ4+
 g5yQ4GzUXGMNA/oGJuy4vANmRIMWlvgBhkA+yCE8GnxM5s+RXhtfHKYsRk6pPdXA
 6obVCo1eY9lZd/clBBnjAreD4bM94fWjZqupwvJDKMnWQhAvA6FC8kRQsyU0ZpvV
 RUH8AMY9Pf9F6rZ+3YxFvqov4xDHdH5BhQ9ZjjmPs1kV56rPS+xoqN3S8gIQR/Zk
 zVMtZ+XBl/n47gEL827GP1ZA42i9+fhWqBJ4PaIWJFPYtvGYdoId0NXTpPyzcMrn
 Ox93PXR+FSZHFill7FIdJ2qam6eBZrhuhXotKIFthe8uWauE9UweTFn0bKlgwXRI
 5bLi9B4VXCYSS3PDEiDg+ohabaJBYfmIingBcr8PK+0vMdRN+A0ovKPkm3Et4dy3
 wcPXuSsVOziwqgYHLvAWjo0M3hN9L9Nm+RTs6izhWunW6vTCzfOABBAT9+a6a7Fp
 v3XNJwV1NxxU9Mcj/LKgIXgQl8r+YAUHHjn6yBbdwh0iWcNRVBqpkaUygXogAJMi
 6qeN0znLc3k4k05Vsv/oAm3h/f+dY6yVslXJTVhjWDzC4z3pywRyAfSzMai+Ai1f
 YFzz19abzJ/FvHMVG8jeDjpn0nk3s14IClK9wFcQfMPS4GUyCyWF6MAGTw==
 =sCfc
 -----END PGP SIGNATURE-----

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.
"
This commit is contained in:
Richard Weinberger 2017-11-02 22:29:24 +01:00
commit 20b2fc79a2
12 changed files with 406 additions and 115 deletions

View File

@ -1,7 +1,9 @@
* Cadence Quad SPI controller
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
physical address and length. The first entry is the address and
length of the controller register set. The second entry is the
@ -14,6 +16,9 @@ Required properties:
Optional properties:
- 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:
Subnodes of the Cadence Quad SPI controller are spi slave nodes with additional

View File

@ -13,6 +13,7 @@ Required properties:
at25df321a
at25df641
at26df081a
mr25h128
mr25h256
mr25h10
mr25h40

View File

@ -1,13 +1,16 @@
* Serial NOR flash controller for MTK MT81xx (and similar)
Required properties:
- compatible: The possible values are:
"mediatek,mt2701-nor"
"mediatek,mt7623-nor"
- compatible: For mt8173, compatible should be "mediatek,mt8173-nor",
and it's the fallback compatible for other Soc.
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"
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
- clocks: the phandle of the clocks needed by the nor controller
- clock-names: the names of the clocks

View File

@ -359,6 +359,7 @@ static const struct spi_device_id m25p_ids[] = {
{"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"},
/* Everspin MRAMs (non-JEDEC) */
{ "mr25h128" }, /* 128 Kib, 40 MHz */
{ "mr25h256" }, /* 256 Kib, 40 MHz */
{ "mr25h10" }, /* 1 Mib, 40 MHz */
{ "mr25h40" }, /* 4 Mib, 40 MHz */

View File

@ -50,7 +50,7 @@ config SPI_ATMEL_QUADSPI
config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller"
depends on OF && (ARM || COMPILE_TEST)
depends on OF && (ARM || ARM64 || COMPILE_TEST)
help
Enable support for the Cadence Quad SPI Flash controller.
@ -90,7 +90,7 @@ config SPI_INTEL_SPI
tristate
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
select SPI_INTEL_SPI
help
@ -106,7 +106,7 @@ config SPI_INTEL_SPI_PCI
will be called intel-spi-pci.
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
select SPI_INTEL_SPI
help

View File

@ -31,6 +31,7 @@
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sched.h>
#include <linux/spi/spi.h>
#include <linux/timer.h>
@ -38,6 +39,9 @@
#define CQSPI_NAME "cadence-qspi"
#define CQSPI_MAX_CHIPSELECT 16
/* Quirks */
#define CQSPI_NEEDS_WR_DELAY BIT(0)
struct cqspi_st;
struct cqspi_flash_pdata {
@ -75,7 +79,9 @@ struct cqspi_st {
bool is_decoded_cs;
u32 fifo_depth;
u32 fifo_width;
bool rclk_en;
u32 trigger_address;
u32 wr_delay;
struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
};
@ -608,6 +614,15 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor,
reinit_completion(&cqspi->transfer_complete);
writel(CQSPI_REG_INDIRECTWR_START_MASK,
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) {
write_bytes = remaining > page_size ? page_size : remaining;
@ -775,7 +790,7 @@ static void cqspi_config_baudrate_div(struct cqspi_st *cqspi)
}
static void cqspi_readdata_capture(struct cqspi_st *cqspi,
const unsigned int bypass,
const bool bypass,
const unsigned int delay)
{
void __iomem *reg_base = cqspi->iobase;
@ -839,7 +854,8 @@ static void cqspi_configure(struct spi_nor *nor)
cqspi->sclk = sclk;
cqspi_config_baudrate_div(cqspi);
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)
@ -1036,6 +1052,8 @@ static int cqspi_of_get_pdata(struct platform_device *pdev)
return -ENXIO;
}
cqspi->rclk_en = of_property_read_bool(np, "cdns,rclk-en");
return 0;
}
@ -1156,6 +1174,7 @@ static int cqspi_probe(struct platform_device *pdev)
struct cqspi_st *cqspi;
struct resource *res;
struct resource *res_ahb;
unsigned long data;
int ret;
int irq;
@ -1206,13 +1225,24 @@ static int cqspi_probe(struct platform_device *pdev)
return -ENXIO;
}
ret = clk_prepare_enable(cqspi->clk);
if (ret) {
dev_err(dev, "Cannot enable QSPI clock.\n");
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);
if (ret) {
dev_err(dev, "Cannot enable QSPI clock.\n");
goto probe_clk_failed;
}
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,
pdev->name, cqspi);
@ -1233,10 +1263,13 @@ static int cqspi_probe(struct platform_device *pdev)
}
return ret;
probe_irq_failed:
cqspi_controller_enable(cqspi, 0);
probe_setup_failed:
cqspi_controller_enable(cqspi, 0);
probe_irq_failed:
clk_disable_unprepare(cqspi->clk);
probe_clk_failed:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
return ret;
}
@ -1253,6 +1286,9 @@ static int cqspi_remove(struct platform_device *pdev)
clk_disable_unprepare(cqspi->clk);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
@ -1284,7 +1320,14 @@ static const struct dev_pm_ops cqspi__dev_pm_ops = {
#endif
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 */ }
};

View File

@ -63,7 +63,10 @@ static void intel_spi_pci_remove(struct pci_dev *pdev)
}
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, 0xa1a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
{ },
};
MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);

View File

@ -67,8 +67,6 @@
#define PR_LIMIT_MASK (0x3fff << PR_LIMIT_SHIFT)
#define PR_RPE BIT(15)
#define PR_BASE_MASK 0x3fff
/* Last PR is GPR0 */
#define PR_NUM (5 + 1)
/* Offsets are from @ispi->sregs */
#define SSFSTS_CTL 0x00
@ -90,20 +88,35 @@
#define OPMENU0 0x08
#define OPMENU1 0x0c
#define OPTYPE_READ_NO_ADDR 0
#define OPTYPE_WRITE_NO_ADDR 1
#define OPTYPE_READ_WITH_ADDR 2
#define OPTYPE_WRITE_WITH_ADDR 3
/* CPU specifics */
#define BYT_PR 0x74
#define BYT_SSFSTS_CTL 0x90
#define BYT_BCR 0xfc
#define BYT_BCR_WPD BIT(0)
#define BYT_FREG_NUM 5
#define BYT_PR_NUM 5
#define LPT_PR 0x74
#define LPT_SSFSTS_CTL 0x90
#define LPT_FREG_NUM 5
#define LPT_PR_NUM 5
#define BXT_PR 0x84
#define BXT_SSFSTS_CTL 0xa0
#define BXT_FREG_NUM 12
#define BXT_PR_NUM 6
#define LVSCC 0xc4
#define UVSCC 0xc8
#define ERASE_OPCODE_SHIFT 8
#define ERASE_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT)
#define ERASE_64K_OPCODE_SHIFT 16
#define ERASE_64K_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT)
#define INTEL_SPI_TIMEOUT 5000 /* ms */
#define INTEL_SPI_FIFO_SZ 64
@ -117,8 +130,11 @@
* @pregs: Start of protection registers
* @sregs: Start of software sequencer registers
* @nregions: Maximum number of regions
* @pr_num: Maximum number of protected range registers
* @writeable: Is the chip writeable
* @swseq: Use SW sequencer in register reads/writes
* @locked: Is SPI setting locked
* @swseq_reg: Use SW sequencer in register reads/writes
* @swseq_erase: Use SW sequencer in erase operation
* @erase_64k: 64k erase supported
* @opcodes: Opcodes which are supported. This are programmed by BIOS
* before it locks down the controller.
@ -132,8 +148,11 @@ struct intel_spi {
void __iomem *pregs;
void __iomem *sregs;
size_t nregions;
size_t pr_num;
bool writeable;
bool swseq;
bool locked;
bool swseq_reg;
bool swseq_erase;
bool erase_64k;
u8 opcodes[8];
u8 preopcodes[2];
@ -167,7 +186,7 @@ static void intel_spi_dump_regs(struct intel_spi *ispi)
for (i = 0; i < ispi->nregions; i++)
dev_dbg(ispi->dev, "FREG(%d)=0x%08x\n", i,
readl(ispi->base + FREG(i)));
for (i = 0; i < PR_NUM; i++)
for (i = 0; i < ispi->pr_num; i++)
dev_dbg(ispi->dev, "PR(%d)=0x%08x\n", i,
readl(ispi->pregs + PR(i)));
@ -181,8 +200,11 @@ static void intel_spi_dump_regs(struct intel_spi *ispi)
if (ispi->info->type == INTEL_SPI_BYT)
dev_dbg(ispi->dev, "BCR=0x%08x\n", readl(ispi->base + BYT_BCR));
dev_dbg(ispi->dev, "LVSCC=0x%08x\n", readl(ispi->base + LVSCC));
dev_dbg(ispi->dev, "UVSCC=0x%08x\n", readl(ispi->base + UVSCC));
dev_dbg(ispi->dev, "Protected regions:\n");
for (i = 0; i < PR_NUM; i++) {
for (i = 0; i < ispi->pr_num; i++) {
u32 base, limit;
value = readl(ispi->pregs + PR(i));
@ -214,7 +236,9 @@ static void intel_spi_dump_regs(struct intel_spi *ispi)
}
dev_dbg(ispi->dev, "Using %cW sequencer for register access\n",
ispi->swseq ? 'S' : 'H');
ispi->swseq_reg ? 'S' : 'H');
dev_dbg(ispi->dev, "Using %cW sequencer for erase operation\n",
ispi->swseq_erase ? 'S' : 'H');
}
/* Reads max INTEL_SPI_FIFO_SZ bytes from the device fifo */
@ -278,7 +302,7 @@ static int intel_spi_wait_sw_busy(struct intel_spi *ispi)
static int intel_spi_init(struct intel_spi *ispi)
{
u32 opmenu0, opmenu1, val;
u32 opmenu0, opmenu1, lvscc, uvscc, val;
int i;
switch (ispi->info->type) {
@ -286,6 +310,8 @@ static int intel_spi_init(struct intel_spi *ispi)
ispi->sregs = ispi->base + BYT_SSFSTS_CTL;
ispi->pregs = ispi->base + BYT_PR;
ispi->nregions = BYT_FREG_NUM;
ispi->pr_num = BYT_PR_NUM;
ispi->swseq_reg = true;
if (writeable) {
/* Disable write protection */
@ -305,12 +331,15 @@ static int intel_spi_init(struct intel_spi *ispi)
ispi->sregs = ispi->base + LPT_SSFSTS_CTL;
ispi->pregs = ispi->base + LPT_PR;
ispi->nregions = LPT_FREG_NUM;
ispi->pr_num = LPT_PR_NUM;
ispi->swseq_reg = true;
break;
case INTEL_SPI_BXT:
ispi->sregs = ispi->base + BXT_SSFSTS_CTL;
ispi->pregs = ispi->base + BXT_PR;
ispi->nregions = BXT_FREG_NUM;
ispi->pr_num = BXT_PR_NUM;
ispi->erase_64k = true;
break;
@ -318,42 +347,64 @@ static int intel_spi_init(struct intel_spi *ispi)
return -EINVAL;
}
/* Disable #SMI generation */
/* Disable #SMI generation from HW sequencer */
val = readl(ispi->base + HSFSTS_CTL);
val &= ~HSFSTS_CTL_FSMIE;
writel(val, ispi->base + HSFSTS_CTL);
/*
* BIOS programs allowed opcodes and then locks down the register.
* So read back what opcodes it decided to support. That's the set
* we are going to support as well.
* Determine whether erase operation should use HW or SW sequencer.
*
* The HW sequencer has a predefined list of opcodes, with only the
* erase opcode being programmable in LVSCC and UVSCC registers.
* If these registers don't contain a valid erase opcode, erase
* cannot be done using HW sequencer.
*/
opmenu0 = readl(ispi->sregs + OPMENU0);
opmenu1 = readl(ispi->sregs + OPMENU1);
lvscc = readl(ispi->base + LVSCC);
uvscc = readl(ispi->base + UVSCC);
if (!(lvscc & ERASE_OPCODE_MASK) || !(uvscc & ERASE_OPCODE_MASK))
ispi->swseq_erase = true;
/* SPI controller on Intel BXT supports 64K erase opcode */
if (ispi->info->type == INTEL_SPI_BXT && !ispi->swseq_erase)
if (!(lvscc & ERASE_64K_OPCODE_MASK) ||
!(uvscc & ERASE_64K_OPCODE_MASK))
ispi->erase_64k = false;
/*
* Some controllers can only do basic operations using hardware
* sequencer. All other operations are supposed to be carried out
* using software sequencer. If we find that BIOS has programmed
* opcodes for the software sequencer we use that over the hardware
* sequencer.
* using software sequencer.
*/
if (opmenu0 && opmenu1) {
for (i = 0; i < ARRAY_SIZE(ispi->opcodes) / 2; i++) {
ispi->opcodes[i] = opmenu0 >> i * 8;
ispi->opcodes[i + 4] = opmenu1 >> i * 8;
}
val = readl(ispi->sregs + PREOP_OPTYPE);
ispi->preopcodes[0] = val;
ispi->preopcodes[1] = val >> 8;
if (ispi->swseq_reg) {
/* Disable #SMI generation from SW sequencer */
val = readl(ispi->sregs + SSFSTS_CTL);
val &= ~SSFSTS_CTL_FSMIE;
writel(val, ispi->sregs + SSFSTS_CTL);
}
ispi->swseq = true;
/* Check controller's lock status */
val = readl(ispi->base + HSFSTS_CTL);
ispi->locked = !!(val & HSFSTS_CTL_FLOCKDN);
if (ispi->locked) {
/*
* BIOS programs allowed opcodes and then locks down the
* register. So read back what opcodes it decided to support.
* That's the set we are going to support as well.
*/
opmenu0 = readl(ispi->sregs + OPMENU0);
opmenu1 = readl(ispi->sregs + OPMENU1);
if (opmenu0 && opmenu1) {
for (i = 0; i < ARRAY_SIZE(ispi->opcodes) / 2; i++) {
ispi->opcodes[i] = opmenu0 >> i * 8;
ispi->opcodes[i + 4] = opmenu1 >> i * 8;
}
val = readl(ispi->sregs + PREOP_OPTYPE);
ispi->preopcodes[0] = val;
ispi->preopcodes[1] = val >> 8;
}
}
intel_spi_dump_regs(ispi);
@ -361,18 +412,28 @@ static int intel_spi_init(struct intel_spi *ispi)
return 0;
}
static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode)
static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode, int optype)
{
int i;
int preop;
for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++)
if (ispi->opcodes[i] == opcode)
return i;
return -EINVAL;
if (ispi->locked) {
for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++)
if (ispi->opcodes[i] == opcode)
return i;
return -EINVAL;
}
/* The lock is off, so just use index 0 */
writel(opcode, ispi->sregs + OPMENU0);
preop = readw(ispi->sregs + PREOP_OPTYPE);
writel(optype << 16 | preop, ispi->sregs + PREOP_OPTYPE);
return 0;
}
static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf,
int len)
static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, int len)
{
u32 val, status;
int ret;
@ -394,6 +455,9 @@ static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf,
return -EINVAL;
}
if (len > INTEL_SPI_FIFO_SZ)
return -EINVAL;
val |= (len - 1) << HSFSTS_CTL_FDBC_SHIFT;
val |= HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
val |= HSFSTS_CTL_FGO;
@ -412,27 +476,39 @@ static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf,
return 0;
}
static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf,
int len)
static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, int len,
int optype)
{
u32 val, status;
u32 val = 0, status;
u16 preop;
int ret;
ret = intel_spi_opcode_index(ispi, opcode);
ret = intel_spi_opcode_index(ispi, opcode, optype);
if (ret < 0)
return ret;
val = (len << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS;
if (len > INTEL_SPI_FIFO_SZ)
return -EINVAL;
/* Only mark 'Data Cycle' bit when there is data to be transferred */
if (len > 0)
val = ((len - 1) << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS;
val |= ret << SSFSTS_CTL_COP_SHIFT;
val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE;
val |= SSFSTS_CTL_SCGO;
preop = readw(ispi->sregs + PREOP_OPTYPE);
if (preop) {
val |= SSFSTS_CTL_ACS;
if (preop >> 8)
val |= SSFSTS_CTL_SPOP;
}
writel(val, ispi->sregs + SSFSTS_CTL);
ret = intel_spi_wait_sw_busy(ispi);
if (ret)
return ret;
status = readl(ispi->base + SSFSTS_CTL);
status = readl(ispi->sregs + SSFSTS_CTL);
if (status & SSFSTS_CTL_FCERR)
return -EIO;
else if (status & SSFSTS_CTL_AEL)
@ -449,10 +525,11 @@ static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
/* Address of the first chip */
writel(0, ispi->base + FADDR);
if (ispi->swseq)
ret = intel_spi_sw_cycle(ispi, opcode, buf, len);
if (ispi->swseq_reg)
ret = intel_spi_sw_cycle(ispi, opcode, len,
OPTYPE_READ_NO_ADDR);
else
ret = intel_spi_hw_cycle(ispi, opcode, buf, len);
ret = intel_spi_hw_cycle(ispi, opcode, len);
if (ret)
return ret;
@ -467,10 +544,15 @@ static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
/*
* This is handled with atomic operation and preop code in Intel
* controller so skip it here now.
* controller so skip it here now. If the controller is not locked,
* program the opcode to the PREOP register for later use.
*/
if (opcode == SPINOR_OP_WREN)
if (opcode == SPINOR_OP_WREN) {
if (!ispi->locked)
writel(opcode, ispi->sregs + PREOP_OPTYPE);
return 0;
}
writel(0, ispi->base + FADDR);
@ -479,9 +561,10 @@ static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
if (ret)
return ret;
if (ispi->swseq)
return intel_spi_sw_cycle(ispi, opcode, buf, len);
return intel_spi_hw_cycle(ispi, opcode, buf, len);
if (ispi->swseq_reg)
return intel_spi_sw_cycle(ispi, opcode, len,
OPTYPE_WRITE_NO_ADDR);
return intel_spi_hw_cycle(ispi, opcode, len);
}
static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len,
@ -561,12 +644,6 @@ static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len,
val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT;
val |= HSFSTS_CTL_FCYCLE_WRITE;
/* Write enable */
if (ispi->preopcodes[1] == SPINOR_OP_WREN)
val |= SSFSTS_CTL_SPOP;
val |= SSFSTS_CTL_ACS;
writel(val, ispi->base + HSFSTS_CTL);
ret = intel_spi_write_block(ispi, write_buf, block_size);
if (ret) {
dev_err(ispi->dev, "failed to write block\n");
@ -574,8 +651,8 @@ static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len,
}
/* Start the write now */
val = readl(ispi->base + HSFSTS_CTL);
writel(val | HSFSTS_CTL_FGO, ispi->base + HSFSTS_CTL);
val |= HSFSTS_CTL_FGO;
writel(val, ispi->base + HSFSTS_CTL);
ret = intel_spi_wait_hw_busy(ispi);
if (ret) {
@ -620,6 +697,22 @@ static int intel_spi_erase(struct spi_nor *nor, loff_t offs)
erase_size = SZ_4K;
}
if (ispi->swseq_erase) {
while (len > 0) {
writel(offs, ispi->base + FADDR);
ret = intel_spi_sw_cycle(ispi, nor->erase_opcode,
0, OPTYPE_WRITE_WITH_ADDR);
if (ret)
return ret;
offs += erase_size;
len -= erase_size;
}
return 0;
}
while (len > 0) {
writel(offs, ispi->base + FADDR);
@ -652,7 +745,7 @@ static bool intel_spi_is_protected(const struct intel_spi *ispi,
{
int i;
for (i = 0; i < PR_NUM; i++) {
for (i = 0; i < ispi->pr_num; i++) {
u32 pr_base, pr_limit, pr_value;
pr_value = readl(ispi->pregs + PR(i));

View File

@ -404,6 +404,29 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
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,
struct device_node *flash_node)
{
@ -468,15 +491,11 @@ static int mtk_nor_drv_probe(struct platform_device *pdev)
return PTR_ERR(mt8173_nor->nor_clk);
mt8173_nor->dev = &pdev->dev;
ret = clk_prepare_enable(mt8173_nor->spi_clk);
ret = mt8173_nor_enable_clk(mt8173_nor);
if (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 */
flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
if (!flash_np) {
@ -487,10 +506,9 @@ static int mtk_nor_drv_probe(struct platform_device *pdev)
ret = mtk_nor_init(mt8173_nor, flash_np);
nor_free:
if (ret) {
clk_disable_unprepare(mt8173_nor->spi_clk);
clk_disable_unprepare(mt8173_nor->nor_clk);
}
if (ret)
mt8173_nor_disable_clk(mt8173_nor);
return ret;
}
@ -498,11 +516,38 @@ static int mtk_nor_drv_remove(struct platform_device *pdev)
{
struct mt8173_nor *mt8173_nor = platform_get_drvdata(pdev);
clk_disable_unprepare(mt8173_nor->spi_clk);
clk_disable_unprepare(mt8173_nor->nor_clk);
mt8173_nor_disable_clk(mt8173_nor);
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[] = {
{ .compatible = "mediatek,mt8173-nor"},
{ /* sentinel */ }
@ -514,6 +559,7 @@ static struct platform_driver mtk_nor_driver = {
.remove = mtk_nor_drv_remove,
.driver = {
.name = "mtk-nor",
.pm = MTK_NOR_DEV_PM_OPS,
.of_match_table = mtk_nor_of_ids,
},
};

View File

@ -89,6 +89,8 @@ struct flash_info {
#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 USE_CLSR BIT(14) /* use CLSR command */
int (*quad_enable)(struct spi_nor *nor);
};
#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)
return ret;
}
static int macronix_quad_enable(struct spi_nor *nor);
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
.id = { \
@ -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) },
/* 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) },
{ "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) },
@ -982,6 +987,11 @@ static const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
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,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
@ -997,6 +1007,12 @@ static const struct flash_info spi_nor_ids[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
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 */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
@ -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) },
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
{ "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) },
{ "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) },
@ -1137,6 +1153,11 @@ static const struct flash_info spi_nor_ids[] = {
{ "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) },
{ "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, 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) },
{ "w25q20cl", INFO(0xef4012, 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,
/* Check the SFDP header version. */
if (le32_to_cpu(header.signature) != SFDP_SIGNATURE ||
header.major != SFDP_JESD216_MAJOR ||
header.minor < SFDP_JESD216_MINOR)
header.major != SFDP_JESD216_MAJOR)
return -EINVAL;
/*
@ -2427,6 +2447,15 @@ static int spi_nor_init_params(struct spi_nor *nor,
params->quad_enable = spansion_quad_enable;
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. */
@ -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_io = (spi_nor_get_protocol_width(nor->read_proto) == 4 ||
spi_nor_get_protocol_width(nor->write_proto) == 4);
if (enable_quad_io && params->quad_enable) {
err = params->quad_enable(nor);
if (enable_quad_io && params->quad_enable)
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) {
dev_err(nor->dev, "quad mode not supported\n");
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;
}
/* 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,
const struct spi_nor_hwcaps *hwcaps)
{
@ -2708,20 +2780,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (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)
mtd->name = dev_name(dev);
mtd->priv = nor;
@ -2731,6 +2789,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
mtd->size = params.size;
mtd->_erase = spi_nor_erase;
mtd->_read = spi_nor_read;
mtd->_resume = spi_nor_resume;
/* NOR protection support for STmicro/Micron chips and similar */
if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
@ -2804,8 +2863,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
info->flags & SPI_NOR_4B_OPCODES)
spi_nor_set_4byte_opcodes(nor, info);
else
set_4byte(nor, info, 1);
} else {
nor->addr_width = 3;
}
@ -2822,6 +2879,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
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,
(long long)mtd->size >> 10);

View File

@ -1,9 +1,22 @@
/*
* 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/errno.h>
@ -113,6 +126,7 @@
#define STM32_MAX_MMAP_SZ SZ_256M
#define STM32_MAX_NORCHIP 2
#define STM32_QSPI_FIFO_SZ 32
#define STM32_QSPI_FIFO_TIMEOUT_US 30000
#define STM32_QSPI_BUSY_TIMEOUT_US 100000
@ -124,6 +138,7 @@ struct stm32_qspi_flash {
u32 presc;
u32 read_mode;
bool registered;
u32 prefetch_limit;
};
struct stm32_qspi {
@ -240,12 +255,12 @@ static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
STM32_QSPI_FIFO_TIMEOUT_US);
if (ret) {
dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr);
break;
return ret;
}
tx_fifo(buf++, qspi->io_base + QUADSPI_DR);
}
return ret;
return 0;
}
static int stm32_qspi_tx_mm(struct stm32_qspi *qspi,
@ -272,6 +287,7 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash,
{
struct stm32_qspi *qspi = flash->qspi;
u32 ccr, dcr, cr;
u32 last_byte;
int err;
err = stm32_qspi_wait_nobusy(qspi);
@ -314,6 +330,10 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash,
if (err)
goto abort;
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;
@ -322,7 +342,9 @@ abort:
cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT;
writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
dev_err(qspi->dev, "%s abort err:%d\n", __func__, err);
if (err)
dev_err(qspi->dev, "%s abort err:%d\n", __func__, err);
return err;
}
@ -550,6 +572,7 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
}
flash->fsize = FSIZE_VAL(mtd->size);
flash->prefetch_limit = mtd->size - STM32_QSPI_FIFO_SZ;
flash->read_mode = CCR_FMODE_MM;
if (mtd->size > qspi->mm_size)

View File

@ -231,11 +231,18 @@ enum spi_nor_option_flags {
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
* @mtd: point to a mtd_info structure
* @lock: the lock for the read/write/erase/lock/unlock operations
* @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
* @addr_width: number of address bytes
* @erase_opcode: the opcode for erasing a sector
@ -262,6 +269,7 @@ enum spi_nor_option_flags {
* @flash_lock: [FLASH-SPECIFIC] lock 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
* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode
* completely locked
* @priv: the private data
*/
@ -269,6 +277,7 @@ struct spi_nor {
struct mtd_info mtd;
struct mutex lock;
struct device *dev;
const struct flash_info *info;
u32 page_size;
u8 addr_width;
u8 erase_opcode;
@ -296,6 +305,7 @@ struct spi_nor {
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_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*quad_enable)(struct spi_nor *nor);
void *priv;
};