[PATCH 8/8] spi: aspeed: SPI dirmap read support
Chin-Ting Kuo
chin-ting_kuo at aspeedtech.com
Thu Apr 14 13:23:50 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, a specific 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>
---
configs/evb-ast2500_defconfig | 1 +
configs/evb-ast2600_defconfig | 1 +
drivers/spi/spi-aspeed.c | 93 +++++++++++++++++++++++++++++++++++
3 files changed, 95 insertions(+)
diff --git a/configs/evb-ast2500_defconfig b/configs/evb-ast2500_defconfig
index f00bded237..b702a92289 100644
--- a/configs/evb-ast2500_defconfig
+++ b/configs/evb-ast2500_defconfig
@@ -57,6 +57,7 @@ CONFIG_DM_SERIAL=y
CONFIG_SYS_NS16550=y
CONFIG_SPI=y
CONFIG_DM_SPI=y
+CONFIG_SPI_DIRMAP=y
CONFIG_SPI_ASPEED=y
CONFIG_SYSRESET=y
CONFIG_TIMER=y
diff --git a/configs/evb-ast2600_defconfig b/configs/evb-ast2600_defconfig
index e013976bb0..279e5a6238 100644
--- a/configs/evb-ast2600_defconfig
+++ b/configs/evb-ast2600_defconfig
@@ -90,6 +90,7 @@ CONFIG_DM_SERIAL=y
CONFIG_SYS_NS16550=y
CONFIG_SPI=y
CONFIG_DM_SPI=y
+CONFIG_SPI_DIRMAP=y
CONFIG_SPI_ASPEED=y
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
diff --git a/drivers/spi/spi-aspeed.c b/drivers/spi/spi-aspeed.c
index 9574aff793..e5e348eb7b 100644
--- a/drivers/spi/spi-aspeed.c
+++ b/drivers/spi/spi-aspeed.c
@@ -85,6 +85,8 @@ struct aspeed_spi_info {
static int aspeed_spi_trim_decoded_size(struct udevice *bus,
u32 decoded_sz_arr[]);
+static int aspeed_spi_decoded_range_config(struct udevice *bus,
+ u32 decoded_sz_arr[]);
static u32 aspeed_spi_get_io_mode(u32 bus_width)
{
@@ -509,6 +511,95 @@ 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_plat *plat = dev_get_plat(bus);
+ 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 decoded_sz_arr[ASPEED_SPI_MAX_CS];
+ u32 reg_val;
+
+ if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) {
+ for (i = 0; i < priv->num_cs; i++) {
+ reg_val = readl(plat->ctrl_base +
+ REG_CE0_DECODED_ADDR_REG + i * 4);
+ decoded_sz_arr[i] =
+ info->segment_end(bus, reg_val) -
+ info->segment_start(bus, reg_val);
+ }
+
+ decoded_sz_arr[cs] = desc->info.length;
+
+ if (info->adjust_decoded_sz)
+ info->adjust_decoded_sz(bus, decoded_sz_arr);
+
+ for (i = 0; i < priv->num_cs; i++) {
+ dev_dbg(dev, "cs: %d, sz: 0x%x\n", i,
+ decoded_sz_arr[i]);
+ }
+
+ ret = aspeed_spi_decoded_range_config(bus, decoded_sz_arr);
+ if (ret)
+ return ret;
+
+ reg_val = readl(plat->ctrl_base + REG_CE0_CTRL_REG + cs * 4) &
+ (~info->cmd_io_ctrl_mask);
+ 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,
+ plat->ctrl_base + REG_CE0_CTRL_REG + cs * 4);
+ priv->flashes[cs].ce_ctrl_read = reg_val;
+
+ dev_dbg(dev, "read bus width: %d [0x%08x]\n",
+ op_tmpl.data.buswidth, priv->flashes[cs].ce_ctrl_read);
+ } else {
+ /*
+ * 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;
+ }
+
+ 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_win_sz < offs + len ||
+ (offs + len) % 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;
@@ -792,6 +883,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