blob: 52ceed1b0298b8ed940080fb999264293b2220b8 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 366697018c9a2aa67d457bfdc495115cface6ae8 Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun@nic.cz>
3Date: Thu, 30 Apr 2020 10:06:20 +0200
4Subject: [PATCH] PCI: aardvark: Add PHY support
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9With recent proposed changes for U-Boot it is possible that bootloader
10won't initialize the PHY for this controller (currently the PHY is
11initialized regardless whether PCI is used in U-Boot, but with these
12proposed changes the PHY is initialized only on request).
13
14Since the mvebu-a3700-comphy driver by Miquèl Raynal supports enabling
15PCIe PHY, and since Linux' functionality should be independent on what
16bootloader did, add code for enabling generic PHY if found in device OF
17node.
18
19The mvebu-a3700-comphy driver does PHY powering via SMC calls to ARM
20Trusted Firmware. The corresponding code in ARM Trusted Firmware skips
21one register write which U-Boot does not: step 7 ("Enable TX"), see [1].
22Instead ARM Trusted Firmware expects PCIe driver to do this step,
23probably because the register is in PCIe controller address space,
24instead of PHY address space. We therefore add this step into the
25advk_pcie_setup_hw function.
26
27[1] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/drivers/marvell/comphy/phy-comphy-3700.c?h=v2.3-rc2#n836
28
29Link: https://lore.kernel.org/r/20200430080625.26070-8-pali@kernel.org
30Tested-by: Tomasz Maciej Nowak <tmn505@gmail.com>
31Signed-off-by: Marek Behún <marek.behun@nic.cz>
32Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
33Reviewed-by: Rob Herring <robh@kernel.org>
34Acked-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
35Cc: Miquèl Raynal <miquel.raynal@bootlin.com>
36---
37 drivers/pci/controller/pci-aardvark.c | 69 +++++++++++++++++++++++++++
38 1 file changed, 69 insertions(+)
39
40--- a/drivers/pci/controller/pci-aardvark.c
41+++ b/drivers/pci/controller/pci-aardvark.c
42@@ -16,6 +16,7 @@
43 #include <linux/kernel.h>
44 #include <linux/pci.h>
45 #include <linux/init.h>
46+#include <linux/phy/phy.h>
47 #include <linux/platform_device.h>
48 #include <linux/of_address.h>
49 #include <linux/of_gpio.h>
50@@ -90,6 +91,8 @@
51 #define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5)
52 #define PCIE_CORE_CTRL2_OB_WIN_ENABLE BIT(6)
53 #define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10)
54+#define PCIE_CORE_REF_CLK_REG (CONTROL_BASE_ADDR + 0x14)
55+#define PCIE_CORE_REF_CLK_TX_ENABLE BIT(1)
56 #define PCIE_MSG_LOG_REG (CONTROL_BASE_ADDR + 0x30)
57 #define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40)
58 #define PCIE_MSG_PM_PME_MASK BIT(7)
59@@ -289,6 +292,7 @@ struct advk_pcie {
60 int link_gen;
61 struct pci_bridge_emul bridge;
62 struct gpio_desc *reset_gpio;
63+ struct phy *phy;
64 };
65
66 static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg)
67@@ -482,6 +486,11 @@ static void advk_pcie_setup_hw(struct ad
68 u32 reg;
69 int i;
70
71+ /* Enable TX */
72+ reg = advk_readl(pcie, PCIE_CORE_REF_CLK_REG);
73+ reg |= PCIE_CORE_REF_CLK_TX_ENABLE;
74+ advk_writel(pcie, reg, PCIE_CORE_REF_CLK_REG);
75+
76 /* Set to Direct mode */
77 reg = advk_readl(pcie, CTRL_CONFIG_REG);
78 reg &= ~(CTRL_MODE_MASK << CTRL_MODE_SHIFT);
79@@ -1491,6 +1500,62 @@ out_release_res:
80 return err;
81 }
82
83+static void __maybe_unused advk_pcie_disable_phy(struct advk_pcie *pcie)
84+{
85+ phy_power_off(pcie->phy);
86+ phy_exit(pcie->phy);
87+}
88+
89+static int advk_pcie_enable_phy(struct advk_pcie *pcie)
90+{
91+ int ret;
92+
93+ if (!pcie->phy)
94+ return 0;
95+
96+ ret = phy_init(pcie->phy);
97+ if (ret)
98+ return ret;
99+
100+ ret = phy_set_mode(pcie->phy, PHY_MODE_PCIE);
101+ if (ret) {
102+ phy_exit(pcie->phy);
103+ return ret;
104+ }
105+
106+ ret = phy_power_on(pcie->phy);
107+ if (ret) {
108+ phy_exit(pcie->phy);
109+ return ret;
110+ }
111+
112+ return 0;
113+}
114+
115+static int advk_pcie_setup_phy(struct advk_pcie *pcie)
116+{
117+ struct device *dev = &pcie->pdev->dev;
118+ struct device_node *node = dev->of_node;
119+ int ret = 0;
120+
121+ pcie->phy = devm_of_phy_get(dev, node, NULL);
122+ if (IS_ERR(pcie->phy) && (PTR_ERR(pcie->phy) == -EPROBE_DEFER))
123+ return PTR_ERR(pcie->phy);
124+
125+ /* Old bindings miss the PHY handle */
126+ if (IS_ERR(pcie->phy)) {
127+ dev_warn(dev, "PHY unavailable (%ld)\n", PTR_ERR(pcie->phy));
128+ pcie->phy = NULL;
129+ return 0;
130+ }
131+
132+ ret = advk_pcie_enable_phy(pcie);
133+ if (ret)
134+ dev_err(dev, "Failed to initialize PHY (%d)\n", ret);
135+
136+ return ret;
137+}
138+
139 static int advk_pcie_probe(struct platform_device *pdev)
140 {
141 struct device *dev = &pdev->dev;
142@@ -1623,6 +1688,10 @@ static int advk_pcie_probe(struct platfo
143 else
144 pcie->link_gen = ret;
145
146+ ret = advk_pcie_setup_phy(pcie);
147+ if (ret)
148+ return ret;
149+
150 advk_pcie_setup_hw(pcie);
151
152 ret = advk_sw_pci_bridge_init(pcie);