/******************************************************************************* * (c) Copyright 2012-2013 Microsemi SoC Products Group. All rights reserved. * * SmartFusion2 CMSIS system initialization. * * SVN $Revision: 7375 $ * SVN $Date: 2015-05-01 14:57:40 +0100 (Fri, 01 May 2015) $ */ #include "m2sxxx.h" #if MSCC_NO_RELATIVE_PATHS #include "sys_config.h" #else #include "sys_config.h" #endif #include "sys_init_cfg_types.h" /*------------------------------------------------------------------------------ Silicon revisions. */ #define UNKNOWN_SILICON_REV 0 #define M2S050_REV_A_SILICON 1 #define M2S050_REV_B_SILICON 2 /*------------------------------------------------------------------------------ * CoreConfigP IP block version. */ #define CORE_CONFIGP_V7_0 0x00070000u /*------------------------------------------------------------------------------ * */ void mscc_post_hw_cfg_init(void); /*------------------------------------------------------------------------------ * CoreConfigP/CoreConfigP register bits */ #define CONFIG_1_DONE 1u #define CONFIG_2_DONE 2u #define INIT_DONE_MASK 0x00000001u #define SDIF_RELEASED_MASK 0x00000002u /*------------------------------------------------------------------------------ * System registers of interest. */ /* * MSSDDR_FACC1_CR register masks: */ #define DDR_CLK_EN_SHIFT 8u #define FACC_GLMUX_SEL_MASK 0x00001000u #define CONTROLLER_PLL_INIT_MASK 0x04000000u #define RCOSC_DIV2_MASK 0x00000004u /* * MSSDDR_PLL_STATUS register masks: */ #define FAB_PLL_LOCK_MASK 0x00000001u #define MPLL_LOCK_MASK 0x00000002u /* * MSSDDR_PLL_STATUS_HIGH_CR register masks: */ #define FACC_PLL_BYPASS_MASK 0x00000001u /*------------------------------------------------------------------------------ * Standard CMSIS global variables. */ uint32_t SystemCoreClock = MSS_SYS_M3_CLK_FREQ; /*!< System Clock Frequency (Core Clock) */ /*------------------------------------------------------------------------------ * SmartFusion2 specific clocks. */ uint32_t g_FrequencyPCLK0 = MSS_SYS_APB_0_CLK_FREQ; /*!< Clock frequency of APB bus 0. */ uint32_t g_FrequencyPCLK1 = MSS_SYS_APB_1_CLK_FREQ; /*!< Clock frequency of APB bus 1. */ uint32_t g_FrequencyPCLK2 = MSS_SYS_APB_2_CLK_FREQ; /*!< Clock frequency of APB bus 2. */ uint32_t g_FrequencyFIC0 = MSS_SYS_FIC_0_CLK_FREQ; /*!< Clock frequecny of FPGA fabric interface controller 1. */ uint32_t g_FrequencyFIC1 = MSS_SYS_FIC_1_CLK_FREQ; /*!< Clock frequecny of FPGA fabric inteface controller 2. */ uint32_t g_FrequencyFIC64 = MSS_SYS_FIC64_CLK_FREQ; /*!< Clock frequecny of 64-bit FPGA fabric interface controller. */ /*------------------------------------------------------------------------------ * System configuration tables generated by Libero. */ #if MSS_SYS_MDDR_CONFIG_BY_CORTEX extern MDDR_TypeDef * const g_m2s_mddr_addr; extern const ddr_subsys_cfg_t g_m2s_mddr_subsys_config; #endif #if MSS_SYS_FDDR_CONFIG_BY_CORTEX extern FDDR_TypeDef * const g_m2s_fddr_addr; extern const ddr_subsys_cfg_t g_m2s_fddr_subsys_config; #endif #define MSS_SYS_SERDES_CONFIG_BY_CORTEX (MSS_SYS_SERDES_0_CONFIG_BY_CORTEX || MSS_SYS_SERDES_1_CONFIG_BY_CORTEX || MSS_SYS_SERDES_2_CONFIG_BY_CORTEX || MSS_SYS_SERDES_3_CONFIG_BY_CORTEX) #if MSS_SYS_SERDES_0_CONFIG_BY_CORTEX extern const cfg_addr_value_pair_t g_m2s_serdes_0_config[SERDES_0_CFG_NB_OF_PAIRS]; #endif #if MSS_SYS_SERDES_1_CONFIG_BY_CORTEX extern const cfg_addr_value_pair_t g_m2s_serdes_1_config[SERDES_1_CFG_NB_OF_PAIRS]; #endif #if MSS_SYS_SERDES_2_CONFIG_BY_CORTEX extern const cfg_addr_value_pair_t g_m2s_serdes_2_config[SERDES_2_CFG_NB_OF_PAIRS]; #endif #if MSS_SYS_SERDES_3_CONFIG_BY_CORTEX extern const cfg_addr_value_pair_t g_m2s_serdes_3_config[SERDES_3_CFG_NB_OF_PAIRS]; #endif #define MSS_SYS_CORESF2RESET_USED (MSS_SYS_MDDR_CONFIG_BY_CORTEX || MSS_SYS_FDDR_CONFIG_BY_CORTEX || MSS_SYS_SERDES_CONFIG_BY_CORTEX) /*============================================================================== * List of PCIe lanes on which PMA_READY must be polled. Allows only polling PMA * READY on the first lane of a PCIe link regardless of the number of lanes used * or whether lane reversal is used. */ #if MSS_SYS_SERDES_CONFIG_BY_CORTEX #define CONFIG_REG_LANE_SEL_LANE_0 0x00000100U #define CONFIG_REG_LANE_SEL_LANE_1 0x00000200U #define CONFIG_REG_LANE_SEL_LANE_2 0x00000400U #define CONFIG_REG_LANE_SEL_LANE_3 0x00000800U #define CONFIG_REG_LANE_SEL_MASK (CONFIG_REG_LANE_SEL_LANE_0 | \ CONFIG_REG_LANE_SEL_LANE_1 | \ CONFIG_REG_LANE_SEL_LANE_2 | \ CONFIG_REG_LANE_SEL_LANE_3) #define FIRST_PCIE_CTRL 1U #define SECOND_PCIE_CTRL 2U typedef struct pma_poll_info { SERDESIF_TypeDef * serdes; SERDES_TypeDef * const lane; uint16_t config_reg_lane_sel; uint16_t pcie_ctrl_id; /* distinguish between first and second PCIe controller on M2S090. */ } pma_poll_info_t; /*------------------------------------------------------------------------------ * SERDES0: list of PMA to poll as part of PCIe configuration. This list only * handles the first PCIe controller of SERDES0. */ static const pma_poll_info_t g_serdes0_pcie_lane_cfg_lut[] = { #if defined(SERDESIF_0_PCIE_LANE_PMA_STATUS_LANE_0) { SERDES0, /* SERDESIF_TypeDef * serdes */ &SERDES0->lane[0], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_0, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_0_PCIE_LANE_PMA_STATUS_LANE_1) { SERDES0, /* SERDESIF_TypeDef * serdes */ &SERDES0->lane[1], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_1, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_0_PCIE_LANE_PMA_STATUS_LANE_2) { SERDES0, /* SERDESIF_TypeDef * serdes */ &SERDES0->lane[2], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_2, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_0_PCIE_LANE_PMA_STATUS_LANE_3) { SERDES0, /* SERDESIF_TypeDef * serdes */ &SERDES0->lane[3], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_3, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif { (SERDESIF_TypeDef *)0, /* SERDESIF_TypeDef * serdes */ (SERDES_TypeDef *)0, /* SERDES_TypeDef * const lane */ 0, /* uint16_t config_reg_lane_sel */ 0 /* uint16_t pcie_ctrl_id */ } }; /*------------------------------------------------------------------------------ * SERDES1: list of PMA to poll as part of PCIe configuration. This list handles * both SERDES1 first PCIe controller and the M2S090 SERDES0 second PCIe * controller. */ static const pma_poll_info_t g_serdes1_pcie_lane_cfg_lut[] = { #if defined(SERDESIF_1_PCIE_LANE_PMA_STATUS_LANE_0) { SERDES1, /* SERDESIF_TypeDef * serdes */ &SERDES1->lane[0], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_0, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_1_PCIE_LANE_PMA_STATUS_LANE_1) { SERDES1, /* SERDESIF_TypeDef * serdes */ &SERDES1->lane[1], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_1, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_1_PCIE_LANE_PMA_STATUS_LANE_2) { SERDES1, /* SERDESIF_TypeDef * serdes */ &SERDES1->lane[2], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_2, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_1_PCIE_LANE_PMA_STATUS_LANE_3) { SERDES1, /* SERDESIF_TypeDef * serdes */ &SERDES1->lane[3], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_3, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_0_PCIE_1_LANE_PMA_STATUS_LANE_0) { SERDES0, /* SERDESIF_TypeDef * serdes */ &SERDES0->lane[0], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_0, /* uint16_t config_reg_lane_sel */ SECOND_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_0_PCIE_1_LANE_PMA_STATUS_LANE_1) { SERDES0, /* SERDESIF_TypeDef * serdes */ &SERDES0->lane[1], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_1, /* uint16_t config_reg_lane_sel */ SECOND_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_0_PCIE_1_LANE_PMA_STATUS_LANE_2) { SERDES0, /* SERDESIF_TypeDef * serdes */ &SERDES0->lane[2], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_2, /* uint16_t config_reg_lane_sel */ SECOND_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_0_PCIE_1_LANE_PMA_STATUS_LANE_3) { SERDES0, /* SERDESIF_TypeDef * serdes */ &SERDES0->lane[3], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_3, /* uint16_t config_reg_lane_sel */ SECOND_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif { (SERDESIF_TypeDef *)0, /* SERDESIF_TypeDef * serdes */ (SERDES_TypeDef *)0, /* SERDES_TypeDef * const lane */ 0, /* uint16_t config_reg_lane_sel */ 0 /* uint16_t pcie_ctrl_id */ } }; /*------------------------------------------------------------------------------ * SERDES2: list of PMA to poll as part of PCIe configuration. */ static const pma_poll_info_t g_serdes2_pcie_lane_cfg_lut[] = { #if defined(SERDESIF_2_PCIE_LANE_PMA_STATUS_LANE_0) { SERDES2, /* SERDESIF_TypeDef * serdes */ &SERDES2->lane[0], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_0, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_2_PCIE_LANE_PMA_STATUS_LANE_1) { SERDES2, /* SERDESIF_TypeDef * serdes */ &SERDES2->lane[1], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_1, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_2_PCIE_LANE_PMA_STATUS_LANE_2) { SERDES2, /* SERDESIF_TypeDef * serdes */ &SERDES2->lane[2], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_2, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_2_PCIE_LANE_PMA_STATUS_LANE_3) { SERDES2, /* SERDESIF_TypeDef * serdes */ &SERDES2->lane[3], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_3, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif { (SERDESIF_TypeDef *)0, /* SERDESIF_TypeDef * serdes */ (SERDES_TypeDef *)0, /* SERDES_TypeDef * const lane */ 0, /* uint16_t config_reg_lane_sel */ 0 /* uint16_t pcie_ctrl_id */ } }; /*------------------------------------------------------------------------------ * SERDES3: list of PMA to poll as part of PCIe configuration. */ static const pma_poll_info_t g_serdes3_pcie_lane_cfg_lut[] = { #if defined(SERDESIF_3_PCIE_LANE_PMA_STATUS_LANE_0) { SERDES3, /* SERDESIF_TypeDef * serdes */ &SERDES3->lane[0], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_0, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_3_PCIE_LANE_PMA_STATUS_LANE_1) { SERDES3, /* SERDESIF_TypeDef * serdes */ &SERDES3->lane[1], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_1, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_3_PCIE_LANE_PMA_STATUS_LANE_2) { SERDES3, /* SERDESIF_TypeDef * serdes */ &SERDES3->lane[2], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_2, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif #if defined(SERDESIF_3_PCIE_LANE_PMA_STATUS_LANE_3) { SERDES3, /* SERDESIF_TypeDef * serdes */ &SERDES3->lane[3], /* SERDES_TypeDef * const lane */ CONFIG_REG_LANE_SEL_LANE_3, /* uint16_t config_reg_lane_sel */ FIRST_PCIE_CTRL /* uint16_t pcie_ctrl_id */ }, #endif { (SERDESIF_TypeDef *)0, /* SERDESIF_TypeDef * serdes */ (SERDES_TypeDef *)0, /* SERDES_TypeDef * const lane */ 0, /* uint16_t config_reg_lane_sel */ 0 /* uint16_t pcie_ctrl_id */ } }; /*------------------------------------------------------------------------------ * Master lookup table for all SERDES PCIe configuration. */ static const pma_poll_info_t * const g_pcie_lane_cfg_lut[] = { g_serdes0_pcie_lane_cfg_lut, g_serdes1_pcie_lane_cfg_lut, g_serdes2_pcie_lane_cfg_lut, g_serdes3_pcie_lane_cfg_lut }; #endif /*------------------------------------------------------------------------------ * Local functions: */ static uint32_t get_silicon_revision(void); static void silicon_workarounds(void); static void m2s050_rev_a_workarounds(void); #if (MSS_SYS_FACC_INIT_BY_CORTEX == 1) static void complete_clock_config(void); #endif #if MSS_SYS_SERDES_CONFIG_BY_CORTEX static void configure_serdes_intf(void); static void configure_pcie_intf(void); static void configure_pcie_block ( const cfg_addr_value_pair_t * p_addr_value_pair, uint32_t nb_of_cfg_pairs, uint32_t serdes_id ); #endif #if (MSS_SYS_MDDR_CONFIG_BY_CORTEX || MSS_SYS_FDDR_CONFIG_BY_CORTEX) static void config_ddr_subsys ( const ddr_subsys_cfg_t * p_ddr_subsys_cfg, DDRCore_TypeDef * p_ddr_subsys_regs ); #endif #if MSS_SYS_SERDES_CONFIG_BY_CORTEX static void config_by_addr_value ( const cfg_addr_value_pair_t * p_addr_value_pair, uint32_t nb_of_cfg_pairs ); #endif static uint32_t get_rcosc_25_50mhz_frequency(void); static void set_clock_frequency_globals(uint32_t fclk); /***************************************************************************//** * See system_m2sxxx.h for details. */ void SystemInit(void) { #if MSS_SYS_SERDES_CONFIG_BY_CORTEX uint32_t sdif_released; #endif #if MSS_SYS_CORESF2RESET_USED uint32_t init_done; #endif #if MSS_SYS_SERDES_CONFIG_BY_CORTEX uint32_t core_cfg_version; core_cfg_version = CORE_SF2_CFG->IP_VERSION_SR; #endif /* * Do not make use of global variables or make any asumptions regarding * memory content if modifying this function. The memory content has not been * initialised by the time this function is called by the start-up code. */ #if (MSS_SYS_FACC_INIT_BY_CORTEX == 1) complete_clock_config(); #endif silicon_workarounds(); /*-------------------------------------------------------------------------- * Set STKALIGN to ensure exception stacking starts on 8 bytes address * boundary. This ensures compliance with the "Procedure Call Standards for * the ARM Architecture" (AAPCS). */ SCB->CCR |= SCB_CCR_STKALIGN_Msk; /*-------------------------------------------------------------------------- * MDDR configuration */ #if MSS_SYS_MDDR_CONFIG_BY_CORTEX if(0u == SYSREG->DDR_CR) { /* * We only configure the MDDR memory controller if MDDR is not remapped * to address 0x00000000. If MDDR is remapped to 0x00000000 then we are * probably executing this code from MDDR in a debugging session and * attempting to reconfigure the MDDR memory controller will cause the * Cortex-M3 to crash. */ config_ddr_subsys(&g_m2s_mddr_subsys_config, &g_m2s_mddr_addr->core); } #endif /*-------------------------------------------------------------------------- * FDDR configuration */ #if MSS_SYS_FDDR_CONFIG_BY_CORTEX config_ddr_subsys(&g_m2s_fddr_subsys_config, &g_m2s_fddr_addr->core); #endif /*-------------------------------------------------------------------------- * Call user defined configuration function. */ mscc_post_hw_cfg_init(); /*-------------------------------------------------------------------------- * SERDES interfaces configuration. */ #if MSS_SYS_SERDES_CONFIG_BY_CORTEX configure_serdes_intf(); if(core_cfg_version >= CORE_CONFIGP_V7_0) { CORE_SF2_CFG->CONFIG_DONE = CONFIG_1_DONE; /* Poll for SDIF_RELEASED. */ do { sdif_released = CORE_SF2_CFG->INIT_DONE & SDIF_RELEASED_MASK; } while (0u == sdif_released); } configure_pcie_intf(); #endif /*-------------------------------------------------------------------------- * Synchronize with CoreSF2Reset controlling resets from the fabric. */ #if MSS_SYS_CORESF2RESET_USED /* * Negate FPGA_SOFTRESET to de-assert MSS_RESET_N_M2F in the fabric. We must * do this here because this signal is only deasserted by the System * Controller on a power-on reset. Other types of reset such as a watchdog * reset would result in the FPGA fabric being held in reset and getting * stuck waiting for the CoreSF2Config INIT_DONE to become asserted. */ SYSREG->SOFT_RST_CR &= ~SYSREG_FPGA_SOFTRESET_MASK; /* * Signal to CoreSF2Reset that peripheral configuration registers have been * written. */ CORE_SF2_CFG->CONFIG_DONE |= (CONFIG_1_DONE | CONFIG_2_DONE); /* Wait for INIT_DONE from CoreSF2Reset. */ do { init_done = CORE_SF2_CFG->INIT_DONE & INIT_DONE_MASK; } while (0u == init_done); #endif } /***************************************************************************//** * SystemCoreClockUpdate() */ #define RCOSC_25_50MHZ_CLK_SRC 0u #define CLK_XTAL_CLK_SRC 1u #define RCOSC_1_MHZ_CLK_SRC 2u #define CCC2ASCI_CLK_SRC 3u #define FACC_STANDBY_SHIFT 6u #define FACC_STANDBY_SEL_MASK 0x00000007u #define FREQ_32KHZ 32768u #define FREQ_1MHZ 1000000u #define FREQ_25MHZ 25000000u #define FREQ_50MHZ 50000000u void SystemCoreClockUpdate(void) { uint32_t controller_pll_init; uint32_t clk_src; controller_pll_init = SYSREG->MSSDDR_FACC1_CR & CONTROLLER_PLL_INIT_MASK; if(0u == controller_pll_init) { /* Normal operations. */ uint32_t global_mux_sel; global_mux_sel = SYSREG->MSSDDR_FACC1_CR & FACC_GLMUX_SEL_MASK; if(0u == global_mux_sel) { /* MSS clocked from MSS PLL. Use Libero flow defines. */ SystemCoreClock = MSS_SYS_M3_CLK_FREQ; g_FrequencyPCLK0 = MSS_SYS_APB_0_CLK_FREQ; g_FrequencyPCLK1 = MSS_SYS_APB_1_CLK_FREQ; g_FrequencyPCLK2 = MSS_SYS_APB_2_CLK_FREQ; g_FrequencyFIC0 = MSS_SYS_FIC_0_CLK_FREQ; g_FrequencyFIC1 = MSS_SYS_FIC_1_CLK_FREQ; g_FrequencyFIC64 = MSS_SYS_FIC64_CLK_FREQ; } else { /* MSS clocked from standby clock. */ const uint8_t standby_clock_lut[8] = { RCOSC_25_50MHZ_CLK_SRC, CLK_XTAL_CLK_SRC, RCOSC_25_50MHZ_CLK_SRC, CLK_XTAL_CLK_SRC, RCOSC_1_MHZ_CLK_SRC, RCOSC_1_MHZ_CLK_SRC, CCC2ASCI_CLK_SRC, CCC2ASCI_CLK_SRC }; uint32_t standby_sel; uint8_t clock_source; standby_sel = (SYSREG->MSSDDR_FACC2_CR >> FACC_STANDBY_SHIFT) & FACC_STANDBY_SEL_MASK; clock_source = standby_clock_lut[standby_sel]; switch(clock_source) { case RCOSC_25_50MHZ_CLK_SRC: clk_src = get_rcosc_25_50mhz_frequency(); set_clock_frequency_globals(clk_src); break; case CLK_XTAL_CLK_SRC: set_clock_frequency_globals(FREQ_32KHZ); break; case RCOSC_1_MHZ_CLK_SRC: set_clock_frequency_globals(FREQ_1MHZ); break; case CCC2ASCI_CLK_SRC: /* Fall through. */ default: set_clock_frequency_globals(FREQ_1MHZ); break; } } } else { /* PLL initialization mode. Running from 25/50MHZ RC oscillator. */ clk_src = get_rcosc_25_50mhz_frequency(); set_clock_frequency_globals(clk_src); } } /***************************************************************************//** * Find out frequency generated by the 25_50mhz RC osciallator. */ static uint32_t get_rcosc_25_50mhz_frequency(void) { uint32_t rcosc_div2; uint32_t rcosc_frequency; rcosc_div2 = SYSREG->MSSDDR_PLL_STATUS & RCOSC_DIV2_MASK; if(0u == rcosc_div2) { /* 25_50mhz oscillator is configured for 25 MHz operations. */ rcosc_frequency = FREQ_25MHZ; } else { /* 25_50mhz oscillator is configured for 50 MHz operations. */ rcosc_frequency = FREQ_50MHZ; } return rcosc_frequency; } /***************************************************************************//** Set the value of the clock frequency global variables based on the value of standby_clk passed as parameter. The following global variables are set by this function: - SystemCoreClock - g_FrequencyPCLK0 - g_FrequencyPCLK1 - g_FrequencyPCLK2 - g_FrequencyFIC0 - g_FrequencyFIC1 - g_FrequencyFIC64 */ static void set_clock_frequency_globals(uint32_t standby_clk) { SystemCoreClock = standby_clk; g_FrequencyPCLK0 = standby_clk; g_FrequencyPCLK1 = standby_clk; g_FrequencyPCLK2 = MSS_SYS_APB_2_CLK_FREQ; g_FrequencyFIC0 = standby_clk; g_FrequencyFIC1 = standby_clk; g_FrequencyFIC64 = standby_clk; } /***************************************************************************//** * Write 16-bit configuration values into 32-bit word aligned registers. */ #if (MSS_SYS_MDDR_CONFIG_BY_CORTEX || MSS_SYS_FDDR_CONFIG_BY_CORTEX) static void copy_cfg16_to_regs ( volatile uint32_t * p_regs, const uint16_t * p_cfg, uint32_t nb_16bit_words ) { uint32_t inc; for(inc = 0u; inc < nb_16bit_words; ++inc) { p_regs[inc] = p_cfg[inc]; } } #endif /***************************************************************************//** * Configure peripheral using register address and register value pairs. */ #if MSS_SYS_SERDES_CONFIG_BY_CORTEX static void config_by_addr_value ( const cfg_addr_value_pair_t * p_addr_value_pair, uint32_t nb_of_cfg_pairs ) { uint32_t inc; for(inc = 0u; inc < nb_of_cfg_pairs; ++inc) { *p_addr_value_pair[inc].p_reg = p_addr_value_pair[inc].value; } } #endif /***************************************************************************//** * DDR subsystem configuration. */ #if (MSS_SYS_MDDR_CONFIG_BY_CORTEX || MSS_SYS_FDDR_CONFIG_BY_CORTEX) #define NB_OF_DDRC_REGS_TO_CONFIG 57u #define NB_OF_DDR_PHY_REGS_TO_CONFIG 65u static void config_ddr_subsys ( const ddr_subsys_cfg_t * p_ddr_subsys_cfg, DDRCore_TypeDef * p_ddr_subsys_regs ) { volatile uint32_t * p_regs; const uint16_t * p_cfg; /*-------------------------------------------------------------------------- * Configure DDR controller part of the MDDR subsystem. */ p_cfg = &p_ddr_subsys_cfg->ddrc.DYN_SOFT_RESET_CR; p_regs = &p_ddr_subsys_regs->ddrc.DYN_SOFT_RESET_CR; copy_cfg16_to_regs(p_regs, p_cfg, NB_OF_DDRC_REGS_TO_CONFIG); /*-------------------------------------------------------------------------- * Configure DDR PHY. */ p_cfg = &p_ddr_subsys_cfg->phy.LOOPBACK_TEST_CR; p_regs = &p_ddr_subsys_regs->phy.LOOPBACK_TEST_CR; copy_cfg16_to_regs(p_regs, p_cfg, NB_OF_DDR_PHY_REGS_TO_CONFIG); /*-------------------------------------------------------------------------- * Configure DDR FIC. */ p_ddr_subsys_regs->fic.NB_ADDR_CR = p_ddr_subsys_cfg->fic.NB_ADDR_CR; p_ddr_subsys_regs->fic.NBRWB_SIZE_CR = p_ddr_subsys_cfg->fic.NBRWB_SIZE_CR; p_ddr_subsys_regs->fic.WB_TIMEOUT_CR = p_ddr_subsys_cfg->fic.WB_TIMEOUT_CR; p_ddr_subsys_regs->fic.HPD_SW_RW_EN_CR = p_ddr_subsys_cfg->fic.HPD_SW_RW_EN_CR; p_ddr_subsys_regs->fic.HPD_SW_RW_INVAL_CR = p_ddr_subsys_cfg->fic.HPD_SW_RW_INVAL_CR; p_ddr_subsys_regs->fic.SW_WR_ERCLR_CR = p_ddr_subsys_cfg->fic.SW_WR_ERCLR_CR; p_ddr_subsys_regs->fic.ERR_INT_ENABLE_CR = p_ddr_subsys_cfg->fic.ERR_INT_ENABLE_CR; p_ddr_subsys_regs->fic.NUM_AHB_MASTERS_CR = p_ddr_subsys_cfg->fic.NUM_AHB_MASTERS_CR; p_ddr_subsys_regs->fic.LOCK_TIMEOUTVAL_CR[0] = p_ddr_subsys_cfg->fic.LOCK_TIMEOUTVAL_1_CR; p_ddr_subsys_regs->fic.LOCK_TIMEOUTVAL_CR[1] = p_ddr_subsys_cfg->fic.LOCK_TIMEOUTVAL_2_CR; p_ddr_subsys_regs->fic.LOCK_TIMEOUT_EN_CR = p_ddr_subsys_cfg->fic.LOCK_TIMEOUT_EN_CR; /*-------------------------------------------------------------------------- * Enable DDR. */ p_ddr_subsys_regs->ddrc.DYN_SOFT_RESET_CR = 0x01u; while(0x0000u == p_ddr_subsys_regs->ddrc.DDRC_SR) { ; } } #endif /***************************************************************************//** * Configure SERDES interfaces. */ #if MSS_SYS_SERDES_CONFIG_BY_CORTEX static void configure_serdes_intf(void) { #if MSS_SYS_SERDES_0_CONFIG_BY_CORTEX config_by_addr_value(g_m2s_serdes_0_config, SERDES_0_CFG_NB_OF_PAIRS); #endif #if MSS_SYS_SERDES_1_CONFIG_BY_CORTEX config_by_addr_value(g_m2s_serdes_1_config, SERDES_1_CFG_NB_OF_PAIRS); #endif #if MSS_SYS_SERDES_2_CONFIG_BY_CORTEX config_by_addr_value(g_m2s_serdes_2_config, SERDES_2_CFG_NB_OF_PAIRS); #endif #if MSS_SYS_SERDES_3_CONFIG_BY_CORTEX config_by_addr_value(g_m2s_serdes_3_config, SERDES_3_CFG_NB_OF_PAIRS); #endif } /***************************************************************************//** * Configure PCIe interfaces. */ static void configure_pcie_intf(void) { #if MSS_SYS_SERDES_0_CONFIG_BY_CORTEX configure_pcie_block(g_m2s_serdes_0_config, SERDES_0_CFG_NB_OF_PAIRS, 0u); #endif #if MSS_SYS_SERDES_1_CONFIG_BY_CORTEX configure_pcie_block(g_m2s_serdes_1_config, SERDES_1_CFG_NB_OF_PAIRS, 1u); #endif #if MSS_SYS_SERDES_2_CONFIG_BY_CORTEX configure_pcie_block(g_m2s_serdes_2_config, SERDES_2_CFG_NB_OF_PAIRS, 2u); #endif #if MSS_SYS_SERDES_3_CONFIG_BY_CORTEX configure_pcie_block(g_m2s_serdes_3_config, SERDES_3_CFG_NB_OF_PAIRS, 3u); #endif } /*------------------------------------------------------------------------------ Configure one individual PCIe block. */ static void configure_pcie_block ( const cfg_addr_value_pair_t * p_addr_value_pair, uint32_t nb_of_cfg_pairs, uint32_t serdes_id ) { uint32_t inc; const uint32_t PMA_READY_MASK = 0x00000080u; const uint32_t PCIE_CTRL_REG_LENGTH = 0x1000u; const uint32_t PCIE_CTLR_SOFTRESET_MASK = 0x00000001; const uint32_t PCIE2_CTLR_SOFTRESET_MASK = 0x00000040; SERDESIF_TypeDef * const serdes_lut[4] = { SERDES0, SERDES1, SERDES2, SERDES3 }; const uint32_t pcie_ctrl_top_addr_lut[4] = { SERDES0_CFG_BASE + PCIE_CTRL_REG_LENGTH, SERDES1_CFG_BASE + PCIE_CTRL_REG_LENGTH, SERDES2_CFG_BASE + PCIE_CTRL_REG_LENGTH, SERDES3_CFG_BASE + PCIE_CTRL_REG_LENGTH }; /* * Poll for PMA_READY. */ inc = 0U; while(g_pcie_lane_cfg_lut[serdes_id][inc].config_reg_lane_sel != 0) { uint32_t pma_ready; uint32_t config_phy_mode_1; /* select lane */ config_phy_mode_1 = g_pcie_lane_cfg_lut[serdes_id][inc].serdes->sys_regs.CONFIG_PHY_MODE_1; config_phy_mode_1 &= ~CONFIG_REG_LANE_SEL_MASK; config_phy_mode_1 |= (uint32_t)g_pcie_lane_cfg_lut[serdes_id][inc].config_reg_lane_sel; g_pcie_lane_cfg_lut[serdes_id][inc].serdes->sys_regs.CONFIG_PHY_MODE_1 = config_phy_mode_1; /* Wait for PMA to become ready. */ do { pma_ready = g_pcie_lane_cfg_lut[serdes_id][inc].lane->PMA_STATUS & PMA_READY_MASK; } while (0u == pma_ready); ++inc; } /* * Configure the PCIe controller registers. */ for(inc = 0u; inc < nb_of_cfg_pairs; ++inc) { uint32_t reg_addr; reg_addr = (uint32_t)p_addr_value_pair[inc].p_reg; if(reg_addr < pcie_ctrl_top_addr_lut[serdes_id]) { *p_addr_value_pair[inc].p_reg = p_addr_value_pair[inc].value; } } /* * Issue a soft-reset to the PCIe controller */ inc = 0U; while(g_pcie_lane_cfg_lut[serdes_id][inc].config_reg_lane_sel != 0) { if(FIRST_PCIE_CTRL == g_pcie_lane_cfg_lut[serdes_id][inc].pcie_ctrl_id) { serdes_lut[serdes_id]->sys_regs.SERDESIF_SOFT_RESET &= ~PCIE_CTLR_SOFTRESET_MASK; serdes_lut[serdes_id]->sys_regs.SERDESIF_SOFT_RESET |= PCIE_CTLR_SOFTRESET_MASK; } else { serdes_lut[serdes_id]->sys_regs.SERDESIF_SOFT_RESET &= ~PCIE2_CTLR_SOFTRESET_MASK; serdes_lut[serdes_id]->sys_regs.SERDESIF_SOFT_RESET |= PCIE2_CTLR_SOFTRESET_MASK; } ++inc; } } #endif /*------------------------------------------------------------------------------ Retrieve silicon revision from system registers. */ static uint32_t get_silicon_revision(void) { uint32_t silicon_revision; uint32_t device_version; device_version = SYSREG->DEVICE_VERSION; switch(device_version) { case 0x0000F802: silicon_revision = M2S050_REV_A_SILICON; break; case 0x0001F802: silicon_revision = M2S050_REV_B_SILICON; break; default: silicon_revision = UNKNOWN_SILICON_REV; break; } return silicon_revision; } /*------------------------------------------------------------------------------ Workarounds for various silicon versions. */ static void silicon_workarounds(void) { uint32_t silicon_revision; silicon_revision = get_silicon_revision(); switch(silicon_revision) { case M2S050_REV_A_SILICON: m2s050_rev_a_workarounds(); break; case M2S050_REV_B_SILICON: /* Fall through. */ case UNKNOWN_SILICON_REV: /* Fall through. */ default: break; } } /*------------------------------------------------------------------------------ Silicon workarounds for M2S050 rev A. */ static void m2s050_rev_a_workarounds(void) { /*-------------------------------------------------------------------------- * Work around a couple of silicon issues: */ /* DDR_CLK_EN <- 1 */ SYSREG->MSSDDR_FACC1_CR |= (uint32_t)1 << DDR_CLK_EN_SHIFT; /* CONTROLLER_PLL_INIT <- 0 */ SYSREG->MSSDDR_FACC1_CR = SYSREG->MSSDDR_FACC1_CR & ~CONTROLLER_PLL_INIT_MASK; } /*------------------------------------------------------------------------------ Complete clock configuration if requested by Libero. */ #if (MSS_SYS_FACC_INIT_BY_CORTEX == 1) static void complete_clock_config(void) { uint32_t pll_locked; /* Wait for fabric PLL to lock. */ do { pll_locked = SYSREG->MSSDDR_PLL_STATUS & FAB_PLL_LOCK_MASK; } while(!pll_locked); /* Negate MPLL bypass. */ SYSREG->MSSDDR_PLL_STATUS_HIGH_CR &= ~FACC_PLL_BYPASS_MASK; /* Wait for MPLL to lock. */ do { pll_locked = SYSREG->MSSDDR_PLL_STATUS & MPLL_LOCK_MASK; } while(!pll_locked); /* Switch FACC from standby to run mode. */ SYSREG->MSSDDR_FACC1_CR &= ~FACC_GLMUX_SEL_MASK; /* Negate FPGA_SOFTRESET to de-assert MSS_RESET_N_M2F in the fabric */ SYSREG->SOFT_RST_CR &= ~SYSREG_FPGA_SOFTRESET_MASK; } #endif