273 lines
8.0 KiB
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
|