linux firmware相关
背景
在bt、wifi、tp-touch、camera、vpu等驱动中会经常遇到firmware, firmware主要是其他外设控制器的运行程序或者配置;
一般有以下2种使用方式:
- 将fw data转化为特定的数组,编码在驱动代码中。会造成kernel镜像size变大, 有可能造成镜像超限, 导致kernel启动失败; 调试升级都不方便, 每次修改fw都需要重新编译内核
- 将fw打包到文件系统中,如vendor,system,lib/firmware等等,需要的时候从用户空间中load到kernel空间中,在驱动中应用比较广泛
以前在汇顶的TP-touch驱动中load配置2种方式都有使用,常用的最后一种,比较灵活;
使用
主要API:
- Synchronous:
request_firmware
- Asynchronous:
request_firmware_nowait
该接口不会导致进程睡眠,cannot be called in atomic contexts
使用流程:request_firmware
-> memcpy
-> release_firmware
request_firmware流程:
request_firmware()
|
| Y
firmware built in kernel image? ------------------- load from kernel image -------
| |
| N |
| Y |
load directly from fs ? ------------------ load directly from "path" - |
| | |
| N | |
| | |
load with file node "/sys/class/firmware/xx.bin/" | |
| | |
| | |
exit exit
Note:
request_firmware在内核使用,需要文件系统支持,就是说,启动的时候如果在驱动里面的probe函数调用 request_firmware ,那么系统将等待30s左右,因为文件系统还没有挂载,当然找不到固件了,所以最好在中断里面启动tasklet,然后request_firmware 。如果不想等待,就用request_firmware_nowait,说明如下:
Asynchronous variant of request_firmware for user contexts: - sleep for as small periods as possible since it may increase kernel boot time of built-in device drivers requesting firmware in their ->probe methods, if gfp is GFP_KERNEL.
从kernel-image中Load
Built-in firmware
config配置:
CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE_DIR="firmware" // this means $(source_dir)/firmware
CONFIG_EXTRA_FIRMWARE="fw_xxx.bin"
为啥会考虑这种?
- speed
- boot device需要该固件
不能使用的情形:
- 许可问题,有些firmware不是GPL许可
- firmware需要方便升级
- firmware的size比较大
- firmware需要动态修改,对于每个设备都不一样, 例如一些WiFi或者TP等的修正参数等
- 等
从文件系统Load
Firmware搜索路径,依次搜索:
- fw_path_para - module parameter(
firmware_class.path=xxx
或者/sys/module/firmware_class/parameters/path
指定) - /lib/firmware/updates/UTS_RELEASE/ - (
UTS_RELEASE
为kernel release version number) - /lib/firmware/updates/
- /lib/firmware/UTS_RELEASE/
- /lib/firmware/
MODULE_FIRMWARE
宏
从userspace中Load
路径:/sys/class/firmware/xxx
hotplug-script
的脚本sample:
#!/bin/sh
# Simple hotplug script sample:
#
# Both $DEVPATH and $FIRMWARE are already provided in the environment.
# $DEVPATH常用:/sys/class/firmware/xxx
HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
if [ "$SUBSYSTEM" == "firmware" -a "$ACTION" == "add" ]; then
if [ -f $HOTPLUG_FW_DIR/$FIRMWARE ]; then
echo 1 > /sys/$DEVPATH/loading
cat $HOTPLUG_FW_DIR/$FIRMWARE > /sys/$DEVPATH/data
echo 0 > /sys/$DEVPATH/loading
else
echo -1 > /sys/$DEVPATH/loading
fi
fi
触发
热插拔uevent事件
udev
linux-firmware包
在Linux的发行版中常用linux-firmware软件包来维护firmware
参考:
- https://blog.csdn.net/weixin_41028621/article/details/103047831
- Documentation/driver-api/firmware/
- Documentation/firmware_class/hotplug-script