[PATCH v3 5/9] spi: bcm-qspi: Implement the spi_mem interface
Kamal Dasu
kdasu.kdev at gmail.com
Tue Apr 24 08:19:24 PDT 2018
On Sun, Apr 22, 2018 at 2:35 PM, Boris Brezillon
<boris.brezillon at bootlin.com> wrote:
> 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: Boris Brezillon <boris.brezillon at bootlin.com>
Reviewed-by: Kamal Dasu <kdasu.kdev at gmail.com>
Tested-by: Kamal Dasu <kdasu.kdev at gmail.com>
> ---
> Changes in v3:
> - none
>
> Changes in v2:
> - include spi-mem.h
> - treat op->addr.val differently since it's now an u64
> ---
> drivers/spi/spi-bcm-qspi.c | 190 ++++++++++++++++++++++++++-------------------
> 1 file changed, 111 insertions(+), 79 deletions(-)
>
> diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
> index 1596d35498c5..9f94268a68b5 100644
> --- a/drivers/spi/spi-bcm-qspi.c
> +++ b/drivers/spi/spi-bcm-qspi.c
> @@ -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;
> --
> 2.14.1
>
More information about the linux-mtd
mailing list