Commit b771327a authored by Boris Brezillon's avatar Boris Brezillon
Browse files

Merge tag 'spi-nor/for-4.18' of git://git.infradead.org/linux-mtd into mtd/next

Core changes:
- Add support for a bunch of SPI NOR chips
- Clear EAR reg when switching to 3-byte addressing mode on Winbond
  chips

SPI NOR controller driver changes:
- cadence: Add DMA support for direct mode reads
- hisi: Prefix a few functions with hisi_
- intel:
  * Mark the driver as "dangerous" in Kconfig
  * Fix atomic sequence handling
  * Pass a 40us delay (instead of 0us) to readl_poll_timeout()
- fsl:
  * fix a typo in a function name
  * add support for IP variants embedded in the ls2080a and ls1080a
    SoCs
- stm32: request exclusive control of the reset line
parents 6e89b84e 771ff17e
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ config SPI_INTEL_SPI
	tristate

config SPI_INTEL_SPI_PCI
	tristate "Intel PCH/PCU SPI flash PCI driver"
	tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)"
	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"
	tristate "Intel PCH/PCU SPI flash platform driver (DANGEROUS)"
	depends on X86
	select SPI_INTEL_SPI
	help
+94 −2
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
@@ -73,6 +75,10 @@ struct cqspi_st {
	struct completion	transfer_complete;
	struct mutex		bus_mutex;

	struct dma_chan		*rx_chan;
	struct completion	rx_dma_complete;
	dma_addr_t		mmap_phys_base;

	int			current_cs;
	int			current_page_size;
	int			current_erase_size;
@@ -915,11 +921,75 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
	return len;
}

static void cqspi_rx_dma_callback(void *param)
{
	struct cqspi_st *cqspi = param;

	complete(&cqspi->rx_dma_complete);
}

static int cqspi_direct_read_execute(struct spi_nor *nor, u_char *buf,
				     loff_t from, size_t len)
{
	struct cqspi_flash_pdata *f_pdata = nor->priv;
	struct cqspi_st *cqspi = f_pdata->cqspi;
	enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
	dma_addr_t dma_src = (dma_addr_t)cqspi->mmap_phys_base + from;
	int ret = 0;
	struct dma_async_tx_descriptor *tx;
	dma_cookie_t cookie;
	dma_addr_t dma_dst;

	if (!cqspi->rx_chan || !virt_addr_valid(buf)) {
		memcpy_fromio(buf, cqspi->ahb_base + from, len);
		return 0;
	}

	dma_dst = dma_map_single(nor->dev, buf, len, DMA_DEV_TO_MEM);
	if (dma_mapping_error(nor->dev, dma_dst)) {
		dev_err(nor->dev, "dma mapping failed\n");
		return -ENOMEM;
	}
	tx = dmaengine_prep_dma_memcpy(cqspi->rx_chan, dma_dst, dma_src,
				       len, flags);
	if (!tx) {
		dev_err(nor->dev, "device_prep_dma_memcpy error\n");
		ret = -EIO;
		goto err_unmap;
	}

	tx->callback = cqspi_rx_dma_callback;
	tx->callback_param = cqspi;
	cookie = tx->tx_submit(tx);
	reinit_completion(&cqspi->rx_dma_complete);

	ret = dma_submit_error(cookie);
	if (ret) {
		dev_err(nor->dev, "dma_submit_error %d\n", cookie);
		ret = -EIO;
		goto err_unmap;
	}

	dma_async_issue_pending(cqspi->rx_chan);
	ret = wait_for_completion_timeout(&cqspi->rx_dma_complete,
					  msecs_to_jiffies(len));
	if (ret <= 0) {
		dmaengine_terminate_sync(cqspi->rx_chan);
		dev_err(nor->dev, "DMA wait_for_completion_timeout\n");
		ret = -ETIMEDOUT;
		goto err_unmap;
	}

err_unmap:
	dma_unmap_single(nor->dev, dma_dst, len, DMA_DEV_TO_MEM);

	return 0;
}

