public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH v2 1/3] sunxi: a133: dram: Add NSI arbiter configuration support
@ 2026-01-28 23:57 Paul Kocialkowski
  2026-01-28 23:57 ` [PATCH v2 2/3] sunxi: a133: dram: Fix PHY dx delays offsets and add dmb Paul Kocialkowski
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Paul Kocialkowski @ 2026-01-28 23:57 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jagan Teki, Andre Przywara, Chen-Yu Tsai, Icenowy Zheng,
	Jernej Skrabec, Paul Kocialkowski

From: Paul Kocialkowski <paulk@sys-base.io>

In previous generations of Allwinner SoCs, the memory bus (MBUS) access
arbitration was configured as part of the DRAM top registers. This is no
longer the case starting with the A133, which has a dedicated base
address for the bus arbiter that is now called NSI instead of MBUS.

NSI appears to be a later iteration of MBUS design, with new dedicated
registers that resemble the previous MBUS ones. Despite NSI not being
documented in the manual, the A133 BSP includes a nsi driver with some
description of the registers. Like previous generations, it implements
port arbitration priority for DRAM access and also supports an optional
QoS mode based on bandwidth limits.

Configuring port arbitration priority is especially important to make
sure that critical masters are not starved by other less important
ones. This is especially the case with the display engine that needs
to be able to fetch pixels in time for scanout and can easily be
starved by CPU or GPU access.

This introduces support for the NSI arbiter in the A133 DRAM init
code. The list and order of available ports are highly SoC-specific
and the default config values are set to match the BSP's defaults.

Signed-off-by: Paul Kocialkowski <paulk@sys-base.io>
Sponsored-by: MEC Electronics GmbH <https://www.mec.at/>
---
 .../include/asm/arch-sunxi/cpu_sun50i_h6.h    |  4 ++
 .../include/asm/arch-sunxi/dram_sun50i_a133.h | 36 ++++++++++
 arch/arm/mach-sunxi/dram_sun50i_a133.c        | 67 ++++++++++++++++++-
 3 files changed, 106 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
index 2a9b086991c3..8e80c520706b 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
@@ -16,6 +16,10 @@
 
 #define SUNXI_GIC400_BASE		0x03020000
 
+#ifdef CONFIG_MACH_SUN50I_A133
+#define SUNXI_NSI_BASE			0x03100000
+#endif
+
 #ifdef CONFIG_MACH_SUN50I_H6
 #define SUNXI_DRAM_COM_BASE		0x04002000
 #define SUNXI_DRAM_CTL0_BASE		0x04003000
diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h
index a5fc6ad36560..eadec74cc2b6 100644
--- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h
@@ -24,6 +24,42 @@ static inline int ns_to_t(int nanoseconds)
 	return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
 }
 
+#define SUNXI_NSI_MODE_REG(i)		((i) * 0x200 + 0x10)
+#define SUNXI_NSI_PRI_CFG_REG(i)	((i) * 0x200 + 0x14)
+#define SUNXI_NSI_PRI_CFG_RD(v)		(((v) & 0x3) << 2)
+#define SUNXI_NSI_PRI_CFG_WR(v)		((v) & 0x3)
+#define SUNXI_NSI_PRI_CFG_LOWEST	0
+#define SUNXI_NSI_PRI_CFG_LOW		1
+#define SUNXI_NSI_PRI_CFG_HIGH		2
+#define SUNXI_NSI_PRI_CFG_HIGHEST	3
+#define SUNXI_NSI_IO_CFG_REG(i)		((i) * 0x200 + 0x18)
+#define SUNXI_NSI_IO_CFG_QOS_SEL_OUTPUT	0
+#define SUNXI_NSI_IO_CFG_QOS_SEL_INPUT	1
+#define SUNXI_NSI_ENABLE_REG(i)		((i) * 0x200 + 0xc0)
+
+enum sunxi_nsi_port {
+	SUNXI_NSI_PORT_CPU	= 0,
+	SUNXI_NSI_PORT_GPU,
+	SUNXI_NSI_PORT_SD1,
+	SUNXI_NSI_PORT_MSTG,
+	SUNXI_NSI_PORT_GMAC0,
+	SUNXI_NSI_PORT_GMAC1,
+	SUNXI_NSI_PORT_USB0,
+	SUNXI_NSI_PORT_USB1,
+	SUNXI_NSI_PORT_NDFC,
+	SUNXI_NSI_PORT_DMAC,
+	SUNXI_NSI_PORT_CE,
+	SUNXI_NSI_PORT_DE0,
+	SUNXI_NSI_PORT_DE1,
+	SUNXI_NSI_PORT_VE,
+	SUNXI_NSI_PORT_CSI,
+	SUNXI_NSI_PORT_ISP,
+	SUNXI_NSI_PORT_G2D,
+	SUNXI_NSI_PORT_EINK,
+	SUNXI_NSI_PORT_IOMMU,
+	SUNXI_NSI_PORT_CPUS,
+};
+
 /* MBUS part is largely the same as in H6, except for one special register */
 #define MCTL_COM_UNK_008	0x008
 /* NOTE: This register has the same importance as mctl_ctl->clken in H616 */
diff --git a/arch/arm/mach-sunxi/dram_sun50i_a133.c b/arch/arm/mach-sunxi/dram_sun50i_a133.c
index 1496f99624dd..204810aecf2a 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_a133.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_a133.c
@@ -69,6 +69,66 @@ static const u8 phy_init[] = {
 };
 #endif
 
+static void nsi_configure_port(unsigned int port, u8 pri, u8 qos_sel)
+{
+	void *base = (void *)SUNXI_NSI_BASE;
+	u32 pri_cfg;
+
+	/* QoS with bandwidth limits is not supported, disable it. */
+	writel(0, base + SUNXI_NSI_MODE_REG(port));
+	writel(0, base + SUNXI_NSI_ENABLE_REG(port));
+
+	/*
+	 * QoS direction selection should not be in use, but set it nevertheless
+	 * to match the BSP behavior (in case it has some other meaning).
+	 */
+	writel(qos_sel, base + SUNXI_NSI_IO_CFG_REG(port));
+
+	/* Port priority is always active. */
+	pri_cfg = SUNXI_NSI_PRI_CFG_RD(pri) | SUNXI_NSI_PRI_CFG_WR(pri);
+
+	writel(pri_cfg, base + SUNXI_NSI_PRI_CFG_REG(port));
+}
+
+#define NSI_CONF(port, pri, qos_sel) \
+	{ SUNXI_NSI_PORT_ ## port, SUNXI_NSI_PRI_CFG_ ## pri, \
+	  SUNXI_NSI_IO_CFG_QOS_SEL_ ## qos_sel }
+
+static void nsi_set_master_priority(void)
+{
+	struct {
+		unsigned int port;
+		u8 pri;
+		u8 qos_sel;
+	} ports[] = {
+		NSI_CONF(CPU,	LOWEST,		INPUT),
+		NSI_CONF(GPU,	LOWEST,		INPUT),
+		NSI_CONF(SD1,	LOWEST,		OUTPUT),
+		NSI_CONF(MSTG,	LOWEST,		OUTPUT),
+		NSI_CONF(GMAC0,	LOWEST,		OUTPUT),
+		NSI_CONF(GMAC1,	LOWEST,		OUTPUT),
+		NSI_CONF(USB0,	LOWEST,		OUTPUT),
+		NSI_CONF(USB1,	LOWEST,		OUTPUT),
+		NSI_CONF(NDFC,	LOWEST,		OUTPUT),
+		NSI_CONF(DMAC,	LOWEST,		OUTPUT),
+		NSI_CONF(CE,	LOWEST,		OUTPUT),
+		NSI_CONF(DE0,	HIGH,		INPUT),
+		NSI_CONF(DE1,	HIGH,		INPUT),
+		NSI_CONF(VE,	LOWEST,		INPUT),
+		NSI_CONF(CSI,	HIGH,		INPUT),
+		NSI_CONF(ISP,	HIGH,		INPUT),
+		NSI_CONF(G2D,	LOWEST,		INPUT),
+		NSI_CONF(EINK,	LOWEST,		OUTPUT),
+		NSI_CONF(IOMMU,	HIGHEST,	INPUT),
+		NSI_CONF(CPUS,	LOWEST,		OUTPUT),
+	};
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(ports); i++)
+		nsi_configure_port(ports[i].port, ports[i].pri,
+				   ports[i].qos_sel);
+}
+
 static void mctl_clk_init(u32 clk)
 {
 	void * const ccm = (void *)SUNXI_CCM_BASE;
@@ -1184,6 +1244,7 @@ static const struct dram_para para = {
 unsigned long sunxi_dram_init(void)
 {
 	struct dram_config config;
+	unsigned long size;
 
 	/* Writing to undocumented SYS_CFG area, according to user manual. */
 	setbits_le32(0x03000160, BIT(8));
@@ -1200,5 +1261,9 @@ unsigned long sunxi_dram_init(void)
 	      1U << config.bankgrps, 1U << config.ranks,
 	      16U << config.bus_full_width);
 
-	return calculate_dram_size(&config);
+	size = calculate_dram_size(&config);
+
+	nsi_set_master_priority();
+
+	return size;
 }
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 2/3] sunxi: a133: dram: Fix PHY dx delays offsets and add dmb
  2026-01-28 23:57 [PATCH v2 1/3] sunxi: a133: dram: Add NSI arbiter configuration support Paul Kocialkowski
@ 2026-01-28 23:57 ` Paul Kocialkowski
  2026-02-04 17:35   ` Jernej Škrabec
  2026-01-28 23:57 ` [PATCH v2 3/3] sunxi: a133: dram: Align parameters terminology with Allwinner Paul Kocialkowski
  2026-02-04 17:33 ` [PATCH v2 1/3] sunxi: a133: dram: Add NSI arbiter configuration support Jernej Škrabec
  2 siblings, 1 reply; 6+ messages in thread
From: Paul Kocialkowski @ 2026-01-28 23:57 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jagan Teki, Andre Przywara, Chen-Yu Tsai, Icenowy Zheng,
	Jernej Skrabec, Paul Kocialkowski

From: Paul Kocialkowski <paulk@sys-base.io>

Some of the offsets for the DRAM PHY dx delays are wrong (as compared
to the H616 code and the reference binary) since the
mctl_phy_dx_delay0_inner function does not perform the correct
calculation for some of them.

Introduce a mctl_phy_dx_delay0_inner0 to fix the incorrect offsets and
rename the existing function to mctl_phy_dx_delay0_inner1 for the
offsets it correctly handles.

Also add memory barriers that are also present in the H616 code while
at it.

This fixes detection of 4 GiB DRAM on some boards using LPDDR4.

Signed-off-by: Paul Kocialkowski <paulk@sys-base.io>
Sponsored-by: MEC Electronics GmbH <https://www.mec.at/>
---
 arch/arm/mach-sunxi/dram_sun50i_a133.c | 61 +++++++++++++++++---------
 1 file changed, 41 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-sunxi/dram_sun50i_a133.c b/arch/arm/mach-sunxi/dram_sun50i_a133.c
index 204810aecf2a..568dc1eea2ea 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_a133.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_a133.c
@@ -931,7 +931,24 @@ static inline void mctl_phy_dx_delay1_inner(u32 *base, u32 val1, u32 val2)
 	writel_relaxed(val2, ptr + 48);
 }
 
-static inline void mctl_phy_dx_delay0_inner(u32 *base1, u32 *base2, u32 val1,
+static inline void mctl_phy_dx_delay0_inner0(u32 *base1, u32 *base2, u32 val1,
+					    u32 val2)
+{
+	u32 *ptr = base1;
+
+	for (int i = 0; i < 9; i++) {
+		writel_relaxed(val1, ptr);
+		writel_relaxed(val1, ptr + 0x30);
+		ptr += 2;
+	}
+
+	writel_relaxed(val2, base2);
+	writel_relaxed(val2, base2 + 48);
+	writel_relaxed(val2, ptr);
+	writel_relaxed(val2, base2 + 24);
+}
+
+static inline void mctl_phy_dx_delay0_inner1(u32 *base1, u32 *base2, u32 val1,
 					    u32 val2)
 {
 	u32 *ptr = base1;
@@ -975,6 +992,8 @@ static void mctl_phy_dx_delay_compensation(const struct dram_para *para)
 					 (para->tpr11 >> 24) & 0x3f,
 					 (para->para0 >> 24) & 0x3f);
 
+		dmb();
+
 		setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x60, 1);
 	}
 
@@ -982,25 +1001,27 @@ static void mctl_phy_dx_delay_compensation(const struct dram_para *para)
 		clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x54, BIT(7));
 		clrbits_le32(SUNXI_DRAM_PHY0_BASE + 0x190, BIT(2));
 
-		mctl_phy_dx_delay0_inner((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x480),
-					 (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x528),
-					 para->tpr12 & 0x3f,
-					 para->tpr14 & 0x3f);
-
-		mctl_phy_dx_delay0_inner((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x4d4),
-					 (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x52c),
-					 (para->tpr12 >> 8) & 0x3f,
-					 (para->tpr14 >> 8) & 0x3f);
-
-		mctl_phy_dx_delay0_inner((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x600),
-					 (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x6a8),
-					 (para->tpr12 >> 16) & 0x3f,
-					 (para->tpr14 >> 16) & 0x3f);
-
-		mctl_phy_dx_delay0_inner((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x6ac),
-					 (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x528),
-					 (para->tpr12 >> 24) & 0x3f,
-					 (para->tpr14 >> 24) & 0x3f);
+		mctl_phy_dx_delay0_inner0((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x480),
+					  (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x528),
+					  para->tpr12 & 0x3f,
+					  para->tpr14 & 0x3f);
+
+		mctl_phy_dx_delay0_inner1((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x4d4),
+					  (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x52c),
+					  (para->tpr12 >> 8) & 0x3f,
+					  (para->tpr14 >> 8) & 0x3f);
+
+		mctl_phy_dx_delay0_inner0((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x600),
+					  (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x6a8),
+					  (para->tpr12 >> 16) & 0x3f,
+					  (para->tpr14 >> 16) & 0x3f);
+
+		mctl_phy_dx_delay0_inner1((u32 *)(SUNXI_DRAM_PHY0_BASE + 0x654),
+					  (u32 *)(SUNXI_DRAM_PHY0_BASE + 0x6ac),
+					  (para->tpr12 >> 24) & 0x3f,
+					  (para->tpr14 >> 24) & 0x3f);
+
+		dmb();
 
 		setbits_le32(SUNXI_DRAM_PHY0_BASE + 0x54, BIT(7));
 	}
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 3/3] sunxi: a133: dram: Align parameters terminology with Allwinner
  2026-01-28 23:57 [PATCH v2 1/3] sunxi: a133: dram: Add NSI arbiter configuration support Paul Kocialkowski
  2026-01-28 23:57 ` [PATCH v2 2/3] sunxi: a133: dram: Fix PHY dx delays offsets and add dmb Paul Kocialkowski
