xref: /freebsd/sys/dev/etherswitch/ar40xx/ar40xx_hw_psgmii.c (revision 1f469a9fc498c3d406ef7c4e347232678f49da0a)
1e388de98SAdrian Chadd /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3e388de98SAdrian Chadd  *
4e388de98SAdrian Chadd  * Copyright (c) 2022 Adrian Chadd <adrian@FreeBSD.org>.
5e388de98SAdrian Chadd  *
6e388de98SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
7e388de98SAdrian Chadd  * modification, are permitted provided that the following conditions
8e388de98SAdrian Chadd  * are met:
9e388de98SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
10e388de98SAdrian Chadd  *    notice, this list of conditions and the following disclaimer.
11e388de98SAdrian Chadd  * 2. Redistributions in binary form must reproduce the above copyright
12e388de98SAdrian Chadd  *    notice, this list of conditions and the following disclaimer in the
13e388de98SAdrian Chadd  *    documentation and/or other materials provided with the distribution.
14e388de98SAdrian Chadd  *
15e388de98SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e388de98SAdrian Chadd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e388de98SAdrian Chadd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e388de98SAdrian Chadd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e388de98SAdrian Chadd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e388de98SAdrian Chadd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e388de98SAdrian Chadd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e388de98SAdrian Chadd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e388de98SAdrian Chadd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e388de98SAdrian Chadd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e388de98SAdrian Chadd  * SUCH DAMAGE.
26e388de98SAdrian Chadd  */
27e388de98SAdrian Chadd 
28e388de98SAdrian Chadd #include <sys/param.h>
29e388de98SAdrian Chadd #include <sys/bus.h>
30e388de98SAdrian Chadd #include <sys/errno.h>
31e388de98SAdrian Chadd #include <sys/kernel.h>
32e388de98SAdrian Chadd #include <sys/malloc.h>
33e388de98SAdrian Chadd #include <sys/module.h>
34e388de98SAdrian Chadd #include <sys/socket.h>
35e388de98SAdrian Chadd #include <sys/sockio.h>
36e388de98SAdrian Chadd #include <sys/sysctl.h>
37e388de98SAdrian Chadd #include <sys/systm.h>
38e388de98SAdrian Chadd 
39e388de98SAdrian Chadd #include <net/if.h>
40e388de98SAdrian Chadd #include <net/if_var.h>
41e388de98SAdrian Chadd #include <net/if_arp.h>
42e388de98SAdrian Chadd #include <net/ethernet.h>
43e388de98SAdrian Chadd #include <net/if_dl.h>
44e388de98SAdrian Chadd #include <net/if_media.h>
45e388de98SAdrian Chadd #include <net/if_types.h>
46e388de98SAdrian Chadd 
47e388de98SAdrian Chadd #include <machine/bus.h>
48e388de98SAdrian Chadd #include <dev/iicbus/iic.h>
49e388de98SAdrian Chadd #include <dev/iicbus/iiconf.h>
50e388de98SAdrian Chadd #include <dev/iicbus/iicbus.h>
51e388de98SAdrian Chadd #include <dev/mii/mii.h>
52e388de98SAdrian Chadd #include <dev/mii/miivar.h>
53e388de98SAdrian Chadd #include <dev/mdio/mdio.h>
54be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
55*1f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h>
56e388de98SAdrian Chadd 
57e388de98SAdrian Chadd #include <dev/fdt/fdt_common.h>
58e388de98SAdrian Chadd #include <dev/ofw/ofw_bus.h>
59e388de98SAdrian Chadd #include <dev/ofw/ofw_bus_subr.h>
60e388de98SAdrian Chadd 
61e388de98SAdrian Chadd #include <dev/etherswitch/etherswitch.h>
62e388de98SAdrian Chadd 
63e388de98SAdrian Chadd #include <dev/etherswitch/ar40xx/ar40xx_var.h>
64e388de98SAdrian Chadd #include <dev/etherswitch/ar40xx/ar40xx_reg.h>
65e388de98SAdrian Chadd #include <dev/etherswitch/ar40xx/ar40xx_hw.h>
66e388de98SAdrian Chadd #include <dev/etherswitch/ar40xx/ar40xx_phy.h>
67e388de98SAdrian Chadd #include <dev/etherswitch/ar40xx/ar40xx_hw_atu.h>
68e388de98SAdrian Chadd #include <dev/etherswitch/ar40xx/ar40xx_hw_mdio.h>
69e388de98SAdrian Chadd #include <dev/etherswitch/ar40xx/ar40xx_hw_psgmii.h>
70e388de98SAdrian Chadd 
71e388de98SAdrian Chadd #include "mdio_if.h"
72e388de98SAdrian Chadd #include "miibus_if.h"
73e388de98SAdrian Chadd #include "etherswitch_if.h"
74e388de98SAdrian Chadd 
75e388de98SAdrian Chadd /*
76e388de98SAdrian Chadd  * Routines that control the ess-psgmii block - the interconnect
77e388de98SAdrian Chadd  * between the ess-switch and the external multi-port PHY
78e388de98SAdrian Chadd  * (eg Maple.)
79e388de98SAdrian Chadd  */
80e388de98SAdrian Chadd 
81e388de98SAdrian Chadd static void
ar40xx_hw_psgmii_reg_write(struct ar40xx_softc * sc,uint32_t reg,uint32_t val)82e388de98SAdrian Chadd ar40xx_hw_psgmii_reg_write(struct ar40xx_softc *sc, uint32_t reg,
83e388de98SAdrian Chadd     uint32_t val)
84e388de98SAdrian Chadd {
85e388de98SAdrian Chadd 	bus_space_write_4(sc->sc_psgmii_mem_tag, sc->sc_psgmii_mem_handle,
86e388de98SAdrian Chadd 	    reg, val);
87e388de98SAdrian Chadd 	bus_space_barrier(sc->sc_psgmii_mem_tag, sc->sc_psgmii_mem_handle,
88e388de98SAdrian Chadd 	    0, sc->sc_psgmii_mem_size, BUS_SPACE_BARRIER_WRITE);
89e388de98SAdrian Chadd }
90e388de98SAdrian Chadd 
91e388de98SAdrian Chadd static int
ar40xx_hw_psgmii_reg_read(struct ar40xx_softc * sc,uint32_t reg)92e388de98SAdrian Chadd ar40xx_hw_psgmii_reg_read(struct ar40xx_softc *sc, uint32_t reg)
93e388de98SAdrian Chadd {
94e388de98SAdrian Chadd 	int ret;
95e388de98SAdrian Chadd 
96e388de98SAdrian Chadd 	bus_space_barrier(sc->sc_psgmii_mem_tag, sc->sc_psgmii_mem_handle,
97e388de98SAdrian Chadd 	    0, sc->sc_psgmii_mem_size, BUS_SPACE_BARRIER_READ);
98e388de98SAdrian Chadd 	ret = bus_space_read_4(sc->sc_psgmii_mem_tag, sc->sc_psgmii_mem_handle,
99e388de98SAdrian Chadd 	    reg);
100e388de98SAdrian Chadd 
101e388de98SAdrian Chadd 	return (ret);
102e388de98SAdrian Chadd }
103e388de98SAdrian Chadd 
104e388de98SAdrian Chadd int
ar40xx_hw_psgmii_set_mac_mode(struct ar40xx_softc * sc,uint32_t mac_mode)105e388de98SAdrian Chadd ar40xx_hw_psgmii_set_mac_mode(struct ar40xx_softc *sc, uint32_t mac_mode)
106e388de98SAdrian Chadd {
107e388de98SAdrian Chadd 	if (mac_mode == PORT_WRAPPER_PSGMII) {
108e388de98SAdrian Chadd 		ar40xx_hw_psgmii_reg_write(sc, AR40XX_PSGMII_MODE_CONTROL,
109e388de98SAdrian Chadd 		    0x2200);
110e388de98SAdrian Chadd 		ar40xx_hw_psgmii_reg_write(sc, AR40XX_PSGMIIPHY_TX_CONTROL,
111e388de98SAdrian Chadd 		    0x8380);
112e388de98SAdrian Chadd 	} else {
113e388de98SAdrian Chadd 		device_printf(sc->sc_dev, "WARNING: unknown MAC_MODE=%u\n",
114e388de98SAdrian Chadd 		    mac_mode);
115e388de98SAdrian Chadd 	}
116e388de98SAdrian Chadd 
117e388de98SAdrian Chadd 	return (0);
118e388de98SAdrian Chadd }
119e388de98SAdrian Chadd 
120e388de98SAdrian Chadd int
ar40xx_hw_psgmii_single_phy_testing(struct ar40xx_softc * sc,int phy)121e388de98SAdrian Chadd ar40xx_hw_psgmii_single_phy_testing(struct ar40xx_softc *sc, int phy)
122e388de98SAdrian Chadd {
123e388de98SAdrian Chadd 	int j;
124e388de98SAdrian Chadd 	uint32_t tx_ok, tx_error;
125e388de98SAdrian Chadd 	uint32_t rx_ok, rx_error;
126e388de98SAdrian Chadd 	uint32_t tx_ok_high16;
127e388de98SAdrian Chadd 	uint32_t rx_ok_high16;
128e388de98SAdrian Chadd 	uint32_t tx_all_ok, rx_all_ok;
129e388de98SAdrian Chadd 
130e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, phy, 0x0, 0x9000);
131e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, phy, 0x0, 0x4140);
132e388de98SAdrian Chadd 
133e388de98SAdrian Chadd 	for (j = 0; j < AR40XX_PSGMII_CALB_NUM; j++) {
134e388de98SAdrian Chadd 		uint16_t status;
135e388de98SAdrian Chadd 
136e388de98SAdrian Chadd 	status = MDIO_READREG(sc->sc_mdio_dev, phy, 0x11);
137e388de98SAdrian Chadd 		if (status & AR40XX_PHY_SPEC_STATUS_LINK)
138e388de98SAdrian Chadd 			break;
139e388de98SAdrian Chadd 			/*
140e388de98SAdrian Chadd 			 * the polling interval to check if the PHY link up
141e388de98SAdrian Chadd 			 * or not
142e388de98SAdrian Chadd 			 * maxwait_timer: 750 ms +/-10 ms
143e388de98SAdrian Chadd 			 * minwait_timer : 1 us +/- 0.1us
144e388de98SAdrian Chadd 			 * time resides in minwait_timer ~ maxwait_timer
145e388de98SAdrian Chadd 			 * see IEEE 802.3 section 40.4.5.2
146e388de98SAdrian Chadd 			 */
147e388de98SAdrian Chadd 		DELAY(8 * 1000);
148e388de98SAdrian Chadd 	}
149e388de98SAdrian Chadd 
150e388de98SAdrian Chadd 	/* enable check */
151e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, phy, 7, 0x8029, 0x0000);
152e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, phy, 7, 0x8029, 0x0003);
153e388de98SAdrian Chadd 
154e388de98SAdrian Chadd 	/* start traffic */
155e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, phy, 7, 0x8020, 0xa000);
156e388de98SAdrian Chadd 	/*
157e388de98SAdrian Chadd 	 *wait for all traffic end
158e388de98SAdrian Chadd 	 * 4096(pkt num)*1524(size)*8ns(125MHz)=49.9ms
159e388de98SAdrian Chadd 	 */
160e388de98SAdrian Chadd 	DELAY(60 * 1000);
161e388de98SAdrian Chadd 
162e388de98SAdrian Chadd 	/* check counter */
163e388de98SAdrian Chadd 	tx_ok = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802e);
164e388de98SAdrian Chadd 	tx_ok_high16 = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802d);
165e388de98SAdrian Chadd 	tx_error = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802f);
166e388de98SAdrian Chadd 	rx_ok = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802b);
167e388de98SAdrian Chadd 	rx_ok_high16 = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802a);
168e388de98SAdrian Chadd 	rx_error = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802c);
169e388de98SAdrian Chadd 	tx_all_ok = tx_ok + (tx_ok_high16 << 16);
170e388de98SAdrian Chadd 	rx_all_ok = rx_ok + (rx_ok_high16 << 16);
171e388de98SAdrian Chadd 
172e388de98SAdrian Chadd 	if (tx_all_ok == 0x1000 && tx_error == 0) {
173e388de98SAdrian Chadd 		/* success */
174e388de98SAdrian Chadd 		sc->sc_psgmii.phy_t_status &= ~(1U << phy);
175e388de98SAdrian Chadd 	} else {
176e388de98SAdrian Chadd 		device_printf(sc->sc_dev, "TX_OK=%d, tx_error=%d RX_OK=%d"
177e388de98SAdrian Chadd 		    " rx_error=%d\n",
178e388de98SAdrian Chadd 		    tx_all_ok, tx_error, rx_all_ok, rx_error);
179e388de98SAdrian Chadd 		device_printf(sc->sc_dev,
180e388de98SAdrian Chadd 		    "PHY %d single test PSGMII issue happen!\n", phy);
181e388de98SAdrian Chadd 		sc->sc_psgmii.phy_t_status |= BIT(phy);
182e388de98SAdrian Chadd 	}
183e388de98SAdrian Chadd 
184e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, phy, 0x0, 0x1840);
185e388de98SAdrian Chadd 	return (0);
186e388de98SAdrian Chadd }
187e388de98SAdrian Chadd 
188e388de98SAdrian Chadd int
ar40xx_hw_psgmii_all_phy_testing(struct ar40xx_softc * sc)189e388de98SAdrian Chadd ar40xx_hw_psgmii_all_phy_testing(struct ar40xx_softc *sc)
190e388de98SAdrian Chadd {
191e388de98SAdrian Chadd 	int phy, j;
192e388de98SAdrian Chadd 
193e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 0x1f, 0x0, 0x9000);
194e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 0x1f, 0x0, 0x4140);
195e388de98SAdrian Chadd 
196e388de98SAdrian Chadd 	for (j = 0; j < AR40XX_PSGMII_CALB_NUM; j++) {
197e388de98SAdrian Chadd 		for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
198e388de98SAdrian Chadd 			uint16_t status;
199e388de98SAdrian Chadd 
200e388de98SAdrian Chadd 			status = MDIO_READREG(sc->sc_mdio_dev, phy, 0x11);
201e388de98SAdrian Chadd 			if (!(status & (1U << 10)))
202e388de98SAdrian Chadd 				break;
203e388de98SAdrian Chadd 		}
204e388de98SAdrian Chadd 
205e388de98SAdrian Chadd 		if (phy >= (AR40XX_NUM_PORTS - 1))
206e388de98SAdrian Chadd 			break;
207e388de98SAdrian Chadd 		/* The polling interval to check if the PHY link up or not */
208e388de98SAdrian Chadd 		DELAY(8*1000);
209e388de98SAdrian Chadd 	}
210e388de98SAdrian Chadd 
211e388de98SAdrian Chadd 	/* enable check */
212e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, 0x1f, 7, 0x8029, 0x0000);
213e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, 0x1f, 7, 0x8029, 0x0003);
214e388de98SAdrian Chadd 
215e388de98SAdrian Chadd 	/* start traffic */
216e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, 0x1f, 7, 0x8020, 0xa000);
217e388de98SAdrian Chadd 	/*
218e388de98SAdrian Chadd 	 * wait for all traffic end
219e388de98SAdrian Chadd 	 * 4096(pkt num)*1524(size)*8ns(125MHz)=49.9ms
220e388de98SAdrian Chadd 	 */
221e388de98SAdrian Chadd 	DELAY(60*1000); /* was 50ms */
222e388de98SAdrian Chadd 
223e388de98SAdrian Chadd 	for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
224e388de98SAdrian Chadd 		uint32_t tx_ok, tx_error;
225e388de98SAdrian Chadd 		uint32_t rx_ok, rx_error;
226e388de98SAdrian Chadd 		uint32_t tx_ok_high16;
227e388de98SAdrian Chadd 		uint32_t rx_ok_high16;
228e388de98SAdrian Chadd 		uint32_t tx_all_ok, rx_all_ok;
229e388de98SAdrian Chadd 
230e388de98SAdrian Chadd 		/* check counter */
231e388de98SAdrian Chadd 		tx_ok = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802e);
232e388de98SAdrian Chadd 		tx_ok_high16 = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802d);
233e388de98SAdrian Chadd 		tx_error = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802f);
234e388de98SAdrian Chadd 		rx_ok = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802b);
235e388de98SAdrian Chadd 		rx_ok_high16 = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802a);
236e388de98SAdrian Chadd 		rx_error = ar40xx_hw_phy_mmd_read(sc, phy, 7, 0x802c);
237e388de98SAdrian Chadd 
238e388de98SAdrian Chadd 		tx_all_ok = tx_ok + (tx_ok_high16<<16);
239e388de98SAdrian Chadd 		rx_all_ok = rx_ok + (rx_ok_high16<<16);
240e388de98SAdrian Chadd 		if (tx_all_ok == 0x1000 && tx_error == 0) {
241e388de98SAdrian Chadd 			/* success */
242e388de98SAdrian Chadd 			sc->sc_psgmii.phy_t_status &= ~(1U << (phy + 8));
243e388de98SAdrian Chadd 		} else {
244e388de98SAdrian Chadd 			device_printf(sc->sc_dev,
245e388de98SAdrian Chadd 			    "PHY%d test see issue! (tx_all_ok=%u,"
246e388de98SAdrian Chadd 			    " rx_all_ok=%u, tx_error=%u, rx_error=%u)\n",
247e388de98SAdrian Chadd 			    phy, tx_all_ok, rx_all_ok, tx_error, rx_error);
248e388de98SAdrian Chadd 			sc->sc_psgmii.phy_t_status |= (1U << (phy + 8));
249e388de98SAdrian Chadd 		}
250e388de98SAdrian Chadd 	}
251e388de98SAdrian Chadd 
252e388de98SAdrian Chadd 	device_printf(sc->sc_dev, "PHY all test 0x%x\n",
253e388de98SAdrian Chadd 	    sc->sc_psgmii.phy_t_status);
254e388de98SAdrian Chadd 	return (0);
255e388de98SAdrian Chadd }
256e388de98SAdrian Chadd 
257e388de98SAdrian Chadd /*
258e388de98SAdrian Chadd  * Reset PSGMII in the Malibu PHY.
259e388de98SAdrian Chadd  */
260e388de98SAdrian Chadd int
ar40xx_hw_malibu_psgmii_ess_reset(struct ar40xx_softc * sc)261e388de98SAdrian Chadd ar40xx_hw_malibu_psgmii_ess_reset(struct ar40xx_softc *sc)
262e388de98SAdrian Chadd {
263e388de98SAdrian Chadd 	device_printf(sc->sc_dev, "%s: called\n", __func__);
264e388de98SAdrian Chadd 	uint32_t i;
265e388de98SAdrian Chadd 
266e388de98SAdrian Chadd 	/* reset phy psgmii */
267e388de98SAdrian Chadd 	/* fix phy psgmii RX 20bit */
268e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 5, 0x0, 0x005b);
269e388de98SAdrian Chadd 	/* reset phy psgmii */
270e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 5, 0x0, 0x001b);
271e388de98SAdrian Chadd 	/* release reset phy psgmii */
272e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 5, 0x0, 0x005b);
273e388de98SAdrian Chadd 
274e388de98SAdrian Chadd 	for (i = 0; i < AR40XX_PSGMII_CALB_NUM; i++) {
275e388de98SAdrian Chadd 		uint32_t status;
276e388de98SAdrian Chadd 
277e388de98SAdrian Chadd 		status = ar40xx_hw_phy_mmd_read(sc, 5, 1, 0x28);
278e388de98SAdrian Chadd 		if (status & (1U << 0))
279e388de98SAdrian Chadd 			break;
280e388de98SAdrian Chadd 		/*
281e388de98SAdrian Chadd 		 * Polling interval to check PSGMII PLL in malibu is ready
282e388de98SAdrian Chadd 		 * the worst time is 8.67ms
283e388de98SAdrian Chadd 		 * for 25MHz reference clock
284e388de98SAdrian Chadd 		 * [512+(128+2048)*49]*80ns+100us
285e388de98SAdrian Chadd 		 */
286e388de98SAdrian Chadd 		DELAY(2000);
287e388de98SAdrian Chadd 	}
288e388de98SAdrian Chadd 	/* XXX TODO ;see if it timed out? */
289e388de98SAdrian Chadd 
290e388de98SAdrian Chadd 	/*check malibu psgmii calibration done end..*/
291e388de98SAdrian Chadd 
292e388de98SAdrian Chadd 	/*freeze phy psgmii RX CDR*/
293e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 5, 0x1a, 0x2230);
294e388de98SAdrian Chadd 
295e388de98SAdrian Chadd 	ar40xx_hw_ess_reset(sc);
296e388de98SAdrian Chadd 
297e388de98SAdrian Chadd 	/*check psgmii calibration done start*/
298e388de98SAdrian Chadd 	for (i = 0; i < AR40XX_PSGMII_CALB_NUM; i++) {
299e388de98SAdrian Chadd 		uint32_t status;
300e388de98SAdrian Chadd 
301e388de98SAdrian Chadd 		status = ar40xx_hw_psgmii_reg_read(sc, 0xa0);
302e388de98SAdrian Chadd 		if (status & (1U << 0))
303e388de98SAdrian Chadd 			break;
304e388de98SAdrian Chadd 		/* Polling interval to check PSGMII PLL in ESS is ready */
305e388de98SAdrian Chadd 		DELAY(2000);
306e388de98SAdrian Chadd 	}
307e388de98SAdrian Chadd 	/* XXX TODO ;see if it timed out? */
308e388de98SAdrian Chadd 
309e388de98SAdrian Chadd 	/* check dakota psgmii calibration done end..*/
310e388de98SAdrian Chadd 
311e388de98SAdrian Chadd 	/* release phy psgmii RX CDR */
312e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 5, 0x1a, 0x3230);
313e388de98SAdrian Chadd 	/* release phy psgmii RX 20bit */
314e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 5, 0x0, 0x005f);
315e388de98SAdrian Chadd 
316e388de98SAdrian Chadd 	return (0);
317e388de98SAdrian Chadd }
318e388de98SAdrian Chadd 
319e388de98SAdrian Chadd int
ar40xx_hw_psgmii_self_test(struct ar40xx_softc * sc)320e388de98SAdrian Chadd ar40xx_hw_psgmii_self_test(struct ar40xx_softc *sc)
321e388de98SAdrian Chadd {
322e388de98SAdrian Chadd 	uint32_t i, phy, reg;
323e388de98SAdrian Chadd 
324e388de98SAdrian Chadd 	device_printf(sc->sc_dev, "%s: called\n", __func__);
325e388de98SAdrian Chadd 
326e388de98SAdrian Chadd 	ar40xx_hw_malibu_psgmii_ess_reset(sc);
327e388de98SAdrian Chadd 
328e388de98SAdrian Chadd 	/* switch to access MII reg for copper */
329e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 4, 0x1f, 0x8500);
330e388de98SAdrian Chadd 	for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
331e388de98SAdrian Chadd 		/*enable phy mdio broadcast write*/
332e388de98SAdrian Chadd 		ar40xx_hw_phy_mmd_write(sc, phy, 7, 0x8028, 0x801f);
333e388de98SAdrian Chadd 	}
334e388de98SAdrian Chadd 
335e388de98SAdrian Chadd 	/* force no link by power down */
336e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 0x1f, 0x0, 0x1840);
337e388de98SAdrian Chadd 
338e388de98SAdrian Chadd 	/* packet number*/
339e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, 0x1f, 7, 0x8021, 0x1000);
340e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, 0x1f, 7, 0x8062, 0x05e0);
341e388de98SAdrian Chadd 
342e388de98SAdrian Chadd 	/* fix mdi status */
343e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 0x1f, 0x10, 0x6800);
344e388de98SAdrian Chadd 	for (i = 0; i < AR40XX_PSGMII_CALB_NUM; i++) {
345e388de98SAdrian Chadd 		sc->sc_psgmii.phy_t_status = 0;
346e388de98SAdrian Chadd 
347e388de98SAdrian Chadd 		for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
348e388de98SAdrian Chadd 			/* Enable port loopback for testing */
349e388de98SAdrian Chadd 			AR40XX_REG_BARRIER_READ(sc);
350e388de98SAdrian Chadd 			reg = AR40XX_REG_READ(sc,
351e388de98SAdrian Chadd 			    AR40XX_REG_PORT_LOOKUP(phy + 1));
352e388de98SAdrian Chadd 			reg |= AR40XX_PORT_LOOKUP_LOOPBACK;
353e388de98SAdrian Chadd 			AR40XX_REG_WRITE(sc,
354e388de98SAdrian Chadd 			    AR40XX_REG_PORT_LOOKUP(phy + 1), reg);
355e388de98SAdrian Chadd 			AR40XX_REG_BARRIER_WRITE(sc);
356e388de98SAdrian Chadd 		}
357e388de98SAdrian Chadd 
358e388de98SAdrian Chadd 		for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++)
359e388de98SAdrian Chadd 			ar40xx_hw_psgmii_single_phy_testing(sc, phy);
360e388de98SAdrian Chadd 
361e388de98SAdrian Chadd 		ar40xx_hw_psgmii_all_phy_testing(sc);
362e388de98SAdrian Chadd 
363e388de98SAdrian Chadd 		if (sc->sc_psgmii.phy_t_status)
364e388de98SAdrian Chadd 			ar40xx_hw_malibu_psgmii_ess_reset(sc);
365e388de98SAdrian Chadd 		else
366e388de98SAdrian Chadd 			break;
367e388de98SAdrian Chadd 	}
368e388de98SAdrian Chadd 
369e388de98SAdrian Chadd 	if (i >= AR40XX_PSGMII_CALB_NUM)
370e388de98SAdrian Chadd 		device_printf(sc->sc_dev, "PSGMII cannot recover\n");
371e388de98SAdrian Chadd 	else
372e388de98SAdrian Chadd 		device_printf(sc->sc_dev,
373e388de98SAdrian Chadd 		    "PSGMII recovered after %d times reset\n", i);
374e388de98SAdrian Chadd 
375e388de98SAdrian Chadd 	/* configuration recover */
376e388de98SAdrian Chadd 	/* packet number */
377e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, 0x1f, 7, 0x8021, 0x0);
378e388de98SAdrian Chadd 	/* disable check */
379e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, 0x1f, 7, 0x8029, 0x0);
380e388de98SAdrian Chadd 	/* disable traffic */
381e388de98SAdrian Chadd 	ar40xx_hw_phy_mmd_write(sc, 0x1f, 7, 0x8020, 0x0);
382e388de98SAdrian Chadd 
383e388de98SAdrian Chadd 	return (0);
384e388de98SAdrian Chadd }
385e388de98SAdrian Chadd 
386e388de98SAdrian Chadd int
ar40xx_hw_psgmii_self_test_clean(struct ar40xx_softc * sc)387e388de98SAdrian Chadd ar40xx_hw_psgmii_self_test_clean(struct ar40xx_softc *sc)
388e388de98SAdrian Chadd {
389e388de98SAdrian Chadd 	uint32_t reg;
390e388de98SAdrian Chadd 	int phy;
391e388de98SAdrian Chadd 
392e388de98SAdrian Chadd 	device_printf(sc->sc_dev, "%s: called\n", __func__);
393e388de98SAdrian Chadd 
394e388de98SAdrian Chadd 	/* disable phy internal loopback */
395e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 0x1f, 0x10, 0x6860);
396e388de98SAdrian Chadd 	MDIO_WRITEREG(sc->sc_mdio_dev, 0x1f, 0x0, 0x9040);
397e388de98SAdrian Chadd 
398e388de98SAdrian Chadd         for (phy = 0; phy < AR40XX_NUM_PORTS - 1; phy++) {
399e388de98SAdrian Chadd 		/* disable mac loop back */
400e388de98SAdrian Chadd 		reg = AR40XX_REG_READ(sc, AR40XX_REG_PORT_LOOKUP(phy + 1));
401e388de98SAdrian Chadd 		reg &= ~AR40XX_PORT_LOOKUP_LOOPBACK;
402e388de98SAdrian Chadd 		AR40XX_REG_WRITE(sc, AR40XX_REG_PORT_LOOKUP(phy + 1), reg);
403e388de98SAdrian Chadd 		AR40XX_REG_BARRIER_WRITE(sc);
404e388de98SAdrian Chadd 
405e388de98SAdrian Chadd 		/* disable phy mdio broadcast write */
406e388de98SAdrian Chadd 		ar40xx_hw_phy_mmd_write(sc, phy, 7, 0x8028, 0x001f);
407e388de98SAdrian Chadd 	}
408e388de98SAdrian Chadd 
409e388de98SAdrian Chadd 	/* clear fdb entry */
410e388de98SAdrian Chadd 	ar40xx_hw_atu_flush_all(sc);
411e388de98SAdrian Chadd 
412e388de98SAdrian Chadd 	return (0);
413e388de98SAdrian Chadd }
414e388de98SAdrian Chadd 
415e388de98SAdrian Chadd int
ar40xx_hw_psgmii_init_config(struct ar40xx_softc * sc)416e388de98SAdrian Chadd ar40xx_hw_psgmii_init_config(struct ar40xx_softc *sc)
417e388de98SAdrian Chadd {
418e388de98SAdrian Chadd 	uint32_t reg;
419e388de98SAdrian Chadd 
420e388de98SAdrian Chadd 	/*
421e388de98SAdrian Chadd 	 * This is based on what I found in uboot - it configures
422e388de98SAdrian Chadd 	 * the initial ESS interconnect to either be PSGMII
423e388de98SAdrian Chadd 	 * or RGMII.
424e388de98SAdrian Chadd 	 */
425e388de98SAdrian Chadd 
426e388de98SAdrian Chadd 	/* For now, just assume PSGMII and fix it in post. */
427e388de98SAdrian Chadd 	/* PSGMIIPHY_PLL_VCO_RELATED_CTRL */
428e388de98SAdrian Chadd 	reg = ar40xx_hw_psgmii_reg_read(sc, 0x78c);
429e388de98SAdrian Chadd 	device_printf(sc->sc_dev,
430e388de98SAdrian Chadd 	    "%s: PSGMIIPHY_PLL_VCO_RELATED_CTRL=0x%08x\n", __func__, reg);
431e388de98SAdrian Chadd 	/* PSGMIIPHY_VCO_CALIBRATION_CTRL */
432e388de98SAdrian Chadd 	reg = ar40xx_hw_psgmii_reg_read(sc, 0x09c);
433e388de98SAdrian Chadd 	device_printf(sc->sc_dev,
434e388de98SAdrian Chadd 	    "%s: PSGMIIPHY_VCO_CALIBRATION_CTRL=0x%08x\n", __func__, reg);
435e388de98SAdrian Chadd 
436e388de98SAdrian Chadd 	return (0);
437e388de98SAdrian Chadd }
438