OSDN Git Service

dce41ff7d986a48d02ea70fb1a6a33def7901e67
[mimic/MiMicSDK.git] / lib / src / driver / ethernet / lpc17xx / EtherDev_LAN8720.c
1 /*\r
2     FreeRTOS V7.0.0 - Copyright (C) 2011 Real Time Engineers Ltd.\r
3         \r
4 \r
5     ***************************************************************************\r
6      *                                                                       *\r
7      *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
8      *    Complete, revised, and edited pdf reference manuals are also       *\r
9      *    available.                                                         *\r
10      *                                                                       *\r
11      *    Purchasing FreeRTOS documentation will not only help you, by       *\r
12      *    ensuring you get running as quickly as possible and with an        *\r
13      *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
14      *    the FreeRTOS project to continue with its mission of providing     *\r
15      *    professional grade, cross platform, de facto standard solutions    *\r
16      *    for microcontrollers - completely free of charge!                  *\r
17      *                                                                       *\r
18      *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
19      *                                                                       *\r
20      *    Thank you for using FreeRTOS, and thank you for your support!      *\r
21      *                                                                       *\r
22     ***************************************************************************\r
23 \r
24 \r
25     This file is part of the FreeRTOS distribution.\r
26 \r
27     FreeRTOS is free software; you can redistribute it and/or modify it under\r
28     the terms of the GNU General Public License (version 2) as published by the\r
29     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
30     >>>NOTE<<< The modification to the GPL is included to allow you to\r
31     distribute a combined work that includes FreeRTOS without being obliged to\r
32     provide the source code for proprietary components outside of the FreeRTOS\r
33     kernel.  FreeRTOS is distributed in the hope that it will be useful, but\r
34     WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
35     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
36     more details. You should have received a copy of the GNU General Public\r
37     License and the FreeRTOS license exception along with FreeRTOS; if not it\r
38     can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
39     by writing to Richard Barry, contact details for whom are available on the\r
40     FreeRTOS WEB site.\r
41 \r
42     1 tab == 4 spaces!\r
43 \r
44     http://www.FreeRTOS.org - Documentation, latest information, license and\r
45     contact details.\r
46 \r
47     http://www.SafeRTOS.com - A version that is certified for use in safety\r
48     critical systems.\r
49 \r
50     http://www.OpenRTOS.com - Commercial support, development, porting,\r
51     licensing and training services.\r
52 */\r
53 \r
54 /* Originally adapted from file written by Andreas Dannenberg.  Supplied with permission. */\r
55 /*\r
56  * Modified for MiMic by R.Iizuka. 2011.08.27\r
57  * http://nyatla.jp/mimic\r
58  */\r
59 \r
60 \r
61 #include "NyLPC_config.h"\r
62 #if NyLPC_MCU==NyLPC_MCU_LPC17xx\r
63 #include "EtherDev_LAN8720_protected.h"\r
64 #include "../NyLPC_cEthernetMM.h"\r
65 #include "LPC17xx.h"\r
66 #include "NyLPC_os.h"\r
67 \r
68 #define LAN8720_ID          0x0007C0F0  /* PHY Identifier                    */\r
69 \r
70 /* LAN8720 PHY Registers */\r
71 #define PHY_REG_BMCR        0x00        /* Basic Mode Control Register       */\r
72 #define PHY_REG_BMSR        0x01        /* Basic Mode Status Register        */\r
73 #define PHY_REG_IDR1        0x02        /* PHY Identifier 1                  */\r
74 #define PHY_REG_IDR2        0x03        /* PHY Identifier 2                  */\r
75 #define PHY_REG_ANAR        0x04        /* Auto-Negotiation Advertisement    */\r
76 #define PHY_REG_ANLPAR      0x05        /* Auto-Neg. Link Partner Abitily    */\r
77 #define PHY_REG_ANER        0x06        /* Auto-Neg. Expansion Register      */\r
78 \r
79 /* PHY Extended Registers */\r
80 #define PHY_REG_MODE_CTRL           17\r
81 #define PHY_REG_SPECIAL_MODE    18\r
82 #define PHY_REG_SYMBOL_ERR_CNT  26\r
83 #define PHY_REG_SPECIAL_CTRL    27\r
84 #define PHY_REG_INT_SOURCE          29\r
85 #define PHY_REG_INT_MASK            30\r
86 #define PHY_REG_PHY_CTRL            31\r
87 \r
88 #define PHY_AUTO_NEG            0x3000  /* Select Auto Negotiation           */\r
89 #define PHY_AUTO_NEG_COMPLETE   0x1000  /* Auto negotiation have finished.   */\r
90 \r
91 #define PHY_SPEED_FDUPLX                0x0010  /* Full Duplex   */\r
92 #define PHY_SPEED_100                   0x0008  /* 100Mbit   */\r
93 #define ETHDEV_PHY_DEF_ADR              0x0100  /* Default PHY device address        */\r
94 \r
95 #ifndef configEMAC_INTERRUPT_PRIORITY\r
96         #define configEMAC_INTERRUPT_PRIORITY           5\r
97 #endif\r
98 \r
99 /* Time to wait between each inspection of the link status. */\r
100 #define emacWAIT_FOR_LINK_TO_ESTABLISH_MS 500\r
101 \r
102 /* Short delay used in several places during the initialisation process. */\r
103 #define emacSHORT_DELAY_MS 10\r
104 \r
105 /* Hardware specific bit definitions. */\r
106 #define emacPINSEL2_VALUE                       ( 0x50150105 )\r
107 \r
108 \r
109 /*-----------------------------------------------------------*/\r
110 \r
111 /* Setup the IO and peripherals required for Ethernet communication.*/\r
112 static void prvSetupEMACHardware( void );\r
113 /* Control the auto negotiate process.*/\r
114 static void prvConfigurePHY( void );\r
115 /*\r
116  * Wait for a link to be established, then setup the PHY according to the link\r
117  * parameters.\r
118  */\r
119 static long prvSetupLinkStatus( void );\r
120 /*\r
121  * Send lValue to the lPhyReg within the PHY.\r
122  */\r
123 static long prvWritePHY( long lPhyReg, long lValue );\r
124 /*\r
125  * Read a value from ucPhyReg within the PHY.  *plStatus will be set to\r
126  * pdFALSE if there is an error.\r
127  */\r
128 static unsigned short prvReadPHY( unsigned int ucPhyReg, NyLPC_TBool* o_status);\r
129 \r
130 \r
131 static NyLPC_TBool start(const struct NyLPC_TEthAddr* i_eth_addr,NyLPC_TiEthernetDevice_onEvent i_handler,void* i_param);\r
132 static void stop(void);\r
133 static struct NyLPC_TTxBufferHeader* allocTxBuf(NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_size);\r
134 static void releaseTxBuf(struct NyLPC_TTxBufferHeader* i_buf);\r
135 \r
136 /** EMAC ISRハンドラ*/\r
137 static void emacIsrHandler(unsigned long i_status);\r
138 \r
139 /*-----------------------------------------------------------*/\r
140 \r
141 \r
142 const static struct TiEthernetDevice _interface=\r
143 {\r
144         "LAN8720",\r
145         start,\r
146         stop,\r
147         EthDev_LPC17xx_getRxEthFrame,\r
148         EthDev_LPC17xx_nextRxEthFrame,\r
149         allocTxBuf,\r
150         releaseTxBuf,\r
151         EthDev_LPC17xx_sendTxEthFrame,\r
152         EthDev_LPC17xx_processTx\r
153 };\r
154 static void* _event_param;\r
155 static NyLPC_TiEthernetDevice_onEvent _event_handler;\r
156 \r
157 /*\r
158  * EthernetDeviceのファクトリー関数。インターフェイスを生成できればtrue\r
159  *\r
160  */\r
161 NyLPC_TBool EthDev_LAN8720_getInterface(\r
162         const struct TiEthernetDevice** o_dev)\r
163 {\r
164         unsigned long ulID1, ulID2;\r
165         NyLPC_TBool ret=NyLPC_TBool_TRUE;\r
166         //Reset MCU Interface. and wait for reset.\r
167         prvSetupEMACHardware();\r
168         //Check peripheral name\r
169         ulID1 = prvReadPHY( PHY_REG_IDR1, &ret );\r
170         ulID2 = prvReadPHY( PHY_REG_IDR2, &ret );\r
171         if( ( (ulID1 << 16UL ) | ( ulID2 & 0xFFF0UL ) ) != LAN8720_ID)\r
172         {\r
173                 return NyLPC_TBool_FALSE;\r
174         }\r
175         *o_dev=&_interface;\r
176         LPC_EMAC->TxProduceIndex = 0;\r
177         LPC_EMAC->RxConsumeIndex = 0;\r
178         return NyLPC_TBool_TRUE;\r
179 }\r
180 \r
181 \r
182 \r
183 /***********************************************************************\r
184  * RXバッファ関連の定義\r
185  ***********************************************************************/\r
186 #define ETH_TX_BUF_BASE (void*)(ETH_BUF_BASE+ETH_FRAG_SIZE*NUM_RX_FRAG)\r
187 \r
188 static NyLPC_TBool start(const struct NyLPC_TEthAddr* i_eth_addr,NyLPC_TiEthernetDevice_onEvent i_handler,void* i_param)\r
189 {\r
190         //ISRw割り込み設定\r
191         NyLPC_cIsr_setEnetISR(emacIsrHandler);\r
192         _event_handler=i_handler;\r
193         _event_param=i_param;\r
194         /* Set the Ethernet MAC Address registers */\r
195         LPC_EMAC->SA0 = (((uint32_t)(i_eth_addr->addr[0])) << 8 ) | i_eth_addr->addr[1];\r
196         LPC_EMAC->SA1 = (((uint32_t)(i_eth_addr->addr[2])) << 8 ) | i_eth_addr->addr[3];\r
197         LPC_EMAC->SA2 = (((uint32_t)(i_eth_addr->addr[4])) << 8 ) | i_eth_addr->addr[5];\r
198 \r
199         //TXメモリマネージャの準備\r
200         NyLPC_cEthernetMM_initialize(ETH_TX_BUF_BASE);\r
201         /* Initialize Tx and Rx DMA Descriptors */\r
202         EthDev_LPC17xx_prevRxDescriptor();\r
203         EthDev_LPC17xx_prevTxDescriptor();\r
204 \r
205         /* Setup the PHY. */\r
206         prvConfigurePHY();\r
207 \r
208         //wait for Link up...\r
209         while(!prvSetupLinkStatus())\r
210         {\r
211                 NyLPC_cThread_sleep(100);\r
212         }\r
213 \r
214         /* Receive Broadcast and Perfect Match Packets */\r
215         LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN | RFC_MCAST_EN;\r
216 \r
217         //Ethernetの割込み開始設定\r
218         NyLPC_cIsr_enterCritical();\r
219         {\r
220                 /* Reset all interrupts */\r
221                 LPC_EMAC->IntClear = 0xffff;\r
222                 LPC_EMAC->IntEnable = ( INT_RX_DONE | INT_TX_DONE );\r
223                 /* Enable receive and transmit mode of MAC Ethernet core */\r
224                 LPC_EMAC->Command |= ( CR_RX_EN | CR_TX_EN );\r
225                 LPC_EMAC->MAC1 |= MAC1_REC_EN;\r
226 \r
227                 /* Set the interrupt priority to the max permissible to cause some\r
228                 interrupt nesting. */\r
229                 NVIC_SetPriority( ENET_IRQn, configEMAC_INTERRUPT_PRIORITY );\r
230 \r
231                 /* Enable the interrupt. */\r
232                 NVIC_EnableIRQ( ENET_IRQn );\r
233         }\r
234         NyLPC_cIsr_exitCritical();\r
235 \r
236         return NyLPC_TBool_TRUE;\r
237 }\r
238 static void stop(void)\r
239 {\r
240         NyLPC_cIsr_enterCritical();\r
241         {\r
242                 LPC_EMAC->IntEnable = (~(INT_RX_DONE|INT_TX_DONE))&LPC_EMAC->IntEnable;\r
243                 NVIC_DisableIRQ( ENET_IRQn );\r
244         }\r
245         NyLPC_cIsr_exitCritical();\r
246         LPC_EMAC->Command &= ~( CR_RX_EN | CR_TX_EN );\r
247         LPC_EMAC->MAC1 &= ~MAC1_REC_EN;\r
248         //ISR割り込み解除\r
249         NyLPC_cIsr_setEnetISR(NULL);\r
250         //TXメモリマネージャの終了\r
251         NyLPC_cEthernetMM_finalize();\r
252 }\r
253 \r
254 \r
255 static struct NyLPC_TTxBufferHeader* allocTxBuf(NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_size)\r
256 {\r
257         return NyLPC_cEthernetMM_alloc(i_hint,o_size);\r
258 }\r
259 static void releaseTxBuf(struct NyLPC_TTxBufferHeader* i_buf)\r
260 {\r
261         NyLPC_cEthernetMM_release(i_buf);\r
262 }\r
263 \r
264 \r
265 \r
266 /********************************************************************************\r
267  * Private functions\r
268  *******************************************************************************/\r
269 \r
270 /*-----------------------------------------------------------*/\r
271 \r
272 /*-----------------------------------------------------------*/\r
273 \r
274 static void prvSetupEMACHardware( void )\r
275 {\r
276         unsigned short us;\r
277         long x;\r
278         NyLPC_TBool lDummy;\r
279 \r
280         /* Power Up the EMAC controller. */\r
281         LPC_SC->PCONP |= 0x40000000;\r
282         NyLPC_cThread_sleep( emacSHORT_DELAY_MS);\r
283 \r
284         /* Enable P1 Ethernet Pins. */\r
285         LPC_PINCON->PINSEL2 = emacPINSEL2_VALUE;\r
286         LPC_PINCON->PINSEL3 = ( LPC_PINCON->PINSEL3 & ~0x0000000F ) | 0x00000005;\r
287 \r
288         /* Reset all EMAC internal modules. */\r
289         LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;\r
290         LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES| CR_PASS_RUNT_FRM;\r
291         /* A short delay after reset. */\r
292         NyLPC_cThread_sleep( emacSHORT_DELAY_MS);\r
293 \r
294         /* Initialize MAC control registers. */\r
295         LPC_EMAC->MAC1 = MAC1_PASS_ALL;\r
296         LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;\r
297         LPC_EMAC->MAXF = ETH_MAX_FLEN;\r
298         LPC_EMAC->CLRT = CLRT_DEF;\r
299         LPC_EMAC->IPGR = IPGR_DEF;\r
300 \r
301         /*PCLK=18MHz, clock select=6, MDC=18/6=3MHz */ // I don't think so!\r
302         /* Enable Reduced MII interface. */\r
303         LPC_EMAC->MCFG = MCFG_CLK_DIV20 | MCFG_RES_MII;\r
304         NyLPC_cThread_sleep( emacSHORT_DELAY_MS);\r
305         LPC_EMAC->MCFG = MCFG_CLK_DIV20;\r
306 \r
307         /* Enable Reduced MII interface. */\r
308         LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT;\r
309 \r
310         /* Reset Reduced MII Logic. */\r
311         LPC_EMAC->SUPP = SUPP_RES_RMII | SUPP_SPEED;\r
312         NyLPC_cThread_sleep( emacSHORT_DELAY_MS);\r
313         LPC_EMAC->SUPP = SUPP_SPEED;\r
314 \r
315         /* Put the PHY in reset mode */\r
316         prvWritePHY( PHY_REG_BMCR, MCFG_RES_MII );\r
317         NyLPC_cThread_sleep( emacSHORT_DELAY_MS * 5);\r
318 \r
319         /* Wait for hardware reset to end. */\r
320         for( x = 0; x < 100; x++ )\r
321         {\r
322                 NyLPC_cThread_sleep( emacSHORT_DELAY_MS * 5 );\r
323                 us = prvReadPHY( PHY_REG_BMCR, &lDummy );\r
324                 if( !( us & MCFG_RES_MII ) )\r
325                 {\r
326                         /* Reset complete */\r
327                         break;\r
328                 }\r
329         }\r
330 }\r
331 /*-----------------------------------------------------------*/\r
332 \r
333 \r
334 /*-----------------------------------------------------------*/\r
335 \r
336 static NyLPC_TBool prvWritePHY( long lPhyReg, long lValue )\r
337 {\r
338         const long lMaxTime = 10;\r
339         long x;\r
340 \r
341         LPC_EMAC->MCMD = 0;\r
342         LPC_EMAC->MADR = ETHDEV_PHY_DEF_ADR | lPhyReg;\r
343         LPC_EMAC->MWTD = lValue;\r
344 \r
345         for( x = 0; x < lMaxTime; x++ )\r
346         {\r
347                 if( ( LPC_EMAC->MIND & MIND_BUSY ) == 0 )\r
348                 {\r
349                         /* Operation has finished. */\r
350                         break;\r
351                 }\r
352 \r
353                 NyLPC_cThread_sleep( emacSHORT_DELAY_MS);\r
354         }\r
355 \r
356         if( x < lMaxTime )\r
357         {\r
358                 return NyLPC_TBool_TRUE;\r
359         }\r
360         else\r
361         {\r
362                 return NyLPC_TBool_FALSE;\r
363         }\r
364 }\r
365 /*-----------------------------------------------------------*/\r
366 \r
367 static unsigned short prvReadPHY( unsigned int ucPhyReg, NyLPC_TBool *o_status)\r
368 {\r
369         long x;\r
370         const long lMaxTime = 10;\r
371 \r
372         LPC_EMAC->MCMD = 1;\r
373         LPC_EMAC->MADR = ETHDEV_PHY_DEF_ADR | ucPhyReg;\r
374         LPC_EMAC->MCMD = MCMD_READ;\r
375 \r
376         for( x = 0; x < lMaxTime; x++ )\r
377         {\r
378                 /* Operation has finished. */\r
379                 if( ( LPC_EMAC->MIND & MIND_BUSY ) == 0 )\r
380                 {\r
381                         break;\r
382                 }\r
383                 NyLPC_cThread_sleep( emacSHORT_DELAY_MS);\r
384         }\r
385 \r
386         LPC_EMAC->MCMD = 0;\r
387 \r
388         if( x >= lMaxTime )\r
389         {\r
390                 *o_status =NyLPC_TBool_FALSE;\r
391         }\r
392 \r
393         return( LPC_EMAC->MRDD );\r
394 }\r
395 /**\r
396  * Private function depend on configulation.\r
397  * デバイス依存部分
398  */\r
399 \r
400 \r
401 /* for LPC1769\r
402  */\r
403 static void prvConfigurePHY( void )\r
404 {\r
405         unsigned short us;\r
406         long x;\r
407         NyLPC_TBool lDummy;\r
408         /* Auto negotiate the configuration. */\r
409         if( prvWritePHY( PHY_REG_BMCR, PHY_AUTO_NEG ) )\r
410         {\r
411                 NyLPC_cThread_sleep( emacSHORT_DELAY_MS * 5 );\r
412 \r
413                 for( x = 0; x < 10; x++ )\r
414                 {\r
415                         us = prvReadPHY( PHY_REG_PHY_CTRL, &lDummy );\r
416                         if( us & PHY_AUTO_NEG_COMPLETE )\r
417                         {\r
418                                 break;\r
419                         }\r
420                         NyLPC_cThread_sleep( emacWAIT_FOR_LINK_TO_ESTABLISH_MS);\r
421                 }\r
422         }\r
423 }\r
424 \r
425 static long prvSetupLinkStatus( void )\r
426 {\r
427         long x;\r
428         unsigned short usLinkStatus;\r
429         NyLPC_TBool lReturn=NyLPC_TBool_TRUE;\r
430 \r
431         /* Wait with timeout for the link to be established. */\r
432         for( x = 0; x < 10; x++ )\r
433         {\r
434                 usLinkStatus = prvReadPHY (PHY_REG_PHY_CTRL, &lReturn );\r
435                 if( usLinkStatus & PHY_AUTO_NEG_COMPLETE )\r
436                 {\r
437                         /* Link is established. */\r
438                         lReturn = NyLPC_TBool_TRUE;\r
439                         break;\r
440                 }\r
441                 NyLPC_cThread_sleep( emacWAIT_FOR_LINK_TO_ESTABLISH_MS);\r
442         }\r
443 \r
444         if( lReturn == NyLPC_TBool_TRUE )\r
445         {\r
446                 /* Configure Full/Half Duplex mode. */\r
447                 if (usLinkStatus & PHY_SPEED_FDUPLX )\r
448                 {\r
449                         /* Full duplex is enabled. */\r
450                         LPC_EMAC->MAC2 |= MAC2_FULL_DUP;\r
451                         LPC_EMAC->Command |= CR_FULL_DUP;\r
452                         LPC_EMAC->IPGT = IPGT_FULL_DUP;\r
453                 }\r
454                 else\r
455                 {\r
456                         /* Half duplex mode. */\r
457                         LPC_EMAC->IPGT = IPGT_HALF_DUP;\r
458                 }\r
459 \r
460                 /* Configure 100MBit/10MBit mode. */\r
461                 if( !(usLinkStatus & PHY_SPEED_100) )\r
462                 {\r
463                         /* 10MBit mode. */\r
464                         LPC_EMAC->SUPP = 0;\r
465                 }\r
466                 else\r
467                 {\r
468                         /* 100MBit mode. */\r
469                         LPC_EMAC->SUPP = SUPP_SPEED;\r
470                 }\r
471         }\r
472         return lReturn;\r
473 }\r
474 //--------------------------------------------------------------------------------\r
475 // ISR\r
476 //--------------------------------------------------------------------------------\r
477 \r
478 /**\r
479  * EMACからのハンドラ\r
480  */\r
481 static void emacIsrHandler(unsigned long i_status)\r
482 {\r
483         if( i_status & INT_RX_DONE )\r
484         {\r
485                 _event_handler(_event_param,NyLPC_TiEthernetDevice_EVENT_ON_RX);\r
486         }\r
487         if( i_status & INT_TX_DONE )\r
488         {\r
489                 _event_handler(_event_param,NyLPC_TiEthernetDevice_EVENT_ON_TX);\r
490         }\r
491 }\r
492 \r
493 #endif\r
494 \r
495 \r