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