s600_iap.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #include "s600_iap.h"
  2. #include "s600_can.h"
  3. #include "string.h"
  4. static u8 s600_iap_page[FMC_PAGE_SIZE];
  5. static u32 s600_iap_address;
  6. static u16 s600_iap_length;
  7. static void s600_iap_flag_clear(void)
  8. {
  9. #ifdef CONFIG_GD32E10X
  10. fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR | FMC_FLAG_END);
  11. #else
  12. fmc_flag_clear(FMC_FLAG_BANK0_PGERR | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_END);
  13. #endif
  14. }
  15. static u32 s600_iap_capacity(void)
  16. {
  17. return (REG32(0x1FFFF7E0) & 0xFFFF) << 10;
  18. }
  19. static u32 s600_iap_last_page(void)
  20. {
  21. u32 capacity = s600_iap_capacity();
  22. return 0x08000000 + (capacity - FMC_PAGE_SIZE);
  23. }
  24. void s600_iap_write_begin(void)
  25. {
  26. s600_iap_address = PART_APP;
  27. s600_iap_length = 0;
  28. }
  29. bool s600_iap_write_end(u32 length, u32 checksum)
  30. {
  31. u32 buff[2];
  32. if (!s600_iap_flush(s600_iap_length)) {
  33. return false;
  34. }
  35. if (checksum != s600_iap_checksum(PART_APP, length)) {
  36. return false;
  37. }
  38. buff[0] = length;
  39. buff[1] = checksum;
  40. return s600_iap_write_page(s600_iap_last_page(), buff, sizeof(buff), true);
  41. }
  42. bool s600_iap_write_page(u32 addr, const void *buff, u16 length, bool erase)
  43. {
  44. const u32 *p, *p_end;
  45. fmc_unlock();
  46. if (erase) {
  47. s600_iap_flag_clear();
  48. if (FMC_READY != fmc_page_erase(addr)) {
  49. return false;
  50. }
  51. }
  52. for (p = (const u32 *) buff, p_end = p + ((length + 3) / 4); p < p_end; p++, addr += 4) {
  53. s600_iap_flag_clear();
  54. if (FMC_READY != fmc_word_program(addr, *p)) {
  55. return false;
  56. }
  57. }
  58. fmc_lock();
  59. return true;
  60. }
  61. bool s600_iap_flush(u32 length)
  62. {
  63. if (!s600_iap_write_page(s600_iap_address, s600_iap_page, length, true)) {
  64. return false;
  65. }
  66. s600_iap_address += length;
  67. s600_iap_length = 0;
  68. return true;
  69. }
  70. bool s600_iap_write(const u8 *buff, u16 length)
  71. {
  72. while (1) {
  73. u16 remain = sizeof(s600_iap_page) - s600_iap_length;
  74. if (length < remain) {
  75. memcpy(s600_iap_page + s600_iap_length, buff, length);
  76. s600_iap_length += length;
  77. break;
  78. }
  79. memcpy(s600_iap_page + s600_iap_length, buff, remain);
  80. if (!s600_iap_flush(sizeof(s600_iap_page))) {
  81. return false;
  82. }
  83. buff += remain;
  84. length -= remain;
  85. }
  86. return true;
  87. }
  88. bool s600_iap_write_u32(u32 value)
  89. {
  90. return s600_iap_write((u8 *) &value, sizeof(value));
  91. }
  92. #if S600_IAP_CRC32
  93. u32 s600_iap_checksum(u32 addr, u32 length)
  94. {
  95. u32 crc = 0xFFFFFFFFU;
  96. const u8 *p, *p_end;
  97. for (p = (u8 *) addr, p_end = p + length; p < p_end; p++) {
  98. u8 value = *p;
  99. u8 i;
  100. for (i = 0; i < 8; i++) {
  101. if (((crc ^ value) & 1) != 0) {
  102. crc = (crc >> 1) ^ 0xEDB88320U;
  103. } else {
  104. crc >>= 1;
  105. }
  106. value >>= 1;
  107. }
  108. }
  109. return crc ^ 0xFFFFFFFFU;
  110. }
  111. #else
  112. u32 s600_iap_checksum(u32 addr, u32 length)
  113. {
  114. const u8 *p, *p_end;
  115. u32 checksum = 0;
  116. for (p = (u8 *) addr, p_end = p + length; p < p_end; p++) {
  117. checksum += *p;
  118. }
  119. return checksum;
  120. }
  121. #endif
  122. bool s600_iap_boot(bool normal)
  123. {
  124. const s600_iap_info_t *info = (s600_iap_info_t *) PART_FACTORY;
  125. const char *board_name = (const char *) PART_NAME;
  126. if (info->success == 0xFFFFFFFF) {
  127. u32 value = APP_BOOT_OK;
  128. s600_iap_write_page((u32) &info->success, &value, sizeof(value), false);
  129. s600_iap_write_page(s600_iap_last_page(), info, sizeof(*info), true);
  130. }
  131. if (strcmp(board_name, CONFIG_BOARD_NAME) != 0) {
  132. return false;
  133. }
  134. info = (s600_iap_info_t *) s600_iap_last_page();
  135. if (normal) {
  136. if (info->success != APP_BOOT_OK) {
  137. return false;
  138. }
  139. } else if (info->length > s600_iap_capacity() - 0x2000) {
  140. return false;
  141. } else if (info->checksum != s600_iap_checksum(PART_APP, info->length)) {
  142. return false;
  143. }
  144. #if 0
  145. if ((REG32(PART_APP) & 0x2FFE0000) != 0x20000000) {
  146. return false;
  147. }
  148. #endif
  149. #ifdef CONFIG_BOARD_PS100
  150. nvic_irq_disable(USART0_IRQn);
  151. nvic_irq_disable(USART1_IRQn);
  152. #endif
  153. s600_can_device_deinit();
  154. SysTick->CTRL = 0;
  155. /* initialize user application's stack pointer */
  156. __set_MSP(REG32(PART_APP));
  157. nvic_vector_table_set(PART_APP, 0);
  158. /* jump to user application */
  159. ((void (*)(void)) REG32(PART_APP + 4))();
  160. return false;
  161. }