[v5 09/14] spi: aspeed: SPI dirmap read support

Chin-Ting Kuo chin-ting_kuo at aspeedtech.com
Fri Aug 19 11:01:10 CEST 2022


>From the HW point of view, the performance of
command read mode is greater than user mode slightly.
Thus, dirmap read framework is introduced to achieve
this goal. In dirmap_create, command read mode is
configured. Usually, the decoded address area with flash
size is assigned to each CS. CPU can thus access the
SPI flash as normal memory in dirmap_read function.

Signed-off-by: Chin-Ting Kuo <chin-ting_kuo at aspeedtech.com>
---
 drivers/spi/spi-aspeed-smc.c | 88 ++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index f858d36023..6099b85255 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -87,6 +87,7 @@ struct aspeed_spi_info {
 };
 
 static const struct aspeed_spi_info ast2400_spi_info;
+static int aspeed_spi_decoded_range_config(struct udevice *bus);
 
 static u32 aspeed_spi_get_io_mode(u32 bus_width)
 {
@@ -381,6 +382,91 @@ static int aspeed_spi_exec_op_user_mode(struct spi_slave *slave,
 	return 0;
 }
 
+static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+	int ret = 0;
+	struct udevice *dev = desc->slave->dev;
+	struct udevice *bus = dev->parent;
+	struct aspeed_spi_priv *priv = dev_get_priv(bus);
+	struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
+	const struct aspeed_spi_info *info = priv->info;
+	struct spi_mem_op op_tmpl = desc->info.op_tmpl;
+	u32 i;
+	u32 cs = slave_plat->cs;
+	u32 reg_val;
+	u32 ce_ctrl_reg;
+
+	if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) {
+		/*
+		 * dirmap_write is not supported currently due to a HW
+		 * limitation for command write mode: The written data
+		 * length should be multiple of 4-byte.
+		 */
+		return -EOPNOTSUPP;
+	}
+
+	ce_ctrl_reg = (u32)&priv->regs->ce_ctrl[cs];
+	if (info == &ast2400_spi_info)
+		ce_ctrl_reg = (u32)&priv->regs->ctrl;
+
+	if (desc->info.length > 0x1000000)
+		priv->info->set_4byte(bus, cs);
+
+	/* AST2400 SPI1 doesn't have decoded address segment register. */
+	if (info != &ast2400_spi_info) {
+		priv->flashes[cs].ahb_decoded_sz = desc->info.length;
+
+		for (i = 0; i < priv->num_cs; i++) {
+			dev_dbg(dev, "cs: %d, sz: 0x%x\n", i,
+				priv->flashes[cs].ahb_decoded_sz);
+		}
+
+		ret = aspeed_spi_decoded_range_config(bus);
+		if (ret)
+			return ret;
+	}
+
+	reg_val = aspeed_spi_get_io_mode(op_tmpl.data.buswidth) |
+		  op_tmpl.cmd.opcode << 16 |
+		  ((op_tmpl.dummy.nbytes) & 0x3) << 6 |
+		  ((op_tmpl.dummy.nbytes) & 0x4) << 14 |
+		  CTRL_IO_MODE_CMD_READ;
+
+	writel(reg_val, ce_ctrl_reg);
+
+	priv->flashes[cs].ce_ctrl_read = reg_val;
+
+	dev_dbg(dev, "read bus width: %d ce_ctrl_val: 0x%08x\n",
+		op_tmpl.data.buswidth, priv->flashes[cs].ce_ctrl_read);
+
+	return ret;
+}
+
+static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
+				      u64 offs, size_t len, void *buf)
+{
+	struct udevice *dev = desc->slave->dev;
+	struct aspeed_spi_priv *priv = dev_get_priv(dev->parent);
+	struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
+	u32 cs = slave_plat->cs;
+	int ret;
+
+	dev_dbg(dev, "read op:0x%x, addr:0x%llx, len:0x%x\n",
+		desc->info.op_tmpl.cmd.opcode, offs, len);
+
+	if (priv->flashes[cs].ahb_decoded_sz < offs + len ||
+	    (offs % 4) != 0) {
+		ret = aspeed_spi_exec_op_user_mode(desc->slave,
+						   &desc->info.op_tmpl);
+		if (ret != 0)
+			return 0;
+	} else {
+		memcpy_fromio(buf, priv->flashes[cs].ahb_base + offs, len);
+	}
+
+	return len;
+}
+
 static struct aspeed_spi_flash *aspeed_spi_get_flash(struct udevice *dev)
 {
 	struct udevice *bus = dev->parent;
@@ -662,6 +748,8 @@ static int aspeed_spi_probe(struct udevice *bus)
 static const struct spi_controller_mem_ops aspeed_spi_mem_ops = {
 	.supports_op = aspeed_spi_supports_op,
 	.exec_op = aspeed_spi_exec_op_user_mode,
+	.dirmap_create = aspeed_spi_dirmap_create,
+	.dirmap_read = aspeed_spi_dirmap_read,
 };
 
 static const struct dm_spi_ops aspeed_spi_ops = {
-- 
2.25.1



More information about the U-Boot mailing list