Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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

Pull spi-nor changes from Cyrille Pitchen:

"
  This pull-request contains the following notable changes:

  Core changes:
  * Add support to new ISSI and Cypress/Spansion memory parts.
  * Fix support of Micron memories by checking error bits in the FSR.
  * Fix update of block-protection bits by reading back the SR.
  * Restore the internal state of the SPI flash memory when removing the
    device.

  Driver changes:
  * Maintenance for Freescale, Intel and Metiatek drivers.
  * Add support of the direct access mode for the Cadence QSPI controller.
"
parents 0aede42e 23bae78e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@ Required properties:
  - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
  - interrupts : Should contain the interrupt for the device
  - clocks : The clocks needed by the QuadSPI controller
  - clock-names : the name of the clocks
  - clock-names : Should contain the name of the clocks: "qspi_en" and "qspi".

Optional properties:
  - fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B.
+3 −0
Original line number Diff line number Diff line
@@ -60,3 +60,6 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should
initialize the necessary fields for spi_nor{}. Please see
drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to fsl-quadspi.c
when you want to write a new driver for a SPI NOR controller.
Another API is spi_nor_restore(), this is used to restore the status of SPI
flash chip such as addressing mode. Call it whenever detach the driver from
device or reboot the system.
+9 −0
Original line number Diff line number Diff line
@@ -307,10 +307,18 @@ static int m25p_remove(struct spi_device *spi)
{
	struct m25p	*flash = spi_get_drvdata(spi);

	spi_nor_restore(&flash->spi_nor);

	/* Clean up MTD stuff. */
	return mtd_device_unregister(&flash->spi_nor.mtd);
}

static void m25p_shutdown(struct spi_device *spi)
{
	struct m25p *flash = spi_get_drvdata(spi);

	spi_nor_restore(&flash->spi_nor);
}
/*
 * Do NOT add to this array without reading the following:
 *
@@ -386,6 +394,7 @@ static struct spi_driver m25p80_driver = {
	.id_table	= m25p_ids,
	.probe	= m25p_probe,
	.remove	= m25p_remove,
	.shutdown	= m25p_shutdown,

	/* REVISIT: many of these chips have deep power-down modes, which
	 * should clearly be entered on suspend() to minimize power use.
+39 −16
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ struct cqspi_flash_pdata {
	u8		data_width;
	u8		cs;
	bool		registered;
	bool		use_direct_mode;
};

struct cqspi_st {
@@ -68,6 +69,7 @@ struct cqspi_st {

	void __iomem		*iobase;
	void __iomem		*ahb_base;
	resource_size_t		ahb_size;
	struct completion	transfer_complete;
	struct mutex		bus_mutex;

@@ -103,6 +105,7 @@ struct cqspi_st {
/* Register map */
#define CQSPI_REG_CONFIG			0x00
#define CQSPI_REG_CONFIG_ENABLE_MASK		BIT(0)
#define CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL	BIT(7)
#define CQSPI_REG_CONFIG_DECODE_MASK		BIT(9)
#define CQSPI_REG_CONFIG_CHIPSELECT_LSB		10
#define CQSPI_REG_CONFIG_DMA_MASK		BIT(15)
@@ -450,8 +453,7 @@ static int cqspi_command_write_addr(struct spi_nor *nor,
	return cqspi_exec_flash_cmd(cqspi, reg);
}

static int cqspi_indirect_read_setup(struct spi_nor *nor,
				     const unsigned int from_addr)
static int cqspi_read_setup(struct spi_nor *nor)
{
	struct cqspi_flash_pdata *f_pdata = nor->priv;
	struct cqspi_st *cqspi = f_pdata->cqspi;
@@ -459,8 +461,6 @@ static int cqspi_indirect_read_setup(struct spi_nor *nor,
	unsigned int dummy_clk = 0;
	unsigned int reg;

	writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);

	reg = nor->read_opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
	reg |= cqspi_calc_rdreg(nor, nor->read_opcode);

@@ -493,8 +493,8 @@ static int cqspi_indirect_read_setup(struct spi_nor *nor,
	return 0;
}

static int cqspi_indirect_read_execute(struct spi_nor *nor,
				       u8 *rxbuf, const unsigned n_rx)
static int cqspi_indirect_read_execute(struct spi_nor *nor, u8 *rxbuf,
				       loff_t from_addr, const size_t n_rx)
{
	struct cqspi_flash_pdata *f_pdata = nor->priv;
	struct cqspi_st *cqspi = f_pdata->cqspi;
@@ -504,6 +504,7 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor,
	unsigned int bytes_to_read = 0;
	int ret = 0;

	writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
	writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);

	/* Clear all interrupts. */
@@ -570,8 +571,7 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor,
	return ret;
}

