logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

wear_leveling_efl.c (6958B)


  1. // Copyright 2022 Nick Brassel (@tzarc)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <stdbool.h>
  4. #include <hal.h>
  5. #include "timer.h"
  6. #include "wear_leveling.h"
  7. #include "wear_leveling_efl_config.h"
  8. #include "wear_leveling_internal.h"
  9. static flash_offset_t base_offset = UINT32_MAX;
  10. #if defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  11. static flash_sector_t first_sector = WEAR_LEVELING_EFL_FIRST_SECTOR;
  12. #else // defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  13. static flash_sector_t first_sector = UINT16_MAX;
  14. #endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  15. #if !defined(WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT)
  16. # define WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT 0
  17. #endif // WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT
  18. static flash_sector_t sector_count = UINT16_MAX;
  19. static BaseFlash * flash;
  20. static bool flash_erased_is_one;
  21. static volatile bool is_issuing_read = false;
  22. static volatile bool ecc_error_occurred = false;
  23. // "Automatic" detection of the flash size -- ideally ChibiOS would have this already, but alas, it doesn't.
  24. static inline uint32_t detect_flash_size(void) {
  25. #if defined(WEAR_LEVELING_EFL_FLASH_SIZE)
  26. return WEAR_LEVELING_EFL_FLASH_SIZE;
  27. #elif defined(FLASH_BANK_SIZE)
  28. return FLASH_BANK_SIZE;
  29. #elif defined(FLASH_SIZE)
  30. return FLASH_SIZE;
  31. #elif defined(FLASHSIZE_BASE)
  32. # if defined(QMK_MCU_SERIES_STM32F0XX) || defined(QMK_MCU_SERIES_STM32F1XX) || defined(QMK_MCU_SERIES_STM32F3XX) || defined(QMK_MCU_SERIES_STM32F4XX) || defined(QMK_MCU_SERIES_STM32G4XX) || defined(QMK_MCU_SERIES_STM32L0XX) || defined(QMK_MCU_SERIES_STM32L4XX) || defined(QMK_MCU_SERIES_AT32F415) || defined(QMK_MCU_SERIES_GD32VF103)
  33. return ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) << 10U; // this register has the flash size in kB, so we convert it to bytes
  34. # elif defined(QMK_MCU_SERIES_STM32L1XX)
  35. # error This MCU family has an uncommon flash size register definition and has not been implemented. Perhaps try using the true EEPROM on the MCU instead?
  36. # endif
  37. #else
  38. # error Unknown flash size definition.
  39. return 0;
  40. #endif
  41. }
  42. bool backing_store_init(void) {
  43. bs_dprintf("Init\n");
  44. flash = (BaseFlash *)&EFLD1;
  45. // Need to re-lock the EFL, as if we've just had the bootloader executing it'll already be unlocked.
  46. backing_store_lock();
  47. const flash_descriptor_t *desc = flashGetDescriptor(flash);
  48. uint32_t counter = 0;
  49. uint32_t flash_size = detect_flash_size();
  50. // Check if the hardware erase is logic 1
  51. flash_erased_is_one = (desc->attributes & FLASH_ATTR_ERASED_IS_ONE) ? true : false;
  52. if (WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT >= desc->sectors_count) {
  53. // Last sector defined is greater than available number of sectors. Can't do anything here. Fault.
  54. chSysHalt("Last sector intended to be used with wear_leveling is beyond available flash descriptor range");
  55. }
  56. #if defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  57. // Work out how many sectors we want to use, working forwards from the first sector specified
  58. flash_sector_t last_sector = desc->sectors_count - WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT;
  59. for (flash_sector_t i = 0; i < last_sector - first_sector; ++i) {
  60. counter += flashGetSectorSize(flash, first_sector + i);
  61. if (counter >= (WEAR_LEVELING_BACKING_SIZE)) {
  62. sector_count = i + 1;
  63. base_offset = flashGetSectorOffset(flash, first_sector);
  64. break;
  65. }
  66. }
  67. if (sector_count == UINT16_MAX || base_offset >= flash_size) {
  68. // We didn't get the required number of sectors. Can't do anything here. Fault.
  69. chSysHalt("Invalid sector count intended to be used with wear_leveling");
  70. }
  71. #else // defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  72. // Work out how many sectors we want to use, working backwards from the end of the flash
  73. flash_sector_t last_sector = desc->sectors_count - WEAR_LEVELING_EFL_OMIT_LAST_SECTOR_COUNT;
  74. for (flash_sector_t i = 0; i < last_sector; ++i) {
  75. first_sector = last_sector - i - 1;
  76. if (flashGetSectorOffset(flash, first_sector) >= flash_size) {
  77. last_sector = first_sector;
  78. continue;
  79. }
  80. counter += flashGetSectorSize(flash, first_sector);
  81. if (counter >= (WEAR_LEVELING_BACKING_SIZE)) {
  82. sector_count = last_sector - first_sector;
  83. base_offset = flashGetSectorOffset(flash, first_sector);
  84. break;
  85. }
  86. }
  87. #endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  88. return true;
  89. }
  90. bool backing_store_unlock(void) {
  91. bs_dprintf("Unlock\n");
  92. return eflStart(&EFLD1, NULL) == HAL_RET_SUCCESS;
  93. }
  94. bool backing_store_erase(void) {
  95. #ifdef WEAR_LEVELING_DEBUG_OUTPUT
  96. uint32_t start = timer_read32();
  97. #endif
  98. bool ret = true;
  99. flash_error_t status;
  100. for (int i = 0; i < sector_count; ++i) {
  101. // Kick off the sector erase
  102. status = flashStartEraseSector(flash, first_sector + i);
  103. if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) {
  104. ret = false;
  105. }
  106. // Wait for the erase to complete
  107. status = flashWaitErase(flash);
  108. if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) {
  109. ret = false;
  110. }
  111. }
  112. bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start)));
  113. return ret;
  114. }
  115. bool backing_store_write(uint32_t address, backing_store_int_t value) {
  116. uint32_t offset = (base_offset + address);
  117. bs_dprintf("Write ");
  118. wl_dump(offset, &value, sizeof(value));
  119. if (flash_erased_is_one) {
  120. value = ~value;
  121. }
  122. return flashProgram(flash, offset, sizeof(value), (const uint8_t *)&value) == FLASH_NO_ERROR;
  123. }
  124. bool backing_store_lock(void) {
  125. bs_dprintf("Lock \n");
  126. eflStop(&EFLD1);
  127. return true;
  128. }
  129. static backing_store_int_t backing_store_safe_read_from_location(backing_store_int_t *loc) {
  130. backing_store_int_t value;
  131. is_issuing_read = true;
  132. ecc_error_occurred = false;
  133. value = flash_erased_is_one ? ~(*loc) : (*loc);
  134. is_issuing_read = false;
  135. return value;
  136. }
  137. bool backing_store_read(uint32_t address, backing_store_int_t *value) {
  138. uint32_t offset = (base_offset + address);
  139. backing_store_int_t *loc = (backing_store_int_t *)flashGetOffsetAddress(flash, offset);
  140. backing_store_int_t tmp = backing_store_safe_read_from_location(loc);
  141. if (ecc_error_occurred) {
  142. bs_dprintf("Failed to read from backing store, ECC error detected\n");
  143. ecc_error_occurred = false;
  144. *value = 0;
  145. return false;
  146. }
  147. *value = tmp;
  148. bs_dprintf("Read ");
  149. wl_dump(offset, value, sizeof(backing_store_int_t));
  150. return true;
  151. }
  152. bool backing_store_allow_ecc_errors(void) {
  153. return is_issuing_read;
  154. }
  155. void backing_store_signal_ecc_error(void) {
  156. ecc_error_occurred = true;
  157. }