in controller/cadence/pci-j721e.c [351:542]
static int j721e_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct pci_host_bridge *bridge;
const struct j721e_pcie_data *data;
struct cdns_pcie *cdns_pcie;
struct j721e_pcie *pcie;
struct cdns_pcie_rc *rc;
struct cdns_pcie_ep *ep;
struct gpio_desc *gpiod;
void __iomem *base;
struct clk *clk;
u32 num_lanes;
u32 mode;
int ret;
int irq;
data = of_device_get_match_data(dev);
if (!data)
return -EINVAL;
mode = (u32)data->mode;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
return -ENOMEM;
pcie->mode = mode;
pcie->linkdown_irq_regfield = data->linkdown_irq_regfield;
base = devm_platform_ioremap_resource_byname(pdev, "intd_cfg");
if (IS_ERR(base))
return PTR_ERR(base);
pcie->intd_cfg_base = base;
base = devm_platform_ioremap_resource_byname(pdev, "user_cfg");
if (IS_ERR(base))
return PTR_ERR(base);
pcie->user_cfg_base = base;
ret = of_property_read_u32(node, "num-lanes", &num_lanes);
if (ret || num_lanes > MAX_LANES)
num_lanes = 1;
pcie->num_lanes = num_lanes;
if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)))
return -EINVAL;
irq = platform_get_irq_byname(pdev, "link_state");
if (irq < 0)
return irq;
dev_set_drvdata(dev, pcie);
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "pm_runtime_get_sync failed\n");
goto err_get_sync;
}
ret = j721e_pcie_ctrl_init(pcie);
if (ret < 0) {
dev_err(dev, "pm_runtime_get_sync failed\n");
goto err_get_sync;
}
ret = devm_request_irq(dev, irq, j721e_pcie_link_irq_handler, 0,
"j721e-pcie-link-down-irq", pcie);
if (ret < 0) {
dev_err(dev, "failed to request link state IRQ %d\n", irq);
goto err_get_sync;
}
j721e_pcie_config_link_irq(pcie);
switch (mode) {
case PCI_MODE_RC:
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) {
ret = -ENODEV;
goto err_get_sync;
}
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
if (!bridge) {
ret = -ENOMEM;
goto err_get_sync;
}
if (!data->byte_access_allowed)
bridge->ops = &cdns_ti_pcie_host_ops;
rc = pci_host_bridge_priv(bridge);
rc->quirk_retrain_flag = data->quirk_retrain_flag;
rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
cdns_pcie = &rc->pcie;
cdns_pcie->dev = dev;
cdns_pcie->ops = &j721e_pcie_ops;
pcie->cdns_pcie = cdns_pcie;
gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpiod)) {
ret = PTR_ERR(gpiod);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get reset GPIO\n");
goto err_get_sync;
}
ret = cdns_pcie_init_phy(dev, cdns_pcie);
if (ret) {
dev_err(dev, "Failed to init phy\n");
goto err_get_sync;
}
clk = devm_clk_get_optional(dev, "pcie_refclk");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
dev_err(dev, "failed to get pcie_refclk\n");
goto err_pcie_setup;
}
ret = clk_prepare_enable(clk);
if (ret) {
dev_err(dev, "failed to enable pcie_refclk\n");
goto err_pcie_setup;
}
pcie->refclk = clk;
/*
* "Power Sequencing and Reset Signal Timings" table in
* PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 3.0
* indicates PERST# should be deasserted after minimum of 100us
* once REFCLK is stable. The REFCLK to the connector in RC
* mode is selected while enabling the PHY. So deassert PERST#
* after 100 us.
*/
if (gpiod) {
usleep_range(100, 200);
gpiod_set_value_cansleep(gpiod, 1);
}
ret = cdns_pcie_host_setup(rc);
if (ret < 0) {
clk_disable_unprepare(pcie->refclk);
goto err_pcie_setup;
}
break;
case PCI_MODE_EP:
if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) {
ret = -ENODEV;
goto err_get_sync;
}
ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
if (!ep) {
ret = -ENOMEM;
goto err_get_sync;
}
ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
cdns_pcie = &ep->pcie;
cdns_pcie->dev = dev;
cdns_pcie->ops = &j721e_pcie_ops;
pcie->cdns_pcie = cdns_pcie;
ret = cdns_pcie_init_phy(dev, cdns_pcie);
if (ret) {
dev_err(dev, "Failed to init phy\n");
goto err_get_sync;
}
ret = cdns_pcie_ep_setup(ep);
if (ret < 0)
goto err_pcie_setup;
break;
default:
dev_err(dev, "INVALID device type %d\n", mode);
}
return 0;
err_pcie_setup:
cdns_pcie_disable_phy(cdns_pcie);
err_get_sync:
pm_runtime_put(dev);
pm_runtime_disable(dev);
return ret;
}