@ 2026-01-28 23:57 ` Paul Kocialkowski
  2026-02-04 17:36   ` Jernej Škrabec
  2026-02-04 17:33 ` [PATCH v2 1/3] sunxi: a133: dram: Add NSI arbiter configuration support Jernej Škrabec
  2 siblings, 1 reply; 6+ messages in thread
From: Paul Kocialkowski @ 2026-01-28 23:57 UTC (permalink / raw)
  To: u-boot
  Cc: Tom Rini, Jagan Teki, Andre Przywara, Chen-Yu Tsai, Icenowy Zheng,
	Jernej Skrabec, Paul Kocialkowski, Paul Kocialkowski

There is a mistmatch between Allwinner's dram_para BSP definitions and the
parameters names in mainline u-boot for TPR1-3. What we call TPR1 is actually
MR22 while TPR2 is TPR0 and TPR3 is TPR1. MR22 does get written to the
corresponding register. This only concerns LPDDR4 support.

Introduce a new Kconfig entry for MR22 and proceed with the rename.
Update the only config currently using it.

See the list of parameters from the Allwinner BSP at the end of:
https://linux-sunxi.org/A133/DRAMC

Note that the H616/H6 code is coherent with this new TPR0 definition
(and does not use TPR1 and MR22).

Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Sponsored-by: MEC Electronics GmbH <https://www.mec.at/>
---
 arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h |  2 ++
 arch/arm/mach-sunxi/Kconfig                        |  7 +++++++
 arch/arm/mach-sunxi/dram_sun50i_a133.c             | 12 ++++++------
 configs/liontron-h-a133l_defconfig                 |  6 +++---
 4 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h
index eadec74cc2b6..da3ee5fa0161 100644
--- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h
+++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h
@@ -241,6 +241,8 @@ struct dram_para {
 	uint32_t mr12;
 	uint32_t mr13;
 	uint32_t mr14;
+	uint32_t mr22;
+	uint32_t tpr0;
 	uint32_t tpr1;
 	uint32_t tpr2;
 	uint32_t tpr3;
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index e979ee4a2ccb..70885c1c78bc 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -118,6 +118,13 @@ config DRAM_SUNXI_MR14
 	help
 	  MR14 value from vendor DRAM settings.
 
+config DRAM_SUNXI_MR22
+	hex "DRAM MR22 parameter"
+	depends on DRAM_SUN50I_A133
+	default 0x0
+	help
+	  MR22 value from vendor DRAM settings.
+
 config DRAM_SUNXI_TPR0
 	hex "DRAM TPR0 parameter"
 	default 0x0
diff --git a/arch/arm/mach-sunxi/dram_sun50i_a133.c b/arch/arm/mach-sunxi/dram_sun50i_a133.c
index 568dc1eea2ea..c4022b76fcb4 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_a133.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_a133.c
@@ -486,8 +486,8 @@ static void mctl_drive_odt_config(const struct dram_para *para)
 
 		writel_relaxed(val, base);
 		if (para->type == SUNXI_DRAM_TYPE_LPDDR4) {
-			if (para->tpr3 & 0x1f1f1f1f)
-				val = (para->tpr3 >> (i * 8)) & 0x1f;
+			if (para->tpr1 & 0x1f1f1f1f)
+				val = (para->tpr1 >> (i * 8)) & 0x1f;
 			else
 				val = 4;
 		}
@@ -528,7 +528,7 @@ static void mctl_phy_ca_bit_delay_compensation(const struct dram_para *para)
 	u32 *ptr;
 
 	if (para->tpr10 & BIT(31)) {
-		val = para->tpr2;
+		val = para->tpr0;
 	} else {
 		val = ((para->tpr10 << 1) & 0x1e) |
 		      ((para->tpr10 << 5) & 0x1e00) |
@@ -841,7 +841,7 @@ static void mctl_dfi_init(const struct dram_para *para)
 		mctl_mr_write_lpddr4(12, para->mr12);
 		mctl_mr_write_lpddr4(13, para->mr13);
 		mctl_mr_write_lpddr4(14, para->mr14);
-		mctl_mr_write_lpddr4(22, para->tpr1);
+		mctl_mr_write_lpddr4(22, para->mr22);
 		break;
 	}
 
@@ -1242,7 +1242,6 @@ static const struct dram_para para = {
 #elif defined(CONFIG_SUNXI_DRAM_LPDDR4)
 	.type = SUNXI_DRAM_TYPE_LPDDR4,
 #endif
-	/* TODO: Populate from config */
 	.dx_odt = CONFIG_DRAM_SUNXI_DX_ODT,
 	.dx_dri = CONFIG_DRAM_SUNXI_DX_DRI,
 	.ca_dri = CONFIG_DRAM_SUNXI_CA_DRI,
@@ -1251,9 +1250,10 @@ static const struct dram_para para = {
 	.mr12 = CONFIG_DRAM_SUNXI_MR12,
 	.mr13 = CONFIG_DRAM_SUNXI_MR13,
 	.mr14 = CONFIG_DRAM_SUNXI_MR14,
+	.mr22 = CONFIG_DRAM_SUNXI_MR22,
+	.tpr0 = CONFIG_DRAM_SUNXI_TPR0,
 	.tpr1 = CONFIG_DRAM_SUNXI_TPR1,
 	.tpr2 = CONFIG_DRAM_SUNXI_TPR2,
-	.tpr3 = CONFIG_DRAM_SUNXI_TPR3,
 	.tpr6 = CONFIG_DRAM_SUNXI_TPR6,
 	.tpr10 = CONFIG_DRAM_SUNXI_TPR10,
 	.tpr11 = CONFIG_DRAM_SUNXI_TPR11,
diff --git a/configs/liontron-h-a133l_defconfig b/configs/liontron-h-a133l_defconfig
index 56c5262f2678..831d5b56e3a7 100644
--- a/configs/liontron-h-a133l_defconfig
+++ b/configs/liontron-h-a133l_defconfig
@@ -10,9 +10,9 @@ CONFIG_DRAM_SUNXI_PARA0=0xd0a050c
 CONFIG_DRAM_SUNXI_MR11=0x4
 CONFIG_DRAM_SUNXI_MR12=0x72
 CONFIG_DRAM_SUNXI_MR14=0x7
-CONFIG_DRAM_SUNXI_TPR1=0x26
-CONFIG_DRAM_SUNXI_TPR2=0x6060606
-CONFIG_DRAM_SUNXI_TPR3=0x84040404
+CONFIG_DRAM_SUNXI_MR22=0x26
+CONFIG_DRAM_SUNXI_TPR0=0x6060606
+CONFIG_DRAM_SUNXI_TPR1=0x84040404
 CONFIG_DRAM_SUNXI_TPR6=0x48000000
 CONFIG_DRAM_SUNXI_TPR10=0x273333
 CONFIG_DRAM_SUNXI_TPR11=0x231d151c
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 1/3] sunxi: a133: dram: Add NSI arbiter configuration support
  2026-01-28 23:57 [PATCH v2 1/3] sunxi: a133: dram: Add NSI arbiter configuration support Paul Kocialkowski
  2026-01-28 23:57 ` [PATCH v2 2/3] sunxi: a133: dram: Fix PHY dx delays offsets and add dmb Paul Kocialkowski
  2026-01-28 23:57 ` [PATCH v2 3/3] sunxi: a133: dram: Align parameters terminology with Allwinner Paul Kocialkowski
@ 2026-02-04 17:33 ` Jernej Škrabec
  2 siblings, 0 replies; 6+ messages in thread
