logo

qmk_firmware

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

wear_leveling_rp2040_flash.c (8609B)


  1. /**
  2. * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
  3. * Copyright (c) 2022 Nick Brassel (@tzarc)
  4. * Copyright (c) 2022 Stefan Kerkmann (@KarlK90)
  5. *
  6. * SPDX-License-Identifier: BSD-3-Clause
  7. */
  8. #include <stdbool.h>
  9. #include "pico/bootrom.h"
  10. #include "hardware/flash.h"
  11. #include "hardware/sync.h"
  12. #include "hardware/structs/ssi.h"
  13. #include "hardware/structs/ioqspi.h"
  14. #include "compiler_support.h"
  15. #include "timer.h"
  16. #include "wear_leveling.h"
  17. #include "wear_leveling_rp2040_flash_config.h"
  18. #include "wear_leveling_internal.h"
  19. #ifndef WEAR_LEVELING_RP2040_FLASH_BULK_COUNT
  20. # define WEAR_LEVELING_RP2040_FLASH_BULK_COUNT 64
  21. #endif // WEAR_LEVELING_RP2040_FLASH_BULK_COUNT
  22. #define FLASHCMD_PAGE_PROGRAM 0x02
  23. #define FLASHCMD_READ_STATUS 0x05
  24. #define FLASHCMD_WRITE_ENABLE 0x06
  25. extern const uint8_t BOOT2_ROM[256];
  26. static uint32_t BOOT2_ROM_RAM[64];
  27. static ssi_hw_t *const ssi = (ssi_hw_t *)XIP_SSI_BASE;
  28. // Sanity check
  29. check_hw_layout(ssi_hw_t, ssienr, SSI_SSIENR_OFFSET);
  30. check_hw_layout(ssi_hw_t, spi_ctrlr0, SSI_SPI_CTRLR0_OFFSET);
  31. static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void) {
  32. ((void (*)(void))BOOT2_ROM_RAM + 1)();
  33. }
  34. // Bitbanging the chip select using IO overrides, in case RAM-resident IRQs
  35. // are still running, and the FIFO bottoms out. (the bootrom does the same)
  36. static void __no_inline_not_in_flash_func(flash_cs_force)(bool high) {
  37. uint32_t field_val = high ? IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH : IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW;
  38. hw_write_masked(&ioqspi_hw->io[1].ctrl, field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB, IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS);
  39. }
  40. // Also allow any unbounded loops to check whether the above abort condition
  41. // was asserted, and terminate early
  42. static int __no_inline_not_in_flash_func(flash_was_aborted)(void) {
  43. return *(io_rw_32 *)(IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SD1_CTRL_OFFSET) & IO_QSPI_GPIO_QSPI_SD1_CTRL_INOVER_BITS;
  44. }
  45. // Put bytes from one buffer, and get bytes into another buffer.
  46. // These can be the same buffer.
  47. // If tx is NULL then send zeroes.
  48. // If rx is NULL then all read data will be dropped.
  49. //
  50. // If rx_skip is nonzero, this many bytes will first be consumed from the FIFO,
  51. // before reading a further count bytes into *rx.
  52. // E.g. if you have written a command+address just before calling this function.
  53. static void __no_inline_not_in_flash_func(flash_put_get)(const uint8_t *tx, uint8_t *rx, size_t count, size_t rx_skip) {
  54. // Make sure there is never more data in flight than the depth of the RX
  55. // FIFO. Otherwise, when we are interrupted for long periods, hardware
  56. // will overflow the RX FIFO.
  57. const uint max_in_flight = 16 - 2; // account for data internal to SSI
  58. size_t tx_count = count;
  59. size_t rx_count = count;
  60. while (tx_count || rx_skip || rx_count) {
  61. // NB order of reads, for pessimism rather than optimism
  62. uint32_t tx_level = ssi_hw->txflr;
  63. uint32_t rx_level = ssi_hw->rxflr;
  64. bool did_something = false; // Expect this to be folded into control flow, not register
  65. if (tx_count && tx_level + rx_level < max_in_flight) {
  66. ssi->dr0 = (uint32_t)(tx ? *tx++ : 0);
  67. --tx_count;
  68. did_something = true;
  69. }
  70. if (rx_level) {
  71. uint8_t rxbyte = ssi->dr0;
  72. did_something = true;
  73. if (rx_skip) {
  74. --rx_skip;
  75. } else {
  76. if (rx) *rx++ = rxbyte;
  77. --rx_count;
  78. }
  79. }
  80. // APB load costs 4 cycles, so only do it on idle loops (our budget is
  81. // 48 cyc/byte)
  82. if (!did_something && __builtin_expect(flash_was_aborted(), 0)) break;
  83. }
  84. flash_cs_force(1);
  85. }
  86. // Convenience wrapper for above
  87. // (And it's hard for the debug host to get the tight timing between
  88. // cmd DR0 write and the remaining data)
  89. static void __no_inline_not_in_flash_func(_flash_do_cmd)(uint8_t cmd, const uint8_t *tx, uint8_t *rx, size_t count) {
  90. flash_cs_force(0);
  91. ssi->dr0 = cmd;
  92. flash_put_get(tx, rx, count, 1);
  93. }
  94. // Timing of this one is critical, so do not expose the symbol to debugger etc
  95. static void __no_inline_not_in_flash_func(flash_put_cmd_addr)(uint8_t cmd, uint32_t addr) {
  96. flash_cs_force(0);
  97. addr |= cmd << 24;
  98. for (int i = 0; i < 4; ++i) {
  99. ssi->dr0 = addr >> 24;
  100. addr <<= 8;
  101. }
  102. }
  103. // Poll the flash status register until the busy bit (LSB) clears
  104. static void __no_inline_not_in_flash_func(flash_wait_ready)(void) {
  105. uint8_t stat;
  106. do {
  107. _flash_do_cmd(FLASHCMD_READ_STATUS, NULL, &stat, 1);
  108. } while (stat & 0x1 && !flash_was_aborted());
  109. }
  110. // Set the WEL bit (needed before any program/erase operation)
  111. static void __no_inline_not_in_flash_func(flash_enable_write)(void) {
  112. _flash_do_cmd(FLASHCMD_WRITE_ENABLE, NULL, NULL, 0);
  113. }
  114. static void __no_inline_not_in_flash_func(pico_program_bulk)(uint32_t flash_address, backing_store_int_t *values, size_t item_count) {
  115. rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH);
  116. rom_flash_exit_xip_fn flash_exit_xip = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP);
  117. rom_flash_flush_cache_fn flash_flush_cache = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE);
  118. assert(connect_internal_flash && flash_exit_xip && flash_flush_cache);
  119. static backing_store_int_t bulk_write_buffer[WEAR_LEVELING_RP2040_FLASH_BULK_COUNT];
  120. while (item_count) {
  121. size_t batch_size = MIN(item_count, WEAR_LEVELING_RP2040_FLASH_BULK_COUNT);
  122. for (size_t i = 0; i < batch_size; i++, values++, item_count--) {
  123. bulk_write_buffer[i] = ~(*values);
  124. }
  125. __compiler_memory_barrier();
  126. connect_internal_flash();
  127. flash_exit_xip();
  128. flash_enable_write();
  129. flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, flash_address);
  130. flash_put_get((uint8_t *)bulk_write_buffer, NULL, batch_size * sizeof(backing_store_int_t), 4);
  131. flash_wait_ready();
  132. flash_address += batch_size * sizeof(backing_store_int_t);
  133. flash_flush_cache();
  134. flash_enable_xip_via_boot2();
  135. }
  136. }
  137. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  138. // QMK Wear-Leveling Backing Store implementation
  139. static int interrupts;
  140. bool backing_store_init(void) {
  141. bs_dprintf("Init\n");
  142. memcpy(BOOT2_ROM_RAM, BOOT2_ROM, sizeof(BOOT2_ROM));
  143. __compiler_memory_barrier();
  144. return true;
  145. }
  146. bool backing_store_unlock(void) {
  147. bs_dprintf("Unlock\n");
  148. return true;
  149. }
  150. bool backing_store_erase(void) {
  151. #ifdef WEAR_LEVELING_DEBUG_OUTPUT
  152. uint32_t start = timer_read32();
  153. #endif
  154. // Ensure the backing size can be cleanly subtracted from the flash size without alignment issues.
  155. STATIC_ASSERT((WEAR_LEVELING_BACKING_SIZE) % (FLASH_SECTOR_SIZE) == 0, "Backing size must be a multiple of FLASH_SECTOR_SIZE");
  156. interrupts = save_and_disable_interrupts();
  157. flash_range_erase((WEAR_LEVELING_RP2040_FLASH_BASE), (WEAR_LEVELING_BACKING_SIZE));
  158. restore_interrupts(interrupts);
  159. bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start)));
  160. return true;
  161. }
  162. bool backing_store_write(uint32_t address, backing_store_int_t value) {
  163. return backing_store_write_bulk(address, &value, 1);
  164. }
  165. bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) {
  166. uint32_t offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address;
  167. bs_dprintf("Write ");
  168. wl_dump(offset, values, sizeof(backing_store_int_t) * item_count);
  169. interrupts = save_and_disable_interrupts();
  170. pico_program_bulk(offset, values, item_count);
  171. restore_interrupts(interrupts);
  172. return true;
  173. }
  174. bool backing_store_lock(void) {
  175. return true;
  176. }
  177. bool backing_store_read(uint32_t address, backing_store_int_t *value) {
  178. return backing_store_read_bulk(address, value, 1);
  179. }
  180. bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) {
  181. uint32_t offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address;
  182. backing_store_int_t *loc = (backing_store_int_t *)((XIP_BASE) + offset);
  183. for (size_t i = 0; i < item_count; ++i) {
  184. values[i] = ~loc[i];
  185. }
  186. bs_dprintf("Read ");
  187. wl_dump(offset, values, item_count * sizeof(backing_store_int_t));
  188. return true;
  189. }