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 #ifndef PARTS_RKPARM 92 if (dev_desc->if_type != IF_TYPE_RKNAND) 93 offset = RK_PARAM_OFFSET; 94 #endif 95 part->start = start + offset; 96 /* Last partition use all remain space */ 97 if (size == (~0UL)) 98 size = dev_desc->lba - part->start; 99 part->size = size; 100 strncpy(part->name, next, len); 101 part->name[len] = '\0'; 102 list_add_tail(&part->node, parts_head); 103 next = strchr(next, ','); 104 } 105 106 dev_num = ((dev_desc->if_type << 8) + dev_desc->devnum); 107 108 return 0; 109 } 110 111 static int rkparm_init_param(struct blk_desc *dev_desc, 112 struct list_head *parts_head) 113 { 114 char *parts_list; 115 116 /* 117 * There are ways to get partition tables: 118 * 119 * 1. macro 'PARTS_RKPARM' string list (No RK_PARAM_OFFSET for every partition), 120 * 2. Legacy rk parameter in flash @RK_PARAM_OFFSET sectors offset 121 */ 122 #ifdef PARTS_RKPARM 123 parts_list = PARTS_RKPARM; 124 #else 125 struct rkparm_param *param; 126 int offset = 0; 127 int ret; 128 129 param = memalign(ARCH_DMA_MINALIGN, MAX_PARAM_SIZE); 130 if (!param) { 131 printf("out of memory\n"); 132 return -ENOMEM; 133 } 134 135 if (dev_desc->if_type != IF_TYPE_RKNAND) 136 offset = RK_PARAM_OFFSET; 137 138 ret = blk_dread(dev_desc, offset, MAX_PARAM_SIZE >> 9, (ulong *)param); 139 if (ret != (MAX_PARAM_SIZE >> 9)) { 140 printf("%s param read fail\n", __func__); 141 return -EINVAL; 142 } 143 parts_list = param->params; 144 #endif 145 return rkparm_param_parse(parts_list, parts_head, dev_desc); 146 } 147 148 static void part_print_rkparm(struct blk_desc *dev_desc) 149 { 150 int ret = 0; 151 struct list_head *node; 152 struct rkparm_part *p = NULL; 153 int i = 0; 154 155 if (list_empty(&parts_head) || 156 (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) 157 ret = rkparm_init_param(dev_desc, &parts_head); 158 159 if (ret) { 160 printf("%s Invalid rkparm parameter\n", __func__); 161 return; 162 } 163 164 printf("Part\tStart LBA\tSize\t\tName\n"); 165 list_for_each(node, &parts_head) { 166 p = list_entry(node, struct rkparm_part, node); 167 printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1), 168 p->start, p->size, p->name); 169 } 170 171 return; 172 } 173 174 static int part_get_info_rkparm(struct blk_desc *dev_desc, int idx, 175 disk_partition_t *info) 176 { 177 struct list_head *node; 178 struct rkparm_part *p = NULL; 179 int part_num = 1; 180 int ret = 0; 181 182 if (idx < 1) { 183 printf("%s Invalid partition no.%d\n", __func__, idx); 184 return -EINVAL; 185 } 186 187 if (list_empty(&parts_head) || 188 (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) { 189 ret = rkparm_init_param(dev_desc, &parts_head); 190 if (ret) { 191 printf("%s Invalid rkparm partition\n", __func__); 192 return -1; 193 } 194 } 195 196 list_for_each(node, &parts_head) { 197 p = list_entry(node, struct rkparm_part, node); 198 if (idx == part_num) 199 break; 200 part_num ++; 201 } 202 203 if (part_num < idx) { 204 debug("%s Invalid partition no.%d\n", __func__, idx); 205 return -EINVAL; 206 } 207 208 info->start = p->start; 209 info->size = p->size; 210 info->blksz = dev_desc->blksz; 211 212 sprintf((char *)info->name, "%s", p->name); 213 strcpy((char *)info->type, "U-Boot"); 214 info->bootable = 0; 215 216 return 0; 217 } 218 219 static int part_test_rkparm(struct blk_desc *dev_desc) 220 { 221 int ret = 0; 222 223 if (list_empty(&parts_head) || 224 (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) 225 ret = rkparm_init_param(dev_desc, &parts_head); 226 if (ret) 227 ret = -1; 228 229 return ret; 230 } 231 /* 232 * Add an 'b_' prefix so it comes before 'dos' and after 'a_efi' in the linker 233 * list. We need to check EFI first, and then rkparm partition 234 */ 235 U_BOOT_PART_TYPE(b_rkparm) = { 236 #ifdef PARTS_RKPARM 237 .name = "RKPARM(FIXED)", 238 #else 239 .name = "RKPARM", 240 #endif 241 .part_type = PART_TYPE_RKPARM, 242 .max_entries = RKPARM_ENTRY_NUMBERS, 243 .get_info = part_get_info_ptr(part_get_info_rkparm), 244 .print = part_print_ptr(part_print_rkparm), 245 .test = part_test_rkparm, 246 }; 247 #endif 248