xref: /openbmc/linux/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
194abdad6SFugang Duan // SPDX-License-Identifier: GPL-2.0
294abdad6SFugang Duan /*
394abdad6SFugang Duan  * dwmac-imx.c - DWMAC Specific Glue layer for NXP imx8
494abdad6SFugang Duan  *
594abdad6SFugang Duan  * Copyright 2020 NXP
694abdad6SFugang Duan  *
794abdad6SFugang Duan  */
894abdad6SFugang Duan 
994abdad6SFugang Duan #include <linux/clk.h>
1094abdad6SFugang Duan #include <linux/gpio/consumer.h>
1194abdad6SFugang Duan #include <linux/kernel.h>
1294abdad6SFugang Duan #include <linux/mfd/syscon.h>
1394abdad6SFugang Duan #include <linux/module.h>
1494abdad6SFugang Duan #include <linux/of.h>
1594abdad6SFugang Duan #include <linux/of_net.h>
1694abdad6SFugang Duan #include <linux/phy.h>
1794abdad6SFugang Duan #include <linux/platform_device.h>
1894abdad6SFugang Duan #include <linux/pm_wakeirq.h>
1994abdad6SFugang Duan #include <linux/regmap.h>
2094abdad6SFugang Duan #include <linux/slab.h>
2194abdad6SFugang Duan #include <linux/stmmac.h>
2294abdad6SFugang Duan 
2394abdad6SFugang Duan #include "stmmac_platform.h"
2494abdad6SFugang Duan 
2594abdad6SFugang Duan #define GPR_ENET_QOS_INTF_MODE_MASK	GENMASK(21, 16)
2694abdad6SFugang Duan #define GPR_ENET_QOS_INTF_SEL_MII	(0x0 << 16)
2794abdad6SFugang Duan #define GPR_ENET_QOS_INTF_SEL_RMII	(0x4 << 16)
2894abdad6SFugang Duan #define GPR_ENET_QOS_INTF_SEL_RGMII	(0x1 << 16)
2994abdad6SFugang Duan #define GPR_ENET_QOS_CLK_GEN_EN		(0x1 << 19)
3094abdad6SFugang Duan #define GPR_ENET_QOS_CLK_TX_CLK_SEL	(0x1 << 20)
3194abdad6SFugang Duan #define GPR_ENET_QOS_RGMII_EN		(0x1 << 21)
3294abdad6SFugang Duan 
33e5bf35caSClark Wang #define MX93_GPR_ENET_QOS_INTF_MODE_MASK	GENMASK(3, 0)
344fa6c976SShenwei Wang #define MX93_GPR_ENET_QOS_INTF_MASK		GENMASK(3, 1)
35e5bf35caSClark Wang #define MX93_GPR_ENET_QOS_INTF_SEL_MII		(0x0 << 1)
36e5bf35caSClark Wang #define MX93_GPR_ENET_QOS_INTF_SEL_RMII		(0x4 << 1)
37e5bf35caSClark Wang #define MX93_GPR_ENET_QOS_INTF_SEL_RGMII	(0x1 << 1)
38e5bf35caSClark Wang #define MX93_GPR_ENET_QOS_CLK_GEN_EN		(0x1 << 0)
39e5bf35caSClark Wang 
40b536f32bSShenwei Wang #define DMA_BUS_MODE			0x00001000
41b536f32bSShenwei Wang #define DMA_BUS_MODE_SFT_RESET		(0x1 << 0)
42b536f32bSShenwei Wang #define RMII_RESET_SPEED		(0x3 << 14)
434fa6c976SShenwei Wang #define CTRL_SPEED_MASK			GENMASK(15, 14)
44b536f32bSShenwei Wang 
4594abdad6SFugang Duan struct imx_dwmac_ops {
4694abdad6SFugang Duan 	u32 addr_width;
476cb2e613SJohannes Zink 	u32 flags;
4894abdad6SFugang Duan 	bool mac_rgmii_txclk_auto_adj;
4994abdad6SFugang Duan 
50b536f32bSShenwei Wang 	int (*fix_soc_reset)(void *priv, void __iomem *ioaddr);
5194abdad6SFugang Duan 	int (*set_intf_mode)(struct plat_stmmacenet_data *plat_dat);
524fa6c976SShenwei Wang 	void (*fix_mac_speed)(void *priv, unsigned int speed, unsigned int mode);
5394abdad6SFugang Duan };
5494abdad6SFugang Duan 
5594abdad6SFugang Duan struct imx_priv_data {
5694abdad6SFugang Duan 	struct device *dev;
5794abdad6SFugang Duan 	struct clk *clk_tx;
5894abdad6SFugang Duan 	struct clk *clk_mem;
5994abdad6SFugang Duan 	struct regmap *intf_regmap;
6094abdad6SFugang Duan 	u32 intf_reg_off;
6194abdad6SFugang Duan 	bool rmii_refclk_ext;
624fa6c976SShenwei Wang 	void __iomem *base_addr;
6394abdad6SFugang Duan 
6494abdad6SFugang Duan 	const struct imx_dwmac_ops *ops;
6594abdad6SFugang Duan 	struct plat_stmmacenet_data *plat_dat;
6694abdad6SFugang Duan };
6794abdad6SFugang Duan 
imx8mp_set_intf_mode(struct plat_stmmacenet_data * plat_dat)6894abdad6SFugang Duan static int imx8mp_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
6994abdad6SFugang Duan {
7094abdad6SFugang Duan 	struct imx_priv_data *dwmac = plat_dat->bsp_priv;
7194abdad6SFugang Duan 	int val;
7294abdad6SFugang Duan 
73*a014c355SRussell King (Oracle) 	switch (plat_dat->mac_interface) {
7494abdad6SFugang Duan 	case PHY_INTERFACE_MODE_MII:
7594abdad6SFugang Duan 		val = GPR_ENET_QOS_INTF_SEL_MII;
7694abdad6SFugang Duan 		break;
7794abdad6SFugang Duan 	case PHY_INTERFACE_MODE_RMII:
7894abdad6SFugang Duan 		val = GPR_ENET_QOS_INTF_SEL_RMII;
7994abdad6SFugang Duan 		val |= (dwmac->rmii_refclk_ext ? 0 : GPR_ENET_QOS_CLK_TX_CLK_SEL);
8094abdad6SFugang Duan 		break;
8194abdad6SFugang Duan 	case PHY_INTERFACE_MODE_RGMII:
8294abdad6SFugang Duan 	case PHY_INTERFACE_MODE_RGMII_ID:
8394abdad6SFugang Duan 	case PHY_INTERFACE_MODE_RGMII_RXID:
8494abdad6SFugang Duan 	case PHY_INTERFACE_MODE_RGMII_TXID:
8594abdad6SFugang Duan 		val = GPR_ENET_QOS_INTF_SEL_RGMII |
8694abdad6SFugang Duan 		      GPR_ENET_QOS_RGMII_EN;
8794abdad6SFugang Duan 		break;
8894abdad6SFugang Duan 	default:
8994abdad6SFugang Duan 		pr_debug("imx dwmac doesn't support %d interface\n",
90*a014c355SRussell King (Oracle) 			 plat_dat->mac_interface);
9194abdad6SFugang Duan 		return -EINVAL;
9294abdad6SFugang Duan 	}
9394abdad6SFugang Duan 
9494abdad6SFugang Duan 	val |= GPR_ENET_QOS_CLK_GEN_EN;
9594abdad6SFugang Duan 	return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
9694abdad6SFugang Duan 				  GPR_ENET_QOS_INTF_MODE_MASK, val);
9794abdad6SFugang Duan };
9894abdad6SFugang Duan 
9994abdad6SFugang Duan static int
imx8dxl_set_intf_mode(struct plat_stmmacenet_data * plat_dat)10094abdad6SFugang Duan imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
10194abdad6SFugang Duan {
10294abdad6SFugang Duan 	int ret = 0;
10394abdad6SFugang Duan 
10494abdad6SFugang Duan 	/* TBD: depends on imx8dxl scu interfaces to be upstreamed */
10594abdad6SFugang Duan 	return ret;
10694abdad6SFugang Duan }
10794abdad6SFugang Duan 
imx93_set_intf_mode(struct plat_stmmacenet_data * plat_dat)108e5bf35caSClark Wang static int imx93_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
109e5bf35caSClark Wang {
110e5bf35caSClark Wang 	struct imx_priv_data *dwmac = plat_dat->bsp_priv;
111e5bf35caSClark Wang 	int val;
112e5bf35caSClark Wang 
113*a014c355SRussell King (Oracle) 	switch (plat_dat->mac_interface) {
114e5bf35caSClark Wang 	case PHY_INTERFACE_MODE_MII:
115e5bf35caSClark Wang 		val = MX93_GPR_ENET_QOS_INTF_SEL_MII;
116e5bf35caSClark Wang 		break;
117e5bf35caSClark Wang 	case PHY_INTERFACE_MODE_RMII:
118e5bf35caSClark Wang 		val = MX93_GPR_ENET_QOS_INTF_SEL_RMII;
119e5bf35caSClark Wang 		break;
120e5bf35caSClark Wang 	case PHY_INTERFACE_MODE_RGMII:
121e5bf35caSClark Wang 	case PHY_INTERFACE_MODE_RGMII_ID:
122e5bf35caSClark Wang 	case PHY_INTERFACE_MODE_RGMII_RXID:
123e5bf35caSClark Wang 	case PHY_INTERFACE_MODE_RGMII_TXID:
124e5bf35caSClark Wang 		val = MX93_GPR_ENET_QOS_INTF_SEL_RGMII;
125e5bf35caSClark Wang 		break;
126e5bf35caSClark Wang 	default:
127e5bf35caSClark Wang 		dev_dbg(dwmac->dev, "imx dwmac doesn't support %d interface\n",
128*a014c355SRussell King (Oracle) 			 plat_dat->mac_interface);
129e5bf35caSClark Wang 		return -EINVAL;
130e5bf35caSClark Wang 	}
131e5bf35caSClark Wang 
132e5bf35caSClark Wang 	val |= MX93_GPR_ENET_QOS_CLK_GEN_EN;
133e5bf35caSClark Wang 	return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
134e5bf35caSClark Wang 				  MX93_GPR_ENET_QOS_INTF_MODE_MASK, val);
135e5bf35caSClark Wang };
136e5bf35caSClark Wang 
imx_dwmac_clks_config(void * priv,bool enabled)1378f2f8376SJoakim Zhang static int imx_dwmac_clks_config(void *priv, bool enabled)
1388f2f8376SJoakim Zhang {
1398f2f8376SJoakim Zhang 	struct imx_priv_data *dwmac = priv;
1408f2f8376SJoakim Zhang 	int ret = 0;
1418f2f8376SJoakim Zhang 
1428f2f8376SJoakim Zhang 	if (enabled) {
1438f2f8376SJoakim Zhang 		ret = clk_prepare_enable(dwmac->clk_mem);
1448f2f8376SJoakim Zhang 		if (ret) {
1458f2f8376SJoakim Zhang 			dev_err(dwmac->dev, "mem clock enable failed\n");
1468f2f8376SJoakim Zhang 			return ret;
1478f2f8376SJoakim Zhang 		}
1488f2f8376SJoakim Zhang 
1498f2f8376SJoakim Zhang 		ret = clk_prepare_enable(dwmac->clk_tx);
1508f2f8376SJoakim Zhang 		if (ret) {
1518f2f8376SJoakim Zhang 			dev_err(dwmac->dev, "tx clock enable failed\n");
1528f2f8376SJoakim Zhang 			clk_disable_unprepare(dwmac->clk_mem);
1538f2f8376SJoakim Zhang 			return ret;
1548f2f8376SJoakim Zhang 		}
1558f2f8376SJoakim Zhang 	} else {
1568f2f8376SJoakim Zhang 		clk_disable_unprepare(dwmac->clk_tx);
1578f2f8376SJoakim Zhang 		clk_disable_unprepare(dwmac->clk_mem);
1588f2f8376SJoakim Zhang 	}
1598f2f8376SJoakim Zhang 
1608f2f8376SJoakim Zhang 	return ret;
1618f2f8376SJoakim Zhang }
1628f2f8376SJoakim Zhang 
imx_dwmac_init(struct platform_device * pdev,void * priv)16394abdad6SFugang Duan static int imx_dwmac_init(struct platform_device *pdev, void *priv)
16494abdad6SFugang Duan {
16594abdad6SFugang Duan 	struct plat_stmmacenet_data *plat_dat;
16694abdad6SFugang Duan 	struct imx_priv_data *dwmac = priv;
16794abdad6SFugang Duan 	int ret;
16894abdad6SFugang Duan 
16994abdad6SFugang Duan 	plat_dat = dwmac->plat_dat;
17094abdad6SFugang Duan 
17194abdad6SFugang Duan 	if (dwmac->ops->set_intf_mode) {
17294abdad6SFugang Duan 		ret = dwmac->ops->set_intf_mode(plat_dat);
17394abdad6SFugang Duan 		if (ret)
1748f2f8376SJoakim Zhang 			return ret;
17594abdad6SFugang Duan 	}
17694abdad6SFugang Duan 
17794abdad6SFugang Duan 	return 0;
17894abdad6SFugang Duan }
17994abdad6SFugang Duan 
imx_dwmac_exit(struct platform_device * pdev,void * priv)18094abdad6SFugang Duan static void imx_dwmac_exit(struct platform_device *pdev, void *priv)
18194abdad6SFugang Duan {
1828f2f8376SJoakim Zhang 	/* nothing to do now */
18394abdad6SFugang Duan }
18494abdad6SFugang Duan 
imx_dwmac_fix_speed(void * priv,unsigned int speed,unsigned int mode)1851fc04a0bSShenwei Wang static void imx_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode)
18694abdad6SFugang Duan {
18794abdad6SFugang Duan 	struct plat_stmmacenet_data *plat_dat;
18894abdad6SFugang Duan 	struct imx_priv_data *dwmac = priv;
18994abdad6SFugang Duan 	unsigned long rate;
19094abdad6SFugang Duan 	int err;
19194abdad6SFugang Duan 
19294abdad6SFugang Duan 	plat_dat = dwmac->plat_dat;
19394abdad6SFugang Duan 
19494abdad6SFugang Duan 	if (dwmac->ops->mac_rgmii_txclk_auto_adj ||
195*a014c355SRussell King (Oracle) 	    (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) ||
196*a014c355SRussell King (Oracle) 	    (plat_dat->mac_interface == PHY_INTERFACE_MODE_MII))
19794abdad6SFugang Duan 		return;
19894abdad6SFugang Duan 
19994abdad6SFugang Duan 	switch (speed) {
20094abdad6SFugang Duan 	case SPEED_1000:
20194abdad6SFugang Duan 		rate = 125000000;
20294abdad6SFugang Duan 		break;
20394abdad6SFugang Duan 	case SPEED_100:
20494abdad6SFugang Duan 		rate = 25000000;
20594abdad6SFugang Duan 		break;
20694abdad6SFugang Duan 	case SPEED_10:
20794abdad6SFugang Duan 		rate = 2500000;
20894abdad6SFugang Duan 		break;
20994abdad6SFugang Duan 	default:
21094abdad6SFugang Duan 		dev_err(dwmac->dev, "invalid speed %u\n", speed);
21194abdad6SFugang Duan 		return;
21294abdad6SFugang Duan 	}
21394abdad6SFugang Duan 
21494abdad6SFugang Duan 	err = clk_set_rate(dwmac->clk_tx, rate);
21594abdad6SFugang Duan 	if (err < 0)
21694abdad6SFugang Duan 		dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate);
21794abdad6SFugang Duan }
21894abdad6SFugang Duan 
imx93_dwmac_fix_speed(void * priv,unsigned int speed,unsigned int mode)2194fa6c976SShenwei Wang static void imx93_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode)
2204fa6c976SShenwei Wang {
2214fa6c976SShenwei Wang 	struct imx_priv_data *dwmac = priv;
2224fa6c976SShenwei Wang 	unsigned int iface;
2234fa6c976SShenwei Wang 	int ctrl, old_ctrl;
2244fa6c976SShenwei Wang 
2254fa6c976SShenwei Wang 	imx_dwmac_fix_speed(priv, speed, mode);
2264fa6c976SShenwei Wang 
2274fa6c976SShenwei Wang 	if (!dwmac || mode != MLO_AN_FIXED)
2284fa6c976SShenwei Wang 		return;
2294fa6c976SShenwei Wang 
2304fa6c976SShenwei Wang 	if (regmap_read(dwmac->intf_regmap, dwmac->intf_reg_off, &iface))
2314fa6c976SShenwei Wang 		return;
2324fa6c976SShenwei Wang 
2334fa6c976SShenwei Wang 	iface &= MX93_GPR_ENET_QOS_INTF_MASK;
2344fa6c976SShenwei Wang 	if (iface != MX93_GPR_ENET_QOS_INTF_SEL_RGMII)
2354fa6c976SShenwei Wang 		return;
2364fa6c976SShenwei Wang 
2374fa6c976SShenwei Wang 	old_ctrl = readl(dwmac->base_addr + MAC_CTRL_REG);
2384fa6c976SShenwei Wang 	ctrl = old_ctrl & ~CTRL_SPEED_MASK;
2394fa6c976SShenwei Wang 	regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
2404fa6c976SShenwei Wang 			   MX93_GPR_ENET_QOS_INTF_MODE_MASK, 0);
2414fa6c976SShenwei Wang 	writel(ctrl, dwmac->base_addr + MAC_CTRL_REG);
2424fa6c976SShenwei Wang 
2434fa6c976SShenwei Wang 	 /* Ensure the settings for CTRL are applied. */
2444fa6c976SShenwei Wang 	readl(dwmac->base_addr + MAC_CTRL_REG);
2454fa6c976SShenwei Wang 
2464fa6c976SShenwei Wang 	usleep_range(10, 20);
2474fa6c976SShenwei Wang 	iface |= MX93_GPR_ENET_QOS_CLK_GEN_EN;
2484fa6c976SShenwei Wang 	regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
2494fa6c976SShenwei Wang 			   MX93_GPR_ENET_QOS_INTF_MODE_MASK, iface);
2504fa6c976SShenwei Wang 
2514fa6c976SShenwei Wang 	writel(old_ctrl, dwmac->base_addr + MAC_CTRL_REG);
2524fa6c976SShenwei Wang }
2534fa6c976SShenwei Wang 
imx_dwmac_mx93_reset(void * priv,void __iomem * ioaddr)254b536f32bSShenwei Wang static int imx_dwmac_mx93_reset(void *priv, void __iomem *ioaddr)
255b536f32bSShenwei Wang {
256b536f32bSShenwei Wang 	struct plat_stmmacenet_data *plat_dat = priv;
257b536f32bSShenwei Wang 	u32 value = readl(ioaddr + DMA_BUS_MODE);
258b536f32bSShenwei Wang 
259b536f32bSShenwei Wang 	/* DMA SW reset */
260b536f32bSShenwei Wang 	value |= DMA_BUS_MODE_SFT_RESET;
261b536f32bSShenwei Wang 	writel(value, ioaddr + DMA_BUS_MODE);
262b536f32bSShenwei Wang 
263*a014c355SRussell King (Oracle) 	if (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) {
264b536f32bSShenwei Wang 		usleep_range(100, 200);
265b536f32bSShenwei Wang 		writel(RMII_RESET_SPEED, ioaddr + MAC_CTRL_REG);
266b536f32bSShenwei Wang 	}
267b536f32bSShenwei Wang 
268b536f32bSShenwei Wang 	return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,
269b536f32bSShenwei Wang 				 !(value & DMA_BUS_MODE_SFT_RESET),
270b536f32bSShenwei Wang 				 10000, 1000000);
271b536f32bSShenwei Wang }
272b536f32bSShenwei Wang 
27394abdad6SFugang Duan static int
imx_dwmac_parse_dt(struct imx_priv_data * dwmac,struct device * dev)27494abdad6SFugang Duan imx_dwmac_parse_dt(struct imx_priv_data *dwmac, struct device *dev)
27594abdad6SFugang Duan {
27694abdad6SFugang Duan 	struct device_node *np = dev->of_node;
27794abdad6SFugang Duan 	int err = 0;
27894abdad6SFugang Duan 
2791a87e641SRob Herring 	dwmac->rmii_refclk_ext = of_property_read_bool(np, "snps,rmii_refclk_ext");
28094abdad6SFugang Duan 
28194abdad6SFugang Duan 	dwmac->clk_tx = devm_clk_get(dev, "tx");
28294abdad6SFugang Duan 	if (IS_ERR(dwmac->clk_tx)) {
28394abdad6SFugang Duan 		dev_err(dev, "failed to get tx clock\n");
28494abdad6SFugang Duan 		return PTR_ERR(dwmac->clk_tx);
28594abdad6SFugang Duan 	}
28694abdad6SFugang Duan 
28794abdad6SFugang Duan 	dwmac->clk_mem = NULL;
288e5bf35caSClark Wang 
289e5bf35caSClark Wang 	if (of_machine_is_compatible("fsl,imx8dxl") ||
290e5bf35caSClark Wang 	    of_machine_is_compatible("fsl,imx93")) {
29194abdad6SFugang Duan 		dwmac->clk_mem = devm_clk_get(dev, "mem");
29294abdad6SFugang Duan 		if (IS_ERR(dwmac->clk_mem)) {
29394abdad6SFugang Duan 			dev_err(dev, "failed to get mem clock\n");
29494abdad6SFugang Duan 			return PTR_ERR(dwmac->clk_mem);
29594abdad6SFugang Duan 		}
29694abdad6SFugang Duan 	}
29794abdad6SFugang Duan 
298e5bf35caSClark Wang 	if (of_machine_is_compatible("fsl,imx8mp") ||
299e5bf35caSClark Wang 	    of_machine_is_compatible("fsl,imx93")) {
300e5bf35caSClark Wang 		/* Binding doc describes the propety:
301e5bf35caSClark Wang 		 * is required by i.MX8MP, i.MX93.
302e5bf35caSClark Wang 		 * is optinoal for i.MX8DXL.
30394abdad6SFugang Duan 		 */
30494abdad6SFugang Duan 		dwmac->intf_regmap = syscon_regmap_lookup_by_phandle(np, "intf_mode");
30594abdad6SFugang Duan 		if (IS_ERR(dwmac->intf_regmap))
30694abdad6SFugang Duan 			return PTR_ERR(dwmac->intf_regmap);
30794abdad6SFugang Duan 
30894abdad6SFugang Duan 		err = of_property_read_u32_index(np, "intf_mode", 1, &dwmac->intf_reg_off);
30994abdad6SFugang Duan 		if (err) {
31094abdad6SFugang Duan 			dev_err(dev, "Can't get intf mode reg offset (%d)\n", err);
31194abdad6SFugang Duan 			return err;
31294abdad6SFugang Duan 		}
31394abdad6SFugang Duan 	}
31494abdad6SFugang Duan 
31594abdad6SFugang Duan 	return err;
31694abdad6SFugang Duan }
31794abdad6SFugang Duan 
imx_dwmac_probe(struct platform_device * pdev)31894abdad6SFugang Duan static int imx_dwmac_probe(struct platform_device *pdev)
31994abdad6SFugang Duan {
32094abdad6SFugang Duan 	struct plat_stmmacenet_data *plat_dat;
32194abdad6SFugang Duan 	struct stmmac_resources stmmac_res;
32294abdad6SFugang Duan 	struct imx_priv_data *dwmac;
32394abdad6SFugang Duan 	const struct imx_dwmac_ops *data;
32494abdad6SFugang Duan 	int ret;
32594abdad6SFugang Duan 
32694abdad6SFugang Duan 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
32794abdad6SFugang Duan 	if (ret)
32894abdad6SFugang Duan 		return ret;
32994abdad6SFugang Duan 
33094abdad6SFugang Duan 	dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
33194abdad6SFugang Duan 	if (!dwmac)
332f6c1fb0aSDan Carpenter 		return -ENOMEM;
33394abdad6SFugang Duan 
33483216e39SMichael Walle 	plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
33594abdad6SFugang Duan 	if (IS_ERR(plat_dat))
33694abdad6SFugang Duan 		return PTR_ERR(plat_dat);
33794abdad6SFugang Duan 
33894abdad6SFugang Duan 	data = of_device_get_match_data(&pdev->dev);
33994abdad6SFugang Duan 	if (!data) {
34094abdad6SFugang Duan 		dev_err(&pdev->dev, "failed to get match data\n");
34194abdad6SFugang Duan 		ret = -EINVAL;
34294abdad6SFugang Duan 		goto err_match_data;
34394abdad6SFugang Duan 	}
34494abdad6SFugang Duan 
34594abdad6SFugang Duan 	dwmac->ops = data;
34694abdad6SFugang Duan 	dwmac->dev = &pdev->dev;
34794abdad6SFugang Duan 
34894abdad6SFugang Duan 	ret = imx_dwmac_parse_dt(dwmac, &pdev->dev);
34994abdad6SFugang Duan 	if (ret) {
35094abdad6SFugang Duan 		dev_err(&pdev->dev, "failed to parse OF data\n");
35194abdad6SFugang Duan 		goto err_parse_dt;
35294abdad6SFugang Duan 	}
35394abdad6SFugang Duan 
3546cb2e613SJohannes Zink 	if (data->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
3556cb2e613SJohannes Zink 		plat_dat->flags |= STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY;
3566cb2e613SJohannes Zink 
357070246e4SJochen Henneberg 	plat_dat->host_dma_width = dwmac->ops->addr_width;
35894abdad6SFugang Duan 	plat_dat->init = imx_dwmac_init;
35994abdad6SFugang Duan 	plat_dat->exit = imx_dwmac_exit;
3608f2f8376SJoakim Zhang 	plat_dat->clks_config = imx_dwmac_clks_config;
36194abdad6SFugang Duan 	plat_dat->fix_mac_speed = imx_dwmac_fix_speed;
36294abdad6SFugang Duan 	plat_dat->bsp_priv = dwmac;
36394abdad6SFugang Duan 	dwmac->plat_dat = plat_dat;
3644fa6c976SShenwei Wang 	dwmac->base_addr = stmmac_res.addr;
36594abdad6SFugang Duan 
3668f2f8376SJoakim Zhang 	ret = imx_dwmac_clks_config(dwmac, true);
3678f2f8376SJoakim Zhang 	if (ret)
3688f2f8376SJoakim Zhang 		goto err_clks_config;
3698f2f8376SJoakim Zhang 
37094abdad6SFugang Duan 	ret = imx_dwmac_init(pdev, dwmac);
37194abdad6SFugang Duan 	if (ret)
37294abdad6SFugang Duan 		goto err_dwmac_init;
37394abdad6SFugang Duan 
3744fa6c976SShenwei Wang 	if (dwmac->ops->fix_mac_speed)
3754fa6c976SShenwei Wang 		plat_dat->fix_mac_speed = dwmac->ops->fix_mac_speed;
376b536f32bSShenwei Wang 	dwmac->plat_dat->fix_soc_reset = dwmac->ops->fix_soc_reset;
377b536f32bSShenwei Wang 
37894abdad6SFugang Duan 	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
37994abdad6SFugang Duan 	if (ret)
38094abdad6SFugang Duan 		goto err_drv_probe;
38194abdad6SFugang Duan 
38294abdad6SFugang Duan 	return 0;
38394abdad6SFugang Duan 
38494abdad6SFugang Duan err_drv_probe:
38594abdad6SFugang Duan 	imx_dwmac_exit(pdev, plat_dat->bsp_priv);
3868f2f8376SJoakim Zhang err_dwmac_init:
3878f2f8376SJoakim Zhang 	imx_dwmac_clks_config(dwmac, false);
3888f2f8376SJoakim Zhang err_clks_config:
38994abdad6SFugang Duan err_parse_dt:
39094abdad6SFugang Duan err_match_data:
39194abdad6SFugang Duan 	stmmac_remove_config_dt(pdev, plat_dat);
39294abdad6SFugang Duan 	return ret;
39394abdad6SFugang Duan }
39494abdad6SFugang Duan 
39594abdad6SFugang Duan static struct imx_dwmac_ops imx8mp_dwmac_data = {
39694abdad6SFugang Duan 	.addr_width = 34,
39794abdad6SFugang Duan 	.mac_rgmii_txclk_auto_adj = false,
39894abdad6SFugang Duan 	.set_intf_mode = imx8mp_set_intf_mode,
3996cb2e613SJohannes Zink 	.flags = STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY,
40094abdad6SFugang Duan };
40194abdad6SFugang Duan 
40294abdad6SFugang Duan static struct imx_dwmac_ops imx8dxl_dwmac_data = {
40394abdad6SFugang Duan 	.addr_width = 32,
40494abdad6SFugang Duan 	.mac_rgmii_txclk_auto_adj = true,
40594abdad6SFugang Duan 	.set_intf_mode = imx8dxl_set_intf_mode,
40694abdad6SFugang Duan };
40794abdad6SFugang Duan 
408e5bf35caSClark Wang static struct imx_dwmac_ops imx93_dwmac_data = {
409e5bf35caSClark Wang 	.addr_width = 32,
410e5bf35caSClark Wang 	.mac_rgmii_txclk_auto_adj = true,
411e5bf35caSClark Wang 	.set_intf_mode = imx93_set_intf_mode,
412b536f32bSShenwei Wang 	.fix_soc_reset = imx_dwmac_mx93_reset,
4134fa6c976SShenwei Wang 	.fix_mac_speed = imx93_dwmac_fix_speed,
414e5bf35caSClark Wang };
415e5bf35caSClark Wang 
41694abdad6SFugang Duan static const struct of_device_id imx_dwmac_match[] = {
41794abdad6SFugang Duan 	{ .compatible = "nxp,imx8mp-dwmac-eqos", .data = &imx8mp_dwmac_data },
41894abdad6SFugang Duan 	{ .compatible = "nxp,imx8dxl-dwmac-eqos", .data = &imx8dxl_dwmac_data },
419e5bf35caSClark Wang 	{ .compatible = "nxp,imx93-dwmac-eqos", .data = &imx93_dwmac_data },
42094abdad6SFugang Duan 	{ }
42194abdad6SFugang Duan };
42294abdad6SFugang Duan MODULE_DEVICE_TABLE(of, imx_dwmac_match);
42394abdad6SFugang Duan 
42494abdad6SFugang Duan static struct platform_driver imx_dwmac_driver = {
42594abdad6SFugang Duan 	.probe  = imx_dwmac_probe,
4263246627fSUwe Kleine-König 	.remove_new = stmmac_pltfr_remove,
42794abdad6SFugang Duan 	.driver = {
42894abdad6SFugang Duan 		.name           = "imx-dwmac",
42994abdad6SFugang Duan 		.pm		= &stmmac_pltfr_pm_ops,
43094abdad6SFugang Duan 		.of_match_table = imx_dwmac_match,
43194abdad6SFugang Duan 	},
43294abdad6SFugang Duan };
43394abdad6SFugang Duan module_platform_driver(imx_dwmac_driver);
43494abdad6SFugang Duan 
43594abdad6SFugang Duan MODULE_AUTHOR("NXP");
43694abdad6SFugang Duan MODULE_DESCRIPTION("NXP imx8 DWMAC Specific Glue layer");
43794abdad6SFugang Duan MODULE_LICENSE("GPL v2");
438