/***************************************************************** Ethernet Receive/Transmit Buffer Descriptor *****************************************************************/ // These Buffer Descriptors (BD) are hardware related and are defined in the RM. #include "pack_begin.h" struct rxbd_s { uint16_t flags; uint16_t data_len; uint8_t *p_buf; }; #include "pack_end.h" typedef struct rxbd_s rxbd_t; #include "pack_begin.h" struct txbd_s { uint16_t flags; uint16_t data_len; uint8_t *p_buf; }; #include "pack_end.h" typedef struct txbd_s txbd_t; #define NUM_RXBDS 64 // Number of RX BDs in chain, THIS MUST BE A BINARY MULTIPLE, eg 16,32,64,128 etc. #define NUM_TXBDS 64 // Number of TX BDs in chain, THIS MUST BE A BINARY MULTIPLE, eg 16,32,64,128 etc. rxbd_t rxbd[NUM_RXBDS]; // Rx descriptor ring. Must be aligned to double-word txbd_t txbd[NUM_TXBDS]; // Tx descriptor ring. Must be aligned to double-word uint16_t rx_remove; // Index that driver will remove next rx frame from. uint16_t rx_insert; // Index that driver will insert next empty rx buffer. uint16_t tx_insert; // Index that driver will insert next tx frame to. uint16_t tx_remove; // Index that driver will clean up next tx buffer. // Ethernet interface #define GPIO_ETH_TXD0 201 #define GPIO_ETH_TXD1 202 #define GPIO_ETH_TXD2 203 #define GPIO_ETH_TXD3 204 #define GPIO_ETH_RXD0 211 #define GPIO_ETH_RXD1 212 #define GPIO_ETH_RXD2 213 #define GPIO_ETH_RXD3 214 #define GPIO_ETH_TX_EN 200 #define GPIO_ETH_TX_ER 205 #define GPIO_ETH_TX_CLK 207 #define GPIO_ETH_RX_DV 210 #define GPIO_ETH_RX_ER 215 #define GPIO_ETH_RX_CLK 209 #define GPIO_ETH_CRS 208 #define GPIO_ETH_COL 206 #define GPIO_ETH_MDC 199 #define GPIO_ETH_MDIO 198 // MISC #define GPIO_ETH_RESET 195 static void HalEthernetInitBD() { uint16_t i; /* Initialize empty tx descriptor ring */ for (i = 0; i < NUM_TXBDS - 1; i++) txbd[i].flags = 0; /* Set wrap bit for last descriptor */ txbd[i].flags = TX_BD_W; /* initialize tx indexes */ tx_remove = 0; tx_insert = 0; /* Initialize empty rx descriptor ring */ for (i = 0; i < NUM_RXBDS - 1; i++) rxbd[i].flags = 0; /* Set wrap bit for last descriptor */ rxbd[i].flags = RX_BD_W; /* Initialize rx indexes */ rx_remove = 0; rx_insert = 0; } void HalEthernetEnable() { // Enable the FEC FEC.ECR.B.ETHER_EN=1; // Start receiving FEC.RDAR.R=0xffffffff; } void HalEthernetDisable() { /* Reset the FEC - equivalent to a hard reset */ FEC.ECR.R=1; // Wait for the reset sequence to complete, should take about 16 clock cycles int i = 0; while (FEC.ECR.B.RESET) { if (++i > 100) break; } } void HalEthernetClearTxIrq() { /* clear interrupt status for tx interrupt */ FEC.EIR.R=0x0C000000; } bool HalEthernetInit(uint8_t mac[6], uint16_t rx_buf_len) { uint32_t timer=0; //uint16_t mii_register_data; // We support only one frame length if(rx_buf_len != ETHERNET_RECEIVE_BUFFER_SIZE) return false; HalEthernetDisable(); // Clear MIB RAM memset((void*) 0xfff4c200, 0, (unsigned long)0xE0); // Ethernet reset SIU.GPDO[GPIO_ETH_RESET].R=0; // Ethernet reset SIU.PCR[GPIO_ETH_RESET].R=0x300; // GPIO mode, enable output buffer // Set MDC frequency to 2.5MHz, assuming system clock is 90MHz FEC.MSCR.B.MII_SPEED=0x24; // MDC D13 O A1 SIU.PCR[GPIO_ETH_MDC].B.PA=1; // Alternate 1 SIU.PCR[GPIO_ETH_MDC].B.IBE=1; // Enable input buffer // MDIO A13 O A1 SIU.PCR[GPIO_ETH_MDIO].B.PA=1; // Alternate 1 SIU.PCR[GPIO_ETH_MDIO].B.IBE=1; // Enable input buffer // Wait until the ethernet chip and switch are ready // Sleep a bit to make sure chip enters reset, at least 25ms! HalDelayMs(100); // Bring the ethernet transceiver out of reset. SIU.GPDO[GPIO_ETH_RESET].R=1; // Sleep a bit to make sure that the chip latches our configured values before reconfiguring the IOs HalDelayMs(25); // TXD0 C12 O A1 SIU.PCR[GPIO_ETH_TXD0].B.PA=1; // Alternate 1 SIU.PCR[GPIO_ETH_TXD0].B.IBE=1; // Enable input buffer // TXD1 D11 O A1 SIU.PCR[GPIO_ETH_TXD1].B.PA=1; // Alternate 1 SIU.PCR[GPIO_ETH_TXD1].B.IBE=1; // Enable input buffer // TXD2 D10 O A1 SIU.PCR[GPIO_ETH_TXD2].B.PA=1; // Alternate 1 SIU.PCR[GPIO_ETH_TXD2].B.IBE=1; // Enable input buffer // TXD3 A15 O A1 SIU.PCR[GPIO_ETH_TXD3].B.PA=1; // Alternate 1 SIU.PCR[GPIO_ETH_TXD3].B.IBE=1; // Enable input buffer // TX_EN A14 O A1 SIU.PCR[GPIO_ETH_TX_EN].B.PA=1; // Alternate 1 SIU.PCR[GPIO_ETH_TX_EN].B.IBE=1; // Enable input buffer // TX_ER B13 O A1 SIU.PCR[GPIO_ETH_TX_ER].B.PA=1; // Alternate 1 SIU.PCR[GPIO_ETH_TX_ER].B.IBE=1; // Enable input buffer // TX_CLK B14 I SIU.PCR[GPIO_ETH_TX_CLK].B.IBE=1; // Enable input buffer // RXD0 A12 I SIU.PCR[GPIO_ETH_RXD0].B.IBE=1; // Enable input buffer // RXD1 B12 I SIU.PCR[GPIO_ETH_RXD1].B.IBE=1; // Enable input buffer // RXD2 A10 I SIU.PCR[GPIO_ETH_RXD2].B.IBE=1; // Enable input buffer // RXD3 B10 I SIU.PCR[GPIO_ETH_RXD3].B.IBE=1; // Enable input buffer // RX_ER B11 I SIU.PCR[GPIO_ETH_RX_ER].B.IBE=1; // Enable input buffer // RX_DV D12 I SIU.PCR[GPIO_ETH_RX_DV].B.IBE=1; // Enable input buffer // RX_CLK A11 I SIU.PCR[GPIO_ETH_RX_CLK].B.IBE=1; // Enable input buffer // CRS C11 I SIU.PCR[GPIO_ETH_CRS].B.IBE=1; // Enable input buffer // COL C13 O A1 SIU.PCR[GPIO_ETH_COL].B.PA=1; // Alternate 1 SIU.PCR[GPIO_ETH_COL].B.IBE=1; // Enable input buffer // Disable all interrupts (we will poll) FEC.EIMR.R=0; // Clear Interrupt Event Register FEC.EIR.R=0xFFFFFFFF; // Set lowest transmit watermark to minimize latency FEC.TFWR.R=0; // Set our MAC address FEC.PALR.R= 0 | (mac[0] << 24) | (mac[1] << 16) | (mac[2] << 8) | (mac[3] << 0); FEC.PAUR.R= 0 | (mac[4] << 24) | (mac[5] << 16); // Flow control PAUSE_DUR FEC.OPD.R=0xf; // Set full duplex FEC.TCR.B.FDEN=1; // Set MII mode FEC.RCR.B.MII_MODE=1; // Accept broadcasts FEC.RCR.B.BC_REJ=0; // Disable loopback FEC.RCR.B.LOOP=0; FEC.RCR.B.DRT=0; // Enable promiscuous mode (FOR TESTING ONLY!!!!!!) //FEC.RCR.B.PROM=1; // Set Receive Buffer Size to 2047 bytes. The FEC will truncate larger frames so we don't need support for >2047. FEC.EMRBR.R=ETHERNET_RECEIVE_BUFFER_SIZE-1; HalEthernetInitBD(); // Setup receive BDs start address FEC.ERDSR.R=(uint32_t)rxbd; // Setup transmit BDs start address FEC.ETDSR.R=(uint32_t)txbd; // Enable MIB counters FEC.MIBC.B.MIB_DISABLE=0; // Clear hash table registers FEC.IAUR.R=0; FEC.IALR.R=0; FEC.GAUR.R=0; FEC.GALR.R=0; HalEthernetEnable(); return true; } void HalEthernetTxDescriptorUpdated() { /* Indicate that there has been a transmit buffer produced */ FEC.TDAR.R=0; } void HalEthernetRxDescriptorUpdated() { /* Tell fec that we have filled up her ring */ FEC.RDAR.R=0xffffffff; } uint16_t HalEthernetMIIRegisterRead(uint8_t mii_register) { FEC.EIR.R=0x00800000; FEC.MMFR.R=0x60000000 | (mii_register<<18) | 0x00020000; while(FEC.EIR.B.MII==0) ; // Reset IRQ FEC.EIR.R=0x00800000; return (uint16_t) FEC.MMFR.R&0xffff; } void HalEthernetMIIRegisterWrite(uint8_t mii_register, uint16_t data) { FEC.EIR.R=0x00800000; FEC.MMFR.R=0x50000000 | (mii_register<<18) | 0x00020000 | data; while(FEC.EIR.B.MII==0) ; // Reset IRQ FEC.EIR.R=0x00800000; } bool HalEthernetIsRxAvailable() { if(FEC.EIR.B.RXF) { FEC.EIR.R=0x03000000; return true; } return false; } void HalEthernetResetSet(uint8_t value) { SIU.GPDO[GPIO_ETH_RESET].R = value; SIU.PCR[GPIO_ETH_RESET].R=0x300; // GPIO mode, enable output buffer } uint8_t HalEthernetResetGet() { return SIU.GPDI[GPIO_ETH_RESET].R; } bool HalEthernetSendBuffer(void *buffer, uint16_t length) { if(tx_insert - tx_remove == (uint16_t) NUM_TXBDS) { HalEcuReset(); return false; } uint16_t index=tx_insert++%NUM_TXBDS; txbd[index].p_buf=(uint8_t*)buffer; txbd[index].data_len=length; txbd[index].flags=(txbd[index].flags&TX_BD_W) |TX_BD_L|TX_BD_R|TX_BD_TC; HalEthernetTxDescriptorUpdated(); return true; } void *HalEthernetReclaimSendBuffer() { // Is there anything to remove from the send queue? if(tx_insert==tx_remove) return 0; uint16_t index=tx_remove%NUM_TXBDS; if( (txbd[index].flags&TX_BD_R)==0) { ++tx_remove; return txbd[index].p_buf; } HalEthernetClearTxIrq(); return 0; } bool HalEthernetAddReceiveBuffer(void *buffer, uint16_t length) { if(rx_insert - rx_remove == (uint16_t) NUM_RXBDS) { return false; } uint16_t index=rx_insert++%NUM_RXBDS; rxbd[index].p_buf=(uint8_t*)buffer; rxbd[index].data_len=length; rxbd[index].flags=(rxbd[index].flags&RX_BD_W)|RX_BD_E; /* Tell fec that we have filled up her ring */ HalEthernetRxDescriptorUpdated(); return true; } void *HalEthernetGetReceiveBuffer(uint16_t *length, uint16_t *flags) { // Don't base the guess about rx availability upon this one HalEthernetIsRxAvailable(); // Is there anything to remove from receive queue? if(rx_insert==rx_remove) return 0; uint16_t index=rx_remove%NUM_RXBDS; if((rxbd[index].flags&(RX_BD_E|RX_BD_L))==RX_BD_L) { ++rx_remove; *length=rxbd[index].data_len; *flags=rxbd[index].flags; return rxbd[index].p_buf; } return 0; }