예제 #1
0
/*
 * This function sends a single packet on the network
 * and returns 0 on successful transmit or negative for error
 */
static int davinci_emac_send(struct eth_device *edev, void *packet, int length)
{
	struct davinci_emac_priv *priv = edev->priv;
	uint64_t start;
	int ret_status;

	dev_dbg(priv->dev, "+ emac_send (length %d)\n", length);

	/* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
	if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
		length = EMAC_MIN_ETHERNET_PKT_SIZE;
	}

	/* Populate the TX descriptor */
	writel(0, priv->emac_tx_desc + EMAC_DESC_NEXT);
	writel((uint8_t *) packet, priv->emac_tx_desc + EMAC_DESC_BUFFER);
	writel((length & 0xffff), priv->emac_tx_desc + EMAC_DESC_BUFF_OFF_LEN);
	writel(((length & 0xffff) | EMAC_CPPI_SOP_BIT |
				    EMAC_CPPI_OWNERSHIP_BIT |
				    EMAC_CPPI_EOP_BIT),
		priv->emac_tx_desc + EMAC_DESC_PKT_FLAG_LEN);
	dma_sync_single_for_device((unsigned long)packet, length, DMA_TO_DEVICE);
	/* Send the packet */
	writel(BD_TO_HW(priv->emac_tx_desc), priv->adap_emac + EMAC_TX0HDP);

	/* Wait for packet to complete or link down */
	start = get_time_ns();
	while (1) {
		if (readl(priv->adap_emac + EMAC_TXINTSTATRAW) & 0x01) {
			/* Acknowledge the TX descriptor */
			writel(BD_TO_HW(priv->emac_tx_desc), priv->adap_emac + EMAC_TX0CP);
			ret_status = 0;
			break;
		}
		if (is_timeout(start, 100 * MSECOND)) {
			ret_status = -ETIMEDOUT;
			break;
		}
	}
	dma_sync_single_for_cpu((unsigned long)packet, length, DMA_TO_DEVICE);

	dev_dbg(priv->dev, "- emac_send (ret_status %i)\n", ret_status);
	return ret_status;
}
예제 #2
0
/*
 * This function sends a single packet on the network and returns
 * positive number (number of bytes transmitted) or negative for error
 */
static int davinci_eth_send_packet (struct eth_device *dev,
					void *packet, int length)
{
	int ret_status = -1;
	int index;
	tx_send_loop = 0;

	index = get_active_phy();
	if (index == -1) {
		printf(" WARN: emac_send_packet: No link\n");
		return (ret_status);
	}

	/* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
	if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
		length = EMAC_MIN_ETHERNET_PKT_SIZE;
	}

	/* Populate the TX descriptor */
	emac_tx_desc->next = 0;
	emac_tx_desc->buffer = (u_int8_t *) packet;
	emac_tx_desc->buff_off_len = (length & 0xffff);
	emac_tx_desc->pkt_flag_len = ((length & 0xffff) |
				      EMAC_CPPI_SOP_BIT |
				      EMAC_CPPI_OWNERSHIP_BIT |
				      EMAC_CPPI_EOP_BIT);

	flush_dcache_range((unsigned long)packet,
			   (unsigned long)packet + ALIGN(length, PKTALIGN));

	/* Send the packet */
	writel(BD_TO_HW((unsigned long)emac_tx_desc), &adap_emac->TX0HDP);

	/* Wait for packet to complete or link down */
	while (1) {
		if (!phy[index].get_link_speed(active_phy_addr[index])) {
			davinci_eth_ch_teardown (EMAC_CH_TX);
			return (ret_status);
		}

		if (readl(&adap_emac->TXINTSTATRAW) & 0x01) {
			ret_status = length;
			break;
		}
		tx_send_loop++;
	}

	return (ret_status);
}
예제 #3
0
/*
 * This function sends a single packet on the network and returns
 * positive number (number of bytes transmitted) or negative for error
 */
