lan9250_driver.c
Go to the documentation of this file.
1 /**
2  * @file lan9250_driver.c
3  * @brief LAN9250 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.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 LAN9250 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 LAN9250 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 LAN9250 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  //Before device initialization, the SPI interface will not return valid
88  //data. To determine when the SPI interface is functional, the BYTE_TEST
89  //register should be polled
90  do
91  {
92  //Read BYTE_TEST register
94 
95  //Once the correct pattern is read, the interface can be considered
96  //functional
97  } while(value != LAN9250_BYTE_TEST_DEFAULT);
98 
99  //Perform multi-module reset
101 
102  //Multi-module reset completion can be determined by polling the BYTE_TEST
103  //register
104  do
105  {
106  //Read BYTE_TEST register
108 
109  //Once the correct pattern is read, the reset has completed
110  } while(value != LAN9250_BYTE_TEST_DEFAULT);
111 
112  //At this point, the READY bit in the HW_CFG register can be polled to
113  //determine when the device is fully configured
114  do
115  {
116  //Read HW_CFG register
117  value = lan9250ReadSysReg(interface, LAN9250_HW_CFG);
118 
119  //When set, the READY bit indicates that the reset has completed and
120  //the device is ready to be accessed
121  } while((value & LAN9250_HW_CFG_DEVICE_READY) == 0);
122 
123  //Dump system registers for debugging purpose
124  lan9250DumpSysReg(interface);
125  //Dump host MAC registers for debugging purpose
126  lan9250DumpMacReg(interface);
127  //Dump PHY registers for debugging purpose
128  lan9250DumpPhyReg(interface);
129 
130  //Set the lower 32 bits of the MAC address
131  lan9250WriteMacReg(interface, LAN9250_HMAC_ADDRL, interface->macAddr.b[0] |
132  (interface->macAddr.b[1] << 8) | (interface->macAddr.b[2] << 16) |
133  (interface->macAddr.b[3] << 24));
134 
135  //Set the upper 16 bits of the MAC address
136  lan9250WriteMacReg(interface, LAN9250_HMAC_ADDRH, interface->macAddr.b[4] |
137  (interface->macAddr.b[5] << 8));
138 
139  //Configure the size of the TX FIFO
142 
143  //The host can optionally choose to not read the TX status. The TX status
144  //can be ignored by setting the TXSAO bit
146 
147  //Configure address filtering
150 
151  //Configure the IRQ pin
155 
156  //Configure interrupts as desired
159 
160  //Configure PHY interrupts as desired
163 
164  //Enable transmitter
165  value = lan9250ReadSysReg(interface, LAN9250_TX_CFG);
168 
169  //Enable host MAC transmitter and receiver
173 
174  //Perform custom configuration
175  lan9250InitHook(interface);
176 
177  //Accept any packets from the upper layer
178  osSetEvent(&interface->nicTxEvent);
179 
180  //Force the TCP/IP stack to poll the link state at startup
181  interface->nicEvent = TRUE;
182  //Notify the TCP/IP stack of the event
184 
185  //Successful initialization
186  return NO_ERROR;
187 }
188 
189 
190 /**
191  * @brief LAN9250 custom configuration
192  * @param[in] interface Underlying network interface
193  **/
194 
195 __weak_func void lan9250InitHook(NetInterface *interface)
196 {
197 }
198 
199 
200 /**
201  * @brief LAN9250 timer handler
202  * @param[in] interface Underlying network interface
203  **/
204 
205 void lan9250Tick(NetInterface *interface)
206 {
207 }
208 
209 
210 /**
211  * @brief Enable interrupts
212  * @param[in] interface Underlying network interface
213  **/
214 
216 {
217  //Enable interrupts
218  if(interface->extIntDriver != NULL)
219  {
220  interface->extIntDriver->enableIrq();
221  }
222 }
223 
224 
225 /**
226  * @brief Disable interrupts
227  * @param[in] interface Underlying network interface
228  **/
229 
231 {
232  //Disable interrupts
233  if(interface->extIntDriver != NULL)
234  {
235  interface->extIntDriver->disableIrq();
236  }
237 }
238 
239 
240 /**
241  * @brief LAN9250 interrupt service routine
242  * @param[in] interface Underlying network interface
243  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
244  **/
245 
247 {
248  bool_t flag;
249  size_t n;
250  uint32_t ier;
251  uint32_t isr;
252 
253  //This flag will be set if a higher priority task must be woken
254  flag = FALSE;
255 
256  //Save interrupt enable register value
257  ier = lan9250ReadSysReg(interface, LAN9250_INT_EN);
258  //Disable interrupts to release the interrupt line
259  lan9250WriteSysReg(interface, LAN9250_INT_EN, 0);
260 
261  //Read interrupt status register
262  isr = lan9250ReadSysReg(interface, LAN9250_INT_STS);
263 
264  //PHY interrupt?
265  if((isr & LAN9250_INT_STS_PHY_INT) != 0)
266  {
267  //Disable PHY interrupt
269 
270  //Set event flag
271  interface->nicEvent = TRUE;
272  //Notify the TCP/IP stack of the event
273  flag |= osSetEventFromIsr(&netEvent);
274  }
275 
276  //Packet transmission complete?
277  if((isr & LAN9250_INT_STS_TX_IOC) != 0)
278  {
279  //Clear interrupt flag
281 
282  //Get the amount of free memory available in the TX FIFO
283  n = lan9250ReadSysReg(interface, LAN9250_TX_FIFO_INF) &
285 
286  //Check whether the TX FIFO is available for writing
288  {
289  //Notify the TCP/IP stack that the transmitter is ready to send
290  flag |= osSetEventFromIsr(&interface->nicTxEvent);
291  }
292  }
293 
294  //Packet received?
295  if((isr & LAN9250_INT_STS_RSFL) != 0)
296  {
297  //Disable RSFL interrupt
298  ier &= ~LAN9250_INT_EN_RSFL_EN;
299 
300  //Set event flag
301  interface->nicEvent = TRUE;
302  //Notify the TCP/IP stack of the event
303  flag |= osSetEventFromIsr(&netEvent);
304  }
305 
306  //Re-enable interrupts once the interrupt has been serviced
307  lan9250WriteSysReg(interface, LAN9250_INT_EN, ier);
308 
309  //A higher priority task must be woken?
310  return flag;
311 }
312 
313 
314 /**
315  * @brief LAN9250 event handler
316  * @param[in] interface Underlying network interface
317  **/
318 
320 {
321  error_t error;
322  uint32_t isr;
323  uint32_t value;
324 
325  //Read interrupt status register
326  isr = lan9250ReadSysReg(interface, LAN9250_INT_STS);
327 
328  //PHY interrupt?
329  if((isr & LAN9250_INT_STS_PHY_INT) != 0)
330  {
331  //Read PHY interrupt source register
333 
334  //Link status change?
337  {
338  //Any link failure condition is latched in the BMSR register. Reading
339  //the register twice will always return the actual link status
342 
343  //Check link state
345  {
346  //Read PHY special control status register
348 
349  //Check current operation mode
351  {
352  //10BASE-T half-duplex
354  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
355  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
356  break;
357 
358  //10BASE-T full-duplex
360  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
361  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
362  break;
363 
364  //100BASE-TX half-duplex
366  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
367  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
368  break;
369 
370  //100BASE-TX full-duplex
372  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
373  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
374  break;
375 
376  //Unknown operation mode
377  default:
378  //Debug message
379  TRACE_WARNING("Invalid operation mode!\r\n");
380  break;
381  }
382 
383  //Link is up
384  interface->linkState = TRUE;
385  }
386  else
387  {
388  //Link is down
389  interface->linkState = FALSE;
390  }
391 
392  //Process link state change event
393  nicNotifyLinkChange(interface);
394  }
395  }
396 
397  //Packet received?
398  if((isr & LAN9250_INT_STS_RSFL) != 0)
399  {
400  //Clear interrupt flag
402 
403  //Process all pending packets
404  do
405  {
406  //Read incoming packet
407  error = lan9250ReceivePacket(interface);
408 
409  //No more data in the receive buffer?
410  } while(error != ERROR_BUFFER_EMPTY);
411  }
412 
413  //Re-enable interrupts
416 }
417 
418 
419 /**
420  * @brief Send a packet
421  * @param[in] interface Underlying network interface
422  * @param[in] buffer Multi-part buffer containing the data to send
423  * @param[in] offset Offset to the first data byte
424  * @param[in] ancillary Additional options passed to the stack along with
425  * the packet
426  * @return Error code
427  **/
428 
430  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
431 {
432  static uint8_t temp[LAN9250_ETH_TX_BUFFER_SIZE];
433  size_t n;
434  size_t length;
435 
436  //Retrieve the length of the packet
437  length = netBufferGetLength(buffer) - offset;
438 
439  //Check the frame length
441  {
442  //The transmitter can accept another packet
443  osSetEvent(&interface->nicTxEvent);
444  //Report an error
445  return ERROR_INVALID_LENGTH;
446  }
447 
448  //Get the amount of free memory available in the TX FIFO
449  n = lan9250ReadSysReg(interface, LAN9250_TX_FIFO_INF) &
451 
452  //Before writing the TX command and payload data to the TX FIFO, the host
453  //must check the available TX FIFO space
454  if(n < (length + LAN9250_TX_CMD_SIZE))
455  {
456  return ERROR_FAILURE;
457  }
458 
459  //Copy user data
460  netBufferRead(temp, buffer, offset, length);
461 
462  //The host proceeds to write the TX command by first writing TX command 'A'
467 
468  //Then write TX command 'B'
471 
472  //After writing the command, the host can then move the payload data into
473  //the TX FIFO
474  lan9250WriteFifo(interface, temp, length);
475 
476  //Get the amount of free memory available in the TX FIFO
477  n = lan9250ReadSysReg(interface, LAN9250_TX_FIFO_INF) &
479 
480  //Check whether the TX FIFO is available for writing
482  {
483  //The transmitter can accept another packet
484  osSetEvent(&interface->nicTxEvent);
485  }
486 
487  //Successful processing
488  return NO_ERROR;
489 }
490 
491 
492 /**
493  * @brief Receive a packet
494  * @param[in] interface Underlying network interface
495  * @return Error code
496  **/
497 
499 {
500  static uint8_t temp[LAN9250_ETH_RX_BUFFER_SIZE];
501  error_t error;
502  size_t length;
503  uint32_t status;
504 
505  //Get the amount of space currently used in the RX status FIFO
508 
509  //Any packet pending in the receive buffer?
510  if(length > 0)
511  {
512  //Read RX status word
513  status = lan9250ReadSysReg(interface, LAN9250_RX_STATUS_FIFO);
514  //Get the length of the received packet
515  length = (status & LAN9250_RX_STS_PACKET_LEN) >> 16;
516 
517  //Make sure no error occurred
518  if((status & LAN9250_RX_STS_ERROR_STATUS) == 0)
519  {
520  //Check packet length
522  {
523  //Read packet data
524  lan9250ReadFifo(interface, temp, length);
525  //Valid packet received
526  error = NO_ERROR;
527  }
528  else
529  {
530  //Discard the received packet
531  lan9250DropPacket(interface, length);
532  //Report an error
533  error = ERROR_INVALID_LENGTH;
534  }
535  }
536  else
537  {
538  //Discard the received packet
539  lan9250DropPacket(interface, length);
540  //Report an error
541  error = ERROR_INVALID_PACKET;
542  }
543  }
544  else
545  {
546  //No more data in the receive buffer
547  error = ERROR_BUFFER_EMPTY;
548  }
549 
550  //Check whether a valid packet has been received
551  if(!error)
552  {
553  NetRxAncillary ancillary;
554 
555  //Additional options can be passed to the stack along with the packet
556  ancillary = NET_DEFAULT_RX_ANCILLARY;
557 
558  //Pass the packet to the upper layer
559  nicProcessPacket(interface, temp, length, &ancillary);
560  }
561 
562  //Return status code
563  return error;
564 }
565 
566 
567 /**
568  * @brief Drop the received packet
569  * @param[in] interface Underlying network interface
570  * @param[in] length Length of the packet, in bytes
571  **/
572 
573 void lan9250DropPacket(NetInterface *interface, size_t length)
574 {
575  size_t i;
576 
577  //When performing a fast-forward, there must be at least 4 words of data
578  //in the RX data FIFO for the packet being discarded
579  if(length >= 16)
580  {
581  //Using the RX_FFWD bit, the host can instruct the device to skip the
582  //packet at the head of the RX data FIFO
585 
586  //After initiating a fast-forward operation, do not perform any reads of
587  //the RX data FIFO until the RX_FFWD bit is cleared
588  while((lan9250ReadSysReg(interface, LAN9250_RX_DP_CTRL) &
590  {
591  }
592  }
593  else
594  {
595  //For cases with less than 4 words, data must be read from the RX data
596  //FIFO and discarded using standard PIO read operations
597  for(i = 0; i < length; i += 4)
598  {
599  //Perform standard PIO read operation
601  }
602  }
603 }
604 
605 
606 /**
607  * @brief Configure MAC address filtering
608  * @param[in] interface Underlying network interface
609  * @return Error code
610  **/
611 
613 {
614  uint_t i;
615  uint_t k;
616  uint32_t crc;
617  uint32_t hashTable[2];
618  MacFilterEntry *entry;
619 
620  //Debug message
621  TRACE_DEBUG("Updating MAC filter...\r\n");
622 
623  //Clear hash table
624  osMemset(hashTable, 0, sizeof(hashTable));
625 
626  //The MAC address filter contains the list of MAC addresses to accept
627  //when receiving an Ethernet frame
628  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
629  {
630  //Point to the current entry
631  entry = &interface->macAddrFilter[i];
632 
633  //Valid entry?
634  if(entry->refCount > 0)
635  {
636  //Compute CRC over the current MAC address
637  crc = lan9250CalcCrc(&entry->addr, sizeof(MacAddr));
638  //Calculate the corresponding index in the table
639  k = (crc >> 26) & 0x3F;
640  //Update hash table contents
641  hashTable[k / 32] |= (1 << (k % 32));
642  }
643  }
644 
645  //Write the hash table to the LAN9250 controller
646  lan9250WriteMacReg(interface, LAN9250_HMAC_HASHL, hashTable[0]);
647  lan9250WriteMacReg(interface, LAN9250_HMAC_HASHH, hashTable[1]);
648 
649  //Debug message
650  TRACE_DEBUG(" HMAC_HASHL = %08" PRIX32 "\r\n",
652  TRACE_DEBUG(" HMAC_HASHH = %08" PRIX32 "\r\n",
654 
655  //Successful processing
656  return NO_ERROR;
657 }
658 
659 
660 /**
661  * @brief Write system CSR register
662  * @param[in] interface Underlying network interface
663  * @param[in] address Register address
664  * @param[in] data System register value
665  **/
666 
667 void lan9250WriteSysReg(NetInterface *interface, uint16_t address,
668  uint32_t data)
669 {
670  //Pull the CS pin low
671  interface->spiDriver->assertCs();
672 
673  //Write command
674  interface->spiDriver->transfer(LAN9250_SPI_INSTR_WRITE);
675 
676  //Write address
677  interface->spiDriver->transfer((address >> 8) & 0xFF);
678  interface->spiDriver->transfer(address & 0xFF);
679 
680  //Write data
681  interface->spiDriver->transfer(data & 0xFF);
682  interface->spiDriver->transfer((data >> 8) & 0xFF);
683  interface->spiDriver->transfer((data >> 16) & 0xFF);
684  interface->spiDriver->transfer((data >> 24) & 0xFF);
685 
686  //Terminate the operation by raising the CS pin
687  interface->spiDriver->deassertCs();
688 }
689 
690 
691 /**
692  * @brief Read system CSR register
693  * @param[in] interface Underlying network interface
694  * @param[in] address System register address
695  * @return Register value
696  **/
697 
698 uint32_t lan9250ReadSysReg(NetInterface *interface, uint16_t address)
699 {
700  uint32_t data;
701 
702  //Pull the CS pin low
703  interface->spiDriver->assertCs();
704 
705  //Write command
706  interface->spiDriver->transfer(LAN9250_SPI_INSTR_READ);
707 
708  //Write address
709  interface->spiDriver->transfer((address >> 8) & 0xFF);
710  interface->spiDriver->transfer(address & 0xFF);
711 
712  //Read data
713  data = interface->spiDriver->transfer(0x00);
714  data |= interface->spiDriver->transfer(0x00) << 8;
715  data |= interface->spiDriver->transfer(0x00) << 16;
716  data |= interface->spiDriver->transfer(0x00) << 24;
717 
718  //Terminate the operation by raising the CS pin
719  interface->spiDriver->deassertCs();
720 
721  //Return register value
722  return data;
723 }
724 
725 
726 /**
727  * @brief Dump system CSR registers for debugging purpose
728  * @param[in] interface Underlying network interface
729  **/
730 
732 {
733  uint16_t i;
734 
735  //Loop through system registers
736  for(i = 80; i < 512; i += 4)
737  {
738  //Display current system register
739  TRACE_DEBUG("0x%03" PRIX16 ": 0x%08" PRIX32 "\r\n", i,
740  lan9250ReadSysReg(interface, i));
741  }
742 
743  //Terminate with a line feed
744  TRACE_DEBUG("\r\n");
745 }
746 
747 
748 /**
749  * @brief Write host MAC CSR register
750  * @param[in] interface Underlying network interface
751  * @param[in] address Host MAC register address
752  * @param[in] data Register value
753  **/
754 
755 void lan9250WriteMacReg(NetInterface *interface, uint8_t address,
756  uint32_t data)
757 {
758  uint32_t value;
759 
760  //To perform a write to an individual host MAC register, the desired
761  //data must first be written into the MAC_CSR_DATA register
763 
764  //Set up a write operation
766  //Set register address
768 
769  //The write cycle is initiated by performing a single write to the
770  //MAC_CSR_CMD register
772 
773  //The completion of the write cycle is indicated by the clearing of the
774  //CSR_BUSY bit
775  do
776  {
777  //Read MAC_CSR_CMD register
779 
780  //Poll CSR_BUSY bit
781  } while((value & LAN9250_MAC_CSR_CMD_BUSY) != 0);
782 }
783 
784 
785 /**
786  * @brief Read host MAC CSR register
787  * @param[in] interface Underlying network interface
788  * @param[in] address Host MAC register address
789  * @return Register value
790  **/
791 
792 uint32_t lan9250ReadMacReg(NetInterface *interface, uint8_t address)
793 {
794  uint32_t value;
795 
796  //Set up a read operation
798  //Set register address
800 
801  //To perform a read of an individual host MAC register, the read cycle
802  //must be initiated by performing a single write to the MAC_CSR_CMD
803  //register
805 
806  //Valid data is available for reading when the CSR_BUSY bit is cleared
807  do
808  {
809  //Read MAC_CSR_CMD register
811 
812  //Poll CSR_BUSY bit
813  } while((value & LAN9250_MAC_CSR_CMD_BUSY) != 0);
814 
815  //Read data from the MAC_CSR_DATA register
816  return lan9250ReadSysReg(interface, LAN9250_MAC_CSR_DATA);
817 }
818 
819 
820 /**
821  * @brief Dump host MAC CSR registers for debugging purpose
822  * @param[in] interface Underlying network interface
823  **/
824 
826 {
827  uint8_t i;
828 
829  //Loop through host MAC registers
830  for(i = 0; i < 16; i++)
831  {
832  //Display current host MAC register
833  TRACE_DEBUG("%02" PRIu8 ": 0x%08" PRIX32 "\r\n", i,
834  lan9250ReadMacReg(interface, i));
835  }
836 
837  //Terminate with a line feed
838  TRACE_DEBUG("\r\n");
839 }
840 
841 
842 /**
843  * @brief Write PHY register
844  * @param[in] interface Underlying network interface
845  * @param[in] address PHY register address
846  * @param[in] data Register value
847  **/
848 
849 void lan9250WritePhyReg(NetInterface *interface, uint8_t address,
850  uint16_t data)
851 {
852  uint32_t value;
853 
854  //The HMAC_MII_DATA register contains the data to be written
856 
857  //Set up a write operation
860 
861  //Set register address
863 
864  //Initiate a write cycle
866 
867  //During a MII register access, the MIIBZY bit will be set, signifying a
868  //read or write access is in progress
869  do
870  {
871  //Read HMAC_MII_ACC register
873 
874  //The MIIBZY bit must be polled to determine when the MII register access
875  //is complete
876  } while((value & LAN9250_HMAC_MII_ACC_MIIBZY) != 0);
877 }
878 
879 
880 /**
881  * @brief Read PHY register
882  * @param[in] interface Underlying network interface
883  * @param[in] address PHY register address
884  * @return Register value
885  **/
886 
887 uint16_t lan9250ReadPhyReg(NetInterface *interface, uint8_t address)
888 {
889  uint32_t value;
890 
891  //Set up a read operation
893  //Set register address
895 
896  //Initiate a read cycle
898 
899  //During a MII register access, the MIIBZY bit will be set, signifying a
900  //read or write access is in progress
901  do
902  {
903  //Read HMAC_MII_ACC register
905 
906  //The MIIBZY bit must be polled to determine when the MII register access
907  //is complete
908  } while((value & LAN9250_HMAC_MII_ACC_MIIBZY) != 0);
909 
910  //Read data from the HMAC_MII_DATA register
911  return lan9250ReadMacReg(interface, LAN9250_HMAC_MII_DATA) &
913 }
914 
915 
916 /**
917  * @brief Dump PHY registers for debugging purpose
918  * @param[in] interface Underlying network interface
919  **/
920 
922 {
923  uint8_t i;
924 
925  //Loop through PHY registers
926  for(i = 0; i < 32; i++)
927  {
928  //Display current PHY register
929  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
930  lan9250ReadPhyReg(interface, i));
931  }
932 
933  //Terminate with a line feed
934  TRACE_DEBUG("\r\n");
935 }
936 
937 
938 /**
939  * @brief Write MMD register
940  * @param[in] interface Underlying network interface
941  * @param[in] devAddr Device address
942  * @param[in] regAddr Register address
943  * @param[in] data MMD register value
944  **/
945 
946 void lan9250WriteMmdReg(NetInterface *interface, uint8_t devAddr,
947  uint16_t regAddr, uint16_t data)
948 {
949  //Select register operation
952  (devAddr & LAN9250_PHY_MMD_ACCESS_DEVAD));
953 
954  //Write MMD register address
956 
957  //Select data operation
960  (devAddr & LAN9250_PHY_MMD_ACCESS_DEVAD));
961 
962  //Write the content of the MMD register
964 }
965 
966 
967 /**
968  * @brief Read MMD register
969  * @param[in] interface Underlying network interface
970  * @param[in] devAddr Device address
971  * @param[in] regAddr Register address
972  * @return MMD register value
973  **/
974 
975 uint16_t lan9250ReadMmdReg(NetInterface *interface, uint8_t devAddr,
976  uint16_t regAddr)
977 {
978  //Select register operation
981  (devAddr & LAN9250_PHY_MMD_ACCESS_DEVAD));
982 
983  //Write MMD register address
985 
986  //Select data operation
989  (devAddr & LAN9250_PHY_MMD_ACCESS_DEVAD));
990 
991  //Read the content of the MMD register
992  return lan9250ReadPhyReg(interface, LAN9250_PHY_MMD_ADDR_DATA);
993 }
994 
995 
996 /**
997  * @brief Write TX FIFO
998  * @param[in] interface Underlying network interface
999  * @param[in] data Pointer to the data being written
1000  * @param[in] length Number of data to write
1001  **/
1002 
1003 void lan9250WriteFifo(NetInterface *interface, const uint8_t *data,
1004  size_t length)
1005 {
1006  size_t i;
1007 
1008  //Pull the CS pin low
1009  interface->spiDriver->assertCs();
1010 
1011  //Write command
1012  interface->spiDriver->transfer(LAN9250_SPI_INSTR_WRITE);
1013 
1014  //Write address
1015  interface->spiDriver->transfer((LAN9250_TX_DATA_FIFO >> 8) & 0xFF);
1016  interface->spiDriver->transfer(LAN9250_TX_DATA_FIFO & 0xFF);
1017 
1018  //Write data
1019  for(i = 0; i < length; i++)
1020  {
1021  interface->spiDriver->transfer(data[i]);
1022  }
1023 
1024  //Maintain alignment to 4-byte boundaries
1025  for(; (i % 4) != 0; i++)
1026  {
1027  interface->spiDriver->transfer(0x00);
1028  }
1029 
1030  //Terminate the operation by raising the CS pin
1031  interface->spiDriver->deassertCs();
1032 }
1033 
1034 
1035 /**
1036  * @brief Read RX FIFO
1037  * @param[in] interface Underlying network interface
1038  * @param[out] data Buffer where to store the incoming data
1039  * @param[in] length Number of data to read
1040  **/
1041 
1042 void lan9250ReadFifo(NetInterface *interface, uint8_t *data, size_t length)
1043 {
1044  size_t i;
1045 
1046  //Pull the CS pin low
1047  interface->spiDriver->assertCs();
1048 
1049  //Write command
1050  interface->spiDriver->transfer(LAN9250_SPI_INSTR_READ);
1051 
1052  //Write address
1053  interface->spiDriver->transfer((LAN9250_RX_DATA_FIFO >> 8) & 0xFF);
1054  interface->spiDriver->transfer(LAN9250_RX_DATA_FIFO & 0xFF);
1055 
1056  //Read data
1057  for(i = 0; i < length; i++)
1058  {
1059  data[i] = interface->spiDriver->transfer(0x00);
1060  }
1061 
1062  //Maintain alignment to 4-byte boundaries
1063  for(; (i % 4) != 0; i++)
1064  {
1065  interface->spiDriver->transfer(0x00);
1066  }
1067 
1068  //Terminate the operation by raising the CS pin
1069  interface->spiDriver->deassertCs();
1070 }
1071 
1072 
1073 /**
1074  * @brief CRC calculation
1075  * @param[in] data Pointer to the data over which to calculate the CRC
1076  * @param[in] length Number of bytes to process
1077  * @return Resulting CRC value
1078  **/
1079 
1080 uint32_t lan9250CalcCrc(const void *data, size_t length)
1081 {
1082  uint_t i;
1083  uint_t j;
1084  uint32_t crc;
1085  const uint8_t *p;
1086 
1087  //Point to the data over which to calculate the CRC
1088  p = (uint8_t *) data;
1089  //CRC preset value
1090  crc = 0xFFFFFFFF;
1091 
1092  //Loop through data
1093  for(i = 0; i < length; i++)
1094  {
1095  //The message is processed bit by bit
1096  for(j = 0; j < 8; j++)
1097  {
1098  //Update CRC value
1099  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1100  {
1101  crc = (crc << 1) ^ 0x04C11DB7;
1102  }
1103  else
1104  {
1105  crc = crc << 1;
1106  }
1107  }
1108  }
1109 
1110  //Return CRC value
1111  return crc;
1112 }
unsigned int uint_t
Definition: compiler_port.h:50
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
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PACKET
Definition: error.h:140
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
MacAddr
Definition: ethernet.h:195
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
Ipv6Addr address[]
Definition: ipv6.h:316
const NicDriver lan9250Driver
LAN9250 driver.
void lan9250WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
Write PHY register.
void lan9250WriteSysReg(NetInterface *interface, uint16_t address, uint32_t data)
Write system CSR register.
void lan9250DumpPhyReg(NetInterface *interface)
Dump PHY registers for debugging purpose.
void lan9250EventHandler(NetInterface *interface)
LAN9250 event handler.
error_t lan9250SendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
error_t lan9250ReceivePacket(NetInterface *interface)
Receive a packet.
void lan9250WriteMacReg(NetInterface *interface, uint8_t address, uint32_t data)
Write host MAC CSR register.
uint32_t lan9250ReadSysReg(NetInterface *interface, uint16_t address)
Read system CSR register.
void lan9250WriteFifo(NetInterface *interface, const uint8_t *data, size_t length)
Write TX FIFO.
error_t lan9250UpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void lan9250DropPacket(NetInterface *interface, size_t length)
Drop the received packet.
bool_t lan9250IrqHandler(NetInterface *interface)
LAN9250 interrupt service routine.
uint16_t lan9250ReadPhyReg(NetInterface *interface, uint8_t address)
Read PHY register.
uint16_t lan9250ReadMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
uint32_t lan9250ReadMacReg(NetInterface *interface, uint8_t address)
Read host MAC CSR register.
void lan9250WriteMmdReg(NetInterface *interface, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
void lan9250ReadFifo(NetInterface *interface, uint8_t *data, size_t length)
Read RX FIFO.
void lan9250DumpMacReg(NetInterface *interface)
Dump host MAC CSR registers for debugging purpose.
void lan9250EnableIrq(NetInterface *interface)
Enable interrupts.
uint32_t lan9250CalcCrc(const void *data, size_t length)
CRC calculation.
void lan9250DumpSysReg(NetInterface *interface)
Dump system CSR registers for debugging purpose.
void lan9250Tick(NetInterface *interface)
LAN9250 timer handler.
__weak_func void lan9250InitHook(NetInterface *interface)
LAN9250 custom configuration.
error_t lan9250Init(NetInterface *interface)
LAN9250 controller initialization.
void lan9250DisableIrq(NetInterface *interface)
Disable interrupts.
LAN9250 Ethernet controller.
#define LAN9250_HMAC_MII_DATA
#define LAN9250_PHY_MMD_ACCESS_FUNC_ADDR
#define LAN9250_INT_STS_RSFL
#define LAN9250_BYTE_TEST_DEFAULT
#define LAN9250_TX_CMD_A_LAST_SEG
#define LAN9250_RX_DATA_FIFO
#define LAN9250_MAC_CSR_CMD
#define LAN9250_INT_STS_PHY_INT
#define LAN9250_PHY_SPECIAL_CONTROL_STATUS_SPEED_100BTX_FD
#define LAN9250_BYTE_TEST
#define LAN9250_HMAC_CR_FDPX
#define LAN9250_PHY_INTERRUPT_MASK
#define LAN9250_HW_CFG
#define LAN9250_IRQ_CFG_IRQ_POL_LOW
#define LAN9250_RESET_CTL
#define LAN9250_HW_CFG_DEVICE_READY
#define LAN9250_IRQ_CFG_IRQ_EN
#define LAN9250_PHY_SPECIAL_CONTROL_STATUS_SPEED_100BTX_HD
#define LAN9250_TX_FIFO_INF_TXFREE
#define LAN9250_TX_CFG_TXSAO
#define LAN9250_INT_EN_RSFL_EN
#define LAN9250_RESET_CTL_DIGITAL_RST
#define LAN9250_PHY_MMD_ACCESS
#define LAN9250_HMAC_CR_HPFILT
#define LAN9250_RX_FIFO_INF
#define LAN9250_PHY_SPECIAL_CONTROL_STATUS
#define LAN9250_TX_CMD_A_START_OFFSET_0B
#define LAN9250_HMAC_MII_ACC_MIIBZY
#define LAN9250_HMAC_CR_TXEN
#define LAN9250_ETH_RX_BUFFER_SIZE
#define LAN9250_HMAC_HASHH
#define LAN9250_TX_CMD_A_INT_ON_COMP
#define LAN9250_HMAC_ADDRL
#define LAN9250_INT_EN
#define LAN9250_HMAC_ADDRH
#define LAN9250_HMAC_MII_ACC
#define LAN9250_PHY_MMD_ADDR_DATA
#define LAN9250_HMAC_CR_RXEN
#define LAN9250_RX_STS_ERROR_STATUS
#define LAN9250_INT_STS_TX_IOC
#define LAN9250_INT_STS
#define LAN9250_PHY_MMD_ACCESS_FUNC_DATA_NO_POST_INC
#define LAN9250_RX_DP_CTRL_RX_FFWD
#define LAN9250_PHY_INTERRUPT_MASK_LINK_DOWN
#define LAN9250_MAC_CSR_CMD_ADDR
#define LAN9250_RX_DP_CTRL
#define LAN9250_HMAC_MII_ACC_MIIW_R
#define LAN9250_HW_CFG_MBO
#define LAN9250_MAC_CSR_DATA
#define LAN9250_IRQ_CFG_IRQ_TYPE_OD
#define LAN9250_TX_DATA_FIFO
#define LAN9250_TX_CMD_A_BUFFER_ALIGN_4B
#define LAN9250_HMAC_HASHL
#define LAN9250_HMAC_MII_ACC_PHY_ADDR_DEFAULT
#define LAN9250_MAC_CSR_CMD_BUSY
#define LAN9250_PHY_BASIC_STATUS_LINK_STATUS
#define LAN9250_INT_EN_PHY_INT_EN
#define LAN9250_PHY_SPECIAL_CONTROL_STATUS_SPEED
#define LAN9250_PHY_INTERRUPT_SOURCE
#define LAN9250_PHY_INTERRUPT_SOURCE_LINK_UP
#define LAN9250_ETH_TX_BUFFER_SIZE
#define LAN9250_RX_FIFO_INF_RXSUSED
#define LAN9250_SPI_INSTR_WRITE
#define LAN9250_TX_CMD_SIZE
#define LAN9250_RX_STATUS_FIFO
#define LAN9250_TX_CMD_A_FIRST_SEG
#define LAN9250_PHY_INTERRUPT_MASK_LINK_UP
#define LAN9250_RX_STS_PACKET_LEN
#define LAN9250_HW_CFG_TX_FIF_SZ_5KB
#define LAN9250_IRQ_CFG_INT_DEAS_100US
#define LAN9250_IRQ_CFG
#define LAN9250_PHY_SPECIAL_CONTROL_STATUS_SPEED_10BT_FD
#define LAN9250_HMAC_MII_DATA_MII_DATA
#define LAN9250_HMAC_MII_ACC_MIIRINDA
#define LAN9250_MAC_CSR_CMD_READ
#define LAN9250_PHY_INTERRUPT_SOURCE_LINK_DOWN
#define LAN9250_TX_CFG
#define LAN9250_PHY_MMD_ACCESS_DEVAD
#define LAN9250_TX_FIFO_INF
#define LAN9250_MAC_CSR_CMD_WRITE
#define LAN9250_TX_CFG_TX_ON
#define LAN9250_SPI_INSTR_READ
#define LAN9250_TX_CMD_B_PACKET_TAG
#define LAN9250_HMAC_CR
#define LAN9250_HMAC_CR_RCVOWN
#define LAN9250_PHY_SPECIAL_CONTROL_STATUS_SPEED_10BT_HD
#define LAN9250_PHY_BASIC_STATUS
uint16_t regAddr
uint8_t p
Definition: ndp.h:300
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
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:674
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:101
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:548
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
@ 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
#define osMemset(p, value, length)
Definition: os_port.h:135
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
MAC filter table entry.
Definition: ethernet.h:262
MacAddr addr
MAC address.
Definition: ethernet.h:263
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
NIC driver.
Definition: nic.h:283
uint8_t length
Definition: tcp.h:368
uint8_t value[]
Definition: tcp.h:369