diff mbox

[U-Boot,RFC,4/4] arm: socfpga: scrub the SDRAM to properly enable ECC support

Message ID 20161010155223.23751-5-dinguyen@kernel.org
State RFC
Headers show

Commit Message

Dinh Nguyen Oct. 10, 2016, 3:52 p.m. UTC
From: Dinh Nguyen <dinguyen@opensource.altera.com>

In order for SDRAM ECC to work correctly, the SDRAM needs to get zero'd which
enables the ECC bit. By using the PL330 DMA to fill the SDRAM with zeroes,
the operation is completed in ~1.2 seconds, versus ~14 seconds with a memset.

Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
---
 arch/arm/mach-socfpga/include/mach/reset_manager.h | 21 ++++++++++++++++
 arch/arm/mach-socfpga/include/mach/sdram.h         |  2 ++
 arch/arm/mach-socfpga/spl.c                        |  8 +++++++
 arch/arm/mach-socfpga/wrap_sdram_config.c          | 28 ++++++++++++++++++++++
 configs/socfpga_cyclone5_defconfig                 |  2 ++
 5 files changed, 61 insertions(+)

Comments

Chin Liang See Oct. 12, 2016, 4:13 p.m. UTC | #1
On Mon, 2016-10-10 at 10:52 -0500, Dinh Nguyen wrote:
> From: Dinh Nguyen <dinguyen@opensource.altera.com>
> 
> In order for SDRAM ECC to work correctly, the SDRAM needs to get
> zero'd which
> enables the ECC bit. By using the PL330 DMA to fill the SDRAM with
> zeroes,
> the operation is completed in ~1.2 seconds, versus ~14 seconds with a
> memset.
> 
> Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
> ---
>  arch/arm/mach-socfpga/include/mach/reset_manager.h | 21
> ++++++++++++++++
>  arch/arm/mach-socfpga/include/mach/sdram.h         |  2 ++
>  arch/arm/mach-socfpga/spl.c                        |  8 +++++++
>  arch/arm/mach-socfpga/wrap_sdram_config.c          | 28
> ++++++++++++++++++++++
>  configs/socfpga_cyclone5_defconfig                 |  2 ++
>  5 files changed, 61 insertions(+)
> 

[..]

