Skip to contentSkip to conversation

powerpc/p4080: add support for FMan ethernet in Independent mode

PATCH New Mingkai Hu 6 participants 26 messages Jan 27, 2011 – Feb 5, 2011

Subsystems (3)
lore
Share & tools
lore

Mingkai Hu

author
#0 lore raw

cover powerpc/p4080: add support for FMan ethernet in Independent mode

This patchset add support for the P4080's datapath accelation architecture in independent mode, and do some code refactor of the file tsec.c.

1. Add the releated MAC controller support, includeing dTSEC and 10GEC
2. Add support for FMan ethernet in Independent mode
3. Add PHY support (VSC8244 and VSC8234) to a new file fsl_phy.c which can be reused by other code, such tsec and uec code.
4. tsec code cleanup
5. Move all the PHY code in tsec.c to fsl_phy.c to make it reuseable.

Based on the latest WD's U-Boot tree. Tested on P4080DS and MPC8536DS board with SGMII card.

[PATCH 01/14] powerpc/p4080: Add function to report which lane is used for a prtcl [PATCH 02/14] powerpc/fman: add PHY support for dTSEC
[PATCH 03/14] powerpc/fman: add dTSEC controller support
[PATCH 04/14] powerpc/fman: add 10GEC controller and PHY support [PATCH 05/14] powerpc/qoirq: Add support for FMan ethernet in Independent mode [PATCH 06/14] powerpc/corenet_ds: Add fman support
[PATCH 07/14] tsec: use IO accessories to access the register
[PATCH 08/14] tsec: arrange the code to avoid useless function declaration [PATCH 09/14] tsec: use general ethernet MII register struct(tsec_mii_t) [PATCH 10/14] tsec: refactor the PHY code to make it reuseable
[PATCH 11/14] PHY: add some Vitesse phy support
[PATCH 12/14] PHY: add some Broadcom phy support
[PATCH 13/14] PHY: add some Marvell phy support
[PATCH 14/14] PHY: add some misc phy code support

Thanks,
Mingkai

author
#1 lore raw

PATCH 1/14 powerpc/p4080: Add function to report which lane is used for a prtcl

From: Kumar Gala <[email protected]>

Also rename serdes_get_bank() to serdes_get_bank_by_lane().

---
 arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c |   33 +++++++++++++++++++++++-
 arch/powerpc/include/asm/fsl_serdes.h         |    4 +++
 2 files changed, 35 insertions(+), 2 deletions(-)
arch/powerpc/cpu/mpc85xx/fsl_corenet_serdes.c +31 -2
index 7fc00d8..c4c595e 100644
@@ -29,6 +29,7 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/fsl_law.h>
+#include <asm/errno.h>
 #include "fsl_corenet_serdes.h"
 
 static u32 serdes_prtcl_map;
@@ -91,7 +92,7 @@ int serdes_get_lane_idx(int lane)
 	return lanes[lane].idx;
 }
 
-int serdes_get_bank(int lane)
+int serdes_get_bank_by_lane(int lane)
 {
 	return lanes[lane].bank;
 }
@@ -263,6 +264,34 @@ static void p4080_erratum_serdes8(serdes_corenet_t *regs, ccsr_gur_t *gur,
 }
 #endif
 
+static int __serdes_get_first_lane(uint32_t prtcl, enum srds_prtcl device)
+{
+	int i;
+
+	for (i = 0; i < SRDS_MAX_LANES; i++) {
+		if (serdes_get_prtcl(prtcl, i) == device)
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+int serdes_get_first_lane(enum srds_prtcl device)
+{
+	u32 prtcl;
+	const ccsr_gur_t *gur;
+
+	gur = (typeof(gur))CONFIG_SYS_MPC85xx_GUTS_ADDR;
+
+	/* Is serdes enabled@all? */
+	if (unlikely((in_be32(&gur->rcwsr[5]) & 0x2000) == 0))
+		return -ENODEV;
+
+	prtcl = (in_be32(&gur->rcwsr[4]) & FSL_CORENET_RCWSR4_SRDS_PRTCL) >> 26;
+
+	return __serdes_get_first_lane(prtcl, device);
+}
+
 void fsl_serdes_init(void)
 {
 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
@@ -318,7 +347,7 @@ void fsl_serdes_init(void)
 	for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
 		enum srds_prtcl lane_prtcl = serdes_get_prtcl(cfg, lane);
 		if (serdes_lane_enabled(lane)) {
-			have_bank[serdes_get_bank(lane)] = 1;
+			have_bank[serdes_get_bank_by_lane(lane)] = 1;
 			serdes_prtcl_map |= (1 << lane_prtcl);
 		}
 	}
arch/powerpc/include/asm/fsl_serdes.h +4 -0
index 85518eb..9d9f2e4 100644
@@ -53,4 +53,8 @@ enum srds_prtcl {
 int is_serdes_configured(enum srds_prtcl device);
 void fsl_serdes_init(void);
 
+#ifdef CONFIG_FSL_CORENET
+int serdes_get_first_lane(enum srds_prtcl device);
+#endif
+
 #endif /* __FSL_SERDES_H */
Signature · 1 line
1.6.4
author
#2 lore raw

PATCH 2/14 powerpc/fman: add PHY support for dTSEC

From: Kumar Gala <[email protected]>

Add VSC8244 and VSC8234 phy support, this will be reused by etsec code.

---
 arch/powerpc/include/asm/fsl_enet.h |   10 +
 drivers/net/fsl_phy.c               |  353 +++++++++++++++++++++++++++++++++++
 drivers/net/fsl_phy.h               |  176 +++++++++++++++++
 3 files changed, 539 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/fsl_phy.c
 create mode 100644 drivers/net/fsl_phy.h
arch/powerpc/include/asm/fsl_enet.h +10 -0
index 4fb2857..9475249 100644
@@ -28,6 +28,16 @@ enum fsl_phy_enet_if {
 	FSL_ETH_IF_NONE,
 };
 
+typedef struct tsec_mii_mng {
+	u32 miimcfg;		/* MII management configuration reg */
+	u32 miimcom;		/* MII management command reg */
+	u32 miimadd;		/* MII management address reg */
+	u32 miimcon;		/* MII management control reg */
+	u32 miimstat;		/* MII management status reg  */
+	u32 miimind;		/* MII management indication reg */
+	u32 ifstat;		/* Interface Status Register */
+} __attribute__ ((packed))tsec_mii_t;
+
 int fdt_fixup_phy_connection(void *blob, int offset, enum fsl_phy_enet_if phyc);
 
 #endif /* __ASM_PPC_FSL_ENET_H */
drivers/net/fsl_phy.c new file +353 -0

353 lines not on this page · raw message

drivers/net/fsl_phy.h new file +176 -0

176 lines not on this page · raw message

Signature · 1 line
1.6.4
author
#3 lore raw

PATCH 3/14 powerpc/fman: add dTSEC controller support

From: Kumar Gala <[email protected]>

---
 arch/powerpc/include/asm/fsl_enet.h |   12 ++
 drivers/net/fm/dtsec.c              |  168 +++++++++++++++++++++++
 drivers/net/fm/dtsec.h              |  251 +++++++++++++++++++++++++++++++++++
 3 files changed, 431 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/fm/dtsec.c
 create mode 100644 drivers/net/fm/dtsec.h
arch/powerpc/include/asm/fsl_enet.h +12 -0
index 9475249..f94482d 100644
@@ -38,6 +38,18 @@ typedef struct tsec_mii_mng {
 	u32 ifstat;		/* Interface Status Register */
 } __attribute__ ((packed))tsec_mii_t;
 
+struct fsl_enet_mac {
+	void *base; /* MAC controller registers base address */
+	void *phyregs;
+	int max_rx_len;
+	void (*init_mac)(struct fsl_enet_mac *mac);
+	void (*enable_mac)(struct fsl_enet_mac *mac);
+	void (*disable_mac)(struct fsl_enet_mac *mac);
+	void (*set_mac_addr)(struct fsl_enet_mac *mac, u8 *mac_addr);
+	void (*set_if_mode)(struct fsl_enet_mac *mac, enum fsl_phy_enet_if type,
+				int speed);
+};
+
 int fdt_fixup_phy_connection(void *blob, int offset, enum fsl_phy_enet_if phyc);
 
 #endif /* __ASM_PPC_FSL_ENET_H */
drivers/net/fm/dtsec.c new file +168 -0

168 lines not on this page · raw message

drivers/net/fm/dtsec.h new file +251 -0

251 lines not on this page · raw message

Signature · 1 line
1.6.4
author
#4 lore raw

PATCH 4/14 powerpc/fman: add 10GEC controller and PHY support

From: Kumar Gala <[email protected]>

---
 drivers/net/fm/tgec.c     |  104 ++++++++++++++++++++
 drivers/net/fm/tgec.h     |  230 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/fm/tgec_phy.c |  155 ++++++++++++++++++++++++++++++
 3 files changed, 489 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/fm/tgec.c
 create mode 100644 drivers/net/fm/tgec.h
 create mode 100644 drivers/net/fm/tgec_phy.c
drivers/net/fm/tgec.c new file +104 -0
new file mode 100644
index 0000000..02a2476
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *	Dave Liu <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include <asm/fsl_enet.h>
+
+#include "tgec.h"
+
+static void tgec_init_mac(struct fsl_enet_mac *mac)
+{
+	struct tgec *regs = mac->base;
+
+	/* mask all interrupt */
+	out_be32(&regs->imask, IMASK_MASK_ALL);
+
+	/* clear all events */
+	out_be32(&regs->ievent, IEVENT_CLEAR_ALL);
+
+	/* set the max receive length */
+	out_be32(&regs->maxfrm, mac->max_rx_len);
+
+	/* 1588 disable, insert second mac disable
+	 * payload length check disable, normal operation,
+	 * any rx error frame is discarded, clear counters,
+	 * pause frame ignore, no promiscuous, LAN mode
+	 * Rx CRC no strip, Tx CRC append, Rx disable and Tx disable
+	 */
+	out_be32(&regs->command_config, TGEC_CMD_CFG_INIT);
+	udelay(1000);
+	out_be32(&regs->command_config, TGEC_CMD_CFG_FINAL);
+
+	/* multicast frame reception for the hash entry disable */
+	out_be32(&regs->hashtable_ctrl, 0);
+}
+
+static void tgec_enable_mac(struct fsl_enet_mac *mac)
+{
+	struct tgec *regs = mac->base;
+
+	setbits_be32(&regs->command_config, TGEC_CMD_CFG_RXTX_EN);
+}
+
+static void tgec_disable_mac(struct fsl_enet_mac *mac)
+{
+	struct tgec *regs = mac->base;
+
+	clrbits_be32(&regs->command_config, TGEC_CMD_CFG_RXTX_EN);
+}
+
+static void tgec_set_mac_addr(struct fsl_enet_mac *mac, u8 *mac_addr)
+{
+	struct tgec *regs = mac->base;
+	u32 mac_addr0, mac_addr1;
+
+	/* if a station address of 0x12345678ABCD, perform a write to
+	   MAC_ADDR0 of 0x78563412,
+	   MAC_ADDR1 of 0x0000CDAB */
+
+	mac_addr0 = (mac_addr[3] << 24) | (mac_addr[2] << 16) | \
+			(mac_addr[1] << 8)  | (mac_addr[0]);
+	out_be32(&regs->mac_addr_0, mac_addr0);
+
+	mac_addr1 = ((mac_addr[5] << 8) | mac_addr[4]) & 0x0000ffff;
+	out_be32(&regs->mac_addr_1, mac_addr1);
+}
+
+static void tgec_set_interface_mode(struct fsl_enet_mac *mac,
+					enum fsl_phy_enet_if type, int speed)
+{
+	/* nothing right now */
+	return;
+}
+
+void init_tgec(struct fsl_enet_mac *mac, void *base,
+		void *phyregs, int max_rx_len)
+{
+	mac->base = base;
+	mac->phyregs = phyregs;
+	mac->max_rx_len = max_rx_len;
+	mac->init_mac = tgec_init_mac;
+	mac->enable_mac = tgec_enable_mac;
+	mac->disable_mac = tgec_disable_mac;
+	mac->set_mac_addr = tgec_set_mac_addr;
+	mac->set_if_mode = tgec_set_interface_mode;
+}
drivers/net/fm/tgec.h new file +230 -0

230 lines not on this page · raw message

drivers/net/fm/tgec_phy.c new file +155 -0

155 lines not on this page · raw message

Signature · 1 line
1.6.4
author
#5 lore raw

PATCH 5/14 powerpc/qoirq: Add support for FMan ethernet in Independent mode

From: Dave Liu <[email protected]>

---
 Makefile                            |    1 +
 arch/powerpc/cpu/mpc85xx/cpu_init.c |    5 +
 arch/powerpc/cpu/mpc8xxx/cpu.c      |    4 +
 drivers/net/Makefile                |    1 +
 drivers/net/fm/Makefile             |   45 ++
 drivers/net/fm/fm.c                 |  519 +++++++++++++++
 drivers/net/fm/fm.h                 |  312 +++++++++
 drivers/net/fm/fm_eth.c             | 1234 +++++++++++++++++++++++++++++++++++
 include/fm_eth.h                    |  348 ++++++++++
 9 files changed, 2469 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/fm/Makefile
 create mode 100644 drivers/net/fm/fm.c
 create mode 100644 drivers/net/fm/fm.h
 create mode 100644 drivers/net/fm/fm_eth.c
 create mode 100644 include/fm_eth.h
Makefile +1 -0
index 5f93646..a0532e0 100644
@@ -225,6 +225,7 @@ LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o
 endif
 ifeq ($(CPU),mpc85xx)
 LIBS += drivers/qe/libqe.o
+LIBS += drivers/net/fm/libfm.a
 LIBS += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o
 LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o
 endif
arch/powerpc/cpu/mpc85xx/cpu_init.c +5 -0
index 8ece970..0ceec19 100644
@@ -31,6 +31,7 @@
 #include <asm/processor.h>
 #include <ioports.h>
 #include <sata.h>
+#include <fm_eth.h>
 #include <asm/io.h>
 #include <asm/cache.h>
 #include <asm/mmu.h>
@@ -419,6 +420,10 @@ int cpu_init_r(void)
 	isync();
 #endif
 
+#ifdef CONFIG_FMAN_ENET
+	fman_enet_init();
+#endif
+
 	return 0;
 }
 
arch/powerpc/cpu/mpc8xxx/cpu.c +4 -0
index 4335fb4..97e4fa4 100644
@@ -27,6 +27,7 @@
 #include <common.h>
 #include <command.h>
 #include <tsec.h>
+#include <fm_eth.h>
 #include <netdev.h>
 #include <asm/cache.h>
 #include <asm/io.h>
@@ -160,5 +161,8 @@ int cpu_eth_init(bd_t *bis)
 	tsec_standard_init(bis);
 #endif
 
+#ifdef CONFIG_FMAN_ENET
+	fm_standard_init(bis);
+#endif
 	return 0;
 }
drivers/net/Makefile +1 -0
index fd9d0b4..3810665 100644
@@ -80,6 +80,7 @@ COBJS-$(CONFIG_TIGON3) += bcm570x_autoneg.o
 COBJS-$(CONFIG_TIGON3) += 5701rls.o
 COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
 COBJS-$(CONFIG_TSEC_ENET) += tsec.o
+COBJS-$(CONFIG_FMAN_ENET) += fsl_phy.o
 COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o
 COBJS-$(CONFIG_ULI526X) += uli526x.o
 COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o
drivers/net/fm/Makefile new file +45 -0

45 lines not on this page · raw message

drivers/net/fm/fm.c new file +519 -0

519 lines not on this page · raw message

drivers/net/fm/fm.h new file +312 -0

312 lines not on this page · raw message

drivers/net/fm/fm_eth.c new file +1234 -0

1,234 lines not on this page · raw message

include/fm_eth.h new file +348 -0

348 lines not on this page · raw message

Signature · 1 line
1.6.4
author
#6 lore raw

PATCH 6/14 powerpc/corenet_ds: Add fman support

From: Kumar Gala <[email protected]>

---
 board/freescale/corenet_ds/Makefile     |    1 +
 board/freescale/corenet_ds/corenet_ds.c |   11 +-
 board/freescale/corenet_ds/eth_p4080.c  |  352 +++++++++++++++++++++++++++++++
 3 files changed, 359 insertions(+), 5 deletions(-)
 create mode 100644 board/freescale/corenet_ds/eth_p4080.c
board/freescale/corenet_ds/Makefile +1 -0
index 1047d78..a6872ac 100644
@@ -28,6 +28,7 @@ LIB	= $(obj)lib$(BOARD).o
 
 COBJS-y	+= $(BOARD).o
 COBJS-y	+= ddr.o
+COBJS-$(CONFIG_P4080DS)	+= eth_p4080.o
 COBJS-$(CONFIG_P4080DS)	+= p4080ds_ddr.o
 COBJS-$(CONFIG_PCI)	+= pci.o
 COBJS-y	+= law.o
board/freescale/corenet_ds/corenet_ds.c +6 -5
index 232dc72..2eadf99 100644
@@ -32,10 +32,12 @@
 #include <asm/fsl_serdes.h>
 #include <asm/fsl_portals.h>
 #include <asm/fsl_liodn.h>
+#include <fm_eth.h>
 
 extern void pci_of_setup(void *blob, bd_t *bd);
 
 #include "../common/ngpixis.h"
+#include "../../../drivers/net/fm/dtsec.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -193,6 +195,8 @@ void board_lmb_reserve(struct lmb *lmb)
 }
 #endif
 
+extern void fdt_fixup_p4080ds_enet(void * blob);
+
 void ft_board_setup(void *blob, bd_t *bd)
 {
 	phys_addr_t base;
@@ -210,9 +214,6 @@ void ft_board_setup(void *blob, bd_t *bd)
 #endif
 
 	fdt_fixup_liodn(blob);
-}
-
-int board_eth_init(bd_t *bis)
-{
-	return pci_eth_init(bis);
+	fdt_fixup_fman_ethernet(blob);
+	fdt_fixup_p4080ds_enet(blob);
 }
board/freescale/corenet_ds/eth_p4080.c new file +352 -0

352 lines not on this page · raw message

Signature · 1 line
1.6.4
author
#7 lore raw

PATCH 7/14 tsec: use IO accessories to access the register

---
 drivers/net/tsec.c |  232 ++++++++++++++++++++++++++-------------------------
 include/tsec.h     |    6 +-
 2 files changed, 121 insertions(+), 117 deletions(-)
