예제 #1
0
int bdk_if_phy_marvell_setup(bdk_node_t node, int qlm, int mdio_bus, int phy_addr)
{
    BDK_TRACE(PHY,"In %s\n",__FUNCTION__);

    /* Check if the PHY is marvell PHY we expect */
    int phy_status = bdk_mdio_read(node, mdio_bus, phy_addr, BDK_MDIO_PHY_REG_ID1);
    if (phy_status != 0x0141)
        return 0;

    /* Check that the GSER mode is SGMII */
    /* Switch the marvell PHY to the correct mode */
    bdk_qlm_modes_t qlm_mode = bdk_qlm_get_mode(node, qlm);
    
    BDK_TRACE(PHY,"%s: QLM:%d QLM_MODE:%d\n",__FUNCTION__, qlm, qlm_mode);
    
    if ((qlm_mode != BDK_QLM_MODE_SGMII_1X1) &&
        (qlm_mode != BDK_QLM_MODE_SGMII_2X1))
        return 0;

    BDK_TRACE(PHY,"%s: Detected Marvell Phy in SGMII mode\n", __FUNCTION__);    
    for (int port = 0; port < 2; port++)
    {
        setup_marvell_phy(node, mdio_bus, phy_addr + port);
    }
    return 0;
}
예제 #2
0
/**
 * Do all the DRAM Margin tests
 *
 * @param node   Node to test
 *
 * @return Success or Fail
 */
void bdk_dram_margin(int node)
{
    BDK_TRACE(DRAM, "N%d: Starting DRAM margining\n", node);
    libdram_margin(node);
    BDK_TRACE(DRAM, "N%d: Finished DRAM margining.\n", node);
    return;
}
예제 #3
0
/**
 * Determine the DLM/QLM mode based on a QSFP/QSFP+ connected to
 * the port. This code is sloppy about finding the BGX PHY for
 * the DLM/QLM because not all lanes may be used.
 *
 * @param node   Node to determine mode for
 * @param qlm    DLM/QLM the SFP/SFP+ is connected to
 *
 * @return QLM mode or -1 on failure
 */
static int init_qsfp(int node, int qlm)
{
    int mode = BDK_QLM_MODE_XLAUI_1X4; /* Default to XLAUI if detection fails */
    int bgx = -1;
    int bgx_lane_mask = 0;

    find_bgx(node, qlm, &bgx, &bgx_lane_mask);
    if (bgx == -1)
        return mode;

    BDK_TRACE(INIT, "N%d.QLM%d: Checking for QSFP/QSFP+\n", node, qlm);
    int index = 0;

    /* Lookup the PHY address for this BGX port */
    int phy_addr = bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, node, bgx, index);
    /* QSFP/QSFP+ are connected with TWSI, so only check ports with
       PHYs connected with TWSI */
    if ((phy_addr & BDK_IF_PHY_TYPE_MASK) != BDK_IF_PHY_TWSI)
        return mode;

    /* For TWSI:
        Bits[31:24]: Node ID, 0xff for device node
        Bits[23:16]: TWSI internal address width in bytes (0-2)
        Bits[15:12]: 2=TWSI
        Bits[11:8]: TWSI bus number
        Bits[7:0]: TWSI address */
    int n = (phy_addr >> 24) & 0xff;
    int twsi_ia_width = (phy_addr >> 16) & 0xff;
    int twsi_bus = (phy_addr >> 8) & 0xf;
    int twsi_addr = 0x50; /* From SFP spec */
    if (n == 0xff)
        n = node;

    /* Byte 0: Identifier, should be 0x03 for SFP/SFP+
                0x03 = SFP of SFP+
                0x0c = QSFP
                0x0d = QSFP+ */
    int64_t eeprom_00 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 0, 1, twsi_ia_width);
    switch (eeprom_00)
    {
        case 0x03:
            BDK_TRACE(INIT, "N%d.QLM%d: BGX%d QSFP/QSFP+ contains a SFP+\n", node, qlm, bgx);
            mode = init_sfp(node, qlm);
            break;
        case 0x0c:
        case 0x0d:
            BDK_TRACE(INIT, "N%d.QLM%d: BGX%d Found a QSFP/QSFP+, assuming 40G\n", node, qlm, bgx);
            mode = BDK_QLM_MODE_XLAUI_1X4;
            break;
        default:
            BDK_TRACE(INIT, "N%d.QLM%d: BGX%d QSFP/QSFP+ not detected\n", node, qlm, bgx);
            break;
    }
    return mode;
}
예제 #4
0
static void boot_init_qlm_clk(void)
{
    /* Setup reference clocks */
    for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
    {
        if (!bdk_numa_exists(n))
            continue;

        int num_qlms = bdk_qlm_get_num(n);

        BDK_TRACE(INIT, "Initializing QLM clocks on Node %d\n", n);
        for (int qlm = 0; qlm < num_qlms; qlm++)
        {
            bdk_qlm_clock_t clk = bdk_config_get_int(BDK_CONFIG_QLM_CLK, n, qlm);
            if (BDK_QLM_CLK_LAST == clk) /* no entry */
                continue;

            if (clk > BDK_QLM_CLK_LAST)
            {
                bdk_warn("Invalid clock source %d for QLM%d on node %d. Not configuring.\n",
                         clk, qlm, n);
                continue;
            }

            if (0 != bdk_qlm_set_clock(n, qlm, clk))
            {
                bdk_error("Error setting clock source %d for QLM%d on node %d. Ignoring.\n",
                          clk, qlm, n);
            }
        }
    }
}
예제 #5
0
/**
 * Lookup a DRAM configuration by name and initialize DRAM using it
 *
 * @param node   Node to configure
 * @param ddr_clock_override
 *               If non zero, override the DRAM frequency specified
 *               in the config with this value
 *
 * @return Amount of DRAM in MB, or negative on failure
 */
