
From: Tien Fong Chee tien.fong.chee@intel.com
Add FPGA driver support for Arria 10.
Signed-off-by: Tien Fong Chee tien.fong.chee@intel.com Cc: Marek Vasut marex@denx.de Cc: Dinh Nguyen dinguyen@kernel.org Cc: Ching Liang See chin.liang.see@intel.com Cc: Ley Foon ley.foon.tan@intel.com Cc: Westergreen Dalon dalon.westergreen@intel.com --- arch/arm/mach-socfpga/Makefile | 1 + arch/arm/mach-socfpga/include/mach/fpga_manager.h | 2 + .../include/mach/fpga_manager_arria10.h | 120 +++++ drivers/Makefile | 1 + drivers/fpga/Makefile | 1 + drivers/fpga/socfpga_arria10.c | 565 ++++++++++++++++++++ 6 files changed, 690 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h create mode 100644 drivers/fpga/socfpga_arria10.c
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 901bf91..d1ca3ee 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -18,6 +18,7 @@ obj-y += clock_manager_arria10.o obj-y += misc_arria10.o obj-y += pinmux_arria10.o obj-y += reset_manager_arria10.o +obj-y += lowlevel_init.o endif
ifdef CONFIG_TARGET_SOCFPGA_GEN5 diff --git a/arch/arm/mach-socfpga/include/mach/fpga_manager.h b/arch/arm/mach-socfpga/include/mach/fpga_manager.h index 76a9289..64e8344 100644 --- a/arch/arm/mach-socfpga/include/mach/fpga_manager.h +++ b/arch/arm/mach-socfpga/include/mach/fpga_manager.h @@ -12,6 +12,8 @@
#if defined(CONFIG_TARGET_SOCFPGA_GEN5) #include <asm/arch/fpga_manager_gen5.h> +#elif defined(CONFIG_TARGET_SOCFPGA_ARRIA10) +#include <asm/arch/fpga_manager_arria10.h> #endif
/* FPGA CD Ratio Value */ diff --git a/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h b/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h new file mode 100644 index 0000000..a273be7 --- /dev/null +++ b/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2017 Intel Corporation <www.intel.com> + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FPGA_MANAGER_ARRIA10_H_ +#define _FPGA_MANAGER_ARRIA10_H_ + +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR_SET_MSK 0x00000001 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE_SET_MSK 0x00000002 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK 0x00000004 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_INITDONE_OE_SET_MSK 0x00000008 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK 0x00000010 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_OE_SET_MSK 0x00000020 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK 0x00000040 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_OE_SET_MSK 0x00000080 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_CVP_CONF_DONE_SET_MSK 0x00000100 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_PR_READY_SET_MSK 0x00000200 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_PR_DONE_SET_MSK 0x00000400 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR_SET_MSK 0x00000800 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN_SET_MSK 0x00001000 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_NCEO_OE_SET_MSK 0x00002000 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL0_SET_MSK 0x00010000 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL1_SET_MSK 0x00020000 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL2_SET_MSK 0x00040000 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SET_MSD (\ + ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL0_SET_MSK |\ + ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL1_SET_MSK |\ + ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL2_SET_MSK) +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_IMGCFG_FIFOEMPTY_SET_MSK 0x01000000 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_IMGCFG_FIFOFULL_SET_MSK 0x02000000 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_JTAGM_SET_MSK 0x10000000 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_EMR_SET_MSK 0x20000000 +#define ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL0_LSB 16 + +#define ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG_SET_MSK 0x00000001 +#define ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS_SET_MSK 0x00000002 +#define ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE_SET_MSK 0x00000004 +#define ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK 0x00000100 +#define ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NSTATUS_OE_SET_MSK 0x00010000 +#define ALT_FPGAMGR_IMGCFG_CTL_00_S2F_CONDONE_OE_SET_MSK 0x01000000 + +#define ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG_SET_MSK 0x00000001 +#define ALT_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST_SET_MSK 0x00010000 +#define ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK 0x01000000 + +#define ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK 0x00000001 +#define ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK 0x00000100 +#define ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK 0x00030000 +#define ALT_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SET_MSK 0x01000000 +#define ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_LSB 16 + +/* Timeout counter */ +#define FPGA_TIMEOUT_CNT 0x1000000 +#define FPGA_TIMEOUT_MSEC 1000 /* timeout in ms */ + +#ifndef __ASSEMBLY__ + +struct socfpga_fpga_manager { + uint32_t _pad_0x0_0x7[2]; + uint32_t dclkcnt; + uint32_t dclkstat; + uint32_t gpo; + uint32_t gpi; + uint32_t misci; + uint32_t _pad_0x1c_0x2f[5]; + uint32_t emr_data0; + uint32_t emr_data1; + uint32_t emr_data2; + uint32_t emr_data3; + uint32_t emr_data4; + uint32_t emr_data5; + uint32_t emr_valid; + uint32_t emr_en; + uint32_t jtag_config; + uint32_t jtag_status; + uint32_t jtag_kick; + uint32_t _pad_0x5c_0x5f; + uint32_t jtag_data_w; + uint32_t jtag_data_r; + uint32_t _pad_0x68_0x6f[2]; + uint32_t imgcfg_ctrl_00; + uint32_t imgcfg_ctrl_01; + uint32_t imgcfg_ctrl_02; + uint32_t _pad_0x7c_0x7f; + uint32_t imgcfg_stat; + uint32_t intr_masked_status; + uint32_t intr_mask; + uint32_t intr_polarity; + uint32_t dma_config; + uint32_t imgcfg_fifo_status; +}; + +/* Functions */ +int is_fpgamgr_fpga_ready(void); +int poll_fpgamgr_fpga_ready(void); +int fpgamgr_program_init(u32 * rbf_data, u32 rbf_size); +int fpgamgr_program_fini(void); +void fpgamgr_program_write(const unsigned long *rbf_data, + unsigned long rbf_size); +void fpgamgr_program_sync(void); +int fpgamgr_program_poll_cd(void); +int fpgamgr_program_poll_initphase(void); +int is_fpgamgr_user_mode(void); +int fpgamgr_program_poll_usermode(void); +int fpgamgr_program_poll_usermode(void); +int fpgamgr_program_fpga(const unsigned long *rbf_data, + unsigned long rbf_size); +void fpgamgr_axi_write(const unsigned long *rbf_data, + const unsigned long fpgamgr_data_addr, unsigned long rbf_size); +int fpgamgr_wait_early_user_mode(void); +int is_fpgamgr_early_user_mode(void); +int fpgamgr_reset(void); +int wait_for_nconfig_pin_and_nstatus_pin(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* _FPGA_MANAGER_ARRIA10_H_ */ diff --git a/drivers/Makefile b/drivers/Makefile index 6e7a2c3..375ee78 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_$(SPL_)RAM) += ram/
ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_FPGA) += fpga/ obj-$(CONFIG_SPL_CPU_SUPPORT) += cpu/ obj-$(CONFIG_SPL_CRYPTO_SUPPORT) += crypto/ obj-$(CONFIG_SPL_I2C_SUPPORT) += i2c/ diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index c70ee40..bb063e0 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -22,5 +22,6 @@ obj-$(CONFIG_FPGA_STRATIX_V) += stratixv.o ifdef CONFIG_FPGA_SOCFPGA obj-y += socfpga.o obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += socfpga_gen5.o +obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += socfpga_arria10.o endif endif diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c new file mode 100644 index 0000000..e6c767b --- /dev/null +++ b/drivers/fpga/socfpga_arria10.c @@ -0,0 +1,565 @@ +/* + * Copyright (C) 2017 Intel Corporation <www.intel.com> + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/fpga_manager.h> +#include <asm/arch/reset_manager.h> +#include <asm/arch/system_manager.h> +#include <asm/arch/sdram.h> +#include <asm/arch/misc.h> +#include <altera.h> +#include <errno.h> +#include <watchdog.h> + +#define CFGWDTH_32 1 + +DECLARE_GLOBAL_DATA_PTR; + +static const struct socfpga_fpga_manager *fpga_manager_base = + (void *)SOCFPGA_FPGAMGRREGS_ADDRESS; + +static const struct socfpga_system_manager *system_manager_base = + (void *)SOCFPGA_SYSMGR_ADDRESS; + +static void fpgamgr_set_cd_ratio(unsigned long ratio); + +static uint32_t fpgamgr_get_msel(void) +{ + uint32_t reg; + + reg = readl(&fpga_manager_base->imgcfg_stat); + reg = ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SET_MSD) >> + ALT_FPGAMGR_IMGCFG_STAT_F2S_MSEL0_LSB); + + return reg; +} + +static void fpgamgr_set_cfgwdth(int width) +{ + if (width) + setbits_le32(&fpga_manager_base->imgcfg_ctrl_02, + ALT_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SET_MSK); + else + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02, + ALT_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SET_MSK); +} + +/* Check whether FPGA Init_Done signal is high */ +int is_fpgamgr_initdone_high(void) +{ + return (readl(&fpga_manager_base->imgcfg_stat) & + ALT_FPGAMGR_IMGCFG_STAT_F2S_INITDONE_OE_SET_MSK) != 0; +} + +int is_fpgamgr_user_mode(void) +{ + return (readl(&fpga_manager_base->imgcfg_stat) & + ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK) != 0; +} + +static int wait_for_user_mode(void) +{ + unsigned start = get_timer(0); + + while (!(is_fpgamgr_user_mode())) { + if (get_timer(start) > FPGA_TIMEOUT_MSEC) + return -ETIMEDOUT; + } + + return 0; +} + +int is_fpgamgr_early_user_mode(void) +{ + return (readl(&fpga_manager_base->imgcfg_stat) & + ALT_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE_SET_MSK) != 0; +} + +int fpgamgr_wait_early_user_mode(void) +{ + u32 sync_data = 0xffffffff; + u32 i = 0; + unsigned start = get_timer(0); + unsigned long cd_ratio; + + /* Getting existing CDRATIO */ + cd_ratio = (readl(&fpga_manager_base->imgcfg_ctrl_02) & + ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK) >> + ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_LSB; + + /* Using CDRATIO_X1 for better compatibility */ + fpgamgr_set_cd_ratio(CDRATIO_x1); + + while (!(is_fpgamgr_early_user_mode())) { + if (get_timer(start) > FPGA_TIMEOUT_MSEC) + return -ETIMEDOUT; + fpgamgr_program_write((const long unsigned int *)&sync_data, + sizeof(sync_data)); + udelay(1000); + i++; + } + + debug("Additional %i sync word needed\n", i); + + /* restoring original CDRATIO */ + fpgamgr_set_cd_ratio(cd_ratio); + + return 0; +} + +/* send sync words to clock data through the control block */ +void fpgamgr_program_sync(void) +{ + u32 sync_data = 0xffffffff; + int i; + for (i = 0; i < 10; i++) { + fpgamgr_program_write((const long unsigned int *)&sync_data, + sizeof(sync_data)); + } +} + +static int wait_for_imgcfg_stat(unsigned long mask) +{ + unsigned long reg, i; + + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + reg = readl(&fpga_manager_base->imgcfg_stat); + if ((reg & mask) == mask) + break; + } + + return i; +} + +/* Read f2s_nconfig_pin and f2s_nstatus_pin; loop until de-asserted */ +int wait_for_nconfig_pin_and_nstatus_pin(void) +{ + return wait_for_imgcfg_stat( + ALT_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN_SET_MSK | + ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK); +} + +static int wait_for_f2s_nstatus_pin(unsigned long value) +{ + unsigned long reg, i, desired; + unsigned long mask = ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK; + + if (value == 0) + desired = 0; + else + desired = mask; + + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + reg = readl(&fpga_manager_base->imgcfg_stat); + if ((reg & mask) == desired) + break; + } + + return i; +} + +/* Check whether FPGA is ready to be accessed */ +int is_fpgamgr_fpga_ready(void) +{ + /* check for init done signal */ + if (is_fpgamgr_initdone_high() == 0) + return 0; + + /* check again to avoid false glitches */ + if (is_fpgamgr_initdone_high() == 0) + return 0; + + if (!is_fpgamgr_user_mode()) + return 0; + + return 1; +} + +/* Poll until FPGA is ready to be accessed or timeout occurred */ +int poll_fpgamgr_fpga_ready(void) +{ + unsigned long i; + + /* If FPGA is blank, wait till WD invoke warm reset */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + /* check for init done signal */ + if (is_fpgamgr_initdone_high() == 0) + continue; + + /* check again to avoid false glitches */ + if (is_fpgamgr_initdone_high() == 0) + continue; + + return 1; + } + + return 0; +} + +/* set CD ratio */ +static void fpgamgr_set_cd_ratio(unsigned long ratio) +{ + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02, + ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK); + + setbits_le32(&fpga_manager_base->imgcfg_ctrl_02, + (ratio << ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_LSB) & + ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SET_MSK); +} + +/* get the MSEL value, verify we are set for FPP configuration mode */ +static int fpgamgr_verify_msel(void) +{ + unsigned int msel = fpgamgr_get_msel(); + + if ((msel != 0) && (msel != 1)) { + printf("Fail: read msel=%d\n", msel); + return -1; + } + + return 0; +} + +/* + * Write cdratio and cdwidth based on whether the bitstream is compressed + * and/or encoded + */ +static int fpgamgr_set_cdratio_cdwidth(unsigned int cfg_width, u32 *rbf_data, + u32 rbf_size) +{ + unsigned int cd_ratio; + bool encrypt, compress; + + if (rbf_size < 230) + return -1; + + encrypt = (rbf_data[69] >> 2) & 3; + encrypt = encrypt != 0; + + compress = (rbf_data[229] >> 1) & 1; + compress = !compress; + +#if 0 + printf("header word %d = %08x\n", 69, rbf_data[69]); + printf("header word %d = %08x\n", 229, rbf_data[229]); + printf("read from rbf header: encrypt=%d compress=%d\n", encrypt, compress); +#endif + + /* + * from the register map description of cdratio in imgcfg_ctrl_02: + * Normal Configuration : 32bit Passive Parallel + * Partial Reconfiguration : 16bit Passive Parallel + */ + + /* + * cd ratio is dependent on cfg width and whether the bitstream + * is encrypted and/or compressed. + * + * | width | encr. | compr. | cd ratio | + * | 16 | 0 | 0 | 1 | + * | 16 | 0 | 1 | 4 | + * | 16 | 1 | 0 | 2 | + * | 16 | 1 | 1 | 4 | + * | 32 | 0 | 0 | 1 | + * | 32 | 0 | 1 | 8 | + * | 32 | 1 | 0 | 4 | + * | 32 | 1 | 1 | 8 | + */ + if (!compress && !encrypt) { + cd_ratio = CDRATIO_x1; + } else { + if (compress) + cd_ratio = CDRATIO_x4; + else + cd_ratio = CDRATIO_x2; + + /* if 32 bit, double the cd ratio (so register + field setting is incremented) */ + if (cfg_width == CFGWDTH_32) + cd_ratio += 1; + } + + fpgamgr_set_cfgwdth(cfg_width); + fpgamgr_set_cd_ratio(cd_ratio); + + return 0; +} + +int fpgamgr_reset(void) +{ + unsigned long reg; + + /* S2F_NCONFIG = 0 */ + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_00, + ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK); + + /* Wait for f2s_nstatus == 0 */ + if (wait_for_f2s_nstatus_pin(0) == FPGA_TIMEOUT_CNT) + return -5; + + /* S2F_NCONFIG = 1 */ + setbits_le32(&fpga_manager_base->imgcfg_ctrl_00, + ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK); + + /* Wait for f2s_nstatus == 1 */ + if (wait_for_f2s_nstatus_pin(1) == FPGA_TIMEOUT_CNT) + return -6; + + /* read and confirm f2s_condone_pin = 0 and f2s_condone_oe = 1 */ + reg = readl(&fpga_manager_base->imgcfg_stat); + if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) != 0) + return -7; + + if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_OE_SET_MSK) == 0) + return -8; + + return 0; +} + +/* Start the FPGA programming by initialize the FPGA Manager */ +int fpgamgr_program_init(u32 * rbf_data, u32 rbf_size) +{ + int ret; + + /* Step 1 */ + if (fpgamgr_verify_msel()) + return -1; + + /* Step 2 */ + if (fpgamgr_set_cdratio_cdwidth(CFGWDTH_32, rbf_data, rbf_size)) + return -2; + + /* + * Step 3: + * Make sure no other external devices are trying to interfere with + * programming: + */ + if (wait_for_nconfig_pin_and_nstatus_pin() == FPGA_TIMEOUT_CNT) + return -3; + + /* + * Step 4: + * Deassert the signal drives from HPS + * + * S2F_NCE = 1 + * S2F_PR_REQUEST = 0 + * EN_CFG_CTRL = 0 + * EN_CFG_DATA = 0 + * S2F_NCONFIG = 1 + * S2F_NSTATUS_OE = 0 + * S2F_CONDONE_OE = 0 + */ + setbits_le32(&fpga_manager_base->imgcfg_ctrl_01, + ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK); + + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_01, + ALT_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST_SET_MSK); + + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02, + ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK | + ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK); + + setbits_le32(&fpga_manager_base->imgcfg_ctrl_00, + ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG_SET_MSK); + + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_00, + ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NSTATUS_OE_SET_MSK | + ALT_FPGAMGR_IMGCFG_CTL_00_S2F_CONDONE_OE_SET_MSK); + + /* + * Step 5: + * Enable overrides + * S2F_NENABLE_CONFIG = 0 + * S2F_NENABLE_NCONFIG = 0 + */ + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_01, + ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG_SET_MSK); + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_00, + ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG_SET_MSK); + + /* + * Disable driving signals that HPS doesn't need to drive. + * S2F_NENABLE_NSTATUS = 1 + * S2F_NENABLE_CONDONE = 1 + */ + setbits_le32(&fpga_manager_base->imgcfg_ctrl_00, + ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS_SET_MSK | + ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE_SET_MSK); + + /* + * Step 6: + * Drive chip select S2F_NCE = 0 + */ + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_01, + ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK); + + /* Step 7 */ + if (wait_for_nconfig_pin_and_nstatus_pin() == FPGA_TIMEOUT_CNT) + return -4; + + /* Step 8 */ + ret = fpgamgr_reset(); + if (ret) + return ret; + + /* + * Step 9: + * EN_CFG_CTRL and EN_CFG_DATA = 1 + */ + setbits_le32(&fpga_manager_base->imgcfg_ctrl_02, + ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK | + ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK); + + return 0; +} + +int fpgamgr_program_fini(void) +{ + /* Ensure the FPGA entering config done */ + int status = fpgamgr_program_poll_cd(); + if (status) { + printf("FPGA: Poll CD failed with error code %d\n", status); + return -3; + } + WATCHDOG_RESET(); + + /* Ensure the FPGA entering init phase */ + status = fpgamgr_program_poll_initphase(); + if (status) { + printf("FPGA: Poll initphase failed with error code %d\n", + status); + return -4; + } + WATCHDOG_RESET(); + + /* Ensure the FPGA entering user mode */ + status = fpgamgr_program_poll_usermode(); + if (status) { + printf("FPGA: Poll usermode failed with error code %d\n", + status); + return -5; + } + + printf("Full Configuration Succeeded.\n"); + + return 0; +} + +/* Write the RBF data to FPGA Manager */ +void fpgamgr_program_write(const unsigned long *rbf_data, + unsigned long rbf_size) +{ + /* Write sof/pof data to img_data_w */ + fpgamgr_axi_write(rbf_data, SOCFPGA_FPGAMGRDATA_ADDRESS, rbf_size); +} + +/* Ensure the FPGA entering config done */ +int fpgamgr_program_poll_cd(void) +{ + unsigned long reg, i; + + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + reg = readl(&fpga_manager_base->imgcfg_stat); + if (reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) + return 0; + + if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK) == 0) { + printf("nstatus == 0 while waiting for condone\n"); + return -9; + } + } + + if (i == FPGA_TIMEOUT_CNT) + return -10; + + return 0; +} + +/* Ensure the FPGA entering init phase */ +int fpgamgr_program_poll_initphase(void) +{ + return 0; +} + +/* Ensure the FPGA entering user mode */ +int fpgamgr_program_poll_usermode(void) +{ + unsigned long reg; + int ret = 0; + + if (fpgamgr_dclkcnt_set(0xf) == FPGA_TIMEOUT_CNT) + return -11; + + ret = wait_for_user_mode(); + + if (ret < 0) { + printf("%s: Failed to enter user mode with ", __func__); + printf("error code %d\n", ret); + return ret; + } + + /* + * Step 14: + * Stop DATA path and Dclk + * EN_CFG_CTRL and EN_CFG_DATA = 0 + */ + clrbits_le32(&fpga_manager_base->imgcfg_ctrl_02, + ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_DATA_SET_MSK | + ALT_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL_SET_MSK); + + /* + * Step 15: + * Disable overrides + * S2F_NENABLE_CONFIG = 1 + * S2F_NENABLE_NCONFIG = 1 + */ + setbits_le32(&fpga_manager_base->imgcfg_ctrl_01, + ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG_SET_MSK); + setbits_le32(&fpga_manager_base->imgcfg_ctrl_00, + ALT_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG_SET_MSK); + + /* Disable chip select S2F_NCE = 1 */ + setbits_le32(&fpga_manager_base->imgcfg_ctrl_01, + ALT_FPGAMGR_IMGCFG_CTL_01_S2F_NCE_SET_MSK); + + /* + * Step 16: + * Final check + */ + reg = readl(&fpga_manager_base->imgcfg_stat); + if (((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK) == 0) || + ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) == 0) || + ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK) == 0)) + return -13; + + return 0; +} + +/* + * FPGA Manager to program the FPGA. This is the interface used by FPGA driver. + * Return 0 for sucess, non-zero for error. + */ +int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) +{ + unsigned long status; + + /* disable all signals from hps peripheral controller to fpga */ + writel(0, &system_manager_base->fpgaintf_en_global); + + /* disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */ + socfpga_bridges_reset(); + + /* Initialize the FPGA Manager */ + status = fpgamgr_program_init((u32 *)rbf_data, rbf_size); + if (status) + return status; + + /* Write the RBF data to FPGA Manager */ + fpgamgr_program_write(rbf_data, rbf_size); + + return fpgamgr_program_fini(); +}