linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Chuanhong Guo <gch981213@gmail.com>
To: linux-mtd@lists.infradead.org
Cc: Vignesh Raghavendra <vigneshr@ti.com>,
	Tudor Ambarus <tudor.ambarus@microchip.com>,
	Richard Weinberger <richard@nod.at>,
	linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	Miquel Raynal <miquel.raynal@bootlin.com>,
	Matthias Brugger <matthias.bgg@gmail.com>,
	Chuanhong Guo <gch981213@gmail.com>,
	linux-arm-kernel@lists.infradead.org
Subject: [PATCH 2/2] mtd: mtk-quadspi: misuse 1_1_2 read mode for custom read opcode
Date: Sun, 10 Nov 2019 13:21:01 +0800	[thread overview]
Message-ID: <20191110052104.5502-2-gch981213@gmail.com> (raw)
In-Reply-To: <20191110052104.5502-1-gch981213@gmail.com>

1_1_1 reading mode on this controller only support 0x03 and 0x0b
as opcode, but spi-nor framework uses nor->read for SFDP reading
as well.
Add a check for opcode and if it's not supported, misuse 1_1_2
reading and extract corresponding bits from returned data.

Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---
 drivers/mtd/spi-nor/mtk-quadspi.c | 78 ++++++++++++++++++++++++++++++-
 1 file changed, 76 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c
index ac0e531ce80c..46bf27c0e6e8 100644
--- a/drivers/mtd/spi-nor/mtk-quadspi.c
+++ b/drivers/mtd/spi-nor/mtk-quadspi.c
@@ -357,8 +357,8 @@ static ssize_t mtk_nor_read_dma_bounce(struct mtk_nor *mtk_nor, loff_t from,
 	return length;
 }
 
-static ssize_t mtk_nor_read(struct spi_nor *nor, loff_t from, size_t length,
-			    u_char *buffer)
+static ssize_t mtk_nor_flash_read(struct spi_nor *nor, loff_t from,
+				  size_t length, u_char *buffer)
 {
 	struct mtk_nor *mtk_nor = nor->priv;
 
@@ -372,6 +372,80 @@ static ssize_t mtk_nor_read(struct spi_nor *nor, loff_t from, size_t length,
 	return mtk_nor_read_dma(mtk_nor, from, length, buffer);
 }
 
+static ssize_t mtk_nor_generic_read(struct spi_nor *nor, loff_t from,
+				    size_t length, u_char *buffer)
+{
+	struct mtk_nor *mtk_nor = nor->priv;
+	ssize_t nor_unaligned_len = from % MTK_NOR_DMA_ALIGN;
+	loff_t read_from = from & ~(MTK_NOR_DMA_ALIGN - 1);
+	ssize_t read_len;
+	u_char *buf, *bouncebuf, tmp;
+	size_t mem_unaligned_len, i;
+	dma_addr_t dma_addr;
+	int ret;
+
+	if (length > MTK_NOR_MAX_BBUF_READ / 2)
+		length = MTK_NOR_MAX_BBUF_READ / 2;
+	read_len = ((length + nor_unaligned_len) * 2 + MTK_NOR_DMA_ALIGN) &
+		   ~(MTK_NOR_DMA_ALIGN - 1);
+
+	buf = kmalloc(read_len + MTK_NOR_DMA_ALIGN, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	mem_unaligned_len = (u32)buf % MTK_NOR_DMA_ALIGN;
+	bouncebuf = (buf + MTK_NOR_DMA_ALIGN) - mem_unaligned_len;
+
+	writeb(nor->read_opcode, mtk_nor->base + MTK_NOR_PRGDATA3_REG);
+	writeb(MTK_NOR_DUAL_READ_EN, mtk_nor->base + MTK_NOR_DUAL_REG);
+	mtk_nor_set_addr_width(mtk_nor);
+
+	dma_addr = dma_map_single(mtk_nor->dev, bouncebuf, read_len,
+				  DMA_FROM_DEVICE);
+	ret = dma_mapping_error(mtk_nor->dev, dma_addr);
+	if (ret) {
+		dev_err(mtk_nor->dev, "failed to map dma buffer.");
+		goto err;
+	}
+
+	writel(read_from, mtk_nor->base + MTK_NOR_FDMA_FADR_REG);
+	writel(dma_addr, mtk_nor->base + MTK_NOR_FDMA_DADR_REG);
+	writel((u32)dma_addr + read_len,
+	       mtk_nor->base + MTK_NOR_FDMA_END_DADR_REG);
+	ret = mtk_nor_dma_exec(mtk_nor);
+	dma_unmap_single(mtk_nor->dev, dma_addr, read_len, DMA_FROM_DEVICE);
+
+	if (ret)
+		goto err;
+
+	/* extract bits from DO line */
+	for (i = 0; i < length; i++) {
+		tmp = bouncebuf[(i + nor_unaligned_len) * 2];
+		buffer[i] = (tmp & BIT(7)) | ((tmp & BIT(5)) << 1) |
+			    ((tmp & BIT(3)) << 2) | ((tmp & BIT(1)) << 3);
+		tmp = bouncebuf[(i + nor_unaligned_len) * 2 + 1];
+		buffer[i] |= (tmp & BIT(7)) >> 4 | ((tmp & BIT(5)) >> 3) |
+			     ((tmp & BIT(3)) >> 2) | ((tmp & BIT(1)) >> 1);
+	}
+	ret = length;
+err:
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t mtk_nor_read(struct spi_nor *nor, loff_t from, size_t length,
+			    u_char *buffer)
+{
+	if ((nor->read_proto != SNOR_PROTO_1_1_1) ||
+	    (nor->read_opcode == SPINOR_OP_READ) ||
+	    (nor->read_opcode == SPINOR_OP_READ_FAST))
+		return mtk_nor_flash_read(nor, from, length, buffer);
+	else if (nor->read_dummy == 8)
+		return mtk_nor_generic_read(nor, from, length, buffer);
+	else
+		return -EOPNOTSUPP;
+}
+
 static int mtk_nor_write_single_byte(struct mtk_nor *mtk_nor,
 				     int addr, int length, u8 *data)
 {
-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2019-11-10  5:22 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-10  5:21 [PATCH 1/2] mtd: mtk-quadspi: add support for DMA reading Chuanhong Guo
2019-11-10  5:21 ` Chuanhong Guo [this message]
2019-11-12  7:28 ` kbuild test robot
2019-11-14  8:19   ` Chuanhong Guo
2019-11-12  8:06 ` kbuild test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191110052104.5502-2-gch981213@gmail.com \
    --to=gch981213@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=matthias.bgg@gmail.com \
    --cc=miquel.raynal@bootlin.com \
    --cc=richard@nod.at \
    --cc=tudor.ambarus@microchip.com \
    --cc=vigneshr@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).