xref: /linux/drivers/phy/socionext/phy-uniphier-pcie.c (revision c6d9b132415951a8e8025a5b0e7f6b805737528c)
1*c6d9b132SKunihiko Hayashi // SPDX-License-Identifier: GPL-2.0
2*c6d9b132SKunihiko Hayashi /*
3*c6d9b132SKunihiko Hayashi  * phy-uniphier-pcie.c - PHY driver for UniPhier PCIe controller
4*c6d9b132SKunihiko Hayashi  * Copyright 2018, Socionext Inc.
5*c6d9b132SKunihiko Hayashi  * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
6*c6d9b132SKunihiko Hayashi  */
7*c6d9b132SKunihiko Hayashi 
8*c6d9b132SKunihiko Hayashi #include <linux/bitops.h>
9*c6d9b132SKunihiko Hayashi #include <linux/bitfield.h>
10*c6d9b132SKunihiko Hayashi #include <linux/clk.h>
11*c6d9b132SKunihiko Hayashi #include <linux/iopoll.h>
12*c6d9b132SKunihiko Hayashi #include <linux/mfd/syscon.h>
13*c6d9b132SKunihiko Hayashi #include <linux/module.h>
14*c6d9b132SKunihiko Hayashi #include <linux/of_device.h>
15*c6d9b132SKunihiko Hayashi #include <linux/phy/phy.h>
16*c6d9b132SKunihiko Hayashi #include <linux/platform_device.h>
17*c6d9b132SKunihiko Hayashi #include <linux/regmap.h>
18*c6d9b132SKunihiko Hayashi #include <linux/reset.h>
19*c6d9b132SKunihiko Hayashi #include <linux/resource.h>
20*c6d9b132SKunihiko Hayashi 
21*c6d9b132SKunihiko Hayashi /* PHY */
22*c6d9b132SKunihiko Hayashi #define PCL_PHY_TEST_I		0x2000
23*c6d9b132SKunihiko Hayashi #define PCL_PHY_TEST_O		0x2004
24*c6d9b132SKunihiko Hayashi #define TESTI_DAT_MASK		GENMASK(13, 6)
25*c6d9b132SKunihiko Hayashi #define TESTI_ADR_MASK		GENMASK(5, 1)
26*c6d9b132SKunihiko Hayashi #define TESTI_WR_EN		BIT(0)
27*c6d9b132SKunihiko Hayashi 
28*c6d9b132SKunihiko Hayashi #define PCL_PHY_RESET		0x200c
29*c6d9b132SKunihiko Hayashi #define PCL_PHY_RESET_N_MNMODE	BIT(8)	/* =1:manual */
30*c6d9b132SKunihiko Hayashi #define PCL_PHY_RESET_N		BIT(0)	/* =1:deasssert */
31*c6d9b132SKunihiko Hayashi 
32*c6d9b132SKunihiko Hayashi /* SG */
33*c6d9b132SKunihiko Hayashi #define SG_USBPCIESEL		0x590
34*c6d9b132SKunihiko Hayashi #define SG_USBPCIESEL_PCIE	BIT(0)
35*c6d9b132SKunihiko Hayashi 
36*c6d9b132SKunihiko Hayashi #define PCL_PHY_R00		0
37*c6d9b132SKunihiko Hayashi #define   RX_EQ_ADJ_EN		BIT(3)		/* enable for EQ adjustment */
38*c6d9b132SKunihiko Hayashi #define PCL_PHY_R06		6
39*c6d9b132SKunihiko Hayashi #define   RX_EQ_ADJ		GENMASK(5, 0)	/* EQ adjustment value */
40*c6d9b132SKunihiko Hayashi #define   RX_EQ_ADJ_VAL		0
41*c6d9b132SKunihiko Hayashi #define PCL_PHY_R26		26
42*c6d9b132SKunihiko Hayashi #define   VCO_CTRL		GENMASK(7, 4)	/* Tx VCO adjustment value */
43*c6d9b132SKunihiko Hayashi #define   VCO_CTRL_INIT_VAL	5
44*c6d9b132SKunihiko Hayashi 
45*c6d9b132SKunihiko Hayashi struct uniphier_pciephy_priv {
46*c6d9b132SKunihiko Hayashi 	void __iomem *base;
47*c6d9b132SKunihiko Hayashi 	struct device *dev;
48*c6d9b132SKunihiko Hayashi 	struct clk *clk;
49*c6d9b132SKunihiko Hayashi 	struct reset_control *rst;
50*c6d9b132SKunihiko Hayashi 	const struct uniphier_pciephy_soc_data *data;
51*c6d9b132SKunihiko Hayashi };
52*c6d9b132SKunihiko Hayashi 
53*c6d9b132SKunihiko Hayashi struct uniphier_pciephy_soc_data {
54*c6d9b132SKunihiko Hayashi 	bool has_syscon;
55*c6d9b132SKunihiko Hayashi };
56*c6d9b132SKunihiko Hayashi 
57*c6d9b132SKunihiko Hayashi static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv,
58*c6d9b132SKunihiko Hayashi 					  u32 data)
59*c6d9b132SKunihiko Hayashi {
60*c6d9b132SKunihiko Hayashi 	/* need to read TESTO twice after accessing TESTI */
61*c6d9b132SKunihiko Hayashi 	writel(data, priv->base + PCL_PHY_TEST_I);
62*c6d9b132SKunihiko Hayashi 	readl(priv->base + PCL_PHY_TEST_O);
63*c6d9b132SKunihiko Hayashi 	readl(priv->base + PCL_PHY_TEST_O);
64*c6d9b132SKunihiko Hayashi }
65*c6d9b132SKunihiko Hayashi 
66*c6d9b132SKunihiko Hayashi static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv *priv,
67*c6d9b132SKunihiko Hayashi 				       u32 reg, u32 mask, u32 param)
68*c6d9b132SKunihiko Hayashi {
69*c6d9b132SKunihiko Hayashi 	u32 val;
70*c6d9b132SKunihiko Hayashi 
71*c6d9b132SKunihiko Hayashi 	/* read previous data */
72*c6d9b132SKunihiko Hayashi 	val  = FIELD_PREP(TESTI_DAT_MASK, 1);
73*c6d9b132SKunihiko Hayashi 	val |= FIELD_PREP(TESTI_ADR_MASK, reg);
74*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_testio_write(priv, val);
75*c6d9b132SKunihiko Hayashi 	val = readl(priv->base + PCL_PHY_TEST_O);
76*c6d9b132SKunihiko Hayashi 
77*c6d9b132SKunihiko Hayashi 	/* update value */
78*c6d9b132SKunihiko Hayashi 	val &= ~FIELD_PREP(TESTI_DAT_MASK, mask);
79*c6d9b132SKunihiko Hayashi 	val  = FIELD_PREP(TESTI_DAT_MASK, mask & param);
80*c6d9b132SKunihiko Hayashi 	val |= FIELD_PREP(TESTI_ADR_MASK, reg);
81*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_testio_write(priv, val);
82*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_testio_write(priv, val | TESTI_WR_EN);
83*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_testio_write(priv, val);
84*c6d9b132SKunihiko Hayashi 
85*c6d9b132SKunihiko Hayashi 	/* read current data as dummy */
86*c6d9b132SKunihiko Hayashi 	val  = FIELD_PREP(TESTI_DAT_MASK, 1);
87*c6d9b132SKunihiko Hayashi 	val |= FIELD_PREP(TESTI_ADR_MASK, reg);
88*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_testio_write(priv, val);
89*c6d9b132SKunihiko Hayashi 	readl(priv->base + PCL_PHY_TEST_O);
90*c6d9b132SKunihiko Hayashi }
91*c6d9b132SKunihiko Hayashi 
92*c6d9b132SKunihiko Hayashi static void uniphier_pciephy_assert(struct uniphier_pciephy_priv *priv)
93*c6d9b132SKunihiko Hayashi {
94*c6d9b132SKunihiko Hayashi 	u32 val;
95*c6d9b132SKunihiko Hayashi 
96*c6d9b132SKunihiko Hayashi 	val = readl(priv->base + PCL_PHY_RESET);
97*c6d9b132SKunihiko Hayashi 	val &= ~PCL_PHY_RESET_N;
98*c6d9b132SKunihiko Hayashi 	val |= PCL_PHY_RESET_N_MNMODE;
99*c6d9b132SKunihiko Hayashi 	writel(val, priv->base + PCL_PHY_RESET);
100*c6d9b132SKunihiko Hayashi }
101*c6d9b132SKunihiko Hayashi 
102*c6d9b132SKunihiko Hayashi static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv *priv)
103*c6d9b132SKunihiko Hayashi {
104*c6d9b132SKunihiko Hayashi 	u32 val;
105*c6d9b132SKunihiko Hayashi 
106*c6d9b132SKunihiko Hayashi 	val = readl(priv->base + PCL_PHY_RESET);
107*c6d9b132SKunihiko Hayashi 	val |= PCL_PHY_RESET_N_MNMODE | PCL_PHY_RESET_N;
108*c6d9b132SKunihiko Hayashi 	writel(val, priv->base + PCL_PHY_RESET);
109*c6d9b132SKunihiko Hayashi }
110*c6d9b132SKunihiko Hayashi 
111*c6d9b132SKunihiko Hayashi static int uniphier_pciephy_init(struct phy *phy)
112*c6d9b132SKunihiko Hayashi {
113*c6d9b132SKunihiko Hayashi 	struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
114*c6d9b132SKunihiko Hayashi 	int ret;
115*c6d9b132SKunihiko Hayashi 
116*c6d9b132SKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk);
117*c6d9b132SKunihiko Hayashi 	if (ret)
118*c6d9b132SKunihiko Hayashi 		return ret;
119*c6d9b132SKunihiko Hayashi 
120*c6d9b132SKunihiko Hayashi 	ret = reset_control_deassert(priv->rst);
121*c6d9b132SKunihiko Hayashi 	if (ret)
122*c6d9b132SKunihiko Hayashi 		goto out_clk_disable;
123*c6d9b132SKunihiko Hayashi 
124*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_set_param(priv, PCL_PHY_R00,
125*c6d9b132SKunihiko Hayashi 				   RX_EQ_ADJ_EN, RX_EQ_ADJ_EN);
126*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ,
127*c6d9b132SKunihiko Hayashi 				   FIELD_PREP(RX_EQ_ADJ, RX_EQ_ADJ_VAL));
128*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_set_param(priv, PCL_PHY_R26, VCO_CTRL,
129*c6d9b132SKunihiko Hayashi 				   FIELD_PREP(VCO_CTRL, VCO_CTRL_INIT_VAL));
130*c6d9b132SKunihiko Hayashi 	usleep_range(1, 10);
131*c6d9b132SKunihiko Hayashi 
132*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_deassert(priv);
133*c6d9b132SKunihiko Hayashi 	usleep_range(1, 10);
134*c6d9b132SKunihiko Hayashi 
135*c6d9b132SKunihiko Hayashi 	return 0;
136*c6d9b132SKunihiko Hayashi 
137*c6d9b132SKunihiko Hayashi out_clk_disable:
138*c6d9b132SKunihiko Hayashi 	clk_disable_unprepare(priv->clk);
139*c6d9b132SKunihiko Hayashi 
140*c6d9b132SKunihiko Hayashi 	return ret;
141*c6d9b132SKunihiko Hayashi }
142*c6d9b132SKunihiko Hayashi 
143*c6d9b132SKunihiko Hayashi static int uniphier_pciephy_exit(struct phy *phy)
144*c6d9b132SKunihiko Hayashi {
145*c6d9b132SKunihiko Hayashi 	struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
146*c6d9b132SKunihiko Hayashi 
147*c6d9b132SKunihiko Hayashi 	uniphier_pciephy_assert(priv);
148*c6d9b132SKunihiko Hayashi 	reset_control_assert(priv->rst);
149*c6d9b132SKunihiko Hayashi 	clk_disable_unprepare(priv->clk);
150*c6d9b132SKunihiko Hayashi 
151*c6d9b132SKunihiko Hayashi 	return 0;
152*c6d9b132SKunihiko Hayashi }
153*c6d9b132SKunihiko Hayashi 
154*c6d9b132SKunihiko Hayashi static const struct phy_ops uniphier_pciephy_ops = {
155*c6d9b132SKunihiko Hayashi 	.init  = uniphier_pciephy_init,
156*c6d9b132SKunihiko Hayashi 	.exit  = uniphier_pciephy_exit,
157*c6d9b132SKunihiko Hayashi 	.owner = THIS_MODULE,
158*c6d9b132SKunihiko Hayashi };
159*c6d9b132SKunihiko Hayashi 
160*c6d9b132SKunihiko Hayashi static int uniphier_pciephy_probe(struct platform_device *pdev)
161*c6d9b132SKunihiko Hayashi {
162*c6d9b132SKunihiko Hayashi 	struct uniphier_pciephy_priv *priv;
163*c6d9b132SKunihiko Hayashi 	struct phy_provider *phy_provider;
164*c6d9b132SKunihiko Hayashi 	struct device *dev = &pdev->dev;
165*c6d9b132SKunihiko Hayashi 	struct regmap *regmap;
166*c6d9b132SKunihiko Hayashi 	struct resource *res;
167*c6d9b132SKunihiko Hayashi 	struct phy *phy;
168*c6d9b132SKunihiko Hayashi 
169*c6d9b132SKunihiko Hayashi 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
170*c6d9b132SKunihiko Hayashi 	if (!priv)
171*c6d9b132SKunihiko Hayashi 		return -ENOMEM;
172*c6d9b132SKunihiko Hayashi 
173*c6d9b132SKunihiko Hayashi 	priv->data = of_device_get_match_data(dev);
174*c6d9b132SKunihiko Hayashi 	if (WARN_ON(!priv->data))
175*c6d9b132SKunihiko Hayashi 		return -EINVAL;
176*c6d9b132SKunihiko Hayashi 
177*c6d9b132SKunihiko Hayashi 	priv->dev = dev;
178*c6d9b132SKunihiko Hayashi 
179*c6d9b132SKunihiko Hayashi 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
180*c6d9b132SKunihiko Hayashi 	priv->base = devm_ioremap_resource(dev, res);
181*c6d9b132SKunihiko Hayashi 	if (IS_ERR(priv->base))
182*c6d9b132SKunihiko Hayashi 		return PTR_ERR(priv->base);
183*c6d9b132SKunihiko Hayashi 
184*c6d9b132SKunihiko Hayashi 	priv->clk = devm_clk_get(dev, NULL);
185*c6d9b132SKunihiko Hayashi 	if (IS_ERR(priv->clk))
186*c6d9b132SKunihiko Hayashi 		return PTR_ERR(priv->clk);
187*c6d9b132SKunihiko Hayashi 
188*c6d9b132SKunihiko Hayashi 	priv->rst = devm_reset_control_get_shared(dev, NULL);
189*c6d9b132SKunihiko Hayashi 	if (IS_ERR(priv->rst))
190*c6d9b132SKunihiko Hayashi 		return PTR_ERR(priv->rst);
191*c6d9b132SKunihiko Hayashi 
192*c6d9b132SKunihiko Hayashi 	phy = devm_phy_create(dev, dev->of_node, &uniphier_pciephy_ops);
193*c6d9b132SKunihiko Hayashi 	if (IS_ERR(phy))
194*c6d9b132SKunihiko Hayashi 		return PTR_ERR(phy);
195*c6d9b132SKunihiko Hayashi 
196*c6d9b132SKunihiko Hayashi 	regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
197*c6d9b132SKunihiko Hayashi 						 "socionext,syscon");
198*c6d9b132SKunihiko Hayashi 	if (!IS_ERR(regmap) && priv->data->has_syscon)
199*c6d9b132SKunihiko Hayashi 		regmap_update_bits(regmap, SG_USBPCIESEL,
200*c6d9b132SKunihiko Hayashi 				   SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
201*c6d9b132SKunihiko Hayashi 
202*c6d9b132SKunihiko Hayashi 	phy_set_drvdata(phy, priv);
203*c6d9b132SKunihiko Hayashi 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
204*c6d9b132SKunihiko Hayashi 
205*c6d9b132SKunihiko Hayashi 	return PTR_ERR_OR_ZERO(phy_provider);
206*c6d9b132SKunihiko Hayashi }
207*c6d9b132SKunihiko Hayashi 
208*c6d9b132SKunihiko Hayashi static const struct uniphier_pciephy_soc_data uniphier_ld20_data = {
209*c6d9b132SKunihiko Hayashi 	.has_syscon = true,
210*c6d9b132SKunihiko Hayashi };
211*c6d9b132SKunihiko Hayashi 
212*c6d9b132SKunihiko Hayashi static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = {
213*c6d9b132SKunihiko Hayashi 	.has_syscon = false,
214*c6d9b132SKunihiko Hayashi };
215*c6d9b132SKunihiko Hayashi 
216*c6d9b132SKunihiko Hayashi static const struct of_device_id uniphier_pciephy_match[] = {
217*c6d9b132SKunihiko Hayashi 	{
218*c6d9b132SKunihiko Hayashi 		.compatible = "socionext,uniphier-ld20-pcie-phy",
219*c6d9b132SKunihiko Hayashi 		.data = &uniphier_ld20_data,
220*c6d9b132SKunihiko Hayashi 	},
221*c6d9b132SKunihiko Hayashi 	{
222*c6d9b132SKunihiko Hayashi 		.compatible = "socionext,uniphier-pxs3-pcie-phy",
223*c6d9b132SKunihiko Hayashi 		.data = &uniphier_pxs3_data,
224*c6d9b132SKunihiko Hayashi 	},
225*c6d9b132SKunihiko Hayashi 	{ /* sentinel */ },
226*c6d9b132SKunihiko Hayashi };
227*c6d9b132SKunihiko Hayashi MODULE_DEVICE_TABLE(of, uniphier_pciephy_match);
228*c6d9b132SKunihiko Hayashi 
229*c6d9b132SKunihiko Hayashi static struct platform_driver uniphier_pciephy_driver = {
230*c6d9b132SKunihiko Hayashi 	.probe = uniphier_pciephy_probe,
231*c6d9b132SKunihiko Hayashi 	.driver = {
232*c6d9b132SKunihiko Hayashi 		.name = "uniphier-pcie-phy",
233*c6d9b132SKunihiko Hayashi 		.of_match_table = uniphier_pciephy_match,
234*c6d9b132SKunihiko Hayashi 	},
235*c6d9b132SKunihiko Hayashi };
236*c6d9b132SKunihiko Hayashi module_platform_driver(uniphier_pciephy_driver);
237*c6d9b132SKunihiko Hayashi 
238*c6d9b132SKunihiko Hayashi MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
239*c6d9b132SKunihiko Hayashi MODULE_DESCRIPTION("UniPhier PHY driver for PCIe controller");
240*c6d9b132SKunihiko Hayashi MODULE_LICENSE("GPL v2");
241