eth_sam3.c
Go to the documentation of this file.00001
00040 #include "cfg/cfg_eth.h"
00041
00042 #define LOG_LEVEL ETH_LOG_LEVEL
00043 #define LOG_FORMAT ETH_LOG_FORMAT
00044
00045 #include <cfg/log.h>
00046
00047 #include <cfg/debug.h>
00048 #include <cfg/log.h>
00049 #include <cfg/macros.h>
00050 #include <cfg/compiler.h>
00051
00052
00053
00054
00055
00056 #include <io/sam3.h>
00057 #include <drv/irq_cm3.h>
00058
00059 #include <cpu/power.h>
00060 #include <cpu/types.h>
00061 #include <cpu/irq.h>
00062
00063 #include <drv/timer.h>
00064 #include <drv/eth.h>
00065
00066 #include <mware/event.h>
00067
00068 #include <string.h>
00069
00070 #include "eth_sam3.h"
00071
00072 #define EMAC_RX_INTS (BV(EMAC_RCOMP) | BV(EMAC_ROVR) | BV(EMAC_RXUBR))
00073 #define EMAC_TX_INTS (BV(EMAC_TCOMP) | BV(EMAC_TXUBR) | BV(EMAC_RLEX))
00074
00075
00076 #ifndef __doxygen__
00077
00078
00079
00080
00081
00082 static uint8_t tx_buf[EMAC_TX_BUFFERS * EMAC_TX_BUFSIZ] ALIGNED(8);
00083 static volatile BufDescriptor tx_buf_tab[EMAC_TX_DESCRIPTORS] ALIGNED(8);
00084
00085
00086
00087
00088
00089
00090 static uint8_t rx_buf[EMAC_RX_BUFFERS * EMAC_RX_BUFSIZ] ALIGNED(8);
00091 static volatile BufDescriptor rx_buf_tab[EMAC_RX_DESCRIPTORS] ALIGNED(8);
00092 #endif
00093
00094 static int tx_buf_idx;
00095 static int tx_buf_offset;
00096 static int rx_buf_idx;
00097
00098 static Event recv_wait, send_wait;
00099
00100 static DECLARE_ISR(emac_irqHandler)
00101 {
00102
00103 uint32_t isr = EMAC_ISR;
00104
00105
00106 if ((isr & EMAC_RX_INTS))
00107 {
00108 if (isr & BV(EMAC_RCOMP))
00109 event_do(&recv_wait);
00110 EMAC_RSR = EMAC_RX_INTS;
00111 }
00112
00113 if (isr & EMAC_TX_INTS)
00114 {
00115 if (isr & BV(EMAC_TCOMP))
00116 event_do(&send_wait);
00117 EMAC_TSR = EMAC_TX_INTS;
00118 }
00119
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129 static uint16_t phy_hw_read(uint8_t phy_addr, reg8_t reg)
00130 {
00131
00132 EMAC_MAN = EMAC_SOF | EMAC_RW_READ
00133 | ((phy_addr << EMAC_PHYA_SHIFT) & EMAC_PHYA)
00134 | ((reg << EMAC_REGA_SHIFT) & EMAC_REGA)
00135 | EMAC_CODE;
00136
00137
00138 while (!(EMAC_NSR & BV(EMAC_IDLE)))
00139 cpu_relax();
00140
00141
00142 return (uint16_t)(EMAC_MAN & EMAC_DATA);
00143 }
00144
00145 #if 0
00146
00147
00148
00149
00150
00151
00152 static void phy_hw_write(uint8_t phy_addr, reg8_t reg, uint16_t val)
00153 {
00154
00155 EMAC_MAN = EMAC_SOF | EMAC_RW_WRITE
00156 | ((phy_addr << EMAC_PHYA_SHIFT) & EMAC_PHYA)
00157 | ((reg << EMAC_REGA_SHIFT) & EMAC_REGA)
00158 | EMAC_CODE | val;
00159
00160
00161 while (!(EMAC_NSR & BV(EMAC_IDLE)))
00162 cpu_relax();
00163 }
00164 #endif
00165
00166
00167
00168
00169
00170
00171 static void emac_autoNegotiation(void)
00172 {
00173 uint16_t reg;
00174 time_t start;
00175
00176
00177 start = timer_clock();
00178 do {
00179 reg = phy_hw_read(NIC_PHY_ADDR, NIC_PHY_BMSR);
00180 if (timer_clock() - start > 2000)
00181 {
00182 kprintf("eth error: auto-negotiation timeout\n");
00183 return;
00184 }
00185 }
00186 while (!(reg & NIC_PHY_BMSR_ANCOMPL));
00187
00188 reg = phy_hw_read(NIC_PHY_ADDR, NIC_PHY_ANLPAR);
00189
00190 if ((reg & NIC_PHY_ANLPAR_TX_FDX) || (reg & NIC_PHY_ANLPAR_TX_HDX))
00191 {
00192 LOG_INFO("eth: 100BASE-TX\n");
00193 EMAC_NCFGR |= BV(EMAC_SPD);
00194 }
00195 else
00196 {
00197 LOG_INFO("eth: 10BASE-T\n");
00198 EMAC_NCFGR &= ~BV(EMAC_SPD);
00199 }
00200
00201 if ((reg & NIC_PHY_ANLPAR_TX_FDX) || (reg & NIC_PHY_ANLPAR_10_FDX))
00202 {
00203 LOG_INFO("eth: full duplex\n");
00204 EMAC_NCFGR |= BV(EMAC_FD);
00205 }
00206 else
00207 {
00208 LOG_INFO("eth: half duplex\n");
00209 EMAC_NCFGR &= ~BV(EMAC_FD);
00210 }
00211 }
00212
00213
00214 static int emac_reset(void)
00215 {
00216 #if CPU_ARM_AT91
00217
00218 PMC_PCER = BV(PIOA_ID);
00219 PMC_PCER = BV(PIOB_ID);
00220 PMC_PCER = BV(EMAC_ID);
00221
00222
00223 PIOB_PUDR = BV(PHY_RXDV_TESTMODE_BIT);
00224 PIOB_PUDR = BV(PHY_COL_RMII_BIT);
00225
00226
00227 PIOB_PER = BV(PHY_PWRDN_BIT);
00228 PIOB_OER = BV(PHY_PWRDN_BIT);
00229 PIOB_CODR = BV(PHY_PWRDN_BIT);
00230 #else
00231 pmc_periphEnable(PIOA_ID);
00232 pmc_periphEnable(PIOB_ID);
00233 pmc_periphEnable(PIOC_ID);
00234 pmc_periphEnable(PIOD_ID);
00235 pmc_periphEnable(EMAC_ID);
00236
00237
00238 PIOB_PUDR = BV(PHY_RXDV_TESTMODE_BIT);
00239 #endif
00240
00241
00242 RSTC_MR = RSTC_KEY | (1 << RSTC_ERSTL_SHIFT) | BV(RSTC_URSTEN);
00243 RSTC_CR = RSTC_KEY | BV(RSTC_EXTRST);
00244
00245 while ((RSTC_SR & BV(RSTC_NRSTL)) == 0)
00246 cpu_relax();
00247
00248
00249 #if CPU_ARM_AT91
00250 PIOB_ASR = PHY_MII_PINS;
00251 PIOB_BSR = 0;
00252 PIOB_PDR = PHY_MII_PINS;
00253
00254
00255 EMAC_USRIO = BV(EMAC_CLKEN);
00256 #else
00257 PIO_PERIPH_SEL(PIOB_BASE, PHY_MII_PINS_PORTB, PIO_PERIPH_A);
00258 PIOB_PDR = PHY_MII_PINS_PORTB;
00259
00260
00261 EMAC_USRIO = BV(EMAC_CLKEN) | BV(EMAC_RMII);
00262 #endif
00263
00264
00265 EMAC_NCR |= BV(EMAC_MPE);
00266 EMAC_NCFGR |= EMAC_CLK_HCLK_64;
00267
00268
00269 EMAC_SA1L = (mac_addr[3] << 24) | (mac_addr[2] << 16) |
00270 (mac_addr[1] << 8) | mac_addr[0];
00271 EMAC_SA1H = (mac_addr[5] << 8) | mac_addr[4];
00272
00273 emac_autoNegotiation();
00274
00275
00276 EMAC_NCR &= ~BV(EMAC_MPE);
00277
00278 return 0;
00279 }
00280
00281
00282 static int emac_start(void)
00283 {
00284 uint32_t addr;
00285 int i;
00286
00287 for (i = 0; i < EMAC_RX_DESCRIPTORS; i++)
00288 {
00289 addr = (uint32_t)(rx_buf + (i * EMAC_RX_BUFSIZ));
00290 rx_buf_tab[i].addr = addr & BUF_ADDRMASK;
00291 }
00292 rx_buf_tab[EMAC_RX_DESCRIPTORS - 1].addr |= RXBUF_WRAP;
00293
00294 for (i = 0; i < EMAC_TX_DESCRIPTORS; i++)
00295 {
00296 addr = (uint32_t)(tx_buf + (i * EMAC_TX_BUFSIZ));
00297 tx_buf_tab[i].addr = addr & BUF_ADDRMASK;
00298 tx_buf_tab[i].stat = TXS_USED;
00299 }
00300 tx_buf_tab[EMAC_TX_DESCRIPTORS - 1].stat = TXS_USED | TXS_WRAP;
00301
00302
00303 EMAC_RBQP = (uint32_t)rx_buf_tab;
00304 EMAC_TBQP = (uint32_t)tx_buf_tab;
00305
00306
00307 EMAC_RSR = BV(EMAC_OVR) | BV(EMAC_REC) | BV(EMAC_BNA);
00308
00309
00310 EMAC_NCFGR |= BV(EMAC_CAF) | BV(EMAC_DRFCS);
00311
00312
00313 EMAC_NCR |= BV(EMAC_TE) | BV(EMAC_RE) | BV(EMAC_WESTAT);
00314
00315 return 0;
00316 }
00317
00318 ssize_t eth_putFrame(const uint8_t *buf, size_t len)
00319 {
00320 size_t wr_len;
00321
00322 if (UNLIKELY(!len))
00323 return -1;
00324 ASSERT(len <= sizeof(tx_buf));
00325
00326
00327 while (!(tx_buf_tab[tx_buf_idx].stat & TXS_USED))
00328 event_wait(&send_wait);
00329
00330
00331 wr_len = MIN(len, (size_t)EMAC_TX_BUFSIZ - tx_buf_offset);
00332 memcpy((uint8_t *)tx_buf_tab[tx_buf_idx].addr + tx_buf_offset,
00333 buf, wr_len);
00334 tx_buf_offset += wr_len;
00335
00336 return wr_len;
00337 }
00338
00339 void eth_sendFrame(void)
00340 {
00341 tx_buf_tab[tx_buf_idx].stat = (tx_buf_offset & TXS_LENGTH_FRAME) |
00342 TXS_LAST_BUFF |
00343 ((tx_buf_idx == EMAC_TX_DESCRIPTORS - 1) ? TXS_WRAP : 0);
00344 EMAC_NCR |= BV(EMAC_TSTART);
00345
00346 tx_buf_offset = 0;
00347 if (++tx_buf_idx >= EMAC_TX_DESCRIPTORS)
00348 tx_buf_idx = 0;
00349 }
00350
00351 ssize_t eth_send(const uint8_t *buf, size_t len)
00352 {
00353 if (UNLIKELY(!len))
00354 return -1;
00355
00356 len = eth_putFrame(buf, len);
00357 eth_sendFrame();
00358
00359 return len;
00360 }
00361
00362 static void eth_buf_realign(int idx)
00363 {
00364
00365 do {
00366 rx_buf_tab[rx_buf_idx].addr &= ~RXBUF_OWNERSHIP;
00367 if (++rx_buf_idx >= EMAC_RX_BUFFERS)
00368 rx_buf_idx = 0;
00369 } while (idx != rx_buf_idx);
00370 }
00371
00372 static size_t __eth_getFrameLen(void)
00373 {
00374 int idx, n = EMAC_RX_BUFFERS;
00375
00376 skip:
00377
00378 while ((n > 0) && !(rx_buf_tab[rx_buf_idx].addr & RXBUF_OWNERSHIP))
00379 {
00380 if (++rx_buf_idx >= EMAC_RX_BUFFERS)
00381 rx_buf_idx = 0;
00382 n--;
00383 }
00384 if (UNLIKELY(!n))
00385 {
00386 LOG_INFO("no frame found\n");
00387 return 0;
00388 }
00389
00390 while ((n > 0) && (rx_buf_tab[rx_buf_idx].addr & RXBUF_OWNERSHIP) &&
00391 !(rx_buf_tab[rx_buf_idx].stat & RXS_SOF))
00392 {
00393 rx_buf_tab[rx_buf_idx].addr &= ~RXBUF_OWNERSHIP;
00394 if (++rx_buf_idx >= EMAC_RX_BUFFERS)
00395 rx_buf_idx = 0;
00396 n--;
00397 }
00398 if (UNLIKELY(!n))
00399 {
00400 LOG_INFO("no SOF found\n");
00401 return 0;
00402 }
00403
00404 idx = rx_buf_idx;
00405 restart:
00406 while (n > 0)
00407 {
00408 if (UNLIKELY(!(rx_buf_tab[idx].addr & RXBUF_OWNERSHIP)))
00409 {
00410
00411 eth_buf_realign(idx);
00412 goto skip;
00413 }
00414 if (rx_buf_tab[idx].stat & RXS_EOF)
00415 return rx_buf_tab[idx].stat & RXS_LENGTH_FRAME;
00416 if (UNLIKELY((idx != rx_buf_idx) &&
00417 (rx_buf_tab[idx].stat & RXS_SOF)))
00418 {
00419
00420 eth_buf_realign(idx);
00421 goto restart;
00422 }
00423 if (++idx >= EMAC_RX_BUFFERS)
00424 idx = 0;
00425 n--;
00426 }
00427 LOG_INFO("no EOF found\n");
00428 return 0;
00429 }
00430
00431 size_t eth_getFrameLen(void)
00432 {
00433 size_t len;
00434
00435
00436 while (1)
00437 {
00438 len = __eth_getFrameLen();
00439 if (LIKELY(len))
00440 break;
00441
00442 event_wait(&recv_wait);
00443 }
00444 return len;
00445 }
00446
00447 ssize_t eth_getFrame(uint8_t *buf, size_t len)
00448 {
00449 uint8_t *addr;
00450 size_t rd_len = 0;
00451
00452 if (UNLIKELY(!len))
00453 return -1;
00454 ASSERT(len <= sizeof(rx_buf));
00455
00456
00457 addr = (uint8_t *)(rx_buf_tab[rx_buf_idx].addr & BUF_ADDRMASK);
00458 if (addr + len > &rx_buf[countof(rx_buf)])
00459 {
00460 size_t count = &rx_buf[countof(rx_buf)] - addr;
00461
00462 memcpy(buf, addr, count);
00463 memcpy(buf + count, rx_buf, len - count);
00464 }
00465 else
00466 {
00467 memcpy(buf, addr, len);
00468 }
00469
00470 while (rd_len < len)
00471 {
00472 if (len - rd_len >= EMAC_RX_BUFSIZ)
00473 rd_len += EMAC_RX_BUFSIZ;
00474 else
00475 rd_len += len - rd_len;
00476 if (UNLIKELY(!(rx_buf_tab[rx_buf_idx].addr & RXBUF_OWNERSHIP)))
00477 {
00478 LOG_INFO("bad frame found\n");
00479 return 0;
00480 }
00481 rx_buf_tab[rx_buf_idx].addr &= ~RXBUF_OWNERSHIP;
00482 if (++rx_buf_idx >= EMAC_RX_DESCRIPTORS)
00483 rx_buf_idx = 0;
00484 }
00485
00486 return rd_len;
00487 }
00488
00489 ssize_t eth_recv(uint8_t *buf, size_t len)
00490 {
00491 if (UNLIKELY(!len))
00492 return -1;
00493 len = MIN(len, eth_getFrameLen());
00494 return len ? eth_getFrame(buf, len) : 0;
00495 }
00496
00497 int eth_init()
00498 {
00499 cpu_flags_t flags;
00500
00501 emac_reset();
00502 emac_start();
00503
00504 event_initGeneric(&recv_wait);
00505 event_initGeneric(&send_wait);
00506
00507
00508 IRQ_SAVE_DISABLE(flags);
00509
00510
00511 EMAC_IDR = 0xFFFFFFFF;
00512
00513 #if CPU_ARM_AT91
00514
00515
00516 AIC_SVR(EMAC_ID) = emac_irqHandler;
00517
00518 AIC_SMR(EMAC_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED;
00519
00520 AIC_ICCR = BV(EMAC_ID);
00521
00522 AIC_IECR = BV(EMAC_ID);
00523 #else
00524 sysirq_setHandler(INT_EMAC, emac_irqHandler);
00525 #endif
00526
00527
00528 EMAC_IER = EMAC_RX_INTS | EMAC_TX_INTS;
00529
00530 IRQ_RESTORE(flags);
00531
00532 return 0;
00533 }