Browse Source

Merge branch 'master' of git://git.denx.de/u-boot-net

Tom Rini 8 years ago
parent
commit
82d72a1b99

+ 6 - 10
arch/arm/cpu/armv7/ls102xa/fdt.c

@@ -30,17 +30,13 @@ void ft_fixup_enet_phy_connect_type(void *fdt)
 	int phy_node;
 	int i = 0;
 	uint32_t ph;
+	char *name[3] = { "eTSEC1", "eTSEC2", "eTSEC3" };
 
-	while ((dev = eth_get_dev_by_index(i++)) != NULL) {
-		if (strstr(dev->name, "eTSEC1")) {
-			strcpy(enet, "ethernet0");
-			strcpy(phy, "enet0_rgmii_phy");
-		} else if (strstr(dev->name, "eTSEC2")) {
-			strcpy(enet, "ethernet1");
-			strcpy(phy, "enet1_rgmii_phy");
-		} else if (strstr(dev->name, "eTSEC3")) {
-			strcpy(enet, "ethernet2");
-			strcpy(phy, "enet2_rgmii_phy");
+	for (; i < ARRAY_SIZE(name); i++) {
+		dev = eth_get_dev_by_name(name[i]);
+		if (dev) {
+			sprintf(enet, "ethernet%d", i);
+			sprintf(phy, "enet%d_rgmii_phy", i);
 		} else {
 			continue;
 		}

+ 2 - 2
board/freescale/bsc9132qds/bsc9132qds.c

@@ -227,9 +227,9 @@ int checkboard(void)
 	return 0;
 }
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
 	struct fsl_pq_mdio_info mdio_info;
 	struct tsec_info_struct tsec_info[4];
 	int num = 0;
@@ -250,6 +250,7 @@ int board_eth_init(bd_t *bis)
 
 	fsl_pq_mdio_init(bis, &mdio_info);
 	tsec_eth_init(bis, tsec_info, num);
+#endif
 
 	#ifdef CONFIG_PCI
 	pci_eth_init(bis);
@@ -257,7 +258,6 @@ int board_eth_init(bd_t *bis)
 
 	return 0;
 }
-#endif
 
 #define USBMUX_SEL_MASK		0xc0
 #define USBMUX_SEL_UART2	0xc0

+ 2 - 2
board/freescale/c29xpcie/c29xpcie.c

@@ -83,9 +83,9 @@ void pci_init_board(void)
 }
 #endif /* ifdef CONFIG_PCI */
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
 	struct fsl_pq_mdio_info mdio_info;
 	struct tsec_info_struct tsec_info[2];
 	int num = 0;
@@ -110,10 +110,10 @@ int board_eth_init(bd_t *bis)
 	fsl_pq_mdio_init(bis, &mdio_info);
 
 	tsec_eth_init(bis, tsec_info, num);
+#endif
 
 	return pci_eth_init(bis);
 }
-#endif
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 void fdt_del_sec(void *blob, int offset)

+ 2 - 2
board/freescale/ls1021atwr/ls1021atwr.c

@@ -244,9 +244,9 @@ int board_mmc_init(bd_t *bis)
 }
 #endif
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
 	struct fsl_pq_mdio_info mdio_info;
 	struct tsec_info_struct tsec_info[4];
 	int num = 0;
@@ -281,10 +281,10 @@ int board_eth_init(bd_t *bis)
 	fsl_pq_mdio_init(bis, &mdio_info);
 
 	tsec_eth_init(bis, tsec_info, num);
+#endif
 
 	return pci_eth_init(bis);
 }
-#endif
 
 #if !defined(CONFIG_QSPI_BOOT) && !defined(CONFIG_SD_BOOT_QSPI)
 int config_serdes_mux(void)

+ 2 - 2
board/freescale/mpc8548cds/mpc8548cds.c

@@ -301,9 +301,9 @@ void configure_rgmii(void)
 	return;
 }
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
 	struct fsl_pq_mdio_info mdio_info;
 	struct tsec_info_struct tsec_info[4];
 	int num = 0;
@@ -345,10 +345,10 @@ int board_eth_init(bd_t *bis)
 
 	tsec_eth_init(bis, tsec_info, num);
 	configure_rgmii();
+#endif
 
 	return pci_eth_init(bis);
 }
-#endif
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 void ft_pci_setup(void *blob, bd_t *bd)

+ 2 - 2
board/freescale/mpc8572ds/mpc8572ds.c

@@ -171,9 +171,9 @@ int board_early_init_r(void)
 	return 0;
 }
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
 	struct fsl_pq_mdio_info mdio_info;
 	struct tsec_info_struct tsec_info[4];
 	int num = 0;
@@ -226,10 +226,10 @@ int board_eth_init(bd_t *bis)
 	fsl_pq_mdio_init(bis, &mdio_info);
 
 	tsec_eth_init(bis, tsec_info, num);
+#endif
 
 	return pci_eth_init(bis);
 }
-#endif
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 int ft_board_setup(void *blob, bd_t *bd)

+ 2 - 2
board/freescale/p1010rdb/p1010rdb.c

@@ -326,9 +326,9 @@ int checkboard(void)
 	return 0;
 }
 
-#ifdef CONFIG_TSEC_ENET
 int board_eth_init(bd_t *bis)
 {
+#ifdef CONFIG_TSEC_ENET
 	struct fsl_pq_mdio_info mdio_info;
 	struct tsec_info_struct tsec_info[4];
 	struct cpu_type *cpu;
@@ -362,10 +362,10 @@ int board_eth_init(bd_t *bis)
 	fsl_pq_mdio_init(bis, &mdio_info);
 
 	tsec_eth_init(bis, tsec_info, num);
+#endif
 
 	return pci_eth_init(bis);
 }
-#endif
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 void fdt_del_flexcan(void *blob)

+ 76 - 2
cmd/ethsw.c

@@ -71,7 +71,7 @@ static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd)
 
 #define ETHSW_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \
 "{ [help] | show | all | none | pvid } " \
-" - set egress tagging mod for a port"
+" - set egress tagging mode for a port"
 
 static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd)
 {
@@ -114,6 +114,17 @@ static int ethsw_ingr_fltr_help_key_func(struct ethsw_command_def *parsed_cmd)
 	return CMD_RET_SUCCESS;
 }
 
+#define ETHSW_PORT_AGGR_HELP "ethsw [port <port_no>] aggr" \
+" { [help] | show | <lag_group_no> } " \
+"- get/set LAG group for a port"
+
+static int ethsw_port_aggr_help_key_func(struct ethsw_command_def *parsed_cmd)
+{
+	printf(ETHSW_PORT_AGGR_HELP"\n");
+
+	return CMD_RET_SUCCESS;
+}
+
 static struct keywords_to_function {
 	enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
 	int cmd_func_offset;
@@ -532,6 +543,39 @@ static struct keywords_to_function {
 			.cmd_func_offset = offsetof(struct ethsw_command_func,
 						    port_ingr_filt_set),
 			.keyword_function = NULL,
+		}, {
+			.cmd_keyword = {
+					ethsw_id_aggr,
+					ethsw_id_key_end,
+			},
+			.cmd_func_offset = -1,
+			.keyword_function = &ethsw_port_aggr_help_key_func,
+		}, {
+			.cmd_keyword = {
+					ethsw_id_aggr,
+					ethsw_id_help,
+					ethsw_id_key_end,
+			},
+			.cmd_func_offset = -1,
+			.keyword_function = &ethsw_port_aggr_help_key_func,
+		}, {
+			.cmd_keyword = {
+					ethsw_id_aggr,
+					ethsw_id_show,
+					ethsw_id_key_end,
+			},
+			.cmd_func_offset = offsetof(struct ethsw_command_func,
+						    port_aggr_show),
+			.keyword_function = NULL,
+		}, {
+			.cmd_keyword = {
+					ethsw_id_aggr,
+					ethsw_id_aggr_no,
+					ethsw_id_key_end,
+			},
+			.cmd_func_offset = offsetof(struct ethsw_command_func,
+						    port_aggr_set),
+			.keyword_function = NULL,
 		},
 };
 
@@ -576,6 +620,9 @@ static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
 static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
 				  char *const argv[], int *argc_nr,
 				  struct ethsw_command_def *parsed_cmd);
+static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
+			      char *const argv[], int *argc_nr,
+			      struct ethsw_command_def *parsed_cmd);
 
 /*
  * Define properties for each keyword;
@@ -661,6 +708,9 @@ struct keyword_def {
 		}, {
 				.keyword_name = "filtering",
 				.match = &keyword_match_gen,
+		}, {
+				.keyword_name = "aggr",
+				.match = &keyword_match_aggr,
 		},
 };
 
@@ -826,6 +876,28 @@ static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
 	return 1;
 }
 
+/* Function used to match the command's aggregation number */
+static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
+			      char *const argv[], int *argc_nr,
+			      struct ethsw_command_def *parsed_cmd)
+{
+	unsigned long val;
+
+	if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
+		return 0;
+
+	if (*argc_nr + 1 >= argc)
+		return 1;
+
+	if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
+		parsed_cmd->aggr_grp = val;
+		(*argc_nr)++;
+		parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_aggr_no;
+	}
+
+	return 1;
+}
+
 /* Finds optional keywords and modifies *argc_va to skip them */
 static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd,
 				   int *argc_val)
@@ -984,6 +1056,7 @@ static void command_def_init(struct ethsw_command_def *parsed_cmd)
 
 	parsed_cmd->port = ETHSW_CMD_PORT_ALL;
 	parsed_cmd->vid = ETHSW_CMD_VLAN_ALL;
+	parsed_cmd->aggr_grp = ETHSW_CMD_AGGR_GRP_NONE;
 	parsed_cmd->cmd_function = NULL;
 
 	/* We initialize the MAC address with the Broadcast address */
@@ -1010,7 +1083,7 @@ static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 
 #define ETHSW_PORT_CONF_HELP "[port <port_no>] { enable | disable | show } " \
-"- enable/disable a port; show shows a port's configuration"
+"- enable/disable a port; show a port's configuration"
 
 U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
 	   "Ethernet l2 switch commands",
@@ -1024,4 +1097,5 @@ U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
 	   ETHSW_EGR_VLAN_TAG_HELP"\n"
 	   ETHSW_VLAN_FDB_HELP"\n"
 	   ETHSW_PORT_INGR_FLTR_HELP"\n"
+	   ETHSW_PORT_AGGR_HELP"\n"
 );

+ 22 - 7
doc/README.t1040-l2switch

@@ -24,16 +24,31 @@ Switch interfaces:
 Commands Overview:
 =============
 Commands supported
-	- enable/disable a port
-	- check a port's link speed, duplexity and status.
+	- enable/disable a port or show its configuration (speed, duplexity, status, etc.)
+	- port statistics
+	- MAC learning
+	- add/remove FDB entries
+	- Port-based VLAN
+	- Private/Shared VLAN learning
+	- VLAN ingress filtering
+	- Port LAG
 
 Commands syntax
-	ethsw port <port_nr> enable|disable		- enable/disable an l2 switch port
-	ethsw port <port_nr> show			- show an l2 switch port's configuration
+ethsw [port <port_no>] { enable | disable | show } - enable/disable a port; show a port's configuration
+ethsw [port <port_no>] statistics { [help] | [clear] } - show an l2 switch port's statistics
+ethsw [port <port_no>] learning { [help] | show | auto | disable } - enable/disable/show learning configuration on a port
+ethsw [port <port_no>] [vlan <vid>] fdb { [help] | show | flush | { add | del } <mac> } - add/delete a mac entry in FDB; use show to see FDB entries;
+											  if [vlan <vid>] is missing, VID 1 will be used
+ethsw [port <port_no>] pvid { [help] | show | <pvid> } - set/show PVID (ingress and egress VLAN tagging) for a port
+ethsw [port <port_no>] vlan { [help] | show | add <vid> | del <vid> } - add a VLAN to a port (VLAN members)
+ethsw [port <port_no>] untagged { [help] | show | all | none | pvid } - set egress tagging mode for a port
+ethsw [port <port_no>] egress tag { [help] | show | pvid | classified } - configure VID source for egress tag.
+									  Tag's VID could be the frame's classified VID or the PVID of the port
+ethsw vlan fdb { [help] | show | shared | private } - make VLAN learning shared or private
+ethsw [port <port_no>] ingress filtering { [help] | show | enable | disable } - enable/disable VLAN ingress filtering on port
+ethsw [port <port_no>] aggr { [help] | show | <lag_group_no> } - get/set LAG group for a port
 
-	port_nr=0..9; use "all" for all ports
-
-=> ethsw port all show
+=> ethsw show
     Port   Status     Link    Speed   Duplex
        0  enabled     down       10     half
        1  enabled     down       10     half

+ 64 - 0
doc/device-tree-bindings/net/fsl-tsec-phy.txt

@@ -0,0 +1,64 @@
+* TSEC-compatible ethernet nodes
+
+Properties:
+
+  - compatible : Should be "fsl,tsec"
+  - reg : Offset and length of the register set for the device
+  - phy-handle : See ethernet.txt file in the same directory.
+  - phy-connection-type : See ethernet.txt file in the same directory. This
+    property is only really needed if the connection is of type "rgmii-id",
+    "rgmii-rxid" and "rgmii-txid" as all other connection types are detected
+    by hardware.
+
+Example:
+	ethernet@24000 {
+		compatible = "fsl,tsec";
+		reg = <0x24000 0x1000>;
+		phy-handle = <&phy0>;
+		phy-connection-type = "sgmii";
+	};
+
+Child nodes of the TSEC controller are typically the individual PHY devices
+connected via the MDIO bus (sometimes the MDIO bus controller is separate).
+
+* MDIO IO device
+
+The MDIO is a bus to which the PHY devices are connected.  For each
+device that exists on this bus, a PHY node should be created.
+
+Required properties:
+  - compatible : Should define the compatible device type for the
+    mdio. Currently supported string/device is "fsl,tsec-mdio".
+  - reg : Offset and length of the register set for the device
+
+Example:
+
+	mdio@24520 {
+		compatible = "fsl,tsec-mdio";
+		reg = <0x24520 0x20>;
+
+		ethernet-phy@0 {
+			reg = <0>;
+		};
+	};
+
+* TBI Internal MDIO bus
+
+As of this writing, every tsec is associated with an internal TBI PHY.
+This PHY is accessed through the local MDIO bus.  These buses are defined
+similarly to the mdio buses.  The TBI PHYs underneath them are similar to
+normal PHYs, but the reg property is considered instructive, rather than
+descriptive.  The reg property should be chosen so it doesn't interfere
+with other PHYs on the bus.  The TBI PHYs are referred to by a "tbi-handle"
+property under the tsec node, which has a similar meaning of "phy-handle".
+
+Example:
+	ethernet@24000 {
+		phy-handle = <&tbi1>;
+	};
+
+	mdio@24520 {
+		tbi1: tbi-phy@1f {
+			reg = <0x1f>;
+		};
+	};

