1 // SPDX-License-Identifier: GPL-2.0
2  /*
3  * Copyright (C) 2018-2019 Intel Corporation <www.intel.com>
4  *
5  */
6 #include <common.h>
7 #include <dm.h>
8 #include <env.h>
9 #include <errno.h>
10 #include <blk.h>
11 #include <fs.h>
12 #include <fs_loader.h>
13 #include <log.h>
14 #include <asm/global_data.h>
15 #include <linux/string.h>
16 #include <mapmem.h>
17 #include <malloc.h>
18 #include <spl.h>
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 /**
23  * struct firmware - A place for storing firmware and its attribute data.
24  *
25  * This holds information about a firmware and its content.
26  *
27  * @size: Size of a file
28  * @data: Buffer for file
29  * @priv: Firmware loader private fields
30  * @name: Filename
31  * @offset: Offset of reading a file
32  */
33 struct firmware {
34 	size_t size;
35 	const u8 *data;
36 	const char *name;
37 	u32 offset;
38 };
39 
40 #ifdef CONFIG_CMD_UBIFS
mount_ubifs(char * mtdpart,char * ubivol)41 static int mount_ubifs(char *mtdpart, char *ubivol)
42 {
43 	int ret = ubi_part(mtdpart, NULL);
44 
45 	if (ret) {
46 		debug("Cannot find mtd partition %s\n", mtdpart);
47 		return ret;
48 	}
49 
50 	return cmd_ubifs_mount(ubivol);
51 }
52 
umount_ubifs(void)53 static int umount_ubifs(void)
54 {
55 	return cmd_ubifs_umount();
56 }
57 #else
mount_ubifs(char * mtdpart,char * ubivol)58 static int mount_ubifs(char *mtdpart, char *ubivol)
59 {
60 	debug("Error: Cannot load image: no UBIFS support\n");
61 	return -ENOSYS;
62 }
63 #endif
64 
select_fs_dev(struct device_plat * plat)65 static int select_fs_dev(struct device_plat *plat)
66 {
67 	int ret;
68 
69 	if (plat->phandlepart.phandle) {
70 		ofnode node;
71 
72 		node = ofnode_get_by_phandle(plat->phandlepart.phandle);
73 
74 		struct udevice *dev;
75 
76 		ret = device_get_global_by_ofnode(node, &dev);
77 		if (!ret) {
78 			struct blk_desc *desc = blk_get_by_device(dev);
79 			if (desc) {
80 				ret = fs_set_blk_dev_with_part(desc,
81 					plat->phandlepart.partition);
82 			} else {
83 				debug("%s: No device found\n", __func__);
84 				return -ENODEV;
85 			}
86 		}
87 	} else if (plat->mtdpart && plat->ubivol) {
88 		ret = mount_ubifs(plat->mtdpart, plat->ubivol);
89 		if (ret)
90 			return ret;
91 
92 		ret = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
93 	} else {
94 		debug("Error: unsupported storage device.\n");
95 		return -ENODEV;
96 	}
97 
98 	if (ret)
99 		debug("Error: could not access storage.\n");
100 
101 	return ret;
102 }
103 
104 /**
105  * _request_firmware_prepare - Prepare firmware struct.
106  *
107  * @dev: An instance of a driver.
108  * @name: Name of firmware file.
109  * @dbuf: Address of buffer to load firmware into.
110  * @size: Size of buffer.
111  * @offset: Offset of a file for start reading into buffer.
112  *
113  * Return: Negative value if fail, 0 for successful.
114  */
_request_firmware_prepare(struct udevice * dev,const char * name,void * dbuf,size_t size,u32 offset)115 static int _request_firmware_prepare(struct udevice *dev,
116 				    const char *name, void *dbuf,
117 				    size_t size, u32 offset)
118 {
119 	if (!name || name[0] == '\0')
120 		return -EINVAL;
121 
122 	struct firmware *firmwarep = dev_get_priv(dev);
123 
124 	if (!firmwarep)
125 		return -ENOMEM;
126 
127 	firmwarep->name = name;
128 	firmwarep->offset = offset;
129 	firmwarep->data = dbuf;
130 	firmwarep->size = size;
131 
132 	return 0;
133 }
134 
135 /**
136  * fw_get_filesystem_firmware - load firmware into an allocated buffer.
137  * @dev: An instance of a driver.
138  *
139  * Return: Size of total read, negative value when error.
140  */
fw_get_filesystem_firmware(struct udevice * dev)141 static int fw_get_filesystem_firmware(struct udevice *dev)
142 {
143 	loff_t actread;
144 	char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume;
145 	int ret;
146 
147 	storage_interface = env_get("storage_interface");
148 	dev_part = env_get("fw_dev_part");
149 	ubi_mtdpart = env_get("fw_ubi_mtdpart");
150 	ubi_volume = env_get("fw_ubi_volume");
151 
152 	if (storage_interface && dev_part) {
153 		ret = fs_set_blk_dev(storage_interface, dev_part, FS_TYPE_ANY);
154 	} else if (storage_interface && ubi_mtdpart && ubi_volume) {
155 		ret = mount_ubifs(ubi_mtdpart, ubi_volume);
156 		if (ret)
157 			return ret;
158 
159 		if (!strcmp("ubi", storage_interface))
160 			ret = fs_set_blk_dev(storage_interface, NULL,
161 				FS_TYPE_UBIFS);
162 		else
163 			ret = -ENODEV;
164 	} else {
165 		ret = select_fs_dev(dev_get_plat(dev));
166 	}
167 
168 	if (ret)
169 		goto out;
170 
171 	struct firmware *firmwarep = dev_get_priv(dev);
172 
173 	if (!firmwarep)
174 		return -ENOMEM;
175 
176 	ret = fs_read(firmwarep->name, (ulong)map_to_sysmem(firmwarep->data),
177 			firmwarep->offset, firmwarep->size, &actread);
178 
179 	if (ret) {
180 		debug("Error: %d Failed to read %s from flash %lld != %zu.\n",
181 		      ret, firmwarep->name, actread, firmwarep->size);
182 	} else {
183 		ret = actread;
184 	}
185 
186 out:
187 #ifdef CONFIG_CMD_UBIFS
188 	umount_ubifs();
189 #endif
190 	return ret;
191 }
192 
193 /**
194  * request_firmware_into_buf - Load firmware into a previously allocated buffer.
195  * @dev: An instance of a driver.
196  * @name: Name of firmware file.
197  * @buf: Address of buffer to load firmware into.
198  * @size: Size of buffer.
199  * @offset: Offset of a file for start reading into buffer.
200  *
201  * The firmware is loaded directly into the buffer pointed to by @buf.
202  *
203  * Return: Size of total read, negative value when error.
204  */
request_firmware_into_buf(struct udevice * dev,const char * name,void * buf,size_t size,u32 offset)205 int request_firmware_into_buf(struct udevice *dev,
206 			      const char *name,
207 			      void *buf, size_t size, u32 offset)
208 {
209 	int ret;
210 
211 	if (!dev)
212 		return -EINVAL;
213 
214 	ret = _request_firmware_prepare(dev, name, buf, size, offset);
215 	if (ret < 0) /* error */
216 		return ret;
217 
218 	ret = fw_get_filesystem_firmware(dev);
219 
220 	return ret;
221 }
222 
fs_loader_of_to_plat(struct udevice * dev)223 static int fs_loader_of_to_plat(struct udevice *dev)
224 {
225 	u32 phandlepart[2];
226 
227 	ofnode fs_loader_node = dev_ofnode(dev);
228 
229 	if (ofnode_valid(fs_loader_node)) {
230 		struct device_plat *plat;
231 
232 		plat = dev_get_plat(dev);
233 		if (!ofnode_read_u32_array(fs_loader_node,
234 					  "phandlepart",
235 					  phandlepart, 2)) {
236 			plat->phandlepart.phandle = phandlepart[0];
237 			plat->phandlepart.partition = phandlepart[1];
238 		}
239 
240 		plat->mtdpart = (char *)ofnode_read_string(
241 				 fs_loader_node, "mtdpart");
242 
243 		plat->ubivol = (char *)ofnode_read_string(
244 				 fs_loader_node, "ubivol");
245 	}
246 
247 	return 0;
248 }
249 
fs_loader_probe(struct udevice * dev)250 static int fs_loader_probe(struct udevice *dev)
251 {
252 #if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(BLK)
253 	int ret;
254 	struct device_plat *plat = dev_get_plat(dev);
255 
256 	if (plat->phandlepart.phandle) {
257 		ofnode node = ofnode_get_by_phandle(plat->phandlepart.phandle);
258 		struct udevice *parent_dev = NULL;
259 
260 		ret = device_get_global_by_ofnode(node, &parent_dev);
261 		if (!ret) {
262 			struct udevice *dev;
263 
264 			ret = blk_get_from_parent(parent_dev, &dev);
265 			if (ret) {
266 				debug("fs_loader: No block device: %d\n",
267 					ret);
268 
269 				return ret;
270 			}
271 		}
272 	}
273 #endif
274 
275 	return 0;
276 };
277 
278 static const struct udevice_id fs_loader_ids[] = {
279 	{ .compatible = "u-boot,fs-loader"},
280 	{ }
281 };
282 
283 U_BOOT_DRIVER(fs_loader) = {
284 	.name			= "fs-loader",
285 	.id			= UCLASS_FS_FIRMWARE_LOADER,
286 	.of_match		= fs_loader_ids,
287 	.probe			= fs_loader_probe,
288 	.of_to_plat	= fs_loader_of_to_plat,
289 	.plat_auto	= sizeof(struct device_plat),
290 	.priv_auto	= sizeof(struct firmware),
291 };
292 
293 UCLASS_DRIVER(fs_loader) = {
294 	.id		= UCLASS_FS_FIRMWARE_LOADER,
295 	.name		= "fs-loader",
296 };
297