From 091dc9f6adaf572b067ae91af92c4e7db33d7903 Mon Sep 17 00:00:00 2001 From: Zach LeRoy Date: Fri, 22 May 2009 10:26:33 -0500 Subject: tsec: Add support for BCM5482S PHY Signed-off-by: Zach LeRoy Acked-by: Kumar Gala Signed-off-by: Ben Warren --- drivers/net/tsec.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/tsec.h | 2 ++ 2 files changed, 43 insertions(+) diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 399116f..63fc02e 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -468,6 +468,18 @@ uint mii_parse_link(uint mii_reg, struct tsec_private *priv) } /* + * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain + * circumstances. eg a gigabit TSEC connected to a gigabit switch with + * a 4-wire ethernet cable. Both ends advertise gigabit, but can't + * link. "Ethernet@Wirespeed" reduces advertised speed until link + * can be achieved. + */ +uint mii_BCM54xx_wirespeed(uint mii_reg, struct tsec_private *priv) +{ + return (read_phy_reg(priv, mii_reg) & 0x8FFF) | 0x8010; +} + +/* * Parse the BCM54xx status register for speed and duplex information. * The linux sungem_phy has this information, but in a table format. */ @@ -1070,6 +1082,34 @@ struct phy_info phy_info_BCM5464S = { }, }; +struct phy_info phy_info_BCM5482S = { + 0x0143bcb, + "Broadcom BCM5482S", + 4, + (struct phy_cmd[]) { /* config */ + /* Reset and configure the PHY */ + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + /* Setup read from auxilary control shadow register 7 */ + {MIIM_BCM54xx_AUXCNTL, MIIM_BCM54xx_AUXCNTL_ENCODE(7), NULL}, + /* Read Misc Control register and or in Ethernet@Wirespeed */ + {MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed}, + {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + {miim_end,} + }, + (struct phy_cmd[]) { /* startup */ + /* Status is read once to clear old link state */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, + /* Read the status */ + {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, + {miim_end,} + }, + (struct phy_cmd[]) { /* shutdown */ + {miim_end,} + }, +}; + struct phy_info phy_info_M88E1011S = { 0x01410c6, "Marvell 88E1011S", @@ -1611,6 +1651,7 @@ struct phy_info *phy_info[] = { &phy_info_cis8201, &phy_info_BCM5461S, &phy_info_BCM5464S, + &phy_info_BCM5482S, &phy_info_M88E1011S, &phy_info_M88E1111S, &phy_info_M88E1118, diff --git a/include/tsec.h b/include/tsec.h index 9184256..0ac3034 100644 --- a/include/tsec.h +++ b/include/tsec.h @@ -152,6 +152,8 @@ #define MIIM_EXT_PAGE_ACCESS 0x1f /* Broadcom BCM54xx -- taken from linux sungem_phy */ +#define MIIM_BCM54xx_AUXCNTL 0x18 +#define MIIM_BCM54xx_AUXCNTL_ENCODE(val) ((val & 0x7) << 12)|(val & 0x7) #define MIIM_BCM54xx_AUXSTATUS 0x19 #define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK 0x0700 #define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT 8 -- cgit v1.1 From 6f51deb7f298413cfcb0a36d24c97ef7dd69d48f Mon Sep 17 00:00:00 2001 From: Prafulla Wadaskar Date: Tue, 19 May 2009 01:40:16 +0530 Subject: Marvell MV88E61XX Switch Driver support Chips supported:- 1. 88E6161 6 port gbe swtich with 5 integrated PHYs 2. 88E6165 6 port gbe swtich with 5 integrated PHYs 2. 88E6132 3 port gbe swtich with 2 integrated PHYs Platform specific configuration supported for:- default or router port vlan configuration led_init configuration mdip/n polarity reversal configuration Note: This driver is supported and tested against kirkwood egiga interface Contributors: Yotam Admon Michael Blostein Signed-off-by: Prafulla Wadaskar Signed-off-by: Ben Warren --- drivers/net/phy/Makefile | 1 + drivers/net/phy/mv88e61xx.c | 413 ++++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/mv88e61xx.h | 62 +++++++ include/netdev.h | 47 +++++ 4 files changed, 523 insertions(+) create mode 100644 drivers/net/phy/mv88e61xx.c create mode 100644 drivers/net/phy/mv88e61xx.h diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 4fe3b05..3b92614 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libphy.a COBJS-$(CONFIG_BITBANGMII) += miiphybb.o +COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c new file mode 100644 index 0000000..ec47286 --- /dev/null +++ b/drivers/net/phy/mv88e61xx.c @@ -0,0 +1,413 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor + * Prafulla Wadaskar + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include "mv88e61xx.h" + +#ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE +/* Chip Address mode + * The Switch support two modes of operation + * 1. single chip mode and + * 2. Multi-chip mode + * Refer section 9.2 &9.3 in chip datasheet-02 for more details + * + * By default single chip mode is configured + * multichip mode operation can be configured in board header + */ +static int mv88e61xx_busychk_multic(u32 devaddr) +{ + u32 reg = 0; + u32 timeout = MV88E61XX_PHY_TIMEOUT; + + /* Poll till SMIBusy bit is clear */ + do { + miiphy_read(name, devaddr, 0x0, ®); + if (timeout-- == 0) { + printf("SMI busy timeout\n"); + return -1; + } + } while (reg & (1 << 15)); + return 0; +} + +static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) +{ + u16 reg; + u32 mii_dev_addr; + + /* command to read PHY dev address */ + if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { + printf("Error..could not read PHY dev address\n"); + return; + } + mv88e61xx_busychk_multic(mii_dev_addr); + /* Write data to Switch indirect data register */ + miiphy_write(name, mii_dev_addr, 0x1, data); + /* Write command to Switch indirect command register (write) */ + miiphy_write(name, mii_dev_addr, 0x0, + reg_ofs | (phy_adr << 5) | (1 << 10) | (1 << 12) | (1 << + 15)); +} + +static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) +{ + u16 reg; + u32 mii_dev_addr; + + /* command to read PHY dev address */ + if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { + printf("Error..could not read PHY dev address\n"); + return; + } + mv88e61xx_busychk_multic(mii_dev_addr); + /* Write command to Switch indirect command register (read) */ + miiphy_write(name, mii_dev_addr, 0x0, + reg_ofs | (phy_adr << 5) | (1 << 10) | (1 << 12) | (1 << + 15)); + mv88e61xx_busychk_multic(mii_dev_addr); + /* Read data from Switch indirect data register */ + miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data); +} +#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ + +static void mv88e61xx_port_vlan_config(struct mv88e61xx_config *swconfig, + u32 max_prtnum, u32 ports_ofs) +{ + u32 prt; + u16 reg; + char *name = swconfig->name; + u32 cpu_port = swconfig->cpuport; + u32 port_mask = swconfig->ports_enabled; + enum mv88e61xx_cfg_vlan vlancfg = swconfig->vlancfg; + + /* be sure all ports are disabled */ + for (prt = 0; prt < max_prtnum; prt++) { + RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, ®); + reg &= ~0x3; + WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, reg); + + if (!(cpu_port & (1 << prt))) + continue; + /* Set CPU port VID to 0x1 */ + RD_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, ®); + reg &= ~0xfff; + reg |= 0x1; + WR_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, reg); + } + + /* Setting Port default priority for all ports to zero */ + for (prt = 0; prt < max_prtnum; prt++) { + RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, ®); + reg &= ~0xc000; + WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, reg); + } + /* Setting VID and VID map for all ports except CPU port */ + for (prt = 0; prt < max_prtnum; prt++) { + /* only for enabled ports */ + if ((1 << prt) & port_mask) { + /* skip CPU port */ + if ((1 << prt) & cpu_port) { + /* + * Set Vlan map table for cpu_port to see + * all ports + */ + RD_PHY(name, (ports_ofs + prt), + MV88E61XX_PRT_VMAP_REG, ®); + reg &= ~((1 << max_prtnum) - 1); + reg |= port_mask & ~(1 << prt); + WR_PHY(name, (ports_ofs + prt), + MV88E61XX_PRT_VMAP_REG, reg); + } else { + + /* + * set Ports VLAN Mapping. + * port prt <--> cpu_port VLAN #prt+1. + */ + RD_PHY(name, ports_ofs + prt, + MV88E61XX_PRT_VID_REG, ®); + reg &= ~0x0fff; + reg |= (prt + 1); + WR_PHY(name, ports_ofs + prt, + MV88E61XX_PRT_VID_REG, reg); + + RD_PHY(name, ports_ofs + prt, + MV88E61XX_PRT_VMAP_REG, ®); + if (vlancfg == MV88E61XX_VLANCFG_DEFAULT) { + /* + * all any port can send frames to all other ports + * ref: sec 3.2.1.1 of datasheet + */ + reg |= 0x03f; + reg &= ~(1 << prt); + } else if (vlancfg == MV88E61XX_VLANCFG_ROUTER) { + /* + * all other ports can send frames to CPU port only + * ref: sec 3.2.1.2 of datasheet + */ + reg &= ~((1 << max_prtnum) - 1); + reg |= cpu_port; + } + WR_PHY(name, ports_ofs + prt, + MV88E61XX_PRT_VMAP_REG, reg); + } + } + } + + /* + * enable only appropriate ports to forwarding mode + * and disable the others + */ + for (prt = 0; prt < max_prtnum; prt++) { + if ((1 << prt) & port_mask) { + RD_PHY(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, ®); + reg |= 0x3; + WR_PHY(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, reg); + } else { + /* Disable port */ + RD_PHY(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, ®); + reg &= ~0x3; + WR_PHY(name, ports_ofs + prt, + MV88E61XX_PRT_CTRL_REG, reg); + } + } +} + +/* + * Make sure SMIBusy bit cleared before another + * SMI operation can take place + */ +static int mv88e61xx_busychk(char *name) +{ + u32 reg = 0; + u32 timeout = MV88E61XX_PHY_TIMEOUT; + do { + RD_PHY(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (u16 *) & reg); + if (timeout-- == 0) { + printf("SMI busy timeout\n"); + return -1; + } + } while (reg & 1 << 28); /* busy mask */ + return 0; +} + +/* + * Power up the specified port and reset PHY + */ +static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 prt) +{ + char *name = swconfig->name; + + /* Write Copper Specific control reg1 (0x14) for- + * Enable Phy power up + * Energy Detect on (sense&Xmit NLP Periodically + * reset other settings default + */ + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, 0x3360); + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (0x9410 | (prt << 5))); + + if (mv88e61xx_busychk(name)) + return -1; + + /* Write PHY ctrl reg (0x0) to apply + * Phy reset (set bit 15 low) + * reset other default values + */ + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, 0x1140); + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (0x9400 | (prt << 5))); + + if (mv88e61xx_busychk(name)) + return -1; + + return 0; +} + +/* + * Default Setup for LED[0]_Control (ref: Table 46 Datasheet-3) + * is set to "On-1000Mb/s Link, Off Else" + * This function sets it to "On-Link, Blink-Activity, Off-NoLink" + * + * This is optional settings may be needed on some boards + * to setup PHY LEDs default configuration to detect 10/100/1000Mb/s + * Link status + */ +static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 prt) +{ + char *name = swconfig->name; + u16 reg; + + if (swconfig->led_init != MV88E61XX_LED_INIT_EN) + return 0; + + /* set page address to 3 */ + reg = 3; + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | + 1 << MV88E61XX_MODE_OFST | + 1 << MV88E61XX_OP_OFST | + prt << MV88E61XX_ADDR_OFST | 22)); + + if (mv88e61xx_busychk(name)) + return -1; + + /* set LED Func Ctrl reg */ + reg = 1; /* LED[0] On-Link, Blink-Activity, Off-NoLink */ + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | + 1 << MV88E61XX_MODE_OFST | + 1 << MV88E61XX_OP_OFST | + prt << MV88E61XX_ADDR_OFST | 16)); + + if (mv88e61xx_busychk(name)) + return -1; + + /* set page address to 0 */ + reg = 0; + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | + 1 << MV88E61XX_MODE_OFST | + 1 << MV88E61XX_OP_OFST | + prt << MV88E61XX_ADDR_OFST | 22)); + + if (mv88e61xx_busychk(name)) + return -1; + + return 0; +} + +/* + * Reverse Transmit polarity for Media Dependent Interface + * Pins (MDIP) bits in Copper Specific Control Register 3 + * (Page 0, Reg 20 for each phy (except cpu port) + * Reference: Section 1.1 Switch datasheet-3 + * + * This is optional settings may be needed on some boards + * for PHY<->magnetics h/w tuning + */ +static int mv88361xx_reverse_mdipn(struct mv88e61xx_config *swconfig, u32 prt) +{ + char *name = swconfig->name; + u16 reg; + + if (swconfig->mdip != MV88E61XX_MDIP_REVERSE) + return 0; + + reg = 0x0f; /*Reverse MDIP/N[3:0] bits */ + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); + WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, + MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | + 1 << MV88E61XX_MODE_OFST | + 1 << MV88E61XX_OP_OFST | + prt << MV88E61XX_ADDR_OFST | 20)); + + if (mv88e61xx_busychk(name)) + return -1; + + return 0; +} + +/* + * Marvell 88E61XX Switch initialization + */ +int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig) +{ + u32 prt; + u16 reg; + char *idstr; + char *name = swconfig->name; + + if (miiphy_set_current_dev(name)) { + printf("%s failed\n", __FUNCTION__); + return -1; + } + + if (!(swconfig->cpuport & ((1 << 4) | (1 << 5)))) { + swconfig->cpuport = (1 << 5); + printf("Invalid cpu port config, using default port5\n"); + } + + RD_PHY(name, MV88E61XX_PRT_OFST, PHY_PHYIDR2, ®); + reg &= 0xfff0; + if (reg == 0x1610) + idstr = "88E6161"; + if (reg == 0x1650) + idstr = "88E6165"; + if (reg == 0x1210) { + idstr = "88E6123"; + /* ports 2,3,4 not available */ + swconfig->ports_enabled &= 0x023; + } + + /* Port based VLANs configuration */ + if ((swconfig->vlancfg == MV88E61XX_VLANCFG_DEFAULT) + || (swconfig->vlancfg == MV88E61XX_VLANCFG_ROUTER)) + mv88e61xx_port_vlan_config(swconfig, MV88E61XX_MAX_PORTS_NUM, + MV88E61XX_PRT_OFST); + else { + printf("Unsupported mode %s failed\n", __FUNCTION__); + return -1; + } + + if (swconfig->rgmii_delay == MV88E61XX_RGMII_DELAY_EN) { + /* + * Enable RGMII delay on Tx and Rx for CPU port + * Ref: sec 9.5 of chip datasheet-02 + */ + WR_PHY(name, MV88E61XX_PRT_OFST + 5, + MV88E61XX_RGMII_TIMECTRL_REG, 0x18); + WR_PHY(name, MV88E61XX_PRT_OFST + 4, + MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); + } + + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { + if (!((1 << prt) & swconfig->cpuport)) { + + if (mv88361xx_led_init(swconfig, prt)) + return -1; + if (mv88361xx_reverse_mdipn(swconfig, prt)) + return -1; + if (mv88361xx_powerup(swconfig, prt)) + return -1; + } + + /*Program port state */ + RD_PHY(name, MV88E61XX_PRT_OFST + prt, + MV88E61XX_PRT_CTRL_REG, ®); + WR_PHY(name, MV88E61XX_PRT_OFST + prt, + MV88E61XX_PRT_CTRL_REG, + reg | (swconfig->portstate & 0x03)); + } + + printf("%s Initialized on %s\n", idstr, name); + return 0; +} diff --git a/drivers/net/phy/mv88e61xx.h b/drivers/net/phy/mv88e61xx.h new file mode 100644 index 0000000..4279464 --- /dev/null +++ b/drivers/net/phy/mv88e61xx.h @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor + * Prafulla Wadaskar + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _MV88E61XX_H +#define _MV88E61XX_H + +#include + +#define MV88E61XX_CPU_PORT 0x5 +#define MV88E61XX_MAX_PORTS_NUM 0x6 + +#define MV88E61XX_PHY_TIMEOUT 100000 + +#define MV88E61XX_PRT_STS_REG 0x1 +#define MV88E61XX_PRT_CTRL_REG 0x4 +#define MV88E61XX_PRT_VMAP_REG 0x6 +#define MV88E61XX_PRT_VID_REG 0x7 + +#define MV88E61XX_PRT_OFST 0x10 +#define MV88E61XX_PHY_CMD 0x18 +#define MV88E61XX_PHY_DATA 0x19 +#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A +#define MV88E61XX_GLB2REG_DEVADR 0x1C + +#define MV88E61XX_BUSY_OFST 15 +#define MV88E61XX_MODE_OFST 12 +#define MV88E61XX_OP_OFST 10 +#define MV88E61XX_ADDR_OFST 5 + +#ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE +static int mv88e61xx_busychk_multic(u32 devaddr); +static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data); +static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data); +#define WR_PHY mv88e61xx_wr_phy +#define RD_PHY mv88e61xx_rd_phy +#else +#define WR_PHY miiphy_write +#define RD_PHY miiphy_read +#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ + +#endif /* _MV88E61XX_H */ diff --git a/include/netdev.h b/include/netdev.h index 63cf730..4f2b23a 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -116,4 +116,51 @@ static inline int pci_eth_init(bd_t *bis) return num; } +/* + * Boards with mv88e61xx switch can use this by defining + * CONFIG_MV88E61XX_SWITCH in respective board configheader file + * the stuct and enums here are used to specify switch configuration params + */ +#if defined(CONFIG_MV88E61XX_SWITCH) +enum mv88e61xx_cfg_vlan { + MV88E61XX_VLANCFG_DEFAULT, + MV88E61XX_VLANCFG_ROUTER +}; + +enum mv88e61xx_cfg_mdip { + MV88E61XX_MDIP_NOCHANGE, + MV88E61XX_MDIP_REVERSE +}; + +enum mv88e61xx_cfg_ledinit { + MV88E61XX_LED_INIT_DIS, + MV88E61XX_LED_INIT_EN +}; + +enum mv88e61xx_cfg_rgmiid { + MV88E61XX_RGMII_DELAY_DIS, + MV88E61XX_RGMII_DELAY_EN +}; + +enum mv88e61xx_cfg_prtstt { + MV88E61XX_PORTSTT_DISABLED, + MV88E61XX_PORTSTT_BLOCKING, + MV88E61XX_PORTSTT_LEARNING, + MV88E61XX_PORTSTT_FORWARDING +}; + +struct mv88e61xx_config { + char *name; + enum mv88e61xx_cfg_vlan vlancfg; + enum mv88e61xx_cfg_rgmiid rgmii_delay; + enum mv88e61xx_cfg_prtstt portstate; + enum mv88e61xx_cfg_ledinit led_init; + enum mv88e61xx_cfg_mdip mdip; + u32 ports_enabled; + u8 cpuport; +}; + +int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig); +#endif /* CONFIG_MV88E61XX_SWITCH */ + #endif /* _NETDEV_H_ */ -- cgit v1.1 From 09cdd1b9b01450e91786d26ff3c866dc9c8d8d6b Mon Sep 17 00:00:00 2001 From: Ben Warren Date: Tue, 26 May 2009 00:17:59 -0700 Subject: Moved Davinci Ethernet driver to drivers/net This driver has been renamed davinci_emac.c Signed-off-by: Ben Warren --- cpu/arm926ejs/davinci/Makefile | 2 +- cpu/arm926ejs/davinci/ether.c | 655 ----------------------------------------- drivers/net/Makefile | 1 + drivers/net/davinci_emac.c | 655 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 657 insertions(+), 656 deletions(-) delete mode 100644 cpu/arm926ejs/davinci/ether.c create mode 100644 drivers/net/davinci_emac.c diff --git a/cpu/arm926ejs/davinci/Makefile b/cpu/arm926ejs/davinci/Makefile index 6eaa89c..e45ad25 100644 --- a/cpu/arm926ejs/davinci/Makefile +++ b/cpu/arm926ejs/davinci/Makefile @@ -30,7 +30,7 @@ LIB = $(obj)lib$(SOC).a COBJS-y += cpu.o timer.o psc.o COBJS-$(CONFIG_SOC_DM355) += dm355.o COBJS-$(CONFIG_SOC_DM644X) += dm644x.o -COBJS-$(CONFIG_DRIVER_TI_EMAC) += ether.o lxt972.o dp83848.o +COBJS-$(CONFIG_DRIVER_TI_EMAC) += lxt972.o dp83848.o SOBJS = reset.o diff --git a/cpu/arm926ejs/davinci/ether.c b/cpu/arm926ejs/davinci/ether.c deleted file mode 100644 index f6f81df..0000000 --- a/cpu/arm926ejs/davinci/ether.c +++ /dev/null @@ -1,655 +0,0 @@ -/* - * Ethernet driver for TI TMS320DM644x (DaVinci) chips. - * - * Copyright (C) 2007 Sergey Kubushyn - * - * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright - * follows: - * - * ---------------------------------------------------------------------------- - * - * dm644x_emac.c - * - * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM - * - * Copyright (C) 2005 Texas Instruments. - * - * ---------------------------------------------------------------------------- - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * ---------------------------------------------------------------------------- - - * Modifications: - * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot. - * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors - * - */ -#include -#include -#include -#include -#include - -#ifdef CONFIG_DRIVER_TI_EMAC - -#ifdef CONFIG_CMD_NET - -unsigned int emac_dbg = 0; -#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) - -/* Internal static functions */ -static int davinci_eth_hw_init (void); -static int davinci_eth_open (void); -static int davinci_eth_close (void); -static int davinci_eth_send_packet (volatile void *packet, int length); -static int davinci_eth_rcv_packet (void); -static void davinci_eth_mdio_enable(void); - -static int gen_init_phy(int phy_addr); -static int gen_is_phy_connected(int phy_addr); -static int gen_get_link_speed(int phy_addr); -static int gen_auto_negotiate(int phy_addr); - -/* Wrappers exported to the U-Boot proper */ -int eth_hw_init(void) -{ - return(davinci_eth_hw_init()); -} - -int eth_init(bd_t * bd) -{ - return(davinci_eth_open()); -} - -void eth_halt(void) -{ - davinci_eth_close(); -} - -int eth_send(volatile void *packet, int length) -{ - return(davinci_eth_send_packet(packet, length)); -} - -int eth_rx(void) -{ - return(davinci_eth_rcv_packet()); -} - -void eth_mdio_enable(void) -{ - davinci_eth_mdio_enable(); -} -/* End of wrappers */ - - -static u_int8_t davinci_eth_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -/* - * This function must be called before emac_open() if you want to override - * the default mac address. - */ -void davinci_eth_set_mac_addr(const u_int8_t *addr) -{ - int i; - - for (i = 0; i < sizeof (davinci_eth_mac_addr); i++) { - davinci_eth_mac_addr[i] = addr[i]; - } -} - -/* EMAC Addresses */ -static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; -static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; -static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR; - -/* EMAC descriptors */ -static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); -static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); -static volatile emac_desc *emac_rx_active_head = 0; -static volatile emac_desc *emac_rx_active_tail = 0; -static int emac_rx_queue_active = 0; - -/* Receive packet buffers */ -static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; - -/* PHY address for a discovered PHY (0xff - not found) */ -static volatile u_int8_t active_phy_addr = 0xff; - -phy_t phy; - -static void davinci_eth_mdio_enable(void) -{ - u_int32_t clkdiv; - - clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; - - adap_mdio->CONTROL = (clkdiv & 0xff) | - MDIO_CONTROL_ENABLE | - MDIO_CONTROL_FAULT | - MDIO_CONTROL_FAULT_ENABLE; - - while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;} -} - -/* - * Tries to find an active connected PHY. Returns 1 if address if found. - * If no active PHY (or more than one PHY) found returns 0. - * Sets active_phy_addr variable. - */ -static int davinci_eth_phy_detect(void) -{ - u_int32_t phy_act_state; - int i; - - active_phy_addr = 0xff; - - if ((phy_act_state = adap_mdio->ALIVE) == 0) - return(0); /* No active PHYs */ - - debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); - - for (i = 0; i < 32; i++) { - if (phy_act_state & (1 << i)) { - if (phy_act_state & ~(1 << i)) - return(0); /* More than one PHY */ - else { - active_phy_addr = i; - return(1); - } - } - } - - return(0); /* Just to make GCC happy */ -} - - -/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ -int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) -{ - int tmp; - - while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} - - adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | - MDIO_USERACCESS0_WRITE_READ | - ((reg_num & 0x1f) << 21) | - ((phy_addr & 0x1f) << 16); - - /* Wait for command to complete */ - while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;} - - if (tmp & MDIO_USERACCESS0_ACK) { - *data = tmp & 0xffff; - return(1); - } - - *data = -1; - return(0); -} - -/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ -int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) -{ - - while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} - - adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | - MDIO_USERACCESS0_WRITE_WRITE | - ((reg_num & 0x1f) << 21) | - ((phy_addr & 0x1f) << 16) | - (data & 0xffff); - - /* Wait for command to complete */ - while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} - - return(1); -} - -/* PHY functions for a generic PHY */ -static int gen_init_phy(int phy_addr) -{ - int ret = 1; - - if (gen_get_link_speed(phy_addr)) { - /* Try another time */ - ret = gen_get_link_speed(phy_addr); - } - - return(ret); -} - -static int gen_is_phy_connected(int phy_addr) -{ - u_int16_t dummy; - - return(davinci_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy)); -} - -static int gen_get_link_speed(int phy_addr) -{ - u_int16_t tmp; - - if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04)) - return(1); - - return(0); -} - -static int gen_auto_negotiate(int phy_addr) -{ - u_int16_t tmp; - - if (!davinci_eth_phy_read(phy_addr, PHY_BMCR, &tmp)) - return(0); - - /* Restart Auto_negotiation */ - tmp |= PHY_BMCR_AUTON; - davinci_eth_phy_write(phy_addr, PHY_BMCR, tmp); - - /*check AutoNegotiate complete */ - udelay (10000); - if (!davinci_eth_phy_read(phy_addr, PHY_BMSR, &tmp)) - return(0); - - if (!(tmp & PHY_BMSR_AUTN_COMP)) - return(0); - - return(gen_get_link_speed(phy_addr)); -} -/* End of generic PHY functions */ - - -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) -static int davinci_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) -{ - return(davinci_eth_phy_read(addr, reg, value) ? 0 : 1); -} - -static int davinci_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value) -{ - return(davinci_eth_phy_write(addr, reg, value) ? 0 : 1); -} - -int davinci_eth_miiphy_initialize(bd_t *bis) -{ - miiphy_register(phy.name, davinci_mii_phy_read, davinci_mii_phy_write); - - return(1); -} -#endif - -/* - * This function initializes the emac hardware. It does NOT initialize - * EMAC modules power or pin multiplexors, that is done by board_init() - * much earlier in bootup process. Returns 1 on success, 0 otherwise. - */ -static int davinci_eth_hw_init(void) -{ - u_int32_t phy_id; - u_int16_t tmp; - int i; - - davinci_eth_mdio_enable(); - - for (i = 0; i < 256; i++) { - if (adap_mdio->ALIVE) - break; - udelay(10); - } - - if (i >= 256) { - printf("No ETH PHY detected!!!\n"); - return(0); - } - - /* Find if a PHY is connected and get it's address */ - if (!davinci_eth_phy_detect()) - return(0); - - /* Get PHY ID and initialize phy_ops for a detected PHY */ - if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) { - active_phy_addr = 0xff; - return(0); - } - - phy_id = (tmp << 16) & 0xffff0000; - - if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) { - active_phy_addr = 0xff; - return(0); - } - - phy_id |= tmp & 0x0000ffff; - - switch (phy_id) { - case PHY_LXT972: - sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr); - phy.init = lxt972_init_phy; - phy.is_phy_connected = lxt972_is_phy_connected; - phy.get_link_speed = lxt972_get_link_speed; - phy.auto_negotiate = lxt972_auto_negotiate; - break; - case PHY_DP83848: - sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr); - phy.init = dp83848_init_phy; - phy.is_phy_connected = dp83848_is_phy_connected; - phy.get_link_speed = dp83848_get_link_speed; - phy.auto_negotiate = dp83848_auto_negotiate; - break; - default: - sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); - phy.init = gen_init_phy; - phy.is_phy_connected = gen_is_phy_connected; - phy.get_link_speed = gen_get_link_speed; - phy.auto_negotiate = gen_auto_negotiate; - } - - printf("Ethernet PHY: %s\n", phy.name); - - return(1); -} - - -/* Eth device open */ -static int davinci_eth_open(void) -{ - dv_reg_p addr; - u_int32_t clkdiv, cnt; - volatile emac_desc *rx_desc; - - debug_emac("+ emac_open\n"); - - /* Reset EMAC module and disable interrupts in wrapper */ - adap_emac->SOFTRESET = 1; - while (adap_emac->SOFTRESET != 0) {;} - adap_ewrap->EWCTL = 0; - for (cnt = 0; cnt < 5; cnt++) { - clkdiv = adap_ewrap->EWCTL; - } - - rx_desc = emac_rx_desc; - - adap_emac->TXCONTROL = 0x01; - adap_emac->RXCONTROL = 0x01; - - /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */ - /* Using channel 0 only - other channels are disabled */ - adap_emac->MACINDEX = 0; - adap_emac->MACADDRHI = - (davinci_eth_mac_addr[3] << 24) | - (davinci_eth_mac_addr[2] << 16) | - (davinci_eth_mac_addr[1] << 8) | - (davinci_eth_mac_addr[0]); - adap_emac->MACADDRLO = - (davinci_eth_mac_addr[5] << 8) | - (davinci_eth_mac_addr[4]); - - adap_emac->MACHASH1 = 0; - adap_emac->MACHASH2 = 0; - - /* Set source MAC address - REQUIRED */ - adap_emac->MACSRCADDRHI = - (davinci_eth_mac_addr[3] << 24) | - (davinci_eth_mac_addr[2] << 16) | - (davinci_eth_mac_addr[1] << 8) | - (davinci_eth_mac_addr[0]); - adap_emac->MACSRCADDRLO = - (davinci_eth_mac_addr[4] << 8) | - (davinci_eth_mac_addr[5]); - - /* Set DMA 8 TX / 8 RX Head pointers to 0 */ - addr = &adap_emac->TX0HDP; - for(cnt = 0; cnt < 16; cnt++) - *addr++ = 0; - - addr = &adap_emac->RX0HDP; - for(cnt = 0; cnt < 16; cnt++) - *addr++ = 0; - - /* Clear Statistics (do this before setting MacControl register) */ - addr = &adap_emac->RXGOODFRAMES; - for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) - *addr++ = 0; - - /* No multicast addressing */ - adap_emac->MACHASH1 = 0; - adap_emac->MACHASH2 = 0; - - /* Create RX queue and set receive process in place */ - emac_rx_active_head = emac_rx_desc; - for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { - rx_desc->next = (u_int32_t)(rx_desc + 1); - rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; - rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; - rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; - rx_desc++; - } - - /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ - rx_desc--; - rx_desc->next = 0; - emac_rx_active_tail = rx_desc; - emac_rx_queue_active = 1; - - /* Enable TX/RX */ - adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE; - adap_emac->RXBUFFEROFFSET = 0; - - /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ - adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN; - - /* Enable ch 0 only */ - adap_emac->RXUNICASTSET = 0x01; - - /* Enable MII interface and Full duplex mode */ - adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE); - - /* Init MDIO & get link state */ - clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; - adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT); - - if (!phy.get_link_speed(active_phy_addr)) - return(0); - - /* Start receive process */ - adap_emac->RX0HDP = (u_int32_t)emac_rx_desc; - - debug_emac("- emac_open\n"); - - return(1); -} - -/* EMAC Channel Teardown */ -static void davinci_eth_ch_teardown(int ch) -{ - dv_reg dly = 0xff; - dv_reg cnt; - - debug_emac("+ emac_ch_teardown\n"); - - if (ch == EMAC_CH_TX) { - /* Init TX channel teardown */ - adap_emac->TXTEARDOWN = 1; - for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) { - /* Wait here for Tx teardown completion interrupt to occur - * Note: A task delay can be called here to pend rather than - * occupying CPU cycles - anyway it has been found that teardown - * takes very few cpu cycles and does not affect functionality */ - dly--; - udelay(1); - if (dly == 0) - break; - } - adap_emac->TX0CP = cnt; - adap_emac->TX0HDP = 0; - } else { - /* Init RX channel teardown */ - adap_emac->RXTEARDOWN = 1; - for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) { - /* Wait here for Rx teardown completion interrupt to occur - * Note: A task delay can be called here to pend rather than - * occupying CPU cycles - anyway it has been found that teardown - * takes very few cpu cycles and does not affect functionality */ - dly--; - udelay(1); - if (dly == 0) - break; - } - adap_emac->RX0CP = cnt; - adap_emac->RX0HDP = 0; - } - - debug_emac("- emac_ch_teardown\n"); -} - -/* Eth device close */ -static int davinci_eth_close(void) -{ - debug_emac("+ emac_close\n"); - - davinci_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ - davinci_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ - - /* Reset EMAC module and disable interrupts in wrapper */ - adap_emac->SOFTRESET = 1; - adap_ewrap->EWCTL = 0; - - debug_emac("- emac_close\n"); - return(1); -} - -static int tx_send_loop = 0; - -/* - * This function sends a single packet on the network and returns - * positive number (number of bytes transmitted) or negative for error - */ -static int davinci_eth_send_packet (volatile void *packet, int length) -{ - int ret_status = -1; - - tx_send_loop = 0; - - /* Return error if no link */ - if (!phy.get_link_speed (active_phy_addr)) { - printf ("WARN: emac_send_packet: No link\n"); - return (ret_status); - } - - /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ - if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { - length = EMAC_MIN_ETHERNET_PKT_SIZE; - } - - /* Populate the TX descriptor */ - emac_tx_desc->next = 0; - emac_tx_desc->buffer = (u_int8_t *) packet; - emac_tx_desc->buff_off_len = (length & 0xffff); - emac_tx_desc->pkt_flag_len = ((length & 0xffff) | - EMAC_CPPI_SOP_BIT | - EMAC_CPPI_OWNERSHIP_BIT | - EMAC_CPPI_EOP_BIT); - /* Send the packet */ - adap_emac->TX0HDP = (unsigned int) emac_tx_desc; - - /* Wait for packet to complete or link down */ - while (1) { - if (!phy.get_link_speed (active_phy_addr)) { - davinci_eth_ch_teardown (EMAC_CH_TX); - return (ret_status); - } - if (adap_emac->TXINTSTATRAW & 0x01) { - ret_status = length; - break; - } - tx_send_loop++; - } - - return (ret_status); -} - -/* - * This function handles receipt of a packet from the network - */ -static int davinci_eth_rcv_packet (void) -{ - volatile emac_desc *rx_curr_desc; - volatile emac_desc *curr_desc; - volatile emac_desc *tail_desc; - int status, ret = -1; - - rx_curr_desc = emac_rx_active_head; - status = rx_curr_desc->pkt_flag_len; - if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) { - if (status & EMAC_CPPI_RX_ERROR_FRAME) { - /* Error in packet - discard it and requeue desc */ - printf ("WARN: emac_rcv_pkt: Error in packet\n"); - } else { - NetReceive (rx_curr_desc->buffer, - (rx_curr_desc->buff_off_len & 0xffff)); - ret = rx_curr_desc->buff_off_len & 0xffff; - } - - /* Ack received packet descriptor */ - adap_emac->RX0CP = (unsigned int) rx_curr_desc; - curr_desc = rx_curr_desc; - emac_rx_active_head = - (volatile emac_desc *) rx_curr_desc->next; - - if (status & EMAC_CPPI_EOQ_BIT) { - if (emac_rx_active_head) { - adap_emac->RX0HDP = - (unsigned int) emac_rx_active_head; - } else { - emac_rx_queue_active = 0; - printf ("INFO:emac_rcv_packet: RX Queue not active\n"); - } - } - - /* Recycle RX descriptor */ - rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; - rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; - rx_curr_desc->next = 0; - - if (emac_rx_active_head == 0) { - printf ("INFO: emac_rcv_pkt: active queue head = 0\n"); - emac_rx_active_head = curr_desc; - emac_rx_active_tail = curr_desc; - if (emac_rx_queue_active != 0) { - adap_emac->RX0HDP = - (unsigned int) emac_rx_active_head; - printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); - emac_rx_queue_active = 1; - } - } else { - tail_desc = emac_rx_active_tail; - emac_rx_active_tail = curr_desc; - tail_desc->next = (unsigned int) curr_desc; - status = tail_desc->pkt_flag_len; - if (status & EMAC_CPPI_EOQ_BIT) { - adap_emac->RX0HDP = (unsigned int) curr_desc; - status &= ~EMAC_CPPI_EOQ_BIT; - tail_desc->pkt_flag_len = status; - } - } - return (ret); - } - return (0); -} - -#endif /* CONFIG_CMD_NET */ - -#endif /* CONFIG_DRIVER_TI_EMAC */ diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a360a50..575d9d9 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -64,6 +64,7 @@ COBJS-$(CONFIG_SH_ETHER) += sh_eth.o COBJS-$(CONFIG_DRIVER_SMC91111) += smc91111.o COBJS-$(CONFIG_DRIVER_SMC911X) += smc911x.o COBJS-$(CONFIG_TIGON3) += tigon3.o bcm570x_autoneg.o 5701rls.o +COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o COBJS-$(CONFIG_TSEC_ENET) += tsec.o COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o COBJS-$(CONFIG_ULI526X) += uli526x.o diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c new file mode 100644 index 0000000..f6f81df --- /dev/null +++ b/drivers/net/davinci_emac.c @@ -0,0 +1,655 @@ +/* + * Ethernet driver for TI TMS320DM644x (DaVinci) chips. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright + * follows: + * + * ---------------------------------------------------------------------------- + * + * dm644x_emac.c + * + * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM + * + * Copyright (C) 2005 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + + * Modifications: + * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot. + * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors + * + */ +#include +#include +#include +#include +#include + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +unsigned int emac_dbg = 0; +#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) + +/* Internal static functions */ +static int davinci_eth_hw_init (void); +static int davinci_eth_open (void); +static int davinci_eth_close (void); +static int davinci_eth_send_packet (volatile void *packet, int length); +static int davinci_eth_rcv_packet (void); +static void davinci_eth_mdio_enable(void); + +static int gen_init_phy(int phy_addr); +static int gen_is_phy_connected(int phy_addr); +static int gen_get_link_speed(int phy_addr); +static int gen_auto_negotiate(int phy_addr); + +/* Wrappers exported to the U-Boot proper */ +int eth_hw_init(void) +{ + return(davinci_eth_hw_init()); +} + +int eth_init(bd_t * bd) +{ + return(davinci_eth_open()); +} + +void eth_halt(void) +{ + davinci_eth_close(); +} + +int eth_send(volatile void *packet, int length) +{ + return(davinci_eth_send_packet(packet, length)); +} + +int eth_rx(void) +{ + return(davinci_eth_rcv_packet()); +} + +void eth_mdio_enable(void) +{ + davinci_eth_mdio_enable(); +} +/* End of wrappers */ + + +static u_int8_t davinci_eth_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +/* + * This function must be called before emac_open() if you want to override + * the default mac address. + */ +void davinci_eth_set_mac_addr(const u_int8_t *addr) +{ + int i; + + for (i = 0; i < sizeof (davinci_eth_mac_addr); i++) { + davinci_eth_mac_addr[i] = addr[i]; + } +} + +/* EMAC Addresses */ +static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; +static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; +static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR; + +/* EMAC descriptors */ +static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); +static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); +static volatile emac_desc *emac_rx_active_head = 0; +static volatile emac_desc *emac_rx_active_tail = 0; +static int emac_rx_queue_active = 0; + +/* Receive packet buffers */ +static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + +/* PHY address for a discovered PHY (0xff - not found) */ +static volatile u_int8_t active_phy_addr = 0xff; + +phy_t phy; + +static void davinci_eth_mdio_enable(void) +{ + u_int32_t clkdiv; + + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + + adap_mdio->CONTROL = (clkdiv & 0xff) | + MDIO_CONTROL_ENABLE | + MDIO_CONTROL_FAULT | + MDIO_CONTROL_FAULT_ENABLE; + + while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;} +} + +/* + * Tries to find an active connected PHY. Returns 1 if address if found. + * If no active PHY (or more than one PHY) found returns 0. + * Sets active_phy_addr variable. + */ +static int davinci_eth_phy_detect(void) +{ + u_int32_t phy_act_state; + int i; + + active_phy_addr = 0xff; + + if ((phy_act_state = adap_mdio->ALIVE) == 0) + return(0); /* No active PHYs */ + + debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); + + for (i = 0; i < 32; i++) { + if (phy_act_state & (1 << i)) { + if (phy_act_state & ~(1 << i)) + return(0); /* More than one PHY */ + else { + active_phy_addr = i; + return(1); + } + } + } + + return(0); /* Just to make GCC happy */ +} + + +/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ +int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) +{ + int tmp; + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_READ | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16); + + /* Wait for command to complete */ + while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;} + + if (tmp & MDIO_USERACCESS0_ACK) { + *data = tmp & 0xffff; + return(1); + } + + *data = -1; + return(0); +} + +/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ +int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) +{ + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_WRITE | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16) | + (data & 0xffff); + + /* Wait for command to complete */ + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + return(1); +} + +/* PHY functions for a generic PHY */ +static int gen_init_phy(int phy_addr) +{ + int ret = 1; + + if (gen_get_link_speed(phy_addr)) { + /* Try another time */ + ret = gen_get_link_speed(phy_addr); + } + + return(ret); +} + +static int gen_is_phy_connected(int phy_addr) +{ + u_int16_t dummy; + + return(davinci_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy)); +} + +static int gen_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + + if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04)) + return(1); + + return(0); +} + +static int gen_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + if (!davinci_eth_phy_read(phy_addr, PHY_BMCR, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp |= PHY_BMCR_AUTON; + davinci_eth_phy_write(phy_addr, PHY_BMCR, tmp); + + /*check AutoNegotiate complete */ + udelay (10000); + if (!davinci_eth_phy_read(phy_addr, PHY_BMSR, &tmp)) + return(0); + + if (!(tmp & PHY_BMSR_AUTN_COMP)) + return(0); + + return(gen_get_link_speed(phy_addr)); +} +/* End of generic PHY functions */ + + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +static int davinci_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) +{ + return(davinci_eth_phy_read(addr, reg, value) ? 0 : 1); +} + +static int davinci_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value) +{ + return(davinci_eth_phy_write(addr, reg, value) ? 0 : 1); +} + +int davinci_eth_miiphy_initialize(bd_t *bis) +{ + miiphy_register(phy.name, davinci_mii_phy_read, davinci_mii_phy_write); + + return(1); +} +#endif + +/* + * This function initializes the emac hardware. It does NOT initialize + * EMAC modules power or pin multiplexors, that is done by board_init() + * much earlier in bootup process. Returns 1 on success, 0 otherwise. + */ +static int davinci_eth_hw_init(void) +{ + u_int32_t phy_id; + u_int16_t tmp; + int i; + + davinci_eth_mdio_enable(); + + for (i = 0; i < 256; i++) { + if (adap_mdio->ALIVE) + break; + udelay(10); + } + + if (i >= 256) { + printf("No ETH PHY detected!!!\n"); + return(0); + } + + /* Find if a PHY is connected and get it's address */ + if (!davinci_eth_phy_detect()) + return(0); + + /* Get PHY ID and initialize phy_ops for a detected PHY */ + if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id = (tmp << 16) & 0xffff0000; + + if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id |= tmp & 0x0000ffff; + + switch (phy_id) { + case PHY_LXT972: + sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr); + phy.init = lxt972_init_phy; + phy.is_phy_connected = lxt972_is_phy_connected; + phy.get_link_speed = lxt972_get_link_speed; + phy.auto_negotiate = lxt972_auto_negotiate; + break; + case PHY_DP83848: + sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr); + phy.init = dp83848_init_phy; + phy.is_phy_connected = dp83848_is_phy_connected; + phy.get_link_speed = dp83848_get_link_speed; + phy.auto_negotiate = dp83848_auto_negotiate; + break; + default: + sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); + phy.init = gen_init_phy; + phy.is_phy_connected = gen_is_phy_connected; + phy.get_link_speed = gen_get_link_speed; + phy.auto_negotiate = gen_auto_negotiate; + } + + printf("Ethernet PHY: %s\n", phy.name); + + return(1); +} + + +/* Eth device open */ +static int davinci_eth_open(void) +{ + dv_reg_p addr; + u_int32_t clkdiv, cnt; + volatile emac_desc *rx_desc; + + debug_emac("+ emac_open\n"); + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + while (adap_emac->SOFTRESET != 0) {;} + adap_ewrap->EWCTL = 0; + for (cnt = 0; cnt < 5; cnt++) { + clkdiv = adap_ewrap->EWCTL; + } + + rx_desc = emac_rx_desc; + + adap_emac->TXCONTROL = 0x01; + adap_emac->RXCONTROL = 0x01; + + /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */ + /* Using channel 0 only - other channels are disabled */ + adap_emac->MACINDEX = 0; + adap_emac->MACADDRHI = + (davinci_eth_mac_addr[3] << 24) | + (davinci_eth_mac_addr[2] << 16) | + (davinci_eth_mac_addr[1] << 8) | + (davinci_eth_mac_addr[0]); + adap_emac->MACADDRLO = + (davinci_eth_mac_addr[5] << 8) | + (davinci_eth_mac_addr[4]); + + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Set source MAC address - REQUIRED */ + adap_emac->MACSRCADDRHI = + (davinci_eth_mac_addr[3] << 24) | + (davinci_eth_mac_addr[2] << 16) | + (davinci_eth_mac_addr[1] << 8) | + (davinci_eth_mac_addr[0]); + adap_emac->MACSRCADDRLO = + (davinci_eth_mac_addr[4] << 8) | + (davinci_eth_mac_addr[5]); + + /* Set DMA 8 TX / 8 RX Head pointers to 0 */ + addr = &adap_emac->TX0HDP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + addr = &adap_emac->RX0HDP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + /* Clear Statistics (do this before setting MacControl register) */ + addr = &adap_emac->RXGOODFRAMES; + for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) + *addr++ = 0; + + /* No multicast addressing */ + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Create RX queue and set receive process in place */ + emac_rx_active_head = emac_rx_desc; + for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { + rx_desc->next = (u_int32_t)(rx_desc + 1); + rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_desc++; + } + + /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ + rx_desc--; + rx_desc->next = 0; + emac_rx_active_tail = rx_desc; + emac_rx_queue_active = 1; + + /* Enable TX/RX */ + adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE; + adap_emac->RXBUFFEROFFSET = 0; + + /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ + adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN; + + /* Enable ch 0 only */ + adap_emac->RXUNICASTSET = 0x01; + + /* Enable MII interface and Full duplex mode */ + adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE); + + /* Init MDIO & get link state */ + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT); + + if (!phy.get_link_speed(active_phy_addr)) + return(0); + + /* Start receive process */ + adap_emac->RX0HDP = (u_int32_t)emac_rx_desc; + + debug_emac("- emac_open\n"); + + return(1); +} + +/* EMAC Channel Teardown */ +static void davinci_eth_ch_teardown(int ch) +{ + dv_reg dly = 0xff; + dv_reg cnt; + + debug_emac("+ emac_ch_teardown\n"); + + if (ch == EMAC_CH_TX) { + /* Init TX channel teardown */ + adap_emac->TXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) { + /* Wait here for Tx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->TX0CP = cnt; + adap_emac->TX0HDP = 0; + } else { + /* Init RX channel teardown */ + adap_emac->RXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) { + /* Wait here for Rx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->RX0CP = cnt; + adap_emac->RX0HDP = 0; + } + + debug_emac("- emac_ch_teardown\n"); +} + +/* Eth device close */ +static int davinci_eth_close(void) +{ + debug_emac("+ emac_close\n"); + + davinci_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ + davinci_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + adap_ewrap->EWCTL = 0; + + debug_emac("- emac_close\n"); + return(1); +} + +static int tx_send_loop = 0; + +/* + * This function sends a single packet on the network and returns + * positive number (number of bytes transmitted) or negative for error + */ +static int davinci_eth_send_packet (volatile void *packet, int length) +{ + int ret_status = -1; + + tx_send_loop = 0; + + /* Return error if no link */ + if (!phy.get_link_speed (active_phy_addr)) { + printf ("WARN: emac_send_packet: No link\n"); + return (ret_status); + } + + /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ + if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { + length = EMAC_MIN_ETHERNET_PKT_SIZE; + } + + /* Populate the TX descriptor */ + emac_tx_desc->next = 0; + emac_tx_desc->buffer = (u_int8_t *) packet; + emac_tx_desc->buff_off_len = (length & 0xffff); + emac_tx_desc->pkt_flag_len = ((length & 0xffff) | + EMAC_CPPI_SOP_BIT | + EMAC_CPPI_OWNERSHIP_BIT | + EMAC_CPPI_EOP_BIT); + /* Send the packet */ + adap_emac->TX0HDP = (unsigned int) emac_tx_desc; + + /* Wait for packet to complete or link down */ + while (1) { + if (!phy.get_link_speed (active_phy_addr)) { + davinci_eth_ch_teardown (EMAC_CH_TX); + return (ret_status); + } + if (adap_emac->TXINTSTATRAW & 0x01) { + ret_status = length; + break; + } + tx_send_loop++; + } + + return (ret_status); +} + +/* + * This function handles receipt of a packet from the network + */ +static int davinci_eth_rcv_packet (void) +{ + volatile emac_desc *rx_curr_desc; + volatile emac_desc *curr_desc; + volatile emac_desc *tail_desc; + int status, ret = -1; + + rx_curr_desc = emac_rx_active_head; + status = rx_curr_desc->pkt_flag_len; + if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) { + if (status & EMAC_CPPI_RX_ERROR_FRAME) { + /* Error in packet - discard it and requeue desc */ + printf ("WARN: emac_rcv_pkt: Error in packet\n"); + } else { + NetReceive (rx_curr_desc->buffer, + (rx_curr_desc->buff_off_len & 0xffff)); + ret = rx_curr_desc->buff_off_len & 0xffff; + } + + /* Ack received packet descriptor */ + adap_emac->RX0CP = (unsigned int) rx_curr_desc; + curr_desc = rx_curr_desc; + emac_rx_active_head = + (volatile emac_desc *) rx_curr_desc->next; + + if (status & EMAC_CPPI_EOQ_BIT) { + if (emac_rx_active_head) { + adap_emac->RX0HDP = + (unsigned int) emac_rx_active_head; + } else { + emac_rx_queue_active = 0; + printf ("INFO:emac_rcv_packet: RX Queue not active\n"); + } + } + + /* Recycle RX descriptor */ + rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_curr_desc->next = 0; + + if (emac_rx_active_head == 0) { + printf ("INFO: emac_rcv_pkt: active queue head = 0\n"); + emac_rx_active_head = curr_desc; + emac_rx_active_tail = curr_desc; + if (emac_rx_queue_active != 0) { + adap_emac->RX0HDP = + (unsigned int) emac_rx_active_head; + printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); + emac_rx_queue_active = 1; + } + } else { + tail_desc = emac_rx_active_tail; + emac_rx_active_tail = curr_desc; + tail_desc->next = (unsigned int) curr_desc; + status = tail_desc->pkt_flag_len; + if (status & EMAC_CPPI_EOQ_BIT) { + adap_emac->RX0HDP = (unsigned int) curr_desc; + status &= ~EMAC_CPPI_EOQ_BIT; + tail_desc->pkt_flag_len = status; + } + } + return (ret); + } + return (0); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_TI_EMAC */ -- cgit v1.1 From 8cc13c13f1d154c8fa8fff56cea357ed38af76bf Mon Sep 17 00:00:00 2001 From: Ben Warren Date: Mon, 27 Apr 2009 23:19:10 -0700 Subject: Initial cleanup of Davinci Ethernet driver Removed pointless #ifdefs Moved functions around in file in preparation for switch to newer API Signed-off-by: Ben Warren --- drivers/net/davinci_emac.c | 146 +++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 77 deletions(-) diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index f6f81df..f5cec05 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -42,10 +42,6 @@ #include #include -#ifdef CONFIG_DRIVER_TI_EMAC - -#ifdef CONFIG_CMD_NET - unsigned int emac_dbg = 0; #define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) @@ -291,77 +287,6 @@ int davinci_eth_miiphy_initialize(bd_t *bis) } #endif -/* - * This function initializes the emac hardware. It does NOT initialize - * EMAC modules power or pin multiplexors, that is done by board_init() - * much earlier in bootup process. Returns 1 on success, 0 otherwise. - */ -static int davinci_eth_hw_init(void) -{ - u_int32_t phy_id; - u_int16_t tmp; - int i; - - davinci_eth_mdio_enable(); - - for (i = 0; i < 256; i++) { - if (adap_mdio->ALIVE) - break; - udelay(10); - } - - if (i >= 256) { - printf("No ETH PHY detected!!!\n"); - return(0); - } - - /* Find if a PHY is connected and get it's address */ - if (!davinci_eth_phy_detect()) - return(0); - - /* Get PHY ID and initialize phy_ops for a detected PHY */ - if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) { - active_phy_addr = 0xff; - return(0); - } - - phy_id = (tmp << 16) & 0xffff0000; - - if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) { - active_phy_addr = 0xff; - return(0); - } - - phy_id |= tmp & 0x0000ffff; - - switch (phy_id) { - case PHY_LXT972: - sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr); - phy.init = lxt972_init_phy; - phy.is_phy_connected = lxt972_is_phy_connected; - phy.get_link_speed = lxt972_get_link_speed; - phy.auto_negotiate = lxt972_auto_negotiate; - break; - case PHY_DP83848: - sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr); - phy.init = dp83848_init_phy; - phy.is_phy_connected = dp83848_is_phy_connected; - phy.get_link_speed = dp83848_get_link_speed; - phy.auto_negotiate = dp83848_auto_negotiate; - break; - default: - sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); - phy.init = gen_init_phy; - phy.is_phy_connected = gen_is_phy_connected; - phy.get_link_speed = gen_get_link_speed; - phy.auto_negotiate = gen_auto_negotiate; - } - - printf("Ethernet PHY: %s\n", phy.name); - - return(1); -} - /* Eth device open */ static int davinci_eth_open(void) @@ -650,6 +575,73 @@ static int davinci_eth_rcv_packet (void) return (0); } -#endif /* CONFIG_CMD_NET */ +/* + * This function initializes the emac hardware. It does NOT initialize + * EMAC modules power or pin multiplexors, that is done by board_init() + * much earlier in bootup process. Returns 1 on success, 0 otherwise. + */ +static int davinci_eth_hw_init(void) +{ + u_int32_t phy_id; + u_int16_t tmp; + int i; + + davinci_eth_mdio_enable(); + + for (i = 0; i < 256; i++) { + if (adap_mdio->ALIVE) + break; + udelay(10); + } + + if (i >= 256) { + printf("No ETH PHY detected!!!\n"); + return(0); + } + + /* Find if a PHY is connected and get it's address */ + if (!davinci_eth_phy_detect()) + return(0); + + /* Get PHY ID and initialize phy_ops for a detected PHY */ + if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) { + active_phy_addr = 0xff; + return(0); + } -#endif /* CONFIG_DRIVER_TI_EMAC */ + phy_id = (tmp << 16) & 0xffff0000; + + if (!davinci_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id |= tmp & 0x0000ffff; + + switch (phy_id) { + case PHY_LXT972: + sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr); + phy.init = lxt972_init_phy; + phy.is_phy_connected = lxt972_is_phy_connected; + phy.get_link_speed = lxt972_get_link_speed; + phy.auto_negotiate = lxt972_auto_negotiate; + break; + case PHY_DP83848: + sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr); + phy.init = dp83848_init_phy; + phy.is_phy_connected = dp83848_is_phy_connected; + phy.get_link_speed = dp83848_get_link_speed; + phy.auto_negotiate = dp83848_auto_negotiate; + break; + default: + sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); + phy.init = gen_init_phy; + phy.is_phy_connected = gen_is_phy_connected; + phy.get_link_speed = gen_get_link_speed; + phy.auto_negotiate = gen_auto_negotiate; + } + + printf("Ethernet PHY: %s\n", phy.name); + + return(1); +} -- cgit v1.1 From 8453587ef9137daf98b7c9cf4f3b865f4039cea0 Mon Sep 17 00:00:00 2001 From: Ben Warren Date: Tue, 26 May 2009 00:34:07 -0700 Subject: Switched davinci_emac Ethernet driver to use newer API Added CONFIG_NET_MULTI to all Davinci boards Removed all calls to Davinci network driver from board code Added cpu_eth_init() to cpu/arm926ejs/cpu.c Signed-off-by: Ben Warren --- board/davinci/common/misc.h | 1 - board/davinci/dvevm/dvevm.c | 3 -- board/davinci/schmoogie/schmoogie.c | 3 -- board/davinci/sffsdr/sffsdr.c | 3 -- board/davinci/sonata/sonata.c | 3 -- cpu/arm926ejs/davinci/cpu.c | 12 +++++++ drivers/net/davinci_emac.c | 70 +++++++++++++------------------------ include/configs/davinci_dvevm.h | 1 + include/configs/davinci_schmoogie.h | 1 + include/configs/davinci_sffsdr.h | 1 + include/configs/davinci_sonata.h | 1 + include/netdev.h | 1 + net/eth.c | 4 --- 13 files changed, 41 insertions(+), 63 deletions(-) diff --git a/board/davinci/common/misc.h b/board/davinci/common/misc.h index 316159a..dc3cc41 100644 --- a/board/davinci/common/misc.h +++ b/board/davinci/common/misc.h @@ -22,7 +22,6 @@ #ifndef __MISC_H #define __MISC_H -extern int eth_hw_init(void); int dvevm_read_mac_address(uint8_t *buf); void dv_configure_mac_address(uint8_t *rom_enetaddr); diff --git a/board/davinci/dvevm/dvevm.c b/board/davinci/dvevm/dvevm.c index 8f38633..98937a9 100644 --- a/board/davinci/dvevm/dvevm.c +++ b/board/davinci/dvevm/dvevm.c @@ -73,9 +73,6 @@ int misc_init_r(void) if (dvevm_read_mac_address(eeprom_enetaddr)) dv_configure_mac_address(eeprom_enetaddr); - if (!eth_hw_init()) - printf("ethernet init failed!\n"); - i2c_read(0x39, 0x00, 1, &video_mode, 1); setenv("videostd", ((video_mode & 0x80) ? "pal" : "ntsc")); diff --git a/board/davinci/schmoogie/schmoogie.c b/board/davinci/schmoogie/schmoogie.c index 6e0f591..19c9580 100644 --- a/board/davinci/schmoogie/schmoogie.c +++ b/board/davinci/schmoogie/schmoogie.c @@ -130,8 +130,5 @@ int misc_init_r(void) forceenv("serial#", (char *)&tmp[0]); } - if (!eth_hw_init()) - printf("ethernet init failed!\n"); - return(0); } diff --git a/board/davinci/sffsdr/sffsdr.c b/board/davinci/sffsdr/sffsdr.c index 7f4ee36..c24b9e1 100644 --- a/board/davinci/sffsdr/sffsdr.c +++ b/board/davinci/sffsdr/sffsdr.c @@ -143,8 +143,5 @@ int misc_init_r(void) if (sffsdr_read_mac_address(eeprom_enetaddr)) dv_configure_mac_address(eeprom_enetaddr); - if (!eth_hw_init()) - printf("Ethernet init failed\n"); - return(0); } diff --git a/board/davinci/sonata/sonata.c b/board/davinci/sonata/sonata.c index a0bea05..7f9d9bb 100644 --- a/board/davinci/sonata/sonata.c +++ b/board/davinci/sonata/sonata.c @@ -70,8 +70,5 @@ int misc_init_r(void) if (dvevm_read_mac_address(eeprom_enetaddr)) dv_configure_mac_address(eeprom_enetaddr); - if (!eth_hw_init()) - printf("ethernet init failed!\n"); - return(0); } diff --git a/cpu/arm926ejs/davinci/cpu.c b/cpu/arm926ejs/davinci/cpu.c index 29aead6..390cab8 100644 --- a/cpu/arm926ejs/davinci/cpu.c +++ b/cpu/arm926ejs/davinci/cpu.c @@ -21,6 +21,7 @@ */ #include +#include #include @@ -129,3 +130,14 @@ int print_cpuinfo(void) #endif +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ +#if defined(CONFIG_DRIVER_TI_EMAC) + davinci_emac_initialize(); +#endif + return 0; +} diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index f5cec05..fa8cee4 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -40,17 +40,12 @@ #include #include #include +#include #include unsigned int emac_dbg = 0; #define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) -/* Internal static functions */ -static int davinci_eth_hw_init (void); -static int davinci_eth_open (void); -static int davinci_eth_close (void); -static int davinci_eth_send_packet (volatile void *packet, int length); -static int davinci_eth_rcv_packet (void); static void davinci_eth_mdio_enable(void); static int gen_init_phy(int phy_addr); @@ -58,38 +53,10 @@ static int gen_is_phy_connected(int phy_addr); static int gen_get_link_speed(int phy_addr); static int gen_auto_negotiate(int phy_addr); -/* Wrappers exported to the U-Boot proper */ -int eth_hw_init(void) -{ - return(davinci_eth_hw_init()); -} - -int eth_init(bd_t * bd) -{ - return(davinci_eth_open()); -} - -void eth_halt(void) -{ - davinci_eth_close(); -} - -int eth_send(volatile void *packet, int length) -{ - return(davinci_eth_send_packet(packet, length)); -} - -int eth_rx(void) -{ - return(davinci_eth_rcv_packet()); -} - void eth_mdio_enable(void) { davinci_eth_mdio_enable(); } -/* End of wrappers */ - static u_int8_t davinci_eth_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -279,17 +246,11 @@ static int davinci_mii_phy_write(char *devname, unsigned char addr, unsigned cha return(davinci_eth_phy_write(addr, reg, value) ? 0 : 1); } -int davinci_eth_miiphy_initialize(bd_t *bis) -{ - miiphy_register(phy.name, davinci_mii_phy_read, davinci_mii_phy_write); - - return(1); -} #endif /* Eth device open */ -static int davinci_eth_open(void) +static int davinci_eth_open(struct eth_device *dev, bd_t *bis) { dv_reg_p addr; u_int32_t clkdiv, cnt; @@ -441,7 +402,7 @@ static void davinci_eth_ch_teardown(int ch) } /* Eth device close */ -static int davinci_eth_close(void) +static void davinci_eth_close(struct eth_device *dev) { debug_emac("+ emac_close\n"); @@ -453,7 +414,6 @@ static int davinci_eth_close(void) adap_ewrap->EWCTL = 0; debug_emac("- emac_close\n"); - return(1); } static int tx_send_loop = 0; @@ -462,7 +422,8 @@ static int tx_send_loop = 0; * This function sends a single packet on the network and returns * positive number (number of bytes transmitted) or negative for error */ -static int davinci_eth_send_packet (volatile void *packet, int length) +static int davinci_eth_send_packet (struct eth_device *dev, + volatile void *packet, int length) { int ret_status = -1; @@ -509,7 +470,7 @@ static int davinci_eth_send_packet (volatile void *packet, int length) /* * This function handles receipt of a packet from the network */ -static int davinci_eth_rcv_packet (void) +static int davinci_eth_rcv_packet (struct eth_device *dev) { volatile emac_desc *rx_curr_desc; volatile emac_desc *curr_desc; @@ -580,11 +541,27 @@ static int davinci_eth_rcv_packet (void) * EMAC modules power or pin multiplexors, that is done by board_init() * much earlier in bootup process. Returns 1 on success, 0 otherwise. */ -static int davinci_eth_hw_init(void) +int davinci_emac_initialize(void) { u_int32_t phy_id; u_int16_t tmp; int i; + struct eth_device *dev; + + dev = malloc(sizeof *dev); + + if (dev == NULL) + return -1; + + memset(dev, 0, sizeof *dev); + + dev->iobase = 0; + dev->init = davinci_eth_open; + dev->halt = davinci_eth_close; + dev->send = davinci_eth_send_packet; + dev->recv = davinci_eth_rcv_packet; + + eth_register(dev); davinci_eth_mdio_enable(); @@ -643,5 +620,6 @@ static int davinci_eth_hw_init(void) printf("Ethernet PHY: %s\n", phy.name); + miiphy_register(phy.name, davinci_mii_phy_read, davinci_mii_phy_write); return(1); } diff --git a/include/configs/davinci_dvevm.h b/include/configs/davinci_dvevm.h index 6c5d065..96b6afc 100644 --- a/include/configs/davinci_dvevm.h +++ b/include/configs/davinci_dvevm.h @@ -109,6 +109,7 @@ #define CONFIG_BOOTP_DNS2 #define CONFIG_BOOTP_SEND_HOSTNAME #define CONFIG_NET_RETRY_COUNT 10 +#define CONFIG_NET_MULTI /*=====================*/ /* Flash & Environment */ /*=====================*/ diff --git a/include/configs/davinci_schmoogie.h b/include/configs/davinci_schmoogie.h index 6612cb3..9cb9838 100644 --- a/include/configs/davinci_schmoogie.h +++ b/include/configs/davinci_schmoogie.h @@ -77,6 +77,7 @@ #define CONFIG_BOOTP_SEND_HOSTNAME #define CONFIG_NET_RETRY_COUNT 10 #define CONFIG_OVERWRITE_ETHADDR_ONCE +#define CONFIG_NET_MULTI /*=====================*/ /* Flash & Environment */ /*=====================*/ diff --git a/include/configs/davinci_sffsdr.h b/include/configs/davinci_sffsdr.h index 6c1dc11..a47620f 100644 --- a/include/configs/davinci_sffsdr.h +++ b/include/configs/davinci_sffsdr.h @@ -74,6 +74,7 @@ #define CONFIG_BOOTP_SEND_HOSTNAME #define CONFIG_NET_RETRY_COUNT 10 #define CONFIG_OVERWRITE_ETHADDR_ONCE +#define CONFIG_NET_MULTI /* Flash & Environment */ #undef CONFIG_ENV_IS_IN_FLASH #define CONFIG_SYS_NO_FLASH diff --git a/include/configs/davinci_sonata.h b/include/configs/davinci_sonata.h index 893729c..82901b3 100644 --- a/include/configs/davinci_sonata.h +++ b/include/configs/davinci_sonata.h @@ -109,6 +109,7 @@ #define CONFIG_BOOTP_DNS2 #define CONFIG_BOOTP_SEND_HOSTNAME #define CONFIG_NET_RETRY_COUNT 10 +#define CONFIG_NET_MULTI /*=====================*/ /* Flash & Environment */ /*=====================*/ diff --git a/include/netdev.h b/include/netdev.h index 4f2b23a..df3bc63 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -44,6 +44,7 @@ int cpu_eth_init(bd_t *bis); int au1x00_enet_initialize(bd_t*); int bfin_EMAC_initialize(bd_t *bis); int dc21x4x_initialize(bd_t *bis); +int davinci_emac_initialize(void); int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr); int e1000_initialize(bd_t *bis); int eepro100_initialize(bd_t *bis); diff --git a/net/eth.c b/net/eth.c index 8940ebf..eb218b6 100644 --- a/net/eth.c +++ b/net/eth.c @@ -504,7 +504,6 @@ extern int at91rm9200_miiphy_initialize(bd_t *bis); extern int emac4xx_miiphy_initialize(bd_t *bis); extern int mcf52x2_miiphy_initialize(bd_t *bis); extern int ns7520_miiphy_initialize(bd_t *bis); -extern int davinci_eth_miiphy_initialize(bd_t *bis); int eth_initialize(bd_t *bis) @@ -525,9 +524,6 @@ int eth_initialize(bd_t *bis) #if defined(CONFIG_DRIVER_NS7520_ETHERNET) ns7520_miiphy_initialize(bis); #endif -#if defined(CONFIG_DRIVER_TI_EMAC) - davinci_eth_miiphy_initialize(bis); -#endif return 0; } #endif -- cgit v1.1 From 6e0d2fc7fe0dcfa2f51ab8931d706940ee364193 Mon Sep 17 00:00:00 2001 From: Ben Warren Date: Tue, 28 Apr 2009 16:39:19 -0700 Subject: Remove support for non-CONFIG_NET_MULTI on PPC4xx EMAC Signed-off-by: Ben Warren --- drivers/net/4xx_enet.c | 54 -------------------------------------------------- net/eth.c | 4 ---- 2 files changed, 58 deletions(-) diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c index 7bf3e0a..587605d 100644 --- a/drivers/net/4xx_enet.c +++ b/drivers/net/4xx_enet.c @@ -259,9 +259,6 @@ static const struct fixed_phy_port fixed_phy_port[] = { /*-----------------------------------------------------------------------------+ * Global variables. TX and RX descriptors and buffers. *-----------------------------------------------------------------------------*/ -#if !defined(CONFIG_NET_MULTI) -struct eth_device *emac0_dev = NULL; -#endif /* * Get count of EMAC devices (doesn't have to be the max. possible number @@ -1643,11 +1640,7 @@ int enetInt (struct eth_device *dev) * Because the mal is generic, we need to get the current * eth device */ -#if defined(CONFIG_NET_MULTI) dev = eth_get_dev(); -#else - dev = emac0_dev; -#endif hw_p = dev->priv; @@ -2066,60 +2059,13 @@ int ppc_4xx_eth_initialize (bd_t * bis) virgin = 1; } -#if defined(CONFIG_NET_MULTI) eth_register (dev); -#else - emac0_dev = dev; -#endif -#if defined(CONFIG_NET_MULTI) #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register (dev->name, emac4xx_miiphy_read, emac4xx_miiphy_write); #endif -#endif } /* end for each supported device */ return 0; } - -#if !defined(CONFIG_NET_MULTI) -void eth_halt (void) { - if (emac0_dev) { - ppc_4xx_eth_halt(emac0_dev); - free(emac0_dev); - emac0_dev = NULL; - } -} - -int eth_init (bd_t *bis) -{ - ppc_4xx_eth_initialize(bis); - if (emac0_dev) { - return ppc_4xx_eth_init(emac0_dev, bis); - } else { - printf("ERROR: ethaddr not set!\n"); - return -1; - } -} - -int eth_send(volatile void *packet, int length) -{ - return (ppc_4xx_eth_send(emac0_dev, packet, length)); -} - -int eth_rx(void) -{ - return (ppc_4xx_eth_rx(emac0_dev)); -} - -int emac4xx_miiphy_initialize (bd_t * bis) -{ -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - miiphy_register ("ppc_4xx_eth0", - emac4xx_miiphy_read, emac4xx_miiphy_write); -#endif - - return 0; -} -#endif /* !defined(CONFIG_NET_MULTI) */ diff --git a/net/eth.c b/net/eth.c index eb218b6..3d93966 100644 --- a/net/eth.c +++ b/net/eth.c @@ -501,7 +501,6 @@ char *eth_get_name (void) #elif defined(CONFIG_CMD_NET) && !defined(CONFIG_NET_MULTI) extern int at91rm9200_miiphy_initialize(bd_t *bis); -extern int emac4xx_miiphy_initialize(bd_t *bis); extern int mcf52x2_miiphy_initialize(bd_t *bis); extern int ns7520_miiphy_initialize(bd_t *bis); @@ -515,9 +514,6 @@ int eth_initialize(bd_t *bis) #if defined(CONFIG_AT91RM9200) at91rm9200_miiphy_initialize(bis); #endif -#if defined(CONFIG_PPC4xx_EMAC) - emac4xx_miiphy_initialize(bis); -#endif #if defined(CONFIG_MCF52x2) mcf52x2_miiphy_initialize(bis); #endif -- cgit v1.1 From c9a2aab1512fb2d132670fff9c27656d2eb949cd Mon Sep 17 00:00:00 2001 From: Norbert van Bolhuis Date: Thu, 4 Jun 2009 09:39:48 +0200 Subject: A VLAN tagged DHCP request/discover is 4 bytes short The problem is that BOOTP_SIZE uses ETHER_HDR_SIZE which is 14 bytes. If sending a VLAN tagged frame (when env variable vlan is set) this should be VLAN_ETHER_HDR_SIZE=18 which is what NetSetEther returns. Signed-off-by: Norbert van Bolhuis Signed-off-by: Ben Warren --- net/bootp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bootp.c b/net/bootp.c index 3dea70aa..77057c6 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -687,7 +687,7 @@ BootpRequest (void) * Calculate proper packet lengths taking into account the * variable size of the options field */ - pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + ext_len; + pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len; iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len; NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen); NetSetTimeout(SELECT_TIMEOUT, BootpTimeout); @@ -860,7 +860,7 @@ static void DhcpSendRequestPkt(Bootp_t *bp_offer) NetCopyIP(&OfferedIP, &bp_offer->bp_yiaddr); extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP); - pktlen = BOOTP_SIZE - sizeof(bp->bp_vend) + extlen; + pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen; iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen; NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen); -- cgit v1.1 From 44578bea14e49035331a8f0e000e935e0d830ff4 Mon Sep 17 00:00:00 2001 From: Richard Retanubun Date: Tue, 26 May 2009 08:29:29 -0400 Subject: Subject: [PATCH] [repost] Standardize the use of MCFFEC_TOUT_LOOP as a udelay(1) loop counter. From 584b5fbd4abfc43f920cc1c329633e03816e28be Mon Sep 17 00:00:00 2001 From: Richard Retanubun Date: Wed, 20 May 2009 18:26:01 -0400 Subject: [PATCH] Standardize the use of MCFFEC_TOUT_LOOP as a udelay(1) loop counter. Signed-off-by: Richard Retanubun Signed-off-by: Ben Warren --- drivers/net/mcfmii.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/mcfmii.c b/drivers/net/mcfmii.c index 4f1c0a0..4acc29e 100644 --- a/drivers/net/mcfmii.c +++ b/drivers/net/mcfmii.c @@ -270,7 +270,7 @@ void __mii_init(void) if ((status & linkgood) == linkgood) break; - udelay(500); + udelay(1); } if (i >= MCFFEC_TOUT_LOOP) { printf("Link UP timeout\n"); -- cgit v1.1 From 7835f4b94927ecb5affd99aad62592108db606ad Mon Sep 17 00:00:00 2001 From: "s-paulraj@ti.com" Date: Tue, 12 May 2009 11:45:34 -0400 Subject: DaVinci Network Driver Updates Different flavours of DaVinci SOC's have differences in their EMAC IP This patch does the following 1) Updates base addresses for DM365 2) Updates MDIO frequencies for DM365 and DM646x 3) Update EMAC wrapper registers for DM365 and DM646x Patch applies to u-boot-net git. the EMAC driver itself will be updated shortly to add support for DM365 and DM646x Signed-off-by: Sandeep Paulraj Signed-off-by: Ben Warren --- include/asm-arm/arch-davinci/emac_defs.h | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/include/asm-arm/arch-davinci/emac_defs.h b/include/asm-arm/arch-davinci/emac_defs.h index c11161f..ae75f84 100644 --- a/include/asm-arm/arch-davinci/emac_defs.h +++ b/include/asm-arm/arch-davinci/emac_defs.h @@ -38,15 +38,38 @@ #include +#ifdef CONFIG_SOC_DM365 +#define EMAC_BASE_ADDR (0x01d07000) +#define EMAC_WRAPPER_BASE_ADDR (0x01d0a000) +#define EMAC_WRAPPER_RAM_ADDR (0x01d08000) +#define EMAC_MDIO_BASE_ADDR (0x01d0b000) +#else #define EMAC_BASE_ADDR (0x01c80000) #define EMAC_WRAPPER_BASE_ADDR (0x01c81000) #define EMAC_WRAPPER_RAM_ADDR (0x01c82000) #define EMAC_MDIO_BASE_ADDR (0x01c84000) +#endif +#ifdef CONFIG_SOC_DM646x +/* MDIO module input frequency */ +#define EMAC_MDIO_BUS_FREQ 76500000 +/* MDIO clock output frequency */ +#define EMAC_MDIO_CLOCK_FREQ 2500000 /* 2.5 MHz */ +#elif defined(CONFIG_SOC_DM365) +/* MDIO module input frequency */ +#define EMAC_MDIO_BUS_FREQ 121500000 +/* MDIO clock output frequency */ +#define EMAC_MDIO_CLOCK_FREQ 2200000 /* 2.2 MHz */ +#else /* MDIO module input frequency */ #define EMAC_MDIO_BUS_FREQ 99000000 /* PLL/6 - 99 MHz */ /* MDIO clock output frequency */ #define EMAC_MDIO_CLOCK_FREQ 2000000 /* 2.0 MHz */ +#endif + +/* PHY mask - set only those phy number bits where phy is/can be connected */ +#define EMAC_MDIO_PHY_NUM 1 +#define EMAC_MDIO_PHY_MASK (1 << EMAC_MDIO_PHY_NUM) /* Ethernet Min/Max packet size */ #define EMAC_MIN_ETHERNET_PKT_SIZE 60 @@ -103,6 +126,8 @@ typedef volatile struct _emac_desc #define EMAC_MACCONTROL_MIIEN_ENABLE (0x20) #define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1) +#define EMAC_MACCONTROL_GIGABIT_ENABLE (1 << 7) +#define EMAC_MACCONTROL_GIGFORCE (1 << 17) #define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000) #define EMAC_RXMBPENABLE_RXBROADEN (0x2000) @@ -258,12 +283,17 @@ typedef struct { /* EMAC Wrapper Registers Structure */ typedef struct { +#if defined(CONFIG_SOC_DM646x) || defined(CONFIG_SOC_DM365) + dv_reg IDVER; + dv_reg SOFTRST; + dv_reg EMCTRL; +#else u_int8_t RSVD0[4100]; dv_reg EWCTL; dv_reg EWINTTCNT; +#endif } ewrap_regs; - /* EMAC MDIO Registers Structure */ typedef struct { dv_reg VERSION; -- cgit v1.1 From 9131589ada4dda0718604d0a425ca46e52775f6e Mon Sep 17 00:00:00 2001 From: Prafulla Wadaskar Date: Sun, 14 Jun 2009 22:33:46 +0530 Subject: net: Add Marvell Kirkwood gigabit ethernet driver This patch adds a egiga driver for the Marvell Kirkwood SoC's. Contributors: Yotam Admon Michael Blostein Acked-by: Stefan Rose Signed-off-by: Prafulla Wadaskar Signed-off-by: Ben Warren --- drivers/net/Makefile | 1 + drivers/net/kirkwood_egiga.c | 664 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/kirkwood_egiga.h | 503 ++++++++++++++++++++++++++++++++ include/netdev.h | 1 + 4 files changed, 1169 insertions(+) create mode 100644 drivers/net/kirkwood_egiga.c create mode 100644 drivers/net/kirkwood_egiga.h diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 575d9d9..c6097c3 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -40,6 +40,7 @@ COBJS-$(CONFIG_ENC28J60) += enc28j60.o COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o COBJS-$(CONFIG_GRETH) += greth.o COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o +COBJS-$(CONFIG_KIRKWOOD_EGIGA) += kirkwood_egiga.o COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o COBJS-$(CONFIG_DRIVER_LAN91C96) += lan91c96.o COBJS-$(CONFIG_MACB) += macb.o diff --git a/drivers/net/kirkwood_egiga.c b/drivers/net/kirkwood_egiga.c new file mode 100644 index 0000000..b43bbf2 --- /dev/null +++ b/drivers/net/kirkwood_egiga.c @@ -0,0 +1,664 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor + * Written-by: Prafulla Wadaskar + * + * (C) Copyright 2003 + * Ingo Assmus + * + * based on - Driver for MV64360X ethernet ports + * Copyright (C) 2002 rabeeh@galileo.co.il + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "kirkwood_egiga.h" + +/* + * smi_reg_read - miiphy_read callback function. + * + * Returns 16bit phy register value, or 0xffff on error + */ +static int smi_reg_read(char *devname, u8 phy_adr, u8 reg_ofs, u16 * data) +{ + struct eth_device *dev = eth_get_dev_by_name(devname); + struct kwgbe_device *dkwgbe = to_dkwgbe(dev); + struct kwgbe_registers *regs = dkwgbe->regs; + u32 smi_reg; + volatile u32 timeout; + + /* Phyadr read request */ + if (phy_adr == 0xEE && reg_ofs == 0xEE) { + /* */ + *data = (u16) (KWGBEREG_RD(regs->phyadr) & PHYADR_MASK); + return 0; + } + /* check parameters */ + if (phy_adr > PHYADR_MASK) { + printf("Err..(%s) Invalid PHY address %d\n", + __FUNCTION__, phy_adr); + return -EFAULT; + } + if (reg_ofs > PHYREG_MASK) { + printf("Err..(%s) Invalid register offset %d\n", + __FUNCTION__, reg_ofs); + return -EFAULT; + } + + timeout = KWGBE_PHY_SMI_TIMEOUT; + /* wait till the SMI is not busy */ + do { + /* read smi register */ + smi_reg = KWGBEREG_RD(regs->smi); + if (timeout-- == 0) { + printf("Err..(%s) SMI busy timeout\n", __FUNCTION__); + return -EFAULT; + } + } while (smi_reg & KWGBE_PHY_SMI_BUSY_MASK); + + /* fill the phy address and regiser offset and read opcode */ + smi_reg = (phy_adr << KWGBE_PHY_SMI_DEV_ADDR_OFFS) + | (reg_ofs << KWGBE_SMI_REG_ADDR_OFFS) + | KWGBE_PHY_SMI_OPCODE_READ; + + /* write the smi register */ + KWGBEREG_WR(regs->smi, smi_reg); + + /*wait till read value is ready */ + timeout = KWGBE_PHY_SMI_TIMEOUT; + + do { + /* read smi register */ + smi_reg = KWGBEREG_RD(regs->smi); + if (timeout-- == 0) { + printf("Err..(%s) SMI read ready timeout\n", + __FUNCTION__); + return -EFAULT; + } + } while (!(smi_reg & KWGBE_PHY_SMI_READ_VALID_MASK)); + + /* Wait for the data to update in the SMI register */ + for (timeout = 0; timeout < KWGBE_PHY_SMI_TIMEOUT; timeout++) ; + + *data = (u16) (KWGBEREG_RD(regs->smi) & KWGBE_PHY_SMI_DATA_MASK); + + debug("%s:(adr %d, off %d) value= %04x\n", __FUNCTION__, phy_adr, + reg_ofs, *data); + + return 0; +} + +/* + * smi_reg_write - imiiphy_write callback function. + * + * Returns 0 if write succeed, -EINVAL on bad parameters + * -ETIME on timeout + */ +static int smi_reg_write(char *devname, u8 phy_adr, u8 reg_ofs, u16 data) +{ + struct eth_device *dev = eth_get_dev_by_name(devname); + struct kwgbe_device *dkwgbe = to_dkwgbe(dev); + struct kwgbe_registers *regs = dkwgbe->regs; + u32 smi_reg; + volatile u32 timeout; + + /* Phyadr write request*/ + if (phy_adr == 0xEE && reg_ofs == 0xEE) { + KWGBEREG_WR(regs->phyadr, data); + return 0; + } + + /* check parameters */ + if (phy_adr > PHYADR_MASK) { + printf("Err..(%s) Invalid phy address\n", __FUNCTION__); + return -EINVAL; + } + if (reg_ofs > PHYREG_MASK) { + printf("Err..(%s) Invalid register offset\n", __FUNCTION__); + return -EINVAL; + } + + /* wait till the SMI is not busy */ + timeout = KWGBE_PHY_SMI_TIMEOUT; + do { + /* read smi register */ + smi_reg = KWGBEREG_RD(regs->smi); + if (timeout-- == 0) { + printf("Err..(%s) SMI busy timeout\n", __FUNCTION__); + return -ETIME; + } + } while (smi_reg & KWGBE_PHY_SMI_BUSY_MASK); + + /* fill the phy addr and reg offset and write opcode and data */ + smi_reg = (data << KWGBE_PHY_SMI_DATA_OFFS); + smi_reg |= (phy_adr << KWGBE_PHY_SMI_DEV_ADDR_OFFS) + | (reg_ofs << KWGBE_SMI_REG_ADDR_OFFS); + smi_reg &= ~KWGBE_PHY_SMI_OPCODE_READ; + + /* write the smi register */ + KWGBEREG_WR(regs->smi, smi_reg); + + return 0; +} + +/* Stop and checks all queues */ +static void stop_queue(u32 * qreg) +{ + u32 reg_data; + + reg_data = readl(qreg); + + if (reg_data & 0xFF) { + /* Issue stop command for active channels only */ + writel((reg_data << 8), qreg); + + /* Wait for all queue activity to terminate. */ + do { + /* + * Check port cause register that all queues + * are stopped + */ + reg_data = readl(qreg); + } + while (reg_data & 0xFF); + } +} + +/* + * set_access_control - Config address decode parameters for Ethernet unit + * + * This function configures the address decode parameters for the Gigabit + * Ethernet Controller according the given parameters struct. + * + * @regs Register struct pointer. + * @param Address decode parameter struct. + */ +static void set_access_control(struct kwgbe_registers *regs, + struct kwgbe_winparam *param) +{ + u32 access_prot_reg; + + /* Set access control register */ + access_prot_reg = KWGBEREG_RD(regs->epap); + /* clear window permission */ + access_prot_reg &= (~(3 << (param->win * 2))); + access_prot_reg |= (param->access_ctrl << (param->win * 2)); + KWGBEREG_WR(regs->epap, access_prot_reg); + + /* Set window Size reg (SR) */ + KWGBEREG_WR(regs->barsz[param->win].size, + (((param->size / 0x10000) - 1) << 16)); + + /* Set window Base address reg (BA) */ + KWGBEREG_WR(regs->barsz[param->win].bar, + (param->target | param->attrib | param->base_addr)); + /* High address remap reg (HARR) */ + if (param->win < 4) + KWGBEREG_WR(regs->ha_remap[param->win], param->high_addr); + + /* Base address enable reg (BARER) */ + if (param->enable == 1) + KWGBEREG_BITS_RESET(regs->bare, (1 << param->win)); + else + KWGBEREG_BITS_SET(regs->bare, (1 << param->win)); +} + +static void set_dram_access(struct kwgbe_registers *regs) +{ + struct kwgbe_winparam win_param; + int i; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + /* Set access parameters for DRAM bank i */ + win_param.win = i; /* Use Ethernet window i */ + /* Window target - DDR */ + win_param.target = KWGBE_TARGET_DRAM; + /* Enable full access */ + win_param.access_ctrl = EWIN_ACCESS_FULL; + win_param.high_addr = 0; + /* Get bank base */ + win_param.base_addr = kw_sdram_bar(i); + win_param.size = kw_sdram_bs(i); /* Get bank size */ + if (win_param.size == 0) + win_param.enable = 0; + else + win_param.enable = 1; /* Enable the access */ + + /* Enable DRAM bank */ + switch (i) { + case 0: + win_param.attrib = EBAR_DRAM_CS0; + break; + case 1: + win_param.attrib = EBAR_DRAM_CS1; + break; + case 2: + win_param.attrib = EBAR_DRAM_CS2; + break; + case 3: + win_param.attrib = EBAR_DRAM_CS3; + break; + default: + /* invalide bank, disable access */ + win_param.enable = 0; + win_param.attrib = 0; + break; + } + /* Set the access control for address window(EPAPR) RD/WR */ + set_access_control(regs, &win_param); + } +} + +/* + * port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables + * + * Go through all the DA filter tables (Unicast, Special Multicast & Other + * Multicast) and set each entry to 0. + */ +static void port_init_mac_tables(struct kwgbe_registers *regs) +{ + int table_index; + + /* Clear DA filter unicast table (Ex_dFUT) */ + for (table_index = 0; table_index < 4; ++table_index) + KWGBEREG_WR(regs->dfut[table_index], 0); + + for (table_index = 0; table_index < 64; ++table_index) { + /* Clear DA filter special multicast table (Ex_dFSMT) */ + KWGBEREG_WR(regs->dfsmt[table_index], 0); + /* Clear DA filter other multicast table (Ex_dFOMT) */ + KWGBEREG_WR(regs->dfomt[table_index], 0); + } +} + +/* + * port_uc_addr - This function Set the port unicast address table + * + * This function locates the proper entry in the Unicast table for the + * specified MAC nibble and sets its properties according to function + * parameters. + * This function add/removes MAC addresses from the port unicast address + * table. + * + * @uc_nibble Unicast MAC Address last nibble. + * @option 0 = Add, 1 = remove address. + * + * RETURN: 1 if output succeeded. 0 if option parameter is invalid. + */ +static int port_uc_addr(struct kwgbe_registers *regs, u8 uc_nibble, + int option) +{ + u32 unicast_reg; + u32 tbl_offset; + u32 reg_offset; + + /* Locate the Unicast table entry */ + uc_nibble = (0xf & uc_nibble); + /* Register offset from unicast table base */ + tbl_offset = (uc_nibble / 4); + /* Entry offset within the above register */ + reg_offset = uc_nibble % 4; + + switch (option) { + case REJECT_MAC_ADDR: + /* + * Clear accepts frame bit at specified unicast + * DA table entry + */ + unicast_reg = KWGBEREG_RD(regs->dfut[tbl_offset]); + unicast_reg &= (0xFF << (8 * reg_offset)); + KWGBEREG_WR(regs->dfut[tbl_offset], unicast_reg); + break; + case ACCEPT_MAC_ADDR: + /* Set accepts frame bit at unicast DA filter table entry */ + unicast_reg = KWGBEREG_RD(regs->dfut[tbl_offset]); + unicast_reg &= (0xFF << (8 * reg_offset)); + unicast_reg |= ((0x01 | (RXUQ << 1)) << (8 * reg_offset)); + KWGBEREG_WR(regs->dfut[tbl_offset], unicast_reg); + break; + default: + return 0; + } + return 1; +} + +/* + * port_uc_addr_set - This function Set the port Unicast address. + */ +static void port_uc_addr_set(struct kwgbe_registers *regs, u8 * p_addr) +{ + u32 mac_h; + u32 mac_l; + + mac_l = (p_addr[4] << 8) | (p_addr[5]); + mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) | + (p_addr[3] << 0); + + KWGBEREG_WR(regs->macal, mac_l); + KWGBEREG_WR(regs->macah, mac_h); + + /* Accept frames of this address */ + port_uc_addr(regs, p_addr[5], ACCEPT_MAC_ADDR); +} + +/* + * kwgbe_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory. + */ +static void kwgbe_init_rx_desc_ring(struct kwgbe_device *dkwgbe) +{ + volatile struct kwgbe_rxdesc *p_rx_desc; + int i; + + /* initialize the Rx descriptors ring */ + p_rx_desc = dkwgbe->p_rxdesc; + for (i = 0; i < RINGSZ; i++) { + p_rx_desc->cmd_sts = + KWGBE_BUFFER_OWNED_BY_DMA | KWGBE_RX_EN_INTERRUPT; + p_rx_desc->buf_size = PKTSIZE_ALIGN; + p_rx_desc->byte_cnt = 0; + p_rx_desc->buf_ptr = dkwgbe->p_rxbuf + i * PKTSIZE_ALIGN; + if (i == (RINGSZ - 1)) + p_rx_desc->nxtdesc_p = dkwgbe->p_rxdesc; + else { + p_rx_desc->nxtdesc_p = (struct kwgbe_rxdesc *) + ((u32) p_rx_desc + KW_RXQ_DESC_ALIGNED_SIZE); + p_rx_desc = p_rx_desc->nxtdesc_p; + } + } + dkwgbe->p_rxdesc_curr = dkwgbe->p_rxdesc; +} + +static int kwgbe_init(struct eth_device *dev) +{ + struct kwgbe_device *dkwgbe = to_dkwgbe(dev); + struct kwgbe_registers *regs = dkwgbe->regs; + + /* setup RX rings */ + kwgbe_init_rx_desc_ring(dkwgbe); + + /* Clear the ethernet port interrupts */ + KWGBEREG_WR(regs->ic, 0); + KWGBEREG_WR(regs->ice, 0); + /* Unmask RX buffer and TX end interrupt */ + KWGBEREG_WR(regs->pim, INT_CAUSE_UNMASK_ALL); + /* Unmask phy and link status changes interrupts */ + KWGBEREG_WR(regs->peim, INT_CAUSE_UNMASK_ALL_EXT); + + set_dram_access(regs); + port_init_mac_tables(regs); + port_uc_addr_set(regs, dkwgbe->dev.enetaddr); + + /* Assign port configuration and command. */ + KWGBEREG_WR(regs->pxc, PRT_CFG_VAL); + KWGBEREG_WR(regs->pxcx, PORT_CFG_EXTEND_VALUE); + KWGBEREG_WR(regs->psc0, PORT_SERIAL_CONTROL_VALUE); + /* Disable port initially */ + KWGBEREG_BITS_SET(regs->psc0, KWGBE_SERIAL_PORT_EN); + + /* Assign port SDMA configuration */ + KWGBEREG_WR(regs->sdc, PORT_SDMA_CFG_VALUE); + KWGBEREG_WR(regs->tqx[0].qxttbc, QTKNBKT_DEF_VAL); + KWGBEREG_WR(regs->tqx[0].tqxtbc, (QMTBS_DEF_VAL << 16) | QTKNRT_DEF_VAL); + /* Turn off the port/RXUQ bandwidth limitation */ + KWGBEREG_WR(regs->pmtu, 0); + + /* Set maximum receive buffer to 9700 bytes */ + KWGBEREG_WR(regs->psc0, KWGBE_MAX_RX_PACKET_9700BYTE + | (KWGBEREG_RD(regs->psc0) & MRU_MASK)); + + /* + * Set ethernet MTU for leaky bucket mechanism to 0 - this will + * disable the leaky bucket mechanism . + */ + KWGBEREG_WR(regs->pmtu, 0); + + /* Assignment of Rx CRDB of given RXUQ */ + KWGBEREG_WR(regs->rxcdp[RXUQ].rxcdp, (u32) dkwgbe->p_rxdesc_curr); + /* Enable port Rx. */ + KWGBEREG_WR(regs->rqc, (1 << RXUQ)); + +#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \ + && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN) + u16 phyadr; + miiphy_read(dev->name, 0xEE, 0xEE, &phyadr); + if (!miiphy_link(dev->name, phyadr)) { + printf("%s: No link on %s\n", __FUNCTION__, dev->name); + return -1; + } +#endif + return 0; +} + +static int kwgbe_halt(struct eth_device *dev) +{ + struct kwgbe_device *dkwgbe = to_dkwgbe(dev); + struct kwgbe_registers *regs = dkwgbe->regs; + + /* Disable all gigE address decoder */ + KWGBEREG_WR(regs->bare, 0x3f); + + stop_queue(®s->tqc); + stop_queue(®s->rqc); + + /* Enable port */ + KWGBEREG_BITS_RESET(regs->psc0, KWGBE_SERIAL_PORT_EN); + /* Set port is not reset */ + KWGBEREG_BITS_RESET(regs->psc1, 1 << 4); +#ifdef CONFIG_SYS_MII_MODE + /* Set MMI interface up */ + KWGBEREG_BITS_RESET(regs->psc1, 1 << 3); +#endif + /* Disable & mask ethernet port interrupts */ + KWGBEREG_WR(regs->ic, 0); + KWGBEREG_WR(regs->ice, 0); + KWGBEREG_WR(regs->pim, 0); + KWGBEREG_WR(regs->peim, 0); + + return 0; +} + +static int kwgbe_send(struct eth_device *dev, volatile void *dataptr, + int datasize) +{ + struct kwgbe_device *dkwgbe = to_dkwgbe(dev); + struct kwgbe_registers *regs = dkwgbe->regs; + struct kwgbe_txdesc *p_txdesc = dkwgbe->p_txdesc; + + if ((u32) dataptr & 0x07) { + printf("Err..(%s) xmit dataptr not 64bit aligned\n", + __FUNCTION__); + return -1; + } + p_txdesc->cmd_sts = KWGBE_ZERO_PADDING | KWGBE_GEN_CRC; + p_txdesc->cmd_sts |= KWGBE_TX_FIRST_DESC | KWGBE_TX_LAST_DESC; + p_txdesc->cmd_sts |= KWGBE_BUFFER_OWNED_BY_DMA; + p_txdesc->cmd_sts |= KWGBE_TX_EN_INTERRUPT; + p_txdesc->buf_ptr = (u8 *) dataptr; + p_txdesc->byte_cnt = datasize; + + /* Apply send command using zeroth RXUQ */ + KWGBEREG_WR(regs->tcqdp[TXUQ], (u32) p_txdesc); + KWGBEREG_WR(regs->tqc, (1 << TXUQ)); + + /* + * wait for packet xmit completion + */ + while (p_txdesc->cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA) { + /* return fail if error is detected */ + if (p_txdesc->cmd_sts & (KWGBE_UR_ERROR | KWGBE_RL_ERROR)) { + printf("Err..(%s) in xmit packet\n", __FUNCTION__); + return -1; + } + }; + return 0; +} + +static int kwgbe_recv(struct eth_device *dev) +{ + volatile struct kwgbe_device *dkwgbe = to_dkwgbe(dev); + volatile struct kwgbe_rxdesc *p_rxdesc_curr = dkwgbe->p_rxdesc_curr; + volatile u32 timeout = 0; + + /* wait untill rx packet available or timeout */ + do { + if (timeout < KWGBE_PHY_SMI_TIMEOUT) + timeout++; + else { + debug("%s time out...\n", __FUNCTION__); + return -1; + } + } while (p_rxdesc_curr->cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA); + + if (p_rxdesc_curr->byte_cnt != 0) { + debug("%s: Received %d byte Packet @ 0x%x (cmd_sts= %08x)\n", + __FUNCTION__, (u32) p_rxdesc_curr->byte_cnt, + (u32) p_rxdesc_curr->buf_ptr, + (u32) p_rxdesc_curr->cmd_sts); + } + + /* + * In case received a packet without first/last bits on + * OR the error summary bit is on, + * the packets needs to be dropeed. + */ + if ((p_rxdesc_curr->cmd_sts & + (KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC)) + != (KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC)) { + + printf("Err..(%s) Dropping packet spread on" + " multiple descriptors\n", __FUNCTION__); + + } else if (p_rxdesc_curr->cmd_sts & KWGBE_ERROR_SUMMARY) { + + printf("Err..(%s) Dropping packet with errors\n", + __FUNCTION__); + + } else { + /* !!! call higher layer processing */ + debug("%s: Sending Received packet to" + " upper layer (NetReceive)\n", __FUNCTION__); + + /* let the upper layer handle the packet */ + NetReceive((p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET), + (int)(p_rxdesc_curr->byte_cnt - RX_BUF_OFFSET)); + } + /* + * free these descriptors and point next in the ring + */ + p_rxdesc_curr->cmd_sts = + KWGBE_BUFFER_OWNED_BY_DMA | KWGBE_RX_EN_INTERRUPT; + p_rxdesc_curr->buf_size = PKTSIZE_ALIGN; + p_rxdesc_curr->byte_cnt = 0; + + dkwgbe->p_rxdesc_curr = p_rxdesc_curr->nxtdesc_p; + return 0; +} + +int kirkwood_egiga_initialize(bd_t * bis) +{ + struct kwgbe_device *dkwgbe; + struct eth_device *dev; + int devnum; + char *s, buf[NAMESIZE * 2]; + u8 used_ports[MAX_KWGBE_DEVS] = CONFIG_KIRKWOOD_EGIGA_PORTS; + + for (devnum = 0; devnum < MAX_KWGBE_DEVS; devnum++) { + /*skip if port is configured not to use */ + if (used_ports[devnum] == 0) + continue; + + if (!(dkwgbe = malloc(sizeof(struct kwgbe_device)))) + goto error1; + + memset(dkwgbe, 0, sizeof(struct kwgbe_device)); + + if (!(dkwgbe->p_rxdesc = + (struct kwgbe_rxdesc *)memalign(PKTALIGN, + KW_RXQ_DESC_ALIGNED_SIZE + * RINGSZ + 1))) + goto error2; + + if (!(dkwgbe->p_rxbuf = (u8 *) memalign(PKTALIGN, RINGSZ + * PKTSIZE_ALIGN + 1))) + goto error3; + + if (!(dkwgbe->p_txdesc = (struct kwgbe_txdesc *) + memalign(PKTALIGN, sizeof(struct kwgbe_txdesc) + 1))) { + free(dkwgbe->p_rxbuf); + error3: + free(dkwgbe->p_rxdesc); + error2: + free(dkwgbe); + error1: + printf("Err.. %s Failed to allocate memory\n", + __FUNCTION__); + return -1; + } + + dev = &dkwgbe->dev; + + /* must be less than NAMESIZE (16) */ + sprintf(dev->name, "egiga%d", devnum); + + /* Extract the MAC address from the environment */ + switch (devnum) { + case 0: + dkwgbe->regs = (void *)KW_EGIGA0_BASE; + s = "ethaddr"; + break; + case 1: + dkwgbe->regs = (void *)KW_EGIGA1_BASE; + s = "eth1addr"; + break; + default: /* this should never happen */ + printf("Err..(%s) Invalid device number %d\n", + __FUNCTION__, devnum); + return -1; + } + + while (!eth_getenv_enetaddr(s, dev->enetaddr)) { + /* Generate Ramdom MAC addresses if not set */ + sprintf(buf, "00:50:43:%02x:%02x:%02x", + get_random_hex(), get_random_hex(), + get_random_hex()); + setenv(s, buf); + } + + dev->init = (void *)kwgbe_init; + dev->halt = (void *)kwgbe_halt; + dev->send = (void *)kwgbe_send; + dev->recv = (void *)kwgbe_recv; + + eth_register(dev); + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + miiphy_register(dev->name, smi_reg_read, smi_reg_write); + /* Set phy address of the port */ + miiphy_write(dev->name, 0xEE, 0xEE, PHY_BASE_ADR + devnum); +#endif + } + return 0; diff --git a/drivers/net/kirkwood_egiga.h b/drivers/net/kirkwood_egiga.h new file mode 100644 index 0000000..8b67c9c --- /dev/null +++ b/drivers/net/kirkwood_egiga.h @@ -0,0 +1,503 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor + * Written-by: Prafulla Wadaskar + * + * based on - Driver for MV64360X ethernet ports + * Copyright (C) 2002 rabeeh@galileo.co.il + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef __EGIGA_H__ +#define __EGIGA_H__ + +#define MAX_KWGBE_DEVS 2 /*controller has two ports */ + +/* PHY_BASE_ADR is board specific and can be configured */ +#if defined (CONFIG_PHY_BASE_ADR) +#define PHY_BASE_ADR CONFIG_PHY_BASE_ADR +#else +#define PHY_BASE_ADR 0x08 /* default phy base addr */ +#endif + +/* Constants */ +#define INT_CAUSE_UNMASK_ALL 0x0007ffff +#define INT_CAUSE_UNMASK_ALL_EXT 0x0011ffff +#define MRU_MASK 0xfff1ffff +#define PHYADR_MASK 0x0000001f +#define PHYREG_MASK 0x0000001f +#define QTKNBKT_DEF_VAL 0x3fffffff +#define QMTBS_DEF_VAL 0x000003ff +#define QTKNRT_DEF_VAL 0x0000fcff +#define RXUQ 0 /* Used Rx queue */ +#define TXUQ 0 /* Used Rx queue */ + +#define to_dkwgbe(_kd) container_of(_kd, struct kwgbe_device, dev) +#define KWGBEREG_WR(adr, val) writel(val, &adr) +#define KWGBEREG_RD(adr) readl(&adr) +#define KWGBEREG_BITS_RESET(adr, val) writel(readl(&adr) & ~(val), &adr) +#define KWGBEREG_BITS_SET(adr, val) writel(readl(&adr) | val, &adr) + +/* Default port configuration value */ +#define PRT_CFG_VAL ( \ + KWGBE_UCAST_MOD_NRML | \ + KWGBE_DFLT_RXQ(RXUQ) | \ + KWGBE_DFLT_RX_ARPQ(RXUQ) | \ + KWGBE_RX_BC_IF_NOT_IP_OR_ARP | \ + KWGBE_RX_BC_IF_IP | \ + KWGBE_RX_BC_IF_ARP | \ + KWGBE_CPTR_TCP_FRMS_DIS | \ + KWGBE_CPTR_UDP_FRMS_DIS | \ + KWGBE_DFLT_RX_TCPQ(RXUQ) | \ + KWGBE_DFLT_RX_UDPQ(RXUQ) | \ + KWGBE_DFLT_RX_BPDUQ(RXUQ)) + +/* Default port extend configuration value */ +#define PORT_CFG_EXTEND_VALUE \ + KWGBE_SPAN_BPDU_PACKETS_AS_NORMAL | \ + KWGBE_PARTITION_DIS | \ + KWGBE_TX_CRC_GENERATION_EN + +#define GT_KWGBE_IPG_INT_RX(value) ((value & 0x3fff) << 8) + +/* Default sdma control value */ +#define PORT_SDMA_CFG_VALUE ( \ + KWGBE_RX_BURST_SIZE_16_64BIT | \ + KWGBE_BLM_RX_NO_SWAP | \ + KWGBE_BLM_TX_NO_SWAP | \ + GT_KWGBE_IPG_INT_RX(RXUQ) | \ + KWGBE_TX_BURST_SIZE_16_64BIT) + +/* Default port serial control value */ +#define PORT_SERIAL_CONTROL_VALUE ( \ + KWGBE_FORCE_LINK_PASS | \ + KWGBE_DIS_AUTO_NEG_FOR_DUPLX | \ + KWGBE_DIS_AUTO_NEG_FOR_FLOW_CTRL | \ + KWGBE_ADV_NO_FLOW_CTRL | \ + KWGBE_FORCE_FC_MODE_NO_PAUSE_DIS_TX | \ + KWGBE_FORCE_BP_MODE_NO_JAM | \ + (1 << 9) /* Reserved bit has to be 1 */ | \ + KWGBE_DO_NOT_FORCE_LINK_FAIL | \ + KWGBE_EN_AUTO_NEG_SPEED_GMII | \ + KWGBE_DTE_ADV_0 | \ + KWGBE_MIIPHY_MAC_MODE | \ + KWGBE_AUTO_NEG_NO_CHANGE | \ + KWGBE_MAX_RX_PACKET_1552BYTE | \ + KWGBE_CLR_EXT_LOOPBACK | \ + KWGBE_SET_FULL_DUPLEX_MODE | \ + KWGBE_DIS_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX) + +/* Tx WRR confoguration macros */ +#define PORT_MAX_TRAN_UNIT 0x24 /* MTU register (default) 9KByte */ +#define PORT_MAX_TOKEN_BUCKET_SIZE 0x_FFFF /* PMTBS reg (default) */ +#define PORT_TOKEN_RATE 1023 /* PTTBRC reg (default) */ +/* MAC accepet/reject macros */ +#define ACCEPT_MAC_ADDR 0 +#define REJECT_MAC_ADDR 1 +/* Size of a Tx/Rx descriptor used in chain list data structure */ +#define KW_RXQ_DESC_ALIGNED_SIZE \ + (((sizeof(struct kwgbe_rxdesc) / PKTALIGN) + 1) * PKTALIGN) +/* Buffer offset from buffer pointer */ +#define RX_BUF_OFFSET 0x2 + +/* Port serial status reg (PSR) */ +#define KWGBE_INTERFACE_GMII_MII 0 +#define KWGBE_INTERFACE_PCM 1 +#define KWGBE_LINK_IS_DOWN 0 +#define KWGBE_LINK_IS_UP (1 << 1) +#define KWGBE_PORT_AT_HALF_DUPLEX 0 +#define KWGBE_PORT_AT_FULL_DUPLEX (1 << 2) +#define KWGBE_RX_FLOW_CTRL_DISD 0 +#define KWGBE_RX_FLOW_CTRL_ENBALED (1 << 3) +#define KWGBE_GMII_SPEED_100_10 0 +#define KWGBE_GMII_SPEED_1000 (1 << 4) +#define KWGBE_MII_SPEED_10 0 +#define KWGBE_MII_SPEED_100 (1 << 5) +#define KWGBE_NO_TX 0 +#define KWGBE_TX_IN_PROGRESS (1 << 7) +#define KWGBE_BYPASS_NO_ACTIVE 0 +#define KWGBE_BYPASS_ACTIVE (1 << 8) +#define KWGBE_PORT_NOT_AT_PARTN_STT 0 +#define KWGBE_PORT_AT_PARTN_STT (1 << 9) +#define KWGBE_PORT_TX_FIFO_NOT_EMPTY 0 +#define KWGBE_PORT_TX_FIFO_EMPTY (1 << 10) + +/* These macros describes the Port configuration reg (Px_cR) bits */ +#define KWGBE_UCAST_MOD_NRML 0 +#define KWGBE_UNICAST_PROMISCUOUS_MODE 1 +#define KWGBE_DFLT_RXQ(_x) (_x << 1) +#define KWGBE_DFLT_RX_ARPQ(_x) (_x << 4) +#define KWGBE_RX_BC_IF_NOT_IP_OR_ARP 0 +#define KWGBE_REJECT_BC_IF_NOT_IP_OR_ARP (1 << 7) +#define KWGBE_RX_BC_IF_IP 0 +#define KWGBE_REJECT_BC_IF_IP (1 << 8) +#define KWGBE_RX_BC_IF_ARP 0 +#define KWGBE_REJECT_BC_IF_ARP (1 << 9) +#define KWGBE_TX_AM_NO_UPDATE_ERR_SMRY (1 << 12) +#define KWGBE_CPTR_TCP_FRMS_DIS 0 +#define KWGBE_CPTR_TCP_FRMS_EN (1 << 14) +#define KWGBE_CPTR_UDP_FRMS_DIS 0 +#define KWGBE_CPTR_UDP_FRMS_EN (1 << 15) +#define KWGBE_DFLT_RX_TCPQ(_x) (_x << 16) +#define KWGBE_DFLT_RX_UDPQ(_x) (_x << 19) +#define KWGBE_DFLT_RX_BPDUQ(_x) (_x << 22) +#define KWGBE_DFLT_RX_TCP_CHKSUM_MODE (1 << 25) + +/* These macros describes the Port configuration extend reg (Px_cXR) bits*/ +#define KWGBE_CLASSIFY_EN 1 +#define KWGBE_SPAN_BPDU_PACKETS_AS_NORMAL 0 +#define KWGBE_SPAN_BPDU_PACKETS_TO_RX_Q7 (1 << 1) +#define KWGBE_PARTITION_DIS 0 +#define KWGBE_PARTITION_EN (1 << 2) +#define KWGBE_TX_CRC_GENERATION_EN 0 +#define KWGBE_TX_CRC_GENERATION_DIS (1 << 3) + +/* These macros describes the Port Sdma configuration reg (SDCR) bits */ +#define KWGBE_RIFB 1 +#define KWGBE_RX_BURST_SIZE_1_64BIT 0 +#define KWGBE_RX_BURST_SIZE_2_64BIT (1 << 1) +#define KWGBE_RX_BURST_SIZE_4_64BIT (1 << 2) +#define KWGBE_RX_BURST_SIZE_8_64BIT ((1 << 2) | (1 << 1)) +#define KWGBE_RX_BURST_SIZE_16_64BIT (1 << 3) +#define KWGBE_BLM_RX_NO_SWAP (1 << 4) +#define KWGBE_BLM_RX_BYTE_SWAP 0 +#define KWGBE_BLM_TX_NO_SWAP (1 << 5) +#define KWGBE_BLM_TX_BYTE_SWAP 0 +#define KWGBE_DESCRIPTORS_BYTE_SWAP (1 << 6) +#define KWGBE_DESCRIPTORS_NO_SWAP 0 +#define KWGBE_TX_BURST_SIZE_1_64BIT 0 +#define KWGBE_TX_BURST_SIZE_2_64BIT (1 << 22) +#define KWGBE_TX_BURST_SIZE_4_64BIT (1 << 23) +#define KWGBE_TX_BURST_SIZE_8_64BIT ((1 << 23) | (1 << 22)) +#define KWGBE_TX_BURST_SIZE_16_64BIT (1 << 24) + +/* These macros describes the Port serial control reg (PSCR) bits */ +#define KWGBE_SERIAL_PORT_DIS 0 +#define KWGBE_SERIAL_PORT_EN 1 +#define KWGBE_FORCE_LINK_PASS (1 << 1) +#define KWGBE_DO_NOT_FORCE_LINK_PASS 0 +#define KWGBE_EN_AUTO_NEG_FOR_DUPLX 0 +#define KWGBE_DIS_AUTO_NEG_FOR_DUPLX (1 << 2) +#define KWGBE_EN_AUTO_NEG_FOR_FLOW_CTRL 0 +#define KWGBE_DIS_AUTO_NEG_FOR_FLOW_CTRL (1 << 3) +#define KWGBE_ADV_NO_FLOW_CTRL 0 +#define KWGBE_ADV_SYMMETRIC_FLOW_CTRL (1 << 4) +#define KWGBE_FORCE_FC_MODE_NO_PAUSE_DIS_TX 0 +#define KWGBE_FORCE_FC_MODE_TX_PAUSE_DIS (1 << 5) +#define KWGBE_FORCE_BP_MODE_NO_JAM 0 +#define KWGBE_FORCE_BP_MODE_JAM_TX (1 << 7) +#define KWGBE_FORCE_BP_MODE_JAM_TX_ON_RX_ERR (1 << 8) +#define KWGBE_FORCE_LINK_FAIL 0 +#define KWGBE_DO_NOT_FORCE_LINK_FAIL (1 << 10) +#define KWGBE_DIS_AUTO_NEG_SPEED_GMII (1 << 13) +#define KWGBE_EN_AUTO_NEG_SPEED_GMII 0 +#define KWGBE_DTE_ADV_0 0 +#define KWGBE_DTE_ADV_1 (1 << 14) +#define KWGBE_MIIPHY_MAC_MODE 0 +#define KWGBE_MIIPHY_PHY_MODE (1 << 15) +#define KWGBE_AUTO_NEG_NO_CHANGE 0 +#define KWGBE_RESTART_AUTO_NEG (1 << 16) +#define KWGBE_MAX_RX_PACKET_1518BYTE 0 +#define KWGBE_MAX_RX_PACKET_1522BYTE (1 << 17) +#define KWGBE_MAX_RX_PACKET_1552BYTE (1 << 18) +#define KWGBE_MAX_RX_PACKET_9022BYTE ((1 << 18) | (1 << 17)) +#define KWGBE_MAX_RX_PACKET_9192BYTE (1 << 19) +#define KWGBE_MAX_RX_PACKET_9700BYTE ((1 << 19) | (1 << 17)) +#define KWGBE_SET_EXT_LOOPBACK (1 << 20) +#define KWGBE_CLR_EXT_LOOPBACK 0 +#define KWGBE_SET_FULL_DUPLEX_MODE (1 << 21) +#define KWGBE_SET_HALF_DUPLEX_MODE 0 +#define KWGBE_EN_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX (1 << 22) +#define KWGBE_DIS_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX 0 +#define KWGBE_SET_GMII_SPEED_TO_10_100 0 +#define KWGBE_SET_GMII_SPEED_TO_1000 (1 << 23) +#define KWGBE_SET_MII_SPEED_TO_10 0 +#define KWGBE_SET_MII_SPEED_TO_100 (1 << 24) + +/* SMI register fields */ +#define KWGBE_PHY_SMI_TIMEOUT 10000 +#define KWGBE_PHY_SMI_DATA_OFFS 0 /* Data */ +#define KWGBE_PHY_SMI_DATA_MASK (0xffff << KWGBE_PHY_SMI_DATA_OFFS) +#define KWGBE_PHY_SMI_DEV_ADDR_OFFS 16 /* PHY device address */ +#define KWGBE_PHY_SMI_DEV_ADDR_MASK (PHYADR_MASK << KWGBE_PHY_SMI_DEV_ADDR_OFFS) +#define KWGBE_SMI_REG_ADDR_OFFS 21 /* PHY device reg addr */ +#define KWGBE_SMI_REG_ADDR_MASK (PHYADR_MASK << KWGBE_SMI_REG_ADDR_OFFS) +#define KWGBE_PHY_SMI_OPCODE_OFFS 26 /* Write/Read opcode */ +#define KWGBE_PHY_SMI_OPCODE_MASK (3 << KWGBE_PHY_SMI_OPCODE_OFFS) +#define KWGBE_PHY_SMI_OPCODE_WRITE (0 << KWGBE_PHY_SMI_OPCODE_OFFS) +#define KWGBE_PHY_SMI_OPCODE_READ (1 << KWGBE_PHY_SMI_OPCODE_OFFS) +#define KWGBE_PHY_SMI_READ_VALID_MASK (1 << 27) /* Read Valid */ +#define KWGBE_PHY_SMI_BUSY_MASK (1 << 28) /* Busy */ + +/* SDMA command status fields macros */ +/* Tx & Rx descriptors status */ +#define KWGBE_ERROR_SUMMARY 1 +/* Tx & Rx descriptors command */ +#define KWGBE_BUFFER_OWNED_BY_DMA (1 << 31) +/* Tx descriptors status */ +#define KWGBE_LC_ERROR 0 +#define KWGBE_UR_ERROR (1 << 1) +#define KWGBE_RL_ERROR (1 << 2) +#define KWGBE_LLC_SNAP_FORMAT (1 << 9) + +/* Rx descriptors status */ +#define KWGBE_CRC_ERROR 0 +#define KWGBE_OVERRUN_ERROR (1 << 1) +#define KWGBE_MAX_FRAME_LENGTH_ERROR (1 << 2) +#define KWGBE_RESOURCE_ERROR ((1 << 2) | (1 << 1)) +#define KWGBE_VLAN_TAGGED (1 << 19) +#define KWGBE_BPDU_FRAME (1 << 20) +#define KWGBE_TCP_FRAME_OVER_IP_V_4 0 +#define KWGBE_UDP_FRAME_OVER_IP_V_4 (1 << 21) +#define KWGBE_OTHER_FRAME_TYPE (1 << 22) +#define KWGBE_LAYER_2_IS_KWGBE_V_2 (1 << 23) +#define KWGBE_FRAME_TYPE_IP_V_4 (1 << 24) +#define KWGBE_FRAME_HEADER_OK (1 << 25) +#define KWGBE_RX_LAST_DESC (1 << 26) +#define KWGBE_RX_FIRST_DESC (1 << 27) +#define KWGBE_UNKNOWN_DESTINATION_ADDR (1 << 28) +#define KWGBE_RX_EN_INTERRUPT (1 << 29) +#define KWGBE_LAYER_4_CHECKSUM_OK (1 << 30) + +/* Rx descriptors byte count */ +#define KWGBE_FRAME_FRAGMENTED (1 << 2) + +/* Tx descriptors command */ +#define KWGBE_LAYER_4_CHECKSUM_FIRST_DESC (1 << 10) +#define KWGBE_FRAME_SET_TO_VLAN (1 << 15) +#define KWGBE_TCP_FRAME 0 +#define KWGBE_UDP_FRAME (1 << 16) +#define KWGBE_GEN_TCP_UDP_CHECKSUM (1 << 17) +#define KWGBE_GEN_IP_V_4_CHECKSUM (1 << 18) +#define KWGBE_ZERO_PADDING (1 << 19) +#define KWGBE_TX_LAST_DESC (1 << 20) +#define KWGBE_TX_FIRST_DESC (1 << 21) +#define KWGBE_GEN_CRC (1 << 22) +#define KWGBE_TX_EN_INTERRUPT (1 << 23) +#define KWGBE_AUTO_MODE (1 << 30) + +/* Address decode parameters */ +/* Ethernet Base Address Register bits */ +#define EBAR_TARGET_DRAM 0x00000000 +#define EBAR_TARGET_DEVICE 0x00000001 +#define EBAR_TARGET_CBS 0x00000002 +#define EBAR_TARGET_PCI0 0x00000003 +#define EBAR_TARGET_PCI1 0x00000004 +#define EBAR_TARGET_CUNIT 0x00000005 +#define EBAR_TARGET_AUNIT 0x00000006 +#define EBAR_TARGET_GUNIT 0x00000007 + +/* Window attrib */ +#define EBAR_DRAM_CS0 0x00000E00 +#define EBAR_DRAM_CS1 0x00000D00 +#define EBAR_DRAM_CS2 0x00000B00 +#define EBAR_DRAM_CS3 0x00000700 + +/* DRAM Target interface */ +#define EBAR_DRAM_NO_CACHE_COHERENCY 0x00000000 +#define EBAR_DRAM_CACHE_COHERENCY_WT 0x00001000 +#define EBAR_DRAM_CACHE_COHERENCY_WB 0x00002000 + +/* Device Bus Target interface */ +#define EBAR_DEVICE_DEVCS0 0x00001E00 +#define EBAR_DEVICE_DEVCS1 0x00001D00 +#define EBAR_DEVICE_DEVCS2 0x00001B00 +#define EBAR_DEVICE_DEVCS3 0x00001700 +#define EBAR_DEVICE_BOOTCS3 0x00000F00 + +/* PCI Target interface */ +#define EBAR_PCI_BYTE_SWAP 0x00000000 +#define EBAR_PCI_NO_SWAP 0x00000100 +#define EBAR_PCI_BYTE_WORD_SWAP 0x00000200 +#define EBAR_PCI_WORD_SWAP 0x00000300 +#define EBAR_PCI_NO_SNOOP_NOT_ASSERT 0x00000000 +#define EBAR_PCI_NO_SNOOP_ASSERT 0x00000400 +#define EBAR_PCI_IO_SPACE 0x00000000 +#define EBAR_PCI_MEMORY_SPACE 0x00000800 +#define EBAR_PCI_REQ64_FORCE 0x00000000 +#define EBAR_PCI_REQ64_SIZE 0x00001000 + +/* Window access control */ +#define EWIN_ACCESS_NOT_ALLOWED 0 +#define EWIN_ACCESS_READ_ONLY 1 +#define EWIN_ACCESS_FULL ((1 << 1) | 1) + +/* structures represents Controller registers */ +struct kwgbe_barsz { + u32 bar; + u32 size; +}; + +struct kwgbe_rxcdp { + struct kwgbe_rxdesc *rxcdp; + u32 rxcdp_pad[3]; +}; + +struct kwgbe_tqx { + u32 qxttbc; + u32 tqxtbc; + u32 tqxac; + u32 tqxpad; +}; + +struct kwgbe_registers { + u32 phyadr; + u32 smi; + u32 euda; + u32 eudid; + u8 pad1[0x080 - 0x00c - 4]; + u32 euic; + u32 euim; + u8 pad2[0x094 - 0x084 - 4]; + u32 euea; + u32 euiae; + u8 pad3[0x0b0 - 0x098 - 4]; + u32 euc; + u8 pad3a[0x200 - 0x0b0 - 4]; + struct kwgbe_barsz barsz[6]; + u8 pad4[0x280 - 0x22c - 4]; + u32 ha_remap[4]; + u32 bare; + u32 epap; + u8 pad5[0x400 - 0x294 - 4]; + u32 pxc; + u32 pxcx; + u32 mii_ser_params; + u8 pad6[0x410 - 0x408 - 4]; + u32 evlane; + u32 macal; + u32 macah; + u32 sdc; + u32 dscp[7]; + u32 psc0; + u32 vpt2p; + u32 ps0; + u32 tqc; + u32 psc1; + u32 ps1; + u32 mrvl_header; + u8 pad7[0x460 - 0x454 - 4]; + u32 ic; + u32 ice; + u32 pim; + u32 peim; + u8 pad8[0x474 - 0x46c - 4]; + u32 pxtfut; + u32 pad9; + u32 pxmfs; + u32 pad10; + u32 pxdfc; + u32 pxofc; + u8 pad11[0x494 - 0x488 - 4]; + u32 peuiae; + u8 pad12[0x4bc - 0x494 - 4]; + u32 eth_type_prio; + u8 pad13[0x4dc - 0x4bc - 4]; + u32 tqfpc; + u32 pttbrc; + u32 tqc1; + u32 pmtu; + u32 pmtbs; + u8 pad14[0x60c - 0x4ec - 4]; + struct kwgbe_rxcdp rxcdp[7]; + u32 rxcdp7; + u32 rqc; + struct kwgbe_txdesc *tcsdp; + u8 pad15[0x6c0 - 0x684 - 4]; + struct kwgbe_txdesc *tcqdp[8]; + u8 pad16[0x700 - 0x6dc - 4]; + struct kwgbe_tqx tqx[8]; + u32 pttbc; + u8 pad17[0x7a8 - 0x780 - 4]; + u32 tqxipg0; + u32 pad18[3]; + u32 tqxipg1; + u8 pad19[0x7c0 - 0x7b8 - 4]; + u32 hitkninlopkt; + u32 hitkninasyncpkt; + u32 lotkninasyncpkt; + u32 pad20; + u32 ts; + u8 pad21[0x3000 - 0x27d0 - 4]; + u32 pad20_1[32]; /* mib counter registes */ + u8 pad22[0x3400 - 0x3000 - sizeof(u32) * 32]; + u32 dfsmt[64]; + u32 dfomt[64]; + u32 dfut[4]; + u8 pad23[0xe20c0 - 0x7360c - 4]; + u32 pmbus_top_arbiter; +}; + +/* structures/enums needed by driver */ +enum kwgbe_adrwin { + KWGBE_WIN0, + KWGBE_WIN1, + KWGBE_WIN2, + KWGBE_WIN3, + KWGBE_WIN4, + KWGBE_WIN5 +}; + +enum kwgbe_target { + KWGBE_TARGET_DRAM, + KWGBE_TARGET_DEV, + KWGBE_TARGET_CBS, + KWGBE_TARGET_PCI0, + KWGBE_TARGET_PCI1 +}; + +struct kwgbe_winparam { + enum kwgbe_adrwin win; /* Window number */ + enum kwgbe_target target; /* System targets */ + u16 attrib; /* BAR attrib. See above macros */ + u32 base_addr; /* Window base address in u32 form */ + u32 high_addr; /* Window high address in u32 form */ + u32 size; /* Size in MBytes. Must be % 64Kbyte. */ + int enable; /* Enable/disable access to the window. */ + u16 access_ctrl; /*Access ctrl register. see above macros */ +}; + +struct kwgbe_rxdesc { + u32 cmd_sts; /* Descriptor command status */ + u16 buf_size; /* Buffer size */ + u16 byte_cnt; /* Descriptor buffer byte count */ + u8 *buf_ptr; /* Descriptor buffer pointer */ + struct kwgbe_rxdesc *nxtdesc_p; /* Next descriptor pointer */ +}; + +struct kwgbe_txdesc { + u32 cmd_sts; /* Descriptor command status */ + u16 l4i_chk; /* CPU provided TCP Checksum */ + u16 byte_cnt; /* Descriptor buffer byte count */ + u8 *buf_ptr; /* Descriptor buffer ptr */ + struct kwgbe_txdesc *nxtdesc_p; /* Next descriptor ptr */ +}; + +/* port device data struct */ +struct kwgbe_device { + struct eth_device dev; + struct kwgbe_registers *regs; + struct kwgbe_txdesc *p_txdesc; + struct kwgbe_rxdesc *p_rxdesc; + struct kwgbe_rxdesc *p_rxdesc_curr; + u8 *p_rxbuf; +}; + +#endif /* __EGIGA_H__ */ diff --git a/include/netdev.h b/include/netdev.h index df3bc63..5571070 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -53,6 +53,7 @@ int fec_initialize (bd_t *bis); int greth_initialize(bd_t *bis); void gt6426x_eth_initialize(bd_t *bis); int inca_switch_initialize(bd_t *bis); +int kirkwood_egiga_initialize(bd_t *bis); int macb_eth_initialize(int id, void *regs, unsigned int phy_addr); int mcdmafec_initialize(bd_t *bis); int mcffec_initialize(bd_t *bis); -- cgit v1.1 From 60f61e6d7655400bb785a2ef637581679941f6d1 Mon Sep 17 00:00:00 2001 From: Remy Bohmer Date: Sat, 2 May 2009 21:49:18 +0200 Subject: Convert DM9000 driver for CONFIG_NET_MULTI All drivers need to be converted to CONFIG_NET_MULTI. This patch converts the dm9000 driver. Signed-off-by: Thomas Smits Signed-off-by: Remy Bohmer Signed-off-by: Ben Warren --- board/atmel/at91sam9261ek/at91sam9261ek.c | 7 +++++ board/freescale/m5253demo/m5253demo.c | 9 +++++++ board/scb9328/scb9328.c | 8 ++++++ board/trizepsiv/conxs.c | 8 ++++++ drivers/net/dm9000x.c | 44 +++++++++++++++++++------------ include/configs/M5253DEMO.h | 1 + include/configs/at91sam9261ek.h | 1 + include/configs/scb9328.h | 1 + include/configs/trizepsiv.h | 1 + include/netdev.h | 1 + 10 files changed, 64 insertions(+), 17 deletions(-) diff --git a/board/atmel/at91sam9261ek/at91sam9261ek.c b/board/atmel/at91sam9261ek/at91sam9261ek.c index a89cb8b..0817e60 100644 --- a/board/atmel/at91sam9261ek/at91sam9261ek.c +++ b/board/atmel/at91sam9261ek/at91sam9261ek.c @@ -36,6 +36,7 @@ #include #if defined(CONFIG_RESET_PHY_R) && defined(CONFIG_DRIVER_DM9000) #include +#include #endif DECLARE_GLOBAL_DATA_PTR; @@ -227,6 +228,12 @@ int board_init(void) return 0; } +#ifdef CONFIG_DRIVER_DM9000 + int board_eth_init(bd_t *bis) + { + return dm9000_initialize(bis); + } + #endif int dram_init(void) { gd->bd->bi_dram[0].start = PHYS_SDRAM; diff --git a/board/freescale/m5253demo/m5253demo.c b/board/freescale/m5253demo/m5253demo.c index b39cd4d..4772074 100644 --- a/board/freescale/m5253demo/m5253demo.c +++ b/board/freescale/m5253demo/m5253demo.c @@ -26,6 +26,7 @@ #include #include +#include int checkboard(void) { @@ -138,3 +139,11 @@ void ide_set_reset(int idereset) } } #endif /* CONFIG_CMD_IDE */ + + +#ifdef CONFIG_DRIVER_DM9000 +int board_eth_init(bd_t *bis) +{ + return dm9000_initialize(bis); +} +#endif diff --git a/board/scb9328/scb9328.c b/board/scb9328/scb9328.c index 3f6831b..428e8c9 100644 --- a/board/scb9328/scb9328.c +++ b/board/scb9328/scb9328.c @@ -19,6 +19,7 @@ */ #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -70,3 +71,10 @@ void show_boot_progress (int status) { return; } + +#ifdef CONFIG_DRIVER_DM9000 +int board_eth_init(bd_t *bis) +{ + return dm9000_initialize(bis); +} +#endif diff --git a/board/trizepsiv/conxs.c b/board/trizepsiv/conxs.c index 7c6c855..5c0eb41 100644 --- a/board/trizepsiv/conxs.c +++ b/board/trizepsiv/conxs.c @@ -33,6 +33,7 @@ #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -144,3 +145,10 @@ int dram_init (void) return 0; } + +#ifdef CONFIG_DRIVER_DM9000 +int board_eth_init(bd_t *bis) +{ + return dm9000_initialize(bis); +} +#endif diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c index f139435..efe9135 100644 --- a/drivers/net/dm9000x.c +++ b/drivers/net/dm9000x.c @@ -103,14 +103,12 @@ typedef struct board_info { void (*outblk)(volatile void *data_ptr, int count); void (*inblk)(void *data_ptr, int count); void (*rx_status)(u16 *RxStatus, u16 *RxLen); + struct eth_device netdev; } board_info_t; static board_info_t dm9000_info; + /* function declaration ------------------------------------- */ -int eth_init(bd_t * bd); -int eth_send(volatile void *, int); -int eth_rx(void); -void eth_halt(void); static int dm9000_probe(void); static u16 phy_read(int); static void phy_write(int, u16); @@ -279,17 +277,16 @@ dm9000_reset(void) printf("ERROR: resetting DM9000 -> not responding\n"); } -/* Initilize dm9000 board +/* Initialize dm9000 board */ -int -eth_init(bd_t * bd) +static int dm9000_init(struct eth_device *dev, bd_t *bd) { int i, oft, lnk; u8 io_mode; struct board_info *db = &dm9000_info; uchar enetaddr[6]; - DM9000_DBG("eth_init()\n"); + DM9000_DBG("%s\n", __func__); /* RESET device */ dm9000_reset(); @@ -411,13 +408,13 @@ eth_init(bd_t * bd) Hardware start transmission. Send a packet to media from the upper layer. */ -int -eth_send(volatile void *packet, int length) +static int dm9000_send(struct eth_device *netdev, volatile void *packet, + int length) { int tmo; struct board_info *db = &dm9000_info; - DM9000_DMP_PACKET("eth_send", packet, length); + DM9000_DMP_PACKET(__func__ , packet, length); DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */ @@ -453,10 +450,9 @@ eth_send(volatile void *packet, int length) Stop the interface. The interface is stopped when it is brought. */ -void -eth_halt(void) +static void dm9000_halt(struct eth_device *netdev) { - DM9000_DBG("eth_halt\n"); + DM9000_DBG("%s\n", __func__); /* RESET devie */ phy_write(0, 0x8000); /* PHY RESET */ @@ -468,8 +464,7 @@ eth_halt(void) /* Received a packet and pass to upper layer */ -int -eth_rx(void) +static int dm9000_rx(struct eth_device *netdev) { u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0]; u16 RxStatus, RxLen = 0; @@ -529,7 +524,7 @@ eth_rx(void) dm9000_reset(); } } else { - DM9000_DMP_PACKET("eth_rx", rdptr, RxLen); + DM9000_DMP_PACKET(__func__ , rdptr, RxLen); DM9000_DBG("passing packet to upper layer\n"); NetReceive(NetRxPackets[0], RxLen); @@ -621,3 +616,18 @@ phy_write(int reg, u16 value) DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */ DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value); } + +int dm9000_initialize(bd_t *bis) +{ + struct eth_device *dev = &(dm9000_info.netdev); + + dev->init = dm9000_init; + dev->halt = dm9000_halt; + dev->send = dm9000_send; + dev->recv = dm9000_rx; + sprintf(dev->name, "dm9000"); + + eth_register(dev); + + return 0; +} diff --git a/include/configs/M5253DEMO.h b/include/configs/M5253DEMO.h index 1fea6c3..50b3a03 100644 --- a/include/configs/M5253DEMO.h +++ b/include/configs/M5253DEMO.h @@ -88,6 +88,7 @@ # define _IO_BASE 0 #endif +#define CONFIG_NET_MULTI 1 #define CONFIG_DRIVER_DM9000 #ifdef CONFIG_DRIVER_DM9000 # define CONFIG_DM9000_BASE (CONFIG_SYS_CS1_BASE | 0x300) diff --git a/include/configs/at91sam9261ek.h b/include/configs/at91sam9261ek.h index 4f6b640..83e05b3 100644 --- a/include/configs/at91sam9261ek.h +++ b/include/configs/at91sam9261ek.h @@ -131,6 +131,7 @@ #define CONFIG_SYS_NO_FLASH 1 /* Ethernet */ +#define CONFIG_NET_MULTI 1 #define CONFIG_DRIVER_DM9000 1 #define CONFIG_DM9000_BASE 0x30000000 #define DM9000_IO CONFIG_DM9000_BASE diff --git a/include/configs/scb9328.h b/include/configs/scb9328.h index 893c3d3..5556714 100644 --- a/include/configs/scb9328.h +++ b/include/configs/scb9328.h @@ -255,6 +255,7 @@ #define CONFIG_SYS_CS5U_VAL 0x00008400 #define CONFIG_SYS_CS5L_VAL 0x00000D03 +#define CONFIG_NET_MULTI 1 #define CONFIG_DRIVER_DM9000 1 #define CONFIG_DM9000_BASE 0x16000000 #define DM9000_IO CONFIG_DM9000_BASE diff --git a/include/configs/trizepsiv.h b/include/configs/trizepsiv.h index 49045fd..bfa7157 100644 --- a/include/configs/trizepsiv.h +++ b/include/configs/trizepsiv.h @@ -278,6 +278,7 @@ #define CONFIG_SYS_MCIO0_VAL 0x00008407 #define CONFIG_SYS_MCIO1_VAL 0x0000c108 +#define CONFIG_NET_MULTI 1 #define CONFIG_DRIVER_DM9000 1 #define CONFIG_DM9000_BASE 0x08000000 #define DM9000_IO CONFIG_DM9000_BASE diff --git a/include/netdev.h b/include/netdev.h index 5571070..aed5c4c 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -75,6 +75,7 @@ int tsi108_eth_initialize(bd_t *bis); int uec_initialize(int index); int uli526x_initialize(bd_t *bis); int sh_eth_initialize(bd_t *bis); +int dm9000_initialize(bd_t *bis); /* Boards with PCI network controllers can call this from their board_eth_init() * function to initialize whatever's on board. -- cgit v1.1