288 lines
7.9 KiB
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
|