From: Jernej Škrabec @ 2026-02-04 17:33 UTC (permalink / raw)
  To: u-boot, Paul Kocialkowski
  Cc: Tom Rini, Jagan Teki, Andre Przywara, Chen-Yu Tsai, Icenowy Zheng,
	Paul Kocialkowski

Dne četrtek, 29. januar 2026 ob 00:57:15 Srednjeevropski standardni čas je Paul Kocialkowski napisal(a):
> From: Paul Kocialkowski <paulk@sys-base.io>
> 
> In previous generations of Allwinner SoCs, the memory bus (MBUS) access
> arbitration was configured as part of the DRAM top registers. This is no
> longer the case starting with the A133, which has a dedicated base
> address for the bus arbiter that is now called NSI instead of MBUS.
> 
> NSI appears to be a later iteration of MBUS design, with new dedicated
> registers that resemble the previous MBUS ones. Despite NSI not being
> documented in the manual, the A133 BSP includes a nsi driver with some
> description of the registers. Like previous generations, it implements
> port arbitration priority for DRAM access and also supports an optional
> QoS mode based on bandwidth limits.
> 
> Configuring port arbitration priority is especially important to make
> sure that critical masters are not starved by other less important
> ones. This is especially the case with the display engine that needs
> to be able to fetch pixels in time for scanout and can easily be
> starved by CPU or GPU access.
> 
> This introduces support for the NSI arbiter in the A133 DRAM init
> code. The list and order of available ports are highly SoC-specific
> and the default config values are set to match the BSP's defaults.
> 
> Signed-off-by: Paul Kocialkowski <paulk@sys-base.io>
> Sponsored-by: MEC Electronics GmbH <https://www.mec.at/>

