Merge pull request #294 from wolfmanjm/upstreamedge
[clinton/Smoothieware.git] / src / libs / Network / Drivers / LPC17XX_Ethernet.cpp
1 #if 0
2 #include "LPC17XX_Ethernet.h"
3
4 #include <cstring>
5 #include <cstdio>
6
7 #include "lpc17xx_clkpwr.h"
8
9 #include <mri.h>
10
11 // #include "netcore.h"
12
13 static const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28 };
14
15 /*--------------------------- write_PHY -------------------------------------*/
16 /*********************************************************************//**
17 * @brief Write value to PHY device
18 * @param[in] PhyReg: PHY Register address
19 * @param[in] Value: Value to write
20 * @return 0 - if success
21 * 1 - if fail
22 ***********************************************************************/
23 static int32_t write_PHY (uint32_t PhyReg, uint16_t Value)
24 {
25 /* Write a data 'Value' to PHY register 'PhyReg'. */
26 uint32_t tout;
27
28 LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg;
29 LPC_EMAC->MWTD = Value;
30
31 /* Wait until operation completed */
32 tout = 0;
33 for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) {
34 if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) {
35 return (0);
36 }
37 }
38 printf("write PHY %lu %04X failed!\n", PhyReg, Value);
39 // Time out!
40 return (-1);
41 }
42
43
44 /*--------------------------- read_PHY --------------------------------------*/
45 /*********************************************************************//**
46 * @brief Read value from PHY device
47 * @param[in] PhyReg: PHY Register address
48 * @return 0 - if success
49 * 1 - if fail
50 ***********************************************************************/
51 static int32_t read_PHY (uint32_t PhyReg)
52 {
53 /* Read a PHY register 'PhyReg'. */
54 uint32_t tout;
55
56 LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg;
57 LPC_EMAC->MCMD = EMAC_MCMD_READ;
58
59 /* Wait until operation completed */
60 tout = 0;
61 for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++) {
62 if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) {
63 LPC_EMAC->MCMD = 0;
64 return (LPC_EMAC->MRDD);
65 }
66 }
67 printf("read PHY %lu failed!\n", PhyReg);
68 // Time out!
69 return (-1);
70 }
71
72 /*********************************************************************//**
73 * @brief Set Station MAC address for EMAC module
74 * @param[in] abStationAddr Pointer to Station address that contains 6-bytes
75 * of MAC address (should be in order from MAC Address 1 to MAC Address 6)
76 * @return None
77 **********************************************************************/
78 static void setEmacAddr(uint8_t abStationAddr[])
79 {
80 /* Set the Ethernet MAC Address registers */
81 LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4];
82 LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2];
83 LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0];
84 }
85
86 /*********************************************************************//**
87 * @brief Set specified PHY mode in EMAC peripheral
88 * @param[in] ulPHYMode Specified PHY mode, should be:
89 * - EMAC_MODE_AUTO
90 * - EMAC_MODE_10M_FULL
91 * - EMAC_MODE_10M_HALF
92 * - EMAC_MODE_100M_FULL
93 * - EMAC_MODE_100M_HALF
94 * @return Return (0) if no error, otherwise return (-1)
95 **********************************************************************/
96 int32_t emac_SetPHYMode(uint32_t ulPHYMode)
97 {
98 int32_t id1, id2, tout, regv;
99
100 id1 = read_PHY (EMAC_PHY_REG_IDR1);
101 id2 = read_PHY (EMAC_PHY_REG_IDR2);
102
103 if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_SMSC_8720A) {
104 switch(ulPHYMode){
105 case EMAC_MODE_AUTO:
106 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG);
107 /* Wait to complete Auto_Negotiation */
108 for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
109 regv = read_PHY (EMAC_PHY_REG_BMSR);
110 if (regv & EMAC_PHY_BMSR_AUTO_DONE) {
111 /* Auto-negotiation Complete. */
112 break;
113 }
114 if (tout == 0){
115 // Time out, return error
116 return (-1);
117 }
118 }
119 break;
120 case EMAC_MODE_10M_FULL:
121 /* Connect at 10MBit full-duplex */
122 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M);
123 break;
124 case EMAC_MODE_10M_HALF:
125 /* Connect at 10MBit half-duplex */
126 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M);
127 break;
128 case EMAC_MODE_100M_FULL:
129 /* Connect at 100MBit full-duplex */
130 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M);
131 break;
132 case EMAC_MODE_100M_HALF:
133 /* Connect at 100MBit half-duplex */
134 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M);
135 break;
136 default:
137 // un-supported
138 return (-1);
139 }
140 }
141 // It's not correct module ID
142 else {
143 printf("PHY reports id %04lX %04lX - not an SMSC 8720A\n", id1, id2);
144 return (-1);
145 }
146
147 // Update EMAC configuration with current PHY status
148 if (EMAC_UpdatePHYStatus() < 0){
149 return (-1);
150 }
151
152 // Complete
153 return (0);
154 }
155
156 _rxbuf_t LPC17XX_Ethernet::rxbuf __attribute__ ((section ("AHBSRAM1")));
157 _txbuf_t LPC17XX_Ethernet::txbuf __attribute__ ((section ("AHBSRAM1")));
158
159 LPC17XX_Ethernet* LPC17XX_Ethernet::instance;
160
161 LPC17XX_Ethernet::LPC17XX_Ethernet()
162 {
163 mac_address[0] = 0xAE;
164 mac_address[1] = 0xF0;
165 mac_address[2] = 0x28;
166 mac_address[3] = 0x5D;
167 mac_address[4] = 0x66;
168 mac_address[5] = 0x41;
169
170 ip_address = IPA(192,168,1,27);
171 ip_mask = 0xFFFFFF00;
172
173 for (int i = 0; i < 5; i++)
174 {
175 rxbuf.rxdesc[i].packet = rxbuf.buf[i];
176 rxbuf.rxdesc[i].control = (1536 - 1) | EMAC_RCTRL_INT;
177
178 rxbuf.rxstat[i].Info = 0;
179 rxbuf.rxstat[i].HashCRC = 0;
180
181 txbuf.txdesc[i].packet = txbuf.buf[i];
182 txbuf.txdesc[i].control = (1536 - 1) | EMAC_TCTRL_PAD | EMAC_TCTRL_CRC | EMAC_TCTRL_LAST | EMAC_TCTRL_INT;
183
184 txbuf.txstat[i].Info = 0;
185 }
186
187 interface_name = (uint8_t*) malloc(5);
188 memcpy(interface_name, "eth0", 5);
189
190 instance = this;
191
192 up = false;
193 }
194
195 void LPC17XX_Ethernet::on_module_loaded()
196 {
197 LPC_PINCON->PINSEL2 = (1 << 0) | (1 << 2) | (1 << 8) | (1 << 16) | (1 << 18) | (1 << 20) | (1 << 28) | (1 << 30);
198 LPC_PINCON->PINSEL3 &= (2 << 0) | (2 << 2);
199 LPC_PINCON->PINSEL3 |= (1 << 0) | (1 << 2);
200
201 printf("EMAC_INIT\n");
202 emac_init();
203 printf("INIT OK\n");
204
205 register_for_event(ON_IDLE);
206 register_for_event(ON_SECOND_TICK);
207 }
208
209 void LPC17XX_Ethernet::on_idle(void*)
210 {
211 _receive_frame();
212 }
213
214 void LPC17XX_Ethernet::on_second_tick(void*)
215 {
216 // LPC_EMAC->Command = 0x303;
217 // setEmacAddr(mac_address);
218 uint32_t st;
219 st = read_PHY (EMAC_PHY_REG_BMSR);
220
221 if ((st & EMAC_PHY_BMSR_LINK_ESTABLISHED) && (st & EMAC_PHY_BMSR_AUTO_DONE) && (up == false))
222 {
223 // TODO: link up event
224 up = true;
225 // net->set_interface_status(this, up);
226 uint32_t scsr = read_PHY(EMAC_PHY_REG_SCSR);
227 printf("%s: link up: ", interface_name);
228 switch ((scsr >> 2) & 0x7)
229 {
230 case 1:
231 printf("10MBit Half Duplex\n");
232 break;
233 case 5:
234 printf("10MBit Full Duplex\n");
235 break;
236 case 2:
237 printf("100MBit Half Duplex\n");
238 break;
239 case 6:
240 printf("100MBit Full Duplex\n");
241 break;
242 default:
243 printf("Unknown speed: SCSR = 0x%04lX\n", scsr);
244 break;
245 }
246 }
247 else if (((st & EMAC_PHY_BMSR_LINK_ESTABLISHED) == 0) && up)
248 {
249 // TODO: link down event
250 up = false;
251 // net->set_interface_status(this, up);
252 printf("%s: link down\n", interface_name);
253 }
254
255 // printf("PHY: id:%04lX %04lX st:%04lX\n", id1, id2, st);
256 // printf("ETH: Rx:%lu/%lu Tx:%lu/%lu\n", LPC_EMAC->RxConsumeIndex, LPC_EMAC->RxProduceIndex, LPC_EMAC->TxProduceIndex, LPC_EMAC->TxConsumeIndex);
257 // printf("MII: 0x%1lX\n", LPC_EMAC->MIND);
258 // printf("Command: 0x%03lX Status: 0x%1lX\n", LPC_EMAC->Command, LPC_EMAC->Status);
259 // printf("RxN: %lu TxN: %lu\n", LPC_EMAC->RxDescriptorNumber, LPC_EMAC->TxDescriptorNumber);
260 // printf("MAC1: 0x%04lX MAC2: 0x%04lX\n", LPC_EMAC->MAC1, LPC_EMAC->MAC2);
261 // printf("MAC Address: %02lX:%02lX:%02lX:%02lX:%02lX:%02lX\n", (LPC_EMAC->SA2) & 0xFF, (LPC_EMAC->SA2 >> 8) & 0xFF, (LPC_EMAC->SA1) & 0xFF, (LPC_EMAC->SA1 >> 8) & 0xFF, (LPC_EMAC->SA0) & 0xFF, (LPC_EMAC->SA0 >> 8) & 0xFF);
262 }
263
264 void LPC17XX_Ethernet::emac_init()
265 {
266 /* Initialize the EMAC Ethernet controller. */
267 int32_t regv,tout, tmp;
268 volatile uint32_t d;
269
270 /* Set up clock and power for Ethernet module */
271 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE);
272
273 /* Reset all EMAC internal modules */
274 LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX |
275 EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES;
276
277 LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES;
278
279 /* A short delay after reset. */
280 for (d = 256; d; d--);
281
282 /* Initialize MAC control registers. */
283 LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
284 LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN | EMAC_MAC2_FULL_DUP;
285 LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
286 /*
287 * Find the clock that close to desired target clock
288 */
289 tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK;
290 for (tout = 0; tout < (int32_t) sizeof (EMAC_clkdiv); tout++){
291 if (EMAC_clkdiv[tout] >= tmp) break;
292 }
293 tout++;
294 // Write to MAC configuration register and reset
295 LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII;
296 // release reset
297 LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII);
298 LPC_EMAC->CLRT = EMAC_CLRT_DEF;
299 LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF;
300
301 /* Enable Reduced MII interface. */
302 LPC_EMAC->Command = EMAC_CR_RMII;
303
304 /* Reset Reduced MII Logic. */
305 LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII;
306
307 for (d = 256; d; d--);
308 LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
309
310 /* Put the DP83848C in reset mode */
311 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET);
312
313 /* Wait for hardware reset to end. */
314 for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
315 regv = read_PHY (EMAC_PHY_REG_BMCR);
316 if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) {
317 /* Reset complete, device not Power Down. */
318 break;
319 }
320 if (tout == 0){
321 // Time out, return ERROR
322 printf("ETH: PHY TIMEOUT\n");
323 return;
324 }
325 }
326
327 // Set PHY mode
328 // if (emac_SetPHYMode(EMAC_MODE_AUTO) < 0){
329 // printf("ETH: Error Setting Mode\n");
330 // return;
331 // }
332 write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG);
333
334 // Set EMAC address
335 setEmacAddr(mac_address);
336
337 /* Initialize Tx and Rx DMA Descriptors */
338 LPC_EMAC->RxDescriptor = (uint32_t) rxbuf.rxdesc;
339 LPC_EMAC->RxStatus = (uint32_t) rxbuf.rxstat;
340 LPC_EMAC->RxDescriptorNumber = 4;
341
342 LPC_EMAC->TxDescriptor = (uint32_t) txbuf.txdesc;
343 LPC_EMAC->TxStatus = (uint32_t) txbuf.txstat;
344 LPC_EMAC->TxDescriptorNumber = 4;
345
346 // Set Receive Filter register: enable broadcast and multicast
347 LPC_EMAC->RxFilterCtrl = EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN;
348
349 /* Enable Rx Done and Tx Done interrupt for EMAC */
350 LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE;
351
352 /* Reset all interrupts */
353 LPC_EMAC->IntClear = 0xFFFF;
354
355 /* Enable receive and transmit mode of MAC Ethernet core */
356 LPC_EMAC->Command = EMAC_CR_RX_EN | EMAC_CR_TX_EN | EMAC_CR_RMII | EMAC_CR_FULL_DUP | EMAC_CR_PASS_RUNT_FRM;
357 LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
358
359 printf("ETH:EMAC INITIALISED\n");
360 }
361
362 void LPC17XX_Ethernet::set_mac(uint8_t* newmac)
363 {
364 memcpy(mac_address, newmac, 6);
365 }
366
367 void LPC17XX_Ethernet::_receive_frame()
368 {
369 if (can_read_packet() && can_write_packet())
370 {
371 int i = LPC_EMAC->RxConsumeIndex;
372 RX_Stat* stat = &(rxbuf.rxstat[i]);
373 NET_PACKET packet = (NET_PACKET) rxbuf.buf[i];
374
375 int size = stat->Info & EMAC_RINFO_SIZE;
376 printf("Received %d byte Ethernet frame %lu/%lu\n", size, LPC_EMAC->RxProduceIndex, LPC_EMAC->RxConsumeIndex);
377
378 // TODO: feed received packet to network stack here
379 // int s = net->receive_packet(this, packet, size);
380 // if (s)
381 // {
382 // memcpy(request_packet_buffer(), packet, s);
383 // write_packet((uint8_t*) request_packet_buffer(), s);
384 // }
385
386 uint32_t r = LPC_EMAC->RxConsumeIndex + 1;
387 if (r > LPC_EMAC->RxDescriptorNumber)
388 r = 0;
389 LPC_EMAC->RxConsumeIndex = r;
390 }
391 }
392
393 void LPC17XX_Ethernet::irq()
394 {
395 if (EMAC_IntGetStatus(EMAC_INT_RX_DONE))
396 {
397 _receive_frame();
398 }
399
400 if (EMAC_IntGetStatus(EMAC_INT_TX_DONE))
401 {
402 }
403 }
404
405 bool LPC17XX_Ethernet::can_read_packet()
406 {
407 return (LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex);
408 }
409
410 int LPC17XX_Ethernet::read_packet(uint8_t** buf)
411 {
412 *buf = rxbuf.buf[LPC_EMAC->RxConsumeIndex];
413 return rxbuf.rxstat[LPC_EMAC->RxConsumeIndex].Info & EMAC_RINFO_SIZE;
414 }
415
416 void LPC17XX_Ethernet::release_read_packet(uint8_t*)
417 {
418 uint32_t r = LPC_EMAC->RxConsumeIndex + 1;
419 if (r > LPC_EMAC->RxDescriptorNumber)
420 r = 0;
421 LPC_EMAC->RxConsumeIndex = r;
422 }
423
424 bool LPC17XX_Ethernet::can_write_packet()
425 {
426 uint32_t r = LPC_EMAC->TxProduceIndex + 1;
427 if (r > LPC_EMAC->TxDescriptorNumber)
428 r = 0;
429 return (r != LPC_EMAC->TxConsumeIndex);
430 }
431
432 int LPC17XX_Ethernet::write_packet(uint8_t* buf, int size)
433 {
434 txbuf.txdesc[LPC_EMAC->TxProduceIndex].control = size | EMAC_TCTRL_LAST | EMAC_TCTRL_CRC | EMAC_TCTRL_PAD | EMAC_TCTRL_INT;
435
436 uint32_t r = LPC_EMAC->TxProduceIndex + 1;
437 if (r > LPC_EMAC->TxDescriptorNumber)
438 r = 0;
439
440 if (r == LPC_EMAC->TxConsumeIndex)
441 return 0;
442
443 LPC_EMAC->TxProduceIndex = r;
444
445 return size;
446 }
447
448 void* LPC17XX_Ethernet::request_packet_buffer()
449 {
450 return txbuf.txdesc[LPC_EMAC->TxProduceIndex].packet;
451 }
452
453 NET_PACKET LPC17XX_Ethernet::get_new_packet_buffer(NetworkInterface* ni)
454 {
455 if (ni != this)
456 return NULL;
457
458 return (NET_PACKET) request_packet_buffer();
459 }
460
461 NET_PAYLOAD LPC17XX_Ethernet::get_payload_buffer(NET_PACKET packet)
462 {
463 return (NET_PAYLOAD) packet;
464 }
465
466 void LPC17XX_Ethernet::set_payload_length(NET_PACKET packet, int length)
467 {
468 uint32_t offset = ((uint8_t*) packet) - txbuf.buf[0];
469 int i = (offset / LPC17XX_MAX_PACKET);
470 if ((i < LPC17XX_TXBUFS) && ((offset % LPC17XX_MAX_PACKET) == 0))
471 {
472 txbuf.txdesc[i].control = (txbuf.txdesc[i].control & ~EMAC_TCTRL_SIZE) | (length & EMAC_TCTRL_SIZE);
473 }
474 }
475
476 int LPC17XX_Ethernet::receive(NetworkInterface* ni, NET_PACKET packet, int length)
477 {
478 if (can_write_packet())
479 return write_packet((uint8_t*) packet, length);
480 return 0;
481 }
482
483 int LPC17XX_Ethernet::construct(NetworkInterface* ni, NET_PACKET packet, int length)
484 {
485 return length;
486 }
487
488 extern "C" {
489 void ENET_IRQHandler()
490 {
491 LPC17XX_Ethernet::instance->irq();
492 }
493 }
494
495 // void LPC17XX_Ethernet::provide_net(netcore* n)
496 // {
497 // NetworkInterface::provide_net(n);
498 // up = false;
499 // n->set_interface_status(this, up);
500 // }
501
502 #endif