diff --git a/ports/ARM7-AT91SAM7X/sam7x_emac.c b/ports/ARM7-AT91SAM7X/sam7x_emac.c index 313d7f499..0a3d1144b 100644 --- a/ports/ARM7-AT91SAM7X/sam7x_emac.c +++ b/ports/ARM7-AT91SAM7X/sam7x_emac.c @@ -31,9 +31,10 @@ #define EMAC_TRANSMIT_BUFFERS 2 #define EMAC_TRANSMIT_BUFFERS_SIZE 1518 -EventSource EMACFrameTransmitted; /* A frame was transmitted. */ -EventSource EMACFrameReceived; /* A frame was received. */ -static int received; /* Buffered frames counter. */ +EventSource EMACFrameTransmitted; /* A frame was transmitted. */ +EventSource EMACFrameReceived; /* A frame was received. */ +static int received; /* Buffered frames counter. */ +static bool_t link_up; /* Last from EMACGetLinkStatus()*/ static uint8_t default_mac[] = {0xAA, 0x55, 0x13, 0x37, 0x01, 0x10}; @@ -89,37 +90,6 @@ static uint32_t phy_get(uint8_t regno) { ; }*/ -/* - * Returns FALSE if the link is not established. - * It also setup the link-related EMAC registers. - */ -static bool_t get_link_status(void) { - uint32_t ncfgr, bmsr, bmcr, lpa; - - (void)phy_get(MII_BMSR); - bmsr = phy_get(MII_BMSR); - if (!(bmsr & BMSR_LSTATUS)) - return FALSE; - - ncfgr = AT91C_BASE_EMAC->EMAC_NCFGR & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD); - bmcr = phy_get(MII_BMCR); - if (bmcr & BMCR_ANENABLE) { - lpa = phy_get(MII_LPA); - if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4)) - ncfgr |= AT91C_EMAC_SPD; - if (lpa & (LPA_10FULL | LPA_100FULL)) - ncfgr |= AT91C_EMAC_FD; - } - else { - if (bmcr & BMCR_SPEED100) - ncfgr |= AT91C_EMAC_SPD; - if (bmcr & BMCR_FULLDPLX) - ncfgr |= AT91C_EMAC_FD; - } - AT91C_BASE_EMAC->EMAC_NCFGR = ncfgr; - return TRUE; -} - #define RSR_BITS (AT91C_EMAC_BNA | AT91C_EMAC_REC | AT91C_EMAC_OVR) #define TSR_BITS (AT91C_EMAC_UBR | AT91C_EMAC_COL | AT91C_EMAC_RLES | \ AT91C_EMAC_BEX | AT91C_EMAC_COMP | AT91C_EMAC_UND) @@ -199,7 +169,6 @@ void InitEMAC(int prio) { */ AT91C_BASE_PIOB->PIO_OER = PIOB_PHY_PD; // Becomes an output. AT91C_BASE_PIOB->PIO_PPUDR = PIOB_PHY_PD; // Default pullup disabled. -// AT91C_BASE_PIOB->PIO_CODR = PIOB_PHY_PD; // Output to low level. AT91C_BASE_PIOB->PIO_SODR = PIOB_PHY_PD; // Output to high level. /* @@ -217,20 +186,13 @@ void InitEMAC(int prio) { AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_EMAC; AT91C_BASE_PIOB->PIO_ASR = EMAC_PIN_MASK; AT91C_BASE_PIOB->PIO_PDR = EMAC_PIN_MASK; - AT91C_BASE_PIOB->PIO_PPUDR = EMAC_PIN_MASK; // Really needed ????? + AT91C_BASE_PIOB->PIO_PPUDR = EMAC_PIN_MASK; /* * EMAC setup. */ -// AT91C_BASE_EMAC->EMAC_NCR = AT91C_EMAC_MPE; // Enable Management Port + AT91C_BASE_EMAC->EMAC_NCR = 0; // Initial setting. AT91C_BASE_EMAC->EMAC_NCFGR = 2 << 10; // MDC-CLK = MCK / 32 -// chThdSleep(5); // It could perform one or more dummy phy_get() instead. -// (void)phy_get(MII_PHYSID1); -// (void)phy_get(MII_PHYSID2); -// (void)phy_get(MII_BMCR); -// phy_put(MII_BMCR, phy_get(MII_BMCR) & ~BMCR_ISOLATE); // Disable ISOLATE - AT91C_BASE_EMAC->EMAC_NCR = 0; // Disable Management Port - AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN; // Enable EMAC in MII mode AT91C_BASE_EMAC->EMAC_RBQP = (AT91_REG)rent; // RX buffers list AT91C_BASE_EMAC->EMAC_TBQP = (AT91_REG)tent; // TX buffers list @@ -245,14 +207,20 @@ void InitEMAC(int prio) { EMACSetAddress(default_mac); /* - * PHY checks and settings. + * PHY detection and settings. */ AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE; if ((phy_get(MII_PHYSID1) != (MII_MICREL_ID >> 16)) || ((phy_get(MII_PHYSID2) & 0xFFF0) != (MII_MICREL_ID & 0xFFF0))) chSysHalt(); - if (!get_link_status()) - chSysHalt(); + + /* + * Waits for auto-negotiation to end and then detects the link status. + */ +/* while (!(phy_get(MII_BMSR) & BMSR_ANEGCOMPLETE)) + ; + if (!EMACGetLinkStatus()) + chDbgPanic("no link");*/ AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE; /* @@ -281,6 +249,42 @@ void EMACSetAddress(uint8_t *eaddr) { AT91C_BASE_EMAC->EMAC_SA1H = (AT91_REG)((eaddr[5] << 8) | eaddr[4]); } +/* + * Returns TRUE if the link is active. To be invoked at regular intervals in + * order to monitor the link. + * @note It is not thread-safe. + */ +bool_t EMACGetLinkStatus(void) { + uint32_t ncfgr, bmsr, bmcr, lpa; + + AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE; + (void)phy_get(MII_BMSR); + bmsr = phy_get(MII_BMSR); + if (!(bmsr & BMSR_LSTATUS)) { + AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE; + return link_up = FALSE; + } + + ncfgr = AT91C_BASE_EMAC->EMAC_NCFGR & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD); + bmcr = phy_get(MII_BMCR); + if (bmcr & BMCR_ANENABLE) { + lpa = phy_get(MII_LPA); + if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4)) + ncfgr |= AT91C_EMAC_SPD; + if (lpa & (LPA_10FULL | LPA_100FULL)) + ncfgr |= AT91C_EMAC_FD; + } + else { + if (bmcr & BMCR_SPEED100) + ncfgr |= AT91C_EMAC_SPD; + if (bmcr & BMCR_FULLDPLX) + ncfgr |= AT91C_EMAC_FD; + } + AT91C_BASE_EMAC->EMAC_NCFGR = ncfgr; + AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE; + return link_up = TRUE; +} + /* * Transmits an ethernet frame. * Returns TRUE if the frame is queued for transmission else FALSE. @@ -295,6 +299,9 @@ bool_t EMACTransmit(struct MACHeader *hdr, uint8_t *data, size_t size) { EMAC_TRANSMIT_BUFFERS_SIZE), "sam7x_emac.c, EMACTransmit #2"); + if (!link_up) + return FALSE; + chSysLock(); cptr = txptr; if (!(cptr->w2 & W2_T_USED) || @@ -329,7 +336,7 @@ bool_t EMACTransmit(struct MACHeader *hdr, uint8_t *data, size_t size) { /* * Reads a buffered frame. * Returns TRUE if a frame was present and read else FALSE. - * Note, it is not thread safe, it would require a semaphore or a mutex. + * @note It is not thread-safe. */ bool_t EMACReceive(uint8_t *buf, size_t *sizep) { unsigned n; diff --git a/ports/ARM7-AT91SAM7X/sam7x_emac.h b/ports/ARM7-AT91SAM7X/sam7x_emac.h index a6f43a2c8..aa69a5e29 100644 --- a/ports/ARM7-AT91SAM7X/sam7x_emac.h +++ b/ports/ARM7-AT91SAM7X/sam7x_emac.h @@ -72,6 +72,7 @@ extern "C" { #endif void InitEMAC(int prio); void EMACSetAddress(uint8_t *eaddr); + bool_t EMACGetLinkStatus(void); bool_t EMACTransmit(struct MACHeader *hdr, uint8_t *data, size_t size); bool_t EMACReceive(uint8_t *buf, size_t *sizep); #ifdef __cplusplus