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