GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / phy / freescale / phy-fsl-imx8m-pcie.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2021 NXP
4  */
5
6 #include <linux/bitfield.h>
7 #include <linux/clk.h>
8 #include <linux/delay.h>
9 #include <linux/io.h>
10 #include <linux/iopoll.h>
11 #include <linux/mfd/syscon.h>
12 #include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
13 #include <linux/module.h>
14 #include <linux/phy/phy.h>
15 #include <linux/platform_device.h>
16 #include <linux/regmap.h>
17 #include <linux/reset.h>
18
19 #include <dt-bindings/phy/phy-imx8-pcie.h>
20
21 #define IMX8MM_PCIE_PHY_CMN_REG061      0x184
22 #define  ANA_PLL_CLK_OUT_TO_EXT_IO_EN   BIT(0)
23 #define IMX8MM_PCIE_PHY_CMN_REG062      0x188
24 #define  ANA_PLL_CLK_OUT_TO_EXT_IO_SEL  BIT(3)
25 #define IMX8MM_PCIE_PHY_CMN_REG063      0x18C
26 #define  AUX_PLL_REFCLK_SEL_SYS_PLL     GENMASK(7, 6)
27 #define IMX8MM_PCIE_PHY_CMN_REG064      0x190
28 #define  ANA_AUX_RX_TX_SEL_TX           BIT(7)
29 #define  ANA_AUX_RX_TERM_GND_EN         BIT(3)
30 #define  ANA_AUX_TX_TERM                BIT(2)
31 #define IMX8MM_PCIE_PHY_CMN_REG065      0x194
32 #define  ANA_AUX_RX_TERM                (BIT(7) | BIT(4))
33 #define  ANA_AUX_TX_LVL                 GENMASK(3, 0)
34 #define IMX8MM_PCIE_PHY_CMN_REG75       0x1D4
35 #define  PCIE_PHY_CMN_REG75_PLL_DONE    0x3
36 #define PCIE_PHY_TRSV_REG5              0x414
37 #define  PCIE_PHY_TRSV_REG5_GEN1_DEEMP  0x2D
38 #define PCIE_PHY_TRSV_REG6              0x418
39 #define  PCIE_PHY_TRSV_REG6_GEN2_DEEMP  0xF
40
41 #define IMX8MM_GPR_PCIE_REF_CLK_SEL     GENMASK(25, 24)
42 #define IMX8MM_GPR_PCIE_REF_CLK_PLL     FIELD_PREP(IMX8MM_GPR_PCIE_REF_CLK_SEL, 0x3)
43 #define IMX8MM_GPR_PCIE_REF_CLK_EXT     FIELD_PREP(IMX8MM_GPR_PCIE_REF_CLK_SEL, 0x2)
44 #define IMX8MM_GPR_PCIE_AUX_EN          BIT(19)
45 #define IMX8MM_GPR_PCIE_CMN_RST         BIT(18)
46 #define IMX8MM_GPR_PCIE_POWER_OFF       BIT(17)
47 #define IMX8MM_GPR_PCIE_SSC_EN          BIT(16)
48 #define IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE BIT(9)
49
50 struct imx8_pcie_phy {
51         void __iomem            *base;
52         struct clk              *clk;
53         struct phy              *phy;
54         struct regmap           *iomuxc_gpr;
55         struct reset_control    *reset;
56         u32                     refclk_pad_mode;
57         u32                     tx_deemph_gen1;
58         u32                     tx_deemph_gen2;
59         bool                    clkreq_unused;
60 };
61
62 static int imx8_pcie_phy_init(struct phy *phy)
63 {
64         int ret;
65         u32 val, pad_mode;
66         struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
67
68         reset_control_assert(imx8_phy->reset);
69
70         pad_mode = imx8_phy->refclk_pad_mode;
71         /* Set AUX_EN_OVERRIDE 1'b0, when the CLKREQ# isn't hooked */
72         regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
73                            IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE,
74                            imx8_phy->clkreq_unused ?
75                            0 : IMX8MM_GPR_PCIE_AUX_EN_OVERRIDE);
76         regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
77                            IMX8MM_GPR_PCIE_AUX_EN,
78                            IMX8MM_GPR_PCIE_AUX_EN);
79         regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
80                            IMX8MM_GPR_PCIE_POWER_OFF, 0);
81         regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
82                            IMX8MM_GPR_PCIE_SSC_EN, 0);
83
84         regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
85                            IMX8MM_GPR_PCIE_REF_CLK_SEL,
86                            pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ?
87                            IMX8MM_GPR_PCIE_REF_CLK_EXT :
88                            IMX8MM_GPR_PCIE_REF_CLK_PLL);
89         usleep_range(100, 200);
90
91         /* Do the PHY common block reset */
92         regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
93                            IMX8MM_GPR_PCIE_CMN_RST,
94                            IMX8MM_GPR_PCIE_CMN_RST);
95         usleep_range(200, 500);
96
97         if (pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ||
98             pad_mode == IMX8_PCIE_REFCLK_PAD_UNUSED) {
99                 /* Configure the pad as input */
100                 val = readl(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
101                 writel(val & ~ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
102                        imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
103         } else {
104                 /* Configure the PHY to output the refclock via pad */
105                 writel(ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
106                        imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
107         }
108
109         if (pad_mode == IMX8_PCIE_REFCLK_PAD_OUTPUT ||
110             pad_mode == IMX8_PCIE_REFCLK_PAD_UNUSED) {
111                 /* Source clock from SoC internal PLL */
112                 writel(ANA_PLL_CLK_OUT_TO_EXT_IO_SEL,
113                        imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG062);
114                 writel(AUX_PLL_REFCLK_SEL_SYS_PLL,
115                        imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG063);
116                 val = ANA_AUX_RX_TX_SEL_TX | ANA_AUX_TX_TERM;
117                 writel(val | ANA_AUX_RX_TERM_GND_EN,
118                        imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG064);
119                 writel(ANA_AUX_RX_TERM | ANA_AUX_TX_LVL,
120                        imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG065);
121         }
122
123         /* Tune PHY de-emphasis setting to pass PCIe compliance. */
124         if (imx8_phy->tx_deemph_gen1)
125                 writel(imx8_phy->tx_deemph_gen1,
126                        imx8_phy->base + PCIE_PHY_TRSV_REG5);
127         if (imx8_phy->tx_deemph_gen2)
128                 writel(imx8_phy->tx_deemph_gen2,
129                        imx8_phy->base + PCIE_PHY_TRSV_REG6);
130
131         reset_control_deassert(imx8_phy->reset);
132
133         /* Polling to check the phy is ready or not. */
134         ret = readl_poll_timeout(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG75,
135                                  val, val == PCIE_PHY_CMN_REG75_PLL_DONE,
136                                  10, 20000);
137         return ret;
138 }
139
140 static int imx8_pcie_phy_power_on(struct phy *phy)
141 {
142         struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
143
144         return clk_prepare_enable(imx8_phy->clk);
145 }
146
147 static int imx8_pcie_phy_power_off(struct phy *phy)
148 {
149         struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
150
151         clk_disable_unprepare(imx8_phy->clk);
152
153         return 0;
154 }
155
156 static const struct phy_ops imx8_pcie_phy_ops = {
157         .init           = imx8_pcie_phy_init,
158         .power_on       = imx8_pcie_phy_power_on,
159         .power_off      = imx8_pcie_phy_power_off,
160         .owner          = THIS_MODULE,
161 };
162
163 static int imx8_pcie_phy_probe(struct platform_device *pdev)
164 {
165         struct phy_provider *phy_provider;
166         struct device *dev = &pdev->dev;
167         struct device_node *np = dev->of_node;
168         struct imx8_pcie_phy *imx8_phy;
169         struct resource *res;
170
171         imx8_phy = devm_kzalloc(dev, sizeof(*imx8_phy), GFP_KERNEL);
172         if (!imx8_phy)
173                 return -ENOMEM;
174
175         /* get PHY refclk pad mode */
176         of_property_read_u32(np, "fsl,refclk-pad-mode",
177                              &imx8_phy->refclk_pad_mode);
178
179         if (of_property_read_u32(np, "fsl,tx-deemph-gen1",
180                                  &imx8_phy->tx_deemph_gen1))
181                 imx8_phy->tx_deemph_gen1 = 0;
182
183         if (of_property_read_u32(np, "fsl,tx-deemph-gen2",
184                                  &imx8_phy->tx_deemph_gen2))
185                 imx8_phy->tx_deemph_gen2 = 0;
186
187         if (of_property_read_bool(np, "fsl,clkreq-unsupported"))
188                 imx8_phy->clkreq_unused = true;
189         else
190                 imx8_phy->clkreq_unused = false;
191
192         imx8_phy->clk = devm_clk_get(dev, "ref");
193         if (IS_ERR(imx8_phy->clk)) {
194                 dev_err(dev, "failed to get imx pcie phy clock\n");
195                 return PTR_ERR(imx8_phy->clk);
196         }
197
198         /* Grab GPR config register range */
199         imx8_phy->iomuxc_gpr =
200                  syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
201         if (IS_ERR(imx8_phy->iomuxc_gpr)) {
202                 dev_err(dev, "unable to find iomuxc registers\n");
203                 return PTR_ERR(imx8_phy->iomuxc_gpr);
204         }
205
206         imx8_phy->reset = devm_reset_control_get_exclusive(dev, "pciephy");
207         if (IS_ERR(imx8_phy->reset)) {
208                 dev_err(dev, "Failed to get PCIEPHY reset control\n");
209                 return PTR_ERR(imx8_phy->reset);
210         }
211
212         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
213         imx8_phy->base = devm_ioremap_resource(dev, res);
214         if (IS_ERR(imx8_phy->base))
215                 return PTR_ERR(imx8_phy->base);
216
217         imx8_phy->phy = devm_phy_create(dev, NULL, &imx8_pcie_phy_ops);
218         if (IS_ERR(imx8_phy->phy))
219                 return PTR_ERR(imx8_phy->phy);
220
221         phy_set_drvdata(imx8_phy->phy, imx8_phy);
222
223         phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
224
225         return PTR_ERR_OR_ZERO(phy_provider);
226 }
227
228 static const struct of_device_id imx8_pcie_phy_of_match[] = {
229         {.compatible = "fsl,imx8mm-pcie-phy",},
230         { },
231 };
232 MODULE_DEVICE_TABLE(of, imx8_pcie_phy_of_match);
233
234 static struct platform_driver imx8_pcie_phy_driver = {
235         .probe  = imx8_pcie_phy_probe,
236         .driver = {
237                 .name   = "imx8-pcie-phy",
238                 .of_match_table = imx8_pcie_phy_of_match,
239         }
240 };
241 module_platform_driver(imx8_pcie_phy_driver);
242
243 MODULE_DESCRIPTION("FSL IMX8 PCIE PHY driver");
244 MODULE_LICENSE("GPL v2");