1 /* SPDX-License-Identifier: GPL-2.0+ */ 2 /* 3 * (C) Copyright 2022 Rockchip Electronics Co., Ltd 4 * 5 */ 6 7 #include <common.h> 8 #include <boot_rkimg.h> 9 #include <crc.h> 10 #include <errno.h> 11 #include <fdt_support.h> 12 #include <image.h> 13 #include <misc.h> 14 #include <spl.h> 15 #include <asm/arch/rk_meta.h> 16 17 static char *cmdline; 18 19 #if defined(CONFIG_ROCKCHIP_RV1106) || \ 20 defined(CONFIG_ROCKCHIP_RV1103B) || \ 21 defined(CONFIG_ROCKCHIP_RV1126B) 22 #define COMPRESS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0xa0000) 23 #else 24 #error "Please Define COMPRESS_LOAD_ADDR !!!" 25 #endif 26 27 __weak void rk_meta_process(void) { } 28 29 static int rk_meta_get_startup_part_info(struct spl_load_info *info, disk_partition_t part_info, 30 uint32_t *per_part_size, struct meta_head *meta_p) 31 { 32 struct meta_head meta_next; 33 uint32_t total_part_num = 1; 34 uint32_t i = 1; 35 ulong sector = part_info.start; 36 37 if (info->read(info, sector, 1, meta_p) != 1) { 38 printf("%s: Failed to read header\n", __func__); 39 return -EIO; 40 } 41 42 if (meta_p->tag != RK_META) { 43 printf("Invalid meta tag is %x.\n", meta_p->tag); 44 return -EINVAL; 45 } 46 47 total_part_num = meta_p->total_part_num; 48 *per_part_size = meta_p->size + meta_p->part_reserved_size; 49 if (*per_part_size * meta_p->total_part_num > part_info.size * part_info.blksz) { 50 printf("Error: Total part size (0x%08x * %d) is larger than partition size (0x%08lx).\n", 51 *per_part_size, meta_p->total_part_num, part_info.size * part_info.blksz); 52 return -EINVAL; 53 } 54 55 memset(&meta_next, 0, sizeof(struct meta_head)); 56 for (i = 1; i < total_part_num; i++) { 57 if (info->read(info, sector + i * (*per_part_size / info->bl_len), 58 1, &meta_next) != 1) { 59 printf("%s: Failed to read header\n", __func__); 60 return -EIO; 61 } 62 63 if (meta_next.tag != RK_META) { 64 debug("Not read meta tag from meta part[%d], read from part[%d] by default.\n", i, i - 1); 65 break; 66 } 67 68 debug("Check part[%d]:part_flag=%d part[%d]:part_flag=%d\n", i - 1, meta_p->part_flag, 69 i, meta_next.part_flag); 70 if (meta_next.part_flag != meta_p->part_flag) 71 break; 72 73 memcpy(meta_p, &meta_next, sizeof(struct meta_head)); 74 } 75 76 if (meta_p->crc32 != crc32(0, (const unsigned char *)meta_p, sizeof(struct meta_head) - 4 - 4)) { 77 printf("Invalid meta crc32.\n"); 78 return -EINVAL; 79 } 80 81 return i; 82 } 83 84 static int rk_meta_iq_decom(unsigned long dst, unsigned long src, 85 unsigned long src_len, u64 *len) 86 { 87 int ret; 88 #if CONFIG_IS_ENABLED(MISC_DECOMPRESS) 89 90 ret = misc_decompress_process(dst, src, src_len, DECOM_GZIP, true, len, 0); 91 misc_decompress_sync(IH_COMP_GZIP); 92 #else 93 ret = gunzip((void *)&dst, ALIGN(len, FIT_MAX_SPL_IMAGE_SZ), 94 (void *)&src, (void *)len); 95 #endif 96 97 return ret; 98 } 99 100 int spl_load_meta(struct spl_image_info *spl_image, struct spl_load_info *info) 101 { 102 const char *part_name = PART_META; 103 disk_partition_t part_info; 104 struct meta_head meta; 105 struct meta_head *meta_p; 106 struct cmdline_info *cmd; 107 ulong sector; 108 char *data; 109 u64 len; 110 int meta_iq_item_size = 0; 111 int meta_startup_part_num = 0; 112 uint32_t meta_per_part_size = 0; 113 uint32_t meta_startup_part_offset = 0; 114 115 if (part_get_info_by_name(info->dev, part_name, &part_info) <= 0) { 116 debug("%s: no partition\n", __func__); 117 return -EINVAL; 118 } 119 sector = part_info.start; 120 121 printf("\n"); 122 memset(&meta, 0, sizeof(struct meta_head)); 123 124 meta_startup_part_num = rk_meta_get_startup_part_info(info, part_info, &meta_per_part_size, &meta); 125 if (meta_startup_part_num <= 0) { 126 debug("Get startup part number failed.[%d]\n", meta_startup_part_num); 127 return -EINVAL; 128 } 129 printf("Meta: Found meta partition. Current part number: %d, total: %d\n", 130 meta_startup_part_num, meta.total_part_num); 131 132 /* The first part offset starts at 0x0 offset. */ 133 meta_startup_part_offset = (meta_startup_part_num - 1) * (meta_per_part_size / info->bl_len); 134 135 data = (char *)(uintptr_t)meta.load; 136 printf("Meta: 0x%08x - 0x%08x\n", meta.load, meta.load + meta.size); 137 if (info->read(info, sector + meta_startup_part_offset, 138 DIV_ROUND_UP(MAX_META_SEGMENT_SIZE, info->bl_len), data) 139 != DIV_ROUND_UP(MAX_META_SEGMENT_SIZE, info->bl_len)) { 140 debug("%s: Failed to read header\n", __func__); 141 return -EIO; 142 } 143 144 meta_p = (struct meta_head *)(uintptr_t)meta.load; 145 146 cmd = (struct cmdline_info *)(uintptr_t)(meta_p->load + CMDLINE_OFFSET); 147 if (cmd->tag == RK_CMDLINE) { 148 if (cmd->crc32 == crc32(0, (const unsigned char *)cmd, sizeof(struct cmdline_info) - 4)) 149 cmdline = (char *)cmd->data; 150 } 151 152 /* load compress data */ 153 data = (char *)COMPRESS_LOAD_ADDR; 154 meta_iq_item_size = meta_p->iq_item_size + meta.comp_size; 155 if (meta_p->comp_type == META_COMPRESS_TYPE_GZ) { 156 if (info->read(info, 157 sector + meta_startup_part_offset + (MAX_META_SEGMENT_SIZE / info->bl_len), 158 DIV_ROUND_UP(meta_iq_item_size, info->bl_len), 159 data) 160 != DIV_ROUND_UP(meta_iq_item_size, info->bl_len)) { 161 printf("%s: Failed to read compress data.\n", __func__); 162 return -EIO; 163 } 164 165 memcpy((void *)(uintptr_t)(meta_p->load + SENSOR_IQ_BIN_OFFSET), data, meta_p->iq_item_size); 166 167 if (rk_meta_iq_decom((meta_p->load + meta_p->comp_off), 168 (unsigned long)(data + meta_p->comp_off - 169 MAX_META_SEGMENT_SIZE), 170 meta.comp_size, &len)) { 171 printf("%s: Failed to decompress.\n", __func__); 172 return -EIO; 173 } 174 175 } else { 176 if (info->read(info, 177 sector + meta_startup_part_offset + (MAX_META_SEGMENT_SIZE / info->bl_len), 178 DIV_ROUND_UP(meta_iq_item_size, info->bl_len), 179 (void *)(uintptr_t)(meta_p->load + MAX_META_SEGMENT_SIZE)) 180 != DIV_ROUND_UP(meta_iq_item_size, info->bl_len)) { 181 printf("%s: Failed to read\n", __func__); 182 return -EIO; 183 } 184 } 185 186 meta_p->meta_flags = META_READ_DONE_FLAG; 187 flush_cache(meta_p->load, meta_p->size); 188 rk_meta_process(); 189 190 printf("\nMeta: ok\n"); 191 return 0; 192 } 193 194 void rk_meta_bootargs_append(void *fdt) 195 { 196 if (!cmdline || (!fdt || fdt_check_header(fdt))) 197 return; 198 199 fdt_bootargs_append(fdt, cmdline); 200 } 201