Unverified Commit df5c2100 authored by Sergei Shtylyov's avatar Sergei Shtylyov Committed by Tudor Ambarus
Browse files

mtd: spi-nor: use spi-mem dirmap API



Make use of the spi-mem direct mapping API to let advanced controllers
optimize read/write operations when they support direct mapping.

Based on the original patch by Boris Brezillon
<boris.brezillon@bootlin.com>.

Signed-off-by: default avatarSergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Reviewed-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: default avatarTudor Ambarus <tudor.ambarus@microchip.com>
parent b7ad6be2
Loading
Loading
Loading
Loading
+84 −10
Original line number Diff line number Diff line
@@ -306,6 +306,7 @@ static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from,
			   SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
			   SPI_MEM_OP_DATA_IN(len, buf, 1));
	bool usebouncebuf;
	ssize_t nbytes;
	int error;

	/* get transfer protocols. */
@@ -319,14 +320,20 @@ static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t from,

	usebouncebuf = spi_nor_spimem_bounce(nor, &op);

	if (nor->dirmap.rdesc) {
		nbytes = spi_mem_dirmap_read(nor->dirmap.rdesc, op.addr.val,
					     op.data.nbytes, op.data.buf.in);
	} else {
		error = spi_nor_spimem_exec_op(nor, &op);
		if (error)
			return error;
		nbytes = op.data.nbytes;
	}

	if (usebouncebuf)
		memcpy(buf, op.data.buf.in, op.data.nbytes);
	if (usebouncebuf && nbytes > 0)
		memcpy(buf, op.data.buf.in, nbytes);

	return op.data.nbytes;
	return nbytes;
}

/**
@@ -365,6 +372,7 @@ static ssize_t spi_nor_spimem_write_data(struct spi_nor *nor, loff_t to,
			   SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
			   SPI_MEM_OP_NO_DUMMY,
			   SPI_MEM_OP_DATA_OUT(len, buf, 1));
	ssize_t nbytes;
	int error;

	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
@@ -377,11 +385,17 @@ static ssize_t spi_nor_spimem_write_data(struct spi_nor *nor, loff_t to,
	if (spi_nor_spimem_bounce(nor, &op))
		memcpy(nor->bouncebuf, buf, op.data.nbytes);

	if (nor->dirmap.wdesc) {
		nbytes = spi_mem_dirmap_write(nor->dirmap.wdesc, op.addr.val,
					      op.data.nbytes, op.data.buf.out);
	} else {
		error = spi_nor_spimem_exec_op(nor, &op);
		if (error)
			return error;
		nbytes = op.data.nbytes;
	}

	return op.data.nbytes;
	return nbytes;
}

/**
@@ -5265,6 +5279,58 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
}
EXPORT_SYMBOL_GPL(spi_nor_scan);

static int spi_nor_create_read_dirmap(struct spi_nor *nor)
{
	struct spi_mem_dirmap_info info = {
		.op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
				      SPI_MEM_OP_ADDR(nor->addr_width, 0, 1),
				      SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
				      SPI_MEM_OP_DATA_IN(0, NULL, 1)),
		.offset = 0,
		.length = nor->mtd.size,
	};
	struct spi_mem_op *op = &info.op_tmpl;

	/* get transfer protocols. */
	op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
	op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
	op->dummy.buswidth = op->addr.buswidth;
	op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);

	/* convert the dummy cycles to the number of bytes */
	op->dummy.nbytes = (nor->read_dummy * op->dummy.buswidth) / 8;

	nor->dirmap.rdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem,
						       &info);
	return PTR_ERR_OR_ZERO(nor->dirmap.rdesc);
}

static int spi_nor_create_write_dirmap(struct spi_nor *nor)
{
	struct spi_mem_dirmap_info info = {
		.op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
				      SPI_MEM_OP_ADDR(nor->addr_width, 0, 1),
				      SPI_MEM_OP_NO_DUMMY,
				      SPI_MEM_OP_DATA_OUT(0, NULL, 1)),
		.offset = 0,
		.length = nor->mtd.size,
	};
	struct spi_mem_op *op = &info.op_tmpl;

	/* get transfer protocols. */
	op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
	op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
	op->dummy.buswidth = op->addr.buswidth;
	op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);

	if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
		op->addr.nbytes = 0;

	nor->dirmap.wdesc = devm_spi_mem_dirmap_create(nor->dev, nor->spimem,
						       &info);
	return PTR_ERR_OR_ZERO(nor->dirmap.wdesc);
}

static int spi_nor_probe(struct spi_mem *spimem)
{
	struct spi_device *spi = spimem->spi;
@@ -5326,6 +5392,14 @@ static int spi_nor_probe(struct spi_mem *spimem)
			return -ENOMEM;
	}

	ret = spi_nor_create_read_dirmap(nor);
	if (ret)
		return ret;

	ret = spi_nor_create_write_dirmap(nor);
	if (ret)
		return ret;

	return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
				   data ? data->nr_parts : 0);
}
+6 −0
Original line number Diff line number Diff line
@@ -580,6 +580,7 @@ struct flash_info;
 *                      The structure includes legacy flash parameters and
 *                      settings that can be overwritten by the spi_nor_fixups
 *                      hooks, or dynamically when parsing the SFDP tables.
 * @dirmap:		pointers to struct spi_mem_dirmap_desc for reads/writes.
 * @priv:		the private data
 */
struct spi_nor {
@@ -606,6 +607,11 @@ struct spi_nor {

	struct spi_nor_flash_parameter params;

	struct {
		struct spi_mem_dirmap_desc *rdesc;
		struct spi_mem_dirmap_desc *wdesc;
	} dirmap;

	void *priv;
};