/* * uartboot.c - UART boot mode * * Copyright (C) 2008 Hugo Villeneuve * * Based on TI DaVinci Flash and Boot Utilities, original copyright follows: * Copyright 2008 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "common.h" #include "davinci.h" #include "uart.h" #include "util.h" #include "crc.h" #if defined(FLASH_TYPE_NOR) #include "nor.h" #elif defined(FLASH_TYPE_NAND) #include "nand.h" #endif /* Symbols from linker script */ extern uint32_t __DDR_START; extern uint32_t DDR_SIZE; static int ddr_memory_test(void) { int k; volatile uint32_t *ddr_start = &__DDR_START; uint32_t read32; log_info("DDR tests"); log_info("1. RAMP test:"); for (k = 0; k < DDR_SIZE/4; k++) ddr_start[k] = k; /* Write */ for (k = 0; k < DDR_SIZE/4; k++) { read32 = ddr_start[k]; /* Read */ if (read32 != k) goto error; } log_info(" Success"); log_info("2. PATTERN test:"); for (k = 0; k < DDR_SIZE/4; k++) ddr_start[k] = DDR_TEST_PATTERN; /* Write */ for (k = 0; k < DDR_SIZE/4; k++) { read32 = ddr_start[k]; /* Read */ if (read32 != DDR_TEST_PATTERN) goto error; } log_info(" Success"); host_msg("DDRTEST_SUCCESS"); return 0; error: uart_send_str("Failed at address: "); uart_send_hexnum(k * 4, 8); uart_send_str(", Expected: "); uart_send_hexnum(k, 8); uart_send_str(", Read: "); uart_send_hexnum(read32, 8); uart_send_lf(); host_msg("DDRTEST_FAILURE"); return -1; } void uart_boot(uint32_t *jump_entry_point, int need_nwp_nand) { #if defined(FLASH_TYPE_NAND) int wrote_copies = 0; int prog_ok = 0; int block_num; struct nand_image_descriptor_t im_desc; #elif defined(FLASH_TYPE_NOR) struct nor_boot_t norBoot; uint32_t blkAddress, blkSize, baseAddress; #endif struct uart_ack_header_t uart_ack_header; uint32_t boot_cmd; crc32_dv_build_table(); log_info("Starting UART Boot"); host_msg("BOOTPSP"); /* Get the BOOT command */ if (uart_get_cmd(&boot_cmd) != E_PASS) goto uartboot_error; /* Set the entry point to reset by default */ *jump_entry_point = 0x0; switch (boot_cmd) { case UBL_CMD_DDR_TEST: /* Perform DDR memory testing. */ ddr_memory_test(); break; /* Download via UART UBL and APP and burn to flash. */ case UBL_CMD_FLASH_UBL_APP: host_msg("SENDUBL"); /* Download UBL */ if (uart_get_prog(&uart_ack_header) != E_PASS) goto uartboot_error; log_info("Writing UBL"); #if defined(FLASH_TYPE_NOR) NOR_Erase(nor_get_flashbase(), uart_ack_header.size); /* Write binary UBL to NOR flash. */ NOR_WriteBytes(nor_get_flashbase(), uart_ack_header.size, (uint32_t) uart_ack_header.recv_buffer); #elif defined(FLASH_TYPE_NAND) nand_remove_nwp(need_nwp_nand); wrote_copies = 0; for (block_num = START_UBL_BLOCK_NUM; block_num <= END_UBL_BLOCK_NUM; block_num++) { im_desc.magic = uart_ack_header.magic; im_desc.block_num = block_num; im_desc.entry_point = uart_ack_header.entry_point; im_desc.load_address = 0; /* Load address not used by RBL */ if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer, uart_ack_header.size) == E_PASS) { wrote_copies += 1; prog_ok = 1; } } if (!prog_ok) goto uartboot_error; #endif /* Indicate that UBL flashing was successfull. */ uart_send_str("INFO: UBLs written: "); uart_send_hexnum(wrote_copies, 1); uart_send_lf(); host_msg("DONE"); host_msg("SENDAPP"); /* Get the application header and data */ if (uart_get_prog(&uart_ack_header) != E_PASS) goto uartboot_error; log_info("Writing APP"); #if defined(FLASH_TYPE_NOR) /* Erase the NOR flash where header and data will go */ DiscoverBlockInfo((nor_get_flashbase() + UBL_IMAGE_SIZE), &blkSize, &blkAddress); baseAddress = blkAddress + blkSize; NOR_Erase(baseAddress, uart_ack_header.size + sizeof(norBoot)); /* MagicFlag for Application (binary or safe) */ norBoot.magicNum = uart_ack_header.magic; /* Bytes of application (either srec or binary) */ norBoot.appSize = uart_ack_header.size; /* Value from ACK header */ norBoot.entryPoint = uart_ack_header.entry_point; /* Semi-hardcoded load address to entry point. FIXME */ norBoot.ldAddress = uart_ack_header.entry_point; /* Write the struct nor_boot_t header to the flash */ NOR_WriteBytes(baseAddress, sizeof(norBoot), (uint32_t) &norBoot); /* Write the application data to the flash */ NOR_WriteBytes((baseAddress + sizeof(norBoot)), uart_ack_header.size, (uint32_t) uart_ack_header.recv_buffer); /* Semi-hardcoded load address to entry point. FIXME */ if (nor_write_prog(&nor_boot, uart_ack_header.recv_buffer, uart_ack_header.size, baseAddress + sizeof(norBoot), uart_ack_header.magic, uart_ack_header.entry_point, uart_ack_header.entry_point) != E_PASS) goto uartboot_error; #elif defined(FLASH_TYPE_NAND) /* Write multiple copy of U-Boot (depending on the defines in NAND.h) */ nand_remove_nwp(need_nwp_nand); prog_ok = 0; wrote_copies = 0; for (block_num = START_UBOOT_BLOCK_NUM; (block_num+MAX_BLOCK_PER_UBOOT-1) <= END_UBOOT_BLOCK_NUM; block_num += MAX_BLOCK_PER_UBOOT) { im_desc.magic = uart_ack_header.magic; im_desc.block_num = block_num; im_desc.entry_point = uart_ack_header.entry_point; /* Assuming load address is identical to entry point. */ im_desc.load_address = uart_ack_header.entry_point; if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer, uart_ack_header.size) == E_PASS) { wrote_copies += 1; prog_ok = 1; } } if (!prog_ok) goto uartboot_error; #endif /* Indicate that APP flashing was successfull. */ uart_send_str("INFO: APPs written: "); uart_send_hexnum(wrote_copies, 1); uart_send_lf(); host_msg("DONE"); break; case UBL_CMD_FLASH_DATA: host_msg("SENDDATA"); /* Get the data block infos and actual bytes */ if (uart_get_prog(&uart_ack_header) != E_PASS) goto uartboot_error; log_info("Writing DATA"); im_desc.magic = uart_ack_header.magic; im_desc.block_num = uart_ack_header.entry_point; /* Block in flash */ if (nand_write_prog(&im_desc, uart_ack_header.recv_buffer, uart_ack_header.size) != E_PASS) goto uartboot_error; /* Indicate that APP flashing was successfull. */ host_msg("DONE"); break; case UBL_CMD_FLASH_ERASE: log_info("Erasing whole flash"); #if defined(FLASH_TYPE_NOR) if (NOR_GlobalErase() != E_PASS) { log_info("Erase failed"); goto uartboot_error; } #elif defined(FLASH_TYPE_NAND) nand_remove_nwp(need_nwp_nand); if (nand_erase_all() != E_PASS) { log_info("Erase failed"); goto uartboot_error; } #endif log_info("Erase successfull"); break; default: /* Load and run application */ host_msg("SENDAPP"); if (uart_get_prog(&uart_ack_header) != E_PASS) goto uartboot_error; *jump_entry_point = uart_ack_header.entry_point; break; } /* end switch statement */ return; uartboot_error: /* Set the entry point to reset. */ *jump_entry_point = 0x0; }