aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/hal/ports/STM32/STM32G0xx/hal_efl_lld.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios/os/hal/ports/STM32/STM32G0xx/hal_efl_lld.c')
-rw-r--r--lib/chibios/os/hal/ports/STM32/STM32G0xx/hal_efl_lld.c608
1 files changed, 608 insertions, 0 deletions
diff --git a/lib/chibios/os/hal/ports/STM32/STM32G0xx/hal_efl_lld.c b/lib/chibios/os/hal/ports/STM32/STM32G0xx/hal_efl_lld.c
new file mode 100644
index 000000000..22784ecc8
--- /dev/null
+++ b/lib/chibios/os/hal/ports/STM32/STM32G0xx/hal_efl_lld.c
@@ -0,0 +1,608 @@
1/*
2 ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio
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 hal_efl_lld.c
19 * @brief STM32G07/8nxx Embedded Flash subsystem low level driver source.
20 *
21 * @addtogroup HAL_EFL
22 * @{
23 */
24
25#include <string.h>
26
27#include "hal.h"
28
29#if (HAL_USE_EFL == TRUE) || defined(__DOXYGEN__)
30
31/*===========================================================================*/
32/* Driver local definitions. */
33/*===========================================================================*/
34
35#define STM32_FLASH_LINE_SIZE 8U
36#define STM32_FLASH_LINE_MASK (STM32_FLASH_LINE_SIZE - 1U)
37
38#define FLASH_PDKEY1 0x04152637U
39#define FLASH_PDKEY2 0xFAFBFCFDU
40
41#define FLASH_KEY1 0x45670123U
42#define FLASH_KEY2 0xCDEF89ABU
43
44#define FLASH_OPTKEY1 0x08192A3BU
45#define FLASH_OPTKEY2 0x4C5D6E7FU
46
47/*===========================================================================*/
48/* Driver exported variables. */
49/*===========================================================================*/
50
51/**
52 * @brief EFL1 driver identifier.
53 */
54EFlashDriver EFLD1;
55
56/*===========================================================================*/
57/* Driver local variables and types. */
58/*===========================================================================*/
59
60/* The descriptor for 64K devices. */
61static const flash_descriptor_t efl_lld_size1[STM32_FLASH_NUMBER_OF_BANKS] = {
62 { /* Bank 1. */
63 .attributes = FLASH_ATTR_ERASED_IS_ONE |
64 FLASH_ATTR_MEMORY_MAPPED |
65 FLASH_ATTR_ECC_CAPABLE |
66 FLASH_ATTR_ECC_ZERO_LINE_CAPABLE,
67 .page_size = STM32_FLASH_LINE_SIZE,
68 .sectors_count = STM32_FLASH_SECTORS_TOTAL_64K,
69 .sectors = NULL,
70 .sectors_size = STM32_FLASH_SECTOR_SIZE_64K,
71 .address = (uint8_t *)FLASH_BASE,
72 .size = STM32_FLASH_SIZE_64K * STM32_FLASH_SIZE_SCALE
73 }
74};
75
76/* The descriptor for 128K devices. */
77static const flash_descriptor_t efl_lld_size2[STM32_FLASH_NUMBER_OF_BANKS] = {
78 { /* Bank 1. */
79 .attributes = FLASH_ATTR_ERASED_IS_ONE |
80 FLASH_ATTR_MEMORY_MAPPED |
81 FLASH_ATTR_ECC_CAPABLE |
82 FLASH_ATTR_ECC_ZERO_LINE_CAPABLE,
83 .page_size = STM32_FLASH_LINE_SIZE,
84 .sectors_count = STM32_FLASH_SECTORS_TOTAL_128K,
85 .sectors = NULL,
86 .sectors_size = STM32_FLASH_SECTOR_SIZE_128K,
87 .address = (uint8_t *)FLASH_BASE,
88 .size = STM32_FLASH_SIZE_128K * STM32_FLASH_SIZE_SCALE
89 }
90};
91
92/* Table describing possible flash sizes and descriptors for this device. */
93static const efl_lld_size_t efl_lld_flash_sizes[] = {
94 {
95 .desc = efl_lld_size1
96 },
97 {
98 .desc = efl_lld_size2
99 }
100};
101
102/*===========================================================================*/
103/* Driver local functions. */
104/*===========================================================================*/
105
106static inline void stm32_flash_lock(EFlashDriver *eflp) {
107
108 eflp->flash->CR |= FLASH_CR_LOCK;
109}
110
111static inline void stm32_flash_unlock(EFlashDriver *eflp) {
112
113 eflp->flash->KEYR |= FLASH_KEY1;
114 eflp->flash->KEYR |= FLASH_KEY2;
115}
116
117static inline void stm32_flash_enable_pgm(EFlashDriver *eflp) {
118
119 eflp->flash->CR |= FLASH_CR_PG;
120}
121
122static inline void stm32_flash_disable_pgm(EFlashDriver *eflp) {
123
124 eflp->flash->CR &= ~FLASH_CR_PG;
125}
126
127static inline void stm32_flash_clear_status(EFlashDriver *eflp) {
128
129 eflp->flash->SR = 0x0000FFFFU;
130}
131
132static inline void stm32_flash_wait_busy(EFlashDriver *eflp) {
133
134 /* Wait for busy bit clear.*/
135 while ((eflp->flash->SR & FLASH_SR_BSY1) != 0U) {
136 }
137}
138
139static inline size_t stm32_flash_get_size(void) {
140 return *(uint16_t*)((uint32_t) STM32_FLASH_SIZE_REGISTER) * STM32_FLASH_SIZE_SCALE;
141}
142
143static inline bool stm32_flash_dual_bank(EFlashDriver *eflp) {
144
145#if STM32_FLASH_NUMBER_OF_BANKS > 1
146#error "Device settings incorrectly configured - single bank mode only supported"
147#endif
148 (void)eflp;
149 return false;
150}
151
152static inline flash_error_t stm32_flash_check_errors(EFlashDriver *eflp) {
153 uint32_t sr = eflp->flash->SR;
154
155 /* Clearing error conditions.*/
156 eflp->flash->SR = sr & 0x0000FFFFU;
157
158 /* Some errors are only caught by assertion.*/
159 osalDbgAssert((sr & (FLASH_SR_FASTERR |
160 FLASH_SR_MISERR |
161 FLASH_SR_SIZERR)) == 0U, "unexpected flash error");
162
163 /* Decoding relevant errors.*/
164 if ((sr & FLASH_SR_WRPERR) != 0U) {
165 return FLASH_ERROR_HW_FAILURE;
166 }
167
168 if ((sr & (FLASH_SR_PGAERR | FLASH_SR_PROGERR | FLASH_SR_OPERR)) != 0U) {
169 return eflp->state == FLASH_PGM ? FLASH_ERROR_PROGRAM : FLASH_ERROR_ERASE;
170 }
171
172 return FLASH_NO_ERROR;
173}
174
175/*===========================================================================*/
176/* Driver interrupt handlers. */
177/*===========================================================================*/
178
179/*===========================================================================*/
180/* Driver exported functions. */
181/*===========================================================================*/
182
183/**
184 * @brief Low level Embedded Flash driver initialization.
185 *
186 * @notapi
187 */
188void efl_lld_init(void) {
189
190 /* Driver initialization.*/
191 eflObjectInit(&EFLD1);
192 EFLD1.flash = FLASH;
193 /* Find the size of the flash and set descriptor reference. */
194 uint8_t i;
195 for (i = 0; i < (sizeof(efl_lld_flash_sizes) / sizeof(efl_lld_size_t)); i++) {
196 if (efl_lld_flash_sizes[i].desc->size == stm32_flash_get_size()) {
197 EFLD1.descriptor = efl_lld_flash_sizes[i].desc;
198 if (stm32_flash_dual_bank(&EFLD1)) {
199 /* Point to the dual bank descriptor. */
200 EFLD1.descriptor++;
201 }
202 return;
203 }
204 }
205 osalDbgAssert(false, "invalid flash configuration");
206}
207
208/**
209 * @brief Configures and activates the Embedded Flash peripheral.
210 *
211 * @param[in] eflp pointer to a @p EFlashDriver structure
212 *
213 * @notapi
214 */
215void efl_lld_start(EFlashDriver *eflp) {
216 stm32_flash_unlock(eflp);
217 FLASH->CR = 0x00000000U;
218}
219
220/**
221 * @brief Deactivates the Embedded Flash peripheral.
222 *
223 * @param[in] eflp pointer to a @p EFlashDriver structure
224 *
225 * @notapi
226 */
227void efl_lld_stop(EFlashDriver *eflp) {
228
229 stm32_flash_lock(eflp);
230}
231
232/**
233 * @brief Gets the flash descriptor structure.
234 *
235 * @param[in] ip pointer to a @p EFlashDriver instance
236 * @return A flash device descriptor.
237 * @retval Pointer to single bank if DBM not enabled.
238 * @retval Pointer to bank1 if DBM enabled.
239 *
240 * @notapi
241 */
242const flash_descriptor_t *efl_lld_get_descriptor(void *instance) {
243 EFlashDriver *devp = (EFlashDriver *)instance;
244 return devp->descriptor;
245}
246
247/**
248 * @brief Read operation.
249 *
250 * @param[in] ip pointer to a @p EFlashDriver instance
251 * @param[in] offset offset within full flash address space
252 * @param[in] n number of bytes to be read
253 * @param[out] rp pointer to the data buffer
254 * @return An error code.
255 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
256 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
257 * @retval FLASH_ERROR_READ if the read operation failed.
258 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
259 *
260 * @notapi
261 */
262flash_error_t efl_lld_read(void *instance, flash_offset_t offset,
263 size_t n, uint8_t *rp) {
264 EFlashDriver *devp = (EFlashDriver *)instance;
265 flash_error_t err = FLASH_NO_ERROR;
266
267 osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
268
269 const flash_descriptor_t *bank = efl_lld_get_descriptor(instance);
270 osalDbgCheck((size_t)offset + n <= (size_t)bank->size);
271 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
272 "invalid state");
273
274 /* No reading while erasing.*/
275 if (devp->state == FLASH_ERASE) {
276 return FLASH_BUSY_ERASING;
277 }
278
279 /* FLASH_READ state while the operation is performed.*/
280 devp->state = FLASH_READ;
281
282 /* Clearing error status bits.*/
283 stm32_flash_clear_status(devp);
284
285 /* Actual read implementation.*/
286 memcpy((void *)rp, (const void *)efl_lld_get_descriptor(instance)->address
287 + offset, n);
288
289 /* Checking for errors after reading.*/
290 if ((devp->flash->SR & FLASH_SR_RDERR) != 0U) {
291 err = FLASH_ERROR_READ;
292 }
293
294 /* Ready state again.*/
295 devp->state = FLASH_READY;
296
297 return err;
298
299}
300
301/**
302 * @brief Program operation.
303 * @note The device supports ECC, it is only possible to write erased
304 * pages once except when writing all zeroes.
305 *
306 * @param[in] ip pointer to a @p EFlashDriver instance
307 * @param[in] offset offset within full flash address space
308 * @param[in] n number of bytes to be programmed
309 * @param[in] pp pointer to the data buffer
310 * @return An error code.
311 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
312 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
313 * @retval FLASH_ERROR_PROGRAM if the program operation failed.
314 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
315 *
316 * @notapi
317 */
318flash_error_t efl_lld_program(void *instance, flash_offset_t offset,
319 size_t n, const uint8_t *pp) {
320 EFlashDriver *devp = (EFlashDriver *)instance;
321 const flash_descriptor_t *bank = efl_lld_get_descriptor(instance);
322 flash_error_t err = FLASH_NO_ERROR;
323
324 osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U));
325 osalDbgCheck((size_t)offset + n <= (size_t)bank->size);
326 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
327 "invalid state");
328
329 /* No programming while erasing.*/
330 if (devp->state == FLASH_ERASE) {
331 return FLASH_BUSY_ERASING;
332 }
333
334 /* FLASH_PGM state while the operation is performed.*/
335 devp->state = FLASH_PGM;
336
337 /* Clearing error status bits.*/
338 stm32_flash_clear_status(devp);
339
340 /* Enabling PGM mode in the controller.*/
341 stm32_flash_enable_pgm(devp);
342
343 /* Actual program implementation.*/
344 while (n > 0U) {
345 volatile uint32_t *address;
346
347 union {
348 uint32_t w[STM32_FLASH_LINE_SIZE / sizeof (uint32_t)];
349 uint8_t b[STM32_FLASH_LINE_SIZE / sizeof (uint8_t)];
350 } line;
351
352 /* Unwritten bytes are initialized to all ones.*/
353 line.w[0] = 0xFFFFFFFFU;
354 line.w[1] = 0xFFFFFFFFU;
355
356 /* Programming address aligned to flash lines.*/
357 address = (volatile uint32_t *)(bank->address +
358 (offset & ~STM32_FLASH_LINE_MASK));
359
360 /* Copying data inside the prepared line.*/
361 do {
362 line.b[offset & STM32_FLASH_LINE_MASK] = *pp;
363 offset++;
364 n--;
365 pp++;
366 }
367 while ((n > 0U) & ((offset & STM32_FLASH_LINE_MASK) != 0U));
368
369 /* Programming line.*/
370 address[0] = line.w[0];
371 address[1] = line.w[1];
372 stm32_flash_wait_busy(devp);
373 err = stm32_flash_check_errors(devp);
374 if (err != FLASH_NO_ERROR) {
375 break;
376 }
377 }
378
379 /* Disabling PGM mode in the controller.*/
380 stm32_flash_disable_pgm(devp);
381
382 /* Ready state again.*/
383 devp->state = FLASH_READY;
384
385 return err;
386}
387
388/**
389 * @brief Starts a whole-device erase operation.
390 * @note This function only erases bank 2 if it is present. Bank 1 is not
391 * allowed since it is normally where the primary program is located.
392 * Pages on bank 1 can be individually erased.
393 *
394 * @param[in] ip pointer to a @p EFlashDriver instance
395 * @return An error code.
396 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
397 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
398 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
399 *
400 * @notapi
401 */
402flash_error_t efl_lld_start_erase_all(void *instance) {
403 EFlashDriver *devp = (EFlashDriver *)instance;
404
405 osalDbgCheck(instance != NULL);
406 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
407 "invalid state");
408
409 /* No erasing while erasing.*/
410 if (devp->state == FLASH_ERASE) {
411 return FLASH_BUSY_ERASING;
412 }
413
414#if defined(FLASH_CR_MER2)
415 /* If dual bank is active then mass erase bank2. */
416 if (stm32_flash_dual_bank(devp)) {
417
418 /* FLASH_ERASE state while the operation is performed.*/
419 devp->state = FLASH_ERASE;
420
421 /* Clearing error status bits.*/
422 stm32_flash_clear_status(devp);
423
424 devp->flash->CR |= FLASH_CR_MER2;
425 devp->flash->CR |= FLASH_CR_STRT;
426 return FLASH_NO_ERROR;
427 }
428#endif
429
430 /* Mass erase not allowed. */
431 return FLASH_ERROR_UNIMPLEMENTED;
432}
433
434/**
435 * @brief Starts an sector erase operation.
436 *
437 * @param[in] ip pointer to a @p EFlashDriver instance
438 * @param[in] sector sector to be erased
439 * this is an index within the total sectors
440 * in a flash bank
441 * @return An error code.
442 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
443 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
444 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
445 *
446 * @notapi
447 */
448flash_error_t efl_lld_start_erase_sector(void *instance,
449 flash_sector_t sector) {
450 EFlashDriver *devp = (EFlashDriver *)instance;
451 const flash_descriptor_t *bank = efl_lld_get_descriptor(instance);
452 osalDbgCheck(instance != NULL);
453 osalDbgCheck(sector < bank->sectors_count);
454 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
455 "invalid state");
456
457 /* No erasing while erasing.*/
458 if (devp->state == FLASH_ERASE) {
459 return FLASH_BUSY_ERASING;
460 }
461
462 /* FLASH_PGM state while the operation is performed.*/
463 devp->state = FLASH_ERASE;
464
465 /* Clearing error status bits.*/
466 stm32_flash_clear_status(devp);
467
468 /* Enable page erase.*/
469 devp->flash->CR |= FLASH_CR_PER;
470
471#if defined(FLASH_CR_BKER)
472 /* If dual bank is active then setup relevant bank. */
473 if (stm32_flash_dual_bank(devp)) {
474 if (sector < (bank->sectors_count / 2)) {
475 /* First bank.*/
476 devp->flash->CR &= ~FLASH_CR_BKER;
477 }
478 else {
479 /* Second bank. Adjust sector index. */
480 sector -= (bank->sectors_count / 2);
481 devp->flash->CR |= FLASH_CR_BKER;
482 }
483 }
484#endif
485
486 /* Mask off the page selection bits.*/
487 devp->flash->CR &= ~FLASH_CR_PNB;
488
489 /* Set the page selection bits.*/
490 devp->flash->CR |= sector << FLASH_CR_PNB_Pos;
491
492 /* Start the erase.*/
493 devp->flash->CR |= FLASH_CR_STRT;
494
495 return FLASH_NO_ERROR;
496}
497
498/**
499 * @brief Queries the driver for erase operation progress.
500 *
501 * @param[in] ip pointer to a @p EFlashDriver instance
502 * @param[out] msec recommended time, in milliseconds, that
503 * should be spent before calling this
504 * function again, can be @p NULL
505 * @return An error code.
506 * @retval FLASH_NO_ERROR if there is no erase operation in progress.
507 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
508 * @retval FLASH_ERROR_ERASE if the erase operation failed.
509 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
510 *
511 * @api
512 */
513flash_error_t efl_lld_query_erase(void *instance, uint32_t *msec) {
514 EFlashDriver *devp = (EFlashDriver *)instance;
515 flash_error_t err;
516
517 /* If there is an erase in progress then the device must be checked.*/
518 if (devp->state == FLASH_ERASE) {
519
520 /* Checking for operation in progress.*/
521 if ((devp->flash->SR & FLASH_SR_BSY1) == 0U) {
522
523 /* Disabling the various erase control bits.*/
524 devp->flash->CR &= ~(FLASH_CR_MER1 |
525#if defined(FLASH_CR_MER2)
526 FLASH_CR_MER2 |
527#endif
528 FLASH_CR_PER);
529
530 /* No operation in progress, checking for errors.*/
531 err = stm32_flash_check_errors(devp);
532
533 /* Back to ready state.*/
534 devp->state = FLASH_READY;
535 }
536 else {
537 /* Recommended time before polling again. This is a simplified
538 implementation.*/
539 if (msec != NULL) {
540 *msec = (uint32_t)STM32_FLASH_WAIT_TIME_MS;
541 }
542
543 err = FLASH_BUSY_ERASING;
544 }
545 }
546 else {
547 err = FLASH_NO_ERROR;
548 }
549
550 return err;
551}
552
553/**
554 * @brief Returns the erase state of a sector.
555 *
556 * @param[in] ip pointer to a @p EFlashDriver instance
557 * @param[in] sector sector to be verified
558 * @return An error code.
559 * @retval FLASH_NO_ERROR if the sector is erased.
560 * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
561 * @retval FLASH_ERROR_VERIFY if the verify operation failed.
562 * @retval FLASH_ERROR_HW_FAILURE if access to the memory failed.
563 *
564 * @notapi
565 */
566flash_error_t efl_lld_verify_erase(void *instance, flash_sector_t sector) {
567 EFlashDriver *devp = (EFlashDriver *)instance;
568 uint32_t *address;
569 const flash_descriptor_t *bank = efl_lld_get_descriptor(instance);
570 flash_error_t err = FLASH_NO_ERROR;
571 unsigned i;
572
573 osalDbgCheck(instance != NULL);
574 osalDbgCheck(sector < bank->sectors_count);
575 osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
576 "invalid state");
577
578 /* No verifying while erasing.*/
579 if (devp->state == FLASH_ERASE) {
580 return FLASH_BUSY_ERASING;
581 }
582
583 /* Address of the sector in the selected bank.*/
584 address = (uint32_t *)(bank->address +
585 flashGetSectorOffset(getBaseFlash(devp), sector));
586
587 /* FLASH_READ state while the operation is performed.*/
588 devp->state = FLASH_READ;
589
590 /* Scanning the sector space.*/
591 uint32_t sector_size = flashGetSectorSize(getBaseFlash(devp), sector);
592 for (i = 0U; i < sector_size / sizeof(uint32_t); i++) {
593 if (*address != 0xFFFFFFFFU) {
594 err = FLASH_ERROR_VERIFY;
595 break;
596 }
597 address++;
598 }
599
600 /* Ready state again.*/
601 devp->state = FLASH_READY;
602
603 return err;
604}
605
606#endif /* HAL_USE_EFL == TRUE */
607
608/** @} */