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.

DP83825I: Software Driver Support

Part Number: DP83825I

Tool/software:

I am writing software for a new board with the DP83825I connected an i.MX RT1175 running the lwip stack in a bare metal application.

Is there a recommended phy driver file to use as a base to create my own phy driver in the format required for my environment?

  • Example of a driver provided by the micro SDK for a different phy.

    /*
     * Copyright 2020-2023 NXP
     *
     * SPDX-License-Identifier: BSD-3-Clause
     */
    
    #include "fsl_phyksz8081.h"
    
    /*******************************************************************************
     * Definitions
     ******************************************************************************/
    
    /*! @brief Defines the PHY KSZ8081 vendor defined registers. */
    #define PHY_INTR_CONTROL_STATUS_REG (0x1BU) /*!< The PHY interrupt control/status register. */
    #define PHY_CONTROL1_REG            (0x1EU) /*!< The PHY control one register. */
    #define PHY_CONTROL2_REG            (0x1FU) /*!< The PHY control two register. */
    
    /*! @brief Defines the PHY KSZ8081 ID number. */
    #define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1 */
    
    /*! @brief Defines the mask flag of operation mode in interrupt control/status registers */
    #define PHY_INTR_CONTROL_STATUS_LINK_UP_MASK   ((uint16_t)0x0100U) /*!< The PHY link up interrupt mask. */
    #define PHY_INTR_CONTROL_STATUS_LINK_DOWN_MASK ((uint16_t)0x0400U) /*!< The PHY link down interrupt mask. */
    
    /*! @brief Defines the mask flag of operation mode in control registers */
    #define PHY_CTL2_REMOTELOOP_MASK    ((uint16_t)0x0004U) /*!< The PHY remote loopback mask. */
    #define PHY_CTL2_REFCLK_SELECT_MASK ((uint16_t)0x0080U) /*!< The PHY RMII reference clock select. */
    #define PHY_CTL2_INTR_LEVEL_MASK    ((uint16_t)0x0200U) /*!< The PHY interrupt level mask. */
    #define PHY_CTL1_10HALFDUPLEX_MASK  ((uint16_t)0x0001U) /*!< The PHY 10M half duplex mask. */
    #define PHY_CTL1_100HALFDUPLEX_MASK ((uint16_t)0x0002U) /*!< The PHY 100M half duplex mask. */
    #define PHY_CTL1_10FULLDUPLEX_MASK  ((uint16_t)0x0005U) /*!< The PHY 10M full duplex mask. */
    #define PHY_CTL1_100FULLDUPLEX_MASK ((uint16_t)0x0006U) /*!< The PHY 100M full duplex mask. */
    #define PHY_CTL1_SPEEDUPLX_MASK     ((uint16_t)0x0007U) /*!< The PHY speed and duplex mask. */
    #define PHY_CTL1_ENERGYDETECT_MASK  ((uint16_t)0x0010U) /*!< The PHY signal present on rx differential pair. */
    #define PHY_CTL1_LINKUP_MASK        ((uint16_t)0x0100U) /*!< The PHY link up. */
    #define PHY_LINK_READY_MASK         (PHY_CTL1_ENERGYDETECT_MASK | PHY_CTL1_LINKUP_MASK)
    
    /*! @brief Defines the timeout macro. */
    #define PHY_READID_TIMEOUT_COUNT (1000U)
    
    /*! @brief Defines the PHY resource interface. */
    #define PHY_KSZ8081_WRITE(handle, regAddr, data) \
        (((phy_ksz8081_resource_t *)(handle)->resource)->write((handle)->phyAddr, regAddr, data))
    #define PHY_KSZ8081_READ(handle, regAddr, pData) \
        (((phy_ksz8081_resource_t *)(handle)->resource)->read((handle)->phyAddr, regAddr, pData))
    
    /*******************************************************************************
     * Prototypes
     ******************************************************************************/
    
    /*******************************************************************************
     * Variables
     ******************************************************************************/
    const phy_operations_t phyksz8081_ops = {.phyInit             = PHY_KSZ8081_Init,
                                             .phyWrite            = PHY_KSZ8081_Write,
                                             .phyRead             = PHY_KSZ8081_Read,
                                             .getAutoNegoStatus   = PHY_KSZ8081_GetAutoNegotiationStatus,
                                             .getLinkStatus       = PHY_KSZ8081_GetLinkStatus,
                                             .getLinkSpeedDuplex  = PHY_KSZ8081_GetLinkSpeedDuplex,
                                             .setLinkSpeedDuplex  = PHY_KSZ8081_SetLinkSpeedDuplex,
                                             .enableLoopback      = PHY_KSZ8081_EnableLoopback,
                                             .enableLinkInterrupt = PHY_KSZ8081_EnableLinkInterrupt,
                                             .clearInterrupt      = PHY_KSZ8081_ClearInterrupt};
    
    /*******************************************************************************
     * Code
     ******************************************************************************/
    
    status_t PHY_KSZ8081_Init(phy_handle_t *handle, const phy_config_t *config)
    {
        uint32_t counter  = PHY_READID_TIMEOUT_COUNT;
        status_t result   = kStatus_Success;
        uint16_t regValue = 0;
    
        /* Assign PHY address and operation resource. */
        handle->phyAddr  = config->phyAddr;
        handle->resource = config->resource;
    
        /* Check PHY ID. */
        do
        {
            result = PHY_KSZ8081_READ(handle, PHY_ID1_REG, &regValue);
            if (result != kStatus_Success)
            {
                return result;
            }
            counter--;
        } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
    
        if (counter == 0U)
        {
            return kStatus_Fail;
        }
    
        /* Reset PHY. */
        result = PHY_KSZ8081_WRITE(handle, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
        if (result == kStatus_Success)
        {
    #if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE)
            result = PHY_KSZ8081_READ(handle, PHY_CONTROL2_REG, &regValue);
            if (result != kStatus_Success)
            {
                return result;
            }
            result = PHY_KSZ8081_WRITE(handle, PHY_CONTROL2_REG, (regValue | PHY_CTL2_REFCLK_SELECT_MASK));
            if (result != kStatus_Success)
            {
                return result;
            }
    #endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */
    
            if (config->autoNeg)
            {
                /* Set the auto-negotiation then start it. */
                result = PHY_KSZ8081_WRITE(
                    handle, PHY_AUTONEG_ADVERTISE_REG,
                    (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | PHY_10BASETX_FULLDUPLEX_MASK |
                     PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK));
                if (result == kStatus_Success)
                {
                    result = PHY_KSZ8081_WRITE(handle, PHY_BASICCONTROL_REG,
                                               (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
                }
            }
            else
            {
                /* This PHY only supports 10/100M speed. */
                assert(config->speed <= kPHY_Speed100M);
    
                /* Disable isolate mode */
                result = PHY_KSZ8081_READ(handle, PHY_BASICCONTROL_REG, &regValue);
                if (result != kStatus_Success)
                {
                    return result;
                }
                regValue &= ~PHY_BCTL_ISOLATE_MASK;
                result = PHY_KSZ8081_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
                if (result != kStatus_Success)
                {
                    return result;
                }
    
                /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
                result = PHY_KSZ8081_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
            }
            if (result != kStatus_Success)
            {
                return result;
            }
    
            /* Set PHY link status management interrupt. */
            result = PHY_KSZ8081_EnableLinkInterrupt(handle, config->intrType);
        }
        return result;
    }
    
    status_t PHY_KSZ8081_Write(phy_handle_t *handle, uint8_t phyReg, uint16_t data)
    {
        return PHY_KSZ8081_WRITE(handle, phyReg, data);
    }
    
    status_t PHY_KSZ8081_Read(phy_handle_t *handle, uint8_t phyReg, uint16_t *pData)
    {
        return PHY_KSZ8081_READ(handle, phyReg, pData);
    }
    
    status_t PHY_KSZ8081_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status)
    {
        assert(status);
    
        status_t result;
        uint16_t regValue;
    
        *status = false;
    
        /* Check auto negotiation complete. */
        result = PHY_KSZ8081_READ(handle, PHY_BASICSTATUS_REG, &regValue);
        if (result == kStatus_Success)
        {
            if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U)
            {
                *status = true;
            }
        }
        return result;
    }
    
    status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status)
    {
        assert(status);
    
        status_t result;
        uint16_t regValue;
    
        /* Read the basic status register. */
        result = PHY_KSZ8081_READ(handle, PHY_BASICSTATUS_REG, &regValue);
        if (result == kStatus_Success)
        {
            if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U)
            {
                /* Link up. */
                *status = true;
            }
            else
            {
                /* Link down. */
                *status = false;
            }
        }
        return result;
    }
    
    status_t PHY_KSZ8081_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex)
    {
        assert(!((speed == NULL) && (duplex == NULL)));
    
        status_t result;
        uint16_t regValue;
        uint16_t flag;
    
        /* Read the control register. */
        result = PHY_KSZ8081_READ(handle, PHY_CONTROL1_REG, &regValue);
        if (result == kStatus_Success)
        {
            if (speed != NULL)
            {
                flag = regValue & PHY_CTL1_SPEEDUPLX_MASK;
                if ((PHY_CTL1_100HALFDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag))
                {
                    *speed = kPHY_Speed100M;
                }
                else
                {
                    *speed = kPHY_Speed10M;
                }
            }
    
            if (duplex != NULL)
            {
                flag = regValue & PHY_CTL1_SPEEDUPLX_MASK;
                if ((PHY_CTL1_10FULLDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag))
                {
                    *duplex = kPHY_FullDuplex;
                }
                else
                {
                    *duplex = kPHY_HalfDuplex;
                }
            }
        }
        return result;
    }
    
    status_t PHY_KSZ8081_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex)
    {
        /* This PHY only supports 10/100M speed. */
        assert(speed <= kPHY_Speed100M);
    
        status_t result;
        uint16_t regValue;
    
        result = PHY_KSZ8081_READ(handle, PHY_BASICCONTROL_REG, &regValue);
        if (result == kStatus_Success)
        {
            /* Disable the auto-negotiation and set according to user-defined configuration. */
            regValue &= ~PHY_BCTL_AUTONEG_MASK;
            if (speed == kPHY_Speed100M)
            {
                regValue |= PHY_BCTL_SPEED0_MASK;
            }
            else
            {
                regValue &= ~PHY_BCTL_SPEED0_MASK;
            }
            if (duplex == kPHY_FullDuplex)
            {
                regValue |= PHY_BCTL_DUPLEX_MASK;
            }
            else
            {
                regValue &= ~PHY_BCTL_DUPLEX_MASK;
            }
            result = PHY_KSZ8081_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
        }
        return result;
    }
    
    status_t PHY_KSZ8081_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable)
    {
        /* This PHY only supports local/remote loopback and 10/100M speed. */
        assert(mode <= kPHY_RemoteLoop);
        assert(speed <= kPHY_Speed100M);
    
        status_t result;
        uint16_t regValue;
    
        /* Set the loop mode. */
        if (enable)
        {
            if (mode == kPHY_LocalLoop)
            {
                if (speed == kPHY_Speed100M)
                {
                    regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
                }
                else
                {
                    regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
                }
                return PHY_KSZ8081_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
            }
            else
            {
                /* Remote loopback only supports 100M full-duplex. */
                assert(speed == kPHY_Speed100M);
    
                regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
                result   = PHY_KSZ8081_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
                if (result != kStatus_Success)
                {
                    return result;
                }
                /* Set the remote loopback bit. */
                result = PHY_KSZ8081_READ(handle, PHY_CONTROL2_REG, &regValue);
                if (result == kStatus_Success)
                {
                    return PHY_KSZ8081_WRITE(handle, PHY_CONTROL2_REG, (regValue | PHY_CTL2_REMOTELOOP_MASK));
                }
            }
        }
        else
        {
            /* Disable the loop mode. */
            if (mode == kPHY_LocalLoop)
            {
                /* First read the current status in control register. */
                result = PHY_KSZ8081_READ(handle, PHY_BASICCONTROL_REG, &regValue);
                if (result == kStatus_Success)
                {
                    regValue &= ~PHY_BCTL_LOOP_MASK;
                    return PHY_KSZ8081_WRITE(handle, PHY_BASICCONTROL_REG, (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
                }
            }
            else
            {
                /* First read the current status in control one register. */
                result = PHY_KSZ8081_READ(handle, PHY_CONTROL2_REG, &regValue);
                if (result == kStatus_Success)
                {
                    return PHY_KSZ8081_WRITE(handle, PHY_CONTROL2_REG, regValue & ~PHY_CTL2_REMOTELOOP_MASK);
                }
            }
        }
        return result;
    }
    
    status_t PHY_KSZ8081_EnableLinkInterrupt(phy_handle_t *handle, phy_interrupt_type_t type)
    {
        status_t result;
        uint16_t regValue;
    
        /* Read operation will clear pending interrupt before enable interrupt. */
        result = PHY_KSZ8081_READ(handle, PHY_INTR_CONTROL_STATUS_REG, &regValue);
        if (result == kStatus_Success)
        {
            /* Enable/Disable link up+down interrupt. */
            if (type != kPHY_IntrDisable)
            {
                regValue |= (PHY_INTR_CONTROL_STATUS_LINK_UP_MASK | PHY_INTR_CONTROL_STATUS_LINK_DOWN_MASK);
            }
            else
            {
                regValue &= ~(PHY_INTR_CONTROL_STATUS_LINK_UP_MASK | PHY_INTR_CONTROL_STATUS_LINK_DOWN_MASK);
            }
            result = PHY_KSZ8081_WRITE(handle, PHY_INTR_CONTROL_STATUS_REG, regValue);
        }
        if (result != kStatus_Success)
        {
            return result;
        }
    
        if (type != kPHY_IntrDisable)
        {
            /* Set link interrupt type. */
            result = PHY_KSZ8081_READ(handle, PHY_CONTROL2_REG, &regValue);
            if (result == kStatus_Success)
            {
                if (type == kPHY_IntrActiveLow)
                {
                    regValue &= ~PHY_CTL2_INTR_LEVEL_MASK;
                }
                else
                {
                    regValue |= PHY_CTL2_INTR_LEVEL_MASK;
                }
                result = PHY_KSZ8081_WRITE(handle, PHY_CONTROL2_REG, regValue);
            }
        }
    
        return result;
    }
    
    status_t PHY_KSZ8081_ClearInterrupt(phy_handle_t *handle)
    {
        uint16_t regValue;
    
        return PHY_KSZ8081_READ(handle, PHY_INTR_CONTROL_STATUS_REG, &regValue);
    }
    

  • Hi Mitch,

    Please refer to our DP83822 RTOS driver found here as a reference:

    https://github.com/TexasInstruments/ti-ethernet-software/tree/main/rtos_drivers

    src/dp83822.c

    src/dp83822_priv.h

    include/dp83822.h

    Thank you,

    Evan