OSDN Git Service

driverのuipをethernetに変更
[mimic/MiMicSDK.git] / lib / src / driver / uip / EtherDev_DP83848C.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 /* Kernel includes. */\r
62 #include "EtherDev_DP83848C_protected.h"\r
63 #include "LPC17xx.h"\r
64 #include "NyLPC_os.h"\r
65 \r
66 \r
67 #define DP83848C_ID         0x20005C90  /* PHY Identifier                    */\r
68 \r
69 /* DP83848C PHY Registers */\r
70 #define PHY_REG_BMCR        0x00        /* Basic Mode Control Register       */\r
71 #define PHY_REG_BMSR        0x01        /* Basic Mode Status Register        */\r
72 #define PHY_REG_IDR1        0x02        /* PHY Identifier 1                  */\r
73 #define PHY_REG_IDR2        0x03        /* PHY Identifier 2                  */\r
74 #define PHY_REG_ANAR        0x04        /* Auto-Negotiation Advertisement    */\r
75 #define PHY_REG_ANLPAR      0x05        /* Auto-Neg. Link Partner Abitily    */\r
76 #define PHY_REG_ANER        0x06        /* Auto-Neg. Expansion Register      */\r
77 #define PHY_REG_ANNPTR      0x07        /* Auto-Neg. Next Page TX            */\r
78 \r
79 /* PHY Extended Registers */\r
80 #define PHY_REG_STS         0x10        /* Status Register                   */\r
81 #define PHY_REG_MICR        0x11        /* MII Interrupt Control Register    */\r
82 #define PHY_REG_MISR        0x12        /* MII Interrupt Status Register     */\r
83 #define PHY_REG_FCSCR       0x14        /* False Carrier Sense Counter       */\r
84 #define PHY_REG_RECR        0x15        /* Receive Error Counter             */\r
85 #define PHY_REG_PCSR        0x16        /* PCS Sublayer Config. and Status   */\r
86 #define PHY_REG_RBR         0x17        /* RMII and Bypass Register          */\r
87 #define PHY_REG_LEDCR       0x18        /* LED Direct Control Register       */\r
88 #define PHY_REG_PHYCR       0x19        /* PHY Control Register              */\r
89 #define PHY_REG_10BTSCR     0x1A        /* 10Base-T Status/Control Register  */\r
90 #define PHY_REG_CDCTRL1     0x1B        /* CD Test Control and BIST Extens.  */\r
91 #define PHY_REG_EDCR        0x1D        /* Energy Detect Control Register    */\r
92 \r
93 #define PHY_FULLD_100M      0x2100      /* Full Duplex 100Mbit               */\r
94 #define PHY_HALFD_100M      0x2000      /* Half Duplex 100Mbit               */\r
95 #define PHY_FULLD_10M       0x0100      /* Full Duplex 10Mbit                */\r
96 #define PHY_HALFD_10M       0x0000      /* Half Duplex 10MBit                */\r
97 #define PHY_AUTO_NEG        0x3000      /* Select Auto Negotiation           */\r
98 #define PHY_AUTO_NEG_COMPLETE 0x0020    /* Auto negotiation have finished.   */\r
99 #define ETHDEV_PHY_DEF_ADR    0x0100      /* Default PHY device address        */\r
100 \r
101 \r
102 #ifndef configEMAC_INTERRUPT_PRIORITY\r
103     #define configEMAC_INTERRUPT_PRIORITY       5\r
104 #endif\r
105 \r
106 /* Time to wait between each inspection of the link status. */\r
107 #define emacWAIT_FOR_LINK_TO_ESTABLISH_MS 500\r
108 \r
109 /* Short delay used in several places during the initialisation process. */\r
110 #define emacSHORT_DELAY_MS                 10\r
111 \r
112 /* Hardware specific bit definitions. */\r
113 #define emacPINSEL2_VALUE           ( 0x50150105 )\r
114 \r
115 /* If no buffers are available, then wait this long before looking again.... */\r
116 #define emacBUFFER_WAIT_DELAY_MS 3\r
117 #define emacBUFFER_WAIT_EMPTY_MS 10\r
118 \r
119 /* ...and don't look more than this many times. */\r
120 #define emacBUFFER_WAIT_ATTEMPTS    ( 30 )\r
121 \r
122 /* Index to the Tx descriptor that is always used first for every Tx.  The second\r
123 descriptor is then used to re-send in order to speed up the uIP Tx process. */\r
124 #define emacTX_DESC_INDEX           ( 0 )\r
125 \r
126 /*-----------------------------------------------------------*/\r
127 \r
128 /* Setup the IO and peripherals required for Ethernet communication.*/\r
129 static void prvSetupEMACHardware( void );\r
130 /* Control the auto negotiate process.*/\r
131 static void prvConfigurePHY( void );\r
132 /*\r
133  * Wait for a link to be established, then setup the PHY according to the link\r
134  * parameters.\r
135  */\r
136 static NyLPC_TBool prvSetupLinkStatus( void );\r
137 /*\r
138  * Send lValue to the lPhyReg within the PHY.\r
139  */\r
140 static NyLPC_TBool prvWritePHY( long lPhyReg, long lValue );\r
141 /*\r
142  * Read a value from ucPhyReg within the PHY.  *plStatus will be set to\r
143  * pdFALSE if there is an error.\r
144  */\r
145 static unsigned short prvReadPHY( unsigned int ucPhyReg, long *plStatus );\r
146 \r
147 \r
148 \r
149 static NyLPC_TBool start(const struct NyLPC_TEthAddr* i_eth_addr);\r
150 static void stop(void);\r
151 \r
152 /*-----------------------------------------------------------*/\r
153 \r
154 \r
155 \r
156 const static struct TiEthernetDevice _interface=\r
157 {\r
158     "DP83848C",\r
159     start,\r
160     stop,\r
161     EthDev_LPC17xx_getRxEthFrame,\r
162     EthDev_LPC17xx_nextRxEthFrame,\r
163     EthDev_LPC17xx_allocTxBuf,\r
164     EthDev_LPC17xx_releaseTxBuf,\r
165     EthDev_LPC17xx_sendTxEthFrame,\r
166     EthDev_LPC17xx_processTx};\r
167 /*\r
168  * EthernetDeviceのファクトリー関数\r
169  */\r
170 \r
171 NyLPC_TBool EthDev_DP83848C_getInterface(\r
172     const struct TiEthernetDevice** o_dev)\r
173 {\r
174     unsigned long ulID1, ulID2;\r
175     NyLPC_TBool lReturn = NyLPC_TBool_TRUE;\r
176     //Reset MCU Interface. and wait for reset.\r
177     prvSetupEMACHardware();\r
178     //Check peripheral name\r
179     ulID1 = prvReadPHY( PHY_REG_IDR1, &lReturn );\r
180     ulID2 = prvReadPHY( PHY_REG_IDR2, &lReturn );\r
181     if( ( (ulID1 << 16UL ) | ( ulID2 & 0xFFF0UL ) ) != DP83848C_ID)\r
182     {\r
183         return NyLPC_TBool_FALSE;\r
184     }\r
185     *o_dev=&_interface;\r
186         LPC_EMAC->TxProduceIndex = 0;\r
187         LPC_EMAC->RxConsumeIndex = 0;\r
188     return NyLPC_TBool_TRUE;\r
189 }\r
190 \r
191 \r
192 static NyLPC_TBool start(const struct NyLPC_TEthAddr* i_eth_addr)\r
193 {\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     /* Initialize Tx and Rx DMA Descriptors */\r
200     EthDev_LPC17xx_prevRxDescriptor();\r
201     EthDev_LPC17xx_prevTxDescriptor();\r
202 \r
203 \r
204     /* Setup the PHY. */\r
205     prvConfigurePHY();\r
206 \r
207     //wait for Link up...\r
208     while(!prvSetupLinkStatus())\r
209     {\r
210         NyLPC_cThread_sleep(100);\r
211     }\r
212 \r
213     /* Receive Broadcast and Perfect Match Packets */\r
214     LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN | RFC_MCAST_EN;\r
215 \r
216     //Ethernetの割込み開始設定\r
217     NyLPC_cIsr_enterCritical();\r
218     {\r
219         /* Reset all interrupts */\r
220         LPC_EMAC->IntClear = 0xffff;\r
221         LPC_EMAC->IntEnable = ( INT_RX_DONE | INT_TX_DONE );\r
222 \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 }\r
239 static void stop(void)\r
240 {\r
241     NyLPC_cIsr_enterCritical();\r
242     {\r
243         LPC_EMAC->IntEnable = (~(INT_RX_DONE|INT_TX_DONE))&LPC_EMAC->IntEnable;\r
244         NVIC_DisableIRQ( ENET_IRQn );\r
245     }\r
246     NyLPC_cIsr_exitCritical();\r
247         LPC_EMAC->Command &= ~( CR_RX_EN | CR_TX_EN );\r
248         LPC_EMAC->MAC1 &= ~MAC1_REC_EN;\r
249     return;\r
250 }\r
251 \r
252 \r
253 \r
254 \r
255 /********************************************************************************\r
256  * Private functions\r
257  *******************************************************************************/\r
258 \r
259 /*-----------------------------------------------------------*/\r
260 \r
261 /*-----------------------------------------------------------*/\r
262 \r
263 static void prvSetupEMACHardware( void )\r
264 {\r
265     unsigned short us;\r
266     long x;\r
267     NyLPC_TBool lDummy;\r
268 \r
269     /* Power Up the EMAC controller. */\r
270     LPC_SC->PCONP |= 0x40000000;\r
271     NyLPC_cThread_sleep( emacSHORT_DELAY_MS);\r
272 \r
273     /* Enable P1 Ethernet Pins. */\r
274     LPC_PINCON->PINSEL2 = emacPINSEL2_VALUE;\r
275     LPC_PINCON->PINSEL3 = ( LPC_PINCON->PINSEL3 & ~0x0000000F ) | 0x00000005;\r
276 \r
277     /* Reset all EMAC internal modules. */\r
278     LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;\r
279     LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES| CR_PASS_RUNT_FRM;\r
280     /* A short delay after reset. */\r
281     NyLPC_cThread_sleep( emacSHORT_DELAY_MS );\r
282 \r
283     /* Initialize MAC control registers. */\r
284     LPC_EMAC->MAC1 = MAC1_PASS_ALL;\r
285     LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;\r
286     LPC_EMAC->MAXF = ETH_MAX_FLEN;\r
287     LPC_EMAC->CLRT = CLRT_DEF;\r
288     LPC_EMAC->IPGR = IPGR_DEF;\r
289 \r
290     /*PCLK=18MHz, clock select=6, MDC=18/6=3MHz */ // I don't think so!\r
291     /* Enable Reduced MII interface. */\r
292     LPC_EMAC->MCFG = MCFG_CLK_DIV20 | MCFG_RES_MII;\r
293     NyLPC_cThread_sleep( emacSHORT_DELAY_MS );\r
294     LPC_EMAC->MCFG = MCFG_CLK_DIV20;\r
295 \r
296     /* Enable Reduced MII interface. */\r
297     LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT;\r
298 \r
299     /* Reset Reduced MII Logic. */\r
300     LPC_EMAC->SUPP = SUPP_RES_RMII | SUPP_SPEED;\r
301     NyLPC_cThread_sleep( emacSHORT_DELAY_MS );\r
302     LPC_EMAC->SUPP = SUPP_SPEED;\r
303 \r
304     /* Put the PHY in reset mode */\r
305     prvWritePHY( PHY_REG_BMCR, MCFG_RES_MII );\r
306     NyLPC_cThread_sleep( emacSHORT_DELAY_MS * 5);\r
307 \r
308     /* Wait for hardware reset to end. */\r
309     for( x = 0; x < 100; x++ )\r
310     {\r
311         NyLPC_cThread_sleep( emacSHORT_DELAY_MS * 5 );\r
312         us = prvReadPHY( PHY_REG_BMCR, &lDummy );\r
313         if( !( us & MCFG_RES_MII ) )\r
314         {\r
315             /* Reset complete */\r
316             break;\r
317         }\r
318     }\r
319 }\r
320 /*-----------------------------------------------------------*/\r
321 \r
322 \r
323 /*-----------------------------------------------------------*/\r
324 \r
325 static NyLPC_TBool prvWritePHY( long lPhyReg, long lValue )\r
326 {\r
327     const long lMaxTime = 10;\r
328     long x;\r
329 \r
330     LPC_EMAC->MCMD = 0;\r
331     LPC_EMAC->MADR = ETHDEV_PHY_DEF_ADR | lPhyReg;\r
332     LPC_EMAC->MWTD = lValue;\r
333 \r
334     for( x = 0; x < lMaxTime; x++ )\r
335     {\r
336         if( ( LPC_EMAC->MIND & MIND_BUSY ) == 0 )\r
337         {\r
338             /* Operation has finished. */\r
339             break;\r
340         }\r
341 \r
342         NyLPC_cThread_sleep( emacSHORT_DELAY_MS );\r
343     }\r
344 \r
345     if( x < lMaxTime )\r
346     {\r
347         return NyLPC_TBool_TRUE;\r
348     }\r
349     else\r
350     {\r
351         return NyLPC_TBool_FALSE;\r
352     }\r
353 }\r
354 /*-----------------------------------------------------------*/\r
355 \r
356 static unsigned short prvReadPHY( unsigned int ucPhyReg, NyLPC_TBool* plStatus )\r
357 {\r
358     long x;\r
359     const long lMaxTime = 10;\r
360 \r
361     LPC_EMAC->MCMD = 1;\r
362     LPC_EMAC->MADR = ETHDEV_PHY_DEF_ADR | ucPhyReg;\r
363     LPC_EMAC->MCMD = MCMD_READ;\r
364 \r
365     for( x = 0; x < lMaxTime; x++ )\r
366     {\r
367         /* Operation has finished. */\r
368         if( ( LPC_EMAC->MIND & MIND_BUSY ) == 0 )\r
369         {\r
370             break;\r
371         }\r
372         NyLPC_cThread_sleep( emacSHORT_DELAY_MS );\r
373     }\r
374 \r
375     LPC_EMAC->MCMD = 0;\r
376 \r
377     if( x >= lMaxTime )\r
378     {\r
379         *plStatus = NyLPC_TBool_FALSE;\r
380     }\r
381 \r
382     return( LPC_EMAC->MRDD );\r
383 }\r
384 /*------------------------------------------------\r
385  * Private function depend on device.\r
386  * デバイス依存部分\r
387  ------------------------------------------------*/\r
388 \r
389 \r
390 /*for mbed\r
391  */\r
392 #define emacLINK_ESTABLISHED        ( 0x0001 )\r
393 #define emacFULL_DUPLEX_ENABLED     ( 0x0004 )\r
394 #define emac10BASE_T_MODE           ( 0x0002 )\r
395 \r
396 \r
397 static void prvConfigurePHY( void )\r
398 {\r
399     unsigned short us;\r
400     long x;\r
401     NyLPC_TBool lDummy;\r
402 \r
403     /* Auto negotiate the configuration. */\r
404     if( prvWritePHY( PHY_REG_BMCR, PHY_AUTO_NEG ) )\r
405     {\r
406         NyLPC_cThread_sleep( emacSHORT_DELAY_MS * 5 );\r
407 \r
408         for( x = 0; x < 10; x++ )\r
409         {\r
410             us = prvReadPHY( PHY_REG_BMSR, &lDummy );\r
411 \r
412             if( us & PHY_AUTO_NEG_COMPLETE )\r
413             {\r
414                 break;\r
415             }\r
416 \r
417             NyLPC_cThread_sleep( emacWAIT_FOR_LINK_TO_ESTABLISH_MS);\r
418         }\r
419     }\r
420 }\r
421 \r
422 static NyLPC_TBool prvSetupLinkStatus( void )\r
423 {\r
424     NyLPC_TBool lReturn = NyLPC_TBool_FALSE;\r
425     long x;\r
426     unsigned short usLinkStatus;\r
427 \r
428     /* Wait with timeout for the link to be established. */\r
429     for( x = 0; x < 10; x++ )\r
430     {\r
431         usLinkStatus = prvReadPHY( PHY_REG_STS, &lReturn );\r
432         if( usLinkStatus & emacLINK_ESTABLISHED )\r
433         {\r
434             /* Link is established. */\r
435             lReturn = NyLPC_TBool_TRUE;\r
436             break;\r
437         }\r
438 \r
439         NyLPC_cThread_sleep( emacWAIT_FOR_LINK_TO_ESTABLISH_MS);\r
440     }\r
441 \r
442     if( lReturn == NyLPC_TBool_TRUE )\r
443     {\r
444         /* Configure Full/Half Duplex mode. */\r
445         if( usLinkStatus & emacFULL_DUPLEX_ENABLED )\r
446         {\r
447             /* Full duplex is enabled. */\r
448             LPC_EMAC->MAC2 |= MAC2_FULL_DUP;\r
449             LPC_EMAC->Command |= CR_FULL_DUP;\r
450             LPC_EMAC->IPGT = IPGT_FULL_DUP;\r
451         }\r
452         else\r
453         {\r
454             /* Half duplex mode. */\r
455             LPC_EMAC->IPGT = IPGT_HALF_DUP;\r
456         }\r
457 \r
458         /* Configure 100MBit/10MBit mode. */\r
459         if( usLinkStatus & emac10BASE_T_MODE )\r
460         {\r
461             /* 10MBit mode. */\r
462             LPC_EMAC->SUPP = 0;\r
463         }\r
464         else\r
465         {\r
466             /* 100MBit mode. */\r
467             LPC_EMAC->SUPP = SUPP_SPEED;\r
468         }\r
469     }\r
470 \r
471     return lReturn;\r
472 }\r
473 \r
474 \r