]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
common: memsize: add RAM size probe based on alias detection
authorEmanuele Ghidoli <emanuele.ghidoli@toradex.com>
Fri, 17 Apr 2026 07:13:31 +0000 (09:13 +0200)
committerFabio Estevam <festevam@gmail.com>
Tue, 21 Apr 2026 23:49:39 +0000 (20:49 -0300)
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 <emanuele.ghidoli@toradex.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
common/memsize.c
include/init.h

index 1abf3fc47d7346c90dd401af954c772ed49b6cec..3ecf9bac2aaca7cfcc3784dc743228baf0fde2d7 100644 (file)
@@ -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;
index 1e375da489360ee429ac79aacb12117a35bda02d..c31ebd83b85ed440fede38c08ce7f0f92930aad1 100644 (file)
 
 #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);