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