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