int bdk_dram_config(int node, int ddr_clock_override)
{
    const dram_config_t *config = libdram_config_load(node);
    if (!config)
    {
        printf("N%d: No DRAM config specified, skipping DRAM init\n", node);
        return 0;
    }

    BDK_TRACE(DRAM, "N%d: Starting DRAM init (config=%p, ddr_clock_override=%d)\n", node, config, ddr_clock_override);
    int mbytes = libdram_config(node, config, ddr_clock_override);
    BDK_TRACE(DRAM, "N%d: DRAM init returned %d\n", node, mbytes);
    if (mbytes <= 0)
    {
        printf("ERROR: DDR initialization failed\n");
        return -1;
    }

    return mbytes;
}
예제 #6
0
/**
 * Setup marvell PHYs
 * This function sets up one port in a marvell 88E1512 in SGMII mode
 */
static void setup_marvell_phy(bdk_node_t node, int mdio_bus, int mdio_addr)
{
      int phy_status = 0;

           BDK_TRACE(PHY, "%s In SGMII mode for Marvell PHY 88E1512\n", __FUNCTION__);
          /* Switch to Page 18 */
            phy_status = bdk_mdio_write(node, mdio_bus, mdio_addr, 22, 18);
          if (phy_status < 0)
                       return;

          phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 22);
          if (phy_status < 0)
                       return;

          /* Change the Phy System mode from RGMII(default hw reset mode) to SGMII */
          phy_status = bdk_mdio_write(node, mdio_bus, mdio_addr, 20, 1);
          if (phy_status < 0)
                return;

          /* Requires a Software reset */
          phy_status = bdk_mdio_write(node, mdio_bus, mdio_addr, 20, 0x8001);
          if (phy_status < 0)
                return;

          phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 20);
          if (phy_status < 0)
                       return;

          /* Change the Page back to 0 */
            phy_status = bdk_mdio_write(node, mdio_bus, mdio_addr, 22, 0);
          if (phy_status < 0)
                       return;

          phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 22);
          if (phy_status < 0)
                       return;
      
      phy_status = bdk_mdio_read(node, mdio_bus, mdio_addr, 17);
      if (phy_status < 0)
           return;
}
예제 #7
0
/**
 * Given a node and DLM/QLM, return the possible BGX lanes connected to it. This
 * is needed to determine which PHY address to use for SFP/SFP+ detection.
 *
 * @param node   Node the DLM/QLM is on
 * @param qlm    DLM/QLM to find the BGX for
 * @param bgx    Output: The BGX instance number, or -1 on failure
 * @param bgx_lane_mask
 *               Output: Which BGX indexes may be connected to this port
 */
