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