2 #include "LPC17XX_Ethernet.h"
7 #include "lpc17xx_clkpwr.h"
11 // #include "netcore.h"
13 static const uint8_t EMAC_clkdiv
[] = { 4, 6, 8, 10, 14, 20, 28 };
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
22 ***********************************************************************/
23 static int32_t write_PHY (uint32_t PhyReg
, uint16_t Value
)
25 /* Write a data 'Value' to PHY register 'PhyReg'. */
28 LPC_EMAC
->MADR
= EMAC_DEF_ADR
| PhyReg
;
29 LPC_EMAC
->MWTD
= Value
;
31 /* Wait until operation completed */
33 for (tout
= 0; tout
< EMAC_MII_WR_TOUT
; tout
++) {
34 if ((LPC_EMAC
->MIND
& EMAC_MIND_BUSY
) == 0) {
38 printf("write PHY %lu %04X failed!\n", PhyReg
, Value
);
44 /*--------------------------- read_PHY --------------------------------------*/
45 /*********************************************************************//**
46 * @brief Read value from PHY device
47 * @param[in] PhyReg: PHY Register address
48 * @return 0 - if success
50 ***********************************************************************/
51 static int32_t read_PHY (uint32_t PhyReg
)
53 /* Read a PHY register 'PhyReg'. */
56 LPC_EMAC
->MADR
= EMAC_DEF_ADR
| PhyReg
;
57 LPC_EMAC
->MCMD
= EMAC_MCMD_READ
;
59 /* Wait until operation completed */
61 for (tout
= 0; tout
< EMAC_MII_RD_TOUT
; tout
++) {
62 if ((LPC_EMAC
->MIND
& EMAC_MIND_BUSY
) == 0) {
64 return (LPC_EMAC
->MRDD
);
67 printf("read PHY %lu failed!\n", PhyReg
);
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)
77 **********************************************************************/
78 static void setEmacAddr(uint8_t abStationAddr
[])
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];
86 /*********************************************************************//**
87 * @brief Set specified PHY mode in EMAC peripheral
88 * @param[in] ulPHYMode Specified PHY mode, should be:
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
)
98 int32_t id1
, id2
, tout
, regv
;
100 id1
= read_PHY (EMAC_PHY_REG_IDR1
);
101 id2
= read_PHY (EMAC_PHY_REG_IDR2
);
103 if (((id1
<< 16) | (id2
& 0xFFF0)) == EMAC_SMSC_8720A
) {
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. */
115 // Time out, return error
120 case EMAC_MODE_10M_FULL
:
121 /* Connect at 10MBit full-duplex */
122 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_FULLD_10M
);
124 case EMAC_MODE_10M_HALF
:
125 /* Connect at 10MBit half-duplex */
126 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_HALFD_10M
);
128 case EMAC_MODE_100M_FULL
:
129 /* Connect at 100MBit full-duplex */
130 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_FULLD_100M
);
132 case EMAC_MODE_100M_HALF
:
133 /* Connect at 100MBit half-duplex */
134 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_HALFD_100M
);
141 // It's not correct module ID
143 printf("PHY reports id %04lX %04lX - not an SMSC 8720A\n", id1
, id2
);
147 // Update EMAC configuration with current PHY status
148 if (EMAC_UpdatePHYStatus() < 0){
156 _rxbuf_t
LPC17XX_Ethernet::rxbuf
__attribute__ ((section ("AHBSRAM1")));
157 _txbuf_t
LPC17XX_Ethernet::txbuf
__attribute__ ((section ("AHBSRAM1")));
159 LPC17XX_Ethernet
* LPC17XX_Ethernet::instance
;
161 LPC17XX_Ethernet::LPC17XX_Ethernet()
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;
170 ip_address
= IPA(192,168,1,27);
171 ip_mask
= 0xFFFFFF00;
173 for (int i
= 0; i
< 5; i
++)
175 rxbuf
.rxdesc
[i
].packet
= rxbuf
.buf
[i
];
176 rxbuf
.rxdesc
[i
].control
= (1536 - 1) | EMAC_RCTRL_INT
;
178 rxbuf
.rxstat
[i
].Info
= 0;
179 rxbuf
.rxstat
[i
].HashCRC
= 0;
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
;
184 txbuf
.txstat
[i
].Info
= 0;
187 interface_name
= (uint8_t*) malloc(5);
188 memcpy(interface_name
, "eth0", 5);
195 void LPC17XX_Ethernet::on_module_loaded()
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);
201 printf("EMAC_INIT\n");
205 register_for_event(ON_IDLE
);
206 register_for_event(ON_SECOND_TICK
);
209 void LPC17XX_Ethernet::on_idle(void*)
214 void LPC17XX_Ethernet::on_second_tick(void*)
216 // LPC_EMAC->Command = 0x303;
217 // setEmacAddr(mac_address);
219 st
= read_PHY (EMAC_PHY_REG_BMSR
);
221 if ((st
& EMAC_PHY_BMSR_LINK_ESTABLISHED
) && (st
& EMAC_PHY_BMSR_AUTO_DONE
) && (up
== false))
223 // TODO: link up event
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)
231 printf("10MBit Half Duplex\n");
234 printf("10MBit Full Duplex\n");
237 printf("100MBit Half Duplex\n");
240 printf("100MBit Full Duplex\n");
243 printf("Unknown speed: SCSR = 0x%04lX\n", scsr
);
247 else if (((st
& EMAC_PHY_BMSR_LINK_ESTABLISHED
) == 0) && up
)
249 // TODO: link down event
251 // net->set_interface_status(this, up);
252 printf("%s: link down\n", interface_name
);
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);
264 void LPC17XX_Ethernet::emac_init()
266 /* Initialize the EMAC Ethernet controller. */
267 int32_t regv
,tout
, tmp
;
270 /* Set up clock and power for Ethernet module */
271 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET
, ENABLE
);
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
;
277 LPC_EMAC
->Command
= EMAC_CR_REG_RES
| EMAC_CR_TX_RES
| EMAC_CR_RX_RES
;
279 /* A short delay after reset. */
280 for (d
= 256; d
; d
--);
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
;
287 * Find the clock that close to desired target clock
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;
294 // Write to MAC configuration register and reset
295 LPC_EMAC
->MCFG
= EMAC_MCFG_CLK_SEL(tout
) | EMAC_MCFG_RES_MII
;
297 LPC_EMAC
->MCFG
&= ~(EMAC_MCFG_RES_MII
);
298 LPC_EMAC
->CLRT
= EMAC_CLRT_DEF
;
299 LPC_EMAC
->IPGR
= EMAC_IPGR_P2_DEF
;
301 /* Enable Reduced MII interface. */
302 LPC_EMAC
->Command
= EMAC_CR_RMII
;
304 /* Reset Reduced MII Logic. */
305 LPC_EMAC
->SUPP
= EMAC_SUPP_RES_RMII
;
307 for (d
= 256; d
; d
--);
308 LPC_EMAC
->SUPP
= EMAC_SUPP_SPEED
;
310 /* Put the DP83848C in reset mode */
311 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_BMCR_RESET
);
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. */
321 // Time out, return ERROR
322 printf("ETH: PHY TIMEOUT\n");
328 // if (emac_SetPHYMode(EMAC_MODE_AUTO) < 0){
329 // printf("ETH: Error Setting Mode\n");
332 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_AUTO_NEG
);
335 setEmacAddr(mac_address
);
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;
342 LPC_EMAC
->TxDescriptor
= (uint32_t) txbuf
.txdesc
;
343 LPC_EMAC
->TxStatus
= (uint32_t) txbuf
.txstat
;
344 LPC_EMAC
->TxDescriptorNumber
= 4;
346 // Set Receive Filter register: enable broadcast and multicast
347 LPC_EMAC
->RxFilterCtrl
= EMAC_RFC_BCAST_EN
| EMAC_RFC_PERFECT_EN
;
349 /* Enable Rx Done and Tx Done interrupt for EMAC */
350 LPC_EMAC
->IntEnable
= EMAC_INT_RX_DONE
| EMAC_INT_TX_DONE
;
352 /* Reset all interrupts */
353 LPC_EMAC
->IntClear
= 0xFFFF;
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
;
359 printf("ETH:EMAC INITIALISED\n");
362 void LPC17XX_Ethernet::set_mac(uint8_t* newmac
)
364 memcpy(mac_address
, newmac
, 6);
367 void LPC17XX_Ethernet::_receive_frame()
369 if (can_read_packet() && can_write_packet())
371 int i
= LPC_EMAC
->RxConsumeIndex
;
372 RX_Stat
* stat
= &(rxbuf
.rxstat
[i
]);
373 NET_PACKET packet
= (NET_PACKET
) rxbuf
.buf
[i
];
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
);
378 // TODO: feed received packet to network stack here
379 // int s = net->receive_packet(this, packet, size);
382 // memcpy(request_packet_buffer(), packet, s);
383 // write_packet((uint8_t*) request_packet_buffer(), s);
386 uint32_t r
= LPC_EMAC
->RxConsumeIndex
+ 1;
387 if (r
> LPC_EMAC
->RxDescriptorNumber
)
389 LPC_EMAC
->RxConsumeIndex
= r
;
393 void LPC17XX_Ethernet::irq()
395 if (EMAC_IntGetStatus(EMAC_INT_RX_DONE
))
400 if (EMAC_IntGetStatus(EMAC_INT_TX_DONE
))
405 bool LPC17XX_Ethernet::can_read_packet()
407 return (LPC_EMAC
->RxProduceIndex
!= LPC_EMAC
->RxConsumeIndex
);
410 int LPC17XX_Ethernet::read_packet(uint8_t** buf
)
412 *buf
= rxbuf
.buf
[LPC_EMAC
->RxConsumeIndex
];
413 return rxbuf
.rxstat
[LPC_EMAC
->RxConsumeIndex
].Info
& EMAC_RINFO_SIZE
;
416 void LPC17XX_Ethernet::release_read_packet(uint8_t*)
418 uint32_t r
= LPC_EMAC
->RxConsumeIndex
+ 1;
419 if (r
> LPC_EMAC
->RxDescriptorNumber
)
421 LPC_EMAC
->RxConsumeIndex
= r
;
424 bool LPC17XX_Ethernet::can_write_packet()
426 uint32_t r
= LPC_EMAC
->TxProduceIndex
+ 1;
427 if (r
> LPC_EMAC
->TxDescriptorNumber
)
429 return (r
!= LPC_EMAC
->TxConsumeIndex
);
432 int LPC17XX_Ethernet::write_packet(uint8_t* buf
, int size
)
434 txbuf
.txdesc
[LPC_EMAC
->TxProduceIndex
].control
= size
| EMAC_TCTRL_LAST
| EMAC_TCTRL_CRC
| EMAC_TCTRL_PAD
| EMAC_TCTRL_INT
;
436 uint32_t r
= LPC_EMAC
->TxProduceIndex
+ 1;
437 if (r
> LPC_EMAC
->TxDescriptorNumber
)
440 if (r
== LPC_EMAC
->TxConsumeIndex
)
443 LPC_EMAC
->TxProduceIndex
= r
;
448 void* LPC17XX_Ethernet::request_packet_buffer()
450 return txbuf
.txdesc
[LPC_EMAC
->TxProduceIndex
].packet
;
453 NET_PACKET
LPC17XX_Ethernet::get_new_packet_buffer(NetworkInterface
* ni
)
458 return (NET_PACKET
) request_packet_buffer();
461 NET_PAYLOAD
LPC17XX_Ethernet::get_payload_buffer(NET_PACKET packet
)
463 return (NET_PAYLOAD
) packet
;
466 void LPC17XX_Ethernet::set_payload_length(NET_PACKET packet
, int length
)
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))
472 txbuf
.txdesc
[i
].control
= (txbuf
.txdesc
[i
].control
& ~EMAC_TCTRL_SIZE
) | (length
& EMAC_TCTRL_SIZE
);
476 int LPC17XX_Ethernet::receive(NetworkInterface
* ni
, NET_PACKET packet
, int length
)
478 if (can_write_packet())
479 return write_packet((uint8_t*) packet
, length
);
483 int LPC17XX_Ethernet::construct(NetworkInterface
* ni
, NET_PACKET packet
, int length
)
489 void ENET_IRQHandler()
491 LPC17XX_Ethernet::instance
->irq();
495 // void LPC17XX_Ethernet::provide_net(netcore* n)
497 // NetworkInterface::provide_net(n);
499 // n->set_interface_status(this, up);