[v2,2/2] sunxi: A133: dram: Add NSI arbiter configuration support

Message ID 20260430135838.3438728-3-andre.przywara@arm.com (mailing list archive)
State New
Headers
Series sunxi: DRAM: rework NSI priority settings |

Commit Message

Andre Przywara April 30, 2026, 1:58 p.m. UTC
From: Paul Kocialkowski <contact@paulk.fr>

The Allwinner DRAM controllers contains logic to assign priorities to
various DRAM DMA masters. Configuring this DRAM port arbitration priority
correctly is 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.

Add support for configuring the NSI arbiter in the A133 DRAM init code,
using the recently refactored NSI code already used on the A523.
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>
[Andre: using new generic NSI function]
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
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 | 23 ++++++++++
 arch/arm/mach-sunxi/Makefile                  |  2 +-
 arch/arm/mach-sunxi/dram_sun50i_a133.c        | 43 ++++++++++++++++++-
 4 files changed, 70 insertions(+), 2 deletions(-)
  

Comments

Paul Kocialkowski May 8, 2026, 12:25 p.m. UTC | #1
Hi Andre,

On Thu 30 Apr 26, 15:58, Andre Przywara wrote:
> From: Paul Kocialkowski <contact@paulk.fr>

Actually I made a mistake when sending this initially and this should
be my work email instead:

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

All the best,

Paul

> 
> The Allwinner DRAM controllers contains logic to assign priorities to
> various DRAM DMA masters. Configuring this DRAM port arbitration priority
> correctly is 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.
> 
> Add support for configuring the NSI arbiter in the A133 DRAM init code,
> using the recently refactored NSI code already used on the A523.
> 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>
> [Andre: using new generic NSI function]
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> 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 | 23 ++++++++++
>  arch/arm/mach-sunxi/Makefile                  |  2 +-
>  arch/arm/mach-sunxi/dram_sun50i_a133.c        | 43 ++++++++++++++++++-
>  4 files changed, 70 insertions(+), 2 deletions(-)
> 
> 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 b0f2d3f4656..c31437f9acc 100644
> --- a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> +++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
> @@ -17,6 +17,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 01f2214cd15..1e8e0f7ab96 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,29 @@ static inline int ns_to_t(int nanoseconds)
>  	return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
>  }
>  
> +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/Makefile b/arch/arm/mach-sunxi/Makefile
> index 3ef0113ea43..30cce7d1784 100644
> --- a/arch/arm/mach-sunxi/Makefile
> +++ b/arch/arm/mach-sunxi/Makefile
> @@ -48,7 +48,7 @@ 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)	+= dram_timings/
> -obj-$(CONFIG_DRAM_SUN50I_A133)	+= dram_sun50i_a133.o
> +obj-$(CONFIG_DRAM_SUN50I_A133)	+= dram_sun50i_a133.o sunxi_nsi.o
>  obj-$(CONFIG_DRAM_SUN50I_A133)	+= dram_timings/
>  obj-$(CONFIG_MACH_SUN55I_A523)	+= dram_sun55i_a523.o dram_dw_helpers.o sunxi_nsi.o
>  obj-$(CONFIG_DRAM_SUN55I_A523)	+= dram_timings/
> diff --git a/arch/arm/mach-sunxi/dram_sun50i_a133.c b/arch/arm/mach-sunxi/dram_sun50i_a133.c
> index ca3e2513c69..433044e1e2b 100644
> --- a/arch/arm/mach-sunxi/dram_sun50i_a133.c
> +++ b/arch/arm/mach-sunxi/dram_sun50i_a133.c
> @@ -21,6 +21,7 @@
>  #include <asm/arch/cpu.h>
>  #include <asm/arch/dram.h>
>  #include <asm/arch/prcm.h>
> +#include <asm/arch/sunxi_nsi.h>
>  #include <asm/io.h>
>  #include <init.h>
>  #include <linux/bitops.h>
> @@ -69,6 +70,41 @@ static const u8 phy_init[] = {
>  };
>  #endif
>  
> +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;
> @@ -1205,6 +1241,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));
> @@ -1221,5 +1258,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.43.0
>
  

Patch

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 b0f2d3f4656..c31437f9acc 100644
--- a/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
+++ b/arch/arm/include/asm/arch-sunxi/cpu_sun50i_h6.h
@@ -17,6 +17,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 01f2214cd15..1e8e0f7ab96 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,29 @@  static inline int ns_to_t(int nanoseconds)
 	return DIV_ROUND_UP(ctrl_freq * nanoseconds, 1000);
 }
 
+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/Makefile b/arch/arm/mach-sunxi/Makefile
index 3ef0113ea43..30cce7d1784 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -48,7 +48,7 @@  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)	+= dram_timings/
-obj-$(CONFIG_DRAM_SUN50I_A133)	+= dram_sun50i_a133.o
+obj-$(CONFIG_DRAM_SUN50I_A133)	+= dram_sun50i_a133.o sunxi_nsi.o
 obj-$(CONFIG_DRAM_SUN50I_A133)	+= dram_timings/
 obj-$(CONFIG_MACH_SUN55I_A523)	+= dram_sun55i_a523.o dram_dw_helpers.o sunxi_nsi.o
 obj-$(CONFIG_DRAM_SUN55I_A523)	+= dram_timings/
diff --git a/arch/arm/mach-sunxi/dram_sun50i_a133.c b/arch/arm/mach-sunxi/dram_sun50i_a133.c
index ca3e2513c69..433044e1e2b 100644
--- a/arch/arm/mach-sunxi/dram_sun50i_a133.c
+++ b/arch/arm/mach-sunxi/dram_sun50i_a133.c
@@ -21,6 +21,7 @@ 
 #include <asm/arch/cpu.h>
 #include <asm/arch/dram.h>
 #include <asm/arch/prcm.h>
+#include <asm/arch/sunxi_nsi.h>
 #include <asm/io.h>
 #include <init.h>
 #include <linux/bitops.h>
@@ -69,6 +70,41 @@  static const u8 phy_init[] = {
 };
 #endif
 
+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;
@@ -1205,6 +1241,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));
@@ -1221,5 +1258,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;
 }