wear_leveling_efl.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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_internal.h"
  8. static flash_offset_t base_offset = UINT32_MAX;
  9. #if defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  10. static flash_sector_t first_sector = WEAR_LEVELING_EFL_FIRST_SECTOR;
  11. #else // defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  12. static flash_sector_t first_sector = UINT16_MAX;
  13. #endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  14. static flash_sector_t sector_count = UINT16_MAX;
  15. static BaseFlash * flash;
  16. #ifndef WEAR_LEVELING_EFL_FIRST_SECTOR
  17. // "Automatic" detection of the flash size -- ideally ChibiOS would have this already, but alas, it doesn't.
  18. static inline uint32_t detect_flash_size(void) {
  19. # if defined(WEAR_LEVELING_EFL_FLASH_SIZE)
  20. return WEAR_LEVELING_EFL_FLASH_SIZE;
  21. # elif defined(FLASH_BANK_SIZE)
  22. return FLASH_BANK_SIZE;
  23. # elif defined(FLASH_SIZE)
  24. return FLASH_SIZE;
  25. # elif defined(FLASHSIZE_BASE)
  26. # 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_GD32VF103)
  27. return ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) << 10U; // this register has the flash size in kB, so we convert it to bytes
  28. # elif defined(QMK_MCU_SERIES_STM32L1XX)
  29. # 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?
  30. # endif
  31. # else
  32. # error Unknown flash size definition.
  33. return 0;
  34. # endif
  35. }
  36. #endif // WEAR_LEVELING_EFL_FIRST_SECTOR
  37. bool backing_store_init(void) {
  38. bs_dprintf("Init\n");
  39. flash = (BaseFlash *)&EFLD1;
  40. // Need to re-lock the EFL, as if we've just had the bootloader executing it'll already be unlocked.
  41. backing_store_lock();
  42. const flash_descriptor_t *desc = flashGetDescriptor(flash);
  43. uint32_t counter = 0;
  44. #if defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  45. // Work out how many sectors we want to use, working forwards from the first sector specified
  46. for (flash_sector_t i = 0; i < desc->sectors_count - first_sector; ++i) {
  47. counter += flashGetSectorSize(flash, first_sector + i);
  48. if (counter >= (WEAR_LEVELING_BACKING_SIZE)) {
  49. sector_count = i + 1;
  50. base_offset = flashGetSectorOffset(flash, first_sector);
  51. break;
  52. }
  53. }
  54. if (sector_count == UINT16_MAX || base_offset >= flash_size) {
  55. // We didn't get the required number of sectors. Can't do anything here. Fault.
  56. chSysHalt("Invalid sector count intended to be used with wear_leveling");
  57. }
  58. #else // defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  59. // Work out how many sectors we want to use, working backwards from the end of the flash
  60. uint32_t flash_size = detect_flash_size();
  61. flash_sector_t last_sector = desc->sectors_count;
  62. for (flash_sector_t i = 0; i < desc->sectors_count; ++i) {
  63. first_sector = desc->sectors_count - i - 1;
  64. if (flashGetSectorOffset(flash, first_sector) >= flash_size) {
  65. last_sector = first_sector;
  66. continue;
  67. }
  68. counter += flashGetSectorSize(flash, first_sector);
  69. if (counter >= (WEAR_LEVELING_BACKING_SIZE)) {
  70. sector_count = last_sector - first_sector;
  71. base_offset = flashGetSectorOffset(flash, first_sector);
  72. break;
  73. }
  74. }
  75. #endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR)
  76. return true;
  77. }
  78. bool backing_store_unlock(void) {
  79. bs_dprintf("Unlock\n");
  80. return eflStart(&EFLD1, NULL) == HAL_RET_SUCCESS;
  81. }
  82. bool backing_store_erase(void) {
  83. #ifdef WEAR_LEVELING_DEBUG_OUTPUT
  84. uint32_t start = timer_read32();
  85. #endif
  86. bool ret = true;
  87. flash_error_t status;
  88. for (int i = 0; i < sector_count; ++i) {
  89. // Kick off the sector erase
  90. status = flashStartEraseSector(flash, first_sector + i);
  91. if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) {
  92. ret = false;
  93. }
  94. // Wait for the erase to complete
  95. status = flashWaitErase(flash);
  96. if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) {
  97. ret = false;
  98. }
  99. }
  100. bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start)));
  101. return ret;
  102. }
  103. bool backing_store_write(uint32_t address, backing_store_int_t value) {
  104. uint32_t offset = (base_offset + address);
  105. bs_dprintf("Write ");
  106. wl_dump(offset, &value, sizeof(value));
  107. value = ~value;
  108. return flashProgram(flash, offset, sizeof(value), (const uint8_t *)&value) == FLASH_NO_ERROR;
  109. }
  110. bool backing_store_lock(void) {
  111. bs_dprintf("Lock \n");
  112. eflStop(&EFLD1);
  113. return true;
  114. }
  115. bool backing_store_read(uint32_t address, backing_store_int_t *value) {
  116. uint32_t offset = (base_offset + address);
  117. backing_store_int_t *loc = (backing_store_int_t *)flashGetOffsetAddress(flash, offset);
  118. *value = ~(*loc);
  119. bs_dprintf("Read ");
  120. wl_dump(offset, value, sizeof(backing_store_int_t));
  121. return true;
  122. }