首页
/ Linux 内核 R-Car Gen4 PCIe 固件指南:从 R-Car V4H 数据手册提取 rcar_gen4_pcie.bin 并部署到 /lib/firmware

Linux 内核 R-Car Gen4 PCIe 固件指南:从 R-Car V4H 数据手册提取 rcar_gen4_pcie.bin 并部署到 /lib/firmware

2026-09-03 15:35:49作者:晏闻田Solitary

本文围绕 Linux 内核文档 rcar-pcie-firmware.rst 展开,讲解 Renesas R-Car V4H(r8a779g0)SoC 上 PCIe 控制器所需的 PHY 固件如何从厂商数据手册(datasheet)中的文本格式转换回二进制文件 rcar_gen4_pcie.bin、如何校验其 SHA1 值、如何放置到 /lib/firmware 目录,并结合驱动源码 pcie-rcar-gen4.c 深入剖析内核在启动时加载、写入该固件的完整机制。读完本文后,你将能够独立完成该固件的提取、转换、校验与部署,并理解驱动加载失败时内核报出 "Failed to load firmware" 错误的根本原因与排查路径。

一、为什么 R-Car V4H 的 PCIe 需要额外固件

Renesas R-Car V4H(r8a779g0)内置一个 PCIe 控制器(基于 Synopsys DesignWare IP,由 pcie-rcar-gen4 平台驱动支持),它的 PHY 初始化流程必须向硬件写入一段专有固件,否则 PCIe 控制器无法完成链路训练,整个控制器将不可用。驱动源码头部注释明确写道:

/*
 * The r8a779g0 (R-Car V4H) controller requires a specific firmware to be
 * provided, to initialize the PHY. Otherwise, the PCIe controller will not
 * work.
 */

(见 pcie-rcar-gen4.c

而 Renesas 目前无法免费分发这段固件的二进制文件。但厂商数据手册中附带了该固件的内容——只不过以文本形式编码在手册里,因此需要用户自己动手把文本内容还原成二进制。这正是 rcar-pcie-firmware.rst 这份文档存在的意义:它是一份可操作的“固件准备手册”。

二、固件文件从哪里来:数据手册中的文本转储

根据官方文档说明:

  • 固件内容可以从数据手册中找到,对应的文本文件名是 104_PCIe_fw_addr_data_ver1.05.txt(注意:不同版本的数据手册中该文件名可能不同,需要以你所持手册版本为准);
  • 文本文件中的固件是按“地址 + 数据”逐行排列的十六进制转储;
  • 由于是文本编码,其内容必须转换回二进制形式才能被内核使用。

文档给出了使用 awkxxd 的组合命令完成转换的示例脚本:

$ awk '/^\s*0x[0-9A-Fa-f]{4}\s+0x[0-9A-Fa-f]{4}/ { print substr($2,5,2) substr($2,3,2) }' \
	104_PCIe_fw_addr_data_ver1.05.txt | \
		xxd -p -r > rcar_gen4_pcie.bin

这段脚本的逐层含义值得拆开来看,它解释了为什么转换结果能被驱动正确写入硬件:

  1. 正则筛选/^\s*0x[0-9A-Fa-f]{4}\s+0x[0-9A-Fa-f]{4}/ 只匹配“以 0x 开头的 4 位地址 + 以 0x 开头的 4 位数据”的行,滤掉手册中的标题、说明文字等无关行;
  2. 字节序翻转:数据字段 $2 形如 0x1234substr($2,3,2) 取出高字节 12substr($2,5,2) 取出低字节 34,脚本先输出低字节再输出高字节,即完成大端文本 → 小端字节流的转换。这与驱动侧的读法是严格对应的——驱动按 16 位小端字解析固件数据:
data = fw->data[(i * 2) + 1] << 8 | fw->data[i * 2];

(见 pcie-rcar-gen4.c);

  1. hex 转 binaryxxd -p -r 把成对的十六进制字符还原为原始二进制字节,重定向生成最终文件 rcar_gen4_pcie.bin

三、校验转换结果:SHA1 指纹

转换完成后,必须校验文件内容是否与数据手册中描述的固件一致,防止手册版本、复制粘贴或转换脚本问题引入错误。文档要求使用 sha1sum 校验:

$ sha1sum rcar_gen4_pcie.bin
1d0bd4b189b4eb009f5d564b1f93a79112994945  rcar_gen4_pcie.bin

官方文档给出的期望指纹为 1d0bd4b189b4eb009f5d564b1f93a79112994945(对应 104_PCIe_fw_addr_data_ver1.05 版本)。如果你的输出与之一致,说明文本转二进制过程无误;若不一致,应优先检查:所用数据手册版本、文件名是否为文档所述版本、awk 脚本是否完整复制。

四、部署固件:放置到 /lib/firmware

转换并校验通过之后,官方文档给出的部署要求只有一条,但非常明确:

生成的二进制文件 rcar_gen4_pcie.bin 必须在驱动运行之前放置到 /lib/firmware 目录中。

也就是说,部署动作是:

sudo install -m 0644 rcar_gen4_pcie.bin /lib/firmware/

install 命令仅用于展示放置方式,权限可按发行版规范调整。)

