[Add] First commit
This commit is contained in:
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* @brief SMSC 87x0 simple PHY driver
|
||||
*
|
||||
* @note
|
||||
* Copyright(C) NXP Semiconductors, 2012
|
||||
* All rights reserved.
|
||||
*
|
||||
* @par
|
||||
* Software that is described herein is for illustrative purposes only
|
||||
* which provides customers with programming information regarding the
|
||||
* LPC products. This software is supplied "AS IS" without any warranties of
|
||||
* any kind, and NXP Semiconductors and its licensor disclaim any and
|
||||
* all warranties, express or implied, including all implied warranties of
|
||||
* merchantability, fitness for a particular purpose and non-infringement of
|
||||
* intellectual property rights. NXP Semiconductors assumes no responsibility
|
||||
* or liability for the use of the software, conveys no license or rights under any
|
||||
* patent, copyright, mask work right, or any other intellectual property rights in
|
||||
* or to any products. NXP Semiconductors reserves the right to make changes
|
||||
* in the software without notification. NXP Semiconductors also makes no
|
||||
* representation or warranty that such application will be suitable for the
|
||||
* specified use without further testing or modification.
|
||||
*
|
||||
* @par
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation is hereby granted, under NXP Semiconductors' and its
|
||||
* licensor's relevant copyrights in the software, without fee, provided that it
|
||||
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||||
* copyright, permission, and disclaimer notice must appear in all copies of
|
||||
* this code.
|
||||
*/
|
||||
|
||||
#include "chip.h"
|
||||
#include "lpc_phy.h"
|
||||
|
||||
/** @defgroup SMSC87X0_PHY BOARD: PHY status and control driver for the SMSC 87x0
|
||||
* @ingroup BOARD_PHY
|
||||
* Various functions for controlling and monitoring the status of the
|
||||
* SMSC 87x0 PHY.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* LAN8720 PHY register offsets */
|
||||
#define LAN8_BCR_REG 0x0 /*!< Basic Control Register */
|
||||
#define LAN8_BSR_REG 0x1 /*!< Basic Status Reg */
|
||||
#define LAN8_PHYID1_REG 0x2 /*!< PHY ID 1 Reg */
|
||||
#define LAN8_PHYID2_REG 0x3 /*!< PHY ID 2 Reg */
|
||||
#define LAN8_PHYSPLCTL_REG 0x1F/*!< PHY special control/status Reg */
|
||||
|
||||
/* LAN8720 BCR register definitions */
|
||||
#define LAN8_RESET (1 << 15) /*!< 1= S/W Reset */
|
||||
#define LAN8_LOOPBACK (1 << 14) /*!< 1=loopback Enabled */
|
||||
#define LAN8_SPEED_SELECT (1 << 13) /*!< 1=Select 100MBps */
|
||||
#define LAN8_AUTONEG (1 << 12) /*!< 1=Enable auto-negotiation */
|
||||
#define LAN8_POWER_DOWN (1 << 11) /*!< 1=Power down PHY */
|
||||
#define LAN8_ISOLATE (1 << 10) /*!< 1=Isolate PHY */
|
||||
#define LAN8_RESTART_AUTONEG (1 << 9) /*!< 1=Restart auto-negoatiation */
|
||||
#define LAN8_DUPLEX_MODE (1 << 8) /*!< 1=Full duplex mode */
|
||||
|
||||
/* LAN8720 BSR register definitions */
|
||||
#define LAN8_100BASE_T4 (1 << 15) /*!< T4 mode */
|
||||
#define LAN8_100BASE_TX_FD (1 << 14) /*!< 100MBps full duplex */
|
||||
#define LAN8_100BASE_TX_HD (1 << 13) /*!< 100MBps half duplex */
|
||||
#define LAN8_10BASE_T_FD (1 << 12) /*!< 100Bps full duplex */
|
||||
#define LAN8_10BASE_T_HD (1 << 11) /*!< 10MBps half duplex */
|
||||
#define LAN8_AUTONEG_COMP (1 << 5) /*!< Auto-negotation complete */
|
||||
#define LAN8_RMT_FAULT (1 << 4) /*!< Fault */
|
||||
#define LAN8_AUTONEG_ABILITY (1 << 3) /*!< Auto-negotation supported */
|
||||
#define LAN8_LINK_STATUS (1 << 2) /*!< 1=Link active */
|
||||
#define LAN8_JABBER_DETECT (1 << 1) /*!< Jabber detect */
|
||||
#define LAN8_EXTEND_CAPAB (1 << 0) /*!< Supports extended capabilities */
|
||||
|
||||
/* LAN8720 PHYSPLCTL status definitions */
|
||||
#define LAN8_SPEEDMASK (7 << 2) /*!< Speed and duplex mask */
|
||||
#define LAN8_SPEED100F (6 << 2) /*!< 100BT full duplex */
|
||||
#define LAN8_SPEED10F (5 << 2) /*!< 10BT full duplex */
|
||||
#define LAN8_SPEED100H (2 << 2) /*!< 100BT half duplex */
|
||||
#define LAN8_SPEED10H (1 << 2) /*!< 10BT half duplex */
|
||||
|
||||
/* LAN8720 PHY ID 1/2 register definitions */
|
||||
#define LAN8_PHYID1_OUI 0x0007 /*!< Expected PHY ID1 */
|
||||
#define LAN8_PHYID2_OUI 0xC0F0 /*!< Expected PHY ID2, except last 4 bits */
|
||||
|
||||
/* DP83848 PHY update flags */
|
||||
static uint32_t physts, olddphysts;
|
||||
|
||||
/* PHY update counter for state machine */
|
||||
static int32_t phyustate;
|
||||
|
||||
/* Pointer to delay function used for this driver */
|
||||
static p_msDelay_func_t pDelayMs;
|
||||
|
||||
/* Write to the PHY. Will block for delays based on the pDelayMs function. Returns
|
||||
true on success, or false on failure */
|
||||
static Status lpc_mii_write(uint8_t reg, uint16_t data)
|
||||
{
|
||||
Status sts = ERROR;
|
||||
int32_t mst = 250;
|
||||
|
||||
/* Write value for register */
|
||||
Chip_ENET_StartMIIWrite(LPC_ETHERNET, reg, data);
|
||||
|
||||
/* Wait for unbusy status */
|
||||
while (mst > 0) {
|
||||
if (Chip_ENET_IsMIIBusy(LPC_ETHERNET)) {
|
||||
mst--;
|
||||
pDelayMs(1);
|
||||
}
|
||||
else {
|
||||
mst = 0;
|
||||
sts = SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
/* Read from the PHY. Will block for delays based on the pDelayMs function. Returns
|
||||
true on success, or false on failure */
|
||||
static Status lpc_mii_read(uint8_t reg, uint16_t *data)
|
||||
{
|
||||
Status sts = ERROR;
|
||||
int32_t mst = 250;
|
||||
|
||||
/* Start register read */
|
||||
Chip_ENET_StartMIIRead(LPC_ETHERNET, reg);
|
||||
|
||||
/* Wait for unbusy status */
|
||||
while (mst > 0) {
|
||||
if (!Chip_ENET_IsMIIBusy(LPC_ETHERNET)) {
|
||||
mst = 0;
|
||||
*data = Chip_ENET_ReadMIIData(LPC_ETHERNET);
|
||||
sts = SUCCESS;
|
||||
}
|
||||
else {
|
||||
mst--;
|
||||
pDelayMs(1);
|
||||
}
|
||||
}
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
/* Update PHY status from passed value */
|
||||
static void smsc_update_phy_sts(uint16_t linksts, uint16_t sdsts)
|
||||
{
|
||||
/* Update link active status */
|
||||
if (linksts & LAN8_LINK_STATUS) {
|
||||
physts |= PHY_LINK_CONNECTED;
|
||||
}
|
||||
else {
|
||||
physts &= ~PHY_LINK_CONNECTED;
|
||||
}
|
||||
|
||||
switch (sdsts & LAN8_SPEEDMASK) {
|
||||
case LAN8_SPEED100F:
|
||||
default:
|
||||
physts |= PHY_LINK_SPEED100;
|
||||
physts |= PHY_LINK_FULLDUPLX;
|
||||
break;
|
||||
|
||||
case LAN8_SPEED10F:
|
||||
physts &= ~PHY_LINK_SPEED100;
|
||||
physts |= PHY_LINK_FULLDUPLX;
|
||||
break;
|
||||
|
||||
case LAN8_SPEED100H:
|
||||
physts |= PHY_LINK_SPEED100;
|
||||
physts &= ~PHY_LINK_FULLDUPLX;
|
||||
break;
|
||||
|
||||
case LAN8_SPEED10H:
|
||||
physts &= ~PHY_LINK_SPEED100;
|
||||
physts &= ~PHY_LINK_FULLDUPLX;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the status has changed, indicate via change flag */
|
||||
if ((physts & (PHY_LINK_SPEED100 | PHY_LINK_FULLDUPLX | PHY_LINK_CONNECTED)) !=
|
||||
(olddphysts & (PHY_LINK_SPEED100 | PHY_LINK_FULLDUPLX | PHY_LINK_CONNECTED))) {
|
||||
olddphysts = physts;
|
||||
physts |= PHY_LINK_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the SMSC 87x0 PHY */
|
||||
uint32_t lpc_phy_init(bool rmii, p_msDelay_func_t pDelayMsFunc)
|
||||
{
|
||||
uint16_t tmp;
|
||||
int32_t i;
|
||||
|
||||
pDelayMs = pDelayMsFunc;
|
||||
|
||||
/* Initial states for PHY status and state machine */
|
||||
olddphysts = physts = phyustate = 0;
|
||||
|
||||
/* Only first read and write are checked for failure */
|
||||
/* Put the DP83848C in reset mode and wait for completion */
|
||||
if (lpc_mii_write(LAN8_BCR_REG, LAN8_RESET) != SUCCESS) {
|
||||
return ERROR;
|
||||
}
|
||||
i = 400;
|
||||
while (i > 0) {
|
||||
pDelayMs(1);
|
||||
if (lpc_mii_read(LAN8_BCR_REG, &tmp) != SUCCESS) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (!(tmp & (LAN8_RESET | LAN8_POWER_DOWN))) {
|
||||
i = -1;
|
||||
}
|
||||
else {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
/* Timeout? */
|
||||
if (i == 0) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Setup link */
|
||||
lpc_mii_write(LAN8_BCR_REG, LAN8_AUTONEG);
|
||||
|
||||
/* The link is not set active at this point, but will be detected
|
||||
later */
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* Phy status update state machine */
|
||||
uint32_t lpcPHYStsPoll(void)
|
||||
{
|
||||
static uint16_t sts;
|
||||
|
||||
switch (phyustate) {
|
||||
default:
|
||||
case 0:
|
||||
/* Read BMSR to clear faults */
|
||||
Chip_ENET_StartMIIRead(LPC_ETHERNET, LAN8_BSR_REG);
|
||||
physts &= ~PHY_LINK_CHANGED;
|
||||
physts = physts | PHY_LINK_BUSY;
|
||||
phyustate = 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Wait for read status state */
|
||||
if (!Chip_ENET_IsMIIBusy(LPC_ETHERNET)) {
|
||||
/* Get PHY status with link state */
|
||||
sts = Chip_ENET_ReadMIIData(LPC_ETHERNET);
|
||||
Chip_ENET_StartMIIRead(LPC_ETHERNET, LAN8_PHYSPLCTL_REG);
|
||||
phyustate = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Wait for read status state */
|
||||
if (!Chip_ENET_IsMIIBusy(LPC_ETHERNET)) {
|
||||
/* Update PHY status */
|
||||
physts &= ~PHY_LINK_BUSY;
|
||||
smsc_update_phy_sts(sts, Chip_ENET_ReadMIIData(LPC_ETHERNET));
|
||||
phyustate = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return physts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
Reference in New Issue
Block a user