+ 165 - 0
doc/device-tree-bindings/net/micrel-ksz90x1.txt

@@ -0,0 +1,165 @@
+Micrel KSZ9021/KSZ9031 Gigabit Ethernet PHY
+
+Some boards require special tuning values, particularly when it comes to
+clock delays. You can specify clock delay values by adding
+micrel-specific properties to an Ethernet OF device node.
+
+Note that these settings are applied after any phy-specific fixup from
+phy_fixup_list (see phy_init_hw() from drivers/net/phy/phy_device.c),
+and therefore may overwrite them.
+
+KSZ9021:
+
+  All skew control options are specified in picoseconds. The minimum
+  value is 0, the maximum value is 1800, and it is incremented by 120ps
+  steps.
+
+  Optional properties:
+
+    - rxc-skew-ps : Skew control of RXC pad
+    - rxdv-skew-ps : Skew control of RX CTL pad
+    - txc-skew-ps : Skew control of TXC pad
+    - txen-skew-ps : Skew control of TX CTL pad
+    - rxd0-skew-ps : Skew control of RX data 0 pad
+    - rxd1-skew-ps : Skew control of RX data 1 pad
+    - rxd2-skew-ps : Skew control of RX data 2 pad
+    - rxd3-skew-ps : Skew control of RX data 3 pad
+    - txd0-skew-ps : Skew control of TX data 0 pad
+    - txd1-skew-ps : Skew control of TX data 1 pad
+    - txd2-skew-ps : Skew control of TX data 2 pad
+    - txd3-skew-ps : Skew control of TX data 3 pad
+
+KSZ9031:
+
+  All skew control options are specified in picoseconds. The minimum
+  value is 0, and the maximum is property-dependent. The increment
+  step is 60ps.
+
+  The KSZ9031 hardware supports a range of skew values from negative to
+  positive, where the specific range is property dependent. All values
+  specified in the devicetree are offset by the minimum value so they
+  can be represented as positive integers in the devicetree since it's
+  difficult to represent a negative number in the devictree.
+
+  The following 5-bit values table apply to rxc-skew-ps and txc-skew-ps.
+
+  Pad Skew Value	Delay (ps)	Devicetree Value
+  ------------------------------------------------------
+  0_0000		-900ps		0
+  0_0001		-840ps		60
+  0_0010		-780ps		120
+  0_0011		-720ps		180
+  0_0100		-660ps		240
+  0_0101		-600ps		300
+  0_0110		-540ps		360
+  0_0111		-480ps		420
+  0_1000		-420ps		480
+  0_1001		-360ps		540
+  0_1010		-300ps		600
+  0_1011		-240ps		660
+  0_1100		-180ps		720
+  0_1101		-120ps		780
+  0_1110		-60ps		840
+  0_1111		0ps		900
+  1_0000		60ps		960
+  1_0001		120ps		1020
+  1_0010		180ps		1080
+  1_0011		240ps		1140
+  1_0100		300ps		1200
+  1_0101		360ps		1260
+  1_0110		420ps		1320
+  1_0111		480ps		1380
+  1_1000		540ps		1440
+  1_1001		600ps		1500
+  1_1010		660ps		1560
+  1_1011		720ps		1620
+  1_1100		780ps		1680
+  1_1101		840ps		1740
+  1_1110		900ps		1800
+  1_1111		960ps		1860
+
+  The following 4-bit values table apply to the txdX-skew-ps, rxdX-skew-ps
+  data pads, and the rxdv-skew-ps, txen-skew-ps control pads.
+
+  Pad Skew Value	Delay (ps)	Devicetree Value
+  ------------------------------------------------------
+  0000			-420ps		0
+  0001			-360ps		60
+  0010			-300ps		120
+  0011			-240ps		180
+  0100			-180ps		240
+  0101			-120ps		300
+  0110			-60ps		360
+  0111			0ps		420
+  1000			60ps		480
+  1001			120ps		540
+  1010			180ps		600
+  1011			240ps		660
+  1100			300ps		720
+  1101			360ps		780
+  1110			420ps		840
+  1111			480ps		900
+
+  Optional properties:
+
+    Maximum value of 1860:
+
+      - rxc-skew-ps : Skew control of RX clock pad
+      - txc-skew-ps : Skew control of TX clock pad
+
+    Maximum value of 900:
+
+      - rxdv-skew-ps : Skew control of RX CTL pad
+      - txen-skew-ps : Skew control of TX CTL pad
+      - rxd0-skew-ps : Skew control of RX data 0 pad
+      - rxd1-skew-ps : Skew control of RX data 1 pad
+      - rxd2-skew-ps : Skew control of RX data 2 pad
+      - rxd3-skew-ps : Skew control of RX data 3 pad
+      - txd0-skew-ps : Skew control of TX data 0 pad
+      - txd1-skew-ps : Skew control of TX data 1 pad
+      - txd2-skew-ps : Skew control of TX data 2 pad
+      - txd3-skew-ps : Skew control of TX data 3 pad
+
+Examples:
+
+	/* Attach to an Ethernet device with autodetected PHY */
+	&enet {
+		rxc-skew-ps = <1800>;
+		rxdv-skew-ps = <0>;
+		txc-skew-ps = <1800>;
+		txen-skew-ps = <0>;
+		status = "okay";
+	};
+
+	/* Attach to an explicitly-specified PHY */
+	mdio {
+		phy0: ethernet-phy@0 {
+			rxc-skew-ps = <1800>;
+			rxdv-skew-ps = <0>;
+			txc-skew-ps = <1800>;
+			txen-skew-ps = <0>;
+			reg = <0>;
+		};
+	};
+	ethernet@70000 {
+		status = "okay";
+		phy = <&phy0>;
+		phy-mode = "rgmii-id";
+	};
+
+References
+
+  Micrel ksz9021rl/rn Data Sheet, Revision 1.2. Dated 2/13/2014.
+  http://www.micrel.com/_PDF/Ethernet/datasheets/ksz9021rl-rn_ds.pdf
+
+  Micrel ksz9031rnx Data Sheet, Revision 2.1. Dated 11/20/2014.
+  http://www.micrel.com/_PDF/Ethernet/datasheets/KSZ9031RNX.pdf
+
+Notes:
+
+  Note that a previous version of the Micrel ksz9021rl/rn Data Sheet
+  was missing extended register 106 (transmit data pad skews), and
+  incorrectly specified the ps per step as 200ps/step instead of
+  120ps/step. The latest update to this document reflects the latest
+  revision of the Micrel specification even though usage in the kernel
+  still reflects that incorrect document.

+ 15 - 1
drivers/net/designware.c

@@ -196,6 +196,8 @@ static void dw_adjust_link(struct eth_mac_regs *mac_p,
 
 	if (phydev->speed != 1000)
 		conf |= MII_PORTSELECT;
+	else
+		conf &= ~MII_PORTSELECT;
 
 	if (phydev->speed == 100)
 		conf |= FES_100;
@@ -404,7 +406,7 @@ static int _dw_free_pkt(struct dw_eth_dev *priv)
 static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
 {
 	struct phy_device *phydev;
-	int mask = 0xffffffff;
+	int mask = 0xffffffff, ret;
 
 #ifdef CONFIG_PHY_ADDR
 	mask = 1 << CONFIG_PHY_ADDR;
@@ -417,6 +419,11 @@ static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
 	phy_connect_dev(phydev, dev);
 
 	phydev->supported &= PHY_GBIT_FEATURES;
+	if (priv->max_speed) {
+		ret = phy_set_supported(phydev, priv->max_speed);
+		if (ret)
+			return ret;
+	}
 	phydev->advertising = phydev->supported;
 
 	priv->phydev = phydev;
@@ -599,6 +606,7 @@ static int designware_eth_probe(struct udevice *dev)
 	priv->mac_regs_p = (struct eth_mac_regs *)iobase;
 	priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET);
 	priv->interface = pdata->phy_interface;
+	priv->max_speed = pdata->max_speed;
 
 	dw_mdio_init(dev->name, priv->mac_regs_p);
 	priv->bus = miiphy_get_dev_by_name(dev->name);
@@ -633,6 +641,7 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
 {
 	struct eth_pdata *pdata = dev_get_platdata(dev);
 	const char *phy_mode;
+	const fdt32_t *cell;
 
 	pdata->iobase = dev_get_addr(dev);
 	pdata->phy_interface = -1;
@@ -644,6 +653,11 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
 		return -EINVAL;
 	}
 
+	pdata->max_speed = 0;
+	cell = fdt_getprop(gd->fdt_blob, dev->of_offset, "max-speed", NULL);
+	if (cell)
+		pdata->max_speed = fdt32_to_cpu(*cell);
+
 	return 0;
 }
 

+ 1 - 0
drivers/net/designware.h

@@ -223,6 +223,7 @@ struct dw_eth_dev {
 	char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
 
 	u32 interface;
+	u32 max_speed;
 	u32 tx_currdescnum;
 	u32 rx_currdescnum;
 

+ 2 - 2
drivers/net/fsl_mdio.c

@@ -5,6 +5,7 @@
  *
  * SPDX-License-Identifier:	GPL-2.0+
  */
+
 #include <common.h>
 #include <miiphy.h>
 #include <phy.h>
@@ -32,8 +33,7 @@ int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
 	int value;
 	int timeout = 1000000;
 
-	/* Put the address of the phy, and the register
-	 * number into MIIMADD */
+	/* 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 */

+ 7 - 0
drivers/net/phy/cortina.c

@@ -257,6 +257,12 @@ int cs4340_config(struct phy_device *phydev)
 	return 0;
 }
 
+int cs4340_probe(struct phy_device *phydev)
+{
+	phydev->flags = PHY_FLAG_BROKEN_RESET;
+	return 0;
+}
+
 int cs4340_startup(struct phy_device *phydev)
 {
 	phydev->link = 1;
@@ -276,6 +282,7 @@ struct phy_driver cs4340_driver = {
 		 MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
 		 MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
 	.config = &cs4340_config,
+	.probe	= &cs4340_probe,
 	.startup = &cs4340_startup,
 	.shutdown = &gen10g_shutdown,
 };

+ 22 - 3
drivers/net/phy/micrel.c

@@ -27,12 +27,31 @@ static struct phy_driver KSZ804_driver = {
 	.shutdown = &genphy_shutdown,
 };
 
+#define MII_KSZPHY_OMSO		0x16
+#define KSZPHY_OMSO_B_CAST_OFF	(1 << 9)
+
+static int ksz_genconfig_bcastoff(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
+	if (ret < 0)
+		return ret;
+
+	ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
+			ret | KSZPHY_OMSO_B_CAST_OFF);
+	if (ret < 0)
+		return ret;
+
+	return genphy_config(phydev);
+}
+
 static struct phy_driver KSZ8031_driver = {
 	.name = "Micrel KSZ8021/KSZ8031",
 	.uid = 0x221550,
 	.mask = 0xfffff0,
 	.features = PHY_BASIC_FEATURES,
-	.config = &genphy_config,
+	.config = &ksz_genconfig_bcastoff,
 	.startup = &genphy_startup,
 	.shutdown = &genphy_shutdown,
 };
@@ -70,7 +89,7 @@ static struct phy_driver KSZ8081_driver = {
 	.uid = 0x221560,
 	.mask = 0xfffff0,
 	.features = PHY_BASIC_FEATURES,
-	.config = &genphy_config,
+	.config = &ksz_genconfig_bcastoff,
 	.startup = &genphy_startup,
 	.shutdown = &genphy_shutdown,
 };
@@ -211,7 +230,7 @@ static int ksz90x1_of_config_group(struct phy_device *phydev,
 {
 	struct udevice *dev = phydev->dev;
 	struct phy_driver *drv = phydev->drv;
-	const int ps_to_regval = 200;
+	const int ps_to_regval = 60;
 	int val[4];
 	int i, changed = 0, offset, max;
 	u16 regval = 0;

+ 67 - 35
drivers/net/phy/phy.c

@@ -38,16 +38,16 @@ DECLARE_GLOBAL_DATA_PTR;
 static int genphy_config_advert(struct phy_device *phydev)
 {
 	u32 advertise;
-	int oldadv, adv;
+	int oldadv, adv, bmsr;
 	int err, changed = 0;
 
-	/* Only allow advertising what
-	 * this PHY supports */
+	/* Only allow advertising what this PHY supports */
 	phydev->advertising &= phydev->supported;
 	advertise = phydev->advertising;
 
 	/* Setup standard advertisement */
-	oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+	adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+	oldadv = adv;
 
 	if (adv < 0)
 		return adv;
@@ -79,29 +79,40 @@ static int genphy_config_advert(struct phy_device *phydev)
 		changed = 1;
 	}
 
+	bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+	if (bmsr < 0)
+		return bmsr;
+
+	/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
+	 * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
+	 * logical 1.
+	 */
+	if (!(bmsr & BMSR_ESTATEN))
+		return changed;
+
 	/* Configure gigabit if it's supported */
-	if (phydev->supported & (SUPPORTED_1000baseT_Half |
-				SUPPORTED_1000baseT_Full)) {
-		oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+	adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+	oldadv = adv;
+
+	if (adv < 0)
+		return adv;
 
-		if (adv < 0)
-			return adv;
+	adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
 
-		adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+	if (phydev->supported & (SUPPORTED_1000baseT_Half |
+				SUPPORTED_1000baseT_Full)) {
 		if (advertise & SUPPORTED_1000baseT_Half)
 			adv |= ADVERTISE_1000HALF;
 		if (advertise & SUPPORTED_1000baseT_Full)
 			adv |= ADVERTISE_1000FULL;
+	}
 
-		if (adv != oldadv) {
-			err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
-					adv);
+	if (adv != oldadv)
+		changed = 1;
 
-			if (err < 0)
-				return err;
-			changed = 1;
-		}
-	}
+	err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv);
+	if (err < 0)
+		return err;
 
 	return changed;
 }