static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
			  size_t len, u_char *buf)
{
	struct cqspi_flash_pdata *f_pdata = nor->priv;
	struct cqspi_st *cqspi = f_pdata->cqspi;
	int ret;

	ret = cqspi_set_protocol(nor, 1);
@@ -931,7 +1001,7 @@ static ssize_t cqspi_read(struct spi_nor *nor, loff_t from,
		return ret;

	if (f_pdata->use_direct_mode)
		memcpy_fromio(buf, cqspi->ahb_base + from, len);
		ret = cqspi_direct_read_execute(nor, buf, from, len);
	else
		ret = cqspi_indirect_read_execute(nor, buf, from, len);
	if (ret)
@@ -1100,6 +1170,21 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
	cqspi_controller_enable(cqspi, 1);
}

static void cqspi_request_mmap_dma(struct cqspi_st *cqspi)
{
	dma_cap_mask_t mask;

	dma_cap_zero(mask);
	dma_cap_set(DMA_MEMCPY, mask);

	cqspi->rx_chan = dma_request_chan_by_mask(&mask);
	if (IS_ERR(cqspi->rx_chan)) {
		dev_err(&cqspi->pdev->dev, "No Rx DMA available\n");
		cqspi->rx_chan = NULL;
	}
	init_completion(&cqspi->rx_dma_complete);
}

static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
{
	const struct spi_nor_hwcaps hwcaps = {
@@ -1177,6 +1262,9 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
			f_pdata->use_direct_mode = true;
			dev_dbg(nor->dev, "using direct mode for %s\n",
				mtd->name);

			if (!cqspi->rx_chan)
				cqspi_request_mmap_dma(cqspi);
		}
	}

@@ -1237,6 +1325,7 @@ static int cqspi_probe(struct platform_device *pdev)
		dev_err(dev, "Cannot remap AHB address.\n");
		return PTR_ERR(cqspi->ahb_base);
	}
	cqspi->mmap_phys_base = (dma_addr_t)res_ahb->start;
	cqspi->ahb_size = resource_size(res_ahb);

	init_completion(&cqspi->transfer_complete);
@@ -1307,6 +1396,9 @@ static int cqspi_remove(struct platform_device *pdev)

	cqspi_controller_enable(cqspi, 0);

	if (cqspi->rx_chan)
		dma_release_channel(cqspi->rx_chan);

	clk_disable_unprepare(cqspi->clk);

	pm_runtime_put_sync(&pdev->dev);
+13 −2
Original line number Diff line number Diff line
@@ -214,6 +214,7 @@ enum fsl_qspi_devtype {
	FSL_QUADSPI_IMX7D,
	FSL_QUADSPI_IMX6UL,
	FSL_QUADSPI_LS1021A,
	FSL_QUADSPI_LS2080A,
};

struct fsl_qspi_devtype_data {
@@ -267,6 +268,15 @@ static struct fsl_qspi_devtype_data ls1021a_data = {
	.driver_data = 0,
};

static const struct fsl_qspi_devtype_data ls2080a_data = {
	.devtype = FSL_QUADSPI_LS2080A,
	.rxfifo = 128,
	.txfifo = 64,
	.ahb_buf_size = 1024,
	.driver_data = QUADSPI_QUIRK_TKT253890,
};


#define FSL_QSPI_MAX_CHIP	4
struct fsl_qspi {
	struct spi_nor nor[FSL_QSPI_MAX_CHIP];
@@ -661,7 +671,7 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
 * causes the controller to clear the buffer, and use the sequence pointed
 * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
 */
static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
{
	void __iomem *base = q->iobase;
	int seqid;
@@ -795,7 +805,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
	fsl_qspi_init_lut(q);

	/* Init for AHB read */
	fsl_qspi_init_abh_read(q);
	fsl_qspi_init_ahb_read(q);

	return 0;
}
@@ -806,6 +816,7 @@ static const struct of_device_id fsl_qspi_dt_ids[] = {
	{ .compatible = "fsl,imx7d-qspi", .data = &imx7d_data, },
	{ .compatible = "fsl,imx6ul-qspi", .data = &imx6ul_data, },
	{ .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
	{ .compatible = "fsl,ls2080a-qspi", .data = &ls2080a_data, },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
+6 −6
Original line number Diff line number Diff line
@@ -112,7 +112,7 @@ struct hifmc_host {
	u32 num_chip;
};

static inline int wait_op_finish(struct hifmc_host *host)
static inline int hisi_spi_nor_wait_op_finish(struct hifmc_host *host)
{
	u32 reg;

@@ -120,7 +120,7 @@ static inline int wait_op_finish(struct hifmc_host *host)
		(reg & FMC_INT_OP_DONE), 0, FMC_WAIT_TIMEOUT);
}

static int get_if_type(enum spi_nor_protocol proto)
static int hisi_spi_nor_get_if_type(enum spi_nor_protocol proto)
{
	enum hifmc_iftype if_type;

@@ -208,7 +208,7 @@ static int hisi_spi_nor_op_reg(struct spi_nor *nor,
	reg = FMC_OP_CMD1_EN | FMC_OP_REG_OP_START | optype;
	writel(reg, host->regbase + FMC_OP);

	return wait_op_finish(host);
	return hisi_spi_nor_wait_op_finish(host);
}

static int hisi_spi_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
@@ -259,9 +259,9 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,

	reg = OP_CFG_FM_CS(priv->chipselect);
	if (op_type == FMC_OP_READ)
		if_type = get_if_type(nor->read_proto);
		if_type = hisi_spi_nor_get_if_type(nor->read_proto);
	else
		if_type = get_if_type(nor->write_proto);
		if_type = hisi_spi_nor_get_if_type(nor->write_proto);
	reg |= OP_CFG_MEM_IF_TYPE(if_type);
	if (op_type == FMC_OP_READ)
		reg |= OP_CFG_DUMMY_NUM(nor->read_dummy >> 3);
@@ -274,7 +274,7 @@ static int hisi_spi_nor_dma_transfer(struct spi_nor *nor, loff_t start_off,
		: OP_CTRL_WR_OPCODE(nor->program_opcode);
	writel(reg, host->regbase + FMC_OP_DMA);

	return wait_op_finish(host);
	return hisi_spi_nor_wait_op_finish(host);
}

static ssize_t hisi_spi_nor_read(struct spi_nor *nor, loff_t from, size_t len,
+69 −11
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@
 * @swseq_reg: Use SW sequencer in register reads/writes
 * @swseq_erase: Use SW sequencer in erase operation
 * @erase_64k: 64k erase supported
 * @atomic_preopcode: Holds preopcode when atomic sequence is requested
 * @opcodes: Opcodes which are supported. This are programmed by BIOS
 *           before it locks down the controller.
 */
@@ -153,6 +154,7 @@ struct intel_spi {
	bool swseq_reg;
	bool swseq_erase;
	bool erase_64k;
	u8 atomic_preopcode;
	u8 opcodes[8];
};

@@ -285,7 +287,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), 0,
				  !(val & HSFSTS_CTL_SCIP), 40,
				  INTEL_SPI_TIMEOUT * 1000);
}

@@ -294,7 +296,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), 0,
				  !(val & SSFSTS_CTL_SCIP), 40,
				  INTEL_SPI_TIMEOUT * 1000);
}

