[U-Boot] [PATCH] arm: socfpga: fix issue with warm reset when CSEL is 0
Dalon Westergreen
dwesterg at gmail.com
Tue Feb 14 15:23:53 UTC 2017
When CSEL=0x0 the socfpga bootrom does not touch the clock
configuration for the device. This can lead to a boot failure
on warm resets. To address this, the bootrom is configured to
run a bit of code in the last 4KB of onchip ram on a warm reset.
This code puts the PLLs in bypass, disables the bootrom configuration
to run the code snippet, and issues a warm reset to run the bootrom.
Signed-off-by: Dalon Westergreen <dwesterg at gmail.com>
---
arch/arm/mach-socfpga/Makefile | 2 +-
arch/arm/mach-socfpga/include/mach/clock_manager.h | 22 ++++++-
arch/arm/mach-socfpga/include/mach/reset_manager.h | 4 ++
.../arm/mach-socfpga/include/mach/system_manager.h | 7 ++-
arch/arm/mach-socfpga/misc.c | 29 +++++++++
arch/arm/mach-socfpga/reset_clock_manager.S | 71 ++++++++++++++++++++++
6 files changed, 132 insertions(+), 3 deletions(-)
create mode 100644 arch/arm/mach-socfpga/reset_clock_manager.S
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index 809cd47..6876ccf 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -8,7 +8,7 @@
#
obj-y += misc.o timer.o reset_manager.o system_manager.o clock_manager.o \
- fpga_manager.o board.o
+ fpga_manager.o board.o reset_clock_manager.o
obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o
diff --git a/arch/arm/mach-socfpga/include/mach/clock_manager.h b/arch/arm/mach-socfpga/include/mach/clock_manager.h
index 803c926..dd58c20 100644
--- a/arch/arm/mach-socfpga/include/mach/clock_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/clock_manager.h
@@ -21,7 +21,6 @@ const unsigned int cm_get_f2s_sdr_ref_clk_hz(void);
/* Clock configuration accessors */
const struct cm_config * const cm_get_default_config(void);
-#endif
struct cm_config {
/* main group */
@@ -127,6 +126,19 @@ struct socfpga_clock_manager {
struct socfpga_clock_manager_altera altera;
u32 _pad_0xe8_0x200[70];
};
+#endif
+
+#define CLKMGR_CTRL_ADDRESS 0x0
+#define CLKMGR_BYPASS_ADDRESS 0x4
+#define CLKMGR_INTER_ADDRESS 0x8
+#define CLKMGR_INTREN_ADDRESS 0xc
+#define CLKMGR_DBCTRL_ADDRESS 0x10
+#define CLKMGR_STAT_ADDRESS 0x14
+#define CLKMGR_MAINPLLGRP_MAINQSPICLK_ADDRESS 0x54
+#define CLKMGR_MAINPLLGRP_MAINNANDSDMMCCLK_ADDRESS 0x58
+#define CLKMGR_PERPLLGRP_PERQSPICLK_ADDRESS 0x90
+#define CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_ADDRESS 0x94
+
#define CLKMGR_CTRL_SAFEMODE (1 << 0)
#define CLKMGR_CTRL_SAFEMODE_OFFSET 0
@@ -314,4 +326,12 @@ struct socfpga_clock_manager {
#define CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_OFFSET 9
#define CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_MASK 0x00000e00
+/* 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/mach-socfpga/include/mach/reset_manager.h b/arch/arm/mach-socfpga/include/mach/reset_manager.h
index 2f070f2..58d77fb 100644
--- a/arch/arm/mach-socfpga/include/mach/reset_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/reset_manager.h
@@ -7,6 +7,7 @@
#ifndef _RESET_MANAGER_H_
#define _RESET_MANAGER_H_
+#ifndef __ASSEMBLY__
void reset_cpu(ulong addr);
void reset_deassert_peripherals_handoff(void);
@@ -28,6 +29,8 @@ struct socfpga_reset_manager {
u32 padding2[12];
u32 tstscratch;
};
+#endif
+
#if defined(CONFIG_SOCFPGA_VIRTUAL_TARGET)
#define RSTMGR_CTRL_SWWARMRSTREQ_LSB 2
@@ -40,6 +43,7 @@ struct socfpga_reset_manager {
* and reset ID can be extracted using the subsequent macros
* RSTMGR_RESET() and RSTMGR_BANK().
*/
+#define RSTMGR_CTRL_OFFSET 4
#define RSTMGR_BANK_OFFSET 8
#define RSTMGR_BANK_MASK 0x7
#define RSTMGR_RESET_OFFSET 0
diff --git a/arch/arm/mach-socfpga/include/mach/system_manager.h b/arch/arm/mach-socfpga/include/mach/system_manager.h
index c45edea..d04fa2f 100644
--- a/arch/arm/mach-socfpga/include/mach/system_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/system_manager.h
@@ -13,7 +13,6 @@ void sysmgr_pinmux_init(void);
void sysmgr_config_warmrstcfgio(int enable);
void sysmgr_get_pinmux_table(const u8 **table, unsigned int *table_len);
-#endif
struct socfpga_system_manager {
/* System Manager Module */
@@ -115,6 +114,12 @@ struct socfpga_system_manager {
u32 _pad_0x734;
u32 spim0usefpga; /* 0x738 */
};
+#endif
+
+#define CONFIG_SYSMGR_WARMRAMGRP_ENABLE (SOCFPGA_SYSMGR_ADDRESS + 0xe0)
+
+#define SYSMGR_BOOTINFO_CSEL_MASK 0x18
+#define SYSMGR_BOOTINFO_CSEL_LSB 3
#define SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGPINMUX (1 << 0)
#define SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGIO (1 << 1)
diff --git a/arch/arm/mach-socfpga/misc.c b/arch/arm/mach-socfpga/misc.c
index dd6b53b..4d41420 100644
--- a/arch/arm/mach-socfpga/misc.c
+++ b/arch/arm/mach-socfpga/misc.c
@@ -22,6 +22,9 @@
#include <dt-bindings/reset/altr,rst-mgr.h>
+void reset_clock_manager(void);
+extern unsigned reset_clock_manager_size;
+
DECLARE_GLOBAL_DATA_PTR;
static struct pl310_regs *const pl310 =
@@ -356,6 +359,32 @@ static uint32_t iswgrp_handoff[8];
int arch_early_init_r(void)
{
int i;
+ unsigned csel, ramboot_addr;
+
+ /* Check the CSEL value */
+ csel = (readl(&sysmgr_regs->bootinfo) & SYSMGR_BOOTINFO_CSEL_MASK) >>
+ SYSMGR_BOOTINFO_CSEL_LSB;
+
+ /*
+ * For CSEL = 0 the bootrom does not configure the clocks which can
+ * result in a boot failure on warm resets. To remedy this a small
+ * bit of code is placed at the end of the onchip ram and run on
+ * a warm reset. It puts the PLLs in bypass and issues another warm
+ * reset to get back to the bootrom.
+ */
+ if(!csel) {
+ /* Put the code snippet in the last 4KB of the onchip ram */
+ ramboot_addr = CONFIG_SYS_INIT_RAM_ADDR +
+ CONFIG_SYS_INIT_RAM_SIZE - 0x1000;
+
+ /* Copy the code to the onchip ramlocation */
+ memcpy((void *)ramboot_addr, reset_clock_manager,
+ reset_clock_manager_size);
+
+ /* Set the bootrom to run the code snippet on reset */
+ writel(ramboot_addr,
+ &sysmgr_regs->romcodegrp_warmramgrp_execution);
+ }
/*
* Write magic value into magic register to unlock support for
diff --git a/arch/arm/mach-socfpga/reset_clock_manager.S b/arch/arm/mach-socfpga/reset_clock_manager.S
new file mode 100644
index 0000000..1818b2d
--- /dev/null
+++ b/arch/arm/mach-socfpga/reset_clock_manager.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017, Intel Corporation
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+#include <asm/arch/system_manager.h>
+#include <asm/arch/reset_manager.h>
+#include <asm/arch/clock_manager.h>
+
+/*
+ */
+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
+ ldr r4, [r2]
+ orr r4, r3, r4
+ str r4, [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
+
--
2.7.4
More information about the U-Boot
mailing list