@@ -117,7 +128,7 @@ static int genphy_config_advert(struct phy_device *phydev)
 static int genphy_setup_forced(struct phy_device *phydev)
 {
 	int err;
-	int ctl = 0;
+	int ctl = BMCR_ANRESTART;
 
 	phydev->pause = phydev->asym_pause = 0;
 
@@ -224,7 +235,8 @@ int genphy_update_link(struct phy_device *phydev)
 	if (phydev->link && mii_reg & BMSR_LSTATUS)
 		return 0;
 
-	if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+	if ((phydev->autoneg == AUTONEG_ENABLE) &&
+	    !(mii_reg & BMSR_ANEGCOMPLETE)) {
 		int i = 0;
 
 		printf("%s Waiting for PHY auto negotiation to complete",
@@ -280,7 +292,7 @@ int genphy_parse_link(struct phy_device *phydev)
 	int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
 
 	/* We're using autonegotiation */
-	if (phydev->supported & SUPPORTED_Autoneg) {
+	if (phydev->autoneg == AUTONEG_ENABLE) {
 		u32 lpa = 0;
 		int gblpa = 0;
 		u32 estatus = 0;
@@ -371,8 +383,6 @@ int genphy_config(struct phy_device *phydev)
 	int val;
 	u32 features;
 
-	/* For now, I'll claim that the generic driver supports
-	 * all possible port types */
 	features = (SUPPORTED_TP | SUPPORTED_MII
 			| SUPPORTED_AUI | SUPPORTED_FIBRE |
 			SUPPORTED_BNC);
@@ -411,8 +421,8 @@ int genphy_config(struct phy_device *phydev)
 			features |= SUPPORTED_1000baseX_Half;
 	}
 
-	phydev->supported = features;
-	phydev->advertising = features;
+	phydev->supported &= features;
+	phydev->advertising &= features;
 
 	genphy_config_aneg(phydev);
 
@@ -436,7 +446,9 @@ static struct phy_driver genphy_driver = {
 	.uid		= 0xffffffff,
 	.mask		= 0xffffffff,
 	.name		= "Generic PHY",
-	.features	= 0,
+	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII |
+			  SUPPORTED_AUI | SUPPORTED_FIBRE |
+			  SUPPORTED_BNC,
 	.config		= genphy_config,
 	.startup	= genphy_startup,
 	.shutdown	= genphy_shutdown,
@@ -517,6 +529,30 @@ int phy_register(struct phy_driver *drv)
 	return 0;
 }
 
+int phy_set_supported(struct phy_device *phydev, u32 max_speed)
+{
+	/* The default values for phydev->supported are provided by the PHY
+	 * driver "features" member, we want to reset to sane defaults first
+	 * before supporting higher speeds.
+	 */
+	phydev->supported &= PHY_DEFAULT_FEATURES;
+
+	switch (max_speed) {
+	default:
+		return -ENOTSUPP;
+	case SPEED_1000:
+		phydev->supported |= PHY_1000BT_FEATURES;
+		/* fall through */
+	case SPEED_100:
+		phydev->supported |= PHY_100BT_FEATURES;
+		/* fall through */
+	case SPEED_10:
+		phydev->supported |= PHY_10BT_FEATURES;
+	}
+
+	return 0;
+}
+
 static int phy_probe(struct phy_device *phydev)
 {
 	int err = 0;
@@ -707,6 +743,9 @@ int phy_reset(struct phy_device *phydev)
 	int timeout = 500;
 	int devad = MDIO_DEVAD_NONE;
 
+	if (phydev->flags & PHY_FLAG_BROKEN_RESET)
+		return 0;
+
 #ifdef CONFIG_PHYLIB_10G
 	/* If it's 10G, we need to issue reset through one of the MMDs */
 	if (is_10g_interface(phydev->interface)) {
@@ -717,15 +756,7 @@ int phy_reset(struct phy_device *phydev)
 	}
 #endif
 
-	reg = phy_read(phydev, devad, MII_BMCR);
-	if (reg < 0) {
-		debug("PHY status read failed\n");
-		return -1;
-	}
-
-	reg |= BMCR_RESET;
-
-	if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
+	if (phy_write(phydev, devad, MII_BMCR, BMCR_RESET) < 0) {
 		debug("PHY reset failed\n");
 		return -1;
 	}
@@ -738,6 +769,7 @@ int phy_reset(struct phy_device *phydev)
 	 * auto-clearing).  This should happen within 0.5 seconds per the
 	 * IEEE spec.
 	 */
+	reg = phy_read(phydev, devad, MII_BMCR);
 	while ((reg & BMCR_RESET) && timeout--) {
 		reg = phy_read(phydev, devad, MII_BMCR);
 

+ 365 - 171
drivers/net/tsec.c

@@ -1,18 +1,16 @@
 /*
  * Freescale Three Speed Ethernet Controller driver
  *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
  * Copyright 2004-2011, 2013 Freescale Semiconductor, Inc.
  * (C) Copyright 2003, Motorola, Inc.
  * author Andy Fleming
  *
+ * SPDX-License-Identifier:	GPL-2.0+
  */
 
 #include <config.h>
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
 #include <net.h>
 #include <command.h>
@@ -24,21 +22,7 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define TX_BUF_CNT		2
-
-static uint rx_idx;		/* index of the current RX buffer */
-static uint tx_idx;		/* index of the current TX buffer */
-
-#ifdef __GNUC__
-static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8);
-static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8);
-
-#else
-#error "rtx must be 64-bit aligned"
-#endif
-
-static int tsec_send(struct eth_device *dev, void *packet, int length);
-
+#ifndef CONFIG_DM_ETH
 /* Default initializations for TSEC controllers. */
 
 static struct tsec_info_struct tsec_info[] = {
@@ -64,6 +48,7 @@ static struct tsec_info_struct tsec_info[] = {
 	STD_TSEC_INFO(4),	/* TSEC4 */
 #endif
 };
+#endif /* CONFIG_DM_ETH */
 
 #define TBIANA_SETTINGS ( \
 		TBIANA_ASYMMETRIC_PAUSE \
@@ -84,8 +69,10 @@ static struct tsec_info_struct tsec_info[] = {
 /* Configure the TBI for SGMII operation */
 static void tsec_configure_serdes(struct tsec_private *priv)
 {
-	/* Access TBI PHY registers at given TSEC register offset as opposed
-	 * to the register offset used for external PHY accesses */
+	/*
+	 * Access TBI PHY registers at given TSEC register offset as opposed
+	 * to the register offset used for external PHY accesses
+	 */
 	tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
 			0, TBI_ANA, TBIANA_SETTINGS);
 	tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
@@ -100,7 +87,8 @@ static void tsec_configure_serdes(struct tsec_private *priv)
 
 /* Set the appropriate hash bit for the given addr */
 
-/* The algorithm works like so:
+/*
+ * The algorithm works like so:
  * 1) Take the Destination Address (ie the multicast address), and
  * do a CRC on it (little endian), and reverse the bits of the
  * result.
@@ -111,9 +99,13 @@ static void tsec_configure_serdes(struct tsec_private *priv)
  * hash index which gaddr register to use, and the 5 other bits
  * indicate which bit (assuming an IBM numbering scheme, which
  * for PowerPC (tm) is usually the case) in the register holds
- * the entry. */
-static int
-tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
+ * the entry.
+ */
+#ifndef CONFIG_DM_ETH
+static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
+#else
+static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int set)
+#endif
 {
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
 	struct tsec __iomem *regs = priv->regs;
@@ -135,7 +127,8 @@ tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
 }
 #endif /* Multicast TFTP ? */
 
-/* Initialized required registers to appropriate values, zeroing
+/*
+ * 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)
  */
@@ -181,7 +174,8 @@ static void init_registers(struct tsec __iomem *regs)
 
 }
 
-/* Configure maccfg2 based on negotiated speed and duplex
+/*
+ * Configure maccfg2 based on negotiated speed and duplex
  * reported by PHY handling code
  */
 static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
@@ -212,7 +206,8 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
 	case 10:
 		maccfg2 |= MACCFG2_MII;
 
-		/* Set R100 bit in all modes although
+		/*
+		 * Set R100 bit in all modes although
 		 * it is only used in RGMII mode
 		 */
 		if (phydev->speed == 100)
@@ -231,15 +226,174 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
 			(phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
 }
 
+/*
+ * 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
+ */
+#ifndef CONFIG_DM_ETH
+static int tsec_send(struct eth_device *dev, void *packet, int length)
+#else
+static int tsec_send(struct udevice *dev, void *packet, int length)
+#endif
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	struct tsec __iomem *regs = priv->regs;
+	uint16_t status;
+	int result = 0;
+	int i;
+
+	/* Find an empty buffer descriptor */
+	for (i = 0;
+	     in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
+	     i++) {
+		if (i >= TOUT_LOOP) {
+			debug("%s: tsec: tx buffers full\n", dev->name);
+			return result;
+		}
+	}
+
+	out_be32(&priv->txbd[priv->tx_idx].bufptr, (u32)packet);
+	out_be16(&priv->txbd[priv->tx_idx].length, length);
+	status = in_be16(&priv->txbd[priv->tx_idx].status);
+	out_be16(&priv->txbd[priv->tx_idx].status, 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;
+	     in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
+	     i++) {
+		if (i >= TOUT_LOOP) {
+			debug("%s: tsec: tx error\n", dev->name);
+			return result;
+		}
+	}
+
+	priv->tx_idx = (priv->tx_idx + 1) % TX_BUF_CNT;
+	result = in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_STATS;
+
+	return result;
+}
+
+#ifndef CONFIG_DM_ETH
+static int tsec_recv(struct eth_device *dev)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	struct tsec __iomem *regs = priv->regs;
+
+	while (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
+		int length = in_be16(&priv->rxbd[priv->rx_idx].length);
+		uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
+		uchar *packet = net_rx_packets[priv->rx_idx];
+
+		/* Send the packet up if there were no errors */
+		if (!(status & RXBD_STATS))
+			net_process_received_packet(packet, length - 4);
+		else
+			printf("Got error %x\n", (status & RXBD_STATS));
+
+		out_be16(&priv->rxbd[priv->rx_idx].length, 0);
+
+		status = RXBD_EMPTY;
+		/* Set the wrap bit if this is the last element in the list */
+		if ((priv->rx_idx + 1) == PKTBUFSRX)
+			status |= RXBD_WRAP;
+		out_be16(&priv->rxbd[priv->rx_idx].status, status);
+
+		priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
+	}
+
+	if (in_be32(&regs->ievent) & IEVENT_BSY) {
+		out_be32(&regs->ievent, IEVENT_BSY);
+		out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+	}
+
+	return -1;
+}
+#else
+static int tsec_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	struct tsec __iomem *regs = priv->regs;
+	int ret = -1;
+
+	if (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
+		int length = in_be16(&priv->rxbd[priv->rx_idx].length);
+		uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
+		uint32_t buf;
+
+		/* Send the packet up if there were no errors */
+		if (!(status & RXBD_STATS)) {
+			buf = in_be32(&priv->rxbd[priv->rx_idx].bufptr);
+			*packetp = (uchar *)buf;
+			ret = length - 4;
+		} else {
+			printf("Got error %x\n", (status & RXBD_STATS));
+		}
+	}
+
+	if (in_be32(&regs->ievent) & IEVENT_BSY) {
+		out_be32(&regs->ievent, IEVENT_BSY);
+		out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+	}
+
+	return ret;
+}
+
+static int tsec_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	uint16_t status;
+
+	out_be16(&priv->rxbd[priv->rx_idx].length, 0);
+
+	status = RXBD_EMPTY;
+	/* Set the wrap bit if this is the last element in the list */
+	if ((priv->rx_idx + 1) == PKTBUFSRX)
+		status |= RXBD_WRAP;
+	out_be16(&priv->rxbd[priv->rx_idx].status, status);
+
+	priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
+
+	return 0;
+}
+#endif
+
+/* Stop the interface */
+#ifndef CONFIG_DM_ETH
+static void tsec_halt(struct eth_device *dev)
+#else
+static void tsec_halt(struct udevice *dev)
+#endif
+{
+	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+	struct tsec __iomem *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 */
+	phy_shutdown(priv->phydev);
+}
+
 #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
 /*
  * When MACCFG1[Rx_EN] is enabled during system boot as part
  * of the eTSEC port initialization sequence,
  * the eTSEC Rx logic may not be properly initialized.
  */
