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