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 <j...@emlix.com>
> + *
> + * (C) Copyright 2008, DSPG Technologies GmbH, Germany
> + * (C) Copyright 2007, NXP Semiconductors Germany GmbH
> + * Matthias Wenzel, <n...@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 <j...@emlix.com>
> + *
> + * (C) Copyright 2008, DSPG Technologies GmbH, Germany
> + * (C) Copyright 2007, NXP Semiconductors Germany GmbH
> + * Matthias Wenzel, <n...@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
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to