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; 38*ec6d4288SJason Zhu if (!mtd) 39*ec6d4288SJason Zhu return NULL; 40*ec6d4288SJason 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); 99054229abSJason Zhu 100054229abSJason Zhu if (!desc) 101054229abSJason Zhu return 0; 102054229abSJason Zhu 103054229abSJason Zhu if (blkcnt == 0) 104054229abSJason Zhu return 0; 105054229abSJason Zhu 106054229abSJason Zhu if (desc->devnum == BLK_MTD_NAND) { 107054229abSJason Zhu int ret = 0; 108054229abSJason Zhu size_t rwsize = blkcnt * 512; 109054229abSJason Zhu struct mtd_info *mtd = dev_get_priv(udev->parent); 110054229abSJason Zhu struct nand_chip *chip = mtd_to_nand(mtd); 111054229abSJason Zhu loff_t off = (loff_t)(start * 512); 112054229abSJason Zhu 113054229abSJason Zhu if (!mtd) { 114054229abSJason Zhu puts("\nno mtd available\n"); 115054229abSJason Zhu return 0; 116054229abSJason Zhu } 117054229abSJason Zhu 118054229abSJason Zhu if (!chip) { 119054229abSJason Zhu puts("\nno chip available\n"); 120054229abSJason Zhu return 0; 121054229abSJason Zhu } 122054229abSJason Zhu 123054229abSJason Zhu ret = nand_read_skip_bad(&chip->mtd, off, &rwsize, 124054229abSJason Zhu NULL, chip->mtd.size, 125054229abSJason Zhu (u_char *)(dst)); 126054229abSJason Zhu if (ret) 127054229abSJason Zhu return 0; 128054229abSJason Zhu else 129054229abSJason Zhu return blkcnt; 130054229abSJason Zhu } else if (desc->devnum == BLK_MTD_SPI_NAND) { 131054229abSJason Zhu /* Not implemented */ 132054229abSJason Zhu return 0; 133054229abSJason Zhu } else if (desc->devnum == BLK_MTD_SPI_NOR) { 134054229abSJason Zhu /* Not implemented */ 135054229abSJason Zhu return 0; 136054229abSJason Zhu } else { 137054229abSJason Zhu return 0; 138054229abSJason Zhu } 139054229abSJason Zhu } 140054229abSJason Zhu 141054229abSJason Zhu ulong mtd_dwrite(struct udevice *udev, lbaint_t start, 142054229abSJason Zhu lbaint_t blkcnt, const void *src) 143054229abSJason Zhu { 144054229abSJason Zhu /* Not implemented */ 145054229abSJason Zhu return 0; 146054229abSJason Zhu } 147054229abSJason Zhu 148054229abSJason Zhu ulong mtd_derase(struct udevice *udev, lbaint_t start, 149054229abSJason Zhu lbaint_t blkcnt) 150054229abSJason Zhu { 151054229abSJason Zhu /* Not implemented */ 152054229abSJason Zhu return 0; 153054229abSJason Zhu } 154054229abSJason Zhu 155054229abSJason Zhu static int mtd_blk_probe(struct udevice *udev) 156054229abSJason Zhu { 157054229abSJason Zhu struct blk_desc *desc = dev_get_uclass_platdata(udev); 158f1892190SJason Zhu struct mtd_info *mtd = dev_get_priv(udev->parent); 159054229abSJason Zhu 160c9289eddSJason Zhu desc->bdev->priv = mtd; 161054229abSJason Zhu sprintf(desc->vendor, "0x%.4x", 0x2207); 162e6482de4SJason Zhu memcpy(desc->product, mtd->name, strlen(mtd->name)); 163054229abSJason Zhu memcpy(desc->revision, "V1.00", sizeof("V1.00")); 164f1892190SJason Zhu if (mtd->type == MTD_NANDFLASH) { 165f1892190SJason Zhu /* Reserve 4 blocks for BBT(Bad Block Table) */ 166f1892190SJason Zhu desc->lba = (mtd->size >> 9) - (mtd->erasesize >> 9) * 4; 167f1892190SJason Zhu } else { 168f1892190SJason Zhu desc->lba = mtd->size >> 9; 169f1892190SJason Zhu } 170054229abSJason Zhu 171054229abSJason Zhu return 0; 172054229abSJason Zhu } 173054229abSJason Zhu 174054229abSJason Zhu static const struct blk_ops mtd_blk_ops = { 175054229abSJason Zhu .read = mtd_dread, 176054229abSJason Zhu #ifndef CONFIG_SPL_BUILD 177054229abSJason Zhu .write = mtd_dwrite, 178054229abSJason Zhu .erase = mtd_derase, 179054229abSJason Zhu #endif 180054229abSJason Zhu }; 181054229abSJason Zhu 182054229abSJason Zhu U_BOOT_DRIVER(mtd_blk) = { 183054229abSJason Zhu .name = "mtd_blk", 184054229abSJason Zhu .id = UCLASS_BLK, 185054229abSJason Zhu .ops = &mtd_blk_ops, 186054229abSJason Zhu .probe = mtd_blk_probe, 187054229abSJason Zhu }; 188