ksz8851snl.c

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