xref: /rk3399_rockchip-uboot/drivers/mtd/mtd_blk.c (revision 8cf6fca4b89eca507b30e4950bce1b2ee4930c2c)
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