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

Unverified Commit 5f195ee7 authored by Boris Brezillon's avatar Boris Brezillon Committed by Mark Brown
Browse files

spi: bcm-qspi: Implement the spi_mem interface



The spi_mem interface is meant to replace the ->spi_flash_read() one.
Implement the ->exec_op() method to ease removal of the old interface.

Not that ->spi_flash_read() is now implemented as a wrapper around the
new bcm_qspi_exec_mem_op() function so that we can easily get rid of
it when ->spi_flash_read() is removed.

Signed-off-by: default avatarBoris Brezillon <boris.brezillon@bootlin.com>
Reviewed-by: default avatarKamal Dasu <kdasu.kdev@gmail.com>
Tested-by: default avatarKamal Dasu <kdasu.kdev@gmail.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent b5932f5c
Loading
Loading
Loading
Loading
+111 −79
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#include <linux/sysfs.h>
#include <linux/types.h>
#include "spi-bcm-qspi.h"
@@ -215,10 +216,10 @@ struct bcm_qspi {
	int bspi_maj_rev;
	int bspi_min_rev;
	int bspi_enabled;
	struct spi_flash_read_message *bspi_rf_msg;
	u32 bspi_rf_msg_idx;
	u32 bspi_rf_msg_len;
	u32 bspi_rf_msg_status;
	const struct spi_mem_op *bspi_rf_op;
	u32 bspi_rf_op_idx;
	u32 bspi_rf_op_len;
	u32 bspi_rf_op_status;
	struct bcm_xfer_mode xfer_mode;
	u32 s3_strap_override_ctrl;
	bool bspi_mode;
@@ -313,26 +314,26 @@ static inline void bcm_qspi_bspi_lr_clear(struct bcm_qspi *qspi)

static void bcm_qspi_bspi_lr_data_read(struct bcm_qspi *qspi)
{
	u32 *buf = (u32 *)qspi->bspi_rf_msg->buf;
	u32 *buf = (u32 *)qspi->bspi_rf_op->data.buf.in;
	u32 data = 0;

	dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_msg,
		qspi->bspi_rf_msg->buf, qspi->bspi_rf_msg_len);
	dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_op,
		qspi->bspi_rf_op->data.buf.in, qspi->bspi_rf_op_len);
	while (!bcm_qspi_bspi_lr_is_fifo_empty(qspi)) {
		data = bcm_qspi_bspi_lr_read_fifo(qspi);
		if (likely(qspi->bspi_rf_msg_len >= 4) &&
		if (likely(qspi->bspi_rf_op_len >= 4) &&
		    IS_ALIGNED((uintptr_t)buf, 4)) {
			buf[qspi->bspi_rf_msg_idx++] = data;
			qspi->bspi_rf_msg_len -= 4;
			buf[qspi->bspi_rf_op_idx++] = data;
			qspi->bspi_rf_op_len -= 4;
		} else {
			/* Read out remaining bytes, make sure*/
			u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_msg_idx];
			u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_op_idx];

			data = cpu_to_le32(data);
			while (qspi->bspi_rf_msg_len) {
			while (qspi->bspi_rf_op_len) {
				*cbuf++ = (u8)data;
				data >>= 8;
				qspi->bspi_rf_msg_len--;
				qspi->bspi_rf_op_len--;
			}
		}
	}
@@ -349,14 +350,12 @@ static void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte,
}

static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
				       struct spi_flash_read_message *msg,
				       int hp)
				       const struct spi_mem_op *op, int hp)
{
	int bpc = 0, bpp = 0;
	u8 command = msg->read_opcode;
	int width  = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
	int addrlen = msg->addr_width;
	int addr_nbits = msg->addr_nbits ? msg->addr_nbits : SPI_NBITS_SINGLE;
	u8 command = op->cmd.opcode;
	int width  = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE;
	int addrlen = op->addr.nbytes * 8;
	int flex_mode = 1;

	dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n",
@@ -365,7 +364,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
	if (addrlen == BSPI_ADDRLEN_4BYTES)
		bpp = BSPI_BPP_ADDR_SELECT_MASK;

	bpp |= msg->dummy_bytes * (8/addr_nbits);
	bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;

	switch (width) {
	case SPI_NBITS_SINGLE:
@@ -397,11 +396,10 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
}

static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
				      struct spi_flash_read_message *msg,
				      int hp)
				      const struct spi_mem_op *op, int hp)
{
	int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
	int addrlen = msg->addr_width;
	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
	int addrlen = op->addr.nbytes;
	u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);

	dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n",
