summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChin-Ting Kuo <chin-ting_kuo@aspeedtech.com>2025-10-01 19:26:05 +0800
committerMark Brown <broonie@kernel.org>2025-10-13 11:27:47 +0100
commit64d87ccfae3326a9561fe41dc6073064a083e0df (patch)
treefb7d3e54b982a75fcf38412f10b8b86963c25811
parent0586b53d4a0c7c5a132629f99da934cc674ea4cd (diff)
spi: aspeed: Only map necessary address window region
Previously, the driver mapped the entire SPI address decoding region during probe. On systems with small flash or limited memory, this could lead to excessive memory usage or allocation failures. This patch changes the strategy to initially map a small address window for SPI flash device probing. After determining each chip select's flash size, the driver unmaps the temporary region and remaps only the required address window accordingly. Signed-off-by: Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com> Link: https://patch.msgid.link/20251001112605.1130723-7-chin-ting_kuo@aspeedtech.com Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/spi-aspeed-smc.c39
1 files changed, 32 insertions, 7 deletions
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index 4f6ae48dd904..0c3de371fd39 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -7,6 +7,7 @@
*/
#include <linux/clk.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -96,7 +97,6 @@ struct aspeed_spi {
const struct aspeed_spi_data *data;
void __iomem *regs;
- void __iomem *ahb_base;
u32 ahb_base_phy;
u32 ahb_window_size;
u32 num_cs;
@@ -395,6 +395,13 @@ static int aspeed_spi_set_window(struct aspeed_spi *aspi)
size_t window_size;
for (cs = 0; cs < aspi->data->max_cs; cs++) {
+ if (aspi->chips[cs].ahb_base) {
+ iounmap(aspi->chips[cs].ahb_base);
+ aspi->chips[cs].ahb_base = NULL;
+ }
+ }
+
+ for (cs = 0; cs < aspi->data->max_cs; cs++) {
seg_reg = seg_reg_base + cs * 4;
seg_val_backup = readl(seg_reg);
@@ -425,13 +432,29 @@ static int aspeed_spi_set_window(struct aspeed_spi *aspi)
else
dev_dbg(dev, "CE%d window closed\n", cs);
- aspi->chips[cs].ahb_base = aspi->ahb_base + offset;
offset += window_size;
if (offset > aspi->ahb_window_size) {
dev_err(dev, "CE%d offset value 0x%llx is too large.\n",
cs, (u64)offset);
return -ENOSPC;
}
+
+ /*
+ * No need to map the address deocding range when
+ * - window size is 0.
+ * - the CS is unused.
+ */
+ if (window_size == 0 || cs >= aspi->num_cs)
+ continue;
+
+ aspi->chips[cs].ahb_base =
+ devm_ioremap(aspi->dev, start, window_size);
+ if (!aspi->chips[cs].ahb_base) {
+ dev_err(aspi->dev,
+ "Fail to remap window [0x%.9llx - 0x%.9llx]\n",
+ (u64)start, (u64)end - 1);
+ return -ENOMEM;
+ }
}
return 0;
@@ -447,7 +470,9 @@ static int aspeed_spi_chip_set_default_window(struct aspeed_spi *aspi)
/* No segment registers for the AST2400 SPI controller */
if (aspi->data == &ast2400_spi_data) {
- aspi->chips[0].ahb_base = aspi->ahb_base;
+ aspi->chips[0].ahb_base = devm_ioremap(aspi->dev,
+ aspi->ahb_base_phy,
+ aspi->ahb_window_size);
aspi->chips[0].ahb_window_size = aspi->ahb_window_size;
return 0;
}
@@ -839,10 +864,10 @@ static int aspeed_spi_probe(struct platform_device *pdev)
if (IS_ERR(aspi->regs))
return PTR_ERR(aspi->regs);
- aspi->ahb_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
- if (IS_ERR(aspi->ahb_base)) {
- dev_err(dev, "missing AHB mapping window\n");
- return PTR_ERR(aspi->ahb_base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (IS_ERR(res)) {
+ dev_err(dev, "missing AHB memory\n");
+ return PTR_ERR(res);
}
aspi->ahb_window_size = resource_size(res);