1/* $NetBSD: rk_gmac.c,v 1.22 2023/12/31 09:45:58 skrll Exp $ */
2
3/*-
4 * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30
31__KERNEL_RCSID(0, "$NetBSD: rk_gmac.c,v 1.22 2023/12/31 09:45:58 skrll Exp $");
32
33#include <sys/param.h>
34#include <sys/bus.h>
35#include <sys/device.h>
36#include <sys/intr.h>
37#include <sys/systm.h>
38#include <sys/gpio.h>
39#include <sys/rndsource.h>
40
41#include <net/if.h>
42#include <net/if_ether.h>
43#include <net/if_media.h>
44
45#include <dev/mii/miivar.h>
46
47#include <dev/ic/dwc_gmac_var.h>
48#include <dev/ic/dwc_gmac_reg.h>
49
50#include <dev/fdt/fdtvar.h>
51#include <dev/fdt/syscon.h>
52
53#define	RK_GMAC_TXDLY_DEFAULT	0x30
54#define	RK_GMAC_RXDLY_DEFAULT	0x10
55
56enum rk_gmac_type {
57	GMAC_RK3288 = 1,
58	GMAC_RK3328,
59	GMAC_RK3399
60};
61
62static const struct device_compatible_entry compat_data[] = {
63	{ .compat = "rockchip,rk3288-gmac",	.value = GMAC_RK3288 },
64	{ .compat = "rockchip,rk3328-gmac",	.value = GMAC_RK3328 },
65	{ .compat = "rockchip,rk3399-gmac",	.value = GMAC_RK3399 },
66	DEVICE_COMPAT_EOL
67};
68
69struct rk_gmac_softc {
70	struct dwc_gmac_softc	sc_base;
71	struct syscon		*sc_syscon;
72	enum rk_gmac_type	sc_type;
73};
74
75/*
76 * RK3288 specific
77 */
78
79#define	RK3288_GRF_SOC_CON1	0x0248
80#define	 RK3288_GRF_SOC_CON1_RMII_MODE		__BIT(14)
81#define	 RK3288_GRF_SOC_CON1_GMAC_CLK_SEL	__BITS(13,12)
82#define	  RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_125M		0
83#define	  RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_2_5M		2
84#define	  RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_25M		3
85#define	 RK3288_GRF_SOC_CON1_RMII_CLK_SEL	__BIT(11)
86#define	  RK3288_GRF_SOC_CON1_RMII_CLK_SEL_25M		1
87#define	  RK3288_GRF_SOC_CON1_RMII_CLK_SEL_2_5M		0
88#define	 RK3288_GRF_SOC_CON1_GMAC_SPEED		__BIT(10)
89#define	  RK3288_GRF_SOC_CON1_GMAC_SPEED_10M		0
90#define	  RK3288_GRF_SOC_CON1_GMAC_SPEED_100M		1
91#define	 RK3288_GRF_SOC_CON1_GMAC_FLOWCTRL	__BIT(9)
92#define	 RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL	__BITS(8,6)
93#define	  RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL_RGMII	1
94#define	  RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL_RMII	4
95
96#define	RK3288_GRF_SOC_CON3	0x0250
97#define	 RK3288_GRF_SOC_CON3_RXCLK_DLY_ENA_GMAC	__BIT(15)
98#define	 RK3288_GRF_SOC_CON3_TXCLK_DLY_ENA_GMAC	__BIT(14)
99#define	 RK3288_GRF_SOC_CON3_CLK_RX_DL_CFG_GMAC	__BITS(13,7)
100#define	 RK3288_GRF_SOC_CON3_CLK_TX_DL_CFG_GMAC	__BITS(6,0)
101
102static void
103rk3288_gmac_set_mode_rgmii(struct dwc_gmac_softc *sc, u_int tx_delay, u_int rx_delay, bool set_delay)
104{
105	struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
106	uint32_t write_mask, write_val;
107
108	syscon_lock(rk_sc->sc_syscon);
109
110	write_mask = (RK3288_GRF_SOC_CON1_RMII_MODE |
111		      RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL) << 16;
112	write_val = __SHIFTIN(RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL_RGMII,
113			      RK3288_GRF_SOC_CON1_GMAC_PHY_INTF_SEL);
114	syscon_write_4(rk_sc->sc_syscon, RK3288_GRF_SOC_CON1,
115	    write_mask | write_val);
116
117	if (set_delay) {
118		write_mask = (RK3288_GRF_SOC_CON3_RXCLK_DLY_ENA_GMAC |
119			      RK3288_GRF_SOC_CON3_TXCLK_DLY_ENA_GMAC |
120			      RK3288_GRF_SOC_CON3_CLK_RX_DL_CFG_GMAC |
121			      RK3288_GRF_SOC_CON3_CLK_TX_DL_CFG_GMAC) << 16;
122		write_val = 0;
123		if (tx_delay) {
124			write_mask |= RK3288_GRF_SOC_CON3_TXCLK_DLY_ENA_GMAC |
125				      __SHIFTIN(tx_delay,
126						RK3288_GRF_SOC_CON3_CLK_TX_DL_CFG_GMAC);
127		}
128		if (rx_delay) {
129			write_mask |= RK3288_GRF_SOC_CON3_RXCLK_DLY_ENA_GMAC |
130				      __SHIFTIN(rx_delay,
131						RK3288_GRF_SOC_CON3_CLK_RX_DL_CFG_GMAC);
132		}
133		syscon_write_4(rk_sc->sc_syscon, RK3288_GRF_SOC_CON3,
134		    write_mask | write_val);
135	}
136
137	syscon_unlock(rk_sc->sc_syscon);
138}
139
140static void
141rk3288_gmac_set_speed_rgmii(struct dwc_gmac_softc *sc, int speed)
142{
143	struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
144	uint32_t write_mask, write_val;
145
146	syscon_lock(rk_sc->sc_syscon);
147
148	write_mask = (RK3288_GRF_SOC_CON1_GMAC_CLK_SEL) << 16;
149	switch (speed) {
150	case IFM_10_T:
151		write_val = RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_2_5M;
152		break;
153	case IFM_100_TX:
154		write_val = RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_25M;
155		break;
156	case IFM_1000_T:
157	default:
158		write_val = RK3288_GRF_SOC_CON1_GMAC_CLK_SEL_125M;
159		break;
160	}
161	syscon_write_4(rk_sc->sc_syscon, RK3288_GRF_SOC_CON1,
162	    write_mask | write_val);
163
164	syscon_unlock(rk_sc->sc_syscon);
165}
166
167/*
168 * RK3328 specific
169 */
170
171#define	RK3328_GRF_MAC_CON0	0x0900
172#define	 RK3328_GRF_MAC_CON0_RXDLY	__BITS(13,7)
173#define	 RK3328_GRF_MAC_CON0_TXDLY	__BITS(6,0)
174
175#define	RK3328_GRF_MAC_CON1	0x0904
176#define	 RK3328_GRF_MAC_CON1_CLKSEL	__BITS(12,11)
177#define	  RK3328_GRF_MAC_CON1_CLKSEL_125M	0
178#define	  RK3328_GRF_MAC_CON1_CLKSEL_2_5M	2
179#define	  RK3328_GRF_MAC_CON1_CLKSEL_25M	3
180#define	 RK3328_GRF_MAC_CON1_MODE	__BIT(9)
181#define	 RK3328_GRF_MAC_CON1_SEL	__BITS(6,4)
182#define	  RK3328_GRF_MAC_CON1_SEL_RGMII	1
183#define	 RK3328_GRF_MAC_CON1_RXDLY_EN	__BIT(1)
184#define	 RK3328_GRF_MAC_CON1_TXDLY_EN	__BIT(0)
185
186static void
187rk3328_gmac_set_mode_rgmii(struct dwc_gmac_softc *sc, u_int tx_delay, u_int rx_delay, bool set_delay)
188{
189	struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
190	uint32_t write_mask, write_val;
191
192	syscon_lock(rk_sc->sc_syscon);
193
194	write_mask = (RK3328_GRF_MAC_CON1_MODE | RK3328_GRF_MAC_CON1_SEL) << 16;
195	write_val = __SHIFTIN(RK3328_GRF_MAC_CON1_SEL_RGMII,
196	    RK3328_GRF_MAC_CON1_SEL);
197	syscon_write_4(rk_sc->sc_syscon, RK3328_GRF_MAC_CON1,
198	    write_mask | write_val);
199
200	if (set_delay) {
201		write_mask = (
202		    RK3328_GRF_MAC_CON0_TXDLY |
203		    RK3328_GRF_MAC_CON0_RXDLY) << 16;
204		write_val =
205		    __SHIFTIN(tx_delay, RK3328_GRF_MAC_CON0_TXDLY) |
206		    __SHIFTIN(rx_delay, RK3328_GRF_MAC_CON0_RXDLY);
207		syscon_write_4(rk_sc->sc_syscon, RK3328_GRF_MAC_CON0,
208		    write_mask | write_val);
209
210		write_mask = (
211		    RK3328_GRF_MAC_CON1_RXDLY_EN |
212		    RK3328_GRF_MAC_CON1_TXDLY_EN) << 16;
213		write_val =
214		    RK3328_GRF_MAC_CON1_RXDLY_EN |
215		    RK3328_GRF_MAC_CON1_TXDLY_EN;
216		syscon_write_4(rk_sc->sc_syscon, RK3328_GRF_MAC_CON1,
217		    write_mask | write_val);
218	}
219
220	syscon_unlock(rk_sc->sc_syscon);
221}
222
223static void
224rk3328_gmac_set_speed_rgmii(struct dwc_gmac_softc *sc, int speed)
225{
226	struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
227#if 0
228	u_int clksel;
229
230	switch (speed) {
231	case IFM_10_T:
232		clksel = RK3328_GRF_MAC_CON1_CLKSEL_2_5M;
233		break;
234	case IFM_100_TX:
235		clksel = RK3328_GRF_MAC_CON1_CLKSEL_25M;
236		break;
237	default:
238		clksel = RK3328_GRF_MAC_CON1_CLKSEL_125M;
239		break;
240	}
241#endif
242
243	syscon_lock(rk_sc->sc_syscon);
244	syscon_write_4(rk_sc->sc_syscon, RK3328_GRF_MAC_CON1,
245	    (RK3328_GRF_MAC_CON1_CLKSEL << 16) |
246	    __SHIFTIN(RK3328_GRF_MAC_CON1_CLKSEL_125M, RK3328_GRF_MAC_CON1_CLKSEL));
247	syscon_unlock(rk_sc->sc_syscon);
248}
249
250/*
251 * RK3399 specific
252 */
253
254#define	RK3399_GRF_SOC_CON5		0x0c214
255#define	 RK3399_GRF_SOC_CON5_GMAC_PHY_INTF_SEL	__BITS(11,9)
256#define	 RK3399_GRF_SOC_CON5_GMAC_FLOWCTRL	__BIT(8)
257#define	 RK3399_GRF_SOC_CON5_GMAC_SPEED		__BIT(7)
258#define	 RK3399_GRF_SOC_CON5_RMII_MODE		__BIT(6)
259#define	 RK3399_GRF_SOC_CON5_GMAC_CLK_SEL	__BITS(5,4)
260#define	  RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_125M	0
261#define	  RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_25M	3
262#define	  RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_2_5M	2
263#define	 RK3399_GRF_SOC_CON5_RMII_CLK_SEL	__BIT(3)
264#define	RK3399_GRF_SOC_CON6		0x0c218
265#define	 RK3399_GRF_SOC_CON6_GMAC_RXCLK_DLY_ENA	__BIT(15)
266#define	 RK3399_GRF_SOC_CON6_GMAC_CLK_RX_DL_CFG	__BITS(14,8)
267#define	 RK3399_GRF_SOC_CON6_GMAC_TXCLK_DLY_ENA	__BIT(7)
268#define	 RK3399_GRF_SOC_CON6_GMAC_CLK_TX_DL_CFG	__BITS(6,0)
269
270static void
271rk3399_gmac_set_mode_rgmii(struct dwc_gmac_softc *sc, u_int tx_delay,
272    u_int rx_delay, bool set_delay)
273{
274	struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
275	uint32_t write_mask, write_val;
276
277	syscon_lock(rk_sc->sc_syscon);
278
279	write_mask = (
280	    RK3399_GRF_SOC_CON5_RMII_MODE |
281	    RK3399_GRF_SOC_CON5_GMAC_PHY_INTF_SEL) << 16;
282	write_val = __SHIFTIN(1, RK3399_GRF_SOC_CON5_GMAC_PHY_INTF_SEL);
283	syscon_write_4(rk_sc->sc_syscon, RK3399_GRF_SOC_CON5,
284	    write_mask | write_val);
285	if (set_delay) {
286		write_mask = (
287		    RK3399_GRF_SOC_CON6_GMAC_TXCLK_DLY_ENA |
288		    RK3399_GRF_SOC_CON6_GMAC_RXCLK_DLY_ENA |
289		    RK3399_GRF_SOC_CON6_GMAC_CLK_RX_DL_CFG |
290		    RK3399_GRF_SOC_CON6_GMAC_CLK_TX_DL_CFG) << 16;
291		write_val =
292		    (tx_delay ? RK3399_GRF_SOC_CON6_GMAC_TXCLK_DLY_ENA : 0) |
293		    (rx_delay ? RK3399_GRF_SOC_CON6_GMAC_RXCLK_DLY_ENA : 0) |
294		    __SHIFTIN(rx_delay, RK3399_GRF_SOC_CON6_GMAC_CLK_RX_DL_CFG) |
295		    __SHIFTIN(tx_delay, RK3399_GRF_SOC_CON6_GMAC_CLK_TX_DL_CFG);
296		syscon_write_4(rk_sc->sc_syscon, RK3399_GRF_SOC_CON6,
297		    write_mask | write_val);
298	}
299	syscon_unlock(rk_sc->sc_syscon);
300}
301
302static void
303rk3399_gmac_set_speed_rgmii(struct dwc_gmac_softc *sc, int speed)
304{
305	struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc;
306	u_int clksel;
307
308	switch (speed) {
309	case IFM_10_T:
310		clksel = RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_2_5M;
311		break;
312	case IFM_100_TX:
313		clksel = RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_25M;
314		break;
315	default:
316		clksel = RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_125M;
317		break;
318	}
319
320	const uint32_t con5_mask =
321	    RK3399_GRF_SOC_CON5_GMAC_CLK_SEL << 16;
322	const uint32_t con5 =
323	    __SHIFTIN(clksel, RK3399_GRF_SOC_CON5_GMAC_CLK_SEL);
324
325	syscon_lock(rk_sc->sc_syscon);
326	syscon_write_4(rk_sc->sc_syscon, RK3399_GRF_SOC_CON5, con5 | con5_mask);
327	syscon_unlock(rk_sc->sc_syscon);
328}
329
330static int
331rk_gmac_reset(const int phandle)
332{
333	struct fdtbus_gpio_pin *pin_reset;
334	const u_int *reset_delay_us;
335	bool reset_active_low;
336	int len;
337
338	if (!of_hasprop(phandle, "snps,reset-gpio"))
339		return 0;
340
341	pin_reset = fdtbus_gpio_acquire(phandle, "snps,reset-gpio", GPIO_PIN_OUTPUT);
342	if (pin_reset == NULL)
343		return ENOENT;
344
345	reset_delay_us = fdtbus_get_prop(phandle, "snps,reset-delays-us", &len);
346	if (reset_delay_us == NULL || len != 12)
347		return ENXIO;
348
349	reset_active_low = of_hasprop(phandle, "snps,reset-active-low");
350
351	fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0);
352	delay(be32toh(reset_delay_us[0]));
353	fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 0 : 1);
354	delay(be32toh(reset_delay_us[1]));
355	fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0);
356	delay(be32toh(reset_delay_us[2]));
357
358	return 0;
359}
360
361static int
362rk_gmac_intr(void *arg)
363{
364	return dwc_gmac_intr(arg);
365}
366
367static int
368rk_gmac_setup_clocks(int phandle)
369{
370	static const char * const clknames[] = {
371#if 0
372		"stmmaceth",
373		"mac_clk_rx",
374		"mac_clk_tx",
375		"clk_mac_ref",
376		"clk_mac_refout",
377		"aclk_mac",
378		"pclk_mac"
379#else
380		"stmmaceth",
381		"aclk_mac",
382		"pclk_mac",
383		"mac_clk_tx",
384		"mac_clk_rx"
385#endif
386	};
387	static const char * const rstnames[] = {
388		"stmmaceth"
389	};
390	struct fdtbus_reset *rst;
391	struct clk *clk;
392	int error, n;
393
394	fdtbus_clock_assign(phandle);
395
396	for (n = 0; n < __arraycount(clknames); n++) {
397		clk = fdtbus_clock_get(phandle, clknames[n]);
398		if (clk == NULL) {
399			aprint_error(": couldn't get %s clock\n", clknames[n]);
400			return ENXIO;
401		}
402		error = clk_enable(clk);
403		if (error != 0) {
404			aprint_error(": couldn't enable %s clock: %d\n",
405			    clknames[n], error);
406			return error;
407		}
408	}
409
410	for (n = 0; n < __arraycount(rstnames); n++) {
411		rst = fdtbus_reset_get(phandle, rstnames[n]);
412		if (rst == NULL) {
413			aprint_error(": couldn't get %s reset\n", rstnames[n]);
414			return ENXIO;
415		}
416		error = fdtbus_reset_deassert(rst);
417		if (error != 0) {
418			aprint_error(": couldn't de-assert %s reset: %d\n",
419			    rstnames[n], error);
420			return error;
421		}
422	}
423
424	delay(5000);
425
426	return 0;
427}
428
429static int
430rk_gmac_match(device_t parent, cfdata_t cf, void *aux)
431{
432	struct fdt_attach_args * const faa = aux;
433
434	return of_compatible_match(faa->faa_phandle, compat_data);
435}
436
437static void
438rk_gmac_attach(device_t parent, device_t self, void *aux)
439{
440	struct rk_gmac_softc * const rk_sc = device_private(self);
441	struct dwc_gmac_softc * const sc = &rk_sc->sc_base;
442	struct fdt_attach_args * const faa = aux;
443	const int phandle = faa->faa_phandle;
444	const char *phy_mode;
445	char intrstr[128];
446	bus_addr_t addr;
447	bus_size_t size;
448	u_int tx_delay, rx_delay;
449#ifdef notyet
450	bool set_delay = true;
451#else
452	bool set_delay = false;
453#endif
454
455	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
456		aprint_error(": couldn't get registers\n");
457		return;
458	}
459
460	rk_sc->sc_type = of_compatible_lookup(phandle, compat_data)->value;
461
462	rk_sc->sc_syscon = fdtbus_syscon_acquire(phandle, "rockchip,grf");
463	if (rk_sc->sc_syscon == NULL) {
464		aprint_error(": couldn't get grf syscon\n");
465		return;
466	}
467
468	if (of_getprop_uint32(phandle, "tx_delay", &tx_delay) != 0) {
469		tx_delay = RK_GMAC_TXDLY_DEFAULT;
470		set_delay = false;
471	}
472
473	if (of_getprop_uint32(phandle, "rx_delay", &rx_delay) != 0) {
474		rx_delay = RK_GMAC_RXDLY_DEFAULT;
475		set_delay = false;
476	}
477
478	sc->sc_dev = self;
479	sc->sc_bst = faa->faa_bst;
480	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
481		aprint_error(": couldn't map registers\n");
482		return;
483	}
484	sc->sc_dmat = faa->faa_dmat;
485
486	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
487		aprint_error(": failed to decode interrupt\n");
488		return;
489	}
490
491	if (rk_gmac_setup_clocks(phandle) != 0)
492		return;
493
494	if (rk_gmac_reset(phandle) != 0)
495		aprint_error_dev(self, "PHY reset failed\n");
496
497	/* Rock64 seems to need more time for the reset to complete */
498	delay(100000);
499
500#if notyet
501	if (of_hasprop(phandle, "snps,force_thresh_dma_mode"))
502		sc->sc_flags |= DWC_GMAC_FORCE_THRESH_DMA_MODE;
503#endif
504
505	phy_mode = fdtbus_get_string(phandle, "phy-mode");
506	if (phy_mode == NULL) {
507		aprint_error(": missing 'phy-mode' property\n");
508		return;
509	}
510
511	switch (rk_sc->sc_type) {
512	case GMAC_RK3288:
513		if (strncmp(phy_mode, "rgmii", 5) == 0) {
514			rk3288_gmac_set_mode_rgmii(sc, tx_delay, rx_delay,
515			    set_delay);
516
517			sc->sc_set_speed = rk3288_gmac_set_speed_rgmii;
518		} else {
519			aprint_error(": unsupported phy-mode '%s'\n", phy_mode);
520			return;
521		}
522		break;
523	case GMAC_RK3328:
524		if (strncmp(phy_mode, "rgmii", 5) == 0) {
525			rk3328_gmac_set_mode_rgmii(sc, tx_delay, rx_delay,
526			    set_delay);
527
528			sc->sc_set_speed = rk3328_gmac_set_speed_rgmii;
529		} else {
530			aprint_error(": unsupported phy-mode '%s'\n", phy_mode);
531			return;
532		}
533		break;
534	case GMAC_RK3399:
535		if (strncmp(phy_mode, "rgmii", 5) == 0) {
536			rk3399_gmac_set_mode_rgmii(sc, tx_delay, rx_delay,
537			    set_delay);
538
539			sc->sc_set_speed = rk3399_gmac_set_speed_rgmii;
540		} else {
541			aprint_error(": unsupported phy-mode '%s'\n", phy_mode);
542			return;
543		}
544		break;
545	}
546
547	aprint_naive("\n");
548	aprint_normal(": GMAC\n");
549
550	if (dwc_gmac_attach(sc, MII_PHY_ANY, GMAC_MII_CLK_150_250M_DIV102) != 0)
551		return;
552
553	if (fdtbus_intr_establish_xname(phandle, 0, IPL_NET,
554	    DWCGMAC_FDT_INTR_MPSAFE, rk_gmac_intr, sc,
555	    device_xname(self)) == NULL) {
556		aprint_error_dev(self, "failed to establish interrupt on %s\n", intrstr);
557		return;
558	}
559	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
560}
561
562CFATTACH_DECL_NEW(rk_gmac, sizeof(struct rk_gmac_softc),
563	rk_gmac_match, rk_gmac_attach, NULL, NULL);
564