xref: /linux/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c (revision bca5cfbb694d66a1c482d0c347eee80f6afbc870)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Synopsys DWC Ethernet Quality-of-Service v4.10a linux driver
4  *
5  * Copyright (C) 2016 Joao Pinto <jpinto@synopsys.com>
6  */
7 
8 #include <linux/clk.h>
9 #include <linux/clk-provider.h>
10 #include <linux/device.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/ethtool.h>
13 #include <linux/io.h>
14 #include <linux/iopoll.h>
15 #include <linux/ioport.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <linux/of_net.h>
19 #include <linux/mfd/syscon.h>
20 #include <linux/platform_device.h>
21 #include <linux/reset.h>
22 #include <linux/stmmac.h>
23 
24 #include "stmmac_platform.h"
25 #include "dwmac4.h"
26 
27 struct tegra_eqos {
28 	struct device *dev;
29 	void __iomem *regs;
30 
31 	struct reset_control *rst;
32 
33 	struct gpio_desc *reset;
34 };
35 
36 static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
37 				   struct plat_stmmacenet_data *plat_dat)
38 {
39 	struct device *dev = &pdev->dev;
40 	u32 burst_map = 0;
41 	u32 bit_index = 0;
42 	u32 a_index = 0;
43 
44 	if (!plat_dat->axi) {
45 		plat_dat->axi = devm_kzalloc(&pdev->dev,
46 					     sizeof(struct stmmac_axi),
47 					     GFP_KERNEL);
48 
49 		if (!plat_dat->axi)
50 			return -ENOMEM;
51 	}
52 
53 	plat_dat->axi->axi_lpi_en = device_property_read_bool(dev,
54 							      "snps,en-lpi");
55 	if (device_property_read_u32(dev, "snps,write-requests",
56 				     &plat_dat->axi->axi_wr_osr_lmt)) {
57 		/**
58 		 * Since the register has a reset value of 1, if property
59 		 * is missing, default to 1.
60 		 */
61 		plat_dat->axi->axi_wr_osr_lmt = 1;
62 	} else {
63 		/**
64 		 * If property exists, to keep the behavior from dwc_eth_qos,
65 		 * subtract one after parsing.
66 		 */
67 		plat_dat->axi->axi_wr_osr_lmt--;
68 	}
69 
70 	if (device_property_read_u32(dev, "snps,read-requests",
71 				     &plat_dat->axi->axi_rd_osr_lmt)) {
72 		/**
73 		 * Since the register has a reset value of 1, if property
74 		 * is missing, default to 1.
75 		 */
76 		plat_dat->axi->axi_rd_osr_lmt = 1;
77 	} else {
78 		/**
79 		 * If property exists, to keep the behavior from dwc_eth_qos,
80 		 * subtract one after parsing.
81 		 */
82 		plat_dat->axi->axi_rd_osr_lmt--;
83 	}
84 	device_property_read_u32(dev, "snps,burst-map", &burst_map);
85 
86 	/* converts burst-map bitmask to burst array */
87 	for (bit_index = 0; bit_index < 7; bit_index++) {
88 		if (burst_map & (1 << bit_index)) {
89 			switch (bit_index) {
90 			case 0:
91 			plat_dat->axi->axi_blen[a_index] = 4; break;
92 			case 1:
93 			plat_dat->axi->axi_blen[a_index] = 8; break;
94 			case 2:
95 			plat_dat->axi->axi_blen[a_index] = 16; break;
96 			case 3:
97 			plat_dat->axi->axi_blen[a_index] = 32; break;
98 			case 4:
99 			plat_dat->axi->axi_blen[a_index] = 64; break;
100 			case 5:
101 			plat_dat->axi->axi_blen[a_index] = 128; break;
102 			case 6:
103 			plat_dat->axi->axi_blen[a_index] = 256; break;
104 			default:
105 			break;
106 			}
107 			a_index++;
108 		}
109 	}
110 
111 	/* dwc-qos needs GMAC4, AAL, TSO and PMT */
112 	plat_dat->has_gmac4 = 1;
113 	plat_dat->dma_cfg->aal = 1;
114 	plat_dat->flags |= STMMAC_FLAG_TSO_EN;
115 	plat_dat->pmt = 1;
116 
117 	return 0;
118 }
119 
120 static int dwc_qos_probe(struct platform_device *pdev,
121 			 struct plat_stmmacenet_data *plat_dat,
122 			 struct stmmac_resources *stmmac_res)
123 {
124 	plat_dat->pclk = stmmac_pltfr_find_clk(plat_dat, "phy_ref_clk");
125 
126 	return 0;
127 }
128 
129 #define SDMEMCOMPPADCTRL 0x8800
130 #define  SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31)
131 
132 #define AUTO_CAL_CONFIG 0x8804
133 #define  AUTO_CAL_CONFIG_START BIT(31)
134 #define  AUTO_CAL_CONFIG_ENABLE BIT(29)
135 
136 #define AUTO_CAL_STATUS 0x880c
137 #define  AUTO_CAL_STATUS_ACTIVE BIT(31)
138 
139 static void tegra_eqos_fix_speed(void *bsp_priv, int speed, unsigned int mode)
140 {
141 	struct tegra_eqos *eqos = bsp_priv;
142 	bool needs_calibration = false;
143 	struct stmmac_priv *priv;
144 	u32 value;
145 	int err;
146 
147 	switch (speed) {
148 	case SPEED_1000:
149 	case SPEED_100:
150 		needs_calibration = true;
151 		fallthrough;
152 
153 	case SPEED_10:
154 		break;
155 
156 	default:
157 		dev_err(eqos->dev, "invalid speed %d\n", speed);
158 		break;
159 	}
160 
161 	if (needs_calibration) {
162 		priv = netdev_priv(dev_get_drvdata(eqos->dev));
163 
164 		/* Calibration should be done with the MDIO bus idle */
165 		mutex_lock(&priv->mii->mdio_lock);
166 
167 		/* calibrate */
168 		value = readl(eqos->regs + SDMEMCOMPPADCTRL);
169 		value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
170 		writel(value, eqos->regs + SDMEMCOMPPADCTRL);
171 
172 		udelay(1);
173 
174 		value = readl(eqos->regs + AUTO_CAL_CONFIG);
175 		value |= AUTO_CAL_CONFIG_START | AUTO_CAL_CONFIG_ENABLE;
176 		writel(value, eqos->regs + AUTO_CAL_CONFIG);
177 
178 		err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
179 						value,
180 						value & AUTO_CAL_STATUS_ACTIVE,
181 						1, 10);
182 		if (err < 0) {
183 			dev_err(eqos->dev, "calibration did not start\n");
184 			goto failed;
185 		}
186 
187 		err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
188 						value,
189 						(value & AUTO_CAL_STATUS_ACTIVE) == 0,
190 						20, 200);
191 		if (err < 0) {
192 			dev_err(eqos->dev, "calibration didn't finish\n");
193 			goto failed;
194 		}
195 
196 	failed:
197 		value = readl(eqos->regs + SDMEMCOMPPADCTRL);
198 		value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
199 		writel(value, eqos->regs + SDMEMCOMPPADCTRL);
200 
201 		mutex_unlock(&priv->mii->mdio_lock);
202 	} else {
203 		value = readl(eqos->regs + AUTO_CAL_CONFIG);
204 		value &= ~AUTO_CAL_CONFIG_ENABLE;
205 		writel(value, eqos->regs + AUTO_CAL_CONFIG);
206 	}
207 }
208 
209 static int tegra_eqos_probe(struct platform_device *pdev,
210 			    struct plat_stmmacenet_data *plat_dat,
211 			    struct stmmac_resources *res)
212 {
213 	struct device *dev = &pdev->dev;
214 	struct tegra_eqos *eqos;
215 	int err;
216 
217 	eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL);
218 	if (!eqos)
219 		return -ENOMEM;
220 
221 	eqos->dev = &pdev->dev;
222 	eqos->regs = res->addr;
223 
224 	if (!is_of_node(dev->fwnode))
225 		goto bypass_clk_reset_gpio;
226 
227 	plat_dat->clk_tx_i = stmmac_pltfr_find_clk(plat_dat, "tx");
228 
229 	eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH);
230 	if (IS_ERR(eqos->reset)) {
231 		err = PTR_ERR(eqos->reset);
232 		return err;
233 	}
234 
235 	usleep_range(2000, 4000);
236 	gpiod_set_value(eqos->reset, 0);
237 
238 	/* MDIO bus was already reset just above */
239 	plat_dat->mdio_bus_data->needs_reset = false;
240 
241 	eqos->rst = devm_reset_control_get(&pdev->dev, "eqos");
242 	if (IS_ERR(eqos->rst)) {
243 		err = PTR_ERR(eqos->rst);
244 		goto reset_phy;
245 	}
246 
247 	err = reset_control_assert(eqos->rst);
248 	if (err < 0)
249 		goto reset_phy;
250 
251 	usleep_range(2000, 4000);
252 
253 	err = reset_control_deassert(eqos->rst);
254 	if (err < 0)
255 		goto reset_phy;
256 
257 	usleep_range(2000, 4000);
258 
259 bypass_clk_reset_gpio:
260 	plat_dat->fix_mac_speed = tegra_eqos_fix_speed;
261 	plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate;
262 	plat_dat->bsp_priv = eqos;
263 	plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE |
264 			   STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP;
265 
266 	return 0;
267 
268 reset_phy:
269 	gpiod_set_value(eqos->reset, 1);
270 
271 	return err;
272 }
273 
274 static void tegra_eqos_remove(struct platform_device *pdev)
275 {
276 	struct tegra_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev);
277 
278 	reset_control_assert(eqos->rst);
279 	gpiod_set_value(eqos->reset, 1);
280 }
281 
282 struct dwc_eth_dwmac_data {
283 	int (*probe)(struct platform_device *pdev,
284 		     struct plat_stmmacenet_data *plat_dat,
285 		     struct stmmac_resources *res);
286 	void (*remove)(struct platform_device *pdev);
287 	const char *stmmac_clk_name;
288 };
289 
290 static const struct dwc_eth_dwmac_data dwc_qos_data = {
291 	.probe = dwc_qos_probe,
292 	.stmmac_clk_name = "apb_pclk",
293 };
294 
295 static const struct dwc_eth_dwmac_data tegra_eqos_data = {
296 	.probe = tegra_eqos_probe,
297 	.remove = tegra_eqos_remove,
298 	.stmmac_clk_name = "slave_bus",
299 };
300 
301 static const struct dwc_eth_dwmac_data fsd_eqos_data = {
302 	.stmmac_clk_name = "slave_bus",
303 };
304 
305 static int dwc_eth_dwmac_probe(struct platform_device *pdev)
306 {
307 	const struct dwc_eth_dwmac_data *data;
308 	struct plat_stmmacenet_data *plat_dat;
309 	struct stmmac_resources stmmac_res;
310 	int ret;
311 
312 	data = device_get_match_data(&pdev->dev);
313 
314 	memset(&stmmac_res, 0, sizeof(struct stmmac_resources));
315 
316 	/**
317 	 * Since stmmac_platform supports name IRQ only, basic platform
318 	 * resource initialization is done in the glue logic.
319 	 */
320 	stmmac_res.irq = platform_get_irq(pdev, 0);
321 	if (stmmac_res.irq < 0)
322 		return stmmac_res.irq;
323 	stmmac_res.wol_irq = stmmac_res.irq;
324 
325 	stmmac_res.addr = devm_platform_ioremap_resource(pdev, 0);
326 	if (IS_ERR(stmmac_res.addr))
327 		return PTR_ERR(stmmac_res.addr);
328 
329 	plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
330 	if (IS_ERR(plat_dat))
331 		return PTR_ERR(plat_dat);
332 
333 	ret = devm_clk_bulk_get_all(&pdev->dev, &plat_dat->clks);
334 	if (ret < 0)
335 		return dev_err_probe(&pdev->dev, ret, "Failed to retrieve all required clocks\n");
336 	plat_dat->num_clks = ret;
337 
338 	ret = clk_bulk_prepare_enable(plat_dat->num_clks, plat_dat->clks);
339 	if (ret)
340 		return dev_err_probe(&pdev->dev, ret, "Failed to enable clocks\n");
341 
342 	plat_dat->stmmac_clk = stmmac_pltfr_find_clk(plat_dat,
343 						     data->stmmac_clk_name);
344 
345 	if (data->probe)
346 		ret = data->probe(pdev, plat_dat, &stmmac_res);
347 	if (ret < 0) {
348 		dev_err_probe(&pdev->dev, ret, "failed to probe subdriver\n");
349 		clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks);
350 		return ret;
351 	}
352 
353 	ret = dwc_eth_dwmac_config_dt(pdev, plat_dat);
354 	if (ret)
355 		goto remove;
356 
357 	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
358 	if (ret)
359 		goto remove;
360 
361 	return ret;
362 
363 remove:
364 	if (data->remove)
365 		data->remove(pdev);
366 
367 	return ret;
368 }
369 
370 static void dwc_eth_dwmac_remove(struct platform_device *pdev)
371 {
372 	const struct dwc_eth_dwmac_data *data = device_get_match_data(&pdev->dev);
373 	struct plat_stmmacenet_data *plat_dat = dev_get_platdata(&pdev->dev);
374 
375 	stmmac_dvr_remove(&pdev->dev);
376 
377 	if (data->remove)
378 		data->remove(pdev);
379 
380 	if (plat_dat)
381 		clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks);
382 }
383 
384 static const struct of_device_id dwc_eth_dwmac_match[] = {
385 	{ .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data },
386 	{ .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data },
387 	{ .compatible = "tesla,fsd-ethqos", .data = &fsd_eqos_data },
388 	{ }
389 };
390 MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match);
391 
392 static struct platform_driver dwc_eth_dwmac_driver = {
393 	.probe  = dwc_eth_dwmac_probe,
394 	.remove = dwc_eth_dwmac_remove,
395 	.driver = {
396 		.name           = "dwc-eth-dwmac",
397 		.pm             = &stmmac_pltfr_pm_ops,
398 		.of_match_table = dwc_eth_dwmac_match,
399 	},
400 };
401 module_platform_driver(dwc_eth_dwmac_driver);
402 
403 MODULE_AUTHOR("Joao Pinto <jpinto@synopsys.com>");
404 MODULE_DESCRIPTION("Synopsys DWC Ethernet Quality-of-Service v4.10a driver");
405 MODULE_LICENSE("GPL v2");
406