| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lpc_phy_smsc87x0.c
Go to the documentation of this file.
1 /*
2 * @brief SMSC 87x0 simple PHY driver
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2012
6 * All rights reserved.
7 *
8 * @par
9 * Software that is described herein is for illustrative purposes only
10 * which provides customers with programming information regarding the
11 * LPC products. This software is supplied "AS IS" without any warranties of
12 * any kind, and NXP Semiconductors and its licensor disclaim any and
13 * all warranties, express or implied, including all implied warranties of
14 * merchantability, fitness for a particular purpose and non-infringement of
15 * intellectual property rights. NXP Semiconductors assumes no responsibility
16 * or liability for the use of the software, conveys no license or rights under any
17 * patent, copyright, mask work right, or any other intellectual property rights in
18 * or to any products. NXP Semiconductors reserves the right to make changes
19 * in the software without notification. NXP Semiconductors also makes no
20 * representation or warranty that such application will be suitable for the
21 * specified use without further testing or modification.
22 *
23 * @par
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation is hereby granted, under NXP Semiconductors' and its
26 * licensor's relevant copyrights in the software, without fee, provided that it
27 * is used in conjunction with NXP Semiconductors microcontrollers. This
28 * copyright, permission, and disclaimer notice must appear in all copies of
29 * this code.
30 */
31
32 #include "chip.h"
33 #include "lpc_phy.h"
34
42 /* LAN8720 PHY register offsets */
43 #define LAN8_BCR_REG 0x0
44 #define LAN8_BSR_REG 0x1
45 #define LAN8_PHYID1_REG 0x2
46 #define LAN8_PHYID2_REG 0x3
47 #define LAN8_PHYSPLCTL_REG 0x1F
49 /* LAN8720 BCR register definitions */
50 #define LAN8_RESET (1 << 15)
51 #define LAN8_LOOPBACK (1 << 14)
52 #define LAN8_SPEED_SELECT (1 << 13)
53 #define LAN8_AUTONEG (1 << 12)
54 #define LAN8_POWER_DOWN (1 << 11)
55 #define LAN8_ISOLATE (1 << 10)
56 #define LAN8_RESTART_AUTONEG (1 << 9)
57 #define LAN8_DUPLEX_MODE (1 << 8)
59 /* LAN8720 BSR register definitions */
60 #define LAN8_100BASE_T4 (1 << 15)
61 #define LAN8_100BASE_TX_FD (1 << 14)
62 #define LAN8_100BASE_TX_HD (1 << 13)
63 #define LAN8_10BASE_T_FD (1 << 12)
64 #define LAN8_10BASE_T_HD (1 << 11)
65 #define LAN8_AUTONEG_COMP (1 << 5)
66 #define LAN8_RMT_FAULT (1 << 4)
67 #define LAN8_AUTONEG_ABILITY (1 << 3)
68 #define LAN8_LINK_STATUS (1 << 2)
69 #define LAN8_JABBER_DETECT (1 << 1)
70 #define LAN8_EXTEND_CAPAB (1 << 0)
72 /* LAN8720 PHYSPLCTL status definitions */
73 #define LAN8_SPEEDMASK (7 << 2)
74 #define LAN8_SPEED100F (6 << 2)
75 #define LAN8_SPEED10F (5 << 2)
76 #define LAN8_SPEED100H (2 << 2)
77 #define LAN8_SPEED10H (1 << 2)
79 /* LAN8720 PHY ID 1/2 register definitions */
80 #define LAN8_PHYID1_OUI 0x0007
81 #define LAN8_PHYID2_OUI 0xC0F0
83 /* DP83848 PHY update flags */
84 static uint32_t physts, olddphysts;
85
86 /* PHY update counter for state machine */
87 static int32_t phyustate;
88
89 /* Pointer to delay function used for this driver */
90 static p_msDelay_func_t pDelayMs;
91
92 /* Write to the PHY. Will block for delays based on the pDelayMs function. Returns
93 true on success, or false on failure */
94 static Status lpc_mii_write(uint8_t reg, uint16_t data)
95 {
96 Status sts = ERROR;
97 int32_t mst = 250;
98
99 /* Write value for register */
100 Chip_ENET_StartMIIWrite(LPC_ETHERNET, reg, data);
101
102 /* Wait for unbusy status */
103 while (mst > 0) {
104 if (Chip_ENET_IsMIIBusy(LPC_ETHERNET)) {
105 mst--;
106 pDelayMs(1);
107 }
108 else {
109 mst = 0;
110 sts = SUCCESS;
111 }
112 }
113
114 return sts;
115 }
116
117 /* Read from the PHY. Will block for delays based on the pDelayMs function. Returns
118 true on success, or false on failure */
119 static Status lpc_mii_read(uint8_t reg, uint16_t *data)
120 {
121 Status sts = ERROR;
122 int32_t mst = 250;
123
124 /* Start register read */
125 Chip_ENET_StartMIIRead(LPC_ETHERNET, reg);
126
127 /* Wait for unbusy status */
128 while (mst > 0) {
129 if (!Chip_ENET_IsMIIBusy(LPC_ETHERNET)) {
130 mst = 0;
131 *data = Chip_ENET_ReadMIIData(LPC_ETHERNET);
132 sts = SUCCESS;
133 }
134 else {
135 mst--;
136 pDelayMs(1);
137 }
138 }
139
140 return sts;
141 }
142
143 /* Update PHY status from passed value */
144 static void smsc_update_phy_sts(uint16_t linksts, uint16_t sdsts)
145 {
146 /* Update link active status */
147 if (linksts & LAN8_LINK_STATUS) {
148 physts |= PHY_LINK_CONNECTED;
149 }
150 else {
151 physts &= ~PHY_LINK_CONNECTED;
152 }
153
154 switch (sdsts & LAN8_SPEEDMASK) {
155 case LAN8_SPEED100F:
156 default:
157 physts |= PHY_LINK_SPEED100;
158 physts |= PHY_LINK_FULLDUPLX;
159 break;
160
161 case LAN8_SPEED10F:
162 physts &= ~PHY_LINK_SPEED100;
163 physts |= PHY_LINK_FULLDUPLX;
164 break;
165
166 case LAN8_SPEED100H:
167 physts |= PHY_LINK_SPEED100;
168 physts &= ~PHY_LINK_FULLDUPLX;
169 break;
170
171 case LAN8_SPEED10H:
172 physts &= ~PHY_LINK_SPEED100;
173 physts &= ~PHY_LINK_FULLDUPLX;
174 break;
175 }
176
177 /* If the status has changed, indicate via change flag */
178 if ((physts & (PHY_LINK_SPEED100 | PHY_LINK_FULLDUPLX | PHY_LINK_CONNECTED)) !=
179 (olddphysts & (PHY_LINK_SPEED100 | PHY_LINK_FULLDUPLX | PHY_LINK_CONNECTED))) {
180 olddphysts = physts;
181 physts |= PHY_LINK_CHANGED;
182 }
183 }
184
185 /* Initialize the SMSC 87x0 PHY */
186 uint32_t lpc_phy_init(bool rmii, p_msDelay_func_t pDelayMsFunc)
187 {
188 uint16_t tmp;
189 int32_t i;
190
191 pDelayMs = pDelayMsFunc;
192
193 /* Initial states for PHY status and state machine */
194 olddphysts = physts = phyustate = 0;
195
196 /* Only first read and write are checked for failure */
197 /* Put the DP83848C in reset mode and wait for completion */
198 if (lpc_mii_write(LAN8_BCR_REG, LAN8_RESET) != SUCCESS) {
199 return ERROR;
200 }
201 i = 400;
202 while (i > 0) {
203 pDelayMs(1);
204 if (lpc_mii_read(LAN8_BCR_REG, &tmp) != SUCCESS) {
205 return ERROR;
206 }
207
208 if (!(tmp & (LAN8_RESET | LAN8_POWER_DOWN))) {
209 i = -1;
210 }
211 else {
212 i--;
213 }
214 }
215 /* Timeout? */
216 if (i == 0) {
217 return ERROR;
218 }
219
220 /* Setup link */
221 lpc_mii_write(LAN8_BCR_REG, LAN8_AUTONEG);
222
223 /* The link is not set active at this point, but will be detected
224 later */
225
226 return SUCCESS;
227 }
228
229 /* Phy status update state machine */
230 uint32_t lpcPHYStsPoll(void)
231 {
232 static uint16_t sts;
233
234 switch (phyustate) {
235 default:
236 case 0:
237 /* Read BMSR to clear faults */
238 Chip_ENET_StartMIIRead(LPC_ETHERNET, LAN8_BSR_REG);
239 physts &= ~PHY_LINK_CHANGED;
240 physts = physts | PHY_LINK_BUSY;
241 phyustate = 1;
242 break;
243
244 case 1:
245 /* Wait for read status state */
246 if (!Chip_ENET_IsMIIBusy(LPC_ETHERNET)) {
247 /* Get PHY status with link state */
248 sts = Chip_ENET_ReadMIIData(LPC_ETHERNET);
249 Chip_ENET_StartMIIRead(LPC_ETHERNET, LAN8_PHYSPLCTL_REG);
250 phyustate = 2;
251 }
252 break;
253
254 case 2:
255 /* Wait for read status state */
256 if (!Chip_ENET_IsMIIBusy(LPC_ETHERNET)) {
257 /* Update PHY status */
258 physts &= ~PHY_LINK_BUSY;
259 smsc_update_phy_sts(sts, Chip_ENET_ReadMIIData(LPC_ETHERNET));
260 phyustate = 0;
261 }
262 break;
263 }
264
265 return physts;
266 }
267