static int davinci_eth_send_packet (struct eth_device *dev,
					volatile void *packet, int length)
{
	int ret_status = -1;

	tx_send_loop = 0;

	/* Return error if no link */
	if (!phy.get_link_speed (active_phy_addr)) {
		printf ("WARN: emac_send_packet: No link\n");
		return (ret_status);
	}

	/* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
	if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
		length = EMAC_MIN_ETHERNET_PKT_SIZE;
	}

	/* Populate the TX descriptor */
	emac_tx_desc->next = 0;
	emac_tx_desc->buffer = (u_int8_t *) packet;
	emac_tx_desc->buff_off_len = (length & 0xffff);
	emac_tx_desc->pkt_flag_len = ((length & 0xffff) |
				      EMAC_CPPI_SOP_BIT |
				      EMAC_CPPI_OWNERSHIP_BIT |
				      EMAC_CPPI_EOP_BIT);
	/* Send the packet */
	adap_emac->TX0HDP = BD_TO_HW((unsigned int) emac_tx_desc);

	/* Wait for packet to complete or link down */
	while (1) {
		if (!phy.get_link_speed (active_phy_addr)) {
			davinci_eth_ch_teardown (EMAC_CH_TX);
			return (ret_status);
		}
		if (adap_emac->TXINTSTATRAW & 0x01) {
			ret_status = length;
			break;
		}
		tx_send_loop++;
	}

	return (ret_status);
}
예제 #4
0
/*
 * This function handles receipt of a packet from the network
 */
static int davinci_eth_rcv_packet (struct eth_device *dev)
{
	volatile emac_desc *rx_curr_desc;
	volatile emac_desc *curr_desc;
	volatile emac_desc *tail_desc;
	int status, ret = -1;

	rx_curr_desc = emac_rx_active_head;
	if (!rx_curr_desc)
		return 0;
	status = rx_curr_desc->pkt_flag_len;
	if ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0) {
		if (status & EMAC_CPPI_RX_ERROR_FRAME) {
			/* Error in packet - discard it and requeue desc */
			printf ("WARN: emac_rcv_pkt: Error in packet\n");
		} else {
			unsigned long tmp = (unsigned long)rx_curr_desc->buffer;
			unsigned short len =
				rx_curr_desc->buff_off_len & 0xffff;

			invalidate_dcache_range(tmp, tmp + ALIGN(len, PKTALIGN));
			net_process_received_packet(rx_curr_desc->buffer, len);
			ret = len;
		}

		/* Ack received packet descriptor */
		writel(BD_TO_HW((ulong)rx_curr_desc), &adap_emac->RX0CP);
		curr_desc = rx_curr_desc;
		emac_rx_active_head =
			(volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next));

		if (status & EMAC_CPPI_EOQ_BIT) {
			if (emac_rx_active_head) {
				writel(BD_TO_HW((ulong)emac_rx_active_head),
				       &adap_emac->RX0HDP);
			} else {
				emac_rx_queue_active = 0;
				printf ("INFO:emac_rcv_packet: RX Queue not active\n");
			}
		}

		/* Recycle RX descriptor */
		rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
		rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
		rx_curr_desc->next = 0;

		if (emac_rx_active_head == 0) {
			printf ("INFO: emac_rcv_pkt: active queue head = 0\n");
			emac_rx_active_head = curr_desc;
			emac_rx_active_tail = curr_desc;
			if (emac_rx_queue_active != 0) {
				writel(BD_TO_HW((ulong)emac_rx_active_head),
				       &adap_emac->RX0HDP);
				printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
				emac_rx_queue_active = 1;
			}
		} else {
			tail_desc = emac_rx_active_tail;
			emac_rx_active_tail = curr_desc;
			tail_desc->next = BD_TO_HW((ulong) curr_desc);
			status = tail_desc->pkt_flag_len;
			if (status & EMAC_CPPI_EOQ_BIT) {
				writel(BD_TO_HW((ulong)curr_desc),
				       &adap_emac->RX0HDP);
				status &= ~EMAC_CPPI_EOQ_BIT;
				tail_desc->pkt_flag_len = status;
			}
		}
		return (ret);
	}
	return (0);
}
예제 #5
0
/* Eth device open */
static int davinci_eth_open(struct eth_device *dev, bd_t *bis)
{
	dv_reg_p		addr;
	u_int32_t		clkdiv, cnt, mac_control;
	uint16_t		__maybe_unused lpa_val;
	volatile emac_desc	*rx_desc;
	int			index;

	debug_emac("+ emac_open\n");

	/* Reset EMAC module and disable interrupts in wrapper */
	writel(1, &adap_emac->SOFTRESET);
	while (readl(&adap_emac->SOFTRESET) != 0)
		;
#if defined(DAVINCI_EMAC_VERSION2)
	writel(1, &adap_ewrap->softrst);
	while (readl(&adap_ewrap->softrst) != 0)
		;
#else
	writel(0, &adap_ewrap->EWCTL);
	for (cnt = 0; cnt < 5; cnt++) {
		clkdiv = readl(&adap_ewrap->EWCTL);
	}
#endif

#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
	defined(CONFIG_MACH_DAVINCI_DA850_EVM)
	adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0;
	adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0;
	adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0;
#endif
	rx_desc = emac_rx_desc;

	writel(1, &adap_emac->TXCONTROL);
	writel(1, &adap_emac->RXCONTROL);

	davinci_eth_set_mac_addr(dev);

	/* Set DMA 8 TX / 8 RX Head pointers to 0 */
	addr = &adap_emac->TX0HDP;
	for (cnt = 0; cnt < 8; cnt++)
		writel(0, addr++);

	addr = &adap_emac->RX0HDP;
	for (cnt = 0; cnt < 8; cnt++)
		writel(0, addr++);

	/* Clear Statistics (do this before setting MacControl register) */
	addr = &adap_emac->RXGOODFRAMES;
	for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
		writel(0, addr++);

	/* No multicast addressing */
	writel(0, &adap_emac->MACHASH1);
	writel(0, &adap_emac->MACHASH2);

	/* Create RX queue and set receive process in place */
	emac_rx_active_head = emac_rx_desc;
	for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
		rx_desc->next = BD_TO_HW((u_int32_t)(rx_desc + 1));
		rx_desc->buffer = &emac_rx_buffers[cnt * EMAC_RXBUF_SIZE];
		rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
		rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
		rx_desc++;
	}

	/* Finalize the rx desc list */
	rx_desc--;
	rx_desc->next = 0;
	emac_rx_active_tail = rx_desc;
	emac_rx_queue_active = 1;

	/* Enable TX/RX */
	writel(EMAC_MAX_ETHERNET_PKT_SIZE, &adap_emac->RXMAXLEN);
	writel(0, &adap_emac->RXBUFFEROFFSET);

	/*
	 * No fancy configs - Use this for promiscous debug
	 *   - EMAC_RXMBPENABLE_RXCAFEN_ENABLE
	 */
	writel(EMAC_RXMBPENABLE_RXBROADEN, &adap_emac->RXMBPENABLE);

	/* Enable ch 0 only */
	writel(1, &adap_emac->RXUNICASTSET);

	/* Init MDIO & get link state */
	clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV;
	writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
	       &adap_mdio->CONTROL);

	/* We need to wait for MDIO to start */
	udelay(1000);

	index = get_active_phy();
	if (index == -1)
		return(0);

	/* Enable MII interface */
	mac_control = EMAC_MACCONTROL_MIIEN_ENABLE;
