lan8670_driver.c
Go to the documentation of this file.
1 /**
2  * @file lan8670_driver.c
3  * @brief LAN8670 10Base-T1S 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.4
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 LAN8670 Ethernet PHY driver
42  **/
43 
45 {
51 };
52 
53 
54 /**
55  * @brief LAN8670 PHY transceiver initialization
56  * @param[in] interface Underlying network interface
57  * @return Error code
58  **/
59 
61 {
62  //Debug message
63  TRACE_INFO("Initializing LAN8670...\r\n");
64 
65  //Undefined PHY address?
66  if(interface->phyAddr >= 32)
67  {
68  //Use the default address
69  interface->phyAddr = LAN8670_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  //Dump PHY registers for debugging purpose
85  lan8670DumpPhyReg(interface);
86 
87  //Configure PHY transceiver
88  lan8670ModifyMmdReg(interface, 0x1F, 0x00D0, 0x0E03, 0x0002);
89  lan8670ModifyMmdReg(interface, 0x1F, 0x00D1, 0x0300, 0x0000);
90  lan8670ModifyMmdReg(interface, 0x1F, 0x0084, 0xFFC0, 0x3380);
91  lan8670ModifyMmdReg(interface, 0x1F, 0x0085, 0x000F, 0x0006);
92  lan8670ModifyMmdReg(interface, 0x1F, 0x008A, 0xF800, 0xC000);
93  lan8670ModifyMmdReg(interface, 0x1F, 0x0087, 0x801C, 0x801C);
94  lan8670ModifyMmdReg(interface, 0x1F, 0x0088, 0x1FFF, 0x033F);
95  lan8670ModifyMmdReg(interface, 0x1F, 0x008B, 0xFFFF, 0x0404);
96  lan8670ModifyMmdReg(interface, 0x1F, 0x0080, 0x0600, 0x0600);
97  lan8670ModifyMmdReg(interface, 0x1F, 0x00F1, 0x7F00, 0x2400);
98  lan8670ModifyMmdReg(interface, 0x1F, 0x0096, 0x2000, 0x2000);
99  lan8670ModifyMmdReg(interface, 0x1F, 0x0099, 0xFFFF, 0x7F80);
100 
101  //Perform custom configuration
102  lan8670InitHook(interface);
103 
104  //Force the TCP/IP stack to poll the link state at startup
105  interface->phyEvent = TRUE;
106  //Notify the TCP/IP stack of the event
108 
109  //Successful initialization
110  return NO_ERROR;
111 }
112 
113 
114 /**
115  * @brief LAN8670 custom configuration
116  * @param[in] interface Underlying network interface
117  **/
118 
119 __weak_func void lan8670InitHook(NetInterface *interface)
120 {
121 #if (LAN8670_PLCA_SUPPORT == ENABLED)
122  //Set PLCA burst
125 
126  //Set PLCA node count and local ID
130 
131  //Enable PLCA
133 #else
134  //Disable PLCA
135  lan8670WriteMmdReg(interface, LAN8670_PLCA_CTRL0, 0);
136 #endif
137 }
138 
139 
140 /**
141  * @brief LAN8670 timer handler
142  * @param[in] interface Underlying network interface
143  **/
144 
145 void lan8670Tick(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 #if (LAN8670_PLCA_SUPPORT == ENABLED)
154  //Read PLCA status register
156 
157  //The PST field indicates that the PLCA reconciliation sublayer is active
158  //and a BEACON is being regularly transmitted or received
159  linkState = (value & LAN8670_PLCA_STS_PST) ? TRUE : FALSE;
160 #else
161  //Link status indication is not supported
162  linkState = TRUE;
163 #endif
164 
165  //Link up event?
166  if(linkState && !interface->linkState)
167  {
168  //Set event flag
169  interface->phyEvent = TRUE;
170  //Notify the TCP/IP stack of the event
172  }
173  //Link down event?
174  else if(!linkState && interface->linkState)
175  {
176  //Set event flag
177  interface->phyEvent = TRUE;
178  //Notify the TCP/IP stack of the event
180  }
181  }
182 }
183 
184 
185 /**
186  * @brief Enable interrupts
187  * @param[in] interface Underlying network interface
188  **/
189 
191 {
192  //Enable PHY transceiver interrupts
193  if(interface->extIntDriver != NULL)
194  {
195  interface->extIntDriver->enableIrq();
196  }
197 }
198 
199 
200 /**
201  * @brief Disable interrupts
202  * @param[in] interface Underlying network interface
203  **/
204 
206 {
207  //Disable PHY transceiver interrupts
208  if(interface->extIntDriver != NULL)
209  {
210  interface->extIntDriver->disableIrq();
211  }
212 }
213 
214 
215 /**
216  * @brief LAN8670 event handler
217  * @param[in] interface Underlying network interface
218  **/
219 
221 {
222  uint16_t value;
223  bool_t linkState;
224 
225 #if (LAN8670_PLCA_SUPPORT == ENABLED)
226  //Read PLCA status register
228 
229  //The PST field indicates that the PLCA reconciliation sublayer is active
230  //and a BEACON is being regularly transmitted or received
231  linkState = (value & LAN8670_PLCA_STS_PST) ? TRUE : FALSE;
232 #else
233  //Link status indication is not supported
234  linkState = TRUE;
235 #endif
236 
237  //Link is up?
238  if(linkState)
239  {
240  //The PHY is only able to operate in 10 Mbps mode
241  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
242  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
243 
244  //Adjust MAC configuration parameters for proper operation
245  interface->nicDriver->updateMacConfig(interface);
246 
247  //Update link state
248  interface->linkState = TRUE;
249  }
250  else
251  {
252  //Update link state
253  interface->linkState = FALSE;
254  }
255 
256  //Process link state change event
257  nicNotifyLinkChange(interface);
258 }
259 
260 
261 /**
262  * @brief Write PHY register
263  * @param[in] interface Underlying network interface
264  * @param[in] address PHY register address
265  * @param[in] data Register value
266  **/
267 
268 void lan8670WritePhyReg(NetInterface *interface, uint8_t address,
269  uint16_t data)
270 {
271  //Write the specified PHY register
272  if(interface->smiDriver != NULL)
273  {
274  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE,
275  interface->phyAddr, address, data);
276  }
277  else
278  {
279  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE,
280  interface->phyAddr, address, data);
281  }
282 }
283 
284 
285 /**
286  * @brief Read PHY register
287  * @param[in] interface Underlying network interface
288  * @param[in] address PHY register address
289  * @return Register value
290  **/
291 
292 uint16_t lan8670ReadPhyReg(NetInterface *interface, uint8_t address)
293 {
294  uint16_t data;
295 
296  //Read the specified PHY register
297  if(interface->smiDriver != NULL)
298  {
299  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ,
300  interface->phyAddr, address);
301  }
302  else
303  {
304  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ,
305  interface->phyAddr, address);
306  }
307 
308  //Return the value of the PHY register
309  return data;
310 }
311 
312 
313 /**
314  * @brief Dump PHY registers for debugging purpose
315  * @param[in] interface Underlying network interface
316  **/
317 
319 {
320  uint8_t i;
321 
322  //Loop through PHY registers
323  for(i = 0; i < 32; i++)
324  {
325  //Display current PHY register
326  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
327  lan8670ReadPhyReg(interface, i));
328  }
329 
330  //Terminate with a line feed
331  TRACE_DEBUG("\r\n");
332 }
333 
334 
335 /**
336  * @brief Write MMD register
337  * @param[in] interface Underlying network interface
338  * @param[in] devAddr Device address
339  * @param[in] regAddr Register address
340  * @param[in] data MMD register value
341  **/
342 
343 void lan8670WriteMmdReg(NetInterface *interface, uint8_t devAddr,
344  uint16_t regAddr, uint16_t data)
345 {
346  //Select register operation
349 
350  //Write MMD register address
352 
353  //Select data operation
356 
357  //Write the content of the MMD register
359 }
360 
361 
362 /**
363  * @brief Read MMD register
364  * @param[in] interface Underlying network interface
365  * @param[in] devAddr Device address
366  * @param[in] regAddr Register address
367  * @return MMD register value
368  **/
369 
370 uint16_t lan8670ReadMmdReg(NetInterface *interface, uint8_t devAddr,
371  uint16_t regAddr)
372 {
373  //Select register operation
376 
377  //Write MMD register address
379 
380  //Select data operation
383 
384  //Read the content of the MMD register
385  return lan8670ReadPhyReg(interface, LAN8670_MMDAD);
386 }
387 
388 
389 /**
390  * @brief Modify MMD register
391  * @param[in] interface Underlying network interface
392  * @param[in] devAddr Device address
393  * @param[in] regAddr Register address
394  * @param[in] mask 16-bit mask
395  * @param[in] data 16-bit value
396  **/
397 
398 void lan8670ModifyMmdReg(NetInterface *interface, uint8_t devAddr,
399  uint16_t regAddr, uint16_t mask, uint16_t data)
400 {
401  uint16_t value;
402 
403  //Read the current value of the MMD register
404  value = lan8670ReadMmdReg(interface, devAddr, regAddr);
405  //Modify register value
406  value = (value & ~mask) | data;
407  //Write the modified value back to the MMD register
408  lan8670WriteMmdReg(interface, devAddr, regAddr, value);
409 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:559
const PhyDriver lan8670PhyDriver
LAN8670 Ethernet PHY driver.
__weak_func void lan8670InitHook(NetInterface *interface)
LAN8670 custom configuration.
int bool_t
Definition: compiler_port.h:53
#define LAN8670_PLCA_CTRL1_NCNT
#define netEvent
Definition: net_legacy.h:196
#define LAN8670_PLCA_CTRL0_EN
#define LAN8670_MMDCTRL_FNCTN_DATA_NO_POST_INC
#define TRUE
Definition: os_port.h:50
Ethernet PHY driver.
Definition: nic.h:311
uint8_t data[]
Definition: ethernet.h:222
void lan8670Tick(NetInterface *interface)
LAN8670 timer handler.
void lan8670ModifyMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr, uint16_t mask, uint16_t data)
Modify MMD register.
#define LAN8670_PLCA_BURST_BTMR_DEFAULT
#define LAN8670_PLCA_CTRL1
#define LAN8670_MMDAD
void lan8670EnableIrq(NetInterface *interface)
Enable interrupts.
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define LAN8670_NODE_COUNT
void lan8670WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
Write PHY register.
#define FALSE
Definition: os_port.h:46
error_t
Error codes.
Definition: error.h:43
uint16_t lan8670ReadPhyReg(NetInterface *interface, uint8_t address)
Read PHY register.
#define NetInterface
Definition: net.h:36
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
LAN8670 10Base-T1S Ethernet PHY driver.
uint16_t lan8670ReadMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
uint8_t mask
Definition: web_socket.h:319
#define SMI_OPCODE_READ
Definition: nic.h:67
#define LAN8670_PLCA_STS_PST
void lan8670DisableIrq(NetInterface *interface)
Disable interrupts.
#define TRACE_INFO(...)
Definition: debug.h:95
#define LAN8670_PLCA_CTRL1_ID
void lan8670EventHandler(NetInterface *interface)
LAN8670 event handler.
#define LAN8670_PLCA_BURST_MAXBC_DISABLED
#define LAN8670_PHY_ADDR
void lan8670WriteMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
error_t lan8670Init(NetInterface *interface)
LAN8670 PHY transceiver initialization.
#define LAN8670_MMDCTRL
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define LAN8670_PLCA_STS
uint16_t regAddr
Ipv6Addr address[]
Definition: ipv6.h:325
#define LAN8670_MMDCTRL_FNCTN_ADDR
#define LAN8670_PLCA_CTRL0
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
uint8_t value[]
Definition: tcp.h:369
#define LAN8670_MMDCTRL_DEVAD
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void lan8670DumpPhyReg(NetInterface *interface)
Dump PHY registers for debugging purpose.
TCP/IP stack core.
#define LAN8670_LOCAL_ID
#define LAN8670_PLCA_BURST
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.