Example #1
0
/**
 * \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);
	}
}
Example #2
0
/**
 * \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;
}
Example #3
0
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. */
}
Example #4
0
/**
 * \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;
}
Example #5
0
/**
 * \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;
}