static void find_bgx(int node, int qlm, int *bgx, int *bgx_lane_mask)
{
    *bgx = -1;
    *bgx_lane_mask = 0;

    if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
    {
        switch (qlm)
        {
            case 0: /* BGX0 -> QLM0 */
            case 1: /* BGX1 -> QLM1 */
                *bgx = qlm;
                *bgx_lane_mask = 0xf;
                return;
            default:
                BDK_TRACE(INIT, "N%d.QLM%d: No BGX for this QLM, illegal config\n", node, qlm);
                return;
        }
    }
    else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
    {
        switch (qlm)
        {
            case 2: /* BGX0 -> QLM2 */
                *bgx = 0;
                *bgx_lane_mask = 0xf;
                return;
            case 3: /* BGX1 -> QLM3 */
                *bgx = 1;
                *bgx_lane_mask = 0xf;
                return;
            case 4: /* BGX3 -> DLM4 */
                *bgx = 3;
                *bgx_lane_mask = 0x3;
                return;
            case 5: /* BGX2 -> DLM5 */
                *bgx = 2;
                *bgx_lane_mask = 0x3;
                return;
            case 6: /* BGX2 -> DLM6 */
                *bgx = 2;
                *bgx_lane_mask = 0xc;
                return;
            default:
                BDK_TRACE(INIT, "N%d.QLM%d: No BGX for this QLM, illegal config\n", node, qlm);
                return;
        }
    }
    else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
    {
        switch (qlm)
        {
            case 0: /* BGX0 -> DLM0 */
                *bgx = 0;
                *bgx_lane_mask = 0x3;
                return;
            case 1: /* BGX0 -> DLM1 */
                *bgx = 0;
                *bgx_lane_mask = 0xc;
                return;
            case 2: /* BGX1 -> DLM2 */
                *bgx = 1;
                *bgx_lane_mask = 0x3;
                return;
            case 3: /* BGX1 -> DLM3 */
                *bgx = 1;
                *bgx_lane_mask = 0xc;
                return;
            default:
                BDK_TRACE(INIT, "N%d.QLM%d: No BGX for this QLM, illegal config\n", node, qlm);
                return;
        }
    }
    else
        bdk_error("N%d.QLM%d: Unsupported chip, update %s()\n", node, qlm, __FUNCTION__);
}
예제 #8
0
static void boot_init_qlm_mode(void)
{
    /* Check if QLM autoconfig is requested */
    int qlm_auto = bdk_config_get_int(BDK_CONFIG_QLM_AUTO_CONFIG);
    if (qlm_auto)
    {
        /* Auto configuration of QLMs
         */
        for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
        {
            if (bdk_numa_exists(n))
            {
                BDK_TRACE(INIT, "Initializing QLMs on Node %d\n", n);
                bdk_qlm_auto_config(n);
            }
        }
    }
   /*
    * Check if QLM autoconfig from DIP switch settings is requested
    */
    else if (bdk_config_get_int(BDK_CONFIG_QLM_DIP_AUTO_CONFIG))
    {
        BDK_TRACE(INIT, "Reading DIP Switch settings for QLM Auto configuration\n");

        /* Auto configuration of QLMs
         */
        for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
        {
            if (bdk_numa_exists(n))
            {
                BDK_TRACE(INIT, "Initializing QLMs on Node %d\n", n);
                if (bdk_qlm_dip_auto_config(n))
                    bdk_error("QLM Auto configuration failed!\n");
            }
        }

    }
    else
    {
        /* Initialize the QLMs based on configuration file settings
         */

        boot_init_qlm_clk();

        for (bdk_node_t n = BDK_NODE_0; n < BDK_NUMA_MAX_NODES; n++)
        {
            if (!bdk_numa_exists(n))
                continue;

            int num_qlms = bdk_qlm_get_num(n);

            BDK_TRACE(INIT, "Initializing QLMs on Node %d\n", n);
            for (int qlm = 0; qlm < num_qlms; qlm++)
            {
                const char *cfg_val;

                cfg_val = bdk_config_get_str(BDK_CONFIG_QLM_MODE, n, qlm);
                if (!cfg_val)
                    continue;

                int mode;
                int freq;
                /* Check for special token telling us to configure the QLM
                   based on the SFP/SFP+/QSFP/QSFP+ plugged into the system. */
                if ((strcmp(cfg_val, "SFP+") == 0) || (strcmp(cfg_val, "QSFP+") == 0))
                {
                    if (strcmp(cfg_val, "SFP+") == 0)
                        mode = init_sfp(n, qlm);
                    else
                        mode = init_qsfp(n, qlm);

                    if (mode == BDK_QLM_MODE_SGMII_4X1)
                        freq = 1250;
                    else
                        freq = 10321;
                }
                else
                {
                    mode = bdk_qlm_cfg_string_to_mode(cfg_val);
                    freq = bdk_config_get_int(BDK_CONFIG_QLM_FREQ, n, qlm);
                }
                if (-1 == mode)
                {
                    bdk_error("Invalid QLM mode string '%s' for QLM%d on node %d. "
                                "Not configuring.\n", cfg_val, qlm, n);
                    continue;
                }
                if (-1 == freq)
                {
                    bdk_error("No frequency setting for QLM%d on node %d. "
                                "Not configuring.\n", qlm, n);
                    continue;
                }

                bdk_qlm_set_mode(n, qlm, mode, freq, 0);
            }
        }
    }
}
예제 #9
0
/**
 * Determine the DLM/QLM mode based on a SFP/SFP+ connected to the port. Note that
 * the CN8XXX parts can't control mode per lane, so all SFP/SFP+ on a DLM/QLM must
 * be the same mode. This code is sloppy about finding the BGX PHY for the DLM/QLM
 * because not all lanes may be used.
 *
 * @param node   Node to determine mode for
 * @param qlm    DLM/QLM the SFP/SFP+ is connected to
 *
 * @return QLM mode or -1 on failure
 */
