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