You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
5.1 KiB

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