This code looks good in general. However, since NSI seems common
thing for newer SoCs (like A523, which is already included in U-Boot),
I think it would be better to make some kind of NSI module instead of
duplicating definitions for each SoCs.

I dislike current MBUS approach, but that was done due to organic code
growth without planning. Let's not repeat that here.

Best regards,
Jernej

> ---
>  .../include/asm/arch-sunxi/cpu_sun50i_h6.h    |  4 ++
>  .../include/asm/arch-sunxi/dram_sun50i_a133.h | 36 ++++++++++
>  arch/arm/mach-sunxi/dram_sun50i_a133.c        | 67 ++++++++++++++++++-
>  3 files changed, 106 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> index 2a9b086991c3..8e80c520706b 100644
> --- a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> @@ -16,6 +16,10 @@
>  
>  #define SUNXI_GIC400_BASE		0x03020000
>  
> +#ifdef CONFIG_MACH_SUN50I_A133
> +#define SUNXI_NSI_BASE			0x03100000
> +#endif
> +
>  #ifdef CONFIG_MACH_SUN50I_H6
>  #define SUNXI_DRAM_COM_BASE		0x04002000
>  #define SUNXI_DRAM_CTL0_BASE		0x04003000
> diff --git a/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h b/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h
> index a5fc6ad36560..eadec74cc2b6 100644
> --- a/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h
> +++ b/arch/arm/include/asm/arch-sunxi/dram_sun50i_a133.h
> @@ -24,6 +24,42 @@ static inline int ns_to_t(int nanoseconds)
>  	return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
>  }
>  
> +#define SUNXI_NSI_MODE_REG(i)		((i) * 0x200 + 0x10)
> +#define SUNXI_NSI_PRI_CFG_REG(i)	((i) * 0x200 + 0x14)
> +#define SUNXI_NSI_PRI_CFG_RD(v)		(((v) & 0x3) << 2)
> +#define SUNXI_NSI_PRI_CFG_WR(v)		((v) & 0x3)
> +#define SUNXI_NSI_PRI_CFG_LOWEST	0
> +#define SUNXI_NSI_PRI_CFG_LOW		1
> +#define SUNXI_NSI_PRI_CFG_HIGH		2
> +#define SUNXI_NSI_PRI_CFG_HIGHEST	3
> +#define SUNXI_NSI_IO_CFG_REG(i)		((i) * 0x200 + 0x18)
> +#define SUNXI_NSI_IO_CFG_QOS_SEL_OUTPUT	0
> +#define SUNXI_NSI_IO_CFG_QOS_SEL_INPUT	1
> +#define SUNXI_NSI_ENABLE_REG(i)		((i) * 0x200 + 0xc0)
> +
> +enum sunxi_nsi_port {
> +	SUNXI_NSI_PORT_CPU	= 0,
> +	SUNXI_NSI_PORT_GPU,
> +	SUNXI_NSI_PORT_SD1,
> +	SUNXI_NSI_PORT_MSTG,
> +	SUNXI_NSI_PORT_GMAC0,
> +	SUNXI_NSI_PORT_GMAC1,
> +	SUNXI_NSI_PORT_USB0,
> +	SUNXI_NSI_PORT_USB1,
> +	SUNXI_NSI_PORT_NDFC,
> +	SUNXI_NSI_PORT_DMAC,
> +	SUNXI_NSI_PORT_CE,
> +	SUNXI_NSI_PORT_DE0,
> +	SUNXI_NSI_PORT_DE1,
> +	SUNXI_NSI_PORT_VE,
> +	SUNXI_NSI_PORT_CSI,
> +	SUNXI_NSI_PORT_ISP,
> +	SUNXI_NSI_PORT_G2D,
> +	SUNXI_NSI_PORT_EINK,
> +	SUNXI_NSI_PORT_IOMMU,
> +	SUNXI_NSI_PORT_CPUS,
> +};
> +
>  /* MBUS part is largely the same as in H6, except for one special register */
>  #define MCTL_COM_UNK_008	0x008
>  /* NOTE: This register has the same importance as mctl_ctl->clken in H616 */
> diff --git a/arch/arm/mach-sunxi/dram_sun50i_a133.c b/arch/arm/mach-sunxi/dram_sun50i_a133.c
> index 1496f99624dd..204810aecf2a 100644
> --- a/arch/arm/mach-sunxi/dram_sun50i_a133.c
> +++ b/arch/arm/mach-sunxi/dram_sun50i_a133.c
> @@ -69,6 +69,66 @@ static const u8 phy_init[] = {
>  };
>  #endif
>  
> +static void nsi_configure_port(unsigned int port, u8 pri, u8 qos_sel)
> +{
> +	void *base = (void *)SUNXI_NSI_BASE;
> +	u32 pri_cfg;
> +
> +	/* QoS with bandwidth limits is not supported, disable it. */
> +	writel(0, base + SUNXI_NSI_MODE_REG(port));
> +	writel(0, base + SUNXI_NSI_ENABLE_REG(port));
> +
> +	/*
> +	 * QoS direction selection should not be in use, but set it nevertheless
> +	 * to match the BSP behavior (in case it has some other meaning).
> +	 */
> +	writel(qos_sel, base + SUNXI_NSI_IO_CFG_REG(port));
> +
> +	/* Port priority is always active. */
> +	pri_cfg = SUNXI_NSI_PRI_CFG_RD(pri) | SUNXI_NSI_PRI_CFG_WR(pri);
> +
> +	writel(pri_cfg, base + SUNXI_NSI_PRI_CFG_REG(port));
> +}
> +
> +#define NSI_CONF(port, pri, qos_sel) \
> +	{ SUNXI_NSI_PORT_ ## port, SUNXI_NSI_PRI_CFG_ ## pri, \
> +	  SUNXI_NSI_IO_CFG_QOS_SEL_ ## qos_sel }
> +
> +static void nsi_set_master_priority(void)
> +{
> +	struct {
> +		unsigned int port;
> +		u8 pri;
> +		u8 qos_sel;
> +	} ports[] = {
> +		NSI_CONF(CPU,	LOWEST,		INPUT),
> +		NSI_CONF(GPU,	LOWEST,		INPUT),
> +		NSI_CONF(SD1,	LOWEST,		OUTPUT),
> +		NSI_CONF(MSTG,	LOWEST,		OUTPUT),
> +		NSI_CONF(GMAC0,	LOWEST,		OUTPUT),
> +		NSI_CONF(GMAC1,	LOWEST,		OUTPUT),
> +		NSI_CONF(USB0,	LOWEST,		OUTPUT),
> +		NSI_CONF(USB1,	LOWEST,		OUTPUT),
> +		NSI_CONF(NDFC,	LOWEST,		OUTPUT),
> +		NSI_CONF(DMAC,	LOWEST,		OUTPUT),
> +		NSI_CONF(CE,	LOWEST,		OUTPUT),
> +		NSI_CONF(DE0,	HIGH,		INPUT),
> +		NSI_CONF(DE1,	HIGH,		INPUT),
> +		NSI_CONF(VE,	LOWEST,		INPUT),
> +		NSI_CONF(CSI,	HIGH,		INPUT),
> +		NSI_CONF(ISP,	HIGH,		INPUT),
> +		NSI_CONF(G2D,	LOWEST,		INPUT),
> +		NSI_CONF(EINK,	LOWEST,		OUTPUT),
> +		NSI_CONF(IOMMU,	HIGHEST,	INPUT),
> +		NSI_CONF(CPUS,	LOWEST,		OUTPUT),
> +	};
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(ports); i++)
> +		nsi_configure_port(ports[i].port, ports[i].pri,
> +				   ports[i].qos_sel);
> +}
> +
>  static void mctl_clk_init(u32 clk)
>  {
>  	void * const ccm = (void *)SUNXI_CCM_BASE;
> @@ -1184,6 +1244,7 @@ static const struct dram_para para = {
>  unsigned long sunxi_dram_init(void)
>  {
>  	struct dram_config config;
> +	unsigned long size;
>  
>  	/* Writing to undocumented SYS_CFG area, according to user manual. */
>  	setbits_le32(0x03000160, BIT(8));
> @@ -1200,5 +1261,9 @@ unsigned long sunxi_dram_init(void)
>  	      1U << config.bankgrps, 1U << config.ranks,
>  	      16U << config.bus_full_width);
>  
> -	return calculate_dram_size(&config);
> +	size = calculate_dram_size(&config);
> +
> +	nsi_set_master_priority();
> +
> +	return size;
>  }
> 





^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 2/3] sunxi: a133: dram: Fix PHY dx delays offsets and add dmb
  2026-01-28 23:57 ` [PATCH v2 2/3] sunxi: a133: dram: Fix PHY dx delays offsets and add dmb Paul Kocialkowski
@ 2026-02-04 17:35   ` Jernej Škrabec
  0 siblings, 0 replies; 6+ messages in thread
