uboot/arch/mips/mach-octeon/cvmx-helper-sfp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2018-2022 Marvell International Ltd.
   4 */
   5
   6#include <errno.h>
   7#include <i2c.h>
   8#include <log.h>
   9#include <malloc.h>
  10#include <linux/delay.h>
  11#include <display_options.h>
  12
  13#include <mach/cvmx-regs.h>
  14#include <mach/cvmx-csr.h>
  15#include <mach/cvmx-bootmem.h>
  16#include <mach/octeon-model.h>
  17#include <mach/cvmx-fuse.h>
  18#include <mach/octeon-feature.h>
  19#include <mach/cvmx-qlm.h>
  20#include <mach/octeon_qlm.h>
  21#include <mach/cvmx-pcie.h>
  22#include <mach/cvmx-coremask.h>
  23
  24#include <mach/cvmx-helper.h>
  25#include <mach/cvmx-helper-board.h>
  26#include <mach/cvmx-helper-fdt.h>
  27#include <mach/cvmx-helper-cfg.h>
  28#include <mach/cvmx-helper-gpio.h>
  29#include <mach/cvmx-helper-util.h>
  30
  31extern void octeon_i2c_unblock(int bus);
  32
  33static struct cvmx_fdt_sfp_info *sfp_list;
  34
  35/**
  36 * Local allocator to handle both SE and U-Boot that also zeroes out memory
  37 *
  38 * @param       size    number of bytes to allocate
  39 *
  40 * @return      pointer to allocated memory or NULL if out of memory.
  41 *              Alignment is set to 8-bytes.
  42 */
  43static void *cvm_sfp_alloc(size_t size)
  44{
  45        return calloc(size, 1);
  46}
  47
  48/**
  49 * Free allocated memory.
  50 *
  51 * @param       ptr     pointer to memory to free
  52 *
  53 * NOTE: This only works in U-Boot since SE does not really have a freeing
  54 *       mechanism.  In SE the memory is zeroed out and not freed so this
  55 *       is a memory leak if errors occur.
  56 */
  57static inline void cvm_sfp_free(void *ptr, size_t size)
  58{
  59        free(ptr);
  60}
  61
  62/**
  63 * Select a QSFP device before accessing the EEPROM
  64 *
  65 * @param       sfp     handle for sfp/qsfp connector
  66 * @param       enable  Set true to select, false to deselect
  67 *
  68 * @return      0 on success or if SFP or no select GPIO, -1 on GPIO error
  69 */
  70static int cvmx_qsfp_select(const struct cvmx_fdt_sfp_info *sfp, bool enable)
  71{
  72        /* Select is only needed for QSFP modules */
  73        if (!sfp->is_qsfp) {
  74                debug("%s(%s, %d): not QSFP\n", __func__, sfp->name, enable);
  75                return 0;
  76        }
  77
  78        if (dm_gpio_is_valid(&sfp->select)) {
  79                /* Note that select is active low */
  80                return dm_gpio_set_value(&sfp->select, !enable);
  81        }
  82
  83        debug("%s: select GPIO unknown\n", __func__);
  84        return 0;
  85}
  86
  87static int cvmx_sfp_parse_sfp_buffer(struct cvmx_sfp_mod_info *sfp_info,
  88                                     const uint8_t *buffer)
  89{
  90        u8 csum = 0;
  91        bool csum_good = false;
  92        int i;
  93
  94        /* Validate the checksum */
  95        for (i = 0; i < 0x3f; i++)
  96                csum += buffer[i];
  97        csum_good = csum == buffer[0x3f];
  98        debug("%s: Lower checksum: 0x%02x, expected: 0x%02x\n", __func__, csum,
  99              buffer[0x3f]);
 100        csum = 0;
 101        for (i = 0x40; i < 0x5f; i++)
 102                csum += buffer[i];
 103        debug("%s: Upper checksum: 0x%02x, expected: 0x%02x\n", __func__, csum,
 104              buffer[0x5f]);
 105        if (csum != buffer[0x5f] || !csum_good) {
 106                debug("Error: SFP EEPROM checksum information is incorrect\n");
 107                return -1;
 108        }
 109
 110        sfp_info->conn_type = buffer[0];
 111        if (buffer[1] < 1 || buffer[1] > 7) { /* Extended ID */
 112                debug("Error: Unknown SFP extended identifier 0x%x\n",
 113                      buffer[1]);
 114                return -1;
 115        }
 116        if (buffer[1] != 4) {
 117                debug("Module is not SFP/SFP+/SFP28/QSFP+\n");
 118                return -1;
 119        }
 120        sfp_info->mod_type = buffer[2];
 121        sfp_info->eth_comp = buffer[3] & 0xf0;
 122        sfp_info->cable_comp = buffer[0x24];
 123
 124        /* There are several ways a cable can be marked as active or
 125         * passive.  8.[2-3] specify the SFP+ cable technology.  Some
 126         * modules also use 3.[0-1] for Infiniband, though it's
 127         * redundant.
 128         */
 129        if ((buffer[8] & 0x0C) == 0x08) {
 130                sfp_info->limiting = true;
 131                sfp_info->active_cable = true;
 132        } else if ((buffer[8] & 0xC) == 0x4) {
 133                sfp_info->limiting = false;
 134                sfp_info->active_cable = false;
 135        }
 136        if ((buffer[3] & 3) == 2) {
 137                sfp_info->active_cable = true;
 138                sfp_info->limiting = true;
 139        }
 140
 141        switch (sfp_info->mod_type) {
 142        case CVMX_SFP_MOD_OPTICAL_LC:
 143        case CVMX_SFP_MOD_OPTICAL_PIGTAIL:
 144                sfp_info->copper_cable = false;
 145                break;
 146        case CVMX_SFP_MOD_COPPER_PIGTAIL:
 147                sfp_info->copper_cable = true;
 148                break;
 149        case CVMX_SFP_MOD_NO_SEP_CONN:
 150                switch (sfp_info->cable_comp) {
 151                case CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_HIGH_BER:
 152                case CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_LOW_BER:
 153                case CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_LOW_BER:
 154                        sfp_info->copper_cable = false;
 155                        sfp_info->limiting = true;
 156                        sfp_info->active_cable = true;
 157                        break;
 158
 159                case CVMX_SFP_CABLE_100G_SR4_25G_SR:
 160                case CVMX_SFP_CABLE_100G_LR4_25G_LR:
 161                case CVMX_SFP_CABLE_100G_ER4_25G_ER:
 162                case CVMX_SFP_CABLE_100G_SR10:
 163                case CVMX_SFP_CABLE_100G_CWDM4_MSA:
 164                case CVMX_SFP_CABLE_100G_PSM4:
 165                case CVMX_SFP_CABLE_100G_CWDM4:
 166                case CVMX_SFP_CABLE_40G_ER4:
 167                case CVMX_SFP_CABLE_4X10G_SR:
 168                case CVMX_SFP_CABLE_G959_1_P1I1_2D1:
 169                case CVMX_SFP_CABLE_G959_1_P1S1_2D2:
 170                case CVMX_SFP_CABLE_G959_1_P1L1_2D2:
 171                case CVMX_SFP_CABLE_100G_CLR4:
 172                case CVMX_SFP_CABLE_100G_2_LAMBDA_DWDM:
 173                case CVMX_SFP_CABLE_40G_SWDM4:
 174                case CVMX_SFP_CABLE_100G_SWDM4:
 175                case CVMX_SFP_CABLE_100G_PAM4_BIDI:
 176                        sfp_info->copper_cable = false;
 177                        break;
 178
 179                case CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_HIGH_BER:
 180                case CVMX_SFP_CABLE_10GBASE_T:
 181                case CVMX_SFP_CABLE_10GBASE_T_SR:
 182                case CVMX_SFP_CABLE_5GBASE_T:
 183                case CVMX_SFP_CABLE_2_5GBASE_T:
 184                        sfp_info->copper_cable = true;
 185                        sfp_info->limiting = true;
 186                        sfp_info->active_cable = true;
 187                        break;
 188
 189                case CVMX_SFP_CABLE_100G_CR4_25G_CR_CA_L:
 190                case CVMX_SFP_CABLE_25G_CR_CA_S:
 191                case CVMX_SFP_CABLE_25G_CR_CA_N:
 192                case CVMX_SFP_CABLE_40G_PSM4:
 193                        sfp_info->copper_cable = true;
 194                        break;
 195
 196                default:
 197                        switch (sfp_info->eth_comp) {
 198                        case CVMX_SFP_CABLE_10GBASE_ER:
 199                        case CVMX_SFP_CABLE_10GBASE_LRM:
 200                        case CVMX_SFP_CABLE_10GBASE_LR:
 201                        case CVMX_SFP_CABLE_10GBASE_SR:
 202                                sfp_info->copper_cable = false;
 203                                break;
 204                        }
 205                        break;
 206                }
 207                break;
 208
 209        case CVMX_SFP_MOD_RJ45:
 210                debug("%s: RJ45 adapter\n", __func__);
 211                sfp_info->copper_cable = true;
 212                sfp_info->active_cable = true;
 213                sfp_info->limiting = true;
 214                break;
 215        case CVMX_SFP_MOD_UNKNOWN:
 216                /* The Avago 1000Base-X to 1000Base-T module reports that it
 217                 * is an unknown module type but the Ethernet compliance code
 218                 * says it is 1000Base-T.  We'll change the reporting to RJ45.
 219                 */
 220                if (buffer[6] & 8) {
 221                        debug("RJ45 gigabit module detected\n");
 222                        sfp_info->mod_type = CVMX_SFP_MOD_RJ45;
 223                        sfp_info->copper_cable = false;
 224                        sfp_info->limiting = true;
 225                        sfp_info->active_cable = true;
 226                        sfp_info->max_copper_cable_len = buffer[0x12];
 227                        sfp_info->rate = CVMX_SFP_RATE_1G;
 228                } else {
 229                        debug("Unknown module type 0x%x\n", sfp_info->mod_type);
 230                }
 231                sfp_info->limiting = true;
 232                break;
 233        case CVMX_SFP_MOD_MXC_2X16:
 234                debug("%s: MXC 2X16\n", __func__);
 235                break;
 236        default:
 237                sfp_info->limiting = true;
 238                break;
 239        }
 240
 241        if (sfp_info->copper_cable)
 242                sfp_info->max_copper_cable_len = buffer[0x12];
 243        else
 244                sfp_info->max_50um_om4_cable_length = buffer[0x12] * 10;
 245
 246        if (buffer[0xe])
 247                sfp_info->max_single_mode_cable_length = buffer[0xe] * 1000;
 248        else
 249                sfp_info->max_single_mode_cable_length = buffer[0xf] * 100000;
 250
 251        sfp_info->max_50um_om2_cable_length = buffer[0x10] * 10;
 252        sfp_info->max_62_5um_om1_cable_length = buffer[0x11] * 10;
 253        sfp_info->max_50um_om3_cable_length = buffer[0x13] * 10;
 254
 255        if (buffer[0xc] == 0xff) {
 256                if (buffer[0x42] >= 255)
 257                        sfp_info->rate = CVMX_SFP_RATE_100G;
 258                else if (buffer[0x42] >= 160)
 259                        sfp_info->rate = CVMX_SFP_RATE_40G;
 260                else if (buffer[0x42] >= 100)
 261                        sfp_info->rate = CVMX_SFP_RATE_25G;
 262                else
 263                        sfp_info->rate = CVMX_SFP_RATE_UNKNOWN;
 264        } else if (buffer[0xc] >= 100) {
 265                sfp_info->rate = CVMX_SFP_RATE_10G;
 266        } else if (buffer[0xc] >= 10) {
 267                sfp_info->rate = CVMX_SFP_RATE_1G;
 268        } else {
 269                sfp_info->rate = CVMX_SFP_RATE_UNKNOWN;
 270        }
 271
 272        if (sfp_info->rate == CVMX_SFP_RATE_UNKNOWN) {
 273                switch (sfp_info->cable_comp) {
 274                case CVMX_SFP_CABLE_100G_SR10:
 275                case CVMX_SFP_CABLE_100G_CWDM4_MSA:
 276                case CVMX_SFP_CABLE_100G_PSM4:
 277                case CVMX_SFP_CABLE_100G_CWDM4:
 278                case CVMX_SFP_CABLE_100G_CLR4:
 279                case CVMX_SFP_CABLE_100G_2_LAMBDA_DWDM:
 280                case CVMX_SFP_CABLE_100G_SWDM4:
 281                case CVMX_SFP_CABLE_100G_PAM4_BIDI:
 282                        sfp_info->rate = CVMX_SFP_RATE_100G;
 283                        break;
 284                case CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_HIGH_BER:
 285                case CVMX_SFP_CABLE_100G_SR4_25G_SR:
 286                case CVMX_SFP_CABLE_100G_LR4_25G_LR:
 287                case CVMX_SFP_CABLE_100G_ER4_25G_ER:
 288                case CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_HIGH_BER:
 289                case CVMX_SFP_CABLE_100G_CR4_25G_CR_CA_L:
 290                case CVMX_SFP_CABLE_25G_CR_CA_S:
 291                case CVMX_SFP_CABLE_25G_CR_CA_N:
 292                case CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_LOW_BER:
 293                case CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_LOW_BER:
 294                        sfp_info->rate = CVMX_SFP_RATE_25G;
 295                        break;
 296                case CVMX_SFP_CABLE_40G_ER4:
 297                case CVMX_SFP_CABLE_4X10G_SR:
 298                case CVMX_SFP_CABLE_40G_PSM4:
 299                case CVMX_SFP_CABLE_40G_SWDM4:
 300                        sfp_info->rate = CVMX_SFP_RATE_40G;
 301                        break;
 302                case CVMX_SFP_CABLE_G959_1_P1I1_2D1:
 303                case CVMX_SFP_CABLE_G959_1_P1S1_2D2:
 304                case CVMX_SFP_CABLE_G959_1_P1L1_2D2:
 305                case CVMX_SFP_CABLE_10GBASE_T:
 306                case CVMX_SFP_CABLE_10GBASE_T_SR:
 307                case CVMX_SFP_CABLE_5GBASE_T:
 308                case CVMX_SFP_CABLE_2_5GBASE_T:
 309                        sfp_info->rate = CVMX_SFP_RATE_10G;
 310                        break;
 311                default:
 312                        switch (sfp_info->eth_comp) {
 313                        case CVMX_SFP_CABLE_10GBASE_ER:
 314                        case CVMX_SFP_CABLE_10GBASE_LRM:
 315                        case CVMX_SFP_CABLE_10GBASE_LR:
 316                        case CVMX_SFP_CABLE_10GBASE_SR:
 317                                sfp_info->rate = CVMX_SFP_RATE_10G;
 318                                break;
 319                        default:
 320                                sfp_info->rate = CVMX_SFP_RATE_UNKNOWN;
 321                                break;
 322                        }
 323                        break;
 324                }
 325        }
 326
 327        if (buffer[0xc] < 0xff)
 328                sfp_info->bitrate_max = buffer[0xc] * 100;
 329        else
 330                sfp_info->bitrate_max = buffer[0x42] * 250;
 331
 332        if ((buffer[8] & 0xc) == 8) {
 333                if (buffer[0x3c] & 0x4)
 334                        sfp_info->limiting = true;
 335        }
 336
 337        /* Currently we only set this for 25G.  FEC is required for CA-S cables
 338         * and for cable lengths >= 5M as of this writing.
 339         */
 340        if ((sfp_info->rate == CVMX_SFP_RATE_25G &&
 341             sfp_info->copper_cable) &&
 342            (sfp_info->cable_comp == CVMX_SFP_CABLE_25G_CR_CA_S ||
 343             sfp_info->max_copper_cable_len >= 5))
 344                sfp_info->fec_required = true;
 345
 346        /* copy strings and vendor info, strings will be automatically NUL
 347         * terminated.
 348         */
 349        memcpy(sfp_info->vendor_name, &buffer[0x14], 16);
 350        memcpy(sfp_info->vendor_oui, &buffer[0x25], 3);
 351        memcpy(sfp_info->vendor_pn, &buffer[0x28], 16);
 352        memcpy(sfp_info->vendor_rev, &buffer[0x38], 4);
 353        memcpy(sfp_info->vendor_sn, &buffer[0x44], 16);
 354        memcpy(sfp_info->date_code, &buffer[0x54], 8);
 355
 356        sfp_info->cooled_laser = !!(buffer[0x40] & 4);
 357        sfp_info->internal_cdr = !!(buffer[0x40] & 8);
 358
 359        if (buffer[0x40] & 0x20)
 360                sfp_info->power_level = 3;
 361        else
 362                sfp_info->power_level = (buffer[0x40] & 2) ? 2 : 1;
 363
 364        sfp_info->diag_paging = !!(buffer[0x40] & 0x10);
 365        sfp_info->linear_rx_output = !(buffer[0x40] & 1);
 366        sfp_info->los_implemented = !!(buffer[0x41] & 2);
 367        sfp_info->los_inverted = !!(buffer[0x41] & 4);
 368        sfp_info->tx_fault_implemented = !!(buffer[0x41] & 8);
 369        sfp_info->tx_disable_implemented = !!(buffer[0x41] & 0x10);
 370        sfp_info->rate_select_implemented = !!(buffer[0x41] & 0x20);
 371        sfp_info->tuneable_transmitter = !!(buffer[0x41] & 0x40);
 372        sfp_info->rx_decision_threshold_implemented = !!(buffer[0x41] & 0x80);
 373
 374        sfp_info->diag_monitoring = !!(buffer[0x5c] & 0x40);
 375        sfp_info->diag_rx_power_averaged = !!(buffer[0x5c] & 0x8);
 376        sfp_info->diag_externally_calibrated = !!(buffer[0x5c] & 0x10);
 377        sfp_info->diag_internally_calibrated = !!(buffer[0x5c] & 0x20);
 378        sfp_info->diag_addr_change_required = !!(buffer[0x5c] & 0x4);
 379        sfp_info->diag_soft_rate_select_control = !!(buffer[0x5d] & 2);
 380        sfp_info->diag_app_select_control = !!(buffer[0x5d] & 4);
 381        sfp_info->diag_soft_rate_select_control = !!(buffer[0x5d] & 8);
 382        sfp_info->diag_soft_rx_los_implemented = !!(buffer[0x5d] & 0x10);
 383        sfp_info->diag_soft_tx_fault_implemented = !!(buffer[0x5d] & 0x20);
 384        sfp_info->diag_soft_tx_disable_implemented = !!(buffer[0x5d] & 0x40);
 385        sfp_info->diag_alarm_warning_flags_implemented =
 386                !!(buffer[0x5d] & 0x80);
 387        sfp_info->diag_rev = buffer[0x5e];
 388
 389        return 0;
 390}
 391
 392static int cvmx_sfp_parse_qsfp_buffer(struct cvmx_sfp_mod_info *sfp_info,
 393                                      const uint8_t *buffer)
 394{
 395        u8 csum = 0;
 396        bool csum_good = false;
 397        int i;
 398
 399        /* Validate the checksum */
 400        for (i = 0x80; i < 0xbf; i++)
 401                csum += buffer[i];
 402        csum_good = csum == buffer[0xbf];
 403        debug("%s: Lower checksum: 0x%02x, expected: 0x%02x\n", __func__, csum,
 404              buffer[0xbf]);
 405        csum = 0;
 406        for (i = 0xc0; i < 0xdf; i++)
 407                csum += buffer[i];
 408        debug("%s: Upper checksum: 0x%02x, expected: 0x%02x\n", __func__, csum,
 409              buffer[0xdf]);
 410        if (csum != buffer[0xdf] || !csum_good) {
 411                debug("Error: SFP EEPROM checksum information is incorrect\n");
 412                return -1;
 413        }
 414
 415        sfp_info->conn_type = buffer[0x80];
 416        sfp_info->mod_type = buffer[0x82];
 417        sfp_info->eth_comp = buffer[0x83] & 0xf0;
 418        sfp_info->cable_comp = buffer[0xa4];
 419
 420        switch (sfp_info->mod_type) {
 421        case CVMX_SFP_MOD_COPPER_PIGTAIL:
 422        case CVMX_SFP_MOD_NO_SEP_CONN:
 423                debug("%s: copper pigtail or no separable cable\n", __func__);
 424                /* There are several ways a cable can be marked as active or
 425                 * passive.  8.[2-3] specify the SFP+ cable technology.  Some
 426                 * modules also use 3.[0-1] for Infiniband, though it's
 427                 * redundant.
 428                 */
 429                sfp_info->copper_cable = true;
 430                if ((buffer[0x88] & 0x0C) == 0x08) {
 431                        sfp_info->limiting = true;
 432                        sfp_info->active_cable = true;
 433                } else if ((buffer[0x88] & 0xC) == 0x4) {
 434                        sfp_info->limiting = false;
 435                        sfp_info->active_cable = false;
 436                }
 437                if ((buffer[0x83] & 3) == 2) {
 438                        sfp_info->active_cable = true;
 439                        sfp_info->limiting = true;
 440                }
 441                break;
 442        case CVMX_SFP_MOD_RJ45:
 443                debug("%s: RJ45 adapter\n", __func__);
 444                sfp_info->copper_cable = true;
 445                sfp_info->active_cable = true;
 446                sfp_info->limiting = true;
 447                break;
 448        case CVMX_SFP_MOD_UNKNOWN:
 449                debug("Unknown module type\n");
 450                /* The Avago 1000Base-X to 1000Base-T module reports that it
 451                 * is an unknown module type but the Ethernet compliance code
 452                 * says it is 1000Base-T.  We'll change the reporting to RJ45.
 453                 */
 454                if (buffer[0x86] & 8) {
 455                        sfp_info->mod_type = CVMX_SFP_MOD_RJ45;
 456                        sfp_info->copper_cable = false;
 457                        sfp_info->limiting = true;
 458                        sfp_info->active_cable = true;
 459                        sfp_info->max_copper_cable_len = buffer[0x92];
 460                        sfp_info->rate = CVMX_SFP_RATE_1G;
 461                }
 462                fallthrough;
 463        default:
 464                sfp_info->limiting = true;
 465                break;
 466        }
 467
 468        if (sfp_info->copper_cable)
 469                sfp_info->max_copper_cable_len = buffer[0x92];
 470        else
 471                sfp_info->max_50um_om4_cable_length = buffer[0x92] * 10;
 472
 473        debug("%s: copper cable: %d, max copper cable len: %d\n", __func__,
 474              sfp_info->copper_cable, sfp_info->max_copper_cable_len);
 475        if (buffer[0xe])
 476                sfp_info->max_single_mode_cable_length = buffer[0x8e] * 1000;
 477        else
 478                sfp_info->max_single_mode_cable_length = buffer[0x8f] * 100000;
 479
 480        sfp_info->max_50um_om2_cable_length = buffer[0x90] * 10;
 481        sfp_info->max_62_5um_om1_cable_length = buffer[0x91] * 10;
 482        sfp_info->max_50um_om3_cable_length = buffer[0x93] * 10;
 483
 484        if (buffer[0x8c] == 12) {
 485                sfp_info->rate = CVMX_SFP_RATE_1G;
 486        } else if (buffer[0x8c] == 103) {
 487                sfp_info->rate = CVMX_SFP_RATE_10G;
 488        } else if (buffer[0x8c] == 0xff) {
 489                if (buffer[0xc2] == 103)
 490                        sfp_info->rate = CVMX_SFP_RATE_100G;
 491        }
 492
 493        if (buffer[0x8c] < 0xff)
 494                sfp_info->bitrate_max = buffer[0x8c] * 100;
 495        else
 496                sfp_info->bitrate_max = buffer[0xc2] * 250;
 497
 498        if ((buffer[0x88] & 0xc) == 8) {
 499                if (buffer[0xbc] & 0x4)
 500                        sfp_info->limiting = true;
 501        }
 502
 503        /* Currently we only set this for 25G.  FEC is required for CA-S cables
 504         * and for cable lengths >= 5M as of this writing.
 505         */
 506        /* copy strings and vendor info, strings will be automatically NUL
 507         * terminated.
 508         */
 509        memcpy(sfp_info->vendor_name, &buffer[0x94], 16);
 510        memcpy(sfp_info->vendor_oui, &buffer[0xa5], 3);
 511        memcpy(sfp_info->vendor_pn, &buffer[0xa8], 16);
 512        memcpy(sfp_info->vendor_rev, &buffer[0xb8], 4);
 513        memcpy(sfp_info->vendor_sn, &buffer[0xc4], 16);
 514        memcpy(sfp_info->date_code, &buffer[0xd4], 8);
 515
 516        sfp_info->linear_rx_output = !!(buffer[0xc0] & 1);
 517        sfp_info->cooled_laser = !!(buffer[0xc0] & 4);
 518        sfp_info->internal_cdr = !!(buffer[0xc0] & 8);
 519
 520        if (buffer[0xc0] & 0x20)
 521                sfp_info->power_level = 3;
 522        else
 523                sfp_info->power_level = (buffer[0xc0] & 2) ? 2 : 1;
 524
 525        sfp_info->diag_paging = !!(buffer[0xc0] & 0x10);
 526        sfp_info->los_implemented = !!(buffer[0xc1] & 2);
 527        sfp_info->los_inverted = !!(buffer[0xc1] & 4);
 528        sfp_info->tx_fault_implemented = !!(buffer[0xc1] & 8);
 529        sfp_info->tx_disable_implemented = !!(buffer[0xc1] & 0x10);
 530        sfp_info->rate_select_implemented = !!(buffer[0xc1] & 0x20);
 531        sfp_info->tuneable_transmitter = !!(buffer[0xc1] & 0x40);
 532        sfp_info->rx_decision_threshold_implemented = !!(buffer[0xc1] & 0x80);
 533
 534        sfp_info->diag_monitoring = !!(buffer[0xdc] & 0x40);
 535        sfp_info->diag_rx_power_averaged = !!(buffer[0xdc] & 0x8);
 536        sfp_info->diag_externally_calibrated = !!(buffer[0xdc] & 0x10);
 537        sfp_info->diag_internally_calibrated = !!(buffer[0xdc] & 0x20);
 538        sfp_info->diag_addr_change_required = !!(buffer[0xdc] & 0x4);
 539        sfp_info->diag_soft_rate_select_control = !!(buffer[0xdd] & 2);
 540        sfp_info->diag_app_select_control = !!(buffer[0xdd] & 4);
 541        sfp_info->diag_soft_rate_select_control = !!(buffer[0xdd] & 8);
 542        sfp_info->diag_soft_rx_los_implemented = !!(buffer[0xdd] & 0x10);
 543        sfp_info->diag_soft_tx_fault_implemented = !!(buffer[0xdd] & 0x20);
 544        sfp_info->diag_soft_tx_disable_implemented = !!(buffer[0xdd] & 0x40);
 545        sfp_info->diag_alarm_warning_flags_implemented =
 546                !!(buffer[0xdd] & 0x80);
 547        sfp_info->diag_rev = buffer[0xde];
 548
 549        return 0;
 550}
 551
 552static bool sfp_verify_checksum(const uint8_t *buffer)
 553{
 554        u8 csum = 0;
 555        u8 offset;
 556        bool csum_good = false;
 557        int i;
 558
 559        switch (buffer[0]) {
 560        case CVMX_SFP_CONN_QSFP:
 561        case CVMX_SFP_CONN_QSFPP:
 562        case CVMX_SFP_CONN_QSFP28:
 563        case CVMX_SFP_CONN_MICRO_QSFP:
 564        case CVMX_SFP_CONN_QSFP_DD:
 565                offset = 0x80;
 566                break;
 567        default:
 568                offset = 0;
 569                break;
 570        }
 571        for (i = offset; i < offset + 0x3f; i++)
 572                csum += buffer[i];
 573        csum_good = csum == buffer[offset + 0x3f];
 574        if (!csum_good) {
 575                debug("%s: Lower checksum bad, got 0x%x, expected 0x%x\n",
 576                      __func__, csum, buffer[offset + 0x3f]);
 577                return false;
 578        }
 579        csum = 0;
 580        for (i = offset + 0x40; i < offset + 0x5f; i++)
 581                csum += buffer[i];
 582        if (csum != buffer[offset + 0x5f]) {
 583                debug("%s: Upper checksum bad, got 0x%x, expected 0x%x\n",
 584                      __func__, csum, buffer[offset + 0x5f]);
 585                return false;
 586        }
 587        return true;
 588}
 589
 590/**
 591 * Reads and parses SFP/QSFP EEPROM
 592 *
 593 * @param       sfp     sfp handle to read
 594 *
 595 * @return      0 for success, -1 on error.
 596 */
 597int cvmx_sfp_read_i2c_eeprom(struct cvmx_fdt_sfp_info *sfp)
 598{
 599        const struct cvmx_fdt_i2c_bus_info *bus = sfp->i2c_bus;
 600        int oct_bus = cvmx_fdt_i2c_get_root_bus(bus);
 601        struct udevice *dev;
 602        u8 buffer[256];
 603        bool is_qsfp;
 604        int retry;
 605        int err;
 606
 607        if (!bus) {
 608                debug("%s(%s): Error: i2c bus undefined for eeprom\n", __func__,
 609                      sfp->name);
 610                return -1;
 611        }
 612
 613        is_qsfp = (sfp->sfp_info.conn_type == CVMX_SFP_CONN_QSFP ||
 614                   sfp->sfp_info.conn_type == CVMX_SFP_CONN_QSFPP ||
 615                   sfp->sfp_info.conn_type == CVMX_SFP_CONN_QSFP28 ||
 616                   sfp->sfp_info.conn_type == CVMX_SFP_CONN_MICRO_QSFP) ||
 617                  sfp->is_qsfp;
 618
 619        err = cvmx_qsfp_select(sfp, true);
 620        if (err) {
 621                debug("%s: Error selecting SFP/QSFP slot\n", __func__);
 622                return err;
 623        }
 624
 625        debug("%s: Reading eeprom from i2c address %d:0x%x\n", __func__,
 626              oct_bus, sfp->i2c_eeprom_addr);
 627        for (retry = 0; retry < 3; retry++) {
 628                err = i2c_get_chip(bus->i2c_bus, sfp->i2c_eeprom_addr, 1, &dev);
 629                if (err) {
 630                        debug("Cannot find I2C device: %d\n", err);
 631                        goto error;
 632                }
 633
 634                err = dm_i2c_read(dev, 0, buffer, 256);
 635                if (err || !sfp_verify_checksum(buffer)) {
 636                        debug("%s: Error %d reading eeprom at 0x%x, bus %d\n",
 637                              __func__, err, sfp->i2c_eeprom_addr, oct_bus);
 638                        debug("%s: Retry %d\n", __func__, retry + 1);
 639                        mdelay(1000);
 640                } else {
 641                        break;
 642                }
 643        }
 644        if (err) {
 645                debug("%s: Error reading eeprom from SFP %s\n", __func__,
 646                      sfp->name);
 647                return -1;
 648        }
 649#ifdef DEBUG
 650        print_buffer(0, buffer, 1, 256, 0);
 651#endif
 652        memset(&sfp->sfp_info, 0, sizeof(struct cvmx_sfp_mod_info));
 653
 654        switch (buffer[0]) {
 655        case CVMX_SFP_CONN_SFP:
 656                err = cvmx_sfp_parse_sfp_buffer(&sfp->sfp_info, buffer);
 657                break;
 658        case CVMX_SFP_CONN_QSFP:
 659        case CVMX_SFP_CONN_QSFPP:
 660        case CVMX_SFP_CONN_QSFP28:
 661        case CVMX_SFP_CONN_MICRO_QSFP:
 662                err = cvmx_sfp_parse_qsfp_buffer(&sfp->sfp_info, buffer);
 663                break;
 664        default:
 665                debug("%s: Unknown SFP transceiver type 0x%x\n", __func__,
 666                      buffer[0]);
 667                err = -1;
 668                break;
 669        }
 670
 671error:
 672        if (is_qsfp)
 673                err |= cvmx_qsfp_select(sfp, false);
 674
 675        if (!err) {
 676                sfp->valid = true;
 677                sfp->sfp_info.valid = true;
 678        } else {
 679                sfp->valid = false;
 680                sfp->sfp_info.valid = false;
 681        }
 682
 683        return err;
 684}
 685
 686/**
 687 * Function called to check and return the status of the mod_abs pin or
 688 * mod_pres pin for QSFPs.
 689 *
 690 * @param       sfp     Handle to SFP information.
 691 * @param       data    User-defined data passed to the function
 692 *
 693 * @return      0 if absent, 1 if present, -1 on error
 694 */
 695int cvmx_sfp_check_mod_abs(struct cvmx_fdt_sfp_info *sfp, void *data)
 696{
 697        int val;
 698        int err = 0;
 699        int mode;
 700
 701        if (!dm_gpio_is_valid(&sfp->mod_abs)) {
 702                debug("%s: Error: mod_abs not set for %s\n", __func__,
 703                      sfp->name);
 704                return -1;
 705        }
 706        val = dm_gpio_get_value(&sfp->mod_abs);
 707        debug("%s(%s, %p) mod_abs: %d\n", __func__, sfp->name, data, val);
 708        if (val >= 0 && val != sfp->last_mod_abs && sfp->mod_abs_changed) {
 709                err = 0;
 710                if (!val) {
 711                        err = cvmx_sfp_read_i2c_eeprom(sfp);
 712                        if (err)
 713                                debug("%s: Error reading SFP %s EEPROM\n",
 714                                      __func__, sfp->name);
 715                }
 716                err = sfp->mod_abs_changed(sfp, val, sfp->mod_abs_changed_data);
 717        }
 718        debug("%s(%s (%p)): Last mod_abs: %d, current: %d, changed: %p, rc: %d, next: %p, caller: %p\n",
 719              __func__, sfp->name, sfp, sfp->last_mod_abs, val,
 720              sfp->mod_abs_changed, err, sfp->next_iface_sfp,
 721              __builtin_return_address(0));
 722
 723        if (err >= 0) {
 724                sfp->last_mod_abs = val;
 725                mode = cvmx_helper_interface_get_mode(sfp->xiface);
 726                cvmx_sfp_validate_module(sfp, mode);
 727        } else {
 728                debug("%s: mod_abs_changed for %s returned error\n", __func__,
 729                      sfp->name);
 730        }
 731
 732        return err < 0 ? err : val;
 733}
 734
 735/**
 736 * Reads the EEPROMs of all SFP modules.
 737 *
 738 * @return 0 for success
 739 */
 740int cvmx_sfp_read_all_modules(void)
 741{
 742        struct cvmx_fdt_sfp_info *sfp;
 743        int val;
 744        bool error = false;
 745        int rc;
 746
 747        for (sfp = sfp_list; sfp; sfp = sfp->next) {
 748                if (dm_gpio_is_valid(&sfp->mod_abs)) {
 749                        /* Check if module absent */
 750                        val = dm_gpio_get_value(&sfp->mod_abs);
 751                        sfp->last_mod_abs = val;
 752                        if (val)
 753                                continue;
 754                }
 755                rc = cvmx_sfp_read_i2c_eeprom(sfp);
 756                if (rc) {
 757                        debug("%s: Error reading eeprom from SFP %s\n",
 758                              __func__, sfp->name);
 759                        error = true;
 760                }
 761        }
 762
 763        return error ? -1 : 0;
 764}
 765
 766/**
 767 * Registers a function to be called whenever the mod_abs/mod_pres signal
 768 * changes.
 769 *
 770 * @param       sfp             Handle to SFP data structure
 771 * @param       mod_abs_changed Function called whenever mod_abs is changed
 772 *                              or NULL to remove.
 773 * @param       mod_abs_changed_data    User-defined data passed to
 774 *                                      mod_abs_changed
 775 *
 776 * @return      0 for success
 777 *
 778 * @NOTE: If multiple SFP slots are linked together, all subsequent slots
 779 *        will also be registered for the same handler.
 780 */
 781int cvmx_sfp_register_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp,
 782                                      int (*mod_abs_changed)(struct cvmx_fdt_sfp_info *sfp,
 783                                                             int val, void *data),
 784                                      void *mod_abs_changed_data)
 785{
 786        sfp->mod_abs_changed = mod_abs_changed;
 787        sfp->mod_abs_changed_data = mod_abs_changed_data;
 788
 789        sfp->last_mod_abs = -2; /* undefined */
 790
 791        return 0;
 792}
 793
 794/**
 795 * Parses a SFP slot from the device tree
 796 *
 797 * @param       sfp             SFP handle to store data in
 798 * @param       fdt_addr        Address of flat device tree
 799 * @param       of_offset       Node in device tree for SFP slot
 800 *
 801 * @return      0 on success, -1 on error
 802 */
 803static int cvmx_sfp_parse_sfp(struct cvmx_fdt_sfp_info *sfp, ofnode node)
 804{
 805        struct ofnode_phandle_args phandle;
 806        int err;
 807
 808        sfp->name = ofnode_get_name(node);
 809        sfp->of_offset = ofnode_to_offset(node);
 810
 811        err = gpio_request_by_name_nodev(node, "tx_disable", 0,
 812                                         &sfp->tx_disable, GPIOD_IS_OUT);
 813        if (err) {
 814                printf("%s: tx_disable not found in DT!\n", __func__);
 815                return -ENODEV;
 816        }
 817        dm_gpio_set_value(&sfp->tx_disable, 0);
 818
 819        err = gpio_request_by_name_nodev(node, "mod_abs", 0,
 820                                         &sfp->mod_abs, GPIOD_IS_IN);
 821        if (err) {
 822                printf("%s: mod_abs not found in DT!\n", __func__);
 823                return -ENODEV;
 824        }
 825
 826        err = gpio_request_by_name_nodev(node, "tx_error", 0,
 827                                         &sfp->tx_error, GPIOD_IS_IN);
 828        if (err) {
 829                printf("%s: tx_error not found in DT!\n", __func__);
 830                return -ENODEV;
 831        }
 832
 833        err = gpio_request_by_name_nodev(node, "rx_los", 0,
 834                                         &sfp->rx_los, GPIOD_IS_IN);
 835        if (err) {
 836                printf("%s: rx_los not found in DT!\n", __func__);
 837                return -ENODEV;
 838        }
 839
 840        err = ofnode_parse_phandle_with_args(node, "eeprom", NULL, 0, 0,
 841                                             &phandle);
 842        if (!err) {
 843                sfp->i2c_eeprom_addr = ofnode_get_addr(phandle.node);
 844                debug("%s: eeprom address: 0x%x\n", __func__,
 845                      sfp->i2c_eeprom_addr);
 846
 847                debug("%s: Getting eeprom i2c bus for %s\n", __func__,
 848                      sfp->name);
 849                sfp->i2c_bus = cvmx_ofnode_get_i2c_bus(ofnode_get_parent(phandle.node));
 850        }
 851
 852        err = ofnode_parse_phandle_with_args(node, "diag", NULL, 0, 0,
 853                                             &phandle);
 854        if (!err) {
 855                sfp->i2c_diag_addr = ofnode_get_addr(phandle.node);
 856                if (!sfp->i2c_bus)
 857                        sfp->i2c_bus = cvmx_ofnode_get_i2c_bus(ofnode_get_parent(phandle.node));
 858        }
 859
 860        sfp->last_mod_abs = -2;
 861        sfp->last_rx_los = -2;
 862
 863        if (!sfp->i2c_bus) {
 864                debug("%s(%s): Error: could not get i2c bus from device tree\n",
 865                      __func__, sfp->name);
 866                err = -1;
 867        }
 868
 869        if (err) {
 870                dm_gpio_free(sfp->tx_disable.dev, &sfp->tx_disable);
 871                dm_gpio_free(sfp->mod_abs.dev, &sfp->mod_abs);
 872                dm_gpio_free(sfp->tx_error.dev, &sfp->tx_error);
 873                dm_gpio_free(sfp->rx_los.dev, &sfp->rx_los);
 874        } else {
 875                sfp->valid = true;
 876        }
 877
 878        return err;
 879}
 880
 881/**
 882 * Parses a QSFP slot from the device tree
 883 *
 884 * @param       sfp             SFP handle to store data in
 885 * @param       fdt_addr        Address of flat device tree
 886 * @param       of_offset       Node in device tree for SFP slot
 887 *
 888 * @return      0 on success, -1 on error
 889 */
 890static int cvmx_sfp_parse_qsfp(struct cvmx_fdt_sfp_info *sfp, ofnode node)
 891{
 892        struct ofnode_phandle_args phandle;
 893        int err;
 894
 895        sfp->is_qsfp = true;
 896        sfp->name = ofnode_get_name(node);
 897        sfp->of_offset = ofnode_to_offset(node);
 898
 899        err = gpio_request_by_name_nodev(node, "lp_mode", 0,
 900                                         &sfp->lp_mode, GPIOD_IS_OUT);
 901        if (err) {
 902                printf("%s: lp_mode not found in DT!\n", __func__);
 903                return -ENODEV;
 904        }
 905
 906        err = gpio_request_by_name_nodev(node, "mod_prs", 0,
 907                                         &sfp->mod_abs, GPIOD_IS_IN);
 908        if (err) {
 909                printf("%s: mod_prs not found in DT!\n", __func__);
 910                return -ENODEV;
 911        }
 912
 913        err = gpio_request_by_name_nodev(node, "select", 0,
 914                                         &sfp->select, GPIOD_IS_IN);
 915        if (err) {
 916                printf("%s: select not found in DT!\n", __func__);
 917                return -ENODEV;
 918        }
 919
 920        err = gpio_request_by_name_nodev(node, "reset", 0,
 921                                         &sfp->reset, GPIOD_IS_OUT);
 922        if (err) {
 923                printf("%s: reset not found in DT!\n", __func__);
 924                return -ENODEV;
 925        }
 926
 927        err = gpio_request_by_name_nodev(node, "interrupt", 0,
 928                                         &sfp->interrupt, GPIOD_IS_IN);
 929        if (err) {
 930                printf("%s: interrupt not found in DT!\n", __func__);
 931                return -ENODEV;
 932        }
 933
 934        err = ofnode_parse_phandle_with_args(node, "eeprom", NULL, 0, 0,
 935                                             &phandle);
 936        if (!err) {
 937                sfp->i2c_eeprom_addr = ofnode_get_addr(phandle.node);
 938                sfp->i2c_bus = cvmx_ofnode_get_i2c_bus(ofnode_get_parent(phandle.node));
 939        }
 940
 941        err = ofnode_parse_phandle_with_args(node, "diag", NULL, 0, 0,
 942                                             &phandle);
 943        if (!err) {
 944                sfp->i2c_diag_addr = ofnode_get_addr(phandle.node);
 945                if (!sfp->i2c_bus)
 946                        sfp->i2c_bus = cvmx_ofnode_get_i2c_bus(ofnode_get_parent(phandle.node));
 947        }
 948
 949        sfp->last_mod_abs = -2;
 950        sfp->last_rx_los = -2;
 951
 952        if (!sfp->i2c_bus) {
 953                cvmx_printf("%s(%s): Error: could not get i2c bus from device tree\n",
 954                            __func__, sfp->name);
 955                err = -1;
 956        }
 957
 958        if (err) {
 959                dm_gpio_free(sfp->lp_mode.dev, &sfp->lp_mode);
 960                dm_gpio_free(sfp->mod_abs.dev, &sfp->mod_abs);
 961                dm_gpio_free(sfp->select.dev, &sfp->select);
 962                dm_gpio_free(sfp->reset.dev, &sfp->reset);
 963                dm_gpio_free(sfp->interrupt.dev, &sfp->interrupt);
 964        } else {
 965                sfp->valid = true;
 966        }
 967
 968        return err;
 969}
 970
 971/**
 972 * Parses the device tree for SFP and QSFP slots
 973 *
 974 * @param       fdt_addr        Address of flat device-tree
 975 *
 976 * @return      0 for success, -1 on error
 977 */
 978int cvmx_sfp_parse_device_tree(const void *fdt_addr)
 979{
 980        struct cvmx_fdt_sfp_info *sfp, *first_sfp = NULL, *last_sfp = NULL;
 981        ofnode node;
 982        int err = 0;
 983        int reg;
 984        static bool parsed;
 985
 986        debug("%s(%p): Parsing...\n", __func__, fdt_addr);
 987        if (parsed) {
 988                debug("%s(%p): Already parsed\n", __func__, fdt_addr);
 989                return 0;
 990        }
 991
 992        ofnode_for_each_compatible_node(node, "ethernet,sfp-slot") {
 993                if (!ofnode_valid(node))
 994                        continue;
 995
 996                sfp = cvm_sfp_alloc(sizeof(*sfp));
 997                if (!sfp)
 998                        return -1;
 999
1000                err = cvmx_sfp_parse_sfp(sfp, node);
1001                if (!err) {
1002                        if (!sfp_list)
1003                                sfp_list = sfp;
1004                        if (last_sfp)
1005                                last_sfp->next = sfp;
1006                        sfp->prev = last_sfp;
1007                        last_sfp = sfp;
1008                        debug("%s: parsed %s\n", __func__, sfp->name);
1009                } else {
1010                        debug("%s: Error parsing SFP at node %s\n",
1011                              __func__, ofnode_get_name(node));
1012                        return err;
1013                }
1014        }
1015
1016        ofnode_for_each_compatible_node(node, "ethernet,qsfp-slot") {
1017                if (!ofnode_valid(node))
1018                        continue;
1019
1020                sfp = cvm_sfp_alloc(sizeof(*sfp));
1021                if (!sfp)
1022                        return -1;
1023
1024                err = cvmx_sfp_parse_qsfp(sfp, node);
1025                if (!err) {
1026                        if (!sfp_list)
1027                                sfp_list = sfp;
1028                        if (last_sfp)
1029                                last_sfp->next = sfp;
1030                        sfp->prev = last_sfp;
1031                        last_sfp = sfp;
1032                        debug("%s: parsed %s\n", __func__, sfp->name);
1033                } else {
1034                        debug("%s: Error parsing QSFP at node %s\n",
1035                              __func__, ofnode_get_name(node));
1036                        return err;
1037                }
1038        }
1039
1040        if (!octeon_has_feature(OCTEON_FEATURE_BGX))
1041                return 0;
1042
1043        err = 0;
1044        ofnode_for_each_compatible_node(node, "cavium,octeon-7890-bgx-port") {
1045                int sfp_nodes[4];
1046                ofnode sfp_ofnodes[4];
1047                int num_sfp_nodes;
1048                u64 reg_addr;
1049                struct cvmx_xiface xi;
1050                int xiface, index;
1051                cvmx_helper_interface_mode_t mode;
1052                int i;
1053                int rc;
1054
1055                if (!ofnode_valid(node))
1056                        break;
1057
1058                num_sfp_nodes = ARRAY_SIZE(sfp_nodes);
1059                rc = cvmx_ofnode_lookup_phandles(node, "sfp-slot",
1060                                                 &num_sfp_nodes, sfp_ofnodes);
1061                if (rc != 0 || num_sfp_nodes < 1)
1062                        rc = cvmx_ofnode_lookup_phandles(node, "qsfp-slot",
1063                                                         &num_sfp_nodes,
1064                                                         sfp_ofnodes);
1065                /* If no SFP or QSFP slot found, go to next port */
1066                if (rc < 0)
1067                        continue;
1068
1069                last_sfp = NULL;
1070                for (i = 0; i < num_sfp_nodes; i++) {
1071                        sfp = cvmx_sfp_find_slot_by_fdt_node(ofnode_to_offset(sfp_ofnodes[i]));
1072                        debug("%s: Adding sfp %s (%p) to BGX port\n",
1073                              __func__, sfp->name, sfp);
1074                        if (last_sfp)
1075                                last_sfp->next_iface_sfp = sfp;
1076                        else
1077                                first_sfp = sfp;
1078                        last_sfp = sfp;
1079                }
1080                if (!first_sfp) {
1081                        debug("%s: Error: could not find SFP slot for BGX port %s\n",
1082                              __func__,
1083                              fdt_get_name(fdt_addr, sfp_nodes[0],
1084                                           NULL));
1085                        err = -1;
1086                        break;
1087                }
1088
1089                /* Get the port index */
1090                reg = ofnode_get_addr(node);
1091                if (reg < 0) {
1092                        debug("%s: Error: could not get BGX port reg value\n",
1093                              __func__);
1094                        err = -1;
1095                        break;
1096                }
1097                index = reg;
1098
1099                /* Get BGX node and address */
1100                reg_addr = ofnode_get_addr(ofnode_get_parent(node));
1101                /* Extrace node */
1102                xi.node = cvmx_csr_addr_to_node(reg_addr);
1103                /* Extract reg address */
1104                reg_addr = cvmx_csr_addr_strip_node(reg_addr);
1105                if ((reg_addr & 0xFFFFFFFFF0000000) !=
1106                    0x00011800E0000000) {
1107                        debug("%s: Invalid BGX address 0x%llx\n",
1108                              __func__, (unsigned long long)reg_addr);
1109                        xi.node = -1;
1110                        err = -1;
1111                        break;
1112                }
1113
1114                /* Extract interface from address */
1115                xi.interface = (reg_addr >> 24) & 0x0F;
1116                /* Convert to xiface */
1117                xiface = cvmx_helper_node_interface_to_xiface(xi.node,
1118                                                              xi.interface);
1119                debug("%s: Parsed %d SFP slots for interface 0x%x, index %d\n",
1120                      __func__, num_sfp_nodes, xiface, index);
1121
1122                mode = cvmx_helper_interface_get_mode(xiface);
1123                for (sfp = first_sfp; sfp; sfp = sfp->next_iface_sfp) {
1124                        sfp->xiface = xiface;
1125                        sfp->index = index;
1126                        /* Convert to IPD port */
1127                        sfp->ipd_port[0] =
1128                                cvmx_helper_get_ipd_port(xiface, index);
1129                        debug("%s: sfp %s (%p) xi: 0x%x, index: 0x%x, node: %d, mode: 0x%x, next: %p\n",
1130                              __func__, sfp->name, sfp, sfp->xiface,
1131                              sfp->index, xi.node, mode,
1132                              sfp->next_iface_sfp);
1133                        if (mode == CVMX_HELPER_INTERFACE_MODE_XLAUI ||
1134                            mode == CVMX_HELPER_INTERFACE_MODE_40G_KR4)
1135                                for (i = 1; i < 4; i++)
1136                                        sfp->ipd_port[i] = -1;
1137                        else
1138                                for (i = 1; i < 4; i++)
1139                                        sfp->ipd_port[i] =
1140                                                cvmx_helper_get_ipd_port(
1141                                                        xiface, i);
1142                }
1143                cvmx_helper_cfg_set_sfp_info(xiface, index, first_sfp);
1144        }
1145
1146        if (!err) {
1147                parsed = true;
1148                cvmx_sfp_read_all_modules();
1149        }
1150
1151        return err;
1152}
1153
1154/**
1155 * Given a fdt node offset find the corresponding SFP or QSFP slot
1156 *
1157 * @param       of_offset       flat device tree node offset
1158 *
1159 * @return      pointer to SFP data structure or NULL if not found
1160 */
1161struct cvmx_fdt_sfp_info *cvmx_sfp_find_slot_by_fdt_node(int of_offset)
1162{
1163        struct cvmx_fdt_sfp_info *sfp = sfp_list;
1164
1165        while (sfp) {
1166                if (sfp->of_offset == of_offset)
1167                        return sfp;
1168                sfp = sfp->next;
1169        }
1170        return NULL;
1171}
1172
1173static bool cvmx_sfp_validate_quad(struct cvmx_fdt_sfp_info *sfp,
1174                                   struct cvmx_phy_gpio_leds *leds)
1175{
1176        bool multi_led = leds && (leds->next);
1177        bool error = false;
1178        int mod_abs;
1179
1180        do {
1181                /* Skip missing modules */
1182                if (dm_gpio_is_valid(&sfp->mod_abs))
1183                        mod_abs = dm_gpio_get_value(&sfp->mod_abs);
1184                else
1185                        mod_abs = 0;
1186                if (!mod_abs) {
1187                        if (cvmx_sfp_read_i2c_eeprom(sfp)) {
1188                                debug("%s: Error reading eeprom for %s\n",
1189                                      __func__, sfp->name);
1190                        }
1191                        if (sfp->sfp_info.rate < CVMX_SFP_RATE_10G) {
1192                                cvmx_helper_leds_show_error(leds, true);
1193                                error = true;
1194                        } else if (sfp->sfp_info.rate >= CVMX_SFP_RATE_10G) {
1195                                /* We don't support 10GBase-T modules in
1196                                 * this mode.
1197                                 */
1198                                switch (sfp->sfp_info.cable_comp) {
1199                                case CVMX_SFP_CABLE_10GBASE_T:
1200                                case CVMX_SFP_CABLE_10GBASE_T_SR:
1201                                case CVMX_SFP_CABLE_5GBASE_T:
1202                                case CVMX_SFP_CABLE_2_5GBASE_T:
1203                                        cvmx_helper_leds_show_error(leds, true);
1204                                        error = true;
1205                                        break;
1206                                default:
1207                                        break;
1208                                }
1209                        }
1210                } else if (multi_led) {
1211                        cvmx_helper_leds_show_error(leds, false);
1212                }
1213
1214                if (multi_led && leds->next)
1215                        leds = leds->next;
1216                sfp = sfp->next_iface_sfp;
1217        } while (sfp);
1218
1219        if (!multi_led)
1220                cvmx_helper_leds_show_error(leds, error);
1221
1222        return error;
1223}
1224
1225/**
1226 * Validates if the module is correct for the specified port
1227 *
1228 * @param[in]   sfp     SFP port to check
1229 * @param       xiface  interface
1230 * @param       index   port index
1231 * @param       speed   link speed, -1 if unknown
1232 * @param       mode    interface mode
1233 *
1234 * @return      true if module is valid, false if invalid
1235 * NOTE: This will also toggle the error LED, if present
1236 */
1237bool cvmx_sfp_validate_module(struct cvmx_fdt_sfp_info *sfp, int mode)
1238{
1239        const struct cvmx_sfp_mod_info *mod_info = &sfp->sfp_info;
1240        int xiface = sfp->xiface;
1241        int index = sfp->index;
1242        struct cvmx_phy_gpio_leds *leds;
1243        bool error = false;
1244        bool quad_mode = false;
1245
1246        debug("%s(%s, 0x%x, 0x%x, 0x%x)\n", __func__, sfp->name, xiface, index,
1247              mode);
1248        if (!sfp) {
1249                debug("%s: Error: sfp is NULL\n", __func__);
1250                return false;
1251        }
1252        /* No module is valid */
1253        leds = cvmx_helper_get_port_phy_leds(xiface, index);
1254        if (!leds)
1255                debug("%s: No leds for 0x%x:0x%x\n", __func__, xiface, index);
1256
1257        if (mode != CVMX_HELPER_INTERFACE_MODE_XLAUI &&
1258            mode != CVMX_HELPER_INTERFACE_MODE_40G_KR4 && !sfp->is_qsfp &&
1259            sfp->last_mod_abs && leds) {
1260                cvmx_helper_leds_show_error(leds, false);
1261                debug("%s: %s: last_mod_abs: %d, no error\n", __func__,
1262                      sfp->name, sfp->last_mod_abs);
1263                return true;
1264        }
1265
1266        switch (mode) {
1267        case CVMX_HELPER_INTERFACE_MODE_RGMII:
1268        case CVMX_HELPER_INTERFACE_MODE_GMII:
1269        case CVMX_HELPER_INTERFACE_MODE_SGMII:
1270        case CVMX_HELPER_INTERFACE_MODE_QSGMII:
1271        case CVMX_HELPER_INTERFACE_MODE_AGL:
1272        case CVMX_HELPER_INTERFACE_MODE_SPI:
1273                if ((mod_info->active_cable &&
1274                     mod_info->rate != CVMX_SFP_RATE_1G) ||
1275                    mod_info->rate < CVMX_SFP_RATE_1G)
1276                        error = true;
1277                break;
1278        case CVMX_HELPER_INTERFACE_MODE_RXAUI:
1279        case CVMX_HELPER_INTERFACE_MODE_XAUI:
1280        case CVMX_HELPER_INTERFACE_MODE_10G_KR:
1281        case CVMX_HELPER_INTERFACE_MODE_XFI:
1282                if ((mod_info->active_cable &&
1283                     mod_info->rate != CVMX_SFP_RATE_10G) ||
1284                    mod_info->rate < CVMX_SFP_RATE_10G)
1285                        error = true;
1286                break;
1287        case CVMX_HELPER_INTERFACE_MODE_XLAUI:
1288        case CVMX_HELPER_INTERFACE_MODE_40G_KR4:
1289                if (!sfp->is_qsfp) {
1290                        quad_mode = true;
1291                        error = cvmx_sfp_validate_quad(sfp, leds);
1292                } else {
1293                        if ((mod_info->active_cable &&
1294                             mod_info->rate != CVMX_SFP_RATE_40G) ||
1295                            mod_info->rate < CVMX_SFP_RATE_25G)
1296                                error = true;
1297                }
1298                break;
1299        default:
1300                debug("%s: Unsupported interface mode %d on xiface 0x%x\n",
1301                      __func__, mode, xiface);
1302                return false;
1303        }
1304        debug("%s: %s: error: %d\n", __func__, sfp->name, error);
1305        if (leds && !quad_mode)
1306                cvmx_helper_leds_show_error(leds, error);
1307
1308        return !error;
1309}
1310