Tien Fong Chee | c1ef736 | 2019-03-05 23:29:38 +0800 | [diff] [blame] | 1 | # Copyright (C) 2018-2019 Intel Corporation <www.intel.com> |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 2 | # |
| 3 | # SPDX-License-Identifier: GPL-2.0 |
| 4 | |
| 5 | Introduction |
| 6 | ============ |
| 7 | |
| 8 | This is file system firmware loader for U-Boot framework, which has very close |
| 9 | to some Linux Firmware API. For the details of Linux Firmware API, you can refer |
| 10 | to https://01.org/linuxgraphics/gfx-docs/drm/driver-api/firmware/index.html. |
| 11 | |
| 12 | File system firmware loader can be used to load whatever(firmware, image, |
| 13 | and binary) from the storage device in file system format into target location |
| 14 | such as memory, then consumer driver such as FPGA driver can program FPGA image |
| 15 | from the target location into FPGA. |
| 16 | |
| 17 | To enable firmware loader, CONFIG_FS_LOADER need to be set at |
| 18 | <board_name>_defconfig such as "CONFIG_FS_LOADER=y". |
| 19 | |
| 20 | Firmware Loader API core features |
| 21 | --------------------------------- |
| 22 | |
| 23 | Firmware storage device described in device tree source |
| 24 | ------------------------------------------------------- |
| 25 | For passing data like storage device phandle and partition where the |
| 26 | firmware loading from to the firmware loader driver, those data could be |
| 27 | defined in fs-loader node as shown in below: |
| 28 | |
| 29 | Example for block device: |
Tien Fong Chee | c1ef736 | 2019-03-05 23:29:38 +0800 | [diff] [blame] | 30 | fs_loader0: fs-loader { |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 31 | u-boot,dm-pre-reloc; |
| 32 | compatible = "u-boot,fs-loader"; |
| 33 | phandlepart = <&mmc 1>; |
| 34 | }; |
| 35 | |
| 36 | <&mmc 1> means block storage device pointer and its partition. |
| 37 | |
| 38 | Above example is a description for block storage, but for UBI storage |
| 39 | device, it can be described in FDT as shown in below: |
| 40 | |
| 41 | Example for ubi: |
Tien Fong Chee | c1ef736 | 2019-03-05 23:29:38 +0800 | [diff] [blame] | 42 | fs_loader1: fs-loader { |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 43 | u-boot,dm-pre-reloc; |
| 44 | compatible = "u-boot,fs-loader"; |
| 45 | mtdpart = "UBI", |
| 46 | ubivol = "ubi0"; |
| 47 | }; |
| 48 | |
Tien Fong Chee | c1ef736 | 2019-03-05 23:29:38 +0800 | [diff] [blame] | 49 | Then, firmware-loader property can be added with any device node, which |
| 50 | driver would use the firmware loader for loading. |
| 51 | |
| 52 | The value of the firmware-loader property should be set with phandle |
| 53 | of the fs-loader node. |
| 54 | For example: |
| 55 | firmware-loader = <&fs_loader0>; |
| 56 | |
| 57 | If there are majority of devices using the same fs-loader node, then |
| 58 | firmware-loader property can be added under /chosen node instead of |
| 59 | adding to each of device node. |
| 60 | |
| 61 | For example: |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 62 | /{ |
| 63 | chosen { |
Tien Fong Chee | c1ef736 | 2019-03-05 23:29:38 +0800 | [diff] [blame] | 64 | firmware-loader = <&fs_loader0>; |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 65 | }; |
| 66 | }; |
| 67 | |
Tien Fong Chee | c1ef736 | 2019-03-05 23:29:38 +0800 | [diff] [blame] | 68 | In each respective driver of devices using firmware loader, the firmware |
| 69 | loaded instance should be created by DT phandle. |
| 70 | |
| 71 | For example of getting DT phandle from /chosen and creating instance: |
| 72 | chosen_node = ofnode_path("/chosen"); |
| 73 | if (!ofnode_valid(chosen_node)) { |
| 74 | debug("/chosen node was not found.\n"); |
| 75 | return -ENOENT; |
| 76 | } |
| 77 | |
| 78 | phandle_p = ofnode_get_property(chosen_node, "firmware-loader", &size); |
| 79 | if (!phandle_p) { |
| 80 | debug("firmware-loader property was not found.\n"); |
| 81 | return -ENOENT; |
| 82 | } |
| 83 | |
| 84 | phandle = fdt32_to_cpu(*phandle_p); |
| 85 | ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER, |
| 86 | phandle, &dev); |
| 87 | if (ret) |
| 88 | return ret; |
| 89 | |
| 90 | Firmware loader driver is also designed to support U-boot environment |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 91 | variables, so all these data from FDT can be overwritten |
| 92 | through the U-boot environment variable during run time. |
| 93 | For examples: |
| 94 | "storage_interface" - Storage interface, it can be "mmc", "usb", "sata" |
| 95 | or "ubi". |
| 96 | "fw_dev_part" - Block device number and its partition, it can be "0:1". |
| 97 | "fw_ubi_mtdpart" - UBI device mtd partition, it can be "UBI". |
| 98 | "fw_ubi_volume" - UBI volume, it can be "ubi0". |
| 99 | |
| 100 | When above environment variables are set, environment values would be |
| 101 | used instead of data from FDT. |
| 102 | The benefit of this design allows user to change storage attribute data |
| 103 | at run time through U-boot console and saving the setting as default |
| 104 | environment values in the storage for the next power cycle, so no |
| 105 | compilation is required for both driver and FDT. |
| 106 | |
| 107 | File system firmware Loader API |
| 108 | ------------------------------- |
| 109 | |
Tien Fong Chee | 31a2cf1 | 2018-12-10 21:29:44 +0800 | [diff] [blame] | 110 | int request_firmware_into_buf(struct udevice *dev, |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 111 | const char *name, |
Tien Fong Chee | 31a2cf1 | 2018-12-10 21:29:44 +0800 | [diff] [blame] | 112 | void *buf, size_t size, u32 offset) |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 113 | -------------------------------------------------------------------- |
| 114 | Load firmware into a previously allocated buffer |
| 115 | |
| 116 | Parameters: |
| 117 | |
Tien Fong Chee | 31a2cf1 | 2018-12-10 21:29:44 +0800 | [diff] [blame] | 118 | 1. struct udevice *dev |
| 119 | An instance of a driver |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 120 | |
| 121 | 2. const char *name |
| 122 | name of firmware file |
| 123 | |
| 124 | 3. void *buf |
| 125 | address of buffer to load firmware into |
| 126 | |
| 127 | 4. size_t size |
| 128 | size of buffer |
| 129 | |
| 130 | 5. u32 offset |
| 131 | offset of a file for start reading into buffer |
| 132 | |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 133 | return: |
| 134 | size of total read |
| 135 | -ve when error |
| 136 | |
| 137 | Description: |
Tien Fong Chee | 31a2cf1 | 2018-12-10 21:29:44 +0800 | [diff] [blame] | 138 | The firmware is loaded directly into the buffer pointed to by buf |
Tien Fong Chee | 4502975 | 2018-07-06 16:27:08 +0800 | [diff] [blame] | 139 | |
Tien Fong Chee | c1ef736 | 2019-03-05 23:29:38 +0800 | [diff] [blame] | 140 | Example of calling request_firmware_into_buf API after creating firmware loader |
| 141 | instance: |
| 142 | ret = uclass_get_device_by_phandle_id(UCLASS_FS_FIRMWARE_LOADER, |
| 143 | phandle, &dev); |
| 144 | if (ret) |
| 145 | return ret; |
| 146 | |
| 147 | request_firmware_into_buf(dev, filename, buffer_location, buffer_size, |
| 148 | offset_ofreading); |