From: Jernej Škrabec @ 2026-02-04 17:35 UTC (permalink / raw)
  To: u-boot, Paul Kocialkowski
  Cc: Tom Rini, Jagan Teki, Andre Przywara, Chen-Yu Tsai, Icenowy Zheng,
	Paul Kocialkowski

Dne četrtek, 29. januar 2026 ob 00:57:16 Srednjeevropski standardni čas je Paul Kocialkowski napisal(a):
> From: Paul Kocialkowski <paulk@sys-base.io>
> 
> Some of the offsets for the DRAM PHY dx delays are wrong (as compared
> to the H616 code and the reference binary) since the
> mctl_phy_dx_delay0_inner function does not perform the correct
> calculation for some of them.
> 
> Introduce a mctl_phy_dx_delay0_inner0 to fix the incorrect offsets and
> rename the existing function to mctl_phy_dx_delay0_inner1 for the
> offsets it correctly handles.
> 
> Also add memory barriers that are also present in the H616 code while
> at it.
> 
> This fixes detection of 4 GiB DRAM on some boards using LPDDR4.
> 
> Signed-off-by: Paul Kocialkowski <paulk@sys-base.io>
> Sponsored-by: MEC Electronics GmbH <https://www.mec.at/>

Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>

Best regards,
Jernej



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 3/3] sunxi: a133: dram: Align parameters terminology with Allwinner
  2026-01-28 23:57 ` [PATCH v2 3/3] sunxi: a133: dram: Align parameters terminology with Allwinner Paul Kocialkowski
@ 2026-02-04 17:36   ` Jernej Škrabec
  0 siblings, 0 replies; 6+ messages in thread
