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