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

一、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-2~default~baidujs_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

  2. 使能 NVMe 设备(建立在 PCIe 接口的 SSD)

    CONFIG_BLK_DEV_NVME=y

  3. 使能 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中的一致
相关推荐
riverz12277 分钟前
ARM 和 x86_64是什么关系
linux
qq_243050794 小时前
aflplusplus:开源的模糊测试工具!全参数详细教程!Kali Linux教程!(一)
linux·web安全·网络安全·黑客·渗透测试·模糊测试·kali linux
小慧10245 小时前
2.1话题发布
linux·ros
夜影风6 小时前
Linux系统中自签名HTTPS证书
linux·运维·https
成工小白7 小时前
【Linux】C语言模拟实现shell命令行(程序替换原理)
linux·运维·服务器
福理原乡大王9 小时前
Linux信号详解
linux·运维·服务器·c++·ubuntu·信号处理
锅锅是锅锅9 小时前
ubuntu调整硬盘大小-使用gparted
linux·ubuntu·硬盘·gparted
孙克旭_10 小时前
day031-Shell自动化编程-数组与案例
linux·运维·自动化
潘yi.10 小时前
ELK1日志分析系统
linux·elk
腾飞的信仰11 小时前
单片机,主循环和中断资源访问冲突的案例
单片机·嵌入式硬件