You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
6.3 KiB
288 lines
6.3 KiB
/* |
|
* ubl.c - main file |
|
* |
|
* 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" |
|
#if defined(FLASH_TYPE_NOR) |
|
#include "nor.h" |
|
#elif defined(FLASH_TYPE_NAND) |
|
#include "nand.h" |
|
#endif |
|
|
|
#define C1_IC (1 << 12) /* icache off/on */ |
|
|
|
static uint32_t jump_entry_point; |
|
static int need_nwp_nand; |
|
|
|
enum bootmode_t bootmode; |
|
|
|
/* read co-processor 15, register #1 (control register) */ |
|
static uint32_t |
|
read_p15_c1(void) |
|
{ |
|
uint32_t value; |
|
|
|
__asm__ __volatile__( |
|
"mrc p15, 0, %0, c1, c0, 0 @ read control reg\n" |
|
: "=r" (value) |
|
: |
|
: "memory"); |
|
|
|
return value; |
|
} |
|
|
|
/* write to co-processor 15, register #1 (control register) */ |
|
static void |
|
write_p15_c1(uint32_t value) |
|
{ |
|
__asm__ __volatile__( |
|
"mcr p15, 0, %0, c1, c0, 0 @ write it back\n" |
|
: |
|
: "r" (value) |
|
: "memory"); |
|
|
|
read_p15_c1(); |
|
} |
|
|
|
static void |
|
cp_delay(void) |
|
{ |
|
volatile int i; |
|
|
|
/* copro seems to need some delay between reading and writing */ |
|
for (i = 0; i < 100; i++) |
|
; |
|
} |
|
|
|
static void |
|
icache_enable(void) |
|
{ |
|
uint32_t reg; |
|
|
|
reg = read_p15_c1(); /* get control reg. */ |
|
cp_delay(); |
|
write_p15_c1(reg | C1_IC); |
|
} |
|
|
|
/* Disable this for more secure boots */ |
|
#ifdef ENABLE_BOOT_INTERRUPT |
|
static uint32_t boot_cmd; |
|
static void |
|
interrupt_me(void) |
|
{ |
|
|
|
/* short for interrupt me */ |
|
host_msg("I_ME"); |
|
|
|
if (uart_get_cmd_timeout(&boot_cmd, 1) != E_PASS) |
|
return; |
|
if (boot_cmd != 0x23) |
|
return; |
|
|
|
log_info("Boot interrupted"); |
|
uart_boot(&jump_entry_point, need_nwp_nand); |
|
} |
|
#else |
|
static void |
|
interrupt_me(void) |
|
{ |
|
} |
|
#endif |
|
|
|
static int |
|
ubl_main(void) |
|
{ |
|
int status; |
|
|
|
/* Read boot mode */ |
|
bootmode = (enum bootmode_t) (((SYSTEM->BOOTCFG) & 0xC0) >> 6); |
|
|
|
/* Wait until the RBL is done using the UART. */ |
|
if (bootmode == NON_SECURE_UART) |
|
while ((UART0->LSR & 0x40) == 0); |
|
|
|
status = davinci_platform_init(UBL_VERSION_STR, &need_nwp_nand); |
|
if (status != E_PASS) |
|
goto error; |
|
|
|
#if defined(FLASH_TYPE_NOR) |
|
status = NOR_Init(); |
|
#elif defined(FLASH_TYPE_NAND) |
|
status = nand_init(); |
|
#endif |
|
if (status != E_PASS) { |
|
uart_send_str("flash init failed"); |
|
goto error; |
|
} |
|
|
|
uart_send_str("BootMode = "); |
|
|
|
/* Select Boot Mode */ |
|
switch (bootmode) { |
|
#if defined(FLASH_TYPE_NAND) |
|
case NON_SECURE_NAND: |
|
log_info("NAND"); /* Report boot mode to host */ |
|
|
|
interrupt_me(); |
|
|
|
/* Copy binary application data from NAND to DDRAM */ |
|
if (nand_copy(&jump_entry_point) != E_PASS) { |
|
log_info("Boot failed."); |
|
goto fallback; |
|
} |
|
break; |
|
#elif defined(FLASH_TYPE_NOR) |
|
case NON_SECURE_NOR: |
|
log_info("NOR"); /* Report boot mode to host */ |
|
|
|
/* Copy binary application data from NOR to DDRAM */ |
|
if (nor_copy() != E_PASS) { |
|
log_info("Boot failed."); |
|
goto fallback; |
|
} |
|
break; |
|
#endif |
|
case NON_SECURE_UART: |
|
log_info("UART"); /* Report boot mode to host */ |
|
goto UARTBOOT; |
|
break; |
|
default: |
|
UARTBOOT: |
|
uart_boot(&jump_entry_point, need_nwp_nand); |
|
break; |
|
} |
|
|
|
waitloop(10000); |
|
|
|
/* Disabling UART timeout timer */ |
|
while ((UART0->LSR & 0x40) == 0) |
|
; |
|
TIMER0->TCR = 0x00000000; |
|
|
|
return E_PASS; |
|
|
|
fallback: |
|
/* Wait until the RBL is done using the UART. */ |
|
while ((UART0->LSR & 0x40) == 0); |
|
|
|
uart_send_str("BootMode = "); |
|
log_info("UART"); /* Report boot mode to host */ |
|
|
|
goto UARTBOOT; |
|
|
|
error: |
|
jump_entry_point = 0; /* Reset */ |
|
return E_FAIL; |
|
} |
|
|
|
/* |
|
* boot() has naked attribute (doesn't save registers since it is the entry |
|
* point out of boot and it doesn't have an exit point). This setup requires |
|
* that the gnu compiler uses the -nostdlib option. |
|
*/ |
|
__attribute__((naked, section(".boot"))) void boot(void); |
|
|
|
void |
|
boot(void) |
|
{ |
|
void (*app_entry_function)(void); |
|
extern uint32_t __topstack; /* symbol defined in linker script */ |
|
register uint32_t *stackpointer asm("sp"); |
|
|
|
asm(" MRS r0, cpsr"); |
|
asm(" BIC r0, r0, #0x1F"); /* Clear MODES */ |
|
asm(" ORR r0, r0, #0x13"); /* Set SUPERVISOR mode */ |
|
asm(" ORR r0, r0, #0xC0"); /* Disable FIQ and IRQ */ |
|
asm(" MSR cpsr, r0"); |
|
|
|
/* Set the IVT to low memory, leave MMU & caches disabled */ |
|
asm(" MRC p15, 0, r1, c1, c0, 0"); |
|
asm(" BIC r0,r0,#0x00002000"); |
|
asm(" MCR p15, 0, r1, c1, c0, 0"); |
|
|
|
/* Stack setup */ |
|
stackpointer = &(__topstack); |
|
|
|
icache_enable(); |
|
|
|
/* Call to main code */ |
|
ubl_main(); |
|
|
|
uart_send_str("Starting app at: "); |
|
uart_send_hexnum((uint32_t) jump_entry_point, 8); |
|
uart_send_lf(); |
|
|
|
/* Jump to entry point */ |
|
app_entry_function = (void *) jump_entry_point; |
|
(*app_entry_function)(); |
|
} |
|
|
|
/* |
|
* selfcopy() has naked attribute (doesn't save registers since it is the |
|
* entry point when the UBL is found at the base of the NOR Flash and then |
|
* goes directly to the the boot() function, which is also naked). This setup |
|
* requires that the gnu compiler uses the -nostdlib option. |
|
*/ |
|
#if defined(FLASH_TYPE_NOR) |
|
__attribute__((naked, section(".selfcopy"))) void selfcopy(void); |
|
|
|
void |
|
selfcopy(void) |
|
{ |
|
volatile uint32_t *src = &(__selfcopysrc); |
|
volatile uint32_t *dest = &(__selfcopydest); |
|
volatile uint32_t *destend = &(__selfcopydestend); |
|
extern uint32_t __selfcopysrc, __selfcopydest, __selfcopydestend; |
|
|
|
/* Enable ITCM */ |
|
asm(" MRC p15, 0, r0, c9, c1, 1"); |
|
asm(" MOV r0, #0x1"); |
|
asm(" MCR p15, 0, r0, c9, c1, 1"); |
|
|
|
/* Enable DTCM */ |
|
asm(" MRC p15, 0, r0, c9, c1, 0"); |
|
asm(" MOV r0, #0x8000"); |
|
asm(" ORR r0, r0, #0x1"); |
|
asm(" MCR p15, 0, r0, c9, c1, 0"); |
|
|
|
/* Copy the words */ |
|
while (dest < destend) { |
|
*dest = *src; |
|
dest++; |
|
src++; |
|
} |
|
|
|
/* Jump to the normal entry point */ |
|
boot(); |
|
} |
|
|
|
__attribute__ ((naked, section(".fakeentry"))) void fake_entry(void); |
|
|
|
void |
|
fake_entry(void) |
|
{ |
|
boot(); |
|
} |
|
#endif /* FLASH_TYPE_NOR */
|
|
|