-void redundant_init(struct eth_device *dev)
+void redundant_init(struct tsec_private *priv)
 {
-	struct tsec_private *priv = dev->priv;
 	struct tsec __iomem *regs = priv->regs;
 	uint t, count = 0;
 	int fail = 1;
@@ -274,25 +428,27 @@ void redundant_init(struct eth_device *dev)
 
 	do {
 		uint16_t status;
-		tsec_send(dev, (void *)pkt, sizeof(pkt));
+		tsec_send(priv->dev, (void *)pkt, sizeof(pkt));
 
 		/* Wait for buffer to be received */
-		for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) {
+		for (t = 0;
+		     in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY;
+		     t++) {
 			if (t >= 10 * TOUT_LOOP) {
-				printf("%s: tsec: rx error\n", dev->name);
+				printf("%s: tsec: rx error\n", priv->dev->name);
 				break;
 			}
 		}
 
-		if (!memcmp(pkt, (void *)net_rx_packets[rx_idx], sizeof(pkt)))
+		if (!memcmp(pkt, net_rx_packets[priv->rx_idx], sizeof(pkt)))
 			fail = 0;
 
-		out_be16(&rxbd[rx_idx].length, 0);
+		out_be16(&priv->rxbd[priv->rx_idx].length, 0);
 		status = RXBD_EMPTY;
-		if ((rx_idx + 1) == PKTBUFSRX)
+		if ((priv->rx_idx + 1) == PKTBUFSRX)
 			status |= RXBD_WRAP;
-		out_be16(&rxbd[rx_idx].status, status);
-		rx_idx = (rx_idx + 1) % PKTBUFSRX;
+		out_be16(&priv->rxbd[priv->rx_idx].status, status);
+		priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
 
 		if (in_be32(&regs->ievent) & IEVENT_BSY) {
 			out_be32(&regs->ievent, IEVENT_BSY);
@@ -315,49 +471,49 @@ void redundant_init(struct eth_device *dev)
 }
 #endif
 
-/* Set up the buffers and their descriptors, and bring up the
+/*
+ * Set up the buffers and their descriptors, and bring up the
  * interface
  */
-static void startup_tsec(struct eth_device *dev)
+static void startup_tsec(struct tsec_private *priv)
 {
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
 	struct tsec __iomem *regs = priv->regs;
 	uint16_t status;
 	int i;
 
 	/* reset the indices to zero */
-	rx_idx = 0;
-	tx_idx = 0;
+	priv->rx_idx = 0;
+	priv->tx_idx = 0;
 #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
 	uint svr;
 #endif
 
 	/* Point to the buffer descriptors */
-	out_be32(&regs->tbase, (u32)&txbd[0]);
-	out_be32(&regs->rbase, (u32)&rxbd[0]);
+	out_be32(&regs->tbase, (u32)&priv->txbd[0]);
+	out_be32(&regs->rbase, (u32)&priv->rxbd[0]);
 
 	/* Initialize the Rx Buffer descriptors */
 	for (i = 0; i < PKTBUFSRX; i++) {
-		out_be16(&rxbd[i].status, RXBD_EMPTY);
-		out_be16(&rxbd[i].length, 0);
-		out_be32(&rxbd[i].bufptr, (u32)net_rx_packets[i]);
+		out_be16(&priv->rxbd[i].status, RXBD_EMPTY);
+		out_be16(&priv->rxbd[i].length, 0);
+		out_be32(&priv->rxbd[i].bufptr, (u32)net_rx_packets[i]);
 	}
-	status = in_be16(&rxbd[PKTBUFSRX - 1].status);
-	out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
+	status = in_be16(&priv->rxbd[PKTBUFSRX - 1].status);
+	out_be16(&priv->rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
 
 	/* Initialize the TX Buffer Descriptors */
 	for (i = 0; i < TX_BUF_CNT; i++) {
-		out_be16(&txbd[i].status, 0);
-		out_be16(&txbd[i].length, 0);
-		out_be32(&txbd[i].bufptr, 0);
+		out_be16(&priv->txbd[i].status, 0);
+		out_be16(&priv->txbd[i].length, 0);
+		out_be32(&priv->txbd[i].bufptr, 0);
 	}
-	status = in_be16(&txbd[TX_BUF_CNT - 1].status);
-	out_be16(&txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
+	status = in_be16(&priv->txbd[TX_BUF_CNT - 1].status);
+	out_be16(&priv->txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
 
 #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
 	svr = get_svr();
 	if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
-		redundant_init(dev);
+		redundant_init(priv);
 #endif
 	/* Enable Transmit and Receive */
 	setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
@@ -369,113 +525,22 @@ static void startup_tsec(struct eth_device *dev)
 	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, void *packet, int length)
-{
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	struct tsec __iomem *regs = priv->regs;
-	uint16_t status;
-	int result = 0;
-	int i;
-
-	/* Find an empty buffer descriptor */
-	for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
-		if (i >= TOUT_LOOP) {
-			debug("%s: tsec: tx buffers full\n", dev->name);
-			return result;
-		}
-	}
-
-	out_be32(&txbd[tx_idx].bufptr, (u32)packet);
-	out_be16(&txbd[tx_idx].length, length);
-	status = in_be16(&txbd[tx_idx].status);
-	out_be16(&txbd[tx_idx].status, 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; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
-		if (i >= TOUT_LOOP) {
-			debug("%s: tsec: tx error\n", dev->name);
-			return result;
-		}
-	}
-
-	tx_idx = (tx_idx + 1) % TX_BUF_CNT;
-	result = in_be16(&txbd[tx_idx].status) & TXBD_STATS;
-
-	return result;
-}
-
-static int tsec_recv(struct eth_device *dev)
-{
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
-	struct tsec __iomem *regs = priv->regs;
-
-	while (!(in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY)) {
-		int length = in_be16(&rxbd[rx_idx].length);
-		uint16_t status = in_be16(&rxbd[rx_idx].status);
-
-		/* Send the packet up if there were no errors */
-		if (!(status & RXBD_STATS))
-			net_process_received_packet(net_rx_packets[rx_idx],
-						    length - 4);
-		else
-			printf("Got error %x\n", (status & RXBD_STATS));
-
-		out_be16(&rxbd[rx_idx].length, 0);
-
-		status = RXBD_EMPTY;
-		/* Set the wrap bit if this is the last element in the list */
-		if ((rx_idx + 1) == PKTBUFSRX)
-			status |= RXBD_WRAP;
-		out_be16(&rxbd[rx_idx].status, status);
-
-		rx_idx = (rx_idx + 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;
-	struct tsec __iomem *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 */
-	phy_shutdown(priv->phydev);
-}
-
-/* Initializes data structures and registers for the controller,
- * and brings the interface up.	 Returns the link status, meaning
+/*
+ * 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.
+ * This allows U-Boot to find the first active controller.
  */
+#ifndef CONFIG_DM_ETH
 static int tsec_init(struct eth_device *dev, bd_t * bd)
+#else
+static int tsec_init(struct udevice *dev)
+#endif
 {
 	struct tsec_private *priv = (struct tsec_private *)dev->priv;
+#ifdef CONFIG_DM_ETH
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+#endif
 	struct tsec __iomem *regs = priv->regs;
 	u32 tempval;
 	int ret;
@@ -489,17 +554,27 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
 	/* Init ECNTRL */
 	out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
 
-	/* Copy the station address into the address registers.
+	/*
+	 * Copy the station address into the address registers.
 	 * For a station address of 0x12345678ABCD in transmission
 	 * order (BE), MACnADDR1 is set to 0xCDAB7856 and
 	 * MACnADDR2 is set to 0x34120000.
 	 */
+#ifndef CONFIG_DM_ETH
 	tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
 		  (dev->enetaddr[3] << 8)  |  dev->enetaddr[2];
+#else
+	tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) |
+		  (pdata->enetaddr[3] << 8)  |  pdata->enetaddr[2];
+#endif
 
 	out_be32(&regs->macstnaddr1, tempval);
 
+#ifndef CONFIG_DM_ETH
 	tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
+#else
+	tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16);
+#endif
 
 	out_be32(&regs->macstnaddr2, tempval);
 
@@ -507,7 +582,7 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
 	init_registers(regs);
 
 	/* Ready the device for tx/rx */
-	startup_tsec(dev);
+	startup_tsec(priv);
 
 	/* Start up the PHY */
 	ret = phy_startup(priv->phydev);
@@ -551,8 +626,8 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
 			 * be set by the platform code.
 			 */
 			if ((interface == PHY_INTERFACE_MODE_RGMII_ID) ||
-				 (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
-				 (interface == PHY_INTERFACE_MODE_RGMII_RXID))
+			    (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
+			    (interface == PHY_INTERFACE_MODE_RGMII_RXID))
 				return interface;
 
 			return PHY_INTERFACE_MODE_RGMII;
@@ -565,14 +640,13 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
 	return PHY_INTERFACE_MODE_MII;
 }
 
-
-/* Discover which PHY is attached to the device, and configure it
+/*
+ * 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)
+static int init_phy(struct tsec_private *priv)
 {
-	struct tsec_private *priv = (struct tsec_private *)dev->priv;
 	struct phy_device *phydev;
 	struct tsec __iomem *regs = priv->regs;
 	u32 supported = (SUPPORTED_10baseT_Half |
@@ -584,14 +658,15 @@ static int init_phy(struct eth_device *dev)
 		supported |= SUPPORTED_1000baseT_Full;
 
 	/* Assign a Physical address to the TBI */
-	out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
+	out_be32(&regs->tbipa, priv->tbiaddr);
 
 	priv->interface = tsec_get_interface(priv);
 
 	if (priv->interface == PHY_INTERFACE_MODE_SGMII)
 		tsec_configure_serdes(priv);
 
-	phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
+	phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev,
+			     priv->interface);
 	if (!phydev)
 		return 0;
 
@@ -605,7 +680,9 @@ static int init_phy(struct eth_device *dev)
 	return 1;
 }
 
-/* Initialize device structure. Returns success if PHY
+#ifndef CONFIG_DM_ETH
+/*
+ * 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)
@@ -630,11 +707,13 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
 	priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
 
 	priv->phyaddr = tsec_info->phyaddr;
+	priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
 	priv->flags = tsec_info->flags;
 
 	strcpy(dev->name, tsec_info->devname);
 	priv->interface = tsec_info->interface;
 	priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname);
+	priv->dev = dev;
 	dev->iobase = 0;
 	dev->priv = priv;
 	dev->init = tsec_init;
@@ -645,7 +724,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
 	dev->mcast = tsec_mcast_addr;
 #endif
 
-	/* Tell u-boot to get the addr from the env */
+	/* Tell U-Boot to get the addr from the env */
 	for (i = 0; i < 6; i++)
 		dev->enetaddr[i] = 0;
 
@@ -657,7 +736,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
 	clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
 
 	/* Try to initialize PHY here, and return */
-	return init_phy(dev);
+	return init_phy(priv);
 }
 
 /*
@@ -690,3 +769,118 @@ int tsec_standard_init(bd_t *bis)
 
 	return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
 }
+#else /* CONFIG_DM_ETH */
+int tsec_probe(struct udevice *dev)
+{
+	struct tsec_private *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct fsl_pq_mdio_info mdio_info;
+	int offset = 0;
+	int reg;
+	const char *phy_mode;
+	int ret;
+
+	pdata->iobase = (phys_addr_t)dev_get_addr(dev);
+	priv->regs = (struct tsec *)pdata->iobase;
+
+	offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+				       "phy-handle");
+	if (offset > 0) {
+		reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
+		priv->phyaddr = reg;
+	} else {
+		debug("phy-handle does not exist under tsec %s\n", dev->name);
+		return -ENOENT;
+	}
+
+	offset = fdt_parent_offset(gd->fdt_blob, offset);
+	if (offset > 0) {
+		reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
+		priv->phyregs_sgmii = (struct tsec_mii_mng *)(reg + 0x520);
+	} else {
+		debug("No parent node for PHY?\n");
+		return -ENOENT;
+	}
+
+	offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+				       "tbi-handle");
+	if (offset > 0) {
+		reg = fdtdec_get_int(gd->fdt_blob, offset, "reg",
+				     CONFIG_SYS_TBIPA_VALUE);
+		priv->tbiaddr = reg;
+	} else {
+		priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
+	}
+
+	phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset,
+			       "phy-connection-type", NULL);
+	if (phy_mode)
+		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+	if (pdata->phy_interface == -1) {
+		debug("Invalid PHY interface '%s'\n", phy_mode);
+		return -EINVAL;
+	}
+	priv->interface = pdata->phy_interface;
+
+	/* Initialize flags */
+	priv->flags = TSEC_GIGABIT;
+	if (priv->interface == PHY_INTERFACE_MODE_SGMII)
+		priv->flags |= TSEC_SGMII;
+
+	mdio_info.regs = priv->phyregs_sgmii;
+	mdio_info.name = (char *)dev->name;
+	ret = fsl_pq_mdio_init(NULL, &mdio_info);
+	if (ret)
+		return ret;
+
+	/* 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);
+
+	priv->dev = dev;
+	priv->bus = miiphy_get_dev_by_name(dev->name);
+
+	/* Try to initialize PHY here, and return */
+	return !init_phy(priv);
+}
+
+int tsec_remove(struct udevice *dev)
+{
+	struct tsec_private *priv = dev->priv;
+
+	free(priv->phydev);
+	mdio_unregister(priv->bus);
+	mdio_free(priv->bus);
+
+	return 0;
+}
+
+static const struct eth_ops tsec_ops = {
+	.start = tsec_init,
+	.send = tsec_send,
+	.recv = tsec_recv,
+	.free_pkt = tsec_free_pkt,
+	.stop = tsec_halt,
+#ifdef CONFIG_MCAST_TFTP
+	.mcast = tsec_mcast_addr,
+#endif
+};
+
+static const struct udevice_id tsec_ids[] = {
+	{ .compatible = "fsl,tsec" },
+	{ }
+};
+
+U_BOOT_DRIVER(eth_tsec) = {
+	.name = "tsec",
+	.id = UCLASS_ETH,
+	.of_match = tsec_ids,
+	.probe = tsec_probe,
+	.remove = tsec_remove,
+	.ops = &tsec_ops,
+	.priv_auto_alloc_size = sizeof(struct tsec_private),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif /* CONFIG_DM_ETH */

+ 353 - 1
drivers/net/vsc9953.c

@@ -469,6 +469,47 @@ static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
 		clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
 }
 
+enum aggr_code_mode {
+	AGGR_CODE_RAND = 0,
+	AGGR_CODE_ALL,	/* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */
+};
+
+/* Set aggregation code generation mode */
+static int vsc9953_aggr_code_set(enum aggr_code_mode ac)
+{
+	int rc;
+	struct vsc9953_analyzer *l2ana_reg;
+
+	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+						VSC9953_ANA_OFFSET);
+
+	switch (ac) {
+	case AGGR_CODE_RAND:
+		clrsetbits_le32(&l2ana_reg->common.aggr_cfg,
+				VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
+				VSC9953_AC_IP6_LBL_ENA |
+				VSC9953_AC_IP6_TCPUDP_ENA |
+				VSC9953_AC_IP4_SIPDIP_ENA |
+				VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA);
+		rc = 0;
+		break;
+	case AGGR_CODE_ALL:
+		clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA,
+				VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
+				VSC9953_AC_IP6_LBL_ENA |
+				VSC9953_AC_IP6_TCPUDP_ENA |
+				VSC9953_AC_IP4_SIPDIP_ENA |
+				VSC9953_AC_IP4_TCPUDP_ENA);
+		rc = 0;
+		break;
+	default:
+		/* unknown mode for aggregation code */
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
 /* Egress untag modes of a VSC9953 port */
 enum egress_untag_mode {
 	EGRESS_UNTAG_ALL = 0,
@@ -593,6 +634,25 @@ static void vsc9953_port_all_vlan_egress_untagged_set(
 		vsc9953_port_vlan_egr_untag_set(i, mode);
 }
 
+static int vsc9953_autoage_time_set(int age_period)
+{
+	u32 autoage;
+	struct vsc9953_analyzer *l2ana_reg;
+
+	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+						VSC9953_ANA_OFFSET);
+
+	if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
+		return -EINVAL;
+
+	autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
+					   VSC9953_AUTOAGE_PERIOD_MASK,
+					   age_period);
+	out_le32(&l2ana_reg->ana.auto_age, autoage);
+
+	return 0;
+}
+
 #ifdef CONFIG_CMD_ETHSW
 
 /* Enable/disable status of a VSC9953 port */
@@ -1474,6 +1534,224 @@ static int vsc9953_port_ingress_filtering_get(int port_no)
 	return !!(val & (1 << port_no));
 }
 
