BeRTOS
|
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 }