aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/hal/ports/SPC5/SPC56ECxx/hal_lld.c
diff options
context:
space:
mode:
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.c291
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
37typedef 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 */
46static 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 */
64void 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 */
98void 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 */
228bool 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 */
255void 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 */
270uint32_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/** @} */