summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDong Aisheng <aisheng.dong@nxp.com>2021-11-30 15:01:16 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2021-11-30 15:01:16 +0800
commite7cbe0af8dd6e9dfe28f46e566f6db3065feddb0 (patch)
tree45b935b95c3de4f2747b7b07282978d5c112ed2f
parent30c78dc3b9a703b075901398d9e4a5ace5707b2c (diff)
parent4083c5bc6e6860a159503e766abdfe09c18caaab (diff)
Merge branch 'spi/next' into next
* spi/next: (21 commits) LF-2090: spi: spi-fsl-qspi: fix dereference null return value issue LF-20-3 mtd: spi-nor: Use 1 bit mode of spansion(s25fs512s) flash dt-bindings: spi: spi-fsl-qspi: Add bindings of ls1088a and ls1012a LF-1723: spi: lpspi: run transfer speed_hz sanity check LF-1723: spi: lpspi: run perclk_rate sanity check ...
-rw-r--r--Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml5
-rw-r--r--drivers/mtd/spi-nor/macronix.c199
-rw-r--r--drivers/mtd/spi-nor/spansion.c2
-rw-r--r--drivers/spi/spi-fsl-lpspi.c15
-rw-r--r--drivers/spi/spi-fsl-qspi.c4
-rw-r--r--drivers/spi/spi-imx.c97
-rw-r--r--drivers/spi/spi-nxp-fspi.c199
7 files changed, 465 insertions, 56 deletions
diff --git a/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml b/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml
index e58644558412..ed6fb7367525 100644
--- a/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml
+++ b/Documentation/devicetree/bindings/spi/fsl,spi-fsl-qspi.yaml
@@ -25,9 +25,14 @@ properties:
- items:
- enum:
- fsl,ls1043a-qspi
+ - fsl,ls1012a-qspi
- const: fsl,ls1021a-qspi
- items:
- enum:
+ - fsl,ls1088a-qspi
+ - const: fsl,ls2080a-qspi
+ - items:
+ - enum:
- fsl,imx8mq-qspi
- const: fsl,imx7d-qspi
diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c
index 27498ed0cc0d..2c6ed978c69b 100644
--- a/drivers/mtd/spi-nor/macronix.c
+++ b/drivers/mtd/spi-nor/macronix.c
@@ -8,6 +8,13 @@
#include "core.h"
+#define SPINOR_OP_RD_CR2 0x71 /* Read configuration register 2 */
+#define SPINOR_OP_WR_CR2 0x72 /* Write configuration register 2 */
+#define SPINOR_REG_MXIC_CR2_MODE 0x00000000 /* For setting octal DTR mode */
+#define SPINOR_REG_MXIC_OPI_DTR_EN 0x2 /* Enable Octal DTR */
+#define SPINOR_REG_MXIC_SPI_EN 0x0 /* Enable SPI */
+#define SPINOR_OP_OPI_DTR_RD 0xEE /* OPI DTR first read opcode */
+
static int
mx25l25635_post_bfpt_fixups(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
@@ -32,6 +39,98 @@ static struct spi_nor_fixups mx25l25635_fixups = {
.post_bfpt = mx25l25635_post_bfpt_fixups,
};
+/**
+ * spi_nor_macronix_octal_dtr_enable() - Enable octal DTR on Macronix flashes.
+ * @nor: pointer to a 'struct spi_nor'
+ * @enable: whether to enable Octal DTR or switch back to SPI
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor, bool enable)
+{
+ struct spi_mem_op op;
+ u8 *buf = nor->bouncebuf, i;
+ int ret;
+
+ /* Set/unset the octal and DTR enable bits. */
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ if (enable) {
+ buf[0] = SPINOR_REG_MXIC_OPI_DTR_EN;
+ } else {
+ /*
+ * The register is 1-byte wide, but 1-byte transactions are not
+ * allowed in 8D-8D-8D mode. Since there is no register at the
+ * next location, just initialize the value to 0 and let the
+ * transaction go on.
+ */
+ buf[0] = SPINOR_REG_MXIC_SPI_EN;
+ buf[1] = 0x0;
+ }
+
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1),
+ SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_MODE, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(enable ? 1 : 2, buf, 1));
+
+ if (!enable)
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ /* Read flash ID to make sure the switch was successful. */
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 1),
+ SPI_MEM_OP_ADDR(enable ? 4 : 0, 0, 1),
+ SPI_MEM_OP_DUMMY(enable ? 4 : 0, 1),
+ SPI_MEM_OP_DATA_IN(SPI_NOR_MAX_ID_LEN, buf, 1));
+
+ if (enable)
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ if (enable) {
+ for (i = 0; i < nor->info->id_len; i++)
+ if (buf[i * 2] != nor->info->id[i])
+ return -EINVAL;
+ } else {
+ if (memcmp(buf, nor->info->id, nor->info->id_len))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void octaflash_default_init(struct spi_nor *nor)
+{
+ nor->params->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable;
+}
+
+static struct spi_nor_fixups octaflash_fixups = {
+ .default_init = octaflash_default_init,
+};
+
+static void mx25uw51345g_post_sfdp_fixup(struct spi_nor *nor)
+{
+ nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
+ spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR],
+ 0, 20, SPINOR_OP_OPI_DTR_RD,
+ SNOR_PROTO_8_8_8_DTR);
+}
+
+static struct spi_nor_fixups mx25uw51345g_fixups = {
+ .default_init = octaflash_default_init,
+ .post_sfdp = mx25uw51345g_post_sfdp_fixup,
+};
+
static const struct flash_info macronix_parts[] = {
/* Macronix */
{ "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) },
@@ -87,6 +186,106 @@ static const struct flash_info macronix_parts[] = {
{ "mx66u2g45g", INFO(0xc2253c, 0, 64 * 1024, 4096,
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+ { "mx66lm2g45g", INFO(0xc2853c, 0, 64 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx66lm1g45g", INFO(0xc2853b, 0, 32 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx66lw1g45g", INFO(0xc2863b, 0, 32 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25lm51245g", INFO(0xc2853a, 0, 16 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25lw51245g", INFO(0xc2863a, 0, 16 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25lm25645g", INFO(0xc28539, 0, 8 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25lw25645g", INFO(0xc28639, 0, 8 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx66um2g45g", INFO(0xc2803c, 0, 64 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx66uw2g345g", INFO(0xc2843c, 0, 64 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx66uw2g345gx0", INFO(0xc2943c, 0, 64 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx66um1g45g", INFO(0xc2803b, 0, 32 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx66um1g45g40", INFO(0xc2808b, 0, 32 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx66uw1g45g", INFO(0xc2813b, 0, 32 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25um51245g", INFO(0xc2803a, 0, 16 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25uw51245g", INFO(0xc2813a, 0, 16 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25uw51345g", INFO(0xc2843a, 0, 16 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &mx25uw51345g_fixups },
+ { "mx25um25645g", INFO(0xc28039, 0, 8 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25uw25645g", INFO(0xc28139, 0, 8 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25um25345g", INFO(0xc28339, 0, 8 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25uw25345g", INFO(0xc28439, 0, 8 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25uw12845g", INFO(0xc28138, 0, 4 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25uw12a45g", INFO(0xc28938, 0, 4 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25uw12345g", INFO(0xc28438, 0, 4 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25uw6445g", INFO(0xc28137, 0, 2 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
+ { "mx25uw6345g", INFO(0xc28437, 0, 2 * 1024, 4096,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ |
+ SPI_NOR_OCTAL_DTR_PP | SPI_NOR_4B_OPCODES)
+ .fixups = &octaflash_fixups },
};
static void macronix_default_init(struct spi_nor *nor)
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index ee82dcd75310..6b8b2be93999 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -227,7 +227,7 @@ static const struct flash_info spansion_parts[] = {
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
USE_CLSR) },
{ "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256,
- SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR)
+ SPI_NOR_4B_OPCODES | USE_CLSR)
.fixups = &s25fs_s_fixups, },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 5d98611dd999..25b1e1d92fc8 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -301,6 +301,16 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
u8 prescale;
perclk_rate = clk_get_rate(fsl_lpspi->clk_per);
+ if (!perclk_rate) {
+ dev_err(fsl_lpspi->dev, "per-clk rate was not set\n");
+ return -EINVAL;
+ }
+
+ if (!config.speed_hz) {
+ dev_err(fsl_lpspi->dev,
+ "error: the transmission speed provided is 0!\n");
+ return -EINVAL;
+ }
if (config.speed_hz > perclk_rate / 2) {
dev_err(fsl_lpspi->dev,
@@ -906,9 +916,12 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller);
if (ret == -EPROBE_DEFER)
goto out_pm_get;
-
if (ret < 0)
dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret);
+ else
+ /* disable LPSPI module IRQ when enable DMA mode successfully,
+ * to prevent the unexpected LPSPI module IRQ events*/
+ disable_irq(irq);
ret = devm_spi_register_controller(&pdev->dev, controller);
if (ret < 0) {
diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
index 9851551ebbe0..68434d3f309e 100644
--- a/drivers/spi/spi-fsl-qspi.c
+++ b/drivers/spi/spi-fsl-qspi.c
@@ -876,6 +876,10 @@ static int fsl_qspi_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"QuadSPI-memory");
+ if (!res) {
+ ret = -ENOMEM;
+ goto err_put_ctrl;
+ }
q->memmap_phy = res->start;
/* Since there are 4 cs, map size required is 4 times ahb_buf_size */
q->ahb_addr = devm_ioremap(dev, q->memmap_phy,
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index b2dd0a4d2446..e41d1c4d8591 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -33,6 +33,7 @@ module_param(use_dma, bool, 0644);
MODULE_PARM_DESC(use_dma, "Enable usage of DMA when available (default)");
#define MXC_RPM_TIMEOUT 2000 /* 2000ms */
+#define MXC_SPI_DEFAULT_SPEED 500000 /* 500KHz */
#define MXC_CSPIRXDATA 0x00
#define MXC_CSPITXDATA 0x04
@@ -390,7 +391,12 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
{
- u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA));
+ u32 val = readl(spi_imx->base + MXC_CSPIRXDATA);
+
+ if (spi_imx->bits_per_word <= 8)
+ val = be32_to_cpu(val);
+ else if (spi_imx->bits_per_word <= 16)
+ val = (val << 16) | (val >> 16);
if (spi_imx->rx_buf) {
int n_bytes = spi_imx->slave_burst % sizeof(val);
@@ -419,7 +425,11 @@ static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
if (spi_imx->tx_buf) {
memcpy(((u8 *)&val) + sizeof(val) - n_bytes,
spi_imx->tx_buf, n_bytes);
- val = cpu_to_be32(val);
+ if (spi_imx->bits_per_word <= 8)
+ val = cpu_to_be32(val);
+ else if (spi_imx->bits_per_word <= 16)
+ val = (val << 16) | (val >> 16);
+
spi_imx->tx_buf += n_bytes;
}
@@ -487,9 +497,15 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
{
u32 reg;
- reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
- reg |= MX51_ECSPI_CTRL_XCH;
- writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
+ if (spi_imx->usedma) {
+ reg = readl(spi_imx->base + MX51_ECSPI_DMA);
+ reg |= MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN;
+ writel(reg, spi_imx->base + MX51_ECSPI_DMA);
+ } else {
+ reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
+ reg |= MX51_ECSPI_CTRL_XCH;
+ writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
+ }
}
static void mx51_disable_dma(struct spi_imx_data *spi_imx)
@@ -549,7 +565,7 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
* is not functional for imx53 Soc, config SPI burst completed when
* BURST_LENGTH + 1 bits are received
*/
- if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+ if (spi_imx->slave_mode)
cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
else
cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
@@ -614,7 +630,7 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
/* Clear BL field and set the right value */
ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
- if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+ if (spi_imx->slave_mode)
ctrl |= (spi_imx->slave_burst * 8 - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
else
@@ -624,8 +640,11 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
/* set clock speed */
ctrl &= ~(0xf << MX51_ECSPI_CTRL_POSTDIV_OFFSET |
0xf << MX51_ECSPI_CTRL_PREDIV_OFFSET);
- ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk);
- spi_imx->spi_bus_clk = clk;
+
+ if (!spi_imx->slave_mode) {
+ ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk);
+ spi_imx->spi_bus_clk = clk;
+ }
/*
* ERR009165: work in XHC mode instead of SMC as PIO on the chips
@@ -654,7 +673,6 @@ static void mx51_setup_wml(struct spi_imx_data *spi_imx)
writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |
MX51_ECSPI_DMA_TX_WML(tx_wml) |
MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
- MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
}
@@ -734,9 +752,11 @@ static int mx31_prepare_transfer(struct spi_imx_data *spi_imx,
unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
unsigned int clk;
- reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
- MX31_CSPICTRL_DR_SHIFT;
- spi_imx->spi_bus_clk = clk;
+ if (!spi_imx->slave_mode) {
+ reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
+ MX31_CSPICTRL_DR_SHIFT;
+ spi_imx->spi_bus_clk = clk;
+ }
if (is_imx35_cspi(spi_imx)) {
reg |= (spi_imx->bits_per_word - 1) << MX35_CSPICTRL_BL_SHIFT;
@@ -839,9 +859,11 @@ static int mx21_prepare_transfer(struct spi_imx_data *spi_imx,
unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
unsigned int clk;
- reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, spi_imx->spi_bus_clk, max, &clk)
- << MX21_CSPICTRL_DR_SHIFT;
- spi_imx->spi_bus_clk = clk;
+ if (!spi_imx->slave_mode) {
+ reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, spi_imx->spi_bus_clk, max, &clk)
+ << MX21_CSPICTRL_DR_SHIFT;
+ spi_imx->spi_bus_clk = clk;
+ }
reg |= spi_imx->bits_per_word - 1;
@@ -913,9 +935,11 @@ static int mx1_prepare_transfer(struct spi_imx_data *spi_imx,
unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
unsigned int clk;
- reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
- MX1_CSPICTRL_DR_SHIFT;
- spi_imx->spi_bus_clk = clk;
+ if (!spi_imx->slave_mode) {
+ reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
+ MX1_CSPICTRL_DR_SHIFT;
+ spi_imx->spi_bus_clk = clk;
+ }
reg |= spi_imx->bits_per_word - 1;
@@ -1178,6 +1202,8 @@ static int spi_imx_dma_configure(struct spi_master *master)
tx.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA;
tx.dst_addr_width = buswidth;
tx.dst_maxburst = spi_imx->wml;
+ tx.peripheral_config = NULL;
+ tx.peripheral_size = 0;
ret = dmaengine_slave_config(master->dma_tx, &tx);
if (ret) {
dev_err(spi_imx->dev, "TX dma configuration failed with %d\n", ret);
@@ -1188,6 +1214,8 @@ static int spi_imx_dma_configure(struct spi_master *master)
rx.src_addr = spi_imx->base_phys + MXC_CSPIRXDATA;
rx.src_addr_width = buswidth;
rx.src_maxburst = spi_imx->wml;
+ rx.peripheral_config = NULL;
+ rx.peripheral_size = 0;
ret = dmaengine_slave_config(master->dma_rx, &rx);
if (ret) {
dev_err(spi_imx->dev, "RX dma configuration failed with %d\n", ret);
@@ -1205,15 +1233,17 @@ static int spi_imx_setupxfer(struct spi_device *spi,
if (!t)
return 0;
- if (!t->speed_hz) {
- if (!spi->max_speed_hz) {
- dev_err(&spi->dev, "no speed_hz provided!\n");
- return -EINVAL;
- }
- dev_dbg(&spi->dev, "using spi->max_speed_hz!\n");
- spi_imx->spi_bus_clk = spi->max_speed_hz;
- } else
- spi_imx->spi_bus_clk = t->speed_hz;
+ if (!spi_imx->slave_mode) {
+ if (!t->speed_hz) {
+ if (!spi->max_speed_hz) {
+ dev_err(&spi->dev, "no speed_hz provided!\n");
+ return -EINVAL;
+ }
+ dev_dbg(&spi->dev, "using spi->max_speed_hz!\n");
+ spi_imx->spi_bus_clk = spi->max_speed_hz;
+ } else
+ spi_imx->spi_bus_clk = t->speed_hz;
+ }
spi_imx->bits_per_word = t->bits_per_word;
@@ -1251,7 +1281,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
else
spi_imx->usedma = false;
- if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {
+ if (spi_imx->slave_mode) {
spi_imx->rx = mx53_ecspi_rx_slave;
spi_imx->tx = mx53_ecspi_tx_slave;
spi_imx->slave_burst = t->len;
@@ -1411,6 +1441,8 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
reinit_completion(&spi_imx->dma_tx_completion);
dma_async_issue_pending(master->dma_tx);
+ spi_imx->devtype_data->trigger(spi_imx);
+
transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
/* Wait SDMA to finish the data transfer.*/
@@ -1477,7 +1509,7 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi,
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
int ret = transfer->len;
- if (is_imx53_ecspi(spi_imx) &&
+ if ((is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx)) &&
transfer->len > MX53_MAX_TRANSFER_BYTES) {
dev_err(&spi->dev, "Transaction too big, max size is %d bytes\n",
MX53_MAX_TRANSFER_BYTES);
@@ -1520,8 +1552,6 @@ static int spi_imx_transfer(struct spi_device *spi,
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
- transfer->effective_speed_hz = spi_imx->spi_bus_clk;
-
/* flush rxfifo before transfer */
while (spi_imx->devtype_data->rx_available(spi_imx))
readl(spi_imx->base + MXC_CSPIRXDATA);
@@ -1529,6 +1559,8 @@ static int spi_imx_transfer(struct spi_device *spi,
if (spi_imx->slave_mode)
return spi_imx_pio_transfer_slave(spi, transfer);
+ transfer->effective_speed_hz = spi_imx->spi_bus_clk;
+
if (spi_imx->usedma)
return spi_imx_dma_transfer(spi_imx, transfer);
@@ -1628,6 +1660,7 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->bitbang.master = master;
spi_imx->dev = &pdev->dev;
spi_imx->slave_mode = slave_mode;
+ spi_imx->spi_bus_clk = MXC_SPI_DEFAULT_SPEED;
spi_imx->devtype_data = devtype_data;
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 2b0301fc971c..76032c7258e9 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -49,6 +49,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pm_qos.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
@@ -58,12 +59,17 @@
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
+#include <linux/pm_runtime.h>
+
+/* runtime pm timeout */
+#define FSPI_RPM_TIMEOUT 50 /* 50ms */
+
/*
* The driver only uses one single LUT entry, that is updated on
* each call of exec_op(). Index 0 is preset at boot with a basic
- * read operation, so let's use the last entry (31).
+ * read operation, so let's use the last entry (15).
*/
-#define SEQID_LUT 31
+#define SEQID_LUT 15
/* Registers used by the driver */
#define FSPI_MCR0 0x00
@@ -321,6 +327,9 @@
/* Access flash memory using IP bus only */
#define FSPI_QUIRK_USE_IP_ONLY BIT(0)
+/* Disable Octal DTR */
+#define NXP_FSPI_QUIRK_DISABLE_DTR BIT(1)
+
struct nxp_fspi_devtype_data {
unsigned int rxfifo;
unsigned int txfifo;
@@ -333,7 +342,7 @@ static struct nxp_fspi_devtype_data lx2160a_data = {
.rxfifo = SZ_512, /* (64 * 64 bits) */
.txfifo = SZ_1K, /* (128 * 64 bits) */
.ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
- .quirks = 0,
+ .quirks = NXP_FSPI_QUIRK_DISABLE_DTR,
.little_endian = true, /* little-endian */
};
@@ -375,6 +384,9 @@ struct nxp_fspi {
struct mutex lock;
struct pm_qos_request pm_qos_req;
int selected;
+#define FSPI_INITILIZED (1 << 0)
+#define FSPI_RXCLKSRC_3 (1 << 1)
+ int flags;
};
static inline int needs_ip_only(struct nxp_fspi *f)
@@ -382,6 +394,11 @@ static inline int needs_ip_only(struct nxp_fspi *f)
return f->devtype_data->quirks & FSPI_QUIRK_USE_IP_ONLY;
}
+static inline int nxp_fspi_disable_dtr(struct nxp_fspi *f)
+{
+ return f->devtype_data->quirks & NXP_FSPI_QUIRK_DISABLE_DTR;
+}
+
/*
* R/W functions for big- or little-endian registers:
* The FSPI controller's endianness is independent of
@@ -483,6 +500,10 @@ static bool nxp_fspi_supports_op(struct spi_mem *mem,
op->data.nbytes > f->devtype_data->txfifo)
return false;
+ if (!nxp_fspi_disable_dtr(f) &&
+ op->cmd.dtr && op->addr.dtr && op->dummy.dtr && op->data.dtr)
+ return spi_mem_dtr_supports_op(mem, op);
+
return spi_mem_default_supports_op(mem, op);
}
@@ -531,12 +552,22 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
int lutidx = 1, i;
/* cmd */
- lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth),
- op->cmd.opcode);
+ if (op->cmd.dtr) {
+ lutval[0] |= LUT_DEF(0, LUT_CMD_DDR, LUT_PAD(op->cmd.buswidth),
+ op->cmd.opcode >> 8);
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_CMD_DDR,
+ LUT_PAD(op->cmd.buswidth),
+ op->cmd.opcode & 0x00ff);
+ lutidx++;
+ } else {
+ lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth),
+ op->cmd.opcode);
+ }
/* addr bytes */
if (op->addr.nbytes) {
- lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_ADDR,
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, op->addr.dtr ?
+ LUT_ADDR_DDR : LUT_ADDR,
LUT_PAD(op->addr.buswidth),
op->addr.nbytes * 8);
lutidx++;
@@ -544,7 +575,8 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
/* dummy bytes, if needed */
if (op->dummy.nbytes) {
- lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_DUMMY,
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, op->dummy.dtr ?
+ LUT_DUMMY_DDR : LUT_DUMMY,
/*
* Due to FlexSPI controller limitation number of PAD for dummy
* buswidth needs to be programmed as equal to data buswidth.
@@ -559,7 +591,8 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
if (op->data.nbytes) {
lutval[lutidx / 2] |= LUT_DEF(lutidx,
op->data.dir == SPI_MEM_DATA_IN ?
- LUT_NXP_READ : LUT_NXP_WRITE,
+ (op->data.dtr ? LUT_READ_DDR : LUT_NXP_READ) :
+ (op->data.dtr ? LUT_WRITE_DDR : LUT_NXP_WRITE),
LUT_PAD(op->data.buswidth),
0);
lutidx++;
@@ -859,6 +892,50 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op)
return err;
}
+/*
+ * Sample Clock source selection for Flash Reading
+ * Four modes defined by fspi:
+ * mode 0: Dummy Read strobe generated by FlexSPI Controller
+ * and loopback internally
+ * mode 1: Dummy Read strobe generated by FlexSPI Controller
+ * and loopback from DQS pad
+ * mode 2: Reserved
+ * mode 3: Flash provided Read strobe and input from DQS pad
+ *
+ * fspi default use mode 0 after reset
+ */
+static void nxp_fspi_select_rx_sample_clk_source(struct nxp_fspi *f,
+ const struct spi_mem_op *op)
+{
+ u32 reg;
+
+ /*
+ * For 8-8-8-DTR mode, need to use mode 3 (Flash provided Read
+ * strobe and input from DQS pad), otherwise read operaton may
+ * meet issue.
+ * This mode require flash device connect the DQS pad on board.
+ * For other modes, still use mode 0, keep align with before.
+ * spi_nor_suspend will disable 8-8-8-DTR mode, also need to
+ * change the mode back to mode 0.
+ */
+ if (!(f->flags & FSPI_RXCLKSRC_3) &&
+ op->cmd.dtr && op->addr.dtr &&
+ op->dummy.dtr && op->data.dtr) {
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ reg |= FSPI_MCR0_RXCLKSRC(3);
+ fspi_writel(f, reg, f->iobase + FSPI_MCR0);
+ f->flags |= FSPI_RXCLKSRC_3;
+ } else if ((f->flags & FSPI_RXCLKSRC_3) &&
+ !op->cmd.dtr && !op->addr.dtr &&
+ !op->dummy.dtr && !op->data.dtr) {
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ reg &= ~FSPI_MCR0_RXCLKSRC(3); /* select mode 0 */
+ fspi_writel(f, reg, f->iobase + FSPI_MCR0);
+ f->flags &= ~FSPI_RXCLKSRC_3;
+ }
+
+}
+
static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master);
@@ -866,6 +943,12 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
mutex_lock(&f->lock);
+ err = pm_runtime_get_sync(f->dev);
+ if (err < 0) {
+ dev_err(f->dev, "Failed to enable clock %d\n", __LINE__);
+ goto err_mutex;
+ }
+
/* Wait for controller being ready. */
err = fspi_readl_poll_tout(f, f->iobase + FSPI_STS0,
FSPI_STS0_ARB_IDLE, 1, POLL_TOUT, true);
@@ -873,6 +956,8 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
nxp_fspi_select_mem(f, mem->spi);
+ nxp_fspi_select_rx_sample_clk_source(f, op);
+
nxp_fspi_prepare_lut(f, op);
/*
* If we have large chunks of data, we read them through the AHB bus by
@@ -894,8 +979,14 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
/* Invalidate the data in the AHB buffer. */
nxp_fspi_invalid(f);
+ pm_runtime_mark_last_busy(f->dev);
+ pm_runtime_put_autosuspend(f->dev);
+
mutex_unlock(&f->lock);
+ return err;
+err_mutex:
+ mutex_unlock(&f->lock);
return err;
}
@@ -1141,12 +1232,17 @@ static int nxp_fspi_probe(struct platform_device *pdev)
ret = PTR_ERR(f->clk);
goto err_put_ctrl;
}
+ }
- ret = nxp_fspi_clk_prep_enable(f);
- if (ret) {
- dev_err(dev, "can not enable the clock\n");
- goto err_put_ctrl;
- }
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, FSPI_RPM_TIMEOUT);
+ pm_runtime_use_autosuspend(dev);
+
+ /* enable clock */
+ ret = pm_runtime_get_sync(f->dev);
+ if (ret < 0) {
+ dev_err(f->dev, "Failed to enable clock %d\n", __LINE__);
+ goto err_put_ctrl;
}
/* Clear potential interrupts */
@@ -1180,13 +1276,19 @@ static int nxp_fspi_probe(struct platform_device *pdev)
if (ret)
goto err_destroy_mutex;
+ pm_runtime_mark_last_busy(f->dev);
+ pm_runtime_put_autosuspend(f->dev);
+
+ /* indicate the controller has been initialized */
+ f->flags |= FSPI_INITILIZED;
+
return 0;
err_destroy_mutex:
mutex_destroy(&f->lock);
err_disable_clk:
- nxp_fspi_clk_disable_unprep(f);
+ pm_runtime_disable(dev);
err_put_ctrl:
spi_controller_put(ctlr);
@@ -1212,20 +1314,78 @@ static int nxp_fspi_remove(struct platform_device *pdev)
return 0;
}
-static int nxp_fspi_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int nxp_fspi_initialized(struct nxp_fspi *f)
+{
+ return f->flags & FSPI_INITILIZED;
+}
+
+static int nxp_fspi_need_reinit(struct nxp_fspi *f)
{
+ /* we always use the controller in combination mode, so we check this */
+ /* register bit to determine if the controller once lost power, such as */
+ /* suspend/resume, and need to be re-init */
+
+ return !(readl(f->iobase + FSPI_MCR0) & FSPI_MCR0_OCTCOMB_EN);
+}
+
+
+static int nxp_fspi_runtime_suspend(struct device *dev)
+{
+ struct nxp_fspi *f = dev_get_drvdata(dev);
+
+ nxp_fspi_clk_disable_unprep(f);
+
return 0;
}
-static int nxp_fspi_resume(struct device *dev)
+static int nxp_fspi_runtime_resume(struct device *dev)
{
struct nxp_fspi *f = dev_get_drvdata(dev);
- nxp_fspi_default_setup(f);
+ nxp_fspi_clk_prep_enable(f);
+
+ if (nxp_fspi_initialized(f) && nxp_fspi_need_reinit(f))
+ nxp_fspi_default_setup(f);
return 0;
}
+static int nxp_fspi_suspend(struct device *dev)
+{
+ int ret;
+
+ ret = pinctrl_pm_select_sleep_state(dev);
+ if (ret) {
+ dev_err(dev, "select flexspi sleep pinctrl failed!\n");
+ return ret;
+ }
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int nxp_fspi_resume(struct device *dev)
+{
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ ret = pinctrl_pm_select_default_state(dev);
+ if (ret)
+ dev_err(dev, "select flexspi default pinctrl failed!\n");
+
+ return ret;
+}
+
+static const struct dev_pm_ops nxp_fspi_pm_ops = {
+ SET_RUNTIME_PM_OPS(nxp_fspi_runtime_suspend, nxp_fspi_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(nxp_fspi_suspend, nxp_fspi_resume)
+};
+
+#endif /* CONFIG_PM */
+
static const struct of_device_id nxp_fspi_dt_ids[] = {
{ .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, },
{ .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, },
@@ -1244,11 +1404,6 @@ static const struct acpi_device_id nxp_fspi_acpi_ids[] = {
MODULE_DEVICE_TABLE(acpi, nxp_fspi_acpi_ids);
#endif
-static const struct dev_pm_ops nxp_fspi_pm_ops = {
- .suspend = nxp_fspi_suspend,
- .resume = nxp_fspi_resume,
-};
-
static struct platform_driver nxp_fspi_driver = {
.driver = {
.name = "nxp-fspi",