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