drivers/net/tsec.c +118 -114
index 9c8fe62..910cf9e 100644
@@ -50,7 +50,7 @@ static int tsec_recv(struct eth_device *dev);
 static int tsec_init(struct eth_device *dev, bd_t * bd);
 static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info);
 static void tsec_halt(struct eth_device *dev);
-static void init_registers(volatile tsec_t * regs);
+static void init_registers(tsec_t * regs);
 static void startup_tsec(struct eth_device *dev);
 static int init_phy(struct eth_device *dev);
 void write_phy_reg(struct tsec_private *priv, uint regnum, uint value);
@@ -166,9 +166,9 @@ static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info)
 	eth_register(dev);
 
 	/* Reset the MAC */
-	priv->regs->maccfg1 |= MACCFG1_SOFT_RESET;
+	setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
 	udelay(2);  /* Soft Reset must be asserted for 3 TX clocks */
-	priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
+	clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
 
 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
 	&& !defined(BITBANGMII)
@@ -190,16 +190,16 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
 	char tmpbuf[MAC_ADDR_LEN];
 	int i;
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	volatile tsec_t *regs = priv->regs;
+	tsec_t *regs = priv->regs;
 
 	/* Make sure the controller is stopped */
 	tsec_halt(dev);
 
 	/* Init MACCFG2.  Defaults to GMII */
-	regs->maccfg2 = MACCFG2_INIT_SETTINGS;
+	out_be32(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
 
 	/* Init ECNTRL */
-	regs->ecntrl = ECNTRL_INIT_SETTINGS;
+	out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
 
 	/* Copy the station address into the address registers.
 	 * Backwards, because little endian MACS are dumb */
@@ -209,11 +209,11 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
 	tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
 		  tmpbuf[3];
 
-	regs->macstnaddr1 = tempval;
+	out_be32(&regs->macstnaddr1, tempval);
 
 	tempval = *((uint *) (tmpbuf + 4));
 
-	regs->macstnaddr2 = tempval;
+	out_be32(&regs->macstnaddr2, tempval);
 
 	/* reset the indices to zero */
 	rxIdx = 0;
@@ -230,17 +230,17 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
 }
 
 /* Writes the given phy's reg with value, using the specified MDIO regs */
-static void tsec_local_mdio_write(volatile tsec_mdio_t *phyregs, uint addr,
+static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr,
 		uint reg, uint value)
 {
 	int timeout = 1000000;
 
-	phyregs->miimadd = (addr << 8) | reg;
-	phyregs->miimcon = value;
+	out_be32(&phyregs->miimadd, (addr << 8) | reg);
+	out_be32(&phyregs->miimcon, value);
 	asm("sync");
 
 	timeout = 1000000;
-	while ((phyregs->miimind & MIIMIND_BUSY) && timeout--) ;
+	while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--) ;
 }
 
 
@@ -254,28 +254,27 @@ static void tsec_local_mdio_write(volatile tsec_mdio_t *phyregs, uint addr,
  * notvalid bit cleared), and the bus to cease activity (miimind
  * busy bit cleared), and then returns the value
  */
-static uint tsec_local_mdio_read(volatile tsec_mdio_t *phyregs,
-				uint phyid, uint regnum)
+static uint tsec_local_mdio_read(tsec_mdio_t *phyregs, uint phyid, uint regnum)
 {
 	uint value;
 
 	/* Put the address of the phy, and the register
 	 * number into MIIMADD */
-	phyregs->miimadd = (phyid << 8) | regnum;
+	out_be32(&phyregs->miimadd, (phyid << 8) | regnum);
 
 	/* Clear the command register, and wait */
-	phyregs->miimcom = 0;
+	out_be32(&phyregs->miimcom, 0);
 	asm("sync");
 
 	/* Initiate a read command, and wait */
-	phyregs->miimcom = MIIM_READ_COMMAND;
+	out_be32(&phyregs->miimcom, MIIM_READ_COMMAND);
 	asm("sync");
 
 	/* Wait for the the indication that the read is done */
-	while ((phyregs->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
+	while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;
 
 	/* Grab the value read from the PHY */
-	value = phyregs->miimstat;
+	value = in_be32(&phyregs->miimstat);
 
 	return value;
 }
@@ -321,18 +320,18 @@ static int init_phy(struct eth_device *dev)
 {
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
 	struct phy_info *curphy;
-	volatile tsec_t *regs = priv->regs;
+	tsec_t *regs = priv->regs;
 
 	/* Assign a Physical address to the TBI */
-	regs->tbipa = CONFIG_SYS_TBIPA_VALUE;
+	out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
 	asm("sync");
 
 	/* Reset MII (due to new addresses) */
-	priv->phyregs->miimcfg = MIIMCFG_RESET;
+	out_be32(&priv->phyregs->miimcfg, MIIMCFG_RESET);
 	asm("sync");
-	priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE;
+	out_be32(&priv->phyregs->miimcfg, MIIMCFG_INIT_VALUE);
 	asm("sync");
-	while (priv->phyregs->miimind & MIIMIND_BUSY) ;
+	while (in_be32(&priv->phyregs->miimind) & MIIMIND_BUSY) ;
 
 	/* Get the cmd structure corresponding to the attached
 	 * PHY */
@@ -345,7 +344,7 @@ static int init_phy(struct eth_device *dev)
 		return 0;
 	}
 
-	if (regs->ecntrl & ECNTRL_SGMII_MODE)
+	if (in_be32(&regs->ecntrl) & ECNTRL_SGMII_MODE)
 		tsec_configure_serdes(priv);
 
 	priv->phyinfo = curphy;
@@ -838,16 +837,16 @@ static uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv)
 static uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv)
 {
 	uint phyid;
-	volatile tsec_mdio_t *regbase = priv->phyregs;
+	tsec_mdio_t *regbase = priv->phyregs;
 	int timeout = 1000000;
 
 	for (phyid = 0; phyid < 4; phyid++) {
-		regbase->miimadd = (phyid << 8) | mii_reg;
-		regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT;
+		out_be32(&regbase->miimadd, (phyid << 8) | mii_reg);
+		out_be32(&regbase->miimcon, MIIM_CIS8204_SLEDCON_INIT);
 		asm("sync");
 
 		timeout = 1000000;
-		while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;
+		while ((in_be32(&regbase->miimind) & MIIMIND_BUSY) && timeout--) ;
 	}
 
 	return MIIM_CIS8204_SLEDCON_INIT;
@@ -874,45 +873,45 @@ static uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv)
  * those we don't care about (unless zero is bad, in which case,
  * choose a more appropriate value)
  */
-static void init_registers(volatile tsec_t * regs)
+static void init_registers(tsec_t * regs)
 {
 	/* Clear IEVENT */
-	regs->ievent = IEVENT_INIT_CLEAR;
-
-	regs->imask = IMASK_INIT_CLEAR;
-
-	regs->hash.iaddr0 = 0;
-	regs->hash.iaddr1 = 0;
-	regs->hash.iaddr2 = 0;
-	regs->hash.iaddr3 = 0;
-	regs->hash.iaddr4 = 0;
-	regs->hash.iaddr5 = 0;
-	regs->hash.iaddr6 = 0;
-	regs->hash.iaddr7 = 0;
-
-	regs->hash.gaddr0 = 0;
-	regs->hash.gaddr1 = 0;
-	regs->hash.gaddr2 = 0;
-	regs->hash.gaddr3 = 0;
-	regs->hash.gaddr4 = 0;
-	regs->hash.gaddr5 = 0;
-	regs->hash.gaddr6 = 0;
-	regs->hash.gaddr7 = 0;
-
-	regs->rctrl = 0x00000000;
+	out_be32(&regs->ievent, IEVENT_INIT_CLEAR);
+
+	out_be32(&regs->imask, IMASK_INIT_CLEAR);
+
+	out_be32(&regs->hash.iaddr0, 0);
+	out_be32(&regs->hash.iaddr1, 0);
+	out_be32(&regs->hash.iaddr2, 0);
+	out_be32(&regs->hash.iaddr3, 0);
+	out_be32(&regs->hash.iaddr4, 0);
+	out_be32(&regs->hash.iaddr5, 0);
+	out_be32(&regs->hash.iaddr6, 0);
+	out_be32(&regs->hash.iaddr7, 0);
+
+	out_be32(&regs->hash.gaddr0, 0);
+	out_be32(&regs->hash.gaddr1, 0);
+	out_be32(&regs->hash.gaddr2, 0);
+	out_be32(&regs->hash.gaddr3, 0);
+	out_be32(&regs->hash.gaddr4, 0);
+	out_be32(&regs->hash.gaddr5, 0);
+	out_be32(&regs->hash.gaddr6, 0);
+	out_be32(&regs->hash.gaddr7, 0);
+
+	out_be32(&regs->rctrl, 0x00000000);
 
 	/* Init RMON mib registers */
 	memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
 
-	regs->rmon.cam1 = 0xffffffff;
-	regs->rmon.cam2 = 0xffffffff;
+	out_be32(&regs->rmon.cam1, 0xffffffff);
+	out_be32(&regs->rmon.cam2, 0xffffffff);
 
-	regs->mrblr = MRBLR_INIT_SETTINGS;
+	out_be32(&regs->mrblr, MRBLR_INIT_SETTINGS);
 
-	regs->minflr = MINFLR_INIT_SETTINGS;
+	out_be32(&regs->minflr, MINFLR_INIT_SETTINGS);
 
-	regs->attr = ATTR_INIT_SETTINGS;
-	regs->attreli = ATTRELI_INIT_SETTINGS;
+	out_be32(&regs->attr, ATTR_INIT_SETTINGS);
+	out_be32(&regs->attreli, ATTRELI_INIT_SETTINGS);
 
 }
 
@@ -922,44 +921,49 @@ static void init_registers(volatile tsec_t * regs)
 static void adjust_link(struct eth_device *dev)
 {
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	volatile tsec_t *regs = priv->regs;
+	tsec_t *regs = priv->regs;
+	u32 ecntrl, maccfg2;
 
-	if (priv->link) {
-		if (priv->duplexity != 0)
-			regs->maccfg2 |= MACCFG2_FULL_DUPLEX;
-		else
-			regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX);
+	if (!priv->link) {
+		printf("%s: No link.\n", dev->name);
+		return;
+	}
 
-		switch (priv->speed) {
-		case 1000:
-			regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF))
-					 | MACCFG2_GMII);
-			break;
-		case 100:
-		case 10:
-			regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF))
-					 | MACCFG2_MII);
+	/* clear all bits relative with interface mode */
+	ecntrl = in_be32(&regs->ecntrl);
+	ecntrl &= ~ECNTRL_R100;
 
-			/* Set R100 bit in all modes although
-			 * it is only used in RGMII mode
-			 */
-			if (priv->speed == 100)
-				regs->ecntrl |= ECNTRL_R100;
-			else
-				regs->ecntrl &= ~(ECNTRL_R100);
-			break;
-		default:
-			printf("%s: Speed was bad\n", dev->name);
-			break;
-		}
+	maccfg2 = in_be32(&regs->maccfg2);
+	maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX);
 
-		printf("Speed: %d, %s duplex%s\n", priv->speed,
-		       (priv->duplexity) ? "full" : "half",
-		       (priv->flags & TSEC_FIBER) ? ", fiber mode" : "");
+	if (priv->duplexity)
+		maccfg2 |= MACCFG2_FULL_DUPLEX;
 
-	} else {
-		printf("%s: No link.\n", dev->name);
+	switch (priv->speed) {
+	case 1000:
+		maccfg2 |= MACCFG2_GMII;
+		break;
+	case 100:
+	case 10:
+		maccfg2 |= MACCFG2_MII;
+
+		/* Set R100 bit in all modes although
+		 * it is only used in RGMII mode
+		 */
+		if (priv->speed == 100)
+			ecntrl |= ECNTRL_R100;
+		break;
+	default:
+		printf("%s: Speed was bad\n", dev->name);
+		break;
 	}
+
+	out_be32(&regs->ecntrl, ecntrl);
+	out_be32(&regs->maccfg2, maccfg2);
+
+	printf("Speed: %d, %s duplex%s\n", priv->speed,
+			(priv->duplexity) ? "full" : "half",
+			(priv->flags & TSEC_FIBER) ? ", fiber mode" : "");
 }
 
 /* Set up the buffers and their descriptors, and bring up the
@@ -969,11 +973,11 @@ static void startup_tsec(struct eth_device *dev)
 {
 	int i;
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	volatile tsec_t *regs = priv->regs;
+	tsec_t *regs = priv->regs;
 
 	/* Point to the buffer descriptors */
-	regs->tbase = (unsigned int)(&rtx.txbd[txIdx]);
-	regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
+	out_be32(&regs->tbase, (unsigned int)(&rtx.txbd[txIdx]));
+	out_be32(&regs->rbase, (unsigned int)(&rtx.rxbd[rxIdx]));
 
 	/* Initialize the Rx Buffer descriptors */
 	for (i = 0; i < PKTBUFSRX; i++) {
@@ -998,13 +1002,13 @@ static void startup_tsec(struct eth_device *dev)
 	adjust_link(dev);
 
 	/* Enable Transmit and Receive */
-	regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+	setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
 
 	/* Tell the DMA it is clear to go */
-	regs->dmactrl |= DMACTRL_INIT_SETTINGS;
-	regs->tstat = TSTAT_CLEAR_THALT;
-	regs->rstat = RSTAT_CLEAR_RHALT;
-	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
+	setbits_be32(&regs->dmactrl, DMACTRL_INIT_SETTINGS);
+	out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
+	out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+	clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
 }
 
 /* This returns the status bits of the device.	The return value
@@ -1017,7 +1021,7 @@ static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
 	int i;
 	int result = 0;
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	volatile tsec_t *regs = priv->regs;
+	tsec_t *regs = priv->regs;
 
 	/* Find an empty buffer descriptor */
 	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
@@ -1033,7 +1037,7 @@ static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
 	    (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
 
 	/* Tell the DMA to go */
-	regs->tstat = TSTAT_CLEAR_THALT;
+	out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
 
 	/* Wait for buffer to be transmitted */
 	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
@@ -1053,7 +1057,7 @@ static int tsec_recv(struct eth_device *dev)
 {
 	int length;
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	volatile tsec_t *regs = priv->regs;
+	tsec_t *regs = priv->regs;
 
 	while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
 
@@ -1076,9 +1080,9 @@ static int tsec_recv(struct eth_device *dev)
 		rxIdx = (rxIdx + 1) % PKTBUFSRX;
 	}
 
-	if (regs->ievent & IEVENT_BSY) {
-		regs->ievent = IEVENT_BSY;
-		regs->rstat = RSTAT_CLEAR_RHALT;
+	if (in_be32(&regs->ievent) & IEVENT_BSY) {
+		out_be32(&regs->ievent, IEVENT_BSY);
+		out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
 	}
 
 	return -1;
@@ -1089,15 +1093,15 @@ static int tsec_recv(struct eth_device *dev)
 static void tsec_halt(struct eth_device *dev)
 {
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	volatile tsec_t *regs = priv->regs;
+	tsec_t *regs = priv->regs;
 
-	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);
-	regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS);
+	clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+	setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
 
-	while ((regs->ievent & (IEVENT_GRSC | IEVENT_GTSC))
+	while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
 		!= (IEVENT_GRSC | IEVENT_GTSC)) ;
 
-	regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN);
+	clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
 
 	/* Shut down the PHY, as needed */
 	if(priv->phyinfo)
