device_stm32h7.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include "device.h"
  2. #include "log.h"
  3. #if MG_DEVICE == MG_DEVICE_STM32H7
  4. #define FLASH_BASE1 0x52002000 // Base address for bank1
  5. #define FLASH_BASE2 0x52002100 // Base address for bank2
  6. #define FLASH_KEYR 0x04 // See RM0433 4.9.2
  7. #define FLASH_OPTKEYR 0x08
  8. #define FLASH_OPTCR 0x18
  9. #define FLASH_SR 0x10
  10. #define FLASH_CR 0x0c
  11. #define FLASH_CCR 0x14
  12. #define FLASH_OPTSR_CUR 0x1c
  13. #define FLASH_OPTSR_PRG 0x20
  14. #define FLASH_SIZE_REG 0x1ff1e880
  15. MG_IRAM void *mg_flash_start(void) {
  16. return (void *) 0x08000000;
  17. }
  18. MG_IRAM size_t mg_flash_size(void) {
  19. return MG_REG(FLASH_SIZE_REG) * 1024;
  20. }
  21. MG_IRAM size_t mg_flash_sector_size(void) {
  22. return 128 * 1024; // 128k
  23. }
  24. MG_IRAM size_t mg_flash_write_align(void) {
  25. return 32; // 256 bit
  26. }
  27. MG_IRAM int mg_flash_bank(void) {
  28. if (mg_flash_size() < 2 * 1024 * 1024) return 0; // No dual bank support
  29. return MG_REG(FLASH_BASE1 + FLASH_OPTCR) & MG_BIT(31) ? 2 : 1;
  30. }
  31. MG_IRAM static void flash_unlock(void) {
  32. static bool unlocked = false;
  33. if (unlocked == false) {
  34. MG_REG(FLASH_BASE1 + FLASH_KEYR) = 0x45670123;
  35. MG_REG(FLASH_BASE1 + FLASH_KEYR) = 0xcdef89ab;
  36. if (mg_flash_bank() > 0) {
  37. MG_REG(FLASH_BASE2 + FLASH_KEYR) = 0x45670123;
  38. MG_REG(FLASH_BASE2 + FLASH_KEYR) = 0xcdef89ab;
  39. }
  40. MG_REG(FLASH_BASE1 + FLASH_OPTKEYR) = 0x08192a3b; // opt reg is "shared"
  41. MG_REG(FLASH_BASE1 + FLASH_OPTKEYR) = 0x4c5d6e7f; // thus unlock once
  42. unlocked = true;
  43. }
  44. }
  45. MG_IRAM static bool flash_page_start(volatile uint32_t *dst) {
  46. char *base = (char *) mg_flash_start(), *end = base + mg_flash_size();
  47. volatile char *p = (char *) dst;
  48. return p >= base && p < end && ((p - base) % mg_flash_sector_size()) == 0;
  49. }
  50. MG_IRAM static bool flash_is_err(uint32_t bank) {
  51. return MG_REG(bank + FLASH_SR) & ((MG_BIT(11) - 1) << 17); // RM0433 4.9.5
  52. }
  53. MG_IRAM static void flash_wait(uint32_t bank) {
  54. while (MG_REG(bank + FLASH_SR) & (MG_BIT(0) | MG_BIT(2))) (void) 0;
  55. }
  56. MG_IRAM static void flash_clear_err(uint32_t bank) {
  57. flash_wait(bank); // Wait until ready
  58. MG_REG(bank + FLASH_CCR) = ((MG_BIT(11) - 1) << 16U); // Clear all errors
  59. }
  60. MG_IRAM static bool flash_bank_is_swapped(uint32_t bank) {
  61. return MG_REG(bank + FLASH_OPTCR) & MG_BIT(31); // RM0433 4.9.7
  62. }
  63. // Figure out flash bank based on the address
  64. MG_IRAM static uint32_t flash_bank(void *addr) {
  65. size_t ofs = (char *) addr - (char *) mg_flash_start();
  66. if (mg_flash_bank() == 0) return FLASH_BASE1;
  67. return ofs < mg_flash_size() / 2 ? FLASH_BASE1 : FLASH_BASE2;
  68. }
  69. MG_IRAM bool mg_flash_erase(void *addr) {
  70. bool ok = false;
  71. if (flash_page_start(addr) == false) {
  72. MG_ERROR(("%p is not on a sector boundary", addr));
  73. } else {
  74. uintptr_t diff = (char *) addr - (char *) mg_flash_start();
  75. uint32_t sector = diff / mg_flash_sector_size();
  76. uint32_t bank = flash_bank(addr);
  77. uint32_t saved_cr = MG_REG(bank + FLASH_CR); // Save CR value
  78. flash_unlock();
  79. if (sector > 7) sector -= 8;
  80. flash_clear_err(bank);
  81. MG_REG(bank + FLASH_CR) = MG_BIT(5); // 32-bit write parallelism
  82. MG_REG(bank + FLASH_CR) |= (sector & 7U) << 8U; // Sector to erase
  83. MG_REG(bank + FLASH_CR) |= MG_BIT(2); // Sector erase bit
  84. MG_REG(bank + FLASH_CR) |= MG_BIT(7); // Start erasing
  85. ok = !flash_is_err(bank);
  86. MG_DEBUG(("Erase sector %lu @ %p %s. CR %#lx SR %#lx", sector, addr,
  87. ok ? "ok" : "fail", MG_REG(bank + FLASH_CR),
  88. MG_REG(bank + FLASH_SR)));
  89. MG_REG(bank + FLASH_CR) = saved_cr; // Restore CR
  90. }
  91. return ok;
  92. }
  93. MG_IRAM bool mg_flash_swap_bank() {
  94. if (mg_flash_bank() == 0) return true;
  95. uint32_t bank = FLASH_BASE1;
  96. uint32_t desired = flash_bank_is_swapped(bank) ? 0 : MG_BIT(31);
  97. flash_unlock();
  98. flash_clear_err(bank);
  99. // printf("OPTSR_PRG 1 %#lx\n", FLASH->OPTSR_PRG);
  100. MG_SET_BITS(MG_REG(bank + FLASH_OPTSR_PRG), MG_BIT(31), desired);
  101. // printf("OPTSR_PRG 2 %#lx\n", FLASH->OPTSR_PRG);
  102. MG_REG(bank + FLASH_OPTCR) |= MG_BIT(1); // OPTSTART
  103. while ((MG_REG(bank + FLASH_OPTSR_CUR) & MG_BIT(31)) != desired) (void) 0;
  104. return true;
  105. }
  106. MG_IRAM bool mg_flash_write(void *addr, const void *buf, size_t len) {
  107. if ((len % mg_flash_write_align()) != 0) {
  108. MG_ERROR(("%lu is not aligned to %lu", len, mg_flash_write_align()));
  109. return false;
  110. }
  111. uint32_t bank = flash_bank(addr);
  112. uint32_t *dst = (uint32_t *) addr;
  113. uint32_t *src = (uint32_t *) buf;
  114. uint32_t *end = (uint32_t *) ((char *) buf + len);
  115. bool ok = true;
  116. flash_unlock();
  117. flash_clear_err(bank);
  118. MG_REG(bank + FLASH_CR) = MG_BIT(1); // Set programming flag
  119. MG_REG(bank + FLASH_CR) |= MG_BIT(5); // 32-bit write parallelism
  120. MG_DEBUG(("Writing flash @ %p, %lu bytes", addr, len));
  121. MG_ARM_DISABLE_IRQ();
  122. while (ok && src < end) {
  123. if (flash_page_start(dst) && mg_flash_erase(dst) == false) break;
  124. *(volatile uint32_t *) dst++ = *src++;
  125. flash_wait(bank);
  126. if (flash_is_err(bank)) ok = false;
  127. }
  128. MG_ARM_ENABLE_IRQ();
  129. MG_DEBUG(("Flash write %lu bytes @ %p: %s. CR %#lx SR %#lx", len, dst,
  130. ok ? "ok" : "fail", MG_REG(bank + FLASH_CR),
  131. MG_REG(bank + FLASH_SR)));
  132. MG_REG(bank + FLASH_CR) &= ~MG_BIT(1); // Clear programming flag
  133. return ok;
  134. }
  135. MG_IRAM void mg_device_reset(void) {
  136. // SCB->AIRCR = ((0x5fa << SCB_AIRCR_VECTKEY_Pos)|SCB_AIRCR_SYSRESETREQ_Msk);
  137. *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004;
  138. }
  139. #endif