/** * \brief Disable receiver, reset registers and descriptor list. * * \param p_dev Pointer to GMAC Driver instance. */ static void gmac_reset_rx_mem(gmac_device_t* p_dev, gmac_quelist_t queue_idx) { Gmac *p_hw = p_dev->p_hw; uint8_t *p_rx_buff = p_dev->gmac_queue_list[queue_idx].p_rx_buffer; gmac_rx_descriptor_t *pRd = p_dev->gmac_queue_list[queue_idx].p_rx_dscr; uint32_t ul_index; uint32_t ul_address; /* Disable RX */ gmac_enable_receive(p_hw, 0); /* Set up the RX descriptors */ p_dev->gmac_queue_list[queue_idx].us_rx_idx = 0; for (ul_index = 0; ul_index < p_dev->gmac_queue_list[queue_idx].us_rx_list_size; ul_index++) { ul_address = (uint32_t) (&(p_rx_buff[ul_index * GMAC_RX_UNITSIZE])); pRd[ul_index].addr.val = ul_address & GMAC_RXD_ADDR_MASK; pRd[ul_index].status.val = 0; } pRd[p_dev->gmac_queue_list[queue_idx].us_rx_list_size - 1].addr.val |= GMAC_RXD_WRAP; /* Set receive buffer queue */ if(queue_idx == GMAC_QUE_0) { gmac_set_rx_queue(p_hw, (uint32_t) pRd); } else { gmac_set_rx_priority_queue(p_hw, (uint32_t) pRd, queue_idx); } }
/** * \brief Initialize the allocated buffer lists for GMAC driver to transfer data. * Must be invoked after gmac_dev_init() but before RX/TX starts. * * \note If input address is not 8-byte aligned, the address is automatically * adjusted and the list size is reduced by one. * * \param p_gmac Pointer to GMAC instance. * \param p_gmac_dev Pointer to GMAC device instance. * \param p_dev_mm Pointer to the GMAC memory management control block. * \param p_tx_cb Pointer to allocated TX callback list. * * \return GMAC_OK or GMAC_PARAM. */ static uint8_t gmac_init_mem(Gmac* p_gmac, gmac_device_t* p_gmac_dev, gmac_dev_mem_t* p_dev_mm, gmac_dev_tx_cb_t* p_tx_cb) { if (p_dev_mm->us_rx_size <= 1 || p_dev_mm->us_tx_size <= 1 || p_tx_cb == NULL) { return GMAC_PARAM; } /* Assign RX buffers */ if (((uint32_t) p_dev_mm->p_rx_buffer & 0x7) || ((uint32_t) p_dev_mm->p_rx_dscr & 0x7)) { p_dev_mm->us_rx_size--; } p_gmac_dev->p_rx_buffer = (uint8_t *) ((uint32_t) p_dev_mm->p_rx_buffer & 0xFFFFFFF8); p_gmac_dev->p_rx_dscr = (gmac_rx_descriptor_t *) ((uint32_t) p_dev_mm->p_rx_dscr & 0xFFFFFFF8); p_gmac_dev->us_rx_list_size = p_dev_mm->us_rx_size; /* Assign TX buffers */ if (((uint32_t) p_dev_mm->p_tx_buffer & 0x7) || ((uint32_t) p_dev_mm->p_tx_dscr & 0x7)) { p_dev_mm->us_tx_size--; } p_gmac_dev->p_tx_buffer = (uint8_t *) ((uint32_t) p_dev_mm->p_tx_buffer & 0xFFFFFFF8); p_gmac_dev->p_tx_dscr = (gmac_tx_descriptor_t *) ((uint32_t) p_dev_mm->p_tx_dscr & 0xFFFFFFF8); p_gmac_dev->us_tx_list_size = p_dev_mm->us_tx_size; p_gmac_dev->func_tx_cb_list = p_tx_cb; /* Reset TX & RX */ gmac_reset_rx_mem(p_gmac_dev); gmac_reset_tx_mem(p_gmac_dev); /* Enable Rx and Tx, plus the statistics register */ gmac_enable_transmit(p_gmac, true); gmac_enable_receive(p_gmac, true); gmac_enable_statistics_write(p_gmac, true); /* Set up the interrupts for transmission and errors */ gmac_enable_interrupt(p_gmac, GMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */ GMAC_IER_TUR | /* Enable transmit underrun interrupt. */ GMAC_IER_RLEX | /* Enable retry limit exceeded interrupt. */ GMAC_IER_TFC | /* Enable transmit buffers exhausted in mid-frame interrupt. */ GMAC_IER_TCOMP | /* Enable transmit complete interrupt. */ GMAC_IER_ROVR | /* Enable receive overrun interrupt. */ GMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */ GMAC_IER_PFNZ | /* Enable pause frame received interrupt. */ GMAC_IER_PTZ); /* Enable pause time zero interrupt. */ return GMAC_OK; }
static void gmac_init_queue(Gmac* p_gmac, gmac_device_t* p_gmac_dev) { gmac_dev_mem_t gmac_dev_mm; /* Clear interrupts */ gmac_get_priority_interrupt_status(p_gmac, GMAC_QUE_2); gmac_get_priority_interrupt_status(p_gmac, GMAC_QUE_1); gmac_set_tx_priority_queue(p_gmac, (uint32_t)&gs_tx_desc_null, GMAC_QUE_2); gmac_set_tx_priority_queue(p_gmac, (uint32_t)&gs_tx_desc_null, GMAC_QUE_1); gmac_set_rx_priority_queue(p_gmac, (uint32_t)&gs_rx_desc_null, GMAC_QUE_2); gmac_set_rx_priority_queue(p_gmac, (uint32_t)&gs_rx_desc_null, GMAC_QUE_1); /* Clear interrupts */ gmac_get_interrupt_status(p_gmac); /* Fill in GMAC device memory management */ gmac_dev_mm.p_rx_buffer = gs_uc_rx_buffer; gmac_dev_mm.p_rx_dscr = gs_rx_desc; gmac_dev_mm.us_rx_size = GMAC_RX_BUFFERS; gmac_dev_mm.p_tx_buffer = gs_uc_tx_buffer; gmac_dev_mm.p_tx_dscr = gs_tx_desc; gmac_dev_mm.us_tx_size = GMAC_TX_BUFFERS; gmac_init_mem(p_gmac_dev, GMAC_QUE_0, &gmac_dev_mm, gs_tx_callback); /* Enable Rx and Tx, plus the statistics register */ gmac_enable_transmit(p_gmac, true); gmac_enable_receive(p_gmac, true); gmac_enable_statistics_write(p_gmac, true); /* Set up the interrupts for transmission and errors */ gmac_enable_interrupt(p_gmac, GMAC_IER_RLEX | /* Enable retry limit exceeded interrupt. */ GMAC_IER_RCOMP | /* Enable receive complete interrupt. */ GMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */ GMAC_IER_ROVR | /* Enable receive overrun interrupt. */ GMAC_IER_TCOMP | /* Enable transmit complete interrupt. */ GMAC_IER_TUR | /* Enable transmit underrun interrupt. */ GMAC_IER_TFC | /* Enable transmit buffers exhausted in mid-frame interrupt. */ GMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */ GMAC_IER_PFNZ | /* Enable pause frame received interrupt. */ GMAC_IER_PTZ); /* Enable pause time zero interrupt. */ }
/** * \brief Issue an auto negotiation of the PHY. * * \param p_gmac Pointer to the GMAC instance. * \param uc_phy_addr PHY address. * * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. */ uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr) { uint32_t ul_retry_max = ETH_PHY_RETRY_MAX; uint32_t ul_value; uint32_t ul_phy_anar; uint32_t ul_retry_count = 0; uint8_t uc_speed = 0; uint8_t uc_fd=0; uint8_t uc_rc = GMAC_TIMEOUT; gmac_enable_management(p_gmac, true); /* Set up control register */ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); phy_props.phy_result = -1; return uc_rc; } ul_value &= ~(uint32_t)GMII_AUTONEG; /* Remove auto-negotiation enable */ ul_value &= ~(uint32_t)(GMII_LOOPBACK | GMII_POWER_DOWN); ul_value |= (uint32_t)GMII_ISOLATE; /* Electrically isolate PHY */ uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); phy_props.phy_result = -2; return uc_rc; } /* * Set the Auto_negotiation Advertisement Register. * MII advertising for Next page. * 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3. */ ul_phy_anar = GMII_100TX_FDX | GMII_100TX_HDX | GMII_10_FDX | GMII_10_HDX | GMII_AN_IEEE_802_3; uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_ANAR, ul_phy_anar); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); phy_props.phy_result = -3; return uc_rc; } /* Read & modify control register */ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); phy_props.phy_result = -4; return uc_rc; } ul_value |= GMII_SPEED_SELECT | GMII_AUTONEG | GMII_DUPLEX_MODE; uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); phy_props.phy_result = -5; return uc_rc; } /* Restart auto negotiation */ ul_value |= (uint32_t)GMII_RESTART_AUTONEG; ul_value &= ~(uint32_t)GMII_ISOLATE; uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); phy_props.phy_result = -6; return uc_rc; } /* Check if auto negotiation is completed */ while (1) { uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMSR, &ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); phy_props.phy_result = -7; return uc_rc; } /* Done successfully */ if (ul_value & GMII_AUTONEG_COMP) { break; } /* Timeout check */ if (ul_retry_max) { if (++ul_retry_count >= ul_retry_max) { gmac_enable_management(p_gmac, false); phy_props.phy_result = -8; return GMAC_TIMEOUT; } } } /* Get the auto negotiate link partner base page */ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_PCR1, &phy_props.phy_params); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); phy_props.phy_result = -9; return uc_rc; } /* Set up the GMAC link speed */ if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_FDX) { /* Set MII for 100BaseTX and Full Duplex */ uc_speed = true; uc_fd = true; } else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_FDX) { /* Set MII for 10BaseT and Full Duplex */ uc_speed = false; uc_fd = true; } else if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_HDX) { /* Set MII for 100BaseTX and half Duplex */ uc_speed = true; uc_fd = false; } else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_HDX) { /* Set MII for 10BaseT and half Duplex */ uc_speed = false; uc_fd = false; } gmac_set_speed(p_gmac, uc_speed); gmac_enable_full_duplex(p_gmac, uc_fd); /* Select Media Independent Interface type */ gmac_select_mii_mode(p_gmac, ETH_PHY_MODE); gmac_enable_transmit(GMAC, true); gmac_enable_receive(GMAC, true); gmac_enable_management(p_gmac, false); phy_props.phy_result = 1; return uc_rc; }
/** * \brief Issue an auto negotiation of the PHY. * * \param p_gmac Pointer to the GMAC instance. * \param uc_phy_addr PHY address. * * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. */ uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr) { uint32_t ul_value; uint32_t ul_phy_anar; uint32_t ul_phy_analpar; uint8_t uc_speed = 0; uint8_t uc_fd=0; uint8_t uc_rc; if(auto_negotiate_state == AUTO_NEGOTIATE_STATE_START) { auto_negotiate_wait_counter = 0; gmac_enable_management(p_gmac, true); /* Set up control register */ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); return uc_rc; } ul_value &= ~(uint32_t)GMII_AUTONEG; /* Remove auto-negotiation enable */ ul_value &= ~(uint32_t)(GMII_LOOPBACK | GMII_POWER_DOWN); ul_value |= (uint32_t)GMII_ISOLATE; /* Electrically isolate PHY */ uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); return uc_rc; } /* * Set the Auto_negotiation Advertisement Register. * MII advertising for Next page. * 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3. */ ul_phy_anar = GMII_100TX_FDX | GMII_100TX_HDX | GMII_10_FDX | GMII_10_HDX | GMII_AN_IEEE_802_3; uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_ANAR, ul_phy_anar); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); return uc_rc; } /* Read & modify control register */ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); return uc_rc; } ul_value |= GMII_SPEED_SELECT | GMII_AUTONEG | GMII_DUPLEX_MODE; uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); return uc_rc; } /* Restart auto negotiation */ ul_value |= (uint32_t)GMII_RESTART_AUTONEG; ul_value &= ~(uint32_t)GMII_ISOLATE; uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); return uc_rc; } auto_negotiate_state = AUTO_NEGOTIATE_STATE_WAIT; } if(auto_negotiate_state == AUTO_NEGOTIATE_STATE_WAIT) { uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMSR, &ul_value); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); auto_negotiate_state = AUTO_NEGOTIATE_STATE_START; return uc_rc; } // Not done successfully, we will try again later if(!(ul_value & GMII_AUTONEG_COMP)) { auto_negotiate_wait_counter++; // here we will try again later if (auto_negotiate_wait_counter >= ETH_PHY_RETRY_MAX) { gmac_enable_management(p_gmac, false); auto_negotiate_state = AUTO_NEGOTIATE_STATE_START; } return GMAC_TIMEOUT; } auto_negotiate_state = AUTO_NEGOTIATE_STATE_START; /* Get the auto negotiate link partner base page */ uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_ANLPAR, &ul_phy_analpar); if (uc_rc != GMAC_OK) { gmac_enable_management(p_gmac, false); return uc_rc; } /* Set up the GMAC link speed */ if ((ul_phy_anar & ul_phy_analpar) & GMII_100TX_FDX) { /* Set MII for 100BaseTX and Full Duplex */ uc_speed = true; uc_fd = true; } else if ((ul_phy_anar & ul_phy_analpar) & GMII_10_FDX) { /* Set MII for 10BaseT and Full Duplex */ uc_speed = false; uc_fd = true; } else if ((ul_phy_anar & ul_phy_analpar) & GMII_100TX_HDX) { /* Set MII for 100BaseTX and half Duplex */ uc_speed = true; uc_fd = false; } else if ((ul_phy_anar & ul_phy_analpar) & GMII_10_HDX) { /* Set MII for 10BaseT and half Duplex */ uc_speed = false; uc_fd = false; } gmac_set_speed(p_gmac, uc_speed); gmac_enable_full_duplex(p_gmac, uc_fd); /* Select Media Independent Interface type */ gmac_select_mii_mode(p_gmac, ETH_PHY_MODE); gmac_enable_transmit(GMAC, true); gmac_enable_receive(GMAC, true); gmac_enable_management(p_gmac, false); } return uc_rc; }