Commit 000f60db authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab Committed by Bjorn Helgaas
Browse files

PCI: kirin: Add support for a PHY layer

The pcie-kirin driver contains both PHY and generic PCI driver.

The best would be, instead, to support a PCI PHY driver, making the driver
more generic.

However, it is too late to remove the Kirin 960 PHY, as a change like that
would make the DT schema incompatible with past versions.

So, add support for an external PHY driver without removing the existing
Kirin 960 PHY from it.

Link: https://lore.kernel.org/r/f38361df2e9d0dc5a38ff942b631f7fef64cdc12.1634812676.git.mchehab+huawei@kernel.org


Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
Acked-by: default avatarXiaowei Song <songxiaowei@hisilicon.com>
parent 61d37547
Loading
Loading
Loading
Loading
+79 −14
Original line number Diff line number Diff line
@@ -8,16 +8,18 @@
 * Author: Xiaowei Song <songxiaowei@huawei.com>
 */

#include <linux/compiler.h>
#include <linux/clk.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_pci.h>
#include <linux/phy/phy.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/platform_device.h>
@@ -50,11 +52,18 @@
#define PCIE_DEBOUNCE_PARAM	0xF0F400
#define PCIE_OE_BYPASS		(0x3 << 28)

enum pcie_kirin_phy_type {
	PCIE_KIRIN_INTERNAL_PHY,
	PCIE_KIRIN_EXTERNAL_PHY
};

struct kirin_pcie {
	enum pcie_kirin_phy_type	type;

	struct dw_pcie	*pci;
	struct phy	*phy;
	void __iomem	*apb_base;
	void		*phy_priv;	/* Needed for Kirin 960 PHY */
	void		*phy_priv;	/* only for PCIE_KIRIN_INTERNAL_PHY */
};

/*
@@ -476,8 +485,63 @@ static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
	.host_init = kirin_pcie_host_init,
};

static int kirin_pcie_power_on(struct platform_device *pdev,
			       struct kirin_pcie *kirin_pcie)
{
	struct device *dev = &pdev->dev;
	int ret;

	if (kirin_pcie->type == PCIE_KIRIN_INTERNAL_PHY) {
		ret = hi3660_pcie_phy_init(pdev, kirin_pcie);
		if (ret)
			return ret;

		return hi3660_pcie_phy_power_on(kirin_pcie);
	}

	kirin_pcie->phy = devm_of_phy_get(dev, dev->of_node, NULL);
	if (IS_ERR(kirin_pcie->phy))
		return PTR_ERR(kirin_pcie->phy);

	ret = phy_init(kirin_pcie->phy);
	if (ret)
		goto err;

	ret = phy_power_on(kirin_pcie->phy);
	if (ret)
		goto err;

	return 0;
err:
	phy_exit(kirin_pcie->phy);
	return ret;
}

static int __exit kirin_pcie_remove(struct platform_device *pdev)
{
	struct kirin_pcie *kirin_pcie = platform_get_drvdata(pdev);

	if (kirin_pcie->type == PCIE_KIRIN_INTERNAL_PHY)
		return 0;

	phy_power_off(kirin_pcie->phy);
	phy_exit(kirin_pcie->phy);

	return 0;
}

static const struct of_device_id kirin_pcie_match[] = {
	{
		.compatible = "hisilicon,kirin960-pcie",
		.data = (void *)PCIE_KIRIN_INTERNAL_PHY
	},
	{},
};

static int kirin_pcie_probe(struct platform_device *pdev)
{
	enum pcie_kirin_phy_type phy_type;
	const struct of_device_id *of_id;
	struct device *dev = &pdev->dev;
	struct kirin_pcie *kirin_pcie;
	struct dw_pcie *pci;
@@ -488,6 +552,14 @@ static int kirin_pcie_probe(struct platform_device *pdev)
		return -EINVAL;
	}

	of_id = of_match_device(kirin_pcie_match, dev);
	if (!of_id) {
		dev_err(dev, "OF data missing\n");
		return -EINVAL;
	}

	phy_type = (long)of_id->data;

	kirin_pcie = devm_kzalloc(dev, sizeof(struct kirin_pcie), GFP_KERNEL);
	if (!kirin_pcie)
		return -ENOMEM;
@@ -500,31 +572,24 @@ static int kirin_pcie_probe(struct platform_device *pdev)
	pci->ops = &kirin_dw_pcie_ops;
	pci->pp.ops = &kirin_pcie_host_ops;
	kirin_pcie->pci = pci;

	ret = hi3660_pcie_phy_init(pdev, kirin_pcie);
	if (ret)
		return ret;
	kirin_pcie->type = phy_type;

	ret = kirin_pcie_get_resource(kirin_pcie, pdev);
	if (ret)
		return ret;

	ret = hi3660_pcie_phy_power_on(kirin_pcie);
	platform_set_drvdata(pdev, kirin_pcie);

	ret = kirin_pcie_power_on(pdev, kirin_pcie);
	if (ret)
		return ret;

	platform_set_drvdata(pdev, kirin_pcie);

	return dw_pcie_host_init(&pci->pp);
}

static const struct of_device_id kirin_pcie_match[] = {
	{ .compatible = "hisilicon,kirin960-pcie" },
	{},
};

static struct platform_driver kirin_pcie_driver = {
	.probe			= kirin_pcie_probe,
	.remove	        	= __exit_p(kirin_pcie_remove),
	.driver			= {
		.name			= "kirin-pcie",
		.of_match_table		= kirin_pcie_match,