xref: /OK3568_Linux_fs/kernel/drivers/phy/hisilicon/phy-histb-combphy.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * COMBPHY driver for HiSilicon STB SoCs
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Authors: Jianguo Sun <sunjianguo1@huawei.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/clk.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/io.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/of_device.h>
17*4882a593Smuzhiyun #include <linux/phy/phy.h>
18*4882a593Smuzhiyun #include <linux/regmap.h>
19*4882a593Smuzhiyun #include <linux/reset.h>
20*4882a593Smuzhiyun #include <dt-bindings/phy/phy.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define COMBPHY_MODE_PCIE		0
23*4882a593Smuzhiyun #define COMBPHY_MODE_USB3		1
24*4882a593Smuzhiyun #define COMBPHY_MODE_SATA		2
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define COMBPHY_CFG_REG			0x0
27*4882a593Smuzhiyun #define COMBPHY_BYPASS_CODEC		BIT(31)
28*4882a593Smuzhiyun #define COMBPHY_TEST_WRITE		BIT(24)
29*4882a593Smuzhiyun #define COMBPHY_TEST_DATA_SHIFT		20
30*4882a593Smuzhiyun #define COMBPHY_TEST_DATA_MASK		GENMASK(23, 20)
31*4882a593Smuzhiyun #define COMBPHY_TEST_ADDR_SHIFT		12
32*4882a593Smuzhiyun #define COMBPHY_TEST_ADDR_MASK		GENMASK(16, 12)
33*4882a593Smuzhiyun #define COMBPHY_CLKREF_OUT_OEN		BIT(0)
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun struct histb_combphy_mode {
36*4882a593Smuzhiyun 	int fixed;
37*4882a593Smuzhiyun 	int select;
38*4882a593Smuzhiyun 	u32 reg;
39*4882a593Smuzhiyun 	u32 shift;
40*4882a593Smuzhiyun 	u32 mask;
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun struct histb_combphy_priv {
44*4882a593Smuzhiyun 	void __iomem *mmio;
45*4882a593Smuzhiyun 	struct regmap *syscon;
46*4882a593Smuzhiyun 	struct reset_control *por_rst;
47*4882a593Smuzhiyun 	struct clk *ref_clk;
48*4882a593Smuzhiyun 	struct phy *phy;
49*4882a593Smuzhiyun 	struct histb_combphy_mode mode;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
nano_register_write(struct histb_combphy_priv * priv,u32 addr,u32 data)52*4882a593Smuzhiyun static void nano_register_write(struct histb_combphy_priv *priv,
53*4882a593Smuzhiyun 				u32 addr, u32 data)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	void __iomem *reg = priv->mmio + COMBPHY_CFG_REG;
56*4882a593Smuzhiyun 	u32 val;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	/* Set up address and data for the write */
59*4882a593Smuzhiyun 	val = readl(reg);
60*4882a593Smuzhiyun 	val &= ~COMBPHY_TEST_ADDR_MASK;
61*4882a593Smuzhiyun 	val |= addr << COMBPHY_TEST_ADDR_SHIFT;
62*4882a593Smuzhiyun 	val &= ~COMBPHY_TEST_DATA_MASK;
63*4882a593Smuzhiyun 	val |= data << COMBPHY_TEST_DATA_SHIFT;
64*4882a593Smuzhiyun 	writel(val, reg);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	/* Flip strobe control to trigger the write */
67*4882a593Smuzhiyun 	val &= ~COMBPHY_TEST_WRITE;
68*4882a593Smuzhiyun 	writel(val, reg);
69*4882a593Smuzhiyun 	val |= COMBPHY_TEST_WRITE;
70*4882a593Smuzhiyun 	writel(val, reg);
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
is_mode_fixed(struct histb_combphy_mode * mode)73*4882a593Smuzhiyun static int is_mode_fixed(struct histb_combphy_mode *mode)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	return (mode->fixed != PHY_NONE) ? true : false;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun 
histb_combphy_set_mode(struct histb_combphy_priv * priv)78*4882a593Smuzhiyun static int histb_combphy_set_mode(struct histb_combphy_priv *priv)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	struct histb_combphy_mode *mode = &priv->mode;
81*4882a593Smuzhiyun 	struct regmap *syscon = priv->syscon;
82*4882a593Smuzhiyun 	u32 hw_sel;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (is_mode_fixed(mode))
85*4882a593Smuzhiyun 		return 0;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	switch (mode->select) {
88*4882a593Smuzhiyun 	case PHY_TYPE_SATA:
89*4882a593Smuzhiyun 		hw_sel = COMBPHY_MODE_SATA;
90*4882a593Smuzhiyun 		break;
91*4882a593Smuzhiyun 	case PHY_TYPE_PCIE:
92*4882a593Smuzhiyun 		hw_sel = COMBPHY_MODE_PCIE;
93*4882a593Smuzhiyun 		break;
94*4882a593Smuzhiyun 	case PHY_TYPE_USB3:
95*4882a593Smuzhiyun 		hw_sel = COMBPHY_MODE_USB3;
96*4882a593Smuzhiyun 		break;
97*4882a593Smuzhiyun 	default:
98*4882a593Smuzhiyun 		return -EINVAL;
99*4882a593Smuzhiyun 	}
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	return regmap_update_bits(syscon, mode->reg, mode->mask,
102*4882a593Smuzhiyun 				  hw_sel << mode->shift);
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
histb_combphy_init(struct phy * phy)105*4882a593Smuzhiyun static int histb_combphy_init(struct phy *phy)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	struct histb_combphy_priv *priv = phy_get_drvdata(phy);
108*4882a593Smuzhiyun 	u32 val;
109*4882a593Smuzhiyun 	int ret;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	ret = histb_combphy_set_mode(priv);
112*4882a593Smuzhiyun 	if (ret)
113*4882a593Smuzhiyun 		return ret;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	/* Clear bypass bit to enable encoding/decoding */
116*4882a593Smuzhiyun 	val = readl(priv->mmio + COMBPHY_CFG_REG);
117*4882a593Smuzhiyun 	val &= ~COMBPHY_BYPASS_CODEC;
118*4882a593Smuzhiyun 	writel(val, priv->mmio + COMBPHY_CFG_REG);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	ret = clk_prepare_enable(priv->ref_clk);
121*4882a593Smuzhiyun 	if (ret)
122*4882a593Smuzhiyun 		return ret;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	reset_control_deassert(priv->por_rst);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	/* Enable EP clock */
127*4882a593Smuzhiyun 	val = readl(priv->mmio + COMBPHY_CFG_REG);
128*4882a593Smuzhiyun 	val |= COMBPHY_CLKREF_OUT_OEN;
129*4882a593Smuzhiyun 	writel(val, priv->mmio + COMBPHY_CFG_REG);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	/* Need to wait for EP clock stable */
132*4882a593Smuzhiyun 	mdelay(5);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	/* Configure nano phy registers as suggested by vendor */
135*4882a593Smuzhiyun 	nano_register_write(priv, 0x1, 0x8);
136*4882a593Smuzhiyun 	nano_register_write(priv, 0xc, 0x9);
137*4882a593Smuzhiyun 	nano_register_write(priv, 0x1a, 0x4);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	return 0;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
histb_combphy_exit(struct phy * phy)142*4882a593Smuzhiyun static int histb_combphy_exit(struct phy *phy)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	struct histb_combphy_priv *priv = phy_get_drvdata(phy);
145*4882a593Smuzhiyun 	u32 val;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/* Disable EP clock */
148*4882a593Smuzhiyun 	val = readl(priv->mmio + COMBPHY_CFG_REG);
149*4882a593Smuzhiyun 	val &= ~COMBPHY_CLKREF_OUT_OEN;
150*4882a593Smuzhiyun 	writel(val, priv->mmio + COMBPHY_CFG_REG);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	reset_control_assert(priv->por_rst);
153*4882a593Smuzhiyun 	clk_disable_unprepare(priv->ref_clk);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun static const struct phy_ops histb_combphy_ops = {
159*4882a593Smuzhiyun 	.init = histb_combphy_init,
160*4882a593Smuzhiyun 	.exit = histb_combphy_exit,
161*4882a593Smuzhiyun 	.owner = THIS_MODULE,
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun 
histb_combphy_xlate(struct device * dev,struct of_phandle_args * args)164*4882a593Smuzhiyun static struct phy *histb_combphy_xlate(struct device *dev,
165*4882a593Smuzhiyun 				       struct of_phandle_args *args)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	struct histb_combphy_priv *priv = dev_get_drvdata(dev);
168*4882a593Smuzhiyun 	struct histb_combphy_mode *mode = &priv->mode;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (args->args_count < 1) {
171*4882a593Smuzhiyun 		dev_err(dev, "invalid number of arguments\n");
172*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	mode->select = args->args[0];
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (mode->select < PHY_TYPE_SATA || mode->select > PHY_TYPE_USB3) {
178*4882a593Smuzhiyun 		dev_err(dev, "invalid phy mode select argument\n");
179*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	if (is_mode_fixed(mode) && mode->select != mode->fixed) {
183*4882a593Smuzhiyun 		dev_err(dev, "mode select %d mismatch fixed phy mode %d\n",
184*4882a593Smuzhiyun 			mode->select, mode->fixed);
185*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	return priv->phy;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
histb_combphy_probe(struct platform_device * pdev)191*4882a593Smuzhiyun static int histb_combphy_probe(struct platform_device *pdev)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	struct phy_provider *phy_provider;
194*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
195*4882a593Smuzhiyun 	struct histb_combphy_priv *priv;
196*4882a593Smuzhiyun 	struct device_node *np = dev->of_node;
197*4882a593Smuzhiyun 	struct histb_combphy_mode *mode;
198*4882a593Smuzhiyun 	u32 vals[3];
199*4882a593Smuzhiyun 	int ret;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
202*4882a593Smuzhiyun 	if (!priv)
203*4882a593Smuzhiyun 		return -ENOMEM;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	priv->mmio = devm_platform_ioremap_resource(pdev, 0);
206*4882a593Smuzhiyun 	if (IS_ERR(priv->mmio)) {
207*4882a593Smuzhiyun 		ret = PTR_ERR(priv->mmio);
208*4882a593Smuzhiyun 		return ret;
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	priv->syscon = syscon_node_to_regmap(np->parent);
212*4882a593Smuzhiyun 	if (IS_ERR(priv->syscon)) {
213*4882a593Smuzhiyun 		dev_err(dev, "failed to find peri_ctrl syscon regmap\n");
214*4882a593Smuzhiyun 		return PTR_ERR(priv->syscon);
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	mode = &priv->mode;
218*4882a593Smuzhiyun 	mode->fixed = PHY_NONE;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "hisilicon,fixed-mode", &mode->fixed);
221*4882a593Smuzhiyun 	if (ret == 0)
222*4882a593Smuzhiyun 		dev_dbg(dev, "found fixed phy mode %d\n", mode->fixed);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	ret = of_property_read_u32_array(np, "hisilicon,mode-select-bits",
225*4882a593Smuzhiyun 					 vals, ARRAY_SIZE(vals));
226*4882a593Smuzhiyun 	if (ret == 0) {
227*4882a593Smuzhiyun 		if (is_mode_fixed(mode)) {
228*4882a593Smuzhiyun 			dev_err(dev, "found select bits for fixed mode phy\n");
229*4882a593Smuzhiyun 			return -EINVAL;
230*4882a593Smuzhiyun 		}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 		mode->reg = vals[0];
233*4882a593Smuzhiyun 		mode->shift = vals[1];
234*4882a593Smuzhiyun 		mode->mask = vals[2];
235*4882a593Smuzhiyun 		dev_dbg(dev, "found mode select bits\n");
236*4882a593Smuzhiyun 	} else {
237*4882a593Smuzhiyun 		if (!is_mode_fixed(mode)) {
238*4882a593Smuzhiyun 			dev_err(dev, "no valid select bits found for non-fixed phy\n");
239*4882a593Smuzhiyun 			return -ENODEV;
240*4882a593Smuzhiyun 		}
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	priv->ref_clk = devm_clk_get(dev, NULL);
244*4882a593Smuzhiyun 	if (IS_ERR(priv->ref_clk)) {
245*4882a593Smuzhiyun 		dev_err(dev, "failed to find ref clock\n");
246*4882a593Smuzhiyun 		return PTR_ERR(priv->ref_clk);
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	priv->por_rst = devm_reset_control_get(dev, NULL);
250*4882a593Smuzhiyun 	if (IS_ERR(priv->por_rst)) {
251*4882a593Smuzhiyun 		dev_err(dev, "failed to get poweron reset\n");
252*4882a593Smuzhiyun 		return PTR_ERR(priv->por_rst);
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	priv->phy = devm_phy_create(dev, NULL, &histb_combphy_ops);
256*4882a593Smuzhiyun 	if (IS_ERR(priv->phy)) {
257*4882a593Smuzhiyun 		dev_err(dev, "failed to create combphy\n");
258*4882a593Smuzhiyun 		return PTR_ERR(priv->phy);
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	dev_set_drvdata(dev, priv);
262*4882a593Smuzhiyun 	phy_set_drvdata(priv->phy, priv);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	phy_provider = devm_of_phy_provider_register(dev, histb_combphy_xlate);
265*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(phy_provider);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun static const struct of_device_id histb_combphy_of_match[] = {
269*4882a593Smuzhiyun 	{ .compatible = "hisilicon,hi3798cv200-combphy" },
270*4882a593Smuzhiyun 	{ },
271*4882a593Smuzhiyun };
272*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, histb_combphy_of_match);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun static struct platform_driver histb_combphy_driver = {
275*4882a593Smuzhiyun 	.probe	= histb_combphy_probe,
276*4882a593Smuzhiyun 	.driver = {
277*4882a593Smuzhiyun 		.name = "combphy",
278*4882a593Smuzhiyun 		.of_match_table = histb_combphy_of_match,
279*4882a593Smuzhiyun 	},
280*4882a593Smuzhiyun };
281*4882a593Smuzhiyun module_platform_driver(histb_combphy_driver);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun MODULE_DESCRIPTION("HiSilicon STB COMBPHY driver");
284*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
285