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 <image.h> 13 #include <linux/log2.h> 14 #include <malloc.h> 15 #include <nand.h> 16 #include <part.h> 17 #include <spi.h> 18 #include <dm/device-internal.h> 19 #include <linux/mtd/spi-nor.h> 20 #ifdef CONFIG_NAND 21 #include <linux/mtd/nand.h> 22 #endif 23 24 #define MTD_PART_NAND_HEAD "mtdparts=" 25 #define MTD_PART_INFO_MAX_SIZE 512 26 #define MTD_SINGLE_PART_INFO_MAX_SIZE 40 27 28 #define MTD_BLK_TABLE_BLOCK_UNKNOWN (-2) 29 #define MTD_BLK_TABLE_BLOCK_SHIFT (-1) 30 31 static int *mtd_map_blk_table; 32 33 int mtd_blk_map_table_init(struct blk_desc *desc, 34 loff_t offset, 35 size_t length) 36 { 37 u32 blk_total, blk_begin, blk_cnt; 38 struct mtd_info *mtd = NULL; 39 int i, j; 40 41 if (!desc) 42 return -ENODEV; 43 44 switch (desc->devnum) { 45 case BLK_MTD_NAND: 46 case BLK_MTD_SPI_NAND: 47 mtd = desc->bdev->priv; 48 break; 49 default: 50 break; 51 } 52 53 if (!mtd) { 54 return -ENODEV; 55 } else { 56 blk_total = (mtd->size + mtd->erasesize - 1) >> mtd->erasesize_shift; 57 if (!mtd_map_blk_table) { 58 mtd_map_blk_table = (int *)malloc(blk_total * sizeof(int)); 59 if (!mtd_map_blk_table) 60 return -ENOMEM; 61 for (i = 0; i < blk_total; i++) 62 mtd_map_blk_table[i] = MTD_BLK_TABLE_BLOCK_UNKNOWN; 63 } 64 65 blk_begin = (u32)offset >> mtd->erasesize_shift; 66 blk_cnt = ((u32)((offset & mtd->erasesize_mask) + length + \ 67 mtd->erasesize - 1) >> mtd->erasesize_shift); 68 if (blk_begin >= blk_total) { 69 pr_err("map table blk begin[%d] overflow\n", blk_begin); 70 return -EINVAL; 71 } 72 if ((blk_begin + blk_cnt) > blk_total) 73 blk_cnt = blk_total - blk_begin; 74 75 if (mtd_map_blk_table[blk_begin] != MTD_BLK_TABLE_BLOCK_UNKNOWN) 76 return 0; 77 78 j = 0; 79 /* should not across blk_cnt */ 80 for (i = 0; i < blk_cnt; i++) { 81 if (j >= blk_cnt) 82 mtd_map_blk_table[blk_begin + i] = MTD_BLK_TABLE_BLOCK_SHIFT; 83 for (; j < blk_cnt; j++) { 84 if (!mtd_block_isbad(mtd, (blk_begin + j) << mtd->erasesize_shift)) { 85 mtd_map_blk_table[blk_begin + i] = blk_begin + j; 86 j++; 87 if (j == blk_cnt) 88 j++; 89 break; 90 } 91 } 92 } 93 94 return 0; 95 } 96 } 97 98 static bool get_mtd_blk_map_address(struct mtd_info *mtd, loff_t *off) 99 { 100 bool mapped; 101 loff_t offset = *off; 102 size_t block_offset = offset & (mtd->erasesize - 1); 103 104 mapped = false; 105 if (!mtd_map_blk_table || 106 mtd_map_blk_table[(u64)offset >> mtd->erasesize_shift] == 107 MTD_BLK_TABLE_BLOCK_UNKNOWN || 108 mtd_map_blk_table[(u64)offset >> mtd->erasesize_shift] == 109 0xffffffff) 110 return mapped; 111 112 mapped = true; 113 *off = (loff_t)(((u32)mtd_map_blk_table[(u64)offset >> 114 mtd->erasesize_shift] << mtd->erasesize_shift) + block_offset); 115 116 return mapped; 117 } 118 119 void mtd_blk_map_partitions(struct blk_desc *desc) 120 { 121 disk_partition_t info; 122 int i, ret; 123 124 if (!desc) 125 return; 126 127 if (desc->if_type != IF_TYPE_MTD) 128 return; 129 130 for (i = 1; i < MAX_SEARCH_PARTITIONS; i++) { 131 ret = part_get_info(desc, i, &info); 132 if (ret != 0) 133 break; 134 135 if (mtd_blk_map_table_init(desc, 136 info.start << 9, 137 info.size << 9)) { 138 pr_debug("mtd block map table fail\n"); 139 } 140 } 141 } 142 143 void mtd_blk_map_fit(struct blk_desc *desc, ulong sector, void *fit) 144 { 145 struct mtd_info *mtd = NULL; 146 int totalsize = 0; 147 148 if (desc->if_type != IF_TYPE_MTD) 149 return; 150 151 if (desc->devnum == BLK_MTD_NAND) { 152 #if defined(CONFIG_NAND) 153 mtd = dev_get_priv(desc->bdev->parent); 154 #endif 155 } else if (desc->devnum == BLK_MTD_SPI_NAND) { 156 #if defined(CONFIG_MTD_SPI_NAND) 157 mtd = desc->bdev->priv; 158 #endif 159 } 160 161 #ifdef CONFIG_SPL_FIT 162 if (fit_get_totalsize(fit, &totalsize)) 163 debug("Can not find /totalsize node.\n"); 164 #endif 165 if (mtd && totalsize) { 166 if (mtd_blk_map_table_init(desc, sector << 9, totalsize + (size_t)mtd->erasesize)) 167 debug("Map block table fail.\n"); 168 } 169 } 170 171 static __maybe_unused int mtd_map_read(struct mtd_info *mtd, loff_t offset, 172 size_t *length, size_t *actual, 173 loff_t lim, u_char *buffer) 174 { 175 size_t left_to_read = *length; 176 u_char *p_buffer = buffer; 177 int rval; 178 179 while (left_to_read > 0) { 180 size_t block_offset = offset & (mtd->erasesize - 1); 181 size_t read_length; 182 loff_t mapped_offset; 183 184 if (offset >= mtd->size) 185 return 0; 186 187 mapped_offset = offset; 188 if (!get_mtd_blk_map_address(mtd, &mapped_offset)) { 189 if (mtd_block_isbad(mtd, mapped_offset & 190 ~(mtd->erasesize - 1))) { 191 printf("Skipping bad block 0x%08llx\n", 192 offset & ~(mtd->erasesize - 1)); 193 offset += mtd->erasesize - block_offset; 194 continue; 195 } 196 } 197 198 if (left_to_read < (mtd->erasesize - block_offset)) 199 read_length = left_to_read; 200 else 201 read_length = mtd->erasesize - block_offset; 202 203 rval = mtd_read(mtd, mapped_offset, read_length, &read_length, 204 p_buffer); 205 if (rval && rval != -EUCLEAN) { 206 printf("NAND read from offset %llx failed %d\n", 207 offset, rval); 208 *length -= left_to_read; 209 return rval; 210 } 211 212 left_to_read -= read_length; 213 offset += read_length; 214 p_buffer += read_length; 215 } 216 217 return 0; 218 } 219 220 static __maybe_unused int mtd_map_write(struct mtd_info *mtd, loff_t offset, 221 size_t *length, size_t *actual, 222 loff_t lim, u_char *buffer, int flags) 223 { 224 int rval = 0, blocksize; 225 size_t left_to_write = *length; 226 u_char *p_buffer = buffer; 227 struct erase_info ei; 228 229 blocksize = mtd->erasesize; 230 231 /* 232 * nand_write() handles unaligned, partial page writes. 233 * 234 * We allow length to be unaligned, for convenience in 235 * using the $filesize variable. 236 * 237 * However, starting at an unaligned offset makes the 238 * semantics of bad block skipping ambiguous (really, 239 * you should only start a block skipping access at a 240 * partition boundary). So don't try to handle that. 241 */ 242 if ((offset & (mtd->writesize - 1)) != 0) { 243 printf("Attempt to write non page-aligned data\n"); 244 *length = 0; 245 return -EINVAL; 246 } 247 248 while (left_to_write > 0) { 249 size_t block_offset = offset & (mtd->erasesize - 1); 250 size_t write_size, truncated_write_size; 251 loff_t mapped_offset; 252 253 if (offset >= mtd->size) 254 return 0; 255 256 mapped_offset = offset; 257 if (!get_mtd_blk_map_address(mtd, &mapped_offset)) { 258 if (mtd_block_isbad(mtd, mapped_offset & 259 ~(mtd->erasesize - 1))) { 260 printf("Skipping bad block 0x%08llx\n", 261 offset & ~(mtd->erasesize - 1)); 262 offset += mtd->erasesize - block_offset; 263 continue; 264 } 265 } 266 267 if (!(mapped_offset & mtd->erasesize_mask)) { 268 memset(&ei, 0, sizeof(struct erase_info)); 269 ei.addr = mapped_offset; 270 ei.len = mtd->erasesize; 271 rval = mtd_erase(mtd, &ei); 272 if (rval) { 273 pr_info("error %d while erasing %llx\n", rval, 274 mapped_offset); 275 return rval; 276 } 277 } 278 279 if (left_to_write < (blocksize - block_offset)) 280 write_size = left_to_write; 281 else 282 write_size = blocksize - block_offset; 283 284 truncated_write_size = write_size; 285 rval = mtd_write(mtd, mapped_offset, truncated_write_size, 286 (size_t *)(&truncated_write_size), p_buffer); 287 288 offset += write_size; 289 p_buffer += write_size; 290 291 if (rval != 0) { 292 printf("NAND write to offset %llx failed %d\n", 293 offset, rval); 294 *length -= left_to_write; 295 return rval; 296 } 297 298 left_to_write -= write_size; 299 } 300 301 return 0; 302 } 303 304 static __maybe_unused int mtd_map_erase(struct mtd_info *mtd, loff_t offset, 305 size_t length) 306 { 307 struct erase_info ei; 308 loff_t pos, len; 309 int ret; 310 311 pos = offset; 312 len = length; 313 314 if ((pos & mtd->erasesize_mask) || (len & mtd->erasesize_mask)) { 315 pr_err("Attempt to erase non block-aligned data, pos= %llx, len= %llx\n", 316 pos, len); 317 318 return -EINVAL; 319 } 320 321 while (len) { 322 loff_t mapped_offset; 323 324 mapped_offset = pos; 325 if (!get_mtd_blk_map_address(mtd, &mapped_offset)) { 326 if (mtd_block_isbad(mtd, pos) || mtd_block_isreserved(mtd, pos)) { 327 pr_debug("attempt to erase a bad/reserved block @%llx\n", 328 pos); 329 pos += mtd->erasesize; 330 continue; 331 } 332 } 333 334 memset(&ei, 0, sizeof(struct erase_info)); 335 ei.addr = mapped_offset; 336 ei.len = mtd->erasesize; 337 ret = mtd_erase(mtd, &ei); 338 if (ret) { 339 pr_err("map_erase error %d while erasing %llx\n", ret, 340 pos); 341 return ret; 342 } 343 344 pos += mtd->erasesize; 345 len -= mtd->erasesize; 346 } 347 348 return 0; 349 } 350 351 char *mtd_part_parse(struct blk_desc *dev_desc) 352 { 353 char mtd_part_info_temp[MTD_SINGLE_PART_INFO_MAX_SIZE] = {0}; 354 u32 length, data_len = MTD_PART_INFO_MAX_SIZE; 355 disk_partition_t info; 356 char *mtd_part_info_p; 357 struct mtd_info *mtd; 358 char *mtd_part_info; 359 int ret; 360 int p; 361 362 #ifndef CONFIG_SPL_BUILD 363 dev_desc = rockchip_get_bootdev(); 364 #endif 365 if (!dev_desc) 366 return NULL; 367 368 mtd = (struct mtd_info *)dev_desc->bdev->priv; 369 if (!mtd) 370 return NULL; 371 372 mtd_part_info = (char *)calloc(MTD_PART_INFO_MAX_SIZE, sizeof(char)); 373 if (!mtd_part_info) { 374 printf("%s: Fail to malloc!", __func__); 375 return NULL; 376 } 377 378 mtd_part_info_p = mtd_part_info; 379 snprintf(mtd_part_info_p, data_len - 1, "%s%s:", 380 MTD_PART_NAND_HEAD, 381 dev_desc->product); 382 data_len -= strlen(mtd_part_info_p); 383 mtd_part_info_p = mtd_part_info_p + strlen(mtd_part_info_p); 384 385 for (p = 1; p < MAX_SEARCH_PARTITIONS; p++) { 386 ret = part_get_info(dev_desc, p, &info); 387 if (ret) 388 break; 389 390 debug("name is %s, start addr is %x\n", info.name, 391 (int)(size_t)info.start); 392 393 snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 394 (int)(size_t)info.size << 9, 395 (int)(size_t)info.start << 9, 396 info.name); 397 snprintf(mtd_part_info_temp, MTD_SINGLE_PART_INFO_MAX_SIZE - 1, 398 "0x%x@0x%x(%s)", 399 (int)(size_t)info.size << 9, 400 (int)(size_t)info.start << 9, 401 info.name); 402 strcat(mtd_part_info, ","); 403 if (part_get_info(dev_desc, p + 1, &info)) { 404 /* Partition with grow tag in parameter will be resized */ 405 if ((info.size + info.start + 64) >= dev_desc->lba) { 406 if (dev_desc->devnum == BLK_MTD_SPI_NOR) { 407 /* Nor is 64KB erase block(kernel) and gpt table just 408 * resserve 33 sectors for the last partition. This 409 * will erase the backup gpt table by user program, 410 * so reserve one block. 411 */ 412 snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 413 (int)(size_t)(info.size - 414 (info.size - 1) % 415 (0x10000 >> 9) - 1) << 9, 416 (int)(size_t)info.start << 9, 417 info.name); 418 break; 419 } else { 420 /* Nand flash is erased by block and gpt table just 421 * resserve 33 sectors for the last partition. This 422 * will erase the backup gpt table by user program, 423 * so reserve one block. 424 */ 425 snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 426 (int)(size_t)(info.size - 427 (info.size - 1) % 428 (mtd->erasesize >> 9) - 1) << 9, 429 (int)(size_t)info.start << 9, 430 info.name); 431 break; 432 } 433 } else { 434 snprintf(mtd_part_info_temp, MTD_SINGLE_PART_INFO_MAX_SIZE - 1, 435 "0x%x@0x%x(%s)", 436 (int)(size_t)info.size << 9, 437 (int)(size_t)info.start << 9, 438 info.name); 439 break; 440 } 441 } 442 length = strlen(mtd_part_info_temp); 443 data_len -= length; 444 mtd_part_info_p = mtd_part_info_p + length + 1; 445 memset(mtd_part_info_temp, 0, MTD_SINGLE_PART_INFO_MAX_SIZE); 446 } 447 448 return mtd_part_info; 449 } 450 451 ulong mtd_dread(struct udevice *udev, lbaint_t start, 452 lbaint_t blkcnt, void *dst) 453 { 454 struct blk_desc *desc = dev_get_uclass_platdata(udev); 455 #if defined(CONFIG_NAND) || defined(CONFIG_MTD_SPI_NAND) || defined(CONFIG_SPI_FLASH_MTD) 456 loff_t off = (loff_t)(start * 512); 457 size_t rwsize = blkcnt * 512; 458 #endif 459 struct mtd_info *mtd; 460 int ret = 0; 461 462 if (!desc) 463 return ret; 464 465 mtd = desc->bdev->priv; 466 if (!mtd) 467 return 0; 468 469 if (blkcnt == 0) 470 return 0; 471 472 pr_debug("mtd dread %s %lx %lx\n", mtd->name, start, blkcnt); 473 474 if (desc->devnum == BLK_MTD_NAND) { 475 ret = mtd_map_read(mtd, off, &rwsize, 476 NULL, mtd->size, 477 (u_char *)(dst)); 478 if (!ret) 479 return blkcnt; 480 else 481 return 0; 482 } else if (desc->devnum == BLK_MTD_SPI_NAND) { 483 ret = mtd_map_read(mtd, off, &rwsize, 484 NULL, mtd->size, 485 (u_char *)(dst)); 486 if (!ret) 487 return blkcnt; 488 else 489 return 0; 490 } else if (desc->devnum == BLK_MTD_SPI_NOR) { 491 #if defined(CONFIG_SPI_FLASH_MTD) || defined(CONFIG_SPL_BUILD) 492 struct spi_nor *nor = (struct spi_nor *)mtd->priv; 493 struct spi_slave *spi = nor->spi; 494 size_t retlen_nor; 495 496 if (desc->op_flag == BLK_PRE_RW) 497 spi->mode |= SPI_DMA_PREPARE; 498 mtd_read(mtd, off, rwsize, &retlen_nor, dst); 499 if (desc->op_flag == BLK_PRE_RW) 500 spi->mode &= ~SPI_DMA_PREPARE; 501 502 if (retlen_nor == rwsize) 503 return blkcnt; 504 else 505 #endif 506 return 0; 507 } else { 508 return 0; 509 } 510 } 511 512 #if CONFIG_IS_ENABLED(MTD_WRITE) 513 ulong mtd_dwrite(struct udevice *udev, lbaint_t start, 514 lbaint_t blkcnt, const void *src) 515 { 516 struct blk_desc *desc = dev_get_uclass_platdata(udev); 517 #if defined(CONFIG_NAND) || defined(CONFIG_MTD_SPI_NAND) || defined(CONFIG_SPI_FLASH_MTD) 518 loff_t off = (loff_t)(start * 512); 519 size_t rwsize = blkcnt * 512; 520 #endif 521 struct mtd_info *mtd; 522 int ret = 0; 523 524 if (!desc) 525 return ret; 526 527 mtd = desc->bdev->priv; 528 if (!mtd) 529 return 0; 530 531 pr_debug("mtd dwrite %s %lx %lx\n", mtd->name, start, blkcnt); 532 533 if (blkcnt == 0) 534 return 0; 535 536 if (desc->devnum == BLK_MTD_NAND || 537 desc->devnum == BLK_MTD_SPI_NAND || 538 desc->devnum == BLK_MTD_SPI_NOR) { 539 if (desc->op_flag == BLK_MTD_CONT_WRITE) { 540 ret = mtd_map_write(mtd, off, &rwsize, 541 NULL, mtd->size, 542 (u_char *)(src), 0); 543 if (!ret) 544 return blkcnt; 545 else 546 return 0; 547 } else { 548 lbaint_t off_aligned, alinged; 549 size_t rwsize_aligned; 550 u8 *p_buf; 551 552 alinged = off & mtd->erasesize_mask; 553 off_aligned = off - alinged; 554 rwsize_aligned = rwsize + alinged; 555 rwsize_aligned = (rwsize_aligned + mtd->erasesize - 1) & 556 ~(mtd->erasesize - 1); 557 558 p_buf = malloc(rwsize_aligned); 559 if (!p_buf) { 560 printf("%s: Fail to malloc!", __func__); 561 return 0; 562 } 563 564 ret = mtd_map_read(mtd, off_aligned, &rwsize_aligned, 565 NULL, mtd->size, 566 (u_char *)(p_buf)); 567 if (ret) { 568 free(p_buf); 569 return 0; 570 } 571 572 memcpy(p_buf + alinged, src, rwsize); 573 574 ret = mtd_map_write(mtd, off_aligned, &rwsize_aligned, 575 NULL, mtd->size, 576 (u_char *)(p_buf), 0); 577 free(p_buf); 578 if (!ret) 579 return blkcnt; 580 else 581 return 0; 582 } 583 } else { 584 return 0; 585 } 586 587 return 0; 588 } 589 590 ulong mtd_derase(struct udevice *udev, lbaint_t start, 591 lbaint_t blkcnt) 592 { 593 struct blk_desc *desc = dev_get_uclass_platdata(udev); 594 #if defined(CONFIG_NAND) || defined(CONFIG_MTD_SPI_NAND) || defined(CONFIG_SPI_FLASH_MTD) 595 loff_t off = (loff_t)(start * 512); 596 size_t len = blkcnt * 512; 597 #endif 598 struct mtd_info *mtd; 599 int ret = 0; 600 601 if (!desc) 602 return ret; 603 604 mtd = desc->bdev->priv; 605 if (!mtd) 606 return 0; 607 608 pr_debug("mtd derase %s %lx %lx\n", mtd->name, start, blkcnt); 609 610 if (blkcnt == 0) 611 return 0; 612 613 if (desc->devnum == BLK_MTD_NAND || 614 desc->devnum == BLK_MTD_SPI_NAND || 615 desc->devnum == BLK_MTD_SPI_NOR) { 616 ret = mtd_map_erase(mtd, off, len); 617 if (ret) 618 return ret; 619 } else { 620 return 0; 621 } 622 623 return blkcnt; 624 } 625 #endif 626 627 static int mtd_blk_probe(struct udevice *udev) 628 { 629 struct mtd_info *mtd; 630 struct blk_desc *desc = dev_get_uclass_platdata(udev); 631 int ret, i = 0; 632 633 mtd = dev_get_uclass_priv(udev->parent); 634 if (mtd->type == MTD_NANDFLASH && desc->devnum == BLK_MTD_NAND) { 635 #ifndef CONFIG_SPL_BUILD 636 mtd = dev_get_priv(udev->parent); 637 #endif 638 } 639 640 /* Fill mtd devices information */ 641 if (is_power_of_2(mtd->erasesize)) 642 mtd->erasesize_shift = ffs(mtd->erasesize) - 1; 643 else 644 mtd->erasesize_shift = 0; 645 646 if (is_power_of_2(mtd->writesize)) 647 mtd->writesize_shift = ffs(mtd->writesize) - 1; 648 else 649 mtd->writesize_shift = 0; 650 651 mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; 652 mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; 653 654 desc->bdev->priv = mtd; 655 sprintf(desc->vendor, "0x%.4x", 0x2207); 656 if (strncmp(mtd->name, "nand", 4) == 0) 657 memcpy(desc->product, "rk-nand", strlen("rk-nand")); 658 else 659 memcpy(desc->product, mtd->name, strlen(mtd->name)); 660 memcpy(desc->revision, "V1.00", sizeof("V1.00")); 661 if (mtd->type == MTD_NANDFLASH) { 662 #ifdef CONFIG_NAND 663 if (desc->devnum == BLK_MTD_NAND) 664 i = NAND_BBT_SCAN_MAXBLOCKS; 665 else if (desc->devnum == BLK_MTD_SPI_NAND) 666 i = NANDDEV_BBT_SCAN_MAXBLOCKS; 667 #endif 668 669 /* 670 * Find the first useful block in the end, 671 * and it is the end lba of the nand storage. 672 */ 673 for (; i < (mtd->size / mtd->erasesize); i++) { 674 ret = mtd_block_isbad(mtd, 675 mtd->size - mtd->erasesize * (i + 1)); 676 if (!ret) { 677 desc->lba = (mtd->size >> 9) - 678 (mtd->erasesize >> 9) * i; 679 break; 680 } 681 } 682 } else { 683 desc->lba = mtd->size >> 9; 684 } 685 686 debug("MTD: desc->lba is %lx\n", desc->lba); 687 688 return 0; 689 } 690 691 static const struct blk_ops mtd_blk_ops = { 692 .read = mtd_dread, 693 #if CONFIG_IS_ENABLED(MTD_WRITE) 694 .write = mtd_dwrite, 695 .erase = mtd_derase, 696 #endif 697 }; 698 699 U_BOOT_DRIVER(mtd_blk) = { 700 .name = "mtd_blk", 701 .id = UCLASS_BLK, 702 .ops = &mtd_blk_ops, 703 .probe = mtd_blk_probe, 704 }; 705