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