108dcd37cSAndy Yan /*
208dcd37cSAndy Yan * (C) Copyright 2017 Rockchip Electronics Co., Ltd
308dcd37cSAndy Yan *
408dcd37cSAndy Yan * SPDX-License-Identifier: GPL-2.0+
508dcd37cSAndy Yan */
608dcd37cSAndy Yan #include <common.h>
709052952SJoseph Chen #include <boot_rkimg.h>
81d30bcc5SJoseph Chen #include <bmp_layout.h>
908dcd37cSAndy Yan #include <malloc.h>
101d30bcc5SJoseph Chen #include <asm/unaligned.h>
116ea28a6cSJoseph Chen #include <linux/libfdt.h>
1209052952SJoseph Chen #include <linux/list.h>
1309052952SJoseph Chen #include <asm/arch/resource_img.h>
14de479f92SXuhui Lin #include <asm/arch/rk_hwid.h>
156ea28a6cSJoseph Chen #include <asm/arch/uimage.h>
166ea28a6cSJoseph Chen #include <asm/arch/fit.h>
1708dcd37cSAndy Yan
18740107bbSJoseph Chen DECLARE_GLOBAL_DATA_PTR;
19740107bbSJoseph Chen
2008dcd37cSAndy Yan #define PART_RESOURCE "resource"
2108dcd37cSAndy Yan #define RESOURCE_MAGIC "RSCE"
2208dcd37cSAndy Yan #define RESOURCE_MAGIC_SIZE 4
2308dcd37cSAndy Yan #define ENTRY_TAG "ENTR"
2408dcd37cSAndy Yan #define ENTRY_TAG_SIZE 4
25e0cee412SJoseph Chen #define MAX_FILE_NAME_LEN 220
26e0cee412SJoseph Chen #define MAX_HASH_LEN 32
27dca57e1cSJoseph Chen #define DEFAULT_DTB_FILE "rk-kernel.dtb"
2809052952SJoseph Chen
2908dcd37cSAndy Yan /*
3008dcd37cSAndy Yan * resource image structure
3108dcd37cSAndy Yan * ----------------------------------------------
3208dcd37cSAndy Yan * | |
3308dcd37cSAndy Yan * | header (1 block) |
3408dcd37cSAndy Yan * | |
3508dcd37cSAndy Yan * ---------------------------------------------|
3608dcd37cSAndy Yan * | | |
3708dcd37cSAndy Yan * | entry0 (1 block) | |
3808dcd37cSAndy Yan * | | |
3908dcd37cSAndy Yan * ------------------------ |
4008dcd37cSAndy Yan * | | |
4108dcd37cSAndy Yan * | entry1 (1 block) | contents (n blocks) |
4208dcd37cSAndy Yan * | | |
4308dcd37cSAndy Yan * ------------------------ |
4408dcd37cSAndy Yan * | ...... | |
4508dcd37cSAndy Yan * ------------------------ |
4608dcd37cSAndy Yan * | | |
4708dcd37cSAndy Yan * | entryn (1 block) | |
4808dcd37cSAndy Yan * | | |
4908dcd37cSAndy Yan * ----------------------------------------------
5008dcd37cSAndy Yan * | |
5108dcd37cSAndy Yan * | file0 (x blocks) |
5208dcd37cSAndy Yan * | |
5308dcd37cSAndy Yan * ----------------------------------------------
5408dcd37cSAndy Yan * | |
5508dcd37cSAndy Yan * | file1 (y blocks) |
5608dcd37cSAndy Yan * | |
5708dcd37cSAndy Yan * ----------------------------------------------
5808dcd37cSAndy Yan * | ...... |
5908dcd37cSAndy Yan * |---------------------------------------------
6008dcd37cSAndy Yan * | |
6108dcd37cSAndy Yan * | filen (z blocks) |
6208dcd37cSAndy Yan * | |
6308dcd37cSAndy Yan * ----------------------------------------------
6408dcd37cSAndy Yan */
6508dcd37cSAndy Yan
6608dcd37cSAndy Yan /**
676ea28a6cSJoseph Chen * struct resource_img_hdr
6808dcd37cSAndy Yan *
6908dcd37cSAndy Yan * @magic: should be "RSCE"
7008dcd37cSAndy Yan * @version: resource image version, current is 0
7108dcd37cSAndy Yan * @c_version: content version, current is 0
7208dcd37cSAndy Yan * @blks: the size of the header ( 1 block = 512 bytes)
7308dcd37cSAndy Yan * @c_offset: contents offset(by block) in the image
7408dcd37cSAndy Yan * @e_blks: the size(by block) of the entry in the contents
7508dcd37cSAndy Yan * @e_num: numbers of the entrys.
7608dcd37cSAndy Yan */
7708dcd37cSAndy Yan struct resource_img_hdr {
7808dcd37cSAndy Yan char magic[4];
7908dcd37cSAndy Yan uint16_t version;
8008dcd37cSAndy Yan uint16_t c_version;
8108dcd37cSAndy Yan uint8_t blks;
8208dcd37cSAndy Yan uint8_t c_offset;
8308dcd37cSAndy Yan uint8_t e_blks;
8408dcd37cSAndy Yan uint32_t e_nums;
8508dcd37cSAndy Yan };
8608dcd37cSAndy Yan
8708dcd37cSAndy Yan struct resource_entry {
8808dcd37cSAndy Yan char tag[4];
8908dcd37cSAndy Yan char name[MAX_FILE_NAME_LEN];
90e0cee412SJoseph Chen char hash[MAX_HASH_LEN];
91e0cee412SJoseph Chen uint32_t hash_size;
926ea28a6cSJoseph Chen uint32_t blk_offset;
936ea28a6cSJoseph Chen uint32_t size; /* in byte */
9408dcd37cSAndy Yan };
9508dcd37cSAndy Yan
966ea28a6cSJoseph Chen LIST_HEAD(entry_head);
9708dcd37cSAndy Yan
resource_check_header(struct resource_img_hdr * hdr)986ea28a6cSJoseph Chen static int resource_check_header(struct resource_img_hdr *hdr)
9908dcd37cSAndy Yan {
1006ea28a6cSJoseph Chen return memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE);
10108dcd37cSAndy Yan }
10209052952SJoseph Chen
resource_dump(struct resource_file * f)1036ea28a6cSJoseph Chen static void resource_dump(struct resource_file *f)
10408dcd37cSAndy Yan {
1056ea28a6cSJoseph Chen printf("%s\n", f->name);
1061cc374d6SXuhui Lin printf(" blk_start: 0x%08lx\n", f->blk_start);
1071cc374d6SXuhui Lin printf(" blk_offset: 0x%08lx\n", f->blk_offset);
1086ea28a6cSJoseph Chen printf(" size: 0x%08x\n", f->size);
1096ea28a6cSJoseph Chen printf(" in_ram: %d\n", f->in_ram);
1106ea28a6cSJoseph Chen printf(" hash_size: %d\n\n", f->hash_size);
11108dcd37cSAndy Yan }
11209052952SJoseph Chen
resource_add_file(const char * name,u32 size,ulong blk_start,u32 blk_offset,char * hash,u32 hash_size,bool in_ram)1136ea28a6cSJoseph Chen static int resource_add_file(const char *name, u32 size,
1141cc374d6SXuhui Lin ulong blk_start, u32 blk_offset,
1156ea28a6cSJoseph Chen char *hash, u32 hash_size,
1166ea28a6cSJoseph Chen bool in_ram)
1174ebf6738SJoseph Chen {
1186ea28a6cSJoseph Chen struct resource_file *f;
1194ebf6738SJoseph Chen struct list_head *node;
1206ea28a6cSJoseph Chen bool _new = true;
1214ebf6738SJoseph Chen
1226ea28a6cSJoseph Chen /* old one ? */
1236ea28a6cSJoseph Chen list_for_each(node, &entry_head) {
1246ea28a6cSJoseph Chen f = list_entry(node, struct resource_file, link);
1256ea28a6cSJoseph Chen if (!strcmp(f->name, name)) {
1266ea28a6cSJoseph Chen _new = false;
1274ebf6738SJoseph Chen break;
1284ebf6738SJoseph Chen }
1294ebf6738SJoseph Chen }
1304ebf6738SJoseph Chen
1316ea28a6cSJoseph Chen if (_new) {
1326ea28a6cSJoseph Chen f = calloc(1, sizeof(*f));
1336ea28a6cSJoseph Chen if (!f)
1346ea28a6cSJoseph Chen return -ENOMEM;
1354ebf6738SJoseph Chen
1366ea28a6cSJoseph Chen list_add_tail(&f->link, &entry_head);
1376ea28a6cSJoseph Chen }
1386ea28a6cSJoseph Chen
1396ea28a6cSJoseph Chen strcpy(f->name, name);
1406ea28a6cSJoseph Chen f->size = size;
1416ea28a6cSJoseph Chen f->in_ram = in_ram;
1426ea28a6cSJoseph Chen f->blk_start = blk_start;
1436ea28a6cSJoseph Chen f->blk_offset = blk_offset;
1446ea28a6cSJoseph Chen f->hash_size = hash_size;
1456ea28a6cSJoseph Chen memcpy(f->hash, hash, hash_size);
1466ea28a6cSJoseph Chen #ifdef DEBUG
1476ea28a6cSJoseph Chen resource_dump(f);
1486ea28a6cSJoseph Chen #endif
1494ebf6738SJoseph Chen return 0;
1504ebf6738SJoseph Chen }
1514ebf6738SJoseph Chen
resource_destroy(void)152*06a21341SJoseph Chen void resource_destroy(void)
153*06a21341SJoseph Chen {
154*06a21341SJoseph Chen INIT_LIST_HEAD(&entry_head);
155*06a21341SJoseph Chen }
156*06a21341SJoseph Chen
15763f38f9dSJoseph Chen #ifdef CONFIG_ANDROID_BOOT_IMAGE
1586ea28a6cSJoseph Chen /*
1596ea28a6cSJoseph Chen * Add logo.bmp and logo_kernel.bmp from "logo" parititon
1606ea28a6cSJoseph Chen *
1616ea28a6cSJoseph Chen * Provide a "logo" partition for user to store logo.bmp and
1626ea28a6cSJoseph Chen * logo_kernel.bmp, so that the user can update them from
1636ea28a6cSJoseph Chen * kernel or user-space dynamically.
1646ea28a6cSJoseph Chen *
1656ea28a6cSJoseph Chen * "logo" partition layout, do not change order:
1666ea28a6cSJoseph Chen *
1676ea28a6cSJoseph Chen * |----------------------| 0x00
1686ea28a6cSJoseph Chen * | raw logo.bmp |
1696ea28a6cSJoseph Chen * |----------------------| -> 512-byte aligned
1706ea28a6cSJoseph Chen * | raw logo_kernel.bmp |
1716ea28a6cSJoseph Chen * |----------------------|
1726ea28a6cSJoseph Chen *
1736ea28a6cSJoseph Chen * N: the sector count of logo.bmp
1746ea28a6cSJoseph Chen *
1756ea28a6cSJoseph Chen * How to generate:
1766ea28a6cSJoseph Chen * cat logo.bmp > logo.img && truncate -s %512 logo.img && cat logo_kernel.bmp >> logo.img
1776ea28a6cSJoseph Chen */
resource_setup_logo_bmp(struct blk_desc * desc)1786ea28a6cSJoseph Chen static int resource_setup_logo_bmp(struct blk_desc *desc)
17945390edfSJoseph Chen {
1806ea28a6cSJoseph Chen struct bmp_header *header;
1816ea28a6cSJoseph Chen const char *name[] = { "logo.bmp", "logo_kernel.bmp" };
1826ea28a6cSJoseph Chen disk_partition_t part;
1836ea28a6cSJoseph Chen u32 blk_offset = 0;
1846ea28a6cSJoseph Chen u32 filesz;
1856ea28a6cSJoseph Chen int ret, i;
18645390edfSJoseph Chen
1876ea28a6cSJoseph Chen if (part_get_info_by_name(desc, PART_LOGO, &part) < 0)
1886ea28a6cSJoseph Chen return 0;
1896ea28a6cSJoseph Chen
1906ea28a6cSJoseph Chen header = memalign(ARCH_DMA_MINALIGN, desc->blksz);
1916ea28a6cSJoseph Chen if (!header)
1926ea28a6cSJoseph Chen return -ENOMEM;
1936ea28a6cSJoseph Chen
1946ea28a6cSJoseph Chen for (i = 0; i < ARRAY_SIZE(name); i++) {
1956ea28a6cSJoseph Chen if (blk_dread(desc, part.start + blk_offset, 1, header) != 1) {
1966ea28a6cSJoseph Chen ret = -EIO;
1976ea28a6cSJoseph Chen break;
1986ea28a6cSJoseph Chen }
1996ea28a6cSJoseph Chen
2006ea28a6cSJoseph Chen if (header->signature[0] != 'B' || header->signature[1] != 'M') {
20145390edfSJoseph Chen ret = -EINVAL;
2026ea28a6cSJoseph Chen break;
20345390edfSJoseph Chen }
20445390edfSJoseph Chen
2056ea28a6cSJoseph Chen filesz = get_unaligned_le32(&header->file_size);
2066ea28a6cSJoseph Chen ret = resource_add_file(name[i], filesz, part.start, blk_offset,
2076ea28a6cSJoseph Chen NULL, 0, false);
2086ea28a6cSJoseph Chen if (ret)
2096ea28a6cSJoseph Chen break;
2106ea28a6cSJoseph Chen
2116ea28a6cSJoseph Chen /* move to next file */
2126ea28a6cSJoseph Chen blk_offset += DIV_ROUND_UP(filesz, desc->blksz);
2136ea28a6cSJoseph Chen
2146ea28a6cSJoseph Chen printf("LOGO: %s\n", name[i]);
2156ea28a6cSJoseph Chen
21645390edfSJoseph Chen }
2176ea28a6cSJoseph Chen
2186ea28a6cSJoseph Chen free(header);
21945390edfSJoseph Chen
22045390edfSJoseph Chen return ret;
22145390edfSJoseph Chen }
22207dca981SXuhui Lin #endif
22345390edfSJoseph Chen
resource_setup_list(struct blk_desc * desc,ulong blk_start,void * resc_hdr,bool in_ram)2241cc374d6SXuhui Lin static int resource_setup_list(struct blk_desc *desc, ulong blk_start,
22507dca981SXuhui Lin void *resc_hdr, bool in_ram)
22607dca981SXuhui Lin {
22707dca981SXuhui Lin struct resource_img_hdr *hdr = resc_hdr;
22807dca981SXuhui Lin struct resource_entry *et;
22907dca981SXuhui Lin u32 i, stride;
23007dca981SXuhui Lin void *pos;
23107dca981SXuhui Lin
23207dca981SXuhui Lin pos = (void *)hdr + hdr->c_offset * desc->blksz;
23307dca981SXuhui Lin stride = hdr->e_blks * desc->blksz;
23407dca981SXuhui Lin
23507dca981SXuhui Lin for (i = 0; i < hdr->e_nums; i++) {
23607dca981SXuhui Lin et = pos + (i * stride);
23707dca981SXuhui Lin if (memcmp(et->tag, ENTRY_TAG, ENTRY_TAG_SIZE))
23807dca981SXuhui Lin continue;
23907dca981SXuhui Lin
24007dca981SXuhui Lin resource_add_file(et->name, et->size,
24107dca981SXuhui Lin blk_start, et->blk_offset,
24207dca981SXuhui Lin et->hash, et->hash_size, in_ram);
24307dca981SXuhui Lin }
24407dca981SXuhui Lin #ifdef CONFIG_ANDROID_BOOT_IMAGE
24507dca981SXuhui Lin resource_setup_logo_bmp(desc);
24607dca981SXuhui Lin #endif
24707dca981SXuhui Lin return 0;
24807dca981SXuhui Lin }
24907dca981SXuhui Lin
resource_setup_ram_list(struct blk_desc * desc,void * hdr)25007dca981SXuhui Lin int resource_setup_ram_list(struct blk_desc *desc, void *hdr)
25107dca981SXuhui Lin {
25207dca981SXuhui Lin if (!desc)
25307dca981SXuhui Lin return -ENODEV;
25407dca981SXuhui Lin
25507dca981SXuhui Lin if (resource_check_header(hdr)) {
25607dca981SXuhui Lin printf("RESC: invalid\n");
25707dca981SXuhui Lin return -EINVAL;
25807dca981SXuhui Lin }
25907dca981SXuhui Lin
26007dca981SXuhui Lin /* @blk_start: set as 'hdr' point addr, to be used in byte */
2611cc374d6SXuhui Lin return resource_setup_list(desc, (ulong)hdr, hdr, true);
26207dca981SXuhui Lin }
26307dca981SXuhui Lin
26407dca981SXuhui Lin #ifdef CONFIG_ANDROID_BOOT_IMAGE
resource_setup_blk_list(struct blk_desc * desc,ulong blk_start)2651cc374d6SXuhui Lin static int resource_setup_blk_list(struct blk_desc *desc, ulong blk_start)
26645390edfSJoseph Chen {
26745390edfSJoseph Chen struct resource_img_hdr *hdr;
2686ea28a6cSJoseph Chen int blk_cnt;
26945390edfSJoseph Chen int ret = 0;
2706ea28a6cSJoseph Chen void *buf;
27145390edfSJoseph Chen
2726ea28a6cSJoseph Chen hdr = memalign(ARCH_DMA_MINALIGN, desc->blksz);
27309052952SJoseph Chen if (!hdr)
27409052952SJoseph Chen return -ENOMEM;
27509052952SJoseph Chen
2766ea28a6cSJoseph Chen if (blk_dread(desc, blk_start, 1, hdr) != 1) {
277a84f21ebSJoseph Chen ret = -EIO;
2786ea28a6cSJoseph Chen goto out;
279a84f21ebSJoseph Chen }
280a84f21ebSJoseph Chen
2816ea28a6cSJoseph Chen if (resource_check_header(hdr)) {
2826ea28a6cSJoseph Chen printf("RESC: invalid\n");
28345390edfSJoseph Chen if (fdt_check_header(hdr)) {
28401ff14b0SJoseph Chen ret = -EINVAL;
2856ea28a6cSJoseph Chen goto out;
28645390edfSJoseph Chen } else {
2876ea28a6cSJoseph Chen /* this is a dtb file */
2886ea28a6cSJoseph Chen printf("RESC: this is dtb\n");
2896ea28a6cSJoseph Chen ret = resource_add_file(DEFAULT_DTB_FILE,
2906ea28a6cSJoseph Chen fdt_totalsize(hdr),
2916ea28a6cSJoseph Chen blk_start, 0, NULL, 0, false);
2926ea28a6cSJoseph Chen goto out;
29345390edfSJoseph Chen }
29401ff14b0SJoseph Chen }
295b498696eSJoseph Chen
2966ea28a6cSJoseph Chen blk_cnt = hdr->e_blks * hdr->e_nums;
2976ea28a6cSJoseph Chen hdr = realloc(hdr, (1 + blk_cnt) * desc->blksz);
2986ea28a6cSJoseph Chen if (!hdr) {
29901ff14b0SJoseph Chen ret = -ENOMEM;
3006ea28a6cSJoseph Chen goto out;
30108dcd37cSAndy Yan }
302b498696eSJoseph Chen
3036ea28a6cSJoseph Chen buf = (void *)hdr + desc->blksz;
3046ea28a6cSJoseph Chen if (blk_dread(desc, blk_start + hdr->c_offset, blk_cnt, buf) != blk_cnt) {
30501ff14b0SJoseph Chen ret = -EIO;
3066ea28a6cSJoseph Chen goto out;
30710660eccSJoseph Chen }
30808dcd37cSAndy Yan
3096ea28a6cSJoseph Chen resource_setup_list(desc, blk_start, hdr, false);
3106ea28a6cSJoseph Chen out:
31108dcd37cSAndy Yan free(hdr);
31208dcd37cSAndy Yan
31301ff14b0SJoseph Chen return ret;
31408dcd37cSAndy Yan }
31508dcd37cSAndy Yan
resource_init(struct blk_desc * desc,disk_partition_t * part,ulong blk_offset)3166ea28a6cSJoseph Chen static int resource_init(struct blk_desc *desc,
3176ea28a6cSJoseph Chen disk_partition_t *part,
3186ea28a6cSJoseph Chen ulong blk_offset)
319745aeb1aSJoseph Chen {
3206ea28a6cSJoseph Chen printf("RESC: '%s', blk@0x%08lx\n", part->name, part->start + blk_offset);
321745aeb1aSJoseph Chen
32277cf005eSJoseph Chen #ifdef CONFIG_ANDROID_AVB
32377cf005eSJoseph Chen char hdr[512];
32463f38f9dSJoseph Chen ulong resc_buf = 0;
32577cf005eSJoseph Chen int ret;
32677cf005eSJoseph Chen
32777cf005eSJoseph Chen if (blk_dread(desc, part->start, 1, hdr) != 1)
32877cf005eSJoseph Chen return -EIO;
32977cf005eSJoseph Chen
33077cf005eSJoseph Chen /* only handle android boot/recovery.img and resource.img, ignore fit */
33177cf005eSJoseph Chen if (!android_image_check_header((void *)hdr) ||
33277cf005eSJoseph Chen !resource_check_header((void *)hdr)) {
33363f38f9dSJoseph Chen ret = android_image_verify_resource((const char *)part->name, &resc_buf);
33477cf005eSJoseph Chen if (ret) {
33577cf005eSJoseph Chen printf("RESC: '%s', avb verify fail: %d\n", part->name, ret);
33677cf005eSJoseph Chen return ret;
33777cf005eSJoseph Chen }
33877cf005eSJoseph Chen
33963f38f9dSJoseph Chen /*
34063f38f9dSJoseph Chen * unlock=0: resc_buf is valid and file was already full load in ram.
34163f38f9dSJoseph Chen * unlock=1: resc_buf is 0.
34263f38f9dSJoseph Chen */
34363f38f9dSJoseph Chen if (resc_buf && !resource_check_header((void *)resc_buf))
34463f38f9dSJoseph Chen return resource_setup_ram_list(desc, (void *)resc_buf);
34577cf005eSJoseph Chen }
3469274b15fSXuhui Lin
34777cf005eSJoseph Chen #endif
34877cf005eSJoseph Chen
3496ea28a6cSJoseph Chen return resource_setup_blk_list(desc, part->start + blk_offset);
350745aeb1aSJoseph Chen }
351745aeb1aSJoseph Chen
resource_default(struct blk_desc * desc,disk_partition_t * out_part,ulong * out_blk_offset)3526ea28a6cSJoseph Chen static int resource_default(struct blk_desc *desc,
3536ea28a6cSJoseph Chen disk_partition_t *out_part,
3546ea28a6cSJoseph Chen ulong *out_blk_offset)
35545390edfSJoseph Chen {
35645390edfSJoseph Chen disk_partition_t part;
35745390edfSJoseph Chen
3586ea28a6cSJoseph Chen if (part_get_info_by_name(desc, PART_RESOURCE, &part) < 0)
35945390edfSJoseph Chen return -ENODEV;
3606ea28a6cSJoseph Chen
3616ea28a6cSJoseph Chen *out_part = part;
3626ea28a6cSJoseph Chen *out_blk_offset = 0;
3636ea28a6cSJoseph Chen
3646ea28a6cSJoseph Chen return 0;
3656ea28a6cSJoseph Chen }
36663f38f9dSJoseph Chen #endif
3676ea28a6cSJoseph Chen
resource_scan(void)3686ea28a6cSJoseph Chen static int resource_scan(void)
3696ea28a6cSJoseph Chen {
3706ea28a6cSJoseph Chen struct blk_desc *desc = rockchip_get_bootdev();
37163f38f9dSJoseph Chen __maybe_unused int ret;
3726ea28a6cSJoseph Chen
3736ea28a6cSJoseph Chen if (!desc) {
3746ea28a6cSJoseph Chen printf("RESC: No bootdev\n");
3756ea28a6cSJoseph Chen return -ENODEV;
3766ea28a6cSJoseph Chen }
3776ea28a6cSJoseph Chen
3786ea28a6cSJoseph Chen if (!list_empty(&entry_head))
3796ea28a6cSJoseph Chen return 0;
3806ea28a6cSJoseph Chen
3816ea28a6cSJoseph Chen #ifdef CONFIG_ROCKCHIP_FIT_IMAGE
38263f38f9dSJoseph Chen ret = fit_image_init_resource(desc);
38363f38f9dSJoseph Chen if (!ret || ret != -EAGAIN)
38463f38f9dSJoseph Chen return ret;
3856ea28a6cSJoseph Chen #endif
3866ea28a6cSJoseph Chen #ifdef CONFIG_ROCKCHIP_UIMAGE
38763f38f9dSJoseph Chen ret = uimage_init_resource(desc);
38863f38f9dSJoseph Chen if (!ret || ret != -EAGAIN)
38963f38f9dSJoseph Chen return ret;
3906ea28a6cSJoseph Chen #endif
39163f38f9dSJoseph Chen #ifdef CONFIG_ANDROID_BOOT_IMAGE
39263f38f9dSJoseph Chen disk_partition_t part;
39363f38f9dSJoseph Chen ulong blk_offset;
39463f38f9dSJoseph Chen char hdr[512];
39563f38f9dSJoseph Chen char name[32];
39663f38f9dSJoseph Chen
39763f38f9dSJoseph Chen /* partition priority: boot/recovery > resource */
39863f38f9dSJoseph Chen if (!android_image_init_resource(desc, &part, &blk_offset)) {
3996ea28a6cSJoseph Chen if (blk_dread(desc, part.start + blk_offset, 1, hdr) != 1)
4006ea28a6cSJoseph Chen return -EIO;
4016ea28a6cSJoseph Chen
4026ea28a6cSJoseph Chen if (resource_check_header((void *)hdr)) {
4036ea28a6cSJoseph Chen strcpy(name, (char *)part.name);
4046ea28a6cSJoseph Chen if (resource_default(desc, &part, &blk_offset))
4056ea28a6cSJoseph Chen return -ENOENT;
4066ea28a6cSJoseph Chen
4076ea28a6cSJoseph Chen printf("RESC: '%s' -> '%s'\n", name, part.name);
4086ea28a6cSJoseph Chen }
409745aeb1aSJoseph Chen } else {
4106ea28a6cSJoseph Chen if (resource_default(desc, &part, &blk_offset))
41145390edfSJoseph Chen return -ENOENT;
41245390edfSJoseph Chen }
41309052952SJoseph Chen
41463f38f9dSJoseph Chen /* now, 'part' can be boot/recovery/resource */
4156ea28a6cSJoseph Chen return resource_init(desc, &part, blk_offset);
41663f38f9dSJoseph Chen #endif
41763f38f9dSJoseph Chen return -ENOENT;
4186ea28a6cSJoseph Chen }
4196ea28a6cSJoseph Chen
resource_get_file(const char * name)4206ea28a6cSJoseph Chen static struct resource_file *resource_get_file(const char *name)
4216ea28a6cSJoseph Chen {
4226ea28a6cSJoseph Chen struct resource_file *f;
4236ea28a6cSJoseph Chen struct list_head *node;
4246ea28a6cSJoseph Chen
4256ea28a6cSJoseph Chen if (resource_scan())
4266ea28a6cSJoseph Chen return NULL;
4276ea28a6cSJoseph Chen
4286ea28a6cSJoseph Chen list_for_each(node, &entry_head) {
4296ea28a6cSJoseph Chen f = list_entry(node, struct resource_file, link);
4306ea28a6cSJoseph Chen if (!strcmp(f->name, name))
4316ea28a6cSJoseph Chen return f;
4326ea28a6cSJoseph Chen }
4336ea28a6cSJoseph Chen
4346ea28a6cSJoseph Chen return NULL;
4356ea28a6cSJoseph Chen }
4366ea28a6cSJoseph Chen
rockchip_read_resource_file(void * buf,const char * name,int blk_offset,int len)4376ea28a6cSJoseph Chen int rockchip_read_resource_file(void *buf, const char *name, int blk_offset, int len)
4386ea28a6cSJoseph Chen {
4396ea28a6cSJoseph Chen struct blk_desc *desc = rockchip_get_bootdev();
4406ea28a6cSJoseph Chen struct resource_file *f;
4416ea28a6cSJoseph Chen int blk_cnt;
4421cc374d6SXuhui Lin ulong pos;
4436ea28a6cSJoseph Chen
4446ea28a6cSJoseph Chen if (!desc)
44509052952SJoseph Chen return -ENODEV;
4466ea28a6cSJoseph Chen
4476ea28a6cSJoseph Chen f = resource_get_file(name);
4486ea28a6cSJoseph Chen if (!f) {
4496ea28a6cSJoseph Chen printf("No resource file: %s\n", name);
4506ea28a6cSJoseph Chen return -ENOENT;
45109052952SJoseph Chen }
45208dcd37cSAndy Yan
4536ea28a6cSJoseph Chen if (len <= 0 || len > f->size)
4546ea28a6cSJoseph Chen len = f->size;
45509052952SJoseph Chen
4566ea28a6cSJoseph Chen if (f->in_ram) {
4576ea28a6cSJoseph Chen pos = f->blk_start + (f->blk_offset + blk_offset) * desc->blksz;
4586ea28a6cSJoseph Chen memcpy(buf, (char *)pos, len);
45945390edfSJoseph Chen } else {
4606ea28a6cSJoseph Chen blk_cnt = DIV_ROUND_UP(len, desc->blksz);
4616ea28a6cSJoseph Chen if (blk_dread(desc,
4626ea28a6cSJoseph Chen f->blk_start + f->blk_offset + blk_offset,
4636ea28a6cSJoseph Chen blk_cnt, buf) != blk_cnt)
4646ea28a6cSJoseph Chen len = -EIO;
46545390edfSJoseph Chen }
46608dcd37cSAndy Yan
4676ea28a6cSJoseph Chen return len;
46808dcd37cSAndy Yan }
469740107bbSJoseph Chen
470de479f92SXuhui Lin #ifdef CONFIG_ROCKCHIP_HWID_DTB
resource_read_hwid_dtb(void)471de479f92SXuhui Lin static struct resource_file *resource_read_hwid_dtb(void)
472de479f92SXuhui Lin {
473de479f92SXuhui Lin struct resource_file *file;
474de479f92SXuhui Lin struct list_head *node;
475de479f92SXuhui Lin
476de479f92SXuhui Lin hwid_init_data();
477de479f92SXuhui Lin
478de479f92SXuhui Lin list_for_each(node, &entry_head) {
479de479f92SXuhui Lin file = list_entry(node, struct resource_file, link);
480de479f92SXuhui Lin if (!strstr(file->name, DTB_SUFFIX))
481de479f92SXuhui Lin continue;
482de479f92SXuhui Lin
483de479f92SXuhui Lin if (hwid_dtb_is_available(file->name))
484de479f92SXuhui Lin return file;
485de479f92SXuhui Lin }
486de479f92SXuhui Lin
487de479f92SXuhui Lin return NULL;
488de479f92SXuhui Lin }
489de479f92SXuhui Lin #endif
4906ea28a6cSJoseph Chen
rockchip_read_resource_dtb(void * fdt_addr,char ** hash,int * hash_size)491bc4ccd53SJoseph Chen int rockchip_read_resource_dtb(void *fdt_addr, char **hash, int *hash_size)
492740107bbSJoseph Chen {
4936ea28a6cSJoseph Chen struct resource_file *f = NULL;
494a6926964SJoseph Chen int ret;
495740107bbSJoseph Chen
496ca6fb291SJoseph Chen #ifdef CONFIG_ROCKCHIP_HWID_DTB
4976ea28a6cSJoseph Chen if (resource_scan())
4986ea28a6cSJoseph Chen return -ENOENT;
499ea513bf6SJoseph Chen
5006ea28a6cSJoseph Chen f = resource_read_hwid_dtb();
5016ea28a6cSJoseph Chen #endif
5026ea28a6cSJoseph Chen /* If no dtb match hardware id(GPIO/ADC), use the default */
5036ea28a6cSJoseph Chen if (!f)
5046ea28a6cSJoseph Chen f = resource_get_file(DEFAULT_DTB_FILE);
5056ea28a6cSJoseph Chen
5066ea28a6cSJoseph Chen if (!f)
5076069a2ccSJoseph Chen return -ENODEV;
508740107bbSJoseph Chen
5096ea28a6cSJoseph Chen ret = rockchip_read_resource_file(fdt_addr, f->name, 0, 0);
510a6926964SJoseph Chen if (ret < 0)
511a6926964SJoseph Chen return ret;
512b4a94719SJoseph Chen
513bc4ccd53SJoseph Chen if (fdt_check_header(fdt_addr))
5144f74cb30SJoseph Chen return -EBADF;
5154f74cb30SJoseph Chen
5166ea28a6cSJoseph Chen *hash = f->hash;
5176ea28a6cSJoseph Chen *hash_size = f->hash_size;
518e0cee412SJoseph Chen
5196ea28a6cSJoseph Chen printf("DTB: %s\n", f->name);
520ea513bf6SJoseph Chen
521ea513bf6SJoseph Chen return 0;
522ea513bf6SJoseph Chen }
5235f63fd7aSJoseph Chen
do_dump_resource(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])5245f63fd7aSJoseph Chen static int do_dump_resource(cmd_tbl_t *cmdtp, int flag,
5255f63fd7aSJoseph Chen int argc, char *const argv[])
5265f63fd7aSJoseph Chen {
5276ea28a6cSJoseph Chen struct resource_file *f;
5285f63fd7aSJoseph Chen struct list_head *node;
5295f63fd7aSJoseph Chen
5306ea28a6cSJoseph Chen list_for_each(node, &entry_head) {
5316ea28a6cSJoseph Chen f = list_entry(node, struct resource_file, link);
5326ea28a6cSJoseph Chen resource_dump(f);
5335f63fd7aSJoseph Chen }
5345f63fd7aSJoseph Chen
5355f63fd7aSJoseph Chen return 0;
5365f63fd7aSJoseph Chen }
5375f63fd7aSJoseph Chen
5385f63fd7aSJoseph Chen U_BOOT_CMD(
5395f63fd7aSJoseph Chen dump_resource, 1, 1, do_dump_resource,
5406ea28a6cSJoseph Chen "dump resource files",
5415f63fd7aSJoseph Chen ""
5425f63fd7aSJoseph Chen );
5435f63fd7aSJoseph Chen
544