static int dra7xx_pcie_probe()

in controller/dwc/pci-dra7xx.c [684:863]


static int dra7xx_pcie_probe(struct platform_device *pdev)
{
	u32 reg;
	int ret;
	int irq;
	int i;
	int phy_count;
	struct phy **phy;
	struct device_link **link;
	void __iomem *base;
	struct dw_pcie *pci;
	struct dra7xx_pcie *dra7xx;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	char name[10];
	struct gpio_desc *reset;
	const struct dra7xx_pcie_of_data *data;
	enum dw_pcie_device_mode mode;
	u32 b1co_mode_sel_mask;

	data = of_device_get_match_data(dev);
	if (!data)
		return -EINVAL;

	mode = (enum dw_pcie_device_mode)data->mode;
	b1co_mode_sel_mask = data->b1co_mode_sel_mask;

	dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
	if (!dra7xx)
		return -ENOMEM;

	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
	if (!pci)
		return -ENOMEM;

	pci->dev = dev;
	pci->ops = &dw_pcie_ops;

	irq = platform_get_irq(pdev, 0);
	if (irq < 0)
		return irq;

	base = devm_platform_ioremap_resource_byname(pdev, "ti_conf");
	if (IS_ERR(base))
		return PTR_ERR(base);

	phy_count = of_property_count_strings(np, "phy-names");
	if (phy_count < 0) {
		dev_err(dev, "unable to find the strings\n");
		return phy_count;
	}

	phy = devm_kcalloc(dev, phy_count, sizeof(*phy), GFP_KERNEL);
	if (!phy)
		return -ENOMEM;

	link = devm_kcalloc(dev, phy_count, sizeof(*link), GFP_KERNEL);
	if (!link)
		return -ENOMEM;

	dra7xx->clk = devm_clk_get_optional(dev, NULL);
	if (IS_ERR(dra7xx->clk))
		return dev_err_probe(dev, PTR_ERR(dra7xx->clk),
				     "clock request failed");

	ret = clk_prepare_enable(dra7xx->clk);
	if (ret)
		return ret;

	for (i = 0; i < phy_count; i++) {
		snprintf(name, sizeof(name), "pcie-phy%d", i);
		phy[i] = devm_phy_get(dev, name);
		if (IS_ERR(phy[i]))
			return PTR_ERR(phy[i]);

		link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS);
		if (!link[i]) {
			ret = -EINVAL;
			goto err_link;
		}
	}

	dra7xx->base = base;
	dra7xx->phy = phy;
	dra7xx->pci = pci;
	dra7xx->phy_count = phy_count;

	if (phy_count == 2) {
		ret = dra7xx_pcie_configure_two_lane(dev, b1co_mode_sel_mask);
		if (ret < 0)
			dra7xx->phy_count = 1; /* Fallback to x1 lane mode */
	}

	ret = dra7xx_pcie_enable_phy(dra7xx);
	if (ret) {
		dev_err(dev, "failed to enable phy\n");
		return ret;
	}

	platform_set_drvdata(pdev, dra7xx);

	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;
	}

	reset = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
	if (IS_ERR(reset)) {
		ret = PTR_ERR(reset);
		dev_err(&pdev->dev, "gpio request failed, ret %d\n", ret);
		goto err_gpio;
	}

	reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
	reg &= ~LTSSM_EN;
	dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);

	switch (mode) {
	case DW_PCIE_RC_TYPE:
		if (!IS_ENABLED(CONFIG_PCI_DRA7XX_HOST)) {
			ret = -ENODEV;
			goto err_gpio;
		}

		dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
				   DEVICE_TYPE_RC);

		ret = dra7xx_pcie_unaligned_memaccess(dev);
		if (ret)
			dev_err(dev, "WA for Errata i870 not applied\n");

		ret = dra7xx_add_pcie_port(dra7xx, pdev);
		if (ret < 0)
			goto err_gpio;
		break;
	case DW_PCIE_EP_TYPE:
		if (!IS_ENABLED(CONFIG_PCI_DRA7XX_EP)) {
			ret = -ENODEV;
			goto err_gpio;
		}

		dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
				   DEVICE_TYPE_EP);

		ret = dra7xx_pcie_unaligned_memaccess(dev);
		if (ret)
			goto err_gpio;

		ret = dra7xx_add_pcie_ep(dra7xx, pdev);
		if (ret < 0)
			goto err_gpio;
		break;
	default:
		dev_err(dev, "INVALID device type %d\n", mode);
	}
	dra7xx->mode = mode;

	ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler,
			       IRQF_SHARED, "dra7xx-pcie-main", dra7xx);
	if (ret) {
		dev_err(dev, "failed to request irq\n");
		goto err_gpio;
	}

	return 0;

err_gpio:
err_get_sync:
	pm_runtime_put(dev);
	pm_runtime_disable(dev);
	dra7xx_pcie_disable_phy(dra7xx);

err_link:
	while (--i >= 0)
		device_link_del(link[i]);

	return ret;
}