From: Jernej Škrabec @ 2026-02-04 17:36 UTC (permalink / raw)
  To: u-boot, Paul Kocialkowski
  Cc: Tom Rini, Jagan Teki, Andre Przywara, Chen-Yu Tsai, Icenowy Zheng,
	Paul Kocialkowski, Paul Kocialkowski

Dne četrtek, 29. januar 2026 ob 00:57:17 Srednjeevropski standardni čas je Paul Kocialkowski napisal(a):
> There is a mistmatch between Allwinner's dram_para BSP definitions and the
> parameters names in mainline u-boot for TPR1-3. What we call TPR1 is actually
> MR22 while TPR2 is TPR0 and TPR3 is TPR1. MR22 does get written to the
> corresponding register. This only concerns LPDDR4 support.
> 
> Introduce a new Kconfig entry for MR22 and proceed with the rename.
> Update the only config currently using it.
> 
> See the list of parameters from the Allwinner BSP at the end of:
> https://linux-sunxi.org/A133/DRAMC
> 
> Note that the H616/H6 code is coherent with this new TPR0 definition
> (and does not use TPR1 and MR22).
> 
> Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
> Sponsored-by: MEC Electronics GmbH <https://www.mec.at/>

Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>

Best regards,
Jernej



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-02-04 18:19 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-28 23:57 [PATCH v2 1/3] sunxi: a133: dram: Add NSI arbiter configuration support Paul Kocialkowski
2026-01-28 23:57 ` [PATCH v2 2/3] sunxi: a133: dram: Fix PHY dx delays offsets and add dmb Paul Kocialkowski
2026-02-04 17:35   ` Jernej Škrabec
2026-01-28 23:57 ` [PATCH v2 3/3] sunxi: a133: dram: Align parameters terminology with Allwinner Paul Kocialkowski
2026-02-04 17:36   ` Jernej Škrabec
2026-02-04 17:33 ` [PATCH v2 1/3] sunxi: a133: dram: Add NSI arbiter configuration support Jernej Škrabec

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox