mirror of https://github.com/torvalds/linux.git
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>
This commit is contained in:
parent
0586b53d4a
commit
64d87ccfae
|
|
@ -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;
|
||||
|
|
@ -394,6 +394,13 @@ static int aspeed_spi_set_window(struct aspeed_spi *aspi)
|
|||
u32 cs;
|
||||
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue