in controller/dwc/pci-keystone.c [1104:1304]
static int __init ks_pcie_probe(struct platform_device *pdev)
{
const struct dw_pcie_host_ops *host_ops;
const struct dw_pcie_ep_ops *ep_ops;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
const struct ks_pcie_of_data *data;
enum dw_pcie_device_mode mode;
struct dw_pcie *pci;
struct keystone_pcie *ks_pcie;
struct device_link **link;
struct gpio_desc *gpiod;
struct resource *res;
unsigned int version;
void __iomem *base;
u32 num_viewport;
struct phy **phy;
u32 num_lanes;
char name[10];
int ret;
int irq;
int i;
data = of_device_get_match_data(dev);
if (!data)
return -EINVAL;
version = data->version;
host_ops = data->host_ops;
ep_ops = data->ep_ops;
mode = data->mode;
ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL);
if (!ks_pcie)
return -ENOMEM;
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
if (!pci)
return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app");
ks_pcie->va_app_base = devm_ioremap_resource(dev, res);
if (IS_ERR(ks_pcie->va_app_base))
return PTR_ERR(ks_pcie->va_app_base);
ks_pcie->app = *res;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbics");
base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
if (of_device_is_compatible(np, "ti,am654-pcie-rc"))
ks_pcie->is_am6 = true;
pci->dbi_base = base;
pci->dbi_base2 = base;
pci->dev = dev;
pci->ops = &ks_pcie_dw_pcie_ops;
pci->version = version;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = request_irq(irq, ks_pcie_err_irq_handler, IRQF_SHARED,
"ks-pcie-error-irq", ks_pcie);
if (ret < 0) {
dev_err(dev, "failed to request error IRQ %d\n",
irq);
return ret;
}
ret = of_property_read_u32(np, "num-lanes", &num_lanes);
if (ret)
num_lanes = 1;
phy = devm_kzalloc(dev, sizeof(*phy) * num_lanes, GFP_KERNEL);
if (!phy)
return -ENOMEM;
link = devm_kzalloc(dev, sizeof(*link) * num_lanes, GFP_KERNEL);
if (!link)
return -ENOMEM;
for (i = 0; i < num_lanes; i++) {
snprintf(name, sizeof(name), "pcie-phy%d", i);
phy[i] = devm_phy_optional_get(dev, name);
if (IS_ERR(phy[i])) {
ret = PTR_ERR(phy[i]);
goto err_link;
}
if (!phy[i])
continue;
link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
if (!link[i]) {
ret = -EINVAL;
goto err_link;
}
}
ks_pcie->np = np;
ks_pcie->pci = pci;
ks_pcie->link = link;
ks_pcie->num_lanes = num_lanes;
ks_pcie->phy = phy;
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_link;
}
ret = ks_pcie_enable_phy(ks_pcie);
if (ret) {
dev_err(dev, "failed to enable phy\n");
goto err_link;
}
platform_set_drvdata(pdev, ks_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;
}
if (pci->version >= 0x480A)
ret = ks_pcie_am654_set_mode(dev, mode);
else
ret = ks_pcie_set_mode(dev);
if (ret < 0)
goto err_get_sync;
switch (mode) {
case DW_PCIE_RC_TYPE:
if (!IS_ENABLED(CONFIG_PCI_KEYSTONE_HOST)) {
ret = -ENODEV;
goto err_get_sync;
}
ret = of_property_read_u32(np, "num-viewport", &num_viewport);
if (ret < 0) {
dev_err(dev, "unable to read *num-viewport* property\n");
goto err_get_sync;
}
/*
* "Power Sequencing and Reset Signal Timings" table in
* PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.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);
}
ks_pcie->num_viewport = num_viewport;
pci->pp.ops = host_ops;
ret = dw_pcie_host_init(&pci->pp);
if (ret < 0)
goto err_get_sync;
break;
case DW_PCIE_EP_TYPE:
if (!IS_ENABLED(CONFIG_PCI_KEYSTONE_EP)) {
ret = -ENODEV;
goto err_get_sync;
}
pci->ep.ops = ep_ops;
ret = dw_pcie_ep_init(&pci->ep);
if (ret < 0)
goto err_get_sync;
break;
default:
dev_err(dev, "INVALID device type %d\n", mode);
}
ks_pcie_enable_error_irq(ks_pcie);
return 0;
err_get_sync:
pm_runtime_put(dev);
pm_runtime_disable(dev);
ks_pcie_disable_phy(ks_pcie);
err_link:
while (--i >= 0 && link[i])
device_link_del(link[i]);
return ret;
}