#ifdef DAVINCI_EMAC_GIG_ENABLE
	davinci_eth_phy_read(active_phy_addr[index], MII_STAT1000, &lpa_val);
	if (lpa_val & PHY_1000BTSR_1000FD) {
		debug_emac("eth_open : gigabit negotiated\n");
		mac_control |= EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
		mac_control |= EMAC_MACCONTROL_GIGABIT_ENABLE;
	}
#endif

	davinci_eth_phy_read(active_phy_addr[index], MII_LPA, &lpa_val);
	if (lpa_val & (LPA_100FULL | LPA_10FULL))
		/* set EMAC for Full Duplex  */
		mac_control |= EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
#if defined(CONFIG_SOC_DA8XX) || \
	(defined(CONFIG_OMAP34XX) && defined(CONFIG_DRIVER_TI_EMAC_USE_RMII))
	mac_control |= EMAC_MACCONTROL_RMIISPEED_100;
#endif
	writel(mac_control, &adap_emac->MACCONTROL);
	/* Start receive process */
	writel(BD_TO_HW((u_int32_t)emac_rx_desc), &adap_emac->RX0HDP);

	debug_emac("- emac_open\n");

	return(1);
}
예제 #6
0
/*
 * This function handles receipt of a packet from the network
 */
static int davinci_eth_rcv_packet (struct eth_device *dev)
{
	volatile emac_desc *rx_curr_desc;
	volatile emac_desc *curr_desc;
	volatile emac_desc *tail_desc;
	int status, ret = -1;

	rx_curr_desc = emac_rx_active_head;
	status = rx_curr_desc->pkt_flag_len;
	if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
		if (status & EMAC_CPPI_RX_ERROR_FRAME) {
			/* Error in packet - discard it and requeue desc */
			printf ("WARN: emac_rcv_pkt: Error in packet\n");
		} else {
			NetReceive (rx_curr_desc->buffer,
				    (rx_curr_desc->buff_off_len & 0xffff));
			ret = rx_curr_desc->buff_off_len & 0xffff;
		}

		/* Ack received packet descriptor */
		adap_emac->RX0CP = BD_TO_HW((unsigned int) rx_curr_desc);
		curr_desc = rx_curr_desc;
		emac_rx_active_head =
			(volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next));

		if (status & EMAC_CPPI_EOQ_BIT) {
			if (emac_rx_active_head) {
				adap_emac->RX0HDP =
				BD_TO_HW((unsigned int) emac_rx_active_head);
			} else {
				emac_rx_queue_active = 0;
				printf ("INFO:emac_rcv_packet: RX Queue not active\n");
			}
		}

		/* Recycle RX descriptor */
		rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
		rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
		rx_curr_desc->next = 0;

		if (emac_rx_active_head == 0) {
			printf ("INFO: emac_rcv_pkt: active queue head = 0\n");
			emac_rx_active_head = curr_desc;
			emac_rx_active_tail = curr_desc;
			if (emac_rx_queue_active != 0) {
				adap_emac->RX0HDP =
					BD_TO_HW((unsigned int) emac_rx_active_head);
				printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
				emac_rx_queue_active = 1;
			}
		} else {
			tail_desc = emac_rx_active_tail;
			emac_rx_active_tail = curr_desc;
			tail_desc->next = BD_TO_HW((unsigned int) curr_desc);
			status = tail_desc->pkt_flag_len;
			if (status & EMAC_CPPI_EOQ_BIT) {
				adap_emac->RX0HDP = BD_TO_HW((unsigned int) curr_desc);
				status &= ~EMAC_CPPI_EOQ_BIT;
				tail_desc->pkt_flag_len = status;
			}
		}
		return (ret);
	}

	return (0);
}
예제 #7
0
/* Eth device open */
static int davinci_eth_open(struct eth_device *dev, bd_t *bis)
{
	dv_reg_p		addr;
	u_int32_t		clkdiv, cnt;
	volatile emac_desc	*rx_desc;
	u_int16_t		lpa_val;

	debug_emac("+ emac_open\n");

	/* Reset EMAC module and disable interrupts in wrapper */
	adap_emac->SOFTRESET = 1;
	while (adap_emac->SOFTRESET != 0) {;}

#if (defined(CONFIG_SOC_DM646x) || defined(CONFIG_SOC_DM365) || \
     defined(CONFIG_OMAP3_AM3517EVM) || defined(CONFIG_OMAP3_AM3517CRANE))

	adap_ewrap->SOFTRST = 1;
	while (adap_ewrap->SOFTRST != 0) {;}
