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