ksz8851snl.c

Go to the documentation of this file.
00001 /***************************************************************************/
00017 #include "ksz8851snl.h"
00018 #include "ethspi.h"
00019 #include "em_gpio.h"
00020 #include <stdio.h>
00021 
00023 static uint16_t frameId = 0;        
00024 static uint8_t  macAddress[6];      
00026 #if KSZ8851SNL_DEBUG
00027 static void     KSZ8851SNL_SetDigitalLoopbackMode(void);
00028 static void     KSZ8851SNL_DumpRegisters(void);
00029 #endif /* KSZ8851SNL_DEBUG */
00030 static void     KSZ8851SNL_ExceptionHandler(enum exceptionType_e exc_type, char* param);
00031 static void     KSZ8851SNL_ReleaseIncosistentFrame(void);
00032 static uint8_t  KSZ8851SNL_DwordAllignDiff(uint8_t val);
00035 /**************************************************************************/
00038 void KSZ8851SNL_EnableInterupts(void)
00039 {
00040   uint16_t data;
00041   /* Enable interupts */
00042   data = INT_MASK_EXAMPLE;
00043   ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00044 }
00045 
00046 
00047 /***************************************************************************/
00057 uint16_t KSZ8851SNL_CheckIrqStat(void)
00058 {
00059   uint16_t data, ISR_stat, found_INT;
00060   found_INT = 0;
00061   ETHSPI_ReadRegister(INT_STATUS_REG, 2, &ISR_stat);
00062 
00063   /* Disable interupts on KSZ8851SNL */
00064   data = NO_INT;
00065   ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00066 
00067   /* Resolve the RX completion interrupt */
00068   if (ISR_stat & INT_RX_DONE)
00069   {
00070     /* Clear RX Interrupt flag */
00071     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00072     data = INT_RX_DONE;
00073     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00074     found_INT |= INT_RX_DONE;
00075   }
00076   /* Resolve the Link change interrupt */
00077   if (ISR_stat & INT_LINK_CHANGE)
00078   {
00079     /* Clear Link change Interrupt flag */
00080     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00081     data = INT_LINK_CHANGE;
00082     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00083     found_INT |= INT_LINK_CHANGE;
00084   }
00085   /* Resolve the RX overrun interrupt */
00086   if (ISR_stat & INT_RX_OVERRUN)
00087   {
00088     /* Clear RX overrun Interrupt flag */
00089     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00090     data = INT_RX_OVERRUN;
00091     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00092     found_INT |= INT_RX_OVERRUN;
00093   }
00094   /* Resolve the TX stopped interrupt */
00095   if (ISR_stat & INT_TX_STOPPED)
00096   {
00097     /* Clear TX stopped Interrupt flag */
00098     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00099     data = INT_TX_STOPPED;
00100     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00101     found_INT |= INT_TX_STOPPED;
00102   }
00103   /* Resolve the RX stopped interrupt */
00104   if (ISR_stat & INT_RX_STOPPED)
00105   {
00106     /* Clear RX stopped Interrupt flag */
00107     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00108     data = INT_RX_STOPPED;
00109     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00110     found_INT |= INT_RX_STOPPED;
00111   }
00112   /* Resolve the RX of a WakeOnLan frame interrupt */
00113   if (ISR_stat & INT_RX_WOL_FRAME)
00114   {
00115     /* Clear RX of a WakeOnLan Interrupt flag */
00116     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00117     data = INT_RX_WOL_FRAME;
00118     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00119     found_INT |= INT_RX_WOL_FRAME;
00120   }
00121   /* Resolve the RX of a magic frame interrupt */
00122   if (ISR_stat & INT_MAGIC)
00123   {
00124     /* Clear RX of a magic frame Interrupt flag */
00125     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00126     data = INT_MAGIC;
00127     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00128     found_INT |= INT_MAGIC;
00129   }
00130   /* Resolve the RX of a LINKUP interrupt */
00131   if (ISR_stat & INT_LINKUP)
00132   {
00133     /* Clear RX of a LINKUP Interrupt flag */
00134     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00135     data = INT_LINKUP;
00136     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00137     found_INT |= INT_LINKUP;
00138   }
00139   /* Resolve the RX of a Energy interrupt */
00140   if (ISR_stat & INT_ENERGY)
00141   {
00142     /* Clear RX of a Energy Interrupt flag */
00143     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00144     data = INT_ENERGY;
00145     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00146     found_INT |= INT_ENERGY;
00147   }
00148   /* Resolve the SPI Error interrupt */
00149   if (ISR_stat & INT_SPI_ERROR)
00150   {
00151     /* Clear SPI Error Interrupt flag */
00152     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00153     data = INT_SPI_ERROR;
00154     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00155     found_INT |= INT_SPI_ERROR;
00156   }
00157   /* Resolve the TX space interrupt */
00158   if (ISR_stat & INT_TX_SPACE)
00159   {
00160     /* Clear TX space Interrupt flag */
00161     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00162     data = INT_TX_SPACE;
00163     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00164     found_INT |= INT_TX_SPACE;
00165   }
00166   return found_INT;
00167 }
00168 
00169 
00170 /***************************************************************************/
00177 uint16_t KSZ8851SNL_CurrFrameSize(void)
00178 {
00179   uint16_t data;
00180 
00181   /* Read the byte size of the received frame */
00182   ETHSPI_ReadRegister(RX_FRH_BC_REG, 2, &data);
00183 
00184   data &= RX_BYTE_CNT_MASK;
00185 
00186   return data;
00187 }
00188 
00189 
00190 /***************************************************************************/
00199 static uint8_t KSZ8851SNL_DwordAllignDiff(uint8_t val)
00200 {
00201   if (val % 4 == 0) return 0;
00202   else return val % 4;
00203 }
00204 
00205 
00206 /***************************************************************************/
00216 static void KSZ8851SNL_ExceptionHandler(enum exceptionType_e exc_type, char* param)
00217 {
00218   uint16_t data;
00219   (void)param; /* unused param */
00220   /* Disable interupts on KSZ8851SNL */
00221   data = NO_INT;
00222   ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00223   switch (exc_type)
00224   {
00225   case ERROR:
00226     DEBUG_PRINT("ERROR:%s\n", param);
00227     while (1) ;
00228   case INFO:
00229     DEBUG_PRINT("INFO:%s\n", param);
00230     break;
00231   }
00232   /* Enable interupts */
00233   data = INT_MASK_EXAMPLE;
00234   ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00235 }
00236 
00237 
00238 /***************************************************************************/
00246 void KSZ8851SNL_ReadMIBCounters(char* param)
00247 {
00248   EFM_ASSERT(param != NULL);
00249   uint16_t data, dataLow, dataHigh;
00250   DEBUG_PRINT("#################################################################\n");
00251   DEBUG_PRINT("Dumping MIB Counters values @%s\n", param);
00252   int i;
00253   for (i = 0; i < 0x20; i++)
00254   {
00255     data = MIB_MASK | i;
00256     ETHSPI_WriteRegister(IND_ACC_CTRL_REG, 2, &data);
00257     ETHSPI_ReadRegister(IND_ACC_DATA_LOW_REG, 2, &dataLow);
00258     ETHSPI_ReadRegister(IND_ACC_DATA_HIGH_REG, 2, &dataHigh);
00259     DEBUG_PRINT("MIB_REG[%2X] contains %X - %X\n", i, dataHigh, dataLow);
00260   }
00261   DEBUG_PRINT("#################################################################\n");
00262 }
00263 
00264 
00265 #if KSZ8851SNL_DEBUG
00266 /***************************************************************************/
00270 static void KSZ8851SNL_DumpRegisters(void)
00271 {
00272   uint16_t data;
00273 
00274   DEBUG_PRINT("#################################################################\n");
00275   DEBUG_PRINT("Dumping Register values\n");
00276 
00277   DEBUG_PRINT("#################################################################\n");
00278   DEBUG_PRINT("Dumping ALL Register values\n");
00279 
00280   int i;
00281   for (i = 0; = 0x00; i < 0xFF; i += 0x02)
00282   {
00283     ETHSPI_ReadRegister(i, 2, &data);
00284     DEBUG_PRINT("REG[0x%X] contains 0x%X\n", i, data);
00285   }
00286   DEBUG_PRINT("#################################################################\n");
00287   DEBUG_PRINT("Dumping used registers values\n");
00288 
00289   ETHSPI_ReadRegister(LOW_QMU_MAC_REG, 2, &data);
00290   DEBUG_PRINT("REG[%2X] contains %2X\n", LOW_QMU_MAC_REG, data);
00291   ETHSPI_ReadRegister(MID_QMU_MAC_REG, 2, &data);
00292   DEBUG_PRINT("REG[%2X] contains %2X\n", MID_QMU_MAC_REG, data);
00293   ETHSPI_ReadRegister(HIGH_QMU_MAC_REG, 2, &data);
00294   DEBUG_PRINT("REG[%2X] contains %2X\n", HIGH_QMU_MAC_REG, data);
00295   ETHSPI_ReadRegister(OBC_REG, 2, &data);
00296   DEBUG_PRINT("REG[%2X] contains %2X\n", OBC_REG, data);
00297   ETHSPI_ReadRegister(GLOBAL_RESET_REG, 2, &data);
00298   DEBUG_PRINT("REG[%2X] contains %2X\n", GLOBAL_RESET_REG, data);
00299   ETHSPI_ReadRegister(TX_FLOW_CTRL_REG, 2, &data);
00300   DEBUG_PRINT("REG[%2X] contains %2X\n", TX_FLOW_CTRL_REG, data);
00301   ETHSPI_ReadRegister(RX_FLOW_CTRL1_REG, 2, &data);
00302   DEBUG_PRINT("REG[%2X] contains %2X\n", RX_FLOW_CTRL1_REG, data);
00303   ETHSPI_ReadRegister(RX_FLOW_CTRL2_REG, 2, &data);
00304   DEBUG_PRINT("REG[%2X] contains %2X\n", RX_FLOW_CTRL2_REG, data);
00305   ETHSPI_ReadRegister(TX_MEM_INFO_REG, 2, &data);
00306   DEBUG_PRINT("REG[%2X] contains %2X\n", TX_MEM_INFO_REG, data);
00307   ETHSPI_ReadRegister(RX_FRH_STAT_REG, 2, &data);
00308   DEBUG_PRINT("REG[%2X] contains %2X\n", RX_FRH_STAT_REG, data);
00309   ETHSPI_ReadRegister(TXQ_CMD_REG, 2, &data);
00310   DEBUG_PRINT("REG[%2X] contains %2X\n", TXQ_CMD_REG, data);
00311   ETHSPI_ReadRegister(RXQ_CMD_REG, 2, &data);
00312   DEBUG_PRINT("REG[%2X] contains %2X\n", RXQ_CMD_REG, data);
00313   ETHSPI_ReadRegister(TX_FD_PTR_REG, 2, &data);
00314   DEBUG_PRINT("REG[%2X] contains %2X\n", TX_FD_PTR_REG, data);
00315   ETHSPI_ReadRegister(RX_FD_PTR_REG, 2, &data);
00316   DEBUG_PRINT("REG[%2X] contains %2X\n", RX_FD_PTR_REG, data);
00317   ETHSPI_ReadRegister(INT_ENABLE_REG, 2, &data);
00318   DEBUG_PRINT("REG[%2X] contains %2X\n", INT_ENABLE_REG, data);
00319   ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00320   DEBUG_PRINT("REG[%2X] contains %2X\n", INT_STATUS_REG, data);
00321   ETHSPI_ReadRegister(RX_FRAME_THRES_REG, 2, &data);
00322   DEBUG_PRINT("REG[%2X] contains %2X\n", RX_FRAME_THRES_REG, data);
00323   ETHSPI_ReadRegister(TX_NEXT_FRS_REG, 2, &data);
00324   DEBUG_PRINT("REG[%2X] contains %2X\n", TX_NEXT_FRS_REG, data);
00325   ETHSPI_ReadRegister(CIDER_REG, 2, &data);
00326   DEBUG_PRINT("REG[%2X] contains %2X\n", CIDER_REG, data);
00327   ETHSPI_ReadRegister(PHY_RST_REG, 2, &data);
00328   DEBUG_PRINT("REG[%2X] contains %2X\n", PHY_RST_REG, data);
00329   ETHSPI_ReadRegister(PHY1_CTRL_REG, 2, &data);
00330   DEBUG_PRINT("REG[%2X] contains %2X\n", PHY1_CTRL_REG, data);
00331   ETHSPI_ReadRegister(PORT1_CTRL_REG, 2, &data);
00332   DEBUG_PRINT("REG[%2X] contains %2X\n", PORT1_CTRL_REG, data);
00333   DEBUG_PRINT("#################################################################\n");
00334 }
00335 #endif /* KSZ8851SNL_DEBUG */
00336 
00337 
00338 /***************************************************************************/
00341 void KSZ8851SNL_Init(void)
00342 {
00343   uint16_t data;
00344 
00345   /* Initialize SPI Interface */
00346   ETHSPI_Init();
00347 
00348   /* Reset Soft (clear registers of PHY, MAC, QMU, DMA) */
00349   data = GLOBAL_SOFT_RESET;
00350   ETHSPI_WriteRegister(GLOBAL_RESET_REG, 2, &data);
00351   ETHSPI_ReadRegister(GLOBAL_RESET_REG, 2, &data);
00352   data &= ~GLOBAL_SOFT_RESET;
00353   ETHSPI_WriteRegister(GLOBAL_RESET_REG, 2, &data);
00354 
00355   /* Reset QMU Modules(flush out TXQ and RXQ) */
00356   data = QMU_MODULE_SOFT_RESET;
00357   ETHSPI_WriteRegister(GLOBAL_RESET_REG, 2, &data);
00358   ETHSPI_ReadRegister(GLOBAL_RESET_REG, 2, &data);
00359   data &= ~QMU_MODULE_SOFT_RESET;
00360   ETHSPI_WriteRegister(GLOBAL_RESET_REG, 2, &data);
00361 
00362 #ifdef DIGITAL_PHY_LOOPBACK
00363   KSZ8851SNL_SetDigitalLoopbackMode();
00364 #endif /* DIGITAL_PHY_LOOPBACK */
00365 
00366   /* Read the chip ID and check if that is correct */
00367   ETHSPI_ReadRegister(CIDER_REG, 2, &data);
00368 
00369   /* The CIDER lower bits [3..1] are defined as revision number,
00370    *   thus a mask needs to be applied
00371    */
00372   if ((data & CHIP_ID_MASK) != KSZ8851SNL_CHIP_ID)
00373   {
00374     KSZ8851SNL_ExceptionHandler(ERROR, "ETH: Incorrect Device ID");
00375   }
00376 
00377   /* Write the Queue Management Unit MAC Address */
00378   KSZ8851SNL_GetMacAddress(macAddress);
00379   /* Write the appropriate KSZ8851SNL MAC registers
00380    *   starting from the HIGH part towards the lower one
00381    *   going with a step of 2
00382    */
00383   int i;
00384   for (i = 0; (i < 6); i += 2)
00385   {
00386     data = (macAddress[i] << MSB_POS) | macAddress[i + 1];
00387     ETHSPI_WriteRegister(HIGH_QMU_MAC_REG - i, 2, &data);
00388   }
00389 
00390   /* Enable QMU Transmit Frame Data Pointer Auto Increment */
00391   data = FD_PTR_AUTO_INC;
00392   ETHSPI_WriteRegister(TX_FD_PTR_REG, 2, &data);
00393 
00394   /* FLUSH TX queue */
00395   data |= TX_FLOW_CTRL_FLUSH_QUEUE;
00396   ETHSPI_WriteRegister(TX_FLOW_CTRL_REG, 2, &data);
00397 
00398   /* Enable QMU Transmit:
00399    *  flow control,
00400    *  padding,
00401    *  CRC,
00402    *  IP/TCP/UDP/ICMP checksum generation.
00403    */
00404   data = TX_FLOW_CTRL_EXAMPLE;
00405   ETHSPI_WriteRegister(TX_FLOW_CTRL_REG, 2, &data);
00406 
00407   /* Enable QMU Receive Frame Data Pointer Auto Increment */
00408   data = FD_PTR_AUTO_INC;
00409   ETHSPI_WriteRegister(RX_FD_PTR_REG, 2, &data);
00410 
00411   /* Configure Receive Frame Threshold for one frame */
00412   data = ONE_FRAME_THRES;
00413   ETHSPI_WriteRegister(RX_FRAME_THRES_REG, 2, &data);
00414 
00415   /* Enable QMU Receive:
00416    *  flow control,
00417    *  receive all broadcast frame,
00418    *  receive unicast frame,
00419    *  IP/TCP/UDP/ICMP checksum generation.
00420    */
00421   data = RX_FLOW_CTRL1_EXAMPLE;
00422   ETHSPI_WriteRegister(RX_FLOW_CTRL1_REG, 2, &data);
00423 
00424   /* Enable QMU Receive:
00425    *  ICMP/UDP Lite frame checksum verification,
00426    *  UDP Lite frame checksum generation,
00427    *  IPv6 UDP fragment frame pass.
00428    */
00429   data = RX_FLOW_CTRL2_EXAMPLE;
00430   ETHSPI_WriteRegister(RX_FLOW_CTRL2_REG, 2, &data);
00431 
00432   /* Enable QMU Receive:
00433    *  IP Header Two-Byte Offset,
00434    *  Receive Frame Count Threshold,
00435    *  RXQ Auto-Dequeue frame.
00436    */
00437   data = RXQ_CMD_EXAMPLE;
00438   ETHSPI_WriteRegister(RXQ_CMD_REG, 2, &data);
00439 
00440   /* Restart Port 1 auto-negotiation */
00441   ETHSPI_ReadRegister(PORT1_CTRL_REG, 2, &data);
00442   data |= PORT1_AUTO_NEG_RESTART;
00443   ETHSPI_WriteRegister(PORT1_CTRL_REG, 2, &data);
00444 
00445   /* Force link in half duplex if auto-negotiation failed  */
00446   ETHSPI_ReadRegister(PORT1_CTRL_REG, 2, &data);
00447   if ((data & PORT1_AUTO_NEG_RESTART) != PORT1_AUTO_NEG_RESTART)
00448   {
00449     data &= ~PORT1_FORCE_FULL_DUPLEX;
00450     ETHSPI_WriteRegister(PORT1_CTRL_REG, 2, &data);
00451   }
00452   /* Configure Low Watermark to 6KByte available buffer space out of 12KByte */
00453   data = WATERMARK_6KB;
00454   ETHSPI_WriteRegister(FLOW_CTRL_LOW_WATERMARK, 2, &data);
00455 
00456   /* Configure High Watermark to 4KByte available buffer space out of 12KByte */
00457   data = WATERMARK_4KB;
00458   ETHSPI_WriteRegister(FLOW_CTRL_HIGH_WATERMARK, 2, &data);
00459 
00460   /* Clear the interrupts status */
00461   data = CLEAR_INT;
00462   ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00463 
00464   /* Enable Interrupts on:
00465    *  Link Change
00466    *  Transmit
00467    *  Receive
00468    *  Receive Overrun
00469    *  Transmit Process Stop
00470    *  Receive Process Stop
00471    */
00472   data = INT_MASK_EXAMPLE;
00473   ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00474 
00475   /* Enable QMU Transmit */
00476   ETHSPI_ReadRegister(TX_FLOW_CTRL_REG, 2, &data);
00477   data |= TX_FLOW_CTRL_ENABLE;
00478   ETHSPI_WriteRegister(TX_FLOW_CTRL_REG, 2, &data);
00479 
00480   /* Enable QMU Receive */
00481   ETHSPI_ReadRegister(RX_FLOW_CTRL1_REG, 2, &data);
00482   data |= RX_FLOW_CTRL_ENABLE;
00483   ETHSPI_WriteRegister(RX_FLOW_CTRL1_REG, 2, &data);
00484 
00485   KSZ8851SNL_ExceptionHandler(INFO, "ETH: Initialization complete");
00486 }
00487 
00488 
00489 /***************************************************************************/
00497 void KSZ8851SNL_Send(uint16_t pTXLength, uint8_t *pTXData)
00498 {
00499   EFM_ASSERT(pTXData != NULL);
00500 
00501   uint16_t txmir;
00502   uint16_t data, reqSize;
00503   uint8_t  outbuf[4];
00504 
00505   /* Check if TXQ has enough memory for the transmission of the package */
00506   ETHSPI_ReadRegister(TX_MEM_INFO_REG, 2, &data);
00507   txmir = data & TX_MEM_AVAIL_MASK;
00508 
00509   reqSize = pTXLength + EXTRA_SIZE;
00510   if (txmir < reqSize)
00511   {
00512     KSZ8851SNL_ExceptionHandler(INFO, "I will wait until mem is available\n");
00513     /* Enable TX memory available monitor */
00514     ETHSPI_WriteRegister(TX_NEXT_FRS_REG, 2, &reqSize);
00515     ETHSPI_ReadRegister(TXQ_CMD_REG, 2, &data);
00516     data |= TXQ_MEM_AVAILABLE_INT;
00517     ETHSPI_WriteRegister(TXQ_CMD_REG, 2, &data);
00518 
00519     /* Wait until enough space is available */
00520     while (1)
00521     {
00522       ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00523       if ((data & INT_TX_SPACE) == INT_TX_SPACE)
00524       {
00525         break;
00526       }
00527     }
00528     KSZ8851SNL_ExceptionHandler(INFO, "Done\n");
00529 
00530     /* Clear flag */
00531     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00532     data &= ~INT_TX_SPACE;
00533     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00534   }
00535 
00536   /* Disable interupts on KSZ8851SNL */
00537   data = NO_INT;
00538   ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00539 
00540   /* Enable TXQ write access */
00541   ETHSPI_ReadRegister(RXQ_CMD_REG, 2, &data);
00542   data |= RXQ_START;
00543   ETHSPI_WriteRegister(RXQ_CMD_REG, 2, &data);
00544 
00545   /* Write frame ID, control word and byte count */
00546   outbuf[0] = (frameId++ & frameId_MASK) | TX_INT_on_COMPLETION;
00547   outbuf[1] = 0;
00548   outbuf[2] = pTXLength & LSB_MASK;
00549   outbuf[3] = pTXLength >> MSB_POS;
00550 
00551   /* Start the SPI Transfer */
00552   ETHSPI_StartWriteFIFO();
00553   /* Send the frame header info */
00554   ETHSPI_WriteFifoContinue(4, outbuf);
00555 
00556   /* Send the actual data */
00557   ETHSPI_WriteFifoContinue(pTXLength, pTXData);
00558 
00559   /* Send dummy bytes to align data to DWORD */
00560   ETHSPI_WriteFifoContinue(KSZ8851SNL_DwordAllignDiff(pTXLength), pTXData);
00561 
00562   /* Stop the SPI Transfer */
00563   ETHSPI_StopFIFO();
00564 
00565   /* Disable TXQ write access */
00566   ETHSPI_ReadRegister(RXQ_CMD_REG, 2, &data);
00567   data &= ~RXQ_START;
00568   ETHSPI_WriteRegister(RXQ_CMD_REG, 2, &data);
00569 
00570   /* Start TXQ Manual Engue */
00571   ETHSPI_ReadRegister(TXQ_CMD_REG, 2, &data);
00572   data |= TXQ_ENQUEUE;
00573   ETHSPI_WriteRegister(TXQ_CMD_REG, 2, &data);
00574 
00575   /* Wait until transmit command clears */
00576   while (1)
00577   {
00578     ETHSPI_ReadRegister(TXQ_CMD_REG, 2, &data);
00579     if (!(data & TXQ_ENQUEUE))
00580       break;
00581   }
00582 
00583   /* Enable interupts */
00584   data = INT_MASK_EXAMPLE;
00585   ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00586 }
00587 
00588 
00589 /***************************************************************************/
00596 void KSZ8851SNL_InitiateLongTransmit(uint16_t pTXLength)
00597 {
00598   uint16_t txmir;
00599   uint16_t data, reqSize;
00600   uint8_t  outbuf[4];
00601 
00602   /* Check if TXQ has enough memory for the transmission of the package */
00603   ETHSPI_ReadRegister(TX_MEM_INFO_REG, 2, &data);
00604   txmir = data & TX_MEM_AVAIL_MASK;
00605 
00606   reqSize = pTXLength + EXTRA_SIZE;
00607   if (txmir < reqSize)
00608   {
00609     KSZ8851SNL_ExceptionHandler(INFO, "I will wait until mem is available\n");
00610     /* Enable TX memory available monitor */
00611     ETHSPI_WriteRegister(TX_NEXT_FRS_REG, 2, &reqSize);
00612     ETHSPI_ReadRegister(TXQ_CMD_REG, 2, &data);
00613     data |= TXQ_MEM_AVAILABLE_INT;
00614     ETHSPI_WriteRegister(TXQ_CMD_REG, 2, &data);
00615 
00616     /* Wait until enough space is available */
00617     while (1)
00618     {
00619       ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00620       if ((data & INT_TX_SPACE) == INT_TX_SPACE)
00621       {
00622         break;
00623       }
00624     }
00625     KSZ8851SNL_ExceptionHandler(INFO, "Done\n");
00626 
00627     /* Clear flag */
00628     ETHSPI_ReadRegister(INT_STATUS_REG, 2, &data);
00629     data &= ~INT_TX_SPACE;
00630     ETHSPI_WriteRegister(INT_STATUS_REG, 2, &data);
00631   }
00632 
00633   /* Disable interupts on KSZ8851SNL */
00634   data = NO_INT;
00635   ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00636 
00637   /* Enable TXQ write access */
00638   ETHSPI_ReadRegister(RXQ_CMD_REG, 2, &data);
00639   data |= RXQ_START;
00640   ETHSPI_WriteRegister(RXQ_CMD_REG, 2, &data);
00641 
00642   /* Write frame ID, control word and byte count */
00643   outbuf[0] = (frameId++ & frameId_MASK) | TX_INT_on_COMPLETION;
00644   outbuf[1] = 0;
00645   outbuf[2] = pTXLength & LSB_MASK;
00646   outbuf[3] = pTXLength >> MSB_POS;
00647 
00648   /* Start the SPI Transfer */
00649   ETHSPI_StartWriteFIFO();
00650   /* Send the frame header info */
00651   ETHSPI_WriteFifoContinue(4, outbuf);
00652 }
00653 
00654 
00655 /***************************************************************************/
00663 void KSZ8851SNL_LongTransmit(uint16_t pTXLength, uint8_t *pTXData)
00664 {
00665   EFM_ASSERT(pTXData != NULL);
00666   /* Send the actual data */
00667   ETHSPI_WriteFifoContinue(pTXLength, pTXData);
00668 }
00669 
00670 
00671 /***************************************************************************/
00680 void KSZ8851SNL_TerminateLongTransmit(uint16_t pTXLength, uint8_t *pTXData)
00681 {
00682   EFM_ASSERT(pTXData != NULL);
00683 
00684   uint16_t data;
00685 
00686   /* Send dummy bytes to align data to DWORD */
00687   ETHSPI_WriteFifoContinue(KSZ8851SNL_DwordAllignDiff(pTXLength), pTXData);
00688 
00689   /* Stop the SPI Transfer */
00690   ETHSPI_StopFIFO();
00691 
00692   /* Disable TXQ write access */
00693   ETHSPI_ReadRegister(RXQ_CMD_REG, 2, &data);
00694   data &= ~RXQ_START;
00695   ETHSPI_WriteRegister(RXQ_CMD_REG, 2, &data);
00696 
00697   /* Start TXQ Manual Engue */
00698   ETHSPI_ReadRegister(TXQ_CMD_REG, 2, &data);
00699   data |= TXQ_ENQUEUE;
00700   ETHSPI_WriteRegister(TXQ_CMD_REG, 2, &data);
00701 
00702   /* Wait until transmit command clears */
00703   while (1)
00704   {
00705     ETHSPI_ReadRegister(TXQ_CMD_REG, 2, &data);
00706     if (!(data & TXQ_ENQUEUE))
00707       break;
00708   }
00709 
00710   /* Enable interupts */
00711   data = INT_MASK_EXAMPLE;
00712   ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00713 }
00714 
00715 
00716 /***************************************************************************/
00720 static void KSZ8851SNL_ReleaseIncosistentFrame(void)
00721 {
00722   uint16_t data;
00723   /* Issue the Release error frame command */
00724   ETHSPI_ReadRegister(RXQ_CMD_REG, 2, &data);
00725   data |= RXQ_RELEASE_CUR_FR;
00726   ETHSPI_WriteRegister(RXQ_CMD_REG, 2, &data);
00727   KSZ8851SNL_ExceptionHandler(INFO, "The frame was inconsistent\n");
00728 }
00729 
00730 
00731 #if KSZ8851SNL_DEBUG
00732 /***************************************************************************/
00736 static void KSZ8851SNL_SetDigitalLoopbackMode(void)
00737 {
00738   uint16_t data;
00739   /* Reset PHY. */
00740   data = PHY_RESET;
00741   ETHSPI_WriteRegister(PHY_RST_REG, 2, &data);
00742   /* Disable Auto-negotiation.1. Reset PHY. */
00743   /* Set Speed to either 100Base-TX or 10Base-T. */
00744   /* Set Duplex to full-duplex. */
00745   /* Set PHY register 0.14 to ‘1’ to enable Local Loop-back. */
00746   data  = DIGITAL_LOOPBACK | FORCE_FULL_DUPLEX | FORCE_100;
00747   data &= ~AUTO_NEG;
00748   ETHSPI_WriteRegister(PHY1_CTRL_REG, 2, &data);
00749 
00750   KSZ8851SNL_ExceptionHandler(INFO, "Loopback mode initiated");
00751 }
00752 #endif /* KSZ8851SNL_DEBUG */
00753 
00754 
00755 /***************************************************************************/
00766 uint16_t KSZ8851SNL_Receive(uint8_t *pRXData, uint16_t *pRXLength)
00767 {
00768   uint16_t data;
00769   uint8_t  *pDummy = pRXData;
00770   uint16_t rxFrameCount, rxftr;
00771   uint16_t rxStatus;
00772 
00773   EFM_ASSERT(pRXData != NULL);
00774   EFM_ASSERT(pRXLength != NULL);
00775 
00776   /* Read the frame count and threshold register */
00777   ETHSPI_ReadRegister(RX_FRAME_THRES_REG, 2, &rxftr);
00778   /* Extract the actual number of frames from RX_FRAME_THRES_REG*/
00779   rxFrameCount = rxftr >> MSB_POS;
00780 
00781   while (rxFrameCount > 0)
00782   {
00783     /* Read the received frame status */
00784     ETHSPI_ReadRegister(RX_FRH_STAT_REG, 2, &rxStatus);
00785 
00786     /* Check the consistency of the frame */
00787     if (!(rxStatus >> RECEIVED_FRAME_VALID_POS == 0) || ((rxStatus & RECEIVE_VALID_FRAME_MASK) == RECEIVE_VALID_FRAME_MASK))
00788     {
00789       /* Issue the Release error frame command */
00790       KSZ8851SNL_ReleaseIncosistentFrame();
00791     }
00792     else
00793     {
00794       /* Read the byte size of the received frame */
00795       ETHSPI_ReadRegister(RX_FRH_BC_REG, 2, pRXLength);
00796 
00797       *pRXLength &= RX_BYTE_CNT_MASK;
00798 
00799       if (*pRXLength <= 0)
00800       {
00801         /* Issue the Release error frame command */
00802         KSZ8851SNL_ReleaseIncosistentFrame();
00803         /* Discard the frame*/
00804         rxFrameCount--;
00805         /* continue to next frame */
00806         continue;
00807       }
00808 
00809       /* Reset QMU RXQ frame pointer to zero */
00810       data = FD_PTR_AUTO_INC;
00811       ETHSPI_WriteRegister(RX_FD_PTR_REG, 2, &data);
00812 
00813       /* Start QMU DMA transfer */
00814       ETHSPI_ReadRegister(RXQ_CMD_REG, 2, &data);
00815       data |= RXQ_START;
00816       ETHSPI_WriteRegister(RXQ_CMD_REG, 2, &data);
00817 
00818       /* Start the SPI transfer */
00819       ETHSPI_StartReadFIFO();
00820 
00821       /* Read 4 dummy, 2 status word and 2 bytecount bytes of the frame header */
00822       ETHSPI_ReadFifoContinue(4, pDummy);
00823       ETHSPI_ReadFifoContinue(2, pDummy);
00824       ETHSPI_ReadFifoContinue(2, pDummy);
00825 
00826       /* Remove the first 2 extra bytes consisting of the 2 bytes offset*/
00827       ETHSPI_ReadFifoContinue(2, pDummy);
00828       *pRXLength -= 2;
00829 
00830       /* Read the received data */
00831       ETHSPI_ReadFifoContinue(*pRXLength, pRXData);
00832 
00833       /* Stoping the SPI transfer */
00834       ETHSPI_StopFIFO();
00835 
00836       /* Stop QMU DMA transfer */
00837       ETHSPI_ReadRegister(RXQ_CMD_REG, 2, &data);
00838       data &= ~RXQ_START;
00839       ETHSPI_WriteRegister(RXQ_CMD_REG, 2, &data);
00840 
00841       /* Enable interupts */
00842       data = INT_MASK_EXAMPLE;
00843       ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00844 
00845       /* Remove the last 4 extra bytes consisting of the CRC field*/
00846       *pRXLength -= 4;
00847 
00848       /* After reading one frame, we return its length.
00849        *   Can also be implemented as callback function
00850        *   but it is not the purpose of lwIP implementation
00851        */
00852       return *pRXLength;
00853     }
00854 
00855     /* Finished reading one frame */
00856     rxFrameCount--;
00857 
00858     /* Enable interupts */
00859     data = INT_MASK_EXAMPLE;
00860     ETHSPI_WriteRegister(INT_ENABLE_REG, 2, &data);
00861   }
00862   return 0;
00863 }
00864 
00865 
00866 /***************************************************************************/
00872 void KSZ8851SNL_GetMacAddress(uint8_t *macAddress)
00873 {
00874   /* TODO:  Get MAC based on actual MAC and not on the CMU unique ID. */
00875 
00876   EFM_ASSERT(macAddress != NULL);
00877 
00878   /* set the first 3 bytes given by the EM MAC Address space */
00879   macAddress[0] = HIGH_QMU_MAC_H;
00880   macAddress[1] = HIGH_QMU_MAC_L;
00881   macAddress[2] = MID_QMU_MAC_H;
00882   /* set the next 3 bytes given by the CMU unique ID */
00883   int i;
00884   for (i = 0; i < 3; i++)
00885   {
00886     macAddress[5 - i] = (DEVINFO->UNIQUEL & (BYTE_MASK << i * BYTE_SIZE)) >> i * BYTE_SIZE;
00887   }
00888 }
00889