1
+ /*
2
+ * Copyright (c) 2013 Nuvoton Technology Corp.
3
+ *
4
+ * See file CREDITS for list of people who contributed to this
5
+ * project.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of
10
+ * the License, or (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20
+ * MA 02111-1307 USA
21
+ *
22
+ * Description: NUC472 MAC driver source file
23
+ */
24
+ #include "nuc472_eth.h"
25
+ #include "lwip/opt.h"
26
+ #include "lwip/def.h"
27
+
28
+
29
+ #define ETH_TRIGGER_RX () do{EMAC->RXST = 0;}while(0)
30
+ #define ETH_TRIGGER_TX () do{EMAC->TXST = 0;}while(0)
31
+ #define ETH_ENABLE_TX () do{EMAC->CTL |= EMAC_CTL_TXON;}while(0)
32
+ #define ETH_ENABLE_RX () do{EMAC->CTL |= EMAC_CTL_RXON;}while(0)
33
+ #define ETH_DISABLE_TX () do{EMAC->CTL &= ~EMAC_CTL_TXON;}while(0)
34
+ #define ETH_DISABLE_RX () do{EMAC->CTL &= ~EMAC_CTL_RXON;}while(0)
35
+
36
+ #ifdef __ICCARM__
37
+ #pragma data_alignment=4
38
+ struct eth_descriptor rx_desc [RX_DESCRIPTOR_NUM ];
39
+ struct eth_descriptor tx_desc [TX_DESCRIPTOR_NUM ];
40
+ #else
41
+ struct eth_descriptor rx_desc [RX_DESCRIPTOR_NUM ] __attribute__ ((aligned (4 )));
42
+ struct eth_descriptor tx_desc [TX_DESCRIPTOR_NUM ] __attribute__ ((aligned (4 )));
43
+ #endif
44
+ struct eth_descriptor volatile * cur_tx_desc_ptr , * cur_rx_desc_ptr , * fin_tx_desc_ptr ;
45
+
46
+ u8_t rx_buf [RX_DESCRIPTOR_NUM ][PACKET_BUFFER_SIZE ];
47
+ u8_t tx_buf [TX_DESCRIPTOR_NUM ][PACKET_BUFFER_SIZE ];
48
+
49
+ extern void ethernetif_input (u16_t len , u8_t * buf , u32_t s , u32_t ns );
50
+ extern void ethernetif_loopback_input (struct pbuf * p );
51
+
52
+ // PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
53
+ // Assume we want to set each tick to 100ns.
54
+ // Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7
55
+ // Addend register = 2^32 * tick_freq / (84MHz), where tick_freq = (2^31 / 215) MHz
56
+ // From above equation, addend register = 2^63 / (84M * 215) ~= 510707200 = 0x1E70C600
57
+
58
+
59
+
60
+ static void mdio_write (u8_t addr , u8_t reg , u16_t val )
61
+ {
62
+
63
+ EMAC -> MIIMDAT = val ;
64
+ EMAC -> MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos ) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk ;
65
+
66
+ while (EMAC -> MIIMCTL & EMAC_MIIMCTL_BUSY_Msk );
67
+
68
+ }
69
+
70
+
71
+ static u16_t mdio_read (u8_t addr , u8_t reg )
72
+ {
73
+ EMAC -> MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos ) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk ;
74
+ while (EMAC -> MIIMCTL & EMAC_MIIMCTL_BUSY_Msk );
75
+
76
+ return (EMAC -> MIIMDAT );
77
+ }
78
+
79
+ static int reset_phy (void )
80
+ {
81
+
82
+ u16_t reg ;
83
+ u32_t delay ;
84
+
85
+
86
+ mdio_write (CONFIG_PHY_ADDR , MII_BMCR , BMCR_RESET );
87
+
88
+ delay = 2000 ;
89
+ while (delay -- > 0 ) {
90
+ if ((mdio_read (CONFIG_PHY_ADDR , MII_BMCR ) & BMCR_RESET ) == 0 )
91
+ break ;
92
+
93
+ }
94
+
95
+ if (delay == 0 ) {
96
+ printf ("Reset phy failed\n" );
97
+ return (-1 );
98
+ }
99
+
100
+ mdio_write (CONFIG_PHY_ADDR , MII_ADVERTISE , ADVERTISE_CSMA |
101
+ ADVERTISE_10HALF |
102
+ ADVERTISE_10FULL |
103
+ ADVERTISE_100HALF |
104
+ ADVERTISE_100FULL );
105
+
106
+ reg = mdio_read (CONFIG_PHY_ADDR , MII_BMCR );
107
+ mdio_write (CONFIG_PHY_ADDR , MII_BMCR , reg | BMCR_ANRESTART );
108
+
109
+ delay = 200000 ;
110
+ while (delay -- > 0 ) {
111
+ if ((mdio_read (CONFIG_PHY_ADDR , MII_BMSR ) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS ))
112
+ == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS ))
113
+ break ;
114
+ }
115
+
116
+ if (delay == 0 ) {
117
+ printf ("AN failed. Set to 100 FULL\n" );
118
+ EMAC -> CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk );
119
+ return (-1 );
120
+ } else {
121
+ reg = mdio_read (CONFIG_PHY_ADDR , MII_LPA );
122
+
123
+ if (reg & ADVERTISE_100FULL ) {
124
+ printf ("100 full\n" );
125
+ EMAC -> CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk );
126
+ } else if (reg & ADVERTISE_100HALF ) {
127
+ printf ("100 half\n" );
128
+ EMAC -> CTL = (EMAC -> CTL & ~EMAC_CTL_FUDUP_Msk ) | EMAC_CTL_OPMODE_Msk ;
129
+ } else if (reg & ADVERTISE_10FULL ) {
130
+ printf ("10 full\n" );
131
+ EMAC -> CTL = (EMAC -> CTL & ~EMAC_CTL_OPMODE_Msk ) | EMAC_CTL_FUDUP_Msk ;
132
+ } else {
133
+ printf ("10 half\n" );
134
+ EMAC -> CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk );
135
+ }
136
+ }
137
+
138
+ return (0 );
139
+ }
140
+
141
+
142
+ static void init_tx_desc (void )
143
+ {
144
+ u32_t i ;
145
+
146
+
147
+ cur_tx_desc_ptr = fin_tx_desc_ptr = & tx_desc [0 ];
148
+
149
+ for (i = 0 ; i < TX_DESCRIPTOR_NUM ; i ++ ) {
150
+ tx_desc [i ].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN ;
151
+ tx_desc [i ].buf = & tx_buf [i ][0 ];
152
+ tx_desc [i ].status2 = 0 ;
153
+ tx_desc [i ].next = & tx_desc [(i + 1 ) % TX_DESCRIPTOR_NUM ];
154
+
155
+ }
156
+ EMAC -> TXDSA = (unsigned int )& tx_desc [0 ];
157
+ return ;
158
+ }
159
+
160
+ static void init_rx_desc (void )
161
+ {
162
+ u32_t i ;
163
+
164
+
165
+ cur_rx_desc_ptr = & rx_desc [0 ];
166
+
167
+ for (i = 0 ; i < RX_DESCRIPTOR_NUM ; i ++ ) {
168
+ rx_desc [i ].status1 = OWNERSHIP_EMAC ;
169
+ rx_desc [i ].buf = & rx_buf [i ][0 ];
170
+ rx_desc [i ].status2 = 0 ;
171
+ rx_desc [i ].next = & rx_desc [(i + 1 ) % TX_DESCRIPTOR_NUM ];
172
+ }
173
+ EMAC -> RXDSA = (unsigned int )& rx_desc [0 ];
174
+ return ;
175
+ }
176
+
177
+ static void set_mac_addr (u8_t * addr )
178
+ {
179
+
180
+ EMAC -> CAM0M = (addr [0 ] << 24 ) |
181
+ (addr [1 ] << 16 ) |
182
+ (addr [2 ] << 8 ) |
183
+ addr [3 ];
184
+
185
+ EMAC -> CAM0L = (addr [4 ] << 24 ) |
186
+ (addr [5 ] << 16 );
187
+
188
+ EMAC -> CAMCTL = EMAC_CAMCTL_CMPEN_Msk | EMAC_CAMCTL_AMP_Msk | EMAC_CAMCTL_ABP_Msk ;
189
+ EMAC -> CAMEN = 1 ; // Enable CAM entry 0
190
+
191
+ }
192
+
193
+ static void __eth_clk_pin_init ()
194
+ {
195
+ /* Enable IP clock */
196
+ CLK_EnableModuleClock (EMAC_MODULE );
197
+ // Configure MDC clock rate to HCLK / (127 + 1) = 656 kHz if system is running at 84 MHz
198
+ CLK_SetModuleClock (EMAC_MODULE , 0 , CLK_CLKDIV3_EMAC (127 ));
199
+ /*---------------------------------------------------------------------------------------------------------*/
200
+ /* Init I/O Multi-function */
201
+ /*---------------------------------------------------------------------------------------------------------*/
202
+ // Configure RMII pins
203
+ SYS -> GPC_MFPL |= SYS_GPC_MFPL_PC0MFP_EMAC_REFCLK |
204
+ SYS_GPC_MFPL_PC1MFP_EMAC_MII_RXERR |
205
+ SYS_GPC_MFPL_PC2MFP_EMAC_MII_RXDV |
206
+ SYS_GPC_MFPL_PC3MFP_EMAC_MII_RXD1 |
207
+ SYS_GPC_MFPL_PC4MFP_EMAC_MII_RXD0 |
208
+ SYS_GPC_MFPL_PC6MFP_EMAC_MII_TXD0 |
209
+ SYS_GPC_MFPL_PC7MFP_EMAC_MII_TXD1 ;
210
+
211
+
212
+ SYS -> GPC_MFPH |= SYS_GPC_MFPH_PC8MFP_EMAC_MII_TXEN ;
213
+ // Enable high slew rate on all RMII pins
214
+ PC -> SLEWCTL |= 0x1DF ;
215
+
216
+ // Configure MDC, MDIO at PB14 & PB15
217
+ SYS -> GPB_MFPH |= SYS_GPB_MFPH_PB14MFP_EMAC_MII_MDC | SYS_GPB_MFPH_PB15MFP_EMAC_MII_MDIO ;
218
+
219
+ }
220
+
221
+ void ETH_init (u8_t * mac_addr )
222
+ {
223
+ // init CLK & pins
224
+ __eth_clk_pin_init ();
225
+
226
+ // Reset MAC
227
+ EMAC -> CTL = EMAC_CTL_RST_Msk ;
228
+
229
+ init_tx_desc ();
230
+ init_rx_desc ();
231
+
232
+ set_mac_addr (mac_addr ); // need to reconfigure hardware address 'cos we just RESET emc...
233
+ reset_phy ();
234
+
235
+ EMAC -> CTL |= EMAC_CTL_STRIPCRC_Msk | EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk | EMAC_CTL_RMIIEN_Msk | EMAC_CTL_RMIIRXCTL_Msk ;
236
+ EMAC -> INTEN |= EMAC_INTEN_RXIEN_Msk |
237
+ EMAC_INTEN_RXGDIEN_Msk |
238
+ EMAC_INTEN_RDUIEN_Msk |
239
+ EMAC_INTEN_RXBEIEN_Msk |
240
+ EMAC_INTEN_TXIEN_Msk |
241
+ EMAC_INTEN_TXABTIEN_Msk |
242
+ EMAC_INTEN_TXCPIEN_Msk |
243
+ EMAC_INTEN_TXBEIEN_Msk ;
244
+ EMAC -> RXST = 0 ; // trigger Rx
245
+ }
246
+
247
+
248
+
249
+ void ETH_halt (void )
250
+ {
251
+
252
+ EMAC -> CTL &= ~(EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk );
253
+ }
254
+
255
+
256
+
257
+ void EMAC_RX_IRQHandler (void )
258
+ {
259
+ unsigned int cur_entry , status ;
260
+
261
+ status = EMAC -> INTSTS & 0xFFFF ;
262
+ EMAC -> INTSTS = status ;
263
+ if (status & EMAC_INTSTS_RXBEIF_Msk ) {
264
+ // Shouldn't goes here, unless descriptor corrupted
265
+ printf ("RX descriptor corrupted \r\n" );
266
+ //return;
267
+ }
268
+ ack_emac_rx_isr ();
269
+ }
270
+
271
+ void EMAC_RX_Action (void )
272
+ {
273
+ unsigned int cur_entry , status ;
274
+ do {
275
+
276
+ cur_entry = EMAC -> CRXDSA ;
277
+
278
+ if ((cur_entry == (u32_t )cur_rx_desc_ptr ) && (!(status & EMAC_INTSTS_RDUIF_Msk ))) // cur_entry may equal to cur_rx_desc_ptr if RDU occures
279
+ break ;
280
+ status = cur_rx_desc_ptr -> status1 ;
281
+
282
+ if (status & OWNERSHIP_EMAC )
283
+ break ;
284
+
285
+ if (status & RXFD_RXGD ) {
286
+ // Lwip will invoke osMutexWait for resource protection, so ethernetif_input can't be called in EMAC_RX_IRQHandler.
287
+ ethernetif_input (status & 0xFFFF , cur_rx_desc_ptr -> buf , cur_rx_desc_ptr -> status2 , (u32_t )cur_rx_desc_ptr -> next );
288
+
289
+ }
290
+
291
+ cur_rx_desc_ptr -> status1 = OWNERSHIP_EMAC ;
292
+ cur_rx_desc_ptr = cur_rx_desc_ptr -> next ;
293
+
294
+ } while (1 );
295
+
296
+ ETH_TRIGGER_RX ();
297
+ // eth_arch_tcpip_thread();
298
+ }
299
+
300
+ void EMAC_TX_IRQHandler (void )
301
+ {
302
+ unsigned int cur_entry , status ;
303
+
304
+ status = EMAC -> INTSTS & 0xFFFF0000 ;
305
+ EMAC -> INTSTS = status ;
306
+ if (status & EMAC_INTSTS_TXBEIF_Msk ) {
307
+ // Shouldn't goes here, unless descriptor corrupted
308
+ return ;
309
+ }
310
+
311
+ cur_entry = EMAC -> CTXDSA ;
312
+
313
+ while (cur_entry != (u32_t )fin_tx_desc_ptr ) {
314
+
315
+ fin_tx_desc_ptr = fin_tx_desc_ptr -> next ;
316
+ }
317
+
318
+ }
319
+
320
+ u8_t * ETH_get_tx_buf (void )
321
+ {
322
+ if (cur_tx_desc_ptr -> status1 & OWNERSHIP_EMAC )
323
+ return (NULL );
324
+ else
325
+ return (cur_tx_desc_ptr -> buf );
326
+ }
327
+
328
+ void ETH_trigger_tx (u16_t length , struct pbuf * p )
329
+ {
330
+ struct eth_descriptor volatile * desc ;
331
+ cur_tx_desc_ptr -> status2 = (unsigned int )length ;
332
+ desc = cur_tx_desc_ptr -> next ; // in case TX is transmitting and overwrite next pointer before we can update cur_tx_desc_ptr
333
+ cur_tx_desc_ptr -> status1 |= OWNERSHIP_EMAC ;
334
+ cur_tx_desc_ptr = desc ;
335
+
336
+ ETH_TRIGGER_TX ();
337
+
338
+ }
339
+
340
+ int ETH_link_ok ()
341
+ {
342
+ /* first, a dummy read to latch */
343
+ mdio_read (CONFIG_PHY_ADDR , MII_BMSR );
344
+ if (mdio_read (CONFIG_PHY_ADDR , MII_BMSR ) & BMSR_LSTATUS )
345
+ return 1 ;
346
+ return 0 ;
347
+ }
0 commit comments