mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-02 09:46:37 +03:00
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 <emanuele.ghidoli@toradex.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
committed by
Fabio Estevam
parent
60f6514608
commit
0977448b45
@@ -127,6 +127,65 @@ long get_ram_size(long *base, long maxsize)
|
|||||||
return (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 __weak get_effective_memsize(void)
|
||||||
{
|
{
|
||||||
phys_size_t ram_size = gd->ram_size;
|
phys_size_t ram_size = gd->ram_size;
|
||||||
|
|||||||
@@ -14,6 +14,12 @@
|
|||||||
|
|
||||||
#include <linux/types.h>
|
#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
|
* In case of the EFI app the UEFI firmware provides the low-level
|
||||||
* initialisation.
|
* initialisation.
|
||||||
@@ -88,6 +94,7 @@ int dram_init(void);
|
|||||||
int dram_init_banksize(void);
|
int dram_init_banksize(void);
|
||||||
|
|
||||||
long get_ram_size(long *base, long size);
|
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);
|
phys_size_t get_effective_memsize(void);
|
||||||
|
|
||||||
int testdram(void);
|
int testdram(void);
|
||||||
|
|||||||
Reference in New Issue
Block a user