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