diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index d2b33cffb7..bd58ed93b6 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -192,6 +192,12 @@ config ROCKCHIP_RESOURCE_IMAGE This enables support to get dtb or logo files from rockchip resource image format partition. +config ROCKCHIP_PARTITION_BOOT + bool "Enable support for booting system from rockchip format partition" + depends on ROCKCHIP_RESOURCE_IMAGE + help + This enables support for bootimg system from rockchip format partition + source "arch/arm/mach-rockchip/rk3036/Kconfig" source "arch/arm/mach-rockchip/rk3188/Kconfig" source "arch/arm/mach-rockchip/rk322x/Kconfig" diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile index b55985f0fb..aac2d4418d 100644 --- a/arch/arm/mach-rockchip/Makefile +++ b/arch/arm/mach-rockchip/Makefile @@ -26,6 +26,7 @@ ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) obj-$(CONFIG_ROCKCHIP_BLOCK_API) += blk.o obj-$(CONFIG_ROCKCHIP_PARAM) += rockchip_parameter.o obj-$(CONFIG_ROCKCHIP_RESOURCE_IMAGE) += resource_img.o +obj-$(CONFIG_ROCKCHIP_PARTITION_BOOT) += bootrkp.o obj-$(CONFIG_ROCKCHIP_RK3188) += rk3188-board.o obj-$(CONFIG_ROCKCHIP_RK322X) += rk322x-board.o obj-$(CONFIG_ROCKCHIP_RK3288) += rk3288-board.o diff --git a/arch/arm/mach-rockchip/bootrkp.c b/arch/arm/mach-rockchip/bootrkp.c new file mode 100644 index 0000000000..b9ef47fc6d --- /dev/null +++ b/arch/arm/mach-rockchip/bootrkp.c @@ -0,0 +1,200 @@ +/* + * (C) Copyright 2017 Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include "rockchip_parameter.h" +#include "rockchip_blk.h" + +#define TAG_KERNEL 0x4C4E524B + +#define PART_MISC "misc" +#define PART_KERNEL "kernel" +#define PART_BOOT "boot" +#define PART_RECOVERY "recovery" + +#define DTB_FILE "rk-kernel.dtb" + +#define BOOTLOADER_MESSAGE_OFFSET_IN_MISC (16 * 1024) +#define BOOTLOADER_MESSAGE_BLK_OFFSET (BOOTLOADER_MESSAGE_OFFSET_IN_MISC >> 9) + +enum android_boot_mode { + ANDROID_BOOT_MODE_NORMAL = 0, + + /* "recovery" mode is triggered by the "reboot recovery" command or + * equivalent adb/fastboot command. It can also be triggered by writing + * "boot-recovery" in the BCB message. This mode should boot the + * recovery kernel. + */ + ANDROID_BOOT_MODE_RECOVERY, + + /* "bootloader" mode is triggered by the "reboot bootloader" command or + * equivalent adb/fastboot command. It can also be triggered by writing + * "bootonce-bootloader" in the BCB message. This mode should boot into + * fastboot. + */ + ANDROID_BOOT_MODE_BOOTLOADER, +}; + +struct bootloader_message { + char command[32]; + char status[32]; + char recovery[768]; + + /* + * The 'recovery' field used to be 1024 bytes. It has only ever + * been used to store the recovery command line, so 768 bytes + * should be plenty. We carve off the last 256 bytes to store the + * stage string (for multistage packages) and possible future + * expansion. + */ + char stage[32]; + char slot_suffix[32]; + char reserved[192]; +}; + +struct rockchip_image { + uint32_t tag; + uint32_t size; + int8_t image[1]; + uint32_t crc; +}; + +static int read_boot_mode_from_misc(struct blk_part *misc) +{ + struct bootloader_message *bmsg; + int size = DIV_ROUND_UP(sizeof(struct bootloader_message), + RK_BLK_SIZE) * RK_BLK_SIZE; + int ret = 0; + + bmsg = memalign(ARCH_DMA_MINALIGN, size); + ret = blkdev_read(bmsg, misc->from + BOOTLOADER_MESSAGE_BLK_OFFSET, + size >> 9); + if (ret < 0) + goto out; + + if (!strcmp(bmsg->command, "boot-recovery")) { + printf("boot mode: recovery\n"); + ret = ANDROID_BOOT_MODE_RECOVERY; + } else { + printf("boot mode: normal\n"); + ret = ANDROID_BOOT_MODE_NORMAL; + } + +out: + free(bmsg); + return ret; +} + +/* + * non-OTA packaged kernel.img & boot.img + * return the image size on success, and a + * negative value on error. + */ +static int read_rockchip_image(struct blk_part *part, void *dst) +{ + struct rockchip_image *img; + int header_len = 8; + int cnt; + int ret; + + img = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE); + if (!img) { + printf("out of memory\n"); + return -ENOMEM; + } + + /* read first block with header imformation */ + ret = blkdev_read(img, part->from, 1); + if (ret < 0) + goto err; + if (img->tag != TAG_KERNEL) { + printf("%s: invalid image tag\n", part->name); + goto err; + } + + memcpy(dst, img->image, RK_BLK_SIZE - header_len); + /* + * read the rest blks + * total size = image size + 8 bytes header + 4 bytes crc32 + */ + cnt = DIV_ROUND_UP(img->size + 8 + 4, RK_BLK_SIZE); + ret = blkdev_read(dst + RK_BLK_SIZE - header_len, + part->from + 1, cnt - 1); + if (!ret) + ret = img->size; +err: + free(img); + return ret; +} + +static int do_bootrkp(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + ulong fdt_addr_r = env_get_ulong("fdt_addr_r", 16, 0); + ulong ramdisk_addr_r = env_get_ulong("ramdisk_addr_r", 16, 0); + ulong kernel_addr_r = env_get_ulong("kernel_addr_r", 16, 0x480000); + struct blk_part *boot; + struct blk_part *kernel; + struct blk_part *misc; + int ramdisk_size; + int kernel_size; + int fdt_size; + int boot_mode; + int ret = 0; + char cmdbuf[64]; + + misc = rockchip_get_blk_part(PART_MISC); + if (misc) + boot_mode = read_boot_mode_from_misc(misc); + else + boot_mode = ANDROID_BOOT_MODE_RECOVERY; + + if (boot_mode == ANDROID_BOOT_MODE_RECOVERY) + boot = rockchip_get_blk_part(PART_RECOVERY); + else + boot = rockchip_get_blk_part(PART_BOOT); + kernel = rockchip_get_blk_part(PART_KERNEL); + + if (!kernel || !boot) { + ret = CMD_RET_FAILURE; + goto out; + } + + kernel_size = read_rockchip_image(kernel, (void *)kernel_addr_r); + if (kernel_size < 0) { + ret = CMD_RET_FAILURE; + goto out; + } + + ramdisk_size = read_rockchip_image(boot, (void *)ramdisk_addr_r); + if (ramdisk_size < 0) { + ret = CMD_RET_FAILURE; + goto out; + } + + fdt_size = rockchip_read_resource_file((void *)fdt_addr_r, DTB_FILE, 0, 0); + if (fdt_size < 0) { + ret = CMD_RET_FAILURE; + goto out; + } + + printf("kernel_size:0x%ulx ramdisk_size:0x%x\n", kernel_size, ramdisk_size); + sprintf(cmdbuf, "booti 0x%lx 0x%lx:0x%x 0x%lx", + kernel_addr_r, ramdisk_addr_r, ramdisk_size, fdt_addr_r); + run_command(cmdbuf, 0); +out: + return ret; +} + +U_BOOT_CMD( + bootrkp, CONFIG_SYS_MAXARGS, 1, do_bootrkp, + "boot Linux Image image from rockchip partition storage", + "" +);