@@ -437,17 +435,17 @@ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
	/* set the override mode */
	data |=	BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
	bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data);
	bcm_qspi_bspi_set_xfer_params(qspi, msg->read_opcode, 0, 0, 0);
	bcm_qspi_bspi_set_xfer_params(qspi, op->cmd.opcode, 0, 0, 0);

	return 0;
}

static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
				  struct spi_flash_read_message *msg, int hp)
				  const struct spi_mem_op *op, int hp)
{
	int error = 0;
	int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
	int addrlen = msg->addr_width;
	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
	int addrlen = op->addr.nbytes;

	/* default mode */
	qspi->xfer_mode.flex_mode = true;
@@ -460,12 +458,12 @@ static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
		if (val & mask || qspi->s3_strap_override_ctrl & mask) {
			qspi->xfer_mode.flex_mode = false;
			bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0);
			error = bcm_qspi_bspi_set_override(qspi, msg, hp);
			error = bcm_qspi_bspi_set_override(qspi, op, hp);
		}
	}

	if (qspi->xfer_mode.flex_mode)
		error = bcm_qspi_bspi_set_flex_mode(qspi, msg, hp);
		error = bcm_qspi_bspi_set_flex_mode(qspi, op, hp);

	if (error) {
		dev_warn(&qspi->pdev->dev,
@@ -794,19 +792,20 @@ static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
	return slot;
}

static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
				    struct spi_flash_read_message *msg)
static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
				     const struct spi_mem_op *op)
{
	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
	u32 addr = 0, len, rdlen, len_words;
	u32 addr = 0, len, rdlen, len_words, from = 0;
	int ret = 0;
	unsigned long timeo = msecs_to_jiffies(100);
	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;

	if (bcm_qspi_bspi_ver_three(qspi))
		if (msg->addr_width == BSPI_ADDRLEN_4BYTES)
		if (op->addr.nbytes == BSPI_ADDRLEN_4BYTES)
			return -EIO;

	from = op->addr.val;
	bcm_qspi_chip_select(qspi, spi->chip_select);
	bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);

@@ -815,15 +814,15 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
	 * the upper address byte to bspi
	 */
	if (bcm_qspi_bspi_ver_three(qspi) == false) {
		addr = msg->from & 0xff000000;
		addr = from & 0xff000000;
		bcm_qspi_write(qspi, BSPI,
			       BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr);
	}

	if (!qspi->xfer_mode.flex_mode)
		addr = msg->from;
		addr = from;
	else
		addr = msg->from & 0x00ffffff;
		addr = from & 0x00ffffff;

	if (bcm_qspi_bspi_ver_three(qspi) == true)
		addr = (addr + 0xc00000) & 0xffffff;
@@ -832,8 +831,8 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
	 * read into the entire buffer by breaking the reads
	 * into RAF buffer read lengths
	 */
	len = msg->len;
	qspi->bspi_rf_msg_idx = 0;
	len = op->data.nbytes;
	qspi->bspi_rf_op_idx = 0;

	do {
		if (len > BSPI_READ_LENGTH)
@@ -844,9 +843,9 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
		reinit_completion(&qspi->bspi_done);
		bcm_qspi_enable_bspi(qspi);
		len_words = (rdlen + 3) >> 2;
		qspi->bspi_rf_msg = msg;
		qspi->bspi_rf_msg_status = 0;
		qspi->bspi_rf_msg_len = rdlen;
		qspi->bspi_rf_op = op;
		qspi->bspi_rf_op_status = 0;
		qspi->bspi_rf_op_len = rdlen;
		dev_dbg(&qspi->pdev->dev,
			"bspi xfr addr 0x%x len 0x%x", addr, rdlen);
		bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr);
