1 #include "NyLPC_config.h"
\r
2 #if NyLPC_MCU==NyLPC_MCU_LPC4088
\r
3 #include "NyLPC_os.h"
\r
4 #include "copy_of_ethernet_api.h"
\r
5 #include "NyLPC_IEthernetDevice.h"
\r
6 #include "NyLPC_cEthernetMM.h"
\r
10 #define emacSHORT_DELAY_MS 10
\r
11 #ifndef configEMAC_INTERRUPT_PRIORITY
\r
12 #define configEMAC_INTERRUPT_PRIORITY 5
\r
14 ////////////////////////////////////////////////////////////////////////////////
\r
16 ////////////////////////////////////////////////////////////////////////////////
\r
18 #define AHB_SRAM_BANK1_BASE 0x20004000UL
\r
19 #define RX_DESC_BASE (AHB_SRAM_BANK1_BASE )
\r
20 #define RX_STAT_BASE (RX_DESC_BASE + NUM_RX_FRAG*(2*4)) /* 2 * uint32_t, see RX_DESC_TypeDef */
\r
21 #define TX_DESC_BASE (RX_STAT_BASE + NUM_RX_FRAG*(2*4)) /* 2 * uint32_t, see RX_STAT_TypeDef */
\r
22 #define TX_STAT_BASE (TX_DESC_BASE + NUM_TX_FRAG*(2*4)) /* 2 * uint32_t, see TX_DESC_TypeDef */
\r
23 #define ETH_BUF_BASE (TX_STAT_BASE + NUM_TX_FRAG*(1*4)) /* 1 * uint32_t, see TX_STAT_TypeDef */
\r
27 * descriptor = NUM_RX_FRAG*16+NUM_TX_FRAG*12.
\r
28 * EthnetBuf=ETH_FRAG_SIZE*NUM_RX_FRAG
\r
31 /* RX and TX descriptor and status definitions. */
\r
32 #define RX_DESC_PACKET(i) (*(unsigned int *)(RX_DESC_BASE + 8*i))
\r
33 #define RX_DESC_CTRL(i) (*(unsigned int *)(RX_DESC_BASE+4 + 8*i))
\r
34 #define RX_STAT_INFO(i) (*(unsigned int *)(RX_STAT_BASE + 8*i))
\r
35 #define RX_STAT_HASHCRC(i) (*(unsigned int *)(RX_STAT_BASE+4 + 8*i))
\r
36 #define TX_DESC_PACKET(i) (*(unsigned int *)(TX_DESC_BASE + 8*i))
\r
37 #define TX_DESC_CTRL(i) (*(unsigned int *)(TX_DESC_BASE+4 + 8*i))
\r
38 #define TX_STAT_INFO(i) (*(unsigned int *)(TX_STAT_BASE + 4*i))
\r
39 #define ETH_BUF(i) ( ETH_BUF_BASE + ETH_FRAG_SIZE*i )
\r
40 #define ETH_TX_BUF_BASE ((void*)(ETH_BUF_BASE+ETH_FRAG_SIZE*NUM_RX_FRAG))
\r
43 #define emacWAIT_FOR_LINK_TO_ESTABLISH_MS 500
\r
45 ////////////////////////////////////////////////////////////////////////////////
\r
46 // Ethernet interdface functions
\r
47 ////////////////////////////////////////////////////////////////////////////////
\r
48 static NyLPC_TBool start(const struct NyLPC_TEthAddr* i_eth_addr,NyLPC_TiEthernetDevice_onEvent i_handler,void* i_param);
\r
49 static void stop(void);
\r
50 static void* getRxEthFrame(unsigned short* o_len_of_data);
\r
51 static void nextRxEthFrame(void);
\r
52 static void* allocTxBuf(NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_size);
\r
53 static void releaseTxBuf(void* i_buf);
\r
54 static void sendTxEthFrame(void* i_buf,unsigned short i_size);
\r
55 static void processTx(void);
\r
57 ////////////////////////////////////////////////////////////////////////////////
\r
59 ////////////////////////////////////////////////////////////////////////////////
\r
60 static void emacIsrHandler(unsigned long i_status);
\r
61 static unsigned int clockselect(void);
\r
62 static int ethernet_link(void);
\r
63 static int phy_write(unsigned int PhyReg, unsigned short Data);
\r
64 static int phy_read(unsigned int PhyReg);
\r
65 static void prevTxDescriptor(void);
\r
66 static void prevRxDescriptor(void);
\r
67 static NyLPC_TUInt32 waitForTxEthFrameEmpty(void);
\r
69 /*-----------------------------------------------------------*/
\r
72 const static struct TiEthernetDevice _interface_LAN8720=
\r
84 const static struct TiEthernetDevice _interface_DP83848C=
\r
97 static void* _event_param;
\r
98 static NyLPC_TiEthernetDevice_onEvent _event_handler;
\r
99 static unsigned int phy_id;
\r
102 * EthernetDeviceのファクトリー関数。インターフェイスを生成できればtrue
\r
105 NyLPC_TBool EthDev_LPC4088_getInterface(
\r
106 const struct TiEthernetDevice** o_dev)
\r
109 unsigned int clock = clockselect();
\r
111 LPC_SC->PCONP |= 0x40000000; /* Power Up the EMAC controller. */
\r
112 LPC_IOCON->P1_0 &= ~0x07; /* ENET I/O config */
\r
113 LPC_IOCON->P1_0 |= 0x01; /* ENET_TXD0 */
\r
114 LPC_IOCON->P1_1 &= ~0x07;
\r
115 LPC_IOCON->P1_1 |= 0x01; /* ENET_TXD1 */
\r
116 LPC_IOCON->P1_4 &= ~0x07;
\r
117 LPC_IOCON->P1_4 |= 0x01; /* ENET_TXEN */
\r
118 LPC_IOCON->P1_8 &= ~0x07;
\r
119 LPC_IOCON->P1_8 |= 0x01; /* ENET_CRS */
\r
120 LPC_IOCON->P1_9 &= ~0x07;
\r
121 LPC_IOCON->P1_9 |= 0x01; /* ENET_RXD0 */
\r
122 LPC_IOCON->P1_10 &= ~0x07;
\r
123 LPC_IOCON->P1_10 |= 0x01; /* ENET_RXD1 */
\r
124 LPC_IOCON->P1_14 &= ~0x07;
\r
125 LPC_IOCON->P1_14 |= 0x01; /* ENET_RX_ER */
\r
126 LPC_IOCON->P1_15 &= ~0x07;
\r
127 LPC_IOCON->P1_15 |= 0x01; /* ENET_REF_CLK */
\r
128 LPC_IOCON->P1_16 &= ~0x07; /* ENET/PHY I/O config */
\r
129 LPC_IOCON->P1_16 |= 0x01; /* ENET_MDC */
\r
130 LPC_IOCON->P1_17 &= ~0x07;
\r
131 LPC_IOCON->P1_17 |= 0x01; /* ENET_MDIO */
\r
133 /* Reset all EMAC internal modules. */
\r
134 LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;
\r
135 LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;
\r
136 for (tout = 100; tout; tout--) { __NOP(); } /* A short delay */
\r
138 /* Initialize MAC control registers. */
\r
139 LPC_EMAC->MAC1 = MAC1_PASS_ALL;
\r
140 LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
\r
141 LPC_EMAC->MAXF = ETH_MAX_FLEN;
\r
142 LPC_EMAC->CLRT = CLRT_DEF;
\r
143 LPC_EMAC->IPGR = IPGR_DEF;
\r
145 /* Enable Reduced MII interface. */
\r
146 LPC_EMAC->MCFG = (clock << 0x2) & MCFG_CLK_SEL; /* Set clock */
\r
147 LPC_EMAC->MCFG |= MCFG_RES_MII; /* and reset */
\r
148 LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM |CR_PASS_RX_FILT; /* Enable Reduced MII interface. */
\r
150 for (tout = 100; tout; tout--) { __NOP(); } /* A short delay */
\r
152 LPC_EMAC->MCFG = (clock << 0x2) & MCFG_CLK_SEL;
\r
153 LPC_EMAC->MCMD = 0;
\r
154 LPC_EMAC->SUPP = SUPP_RES_RMII; /* Reset Reduced MII Logic. */
\r
155 for (tout = 100; tout; tout--) { __NOP(); } /* A short delay */
\r
156 LPC_EMAC->SUPP = SUPP_SPEED;
\r
158 phy_write(PHY_REG_BMCR, PHY_BMCR_RESET); /* perform PHY reset */
\r
159 for(tout = 0x20000; ; tout--) { /* Wait for hardware reset to end. */
\r
160 regv = phy_read(PHY_REG_BMCR);
\r
161 if(regv < 0 || tout == 0) {
\r
162 return NyLPC_TBool_FALSE; /* Error */
\r
164 if(!(regv & PHY_BMCR_RESET)) {
\r
165 break; /* Reset complete. */
\r
169 phy_id = (phy_read(PHY_REG_IDR1) << 16);
\r
170 phy_id |= (phy_read(PHY_REG_IDR2) & 0XFFF0);
\r
174 *o_dev=&_interface_DP83848C;
\r
177 *o_dev=&_interface_LAN8720;
\r
180 return NyLPC_TBool_FALSE; /* Error */
\r
182 LPC_EMAC->TxProduceIndex = 0;
\r
183 LPC_EMAC->RxConsumeIndex = 0;
\r
184 return NyLPC_TBool_TRUE;
\r
189 static NyLPC_TBool start(const struct NyLPC_TEthAddr* i_eth_addr,NyLPC_TiEthernetDevice_onEvent i_handler,void* i_param)
\r
193 NyLPC_cIsr_setEnetISR(emacIsrHandler);
\r
194 _event_handler=i_handler;
\r
195 _event_param=i_param;
\r
196 /* Set the Ethernet MAC Address registers */
\r
197 LPC_EMAC->SA0 = (((uint32_t)(i_eth_addr->addr[0])) << 8 ) | i_eth_addr->addr[1];
\r
198 LPC_EMAC->SA1 = (((uint32_t)(i_eth_addr->addr[2])) << 8 ) | i_eth_addr->addr[3];
\r
199 LPC_EMAC->SA2 = (((uint32_t)(i_eth_addr->addr[4])) << 8 ) | i_eth_addr->addr[5];
\r
202 NyLPC_cEthernetMM_initialize(ETH_TX_BUF_BASE);
\r
203 /* Initialize Tx and Rx DMA Descriptors */
\r
204 prevRxDescriptor();
\r
205 prevTxDescriptor();
\r
206 //wait for link up
\r
208 if(ethernet_link()!=0){
\r
211 NyLPC_cThread_sleep(emacWAIT_FOR_LINK_TO_ESTABLISH_MS);
\r
215 ethernet_set_link(-1, 0);
\r
217 LPC_EMAC->RxFilterCtrl = RFC_UCAST_EN | RFC_MCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;
\r
218 /* Receive Broadcast, Perfect Match Packets */
\r
221 NyLPC_cIsr_enterCritical();
\r
223 LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE; /* Enable EMAC interrupts. */
\r
224 LPC_EMAC->IntClear = 0xFFFF; /* Reset all interrupts */
\r
226 LPC_EMAC->Command |= (CR_RX_EN | CR_TX_EN); /* Enable receive and transmit mode of MAC Ethernet core */
\r
227 LPC_EMAC->MAC1 |= MAC1_REC_EN;
\r
229 NVIC_SetPriority( ENET_IRQn, configEMAC_INTERRUPT_PRIORITY );
\r
230 NVIC_EnableIRQ( ENET_IRQn );
\r
232 NyLPC_cIsr_exitCritical();
\r
234 return NyLPC_TBool_TRUE;
\r
238 static void stop(void)
\r
240 NyLPC_cIsr_enterCritical();
\r
242 LPC_EMAC->IntEnable &= ~(INT_RX_DONE | INT_TX_DONE);
\r
243 LPC_EMAC->IntClear = 0xFFFF;
\r
245 NVIC_DisableIRQ( ENET_IRQn );
\r
247 NyLPC_cIsr_exitCritical();
\r
248 LPC_EMAC->Command &= ~( CR_RX_EN | CR_TX_EN );
\r
249 LPC_EMAC->MAC1 &= ~MAC1_REC_EN;
\r
251 NyLPC_cIsr_setEnetISR(NULL);
\r
253 NyLPC_cEthernetMM_finalize();
\r
256 static void* allocTxBuf(NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_size)
\r
258 return NyLPC_cEthernetMM_alloc(i_hint,o_size);
\r
260 static void releaseTxBuf(void* i_buf)
\r
262 NyLPC_cEthernetMM_release(i_buf);
\r
268 static void processTx(void)
\r
270 waitForTxEthFrameEmpty();
\r
276 * Ethernetパケットを送信します。
\r
277 * allocTxBufで得たバッファを指定すること。
\r
282 static void sendTxEthFrame(void* i_buf,unsigned short i_size)
\r
284 NyLPC_TUInt32 IndexNext,Index;
\r
285 struct NyLPC_TTxBufferHeader* bh=NyLPC_TTxBufferHeader_getBufferHeaderAddr(i_buf);
\r
293 IndexNext =waitForTxEthFrameEmpty();
\r
295 //送信対象のメモリブロックを送信中に設定。
\r
302 bh->is_lock=NyLPC_TUInt8_TRUE;
\r
305 Index = LPC_EMAC->TxProduceIndex;
\r
306 if (i_size > ETH_FRAG_SIZE){
\r
307 i_size = ETH_FRAG_SIZE;
\r
310 TX_DESC_PACKET( Index ) = ( unsigned long )i_buf;
\r
311 //See UM10360.pdf Table 181. Transmit descriptor control word
\r
312 TX_DESC_CTRL( Index ) = ((i_size-1) | TCTRL_LAST | TCTRL_INT );
\r
313 LPC_EMAC->TxProduceIndex = IndexNext;
\r
319 static void prevTxDescriptor(void)
\r
323 for( x = 0; x < NUM_TX_FRAG; x++ )
\r
325 TX_DESC_PACKET( x ) = ( unsigned long ) NULL;
\r
326 TX_DESC_CTRL( x ) = 0;
\r
327 TX_STAT_INFO( x ) = 0;
\r
329 /* Set LPC_EMAC Transmit Descriptor Registers. */
\r
330 LPC_EMAC->TxDescriptor =TX_DESC_BASE;
\r
331 LPC_EMAC->TxStatus = TX_STAT_BASE;
\r
332 LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG - 1;
\r
334 static void prevRxDescriptor(void)
\r
338 for( x = 0; x < NUM_RX_FRAG; x++ )
\r
340 /* Allocate the next Ethernet buffer to this descriptor. */
\r
341 RX_DESC_PACKET(x) = ETH_BUF(x);
\r
342 RX_DESC_CTRL(x) = RCTRL_INT | ( ETH_FRAG_SIZE - 1 );
\r
343 RX_STAT_INFO(x) = 0;
\r
344 RX_STAT_HASHCRC(x) = 0;
\r
347 /* Set LPC_EMAC Receive Descriptor Registers. */
\r
348 LPC_EMAC->RxDescriptor = RX_DESC_BASE;
\r
349 LPC_EMAC->RxStatus = RX_STAT_BASE;
\r
350 LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG - 1;
\r
356 * 受信キューの先頭にあるRXフレームのポインタを返します。
\r
357 * 関数は、受信キューのポインタを操作しません。続けて読み出したとしても、同じポインターを返します。
\r
358 * 制限として、返却したポインタの内容は、一時的に書き換え可としてください。(この制限は将来削除します。)
\r
360 * 成功した場合、受信データを格納したバッファポインターです。
\r
361 * 次回nextRxEthFrameを呼び出すまで有効です。
\r
363 static void* getRxEthFrame(unsigned short* o_len_of_data)
\r
365 if( LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex )
\r
368 *o_len_of_data = (unsigned short)(( RX_STAT_INFO( LPC_EMAC->RxConsumeIndex ) & RINFO_SIZE ) - 3);
\r
369 return ( unsigned char * ) RX_DESC_PACKET( LPC_EMAC->RxConsumeIndex );
\r
378 static void nextRxEthFrame(void)
\r
381 if( LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex )
\r
384 lIndex = LPC_EMAC->RxConsumeIndex;
\r
386 if( lIndex >= NUM_RX_FRAG )
\r
390 LPC_EMAC->RxConsumeIndex = lIndex;
\r
393 /********************************************************************************
\r
394 * Private functions
\r
395 *******************************************************************************/
\r
400 * 送信中のイーサフレームを処理する機会を与えて、送信キューが空くまで待ちます。
\r
401 * LPC1769の場合は、非同期に更新したディスクリプタの内容から、送信メモリのフラグを更新します。
\r
403 * 次に書き込むことが出来る送信キュー。
\r
405 static NyLPC_TUInt32 waitForTxEthFrameEmpty(void)
\r
407 NyLPC_TUInt32 IndexNext;
\r
408 struct NyLPC_TTxBufferHeader *b;
\r
413 IndexNext = (LPC_EMAC->TxProduceIndex + 1)%NUM_TX_FRAG;
\r
415 //送信キューフルが解除されるまで待ち
\r
416 while(IndexNext == LPC_EMAC->TxConsumeIndex)
\r
419 NyLPC_cThread_sleep(emacSHORT_DELAY_MS);
\r
422 //(TxProduceIndex+1)→TxConsumeIndexにあるデータのsentフラグを消去
\r
423 for(i=IndexNext;i!=LPC_EMAC->TxConsumeIndex;i=(i+1)%NUM_TX_FRAG)
\r
425 p=(void*)TX_DESC_PACKET(i);
\r
427 b=NyLPC_TTxBufferHeader_getBufferHeaderAddr(p);
\r
428 b->is_lock=NyLPC_TUInt8_FALSE;
\r
429 TX_DESC_PACKET(i)=0;
\r
432 p=(void*)TX_DESC_PACKET(i);
\r
434 b=NyLPC_TTxBufferHeader_getBufferHeaderAddr(p);
\r
435 b->is_lock=NyLPC_TUInt8_FALSE;
\r
436 TX_DESC_PACKET(i)=0;
\r
441 //--------------------------------------------------------------------------------
\r
443 //--------------------------------------------------------------------------------
\r
445 static void ethernet_set_link(int speed, int duplex) {
\r
446 unsigned short phy_data;
\r
449 if((speed < 0) || (speed > 1)) {
\r
450 phy_data = PHY_AUTO_NEG;
\r
452 phy_data = (((unsigned short) speed << 13) |
\r
453 ((unsigned short) duplex << 8));
\r
456 phy_write(PHY_REG_BMCR, phy_data);
\r
458 for (tout = 100; tout; tout--) { __NOP(); } /* A short delay */
\r
462 phy_data = phy_read(PHY_REG_STS);
\r
464 if(phy_data & PHY_STS_DUPLEX) {
\r
465 LPC_EMAC->MAC2 |= MAC2_FULL_DUP;
\r
466 LPC_EMAC->Command |= CR_FULL_DUP;
\r
467 LPC_EMAC->IPGT = IPGT_FULL_DUP;
\r
469 LPC_EMAC->MAC2 &= ~MAC2_FULL_DUP;
\r
470 LPC_EMAC->Command &= ~CR_FULL_DUP;
\r
471 LPC_EMAC->IPGT = IPGT_HALF_DUP;
\r
474 if(phy_data & PHY_STS_SPEED) {
\r
475 LPC_EMAC->SUPP &= ~SUPP_SPEED;
\r
477 LPC_EMAC->SUPP |= SUPP_SPEED;
\r
482 phy_data = phy_read(PHY_REG_SCSR);
\r
484 if (phy_data & PHY_SCSR_DUPLEX) {
\r
485 LPC_EMAC->MAC2 |= MAC2_FULL_DUP;
\r
486 LPC_EMAC->Command |= CR_FULL_DUP;
\r
487 LPC_EMAC->IPGT = IPGT_FULL_DUP;
\r
489 LPC_EMAC->Command &= ~CR_FULL_DUP;
\r
490 LPC_EMAC->IPGT = IPGT_HALF_DUP;
\r
493 if(phy_data & PHY_SCSR_100MBIT) {
\r
494 LPC_EMAC->SUPP |= SUPP_SPEED;
\r
496 LPC_EMAC->SUPP &= ~SUPP_SPEED;
\r
503 static int phy_write(unsigned int PhyReg, unsigned short Data) {
\r
504 unsigned int timeOut;
\r
506 LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg;
\r
507 LPC_EMAC->MWTD = Data;
\r
509 for(timeOut = 0; timeOut < MII_WR_TOUT; timeOut++) { /* Wait until operation completed */
\r
510 if((LPC_EMAC->MIND & MIND_BUSY) == 0) {
\r
519 static int phy_read(unsigned int PhyReg) {
\r
520 unsigned int timeOut;
\r
522 LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg;
\r
523 LPC_EMAC->MCMD = MCMD_READ;
\r
525 for(timeOut = 0; timeOut < MII_RD_TOUT; timeOut++) { /* Wait until operation completed */
\r
526 if((LPC_EMAC->MIND & MIND_BUSY) == 0) {
\r
527 LPC_EMAC->MCMD = 0;
\r
528 return LPC_EMAC->MRDD; /* Return a 16-bit value. */
\r
536 //extern unsigned int SystemFrequency;
\r
537 static unsigned int clockselect(void)
\r
539 if(SystemCoreClock < 10000000) {
\r
541 } else if(SystemCoreClock < 15000000) {
\r
543 } else if(SystemCoreClock < 20000000) {
\r
545 } else if(SystemCoreClock < 25000000) {
\r
547 } else if(SystemCoreClock < 35000000) {
\r
549 } else if(SystemCoreClock < 50000000) {
\r
551 } else if(SystemCoreClock < 70000000) {
\r
553 } else if(SystemCoreClock < 80000000) {
\r
555 } else if(SystemCoreClock < 90000000) {
\r
557 } else if(SystemCoreClock < 100000000) {
\r
559 } else if(SystemCoreClock < 120000000) {
\r
561 } else if(SystemCoreClock < 130000000) {
\r
563 } else if(SystemCoreClock < 140000000) {
\r
565 } else if(SystemCoreClock < 150000000) {
\r
567 } else if(SystemCoreClock < 160000000) {
\r
574 static int ethernet_link(void)
\r
577 if (phy_id == DP83848C_ID) {
\r
578 return (phy_read(PHY_REG_STS) & PHY_STS_LINK);
\r
580 else { // LAN8720_ID
\r
581 return (phy_read(PHY_REG_BMSR) & PHY_BMSR_LINK);
\r
584 //--------------------------------------------------------------------------------
\r
586 //--------------------------------------------------------------------------------
\r
592 static void emacIsrHandler(unsigned long i_status)
\r
594 if( i_status & INT_RX_DONE )
\r
596 _event_handler(_event_param,NyLPC_TiEthernetDevice_EVENT_ON_RX);
\r
598 if( i_status & INT_TX_DONE )
\r
600 _event_handler(_event_param,NyLPC_TiEthernetDevice_EVENT_ON_TX);
\r