BaseType_t xPhyStartAutoNegotiation()

in portable/NetworkInterface/Common/phyHandling.c [537:724]


BaseType_t xPhyStartAutoNegotiation( EthernetPhy_t * pxPhyObject,
                                     uint32_t ulPhyMask )
{
    uint32_t xPhyIndex, ulDoneMask, ulBitMask;
    uint32_t ulPHYLinkStatus, ulRegValue;
    TickType_t xRemainingTime;
    TimeOut_t xTimer;

    if( ulPhyMask == ( uint32_t ) 0U )
    {
        return 0;
    }

    for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++ )
    {
        if( ( ulPhyMask & ( 1lu << xPhyIndex ) ) != 0lu )
        {
            BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];

            /* Enable Auto-Negotiation. */
            pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, pxPhyObject->ulACRValue );
            pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue | phyBMCR_AN_RESTART );
        }
    }

    xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( phyPHY_MAX_NEGOTIATE_TIME_MS );
    vTaskSetTimeOutState( &xTimer );
    ulDoneMask = 0;

    /* Wait until the auto-negotiation will be completed */
    for( ; ; )
    {
        ulBitMask = ( uint32_t ) 1U;

        for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
        {
            if( ( ulPhyMask & ulBitMask ) != 0lu )
            {
                if( ( ulDoneMask & ulBitMask ) == 0lu )
                {
                    BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];

                    pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue );

                    if( ( ulRegValue & phyBMSR_AN_COMPLETE ) != 0 )
                    {
                        ulDoneMask |= ulBitMask;
                    }
                }
            }
        }

        if( ulPhyMask == ulDoneMask )
        {
            break;
        }

        if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE )
        {
            FreeRTOS_printf( ( "xPhyStartAutoNegotiation: phyBMSR_AN_COMPLETE timed out ( done 0x%02lX )\n", ulDoneMask ) );
            break;
        }

        vTaskDelay( pdMS_TO_TICKS( phySHORT_DELAY_MS ) );
    }

    if( ulDoneMask != ( uint32_t ) 0U )
    {
        ulBitMask = ( uint32_t ) 1U;
        pxPhyObject->ulLinkStatusMask &= ~( ulDoneMask );

        for( xPhyIndex = 0; xPhyIndex < ( uint32_t ) pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 )
        {
            BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ];
            uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ];

            if( ( ulDoneMask & ulBitMask ) == ( uint32_t ) 0U )
            {
                continue;
            }

            /* Clear the 'phyBMCR_AN_RESTART'  bit. */
            pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue );

            pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue );

            if( ( ulRegValue & phyBMSR_LINK_STATUS ) != 0 )
            {
                ulPHYLinkStatus |= phyBMSR_LINK_STATUS;
                pxPhyObject->ulLinkStatusMask |= ulBitMask;
            }
            else
            {
                ulPHYLinkStatus &= ~( phyBMSR_LINK_STATUS );
            }

            if( ulPhyID == PHY_ID_KSZ8081MNXIA )
            {
                uint32_t ulControlStatus;

                pxPhyObject->fnPhyRead( xPhyAddress, 0x1E, &ulControlStatus );

                switch( ulControlStatus & 0x07 )
                {
                    case 0x01:
                    case 0x05:
/*	[001] = 10BASE-T half-duplex */
/*	[101] = 10BASE-T full-duplex */
                        /* 10 Mbps. */
                        ulRegValue |= phyPHYSTS_SPEED_STATUS;
                        break;

                    case 0x02:
                    case 0x06:
/*	[010] = 100BASE-TX half-duplex */
/*	[110] = 100BASE-TX full-duplex */
                        break;
                }

                switch( ulControlStatus & 0x07 )
                {
                    case 0x05:
                    case 0x06:
/*	[101] = 10BASE-T full-duplex */
/*	[110] = 100BASE-TX full-duplex */
                        /* Full duplex. */
                        ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
                        break;

                    case 0x01:
                    case 0x02:
/*	[001] = 10BASE-T half-duplex */
/*	[010] = 100BASE-TX half-duplex */
                        break;
                }
            }
            else if( xHas_1F_PHYSPCS( ulPhyID ) )
            {
                /* 31 RW PHY Special Control Status */
                uint32_t ulControlStatus;

                pxPhyObject->fnPhyRead( xPhyAddress, phyREG_1F_PHYSPCS, &ulControlStatus );
                ulRegValue = 0;

                if( ( ulControlStatus & phyPHYSPCS_FULL_DUPLEX ) != 0 )
                {
                    ulRegValue |= phyPHYSTS_DUPLEX_STATUS;
                }

                if( ( ulControlStatus & phyPHYSPCS_SPEED_MASK ) == phyPHYSPCS_SPEED_10 )
                {
                    ulRegValue |= phyPHYSTS_SPEED_STATUS;
                }
            }
            else
            {
                /* Read the result of the auto-negotiation. */
                pxPhyObject->fnPhyRead( xPhyAddress, PHYREG_10_PHYSTS, &ulRegValue );
            }

            FreeRTOS_printf( ( "Autonego ready: %08lx: %s duplex %u mbit %s status\n",
                               ulRegValue,
                               ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) ? "full" : "half",
                               ( ulRegValue & phyPHYSTS_SPEED_STATUS ) ? 10 : 100,
                               ( ( ulPHYLinkStatus |= phyBMSR_LINK_STATUS ) != 0 ) ? "high" : "low" ) );

            if( ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) != ( uint32_t ) 0U )
            {
                pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_FULL;
            }
            else
            {
                pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_HALF;
            }

            if( ( ulRegValue & phyPHYSTS_SPEED_STATUS ) != 0 )
            {
                pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_10;
            }
            else
            {
                pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_100;
            }
        }
    } /* if( ulDoneMask != ( uint32_t) 0U ) */

    return 0;
}