@@ -871,7 +870,6 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
		}

		/* set msg return length */
		msg->retlen += rdlen;
		addr += rdlen;
		len -= rdlen;
	} while (len);
@@ -906,61 +904,62 @@ static int bcm_qspi_transfer_one(struct spi_master *master,
	return 0;
}

static int bcm_qspi_mspi_flash_read(struct spi_device *spi,
				    struct spi_flash_read_message *msg)
static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
				     const struct spi_mem_op *op)
{
	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
	struct spi_master *master = spi->master;
	struct bcm_qspi *qspi = spi_master_get_devdata(master);
	struct spi_transfer t[2];
	u8 cmd[6];
	int ret;
	u8 cmd[6] = { };
	int ret, i;

	memset(cmd, 0, sizeof(cmd));
	memset(t, 0, sizeof(t));

	/* tx */
	/* opcode is in cmd[0] */
	cmd[0] = msg->read_opcode;
	cmd[1] = msg->from >> (msg->addr_width * 8 -  8);
	cmd[2] = msg->from >> (msg->addr_width * 8 - 16);
	cmd[3] = msg->from >> (msg->addr_width * 8 - 24);
	cmd[4] = msg->from >> (msg->addr_width * 8 - 32);
	cmd[0] = op->cmd.opcode;
	for (i = 0; i < op->addr.nbytes; i++)
		cmd[1 + i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1));

	t[0].tx_buf = cmd;
	t[0].len = msg->addr_width + msg->dummy_bytes + 1;
	t[0].len = op->addr.nbytes + op->dummy.nbytes + 1;
	t[0].bits_per_word = spi->bits_per_word;
	t[0].tx_nbits = msg->opcode_nbits;
	t[0].tx_nbits = op->cmd.buswidth;
	/* lets mspi know that this is not last transfer */
	qspi->trans_pos.mspi_last_trans = false;
	ret = bcm_qspi_transfer_one(spi->master, spi, &t[0]);
	ret = bcm_qspi_transfer_one(master, spi, &t[0]);

	/* rx */
	qspi->trans_pos.mspi_last_trans = true;
	if (!ret) {
		/* rx */
		t[1].rx_buf = msg->buf;
		t[1].len = msg->len;
		t[1].rx_nbits =  msg->data_nbits;
		t[1].rx_buf = op->data.buf.in;
		t[1].len = op->data.nbytes;
		t[1].rx_nbits =  op->data.buswidth;
		t[1].bits_per_word = spi->bits_per_word;
		ret = bcm_qspi_transfer_one(spi->master, spi, &t[1]);
		ret = bcm_qspi_transfer_one(master, spi, &t[1]);
	}

	if (!ret)
		msg->retlen = msg->len;

	return ret;
}

static int bcm_qspi_flash_read(struct spi_device *spi,
			       struct spi_flash_read_message *msg)
