Загрузка данных


#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;
        }
    }
}