| 1 | --- a/Embedded/src/GbE/iegbe_oem_phy.c |
| 2 | +++ b/Embedded/src/GbE/iegbe_oem_phy.c |
| 3 | @@ -65,6 +65,10 @@ static int32_t iegbe_oem_link_m88_setup( |
| 4 | static int32_t iegbe_oem_set_phy_mode(struct iegbe_hw *hw); |
| 5 | static int32_t iegbe_oem_detect_phy(struct iegbe_hw *hw); |
| 6 | |
| 7 | +static int32_t iegbe_oem_link_bcm5481_setup(struct iegbe_hw *hw); |
| 8 | +static int32_t bcm5481_read_18sv (struct iegbe_hw *hw, int sv, uint16_t *data); |
| 9 | +static int32_t oi_phy_setup (struct iegbe_hw *hw); |
| 10 | + |
| 11 | /** |
| 12 | * iegbe_oem_setup_link |
| 13 | * @hw: iegbe_hw struct containing device specific information |
| 14 | @@ -114,6 +118,10 @@ iegbe_oem_setup_link(struct iegbe_hw *hw |
| 15 | } |
| 16 | |
| 17 | switch (hw->phy_id) { |
| 18 | + case BCM5395S_PHY_ID: |
| 19 | + return E1000_SUCCESS; |
| 20 | + break; |
| 21 | + |
| 22 | case M88E1000_I_PHY_ID: |
| 23 | case M88E1141_E_PHY_ID: |
| 24 | ret_val = iegbe_oem_link_m88_setup(hw); |
| 25 | @@ -121,6 +129,12 @@ iegbe_oem_setup_link(struct iegbe_hw *hw |
| 26 | return ret_val; |
| 27 | } |
| 28 | break; |
| 29 | + case BCM5481_PHY_ID: |
| 30 | + ret_val = iegbe_oem_link_bcm5481_setup(hw); |
| 31 | + if(ret_val) { |
| 32 | + return ret_val; |
| 33 | + } |
| 34 | + break; |
| 35 | default: |
| 36 | DEBUGOUT("Invalid PHY ID\n"); |
| 37 | return -E1000_ERR_PHY_TYPE; |
| 38 | @@ -179,6 +193,51 @@ iegbe_oem_setup_link(struct iegbe_hw *hw |
| 39 | #endif /* ifdef EXTERNAL_MDIO */ |
| 40 | } |
| 41 | |
| 42 | +/** |
| 43 | + * iegbe_oem_link_bcm5481_setup |
| 44 | + * @hw: iegbe_hw struct containing device specific information |
| 45 | + * |
| 46 | + * Returns E1000_SUCCESS, negative E1000 error code on failure |
| 47 | + * |
| 48 | + * copied verbatim from iegbe_oem_link_m88_setup |
| 49 | + **/ |
| 50 | +static int32_t |
| 51 | +iegbe_oem_link_bcm5481_setup(struct iegbe_hw *hw) |
| 52 | +{ |
| 53 | + int32_t ret_val; |
| 54 | + uint16_t phy_data; |
| 55 | + |
| 56 | + //DEBUGFUNC(__func__); |
| 57 | + |
| 58 | + if(!hw) |
| 59 | + return -1; |
| 60 | + |
| 61 | + /* phy_reset_disable is set in iegbe_oem_set_phy_mode */ |
| 62 | + if(hw->phy_reset_disable) |
| 63 | + return E1000_SUCCESS; |
| 64 | + |
| 65 | + // Enable MDIX in extended control reg. |
| 66 | + ret_val = iegbe_oem_read_phy_reg_ex(hw, BCM5481_ECTRL, &phy_data); |
| 67 | + if(ret_val) |
| 68 | + { |
| 69 | + DEBUGOUT("Unable to read BCM5481_ECTRL register\n"); |
| 70 | + return ret_val; |
| 71 | + } |
| 72 | + |
| 73 | + phy_data &= ~BCM5481_ECTRL_DISMDIX; |
| 74 | + ret_val = iegbe_oem_write_phy_reg_ex(hw, BCM5481_ECTRL, phy_data); |
| 75 | + if(ret_val) |
| 76 | + { |
| 77 | + DEBUGOUT("Unable to write BCM5481_ECTRL register\n"); |
| 78 | + return ret_val; |
| 79 | + } |
| 80 | + |
| 81 | + ret_val = oi_phy_setup (hw); |
| 82 | + if (ret_val) |
| 83 | + return ret_val; |
| 84 | + |
| 85 | + return E1000_SUCCESS; |
| 86 | +} |
| 87 | |
| 88 | /** |
| 89 | * iegbe_oem_link_m88_setup |
| 90 | @@ -340,6 +399,11 @@ iegbe_oem_force_mdi(struct iegbe_hw *hw, |
| 91 | * see iegbe_phy_force_speed_duplex, which does the following for M88 |
| 92 | */ |
| 93 | switch (hw->phy_id) { |
| 94 | + case BCM5395S_PHY_ID: |
| 95 | + case BCM5481_PHY_ID: |
| 96 | + DEBUGOUT("WARNING: An empty iegbe_oem_force_mdi() has been called!\n"); |
| 97 | + break; |
| 98 | + |
| 99 | case M88E1000_I_PHY_ID: |
| 100 | case M88E1141_E_PHY_ID: |
| 101 | ret_val = iegbe_oem_read_phy_reg_ex(hw, |
| 102 | @@ -415,6 +479,8 @@ iegbe_oem_phy_reset_dsp(struct iegbe_hw |
| 103 | switch (hw->phy_id) { |
| 104 | case M88E1000_I_PHY_ID: |
| 105 | case M88E1141_E_PHY_ID: |
| 106 | + case BCM5481_PHY_ID: |
| 107 | + case BCM5395S_PHY_ID: |
| 108 | DEBUGOUT("No DSP to reset on OEM PHY\n"); |
| 109 | break; |
| 110 | default: |
| 111 | @@ -460,6 +526,11 @@ iegbe_oem_cleanup_after_phy_reset(struct |
| 112 | * see iegbe_phy_force_speed_duplex, which does the following for M88 |
| 113 | */ |
| 114 | switch (hw->phy_id) { |
| 115 | + case BCM5395S_PHY_ID: |
| 116 | + case BCM5481_PHY_ID: |
| 117 | + DEBUGOUT("WARNING: An empty iegbe_oem_cleanup_after_phy_reset() has been called!\n"); |
| 118 | + break; |
| 119 | + |
| 120 | case M88E1000_I_PHY_ID: |
| 121 | case M88E1141_E_PHY_ID: |
| 122 | /* |
| 123 | @@ -573,6 +644,11 @@ iegbe_oem_set_phy_mode(struct iegbe_hw * |
| 124 | * use iegbe_set_phy_mode as example |
| 125 | */ |
| 126 | switch (hw->phy_id) { |
| 127 | + case BCM5395S_PHY_ID: |
| 128 | + case BCM5481_PHY_ID: |
| 129 | + DEBUGOUT("WARNING: An empty iegbe_oem_set_phy_mode() has been called!\n"); |
| 130 | + break; |
| 131 | + |
| 132 | case M88E1000_I_PHY_ID: |
| 133 | case M88E1141_E_PHY_ID: |
| 134 | ret_val = iegbe_read_eeprom(hw, |
| 135 | @@ -641,6 +717,19 @@ iegbe_oem_detect_phy(struct iegbe_hw *hw |
| 136 | } |
| 137 | hw->phy_type = iegbe_phy_oem; |
| 138 | |
| 139 | +{ |
| 140 | + // If MAC2 (BCM5395 switch), manually detect the phy |
| 141 | + struct iegbe_adapter *adapter; |
| 142 | + uint32_t device_number; |
| 143 | + adapter = (struct iegbe_adapter *) hw->back; |
| 144 | + device_number = PCI_SLOT(adapter->pdev->devfn); |
| 145 | + if (device_number == ICP_XXXX_MAC_2) { |
| 146 | + hw->phy_id = BCM5395S_PHY_ID; |
| 147 | + hw->phy_revision = 0; |
| 148 | + return E1000_SUCCESS; |
| 149 | + } |
| 150 | +} |
| 151 | + |
| 152 | ret_val = iegbe_oem_read_phy_reg_ex(hw, PHY_ID1, &phy_id_high); |
| 153 | if(ret_val) { |
| 154 | DEBUGOUT("Unable to read PHY register PHY_ID1\n"); |
| 155 | @@ -690,6 +779,8 @@ iegbe_oem_get_tipg(struct iegbe_hw *hw) |
| 156 | switch (hw->phy_id) { |
| 157 | case M88E1000_I_PHY_ID: |
| 158 | case M88E1141_E_PHY_ID: |
| 159 | + case BCM5481_PHY_ID: |
| 160 | + case BCM5395S_PHY_ID: |
| 161 | phy_num = DEFAULT_ICP_XXXX_TIPG_IPGT; |
| 162 | break; |
| 163 | default: |
| 164 | @@ -738,6 +829,8 @@ iegbe_oem_phy_is_copper(struct iegbe_hw |
| 165 | switch (hw->phy_id) { |
| 166 | case M88E1000_I_PHY_ID: |
| 167 | case M88E1141_E_PHY_ID: |
| 168 | + case BCM5481_PHY_ID: |
| 169 | + case BCM5395S_PHY_ID: |
| 170 | isCopper = TRUE; |
| 171 | break; |
| 172 | default: |
| 173 | @@ -796,13 +889,13 @@ iegbe_oem_get_phy_dev_number(struct iegb |
| 174 | switch(device_number) |
| 175 | { |
| 176 | case ICP_XXXX_MAC_0: |
| 177 | - hw->phy_addr = 0x00; |
| 178 | + hw->phy_addr = 0x01; |
| 179 | break; |
| 180 | case ICP_XXXX_MAC_1: |
| 181 | - hw->phy_addr = 0x01; |
| 182 | + hw->phy_addr = 0x02; |
| 183 | break; |
| 184 | case ICP_XXXX_MAC_2: |
| 185 | - hw->phy_addr = 0x02; |
| 186 | + hw->phy_addr = 0x00; |
| 187 | break; |
| 188 | default: hw->phy_addr = 0x00; |
| 189 | } |
| 190 | @@ -851,6 +944,12 @@ iegbe_oem_mii_ioctl(struct iegbe_adapter |
| 191 | if(!adapter || !ifr) { |
| 192 | return -1; |
| 193 | } |
| 194 | + |
| 195 | + // If MAC2 (BCM5395 switch) then leave now |
| 196 | + if ((PCI_SLOT(adapter->pdev->devfn)) == ICP_XXXX_MAC_2) { |
| 197 | + return -1; |
| 198 | + } |
| 199 | + |
| 200 | switch (data->reg_num) { |
| 201 | case PHY_CTRL: |
| 202 | if(mii_reg & MII_CR_POWER_DOWN) { |
| 203 | @@ -987,6 +1086,11 @@ void iegbe_oem_get_phy_regs(struct iegbe |
| 204 | * [10] = mdix mode |
| 205 | */ |
| 206 | switch (adapter->hw.phy_id) { |
| 207 | + case BCM5395S_PHY_ID: |
| 208 | + case BCM5481_PHY_ID: |
| 209 | + DEBUGOUT("WARNING: An empty iegbe_oem_get_phy_regs() has been called!\n"); |
| 210 | + break; |
| 211 | + |
| 212 | case M88E1000_I_PHY_ID: |
| 213 | case M88E1141_E_PHY_ID: |
| 214 | if(corrected_len > 0) { |
| 215 | @@ -1068,8 +1172,13 @@ iegbe_oem_phy_loopback(struct iegbe_adap |
| 216 | * Loopback configuration is the same for each of the supported PHYs. |
| 217 | */ |
| 218 | switch (adapter->hw.phy_id) { |
| 219 | + case BCM5395S_PHY_ID: |
| 220 | + DEBUGOUT("WARNING: An empty iegbe_oem_phy_loopback() has been called!\n"); |
| 221 | + break; |
| 222 | + |
| 223 | case M88E1000_I_PHY_ID: |
| 224 | case M88E1141_E_PHY_ID: |
| 225 | + case BCM5481_PHY_ID: |
| 226 | |
| 227 | adapter->hw.autoneg = FALSE; |
| 228 | |
| 229 | @@ -1182,8 +1291,14 @@ iegbe_oem_loopback_cleanup(struct iegbe_ |
| 230 | } |
| 231 | |
| 232 | switch (adapter->hw.phy_id) { |
| 233 | + case BCM5395S_PHY_ID: |
| 234 | + DEBUGOUT("WARNING: An empty iegbe_oem_loopback_cleanup() has been called!\n"); |
| 235 | + return; |
| 236 | + break; |
| 237 | + |
| 238 | case M88E1000_I_PHY_ID: |
| 239 | case M88E1141_E_PHY_ID: |
| 240 | + case BCM5481_PHY_ID: |
| 241 | default: |
| 242 | adapter->hw.autoneg = TRUE; |
| 243 | |
| 244 | @@ -1243,6 +1358,11 @@ iegbe_oem_phy_speed_downgraded(struct ie |
| 245 | */ |
| 246 | |
| 247 | switch (hw->phy_id) { |
| 248 | + case BCM5395S_PHY_ID: |
| 249 | + case BCM5481_PHY_ID: |
| 250 | + *isDowngraded = 0; |
| 251 | + break; |
| 252 | + |
| 253 | case M88E1000_I_PHY_ID: |
| 254 | case M88E1141_E_PHY_ID: |
| 255 | ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, |
| 256 | @@ -1305,6 +1425,11 @@ iegbe_oem_check_polarity(struct iegbe_hw |
| 257 | */ |
| 258 | |
| 259 | switch (hw->phy_id) { |
| 260 | + case BCM5395S_PHY_ID: |
| 261 | + case BCM5481_PHY_ID: |
| 262 | + *polarity = 0; |
| 263 | + break; |
| 264 | + |
| 265 | case M88E1000_I_PHY_ID: |
| 266 | case M88E1141_E_PHY_ID: |
| 267 | /* return the Polarity bit in the Status register. */ |
| 268 | @@ -1367,6 +1492,25 @@ iegbe_oem_phy_is_full_duplex(struct iegb |
| 269 | */ |
| 270 | |
| 271 | switch (hw->phy_id) { |
| 272 | + case BCM5395S_PHY_ID: |
| 273 | + /* Always full duplex */ |
| 274 | + *isFD = 1; |
| 275 | + break; |
| 276 | + |
| 277 | + case BCM5481_PHY_ID: |
| 278 | + ret_val = iegbe_read_phy_reg(hw, BCM5481_ASTAT, &phy_data); |
| 279 | + if(ret_val) return ret_val; |
| 280 | + |
| 281 | + switch (BCM5481_ASTAT_HCD(phy_data)) { |
| 282 | + case BCM5481_ASTAT_1KBTFD: |
| 283 | + case BCM5481_ASTAT_100BTXFD: |
| 284 | + *isFD = 1; |
| 285 | + break; |
| 286 | + default: |
| 287 | + *isFD = 0; |
| 288 | + } |
| 289 | + break; |
| 290 | + |
| 291 | case M88E1000_I_PHY_ID: |
| 292 | case M88E1141_E_PHY_ID: |
| 293 | ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, |
| 294 | @@ -1423,6 +1567,25 @@ iegbe_oem_phy_is_speed_1000(struct iegbe |
| 295 | */ |
| 296 | |
| 297 | switch (hw->phy_id) { |
| 298 | + case BCM5395S_PHY_ID: |
| 299 | + /* Always 1000mb */ |
| 300 | + *is1000 = 1; |
| 301 | + break; |
| 302 | + |
| 303 | + case BCM5481_PHY_ID: |
| 304 | + ret_val = iegbe_read_phy_reg(hw, BCM5481_ASTAT, &phy_data); |
| 305 | + if(ret_val) return ret_val; |
| 306 | + |
| 307 | + switch (BCM5481_ASTAT_HCD(phy_data)) { |
| 308 | + case BCM5481_ASTAT_1KBTFD: |
| 309 | + case BCM5481_ASTAT_1KBTHD: |
| 310 | + *is1000 = 1; |
| 311 | + break; |
| 312 | + default: |
| 313 | + *is1000 = 0; |
| 314 | + } |
| 315 | + break; |
| 316 | + |
| 317 | case M88E1000_I_PHY_ID: |
| 318 | case M88E1141_E_PHY_ID: |
| 319 | ret_val = iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, |
| 320 | @@ -1478,6 +1641,25 @@ iegbe_oem_phy_is_speed_100(struct iegbe_ |
| 321 | * see iegbe_config_mac_to_phy |
| 322 | */ |
| 323 | switch (hw->phy_id) { |
| 324 | + case BCM5395S_PHY_ID: |
| 325 | + /* Always 1000Mb, never 100mb */ |
| 326 | + *is100 = 0; |
| 327 | + break; |
| 328 | + |
| 329 | + case BCM5481_PHY_ID: |
| 330 | + ret_val = iegbe_read_phy_reg(hw, BCM5481_ASTAT, &phy_data); |
| 331 | + if(ret_val) return ret_val; |
| 332 | + |
| 333 | + switch (BCM5481_ASTAT_HCD(phy_data)) { |
| 334 | + case BCM5481_ASTAT_100BTXFD: |
| 335 | + case BCM5481_ASTAT_100BTXHD: |
| 336 | + *is100 = 1; |
| 337 | + break; |
| 338 | + default: |
| 339 | + *is100 = 0; |
| 340 | + } |
| 341 | + break; |
| 342 | + |
| 343 | case M88E1000_I_PHY_ID: |
| 344 | case M88E1141_E_PHY_ID: |
| 345 | ret_val = iegbe_oem_read_phy_reg_ex(hw, |
| 346 | @@ -1535,6 +1717,11 @@ iegbe_oem_phy_get_info(struct iegbe_hw * |
| 347 | * see iegbe_phy_m88_get_info |
| 348 | */ |
| 349 | switch (hw->phy_id) { |
| 350 | + case BCM5395S_PHY_ID: |
| 351 | + case BCM5481_PHY_ID: |
| 352 | + DEBUGOUT("WARNING: An empty iegbe_oem_phy_get_info() has been called!\n"); |
| 353 | + break; |
| 354 | + |
| 355 | case M88E1000_I_PHY_ID: |
| 356 | case M88E1141_E_PHY_ID: |
| 357 | /* The downshift status is checked only once, after link is |
| 358 | @@ -1636,8 +1823,13 @@ iegbe_oem_phy_hw_reset(struct iegbe_hw * |
| 359 | * the M88 used in truxton. |
| 360 | */ |
| 361 | switch (hw->phy_id) { |
| 362 | + case BCM5395S_PHY_ID: |
| 363 | + DEBUGOUT("WARNING: An empty iegbe_oem_phy_hw_reset() has been called!\n"); |
| 364 | + break; |
| 365 | + |
| 366 | case M88E1000_I_PHY_ID: |
| 367 | case M88E1141_E_PHY_ID: |
| 368 | + case BCM5481_PHY_ID: |
| 369 | ret_val = iegbe_oem_read_phy_reg_ex(hw, PHY_CTRL, &phy_data); |
| 370 | if(ret_val) { |
| 371 | DEBUGOUT("Unable to read register PHY_CTRL\n"); |
| 372 | @@ -1699,6 +1891,8 @@ iegbe_oem_phy_init_script(struct iegbe_h |
| 373 | switch (hw->phy_id) { |
| 374 | case M88E1000_I_PHY_ID: |
| 375 | case M88E1141_E_PHY_ID: |
| 376 | + case BCM5481_PHY_ID: |
| 377 | + case BCM5395S_PHY_ID: |
| 378 | DEBUGOUT("Nothing to do for OEM PHY Init"); |
| 379 | break; |
| 380 | default: |
| 381 | @@ -1735,6 +1929,11 @@ iegbe_oem_read_phy_reg_ex(struct iegbe_h |
| 382 | return -1; |
| 383 | } |
| 384 | |
| 385 | + if (hw->phy_id == BCM5395S_PHY_ID) { |
| 386 | + DEBUGOUT("WARNING: iegbe_oem_read_phy_reg_ex() has been unexpectedly called!\n"); |
| 387 | + return -1; |
| 388 | + } |
| 389 | + |
| 390 | /* call the GCU func that will read the phy |
| 391 | * |
| 392 | * Make note that the M88 phy is what'll be used on Truxton. |
| 393 | @@ -1782,6 +1981,11 @@ iegbe_oem_set_trans_gasket(struct iegbe_ |
| 394 | } |
| 395 | |
| 396 | switch (hw->phy_id) { |
| 397 | + case BCM5395S_PHY_ID: |
| 398 | + case BCM5481_PHY_ID: |
| 399 | + DEBUGOUT("WARNING: An empty iegbe_oem_set_trans_gasket() has been called!\n"); |
| 400 | + break; |
| 401 | + |
| 402 | case M88E1000_I_PHY_ID: |
| 403 | case M88E1141_E_PHY_ID: |
| 404 | /* Gasket set correctly for Marvell Phys, so nothing to do */ |
| 405 | @@ -1886,6 +2090,8 @@ iegbe_oem_phy_needs_reset_with_mac(struc |
| 406 | switch (hw->phy_id) { |
| 407 | case M88E1000_I_PHY_ID: |
| 408 | case M88E1141_E_PHY_ID: |
| 409 | + case BCM5481_PHY_ID: |
| 410 | + case BCM5395S_PHY_ID: |
| 411 | ret_val = FALSE; |
| 412 | break; |
| 413 | default: |
| 414 | @@ -1935,6 +2141,8 @@ iegbe_oem_config_dsp_after_link_change(s |
| 415 | switch (hw->phy_id) { |
| 416 | case M88E1000_I_PHY_ID: |
| 417 | case M88E1141_E_PHY_ID: |
| 418 | + case BCM5481_PHY_ID: |
| 419 | + case BCM5395S_PHY_ID: |
| 420 | DEBUGOUT("No DSP to configure on OEM PHY"); |
| 421 | break; |
| 422 | default: |
| 423 | @@ -1978,6 +2186,12 @@ iegbe_oem_get_cable_length(struct iegbe_ |
| 424 | } |
| 425 | |
| 426 | switch (hw->phy_id) { |
| 427 | + case BCM5395S_PHY_ID: |
| 428 | + case BCM5481_PHY_ID: |
| 429 | + *min_length = 0; |
| 430 | + *max_length = iegbe_igp_cable_length_150; |
| 431 | + break; |
| 432 | + |
| 433 | case M88E1000_I_PHY_ID: |
| 434 | case M88E1141_E_PHY_ID: |
| 435 | ret_val = iegbe_oem_read_phy_reg_ex(hw, |
| 436 | @@ -2061,6 +2275,23 @@ iegbe_oem_phy_is_link_up(struct iegbe_hw |
| 437 | */ |
| 438 | |
| 439 | switch (hw->phy_id) { |
| 440 | + case BCM5395S_PHY_ID: |
| 441 | + /* Link always up */ |
| 442 | + *isUp = TRUE; |
| 443 | + return E1000_SUCCESS; |
| 444 | + break; |
| 445 | + |
| 446 | + case BCM5481_PHY_ID: |
| 447 | + iegbe_oem_read_phy_reg_ex(hw, BCM5481_ESTAT, &phy_data); |
| 448 | + ret_val = iegbe_oem_read_phy_reg_ex(hw, BCM5481_ESTAT, &phy_data); |
| 449 | + if(ret_val) |
| 450 | + { |
| 451 | + DEBUGOUT("Unable to read PHY register BCM5481_ESTAT\n"); |
| 452 | + return ret_val; |
| 453 | + } |
| 454 | + statusMask = BCM5481_ESTAT_LINK; |
| 455 | + break; |
| 456 | + |
| 457 | case M88E1000_I_PHY_ID: |
| 458 | case M88E1141_E_PHY_ID: |
| 459 | iegbe_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); |
| 460 | @@ -2092,3 +2323,210 @@ iegbe_oem_phy_is_link_up(struct iegbe_hw |
| 461 | #endif /* ifdef EXTERNAL_MDIO */ |
| 462 | } |
| 463 | |
| 464 | + |
| 465 | + |
| 466 | +//----- |
| 467 | +// Read BCM5481 expansion register |
| 468 | +// |
| 469 | +int32_t |
| 470 | +bcm5481_read_ex (struct iegbe_hw *hw, uint16_t reg, uint16_t *data) |
| 471 | +{ |
| 472 | + int ret; |
| 473 | + uint16_t selector; |
| 474 | + uint16_t reg_data; |
| 475 | + |
| 476 | + // Get the current value of bits 15:12 |
| 477 | + ret = iegbe_oem_read_phy_reg_ex (hw, 0x15, &selector); |
| 478 | + if (ret) |
| 479 | + return ret; |
| 480 | + |
| 481 | + // Select the expansion register |
| 482 | + selector &= 0xf000; |
| 483 | + selector |= (0xf << 8) | (reg); |
| 484 | + iegbe_oem_write_phy_reg_ex (hw, 0x17, selector); |
| 485 | + |
| 486 | + // Read the expansion register |
| 487 | + ret = iegbe_oem_read_phy_reg_ex (hw, 0x15, ®_data); |
| 488 | + |
| 489 | + // De-select the expansion registers. |
| 490 | + selector &= 0xf000; |
| 491 | + iegbe_oem_write_phy_reg_ex (hw, 0x17, selector); |
| 492 | + |
| 493 | + if (ret) |
| 494 | + return ret; |
| 495 | + |
| 496 | + *data = reg_data; |
| 497 | + return ret; |
| 498 | +} |
| 499 | + |
| 500 | +//----- |
| 501 | +// Read reg 0x18 sub-register |
| 502 | +// |
| 503 | +static int32_t |
| 504 | +bcm5481_read_18sv (struct iegbe_hw *hw, int sv, uint16_t *data) |
| 505 | +{ |
| 506 | + int ret; |
| 507 | + uint16_t tmp_data; |
| 508 | + |
| 509 | + // Select reg 0x18, sv |
| 510 | + tmp_data = ((sv & BCM5481_R18H_SV_MASK) << 12) | BCM5481_R18H_SV_MCTRL; |
| 511 | + ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R18H, tmp_data); |
| 512 | + if(ret) |
| 513 | + return ret; |
| 514 | + |
| 515 | + // Read reg 0x18, sv |
| 516 | + ret = iegbe_oem_read_phy_reg_ex (hw, BCM5481_R18H, &tmp_data); |
| 517 | + if(ret) |
| 518 | + return ret; |
| 519 | + |
| 520 | + *data = tmp_data; |
| 521 | + return ret; |
| 522 | +} |
| 523 | + |
| 524 | +//----- |
| 525 | +// Read reg 0x1C sub-register |
| 526 | +// |
| 527 | +int32_t |
| 528 | +bcm5481_read_1csv (struct iegbe_hw *hw, int sv, uint16_t *data) |
| 529 | +{ |
| 530 | + int ret; |
| 531 | + uint16_t tmp_data; |
| 532 | + |
| 533 | + // Select reg 0x1c, sv |
| 534 | + tmp_data = ((sv & BCM5481_R1CH_SV_MASK) << BCM5481_R1CH_SV_SHIFT); |
| 535 | + |
| 536 | + ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R1CH, tmp_data); |
| 537 | + if(ret) |
| 538 | + return ret; |
| 539 | + |
| 540 | + // Read reg 0x1c, sv |
| 541 | + ret = iegbe_oem_read_phy_reg_ex (hw, BCM5481_R1CH, &tmp_data); |
| 542 | + if(ret) |
| 543 | + return ret; |
| 544 | + |
| 545 | + *data = tmp_data; |
| 546 | + return ret; |
| 547 | +} |
| 548 | + |
| 549 | +//----- |
| 550 | +// Read-modify-write a 0x1C register. |
| 551 | +// |
| 552 | +// hw - hardware access info. |
| 553 | +// reg - 0x1C register to modify. |
| 554 | +// data - bits which should be set. |
| 555 | +// mask - the '1' bits in this argument will be cleared in the data |
| 556 | +// read from 'reg' then 'data' will be or'd in and the result |
| 557 | +// will be written to 'reg'. |
| 558 | + |
| 559 | +int32_t |
| 560 | +bcm5481_rmw_1csv (struct iegbe_hw *hw, uint16_t reg, uint16_t data, uint16_t mask) |
| 561 | +{ |
| 562 | + int32_t ret; |
| 563 | + uint16_t reg_data; |
| 564 | + |
| 565 | + ret = 0; |
| 566 | + |
| 567 | + ret = bcm5481_read_1csv (hw, reg, ®_data); |
| 568 | + if (ret) |
| 569 | + { |
| 570 | + DEBUGOUT("Unable to read BCM5481 1CH register\n"); |
| 571 | + printk (KERN_ERR "Unable to read BCM5481 1CH register [0x%x]\n", reg); |
| 572 | + return ret; |
| 573 | + } |
| 574 | + |
| 575 | + reg_data &= ~mask; |
| 576 | + reg_data |= (BCM5481_R1CH_WE | data); |
| 577 | + |
| 578 | + ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R1CH, reg_data); |
| 579 | + if(ret) |
| 580 | + { |
| 581 | + DEBUGOUT("Unable to write BCM5481 1CH register\n"); |
| 582 | + printk (KERN_ERR "Unable to write BCM5481 1CH register\n"); |
| 583 | + return ret; |
| 584 | + } |
| 585 | + |
| 586 | + return ret; |
| 587 | +} |
| 588 | + |
| 589 | +int32_t |
| 590 | +oi_phy_setup (struct iegbe_hw *hw) |
| 591 | +{ |
| 592 | + int ret; |
| 593 | + uint16_t pmii_data; |
| 594 | + uint16_t mctrl_data; |
| 595 | + uint16_t cacr_data; |
| 596 | + |
| 597 | + ret = 0; |
| 598 | + |
| 599 | + // Set low power mode via reg 0x18, sv010, bit 6 |
| 600 | + // Do a read-modify-write on reg 0x18, sv010 register to preserve existing bits. |
| 601 | + ret = bcm5481_read_18sv (hw, BCM5481_R18H_SV_PMII, &pmii_data); |
| 602 | + if (ret) |
| 603 | + { |
| 604 | + DEBUGOUT("Unable to read BCM5481_R18H_SV_PMII register\n"); |
| 605 | + printk (KERN_ERR "Unable to read BCM5481_R18H_SV_PMII register\n"); |
| 606 | + return ret; |
| 607 | + } |
| 608 | + |
| 609 | + // Set the LPM bit in the data just read and write back to sv010 |
| 610 | + // The shadow register select bits [2:0] are set by reading the sv010 |
| 611 | + // register. |
| 612 | + pmii_data |= BCM5481_R18H_SV010_LPM; |
| 613 | + ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R18H, pmii_data); |
| 614 | + if(ret) |
| 615 | + { |
| 616 | + DEBUGOUT("Unable to write BCM5481_R18H register\n"); |
| 617 | + printk (KERN_ERR "Unable to write BCM5481_R18H register\n"); |
| 618 | + return ret; |
| 619 | + } |
| 620 | + |
| 621 | + |
| 622 | + // Set the RGMII RXD to RXC skew bit in reg 0x18, sv111 |
| 623 | + |
| 624 | + if (bcm5481_read_18sv (hw, BCM5481_R18H_SV_MCTRL, &mctrl_data)) |
| 625 | + { |
| 626 | + DEBUGOUT("Unable to read BCM5481_R18H_SV_MCTRL register\n"); |
| 627 | + printk (KERN_ERR "Unable to read BCM5481_R18H_SV_MCTRL register\n"); |
| 628 | + return ret; |
| 629 | + } |
| 630 | + mctrl_data |= (BCM5481_R18H_WE | BCM5481_R18H_SV111_SKEW); |
| 631 | + |
| 632 | + ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R18H, mctrl_data); |
| 633 | + if(ret) |
| 634 | + { |
| 635 | + DEBUGOUT("Unable to write BCM5481_R18H register\n"); |
| 636 | + printk (KERN_ERR "Unable to write BCM5481_R18H register\n"); |
| 637 | + return ret; |
| 638 | + } |
| 639 | + |
| 640 | + // Enable RGMII transmit clock delay in reg 0x1c, sv00011 |
| 641 | + ret = bcm5481_read_1csv (hw, BCM5481_R1CH_CACR, &cacr_data); |
| 642 | + if (ret) |
| 643 | + { |
| 644 | + DEBUGOUT("Unable to read BCM5481_R1CH_CACR register\n"); |
| 645 | + printk (KERN_ERR "Unable to read BCM5481_R1CH_CACR register\n"); |
| 646 | + return ret; |
| 647 | + } |
| 648 | + |
| 649 | + cacr_data |= (BCM5481_R1CH_WE | BCM5481_R1CH_CACR_TCD); |
| 650 | + |
| 651 | + ret = iegbe_oem_write_phy_reg_ex (hw, BCM5481_R1CH, cacr_data); |
| 652 | + if(ret) |
| 653 | + { |
| 654 | + DEBUGOUT("Unable to write BCM5481_R1CH register\n"); |
| 655 | + printk (KERN_ERR "Unable to write BCM5481_R1CH register\n"); |
| 656 | + return ret; |
| 657 | + } |
| 658 | + |
| 659 | + // Enable dual link speed indication (0x1c, sv 00010, bit 2) |
| 660 | + ret = bcm5481_rmw_1csv (hw, BCM5481_R1CH_SC1, BCM5481_R1CH_SC1_LINK, BCM5481_R1CH_SC1_LINK); |
| 661 | + if (ret) |
| 662 | + return ret; |
| 663 | + |
| 664 | + // Enable link and activity on ACTIVITY LED (0x1c, sv 01001, bit 4=1, bit 3=0) |
| 665 | + ret = bcm5481_rmw_1csv (hw, BCM5481_R1CH_LCTRL, BCM5481_R1CH_LCTRL_ALEN, BCM5481_R1CH_LCTRL_ALEN | BCM5481_R1CH_LCTRL_AEN); |
| 666 | + if (ret) |
| 667 | + return ret; |
| 668 | + |
| 669 | + return ret; |
| 670 | +} |
| 671 | --- a/Embedded/src/GbE/iegbe_oem_phy.h |
| 672 | +++ b/Embedded/src/GbE/iegbe_oem_phy.h |
| 673 | @@ -95,6 +95,8 @@ int32_t iegbe_oem_phy_is_link_up(struct |
| 674 | |
| 675 | #define DEFAULT_ICP_XXXX_TIPG_IPGT 8 /* Inter Packet Gap Transmit Time */ |
| 676 | #define ICP_XXXX_TIPG_IPGT_MASK 0x000003FFUL |
| 677 | +#define BCM5481_PHY_ID 0x0143BCA0 |
| 678 | +#define BCM5395S_PHY_ID 0x0143BCF0 |
| 679 | |
| 680 | /* Miscellaneous defines */ |
| 681 | #ifdef IEGBE_10_100_ONLY |
| 682 | @@ -103,5 +105,65 @@ int32_t iegbe_oem_phy_is_link_up(struct |
| 683 | #define ICP_XXXX_AUTONEG_ADV_DEFAULT 0x2F |
| 684 | #endif |
| 685 | |
| 686 | +/* BCM5481 specifics */ |
| 687 | + |
| 688 | +#define BCM5481_ECTRL (0x10) |
| 689 | +#define BCM5481_ESTAT (0x11) |
| 690 | +#define BCM5481_RXERR (0x12) |
| 691 | +#define BCM5481_EXPRW (0x15) |
| 692 | +#define BCM5481_EXPACC (0x17) |
| 693 | +#define BCM5481_ASTAT (0x19) |
| 694 | +#define BCM5481_R18H (0x18) |
| 695 | +#define BCM5481_R1CH (0x1c) |
| 696 | + |
| 697 | +/* indirect register access via register 18h */ |
| 698 | + |
| 699 | +#define BCM5481_R18H_SV_MASK (7) // Mask for SV bits. |
| 700 | +#define BCM5481_R18H_SV_ACTRL (0) // SV000 Aux. control |
| 701 | +#define BCM5481_R18H_SV_10BT (1) // SV001 10Base-T |
| 702 | +#define BCM5481_R18H_SV_PMII (2) // SV010 Power/MII control |
| 703 | +#define BCM5481_R18H_SV_MTEST (4) // SV100 Misc. test |
| 704 | +#define BCM5481_R18H_SV_MCTRL (7) // SV111 Misc. control |
| 705 | + |
| 706 | +#define BCM5481_R18H_SV001_POL (1 << 13) // Polarity |
| 707 | +#define BCM5481_R18H_SV010_LPM (1 << 6) |
| 708 | +#define BCM5481_R18H_SV111_SKEW (1 << 8) |
| 709 | +#define BCM5481_R18H_WE (1 << 15) // Write enable |
| 710 | + |
| 711 | +// 0x1c registers |
| 712 | +#define BCM5481_R1CH_SV_SHIFT (10) |
| 713 | +#define BCM5481_R1CH_SV_MASK (0x1f) |
| 714 | +#define BCM5481_R1CH_SC1 (0x02) // sv00010 Spare control 1 |
| 715 | +#define BCM5481_R1CH_CACR (0x03) // sv00011 Clock alignment control |
| 716 | +#define BCM5481_R1CH_LCTRL (0x09) // sv01001 LED control |
| 717 | +#define BCM5481_R1CH_LEDS1 (0x0d) // sv01101 LED selector 1 |
| 718 | + |
| 719 | +// 0x1c common |
| 720 | +#define BCM5481_R1CH_WE (1 << 15) // Write enable |
| 721 | + |
| 722 | +// 0x1c, sv 00010 |
| 723 | +#define BCM5481_R1CH_SC1_LINK (1 << 2) // sv00010 Linkspeed |
| 724 | + |
| 725 | +// 0x1c, sv 00011 |
| 726 | +#define BCM5481_R1CH_CACR_TCD (1 << 9) // sv00011 RGMII tx clock delay |
| 727 | + |
| 728 | +// 0x1c, sv 01001 |
| 729 | +#define BCM5481_R1CH_LCTRL_ALEN (1 << 4) // Activity/Link enable on ACTIVITY LED |
| 730 | +#define BCM5481_R1CH_LCTRL_AEN (1 << 3) // Activity enable on ACTIVITY LED |
| 731 | + |
| 732 | +#define BCM5481_ECTRL_DISMDIX (1 <<14) |
| 733 | + |
| 734 | +#define BCM5481_MCTRL_AUTOMDIX (1 <<9) |
| 735 | + |
| 736 | +#define BCM5481_ESTAT_LINK (1 << 8) |
| 737 | + |
| 738 | +#define BCM5481_ASTAT_ANC (1 << 15) |
| 739 | +#define BCM5481_ASTAT_ANHCD (7 << 8) |
| 740 | +#define BCM5481_ASTAT_HCD(x) ((x >> 8) & 7) |
| 741 | +#define BCM5481_ASTAT_1KBTFD (0x7) |
| 742 | +#define BCM5481_ASTAT_1KBTHD (0x6) |
| 743 | +#define BCM5481_ASTAT_100BTXFD (0x5) |
| 744 | +#define BCM5481_ASTAT_100BTXHD (0x3) |
| 745 | + |
| 746 | #endif /* ifndef _IEGBE_OEM_PHY_H_ */ |
| 747 | |
| 748 | |