[v5 12/14] spi: aspeed: Support customized decoded address ranges
Chin-Ting Kuo
chin-ting_kuo at aspeedtech.com
Fri Aug 19 11:01:13 CEST 2022
If "decoded-ranges" is defined in the device tree, the
driver will apply the decoded address ranges from this
property to the controller during probe stage.
This patch refers to the following OpenBMC u-boot patch.
https://patchwork.ozlabs.org/project/openbmc/list/?series=306969
Signed-off-by: Chin-Ting Kuo <chin-ting_kuo at aspeedtech.com>
---
drivers/spi/spi-aspeed-smc.c | 136 ++++++++++++++++++++++++++++++++---
1 file changed, 127 insertions(+), 9 deletions(-)
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index 4287f5d8c0..2b6c4b48bd 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -74,6 +74,7 @@ struct aspeed_spi_priv {
struct aspeed_spi_regs *regs;
struct aspeed_spi_info *info;
struct aspeed_spi_flash flashes[ASPEED_SPI_MAX_CS];
+ bool fixed_decoded_range;
};
struct aspeed_spi_info {
@@ -87,7 +88,15 @@ struct aspeed_spi_info {
int (*adjust_decoded_sz)(struct udevice *bus);
};
+struct aspeed_spi_decoded_range {
+ u32 cs;
+ u32 ahb_base;
+ u32 sz;
+};
+
static const struct aspeed_spi_info ast2400_spi_info;
+static const struct aspeed_spi_info ast2500_fmc_info;
+static const struct aspeed_spi_info ast2500_spi_info;
static int aspeed_spi_decoded_range_config(struct udevice *bus);
static int aspeed_spi_trim_decoded_size(struct udevice *bus);
@@ -618,6 +627,9 @@ static void aspeed_spi_decoded_base_calculate(struct udevice *bus)
struct aspeed_spi_priv *priv = dev_get_priv(bus);
u32 cs;
+ if (priv->fixed_decoded_range)
+ return;
+
priv->flashes[0].ahb_base = plat->ahb_base;
for (cs = 1; cs < plat->max_cs; cs++) {
@@ -654,7 +666,8 @@ static int aspeed_spi_decoded_range_config(struct udevice *bus)
int ret = 0;
struct aspeed_spi_priv *priv = dev_get_priv(bus);
- if (priv->info->adjust_decoded_sz) {
+ if (priv->info->adjust_decoded_sz &&
+ !priv->fixed_decoded_range) {
ret = priv->info->adjust_decoded_sz(bus);
if (ret != 0)
return ret;
@@ -666,6 +679,104 @@ static int aspeed_spi_decoded_range_config(struct udevice *bus)
return ret;
}
+static int aspeed_spi_decoded_ranges_sanity(struct udevice *bus)
+{
+ struct aspeed_spi_plat *plat = dev_get_plat(bus);
+ struct aspeed_spi_priv *priv = dev_get_priv(bus);
+ u32 cs;
+ u32 total_sz = 0;
+
+ /* Check overall size. */
+ for (cs = 0; cs < plat->max_cs; cs++)
+ total_sz += priv->flashes[cs].ahb_decoded_sz;
+
+ if (total_sz > plat->ahb_sz) {
+ dev_err(bus, "invalid total size 0x%08x\n", total_sz);
+ return -EINVAL;
+ }
+
+ /* Check each decoded range size for AST2500. */
+ if (priv->info == &ast2500_fmc_info ||
+ priv->info == &ast2500_spi_info) {
+ for (cs = 0; cs < plat->max_cs; cs++) {
+ if (priv->flashes[cs].ahb_decoded_sz <
+ priv->info->min_decoded_sz) {
+ dev_err(bus, "insufficient decoded range.\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ /*
+ * Check overlay. Here, we assume the deccded ranges and
+ * 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 +
+ 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);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int aspeed_spi_read_fixed_decoded_ranges(struct udevice *bus)
+{
+ int ret = 0;
+ struct aspeed_spi_plat *plat = dev_get_plat(bus);
+ struct aspeed_spi_priv *priv = dev_get_priv(bus);
+ const char *range_prop = "decoded-ranges";
+ struct aspeed_spi_decoded_range ranges[ASPEED_SPI_MAX_CS];
+ const struct property *prop;
+ u32 prop_sz;
+ u32 count;
+ u32 i;
+
+ priv->fixed_decoded_range = false;
+
+ prop = dev_read_prop(bus, range_prop, &prop_sz);
+ if (!prop)
+ return 0;
+
+ count = prop_sz / sizeof(struct aspeed_spi_decoded_range);
+ if (count > plat->max_cs || count < priv->num_cs) {
+ dev_err(bus, "invalid '%s' property %d %d\n",
+ range_prop, count, priv->num_cs);
+ return -EINVAL;
+ }
+
+ ret = dev_read_u32_array(bus, range_prop, (u32 *)ranges, count * 3);
+ if (ret)
+ 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_decoded_sz =
+ ranges[i].sz;
+ }
+
+ for (i = 0; i < plat->max_cs; i++) {
+ dev_dbg(bus, "ahb_base: 0x%p, size: 0x%08x\n",
+ priv->flashes[i].ahb_base,
+ priv->flashes[i].ahb_decoded_sz);
+ }
+
+ ret = aspeed_spi_decoded_ranges_sanity(bus);
+ if (ret != 0)
+ return ret;
+
+ priv->fixed_decoded_range = true;
+
+ return 0;
+}
+
/*
* Initialize SPI controller for each chip select.
* Here, only the minimum decode range is configured
@@ -709,16 +820,23 @@ static int aspeed_spi_ctrl_init(struct udevice *bus)
return 0;
}
- /* Assign basic AHB decoded size for each CS. */
- for (cs = 0; cs < plat->max_cs; cs++) {
- reg_val = readl(&priv->regs->segment_addr[cs]);
- decoded_sz = priv->info->segment_end(bus, reg_val) -
- priv->info->segment_start(bus, reg_val);
- if (decoded_sz < priv->info->min_decoded_sz)
- decoded_sz = priv->info->min_decoded_sz;
+ ret = aspeed_spi_read_fixed_decoded_ranges(bus);
+ if (ret != 0)
+ return ret;
+
+ if (!priv->fixed_decoded_range) {
+ /* Assign basic AHB decoded size for each CS. */
+ for (cs = 0; cs < plat->max_cs; cs++) {
+ reg_val = readl(&priv->regs->segment_addr[cs]);
+ decoded_sz = priv->info->segment_end(bus, reg_val) -
+ priv->info->segment_start(bus, reg_val);
+
+ if (decoded_sz < priv->info->min_decoded_sz)
+ decoded_sz = priv->info->min_decoded_sz;
- priv->flashes[cs].ahb_decoded_sz = decoded_sz;
+ priv->flashes[cs].ahb_decoded_sz = decoded_sz;
+ }
}
ret = aspeed_spi_decoded_range_config(bus);
--
2.25.1
More information about the U-Boot
mailing list