18.PCIe总线入门理解与Linux上PCIe设备配置与使用

发布于:2025-03-28 ⋅ 阅读:(30) ⋅ 点赞:(0)

一、ARM和x86上PCIe接口

参考传送门:

mini PCIe
https://blog.csdn.net/huxyc/article/details/124854928

PCI、PCIe、Mini PCIe、SATA、mSATA、M.2
https://blog.csdn.net/lyndon_li/article/details/120662832?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-120662832-blog-128689170.235

PCie接口的设备很多很常见,例如显卡(GPU)、网卡、声卡和NVMe固态硬盘(SSD)等,但说的是在x86上。ARM相比x86的一个优势就是体积小,在一块板子上完成很多功能,而不是留下很多接口来保证可扩展性,所以很多ARM开发者可能对PCIe设备都没有概念或概念混成一团(没错就是我)。

认识一个事物,最简单的方法是从实物出发,下面是一个x86上使用的PCIe的显卡,和一个PCIe转SATA3.0的转接卡

在这里插入图片描述

在这里插入图片描述

其在x86上的插槽大致模样如下:

在这里插入图片描述

“miniPCIe”,则是基于PCIe总线的一种较小型的接口,专门用于笔记本电脑、平板电脑、嵌入式系统和其他便携式电子设备。它继承了PCIe的高速串行通信特点,但体积更小下面是祥硕ASM1061芯片,支持mini PCIe转双SATA3接口,以及主板上的mini PCIe的插槽。

在这里插入图片描述
在这里插入图片描述

二、miniPCIe引脚定义

PCIe总线使用了高速差分异步总线,并采用端到端的连接方式,因此在每一条PCIe链路中只能连接两个设备。

在这里插入图片描述

如上图所示每一个PCIe链路(Link)只能连接两个设备,PCIe的link宽度支持的Lane数为x1, x2, x4, x8, x12, x16, x32。PCIe的一条lane由两个信号线(Signal TX和Signal Rx)组成,每个Signal由两根线Wire组成。

以ASM1061为例,The ASM1061, X1 PCI Express Gen2 to two-ports Serial ATA Controller,结合PCIe总线的性质,不难猜出其芯片的接口大致分为,PCIe的供电引脚,PCIe的差分时钟线,x1Lane的四条线,两个SATA的数据、时钟、供电复位线。

在这里插入图片描述

在firefly-RK3399原理图上(J29)PCIE M2.NGFF B-KEY 接口
在这里插入图片描述

三、设备树节点

	pcie0: pcie@f8000000 {
		compatible = "rockchip,rk3399-pcie";
		#address-cells = <3>;
		#size-cells = <2>;
		aspm-no-l0s;
		clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>,
			 <&cru PCLK_PCIE>, <&cru SCLK_PCIE_PM>;
		clock-names = "aclk", "aclk-perf",
			      "hclk", "pm";
		bus-range = <0x0 0x1f>;
		max-link-speed = <1>;
		linux,pci-domain = <0>;
		msi-map = <0x0 &its 0x0 0x1000>;
		interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH 0>,
			     <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH 0>,
			     <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH 0>;
		interrupt-names = "sys", "legacy", "client";
		#interrupt-cells = <1>;
		interrupt-map-mask = <0 0 0 7>;
		interrupt-map = <0 0 0 1 &pcie0_intc 0>,
				<0 0 0 2 &pcie0_intc 1>,
				<0 0 0 3 &pcie0_intc 2>,
				<0 0 0 4 &pcie0_intc 3>;
		power-domains = <&power RK3399_PD_PERIHP>;
		phys = <&pcie_phy>;
		phy-names = "pcie-phy";
		ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x1e00000
			  0x81000000 0x0 0xfbe00000 0x0 0xfbe00000 0x0 0x100000>;
		reg = <0x0 0xf8000000 0x0 0x2000000>,
		      <0x0 0xfd000000 0x0 0x1000000>;
		reg-names = "axi-base", "apb-base";
		resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
			 <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>,
			 <&cru SRST_PCIE_PM>, <&cru SRST_P_PCIE>,
			 <&cru SRST_A_PCIE>;
		reset-names = "core", "mgmt", "mgmt-sticky", "pipe",
			      "pm", "pclk", "aclk";
		status = "disabled";
		pcie0_intc: interrupt-controller {
			interrupt-controller;
			#address-cells = <0>;
			#interrupt-cells = <1>;
		};
	};