@@ -474,7 +476,7 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, int len,
			      int optype)
{
	u32 val = 0, status;
	u16 preop;
	u8 atomic_preopcode;
	int ret;

	ret = intel_spi_opcode_index(ispi, opcode, optype);
@@ -484,17 +486,42 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, int len,
	if (len > INTEL_SPI_FIFO_SZ)
		return -EINVAL;

	/*
	 * Always clear it after each SW sequencer operation regardless
	 * of whether it is successful or not.
	 */
	atomic_preopcode = ispi->atomic_preopcode;
	ispi->atomic_preopcode = 0;

	/* 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;
	if (atomic_preopcode) {
		u16 preop;

		switch (optype) {
		case OPTYPE_WRITE_NO_ADDR:
		case OPTYPE_WRITE_WITH_ADDR:
			/* Pick matching preopcode for the atomic sequence */
			preop = readw(ispi->sregs + PREOP_OPTYPE);
	if (preop) {
		val |= SSFSTS_CTL_ACS;
		if (preop >> 8)
			if ((preop & 0xff) == atomic_preopcode)
				; /* Do nothing */
			else if ((preop >> 8) == atomic_preopcode)
				val |= SSFSTS_CTL_SPOP;
			else
				return -EINVAL;

			/* Enable atomic sequence */
			val |= SSFSTS_CTL_ACS;
			break;

		default:
			return -EINVAL;
		}

	}
	writel(val, ispi->sregs + SSFSTS_CTL);

@@ -538,13 +565,31 @@ 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. If the controller is not locked,
	 * program the opcode to the PREOP register for later use.
	 * controller so we only verify that it is available. If the
	 * controller is not locked, program the opcode to the PREOP
	 * register for later use.
	 *
	 * When hardware sequencer is used there is no need to program
	 * any opcodes (it handles them automatically as part of a command).
	 */
	if (opcode == SPINOR_OP_WREN) {
		if (!ispi->locked)
		u16 preop;

		if (!ispi->swseq_reg)
			return 0;

		preop = readw(ispi->sregs + PREOP_OPTYPE);
		if ((preop & 0xff) != opcode && (preop >> 8) != opcode) {
			if (ispi->locked)
				return -EINVAL;
			writel(opcode, ispi->sregs + PREOP_OPTYPE);
		}

		/*
		 * This enables atomic sequence on next SW sycle. Will
		 * be cleared after next operation.
		 */
		ispi->atomic_preopcode = opcode;
		return 0;
	}

@@ -569,6 +614,13 @@ static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len,
	u32 val, status;
	ssize_t ret;

	/*
	 * Atomic sequence is not expected with HW sequencer reads. Make
	 * sure it is cleared regardless.
	 */
	if (WARN_ON_ONCE(ispi->atomic_preopcode))
		ispi->atomic_preopcode = 0;

	switch (nor->read_opcode) {
	case SPINOR_OP_READ:
	case SPINOR_OP_READ_FAST:
@@ -627,6 +679,9 @@ static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len,
	u32 val, status;
	ssize_t ret;

	/* Not needed with HW sequencer write, make sure it is cleared */
	ispi->atomic_preopcode = 0;

	while (len > 0) {
		block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ);

@@ -707,6 +762,9 @@ static int intel_spi_erase(struct spi_nor *nor, loff_t offs)
		return 0;
	}

	/* Not needed with HW sequencer erase, make sure it is cleared */
	ispi->atomic_preopcode = 0;

	while (len > 0) {
		writel(offs, ispi->base + FADDR);

Loading