dp83867_driver.c
Go to the documentation of this file.
1 /**
2  * @file dp83867_driver.c
3  * @brief DP83867 Gigabit Ethernet PHY driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
37 #include "debug.h"
38 
39 
40 /**
41  * @brief DP83867 Ethernet PHY driver
42  **/
43 
45 {
51 };
52 
53 
54 /**
55  * @brief DP83867 PHY transceiver initialization
56  * @param[in] interface Underlying network interface
57  * @return Error code
58  **/
59 
61 {
62  uint16_t temp;
63 
64  //Debug message
65  TRACE_INFO("Initializing DP83867...\r\n");
66 
67  //Undefined PHY address?
68  if(interface->phyAddr >= 32)
69  {
70  //Use the default address
71  interface->phyAddr = DP83867_PHY_ADDR;
72  }
73 
74  //Initialize serial management interface
75  if(interface->smiDriver != NULL)
76  {
77  interface->smiDriver->init();
78  }
79 
80  //Initialize external interrupt line driver
81  if(interface->extIntDriver != NULL)
82  {
83  interface->extIntDriver->init();
84  }
85 
86  //Reset PHY transceiver
88 
89  //Wait for the reset to complete
91  {
92  }
93 
94  //Dump PHY registers for debugging purpose
95  dp83867DumpPhyReg(interface);
96 
97  //Set RGMII TX and RX clock delays
101 
102  //Enable shift mode
103  temp = dp83867ReadMmdReg(interface, DP83867_RGMIICTL);
106  dp83867WriteMmdReg(interface, DP83867_RGMIICTL, temp);
107 
108  //Set GPIO mux control
112 
113  //Set LED mode
117 
118  //Configure INTN/PWDNN pin as an interrupt output
120 
121  //The PHY will generate interrupts when link status changes are detected
122  dp83867WritePhyReg(interface, DP83867_MICR,
124 
125  //Perform custom configuration
126  dp83867InitHook(interface);
127 
128  //Force the TCP/IP stack to poll the link state at startup
129  interface->phyEvent = TRUE;
130  //Notify the TCP/IP stack of the event
132 
133  //Successful initialization
134  return NO_ERROR;
135 }
136 
137 
138 /**
139  * @brief DP83867 custom configuration
140  * @param[in] interface Underlying network interface
141  **/
142 
143 __weak_func void dp83867InitHook(NetInterface *interface)
144 {
145 }
146 
147 
148 /**
149  * @brief DP83867 timer handler
150  * @param[in] interface Underlying network interface
151  **/
152 
153 void dp83867Tick(NetInterface *interface)
154 {
155  uint16_t value;
156  bool_t linkState;
157 
158  //No external interrupt line driver?
159  if(interface->extIntDriver == NULL)
160  {
161  //Read basic status register
162  value = dp83867ReadPhyReg(interface, DP83867_BMSR);
163  //Retrieve current link state
164  linkState = (value & DP83867_BMSR_LINK_STATUS) ? TRUE : FALSE;
165 
166  //Link up event?
167  if(linkState && !interface->linkState)
168  {
169  //Set event flag
170  interface->phyEvent = TRUE;
171  //Notify the TCP/IP stack of the event
173  }
174  //Link down event?
175  else if(!linkState && interface->linkState)
176  {
177  //Set event flag
178  interface->phyEvent = TRUE;
179  //Notify the TCP/IP stack of the event
181  }
182  }
183 }
184 
185 
186 /**
187  * @brief Enable interrupts
188  * @param[in] interface Underlying network interface
189  **/
190 
192 {
193  //Enable PHY transceiver interrupts
194  if(interface->extIntDriver != NULL)
195  {
196  interface->extIntDriver->enableIrq();
197  }
198 }
199 
200 
201 /**
202  * @brief Disable interrupts
203  * @param[in] interface Underlying network interface
204  **/
205 
207 {
208  //Disable PHY transceiver interrupts
209  if(interface->extIntDriver != NULL)
210  {
211  interface->extIntDriver->disableIrq();
212  }
213 }
214 
215 
216 /**
217  * @brief DP83867 event handler
218  * @param[in] interface Underlying network interface
219  **/
220 
222 {
223  uint16_t status;
224 
225  //Read status register to acknowledge the interrupt
226  status = dp83867ReadPhyReg(interface, DP83867_MISR);
227 
228  //Link status change?
229  if((status & DP83867_MISR_LINK_STATUS_CHNG_INT) != 0)
230  {
231  //Read PHY status register
232  status = dp83867ReadPhyReg(interface, DP83867_PHYSTS);
233 
234  //Link is up?
235  if((status & DP83867_PHYSTS_LINK_STATUS) != 0)
236  {
237  //Check current speed
238  switch(status & DP83867_PHYSTS_SPEED_SEL)
239  {
240  //10BASE-T
242  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
243  break;
244  //100BASE-TX
246  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
247  break;
248  //1000BASE-T
250  interface->linkSpeed = NIC_LINK_SPEED_1GBPS;
251  break;
252  //Unknown speed
253  default:
254  //Debug message
255  TRACE_WARNING("Invalid speed\r\n");
256  break;
257  }
258 
259  //Check duplex mode
260  if((status & DP83867_PHYSTS_DUPLEX_MODE) != 0)
261  {
262  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
263  }
264  else
265  {
266  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
267  }
268 
269  //Update link state
270  interface->linkState = TRUE;
271 
272  //Adjust MAC configuration parameters for proper operation
273  interface->nicDriver->updateMacConfig(interface);
274  }
275  else
276  {
277  //Update link state
278  interface->linkState = FALSE;
279  }
280 
281  //Process link state change event
282  nicNotifyLinkChange(interface);
283  }
284 }
285 
286 
287 /**
288  * @brief Write PHY register
289  * @param[in] interface Underlying network interface
290  * @param[in] address PHY register address
291  * @param[in] data Register value
292  **/
293 
294 void dp83867WritePhyReg(NetInterface *interface, uint8_t address,
295  uint16_t data)
296 {
297  //Write the specified PHY register
298  if(interface->smiDriver != NULL)
299  {
300  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE,
301  interface->phyAddr, address, data);
302  }
303  else
304  {
305  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE,
306  interface->phyAddr, address, data);
307  }
308 }
309 
310 
311 /**
312  * @brief Read PHY register
313  * @param[in] interface Underlying network interface
314  * @param[in] address PHY register address
315  * @return Register value
316  **/
317 
318 uint16_t dp83867ReadPhyReg(NetInterface *interface, uint8_t address)
319 {
320  uint16_t data;
321 
322  //Read the specified PHY register
323  if(interface->smiDriver != NULL)
324  {
325  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ,
326  interface->phyAddr, address);
327  }
328  else
329  {
330  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ,
331  interface->phyAddr, address);
332  }
333 
334  //Return the value of the PHY register
335  return data;
336 }
337 
338 
339 /**
340  * @brief Dump PHY registers for debugging purpose
341  * @param[in] interface Underlying network interface
342  **/
343 
345 {
346  uint8_t i;
347 
348  //Loop through PHY registers
349  for(i = 0; i < 32; i++)
350  {
351  //Display current PHY register
352  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
353  dp83867ReadPhyReg(interface, i));
354  }
355 
356  //Terminate with a line feed
357  TRACE_DEBUG("\r\n");
358 }
359 
360 
361 /**
362  * @brief Write MMD register
363  * @param[in] interface Underlying network interface
364  * @param[in] devAddr Device address
365  * @param[in] regAddr Register address
366  * @param[in] data MMD register value
367  **/
368 
369 void dp83867WriteMmdReg(NetInterface *interface, uint8_t devAddr,
370  uint16_t regAddr, uint16_t data)
371 {
372  //Select register operation
375 
376  //Write MMD register address
378 
379  //Select data operation
382 
383  //Write the content of the MMD register
385 }
386 
387 
388 /**
389  * @brief Read MMD register
390  * @param[in] interface Underlying network interface
391  * @param[in] devAddr Device address
392  * @param[in] regAddr Register address
393  * @return MMD register value
394  **/
395 
396 uint16_t dp83867ReadMmdReg(NetInterface *interface, uint8_t devAddr,
397  uint16_t regAddr)
398 {
399  //Select register operation
402 
403  //Write MMD register address
405 
406  //Select data operation
409 
410  //Read the content of the MMD register
411  return dp83867ReadPhyReg(interface, DP83867_ADDAR);
412 }
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_WARNING(...)
Definition: debug.h:85
#define TRACE_INFO(...)
Definition: debug.h:95
void dp83867WriteMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
error_t dp83867Init(NetInterface *interface)
DP83867 PHY transceiver initialization.
void dp83867DumpPhyReg(NetInterface *interface)
Dump PHY registers for debugging purpose.
uint16_t dp83867ReadPhyReg(NetInterface *interface, uint8_t address)
Read PHY register.
void dp83867Tick(NetInterface *interface)
DP83867 timer handler.
__weak_func void dp83867InitHook(NetInterface *interface)
DP83867 custom configuration.
void dp83867EnableIrq(NetInterface *interface)
Enable interrupts.
uint16_t dp83867ReadMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
void dp83867EventHandler(NetInterface *interface)
DP83867 event handler.
void dp83867WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
Write PHY register.
void dp83867DisableIrq(NetInterface *interface)
Disable interrupts.
const PhyDriver dp83867PhyDriver
DP83867 Ethernet PHY driver.
DP83867 Gigabit Ethernet PHY driver.
#define DP83867_PHYSTS_SPEED_SEL_100MBPS
#define DP83867_CFG3_INT_OE
#define DP83867_LEDCR1
#define DP83867_MISR
#define DP83867_REGCR_FUNC_ADDR
#define DP83867_LEDCR1_LED_GPIO_SEL_10_100
#define DP83867_BMSR
#define DP83867_REGCR
#define DP83867_REGCR_FUNC_DATA_NO_POST_INC
#define DP83867_GPIO_MUX_CTRL_GPIO_0_CTRL_LED_3
#define DP83867_MICR
#define DP83867_PHYSTS_LINK_STATUS
#define DP83867_RGMIIDCTL
#define DP83867_GPIO_MUX_CTRL_GPIO_1_CTRL_CONST_0
#define DP83867_CFG3
#define DP83867_BMCR_RESET
#define DP83867_PHY_ADDR
#define DP83867_BMCR
#define DP83867_RGMIIDCTL_RGMII_RX_DELAY_CTRL_2_00NS
#define DP83867_PHYSTS_SPEED_SEL_10MBPS
#define DP83867_LEDCR1_LED_2_SEL_ACT
#define DP83867_ADDAR
#define DP83867_PHYSTS_SPEED_SEL
#define DP83867_PHYSTS_DUPLEX_MODE
#define DP83867_LEDCR1_LED_0_SEL_LINK
#define DP83867_MICR_LINK_STATUS_CHNG_INT_EN
#define DP83867_MISR_LINK_STATUS_CHNG_INT
#define DP83867_PHYSTS_SPEED_SEL_1000MBPS
#define DP83867_GPIO_MUX_CTRL
#define DP83867_REGCR_DEVAD
#define DP83867_LEDCR1_LED_1_SEL_1000
#define DP83867_RGMIIDCTL_RGMII_TX_DELAY_CTRL_1_50NS
#define DP83867_RGMIICTL
#define DP83867_RGMIICTL_RGMII_TX_CLK_DELAY
#define DP83867_PHYSTS
#define DP83867_RGMIICTL_RGMII_RX_CLK_DELAY
#define DP83867_BMSR_LINK_STATUS
error_t
Error codes.
Definition: error.h:43
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t data[]
Definition: ethernet.h:222
Ipv6Addr address[]
Definition: ipv6.h:316
uint16_t regAddr
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netEvent
Definition: net_legacy.h:196
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:548
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define SMI_OPCODE_READ
Definition: nic.h:67
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
Ethernet PHY driver.
Definition: nic.h:308
uint8_t value[]
Definition: tcp.h:369