xref: /openbmc/linux/drivers/net/ethernet/arc/emac_rockchip.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   * emac-rockchip.c - Rockchip EMAC specific glue layer
4   *
5   * Copyright (C) 2014 Romain Perier <romain.perier@gmail.com>
6   */
7  
8  #include <linux/etherdevice.h>
9  #include <linux/mfd/syscon.h>
10  #include <linux/module.h>
11  #include <linux/of_net.h>
12  #include <linux/platform_device.h>
13  #include <linux/regmap.h>
14  #include <linux/regulator/consumer.h>
15  
16  #include "emac.h"
17  
18  #define DRV_NAME        "rockchip_emac"
19  
20  struct emac_rockchip_soc_data {
21  	unsigned int grf_offset;
22  	unsigned int grf_mode_offset;
23  	unsigned int grf_speed_offset;
24  	bool need_div_macclk;
25  };
26  
27  struct rockchip_priv_data {
28  	struct arc_emac_priv emac;
29  	struct regmap *grf;
30  	const struct emac_rockchip_soc_data *soc_data;
31  	struct regulator *regulator;
32  	struct clk *refclk;
33  	struct clk *macclk;
34  };
35  
emac_rockchip_set_mac_speed(void * priv,unsigned int speed)36  static void emac_rockchip_set_mac_speed(void *priv, unsigned int speed)
37  {
38  	struct rockchip_priv_data *emac = priv;
39  	u32 speed_offset = emac->soc_data->grf_speed_offset;
40  	u32 data;
41  	int err = 0;
42  
43  	switch (speed) {
44  	case 10:
45  		data = (1 << (speed_offset + 16)) | (0 << speed_offset);
46  		break;
47  	case 100:
48  		data = (1 << (speed_offset + 16)) | (1 << speed_offset);
49  		break;
50  	default:
51  		pr_err("speed %u not supported\n", speed);
52  		return;
53  	}
54  
55  	err = regmap_write(emac->grf, emac->soc_data->grf_offset, data);
56  	if (err)
57  		pr_err("unable to apply speed %u to grf (%d)\n", speed, err);
58  }
59  
60  static const struct emac_rockchip_soc_data emac_rk3036_emac_data = {
61  	.grf_offset = 0x140,   .grf_mode_offset = 8,
62  	.grf_speed_offset = 9, .need_div_macclk = 1,
63  };
64  
65  static const struct emac_rockchip_soc_data emac_rk3066_emac_data = {
66  	.grf_offset = 0x154,   .grf_mode_offset = 0,
67  	.grf_speed_offset = 1, .need_div_macclk = 0,
68  };
69  
70  static const struct emac_rockchip_soc_data emac_rk3188_emac_data = {
71  	.grf_offset = 0x0a4,   .grf_mode_offset = 0,
72  	.grf_speed_offset = 1, .need_div_macclk = 0,
73  };
74  
75  static const struct of_device_id emac_rockchip_dt_ids[] = {
76  	{
77  		.compatible = "rockchip,rk3036-emac",
78  		.data = &emac_rk3036_emac_data,
79  	},
80  	{
81  		.compatible = "rockchip,rk3066-emac",
82  		.data = &emac_rk3066_emac_data,
83  	},
84  	{
85  		.compatible = "rockchip,rk3188-emac",
86  		.data = &emac_rk3188_emac_data,
87  	},
88  	{ /* Sentinel */ }
89  };
90  
91  MODULE_DEVICE_TABLE(of, emac_rockchip_dt_ids);
92  
emac_rockchip_probe(struct platform_device * pdev)93  static int emac_rockchip_probe(struct platform_device *pdev)
94  {
95  	struct device *dev = &pdev->dev;
96  	struct net_device *ndev;
97  	struct rockchip_priv_data *priv;
98  	const struct of_device_id *match;
99  	phy_interface_t interface;
100  	u32 data;
101  	int err;
102  
103  	if (!pdev->dev.of_node)
104  		return -ENODEV;
105  
106  	ndev = alloc_etherdev(sizeof(struct rockchip_priv_data));
107  	if (!ndev)
108  		return -ENOMEM;
109  	platform_set_drvdata(pdev, ndev);
110  	SET_NETDEV_DEV(ndev, dev);
111  
112  	priv = netdev_priv(ndev);
113  	priv->emac.drv_name = DRV_NAME;
114  	priv->emac.set_mac_speed = emac_rockchip_set_mac_speed;
115  
116  	err = of_get_phy_mode(dev->of_node, &interface);
117  	if (err)
118  		goto out_netdev;
119  
120  	/* RK3036/RK3066/RK3188 SoCs only support RMII */
121  	if (interface != PHY_INTERFACE_MODE_RMII) {
122  		dev_err(dev, "unsupported phy interface mode %d\n", interface);
123  		err = -ENOTSUPP;
124  		goto out_netdev;
125  	}
126  
127  	priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
128  						    "rockchip,grf");
129  	if (IS_ERR(priv->grf)) {
130  		dev_err(dev, "failed to retrieve global register file (%ld)\n",
131  			PTR_ERR(priv->grf));
132  		err = PTR_ERR(priv->grf);
133  		goto out_netdev;
134  	}
135  
136  	match = of_match_node(emac_rockchip_dt_ids, dev->of_node);
137  	priv->soc_data = match->data;
138  
139  	priv->emac.clk = devm_clk_get(dev, "hclk");
140  	if (IS_ERR(priv->emac.clk)) {
141  		dev_err(dev, "failed to retrieve host clock (%ld)\n",
142  			PTR_ERR(priv->emac.clk));
143  		err = PTR_ERR(priv->emac.clk);
144  		goto out_netdev;
145  	}
146  
147  	priv->refclk = devm_clk_get(dev, "macref");
148  	if (IS_ERR(priv->refclk)) {
149  		dev_err(dev, "failed to retrieve reference clock (%ld)\n",
150  			PTR_ERR(priv->refclk));
151  		err = PTR_ERR(priv->refclk);
152  		goto out_netdev;
153  	}
154  
155  	err = clk_prepare_enable(priv->refclk);
156  	if (err) {
157  		dev_err(dev, "failed to enable reference clock (%d)\n", err);
158  		goto out_netdev;
159  	}
160  
161  	/* Optional regulator for PHY */
162  	priv->regulator = devm_regulator_get_optional(dev, "phy");
163  	if (IS_ERR(priv->regulator)) {
164  		if (PTR_ERR(priv->regulator) == -EPROBE_DEFER) {
165  			err = -EPROBE_DEFER;
166  			goto out_clk_disable;
167  		}
168  		dev_err(dev, "no regulator found\n");
169  		priv->regulator = NULL;
170  	}
171  
172  	if (priv->regulator) {
173  		err = regulator_enable(priv->regulator);
174  		if (err) {
175  			dev_err(dev, "failed to enable phy-supply (%d)\n", err);
176  			goto out_clk_disable;
177  		}
178  	}
179  
180  	/* Set speed 100M */
181  	data = (1 << (priv->soc_data->grf_speed_offset + 16)) |
182  	       (1 << priv->soc_data->grf_speed_offset);
183  	/* Set RMII mode */
184  	data |= (1 << (priv->soc_data->grf_mode_offset + 16)) |
185  		(0 << priv->soc_data->grf_mode_offset);
186  
187  	err = regmap_write(priv->grf, priv->soc_data->grf_offset, data);
188  	if (err) {
189  		dev_err(dev, "unable to apply initial settings to grf (%d)\n",
190  			err);
191  		goto out_regulator_disable;
192  	}
193  
194  	/* RMII interface needs always a rate of 50MHz */
195  	err = clk_set_rate(priv->refclk, 50000000);
196  	if (err) {
197  		dev_err(dev,
198  			"failed to change reference clock rate (%d)\n", err);
199  		goto out_regulator_disable;
200  	}
201  
202  	if (priv->soc_data->need_div_macclk) {
203  		priv->macclk = devm_clk_get(dev, "macclk");
204  		if (IS_ERR(priv->macclk)) {
205  			dev_err(dev, "failed to retrieve mac clock (%ld)\n",
206  				PTR_ERR(priv->macclk));
207  			err = PTR_ERR(priv->macclk);
208  			goto out_regulator_disable;
209  		}
210  
211  		err = clk_prepare_enable(priv->macclk);
212  		if (err) {
213  			dev_err(dev, "failed to enable mac clock (%d)\n", err);
214  			goto out_regulator_disable;
215  		}
216  
217  		/* RMII TX/RX needs always a rate of 25MHz */
218  		err = clk_set_rate(priv->macclk, 25000000);
219  		if (err) {
220  			dev_err(dev,
221  				"failed to change mac clock rate (%d)\n", err);
222  			goto out_clk_disable_macclk;
223  		}
224  	}
225  
226  	err = arc_emac_probe(ndev, interface);
227  	if (err) {
228  		dev_err(dev, "failed to probe arc emac (%d)\n", err);
229  		goto out_clk_disable_macclk;
230  	}
231  
232  	return 0;
233  
234  out_clk_disable_macclk:
235  	if (priv->soc_data->need_div_macclk)
236  		clk_disable_unprepare(priv->macclk);
237  out_regulator_disable:
238  	if (priv->regulator)
239  		regulator_disable(priv->regulator);
240  out_clk_disable:
241  	clk_disable_unprepare(priv->refclk);
242  out_netdev:
243  	free_netdev(ndev);
244  	return err;
245  }
246  
emac_rockchip_remove(struct platform_device * pdev)247  static int emac_rockchip_remove(struct platform_device *pdev)
248  {
249  	struct net_device *ndev = platform_get_drvdata(pdev);
250  	struct rockchip_priv_data *priv = netdev_priv(ndev);
251  
252  	arc_emac_remove(ndev);
253  
254  	clk_disable_unprepare(priv->refclk);
255  
256  	if (priv->regulator)
257  		regulator_disable(priv->regulator);
258  
259  	if (priv->soc_data->need_div_macclk)
260  		clk_disable_unprepare(priv->macclk);
261  
262  	free_netdev(ndev);
263  	return 0;
264  }
265  
266  static struct platform_driver emac_rockchip_driver = {
267  	.probe = emac_rockchip_probe,
268  	.remove = emac_rockchip_remove,
269  	.driver = {
270  		.name = DRV_NAME,
271  		.of_match_table  = emac_rockchip_dt_ids,
272  	},
273  };
274  
275  module_platform_driver(emac_rockchip_driver);
276  
277  MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
278  MODULE_DESCRIPTION("Rockchip EMAC platform driver");
279  MODULE_LICENSE("GPL");
280