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

Reply via email to