@@ -1881,13 +1885,13 @@ static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
 {
 	int i;
 	uint result;
-	volatile tsec_mdio_t *phyregs = priv->phyregs;
+	tsec_mdio_t *phyregs = priv->phyregs;
 
-	phyregs->miimcfg = MIIMCFG_RESET;
+	out_be32(&phyregs->miimcfg, MIIMCFG_RESET);
 
-	phyregs->miimcfg = MIIMCFG_INIT_VALUE;
+	out_be32(&phyregs->miimcfg, MIIMCFG_INIT_VALUE);
 
-	while (phyregs->miimind & MIIMIND_BUSY) ;
+	while (in_be32(&phyregs->miimind) & MIIMIND_BUSY) ;
 
 	for (i = 0; cmd->mii_reg != miim_end; i++) {
 		if (cmd->mii_data == miim_read) {
include/tsec.h +3 -3
index d56ec2c..6971b47 100644
@@ -587,9 +587,9 @@ typedef struct tsec
 #define TSEC_FIBER	(1 << 3)	/* PHY uses fiber, eg 1000 Base-X */
 
 struct tsec_private {
-	volatile tsec_t *regs;
-	volatile tsec_mdio_t *phyregs;
-	volatile tsec_mdio_t *phyregs_sgmii;
+	tsec_t *regs;
+	tsec_mdio_t *phyregs;
+	tsec_mdio_t *phyregs_sgmii;
 	struct phy_info *phyinfo;
 	uint phyaddr;
 	u32 flags;
Signature · 1 line
1.6.4
author
#8 lore raw

PATCH 8/14 tsec: arrange the code to avoid useless function declaration

---
 drivers/net/tsec.c |  857 +++++++++++++++++++++++++---------------------------
 1 files changed, 416 insertions(+), 441 deletions(-)
drivers/net/tsec.c +416 -441
index 910cf9e..40f1c76 100644
@@ -44,31 +44,6 @@ static RTXBD rtx __attribute__ ((aligned(8)));
 #error "rtx must be 64-bit aligned"
 #endif
 
-static int tsec_send(struct eth_device *dev,
-		     volatile void *packet, int length);
-static int tsec_recv(struct eth_device *dev);
-static int tsec_init(struct eth_device *dev, bd_t * bd);
-static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info);
-static void tsec_halt(struct eth_device *dev);
-static void init_registers(tsec_t * regs);
-static void startup_tsec(struct eth_device *dev);
-static int init_phy(struct eth_device *dev);
-void write_phy_reg(struct tsec_private *priv, uint regnum, uint value);
-uint read_phy_reg(struct tsec_private *priv, uint regnum);
-static struct phy_info *get_phy_info(struct eth_device *dev);
-static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd);
-static void adjust_link(struct eth_device *dev);
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
-	&& !defined(BITBANGMII)
-static int tsec_miiphy_write(const char *devname, unsigned char addr,
-			     unsigned char reg, unsigned short value);
-static int tsec_miiphy_read(const char *devname, unsigned char addr,
-			    unsigned char reg, unsigned short *value);
-#endif
-#ifdef CONFIG_MCAST_TFTP
-static int tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set);
-#endif
-
 /* Default initializations for TSEC controllers. */
 
 static struct tsec_info_struct tsec_info[] = {
@@ -95,140 +70,6 @@ static struct tsec_info_struct tsec_info[] = {
 #endif
 };
 
-/*
- * Initialize all the TSEC devices
- *
- * Returns the number of TSEC devices that were initialized
- */
-int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
-{
-	int i;
-	int ret, count = 0;
-
-	for (i = 0; i < num; i++) {
-		ret = tsec_initialize(bis, &tsecs[i]);
-		if (ret > 0)
-			count += ret;
-	}
-
-	return count;
-}
-
-int tsec_standard_init(bd_t *bis)
-{
-	return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
-}
-
-/* Initialize device structure. Returns success if PHY
- * initialization succeeded (i.e. if it recognizes the PHY)
- */
-static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info)
-{
-	struct eth_device *dev;
-	int i;
-	struct tsec_private *priv;
-
-	dev = (struct eth_device *)malloc(sizeof *dev);
-
-	if (NULL == dev)
-		return 0;
-
-	memset(dev, 0, sizeof *dev);
-
-	priv = (struct tsec_private *)malloc(sizeof(*priv));
-
-	if (NULL == priv)
-		return 0;
-
-	privlist[num_tsecs++] = priv;
-	priv->regs = tsec_info->regs;
-	priv->phyregs = tsec_info->miiregs;
-	priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
-
-	priv->phyaddr = tsec_info->phyaddr;
-	priv->flags = tsec_info->flags;
-
-	sprintf(dev->name, tsec_info->devname);
-	dev->iobase = 0;
-	dev->priv = priv;
-	dev->init = tsec_init;
-	dev->halt = tsec_halt;
-	dev->send = tsec_send;
-	dev->recv = tsec_recv;
-#ifdef CONFIG_MCAST_TFTP
-	dev->mcast = tsec_mcast_addr;
-#endif
-
-	/* Tell u-boot to get the addr from the env */
-	for (i = 0; i < 6; i++)
-		dev->enetaddr[i] = 0;
-
-	eth_register(dev);
-
-	/* Reset the MAC */
-	setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
-	udelay(2);  /* Soft Reset must be asserted for 3 TX clocks */
-	clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
-
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
-	&& !defined(BITBANGMII)
-	miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
-#endif
-
-	/* Try to initialize PHY here, and return */
-	return init_phy(dev);
-}
-
-/* Initializes data structures and registers for the controller,
- * and brings the interface up.	 Returns the link status, meaning
- * that it returns success if the link is up, failure otherwise.
- * This allows u-boot to find the first active controller.
- */
-static int tsec_init(struct eth_device *dev, bd_t * bd)
-{
-	uint tempval;
-	char tmpbuf[MAC_ADDR_LEN];
-	int i;
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	tsec_t *regs = priv->regs;
-
-	/* Make sure the controller is stopped */
-	tsec_halt(dev);
-
-	/* Init MACCFG2.  Defaults to GMII */
-	out_be32(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
-
-	/* Init ECNTRL */
-	out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
-
-	/* Copy the station address into the address registers.
-	 * Backwards, because little endian MACS are dumb */
-	for (i = 0; i < MAC_ADDR_LEN; i++) {
-		tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
-	}
-	tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
-		  tmpbuf[3];
-
-	out_be32(&regs->macstnaddr1, tempval);
-
-	tempval = *((uint *) (tmpbuf + 4));
-
-	out_be32(&regs->macstnaddr2, tempval);
-
-	/* reset the indices to zero */
-	rxIdx = 0;
-	txIdx = 0;
-
-	/* Clear out (for the most part) the other registers */
-	init_registers(regs);
-
-	/* Ready the device for tx/rx */
-	startup_tsec(dev);
-
-	/* If there's no link, fail */
-	return (priv->link ? 0 : -1);
-}
-
 /* Writes the given phy's reg with value, using the specified MDIO regs */
 static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr,
 		uint reg, uint value)
@@ -243,7 +84,6 @@ static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr,
 	while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--) ;
 }
 
-
 /* Provide the default behavior of writing the PHY of this ethernet device */
 #define write_phy_reg(priv, regnum, value) \
 	tsec_local_mdio_write(priv->phyregs,priv->phyaddr,regnum,value)
@@ -312,48 +152,6 @@ static void tsec_configure_serdes(struct tsec_private *priv)
 			CONFIG_TSEC_TBICR_SETTINGS);
 }
 
-/* Discover which PHY is attached to the device, and configure it
- * properly.  If the PHY is not recognized, then return 0
- * (failure).  Otherwise, return 1
- */
-static int init_phy(struct eth_device *dev)
-{
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	struct phy_info *curphy;
-	tsec_t *regs = priv->regs;
-
-	/* Assign a Physical address to the TBI */
-	out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
-	asm("sync");
-
-	/* Reset MII (due to new addresses) */
-	out_be32(&priv->phyregs->miimcfg, MIIMCFG_RESET);
-	asm("sync");
-	out_be32(&priv->phyregs->miimcfg, MIIMCFG_INIT_VALUE);
-	asm("sync");
-	while (in_be32(&priv->phyregs->miimind) & MIIMIND_BUSY) ;
-
-	/* Get the cmd structure corresponding to the attached
-	 * PHY */
-	curphy = get_phy_info(dev);
-
-	if (curphy == NULL) {
-		priv->phyinfo = NULL;
-		printf("%s: No PHY found\n", dev->name);
-
-		return 0;
-	}
-
-	if (in_be32(&regs->ecntrl) & ECNTRL_SGMII_MODE)
-		tsec_configure_serdes(priv);
-
-	priv->phyinfo = curphy;
-
-	phy_run_commands(priv, priv->phyinfo->config);
-
-	return 1;
-}
-
 /*
  * Returns which value to write to the control register.
  * For 10/100, the value is slightly different
@@ -869,245 +667,6 @@ static uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv)
 	return mii_data;
 }
 
-/* Initialized required registers to appropriate values, zeroing
- * those we don't care about (unless zero is bad, in which case,
- * choose a more appropriate value)
- */
-static void init_registers(tsec_t * regs)
-{
-	/* Clear IEVENT */
-	out_be32(&regs->ievent, IEVENT_INIT_CLEAR);
-
-	out_be32(&regs->imask, IMASK_INIT_CLEAR);
-
-	out_be32(&regs->hash.iaddr0, 0);
-	out_be32(&regs->hash.iaddr1, 0);
-	out_be32(&regs->hash.iaddr2, 0);
-	out_be32(&regs->hash.iaddr3, 0);
-	out_be32(&regs->hash.iaddr4, 0);
-	out_be32(&regs->hash.iaddr5, 0);
-	out_be32(&regs->hash.iaddr6, 0);
-	out_be32(&regs->hash.iaddr7, 0);
-
-	out_be32(&regs->hash.gaddr0, 0);
-	out_be32(&regs->hash.gaddr1, 0);
-	out_be32(&regs->hash.gaddr2, 0);
-	out_be32(&regs->hash.gaddr3, 0);
-	out_be32(&regs->hash.gaddr4, 0);
-	out_be32(&regs->hash.gaddr5, 0);
-	out_be32(&regs->hash.gaddr6, 0);
-	out_be32(&regs->hash.gaddr7, 0);
-
-	out_be32(&regs->rctrl, 0x00000000);
-
-	/* Init RMON mib registers */
-	memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
-
-	out_be32(&regs->rmon.cam1, 0xffffffff);
-	out_be32(&regs->rmon.cam2, 0xffffffff);
-
-	out_be32(&regs->mrblr, MRBLR_INIT_SETTINGS);
-
-	out_be32(&regs->minflr, MINFLR_INIT_SETTINGS);
-
-	out_be32(&regs->attr, ATTR_INIT_SETTINGS);
-	out_be32(&regs->attreli, ATTRELI_INIT_SETTINGS);
-
-}
-
-/* Configure maccfg2 based on negotiated speed and duplex
- * reported by PHY handling code
- */
-static void adjust_link(struct eth_device *dev)
-{
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	tsec_t *regs = priv->regs;
-	u32 ecntrl, maccfg2;
-
-	if (!priv->link) {
-		printf("%s: No link.\n", dev->name);
-		return;
-	}
-
-	/* clear all bits relative with interface mode */
-	ecntrl = in_be32(&regs->ecntrl);
-	ecntrl &= ~ECNTRL_R100;
-
-	maccfg2 = in_be32(&regs->maccfg2);
-	maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX);
-
-	if (priv->duplexity)
-		maccfg2 |= MACCFG2_FULL_DUPLEX;
-
-	switch (priv->speed) {
-	case 1000:
-		maccfg2 |= MACCFG2_GMII;
-		break;
-	case 100:
-	case 10:
-		maccfg2 |= MACCFG2_MII;
-
-		/* Set R100 bit in all modes although
-		 * it is only used in RGMII mode
-		 */
-		if (priv->speed == 100)
-			ecntrl |= ECNTRL_R100;
-		break;
-	default:
-		printf("%s: Speed was bad\n", dev->name);
-		break;
-	}
-
-	out_be32(&regs->ecntrl, ecntrl);
-	out_be32(&regs->maccfg2, maccfg2);
-
-	printf("Speed: %d, %s duplex%s\n", priv->speed,
-			(priv->duplexity) ? "full" : "half",
-			(priv->flags & TSEC_FIBER) ? ", fiber mode" : "");
-}
-
-/* Set up the buffers and their descriptors, and bring up the
- * interface
- */
-static void startup_tsec(struct eth_device *dev)
-{
-	int i;
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	tsec_t *regs = priv->regs;
-
-	/* Point to the buffer descriptors */
-	out_be32(&regs->tbase, (unsigned int)(&rtx.txbd[txIdx]));
-	out_be32(&regs->rbase, (unsigned int)(&rtx.rxbd[rxIdx]));
-
-	/* Initialize the Rx Buffer descriptors */
-	for (i = 0; i < PKTBUFSRX; i++) {
-		rtx.rxbd[i].status = RXBD_EMPTY;
-		rtx.rxbd[i].length = 0;
-		rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i];
-	}
-	rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP;
-
-	/* Initialize the TX Buffer Descriptors */
-	for (i = 0; i < TX_BUF_CNT; i++) {
-		rtx.txbd[i].status = 0;
-		rtx.txbd[i].length = 0;
-		rtx.txbd[i].bufPtr = 0;
-	}
-	rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
-
-	/* Start up the PHY */
-	if(priv->phyinfo)
-		phy_run_commands(priv, priv->phyinfo->startup);
-
-	adjust_link(dev);
-
-	/* Enable Transmit and Receive */
-	setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
-
-	/* Tell the DMA it is clear to go */
-	setbits_be32(&regs->dmactrl, DMACTRL_INIT_SETTINGS);
-	out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
-	out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
-	clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
-}
-
-/* This returns the status bits of the device.	The return value
- * is never checked, and this is what the 8260 driver did, so we
- * do the same.	 Presumably, this would be zero if there were no
- * errors
- */
-static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
-{
-	int i;
-	int result = 0;
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	tsec_t *regs = priv->regs;
-
-	/* Find an empty buffer descriptor */
-	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
-		if (i >= TOUT_LOOP) {
-			debug("%s: tsec: tx buffers full\n", dev->name);
-			return result;
-		}
-	}
-
-	rtx.txbd[txIdx].bufPtr = (uint) packet;
-	rtx.txbd[txIdx].length = length;
-	rtx.txbd[txIdx].status |=
-	    (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
-
-	/* Tell the DMA to go */
-	out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
-
-	/* Wait for buffer to be transmitted */
-	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
-		if (i >= TOUT_LOOP) {
-			debug("%s: tsec: tx error\n", dev->name);
-			return result;
-		}
-	}
-
-	txIdx = (txIdx + 1) % TX_BUF_CNT;
-	result = rtx.txbd[txIdx].status & TXBD_STATS;
-
-	return result;
-}
-
-static int tsec_recv(struct eth_device *dev)
-{
-	int length;
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	tsec_t *regs = priv->regs;
-
-	while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
-
-		length = rtx.rxbd[rxIdx].length;
-
-		/* Send the packet up if there were no errors */
-		if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
-			NetReceive(NetRxPackets[rxIdx], length - 4);
-		} else {
-			printf("Got error %x\n",
-			       (rtx.rxbd[rxIdx].status & RXBD_STATS));
-		}
-
-		rtx.rxbd[rxIdx].length = 0;
-
-		/* Set the wrap bit if this is the last element in the list */
-		rtx.rxbd[rxIdx].status =
-		    RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
-
-		rxIdx = (rxIdx + 1) % PKTBUFSRX;
-	}
-
-	if (in_be32(&regs->ievent) & IEVENT_BSY) {
-		out_be32(&regs->ievent, IEVENT_BSY);
-		out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
-	}
-
-	return -1;
-
-}
-
-/* Stop the interface */
-static void tsec_halt(struct eth_device *dev)
-{
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	tsec_t *regs = priv->regs;
-
-	clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
-	setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
-
-	while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
-		!= (IEVENT_GRSC | IEVENT_GTSC)) ;
-
-	clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
-
-	/* Shut down the PHY, as needed */
-	if(priv->phyinfo)
-		phy_run_commands(priv, priv->phyinfo->shutdown);
-}
-
 static struct phy_info phy_info_M88E1149S = {
 	0x1410ca,
 	"Marvell 88E1149S",
@@ -2003,3 +1562,419 @@ tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set)
 	return 0;
 }
 #endif /* Multicast TFTP ? */
