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