1 /* $NetBSD: mcommphy.c,v 1.6 2025/11/30 07:12:03 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 2022 Jared McNeill <jmcneill (at) 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 /* 30 * Motorcomm YT8511C / YT8511H Integrated 10/100/1000 Gigabit Ethernet 31 * Transceiver. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: mcommphy.c,v 1.6 2025/11/30 07:12:03 skrll Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/device.h> 41 #include <sys/socket.h> 42 #include <sys/errno.h> 43 44 #include <net/if.h> 45 #include <net/if_media.h> 46 47 #include <dev/mii/mii.h> 48 #include <dev/mii/miivar.h> 49 #include <dev/mii/miidevs.h> 50 51 #define YT85X1_MCOMMPHY_OUI 0x000000 52 #define YT8511_MCOMMPHY_MODEL 0x10 53 #define YT8521_MCOMMPHY_MODEL 0x11 54 #define YT85X1_MCOMMPHY_REV 0x0a 55 56 #define YTPHY_EXT_REG_ADDR 0x1e 57 #define YTPHY_EXT_REG_DATA 0x1f 58 59 /* Extended registers */ 60 #define YT8511_CLOCK_GATING_REG 0x0c 61 #define YT8511_TX_CLK_DELAY_SEL __BITS(7,4) 62 #define YT8511_CLK_25M_SEL __BITS(2,1) 63 #define YT8511_CLK_25M_SEL_125M 3 64 #define YT8511_RX_CLK_DELAY_EN __BIT(0) 65 66 #define YT8511_DELAY_DRIVE_REG 0x0d 67 #define YT8511_FE_TX_CLK_DELAY_SEL __BITS(15,12) 68 69 #define YT8521_CLOCK_GATING_REG 0x0c 70 #define YT8521_RX_CLK_EN __BIT(12) 71 72 #define YT8511_SLEEP_CONTROL1_REG 0x27 73 #define YT8511_PLLON_IN_SLP __BIT(14) 74 75 #define YT8521_SLEEP_CONTROL1_REG 0x27 76 #define YT8521_PLLON_IN_SLP __BIT(14) 77 78 #define YT8521_EXT_CHIP_CONFIG 0xa001 79 #define YT8521_RXC_DLY_EN __BIT(8) 80 #define YT8521_CFG_LDO_MASK __BITS(5, 4) 81 #define YT8521_CFG_LDO_3V3 0 82 #define YT8521_CFG_LDO_2V5 1 83 #define YT8521_CFG_LDO_1V8 2 /* or 3 */ 84 85 #define YT8521_EXT_SDS_CONFIG 0xa002 86 87 #define YT8521_EXT_RGMII_CONFIG1 0xa003 88 #define YT8521_TX_CLK_SEL_INV __BIT(14) 89 #define YT8521_RX_DELAY_SEL_MASK __BITS(13, 10) 90 #define YT8521_FE_TX_DELAY_SEL_MASK __BITS(7, 4) 91 #define YT8521_GE_TX_DELAY_SEL_MASK __BITS(3, 0) 92 #define YT8521_DELAY_PS(ps) ((ps) / 150) 93 #define YT8521_DELAY_DEFAULT 1950 94 95 #define YT8521_EXT_RGMII_CONFIG2 0xa004 96 97 #define YT8521_EXT_PAD_DRIVE_STRENGTH 0xa010 98 #define YT8531_RGMII_RXC_DS_MASK __BITS(15, 13) 99 #define YT8531_RGMII_RXD_DS_HIMASK __BIT(12) 100 #define YT8531_RGMII_RXD_DS_LOMASK __BITS(5, 4) 101 #define YT8531_RGMII_RX_DS_DEFAULT 0x3 102 #define YT8531_RGMII_RXD_DS_MASK \ 103 (YT8531_RGMII_RXD_DS_HIMASK | YT8531_RGMII_RXD_DS_LOMASK) 104 105 #define YT8531_RGMII_RXD_DS_HIBITS __BIT(2) 106 #define YT8531_RGMII_RXD_DS_LOBITS __BITS(1, 0) 107 108 CTASSERT(__SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_HIMASK) == 109 __SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_HIBITS)); 110 CTASSERT(__SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_LOMASK) == 111 __SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_LOBITS)); 112 113 #define YT8531_DEFAULT_DS 3 114 115 #define YT8521_EXT_SYNCE_CFG 0xa012 116 #define YT8531_EN_SYNC_E __BIT(6) 117 #define YT8531_CLK_FRE_SEL_125M __BIT(4) 118 #define YT8531_CLK_SRC_SEL_MASK __BITS(3, 1) 119 #define YT8531_CLK_SRC_SEL_PLL_125M 0 120 #define YT8531_CLK_SRC_SEL_REF_25M 4 121 122 123 typedef enum mcommtype { 124 YTUNK, 125 YT8511, 126 YT8521, 127 YT8531, 128 } mcommtype_t; 129 130 struct mcomm_softc { 131 struct mii_softc sc_miisc; 132 133 mcommtype_t sc_type; 134 135 bool sc_tx_clk_adj_enabled; 136 bool sc_tx_clk_10_inverted; 137 bool sc_tx_clk_100_inverted; 138 bool sc_tx_clk_1000_inverted; 139 u_int sc_clk_out_frequency_hz; 140 u_int sc_rx_clk_drv_microamp; 141 u_int sc_rx_data_drv_microamp; 142 u_int sc_rx_internal_delay_ps; 143 u_int sc_tx_internal_delay_ps; 144 }; 145 146 static int mcommphymatch(device_t, cfdata_t, void *); 147 static void mcommphyattach(device_t, device_t, void *); 148 149 CFATTACH_DECL_NEW(mcommphy, sizeof(struct mcomm_softc), 150 mcommphymatch, mcommphyattach, mii_phy_detach, mii_phy_activate); 151 152 static int mcommphy_service(struct mii_softc *, struct mii_data *, int); 153 static void mcommphy_reset(struct mii_softc *); 154 155 static const struct mii_phy_funcs mcommphy_funcs = { 156 .pf_service = mcommphy_service, 157 .pf_status = ukphy_status, 158 .pf_reset = mcommphy_reset, 159 }; 160 161 static const struct mii_phydesc mcommphys[] = { 162 MII_PHY_DESC(MOTORCOMM, YT8531), 163 MII_PHY_END, 164 }; 165 166 static void 167 mcomm_yt8531properties(struct mcomm_softc *msc, prop_dictionary_t dict) 168 { 169 struct mii_softc * const sc = &msc->sc_miisc; 170 171 if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-adj-enabled", 172 &msc->sc_tx_clk_adj_enabled)) { 173 msc->sc_tx_clk_adj_enabled = false; 174 } else { 175 aprint_verbose_dev(sc->mii_dev, 176 "motorcomm,tx-clk-adj-enabled is %s\n", 177 msc->sc_tx_clk_adj_enabled ? "true" : "false"); 178 } 179 180 if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-10-inverted", 181 &msc->sc_tx_clk_10_inverted)) { 182 msc->sc_tx_clk_10_inverted = false; 183 } else { 184 aprint_verbose_dev(sc->mii_dev, 185 "motorcomm,tx_clk_10_inverted is %s\n", 186 msc->sc_tx_clk_10_inverted ? "true" : "false"); 187 } 188 189 if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-100-inverted", 190 &msc->sc_tx_clk_100_inverted)) { 191 msc->sc_tx_clk_100_inverted = false; 192 } else { 193 aprint_verbose_dev(sc->mii_dev, 194 "motorcomm,tx-clk-100-inverted is %s\n", 195 msc->sc_tx_clk_100_inverted ? "true" : "false"); 196 } 197 198 if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-1000-inverted", 199 &msc->sc_tx_clk_1000_inverted)) { 200 msc->sc_tx_clk_1000_inverted = false; 201 } else { 202 aprint_verbose_dev(sc->mii_dev, 203 "motorcomm,tx-clk-1000-inverted is %s\n", 204 msc->sc_tx_clk_1000_inverted ? "true" : "false"); 205 } 206 207 if (!prop_dictionary_get_uint32(dict, "motorcomm,clk-out-frequency-hz", 208 &msc->sc_clk_out_frequency_hz)) { 209 msc->sc_clk_out_frequency_hz = 0; 210 } else { 211 aprint_verbose_dev(sc->mii_dev, 212 "motorcomm,clk-out-frequency-hz is %u\n", 213 msc->sc_clk_out_frequency_hz); 214 } 215 216 if (!prop_dictionary_get_uint32(dict, "motorcomm,rx-clk-drv-microamp", 217 &msc->sc_rx_clk_drv_microamp)) { 218 aprint_debug_dev(sc->mii_dev, 219 "motorcomm,rx-clk-drv-microamp not found\n"); 220 } else { 221 aprint_verbose_dev(sc->mii_dev, 222 "rx-clk-drv-microamp is %u\n", 223 msc->sc_rx_clk_drv_microamp); 224 } 225 226 if (!prop_dictionary_get_uint32(dict, "motorcomm,rx-data-drv-microamp", 227 &msc->sc_rx_data_drv_microamp)) { 228 aprint_debug_dev(sc->mii_dev, 229 "motorcomm,rx-data-drv-microamp not found\n"); 230 } else { 231 aprint_verbose_dev(sc->mii_dev, 232 "motorcomm,rx-data-drv-microamp is %u\n", 233 msc->sc_rx_data_drv_microamp); 234 } 235 236 if (!prop_dictionary_get_uint32(dict, "rx-internal-delay-ps", 237 &msc->sc_rx_internal_delay_ps)) { 238 aprint_debug_dev(sc->mii_dev, 239 "rx-internal-delay-ps not found\n"); 240 } else { 241 aprint_verbose_dev(sc->mii_dev, 242 "rx-internal-delay-ps is %u\n", 243 msc->sc_rx_internal_delay_ps); 244 } 245 246 if (!prop_dictionary_get_uint32(dict, "tx-internal-delay-ps", 247 &msc->sc_tx_internal_delay_ps)) { 248 aprint_debug_dev(sc->mii_dev, 249 "tx-internal-delay-ps not found\n"); 250 } else { 251 aprint_verbose_dev(sc->mii_dev, 252 "tx-internal-delay-ps is %u\n", 253 msc->sc_tx_internal_delay_ps); 254 } 255 } 256 257 static bool 258 mcommphy_isyt8511(struct mii_attach_args *ma) 259 { 260 261 /* 262 * The YT8511C reports an OUI of 0. Best we can do here is to match 263 * exactly the contents of the PHY identification registers. 264 */ 265 if (MII_OUI(ma->mii_id1, ma->mii_id2) == YT85X1_MCOMMPHY_OUI && 266 MII_MODEL(ma->mii_id2) == YT8511_MCOMMPHY_MODEL && 267 MII_REV(ma->mii_id2) == YT85X1_MCOMMPHY_REV) { 268 return true; 269 } 270 return false; 271 } 272 273 274 static int 275 mcommphymatch(device_t parent, cfdata_t match, void *aux) 276 { 277 struct mii_attach_args *ma = aux; 278 279 if (mii_phy_match(ma, mcommphys) != NULL) 280 return 10; 281 282 if (mcommphy_isyt8511(ma)) 283 return 10; 284 285 return 0; 286 } 287 288 static void 289 mcomm_yt8511_init(struct mcomm_softc *msc) 290 { 291 struct mii_softc *sc = &msc->sc_miisc; 292 uint16_t oldaddr, data; 293 294 PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr); 295 296 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8511_CLOCK_GATING_REG); 297 298 PHY_READ(sc, YTPHY_EXT_REG_DATA, &data); 299 300 data &= ~YT8511_CLK_25M_SEL; 301 data |= __SHIFTIN(YT8511_CLK_25M_SEL_125M, YT8511_CLK_25M_SEL); 302 if (ISSET(sc->mii_flags, MIIF_RXID)) { 303 data |= YT8511_RX_CLK_DELAY_EN; 304 } else { 305 data &= ~YT8511_RX_CLK_DELAY_EN; 306 } 307 data &= ~YT8511_TX_CLK_DELAY_SEL; 308 if (ISSET(sc->mii_flags, MIIF_TXID)) { 309 data |= __SHIFTIN(0xf, YT8511_TX_CLK_DELAY_SEL); 310 } else { 311 data |= __SHIFTIN(0x2, YT8511_TX_CLK_DELAY_SEL); 312 } 313 PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data); 314 315 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8511_SLEEP_CONTROL1_REG); 316 PHY_READ(sc, YTPHY_EXT_REG_DATA, &data); 317 318 data |= YT8511_PLLON_IN_SLP; 319 320 PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data); 321 322 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr); 323 } 324 325 326 327 static void 328 mcomm_yt8521_init(struct mcomm_softc *msc) 329 { 330 struct mii_softc *sc = &msc->sc_miisc; 331 bool rx_delay_en = false; 332 u_int rx_delay_val; 333 u_int tx_delay_val; 334 uint16_t oldaddr, data; 335 336 PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr); 337 338 u_int rx_delay = msc->sc_rx_internal_delay_ps; 339 if (rx_delay <= 15 * 150 && rx_delay % 150 == 0) { 340 rx_delay_val = YT8521_DELAY_PS(rx_delay); 341 } else { 342 /* It's OK if this underflows */ 343 rx_delay -= 1900; 344 if (rx_delay <= 15 * 150 && rx_delay % 150 == 0) { 345 rx_delay_en = true; 346 rx_delay_val = YT8521_DELAY_PS(rx_delay); 347 } else { 348 rx_delay_val = YT8521_DELAY_PS(YT8521_DELAY_DEFAULT); 349 } 350 } 351 352 u_int tx_delay = msc->sc_tx_internal_delay_ps; 353 if (tx_delay <= 15 * 150 && tx_delay % 150 == 0) { 354 tx_delay_val = YT8521_DELAY_PS(tx_delay); 355 } else { 356 tx_delay_val = YT8521_DELAY_PS(YT8521_DELAY_DEFAULT); 357 } 358 359 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_CHIP_CONFIG); 360 PHY_READ(sc, YTPHY_EXT_REG_DATA, &data); 361 362 if (rx_delay_en) 363 data |= YT8521_RXC_DLY_EN; 364 else 365 data &= ~YT8521_RXC_DLY_EN; 366 367 PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data); 368 369 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_RGMII_CONFIG1); 370 PHY_READ(sc, YTPHY_EXT_REG_DATA, &data); 371 372 data &= ~(YT8521_RX_DELAY_SEL_MASK | YT8521_GE_TX_DELAY_SEL_MASK); 373 // XXX FE? 374 data |= 375 __SHIFTIN(rx_delay_val, YT8521_RX_DELAY_SEL_MASK) | 376 __SHIFTIN(tx_delay_val, YT8521_GE_TX_DELAY_SEL_MASK); 377 378 PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data); 379 380 /* Restore address register. */ 381 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr); 382 } 383 384 struct mcomm_ytphy_ds_map { 385 u_int microamps; 386 u_int ds; 387 }; 388 389 struct mcomm_ytphy_ds_map mcomm_1d8v_ds_map[] = { 390 { .microamps = 1200, .ds = 0 }, 391 { .microamps = 2100, .ds = 1 }, 392 { .microamps = 2700, .ds = 2 }, 393 { .microamps = 2910, .ds = 3 }, 394 { .microamps = 3110, .ds = 4 }, 395 { .microamps = 3600, .ds = 5 }, 396 { .microamps = 3970, .ds = 6 }, 397 { .microamps = 4350, .ds = 7 }, 398 }; 399 struct mcomm_ytphy_ds_map mcomm_3d3v_ds_map[] = { 400 { .microamps = 3070, .ds = 0 }, 401 { .microamps = 4080, .ds = 1 }, 402 { .microamps = 4370, .ds = 2 }, 403 { .microamps = 4680, .ds = 3 }, 404 { .microamps = 5020, .ds = 4 }, 405 { .microamps = 5450, .ds = 5 }, 406 { .microamps = 5740, .ds = 6 }, 407 { .microamps = 6140, .ds = 7 }, 408 }; 409 410 static u_int 411 mcomm_yt8531_ds(struct mcomm_softc *msc, 412 struct mcomm_ytphy_ds_map *ds_map, size_t n, 413 u_int microamps, u_int millivolts) 414 { 415 for (size_t i = 0; i < n; i++) { 416 if (ds_map[i].microamps == microamps) 417 return ds_map[i].ds; 418 } 419 if (microamps) { 420 struct mii_softc *sc = &msc->sc_miisc; 421 422 aprint_error_dev(sc->mii_dev, "unknown drive strength " 423 "(%u uA at %u mV)", microamps, millivolts); 424 } 425 return YT8531_DEFAULT_DS; 426 } 427 428 static void 429 mcomm_yt8531_init(struct mcomm_softc *msc) 430 { 431 struct mii_softc *sc = &msc->sc_miisc; 432 uint16_t oldaddr, data; 433 434 mcomm_yt8521_init(msc); 435 436 /* Save address register. */ 437 PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr); 438 439 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_CHIP_CONFIG); 440 PHY_READ(sc, YTPHY_EXT_REG_DATA, &data); 441 442 struct mcomm_ytphy_ds_map *ds_map = NULL; 443 size_t ds_mapsize; 444 u_int millivolts = 1800; 445 switch (__SHIFTOUT(data, YT8521_CFG_LDO_MASK)) { 446 case YT8521_CFG_LDO_3V3: 447 ds_map = mcomm_3d3v_ds_map; 448 ds_mapsize = __arraycount(mcomm_3d3v_ds_map); 449 millivolts = 3300; 450 break; 451 case YT8521_CFG_LDO_2V5: 452 millivolts = 2500; 453 break; 454 default: 455 ds_map = mcomm_1d8v_ds_map; 456 ds_mapsize = __arraycount(mcomm_1d8v_ds_map); 457 break; 458 } 459 460 if (ds_map) { 461 u_int rx_clk_ds = mcomm_yt8531_ds(msc, ds_map, ds_mapsize, 462 msc->sc_rx_clk_drv_microamp, millivolts); 463 u_int rx_data_ds = mcomm_yt8531_ds(msc, ds_map, ds_mapsize, 464 msc->sc_rx_data_drv_microamp, millivolts); 465 466 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_PAD_DRIVE_STRENGTH); 467 PHY_READ(sc, YTPHY_EXT_REG_DATA, &data); 468 469 data &= ~(YT8531_RGMII_RXC_DS_MASK | YT8531_RGMII_RXD_DS_MASK); 470 471 u_int rx_data_ds_hi = 472 __SHIFTOUT(rx_data_ds, YT8531_RGMII_RXD_DS_HIBITS); 473 u_int rx_data_ds_lo = 474 __SHIFTOUT(rx_data_ds, YT8531_RGMII_RXD_DS_LOBITS); 475 data |= 476 __SHIFTIN(rx_clk_ds, YT8531_RGMII_RXC_DS_MASK) | 477 __SHIFTIN(rx_data_ds_hi, YT8531_RGMII_RXD_DS_HIMASK) | 478 __SHIFTIN(rx_data_ds_lo, YT8531_RGMII_RXD_DS_LOMASK); 479 480 PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data); 481 } 482 483 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_SYNCE_CFG); 484 PHY_READ(sc, YTPHY_EXT_REG_DATA, &data); 485 486 switch (msc->sc_clk_out_frequency_hz) { 487 case 0: 488 data &= ~YT8531_EN_SYNC_E; 489 break; 490 case 125000000: 491 data &= ~(YT8531_EN_SYNC_E | YT8531_CLK_SRC_SEL_MASK); 492 data |= YT8531_EN_SYNC_E; 493 data |= YT8531_CLK_FRE_SEL_125M; 494 data |= __SHIFTIN(YT8531_CLK_SRC_SEL_PLL_125M, YT8531_CLK_SRC_SEL_MASK); 495 break; 496 case 25000000: 497 data &= ~(YT8531_EN_SYNC_E | YT8531_CLK_SRC_SEL_MASK); 498 data |= YT8531_EN_SYNC_E; 499 data |= __SHIFTIN(YT8531_CLK_SRC_SEL_REF_25M, YT8531_CLK_SRC_SEL_MASK); 500 break; 501 default: 502 break; 503 } 504 505 PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data); 506 507 /* Restore address register. */ 508 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr); 509 } 510 511 512 static void 513 mcommphy_reset(struct mii_softc *sc) 514 { 515 struct mcomm_softc * const msc = 516 container_of(sc, struct mcomm_softc, sc_miisc); 517 518 KASSERT(mii_locked(sc->mii_pdata)); 519 520 mii_phy_reset(sc); 521 522 switch (msc->sc_type) { 523 case YT8511: 524 mcomm_yt8511_init(msc); 525 break; 526 case YT8531: 527 mcomm_yt8531_init(msc); 528 break; 529 default: 530 return; 531 } 532 } 533 534 535 static void 536 mcommphyattach(device_t parent, device_t self, void *aux) 537 { 538 struct mcomm_softc *msc = device_private(self); 539 struct mii_softc *sc = &msc->sc_miisc; 540 struct mii_attach_args *ma = aux; 541 struct mii_data *mii = ma->mii_data; 542 543 msc->sc_type = YTUNK; 544 if (mcommphy_isyt8511(ma)) { 545 msc->sc_type = YT8511; 546 aprint_normal(": Motorcomm YT8511 GbE PHY\n"); 547 } else { 548 KASSERT(mii_phy_match(ma, mcommphys) != NULL); 549 msc->sc_type = YT8531; 550 aprint_normal(": Motorcomm YT8531 GbE PHY\n"); 551 } 552 aprint_naive(": Media interface\n"); 553 554 sc->mii_dev = self; 555 sc->mii_inst = mii->mii_instance; 556 sc->mii_phy = ma->mii_phyno; 557 sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); 558 sc->mii_mpd_model = MII_MODEL(ma->mii_id2); 559 sc->mii_mpd_rev = MII_REV(ma->mii_id2); 560 sc->mii_funcs = &mcommphy_funcs; 561 sc->mii_pdata = mii; 562 sc->mii_flags = ma->mii_flags; 563 564 prop_dictionary_t dict = device_properties(parent); 565 switch (msc->sc_type) { 566 case YT8521: 567 case YT8531: 568 /* Default values */ 569 msc->sc_rx_clk_drv_microamp = YT8531_RGMII_RX_DS_DEFAULT; 570 msc->sc_rx_data_drv_microamp = YT8531_RGMII_RX_DS_DEFAULT; 571 msc->sc_rx_internal_delay_ps = YT8521_DELAY_DEFAULT; 572 msc->sc_tx_internal_delay_ps = YT8521_DELAY_DEFAULT; 573 574 mcomm_yt8531properties(msc, dict); 575 break; 576 default: 577 break; 578 } 579 580 mii_lock(mii); 581 582 PHY_RESET(sc); 583 584 PHY_READ(sc, MII_BMSR, &sc->mii_capabilities); 585 sc->mii_capabilities &= ma->mii_capmask; 586 if (sc->mii_capabilities & BMSR_EXTSTAT) 587 PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities); 588 589 mii_unlock(mii); 590 591 mii_phy_add_media(sc); 592 } 593 594 static void 595 ytphy_yt8521_update(struct mcomm_softc *msc) 596 { 597 struct mii_softc *sc = &msc->sc_miisc; 598 struct mii_data *mii = sc->mii_pdata; 599 bool tx_clk_inv = false; 600 uint16_t oldaddr, data; 601 602 if (sc->mii_media_active == mii->mii_media_active) 603 return; 604 605 if (!msc->sc_tx_clk_adj_enabled) 606 return; 607 608 switch (IFM_SUBTYPE(mii->mii_media_active)) { 609 case IFM_1000_T: 610 tx_clk_inv = msc->sc_tx_clk_1000_inverted; 611 break; 612 case IFM_100_TX: 613 tx_clk_inv = msc->sc_tx_clk_100_inverted; 614 break; 615 case IFM_10_T: 616 tx_clk_inv = msc->sc_tx_clk_10_inverted; 617 break; 618 } 619 620 /* Save address register. */ 621 PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr); 622 623 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_RGMII_CONFIG1); 624 PHY_READ(sc, YTPHY_EXT_REG_DATA, &data); 625 626 if (tx_clk_inv) 627 data |= YT8521_TX_CLK_SEL_INV; 628 else 629 data &= ~YT8521_TX_CLK_SEL_INV; 630 631 PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data); 632 633 /* Restore address register. */ 634 PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr); 635 } 636 637 static int 638 mcommphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 639 { 640 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 641 struct mcomm_softc * const msc = 642 container_of(sc, struct mcomm_softc, sc_miisc); 643 644 KASSERT(mii_locked(mii)); 645 646 switch (cmd) { 647 case MII_POLLSTAT: 648 /* If we're not polling our PHY instance, just return. */ 649 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 650 return 0; 651 break; 652 653 case MII_MEDIACHG: 654 /* If the interface is not up, don't do anything. */ 655 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 656 break; 657 658 mii_phy_setmedia(sc); 659 break; 660 661 case MII_TICK: 662 /* If we're not currently selected, just return. */ 663 if (IFM_INST(ife->ifm_media) != sc->mii_inst) 664 return 0; 665 666 if (mii_phy_tick(sc) == EJUSTRETURN) 667 return 0; 668 break; 669 670 case MII_DOWN: 671 mii_phy_down(sc); 672 return 0; 673 } 674 675 /* Update the media status. */ 676 mii_phy_status(sc); 677 678 /* Callback if something changed. */ 679 if (msc->sc_type != YT8511) 680 ytphy_yt8521_update(msc); 681 682 mii_phy_update(sc, cmd); 683 return 0; 684 } 685