[PATCH v4 5/5] sunxi: h616: support a default DRAM profile from the device tree

James Hilliard james.hilliard1 at gmail.com
Fri Mar 27 21:09:16 CET 2026


Add a second H616 profile source mode which loads the DRAM
parameters from /dram-profiles/default in the U-Boot device tree.

In this mode SPL builds all supported H616 timing backends and selects
the matching one from the dram-type property at boot. This provides the
simplest device-tree-driven parameter flow for boards that need runtime
selection later, while keeping the existing fixed-profile path in the
main H616 driver.

Add a small device-tree DRAM parameter loader for the default profile
and use hidden H616 backend symbols so fixed-profile mode builds one
backend while device-tree profile mode builds all of them, without
reusing the visible timing choice symbols as build plumbing. Also make
SUNXI_DRAM_FIXED_PARAMS a derived hidden symbol so the fixed H616 timing
choice and H616 fixed-parameter prompts are hidden automatically when
device-tree profiles are enabled.

Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
 .../include/asm/arch-sunxi/dram_sun50i_h616.h | 31 ++++++-
 arch/arm/mach-sunxi/Kconfig                   | 78 +++++++++++++---
 arch/arm/mach-sunxi/Makefile                  |  1 +
 arch/arm/mach-sunxi/dram_sun50i_h616.c        | 55 +++++++----
 arch/arm/mach-sunxi/dram_sun50i_h616_dt.c     | 93 +++++++++++++++++++
 arch/arm/mach-sunxi/dram_timings/Makefile     |  6 +-
 6 files changed, 227 insertions(+), 37 deletions(-)
 create mode 100644 arch/arm/mach-sunxi/dram_sun50i_h616_dt.c

diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h
index 6dab3b4832b..9593409b465 100644
--- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_h616.h
@@ -170,6 +170,8 @@ struct dram_config {
 
 #define H616_PHY_INIT_LEN	27
 
+void h616_get_dram_para_dt(struct dram_para *para);
+
 static inline int ns_to_t(const struct dram_para *para, int nanoseconds)
 {
 	const unsigned int ctrl_freq = para->clk / 2;
@@ -187,6 +189,22 @@ const u8 *h616_lpddr4_get_phy_init(void);
 
 static inline void mctl_set_timing_params(const struct dram_para *para)
 {
+	if (IS_ENABLED(CONFIG_DRAM_SUN50I_H616_DT_PROFILE)) {
+		switch (para->type) {
+		case SUNXI_DRAM_TYPE_DDR3:
+			h616_ddr3_set_timing_params(para);
+			return;
+		case SUNXI_DRAM_TYPE_LPDDR3:
+			h616_lpddr3_set_timing_params(para);
+			return;
+		case SUNXI_DRAM_TYPE_LPDDR4:
+			h616_lpddr4_set_timing_params(para);
+			return;
+		default:
+			return;
+		}
+	}
+
 #ifdef CONFIG_SUNXI_DRAM_H616_DDR3_1333
 	h616_ddr3_set_timing_params(para);
 #elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR3)
@@ -198,7 +216,18 @@ static inline void mctl_set_timing_params(const struct dram_para *para)
 
 static inline const u8 *h616_get_phy_init(const struct dram_para *para)
 {
-	(void)para;
+	if (IS_ENABLED(CONFIG_DRAM_SUN50I_H616_DT_PROFILE)) {
+		switch (para->type) {
+		case SUNXI_DRAM_TYPE_DDR3:
+			return h616_ddr3_get_phy_init();
+		case SUNXI_DRAM_TYPE_LPDDR3:
+			return h616_lpddr3_get_phy_init();
+		case SUNXI_DRAM_TYPE_LPDDR4:
+			return h616_lpddr4_get_phy_init();
+		default:
+			return NULL;
+		}
+	}
 
 #ifdef CONFIG_SUNXI_DRAM_H616_DDR3_1333
 	return h616_ddr3_get_phy_init();
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index e979ee4a2cc..e403ef67a0b 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -62,24 +62,74 @@ config DRAM_SUN55I_A523
 	help
 	  Select this DRAM controller driver for A523/T527 SoCs.
 
+if DRAM_SUN50I_H616
+choice
+	prompt "H616 DRAM profile source"
+	default SUNXI_DRAM_H616_FIXED_PROFILE
+	help
+	  Select whether SPL uses the fixed H616 Kconfig DRAM settings or
+	  loads a default H616 DRAM profile from the device tree at boot.
+
+config SUNXI_DRAM_H616_FIXED_PROFILE
+	bool "Fixed build-time DRAM profile"
+	help
+	  Use a single H616 DRAM profile selected at build time.
+	  This keeps the existing Kconfig-based timing selection flow.
+
+config DRAM_SUN50I_H616_DT_PROFILE
+	bool "Default device tree DRAM profile"
+	select OF_CONTROL
+	select SPL_OF_CONTROL
+	help
+	  Load the H616 DRAM parameters from /dram-profiles/default in the
+	  U-Boot device tree at boot.
+
+	  The node must provide the H616 DRAM parameters used by the driver,
+	  including dram-type.
+endchoice
+
+config SUNXI_DRAM_H616_BACKEND_DDR3
+	bool
+	default y if DRAM_SUN50I_H616_DT_PROFILE
+	default y if SUNXI_DRAM_H616_DDR3_1333
+
+config SUNXI_DRAM_H616_BACKEND_LPDDR3
+	bool
+	default y if DRAM_SUN50I_H616_DT_PROFILE
+	default y if SUNXI_DRAM_H616_LPDDR3
+
+config SUNXI_DRAM_H616_BACKEND_LPDDR4
+	bool
+	default y if DRAM_SUN50I_H616_DT_PROFILE
+	default y if SUNXI_DRAM_H616_LPDDR4
+endif
+
+config SUNXI_DRAM_FIXED_PARAMS
+	bool
+	default y if !DRAM_SUN50I_H616
+	default y if DRAM_SUN50I_H616 && SUNXI_DRAM_H616_FIXED_PROFILE
+
 if DRAM_SUN50I_H616 || DRAM_SUN50I_A133 || DRAM_SUN55I_A523
 config DRAM_SUNXI_DX_ODT
-	hex "DRAM DX ODT parameter"
+	hex "DRAM DX ODT parameter" if SUNXI_DRAM_FIXED_PARAMS
+	default 0x0 if !SUNXI_DRAM_FIXED_PARAMS
 	help
 	  DX ODT value from vendor DRAM settings.
 
 config DRAM_SUNXI_DX_DRI
-	hex "DRAM DX DRI parameter"
+	hex "DRAM DX DRI parameter" if SUNXI_DRAM_FIXED_PARAMS
+	default 0x0 if !SUNXI_DRAM_FIXED_PARAMS
 	help
 	  DX DRI value from vendor DRAM settings.
 
 config DRAM_SUNXI_CA_DRI
-	hex "DRAM CA DRI parameter"
+	hex "DRAM CA DRI parameter" if SUNXI_DRAM_FIXED_PARAMS
+	default 0x0 if !SUNXI_DRAM_FIXED_PARAMS
 	help
 	  CA DRI value from vendor DRAM settings.
 
 config DRAM_SUNXI_ODT_EN
-	hex "DRAM ODT EN parameter"
+	hex "DRAM ODT EN parameter" if SUNXI_DRAM_FIXED_PARAMS
 	default 0x1
 	help
 	  ODT EN value from vendor DRAM settings.
@@ -119,49 +169,50 @@ config DRAM_SUNXI_MR14
 	  MR14 value from vendor DRAM settings.
 
 config DRAM_SUNXI_TPR0
-	hex "DRAM TPR0 parameter"
+	hex "DRAM TPR0 parameter" if SUNXI_DRAM_FIXED_PARAMS
 	default 0x0
 	help
 	  TPR0 value from vendor DRAM settings.
 
 config DRAM_SUNXI_TPR1
-	hex "DRAM TPR1 parameter"
+	hex "DRAM TPR1 parameter" if SUNXI_DRAM_FIXED_PARAMS
 	default 0x0
 	help
 	  TPR1 value from vendor DRAM settings.
 
 config DRAM_SUNXI_TPR2
-	hex "DRAM TPR2 parameter"
+	hex "DRAM TPR2 parameter" if SUNXI_DRAM_FIXED_PARAMS
 	default 0x0
 	help
 	  TPR2 value from vendor DRAM settings.
 
 config DRAM_SUNXI_TPR3
-	hex "DRAM TPR3 parameter"
+	hex "DRAM TPR3 parameter" if SUNXI_DRAM_FIXED_PARAMS
 	default 0x0
 	help
 	  TPR3 value from vendor DRAM settings.
 
 config DRAM_SUNXI_TPR6
-	hex "DRAM TPR6 parameter"
+	hex "DRAM TPR6 parameter" if SUNXI_DRAM_FIXED_PARAMS
 	default 0x3300c080
 	help
 	  TPR6 value from vendor DRAM settings.
 
 config DRAM_SUNXI_TPR10
-	hex "DRAM TPR10 parameter"
+	hex "DRAM TPR10 parameter" if SUNXI_DRAM_FIXED_PARAMS
+	default 0x0 if !SUNXI_DRAM_FIXED_PARAMS
 	help
 	  TPR10 value from vendor DRAM settings. It tells which features
 	  should be configured, like write leveling, read calibration, etc.
 
 config DRAM_SUNXI_TPR11
-	hex "DRAM TPR11 parameter"
+	hex "DRAM TPR11 parameter" if SUNXI_DRAM_FIXED_PARAMS
 	default 0x0
 	help
 	  TPR11 value from vendor DRAM settings.
 
 config DRAM_SUNXI_TPR12
-	hex "DRAM TPR12 parameter"
+	hex "DRAM TPR12 parameter" if SUNXI_DRAM_FIXED_PARAMS
 	default 0x0
 	help
 	  TPR12 value from vendor DRAM settings.
@@ -608,6 +659,7 @@ config SUNXI_DRAM_DDR4
 
 choice
 	prompt "DRAM Type and Timing"
+	depends on SUNXI_DRAM_FIXED_PARAMS
 	default SUNXI_DRAM_A523_LPDDR4 if MACH_SUN55I_A523
 	default SUNXI_DRAM_DDR3_1333 if !MACH_SUN8I_V3S
 	default SUNXI_DRAM_DDR2_V3S if MACH_SUN8I_V3S
@@ -718,7 +770,7 @@ config DRAM_TYPE
 	Set the dram type, 3: DDR3, 7: LPDDR3
 
 config DRAM_CLK
-	int "sunxi dram clock speed"
+	int "sunxi dram clock speed" if SUNXI_DRAM_FIXED_PARAMS
 	default 792 if MACH_SUN9I
 	default 648 if MACH_SUN8I_R40
 	default 360 if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || \
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index 9c79b55abf3..862386cf6f0 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SUNXI_DRAM_DW)	+= dram_timings/
 obj-$(CONFIG_DRAM_SUN50I_H6)	+= dram_sun50i_h6.o dram_dw_helpers.o
 obj-$(CONFIG_DRAM_SUN50I_H6)	+= dram_timings/
 obj-$(CONFIG_DRAM_SUN50I_H616)	+= dram_sun50i_h616.o dram_dw_helpers.o
+obj-$(CONFIG_DRAM_SUN50I_H616_DT_PROFILE) += dram_sun50i_h616_dt.o
 obj-$(CONFIG_DRAM_SUN50I_H616)	+= dram_timings/
 obj-$(CONFIG_DRAM_SUN50I_A133)	+= dram_sun50i_a133.o
 obj-$(CONFIG_DRAM_SUN50I_A133)	+= dram_timings/
diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616.c b/arch/arm/mach-sunxi/dram_sun50i_h616.c
index c3e1286fb35..96d84398eee 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_h616.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_h616.c
@@ -1281,33 +1281,48 @@ bool mctl_core_init(const struct dram_para *para,
 	return mctl_ctrl_init(para, config);
 }
 
-static const struct dram_para para = {
-	.clk = CONFIG_DRAM_CLK,
-#ifdef CONFIG_SUNXI_DRAM_H616_DDR3_1333
-	.type = SUNXI_DRAM_TYPE_DDR3,
-#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR3)
-	.type = SUNXI_DRAM_TYPE_LPDDR3,
-#elif defined(CONFIG_SUNXI_DRAM_H616_LPDDR4)
-	.type = SUNXI_DRAM_TYPE_LPDDR4,
-#endif
-	.dx_odt = CONFIG_DRAM_SUNXI_DX_ODT,
-	.dx_dri = CONFIG_DRAM_SUNXI_DX_DRI,
-	.ca_dri = CONFIG_DRAM_SUNXI_CA_DRI,
-	.odt_en = CONFIG_DRAM_SUNXI_ODT_EN,
-	.tpr0 = CONFIG_DRAM_SUNXI_TPR0,
-	.tpr2 = CONFIG_DRAM_SUNXI_TPR2,
-	.tpr6 = CONFIG_DRAM_SUNXI_TPR6,
-	.tpr10 = CONFIG_DRAM_SUNXI_TPR10,
-	.tpr11 = CONFIG_DRAM_SUNXI_TPR11,
-	.tpr12 = CONFIG_DRAM_SUNXI_TPR12,
-};
+static enum sunxi_dram_type h616_get_fixed_dram_type(void)
+{
+	if (IS_ENABLED(CONFIG_SUNXI_DRAM_H616_DDR3_1333))
+		return SUNXI_DRAM_TYPE_DDR3;
+	if (IS_ENABLED(CONFIG_SUNXI_DRAM_H616_LPDDR3))
+		return SUNXI_DRAM_TYPE_LPDDR3;
+	if (IS_ENABLED(CONFIG_SUNXI_DRAM_H616_LPDDR4))
+		return SUNXI_DRAM_TYPE_LPDDR4;
+
+	panic("No fixed H616 DRAM type selected\n");
+}
+
+static void h616_get_fixed_dram_para(struct dram_para *para)
+{
+	*para = (struct dram_para) {
+		.clk = CONFIG_DRAM_CLK,
+		.type = h616_get_fixed_dram_type(),
+		.dx_odt = CONFIG_DRAM_SUNXI_DX_ODT,
+		.dx_dri = CONFIG_DRAM_SUNXI_DX_DRI,
+		.ca_dri = CONFIG_DRAM_SUNXI_CA_DRI,
+		.odt_en = CONFIG_DRAM_SUNXI_ODT_EN,
+		.tpr0 = CONFIG_DRAM_SUNXI_TPR0,
+		.tpr2 = CONFIG_DRAM_SUNXI_TPR2,
+		.tpr6 = CONFIG_DRAM_SUNXI_TPR6,
+		.tpr10 = CONFIG_DRAM_SUNXI_TPR10,
+		.tpr11 = CONFIG_DRAM_SUNXI_TPR11,
+		.tpr12 = CONFIG_DRAM_SUNXI_TPR12,
+	};
+}
 
 unsigned long sunxi_dram_init(void)
 {
 	void *const prcm = (void *)SUNXI_PRCM_BASE;
+	struct dram_para para;
 	struct dram_config config;
 	unsigned long size;
 
+	if (IS_ENABLED(CONFIG_DRAM_SUN50I_H616_DT_PROFILE))
+		h616_get_dram_para_dt(&para);
+	else
+		h616_get_fixed_dram_para(&para);
+
 	setbits_le32(prcm + CCU_PRCM_RES_CAL_CTRL, BIT(8));
 	clrbits_le32(prcm + CCU_PRCM_OHMS240, 0x3f);
 
diff --git a/arch/arm/mach-sunxi/dram_sun50i_h616_dt.c b/arch/arm/mach-sunxi/dram_sun50i_h616_dt.c
new file mode 100644
index 00000000000..2620e24b41a
--- /dev/null
+++ b/arch/arm/mach-sunxi/dram_sun50i_h616_dt.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * H616 DRAM parameter loading from the device tree
+ */
+
+#include <errno.h>
+#include <vsprintf.h>
+#include <asm/global_data.h>
+#include <asm/arch/dram.h>
+#include <linux/libfdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int h616_fdt_read_u32(const void *blob, int node, const char *prop_name,
+			     u32 *val)
+{
+	const fdt32_t *prop;
+	int len;
+
+	prop = fdt_getprop(blob, node, prop_name, &len);
+	if (!prop || len != sizeof(*prop))
+		return -EINVAL;
+
+	*val = fdt32_to_cpu(*prop);
+
+	return 0;
+}
+
+static int h616_get_dram_type(u32 val, enum sunxi_dram_type *type)
+{
+	switch (val) {
+	case SUNXI_DRAM_TYPE_DDR3:
+	case SUNXI_DRAM_TYPE_LPDDR3:
+	case SUNXI_DRAM_TYPE_LPDDR4:
+		*type = val;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int h616_parse_dram_para(const void *blob, int node,
+				struct dram_para *para)
+{
+	u32 val;
+
+	if (h616_fdt_read_u32(blob, node, "allwinner,dram-clk", &para->clk))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,dram-type", &val))
+		return -EINVAL;
+	if (h616_get_dram_type(val, &para->type))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,dx-odt", &para->dx_odt))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,dx-dri", &para->dx_dri))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,ca-dri", &para->ca_dri))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,odt-en", &para->odt_en))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,tpr0", &para->tpr0))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,tpr2", &para->tpr2))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,tpr6", &para->tpr6))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,tpr10", &para->tpr10))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,tpr11", &para->tpr11))
+		return -EINVAL;
+	if (h616_fdt_read_u32(blob, node, "allwinner,tpr12", &para->tpr12))
+		return -EINVAL;
+
+	return 0;
+}
+
+void h616_get_dram_para_dt(struct dram_para *para)
+{
+	const void *blob = gd->fdt_blob;
+	int node, profiles, ret;
+
+	profiles = fdt_path_offset(blob, "/dram-profiles");
+	if (profiles < 0)
+		panic("H616 DT DRAM profile selection failed: %d\n", profiles);
+
+	node = fdt_subnode_offset(blob, profiles, "default");
+	if (node < 0)
+		panic("H616 DT DRAM profile selection failed: %d\n", node);
+
+	ret = h616_parse_dram_para(blob, node, para);
+	if (ret)
+		panic("H616 DT DRAM profile selection failed: %d\n", ret);
+}
diff --git a/arch/arm/mach-sunxi/dram_timings/Makefile b/arch/arm/mach-sunxi/dram_timings/Makefile
index 5de9fd5aab4..165f6123cb4 100644
--- a/arch/arm/mach-sunxi/dram_timings/Makefile
+++ b/arch/arm/mach-sunxi/dram_timings/Makefile
@@ -3,9 +3,9 @@ obj-$(CONFIG_SUNXI_DRAM_LPDDR3_STOCK)	+= lpddr3_stock.o
 obj-$(CONFIG_SUNXI_DRAM_DDR2_V3S)	+= ddr2_v3s.o
 obj-$(CONFIG_SUNXI_DRAM_H6_LPDDR3)	+= h6_lpddr3.o
 obj-$(CONFIG_SUNXI_DRAM_H6_DDR3_1333)	+= h6_ddr3_1333.o
-obj-$(CONFIG_SUNXI_DRAM_H616_DDR3_1333)	+= h616_ddr3_1333.o
-obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR3)	+= h616_lpddr3.o
-obj-$(CONFIG_SUNXI_DRAM_H616_LPDDR4)	+= h616_lpddr4_2133.o
+obj-$(CONFIG_SUNXI_DRAM_H616_BACKEND_DDR3) += h616_ddr3_1333.o
+obj-$(CONFIG_SUNXI_DRAM_H616_BACKEND_LPDDR3) += h616_lpddr3.o
+obj-$(CONFIG_SUNXI_DRAM_H616_BACKEND_LPDDR4) += h616_lpddr4_2133.o
 obj-$(CONFIG_SUNXI_DRAM_A133_DDR4)	+= a133_ddr4.o
 obj-$(CONFIG_SUNXI_DRAM_A133_LPDDR4)	+= a133_lpddr4.o
 obj-$(CONFIG_SUNXI_DRAM_A523_DDR3)	+= a523_ddr3.o
-- 
2.43.0



More information about the U-Boot mailing list