2 #include "LPC17XX_Ethernet.h"
9 #include "lpc17xx_clkpwr.h"
13 // #include "netcore.h"
15 static const uint8_t EMAC_clkdiv
[] = { 4, 6, 8, 10, 14, 20, 28 };
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
24 ***********************************************************************/
25 static int32_t write_PHY (uint32_t PhyReg
, uint16_t Value
)
27 /* Write a data 'Value' to PHY register 'PhyReg'. */
30 LPC_EMAC
->MADR
= EMAC_DEF_ADR
| PhyReg
;
31 LPC_EMAC
->MWTD
= Value
;
33 /* Wait until operation completed */
35 for (tout
= 0; tout
< EMAC_MII_WR_TOUT
; tout
++) {
36 if ((LPC_EMAC
->MIND
& EMAC_MIND_BUSY
) == 0) {
40 printf("write PHY %lu %04X failed!\n", PhyReg
, Value
);
46 /*--------------------------- read_PHY --------------------------------------*/
47 /*********************************************************************//**
48 * @brief Read value from PHY device
49 * @param[in] PhyReg: PHY Register address
50 * @return 0 - if success
52 ***********************************************************************/
53 static int32_t read_PHY (uint32_t PhyReg
)
55 /* Read a PHY register 'PhyReg'. */
58 LPC_EMAC
->MADR
= EMAC_DEF_ADR
| PhyReg
;
59 LPC_EMAC
->MCMD
= EMAC_MCMD_READ
;
61 /* Wait until operation completed */
63 for (tout
= 0; tout
< EMAC_MII_RD_TOUT
; tout
++) {
64 if ((LPC_EMAC
->MIND
& EMAC_MIND_BUSY
) == 0) {
66 return (LPC_EMAC
->MRDD
);
69 printf("read PHY %lu failed!\n", PhyReg
);
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)
79 **********************************************************************/
80 static void setEmacAddr(uint8_t abStationAddr
[])
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];
88 /*********************************************************************//**
89 * @brief Set specified PHY mode in EMAC peripheral
90 * @param[in] ulPHYMode Specified PHY mode, should be:
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
)
100 int32_t id1
, id2
, tout
, regv
;
102 id1
= read_PHY (EMAC_PHY_REG_IDR1
);
103 id2
= read_PHY (EMAC_PHY_REG_IDR2
);
105 if (((id1
<< 16) | (id2
& 0xFFF0)) == EMAC_SMSC_8720A
) {
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. */
117 // Time out, return error
122 case EMAC_MODE_10M_FULL
:
123 /* Connect at 10MBit full-duplex */
124 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_FULLD_10M
);
126 case EMAC_MODE_10M_HALF
:
127 /* Connect at 10MBit half-duplex */
128 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_HALFD_10M
);
130 case EMAC_MODE_100M_FULL
:
131 /* Connect at 100MBit full-duplex */
132 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_FULLD_100M
);
134 case EMAC_MODE_100M_HALF
:
135 /* Connect at 100MBit half-duplex */
136 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_HALFD_100M
);
143 // It's not correct module ID
145 printf("PHY reports id %04lX %04lX - not an SMSC 8720A\n", id1
, id2
);
149 // Update EMAC configuration with current PHY status
150 if (EMAC_UpdatePHYStatus() < 0){
158 _rxbuf_t
LPC17XX_Ethernet::rxbuf
__attribute__ ((section ("AHBSRAM1"))) __attribute__((aligned(8)));
159 _txbuf_t
LPC17XX_Ethernet::txbuf
__attribute__ ((section ("AHBSRAM1"))) __attribute__((aligned(8)));
161 LPC17XX_Ethernet
* LPC17XX_Ethernet::instance
;
163 LPC17XX_Ethernet::LPC17XX_Ethernet()
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;
173 // ip_address = IPA(192,168,3,222);
174 // ip_mask = 0xFFFFFF00;
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
;
180 rxbuf
.rxstat
[i
].Info
= 0;
181 rxbuf
.rxstat
[i
].HashCRC
= 0;
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
;
188 txbuf
.txstat
[i
].Info
= 0;
191 interface_name
= (uint8_t*) malloc(5);
192 memcpy(interface_name
, "eth0", 5);
199 void LPC17XX_Ethernet::on_module_loaded()
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);
205 printf("EMAC_INIT\n");
209 //register_for_event(ON_IDLE);
210 register_for_event(ON_SECOND_TICK
);
213 void LPC17XX_Ethernet::on_idle(void*)
218 void LPC17XX_Ethernet::on_second_tick(void *) {
222 void LPC17XX_Ethernet::check_interface()
224 // LPC_EMAC->Command = 0x303;
225 // setEmacAddr(mac_address);
228 st
= read_PHY (EMAC_PHY_REG_BMSR
);
230 if ((st
& EMAC_PHY_BMSR_LINK_ESTABLISHED
) && (st
& EMAC_PHY_BMSR_AUTO_DONE
) && (up
== false))
232 // TODO: link up event
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)
240 printf("10MBit Half Duplex\n");
243 printf("10MBit Full Duplex\n");
246 printf("100MBit Half Duplex\n");
249 printf("100MBit Full Duplex\n");
252 printf("Unknown speed: SCSR = 0x%04lX\n", scsr
);
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);
257 else if (((st
& EMAC_PHY_BMSR_LINK_ESTABLISHED
) == 0) && up
)
259 // TODO: link down event
261 // net->set_interface_status(this, up);
262 printf("%s: link down\n", interface_name
);
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);
274 void LPC17XX_Ethernet::emac_init()
276 /* Initialize the EMAC Ethernet controller. */
277 int32_t regv
,tout
, tmp
;
280 /* Set up clock and power for Ethernet module */
281 CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET
, ENABLE
);
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
;
287 LPC_EMAC
->Command
= EMAC_CR_REG_RES
| EMAC_CR_TX_RES
| EMAC_CR_RX_RES
;
289 /* A short delay after reset. */
290 for (d
= 256; d
; d
--);
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
;
297 * Find the clock that close to desired target clock
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;
304 // Write to MAC configuration register and reset
305 LPC_EMAC
->MCFG
= EMAC_MCFG_CLK_SEL(tout
) | EMAC_MCFG_RES_MII
;
307 LPC_EMAC
->MCFG
&= ~(EMAC_MCFG_RES_MII
);
308 LPC_EMAC
->CLRT
= EMAC_CLRT_DEF
;
309 LPC_EMAC
->IPGR
= EMAC_IPGR_P2_DEF
;
311 /* Enable Reduced MII interface. */
312 LPC_EMAC
->Command
= EMAC_CR_RMII
;
314 /* Reset Reduced MII Logic. */
315 LPC_EMAC
->SUPP
= EMAC_SUPP_RES_RMII
;
317 for (d
= 256; d
; d
--);
318 LPC_EMAC
->SUPP
= EMAC_SUPP_SPEED
;
320 /* Put the DP83848C in reset mode */
321 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_BMCR_RESET
);
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. */
331 // Time out, return ERROR
332 printf("ETH: PHY TIMEOUT\n");
338 // if (emac_SetPHYMode(EMAC_MODE_AUTO) < 0){
339 // printf("ETH: Error Setting Mode\n");
342 write_PHY (EMAC_PHY_REG_BMCR
, EMAC_PHY_AUTO_NEG
);
345 setEmacAddr(mac_address
);
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;
352 LPC_EMAC
->TxDescriptor
= (uint32_t) txbuf
.txdesc
;
353 LPC_EMAC
->TxStatus
= (uint32_t) txbuf
.txstat
;
354 LPC_EMAC
->TxDescriptorNumber
= LPC17XX_TXBUFS
-1;
356 // Set Receive Filter register: enable broadcast and multicast
357 LPC_EMAC
->RxFilterCtrl
= EMAC_RFC_BCAST_EN
| EMAC_RFC_PERFECT_EN
;
359 /* Enable Rx Done and Tx Done interrupt for EMAC */
360 LPC_EMAC
->IntEnable
= EMAC_INT_RX_DONE
| EMAC_INT_TX_DONE
;
362 /* Reset all interrupts */
363 LPC_EMAC
->IntClear
= 0xFFFF;
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
;
369 printf("ETH:EMAC INITIALISED\n");
372 void LPC17XX_Ethernet::set_mac(uint8_t* newmac
)
374 memcpy(mac_address
, newmac
, 6);
377 bool LPC17XX_Ethernet::_receive_frame(void *packet
, int *size
)
379 if (can_read_packet() && can_write_packet())
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
);
386 //printf("Received %d byte Ethernet frame %lu/%lu\n", *size, LPC_EMAC->RxProduceIndex, LPC_EMAC->RxConsumeIndex);
388 uint32_t r
= LPC_EMAC
->RxConsumeIndex
+ 1;
389 if (r
> LPC_EMAC
->RxDescriptorNumber
)
391 LPC_EMAC
->RxConsumeIndex
= r
;
399 void LPC17XX_Ethernet::irq()
401 // if (EMAC_IntGetStatus(EMAC_INT_RX_DONE))
403 // //_receive_frame();
406 // if (EMAC_IntGetStatus(EMAC_INT_TX_DONE))
411 bool LPC17XX_Ethernet::can_read_packet()
413 return (LPC_EMAC
->RxProduceIndex
!= LPC_EMAC
->RxConsumeIndex
);
416 int LPC17XX_Ethernet::read_packet(uint8_t** buf
)
418 *buf
= rxbuf
.buf
[LPC_EMAC
->RxConsumeIndex
];
419 return rxbuf
.rxstat
[LPC_EMAC
->RxConsumeIndex
].Info
& EMAC_RINFO_SIZE
;
422 void LPC17XX_Ethernet::release_read_packet(uint8_t*)
424 uint32_t r
= LPC_EMAC
->RxConsumeIndex
+ 1;
425 if (r
> LPC_EMAC
->RxDescriptorNumber
)
427 LPC_EMAC
->RxConsumeIndex
= r
;
430 bool LPC17XX_Ethernet::can_write_packet()
432 uint32_t r
= LPC_EMAC
->TxProduceIndex
+ 1;
433 if (r
> LPC_EMAC
->TxDescriptorNumber
)
435 return (r
!= LPC_EMAC
->TxConsumeIndex
);
438 int LPC17XX_Ethernet::write_packet(uint8_t* buf
, int size
)
440 txbuf
.txdesc
[LPC_EMAC
->TxProduceIndex
].control
= ((size
- 1) & 0x7ff) | EMAC_TCTRL_LAST
| EMAC_TCTRL_CRC
| EMAC_TCTRL_PAD
| EMAC_TCTRL_INT
;
442 uint32_t r
= LPC_EMAC
->TxProduceIndex
+ 1;
443 if (r
> LPC_EMAC
->TxDescriptorNumber
)
446 if (r
== LPC_EMAC
->TxConsumeIndex
)
449 LPC_EMAC
->TxProduceIndex
= r
;
454 void* LPC17XX_Ethernet::request_packet_buffer()
456 return txbuf
.txdesc
[LPC_EMAC
->TxProduceIndex
].packet
;
459 NET_PACKET
LPC17XX_Ethernet::get_new_packet_buffer(NetworkInterface
* ni
)
464 return (NET_PACKET
) request_packet_buffer();
467 NET_PAYLOAD
LPC17XX_Ethernet::get_payload_buffer(NET_PACKET packet
)
469 return (NET_PAYLOAD
) packet
;
472 void LPC17XX_Ethernet::set_payload_length(NET_PACKET packet
, int length
)
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))
478 txbuf
.txdesc
[i
].control
= (txbuf
.txdesc
[i
].control
& ~EMAC_TCTRL_SIZE
) | (length
& EMAC_TCTRL_SIZE
);
482 int LPC17XX_Ethernet::receive(NetworkInterface
* ni
, NET_PACKET packet
, int length
)
484 if (can_write_packet())
485 return write_packet((uint8_t*) packet
, length
);
489 int LPC17XX_Ethernet::construct(NetworkInterface
* ni
, NET_PACKET packet
, int length
)
495 void ENET_IRQHandler()
497 LPC17XX_Ethernet::instance
->irq();
501 // void LPC17XX_Ethernet::provide_net(netcore* n)
503 // NetworkInterface::provide_net(n);
505 // n->set_interface_status(this, up);