This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM2634: Ethernet Implementation on Custom PHY chip via SPI.

Part Number: AM2634
Other Parts Discussed in Thread: SYSCONFIG

Hi TI Family,

We have designed custom am2634 board, where instead of DP83869HMGZT  PHY ic (w.r.t launchpad kit) we are using KSZ9893RNXI-TR IC for our ethernet communication.
In launchpad default ic is configured using MDIO/MDC pin. But in custom card, configuration is done using SPI protocol.
To use the existing SDK incorportated in launchpad kit for our custom PCB having KSZ9893RNXI IC, what are the minimal updations required ?

Is there any reference codes that can be used for controlling KSZ9893RNXI-TR IC with AM2634 controller ?

Thanks

  • To use the existing SDK incorportated in launchpad kit for our custom PCB having KSZ9893RNXI IC, what are the minimal updations required ?

    Hi Tej,

    You will need to update the complete mdio implementation underneath:

    source/networking/enet/core/src/mod/mdio_manual_ioctl.c

    source/networking/enet/core/src/mod/mdio.c

    source/networking/enet/core/src/mod/mdio_ioctl.c

  • s there any reference codes that can be used for controlling KSZ9893RNXI-TR IC with AM2634 controller ?

    Unfortunately, we do not have such a reference implementation. I would like to understand the motivation for SPI-based PHY, was it cost?

  • Hi Nilabh,

    Below is the schematic for the custom IC PHY switch ( KSZ9893RNXI-TR ) used in our custom card-


     

    This is how i have planned to implement the ethernet-


    1. There are dedicated pins ( 47, 48, 49, 50) for SPI in our custom IC, which will be used for configuration of PHY ( configuring through MDIO pins needs to be skipped).

    2. MAC layer implementation need to kept similar to that of AM2634 and minimal modification need to be done to synchronize PHY and MAC layer.

    3. Please suggest the best SDK example file which can be used with minimal modification.

    4. Also explain what are modification need to be made, it would be helpful if you can share some reference for the same.

    Thanks and regards.

  • Hi Tej,

    Unfortunately, there isn't a simple way to get around this implementation since you are trying to decouple the MDIO with SPI SPI-based interface; you will need to implement a SPI-to-MDIO translation layer on your own, we do noyt have experience with implementing such a design before.

    the phy and mac layer synchronization layer happens via mdio layer. You will need to modify the above-mentioned file.

    As we do not have any solution with SPI controlled ethernet phy we do not have any reference implementation.

  • Hi Nilabh,

    As we do not have any solution with SPI controlled ethernet phy we do not have any reference implementation.

    Thanks for clarification.

    Actuall i was trying to setup the MAC layer and facing some problem-

    1. Our custom designed board don't have eeprom so i planned to set static MAC address instead of reading MAC values from eeprom with I2C protocol.

    2. I removed the eeprom and i2c that read eeprom from sysconfig.  Below is automatically generated "ti_board_config.c" file after project build.


    /*
     *  Copyright (C) 2021 Texas Instruments Incorporated
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    /*
     * Auto generated file
     */
    #include "ti_board_config.h"
    
    /*
     * Auto generated file
     */
    
    
    /* ========================================================================== */
    /*                             Include Files                                  */
    /* ========================================================================== */
    
    #include <stdint.h>
    #include <enet.h>
    #include <networking/enet/core/include/phy/enetphy.h>
    #include <networking/enet/core/include/phy/dp83869.h>
    #include <networking/enet/utils/include/enet_apputils.h>
    #include <networking/enet/utils/include/enet_appboardutils.h>
    #include <drivers/hw_include/cslr_soc.h>
    #include <networking/enet/core/src/phy/enetphy_priv.h>
    #include "ti_board_open_close.h"
    #include <kernel/dpl/AddrTranslateP.h>
    
    #define CONFIG_ENET_CPSW0_PHY0_ADDR (0U)
    #define CONFIG_ENET_CPSW0_PHY1_ADDR (3U)
    
    #include <ti_drivers_config.h>
    #include <drivers/i2c.h>
    
    #define IO_EXPANDER_PORT0_OUTPUT_REG (0x02U)
    #define IO_EXPANDER_PORT0_DIR_REG (0x06U)
    #define IO_EXPANDER_I2C_ADDR (0x20U)
    
    static void EnetBoard_setMacPort2IOExpanderCfg(void);
    
    /* PHY drivers */
    extern EnetPhy_Drv gEnetPhyDrvGeneric;
    extern EnetPhy_Drv gEnetPhyDrvDp83822;
    extern EnetPhy_Drv gEnetPhyDrvDp83867;
    extern EnetPhy_Drv gEnetPhyDrvDp83869;
    extern EnetPhy_Drv gEnetPhyDrvVsc8514;
    
    /*! \brief All the registered PHY specific drivers. */
    static const EnetPhyDrv_Handle gEnetPhyDrvs[] =
    {
        &gEnetPhyDrvDp83869,   /* DP83869 */
        &gEnetPhyDrvGeneric,   /* Generic PHY - must be last */
    };
    
    const EnetPhy_DrvInfoTbl gEnetPhyDrvTbl =
    {
        .numHandles = ENET_ARRAYSIZE(gEnetPhyDrvs),
        .hPhyDrvList = gEnetPhyDrvs,
    };
    
    /* ========================================================================== */
    /*                           Macros & Typedefs                                */
    /* ========================================================================== */
    
    /**
       TPR:MSS_CTRL:CPSW_CONTROL
    
       Address offset    0x0000016C
       Physical address  0x0212016C
       Instance          MSS_CTRL
       CPSW_CONTROL_RGMII1_ID_MODE     16  Writing 1'b1 would disable the internal clock delays. And those delays need to be handled on board.
       CPSW_CONTROL_RMII_REF_CLK_OE_N  8   To select the rmii_ref_clk from PAD or from MSS_RCM. 0: clock will be from mss_rcm through IO internal loopback 1: will be from
       CPSW_CONTROL_PORT1_MODE_SEL     2:0 Port 1 Interface
                                             00 = GMII/MII
                                             01 = RMII
                                             10 = RGMII
                                             11 = Not Supported
    */
    
    #define MSS_CPSW_CONTROL_PORT_MODE_MII                                   (0x0U)
    #define MSS_CPSW_CONTROL_PORT_MODE_RMII                                  (0x1U)
    #define MSS_CPSW_CONTROL_PORT_MODE_RGMII                                 (0x2U)
    
    #define I2C_EEPROM_MAC_DATA_OFFSET                                        (0x3D)
    #define I2C_EEPROM_MAC_CTRL_OFFSET                                        (0x3B)
    
    #define ENET_BOARD_NUM_MACADDR_MAX                                        (3U)
    #define ENET_GET_NUM_MAC_ADDR(num) ((num>>3)+1)
    #define ENET_MAC_ADDR_VALIDATE_MASK (0x01U)
    /* ========================================================================== */
    /*                         Structure Declarations                             */
    /* ========================================================================== */
    
    /* None */
    
    /* ========================================================================== */
    /*                          Function Declarations                             */
    /* ========================================================================== */
    
    static const EnetBoard_PortCfg *EnetBoard_getPortCfg(const EnetBoard_EthPort *ethPort);
    
    static const EnetBoard_PortCfg *EnetBoard_findPortCfg(const EnetBoard_EthPort *ethPort,
                                                          const EnetBoard_PortCfg *ethPortCfgs,
                                                          uint32_t numEthPorts);
    
    static void EnetBoard_enableExternalMux();
    
    /* ========================================================================== */
    /*                            Global Variables                                */
    /* ========================================================================== */
    
    /*!
     * \brief Common Processor Board (CPB) board's DP83869 PHY configuration.
     */
    static const Dp83869_Cfg gEnetCpbBoard_dp83869PhyCfg =
    {
        .txClkShiftEn         = true,
        .rxClkShiftEn         = true,
        .txDelayInPs          = 500U,  /* Value in pecosec. Refer to DLL_RX_DELAY_CTRL_SL field in ANA_RGMII_DLL_CTRL register of DP83869 PHY datasheet */
        .rxDelayInPs          = 500U,  /* Value in pecosec. Refer to DLL_TX_DELAY_CTRL_SL field in ANA_RGMII_DLL_CTRL register of DP83869 PHY datasheet */
        .txFifoDepth          = 4U,
        .impedanceInMilliOhms = 35000,  /* 35 ohms */
        .idleCntThresh        = 4U,     /* Improves short cable performance */
        .gpio0Mode            = DP83869_GPIO0_LED3,
        .gpio1Mode            = DP83869_GPIO1_COL, /* Unused */
        .ledMode              =
        {
            DP83869_LED_LINKED,         /* Unused */
            DP83869_LED_LINKED_100BTX,
            DP83869_LED_RXTXACT,
            DP83869_LED_LINKED_1000BT,
        },
    };
    
    /*
     * AM263x board configuration.
     *
     * 1 x RGMII PHY connected to AM263x CPSW_3G MAC port.
     */
    static const EnetBoard_PortCfg gEnetCpbBoard_am263xEthPort[] =
    {
        {    /* "CPSW3G" */
            .enetType = ENET_CPSW_3G,
            .instId   = 0U,
            .macPort  = ENET_MAC_PORT_1,
            .mii      = { ENET_MAC_LAYER_GMII, ENET_MAC_SUBLAYER_REDUCED },
            .phyCfg   =
            {
                .phyAddr         = 0,
                .isStrapped      = false,
                .skipExtendedCfg = false,
                .extendedCfg     = &gEnetCpbBoard_dp83869PhyCfg,
                .extendedCfgSize = sizeof(gEnetCpbBoard_dp83869PhyCfg),
            },
            .flags    = 0U,
        },
        {    /* "CPSW3G" */
            .enetType = ENET_CPSW_3G,
            .instId   = 0U,
            .macPort  = ENET_MAC_PORT_2,
            .mii      = { ENET_MAC_LAYER_GMII, ENET_MAC_SUBLAYER_REDUCED },
            .phyCfg   =
            {
                .phyAddr         = 3,
                .isStrapped      = false,
                .skipExtendedCfg = false,
                .extendedCfg     = &gEnetCpbBoard_dp83869PhyCfg,
                .extendedCfgSize = sizeof(gEnetCpbBoard_dp83869PhyCfg),
            },
            .flags    = 0U,
        },
    };
    /*
     * AM263X dummy board used for MAC loopback setup.
     */
    static const EnetBoard_PortCfg gEnetLpbkBoard_am263xEthPort[] =
    {
        {    /* RGMII MAC loopback */
            .enetType = ENET_CPSW_3G,
            .instId   = 0U,
            .macPort  = ENET_MAC_PORT_1,
            .mii      = { ENET_MAC_LAYER_GMII, ENET_MAC_SUBLAYER_REDUCED },
            .phyCfg   =
            {
                .phyAddr = ENETPHY_INVALID_PHYADDR,
            },
            .flags    = 0U,
        },
        {    /* RMII MAC loopback */
            .enetType = ENET_CPSW_3G,
            .instId   = 0U,
            .macPort  = ENET_MAC_PORT_1,
            .mii      = { ENET_MAC_LAYER_MII, ENET_MAC_SUBLAYER_REDUCED },
            .phyCfg   =
            {
                .phyAddr = ENETPHY_INVALID_PHYADDR,
            },
            .flags    = 0U,
        },
        {    /* MII MAC loopback */
            .enetType = ENET_CPSW_3G,
            .instId   = 0U,
            .macPort  = ENET_MAC_PORT_1,
            .mii      = { ENET_MAC_LAYER_MII, ENET_MAC_SUBLAYER_STANDARD },
            .phyCfg   =
            {
                .phyAddr = ENETPHY_INVALID_PHYADDR,
            },
            .flags    = 0U,
        },
    };
    
    /* ========================================================================== */
    /*                          Function Definitions                              */
    /* ========================================================================== */
    
    const EnetBoard_PhyCfg *EnetBoard_getPhyCfg(const EnetBoard_EthPort *ethPort)
    {
        const EnetBoard_PortCfg *portCfg;
    
        portCfg = EnetBoard_getPortCfg(ethPort);
    
        return (portCfg != NULL) ? &portCfg->phyCfg : NULL;
    }
    
    static void EnetBoard_enableExternalMux()
    {
        /* Enable external MUXes, if any, as per the board design */
    }
    
    static const EnetBoard_PortCfg *EnetBoard_getPortCfg(const EnetBoard_EthPort *ethPort)
    {
        const EnetBoard_PortCfg *portCfg = NULL;
    
        if (ENET_NOT_ZERO(ethPort->boardId & ENETBOARD_CPB_ID))
        {
            portCfg = EnetBoard_findPortCfg(ethPort,
                                            gEnetCpbBoard_am263xEthPort,
                                            ENETPHY_ARRAYSIZE(gEnetCpbBoard_am263xEthPort));
        }
        if ((portCfg == NULL) &&
            ENET_NOT_ZERO(ethPort->boardId & ENETBOARD_LOOPBACK_ID))
        {
            portCfg = EnetBoard_findPortCfg(ethPort,
                                            gEnetLpbkBoard_am263xEthPort,
                                            ENETPHY_ARRAYSIZE(gEnetLpbkBoard_am263xEthPort));
        }
    
        return portCfg;
    }
    
    static const EnetBoard_PortCfg *EnetBoard_findPortCfg(const EnetBoard_EthPort *ethPort,
                                                          const EnetBoard_PortCfg *ethPortCfgs,
                                                          uint32_t numEthPorts)
    {
        const EnetBoard_PortCfg *ethPortCfg = NULL;
        bool found = false;
        uint32_t i;
    
        for (i = 0U; i < numEthPorts; i++)
        {
            ethPortCfg = &ethPortCfgs[i];
    
            if ((ethPortCfg->enetType == ethPort->enetType) &&
                (ethPortCfg->instId == ethPort->instId) &&
                (ethPortCfg->macPort == ethPort->macPort) &&
                (ethPortCfg->mii.layerType == ethPort->mii.layerType) &&
                (ethPortCfg->mii.sublayerType == ethPort->mii.sublayerType))
            {
                found = true;
                break;
            }
        }
    
        return found ? ethPortCfg : NULL;
    }
    
    void EnetBoard_getMiiConfig(EnetMacPort_Interface *mii)
    {
        mii->layerType      = ENET_MAC_LAYER_GMII;
        mii->variantType    = ENET_MAC_VARIANT_FORCED;
        mii->sublayerType   = ENET_MAC_SUBLAYER_REDUCED;
    
    }
    
    int32_t EnetBoard_setupPorts(EnetBoard_EthPort *ethPorts,
                                 uint32_t numEthPorts)
    {
        CSL_mss_ctrlRegs *mssCtrlRegs = (CSL_mss_ctrlRegs *)CSL_MSS_CTRL_U_BASE;
    
        DebugP_assert(numEthPorts == 1);
    
    
        EnetBoard_enableExternalMux();
    
        switch(ethPorts->macPort)
        {
            case ENET_MAC_PORT_1:
                CSL_FINS( mssCtrlRegs->CPSW_CONTROL,MSS_CTRL_CPSW_CONTROL_RGMII1_ID_MODE, 0U);
                CSL_FINS( mssCtrlRegs->CPSW_CONTROL,MSS_CTRL_CPSW_CONTROL_PORT1_MODE_SEL, MSS_CPSW_CONTROL_PORT_MODE_RGMII);
                break;
            case ENET_MAC_PORT_2:
                CSL_FINS( mssCtrlRegs->CPSW_CONTROL,MSS_CTRL_CPSW_CONTROL_RGMII2_ID_MODE, 0U);
                CSL_FINS( mssCtrlRegs->CPSW_CONTROL,MSS_CTRL_CPSW_CONTROL_PORT2_MODE_SEL, MSS_CPSW_CONTROL_PORT_MODE_RGMII);
                EnetBoard_setMacPort2IOExpanderCfg();
                break;
            default:
                DebugP_assert(false);
        }
    
        /* Nothing else to do */
        return ENET_SOK;
    }
    
    static void EnetBoard_setMacPort2IOExpanderCfg(void)
    {
        I2C_Transaction i2cTransaction;
        uint8_t buffer[2];
        int32_t status = -1;
    
        I2C_Transaction_init(&i2cTransaction);
        i2cTransaction.writeBuf     = buffer;
        i2cTransaction.writeCount   = 2U;
        i2cTransaction.targetAddress = IO_EXPANDER_I2C_ADDR;
    
        /* Configure MDIO sel pin */
        /* Set output to high */
        buffer[0] = IO_EXPANDER_PORT0_OUTPUT_REG + 1; /* Port 1 */
        buffer[1] = (0x01 << 4); /* Pin 4 */
        I2C_transfer(I2C_getHandle(CONFIG_I2C1), &i2cTransaction);
    
        /* set pin to output */
        buffer[0] = IO_EXPANDER_PORT0_DIR_REG + 1;
        buffer[1] = ~(0x1 << 4);
        status = I2C_transfer(I2C_getHandle(CONFIG_I2C1), &i2cTransaction);
        DebugP_assert(status == I2C_STS_SUCCESS);
    
        /* Configure RGMII2 sel pin */
        /* Set output to low */
        buffer[0] = IO_EXPANDER_PORT0_OUTPUT_REG + 0; /* Port 0 */
        buffer[1] = ~(0x03 << 2); /* Pin 2 & 3 */
        I2C_transfer(I2C_getHandle(CONFIG_I2C1), &i2cTransaction);
        /* set pin to output */
        buffer[0] = IO_EXPANDER_PORT0_DIR_REG + 0;
        buffer[1] = ~(0x3 << 2);
        status = I2C_transfer(I2C_getHandle(CONFIG_I2C1), &i2cTransaction);
        DebugP_assert(status == I2C_STS_SUCCESS);
    
    }
    
    void EnetBoard_getMacAddrList(uint8_t macAddr[][ENET_MAC_ADDR_LEN],
                                  uint32_t maxMacEntries,
                                  uint32_t *pAvailMacEntries)
    {
        int32_t status = ENET_SOK;
        uint32_t macAddrCnt;
        uint32_t i;
        uint8_t numMacMax;
        uint8_t macAddrBuf[ENET_BOARD_NUM_MACADDR_MAX * ENET_MAC_ADDR_LEN];
        uint8_t validNumMac = 0U;
    
        status = EEPROM_read(gEepromHandle[CONFIG_EEPROM0],  I2C_EEPROM_MAC_CTRL_OFFSET, &numMacMax, sizeof(uint8_t));
        EnetAppUtils_assert(status == ENET_SOK);
        EnetAppUtils_assert(ENET_GET_NUM_MAC_ADDR(numMacMax) <= ENET_BOARD_NUM_MACADDR_MAX);
        EnetAppUtils_assert(pAvailMacEntries != NULL);
    
        macAddrCnt = EnetUtils_min(ENET_GET_NUM_MAC_ADDR(numMacMax), maxMacEntries);
    
        status = EEPROM_read(gEepromHandle[CONFIG_EEPROM0], I2C_EEPROM_MAC_DATA_OFFSET, macAddrBuf, (macAddrCnt * ENET_MAC_ADDR_LEN) );
        EnetAppUtils_assert(status == ENET_SOK);
    
        /* Save only those required to meet the max number of MAC entries */
        /* Validating that the MAC addresses from the EEPROM are not MULTICAST addresses */
        for (i = 0U; i < macAddrCnt; i++)
        {
            if(!(macAddrBuf[i * ENET_MAC_ADDR_LEN] & ENET_MAC_ADDR_VALIDATE_MASK)){
                memcpy(macAddr[validNumMac], &macAddrBuf[i * ENET_MAC_ADDR_LEN], ENET_MAC_ADDR_LEN);
                validNumMac++;
            }
        }
    
        *pAvailMacEntries = validNumMac;
    
        if (macAddrCnt == 0U)
        {
            EnetAppUtils_print("EnetBoard_getMacAddrList Failed - IDK not present\n");
            EnetAppUtils_assert(false);
        }
    }
    
    /*
     * Get ethernet board id
     */
    uint32_t EnetBoard_getId(void)
    {
        return ENETBOARD_AM263X_EVM;
    }
    
    
    
    void Board_init(void)
    {
    }
    
    void Board_deinit(void)
    {
    }

    3. But the program is showing Assertion failed error at line 390, as there is no eeprom as of now so it cannot read that.

    4. I want to generate custom function which return static MAC address which will be alternate of "EnetBoard_getMacAddrList".

    5. In simple word "Can you please tell how to assign static MAC address for am2634 custom board without eeprom

    Thanks and regards

  • For static mac address, please modify the function to hard code the mac address:

    • EnetBoard_getMacAddrList(): This function should populate any board specific MAC addresses that are available on board eeprom. 
  • Hi Nilabh,

    For static mac address, please modify the function to hard code the mac address:

    1. But the function "EnetBoard_getMacAddrList()" is inside "ti_board_config.c" file which is generated by sysconfig after each build, which cannot be hardcoded because after each build it will again get modified.

    2. Also if i make seprate file with same function name("EnetBoard_getMacAddrList()") there will be ambiguity if same function name is residing in two different file.

    3. So finally either EnetBoard_getMacAddrList function should be skipped from "ti_board_config.c"( if any setting in sysconfig for same is there please suggest) or if it is there it should assign static MAC without reading eeprom.

    thanks

  • Hi Tej,

    You can change the definition for the following function in the template file below:

    mcu_plus_sdk_am263x\source\networking\enet\core\sysconfig\networking\.meta\enet_cpsw\templates\am2613\enet_soc_cfg.c.xdt

    EnetSoc_getEFusedMacAddrs

    Here you can hard code your MAC address

    or

    You can change definitaion of the below function in the file:

    C:\ti\mcu_plus_sdk_am263x\source\networking\enet\core\sysconfig\board\.meta\ethphy_cpsw_icssg\templates\am263x\enet_board_cfg.c.xdt

    EnetBoard_getMacAddrList