1 // SPDX-License-Identifier: GPL-2.0
3 * phy-uniphier-pcie.c - PHY driver for UniPhier PCIe controller
4 * Copyright 2018, Socionext Inc.
5 * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
8 #include <linux/bitops.h>
9 #include <linux/bitfield.h>
10 #include <linux/clk.h>
11 #include <linux/iopoll.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
14 #include <linux/of_device.h>
15 #include <linux/phy/phy.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/reset.h>
19 #include <linux/resource.h>
22 #define PCL_PHY_CLKCTRL 0x0000
23 #define PORT_SEL_MASK GENMASK(11, 9)
24 #define PORT_SEL_1 FIELD_PREP(PORT_SEL_MASK, 1)
26 #define PCL_PHY_TEST_I 0x2000
27 #define PCL_PHY_TEST_O 0x2004
28 #define TESTI_DAT_MASK GENMASK(13, 6)
29 #define TESTI_ADR_MASK GENMASK(5, 1)
30 #define TESTI_WR_EN BIT(0)
32 #define PCL_PHY_RESET 0x200c
33 #define PCL_PHY_RESET_N_MNMODE BIT(8) /* =1:manual */
34 #define PCL_PHY_RESET_N BIT(0) /* =1:deasssert */
37 #define SG_USBPCIESEL 0x590
38 #define SG_USBPCIESEL_PCIE BIT(0)
41 #define RX_EQ_ADJ_EN BIT(3) /* enable for EQ adjustment */
43 #define RX_EQ_ADJ GENMASK(5, 0) /* EQ adjustment value */
44 #define RX_EQ_ADJ_VAL 0
45 #define PCL_PHY_R26 26
46 #define VCO_CTRL GENMASK(7, 4) /* Tx VCO adjustment value */
47 #define VCO_CTRL_INIT_VAL 5
49 struct uniphier_pciephy_priv
{
52 struct clk
*clk
, *clk_gio
;
53 struct reset_control
*rst
, *rst_gio
;
54 const struct uniphier_pciephy_soc_data
*data
;
57 struct uniphier_pciephy_soc_data
{
59 void (*set_phymode
)(struct regmap
*regmap
);
62 static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv
*priv
,
65 /* need to read TESTO twice after accessing TESTI */
66 writel(data
, priv
->base
+ PCL_PHY_TEST_I
);
67 readl(priv
->base
+ PCL_PHY_TEST_O
);
68 readl(priv
->base
+ PCL_PHY_TEST_O
);
71 static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv
*priv
,
72 u32 reg
, u32 mask
, u32 param
)
76 /* read previous data */
77 val
= FIELD_PREP(TESTI_DAT_MASK
, 1);
78 val
|= FIELD_PREP(TESTI_ADR_MASK
, reg
);
79 uniphier_pciephy_testio_write(priv
, val
);
80 val
= readl(priv
->base
+ PCL_PHY_TEST_O
);
83 val
&= ~FIELD_PREP(TESTI_DAT_MASK
, mask
);
84 val
= FIELD_PREP(TESTI_DAT_MASK
, mask
& param
);
85 val
|= FIELD_PREP(TESTI_ADR_MASK
, reg
);
86 uniphier_pciephy_testio_write(priv
, val
);
87 uniphier_pciephy_testio_write(priv
, val
| TESTI_WR_EN
);
88 uniphier_pciephy_testio_write(priv
, val
);
90 /* read current data as dummy */
91 val
= FIELD_PREP(TESTI_DAT_MASK
, 1);
92 val
|= FIELD_PREP(TESTI_ADR_MASK
, reg
);
93 uniphier_pciephy_testio_write(priv
, val
);
94 readl(priv
->base
+ PCL_PHY_TEST_O
);
97 static void uniphier_pciephy_assert(struct uniphier_pciephy_priv
*priv
)
101 val
= readl(priv
->base
+ PCL_PHY_RESET
);
102 val
&= ~PCL_PHY_RESET_N
;
103 val
|= PCL_PHY_RESET_N_MNMODE
;
104 writel(val
, priv
->base
+ PCL_PHY_RESET
);
107 static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv
*priv
)
111 val
= readl(priv
->base
+ PCL_PHY_RESET
);
112 val
|= PCL_PHY_RESET_N_MNMODE
| PCL_PHY_RESET_N
;
113 writel(val
, priv
->base
+ PCL_PHY_RESET
);
116 static int uniphier_pciephy_init(struct phy
*phy
)
118 struct uniphier_pciephy_priv
*priv
= phy_get_drvdata(phy
);
122 ret
= clk_prepare_enable(priv
->clk
);
126 ret
= clk_prepare_enable(priv
->clk_gio
);
128 goto out_clk_disable
;
130 ret
= reset_control_deassert(priv
->rst
);
132 goto out_clk_gio_disable
;
134 ret
= reset_control_deassert(priv
->rst_gio
);
138 /* support only 1 port */
139 val
= readl(priv
->base
+ PCL_PHY_CLKCTRL
);
140 val
&= ~PORT_SEL_MASK
;
142 writel(val
, priv
->base
+ PCL_PHY_CLKCTRL
);
144 /* legacy controller doesn't have phy_reset and parameters */
145 if (priv
->data
->is_legacy
)
148 uniphier_pciephy_set_param(priv
, PCL_PHY_R00
,
149 RX_EQ_ADJ_EN
, RX_EQ_ADJ_EN
);
150 uniphier_pciephy_set_param(priv
, PCL_PHY_R06
, RX_EQ_ADJ
,
151 FIELD_PREP(RX_EQ_ADJ
, RX_EQ_ADJ_VAL
));
152 uniphier_pciephy_set_param(priv
, PCL_PHY_R26
, VCO_CTRL
,
153 FIELD_PREP(VCO_CTRL
, VCO_CTRL_INIT_VAL
));
156 uniphier_pciephy_deassert(priv
);
162 reset_control_assert(priv
->rst
);
164 clk_disable_unprepare(priv
->clk_gio
);
166 clk_disable_unprepare(priv
->clk
);
171 static int uniphier_pciephy_exit(struct phy
*phy
)
173 struct uniphier_pciephy_priv
*priv
= phy_get_drvdata(phy
);
175 if (!priv
->data
->is_legacy
)
176 uniphier_pciephy_assert(priv
);
177 reset_control_assert(priv
->rst_gio
);
178 reset_control_assert(priv
->rst
);
179 clk_disable_unprepare(priv
->clk_gio
);
180 clk_disable_unprepare(priv
->clk
);
185 static const struct phy_ops uniphier_pciephy_ops
= {
186 .init
= uniphier_pciephy_init
,
187 .exit
= uniphier_pciephy_exit
,
188 .owner
= THIS_MODULE
,
191 static int uniphier_pciephy_probe(struct platform_device
*pdev
)
193 struct uniphier_pciephy_priv
*priv
;
194 struct phy_provider
*phy_provider
;
195 struct device
*dev
= &pdev
->dev
;
196 struct regmap
*regmap
;
199 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
203 priv
->data
= of_device_get_match_data(dev
);
204 if (WARN_ON(!priv
->data
))
209 priv
->base
= devm_platform_ioremap_resource(pdev
, 0);
210 if (IS_ERR(priv
->base
))
211 return PTR_ERR(priv
->base
);
213 if (priv
->data
->is_legacy
) {
214 priv
->clk_gio
= devm_clk_get(dev
, "gio");
215 if (IS_ERR(priv
->clk_gio
))
216 return PTR_ERR(priv
->clk_gio
);
219 devm_reset_control_get_shared(dev
, "gio");
220 if (IS_ERR(priv
->rst_gio
))
221 return PTR_ERR(priv
->rst_gio
);
223 priv
->clk
= devm_clk_get(dev
, "link");
224 if (IS_ERR(priv
->clk
))
225 return PTR_ERR(priv
->clk
);
227 priv
->rst
= devm_reset_control_get_shared(dev
, "link");
228 if (IS_ERR(priv
->rst
))
229 return PTR_ERR(priv
->rst
);
231 priv
->clk
= devm_clk_get(dev
, NULL
);
232 if (IS_ERR(priv
->clk
))
233 return PTR_ERR(priv
->clk
);
235 priv
->rst
= devm_reset_control_get_shared(dev
, NULL
);
236 if (IS_ERR(priv
->rst
))
237 return PTR_ERR(priv
->rst
);
240 phy
= devm_phy_create(dev
, dev
->of_node
, &uniphier_pciephy_ops
);
244 regmap
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
246 if (!IS_ERR(regmap
) && priv
->data
->set_phymode
)
247 priv
->data
->set_phymode(regmap
);
249 phy_set_drvdata(phy
, priv
);
250 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
252 return PTR_ERR_OR_ZERO(phy_provider
);
255 static void uniphier_pciephy_ld20_setmode(struct regmap
*regmap
)
257 regmap_update_bits(regmap
, SG_USBPCIESEL
,
258 SG_USBPCIESEL_PCIE
, SG_USBPCIESEL_PCIE
);
261 static const struct uniphier_pciephy_soc_data uniphier_pro5_data
= {
265 static const struct uniphier_pciephy_soc_data uniphier_ld20_data
= {
267 .set_phymode
= uniphier_pciephy_ld20_setmode
,
270 static const struct uniphier_pciephy_soc_data uniphier_pxs3_data
= {
274 static const struct of_device_id uniphier_pciephy_match
[] = {
276 .compatible
= "socionext,uniphier-pro5-pcie-phy",
277 .data
= &uniphier_pro5_data
,
280 .compatible
= "socionext,uniphier-ld20-pcie-phy",
281 .data
= &uniphier_ld20_data
,
284 .compatible
= "socionext,uniphier-pxs3-pcie-phy",
285 .data
= &uniphier_pxs3_data
,
289 MODULE_DEVICE_TABLE(of
, uniphier_pciephy_match
);
291 static struct platform_driver uniphier_pciephy_driver
= {
292 .probe
= uniphier_pciephy_probe
,
294 .name
= "uniphier-pcie-phy",
295 .of_match_table
= uniphier_pciephy_match
,
298 module_platform_driver(uniphier_pciephy_driver
);
300 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
301 MODULE_DESCRIPTION("UniPhier PHY driver for PCIe controller");
302 MODULE_LICENSE("GPL v2");