#else
	adap_ewrap->EWCTL = 0;
	for (cnt = 0; cnt < 5; cnt++) {
		clkdiv = adap_ewrap->EWCTL;
	}
#endif

	rx_desc = emac_rx_desc;

	adap_emac->TXCONTROL = 0x01;
	adap_emac->RXCONTROL = 0x01;

	/* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */
	/* Using channel 0 only - other channels are disabled */
	adap_emac->MACINDEX = 0;
	adap_emac->MACADDRHI =
		(davinci_eth_mac_addr[3] << 24) |
		(davinci_eth_mac_addr[2] << 16) |
		(davinci_eth_mac_addr[1] << 8)  |
		(davinci_eth_mac_addr[0]);
#if (defined(CONFIG_SOC_DM646x) || defined(CONFIG_SOC_DM365) || \
     defined(CONFIG_OMAP3_AM3517EVM) || defined(CONFIG_OMAP3_AM3517CRANE))
	adap_emac->MACADDRLO =
		(davinci_eth_mac_addr[5] << 8) |
		(davinci_eth_mac_addr[4]| (1 << 19) | (1 << 20));
#else
	adap_emac->MACADDRLO =
		(davinci_eth_mac_addr[5] << 8) |
		(davinci_eth_mac_addr[4]);
#endif

	adap_emac->MACHASH1 = 0;
	adap_emac->MACHASH2 = 0;

	/* Set source MAC address - REQUIRED */
	adap_emac->MACSRCADDRHI =
		(davinci_eth_mac_addr[3] << 24) |
		(davinci_eth_mac_addr[2] << 16) |
		(davinci_eth_mac_addr[1] << 8)  |
		(davinci_eth_mac_addr[0]);
	adap_emac->MACSRCADDRLO =
		(davinci_eth_mac_addr[4] << 8) |
		(davinci_eth_mac_addr[5]);

	/* Set DMA 8 TX / 8 RX Head pointers to 0 */
	addr = &adap_emac->TX0HDP;
	for(cnt = 0; cnt < 16; cnt++)
		*addr++ = 0;
	addr = &adap_emac->RX0HDP;
	for(cnt = 0; cnt < 16; cnt++)
		*addr++ = 0;

	/* Clear Statistics (do this before setting MacControl register) */
	addr = &adap_emac->RXGOODFRAMES;
	for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
		*addr++ = 0;

	/* No multicast addressing */
	adap_emac->MACHASH1 = 0;
	adap_emac->MACHASH2 = 0;

	/* Create RX queue and set receive process in place */
	emac_rx_active_head = emac_rx_desc;
	for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
		rx_desc->next = BD_TO_HW((u_int32_t)(rx_desc + 1));
		rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
		rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
		rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
		rx_desc++;
	}

	/* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
	rx_desc--;
	rx_desc->next = 0;
	emac_rx_active_tail = rx_desc;
	emac_rx_queue_active = 1;

	/* Enable TX/RX */
	adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE;
	adap_emac->RXBUFFEROFFSET = 0;

	/* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
	adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN;

	/* Enable ch 0 only */
	adap_emac->RXUNICASTSET = 0x01;

	/* Init MDIO & get link state */
	clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
	adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT);

	if (!phy.auto_negotiate(active_phy_addr))
		return(0);

	davinci_eth_phy_read(active_phy_addr,PHY_ANLPAR,&lpa_val);
	if (lpa_val & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD) ) {
		/* set EMAC for Full Duplex  */
		adap_emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE |
					 EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
	}else{
		/*set EMAC for Half Duplex  */
		adap_emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
	}