+/* Get the aggregation group of a port */
+static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp)
+{
+	u32 val;
+	struct vsc9953_analyzer *l2ana_reg;
+
+	if (!VSC9953_PORT_CHECK(port_no))
+		return -EINVAL;
+
+	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+						VSC9953_ANA_OFFSET);
+
+	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
+	*aggr_grp = bitfield_extract_by_mask(val,
+					     VSC9953_PORT_CFG_PORTID_MASK);
+
+	return 0;
+}
+
+static void vsc9953_aggr_grp_members_get(int aggr_grp,
+					 u8 aggr_membr[VSC9953_MAX_PORTS])
+{
+	int port_no;
+	int aggr_membr_grp;
+
+	for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) {
+		aggr_membr[port_no] = 0;
+
+		if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp))
+			continue;
+
+		if (aggr_grp == aggr_membr_grp)
+			aggr_membr[port_no] = 1;
+	}
+}
+
+static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old,
+					      u32 membr_bitfld_new)
+{
+	int i;
+	u32 pgid;
+	struct vsc9953_analyzer *l2ana_reg;
+
+	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+						VSC9953_ANA_OFFSET);
+
+	/*
+	 * NOTE: Only the unicast destination masks are updated, since
+	 * we do not support for now Layer-2 multicast entries
+	 */
+	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+		if (i == port_no) {
+			clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i],
+					VSC9953_PGID_PORT_MASK,
+					membr_bitfld_new);
+			continue;
+		}
+
+		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
+		if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
+			pgid &= ~((u32)(1 << port_no));
+		if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
+			pgid |= ((u32)(1 << port_no));
+
+		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
+	}
+}
+
+static void vsc9953_update_source_members_masks(int port_no,
+						u32 membr_bitfld_old,
+						u32 membr_bitfld_new)
+{
+	int i;
+	int index;
+	u32 pgid;
+	struct vsc9953_analyzer *l2ana_reg;
+
+	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+						VSC9953_ANA_OFFSET);
+
+	for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) {
+		index = PGID_SRC_START + i;
+		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]);
+		if (i == port_no) {
+			pgid = (pgid | VSC9953_PGID_PORT_MASK) &
+			       ~membr_bitfld_new;
+			out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index],
+				 pgid);
+			continue;
+		}
+
+		if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
+			pgid |= (u32)(1 << port_no);
+
+		if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
+			pgid &= ~(u32)(1 << port_no);
+		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid);
+	}
+}
+
+static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield)
+{
+	if (!member_bitfield)
+		return 0;
+
+	if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
+		aggr_mask = 1;
+	else
+		aggr_mask <<= 1;
+
+	while (!(aggr_mask & member_bitfield)) {
+		aggr_mask <<= 1;
+		if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
+			aggr_mask = 1;
+	}
+
+	return aggr_mask;
+}
+
+static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old,
+					      u32 membr_bitfld_new)
+{
+	int i;
+	u32 pgid;
+	u32 aggr_mask_old = 0;
+	u32 aggr_mask_new = 0;
+	struct vsc9953_analyzer *l2ana_reg;
+
+	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+						VSC9953_ANA_OFFSET);
+
+	/* Update all the PGID aggregation masks */
+	for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) {
+		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
+
+		aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old,
+							   membr_bitfld_old);
+		pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old;
+
+		aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new,
+							   membr_bitfld_new);
+		pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new;
+
+		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
+	}
+}
+
+static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])
+{
+	int i;
+	u32 member_bitfield = 0;
+
+	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+		if (member[i])
+			member_bitfield |= 1 << i;
+	}
+	member_bitfield &= VSC9953_PGID_PORT_MASK;
+
+	return member_bitfield;
+}
+
+static void vsc9953_update_members_masks(int port_no,
+					 u8 member_old[VSC9953_MAX_PORTS],
+					 u8 member_new[VSC9953_MAX_PORTS])
+{
+	u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old);
+	u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new);
+
+	vsc9953_update_dest_members_masks(port_no, membr_bitfld_old,
+					  membr_bitfld_new);
+	vsc9953_update_source_members_masks(port_no, membr_bitfld_old,
+					    membr_bitfld_new);
+	vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old,
+					  membr_bitfld_new);
+}
+
+/* Set the aggregation group of a port */
+static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp)
+{
+	u8 aggr_membr_old[VSC9953_MAX_PORTS];
+	u8 aggr_membr_new[VSC9953_MAX_PORTS];
+	int rc;
+	int aggr_grp_old;
+	u32 val;
+	struct vsc9953_analyzer *l2ana_reg;
+
+	if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp))
+		return -EINVAL;
+
+	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+						VSC9953_ANA_OFFSET);
+
+	rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old);
+	if (rc)
+		return rc;
+
+	/* get all the members of the old aggregation group */
+	vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old);
+
+	/* get all the members of the same aggregation group */
+	vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new);
+
+	/* add current port as member to the new aggregation group */
+	aggr_membr_old[port_no] = 0;
+	aggr_membr_new[port_no] = 1;
+
+	/* update masks */
+	vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new);
+
+	/* Change logical port number */
+	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
+	val = bitfield_replace_by_mask(val,
+				       VSC9953_PORT_CFG_PORTID_MASK, aggr_grp);
+	out_le32(&l2ana_reg->port[port_no].port_cfg, val);
+
+	return 0;
+}
+
 static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
 {
 	int i;
@@ -2064,6 +2342,72 @@ static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
 	return CMD_RET_SUCCESS;
 }
 
+static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd)
+{
+	int i;
+	int aggr_grp;
+
+	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+			printf("Invalid port number: %d\n", parsed_cmd->port);
+			return CMD_RET_FAILURE;
+		}
+
+		if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp))
+			return CMD_RET_FAILURE;
+		printf("%7s %10s\n", "Port", "Aggr grp");
+		printf("%7d %10d\n", parsed_cmd->port, aggr_grp);
+	} else {
+		printf("%7s %10s\n", "Port", "Aggr grp");
+		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+			if (vsc9953_port_aggr_grp_get(i, &aggr_grp))
+				continue;
+			printf("%7d %10d\n", i, aggr_grp);
+		}
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd)
+{
+	int i;
+
+	/* Aggregation group number should be set in parsed_cmd->aggr_grp */
+	if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) {
+		printf("Please set an aggregation group value\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) {
+		printf("Invalid aggregation group number: %d\n",
+		       parsed_cmd->aggr_grp);
+		return CMD_RET_FAILURE;
+	}
+
+	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+			printf("Invalid port number: %d\n", parsed_cmd->port);
+			return CMD_RET_FAILURE;
+		}
+		if (vsc9953_port_aggr_grp_set(parsed_cmd->port,
+					      parsed_cmd->aggr_grp)) {
+			printf("Port %d: failed to set aggr group %d\n",
+			       parsed_cmd->port, parsed_cmd->aggr_grp);
+		}
+	} else {
+		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+			if (vsc9953_port_aggr_grp_set(i,
+						      parsed_cmd->aggr_grp)) {
+				printf("Port %d: failed to set aggr group %d\n",
+				       i, parsed_cmd->aggr_grp);
+			}
+		}
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
 static struct ethsw_command_func vsc9953_cmd_func = {
 		.ethsw_name = "L2 Switch VSC9953",
 		.port_enable = &vsc9953_port_status_key_func,
@@ -2088,7 +2432,9 @@ static struct ethsw_command_func vsc9953_cmd_func = {
 		.vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
 		.vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
 		.port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
-		.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func
+		.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func,
+		.port_aggr_show = &vsc9953_port_aggr_show_key_func,
+		.port_aggr_set = &vsc9953_port_aggr_set_key_func,
 };
 
 #endif /* CONFIG_CMD_ETHSW */
@@ -2107,6 +2453,10 @@ void vsc9953_default_configuration(void)
 {
 	int i;
 
+	if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
+		debug("VSC9953: failed to set AGE time to %d\n",
+		      VSC9953_DEFAULT_AGE_TIME);
+
 	for (i = 0; i < VSC9953_MAX_VLAN; i++)
 		vsc9953_vlan_table_membership_all_set(i, 0);
 	vsc9953_port_all_vlan_aware_set(1);
@@ -2115,6 +2465,8 @@ void vsc9953_default_configuration(void)
 	vsc9953_vlan_table_membership_all_set(1, 1);
 	vsc9953_vlan_ingr_fltr_learn_drop(1);
 	vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
+	if (vsc9953_aggr_code_set(AGGR_CODE_ALL))
+		debug("VSC9953: failed to set default aggregation code mode\n");
 }
 
 void vsc9953_init(bd_t *bis)

+ 5 - 1
drivers/pci/pci_tegra.c

@@ -465,7 +465,11 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
 		return err;
 	}
 
-	tegra_pcie_board_init();
+	err = tegra_pcie_board_init();
+	if (err < 0) {
+		error("tegra_pcie_board_init() failed: err=%d", err);
+		return err;
+	}
 
 	pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
 	if (pcie->phy) {

+ 6 - 0
include/ethsw.h

@@ -12,6 +12,7 @@
 #define ETHSW_MAX_CMD_PARAMS 20
 #define ETHSW_CMD_PORT_ALL -1
 #define ETHSW_CMD_VLAN_ALL -1
+#define ETHSW_CMD_AGGR_GRP_NONE -1
 
 /* IDs used to track keywords in a command */
 enum ethsw_keyword_id {
@@ -41,6 +42,7 @@ enum ethsw_keyword_id {
 	ethsw_id_private,
 	ethsw_id_ingress,
 	ethsw_id_filtering,
+	ethsw_id_aggr,
 	ethsw_id_count,	/* keep last */
 };
 
@@ -50,6 +52,7 @@ enum ethsw_keyword_opt_id {
 	ethsw_id_pvid_no,
 	ethsw_id_add_del_no,
 	ethsw_id_add_del_mac,
+	ethsw_id_aggr_no,
 	ethsw_id_count_all,	/* keep last */
 };
 
@@ -58,6 +61,7 @@ struct ethsw_command_def {
 	int cmd_keywords_nr;
 	int port;
 	int vid;
+	int aggr_grp;
 	uchar ethaddr[6];
 	int (*cmd_function)(struct ethsw_command_def *parsed_cmd);
 };
@@ -88,6 +92,8 @@ struct ethsw_command_func {
 	int (*vlan_learn_set)(struct ethsw_command_def *parsed_cmd);
 	int (*port_ingr_filt_show)(struct ethsw_command_def *parsed_cmd);
 	int (*port_ingr_filt_set)(struct ethsw_command_def *parsed_cmd);
+	int (*port_aggr_show)(struct ethsw_command_def *parsed_cmd);
+	int (*port_aggr_set)(struct ethsw_command_def *parsed_cmd);
 };
 
 int ethsw_define_functions(const struct ethsw_command_func *cmd_func);

+ 4 - 3
include/fsl_mdio.h

@@ -5,6 +5,7 @@
  *
  * SPDX-License-Identifier:	GPL-2.0+
  */
+
 #ifndef __FSL_PHY_H__
 #define __FSL_PHY_H__
 
@@ -27,9 +28,9 @@ int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc);
 #define PHY_EXT_PAGE_ACCESS	0x1f
 
 /* MII Management Configuration Register */
-#define MIIMCFG_RESET_MGMT          0x80000000
-#define MIIMCFG_MGMT_CLOCK_SELECT   0x00000007
-#define MIIMCFG_INIT_VALUE	    0x00000003
+#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

+ 2 - 0
include/net.h

@@ -86,11 +86,13 @@ enum eth_state_t {
  * @iobase: The base address of the hardware registers
  * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env
  * @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_...
+ * @max_speed: Maximum speed of Ethernet connection supported by MAC
  */
 struct eth_pdata {
 	phys_addr_t iobase;
 	unsigned char enetaddr[6];
 	int phy_interface;
+	int max_speed;
 };
 
 enum eth_recv_flags {

+ 18 - 7
include/phy.h

@@ -17,18 +17,28 @@
 
 #define PHY_MAX_ADDR 32
 
-#define PHY_BASIC_FEATURES	(SUPPORTED_10baseT_Half | \
-				 SUPPORTED_10baseT_Full | \
-				 SUPPORTED_100baseT_Half | \
-				 SUPPORTED_100baseT_Full | \
-				 SUPPORTED_Autoneg | \
+#define PHY_FLAG_BROKEN_RESET	(1 << 0) /* soft reset not supported */
+
+#define PHY_DEFAULT_FEATURES	(SUPPORTED_Autoneg | \
 				 SUPPORTED_TP | \
 				 SUPPORTED_MII)
 
-#define PHY_GBIT_FEATURES	(PHY_BASIC_FEATURES | \
-				 SUPPORTED_1000baseT_Half | \
+#define PHY_10BT_FEATURES	(SUPPORTED_10baseT_Half | \
+				 SUPPORTED_10baseT_Full)
+
+#define PHY_100BT_FEATURES	(SUPPORTED_100baseT_Half | \
+				 SUPPORTED_100baseT_Full)
+
+#define PHY_1000BT_FEATURES	(SUPPORTED_1000baseT_Half | \
 				 SUPPORTED_1000baseT_Full)
 
+#define PHY_BASIC_FEATURES	(PHY_10BT_FEATURES | \
+				 PHY_100BT_FEATURES | \
+				 PHY_DEFAULT_FEATURES)
+
+#define PHY_GBIT_FEATURES	(PHY_BASIC_FEATURES | \
+				 PHY_1000BT_FEATURES)
+
 #define PHY_10G_FEATURES	(PHY_GBIT_FEATURES | \
 				SUPPORTED_10000baseT_Full)
 
@@ -226,6 +236,7 @@ int phy_startup(struct phy_device *phydev);
 int phy_config(struct phy_device *phydev);
 int phy_shutdown(struct phy_device *phydev);
 int phy_register(struct phy_driver *drv);
+int phy_set_supported(struct phy_device *phydev, u32 max_speed);
 int genphy_config_aneg(struct phy_device *phydev);
 int genphy_restart_aneg(struct phy_device *phydev);
 int genphy_update_link(struct phy_device *phydev);

+ 40 - 29
include/tsec.h

@@ -3,15 +3,12 @@
  *
  *  Driver for the Motorola Triple Speed Ethernet Controller
  *
- *  This software may be used and distributed according to the
- *  terms of the GNU Public License, Version 2, incorporated
- *  herein by reference.
- *
  * Copyright 2004, 2007, 2009, 2011, 2013 Freescale Semiconductor, Inc.
  * (C) Copyright 2003, Motorola, Inc.
  * maintained by Xianghua Xiao (x.xiao@motorola.com)
  * author Andy Fleming
  *