之所以必须放在 /lib/firmware 且要在“驱动运行前”就位,是因为驱动通过内核固件框架请求该文件:

  • 驱动中定义了固件名常量并注册了固件依赖:
#define RCAR_GEN4_PCIE_FIRMWARE_NAME		"rcar_gen4_pcie.bin"
#define RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR	0xc000
MODULE_FIRMWARE(RCAR_GEN4_PCIE_FIRMWARE_NAME);

(见 pcie-rcar-gen4.c

  • MODULE_FIRMWARE() 宏会生成 FW_ 前缀的模块依赖段,使 depmod/initramfs 构建工具(dracut 等)能够把 rcar_gen4_pcie.bin 一并打入启动镜像——这对把该 SoC 作为系统盘或网卡所在总线的场景尤为关键;
  • 运行期则通过 request_firmware() 触发用户态 fw_agent(或 udev 触发的 systemd-firmware-loader)从 /lib/firmware 按名称查找文件。查找失败时驱动打印明确的错误信息:
dev_err(dw->dev, "Failed to load firmware (%s): %d\n",
	RCAR_GEN4_PCIE_FIRMWARE_NAME, ret);

即 dmesg 中若出现 Failed to load firmware (rcar_gen4_pcie.bin): ...(错误码常见为 -2 文件不存在、-110 加载超时),第一排查点就是 /lib/firmware/rcar_gen4_pcie.bin 是否就位、SHA1 是否正确。

五、源码深潜:内核如何把固件写入 PHY

rcar_gen4_pcie_download_phy_firmware()pcie-rcar-gen4.c)实现了固件的实际下载过程,理解它对判断“固件加载卡在哪一步”很有帮助。整体调用链为:

rcar_gen4_pcie_ltssm_control(enable=true)
  ├─ 配置 PORT_FORCE / SRIS 模式(PCIEMSR0.APP_SRIS_MODE)
  ├─ 按数据手册初始化 PHY 寄存器(phy_base 下 0x700/0x148/0x1d4/0x514/0x0f8 等偏移)
  ├─ 释放 APP_HOLD_PHY_RST
  ├─ 轮询 PHY 寄存器 0x0f8 的 BIT(18),等待 PHY 就绪
  ├─ rcar_gen4_pcie_download_phy_firmware()   ← 固件下载
  └─ 置位 PCIERSTCTRL1.APP_LTSSM_ENABLE,启动链路状态机

(见 pcie-rcar-gen4.c

固件写入阶段的核心步骤:

  1. request_firmware() 加载 rcar_gen4_pcie.bin,失败则直接返回错误并打印上文提到的 Failed to load firmware 日志;
  2. 按 16 位小端字循环写入。固件被切成 fw->size / 2 个字(word),每字的地址写入 Port Logic 寄存器 PRTLGC89(偏移 0x0b70),数据写入 PRTLGC90(偏移 0x0b74),起始地址由宏 RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR0xc000)加上字偏移 i 组成:
dw_pcie_writel_dbi(dw, PRTLGC89, RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR + i);
dw_pcie_writel_dbi(dw, PRTLGC90, data);
  1. 等待写完成:每写完一个字,驱动轮询 PRTLGC89BIT(30),非零表示硬件仍在处理该次写入,驱动以 usleep_range(100, 200) 休眠重试,最多 100 次,超时返回 -ETIMEDOUTrcar_gen4_pcie_reg_test_bit() 的注释说明该行为来自数据手册的建议(“SoC datasheet suggests checking port logic register bits during firmware write”);
  2. 收尾与校验地址序列。写入全部完成后,先置位 PHY 寄存器 0x0f8BIT(17),随后对数据手册给出的四个“魔数”校验地址依次执行同样的写-轮询流程:
static const u32 check_addr[] = {
	0x00101018,
	0x00101118,
	0x00101021,
	0x00101121,
};

每次写入 check_addr[i] 后轮询 PRTLGC89BIT(30)PRTLGC90BIT(0),全部清零即成功。源码注释直言:“The check_addr values are magical numbers in the datasheet”——这些地址在数据手册中未命名,驱动只能照搬数值,这也是该驱动对文档依赖较深的一处体现; 5. release_firmware() 释放固件 buffer,函数返回 0 表示下载成功。

六、适用范围:哪些 SoC 需要这个固件?

固件下载逻辑挂在 ltssm_control 回调上,而该回调由设备树的 compatible 决定。驱动的匹配表(pcie-rcar-gen4.c)为:

compatible SoC 是否下载固件
renesas,r8a779f0-pcie / renesas,r8a779f0-pcie-ep R-Car S4-8 (r8a779f0) 否(走专用的 r8a779f0_pcie_ltssm_controlL664-L684
renesas,rcar-gen4-pcie / renesas,rcar-gen4-pcie-ep R-Car Gen4 通用(含 V4H r8a779g0) (走 rcar_gen4_pcie_ltssm_control,内部调用固件下载)

从源码结构看:V4H(r8a779g0)的设备树中,SoC 专用的 renesas,r8a779g0-pcie 不在 of_match_table 中,最终落到通用的 renesas,rcar-gen4-pcie 条目上,因此必须准备固件;而 S4-8 因有专属匹配项,使用简化的 LTSSM 控制路径,不需要固件。这也与官方文档聚焦 V4H 的表述一致。

设备树约束可参考绑定文件 rcar-gen4-pci-host.yaml:它列出的 compatible 包括 renesas,r8a779f0-pcie(S4-8)、renesas,r8a779g0-pcie(V4H)、renesas,r8a779h0-pcie(V4M),且必须搭配 renesas,rcar-gen4-pciereg-names 需要包含驱动实际映射的 appphy 两个区域(pcie-rcar-gen4.c 中分别以 devm_platform_ioremap_resource_byname(..., "phy")(..., "app") 获取)。EP(端点)模式另有绑定 rcar-gen4-pci-ep.yaml

七、实战检查清单

把上述内容压缩成一条可执行的排查/准备清单:

  1. 拿到正确版本的数据手册,确认其中固件文本文件名(104_PCIe_fw_addr_data_ver1.05.txt 为文档基准,实际文件名可能随手册版本变化);
  2. 按第二节的 awk + xxd -p -r 命令提取并转换,注意该命令隐含了“数据字段高低字节交换”的小端化过程;
  3. sha1sum rcar_gen4_pcie.bin 必须等于 1d0bd4b189b4eb009f5d564b1f93a79112994945
  4. 将文件安装到 /lib/firmware/rcar_gen4_pcie.bin,权限建议 0644;若内核以 initramfs 启动且 PCIe 设备位于根设备之前,建议将固件加入 initramfs(MODULE_FIRMWARE 依赖会让 dracut 等工具自动收录,但需确认所用 initramfs 已重建);
  5. 启动后检查 dmesg:出现 Failed to load firmware (rcar_gen4_pcie.bin) 说明第 4 步未生效;若没有该报错但链路始终 down,则问题更可能出在固件加载之后的 PHY 寄存器初始化/校验地址轮询环节(返回 -ETIMEDOUT),此时应核对设备树 phy/app 寄存器区域、参考时钟(clock-names = "core", "ref")是否按 rcar-gen4-pci-host.yaml 的示例完整配置。

小结

对于 R-Car V4H 平台上的 Linux 系统,PCIe 控制器能否工作取决于一个并不在开源仓库中、需要用户从厂商数据手册自行提取的固件。本文以 rcar-pcie-firmware.rst 为主线,完整复现了“文本 → 二进制 → 校验 → 部署”的标准流程,并结合 pcie-rcar-gen4.c 展示了内核如何通过 request_firmware 获取 rcar_gen4_pcie.bin、按小端 16 位字经 PRTLGC89/PRTLGC90 写入 0xc000 起始的固件区、以及数据手册“魔数”校验地址序列的轮询细节。掌握这些内容后,无论是首次部署还是排障,都能沿着“文件是否在 /lib/firmware → SHA1 是否匹配 → dmesg 报错停在哪个阶段”这条路径快速定位问题。

登录后查看全文
热门项目推荐
相关项目推荐