2 #include "LPC17XX_Ethernet.h"
9 #include "lpc17xx_clkpwr.h"
13 // #include "netcore.h"
15 #define DEBUG_PRINTF printf
17 static const uint8_t EMAC_clkdiv
[] = { 4, 6, 8, 10, 14, 20, 28 };
19 /*--------------------------- write_PHY -------------------------------------*/
20 /*********************************************************************//**
21 * @brief Write value to PHY device
22 * @param[in] PhyReg: PHY Register address
23 * @param[in] Value: Value to write
24 * @return 0 - if success
26 ***********************************************************************/
27 static int32_t write_PHY (uint32_t PhyReg
, uint16_t Value
)
29 /* Write a data 'Value' to PHY register 'PhyReg'. */
32 LPC_EMAC
->MADR
= EMAC_DEF_ADR
| PhyReg
;
33 LPC_EMAC
->MWTD
= Value
;
35 /* Wait until operation completed */
37 for (tout
= 0; tout
< EMAC_MII_WR_TOUT
; tout
++) {
38 if ((LPC_EMAC
->MIND
& EMAC_MIND_BUSY
) == 0) {
42 DEBUG_PRINTF("write PHY %lu %04X failed!\n", PhyReg
, Value
);
48 /*--------------------------- read_PHY --------------------------------------*/
49 /*********************************************************************//**
50 * @brief Read value from PHY device
51 * @param[in] PhyReg: PHY Register address
52 * @return 0 - if success
54 ***********************************************************************/
55 static int32_t read_PHY (uint32_t PhyReg
)
57 /* Read a PHY register 'PhyReg'. */
60 LPC_EMAC
->MADR
= EMAC_DEF_ADR
| PhyReg
;
61 LPC_EMAC
->MCMD
= EMAC_MCMD_READ
;
63 /* Wait until operation completed */
65 for (tout
= 0; tout
< EMAC_MII_RD_TOUT
; tout
++) {
66 if ((LPC_EMAC
->MIND
& EMAC_MIND_BUSY
) == 0) {
68 return (LPC_EMAC
->MRDD
);
71 DEBUG_PRINTF("read PHY %lu failed!\n", PhyReg
);
76 /*********************************************************************//**
77 * @brief Set Station MAC address for EMAC module
78 * @param[in] abStationAddr Pointer to Station address that contains 6-bytes
79 * of MAC address (should be in order from MAC Address 1 to MAC Address 6)
81 **********************************************************************/
82 static void setEmacAddr(uint8_t abStationAddr
[])
84 /* Set the Ethernet MAC Address registers */
85 LPC_EMAC
->SA0
= ((uint32_t)abStationAddr
[5] << 8) | (uint32_t)abStationAddr
[4];
86 LPC_EMAC
->SA1
= ((uint32_t)abStationAddr
[3] << 8) | (uint32_t)abStationAddr
[2];
87 LPC_EMAC
->SA2
= ((uint32_t)abStationAddr
[1] << 8) | (uint32_t)abStationAddr
[0];
90 /*********************************************************************//**
91 * @brief Set specified PHY mode in EMAC peripheral
92 * @param[in] ulPHYMode Specified PHY mode, should be:
94 * - EMAC_MODE_10M_FULL
95 * - EMAC_MODE_10M_HALF
96 * - EMAC_MODE_100M_FULL
97 * - EMAC_MODE_100M_HALF
98 * @return Return (0) if no error, otherwise return (-1)
99 **********************************************************************/
100 int32_t emac_SetPHYMode(uint32_t ulPHYMode
)
102 int32_t id1
, id2
, tout
, regv
;
104 id1
= read_PHY (EMAC_PHY_REG_IDR1
);
105 id2
= read_PHY (EMAC_PHY_REG_IDR2
);
107 if (((id1
<< 16) | (id2
& 0xFFF0)) == EMAC_SMSC_8720A
) {
110 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_AUTO_NEG
);
111 /* Wait to complete Auto_Negotiation */
112 for (tout
= EMAC_PHY_RESP_TOUT
; tout
; tout
--) {
113 regv
= read_PHY (EMAC_PHY_REG_BMSR
);
114 if (regv
& EMAC_PHY_BMSR_AUTO_DONE
) {
115 /* Auto-negotiation Complete. */
119 // Time out, return error
124 case EMAC_MODE_10M_FULL
:
125 /* Connect at 10MBit full-duplex */
126 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_FULLD_10M
);
128 case EMAC_MODE_10M_HALF
:
129 /* Connect at 10MBit half-duplex */
130 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_HALFD_10M
);
132 case EMAC_MODE_100M_FULL
:
133 /* Connect at 100MBit full-duplex */
134 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_FULLD_100M
);
136 case EMAC_MODE_100M_HALF
:
137 /* Connect at 100MBit half-duplex */
138 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_HALFD_100M
);
145 // It's not correct module ID
147 DEBUG_PRINTF("PHY reports id %04lX %04lX - not an SMSC 8720A\n", id1
, id2
);
151 // Update EMAC configuration with current PHY status
152 if (EMAC_UpdatePHYStatus() < 0){
160 _rxbuf_t
LPC17XX_Ethernet::rxbuf
__attribute__ ((section ("AHBSRAM1"))) __attribute__((aligned(8)));
161 _txbuf_t
LPC17XX_Ethernet::txbuf
__attribute__ ((section ("AHBSRAM1"))) __attribute__((aligned(8)));
163 LPC17XX_Ethernet
* LPC17XX_Ethernet::instance
;
165 LPC17XX_Ethernet::LPC17XX_Ethernet()
167 // TODO these need to be configurable
168 // mac_address[0] = 0xAE;
169 // mac_address[1] = 0xF0;
170 // mac_address[2] = 0x28;
171 // mac_address[3] = 0x5D;
172 // mac_address[4] = 0x66;
173 // mac_address[5] = 0x41;
175 // ip_address = IPA(192,168,3,222);
176 // ip_mask = 0xFFFFFF00;
178 for (int i
= 0; i
< LPC17XX_RXBUFS
; i
++) {
179 rxbuf
.rxdesc
[i
].packet
= rxbuf
.buf
[i
];
180 rxbuf
.rxdesc
[i
].control
= (LPC17XX_MAX_PACKET
- 1) | EMAC_RCTRL_INT
;
182 rxbuf
.rxstat
[i
].Info
= 0;
183 rxbuf
.rxstat
[i
].HashCRC
= 0;
186 for (int i
= 0; i
< LPC17XX_TXBUFS
; i
++) {
187 txbuf
.txdesc
[i
].packet
= txbuf
.buf
[i
];
188 txbuf
.txdesc
[i
].control
= (LPC17XX_MAX_PACKET
- 1) | EMAC_TCTRL_PAD
| EMAC_TCTRL_CRC
| EMAC_TCTRL_LAST
| EMAC_TCTRL_INT
;
190 txbuf
.txstat
[i
].Info
= 0;
193 interface_name
= (uint8_t*) malloc(5);
194 memcpy(interface_name
, "eth0", 5);
201 void LPC17XX_Ethernet::on_module_loaded()
203 LPC_PINCON
->PINSEL2
|= (1 << 0) | (1 << 2) | (1 << 8) | (1 << 16) | (1 << 18) | (1 << 20) | (1 << 28) | (1 << 30);
204 LPC_PINCON
->PINSEL2
&= ~((1 << 1) | (1 << 3) | (1 << 9) | (1 << 17) | (1 << 19) | (1 << 21) | (1 << 29) | (1 << 31));
205 LPC_PINCON
->PINSEL3
|= (1 << 0) | (1 << 2);
206 LPC_PINCON
->PINSEL3
&= ~((1 << 1) | (1 << 3));
208 DEBUG_PRINTF("EMAC_INIT\n");
210 DEBUG_PRINTF("INIT OK\n");
212 //register_for_event(ON_IDLE);
213 register_for_event(ON_SECOND_TICK
);
216 void LPC17XX_Ethernet::on_idle(void*)
221 void LPC17XX_Ethernet::on_second_tick(void *) {
225 void LPC17XX_Ethernet::check_interface()
227 // LPC_EMAC->Command = 0x303;
228 // setEmacAddr(mac_address);
231 st
= read_PHY (EMAC_PHY_REG_BMSR
);
233 if ((st
& EMAC_PHY_BMSR_LINK_ESTABLISHED
) && (st
& EMAC_PHY_BMSR_AUTO_DONE
) && (up
== false))
235 // TODO: link up event
237 // net->set_interface_status(this, up);
238 uint32_t scsr
= read_PHY(EMAC_PHY_REG_SCSR
);
239 DEBUG_PRINTF("%s: link up: ", interface_name
);
240 switch ((scsr
>> 2) & 0x7)
243 DEBUG_PRINTF("10MBit Half Duplex\n");
246 DEBUG_PRINTF("10MBit Full Duplex\n");
249 DEBUG_PRINTF("100MBit Half Duplex\n");
252 DEBUG_PRINTF("100MBit Full Duplex\n");
255 DEBUG_PRINTF("Unknown speed: SCSR = 0x%04lX\n", scsr
);
258 DEBUG_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);
260 else if (((st
& EMAC_PHY_BMSR_LINK_ESTABLISHED
) == 0) && up
)
262 // TODO: link down event
264 // net->set_interface_status(this, up);
265 DEBUG_PRINTF("%s: link down\n", interface_name
);
268 //DEBUG_PRINTF("PHY: id:%04lX %04lX st:%04lX\n", id1, id2, st);
269 // DEBUG_PRINTF("ETH: Rx:%lu/%lu Tx:%lu/%lu\n", LPC_EMAC->RxConsumeIndex, LPC_EMAC->RxProduceIndex, LPC_EMAC->TxProduceIndex, LPC_EMAC->TxConsumeIndex);
270 // DEBUG_PRINTF("MII: 0x%1lX\n", LPC_EMAC->MIND);
271 // DEBUG_PRINTF("Command: 0x%03lX Status: 0x%1lX\n", LPC_EMAC->Command, LPC_EMAC->Status);
272 // DEBUG_PRINTF("RxN: %lu TxN: %lu\n", LPC_EMAC->RxDescriptorNumber, LPC_EMAC->TxDescriptorNumber);
273 // DEBUG_PRINTF("MAC1: 0x%04lX MAC2: 0x%04lX\n", LPC_EMAC->MAC1, LPC_EMAC->MAC2);
274 // DEBUG_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);
277 void LPC17XX_Ethernet::emac_init()
279 /* Initialize the EMAC Ethernet controller. */
280 int32_t regv
,tout
, tmp
;
283 /* Set up clock and power for Ethernet module */
284 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET
, ENABLE
);
286 /* Reset all EMAC internal modules */
287 LPC_EMAC
->MAC1
= EMAC_MAC1_RES_TX
| EMAC_MAC1_RES_MCS_TX
| EMAC_MAC1_RES_RX
|
288 EMAC_MAC1_RES_MCS_RX
| EMAC_MAC1_SIM_RES
| EMAC_MAC1_SOFT_RES
;
290 LPC_EMAC
->Command
= EMAC_CR_REG_RES
| EMAC_CR_TX_RES
| EMAC_CR_RX_RES
;
292 /* A short delay after reset. */
293 for (d
= 256; d
; d
--);
295 /* Initialize MAC control registers. */
296 LPC_EMAC
->MAC1
= EMAC_MAC1_PASS_ALL
;
297 LPC_EMAC
->MAC2
= EMAC_MAC2_CRC_EN
| EMAC_MAC2_PAD_EN
| EMAC_MAC2_FULL_DUP
;
298 LPC_EMAC
->MAXF
= EMAC_ETH_MAX_FLEN
;
300 * Find the clock that close to desired target clock
302 tmp
= SystemCoreClock
/ EMAC_MCFG_MII_MAXCLK
;
303 for (tout
= 0; tout
< (int32_t) sizeof (EMAC_clkdiv
); tout
++){
304 if (EMAC_clkdiv
[tout
] >= tmp
) break;
307 // Write to MAC configuration register and reset
308 LPC_EMAC
->MCFG
= EMAC_MCFG_CLK_SEL(tout
) | EMAC_MCFG_RES_MII
;
310 LPC_EMAC
->MCFG
&= ~(EMAC_MCFG_RES_MII
);
311 LPC_EMAC
->CLRT
= EMAC_CLRT_DEF
;
312 LPC_EMAC
->IPGR
= EMAC_IPGR_P2_DEF
;
314 /* Enable Reduced MII interface. */
315 LPC_EMAC
->Command
= EMAC_CR_RMII
;
317 /* Reset Reduced MII Logic. */
318 LPC_EMAC
->SUPP
= EMAC_SUPP_RES_RMII
;
320 for (d
= 256; d
; d
--);
321 LPC_EMAC
->SUPP
= EMAC_SUPP_SPEED
;
323 /* Put the DP83848C in reset mode */
324 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_BMCR_RESET
);
326 /* Wait for hardware reset to end. */
327 for (tout
= EMAC_PHY_RESP_TOUT
; tout
; tout
--) {
328 regv
= read_PHY (EMAC_PHY_REG_BMCR
);
329 if (!(regv
& (EMAC_PHY_BMCR_RESET
| EMAC_PHY_BMCR_POWERDOWN
))) {
330 /* Reset complete, device not Power Down. */
334 // Time out, return ERROR
335 DEBUG_PRINTF("ETH: PHY TIMEOUT\n");
341 // if (emac_SetPHYMode(EMAC_MODE_AUTO) < 0){
342 // DEBUG_PRINTF("ETH: Error Setting Mode\n");
345 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_AUTO_NEG
);
348 setEmacAddr(mac_address
);
350 /* Initialize Tx and Rx DMA Descriptors */
351 LPC_EMAC
->RxDescriptor
= (uint32_t) rxbuf
.rxdesc
;
352 LPC_EMAC
->RxStatus
= (uint32_t) rxbuf
.rxstat
;
353 LPC_EMAC
->RxDescriptorNumber
= LPC17XX_RXBUFS
-1;
355 LPC_EMAC
->TxDescriptor
= (uint32_t) txbuf
.txdesc
;
356 LPC_EMAC
->TxStatus
= (uint32_t) txbuf
.txstat
;
357 LPC_EMAC
->TxDescriptorNumber
= LPC17XX_TXBUFS
-1;
359 // Set Receive Filter register: enable broadcast and multicast
360 LPC_EMAC
->RxFilterCtrl
= EMAC_RFC_BCAST_EN
| EMAC_RFC_PERFECT_EN
;
362 /* Enable Rx Done and Tx Done interrupt for EMAC */
363 LPC_EMAC
->IntEnable
= EMAC_INT_RX_DONE
| EMAC_INT_TX_DONE
;
365 /* Reset all interrupts */
366 LPC_EMAC
->IntClear
= 0xFFFF;
368 /* Enable receive and transmit mode of MAC Ethernet core */
369 LPC_EMAC
->Command
= EMAC_CR_RX_EN
| EMAC_CR_TX_EN
| EMAC_CR_RMII
| EMAC_CR_FULL_DUP
| EMAC_CR_PASS_RUNT_FRM
;
370 LPC_EMAC
->MAC1
|= EMAC_MAC1_REC_EN
;
372 DEBUG_PRINTF("ETH:EMAC INITIALISED\n");
375 void LPC17XX_Ethernet::set_mac(uint8_t* newmac
)
377 memcpy(mac_address
, newmac
, 6);
380 // size must be preloaded with max size of packet buffer
381 bool LPC17XX_Ethernet::_receive_frame(void *packet
, int *size
)
383 if (can_read_packet() && can_write_packet())
385 int i
= LPC_EMAC
->RxConsumeIndex
;
386 RX_Stat
* stat
= &(rxbuf
.rxstat
[i
]);
387 int len
= (stat
->Info
& EMAC_RINFO_SIZE
) + 1; //this is the index so add one to get the size
388 if(len
<= *size
) { // check against recieving buffer length
389 memcpy(packet
, rxbuf
.buf
[i
], len
);
392 // discard frame that is too big for input buffer
393 DEBUG_PRINTF("WARNING: Discarded ethernet frame that is too big: %08lX, %d - %d\n", stat
->Info
, len
, *size
);
397 //DEBUG_PRINTF("Received %d byte Ethernet frame %lu/%lu\n", *size, LPC_EMAC->RxProduceIndex, LPC_EMAC->RxConsumeIndex);
399 uint32_t r
= LPC_EMAC
->RxConsumeIndex
+ 1;
400 if (r
> LPC_EMAC
->RxDescriptorNumber
)
402 LPC_EMAC
->RxConsumeIndex
= r
;
410 void LPC17XX_Ethernet::irq()
412 // if (EMAC_IntGetStatus(EMAC_INT_RX_DONE))
414 // //_receive_frame();
417 // if (EMAC_IntGetStatus(EMAC_INT_TX_DONE))
422 bool LPC17XX_Ethernet::can_read_packet()
424 return (LPC_EMAC
->RxProduceIndex
!= LPC_EMAC
->RxConsumeIndex
);
427 int LPC17XX_Ethernet::read_packet(uint8_t** buf
)
429 *buf
= rxbuf
.buf
[LPC_EMAC
->RxConsumeIndex
];
430 return rxbuf
.rxstat
[LPC_EMAC
->RxConsumeIndex
].Info
& EMAC_RINFO_SIZE
;
433 void LPC17XX_Ethernet::release_read_packet(uint8_t*)
435 uint32_t r
= LPC_EMAC
->RxConsumeIndex
+ 1;
436 if (r
> LPC_EMAC
->RxDescriptorNumber
)
438 LPC_EMAC
->RxConsumeIndex
= r
;
441 bool LPC17XX_Ethernet::can_write_packet()
443 uint32_t r
= LPC_EMAC
->TxProduceIndex
+ 1;
444 if (r
> LPC_EMAC
->TxDescriptorNumber
)
446 return (r
!= LPC_EMAC
->TxConsumeIndex
);
449 int LPC17XX_Ethernet::write_packet(uint8_t* buf
, int size
)
451 txbuf
.txdesc
[LPC_EMAC
->TxProduceIndex
].control
= ((size
- 1) & 0x7ff) | EMAC_TCTRL_LAST
| EMAC_TCTRL_CRC
| EMAC_TCTRL_PAD
| EMAC_TCTRL_INT
;
453 uint32_t r
= LPC_EMAC
->TxProduceIndex
+ 1;
454 if (r
> LPC_EMAC
->TxDescriptorNumber
)
457 if (r
== LPC_EMAC
->TxConsumeIndex
)
460 LPC_EMAC
->TxProduceIndex
= r
;
465 void* LPC17XX_Ethernet::request_packet_buffer()
467 return txbuf
.txdesc
[LPC_EMAC
->TxProduceIndex
].packet
;
470 NET_PACKET
LPC17XX_Ethernet::get_new_packet_buffer(NetworkInterface
* ni
)
475 return (NET_PACKET
) request_packet_buffer();
478 NET_PAYLOAD
LPC17XX_Ethernet::get_payload_buffer(NET_PACKET packet
)
480 return (NET_PAYLOAD
) packet
;
483 void LPC17XX_Ethernet::set_payload_length(NET_PACKET packet
, int length
)
485 uint32_t offset
= ((uint8_t*) packet
) - txbuf
.buf
[0];
486 int i
= (offset
/ LPC17XX_MAX_PACKET
);
487 if ((i
< LPC17XX_TXBUFS
) && ((offset
% LPC17XX_MAX_PACKET
) == 0))
489 txbuf
.txdesc
[i
].control
= (txbuf
.txdesc
[i
].control
& ~EMAC_TCTRL_SIZE
) | (length
& EMAC_TCTRL_SIZE
);
493 int LPC17XX_Ethernet::receive(NetworkInterface
* ni
, NET_PACKET packet
, int length
)
495 if (can_write_packet())
496 return write_packet((uint8_t*) packet
, length
);
500 int LPC17XX_Ethernet::construct(NetworkInterface
* ni
, NET_PACKET packet
, int length
)
506 void ENET_IRQHandler()
508 LPC17XX_Ethernet::instance
->irq();
512 // void LPC17XX_Ethernet::provide_net(netcore* n)
514 // NetworkInterface::provide_net(n);
516 // n->set_interface_status(this, up);