static int init_sfp(int node, int qlm)
{
    int mode = BDK_QLM_MODE_XFI_4X1; /* Default to XFI if detection fails */
    int bgx = -1;
    int bgx_lane_mask = 0;

    find_bgx(node, qlm, &bgx, &bgx_lane_mask);
    if (bgx == -1)
        return mode;

    BDK_TRACE(INIT, "N%d.QLM%d: Checking for SFP/SFP+\n", node, qlm);

    for (int index = 0; index < 4; index++)
    {
        /* Skip BGX indexes that aren't applicable */
        if ((bgx_lane_mask & (1 << index)) == 0)
            continue;
        /* Lookup the PHY address for this BGX port */
        int phy_addr = bdk_config_get_int(BDK_CONFIG_PHY_ADDRESS, node, bgx, index);
        /* SFP/SFP+ are connected with TWSI, so only check ports with
           PHYs connected with TWSI */
        if ((phy_addr & BDK_IF_PHY_TYPE_MASK) != BDK_IF_PHY_TWSI)
            continue;

        /* For TWSI:
            Bits[31:24]: Node ID, 0xff for device node
            Bits[23:16]: TWSI internal address width in bytes (0-2)
            Bits[15:12]: 2=TWSI
            Bits[11:8]: TWSI bus number
            Bits[7:0]: TWSI address */
        int n = (phy_addr >> 24) & 0xff;
        int twsi_ia_width = (phy_addr >> 16) & 0xff;
        int twsi_bus = (phy_addr >> 8) & 0xf;
        int twsi_addr = 0x50; /* From SFP spec */
        if (n == 0xff)
            n = node;

        /* Read bytes 0-3 from eeprom. Note read is big endian, so byte 0 is
           bits 31:24 in the result */
        int64_t eeprom_00_03 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 0, 4, twsi_ia_width);
        if (eeprom_00_03 == -1)
        {
            BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ eeprom access failed\n", node, qlm, bgx, index);
            continue;
        }
        int64_t eeprom_04_07 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 4, 4, twsi_ia_width);
        if (eeprom_04_07 == -1)
        {
            BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ eeprom access failed\n", node, qlm, bgx, index);
            continue;
        }
        int64_t eeprom_08_11 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 8, 4, twsi_ia_width);
        if (eeprom_08_11 == -1)
        {
            BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ eeprom access failed\n", node, qlm, bgx, index);
            continue;
        }
        int64_t eeprom_12 = bdk_twsix_read_ia(n, twsi_bus, twsi_addr, 12, 1, twsi_ia_width);
        if (eeprom_12 == -1)
        {
            BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ eeprom access failed\n", node, qlm, bgx, index);
            continue;
        }

        /* Byte 0: Identifier, should be 0x03 for SFP/SFP+
                    0x03 = SFP of SFP+
                    0x0c = QSFP
                    0x0d = QSFP+ */
        if (bdk_extract(eeprom_00_03, 24, 8) != 0x03)
        {
            /* Byte 0 of eeprom should be 0x03 for SFP/SFP+ */
            BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ not detected\n", node, qlm, bgx, index);
            continue;
        }
        /* Byte 1: Extended Identifier, should be 0x04 */
        if (bdk_extract(eeprom_00_03, 16, 8) != 0x04)
        {
            BDK_TRACE(INIT, "N%d.QLM%d: BGX%d.%d SFP/SFP+ incorrect extended identifier\n", node, qlm, bgx, index);
            continue;
        }
        /* Byte 2: Connector
                    Value   Description of connector
                    00h     Unknown or unspecified
                    01h     SC
                    02h     Fibre Channel Style 1 copper connector
                    03h     Fibre Channel Style 2 copper connector
                    04h     BNC/TNC
                    05h     Fibre Channel coaxial headers
                    06h     FiberJack
                    07h     LC
                    08h     MT-RJ
                    09h     MU
                    0Ah     SG
                    0Bh     Optical pigtail
                    0Ch     MPO Parallel Optic
                    0Dh-1Fh Reserved, Unallocated
                    20h     HSSDC II
                    21h     Copper Pigtail
                    22h     RJ45
                    23h-7Fh Reserved, Unallocated
                    80-FFh Vendor specific */
        bool isOptical = false;
        switch (bdk_extract(eeprom_00_03, 8, 8))
        {
            case 0x01: /* SC - Short channel */
            case 0x07: /* LC - Long channel */
            case 0x0B: /* Optical pigtail */
                isOptical = true;
                break;
        }
        BDK_TRACE(INIT, "N%d.QLM%d: SFP/SFP+ eeprom Bytes[0:3] 0x%0llx, Bytes[4:7] 0x%08llx, [8:11] 0x%08llx [12] 0x%02llx\n",
            node, qlm, eeprom_00_03, eeprom_04_07, eeprom_08_11, eeprom_12);
        /* Byte 3: Transceiver info first byte. See comments below */
        /* Byte 3, bits 4-7 correspond to 10G Ethernet speeds */
        /* 10G Ethernet Compliance Codes
                Byte 3[7] 10G BASE-ER (Fiber - Extended Reach)
                Byte 3[6] 10G BASE-LRM (Fiber - Long reach multi-mode)
                Byte 3[5] 10G BASE-LR (Fiber - Long reach)
                Byte 3[4] 10G BASE-SR (Fiber - Short reach) */
        bool isXFI = bdk_extract(eeprom_00_03, 0, 8) != 0;
        /* Byte 6, bits 0-7 correspond to Gigabit Ethernet speeds */
        /* Gigabit Ethernet Compliance Codes
                Byte 6[7] BASE-PX
                Byte 6[6] BASE-BX10
                Byte 6[5] 100BASE-FX
                Byte 6[4] 100BASE-LX/LX10 (Fiber)
                Byte 6[3] 1000BASE-T (Twisted pair)
                Byte 6[2] 1000BASE-CX (Shielded balanced copper)
                Byte 6[1] 1000BASE-LX (Fiber)
                Byte 6[0] 1000BASE-SX (Fiber) */
        bool isSGMII = bdk_extract(eeprom_04_07, 8, 8) != 0;
        /* Byte 12 is the nominal bit rate, units of 100 MBits/sec. */
        int bit_rate = eeprom_12 * 100;
        if (bit_rate)
        {
            BDK_TRACE(INIT, "N%d.QLM%d: Nominal bit rate %d  MBits/sec\n",
                node, qlm, bit_rate);
            isXFI = (bit_rate >= 10000);
            isSGMII = (bit_rate <= 2500);
        }

        if (isXFI)
        {
            mode = BDK_QLM_MODE_XFI_4X1;
            if (isOptical)
                BDK_TRACE(INIT, "N%d.QLM%d: SFP+ selecting XFI Optical\n", node, qlm);
            else
                BDK_TRACE(INIT, "N%d.QLM%d: SFP+ selecting XFI Copper\n", node, qlm);
        }
        else if (isSGMII)
        {
            mode = BDK_QLM_MODE_SGMII_4X1;
            if (isOptical)
            {
                /* This should be 1000BASE-X, gigabit over fiber */
                BDK_TRACE(INIT, "N%d.QLM%d: SFP selecting SGMII Optical\n", node, qlm);
            }
            else /* This should be SGMII, gigabit over copper */
                BDK_TRACE(INIT, "N%d.QLM%d: SFP selecting SGMII Copper\n", node, qlm);
        }
    }
    return mode;
}