+ * SPDX-License-Identifier:	GPL-2.0+
  */
 
 #ifndef __TSEC_H
@@ -21,6 +18,8 @@
 #include <config.h>
 #include <phy.h>
 
+#ifndef CONFIG_DM_ETH
+
 #ifdef CONFIG_LS102XA
 #define TSEC_SIZE		0x40000
 #define TSEC_MDIO_OFFSET	0x40000
@@ -67,11 +66,13 @@
 	x.mii_devname = DEFAULT_MII_NAME;\
 }
 
-#define MAC_ADDR_LEN 6
+#endif /* CONFIG_DM_ETH */
+
+#define MAC_ADDR_LEN		6
 
 /* #define TSEC_TIMEOUT	1000000 */
-#define TSEC_TIMEOUT 1000
-#define TOUT_LOOP	1000000
+#define TSEC_TIMEOUT		1000
+#define TOUT_LOOP		1000000
 
 /* TBI register addresses */
 #define TBI_CR			0x00
@@ -83,8 +84,8 @@
 
 /* TBI MDIO register bit fields*/
 #define TBICON_CLK_SELECT	0x0020
-#define TBIANA_ASYMMETRIC_PAUSE 0x0100
-#define TBIANA_SYMMETRIC_PAUSE  0x0080
+#define TBIANA_ASYMMETRIC_PAUSE	0x0100
+#define TBIANA_SYMMETRIC_PAUSE	0x0080
 #define TBIANA_HALF_DUPLEX	0x0040
 #define TBIANA_FULL_DUPLEX	0x0020
 #define TBICR_PHY_RESET		0x8000
@@ -93,13 +94,12 @@
 #define TBICR_FULL_DUPLEX	0x0100
 #define TBICR_SPEED1_SET	0x0040
 
-
 /* MAC register bits */
 #define MACCFG1_SOFT_RESET	0x80000000
 #define MACCFG1_RESET_RX_MC	0x00080000
 #define MACCFG1_RESET_TX_MC	0x00040000
 #define MACCFG1_RESET_RX_FUN	0x00020000
-#define	MACCFG1_RESET_TX_FUN	0x00010000
+#define MACCFG1_RESET_TX_FUN	0x00010000
 #define MACCFG1_LOOPBACK	0x00000100
 #define MACCFG1_RX_FLOW		0x00000020
 #define MACCFG1_TX_FLOW		0x00000010
@@ -122,7 +122,7 @@
 #define ECNTRL_SGMII_MODE	0x00000002
 
 #ifndef CONFIG_SYS_TBIPA_VALUE
-    #define CONFIG_SYS_TBIPA_VALUE	0x1f
+# define CONFIG_SYS_TBIPA_VALUE	0x1f
 #endif
 
 #define MRBLR_INIT_SETTINGS	PKTSIZE_ALIGN
@@ -137,7 +137,6 @@
 #define TSTAT_CLEAR_THALT	0x80000000
 #define RSTAT_CLEAR_RHALT	0x00800000
 
-
 #define IEVENT_INIT_CLEAR	0xffffffff
 #define IEVENT_BABR		0x80000000
 #define IEVENT_RXC		0x40000000
@@ -164,11 +163,9 @@
 #define IMASK_TXFEN		0x00100000
 #define IMASK_RXFEN0		0x00000080
 
-
 /* Default Attribute fields */
-#define ATTR_INIT_SETTINGS     0x000000c0
-#define ATTRELI_INIT_SETTINGS  0x00000000
-
+#define ATTR_INIT_SETTINGS	0x000000c0
+#define ATTRELI_INIT_SETTINGS	0x00000000
 
 /* TxBD status field bits */
 #define TXBD_READY		0x8000
@@ -181,7 +178,7 @@
 #define TXBD_HUGEFRAME		0x0080
 #define TXBD_LATECOLLISION	0x0080
 #define TXBD_RETRYLIMIT		0x0040
-#define	TXBD_RETRYCOUNTMASK	0x003c
+#define TXBD_RETRYCOUNTMASK	0x003c
 #define TXBD_UNDERRUN		0x0002
 #define TXBD_STATS		0x03ff
 
