mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
269 lines
6.6 KiB
C
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
|
|
};
|