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