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.
289 lines
6.3 KiB
289 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 */
|