sdk-hwV1.3/lichee/brandy-2.0/spl/common/linux_loader.c

273 lines
8.0 KiB
C

#include <common.h>
#include <spare_head.h>
#include <android_image.h>
#include <private_uboot.h>
#ifdef CFG_SUNXI_FDT_ADDR
#ifdef CFG_RESERVE_FDT_SIZE
#include <libfdt.h>
#endif
#endif
#if 0
#define kernel_dbg(fmt, arg...) printf(fmt, ##arg)
#else
#define kernel_dbg(fmt, arg...)
#endif
#define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a)-1)
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define SUNXI_FLASH_READ_FIRST_SIZE (32 * 1024)
int exist_uboot_jmp_cardproduct(phys_addr_t uboot_base)
{
if (uboot_base) {
uboot_head_t *header = (uboot_head_t *)uboot_base;
/* fastboot scheme, uboot must jump to the card for mass production*/
printf("workmode 0x%x\n", header->boot_data.work_mode);
if (header->boot_data.work_mode == WORK_MODE_CARD_PRODUCT)
boot0_jmp(uboot_base);
}
return 0;
}
#ifdef CFG_SUNXI_SUPPORT_RAMDISK
int android_image_get_ramdisk(const struct andr_img_hdr *hdr, ulong *rd_data,
ulong *rd_len)
{
if (!hdr->ramdisk_size)
return -1;
*rd_data = (unsigned long)hdr;
*rd_data += hdr->page_size;
*rd_data += ALIGN(hdr->kernel_size, hdr->page_size);
*rd_len = hdr->ramdisk_size;
return 0;
}
#endif
#ifdef CFG_LOAD_DTB_FROM_KERNEL
extern __attribute__((section(".data"))) struct fdt_header *working_fdt;
int android_image_get_dtb(const struct andr_img_hdr *hdr,
ulong *dtb_data, ulong *dtb_len)
{
if (!hdr->dtb_size)
return -1;
*dtb_data = (unsigned long)hdr;
*dtb_data += hdr->page_size;
*dtb_data += ALIGN(hdr->kernel_size, hdr->page_size);
*dtb_data += ALIGN(hdr->ramdisk_size, hdr->page_size);
*dtb_data += ALIGN(hdr->second_size, hdr->page_size);
*dtb_data += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
*dtb_len = hdr->dtb_size;
return 0;
}
#endif
int sunxi_mem_info(unsigned long mem_addr, unsigned long mem_len,
unsigned long other_mem_addr, unsigned long other_mem_len)
{
/*
* | access target |
* | case 1|
* |case 2|
* |case 3|
* |case 4|
* |case 5|
* | case 6 |
* only 4 & 5 is ok
*/
int ret = 0;
if ((mem_addr >= other_mem_addr) && /*case 2 + case3*/
(mem_addr < other_mem_addr + other_mem_len)) {
ret = -1;
} else if ((mem_addr < other_mem_addr) && /*case 1*/
(mem_addr + mem_len >= other_mem_addr)) {
ret = -1;
} else if ((mem_addr < other_mem_addr) &&
(mem_addr + mem_len >=
other_mem_addr + other_mem_len)) { /*case 6*/
ret = -1;
}
return ret;
}
int load_bimage(u32 from_flash, u32 to_ddr,
int (*flash_read)(uint, uint, void *), u32 *kernel_addr)
{
int ret;
u32 rbytes = 0;
u32 rblock = 0;
u32 start_block = from_flash;
struct andr_img_hdr *fb_hdr;
void *addr = (void *)(phys_addr_t)to_ddr;
if (flash_read(start_block, (SUNXI_FLASH_READ_FIRST_SIZE / 512),
addr)) {
printf("Fail to load kernel head\n");
return -1;
}
fb_hdr = (struct andr_img_hdr *)addr;
if (!memcmp(fb_hdr->magic, ANDR_BOOT_MAGIC, 8)) {
kernel_dbg("kernel magic is ok\n");
kernel_dbg("kernel_size = 0x%x\n", fb_hdr->kernel_size);
kernel_dbg("ramdisk_size = 0x%x\n", fb_hdr->ramdisk_size);
rbytes = fb_hdr->kernel_size + fb_hdr->ramdisk_size +
fb_hdr->second_size + 4 * 1024 + 511;
} else {
printf("kernel magic is error\n");
return -1;
}
pr_emerg("kernel_addr:%x\n", fb_hdr->kernel_addr);
rblock = rbytes / 512 - SUNXI_FLASH_READ_FIRST_SIZE / 512;
start_block += SUNXI_FLASH_READ_FIRST_SIZE / 512;
addr = (void *)(phys_addr_t)((to_ddr) + SUNXI_FLASH_READ_FIRST_SIZE);
kernel_dbg("rblock=%d, start=%d\n", rblock, start_block);
ret = flash_read(start_block, rblock, addr);
if (ret) {
printf("load boot_image fail\n");
return -1;
}
kernel_dbg("boot:%x %x\n", to_ddr, rbytes);
#ifdef CFG_KERNEL_CHECKSUM
ret = verify_addsum_for_kernel((void *)to_ddr +
KERNEL_CODE_OFFSET_IN_BIMAGE,
fb_hdr->kernel_size, fb_hdr->checksum);
#endif
if (ret == 0) {
#define GZIP_MAGIC 0x8b1f
if (fb_hdr->kernel_addr !=
to_ddr + KERNEL_CODE_OFFSET_IN_BIMAGE) {
if (sunxi_mem_info((ulong)fb_hdr, rbytes,
fb_hdr->kernel_addr,
fb_hdr->kernel_size) < 0) {
printf("Warning:Please check memory !!!\n");
printf("boot.img:0x%lx-0x%lx\n", (ulong)fb_hdr,
(ulong)((ulong)fb_hdr + rbytes));
printf("kernel_code:0x%lx-0x%lx\n",
(ulong)fb_hdr->kernel_addr,
(ulong)(fb_hdr->kernel_addr +
fb_hdr->kernel_size));
}
#ifdef CFG_SUNXI_GUNZIP
if ((*(unsigned int *)(phys_addr_t)(to_ddr + KERNEL_CODE_OFFSET_IN_BIMAGE)
& 0xffff) == GZIP_MAGIC) {
int ret = 0;
ret = gunzip((char *)(phys_addr_t)fb_hdr->kernel_addr,
(fb_hdr->kernel_size * 3),
(unsigned char *)(phys_addr_t)(to_ddr + KERNEL_CODE_OFFSET_IN_BIMAGE),
(unsigned long *)&fb_hdr->kernel_size);
if (ret) {
printf("Error: gunzip returned %d\n", ret);
return -1;
}
} else
#endif
{
memcpy((void *)(phys_addr_t)fb_hdr->kernel_addr,
(void *)(phys_addr_t)(
to_ddr + KERNEL_CODE_OFFSET_IN_BIMAGE),
fb_hdr->kernel_size);
}
printf("kernel:%x %x\n", fb_hdr->kernel_addr,
fb_hdr->kernel_size);
}
#ifdef CFG_LOAD_DTB_FROM_KERNEL
kernel_dbg("dtb_size = 0x%x\n", fb_hdr->dtb_size);
kernel_dbg("dtb_addr = 0x%x\n", fb_hdr->dtb_addr);
working_fdt = (struct fdt_header *)CFG_SUNXI_FDT_ADDR;
if (fb_hdr->dtb_size) {
ulong dtb_data = 0, dtb_len = 0;
android_image_get_dtb(fb_hdr, &dtb_data, &dtb_len);
ret = flash_read(from_flash + (dtb_data - (unsigned long)fb_hdr)/512,
ALIGN(fb_hdr->dtb_size, 512)/512, (void *)CFG_SUNXI_FDT_ADDR);
if (ret) {
printf("load dtb fail\n");
return -1;
}
#ifdef CFG_SUNXI_FDT_ADDR
#ifdef CFG_RESERVE_FDT_SIZE
u32 fdt_ext_size = ALIGN(CFG_RESERVE_FDT_SIZE, 32);
u32 new_fdt_totalsize = fdt_totalsize(working_fdt);
if (new_fdt_totalsize > fdt_ext_size) {
printf("new fdt(0x%08x) biger than now fdt(0x%08x)\n",
new_fdt_totalsize, fdt_ext_size);
} else {
fdt_set_totalsize(working_fdt, fdt_ext_size);
}
#endif
#endif
}
#endif
#ifdef CFG_SUNXI_SUPPORT_RAMDISK
ulong rd_data, rd_len;
fb_hdr->ramdisk_addr = (ulong)CFG_RAMDISK_ADDR;
if (fb_hdr->ramdisk_size) {
android_image_get_ramdisk(fb_hdr, &rd_data, &rd_len);
if (sunxi_mem_info((ulong)fb_hdr, rbytes,
fb_hdr->ramdisk_addr,
fb_hdr->ramdisk_size) < 0) {
printf("Warning:Please check memory !!!\n");
printf("boot.img:0x%lx-0x%lx\n", (ulong)fb_hdr,
(ulong)((ulong)fb_hdr + rbytes));
printf("ramdisk:0x%lx-0x%lx\n",
(ulong)fb_hdr->ramdisk_addr,
(ulong)(fb_hdr->ramdisk_addr +
fb_hdr->ramdisk_size));
}
pr_emerg("load ramdisk from %0x to %x\n", rd_data, fb_hdr->ramdisk_addr);
memcpy((void *)(long)fb_hdr->ramdisk_addr,
(const void *)rd_data, rd_len);
/* ramdisk need to update dts, so load ramdisk after dtb*/
int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end);
ret = fdt_initrd((void *)CFG_SUNXI_FDT_ADDR, (ulong)fb_hdr->ramdisk_addr,
(ulong)(fb_hdr->ramdisk_addr + rd_len));
if (ret) {
pr_emerg("update initrd fail\n");
return -1;
}
}
#endif
}
*kernel_addr = fb_hdr->kernel_addr;
return ret == 0 ? 0 : -1;
}
#ifdef CFG_KERNEL_UIMAGE
int load_uimage(u32 from_flash, u32 to_ddr, u32 image_size_KB,
int (*flash_read)(uint, uint, void *), u32 *kernel_addr)
{
int ret;
u32 rbytes = (image_size_KB * 1024);
u32 rblock = 0;
u32 start_block = from_flash;
void *addr = (void *)(phys_addr_t)(to_ddr);
if (flash_read(start_block, (SUNXI_FLASH_READ_FIRST_SIZE / 512),
addr)) {
printf("Fail to load kernel head\n");
return -1;
}
rblock = rbytes / 512 - SUNXI_FLASH_READ_FIRST_SIZE / 512;
start_block += SUNXI_FLASH_READ_FIRST_SIZE / 512;
addr = (void *)(phys_addr_t)((to_ddr) + SUNXI_FLASH_READ_FIRST_SIZE);
kernel_dbg("rblock=%d, start=%d\n", rblock, start_block);
ret = flash_read(start_block, rblock, addr);
*kernel_addr = to_ddr + KERNEL_CODE_OFFSET_IN_UIMAGE;
return ret == 0 ? 0 : -1;
}
#endif