static int bcm_qspi_exec_mem_op(struct spi_device *spi,
				const struct spi_mem_op *op)
{
	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
	int ret = 0;
	bool mspi_read = false;
	u32 addr, len;
	u32 addr = 0, len;
	u_char *buf;

	buf = msg->buf;
	addr = msg->from;
	len = msg->len;
	if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 ||
	    op->data.dir != SPI_MEM_DATA_IN)
		return -ENOTSUPP;

	buf = op->data.buf.in;
	addr = op->addr.val;
	len = op->data.nbytes;

	if (bcm_qspi_bspi_ver_three(qspi) == true) {
		/*
@@ -982,12 +981,40 @@ static int bcm_qspi_flash_read(struct spi_device *spi,
		mspi_read = true;

	if (mspi_read)
		return bcm_qspi_mspi_flash_read(spi, msg);
		return bcm_qspi_mspi_exec_mem_op(spi, op);

	ret = bcm_qspi_bspi_set_mode(qspi, msg, -1);
	ret = bcm_qspi_bspi_set_mode(qspi, op, -1);

	if (!ret)
		ret = bcm_qspi_bspi_flash_read(spi, msg);
		ret = bcm_qspi_bspi_exec_mem_op(spi, op);

	return ret;
}

static int bcm_qspi_exec_mem_op_wrapper(struct spi_mem *mem,
					const struct spi_mem_op *op)
{
	return bcm_qspi_exec_mem_op(mem->spi, op);
}

static int bcm_qspi_flash_read_wrapper(struct spi_device *spi,
				       struct spi_flash_read_message *msg)
{
	int ret;
	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(msg->read_opcode, 1),
					  SPI_MEM_OP_ADDR(msg->addr_width,
							  msg->from,
							  msg->addr_nbits),
					  SPI_MEM_OP_DUMMY(msg->dummy_bytes,
							   msg->addr_nbits),
					  SPI_MEM_OP_DATA_IN(msg->len,
							     msg->buf,
							     msg->data_nbits));

	msg->retlen = 0;
	ret = bcm_qspi_exec_mem_op(spi, &op);
	if (!ret)
		msg->retlen = msg->len;

	return ret;
}
@@ -1026,10 +1053,10 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
	u32 status = qspi_dev_id->irqp->mask;

	if (qspi->bspi_enabled && qspi->bspi_rf_msg) {
	if (qspi->bspi_enabled && qspi->bspi_rf_op) {
		bcm_qspi_bspi_lr_data_read(qspi);
		if (qspi->bspi_rf_msg_len == 0) {
			qspi->bspi_rf_msg = NULL;
		if (qspi->bspi_rf_op_len == 0) {
			qspi->bspi_rf_op = NULL;
			if (qspi->soc_intc) {
				/* disable soc BSPI interrupt */
				soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE,
@@ -1038,7 +1065,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
				status = INTR_BSPI_LR_SESSION_DONE_MASK;
			}

			if (qspi->bspi_rf_msg_status)
			if (qspi->bspi_rf_op_status)
				bcm_qspi_bspi_lr_clear(qspi);
			else
				bcm_qspi_bspi_flush_prefetch_buffers(qspi);
@@ -1050,7 +1077,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
	}

	status &= INTR_BSPI_LR_SESSION_DONE_MASK;
	if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0)
	if (qspi->bspi_enabled && status && qspi->bspi_rf_op_len == 0)
		complete(&qspi->bspi_done);

	return IRQ_HANDLED;
@@ -1063,7 +1090,7 @@ static irqreturn_t bcm_qspi_bspi_lr_err_l2_isr(int irq, void *dev_id)
	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;

	dev_err(&qspi->pdev->dev, "BSPI INT error\n");
	qspi->bspi_rf_msg_status = -EIO;
	qspi->bspi_rf_op_status = -EIO;
	if (qspi->soc_intc)
		/* clear soc interrupt */
		soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR);
@@ -1186,6 +1213,10 @@ static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)

}

static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
	.exec_op = bcm_qspi_exec_mem_op_wrapper,
};

static const struct of_device_id bcm_qspi_of_match[] = {
	{ .compatible = "brcm,spi-bcm-qspi" },
	{},
@@ -1228,7 +1259,8 @@ int bcm_qspi_probe(struct platform_device *pdev,
	master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD;
	master->setup = bcm_qspi_setup;
	master->transfer_one = bcm_qspi_transfer_one;
	master->spi_flash_read = bcm_qspi_flash_read;
	master->spi_flash_read = bcm_qspi_flash_read_wrapper;
	master->mem_ops = &bcm_qspi_mem_ops;
	master->cleanup = bcm_qspi_cleanup;
	master->dev.of_node = dev->of_node;
	master->num_chipselect = NUM_CHIPSELECT;