
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