On 02/14/2017 07:28 PM, Dalon Westergreen wrote: > 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 <dwest...@gmail.com> > > -- > Changes in V2: > - Fix checkpatch issues predominently due to whitespace issues > --- > arch/arm/mach-socfpga/Makefile | 2 +- > arch/arm/mach-socfpga/include/mach/clock_manager.h | 26 +++++++- > 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 | 27 ++++++++ > arch/arm/mach-socfpga/reset_clock_manager.S | 71 > ++++++++++++++++++++++ > 6 files changed, 134 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..78f63a4 100644 > --- a/arch/arm/mach-socfpga/include/mach/clock_manager.h > +++ b/arch/arm/mach-socfpga/include/mach/clock_manager.h > @@ -19,9 +19,12 @@ const unsigned int cm_get_osc_clk_hz(const int osc); > const unsigned int cm_get_f2s_per_ref_clk_hz(void); > const unsigned int cm_get_f2s_sdr_ref_clk_hz(void); > > +/* Onchip RAM functions for CSEL=0 */ > +void reset_clock_manager(void); > +extern unsigned reset_clock_manager_size; > + > /* Clock configuration accessors */ > const struct cm_config * const cm_get_default_config(void); > -#endif > > struct cm_config { > /* main group */ > @@ -127,6 +130,19 @@ struct socfpga_clock_manager { > struct socfpga_clock_manager_altera altera; > u32 _pad_0xe8_0x200[70]; > }; > +#endif > + > +#define CLKMGR_CTRL_ADDRESS 0x0
Is this the same as struct socfpga_clock_manager {} ? Why ? > +#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 +330,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..b89f269 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..57e3334 100644 > --- a/arch/arm/mach-socfpga/misc.c > +++ b/arch/arm/mach-socfpga/misc.c > @@ -16,6 +16,7 @@ > #include <asm/arch/reset_manager.h> > #include <asm/arch/scan_manager.h> > #include <asm/arch/system_manager.h> > +#include <asm/arch/clock_manager.h> > #include <asm/arch/nic301.h> > #include <asm/arch/scu.h> > #include <asm/pl310.h> > @@ -356,6 +357,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); So uh, why don't you put this code into SPL and execute it from there ? This is b/s ... > + /* 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) This is just a few writel() calls in SPL , right ? Put it there... > + /* 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 > + > -- Best regards, Marek Vasut _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot