static int tegra194_pcie_probe()

in controller/dwc/pcie-tegra194.c [1960:2147]


static int tegra194_pcie_probe(struct platform_device *pdev)
{
	const struct tegra194_pcie_of_data *data;
	struct device *dev = &pdev->dev;
	struct resource *atu_dma_res;
	struct tegra194_pcie *pcie;
	struct pcie_port *pp;
	struct dw_pcie *pci;
	struct phy **phys;
	char *name;
	int ret;
	u32 i;

	data = of_device_get_match_data(dev);

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

	pci = &pcie->pci;
	pci->dev = &pdev->dev;
	pci->ops = &tegra_dw_pcie_ops;
	pci->n_fts[0] = N_FTS_VAL;
	pci->n_fts[1] = FTS_VAL;
	pci->version = 0x490A;

	pp = &pci->pp;
	pp->num_vectors = MAX_MSI_IRQS;
	pcie->dev = &pdev->dev;
	pcie->mode = (enum dw_pcie_device_mode)data->mode;

	ret = tegra194_pcie_parse_dt(pcie);
	if (ret < 0) {
		const char *level = KERN_ERR;

		if (ret == -EPROBE_DEFER)
			level = KERN_DEBUG;

		dev_printk(level, dev,
			   dev_fmt("Failed to parse device tree: %d\n"),
			   ret);
		return ret;
	}

	ret = tegra_pcie_get_slot_regulators(pcie);
	if (ret < 0) {
		const char *level = KERN_ERR;

		if (ret == -EPROBE_DEFER)
			level = KERN_DEBUG;

		dev_printk(level, dev,
			   dev_fmt("Failed to get slot regulators: %d\n"),
			   ret);
		return ret;
	}

	if (pcie->pex_refclk_sel_gpiod)
		gpiod_set_value(pcie->pex_refclk_sel_gpiod, 1);

	pcie->pex_ctl_supply = devm_regulator_get(dev, "vddio-pex-ctl");
	if (IS_ERR(pcie->pex_ctl_supply)) {
		ret = PTR_ERR(pcie->pex_ctl_supply);
		if (ret != -EPROBE_DEFER)
			dev_err(dev, "Failed to get regulator: %ld\n",
				PTR_ERR(pcie->pex_ctl_supply));
		return ret;
	}

	pcie->core_clk = devm_clk_get(dev, "core");
	if (IS_ERR(pcie->core_clk)) {
		dev_err(dev, "Failed to get core clock: %ld\n",
			PTR_ERR(pcie->core_clk));
		return PTR_ERR(pcie->core_clk);
	}

	pcie->appl_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
						      "appl");
	if (!pcie->appl_res) {
		dev_err(dev, "Failed to find \"appl\" region\n");
		return -ENODEV;
	}

	pcie->appl_base = devm_ioremap_resource(dev, pcie->appl_res);
	if (IS_ERR(pcie->appl_base))
		return PTR_ERR(pcie->appl_base);

	pcie->core_apb_rst = devm_reset_control_get(dev, "apb");
	if (IS_ERR(pcie->core_apb_rst)) {
		dev_err(dev, "Failed to get APB reset: %ld\n",
			PTR_ERR(pcie->core_apb_rst));
		return PTR_ERR(pcie->core_apb_rst);
	}

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

	for (i = 0; i < pcie->phy_count; i++) {
		name = kasprintf(GFP_KERNEL, "p2u-%u", i);
		if (!name) {
			dev_err(dev, "Failed to create P2U string\n");
			return -ENOMEM;
		}
		phys[i] = devm_phy_get(dev, name);
		kfree(name);
		if (IS_ERR(phys[i])) {
			ret = PTR_ERR(phys[i]);
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "Failed to get PHY: %d\n", ret);
			return ret;
		}
	}

	pcie->phys = phys;

	atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
						   "atu_dma");
	if (!atu_dma_res) {
		dev_err(dev, "Failed to find \"atu_dma\" region\n");
		return -ENODEV;
	}
	pcie->atu_dma_res = atu_dma_res;

	pci->atu_size = resource_size(atu_dma_res);
	pci->atu_base = devm_ioremap_resource(dev, atu_dma_res);
	if (IS_ERR(pci->atu_base))
		return PTR_ERR(pci->atu_base);

	pcie->core_rst = devm_reset_control_get(dev, "core");
	if (IS_ERR(pcie->core_rst)) {
		dev_err(dev, "Failed to get core reset: %ld\n",
			PTR_ERR(pcie->core_rst));
		return PTR_ERR(pcie->core_rst);
	}

	pp->irq = platform_get_irq_byname(pdev, "intr");
	if (pp->irq < 0)
		return pp->irq;

	pcie->bpmp = tegra_bpmp_get(dev);
	if (IS_ERR(pcie->bpmp))
		return PTR_ERR(pcie->bpmp);

	platform_set_drvdata(pdev, pcie);

	switch (pcie->mode) {
	case DW_PCIE_RC_TYPE:
		ret = devm_request_irq(dev, pp->irq, tegra_pcie_rp_irq_handler,
				       IRQF_SHARED, "tegra-pcie-intr", pcie);
		if (ret) {
			dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq,
				ret);
			goto fail;
		}

		ret = tegra_pcie_config_rp(pcie);
		if (ret && ret != -ENOMEDIUM)
			goto fail;
		else
			return 0;
		break;

	case DW_PCIE_EP_TYPE:
		ret = devm_request_threaded_irq(dev, pp->irq,
						tegra_pcie_ep_hard_irq,
						tegra_pcie_ep_irq_thread,
						IRQF_SHARED | IRQF_ONESHOT,
						"tegra-pcie-ep-intr", pcie);
		if (ret) {
			dev_err(dev, "Failed to request IRQ %d: %d\n", pp->irq,
				ret);
			goto fail;
		}

		ret = tegra_pcie_config_ep(pcie, pdev);
		if (ret < 0)
			goto fail;
		break;

	default:
		dev_err(dev, "Invalid PCIe device type %d\n", pcie->mode);
	}

fail:
	tegra_bpmp_put(pcie->bpmp);
	return ret;
}