diff options
| author | Emanuele Ghidoli <[email protected]> | 2026-04-17 09:13:31 +0200 |
|---|---|---|
| committer | Fabio Estevam <[email protected]> | 2026-04-21 20:49:39 -0300 |
| commit | 0977448b45e2f1a9cbe7d7e11d208b16460c79ea (patch) | |
| tree | ab9e97ed2f3088b7dad9850646597d7e1fa8f829 | |
| parent | 60f651460849aa9f12ceee8246c169a9dd55e55c (diff) | |
common: memsize: add RAM size probe based on alias detection
Add probe_ram_size_by_alias() to detect RAM size by checking whether a
write to one address aliases to another address.
Compared to get_ram_size(), this function allows the caller to:
- limit probing to a small set of required accesses
- avoid touching reserved or already used memory regions
- handle non-linear alias patterns
On the iMX95 SoC, when used with LPDDR5, accesses beyond the end of an 8GB DDR
configuration do not alias to the expected linear wrap-around addresses.
Instead, the aliased addresses appear to follow a pattern related to the
DDRC bank and bank-group addresses mapping. Experimentally, the observed
pattern is:
Write Read
y00000000 -> x0001c000
y00004000 -> x00018000
y00008000 -> x00014000
y0000c000 -> x00010000
y00010000 -> x0000c000
y00014000 -> x00008000
y00018000 -> x00004000
y0001c000 -> x00000000
This helper makes it possible to probe RAM size by explicitly specifying
the probed address and the expected alias address for each size check.
Signed-off-by: Emanuele Ghidoli <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
| -rw-r--r-- | common/memsize.c | 59 | ||||
| -rw-r--r-- | include/init.h | 7 |
2 files changed, 66 insertions, 0 deletions
diff --git a/common/memsize.c b/common/memsize.c index 1abf3fc47d7..3ecf9bac2aa 100644 --- a/common/memsize.c +++ b/common/memsize.c @@ -127,6 +127,65 @@ long get_ram_size(long *base, long maxsize) return (maxsize); } +/** + * probe_ram_size_by_alias() - Detect RAM size using known alias addresses + * @checks: Array of RAM alias probe descriptors, terminated by a NULL + * @probe_addr entry + * + * Probe RAM size by writing a test pattern to each @probe_addr and checking + * whether the same pattern does not appear at the corresponding @alias_addr. + * This is useful on systems where address wrap-around does not alias to the + * base of memory in a linear way, so get_ram_size() cannot be used directly. + * It is also useful on systems where the base of the physical memory cannot + * be safely accessed, so get_ram_size() cannot be used at all. + * + * Return: The size associated with the first matching entry, or 0 if no match + * is found. + */ +long probe_ram_size_by_alias(const struct ram_alias_check *checks) +{ + long save[2]; + int dcache_en = 0; + long ret = 0; + + if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) + dcache_en = dcache_status(); + + while (checks->probe_addr && !ret) { + volatile long *d = checks->probe_addr; + volatile long *s = checks->alias_addr; + + save[0] = *s; + save[1] = *d; + /* Ensure s is written and not cached */ + if (dcache_en) + dcache_flush_invalidate(s); + + *d = ~save[0]; + sync(); + if (dcache_en) + dcache_flush_invalidate(d); + + if (*s != ~save[0]) + ret = checks->size; + + /* Restore content */ + *d = save[1]; + sync(); + if (dcache_en) + dcache_flush_invalidate(d); + + *s = save[0]; + sync(); + if (dcache_en) + dcache_flush_invalidate(s); + + checks++; + } + + return ret; +} + phys_size_t __weak get_effective_memsize(void) { phys_size_t ram_size = gd->ram_size; diff --git a/include/init.h b/include/init.h index 1e375da4893..c31ebd83b85 100644 --- a/include/init.h +++ b/include/init.h @@ -14,6 +14,12 @@ #include <linux/types.h> +struct ram_alias_check { + void *probe_addr; + void *alias_addr; + long size; +}; + /* * In case of the EFI app the UEFI firmware provides the low-level * initialisation. @@ -88,6 +94,7 @@ int dram_init(void); int dram_init_banksize(void); long get_ram_size(long *base, long size); +long probe_ram_size_by_alias(const struct ram_alias_check *checks); phys_size_t get_effective_memsize(void); int testdram(void); |
