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