ar8031_driver.c
Go to the documentation of this file.
1 /**
2  * @file ar8031_driver.c
3  * @brief AR8031 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 AR8031 Ethernet PHY driver
42  **/
43 
45 {
46  ar8031Init,
47  ar8031Tick,
51 };
52 
53 
54 /**
55  * @brief AR8031 PHY transceiver initialization
56  * @param[in] interface Underlying network interface
57  * @return Error code
58  **/
59 
61 {
62  //Debug message
63  TRACE_INFO("Initializing AR8031...\r\n");
64 
65  //Undefined PHY address?
66  if(interface->phyAddr >= 32)
67  {
68  //Use the default address
69  interface->phyAddr = AR8031_PHY_ADDR;
70  }
71 
72  //Initialize serial management interface
73  if(interface->smiDriver != NULL)
74  {
75  interface->smiDriver->init();
76  }
77 
78  //Initialize external interrupt line driver
79  if(interface->extIntDriver != NULL)
80  {
81  interface->extIntDriver->init();
82  }
83 
84  //Reset PHY transceiver
86 
87  //Wait for the reset to complete
89  {
90  }
91 
92  //Dump PHY registers for debugging purpose
93  ar8031DumpPhyReg(interface);
94 
95  //Chip configuration register
98 
99  //Basic mode control register
102 
103  //Auto-negotiation advertisement register
108 
109  //1000 BASE-T control register
111 
112  //Function control register
116 
117  //The PHY will generate interrupts when link status changes are detected
120 
121  //Perform custom configuration
122  ar8031InitHook(interface);
123 
124  //Force the TCP/IP stack to poll the link state at startup
125  interface->phyEvent = TRUE;
126  //Notify the TCP/IP stack of the event
128 
129  //Successful initialization
130  return NO_ERROR;
131 }
132 
133 
134 /**
135  * @brief AR8031 custom configuration
136  * @param[in] interface Underlying network interface
137  **/
138 
139 __weak_func void ar8031InitHook(NetInterface *interface)
140 {
141 }
142 
143 
144 /**
145  * @brief AR8031 timer handler
146  * @param[in] interface Underlying network interface
147  **/
148 
149 void ar8031Tick(NetInterface *interface)
150 {
151  uint16_t value;
152  bool_t linkState;
153 
154  //No external interrupt line driver?
155  if(interface->extIntDriver == NULL)
156  {
157  //Read basic status register
158  value = ar8031ReadPhyReg(interface, AR8031_BMSR);
159  //Retrieve current link state
160  linkState = (value & AR8031_BMSR_LINK_STATUS) ? TRUE : FALSE;
161 
162  //Link up event?
163  if(linkState && !interface->linkState)
164  {
165  //Set event flag
166  interface->phyEvent = TRUE;
167  //Notify the TCP/IP stack of the event
169  }
170  //Link down event?
171  else if(!linkState && interface->linkState)
172  {
173  //Set event flag
174  interface->phyEvent = TRUE;
175  //Notify the TCP/IP stack of the event
177  }
178  }
179 }
180 
181 
182 /**
183  * @brief Enable interrupts
184  * @param[in] interface Underlying network interface
185  **/
186 
188 {
189  //Enable PHY transceiver interrupts
190  if(interface->extIntDriver != NULL)
191  {
192  interface->extIntDriver->enableIrq();
193  }
194 }
195 
196 
197 /**
198  * @brief Disable interrupts
199  * @param[in] interface Underlying network interface
200  **/
201 
203 {
204  //Disable PHY transceiver interrupts
205  if(interface->extIntDriver != NULL)
206  {
207  interface->extIntDriver->disableIrq();
208  }
209 }
210 
211 
212 /**
213  * @brief AR8031 event handler
214  * @param[in] interface Underlying network interface
215  **/
216 
218 {
219  uint16_t status;
220 
221  //Read status register to acknowledge the interrupt
222  status = ar8031ReadPhyReg(interface, AR8031_INT_STATUS);
223 
224  //Link status change?
226  {
227  //Read PHY status register
228  status = ar8031ReadPhyReg(interface, AR8031_PHY_STATUS);
229 
230  //Link is up?
231  if((status & AR8031_PHY_STATUS_LINK) != 0)
232  {
233  //Check current speed
234  switch(status & AR8031_PHY_STATUS_SPEED)
235  {
236  //10BASE-T
238  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
239  break;
240  //100BASE-TX
242  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
243  break;
244  //1000BASE-T
246  interface->linkSpeed = NIC_LINK_SPEED_1GBPS;
247  break;
248  //Unknown speed
249  default:
250  //Debug message
251  TRACE_WARNING("Invalid speed\r\n");
252  break;
253  }
254 
255  //Check current duplex mode
256  if((status & AR8031_PHY_STATUS_DUPLEX) != 0)
257  {
258  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
259  }
260  else
261  {
262  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
263  }
264 
265  //Update link state
266  interface->linkState = TRUE;
267 
268  //Adjust MAC configuration parameters for proper operation
269  interface->nicDriver->updateMacConfig(interface);
270  }
271  else
272  {
273  //Update link state
274  interface->linkState = FALSE;
275  }
276 
277  //Process link state change event
278  nicNotifyLinkChange(interface);
279  }
280 }
281 
282 
283 /**
284  * @brief Write PHY register
285  * @param[in] interface Underlying network interface
286  * @param[in] address PHY register address
287  * @param[in] data Register value
288  **/
289 
290 void ar8031WritePhyReg(NetInterface *interface, uint8_t address,
291  uint16_t data)
292 {
293  //Write the specified PHY register
294  if(interface->smiDriver != NULL)
295  {
296  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE,
297  interface->phyAddr, address, data);
298  }
299  else
300  {
301  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE,
302  interface->phyAddr, address, data);
303  }
304 }
305 
306 
307 /**
308  * @brief Read PHY register
309  * @param[in] interface Underlying network interface
310  * @param[in] address PHY register address
311  * @return Register value
312  **/
313 
314 uint16_t ar8031ReadPhyReg(NetInterface *interface, uint8_t address)
315 {
316  uint16_t data;
317 
318  //Read the specified PHY register
319  if(interface->smiDriver != NULL)
320  {
321  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ,
322  interface->phyAddr, address);
323  }
324  else
325  {
326  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ,
327  interface->phyAddr, address);
328  }
329 
330  //Return the value of the PHY register
331  return data;
332 }
333 
334 
335 /**
336  * @brief Dump PHY registers for debugging purpose
337  * @param[in] interface Underlying network interface
338  **/
339 
341 {
342  uint8_t i;
343 
344  //Loop through PHY registers
345  for(i = 0; i < 32; i++)
346  {
347  //Display current PHY register
348  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
349  ar8031ReadPhyReg(interface, i));
350  }
351 
352  //Terminate with a line feed
353  TRACE_DEBUG("\r\n");
354 }
355 
356 
357 /**
358  * @brief Write MMD register
359  * @param[in] interface Underlying network interface
360  * @param[in] devAddr Device address
361  * @param[in] regAddr Register address
362  * @param[in] data MMD register value
363  **/
364 
365 void ar8031WriteMmdReg(NetInterface *interface, uint8_t devAddr,
366  uint16_t regAddr, uint16_t data)
367 {
368  //Select register operation
369  ar8031WritePhyReg(interface, AR8031_MMDACR,
371 
372  //Write MMD register address
374 
375  //Select data operation
376  ar8031WritePhyReg(interface, AR8031_MMDACR,
378 
379  //Write the content of the MMD register
381 }
382 
383 
384 /**
385  * @brief Read MMD register
386  * @param[in] interface Underlying network interface
387  * @param[in] devAddr Device address
388  * @param[in] regAddr Register address
389  * @return MMD register value
390  **/
391 
392 uint16_t ar8031ReadMmdReg(NetInterface *interface, uint8_t devAddr,
393  uint16_t regAddr)
394 {
395  //Select register operation
396  ar8031WritePhyReg(interface, AR8031_MMDACR,
398 
399  //Write MMD register address
401 
402  //Select data operation
403  ar8031WritePhyReg(interface, AR8031_MMDACR,
405 
406  //Read the content of the MMD register
407  return ar8031ReadPhyReg(interface, AR8031_MMDAADR);
408 }
const PhyDriver ar8031PhyDriver
AR8031 Ethernet PHY driver.
Definition: ar8031_driver.c:44
void ar8031EnableIrq(NetInterface *interface)
Enable interrupts.
void ar8031WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
Write PHY register.
uint16_t ar8031ReadPhyReg(NetInterface *interface, uint8_t address)
Read PHY register.
__weak_func void ar8031InitHook(NetInterface *interface)
AR8031 custom configuration.
void ar8031DumpPhyReg(NetInterface *interface)
Dump PHY registers for debugging purpose.
error_t ar8031Init(NetInterface *interface)
AR8031 PHY transceiver initialization.
Definition: ar8031_driver.c:60
void ar8031WriteMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
uint16_t ar8031ReadMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
void ar8031EventHandler(NetInterface *interface)
AR8031 event handler.
void ar8031DisableIrq(NetInterface *interface)
Disable interrupts.
void ar8031Tick(NetInterface *interface)
AR8031 timer handler.
AR8031 Gigabit Ethernet PHY driver.
#define AR8031_INT_STATUS
Definition: ar8031_driver.h:62
#define AR8031_BMCR
Definition: ar8031_driver.h:45
#define AR8031_PHY_STATUS_LINK
#define AR8031_ANAR_10BT_FD
#define AR8031_ANAR_XNP_ABLE
#define AR8031_PHY_STATUS_SPEED_100MBPS
#define AR8031_MMDACR_FUNC_ADDR
#define AR8031_MMDAADR
Definition: ar8031_driver.h:57
#define AR8031_ANAR
Definition: ar8031_driver.h:49
#define AR8031_BMCR_RESET
#define AR8031_BMSR_LINK_STATUS
#define AR8031_MMDACR_DEVAD
#define AR8031_PHY_STATUS
Definition: ar8031_driver.h:60
#define AR8031_FUNC_CTRL_ASSERT_CRS_ON_TX
#define AR8031_FUNC_CTRL_POLARITY_REVERSAL
#define AR8031_PHY_STATUS_SPEED_10MBPS
#define AR8031_BMSR
Definition: ar8031_driver.h:46
#define AR8031_INT_STATUS_LINK_FAIL
#define AR8031_FUNC_CTRL
Definition: ar8031_driver.h:59
#define AR8031_BMCR_AN_EN
#define AR8031_GBCR
Definition: ar8031_driver.h:54
#define AR8031_ANAR_ASYM_PAUSE
#define AR8031_PHY_STATUS_SPEED
#define AR8031_BMCR_SPEED_SEL_LSB
#define AR8031_GBCR_1000BT_FD
#define AR8031_ANAR_SELECTOR_DEFAULT
#define AR8031_ANAR_100BTX_FD
#define AR8031_CHIP_CONF_BT_BX_REG_SEL
#define AR8031_BMCR_DUPLEX_MODE
#define AR8031_ANAR_10BT_HD
#define AR8031_INT_EN
Definition: ar8031_driver.h:61
#define AR8031_CHIP_CONF_PRIORITY_SEL
#define AR8031_PHY_STATUS_SPEED_1000MBPS
#define AR8031_PHY_STATUS_DUPLEX
#define AR8031_INT_STATUS_LINK_SUCCESS
#define AR8031_MMDACR
Definition: ar8031_driver.h:56
#define AR8031_ANAR_100BTX_HD
#define AR8031_FUNC_CTRL_MDIX_MODE_AUTO
#define AR8031_PHY_ADDR
Definition: ar8031_driver.h:39
#define AR8031_CHIP_CONF
Definition: ar8031_driver.h:71
#define AR8031_ANAR_PAUSE
#define AR8031_MMDACR_FUNC_DATA_NO_POST_INC
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
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