diff options
Diffstat (limited to 'lib/chibios/os/hal/ports/SPC5/SPC56ECxx/hal_lld.c')
-rw-r--r-- | lib/chibios/os/hal/ports/SPC5/SPC56ECxx/hal_lld.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/lib/chibios/os/hal/ports/SPC5/SPC56ECxx/hal_lld.c b/lib/chibios/os/hal/ports/SPC5/SPC56ECxx/hal_lld.c new file mode 100644 index 000000000..07956081e --- /dev/null +++ b/lib/chibios/os/hal/ports/SPC5/SPC56ECxx/hal_lld.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /* | ||
2 | SPC5 HAL - Copyright (C) 2013 STMicroelectronics | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * @file SPC56ECxx/hal_lld.c | ||
19 | * @brief SPC56ECxx HAL subsystem low level driver source. | ||
20 | * | ||
21 | * @addtogroup HAL | ||
22 | * @{ | ||
23 | */ | ||
24 | |||
25 | #include <string.h> | ||
26 | |||
27 | #include "hal.h" | ||
28 | |||
29 | /*===========================================================================*/ | ||
30 | /* Driver exported variables. */ | ||
31 | /*===========================================================================*/ | ||
32 | |||
33 | /*===========================================================================*/ | ||
34 | /* Driver local variables and types. */ | ||
35 | /*===========================================================================*/ | ||
36 | |||
37 | typedef void (*storefunc_t)(volatile uint32_t *p, uint32_t w); | ||
38 | |||
39 | /*===========================================================================*/ | ||
40 | /* Driver local functions. */ | ||
41 | /*===========================================================================*/ | ||
42 | |||
43 | /* | ||
44 | * Special function to be copied in RAM. | ||
45 | */ | ||
46 | static void do_word_store(volatile uint32_t *p, uint32_t w) { | ||
47 | |||
48 | *p = w; | ||
49 | } | ||
50 | |||
51 | /*===========================================================================*/ | ||
52 | /* Driver interrupt handlers. */ | ||
53 | /*===========================================================================*/ | ||
54 | |||
55 | /*===========================================================================*/ | ||
56 | /* Driver exported functions. */ | ||
57 | /*===========================================================================*/ | ||
58 | |||
59 | /** | ||
60 | * @brief Low level HAL driver initialization. | ||
61 | * | ||
62 | * @notapi | ||
63 | */ | ||
64 | void hal_lld_init(void) { | ||
65 | uint32_t n; | ||
66 | |||
67 | /* The system is switched to the RUN0 mode, the default for normal | ||
68 | operations.*/ | ||
69 | if (halSPCSetRunMode(SPC5_RUNMODE_RUN0) == OSAL_FAILED) { | ||
70 | SPC5_CLOCK_FAILURE_HOOK(); | ||
71 | } | ||
72 | |||
73 | /* Decrementer timer initialized for system tick use, note, it is | ||
74 | initialized here because in the OSAL layer the system clock frequency | ||
75 | is not yet known.*/ | ||
76 | n = halSPCGetSystemClock() / OSAL_ST_FREQUENCY; | ||
77 | port_write_spr(22, n); /* Init. DEC register. */ | ||
78 | port_write_spr(54, n); /* Init. DECAR register.*/ | ||
79 | n = 0x04400000; /* DIE ARE bits. */ | ||
80 | port_write_spr(340, n); /* TCR register. */ | ||
81 | |||
82 | /* TB counter enabled for debug and measurements.*/ | ||
83 | n = 0x4000; /* TBEN bit. */ | ||
84 | port_write_spr(1008, n); /* HID0 register. */ | ||
85 | |||
86 | /* EDMA initialization.*/ | ||
87 | edmaInit(); | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * @brief SPC56ECxx clocks and PLL initialization. | ||
92 | * @note All the involved constants come from the file @p board.h and | ||
93 | * @p hal_lld.h | ||
94 | * @note This function must be invoked only after the system reset. | ||
95 | * | ||
96 | * @special | ||
97 | */ | ||
98 | void spc_clock_init(void) { | ||
99 | #if !SPC5_NO_INIT | ||
100 | uint32_t reg; | ||
101 | uint32_t store_word[8]; | ||
102 | #endif | ||
103 | |||
104 | /* Waiting for IRC stabilization before attempting anything else.*/ | ||
105 | while (!ME.GS.B.S_FIRC) | ||
106 | ; | ||
107 | |||
108 | #if !SPC5_NO_INIT | ||
109 | /* Copies the store function in RAM, this is required in order to perform | ||
110 | some flash-related operations.*/ | ||
111 | memcpy(store_word, do_word_store, sizeof(store_word)); | ||
112 | |||
113 | #if SPC5_DISABLE_WATCHDOG | ||
114 | /* SWT disabled.*/ | ||
115 | SWT.SR.R = 0xC520; | ||
116 | SWT.SR.R = 0xD928; | ||
117 | SWT.CR.R = 0xFF00000A; | ||
118 | #endif | ||
119 | |||
120 | /* SSCM initialization. Setting up the most restrictive handling of | ||
121 | invalid accesses to peripherals.*/ | ||
122 | SSCM.ERROR.R = 3; /* PAE and RAE bits. */ | ||
123 | |||
124 | /* RGM errors clearing.*/ | ||
125 | RGM.FES.R = 0xFFFF; | ||
126 | RGM.DES.R = 0xFFFF; | ||
127 | |||
128 | /* Oscillators dividers setup.*/ | ||
129 | CGM.FIRC_CTL.B.RCDIV = SPC5_IRCDIV_VALUE - 1; | ||
130 | CGM.FXOSC_CTL.B.OSCDIV = SPC5_XOSCDIV_VALUE - 1; | ||
131 | |||
132 | /* The system must be in DRUN mode on entry, if this is not the case then | ||
133 | it is considered a serious anomaly.*/ | ||
134 | if (ME.GS.B.S_CURRENTMODE != SPC5_RUNMODE_DRUN) { | ||
135 | SPC5_CLOCK_FAILURE_HOOK(); | ||
136 | } | ||
137 | |||
138 | #if defined(SPC5_OSC_BYPASS) | ||
139 | /* If the board is equipped with an oscillator instead of a xtal then the | ||
140 | bypass must be activated.*/ | ||
141 | CGM.OSC_CTL.B.OSCBYP = TRUE; | ||
142 | #endif /* SPC5_OSC_BYPASS */ | ||
143 | |||
144 | /* Setting the various dividers and source selectors.*/ | ||
145 | CGM.SC_DC0.R = SPC5_CGM_SC_DC0; | ||
146 | CGM.SC_DC1.R = SPC5_CGM_SC_DC1; | ||
147 | CGM.SC_DC2.R = SPC5_CGM_SC_DC2; | ||
148 | CGM.Z0_DCR.R = SPC5_CGM_Z0_DCR; | ||
149 | CGM.FEC_DCR.R = SPC5_CGM_FEC_DCR; | ||
150 | CGM.FLASH_DCR.R = SPC5_CGM_FLASH_DCR; | ||
151 | |||
152 | /* Selecting the external oscillator as source for the FMPLL, note that on | ||
153 | older silicons, the settings are exchanged, a macro switch is provided.*/ | ||
154 | #if SPC56ECXX_FMPLL_CLOCK_ERRATA_WORKAROUND == TRUE | ||
155 | CGM.AC0_SC.R = 0x01000000; | ||
156 | #else | ||
157 | CGM.AC0_SC.R = 0x00000000; /* TODO: Add a setting. */ | ||
158 | #endif | ||
159 | |||
160 | /* Initialization of the FMPLLs settings.*/ | ||
161 | CGM.FMPLL_CR.R = SPC5_FMPLL0_ODF | | ||
162 | ((SPC5_FMPLL0_IDF_VALUE - 1) << 26) | | ||
163 | (SPC5_FMPLL0_NDIV_VALUE << 16); | ||
164 | CGM.FMPLL_MR.R = 0; /* TODO: Add a setting. */ | ||
165 | |||
166 | /* Run modes initialization.*/ | ||
167 | ME.IS.R = 8; /* Resetting I_ICONF status.*/ | ||
168 | ME.MER.R = SPC5_ME_ME_BITS; /* Enabled run modes. */ | ||
169 | ME.TEST.R = SPC5_ME_TEST_MC_BITS; /* TEST run mode. */ | ||
170 | ME.SAFE.R = SPC5_ME_SAFE_MC_BITS; /* SAFE run mode. */ | ||
171 | ME.DRUN.R = SPC5_ME_DRUN_MC_BITS; /* DRUN run mode. */ | ||
172 | ME.RUN[0].R = SPC5_ME_RUN0_MC_BITS; /* RUN0 run mode. */ | ||
173 | ME.RUN[1].R = SPC5_ME_RUN1_MC_BITS; /* RUN1 run mode. */ | ||
174 | ME.RUN[2].R = SPC5_ME_RUN2_MC_BITS; /* RUN2 run mode. */ | ||
175 | ME.RUN[3].R = SPC5_ME_RUN3_MC_BITS; /* RUN0 run mode. */ | ||
176 | ME.HALT.R = SPC5_ME_HALT0_MC_BITS; /* HALT0 run mode. */ | ||
177 | ME.STOP.R = SPC5_ME_STOP0_MC_BITS; /* STOP0 run mode. */ | ||
178 | ME.STANDBY.R = SPC5_ME_STANDBY0_MC_BITS; /* STANDBY0 run mode. */ | ||
179 | if (ME.IS.B.I_ICONF) { | ||
180 | /* Configuration rejected.*/ | ||
181 | SPC5_CLOCK_FAILURE_HOOK(); | ||
182 | } | ||
183 | |||
184 | /* Peripherals run and low power modes initialization.*/ | ||
185 | ME.RUNPC[0].R = SPC5_ME_RUN_PC0_BITS; | ||
186 | ME.RUNPC[1].R = SPC5_ME_RUN_PC1_BITS; | ||
187 | ME.RUNPC[2].R = SPC5_ME_RUN_PC2_BITS; | ||
188 | ME.RUNPC[3].R = SPC5_ME_RUN_PC3_BITS; | ||
189 | ME.RUNPC[4].R = SPC5_ME_RUN_PC4_BITS; | ||
190 | ME.RUNPC[5].R = SPC5_ME_RUN_PC5_BITS; | ||
191 | ME.RUNPC[6].R = SPC5_ME_RUN_PC6_BITS; | ||
192 | ME.RUNPC[7].R = SPC5_ME_RUN_PC7_BITS; | ||
193 | ME.LPPC[0].R = SPC5_ME_LP_PC0_BITS; | ||
194 | ME.LPPC[1].R = SPC5_ME_LP_PC1_BITS; | ||
195 | ME.LPPC[2].R = SPC5_ME_LP_PC2_BITS; | ||
196 | ME.LPPC[3].R = SPC5_ME_LP_PC3_BITS; | ||
197 | ME.LPPC[4].R = SPC5_ME_LP_PC4_BITS; | ||
198 | ME.LPPC[5].R = SPC5_ME_LP_PC5_BITS; | ||
199 | ME.LPPC[6].R = SPC5_ME_LP_PC6_BITS; | ||
200 | ME.LPPC[7].R = SPC5_ME_LP_PC7_BITS; | ||
201 | |||
202 | /* CFLASH settings calculated for a maximum clock of 120MHz.*/ | ||
203 | reg = (CFLASH_0.PFCR0.R & 0x073EFFFF) | 0x280A0000; | ||
204 | ((storefunc_t)store_word)(&CFLASH_0.PFCR0.R, reg); | ||
205 | reg = (CFLASH_0.PFCR1.R & 0x073EFFFF) | 0x681A0000; | ||
206 | ((storefunc_t)store_word)(&CFLASH_0.PFCR1.R, reg); | ||
207 | |||
208 | /* SRAM settings, 1 wait state.*/ | ||
209 | ECSM.MUDCR.B.RAM_WS = 1; | ||
210 | |||
211 | /* Switches again to DRUN mode (current mode) in order to update the | ||
212 | settings.*/ | ||
213 | if (halSPCSetRunMode(SPC5_RUNMODE_DRUN) == OSAL_FAILED) { | ||
214 | SPC5_CLOCK_FAILURE_HOOK(); | ||
215 | } | ||
216 | #endif /* !SPC5_NO_INIT */ | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * @brief Switches the system to the specified run mode. | ||
221 | * | ||
222 | * @param[in] mode one of the possible run modes | ||
223 | * | ||
224 | * @return The operation status. | ||
225 | * @retval OSAL_SUCCESS if the switch operation has been completed. | ||
226 | * @retval OSAL_FAILED if the switch operation failed. | ||
227 | */ | ||
228 | bool halSPCSetRunMode(spc5_runmode_t mode) { | ||
229 | |||
230 | /* Clearing status register bits I_IMODE(4) and I_IMTC(1).*/ | ||
231 | ME.IS.R = 5; | ||
232 | |||
233 | /* Starts a transition process.*/ | ||
234 | ME.MCTL.R = SPC5_ME_MCTL_MODE(mode) | SPC5_ME_MCTL_KEY; | ||
235 | ME.MCTL.R = SPC5_ME_MCTL_MODE(mode) | SPC5_ME_MCTL_KEY_INV; | ||
236 | |||
237 | /* Waits for the mode switch or an error condition.*/ | ||
238 | while (TRUE) { | ||
239 | uint32_t r = ME.IS.R; | ||
240 | if (r & 1) | ||
241 | return OSAL_SUCCESS; | ||
242 | if (r & 4) | ||
243 | return OSAL_FAILED; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * @brief Changes the clock mode of a peripheral. | ||
249 | * | ||
250 | * @param[in] n index of the @p PCTL register | ||
251 | * @param[in] pctl new value for the @p PCTL register | ||
252 | * | ||
253 | * @notapi | ||
254 | */ | ||
255 | void halSPCSetPeripheralClockMode(uint32_t n, uint32_t pctl) { | ||
256 | uint32_t mode; | ||
257 | |||
258 | ME.PCTL[n].R = pctl; | ||
259 | mode = ME.MCTL.B.TARGET_MODE; | ||
260 | ME.MCTL.R = SPC5_ME_MCTL_MODE(mode) | SPC5_ME_MCTL_KEY; | ||
261 | ME.MCTL.R = SPC5_ME_MCTL_MODE(mode) | SPC5_ME_MCTL_KEY_INV; | ||
262 | } | ||
263 | |||
264 | #if !SPC5_NO_INIT || defined(__DOXYGEN__) | ||
265 | /** | ||
266 | * @brief Returns the system clock under the current run mode. | ||
267 | * | ||
268 | * @return The system clock in Hertz. | ||
269 | */ | ||
270 | uint32_t halSPCGetSystemClock(void) { | ||
271 | uint32_t sysclk; | ||
272 | |||
273 | sysclk = ME.GS.B.S_SYSCLK; | ||
274 | switch (sysclk) { | ||
275 | case SPC5_ME_GS_SYSCLK_IRC: | ||
276 | return SPC5_IRC_CLK; | ||
277 | case SPC5_ME_GS_SYSCLK_DIVIRC: | ||
278 | return SPC5_IRC_CLK / SPC5_IRCDIV_VALUE; | ||
279 | case SPC5_ME_GS_SYSCLK_XOSC: | ||
280 | return SPC5_XOSC_CLK / SPC5_XOSCDIV_VALUE; | ||
281 | case SPC5_ME_GS_SYSCLK_DIVXOSC: | ||
282 | return SPC5_XOSC_CLK; | ||
283 | case SPC5_ME_GS_SYSCLK_FMPLL0: | ||
284 | return SPC5_FMPLL0_CLK; | ||
285 | default: | ||
286 | return 0; | ||
287 | } | ||
288 | } | ||
289 | #endif /* !SPC5_NO_INIT */ | ||
290 | |||
291 | /** @} */ | ||