]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
spi: aspeed: add AST2700 support
authorRyan Chen <ryan_chen@aspeedtech.com>
Fri, 12 Jun 2026 09:43:08 +0000 (17:43 +0800)
committerTom Rini <trini@konsulko.com>
Mon, 29 Jun 2026 19:43:20 +0000 (13:43 -0600)
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@aspeedtech.com>
drivers/spi/spi-aspeed-smc.c

index ca29cfd7c88930a5761223fb58a75c30b3334324..0186b01ad9a8bb38154879bc0a8829c5b30558ac 100644 (file)
@@ -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, },
        { }
 };