ar8035_driver.c
Go to the documentation of this file.
1 /**
2  * @file ar8035_driver.c
3  * @brief AR8035 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 AR8035 Ethernet PHY driver
42  **/
43 
45 {
46  ar8035Init,
47  ar8035Tick,
51 };
52 
53 
54 /**
55  * @brief AR8035 PHY transceiver initialization
56  * @param[in] interface Underlying network interface
57  * @return Error code
58  **/
59 
61 {
62  //Debug message
63  TRACE_INFO("Initializing AR8035...\r\n");
64 
65  //Undefined PHY address?
66  if(interface->phyAddr >= 32)
67  {
68  //Use the default address
69  interface->phyAddr = AR8035_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  ar8035DumpPhyReg(interface);
94 
95  //Basic mode control register
98 
99  //Auto-negotiation advertisement register
104 
105  //1000 BASE-T control register
107 
108  //Function control register
112 
113  //The PHY will generate interrupts when link status changes are detected
116 
117  //Perform custom configuration
118  ar8035InitHook(interface);
119 
120  //Force the TCP/IP stack to poll the link state at startup
121  interface->phyEvent = TRUE;
122  //Notify the TCP/IP stack of the event
124 
125  //Successful initialization
126  return NO_ERROR;
127 }
128 
129 
130 /**
131  * @brief AR8035 custom configuration
132  * @param[in] interface Underlying network interface
133  **/
134 
135 __weak_func void ar8035InitHook(NetInterface *interface)
136 {
137 }
138 
139 
140 /**
141  * @brief AR8035 timer handler
142  * @param[in] interface Underlying network interface
143  **/
144 
145 void ar8035Tick(NetInterface *interface)
146 {
147  uint16_t value;
148  bool_t linkState;
149 
150  //No external interrupt line driver?
151  if(interface->extIntDriver == NULL)
152  {
153  //Read basic status register
154  value = ar8035ReadPhyReg(interface, AR8035_BMSR);
155  //Retrieve current link state
156  linkState = (value & AR8035_BMSR_LINK_STATUS) ? TRUE : FALSE;
157 
158  //Link up event?
159  if(linkState && !interface->linkState)
160  {
161  //Set event flag
162  interface->phyEvent = TRUE;
163  //Notify the TCP/IP stack of the event
165  }
166  //Link down event?
167  else if(!linkState && interface->linkState)
168  {
169  //Set event flag
170  interface->phyEvent = TRUE;
171  //Notify the TCP/IP stack of the event
173  }
174  }
175 }
176 
177 
178 /**
179  * @brief Enable interrupts
180  * @param[in] interface Underlying network interface
181  **/
182 
184 {
185  //Enable PHY transceiver interrupts
186  if(interface->extIntDriver != NULL)
187  {
188  interface->extIntDriver->enableIrq();
189  }
190 }
191 
192 
193 /**
194  * @brief Disable interrupts
195  * @param[in] interface Underlying network interface
196  **/
197 
199 {
200  //Disable PHY transceiver interrupts
201  if(interface->extIntDriver != NULL)
202  {
203  interface->extIntDriver->disableIrq();
204  }
205 }
206 
207 
208 /**
209  * @brief AR8035 event handler
210  * @param[in] interface Underlying network interface
211  **/
212 
214 {
215  uint16_t status;
216 
217  //Read status register to acknowledge the interrupt
218  status = ar8035ReadPhyReg(interface, AR8035_INT_STATUS);
219 
220  //Link status change?
222  {
223  //Read PHY status register
224  status = ar8035ReadPhyReg(interface, AR8035_PHY_STATUS);
225 
226  //Link is up?
227  if((status & AR8035_PHY_STATUS_LINK) != 0)
228  {
229  //Check current speed
230  switch(status & AR8035_PHY_STATUS_SPEED)
231  {
232  //10BASE-T
234  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
235  break;
236  //100BASE-TX
238  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
239  break;
240  //1000BASE-T
242  interface->linkSpeed = NIC_LINK_SPEED_1GBPS;
243  break;
244  //Unknown speed
245  default:
246  //Debug message
247  TRACE_WARNING("Invalid speed\r\n");
248  break;
249  }
250 
251  //Check current duplex mode
252  if((status & AR8035_PHY_STATUS_DUPLEX) != 0)
253  {
254  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
255  }
256  else
257  {
258  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
259  }
260 
261  //Update link state
262  interface->linkState = TRUE;
263 
264  //Adjust MAC configuration parameters for proper operation
265  interface->nicDriver->updateMacConfig(interface);
266  }
267  else
268  {
269  //Update link state
270  interface->linkState = FALSE;
271  }
272 
273  //Process link state change event
274  nicNotifyLinkChange(interface);
275  }
276 }
277 
278 
279 /**
280  * @brief Write PHY register
281  * @param[in] interface Underlying network interface
282  * @param[in] address PHY register address
283  * @param[in] data Register value
284  **/
285 
286 void ar8035WritePhyReg(NetInterface *interface, uint8_t address,
287  uint16_t data)
288 {
289  //Write the specified PHY register
290  if(interface->smiDriver != NULL)
291  {
292  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE,
293  interface->phyAddr, address, data);
294  }
295  else
296  {
297  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE,
298  interface->phyAddr, address, data);
299  }
300 }
301 
302 
303 /**
304  * @brief Read PHY register
305  * @param[in] interface Underlying network interface
306  * @param[in] address PHY register address
307  * @return Register value
308  **/
309 
310 uint16_t ar8035ReadPhyReg(NetInterface *interface, uint8_t address)
311 {
312  uint16_t data;
313 
314  //Read the specified PHY register
315  if(interface->smiDriver != NULL)
316  {
317  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ,
318  interface->phyAddr, address);
319  }
320  else
321  {
322  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ,
323  interface->phyAddr, address);
324  }
325 
326  //Return the value of the PHY register
327  return data;
328 }
329 
330 
331 /**
332  * @brief Dump PHY registers for debugging purpose
333  * @param[in] interface Underlying network interface
334  **/
335 
337 {
338  uint8_t i;
339 
340  //Loop through PHY registers
341  for(i = 0; i < 32; i++)
342  {
343  //Display current PHY register
344  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
345  ar8035ReadPhyReg(interface, i));
346  }
347 
348  //Terminate with a line feed
349  TRACE_DEBUG("\r\n");
350 }
351 
352 
353 /**
354  * @brief Write MMD register
355  * @param[in] interface Underlying network interface
356  * @param[in] devAddr Device address
357  * @param[in] regAddr Register address
358  * @param[in] data MMD register value
359  **/
360 
361 void ar8035WriteMmdReg(NetInterface *interface, uint8_t devAddr,
362  uint16_t regAddr, uint16_t data)
363 {
364  //Select register operation
365  ar8035WritePhyReg(interface, AR8035_MMDACR,
367 
368  //Write MMD register address
370 
371  //Select data operation
372  ar8035WritePhyReg(interface, AR8035_MMDACR,
374 
375  //Write the content of the MMD register
377 }
378 
379 
380 /**
381  * @brief Read MMD register
382  * @param[in] interface Underlying network interface
383  * @param[in] devAddr Device address
384  * @param[in] regAddr Register address
385  * @return MMD register value
386  **/
387 
388 uint16_t ar8035ReadMmdReg(NetInterface *interface, uint8_t devAddr,
389  uint16_t regAddr)
390 {
391  //Select register operation
392  ar8035WritePhyReg(interface, AR8035_MMDACR,
394 
395  //Write MMD register address
397 
398  //Select data operation
399  ar8035WritePhyReg(interface, AR8035_MMDACR,
401 
402  //Read the content of the MMD register
403  return ar8035ReadPhyReg(interface, AR8035_MMDAADR);
404 }
uint16_t ar8035ReadPhyReg(NetInterface *interface, uint8_t address)
Read PHY register.
void ar8035DumpPhyReg(NetInterface *interface)
Dump PHY registers for debugging purpose.
void ar8035EnableIrq(NetInterface *interface)
Enable interrupts.
__weak_func void ar8035InitHook(NetInterface *interface)
AR8035 custom configuration.
void ar8035EventHandler(NetInterface *interface)
AR8035 event handler.
uint16_t ar8035ReadMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
void ar8035DisableIrq(NetInterface *interface)
Disable interrupts.
error_t ar8035Init(NetInterface *interface)
AR8035 PHY transceiver initialization.
Definition: ar8035_driver.c:60
const PhyDriver ar8035PhyDriver
AR8035 Ethernet PHY driver.
Definition: ar8035_driver.c:44
void ar8035WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
Write PHY register.
void ar8035WriteMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
void ar8035Tick(NetInterface *interface)
AR8035 timer handler.
AR8035 Gigabit Ethernet PHY driver.
#define AR8035_BMSR_LINK_STATUS
#define AR8035_INT_STATUS_LINK_SUCCESS
#define AR8035_BMSR
Definition: ar8035_driver.h:46
#define AR8035_INT_STATUS_LINK_FAIL
#define AR8035_PHY_STATUS_SPEED
#define AR8035_ANAR_XNP_ABLE
#define AR8035_PHY_STATUS
Definition: ar8035_driver.h:60
#define AR8035_BMCR_DUPLEX_MODE
Definition: ar8035_driver.h:95
#define AR8035_ANAR_100BTX_FD
#define AR8035_GBCR
Definition: ar8035_driver.h:54
#define AR8035_ANAR_10BT_FD
#define AR8035_ANAR_10BT_HD
#define AR8035_ANAR_SELECTOR_DEFAULT
#define AR8035_ANAR_100BTX_HD
#define AR8035_BMCR_AN_EN
Definition: ar8035_driver.h:91
#define AR8035_INT_EN
Definition: ar8035_driver.h:61
#define AR8035_PHY_ADDR
Definition: ar8035_driver.h:39
#define AR8035_PHY_STATUS_DUPLEX
#define AR8035_MMDACR_FUNC_ADDR
#define AR8035_ANAR_ASYM_PAUSE
#define AR8035_MMDACR_FUNC_DATA_NO_POST_INC
#define AR8035_GBCR_1000BT_FD
#define AR8035_PHY_STATUS_SPEED_1000MBPS
#define AR8035_ANAR
Definition: ar8035_driver.h:49
#define AR8035_BMCR_SPEED_SEL_LSB
Definition: ar8035_driver.h:90
#define AR8035_FUNC_CTRL
Definition: ar8035_driver.h:59
#define AR8035_BMCR_RESET
Definition: ar8035_driver.h:88
#define AR8035_FUNC_CTRL_ASSERT_CRS_ON_TX
#define AR8035_PHY_STATUS_LINK
#define AR8035_FUNC_CTRL_POLARITY_REVERSAL
#define AR8035_FUNC_CTRL_MDIX_MODE_AUTO
#define AR8035_PHY_STATUS_SPEED_10MBPS
#define AR8035_MMDAADR
Definition: ar8035_driver.h:57
#define AR8035_PHY_STATUS_SPEED_100MBPS
#define AR8035_MMDACR
Definition: ar8035_driver.h:56
#define AR8035_INT_STATUS
Definition: ar8035_driver.h:62
#define AR8035_BMCR
Definition: ar8035_driver.h:45
#define AR8035_ANAR_PAUSE
#define AR8035_MMDACR_DEVAD
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