> diff --git a/arch/arm/mach-socfpga/wrap_sdram_config.c
> b/arch/arm/mach-socfpga/wrap_sdram_config.c
> index 31cc7de..dfa6423 100644
> --- a/arch/arm/mach-socfpga/wrap_sdram_config.c
> +++ b/arch/arm/mach-socfpga/wrap_sdram_config.c
> @@ -5,8 +5,10 @@
>   */
>  
>  #include <common.h>
> +#include <dma.h>
>  #include <errno.h>
>  #include <asm/arch/sdram.h>
> +#include <asm/pl330.h>
>  
>  /* Board-specific header. */
>  #include <qts/sdram_config.h>
> @@ -310,3 +312,29 @@ const struct socfpga_sdram_misc_config
> *socfpga_get_sdram_misc_config(void)
>  {
>  	return &misc_config;
>  }
> +
> +#if (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN == 1)
> +/* init the whole SDRAM ECC bit */
> +void sdram_ecc_init(void)
> +{
> +	struct pl330_transfer_struct pl330;
> +	u8 pl330_buf[2000];

Would need size of 2500 if the SDRAM size is 2GB

Thanks
Chin Liang
Marek Vasut Oct. 16, 2016, 4:03 p.m. UTC | #2
On 10/10/2016 05:52 PM, Dinh Nguyen wrote:
> From: Dinh Nguyen <dinguyen@opensource.altera.com>
> 
> In order for SDRAM ECC to work correctly, the SDRAM needs to get zero'd which
> enables the ECC bit. By using the PL330 DMA to fill the SDRAM with zeroes,
> the operation is completed in ~1.2 seconds, versus ~14 seconds with a memset.
> 
> Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
> ---
>  arch/arm/mach-socfpga/include/mach/reset_manager.h | 21 ++++++++++++++++
>  arch/arm/mach-socfpga/include/mach/sdram.h         |  2 ++
>  arch/arm/mach-socfpga/spl.c                        |  8 +++++++
>  arch/arm/mach-socfpga/wrap_sdram_config.c          | 28 ++++++++++++++++++++++
>  configs/socfpga_cyclone5_defconfig                 |  2 ++
>  5 files changed, 61 insertions(+)
> 
> diff --git a/arch/arm/mach-socfpga/include/mach/reset_manager.h b/arch/arm/mach-socfpga/include/mach/reset_manager.h
> index 2f070f2..9750026 100644
> --- a/arch/arm/mach-socfpga/include/mach/reset_manager.h
> +++ b/arch/arm/mach-socfpga/include/mach/reset_manager.h
> @@ -79,4 +79,25 @@ struct socfpga_reset_manager {
>  /* Create a human-readable reference to SoCFPGA reset. */
>  #define SOCFPGA_RESET(_name)	RSTMGR_##_name
>  
> +#define RSTMGR_STAT_L4WD1RST_MASK 0x00008000
> +#define RSTMGR_STAT_L4WD0RST_MASK 0x00004000
> +#define RSTMGR_STAT_MPUWD1RST_MASK 0x00002000
> +#define RSTMGR_STAT_MPUWD0RST_MASK 0x00001000
> +#define RSTMGR_STAT_SWWARMRST_MASK 0x00000400
> +#define RSTMGR_STAT_FPGAWARMRST_MASK 0x00000200
> +#define RSTMGR_STAT_NRSTPINRST_MASK 0x00000100
> +#define RSTMGR_STAT_SWCOLDRST_MASK 0x00000010
> +#define RSTMGR_STAT_CONFIGIOCOLDRST_MASK 0x00000008
> +#define RSTMGR_STAT_FPGACOLDRST_MASK 0x00000004
> +#define RSTMGR_STAT_NPORPINRST_MASK 0x00000002
> +#define RSTMGR_STAT_PORVOLTRST_MASK 0x00000001
> +
> +#define RSTMGR_WARMRST_MASK	(RSTMGR_STAT_SWWARMRST_MASK | \
> +				 RSTMGR_STAT_L4WD0RST_MASK | \
> +				 RSTMGR_STAT_L4WD1RST_MASK | \
> +				 RSTMGR_STAT_MPUWD1RST_MASK | \
> +				 RSTMGR_STAT_MPUWD0RST_MASK | \
> +				 RSTMGR_STAT_FPGAWARMRST_MASK | \
> +				 RSTMGR_STAT_NRSTPINRST_MASK)

This should go into separate patch.

>  #endif /* _RESET_MANAGER_H_ */


[...]

> diff --git a/arch/arm/mach-socfpga/wrap_sdram_config.c b/arch/arm/mach-socfpga/wrap_sdram_config.c
> index 31cc7de..dfa6423 100644
> --- a/arch/arm/mach-socfpga/wrap_sdram_config.c
> +++ b/arch/arm/mach-socfpga/wrap_sdram_config.c
> @@ -5,8 +5,10 @@
>   */
>  
>  #include <common.h>
> +#include <dma.h>
>  #include <errno.h>
>  #include <asm/arch/sdram.h>
> +#include <asm/pl330.h>
>  
>  /* Board-specific header. */
>  #include <qts/sdram_config.h>
> @@ -310,3 +312,29 @@ const struct socfpga_sdram_misc_config *socfpga_get_sdram_misc_config(void)
>  {
>  	return &misc_config;
>  }
> +
> +#if (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN == 1)
> +/* init the whole SDRAM ECC bit */
> +void sdram_ecc_init(void)
> +{
> +	struct pl330_transfer_struct pl330;
> +	u8 pl330_buf[2000];

Why is the buffer 2000 bytes long ?

> +	pl330.dst_addr = CONFIG_SYS_SDRAM_BASE;
> +	pl330.len = sdram_calculate_size();
> +	pl330.channel_num = 0;
> +	pl330.buf_size = sizeof(pl330_buf);
> +	pl330.buf = pl330_buf;
> +
> +	pl330.transfer_type = DMA_SUPPORTS_DEV_TO_MEM;
> +	pl330.reg_base = (void __iomem *)SOCFPGA_DMASECURE_ADDRESS;
> +
> +	puts("SDRAM: Initializing SDRAM ECC\n");
> +
> +	arm_pl330_transfer(&pl330);
> +
> +	printf("SDRAM: ECC initialized successfully\n");
> +}
> +#else
> +void sdram_ecc_init(void) {}
> +#endif
> diff --git a/configs/socfpga_cyclone5_defconfig b/configs/socfpga_cyclone5_defconfig
> index 42b71c3..89c3398 100644
> --- a/configs/socfpga_cyclone5_defconfig
> +++ b/configs/socfpga_cyclone5_defconfig
> @@ -59,3 +59,5 @@ CONFIG_G_DNL_MANUFACTURER="altera"
>  CONFIG_G_DNL_VENDOR_NUM=0x0525
>  CONFIG_G_DNL_PRODUCT_NUM=0xa4a5
>  CONFIG_USE_TINY_PRINTF=y
> +CONFIG_SPL_DMA_SUPPORT=y
> +CONFIG_PL330_DMA=y

This probably shouldn't be enabled by default, or should it ?

What about ArriaV SoCDK ?
diff mbox

Patch

diff --git a/arch/arm/mach-socfpga/include/mach/reset_manager.h b/arch/arm/mach-socfpga/include/mach/reset_manager.h
index 2f070f2..9750026 100644
--- a/arch/arm/mach-socfpga/include/mach/reset_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/reset_manager.h
@@ -79,4 +79,25 @@  struct socfpga_reset_manager {
 /* Create a human-readable reference to SoCFPGA reset. */
 #define SOCFPGA_RESET(_name)	RSTMGR_##_name
 
+#define RSTMGR_STAT_L4WD1RST_MASK 0x00008000
+#define RSTMGR_STAT_L4WD0RST_MASK 0x00004000
+#define RSTMGR_STAT_MPUWD1RST_MASK 0x00002000
+#define RSTMGR_STAT_MPUWD0RST_MASK 0x00001000
+#define RSTMGR_STAT_SWWARMRST_MASK 0x00000400
+#define RSTMGR_STAT_FPGAWARMRST_MASK 0x00000200
+#define RSTMGR_STAT_NRSTPINRST_MASK 0x00000100
+#define RSTMGR_STAT_SWCOLDRST_MASK 0x00000010
+#define RSTMGR_STAT_CONFIGIOCOLDRST_MASK 0x00000008
+#define RSTMGR_STAT_FPGACOLDRST_MASK 0x00000004
+#define RSTMGR_STAT_NPORPINRST_MASK 0x00000002
+#define RSTMGR_STAT_PORVOLTRST_MASK 0x00000001
+
+#define RSTMGR_WARMRST_MASK	(RSTMGR_STAT_SWWARMRST_MASK | \
+				 RSTMGR_STAT_L4WD0RST_MASK | \
+				 RSTMGR_STAT_L4WD1RST_MASK | \
+				 RSTMGR_STAT_MPUWD1RST_MASK | \
+				 RSTMGR_STAT_MPUWD0RST_MASK | \
+				 RSTMGR_STAT_FPGAWARMRST_MASK | \
+				 RSTMGR_STAT_NRSTPINRST_MASK)
+
 #endif /* _RESET_MANAGER_H_ */
diff --git a/arch/arm/mach-socfpga/include/mach/sdram.h b/arch/arm/mach-socfpga/include/mach/sdram.h
index f12bb84..5154ad2 100644
--- a/arch/arm/mach-socfpga/include/mach/sdram.h
+++ b/arch/arm/mach-socfpga/include/mach/sdram.h
@@ -20,6 +20,8 @@  const struct socfpga_sdram_rw_mgr_config *socfpga_get_sdram_rwmgr_config(void);
 const struct socfpga_sdram_io_config *socfpga_get_sdram_io_config(void);
 const struct socfpga_sdram_misc_config *socfpga_get_sdram_misc_config(void);
 
+void sdram_ecc_init(void);
+
 #define SDR_CTRLGRP_ADDRESS	(SOCFPGA_SDR_ADDRESS | 0x5000)
 
 struct socfpga_sdr_ctrl {
diff --git a/arch/arm/mach-socfpga/spl.c b/arch/arm/mach-socfpga/spl.c
index fec4c7a..26688ad 100644
--- a/arch/arm/mach-socfpga/spl.c
+++ b/arch/arm/mach-socfpga/spl.c
@@ -30,6 +30,8 @@  static struct nic301_registers *nic301_regs =
 	(struct nic301_registers *)SOCFPGA_L3REGS_ADDRESS;
 static struct socfpga_system_manager *sysmgr_regs =
 	(struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
+static const struct socfpga_reset_manager *reset_manager_base =
+	(void *)SOCFPGA_RSTMGR_ADDRESS;
 
 u32 spl_boot_device(void)
 {
@@ -85,6 +87,9 @@  void board_init_f(ulong dummy)
 #endif
 	unsigned long sdram_size;
 	unsigned long reg;
+	u32 rst_mgr_status;
+
+	rst_mgr_status = readl(&reset_manager_base->status);
 
 	/*
 	 * First C code to run. Clear fake OCRAM ECC first as SBE
@@ -179,6 +184,9 @@  void board_init_f(ulong dummy)
 
 	socfpga_bridges_reset(1);
 
+	if ((rst_mgr_status & RSTMGR_WARMRST_MASK) == 0)
+		sdram_ecc_init();
+
 	/* Configure simple malloc base pointer into RAM. */
 	gd->malloc_base = CONFIG_SYS_TEXT_BASE + (1024 * 1024);
 }
diff --git a/arch/arm/mach-socfpga/wrap_sdram_config.c b/arch/arm/mach-socfpga/wrap_sdram_config.c
index 31cc7de..dfa6423 100644
--- a/arch/arm/mach-socfpga/wrap_sdram_config.c
+++ b/arch/arm/mach-socfpga/wrap_sdram_config.c
@@ -5,8 +5,10 @@ 
  */
 
 #include <common.h>
+#include <dma.h>
 #include <errno.h>
 #include <asm/arch/sdram.h>
+#include <asm/pl330.h>
 
 /* Board-specific header. */
 #include <qts/sdram_config.h>
@@ -310,3 +312,29 @@  const struct socfpga_sdram_misc_config *socfpga_get_sdram_misc_config(void)
 {
 	return &misc_config;
 }
+
+#if (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN == 1)
+/* init the whole SDRAM ECC bit */
+void sdram_ecc_init(void)
+{
+	struct pl330_transfer_struct pl330;
+	u8 pl330_buf[2000];
+
+	pl330.dst_addr = CONFIG_SYS_SDRAM_BASE;
+	pl330.len = sdram_calculate_size();
+	pl330.channel_num = 0;
+	pl330.buf_size = sizeof(pl330_buf);
+	pl330.buf = pl330_buf;
+
+	pl330.transfer_type = DMA_SUPPORTS_DEV_TO_MEM;
+	pl330.reg_base = (void __iomem *)SOCFPGA_DMASECURE_ADDRESS;
+
+	puts("SDRAM: Initializing SDRAM ECC\n");
+
+	arm_pl330_transfer(&pl330);
+
+	printf("SDRAM: ECC initialized successfully\n");
+}
+#else
+void sdram_ecc_init(void) {}
+#endif
diff --git a/configs/socfpga_cyclone5_defconfig b/configs/socfpga_cyclone5_defconfig
index 42b71c3..89c3398 100644
--- a/configs/socfpga_cyclone5_defconfig
+++ b/configs/socfpga_cyclone5_defconfig
@@ -59,3 +59,5 @@  CONFIG_G_DNL_MANUFACTURER="altera"
 CONFIG_G_DNL_VENDOR_NUM=0x0525
 CONFIG_G_DNL_PRODUCT_NUM=0xa4a5
 CONFIG_USE_TINY_PRINTF=y
+CONFIG_SPL_DMA_SUPPORT=y
+CONFIG_PL330_DMA=y