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