All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Warren <biggerbadderben@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [patch V3] [2/3] ip3912 network driver
Date: Sun, 08 Feb 2009 22:50:14 -0800	[thread overview]
Message-ID: <498FD226.7040505@gmail.com> (raw)
In-Reply-To: <20090104225616.40274804@schleppi.schoew.net>

Hi Jurgen,

Sorry for taking so long to review :(

J?rgen Sch?w wrote:
>  drivers/net/Makefile               |    1 +
>  drivers/net/ip3912.c               |  659 ++++++++++++++++++++++++++++++++++++
>  drivers/net/ip3912.h               |  174 ++++++++++
>
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 631336a..7c82880 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -69,6 +69,7 @@ COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o
>  COBJS-$(CONFIG_XILINX_EMAC) += xilinx_emac.o
>  COBJS-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
>  COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
> +COBJS-$(CONFIG_IP3912_ETHER) += ip3912.o
>   
Please use alphabetical order.  Would you mind putting the SH one in its 
proper place while there?
>  
>  COBJS	:= $(COBJS-y)
>  SRCS	:= $(COBJS:.o=.c)
> diff --git a/drivers/net/ip3912.c b/drivers/net/ip3912.c
> new file mode 100644
> index 0000000..399f0b7
> --- /dev/null
> +++ b/drivers/net/ip3912.c
> @@ -0,0 +1,659 @@
> +/*
> + * ip3912 ethernet driver (PNX8181 / firetux)
> + *
> + * (C) Copyright 2007-2009, emlix GmbH, Germany
> + * Juergen Schoew <js@emlix.com>
> + *
> + * (C) Copyright 2008, DSPG Technologies GmbH, Germany
> + * (C) Copyright 2007, NXP Semiconductors Germany GmbH
> + * Matthias Wenzel, <nxp@mazzoo.de>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <net.h>
> +#include <malloc.h>
> +
> +#include <asm/io.h>
> +
> +#include "ip3912.h"
> +#include <miiphy.h>
> +
> +#define ALIGN8	__attribute__ ((aligned(8)))
> +#define ALIGN4	__attribute__ ((aligned(4)))
> +
> +/* globals */
> +/* ETN rx */
> +ALIGN8 rx_descriptor_t	etn_rxdescriptor[CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER];
> +ALIGN8 rx_status_t	etn_rxstatus[CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER];
> +
> +/* ETN tx */
> +ALIGN8 tx_descriptor_t	etn_txdescriptor[CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER];
> +ALIGN4 tx_status_t	etn_txstatus[CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER];
> +
> +struct ip3912_device {
> +	unsigned int		etn_base;
> +	unsigned int		phy_base;
> +	unsigned char		nr;
>   
What is this 'nr' field?  I gather that it's some kind of overall 
ethernet device index?
> +	unsigned char		phy_addr;
> +	unsigned char		autonegotiate;
> +	unsigned char		speed;
> +	unsigned char		duplex;
> +	unsigned char		rmii;
> +
> +	const struct device	*dev;
> +	struct eth_device	*netdev;
> +};
> +
> +int ip3912_miiphy_write(char *devname, unsigned char addr,
> +				unsigned char reg, unsigned short value)
> +{
> +	int status = 1;
> +	int i = 0;
> +	struct eth_device *netdev;
> +	struct ip3912_device *ip3912;
> +
> +	netdev = eth_get_dev();
> +	ip3912 = netdev->priv;
> +
> +	reg &= 0x001f; /* 5 bit PHY register address */
> +
> +	writel(PHYADDR_TO_REG(addr) | reg, (void *)(ip3912->phy_base
> +								+ ETN_MADR));
> +	writel(value, (void *)(ip3912->phy_base + ETN_MWTD));
> +
>   
I find your format of writel(val, addr) to be counter-intuitive.  These 
functions usually are like: writel(addr, val)
> +	/* poll for done, max 100ms */
> +	while (status && i < 100000) {
> +		status = readl((void *)(ip3912->phy_base + ETN_MIND)) & 0x7;
> +		udelay(1);
> +		i++;
> +	}
> +
> +	if (status) {
> +		printf("ERROR: ip3912_miiphy_write(%d) = "
> +				"0x%x [phy_addr=%x]\n", reg, status, addr);
>   
Some print formatting trivia:  What does "%#04x" do?  Try it - I've been 
programming C for a long time and just found out about this one.
> +		return -1;
> +	} else {
> +		debug("### ip3912_miiphy_write(%2.d, 0x%4.4x) success after"
> +			" %d cycles [phy_addr=%x]###\n", reg, value, i, addr);
> +	}
> +
> +	return 0;
> +}
> +
> +int ip3912_miiphy_read(char *devname, unsigned char addr,
> +				unsigned char reg, unsigned short *value)
> +{
> +	int i = 0, status = 1;
> +	struct eth_device *netdev;
> +	struct ip3912_device *ip3912;
> +
> +	netdev = eth_get_dev();
> +	ip3912 = netdev->priv;
> +
> +	reg &= 0x001f; /* 5 bit PHY register address */
> +	writel(PHYADDR_TO_REG(addr) | reg, (void *)(ip3912->phy_base
> +								+ ETN_MADR));
> +	writel(0x00000001, (void *)(ip3912->phy_base + ETN_MCMD));
> +
> +	/* poll for done, max 100ms */
> +	while (status && i < 100000) {
> +		status = readl((void *)(ip3912->phy_base + ETN_MIND)) & 0x7;
> +		udelay(1);
> +		i++;
> +	}
> +
> +	*value = (unsigned short)readl((void *)(ip3912->phy_base + ETN_MRDD));
> +
> +	writel(0, (void *)(ip3912->phy_base + ETN_MCMD));	/* stop MII */
> +
> +	if (status) {
> +		printf("ERROR: ip3912_miiphy_read(%d) = 0x%x after %d cycles "
> +			"[phy_addr=%x]\n", reg, *value, i, ip3912->phy_addr);
> +		return -1;
> +	} else {
> +		debug("### ip3912_phy_read(%2.d)=0x%4.4x success after %d "
> +					"cycles [phy_addr=%x]###\n",
> +				reg, *value, i, ip3912->phy_addr);
> +	}
> +
> +	return 0;
> +}
> +
> +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
> +int ip3912_mii_negotiate_phy(void)
> +{
> +	char *mode;
> +	int i;
> +	unsigned short value;
> +	struct eth_device *netdev;
> +	struct ip3912_device *ip3912;
> +
> +	netdev = eth_get_dev();
> +	ip3912 = netdev->priv;
> +
> +	/* only set phy if exists */
> +	ip3912_miiphy_read(netdev->name, ip3912->phy_addr,
> +							PHY_PHYIDR1, &value);
> +	if (value  == 0xffff)
> +		return -1;
> +
> +	/* get mode from environment */
> +	mode = getenv("phymode");
>   
You use the environment for storing a forced PHY mode?  Other parts of 
this driver indicate that there can either be more than one or that it 
can exist with other controllers.  In that case, "phymode" isn't a very 
good name.
> +	if (mode  != NULL) {
> +		if (0 == strcmp(mode, "auto")) {
> +			ip3912->autonegotiate = 1;
> +			ip3912->speed = 100;
> +			ip3912->duplex = 1;
> +		} else {
> +			if (0 == strcmp(mode, "100FD")) {
> +				ip3912->speed = 100;
> +				ip3912->duplex = 1;
> +			}
> +			if (0 == strcmp(mode, "100HD")) {
> +				ip3912->speed = 100;
> +				ip3912->duplex = 0;
> +			}
> +			if (0 == strcmp(mode, "10FD")) {
> +				ip3912->speed = 10;
> +				ip3912->duplex = 1;
> +			}
> +			if (0 == strcmp(mode, "10HD")) {
> +				ip3912->speed = 10;
> +				ip3912->duplex = 0;
> +			}
> +			ip3912->autonegotiate = 0;
> +		}
> +	} else {
> +		/* we use 10Mbit FD as fallback */
> +		ip3912->autonegotiate = 0;
> +		ip3912->speed = 10;
> +		ip3912->duplex = 1;
> +	}
>   
Wouldn't autonegotiation be the default?
> +
> +	/* do autonegotiation */
> +	if (ip3912->autonegotiate) {
> +		/* 10/100 and FD/HD mode supported, ieee802.3 */
> +		ip3912_miiphy_write(netdev->name, ip3912->phy_addr,
> +				ETN_PHY_AUTONEG_ADV, ((0xf << 5) | 1));
> +		/* force autorenegotiation */
> +		ip3912_miiphy_write(netdev->name, ip3912->phy_addr,
> +				ETN_PHY_BASIC_CONTROL, ((1 << 13) | (1 << 12) |
> +							 (1 << 9) | (1 << 8)));
> +	} else {
> +		/* only advertise the selected mode */
> +		i = 0x1e0;
> +		if (ip3912->speed == 100)
> +			i &= 0x180;
> +		else
> +			i &= 0x060;
> +		if (ip3912->duplex)
> +			i &= 0x140;
> +		else
> +			i &= 0x0a0;
>   
What are all these magic numbers?
> +		/* set advertise mode */
> +		ip3912_miiphy_write(netdev->name, ip3912->phy_addr,
> +						ETN_PHY_AUTONEG_ADV, (i|1));
> +		/* we set the phy parameter */
> +		ip3912_miiphy_write(netdev->name, ip3912->phy_addr,
> +			ETN_PHY_BASIC_CONTROL, ((ip3912->duplex ? (1<<8) : 0)
> +			| (1 << 9) | ((ip3912->speed == 100) ? (1 << 13) : 0)));
> +	}
> +
> +	/* wait for negotiation finished (max 3.5s) */
> +	i = 0;
> +	ip3912_miiphy_read(netdev->name, ip3912->phy_addr, ETN_PHY_BASIC_STATUS,
> +									&value);
> +	while (((value & (1 << 5)) == 0) && (i < 350)) {
> +		udelay(10000);
> +		i++;
> +		ip3912_miiphy_read(netdev->name, ip3912->phy_addr,
> +						 ETN_PHY_BASIC_STATUS, &value);
> +	}
> +	if (i == 350)
> +		puts("link negotiation timed out\n");
> +
> +
> +	/* check for link */
> +	if (value & (1 << 2)) {
> +		/* OK link present */
> +		ip3912_miiphy_read(netdev->name, ip3912->phy_addr,
> +				ETN_PHY_SPECIAL_MODE_CONTROL_STATUS, &value);
> +		ip3912->speed = (value & (1 << 2)) ? 10 : 100;
> +		ip3912->duplex = (value & (1 << 4)) ? 1 : 0;
> +	}
> +
> +	/* program the mac */
> +	writel((readl((void *)(ip3912->etn_base + ETN_SUPP)) & 0x000018fb) |
> +					((ip3912->speed == 100) ? (1 << 8) : 0),
> +					(void *)(ip3912->etn_base + ETN_SUPP));
> +	writel((readl((void *)(ip3912->etn_base + ETN_MAC2)) & 0x000073fe) |
> +			ip3912->duplex,	(void *)(ip3912->etn_base + ETN_MAC2))
Lots more magic numbers.  Please define in your header.
> ;
> +	/*
> +	 * release rx-path, tx-path, host registers reset
> +	 * set Duplex, enable RMII, enable rx+tx
> +	 * no flow control, no frames<64b
> +	 */
> +	writel(0x00000283 | (ip3912->duplex ? (1 << 10) : 0),
> +				(void *)(ip3912->etn_base + ETN_COMMAND));
> +
> +	udelay(100000);	/* the mac still needs some time to settle 100ms */
> +	ip3912_miiphy_read(netdev->name, ip3912->phy_addr,
> +				ETN_PHY_SPECIAL_MODE_CONTROL_STATUS, &value);
> +	printf(" %s %s negotiation", netdev->name,
> +				(value & (1 << 12)) ? "Auto" : "Manual");
> +	printf(" (10%s Mbit", (value & (1 << 3)) ? "0" : "");
> +	printf(" %sD", (value & (1 << 4)) ? "F" : "H");
> +	ip3912_miiphy_read(netdev->name, ip3912->phy_addr, ETN_PHY_BASIC_STATUS,
> +									&value);
> +	printf(" (%s)\n", (value & 1<<2)
> +			? "Link detected" : "No Link detected, trying anyway");
> +
> +	return 0;
> +}
> +
> +#if defined(CONFIG_DISCOVER_PHY)
> +int mii_discover_phy(void)
> +{
> +	unsigned short id1, id2;
> +	int phytype, phyno;
> +	struct eth_device *netdev;
> +	struct ip3912_device *ip3912;
> +
> +	netdev = eth_get_dev();
> +	ip3912 = netdev->priv;
> +
> +	for (phyno = 0; phyno <= 31 ; ++phyno) {
> +		ip3912_miiphy_read(netdev->name, phyno, PHY_PHYIDR1, &id1);
> +		if (id1 != 0xffff) {
> +			ip3912_miiphy_read(netdev->name, phyno, PHY_PHYIDR2,
> +								&id2);
> +			phytype = ((id1 << 16) | id2);
> +			puts("Using Transceiver: ");
> +			switch (phytype & 0xfffffff0) {
> +			case PHY_ID_LXT970:
> +						puts("LXT970");
> +						break;
> +			case PHY_ID_LXT971:
> +						puts("LXT971");
> +						break;
> +			case PHY_ID_82555:
> +						puts("82555");
> +						break;
> +			case PHY_ID_QS6612:
> +						puts("QS6612");
> +						break;
> +			case PHY_ID_AMD79C784:
> +						puts("AMD79C784");
> +						break;
> +			case PHY_ID_LSI80225:
> +						puts("LSI L80225");
> +						break;
> +			case PHY_ID_LSI80225B:
> +						puts("LSI L80225/B");
> +						break;
> +			case PHY_ID_DM9161:
> +						puts("Davicom DM9161");
> +						break;
> +			case PHY_ID_KSM8995M:
> +						puts("MICREL KS8995M");
> +						break;
> +			case PHY_ID_SMSC8700:
> +						puts("SMSC Lan 8700");
> +						break;
> +			default:
> +						printf("0x%08x", phytype);
> +						break;
> +		}
> +	    }
> +	}
> +
> +	return 0;
> +}
> +#endif /* CONFIG_DISCOVER_PHY */
> +
> +#endif /* defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
> +
> +int ip3912_miiphy_initialize(bd_t *bis)
> +{
> +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
> +	miiphy_register("ip3912", ip3912_miiphy_read, ip3912_miiphy_write);
> +#endif
> +	return 0;
> +}
> +
> +static int ip3912_init_descriptors(struct eth_device *netdev)
> +{
> +	struct ip3912_device *ip3912;
> +	static void *rxbuf;
> +	int i;
> +
> +	ip3912 = netdev->priv;
> +
> +	/* fill in pointer in regs */
> +	writel((unsigned long)etn_rxdescriptor, (void *)(ip3912->etn_base
> +							+ ETN_RXDESCRIPTOR));
> +	writel((unsigned long)etn_rxstatus, (void *)(ip3912->etn_base
> +							+ ETN_RXSTATUS));
> +	writel(0x00000000, (void *)(ip3912->etn_base + ETN_RXCONSUMEINDEX));
> +	writel(CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER - 1,
> +				(void *)(ip3912->etn_base
> +						+ ETN_RXDESCRIPTORNUMBER));
> +
> +	writel((unsigned long)etn_txdescriptor,	(void *)(ip3912->etn_base
> +							+ ETN_TXDESCRIPTOR));
> +	writel((unsigned long)etn_txstatus, (void *)(ip3912->etn_base
> +							+ ETN_TXSTATUS));
> +	writel(0x00000000, (void *)(ip3912->etn_base + ETN_TXPRODUCEINDEX));
> +	writel(CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER - 1,
> +			(void *)(ip3912->etn_base + ETN_TXDESCRIPTORNUMBER));
> +
> +	/* allocate rx-buffers, but only once, we're called multiple times! */
> +	if (!rxbuf)
> +		rxbuf = malloc(MAX_ETH_FRAME_SIZE
> +					* CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER);
> +	if (!rxbuf) {
> +		puts("ERROR: couldn't allocate rx buffers!\n");
> +		return -1;
> +	}
> +
> +	for (i = 0; i < CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER; i++) {
> +		etn_rxdescriptor[i].packet = rxbuf + i * MAX_ETH_FRAME_SIZE;
> +		etn_rxdescriptor[i].control = MAX_ETH_FRAME_SIZE
> +						- sizeof(unsigned long);
> +		etn_rxstatus[i].info = 0;
> +		etn_rxstatus[i].hashCRC = 0;
> +	}
> +
> +	for (i = 0; i < CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER; i++) {
> +		etn_txdescriptor[i].packet = 0;
> +		etn_txdescriptor[i].control = 0;
> +		etn_txstatus[i].info = 0;
> +	}
> +	return 0;
> +}
> +
> +void ip3912_setmac(struct eth_device *netdev)
> +{
> +	struct ip3912_device *ip3912;
> +	unsigned char i, use_etn1addr = 0;
> +	char *mac_string, *pmac, *end;
> +	char tmp[18];
> +
> +	ip3912 = netdev->priv;
> +
> +	mac_string = getenv("ethaddr");
> +
> +	if (ip3912->nr) {
> +		/* we use ETN2 */
> +		mac_string = getenv("eth1addr");
>   
> +		if (!mac_string) {
> +			mac_string = getenv("ethaddr");
>   
Why would you allow this?
> +			use_etn1addr = 1;
> +		}
> +	}
> +
> +	pmac = mac_string;
> +	for (i = 0; i < 6; i++) {
> +		netdev->enetaddr[i] = pmac ? simple_strtoul(pmac, &end, 16) : 0;
> +		if (pmac)
> +			pmac = (*end) ? end + 1 : end;
> +	}
> +
> +	if (use_etn1addr) {
> +		/* flip last bit of mac address */
> +		debug("ip3912_setmac %s flipping last bit\n", netdev->name);
> +		if (netdev->enetaddr[5] & 1)
> +			netdev->enetaddr[5] &= 0xfe;
> +		else
> +			netdev->enetaddr[5] |= 0x01;
>   
What's this all about?  Please add comments to explain why you're 
flipping this bit.
> +		sprintf(tmp, "%02X:%02X:%02X:%02X:%02X:%02X",
> +			 netdev->enetaddr[0], netdev->enetaddr[1],
> +			 netdev->enetaddr[2], netdev->enetaddr[3],
> +			 netdev->enetaddr[4], netdev->enetaddr[5]);
> +		setenv("eth1addr", tmp);
> +		mac_string = tmp;
> +	}
> +
> +	debug("ip3912_setmac set %s to address %s\n", netdev->name, mac_string);
> +
> +	writel((netdev->enetaddr[5] << 8) | netdev->enetaddr[4],
> +					(void *)(ip3912->etn_base + ETN_SA0));
> +	writel((netdev->enetaddr[3] << 8) | netdev->enetaddr[2],
> +					(void *)(ip3912->etn_base + ETN_SA1));
> +	writel((netdev->enetaddr[1] << 8) | netdev->enetaddr[0],
> +					(void *)(ip3912->etn_base + ETN_SA2));
> +}
> +
> +int ip3912_macreset(void)
> +{
> +	struct eth_device *netdev;
> +	struct ip3912_device *ip3912;
> +
> +	netdev = eth_get_dev();
> +	ip3912 = netdev->priv;
> +
> +	debug("ip3912_macreset resetting %s\n", netdev->name);
> +
> +	/* reset MAC layer */
> +	writel(0x0000cf00, (void *)(ip3912->etn_base + ETN_MAC1));
> +	/* release MAC soft reset */
> +	writel(0x00000000, (void *)(ip3912->etn_base + ETN_MAC1));
> +	/* reset rx-path, tx-path, host registers */
> +	writel(0x00000038, (void *)(ip3912->etn_base + ETN_COMMAND));
> +	/* reset RMII, 100Mbps MAC, 10Mbps MAC */
> +	writel(0x1888, (void *)(ip3912->etn_base + ETN_SUPP));
> +	writel(0x1000, (void *)(ip3912->etn_base + ETN_SUPP));
> +
> +	return 0;
> +}
> +
> +static int ip3912_init(struct eth_device *netdev, bd_t *bd)
> +{
> +	unsigned char i;
> +	struct ip3912_device *ip3912 = netdev->priv;
> +
> +	/* update mac address in boardinfo */
> +	ip3912_setmac(netdev);
> +	for (i = 0; i < 6 ; i++)
> +		bd->bi_enetaddr[i] = netdev->enetaddr[i];
> +
> +	/* before enabling the rx-path we need to set up rx-descriptors */
> +	if (ip3912_init_descriptors(netdev))
> +		return -1;
> +
> +	/* set max packet length to 1536 bytes */
> +	writel(MAX_ETH_FRAME_SIZE, (void *)(ip3912->etn_base + ETN_MAXF));
> +	/* full duplex */
> +	writel(0x00000023, (void *)(ip3912->etn_base + ETN_MAC2));
> +	/* inter packet gap register */
> +	writel(0x15, (void *)(ip3912->etn_base + ETN_IPGT));
> +	writel(0x12, (void *)(ip3912->etn_base + ETN_IPGR));
> +	/* enable rx, receive all frames */
> +	writel(0x00000003, (void *)(ip3912->etn_base + ETN_MAC1));
> +	/* accept all multicast, broadcast and station packets */
> +	writel(0x00000026, (void *)(ip3912->etn_base + ETN_RXFILTERCTRL));
> +
> +	/* reset MII mgmt, set MII clock */
> +	writel(0x0000801c, (void *)(ip3912->etn_base + ETN_MCFG));
> +	writel(0x0000001c, (void *)(ip3912->etn_base + ETN_MCFG));
> +
> +	/* release rx-path, tx-path, host registers reset
> +	 * set FullDuplex, enable RMMI, enable rx+tx
> +	 * no flow control, no frames<64b
> +	 */
> +	writel(0x00000683, (void *)(ip3912->etn_base + ETN_COMMAND));
> +	ip3912_init_descriptors(netdev);
> +
> +#ifdef CONFIG_DISCOVER_PHY
> +	mii_discover_phy();
> +#endif
> +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
> +	/* check autonegotiation */
> +	ip3912_mii_negotiate_phy();
> +#endif
> +	return 0;
> +}
> +
> +/* Send a packet */
> +static int ip3912_send(struct eth_device *netdev, volatile void *packet,
> +								int length)
> +{
> +	struct ip3912_device *ip3912 = netdev->priv;
> +	uint32_t next_packet;
> +	uint32_t this_packet;
> +	uint32_t last_packet;
> +
> +	if ((length > MAX_ETH_FRAME_SIZE) || (length <= 0)) {
> +		printf("ERROR: cannot transmit a %d bytes frame!\n", length);
> +		return -1;
> +	}
> +
> +	this_packet = readl((void *)(ip3912->etn_base + ETN_TXPRODUCEINDEX));
> +	next_packet = (this_packet + 1) % CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER;
> +	last_packet = readl((void *)(ip3912->etn_base + ETN_TXCONSUMEINDEX));
> +
> +#define ETN_TX_MAX_RETRY	1000000
> +	int i = 0;
> +	/* wait until the FIFO is ready to accept a new packet */
> +
> +	while ((this_packet == ((last_packet +
> +					CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER - 1)
> +					% CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER))
> +						&& (i < ETN_TX_MAX_RETRY)) {
> +#ifdef ET_DEBUG
> +		/* debug print when FIFO full*/
> +		if ((i > 50000) && (!(i % 50000))) {
> +			this_packet =
> +				readl((void *)(ip3912->etn_base
> +							+ ETN_TXPRODUCEINDEX));
> +			last_packet =
> +				readl((void *)(ip3912->etn_base
> +							+ ETN_TXCONSUMEINDEX));
> +			printf("this=%3.d, last=%3.d, i=%d\n",
> +						this_packet, last_packet, i);
> +		}
> +#endif
> +		i++;
> +		last_packet = readl((void *)(ip3912->etn_base
> +							+ ETN_TXCONSUMEINDEX));
> +	}
> +	if (i == ETN_TX_MAX_RETRY) {
> +		printf("tx FAILED after %d cycles\n", i);
> +		return -1;
> +	}
> +	if (i)
> +		printf("tx after %d cycles\n", i);
> +
> +	etn_txdescriptor[this_packet].packet  = packet;
> +	etn_txdescriptor[this_packet].control = (length - 1) |
> +		ETN_CONTROL_INTERRUPT | ETN_CONTROL_LAST;
> +
> +	/* let the HW know a new packet is ready */
> +	writel(next_packet, (void *)(ip3912->etn_base + ETN_TXPRODUCEINDEX));
> +
> +	return 0;
> +}
> +
> +/* Check for received packets */
> +static int ip3912_recv(struct eth_device *netdev)
> +{
> +	struct ip3912_device *ip3912 = netdev->priv;
> +
> +	unsigned short rxconsume = (unsigned short)
> +		(readl((void *)(ip3912->etn_base + ETN_RXCONSUMEINDEX)));
> +	unsigned short rxproduce = (unsigned short)
> +		(readl((void *)(ip3912->etn_base + ETN_RXPRODUCEINDEX)));
> +	unsigned short psize = 0;
> +
> +	debug("eth_rx: receive_rsv 0x%08x\n",
> +				readl((void *)(ip3912->etn_base + ETN_RSV)));
> +	debug("eth_rx: consume 0x%04x produce 0x%04x\n",
> +							rxconsume, rxproduce);
> +	while (rxconsume != rxproduce) {
> +		rxproduce = (unsigned short)(readl((void *)
> +				(ip3912->etn_base + ETN_RXPRODUCEINDEX)));
> +		psize = (etn_rxstatus[rxconsume].info & 0x07ff) + 1;
> +		if (psize > MAX_ETH_FRAME_SIZE) {
> +			printf("dropping %d bytes frame (too large)!\n",
> +									psize);
> +		} else {
> +			NetReceive(etn_rxdescriptor[rxconsume].packet, psize);
> +		}
> +		rxconsume = (rxconsume + 1)
> +					% CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER;
> +		writel(rxconsume,
> +			(void *)(ip3912->etn_base + ETN_RXCONSUMEINDEX));
> +	}
> +	return psize;
> +}
> +
> +static void ip3912_halt(struct eth_device *netdev)
> +{
> +	struct ip3912_device *ip3912 = netdev->priv;
> +
> +	/* disable rx-path, tx-path, host registers reset
> +	 * set FullDuplex, enable RMMI, disable rx+tx
> +	 * no flow control, no frames<64b
> +	 */
> +	writel(0x000006b8, (void *)(ip3912->etn_base + ETN_COMMAND));
>   
I know you comment it, but OR-ing bitfields is much easier to read than 
magic numbers
> +}
> +
> +int ip3912_eth_initialize(unsigned char nr, unsigned int etn_base,
> +	unsigned int phy_base, unsigned char phy_addr, unsigned char rmii)
> +{
> +	struct ip3912_device *ip3912;
> +	struct eth_device *netdev;
> +
> +	netdev = malloc(sizeof(struct eth_device));
> +	ip3912 = malloc(sizeof(struct ip3912_device));
> +	if ((!ip3912) || (!netdev)) {
> +		printf("Error: Failed to allocate memory for ETN%d\n", nr + 1);
> +		return -1;
> +	}
> +
> +	memset(ip3912, 0, sizeof(struct ip3912_device));
> +	memset(netdev, 0, sizeof(struct eth_device));
> +
> +	ip3912->nr = nr;
> +	ip3912->etn_base = etn_base;
> +	ip3912->phy_base = phy_base;
> +	ip3912->phy_addr = phy_addr;
> +	ip3912->autonegotiate = 0;
> +	ip3912->rmii = rmii;
> +	ip3912->speed = 0;
> +	ip3912->duplex = 0;
> +	ip3912->netdev = netdev;
> +
> +	sprintf(netdev->name, "ETN%d", nr + 1);
> +	netdev->init = ip3912_init;
> +	netdev->send = ip3912_send;
> +	netdev->recv = ip3912_recv;
> +	netdev->halt = ip3912_halt;
> +	netdev->priv = (void *)ip3912;
> +
> +
> +	eth_register(netdev);
> +	ip3912_macreset();
> +	/* we have to set the mac address, because we have no SROM */
> +	ip3912_setmac(netdev);
> +
> +	return 0;
> +}
> diff --git a/drivers/net/ip3912.h b/drivers/net/ip3912.h
> new file mode 100644
> index 0000000..f6343a0
> --- /dev/null
> +++ b/drivers/net/ip3912.h
> @@ -0,0 +1,174 @@
> +/*
> + * ip3912 ethernet driver interface (PNX8181 / firetux)
> + *
> + * (C) Copyright 2007-2009, emlix GmbH, Germany
> + * Juergen Schoew <js@emlix.com>
> + *
> + * (C) Copyright 2008, DSPG Technologies GmbH, Germany
> + * (C) Copyright 2007, NXP Semiconductors Germany GmbH
> + * Matthias Wenzel, <nxp@mazzoo.de>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +/* exported ethernet functions */
> +int mii_discover_phy(void);
> +
> +#define PHYADDR_TO_REG(x)			(x << 8)
> +
> +/* data types */
> +
> +/* rx */
> +typedef struct{
> +	volatile void *packet;
> +	volatile unsigned long control;
> +} rx_descriptor_t;
> +
> +typedef struct{
> +	volatile unsigned long info;		/* RO */
> +	volatile unsigned long hashCRC;		/* RO */
> +} rx_status_t;
> +
> +/* tx */
> +typedef struct{
> +	volatile void *packet;
> +	volatile unsigned long control;
> +} tx_descriptor_t;
> +
> +typedef struct{
> +	volatile unsigned long info;		/* RO */
> +} tx_status_t;
> +
> +/* NXP's OUI registered @ IEEE  */
> +#define NXP_ETN_OUI			0x006037
> +
> +/* ip3912 ETN registers */
> +#define ETN1_BASE			CONFIG_IP3912_ETN1_BASE
> +#define ETN2_BASE			CONFIG_IP3912_ETN2_BASE
> +
> +/* offsets to base address */
> +#define ETN_MAC1			0x0000
> +#define ETN_MAC2			0x0004
> +#define ETN_IPGT			0x0008
> +#define ETN_IPGR			0x000c
> +#define ETN_CLRT			0x0010
> +#define ETN_MAXF			0x0014
> +#define ETN_SUPP			0x0018
> +#define ETN_TEST			0x001c
> +#define ETN_MCFG			0x0020
> +#define ETN_MCMD			0x0024
> +#define ETN_MADR			0x0028
> +#define ETN_MWTD			0x002c
> +#define ETN_MRDD			0x0030
> +#define ETN_MIND			0x0034
> +#define ETN_SA0				0x0040
> +#define ETN_SA1				0x0044
> +#define ETN_SA2				0x0048
> +#define ETN_COMMAND			0x0100
> +#define ETN_STATUS			0x0104
> +#define ETN_RXDESCRIPTOR		0x0108
> +#define ETN_RXSTATUS			0x010c
> +#define ETN_RXDESCRIPTORNUMBER		0x0110
> +#define ETN_RXPRODUCEINDEX		0x0114
> +#define ETN_RXCONSUMEINDEX		0x0118
> +#define ETN_TXDESCRIPTOR		0x011c
> +#define ETN_TXSTATUS			0x0120
> +#define ETN_TXDESCRIPTORNUMBER		0x0124
> +#define ETN_TXPRODUCEINDEX		0x0128
> +#define ETN_TXCONSUMEINDEX		0x012c
> +#define ETN_TXRTDESCRIPTOR		0x0130
> +#define ETN_TXRTSTATUS			0x0134
> +#define ETN_TXRTDESCRIPTORNUMBER	0x0138
> +#define ETN_TXRTPRODUCEINDEX		0x013c
> +#define ETN_TXRTCONSUMEINDEX		0x0140
> +#define ETN_QOSTIMEOUT			0x0148
> +#define ETN_TSV0			0x0158
> +#define ETN_TSV1			0x015c
> +#define ETN_RSV				0x0160
> +#define ETN_FLOWCONTROLCOUNTER		0x0170
> +#define ETN_FLOWCONTROLSTATUS		0x0174
> +#define ETN_RXFILTERCTRL		0x0200
> +#define ETN_RXFILTERWOLSTATUS		0x0204
> +#define ETN_RXFILTERWOLCLEAR		0x0208
> +#define ETN_HASHFILTERL			0x0210
> +#define ETN_HASHFILTERH			0x0214
> +#define ETN_INTSTATUS			0x0fe0
> +#define ETN_INTENABLE			0x0fe4
> +#define ETN_INTCLEAR			0x0fe8
> +#define ETN_INTSET			0x0fec
> +#define ETN_POWERDOWN			0x0ff4
> +#define ETN_MODULEID			0x0ffc
> +
> +/* values for control */
> +#define ETN_CONTROL_INTERRUPT	0x80000000
> +#define ETN_CONTROL_LAST	0x40000000
> +#define ETN_CONTROL_CRC		0x20000000
> +#define ETN_CONTROL_PAD		0x10000000
> +#define ETN_CONTROL_HUGE	0x08000000
> +#define ETN_CONTROL_OVERRIDE	0x04000000
> +
> +/* registers in the SMSC LAN8700 PHY */
> +/*
> +00 Basic Control Register				Basic
> +01 Basic Status Register				Basic
> +02 PHY Identifier 1					Extended
> +03 PHY Identifier 2					Extended
> +04 Auto-Negotiation Advertisement Register		Extended
> +05 Auto-Negotiation Link Partner Ability Register	Extended
> +06 Auto-Negotiation Expansion Register			Extended
> +16 Silicon Revision Register				Vendor-specific
> +17 Mode Control/Status Register				Vendor-specific
> +18 Special Modes					Vendor-specific
> +20 Reserved						Vendor-specific
> +21 Reserved						Vendor-specific
> +22 Reserved						Vendor-specific
> +23 Reserved						Vendor-specific
> +27 Control / Status Indication Register			Vendor-specific
> +28 Special internal testability controls		Vendor-specific
> +29 Interrupt Source Register				Vendor-specific
> +30 Interrupt Mask Register				Vendor-specific
> +31 PHY Special Control/Status Register			Vendor-specific
> +*/
> +#define ETN_PHY_BASIC_CONTROL			0x00
> +#define ETN_PHY_BASIC_STATUS			0x01
> +#define ETN_PHY_ID1				0x02
> +#define ETN_PHY_ID2				0x03
> +#define ETN_PHY_AUTONEG_ADV			0x04
> +#define ETN_PHY_AUTONEG_LINK			0x05
> +#define ETN_PHY_AUTONEG_EXP			0x06
> +#define ETN_PHY_SILICON				0x10
> +#define ETN_PHY_MODE_CONTROL_STATUS		0x11
> +#define ETN_PHY_SPECIAL_MODES			0x12
> +#define ETN_PHY_CONTROL_STATUS_INDICATION	0x1b
> +#define ETN_PHY_INTERNAL_TESTABILITY		0x1c
> +#define ETN_PHY_INTERRUPT_SOURCE		0x1d
> +#define ETN_PHY_INTERRUPT_MASK			0x1e
> +#define ETN_PHY_SPECIAL_MODE_CONTROL_STATUS	0x1f
> +
> +/* PHY identification */
> +#define PHY_ID_LXT970		0x78100000	/* LXT970 */
> +#define PHY_ID_LXT971		0x001378e0	/* LXT971 and 972 */
> +#define PHY_ID_82555		0x02a80150	/* Intel 82555 */
> +#define PHY_ID_QS6612		0x01814400	/* QS6612 */
> +#define PHY_ID_AMD79C784	0x00225610	/* AMD 79C784 */
> +#define PHY_ID_LSI80225		0x0016f870	/* LSI 80225 */
> +#define PHY_ID_LSI80225B	0x0016f880	/* LSI 80225/B */
> +#define PHY_ID_DM9161		0x0181B880	/* Davicom DM9161 */
> +#define PHY_ID_KSM8995M		0x00221450	/* MICREL KS8995MA */
> +#define PHY_ID_SMSC8700		0x0007C0C0	/* SMSC LAN 8700 */
regards,
Ben

  parent reply	other threads:[~2009-02-09  6:50 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-04 21:50 [U-Boot] [patch V3] [0/3] U-Boot Firetux board support (PNX8181) Jürgen Schöw
2009-01-04 21:54 ` [U-Boot] [patch V3] [1/3] PNX8181 SOC support Jürgen Schöw
2009-02-06 22:18   ` Jean-Christophe PLAGNIOL-VILLARD
2009-02-08 12:26     ` Jürgen Schöw
2009-01-04 21:56 ` [U-Boot] [patch V3] [2/3] ip3912 network driver Jürgen Schöw
2009-02-06 22:19   ` Jean-Christophe PLAGNIOL-VILLARD
2009-02-06 22:23     ` Ben Warren
2009-02-08 12:32     ` Jürgen Schöw
2009-02-09  6:50   ` Ben Warren [this message]
2009-02-09 20:06   ` Wolfgang Denk
2009-01-04 21:58 ` [U-Boot] [patch V3] [3/3] firetux board support Jürgen Schöw
2009-02-06 22:26   ` Jean-Christophe PLAGNIOL-VILLARD
2009-02-09 20:07   ` Wolfgang Denk
2009-02-09 23:56     ` Jürgen Schöw
2009-02-10  0:03       ` Wolfgang Denk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=498FD226.7040505@gmail.com \
    --to=biggerbadderben@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.