xref: /linux/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 /*
2  * Qualcomm Atheros IPQ806x GMAC glue layer
3  *
4  * Copyright (C) 2015 The Linux Foundation
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <linux/device.h>
20 #include <linux/platform_device.h>
21 #include <linux/phy.h>
22 #include <linux/regmap.h>
23 #include <linux/clk.h>
24 #include <linux/reset.h>
25 #include <linux/of_net.h>
26 #include <linux/mfd/syscon.h>
27 #include <linux/stmmac.h>
28 #include <linux/of_mdio.h>
29 #include <linux/module.h>
30 #include <linux/sys_soc.h>
31 #include <linux/bitfield.h>
32 
33 #include "stmmac_platform.h"
34 
35 #define NSS_COMMON_CLK_GATE			0x8
36 #define NSS_COMMON_CLK_GATE_PTP_EN(x)		BIT(0x10 + x)
37 #define NSS_COMMON_CLK_GATE_RGMII_RX_EN(x)	BIT(0x9 + (x * 2))
38 #define NSS_COMMON_CLK_GATE_RGMII_TX_EN(x)	BIT(0x8 + (x * 2))
39 #define NSS_COMMON_CLK_GATE_GMII_RX_EN(x)	BIT(0x4 + x)
40 #define NSS_COMMON_CLK_GATE_GMII_TX_EN(x)	BIT(0x0 + x)
41 
42 #define NSS_COMMON_CLK_DIV0			0xC
43 #define NSS_COMMON_CLK_DIV_OFFSET(x)		(x * 8)
44 #define NSS_COMMON_CLK_DIV_MASK			0x7f
45 
46 #define NSS_COMMON_CLK_SRC_CTRL			0x14
47 #define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x)	(x)
48 /* Mode is coded on 1 bit but is different depending on the MAC ID:
49  * MAC0: QSGMII=0 RGMII=1
50  * MAC1: QSGMII=0 SGMII=0 RGMII=1
51  * MAC2 & MAC3: QSGMII=0 SGMII=1
52  */
53 #define NSS_COMMON_CLK_SRC_CTRL_RGMII(x)	1
54 #define NSS_COMMON_CLK_SRC_CTRL_SGMII(x)	((x >= 2) ? 1 : 0)
55 
56 #define NSS_COMMON_GMAC_CTL(x)			(0x30 + (x * 4))
57 #define NSS_COMMON_GMAC_CTL_CSYS_REQ		BIT(19)
58 #define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL	BIT(16)
59 #define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET	8
60 #define NSS_COMMON_GMAC_CTL_IFG_OFFSET		0
61 
62 #define NSS_COMMON_CLK_DIV_RGMII_1000		1
63 #define NSS_COMMON_CLK_DIV_RGMII_100		9
64 #define NSS_COMMON_CLK_DIV_RGMII_10		99
65 #define NSS_COMMON_CLK_DIV_SGMII_1000		0
66 #define NSS_COMMON_CLK_DIV_SGMII_100		4
67 #define NSS_COMMON_CLK_DIV_SGMII_10		49
68 
69 #define QSGMII_PCS_ALL_CH_CTL			0x80
70 #define QSGMII_PCS_CH_SPEED_FORCE		BIT(1)
71 #define QSGMII_PCS_CH_SPEED_10			0x0
72 #define QSGMII_PCS_CH_SPEED_100			BIT(2)
73 #define QSGMII_PCS_CH_SPEED_1000		BIT(3)
74 #define QSGMII_PCS_CH_SPEED_MASK		(QSGMII_PCS_CH_SPEED_FORCE | \
75 						 QSGMII_PCS_CH_SPEED_10 | \
76 						 QSGMII_PCS_CH_SPEED_100 | \
77 						 QSGMII_PCS_CH_SPEED_1000)
78 #define QSGMII_PCS_CH_SPEED_SHIFT(x)		((x) * 4)
79 
80 #define QSGMII_PCS_CAL_LCKDT_CTL		0x120
81 #define QSGMII_PCS_CAL_LCKDT_CTL_RST		BIT(19)
82 
83 /* Only GMAC1/2/3 support SGMII and their CTL register are not contiguous */
84 #define QSGMII_PHY_SGMII_CTL(x)			((x == 1) ? 0x134 : \
85 						 (0x13c + (4 * (x - 2))))
86 #define QSGMII_PHY_CDR_EN			BIT(0)
87 #define QSGMII_PHY_RX_FRONT_EN			BIT(1)
88 #define QSGMII_PHY_RX_SIGNAL_DETECT_EN		BIT(2)
89 #define QSGMII_PHY_TX_DRIVER_EN			BIT(3)
90 #define QSGMII_PHY_QSGMII_EN			BIT(7)
91 #define QSGMII_PHY_DEEMPHASIS_LVL_MASK		GENMASK(11, 10)
92 #define QSGMII_PHY_DEEMPHASIS_LVL(x)		FIELD_PREP(QSGMII_PHY_DEEMPHASIS_LVL_MASK, (x))
93 #define QSGMII_PHY_PHASE_LOOP_GAIN_MASK		GENMASK(14, 12)
94 #define QSGMII_PHY_PHASE_LOOP_GAIN(x)		FIELD_PREP(QSGMII_PHY_PHASE_LOOP_GAIN_MASK, (x))
95 #define QSGMII_PHY_RX_DC_BIAS_MASK		GENMASK(19, 18)
96 #define QSGMII_PHY_RX_DC_BIAS(x)		FIELD_PREP(QSGMII_PHY_RX_DC_BIAS_MASK, (x))
97 #define QSGMII_PHY_RX_INPUT_EQU_MASK		GENMASK(21, 20)
98 #define QSGMII_PHY_RX_INPUT_EQU(x)		FIELD_PREP(QSGMII_PHY_RX_INPUT_EQU_MASK, (x))
99 #define QSGMII_PHY_CDR_PI_SLEW_MASK		GENMASK(23, 22)
100 #define QSGMII_PHY_CDR_PI_SLEW(x)		FIELD_PREP(QSGMII_PHY_CDR_PI_SLEW_MASK, (x))
101 #define QSGMII_PHY_TX_SLEW_MASK			GENMASK(27, 26)
102 #define QSGMII_PHY_TX_SLEW(x)			FIELD_PREP(QSGMII_PHY_TX_SLEW_MASK, (x))
103 #define QSGMII_PHY_TX_DRV_AMP_MASK		GENMASK(31, 28)
104 #define QSGMII_PHY_TX_DRV_AMP(x)		FIELD_PREP(QSGMII_PHY_TX_DRV_AMP_MASK, (x))
105 
106 struct ipq806x_gmac {
107 	struct platform_device *pdev;
108 	struct regmap *nss_common;
109 	struct regmap *qsgmii_csr;
110 	uint32_t id;
111 	struct clk *core_clk;
112 	phy_interface_t phy_mode;
113 };
114 
115 static int get_clk_div_sgmii(struct ipq806x_gmac *gmac, unsigned int speed)
116 {
117 	struct device *dev = &gmac->pdev->dev;
118 	int div;
119 
120 	switch (speed) {
121 	case SPEED_1000:
122 		div = NSS_COMMON_CLK_DIV_SGMII_1000;
123 		break;
124 
125 	case SPEED_100:
126 		div = NSS_COMMON_CLK_DIV_SGMII_100;
127 		break;
128 
129 	case SPEED_10:
130 		div = NSS_COMMON_CLK_DIV_SGMII_10;
131 		break;
132 
133 	default:
134 		dev_err(dev, "Speed %dMbps not supported in SGMII\n", speed);
135 		return -EINVAL;
136 	}
137 
138 	return div;
139 }
140 
141 static int get_clk_div_rgmii(struct ipq806x_gmac *gmac, unsigned int speed)
142 {
143 	struct device *dev = &gmac->pdev->dev;
144 	int div;
145 
146 	switch (speed) {
147 	case SPEED_1000:
148 		div = NSS_COMMON_CLK_DIV_RGMII_1000;
149 		break;
150 
151 	case SPEED_100:
152 		div = NSS_COMMON_CLK_DIV_RGMII_100;
153 		break;
154 
155 	case SPEED_10:
156 		div = NSS_COMMON_CLK_DIV_RGMII_10;
157 		break;
158 
159 	default:
160 		dev_err(dev, "Speed %dMbps not supported in RGMII\n", speed);
161 		return -EINVAL;
162 	}
163 
164 	return div;
165 }
166 
167 static int ipq806x_gmac_set_speed(struct ipq806x_gmac *gmac, unsigned int speed)
168 {
169 	uint32_t clk_bits, val;
170 	int div;
171 
172 	switch (gmac->phy_mode) {
173 	case PHY_INTERFACE_MODE_RGMII:
174 	case PHY_INTERFACE_MODE_RGMII_ID:
175 	case PHY_INTERFACE_MODE_RGMII_RXID:
176 	case PHY_INTERFACE_MODE_RGMII_TXID:
177 		div = get_clk_div_rgmii(gmac, speed);
178 		clk_bits = NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
179 			   NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
180 		break;
181 
182 	case PHY_INTERFACE_MODE_SGMII:
183 		div = get_clk_div_sgmii(gmac, speed);
184 		clk_bits = NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) |
185 			   NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id);
186 		break;
187 
188 	default:
189 		dev_err(&gmac->pdev->dev, "Unsupported PHY mode: \"%s\"\n",
190 			phy_modes(gmac->phy_mode));
191 		return -EINVAL;
192 	}
193 
194 	/* Disable the clocks */
195 	regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
196 	val &= ~clk_bits;
197 	regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
198 
199 	/* Set the divider */
200 	regmap_read(gmac->nss_common, NSS_COMMON_CLK_DIV0, &val);
201 	val &= ~(NSS_COMMON_CLK_DIV_MASK
202 		 << NSS_COMMON_CLK_DIV_OFFSET(gmac->id));
203 	val |= div << NSS_COMMON_CLK_DIV_OFFSET(gmac->id);
204 	regmap_write(gmac->nss_common, NSS_COMMON_CLK_DIV0, val);
205 
206 	/* Enable the clock back */
207 	regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
208 	val |= clk_bits;
209 	regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
210 
211 	return 0;
212 }
213 
214 static int ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
215 {
216 	struct device *dev = &gmac->pdev->dev;
217 	int ret;
218 
219 	ret = of_get_phy_mode(dev->of_node, &gmac->phy_mode);
220 	if (ret) {
221 		dev_err(dev, "missing phy mode property\n");
222 		return -EINVAL;
223 	}
224 
225 	if (of_property_read_u32(dev->of_node, "qcom,id", &gmac->id) < 0) {
226 		dev_err(dev, "missing qcom id property\n");
227 		return -EINVAL;
228 	}
229 
230 	/* The GMACs are called 1 to 4 in the documentation, but to simplify the
231 	 * code and keep it consistent with the Linux convention, we'll number
232 	 * them from 0 to 3 here.
233 	 */
234 	if (gmac->id > 3) {
235 		dev_err(dev, "invalid gmac id\n");
236 		return -EINVAL;
237 	}
238 
239 	gmac->core_clk = devm_clk_get(dev, "stmmaceth");
240 	if (IS_ERR(gmac->core_clk)) {
241 		dev_err(dev, "missing stmmaceth clk property\n");
242 		return PTR_ERR(gmac->core_clk);
243 	}
244 	clk_set_rate(gmac->core_clk, 266000000);
245 
246 	/* Setup the register map for the nss common registers */
247 	gmac->nss_common = syscon_regmap_lookup_by_phandle(dev->of_node,
248 							   "qcom,nss-common");
249 	if (IS_ERR(gmac->nss_common)) {
250 		dev_err(dev, "missing nss-common node\n");
251 		return PTR_ERR(gmac->nss_common);
252 	}
253 
254 	/* Setup the register map for the qsgmii csr registers */
255 	gmac->qsgmii_csr = syscon_regmap_lookup_by_phandle(dev->of_node,
256 							   "qcom,qsgmii-csr");
257 	if (IS_ERR(gmac->qsgmii_csr))
258 		dev_err(dev, "missing qsgmii-csr node\n");
259 
260 	return PTR_ERR_OR_ZERO(gmac->qsgmii_csr);
261 }
262 
263 static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
264 {
265 	struct ipq806x_gmac *gmac = priv;
266 
267 	ipq806x_gmac_set_speed(gmac, speed);
268 }
269 
270 static int
271 ipq806x_gmac_configure_qsgmii_pcs_speed(struct ipq806x_gmac *gmac)
272 {
273 	struct platform_device *pdev = gmac->pdev;
274 	struct device *dev = &pdev->dev;
275 	struct device_node *dn;
276 	int link_speed;
277 	int val = 0;
278 	int ret;
279 
280 	/* Some bootloader may apply wrong configuration and cause
281 	 * not functioning port. If fixed link is not set,
282 	 * reset the force speed bit.
283 	 */
284 	if (!of_phy_is_fixed_link(pdev->dev.of_node))
285 		goto write;
286 
287 	dn = of_get_child_by_name(pdev->dev.of_node, "fixed-link");
288 	ret = of_property_read_u32(dn, "speed", &link_speed);
289 	of_node_put(dn);
290 	if (ret) {
291 		dev_err(dev, "found fixed-link node with no speed");
292 		return ret;
293 	}
294 
295 	val = QSGMII_PCS_CH_SPEED_FORCE;
296 
297 	switch (link_speed) {
298 	case SPEED_1000:
299 		val |= QSGMII_PCS_CH_SPEED_1000;
300 		break;
301 	case SPEED_100:
302 		val |= QSGMII_PCS_CH_SPEED_100;
303 		break;
304 	case SPEED_10:
305 		val |= QSGMII_PCS_CH_SPEED_10;
306 		break;
307 	}
308 
309 write:
310 	regmap_update_bits(gmac->qsgmii_csr, QSGMII_PCS_ALL_CH_CTL,
311 			   QSGMII_PCS_CH_SPEED_MASK <<
312 			   QSGMII_PCS_CH_SPEED_SHIFT(gmac->id),
313 			   val <<
314 			   QSGMII_PCS_CH_SPEED_SHIFT(gmac->id));
315 
316 	return 0;
317 }
318 
319 static const struct soc_device_attribute ipq806x_gmac_soc_v1[] = {
320 	{
321 		.revision = "1.*",
322 	},
323 	{
324 		/* sentinel */
325 	}
326 };
327 
328 static int
329 ipq806x_gmac_configure_qsgmii_params(struct ipq806x_gmac *gmac)
330 {
331 	struct platform_device *pdev = gmac->pdev;
332 	const struct soc_device_attribute *soc;
333 	struct device *dev = &pdev->dev;
334 	u32 qsgmii_param;
335 
336 	switch (gmac->id) {
337 	case 1:
338 		soc = soc_device_match(ipq806x_gmac_soc_v1);
339 
340 		if (soc)
341 			qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xc) |
342 				       QSGMII_PHY_TX_SLEW(0x2) |
343 				       QSGMII_PHY_DEEMPHASIS_LVL(0x2);
344 		else
345 			qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xd) |
346 				       QSGMII_PHY_TX_SLEW(0x0) |
347 				       QSGMII_PHY_DEEMPHASIS_LVL(0x0);
348 
349 		qsgmii_param |= QSGMII_PHY_RX_DC_BIAS(0x2);
350 		break;
351 	case 2:
352 	case 3:
353 		qsgmii_param = QSGMII_PHY_RX_DC_BIAS(0x3) |
354 			       QSGMII_PHY_TX_DRV_AMP(0xc);
355 		break;
356 	default: /* gmac 0 can't be set in SGMII mode */
357 		dev_err(dev, "gmac id %d can't be in SGMII mode", gmac->id);
358 		return -EINVAL;
359 	}
360 
361 	/* Common params across all gmac id */
362 	qsgmii_param |= QSGMII_PHY_CDR_EN |
363 			QSGMII_PHY_RX_FRONT_EN |
364 			QSGMII_PHY_RX_SIGNAL_DETECT_EN |
365 			QSGMII_PHY_TX_DRIVER_EN |
366 			QSGMII_PHY_QSGMII_EN |
367 			QSGMII_PHY_PHASE_LOOP_GAIN(0x4) |
368 			QSGMII_PHY_RX_INPUT_EQU(0x1) |
369 			QSGMII_PHY_CDR_PI_SLEW(0x2);
370 
371 	regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
372 		     qsgmii_param);
373 
374 	return 0;
375 }
376 
377 static int ipq806x_gmac_probe(struct platform_device *pdev)
378 {
379 	struct plat_stmmacenet_data *plat_dat;
380 	struct stmmac_resources stmmac_res;
381 	struct device *dev = &pdev->dev;
382 	struct ipq806x_gmac *gmac;
383 	int val;
384 	int err;
385 
386 	val = stmmac_get_platform_resources(pdev, &stmmac_res);
387 	if (val)
388 		return val;
389 
390 	plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
391 	if (IS_ERR(plat_dat))
392 		return PTR_ERR(plat_dat);
393 
394 	gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
395 	if (!gmac)
396 		return -ENOMEM;
397 
398 	gmac->pdev = pdev;
399 
400 	err = ipq806x_gmac_of_parse(gmac);
401 	if (err) {
402 		dev_err(dev, "device tree parsing error\n");
403 		return err;
404 	}
405 
406 	regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL,
407 		     QSGMII_PCS_CAL_LCKDT_CTL_RST);
408 
409 	/* Inter frame gap is set to 12 */
410 	val = 12 << NSS_COMMON_GMAC_CTL_IFG_OFFSET |
411 	      12 << NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET;
412 	/* We also initiate an AXI low power exit request */
413 	val |= NSS_COMMON_GMAC_CTL_CSYS_REQ;
414 	switch (gmac->phy_mode) {
415 	case PHY_INTERFACE_MODE_RGMII:
416 	case PHY_INTERFACE_MODE_RGMII_ID:
417 	case PHY_INTERFACE_MODE_RGMII_RXID:
418 	case PHY_INTERFACE_MODE_RGMII_TXID:
419 		val |= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
420 		break;
421 	case PHY_INTERFACE_MODE_SGMII:
422 		val &= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
423 		break;
424 	default:
425 		goto err_unsupported_phy;
426 	}
427 	regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val);
428 
429 	/* Configure the clock src according to the mode */
430 	regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val);
431 	val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id));
432 	switch (gmac->phy_mode) {
433 	case PHY_INTERFACE_MODE_RGMII:
434 	case PHY_INTERFACE_MODE_RGMII_ID:
435 	case PHY_INTERFACE_MODE_RGMII_RXID:
436 	case PHY_INTERFACE_MODE_RGMII_TXID:
437 		val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
438 			NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
439 		break;
440 	case PHY_INTERFACE_MODE_SGMII:
441 		val |= NSS_COMMON_CLK_SRC_CTRL_SGMII(gmac->id) <<
442 			NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
443 		break;
444 	default:
445 		goto err_unsupported_phy;
446 	}
447 	regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val);
448 
449 	/* Enable PTP clock */
450 	regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
451 	val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id);
452 	switch (gmac->phy_mode) {
453 	case PHY_INTERFACE_MODE_RGMII:
454 	case PHY_INTERFACE_MODE_RGMII_ID:
455 	case PHY_INTERFACE_MODE_RGMII_RXID:
456 	case PHY_INTERFACE_MODE_RGMII_TXID:
457 		val |= NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
458 			NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
459 		break;
460 	case PHY_INTERFACE_MODE_SGMII:
461 		val |= NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) |
462 				NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id);
463 		break;
464 	default:
465 		goto err_unsupported_phy;
466 	}
467 	regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
468 
469 	if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
470 		err = ipq806x_gmac_configure_qsgmii_params(gmac);
471 		if (err)
472 			return err;
473 
474 		err = ipq806x_gmac_configure_qsgmii_pcs_speed(gmac);
475 		if (err)
476 			return err;
477 	}
478 
479 	plat_dat->has_gmac = true;
480 	plat_dat->bsp_priv = gmac;
481 	plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed;
482 	plat_dat->multicast_filter_bins = 0;
483 	plat_dat->tx_fifo_size = 8192;
484 	plat_dat->rx_fifo_size = 8192;
485 
486 	return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
487 
488 err_unsupported_phy:
489 	dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
490 		phy_modes(gmac->phy_mode));
491 	return -EINVAL;
492 }
493 
494 static const struct of_device_id ipq806x_gmac_dwmac_match[] = {
495 	{ .compatible = "qcom,ipq806x-gmac" },
496 	{ }
497 };
498 MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match);
499 
500 static struct platform_driver ipq806x_gmac_dwmac_driver = {
501 	.probe = ipq806x_gmac_probe,
502 	.remove_new = stmmac_pltfr_remove,
503 	.driver = {
504 		.name		= "ipq806x-gmac-dwmac",
505 		.pm		= &stmmac_pltfr_pm_ops,
506 		.of_match_table	= ipq806x_gmac_dwmac_match,
507 	},
508 };
509 module_platform_driver(ipq806x_gmac_dwmac_driver);
510 
511 MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>");
512 MODULE_DESCRIPTION("Qualcomm Atheros IPQ806x DWMAC specific glue layer");
513 MODULE_LICENSE("Dual BSD/GPL");
514