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