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 if (!mtd) 39 return NULL; 40 41 mtd_part_info = (char *)calloc(MTD_PART_INFO_MAX_SIZE, sizeof(char)); 42 if (!mtd_part_info) { 43 printf("%s: Fail to malloc!", __func__); 44 return NULL; 45 } 46 47 mtd_part_info_p = mtd_part_info; 48 snprintf(mtd_part_info_p, data_len - 1, "%s%s:", 49 MTD_PART_NAND_HEAD, 50 dev_desc->product); 51 data_len -= strlen(mtd_part_info_p); 52 mtd_part_info_p = mtd_part_info_p + strlen(mtd_part_info_p); 53 54 for (p = 1; p < MAX_SEARCH_PARTITIONS; p++) { 55 ret = part_get_info(dev_desc, p, &info); 56 if (ret) 57 break; 58 59 debug("name is %s, start addr is %x\n", info.name, 60 (int)(size_t)info.start); 61 62 snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 63 (int)(size_t)info.size << 9, 64 (int)(size_t)info.start << 9, 65 info.name); 66 snprintf(mtd_part_info_temp, MTD_SINGLE_PART_INFO_MAX_SIZE - 1, 67 "0x%x@0x%x(%s)", 68 (int)(size_t)info.size << 9, 69 (int)(size_t)info.start << 9, 70 info.name); 71 strcat(mtd_part_info, ","); 72 if (part_get_info(dev_desc, p + 1, &info)) { 73 /* Nand flash is erased by block and gpt table just 74 * resserve 33 sectors for the last partition. This 75 * will erase the backup gpt table by user program, 76 * so reserve one block. 77 */ 78 snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 79 (int)(size_t)(info.size - 80 (info.size - 1) % 81 (mtd->erasesize >> 9) - 1) << 9, 82 (int)(size_t)info.start << 9, 83 info.name); 84 break; 85 } 86 length = strlen(mtd_part_info_temp); 87 data_len -= length; 88 mtd_part_info_p = mtd_part_info_p + length + 1; 89 memset(mtd_part_info_temp, 0, MTD_SINGLE_PART_INFO_MAX_SIZE); 90 } 91 92 return mtd_part_info; 93 } 94 95 ulong mtd_dread(struct udevice *udev, lbaint_t start, 96 lbaint_t blkcnt, void *dst) 97 { 98 struct blk_desc *desc = dev_get_uclass_platdata(udev); 99 #if defined(CONFIG_NAND) || defined(CONFIG_MTD_SPI_NAND) || defined(CONFIG_SPI_FLASH_MTD) 100 loff_t off = (loff_t)(start * 512); 101 size_t rwsize = blkcnt * 512; 102 #endif 103 struct mtd_info *mtd; 104 int ret = 0; 105 106 if (!desc) 107 return ret; 108 109 mtd = desc->bdev->priv; 110 if (!mtd) 111 return 0; 112 113 if (blkcnt == 0) 114 return 0; 115 116 if (desc->devnum == BLK_MTD_NAND) { 117 #if defined(CONFIG_NAND) && !defined(CONFIG_SPL_BUILD) 118 mtd = dev_get_priv(udev->parent); 119 if (!mtd) 120 return 0; 121 122 ret = nand_read_skip_bad(mtd, off, &rwsize, 123 NULL, mtd->size, 124 (u_char *)(dst)); 125 if (!ret) 126 return blkcnt; 127 else 128 #endif 129 return 0; 130 } else if (desc->devnum == BLK_MTD_SPI_NAND) { 131 #if defined(CONFIG_MTD_SPI_NAND) && !defined(CONFIG_SPL_BUILD) 132 ret = nand_read_skip_bad(mtd, off, &rwsize, 133 NULL, mtd->size, 134 (u_char *)(dst)); 135 if (!ret) 136 return blkcnt; 137 else 138 #elif defined(CONFIG_SPL_BUILD) 139 size_t retlen; 140 141 mtd_read(mtd, off, rwsize, &retlen, dst); 142 if (retlen == rwsize) 143 return blkcnt; 144 else 145 #endif 146 return 0; 147 } else if (desc->devnum == BLK_MTD_SPI_NOR) { 148 #if defined(CONFIG_SPI_FLASH_MTD) || defined(CONFIG_SPL_BUILD) 149 size_t retlen_nor; 150 151 mtd_read(mtd, off, rwsize, &retlen_nor, dst); 152 if (retlen_nor == rwsize) 153 return blkcnt; 154 else 155 #endif 156 return 0; 157 } else { 158 return 0; 159 } 160 } 161 162 ulong mtd_dwrite(struct udevice *udev, lbaint_t start, 163 lbaint_t blkcnt, const void *src) 164 { 165 /* Not implemented */ 166 return 0; 167 } 168 169 ulong mtd_derase(struct udevice *udev, lbaint_t start, 170 lbaint_t blkcnt) 171 { 172 /* Not implemented */ 173 return 0; 174 } 175 176 static int mtd_blk_probe(struct udevice *udev) 177 { 178 struct mtd_info *mtd = dev_get_uclass_priv(udev->parent); 179 struct blk_desc *desc = dev_get_uclass_platdata(udev); 180 int ret, i; 181 182 desc->bdev->priv = mtd; 183 sprintf(desc->vendor, "0x%.4x", 0x2207); 184 memcpy(desc->product, mtd->name, strlen(mtd->name)); 185 memcpy(desc->revision, "V1.00", sizeof("V1.00")); 186 if (mtd->type == MTD_NANDFLASH) { 187 if (desc->devnum == BLK_MTD_NAND) 188 mtd = dev_get_priv(udev->parent); 189 /* 190 * Find the first useful block in the end, 191 * and it is the end lba of the nand storage. 192 */ 193 for (i = 0; i < (mtd->size / mtd->erasesize); i++) { 194 ret = mtd_block_isbad(mtd, 195 mtd->size - mtd->erasesize * (i + 1)); 196 if (!ret) { 197 desc->lba = (mtd->size >> 9) - 198 (mtd->erasesize >> 9) * i; 199 break; 200 } 201 } 202 } else { 203 desc->lba = mtd->size >> 9; 204 } 205 206 debug("MTD: desc->lba is %lx\n", desc->lba); 207 208 return 0; 209 } 210 211 static const struct blk_ops mtd_blk_ops = { 212 .read = mtd_dread, 213 #ifndef CONFIG_SPL_BUILD 214 .write = mtd_dwrite, 215 .erase = mtd_derase, 216 #endif 217 }; 218 219 U_BOOT_DRIVER(mtd_blk) = { 220 .name = "mtd_blk", 221 .id = UCLASS_BLK, 222 .ops = &mtd_blk_ops, 223 .probe = mtd_blk_probe, 224 }; 225