lan8650_driver.c
Go to the documentation of this file.
1 /**
2  * @file lan8650_driver.c
3  * @brief LAN8650 10Base-T1S Ethernet controller
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 LAN8650 driver
42  **/
43 
45 {
47  ETH_MTU,
55  NULL,
56  NULL,
57  NULL,
58  TRUE,
59  TRUE,
60  TRUE,
61  FALSE
62 };
63 
64 
65 /**
66  * @brief LAN8650 controller initialization
67  * @param[in] interface Underlying network interface
68  * @return Error code
69  **/
70 
72 {
73  uint32_t value;
74 
75  //Debug message
76  TRACE_INFO("Initializing LAN8650 Ethernet controller...\r\n");
77 
78  //Initialize SPI interface
79  interface->spiDriver->init();
80 
81  //Initialize external interrupt line driver
82  if(interface->extIntDriver != NULL)
83  {
84  interface->extIntDriver->init();
85  }
86 
87  //Issue a device reset
89 
90  //Wait for the reset to complete
91  do
92  {
93  //Read reset control and status register
95 
96  //The SWRESET self-clears when the reset finishes
97  } while((value & LAN8650_OA_RESET_SWRESET) != 0);
98 
99  //Read the STATUS0 register and confirm that the RESETC field is 1
100  do
101  {
102  //Read the status register 0
104 
105  //Check the value of the RESETC bit
106  } while((value & LAN8650_OA_STATUS0_RESETC) == 0);
107 
108  //Write 1 to the RESETC field in the STATUS0 register to clear this field
110 
111  //Dump MMS0 registers for debugging purpose
112  TRACE_DEBUG("MMS0 registers:\r\n");
113  lan8650DumpReg(interface, LAN8650_MMS_STD, 0, 16);
114 
115  //Configuration process
116  lan8650Config(interface);
117 
118 #if (LAN8650_PLCA_SUPPORT == ENABLED)
119  //Set PLCA burst
122 
123  //Set PLCA node count and local ID
127 
128  //Enable PLCA
130 #else
131  //Disable PLCA
132  lan8650WriteReg(interface, LAN8650_PLCA_CTRL0, 0);
133 #endif
134 
135  //Perform custom configuration
136  lan8650InitHook(interface);
137 
138  //Configure MAC address filtering
139  lan8650UpdateMacAddrFilter(interface);
140 
141  //Configure the receive filter
144 
145  //Configure the SPI protocol engine
149 
150  //When the MAC is configured, write 1 to the SYNC field in the CONFIG0
151  //register to indicate that the MAC configuration is complete
155 
156  //Enable TX and RX
157  value = lan8650ReadReg(interface, LAN8650_MAC_NCR);
160 
161  //Accept any packets from the upper layer
162  osSetEvent(&interface->nicTxEvent);
163 
164  //Force the TCP/IP stack to poll the status at startup
165  interface->nicEvent = TRUE;
166  //Notify the TCP/IP stack of the event
168 
169  //Successful initialization
170  return NO_ERROR;
171 }
172 
173 
174 /**
175  * @brief LAN8650 custom configuration
176  * @param[in] interface Underlying network interface
177  **/
178 
179 __weak_func void lan8650InitHook(NetInterface *interface)
180 {
181 }
182 
183 
184 /**
185  * @brief LAN8650 controller configuration
186  * @param[in] interface Underlying network interface
187  **/
188 
189 void lan8650Config(NetInterface *interface)
190 {
191  int8_t value1;
192  int8_t value2;
193  uint16_t value3;
194  uint16_t value4;
195  uint16_t value5;
196  uint16_t value6;
197  uint16_t value7;
198  int8_t offset1;
199  int8_t offset2;
200  uint16_t param1;
201  uint16_t param2;
202  uint16_t param3;
203  uint16_t param4;
204  uint16_t param5;
205 
206  //The configuration process begins with reading some registers
207  value1 = lan8650ReadIndirectReg(interface, 0x04);
208  value2 = lan8650ReadIndirectReg(interface, 0x08);
209  value3 = lan8650ReadReg(interface, 0x04, 0x0084);
210  value4 = lan8650ReadReg(interface, 0x04, 0x008A);
211  value5 = lan8650ReadReg(interface, 0x04, 0x00AD);
212  value6 = lan8650ReadReg(interface, 0x04, 0x00AE);
213  value7 = lan8650ReadReg(interface, 0x04, 0x00AF);
214 
215  //Calculation of configuration offset 1
216  if((value1 & 0x10) != 0)
217  {
218  offset1 = value1 | 0xE0;
219  }
220  else
221  {
222  offset1 = value1;
223  }
224 
225  //Calculation of configuration offset 2
226  if((value2 & 0x10) != 0)
227  {
228  offset2 = value2 | 0xE0;
229  }
230  else
231  {
232  offset2 = value2;
233  }
234 
235  //Calculation of configuration parameters
236  param1 = (value3 & 0xF) | (((9 + offset1) << 10) | ((14 + offset1) << 4));
237  param2 = (value4 & 0x3FF) | ((40 + offset2) << 10);
238  param3 = (value5 & 0xC0C0) | (((5 + offset1) << 8) | (9 + offset1));
239  param4 = (value6 & 0xC0C0) | (((9 + offset1) << 8) | (14 + offset1));
240  param5 = (value7 & 0xC0C0) | (((17 + offset1) << 8) | (22 + offset1));
241 
242  //The configuration parameters, along with other constant values are then
243  //written to the device
244  lan8650WriteReg(interface, 0x04, 0x0091, 0x9660);
245  lan8650WriteReg(interface, 0x04, 0x0081, 0x00C0);
246  lan8650WriteReg(interface, 0x01, 0x0077, 0x0028);
247  lan8650WriteReg(interface, 0x04, 0x0043, 0x00FF);
248  lan8650WriteReg(interface, 0x04, 0x0044, 0xFFFF);
249  lan8650WriteReg(interface, 0x04, 0x0045, 0x0000);
250  lan8650WriteReg(interface, 0x04, 0x0053, 0x00FF);
251  lan8650WriteReg(interface, 0x04, 0x0054, 0xFFFF);
252  lan8650WriteReg(interface, 0x04, 0x0055, 0x0000);
253  lan8650WriteReg(interface, 0x04, 0x0040, 0x0002);
254  lan8650WriteReg(interface, 0x04, 0x0050, 0x0002);
255  lan8650WriteReg(interface, 0x04, 0x00D0, 0x5F21);
256  lan8650WriteReg(interface, 0x04, 0x0084, param1);
257  lan8650WriteReg(interface, 0x04, 0x008A, param2);
258  lan8650WriteReg(interface, 0x04, 0x00E9, 0x9E50);
259  lan8650WriteReg(interface, 0x04, 0x00F5, 0x1CF8);
260  lan8650WriteReg(interface, 0x04, 0x00F4, 0xC020);
261  lan8650WriteReg(interface, 0x04, 0x00F8, 0x9B00);
262  lan8650WriteReg(interface, 0x04, 0x00F9, 0x4E53);
263  lan8650WriteReg(interface, 0x04, 0x00AD, param3);
264  lan8650WriteReg(interface, 0x04, 0x00AE, param4);
265  lan8650WriteReg(interface, 0x04, 0x00AF, param5);
266  lan8650WriteReg(interface, 0x04, 0x00B0, 0x0103);
267  lan8650WriteReg(interface, 0x04, 0x00B1, 0x0910);
268  lan8650WriteReg(interface, 0x04, 0x00B2, 0x1D26);
269  lan8650WriteReg(interface, 0x04, 0x00B3, 0x002A);
270  lan8650WriteReg(interface, 0x04, 0x00B4, 0x0103);
271  lan8650WriteReg(interface, 0x04, 0x00B5, 0x070D);
272  lan8650WriteReg(interface, 0x04, 0x00B6, 0x1720);
273  lan8650WriteReg(interface, 0x04, 0x00B7, 0x0027);
274  lan8650WriteReg(interface, 0x04, 0x00B8, 0x0509);
275  lan8650WriteReg(interface, 0x04, 0x00B9, 0x0E13);
276  lan8650WriteReg(interface, 0x04, 0x00BA, 0x1C25);
277  lan8650WriteReg(interface, 0x04, 0x00BB, 0x002B);
278 }
279 
280 
281 /**
282  * @brief LAN8650 timer handler
283  * @param[in] interface Underlying network interface
284  **/
285 
286 void lan8650Tick(NetInterface *interface)
287 {
288  uint32_t value;
289  bool_t linkState;
290 
291 #if (LAN8650_PLCA_SUPPORT == ENABLED)
292  //Read PLCA status register
293  value = lan8650ReadReg(interface, LAN8650_PLCA_STS);
294 
295  //The PST field indicates that the PLCA reconciliation sublayer is active
296  //and a BEACON is being regularly transmitted or received
297  linkState = (value & LAN8650_PLCA_STS_PST) ? TRUE : FALSE;
298 #else
299  //Link status indication is not supported
300  linkState = TRUE;
301 #endif
302 
303  //Link up event?
304  if(linkState && !interface->linkState)
305  {
306  //The PHY is only able to operate in 10 Mbps mode
307  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
308  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
309 
310  //Update link state
311  interface->linkState = TRUE;
312 
313  //Process link state change event
314  nicNotifyLinkChange(interface);
315  }
316  //Link down event?
317  else if(!linkState && interface->linkState)
318  {
319  //Update link state
320  interface->linkState = FALSE;
321 
322  //Process link state change event
323  nicNotifyLinkChange(interface);
324  }
325 }
326 
327 
328 /**
329  * @brief Enable interrupts
330  * @param[in] interface Underlying network interface
331  **/
332 
334 {
335  //Enable interrupts
336  if(interface->extIntDriver != NULL)
337  {
338  interface->extIntDriver->enableIrq();
339  }
340 }
341 
342 
343 /**
344  * @brief Disable interrupts
345  * @param[in] interface Underlying network interface
346  **/
347 
349 {
350  //Disable interrupts
351  if(interface->extIntDriver != NULL)
352  {
353  interface->extIntDriver->disableIrq();
354  }
355 }
356 
357 
358 /**
359  * @brief LAN8650 interrupt service routine
360  * @param[in] interface Underlying network interface
361  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
362  **/
363 
365 {
366  //When the SPI host detects an asserted IRQn from the MACPHY, it should
367  //initiate a data chunk transfer to obtain the current data footer
368  interface->nicEvent = TRUE;
369 
370  //Notify the TCP/IP stack of the event
371  return osSetEventFromIsr(&netEvent);
372 }
373 
374 
375 /**
376  * @brief LAN8650 event handler
377  * @param[in] interface Underlying network interface
378  **/
379 
381 {
382  uint32_t status;
383 
384  //Process all the data chunks
385  do
386  {
387  //Read incoming packet
388  lan8650ReceivePacket(interface);
389 
390  //Read buffer status register
391  status = lan8650ReadReg(interface, LAN8650_OA_BUFSTS);
392 
393  //Any data chunk available to the host MCU for reading?
394  } while((status & LAN8650_OA_BUFSTS_RCA) != 0);
395 }
396 
397 
398 /**
399  * @brief Send a packet
400  * @param[in] interface Underlying network interface
401  * @param[in] buffer Multi-part buffer containing the data to send
402  * @param[in] offset Offset to the first data byte
403  * @param[in] ancillary Additional options passed to the stack along with
404  * the packet
405  * @return Error code
406  **/
407 
409  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
410 {
411  static uint8_t chunk[LAN8650_CHUNK_PAYLOAD_SIZE + 4];
412  size_t i;
413  size_t j;
414  size_t n;
415  size_t length;
416  uint32_t status;
417  uint32_t header;
418  uint32_t footer;
419 
420  //Retrieve the length of the packet
421  length = netBufferGetLength(buffer) - offset;
422 
423  //Read buffer status register
424  status = lan8650ReadReg(interface, LAN8650_OA_BUFSTS);
425  //Get the number of data chunks available in the transmit buffer
426  n = (status & LAN8650_OA_BUFSTS_TXC) >> 8;
427 
428  //Check the number of transmit credits available
430  {
431  //A data transaction consists of multiple chunks
432  for(i = 0; i < length; i += n)
433  {
434  //The default size of the data chunk payload is 64 bytes
436 
437  //Set up a data transfer
440 
441  //Start of packet?
442  if(i == 0)
443  {
444  //The SPI host shall set the SV bit when the beginning of an
445  //Ethernet frame is present in the current transmit data chunk
446  //payload
447  header |= LAN8650_TX_HEADER_SV;
448  }
449 
450  //End of packet?
451  if((i + n) == length)
452  {
453  //The SPI host shall set the EV bit when the end of an Ethernet
454  //frame is present in the current transmit data chunk payload
455  header |= LAN8650_TX_HEADER_EV;
456 
457  //When EV is 1, the EBO field shall contain the byte offset into
458  //the transmit data chunk payload that points to the last byte of
459  //the Ethernet frame to transmit
460  header |= ((n - 1) << 8) & LAN8650_TX_HEADER_EBO;
461  }
462 
463  //The parity bit is calculated over the transmit data header
464  if(lan8650CalcParity(header) != 0)
465  {
466  header |= LAN8650_CTRL_HEADER_P;
467  }
468 
469  //A chunk is composed of 4 bytes of overhead plus the configured
470  //payload size
471  STORE32BE(header, chunk);
472 
473  //Copy data chunk payload
474  netBufferRead(chunk + 4, buffer, offset + i, n);
475 
476  //Pad frames shorter than the data chunk payload
478  {
479  osMemset(chunk + 4 + n, 0, LAN8650_CHUNK_PAYLOAD_SIZE - n);
480  }
481 
482  //Pull the CS pin low
483  interface->spiDriver->assertCs();
484 
485  //Perform data transfer
486  for(j = 0; j < (LAN8650_CHUNK_PAYLOAD_SIZE + 4); j++)
487  {
488  chunk[j] = interface->spiDriver->transfer(chunk[j]);
489  }
490 
491  //Terminate the operation by raising the CS pin
492  interface->spiDriver->deassertCs();
493 
494  //Receive data chunks consist of the receive data chunk payload followed
495  //by a 4-byte footer
496  footer = LOAD32BE(chunk + LAN8650_CHUNK_PAYLOAD_SIZE);
497 
498  //The RCA field indicates the number of receive data chunks available
499  if((footer & LAN8650_RX_FOOTER_RCA) != 0)
500  {
501  //Some data chunks are available for reading
502  interface->nicEvent = TRUE;
503  //Notify the TCP/IP stack of the event
505  }
506  }
507  }
508  else
509  {
510  //No sufficient credits available
511  }
512 
513  //The transmitter can accept another packet
514  osSetEvent(&interface->nicTxEvent);
515 
516  //Successful processing
517  return NO_ERROR;
518 }
519 
520 
521 /**
522  * @brief Receive a packet
523  * @param[in] interface Underlying network interface
524  * @return Error code
525  **/
526 
528 {
529  static uint8_t buffer[LAN8650_ETH_RX_BUFFER_SIZE];
530  static uint8_t chunk[LAN8650_CHUNK_PAYLOAD_SIZE + 4];
531  error_t error;
532  size_t i;
533  size_t n;
534  size_t length;
535  uint32_t header;
536  uint32_t footer;
537 
538  //Initialize variable
539  length = 0;
540 
541  //A data transaction consists of multiple chunks
542  while(1)
543  {
544  //Check the length of the received packet
546  {
547  error = ERROR_BUFFER_OVERFLOW;
548  break;
549  }
550 
551  //The SPI host sets NORX to 0 to indicate that it accepts and process
552  //any receive frame data within the current chunk
553  header = LAN8650_TX_HEADER_DNC;
554 
555  //The parity bit is calculated over the transmit data header
556  if(lan8650CalcParity(header) != 0)
557  {
558  header |= LAN8650_CTRL_HEADER_P;
559  }
560 
561  //Transmit data chunks consist of a 4-byte header followed by the
562  //transmit data chunk payload,
563  STORE32BE(header, chunk);
564 
565  //Clear data chunk payload
566  osMemset(chunk + 4, 0, LAN8650_CHUNK_PAYLOAD_SIZE);
567 
568  //Pull the CS pin low
569  interface->spiDriver->assertCs();
570 
571  //Perform data transfer
572  for(i = 0; i < (LAN8650_CHUNK_PAYLOAD_SIZE + 4); i++)
573  {
574  chunk[i] = interface->spiDriver->transfer(chunk[i]);
575  }
576 
577  //Terminate the operation by raising the CS pin
578  interface->spiDriver->deassertCs();
579 
580  //Receive data chunks consist of the receive data chunk payload followed
581  //by a 4-byte footer
582  footer = LOAD32BE(chunk + LAN8650_CHUNK_PAYLOAD_SIZE);
583 
584  //When the DV bit is 0, the SPI host ignores the chunk payload
585  if((footer & LAN8650_RX_FOOTER_DV) == 0)
586  {
587  error = ERROR_BUFFER_EMPTY;
588  break;
589  }
590 
591  //When the SV bit is 1, the beginning of an Ethernet frame is present in
592  //the current transmit data chunk payload
593  if(length == 0)
594  {
595  if((footer & LAN8650_RX_FOOTER_SV) == 0)
596  {
597  error = ERROR_INVALID_PACKET;
598  break;
599  }
600  }
601  else
602  {
603  if((footer & LAN8650_RX_FOOTER_SV) != 0)
604  {
605  error = ERROR_INVALID_PACKET;
606  break;
607  }
608  }
609 
610  //When EV is 1, the EBO field contains the byte offset into the
611  //receive data chunk payload that points to the last byte of the
612  //received Ethernet frame
613  if((footer & LAN8650_RX_FOOTER_EV) != 0)
614  {
615  n = ((footer & LAN8650_RX_FOOTER_EBO) >> 8) + 1;
616  }
617  else
618  {
620  }
621 
622  //Copy data chunk payload
623  osMemcpy(buffer + length, chunk, n);
624  //Adjust the length of the packet
625  length += n;
626 
627  //When the EV bit is 1, the end of an Ethernet frame is present in the
628  //current receive data chunk payload
629  if((footer & LAN8650_RX_FOOTER_EV) != 0)
630  {
631  NetRxAncillary ancillary;
632 
633  //Additional options can be passed to the stack along with the packet
634  ancillary = NET_DEFAULT_RX_ANCILLARY;
635  //Pass the packet to the upper layer
636  nicProcessPacket(interface, buffer, length, &ancillary);
637 
638  //Successful processing
639  error = NO_ERROR;
640  break;
641  }
642  }
643 
644  //Return status code
645  return error;
646 }
647 
648 
649 /**
650  * @brief Configure MAC address filtering
651  * @param[in] interface Underlying network interface
652  * @return Error code
653  **/
654 
656 {
657  uint_t i;
658  uint_t j;
659  uint_t k;
660  uint8_t *p;
661  uint32_t hashTable[2];
662  MacAddr unicastMacAddr[3];
663  MacFilterEntry *entry;
664 
665  //Debug message
666  TRACE_DEBUG("Updating MAC filter...\r\n");
667 
668  //Set the lower 32 bits of the station MAC address
670  (interface->macAddr.b[3] << 24) | (interface->macAddr.b[2] << 16) |
671  (interface->macAddr.b[1] << 8) | interface->macAddr.b[0]);
672 
673  //Set the upper 16 bits of the station MAC address
675  (interface->macAddr.b[5] << 8) | interface->macAddr.b[4]);
676 
677  //The MAC supports 3 additional addresses for unicast perfect filtering
678  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
679  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
680  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
681 
682  //The hash table is used for multicast address filtering
683  hashTable[0] = 0;
684  hashTable[1] = 0;
685 
686  //The MAC address filter contains the list of MAC addresses to accept
687  //when receiving an Ethernet frame
688  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
689  {
690  //Point to the current entry
691  entry = &interface->macAddrFilter[i];
692 
693  //Valid entry?
694  if(entry->refCount > 0)
695  {
696  //Multicast address?
697  if(macIsMulticastAddr(&entry->addr))
698  {
699  //Point to the MAC address
700  p = entry->addr.b;
701 
702  //Apply the hash function
703  k = (p[0] >> 6) ^ p[0];
704  k ^= (p[1] >> 4) ^ (p[1] << 2);
705  k ^= (p[2] >> 2) ^ (p[2] << 4);
706  k ^= (p[3] >> 6) ^ p[3];
707  k ^= (p[4] >> 4) ^ (p[4] << 2);
708  k ^= (p[5] >> 2) ^ (p[5] << 4);
709 
710  //The hash value is reduced to a 6-bit index
711  k &= 0x3F;
712 
713  //Update hash table contents
714  hashTable[k / 32] |= (1 << (k % 32));
715  }
716  else
717  {
718  //Up to 3 additional MAC addresses can be specified
719  if(j < 3)
720  {
721  //Save the unicast address
722  unicastMacAddr[j++] = entry->addr;
723  }
724  }
725  }
726  }
727 
728  //Configure the first unicast address filter
729  if(j >= 1)
730  {
731  //Set the lower 32 bits of the MAC address
733  (unicastMacAddr[0].b[3] << 24) | (unicastMacAddr[0].b[2] << 16) |
734  (unicastMacAddr[0].b[1] << 8) | unicastMacAddr[0].b[0]);
735 
736  //The address is activated when SAT register is written
738  (unicastMacAddr[0].b[5] << 8) | unicastMacAddr[0].b[4]);
739  }
740  else
741  {
742  //The address is deactivated when SAB register is written
743  lan8650WriteReg(interface, LAN8650_MAC_SAB2, 0);
744  }
745 
746  //Configure the second unicast address filter
747  if(j >= 2)
748  {
749  //Set the lower 32 bits of the MAC address
751  (unicastMacAddr[1].b[3] << 24) | (unicastMacAddr[1].b[2] << 16) |
752  (unicastMacAddr[1].b[1] << 8) | unicastMacAddr[1].b[0]);
753 
754  //The address is activated when SAT register is written
756  (unicastMacAddr[1].b[5] << 8) | unicastMacAddr[1].b[4]);
757  }
758  else
759  {
760  //The address is deactivated when SAB register is written
761  lan8650WriteReg(interface, LAN8650_MAC_SAB3, 0);
762  }
763 
764  //Configure the third unicast address filter
765  if(j >= 3)
766  {
767  //Set the lower 32 bits of the MAC address
769  (unicastMacAddr[2].b[3] << 24) | (unicastMacAddr[2].b[2] << 16) |
770  (unicastMacAddr[2].b[1] << 8) | unicastMacAddr[2].b[0]);
771 
772  //The address is activated when SAT register is written
774  (unicastMacAddr[2].b[5] << 8) | unicastMacAddr[2].b[4]);
775  }
776  else
777  {
778  //The address is deactivated when SAB register is written
779  lan8650WriteReg(interface, LAN8650_MAC_SAB4, 0);
780  }
781 
782  //Configure the multicast hash table
783  lan8650WriteReg(interface, LAN8650_MAC_HRB, hashTable[0]);
784  lan8650WriteReg(interface, LAN8650_MAC_HRT, hashTable[1]);
785 
786  //Debug message
787  TRACE_DEBUG(" HRB = %08" PRIX32 "\r\n", hashTable[0]);
788  TRACE_DEBUG(" HRT = %08" PRIX32 "\r\n", hashTable[1]);
789 
790  //Successful processing
791  return NO_ERROR;
792 }
793 
794 
795 /**
796  * @brief Write register
797  * @param[in] interface Underlying network interface
798  * @param[in] mms Register memory map to access
799  * @param[in] address Register address
800  * @param[in] data Register value
801  **/
802 
803 void lan8650WriteReg(NetInterface *interface, uint8_t mms, uint16_t address,
804  uint32_t data)
805 {
806  uint32_t header;
807 
808  //Set up a register write operation
810  //The MMS field selects the specific register memory map to access
811  header |= (mms << 24) & LAN8650_CTRL_HEADER_MMS;
812  //Address of the first register to access
813  header |= (address << 8) & LAN8650_CTRL_HEADER_ADDR;
814  //Specifies the number of registers to write
815  header |= (0 << 1) & LAN8650_CTRL_HEADER_LEN;
816 
817  //The parity bit is calculated over the control command header
818  if(lan8650CalcParity(header) != 0)
819  {
820  header |= LAN8650_CTRL_HEADER_P;
821  }
822 
823  //Pull the CS pin low
824  interface->spiDriver->assertCs();
825 
826  //Write control command header
827  interface->spiDriver->transfer((header >> 24) & 0xFF);
828  interface->spiDriver->transfer((header >> 16) & 0xFF);
829  interface->spiDriver->transfer((header >> 8) & 0xFF);
830  interface->spiDriver->transfer(header & 0xFF);
831 
832  //Write data
833  interface->spiDriver->transfer((data >> 24) & 0xFF);
834  interface->spiDriver->transfer((data >> 16) & 0xFF);
835  interface->spiDriver->transfer((data >> 8) & 0xFF);
836  interface->spiDriver->transfer(data & 0xFF);
837 
838  //Send 32 bits of dummy data at the end of the control write command
839  interface->spiDriver->transfer(0x00);
840  interface->spiDriver->transfer(0x00);
841  interface->spiDriver->transfer(0x00);
842  interface->spiDriver->transfer(0x00);
843 
844  //Terminate the operation by raising the CS pin
845  interface->spiDriver->deassertCs();
846 }
847 
848 
849 /**
850  * @brief Read register
851  * @param[in] interface Underlying network interface
852  * @param[in] mms Register memory map to access
853  * @param[in] address Register address
854  * @return Register value
855  **/
856 
857 uint32_t lan8650ReadReg(NetInterface *interface, uint8_t mms,
858  uint16_t address)
859 {
860  uint32_t data;
861  uint32_t header;
862 
863  //Set up a register read operation
864  header = LAN8650_CTRL_HEADER_AID;
865  //The MMS field selects the specific register memory map to access
866  header |= (mms << 24) & LAN8650_CTRL_HEADER_MMS;
867  //Address of the first register to access
868  header |= (address << 8) & LAN8650_CTRL_HEADER_ADDR;
869  //Specifies the number of registers to read
870  header |= (0 << 1) & LAN8650_CTRL_HEADER_LEN;
871 
872  //The parity bit is calculated over the control command header
873  if(lan8650CalcParity(header) != 0)
874  {
875  header |= LAN8650_CTRL_HEADER_P;
876  }
877 
878  //Pull the CS pin low
879  interface->spiDriver->assertCs();
880 
881  //Write control command header
882  interface->spiDriver->transfer((header >> 24) & 0xFF);
883  interface->spiDriver->transfer((header >> 16) & 0xFF);
884  interface->spiDriver->transfer((header >> 8) & 0xFF);
885  interface->spiDriver->transfer(header & 0xFF);
886 
887  //Discard the echoed control header
888  interface->spiDriver->transfer(0x00);
889  interface->spiDriver->transfer(0x00);
890  interface->spiDriver->transfer(0x00);
891  interface->spiDriver->transfer(0x00);
892 
893  //Read data
894  data = interface->spiDriver->transfer(0x00) << 24;
895  data |= interface->spiDriver->transfer(0x00) << 16;
896  data |= interface->spiDriver->transfer(0x00) << 8;
897  data |= interface->spiDriver->transfer(0x00);
898 
899  //Terminate the operation by raising the CS pin
900  interface->spiDriver->deassertCs();
901 
902  //Return register value
903  return data;
904 }
905 
906 
907 /**
908  * @brief Dump registers for debugging purpose
909  * @param[in] interface Underlying network interface
910  * @param[in] mms Register memory map to access
911  * @param[in] address Start address
912  * @param[in] num Number of registers to dump
913  **/
914 
915 void lan8650DumpReg(NetInterface *interface, uint8_t mms, uint16_t address,
916  uint_t num)
917 {
918  uint_t i;
919 
920  //Loop through registers
921  for(i = 0; i < num; i++)
922  {
923  //Display current register
924  TRACE_DEBUG("0x%02" PRIX16 ": 0x%08" PRIX32 "\r\n", address + i,
925  lan8650ReadReg(interface, mms, address + i));
926  }
927 
928  //Terminate with a line feed
929  TRACE_DEBUG("\r\n");
930 }
931 
932 
933 /**
934  * @brief Write MMD register
935  * @param[in] interface Underlying network interface
936  * @param[in] devAddr Device address
937  * @param[in] regAddr Register address
938  * @param[in] data MMD register value
939  **/
940 
941 void lan8650WriteMmdReg(NetInterface *interface, uint8_t devAddr,
942  uint16_t regAddr, uint16_t data)
943 {
944  //Select register operation
945  lan8650WriteReg(interface, LAN8650_MMDCTRL,
947 
948  //Write MMD register address
950 
951  //Select data operation
952  lan8650WriteReg(interface, LAN8650_MMDCTRL,
954 
955  //Write the content of the MMD register
956  lan8650WriteReg(interface, LAN8650_MMDAD, data);
957 }
958 
959 
960 /**
961  * @brief Read MMD register
962  * @param[in] interface Underlying network interface
963  * @param[in] devAddr Device address
964  * @param[in] regAddr Register address
965  * @return MMD register value
966  **/
967 
968 uint16_t lan8650ReadMmdReg(NetInterface *interface, uint8_t devAddr,
969  uint16_t regAddr)
970 {
971  //Select register operation
972  lan8650WriteReg(interface, LAN8650_MMDCTRL,
974 
975  //Write MMD register address
977 
978  //Select data operation
979  lan8650WriteReg(interface, LAN8650_MMDCTRL,
981 
982  //Read the content of the MMD register
983  return lan8650ReadReg(interface, LAN8650_MMDAD);
984 }
985 
986 
987 /**
988  * @brief Read indirect register
989  * @param[in] interface Underlying network interface
990  * @param[in] address Register address
991  * @return Indirect register value
992  **/
993 
994 int8_t lan8650ReadIndirectReg(NetInterface *interface, uint8_t address)
995 {
996  //Specify the address of the register to read
997  lan8650WriteMmdReg(interface, 0x04, 0x00D8, address);
998  lan8650WriteMmdReg(interface, 0x04, 0x00DA, 0x0002);
999 
1000  //Read the content of the register
1001  return lan8650ReadMmdReg(interface, 0x04, 0x00D9);
1002 }
1003 
1004 
1005 /**
1006  * @brief Calculate parity bit over a 32-bit data
1007  * @param[in] data 32-bit bit stream
1008  * @return Odd parity bit computed over the supplied data
1009  **/
1010 
1011 uint32_t lan8650CalcParity(uint32_t data)
1012 {
1013  //Calculate the odd parity bit computed over the supplied bit stream
1014  data ^= data >> 1;
1015  data ^= data >> 2;
1016  data ^= data >> 4;
1017  data ^= data >> 8;
1018  data ^= data >> 16;
1019 
1020  //Return '1' when the number of bits set to one in the supplied bit
1021  //stream is even (resulting in an odd number of ones when the parity is
1022  //included), otherwise return '0'
1023  return ~data & 0x01;
1024 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:559
#define LAN8650_TX_HEADER_EV
#define LAN8650_MAC_SAT2
int bool_t
Definition: compiler_port.h:53
uint8_t b
Definition: nbns_common.h:104
#define LAN8650_RX_FOOTER_EV
#define LAN8650_TX_HEADER_SV
#define netEvent
Definition: net_legacy.h:196
#define LAN8650_RX_FOOTER_SV
#define LAN8650_MMDCTRL_FNCTN_DATA_NO_POST_INC
#define LOAD32BE(p)
Definition: cpu_endian.h:210
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:142
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:690
#define LAN8650_MAC_SAB2
uint8_t p
Definition: ndp.h:300
#define LAN8650_MAC_NCR_RXEN
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
#define LAN8650_CTRL_HEADER_MMS
uint8_t data[]
Definition: ethernet.h:222
void lan8650WriteReg(NetInterface *interface, uint8_t mms, uint16_t address, uint32_t data)
Write register.
int8_t lan8650ReadIndirectReg(NetInterface *interface, uint8_t address)
Read indirect register.
#define LAN8650_CTRL_HEADER_AID
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
#define LAN8650_NODE_COUNT
void lan8650Config(NetInterface *interface)
LAN8650 controller configuration.
error_t lan8650ReceivePacket(NetInterface *interface)
Receive a packet.
#define LAN8650_CHUNK_PAYLOAD_SIZE
#define LAN8650_OA_BUFSTS
#define LAN8650_PLCA_STS
#define LAN8650_MAC_SAT4
#define LAN8650_OA_CONFIG0_RFA_CSARFE
#define LAN8650_TX_HEADER_DNC
#define LAN8650_MAC_NCFGR_MTIHEN
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:392
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define LAN8650_ETH_RX_BUFFER_SIZE
void lan8650EnableIrq(NetInterface *interface)
Enable interrupts.
#define LAN8650_MAC_SAT3
error_t lan8650SendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
#define LAN8650_OA_CONFIG0_TXCTHRESH_16_CREDITS
uint16_t lan8650ReadMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
#define LAN8650_TX_HEADER_EBO
#define FALSE
Definition: os_port.h:46
#define LAN8650_PLCA_BURST_BTMR_DEFAULT
#define LAN8650_MAC_NCR_TXEN
#define LAN8650_MMDCTRL_DEVAD
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define LAN8650_OA_RESET
#define LAN8650_MAC_SAT1
error_t
Error codes.
Definition: error.h:43
void lan8650DisableIrq(NetInterface *interface)
Disable interrupts.
uint32_t lan8650CalcParity(uint32_t data)
Calculate parity bit over a 32-bit data.
#define LAN8650_PLCA_CTRL1_ID
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:104
#define LAN8650_MMDCTRL_FNCTN_ADDR
#define LAN8650_MAC_HRT
#define LAN8650_MMS_STD
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:140
#define NetInterface
Definition: net.h:36
#define LAN8650_LOCAL_ID
MacAddr addr
MAC address.
Definition: ethernet.h:263
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
#define LAN8650_OA_CONFIG0_CPS_64_BYTES
#define LAN8650_MAC_SAB1
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
#define LAN8650_OA_CONFIG0
#define LAN8650_PLCA_CTRL0_EN
#define LAN8650_MAC_NCFGR_MAXFS
#define NetTxAncillary
Definition: net_misc.h:36
#define LAN8650_OA_STATUS0_RESETC
uint32_t lan8650ReadReg(NetInterface *interface, uint8_t mms, uint16_t address)
Read register.
__weak_func void lan8650InitHook(NetInterface *interface)
LAN8650 custom configuration.
#define LAN8650_OA_BUFSTS_RCA
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define LAN8650_OA_RESET_SWRESET
#define MIN(a, b)
Definition: os_port.h:63
bool_t lan8650IrqHandler(NetInterface *interface)
LAN8650 interrupt service routine.
#define LAN8650_CTRL_HEADER_LEN
error_t lan8650UpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
MacAddr
Definition: ethernet.h:195
#define LAN8650_MAC_NCFGR
void lan8650EventHandler(NetInterface *interface)
LAN8650 event handler.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define LAN8650_CTRL_HEADER_ADDR
#define LAN8650_MMDAD
void lan8650WriteMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
uint16_t regAddr
#define LAN8650_MAC_HRB
#define LAN8650_OA_CONFIG0_SYNC
#define ETH_MTU
Definition: ethernet.h:116
#define LAN8650_MAC_SAB3
uint8_t n
MAC filter table entry.
Definition: ethernet.h:262
#define LAN8650_PLCA_CTRL0
Ipv6Addr address[]
Definition: ipv6.h:325
#define LAN8650_MAC_NCR
#define LAN8650_CTRL_HEADER_WNR
#define LAN8650_RX_FOOTER_EBO
#define LAN8650_OA_BUFSTS_TXC
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
uint8_t value[]
Definition: tcp.h:369
#define LAN8650_CTRL_HEADER_P
void lan8650DumpReg(NetInterface *interface, uint8_t mms, uint16_t address, uint_t num)
Dump registers for debugging purpose.
error_t lan8650Init(NetInterface *interface)
LAN8650 controller initialization.
#define LAN8650_PLCA_BURST_MAXBC_DEFAULT
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define LAN8650_MAC_SAB4
#define LAN8650_PLCA_CTRL1_NCNT
#define LAN8650_TX_HEADER_DV
#define LAN8650_PLCA_STS_PST
const NicDriver lan8650Driver
LAN8650 driver.
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
TCP/IP stack core.
#define LAN8650_TX_HEADER_NORX
#define LAN8650_MMDCTRL
NIC driver.
Definition: nic.h:286
#define LAN8650_OA_STATUS0
#define LAN8650_PLCA_CTRL1
void lan8650Tick(NetInterface *interface)
LAN8650 timer handler.
LAN8650 10Base-T1S Ethernet controller.
#define LAN8650_RX_FOOTER_RCA
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
#define LAN8650_PLCA_BURST
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define LAN8650_RX_FOOTER_DV