From f7246e13fc639463fd4084fd0d3b851d4a446cb2 Mon Sep 17 00:00:00 2001 From: aleph Date: Wed, 30 Mar 2011 14:05:00 +0000 Subject: [PATCH] sam3 eth: consider PHY auto-negotiation results when initializing emac. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4824 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cpu/cortex-m3/drv/eth_sam3.c | 102 +++++++++++++++------------- bertos/cpu/cortex-m3/drv/eth_sam3.h | 9 ++- 2 files changed, 59 insertions(+), 52 deletions(-) diff --git a/bertos/cpu/cortex-m3/drv/eth_sam3.c b/bertos/cpu/cortex-m3/drv/eth_sam3.c index 686da8ba..0247f618 100644 --- a/bertos/cpu/cortex-m3/drv/eth_sam3.c +++ b/bertos/cpu/cortex-m3/drv/eth_sam3.c @@ -77,7 +77,7 @@ * * TODO: make this paramater user-configurable from the Wizard. */ -const uint8_t mac_addr[] = { 0x00, 0x23, 0x54, 0x6a, 0x77, 0x55 }; +const uint8_t mac_addr[] = { 0x00, 0x45, 0x56, 0x78, 0x9a, 0xbc }; /* Silent Doxygen bug... */ #ifndef __doxygen__ @@ -109,12 +109,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 +120,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 +149,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,12 +168,58 @@ 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); @@ -246,43 +285,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(500); - -#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)); + emac_autoNegotiation(); // Disable management port. EMAC_NCR &= ~BV(EMAC_MPE); @@ -290,6 +293,7 @@ static int emac_reset(void) return 0; } + static int emac_start(void) { uint32_t addr; diff --git a/bertos/cpu/cortex-m3/drv/eth_sam3.h b/bertos/cpu/cortex-m3/drv/eth_sam3.h index bd5e6f32..a756ffc2 100644 --- a/bertos/cpu/cortex-m3/drv/eth_sam3.h +++ b/bertos/cpu/cortex-m3/drv/eth_sam3.h @@ -44,7 +44,7 @@ // \{ #define NIC_PHY_ADDR 0 -//Registry definition +// Register bits definition #define NIC_PHY_BMCR 0x00 // Basic mode control register. #define NIC_PHY_BMCR_COLTEST 0x0080 // Collision test. #define NIC_PHY_BMCR_FDUPLEX 0x0100 // Full duplex mode. @@ -61,6 +61,11 @@ #define NIC_PHY_BMSR_ANEGCAPABLE 0x0008 // Able to do auto-negotiation #define NIC_PHY_BMSR_LINKSTAT 0x0004 // Link status. +#define NIC_PHY_ANLPAR_10_HDX BV(5) // 10BASE-T half duplex +#define NIC_PHY_ANLPAR_10_FDX BV(6) // 10BASE-T full duplex +#define NIC_PHY_ANLPAR_TX_HDX BV(7) // 100BASE-TX half duplex +#define NIC_PHY_ANLPAR_TX_FDX BV(8) // 100BASE-TX full duplex + #define NIC_PHY_ID1 0x02 // PHY identifier register 1. #define NIC_PHY_ID2 0x03 // PHY identifier register 2. #define NIC_PHY_ANAR 0x04 // Auto negotiation advertisement register. @@ -74,7 +79,6 @@ * See schematics for AT91SAM7X-EK evalution board. */ // All pins in port B -#define PHY_TXCLK_ISOLATE_BIT 0 #define PHY_REFCLK_XT2_BIT 0 #define PHY_TXEN_BIT 1 #define PHY_TXD0_BIT 2 @@ -123,7 +127,6 @@ * See schematics for SAM3X-EK evalution board. */ // Port B -#define PHY_TXCLK_ISOLATE_BIT 0 #define PHY_REFCLK_XT2_BIT 0 #define PHY_TXEN_BIT 1 #define PHY_TXD0_BIT 2 -- 2.25.1