#include "fsl_device_registers.h"
#define IPC_BASE_ADDR 0x20000000U /* Локальный адрес начала DTCM для M7 */
#define CMD_DATA_READY 1U
#define CMD_VERIFY_CRC 2U
#define STAT_IDLE 0U
#define STAT_BUSY 1U
#define STAT_ACK 2U
#define STAT_ERROR 3U
/* Внешняя функция подсчета CRC32 (стандартный алгоритм Ethernet / POSIX cksum) */
uint32_t calculate_crc32(const uint8_t *data, uint32_t length, uint32_t previous_crc);
void tcm_bootloader_main(void) {
volatile struct rproc_update_ipc *ipc = (struct rproc_update_ipc *)IPC_BASE_ADDR;
ipc->command = 0;
ipc->status = STAT_IDLE;
uint32_t current_ddr_ptr = 0x80000000U; /* Стартовый адрес боевой DDR M7 */
uint32_t calculated_total_crc = 0xFFFFFFFFU; /* Инициализация CRC32 */
while(1) {
/* Ждем команду от U-Boot */
if (ipc->command == CMD_DATA_READY) {
ipc->status = STAT_BUSY;
/* Железный M7 копирует из своего TCM в свою DDR без TRDC-блокировок */
memcpy((void *)current_ddr_ptr, (void *)ipc->buffer, ipc->chunk_size);
/* Накапливаем CRC32 по мере поступления фрагментов */
calculated_total_crc = calculate_crc32((uint8_t *)ipc->buffer, ipc->chunk_size, calculated_total_crc);
/* Сдвигаем указатель DDR под следующий фрагмент */
current_ddr_ptr += ipc->chunk_size;
/* Отвечаем U-Boot, что кусок принят */
ipc->command = 0;
ipc->status = STAT_ACK;
}
else if (ipc->command == CMD_VERIFY_CRC) {
ipc->status = STAT_BUSY;
/* Финализируем инверсию CRC32 */
calculated_total_crc ^= 0xFFFFFFFFU;
if (calculated_total_crc == ipc->expected_crc) {
ipc->status = STAT_ACK;
/* Очищаем кэши перед прыжком */
SCB_CleanDCache_by_Addr((void *)0x80000000U, (current_ddr_ptr - 0x80000000U));
SCB_InvalidateICache();
__DSB(); __ISB();
/* Прыгаем в боевой код DDR */
uint32_t jump_address = *(volatile uint32_t *)(0x80000004U);
void (*entry_point)(void) = (void (*)(void))jump_address;
/* Устанавливаем указатель стека из начала DDR прошивки */
__set_MSP(*(volatile uint32_t *)(0x80000000U));
/* Перенаправляем таблицу векторов на DDR */
SCB->VTOR = 0x80000000U;
/* Поехали! */
entry_point();
} else {
/* Ошибка валидации прошивки, стопоримся */
ipc->status = STAT_ERROR;
/* Сбрасываем накопленный CRC для последующих попыток */
calculated_total_crc = 0xFFFFFFFFU;
current_ddr_ptr = 0x80000000U;
}
ipc->command = 0;
}
}
}