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 // TODO: unify includes
00053 //#include <io/at91sam7.h>
00054 //#include <io/arm.h>
00055 //#include <io/include.h>
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 /* Silent Doxygen bug... */
00076 #ifndef __doxygen__
00077 /*
00078  * NOTE: this buffer should be declared as 'volatile' because it is read by the
00079  * hardware. However, this is accessed only via memcpy() that should guarantee
00080  * coherency when copying from/to buffers.
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  * NOTE: this buffer should be declared as 'volatile' because it is wrote by
00087  * the hardware. However, this is accessed only via memcpy() that should
00088  * guarantee coherency when copying from/to buffers.
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     /* Read interrupt status and disable interrupts. */
00103     uint32_t isr = EMAC_ISR;
00104 
00105     /* Receiver interrupt */
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     /* Transmitter interrupt */
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     //AIC_EOICR = 0;
00120 }
00121 
00122 /*
00123  * \brief Read contents of PHY register.
00124  *
00125  * \param reg PHY register number.
00126  *
00127  * \return Contents of the specified register.
00128  */
00129 static uint16_t phy_hw_read(uint8_t phy_addr, reg8_t reg)
00130 {
00131     // PHY read command.
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     // Wait until PHY logic completed.
00138     while (!(EMAC_NSR & BV(EMAC_IDLE)))
00139         cpu_relax();
00140 
00141     // Get data from PHY maintenance register.
00142     return (uint16_t)(EMAC_MAN & EMAC_DATA);
00143 }
00144 
00145 #if 0
00146 /*
00147  * \brief Write value to PHY register.
00148  *
00149  * \param reg PHY register number.
00150  * \param val Value to write.
00151  */
00152 static void phy_hw_write(uint8_t phy_addr, reg8_t reg, uint16_t val)
00153 {
00154     // PHY write command.
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     // Wait until PHY logic completed.
00161     while (!(EMAC_NSR & BV(EMAC_IDLE)))
00162         cpu_relax();
00163 }
00164 #endif
00165 
00166 /*
00167  * Check link speed and duplex as negotiated by the PHY
00168  * and configure CPU EMAC accordingly.
00169  * Requires active PHY maintenance mode.
00170  */
00171 static void emac_autoNegotiation(void)
00172 {
00173     uint16_t reg;
00174     time_t start;
00175 
00176     // Wait for auto-negotation to complete
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     // Enable devices
00218     PMC_PCER = BV(PIOA_ID);
00219     PMC_PCER = BV(PIOB_ID);
00220     PMC_PCER = BV(EMAC_ID);
00221 
00222     // Disable TESTMODE and RMII
00223     PIOB_PUDR = BV(PHY_RXDV_TESTMODE_BIT);
00224     PIOB_PUDR = BV(PHY_COL_RMII_BIT);
00225 
00226     // Disable PHY power down.
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     // Disable TESTMODE
00238     PIOB_PUDR = BV(PHY_RXDV_TESTMODE_BIT);
00239 #endif
00240 
00241     // Toggle external hardware reset pin.
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     // Configure MII ports.
00249 #if CPU_ARM_AT91
00250     PIOB_ASR = PHY_MII_PINS;
00251     PIOB_BSR = 0;
00252     PIOB_PDR = PHY_MII_PINS;
00253 
00254     // Enable receive and transmit clocks.
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     // Enable receive, transmit clocks and RMII mode.
00261     EMAC_USRIO = BV(EMAC_CLKEN) | BV(EMAC_RMII);
00262 #endif
00263 
00264     // Enable management port.
00265     EMAC_NCR |= BV(EMAC_MPE);
00266     EMAC_NCFGR |= EMAC_CLK_HCLK_64;
00267 
00268     // Set local MAC address.
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     // Disable management port.
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     /* Tell the EMAC where to find the descriptors. */
00303     EMAC_RBQP = (uint32_t)rx_buf_tab;
00304     EMAC_TBQP = (uint32_t)tx_buf_tab;
00305 
00306     /* Clear receiver status. */
00307     EMAC_RSR = BV(EMAC_OVR) | BV(EMAC_REC) | BV(EMAC_BNA);
00308 
00309     /* Copy all frames and discard FCS. */
00310     EMAC_NCFGR |= BV(EMAC_CAF) | BV(EMAC_DRFCS);
00311 
00312     /* Enable receiver, transmitter and statistics. */
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     /* Check if the transmit buffer is available */
00327     while (!(tx_buf_tab[tx_buf_idx].stat & TXS_USED))
00328         event_wait(&send_wait);
00329 
00330     /* Copy the data into the buffer and prepare descriptor */
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     /* Empty buffer found. Realign. */
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     /* Skip empty buffers */
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     /* Search the start of frame and cleanup fragments */
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     /* Search end of frame to evaluate the total frame size */
00404     idx = rx_buf_idx;
00405 restart:
00406     while (n > 0)
00407     {
00408         if (UNLIKELY(!(rx_buf_tab[idx].addr & RXBUF_OWNERSHIP)))
00409         {
00410             /* Empty buffer found. Realign. */
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             /* Another start of frame found. Realign. */
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     /* Check if there is at least one available frame in the buffer */
00436     while (1)
00437     {
00438         len = __eth_getFrameLen();
00439         if (LIKELY(len))
00440             break;
00441         /* Wait for RX interrupt */
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     /* Copy data from the RX buffer */
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     /* Update descriptors */
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     // Register interrupt vector
00508     IRQ_SAVE_DISABLE(flags);
00509 
00510     /* Disable all emac interrupts */
00511     EMAC_IDR = 0xFFFFFFFF;
00512 
00513 #if CPU_ARM_AT91
00514     // TODO: define sysirq_set...
00515     /* Set the vector. */
00516     AIC_SVR(EMAC_ID) = emac_irqHandler;
00517     /* Initialize to edge triggered with defined priority. */
00518     AIC_SMR(EMAC_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED;
00519     /* Clear pending interrupt */
00520     AIC_ICCR = BV(EMAC_ID);
00521     /* Enable the system IRQ */
00522     AIC_IECR = BV(EMAC_ID);
00523 #else
00524     sysirq_setHandler(INT_EMAC, emac_irqHandler);
00525 #endif
00526 
00527     /* Enable interrupts */
00528     EMAC_IER = EMAC_RX_INTS | EMAC_TX_INTS;
00529 
00530     IRQ_RESTORE(flags);
00531 
00532     return 0;
00533 }