xref: /linux/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c (revision a0285236ab93fdfdd1008afaa04561d142d6c276)
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 *priv, int speed, unsigned int mode)
140 {
141 	struct tegra_eqos *eqos = priv;
142 	bool needs_calibration = false;
143 	u32 value;
144 	int err;
145 
146 	switch (speed) {
147 	case SPEED_1000:
148 	case SPEED_100:
149 		needs_calibration = true;
150 		fallthrough;
151 
152 	case SPEED_10:
153 		break;
154 
155 	default:
156 		dev_err(eqos->dev, "invalid speed %d\n", speed);
157 		break;
158 	}
159 
160 	if (needs_calibration) {
161 		/* calibrate */
162 		value = readl(eqos->regs + SDMEMCOMPPADCTRL);
163 		value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
164 		writel(value, eqos->regs + SDMEMCOMPPADCTRL);
165 
166 		udelay(1);
167 
168 		value = readl(eqos->regs + AUTO_CAL_CONFIG);
169 		value |= AUTO_CAL_CONFIG_START | AUTO_CAL_CONFIG_ENABLE;
170 		writel(value, eqos->regs + AUTO_CAL_CONFIG);
171 
172 		err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
173 						value,
174 						value & AUTO_CAL_STATUS_ACTIVE,
175 						1, 10);
176 		if (err < 0) {
177 			dev_err(eqos->dev, "calibration did not start\n");
178 			goto failed;
179 		}
180 
181 		err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
182 						value,
183 						(value & AUTO_CAL_STATUS_ACTIVE) == 0,
184 						20, 200);
185 		if (err < 0) {
186 			dev_err(eqos->dev, "calibration didn't finish\n");
187 			goto failed;
188 		}
189 
190 	failed:
191 		value = readl(eqos->regs + SDMEMCOMPPADCTRL);
192 		value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
193 		writel(value, eqos->regs + SDMEMCOMPPADCTRL);
194 	} else {
195 		value = readl(eqos->regs + AUTO_CAL_CONFIG);
196 		value &= ~AUTO_CAL_CONFIG_ENABLE;
197 		writel(value, eqos->regs + AUTO_CAL_CONFIG);
198 	}
199 }
200 
201 static int tegra_eqos_probe(struct platform_device *pdev,
202 			    struct plat_stmmacenet_data *plat_dat,
203 			    struct stmmac_resources *res)
204 {
205 	struct device *dev = &pdev->dev;
206 	struct tegra_eqos *eqos;
207 	int err;
208 
209 	eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL);
210 	if (!eqos)
211 		return -ENOMEM;
212 
213 	eqos->dev = &pdev->dev;
214 	eqos->regs = res->addr;
215 
216 	if (!is_of_node(dev->fwnode))
217 		goto bypass_clk_reset_gpio;
218 
219 	plat_dat->clk_tx_i = stmmac_pltfr_find_clk(plat_dat, "tx");
220 
221 	eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH);
222 	if (IS_ERR(eqos->reset)) {
223 		err = PTR_ERR(eqos->reset);
224 		return err;
225 	}
226 
227 	usleep_range(2000, 4000);
228 	gpiod_set_value(eqos->reset, 0);
229 
230 	/* MDIO bus was already reset just above */
231 	plat_dat->mdio_bus_data->needs_reset = false;
232 
233 	eqos->rst = devm_reset_control_get(&pdev->dev, "eqos");
234 	if (IS_ERR(eqos->rst)) {
235 		err = PTR_ERR(eqos->rst);
236 		goto reset_phy;
237 	}
238 
239 	err = reset_control_assert(eqos->rst);
240 	if (err < 0)
241 		goto reset_phy;
242 
243 	usleep_range(2000, 4000);
244 
245 	err = reset_control_deassert(eqos->rst);
246 	if (err < 0)
247 		goto reset_phy;
248 
249 	usleep_range(2000, 4000);
250 
251 bypass_clk_reset_gpio:
252 	plat_dat->fix_mac_speed = tegra_eqos_fix_speed;
253 	plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate;
254 	plat_dat->bsp_priv = eqos;
255 	plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE;
256 
257 	return 0;
258 
259 reset_phy:
260 	gpiod_set_value(eqos->reset, 1);
261 
262 	return err;
263 }
264 
265 static void tegra_eqos_remove(struct platform_device *pdev)
266 {
267 	struct tegra_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev);
268 
269 	reset_control_assert(eqos->rst);
270 	gpiod_set_value(eqos->reset, 1);
271 }
272 
273 struct dwc_eth_dwmac_data {
274 	int (*probe)(struct platform_device *pdev,
275 		     struct plat_stmmacenet_data *plat_dat,
276 		     struct stmmac_resources *res);
277 	void (*remove)(struct platform_device *pdev);
278 	const char *stmmac_clk_name;
279 };
280 
281 static const struct dwc_eth_dwmac_data dwc_qos_data = {
282 	.probe = dwc_qos_probe,
283 	.stmmac_clk_name = "apb_pclk",
284 };
285 
286 static const struct dwc_eth_dwmac_data tegra_eqos_data = {
287 	.probe = tegra_eqos_probe,
288 	.remove = tegra_eqos_remove,
289 	.stmmac_clk_name = "slave_bus",
290 };
291 
292 static const struct dwc_eth_dwmac_data fsd_eqos_data = {
293 	.stmmac_clk_name = "slave_bus",
294 };
295 
296 static int dwc_eth_dwmac_probe(struct platform_device *pdev)
297 {
298 	const struct dwc_eth_dwmac_data *data;
299 	struct plat_stmmacenet_data *plat_dat;
300 	struct stmmac_resources stmmac_res;
301 	int ret;
302 
303 	data = device_get_match_data(&pdev->dev);
304 
305 	memset(&stmmac_res, 0, sizeof(struct stmmac_resources));
306 
307 	/**
308 	 * Since stmmac_platform supports name IRQ only, basic platform
309 	 * resource initialization is done in the glue logic.
310 	 */
311 	stmmac_res.irq = platform_get_irq(pdev, 0);
312 	if (stmmac_res.irq < 0)
313 		return stmmac_res.irq;
314 	stmmac_res.wol_irq = stmmac_res.irq;
315 
316 	stmmac_res.addr = devm_platform_ioremap_resource(pdev, 0);
317 	if (IS_ERR(stmmac_res.addr))
318 		return PTR_ERR(stmmac_res.addr);
319 
320 	plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
321 	if (IS_ERR(plat_dat))
322 		return PTR_ERR(plat_dat);
323 
324 	ret = devm_clk_bulk_get_all(&pdev->dev, &plat_dat->clks);
325 	if (ret < 0)
326 		return dev_err_probe(&pdev->dev, ret, "Failed to retrieve all required clocks\n");
327 	plat_dat->num_clks = ret;
328 
329 	ret = clk_bulk_prepare_enable(plat_dat->num_clks, plat_dat->clks);
330 	if (ret)
331 		return dev_err_probe(&pdev->dev, ret, "Failed to enable clocks\n");
332 
333 	plat_dat->stmmac_clk = stmmac_pltfr_find_clk(plat_dat,
334 						     data->stmmac_clk_name);
335 
336 	if (data->probe)
337 		ret = data->probe(pdev, plat_dat, &stmmac_res);
338 	if (ret < 0) {
339 		dev_err_probe(&pdev->dev, ret, "failed to probe subdriver\n");
340 		clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks);
341 		return ret;
342 	}
343 
344 	ret = dwc_eth_dwmac_config_dt(pdev, plat_dat);
345 	if (ret)
346 		goto remove;
347 
348 	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
349 	if (ret)
350 		goto remove;
351 
352 	return ret;
353 
354 remove:
355 	if (data->remove)
356 		data->remove(pdev);
357 
358 	return ret;
359 }
360 
361 static void dwc_eth_dwmac_remove(struct platform_device *pdev)
362 {
363 	const struct dwc_eth_dwmac_data *data = device_get_match_data(&pdev->dev);
364 	struct plat_stmmacenet_data *plat_dat = dev_get_platdata(&pdev->dev);
365 
366 	stmmac_dvr_remove(&pdev->dev);
367 
368 	if (data->remove)
369 		data->remove(pdev);
370 
371 	if (plat_dat)
372 		clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks);
373 }
374 
375 static const struct of_device_id dwc_eth_dwmac_match[] = {
376 	{ .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data },
377 	{ .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data },
378 	{ .compatible = "tesla,fsd-ethqos", .data = &fsd_eqos_data },
379 	{ }
380 };
381 MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match);
382 
383 static struct platform_driver dwc_eth_dwmac_driver = {
384 	.probe  = dwc_eth_dwmac_probe,
385 	.remove = dwc_eth_dwmac_remove,
386 	.driver = {
387 		.name           = "dwc-eth-dwmac",
388 		.pm             = &stmmac_pltfr_pm_ops,
389 		.of_match_table = dwc_eth_dwmac_match,
390 	},
391 };
392 module_platform_driver(dwc_eth_dwmac_driver);
393 
394 MODULE_AUTHOR("Joao Pinto <jpinto@synopsys.com>");
395 MODULE_DESCRIPTION("Synopsys DWC Ethernet Quality-of-Service v4.10a driver");
396 MODULE_LICENSE("GPL v2");
397