1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 */
9 #include "LPC177x_8x.h"
10 #include "lpc177x_8x_pinsel.h"
11 #include "emac.h"
12
13 #include <rtthread.h>
14 #include "lwipopts.h"
15 #include <netif/ethernetif.h>
16
17 #define EMAC_PHY_AUTO 0
18 #define EMAC_PHY_10MBIT 1
19 #define EMAC_PHY_100MBIT 2
20
21 #define MAX_ADDR_LEN 6
22 struct lpc17xx_emac
23 {
24 /* inherit from ethernet device */
25 struct eth_device parent;
26
27 rt_uint8_t phy_mode;
28
29 /* interface address info. */
30 rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
31 };
32 static struct lpc17xx_emac lpc17xx_emac_device;
33 static struct rt_semaphore sem_lock;
34 static struct rt_event tx_event;
35
36 /* Local Function Prototypes */
37 static void write_PHY (rt_uint32_t PhyReg, rt_uint32_t Value);
38 static rt_uint16_t read_PHY (rt_uint8_t PhyReg) ;
39
ENET_IRQHandler(void)40 void ENET_IRQHandler(void)
41 {
42 rt_uint32_t status;
43
44 /* enter interrupt */
45 rt_interrupt_enter();
46
47 status = LPC_EMAC->IntStatus;
48
49 if (status & INT_RX_DONE)
50 {
51 /* Disable EMAC RxDone interrupts. */
52 LPC_EMAC->IntEnable = INT_TX_DONE;
53
54 /* a frame has been received */
55 eth_device_ready(&(lpc17xx_emac_device.parent));
56 }
57 else if (status & INT_TX_DONE)
58 {
59 /* set event */
60 rt_event_send(&tx_event, 0x01);
61 }
62
63 if (status & INT_RX_OVERRUN)
64 {
65 rt_kprintf("rx overrun\n");
66 }
67
68 if (status & INT_TX_UNDERRUN)
69 {
70 rt_kprintf("tx underrun\n");
71 }
72
73 /* Clear the interrupt. */
74 LPC_EMAC->IntClear = status;
75
76 /* leave interrupt */
77 rt_interrupt_leave();
78 }
79
80 /* phy write */
write_PHY(rt_uint32_t PhyReg,rt_uint32_t Value)81 static void write_PHY (rt_uint32_t PhyReg, rt_uint32_t Value)
82 {
83 unsigned int tout;
84
85 LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg;
86 LPC_EMAC->MWTD = Value;
87
88 /* Wait utill operation completed */
89 tout = 0;
90 for (tout = 0; tout < MII_WR_TOUT; tout++)
91 {
92 if ((LPC_EMAC->MIND & MIND_BUSY) == 0)
93 {
94 break;
95 }
96 }
97 }
98
99 /* phy read */
read_PHY(rt_uint8_t PhyReg)100 static rt_uint16_t read_PHY (rt_uint8_t PhyReg)
101 {
102 rt_uint32_t tout;
103
104 LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg;
105 LPC_EMAC->MCMD = MCMD_READ;
106
107 /* Wait until operation completed */
108 tout = 0;
109 for (tout = 0; tout < MII_RD_TOUT; tout++)
110 {
111 if ((LPC_EMAC->MIND & MIND_BUSY) == 0)
112 {
113 break;
114 }
115 }
116 LPC_EMAC->MCMD = 0;
117 return (LPC_EMAC->MRDD);
118 }
119
120 /* init rx descriptor */
rx_descr_init(void)121 rt_inline void rx_descr_init (void)
122 {
123 rt_uint32_t i;
124
125 for (i = 0; i < NUM_RX_FRAG; i++)
126 {
127 RX_DESC_PACKET(i) = RX_BUF(i);
128 RX_DESC_CTRL(i) = RCTRL_INT | (ETH_FRAG_SIZE-1);
129 RX_STAT_INFO(i) = 0;
130 RX_STAT_HASHCRC(i) = 0;
131 }
132
133 /* Set EMAC Receive Descriptor Registers. */
134 LPC_EMAC->RxDescriptor = RX_DESC_BASE;
135 LPC_EMAC->RxStatus = RX_STAT_BASE;
136 LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG-1;
137
138 /* Rx Descriptors Point to 0 */
139 LPC_EMAC->RxConsumeIndex = 0;
140 }
141
142 /* init tx descriptor */
tx_descr_init(void)143 rt_inline void tx_descr_init (void)
144 {
145 rt_uint32_t i;
146
147 for (i = 0; i < NUM_TX_FRAG; i++)
148 {
149 TX_DESC_PACKET(i) = TX_BUF(i);
150 TX_DESC_CTRL(i) = (1ul<<31) | (1ul<<30) | (1ul<<29) | (1ul<<28) | (1ul<<26) | (ETH_FRAG_SIZE-1);
151 TX_STAT_INFO(i) = 0;
152 }
153
154 /* Set EMAC Transmit Descriptor Registers. */
155 LPC_EMAC->TxDescriptor = TX_DESC_BASE;
156 LPC_EMAC->TxStatus = TX_STAT_BASE;
157 LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1;
158
159 /* Tx Descriptors Point to 0 */
160 LPC_EMAC->TxProduceIndex = 0;
161 }
162
163 /*
164 TX_EN P1_4
165 TXD0 P1_0
166 TXD1 P1_1
167
168 RXD0 P1_9
169 RXD1 P1_10
170 RX_ER P1_14
171 CRS_DV P1_8
172
173 MDC P1_16
174 MDIO P1_17
175
176 PHY_RESET P3_19
177 REF_CLK P1_15
178 */
lpc17xx_emac_init(rt_device_t dev)179 static rt_err_t lpc17xx_emac_init(rt_device_t dev)
180 {
181 /* Initialize the EMAC ethernet controller. */
182 rt_uint32_t regv, tout;
183
184 /* Power Up the EMAC controller. */
185 LPC_SC->PCONP |= (1UL<<30);
186
187 /* config RESET */
188 PINSEL_ConfigPin(3, 19, 0);
189 PINSEL_SetPinMode(3, 19, IOCON_MODE_PLAIN);
190 LPC_GPIO3->DIR |= 1<<19;
191 LPC_GPIO3->CLR = 1<<19;
192
193 /* Enable P1 Ethernet Pins. */
194 PINSEL_ConfigPin(1, 0, 1); /**< P1_0 ENET_TXD0 */
195 PINSEL_ConfigPin(1, 1, 1); /**< P1_1 ENET_TXD1 */
196 PINSEL_ConfigPin(1, 4, 1); /**< P1_4 ENET_TX_EN */
197 PINSEL_ConfigPin(1, 8, 1); /**< P1_8 ENET_CRS_DV */
198 PINSEL_ConfigPin(1, 9, 1); /**< P1_9 ENET_RXD0 */
199 PINSEL_ConfigPin(1, 10, 1); /**< P1_10 ENET_RXD1 */
200 PINSEL_ConfigPin(1, 14, 1); /**< P1_14 ENET_RX_ER */
201 PINSEL_ConfigPin(1, 15, 1); /**< P1_15 ENET_REF_CLK */
202 PINSEL_ConfigPin(1, 16, 1); /**< P1_16 ENET_MDC */
203 PINSEL_ConfigPin(1, 17, 1); /**< P1_17 ENET_MDIO */
204
205 LPC_GPIO3->SET = 1<<19;
206
207 /* Reset all EMAC internal modules. */
208 LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX |
209 MAC1_SIM_RES | MAC1_SOFT_RES;
210 LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES;
211
212 /* A short delay after reset. */
213 for (tout = 100; tout; tout--);
214
215 /* Initialize MAC control registers. */
216 LPC_EMAC->MAC1 = MAC1_PASS_ALL;
217 LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
218 LPC_EMAC->MAXF = ETH_MAX_FLEN;
219 LPC_EMAC->CLRT = CLRT_DEF;
220 LPC_EMAC->IPGR = IPGR_DEF;
221
222 /* PCLK=18MHz, clock select=6, MDC=18/6=3MHz */
223 /* Enable Reduced MII interface. */
224 LPC_EMAC->MCFG = MCFG_CLK_DIV20 | MCFG_RES_MII;
225 for (tout = 100; tout; tout--);
226 LPC_EMAC->MCFG = MCFG_CLK_DIV20;
227
228 /* Enable Reduced MII interface. */
229 LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT;
230
231 /* Reset Reduced MII Logic. */
232 LPC_EMAC->SUPP = SUPP_RES_RMII | SUPP_SPEED;
233 for (tout = 100; tout; tout--);
234 LPC_EMAC->SUPP = SUPP_SPEED;
235
236 /* Put the PHY in reset mode */
237 write_PHY (PHY_REG_BMCR, 0x8000);
238 for (tout = 1000; tout; tout--);
239
240 // /* Wait for hardware reset to end. */
241 // for (tout = 0; tout < 0x100000; tout++)
242 // {
243 // regv = read_PHY (PHY_REG_BMCR);
244 // if (!(regv & 0x8000))
245 // {
246 // /* Reset complete */
247 // break;
248 // }
249 // }
250 // if (tout >= 0x100000)
251 // {
252 // rt_kprintf("reset failed\r\n");
253 // return -RT_ERROR; /* reset failed */
254 // }
255
256 // /* Check if this is a DP83848C PHY. */
257 // id1 = read_PHY (PHY_REG_IDR1);
258 // id2 = read_PHY (PHY_REG_IDR2);
259 //
260 // if (((id1 << 16) | (id2 & 0xFFF0)) != DP83848C_ID)
261 // return -RT_ERROR;
262
263 /* Configure the PHY device */
264 /* Configure the PHY device */
265 switch (lpc17xx_emac_device.phy_mode)
266 {
267 case EMAC_PHY_AUTO:
268 /* Use autonegotiation about the link speed. */
269 write_PHY (PHY_REG_BMCR, PHY_AUTO_NEG);
270 /* Wait to complete Auto_Negotiation. */
271 // for (tout = 0; tout < 0x100000; tout++)
272 // {
273 // regv = read_PHY (PHY_REG_BMSR);
274 // if (regv & 0x0020)
275 // {
276 // /* Autonegotiation Complete. */
277 // break;
278 // }
279 // }
280 break;
281 case EMAC_PHY_10MBIT:
282 /* Connect at 10MBit */
283 write_PHY (PHY_REG_BMCR, PHY_FULLD_10M);
284 break;
285 case EMAC_PHY_100MBIT:
286 /* Connect at 100MBit */
287 write_PHY (PHY_REG_BMCR, PHY_FULLD_100M);
288 break;
289 }
290 if (tout >= 0x100000) return -RT_ERROR; // auto_neg failed
291
292 // /* Check the link status. */
293 // for (tout = 0; tout < 0x10000; tout++)
294 // {
295 // regv = read_PHY (PHY_REG_STS);
296 // if (regv & 0x0001)
297 // {
298 // /* Link is on. */
299 // break;
300 // }
301 // }
302 // if (tout >= 0x10000) return -RT_ERROR;
303
304 regv = 0x0004;
305 /* Configure Full/Half Duplex mode. */
306 if (regv & 0x0004)
307 {
308 /* Full duplex is enabled. */
309 LPC_EMAC->MAC2 |= MAC2_FULL_DUP;
310 LPC_EMAC->Command |= CR_FULL_DUP;
311 LPC_EMAC->IPGT = IPGT_FULL_DUP;
312 }
313 else
314 {
315 /* Half duplex mode. */
316 LPC_EMAC->IPGT = IPGT_HALF_DUP;
317 }
318
319 /* Configure 100MBit/10MBit mode. */
320 if (regv & 0x0002)
321 {
322 /* 10MBit mode. */
323 LPC_EMAC->SUPP = 0;
324 }
325 else
326 {
327 /* 100MBit mode. */
328 LPC_EMAC->SUPP = SUPP_SPEED;
329 }
330
331 /* Set the Ethernet MAC Address registers */
332 LPC_EMAC->SA0 = (lpc17xx_emac_device.dev_addr[1]<<8) | lpc17xx_emac_device.dev_addr[0];
333 LPC_EMAC->SA1 = (lpc17xx_emac_device.dev_addr[3]<<8) | lpc17xx_emac_device.dev_addr[2];
334 LPC_EMAC->SA2 = (lpc17xx_emac_device.dev_addr[5]<<8) | lpc17xx_emac_device.dev_addr[4];
335
336 /* Initialize Tx and Rx DMA Descriptors */
337 rx_descr_init ();
338 tx_descr_init ();
339
340 /* Receive Broadcast and Perfect Match Packets */
341 LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN;
342
343 /* Reset all interrupts */
344 LPC_EMAC->IntClear = 0xFFFF;
345
346 /* Enable EMAC interrupts. */
347 LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE;
348
349 /* Enable receive and transmit mode of MAC Ethernet core */
350 LPC_EMAC->Command |= (CR_RX_EN | CR_TX_EN);
351 LPC_EMAC->MAC1 |= MAC1_REC_EN;
352
353 /* Enable the ENET Interrupt */
354 NVIC_EnableIRQ(ENET_IRQn);
355
356 return RT_EOK;
357 }
358
lpc17xx_emac_open(rt_device_t dev,rt_uint16_t oflag)359 static rt_err_t lpc17xx_emac_open(rt_device_t dev, rt_uint16_t oflag)
360 {
361 return RT_EOK;
362 }
363
lpc17xx_emac_close(rt_device_t dev)364 static rt_err_t lpc17xx_emac_close(rt_device_t dev)
365 {
366 return RT_EOK;
367 }
368
lpc17xx_emac_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)369 static rt_ssize_t lpc17xx_emac_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
370 {
371 return -RT_ENOSYS;
372 }
373
lpc17xx_emac_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)374 static rt_ssize_t lpc17xx_emac_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
375 {
376 return -RT_ENOSYS;
377 }
378
lpc17xx_emac_control(rt_device_t dev,int cmd,void * args)379 static rt_err_t lpc17xx_emac_control(rt_device_t dev, int cmd, void *args)
380 {
381 switch (cmd)
382 {
383 case NIOCTL_GADDR:
384 /* get mac address */
385 if (args) rt_memcpy(args, lpc17xx_emac_device.dev_addr, 6);
386 else return -RT_ERROR;
387 break;
388
389 default :
390 break;
391 }
392
393 return RT_EOK;
394 }
395
396 /* EtherNet Device Interface */
397 /* transmit packet. */
lpc17xx_emac_tx(rt_device_t dev,struct pbuf * p)398 rt_err_t lpc17xx_emac_tx( rt_device_t dev, struct pbuf* p)
399 {
400 rt_uint32_t Index, IndexNext;
401 struct pbuf *q;
402 rt_uint8_t *ptr;
403
404 /* calculate next index */
405 IndexNext = LPC_EMAC->TxProduceIndex + 1;
406 if(IndexNext > LPC_EMAC->TxDescriptorNumber) IndexNext = 0;
407
408 /* check whether block is full */
409 while (IndexNext == LPC_EMAC->TxConsumeIndex)
410 {
411 rt_err_t result;
412 rt_uint32_t recved;
413
414 /* there is no block yet, wait a flag */
415 result = rt_event_recv(&tx_event, 0x01,
416 RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &recved);
417
418 RT_ASSERT(result == RT_EOK);
419 }
420
421 /* lock EMAC device */
422 rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
423
424 /* get produce index */
425 Index = LPC_EMAC->TxProduceIndex;
426
427 /* calculate next index */
428 IndexNext = LPC_EMAC->TxProduceIndex + 1;
429 if(IndexNext > LPC_EMAC->TxDescriptorNumber)
430 IndexNext = 0;
431
432 /* copy data to tx buffer */
433 q = p;
434 ptr = (rt_uint8_t*)TX_BUF(Index);
435 while (q)
436 {
437 memcpy(ptr, q->payload, q->len);
438 ptr += q->len;
439 q = q->next;
440 }
441
442 TX_DESC_CTRL(Index) &= ~0x7ff;
443 TX_DESC_CTRL(Index) |= (p->tot_len - 1) & 0x7ff;
444
445 /* change index to the next */
446 LPC_EMAC->TxProduceIndex = IndexNext;
447
448 /* unlock EMAC device */
449 rt_sem_release(&sem_lock);
450
451 return RT_EOK;
452 }
453
454 /* reception packet. */
lpc17xx_emac_rx(rt_device_t dev)455 struct pbuf *lpc17xx_emac_rx(rt_device_t dev)
456 {
457 struct pbuf* p;
458 rt_uint32_t size;
459 rt_uint32_t Index;
460
461 /* init p pointer */
462 p = RT_NULL;
463
464 /* lock EMAC device */
465 rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
466
467 Index = LPC_EMAC->RxConsumeIndex;
468 if(Index != LPC_EMAC->RxProduceIndex)
469 {
470 size = (RX_STAT_INFO(Index) & 0x7ff)+1;
471 if (size > ETH_FRAG_SIZE) size = ETH_FRAG_SIZE;
472
473 /* allocate buffer */
474 p = pbuf_alloc(PBUF_LINK, size, PBUF_RAM);
475 if (p != RT_NULL)
476 {
477 struct pbuf* q;
478 rt_uint8_t *ptr;
479
480 ptr = (rt_uint8_t*)RX_BUF(Index);
481 for (q = p; q != RT_NULL; q= q->next)
482 {
483 memcpy(q->payload, ptr, q->len);
484 ptr += q->len;
485 }
486 }
487
488 /* move Index to the next */
489 if(++Index > LPC_EMAC->RxDescriptorNumber)
490 Index = 0;
491
492 /* set consume index */
493 LPC_EMAC->RxConsumeIndex = Index;
494 }
495 else
496 {
497 /* Enable RxDone interrupt */
498 LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE;
499 }
500
501 /* unlock EMAC device */
502 rt_sem_release(&sem_lock);
503
504 return p;
505 }
506
lpc17xx_emac_hw_init(void)507 void lpc17xx_emac_hw_init(void)
508 {
509 rt_event_init(&tx_event, "tx_event", RT_IPC_FLAG_FIFO);
510 rt_sem_init(&sem_lock, "eth_lock", 1, RT_IPC_FLAG_FIFO);
511
512 /* set autonegotiation mode */
513 lpc17xx_emac_device.phy_mode = EMAC_PHY_AUTO;
514
515 // OUI 00-60-37 NXP Semiconductors
516 lpc17xx_emac_device.dev_addr[0] = 0x00;
517 lpc17xx_emac_device.dev_addr[1] = 0x60;
518 lpc17xx_emac_device.dev_addr[2] = 0x37;
519 /* set mac address: (only for test) */
520 lpc17xx_emac_device.dev_addr[3] = 0x12;
521 lpc17xx_emac_device.dev_addr[4] = 0x34;
522 lpc17xx_emac_device.dev_addr[5] = 0x56;
523
524 lpc17xx_emac_device.parent.parent.init = lpc17xx_emac_init;
525 lpc17xx_emac_device.parent.parent.open = lpc17xx_emac_open;
526 lpc17xx_emac_device.parent.parent.close = lpc17xx_emac_close;
527 lpc17xx_emac_device.parent.parent.read = lpc17xx_emac_read;
528 lpc17xx_emac_device.parent.parent.write = lpc17xx_emac_write;
529 lpc17xx_emac_device.parent.parent.control = lpc17xx_emac_control;
530 lpc17xx_emac_device.parent.parent.user_data = RT_NULL;
531
532 lpc17xx_emac_device.parent.eth_rx = lpc17xx_emac_rx;
533 lpc17xx_emac_device.parent.eth_tx = lpc17xx_emac_tx;
534
535 eth_device_init(&(lpc17xx_emac_device.parent), "e0");
536 }
537
538 #ifdef RT_USING_FINSH
539 #include <finsh.h>
emac_dump()540 void emac_dump()
541 {
542 rt_kprintf("Command : %08x\n", LPC_EMAC->Command);
543 rt_kprintf("Status : %08x\n", LPC_EMAC->Status);
544 rt_kprintf("RxStatus : %08x\n", LPC_EMAC->RxStatus);
545 rt_kprintf("TxStatus : %08x\n", LPC_EMAC->TxStatus);
546 rt_kprintf("IntEnable: %08x\n", LPC_EMAC->IntEnable);
547 rt_kprintf("IntStatus: %08x\n", LPC_EMAC->IntStatus);
548 }
549 FINSH_FUNCTION_EXPORT(emac_dump, dump emac register);
550 #endif
551
552