summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChin Liang See <clsee@altera.com>2014-06-03 10:20:35 +0800
committerChin Liang See <clsee@altera.com>2014-06-03 10:36:21 +0800
commit08ad1a1f6221b0657d2ca97f95b04f676a829619 (patch)
tree439b1571838656bbf0bac19f1c95c3f8e3e365fa
parent1c0168bcc067cd9941becef3671884361abd9922 (diff)
downloadu-boot-socfpga-08ad1a1f6221b0657d2ca97f95b04f676a829619.tar.gz
FogBugz #208554: RAM boot to reset Clock Manager during CSEL 0rel_socfpga_v2013.01.01_14.06.01
To enable RAM boot when CSEL = 0. The RAM boot code will put Main PLL and Peripheral to bypass mode. It will set the QSPI and NANDSDMMC clock dividers for both PLLs to default value. Later, the code will disable the RAM boot before triggering warm reset. The RAM boot code is located at the last 4kB of on-chip RAM. The purpose of this RAM boot is to overcome boot up hang issue which due to faulty PLL. Signed-off-by: Chin Liang See <clsee@altera.com> --- Changes for v2 - Auto calculate the function size when copying the function
-rw-r--r--arch/arm/cpu/armv7/socfpga/lowlevel_init.S60
-rw-r--r--arch/arm/cpu/armv7/socfpga/misc.c36
-rw-r--r--arch/arm/cpu/armv7/socfpga/spl.c3
-rw-r--r--arch/arm/include/asm/arch-socfpga/clock_manager.h13
-rw-r--r--arch/arm/include/asm/arch-socfpga/reset_manager.h8
-rw-r--r--arch/arm/include/asm/arch-socfpga/system_manager.h12
6 files changed, 130 insertions, 2 deletions
diff --git a/arch/arm/cpu/armv7/socfpga/lowlevel_init.S b/arch/arm/cpu/armv7/socfpga/lowlevel_init.S
index 77dd864d31..1f2899215a 100644
--- a/arch/arm/cpu/armv7/socfpga/lowlevel_init.S
+++ b/arch/arm/cpu/armv7/socfpga/lowlevel_init.S
@@ -22,6 +22,8 @@
#include <asm/arch/sdram.h>
#include <asm/system.h>
#include <asm-offsets.h>
+#include <asm/arch/reset_manager.h>
+#include <asm/arch/clock_manager.h>
#define PRELOADER_DEBUG_MEMMORY_MAGIC 0x444d
#define PRELOADER_DEBUG_MEMMORY_VERSION 0x1
@@ -208,3 +210,61 @@ write_end:
POP {r4-r11, pc}
ENDPROC(fpgamgr_axi_write)
+/*
+ * Relocate the sdram_applycfg_ocram function to OCRAM and call it
+ */
+ENTRY(reset_clock_manager)
+ /* Put Main PLL and Peripheral PLL in bypass */
+ ldr r0, SOCFPGA_CLKMGR
+ mov r1, #CLKMGR_BYPASS_ADDRESS
+ mov r2, #CLKMGR_BYPASS_MAIN_PER_PLL_MASK
+ add r3, r0, r1
+ ldr r4, [r3]
+ orr r5, r4, r2
+ str r5, [r3]
+ dsb
+ isb
+ mov r1, #CLKMGR_MAINPLLGRP_MAINQSPICLK_ADDRESS
+ mov r2, #CLKMGR_MAINQSPICLK_RESET_VALUE
+ add r3, r0, r1
+ str r2, [r3]
+ mov r1, #CLKMGR_MAINPLLGRP_MAINNANDSDMMCCLK_ADDRESS
+ mov r2, #CLKMGR_MAINNANDSDMMCCLK_RESET_VALUE
+ add r3, r0, r1
+ str r2, [r3]
+ mov r1, #CLKMGR_PERPLLGRP_PERQSPICLK_ADDRESS
+ mov r2, #CLKMGR_PERQSPICLK_RESET_VALUE
+ add r3, r0, r1
+ str r2, [r3]
+ mov r1, #CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_ADDRESS
+ mov r2, #CLKMGR_PERNANDSDMMCCLK_RESET_VALUE
+ add r3, r0, r1
+ str r2, [r3]
+
+ /* Disable the RAM boot */
+ ldr r0, SOCFPGA_RSTMGR
+ ldr r1, SYSMGR_WARMRAMGRP_ENABLE
+ mov r2, #0
+ str r2, [r1]
+
+ /* Trigger warm reset to continue boot normally */
+ mov r1, #RSTMGR_CTRL_OFFSET
+ add r2, r0, r1
+ mov r3, #1
+ mov r3, r3, LSL #RSTMGR_CTRL_SWWARMRSTREQ_LSB
+ str r3, [r2]
+
+reset_clock_manager_loop:
+ dsb
+ isb
+ b reset_clock_manager_loop
+ENDPROC(reset_clock_manager)
+
+SOCFPGA_CLKMGR: .word SOCFPGA_CLKMGR_ADDRESS
+SOCFPGA_RSTMGR: .word SOCFPGA_RSTMGR_ADDRESS
+SYSMGR_WARMRAMGRP_ENABLE: .word CONFIG_SYSMGR_WARMRAMGRP_ENABLE
+
+.globl reset_clock_manager_size
+reset_clock_manager_size:
+ .word . - reset_clock_manager
+
diff --git a/arch/arm/cpu/armv7/socfpga/misc.c b/arch/arm/cpu/armv7/socfpga/misc.c
index 27b3ce46e7..3ba9c74901 100644
--- a/arch/arm/cpu/armv7/socfpga/misc.c
+++ b/arch/arm/cpu/armv7/socfpga/misc.c
@@ -29,7 +29,7 @@
#include <netdev.h>
#include <phy.h>
#endif
-
+#include <spl.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -149,3 +149,37 @@ void enable_caches(void)
}
#endif
+#ifdef CONFIG_SPL_BUILD
+/*
+ * Setup RAM boot to ensure the clock are reset under CSEL = 0
+ */
+void ram_boot_setup(void)
+{
+ unsigned csel, ramboot_addr;
+
+ csel = (readl(SYSMGR_BOOTINFO) & SYSMGR_BOOTINFO_CSEL_MASK) >>
+ SYSMGR_BOOTINFO_CSEL_LSB;
+ if (!csel) {
+ /*
+ * Copy the ramboot program at end of Preloader or offset 60kB
+ * which is bigger. With that, customer can modify any content
+ * within first 60kB of OCRAM at any boot stage
+ */
+ ramboot_addr = CONFIG_SYS_INIT_RAM_ADDR + 0xf000;
+ if ((unsigned)&__ecc_padding_end > ramboot_addr)
+ ramboot_addr = (unsigned)&__ecc_padding_end;
+
+ memcpy((void *)ramboot_addr, reset_clock_manager,
+ reset_clock_manager_size);
+
+ /* tell BootROM where the RAM boot code start */
+ writel(ramboot_addr &
+ CONFIG_SYSMGR_WARMRAMGRP_EXECUTION_OFFSET_MASK,
+ CONFIG_SYSMGR_WARMRAMGRP_EXECUTION);
+
+ /* Enable the RAM boot */
+ writel(CONFIG_SYSMGR_WARMRAMGRP_ENABLE_MAGIC,
+ CONFIG_SYSMGR_WARMRAMGRP_ENABLE);
+ }
+}
+#endif
diff --git a/arch/arm/cpu/armv7/socfpga/spl.c b/arch/arm/cpu/armv7/socfpga/spl.c
index 96951eee2f..ec16b50941 100644
--- a/arch/arm/cpu/armv7/socfpga/spl.c
+++ b/arch/arm/cpu/armv7/socfpga/spl.c
@@ -454,6 +454,9 @@ void spl_board_init(void)
WATCHDOG_RESET();
#endif
DEBUG_MEMORY
+ debug("RAM boot setup if CSEL 0\n");
+ ram_boot_setup();
+
debug("Reconfigure Clock Manager\n");
/* reconfigure the PLLs */
cm_basic_init(&cm_default_cfg);
diff --git a/arch/arm/include/asm/arch-socfpga/clock_manager.h b/arch/arm/include/asm/arch-socfpga/clock_manager.h
index 3ff2b7b23a..49a40ad23b 100644
--- a/arch/arm/include/asm/arch-socfpga/clock_manager.h
+++ b/arch/arm/include/asm/arch-socfpga/clock_manager.h
@@ -65,6 +65,8 @@ unsigned long cm_get_qspi_controller_clk_hz(void);
void cm_print_clock_quick_summary(void);
void cm_derive_clocks_for_drivers(void);
+#endif /* __ASSEMBLY__ */
+
#define CLKMGR_CTRL_ADDRESS 0x0
#define CLKMGR_BYPASS_ADDRESS 0x4
#define CLKMGR_INTER_ADDRESS 0x8
@@ -252,11 +254,20 @@ void cm_derive_clocks_for_drivers(void);
#define CLKMGR_QSPI_CLK_SRC_MAIN 0x1
#define CLKMGR_QSPI_CLK_SRC_PER 0x2
+#ifndef __ASSEMBLY__
/* global variable which consume by drivers */
extern unsigned long cm_l4_sp_clock;
extern unsigned long cm_sdmmc_clock;
extern unsigned long cm_qspi_clock;
-
#endif /* __ASSEMBLY__ */
+/* Bypass Main and Per PLL, bypass source per input mux */
+#define CLKMGR_BYPASS_MAIN_PER_PLL_MASK 0x19
+
+#define CLKMGR_MAINQSPICLK_RESET_VALUE 0x3
+#define CLKMGR_MAINNANDSDMMCCLK_RESET_VALUE 0x3
+#define CLKMGR_PERQSPICLK_RESET_VALUE 0x1
+#define CLKMGR_PERNANDSDMMCCLK_RESET_VALUE 0x1
+
+
#endif /* _CLOCK_MANAGER_H_ */
diff --git a/arch/arm/include/asm/arch-socfpga/reset_manager.h b/arch/arm/include/asm/arch-socfpga/reset_manager.h
index 87dbffcca9..6d5c9fe225 100644
--- a/arch/arm/include/asm/arch-socfpga/reset_manager.h
+++ b/arch/arm/include/asm/arch-socfpga/reset_manager.h
@@ -18,6 +18,7 @@
#ifndef _RESET_MANAGER_H_
#define _RESET_MANAGER_H_
+#ifndef __ASSEMBLY__
void watchdog_disable(void);
int is_wdt_in_reset(void);
void reset_cpu(ulong addr);
@@ -35,6 +36,8 @@ void reset_deassert_bridges_handoff(void);
#endif
void emac0_reset_enable(uint state);
void emac1_reset_enable(uint state);
+void reset_clock_manager(void);
+extern unsigned reset_clock_manager_size;
#if defined(CONFIG_SOCFPGA_VIRTUAL_TARGET)
struct socfpga_reset_manager {
@@ -57,6 +60,7 @@ struct socfpga_reset_manager {
u32 brg_mod_reset;
};
#endif
+#endif /* __ASSEMBLY__ */
#if defined(CONFIG_SOCFPGA_VIRTUAL_TARGET)
#define RSTMGR_CTRL_SWWARMRSTREQ_LSB 2
@@ -74,6 +78,10 @@ struct socfpga_reset_manager {
#define RSTMGR_BRGMODRST_LWHPS2FPGA_MASK 0x00000002
#define RSTMGR_BRGMODRST_FPGA2HPS_MASK 0x00000004
+#define RSTMGR_CTRL_OFFSET 0x00000004
+#define RSTMGR_MISCMODRST_OFFSET 0x00000020
+#define RSTMGR_MISCMODRST_CLKMGRCOLD_MASK 0x00000400
+
/* Warm Reset mask */
#if defined(CONFIG_SOCFPGA_VIRTUAL_TARGET)
#define RESET_MANAGER_REGS_STATUS_REG_L4_WD1_RST_FLD_MASK 0x00008000
diff --git a/arch/arm/include/asm/arch-socfpga/system_manager.h b/arch/arm/include/asm/arch-socfpga/system_manager.h
index 75482c0e4f..801935f184 100644
--- a/arch/arm/include/asm/arch-socfpga/system_manager.h
+++ b/arch/arm/include/asm/arch-socfpga/system_manager.h
@@ -23,6 +23,7 @@
/* declaration for system_manager.c */
void sysmgr_pinmux_init(void);
void sysmgr_sdmmc_pweren_mux_check(void);
+void ram_boot_setup(void);
/* declaration for handoff table type */
typedef unsigned long sys_mgr_pinmux_entry_t;
@@ -97,4 +98,15 @@ extern unsigned long sys_mgr_init_table[CONFIG_HPS_PINMUX_NUM];
#define SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB 2
#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003
+/* CSEL */
+#define SYSMGR_BOOTINFO (SOCFPGA_SYSMGR_ADDRESS + 0x14)
+#define SYSMGR_BOOTINFO_CSEL_LSB 3
+#define SYSMGR_BOOTINFO_CSEL_MASK 0x18
+
+/* Warm RAM group */
+#define CONFIG_SYSMGR_WARMRAMGRP_ENABLE (SOCFPGA_SYSMGR_ADDRESS + 0xe0)
+#define CONFIG_SYSMGR_WARMRAMGRP_EXECUTION (SOCFPGA_SYSMGR_ADDRESS + 0xec)
+#define CONFIG_SYSMGR_WARMRAMGRP_ENABLE_MAGIC 0xae9efebc
+#define CONFIG_SYSMGR_WARMRAMGRP_EXECUTION_OFFSET_MASK 0xffff
+
#endif /* _SYSTEM_MANAGER_H_ */