1/*	$OpenBSD: if_dwqe_fdt.c,v 1.18 2024/02/26 18:57:50 kettenis Exp $	*/
2/*
3 * Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org>
4 * Copyright (c) 2017, 2022 Patrick Wildt <patrick@blueri.se>
5 *
6 * Permission to use, copy, modify, and 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/*
20 * Driver for the Synopsys Designware ethernet controller.
21 */
22
23#include "bpfilter.h"
24
25#include <sys/param.h>
26#include <sys/systm.h>
27#include <sys/device.h>
28#include <sys/kernel.h>
29#include <sys/malloc.h>
30#include <sys/mbuf.h>
31#include <sys/queue.h>
32#include <sys/socket.h>
33#include <sys/sockio.h>
34#include <sys/timeout.h>
35#include <sys/task.h>
36
37#include <machine/bus.h>
38#include <machine/fdt.h>
39
40#include <net/if.h>
41#include <net/if_media.h>
42
43#include <dev/ofw/openfirm.h>
44#include <dev/ofw/ofw_clock.h>
45#include <dev/ofw/ofw_gpio.h>
46#include <dev/ofw/ofw_misc.h>
47#include <dev/ofw/ofw_pinctrl.h>
48#include <dev/ofw/ofw_regulator.h>
49#include <dev/ofw/fdt.h>
50
51#include <dev/mii/mii.h>
52#include <dev/mii/miivar.h>
53
54#if NBPFILTER > 0
55#include <net/bpf.h>
56#endif
57
58#include <netinet/in.h>
59#include <netinet/if_ether.h>
60
61#include <dev/ic/dwqevar.h>
62#include <dev/ic/dwqereg.h>
63
64struct dwqe_fdt_softc {
65	struct dwqe_softc	sc_sc;
66	struct if_device	sc_ifd;
67	int			sc_gmac_id;
68};
69
70int	dwqe_fdt_match(struct device *, void *, void *);
71void	dwqe_fdt_attach(struct device *, struct device *, void *);
72void	dwqe_setup_jh7110(struct dwqe_softc *);
73void	dwqe_mii_statchg_jh7110(struct device *);
74void	dwqe_setup_rk3568(struct dwqe_fdt_softc *);
75void	dwqe_mii_statchg_rk3568(struct device *);
76void	dwqe_setup_rk3588(struct dwqe_fdt_softc *);
77void	dwqe_mii_statchg_rk3588(struct device *);
78
79const struct cfattach dwqe_fdt_ca = {
80	sizeof(struct dwqe_fdt_softc), dwqe_fdt_match, dwqe_fdt_attach
81};
82
83void	dwqe_reset_phy(struct dwqe_softc *, uint32_t);
84
85int
86dwqe_fdt_match(struct device *parent, void *cfdata, void *aux)
87{
88	struct fdt_attach_args *faa = aux;
89
90	return OF_is_compatible(faa->fa_node, "snps,dwmac-4.20a") ||
91	    OF_is_compatible(faa->fa_node, "snps,dwmac-5.20");
92}
93
94void
95dwqe_fdt_attach(struct device *parent, struct device *self, void *aux)
96{
97	struct dwqe_fdt_softc *fsc = (void *)self;
98	struct dwqe_softc *sc = &fsc->sc_sc;
99	struct fdt_attach_args *faa = aux;
100	char phy_mode[16] = { 0 };
101	uint32_t phy, phy_supply;
102	uint32_t axi_config;
103	struct ifnet *ifp = &sc->sc_ac.ac_if;
104	int i, node;
105
106	sc->sc_node = faa->fa_node;
107	sc->sc_iot = faa->fa_iot;
108	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
109	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
110		printf(": cannot map registers\n");
111		return;
112	}
113	sc->sc_dmat = faa->fa_dmat;
114
115	/* Decide GMAC id through address */
116	switch (faa->fa_reg[0].addr) {
117	case 0xfe2a0000:	/* RK3568 */
118	case 0xfe1b0000:	/* RK3588 */
119	case 0x16030000:	/* JH7110 */
120		fsc->sc_gmac_id = 0;
121		break;
122	case 0xfe010000:	/* RK3568 */
123	case 0xfe1c0000:	/* RK3588 */
124	case 0x16040000:	/* JH7110 */
125		fsc->sc_gmac_id = 1;
126		break;
127	default:
128		printf(": unknown controller at 0x%llx\n", faa->fa_reg[0].addr);
129		return;
130	}
131
132	printf(" gmac %d", fsc->sc_gmac_id);
133
134	OF_getprop(faa->fa_node, "phy-mode", phy_mode, sizeof(phy_mode));
135	if (strcmp(phy_mode, "rgmii") == 0)
136		sc->sc_phy_mode = DWQE_PHY_MODE_RGMII;
137	else if (strcmp(phy_mode, "rgmii-rxid") == 0)
138		sc->sc_phy_mode = DWQE_PHY_MODE_RGMII_RXID;
139	else if (strcmp(phy_mode, "rgmii-txid") == 0)
140		sc->sc_phy_mode = DWQE_PHY_MODE_RGMII_TXID;
141	else if (strcmp(phy_mode, "rgmii-id") == 0)
142		sc->sc_phy_mode = DWQE_PHY_MODE_RGMII_ID;
143	else if (strcmp(phy_mode, "rmii") == 0)
144		sc->sc_phy_mode = DWQE_PHY_MODE_RMII;
145	else
146		sc->sc_phy_mode = DWQE_PHY_MODE_UNKNOWN;
147
148	/* Lookup PHY. */
149	phy = OF_getpropint(faa->fa_node, "phy", 0);
150	if (phy == 0)
151		phy = OF_getpropint(faa->fa_node, "phy-handle", 0);
152	node = OF_getnodebyphandle(phy);
153	if (node)
154		sc->sc_phyloc = OF_getpropint(node, "reg", MII_PHY_ANY);
155	else
156		sc->sc_phyloc = MII_PHY_ANY;
157	sc->sc_mii.mii_node = node;
158
159	pinctrl_byname(faa->fa_node, "default");
160
161	/* Enable clocks. */
162	clock_set_assigned(faa->fa_node);
163	clock_enable(faa->fa_node, "stmmaceth");
164	clock_enable(faa->fa_node, "pclk");
165	reset_deassert(faa->fa_node, "stmmaceth");
166	reset_deassert(faa->fa_node, "ahb");
167	if (OF_is_compatible(faa->fa_node, "starfive,jh7110-dwmac")) {
168		clock_enable(faa->fa_node, "tx");
169		clock_enable(faa->fa_node, "gtx");
170	} else if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-gmac") ||
171	    OF_is_compatible(faa->fa_node, "rockchip,rk3588-gmac")) {
172		clock_enable(faa->fa_node, "aclk_mac");
173		clock_enable(faa->fa_node, "pclk_mac");
174		clock_enable(faa->fa_node, "mac_clk_tx");
175		clock_enable(faa->fa_node, "clk_mac_speed");
176		if (strcmp(phy_mode, "rmii") == 0) {
177			clock_enable(faa->fa_node, "mac_clk_rx");
178			clock_enable(faa->fa_node, "clk_mac_ref");
179			clock_enable(faa->fa_node, "clk_mac_refout");
180		}
181	}
182	delay(5000);
183
184	/* Do hardware specific initializations. */
185	if (OF_is_compatible(faa->fa_node, "starfive,jh7110-dwmac"))
186		dwqe_setup_jh7110(sc);
187	else if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-gmac"))
188		dwqe_setup_rk3568(fsc);
189	else if (OF_is_compatible(faa->fa_node, "rockchip,rk3588-gmac"))
190		dwqe_setup_rk3588(fsc);
191
192	/* Power up PHY. */
193	phy_supply = OF_getpropint(faa->fa_node, "phy-supply", 0);
194	if (phy_supply)
195		regulator_enable(phy_supply);
196
197	/* Reset PHY */
198	dwqe_reset_phy(sc, phy);
199
200	node = OF_getnodebyname(sc->sc_node, "fixed-link");
201	if (node) {
202		sc->sc_fixed_link = 1;
203
204		ifp->if_baudrate = IF_Mbps(OF_getpropint(node, "speed", 0));
205		ifp->if_link_state = OF_getpropbool(node, "full-duplex") ?
206		    LINK_STATE_FULL_DUPLEX : LINK_STATE_HALF_DUPLEX;
207	}
208
209	sc->sc_clkrate = clock_get_frequency(faa->fa_node, "stmmaceth");
210	if (sc->sc_clkrate > 500000000)
211		sc->sc_clk = GMAC_MAC_MDIO_ADDR_CR_500_800;
212	else if (sc->sc_clkrate > 300000000)
213		sc->sc_clk = GMAC_MAC_MDIO_ADDR_CR_300_500;
214	else if (sc->sc_clkrate > 150000000)
215		sc->sc_clk = GMAC_MAC_MDIO_ADDR_CR_150_250;
216	else if (sc->sc_clkrate > 100000000)
217		sc->sc_clk = GMAC_MAC_MDIO_ADDR_CR_100_150;
218	else if (sc->sc_clkrate > 60000000)
219		sc->sc_clk = GMAC_MAC_MDIO_ADDR_CR_60_100;
220	else if (sc->sc_clkrate > 35000000)
221		sc->sc_clk = GMAC_MAC_MDIO_ADDR_CR_35_60;
222	else
223		sc->sc_clk = GMAC_MAC_MDIO_ADDR_CR_20_35;
224
225	for (i = 0; i < 4; i++)
226		sc->sc_hw_feature[i] = dwqe_read(sc, GMAC_MAC_HW_FEATURE(i));
227
228	if (OF_getprop(faa->fa_node, "local-mac-address",
229	    &sc->sc_lladdr, ETHER_ADDR_LEN) != ETHER_ADDR_LEN)
230		dwqe_lladdr_read(sc, sc->sc_lladdr);
231
232	sc->sc_force_thresh_dma_mode =
233	    OF_getpropbool(faa->fa_node, "snps,force_thresh_dma_mode");
234
235	dwqe_reset(sc);
236
237	sc->sc_fixed_burst = OF_getpropbool(faa->fa_node, "snps,fixed-burst");
238	sc->sc_mixed_burst = OF_getpropbool(faa->fa_node, "snps,mixed-burst");
239	sc->sc_aal = OF_getpropbool(faa->fa_node, "snps,aal");
240	sc->sc_8xpbl = !OF_getpropbool(faa->fa_node, "snps,no-pbl-x8");
241	sc->sc_pbl = OF_getpropint(faa->fa_node, "snps,pbl", 8);
242	sc->sc_txpbl = OF_getpropint(faa->fa_node, "snps,txpbl", sc->sc_pbl);
243	sc->sc_rxpbl = OF_getpropint(faa->fa_node, "snps,rxpbl", sc->sc_pbl);
244
245	/* Configure AXI master. */
246	axi_config = OF_getpropint(faa->fa_node, "snps,axi-config", 0);
247	node = OF_getnodebyphandle(axi_config);
248	if (node) {
249		sc->sc_axi_config = 1;
250		sc->sc_lpi_en = OF_getpropbool(node, "snps,lpi_en");
251		sc->sc_xit_frm = OF_getpropbool(node, "snps,xit_frm");
252
253		sc->sc_wr_osr_lmt = OF_getpropint(node, "snps,wr_osr_lmt", 1);
254		sc->sc_rd_osr_lmt = OF_getpropint(node, "snps,rd_osr_lmt", 1);
255
256		OF_getpropintarray(node, "snps,blen", sc->sc_blen, sizeof(sc->sc_blen));
257	}
258
259	if (dwqe_attach(sc) != 0)
260		return;
261
262	if (OF_is_compatible(faa->fa_node, "starfive,jh7110-dwmac") &&
263	    !OF_getpropbool(faa->fa_node, "starfive,tx-use-rgmii-clk"))
264		sc->sc_mii.mii_statchg = dwqe_mii_statchg_jh7110;
265	else if (OF_is_compatible(faa->fa_node, "rockchip,rk3568-gmac"))
266		sc->sc_mii.mii_statchg = dwqe_mii_statchg_rk3568;
267	else if (OF_is_compatible(faa->fa_node, "rockchip,rk3588-gmac"))
268		sc->sc_mii.mii_statchg = dwqe_mii_statchg_rk3588;
269
270	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_NET | IPL_MPSAFE,
271	    dwqe_intr, sc, sc->sc_dev.dv_xname);
272	if (sc->sc_ih == NULL)
273		printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname);
274
275	fsc->sc_ifd.if_node = faa->fa_node;
276	fsc->sc_ifd.if_ifp = ifp;
277	if_register(&fsc->sc_ifd);
278
279	/* force a configuration of the clocks/mac */
280	if (sc->sc_fixed_link)
281		sc->sc_mii.mii_statchg(self);
282}
283
284void
285dwqe_reset_phy(struct dwqe_softc *sc, uint32_t phy)
286{
287	uint32_t *gpio;
288	uint32_t delays[3];
289	int active = 1;
290	int node, len;
291
292	node = OF_getnodebyphandle(phy);
293	if (node && OF_getproplen(node, "reset-gpios") > 0) {
294		len = OF_getproplen(node, "reset-gpios");
295
296		gpio = malloc(len, M_TEMP, M_WAITOK);
297
298		/* Gather information. */
299		OF_getpropintarray(node, "reset-gpios", gpio, len);
300		delays[0] = OF_getpropint(node, "reset-deassert-us", 0);
301		delays[1] = OF_getpropint(node, "reset-assert-us", 0);
302		delays[2] = OF_getpropint(node, "reset-deassert-us", 0);
303	} else {
304		len = OF_getproplen(sc->sc_node, "snps,reset-gpio");
305		if (len <= 0)
306			return;
307
308		gpio = malloc(len, M_TEMP, M_WAITOK);
309
310		/* Gather information. */
311		OF_getpropintarray(sc->sc_node, "snps,reset-gpio", gpio, len);
312		if (OF_getpropbool(sc->sc_node, "snps-reset-active-low"))
313			active = 0;
314		delays[0] = delays[1] = delays[2] = 0;
315		OF_getpropintarray(sc->sc_node, "snps,reset-delays-us", delays,
316		    sizeof(delays));
317	}
318
319	/* Perform reset sequence. */
320	gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT);
321	gpio_controller_set_pin(gpio, !active);
322	delay(delays[0]);
323	gpio_controller_set_pin(gpio, active);
324	delay(delays[1]);
325	gpio_controller_set_pin(gpio, !active);
326	delay(delays[2]);
327
328	free(gpio, M_TEMP, len);
329}
330
331/* JH7110 registers */
332#define JH7110_PHY_INTF_RGMII		1
333#define JH7110_PHY_INTF_RMII		4
334
335/* RK3568 registers */
336#define RK3568_GRF_GMACx_CON0(x)	(0x0380 + (x) * 0x8)
337#define  RK3568_GMAC_CLK_RX_DL_CFG(val)		((0x7f << 8) << 16 | ((val) << 8))
338#define  RK3568_GMAC_CLK_TX_DL_CFG(val)		((0x7f << 0) << 16 | ((val) << 0))
339#define RK3568_GRF_GMACx_CON1(x)	(0x0384 + (x) * 0x8)
340#define  RK3568_GMAC_PHY_INTF_SEL_RGMII		((0x7 << 4) << 16 | (0x1 << 4))
341#define  RK3568_GMAC_PHY_INTF_SEL_RMII		((0x7 << 4) << 16 | (0x4 << 4))
342#define  RK3568_GMAC_TXCLK_DLY_SET(_v)		((1 << 0) << 16 | ((_v) << 0))
343#define  RK3568_GMAC_RXCLK_DLY_SET(_v)		((1 << 1) << 16 | ((_v) << 1))
344
345/* RK3588 registers */
346#define RK3588_GRF_GMAC_CON7		0x031c
347#define  RK3588_GMACx_RXCLK_DLY_ENA(id)		((1 << (2 * (id) + 3)) << 16 | (1 << (2 * (id) + 3)))
348#define  RK3588_GMACx_TXCLK_DLY_ENA(id)		((1 << (2 * (id) + 2)) << 16 | (1 << (2 * (id) + 2)))
349#define RK3588_GRF_GMAC_CON8		0x0320
350#define RK3588_GRF_GMAC_CON9		0x0324
351#define  RK3588_GMAC_CLK_RX_DL_CFG(val)		((0x7f << 8) << 16 | ((val) << 8))
352#define  RK3588_GMAC_CLK_TX_DL_CFG(val)		((0x7f << 0) << 16 | ((val) << 0))
353#define RK3588_PHP_GRF_GMAC_CON0	0x0008
354#define  RK3588_GMACx_PHY_INTF_SEL_RGMII(id)	((0x7 << (6 * (id) + 3)) << 16 | (0x1 << (6 * (id) + 3)))
355#define  RK3588_GMACx_PHY_INTF_SEL_RMII(id)	((0x7 << (6 * (id) + 3)) << 16 | (0x4 << (6 * (id) + 3)))
356#define RK3588_PHP_GRF_CLK_CON1		0x0070
357#define  RK3588_RMII_MODE_GMACx_RMII(id)	((0x1 << (5 * (id))) << 16 | (0x1 << (5 * (id))))
358#define  RK3588_RMII_MODE_GMACx_RGMII(id)	((0x1 << (5 * (id))) << 16 | (0x0 << (5 * (id))))
359#define  RK3588_MII_TX_CLK_SEL_RMII_2_5(id)	((0x3 << (5 * (id) + 2)) << 16 | (0x1 << (5 * (id) + 2)))
360#define  RK3588_MII_TX_CLK_SEL_RMII_25(id)	((0x3 << (5 * (id) + 2)) << 16 | (0x0 << (5 * (id) + 2)))
361#define  RK3588_MII_TX_CLK_SEL_RGMII_2_5(id)	((0x3 << (5 * (id) + 2)) << 16 | (0x2 << (5 * (id) + 2)))
362#define  RK3588_MII_TX_CLK_SEL_RGMII_25(id)	((0x3 << (5 * (id) + 2)) << 16 | (0x3 << (5 * (id) + 2)))
363#define  RK3588_MII_TX_CLK_SEL_RGMII_125(id)	((0x3 << (5 * (id) + 2)) << 16 | (0x0 << (5 * (id) + 2)))
364
365void	dwqe_mii_statchg_jh7110_task(void *);
366void	dwqe_mii_statchg_rk3568_task(void *);
367
368void
369dwqe_setup_jh7110(struct dwqe_softc *sc)
370{
371	struct regmap *rm;
372	uint32_t cells[3];
373	uint32_t phandle, offset, reg, shift;
374	char phy_mode[32];
375	uint32_t iface;
376
377	if (OF_getpropintarray(sc->sc_node, "starfive,syscon", cells,
378	    sizeof(cells)) != sizeof(cells)) {
379		printf("%s: failed to get starfive,syscon\n", __func__);
380		return;
381	}
382	phandle = cells[0];
383	offset = cells[1];
384	shift = cells[2];
385
386	rm = regmap_byphandle(phandle);
387	if (rm == NULL) {
388		printf("%s: failed to get regmap\n", __func__);
389		return;
390	}
391
392	if (OF_getprop(sc->sc_node, "phy-mode", phy_mode,
393	    sizeof(phy_mode)) <= 0)
394		return;
395
396	if (strcmp(phy_mode, "rgmii") == 0 ||
397	    strcmp(phy_mode, "rgmii-id") == 0) {
398		iface = JH7110_PHY_INTF_RGMII;
399	} else if (strcmp(phy_mode, "rmii") == 0) {
400		iface = JH7110_PHY_INTF_RMII;
401	} else
402		return;
403
404	reg = regmap_read_4(rm, offset);
405	reg &= ~(((1U << 3) - 1) << shift);
406	reg |= iface << shift;
407	regmap_write_4(rm, offset, reg);
408
409	task_set(&sc->sc_statchg_task,
410	    dwqe_mii_statchg_jh7110_task, sc);
411}
412
413void
414dwqe_mii_statchg_jh7110_task(void *arg)
415{
416	struct dwqe_softc *sc = arg;
417	struct ifnet *ifp = &sc->sc_ac.ac_if;
418
419	dwqe_mii_statchg(&sc->sc_dev);
420
421	switch (ifp->if_baudrate) {
422	case IF_Mbps(10):
423		clock_set_frequency(sc->sc_node, "tx", 2500000);
424		break;
425	case IF_Mbps(100):
426		clock_set_frequency(sc->sc_node, "tx", 25000000);
427		break;
428	case IF_Mbps(1000):
429		clock_set_frequency(sc->sc_node, "tx", 125000000);
430		break;
431	}
432}
433
434void
435dwqe_mii_statchg_jh7110(struct device *self)
436{
437	struct dwqe_softc *sc = (void *)self;
438
439	task_add(systq, &sc->sc_statchg_task);
440}
441
442void
443dwqe_setup_rk3568(struct dwqe_fdt_softc *fsc)
444{
445	struct dwqe_softc *sc = &fsc->sc_sc;
446	struct regmap *rm;
447	uint32_t grf;
448	int tx_delay, rx_delay;
449	uint32_t iface;
450
451	grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0);
452	rm = regmap_byphandle(grf);
453	if (rm == NULL)
454		return;
455
456	switch (sc->sc_phy_mode) {
457	case DWQE_PHY_MODE_RGMII:
458	case DWQE_PHY_MODE_RGMII_ID:
459	case DWQE_PHY_MODE_RGMII_RXID:
460	case DWQE_PHY_MODE_RGMII_TXID:
461		iface = RK3568_GMAC_PHY_INTF_SEL_RGMII;
462		break;
463	case DWQE_PHY_MODE_RMII:
464		iface = RK3568_GMAC_PHY_INTF_SEL_RMII;
465		break;
466	default:
467		return;
468	}
469
470	tx_delay = OF_getpropint(sc->sc_node, "tx_delay", 0x30);
471	rx_delay = OF_getpropint(sc->sc_node, "rx_delay", 0x10);
472	switch (sc->sc_phy_mode) {
473	case DWQE_PHY_MODE_RGMII_ID:
474		tx_delay = rx_delay = 0;
475		break;
476	case DWQE_PHY_MODE_RGMII_RXID:
477		rx_delay = 0;
478		break;
479	case DWQE_PHY_MODE_RGMII_TXID:
480		tx_delay = 0;
481		break;
482	default:
483		break;
484	}
485
486	/* Program clock delay lines. */
487	regmap_write_4(rm, RK3568_GRF_GMACx_CON0(fsc->sc_gmac_id),
488	    RK3568_GMAC_CLK_TX_DL_CFG(tx_delay) |
489	    RK3568_GMAC_CLK_RX_DL_CFG(rx_delay));
490
491	/* Set interface and enable/disable clock delay. */
492	regmap_write_4(rm, RK3568_GRF_GMACx_CON1(fsc->sc_gmac_id), iface |
493	    RK3568_GMAC_TXCLK_DLY_SET(tx_delay > 0 ? 1 : 0) |
494	    RK3568_GMAC_RXCLK_DLY_SET(rx_delay > 0 ? 1 : 0));
495
496	task_set(&sc->sc_statchg_task,
497	    dwqe_mii_statchg_rk3568_task, sc);
498}
499
500void
501dwqe_mii_statchg_rk3568_task(void *arg)
502{
503	struct dwqe_softc *sc = arg;
504	struct ifnet *ifp = &sc->sc_ac.ac_if;
505
506	dwqe_mii_statchg(&sc->sc_dev);
507
508	switch (ifp->if_baudrate) {
509	case IF_Mbps(10):
510		clock_set_frequency(sc->sc_node, "clk_mac_speed", 2500000);
511		break;
512	case IF_Mbps(100):
513		clock_set_frequency(sc->sc_node, "clk_mac_speed", 25000000);
514		break;
515	case IF_Mbps(1000):
516		clock_set_frequency(sc->sc_node, "clk_mac_speed", 125000000);
517		break;
518	}
519}
520
521void
522dwqe_mii_statchg_rk3568(struct device *self)
523{
524	struct dwqe_softc *sc = (void *)self;
525
526	task_add(systq, &sc->sc_statchg_task);
527}
528
529void
530dwqe_setup_rk3588(struct dwqe_fdt_softc *fsc)
531{
532	struct dwqe_softc *sc = &fsc->sc_sc;
533	struct regmap *rm;
534	struct regmap *php_rm;
535	uint32_t grf, php_grf;
536	int tx_delay, rx_delay;
537	uint32_t iface, clk;
538
539	grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0);
540	rm = regmap_byphandle(grf);
541	if (rm == NULL)
542		return;
543
544	php_grf = OF_getpropint(sc->sc_node, "rockchip,php-grf", 0);
545	php_rm = regmap_byphandle(php_grf);
546	if (php_rm == NULL)
547		return;
548
549	switch (sc->sc_phy_mode) {
550	case DWQE_PHY_MODE_RGMII:
551	case DWQE_PHY_MODE_RGMII_ID:
552	case DWQE_PHY_MODE_RGMII_RXID:
553	case DWQE_PHY_MODE_RGMII_TXID:
554		iface = RK3588_GMACx_PHY_INTF_SEL_RGMII(fsc->sc_gmac_id);
555		clk = RK3588_RMII_MODE_GMACx_RGMII(fsc->sc_gmac_id);
556		sc->sc_clk_sel_2_5 =
557		    RK3588_MII_TX_CLK_SEL_RGMII_2_5(fsc->sc_gmac_id);
558		sc->sc_clk_sel_25 =
559		    RK3588_MII_TX_CLK_SEL_RGMII_25(fsc->sc_gmac_id);
560		sc->sc_clk_sel_125 =
561		    RK3588_MII_TX_CLK_SEL_RGMII_125(fsc->sc_gmac_id);
562		break;
563	case DWQE_PHY_MODE_RMII:
564		iface = RK3588_GMACx_PHY_INTF_SEL_RMII(fsc->sc_gmac_id);
565		clk = RK3588_RMII_MODE_GMACx_RMII(fsc->sc_gmac_id);
566		sc->sc_clk_sel_2_5 =
567		    RK3588_MII_TX_CLK_SEL_RMII_2_5(fsc->sc_gmac_id);
568		sc->sc_clk_sel_25 =
569		    RK3588_MII_TX_CLK_SEL_RMII_25(fsc->sc_gmac_id);
570		break;
571	default:
572		return;
573	}
574
575	tx_delay = OF_getpropint(sc->sc_node, "tx_delay", 0x30);
576	rx_delay = OF_getpropint(sc->sc_node, "rx_delay", 0x10);
577	switch (sc->sc_phy_mode) {
578	case DWQE_PHY_MODE_RGMII_ID:
579		tx_delay = rx_delay = 0;
580		break;
581	case DWQE_PHY_MODE_RGMII_RXID:
582		rx_delay = 0;
583		break;
584	case DWQE_PHY_MODE_RGMII_TXID:
585		tx_delay = 0;
586		break;
587	default:
588		break;
589	}
590
591	/* Set interface and clock. */
592	regmap_write_4(php_rm, RK3588_PHP_GRF_GMAC_CON0, iface);
593	regmap_write_4(php_rm, RK3588_PHP_GRF_CLK_CON1, clk);
594
595	/* Enable clock delay. */
596	regmap_write_4(rm, RK3588_GRF_GMAC_CON7,
597	    RK3588_GMACx_TXCLK_DLY_ENA(fsc->sc_gmac_id) |
598	    RK3588_GMACx_RXCLK_DLY_ENA(fsc->sc_gmac_id));
599
600	/* Program clock delay lines. */
601	regmap_write_4(rm, fsc->sc_gmac_id == 1 ?
602	    RK3588_GRF_GMAC_CON9 : RK3588_GRF_GMAC_CON8,
603	    RK3588_GMAC_CLK_TX_DL_CFG(tx_delay) |
604	    RK3588_GMAC_CLK_RX_DL_CFG(rx_delay));
605}
606
607void
608dwqe_mii_statchg_rk3588(struct device *self)
609{
610	struct dwqe_softc *sc = (void *)self;
611	struct ifnet *ifp = &sc->sc_ac.ac_if;
612	struct regmap *php_rm;
613	uint32_t php_grf;
614	uint32_t gmac_clk_sel = 0;
615
616	dwqe_mii_statchg(self);
617
618	php_grf = OF_getpropint(sc->sc_node, "rockchip,php-grf", 0);
619	php_rm = regmap_byphandle(php_grf);
620	if (php_rm == NULL)
621		return;
622
623	switch (ifp->if_baudrate) {
624	case IF_Mbps(10):
625		gmac_clk_sel = sc->sc_clk_sel_2_5;
626		break;
627	case IF_Mbps(100):
628		gmac_clk_sel = sc->sc_clk_sel_25;
629		break;
630	case IF_Mbps(1000):
631		gmac_clk_sel = sc->sc_clk_sel_125;
632		break;
633	}
634
635	regmap_write_4(php_rm, RK3588_PHP_GRF_CLK_CON1, gmac_clk_sel);
636}
637