xref: /rk3399_rockchip-uboot/drivers/mtd/mtd_blk.c (revision 5e8564cf419797f9095431e6eb6f0c00dfa423d2)
1 /*
2  * (C) Copyright 2019 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <blk.h>
9 #include <boot_rkimg.h>
10 #include <dm.h>
11 #include <errno.h>
12 #include <malloc.h>
13 #include <nand.h>
14 #include <part.h>
15 #include <dm/device-internal.h>
16 
17 #define MTD_PART_NAND_HEAD		"mtdparts="
18 #define MTD_PART_INFO_MAX_SIZE		512
19 #define MTD_SINGLE_PART_INFO_MAX_SIZE	40
20 
21 char *mtd_part_parse(void)
22 {
23 	char mtd_part_info_temp[MTD_SINGLE_PART_INFO_MAX_SIZE] = {0};
24 	u32 length, data_len = MTD_PART_INFO_MAX_SIZE;
25 	struct blk_desc *dev_desc;
26 	disk_partition_t info;
27 	char *mtd_part_info_p;
28 	struct mtd_info *mtd;
29 	char *mtd_part_info;
30 	int ret;
31 	int p;
32 
33 	dev_desc = rockchip_get_bootdev();
34 	if (!dev_desc)
35 		return NULL;
36 
37 	mtd = (struct mtd_info *)dev_desc->bdev->priv;
38 	mtd_part_info = (char *)calloc(MTD_PART_INFO_MAX_SIZE, sizeof(char));
39 	if (!mtd_part_info) {
40 		printf("%s: Fail to malloc!", __func__);
41 		return NULL;
42 	}
43 
44 	mtd_part_info_p = mtd_part_info;
45 	snprintf(mtd_part_info_p, data_len - 1, "%s%s:",
46 		 MTD_PART_NAND_HEAD,
47 		 dev_desc->product);
48 	data_len -= strlen(mtd_part_info_p);
49 	mtd_part_info_p = mtd_part_info_p + strlen(mtd_part_info_p);
50 
51 	for (p = 1; p < MAX_SEARCH_PARTITIONS; p++) {
52 		ret = part_get_info(dev_desc, p, &info);
53 		if (ret)
54 			break;
55 
56 		debug("name is %s, start addr is %x\n", info.name,
57 		      (int)(size_t)info.start);
58 
59 		snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)",
60 			 (int)(size_t)info.size << 9,
61 			 (int)(size_t)info.start << 9,
62 			 info.name);
63 		snprintf(mtd_part_info_temp, MTD_SINGLE_PART_INFO_MAX_SIZE - 1,
64 			 "0x%x@0x%x(%s)",
65 			 (int)(size_t)info.size << 9,
66 			 (int)(size_t)info.start << 9,
67 			 info.name);
68 		strcat(mtd_part_info, ",");
69 		if (part_get_info(dev_desc, p + 1, &info)) {
70 			/* Nand flash is erased by block and gpt table just
71 			 * resserve 33 sectors for the last partition. This
72 			 * will erase the backup gpt table by user program,
73 			 * so reserve one block.
74 			 */
75 			snprintf(mtd_part_info_p, data_len - 1, "0x%x@0x%x(%s)",
76 				 (int)(size_t)(info.size -
77 				 (info.size - 1) %
78 				 (mtd->erasesize >> 9) - 1) << 9,
79 				 (int)(size_t)info.start << 9,
80 				 info.name);
81 			break;
82 		}
83 		length = strlen(mtd_part_info_temp);
84 		data_len -= length;
85 		mtd_part_info_p = mtd_part_info_p + length + 1;
86 		memset(mtd_part_info_temp, 0, MTD_SINGLE_PART_INFO_MAX_SIZE);
87 	}
88 
89 	return mtd_part_info;
90 }
91 
92 ulong mtd_dread(struct udevice *udev, lbaint_t start,
93 		lbaint_t blkcnt, void *dst)
94 {
95 	struct blk_desc *desc = dev_get_uclass_platdata(udev);
96 
97 	if (!desc)
98 		return 0;
99 
100 	if (blkcnt == 0)
101 		return 0;
102 
103 	if (desc->devnum == BLK_MTD_NAND) {
104 		int ret = 0;
105 		size_t rwsize = blkcnt * 512;
106 		struct mtd_info *mtd = dev_get_priv(udev->parent);
107 		struct nand_chip *chip = mtd_to_nand(mtd);
108 		loff_t off = (loff_t)(start * 512);
109 
110 		if (!mtd) {
111 			puts("\nno mtd available\n");
112 			return 0;
113 		}
114 
115 		if (!chip) {
116 			puts("\nno chip available\n");
117 			return 0;
118 		}
119 
120 		ret = nand_read_skip_bad(&chip->mtd, off, &rwsize,
121 					 NULL, chip->mtd.size,
122 					 (u_char *)(dst));
123 		if (ret)
124 			return 0;
125 		else
126 			return blkcnt;
127 	} else if (desc->devnum == BLK_MTD_SPI_NAND) {
128 		/* Not implemented */
129 		return 0;
130 	} else if (desc->devnum == BLK_MTD_SPI_NOR) {
131 		/* Not implemented */
132 		return 0;
133 	} else {
134 		return 0;
135 	}
136 }
137 
138 ulong mtd_dwrite(struct udevice *udev, lbaint_t start,
139 		 lbaint_t blkcnt, const void *src)
140 {
141 	/* Not implemented */
142 	return 0;
143 }
144 
145 ulong mtd_derase(struct udevice *udev, lbaint_t start,
146 		 lbaint_t blkcnt)
147 {
148 	/* Not implemented */
149 	return 0;
150 }
151 
152 static int mtd_blk_probe(struct udevice *udev)
153 {
154 	struct blk_desc *desc = dev_get_uclass_platdata(udev);
155 	struct mtd_info *mtd = dev_get_priv(udev->parent);
156 
157 	desc->bdev->priv = mtd;
158 	sprintf(desc->vendor, "0x%.4x", 0x2207);
159 	memcpy(desc->product, mtd->name, strlen(mtd->name));
160 	memcpy(desc->revision, "V1.00", sizeof("V1.00"));
161 	if (mtd->type == MTD_NANDFLASH) {
162 		/* Reserve 4 blocks for BBT(Bad Block Table) */
163 		desc->lba = (mtd->size >> 9) - (mtd->erasesize >> 9) * 4;
164 	} else {
165 		desc->lba = mtd->size >> 9;
166 	}
167 
168 	return 0;
169 }
170 
171 static const struct blk_ops mtd_blk_ops = {
172 	.read	= mtd_dread,
173 #ifndef CONFIG_SPL_BUILD
174 	.write	= mtd_dwrite,
175 	.erase	= mtd_derase,
176 #endif
177 };
178 
179 U_BOOT_DRIVER(mtd_blk) = {
180 	.name		= "mtd_blk",
181 	.id		= UCLASS_BLK,
182 	.ops		= &mtd_blk_ops,
183 	.probe		= mtd_blk_probe,
184 };
185