/* * ubl.c - main file * * 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" #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 */