#ifdef CONFIG_DRIVER_TI_EMAC_USE_RMII
	if (lpa_val & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX) ) {
		adap_emac->MACCONTROL |= EMAC_MACCONTROL_RMIISPEED_100;
	} else {
		adap_emac->MACCONTROL &= ~EMAC_MACCONTROL_RMIISPEED_100;
	}
#endif

	/* Start receive process */
	adap_emac->RX0HDP = BD_TO_HW((u_int32_t)emac_rx_desc);

	debug_emac("- emac_open\n");

	return(1);
}
예제 #8
0
/*
 * This function handles receipt of a packet from the network
 */
static int davinci_emac_recv(struct eth_device *edev)
{
	struct davinci_emac_priv *priv = edev->priv;
	void __iomem *rx_curr_desc, *curr_desc, *tail_desc;
	unsigned char *pkt;
	int status, len, ret = -1;

	dev_dbg(priv->dev, "+ emac_recv\n");

	rx_curr_desc = priv->emac_rx_active_head;
	status = readl(rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN);
	if (status & EMAC_CPPI_OWNERSHIP_BIT) {
		ret = 0;
		goto out;
	}

	if (status & EMAC_CPPI_RX_ERROR_FRAME) {
		/* Error in packet - discard it and requeue desc */
		dev_warn(priv->dev, "WARN: emac_rcv_pkt: Error in packet\n");
	} else {
		pkt = (unsigned char *)readl(rx_curr_desc + EMAC_DESC_BUFFER);
		len = readl(rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN) & 0xffff;
		dev_dbg(priv->dev, "| emac_recv got packet (length %i)\n", len);
		dma_sync_single_for_cpu((unsigned long)pkt, len, DMA_FROM_DEVICE);
		net_receive(edev, pkt, len);
		dma_sync_single_for_device((unsigned long)pkt, len, DMA_FROM_DEVICE);
		ret = len;
	}

	/* Ack received packet descriptor */
	writel(BD_TO_HW(rx_curr_desc), priv->adap_emac + EMAC_RX0CP);
	curr_desc = rx_curr_desc;
	priv->emac_rx_active_head = HW_TO_BD(readl(rx_curr_desc + EMAC_DESC_NEXT));

	if (status & EMAC_CPPI_EOQ_BIT) {
		if (priv->emac_rx_active_head) {
			writel(BD_TO_HW(priv->emac_rx_active_head),
				priv->adap_emac + EMAC_RX0HDP);
		} else {
			priv->emac_rx_queue_active = 0;
			dev_info(priv->dev, "INFO:emac_rcv_packet: RX Queue not active\n");
		}
	}

	/* Recycle RX descriptor */
	writel(EMAC_MAX_ETHERNET_PKT_SIZE, rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN);
	writel(EMAC_CPPI_OWNERSHIP_BIT, rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN);
	writel(0, rx_curr_desc + EMAC_DESC_NEXT);

	if (priv->emac_rx_active_head == 0) {
		dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0\n");
		priv->emac_rx_active_head = curr_desc;
		priv->emac_rx_active_tail = curr_desc;
		if (priv->emac_rx_queue_active != 0) {
			writel(BD_TO_HW(priv->emac_rx_active_head), priv->adap_emac + EMAC_RX0HDP);
			dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
			priv->emac_rx_queue_active = 1;
		}
	} else {
		tail_desc = priv->emac_rx_active_tail;
		priv->emac_rx_active_tail = curr_desc;
		writel(BD_TO_HW(curr_desc), tail_desc + EMAC_DESC_NEXT);
		status = readl(tail_desc + EMAC_DESC_PKT_FLAG_LEN);
		if (status & EMAC_CPPI_EOQ_BIT) {
			writel(BD_TO_HW(curr_desc), priv->adap_emac + EMAC_RX0HDP);
			status &= ~EMAC_CPPI_EOQ_BIT;
			writel(status, tail_desc + EMAC_DESC_PKT_FLAG_LEN);
		}
	}

out:
	dev_dbg(priv->dev, "- emac_recv\n");

	return ret;
}
예제 #9
0
static int davinci_emac_open(struct eth_device *edev)
{
	struct davinci_emac_priv *priv = edev->priv;
	uint32_t clkdiv, cnt;
	void __iomem *rx_desc;
	unsigned long mac_hi, mac_lo;
	int ret;

	dev_dbg(priv->dev, "+ emac_open\n");

	dev_dbg(priv->dev, "emac->TXIDVER: 0x%08x\n",
		readl(priv->adap_emac + EMAC_TXIDVER));
	dev_dbg(priv->dev, "emac->RXIDVER: 0x%08x\n",
		readl(priv->adap_emac + EMAC_RXIDVER));

	/* Reset EMAC module and disable interrupts in wrapper */
	writel(1, priv->adap_emac + EMAC_SOFTRESET);
	while (readl(priv->adap_emac + EMAC_SOFTRESET) != 0);
	writel(1, priv->adap_ewrap + EMAC_EWRAP_SOFTRESET);
	while (readl(priv->adap_ewrap + EMAC_EWRAP_SOFTRESET) != 0);

	writel(0, priv->adap_ewrap + EMAC_EWRAP_C0RXEN);
	writel(0, priv->adap_ewrap + EMAC_EWRAP_C1RXEN);
	writel(0, priv->adap_ewrap + EMAC_EWRAP_C2RXEN);
	writel(0, priv->adap_ewrap + EMAC_EWRAP_C0TXEN);
	writel(0, priv->adap_ewrap + EMAC_EWRAP_C1TXEN);
	writel(0, priv->adap_ewrap + EMAC_EWRAP_C2TXEN);
	writel(0, priv->adap_ewrap + EMAC_EWRAP_C0MISCEN);
	writel(0, priv->adap_ewrap + EMAC_EWRAP_C1MISCEN);
	writel(0, priv->adap_ewrap + EMAC_EWRAP_C2MISCEN);

	rx_desc = priv->emac_rx_desc;

	/*
	 * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast
	 * receive)
	 * Use channel 0 only - other channels are disabled
	 */
	writel(0, priv->adap_emac + EMAC_MACINDEX);
	mac_hi = (priv->mac_addr[3] << 24) |
		 (priv->mac_addr[2] << 16) |
		 (priv->mac_addr[1] << 8)  |
		 (priv->mac_addr[0]);
	mac_lo = (priv->mac_addr[5] << 8) |
		 (priv->mac_addr[4]);

	writel(mac_hi, priv->adap_emac + EMAC_MACADDRHI);
	writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH,
	       priv->adap_emac + EMAC_MACADDRLO);

	/* Set source MAC address - REQUIRED */
	writel(mac_hi, priv->adap_emac + EMAC_MACSRCADDRHI);
	writel(mac_lo, priv->adap_emac + EMAC_MACSRCADDRLO);

	/* Set DMA head and completion pointers to 0 */
	for(cnt = 0; cnt < 8; cnt++) {
		writel(0, (void *)priv->adap_emac + EMAC_TX0HDP + 4 * cnt);
		writel(0, (void *)priv->adap_emac + EMAC_RX0HDP + 4 * cnt);
		writel(0, (void *)priv->adap_emac + EMAC_TX0CP + 4 * cnt);
		writel(0, (void *)priv->adap_emac + EMAC_RX0CP + 4 * cnt);
	}

	/* Clear Statistics (do this before setting MacControl register) */
	for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
		writel(0, (void *)priv->adap_emac + EMAC_RXGOODFRAMES + 4 * cnt);

	/* No multicast addressing */
	writel(0, priv->adap_emac + EMAC_MACHASH1);
	writel(0, priv->adap_emac + EMAC_MACHASH2);

	writel(0x01, priv->adap_emac + EMAC_TXCONTROL);
	writel(0x01, priv->adap_emac + EMAC_RXCONTROL);

	/* Create RX queue and set receive process in place */
	priv->emac_rx_active_head = priv->emac_rx_desc;
	for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
		writel(BD_TO_HW(rx_desc + EMAC_DESC_SIZE), rx_desc + EMAC_DESC_NEXT);
		writel(&priv->emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)], rx_desc + EMAC_DESC_BUFFER);
		writel(EMAC_MAX_ETHERNET_PKT_SIZE, rx_desc + EMAC_DESC_BUFF_OFF_LEN);
		writel(EMAC_CPPI_OWNERSHIP_BIT, rx_desc + EMAC_DESC_PKT_FLAG_LEN);
		rx_desc += EMAC_DESC_SIZE;
	}

	/* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
	rx_desc -= EMAC_DESC_SIZE;
	writel(0, rx_desc + EMAC_DESC_NEXT);
	priv->emac_rx_active_tail = rx_desc;
	priv->emac_rx_queue_active = 1;

	/* Enable TX/RX */
	writel(EMAC_MAX_ETHERNET_PKT_SIZE, priv->adap_emac + EMAC_RXMAXLEN);
	writel(0, priv->adap_emac + EMAC_RXBUFFEROFFSET);

	/* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
	writel(EMAC_RXMBPENABLE_RXBROADEN, priv->adap_emac + EMAC_RXMBPENABLE);

	/* Enable ch 0 only */
	writel(0x01, priv->adap_emac + EMAC_RXUNICASTSET);

	/* Enable MII interface and full duplex mode (using RMMI) */
	writel((EMAC_MACCONTROL_MIIEN_ENABLE |
		EMAC_MACCONTROL_FULLDUPLEX_ENABLE |
		EMAC_MACCONTROL_RMIISPEED_100),
	       priv->adap_emac + EMAC_MACCONTROL);

	/* Init MDIO & get link state */
	clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
	writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
		priv->adap_mdio + EMAC_MDIO_CONTROL);

	/* Start receive process */
	writel(BD_TO_HW(priv->emac_rx_desc), priv->adap_emac + EMAC_RX0HDP);

	ret = phy_device_connect(edev, &priv->miibus, priv->phy_addr, NULL,
	                         priv->phy_flags, priv->interface);
	if (ret)
		return ret;

	dev_dbg(priv->dev, "- emac_open\n");

	return 0;
}