@@ -204,15 +201,15 @@
 #define RXBD_STATS		0x003f
 
 struct txbd8 {
-	uint16_t     status;	     /* Status Fields */
-	uint16_t     length;	     /* Buffer length */
-	uint32_t     bufptr;	     /* Buffer Pointer */
+	uint16_t status;	/* Status Fields */
+	uint16_t length;	/* Buffer length */
+	uint32_t bufptr;	/* Buffer Pointer */
 };
 
 struct rxbd8 {
-	uint16_t     status;	     /* Status Fields */
-	uint16_t     length;	     /* Buffer Length */
-	uint32_t     bufptr;	     /* Buffer Pointer */
+	uint16_t status;	/* Status Fields */
+	uint16_t length;	/* Buffer Length */
+	uint32_t bufptr;	/* Buffer Pointer */
 };
 
 struct tsec_rmon_mib {
@@ -336,15 +333,15 @@ struct tsec {
 	u32	rbdlen;		/* RxBD Data Length */
 	u32	res310[4];
 	u32	res320;
-	u32	crbptr;	/* Current Receive Buffer Pointer */
+	u32	crbptr;		/* Current Receive Buffer Pointer */
 	u32	res328[6];
-	u32	mrblr;	/* Maximum Receive Buffer Length */
+	u32	mrblr;		/* Maximum Receive Buffer Length */
 	u32	res344[16];
-	u32	rbptr;	/* RxBD Pointer */
+	u32	rbptr;		/* RxBD Pointer */
 	u32	res388[30];
 	/* (0x2_n400) */
 	u32	res400;
-	u32	rbase;	/* RxBD Base Address */
+	u32	rbase;		/* RxBD Base Address */
 	u32	res408[62];
 
 	/* MAC Registers (0x2_n500) */
@@ -388,21 +385,33 @@ struct tsec {
 	u32	resc00[256];
 };
 
-#define TSEC_GIGABIT (1 << 0)
+#define TSEC_GIGABIT	(1 << 0)
 
 /* These flags currently only have meaning if we're using the eTSEC */
 #define TSEC_REDUCED	(1 << 1)	/* MAC-PHY interface uses RGMII */
 #define TSEC_SGMII	(1 << 2)	/* MAC-PHY interface uses SGMII */
 
+#define TX_BUF_CNT	2
+
 struct tsec_private {
+	struct txbd8 __iomem txbd[TX_BUF_CNT];
+	struct rxbd8 __iomem rxbd[PKTBUFSRX];
 	struct tsec __iomem *regs;
 	struct tsec_mii_mng __iomem *phyregs_sgmii;
 	struct phy_device *phydev;
 	phy_interface_t interface;
 	struct mii_dev *bus;
 	uint phyaddr;
+	uint tbiaddr;
 	char mii_devname[16];
 	u32 flags;
+	uint rx_idx;	/* index of the current RX buffer */
+	uint tx_idx;	/* index of the current TX buffer */
+#ifndef CONFIG_DM_ETH
+	struct eth_device *dev;
+#else
+	struct udevice *dev;
+#endif
 };
 
 struct tsec_info_struct {
@@ -415,7 +424,9 @@ struct tsec_info_struct {
 	u32 flags;
 };
 
+#ifndef CONFIG_DM_ETH
 int tsec_standard_init(bd_t *bis);
 int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsec_info, int num);
+#endif
 
 #endif /* __TSEC_H */

+ 23 - 1
include/vsc9953.h

@@ -126,6 +126,7 @@
 #define VSC9953_PORT_CFG_LEARN_AUTO	0x00000100
 #define VSC9953_PORT_CFG_LEARN_CPU	0x00000200
 #define VSC9953_PORT_CFG_LEARN_DROP	0x00000400
+#define VSC9953_PORT_CFG_PORTID_MASK	0x0000003c
 
 /* Macros for vsc9953_qsys_sys.switch_port_mode register */
 #define VSC9953_PORT_ENA		0x00002000
@@ -136,6 +137,9 @@
 /* Macros for vsc9953_ana_ana.adv_learn register */
 #define VSC9953_VLAN_CHK		0x00000400
 
+/* Macros for vsc9953_ana_ana.auto_age register */
+#define VSC9953_AUTOAGE_PERIOD_MASK	0x001ffffe
+
 /* Macros for vsc9953_rew_port.port_tag_cfg register */
 #define VSC9953_TAG_CFG_MASK		0x00000180
 #define VSC9953_TAG_CFG_NONE		0x00000000
@@ -153,6 +157,19 @@
 /* Macros for vsc9953_ana_ana_tables.mach_data register */
 #define VSC9953_MACHDATA_VID_MASK	0x1fff0000
 
+/* Macros for vsc9953_ana_common.aggr_cfg register */
+#define VSC9953_AC_RND_ENA		0x00000080
+#define VSC9953_AC_DMAC_ENA		0x00000040
+#define VSC9953_AC_SMAC_ENA		0x00000020
+#define VSC9953_AC_IP6_LBL_ENA		0x00000010
+#define VSC9953_AC_IP6_TCPUDP_ENA	0x00000008
+#define VSC9953_AC_IP4_SIPDIP_ENA	0x00000004
+#define VSC9953_AC_IP4_TCPUDP_ENA	0x00000002
+#define VSC9953_AC_MASK			0x000000fe
+
+/* Macros for vsc9953_ana_pgid.port_grp_id[] registers */
+#define VSC9953_PGID_PORT_MASK		0x000003ff
+
 #define VSC9953_MAX_PORTS		10
 #define VSC9953_PORT_CHECK(port)	\
 	(((port) < 0 || (port) >= VSC9953_MAX_PORTS) ? 0 : 1)
@@ -164,6 +181,7 @@
 #define VSC9953_MAX_VLAN		4096
 #define VSC9953_VLAN_CHECK(vid)	\
 	(((vid) < 0 || (vid) >= VSC9953_MAX_VLAN) ? 0 : 1)
+#define VSC9953_DEFAULT_AGE_TIME	300
 
 #define DEFAULT_VSC9953_MDIO_NAME	"VSC9953_MDIO0"
 
@@ -235,6 +253,10 @@ struct vsc9953_ana_ana {
 	u32	port_mode[12];
 };
 
+#define PGID_DST_START		0
+#define PGID_AGGR_START		64
+#define PGID_SRC_START		80
+
 struct vsc9953_ana_pgid {
 	u32	port_grp_id[91];
 };
@@ -269,7 +291,7 @@ struct vsc9953_analyzer {
 	struct vsc9953_ana_ana_tables	ana_tables;
 	u32	reserved2[14];
 	struct vsc9953_ana_ana	ana;
-	u32	reserved3[22];
+	u32	reserved3[21];
 	struct vsc9953_ana_pgid	port_id_tbl;
 	u32	reserved4[549];
 	struct vsc9953_ana_pfc	pfc[10];

+ 6 - 1
net/Makefile

@@ -12,7 +12,12 @@ obj-$(CONFIG_CMD_NET)  += arp.o
 obj-$(CONFIG_CMD_NET)  += bootp.o
 obj-$(CONFIG_CMD_CDP)  += cdp.o
 obj-$(CONFIG_CMD_DNS)  += dns.o
-obj-$(CONFIG_CMD_NET)  += eth.o
+ifdef CONFIG_DM_ETH
+obj-$(CONFIG_CMD_NET)  += eth-uclass.o
+else
+obj-$(CONFIG_CMD_NET)  += eth_legacy.o
+endif
+obj-$(CONFIG_CMD_NET)  += eth_common.o
 obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
 obj-$(CONFIG_CMD_NET)  += net.o
 obj-$(CONFIG_CMD_NFS)  += nfs.o

+ 4 - 0
net/bootp.c

@@ -949,6 +949,7 @@ static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
 	net_write_ip(&bp->bp_giaddr, zero_ip);
 
 	memcpy(bp->bp_chaddr, net_ethaddr, 6);
+	copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
 
 	/*
 	 * ID is the id of the OFFER packet
@@ -995,6 +996,9 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 	debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: "
 	      "%d\n", src, dest, len, dhcp_state);
 
+	if (net_read_ip(&bp->bp_yiaddr).s_addr == 0)
+		return;
+
 	switch (dhcp_state) {
 	case SELECTING:
 		/*

+ 3 - 593
net/eth.c → net/eth-uclass.c

@@ -7,113 +7,13 @@
  */
 
 #include <common.h>
-#include <command.h>
 #include <dm.h>
 #include <environment.h>
 #include <net.h>
-#include <miiphy.h>
-#include <phy.h>
-#include <asm/errno.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
+#include "eth_internal.h"
 
-DECLARE_GLOBAL_DATA_PTR;
-
-void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
-{
-	char *end;
-	int i;
-
-	for (i = 0; i < 6; ++i) {
-		enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
-		if (addr)
-			addr = (*end) ? end + 1 : end;
-	}
-}
-
-int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
-{
-	eth_parse_enetaddr(getenv(name), enetaddr);
-	return is_valid_ethaddr(enetaddr);
-}
-
-int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
-{
-	char buf[20];
-
-	sprintf(buf, "%pM", enetaddr);
-
-	return setenv(name, buf);
-}
-
-int eth_getenv_enetaddr_by_index(const char *base_name, int index,
-				 uchar *enetaddr)
-{
-	char enetvar[32];
-	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
-	return eth_getenv_enetaddr(enetvar, enetaddr);
-}
-
-static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
-				 uchar *enetaddr)
-{
-	char enetvar[32];
-	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
-	return eth_setenv_enetaddr(enetvar, enetaddr);
-}
-
-static int eth_mac_skip(int index)
-{
-	char enetvar[15];
-	char *skip_state;
-
-	sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
-	skip_state = getenv(enetvar);
-	return skip_state != NULL;
-}
-
-static void eth_current_changed(void);
-
-/*
- * CPU and board-specific Ethernet initializations.  Aliased function
- * signals caller to move on
- */
-static int __def_eth_init(bd_t *bis)
-{
-	return -1;
-}
-int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
-int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
-
-static void eth_common_init(void)
-{
-	bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
-	miiphy_init();
-#endif
-
-#ifdef CONFIG_PHYLIB
-	phy_init();
-#endif
-
-	/*
-	 * If board-specific initialization exists, call it.
-	 * If not, call a CPU-specific one
-	 */
-	if (board_eth_init != __def_eth_init) {
-		if (board_eth_init(gd->bd) < 0)
-			printf("Board Net Initialization Failed\n");
-	} else if (cpu_eth_init != __def_eth_init) {
-		if (cpu_eth_init(gd->bd) < 0)
-			printf("CPU Net Initialization Failed\n");
-	} else {
-#ifndef CONFIG_DM_ETH
-		printf("Net Initialization Skipped\n");
-#endif
-	}
-}
-
-#ifdef CONFIG_DM_ETH
 /**
  * struct eth_device_priv - private structure for each Ethernet device
  *
@@ -144,7 +44,7 @@ static struct eth_uclass_priv *eth_get_uclass_priv(void)
 	return uc->priv;
 }
 
-static void eth_set_current_to_next(void)
+void eth_set_current_to_next(void)
 {
 	struct eth_uclass_priv *uc_priv;
 
@@ -177,7 +77,7 @@ struct udevice *eth_get_dev(void)
  * In case it was not probed, we will attempt to do so.
  * dev may be NULL to unset the active device.
  */
-static void eth_set_dev(struct udevice *dev)
+void eth_set_dev(struct udevice *dev)
 {
 	if (dev && !device_active(dev)) {
 		eth_errno = device_probe(dev);
@@ -647,493 +547,3 @@ UCLASS_DRIVER(eth) = {
 	.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 };
-#endif /* #ifdef CONFIG_DM_ETH */
-
-#ifndef CONFIG_DM_ETH
-
-#ifdef CONFIG_API
-static struct {
-	uchar data[PKTSIZE];
-	int length;
-} eth_rcv_bufs[PKTBUFSRX];
-
-static unsigned int eth_rcv_current, eth_rcv_last;
-#endif
-
-static struct eth_device *eth_devices;
-struct eth_device *eth_current;
-
-static void eth_set_current_to_next(void)
-{
-	eth_current = eth_current->next;
-}
-
-static void eth_set_dev(struct eth_device *dev)
-{
-	eth_current = dev;
-}
-
-struct eth_device *eth_get_dev_by_name(const char *devname)
-{
-	struct eth_device *dev, *target_dev;
-
-	BUG_ON(devname == NULL);
-
-	if (!eth_devices)
-		return NULL;
-
-	dev = eth_devices;
-	target_dev = NULL;
-	do {
-		if (strcmp(devname, dev->name) == 0) {
-			target_dev = dev;
-			break;
-		}
-		dev = dev->next;
-	} while (dev != eth_devices);
-
-	return target_dev;
-}
-
-struct eth_device *eth_get_dev_by_index(int index)
-{
-	struct eth_device *dev, *target_dev;
-
-	if (!eth_devices)
-		return NULL;
-
-	dev = eth_devices;
-	target_dev = NULL;
-	do {
-		if (dev->index == index) {
-			target_dev = dev;
-			break;
-		}
-		dev = dev->next;
-	} while (dev != eth_devices);
-
-	return target_dev;
-}
-
-int eth_get_dev_index(void)
-{
-	if (!eth_current)
-		return -1;
-
-	return eth_current->index;
-}
-
-static int on_ethaddr(const char *name, const char *value, enum env_op op,
-	int flags)
-{
-	int index;
-	struct eth_device *dev;
-
-	if (!eth_devices)
-		return 0;
-
-	/* look for an index after "eth" */
-	index = simple_strtoul(name + 3, NULL, 10);
-
-	dev = eth_devices;
-	do {
-		if (dev->index == index) {
-			switch (op) {
-			case env_op_create:
-			case env_op_overwrite:
-				eth_parse_enetaddr(value, dev->enetaddr);
-				break;
-			case env_op_delete:
-				memset(dev->enetaddr, 0, 6);
-			}
-		}
-		dev = dev->next;
-	} while (dev != eth_devices);
-
-	return 0;
-}
-U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
-
-int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
-		   int eth_number)
-{
-	unsigned char env_enetaddr[6];
-	int ret = 0;
-
-	eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
-
-	if (!is_zero_ethaddr(env_enetaddr)) {
-		if (!is_zero_ethaddr(dev->enetaddr) &&
-		    memcmp(dev->enetaddr, env_enetaddr, 6)) {
-			printf("\nWarning: %s MAC addresses don't match:\n",
-			       dev->name);
-			printf("Address in SROM is         %pM\n",
-			       dev->enetaddr);
-			printf("Address in environment is  %pM\n",
-			       env_enetaddr);
-		}
-
-		memcpy(dev->enetaddr, env_enetaddr, 6);
-	} else if (is_valid_ethaddr(dev->enetaddr)) {
-		eth_setenv_enetaddr_by_index(base_name, eth_number,
-					     dev->enetaddr);
-	} else if (is_zero_ethaddr(dev->enetaddr)) {
-#ifdef CONFIG_NET_RANDOM_ETHADDR
-		net_random_ethaddr(dev->enetaddr);
-		printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
-		       dev->name, eth_number, dev->enetaddr);
-#else
-		printf("\nError: %s address not set.\n",
-		       dev->name);
-		return -EINVAL;
-#endif
-	}
-
-	if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
-		if (!is_valid_ethaddr(dev->enetaddr)) {
-			printf("\nError: %s address %pM illegal value\n",
-			       dev->name, dev->enetaddr);
-			return -EINVAL;
-		}
-
-		ret = dev->write_hwaddr(dev);
-		if (ret)
-			printf("\nWarning: %s failed to set MAC address\n",
-			       dev->name);
-	}
-
-	return ret;
-}
-
-int eth_register(struct eth_device *dev)
-{
-	struct eth_device *d;
-	static int index;
-
-	assert(strlen(dev->name) < sizeof(dev->name));
-
-	if (!eth_devices) {
-		eth_devices = dev;
-		eth_current = dev;
-		eth_current_changed();
-	} else {
-		for (d = eth_devices; d->next != eth_devices; d = d->next)
-			;
-		d->next = dev;
-	}
-
-	dev->state = ETH_STATE_INIT;
-	dev->next  = eth_devices;
-	dev->index = index++;
-
-	return 0;
-}
-
-int eth_unregister(struct eth_device *dev)
-{
-	struct eth_device *cur;
-
-	/* No device */
-	if (!eth_devices)
-		return -ENODEV;
-
-	for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
-	     cur = cur->next)
-		;
-
-	/* Device not found */
-	if (cur->next != dev)
-		return -ENODEV;
-
-	cur->next = dev->next;
-
-	if (eth_devices == dev)
-		eth_devices = dev->next == eth_devices ? NULL : dev->next;
-
-	if (eth_current == dev) {
-		eth_current = eth_devices;
-		eth_current_changed();
-	}
-
-	return 0;
-}
-
-int eth_initialize(void)
-{
-	int num_devices = 0;
-
-	eth_devices = NULL;
-	eth_current = NULL;
-	eth_common_init();
-
-	if (!eth_devices) {
-		puts("No ethernet found.\n");
-		bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
-	} else {
-		struct eth_device *dev = eth_devices;
-		char *ethprime = getenv("ethprime");
-
-		bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
-		do {
-			if (dev->index)
-				puts(", ");
-
-			printf("%s", dev->name);
-
-			if (ethprime && strcmp(dev->name, ethprime) == 0) {
-				eth_current = dev;
-				puts(" [PRIME]");
-			}
-
-			if (strchr(dev->name, ' '))
-				puts("\nWarning: eth device name has a space!"
-					"\n");
-
-			eth_write_hwaddr(dev, "eth", dev->index);
-
-			dev = dev->next;
-			num_devices++;
-		} while (dev != eth_devices);
-
-		eth_current_changed();
-		putc('\n');
-	}
-
-	return num_devices;
-}
-
-#ifdef CONFIG_MCAST_TFTP
-/* Multicast.
- * mcast_addr: multicast ipaddr from which multicast Mac is made
- * join: 1=join, 0=leave.
- */
-int eth_mcast_join(struct in_addr mcast_ip, int join)
-{
-	u8 mcast_mac[6];
-	if (!eth_current || !eth_current->mcast)
-		return -1;
-	mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
-	mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
-	mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
-	mcast_mac[2] = 0x5e;
-	mcast_mac[1] = 0x0;
-	mcast_mac[0] = 0x1;
-	return eth_current->mcast(eth_current, mcast_mac, join);
-}
-
-/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
- * and this is the ethernet-crc method needed for TSEC -- and perhaps
- * some other adapter -- hash tables
- */
-#define CRCPOLY_LE 0xedb88320
-u32 ether_crc(size_t len, unsigned char const *p)
-{
-	int i;
-	u32 crc;
-	crc = ~0;
-	while (len--) {
-		crc ^= *p++;
-		for (i = 0; i < 8; i++)
-			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
-	}
-	/* an reverse the bits, cuz of way they arrive -- last-first */
-	crc = (crc >> 16) | (crc << 16);
-	crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
-	crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
-	crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
-	crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
-	return crc;
-}
-
-#endif
-
-
-int eth_init(void)
-{
-	struct eth_device *old_current;
-
-	if (!eth_current) {
-		puts("No ethernet found.\n");
-		return -ENODEV;
-	}
-
-	old_current = eth_current;
-	do {
-		debug("Trying %s\n", eth_current->name);
-
-		if (eth_current->init(eth_current, gd->bd) >= 0) {
-			eth_current->state = ETH_STATE_ACTIVE;
-
-			return 0;
-		}
-		debug("FAIL\n");
-
-		eth_try_another(0);
-	} while (old_current != eth_current);
-
-	return -ETIMEDOUT;
-}
-
-void eth_halt(void)
-{
-	if (!eth_current)
-		return;
-
-	eth_current->halt(eth_current);
-
-	eth_current->state = ETH_STATE_PASSIVE;
-}
-
-int eth_is_active(struct eth_device *dev)
-{
-	return dev && dev->state == ETH_STATE_ACTIVE;
-}
-
-int eth_send(void *packet, int length)
-{
-	if (!eth_current)
-		return -ENODEV;
-
-	return eth_current->send(eth_current, packet, length);
-}
-
-int eth_rx(void)
-{
-	if (!eth_current)
-		return -ENODEV;
-
-	return eth_current->recv(eth_current);
-}
-#endif /* ifndef CONFIG_DM_ETH */
-
-#ifdef CONFIG_API
-static void eth_save_packet(void *packet, int length)
-{
-	char *p = packet;
-	int i;
-
-	if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
-		return;
-
-	if (PKTSIZE < length)
-		return;
-
-	for (i = 0; i < length; i++)
-		eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
-
-	eth_rcv_bufs[eth_rcv_last].length = length;
-	eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
-}
-
-int eth_receive(void *packet, int length)
-{
-	char *p = packet;
-	void *pp = push_packet;
-	int i;
-
-	if (eth_rcv_current == eth_rcv_last) {
-		push_packet = eth_save_packet;
-		eth_rx();
-		push_packet = pp;
-
-		if (eth_rcv_current == eth_rcv_last)
-			return -1;
-	}
-
-	length = min(eth_rcv_bufs[eth_rcv_current].length, length);
-
-	for (i = 0; i < length; i++)
-		p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
-
-	eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
-	return length;
-}
-#endif /* CONFIG_API */
-
-static void eth_current_changed(void)
-{
-	char *act = getenv("ethact");
-	char *ethrotate;
-
-	/*
-	 * The call to eth_get_dev() below has a side effect of rotating
-	 * ethernet device if uc_priv->current == NULL. This is not what
-	 * we want when 'ethrotate' variable is 'no'.
-	 */
-	ethrotate = getenv("ethrotate");
-	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
-		return;
-
-	/* update current ethernet name */
-	if (eth_get_dev()) {
-		if (act == NULL || strcmp(act, eth_get_name()) != 0)
-			setenv("ethact", eth_get_name());
-	}
-	/*
-	 * remove the variable completely if there is no active
-	 * interface
-	 */
-	else if (act != NULL)
-		setenv("ethact", NULL);
-}
-
-void eth_try_another(int first_restart)
-{
-	static void *first_failed;
-	char *ethrotate;
-
-	/*
-	 * Do not rotate between network interfaces when
-	 * 'ethrotate' variable is set to 'no'.
-	 */
-	ethrotate = getenv("ethrotate");
-	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
-		return;
-
-	if (!eth_get_dev())
-		return;
-
-	if (first_restart)
-		first_failed = eth_get_dev();
-
-	eth_set_current_to_next();
-
-	eth_current_changed();
-
-	if (first_failed == eth_get_dev())
-		net_restart_wrap = 1;
-}
-
-void eth_set_current(void)
-{
-	static char *act;
-	static int  env_changed_id;
-	int	env_id;
-
-	env_id = get_env_id();
-	if ((act == NULL) || (env_changed_id != env_id)) {
-		act = getenv("ethact");
-		env_changed_id = env_id;
-	}
-
-	if (act == NULL) {
-		char *ethprime = getenv("ethprime");
-		void *dev = NULL;
-
-		if (ethprime)
-			dev = eth_get_dev_by_name(ethprime);
-		if (dev)
-			eth_set_dev(dev);
-		else
-			eth_set_dev(NULL);
-	} else {
-		eth_set_dev(eth_get_dev_by_name(act));
-	}
-
-	eth_current_changed();
-}
-
-const char *eth_get_name(void)
-{
-	return eth_get_dev() ? eth_get_dev()->name : "unknown";
-}

+ 166 - 0
net/eth_common.c

