/******************************************************************************** * Copyright (c) 2014, Realtek Semiconductor Corp. * All rights reserved. * * This module is a confidential and proprietary property of RealTek and * possession or use of this module requires written permission of RealTek. ******************************************************************************* */ #include "xmport_uart.h" #include "xmport_loguart.h" #include "rtl8195a.h" #include "xmodem.h" #include "xmport_uart.h" #include "hal_spi_flash.h" #include "rtl8195a_spi_flash.h" #include #if /*CONFIG_PERI_UPDATE_IMG*/1 #define IMG1_SIGN_OFFSET 0x34 enum { XMODEM_UART_0 = 0, XMODEM_UART_1 = 1, XMODEM_UART_2 = 2, XMODEM_LOG_UART = 3 }; FWU_DATA_SECTION char xMFrameBuf[XM_BUFFER_SIZE]; FWU_DATA_SECTION XMODEM_CTRL xMCtrl; FWU_DATA_SECTION static u32 fw_img1_size; FWU_DATA_SECTION static u32 fw_img2_size; FWU_DATA_SECTION static u32 fw_img2_addr; FWU_DATA_SECTION static u32 fw_img3_size; FWU_DATA_SECTION static u32 fw_img3_addr; FWU_DATA_SECTION static u32 flash_wr_offset; FWU_DATA_SECTION static u32 flash_erased_addr; FWU_DATA_SECTION static u8 start_with_img1; FWU_DATA_SECTION static u32 flash_wr_err_cnt; FWU_DATA_SECTION HAL_RUART_ADAPTER xmodem_uart_adp; // we can dynamic allocate memory for this object to save memory FWU_RODATA_SECTION const char Img2Signature[8]="81958711"; extern u32 SpicCalibrationPattern[4]; extern const u8 ROM_IMG1_VALID_PATTEN[]; extern HAL_RUART_ADAPTER *pxmodem_uart_adp; #ifdef CONFIG_GPIO_EN extern HAL_GPIO_ADAPTER gBoot_Gpio_Adapter; extern PHAL_GPIO_ADAPTER _pHAL_Gpio_Adapter; #endif extern BOOLEAN SpicFlashInitRtl8195A(u8 SpicBitMode); _LONG_CALL_ extern VOID SpicWaitBusyDoneRtl8195A(VOID); extern VOID SpicWaitWipDoneRefinedRtl8195A(SPIC_INIT_PARA SpicInitPara); VOID WriteImg1Sign(u32 Image2Addr); FWU_TEXT_SECTION void FWU_WriteWord(u32 Addr, u32 FData) { SPIC_INIT_PARA SpicInitPara; HAL_WRITE32(SPI_FLASH_BASE, Addr, FData); // Wait spic busy done SpicWaitBusyDoneRtl8195A(); // Wait flash busy done (wip=0) SpicWaitWipDoneRefinedRtl8195A(SpicInitPara); } FWU_TEXT_SECTION u32 xModem_MemCmp(const u32 *av, const u32 *bv, u32 len) { const u32 *a = av; const u32 *b = (u32*)((u8*)bv+SPI_FLASH_BASE); u32 len4b = len >> 2; u32 i; for (i=0; i 0) && (idx < frame_size)) { flash_wr_offset--; idx++; skip_sz++; } // "fw_img2_size" here is used as the memory length to write // "fw_img2_addr" is used as the start memory address to write while (idx < frame_size) { if (fw_img2_size == 0) { return idx; } if (((fw_img2_addr & 0x03) == 0) && (fw_img2_size > 3) && ((frame_size - idx) > 3)) { // write address is 4-byte aligned *((u32*)fw_img2_addr) = (*((u32*)(ptr+idx))); fw_img2_addr += 4; fw_img2_size -= 4; idx += 4; } else if (fw_img2_size > 0){ *((u8*)fw_img2_addr) = (*((u8*)(ptr+idx))); fw_img2_addr++; fw_img2_size--; idx++; } } return (idx - skip_sz); } FWU_TEXT_SECTION u32 xModem_Frame_FlashWrite(char *ptr, unsigned int frame_num, unsigned int frame_size) { u32 idx=0; u32 skip_sz=0; u32 temp; u32 i; // "flash_wr_offset" here is used as the skip bytes from the head while ((flash_wr_offset > 0) && (idx < frame_size)) { flash_wr_offset--; idx++; skip_sz++; } // "fw_img2_size" here is used as the memory length to write // "fw_img2_addr" is used as the start memory address to write while (idx < frame_size) { if (fw_img2_size == 0) { return idx; } if ((fw_img2_size > 3) && ((frame_size - idx) > 3)) { FWU_WriteWord(fw_img2_addr, (*((u32*)(ptr+idx)))); fw_img2_addr += 4; fw_img2_size -= 4; idx += 4; } else { temp = 0xFFFFFFFF; for (i=0;i<4;i++) { // Just for little endian *((((u8*)&temp) + i)) = (*((u8*)(ptr+idx))); idx++; fw_img2_size--; if ((fw_img2_size == 0) || (idx >= frame_size)) { break; } } FWU_WriteWord(fw_img2_addr, temp); fw_img2_addr += 4; } } return (idx - skip_sz); } FWU_TEXT_SECTION u32 xModem_Frame_Img2(char *ptr, unsigned int frame_num, unsigned int frame_size) { u32 address; u32 ImageIndex=0; u32 rx_len=0; u32 *chk_sr; u32 *chk_dr; u32 err_addr; if (frame_num == 1) { // Parse Image2 header flash_wr_offset = fw_img2_addr; fw_img2_size = rtk_le32_to_cpu(*((u32*)ptr)) + 0x10; if ((fw_img2_size & 0x03) != 0) { DBG_MISC_ERR("xModem_Frame_ImgAll Err#2: fw_img2_addr=0x%x fw_img2_size(%d) isn't 4-bytes aligned\r\n", fw_img2_addr, fw_img2_size); fw_img1_size = 0; fw_img2_size = 0; return rx_len; } if (fw_img2_size > (2*1024*1024)) { DBG_MISC_ERR("xModem_Frame_ImgAll Image2 to Big: fw_img2_addr=0x%x fw_img2_size(%d) \r\n", fw_img2_addr, fw_img2_size); fw_img1_size = 0; fw_img2_size = 0; return rx_len; } fw_img3_addr = fw_img2_addr + fw_img2_size; // erase Flash first address = fw_img2_addr & (~0xfff); // 4k aligned, 4k is the page size of flash memory while ((address) < (fw_img2_addr+fw_img2_size)) { SpicSectorEraseFlashRtl8195A(SPI_FLASH_BASE + address); address += 0x1000; } flash_erased_addr = address; } if (fw_img2_size > 0) { // writing image2 chk_sr = (u32*)((u8*)ptr+ImageIndex); chk_dr = (u32*)flash_wr_offset; while (ImageIndex < frame_size) { FWU_WriteWord(flash_wr_offset, (*((u32*)(ptr+ImageIndex)))); ImageIndex += 4; flash_wr_offset += 4; rx_len += 4; fw_img2_size -= 4; if (fw_img2_size == 0) { // Image2 write done, break; } } err_addr = xModem_MemCmp(chk_sr, chk_dr, (flash_wr_offset - (u32)chk_dr)); if (err_addr) { flash_wr_err_cnt++; } } if (ImageIndex >= frame_size) { return rx_len; } // Skip the gap between image2 and image3, // there is no gap in current image format if (flash_wr_offset < fw_img3_addr) { if ((flash_wr_offset + (frame_size-ImageIndex)) <= fw_img3_addr) { flash_wr_offset += (frame_size-ImageIndex); return rx_len; } else { while (ImageIndex < frame_size) { if (flash_wr_offset == fw_img3_addr) { break; } ImageIndex += 4; flash_wr_offset += 4; } } } if (fw_img3_addr == flash_wr_offset) { if (ImageIndex < frame_size) { fw_img3_size = rtk_le32_to_cpu(*((u32*)(ptr+ImageIndex))); if (fw_img3_size == 0x1A1A1A1A) { // all padding bytes, no image3 fw_img3_size = 0; return rx_len; } if ((fw_img3_size & 0x03) != 0) { DBG_MISC_ERR("xModem_Frame_ImgAll Err#5: fw_img3_addr=0x%x fw_img3_size(%d) isn't 4-bytes aligned\r\n", fw_img3_addr, fw_img3_size); fw_img3_size = 0; return rx_len; } if (fw_img3_size > (2*1024*1024)) { DBG_MISC_ERR("xModem_Frame_ImgAll Image3 to Big: fw_img3_addr=0x%x fw_img2_size(%d) \r\n", fw_img3_addr, fw_img3_size); fw_img3_size = 0; return rx_len; } // Flash sector erase for image2 writing if (flash_erased_addr >= fw_img3_addr) { address = flash_erased_addr; } else { address = fw_img3_addr & (~0xfff); // 4k aligned, 4k is the page size of flash memory } while ((address) < (fw_img3_addr+fw_img3_size)) { DBG_MISC_INFO("Flash Erase: 0x%x\n", address); #if 0 if ((address & 0xFFFF) == 0) { SpicBlockEraseFlashRtl8195A(SPI_FLASH_BASE + address); address += 0x10000; // 1 block = 64k bytes } else #endif { SpicSectorEraseFlashRtl8195A(SPI_FLASH_BASE + address); address += 0x1000; // 1 sector = 4k bytes } } flash_erased_addr = address; } } if (fw_img3_size > 0) { // writing image3 chk_sr = (u32*)((u8*)ptr+ImageIndex); chk_dr = (u32*)flash_wr_offset; while (ImageIndex < frame_size) { FWU_WriteWord(flash_wr_offset, (*((u32*)(ptr+ImageIndex)))); ImageIndex += 4; flash_wr_offset += 4; rx_len += 4; fw_img3_size -= 4; if (fw_img3_size == 0) { // Image3 write done, break; } } err_addr = xModem_MemCmp(chk_sr, chk_dr, (flash_wr_offset - (u32)chk_dr)); if (err_addr) { flash_wr_err_cnt++; } } return rx_len; } FWU_TEXT_SECTION u32 xModem_Frame_ImgAll(char *ptr, unsigned int frame_num, unsigned int frame_size) { int i; u32 address; u32 img_size; u32 img_addr; u32 ImgIdx=0; u32 Img1Sign; u32 rx_len=0; u32 *chk_sr; u32 *chk_dr; u32 err_addr; if (frame_num == 1) { // Check is it the start patten of image1 start_with_img1 = 1; for(i=0; i<4; i++) { Img1Sign = rtk_le32_to_cpu(*((u32*)(ptr + i*4))); if(Img1Sign != SpicCalibrationPattern[i]) { start_with_img1 = 0; break; } } // Get the image size: the first 4 bytes if (start_with_img1) { // Image1 + Image2 // Check the Image1 Signature i=0; while (ROM_IMG1_VALID_PATTEN[i] != 0xff) { if (ptr[i+IMG1_SIGN_OFFSET] != ROM_IMG1_VALID_PATTEN[i]) { // image1 validation patten miss match DBG_MISC_ERR("xModem_Frame_ImgAll Err: Image1 Signature Incorrect\r\n"); fw_img1_size = 0; fw_img2_size = 0; fw_img2_addr = 0; fw_img3_size = 0; fw_img3_addr = 0; return 0; } else { // make the signature all 0xff for now, write the signature when image1 download is done ptr[i+IMG1_SIGN_OFFSET] = 0xff; } i++; } flash_wr_offset = 0; fw_img1_size = rtk_le32_to_cpu(*((u32*)(ptr + 0x10))) + 0x20; if ((fw_img1_size & 0x03) != 0) { DBG_MISC_WARN("xModem_Frame_ImgAll Err: fw_img1_size(0x%x) isn't 4-bytes aligned\r\n", fw_img1_size); fw_img1_size = 0; fw_img2_size = 0; fw_img2_addr = 0; fw_img3_size = 0; fw_img3_addr = 0; return 0; } address = 0; img_size = fw_img1_size; img_addr = 0; fw_img2_addr = rtk_le16_to_cpu(*((u16*)(ptr + 0x18))) * 1024; if (fw_img2_addr == 0) { // it's old format: image1 & image2 is cascaded directly fw_img2_addr = fw_img1_size; } fw_img2_size = 0; DBG_MISC_INFO("Update Image All: Image1 Size=%d, Image2 Addr=0x%x\r\n", fw_img1_size, fw_img2_addr); } else { // It's image2(+image3) only if (fw_img2_addr == 0) { DBG_MISC_WARN("The single-image format in flash now, it cannot just update the image2\r\n"); fw_img1_size = 0; fw_img2_size = 0; return rx_len; } flash_wr_offset = fw_img2_addr; fw_img1_size = 0; fw_img2_size = rtk_le32_to_cpu(*((u32*)ptr)) + 0x10; fw_img3_addr = fw_img2_addr + fw_img2_size; if ((fw_img2_size & 0x03) != 0) { DBG_MISC_ERR("xModem_Frame_ImgAll Err: fw_img2_size(0x%x) isn't 4-bytes aligned\r\n", fw_img2_size); fw_img1_size = 0; fw_img2_size = 0; return rx_len; } address = fw_img2_addr & (~0xfff); // 4k aligned, 4k is the page size of flash memory img_size = fw_img2_size; img_addr = fw_img2_addr; DBG_MISC_INFO("Update Image2: Addr=0x%x, Size=%d\r\n", fw_img2_addr, fw_img2_size); } // erase Flash sector first while ((address) < (img_addr+img_size)) { // DBG_MISC_INFO("Flash Erase: 0x%x\n", address); if ((address >= 0x10000 ) && ((address & 0xFFFF) == 0)) { SpicBlockEraseFlashRtl8195A(SPI_FLASH_BASE + address); address += 0x10000; // 1 Block = 64k bytes } else { SpicSectorEraseFlashRtl8195A(SPI_FLASH_BASE + address); address += 0x1000; // 1 sector = 4k bytes } } flash_erased_addr = address; } { if (!start_with_img1) { if (fw_img2_size > 0) { chk_sr = (u32*)((u8*)ptr+ImgIdx); chk_dr = (u32*)flash_wr_offset; while (ImgIdx < frame_size) { FWU_WriteWord(flash_wr_offset, (*((u32*)(ptr+ImgIdx)))); ImgIdx += 4; flash_wr_offset += 4; rx_len += 4; fw_img2_size -= 4; if (fw_img2_size == 0) { break; } } err_addr = xModem_MemCmp(chk_sr, chk_dr, (flash_wr_offset - (u32)chk_dr)); if (err_addr) { flash_wr_err_cnt++; } } } else { ImgIdx = 0; if (fw_img1_size > 0) { // still writing image1 chk_sr = (u32*)((u8*)ptr+ImgIdx); chk_dr = (u32*)flash_wr_offset; while (ImgIdx < frame_size) { FWU_WriteWord(flash_wr_offset, (*((u32*)(ptr+ImgIdx)))); ImgIdx += 4; flash_wr_offset += 4; rx_len += 4; fw_img1_size -= 4; if (fw_img1_size == 0) { // Image1 write done, break; } } err_addr = xModem_MemCmp(chk_sr, chk_dr, (flash_wr_offset - (u32)chk_dr)); if (err_addr) { flash_wr_err_cnt++; } else { if (fw_img1_size == 0) { // Write Image1 signature WriteImg1Sign(IMG1_SIGN_OFFSET); } } } if (ImgIdx >= frame_size) { return rx_len; } if (fw_img2_addr == 0) { return rx_len; } // Skip the section of system data if (flash_wr_offset < fw_img2_addr) { if ((flash_wr_offset + (frame_size-ImgIdx)) <= fw_img2_addr) { flash_wr_offset += (frame_size-ImgIdx); return rx_len; } else { while (ImgIdx < frame_size) { if (flash_wr_offset == fw_img2_addr) { break; } ImgIdx += 4; flash_wr_offset += 4; rx_len += 4; } } } if (fw_img2_addr == flash_wr_offset) { if (ImgIdx < frame_size) { fw_img2_size = rtk_le32_to_cpu(*((u32*)(ptr+ImgIdx))) + 0x10; fw_img3_addr = fw_img2_addr + fw_img2_size; if ((fw_img2_size & 0x03) != 0) { DBG_MISC_ERR("xModem_Frame_ImgAll Err#2: fw_img2_addr=0x%x fw_img2_size(%d) isn't 4-bytes aligned\r\n", fw_img2_addr, fw_img2_size); fw_img1_size = 0; fw_img2_size = 0; return rx_len; } if (fw_img2_size > (2*1024*1024)) { DBG_MISC_ERR("xModem_Frame_ImgAll Image2 to Big: fw_img2_addr=0x%x fw_img2_size(%d) \r\n", fw_img2_addr, fw_img2_size); fw_img1_size = 0; fw_img2_size = 0; return rx_len; } // Flash sector erase for image2 writing if (flash_erased_addr >= fw_img2_addr) { address = flash_erased_addr; } else { address = fw_img2_addr & (~0xfff); // 4k aligned, 4k is the page size of flash memory } while ((address) < (fw_img2_addr+fw_img2_size)) { DBG_MISC_INFO("Flash Erase: 0x%x\n", address); if ((address & 0xFFFF) == 0) { SpicBlockEraseFlashRtl8195A(SPI_FLASH_BASE + address); address += 0x10000; // 1 block = 64k bytes } else { SpicSectorEraseFlashRtl8195A(SPI_FLASH_BASE + address); address += 0x1000; // 1 sector = 4k bytes } } flash_erased_addr = address; } } if (fw_img2_size > 0) { // writing image2 chk_sr = (u32*)((u8*)ptr+ImgIdx); chk_dr = (u32*)flash_wr_offset; while (ImgIdx < frame_size) { FWU_WriteWord(flash_wr_offset, (*((u32*)(ptr+ImgIdx)))); ImgIdx += 4; flash_wr_offset += 4; rx_len += 4; fw_img2_size -= 4; if (fw_img2_size == 0) { // Image2 write done, break; } } err_addr = xModem_MemCmp(chk_sr, chk_dr, (flash_wr_offset - (u32)chk_dr)); if (err_addr) { flash_wr_err_cnt++; } } if (ImgIdx >= frame_size) { return rx_len; } if (fw_img3_addr == flash_wr_offset) { if (ImgIdx < frame_size) { fw_img3_size = rtk_le32_to_cpu(*((u32*)(ptr+ImgIdx))); if (fw_img3_size == 0x1A1A1A1A) { // all padding bytes, no image3 fw_img3_size = 0; // DBG_8195A("No Img3\r\n"); return rx_len; } if ((fw_img3_size & 0x03) != 0) { DBG_MISC_ERR("xModem_Frame_ImgAll Err#5: fw_img3_addr=0x%x fw_img3_size(%d) isn't 4-bytes aligned\r\n", fw_img3_addr, fw_img3_size); fw_img3_size = 0; return rx_len; } if (fw_img3_size > (2*1024*1024)) { DBG_MISC_ERR("xModem_Frame_ImgAll Image3 to Big: fw_img3_addr=0x%x fw_img2_size(%d) \r\n", fw_img3_addr, fw_img3_size); fw_img3_size = 0; return rx_len; } // Flash sector erase for image2 writing if (flash_erased_addr >= fw_img3_addr) { address = flash_erased_addr; } else { address = fw_img3_addr & (~0xfff); // 4k aligned, 4k is the page size of flash memory } while ((address) < (fw_img3_addr+fw_img3_size)) { DBG_MISC_INFO("Flash Erase: 0x%x\n", address); if ((address & 0xFFFF) == 0) { SpicBlockEraseFlashRtl8195A(SPI_FLASH_BASE + address); address += 0x10000; // 1 block = 64k bytes } else { SpicSectorEraseFlashRtl8195A(SPI_FLASH_BASE + address); address += 0x1000; // 1 sector = 4k bytes } } flash_erased_addr = address; } } if (fw_img3_size > 0) { // writing image3 chk_sr = (u32*)((u8*)ptr+ImgIdx); chk_dr = (u32*)flash_wr_offset; while (ImgIdx < frame_size) { FWU_WriteWord(flash_wr_offset, (*((u32*)(ptr+ImgIdx)))); ImgIdx += 4; flash_wr_offset += 4; rx_len += 4; fw_img3_size -= 4; if (fw_img3_size == 0) { // Image3 write done, break; } } err_addr = xModem_MemCmp(chk_sr, chk_dr, (flash_wr_offset - (u32)chk_dr)); if (err_addr) { flash_wr_err_cnt++; } } } } return rx_len; } FWU_TEXT_SECTION s32 xModem_Init_UART_Port(u8 uart_idx, u8 pin_mux, u32 baud_rate) { if (uart_idx <= XMODEM_UART_2) { // update firmware via generic UART pxmodem_uart_adp = &xmodem_uart_adp; // we can use dynamic allocate to save memory // pxmodem_uart_adp = RtlZmalloc(sizeof(HAL_RUART_ADAPTER)); xmodem_uart_init(uart_idx, pin_mux, baud_rate); xmodem_uart_func_hook(&(xMCtrl.ComPort)); } else if(uart_idx == XMODEM_LOG_UART) { // update firmware via Log UART // DiagPrintf("Open xModem Transfer on Log UART...\r\n"); // xmodem_loguart_init(); xmodem_loguart_init(baud_rate); xmodem_loguart_func_hook(&(xMCtrl.ComPort)); // DiagPrintf("Please Start the xModem Sender...\r\n"); } else { // invalid UART port DBG_MISC_ERR("xModem_Init_UART_Port: Invaild UART port(%d)\n", uart_idx); return -1; } return 0; } FWU_TEXT_SECTION VOID xModem_DeInit_UART_Port(u8 uart_idx) { if (uart_idx <= XMODEM_UART_2) { xmodem_uart_deinit(); } else if (uart_idx == XMODEM_LOG_UART) { xmodem_loguart_deinit(); } } FWU_TEXT_SECTION __weak s32 UpdatedImg2AddrValidate( u32 Image2Addr, u32 DefImage2Addr, u32 DefImage2Size ) { if (Image2Addr == 0xffffffff) { // Upgraded Image2 isn't exist return 0; // invalid address } if ((Image2Addr & 0xfff) != 0) { // Not 4K aligned return 0; // invalid address } if (Image2Addr <= DefImage2Addr) { // Updated image2 address must bigger than the addrss of default image2 return 0; // invalid address } if (Image2Addr < (DefImage2Addr+DefImage2Size)) { // Updated image2 overlap with the default image2 return 0; // invalid address } return 1; // this address is valid } FWU_TEXT_SECTION __weak s32 Img2SignValidate( u32 Image2Addr ) { u32 img2_sig[3]; s32 sign_valid=0; // Image2 header: Size(4B) + Addr(4B) + Signature(8B) img2_sig[0] = HAL_READ32(SPI_FLASH_BASE, Image2Addr + 8); img2_sig[1] = HAL_READ32(SPI_FLASH_BASE, Image2Addr + 12); img2_sig[2] = 0; // end of string if (_memcmp((void*)img2_sig, (void*)Img2Signature, 8)) { DBG_MISC_INFO("Invalid Image2 Signature:%s\n", img2_sig); } else { sign_valid = 1; } return sign_valid; } FWU_TEXT_SECTION VOID MarkImg2SignOld( u32 Image2Addr ) { u32 img2_sig; _memcpy((void*)&img2_sig, (void*)Img2Signature, 4); *((char*)(&img2_sig)) = '0'; // '8' -> the latest image; '0' -> the older image FWU_WriteWord((Image2Addr + 8), img2_sig); } FWU_TEXT_SECTION VOID WriteImg1Sign( u32 Image2Addr ) { u32 img1_sig; _memcpy((void*)&img1_sig, (void*)ROM_IMG1_VALID_PATTEN, 4); FWU_WriteWord(IMG1_SIGN_OFFSET, img1_sig); } FWU_TEXT_SECTION VOID WriteImg2Sign( u32 Image2Addr ) { u32 img2_sig[2]; _memcpy((void*)img2_sig, (void*)Img2Signature, 8); FWU_WriteWord((Image2Addr + 8), img2_sig[0]); FWU_WriteWord((Image2Addr + 12), img2_sig[1]); } FWU_TEXT_SECTION u32 SelectImg2ToUpdate( u32 *OldImg2Addr ) { u32 DefImage2Addr=0xFFFFFFFF; // the default Image2 addr. u32 SecImage2Addr=0xFFFFFFFF; // the 2nd image2 addr. u32 ATSCAddr=0xFFFFFFFF; u32 UpdImage2Addr; // the addr of the image2 to be updated u32 DefImage2Len; #ifdef CONFIG_UPDATE_TOGGLE_IMG2 u32 SigImage0,SigImage1; #endif *OldImg2Addr = 0; DefImage2Addr = (HAL_READ32(SPI_FLASH_BASE, 0x18)&0xFFFF) * 1024; if ((DefImage2Addr != 0) && ((DefImage2Addr < (16*1024*1024)))) { // Valid Default Image2 Addr: != 0 & located in 16M DefImage2Len = HAL_READ32(SPI_FLASH_BASE, DefImage2Addr); // Get the pointer of the upgraded Image2 SecImage2Addr = HAL_READ32(SPI_FLASH_BASE, FLASH_SYSTEM_DATA_ADDR); if (UpdatedImg2AddrValidate(SecImage2Addr, DefImage2Addr, DefImage2Len)) { UpdImage2Addr = SecImage2Addr; // Update the 2nd image2 #ifdef CONFIG_UPDATE_TOGGLE_IMG2 // read Part1/Part2 signature SigImage0 = HAL_READ32(SPI_FLASH_BASE, DefImage2Addr + 8); SigImage1 = HAL_READ32(SPI_FLASH_BASE, DefImage2Addr + 12); DBG_8195A("\n\rPart1 Sig %x", SigImage0); if(SigImage0==0x30303030 && SigImage1==0x30303030) ATSCAddr = DefImage2Addr; // ATSC signature else if(SigImage0==0x35393138 && SigImage1==0x31313738) *OldImg2Addr = DefImage2Addr; // newer version, change to older version else UpdImage2Addr = DefImage2Addr; // update to older version SigImage0 = HAL_READ32(SPI_FLASH_BASE, SecImage2Addr + 8); SigImage1 = HAL_READ32(SPI_FLASH_BASE, SecImage2Addr + 12); DBG_8195A("\n\rPart2 Sig %x\n\r", SigImage0); if(SigImage0==0x30303030 && SigImage1==0x30303030) ATSCAddr = SecImage2Addr; // ATSC signature else if(SigImage0==0x35393138 && SigImage1==0x31313738) *OldImg2Addr = SecImage2Addr; else UpdImage2Addr = SecImage2Addr; // update ATSC clear partitin first if(ATSCAddr != ~0x0){ *OldImg2Addr = UpdImage2Addr; UpdImage2Addr = ATSCAddr; } #endif // end of SWAP_UPDATE, wf, 1006 } else { // The upgraded image2 isn't exist or invalid so we can just update the default image2 UpdImage2Addr = DefImage2Addr; // Update the default image2 #ifdef CONFIG_UPDATE_TOGGLE_IMG2 *OldImg2Addr = DefImage2Addr; #endif } } else { UpdImage2Addr = 0; } return UpdImage2Addr; } FWU_TEXT_SECTION void OTU_FW_Update(u8 uart_idx, u8 pin_mux, u32 baud_rate) { u32 wr_len; u32 OldImage2Addr=0; // the addr of the image2 will become old one SPIC_INIT_PARA SpicInitPara; fw_img1_size = 0; fw_img2_size = 0; fw_img2_addr = 0; fw_img3_size = 0; fw_img3_addr = 0; flash_wr_offset = 0; flash_erased_addr = 0; start_with_img1 = 0;; flash_wr_err_cnt = 0; // Get the address of the image2 to be updated SPI_FLASH_PIN_FCTRL(ON); if (!SpicFlashInitRtl8195A(SpicOneBitMode)){ SPI_FLASH_PIN_FCTRL(OFF); DBG_MISC_ERR("OTU_FW_Update: SPI Init Fail!!!!!!\n"); return; } SpicWaitWipDoneRefinedRtl8195A(SpicInitPara); printf("FW Update Over UART%d, PinMux=%d, Baud=%d\r\n", uart_idx, pin_mux, baud_rate); fw_img2_addr = SelectImg2ToUpdate(&OldImage2Addr); // Start to update the Image2 through xModem on peripheral device printf("FW Update Image2 @ 0x%x\r\n", fw_img2_addr); // We update the image via xModem on UART now, if we want to uase other peripheral device // to update the image then we need to redefine the API if (xModem_Init_UART_Port(uart_idx, pin_mux, baud_rate) < 0) { return; } // xModemStart(&xMCtrl, xMFrameBuf, xModem_Frame_ImgAll); // Support Image format: Image1+Image2 or Image2 only xModemStart(&xMCtrl, xMFrameBuf, xModem_Frame_Img2); // Support Image format: Image2 only // xModemStart(&xMCtrl, xMFrameBuf, xModem_Frame_Dump); // for debugging wr_len = xModemRxBuffer(&xMCtrl, (2*1024*1024)); xModemEnd(&xMCtrl); xModem_DeInit_UART_Port(uart_idx); if ((wr_len > 0) && (flash_wr_err_cnt == 0)) { // Firmware update OK, now write the signature to active this image WriteImg2Sign(fw_img2_addr); #ifdef CONFIG_UPDATE_TOGGLE_IMG2 // Mark the other image2 as old one by modify its signature if (OldImage2Addr != 0) { printf("Mark Image2 @ 0x%x as Old\r\n", OldImage2Addr); MarkImg2SignOld(OldImage2Addr); } #endif } printf("OTU_FW_Update Done, Write Len=%d\n", wr_len); SPI_FLASH_PIN_FCTRL(OFF); } FWU_TEXT_SECTION u8 OTU_check_gpio(void) { #ifdef CONFIG_GPIO_EN HAL_GPIO_PIN GPIO_Pin; u8 enter_update; GPIO_Pin.pin_name = HAL_GPIO_GetIPPinName_8195a(0x21);; //pin PC_1 GPIO_Pin.pin_mode = DIN_PULL_HIGH; _pHAL_Gpio_Adapter = &gBoot_Gpio_Adapter; HAL_GPIO_Init_8195a(&GPIO_Pin); if (HAL_GPIO_ReadPin_8195a(&GPIO_Pin) == GPIO_PIN_LOW) { enter_update = 1; } else { enter_update = 0; } HAL_GPIO_DeInit_8195a(&GPIO_Pin); _pHAL_Gpio_Adapter = NULL; return enter_update; #else return 0; #endif } FWU_TEXT_SECTION u8 OTU_check_uart(u32 UpdateImgCfg){ if(((UpdateImgCfg>>4)&0x03) == 2){ ACTCK_SDIOD_CCTRL(OFF); /* SDIO Function Disable */ SDIOD_ON_FCTRL(OFF); SDIOD_OFF_FCTRL(OFF); // SDIO Pin Mux off SDIOD_PIN_FCTRL(OFF); } if (xModem_Init_UART_Port(((UpdateImgCfg>>4)&0x03), (UpdateImgCfg&0x03), 115200) < 0) { return 0; } char ch; u8 x_count = 0; int timeout1 = 500; while (timeout1 != 0) { if (xMCtrl.ComPort.poll()) { ch = xMCtrl.ComPort.get(); if(ch != 0x78){ xModem_DeInit_UART_Port(((UpdateImgCfg>>4)&0x03)); return 0; } x_count ++; if(x_count == 5){ xModem_DeInit_UART_Port(((UpdateImgCfg>>4)&0x03)); return 1; } } HalDelayUs(200); timeout1--; } if(!x_count){ xModem_DeInit_UART_Port(((UpdateImgCfg>>4)&0x03)); return 0; } int timeout2 = 4500; while (timeout2 != 0) { if (xMCtrl.ComPort.poll()) { ch = xMCtrl.ComPort.get(); if(ch != 0x78){ xModem_DeInit_UART_Port(((UpdateImgCfg>>4)&0x03)); return 0; } x_count ++; if(x_count == 5) { xModem_DeInit_UART_Port(((UpdateImgCfg>>4)&0x03)); return 1; } } HalDelayUs(200); timeout2--; } xModem_DeInit_UART_Port(((UpdateImgCfg>>4)&0x03)); return 0; } FWU_TEXT_SECTION void OTU_Img_Download(u8 uart_idx, u8 pin_mux, u32 baud_rate, u32 start_offset, u32 start_addr, u32 max_size) { SPIC_INIT_PARA SpicInitPara; u32 wr_len; u8 is_flash=0; if (xModem_Init_UART_Port(uart_idx, pin_mux, baud_rate) < 0) { return; } DBG_MISC_INFO("Image Download: StartOffset=%d StartAddr=0x%x MaxSize=%d\r\n", start_offset, start_addr, max_size); fw_img2_addr = start_addr; flash_wr_offset = start_offset; fw_img2_size = max_size; if ((start_addr & 0xFF000000) == SPI_FLASH_BASE) { // it's going to write the Flash memory if (((start_addr & 0x03) != 0) || ((start_offset&0x03) != 0)) { DiagPrintf("StartAddr(0x%x), StartOffset(0x%x) Must 4-bytes Aligned\r\n", start_addr, start_offset); return; } SPI_FLASH_PIN_FCTRL(ON); if (!SpicFlashInitRtl8195A(SpicOneBitMode)){ DBG_MISC_ERR("OTU_FW_Update: SPI Init Fail!!!!!!\n"); SPI_FLASH_PIN_FCTRL(OFF); return; } is_flash = 1; SpicWaitWipDoneRefinedRtl8195A(SpicInitPara); fw_img2_addr = start_addr & 0x00FFFFFF; xModemStart(&xMCtrl, xMFrameBuf, xModem_Frame_FlashWrite); } else { xModemStart(&xMCtrl, xMFrameBuf, xModem_Frame_MemWrite); } wr_len = xModemRxBuffer(&xMCtrl, ((((max_size+flash_wr_offset-1)>>7)+1) << 7)); xModemEnd(&xMCtrl); xModem_DeInit_UART_Port(uart_idx); DBG_MISC_INFO("OTU_Img_Download Done, Write Len=%d\n", wr_len); if (is_flash) { SPI_FLASH_PIN_FCTRL(OFF); } } #endif //#if CONFIG_PERI_UPDATE_IMG