Files
NxpNfcRdLib/.svn/pristine/07/075e0351d2a435a597a2efee30e01926a8ea7521.svn-base
2024-07-08 21:03:06 +08:00

271 lines
7.7 KiB
Plaintext

/*
* @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;
}
/**
* @}
*/