1 /* 2 * (C) Copyright 2017 rkparm Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <malloc.h> 9 #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS 10 #include <asm/arch/rk_atags.h> 11 #endif 12 13 #ifdef HAVE_BLOCK_DEVICE 14 #define RK_PARAM_OFFSET 0x2000 15 #define MAX_PARAM_SIZE (1024 * 64) 16 17 struct rkparm_param { 18 u32 tag; 19 u32 length; 20 char params[1]; 21 u32 crc; 22 }; 23 24 struct rkparm_part { 25 char name[PART_NAME_LEN]; 26 unsigned long start; 27 unsigned long size; 28 struct list_head node; 29 }; 30 31 32 static LIST_HEAD(parts_head); 33 34 /* 35 * What's this? 36 * 37 * There maybe two different storage media need to use this partition driver, 38 * e.g. rkand with SD card. So we need a flag info to recognize it. 39 */ 40 static int dev_num = -1; 41 42 static int rkparm_param_parse(char *param, struct list_head *parts_head, 43 struct blk_desc *dev_desc) 44 { 45 struct rkparm_part *part; 46 const char *cmdline = strstr(param, "CMDLINE:"); 47 const char *blkdev_parts; 48 char *cmdline_end, *next, *pend; 49 int len, offset = 0; 50 unsigned long size, start; 51 52 if (!cmdline) { 53 debug("RKPARM: Invalid parameter part table from storage\n"); 54 return -EINVAL; 55 } 56 57 blkdev_parts = strstr(cmdline, "mtdparts"); 58 next = strchr(blkdev_parts, ':'); 59 cmdline_end = strstr(cmdline, "\n"); /* end by '\n' */ 60 *cmdline_end = '\0'; 61 /* 62 * 1. skip "CMDLINE:" 63 * 2. Initrd fixup: remove unused "initrd=0x...,0x...", this for 64 * compatible with legacy parameter.txt 65 */ 66 env_update_filter("bootargs", cmdline + strlen("CMDLINE:"), "initrd="); 67 68 INIT_LIST_HEAD(parts_head); 69 while (next) { 70 /* Skip ':' and ',' */ 71 next++; 72 if (*next == '-') { 73 size = (~0UL); 74 next++; 75 } else { 76 size = simple_strtoul(next, &next, 16); 77 } 78 /* Skip '@' */ 79 next++; 80 start = simple_strtoul(next, &next, 16); 81 next++; 82 pend = strchr(next, ')'); 83 if (!pend) 84 break; 85 len = min_t(int, pend - next, PART_NAME_LEN); 86 part = malloc(sizeof(*part)); 87 if (!part) { 88 printf("out of memory\n"); 89 break; 90 } 91 if (dev_desc->if_type != IF_TYPE_RKNAND) 92 offset = RK_PARAM_OFFSET; 93 part->start = start + offset; 94 /* Last partition use all remain space */ 95 if (size == (~0UL)) 96 size = dev_desc->lba - part->start; 97 part->size = size; 98 strncpy(part->name, next, len); 99 part->name[len] = '\0'; 100 list_add_tail(&part->node, parts_head); 101 next = strchr(next, ','); 102 } 103 104 dev_num = ((dev_desc->if_type << 8) + dev_desc->devnum); 105 106 return 0; 107 } 108 109 static int rkparm_init_param_from_storage(struct blk_desc *dev_desc, 110 struct list_head *parts_head) 111 { 112 struct rkparm_param *param; 113 int offset = 0; 114 int ret; 115 116 param = memalign(ARCH_DMA_MINALIGN, MAX_PARAM_SIZE); 117 if (!param) { 118 printf("out of memory\n"); 119 return -ENOMEM; 120 } 121 122 if (dev_desc->if_type != IF_TYPE_RKNAND) 123 offset = RK_PARAM_OFFSET; 124 125 ret = blk_dread(dev_desc, offset, MAX_PARAM_SIZE >> 9, (ulong *)param); 126 if (ret != (MAX_PARAM_SIZE >> 9)) { 127 printf("%s param read fail\n", __func__); 128 return -EINVAL; 129 } 130 131 return rkparm_param_parse(param->params, parts_head, dev_desc); 132 } 133 134 #if defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS) && defined(CONFIG_DM_RAMDISK) 135 static int rkparm_init_param_from_atags(struct blk_desc *dev_desc, 136 struct list_head *parts_head) 137 { 138 struct rkparm_part *part; 139 struct tag *t; 140 u64 start, size; 141 int i, len; 142 143 if (!atags_is_available()) { 144 debug("%s: can't find ATAGS\n", __func__); 145 return -ENODATA; 146 } 147 148 t = atags_get_tag(ATAG_RAM_PARTITION); 149 if (!t) { 150 debug("%s: can't find ATAGS ramdisk partition\n", __func__); 151 return -ENODATA; 152 } 153 154 INIT_LIST_HEAD(parts_head); 155 156 for (i = 0; i < t->u.ram_part.count; i++) { 157 part = malloc(sizeof(*part)); 158 if (!part) { 159 printf("%s: out of memory\n", __func__); 160 break; 161 } 162 163 len = strlen(t->u.ram_part.part[i].name) + 1; 164 memcpy((char *)&part->name, 165 (char *)&t->u.ram_part.part[i].name, len); 166 167 start = t->u.ram_part.part[i].start; 168 size = t->u.ram_part.part[i].size; 169 170 if (!IS_ALIGNED(start, dev_desc->blksz)) { 171 printf("%s: '%s' addr(0x%llx) is not %ld byte aligned\n", 172 __func__, part->name, start, dev_desc->blksz); 173 return -EINVAL; 174 } else if (!IS_ALIGNED(size, dev_desc->blksz)) { 175 printf("%s: '%s' size(0x%llx) is not %ld byte aligned\n", 176 __func__, part->name, size, dev_desc->blksz); 177 return -EINVAL; 178 } 179 180 /* Convert bytes to blksz */ 181 part->start = start / dev_desc->blksz; 182 part->size = size / dev_desc->blksz; 183 list_add_tail(&part->node, parts_head); 184 185 debug("%s: name=%s, start=0x%lx, size=0x%lx, blksz=0x%lx\n", 186 __func__, part->name, part->start, 187 part->size, dev_desc->blksz); 188 } 189 190 dev_num = ((dev_desc->if_type << 8) + dev_desc->devnum); 191 192 return 0; 193 } 194 #endif 195 196 static int rkparm_init_param(struct blk_desc *dev_desc, 197 struct list_head *parts_head) 198 { 199 int ret; 200 201 ret = rkparm_init_param_from_storage(dev_desc, parts_head); 202 if (ret) { 203 debug("%s: failed to init param from storage\n", __func__); 204 #if defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS) && defined(CONFIG_DM_RAMDISK) 205 ret = rkparm_init_param_from_atags(dev_desc, parts_head); 206 if (ret) { 207 debug("%s: failed to init param from ram\n", __func__); 208 return ret; 209 } 210 #endif 211 } 212 213 if (ret) 214 printf("RKPARM: Invalid parameter part table\n"); 215 216 return ret; 217 } 218 219 static void part_print_rkparm(struct blk_desc *dev_desc) 220 { 221 int ret = 0; 222 struct list_head *node; 223 struct rkparm_part *p = NULL; 224 int i = 0; 225 226 if (list_empty(&parts_head) || 227 (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) 228 ret = rkparm_init_param(dev_desc, &parts_head); 229 230 if (ret) { 231 printf("%s Invalid rkparm parameter\n", __func__); 232 return; 233 } 234 235 printf("Part\tStart LBA\tSize\t\tName\n"); 236 list_for_each(node, &parts_head) { 237 p = list_entry(node, struct rkparm_part, node); 238 printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1), 239 p->start, p->size, p->name); 240 } 241 242 return; 243 } 244 245 static int part_get_info_rkparm(struct blk_desc *dev_desc, int idx, 246 disk_partition_t *info) 247 { 248 struct list_head *node; 249 struct rkparm_part *p = NULL; 250 int part_num = 1; 251 int ret = 0; 252 253 if (idx < 1) { 254 printf("%s Invalid partition no.%d\n", __func__, idx); 255 return -EINVAL; 256 } 257 258 if (list_empty(&parts_head) || 259 (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) 260 ret = rkparm_init_param(dev_desc, &parts_head); 261 262 if (ret) { 263 printf("%s Invalid rkparm partition\n", __func__); 264 return -1; 265 } 266 267 list_for_each(node, &parts_head) { 268 p = list_entry(node, struct rkparm_part, node); 269 if (idx == part_num) 270 break; 271 part_num ++; 272 } 273 274 if (part_num > idx) { 275 printf("%s Invalid partition no.%d\n", __func__, idx); 276 return -EINVAL; 277 } 278 279 info->start = p->start; 280 info->size = p->size; 281 info->blksz = dev_desc->blksz; 282 283 sprintf((char *)info->name, "%s", p->name); 284 strcpy((char *)info->type, "U-Boot"); 285 info->bootable = 0; 286 287 return 0; 288 } 289 290 static int part_test_rkparm(struct blk_desc *dev_desc) 291 { 292 int ret = 0; 293 294 if (list_empty(&parts_head) || 295 (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) 296 ret = rkparm_init_param(dev_desc, &parts_head); 297 if (ret) 298 ret = -1; 299 300 return ret; 301 } 302 /* 303 * Add an 'b_' prefix so it comes before 'dos' and after 'a_efi' in the linker 304 * list. We need to check EFI first, and then rkparm partition 305 */ 306 U_BOOT_PART_TYPE(b_rkparm) = { 307 .name = "RKPARM", 308 .part_type = PART_TYPE_RKPARM, 309 .max_entries = RKPARM_ENTRY_NUMBERS, 310 .get_info = part_get_info_ptr(part_get_info_rkparm), 311 .print = part_print_ptr(part_print_rkparm), 312 .test = part_test_rkparm, 313 }; 314 #endif 315