xref: /linux/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c (revision ff124bbbca1d3a07fa1392ffdbbdeece71f68ece)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * dwmac-imx.c - DWMAC Specific Glue layer for NXP imx8
4  *
5  * Copyright 2020 NXP
6  *
7  */
8 
9 #include <linux/clk.h>
10 #include <linux/gpio/consumer.h>
11 #include <linux/kernel.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/of_net.h>
16 #include <linux/phy.h>
17 #include <linux/platform_device.h>
18 #include <linux/pm_wakeirq.h>
19 #include <linux/regmap.h>
20 #include <linux/slab.h>
21 #include <linux/stmmac.h>
22 
23 #include "stmmac_platform.h"
24 
25 #define GPR_ENET_QOS_INTF_MODE_MASK	GENMASK(21, 16)
26 #define GPR_ENET_QOS_INTF_SEL_MASK	GENMASK(20, 16)
27 #define GPR_ENET_QOS_CLK_GEN_EN		(0x1 << 19)
28 #define GPR_ENET_QOS_CLK_TX_CLK_SEL	(0x1 << 20)
29 #define GPR_ENET_QOS_RGMII_EN		(0x1 << 21)
30 
31 #define MX93_GPR_ENET_QOS_INTF_SEL_MASK		GENMASK(3, 1)
32 #define MX93_GPR_ENET_QOS_ENABLE		BIT(0)
33 
34 #define MX93_ENET_CLK_SEL_OFFSET		(4)
35 #define MX93_ENET_QOS_CLK_TX_SEL_MASK		BIT_MASK(0)
36 
37 #define DMA_BUS_MODE			0x00001000
38 #define DMA_BUS_MODE_SFT_RESET		(0x1 << 0)
39 #define RMII_RESET_SPEED		(0x3 << 14)
40 #define CTRL_SPEED_MASK			GENMASK(15, 14)
41 
42 struct imx_priv_data;
43 
44 struct imx_dwmac_ops {
45 	u32 addr_width;
46 	u32 flags;
47 	bool mac_rgmii_txclk_auto_adj;
48 
49 	int (*fix_soc_reset)(struct stmmac_priv *priv);
50 	int (*set_intf_mode)(struct imx_priv_data *dwmac, u8 phy_intf_sel);
51 	void (*fix_mac_speed)(void *priv, int speed, unsigned int mode);
52 };
53 
54 struct imx_priv_data {
55 	struct device *dev;
56 	struct clk *clk_tx;
57 	struct clk *clk_mem;
58 	struct regmap *intf_regmap;
59 	u32 intf_reg_off;
60 	bool rmii_refclk_ext;
61 	void __iomem *base_addr;
62 
63 	const struct imx_dwmac_ops *ops;
64 	struct plat_stmmacenet_data *plat_dat;
65 };
66 
67 static int imx8mp_set_intf_mode(struct imx_priv_data *dwmac, u8 phy_intf_sel)
68 {
69 	unsigned int val;
70 
71 	val = FIELD_PREP(GPR_ENET_QOS_INTF_SEL_MASK, phy_intf_sel) |
72 	      GPR_ENET_QOS_CLK_GEN_EN;
73 
74 	if (phy_intf_sel == PHY_INTF_SEL_RMII && !dwmac->rmii_refclk_ext)
75 		val |= GPR_ENET_QOS_CLK_TX_CLK_SEL;
76 	else if (phy_intf_sel == PHY_INTF_SEL_RGMII)
77 		val |= GPR_ENET_QOS_RGMII_EN;
78 
79 	return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
80 				  GPR_ENET_QOS_INTF_MODE_MASK, val);
81 };
82 
83 static int
84 imx8dxl_set_intf_mode(struct imx_priv_data *dwmac, u8 phy_intf_sel)
85 {
86 	/* TBD: depends on imx8dxl scu interfaces to be upstreamed */
87 	return 0;
88 }
89 
90 static int imx93_set_intf_mode(struct imx_priv_data *dwmac, u8 phy_intf_sel)
91 {
92 	unsigned int val;
93 	int ret;
94 
95 	if (phy_intf_sel == PHY_INTF_SEL_RMII && dwmac->rmii_refclk_ext) {
96 		ret = regmap_clear_bits(dwmac->intf_regmap,
97 					dwmac->intf_reg_off +
98 					MX93_ENET_CLK_SEL_OFFSET,
99 					MX93_ENET_QOS_CLK_TX_SEL_MASK);
100 		if (ret)
101 			return ret;
102 	}
103 
104 	val = FIELD_PREP(MX93_GPR_ENET_QOS_INTF_SEL_MASK, phy_intf_sel) |
105 	      MX93_GPR_ENET_QOS_ENABLE;
106 
107 	return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
108 				  MX93_GPR_ENET_QOS_INTF_SEL_MASK |
109 				  MX93_GPR_ENET_QOS_ENABLE, val);
110 };
111 
112 static int imx_dwmac_clks_config(void *priv, bool enabled)
113 {
114 	struct imx_priv_data *dwmac = priv;
115 	int ret = 0;
116 
117 	if (enabled) {
118 		ret = clk_prepare_enable(dwmac->clk_mem);
119 		if (ret) {
120 			dev_err(dwmac->dev, "mem clock enable failed\n");
121 			return ret;
122 		}
123 
124 		ret = clk_prepare_enable(dwmac->clk_tx);
125 		if (ret) {
126 			dev_err(dwmac->dev, "tx clock enable failed\n");
127 			clk_disable_unprepare(dwmac->clk_mem);
128 			return ret;
129 		}
130 	} else {
131 		clk_disable_unprepare(dwmac->clk_tx);
132 		clk_disable_unprepare(dwmac->clk_mem);
133 	}
134 
135 	return ret;
136 }
137 
138 static int imx_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel)
139 {
140 	struct imx_priv_data *dwmac = bsp_priv;
141 
142 	if (!dwmac->ops->set_intf_mode)
143 		return 0;
144 
145 	if (phy_intf_sel != PHY_INTF_SEL_GMII_MII &&
146 	    phy_intf_sel != PHY_INTF_SEL_RGMII &&
147 	    phy_intf_sel != PHY_INTF_SEL_RMII)
148 		return -EINVAL;
149 
150 	return dwmac->ops->set_intf_mode(dwmac, phy_intf_sel);
151 }
152 
153 static int imx_dwmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i,
154 				     phy_interface_t interface, int speed)
155 {
156 	if (interface == PHY_INTERFACE_MODE_RMII ||
157 	    interface == PHY_INTERFACE_MODE_MII)
158 		return 0;
159 
160 	return stmmac_set_clk_tx_rate(bsp_priv, clk_tx_i, interface, speed);
161 }
162 
163 static void imx_dwmac_fix_speed(void *priv, int speed, unsigned int mode)
164 {
165 	struct plat_stmmacenet_data *plat_dat;
166 	struct imx_priv_data *dwmac = priv;
167 	long rate;
168 	int err;
169 
170 	plat_dat = dwmac->plat_dat;
171 
172 	if (dwmac->ops->mac_rgmii_txclk_auto_adj ||
173 	    (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII) ||
174 	    (plat_dat->phy_interface == PHY_INTERFACE_MODE_MII))
175 		return;
176 
177 	rate = rgmii_clock(speed);
178 	if (rate < 0) {
179 		dev_err(dwmac->dev, "invalid speed %d\n", speed);
180 		return;
181 	}
182 
183 	err = clk_set_rate(dwmac->clk_tx, rate);
184 	if (err < 0)
185 		dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate);
186 }
187 
188 static void imx93_dwmac_fix_speed(void *priv, int speed, unsigned int mode)
189 {
190 	struct imx_priv_data *dwmac = priv;
191 	unsigned int iface;
192 	int ctrl, old_ctrl;
193 
194 	imx_dwmac_fix_speed(priv, speed, mode);
195 
196 	if (!dwmac || mode != MLO_AN_FIXED)
197 		return;
198 
199 	if (regmap_read(dwmac->intf_regmap, dwmac->intf_reg_off, &iface))
200 		return;
201 
202 	if (FIELD_GET(MX93_GPR_ENET_QOS_INTF_SEL_MASK, iface) !=
203 	    PHY_INTF_SEL_RGMII)
204 		return;
205 
206 	old_ctrl = readl(dwmac->base_addr + MAC_CTRL_REG);
207 	ctrl = old_ctrl & ~CTRL_SPEED_MASK;
208 	regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
209 			   MX93_GPR_ENET_QOS_INTF_SEL_MASK |
210 			   MX93_GPR_ENET_QOS_ENABLE, 0);
211 	writel(ctrl, dwmac->base_addr + MAC_CTRL_REG);
212 
213 	 /* Ensure the settings for CTRL are applied. */
214 	readl(dwmac->base_addr + MAC_CTRL_REG);
215 
216 	usleep_range(10, 20);
217 	iface &= MX93_GPR_ENET_QOS_INTF_SEL_MASK;
218 	iface |= MX93_GPR_ENET_QOS_ENABLE;
219 	regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
220 			   MX93_GPR_ENET_QOS_INTF_SEL_MASK |
221 			   MX93_GPR_ENET_QOS_ENABLE, iface);
222 
223 	writel(old_ctrl, dwmac->base_addr + MAC_CTRL_REG);
224 }
225 
226 static int imx_dwmac_mx93_reset(struct stmmac_priv *priv)
227 {
228 	struct plat_stmmacenet_data *plat_dat = priv->plat;
229 	void __iomem *ioaddr = priv->ioaddr;
230 	u32 value;
231 
232 	/* DMA SW reset */
233 	value = readl(ioaddr + DMA_BUS_MODE);
234 	value |= DMA_BUS_MODE_SFT_RESET;
235 	writel(value, ioaddr + DMA_BUS_MODE);
236 
237 	if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII) {
238 		usleep_range(100, 200);
239 		writel(RMII_RESET_SPEED, ioaddr + MAC_CTRL_REG);
240 	}
241 
242 	return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
243 				 !(value & DMA_BUS_MODE_SFT_RESET),
244 				 10000, 1000000);
245 }
246 
247 static int
248 imx_dwmac_parse_dt(struct imx_priv_data *dwmac, struct device *dev)
249 {
250 	struct device_node *np = dev->of_node;
251 	int err = 0;
252 
253 	dwmac->rmii_refclk_ext = of_property_read_bool(np, "snps,rmii_refclk_ext");
254 
255 	dwmac->clk_tx = devm_clk_get(dev, "tx");
256 	if (IS_ERR(dwmac->clk_tx)) {
257 		dev_err(dev, "failed to get tx clock\n");
258 		return PTR_ERR(dwmac->clk_tx);
259 	}
260 
261 	dwmac->clk_mem = NULL;
262 
263 	if (of_machine_is_compatible("fsl,imx8dxl") ||
264 	    of_machine_is_compatible("fsl,imx91") ||
265 	    of_machine_is_compatible("fsl,imx93")) {
266 		dwmac->clk_mem = devm_clk_get(dev, "mem");
267 		if (IS_ERR(dwmac->clk_mem)) {
268 			dev_err(dev, "failed to get mem clock\n");
269 			return PTR_ERR(dwmac->clk_mem);
270 		}
271 	}
272 
273 	if (of_machine_is_compatible("fsl,imx8mp") ||
274 	    of_machine_is_compatible("fsl,imx91") ||
275 	    of_machine_is_compatible("fsl,imx93")) {
276 		/* Binding doc describes the property:
277 		 * is required by i.MX8MP, i.MX91, i.MX93.
278 		 * is optional for i.MX8DXL.
279 		 */
280 		dwmac->intf_regmap =
281 			syscon_regmap_lookup_by_phandle_args(np, "intf_mode", 1,
282 							     &dwmac->intf_reg_off);
283 		if (IS_ERR(dwmac->intf_regmap))
284 			return PTR_ERR(dwmac->intf_regmap);
285 	}
286 
287 	return err;
288 }
289 
290 static int imx_dwmac_probe(struct platform_device *pdev)
291 {
292 	struct plat_stmmacenet_data *plat_dat;
293 	struct stmmac_resources stmmac_res;
294 	struct imx_priv_data *dwmac;
295 	const struct imx_dwmac_ops *data;
296 	int ret;
297 
298 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
299 	if (ret)
300 		return ret;
301 
302 	dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
303 	if (!dwmac)
304 		return -ENOMEM;
305 
306 	plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
307 	if (IS_ERR(plat_dat))
308 		return PTR_ERR(plat_dat);
309 
310 	data = of_device_get_match_data(&pdev->dev);
311 	if (!data) {
312 		dev_err(&pdev->dev, "failed to get match data\n");
313 		return -EINVAL;
314 	}
315 
316 	dwmac->ops = data;
317 	dwmac->dev = &pdev->dev;
318 
319 	ret = imx_dwmac_parse_dt(dwmac, &pdev->dev);
320 	if (ret) {
321 		dev_err(&pdev->dev, "failed to parse OF data\n");
322 		return ret;
323 	}
324 
325 	if (data->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
326 		plat_dat->flags |= STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY;
327 
328 	if (data->flags & STMMAC_FLAG_KEEP_PREAMBLE_BEFORE_SFD)
329 		plat_dat->flags |= STMMAC_FLAG_KEEP_PREAMBLE_BEFORE_SFD;
330 
331 	/* Default TX Q0 to use TSO and rest TXQ for TBS */
332 	for (int i = 1; i < plat_dat->tx_queues_to_use; i++)
333 		plat_dat->tx_queues_cfg[i].tbs_en = 1;
334 
335 	plat_dat->host_dma_width = dwmac->ops->addr_width;
336 	plat_dat->set_phy_intf_sel = imx_set_phy_intf_sel;
337 	plat_dat->clks_config = imx_dwmac_clks_config;
338 	plat_dat->bsp_priv = dwmac;
339 	dwmac->plat_dat = plat_dat;
340 	dwmac->base_addr = stmmac_res.addr;
341 
342 	ret = imx_dwmac_clks_config(dwmac, true);
343 	if (ret)
344 		return ret;
345 
346 	if (dwmac->ops->fix_mac_speed) {
347 		plat_dat->fix_mac_speed = dwmac->ops->fix_mac_speed;
348 	} else if (!dwmac->ops->mac_rgmii_txclk_auto_adj) {
349 		plat_dat->clk_tx_i = dwmac->clk_tx;
350 		plat_dat->set_clk_tx_rate = imx_dwmac_set_clk_tx_rate;
351 	}
352 
353 	dwmac->plat_dat->fix_soc_reset = dwmac->ops->fix_soc_reset;
354 
355 	ret = stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
356 	if (ret)
357 		imx_dwmac_clks_config(dwmac, false);
358 
359 	return ret;
360 }
361 
362 static struct imx_dwmac_ops imx8mp_dwmac_data = {
363 	.addr_width = 34,
364 	.mac_rgmii_txclk_auto_adj = false,
365 	.set_intf_mode = imx8mp_set_intf_mode,
366 	.flags = STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY |
367 		 STMMAC_FLAG_KEEP_PREAMBLE_BEFORE_SFD,
368 };
369 
370 static struct imx_dwmac_ops imx8dxl_dwmac_data = {
371 	.addr_width = 32,
372 	.mac_rgmii_txclk_auto_adj = true,
373 	.set_intf_mode = imx8dxl_set_intf_mode,
374 };
375 
376 static struct imx_dwmac_ops imx93_dwmac_data = {
377 	.addr_width = 32,
378 	.mac_rgmii_txclk_auto_adj = true,
379 	.set_intf_mode = imx93_set_intf_mode,
380 	.fix_soc_reset = imx_dwmac_mx93_reset,
381 	.fix_mac_speed = imx93_dwmac_fix_speed,
382 };
383 
384 static const struct of_device_id imx_dwmac_match[] = {
385 	{ .compatible = "nxp,imx8mp-dwmac-eqos", .data = &imx8mp_dwmac_data },
386 	{ .compatible = "nxp,imx8dxl-dwmac-eqos", .data = &imx8dxl_dwmac_data },
387 	{ .compatible = "nxp,imx93-dwmac-eqos", .data = &imx93_dwmac_data },
388 	{ }
389 };
390 MODULE_DEVICE_TABLE(of, imx_dwmac_match);
391 
392 static struct platform_driver imx_dwmac_driver = {
393 	.probe  = imx_dwmac_probe,
394 	.remove = stmmac_pltfr_remove,
395 	.driver = {
396 		.name           = "imx-dwmac",
397 		.pm		= &stmmac_pltfr_pm_ops,
398 		.of_match_table = imx_dwmac_match,
399 	},
400 };
401 module_platform_driver(imx_dwmac_driver);
402 
403 MODULE_AUTHOR("NXP");
404 MODULE_DESCRIPTION("NXP imx8 DWMAC Specific Glue layer");
405 MODULE_LICENSE("GPL v2");
406