2007-07-05 16:02:09 +00:00
|
|
|
#define DEBUG
|
2007-07-05 16:01:39 +00:00
|
|
|
|
|
|
|
#include <common.h>
|
2007-07-05 16:01:56 +00:00
|
|
|
#include <command.h>
|
|
|
|
#include <image.h>
|
2008-02-20 18:01:54 +00:00
|
|
|
#include <init.h>
|
2013-09-06 10:53:12 +00:00
|
|
|
#include <malloc.h>
|
2007-07-05 16:01:56 +00:00
|
|
|
#include <environment.h>
|
|
|
|
#include <asm/bitops.h>
|
2013-09-06 10:53:12 +00:00
|
|
|
#include <asm/processor.h>
|
2008-02-20 18:01:54 +00:00
|
|
|
#include <boot.h>
|
2007-07-05 16:02:09 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fs.h>
|
2007-07-05 16:01:39 +00:00
|
|
|
|
2013-09-06 10:53:12 +00:00
|
|
|
static int bootm_relocate_fdt(void *addr, struct image_data *data)
|
|
|
|
{
|
|
|
|
if (addr < LINUX_TLB1_MAX_ADDR) {
|
|
|
|
/* The kernel is within the boot TLB mapping.
|
|
|
|
* Put the DTB above if there is no space
|
|
|
|
* below.
|
|
|
|
*/
|
|
|
|
if (addr < (void *)data->oftree->totalsize) {
|
|
|
|
addr = (void *)PAGE_ALIGN((phys_addr_t)addr +
|
|
|
|
data->os->header.ih_size);
|
|
|
|
addr += data->oftree->totalsize;
|
|
|
|
if (addr < LINUX_TLB1_MAX_ADDR)
|
|
|
|
addr = LINUX_TLB1_MAX_ADDR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr > LINUX_TLB1_MAX_ADDR) {
|
|
|
|
pr_crit("Unable to relocate DTB to Linux TLB\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr = (void *)PAGE_ALIGN_DOWN((phys_addr_t)addr -
|
|
|
|
data->oftree->totalsize);
|
|
|
|
memcpy(addr, data->oftree, data->oftree->totalsize);
|
|
|
|
free(data->oftree);
|
|
|
|
data->oftree = addr;
|
|
|
|
|
|
|
|
pr_info("Relocating device tree to 0x%p\n", addr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-14 10:09:13 +00:00
|
|
|
static int do_bootm_linux(struct image_data *data)
|
2007-07-05 16:01:39 +00:00
|
|
|
{
|
2011-12-14 10:09:13 +00:00
|
|
|
void (*kernel)(void *, void *, unsigned long,
|
|
|
|
unsigned long, unsigned long);
|
2014-01-09 08:59:59 +00:00
|
|
|
int ret;
|
2007-07-05 16:02:09 +00:00
|
|
|
|
2014-01-09 08:59:59 +00:00
|
|
|
ret = bootm_load_os(data, data->os_address);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2011-12-06 07:53:26 +00:00
|
|
|
|
2013-03-03 13:04:57 +00:00
|
|
|
data->oftree = of_get_fixed_tree(data->of_root_node);
|
|
|
|
if (!data->oftree) {
|
|
|
|
pr_err("bootm: No devicetree given.\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2013-09-06 10:53:12 +00:00
|
|
|
/* Relocate the device tree if outside the initial
|
|
|
|
* Linux mapped TLB.
|
|
|
|
*/
|
|
|
|
if (IS_ENABLED(CONFIG_MPC85xx)) {
|
|
|
|
void *addr = data->oftree;
|
|
|
|
|
|
|
|
if ((addr + data->oftree->totalsize) > LINUX_TLB1_MAX_ADDR) {
|
|
|
|
addr = (void *)data->os_address;
|
|
|
|
|
|
|
|
if (bootm_relocate_fdt(addr, data))
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-03 13:04:57 +00:00
|
|
|
fdt_add_reserve_map(data->oftree);
|
|
|
|
|
2011-12-06 07:53:26 +00:00
|
|
|
kernel = (void *)(data->os_address + data->os_entry);
|
2007-07-05 16:01:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Linux Kernel Parameters (passing device tree):
|
|
|
|
* r3: ptr to OF flat tree, followed by the board info data
|
|
|
|
* r4: physical pointer to the kernel itself
|
|
|
|
* r5: NULL
|
|
|
|
* r6: NULL
|
|
|
|
* r7: NULL
|
|
|
|
*/
|
2011-12-14 10:09:13 +00:00
|
|
|
kernel(data->oftree, kernel, 0, 0, 0);
|
2007-07-05 16:01:39 +00:00
|
|
|
|
2007-07-05 19:43:36 +00:00
|
|
|
reset_cpu(0);
|
2007-07-05 16:02:17 +00:00
|
|
|
|
2013-09-06 10:53:12 +00:00
|
|
|
error:
|
2007-07-05 16:02:17 +00:00
|
|
|
return -1;
|
2007-07-05 16:01:39 +00:00
|
|
|
}
|
|
|
|
|
2008-02-20 18:01:54 +00:00
|
|
|
static struct image_handler handler = {
|
2011-12-06 07:53:26 +00:00
|
|
|
.name = "PowerPC Linux",
|
2008-02-20 18:01:54 +00:00
|
|
|
.bootm = do_bootm_linux,
|
2011-12-06 07:53:26 +00:00
|
|
|
.filetype = filetype_uimage,
|
|
|
|
.ih_os = IH_OS_LINUX,
|
2008-02-20 18:01:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int ppclinux_register_image_handler(void)
|
|
|
|
{
|
|
|
|
return register_image_handler(&handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
late_initcall(ppclinux_register_image_handler);
|