[PATCH v4 1/6] spi: aspeed: add AST2700 support
Ryan Chen
ryan_chen at aspeedtech.com
Fri Jun 12 11:43:08 CEST 2026
AST2700 is a 64-bit SoC whose flash AHB windows are decoded above
the 32-bit address space, so rework AHB addresses to uintptr_t and
decoded window sizes to size_t.
Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
---
drivers/spi/spi-aspeed-smc.c | 219 +++++++++++++++++++++++++++++++------------
1 file changed, 158 insertions(+), 61 deletions(-)
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index ca29cfd7c88..0186b01ad9a 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -53,18 +53,20 @@ struct aspeed_spi_regs {
u32 dma_len; /* 0x8c DMA Length Register */
u32 dma_checksum; /* 0x90 Checksum Calculation Result */
u32 timings[ASPEED_SPI_MAX_CS]; /* 0x94 Read Timing Compensation */
+ u32 _reserved3[83]; /* 0xA8 - 0x1F0 */
+ u32 val_kept_wdt; /* 0x1F4 Value Kept WDT */
};
struct aspeed_spi_plat {
u8 max_cs;
- void __iomem *ahb_base; /* AHB address base for all flash devices. */
+ uintptr_t ahb_base; /* AHB address base for all flash devices. */
fdt_size_t ahb_sz; /* Overall AHB window size for all flash device. */
u32 hclk_rate; /* AHB clock rate */
};
struct aspeed_spi_flash {
- void __iomem *ahb_base;
- u32 ahb_decoded_sz;
+ uintptr_t ahb_base;
+ size_t ahb_decoded_sz;
u32 ce_ctrl_user;
u32 ce_ctrl_read;
u32 max_freq;
@@ -84,9 +86,9 @@ struct aspeed_spi_info {
u32 min_decoded_sz;
u32 clk_ctrl_mask;
void (*set_4byte)(struct udevice *bus, u32 cs);
- u32 (*segment_start)(struct udevice *bus, u32 reg);
- u32 (*segment_end)(struct udevice *bus, u32 reg);
- u32 (*segment_reg)(u32 start, u32 end);
+ uintptr_t (*segment_start)(struct udevice *bus, u32 reg);
+ uintptr_t (*segment_end)(struct udevice *bus, u32 reg);
+ u32 (*segment_reg)(uintptr_t start, uintptr_t end);
int (*adjust_decoded_sz)(struct udevice *bus);
u32 (*get_clk_setting)(struct udevice *dev, uint hz);
};
@@ -118,30 +120,30 @@ static u32 aspeed_spi_get_io_mode(u32 bus_width)
}
}
-static u32 ast2400_spi_segment_start(struct udevice *bus, u32 reg)
+static uintptr_t ast2400_spi_segment_start(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 start_offset = ((reg >> 16) & 0xff) << 23;
+ uintptr_t start_offset = ((reg >> 16) & 0xff) << 23;
if (start_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + start_offset;
+ return plat->ahb_base + start_offset;
}
-static u32 ast2400_spi_segment_end(struct udevice *bus, u32 reg)
+static uintptr_t ast2400_spi_segment_end(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 end_offset = ((reg >> 24) & 0xff) << 23;
+ uintptr_t end_offset = ((reg >> 24) & 0xff) << 23;
/* Meaningless end_offset, set to physical ahb base. */
if (end_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + end_offset;
+ return plat->ahb_base + end_offset;
}
-static u32 ast2400_spi_segment_reg(u32 start, u32 end)
+static u32 ast2400_spi_segment_reg(uintptr_t start, uintptr_t end)
{
if (start == end)
return 0;
@@ -206,30 +208,30 @@ static u32 ast2400_get_clk_setting(struct udevice *dev, uint max_hz)
return hclk_div;
}
-static u32 ast2500_spi_segment_start(struct udevice *bus, u32 reg)
+static uintptr_t ast2500_spi_segment_start(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 start_offset = ((reg >> 16) & 0xff) << 23;
+ uintptr_t start_offset = ((reg >> 16) & 0xff) << 23;
if (start_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + start_offset;
+ return plat->ahb_base + start_offset;
}
-static u32 ast2500_spi_segment_end(struct udevice *bus, u32 reg)
+static uintptr_t ast2500_spi_segment_end(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 end_offset = ((reg >> 24) & 0xff) << 23;
+ uintptr_t end_offset = ((reg >> 24) & 0xff) << 23;
/* Meaningless end_offset, set to physical ahb base. */
if (end_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + end_offset;
+ return plat->ahb_base + end_offset;
}
-static u32 ast2500_spi_segment_reg(u32 start, u32 end)
+static u32 ast2500_spi_segment_reg(uintptr_t start, uintptr_t end)
{
if (start == end)
return 0;
@@ -346,30 +348,30 @@ end:
return hclk_div;
}
-static u32 ast2600_spi_segment_start(struct udevice *bus, u32 reg)
+static uintptr_t ast2600_spi_segment_start(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 start_offset = (reg << 16) & 0x0ff00000;
+ uintptr_t start_offset = (reg << 16) & 0x0ff00000;
if (start_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + start_offset;
+ return plat->ahb_base + start_offset;
}
-static u32 ast2600_spi_segment_end(struct udevice *bus, u32 reg)
+static uintptr_t ast2600_spi_segment_end(struct udevice *bus, u32 reg)
{
struct aspeed_spi_plat *plat = dev_get_plat(bus);
- u32 end_offset = reg & 0x0ff00000;
+ uintptr_t end_offset = reg & 0x0ff00000;
/* Meaningless end_offset, set to physical ahb base. */
if (end_offset == 0)
- return (u32)plat->ahb_base;
+ return plat->ahb_base;
- return (u32)plat->ahb_base + end_offset + 0x100000;
+ return plat->ahb_base + end_offset + 0x100000;
}
-static u32 ast2600_spi_segment_reg(u32 start, u32 end)
+static u32 ast2600_spi_segment_reg(uintptr_t start, uintptr_t end)
{
if (start == end)
return 0;
@@ -473,6 +475,70 @@ static u32 ast2600_get_clk_setting(struct udevice *dev, uint max_hz)
return hclk_div;
}
+static uintptr_t ast2700_spi_segment_start(struct udevice *bus, u32 reg)
+{
+ struct aspeed_spi_plat *plat = dev_get_plat(bus);
+ uintptr_t start_offset = (reg & 0x0000ffff) << 16;
+
+ if (start_offset == 0)
+ return plat->ahb_base;
+
+ return plat->ahb_base + start_offset;
+}
+
+static uintptr_t ast2700_spi_segment_end(struct udevice *bus, u32 reg)
+{
+ struct aspeed_spi_plat *plat = dev_get_plat(bus);
+ uintptr_t end_offset = reg & 0xffff0000;
+
+ /* Meaningless end_offset, set to physical ahb base. */
+ if (end_offset == 0)
+ return plat->ahb_base;
+
+ return plat->ahb_base + end_offset;
+}
+
+static u32 ast2700_spi_segment_reg(uintptr_t start, uintptr_t end)
+{
+ if (start == end)
+ return 0;
+
+ return (((start >> 16) & 0x7fff) | ((end + 1) & 0x7fff0000));
+}
+
+static void ast2700_spi_chip_set_4byte(struct udevice *bus, u32 cs)
+{
+ struct aspeed_spi_priv *priv = dev_get_priv(bus);
+ u32 reg_val;
+
+ reg_val = readl(&priv->regs->ctrl);
+ reg_val |= 0x11 << cs;
+ writel(reg_val, &priv->regs->ctrl);
+
+ reg_val = readl(&priv->regs->val_kept_wdt);
+ reg_val |= (0x11 << 4) << cs;
+ writel(reg_val, &priv->regs->val_kept_wdt);
+}
+
+static int ast2700_adjust_decoded_size(struct udevice *bus)
+{
+ struct aspeed_spi_plat *plat = dev_get_plat(bus);
+ struct aspeed_spi_priv *priv = dev_get_priv(bus);
+ struct aspeed_spi_flash *flashes = &priv->flashes[0];
+ int ret;
+ int cs;
+
+ /* Close unused CS. */
+ for (cs = priv->num_cs; cs < plat->max_cs; cs++)
+ flashes[cs].ahb_decoded_sz = 0;
+
+ ret = aspeed_spi_trim_decoded_size(bus);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
/*
* As the flash size grows up, we need to trim some decoded
* size if needed for the sake of conforming the maximum
@@ -512,12 +578,12 @@ static int aspeed_spi_trim_decoded_size(struct udevice *bus)
return 0;
}
-static int aspeed_spi_read_from_ahb(void __iomem *ahb_base, void *buf,
+static int aspeed_spi_read_from_ahb(uintptr_t ahb_base, void *buf,
size_t len)
{
size_t offset = 0;
- if (IS_ALIGNED((uintptr_t)ahb_base, sizeof(uintptr_t)) &&
+ if (IS_ALIGNED(ahb_base, sizeof(uintptr_t)) &&
IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) {
readsl(ahb_base, buf, len >> 2);
offset = len & ~0x3;
@@ -529,12 +595,12 @@ static int aspeed_spi_read_from_ahb(void __iomem *ahb_base, void *buf,
return 0;
}
-static int aspeed_spi_write_to_ahb(void __iomem *ahb_base, const void *buf,
+static int aspeed_spi_write_to_ahb(uintptr_t ahb_base, const void *buf,
size_t len)
{
size_t offset = 0;
- if (IS_ALIGNED((uintptr_t)ahb_base, sizeof(uintptr_t)) &&
+ if (IS_ALIGNED(ahb_base, sizeof(uintptr_t)) &&
IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) {
writesl(ahb_base, buf, len >> 2);
offset = len & ~0x3;
@@ -589,7 +655,7 @@ static int aspeed_spi_exec_op_user_mode(struct spi_slave *slave,
struct aspeed_spi_priv *priv = dev_get_priv(bus);
struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(slave->dev);
u32 cs = slave_plat->cs[0];
- u32 ce_ctrl_reg = (u32)&priv->regs->ce_ctrl[cs];
+ uintptr_t ce_ctrl_reg = (uintptr_t)&priv->regs->ce_ctrl[cs];
u32 ce_ctrl_val;
struct aspeed_spi_flash *flash = &priv->flashes[cs];
u8 dummy_data[16] = {0};
@@ -602,7 +668,7 @@ static int aspeed_spi_exec_op_user_mode(struct spi_slave *slave,
op->data.nbytes, op->data.buswidth);
if (priv->info == &ast2400_spi_info)
- ce_ctrl_reg = (u32)&priv->regs->ctrl;
+ ce_ctrl_reg = (uintptr_t)&priv->regs->ctrl;
/*
* Set controller to 4-byte address mode
@@ -670,7 +736,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
u32 i;
u32 cs = slave_plat->cs[0];
u32 cmd_io_conf;
- u32 ce_ctrl_reg;
+ uintptr_t ce_ctrl_reg;
if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) {
/*
@@ -681,9 +747,9 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
return -EOPNOTSUPP;
}
- ce_ctrl_reg = (u32)&priv->regs->ce_ctrl[cs];
+ ce_ctrl_reg = (uintptr_t)&priv->regs->ce_ctrl[cs];
if (info == &ast2400_spi_info)
- ce_ctrl_reg = (u32)&priv->regs->ctrl;
+ ce_ctrl_reg = (uintptr_t)&priv->regs->ctrl;
if (desc->info.length > 0x1000000)
priv->info->set_4byte(bus, cs);
@@ -693,7 +759,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
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,
+ dev_dbg(dev, "cs: %d, sz: 0x%zx\n", i,
priv->flashes[cs].ahb_decoded_sz);
}
@@ -728,7 +794,7 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
u32 cs = slave_plat->cs[0];
int ret;
- dev_dbg(dev, "read op:0x%x, addr:0x%llx, len:0x%x\n",
+ dev_dbg(dev, "read op:0x%x, addr:0x%llx, len:0x%zx\n",
desc->info.op_tmpl.cmd.opcode, offs, len);
if (priv->flashes[cs].ahb_decoded_sz < offs + len ||
@@ -738,7 +804,10 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
if (ret != 0)
return 0;
} else {
- memcpy_fromio(buf, priv->flashes[cs].ahb_base + offs, len);
+ memcpy_fromio(buf,
+ (void __iomem *)(priv->flashes[cs].ahb_base +
+ (uintptr_t)offs),
+ len);
}
return len;
@@ -783,19 +852,19 @@ static void aspeed_spi_decoded_range_set(struct udevice *bus)
struct aspeed_spi_plat *plat = dev_get_plat(bus);
struct aspeed_spi_priv *priv = dev_get_priv(bus);
u32 decoded_reg_val;
- u32 start_addr, end_addr;
+ uintptr_t start_addr, end_addr;
u32 cs;
for (cs = 0; cs < plat->max_cs; cs++) {
- start_addr = (u32)priv->flashes[cs].ahb_base;
- end_addr = (u32)priv->flashes[cs].ahb_base +
+ start_addr = priv->flashes[cs].ahb_base;
+ end_addr = priv->flashes[cs].ahb_base +
priv->flashes[cs].ahb_decoded_sz;
decoded_reg_val = priv->info->segment_reg(start_addr, end_addr);
writel(decoded_reg_val, &priv->regs->segment_addr[cs]);
- dev_dbg(bus, "cs: %d, decoded_reg: 0x%x, start: 0x%x, end: 0x%x\n",
+ dev_dbg(bus, "cs: %d, decoded_reg: 0x%x, start: 0x%lx, end: 0x%lx\n",
cs, decoded_reg_val, start_addr, end_addr);
}
}
@@ -851,13 +920,13 @@ static int aspeed_spi_decoded_ranges_sanity(struct udevice *bus)
* address base are monotonic increasing with CE#.
*/
for (cs = plat->max_cs - 1; cs > 0; cs--) {
- if ((u32)priv->flashes[cs].ahb_base != 0 &&
- (u32)priv->flashes[cs].ahb_base <
- (u32)priv->flashes[cs - 1].ahb_base +
+ if (priv->flashes[cs].ahb_base != 0 &&
+ priv->flashes[cs].ahb_base <
+ priv->flashes[cs - 1].ahb_base +
priv->flashes[cs - 1].ahb_decoded_sz) {
- dev_err(bus, "decoded range overlay 0x%08x 0x%08x\n",
- (u32)priv->flashes[cs].ahb_base,
- (u32)priv->flashes[cs - 1].ahb_base);
+ dev_err(bus, "decoded range overlay 0x%08lx 0x%08lx\n",
+ priv->flashes[cs].ahb_base,
+ priv->flashes[cs - 1].ahb_base);
return -EINVAL;
}
}
@@ -895,14 +964,13 @@ static int aspeed_spi_read_fixed_decoded_ranges(struct udevice *bus)
return ret;
for (i = 0; i < count; i++) {
- priv->flashes[ranges[i].cs].ahb_base =
- (void __iomem *)ranges[i].ahb_base;
+ priv->flashes[ranges[i].cs].ahb_base = ranges[i].ahb_base;
priv->flashes[ranges[i].cs].ahb_decoded_sz =
ranges[i].sz;
}
for (i = 0; i < plat->max_cs; i++) {
- dev_dbg(bus, "ahb_base: 0x%p, size: 0x%08x\n",
+ dev_dbg(bus, "ahb_base: 0x%lx, size: 0x%08zx\n",
priv->flashes[i].ahb_base,
priv->flashes[i].ahb_decoded_sz);
}
@@ -1063,6 +1131,32 @@ static const struct aspeed_spi_info ast2600_spi_info = {
.get_clk_setting = ast2600_get_clk_setting,
};
+static const struct aspeed_spi_info ast2700_fmc_info = {
+ .io_mode_mask = 0xf0000000,
+ .max_bus_width = 4,
+ .min_decoded_sz = 0x10000,
+ .clk_ctrl_mask = 0x0f000f00,
+ .set_4byte = ast2700_spi_chip_set_4byte,
+ .segment_start = ast2700_spi_segment_start,
+ .segment_end = ast2700_spi_segment_end,
+ .segment_reg = ast2700_spi_segment_reg,
+ .adjust_decoded_sz = ast2700_adjust_decoded_size,
+ .get_clk_setting = ast2600_get_clk_setting,
+};
+
+static const struct aspeed_spi_info ast2700_spi_info = {
+ .io_mode_mask = 0xf0000000,
+ .max_bus_width = 4,
+ .min_decoded_sz = 0x10000,
+ .clk_ctrl_mask = 0x0f000f00,
+ .set_4byte = ast2700_spi_chip_set_4byte,
+ .segment_start = ast2700_spi_segment_start,
+ .segment_end = ast2700_spi_segment_end,
+ .segment_reg = ast2700_spi_segment_reg,
+ .adjust_decoded_sz = ast2700_adjust_decoded_size,
+ .get_clk_setting = ast2600_get_clk_setting,
+};
+
static int aspeed_spi_claim_bus(struct udevice *dev)
{
struct udevice *bus = dev->parent;
@@ -1129,7 +1223,8 @@ static int apseed_spi_of_to_plat(struct udevice *bus)
return -EINVAL;
}
- plat->ahb_base = devfdt_get_addr_size_index_ptr(bus, 1, &plat->ahb_sz);
+ plat->ahb_base =
+ (uintptr_t)devfdt_get_addr_size_index_ptr(bus, 1, &plat->ahb_sz);
if (!plat->ahb_base) {
dev_err(bus, "wrong AHB base\n");
return -EINVAL;
@@ -1147,8 +1242,8 @@ static int apseed_spi_of_to_plat(struct udevice *bus)
plat->hclk_rate = clk_get_rate(&hclk);
- dev_dbg(bus, "ctrl_base = 0x%x, ahb_base = 0x%p, size = 0x%llx\n",
- (u32)priv->regs, plat->ahb_base, (fdt64_t)plat->ahb_sz);
+ dev_dbg(bus, "ctrl_base = 0x%p, ahb_base = 0x%lx, size = 0x%llx\n",
+ priv->regs, plat->ahb_base, (fdt64_t)plat->ahb_sz);
dev_dbg(bus, "hclk = %dMHz, max_cs = %d\n",
plat->hclk_rate / 1000000, plat->max_cs);
@@ -1199,6 +1294,8 @@ static const struct udevice_id aspeed_spi_ids[] = {
{ .compatible = "aspeed,ast2500-spi", .data = (ulong)&ast2500_spi_info, },
{ .compatible = "aspeed,ast2600-fmc", .data = (ulong)&ast2600_fmc_info, },
{ .compatible = "aspeed,ast2600-spi", .data = (ulong)&ast2600_spi_info, },
+ { .compatible = "aspeed,ast2700-fmc", .data = (ulong)&ast2700_fmc_info, },
+ { .compatible = "aspeed,ast2700-spi", .data = (ulong)&ast2700_spi_info, },
{ }
};
--
2.34.1
More information about the U-Boot
mailing list