1 /*******************************************************************************
\r
2 * (c) Copyright 2009 Actel Corporation. All rights reserved.
\r
4 * SmartFusion A2FxxxM3 CMSIS system initialization.
\r
6 * SVN $Revision: 2069 $
\r
7 * SVN $Date: 2010-01-28 00:23:48 +0000 (Thu, 28 Jan 2010) $
\r
9 #include "a2fxxxm3.h"
\r
10 #include "mss_assert.h"
\r
12 /* System frequency (FCLK) coming out of reset is 25MHz. */
\r
13 #define RESET_SYSCLCK_FREQ 25000000uL
\r
16 * SmartFusion Microcontroller Subsystem FLCK frequency.
\r
17 * The value of SMARTFUSION_FCLK_FREQ is used to report the system's clock
\r
18 * frequency in system's which either do not use the Actel System Boot or
\r
19 * a version of the Actel System Boot older than 1.3.1. In eitehr of these cases
\r
20 * SMARTFUSION_FCLK_FREQ should be defined in the projects settings to reflect
\r
21 * the FCLK frequency selected in the Libero MSS configurator.
\r
22 * Systems using the Actel System Boot version 1.3.1 or later do not require this
\r
23 * define since the system's frequency is retrieved from eNVM spare pages where
\r
24 * the MSS Configurator stored the frequency selected during hardware design/configuration.
\r
26 #ifdef SMARTFUSION_FCLK_FREQ
\r
27 #define SMARTFUSION_FCLK_FREQ_DEFINED 1
\r
29 #define SMARTFUSION_FCLK_FREQ_DEFINED 0
\r
30 #define SMARTFUSION_FCLK_FREQ RESET_SYSCLCK_FREQ
\r
33 /* Divider values for APB0, APB1 and ACE clocks. */
\r
34 #define RESET_PCLK0_DIV 4uL
\r
35 #define RESET_PCLK1_DIV 4uL
\r
36 #define RESET_ACE_DIV 4uL
\r
37 #define RESET_FPGA_CLK_DIV 4uL
\r
39 /* System register clock control mask and shift for PCLK dividers. */
\r
40 #define PCLK_DIV_MASK 0x00000003uL
\r
41 #define PCLK0_DIV_SHIFT 2uL
\r
42 #define PCLK1_DIV_SHIFT 4uL
\r
43 #define ACE_DIV_SHIFT 6uL
\r
45 /* System register MSS_CCC_DIV_CR mask and shift for GLB (FPGA fabric clock). */
\r
46 #define OBDIV_SHIFT 8uL
\r
47 #define OBDIV_MASK 0x0000001FuL
\r
48 #define OBDIVHALF_SHIFT 13uL
\r
49 #define OBDIVHALF_MASK 0x00000001uL
\r
52 * Actel system boot version defines used to extract the system clock from eNVM
\r
54 * These defines allow detecting the presence of Actel system boot in eNVM spare
\r
55 * pages and the version of that system boot executable and associated
\r
56 * configuration data.
\r
58 #define SYSBOOT_KEY_ADDR (uint32_t *)0x6008081C
\r
59 #define SYSBOOT_KEY_VALUE 0x4C544341uL
\r
60 #define SYSBOOT_VERSION_ADDR (uint32_t *)0x60080840
\r
61 #define SYSBOOT_1_3_FCLK_ADDR (uint32_t *)0x6008162C
\r
62 #define SYSBOOT_2_x_FCLK_ADDR (uint32_t *)0x60081EAC
\r
65 * The system boot version is stored in the least significant 24 bits of a word.
\r
66 * The FCLK is stored in eNVM from version 1.3.1 of the system boot. We expect
\r
67 * that the major version number of the system boot version will change if the
\r
68 * system boot configuration data layout needs to change.
\r
70 #define SYSBOOT_VERSION_MASK 0x00FFFFFFuL
\r
71 #define MIN_SYSBOOT_VERSION 0x00010301uL
\r
72 #define SYSBOOT_VERSION_2_X 0x00020000uL
\r
73 #define MAX_SYSBOOT_VERSION 0x00030000uL
\r
75 /* Standard CMSIS global variables. */
\r
76 uint32_t SystemFrequency = SMARTFUSION_FCLK_FREQ; /*!< System Clock Frequency (Core Clock) */
\r
77 uint32_t SystemCoreClock = SMARTFUSION_FCLK_FREQ; /*!< System Clock Frequency (Core Clock) */
\r
79 /* SmartFusion specific clocks. */
\r
80 uint32_t g_FrequencyPCLK0 = (SMARTFUSION_FCLK_FREQ / RESET_PCLK0_DIV); /*!< Clock frequency of APB bus 0. */
\r
81 uint32_t g_FrequencyPCLK1 = (SMARTFUSION_FCLK_FREQ / RESET_PCLK1_DIV); /*!< Clock frequency of APB bus 1. */
\r
82 uint32_t g_FrequencyACE = (SMARTFUSION_FCLK_FREQ / RESET_ACE_DIV); /*!< Clock frequency of Analog Compute Engine. */
\r
83 uint32_t g_FrequencyFPGA = (SMARTFUSION_FCLK_FREQ / RESET_FPGA_CLK_DIV); /*!< Clock frequecny of FPGA fabric */
\r
85 /* Local functions */
\r
86 static uint32_t GetSystemClock( void );
\r
88 /***************************************************************************//**
\r
89 * See system_a2fm3fxxx.h for details.
\r
91 void SystemInit(void)
\r
95 /***************************************************************************//**
\r
98 void SystemCoreClockUpdate (void)
\r
105 const uint32_t pclk_div_lut[4] = { 1uL, 2uL, 4uL, 1uL };
\r
107 /* Read PCLK dividers from system registers. Multiply the value read from
\r
108 * system register by two to get actual divider value. */
\r
109 PclkDiv0 = pclk_div_lut[((SYSREG->MSS_CLK_CR >> PCLK0_DIV_SHIFT) & PCLK_DIV_MASK)];
\r
110 PclkDiv1 = pclk_div_lut[((SYSREG->MSS_CLK_CR >> PCLK1_DIV_SHIFT) & PCLK_DIV_MASK)];
\r
111 AceDiv = pclk_div_lut[((SYSREG->MSS_CLK_CR >> ACE_DIV_SHIFT) & PCLK_DIV_MASK)];
\r
113 /* Compute the FPGA fabric frequency divider. */
\r
115 uint32_t obdivhalf;
\r
117 obdiv = (SYSREG->MSS_CCC_DIV_CR >> OBDIV_SHIFT) & OBDIV_MASK;
\r
118 obdivhalf = (SYSREG->MSS_CCC_DIV_CR >> OBDIVHALF_SHIFT) & OBDIVHALF_MASK;
\r
119 FabDiv = obdiv + 1uL;
\r
120 if ( obdivhalf != 0uL )
\r
122 FabDiv = FabDiv * 2uL;
\r
126 /* Retrieve FCLK from eNVM spare pages if Actel system boot programmed as part of the system. */
\r
128 /* Read system clock from eNVM spare pages. */
\r
129 SystemCoreClock = GetSystemClock();
\r
130 g_FrequencyPCLK0 = SystemCoreClock / PclkDiv0;
\r
131 g_FrequencyPCLK1 = SystemCoreClock / PclkDiv1;
\r
132 g_FrequencyACE = SystemCoreClock / AceDiv;
\r
133 g_FrequencyFPGA = SystemCoreClock / FabDiv;
\r
135 /* Keep SystemFrequency as well as SystemCoreClock for legacy reasons. */
\r
136 SystemFrequency = SystemCoreClock;
\r
139 /***************************************************************************//**
\r
140 * Retrieve the system clock frequency from eNVM spare page if available.
\r
141 * Returns the frequency defined through SMARTFUSION_FCLK_FREQ if FCLK cannot be
\r
142 * retrieved from eNVM spare pages.
\r
143 * The FCLK frequency value selected in the MSS Configurator software tool is
\r
144 * stored in eNVM spare pages as part of the Actel system boot configuration data.
\r
146 uint32_t GetSystemClock( void )
\r
148 uint32_t fclk = 0uL;
\r
150 uint32_t * p_sysboot_key = SYSBOOT_KEY_ADDR;
\r
152 if ( SYSBOOT_KEY_VALUE == *p_sysboot_key )
\r
154 /* Actel system boot programmed, check if it has the FCLK value stored. */
\r
155 uint32_t *p_sysboot_version = SYSBOOT_VERSION_ADDR;
\r
156 uint32_t sysboot_version = *p_sysboot_version;
\r
158 sysboot_version &= SYSBOOT_VERSION_MASK;
\r
160 if ( sysboot_version >= MIN_SYSBOOT_VERSION )
\r
162 /* Handle change of eNVM location of FCLK between 1.3.x and 2.x.x versions of the system boot. */
\r
163 if ( sysboot_version < SYSBOOT_VERSION_2_X )
\r
165 /* Read FCLK value from MSS configurator generated configuration
\r
166 * data stored in eNVM spare pages as part of system boot version 1.3.x
\r
167 * configuration tables. */
\r
168 uint32_t *p_fclk = SYSBOOT_1_3_FCLK_ADDR;
\r
171 else if ( sysboot_version < MAX_SYSBOOT_VERSION )
\r
173 /* Read FCLK value from MSS configurator generated configuration
\r
174 * data stored in eNVM spare pages as part of system boot version 2.x.x
\r
175 * configuration tables. */
\r
176 uint32_t *p_fclk = SYSBOOT_2_x_FCLK_ADDR;
\r
189 * Could not retrieve FCLK from system boot configuration data. Fall back
\r
190 * to using SMARTFUSION_FCLK_FREQ which must then be defined as part of
\r
191 * project settings.
\r
193 ASSERT( SMARTFUSION_FCLK_FREQ_DEFINED );
\r
194 fclk = SMARTFUSION_FCLK_FREQ;
\r