Commit 9e87240c authored by Shawn Lin's avatar Shawn Lin Committed by Bjorn Helgaas
Browse files

PCI: rockchip: Add per-lane PHY support



We distinguish the legacy PHY from newer per-lane PHYs by adding legacy_phy
flag.  Note that the legacy PHY is still the first option to be searched in
order not to break the backward compatibility of DTB.

Tested-by: default avatarJeffy Chen <jeffy.chen@rock-chips.com>
Signed-off-by: default avatarShawn Lin <shawn.lin@rock-chips.com>
[bhelgaas: tidy rockchip_pcie_get_phys()]
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarBrian Norris <briannorris@chromium.org>
Acked-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parent 2ba5991f
Loading
Loading
Loading
Loading
+58 −20
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
#define HIWORD_UPDATE_BIT(val)		HIWORD_UPDATE(val, val)

#define ENCODE_LANES(x)			((((x) >> 1) & 3) << 4)
#define MAX_LANE_NUM			4

#define PCIE_CLIENT_BASE		0x0
#define PCIE_CLIENT_CONFIG		(PCIE_CLIENT_BASE + 0x00)
@@ -210,7 +211,8 @@
struct rockchip_pcie {
	void	__iomem *reg_base;		/* DT axi-base */
	void	__iomem *apb_base;		/* DT apb-base */
	struct	phy *phy;
	bool    legacy_phy;
	struct  phy *phys[MAX_LANE_NUM];
	struct	reset_control *core_rst;
	struct	reset_control *mgmt_rst;
	struct	reset_control *mgmt_sticky_rst;
@@ -515,7 +517,7 @@ static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip)
static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
{
	struct device *dev = rockchip->dev;
	int err;
	int err, i;
	u32 status;

	gpiod_set_value(rockchip->ep_gpio, 0);
@@ -538,11 +540,13 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
		return err;
	}

	err = phy_init(rockchip->phy);
	if (err < 0) {
		dev_err(dev, "fail to init phy, err %d\n", err);
	for (i = 0; i < MAX_LANE_NUM; i++) {
		err = phy_init(rockchip->phys[i]);
		if (err) {
			dev_err(dev, "init phy%d err %d\n", i, err);
			return err;
		}
	}

	err = reset_control_assert(rockchip->core_rst);
	if (err) {
@@ -603,11 +607,13 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
			    PCIE_CLIENT_MODE_RC,
			    PCIE_CLIENT_CONFIG);

	err = phy_power_on(rockchip->phy);
	for (i = 0; i < MAX_LANE_NUM; i++) {
		err = phy_power_on(rockchip->phys[i]);
		if (err) {
		dev_err(dev, "fail to power on phy, err %d\n", err);
			dev_err(dev, "power on phy%d err %d\n", i, err);
			return err;
		}
	}

	/*
	 * Please don't reorder the deassert sequence of the following
@@ -857,12 +863,39 @@ static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
static int rockchip_pcie_get_phys(struct rockchip_pcie *rockchip)
{
	struct device *dev = rockchip->dev;
	struct phy *phy;
	char *name;
	u32 i;

	phy = devm_phy_get(dev, "pcie-phy");
	if (!IS_ERR(phy)) {
		rockchip->legacy_phy = true;
		rockchip->phys[0] = phy;
		dev_warn(dev, "legacy phy model is deprecated!\n");
		return 0;
	}

	if (PTR_ERR(phy) == -EPROBE_DEFER)
		return PTR_ERR(phy);

	rockchip->phy = devm_phy_get(dev, "pcie-phy");
	if (IS_ERR(rockchip->phy)) {
		if (PTR_ERR(rockchip->phy) != -EPROBE_DEFER)
			dev_err(dev, "missing phy\n");
		return PTR_ERR(rockchip->phy);
	dev_dbg(dev, "missing legacy phy; search for per-lane PHY\n");

	for (i = 0; i < MAX_LANE_NUM; i++) {
		name = kasprintf(GFP_KERNEL, "pcie-phy-%u", i);
		if (!name)
			return -ENOMEM;

		phy = devm_of_phy_get(dev, dev->of_node, name);
		kfree(name);

		if (IS_ERR(phy)) {
			if (PTR_ERR(phy) != -EPROBE_DEFER)
				dev_err(dev, "missing phy for lane %d: %ld\n",
					i, PTR_ERR(phy));
			return PTR_ERR(phy);
		}

		rockchip->phys[i] = phy;
	}

	return 0;
@@ -1302,7 +1335,7 @@ static int rockchip_pcie_wait_l2(struct rockchip_pcie *rockchip)
static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev)
{
	struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
	int ret;
	int ret, i;

	/* disable core and cli int since we don't need to ack PME_ACK */
	rockchip_pcie_write(rockchip, (PCIE_CLIENT_INT_CLI << 16) |
@@ -1315,8 +1348,10 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev)
		return ret;
	}

	phy_power_off(rockchip->phy);
	phy_exit(rockchip->phy);
	for (i = 0; i < MAX_LANE_NUM; i++) {
		phy_power_off(rockchip->phys[i]);
		phy_exit(rockchip->phys[i]);
	}

	clk_disable_unprepare(rockchip->clk_pcie_pm);
	clk_disable_unprepare(rockchip->hclk_pcie);
@@ -1554,14 +1589,17 @@ static int rockchip_pcie_remove(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct rockchip_pcie *rockchip = dev_get_drvdata(dev);
	int i;

	pci_stop_root_bus(rockchip->root_bus);
	pci_remove_root_bus(rockchip->root_bus);
	pci_unmap_iospace(rockchip->io);
	irq_domain_remove(rockchip->irq_domain);

	phy_power_off(rockchip->phy);
	phy_exit(rockchip->phy);
	for (i = 0; i < MAX_LANE_NUM; i++) {
		phy_power_off(rockchip->phys[i]);
		phy_exit(rockchip->phys[i]);
	}

	clk_disable_unprepare(rockchip->clk_pcie_pm);
	clk_disable_unprepare(rockchip->hclk_pcie);