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 10 #ifdef HAVE_BLOCK_DEVICE 11 #define RK_PARAM_OFFSET 0x2000 12 #define MAX_PARAM_SIZE (1024 * 64) 13 14 struct rkparm_param { 15 u32 tag; 16 u32 length; 17 char params[1]; 18 u32 crc; 19 }; 20 21 struct rkparm_part { 22 char name[PART_NAME_LEN]; 23 unsigned long start; 24 unsigned long size; 25 struct list_head node; 26 }; 27 28 29 static LIST_HEAD(parts_head); 30 static int dev_num = -1; 31 32 static int rkparm_param_parse(char *param, struct list_head *parts_head, 33 struct blk_desc *dev_desc) 34 { 35 struct rkparm_part *part; 36 const char *cmdline = strstr(param, "CMDLINE:"); 37 const char *blkdev_parts; 38 char *cmdline_end, *next, *pend; 39 int len, offset = 0; 40 unsigned long size, start; 41 42 if (!cmdline) { 43 printf("invalid parameter\n"); 44 return -EINVAL; 45 } 46 47 blkdev_parts = strstr(cmdline, "mtdparts"); 48 next = strchr(blkdev_parts, ':'); 49 cmdline_end = strstr(cmdline, "\n"); /* end by '\n' */ 50 *cmdline_end = '\0'; 51 /* skip "CMDLINE:" */ 52 env_update("bootargs", cmdline + strlen("CMDLINE:")); 53 54 /* 55 * Initrd fixup: remove unused "initrd=0x...,0x...", this for 56 * compatible with legacy parameter.txt 57 */ 58 env_delete("bootargs", "initrd="); 59 60 INIT_LIST_HEAD(parts_head); 61 while (next) { 62 /* Skip ':' and ',' */ 63 next++; 64 if (*next == '-') { 65 size = (~0UL); 66 next++; 67 } else { 68 size = simple_strtoul(next, &next, 16); 69 } 70 /* Skip '@' */ 71 next++; 72 start = simple_strtoul(next, &next, 16); 73 next++; 74 pend = strchr(next, ')'); 75 if (!pend) 76 break; 77 len = min_t(int, pend - next, PART_NAME_LEN); 78 part = malloc(sizeof(*part)); 79 if (!part) { 80 printf("out of memory\n"); 81 break; 82 } 83 if (dev_desc->if_type != IF_TYPE_RKNAND) 84 offset = RK_PARAM_OFFSET; 85 part->start = start + offset; 86 part->size = size; 87 strncpy(part->name, next, len); 88 part->name[len] = '\0'; 89 list_add_tail(&part->node, parts_head); 90 next = strchr(next, ','); 91 } 92 93 dev_num = ((dev_desc->if_type << 8) + dev_desc->devnum); 94 95 return 0; 96 } 97 98 static int rkparm_init_param(struct blk_desc *dev_desc, 99 struct list_head *parts_head) 100 { 101 struct rkparm_param *param; 102 int offset = 0; 103 int ret; 104 105 param = memalign(ARCH_DMA_MINALIGN, MAX_PARAM_SIZE); 106 if (!param) { 107 printf("out of memory\n"); 108 return -ENOMEM; 109 } 110 111 if (dev_desc->if_type != IF_TYPE_RKNAND) 112 offset = RK_PARAM_OFFSET; 113 114 ret = blk_dread(dev_desc, offset, MAX_PARAM_SIZE >> 9, (ulong *)param); 115 if (ret != (MAX_PARAM_SIZE >> 9)) { 116 printf("%s param read fail\n", __func__); 117 return -EINVAL; 118 } 119 120 return rkparm_param_parse(param->params, parts_head, dev_desc); 121 122 } 123 124 static void part_print_rkparm(struct blk_desc *dev_desc) 125 { 126 int ret = 0; 127 struct list_head *node; 128 struct rkparm_part *p = NULL; 129 int i = 0; 130 131 if (list_empty(&parts_head) || 132 (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) 133 ret = rkparm_init_param(dev_desc, &parts_head); 134 135 if (ret) { 136 printf("%s Invalid rkparm parameter\n", __func__); 137 return; 138 } 139 140 printf("Part\tStart LBA\tSize\t\tName\n"); 141 list_for_each(node, &parts_head) { 142 p = list_entry(node, struct rkparm_part, node); 143 printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1), 144 p->start, p->size, p->name); 145 } 146 147 148 return; 149 } 150 151 static int part_get_info_rkparm(struct blk_desc *dev_desc, int idx, 152 disk_partition_t *info) 153 { 154 struct list_head *node; 155 struct rkparm_part *p = NULL; 156 int part_num = 1; 157 int ret = 0; 158 159 if (idx < 1) { 160 printf("%s Invalid partition no.%d\n", __func__, idx); 161 return -EINVAL; 162 } 163 164 if (list_empty(&parts_head) || 165 (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) 166 ret = rkparm_init_param(dev_desc, &parts_head); 167 168 if (ret) { 169 printf("%s Invalid rkparm partition\n", __func__); 170 return -1; 171 } 172 173 list_for_each(node, &parts_head) { 174 p = list_entry(node, struct rkparm_part, node); 175 if (idx == part_num) 176 break; 177 part_num ++; 178 } 179 180 if (part_num > idx) { 181 printf("%s Invalid partition no.%d\n", __func__, idx); 182 return -EINVAL; 183 } 184 185 info->start = p->start; 186 info->size = p->size << 9; 187 info->blksz = dev_desc->blksz; 188 189 sprintf((char *)info->name, "%s", p->name); 190 strcpy((char *)info->type, "U-Boot"); 191 info->bootable = 0; 192 193 return 0; 194 } 195 196 static int part_test_rkparm(struct blk_desc *dev_desc) 197 { 198 int ret = 0; 199 200 if (list_empty(&parts_head) || 201 (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) 202 ret = rkparm_init_param(dev_desc, &parts_head); 203 if (ret) 204 ret = -1; 205 206 return ret; 207 } 208 /* 209 * Add an 'b_' prefix so it comes before 'dos' and after 'a_efi' in the linker 210 * list. We need to check EFI first, and then rkparm partition 211 */ 212 U_BOOT_PART_TYPE(b_rkparm) = { 213 .name = "RKPARM", 214 .part_type = PART_TYPE_RKPARM, 215 .max_entries = GPT_ENTRY_NUMBERS, 216 .get_info = part_get_info_ptr(part_get_info_rkparm), 217 .print = part_print_ptr(part_print_rkparm), 218 .test = part_test_rkparm, 219 }; 220 #endif 221