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-2020 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 1.9.8
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  //Chip configuration register
95 
96  //Basic mode control register
99 
100  //Auto-negotiation advertisement register
105 
106  //1000 BASE-T control register
108 
109  //Function control register
113 
114  //Dump PHY registers for debugging purpose
115  ar8031DumpPhyReg(interface);
116 
117  //The PHY will generate interrupts when link status changes are detected
120 
121  //Force the TCP/IP stack to poll the link state at startup
122  interface->phyEvent = TRUE;
123  //Notify the TCP/IP stack of the event
125 
126  //Successful initialization
127  return NO_ERROR;
128 }
129 
130 
131 /**
132  * @brief AR8031 timer handler
133  * @param[in] interface Underlying network interface
134  **/
135 
136 void ar8031Tick(NetInterface *interface)
137 {
138  uint16_t value;
139  bool_t linkState;
140 
141  //No external interrupt line driver?
142  if(interface->extIntDriver == NULL)
143  {
144  //Read basic status register
145  value = ar8031ReadPhyReg(interface, AR8031_BMSR);
146  //Retrieve current link state
147  linkState = (value & AR8031_BMSR_LINK_STATUS) ? TRUE : FALSE;
148 
149  //Link up event?
150  if(linkState && !interface->linkState)
151  {
152  //Set event flag
153  interface->phyEvent = TRUE;
154  //Notify the TCP/IP stack of the event
156  }
157  //Link down event?
158  else if(!linkState && interface->linkState)
159  {
160  //Set event flag
161  interface->phyEvent = TRUE;
162  //Notify the TCP/IP stack of the event
164  }
165  }
166 }
167 
168 
169 /**
170  * @brief Enable interrupts
171  * @param[in] interface Underlying network interface
172  **/
173 
175 {
176  //Enable PHY transceiver interrupts
177  if(interface->extIntDriver != NULL)
178  {
179  interface->extIntDriver->enableIrq();
180  }
181 }
182 
183 
184 /**
185  * @brief Disable interrupts
186  * @param[in] interface Underlying network interface
187  **/
188 
190 {
191  //Disable PHY transceiver interrupts
192  if(interface->extIntDriver != NULL)
193  {
194  interface->extIntDriver->disableIrq();
195  }
196 }
197 
198 
199 /**
200  * @brief AR8031 event handler
201  * @param[in] interface Underlying network interface
202  **/
203 
205 {
206  uint16_t status;
207 
208  //Read status register to acknowledge the interrupt
209  status = ar8031ReadPhyReg(interface, AR8031_INT_STATUS);
210 
211  //Link status change?
213  {
214  //Read PHY status register
215  status = ar8031ReadPhyReg(interface, AR8031_PHY_STATUS);
216 
217  //Link is up?
218  if((status & AR8031_PHY_STATUS_LINK) != 0)
219  {
220  //Check current speed
221  switch(status & AR8031_PHY_STATUS_SPEED)
222  {
223  //10BASE-T
225  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
226  break;
227  //100BASE-TX
229  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
230  break;
231  //1000BASE-T
233  interface->linkSpeed = NIC_LINK_SPEED_1GBPS;
234  break;
235  //Unknown speed
236  default:
237  //Debug message
238  TRACE_WARNING("Invalid speed\r\n");
239  break;
240  }
241 
242  //Check current duplex mode
243  if((status & AR8031_PHY_STATUS_DUPLEX) != 0)
244  {
245  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
246  }
247  else
248  {
249  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
250  }
251 
252  //Update link state
253  interface->linkState = TRUE;
254 
255  //Adjust MAC configuration parameters for proper operation
256  interface->nicDriver->updateMacConfig(interface);
257  }
258  else
259  {
260  //Update link state
261  interface->linkState = FALSE;
262  }
263 
264  //Process link state change event
265  nicNotifyLinkChange(interface);
266  }
267 }
268 
269 
270 /**
271  * @brief Write PHY register
272  * @param[in] interface Underlying network interface
273  * @param[in] address PHY register address
274  * @param[in] data Register value
275  **/
276 
277 void ar8031WritePhyReg(NetInterface *interface, uint8_t address,
278  uint16_t data)
279 {
280  //Write the specified PHY register
281  if(interface->smiDriver != NULL)
282  {
283  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE,
284  interface->phyAddr, address, data);
285  }
286  else
287  {
288  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE,
289  interface->phyAddr, address, data);
290  }
291 }
292 
293 
294 /**
295  * @brief Read PHY register
296  * @param[in] interface Underlying network interface
297  * @param[in] address PHY register address
298  * @return Register value
299  **/
300 
301 uint16_t ar8031ReadPhyReg(NetInterface *interface, uint8_t address)
302 {
303  uint16_t data;
304 
305  //Read the specified PHY register
306  if(interface->smiDriver != NULL)
307  {
308  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ,
309  interface->phyAddr, address);
310  }
311  else
312  {
313  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ,
314  interface->phyAddr, address);
315  }
316 
317  //Return the value of the PHY register
318  return data;
319 }
320 
321 
322 /**
323  * @brief Dump PHY registers for debugging purpose
324  * @param[in] interface Underlying network interface
325  **/
326 
328 {
329  uint8_t i;
330 
331  //Loop through PHY registers
332  for(i = 0; i < 32; i++)
333  {
334  //Display current PHY register
335  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
336  ar8031ReadPhyReg(interface, i));
337  }
338 
339  //Terminate with a line feed
340  TRACE_DEBUG("\r\n");
341 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:532
int bool_t
Definition: compiler_port.h:49
#define netEvent
Definition: net_legacy.h:267
const PhyDriver ar8031PhyDriver
AR8031 Ethernet PHY driver.
Definition: ar8031_driver.c:44
void ar8031EventHandler(NetInterface *interface)
AR8031 event handler.
uint8_t data[]
Definition: ethernet.h:209
#define AR8031_ANAR
Definition: ar8031_driver.h:49
void ar8031DumpPhyReg(NetInterface *interface)
Dump PHY registers for debugging purpose.
#define AR8031_INT_STATUS_LINK_FAIL
#define AR8031_PHY_STATUS_LINK
#define AR8031_PHY_STATUS_DUPLEX
#define TRUE
Definition: os_port.h:50
#define AR8031_ANAR_10BT_FD
Ethernet PHY driver.
Definition: nic.h:292
#define AR8031_INT_STATUS_LINK_SUCCESS
#define AR8031_GBCR
Definition: ar8031_driver.h:54
#define AR8031_BMCR_DUPLEX_MODE
Definition: ar8031_driver.h:81
#define AR8031_INT_EN
Definition: ar8031_driver.h:61
error_t ar8031Init(NetInterface *interface)
AR8031 PHY transceiver initialization.
Definition: ar8031_driver.c:60
#define AR8031_PHY_STATUS_SPEED_1000MBPS
#define AR8031_PHY_STATUS
Definition: ar8031_driver.h:60
#define AR8031_ANAR_10BT_HD
void ar8031EnableIrq(NetInterface *interface)
Enable interrupts.
#define SMI_OPCODE_WRITE
Definition: nic.h:65
#define AR8031_BMCR_AN_EN
Definition: ar8031_driver.h:77
#define AR8031_INT_STATUS
Definition: ar8031_driver.h:62
#define FALSE
Definition: os_port.h:46
error_t
Error codes.
Definition: error.h:42
#define AR8031_ANAR_100BTX_FD
#define AR8031_GBCR_1000BT_FD
void ar8031Tick(NetInterface *interface)
AR8031 timer handler.
uint8_t value[]
Definition: tcp.h:332
#define AR8031_BMCR_RESET
Definition: ar8031_driver.h:74
#define AR8031_FUNC_CTRL_POLARITY_REVERSAL
void ar8031WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
Write PHY register.
#define NetInterface
Definition: net.h:36
#define AR8031_CHIP_CONF_BT_BX_REG_SEL
#define SMI_OPCODE_READ
Definition: nic.h:66
#define TRACE_INFO(...)
Definition: debug.h:95
#define AR8031_ANAR_SELECTOR_DEFAULT
#define AR8031_PHY_ADDR
Definition: ar8031_driver.h:39
#define TRACE_WARNING(...)
Definition: debug.h:85
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define AR8031_FUNC_CTRL
Definition: ar8031_driver.h:59
#define AR8031_BMSR_LINK_STATUS
Definition: ar8031_driver.h:98
#define AR8031_FUNC_CTRL_ASSERT_CRS_ON_TX
uint16_t ar8031ReadPhyReg(NetInterface *interface, uint8_t address)
Read PHY register.
#define AR8031_BMSR
Definition: ar8031_driver.h:46
#define AR8031_CHIP_CONF
Definition: ar8031_driver.h:71
#define AR8031_ANAR_100BTX_HD
void ar8031DisableIrq(NetInterface *interface)
Disable interrupts.
#define AR8031_CHIP_CONF_PRIORITY_SEL
#define AR8031_ANAR_PAUSE
#define AR8031_ANAR_ASYM_PAUSE
#define AR8031_PHY_STATUS_SPEED_100MBPS
#define AR8031_FUNC_CTRL_MDIX_MODE_AUTO
Ipv6Addr address
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define AR8031_BMCR_SPEED_SEL_LSB
Definition: ar8031_driver.h:76
#define AR8031_PHY_STATUS_SPEED_10MBPS
TCP/IP stack core.
AR8031 Gigabit Ethernet PHY driver.
#define AR8031_PHY_STATUS_SPEED
Success.
Definition: error.h:44
Debugging facilities.
#define AR8031_ANAR_XNP_ABLE
#define AR8031_BMCR
Definition: ar8031_driver.h:45