+
+/* Initialized required registers to appropriate values, zeroing
+ * those we don't care about (unless zero is bad, in which case,
+ * choose a more appropriate value)
+ */
+static void init_registers(tsec_t * regs)
+{
+	/* Clear IEVENT */
+	out_be32(&regs->ievent, IEVENT_INIT_CLEAR);
+
+	out_be32(&regs->imask, IMASK_INIT_CLEAR);
+
+	out_be32(&regs->hash.iaddr0, 0);
+	out_be32(&regs->hash.iaddr1, 0);
+	out_be32(&regs->hash.iaddr2, 0);
+	out_be32(&regs->hash.iaddr3, 0);
+	out_be32(&regs->hash.iaddr4, 0);
+	out_be32(&regs->hash.iaddr5, 0);
+	out_be32(&regs->hash.iaddr6, 0);
+	out_be32(&regs->hash.iaddr7, 0);
+
+	out_be32(&regs->hash.gaddr0, 0);
+	out_be32(&regs->hash.gaddr1, 0);
+	out_be32(&regs->hash.gaddr2, 0);
+	out_be32(&regs->hash.gaddr3, 0);
+	out_be32(&regs->hash.gaddr4, 0);
+	out_be32(&regs->hash.gaddr5, 0);
+	out_be32(&regs->hash.gaddr6, 0);
+	out_be32(&regs->hash.gaddr7, 0);
+
+	out_be32(&regs->rctrl, 0x00000000);
+
+	/* Init RMON mib registers */
+	memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t));
+
+	out_be32(&regs->rmon.cam1, 0xffffffff);
+	out_be32(&regs->rmon.cam2, 0xffffffff);
+
+	out_be32(&regs->mrblr, MRBLR_INIT_SETTINGS);
+
+	out_be32(&regs->minflr, MINFLR_INIT_SETTINGS);
+
+	out_be32(&regs->attr, ATTR_INIT_SETTINGS);
+	out_be32(&regs->attreli, ATTRELI_INIT_SETTINGS);
+
+}
+
+/* Configure maccfg2 based on negotiated speed and duplex
+ * reported by PHY handling code
+ */
+static void adjust_link(struct eth_device *dev)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	tsec_t *regs = priv->regs;
+	u32 ecntrl, maccfg2;
+
+	if (!priv->link) {
+		printf("%s: No link.\n", dev->name);
+		return;
+	}
+
+	/* clear all bits relative with interface mode */
+	ecntrl = in_be32(&regs->ecntrl);
+	ecntrl &= ~ECNTRL_R100;
+
+	maccfg2 = in_be32(&regs->maccfg2);
+	maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX);
+
+	if (priv->duplexity)
+		maccfg2 |= MACCFG2_FULL_DUPLEX;
+
+	switch (priv->speed) {
+	case 1000:
+		maccfg2 |= MACCFG2_GMII;
+		break;
+	case 100:
+	case 10:
+		maccfg2 |= MACCFG2_MII;
+
+		/* Set R100 bit in all modes although
+		 * it is only used in RGMII mode
+		 */
+		if (priv->speed == 100)
+			ecntrl |= ECNTRL_R100;
+		break;
+	default:
+		printf("%s: Speed was bad\n", dev->name);
+		break;
+	}
+
+	out_be32(&regs->ecntrl, ecntrl);
+	out_be32(&regs->maccfg2, maccfg2);
+
+	printf("Speed: %d, %s duplex%s\n", priv->speed,
+			(priv->duplexity) ? "full" : "half",
+			(priv->flags & TSEC_FIBER) ? ", fiber mode" : "");
+}
+
+/* Set up the buffers and their descriptors, and bring up the
+ * interface
+ */
+static void startup_tsec(struct eth_device *dev)
+{
+	int i;
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	tsec_t *regs = priv->regs;
+
+	/* Point to the buffer descriptors */
+	out_be32(&regs->tbase, (unsigned int)(&rtx.txbd[txIdx]));
+	out_be32(&regs->rbase, (unsigned int)(&rtx.rxbd[rxIdx]));
+
+	/* Initialize the Rx Buffer descriptors */
+	for (i = 0; i < PKTBUFSRX; i++) {
+		rtx.rxbd[i].status = RXBD_EMPTY;
+		rtx.rxbd[i].length = 0;
+		rtx.rxbd[i].bufPtr = (uint) NetRxPackets[i];
+	}
+	rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP;
+
+	/* Initialize the TX Buffer Descriptors */
+	for (i = 0; i < TX_BUF_CNT; i++) {
+		rtx.txbd[i].status = 0;
+		rtx.txbd[i].length = 0;
+		rtx.txbd[i].bufPtr = 0;
+	}
+	rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
+
+	/* Start up the PHY */
+	if(priv->phyinfo)
+		phy_run_commands(priv, priv->phyinfo->startup);
+
+	adjust_link(dev);
+
+	/* Enable Transmit and Receive */
+	setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
+
+	/* Tell the DMA it is clear to go */
+	setbits_be32(&regs->dmactrl, DMACTRL_INIT_SETTINGS);
+	out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
+	out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+	clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+}
+
+/* This returns the status bits of the device.	The return value
+ * is never checked, and this is what the 8260 driver did, so we
+ * do the same.	 Presumably, this would be zero if there were no
+ * errors
+ */
+static int tsec_send(struct eth_device *dev, volatile void *packet, int length)
+{
+	int i;
+	int result = 0;
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	tsec_t *regs = priv->regs;
+
+	/* Find an empty buffer descriptor */
+	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
+		if (i >= TOUT_LOOP) {
+			debug("%s: tsec: tx buffers full\n", dev->name);
+			return result;
+		}
+	}
+
+	rtx.txbd[txIdx].bufPtr = (uint) packet;
+	rtx.txbd[txIdx].length = length;
+	rtx.txbd[txIdx].status |=
+	    (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT);
+
+	/* Tell the DMA to go */
+	out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
+
+	/* Wait for buffer to be transmitted */
+	for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) {
+		if (i >= TOUT_LOOP) {
+			debug("%s: tsec: tx error\n", dev->name);
+			return result;
+		}
+	}
+
+	txIdx = (txIdx + 1) % TX_BUF_CNT;
+	result = rtx.txbd[txIdx].status & TXBD_STATS;
+
+	return result;
+}
+
+static int tsec_recv(struct eth_device *dev)
+{
+	int length;
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	tsec_t *regs = priv->regs;
+
+	while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) {
+
+		length = rtx.rxbd[rxIdx].length;
+
+		/* Send the packet up if there were no errors */
+		if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {
+			NetReceive(NetRxPackets[rxIdx], length - 4);
+		} else {
+			printf("Got error %x\n",
+			       (rtx.rxbd[rxIdx].status & RXBD_STATS));
+		}
+
+		rtx.rxbd[rxIdx].length = 0;
+
+		/* Set the wrap bit if this is the last element in the list */
+		rtx.rxbd[rxIdx].status =
+		    RXBD_EMPTY | (((rxIdx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0);
+
+		rxIdx = (rxIdx + 1) % PKTBUFSRX;
+	}
+
+	if (in_be32(&regs->ievent) & IEVENT_BSY) {
+		out_be32(&regs->ievent, IEVENT_BSY);
+		out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+	}
+
+	return -1;
+
+}
+
+/* Stop the interface */
+static void tsec_halt(struct eth_device *dev)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	tsec_t *regs = priv->regs;
+
+	clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+	setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+
+	while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
+		!= (IEVENT_GRSC | IEVENT_GTSC)) ;
+
+	clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
+
+	/* Shut down the PHY, as needed */
+	if(priv->phyinfo)
+		phy_run_commands(priv, priv->phyinfo->shutdown);
+}
+
+/* Initializes data structures and registers for the controller,
+ * and brings the interface up.	 Returns the link status, meaning
+ * that it returns success if the link is up, failure otherwise.
+ * This allows u-boot to find the first active controller.
+ */
+static int tsec_init(struct eth_device *dev, bd_t * bd)
+{
+	uint tempval;
+	char tmpbuf[MAC_ADDR_LEN];
+	int i;
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	tsec_t *regs = priv->regs;
+
+	/* Make sure the controller is stopped */
+	tsec_halt(dev);
+
+	/* Init MACCFG2.  Defaults to GMII */
+	out_be32(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
+
+	/* Init ECNTRL */
+	out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
+
+	/* Copy the station address into the address registers.
+	 * Backwards, because little endian MACS are dumb */
+	for (i = 0; i < MAC_ADDR_LEN; i++) {
+		tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
+	}
+	tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
+		  tmpbuf[3];
+
+	out_be32(&regs->macstnaddr1, tempval);
+
+	tempval = *((uint *) (tmpbuf + 4));
+
+	out_be32(&regs->macstnaddr2, tempval);
+
+	/* reset the indices to zero */
+	rxIdx = 0;
+	txIdx = 0;
+
+	/* Clear out (for the most part) the other registers */
+	init_registers(regs);
+
+	/* Ready the device for tx/rx */
+	startup_tsec(dev);
+
+	/* If there's no link, fail */
+	return (priv->link ? 0 : -1);
+}
+
+/* Discover which PHY is attached to the device, and configure it
+ * properly.  If the PHY is not recognized, then return 0
+ * (failure).  Otherwise, return 1
+ */
+static int init_phy(struct eth_device *dev)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	struct phy_info *curphy;
+	tsec_t *regs = priv->regs;
+
+	/* Assign a Physical address to the TBI */
+	out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
+	asm("sync");
+
+	/* Reset MII (due to new addresses) */
+	out_be32(&priv->phyregs->miimcfg, MIIMCFG_RESET);
+	asm("sync");
+	out_be32(&priv->phyregs->miimcfg, MIIMCFG_INIT_VALUE);
+	asm("sync");
+	while (in_be32(&priv->phyregs->miimind) & MIIMIND_BUSY) ;
+
+	/* Get the cmd structure corresponding to the attached
+	 * PHY */
+	curphy = get_phy_info(dev);
+
+	if (curphy == NULL) {
+		priv->phyinfo = NULL;
+		printf("%s: No PHY found\n", dev->name);
+
+		return 0;
+	}
+
+	if (in_be32(&regs->ecntrl) & ECNTRL_SGMII_MODE)
+		tsec_configure_serdes(priv);
+
+	priv->phyinfo = curphy;
+
+	phy_run_commands(priv, priv->phyinfo->config);
+
+	return 1;
+}
+
+/* Initialize device structure. Returns success if PHY
+ * initialization succeeded (i.e. if it recognizes the PHY)
+ */
+static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info)
+{
+	struct eth_device *dev;
+	int i;
+	struct tsec_private *priv;
+
+	dev = (struct eth_device *)malloc(sizeof *dev);
+
+	if (NULL == dev)
+		return 0;
+
+	memset(dev, 0, sizeof *dev);
+
+	priv = (struct tsec_private *)malloc(sizeof(*priv));
+
+	if (NULL == priv)
+		return 0;
+
+	privlist[num_tsecs++] = priv;
+	priv->regs = tsec_info->regs;
+	priv->phyregs = tsec_info->miiregs;
+	priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
+
+	priv->phyaddr = tsec_info->phyaddr;
+	priv->flags = tsec_info->flags;
+
+	sprintf(dev->name, tsec_info->devname);
+	dev->iobase = 0;
+	dev->priv = priv;
+	dev->init = tsec_init;
+	dev->halt = tsec_halt;
+	dev->send = tsec_send;
+	dev->recv = tsec_recv;
+#ifdef CONFIG_MCAST_TFTP
+	dev->mcast = tsec_mcast_addr;
+#endif
+
+	/* Tell u-boot to get the addr from the env */
+	for (i = 0; i < 6; i++)
+		dev->enetaddr[i] = 0;
+
+	eth_register(dev);
+
+	/* Reset the MAC */
+	setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+	udelay(2);  /* Soft Reset must be asserted for 3 TX clocks */
+	clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
+	&& !defined(BITBANGMII)
+	miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
+#endif
+
+	/* Try to initialize PHY here, and return */
+	return init_phy(dev);
+}
+
+/*
+ * Initialize all the TSEC devices
+ *
+ * Returns the number of TSEC devices that were initialized
+ */
+int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num)
+{
+	int i;
+	int ret, count = 0;
+
+	for (i = 0; i < num; i++) {
+		ret = tsec_initialize(bis, &tsecs[i]);
+		if (ret > 0)
+			count += ret;
+	}
+
+	return count;
+}
+
+int tsec_standard_init(bd_t *bis)
+{
+	return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
+}
+
Signature · 1 line
1.6.4
author
#9 lore raw

PATCH 9/14 tsec: use general ethernet MII register struct(tsec_mii_t)

This will pave the way to move the PHY code to fsl_phy.c which will be reused by all other code.

---
 drivers/net/tsec.c |   10 +++++-----
 include/tsec.h     |   35 +++++++++++------------------------
 2 files changed, 16 insertions(+), 29 deletions(-)
