From dacaffdf195c924b33c6ad0a7f93de18dfed92b4 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sat, 15 Mar 2025 19:52:31 +0100
Subject: [PATCH] sunxi: h6: Fix DRAM size detection

This is based on submitted patches for newer SoCs. It needs to be
properly reworked once they are merged.

Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
 arch/arm/mach-sunxi/dram_sun50i_h6.c | 97 ++++++++++++++++++++++------
 1 file changed, 79 insertions(+), 18 deletions(-)

diff --git a/arch/arm/mach-sunxi/dram_sun50i_h6.c b/arch/arm/mach-sunxi/dram_sun50i_h6.c
index e7862bd06ea3..f5ee64cfead4 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_h6.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_h6.c
@@ -601,32 +601,93 @@ static void mctl_auto_detect_rank_width(struct dram_para *para)
 	panic("This DRAM setup is currently not supported.\n");
 }
 
+static void mctl_write_pattern(void)
+{
+	unsigned int i;
+	u32 *ptr, val;
+
+	ptr = (u32*)CFG_SYS_SDRAM_BASE;
+	for (i = 0; i < 16; ptr++, i++) {
+		if (i & 1)
+			val = ~(ulong)ptr;
+		else
+			val = (ulong)ptr;
+		writel(val, ptr);
+	}
+}
+
+static bool mctl_check_pattern(ulong offset)
+{
+	unsigned int i;
+	u32 *ptr, val;
+
+	ptr = (u32*)CFG_SYS_SDRAM_BASE;
+	for (i = 0; i < 16; ptr++, i++) {
+		if (i & 1)
+			val = ~(ulong)ptr;
+		else
+			val = (ulong)ptr;
+		if (val != *(ptr + offset / 4))
+			return false;
+	}
+
+	return true;
+}
+
 static void mctl_auto_detect_dram_size(struct dram_para *para)
 {
-	/* TODO: non-(LP)DDR3 */
+	unsigned int shift, cols, rows;
+	u32 buffer[16];
 
-	/* detect row address bits */
-	para->cols = 8;
-	para->rows = 18;
-	mctl_core_init(para);
-
-	for (para->rows = 13; para->rows < 18; para->rows++) {
-		/* 8 banks, 8 bit per byte and 16/32 bit width */
-		if (mctl_mem_matches((1 << (para->rows + para->cols +
-					    4 + para->bus_full_width))))
-			break;
-	}
-
-	/* detect column address bits */
+	/* max. config for columns, but not rows */
 	para->cols = 11;
+	para->rows = 13;
 	mctl_core_init(para);
 
-	for (para->cols = 8; para->cols < 11; para->cols++) {
-		/* 8 bits per byte and 16/32 bit width */
-		if (mctl_mem_matches(1 << (para->cols + 1 +
-					   para->bus_full_width)))
+	/*
+	 * Store content so it can be restored later. This is important
+	 * if controller was already initialized and holds any data
+	 * which is important for restoring system.
+	 */
+	memcpy(buffer, (u32*)CFG_SYS_SDRAM_BASE, sizeof(buffer));
+
+	mctl_write_pattern();
+
+	shift = para->bus_full_width + 1;
+
+	/* detect column address bits */
+	for (cols = 8; cols < 11; cols++) {
+		if (mctl_check_pattern(1ULL << (cols + shift)))
 			break;
 	}
+	debug("detected %u columns\n", cols);
+
+	/* restore data */
+	memcpy((u32*)CFG_SYS_SDRAM_BASE, buffer, sizeof(buffer));
+
+	/* reconfigure to make sure that all active rows are accessible */
+	para->cols = 8;
+	para->rows = 17;
+	mctl_core_init(para);
+
+	/* store data again as it might be moved */
+	memcpy(buffer, (u32*)CFG_SYS_SDRAM_BASE, sizeof(buffer));
+
+	mctl_write_pattern();
+
+	/* detect row address bits */
+	shift = para->bus_full_width + 4 + para->cols;
+	for (rows = 13; rows < 17; rows++) {
+		if (mctl_check_pattern(1ULL << (rows + shift)))
+			break;
+	}
+	debug("detected %u rows\n", rows);
+
+	/* restore data again */
+	memcpy((u32*)CFG_SYS_SDRAM_BASE, buffer, sizeof(buffer));
+
+	para->cols = cols;
+	para->rows = rows;
 }
 
 unsigned long mctl_calc_size(struct dram_para *para)
-- 
2.48.1

