aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-12-12 18:21:01 -0500
committerDavid S. Miller <davem@davemloft.net>2018-12-12 18:21:01 -0500
commit9a58ee2f00fb558297c44f69833e408fdadd26db (patch)
treedeb51223f0dae62465b6497dff9e3609ea7ac72f
parent3f9b7eeea0268eba57e2c18b48a9621f38c66101 (diff)
parent58ee90284ffa495b04d56d643001d6f64a13a580 (diff)
Merge branch 'stmmac-mt2712-support'
Biao Huang says: ==================== add Ethernet driver support for mt2712 Changes in v6: modifications according to comments from Rob/Andrew/Sean: 1. use delay_ps instead of delay stage. 2. add comments in driver to avoid confusion. 2. rewrite set_delay function. 3. modify binding document for properties: tx-delay-ps/rx-delay-ps/pericfg etc. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/devicetree/bindings/net/mediatek-dwmac.txt87
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c408
4 files changed, 504 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/net/mediatek-dwmac.txt b/Documentation/devicetree/bindings/net/mediatek-dwmac.txt
new file mode 100644
index 000000000000..4de479b4d44d
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/mediatek-dwmac.txt
@@ -0,0 +1,87 @@
1MediaTek DWMAC glue layer controller
2
3This file documents platform glue layer for stmmac.
4Please see stmmac.txt for the other unchanged properties.
5
6The device node has following properties.
7
8Required properties:
9- compatible: Should be "mediatek,mt2712-gmac" for MT2712 SoC
10- reg: Address and length of the register set for the device
11- interrupts: Should contain the MAC interrupts
12- interrupt-names: Should contain a list of interrupt names corresponding to
13 the interrupts in the interrupts property, if available.
14 Should be "macirq" for the main MAC IRQ
15- clocks: Must contain a phandle for each entry in clock-names.
16- clock-names: The name of the clock listed in the clocks property. These are
17 "axi", "apb", "mac_main", "ptp_ref" for MT2712 SoC
18- mac-address: See ethernet.txt in the same directory
19- phy-mode: See ethernet.txt in the same directory
20- mediatek,pericfg: A phandle to the syscon node that control ethernet
21 interface and timing delay.
22
23Optional properties:
24- mediatek,tx-delay-ps: TX clock delay macro value. Default is 0.
25 It should be defined for rgmii/rgmii-rxid/mii interface.
26- mediatek,rx-delay-ps: RX clock delay macro value. Default is 0.
27 It should be defined for rgmii/rgmii-txid/mii/rmii interface.
28Both delay properties need to be a multiple of 170 for fine-tune rgmii,
29range 0~31*170.
30Both delay properties need to be a multiple of 550 for coarse-tune rgmii,
31range 0~31*550.
32Both delay properties need to be a multiple of 550 for mii/rmii,
33range 0~31*550.
34
35- mediatek,fine-tune: boolean property, if present indicates that fine delay
36 is selected for rgmii interface.
37 If present, tx-delay-ps/rx-delay-ps is 170+/-50ps per stage.
38 Else tx-delay-ps/rx-delay-ps of coarse delay macro is 0.55+/-0.2ns per stage.
39 This property do not apply to non-rgmii PHYs.
40 Only coarse-tune delay is supported for mii/rmii PHYs.
41- mediatek,rmii-rxc: boolean property, if present indicates that the rmii
42 reference clock, which is from external PHYs, is connected to RXC pin
43 on MT2712 SoC.
44 Otherwise, is connected to TXC pin.
45- mediatek,txc-inverse: boolean property, if present indicates that
46 1. tx clock will be inversed in mii/rgmii case,
47 2. tx clock inside MAC will be inversed relative to reference clock
48 which is from external PHYs in rmii case, and it rarely happen.
49- mediatek,rxc-inverse: boolean property, if present indicates that
50 1. rx clock will be inversed in mii/rgmii case.
51 2. reference clock will be inversed when arrived at MAC in rmii case.
52- assigned-clocks: mac_main and ptp_ref clocks
53- assigned-clock-parents: parent clocks of the assigned clocks
54
55Example:
56 eth: ethernet@1101c000 {
57 compatible = "mediatek,mt2712-gmac";
58 reg = <0 0x1101c000 0 0x1300>;
59 interrupts = <GIC_SPI 237 IRQ_TYPE_LEVEL_LOW>;
60 interrupt-names = "macirq";
61 phy-mode ="rgmii";
62 mac-address = [00 55 7b b5 7d f7];
63 clock-names = "axi",
64 "apb",
65 "mac_main",
66 "ptp_ref",
67 "ptp_top";
68 clocks = <&pericfg CLK_PERI_GMAC>,
69 <&pericfg CLK_PERI_GMAC_PCLK>,
70 <&topckgen CLK_TOP_ETHER_125M_SEL>,
71 <&topckgen CLK_TOP_ETHER_50M_SEL>;
72 assigned-clocks = <&topckgen CLK_TOP_ETHER_125M_SEL>,
73 <&topckgen CLK_TOP_ETHER_50M_SEL>;
74 assigned-clock-parents = <&topckgen CLK_TOP_ETHERPLL_125M>,
75 <&topckgen CLK_TOP_APLL1_D3>;
76 mediatek,pericfg = <&pericfg>;
77 mediatek,tx-delay-ps = <1530>;
78 mediatek,rx-delay-ps = <1530>;
79 mediatek,fine-tune;
80 mediatek,rmii-rxc;
81 mediatek,txc-inverse;
82 mediatek,rxc-inverse;
83 snps,txpbl = <32>;
84 snps,rxpbl = <32>;
85 snps,reset-gpio = <&pio 87 GPIO_ACTIVE_LOW>;
86 snps,reset-active-low;
87 };
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 324049eebb9b..6209cc1fb305 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -75,6 +75,14 @@ config DWMAC_LPC18XX
75 ---help--- 75 ---help---
76 Support for NXP LPC18xx/43xx DWMAC Ethernet. 76 Support for NXP LPC18xx/43xx DWMAC Ethernet.
77 77
78config DWMAC_MEDIATEK
79 tristate "MediaTek MT27xx GMAC support"
80 depends on OF && (ARCH_MEDIATEK || COMPILE_TEST)
81 help
82 Support for MediaTek GMAC Ethernet controller.
83
84 This selects the MT2712 SoC support for the stmmac driver.
85
78config DWMAC_MESON 86config DWMAC_MESON
79 tristate "Amlogic Meson dwmac support" 87 tristate "Amlogic Meson dwmac support"
80 default ARCH_MESON 88 default ARCH_MESON
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 99967a80a8c8..bf09701d2623 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
13obj-$(CONFIG_DWMAC_ANARION) += dwmac-anarion.o 13obj-$(CONFIG_DWMAC_ANARION) += dwmac-anarion.o
14obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o 14obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
15obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o 15obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
16obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o
16obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o 17obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o
17obj-$(CONFIG_DWMAC_OXNAS) += dwmac-oxnas.o 18obj-$(CONFIG_DWMAC_OXNAS) += dwmac-oxnas.o
18obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o 19obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
new file mode 100644
index 000000000000..b5db85d298e7
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -0,0 +1,408 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018 MediaTek Inc.
4 */
5#include <linux/bitfield.h>
6#include <linux/io.h>
7#include <linux/mfd/syscon.h>
8#include <linux/of.h>
9#include <linux/of_device.h>
10#include <linux/of_net.h>
11#include <linux/regmap.h>
12#include <linux/stmmac.h>
13
14#include "stmmac.h"
15#include "stmmac_platform.h"
16
17/* Peri Configuration register for mt2712 */
18#define PERI_ETH_PHY_INTF_SEL 0x418
19#define PHY_INTF_MII 0
20#define PHY_INTF_RGMII 1
21#define PHY_INTF_RMII 4
22#define RMII_CLK_SRC_RXC BIT(4)
23#define RMII_CLK_SRC_INTERNAL BIT(5)
24
25#define PERI_ETH_DLY 0x428
26#define ETH_DLY_GTXC_INV BIT(6)
27#define ETH_DLY_GTXC_ENABLE BIT(5)
28#define ETH_DLY_GTXC_STAGES GENMASK(4, 0)
29#define ETH_DLY_TXC_INV BIT(20)
30#define ETH_DLY_TXC_ENABLE BIT(19)
31#define ETH_DLY_TXC_STAGES GENMASK(18, 14)
32#define ETH_DLY_RXC_INV BIT(13)
33#define ETH_DLY_RXC_ENABLE BIT(12)
34#define ETH_DLY_RXC_STAGES GENMASK(11, 7)
35
36#define PERI_ETH_DLY_FINE 0x800
37#define ETH_RMII_DLY_TX_INV BIT(2)
38#define ETH_FINE_DLY_GTXC BIT(1)
39#define ETH_FINE_DLY_RXC BIT(0)
40
41struct mac_delay_struct {
42 u32 tx_delay;
43 u32 rx_delay;
44 bool tx_inv;
45 bool rx_inv;
46 bool fine_tune;
47};
48
49struct mediatek_dwmac_plat_data {
50 const struct mediatek_dwmac_variant *variant;
51 struct mac_delay_struct mac_delay;
52 struct clk_bulk_data *clks;
53 struct device_node *np;
54 struct regmap *peri_regmap;
55 struct device *dev;
56 int phy_mode;
57 bool rmii_rxc;
58};
59
60struct mediatek_dwmac_variant {
61 int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat);
62 int (*dwmac_set_delay)(struct mediatek_dwmac_plat_data *plat);
63
64 /* clock ids to be requested */
65 const char * const *clk_list;
66 int num_clks;
67
68 u32 dma_bit_mask;
69 u32 rx_delay_max;
70 u32 tx_delay_max;
71};
72
73/* list of clocks required for mac */
74static const char * const mt2712_dwmac_clk_l[] = {
75 "axi", "apb", "mac_main", "ptp_ref"
76};
77
78static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat)
79{
80 int rmii_rxc = plat->rmii_rxc ? RMII_CLK_SRC_RXC : 0;
81 u32 intf_val = 0;
82
83 /* select phy interface in top control domain */
84 switch (plat->phy_mode) {
85 case PHY_INTERFACE_MODE_MII:
86 intf_val |= PHY_INTF_MII;
87 break;
88 case PHY_INTERFACE_MODE_RMII:
89 intf_val |= (PHY_INTF_RMII | rmii_rxc);
90 break;
91 case PHY_INTERFACE_MODE_RGMII:
92 case PHY_INTERFACE_MODE_RGMII_TXID:
93 case PHY_INTERFACE_MODE_RGMII_RXID:
94 case PHY_INTERFACE_MODE_RGMII_ID:
95 intf_val |= PHY_INTF_RGMII;
96 break;
97 default:
98 dev_err(plat->dev, "phy interface not supported\n");
99 return -EINVAL;
100 }
101
102 regmap_write(plat->peri_regmap, PERI_ETH_PHY_INTF_SEL, intf_val);
103
104 return 0;
105}
106
107static void mt2712_delay_ps2stage(struct mac_delay_struct *mac_delay)
108{
109 if (mac_delay->fine_tune) {
110 /* 170ps per stage for fine tune delay macro circuit*/
111 mac_delay->tx_delay /= 170;
112 mac_delay->rx_delay /= 170;
113 } else {
114 /* 550ps per stage for coarse tune delay macro circuit*/
115 mac_delay->tx_delay /= 550;
116 mac_delay->rx_delay /= 550;
117 }
118}
119
120static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat)
121{
122 struct mac_delay_struct *mac_delay = &plat->mac_delay;
123 u32 delay_val = 0, fine_val = 0;
124
125 mt2712_delay_ps2stage(mac_delay);
126
127 switch (plat->phy_mode) {
128 case PHY_INTERFACE_MODE_MII:
129 delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->tx_delay);
130 delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->tx_delay);
131 delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->tx_inv);
132
133 delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
134 delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
135 delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
136 break;
137 case PHY_INTERFACE_MODE_RMII:
138 /* the rmii reference clock is from external phy,
139 * and the property "rmii_rxc" indicates which pin(TXC/RXC)
140 * the reference clk is connected to. The reference clock is a
141 * received signal, so rx_delay/rx_inv are used to indicate
142 * the reference clock timing adjustment
143 */
144 if (plat->rmii_rxc) {
145 /* the rmii reference clock from outside is connected
146 * to RXC pin, the reference clock will be adjusted
147 * by RXC delay macro circuit.
148 */
149 delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
150 delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
151 delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
152 } else {
153 /* the rmii reference clock from outside is connected
154 * to TXC pin, the reference clock will be adjusted
155 * by TXC delay macro circuit.
156 */
157 delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->rx_delay);
158 delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->rx_delay);
159 delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->rx_inv);
160 }
161 /* tx_inv will inverse the tx clock inside mac relateive to
162 * reference clock from external phy,
163 * and this bit is located in the same register with fine-tune
164 */
165 if (mac_delay->tx_inv)
166 fine_val = ETH_RMII_DLY_TX_INV;
167 break;
168 case PHY_INTERFACE_MODE_RGMII:
169 /* the PHY is not responsible for inserting any internal
170 * delay by itself in PHY_INTERFACE_MODE_RGMII case,
171 * so Ethernet MAC will insert delays for both transmit
172 * and receive path here.
173 */
174 if (mac_delay->fine_tune)
175 fine_val = ETH_FINE_DLY_GTXC | ETH_FINE_DLY_RXC;
176
177 delay_val |= FIELD_PREP(ETH_DLY_GTXC_ENABLE, !!mac_delay->tx_delay);
178 delay_val |= FIELD_PREP(ETH_DLY_GTXC_STAGES, mac_delay->tx_delay);
179 delay_val |= FIELD_PREP(ETH_DLY_GTXC_INV, mac_delay->tx_inv);
180
181 delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
182 delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
183 delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
184 break;
185 case PHY_INTERFACE_MODE_RGMII_TXID:
186 /* the PHY should insert an internal delay for the transmit
187 * path in PHY_INTERFACE_MODE_RGMII_TXID case,
188 * so Ethernet MAC will insert the delay for receive path here.
189 */
190 if (mac_delay->fine_tune)
191 fine_val = ETH_FINE_DLY_RXC;
192
193 delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
194 delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
195 delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
196 break;
197 case PHY_INTERFACE_MODE_RGMII_RXID:
198 /* the PHY should insert an internal delay for the receive
199 * path in PHY_INTERFACE_MODE_RGMII_RXID case,
200 * so Ethernet MAC will insert the delay for transmit path here.
201 */
202 if (mac_delay->fine_tune)
203 fine_val = ETH_FINE_DLY_GTXC;
204
205 delay_val |= FIELD_PREP(ETH_DLY_GTXC_ENABLE, !!mac_delay->tx_delay);
206 delay_val |= FIELD_PREP(ETH_DLY_GTXC_STAGES, mac_delay->tx_delay);
207 delay_val |= FIELD_PREP(ETH_DLY_GTXC_INV, mac_delay->tx_inv);
208 break;
209 case PHY_INTERFACE_MODE_RGMII_ID:
210 /* the PHY should insert internal delays for both transmit
211 * and receive path in PHY_INTERFACE_MODE_RGMII_RXID case,
212 * so Ethernet MAC will NOT insert any delay here.
213 */
214 break;
215 default:
216 dev_err(plat->dev, "phy interface not supported\n");
217 return -EINVAL;
218 }
219 regmap_write(plat->peri_regmap, PERI_ETH_DLY, delay_val);
220 regmap_write(plat->peri_regmap, PERI_ETH_DLY_FINE, fine_val);
221
222 return 0;
223}
224
225static const struct mediatek_dwmac_variant mt2712_gmac_variant = {
226 .dwmac_set_phy_interface = mt2712_set_interface,
227 .dwmac_set_delay = mt2712_set_delay,
228 .clk_list = mt2712_dwmac_clk_l,
229 .num_clks = ARRAY_SIZE(mt2712_dwmac_clk_l),
230 .dma_bit_mask = 33,
231 .rx_delay_max = 17600,
232 .tx_delay_max = 17600,
233};
234
235static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat)
236{
237 struct mac_delay_struct *mac_delay = &plat->mac_delay;
238 u32 tx_delay_ps, rx_delay_ps;
239
240 plat->peri_regmap = syscon_regmap_lookup_by_phandle(plat->np, "mediatek,pericfg");
241 if (IS_ERR(plat->peri_regmap)) {
242 dev_err(plat->dev, "Failed to get pericfg syscon\n");
243 return PTR_ERR(plat->peri_regmap);
244 }
245
246 plat->phy_mode = of_get_phy_mode(plat->np);
247 if (plat->phy_mode < 0) {
248 dev_err(plat->dev, "not find phy-mode\n");
249 return -EINVAL;
250 }
251
252 if (!of_property_read_u32(plat->np, "mediatek,tx-delay-ps", &tx_delay_ps)) {
253 if (tx_delay_ps < plat->variant->tx_delay_max) {
254 mac_delay->tx_delay = tx_delay_ps;
255 } else {
256 dev_err(plat->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
257 return -EINVAL;
258 }
259 }
260
261 if (!of_property_read_u32(plat->np, "mediatek,rx-delay-ps", &rx_delay_ps)) {
262 if (rx_delay_ps < plat->variant->rx_delay_max) {
263 mac_delay->rx_delay = rx_delay_ps;
264 } else {
265 dev_err(plat->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
266 return -EINVAL;
267 }
268 }
269
270 mac_delay->tx_inv = of_property_read_bool(plat->np, "mediatek,txc-inverse");
271 mac_delay->rx_inv = of_property_read_bool(plat->np, "mediatek,rxc-inverse");
272 mac_delay->fine_tune = of_property_read_bool(plat->np, "mediatek,fine-tune");
273 plat->rmii_rxc = of_property_read_bool(plat->np, "mediatek,rmii-rxc");
274
275 return 0;
276}
277
278static int mediatek_dwmac_clk_init(struct mediatek_dwmac_plat_data *plat)
279{
280 const struct mediatek_dwmac_variant *variant = plat->variant;
281 int i, num = variant->num_clks;
282
283 plat->clks = devm_kcalloc(plat->dev, num, sizeof(*plat->clks), GFP_KERNEL);
284 if (!plat->clks)
285 return -ENOMEM;
286
287 for (i = 0; i < num; i++)
288 plat->clks[i].id = variant->clk_list[i];
289
290 return devm_clk_bulk_get(plat->dev, num, plat->clks);
291}
292
293static int mediatek_dwmac_init(struct platform_device *pdev, void *priv)
294{
295 struct mediatek_dwmac_plat_data *plat = priv;
296 const struct mediatek_dwmac_variant *variant = plat->variant;
297 int ret;
298
299 ret = dma_set_mask_and_coherent(plat->dev, DMA_BIT_MASK(variant->dma_bit_mask));
300 if (ret) {
301 dev_err(plat->dev, "No suitable DMA available, err = %d\n", ret);
302 return ret;
303 }
304
305 ret = variant->dwmac_set_phy_interface(plat);
306 if (ret) {
307 dev_err(plat->dev, "failed to set phy interface, err = %d\n", ret);
308 return ret;
309 }
310
311 ret = variant->dwmac_set_delay(plat);
312 if (ret) {
313 dev_err(plat->dev, "failed to set delay value, err = %d\n", ret);
314 return ret;
315 }
316
317 ret = clk_bulk_prepare_enable(variant->num_clks, plat->clks);
318 if (ret) {
319 dev_err(plat->dev, "failed to enable clks, err = %d\n", ret);
320 return ret;
321 }
322
323 return 0;
324}
325
326static void mediatek_dwmac_exit(struct platform_device *pdev, void *priv)
327{
328 struct mediatek_dwmac_plat_data *plat = priv;
329 const struct mediatek_dwmac_variant *variant = plat->variant;
330
331 clk_bulk_disable_unprepare(variant->num_clks, plat->clks);
332}
333
334static int mediatek_dwmac_probe(struct platform_device *pdev)
335{
336 struct mediatek_dwmac_plat_data *priv_plat;
337 struct plat_stmmacenet_data *plat_dat;
338 struct stmmac_resources stmmac_res;
339 int ret;
340
341 priv_plat = devm_kzalloc(&pdev->dev, sizeof(*priv_plat), GFP_KERNEL);
342 if (!priv_plat)
343 return -ENOMEM;
344
345 priv_plat->variant = of_device_get_match_data(&pdev->dev);
346 if (!priv_plat->variant) {
347 dev_err(&pdev->dev, "Missing dwmac-mediatek variant\n");
348 return -EINVAL;
349 }
350
351 priv_plat->dev = &pdev->dev;
352 priv_plat->np = pdev->dev.of_node;
353
354 ret = mediatek_dwmac_config_dt(priv_plat);
355 if (ret)
356 return ret;
357
358 ret = mediatek_dwmac_clk_init(priv_plat);
359 if (ret)
360 return ret;
361
362 ret = stmmac_get_platform_resources(pdev, &stmmac_res);
363 if (ret)
364 return ret;
365
366 plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
367 if (IS_ERR(plat_dat))
368 return PTR_ERR(plat_dat);
369
370 plat_dat->interface = priv_plat->phy_mode;
371 /* clk_csr_i = 250-300MHz & MDC = clk_csr_i/124 */
372 plat_dat->clk_csr = 5;
373 plat_dat->has_gmac4 = 1;
374 plat_dat->has_gmac = 0;
375 plat_dat->pmt = 0;
376 plat_dat->maxmtu = ETH_DATA_LEN;
377 plat_dat->bsp_priv = priv_plat;
378 plat_dat->init = mediatek_dwmac_init;
379 plat_dat->exit = mediatek_dwmac_exit;
380 mediatek_dwmac_init(pdev, priv_plat);
381
382 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
383 if (ret) {
384 stmmac_remove_config_dt(pdev, plat_dat);
385 return ret;
386 }
387
388 return 0;
389}
390
391static const struct of_device_id mediatek_dwmac_match[] = {
392 { .compatible = "mediatek,mt2712-gmac",
393 .data = &mt2712_gmac_variant },
394 { }
395};
396
397MODULE_DEVICE_TABLE(of, mediatek_dwmac_match);
398
399static struct platform_driver mediatek_dwmac_driver = {
400 .probe = mediatek_dwmac_probe,
401 .remove = stmmac_pltfr_remove,
402 .driver = {
403 .name = "dwmac-mediatek",
404 .pm = &stmmac_pltfr_pm_ops,
405 .of_match_table = mediatek_dwmac_match,
406 },
407};
408module_platform_driver(mediatek_dwmac_driver);