1 #include "LPC17XX_Ethernet.h"
6 #include "lpc17xx_clkpwr.h"
10 // #include "netcore.h"
12 static const uint8_t EMAC_clkdiv
[] = { 4, 6, 8, 10, 14, 20, 28 };
14 /*--------------------------- write_PHY -------------------------------------*/
15 /*********************************************************************//**
16 * @brief Write value to PHY device
17 * @param[in] PhyReg: PHY Register address
18 * @param[in] Value: Value to write
19 * @return 0 - if success
21 ***********************************************************************/
22 static int32_t write_PHY (uint32_t PhyReg
, uint16_t Value
)
24 /* Write a data 'Value' to PHY register 'PhyReg'. */
27 LPC_EMAC
->MADR
= EMAC_DEF_ADR
| PhyReg
;
28 LPC_EMAC
->MWTD
= Value
;
30 /* Wait until operation completed */
32 for (tout
= 0; tout
< EMAC_MII_WR_TOUT
; tout
++) {
33 if ((LPC_EMAC
->MIND
& EMAC_MIND_BUSY
) == 0) {
37 printf("write PHY %lu %04X failed!\n", PhyReg
, Value
);
43 /*--------------------------- read_PHY --------------------------------------*/
44 /*********************************************************************//**
45 * @brief Read value from PHY device
46 * @param[in] PhyReg: PHY Register address
47 * @return 0 - if success
49 ***********************************************************************/
50 static int32_t read_PHY (uint32_t PhyReg
)
52 /* Read a PHY register 'PhyReg'. */
55 LPC_EMAC
->MADR
= EMAC_DEF_ADR
| PhyReg
;
56 LPC_EMAC
->MCMD
= EMAC_MCMD_READ
;
58 /* Wait until operation completed */
60 for (tout
= 0; tout
< EMAC_MII_RD_TOUT
; tout
++) {
61 if ((LPC_EMAC
->MIND
& EMAC_MIND_BUSY
) == 0) {
63 return (LPC_EMAC
->MRDD
);
66 printf("read PHY %lu failed!\n", PhyReg
);
71 /*********************************************************************//**
72 * @brief Set Station MAC address for EMAC module
73 * @param[in] abStationAddr Pointer to Station address that contains 6-bytes
74 * of MAC address (should be in order from MAC Address 1 to MAC Address 6)
76 **********************************************************************/
77 static void setEmacAddr(uint8_t abStationAddr
[])
79 /* Set the Ethernet MAC Address registers */
80 LPC_EMAC
->SA0
= ((uint32_t)abStationAddr
[5] << 8) | (uint32_t)abStationAddr
[4];
81 LPC_EMAC
->SA1
= ((uint32_t)abStationAddr
[3] << 8) | (uint32_t)abStationAddr
[2];
82 LPC_EMAC
->SA2
= ((uint32_t)abStationAddr
[1] << 8) | (uint32_t)abStationAddr
[0];
85 /*********************************************************************//**
86 * @brief Set specified PHY mode in EMAC peripheral
87 * @param[in] ulPHYMode Specified PHY mode, should be:
89 * - EMAC_MODE_10M_FULL
90 * - EMAC_MODE_10M_HALF
91 * - EMAC_MODE_100M_FULL
92 * - EMAC_MODE_100M_HALF
93 * @return Return (0) if no error, otherwise return (-1)
94 **********************************************************************/
95 int32_t emac_SetPHYMode(uint32_t ulPHYMode
)
97 int32_t id1
, id2
, tout
, regv
;
99 id1
= read_PHY (EMAC_PHY_REG_IDR1
);
100 id2
= read_PHY (EMAC_PHY_REG_IDR2
);
102 if (((id1
<< 16) | (id2
& 0xFFF0)) == EMAC_SMSC_8720A
) {
105 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_AUTO_NEG
);
106 /* Wait to complete Auto_Negotiation */
107 for (tout
= EMAC_PHY_RESP_TOUT
; tout
; tout
--) {
108 regv
= read_PHY (EMAC_PHY_REG_BMSR
);
109 if (regv
& EMAC_PHY_BMSR_AUTO_DONE
) {
110 /* Auto-negotiation Complete. */
114 // Time out, return error
119 case EMAC_MODE_10M_FULL
:
120 /* Connect at 10MBit full-duplex */
121 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_FULLD_10M
);
123 case EMAC_MODE_10M_HALF
:
124 /* Connect at 10MBit half-duplex */
125 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_HALFD_10M
);
127 case EMAC_MODE_100M_FULL
:
128 /* Connect at 100MBit full-duplex */
129 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_FULLD_100M
);
131 case EMAC_MODE_100M_HALF
:
132 /* Connect at 100MBit half-duplex */
133 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_HALFD_100M
);
140 // It's not correct module ID
142 printf("PHY reports id %04lX %04lX - not an SMSC 8720A\n", id1
, id2
);
146 // Update EMAC configuration with current PHY status
147 if (EMAC_UpdatePHYStatus() < 0){
155 _rxbuf_t
LPC17XX_Ethernet::rxbuf
__attribute__ ((section ("AHBSRAM1")));
156 _txbuf_t
LPC17XX_Ethernet::txbuf
__attribute__ ((section ("AHBSRAM1")));
158 LPC17XX_Ethernet
* LPC17XX_Ethernet::instance
;
160 LPC17XX_Ethernet::LPC17XX_Ethernet()
162 mac_address
[0] = 0xAE;
163 mac_address
[1] = 0xF0;
164 mac_address
[2] = 0x28;
165 mac_address
[3] = 0x5D;
166 mac_address
[4] = 0x66;
167 mac_address
[5] = 0x41;
169 ip_address
= IPA(192,168,1,27);
170 ip_mask
= 0xFFFFFF00;
172 for (int i
= 0; i
< 5; i
++)
174 rxbuf
.rxdesc
[i
].packet
= rxbuf
.buf
[i
];
175 rxbuf
.rxdesc
[i
].control
= (1536 - 1) | EMAC_RCTRL_INT
;
177 rxbuf
.rxstat
[i
].Info
= 0;
178 rxbuf
.rxstat
[i
].HashCRC
= 0;
180 txbuf
.txdesc
[i
].packet
= txbuf
.buf
[i
];
181 txbuf
.txdesc
[i
].control
= (1536 - 1) | EMAC_TCTRL_PAD
| EMAC_TCTRL_CRC
| EMAC_TCTRL_LAST
| EMAC_TCTRL_INT
;
183 txbuf
.txstat
[i
].Info
= 0;
186 interface_name
= (uint8_t*) malloc(5);
187 memcpy(interface_name
, "eth0", 5);
194 void LPC17XX_Ethernet::on_module_loaded()
196 LPC_PINCON
->PINSEL2
= (1 << 0) | (1 << 2) | (1 << 8) | (1 << 16) | (1 << 18) | (1 << 20) | (1 << 28) | (1 << 30);
197 LPC_PINCON
->PINSEL3
&= (2 << 0) | (2 << 2);
198 LPC_PINCON
->PINSEL3
|= (1 << 0) | (1 << 2);
200 printf("EMAC_INIT\n");
204 register_for_event(ON_IDLE
);
205 register_for_event(ON_SECOND_TICK
);
208 void LPC17XX_Ethernet::on_idle(void*)
213 void LPC17XX_Ethernet::on_second_tick(void*)
215 // LPC_EMAC->Command = 0x303;
216 // setEmacAddr(mac_address);
218 st
= read_PHY (EMAC_PHY_REG_BMSR
);
220 if ((st
& EMAC_PHY_BMSR_LINK_ESTABLISHED
) && (st
& EMAC_PHY_BMSR_AUTO_DONE
) && (up
== false))
222 // TODO: link up event
224 // net->set_interface_status(this, up);
225 uint32_t scsr
= read_PHY(EMAC_PHY_REG_SCSR
);
226 printf("%s: link up: ", interface_name
);
227 switch ((scsr
>> 2) & 0x7)
230 printf("10MBit Half Duplex\n");
233 printf("10MBit Full Duplex\n");
236 printf("100MBit Half Duplex\n");
239 printf("100MBit Full Duplex\n");
242 printf("Unknown speed: SCSR = 0x%04lX\n", scsr
);
246 else if (((st
& EMAC_PHY_BMSR_LINK_ESTABLISHED
) == 0) && up
)
248 // TODO: link down event
250 // net->set_interface_status(this, up);
251 printf("%s: link down\n", interface_name
);
254 // printf("PHY: id:%04lX %04lX st:%04lX\n", id1, id2, st);
255 // printf("ETH: Rx:%lu/%lu Tx:%lu/%lu\n", LPC_EMAC->RxConsumeIndex, LPC_EMAC->RxProduceIndex, LPC_EMAC->TxProduceIndex, LPC_EMAC->TxConsumeIndex);
256 // printf("MII: 0x%1lX\n", LPC_EMAC->MIND);
257 // printf("Command: 0x%03lX Status: 0x%1lX\n", LPC_EMAC->Command, LPC_EMAC->Status);
258 // printf("RxN: %lu TxN: %lu\n", LPC_EMAC->RxDescriptorNumber, LPC_EMAC->TxDescriptorNumber);
259 // printf("MAC1: 0x%04lX MAC2: 0x%04lX\n", LPC_EMAC->MAC1, LPC_EMAC->MAC2);
260 // 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);
263 void LPC17XX_Ethernet::emac_init()
265 /* Initialize the EMAC Ethernet controller. */
266 int32_t regv
,tout
, tmp
;
269 /* Set up clock and power for Ethernet module */
270 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET
, ENABLE
);
272 /* Reset all EMAC internal modules */
273 LPC_EMAC
->MAC1
= EMAC_MAC1_RES_TX
| EMAC_MAC1_RES_MCS_TX
| EMAC_MAC1_RES_RX
|
274 EMAC_MAC1_RES_MCS_RX
| EMAC_MAC1_SIM_RES
| EMAC_MAC1_SOFT_RES
;
276 LPC_EMAC
->Command
= EMAC_CR_REG_RES
| EMAC_CR_TX_RES
| EMAC_CR_RX_RES
;
278 /* A short delay after reset. */
279 for (d
= 256; d
; d
--);
281 /* Initialize MAC control registers. */
282 LPC_EMAC
->MAC1
= EMAC_MAC1_PASS_ALL
;
283 LPC_EMAC
->MAC2
= EMAC_MAC2_CRC_EN
| EMAC_MAC2_PAD_EN
| EMAC_MAC2_FULL_DUP
;
284 LPC_EMAC
->MAXF
= EMAC_ETH_MAX_FLEN
;
286 * Find the clock that close to desired target clock
288 tmp
= SystemCoreClock
/ EMAC_MCFG_MII_MAXCLK
;
289 for (tout
= 0; tout
< (int32_t) sizeof (EMAC_clkdiv
); tout
++){
290 if (EMAC_clkdiv
[tout
] >= tmp
) break;
293 // Write to MAC configuration register and reset
294 LPC_EMAC
->MCFG
= EMAC_MCFG_CLK_SEL(tout
) | EMAC_MCFG_RES_MII
;
296 LPC_EMAC
->MCFG
&= ~(EMAC_MCFG_RES_MII
);
297 LPC_EMAC
->CLRT
= EMAC_CLRT_DEF
;
298 LPC_EMAC
->IPGR
= EMAC_IPGR_P2_DEF
;
300 /* Enable Reduced MII interface. */
301 LPC_EMAC
->Command
= EMAC_CR_RMII
;
303 /* Reset Reduced MII Logic. */
304 LPC_EMAC
->SUPP
= EMAC_SUPP_RES_RMII
;
306 for (d
= 256; d
; d
--);
307 LPC_EMAC
->SUPP
= EMAC_SUPP_SPEED
;
309 /* Put the DP83848C in reset mode */
310 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_BMCR_RESET
);
312 /* Wait for hardware reset to end. */
313 for (tout
= EMAC_PHY_RESP_TOUT
; tout
; tout
--) {
314 regv
= read_PHY (EMAC_PHY_REG_BMCR
);
315 if (!(regv
& (EMAC_PHY_BMCR_RESET
| EMAC_PHY_BMCR_POWERDOWN
))) {
316 /* Reset complete, device not Power Down. */
320 // Time out, return ERROR
321 printf("ETH: PHY TIMEOUT\n");
327 // if (emac_SetPHYMode(EMAC_MODE_AUTO) < 0){
328 // printf("ETH: Error Setting Mode\n");
331 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_AUTO_NEG
);
334 setEmacAddr(mac_address
);
336 /* Initialize Tx and Rx DMA Descriptors */
337 LPC_EMAC
->RxDescriptor
= (uint32_t) rxbuf
.rxdesc
;
338 LPC_EMAC
->RxStatus
= (uint32_t) rxbuf
.rxstat
;
339 LPC_EMAC
->RxDescriptorNumber
= 4;
341 LPC_EMAC
->TxDescriptor
= (uint32_t) txbuf
.txdesc
;
342 LPC_EMAC
->TxStatus
= (uint32_t) txbuf
.txstat
;
343 LPC_EMAC
->TxDescriptorNumber
= 4;
345 // Set Receive Filter register: enable broadcast and multicast
346 LPC_EMAC
->RxFilterCtrl
= EMAC_RFC_BCAST_EN
| EMAC_RFC_PERFECT_EN
;
348 /* Enable Rx Done and Tx Done interrupt for EMAC */
349 LPC_EMAC
->IntEnable
= EMAC_INT_RX_DONE
| EMAC_INT_TX_DONE
;
351 /* Reset all interrupts */
352 LPC_EMAC
->IntClear
= 0xFFFF;
354 /* Enable receive and transmit mode of MAC Ethernet core */
355 LPC_EMAC
->Command
= EMAC_CR_RX_EN
| EMAC_CR_TX_EN
| EMAC_CR_RMII
| EMAC_CR_FULL_DUP
| EMAC_CR_PASS_RUNT_FRM
;
356 LPC_EMAC
->MAC1
|= EMAC_MAC1_REC_EN
;
358 printf("ETH:EMAC INITIALISED\n");
361 void LPC17XX_Ethernet::set_mac(uint8_t* newmac
)
363 memcpy(mac_address
, newmac
, 6);
366 void LPC17XX_Ethernet::_receive_frame()
368 if (can_read_packet() && can_write_packet())
370 int i
= LPC_EMAC
->RxConsumeIndex
;
371 RX_Stat
* stat
= &(rxbuf
.rxstat
[i
]);
372 NET_PACKET packet
= (NET_PACKET
) rxbuf
.buf
[i
];
374 int size
= stat
->Info
& EMAC_RINFO_SIZE
;
375 printf("Received %d byte Ethernet frame %lu/%lu\n", size
, LPC_EMAC
->RxProduceIndex
, LPC_EMAC
->RxConsumeIndex
);
377 // TODO: feed received packet to network stack here
378 // int s = net->receive_packet(this, packet, size);
381 // memcpy(request_packet_buffer(), packet, s);
382 // write_packet((uint8_t*) request_packet_buffer(), s);
385 uint32_t r
= LPC_EMAC
->RxConsumeIndex
+ 1;
386 if (r
> LPC_EMAC
->RxDescriptorNumber
)
388 LPC_EMAC
->RxConsumeIndex
= r
;
392 void LPC17XX_Ethernet::irq()
394 if (EMAC_IntGetStatus(EMAC_INT_RX_DONE
))
399 if (EMAC_IntGetStatus(EMAC_INT_TX_DONE
))
404 bool LPC17XX_Ethernet::can_read_packet()
406 return (LPC_EMAC
->RxProduceIndex
!= LPC_EMAC
->RxConsumeIndex
);
409 int LPC17XX_Ethernet::read_packet(uint8_t** buf
)
411 *buf
= rxbuf
.buf
[LPC_EMAC
->RxConsumeIndex
];
412 return rxbuf
.rxstat
[LPC_EMAC
->RxConsumeIndex
].Info
& EMAC_RINFO_SIZE
;
415 void LPC17XX_Ethernet::release_read_packet(uint8_t*)
417 uint32_t r
= LPC_EMAC
->RxConsumeIndex
+ 1;
418 if (r
> LPC_EMAC
->RxDescriptorNumber
)
420 LPC_EMAC
->RxConsumeIndex
= r
;
423 bool LPC17XX_Ethernet::can_write_packet()
425 uint32_t r
= LPC_EMAC
->TxProduceIndex
+ 1;
426 if (r
> LPC_EMAC
->TxDescriptorNumber
)
428 return (r
!= LPC_EMAC
->TxConsumeIndex
);
431 int LPC17XX_Ethernet::write_packet(uint8_t* buf
, int size
)
433 txbuf
.txdesc
[LPC_EMAC
->TxProduceIndex
].control
= size
| EMAC_TCTRL_LAST
| EMAC_TCTRL_CRC
| EMAC_TCTRL_PAD
| EMAC_TCTRL_INT
;
435 uint32_t r
= LPC_EMAC
->TxProduceIndex
+ 1;
436 if (r
> LPC_EMAC
->TxDescriptorNumber
)
439 if (r
== LPC_EMAC
->TxConsumeIndex
)
442 LPC_EMAC
->TxProduceIndex
= r
;
447 void* LPC17XX_Ethernet::request_packet_buffer()
449 return txbuf
.txdesc
[LPC_EMAC
->TxProduceIndex
].packet
;
452 NET_PACKET
LPC17XX_Ethernet::get_new_packet_buffer(NetworkInterface
* ni
)
457 return (NET_PACKET
) request_packet_buffer();
460 NET_PAYLOAD
LPC17XX_Ethernet::get_payload_buffer(NET_PACKET packet
)
462 return (NET_PAYLOAD
) packet
;
465 void LPC17XX_Ethernet::set_payload_length(NET_PACKET packet
, int length
)
467 uint32_t offset
= ((uint8_t*) packet
) - txbuf
.buf
[0];
468 int i
= (offset
/ LPC17XX_MAX_PACKET
);
469 if ((i
< LPC17XX_TXBUFS
) && ((offset
% LPC17XX_MAX_PACKET
) == 0))
471 txbuf
.txdesc
[i
].control
= (txbuf
.txdesc
[i
].control
& ~EMAC_TCTRL_SIZE
) | (length
& EMAC_TCTRL_SIZE
);
475 int LPC17XX_Ethernet::receive(NetworkInterface
* ni
, NET_PACKET packet
, int length
)
477 if (can_write_packet())
478 return write_packet((uint8_t*) packet
, length
);
482 int LPC17XX_Ethernet::construct(NetworkInterface
* ni
, NET_PACKET packet
, int length
)
488 void ENET_IRQHandler()
490 LPC17XX_Ethernet::instance
->irq();
494 // void LPC17XX_Ethernet::provide_net(netcore* n)
496 // NetworkInterface::provide_net(n);
498 // n->set_interface_status(this, up);