硬件平台:GV9531, PCIE控制器采用的是新思的IP核
软件平台:Linux 4.9
平台驱动初始化
芯片厂商封装IP厂商的数据结构
struct polaris_pcie {
struct dw_pcie *pci;
void __iomem *wrapper_base; // PCIe Wrapper Registers
enum dw_pcie_device_mode mode;
int reset_gpio;
};
数据结构dw_pcie是IP厂商对控制器的抽象数据 结构,polaris_pcie是芯片厂商博雅鸿图自定义的,对控制器的抽象。
由于控制器即可作为EP,也可以做为RC,故存在mode,用于分别是EP还是RC.
而wrapper_base显然是芯片厂商自定义封装的硬件模块控制的虚拟地址指针。
IP厂商定义的控制器抽象数据结构
struct dw_pcie {
struct device *dev; //指向平台设备内嵌的设备模型指针
struct pcie_port pp; //用于RC
struct dw_pcie_ep ep; //用于EP
const struct dw_pcie_ops *op s; //ep和rc统一的函数操作集合
void __iomem *dbi_base; //存储空间抽象指针
void __iomem *dbi_base2;
u32 num_viewport;
u8 iatu_unroll_enabled;
};
控制器驱动初始化
int polaris_pcie_probe(struct platform_device *pdev)
{
struct polaris_pcie *polaris_pcie;
struct dw_pcie *pci;
polaris_pcie = devm_kzalloc(dev, sizeof(*polaris_pcie), GFP_KERNEL);
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
pci->dev = dev;
pci->ops = &polaris_pcie_ops;
//设备树中获取
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wrapper");
polaris_pcie->wrapper_base = devm_ioremap_resource(dev, res);
// iATU 0x300000
// DMA 0x380000
// So we map 0x400000 for DBI
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
pci->dbi_base = devm_ioremap(dev, res->start, 0x400000);
platform_set_drvdata(pdev, polaris_pcie);
switch (polaris_pcie->mode) {
case DW_PCIE_RC_TYPE:
polaris_add_pcie_port(polaris_pcie, pdev);
break;
case DW_PCIE_EP_TYPE:
polaris_add_pcie_ep(polaris_pcie, pdev);
break;
}
return 0;
}
控制器IP核共同的处理函数集合
static const struct dw_pcie_ops polaris_pcie_ops = {
.cpu_addr_fixup = polaris_pcie_cpu_addr_fixup,
.read_dbi = polaris_pcie_read_dbi,
.write_dbi = polaris_pcie_write_dbi,
.link_up = polaris_pcie_link_up,
.start_link = polaris_pcie_establish_link,
.stop_link = polaris_pcie_stop_link,
};