Commit cb413909 authored by Richard Weinberger's avatar Richard Weinberger

Merge tag 'spi-nor/for-5.9' of...

Merge tag 'spi-nor/for-5.9' of https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux into mtd/next

SPI NOR core changes:
- Disable Quad Mode in spi_nor_restore().
- Don't abort BFPT parsing when QER reserved value is used.
- Add support/update capabilities for few flashes.
- Drop s70fl01gs flash: it does not support RDSR(05h) which
  is critical for erase/write.
- Merge the SPIMEM DTR bits in spi-nor/next to avoid conflicts
  during the release cycle.

SPI NOR controller drivers changes:
- Move the cadence-quadspi driver to spi-mem. The series was
  taken through the SPI tree. Merge it also in spi-nor/next
  to avoid conflicts during the release cycle.
- intel-spi:
   - Add new PCI IDs.
   - Ignore the Write Disable command, the controller doesn't
     support it.
   - Fix performance regression.
parents fbd9b543 e93a9773
......@@ -9,17 +9,6 @@ config SPI_ASPEED_SMC
and support for the SPI flash memory controller (SPI) for
the host firmware. The implementation only supports SPI NOR.
config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller"
depends on OF && (ARM || ARM64 || COMPILE_TEST)
help
Enable support for the Cadence Quad SPI Flash controller.
Cadence QSPI is a specialized controller for connecting an SPI
Flash over 1/2/4-bit wide bus. Enable this option if you have a
device with a Cadence QSPI controller and want to access the
Flash as an MTD device.
config SPI_HISI_SFC
tristate "Hisilicon FMC SPI NOR Flash Controller(SFC)"
depends on ARCH_HISI || COMPILE_TEST
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o
obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o
obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o
obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o
......
......@@ -68,7 +68,9 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
......
......@@ -292,7 +292,7 @@ static int intel_spi_wait_hw_busy(struct intel_spi *ispi)
u32 val;
return readl_poll_timeout(ispi->base + HSFSTS_CTL, val,
!(val & HSFSTS_CTL_SCIP), 40,
!(val & HSFSTS_CTL_SCIP), 0,
INTEL_SPI_TIMEOUT * 1000);
}
......@@ -301,7 +301,7 @@ static int intel_spi_wait_sw_busy(struct intel_spi *ispi)
u32 val;
return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val,
!(val & SSFSTS_CTL_SCIP), 40,
!(val & SSFSTS_CTL_SCIP), 0,
INTEL_SPI_TIMEOUT * 1000);
}
......@@ -612,6 +612,15 @@ static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
return 0;
}
/*
* We hope that HW sequencer will do the right thing automatically and
* with the SW sequencer we cannot use preopcode anyway, so just ignore
* the Write Disable operation and pretend it was completed
* successfully.
*/
if (opcode == SPINOR_OP_WRDI)
return 0;
writel(0, ispi->base + FADDR);
/* Write the value beforehand */
......
......@@ -1907,15 +1907,16 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
}
/**
* spi_nor_sr1_bit6_quad_enable() - Set the Quad Enable BIT(6) in the Status
* Register 1.
* spi_nor_sr1_bit6_quad_enable() - Set/Unset the Quad Enable BIT(6) in the
* Status Register 1.
* @nor: pointer to a 'struct spi_nor'
* @enable: true to enable Quad mode, false to disable Quad mode.
*
* Bit 6 of the Status Register 1 is the QE bit for Macronix like QSPI memories.
*
* Return: 0 on success, -errno otherwise.
*/
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor)
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable)
{
int ret;
......@@ -1923,45 +1924,56 @@ int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor)
if (ret)
return ret;
if (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)
if ((enable && (nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)) ||
(!enable && !(nor->bouncebuf[0] & SR1_QUAD_EN_BIT6)))
return 0;
nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6;
if (enable)
nor->bouncebuf[0] |= SR1_QUAD_EN_BIT6;
else
nor->bouncebuf[0] &= ~SR1_QUAD_EN_BIT6;
return spi_nor_write_sr1_and_check(nor, nor->bouncebuf[0]);
}
/**
* spi_nor_sr2_bit1_quad_enable() - set the Quad Enable BIT(1) in the Status
* Register 2.
* spi_nor_sr2_bit1_quad_enable() - set/unset the Quad Enable BIT(1) in the
* Status Register 2.
* @nor: pointer to a 'struct spi_nor'.
* @enable: true to enable Quad mode, false to disable Quad mode.
*
* Bit 1 of the Status Register 2 is the QE bit for Spansion like QSPI memories.
*
* Return: 0 on success, -errno otherwise.
*/
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor)
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable)
{
int ret;
if (nor->flags & SNOR_F_NO_READ_CR)
return spi_nor_write_16bit_cr_and_check(nor, SR2_QUAD_EN_BIT1);
return spi_nor_write_16bit_cr_and_check(nor,
enable ? SR2_QUAD_EN_BIT1 : 0);
ret = spi_nor_read_cr(nor, nor->bouncebuf);
if (ret)
return ret;
if (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)
if ((enable && (nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)) ||
(!enable && !(nor->bouncebuf[0] & SR2_QUAD_EN_BIT1)))
return 0;
nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1;
if (enable)
nor->bouncebuf[0] |= SR2_QUAD_EN_BIT1;
else
nor->bouncebuf[0] &= ~SR2_QUAD_EN_BIT1;
return spi_nor_write_16bit_cr_and_check(nor, nor->bouncebuf[0]);
}
/**
* spi_nor_sr2_bit7_quad_enable() - set QE bit in Status Register 2.
* spi_nor_sr2_bit7_quad_enable() - set/unset QE bit in Status Register 2.
* @nor: pointer to a 'struct spi_nor'
* @enable: true to enable Quad mode, false to disable Quad mode.
*
* Set the Quad Enable (QE) bit in the Status Register 2.
*
......@@ -1971,7 +1983,7 @@ int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor)
*
* Return: 0 on success, -errno otherwise.
*/
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor)
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable)
{
u8 *sr2 = nor->bouncebuf;
int ret;
......@@ -1981,11 +1993,15 @@ int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor)
ret = spi_nor_read_sr2(nor, sr2);
if (ret)
return ret;
if (*sr2 & SR2_QUAD_EN_BIT7)
if ((enable && (*sr2 & SR2_QUAD_EN_BIT7)) ||
(!enable && !(*sr2 & SR2_QUAD_EN_BIT7)))
return 0;
/* Update the Quad Enable bit. */
*sr2 |= SR2_QUAD_EN_BIT7;
if (enable)
*sr2 |= SR2_QUAD_EN_BIT7;
else
*sr2 &= ~SR2_QUAD_EN_BIT7;
ret = spi_nor_write_sr2(nor, sr2);
if (ret)
......@@ -2898,12 +2914,13 @@ static int spi_nor_init_params(struct spi_nor *nor)
}
/**
* spi_nor_quad_enable() - enable Quad I/O if needed.
* spi_nor_quad_enable() - enable/disable Quad I/O if needed.
* @nor: pointer to a 'struct spi_nor'
* @enable: true to enable Quad mode. false to disable Quad mode.
*
* Return: 0 on success, -errno otherwise.
*/
static int spi_nor_quad_enable(struct spi_nor *nor)
static int spi_nor_quad_enable(struct spi_nor *nor, bool enable)
{
if (!nor->params->quad_enable)
return 0;
......@@ -2912,7 +2929,7 @@ static int spi_nor_quad_enable(struct spi_nor *nor)
spi_nor_get_protocol_width(nor->write_proto) == 4))
return 0;
return nor->params->quad_enable(nor);
return nor->params->quad_enable(nor, enable);
}
/**
......@@ -2936,7 +2953,7 @@ static int spi_nor_init(struct spi_nor *nor)
{
int err;
err = spi_nor_quad_enable(nor);
err = spi_nor_quad_enable(nor, true);
if (err) {
dev_dbg(nor->dev, "quad mode not supported\n");
return err;
......@@ -2983,6 +3000,8 @@ void spi_nor_restore(struct spi_nor *nor)
if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET)
nor->params->set_4byte_addr_mode(nor, false);
spi_nor_quad_enable(nor, false);
}
EXPORT_SYMBOL_GPL(spi_nor_restore);
......
......@@ -198,7 +198,7 @@ struct spi_nor_locking_ops {
* higher index in the array, the higher priority.
* @erase_map: the erase map parsed from the SFDP Sector Map Parameter
* Table.
* @quad_enable: enables SPI NOR quad mode.
* @quad_enable: enables/disables SPI NOR Quad mode.
* @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode.
* @convert_addr: converts an absolute address into something the flash
* will understand. Particularly useful when pagesize is
......@@ -219,7 +219,7 @@ struct spi_nor_flash_parameter {
struct spi_nor_erase_map erase_map;
int (*quad_enable)(struct spi_nor *nor);
int (*quad_enable)(struct spi_nor *nor, bool enable);
int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
int (*setup)(struct spi_nor *nor, const struct spi_nor_hwcaps *hwcaps);
......@@ -406,9 +406,9 @@ int spi_nor_write_ear(struct spi_nor *nor, u8 ear);
int spi_nor_wait_till_ready(struct spi_nor *nor);
int spi_nor_lock_and_prep(struct spi_nor *nor);
void spi_nor_unlock_and_unprep(struct spi_nor *nor);
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor);
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor, bool enable);
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor, bool enable);
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor, bool enable);
int spi_nor_xread_sr(struct spi_nor *nor, u8 *sr);
ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
......
......@@ -52,6 +52,9 @@ static const struct flash_info macronix_parts[] = {
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25r1635f", INFO(0xc22815, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) },
{ "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) },
......@@ -84,6 +87,9 @@ static const struct flash_info macronix_parts[] = {
SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048,
SPI_NOR_QUAD_READ) },
{ "mx66u2g45g", INFO(0xc2253c, 0, 64 * 1024, 4096,
SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
};
static void macronix_default_init(struct spi_nor *nor)
......
......@@ -71,8 +71,8 @@ static const struct flash_info st_parts[] = {
SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
NO_CHIP_ERASE) },
{ "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096,
SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
NO_CHIP_ERASE) },
SECT_4K | USE_FSR | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
{ "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) },
{ "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) },
......
......@@ -598,7 +598,8 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
break;
default:
return -EINVAL;
dev_dbg(nor->dev, "BFPT QER reserved value used\n");
break;
}
/* Stop here if not JESD216 rev C or later. */
......
......@@ -64,7 +64,6 @@ static const struct flash_info spansion_parts[] = {
{ "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256,
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR)
.fixups = &s25fs_s_fixups, },
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64,
......@@ -84,7 +83,8 @@ static const struct flash_info spansion_parts[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) },
......
......@@ -64,10 +64,12 @@ static const struct flash_info winbond_parts[] = {
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
{ "w25q64jvm", INFO(0xef7017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
......
......@@ -200,6 +200,17 @@ config SPI_CADENCE
This selects the Cadence SPI controller master driver
used by Xilinx Zynq and ZynqMP.
config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller"
depends on OF && (ARM || ARM64 || COMPILE_TEST)
help
Enable support for the Cadence Quad SPI Flash controller.
Cadence QSPI is a specialized controller for connecting an SPI
Flash over 1/2/4-bit wide bus. Enable this option if you have a
device with a Cadence QSPI controller and want to access the
Flash as an MTD device.
config SPI_CLPS711X
tristate "CLPS711X host SPI controller"
depends on ARCH_CLPS711X || COMPILE_TEST
......
......@@ -31,6 +31,7 @@ obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o
obj-$(CONFIG_SPI_CADENCE_QUADSPI) += spi-cadence-quadspi.o
obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
......
......@@ -285,6 +285,12 @@ static bool atmel_qspi_supports_op(struct spi_mem *mem,
op->dummy.nbytes == 0)
return false;
/* DTR ops not supported. */
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
return false;
if (op->cmd.nbytes != 1)
return false;
return true;
}
......
......@@ -156,6 +156,12 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
op->data.dir == SPI_MEM_DATA_OUT))
return false;
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
return false;
if (op->cmd.nbytes != 1)
return false;
return true;
}
EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
......@@ -170,7 +176,7 @@ static bool spi_mem_buswidth_is_valid(u8 buswidth)
static int spi_mem_check_op(const struct spi_mem_op *op)
{
if (!op->cmd.buswidth)
if (!op->cmd.buswidth || !op->cmd.nbytes)
return -EINVAL;
if ((op->addr.nbytes && !op->addr.buswidth) ||
......@@ -306,8 +312,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
return ret;
}
tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes +
op->dummy.nbytes;
tmpbufsize = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
/*
* Allocate a buffer to transmit the CMD, ADDR cycles with kmalloc() so
......@@ -322,7 +327,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
tmpbuf[0] = op->cmd.opcode;
xfers[xferpos].tx_buf = tmpbuf;
xfers[xferpos].len = sizeof(op->cmd.opcode);
xfers[xferpos].len = op->cmd.nbytes;
xfers[xferpos].tx_nbits = op->cmd.buswidth;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
......@@ -424,8 +429,7 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
return ctlr->mem_ops->adjust_op_size(mem, op);
if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) {
len = sizeof(op->cmd.opcode) + op->addr.nbytes +
op->dummy.nbytes;
len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
if (len > spi_max_transfer_size(mem->spi))
return -EINVAL;
......
......@@ -195,7 +195,7 @@ static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
}
}
len = MTK_NOR_PRG_MAX_SIZE - sizeof(op->cmd.opcode) - op->addr.nbytes -
len = MTK_NOR_PRG_MAX_SIZE - op->cmd.nbytes - op->addr.nbytes -
op->dummy.nbytes;
if (op->data.nbytes > len)
op->data.nbytes = len;
......@@ -211,6 +211,12 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,
if (op->cmd.buswidth != 1)
return false;
/* DTR ops not supported. */
if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
return false;
if (op->cmd.nbytes != 1)
return false;
if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op))
return true;
......@@ -219,7 +225,7 @@ static bool mtk_nor_supports_op(struct spi_mem *mem,
(op->dummy.buswidth == 0) &&
(op->data.buswidth == 1);
}
len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
if ((len > MTK_NOR_PRG_MAX_SIZE) ||
((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))
return false;
......
......@@ -356,6 +356,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
int nio = 1, i, ret;
u32 ss_ctrl;
u8 addr[8];
u8 opcode = op->cmd.opcode;
ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz);
if (ret)
......@@ -393,7 +394,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem,
writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT,
mxic->regs + HC_CFG);
ret = mxic_spi_data_xfer(mxic, &op->cmd.opcode, NULL, 1);
ret = mxic_spi_data_xfer(mxic, &opcode, NULL, 1);
if (ret)
goto out;
......
......@@ -527,20 +527,21 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem,
struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master);
int err = 0, i;
u8 *tmpbuf;
u8 opcode = op->cmd.opcode;
dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n",
op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
opcode, op->cmd.buswidth, op->addr.buswidth,
op->dummy.buswidth, op->data.buswidth);
zynq_qspi_chipselect(mem->spi, true);
zynq_qspi_config_op(xqspi, mem->spi);
if (op->cmd.opcode) {
if (op->cmd.nbytes) {
reinit_completion(&xqspi->data_completion);
xqspi->txbuf = (u8 *)&op->cmd.opcode;
xqspi->txbuf = &opcode;
xqspi->rxbuf = NULL;
xqspi->tx_bytes = sizeof(op->cmd.opcode);
xqspi->rx_bytes = sizeof(op->cmd.opcode);
xqspi->tx_bytes = op->cmd.nbytes;
xqspi->rx_bytes = op->cmd.nbytes;
zynq_qspi_write_op(xqspi, ZYNQ_QSPI_FIFO_DEPTH, true);
zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET,
ZYNQ_QSPI_IXR_RXTX_MASK);
......
......@@ -17,6 +17,7 @@
{ \
.buswidth = __buswidth, \
.opcode = __opcode, \
.nbytes = 1, \
}
#define SPI_MEM_OP_ADDR(__nbytes, __val, __buswidth) \
......@@ -69,11 +70,15 @@ enum spi_mem_data_dir {
/**
* struct spi_mem_op - describes a SPI memory operation
* @cmd.nbytes: number of opcode bytes (only 1 or 2 are valid). The opcode is
* sent MSB-first.
* @cmd.buswidth: number of IO lines used to transmit the command
* @cmd.opcode: operation opcode
* @cmd.dtr: whether the command opcode should be sent in DTR mode or not
* @addr.nbytes: number of address bytes to send. Can be zero if the operation
* does not need to send an address
* @addr.buswidth: number of IO lines used to transmit the address cycles
* @addr.dtr: whether the address should be sent in DTR mode or not
* @addr.val: address value. This value is always sent MSB first on the bus.
* Note that only @addr.nbytes are taken into account in this
* address value, so users should make sure the value fits in the
......@@ -81,7 +86,9 @@ enum spi_mem_data_dir {
* @dummy.nbytes: number of dummy bytes to send after an opcode or address. Can
* be zero if the operation does not require dummy bytes
* @dummy.buswidth: number of IO lanes used to transmit the dummy bytes
* @dummy.dtr: whether the dummy bytes should be sent in DTR mode or not
* @data.buswidth: number of IO lanes used to send/receive the data
* @data.dtr: whether the data should be sent in DTR mode or not
* @data.dir: direction of the transfer
* @data.nbytes: number of data bytes to send/receive. Can be zero if the
* operation does not involve transferring data
......@@ -90,23 +97,28 @@ enum spi_mem_data_dir {
*/
struct spi_mem_op {
struct {
u8 nbytes;
u8 buswidth;
u8 opcode;
u8 dtr : 1;
u16 opcode;
} cmd;
struct {
u8 nbytes;
u8 buswidth;
u8 dtr : 1;
u64 val;
} addr;
struct {
u8 nbytes;
u8 buswidth;
u8 dtr : 1;
} dummy;
struct {
u8 buswidth;
u8 dtr : 1;
enum spi_mem_data_dir dir;
unsigned int nbytes;
union {
......
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