pcie_phy: pcie-phy {
		compatible = "rockchip,rk3399-pcie-phy";
		#phy-cells = <0>;
		rockchip,grf = <&grf>;
		clocks = <&cru SCLK_PCIEPHY_REF>;
		clock-names = "refclk";
		resets = <&cru SRST_PCIEPHY>;
		reset-names = "phy";
		status = "disabled";
	};
	
&pcie_phy {
	status = "okay";
};

&pcie0 {
	ep-gpios = <&gpio4 25 GPIO_ACTIVE_HIGH>;
	num-lanes = <4>;
	pinctrl-names = "default";
	pinctrl-0 = <&pcie_clkreqn>;
	status = "okay";
};

pinctl{		
	...
		pcie {
			pcie_clkreqn: pci-clkreqn {
				rockchip,pins =
					<2 26 RK_FUNC_2 &pcfg_pull_none>;
			};

			pcie_clkreqnb: pci-clkreqnb {
				rockchip,pins =
					<4 24 RK_FUNC_1 &pcfg_pull_none>;
			};
	...
			
	}

1.ep-gpios = <&gpio4 25 GPIO_ACTIVE_HIGH>;

​ 此项是设置 PCIe 接口的 PERST#复位信号;

在这里插入图片描述

2.num-lanes = <4>;

​ 此配置设置 PCIe 设备所使用的 lane 数量,默认不需要调整,软件可以自己探测并关闭不需要的 lane以节省功耗。

3.max-link-speed = <1>;

​ 配置设置 PCIe 的速度登记,1 表示 gen1,2 表示 gen2。RK3399 限制不超过 gen2。另,此配置默认是写在 dtsi,也就是说默认限制为 gen1,这与ASM1061不符,原因是 gen2 的 TX 测试指标无法达到标准,所以不推荐客户开启 gen2 模式,以免引起不必要的链路异常。

4.status = <okay>;

​ 此配置需要在 pcie0 和和 pcie_phy 节点同时使能。默认不使能的原因是如果没有外设,pcie 在初始化时有一个较大的检测延时,会额外增加不必要的开机时间。故,有需要 PCIe 的项目自行开启。

5.pinctrl-0 = <&pcie_clkreqn>;

​ 这里加了一个pinctrl,但我感觉firefly加错了,随他吧,反正RK也没让加,加的GPIO2_D2是蓝牙的唤醒引脚


在这里插入图片描述

四、menuconfig配置

  1. 需要确保如下配置打开,方可正确的使用 PCIe 相关功能
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
CONFIG_PCI_SYSCALL=y
CONFIG_PCI_BUS_ADDR_T_64BIT=y
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PHY_ROCKCHIP_PCIE=y
CONFIG_PCIE_ROCKCHIP=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIEASPM=y
CONFIG_PCIEASPM_POWERSAVE=y
CONFIG_PCIE_PME=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
  1. 使能 NVMe 设备(建立在 PCIe 接口的 SSD)
CONFIG_BLK_DEV_NVME=y
  1. 使能 AHCI 设备(PCIe 转接成 SATA 的 SSD)
CONFIG_SATA_PMP=y
CONFIG_SATA_AHCI=y
CONFIG_ATA_SFF=y
CONFIG_ATA=y

特别说明,默认 4.4 开源内核仅支持 drivers/ata/ahci.c 中列表内的设备,超出部分请找原厂或者代理商支持。

在这里插入图片描述

五、用户空间调试

1.查看pci设备
root@firefly:~# lspci
00:00.0 PCI bridge: Fuzhou Rockchip Electronics Co., Ltd Device 0100
01:00.0 IDE interface: ASMedia Technology Inc. ASM1061 SATA IDE Controller (rev 02)

root@firefly:/sys/bus/pci/devices/0000:01:00.0# cat device
0x0611
#可以看到ID和.c中的一致