ubl/ubl.c

288 lines
6.2 KiB
C

/*
* 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;
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);
}
#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);
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);
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 */