static int cqspi_indirect_write_setup(struct spi_nor *nor,
				      const unsigned int to_addr)
static int cqspi_write_setup(struct spi_nor *nor)
{
	unsigned int reg;
	struct cqspi_flash_pdata *f_pdata = nor->priv;
@@ -584,8 +584,6 @@ static int cqspi_indirect_write_setup(struct spi_nor *nor,
	reg = cqspi_calc_rdreg(nor, nor->program_opcode);
	writel(reg, reg_base + CQSPI_REG_RD_INSTR);

	writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);

	reg = readl(reg_base + CQSPI_REG_SIZE);
	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
	reg |= (nor->addr_width - 1);
@@ -593,8 +591,8 @@ static int cqspi_indirect_write_setup(struct spi_nor *nor,
	return 0;
}

static int cqspi_indirect_write_execute(struct spi_nor *nor,
					const u8 *txbuf, const unsigned n_tx)
static int cqspi_indirect_write_execute(struct spi_nor *nor, loff_t to_addr,
					const u8 *txbuf, const size_t n_tx)
{
	const unsigned int page_size = nor->page_size;
	struct cqspi_flash_pdata *f_pdata = nor->priv;
@@ -604,6 +602,7 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor,
	unsigned int write_bytes;
	int ret;

	writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);
	writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);

	/* Clear all interrupts. */
@@ -894,17 +893,22 @@ static int cqspi_set_protocol(struct spi_nor *nor, const int read)
static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
			   size_t len, const 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, 0);
	if (ret)
		return ret;

	ret = cqspi_indirect_write_setup(nor, to);
	ret = cqspi_write_setup(nor);
	if (ret)
		return ret;

	ret = cqspi_indirect_write_execute(nor, buf, len);
	if (f_pdata->use_direct_mode)
		memcpy_toio(cqspi->ahb_base + to, buf, len);
	else
		ret = cqspi_indirect_write_execute(nor, to, buf, len);
	if (ret)
		return ret;

@@ -914,17 +918,22 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to,
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);
	if (ret)
		return ret;

	ret = cqspi_indirect_read_setup(nor, from);
	ret = cqspi_read_setup(nor);
	if (ret)
		return ret;

	ret = cqspi_indirect_read_execute(nor, buf, len);
	if (f_pdata->use_direct_mode)
		memcpy_fromio(buf, cqspi->ahb_base + from, len);
	else
		ret = cqspi_indirect_read_execute(nor, buf, from, len);
	if (ret)
		return ret;

@@ -1059,6 +1068,8 @@ static int cqspi_of_get_pdata(struct platform_device *pdev)

static void cqspi_controller_init(struct cqspi_st *cqspi)
{
	u32 reg;

	cqspi_controller_enable(cqspi, 0);

	/* Configure the remap address register, no remap */
@@ -1081,6 +1092,11 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
	writel(cqspi->fifo_depth * cqspi->fifo_width / 8,
	       cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);

	/* Enable Direct Access Controller */
	reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
	reg |= CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL;
	writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);

	cqspi_controller_enable(cqspi, 1);
}

@@ -1156,6 +1172,12 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
			goto err;

		f_pdata->registered = true;

		if (mtd->size <= cqspi->ahb_size) {
			f_pdata->use_direct_mode = true;
			dev_dbg(nor->dev, "using direct mode for %s\n",
				mtd->name);
		}
	}

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

	init_completion(&cqspi->transfer_complete);

+4 −4
Original line number Diff line number Diff line
@@ -801,10 +801,10 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
}

static const struct of_device_id fsl_qspi_dt_ids[] = {
	{ .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, },
	{ .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, },
	{ .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, },
	{ .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, },
	{ .compatible = "fsl,vf610-qspi", .data = &vybrid_data, },
	{ .compatible = "fsl,imx6sx-qspi", .data = &imx6sx_data, },
	{ .compatible = "fsl,imx7d-qspi", .data = &imx7d_data, },
	{ .compatible = "fsl,imx6ul-qspi", .data = &imx6ul_data, },
	{ .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
	{ /* sentinel */ }
};
Loading