drivers/net/tsec.c +5 -5
index 40f1c76..ac65c43 100644
@@ -56,7 +56,7 @@ static struct tsec_info_struct tsec_info[] = {
 #ifdef CONFIG_MPC85XX_FEC
 	{
 		.regs = (tsec_t *)(TSEC_BASE_ADDR + 0x2000),
-		.miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR),
+		.miiregs = (tsec_mii_t *)(MDIO_BASE_ADDR + 0x520),
 		.devname = CONFIG_MPC85XX_FEC_NAME,
 		.phyaddr = FEC_PHY_ADDR,
 		.flags = FEC_FLAGS
@@ -71,7 +71,7 @@ static struct tsec_info_struct tsec_info[] = {
 };
 
 /* Writes the given phy's reg with value, using the specified MDIO regs */
-static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr,
+static void tsec_local_mdio_write(tsec_mii_t *phyregs, uint addr,
 		uint reg, uint value)
 {
 	int timeout = 1000000;
@@ -94,7 +94,7 @@ static void tsec_local_mdio_write(tsec_mdio_t *phyregs, uint addr,
  * notvalid bit cleared), and the bus to cease activity (miimind
  * busy bit cleared), and then returns the value
  */
-static uint tsec_local_mdio_read(tsec_mdio_t *phyregs, uint phyid, uint regnum)
+static uint tsec_local_mdio_read(tsec_mii_t *phyregs, uint phyid, uint regnum)
 {
 	uint value;
 
@@ -635,7 +635,7 @@ static uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv)
 static uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv)
 {
 	uint phyid;
-	tsec_mdio_t *regbase = priv->phyregs;
+	tsec_mii_t *regbase = priv->phyregs;
 	int timeout = 1000000;
 
 	for (phyid = 0; phyid < 4; phyid++) {
@@ -1444,7 +1444,7 @@ static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
 {
 	int i;
 	uint result;
-	tsec_mdio_t *phyregs = priv->phyregs;
+	tsec_mii_t *phyregs = priv->phyregs;
 
 	out_be32(&phyregs->miimcfg, MIIMCFG_RESET);
 
include/tsec.h +11 -24
index 6971b47..054e5cf 100644
@@ -19,15 +19,18 @@
 
 #include <net.h>
 #include <config.h>
+#include <asm/fsl_enet.h>
 
 #define TSEC_SIZE 		0x01000
 #define TSEC_MDIO_OFFSET	0x01000
 
+#define CONFIG_SYS_MDIO_BASE_ADDR (TSEC_BASE_ADDR + 0x520)
+
 #define STD_TSEC_INFO(num) \
 {			\
 	.regs = (tsec_t *)(TSEC_BASE_ADDR + ((num - 1) * TSEC_SIZE)), \
-	.miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR), \
-	.miiregs_sgmii = (tsec_mdio_t *)(MDIO_BASE_ADDR \
+	.miiregs = (tsec_mii_t *)(CONFIG_SYS_MDIO_BASE_ADDR), \
+	.miiregs_sgmii = (tsec_mii_t *)(CONFIG_SYS_MDIO_BASE_ADDR \
 					 + (num - 1) * TSEC_MDIO_OFFSET), \
 	.devname = CONFIG_TSEC##num##_NAME, \
 	.phyaddr = TSEC##num##_PHY_ADDR, \
@@ -37,8 +40,8 @@
 #define SET_STD_TSEC_INFO(x, num) \
 {			\
 	x.regs = (tsec_t *)(TSEC_BASE_ADDR + ((num - 1) * TSEC_SIZE)); \
-	x.miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR); \
-	x.miiregs_sgmii = (tsec_mdio_t *)(MDIO_BASE_ADDR \
+	x.miiregs = (tsec_mii_t *)(CONFIG_SYS_MDIO_BASE_ADDR); \
+	x.miiregs_sgmii = (tsec_mii_t *)(CONFIG_SYS_MDIO_BASE_ADDR \
 					  + (num - 1) * TSEC_MDIO_OFFSET); \
 	x.devname = CONFIG_TSEC##num##_NAME; \
 	x.phyaddr = TSEC##num##_PHY_ADDR; \
@@ -467,22 +470,6 @@ typedef struct tsec_hash_regs
 	uint	res2[24];
 } tsec_hash_t;
 
-typedef struct tsec_mdio {
-	uint	res1[4];
-	uint	ieventm;
-	uint	imaskm;
-	uint	res2;
-	uint	emapm;
-	uint	res3[320];
-	uint	miimcfg;	/* MII Management: Configuration */
-	uint	miimcom;	/* MII Management: Command */
-	uint	miimadd;	/* MII Management: Address */
-	uint	miimcon;	/* MII Management: Control */
-	uint	miimstat;	/* MII Management: Status */
-	uint	miimind;	/* MII Management: Indicators */
-	uint	res4[690];
-} tsec_mdio_t;
-
 typedef struct tsec
 {
 	/* General Control and Status Registers (0x2_n000) */
@@ -588,8 +575,8 @@ typedef struct tsec
 
 struct tsec_private {
 	tsec_t *regs;
-	tsec_mdio_t *phyregs;
-	tsec_mdio_t *phyregs_sgmii;
+	tsec_mii_t *phyregs;
+	tsec_mii_t *phyregs_sgmii;
 	struct phy_info *phyinfo;
 	uint phyaddr;
 	u32 flags;
@@ -648,8 +635,8 @@ struct phy_info {
 
 struct tsec_info_struct {
 	tsec_t *regs;
-	tsec_mdio_t *miiregs;
-	tsec_mdio_t *miiregs_sgmii;
+	tsec_mii_t *miiregs;
+	tsec_mii_t *miiregs_sgmii;
 	char *devname;
 	unsigned int phyaddr;
 	u32 flags;
Signature · 1 line
1.6.4
author
#10 lore raw

PATCH 10/14 tsec: refactor the PHY code to make it reuseable

Also remove the PHY code which will be added by the following patches.

---
 drivers/net/Makefile |    2 +-
 drivers/net/tsec.c   | 1483 +++-----------------------------------------------
 include/tsec.h       |  246 +---------
 3 files changed, 70 insertions(+), 1661 deletions(-)
drivers/net/Makefile +1 -1
index 3810665..42fa327 100644
@@ -79,7 +79,7 @@ COBJS-$(CONFIG_TIGON3) += tigon3.o
 COBJS-$(CONFIG_TIGON3) += bcm570x_autoneg.o
 COBJS-$(CONFIG_TIGON3) += 5701rls.o
 COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
-COBJS-$(CONFIG_TSEC_ENET) += tsec.o
+COBJS-$(CONFIG_TSEC_ENET) += tsec.o fsl_phy.o
 COBJS-$(CONFIG_FMAN_ENET) += fsl_phy.o
 COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o
 COBJS-$(CONFIG_ULI526X) += uli526x.o
drivers/net/tsec.c +68 -1415

1,616 lines not on this page · raw message

include/tsec.h +1 -245

270 lines not on this page · raw message

Signature · 1 line
1.6.4
author
#11 lore raw

PATCH 11/14 PHY: add some Vitesse phy support

Port from tsec.c file to add support for vsc8221, vsc8211, vsc8601, vsc8641.

---
 drivers/net/fsl_phy.c |  119 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/fsl_phy.h |   21 +++++++++
 2 files changed, 140 insertions(+), 0 deletions(-)
drivers/net/fsl_phy.c +119 -0
index 1ba0ce1..a6ec614 100644
@@ -242,6 +242,58 @@ static int genphy_shutdown(struct mii_info *phydev)
 	return 0;
 }
 
+/* Vitesse VSC8211 */
+static int vsc8211_config(struct mii_info *mii_info)
+{
+	/* Override PHY config settings */
+	tsec_phy_write(mii_info, 0, MIIM_CIS8201_AUX_CONSTAT,
+			MIIM_CIS8201_AUXCONSTAT_INIT);
+	/* Set up the interface mode */
+	tsec_phy_write(mii_info, 0, MIIM_CIS8201_EXT_CON1,
+			MIIM_CIS8201_EXTCON1_INIT);
+	/* Configure some basic stuff */
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	return 0;
+}
+
+static int vsc8211_parse_status(struct mii_info *mii_info)
+{
+	unsigned int speed;
+	unsigned int mii_reg;
+
+	mii_reg = tsec_phy_read(mii_info, 0, MIIM_CIS8201_AUX_CONSTAT);
+
+	if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
+		mii_info->duplex = DUPLEX_FULL;
+	else
+		mii_info->duplex = DUPLEX_HALF;
+
+	speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
+	switch (speed) {
+	case MIIM_CIS8201_AUXCONSTAT_GBIT:
+		mii_info->speed = SPEED_1000;
+		break;
+	case MIIM_CIS8201_AUXCONSTAT_100:
+		mii_info->speed = SPEED_100;
+		break;
+	default:
+		mii_info->speed = SPEED_10;
+		break;
+	}
+
+	return 0;
+}
+
+static int vsc8211_startup(struct mii_info *mii_info)
+{
+	/* Read the Status (2x to make sure link is right) */
+	genphy_update_link(mii_info);
+	vsc8211_parse_status(mii_info);
+
+	return 0;
+}
+ 
 /* Vitesse VSC8244 */
 static int vsc8244_parse_status(struct mii_info *mii_info)
 {
@@ -280,6 +332,51 @@ static int vsc8244_startup(struct mii_info *mii_info)
 	return 0;
 }
 
+/* Vitesse VSC8601 */
+int vsc8601_config(struct mii_info *mii_info)
+{
+	unsigned int reg;
+
+	/* Configure some basic stuff */
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+#ifdef CONFIG_SYS_VSC8601_SKEWFIX
+	tsec_phy_write(mii_info, 0, MIIM_VSC8601_EPHY_CON,
+			MIIM_VSC8601_EPHY_CON_INIT_SKEW);
+#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX)
+	tsec_phy_write(mii_info, 0, PHY_EXT_PAGE_ACCESS, 1);
+#define VSC8101_SKEW \
+	(CONFIG_SYS_VSC8601_SKEW_TX << 14) | (CONFIG_SYS_VSC8601_SKEW_RX << 12)
+	tsec_phy_write(mii_info, 0, MIIM_VSC8601_SKEW_CTRL, VSC8101_SKEW);
+	tsec_phy_write(mii_info, 0, PHY_EXT_PAGE_ACCESS, 0);
+#endif
+#endif
+	tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+
+	reg = tsec_phy_read(mii_info, 0, MII_BMCR);
+	reg |= BMCR_ANRESTART;
+	tsec_phy_write(mii_info, 0, MII_BMCR, reg);
+
+	return 0;
+}
+
+static struct phy_info phy_info_VSC8211 = {
+	"Vitesse VSC8211",
+	0xfc4b0,
+	0xffff0,
+	&vsc8211_config,
+	&vsc8211_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_VSC8221 = {
+	"Vitesse VSC8221",
+	0xfc550,
+	0xffff0,
+	&genphy_config,
+	&vsc8244_startup,
+	&genphy_shutdown,
+};
+
 static struct phy_info phy_info_VSC8244 = {
 	"Vitesse VSC8244",
 	0xfc6c0,
@@ -298,6 +395,24 @@ static struct phy_info phy_info_VSC8234 = {
 	&genphy_shutdown,
 };
 
+static struct phy_info phy_info_VSC8601 = {
+	"Vitesse VSC8601",
+	0x70420,
+	0xffff0,
+	&vsc8601_config,
+	&vsc8244_startup,
+	&genphy_shutdown,
+};
+
+struct phy_info phy_info_VSC8641 = {
+	"Vitesse VSC8641",
+	0x70430,
+	0xffff0,
+	&genphy_config,
+	&vsc8244_startup,
+	&genphy_shutdown,
+};
+
 static struct phy_info phy_info_generic = {
 	"Unknown/Generic PHY",
 	0x0,
@@ -308,8 +423,12 @@ static struct phy_info phy_info_generic = {
 };
 
 static struct phy_info *phy_info[] = {
+	&phy_info_VSC8211,
+	&phy_info_VSC8221,
 	&phy_info_VSC8244,
 	&phy_info_VSC8234,
+	&phy_info_VSC8601,
+	&phy_info_VSC8641,
 	&phy_info_generic
 };
 
drivers/net/fsl_phy.h +21 -0
index 8a8b6e8..d18cc58 100644
@@ -34,7 +34,11 @@
 #define PORT_MII	0x02
 #define PORT_FIBRE	0x03
 
+/* PHY register offsets */
+#define PHY_EXT_PAGE_ACCESS	0x1f
+
 #define MII_BMCR_INIT           0x00001140
+#define MII_ADVERTISE_INIT	0x1e1
 
 /* MII Management Configuration Register */
 #define MIIMCFG_RESET_MGMT          0x80000000
@@ -96,6 +100,18 @@
 
 #define PHY_AUTONEGOTIATE_TIMEOUT	5000 /* in ms */
 
+/* Cicada Auxiliary Control/Status Register */
+#define MIIM_CIS8201_AUX_CONSTAT	0x1c
+#define MIIM_CIS8201_AUXCONSTAT_INIT	0x0004
+#define MIIM_CIS8201_AUXCONSTAT_DUPLEX	0x0020
+#define MIIM_CIS8201_AUXCONSTAT_SPEED	0x0018
+#define MIIM_CIS8201_AUXCONSTAT_GBIT	0x0010
+#define MIIM_CIS8201_AUXCONSTAT_100	0x0008
+
+/* Cicada Extended Control Register 1 */
+#define MIIM_CIS8201_EXT_CON1		0x17
+#define MIIM_CIS8201_EXTCON1_INIT	0x0000
+
 /* Entry for Vitesse VSC8244 regs starts here */
 /* Vitesse VSC8244 Auxiliary Control/Status Register */
 #define MIIM_VSC8244_AUX_CONSTAT	0x1c
@@ -106,6 +122,11 @@
 #define MIIM_VSC8244_AUXCONSTAT_100	0x0008
 #define MIIM_CONTROL_INIT_LOOPBACK	0x4000
 
+/* Vitesse VSC8601 Extended PHY Control Register 1 */
+#define MIIM_VSC8601_EPHY_CON		0x17
+#define MIIM_VSC8601_EPHY_CON_INIT_SKEW	0x1120
+#define MIIM_VSC8601_SKEW_CTRL		0x1c
+
 struct mii_info {
 	/* Information about the PHY type */
 	/* And management functions */
Signature · 1 line
1.6.4
author
#12 lore raw

PATCH 12/14 PHY: add some Broadcom phy support

Port from tsec.c file to add support for bcm5461, bcm5464, bcm5482s.

---
 drivers/net/fsl_phy.c |  245 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/fsl_phy.h |   22 +++++
 2 files changed, 267 insertions(+), 0 deletions(-)
drivers/net/fsl_phy.c +245 -0
index a6ec614..7c22666 100644
@@ -21,6 +21,7 @@
 #include <common.h>
 #include <asm/io.h>
 #include <asm/errno.h>
+#include <tsec.h>
 
 #include "fsl_phy.h"
 
@@ -242,6 +243,220 @@ static int genphy_shutdown(struct mii_info *phydev)
 	return 0;
 }
 
+/* Broadcom BCM5461S */
+static int bcm5461_config(struct mii_info *mii_info)
+{
+	unsigned int reg;
+
+	/* reset the PHY */
+	reg = tsec_phy_read(mii_info, 0, MII_BMCR);
+	reg |= BMCR_RESET;
+	tsec_phy_write(mii_info, 0, MII_BMCR, reg);
+
+	tsec_phy_write(mii_info, 0, MII_CTRL1000, MII_CTRL1000_INIT);
+	tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+
+	/* reset the PHY */
+	reg = tsec_phy_read(mii_info, 0, MII_BMCR);
+	reg |= BMCR_RESET;
+	tsec_phy_write(mii_info, 0, MII_BMCR, reg);
+
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	return 0;
+}
+
+static int bcm54xx_parse_status(struct mii_info *mii_info)
+{
+	unsigned int mii_reg;
+
+	mii_reg = tsec_phy_read(mii_info, 0, MIIM_BCM54xx_AUXSTATUS);
+
+	switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >>
+			MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) {
+		case 1:
+		mii_info->duplex = DUPLEX_HALF;
+		mii_info->speed = SPEED_10;
+		break;
+		case 2:
+		mii_info->duplex = DUPLEX_FULL;
+		mii_info->speed = SPEED_10;
+		break;
+		case 3:
+		mii_info->duplex = DUPLEX_HALF;
+		mii_info->speed = SPEED_100;
+		break;
+		case 5:
+		mii_info->duplex = DUPLEX_FULL;
+		mii_info->speed = SPEED_100;
+		break;
+		case 6:
+		mii_info->duplex = DUPLEX_HALF;
+		mii_info->speed = SPEED_1000;
+		break;
+		case 7:
+		mii_info->duplex = DUPLEX_FULL;
+		mii_info->speed = SPEED_1000;
+		break;
+		default:
+		printf("Auto-neg error, defaulting to 10BT/HD\n");
+		mii_info->duplex = DUPLEX_HALF;
+		mii_info->speed = SPEED_10;
+		break;
+	}
+
+	return 0;
+}
+
+static int bcm54xx_startup(struct mii_info *mii_info)
+{
+	/* Read the Status (2x to make sure link is right) */
+	genphy_update_link(mii_info);
+	bcm54xx_parse_status(mii_info);
+
+	return 0;
+}
+
+/* Broadcom BCM5482S */
+/*
+ * "Ethernet at 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 at Wirespeed" reduces advertised speed until link
+ * can be achieved.
+ */
+static u32 bcm5482_read_wirespeed(struct mii_info *mii_info, u32 reg)
+{
+	return (tsec_phy_read(mii_info, 0, reg) & 0x8FFF) | 0x8010;
+}
+
+static int bcm5482_config(struct mii_info *mii_info)
+{
+	unsigned int reg;
+
+	/* reset the PHY */
+	reg = tsec_phy_read(mii_info, 0, MII_BMCR);
+	reg |= BMCR_RESET;
+	tsec_phy_write(mii_info, 0, MII_BMCR, reg);
+
+	/* Setup read from auxilary control shadow register 7 */
+	tsec_phy_write(mii_info, 0, MIIM_BCM54xx_AUXCNTL,
+			MIIM_BCM54xx_AUXCNTL_ENCODE(7));
+	/* Read Misc Control register and or in Ethernet at Wirespeed */
+	reg = bcm5482_read_wirespeed(mii_info, MIIM_BCM54xx_AUXCNTL);
+	tsec_phy_write(mii_info, 0, MIIM_BCM54xx_AUXCNTL, reg);
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+	/* Initial config/enable of secondary SerDes interface */
+	tsec_phy_write(mii_info, 0, MIIM_BCM54XX_SHD,
+			MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf));
+	/* Write intial value to secondary SerDes Contol */
+	tsec_phy_write(mii_info, 0, MIIM_BCM54XX_EXP_SEL,
+			MIIM_BCM54XX_EXP_SEL_SSD | 0);
+	tsec_phy_write(mii_info, 0, MIIM_BCM54XX_EXP_DATA, MII_BMCR_RESTART);
+	/* Enable copper/fiber auto-detect */
+	tsec_phy_write(mii_info, 0, MIIM_BCM54XX_SHD,
+			MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201));
+
+	return 0;
+}
+
+/*
+ * Find out if PHY is in copper or serdes mode by looking at Expansion Reg
+ * 0x42 - "Operating Mode Status Register"
+ */
+static int bcm5482_is_serdes(struct mii_info *mii_info)
+{
+	u16 val;
+	int serdes = 0;
+
+	tsec_phy_write(mii_info, 0, MIIM_BCM54XX_EXP_SEL,
+			MIIM_BCM54XX_EXP_SEL_ER | 0x42);
+	val = tsec_phy_read(mii_info, 0, MIIM_BCM54XX_EXP_DATA);
+
+	switch (val & 0x1f) {
+	case 0x0d:	/* RGMII-to-100Base-FX */
+	case 0x0e:	/* RGMII-to-SGMII */
+	case 0x0f:	/* RGMII-to-SerDes */
+	case 0x12:	/* SGMII-to-SerDes */
+	case 0x13:	/* SGMII-to-100Base-FX */
+	case 0x16:	/* SerDes-to-Serdes */
+		serdes = 1;
+		break;
+	case 0x6:	/* RGMII-to-Copper */
+	case 0x14:	/* SGMII-to-Copper */
+	case 0x17:	/* SerDes-to-Copper */
+		break;
+	default:
+		printf("ERROR, invalid PHY mode (0x%x\n)", val);
+		break;
+	}
+
+	return serdes;
+}
+
+/*
+ * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating
+ * Mode Status Register"
+ */
+static u32 bcm5482_parse_serdes_sr(struct mii_info *mii_info)
+{
+	u16 val;
+	int i = 0;
+
+	/* Wait 1s for link - Clause 37 autonegotiation happens very fast */
+	while (1) {
+		tsec_phy_write(mii_info, 0, MIIM_BCM54XX_EXP_SEL,
+				MIIM_BCM54XX_EXP_SEL_ER | 0x42);
+		val = tsec_phy_read(mii_info, 0, MIIM_BCM54XX_EXP_DATA);
+
+		if (val & 0x8000)
+			break;
+
+		if (i++ > 1000) {
+			mii_info->link = 0;
+			return 1;
+		}
+
+		udelay(1000);	/* 1 ms */
+	}
+
+	mii_info->link = 1;
+	switch ((val >> 13) & 0x3) {
+	case (0x00):
+		mii_info->speed = 10;
+		break;
+	case (0x01):
+		mii_info->speed = 100;
+		break;
+	case (0x02):
+		mii_info->speed = 1000;
+		break;
+	}
+
+	mii_info->duplex = (val & 0x1000) == 0x1000;
+
+	return 0;
+}
+
+/*
+ * Figure out if BCM5482 is in serdes or copper mode and determine link
+ * configuration accordingly
+ */
+static int bcm5482_startup(struct mii_info *mii_info)
+{
+	if (bcm5482_is_serdes(mii_info)) {
+		bcm5482_parse_serdes_sr(mii_info);
+		mii_info->flags |= TSEC_FIBER;
+	} else {
+		/* Wait for auto-negotiation to complete or fail */
+		genphy_update_link(mii_info);
+		/* Parse BCM54xx copper aux status register */
+		bcm54xx_parse_status(mii_info);
+	}
+
+	return 0;
+}
+
 /* Vitesse VSC8211 */
 static int vsc8211_config(struct mii_info *mii_info)
 {
@@ -359,6 +574,33 @@ int vsc8601_config(struct mii_info *mii_info)
 	return 0;
 }
 
+static struct phy_info phy_info_BCM5461S = {
+	"Broadcom BCM5461S",
+	0x2060c0,
+	0xfffff0,
+	&bcm5461_config,
+	&bcm54xx_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_BCM5464S = {
+	"Broadcom BCM5464S",
+	0x2060b0,
+	0xfffff0,
+	&bcm5461_config,
+	&bcm54xx_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_BCM5482S = {
+	"Broadcom BCM5482S",
+	0x143bcb0,
+	0xffffff0,
+	&bcm5482_config,
+	&bcm5482_startup,
+	&genphy_shutdown,
+};
+
 static struct phy_info phy_info_VSC8211 = {
 	"Vitesse VSC8211",
 	0xfc4b0,
@@ -423,6 +665,9 @@ static struct phy_info phy_info_generic = {
 };
 
 static struct phy_info *phy_info[] = {
+	&phy_info_BCM5461S,
+	&phy_info_BCM5464S,
+	&phy_info_BCM5482S,
 	&phy_info_VSC8211,
 	&phy_info_VSC8221,
 	&phy_info_VSC8244,
drivers/net/fsl_phy.h +22 -0
index d18cc58..340527c 100644
@@ -38,7 +38,9 @@
 #define PHY_EXT_PAGE_ACCESS	0x1f
 
 #define MII_BMCR_INIT           0x00001140
+#define MII_BMCR_RESTART	0x00001340
 #define MII_ADVERTISE_INIT	0x1e1
+#define MII_CTRL1000_INIT	0xe00
 
 /* MII Management Configuration Register */
 #define MIIMCFG_RESET_MGMT          0x80000000
@@ -100,6 +102,26 @@
 
 #define PHY_AUTONEGOTIATE_TIMEOUT	5000 /* in ms */
 
+/* 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
+
+#define MIIM_BCM54XX_SHD			0x1c
+#define MIIM_BCM54XX_SHD_WRITE			0x8000
+#define MIIM_BCM54XX_SHD_VAL(x)			((x & 0x1f) << 10)
+#define MIIM_BCM54XX_SHD_DATA(x)		((x & 0x3ff) << 0)
+#define MIIM_BCM54XX_SHD_WR_ENCODE(val, data)	\
+	(MIIM_BCM54XX_SHD_WRITE | MIIM_BCM54XX_SHD_VAL(val) | \
+	 MIIM_BCM54XX_SHD_DATA(data))
+
+#define MIIM_BCM54XX_EXP_DATA		0x15	/* Expansion register data */
+#define MIIM_BCM54XX_EXP_SEL		0x17	/* Expansion register select */
+#define MIIM_BCM54XX_EXP_SEL_SSD	0x0e00	/* Secondary SerDes select */
+#define MIIM_BCM54XX_EXP_SEL_ER		0x0f00	/* Expansion register select */
+
 /* Cicada Auxiliary Control/Status Register */
 #define MIIM_CIS8201_AUX_CONSTAT	0x1c
 #define MIIM_CIS8201_AUXCONSTAT_INIT	0x0004
Signature · 1 line
1.6.4
author
#13 lore raw

PATCH 13/14 PHY: add some Marvell phy support

Port from tsec.c file to add support for m88e1011s, m88e1111s, m88e1118, m88e1121r, m88e1145, m88e1149s.

---
 drivers/net/fsl_phy.c |  299 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/fsl_phy.h |   36 ++++++
 2 files changed, 335 insertions(+), 0 deletions(-)
drivers/net/fsl_phy.c +299 -0
index 7c22666..ad9d65e 100644
@@ -457,6 +457,245 @@ static int bcm5482_startup(struct mii_info *mii_info)
 	return 0;
 }
 
+/* Marvell 88E1011S */
+static int m88e1011s_config(struct mii_info *mii_info)
+{
+	/* Reset and configure the PHY */
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+
+	tsec_phy_write(mii_info, 0, 0x1d, 0x1f);
+	tsec_phy_write(mii_info, 0, 0x1e, 0x200c);
+	tsec_phy_write(mii_info, 0, 0x1d, 0x5);
+	tsec_phy_write(mii_info, 0, 0x1e, 0);
+	tsec_phy_write(mii_info, 0, 0x1e, 0x100);
+	tsec_phy_write(mii_info, 0, MII_CTRL1000, MII_CTRL1000_INIT);
+	tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	return 0;
+}
+
+/* Parse the 88E1011's status register for speed and duplex
+ * information
+ */
+static uint m88e1011s_parse_status(struct mii_info *mii_info)
+{
+	unsigned int speed;
+	unsigned int mii_reg;
+
+	mii_reg = tsec_phy_read(mii_info, 0, MIIM_88E1011_PHY_STATUS);
+
+	if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) &&
+		!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
+		int i = 0;
+
+		puts("Waiting for PHY realtime link");
+		while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
+			/* Timeout reached ? */
+			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+				puts(" TIMEOUT !\n");
+				mii_info->link = 0;
+				break;
+			}
+
+			if ((i++ % 1000) == 0) {
+				putc('.');
+			}
+			udelay(1000);
+			mii_reg = tsec_phy_read(mii_info, 0,
+					MIIM_88E1011_PHY_STATUS);
+		}
+		puts(" done\n");
+		udelay(500000);	/* another 500 ms (results in faster booting) */
+	} else {
+		if (mii_reg & MIIM_88E1011_PHYSTAT_LINK)
+			mii_info->link = 1;
+		else
+			mii_info->link = 0;
+	}
+
+	if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
+		mii_info->duplex = DUPLEX_FULL;
+	else
+		mii_info->duplex = DUPLEX_HALF;
+
+	speed = mii_reg & MIIM_88E1011_PHYSTAT_SPEED;
+
+	switch (speed) {
+	case MIIM_88E1011_PHYSTAT_GBIT:
+		mii_info->speed = SPEED_1000;
+		break;
+	case MIIM_88E1011_PHYSTAT_100:
+		mii_info->speed = SPEED_100;
+		break;
+	default:
+		mii_info->speed = SPEED_10;
+		break;
+	}
+
+	return 0;
+}
+
+static int m88e1011s_startup(struct mii_info *mii_info)
+{
+	genphy_update_link(mii_info);
+	m88e1011s_parse_status(mii_info);
+
+	return 0;
+}
+
+/* Marvell 88E1111S */
+static int m88e1111s_config(struct mii_info *mii_info)
+{
+	int reg;
+
+	/* Reset and configure the PHY */
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+
+	if (mii_info->flags & TSEC_REDUCED) {
+		reg = tsec_phy_read(mii_info, 0, 0x1b);
+		reg = (reg & 0xfff0) | 0xb;
+		tsec_phy_write(mii_info, 0, 0x1b, reg);
+	} else {
+		tsec_phy_write(mii_info, 0, 0x1b, 0x1f);
+	}
+
+	tsec_phy_write(mii_info, 0, 0x14, 0x0cd2);
+	tsec_phy_write(mii_info, 0, MII_CTRL1000, MII_CTRL1000_INIT);
+	tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	return 0;
+}
+
+/* Marvell 88E1118 */
+static int m88e1118_config(struct mii_info *mii_info)
+{
+	/* Reset and configure the PHY */
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+	/* Change Page Number */
+	tsec_phy_write(mii_info, 0, 0x16, 0x0002);
+	/* Delay RGMII TX and RX */
+	tsec_phy_write(mii_info, 0, 0x15, 0x1070);
+	/* Change Page Number */
+	tsec_phy_write(mii_info, 0, 0x16, 0x0003);
+	/* Adjust LED control */
+	tsec_phy_write(mii_info, 0, 0x10, 0x021e);
+	/* Change Page Number */
+	tsec_phy_write(mii_info, 0, 0x16, 0x0000);
+
+	tsec_phy_write(mii_info, 0, MII_CTRL1000, MII_CTRL1000_INIT);
+	tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	return 0;
+}
+
+static int m88e1118_startup(struct mii_info *mii_info)
+{
+	/* Change Page Number */
+	tsec_phy_write(mii_info, 0, 0x16, 0x0000);
+
+	genphy_update_link(mii_info);
+	m88e1011s_parse_status(mii_info);
+
+	return 0;
+}
+
+/* Marvell 88E1121R */
+static int m88e1121_config(struct mii_info *mii_info)
+{
+	int pg;
+
+	/* Reset and configure the PHY */
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+	tsec_phy_write(mii_info, 0, MII_CTRL1000, MII_CTRL1000_INIT);
+	tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+
+	/* Switch the page to access the led register */
+	pg = tsec_phy_read(mii_info, 0, MIIM_88E1121_PHY_PAGE);
+	tsec_phy_write(mii_info, 0, MIIM_88E1121_PHY_PAGE,
+			MIIM_88E1121_PHY_LED_PAGE);
+	/* Configure leds */
+	tsec_phy_write(mii_info, 0, MIIM_88E1121_PHY_LED_CTRL,
+			MIIM_88E1121_PHY_LED_DEF);
+	/* Restore the page pointer */
+	tsec_phy_write(mii_info, 0, MIIM_88E1121_PHY_PAGE, pg);
+
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+	/* Disable IRQs and de-assert interrupt */
+	tsec_phy_write(mii_info, 0, MIIM_88E1121_PHY_IRQ_EN, 0);
+	tsec_phy_read(mii_info, 0, MIIM_88E1121_PHY_IRQ_STATUS);
+
+	return 0;
+}
+
+/* Marvell 88E1145 */
+static int m88e1145_config(struct mii_info *mii_info)
+{
+	int reg;
+
+	/* Reset and configure the PHY */
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+
+	/* Errata E0, E1 */
+	tsec_phy_write(mii_info, 0, 29, 0x001b);
+	tsec_phy_write(mii_info, 0, 30, 0x418f);
+	tsec_phy_write(mii_info, 0, 29, 0x0016);
+	tsec_phy_write(mii_info, 0, 30, 0xa2da);
+
+	tsec_phy_write(mii_info, 0, MII_CTRL1000, MII_CTRL1000_INIT);
+	tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+
+	tsec_phy_write(mii_info, 0, MIIM_88E1011_PHY_SCR,
+			MIIM_88E1011_PHY_MDI_X_AUTO);
+
+	reg = tsec_phy_read(mii_info, 0, MIIM_88E1145_PHY_EXT_CR);
+	if (mii_info->flags & TSEC_REDUCED)
+		reg |= MIIM_M88E1145_RGMII_RX_DELAY |
+			MIIM_M88E1145_RGMII_TX_DELAY;
+	tsec_phy_write(mii_info, 0, MIIM_88E1145_PHY_EXT_CR, reg);
+
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	return 0;
+}
+
+static int m88e1145_startup(struct mii_info *mii_info)
+{
+	genphy_update_link(mii_info);
+	tsec_phy_write(mii_info, 0, MIIM_88E1111_PHY_LED_CONTROL,
+			MIIM_88E1111_PHY_LED_DIRECT);
+	m88e1011s_parse_status(mii_info);
+
+	return 0;
+}
+
+/* Marvell 88E1149S */
+static int m88e1149_config(struct mii_info *mii_info)
+{
+	/* Reset and configure the PHY */
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+
+	tsec_phy_write(mii_info, 0, 0x1d, 0x1f);
+	tsec_phy_write(mii_info, 0, 0x1e, 0x200c);
+	tsec_phy_write(mii_info, 0, 0x1d, 0x5);
+	tsec_phy_write(mii_info, 0, 0x1e, 0x0);
+	tsec_phy_write(mii_info, 0, 0x1e, 0x100);
+
+	tsec_phy_write(mii_info, 0, MII_CTRL1000, MII_CTRL1000_INIT);
+	tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	return 0;
+}
+
 /* Vitesse VSC8211 */
 static int vsc8211_config(struct mii_info *mii_info)
 {
@@ -601,6 +840,60 @@ static struct phy_info phy_info_BCM5482S = {
 	&genphy_shutdown,
 };
 
+static struct phy_info phy_info_M88E1011S = {
+	"Marvell 88E1011S",
+	0x1410c60,
+	0xffffff0,
+	&m88e1011s_config,
+	&m88e1011s_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_M88E1111S = {
+	"Marvell 88E1111S",
+	0x1410cc0,
+	0xffffff0,
+	&m88e1111s_config,
+	&m88e1011s_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_M88E1118 = {
+	"Marvell 88E1118",
+	0x1410e10,
+	0xffffff0,
+	&m88e1118_config,
+	&m88e1118_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_M88E1121R = {
+	"Marvell 88E1121R",
+	0x1410cb0,
+	0xffffff0,
+	&m88e1121_config,
+	&genphy_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_M88E1145 = {
+	"Marvell 88E1145",
+	0x1410cd0,
+	0xffffff0,
+	&m88e1145_config,
+	&m88e1145_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_M88E1149S = {
+	"Marvell 88E1149S",
+	0x1410ca0,
+	0xffffff0,
+	&m88e1149_config,
+	&m88e1011s_startup,
+	&genphy_shutdown,
+};
+
 static struct phy_info phy_info_VSC8211 = {
 	"Vitesse VSC8211",
 	0xfc4b0,
@@ -668,6 +961,12 @@ static struct phy_info *phy_info[] = {
 	&phy_info_BCM5461S,
 	&phy_info_BCM5464S,
 	&phy_info_BCM5482S,
+	&phy_info_M88E1011S,
+	&phy_info_M88E1111S,
+	&phy_info_M88E1118,
+	&phy_info_M88E1121R,
+	&phy_info_M88E1145,
+	&phy_info_M88E1149S,
 	&phy_info_VSC8211,
 	&phy_info_VSC8221,
 	&phy_info_VSC8244,
drivers/net/fsl_phy.h +36 -0
index 340527c..5e6d236 100644
@@ -134,6 +134,42 @@
 #define MIIM_CIS8201_EXT_CON1		0x17
 #define MIIM_CIS8201_EXTCON1_INIT	0x0000
 
+/* 88E1011 PHY Status Register */
+#define MIIM_88E1011_PHY_STATUS		0x11
+#define MIIM_88E1011_PHYSTAT_SPEED	0xc000
+#define MIIM_88E1011_PHYSTAT_GBIT	0x8000
+#define MIIM_88E1011_PHYSTAT_100	0x4000
+#define MIIM_88E1011_PHYSTAT_DUPLEX	0x2000
+#define MIIM_88E1011_PHYSTAT_SPDDONE	0x0800
+#define MIIM_88E1011_PHYSTAT_LINK	0x0400
+
+#define MIIM_88E1011_PHY_SCR		0x10
+#define MIIM_88E1011_PHY_MDI_X_AUTO	0x0060
+
+/* 88E1111 PHY LED Control Register */
+#define MIIM_88E1111_PHY_LED_CONTROL	24
+#define MIIM_88E1111_PHY_LED_DIRECT	0x4100
+#define MIIM_88E1111_PHY_LED_COMBINE	0x411C
+
+/* 88E1121 PHY LED Control Register */
+#define MIIM_88E1121_PHY_LED_CTRL	16
+#define MIIM_88E1121_PHY_LED_PAGE	3
+#define MIIM_88E1121_PHY_LED_DEF	0x0030
+
+/* 88E1121 PHY IRQ Enable/Status Register */
+#define MIIM_88E1121_PHY_IRQ_EN		18
+#define MIIM_88E1121_PHY_IRQ_STATUS	19
+
+#define MIIM_88E1121_PHY_PAGE		22
+
+/* 88E1145 Extended PHY Specific Control Register */
+#define MIIM_88E1145_PHY_EXT_CR 20
+#define MIIM_M88E1145_RGMII_RX_DELAY	0x0080
+#define MIIM_M88E1145_RGMII_TX_DELAY	0x0002
+
+#define MIIM_88E1145_PHY_PAGE	29
+#define MIIM_88E1145_PHY_CAL_OV 30
+
 /* Entry for Vitesse VSC8244 regs starts here */
 /* Vitesse VSC8244 Auxiliary Control/Status Register */
 #define MIIM_VSC8244_AUX_CONSTAT	0x1c
Signature · 1 line
1.6.4
author
#14 lore raw

PATCH 14/14 PHY: add some misc phy code support

Port from tsec.c file to add support for cis8201, cis8204, dm9161, dp83865, ksz804, lxt971, rtl8211b.

---
 drivers/net/fsl_phy.c |  356 ++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/fsl_phy.h |   57 ++++++++
 drivers/net/tsec.c    |   24 ++++
 3 files changed, 436 insertions(+), 1 deletions(-)
drivers/net/fsl_phy.c +355 -1
index ad9d65e..3a8ebbc 100644
@@ -457,6 +457,211 @@ static int bcm5482_startup(struct mii_info *mii_info)
 	return 0;
 }
 
+/* CIS8201 */
+static int cis8201_config(struct mii_info *mii_info)
+{
+	/* Override PHY config settings */
+	tsec_phy_write(mii_info, 0, MIIM_CIS8201_AUX_CONSTAT,
+			MIIM_CIS8201_AUXCONSTAT_INIT);
+	/* Set up the interface mode */
+	tsec_phy_write(mii_info, 0, MIIM_CIS8201_EXT_CON1,
+			MIIM_CIS8201_EXTCON1_INIT);
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	return 0;
+}
+
+static int cis8201_parse_status(struct mii_info *mii_info)
+{
+	int speed;
+	int mii_reg;
+
+	mii_reg = tsec_phy_read(mii_info, 0, MIIM_CIS8201_AUX_CONSTAT);
+
+	if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)
+		mii_info->duplex = DUPLEX_FULL;
+	else
+		mii_info->duplex = DUPLEX_HALF;
+
+	speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;
+	switch (speed) {
+	case MIIM_CIS8201_AUXCONSTAT_GBIT:
+		mii_info->speed = SPEED_1000;
+		break;
+	case MIIM_CIS8201_AUXCONSTAT_100:
+		mii_info->speed = SPEED_100;
+		break;
+	default:
+		mii_info->speed = SPEED_10;
+		break;
+	}
+
+	return 0;
+}
+
+static int cis8201_startup(struct mii_info *mii_info)
+{
+	genphy_update_link(mii_info);
+	cis8201_parse_status(mii_info);
+
+	return 0;
+}
+
+/* CIS8204 */
+static int __cis8204_fixled(struct mii_info *mii_info)
+{
+	return 0;
+}
+
+int cis8204_fixled(struct mii_info *mii_info)
+	__attribute__((weak, alias("__cis8204_fixled")));
+
+static int cis8204_config(struct mii_info *mii_info)
+{
+	/* Override PHY config settings */
+	tsec_phy_write(mii_info, 0, MIIM_CIS8201_AUX_CONSTAT,
+			MIIM_CIS8201_AUXCONSTAT_INIT);
+	/* Configure some basic stuff */
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	cis8204_fixled(mii_info);
+
+	if (mii_info->flags & TSEC_REDUCED)
+		tsec_phy_write(mii_info, 0, MIIM_CIS8204_EPHY_CON,
+				MIIM_CIS8204_EPHYCON_INIT |
+				MIIM_CIS8204_EPHYCON_RGMII);
+	else
+		tsec_phy_write(mii_info, 0, MIIM_CIS8204_EPHY_CON,
+				MIIM_CIS8204_EPHYCON_INIT);
+
+	return 0;
+}
+
+/* Davicom DM9161E */
+static int dm9161_config(struct mii_info *mii_info)
+{
+	tsec_phy_write(mii_info, 0, MII_BMCR, MIIM_DM9161_CR_STOP);
+	/* Do not bypass the scrambler/descrambler */
+	tsec_phy_write(mii_info, 0, MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT);
+	/* Clear 10BTCSR to default */
+	tsec_phy_write(mii_info, 0, MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT);
+
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+	/* Restart Auto Negotiation */
+	tsec_phy_write(mii_info, 0, MII_BMCR, MIIM_DM9161_CR_RSTAN);
+
+	return 0;
+}
+
+static int dm9161_parse_status(struct mii_info *mii_info)
+{
+	int mii_reg;
+
+	mii_reg = tsec_phy_read(mii_info, 0, MIIM_DM9161_SCSR);
+
+	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H))
+		mii_info->speed = SPEED_100;
+	else
+		mii_info->speed = SPEED_10;
+
+	if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F))
+		mii_info->duplex = DUPLEX_FULL;
+	else
+		mii_info->duplex = DUPLEX_HALF;
+
+	return 0;
+}
+
+static int dm9161_startup(struct mii_info *mii_info)
+{
+	genphy_update_link(mii_info);
+	dm9161_parse_status(mii_info);
+
+	return 0;
+}
+
+/* NatSemi DP83865 */
+static int dp83865_config(struct mii_info *mii_info)
+{
+	return tsec_phy_write(mii_info, 0, MII_BMCR, MIIM_DP83865_CR_INIT);
+}
+
+static int dp83865_parse_status(struct mii_info *mii_info)
+{
+	int mii_reg;
+
+	mii_reg = tsec_phy_read(mii_info, 0, MIIM_DP83865_LANR);
+
+	switch (mii_reg & MIIM_DP83865_SPD_MASK) {
+
+	case MIIM_DP83865_SPD_1000:
+		mii_info->speed = SPEED_1000;
+		break;
+
+	case MIIM_DP83865_SPD_100:
+		mii_info->speed = SPEED_100;
+		break;
+
+	default:
+		mii_info->speed = SPEED_10;
+		break;
+
+	}
+
+	if (mii_reg & MIIM_DP83865_DPX_FULL)
+		mii_info->duplex = DUPLEX_FULL;
+	else
+		mii_info->duplex = DUPLEX_HALF;
+
+	return 0;
+}
+
+static int dp83865_startup(struct mii_info *mii_info)
+{
+	genphy_update_link(mii_info);
+	dp83865_parse_status(mii_info);
+
+	return 0;
+}
+
+/* LXT971 */
+static int lxt971_parse_status(struct mii_info *mii_info)
+{
+	int mii_reg;
+	int speed;
+
+	mii_reg = tsec_phy_read(mii_info, 0, MIIM_LXT971_SR2);
+	speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK;
+
+	switch (speed) {
+	case MIIM_LXT971_SR2_10HDX:
+		mii_info->speed = SPEED_10;
+		mii_info->duplex = DUPLEX_HALF;
+		break;
+	case MIIM_LXT971_SR2_10FDX:
+		mii_info->speed = SPEED_10;
+		mii_info->duplex = DUPLEX_FULL;
+		break;
+	case MIIM_LXT971_SR2_100HDX:
+		mii_info->speed = SPEED_100;
+		mii_info->duplex = DUPLEX_HALF;
+		break;
+	default:
+		mii_info->speed = SPEED_100;
+		mii_info->duplex = DUPLEX_FULL;
+	}
+
+	return 0;
+}
+
+static int lxt971_startup(struct mii_info *mii_info)
+{
+	genphy_update_link(mii_info);
+	lxt971_parse_status(mii_info);
+
+	return 0;
+}
+
 /* Marvell 88E1011S */
 static int m88e1011s_config(struct mii_info *mii_info)
 {
@@ -747,7 +952,86 @@ static int vsc8211_startup(struct mii_info *mii_info)
 
 	return 0;
 }
- 
+
+/* RealTek RTL8211B */
+static int rtl8211b_config(struct mii_info *mii_info)
+{
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+	tsec_phy_write(mii_info, 0, MII_CTRL1000, MII_CTRL1000_INIT);
+	tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+	tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+	tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+	return 0;
+}
+
+static int rtl8211b_parse_status(struct mii_info *mii_info)
+{
+	unsigned int speed;
+	unsigned int mii_reg;
+
+	mii_reg = tsec_phy_read(mii_info, 0, MIIM_RTL8211B_PHY_STATUS);
+
+	if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
+		int i = 0;
+
+		/* in case of timeout ->link is cleared */
+		mii_info->link = 1;
+		puts("Waiting for PHY realtime link");
+		while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) {
+			/* Timeout reached ? */
+			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
+				puts(" TIMEOUT !\n");
+				mii_info->link = 0;
+				break;
+			}
+
+			if ((i++ % 1000) == 0) {
+				putc('.');
+			}
+			udelay(1000);	/* 1 ms */
+			mii_reg = tsec_phy_read(mii_info, 0,
+					MIIM_RTL8211B_PHY_STATUS);
+		}
+		puts(" done\n");
+		udelay(500000);	/* another 500 ms (results in faster booting) */
+	} else {
+		if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK)
+			mii_info->link = 1;
+		else
+			mii_info->link = 0;
+	}
+
+	if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX)
+		mii_info->duplex = DUPLEX_FULL;
+	else
+		mii_info->duplex = DUPLEX_HALF;
+
+	speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED);
+
+	switch (speed) {
+	case MIIM_RTL8211B_PHYSTAT_GBIT:
+		mii_info->speed = SPEED_1000;
+		break;
+	case MIIM_RTL8211B_PHYSTAT_100:
+		mii_info->speed = SPEED_100;
+		break;
+	default:
+		mii_info->speed = SPEED_10;
+	}
+
+	return 0;
+}
+
+static int rtl8211b_startup(struct mii_info *mii_info)
+{
+	/* Read the Status (2x to make sure link is right) */
+	genphy_update_link(mii_info);
+	rtl8211b_parse_status(mii_info);
+
+	return 0;
+}
+
 /* Vitesse VSC8244 */
 static int vsc8244_parse_status(struct mii_info *mii_info)
 {
@@ -840,6 +1124,60 @@ static struct phy_info phy_info_BCM5482S = {
 	&genphy_shutdown,
 };
 
+static struct phy_info phy_info_CIS8201 = {
+	"CIS8201",
+	0xfc410,
+	0xffff0,
+	&cis8201_config,
+	&cis8201_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_CIS8204 = {
+	"Cicada Cis8204",
+	0xfc440,
+	0xffff0,
+	&cis8204_config,
+	&cis8201_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_DM9161 = {
+	"Davicom DM9161E",
+	0x181b880,
+	0xffffff0,
+	&dm9161_config,
+	&dm9161_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_DP83865 = {
+	"NatSemi DP83865",
+	0x20005c70,
+	0xfffffff0,
+	&dp83865_config,
+	&dp83865_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_KSZ804 = {
+	"Micrel KSZ804",
+	0x221510,
+	0xfffff0,
+	&genphy_config,
+	&genphy_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_LXT971 = {
+	"LXT971",
+	0x1378e0,
+	0xfffff0,
+	&genphy_config,
+	&lxt971_startup,
+	&genphy_shutdown,
+};
+
 static struct phy_info phy_info_M88E1011S = {
 	"Marvell 88E1011S",
 	0x1410c60,
@@ -894,6 +1232,15 @@ static struct phy_info phy_info_M88E1149S = {
 	&genphy_shutdown,
 };
 
+static struct phy_info phy_info_RTL8211B = {
+	"RealTek RTL8211B",
+	0x1cc910,
+	0xfffff0,
+	&rtl8211b_config,
+	&rtl8211b_startup,
+	&genphy_shutdown,
+};
+
 static struct phy_info phy_info_VSC8211 = {
 	"Vitesse VSC8211",
 	0xfc4b0,
@@ -961,12 +1308,19 @@ static struct phy_info *phy_info[] = {
 	&phy_info_BCM5461S,
 	&phy_info_BCM5464S,
 	&phy_info_BCM5482S,
+	&phy_info_CIS8201,
+	&phy_info_CIS8204,
+	&phy_info_DM9161,
+	&phy_info_DP83865,
+	&phy_info_KSZ804,
+	&phy_info_LXT971,
 	&phy_info_M88E1011S,
 	&phy_info_M88E1111S,
 	&phy_info_M88E1118,
 	&phy_info_M88E1121R,
 	&phy_info_M88E1145,
 	&phy_info_M88E1149S,
+	&phy_info_RTL8211B,
 	&phy_info_VSC8211,
 	&phy_info_VSC8221,
 	&phy_info_VSC8244,
drivers/net/fsl_phy.h +57 -0

69 lines not on this page · raw message

drivers/net/tsec.c +24 -0
index 6ed3e09..fd8829d 100644
@@ -190,6 +190,30 @@ tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set)
 }
 #endif /* Multicast TFTP ? */
 
+/*
+ * Hack to write all 4 PHYs with the LED values
+ */
+int cis8204_fixled(struct mii_info *mii_info)
+{
+	uint phyid;
+	tsec_mii_t *regbase = mii_info->phyregs;
+	int timeout = 1000000;
+
+	for (phyid = 0; phyid < 4; phyid++) {
+		out_be32(&regbase->miimadd, (phyid << 8) | MIIM_CIS8204_SLED_CON);
+		out_be32(&regbase->miimcon, MIIM_CIS8204_SLEDCON_INIT);
+		asm("sync");
+
+		timeout = 1000000;
+		while ((in_be32(&regbase->miimind) & MIIMIND_BUSY) && timeout--) ;
+	}
+
+	tsec_phy_write(mii_info, 0, MIIM_CIS8204_SLED_CON,
+			MIIM_CIS8204_SLEDCON_INIT);
+
+	return 0;
+}
+
 /* Initialized required registers to appropriate values, zeroing
  * those we don't care about (unless zero is bad, in which case,
  * choose a more appropriate value)
Signature · 1 line
1.6.4
#15 lore raw

PATCH 13/14 PHY: add some Marvell phy support

In reply to Mingkai Hu

Hi Mingkai,

2011/1/27 Mingkai Hu <[email protected]>

Quoted 28 lines

Port from tsec.c file to add support for m88e1011s, m88e1111s, m88e1118, m88e1121r, m88e1145, m88e1149s.

---
 drivers/net/fsl_phy.c |  299
+++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/fsl_phy.h |   36 ++++++
 2 files changed, 335 insertions(+), 0 deletions(-)
drivers/net/fsl_phy.c +10 -0
index 7c22666..ad9d65e 100644
@@ -457,6 +457,245 @@ static int bcm5482_startup(struct mii_info *mii_info)
       return 0;
 }
 
+/* Marvell 88E1011S */
+static int m88e1011s_config(struct mii_info *mii_info)
+{
+       /* Reset and configure the PHY */
+       tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+
+       tsec_phy_write(mii_info, 0, 0x1d, 0x1f);
+       tsec_phy_write(mii_info, 0, 0x1e, 0x200c);
+       tsec_phy_write(mii_info, 0, 0x1d, 0x5);
+       tsec_phy_write(mii_info, 0, 0x1e, 0);

drivers/net/fsl_phy.c static int bcm5482_startup(struct mii_info *mii_info) · line 479

Quoted 10 lines
drivers/net/fsl_phy.c +9 -0
+       tsec_phy_write(mii_info, 0, 0x1e, 0x100);
+       tsec_phy_write(mii_info, 0, MII_CTRL1000, MII_CTRL1000_INIT);
+       tsec_phy_write(mii_info, 0, MII_ADVERTISE, MII_ADVERTISE_INIT);
+
+       tsec_phy_write(mii_info, 0, MII_BMCR, BMCR_RESET);
+       tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+
+       return 0;
+}
 

Is this possible to assign the clear definition about bit fields with phy registers
rather than hard-code hex value?
I think clear definitions will help both other vendor and your customers, whom are the ODM/OEM vendors is easier to debug with these phy chips.

Hope you can agree with this suggestions.

Signature · 2 lines
Best regards,
Macpaul Lin
Applied
#17 lore raw

PATCH 8/14 tsec: arrange the code to avoid useless function declaration

In reply to Mingkai Hu
Quoted 4 lines · Mingkai Hu

---
drivers/net/tsec.c | 857 +++++++++++++++++++++++++---------------------------

1 files changed, 416 insertions(+), 441 deletions(-)

applied to 85xx next

- k

Applied
#19 lore raw

PATCH 7/14 tsec: use IO accessories to access the register

In reply to Mingkai Hu
Quoted 5 lines · Mingkai Hu

---
drivers/net/tsec.c | 232 ++++++++++++++++++++++++++-------------------------
include/tsec.h | 6 +-

2 files changed, 121 insertions(+), 117 deletions(-)

applied to 85xx next

- k

#20 lore raw

PATCH 6/14 powerpc/corenet_ds: Add fman support

In reply to Mingkai Hu

board/freescale/corenet_ds/eth_p4080.c line 186

Quoted 8 lines · Mingkai Hu
board/freescale/corenet_ds/eth_p4080.c new file +8 -0
+enum board_slots {
+	SLOT1 = 1,
+	SLOT2,
+	SLOT3,
+	SLOT4,
+	SLOT5,
+	SLOT6,
+};

This is silly. SLOT1 == 1, SLOT2 == 2, etc. Just delete this enum and use numbers.

Signature · 2 lines
Timur Tabi
Linux kernel developer at Freescale
#21 lore raw

PATCH 5/14 powerpc/qoirq: Add support for FMan ethernet in Independent mode

In reply to Mingkai Hu
Quoted 1 line · Mingkai Hu

+LIB := $(obj)libfm.a

Libraries are now .o files, not .a files. Take a look at the other Makefiles to see how they've recently changed.

Quoted 7 lines
drivers/net/fm/fm.c new file +7 -0
+u32 fm_muram_alloc(struct fm_muram *mem, u32 size, u32 align)
+{
+	u32 ret;
+	u32 align_mask, off;
+	u32 save;
+
+	align_mask = align - 1;

drivers/net/fm/fm.c line 176

Quoted 10 lines
drivers/net/fm/fm.c new file +10 -0
+	save = mem->alloc;
+
+	if ((off = (save & align_mask)) != 0)
+		mem->alloc += (align - off);
+	if ((off = size & align_mask) != 0)
+		size += (align - off);
+	if ((mem->alloc + size) >= mem->top) {
+		mem->alloc = save;
+		printf("%s: run out of ram.\n", __func__);
+	}

What exactly happens here? If you run out of memory, you return a pointer anyway? Shouldn't you return NULL here or something?

drivers/net/fm/fm.c line 455

Quoted 10 lines
drivers/net/fm/fm.c new file +10 -0
+	/* Loop through each microcode. */
+	for (i = 0; i < firmware->count; i++) {
+		const struct qe_microcode *ucode = &firmware->microcode[i];
+
+		/* Upload a microcode if it's present */
+		if (ucode->code_offset) {
+			printf("Fman: Uploading microcode version %u.%u.%u.\n",
+			       ucode->major, ucode->minor, ucode->revision);
+			fm->ucode = (void *) CONFIG_SYS_FMAN_FW_ADDR +
+				ucode->code_offset;

Just FYI, this code will only work on systems that have NOR flash mapped to I/O space. If the customer boots from NAND and doesn't have any NOR flash on his board, then CONFIG_SYS_FMAN_FW_ADDR will be invalid. In addition, I don't see any code that passes the value of CONFIG_SYS_FMAN_FW_ADDR to the kernel via "fman_ucode".

drivers/net/fm/fm_eth.c line 752

Quoted 5 lines
drivers/net/fm/fm_eth.c new file +5 -0
+	/* setup TxBD */
+	txbd->buf_ptr_hi = 0;
+	txbd->buf_ptr_lo = (u32)buf;
+	txbd->len = len;
+	__asm__ __volatile__ ("sync");

Why do we sometimes do "asm("sync");" and sometimes we do "__asm__ __volatile__ ("sync");"? And why do we have hard-coded asm anyway? There is a sync() function that does this already.

Quoted 9 lines
drivers/net/fm/fm_eth.c new file +9 -0
+	txbd->status = TxBD_READY | TxBD_LAST;
+	__asm__ __volatile__ ("sync");
+
+	/* update TxQD, let RISC to send the packet */
+	offset_in = muram_readw(&pram->txqd.offset_in);
+	offset_in += SIZEOFBD;
+	if (offset_in >= muram_readw(&pram->txqd.bd_ring_size))
+		offset_in = 0;
+	muram_writew(&pram->txqd.offset_in, offset_in);

drivers/net/fm/fm_eth.c line 771

Quoted 10 lines
drivers/net/fm/fm_eth.c new file +10 -0
+	__asm__ __volatile__ ("sync");
+
+	/* wait for buffer to be transmitted */
+	for (i = 0; txbd->status & TxBD_READY; i++) {
+		udelay(1000);
+		if (i > 0x10000) {
+			printf("%s: Tx error\n", dev->name);
+			return 0;
+		}
+	}

If you're going to do a timeout, do it the same way everyone else does. Start with the timeout value, and decrement the variable. Something like this:

	timeout = 0x10000; (why a hex number anyway?)
	while (!(txbd->status & TxBD_READY) && --timeout)
		udelay(1000);

drivers/net/fm/fm_eth.c line 1188

Quoted 5 lines
drivers/net/fm/fm_eth.c new file +5 -0
+static void
+__def_board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
+				enum fm_port port, int offset)
+{
+	return ;

Delete this "return ;". It doesn't do anything.

Signature · 2 lines
Timur Tabi
Linux kernel developer at Freescale
#22 lore raw

PATCH 2/14 powerpc/fman: add PHY support for dTSEC

In reply to Mingkai Hu
Quoted 7 lines · Mingkai Hu

From: Kumar Gala <[email protected]>

Add VSC8244 and VSC8234 phy support, this will be reused by etsec code.

Quoted 8 lines

---

arch/powerpc/include/asm/fsl_enet.h |   10 +
drivers/net/fsl_phy.c               |  353 +++++++++++++++++++++++++++++++++++
drivers/net/fsl_phy.h               |  176 +++++++++++++++++
3 files changed, 539 insertions(+), 0 deletions(-)

create mode 100644 drivers/net/fsl_phy.c
create mode 100644 drivers/net/fsl_phy.h

General question should we use DTSEC name to match p4080 manual for this ?

arch/powerpc/include/asm/fsl_enet.h enum fsl_phy_enet_if { · line 31

Quoted 9 lines
arch/powerpc/include/asm/fsl_enet.h +1 -0
index 4fb2857..9475249 100644
@@ -28,6 +28,16 @@ enum fsl_phy_enet_if {
 	FSL_ETH_IF_NONE,
 };
 
+typedef struct tsec_mii_mng {

Wondering if we should use dtsec_ here since that matches P4080 Manual and possible removes some confusion with tsec enet controller.

Quoted 393 lines
arch/powerpc/include/asm/fsl_enet.h +9 -0
+	u32 miimcfg;		/* MII management configuration reg */
+	u32 miimcom;		/* MII management command reg */
+	u32 miimadd;		/* MII management address reg */
+	u32 miimcon;		/* MII management control reg */
+	u32 miimstat;		/* MII management status reg  */
+	u32 miimind;		/* MII management indication reg */
+	u32 ifstat;		/* Interface Status Register */
+} __attribute__ ((packed))tsec_mii_t;
+
 int fdt_fixup_phy_connection(void *blob, int offset, enum fsl_phy_enet_if phyc);
 
 #endif /* __ASM_PPC_FSL_ENET_H */
drivers/net/fsl_phy.c new file +353 -0
new file mode 100644
index 0000000..1ba0ce1
@@ -0,0 +1,353 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *	Jun-jie Zhang <[email protected]>
+ *	Mingkai Hu <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+
+#include "fsl_phy.h"
+
+void tsec_local_mdio_write(tsec_mii_t *phyregs, int port_addr,
+		int dev_addr, int regnum, int value)
+{
+	int timeout = 1000000;
+
+	out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
+	out_be32(&phyregs->miimcon, value);
+	asm("sync");
+
+	while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--);
+}
+
+int tsec_local_mdio_read(tsec_mii_t *phyregs, int port_addr,
+		int dev_addr, int regnum)
+{
+	int value;
+	int timeout = 1000000;
+
+	/* Put the address of the phy, and the register
+	 * number into MIIMADD */
+	out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
+
+	/* Clear the command register, and wait */
+	out_be32(&phyregs->miimcom, 0);
+	asm("sync");
+
+	/* Initiate a read command, and wait */
+	out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE);
+	asm("sync");
+
+	/* Wait for the the indication that the read is done */
+	while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
+			&& timeout--);
+
+	/* Grab the value read from the PHY */
+	value = in_be32(&phyregs->miimstat);
+
+	return value;
+}
+
+int tsec_phy_read(struct mii_info *mii_info, int dev_addr, int regnum)
+{
+	tsec_mii_t *phyregs = mii_info->phyregs;
+
+	return tsec_local_mdio_read(phyregs, mii_info->mii_id, dev_addr,
+			regnum);
+}
+
+int tsec_phy_write(struct mii_info *mii_info, int dev_addr, int regnum,
+			int value)
+{
+	tsec_mii_t *phyregs = mii_info->phyregs;
+
+	tsec_local_mdio_write(phyregs, mii_info->mii_id, dev_addr, regnum,
+		value);
+
+	return 0;
+}
+
+static int genphy_config(struct mii_info *mii_info)
+{
+	return tsec_phy_write(mii_info, 0, MII_BMCR, MII_BMCR_INIT);
+}
+
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Update the value in phydev->link to reflect the
+ *   current link value.  In order to do this, we need to read
+ *   the status register twice, keeping the second value.
+ */
+static int genphy_update_link(struct mii_info *phydev)
+{
+	unsigned int mii_reg;
+
+	/*
+	 * Wait if the link is up, and autonegotiation is in progress
+	 * (ie - we're capable and it's not done)
+	 */
+	mii_reg = tsec_phy_read(phydev, 0, MII_BMSR);
+
+	/*
+	 * If we already saw the link up, and it hasn't gone down, then
+	 * we don't need to wait for autoneg again
+	 */
+	if (phydev->link && mii_reg & BMSR_LSTATUS)
+		return 0;
+
+	if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+		int i = 0;
+
+		printf("%s Waiting for PHY auto negotiation to complete",
+			phydev->dev->name);
+		while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
+			/*
+			 * Timeout reached ?
+			 */
+			if (i > 5000) {
+				printf(" TIMEOUT !\n");
+				phydev->link = 0;
+				return 0;
+			}
+
+			if (ctrlc()) {
+				puts("user interrupt!\n");
+				phydev->link = 0;
+				return -EINTR;
+			}
+
+			if ((i++ % 500) == 0)
+				printf(".");
+
+			udelay(1000);	/* 1 ms */
+			mii_reg = tsec_phy_read(phydev, 0, MII_BMSR);
+		}
+		printf(" done\n");
+		phydev->link = 1;
+		udelay(500000);	/* another 500 ms (results in faster booting) */
+	} else {
+		/* Read the link a second time to clear the latched state */
+		mii_reg = tsec_phy_read(phydev, 0, MII_BMSR);
+
+		if (mii_reg & BMSR_LSTATUS)
+			phydev->link = 1;
+		else
+			phydev->link = 0;
+	}
+
+	return 0;
+}
+
+/*
+ * Generic function which updates the speed and duplex.  If
+ * autonegotiation is enabled, it uses the AND of the link
+ * partner's advertised capabilities and our advertised
+ * capabilities.  If autonegotiation is disabled, we use the
+ * appropriate bits in the control register.
+ *
+ * Stolen from Linux's mii.c and phy_device.c
+ */
+static int genphy_parse_link(struct mii_info *phydev)
+{
+	int mii_reg = tsec_phy_read(phydev, 0, MII_BMSR);
+
+	/* We're using autonegotiation */
+	if (mii_reg & BMSR_ANEGCAPABLE) {
+		u32 lpa = 0;
+		u32 gblpa = 0;
+
+		/* Check for gigabit capability */
+		if (mii_reg & BMSR_ERCAP) {
+			/* We want a list of states supported by
+			 * both PHYs in the link
+			 */
+			gblpa = tsec_phy_read(phydev, 0, MII_STAT1000);
+			gblpa &= tsec_phy_read(phydev, 0, MII_CTRL1000) << 2;
+		}
+
+		/* Set the baseline so we only have to set them
+		 * if they're different
+		 */
+		phydev->speed = SPEED_10;
+		phydev->duplex = DUPLEX_HALF;
+
+		/* Check the gigabit fields */
+		if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
+			phydev->speed = SPEED_1000;
+
+			if (gblpa & PHY_1000BTSR_1000FD)
+				phydev->duplex = DUPLEX_FULL;
+
+			/* We're done! */
+			return 0;
+		}
+
+		lpa = tsec_phy_read(phydev, 0, MII_ADVERTISE);
+		lpa &= tsec_phy_read(phydev, 0, MII_LPA);
+
+		if (lpa & (LPA_100FULL | LPA_100HALF)) {
+			phydev->speed = SPEED_100;
+
+			if (lpa & LPA_100FULL)
+				phydev->duplex = DUPLEX_FULL;
+
+		} else if (lpa & LPA_10FULL)
+			phydev->duplex = DUPLEX_FULL;
+	} else {
+		u32 bmcr = tsec_phy_read(phydev, 0, MII_BMCR);
+
+		phydev->speed = SPEED_10;
+		phydev->duplex = DUPLEX_HALF;
+
+		if (bmcr & BMCR_FULLDPLX)
+			phydev->duplex = DUPLEX_FULL;
+
+		if (bmcr & BMCR_SPEED1000)
+			phydev->speed = SPEED_1000;
+		else if (bmcr & BMCR_SPEED100)
+			phydev->speed = SPEED_100;
+	}
+
+	return 0;
+}
+
+static int genphy_startup(struct mii_info *phydev)
+{
+	genphy_update_link(phydev);
+	genphy_parse_link(phydev);
+
+	return 0;
+}
+
+static int genphy_shutdown(struct mii_info *phydev)
+{
+	return 0;
+}
+
+/* Vitesse VSC8244 */
+static int vsc8244_parse_status(struct mii_info *mii_info)
+{
+	unsigned int speed;
+	unsigned int mii_reg;
+
+	mii_reg = tsec_phy_read(mii_info, 0, MIIM_VSC8244_AUX_CONSTAT);
+
+	if (mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX)
+		mii_info->duplex = DUPLEX_FULL;
+	else
+		mii_info->duplex = DUPLEX_HALF;
+
+	speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED;
+	switch (speed) {
+	case MIIM_VSC8244_AUXCONSTAT_GBIT:
+		mii_info->speed = SPEED_1000;
+		break;
+	case MIIM_VSC8244_AUXCONSTAT_100:
+		mii_info->speed = SPEED_100;
+		break;
+	default:
+		mii_info->speed = SPEED_10;
+		break;
+	}
+
+	return 0;
+}
+
+static int vsc8244_startup(struct mii_info *mii_info)
+{
+	/* Read the Status (2x to make sure link is right) */
+	genphy_update_link(mii_info);
+	vsc8244_parse_status(mii_info);
+
+	return 0;
+}
+
+static struct phy_info phy_info_VSC8244 = {
+	"Vitesse VSC8244",
+	0xfc6c0,
+	0xffff0,
+	&genphy_config,
+	&vsc8244_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_VSC8234 = {
+	"Vitesse VSC8234",
+	0xfc620,
+	0xffff0,
+	&genphy_config,
+	&vsc8244_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info phy_info_generic = {
+	"Unknown/Generic PHY",
+	0x0,
+	0x0,
+	&genphy_config,
+	&genphy_startup,
+	&genphy_shutdown,
+};
+
+static struct phy_info *phy_info[] = {
+	&phy_info_VSC8244,
+	&phy_info_VSC8234,
+	&phy_info_generic
+};
+
+/*
+ * Use the PHY ID registers to determine what type of PHY is attached
+ * to device dev.  return a struct phy_info structure describing that PHY
+ */
+struct phy_info *tsec_get_phy_info(struct mii_info *mii_info)
+{
+	u16 phy_reg;
+	u32 phy_ID;
+	int i;
+	struct phy_info *theInfo = NULL;
+
+	/* Grab the bits from PHYIR1, and put them in the upper half */
+	phy_reg = tsec_phy_read(mii_info, 0, MII_PHYSID1);
+	phy_ID = (phy_reg & 0xffff) << 16;
+
+	/* Grab the bits from PHYIR2, and put them in the lower half */
+	phy_reg = tsec_phy_read(mii_info, 0, MII_PHYSID2);
+	phy_ID |= (phy_reg & 0xffff);
+
+	/* loop through all the known PHY types, and find one that */
+	/* matches the ID we read from the PHY. */
+	for (i = 0; i < ARRAY_SIZE(phy_info); i++)
+		if ((phy_info[i]->uid & phy_info[i]->mask) ==
+				(phy_ID & phy_info[i]->mask)) {
+			theInfo = phy_info[i];
+			break;
+		}
+
+	if (theInfo == &phy_info_generic) {
+		printf("%s: No support for PHY id %x; assuming generic\n",
+				mii_info->dev->name, phy_ID);
+	} else {
+		printf("%s: PHY is %s (%x)\n", mii_info->dev->name,
+				theInfo->name, phy_ID);
+	}
+
+	return theInfo;
+}
drivers/net/fsl_phy.h new file +16 -0
new file mode 100644
index 0000000..8a8b6e8
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *	Jun-jie Zhang <[email protected]>
+ *	Mingkai Hu <[email protected]>
+ *
+ * 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

drivers/net/fsl_phy.h line 26

Quoted 10 lines
drivers/net/fsl_phy.h new file +10 -0
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __FSL_PHY_H__
+#define __FSL_PHY_H__
+
+#include <net.h>
+#include <miiphy.h>
+#include <asm/fsl_enet.h>

We need to utilize <linux/mii.h>

Quoted 153 lines
drivers/net/fsl_phy.h new file +150 -0
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF		0x00
+#define DUPLEX_FULL		0x01
+
+#define PORT_TP		0x00
+#define PORT_AUI	0x01
+#define PORT_MII	0x02
+#define PORT_FIBRE	0x03
+
+#define MII_BMCR_INIT           0x00001140
+
+/* MII Management Configuration Register */
+#define MIIMCFG_RESET_MGMT          0x80000000
+#define MIIMCFG_MGMT_CLOCK_SELECT   0x00000007
+#define MIIMCFG_INIT_VALUE	    0x00000003
+
+/* MII Management Command Register */
+#define MIIMCOM_READ_CYCLE	0x00000001
+#define MIIMCOM_SCAN_CYCLE	0x00000002
+
+/* MII Management Address Register */
+#define MIIMADD_PHY_ADDR_SHIFT	8
+
+/* MII Management Indicator Register */
+#define MIIMIND_BUSY		0x00000001
+#define MIIMIND_NOTVALID	0x00000004
+
+#define AUTONEG_DISABLE		0x00
+#define AUTONEG_ENABLE		0x01
+#define SPEED_10		10
+#define SPEED_100		100
+#define SPEED_1000		1000
+#define SPEED_2500		2500
+#define SPEED_10000		10000
+#define SUPPORTED_10baseT_Half		(1 << 0)
+#define SUPPORTED_10baseT_Full		(1 << 1)
+#define SUPPORTED_100baseT_Half		(1 << 2)
+#define SUPPORTED_100baseT_Full		(1 << 3)
+#define SUPPORTED_1000baseT_Half	(1 << 4)
+#define SUPPORTED_1000baseT_Full	(1 << 5)
+#define SUPPORTED_Autoneg		(1 << 6)
+#define SUPPORTED_TP			(1 << 7)
+#define SUPPORTED_AUI			(1 << 8)
+#define SUPPORTED_MII			(1 << 9)
+#define SUPPORTED_FIBRE			(1 << 10)
+#define SUPPORTED_BNC			(1 << 11)
+#define SUPPORTED_10000baseT_Full	(1 << 12)
+#define SUPPORTED_Pause			(1 << 13)
+#define SUPPORTED_Asym_Pause		(1 << 14)
+#define SUPPORTED_2500baseX_Full	(1 << 15)
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half		(1 << 0)
+#define ADVERTISED_10baseT_Full		(1 << 1)
+#define ADVERTISED_100baseT_Half	(1 << 2)
+#define ADVERTISED_100baseT_Full	(1 << 3)
+#define ADVERTISED_1000baseT_Half	(1 << 4)
+#define ADVERTISED_1000baseT_Full	(1 << 5)
+#define ADVERTISED_Autoneg		(1 << 6)
+#define ADVERTISED_TP			(1 << 7)
+#define ADVERTISED_AUI			(1 << 8)
+#define ADVERTISED_MII			(1 << 9)
+#define ADVERTISED_FIBRE		(1 << 10)
+#define ADVERTISED_BNC			(1 << 11)
+#define ADVERTISED_10000baseT_Full	(1 << 12)
+#define ADVERTISED_Pause		(1 << 13)
+#define ADVERTISED_Asym_Pause		(1 << 14)
+#define ADVERTISED_2500baseX_Full	(1 << 15)
+
+#define PHY_AUTONEGOTIATE_TIMEOUT	5000 /* in ms */
+
+/* Entry for Vitesse VSC8244 regs starts here */
+/* Vitesse VSC8244 Auxiliary Control/Status Register */
+#define MIIM_VSC8244_AUX_CONSTAT	0x1c
+#define MIIM_VSC8244_AUXCONSTAT_INIT	0x0000
+#define MIIM_VSC8244_AUXCONSTAT_DUPLEX	0x0020
+#define MIIM_VSC8244_AUXCONSTAT_SPEED	0x0018
+#define MIIM_VSC8244_AUXCONSTAT_GBIT	0x0010
+#define MIIM_VSC8244_AUXCONSTAT_100	0x0008
+#define MIIM_CONTROL_INIT_LOOPBACK	0x4000
+
+struct mii_info {
+	/* Information about the PHY type */
+	/* And management functions */
+	struct phy_info *phyinfo;
+	void *phyregs;
+
+	struct eth_device *dev;
+
+	/* forced speed & duplex (no autoneg)
+	 * partner speed & duplex & pause (autoneg)
+	 */
+	int speed;
+	int duplex;
+
+	/* The most recently read link state */
+	int link;
+	int port;
+
+	u32 advertising;
+	int autoneg;
+	int mii_id;
+	u32 flags;
+
+	/* private data pointer */
+	/* For use by PHYs to maintain extra state */
+	void *priv;
+
+	/* Provided by ethernet driver */
+	int (*mdio_read)(struct eth_device *dev, int mii_id, int reg);
+	void (*mdio_write)(struct eth_device *dev, int mii_id, int reg,
+			    int val);
+};
+
+/* struct phy_info: a structure which defines attributes for a PHY
+ *
+ * id will contain a number which represents the PHY.  During
+ * startup, the driver will poll the PHY to find out what its
+ * UID--as defined by registers 2 and 3--is.  The 32-bit result
+ * gotten from the PHY will be masked to
+ * discard any bits which may change based on revision numbers
+ * unimportant to functionality
+ *
+ */
+struct phy_info {
+	char *name;
+	unsigned int uid;
+	unsigned int mask;
+	/* Called to configure the PHY, and modify the controller
+	 * based on the results */
+	int (*config)(struct mii_info *mii_info);
+
+	/* Called when starting up the controller */
+	int (*startup)(struct mii_info *mii_info);
+
+	/* Called when bringing down the controller */
+	int (*shutdown)(struct mii_info *mii_info);
+};
+
+struct phy_info *tsec_get_phy_info(struct mii_info *mii_info);
+void tsec_local_mdio_write(tsec_mii_t *phyregs, int port_addr, int dev_addr,
+		int reg, int value);
+int tsec_local_mdio_read(tsec_mii_t *phyregs, int port_addr, int dev_addr,
+		int regnum);
+int tsec_phy_read(struct mii_info *mii_info, int dev_addr, int regnum);
+int tsec_phy_write(struct mii_info *mii_info, int dev_addr, int regnum,
+		int value);
+#endif /* __FSL_PHY_H__ */
+
Signature · 1 line
1.6.4
#23 lore raw

PATCH 2/14 powerpc/fman: add PHY support for dTSEC

In reply to Mingkai Hu

drivers/net/fsl_phy.c line 333

Quoted 12 lines · Mingkai Hu
drivers/net/fsl_phy.c new file +12 -0
+	u16 phy_reg;
+	u32 phy_ID;
+	int i;
+	struct phy_info *theInfo = NULL;
+
+	/* Grab the bits from PHYIR1, and put them in the upper half */
+	phy_reg = tsec_phy_read(mii_info, 0, MII_PHYSID1);
+	phy_ID = (phy_reg & 0xffff) << 16;
+
+	/* Grab the bits from PHYIR2, and put them in the lower half */
+	phy_reg = tsec_phy_read(mii_info, 0, MII_PHYSID2);
+	phy_ID |= (phy_reg & 0xffff);

The "& 0xffff" is unnecessary since phy_reg is a u16, so it can never be larger than 0xffff.

drivers/net/fsl_phy.c line 340

Quoted 1 line
drivers/net/fsl_phy.c new file +1 -0
+			theInfo = phy_info[i];

CamelCase variables?

Quoted 1 line

+ * Copyright 2009-2010 Freescale Semiconductor, Inc.

Should any of these be 2011?

Signature · 2 lines
Timur Tabi
Linux kernel developer at Freescale
#24 lore raw

cover powerpc/p4080: add support for FMan ethernet in Independent mode

In reply to Mingkai Hu
Quoted 28 lines · Mingkai Hu

This patchset add support for the P4080's datapath accelation architecture in independent mode, and do some code refactor of the file tsec.c.

1. Add the releated MAC controller support, includeing dTSEC and 10GEC
2. Add support for FMan ethernet in Independent mode
3. Add PHY support (VSC8244 and VSC8234) to a new file fsl_phy.c which can be reused by other code, such tsec and uec code.
4. tsec code cleanup
5. Move all the PHY code in tsec.c to fsl_phy.c to make it reuseable.

Based on the latest WD's U-Boot tree. Tested on P4080DS and MPC8536DS board with SGMII card.

[PATCH 01/14] powerpc/p4080: Add function to report which lane is used for a prtcl [PATCH 02/14] powerpc/fman: add PHY support for dTSEC
[PATCH 03/14] powerpc/fman: add dTSEC controller support
[PATCH 04/14] powerpc/fman: add 10GEC controller and PHY support [PATCH 05/14] powerpc/qoirq: Add support for FMan ethernet in Independent mode [PATCH 06/14] powerpc/corenet_ds: Add fman support
[PATCH 07/14] tsec: use IO accessories to access the register
[PATCH 08/14] tsec: arrange the code to avoid useless function declaration [PATCH 09/14] tsec: use general ethernet MII register struct(tsec_mii_t) [PATCH 10/14] tsec: refactor the PHY code to make it reuseable
[PATCH 11/14] PHY: add some Vitesse phy support
[PATCH 12/14] PHY: add some Broadcom phy support
[PATCH 13/14] PHY: add some Marvell phy support
[PATCH 14/14] PHY: add some misc phy code support

Quoted 2 lines

Thanks,
Mingkai

I suggest we re-order these patches to first deal with tsec changes and refactor of the phy code. After which we should introduce fman driver code that shares fsl_phy.c

These patches also break some fundamental rules about patches:
1. some patches aren't used by anything
2. some patches break functionality

- k

#25 lore raw

cover powerpc/p4080: add support for FMan ethernet in Independent mode

Quoted 45 lines

-----Original Message-----
From: Kumar Gala [mailto:galak at kernel.crashing.org]
Sent: Thursday, January 27, 2011 2:05 PM
To: Hu Mingkai-B21284
Cc: u-boot at lists.denx.de; Fleming Andy-AFLEMING; Zang Roy-R61911; Liu Dave- R63238; Medve Emilian-EMMEDVE1; Tabi Timur-B04825; Phillips Kim-R1AAHA; Haruki Dai-R35557; Radulescu Ruxandra Ioana-B05472
Subject: Re: [PATCH 00/14] powerpc/p4080: add support for FMan ethernet in Independent mode

Quoted 27 lines · Mingkai Hu

This patchset add support for the P4080's datapath accelation architecture in independent mode, and do some code refactor of the file tsec.c.

1. Add the releated MAC controller support, includeing dTSEC and 10GEC
2. Add support for FMan ethernet in Independent mode 3. Add PHY support (VSC8244 and VSC8234) to a new file fsl_phy.c which can be reused by other code, such tsec and uec code.
4. tsec code cleanup
5. Move all the PHY code in tsec.c to fsl_phy.c to make it reuseable.

Based on the latest WD's U-Boot tree. Tested on P4080DS and MPC8536DS board with SGMII card.

[PATCH 01/14] powerpc/p4080: Add function to report which lane is used for a prtcl [PATCH 02/14] powerpc/fman: add PHY support for dTSEC [PATCH 03/14] powerpc/fman: add dTSEC controller support [PATCH 04/14] powerpc/fman: add 10GEC controller and PHY support [PATCH 05/14] powerpc/qoirq: Add support for FMan ethernet in Independent mode [PATCH 06/14] powerpc/corenet_ds: Add fman support [PATCH 07/14] tsec:
use IO accessories to access the register [PATCH 08/14] tsec: arrange the code to avoid useless function declaration [PATCH 09/14] tsec: use general ethernet MII register struct(tsec_mii_t) [PATCH 10/14] tsec:
refactor the PHY code to make it reuseable [PATCH 11/14] PHY: add some Vitesse phy support [PATCH 12/14] PHY: add some Broadcom phy support [PATCH 13/14] PHY: add some Marvell phy support [PATCH 14/14] PHY: add some misc phy code support

Quoted 2 lines

Thanks,
Mingkai

Quoted 8 lines

I suggest we re-order these patches to first deal with tsec changes and refactor of the phy code. After which we should introduce fman driver code that shares fsl_phy.c

These patches also break some fundamental rules about patches:
1. some patches aren't used by anything
2. some patches break functionality

OK, I'll reorder the patchset and take care of the above rules in the next version. Thanks for your comments.

Thanks,
Mingkai