MCUXpresso_MIMXRT1052xxxxB/devices/MIMXRT1052/cmsis_drivers/fsl_enet_phy_cmsis.c

288 lines
7.9 KiB
C

/*
* Copyright (c) 2013-2016 ARM Limited. All rights reserved.
* Copyright (c) 2016, Freescale Semiconductor, Inc. Not a Contribution.
* Copyright 2016-2022 NXP. Not a Contribution.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fsl_enet_phy_cmsis.h"
#include "fsl_enet.h"
#define ARM_ETH_PHY_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(2, 1)
#ifndef PHY_AUTONEGO_DELAY_COUNT
#define PHY_AUTONEGO_DELAY_COUNT (800000U)
#endif
typedef struct _cmsis_enet_phy_state
{
cmsis_enet_phy_resource_t *resource; /*!< Basic enet resource. */
uint32_t cmsis_enet_phy_mode; /*!< ENET MII interface work mode. */
} cmsis_enet_phy_state_t;
static const ARM_DRIVER_VERSION s_phyDriverVersion = {ARM_ETH_PHY_API_VERSION, ARM_ETH_PHY_DRV_VERSION};
static ARM_DRIVER_VERSION PHYx_GetVersion(void)
{
return s_phyDriverVersion;
}
static int32_t PHY_SetForcedSpeedDuplexMode(cmsis_enet_phy_state_t *ethPhy, uint32_t mode)
{
int32_t result;
uint16_t bsctlReg;
/* Reset PHY. */
result = PHY_Write(&phyHandle, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
if (result == kStatus_Success)
{
/* Set with the forced speed and duplex. */
result = PHY_Read(&phyHandle, PHY_BASICCONTROL_REG, &bsctlReg);
if (result == kStatus_Success)
{
/* Build the control value. */
bsctlReg &= ~(PHY_BCTL_DUPLEX_MASK | PHY_BCTL_SPEED0_MASK | PHY_BCTL_AUTONEG_MASK);
if (mode == (uint32_t)ARM_ETH_PHY_DUPLEX_FULL)
{
bsctlReg |= PHY_BCTL_DUPLEX_MASK;
}
if (mode == (uint32_t)ARM_ETH_PHY_SPEED_100M)
{
bsctlReg |= PHY_BCTL_SPEED0_MASK;
}
result = PHY_Write(&phyHandle, PHY_BASICCONTROL_REG, bsctlReg);
}
}
return result;
}
static void PHY_SetPowerDown(cmsis_enet_phy_resource_t *enet, bool down)
{
uint16_t data;
if (down)
{
(void)PHY_Read(&phyHandle, PHY_BASICCONTROL_REG, &data);
data |= (uint16_t)(1UL << 11);
(void)PHY_Write(&phyHandle, PHY_BASICCONTROL_REG, data);
}
else
{
(void)PHY_Read(&phyHandle, PHY_BASICCONTROL_REG, &data);
data &= ~(uint16_t)(1UL << 11);
(void)PHY_Write(&phyHandle, PHY_BASICCONTROL_REG, data);
(void)PHY_Read(&phyHandle, PHY_BASICCONTROL_REG, &data);
}
}
#if RTE_ENET
extern cmsis_enet_phy_resource_t ENETPHY0_Resource;
static cmsis_enet_phy_state_t ENETPHY0_State = {&ENETPHY0_Resource, ARM_ETH_PHY_AUTO_NEGOTIATE};
static int32_t PHY0_Initialize(ARM_ETH_PHY_Read_t fn_read, ARM_ETH_PHY_Write_t fn_write)
{
return ARM_DRIVER_OK;
}
static int32_t PHY0_UnInitialize(void)
{
return ARM_DRIVER_OK;
}
static int32_t PHY0_PowerControl(ARM_POWER_STATE state)
{
int32_t status;
phy_config_t phyConfig = {0};
bool autonego = false;
uint32_t count;
switch (state)
{
case ARM_POWER_FULL:
{
phyConfig.phyAddr = ENETPHY0_State.resource->phyAddr;
phyConfig.ops = ENETPHY0_State.resource->ops;
phyConfig.resource = ENETPHY0_State.resource->opsResource;
phyConfig.autoNeg = true;
status = PHY_Init(&phyHandle, &phyConfig);
if (status == kStatus_Success)
{
count = PHY_AUTONEGO_DELAY_COUNT;
do
{
(void)PHY_GetAutoNegotiationStatus(&phyHandle, &autonego);
if (autonego)
{
break;
}
} while (--count != 0U);
}
if (autonego)
{
status = ARM_DRIVER_OK;
}
else
{
status = ARM_DRIVER_ERROR;
}
}
break;
case ARM_POWER_OFF:
{
PHY_SetPowerDown(ENETPHY0_State.resource, true);
status = ARM_DRIVER_OK;
}
break;
default:
status = ARM_DRIVER_ERROR_UNSUPPORTED;
break;
}
return status;
}
static int32_t PHY0_SetInterface(uint32_t interface)
{
int32_t status = ARM_DRIVER_OK;
/* The interface for PHY is fixed or controlled by JUMPER setting.
* The interface setting for MAC is defined by "RTE_ENET_RMII/RTE_ENET_MII"
*/
if (interface == (uint32_t)ARM_ETH_INTERFACE_SMII)
{
status = ARM_DRIVER_ERROR_UNSUPPORTED;
}
return status;
}
static int32_t PHY0_SetMode(uint32_t mode)
{
int32_t status = ARM_DRIVER_OK;
phy_config_t phyConfig = {0};
bool autonego = false;
uint32_t count;
/*!< Check input mode. */
if ((mode == (uint32_t)ARM_ETH_PHY_SPEED_1G) || (mode == ARM_ETH_PHY_ISOLATE))
{
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
if (mode == ARM_ETH_PHY_LOOPBACK)
{
status = PHY_EnableLoopback(&phyHandle, kPHY_RemoteLoop, kPHY_Speed100M, true);
}
else if (mode == ARM_ETH_PHY_AUTO_NEGOTIATE)
{
phyConfig.phyAddr = ENETPHY0_State.resource->phyAddr;
phyConfig.ops = ENETPHY0_State.resource->ops;
phyConfig.resource = &ENETPHY0_State.resource->opsResource;
phyConfig.autoNeg = true;
status = PHY_Init(&phyHandle, &phyConfig);
if (status == kStatus_Success)
{
count = PHY_AUTONEGO_DELAY_COUNT;
do
{
(void)PHY_GetAutoNegotiationStatus(&phyHandle, &autonego);
if (autonego)
{
break;
}
} while (--count != 0U);
if (!autonego)
{
status = kStatus_Fail;
}
}
}
else
{
status = PHY_SetForcedSpeedDuplexMode(&ENETPHY0_State, mode);
}
ENETPHY0_State.cmsis_enet_phy_mode = mode;
/* Convert to CMSIS status */
if (status == kStatus_Success)
{
status = ARM_DRIVER_OK;
}
else
{
status = ARM_DRIVER_ERROR;
}
return status;
}
static ARM_ETH_LINK_STATE PHY0_GetLinkState(void)
{
ARM_ETH_LINK_STATE state;
bool linkUp = false;
int32_t status;
status = PHY_GetLinkStatus(&phyHandle, &linkUp);
if ((status == kStatus_Success) && linkUp)
{
state = ARM_ETH_LINK_UP;
}
else
{
state = ARM_ETH_LINK_DOWN;
}
return state;
}
static ARM_ETH_LINK_INFO PHY0_GetLinkInfo(void)
{
ARM_ETH_LINK_INFO linkInfo = {0};
phy_speed_t speed;
phy_duplex_t duplex;
int32_t status;
status = PHY_GetLinkSpeedDuplex(&phyHandle, &speed, &duplex);
if (status == kStatus_Success)
{
if (speed == kPHY_Speed10M)
{
linkInfo.speed = ARM_ETH_SPEED_10M;
}
else if (speed == kPHY_Speed100M)
{
linkInfo.speed = ARM_ETH_SPEED_100M;
}
else
{
linkInfo.speed = ARM_ETH_SPEED_1G;
}
if (duplex == kPHY_FullDuplex)
{
linkInfo.duplex = ARM_ETH_DUPLEX_FULL;
}
else
{
linkInfo.duplex = ARM_ETH_DUPLEX_HALF;
}
}
return linkInfo;
}
ARM_DRIVER_ETH_PHY Driver_ETH_PHY0 = {PHYx_GetVersion, PHY0_Initialize, PHY0_UnInitialize, PHY0_PowerControl,
PHY0_SetInterface, PHY0_SetMode, PHY0_GetLinkState, PHY0_GetLinkInfo};
#endif