ubl/uartboot.c

288 lines
7.5 KiB
C

/*
* uartboot.c - UART boot mode
*
* Copyright (C) 2008 Hugo Villeneuve <hugo@hugovil.com>
*
* Based on TI DaVinci Flash and Boot Utilities, original copyright follows:
* Copyright 2008 Texas Instruments, Inc. <www.ti.com>
*
* 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;
}