diff --git a/IMX6ULL/doc_pic/10_PCI_PCIe/07_PCI驱动程序框架.md b/IMX6ULL/doc_pic/10_PCI_PCIe/07_PCI驱动程序框架.md new file mode 100644 index 0000000..d820577 --- /dev/null +++ b/IMX6ULL/doc_pic/10_PCI_PCIe/07_PCI驱动程序框架.md @@ -0,0 +1,128 @@ +## PCI驱动程序框架 + +参考资料: + +* 《PCI Express Technology 3.0》,Mike Jackson, Ravi Budruk; MindShare, Inc. +* [《PCIe扫盲系列博文》](http://blog.chinaaet.com/justlxy/p/5100053251),作者Felix,这是对《PCI Express Technology》的理解与翻译 +* 《PCI EXPRESS体系结构导读 (王齐)》 +* 《PCI Express_ Base Specification Revision 4.0 Version 0.3 ( PDFDrive )》 +* 《NCB-PCI_Express_Base_5.0r1.0-2019-05-22》 +* [SOC中AXI总线是如何连接的](https://zhuanlan.zhihu.com/p/157137488) +* [AXI总线整理总结](https://blog.csdn.net/tristan_tian/article/details/89393045) +* [PCIe中MSI和MSI-X中断机制](https://blog.csdn.net/pieces_thinking/article/details/119431791) + + + +### 1. 总线设备驱动模型 + + + +### 2. RK3399驱动 + +怎么找到驱动? + +* 在内核目录下根据芯片名字找到文件:`drivers\pci\host\pcie-rockchip.c` + + * 看到如下代码: + + ```c + static const struct of_device_id rockchip_pcie_of_match[] = { + { .compatible = "rockchip,rk3399-pcie", }, + {} + }; + ``` + +* 在内核`arch/arm64/boot/dts`下搜:`grep "rockchip,rk3399-pcie" * -nr` + + * 找到设备树文件:`arch/arm64/boot/dts/rk3399.dtsi`,代码如下: + + ```shell + pcie0: pcie@f8000000 { + compatible = "rockchip,rk3399-pcie"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0x1f>; + ...... /* 省略 */ + 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>; + ...... /* 省略 */ + }; + ``` + +#### 2.1 设备树解析过程 + +```c +rockchip_pcie_probe + resource_size_t io_base; + LIST_HEAD(res); // 资源链表 + + // 解析设备树获得PCI host bridge的资源(CPU地址空间、PCI地址空间、大小) + err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff, &res, &io_base); + // 解析 bus-range + err = of_pci_parse_bus_range(dev, bus_range); + pci_add_resource(resources, bus_range); + + // 解析 ranges + of_pci_range_parser_init + parser->range = of_get_property(node, "ranges", &rlen); + for_each_of_pci_range(&parser, &range) {// 解析range + + // 把range转换为resource + // res->flags = range->flags; + // res->start = range->cpu_addr; + // res->end = res->start + range->size - 1; + err = of_pci_range_to_resource(&range, dev, res); + + // 在链表中增加一项 + // 注意第3个参数: offset = cpu_addr - pci_addr + pci_add_resource_offset(resources, res, res->start - range.pci_addr); + + } + + /* Get the I/O and memory ranges from DT */ + resource_list_for_each_entry(win, &res) { + rockchip->io_bus_addr = io->start - win->offset; // 0xfbe00000,pci addr + rockchip->mem_bus_addr = mem->start - win->offset; // 0xfba00000, pci addr + rockchip->root_bus_nr = win->res->start; // 0 + } + + bus = pci_scan_root_bus(&pdev->dev, 0, &rockchip_pcie_ops, rockchip, &res); + + pci_bus_add_devices(bus); +``` + + + +`for_each_of_pci_range`解析设备树过程: + +![image-20211224164144628](pic/10_PCI_PCIe/50_parse_range.png) + + + +#### 2.2 扫描总线过程 + +```c +rockchip_pcie_probe + bus = pci_scan_root_bus(&pdev->dev, 0, &rockchip_pcie_ops, rockchip, &res); + pci_scan_root_bus_msi + pci_scan_child_bus + pci_scan_slot + dev = pci_scan_single_device(bus, devfn); + dev = pci_scan_device(bus, devfn); + pci_setup_device + pci_read_bases(dev, 6, PCI_ROM_ADDRESS); + pci_device_add(dev, bus); + + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + + pci_bus_add_devices(bus); + +``` + diff --git a/IMX6ULL/doc_pic/10_PCI_PCIe/07_PCI驱动程序框架.tif b/IMX6ULL/doc_pic/10_PCI_PCIe/07_PCI驱动程序框架.tif new file mode 100644 index 0000000..d568879 Binary files /dev/null and b/IMX6ULL/doc_pic/10_PCI_PCIe/07_PCI驱动程序框架.tif differ diff --git a/IMX6ULL/doc_pic/10_PCI_PCIe/pic/10_PCI_PCIe/50_parse_range.png b/IMX6ULL/doc_pic/10_PCI_PCIe/pic/10_PCI_PCIe/50_parse_range.png new file mode 100644 index 0000000..1f0114c Binary files /dev/null and b/IMX6ULL/doc_pic/10_PCI_PCIe/pic/10_PCI_PCIe/50_parse_range.png differ