The DDR firmware marks the CS1 address map valid even when it trained
one chip select, and dram_init() adds up every valid map. A 4 GiB
Milk-V Jupiter (cs_num 1 in its EEPROM) is reported as 8 GiB, so
U-Boot reserves memory past the end of DRAM and passes 8 GiB to Linux.
Clear the CS1 map valid bit after DDR init when the EEPROM says there
is one chip select, which matches what the vendor U-Boot does by only
counting CS1 when ddr_cs_num > 1.
Fixes: 3691fbccfc89 ("riscv: spacemit: k1: probe dram size during boot phase.")
Signed-off-by: Hung-Chun Tseng <[email protected]>
---
This depends on "spacemit: k1: initialise the EEPROM index in
read_ddr_info()" [1]; without it the EEPROM read can fail, cs_num stays
at the default of 2 and this change does nothing.
Tested on a 4 GiB Milk-V Jupiter booting from SD: the SPL reads
cs_num=1, U-Boot reports "DRAM: 4 GiB" and the second bank is
0x100000000 + 2 GiB (it was 6 GiB).
[1]
https://lore.kernel.org/u-boot/[email protected]/
board/spacemit/k1/spl.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/board/spacemit/k1/spl.c b/board/spacemit/k1/spl.c
index cc0e26bb0..3e8439a71 100644
--- a/board/spacemit/k1/spl.c
+++ b/board/spacemit/k1/spl.c
@@ -56,6 +56,7 @@
#define DDR_DEFAULT_DATA_RATE 2400
#define MAGIC_NUM 0xaa55aa55
+#define DDR_CS1_MAP ((void __iomem *)0xc0000208)
typedef void (*puts_func_t)(const char *s);
typedef int (*ddr_init_func_t)(u64 ddr_base, u32 cs_num, u32 data_rate,
@@ -406,6 +407,12 @@ void ddr_early_init(void)
#else
ddr_init(0xc0000000, cfg.cs_num, cfg.data_rate, NULL);
#endif
+ /*
+ * The DDR firmware leaves the CS1 map valid on single-rank boards too,
+ * and dram_init() adds up every valid map.
+ */
+ if (cfg.cs_num == 1)
+ clrbits_le32(DDR_CS1_MAP, BIT(0));
writel(MAGIC_NUM, (void __iomem *)0x00000000);
flush_dcache_range(0, 64);
invalidate_dcache_range(0, 64);
--
2.43.0