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_TEST_I 0x2000
23 #define PCL_PHY_TEST_O 0x2004
24 #define TESTI_DAT_MASK GENMASK(13, 6)
25 #define TESTI_ADR_MASK GENMASK(5, 1)
26 #define TESTI_WR_EN BIT(0)
28 #define PCL_PHY_RESET 0x200c
29 #define PCL_PHY_RESET_N_MNMODE BIT(8) /* =1:manual */
30 #define PCL_PHY_RESET_N BIT(0) /* =1:deasssert */
33 #define SG_USBPCIESEL 0x590
34 #define SG_USBPCIESEL_PCIE BIT(0)
37 #define RX_EQ_ADJ_EN BIT(3) /* enable for EQ adjustment */
39 #define RX_EQ_ADJ GENMASK(5, 0) /* EQ adjustment value */
40 #define RX_EQ_ADJ_VAL 0
41 #define PCL_PHY_R26 26
42 #define VCO_CTRL GENMASK(7, 4) /* Tx VCO adjustment value */
43 #define VCO_CTRL_INIT_VAL 5
45 struct uniphier_pciephy_priv
{
49 struct reset_control
*rst
;
50 const struct uniphier_pciephy_soc_data
*data
;
53 struct uniphier_pciephy_soc_data
{
57 static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv
*priv
,
60 /* need to read TESTO twice after accessing TESTI */
61 writel(data
, priv
->base
+ PCL_PHY_TEST_I
);
62 readl(priv
->base
+ PCL_PHY_TEST_O
);
63 readl(priv
->base
+ PCL_PHY_TEST_O
);
66 static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv
*priv
,
67 u32 reg
, u32 mask
, u32 param
)
71 /* read previous data */
72 val
= FIELD_PREP(TESTI_DAT_MASK
, 1);
73 val
|= FIELD_PREP(TESTI_ADR_MASK
, reg
);
74 uniphier_pciephy_testio_write(priv
, val
);
75 val
= readl(priv
->base
+ PCL_PHY_TEST_O
);
78 val
&= ~FIELD_PREP(TESTI_DAT_MASK
, mask
);
79 val
= FIELD_PREP(TESTI_DAT_MASK
, mask
& param
);
80 val
|= FIELD_PREP(TESTI_ADR_MASK
, reg
);
81 uniphier_pciephy_testio_write(priv
, val
);
82 uniphier_pciephy_testio_write(priv
, val
| TESTI_WR_EN
);
83 uniphier_pciephy_testio_write(priv
, val
);
85 /* read current data as dummy */
86 val
= FIELD_PREP(TESTI_DAT_MASK
, 1);
87 val
|= FIELD_PREP(TESTI_ADR_MASK
, reg
);
88 uniphier_pciephy_testio_write(priv
, val
);
89 readl(priv
->base
+ PCL_PHY_TEST_O
);
92 static void uniphier_pciephy_assert(struct uniphier_pciephy_priv
*priv
)
96 val
= readl(priv
->base
+ PCL_PHY_RESET
);
97 val
&= ~PCL_PHY_RESET_N
;
98 val
|= PCL_PHY_RESET_N_MNMODE
;
99 writel(val
, priv
->base
+ PCL_PHY_RESET
);
102 static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv
*priv
)
106 val
= readl(priv
->base
+ PCL_PHY_RESET
);
107 val
|= PCL_PHY_RESET_N_MNMODE
| PCL_PHY_RESET_N
;
108 writel(val
, priv
->base
+ PCL_PHY_RESET
);
111 static int uniphier_pciephy_init(struct phy
*phy
)
113 struct uniphier_pciephy_priv
*priv
= phy_get_drvdata(phy
);
116 ret
= clk_prepare_enable(priv
->clk
);
120 ret
= reset_control_deassert(priv
->rst
);
122 goto out_clk_disable
;
124 uniphier_pciephy_set_param(priv
, PCL_PHY_R00
,
125 RX_EQ_ADJ_EN
, RX_EQ_ADJ_EN
);
126 uniphier_pciephy_set_param(priv
, PCL_PHY_R06
, RX_EQ_ADJ
,
127 FIELD_PREP(RX_EQ_ADJ
, RX_EQ_ADJ_VAL
));
128 uniphier_pciephy_set_param(priv
, PCL_PHY_R26
, VCO_CTRL
,
129 FIELD_PREP(VCO_CTRL
, VCO_CTRL_INIT_VAL
));
132 uniphier_pciephy_deassert(priv
);
138 clk_disable_unprepare(priv
->clk
);
143 static int uniphier_pciephy_exit(struct phy
*phy
)
145 struct uniphier_pciephy_priv
*priv
= phy_get_drvdata(phy
);
147 uniphier_pciephy_assert(priv
);
148 reset_control_assert(priv
->rst
);
149 clk_disable_unprepare(priv
->clk
);
154 static const struct phy_ops uniphier_pciephy_ops
= {
155 .init
= uniphier_pciephy_init
,
156 .exit
= uniphier_pciephy_exit
,
157 .owner
= THIS_MODULE
,
160 static int uniphier_pciephy_probe(struct platform_device
*pdev
)
162 struct uniphier_pciephy_priv
*priv
;
163 struct phy_provider
*phy_provider
;
164 struct device
*dev
= &pdev
->dev
;
165 struct regmap
*regmap
;
166 struct resource
*res
;
169 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
173 priv
->data
= of_device_get_match_data(dev
);
174 if (WARN_ON(!priv
->data
))
179 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
180 priv
->base
= devm_ioremap_resource(dev
, res
);
181 if (IS_ERR(priv
->base
))
182 return PTR_ERR(priv
->base
);
184 priv
->clk
= devm_clk_get(dev
, NULL
);
185 if (IS_ERR(priv
->clk
))
186 return PTR_ERR(priv
->clk
);
188 priv
->rst
= devm_reset_control_get_shared(dev
, NULL
);
189 if (IS_ERR(priv
->rst
))
190 return PTR_ERR(priv
->rst
);
192 phy
= devm_phy_create(dev
, dev
->of_node
, &uniphier_pciephy_ops
);
196 regmap
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
198 if (!IS_ERR(regmap
) && priv
->data
->has_syscon
)
199 regmap_update_bits(regmap
, SG_USBPCIESEL
,
200 SG_USBPCIESEL_PCIE
, SG_USBPCIESEL_PCIE
);
202 phy_set_drvdata(phy
, priv
);
203 phy_provider
= devm_of_phy_provider_register(dev
, of_phy_simple_xlate
);
205 return PTR_ERR_OR_ZERO(phy_provider
);
208 static const struct uniphier_pciephy_soc_data uniphier_ld20_data
= {
212 static const struct uniphier_pciephy_soc_data uniphier_pxs3_data
= {
216 static const struct of_device_id uniphier_pciephy_match
[] = {
218 .compatible
= "socionext,uniphier-ld20-pcie-phy",
219 .data
= &uniphier_ld20_data
,
222 .compatible
= "socionext,uniphier-pxs3-pcie-phy",
223 .data
= &uniphier_pxs3_data
,
227 MODULE_DEVICE_TABLE(of
, uniphier_pciephy_match
);
229 static struct platform_driver uniphier_pciephy_driver
= {
230 .probe
= uniphier_pciephy_probe
,
232 .name
= "uniphier-pcie-phy",
233 .of_match_table
= uniphier_pciephy_match
,
236 module_platform_driver(uniphier_pciephy_driver
);
238 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
239 MODULE_DESCRIPTION("UniPhier PHY driver for PCIe controller");
240 MODULE_LICENSE("GPL v2");