1 /* 2 * (C) Copyright 2019 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <blk.h> 9 #include <boot_rkimg.h> 10 #include <dm.h> 11 #include <errno.h> 12 #include <malloc.h> 13 #include <nand.h> 14 #include <part.h> 15 #include <dm/device-internal.h> 16 17 #define MTD_PART_NAND_HEAD "mtdparts=" 18 #define MTD_PART_INFO_MAX_SIZE 512 19 #define MTD_SINGLE_PART_INFO_MAX_SIZE 40 20 21 #define MTD_BLK_TABLE_BLOCK_UNKNOWN (-2) 22 #define MTD_BLK_TABLE_BLOCK_SHIFT (-1) 23 24 static int *mtd_map_blk_table; 25 26 int mtd_blk_map_table_init(struct blk_desc *desc, 27 loff_t offset, 28 size_t length) 29 { 30 u32 blk_total, blk_begin, blk_cnt; 31 struct mtd_info *mtd = NULL; 32 int i, j; 33 34 if (!desc) 35 return -ENODEV; 36 37 if (desc->devnum == BLK_MTD_NAND) { 38 #if defined(CONFIG_NAND) && !defined(CONFIG_SPL_BUILD) 39 mtd = dev_get_priv(desc->bdev->parent); 40 #endif 41 } else if (desc->devnum == BLK_MTD_SPI_NAND) { 42 #if defined(CONFIG_MTD_SPI_NAND) && !defined(CONFIG_SPL_BUILD) 43 mtd = desc->bdev->priv; 44 #endif 45 } 46 47 if (!mtd) { 48 return -ENODEV; 49 } else { 50 blk_total = (mtd->size + mtd->erasesize - 1) >> mtd->erasesize_shift; 51 if (!mtd_map_blk_table) { 52 mtd_map_blk_table = (int *)malloc(blk_total * 4); 53 memset(mtd_map_blk_table, MTD_BLK_TABLE_BLOCK_UNKNOWN, 54 blk_total * 4); 55 } 56 57 blk_begin = (u32)offset >> mtd->erasesize_shift; 58 blk_cnt = ((u32)((offset & mtd->erasesize_mask) + length) >> mtd->erasesize_shift); 59 if ((blk_begin + blk_cnt) > blk_total) 60 blk_cnt = blk_total - blk_begin; 61 62 if (mtd_map_blk_table[blk_begin] != MTD_BLK_TABLE_BLOCK_UNKNOWN) 63 return 0; 64 65 j = 0; 66 /* should not across blk_cnt */ 67 for (i = 0; i < blk_cnt; i++) { 68 if (j >= blk_cnt) 69 mtd_map_blk_table[blk_begin + i] = MTD_BLK_TABLE_BLOCK_SHIFT; 70 for (; j < blk_cnt; j++) { 71 if (!mtd_block_isbad(mtd, (blk_begin + j) << mtd->erasesize_shift)) { 72 mtd_map_blk_table[blk_begin + i] = blk_begin + j; 73 j++; 74 if (j == blk_cnt) 75 j++; 76 break; 77 } 78 } 79 } 80 81 return 0; 82 } 83 } 84 85 static bool get_mtd_blk_map_address(struct mtd_info *mtd, loff_t *off) 86 { 87 bool mapped; 88 loff_t offset = *off; 89 size_t block_offset = offset & (mtd->erasesize - 1); 90 91 mapped = false; 92 if (!mtd_map_blk_table || 93 mtd_map_blk_table[(u64)offset >> mtd->erasesize_shift] == 94 MTD_BLK_TABLE_BLOCK_UNKNOWN || 95 mtd_map_blk_table[(u64)offset >> mtd->erasesize_shift] == 96 0xffffffff) 97 return mapped; 98 99 mapped = true; 100 *off = (loff_t)(((u32)mtd_map_blk_table[(u64)offset >> 101 mtd->erasesize_shift] << mtd->erasesize_shift) + block_offset); 102 103 return mapped; 104 } 105 106 static __maybe_unused int mtd_map_read(struct mtd_info *mtd, loff_t offset, 107 size_t *length, size_t *actual, 108 loff_t lim, u_char *buffer) 109 { 110 size_t left_to_read = *length; 111 u_char *p_buffer = buffer; 112 u32 erasesize = mtd->erasesize; 113 int rval; 114 115 while (left_to_read > 0) { 116 size_t block_offset = offset & (erasesize - 1); 117 size_t read_length; 118 119 if (offset >= mtd->size) 120 return 0; 121 122 if (!get_mtd_blk_map_address(mtd, &offset)) { 123 if (mtd_block_isbad(mtd, offset & ~(erasesize - 1))) { 124 printf("Skip bad block 0x%08llx\n", 125 offset & ~(erasesize - 1)); 126 offset += erasesize - block_offset; 127 continue; 128 } 129 } 130 131 if (left_to_read < (erasesize - block_offset)) 132 read_length = left_to_read; 133 else 134 read_length = erasesize - block_offset; 135 136 rval = mtd_read(mtd, offset, read_length, &read_length, 137 p_buffer); 138 if (rval && rval != -EUCLEAN) { 139 printf("NAND read from offset %llx failed %d\n", 140 offset, rval); 141 *length -= left_to_read; 142 return rval; 143 } 144 145 left_to_read -= read_length; 146 offset += read_length; 147 p_buffer += read_length; 148 } 149 150 return 0; 151 } 152 153 char *mtd_part_parse(void) 154 { 155 char mtd_part_info_temp[MTD_SINGLE_PART_INFO_MAX_SIZE] = {0}; 156 u32 length, data_len = MTD_PART_INFO_MAX_SIZE; 157 struct blk_desc *dev_desc; 158 disk_partition_t info; 159 char *mtd_part_info_p; 160 struct mtd_info *mtd; 161 char *mtd_part_info; 162 int ret; 163 int p; 164 165 dev_desc = rockchip_get_bootdev(); 166 if (!dev_desc) 167 return NULL; 168 169 mtd = (struct mtd_info *)dev_desc->bdev->priv; 170 if (!mtd) 171 return NULL; 172 173 mtd_part_info = (char *)calloc(MTD_PART_INFO_MAX_SIZE, sizeof(char)); 174 if (!mtd_part_info) { 175 printf("%s: Fail to malloc!", __func__); 176 return NULL; 177 } 178 179 mtd_part_info_p = mtd_part_info; 180 snprintf(mtd_part_info_p, data_len - 1, "%s%s:", 181 MTD_PART_NAND_HEAD, 182 dev_desc->product); 183 data_len -= strlen(mtd_part_info_p); 184 mtd_part_info_p = mtd_part_info_p + strlen(mtd_part_info_p); 185 186 for (p = 1; p < MAX_SEARCH_PARTITIONS; p++) { 187 ret = part_get_info(dev_desc, p, &info); 188 if (ret) 189 break; 190 191 debug("name is %s, start addr is %x\n", info.name, 192 (int)(size_t)info.start); 193 194 snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 195 (int)(size_t)info.size << 9, 196 (int)(size_t)info.start << 9, 197 info.name); 198 snprintf(mtd_part_info_temp, MTD_SINGLE_PART_INFO_MAX_SIZE - 1, 199 "0x%x@0x%x(%s)", 200 (int)(size_t)info.size << 9, 201 (int)(size_t)info.start << 9, 202 info.name); 203 strcat(mtd_part_info, ","); 204 if (part_get_info(dev_desc, p + 1, &info)) { 205 /* Nand flash is erased by block and gpt table just 206 * resserve 33 sectors for the last partition. This 207 * will erase the backup gpt table by user program, 208 * so reserve one block. 209 */ 210 snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 211 (int)(size_t)(info.size - 212 (info.size - 1) % 213 (mtd->erasesize >> 9) - 1) << 9, 214 (int)(size_t)info.start << 9, 215 info.name); 216 break; 217 } 218 length = strlen(mtd_part_info_temp); 219 data_len -= length; 220 mtd_part_info_p = mtd_part_info_p + length + 1; 221 memset(mtd_part_info_temp, 0, MTD_SINGLE_PART_INFO_MAX_SIZE); 222 } 223 224 return mtd_part_info; 225 } 226 227 ulong mtd_dread(struct udevice *udev, lbaint_t start, 228 lbaint_t blkcnt, void *dst) 229 { 230 struct blk_desc *desc = dev_get_uclass_platdata(udev); 231 #if defined(CONFIG_NAND) || defined(CONFIG_MTD_SPI_NAND) || defined(CONFIG_SPI_FLASH_MTD) 232 loff_t off = (loff_t)(start * 512); 233 size_t rwsize = blkcnt * 512; 234 #endif 235 struct mtd_info *mtd; 236 int ret = 0; 237 238 if (!desc) 239 return ret; 240 241 mtd = desc->bdev->priv; 242 if (!mtd) 243 return 0; 244 245 if (blkcnt == 0) 246 return 0; 247 248 if (desc->devnum == BLK_MTD_NAND) { 249 #if defined(CONFIG_NAND) && !defined(CONFIG_SPL_BUILD) 250 mtd = dev_get_priv(udev->parent); 251 if (!mtd) 252 return 0; 253 254 ret = nand_read_skip_bad(mtd, off, &rwsize, 255 NULL, mtd->size, 256 (u_char *)(dst)); 257 #else 258 ret = mtd_map_read(mtd, off, &rwsize, 259 NULL, mtd->size, 260 (u_char *)(dst)); 261 #endif 262 if (!ret) 263 return blkcnt; 264 else 265 return 0; 266 } else if (desc->devnum == BLK_MTD_SPI_NAND) { 267 ret = mtd_map_read(mtd, off, &rwsize, 268 NULL, mtd->size, 269 (u_char *)(dst)); 270 if (!ret) 271 return blkcnt; 272 else 273 return 0; 274 } else if (desc->devnum == BLK_MTD_SPI_NOR) { 275 #if defined(CONFIG_SPI_FLASH_MTD) || defined(CONFIG_SPL_BUILD) 276 size_t retlen_nor; 277 278 mtd_read(mtd, off, rwsize, &retlen_nor, dst); 279 if (retlen_nor == rwsize) 280 return blkcnt; 281 else 282 #endif 283 return 0; 284 } else { 285 return 0; 286 } 287 } 288 289 ulong mtd_dwrite(struct udevice *udev, lbaint_t start, 290 lbaint_t blkcnt, const void *src) 291 { 292 /* Not implemented */ 293 return 0; 294 } 295 296 ulong mtd_derase(struct udevice *udev, lbaint_t start, 297 lbaint_t blkcnt) 298 { 299 /* Not implemented */ 300 return 0; 301 } 302 303 static int mtd_blk_probe(struct udevice *udev) 304 { 305 struct mtd_info *mtd = dev_get_uclass_priv(udev->parent); 306 struct blk_desc *desc = dev_get_uclass_platdata(udev); 307 int ret, i; 308 309 desc->bdev->priv = mtd; 310 sprintf(desc->vendor, "0x%.4x", 0x2207); 311 memcpy(desc->product, mtd->name, strlen(mtd->name)); 312 memcpy(desc->revision, "V1.00", sizeof("V1.00")); 313 if (mtd->type == MTD_NANDFLASH) { 314 if (desc->devnum == BLK_MTD_NAND) 315 mtd = dev_get_priv(udev->parent); 316 /* 317 * Find the first useful block in the end, 318 * and it is the end lba of the nand storage. 319 */ 320 for (i = 0; i < (mtd->size / mtd->erasesize); i++) { 321 ret = mtd_block_isbad(mtd, 322 mtd->size - mtd->erasesize * (i + 1)); 323 if (!ret) { 324 desc->lba = (mtd->size >> 9) - 325 (mtd->erasesize >> 9) * i; 326 break; 327 } 328 } 329 } else { 330 desc->lba = mtd->size >> 9; 331 } 332 333 debug("MTD: desc->lba is %lx\n", desc->lba); 334 335 return 0; 336 } 337 338 static const struct blk_ops mtd_blk_ops = { 339 .read = mtd_dread, 340 #ifndef CONFIG_SPL_BUILD 341 .write = mtd_dwrite, 342 .erase = mtd_derase, 343 #endif 344 }; 345 346 U_BOOT_DRIVER(mtd_blk) = { 347 .name = "mtd_blk", 348 .id = UCLASS_BLK, 349 .ops = &mtd_blk_ops, 350 .probe = mtd_blk_probe, 351 }; 352