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); 996e8ac5a8SJason Zhu loff_t off = (loff_t)(start * 512); 1006e8ac5a8SJason Zhu size_t rwsize = blkcnt * 512; 1016e8ac5a8SJason Zhu struct mtd_info *mtd; 102054229abSJason Zhu 103054229abSJason Zhu if (!desc) 104054229abSJason Zhu return 0; 105054229abSJason Zhu 1066e8ac5a8SJason Zhu mtd = desc->bdev->priv; 1076e8ac5a8SJason Zhu if (!mtd) 1086e8ac5a8SJason Zhu return 0; 1096e8ac5a8SJason Zhu 110054229abSJason Zhu if (blkcnt == 0) 111054229abSJason Zhu return 0; 112054229abSJason Zhu 113054229abSJason Zhu if (desc->devnum == BLK_MTD_NAND) { 1146e8ac5a8SJason Zhu #ifdef CONFIG_NAND 115054229abSJason Zhu int ret = 0; 116054229abSJason Zhu 117*8cf6fca4SJason Zhu mtd = dev_get_priv(udev->parent); 118*8cf6fca4SJason Zhu if (!mtd) 119*8cf6fca4SJason Zhu return 0; 120*8cf6fca4SJason Zhu 1216e8ac5a8SJason Zhu ret = nand_read_skip_bad(mtd, off, &rwsize, 1226e8ac5a8SJason Zhu NULL, mtd->size, 123054229abSJason Zhu (u_char *)(dst)); 1246e8ac5a8SJason Zhu if (!ret) 125054229abSJason Zhu return blkcnt; 1266e8ac5a8SJason Zhu else 1276e8ac5a8SJason Zhu #endif 1286e8ac5a8SJason Zhu return 0; 129054229abSJason Zhu } else if (desc->devnum == BLK_MTD_SPI_NAND) { 1306e8ac5a8SJason Zhu #ifdef CONFIG_MTD_SPI_NAND 1316e8ac5a8SJason Zhu size_t retlen; 1326e8ac5a8SJason Zhu 1336e8ac5a8SJason Zhu mtd_read(mtd, off, rwsize, &retlen, dst); 1346e8ac5a8SJason Zhu if (retlen == rwsize) 1356e8ac5a8SJason Zhu return blkcnt; 1366e8ac5a8SJason Zhu else 1376e8ac5a8SJason Zhu #endif 138054229abSJason Zhu return 0; 139054229abSJason Zhu } else if (desc->devnum == BLK_MTD_SPI_NOR) { 140054229abSJason Zhu /* Not implemented */ 141054229abSJason Zhu return 0; 142054229abSJason Zhu } else { 143054229abSJason Zhu return 0; 144054229abSJason Zhu } 145054229abSJason Zhu } 146054229abSJason Zhu 147054229abSJason Zhu ulong mtd_dwrite(struct udevice *udev, lbaint_t start, 148054229abSJason Zhu lbaint_t blkcnt, const void *src) 149054229abSJason Zhu { 150054229abSJason Zhu /* Not implemented */ 151054229abSJason Zhu return 0; 152054229abSJason Zhu } 153054229abSJason Zhu 154054229abSJason Zhu ulong mtd_derase(struct udevice *udev, lbaint_t start, 155054229abSJason Zhu lbaint_t blkcnt) 156054229abSJason Zhu { 157054229abSJason Zhu /* Not implemented */ 158054229abSJason Zhu return 0; 159054229abSJason Zhu } 160054229abSJason Zhu 161054229abSJason Zhu static int mtd_blk_probe(struct udevice *udev) 162054229abSJason Zhu { 1636e8ac5a8SJason Zhu struct mtd_info *mtd = dev_get_uclass_priv(udev->parent); 164054229abSJason Zhu struct blk_desc *desc = dev_get_uclass_platdata(udev); 165054229abSJason Zhu 166c9289eddSJason Zhu desc->bdev->priv = mtd; 167054229abSJason Zhu sprintf(desc->vendor, "0x%.4x", 0x2207); 168e6482de4SJason Zhu memcpy(desc->product, mtd->name, strlen(mtd->name)); 169054229abSJason Zhu memcpy(desc->revision, "V1.00", sizeof("V1.00")); 170f1892190SJason Zhu if (mtd->type == MTD_NANDFLASH) { 171f1892190SJason Zhu /* Reserve 4 blocks for BBT(Bad Block Table) */ 172f1892190SJason Zhu desc->lba = (mtd->size >> 9) - (mtd->erasesize >> 9) * 4; 173f1892190SJason Zhu } else { 174f1892190SJason Zhu desc->lba = mtd->size >> 9; 175f1892190SJason Zhu } 176054229abSJason Zhu 177054229abSJason Zhu return 0; 178054229abSJason Zhu } 179054229abSJason Zhu 180054229abSJason Zhu static const struct blk_ops mtd_blk_ops = { 181054229abSJason Zhu .read = mtd_dread, 182054229abSJason Zhu #ifndef CONFIG_SPL_BUILD 183054229abSJason Zhu .write = mtd_dwrite, 184054229abSJason Zhu .erase = mtd_derase, 185054229abSJason Zhu #endif 186054229abSJason Zhu }; 187054229abSJason Zhu 188054229abSJason Zhu U_BOOT_DRIVER(mtd_blk) = { 189054229abSJason Zhu .name = "mtd_blk", 190054229abSJason Zhu .id = UCLASS_BLK, 191054229abSJason Zhu .ops = &mtd_blk_ops, 192054229abSJason Zhu .probe = mtd_blk_probe, 193054229abSJason Zhu }; 194