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