From 6867e19a439264c80354cdd297f68fa22a98c632 Mon Sep 17 00:00:00 2001 From: Tien Fong Chee Date: Wed, 26 Jul 2017 13:05:38 +0800 Subject: [PATCH] arm: socfpga: Restructure FPGA driver in the preparation to support A10 Move FPGA driver which is Gen5 specific code into Gen5 driver file and keeping common FPGA driver intact. All the changes are still keeping in driver/fpga/ and no functional change. Subsequent patch would move FPGA manager driver from arch/arm into driver/fpga/. Signed-off-by: Tien Fong Chee Reviewed-by: Ley Foon Tan Reviewed-by: Dinh Nguyen --- arch/arm/mach-socfpga/Makefile | 2 +- .../mach-socfpga/include/mach/fpga_manager.h | 68 +---- .../include/mach/fpga_manager_gen5.h | 68 +++++ drivers/fpga/Makefile | 1 + drivers/fpga/socfpga.c | 235 +--------------- drivers/fpga/socfpga_gen5.c | 252 ++++++++++++++++++ 6 files changed, 336 insertions(+), 290 deletions(-) create mode 100644 arch/arm/mach-socfpga/include/mach/fpga_manager_gen5.h create mode 100644 drivers/fpga/socfpga_gen5.c diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 41b779c5ca..286bfef8ca 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -9,7 +9,6 @@ obj-y += board.o obj-y += clock_manager.o -obj-y += fpga_manager.o obj-y += misc.o obj-y += reset_manager.o obj-y += timer.o @@ -21,6 +20,7 @@ obj-y += reset_manager_gen5.o obj-y += scan_manager.o obj-y += system_manager_gen5.o obj-y += wrap_pll_config.o +obj-y += fpga_manager.o endif ifdef CONFIG_TARGET_SOCFPGA_ARRIA10 diff --git a/arch/arm/mach-socfpga/include/mach/fpga_manager.h b/arch/arm/mach-socfpga/include/mach/fpga_manager.h index a077e2284e..b046c2c437 100644 --- a/arch/arm/mach-socfpga/include/mach/fpga_manager.h +++ b/arch/arm/mach-socfpga/include/mach/fpga_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Altera Corporation + * Copyright (C) 2012-2017 Altera Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -10,58 +10,9 @@ #include -struct socfpga_fpga_manager { - /* FPGA Manager Module */ - u32 stat; /* 0x00 */ - u32 ctrl; - u32 dclkcnt; - u32 dclkstat; - u32 gpo; /* 0x10 */ - u32 gpi; - u32 misci; /* 0x18 */ - u32 _pad_0x1c_0x82c[517]; - - /* Configuration Monitor (MON) Registers */ - u32 gpio_inten; /* 0x830 */ - u32 gpio_intmask; - u32 gpio_inttype_level; - u32 gpio_int_polarity; - u32 gpio_intstatus; /* 0x840 */ - u32 gpio_raw_intstatus; - u32 _pad_0x848; - u32 gpio_porta_eoi; - u32 gpio_ext_porta; /* 0x850 */ - u32 _pad_0x854_0x85c[3]; - u32 gpio_1s_sync; /* 0x860 */ - u32 _pad_0x864_0x868[2]; - u32 gpio_ver_id_code; - u32 gpio_config_reg2; /* 0x870 */ - u32 gpio_config_reg1; -}; - -#define FPGAMGRREGS_STAT_MODE_MASK 0x7 -#define FPGAMGRREGS_STAT_MSEL_MASK 0xf8 -#define FPGAMGRREGS_STAT_MSEL_LSB 3 - -#define FPGAMGRREGS_CTRL_CFGWDTH_MASK 0x200 -#define FPGAMGRREGS_CTRL_AXICFGEN_MASK 0x100 -#define FPGAMGRREGS_CTRL_NCONFIGPULL_MASK 0x4 -#define FPGAMGRREGS_CTRL_NCE_MASK 0x2 -#define FPGAMGRREGS_CTRL_EN_MASK 0x1 -#define FPGAMGRREGS_CTRL_CDRATIO_LSB 6 - -#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CRC_MASK 0x8 -#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_ID_MASK 0x4 -#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK 0x2 -#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK 0x1 - -/* FPGA Mode */ -#define FPGAMGRREGS_MODE_FPGAOFF 0x0 -#define FPGAMGRREGS_MODE_RESETPHASE 0x1 -#define FPGAMGRREGS_MODE_CFGPHASE 0x2 -#define FPGAMGRREGS_MODE_INITPHASE 0x3 -#define FPGAMGRREGS_MODE_USERMODE 0x4 -#define FPGAMGRREGS_MODE_UNKNOWN 0x5 +#if defined(CONFIG_TARGET_SOCFPGA_GEN5) +#include +#endif /* FPGA CD Ratio Value */ #define CDRATIO_x1 0x0 @@ -69,9 +20,14 @@ struct socfpga_fpga_manager { #define CDRATIO_x4 0x2 #define CDRATIO_x8 0x3 -/* SoCFPGA support functions */ -int fpgamgr_test_fpga_ready(void); -int fpgamgr_poll_fpga_ready(void); +#ifndef __ASSEMBLY__ + +/* Common prototypes */ int fpgamgr_get_mode(void); +int fpgamgr_poll_fpga_ready(void); +void fpgamgr_program_write(const void *rbf_data, size_t rbf_size); +int fpgamgr_test_fpga_ready(void); +int fpgamgr_dclkcnt_set(unsigned long cnt); +#endif /* __ASSEMBLY__ */ #endif /* _FPGA_MANAGER_H_ */ diff --git a/arch/arm/mach-socfpga/include/mach/fpga_manager_gen5.h b/arch/arm/mach-socfpga/include/mach/fpga_manager_gen5.h new file mode 100644 index 0000000000..2de7a117f9 --- /dev/null +++ b/arch/arm/mach-socfpga/include/mach/fpga_manager_gen5.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012-2017 Altera Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FPGA_MANAGER_GEN5_H_ +#define _FPGA_MANAGER_GEN5_H_ + +#define FPGAMGRREGS_STAT_MODE_MASK 0x7 +#define FPGAMGRREGS_STAT_MSEL_MASK 0xf8 +#define FPGAMGRREGS_STAT_MSEL_LSB 3 + +#define FPGAMGRREGS_CTRL_CFGWDTH_MASK BIT(9) +#define FPGAMGRREGS_CTRL_AXICFGEN_MASK BIT(8) +#define FPGAMGRREGS_CTRL_NCONFIGPULL_MASK BIT(2) +#define FPGAMGRREGS_CTRL_NCE_MASK BIT(1) +#define FPGAMGRREGS_CTRL_EN_MASK BIT(0) +#define FPGAMGRREGS_CTRL_CDRATIO_LSB 6 + +#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CRC_MASK BIT(3) +#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_ID_MASK BIT(2) +#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK BIT(1) +#define FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK BIT(0) + +/* FPGA Mode */ +#define FPGAMGRREGS_MODE_FPGAOFF 0x0 +#define FPGAMGRREGS_MODE_RESETPHASE 0x1 +#define FPGAMGRREGS_MODE_CFGPHASE 0x2 +#define FPGAMGRREGS_MODE_INITPHASE 0x3 +#define FPGAMGRREGS_MODE_USERMODE 0x4 +#define FPGAMGRREGS_MODE_UNKNOWN 0x5 + +#ifndef __ASSEMBLY__ + +struct socfpga_fpga_manager { + /* FPGA Manager Module */ + u32 stat; /* 0x00 */ + u32 ctrl; + u32 dclkcnt; + u32 dclkstat; + u32 gpo; /* 0x10 */ + u32 gpi; + u32 misci; /* 0x18 */ + u32 _pad_0x1c_0x82c[517]; + + /* Configuration Monitor (MON) Registers */ + u32 gpio_inten; /* 0x830 */ + u32 gpio_intmask; + u32 gpio_inttype_level; + u32 gpio_int_polarity; + u32 gpio_intstatus; /* 0x840 */ + u32 gpio_raw_intstatus; + u32 _pad_0x848; + u32 gpio_porta_eoi; + u32 gpio_ext_porta; /* 0x850 */ + u32 _pad_0x854_0x85c[3]; + u32 gpio_1s_sync; /* 0x860 */ + u32 _pad_0x864_0x868[2]; + u32 gpio_ver_id_code; + u32 gpio_config_reg2; /* 0x870 */ + u32 gpio_config_reg1; +}; + +#endif /* __ASSEMBLY__ */ + +#endif /* _FPGA_MANAGER_GEN5_H_ */ diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 777706f186..b65e5bab8f 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -20,4 +20,5 @@ obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o obj-$(CONFIG_FPGA_STRATIX_V) += stratixv.o obj-$(CONFIG_FPGA_SOCFPGA) += socfpga.o +obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += socfpga_gen5.o endif diff --git a/drivers/fpga/socfpga.c b/drivers/fpga/socfpga.c index f1b2f2c4da..28fa16b944 100644 --- a/drivers/fpga/socfpga.c +++ b/drivers/fpga/socfpga.c @@ -19,18 +19,8 @@ DECLARE_GLOBAL_DATA_PTR; static struct socfpga_fpga_manager *fpgamgr_regs = (struct socfpga_fpga_manager *)SOCFPGA_FPGAMGRREGS_ADDRESS; -static struct socfpga_system_manager *sysmgr_regs = - (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; -/* Set CD ratio */ -static void fpgamgr_set_cd_ratio(unsigned long ratio) -{ - clrsetbits_le32(&fpgamgr_regs->ctrl, - 0x3 << FPGAMGRREGS_CTRL_CDRATIO_LSB, - (ratio & 0x3) << FPGAMGRREGS_CTRL_CDRATIO_LSB); -} - -static int fpgamgr_dclkcnt_set(unsigned long cnt) +int fpgamgr_dclkcnt_set(unsigned long cnt) { unsigned long i; @@ -53,98 +43,8 @@ static int fpgamgr_dclkcnt_set(unsigned long cnt) return -ETIMEDOUT; } -/* Start the FPGA programming by initialize the FPGA Manager */ -static int fpgamgr_program_init(void) -{ - unsigned long msel, i; - - /* Get the MSEL value */ - msel = readl(&fpgamgr_regs->stat); - msel &= FPGAMGRREGS_STAT_MSEL_MASK; - msel >>= FPGAMGRREGS_STAT_MSEL_LSB; - - /* - * Set the cfg width - * If MSEL[3] = 1, cfg width = 32 bit - */ - if (msel & 0x8) { - setbits_le32(&fpgamgr_regs->ctrl, - FPGAMGRREGS_CTRL_CFGWDTH_MASK); - - /* To determine the CD ratio */ - /* MSEL[1:0] = 0, CD Ratio = 1 */ - if ((msel & 0x3) == 0x0) - fpgamgr_set_cd_ratio(CDRATIO_x1); - /* MSEL[1:0] = 1, CD Ratio = 4 */ - else if ((msel & 0x3) == 0x1) - fpgamgr_set_cd_ratio(CDRATIO_x4); - /* MSEL[1:0] = 2, CD Ratio = 8 */ - else if ((msel & 0x3) == 0x2) - fpgamgr_set_cd_ratio(CDRATIO_x8); - - } else { /* MSEL[3] = 0 */ - clrbits_le32(&fpgamgr_regs->ctrl, - FPGAMGRREGS_CTRL_CFGWDTH_MASK); - - /* To determine the CD ratio */ - /* MSEL[1:0] = 0, CD Ratio = 1 */ - if ((msel & 0x3) == 0x0) - fpgamgr_set_cd_ratio(CDRATIO_x1); - /* MSEL[1:0] = 1, CD Ratio = 2 */ - else if ((msel & 0x3) == 0x1) - fpgamgr_set_cd_ratio(CDRATIO_x2); - /* MSEL[1:0] = 2, CD Ratio = 4 */ - else if ((msel & 0x3) == 0x2) - fpgamgr_set_cd_ratio(CDRATIO_x4); - } - - /* To enable FPGA Manager configuration */ - clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCE_MASK); - - /* To enable FPGA Manager drive over configuration line */ - setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK); - - /* Put FPGA into reset phase */ - setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK); - - /* (1) wait until FPGA enter reset phase */ - for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { - if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_RESETPHASE) - break; - } - - /* If not in reset state, return error */ - if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_RESETPHASE) { - puts("FPGA: Could not reset\n"); - return -1; - } - - /* Release FPGA from reset phase */ - clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK); - - /* (2) wait until FPGA enter configuration phase */ - for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { - if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_CFGPHASE) - break; - } - - /* If not in configuration state, return error */ - if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_CFGPHASE) { - puts("FPGA: Could not configure\n"); - return -2; - } - - /* Clear all interrupts in CB Monitor */ - writel(0xFFF, &fpgamgr_regs->gpio_porta_eoi); - - /* Enable AXI configuration */ - setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK); - - return 0; -} - /* Write the RBF data to FPGA Manager */ -static void fpgamgr_program_write(const void *rbf_data, unsigned long rbf_size) +void fpgamgr_program_write(const void *rbf_data, size_t rbf_size) { uint32_t src = (uint32_t)rbf_data; uint32_t dst = SOCFPGA_FPGAMGRDATA_ADDRESS; @@ -171,134 +71,3 @@ static void fpgamgr_program_write(const void *rbf_data, unsigned long rbf_size) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "cc"); } -/* Ensure the FPGA entering config done */ -static int fpgamgr_program_poll_cd(void) -{ - const uint32_t mask = FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK | - FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK; - unsigned long reg, i; - - /* (3) wait until full config done */ - for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { - reg = readl(&fpgamgr_regs->gpio_ext_porta); - - /* Config error */ - if (!(reg & mask)) { - printf("FPGA: Configuration error.\n"); - return -3; - } - - /* Config done without error */ - if (reg & mask) - break; - } - - /* Timeout happened, return error */ - if (i == FPGA_TIMEOUT_CNT) { - printf("FPGA: Timeout waiting for program.\n"); - return -4; - } - - /* Disable AXI configuration */ - clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK); - - return 0; -} - -/* Ensure the FPGA entering init phase */ -static int fpgamgr_program_poll_initphase(void) -{ - unsigned long i; - - /* Additional clocks for the CB to enter initialization phase */ - if (fpgamgr_dclkcnt_set(0x4)) - return -5; - - /* (4) wait until FPGA enter init phase or user mode */ - for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { - if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_INITPHASE) - break; - if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE) - break; - } - - /* If not in configuration state, return error */ - if (i == FPGA_TIMEOUT_CNT) - return -6; - - return 0; -} - -/* Ensure the FPGA entering user mode */ -static int fpgamgr_program_poll_usermode(void) -{ - unsigned long i; - - /* Additional clocks for the CB to exit initialization phase */ - if (fpgamgr_dclkcnt_set(0x5000)) - return -7; - - /* (5) wait until FPGA enter user mode */ - for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { - if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE) - break; - } - /* If not in configuration state, return error */ - if (i == FPGA_TIMEOUT_CNT) - return -8; - - /* To release FPGA Manager drive over configuration line */ - clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK); - - 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; - - if ((uint32_t)rbf_data & 0x3) { - puts("FPGA: Unaligned data, realign to 32bit boundary.\n"); - return -EINVAL; - } - - /* Prior programming the FPGA, all bridges need to be shut off */ - - /* Disable all signals from hps peripheral controller to fpga */ - writel(0, &sysmgr_regs->fpgaintfgrp_module); - - /* Disable all signals from FPGA to HPS SDRAM */ -#define SDR_CTRLGRP_FPGAPORTRST_ADDRESS 0x5080 - writel(0, SOCFPGA_SDR_ADDRESS + SDR_CTRLGRP_FPGAPORTRST_ADDRESS); - - /* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */ - socfpga_bridges_reset(1); - - /* Unmap the bridges from NIC-301 */ - writel(0x1, SOCFPGA_L3REGS_ADDRESS); - - /* Initialize the FPGA Manager */ - status = fpgamgr_program_init(); - if (status) - return status; - - /* Write the RBF data to FPGA Manager */ - fpgamgr_program_write(rbf_data, rbf_size); - - /* Ensure the FPGA entering config done */ - status = fpgamgr_program_poll_cd(); - if (status) - return status; - - /* Ensure the FPGA entering init phase */ - status = fpgamgr_program_poll_initphase(); - if (status) - return status; - - /* Ensure the FPGA entering user mode */ - return fpgamgr_program_poll_usermode(); -} diff --git a/drivers/fpga/socfpga_gen5.c b/drivers/fpga/socfpga_gen5.c new file mode 100644 index 0000000000..3dfb0303d3 --- /dev/null +++ b/drivers/fpga/socfpga_gen5.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2012 Altera Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define FPGA_TIMEOUT_CNT 0x1000000 + +static struct socfpga_fpga_manager *fpgamgr_regs = + (struct socfpga_fpga_manager *)SOCFPGA_FPGAMGRREGS_ADDRESS; +static struct socfpga_system_manager *sysmgr_regs = + (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; + +/* Set CD ratio */ +static void fpgamgr_set_cd_ratio(unsigned long ratio) +{ + clrsetbits_le32(&fpgamgr_regs->ctrl, + 0x3 << FPGAMGRREGS_CTRL_CDRATIO_LSB, + (ratio & 0x3) << FPGAMGRREGS_CTRL_CDRATIO_LSB); +} + +/* Start the FPGA programming by initialize the FPGA Manager */ +static int fpgamgr_program_init(void) +{ + unsigned long msel, i; + + /* Get the MSEL value */ + msel = readl(&fpgamgr_regs->stat); + msel &= FPGAMGRREGS_STAT_MSEL_MASK; + msel >>= FPGAMGRREGS_STAT_MSEL_LSB; + + /* + * Set the cfg width + * If MSEL[3] = 1, cfg width = 32 bit + */ + if (msel & 0x8) { + setbits_le32(&fpgamgr_regs->ctrl, + FPGAMGRREGS_CTRL_CFGWDTH_MASK); + + /* To determine the CD ratio */ + /* MSEL[1:0] = 0, CD Ratio = 1 */ + if ((msel & 0x3) == 0x0) + fpgamgr_set_cd_ratio(CDRATIO_x1); + /* MSEL[1:0] = 1, CD Ratio = 4 */ + else if ((msel & 0x3) == 0x1) + fpgamgr_set_cd_ratio(CDRATIO_x4); + /* MSEL[1:0] = 2, CD Ratio = 8 */ + else if ((msel & 0x3) == 0x2) + fpgamgr_set_cd_ratio(CDRATIO_x8); + + } else { /* MSEL[3] = 0 */ + clrbits_le32(&fpgamgr_regs->ctrl, + FPGAMGRREGS_CTRL_CFGWDTH_MASK); + + /* To determine the CD ratio */ + /* MSEL[1:0] = 0, CD Ratio = 1 */ + if ((msel & 0x3) == 0x0) + fpgamgr_set_cd_ratio(CDRATIO_x1); + /* MSEL[1:0] = 1, CD Ratio = 2 */ + else if ((msel & 0x3) == 0x1) + fpgamgr_set_cd_ratio(CDRATIO_x2); + /* MSEL[1:0] = 2, CD Ratio = 4 */ + else if ((msel & 0x3) == 0x2) + fpgamgr_set_cd_ratio(CDRATIO_x4); + } + + /* To enable FPGA Manager configuration */ + clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCE_MASK); + + /* To enable FPGA Manager drive over configuration line */ + setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK); + + /* Put FPGA into reset phase */ + setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK); + + /* (1) wait until FPGA enter reset phase */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_RESETPHASE) + break; + } + + /* If not in reset state, return error */ + if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_RESETPHASE) { + puts("FPGA: Could not reset\n"); + return -1; + } + + /* Release FPGA from reset phase */ + clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_NCONFIGPULL_MASK); + + /* (2) wait until FPGA enter configuration phase */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_CFGPHASE) + break; + } + + /* If not in configuration state, return error */ + if (fpgamgr_get_mode() != FPGAMGRREGS_MODE_CFGPHASE) { + puts("FPGA: Could not configure\n"); + return -2; + } + + /* Clear all interrupts in CB Monitor */ + writel(0xFFF, &fpgamgr_regs->gpio_porta_eoi); + + /* Enable AXI configuration */ + setbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK); + + return 0; +} + +/* Ensure the FPGA entering config done */ +static int fpgamgr_program_poll_cd(void) +{ + const uint32_t mask = FPGAMGRREGS_MON_GPIO_EXT_PORTA_NS_MASK | + FPGAMGRREGS_MON_GPIO_EXT_PORTA_CD_MASK; + unsigned long reg, i; + + /* (3) wait until full config done */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + reg = readl(&fpgamgr_regs->gpio_ext_porta); + + /* Config error */ + if (!(reg & mask)) { + printf("FPGA: Configuration error.\n"); + return -3; + } + + /* Config done without error */ + if (reg & mask) + break; + } + + /* Timeout happened, return error */ + if (i == FPGA_TIMEOUT_CNT) { + printf("FPGA: Timeout waiting for program.\n"); + return -4; + } + + /* Disable AXI configuration */ + clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_AXICFGEN_MASK); + + return 0; +} + +/* Ensure the FPGA entering init phase */ +static int fpgamgr_program_poll_initphase(void) +{ + unsigned long i; + + /* Additional clocks for the CB to enter initialization phase */ + if (fpgamgr_dclkcnt_set(0x4)) + return -5; + + /* (4) wait until FPGA enter init phase or user mode */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_INITPHASE) + break; + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE) + break; + } + + /* If not in configuration state, return error */ + if (i == FPGA_TIMEOUT_CNT) + return -6; + + return 0; +} + +/* Ensure the FPGA entering user mode */ +static int fpgamgr_program_poll_usermode(void) +{ + unsigned long i; + + /* Additional clocks for the CB to exit initialization phase */ + if (fpgamgr_dclkcnt_set(0x5000)) + return -7; + + /* (5) wait until FPGA enter user mode */ + for (i = 0; i < FPGA_TIMEOUT_CNT; i++) { + if (fpgamgr_get_mode() == FPGAMGRREGS_MODE_USERMODE) + break; + } + /* If not in configuration state, return error */ + if (i == FPGA_TIMEOUT_CNT) + return -8; + + /* To release FPGA Manager drive over configuration line */ + clrbits_le32(&fpgamgr_regs->ctrl, FPGAMGRREGS_CTRL_EN_MASK); + + 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; + + if ((uint32_t)rbf_data & 0x3) { + puts("FPGA: Unaligned data, realign to 32bit boundary.\n"); + return -EINVAL; + } + + /* Prior programming the FPGA, all bridges need to be shut off */ + + /* Disable all signals from hps peripheral controller to fpga */ + writel(0, &sysmgr_regs->fpgaintfgrp_module); + + /* Disable all signals from FPGA to HPS SDRAM */ +#define SDR_CTRLGRP_FPGAPORTRST_ADDRESS 0x5080 + writel(0, SOCFPGA_SDR_ADDRESS + SDR_CTRLGRP_FPGAPORTRST_ADDRESS); + + /* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */ + socfpga_bridges_reset(1); + + /* Unmap the bridges from NIC-301 */ + writel(0x1, SOCFPGA_L3REGS_ADDRESS); + + /* Initialize the FPGA Manager */ + status = fpgamgr_program_init(); + if (status) + return status; + + /* Write the RBF data to FPGA Manager */ + fpgamgr_program_write(rbf_data, rbf_size); + + /* Ensure the FPGA entering config done */ + status = fpgamgr_program_poll_cd(); + if (status) + return status; + + /* Ensure the FPGA entering init phase */ + status = fpgamgr_program_poll_initphase(); + if (status) + return status; + + /* Ensure the FPGA entering user mode */ + return fpgamgr_program_poll_usermode(); +} -- 2.39.5