eeprom_samd.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /* Copyright 2017 Fred Sundvik
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "eeprom.h"
  17. #include "debug.h"
  18. #include "samd51j18a.h"
  19. #include "core_cm4.h"
  20. #include "component/nvmctrl.h"
  21. #include "eeprom_samd.h"
  22. #ifndef MAX
  23. # define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
  24. #endif
  25. #ifndef BUSY_RETRIES
  26. # define BUSY_RETRIES 10000
  27. #endif
  28. // #define DEBUG_EEPROM_OUTPUT
  29. /*
  30. * Debug print utils
  31. */
  32. #if defined(DEBUG_EEPROM_OUTPUT)
  33. # define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__);
  34. #else /* NO_DEBUG */
  35. # define eeprom_printf(fmt, ...)
  36. #endif /* NO_DEBUG */
  37. __attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE] = {0};
  38. volatile uint8_t * SmartEEPROM8 = (uint8_t *)SEEPROM_ADDR;
  39. static inline bool eeprom_is_busy(void) {
  40. int timeout = BUSY_RETRIES;
  41. while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0)
  42. ;
  43. return NVMCTRL->SEESTAT.bit.BUSY;
  44. }
  45. static uint32_t get_virtual_eeprom_size(void) {
  46. // clang-format off
  47. static const uint32_t VIRTUAL_EEPROM_MAP[11][8] = {
  48. /* 4 8 16 32 64 128 256 512 */
  49. /* 0*/ { 0, 0, 0, 0, 0, 0, 0, 0 },
  50. /* 1*/ { 512, 1024, 2048, 4096, 4096, 4096, 4096, 4096 },
  51. /* 2*/ { 512, 1024, 2048, 4096, 8192, 8192, 8192, 8192 },
  52. /* 3*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 },
  53. /* 4*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 },
  54. /* 5*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
  55. /* 6*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
  56. /* 7*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
  57. /* 8*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
  58. /* 9*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 },
  59. /*10*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 },
  60. };
  61. // clang-format on
  62. static uint32_t virtual_eeprom_size = UINT32_MAX;
  63. if (virtual_eeprom_size == UINT32_MAX) {
  64. virtual_eeprom_size = VIRTUAL_EEPROM_MAP[NVMCTRL->SEESTAT.bit.PSZ][NVMCTRL->SEESTAT.bit.SBLK];
  65. }
  66. // eeprom_printf("get_virtual_eeprom_size:: %d:%d:%d\n", NVMCTRL->SEESTAT.bit.PSZ, NVMCTRL->SEESTAT.bit.SBLK, virtual_eeprom_size);
  67. return virtual_eeprom_size;
  68. }
  69. uint8_t eeprom_read_byte(const uint8_t *addr) {
  70. uintptr_t offset = (uintptr_t)addr;
  71. if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) {
  72. eeprom_printf("eeprom_read_byte:: out of bounds\n");
  73. return 0x0;
  74. }
  75. if (get_virtual_eeprom_size() == 0) {
  76. return buffer[offset];
  77. }
  78. if (eeprom_is_busy()) {
  79. eeprom_printf("eeprom_write_byte:: timeout\n");
  80. return 0x0;
  81. }
  82. return SmartEEPROM8[offset];
  83. }
  84. void eeprom_write_byte(uint8_t *addr, uint8_t value) {
  85. uintptr_t offset = (uintptr_t)addr;
  86. if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) {
  87. eeprom_printf("eeprom_write_byte:: out of bounds\n");
  88. return;
  89. }
  90. if (get_virtual_eeprom_size() == 0) {
  91. buffer[offset] = value;
  92. return;
  93. }
  94. if (eeprom_is_busy()) {
  95. eeprom_printf("eeprom_write_byte:: timeout\n");
  96. return;
  97. }
  98. SmartEEPROM8[offset] = value;
  99. }
  100. uint16_t eeprom_read_word(const uint16_t *addr) {
  101. const uint8_t *p = (const uint8_t *)addr;
  102. return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
  103. }
  104. uint32_t eeprom_read_dword(const uint32_t *addr) {
  105. const uint8_t *p = (const uint8_t *)addr;
  106. return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
  107. }
  108. void eeprom_read_block(void *buf, const void *addr, size_t len) {
  109. const uint8_t *p = (const uint8_t *)addr;
  110. uint8_t * dest = (uint8_t *)buf;
  111. while (len--) {
  112. *dest++ = eeprom_read_byte(p++);
  113. }
  114. }
  115. void eeprom_write_word(uint16_t *addr, uint16_t value) {
  116. uint8_t *p = (uint8_t *)addr;
  117. eeprom_write_byte(p++, value);
  118. eeprom_write_byte(p, value >> 8);
  119. }
  120. void eeprom_write_dword(uint32_t *addr, uint32_t value) {
  121. uint8_t *p = (uint8_t *)addr;
  122. eeprom_write_byte(p++, value);
  123. eeprom_write_byte(p++, value >> 8);
  124. eeprom_write_byte(p++, value >> 16);
  125. eeprom_write_byte(p, value >> 24);
  126. }
  127. void eeprom_write_block(const void *buf, void *addr, size_t len) {
  128. uint8_t * p = (uint8_t *)addr;
  129. const uint8_t *src = (const uint8_t *)buf;
  130. while (len--) {
  131. eeprom_write_byte(p++, *src++);
  132. }
  133. }
  134. void eeprom_update_byte(uint8_t *addr, uint8_t value) {
  135. eeprom_write_byte(addr, value);
  136. }
  137. void eeprom_update_word(uint16_t *addr, uint16_t value) {
  138. uint8_t *p = (uint8_t *)addr;
  139. eeprom_write_byte(p++, value);
  140. eeprom_write_byte(p, value >> 8);
  141. }
  142. void eeprom_update_dword(uint32_t *addr, uint32_t value) {
  143. uint8_t *p = (uint8_t *)addr;
  144. eeprom_write_byte(p++, value);
  145. eeprom_write_byte(p++, value >> 8);
  146. eeprom_write_byte(p++, value >> 16);
  147. eeprom_write_byte(p, value >> 24);
  148. }
  149. void eeprom_update_block(const void *buf, void *addr, size_t len) {
  150. uint8_t * p = (uint8_t *)addr;
  151. const uint8_t *src = (const uint8_t *)buf;
  152. while (len--) {
  153. eeprom_write_byte(p++, *src++);
  154. }
  155. }