dpdk/drivers/net/ngbe/base/ngbe_phy.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
   3 * Copyright(c) 2010-2017 Intel Corporation
   4 */
   5
   6#include "ngbe_hw.h"
   7#include "ngbe_phy.h"
   8
   9s32 ngbe_mdi_map_register(mdi_reg_t *reg, mdi_reg_22_t *reg22)
  10{
  11        bool match = 1;
  12        switch (reg->device_type) {
  13        case NGBE_MD_DEV_PMA_PMD:
  14                switch (reg->addr) {
  15                case NGBE_MD_PHY_ID_HIGH:
  16                case NGBE_MD_PHY_ID_LOW:
  17                        reg22->page = 0;
  18                        reg22->addr = reg->addr;
  19                        reg22->device_type = 0;
  20                        break;
  21                default:
  22                        match = 0;
  23                }
  24                break;
  25        default:
  26                match = 0;
  27                break;
  28        }
  29
  30        if (!match) {
  31                reg22->page = reg->device_type;
  32                reg22->device_type = reg->device_type;
  33                reg22->addr = reg->addr;
  34        }
  35
  36        return 0;
  37}
  38
  39/**
  40 * ngbe_probe_phy - Identify a single address for a PHY
  41 * @hw: pointer to hardware structure
  42 * @phy_addr: PHY address to probe
  43 *
  44 * Returns true if PHY found
  45 */
  46static bool ngbe_probe_phy(struct ngbe_hw *hw, u16 phy_addr)
  47{
  48        if (!ngbe_validate_phy_addr(hw, phy_addr)) {
  49                DEBUGOUT("Unable to validate PHY address 0x%04X\n",
  50                        phy_addr);
  51                return false;
  52        }
  53
  54        if (ngbe_get_phy_id(hw))
  55                return false;
  56
  57        hw->phy.type = ngbe_get_phy_type_from_id(hw);
  58        if (hw->phy.type == ngbe_phy_unknown)
  59                return false;
  60
  61        return true;
  62}
  63
  64/**
  65 *  ngbe_identify_phy - Get physical layer module
  66 *  @hw: pointer to hardware structure
  67 *
  68 *  Determines the physical layer module found on the current adapter.
  69 **/
  70s32 ngbe_identify_phy(struct ngbe_hw *hw)
  71{
  72        s32 err = NGBE_ERR_PHY_ADDR_INVALID;
  73        u16 phy_addr;
  74
  75        DEBUGFUNC("ngbe_identify_phy");
  76
  77        if (hw->phy.type != ngbe_phy_unknown)
  78                return 0;
  79
  80        /* select clause22 */
  81        wr32(hw, NGBE_MDIOMODE, NGBE_MDIOMODE_MASK);
  82
  83        for (phy_addr = 0; phy_addr < NGBE_MAX_PHY_ADDR; phy_addr++) {
  84                if (ngbe_probe_phy(hw, phy_addr)) {
  85                        err = 0;
  86                        break;
  87                }
  88        }
  89
  90        return err;
  91}
  92
  93/**
  94 * ngbe_check_reset_blocked - check status of MNG FW veto bit
  95 * @hw: pointer to the hardware structure
  96 *
  97 * This function checks the STAT.MNGVETO bit to see if there are
  98 * any constraints on link from manageability.  For MAC's that don't
  99 * have this bit just return faluse since the link can not be blocked
 100 * via this method.
 101 **/
 102s32 ngbe_check_reset_blocked(struct ngbe_hw *hw)
 103{
 104        u32 mmngc;
 105
 106        DEBUGFUNC("ngbe_check_reset_blocked");
 107
 108        mmngc = rd32(hw, NGBE_STAT);
 109        if (mmngc & NGBE_STAT_MNGVETO) {
 110                DEBUGOUT("MNG_VETO bit detected.\n");
 111                return true;
 112        }
 113
 114        return false;
 115}
 116
 117/**
 118 *  ngbe_validate_phy_addr - Determines phy address is valid
 119 *  @hw: pointer to hardware structure
 120 *  @phy_addr: PHY address
 121 *
 122 **/
 123bool ngbe_validate_phy_addr(struct ngbe_hw *hw, u32 phy_addr)
 124{
 125        u16 phy_id = 0;
 126        bool valid = false;
 127
 128        DEBUGFUNC("ngbe_validate_phy_addr");
 129
 130        if (hw->sub_device_id == NGBE_SUB_DEV_ID_EM_YT8521S_SFP)
 131                return true;
 132
 133        hw->phy.addr = phy_addr;
 134        hw->phy.read_reg(hw, NGBE_MD_PHY_ID_HIGH,
 135                             NGBE_MD_DEV_PMA_PMD, &phy_id);
 136
 137        if (phy_id != 0xFFFF && phy_id != 0x0)
 138                valid = true;
 139
 140        DEBUGOUT("PHY ID HIGH is 0x%04X\n", phy_id);
 141
 142        return valid;
 143}
 144
 145/**
 146 *  ngbe_get_phy_id - Get the phy ID
 147 *  @hw: pointer to hardware structure
 148 *
 149 **/
 150s32 ngbe_get_phy_id(struct ngbe_hw *hw)
 151{
 152        u32 err;
 153        u16 phy_id_high = 0;
 154        u16 phy_id_low = 0;
 155
 156        DEBUGFUNC("ngbe_get_phy_id");
 157
 158        err = hw->phy.read_reg(hw, NGBE_MD_PHY_ID_HIGH,
 159                                      NGBE_MD_DEV_PMA_PMD,
 160                                      &phy_id_high);
 161        hw->phy.id = (u32)(phy_id_high << 16);
 162
 163        err = hw->phy.read_reg(hw, NGBE_MD_PHY_ID_LOW,
 164                                NGBE_MD_DEV_PMA_PMD,
 165                                &phy_id_low);
 166        hw->phy.id |= (u32)(phy_id_low & NGBE_PHY_REVISION_MASK);
 167        hw->phy.revision = (u32)(phy_id_low & ~NGBE_PHY_REVISION_MASK);
 168
 169        DEBUGOUT("PHY_ID_HIGH 0x%04X, PHY_ID_LOW 0x%04X\n",
 170                  phy_id_high, phy_id_low);
 171
 172        return err;
 173}
 174
 175/**
 176 *  ngbe_get_phy_type_from_id - Get the phy type
 177 *  @phy_id: PHY ID information
 178 *
 179 **/
 180enum ngbe_phy_type ngbe_get_phy_type_from_id(struct ngbe_hw *hw)
 181{
 182        enum ngbe_phy_type phy_type;
 183
 184        DEBUGFUNC("ngbe_get_phy_type_from_id");
 185
 186        switch (hw->phy.id) {
 187        case NGBE_PHYID_RTL:
 188                phy_type = ngbe_phy_rtl;
 189                break;
 190        case NGBE_PHYID_MVL:
 191                if (hw->phy.media_type == ngbe_media_type_fiber)
 192                        phy_type = ngbe_phy_mvl_sfi;
 193                else
 194                        phy_type = ngbe_phy_mvl;
 195                break;
 196        case NGBE_PHYID_YT:
 197                if (hw->phy.media_type == ngbe_media_type_fiber)
 198                        phy_type = ngbe_phy_yt8521s_sfi;
 199                else
 200                        phy_type = ngbe_phy_yt8521s;
 201                break;
 202        default:
 203                phy_type = ngbe_phy_unknown;
 204                break;
 205        }
 206
 207        return phy_type;
 208}
 209
 210/**
 211 *  ngbe_reset_phy - Performs a PHY reset
 212 *  @hw: pointer to hardware structure
 213 **/
 214s32 ngbe_reset_phy(struct ngbe_hw *hw)
 215{
 216        s32 err = 0;
 217
 218        DEBUGFUNC("ngbe_reset_phy");
 219
 220        if (hw->phy.type == ngbe_phy_unknown)
 221                err = ngbe_identify_phy(hw);
 222
 223        if (err != 0 || hw->phy.type == ngbe_phy_none)
 224                return err;
 225
 226        /* Don't reset PHY if it's shut down due to overtemp. */
 227        if (hw->mac.check_overtemp(hw) == NGBE_ERR_OVERTEMP)
 228                return err;
 229
 230        /* Blocked by MNG FW so bail */
 231        if (ngbe_check_reset_blocked(hw))
 232                return err;
 233
 234        switch (hw->phy.type) {
 235        case ngbe_phy_rtl:
 236                err = ngbe_reset_phy_rtl(hw);
 237                break;
 238        case ngbe_phy_mvl:
 239        case ngbe_phy_mvl_sfi:
 240                err = ngbe_reset_phy_mvl(hw);
 241                break;
 242        case ngbe_phy_yt8521s:
 243        case ngbe_phy_yt8521s_sfi:
 244                err = ngbe_reset_phy_yt(hw);
 245                break;
 246        default:
 247                break;
 248        }
 249
 250        return err;
 251}
 252
 253/**
 254 *  ngbe_read_phy_mdi - Reads a value from a specified PHY register without
 255 *  the SWFW lock
 256 *  @hw: pointer to hardware structure
 257 *  @reg_addr: 32 bit address of PHY register to read
 258 *  @device_type: 5 bit device type
 259 *  @phy_data: Pointer to read data from PHY register
 260 **/
 261s32 ngbe_read_phy_reg_mdi(struct ngbe_hw *hw, u32 reg_addr, u32 device_type,
 262                           u16 *phy_data)
 263{
 264        u32 command, data;
 265
 266        /* Setup and write the address cycle command */
 267        command = NGBE_MDIOSCA_REG(reg_addr) |
 268                  NGBE_MDIOSCA_DEV(device_type) |
 269                  NGBE_MDIOSCA_PORT(hw->phy.addr);
 270        wr32(hw, NGBE_MDIOSCA, command);
 271
 272        command = NGBE_MDIOSCD_CMD_READ |
 273                  NGBE_MDIOSCD_BUSY |
 274                  NGBE_MDIOSCD_CLOCK(6);
 275        wr32(hw, NGBE_MDIOSCD, command);
 276
 277        /*
 278         * Check every 10 usec to see if the address cycle completed.
 279         * The MDI Command bit will clear when the operation is
 280         * complete
 281         */
 282        if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY,
 283                0, NULL, 100, 100)) {
 284                DEBUGOUT("PHY address command did not complete\n");
 285                return NGBE_ERR_PHY;
 286        }
 287
 288        data = rd32(hw, NGBE_MDIOSCD);
 289        *phy_data = (u16)NGBE_MDIOSCD_DAT_R(data);
 290
 291        return 0;
 292}
 293
 294/**
 295 *  ngbe_read_phy_reg - Reads a value from a specified PHY register
 296 *  using the SWFW lock - this function is needed in most cases
 297 *  @hw: pointer to hardware structure
 298 *  @reg_addr: 32 bit address of PHY register to read
 299 *  @device_type: 5 bit device type
 300 *  @phy_data: Pointer to read data from PHY register
 301 **/
 302s32 ngbe_read_phy_reg(struct ngbe_hw *hw, u32 reg_addr,
 303                               u32 device_type, u16 *phy_data)
 304{
 305        s32 err;
 306        u32 gssr = hw->phy.phy_semaphore_mask;
 307
 308        DEBUGFUNC("ngbe_read_phy_reg");
 309
 310        if (hw->mac.acquire_swfw_sync(hw, gssr))
 311                return NGBE_ERR_SWFW_SYNC;
 312
 313        err = hw->phy.read_reg_unlocked(hw, reg_addr, device_type,
 314                                        phy_data);
 315
 316        hw->mac.release_swfw_sync(hw, gssr);
 317
 318        return err;
 319}
 320
 321/**
 322 *  ngbe_write_phy_reg_mdi - Writes a value to specified PHY register
 323 *  without SWFW lock
 324 *  @hw: pointer to hardware structure
 325 *  @reg_addr: 32 bit PHY register to write
 326 *  @device_type: 5 bit device type
 327 *  @phy_data: Data to write to the PHY register
 328 **/
 329s32 ngbe_write_phy_reg_mdi(struct ngbe_hw *hw, u32 reg_addr,
 330                                u32 device_type, u16 phy_data)
 331{
 332        u32 command;
 333
 334        /* write command */
 335        command = NGBE_MDIOSCA_REG(reg_addr) |
 336                  NGBE_MDIOSCA_DEV(device_type) |
 337                  NGBE_MDIOSCA_PORT(hw->phy.addr);
 338        wr32(hw, NGBE_MDIOSCA, command);
 339
 340        command = NGBE_MDIOSCD_CMD_WRITE |
 341                  NGBE_MDIOSCD_DAT(phy_data) |
 342                  NGBE_MDIOSCD_BUSY |
 343                  NGBE_MDIOSCD_CLOCK(6);
 344        wr32(hw, NGBE_MDIOSCD, command);
 345
 346        /* wait for completion */
 347        if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY,
 348                0, NULL, 100, 100)) {
 349                TLOG_DEBUG("PHY write cmd didn't complete\n");
 350                return NGBE_ERR_PHY;
 351        }
 352
 353        return 0;
 354}
 355
 356/**
 357 *  ngbe_write_phy_reg - Writes a value to specified PHY register
 358 *  using SWFW lock- this function is needed in most cases
 359 *  @hw: pointer to hardware structure
 360 *  @reg_addr: 32 bit PHY register to write
 361 *  @device_type: 5 bit device type
 362 *  @phy_data: Data to write to the PHY register
 363 **/
 364s32 ngbe_write_phy_reg(struct ngbe_hw *hw, u32 reg_addr,
 365                                u32 device_type, u16 phy_data)
 366{
 367        s32 err;
 368        u32 gssr = hw->phy.phy_semaphore_mask;
 369
 370        DEBUGFUNC("ngbe_write_phy_reg");
 371
 372        if (hw->mac.acquire_swfw_sync(hw, gssr))
 373                err = NGBE_ERR_SWFW_SYNC;
 374
 375        err = hw->phy.write_reg_unlocked(hw, reg_addr, device_type,
 376                                         phy_data);
 377
 378        hw->mac.release_swfw_sync(hw, gssr);
 379
 380        return err;
 381}
 382
 383/**
 384 *  ngbe_init_phy - PHY specific init
 385 *  @hw: pointer to hardware structure
 386 *
 387 *  Initialize any function pointers that were not able to be
 388 *  set during init_shared_code because the PHY type was
 389 *  not known.
 390 *
 391 **/
 392s32 ngbe_init_phy(struct ngbe_hw *hw)
 393{
 394        struct ngbe_phy_info *phy = &hw->phy;
 395        s32 err = 0;
 396
 397        DEBUGFUNC("ngbe_init_phy");
 398
 399        hw->phy.addr = 0;
 400
 401        switch (hw->sub_device_id) {
 402        case NGBE_SUB_DEV_ID_EM_RTL_SGMII:
 403                hw->phy.read_reg_unlocked = ngbe_read_phy_reg_rtl;
 404                hw->phy.write_reg_unlocked = ngbe_write_phy_reg_rtl;
 405                break;
 406        case NGBE_SUB_DEV_ID_EM_MVL_RGMII:
 407        case NGBE_SUB_DEV_ID_EM_MVL_SFP:
 408                hw->phy.read_reg_unlocked = ngbe_read_phy_reg_mvl;
 409                hw->phy.write_reg_unlocked = ngbe_write_phy_reg_mvl;
 410                break;
 411        case NGBE_SUB_DEV_ID_EM_YT8521S_SFP:
 412                hw->phy.read_reg_unlocked = ngbe_read_phy_reg_yt;
 413                hw->phy.write_reg_unlocked = ngbe_write_phy_reg_yt;
 414                break;
 415        default:
 416                break;
 417        }
 418
 419        hw->phy.phy_semaphore_mask = NGBE_MNGSEM_SWPHY;
 420
 421        /* Identify the PHY */
 422        err = phy->identify(hw);
 423        if (err == NGBE_ERR_PHY_ADDR_INVALID)
 424                goto init_phy_ops_out;
 425
 426        /* Set necessary function pointers based on PHY type */
 427        switch (hw->phy.type) {
 428        case ngbe_phy_rtl:
 429                hw->phy.init_hw = ngbe_init_phy_rtl;
 430                hw->phy.check_link = ngbe_check_phy_link_rtl;
 431                hw->phy.setup_link = ngbe_setup_phy_link_rtl;
 432                hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_rtl;
 433                hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_rtl;
 434                hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_rtl;
 435                break;
 436        case ngbe_phy_mvl:
 437        case ngbe_phy_mvl_sfi:
 438                hw->phy.init_hw = ngbe_init_phy_mvl;
 439                hw->phy.check_link = ngbe_check_phy_link_mvl;
 440                hw->phy.setup_link = ngbe_setup_phy_link_mvl;
 441                hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_mvl;
 442                hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_mvl;
 443                hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_mvl;
 444                break;
 445        case ngbe_phy_yt8521s:
 446        case ngbe_phy_yt8521s_sfi:
 447                hw->phy.init_hw = ngbe_init_phy_yt;
 448                hw->phy.check_link = ngbe_check_phy_link_yt;
 449                hw->phy.setup_link = ngbe_setup_phy_link_yt;
 450                hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_yt;
 451                hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_yt;
 452                hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_yt;
 453        default:
 454                break;
 455        }
 456
 457init_phy_ops_out:
 458        return err;
 459}
 460
 461