Commit 6963d520 authored by Henrik Nordstrom's avatar Henrik Nordstrom
Browse files

felboot: Small system initialization for FEL booting

parent a95d7e18
CC=gcc
BOARD=eoma68
CROSS_COMPILE=/home/henrik/toolchains/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
UBOOT=/home/henrik/SRC/u-boot/
UBOOTOBJ=$(UBOOT)build/$(BOARD)/
CFLAGS=-g -O2 -marm -mno-thumb-interwork -mabi=aapcs-linux -march=armv7-a -fno-common -ffixed-r8 -msoft-float -I$(UBOOTOBJ)include2 -I$(UBOOTOBJ)include -I$(UBOOT)include
all: fel-boot-$(BOARD).bin
UBOOT_OBJS= \
$(addprefix spl/arch/arm/cpu/armv7/sunxi/,clock.o pinmux.o dram.o board.o timer.o) \
spl/arch/arm/cpu/armv7/syslib.o \
spl/arch/arm/lib/eabi_compat.o \
spl/drivers/power/axp209.o \
spl/drivers/i2c/libi2c.o \
spl/common/memsize.o \
spl/board/sunxi/dram_$(BOARD).o
.c.o:
$(CROSS_COMPILE)$(CC) -c $(CFLAGS) $< -o $@
fel-boot-$(BOARD).elf: main.o util_printf.o early_print.o $(addprefix $(UBOOTOBJ),$(UBOOT_OBJS))
$(CROSS_COMPILE)$(CC) -Tfel-boot.ld -static -nostartfiles $(CFLAGS) -Wl,-Map=$@.map $^ -o $@
fel-boot-$(BOARD).bin: fel-boot-$(BOARD).elf
$(CROSS_COMPILE)objcopy -O binary $< $@
clean:
rm -f *.o *.map *.elf
fel-boot.bin is a FEL bootstrap program.
fel write 0x2000 fel-boot.bin
fel exe 0x2000
fel write 0x4a000000 u-boot.bin
fel exe 0x4a000000
optionally load kernel + initramfs before fel exe of u-boot
fel write 0x2000 fel-boot.bin
fel exe 0x2000
fel write 0x4a000000 u-boot.bin
fel write 0x43000000 ../script.bin
fel write 0x44000000 ../uImage
fel write 0x4c000000 ../initramfs.img
fel exe 0x4a000000
Build instructions:
1. You need to build u-boot sunxi-current SPL first for the same CPU generation, i.e. cubieboard.
Change the paths in Makefile to reflect where your copy of u-boot and toolchain is, or specify the paths when runnign make
make
To adopt for another board:
1a) If the board is supported by u-boot SPL then change UBOOT_OBJS to include the dram spefications for your board and remove dram.o from fel-boot.elf: line.
1b) Else update dram.c with the right parameters for your board.
2. Change early_printf.c to define the right UART number for your board.
3. make
#ifndef _COMMON_H
#define _COMMON_H
#include <stdint.h>
#define u32 uint32_t
#define u16 uint16_t
#define u8 uint8_t
#define s32 int32_t
#define s16 int16_t
#define s8 int8_t
#define __u8 u8
#define __u16 u16
#define __u32 u32
#define __s8 s8
#define __s16 s16
#define __s32 s32
#include "io.h"
#include "cpu.h"
#endif
/*
* (C) Copyright 2007-2011
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Tom Cubie <tangliang@allwinnertech.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef _SUNXI_CPU_H
#define _SUNXI_CPU_H
#define SUNXI_SRAM_A1_BASE 0X00000000
#define SUNXI_SRAM_A1_SIZE (16 * 1024) /* 16k */
#define SUNXI_SRAM_A2_BASE 0X00004000 /* 16k */
#define SUNXI_SRAM_A3_BASE 0X00008000 /* 13k */
#define SUNXI_SRAM_A4_BASE 0X0000B400 /* 3k */
#if 0
#define SUNXI_SRAM_NAND_BASE 0Xdeaddead /* 2k(address not available on spec) */
#endif
#define SUNXI_SRAM_D_BASE 0X01C00000
#define SUNXI_SRAM_B_BASE 0X01C00000 /* 64k(secure) */
#define SUNXI_SRAMC_BASE 0X01C00000
#define SUNXI_DRAMC_BASE 0X01C01000
#define SUNXI_DMA_BASE 0X01C02000
#define SUNXI_NFC_BASE 0X01C03000
#define SUNXI_TS_BASE 0X01C04000
#define SUNXI_SPI0_BASE 0X01C05000
#define SUNXI_SPI1_BASE 0X01C06000
#define SUNXI_MS_BASE 0X01C07000
#define SUNXI_TVD_BASE 0X01C08000
#define SUNXI_CSI0_BASE 0X01C09000
#define SUNXI_TVE0_BASE 0X01C0A000
#define SUNXI_EMAC_BASE 0X01C0B000
#define SUNXI_LCD0_BASE 0X01C0C000
#define SUNXI_LCD1_BASE 0X01C0D000
#define SUNXI_VE_BASE 0X01C0E000
#define SUNXI_MMC0_BASE 0X01C0F000
#define SUNXI_MMC1_BASE 0X01C10000
#define SUNXI_MMC2_BASE 0X01C11000
#define SUNXI_MMC3_BASE 0X01C12000
#define SUNXI_USB0_BASE 0X01C13000
#define SUNXI_USB1_BASE 0X01C14000
#define SUNXI_SS_BASE 0X01C15000
#define SUNXI_HDMI_BASE 0X01C16000
#define SUNXI_SPI2_BASE 0X01C17000
#define SUNXI_SATA_BASE 0X01C18000
#define SUNXI_PATA_BASE 0X01C19000
#define SUNXI_ACE_BASE 0X01C1A000
#define SUNXI_TVE1_BASE 0X01C1B000
#define SUNXI_USB2_BASE 0X01C1C000
#define SUNXI_CSI1_BASE 0X01C1D000
#define SUNXI_TZASC_BASE 0X01C1E000
#define SUNXI_SPI3_BASE 0X01C1F000
#define SUNXI_CCM_BASE 0X01C20000
#define SUNXI_INTC_BASE 0X01C20400
#define SUNXI_PIO_BASE 0X01C20800
#define SUNXI_TIMER_BASE 0X01C20C00
#define SUNXI_SPDIF_BASE 0X01C21000
#define SUNXI_AC97_BASE 0X01C21400
#define SUNXI_IR0_BASE 0X01C21800
#define SUNXI_IR1_BASE 0X01C21C00
#define SUNXI_IIS_BASE 0X01C22400
#define SUNXI_LRADC_BASE 0X01C22800
#define SUNXI_AD_DA_BASE 0X01C22C00
#define SUNXI_KEYPAD_BASE 0X01C23000
#define SUNXI_TZPC_BASE 0X01C23400
#define SUNXI_SID_BASE 0X01C23800
#define SUNXI_SJTAG_BASE 0X01C23C00
#define SUNXI_TP_BASE 0X01C25000
#define SUNXI_PMU_BASE 0X01C25400
#define SUNXI_UART0_BASE 0X01C28000
#define SUNXI_UART1_BASE 0X01C28400
#define SUNXI_UART2_BASE 0X01C28800
#define SUNXI_UART3_BASE 0X01C28C00
#define SUNXI_UART4_BASE 0X01C29000
#define SUNXI_UART5_BASE 0X01C29400
#define SUNXI_UART6_BASE 0X01C29800
#define SUNXI_UART7_BASE 0X01C29C00
#define SUNXI_PS2_0_BASE 0X01C2A000
#define SUNXI_PS2_1_BASE 0X01C2A400
#define SUNXI_TWI0_BASE 0X01C2AC00
#define SUNXI_TWI1_BASE 0X01C2B000
#define SUNXI_TWI2_BASE 0X01C2B400
#define SUNXI_CAN_BASE 0X01C2BC00
#define SUNXI_SCR_BASE 0X01C2C400
#define SUNXI_GPS_BASE 0X01C30000
#define SUNXI_MALI400_BASE 0X01C40000
#define SUNXI_SRAM_C_BASE 0X01D00000 /* module sram */
#define SUNXI_DE_FE0_BASE 0X01E00000
#define SUNXI_DE_FE1_BASE 0X01E20000
#define SUNXI_DE_BE0_BASE 0X01E60000
#define SUNXI_DE_BE1_BASE 0X01E40000
#define SUNXI_MP_BASE 0X01E80000
#define SUNXI_AVG_BASE 0X01EA0000
#define SUNXI_CSDM_BASE 0X3F500000 /* CoreSight Debug Module*/
#define SUNXI_DDRII_DDRIII_BASE 0X40000000 /* 2G */
#define SUNXI_BROM_BASE 0XFFFF0000 /* 32K */
#define SUNXI_CPU_CFG (SUNXI_TIMER_BASE + 0x13c)
#ifndef __ASSEMBLY__
/* boot type */
typedef enum {
SUNXI_BOOT_TYPE_NULL,
SUNXI_BOOT_TYPE_MMC0,
SUNXI_BOOT_TYPE_NAND,
SUNXI_BOOT_TYPE_MMC2,
SUNXI_BOOT_TYPE_SPI
} sunxi_boot_type_t;
sunxi_boot_type_t get_boot_type(void);
#endif /* __ASSEMBLY__ */
#endif /* _CPU_H */
/*
* (C) Copyright 2007-2012
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Tom Cubie <tangliang@allwinnertech.com>
*
* Early uart print for debugging.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include "config.h"
#include "common.h"
#include "early_print.h"
#include <asm/arch/gpio.h>
#include <asm/arch/clock.h>
static int uart_initialized = 0;
#define UART CONFIG_CONS_INDEX-1
void uart_init(void) {
/* select dll dlh */
writel(0x80, UART_LCR(UART));
/* set baudrate */
writel(0, UART_DLH(UART));
writel(BAUD_115200, UART_DLL(UART));
/* set line control */
writel(LC_8_N_1, UART_LCR(UART));
uart_initialized = 1;
}
#define TX_READY (readl(UART_LSR(UART)) & (1 << 6))
void uart_putc(char c) {
while(!TX_READY)
;
writel(c, UART_THR(UART));
}
void uart_puts(const char *s) {
while(*s)
uart_putc(*s++);
}
/*
* (C) Copyright 2007-2012
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Tom Cubie <tangliang@allwinnertech.com>
*
* Early uart print for debugging.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef _SUNXI_EARLY_PRINT_H
#define _SUNXI_EARLY_PRINT_H
#define SUNXI_UART_BASE SUNXI_UART0_BASE
#define UART_RBR(n) (SUNXI_UART_BASE + (n)*0x400 + 0x0) /* receive buffer register */
#define UART_THR(n) (SUNXI_UART_BASE + (n)*0x400 + 0x0) /* transmit holding register */
#define UART_DLL(n) (SUNXI_UART_BASE + (n)*0x400 + 0x0) /* divisor latch low register */
#define UART_DLH(n) (SUNXI_UART_BASE + (n)*0x400 + 0x4) /* divisor latch high register */
#define UART_IER(n) (SUNXI_UART_BASE + (n)*0x400 + 0x4) /* interrupt enable reigster */
#define UART_IIR(n) (SUNXI_UART_BASE + (n)*0x400 + 0x8) /* interrupt identity register */
#define UART_FCR(n) (SUNXI_UART_BASE + (n)*0x400 + 0x8) /* fifo control register */
#define UART_LCR(n) (SUNXI_UART_BASE + (n)*0x400 + 0xc) /* line control register */
#define UART_LSR(n) (SUNXI_UART_BASE + (n)*0x400 + 0x14) /* line status register */
#define UART_RBR(n) (SUNXI_UART_BASE + (n)*0x400 + 0x0) /* receive buffer register */
#define UART_THR(n) (SUNXI_UART_BASE + (n)*0x400 + 0x0) /* transmit holding register */
#define UART_DLL(n) (SUNXI_UART_BASE + (n)*0x400 + 0x0) /* divisor latch low register */
#define BAUD_115200 (0xD) /* 24 * 1000 * 1000 / 16 / 115200 = 13 */
#define NO_PARITY (0)
#define ONE_STOP_BIT (0)
#define DAT_LEN_8_BITS (3)
#define LC_8_N_1 (NO_PARITY << 3 | ONE_STOP_BIT << 2 | DAT_LEN_8_BITS)
#ifndef __ASSEMBLY__
void uart_init(void);
void uart_putc(char c);
void uart_puts(const char *s);
#endif /* __ASSEMBLY__ */
#endif /* _SUNXI_EARLY_PRINT_H */
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00002000;
. = ALIGN(4);
.text :
{
main.o (.text*)
*(.text*)
}
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : {
*(.data*)
}
. = ALIGN(4);
. = .;
. = ALIGN(4);
.rel.dyn : {
__rel_dyn_start = .;
*(.rel*)
__rel_dyn_end = .;
}
.dynsym : {
__dynsym_start = .;
*(.dynsym)
}
. = ALIGN(4);
.note.gnu.build-id :
{
*(.note.gnu.build-id)
}
_end = .;
. = ALIGN(4096);
.mmutable : {
*(.mmutable)
}
.bss_start __rel_dyn_start (OVERLAY) : {
KEEP(*(.__bss_start));
__bss_base = .;
}
.bss __bss_base (OVERLAY) : {
*(.bss*)
. = ALIGN(4);
__bss_limit = .;
}
.bss_end __bss_limit (OVERLAY) : {
KEEP(*(.__bss_end));
}
/DISCARD/ : { *(.dynstr*) }
/DISCARD/ : { *(.dynamic*) }
/DISCARD/ : { *(.plt*) }
/DISCARD/ : { *(.interp*) }
/DISCARD/ : { *(.gnu*) }
/DISCARD/ : { *(.note*) }
}
#define __arch_getb(a) (*(volatile unsigned char *)(a))
#define __arch_getw(a) (*(volatile unsigned short *)(a))
#define __arch_getl(a) (*(volatile unsigned int *)(a))
#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v))
#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v))
#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v))
#define dmb() __asm__ __volatile__ ("" : : : "memory")
#define __iormb() dmb()
#define __iowmb() dmb()
#define writeb(v,c) ({ u8 __v = v; __iowmb(); __arch_putb(__v,c); __v; })
#define writew(v,c) ({ u16 __v = v; __iowmb(); __arch_putw(__v,c); __v; })
#define writel(v,c) ({ u32 __v = v; __iowmb(); __arch_putl(__v,c); __v; })
#define readb(c) ({ u8 __v = __arch_getb(c); __iormb(); __v; })
#define readw(c) ({ u16 __v = __arch_getw(c); __iormb(); __v; })
#define readl(c) ({ u32 __v = __arch_getl(c); __iormb(); __v; })
void _start(void)
{
clock_init();
gpio_init();
uart_init();
s_init();
}
void dcache_enable(void)
{
}
void sunxi_wemac_initialize(void)
{
}
void *gd;
int gdata;
void preloader_console_init(void)
{
}
void hang(void)
{
printf("Please reset the board!");
}
void udelay(unsigned long usec)
{
__udelay(usec);
}
void sunxi_board_init(void)
{
int power_failed = 1;
int ramsize;
timer_init();
printf("DRAM:");
ramsize = sunxi_dram_init();
if (!ramsize) {
printf(" ?");
ramsize = sunxi_dram_init();
}
if (!ramsize) {
printf(" ?");
ramsize = sunxi_dram_init();
}
printf(" %dMB\n", ramsize>>20);
if (!ramsize)
hang();
#ifdef CONFIG_AXP209_POWER
power_failed |= axp209_init();
power_failed |= axp209_set_dcdc2(1400);
power_failed |= axp209_set_dcdc3(1250);
power_failed |= axp209_set_ldo2(3000);
power_failed |= axp209_set_ldo3(2800);
power_failed |= axp209_set_ldo4(2800);
#endif
/*
* Only clock up the CPU to full speed if we are reasonably
* assured it's being powered with suitable core voltage
*/
if (!power_failed)
clock_set_pll1(1008000000);
}
#!/bin/sh -ex
fel write 0x2000 fel-boot-${1}.bin
fel exe 0x2000
fel write 0x4a000000 ../u-boot.bin
fel exe 0x4a000000
#!/bin/sh -ex
fel write 0x2000 fel-boot-${1}.bin
fel exe 0x2000
fel write 0x4a000000 ../u-boot.bin
fel write 0x43000000 ../script.bin
fel write 0x44000000 ../uImage
fel write 0x4c000000 ../initramfs.img
fel exe 0x4a000000
/*
*/
#include <stdarg.h>
#include "early_print.h"
/* Debug uart have been init by boot rom. */
void put_char(char ch)
{
uart_putc(ch);
}
static void printchar(char **str, int c)
{
if (str) {
**str = c;
++(*str);
}
else {
put_char(c);
}
}
#define PAD_RIGHT 1
#define PAD_ZERO 2
static int prints(char **out, const char *string, int width, int pad)
{
register int pc = 0, padchar = ' ';
if (width > 0) {
register int len = 0;
register const char *ptr;
for (ptr = string; *ptr; ++ptr) ++len;
if (len >= width) width = 0;
else width -= len;
if (pad & PAD_ZERO) padchar = '0';
}
if (!(pad & PAD_RIGHT)) {
for ( ; width > 0; --width) {
printchar (out, padchar);
++pc;
}
}
for ( ; *string ; ++string) {
printchar (out, *string);
++pc;
}
for ( ; width > 0; --width) {
printchar (out, padchar);
++pc;
}
return pc;
}
/* the following should be enough for 32 bit int */
#define PRINT_BUF_LEN 12
static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase)
{
char print_buf[PRINT_BUF_LEN];
register char *s;
register int t, neg = 0, pc = 0;
register unsigned int u = i;
if (i == 0) {
print_buf[0] = '0';
print_buf[1] = '\0';
return prints (out, print_buf, width, pad);
}
if (sg && b == 10 && i < 0) {
neg = 1;
u = -i;
}
s = print_buf + PRINT_BUF_LEN-1;
*s = '\0';
while (u) {
t = u % b;
if( t >= 10 )
t += letbase - '0' - 10;
*--s = t + '0';
u /= b;
}
if (neg) {
if( width && (pad & PAD_ZERO) ) {
printchar (out, '-');
++pc;
--width;
}
else {
*--s = '-';
}
}
return pc + prints (out, s, width, pad);
}
static int print(char **out, const char *format, va_list args )
{
register int width, pad;
register int pc = 0;
char scr[2];
for (; *format != 0; format++) {
if (*format == '%') {
++format;
width = pad = 0;
if (*format == '\0') break;
if (*format == '%') goto out;
if (*format == '-') {
++format;
pad = PAD_RIGHT;
}
while (*format == '0') {
++format;
pad |= PAD_ZERO;
}
for ( ; *format >= '0' && *format <= '9'; ++format) {
width *= 10;
width += *format - '0';
}
if( *format == 's' ) {
register char *s = (char *)va_arg( args, int );
pc += prints (out, s?s:"(null)", width, pad);
continue;
}
if( *format == 'd' ) {
pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a');
continue;
}
if( *format == 'x' ) {
pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a');
continue;
}
if( *format == 'X' ) {
pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A');
continue;
}
if( *format == 'u' ) {
pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a');
continue;
}
if( *format == 'c' ) {
/* char are converted to int then pushed on the stack */
scr[0] = (char)va_arg( args, int );
scr[1] = '\0';
pc += prints (out, scr, width, pad);
continue;
}
}
else {
out:
printchar (out, *format);
++pc;
}
}
if (out) **out = '\0';
va_end( args );
return pc;
}
int sprintf(char *out, const char *format, ...)
{
va_list args;
va_start( args, format );
return print( &out, format, args );
}
int printf(const char *format, ...)
{
va_list args;
va_start( args, format );
return print( 0, format, args );
}
int printu(const char *format, ...)
{
va_list args;
va_start( args, format );
return print( 0, format, args );
}
void puts ( char * str )
{
int i=0;
while(str[i] != 0)
{
put_char(str[i]);
i++;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment