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 char *mtd_part_parse(void) 22 { 23 char mtd_part_info_temp[MTD_SINGLE_PART_INFO_MAX_SIZE] = {0}; 24 u32 length, data_len = MTD_PART_INFO_MAX_SIZE; 25 struct blk_desc *dev_desc; 26 disk_partition_t info; 27 char *mtd_part_info_p; 28 struct mtd_info *mtd; 29 char *mtd_part_info; 30 int ret; 31 int p; 32 33 dev_desc = rockchip_get_bootdev(); 34 if (!dev_desc) 35 return NULL; 36 37 mtd = (struct mtd_info *)dev_desc->bdev->priv; 38 mtd_part_info = (char *)calloc(MTD_PART_INFO_MAX_SIZE, sizeof(char)); 39 if (!mtd_part_info) { 40 printf("%s: Fail to malloc!", __func__); 41 return NULL; 42 } 43 44 mtd_part_info_p = mtd_part_info; 45 snprintf(mtd_part_info_p, data_len - 1, "%s%s:", 46 MTD_PART_NAND_HEAD, 47 dev_desc->product); 48 data_len -= strlen(mtd_part_info_p); 49 mtd_part_info_p = mtd_part_info_p + strlen(mtd_part_info_p); 50 51 for (p = 1; p < MAX_SEARCH_PARTITIONS; p++) { 52 ret = part_get_info(dev_desc, p, &info); 53 if (ret) 54 break; 55 56 debug("name is %s, start addr is %x\n", info.name, 57 (int)(size_t)info.start); 58 59 snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 60 (int)(size_t)info.size << 9, 61 (int)(size_t)info.start << 9, 62 info.name); 63 snprintf(mtd_part_info_temp, MTD_SINGLE_PART_INFO_MAX_SIZE - 1, 64 "0x%x@0x%x(%s)", 65 (int)(size_t)info.size << 9, 66 (int)(size_t)info.start << 9, 67 info.name); 68 strcat(mtd_part_info, ","); 69 if (part_get_info(dev_desc, p + 1, &info)) { 70 /* Nand flash is erased by block and gpt table just 71 * resserve 33 sectors for the last partition. This 72 * will erase the backup gpt table by user program, 73 * so reserve one block. 74 */ 75 snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 76 (int)(size_t)(info.size - 77 (info.size - 1) % 78 (mtd->erasesize >> 9) - 1) << 9, 79 (int)(size_t)info.start << 9, 80 info.name); 81 break; 82 } 83 length = strlen(mtd_part_info_temp); 84 data_len -= length; 85 mtd_part_info_p = mtd_part_info_p + length + 1; 86 memset(mtd_part_info_temp, 0, MTD_SINGLE_PART_INFO_MAX_SIZE); 87 } 88 89 return mtd_part_info; 90 } 91 92 ulong mtd_dread(struct udevice *udev, lbaint_t start, 93 lbaint_t blkcnt, void *dst) 94 { 95 struct blk_desc *desc = dev_get_uclass_platdata(udev); 96 97 if (!desc) 98 return 0; 99 100 if (blkcnt == 0) 101 return 0; 102 103 if (desc->devnum == BLK_MTD_NAND) { 104 int ret = 0; 105 size_t rwsize = blkcnt * 512; 106 struct mtd_info *mtd = dev_get_priv(udev->parent); 107 struct nand_chip *chip = mtd_to_nand(mtd); 108 loff_t off = (loff_t)(start * 512); 109 110 if (!mtd) { 111 puts("\nno mtd available\n"); 112 return 0; 113 } 114 115 if (!chip) { 116 puts("\nno chip available\n"); 117 return 0; 118 } 119 120 ret = nand_read_skip_bad(&chip->mtd, off, &rwsize, 121 NULL, chip->mtd.size, 122 (u_char *)(dst)); 123 if (ret) 124 return 0; 125 else 126 return blkcnt; 127 } else if (desc->devnum == BLK_MTD_SPI_NAND) { 128 /* Not implemented */ 129 return 0; 130 } else if (desc->devnum == BLK_MTD_SPI_NOR) { 131 /* Not implemented */ 132 return 0; 133 } else { 134 return 0; 135 } 136 } 137 138 ulong mtd_dwrite(struct udevice *udev, lbaint_t start, 139 lbaint_t blkcnt, const void *src) 140 { 141 /* Not implemented */ 142 return 0; 143 } 144 145 ulong mtd_derase(struct udevice *udev, lbaint_t start, 146 lbaint_t blkcnt) 147 { 148 /* Not implemented */ 149 return 0; 150 } 151 152 static int mtd_blk_probe(struct udevice *udev) 153 { 154 struct blk_desc *desc = dev_get_uclass_platdata(udev); 155 struct mtd_info *mtd = dev_get_priv(udev->parent); 156 157 desc->bdev->priv = mtd; 158 sprintf(desc->vendor, "0x%.4x", 0x2207); 159 memcpy(desc->product, mtd->name, strlen(mtd->name)); 160 memcpy(desc->revision, "V1.00", sizeof("V1.00")); 161 if (mtd->type == MTD_NANDFLASH) { 162 /* Reserve 4 blocks for BBT(Bad Block Table) */ 163 desc->lba = (mtd->size >> 9) - (mtd->erasesize >> 9) * 4; 164 } else { 165 desc->lba = mtd->size >> 9; 166 } 167 168 return 0; 169 } 170 171 static const struct blk_ops mtd_blk_ops = { 172 .read = mtd_dread, 173 #ifndef CONFIG_SPL_BUILD 174 .write = mtd_dwrite, 175 .erase = mtd_derase, 176 #endif 177 }; 178 179 U_BOOT_DRIVER(mtd_blk) = { 180 .name = "mtd_blk", 181 .id = UCLASS_BLK, 182 .ops = &mtd_blk_ops, 183 .probe = mtd_blk_probe, 184 }; 185