NOTE:Kernel version: 5.4.24
File Path:drivers/pci/controller/dwc/pci-xxx.c(省略返回值判断)
1、相关结构的定义
struct xxx_pcie {
struct dw_pcie *pci;
int clkreq_gpio;
int dis_gpio;
int reset_gpio;
bool gpio_active_high;
struct clk *pcie_bus;
struct clk *pcie_phy;
struct clk *pcie_phy_pclk;
...
struct regmap *iomuxc_gpr;
struct regmap *hsiomix;
u32 controller_id;
struct reset_control *pciephy_reset;
struct reset_control *pciephy_perst;
struct reset_control *apps_reset;
struct reset_control *turnoff_reset;
struct reset_control *clkreq_reset;
u32 tx_deemph_gen1;
u32 tx_deemph_gen2_3p5db;
u32 tx_deemph_gen2_6db;
u32 tx_swing_full;
u32 tx_swing_low;
u32 hsio_cfg;
u32 ext_osc;
u32 local_addr;
u32 hard_wired;
u32 dma_unroll_offset;
int link_gen;
struct regulator *vpcie;
void __iomem *phy_base;
void __iomem *hsmix_base;
struct device *pd_pcie;
struct device *pd_pcie_per;
struct device *pd_pcie_phy;
struct device *pd_hsio_gpio;
...
const struct xxx_pcie_drvdata *drvdata;
struct regulator *epdev_on;
struct phy *phy;
};
struct dw_pcie {
struct device *dev;
void __iomem *dbi_base;
void __iomem *dbi_base2;
void __iomem *atu_base;
u32 num_viewport;
u8 iatu_unroll_enabled;
struct pcie_port pp;
struct dw_pcie_ep ep;
const struct dw_pcie_ops *ops;
unsigned int version;
};
struct xxx_pcie_drvdata {
enum xxx_pcie_variants variant;
u32 flags;
int dbi_length;
};
struct pcie_port {
struct device *dev;
u8 root_bus_nr;
void __iomem *dbi_base;
u64 cfg0_base;
void __iomem *va_cfg0_base;
u32 cfg0_size;
u64 cfg1_base;
void __iomem *va_cfg1_base;
u32 cfg1_size;
resource_size_t io_base;
phys_addr_t io_bus_addr;
u32 io_size;
u64 mem_base;
phys_addr_t mem_bus_addr;
u32 mem_size;
int cpu_addr_offset;
struct resource *cfg;
struct resource *io;
struct resource *mem;
struct resource *busn;
int irq;
u32 lanes;
u32 num_viewport;
struct pcie_host_ops *ops;
int msi_irq;
struct irq_domain *irq_domain;
u64 msi_target;
u8 iatu_unroll_enabled;
unsigned int msi_enable[MAX_MSI_CTRLS];
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
};
2、controller驱动框架
NOTE: 下述代码凡是对返回值判断均用...代替;而......表示省略部分代码。
7)编写xxx_pcie_host_init函数
static int xxx_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct xxx_pcie *xxx_pcie = to_xxx_pcie(pci);
if (gpio_is_valid(xxx_pcie->dis_gpio))
gpio_set_value_cansleep(xxx_pcie->dis_gpio, 1);
xxx_pcie_assert_core_reset(xxx_pcie);
xxx_pcie_init_phy(xxx_pcie);
xxx_pcie_deassert_core_reset(xxx_pcie);
xxx_setup_phy_mpll(xxx_pcie);
if (!(IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
&& (xxx_pcie->hard_wired == 0))) {
......
......
}
return 0;
}
6)定义pcie_port的操作函数xxx_pcie_host_ops
static const struct dw_pcie_host_ops xxx_pcie_host_ops = {
.host_init = xxx_pcie_host_init,
};
5)probe函数调用的主要函数
5_1)static int xxx_pcie_attach_pd(struct device *dev)
{
struct xxx_pcie *xxx_pcie = dev_get_drvdata(dev);
struct device_link *link;
xxx_pcie->pd_pcie = dev_pm_domain_attach_by_name(dev, "pcie");
...
link = device_link_add(dev, xxx_pcie->pd_pcie,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
...
xxx_pcie->pd_pcie_phy = dev_pm_domain_attach_by_name(dev, "pcie_phy");
...
link = device_link_add(dev, xxx_pcie->pd_pcie_phy,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
return 0;
}
5_2)static int xxx_add_pcie_port(struct xxx_pcie *xxx_pcie, struct platform_device *pdev)
{
struct dw_pcie *pci = xxx_pcie->pci;
struct pcie_port *pp = &pci->pp;
int ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
...
}
pp->ops = &xxx_pcie_host_ops;
ret = dw_pcie_host_init(pp);
...
return 0;
}
5_3)static void pci_xxx_set_msi_en(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
u16 val;
if (pci_msi_enabled()) {
dw_pcie_dbi_ro_wr_en(pci);
val = dw_pcie_readw_dbi(pci, PCIE_RC_xxx_MSI_CAP + PCI_MSI_FLAGS);
val |= PCI_MSI_FLAGS_ENABLE;
dw_pcie_writew_dbi(pci, PCIE_RC_xxx_MSI_CAP + PCI_MSI_FLAGS, val);
dw_pcie_dbi_ro_wr_dis(pci);
}
}
4)编写xxx_pcie_probe和xxx_pcie_shutdown函数
4_1)xxx_pcie_probe函数;
static int xxx_pcie_probe(struct platform_device *pdev)
{
struct xxx_pcie *xxx_pcie;
struct dw_pcie *pci;
struct device *dev = &pdev->dev;
struct device_node *np;
struct resource *dbi_base;
struct device_node *node = dev->of_node;
int ret;
xxx_pcie = devm_kzalloc(dev, sizeof(*xxx_pcie), GFP_KERNEL);
...
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
...
pci->dev = dev;
pci->ops = &dw_pcie_ops;
xxx_pcie->pci = pci;
xxx_pcie->drvdata = of_device_get_match_data(dev);
xxx_pcie->phy = devm_phy_get(dev, "pcie-phy");
...
np = of_parse_phandle(node, "fsl,xxx8mp-hsio-mix", 0);
if(np) {
struct resource res;
ret = of_address_to_resource(np, 0, &res);
...
xxx_pcie->hsmix_base = devm_ioremap_resource(dev, &res);
...
}
dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pci->dbi_base = devm_ioremap_resource(dev, dbi_base);
...
if (of_property_read_u32(node, "hsio-cfg", &xxx_pcie->hsio_cfg))
xxx_pcie->hsio_cfg = 0;
if (of_property_read_u32(node, "ext_osc", &xxx_pcie->ext_osc) < 0)
xxx_pcie->ext_osc = 0;
if (of_property_read_u32(node, "local-addr", &xxx_pcie->local_addr))
xxx_pcie->local_addr = 0;
if (of_property_read_u32(node, "hard-wired", &xxx_pcie->hard_wired))
xxx_pcie->hard_wired = 0;
xxx_pcie->clkreq_gpio = of_get_named_gpio(node, "clkreq-gpio", 0);
...
xxx_pcie->dis_gpio = of_get_named_gpio(node, "disable-gpio", 0);
...
xxx_pcie->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
...
xxx_pcie->gpio_active_high = of_property_read_bool(node, "reset-gpio-active-high");
...
xxx_pcie->epdev_on = devm_regulator_get(&pdev->dev,"epdev_on");
...
xxx_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy");
...
xxx_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus");
...
xxx_pcie->pcie = devm_clk_get(dev, "pcie");
...
xxx_pcie->pciephy_perst = devm_reset_control_get_exclusive(dev, "pciephy_perst");
...
xxx_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff");
...
xxx_pcie->clkreq_reset = devm_reset_control_get_optional_exclusive(dev, "clkreq");
...
if (xxx_pcie->iomuxc_gpr == NULL) {
xxx_pcie->iomuxc_gpr = syscon_regmap_lookup_by_compatible("fsl,xxxq-iomuxc-gpr");
...
}
if (of_property_read_u32(node, "fsl,tx-deemph-gen1", &xxx_pcie->tx_deemph_gen1))
xxx_pcie->tx_deemph_gen1 = 0;
if (of_property_read_u32(node, "fsl,tx-deemph-gen2-3p5db", &xxx_pcie->tx_deemph_gen2_3p5db))
xxx_pcie->tx_deemph_gen2_3p5db = 0;
if (of_property_read_u32(node, "fsl,tx-deemph-gen2-6db", &xxx_pcie->tx_deemph_gen2_6db))
xxx_pcie->tx_deemph_gen2_6db = 20;
if (of_property_read_u32(node, "fsl,tx-swing-full", &xxx_pcie->tx_swing_full))
xxx_pcie->tx_swing_full = 127;
if (of_property_read_u32(node, "fsl,tx-swing-low", &xxx_pcie->tx_swing_low))
xxx_pcie->tx_swing_low = 127;
ret = of_property_read_u32(node, "fsl,max-link-speed", &xxx_pcie->link_gen);
if (ret)
xxx_pcie->link_gen = 1;
platform_set_drvdata(pdev, xxx_pcie);
ret = xxx_pcie_attach_pd(dev);
...
ret = regulator_enable(xxx_pcie->epdev_on);
...
if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
&& (xxx_pcie->hard_wired == 0)) {
......
......
}else {
ret = xxx_add_pcie_port(xxx_pcie, pdev);
if (ret < 0) {
if (IS_ENABLED(CONFIG_PCI_xxx_COMPLIANCE_TEST)) {
......
}
}
pci_xxx_set_msi_en(&xxx_pcie->pci->pp);
if (IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS)
&& (xxx_pcie->hard_wired == 0))
......
ret = xxx_pcie->drvdata->flags & xxx_PCIE_FLAG_SUPPORTS_L1SS;
if (IS_ENABLED(CONFIG_PCIEASPM_POWER_SUPERSAVE) && (ret > 0)) {
......
......
}
}
return 0;
}
4_2)xxx_pcie_shutdown函数;
static void xxx_pcie_shutdown(struct platform_device *pdev)
{
struct xxx_pcie *xxx_pcie = platform_get_drvdata(pdev);
xxx_pcie_assert_core_reset(xxx_pcie);
}
3)定义.driver.of_match_table
static const struct xxx_pcie_drvdata drvdata[] = {
......
......
[xxx8MP] = {
.variant = xxx8MP,
.flags = xxx_PCIE_FLAG_SUPPORTS_SUSPEND,
},
};
static const struct of_device_id xxx_pcie_of_match[] = {
{ .compatible = "fsl,xxx8mq-pcie", .data = &drvdata[xxx8MQ], },
{ .compatible = "fsl,xxx8mm-pcie", .data = &drvdata[xxx8MM], },
{ .compatible = "fsl,xxx8qm-pcie", .data = &drvdata[xxx8QM], },
{ .compatible = "fsl,xxx8qxp-pcie", .data = &drvdata[xxx8QXP], },
{ .compatible = "fsl,xxx8mp-pcie", .data = &drvdata[xxx8MP], },
{},
};
2)定义一个platform driver
static struct platform_driver xxx_pcie_driver = {
.driver = {
.name = "xxx-pcie",
.of_match_table = xxx_pcie_of_match,
.suppress_bind_attrs = true,
.pm = &xxx_pcie_pm_ops,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = xxx_pcie_probe,
.shutdown = xxx_pcie_shutdown,
};
1)入口函数
static int __init xxx_pcie_init(void)
{
#ifdef CONFIG_ARM
hook_fault_code(8, xxx_pcie_abort_handler, SIGBUS, 0,
"external abort on non-linefetch");
#endif
return platform_driver_register(&xxx_pcie_driver);
}
device_initcall(xxx_pcie_init);
3、phy驱动框架
某平台pcie设备的(host)controller驱动框架及其phy驱动框架(二)