openmv/lib/alif/components/Source/driver_phy.c
iabdalkader daf2bb30da misc: Restructure repo.
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
2025-04-13 08:28:34 +02:00

269 lines
6.6 KiB
C

/* Copyright (C) 2022 Alif Semiconductor - All Rights Reserved.
* Use, distribution and modification of this code is permitted under the
* terms stated in the Alif Semiconductor Software License Agreement
*
* You should have received a copy of the Alif Semiconductor Software
* License Agreement with this file. If not, please write to:
* contact@alifsemi.com, or visit: https://alifsemi.com/license
*
*/
/**************************************************************************//**
* @file driver_phy.c
* @author Silesh C V
* @email silesh@alifsemi.com
* @version V1.0.0
* @date 22-Mar-2022
* @brief CMSIS driver for ETH PHY.
* @bug None.
* @Note None
******************************************************************************/
#include "driver_phy.h"
#define ARM_ETH_PHY_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,0) /* driver version */
#ifndef ETH_PHY_NUM
#define ETH_PHY_NUM 0 /* Default driver number */
#endif
#ifndef ETH_PHY_ADDR
#define ETH_PHY_ADDR 0x01 /* Default device address */
#endif
/* Driver Version */
static const ARM_DRIVER_VERSION DriverVersion = {
ARM_ETH_PHY_API_VERSION,
ARM_ETH_PHY_DRV_VERSION
};
/* Ethernet PHY control structure */
static PHY_CTRL PHY = { NULL, NULL, 0, 0, 0 };
/**
\fn ARM_DRIVER_VERSION GetVersion (void)
\brief Get driver version.
\return \ref ARM_DRIVER_VERSION
*/
static ARM_DRIVER_VERSION GetVersion (void) {
return DriverVersion;
}
/**
\fn int32_t Initialize (ARM_ETH_PHY_Read_t fn_read,
ARM_ETH_PHY_Write_t fn_write)
\brief Initialize Ethernet PHY Device.
\param[in] fn_read Pointer to \ref ARM_ETH_MAC_PHY_Read
\param[in] fn_write Pointer to \ref ARM_ETH_MAC_PHY_Write
\return \ref execution_status
*/
static int32_t Initialize (ARM_ETH_PHY_Read_t fn_read, ARM_ETH_PHY_Write_t fn_write) {
if ((fn_read == NULL) || (fn_write == NULL)) { return ARM_DRIVER_ERROR_PARAMETER; }
if ((PHY.flags & PHY_INIT) == 0U) {
/* Register PHY read/write functions. */
PHY.reg_rd = fn_read;
PHY.reg_wr = fn_write;
PHY.bmcr = 0U;
PHY.flags = PHY_INIT;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t Uninitialize (void)
\brief De-initialize Ethernet PHY Device.
\return \ref execution_status
*/
static int32_t Uninitialize (void) {
PHY.reg_rd = NULL;
PHY.reg_wr = NULL;
PHY.bmcr = 0U;
PHY.flags = 0U;
return ARM_DRIVER_OK;
}
/**
\fn int32_t PowerControl (ARM_POWER_STATE state)
\brief Control Ethernet PHY Device Power.
\param[in] state Power state
\return \ref execution_status
*/
static int32_t PowerControl (ARM_POWER_STATE state) {
uint16_t val;
switch ((int32_t)state) {
case ARM_POWER_OFF:
if ((PHY.flags & PHY_INIT) == 0U) {
return ARM_DRIVER_ERROR;
}
PHY.flags &= ~PHY_POWER;
PHY.bmcr = BMCR_POWER_DOWN;
return (PHY.reg_wr(ETH_PHY_ADDR, REG_BMCR, PHY.bmcr));
case ARM_POWER_FULL:
if ((PHY.flags & PHY_INIT) == 0U) {
return ARM_DRIVER_ERROR;
}
if (PHY.flags & PHY_POWER) {
return ARM_DRIVER_OK;
}
/* Check Device Identification. */
PHY.reg_rd(ETH_PHY_ADDR, REG_PHYIDR1, &val);
if (val == 0x0 || val == 0xFFFF) {
/* A valid PHY ID cannot be all zeroes or all ones */
return ARM_DRIVER_ERROR;
}
PHY.bmcr = 0U;
if (PHY.reg_wr(ETH_PHY_ADDR, REG_BMCR, PHY.bmcr) != ARM_DRIVER_OK) {
return ARM_DRIVER_ERROR;
}
PHY.flags |= PHY_POWER;
return ARM_DRIVER_OK;
case ARM_POWER_LOW:
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
}
/**
\fn int32_t SetInterface (uint32_t interface)
\brief Set Ethernet Media Interface.
\param[in] interface Media Interface type
\return \ref execution_status
*/
static int32_t SetInterface (uint32_t interface) {
int32_t status;
if ((PHY.flags & PHY_POWER) == 0U) { return ARM_DRIVER_ERROR; }
/* This device only supports RMII interface */
switch (interface) {
case ARM_ETH_INTERFACE_RMII: status = ARM_DRIVER_OK; break;
default:
status = ARM_DRIVER_ERROR_UNSUPPORTED; break;
}
return (status);
}
/**
\fn int32_t SetMode (uint32_t mode)
\brief Set Ethernet PHY Device Operation mode.
\param[in] mode Operation Mode
\return \ref execution_status
*/
static int32_t SetMode (uint32_t mode) {
uint16_t val;
if ((PHY.flags & PHY_POWER) == 0U) { return ARM_DRIVER_ERROR; }
val = PHY.bmcr & BMCR_POWER_DOWN;
switch (mode & ARM_ETH_PHY_SPEED_Msk) {
case ARM_ETH_PHY_SPEED_10M:
break;
case ARM_ETH_PHY_SPEED_100M:
val |= BMCR_SPEED_SELECT;
break;
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
switch (mode & ARM_ETH_PHY_DUPLEX_Msk) {
case ARM_ETH_PHY_DUPLEX_HALF:
break;
case ARM_ETH_PHY_DUPLEX_FULL:
val |= BMCR_DUPLEX_MODE;
break;
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
if (mode & ARM_ETH_PHY_AUTO_NEGOTIATE) {
val |= BMCR_ANEG_EN | BMCR_RESTART_ANEG;
}
if (mode & ARM_ETH_PHY_LOOPBACK) {
val |= BMCR_LOOPBACK;
}
if (mode & ARM_ETH_PHY_ISOLATE) {
val |= BMCR_ISOLATE;
}
PHY.bmcr = val;
return (PHY.reg_wr(ETH_PHY_ADDR, REG_BMCR, PHY.bmcr));
}
/**
\fn ARM_ETH_LINK_STATE GetLinkState (void)
\brief Get Ethernet PHY Device Link state.
\return current link status \ref ARM_ETH_LINK_STATE
*/
static ARM_ETH_LINK_STATE GetLinkState (void) {
ARM_ETH_LINK_STATE state;
uint16_t val = 0U;
if (PHY.flags & PHY_POWER) {
PHY.reg_rd(ETH_PHY_ADDR, REG_BMSR, &val);
}
state = (val & BMSR_LINK_STAT) ? ARM_ETH_LINK_UP : ARM_ETH_LINK_DOWN;
return (state);
}
/**
\fn ARM_ETH_LINK_INFO GetLinkInfo (void)
\brief Get Ethernet PHY Device Link information.
\return current link parameters \ref ARM_ETH_LINK_INFO
*/
static ARM_ETH_LINK_INFO GetLinkInfo (void) {
ARM_ETH_LINK_INFO info;
uint16_t val = 0U;
if (PHY.flags & PHY_POWER) {
/* Get operation mode indication from the control register */
PHY.reg_rd(ETH_PHY_ADDR, REG_BMCR, &val);
}
/* Link must be up to get valid state */
info.speed = (val & BMCR_SPEED_SELECT) ? ARM_ETH_SPEED_100M : ARM_ETH_SPEED_10M;
info.duplex = (val & BMCR_DUPLEX_MODE) ? ARM_ETH_DUPLEX_FULL : ARM_ETH_DUPLEX_HALF;
return (info);
}
/* PHY Driver Control Block */
extern
ARM_DRIVER_ETH_PHY ARM_Driver_ETH_PHY_(ETH_PHY_NUM);
ARM_DRIVER_ETH_PHY ARM_Driver_ETH_PHY_(ETH_PHY_NUM) = {
GetVersion,
Initialize,
Uninitialize,
PowerControl,
SetInterface,
SetMode,
GetLinkState,
GetLinkInfo
};