@@ -0,0 +1,166 @@
+/*
+ * (C) Copyright 2001-2015
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Joe Hershberger, National Instruments
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <miiphy.h>
+#include <net.h>
+#include "eth_internal.h"
+
+void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
+{
+	char *end;
+	int i;
+
+	for (i = 0; i < 6; ++i) {
+		enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
+		if (addr)
+			addr = (*end) ? end + 1 : end;
+	}
+}
+
+int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
+{
+	eth_parse_enetaddr(getenv(name), enetaddr);
+	return is_valid_ethaddr(enetaddr);
+}
+
+int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
+{
+	char buf[20];
+
+	sprintf(buf, "%pM", enetaddr);
+
+	return setenv(name, buf);
+}
+
+int eth_getenv_enetaddr_by_index(const char *base_name, int index,
+				 uchar *enetaddr)
+{
+	char enetvar[32];
+	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
+	return eth_getenv_enetaddr(enetvar, enetaddr);
+}
+
+int eth_setenv_enetaddr_by_index(const char *base_name, int index,
+				 uchar *enetaddr)
+{
+	char enetvar[32];
+	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
+	return eth_setenv_enetaddr(enetvar, enetaddr);
+}
+
+void eth_common_init(void)
+{
+	bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
+	miiphy_init();
+#endif
+
+#ifdef CONFIG_PHYLIB
+	phy_init();
+#endif
+}
+
+int eth_mac_skip(int index)
+{
+	char enetvar[15];
+	char *skip_state;
+
+	sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
+	skip_state = getenv(enetvar);
+	return skip_state != NULL;
+}
+
+void eth_current_changed(void)
+{
+	char *act = getenv("ethact");
+	char *ethrotate;
+
+	/*
+	 * The call to eth_get_dev() below has a side effect of rotating
+	 * ethernet device if uc_priv->current == NULL. This is not what
+	 * we want when 'ethrotate' variable is 'no'.
+	 */
+	ethrotate = getenv("ethrotate");
+	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
+		return;
+
+	/* update current ethernet name */
+	if (eth_get_dev()) {
+		if (act == NULL || strcmp(act, eth_get_name()) != 0)
+			setenv("ethact", eth_get_name());
+	}
+	/*
+	 * remove the variable completely if there is no active
+	 * interface
+	 */
+	else if (act != NULL)
+		setenv("ethact", NULL);
+}
+
+void eth_try_another(int first_restart)
+{
+	static void *first_failed;
+	char *ethrotate;
+
+	/*
+	 * Do not rotate between network interfaces when
+	 * 'ethrotate' variable is set to 'no'.
+	 */
+	ethrotate = getenv("ethrotate");
+	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
+		return;
+
+	if (!eth_get_dev())
+		return;
+
+	if (first_restart)
+		first_failed = eth_get_dev();
+
+	eth_set_current_to_next();
+
+	eth_current_changed();
+
+	if (first_failed == eth_get_dev())
+		net_restart_wrap = 1;
+}
+
+void eth_set_current(void)
+{
+	static char *act;
+	static int  env_changed_id;
+	int	env_id;
+
+	env_id = get_env_id();
+	if ((act == NULL) || (env_changed_id != env_id)) {
+		act = getenv("ethact");
+		env_changed_id = env_id;
+	}
+
+	if (act == NULL) {
+		char *ethprime = getenv("ethprime");
+		void *dev = NULL;
+
+		if (ethprime)
+			dev = eth_get_dev_by_name(ethprime);
+		if (dev)
+			eth_set_dev(dev);
+		else
+			eth_set_dev(NULL);
+	} else {
+		eth_set_dev(eth_get_dev_by_name(act));
+	}
+
+	eth_current_changed();
+}
+
+const char *eth_get_name(void)
+{
+	return eth_get_dev() ? eth_get_dev()->name : "unknown";
+}

+ 40 - 0
net/eth_internal.h

@@ -0,0 +1,40 @@
+/*
+ * (C) Copyright 2001-2015
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Joe Hershberger, National Instruments
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __ETH_INTERNAL_H
+#define __ETH_INTERNAL_H
+
+/* Do init that is common to driver model and legacy networking */
+void eth_common_init(void);
+
+/**
+ * eth_setenv_enetaddr_by_index() - set the MAC address envrionment variable
+ *
+ * This sets up an environment variable with the given MAC address (@enetaddr).
+ * The environment variable to be set is defined by <@base_name><@index>addr.
+ * If @index is 0 it is omitted. For common Ethernet this means ethaddr,
+ * eth1addr, etc.
+ *
+ * @base_name:	Base name for variable, typically "eth"
+ * @index:	Index of interface being updated (>=0)
+ * @enetaddr:	Pointer to MAC address to put into the variable
+ * @return 0 if OK, other value on error
+ */
+int eth_setenv_enetaddr_by_index(const char *base_name, int index,
+				 uchar *enetaddr);
+
+int eth_mac_skip(int index);
+void eth_current_changed(void);
+#ifdef CONFIG_DM_ETH
+void eth_set_dev(struct udevice *dev);
+#else
+void eth_set_dev(struct eth_device *dev);
+#endif
+void eth_set_current_to_next(void);
+
+#endif

+ 439 - 0
net/eth_legacy.c

@@ -0,0 +1,439 @@
+/*
+ * (C) Copyright 2001-2015
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Joe Hershberger, National Instruments
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <net.h>
+#include <phy.h>
+#include <asm/errno.h>
+#include "eth_internal.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * CPU and board-specific Ethernet initializations.  Aliased function
+ * signals caller to move on
+ */
+static int __def_eth_init(bd_t *bis)
+{
+	return -1;
+}
+int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
+int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
+
+#ifdef CONFIG_API
+static struct {
+	uchar data[PKTSIZE];
+	int length;
+} eth_rcv_bufs[PKTBUFSRX];
+
+static unsigned int eth_rcv_current, eth_rcv_last;
+#endif
+
+static struct eth_device *eth_devices;
+struct eth_device *eth_current;
+
+void eth_set_current_to_next(void)
+{
+	eth_current = eth_current->next;
+}
+
+void eth_set_dev(struct eth_device *dev)
+{
+	eth_current = dev;
+}
+
+struct eth_device *eth_get_dev_by_name(const char *devname)
+{
+	struct eth_device *dev, *target_dev;
+
+	BUG_ON(devname == NULL);
+
+	if (!eth_devices)
+		return NULL;
+
+	dev = eth_devices;
+	target_dev = NULL;
+	do {
+		if (strcmp(devname, dev->name) == 0) {
+			target_dev = dev;
+			break;
+		}
+		dev = dev->next;
+	} while (dev != eth_devices);
+
+	return target_dev;
+}
+
+struct eth_device *eth_get_dev_by_index(int index)
+{
+	struct eth_device *dev, *target_dev;
+
+	if (!eth_devices)
+		return NULL;
+
+	dev = eth_devices;
+	target_dev = NULL;
+	do {
+		if (dev->index == index) {
+			target_dev = dev;
+			break;
+		}
+		dev = dev->next;
+	} while (dev != eth_devices);
+
+	return target_dev;
+}
+
+int eth_get_dev_index(void)
+{
+	if (!eth_current)
+		return -1;
+
+	return eth_current->index;
+}
+
+static int on_ethaddr(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	int index;
+	struct eth_device *dev;
+
+	if (!eth_devices)
+		return 0;
+
+	/* look for an index after "eth" */
+	index = simple_strtoul(name + 3, NULL, 10);
+
+	dev = eth_devices;
+	do {
+		if (dev->index == index) {
+			switch (op) {
+			case env_op_create:
+			case env_op_overwrite:
+				eth_parse_enetaddr(value, dev->enetaddr);
+				break;
+			case env_op_delete:
+				memset(dev->enetaddr, 0, 6);
+			}
+		}
+		dev = dev->next;
+	} while (dev != eth_devices);
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
+
+int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
+		   int eth_number)
+{
+	unsigned char env_enetaddr[6];
+	int ret = 0;
+
+	eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
+
+	if (!is_zero_ethaddr(env_enetaddr)) {
+		if (!is_zero_ethaddr(dev->enetaddr) &&
+		    memcmp(dev->enetaddr, env_enetaddr, 6)) {
+			printf("\nWarning: %s MAC addresses don't match:\n",
+			       dev->name);
+			printf("Address in SROM is         %pM\n",
+			       dev->enetaddr);
+			printf("Address in environment is  %pM\n",
+			       env_enetaddr);
+		}
+
+		memcpy(dev->enetaddr, env_enetaddr, 6);
+	} else if (is_valid_ethaddr(dev->enetaddr)) {
+		eth_setenv_enetaddr_by_index(base_name, eth_number,
+					     dev->enetaddr);
+	} else if (is_zero_ethaddr(dev->enetaddr)) {
+#ifdef CONFIG_NET_RANDOM_ETHADDR
+		net_random_ethaddr(dev->enetaddr);
+		printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
+		       dev->name, eth_number, dev->enetaddr);
+#else
+		printf("\nError: %s address not set.\n",
+		       dev->name);
+		return -EINVAL;
+#endif
+	}
+
+	if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
+		if (!is_valid_ethaddr(dev->enetaddr)) {
+			printf("\nError: %s address %pM illegal value\n",
+			       dev->name, dev->enetaddr);
+			return -EINVAL;
+		}
+
+		ret = dev->write_hwaddr(dev);
+		if (ret)
+			printf("\nWarning: %s failed to set MAC address\n",
+			       dev->name);
+	}
+
+	return ret;
+}
+
+int eth_register(struct eth_device *dev)
+{
+	struct eth_device *d;
+	static int index;
+
+	assert(strlen(dev->name) < sizeof(dev->name));
+
+	if (!eth_devices) {
+		eth_devices = dev;
+		eth_current = dev;
+		eth_current_changed();
+	} else {
+		for (d = eth_devices; d->next != eth_devices; d = d->next)
+			;
+		d->next = dev;
+	}
+
+	dev->state = ETH_STATE_INIT;
+	dev->next  = eth_devices;
+	dev->index = index++;
+
+	return 0;
+}
+
+int eth_unregister(struct eth_device *dev)
+{
+	struct eth_device *cur;
+
+	/* No device */
+	if (!eth_devices)
+		return -ENODEV;
+
+	for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
+	     cur = cur->next)
+		;
+
+	/* Device not found */
+	if (cur->next != dev)
+		return -ENODEV;
+
+	cur->next = dev->next;
+
+	if (eth_devices == dev)
+		eth_devices = dev->next == eth_devices ? NULL : dev->next;
+
+	if (eth_current == dev) {
+		eth_current = eth_devices;
+		eth_current_changed();
+	}
+
+	return 0;
+}
+
+int eth_initialize(void)
+{
+	int num_devices = 0;
+
+	eth_devices = NULL;
+	eth_current = NULL;
+	eth_common_init();
+	/*
+	 * If board-specific initialization exists, call it.
+	 * If not, call a CPU-specific one
+	 */
+	if (board_eth_init != __def_eth_init) {
+		if (board_eth_init(gd->bd) < 0)
+			printf("Board Net Initialization Failed\n");
+	} else if (cpu_eth_init != __def_eth_init) {
+		if (cpu_eth_init(gd->bd) < 0)
+			printf("CPU Net Initialization Failed\n");
+	} else {
+		printf("Net Initialization Skipped\n");
+	}
+
+	if (!eth_devices) {
+		puts("No ethernet found.\n");
+		bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
+	} else {
+		struct eth_device *dev = eth_devices;
+		char *ethprime = getenv("ethprime");
+
+		bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
+		do {
+			if (dev->index)
+				puts(", ");
+
+			printf("%s", dev->name);
+
+			if (ethprime && strcmp(dev->name, ethprime) == 0) {
+				eth_current = dev;
+				puts(" [PRIME]");
+			}
+
+			if (strchr(dev->name, ' '))
+				puts("\nWarning: eth device name has a space!"
+					"\n");
+
+			eth_write_hwaddr(dev, "eth", dev->index);
+
+			dev = dev->next;
+			num_devices++;
+		} while (dev != eth_devices);
+
+		eth_current_changed();
+		putc('\n');
+	}
+
+	return num_devices;
+}
+
+#ifdef CONFIG_MCAST_TFTP
+/* Multicast.
+ * mcast_addr: multicast ipaddr from which multicast Mac is made
+ * join: 1=join, 0=leave.
+ */
+int eth_mcast_join(struct in_addr mcast_ip, int join)
+{
+	u8 mcast_mac[6];
+	if (!eth_current || !eth_current->mcast)
+		return -1;
+	mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
+	mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
+	mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
+	mcast_mac[2] = 0x5e;
+	mcast_mac[1] = 0x0;
+	mcast_mac[0] = 0x1;
+	return eth_current->mcast(eth_current, mcast_mac, join);
+}
+
+/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
+ * and this is the ethernet-crc method needed for TSEC -- and perhaps
+ * some other adapter -- hash tables
+ */
+#define CRCPOLY_LE 0xedb88320
+u32 ether_crc(size_t len, unsigned char const *p)
+{
+	int i;
+	u32 crc;
+	crc = ~0;
+	while (len--) {
+		crc ^= *p++;
+		for (i = 0; i < 8; i++)
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+	}
+	/* an reverse the bits, cuz of way they arrive -- last-first */
+	crc = (crc >> 16) | (crc << 16);
+	crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
+	crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
+	crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
+	crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
+	return crc;
+}
+
+#endif
+
+
+int eth_init(void)
+{
+	struct eth_device *old_current;
+
+	if (!eth_current) {
+		puts("No ethernet found.\n");
+		return -ENODEV;
+	}
+
+	old_current = eth_current;
+	do {
+		debug("Trying %s\n", eth_current->name);
+
+		if (eth_current->init(eth_current, gd->bd) >= 0) {
+			eth_current->state = ETH_STATE_ACTIVE;
+
+			return 0;
+		}
+		debug("FAIL\n");
+
+		eth_try_another(0);
+	} while (old_current != eth_current);
+
+	return -ETIMEDOUT;
+}
+
+void eth_halt(void)
+{
+	if (!eth_current)
+		return;
+
+	eth_current->halt(eth_current);
+
+	eth_current->state = ETH_STATE_PASSIVE;
+}
+
+int eth_is_active(struct eth_device *dev)
+{
+	return dev && dev->state == ETH_STATE_ACTIVE;
+}
+
+int eth_send(void *packet, int length)
+{
+	if (!eth_current)
+		return -ENODEV;
+
+	return eth_current->send(eth_current, packet, length);
+}
+
+int eth_rx(void)
+{
+	if (!eth_current)
+		return -ENODEV;
+
+	return eth_current->recv(eth_current);
+}
+
+#ifdef CONFIG_API
+static void eth_save_packet(void *packet, int length)
+{
+	char *p = packet;
+	int i;
+
+	if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
+		return;
+
+	if (PKTSIZE < length)
+		return;
+
+	for (i = 0; i < length; i++)
+		eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
+
+	eth_rcv_bufs[eth_rcv_last].length = length;
+	eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
+}
+
+int eth_receive(void *packet, int length)
+{
+	char *p = packet;
+	void *pp = push_packet;
+	int i;
+
+	if (eth_rcv_current == eth_rcv_last) {
+		push_packet = eth_save_packet;
+		eth_rx();
+		push_packet = pp;
+
+		if (eth_rcv_current == eth_rcv_last)
+			return -1;
+	}
+
+	length = min(eth_rcv_bufs[eth_rcv_current].length, length);
+
+	for (i = 0; i < length; i++)
+		p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
+
+	eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
+	return length;
+}
+#endif /* CONFIG_API */