Commit 8a4ec5d7 authored by Yuri Tikhonov's avatar Yuri Tikhonov

RT #112561. Add ARM flat device tree support

This is a back-port of the following patch-set:
http://lists.denx.de/pipermail/u-boot/2010-October/079297.htmlSigned-off-by: default avatarYuri Tikhonov <yur@emcraft.com>
parent a82c1ae6
......@@ -2242,6 +2242,19 @@ Configuration Settings:
all data for the Linux kernel must be between "bootm_low"
and "bootm_low" + CONFIG_SYS_BOOTMAPSZ.
- CONFIG_SYS_BOOT_RAMDISK_HIGH:
Enable initrd_high functionality. If defined then the
initrd_high feature is enabled and the bootm ramdisk subcommand
is enabled.
- CONFIG_SYS_BOOT_GET_CMDLINE:
Enables allocating and saving kernel cmdline in space between
"bootm_low" and "bootm_low" + BOOTMAPSZ.
- CONFIG_SYS_BOOT_GET_KBD:
Enables allocating and saving a kernel copy of the bd_info in
space between "bootm_low" and "bootm_low" + BOOTMAPSZ.
- CONFIG_SYS_MAX_FLASH_BANKS:
Max number of Flash memory banks
......
......@@ -304,7 +304,6 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
}
#if defined(CONFIG_OF_LIBFDT)
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC)
/* find flattened device tree */
ret = boot_get_fdt (flag, argc, argv, &images,
&images.ft_addr, &images.ft_len);
......@@ -314,7 +313,6 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
}
set_working_fdt_addr(images.ft_addr);
#endif
#endif
}
......@@ -467,7 +465,7 @@ static int bootm_start_standalone(ulong iflag, int argc, char *argv[])
cmd_tbl_t cmd_bootm_sub[] = {
U_BOOT_CMD_MKENT(start, 0, 1, (void *)BOOTM_STATE_START, "", ""),
U_BOOT_CMD_MKENT(loados, 0, 1, (void *)BOOTM_STATE_LOADOS, "", ""),
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC)
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
U_BOOT_CMD_MKENT(ramdisk, 0, 1, (void *)BOOTM_STATE_RAMDISK, "", ""),
#endif
#ifdef CONFIG_OF_LIBFDT
......@@ -526,7 +524,7 @@ int do_bootm_subcommand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
lmb_reserve(&images.lmb, images.os.load,
(load_end - images.os.load));
break;
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC)
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
case BOOTM_STATE_RAMDISK:
{
ulong rd_len = images.rd_end - images.rd_start;
......
......@@ -360,11 +360,40 @@ void do_fixup_by_compat_u32(void *fdt, const char *compat,
do_fixup_by_compat(fdt, compat, prop, &val, 4, create);
}
int fdt_fixup_memory(void *blob, u64 start, u64 size)
/*
* Get cells len in bytes
* if #NNNN-cells property is 2 then len is 8
* otherwise len is 4
*/
static int get_cells_len(void *blob, char *nr_cells_name)
{
const u32 *cell;
cell = fdt_getprop(blob, 0, nr_cells_name, NULL);
if (cell && *cell == 2)
return 8;
return 4;
}
/*
* Write a 4 or 8 byte big endian cell
*/
static void write_cell(u8 *addr, u64 val, int size)
{
int err, nodeoffset, len = 0;
u8 tmp[16];
const u32 *addrcell, *sizecell;
int shift = (size - 1) * 8;
while (size-- > 0) {
*addr++ = (val >> shift) & 0xff;
shift -= 8;
}
}
int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
{
int err, nodeoffset;
int addr_cell_len, size_cell_len, len;
u8 tmp[banks * 8];
int bank;
err = fdt_check_header(blob);
if (err < 0) {
......@@ -389,44 +418,15 @@ int fdt_fixup_memory(void *blob, u64 start, u64 size)
return err;
}
addrcell = fdt_getprop(blob, 0, "#address-cells", NULL);
/* use shifts and mask to ensure endianness */
if ((addrcell) && (*addrcell == 2)) {
tmp[0] = (start >> 56) & 0xff;
tmp[1] = (start >> 48) & 0xff;
tmp[2] = (start >> 40) & 0xff;
tmp[3] = (start >> 32) & 0xff;
tmp[4] = (start >> 24) & 0xff;
tmp[5] = (start >> 16) & 0xff;
tmp[6] = (start >> 8) & 0xff;
tmp[7] = (start ) & 0xff;
len = 8;
} else {
tmp[0] = (start >> 24) & 0xff;
tmp[1] = (start >> 16) & 0xff;
tmp[2] = (start >> 8) & 0xff;
tmp[3] = (start ) & 0xff;
len = 4;
}
addr_cell_len = get_cells_len(blob, "#address-cells");
size_cell_len = get_cells_len(blob, "#size-cells");
sizecell = fdt_getprop(blob, 0, "#size-cells", NULL);
/* use shifts and mask to ensure endianness */
if ((sizecell) && (*sizecell == 2)) {
tmp[0+len] = (size >> 56) & 0xff;
tmp[1+len] = (size >> 48) & 0xff;
tmp[2+len] = (size >> 40) & 0xff;
tmp[3+len] = (size >> 32) & 0xff;
tmp[4+len] = (size >> 24) & 0xff;
tmp[5+len] = (size >> 16) & 0xff;
tmp[6+len] = (size >> 8) & 0xff;
tmp[7+len] = (size ) & 0xff;
len += 8;
} else {
tmp[0+len] = (size >> 24) & 0xff;
tmp[1+len] = (size >> 16) & 0xff;
tmp[2+len] = (size >> 8) & 0xff;
tmp[3+len] = (size ) & 0xff;
len += 4;
for (bank = 0, len = 0; bank < banks; bank++) {
write_cell(tmp + len, start[bank], addr_cell_len);
len += addr_cell_len;
write_cell(tmp + len, size[bank], size_cell_len);
len += size_cell_len;
}
err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
......@@ -438,6 +438,11 @@ int fdt_fixup_memory(void *blob, u64 start, u64 size)
return 0;
}
int fdt_fixup_memory(void *blob, u64 start, u64 size)
{
return fdt_fixup_memory_banks(blob, &start, &size, 1);
}
void fdt_fixup_ethernet(void *fdt)
{
int node, i, j;
......
......@@ -983,7 +983,7 @@ int boot_get_ramdisk (int argc, char *argv[], bootm_headers_t *images,
return 0;
}
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC)
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
/**
* boot_ramdisk_high - relocate init ramdisk
* @lmb: pointer to lmb handle, will be used for memory mgmt
......@@ -1072,7 +1072,7 @@ int boot_ramdisk_high (struct lmb *lmb, ulong rd_data, ulong rd_len,
error:
return -1;
}
#endif /* defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC) */
#endif /* CONFIG_SYS_BOOT_RAMDISK_HIGH */
#ifdef CONFIG_OF_LIBFDT
static void fdt_error (const char *msg)
......@@ -1242,7 +1242,7 @@ int boot_relocate_fdt (struct lmb *lmb, ulong bootmap_base,
*of_size = of_len;
} else {
*of_flat_tree = fdt_blob;
of_len = (CONFIG_SYS_BOOTMAPSZ + bootmap_base) - (ulong)fdt_blob;
of_len = *of_size + CONFIG_SYS_FDT_PAD;
lmb_reserve(lmb, (ulong)fdt_blob, of_len);
fdt_set_totalsize(*of_flat_tree, of_len);
......@@ -1550,7 +1550,7 @@ int boot_get_fdt (int flag, int argc, char *argv[], bootm_headers_t *images,
goto error;
}
if (be32_to_cpu (fdt_totalsize (fdt_blob)) != fdt_len) {
if (fdt_totalsize(fdt_blob) != fdt_len) {
fdt_error ("fdt size != image size");
goto error;
}
......@@ -1564,7 +1564,7 @@ int boot_get_fdt (int flag, int argc, char *argv[], bootm_headers_t *images,
}
*of_flat_tree = fdt_blob;
*of_size = be32_to_cpu (fdt_totalsize (fdt_blob));
*of_size = fdt_totalsize(fdt_blob);
debug (" of_flat_tree at 0x%08lx size 0x%08lx\n",
(ulong)*of_flat_tree, *of_size);
......@@ -1577,7 +1577,7 @@ error:
}
#endif /* CONFIG_OF_LIBFDT */
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
#ifdef CONFIG_SYS_BOOT_GET_CMDLINE
/**
* boot_get_cmdline - allocate and initialize kernel cmdline
* @lmb: pointer to lmb handle, will be used for memory mgmt
......@@ -1619,7 +1619,9 @@ int boot_get_cmdline (struct lmb *lmb, ulong *cmd_start, ulong *cmd_end,
return 0;
}
#endif /* CONFIG_SYS_BOOT_GET_CMDLINE */
#ifdef CONFIG_SYS_BOOT_GET_KBD
/**
* boot_get_kbd - allocate and initialize kernel copy of board info
* @lmb: pointer to lmb handle, will be used for memory mgmt
......@@ -1652,7 +1654,7 @@ int boot_get_kbd (struct lmb *lmb, bd_t **kbd, ulong bootmap_base)
return 0;
}
#endif /* CONFIG_PPC || CONFIG_M68K */
#endif /* CONFIG_SYS_BOOT_GET_KBD */
#endif /* !USE_HOSTCC */
#if defined(CONFIG_FIT)
......
......@@ -23,5 +23,7 @@
/* Relocation to SDRAM works on all ARM boards */
#define CONFIG_RELOC_FIXUP_WORKS
#define CONFIG_LMB
#define CONFIG_SYS_BOOT_RAMDISK_HIGH
#endif
......@@ -22,5 +22,8 @@
#define _ASM_CONFIG_H_
#define CONFIG_LMB
#define CONFIG_SYS_BOOT_RAMDISK_HIGH
#define CONFIG_SYS_BOOT_GET_CMDLINE
#define CONFIG_SYS_BOOT_GET_KBD
#endif
......@@ -22,6 +22,9 @@
#define _ASM_CONFIG_H_
#define CONFIG_LMB
#define CONFIG_SYS_BOOT_RAMDISK_HIGH
#define CONFIG_SYS_BOOT_GET_CMDLINE
#define CONFIG_SYS_BOOT_GET_KBD
#ifndef CONFIG_MAX_MEM_MAPPED
#if defined(CONFIG_4xx) || defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
......
......@@ -22,5 +22,6 @@
#define _ASM_CONFIG_H_
#define CONFIG_LMB
#define CONFIG_SYS_BOOT_RAMDISK_HIGH
#endif
......@@ -53,6 +53,15 @@
#undef CONFIG_USE_IRQ /* no support for IRQs */
#define CONFIG_MISC_INIT_R
#define CONFIG_OF_LIBFDT 1
/*
* The early kernel mapping on ARM currently only maps from the base of DRAM
* to the end of the kernel image. The kernel is loaded at DRAM base + 0x8000.
* The early kernel pagetable uses DRAM base + 0x4000 to DRAM base + 0x8000,
* so that leaves DRAM base to DRAM base + 0x4000 available.
*/
#define CONFIG_SYS_BOOTMAPSZ 0x4000
#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_INITRD_TAG 1
......
......@@ -48,6 +48,7 @@ void do_fixup_by_compat(void *fdt, const char *compat,
void do_fixup_by_compat_u32(void *fdt, const char *compat,
const char *prop, u32 val, int create);
int fdt_fixup_memory(void *blob, u64 start, u64 size);
int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks);
void fdt_fixup_ethernet(void *fdt);
int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
const void *val, int len, int create);
......
......@@ -340,14 +340,17 @@ int boot_relocate_fdt (struct lmb *lmb, ulong bootmap_base,
char **of_flat_tree, ulong *of_size);
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
int boot_ramdisk_high (struct lmb *lmb, ulong rd_data, ulong rd_len,
ulong *initrd_start, ulong *initrd_end);
#endif /* CONFIG_SYS_BOOT_RAMDISK_HIGH */
#ifdef CONFIG_SYS_BOOT_GET_CMDLINE
int boot_get_cmdline (struct lmb *lmb, ulong *cmd_start, ulong *cmd_end,
ulong bootmap_base);
#endif /* CONFIG_SYS_BOOT_GET_CMDLINE */
#ifdef CONFIG_SYS_BOOT_GET_KBD
int boot_get_kbd (struct lmb *lmb, bd_t **kbd, ulong bootmap_base);
#endif /* CONFIG_PPC || CONFIG_M68K */
#endif /* CONFIG_SYS_BOOT_GET_KBD */
#endif /* !USE_HOSTCC */
/*******************************************************************/
......
......@@ -26,6 +26,9 @@
#include <image.h>
#include <u-boot/zlib.h>
#include <asm/byteorder.h>
#include <fdt.h>
#include <libfdt.h>
#include <fdt_support.h>
DECLARE_GLOBAL_DATA_PTR;
......@@ -61,12 +64,52 @@ static void setup_dmamem_tag (void);
static struct tag *params;
#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
static ulong get_sp(void);
#if defined(CONFIG_OF_LIBFDT)
static int bootm_linux_fdt(int machid, bootm_headers_t *images);
#endif
void arch_lmb_reserve(struct lmb *lmb)
{
ulong sp;
/*
* Booting a (Linux) kernel image
*
* Allocate space for command line and board info - the
* address should be as high as possible within the reach of
* the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused
* memory, which means far enough below the current stack
* pointer.
*/
sp = get_sp();
debug("## Current stack ends at 0x%08lx ", sp);
/* adjust sp by 1K to be safe */
sp -= 1024;
lmb_reserve(lmb, sp,
gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp);
}
static void announce_and_cleanup(void)
{
printf("\nStarting kernel ...\n\n");
#ifdef CONFIG_USB_DEVICE
{
extern void udc_disconnect(void);
udc_disconnect();
}
#endif
cleanup_before_linux();
}
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
bd_t *bd = gd->bd;
char *s;
int machid = bd->bi_arch_number;
void (*theKernel)(int zero, int arch, uint params);
void (*kernel_entry)(int zero, int arch, uint params);
#ifdef CONFIG_CMDLINE_TAG
char *commandline = getenv ("bootargs");
......@@ -75,8 +118,6 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;
theKernel = (void (*)(int, int, uint))images->ep;
s = getenv ("machid");
if (s) {
machid = simple_strtoul (s, NULL, 16);
......@@ -85,8 +126,15 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
show_boot_progress (15);
#ifdef CONFIG_OF_LIBFDT
if (images->ft_len)
return bootm_linux_fdt(machid, images);
#endif
kernel_entry = (void (*)(int, int, uint))images->ep;
debug ("## Transferring control to Linux (at address %08lx) ...\n",
(ulong) theKernel);
(ulong) kernel_entry);
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
......@@ -119,27 +167,74 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
#ifdef CONFIG_DMAMEM_TAG
setup_dmamem_tag();
#endif
setup_end_tag (bd);
setup_end_tag(bd);
#endif
/* we assume that the kernel is in place */
printf ("\nStarting kernel ...\n\n");
announce_and_cleanup();
#ifdef CONFIG_USB_DEVICE
{
extern void udc_disconnect (void);
udc_disconnect ();
kernel_entry(0, machid, bd->bi_boot_params);
/* does not return */
return 1;
}
#if defined(CONFIG_OF_LIBFDT)
static int fixup_memory_node(void *blob)
{
bd_t *bd = gd->bd;
int bank;
u64 start[CONFIG_NR_DRAM_BANKS];
u64 size[CONFIG_NR_DRAM_BANKS];
for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
start[bank] = bd->bi_dram[bank].start;
size[bank] = bd->bi_dram[bank].size;
}
#endif
cleanup_before_linux ();
return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
}
static int bootm_linux_fdt(int machid, bootm_headers_t *images)
{
ulong rd_len;
void (*kernel_entry)(int zero, int dt_machid, void *dtblob);
ulong bootmap_base = getenv_bootm_low();
ulong of_size = images->ft_len;
char **of_flat_tree = &images->ft_addr;
ulong *initrd_start = &images->initrd_start;
ulong *initrd_end = &images->initrd_end;
struct lmb *lmb = &images->lmb;
int ret;
kernel_entry = (void (*)(int, int, void *))images->ep;
rd_len = images->rd_end - images->rd_start;
ret = boot_ramdisk_high(lmb, images->rd_start, rd_len,
initrd_start, initrd_end);
if (ret)
return ret;
theKernel (0, machid, bd->bi_boot_params);
ret = boot_relocate_fdt(lmb, bootmap_base, of_flat_tree, &of_size);
if (ret)
return ret;
debug("## Transferring control to Linux (at address %08lx) ...\n",
(ulong) kernel_entry);
fdt_chosen(*of_flat_tree, 1);
fixup_memory_node(*of_flat_tree);
fdt_initrd(*of_flat_tree, *initrd_start, *initrd_end, 1);
announce_and_cleanup();
kernel_entry(0, machid, *of_flat_tree);
/* does not return */
return 1;
}
#endif
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
......@@ -313,4 +408,12 @@ static void setup_end_tag (bd_t *bd)
params->hdr.size = 0;
}
static ulong get_sp(void)
{
ulong ret;
asm("mov %0, sp" : "=r"(ret) : );
return ret;
}
#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
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