X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Fcortex-m3%2Fdrv%2Feth_sam3.c;h=f83dba7227d71d4ffe551045eb23d82fd2ab6462;hb=ab40eaf9ac5b43e7087588fe7f435bdbc9a6eb23;hp=5e18dfe47764c027953ebf509680f04c4efa666b;hpb=c0199cd9ca0679980556859e79e9f040da6ab598;p=bertos.git diff --git a/bertos/cpu/cortex-m3/drv/eth_sam3.c b/bertos/cpu/cortex-m3/drv/eth_sam3.c index 5e18dfe4..f83dba72 100644 --- a/bertos/cpu/cortex-m3/drv/eth_sam3.c +++ b/bertos/cpu/cortex-m3/drv/eth_sam3.c @@ -72,13 +72,6 @@ #define EMAC_RX_INTS (BV(EMAC_RCOMP) | BV(EMAC_ROVR) | BV(EMAC_RXUBR)) #define EMAC_TX_INTS (BV(EMAC_TCOMP) | BV(EMAC_TXUBR) | BV(EMAC_RLEX)) -/* - * MAC address configuration (please change this in your project!). - * - * TODO: make this paramater user-configurable from the Wizard. - */ -const uint8_t mac_addr[] = { 0x00, 0x23, 0x54, 0x6a, 0x77, 0x55 }; - /* Silent Doxygen bug... */ #ifndef __doxygen__ /* @@ -109,12 +102,9 @@ static DECLARE_ISR(emac_irqHandler) /* Read interrupt status and disable interrupts. */ uint32_t isr = EMAC_ISR; - kprintf("irq: %x\n", isr); - /* Receiver interrupt */ if ((isr & EMAC_RX_INTS)) { - kprintf("emac: rx %x\n", isr); if (isr & BV(EMAC_RCOMP)) event_do(&recv_wait); EMAC_RSR = EMAC_RX_INTS; @@ -123,12 +113,7 @@ static DECLARE_ISR(emac_irqHandler) if (isr & EMAC_TX_INTS) { if (isr & BV(EMAC_TCOMP)) - { - kprintf("emac: tcomp\n"); event_do(&send_wait); - } - if (isr & BV(EMAC_RLEX)) - kprintf("emac: rlex\n"); EMAC_TSR = EMAC_TX_INTS; } //AIC_EOICR = 0; @@ -157,6 +142,7 @@ static uint16_t phy_hw_read(uint8_t phy_addr, reg8_t reg) return (uint16_t)(EMAC_MAN & EMAC_DATA); } +#if 0 /* * \brief Write value to PHY register. * @@ -175,31 +161,86 @@ static void phy_hw_write(uint8_t phy_addr, reg8_t reg, uint16_t val) while (!(EMAC_NSR & BV(EMAC_IDLE))) cpu_relax(); } +#endif -static int emac_reset(void) +/* + * Check link speed and duplex as negotiated by the PHY + * and configure CPU EMAC accordingly. + * Requires active PHY maintenance mode. + */ +static void emac_autoNegotiation(void) { - uint16_t phy_cr; - unsigned i; + uint16_t reg; + time_t start; + + // Wait for auto-negotation to complete + start = timer_clock(); + do { + reg = phy_hw_read(NIC_PHY_ADDR, NIC_PHY_BMSR); + if (timer_clock() - start > 2000) + { + kprintf("eth error: auto-negotiation timeout\n"); + return; + } + } + while (!(reg & NIC_PHY_BMSR_ANCOMPL)); + + reg = phy_hw_read(NIC_PHY_ADDR, NIC_PHY_ANLPAR); + if ((reg & NIC_PHY_ANLPAR_TX_FDX) || (reg & NIC_PHY_ANLPAR_TX_HDX)) + { + LOG_INFO("eth: 100BASE-TX\n"); + EMAC_NCFGR |= BV(EMAC_SPD); + } + else + { + LOG_INFO("eth: 10BASE-T\n"); + EMAC_NCFGR &= ~BV(EMAC_SPD); + } + + if ((reg & NIC_PHY_ANLPAR_TX_FDX) || (reg & NIC_PHY_ANLPAR_10_FDX)) + { + LOG_INFO("eth: full duplex\n"); + EMAC_NCFGR |= BV(EMAC_FD); + } + else + { + LOG_INFO("eth: half duplex\n"); + EMAC_NCFGR &= ~BV(EMAC_FD); + } +} + + +static int emac_reset(void) +{ +#if CPU_ARM_AT91 // Enable devices - //PMC_PCER = BV(PIOA_ID); - //PMC_PCER = BV(PIOB_ID); - //PMC_PCER = BV(EMAC_ID); - // TOOD: Implement in sam7x - pmc_periphEnable(PIOA_ID); - pmc_periphEnable(PIOB_ID); - pmc_periphEnable(EMAC_ID); + PMC_PCER = BV(PIOA_ID); + PMC_PCER = BV(PIOB_ID); + PMC_PCER = BV(EMAC_ID); - // Disable TESTMODE + // Disable TESTMODE and RMII PIOB_PUDR = BV(PHY_RXDV_TESTMODE_BIT); -#if CPU_ARM_AT91 - // Disable RMII PIOB_PUDR = BV(PHY_COL_RMII_BIT); // Disable PHY power down. PIOB_PER = BV(PHY_PWRDN_BIT); PIOB_OER = BV(PHY_PWRDN_BIT); PIOB_CODR = BV(PHY_PWRDN_BIT); +#else + pmc_periphEnable(PIOA_ID); + pmc_periphEnable(PIOB_ID); + pmc_periphEnable(PIOC_ID); + pmc_periphEnable(PIOD_ID); + pmc_periphEnable(EMAC_ID); + + // Disable TESTMODE and RMII + PIOC_PUDR = BV(PHY_RXDV_TESTMODE_BIT); + + // Disable PHY power down. + PIOD_PER = BV(PHY_PWRDN_BIT); + PIOD_OER = BV(PHY_PWRDN_BIT); + PIOD_CODR = BV(PHY_PWRDN_BIT); #endif // Toggle external hardware reset pin. @@ -214,11 +255,16 @@ static int emac_reset(void) PIOB_ASR = PHY_MII_PINS; PIOB_BSR = 0; PIOB_PDR = PHY_MII_PINS; + // Enable receive and transmit clocks. EMAC_USRIO = BV(EMAC_CLKEN); #else - PIO_PERIPH_SEL(PIOB_BASE, PHY_MII_PINS, PIO_PERIPH_A); - PIOB_PDR = PHY_MII_PINS; + PIO_PERIPH_SEL(PIOB_BASE, PHY_MII_PINS_PORTB, PIO_PERIPH_A); + PIOB_PDR = PHY_MII_PINS_PORTB; + + PIO_PERIPH_SEL(PIOC_BASE, PHY_MII_PINS_PORTC, PIO_PERIPH_A); + PIOC_PDR = PHY_MII_PINS_PORTC; + // Enable receive, transmit clocks and RMII mode. EMAC_USRIO = BV(EMAC_CLKEN) | BV(EMAC_RMII); #endif @@ -232,52 +278,7 @@ static int emac_reset(void) (mac_addr[1] << 8) | mac_addr[0]; EMAC_SA1H = (mac_addr[5] << 8) | mac_addr[4]; - // Wait for PHY ready - timer_delay(255); - -#if 0 // debug test - for (;;) - { - for (i = 0; i < 32; i++) - { - // Clear MII isolate. - phy_hw_read(i, NIC_PHY_BMCR); - phy_cr = phy_hw_read(i, NIC_PHY_BMCR); - - phy_cr &= ~NIC_PHY_BMCR_ISOLATE; - phy_hw_write(i, NIC_PHY_BMCR, phy_cr); - - phy_cr = phy_hw_read(i, NIC_PHY_BMCR); - - LOG_INFO("%s: PHY ID %d %#04x %#04x\n", - __func__, i, - phy_hw_read(i, NIC_PHY_ID1), phy_hw_read(i, NIC_PHY_ID2)); - } - timer_delay(1000); - } -#endif - - // Clear MII isolate. - phy_hw_read(NIC_PHY_ADDR, NIC_PHY_BMCR); - phy_cr = phy_hw_read(NIC_PHY_ADDR, NIC_PHY_BMCR); - - phy_cr &= ~NIC_PHY_BMCR_ISOLATE; - phy_hw_write(NIC_PHY_ADDR, NIC_PHY_BMCR, phy_cr); - - phy_cr = phy_hw_read(NIC_PHY_ADDR, NIC_PHY_BMCR); - - LOG_INFO("%s: PHY ID %#04x %#04x\n", - __func__, - phy_hw_read(NIC_PHY_ADDR, NIC_PHY_ID1), phy_hw_read(NIC_PHY_ADDR, NIC_PHY_ID2)); - - // Wait for auto negotiation completed. - phy_hw_read(NIC_PHY_ADDR, NIC_PHY_BMSR); - for (;;) - { - if (phy_hw_read(NIC_PHY_ADDR, NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) - break; - cpu_relax(); - } + emac_autoNegotiation(); // Disable management port. EMAC_NCR &= ~BV(EMAC_MPE); @@ -285,6 +286,7 @@ static int emac_reset(void) return 0; } + static int emac_start(void) { uint32_t addr;