1054229abSJason Zhu /* 2054229abSJason Zhu * (C) Copyright 2019 Rockchip Electronics Co., Ltd 3054229abSJason Zhu * 4054229abSJason Zhu * SPDX-License-Identifier: GPL-2.0+ 5054229abSJason Zhu */ 6054229abSJason Zhu 7054229abSJason Zhu #include <common.h> 822dccd11SJason Zhu #include <blk.h> 922dccd11SJason Zhu #include <boot_rkimg.h> 10054229abSJason Zhu #include <dm.h> 11054229abSJason Zhu #include <errno.h> 1222dccd11SJason Zhu #include <malloc.h> 13054229abSJason Zhu #include <nand.h> 1422dccd11SJason Zhu #include <part.h> 15054229abSJason Zhu #include <dm/device-internal.h> 16054229abSJason Zhu 1722dccd11SJason Zhu #define MTD_PART_NAND_HEAD "mtdparts=" 1822dccd11SJason Zhu #define MTD_PART_INFO_MAX_SIZE 512 1922dccd11SJason Zhu #define MTD_SINGLE_PART_INFO_MAX_SIZE 40 2022dccd11SJason Zhu 2122dccd11SJason Zhu char *mtd_part_parse(void) 2222dccd11SJason Zhu { 2322dccd11SJason Zhu char mtd_part_info_temp[MTD_SINGLE_PART_INFO_MAX_SIZE] = {0}; 2422dccd11SJason Zhu u32 length, data_len = MTD_PART_INFO_MAX_SIZE; 2522dccd11SJason Zhu struct blk_desc *dev_desc; 2622dccd11SJason Zhu disk_partition_t info; 2722dccd11SJason Zhu char *mtd_part_info_p; 28c9289eddSJason Zhu struct mtd_info *mtd; 2922dccd11SJason Zhu char *mtd_part_info; 3022dccd11SJason Zhu int ret; 3122dccd11SJason Zhu int p; 3222dccd11SJason Zhu 3322dccd11SJason Zhu dev_desc = rockchip_get_bootdev(); 3422dccd11SJason Zhu if (!dev_desc) 3522dccd11SJason Zhu return NULL; 3622dccd11SJason Zhu 37c9289eddSJason Zhu mtd = (struct mtd_info *)dev_desc->bdev->priv; 38ec6d4288SJason Zhu if (!mtd) 39ec6d4288SJason Zhu return NULL; 40ec6d4288SJason Zhu 4122dccd11SJason Zhu mtd_part_info = (char *)calloc(MTD_PART_INFO_MAX_SIZE, sizeof(char)); 4222dccd11SJason Zhu if (!mtd_part_info) { 4322dccd11SJason Zhu printf("%s: Fail to malloc!", __func__); 4422dccd11SJason Zhu return NULL; 4522dccd11SJason Zhu } 4622dccd11SJason Zhu 4722dccd11SJason Zhu mtd_part_info_p = mtd_part_info; 4822dccd11SJason Zhu snprintf(mtd_part_info_p, data_len - 1, "%s%s:", 4922dccd11SJason Zhu MTD_PART_NAND_HEAD, 5022dccd11SJason Zhu dev_desc->product); 5122dccd11SJason Zhu data_len -= strlen(mtd_part_info_p); 5222dccd11SJason Zhu mtd_part_info_p = mtd_part_info_p + strlen(mtd_part_info_p); 5322dccd11SJason Zhu 5422dccd11SJason Zhu for (p = 1; p < MAX_SEARCH_PARTITIONS; p++) { 5522dccd11SJason Zhu ret = part_get_info(dev_desc, p, &info); 5622dccd11SJason Zhu if (ret) 5722dccd11SJason Zhu break; 5822dccd11SJason Zhu 5922dccd11SJason Zhu debug("name is %s, start addr is %x\n", info.name, 6022dccd11SJason Zhu (int)(size_t)info.start); 6122dccd11SJason Zhu 6222dccd11SJason Zhu snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 6322dccd11SJason Zhu (int)(size_t)info.size << 9, 6422dccd11SJason Zhu (int)(size_t)info.start << 9, 6522dccd11SJason Zhu info.name); 6622dccd11SJason Zhu snprintf(mtd_part_info_temp, MTD_SINGLE_PART_INFO_MAX_SIZE - 1, 6722dccd11SJason Zhu "0x%x@0x%x(%s)", 6822dccd11SJason Zhu (int)(size_t)info.size << 9, 6922dccd11SJason Zhu (int)(size_t)info.start << 9, 7022dccd11SJason Zhu info.name); 7122dccd11SJason Zhu strcat(mtd_part_info, ","); 7222dccd11SJason Zhu if (part_get_info(dev_desc, p + 1, &info)) { 73c9289eddSJason Zhu /* Nand flash is erased by block and gpt table just 74c9289eddSJason Zhu * resserve 33 sectors for the last partition. This 75c9289eddSJason Zhu * will erase the backup gpt table by user program, 76c9289eddSJason Zhu * so reserve one block. 77c9289eddSJason Zhu */ 78c9289eddSJason Zhu snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)", 79c9289eddSJason Zhu (int)(size_t)(info.size - 80c9289eddSJason Zhu (info.size - 1) % 81c9289eddSJason Zhu (mtd->erasesize >> 9) - 1) << 9, 8222dccd11SJason Zhu (int)(size_t)info.start << 9, 8322dccd11SJason Zhu info.name); 8422dccd11SJason Zhu break; 8522dccd11SJason Zhu } 8622dccd11SJason Zhu length = strlen(mtd_part_info_temp); 8722dccd11SJason Zhu data_len -= length; 8822dccd11SJason Zhu mtd_part_info_p = mtd_part_info_p + length + 1; 8922dccd11SJason Zhu memset(mtd_part_info_temp, 0, MTD_SINGLE_PART_INFO_MAX_SIZE); 9022dccd11SJason Zhu } 9122dccd11SJason Zhu 9222dccd11SJason Zhu return mtd_part_info; 9322dccd11SJason Zhu } 9422dccd11SJason Zhu 95054229abSJason Zhu ulong mtd_dread(struct udevice *udev, lbaint_t start, 96054229abSJason Zhu lbaint_t blkcnt, void *dst) 97054229abSJason Zhu { 98054229abSJason Zhu struct blk_desc *desc = dev_get_uclass_platdata(udev); 99*0dccd0d8SJason Zhu #if defined(CONFIG_NAND) || defined(CONFIG_MTD_SPI_NAND) || defined(CONFIG_SPI_FLASH_MTD) 1006e8ac5a8SJason Zhu loff_t off = (loff_t)(start * 512); 1016e8ac5a8SJason Zhu size_t rwsize = blkcnt * 512; 102*0dccd0d8SJason Zhu #endif 1036e8ac5a8SJason Zhu struct mtd_info *mtd; 104bbb83f58SJason Zhu int ret = 0; 105054229abSJason Zhu 106054229abSJason Zhu if (!desc) 10739e38ab3SJason Zhu return ret; 108054229abSJason Zhu 1096e8ac5a8SJason Zhu mtd = desc->bdev->priv; 1106e8ac5a8SJason Zhu if (!mtd) 1116e8ac5a8SJason Zhu return 0; 1126e8ac5a8SJason Zhu 113054229abSJason Zhu if (blkcnt == 0) 114054229abSJason Zhu return 0; 115054229abSJason Zhu 116054229abSJason Zhu if (desc->devnum == BLK_MTD_NAND) { 11739e38ab3SJason Zhu #if defined(CONFIG_NAND) && !defined(CONFIG_SPL_BUILD) 1188cf6fca4SJason Zhu mtd = dev_get_priv(udev->parent); 1198cf6fca4SJason Zhu if (!mtd) 1208cf6fca4SJason Zhu return 0; 1218cf6fca4SJason Zhu 1226e8ac5a8SJason Zhu ret = nand_read_skip_bad(mtd, off, &rwsize, 1236e8ac5a8SJason Zhu NULL, mtd->size, 124054229abSJason Zhu (u_char *)(dst)); 1256e8ac5a8SJason Zhu if (!ret) 126054229abSJason Zhu return blkcnt; 1276e8ac5a8SJason Zhu else 1286e8ac5a8SJason Zhu #endif 1296e8ac5a8SJason Zhu return 0; 130054229abSJason Zhu } else if (desc->devnum == BLK_MTD_SPI_NAND) { 13139e38ab3SJason Zhu #if defined(CONFIG_MTD_SPI_NAND) && !defined(CONFIG_SPL_BUILD) 132bbb83f58SJason Zhu ret = nand_read_skip_bad(mtd, off, &rwsize, 133bbb83f58SJason Zhu NULL, mtd->size, 134bbb83f58SJason Zhu (u_char *)(dst)); 135bbb83f58SJason Zhu if (!ret) 1366e8ac5a8SJason Zhu return blkcnt; 1376e8ac5a8SJason Zhu else 13839e38ab3SJason Zhu #elif defined(CONFIG_SPL_BUILD) 13939e38ab3SJason Zhu size_t retlen; 140*0dccd0d8SJason Zhu 14139e38ab3SJason Zhu mtd_read(mtd, off, rwsize, &retlen, dst); 14239e38ab3SJason Zhu if (retlen == rwsize) 14339e38ab3SJason Zhu return blkcnt; 144*0dccd0d8SJason Zhu else 1456e8ac5a8SJason Zhu #endif 146054229abSJason Zhu return 0; 147054229abSJason Zhu } else if (desc->devnum == BLK_MTD_SPI_NOR) { 148*0dccd0d8SJason Zhu #if defined(CONFIG_SPI_FLASH_MTD) || defined(CONFIG_SPL_BUILD) 149*0dccd0d8SJason Zhu size_t retlen_nor; 150*0dccd0d8SJason Zhu 151*0dccd0d8SJason Zhu mtd_read(mtd, off, rwsize, &retlen_nor, dst); 152*0dccd0d8SJason Zhu if (retlen_nor == rwsize) 153*0dccd0d8SJason Zhu return blkcnt; 154*0dccd0d8SJason Zhu else 155*0dccd0d8SJason Zhu #endif 156054229abSJason Zhu return 0; 157054229abSJason Zhu } else { 158054229abSJason Zhu return 0; 159054229abSJason Zhu } 160054229abSJason Zhu } 161054229abSJason Zhu 162054229abSJason Zhu ulong mtd_dwrite(struct udevice *udev, lbaint_t start, 163054229abSJason Zhu lbaint_t blkcnt, const void *src) 164054229abSJason Zhu { 165054229abSJason Zhu /* Not implemented */ 166054229abSJason Zhu return 0; 167054229abSJason Zhu } 168054229abSJason Zhu 169054229abSJason Zhu ulong mtd_derase(struct udevice *udev, lbaint_t start, 170054229abSJason Zhu lbaint_t blkcnt) 171054229abSJason Zhu { 172054229abSJason Zhu /* Not implemented */ 173054229abSJason Zhu return 0; 174054229abSJason Zhu } 175054229abSJason Zhu 176054229abSJason Zhu static int mtd_blk_probe(struct udevice *udev) 177054229abSJason Zhu { 1786e8ac5a8SJason Zhu struct mtd_info *mtd = dev_get_uclass_priv(udev->parent); 179054229abSJason Zhu struct blk_desc *desc = dev_get_uclass_platdata(udev); 180054229abSJason Zhu 181c9289eddSJason Zhu desc->bdev->priv = mtd; 182054229abSJason Zhu sprintf(desc->vendor, "0x%.4x", 0x2207); 183e6482de4SJason Zhu memcpy(desc->product, mtd->name, strlen(mtd->name)); 184054229abSJason Zhu memcpy(desc->revision, "V1.00", sizeof("V1.00")); 185f1892190SJason Zhu if (mtd->type == MTD_NANDFLASH) { 186f1892190SJason Zhu /* Reserve 4 blocks for BBT(Bad Block Table) */ 187f1892190SJason Zhu desc->lba = (mtd->size >> 9) - (mtd->erasesize >> 9) * 4; 188f1892190SJason Zhu } else { 189f1892190SJason Zhu desc->lba = mtd->size >> 9; 190f1892190SJason Zhu } 191054229abSJason Zhu 192054229abSJason Zhu return 0; 193054229abSJason Zhu } 194054229abSJason Zhu 195054229abSJason Zhu static const struct blk_ops mtd_blk_ops = { 196054229abSJason Zhu .read = mtd_dread, 197054229abSJason Zhu #ifndef CONFIG_SPL_BUILD 198054229abSJason Zhu .write = mtd_dwrite, 199054229abSJason Zhu .erase = mtd_derase, 200054229abSJason Zhu #endif 201054229abSJason Zhu }; 202054229abSJason Zhu 203054229abSJason Zhu U_BOOT_DRIVER(mtd_blk) = { 204054229abSJason Zhu .name = "mtd_blk", 205054229abSJason Zhu .id = UCLASS_BLK, 206054229abSJason Zhu .ops = &mtd_blk_ops, 207054229abSJason Zhu .probe = mtd_blk_probe, 208054229abSJason Zhu }; 209