1 /**********************************************************************
2 * $Id$ lpc_phy_dp83848.c 2011-11-20
4 * @file lpc_phy_dp83848.c
5 * @brief DP83848C PHY status and control.
8 * @author NXP MCU SW Application Team
10 * Copyright(C) 2011, NXP Semiconductor
11 * All rights reserved.
13 ***********************************************************************
14 * Software that is described herein is for illustrative purposes only
15 * which provides customers with programming information regarding the
16 * products. This software is supplied "AS IS" without any warranties.
17 * NXP Semiconductors assumes no responsibility or liability for the
18 * use of the software, conveys no license or title under any patent,
19 * copyright, or mask work right to the product. NXP Semiconductors
20 * reserves the right to make changes in the software without
21 * notification. NXP Semiconductors also make no representation or
22 * warranty that such application will be suitable for the specified
23 * use without further testing or modification.
24 **********************************************************************/
28 #include "lwip/tcpip.h"
29 #include "lwip/snmp.h"
30 #include "lpc_emac_config.h"
32 #include "lpc17xx_emac.h"
34 /** @defgroup dp83848_phy PHY status and control for the DP83848.
37 * Various functions for controlling and monitoring the status of the
38 * DP83848 PHY. In polled (standalone) systems, the PHY state must be
39 * monitored as part of the application. In a threaded (RTOS) system,
40 * the PHY state is monitored by the PHY handler thread. The MAC
41 * driver will not transmit unless the PHY link is active.
45 /** \brief DP83848 PHY register offsets */
46 #define DP8_BMCR_REG 0x0 /**< Basic Mode Control Register */
47 #define DP8_BMSR_REG 0x1 /**< Basic Mode Status Reg */
48 #define DP8_IDR1_REG 0x2 /**< Basic Mode Status Reg */
49 #define DP8_IDR2_REG 0x3 /**< Basic Mode Status Reg */
50 #define DP8_ANADV_REG 0x4 /**< Auto_Neg Advt Reg */
51 #define DP8_ANLPA_REG 0x5 /**< Auto_neg Link Partner Ability Reg */
52 #define DP8_ANEEXP_REG 0x6 /**< Auto-neg Expansion Reg */
53 #define DP8_PHY_STAT_REG 0x10 /**< PHY Status Register */
54 #define DP8_PHY_INT_CTL_REG 0x11 /**< PHY Interrupt Control Register */
55 #define DP8_PHY_RBR_REG 0x17 /**< PHY RMII and Bypass Register */
56 #define DP8_PHY_STS_REG 0x19 /**< PHY Status Register */
58 #define DP8_PHY_SCSR_REG 0x1f /**< PHY Special Control/Status Register (LAN8720) */
60 /** \brief DP83848 Control register definitions */
61 #define DP8_RESET (1 << 15) /**< 1= S/W Reset */
62 #define DP8_LOOPBACK (1 << 14) /**< 1=loopback Enabled */
63 #define DP8_SPEED_SELECT (1 << 13) /**< 1=Select 100MBps */
64 #define DP8_AUTONEG (1 << 12) /**< 1=Enable auto-negotiation */
65 #define DP8_POWER_DOWN (1 << 11) /**< 1=Power down PHY */
66 #define DP8_ISOLATE (1 << 10) /**< 1=Isolate PHY */
67 #define DP8_RESTART_AUTONEG (1 << 9) /**< 1=Restart auto-negoatiation */
68 #define DP8_DUPLEX_MODE (1 << 8) /**< 1=Full duplex mode */
69 #define DP8_COLLISION_TEST (1 << 7) /**< 1=Perform collsion test */
71 /** \brief DP83848 Status register definitions */
72 #define DP8_100BASE_T4 (1 << 15) /**< T4 mode */
73 #define DP8_100BASE_TX_FD (1 << 14) /**< 100MBps full duplex */
74 #define DP8_100BASE_TX_HD (1 << 13) /**< 100MBps half duplex */
75 #define DP8_10BASE_T_FD (1 << 12) /**< 100Bps full duplex */
76 #define DP8_10BASE_T_HD (1 << 11) /**< 10MBps half duplex */
77 #define DP8_MF_PREAMB_SUPPR (1 << 6) /**< Preamble suppress */
78 #define DP8_AUTONEG_COMP (1 << 5) /**< Auto-negotation complete */
79 #define DP8_RMT_FAULT (1 << 4) /**< Fault */
80 #define DP8_AUTONEG_ABILITY (1 << 3) /**< Auto-negotation supported */
81 #define DP8_LINK_STATUS (1 << 2) /**< 1=Link active */
82 #define DP8_JABBER_DETECT (1 << 1) /**< Jabber detect */
83 #define DP8_EXTEND_CAPAB (1 << 0) /**< Supports extended capabilities */
85 /** \brief DP83848 PHY RBR MII dode definitions */
86 #define DP8_RBR_RMII_MODE (1 << 5) /**< Use RMII mode */
88 /** \brief DP83848 PHY status definitions */
89 #define DP8_REMOTEFAULT (1 << 6) /**< Remote fault */
90 #define DP8_FULLDUPLEX (1 << 2) /**< 1=full duplex */
91 #define DP8_SPEED10MBPS (1 << 1) /**< 1=10MBps speed */
92 #define DP8_VALID_LINK (1 << 0) /**< 1=Link active */
94 /** \brief DP83848 PHY ID register definitions */
95 #define DP8_PHYID1_OUI 0x2000 /**< Expected PHY ID1 */
96 #define DP8_PHYID2_OUI 0x5c90 /**< Expected PHY ID2 */
98 /** \brief LAN8720 PHY Special Control/Status Register */
99 #define PHY_SCSR_100MBIT 0x0008 /**< Speed: 1=100 MBit, 0=10Mbit */
100 #define PHY_SCSR_DUPLEX 0x0010 /**< PHY Duplex Mask */
102 /** \brief Link status bits */
103 #define LNK_STAT_VALID 0x01
104 #define LNK_STAT_FULLDUPLEX 0x02
105 #define LNK_STAT_SPEED10MPS 0x04
107 /** \brief PHY ID definitions */
108 #define DP83848C_ID 0x20005C90 /**< PHY Identifier - DP83848C */
109 #define LAN8720_ID 0x0007C0F0 /**< PHY Identifier - LAN8720 */
111 /** \brief PHY status structure used to indicate current status of PHY.
114 u32_t phy_speed_100mbs
:1; /**< 10/100 MBS connection speed flag. */
115 u32_t phy_full_duplex
:1; /**< Half/full duplex connection speed flag. */
116 u32_t phy_link_active
:1; /**< Phy link active flag. */
119 /** \brief PHY update flags */
120 static PHY_STATUS_TYPE physts
;
122 /** \brief Last PHY update flags, used for determing if something has changed */
123 static PHY_STATUS_TYPE olddphysts
;
125 /** \brief PHY update counter for state machine */
126 static s32_t phyustate
;
128 /** \brief Holds the PHY ID */
131 /** \brief Temporary holder of link status for LAN7420 */
132 static u32_t phy_lan7420_sts_tmp
;
134 /* Write a value via the MII link (non-blocking) */
135 void lpc_mii_write_noblock(u32_t PhyReg
, u32_t Value
)
137 /* Write value at PHY address and register */
138 LPC_EMAC
->MADR
= (LPC_PHYDEF_PHYADDR
<< 8) | PhyReg
;
139 LPC_EMAC
->MWTD
= Value
;
142 /* Write a value via the MII link (blocking) */
143 err_t
lpc_mii_write(u32_t PhyReg
, u32_t Value
)
148 /* Write value at PHY address and register */
149 lpc_mii_write_noblock(PhyReg
, Value
);
151 /* Wait for unbusy status */
153 sts
= LPC_EMAC
->MIND
;
154 if ((sts
& EMAC_MIND_BUSY
) == 0)
168 /* Reads current MII link busy status */
169 u32_t
lpc_mii_is_busy(void)
171 return (u32_t
) (LPC_EMAC
->MIND
& EMAC_MIND_BUSY
);
174 /* Starts a read operation via the MII link (non-blocking) */
175 u32_t
lpc_mii_read_data(void)
177 u32_t data
= LPC_EMAC
->MRDD
;
183 /* Starts a read operation via the MII link (non-blocking) */
184 void lpc_mii_read_noblock(u32_t PhyReg
)
186 /* Read value at PHY address and register */
187 LPC_EMAC
->MADR
= (LPC_PHYDEF_PHYADDR
<< 8) | PhyReg
;
188 LPC_EMAC
->MCMD
= EMAC_MCMD_READ
;
191 /* Read a value via the MII link (blocking) */
192 err_t
lpc_mii_read(u32_t PhyReg
, u32_t
*data
)
197 /* Read value at PHY address and register */
198 lpc_mii_read_noblock(PhyReg
);
200 /* Wait for unbusy status */
202 sts
= LPC_EMAC
->MIND
& ~EMAC_MIND_MII_LINK_FAIL
;
203 if ((sts
& EMAC_MIND_BUSY
) == 0) {
205 *data
= LPC_EMAC
->MRDD
;
222 /** \brief Update PHY status from passed value
224 * This function updates the current PHY status based on the
225 * passed PHY status word. The PHY status indicate if the link
226 * is active, the connection speed, and duplex.
228 * \param[in] netif NETIF structure
229 * \param[in] linksts Status word from PHY
230 * \return 1 if the status has changed, otherwise 0
232 static s32_t
lpc_update_phy_sts(struct netif
*netif
, u32_t linksts
)
236 /* Update link active status */
237 if (linksts
& LNK_STAT_VALID
)
238 physts
.phy_link_active
= 1;
240 physts
.phy_link_active
= 0;
242 /* Full or half duplex */
243 if (linksts
& LNK_STAT_FULLDUPLEX
)
244 physts
.phy_full_duplex
= 1;
246 physts
.phy_full_duplex
= 0;
248 /* Configure 100MBit/10MBit mode. */
249 if (linksts
& LNK_STAT_SPEED10MPS
)
250 physts
.phy_speed_100mbs
= 0;
252 physts
.phy_speed_100mbs
= 1;
254 if (physts
.phy_speed_100mbs
!= olddphysts
.phy_speed_100mbs
) {
256 if (physts
.phy_speed_100mbs
) {
258 lpc_emac_set_speed(1);
260 NETIF_INIT_SNMP(netif
, snmp_ifType_ethernet_csmacd
, 100000000);
264 lpc_emac_set_speed(0);
266 NETIF_INIT_SNMP(netif
, snmp_ifType_ethernet_csmacd
, 10000000);
269 olddphysts
.phy_speed_100mbs
= physts
.phy_speed_100mbs
;
272 if (physts
.phy_full_duplex
!= olddphysts
.phy_full_duplex
) {
274 if (physts
.phy_full_duplex
)
275 lpc_emac_set_duplex(1);
277 lpc_emac_set_duplex(0);
279 olddphysts
.phy_full_duplex
= physts
.phy_full_duplex
;
282 if (physts
.phy_link_active
!= olddphysts
.phy_link_active
) {
285 if (physts
.phy_link_active
)
286 netif_set_link_up(netif
);
288 netif_set_link_down(netif
);
290 if (physts
.phy_link_active
)
291 tcpip_callback_with_block((tcpip_callback_fn
) netif_set_link_up
,
294 tcpip_callback_with_block((tcpip_callback_fn
) netif_set_link_down
,
298 olddphysts
.phy_link_active
= physts
.phy_link_active
;
304 /** \brief Initialize the DP83848 PHY.
306 * This function initializes the DP83848 PHY. It will block until
307 * complete. This function is called as part of the EMAC driver
308 * initialization. Configuration of the PHY at startup is
309 * controlled by setting up configuration defines in lpc_phy.h.
311 * \param[in] netif NETIF structure
312 * \param[in] rmii If set, configures the PHY for RMII mode
313 * \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
315 err_t
lpc_phy_init(struct netif
*netif
, int rmii
)
320 physts
.phy_speed_100mbs
= olddphysts
.phy_speed_100mbs
= 0;
321 physts
.phy_full_duplex
= olddphysts
.phy_full_duplex
= 0;
322 physts
.phy_link_active
= olddphysts
.phy_link_active
= 0;
325 /* Only first read and write are checked for failure */
326 /* Put the DP83848C in reset mode and wait for completion */
327 if (lpc_mii_write(DP8_BMCR_REG
, DP8_RESET
) != 0)
331 osDelay(1); /* 1 ms */
332 if (lpc_mii_read(DP8_BMCR_REG
, &tmp
) != 0)
335 if (!(tmp
& (DP8_RESET
| DP8_POWER_DOWN
)))
345 lpc_mii_read(DP8_IDR1_REG
, &tmp
);
346 phy_id
= (tmp
<< 16);
347 lpc_mii_read(DP8_IDR2_REG
, &tmp
);
348 phy_id
|= (tmp
& 0XFFF0);
350 /* Setup link based on configuration options */
351 #if PHY_USE_AUTONEG==1
356 #if PHY_USE_100MBS==1
357 tmp
|= DP8_SPEED_SELECT
;
359 #if PHY_USE_FULL_DUPLEX==1
360 tmp
|= DP8_DUPLEX_MODE
;
362 lpc_mii_write(DP8_BMCR_REG
, tmp
);
364 /* Enable RMII mode for PHY */
366 lpc_mii_write(DP8_PHY_RBR_REG
, DP8_RBR_RMII_MODE
);
368 /* The link is not set active at this point, but will be detected
374 /* Phy status update state machine */
375 s32_t
lpc_phy_sts_sm(struct netif
*netif
)
384 if (phy_id
== DP83848C_ID
) {
385 lpc_mii_read_noblock(DP8_PHY_STAT_REG
);
388 else if (phy_id
== LAN8720_ID
) {
389 lpc_mii_read_noblock(DP8_PHY_SCSR_REG
);
395 if (phy_id
== LAN8720_ID
) {
396 tmp
= lpc_mii_read_data();
397 // we get speed and duplex here.
398 phy_lan7420_sts_tmp
= (tmp
& PHY_SCSR_DUPLEX
) ? LNK_STAT_FULLDUPLEX
: 0;
399 phy_lan7420_sts_tmp
|= (tmp
& PHY_SCSR_100MBIT
) ? 0 : LNK_STAT_SPEED10MPS
;
401 //read the status register to get link status
402 lpc_mii_read_noblock(DP8_BMSR_REG
);
408 /* Wait for read status state */
409 if (!lpc_mii_is_busy()) {
410 /* Update PHY status */
411 tmp
= lpc_mii_read_data();
413 if (phy_id
== DP83848C_ID
) {
414 // STS register contains all needed status bits
415 data
= (tmp
& DP8_VALID_LINK
) ? LNK_STAT_VALID
: 0;
416 data
|= (tmp
& DP8_FULLDUPLEX
) ? LNK_STAT_FULLDUPLEX
: 0;
417 data
|= (tmp
& DP8_SPEED10MBPS
) ? LNK_STAT_SPEED10MPS
: 0;
419 else if (phy_id
== LAN8720_ID
) {
420 // we only get the link status here.
421 phy_lan7420_sts_tmp
|= (tmp
& DP8_LINK_STATUS
) ? LNK_STAT_VALID
: 0;
422 data
= phy_lan7420_sts_tmp
;
425 changed
= lpc_update_phy_sts(netif
, data
);
438 /* --------------------------------- End Of File ------------------------------ */