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;
}
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;
fsl_pq_mdio_init(bis, &mdio_info);
tsec_eth_init(bis, tsec_info, num);
+#endif
#ifdef CONFIG_PCI
pci_eth_init(bis);
return 0;
}
-#endif
#define USBMUX_SEL_MASK 0xc0
#define USBMUX_SEL_UART2 0xc0
}
#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;
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)
}
#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;
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)
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;
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)
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;
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)
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;
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)
#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)
{
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;
.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 = ðsw_port_aggr_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_aggr,
+ ethsw_id_help,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_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,
},
};
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;
}, {
.keyword_name = "filtering",
.match = &keyword_match_gen,
+ }, {
+ .keyword_name = "aggr",
+ .match = &keyword_match_aggr,
},
};
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)
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 */
}
#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",
ETHSW_EGR_VLAN_TAG_HELP"\n"
ETHSW_VLAN_FDB_HELP"\n"
ETHSW_PORT_INGR_FLTR_HELP"\n"
+ ETHSW_PORT_AGGR_HELP"\n"
);
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
--- /dev/null
+* 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>;
+ };
+ };
--- /dev/null
+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.
if (phydev->speed != 1000)
conf |= MII_PORTSELECT;
+ else
+ conf &= ~MII_PORTSELECT;
if (phydev->speed == 100)
conf |= FES_100;
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;
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;
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);
{
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;
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;
}
char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
u32 interface;
+ u32 max_speed;
u32 tx_currdescnum;
u32 rx_currdescnum;
*
* SPDX-License-Identifier: GPL-2.0+
*/
+
#include <common.h>
#include <miiphy.h>
#include <phy.h>
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 */
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;
MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
.config = &cs4340_config,
+ .probe = &cs4340_probe,
.startup = &cs4340_startup,
.shutdown = &gen10g_shutdown,
};
.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,
};
.uid = 0x221560,
.mask = 0xfffff0,
.features = PHY_BASIC_FEATURES,
- .config = &genphy_config,
+ .config = &ksz_genconfig_bcastoff,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
{
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;
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;
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;
}
static int genphy_setup_forced(struct phy_device *phydev)
{
int err;
- int ctl = 0;
+ int ctl = BMCR_ANRESTART;
phydev->pause = phydev->asym_pause = 0;
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",
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;
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);
features |= SUPPORTED_1000baseX_Half;
}
- phydev->supported = features;
- phydev->advertising = features;
+ phydev->supported &= features;
+ phydev->advertising &= features;
genphy_config_aneg(phydev);
.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,
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;
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)) {
}
#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;
}
* 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);
/*
* 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>
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[] = {
STD_TSEC_INFO(4), /* TSEC4 */
#endif
};
+#endif /* CONFIG_DM_ETH */
#define TBIANA_SETTINGS ( \
TBIANA_ASYMMETRIC_PAUSE \
/* 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),
/* 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.
* 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;
}
#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)
*/
}
-/* 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)
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)
(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(®s->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(®s->ievent) & IEVENT_BSY) {
+ out_be32(®s->ievent, IEVENT_BSY);
+ out_be32(®s->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(®s->ievent) & IEVENT_BSY) {
+ out_be32(®s->ievent, IEVENT_BSY);
+ out_be32(®s->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(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+ setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+
+ while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
+ != (IEVENT_GRSC | IEVENT_GTSC))
+ ;
+
+ clrbits_be32(®s->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;
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(®s->ievent) & IEVENT_BSY) {
out_be32(®s->ievent, IEVENT_BSY);
}
#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(®s->tbase, (u32)&txbd[0]);
- out_be32(®s->rbase, (u32)&rxbd[0]);
+ out_be32(®s->tbase, (u32)&priv->txbd[0]);
+ out_be32(®s->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(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
clrbits_be32(®s->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(®s->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(®s->ievent) & IEVENT_BSY) {
- out_be32(®s->ievent, IEVENT_BSY);
- out_be32(®s->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(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
- setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
-
- while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
- != (IEVENT_GRSC | IEVENT_GTSC))
- ;
-
- clrbits_be32(®s->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;
/* Init ECNTRL */
out_be32(®s->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(®s->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(®s->macstnaddr2, tempval);
init_registers(regs);
/* Ready the device for tx/rx */
- startup_tsec(dev);
+ startup_tsec(priv);
/* Start up the PHY */
ret = phy_startup(priv->phydev);
* 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;
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 |
supported |= SUPPORTED_1000baseT_Full;
/* Assign a Physical address to the TBI */
- out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE);
+ out_be32(®s->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;
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)
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;
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;
clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
/* Try to initialize PHY here, and return */
- return init_phy(dev);
+ return init_phy(priv);
}
/*
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 */
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,
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 */
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;
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,
.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 */
{
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);
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)
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) {
#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 {
ethsw_id_private,
ethsw_id_ingress,
ethsw_id_filtering,
+ ethsw_id_aggr,
ethsw_id_count, /* keep last */
};
ethsw_id_pvid_no,
ethsw_id_add_del_no,
ethsw_id_add_del_mac,
+ ethsw_id_aggr_no,
ethsw_id_count_all, /* keep last */
};
int cmd_keywords_nr;
int port;
int vid;
+ int aggr_grp;
uchar ethaddr[6];
int (*cmd_function)(struct ethsw_command_def *parsed_cmd);
};
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);
*
* SPDX-License-Identifier: GPL-2.0+
*/
+
#ifndef __FSL_PHY_H__
#define __FSL_PHY_H__
#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
* @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 {
#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)
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);
*
* 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
#include <config.h>
#include <phy.h>
+#ifndef CONFIG_DM_ETH
+
#ifdef CONFIG_LS102XA
#define TSEC_SIZE 0x40000
#define TSEC_MDIO_OFFSET 0x40000
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
/* 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
#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
#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
#define TSTAT_CLEAR_THALT 0x80000000
#define RSTAT_CLEAR_RHALT 0x00800000
-
#define IEVENT_INIT_CLEAR 0xffffffff
#define IEVENT_BABR 0x80000000
#define IEVENT_RXC 0x40000000
#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
#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
#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 {
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) */
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 {
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 */
#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
/* 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
/* 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)
#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"
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];
};
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];
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
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
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:
/*
--- /dev/null
+/*
+ * (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 <environment.h>
+#include <net.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include "eth_internal.h"
+
+/**
+ * struct eth_device_priv - private structure for each Ethernet device
+ *
+ * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t)
+ */
+struct eth_device_priv {
+ enum eth_state_t state;
+};
+
+/**
+ * struct eth_uclass_priv - The structure attached to the uclass itself
+ *
+ * @current: The Ethernet device that the network functions are using
+ */
+struct eth_uclass_priv {
+ struct udevice *current;
+};
+
+/* eth_errno - This stores the most recent failure code from DM functions */
+static int eth_errno;
+
+static struct eth_uclass_priv *eth_get_uclass_priv(void)
+{
+ struct uclass *uc;
+
+ uclass_get(UCLASS_ETH, &uc);
+ assert(uc);
+ return uc->priv;
+}
+
+void eth_set_current_to_next(void)
+{
+ struct eth_uclass_priv *uc_priv;
+
+ uc_priv = eth_get_uclass_priv();
+ if (uc_priv->current)
+ uclass_next_device(&uc_priv->current);
+ if (!uc_priv->current)
+ uclass_first_device(UCLASS_ETH, &uc_priv->current);
+}
+
+/*
+ * Typically this will simply return the active device.
+ * In the case where the most recent active device was unset, this will attempt
+ * to return the first device. If that device doesn't exist or fails to probe,
+ * this function will return NULL.
+ */
+struct udevice *eth_get_dev(void)
+{
+ struct eth_uclass_priv *uc_priv;
+
+ uc_priv = eth_get_uclass_priv();
+ if (!uc_priv->current)
+ eth_errno = uclass_first_device(UCLASS_ETH,
+ &uc_priv->current);
+ return uc_priv->current;
+}
+
+/*
+ * Typically this will just store a device pointer.
+ * In case it was not probed, we will attempt to do so.
+ * dev may be NULL to unset the active device.
+ */
+void eth_set_dev(struct udevice *dev)
+{
+ if (dev && !device_active(dev)) {
+ eth_errno = device_probe(dev);
+ if (eth_errno)
+ dev = NULL;
+ }
+
+ eth_get_uclass_priv()->current = dev;
+}
+
+/*
+ * Find the udevice that either has the name passed in as devname or has an
+ * alias named devname.
+ */
+struct udevice *eth_get_dev_by_name(const char *devname)
+{
+ int seq = -1;
+ char *endp = NULL;
+ const char *startp = NULL;
+ struct udevice *it;
+ struct uclass *uc;
+ int len = strlen("eth");
+
+ /* Must be longer than 3 to be an alias */
+ if (!strncmp(devname, "eth", len) && strlen(devname) > len) {
+ startp = devname + len;
+ seq = simple_strtoul(startp, &endp, 10);
+ }
+
+ uclass_get(UCLASS_ETH, &uc);
+ uclass_foreach_dev(it, uc) {
+ /*
+ * We need the seq to be valid, so try to probe it.
+ * If the probe fails, the seq will not match since it will be
+ * -1 instead of what we are looking for.
+ * We don't care about errors from probe here. Either they won't
+ * match an alias or it will match a literal name and we'll pick
+ * up the error when we try to probe again in eth_set_dev().
+ */
+ if (device_probe(it))
+ continue;
+ /* Check for the name or the sequence number to match */
+ if (strcmp(it->name, devname) == 0 ||
+ (endp > startp && it->seq == seq))
+ return it;
+ }
+
+ return NULL;
+}
+
+unsigned char *eth_get_ethaddr(void)
+{
+ struct eth_pdata *pdata;
+
+ if (eth_get_dev()) {
+ pdata = eth_get_dev()->platdata;
+ return pdata->enetaddr;
+ }
+
+ return NULL;
+}
+
+/* Set active state without calling start on the driver */
+int eth_init_state_only(void)
+{
+ struct udevice *current;
+ struct eth_device_priv *priv;
+
+ current = eth_get_dev();
+ if (!current || !device_active(current))
+ return -EINVAL;
+
+ priv = current->uclass_priv;
+ priv->state = ETH_STATE_ACTIVE;
+
+ return 0;
+}
+
+/* Set passive state without calling stop on the driver */
+void eth_halt_state_only(void)
+{
+ struct udevice *current;
+ struct eth_device_priv *priv;
+
+ current = eth_get_dev();
+ if (!current || !device_active(current))
+ return;
+
+ priv = current->uclass_priv;
+ priv->state = ETH_STATE_PASSIVE;
+}
+
+int eth_get_dev_index(void)
+{
+ if (eth_get_dev())
+ return eth_get_dev()->seq;
+ return -1;
+}
+
+static int eth_write_hwaddr(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev->platdata;
+ int ret = 0;
+
+ if (!dev || !device_active(dev))
+ return -EINVAL;
+
+ /* seq is valid since the device is active */
+ if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) {
+ if (!is_valid_ethaddr(pdata->enetaddr)) {
+ printf("\nError: %s address %pM illegal value\n",
+ dev->name, pdata->enetaddr);
+ return -EINVAL;
+ }
+
+ /*
+ * Drivers are allowed to decide not to implement this at
+ * run-time. E.g. Some devices may use it and some may not.
+ */
+ ret = eth_get_ops(dev)->write_hwaddr(dev);
+ if (ret == -ENOSYS)
+ ret = 0;
+ if (ret)
+ printf("\nWarning: %s failed to set MAC address\n",
+ dev->name);
+ }
+
+ return ret;
+}
+
+static int on_ethaddr(const char *name, const char *value, enum env_op op,
+ int flags)
+{
+ int index;
+ int retval;
+ struct udevice *dev;
+
+ /* look for an index after "eth" */
+ index = simple_strtoul(name + 3, NULL, 10);
+
+ retval = uclass_find_device_by_seq(UCLASS_ETH, index, false, &dev);
+ if (!retval) {
+ struct eth_pdata *pdata = dev->platdata;
+ switch (op) {
+ case env_op_create:
+ case env_op_overwrite:
+ eth_parse_enetaddr(value, pdata->enetaddr);
+ break;
+ case env_op_delete:
+ memset(pdata->enetaddr, 0, 6);
+ }
+ }
+
+ return 0;
+}
+U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
+
+int eth_init(void)
+{
+ char *ethact = getenv("ethact");
+ char *ethrotate = getenv("ethrotate");
+ struct udevice *current = NULL;
+ struct udevice *old_current;
+ int ret = -ENODEV;
+
+ /*
+ * When 'ethrotate' variable is set to 'no' and 'ethact' variable
+ * is already set to an ethernet device, we should stick to 'ethact'.
+ */
+ if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) {
+ if (ethact) {
+ current = eth_get_dev_by_name(ethact);
+ if (!current)
+ return -EINVAL;
+ }
+ }
+
+ if (!current) {
+ current = eth_get_dev();
+ if (!current) {
+ printf("No ethernet found.\n");
+ return -ENODEV;
+ }
+ }
+
+ old_current = current;
+ do {
+ if (current) {
+ debug("Trying %s\n", current->name);
+
+ if (device_active(current)) {
+ ret = eth_get_ops(current)->start(current);
+ if (ret >= 0) {
+ struct eth_device_priv *priv =
+ current->uclass_priv;
+
+ priv->state = ETH_STATE_ACTIVE;
+ return 0;
+ }
+ } else {
+ ret = eth_errno;
+ }
+
+ debug("FAIL\n");
+ } else {
+ debug("PROBE FAIL\n");
+ }
+
+ /*
+ * If ethrotate is enabled, this will change "current",
+ * otherwise we will drop out of this while loop immediately
+ */
+ eth_try_another(0);
+ /* This will ensure the new "current" attempted to probe */
+ current = eth_get_dev();
+ } while (old_current != current);
+
+ return ret;
+}
+
+void eth_halt(void)
+{
+ struct udevice *current;
+ struct eth_device_priv *priv;
+
+ current = eth_get_dev();
+ if (!current || !device_active(current))
+ return;
+
+ eth_get_ops(current)->stop(current);
+ priv = current->uclass_priv;
+ priv->state = ETH_STATE_PASSIVE;
+}
+
+int eth_is_active(struct udevice *dev)
+{
+ struct eth_device_priv *priv;
+
+ if (!dev || !device_active(dev))
+ return 0;
+
+ priv = dev_get_uclass_priv(dev);
+ return priv->state == ETH_STATE_ACTIVE;
+}
+
+int eth_send(void *packet, int length)
+{
+ struct udevice *current;
+ int ret;
+
+ current = eth_get_dev();
+ if (!current)
+ return -ENODEV;
+
+ if (!device_active(current))
+ return -EINVAL;
+
+ ret = eth_get_ops(current)->send(current, packet, length);
+ if (ret < 0) {
+ /* We cannot completely return the error at present */
+ debug("%s: send() returned error %d\n", __func__, ret);
+ }
+ return ret;
+}
+
+int eth_rx(void)
+{
+ struct udevice *current;
+ uchar *packet;
+ int flags;
+ int ret;
+ int i;
+
+ current = eth_get_dev();
+ if (!current)
+ return -ENODEV;
+
+ if (!device_active(current))
+ return -EINVAL;
+
+ /* Process up to 32 packets at one time */
+ flags = ETH_RECV_CHECK_DEVICE;
+ for (i = 0; i < 32; i++) {
+ ret = eth_get_ops(current)->recv(current, flags, &packet);
+ flags = 0;
+ if (ret > 0)
+ net_process_received_packet(packet, ret);
+ if (ret >= 0 && eth_get_ops(current)->free_pkt)
+ eth_get_ops(current)->free_pkt(current, packet, ret);
+ if (ret <= 0)
+ break;
+ }
+ if (ret == -EAGAIN)
+ ret = 0;
+ if (ret < 0) {
+ /* We cannot completely return the error at present */
+ debug("%s: recv() returned error %d\n", __func__, ret);
+ }
+ return ret;
+}
+
+int eth_initialize(void)
+{
+ int num_devices = 0;
+ struct udevice *dev;
+
+ eth_common_init();
+
+ /*
+ * Devices need to write the hwaddr even if not started so that Linux
+ * will have access to the hwaddr that u-boot stored for the device.
+ * This is accomplished by attempting to probe each device and calling
+ * their write_hwaddr() operation.
+ */
+ uclass_first_device(UCLASS_ETH, &dev);
+ if (!dev) {
+ printf("No ethernet found.\n");
+ bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
+ } else {
+ char *ethprime = getenv("ethprime");
+ struct udevice *prime_dev = NULL;
+
+ if (ethprime)
+ prime_dev = eth_get_dev_by_name(ethprime);
+ if (prime_dev) {
+ eth_set_dev(prime_dev);
+ eth_current_changed();
+ } else {
+ eth_set_dev(NULL);
+ }
+
+ bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
+ do {
+ if (num_devices)
+ printf(", ");
+
+ printf("eth%d: %s", dev->seq, dev->name);
+
+ if (ethprime && dev == prime_dev)
+ printf(" [PRIME]");
+
+ eth_write_hwaddr(dev);
+
+ uclass_next_device(&dev);
+ num_devices++;
+ } while (dev);
+
+ putc('\n');
+ }
+
+ return num_devices;
+}
+
+static int eth_post_bind(struct udevice *dev)
+{
+ if (strchr(dev->name, ' ')) {
+ printf("\nError: eth device name \"%s\" has a space!\n",
+ dev->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int eth_pre_unbind(struct udevice *dev)
+{
+ /* Don't hang onto a pointer that is going away */
+ if (dev == eth_get_uclass_priv()->current)
+ eth_set_dev(NULL);
+
+ return 0;
+}
+
+static int eth_post_probe(struct udevice *dev)
+{
+ struct eth_device_priv *priv = dev->uclass_priv;
+ struct eth_pdata *pdata = dev->platdata;
+ unsigned char env_enetaddr[6];
+
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ struct eth_ops *ops = eth_get_ops(dev);
+ static int reloc_done;
+
+ if (!reloc_done) {
+ if (ops->start)
+ ops->start += gd->reloc_off;
+ if (ops->send)
+ ops->send += gd->reloc_off;
+ if (ops->recv)
+ ops->recv += gd->reloc_off;
+ if (ops->free_pkt)
+ ops->free_pkt += gd->reloc_off;
+ if (ops->stop)
+ ops->stop += gd->reloc_off;
+#ifdef CONFIG_MCAST_TFTP
+ if (ops->mcast)
+ ops->mcast += gd->reloc_off;
+#endif
+ if (ops->write_hwaddr)
+ ops->write_hwaddr += gd->reloc_off;
+ if (ops->read_rom_hwaddr)
+ ops->read_rom_hwaddr += gd->reloc_off;
+
+ reloc_done++;
+ }
+#endif
+
+ priv->state = ETH_STATE_INIT;
+
+ /* Check if the device has a MAC address in ROM */
+ if (eth_get_ops(dev)->read_rom_hwaddr)
+ eth_get_ops(dev)->read_rom_hwaddr(dev);
+
+ eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
+ if (!is_zero_ethaddr(env_enetaddr)) {
+ if (!is_zero_ethaddr(pdata->enetaddr) &&
+ memcmp(pdata->enetaddr, env_enetaddr, 6)) {
+ printf("\nWarning: %s MAC addresses don't match:\n",
+ dev->name);
+ printf("Address in SROM is %pM\n",
+ pdata->enetaddr);
+ printf("Address in environment is %pM\n",
+ env_enetaddr);
+ }
+
+ /* Override the ROM MAC address */
+ memcpy(pdata->enetaddr, env_enetaddr, 6);
+ } else if (is_valid_ethaddr(pdata->enetaddr)) {
+ eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
+ printf("\nWarning: %s using MAC address from ROM\n",
+ dev->name);
+ } else if (is_zero_ethaddr(pdata->enetaddr)) {
+#ifdef CONFIG_NET_RANDOM_ETHADDR
+ net_random_ethaddr(pdata->enetaddr);
+ printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
+ dev->name, dev->seq, pdata->enetaddr);
+#else
+ printf("\nError: %s address not set.\n",
+ dev->name);
+ return -EINVAL;
+#endif
+ }
+
+ return 0;
+}
+
+static int eth_pre_remove(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev->platdata;
+
+ eth_get_ops(dev)->stop(dev);
+
+ /* clear the MAC address */
+ memset(pdata->enetaddr, 0, 6);
+
+ return 0;
+}
+
+UCLASS_DRIVER(eth) = {
+ .name = "eth",
+ .id = UCLASS_ETH,
+ .post_bind = eth_post_bind,
+ .pre_unbind = eth_pre_unbind,
+ .post_probe = eth_post_probe,
+ .pre_remove = eth_pre_remove,
+ .priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
+ .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+};
+++ /dev/null
-/*
- * (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 <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>
-
-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
- *
- * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t)
- */
-struct eth_device_priv {
- enum eth_state_t state;
-};
-
-/**
- * struct eth_uclass_priv - The structure attached to the uclass itself
- *
- * @current: The Ethernet device that the network functions are using
- */
-struct eth_uclass_priv {
- struct udevice *current;
-};
-
-/* eth_errno - This stores the most recent failure code from DM functions */
-static int eth_errno;
-
-static struct eth_uclass_priv *eth_get_uclass_priv(void)
-{
- struct uclass *uc;
-
- uclass_get(UCLASS_ETH, &uc);
- assert(uc);
- return uc->priv;
-}
-
-static void eth_set_current_to_next(void)
-{
- struct eth_uclass_priv *uc_priv;
-
- uc_priv = eth_get_uclass_priv();
- if (uc_priv->current)
- uclass_next_device(&uc_priv->current);
- if (!uc_priv->current)
- uclass_first_device(UCLASS_ETH, &uc_priv->current);
-}
-
-/*
- * Typically this will simply return the active device.
- * In the case where the most recent active device was unset, this will attempt
- * to return the first device. If that device doesn't exist or fails to probe,
- * this function will return NULL.
- */
-struct udevice *eth_get_dev(void)
-{
- struct eth_uclass_priv *uc_priv;
-
- uc_priv = eth_get_uclass_priv();
- if (!uc_priv->current)
- eth_errno = uclass_first_device(UCLASS_ETH,
- &uc_priv->current);
- return uc_priv->current;
-}
-
-/*
- * Typically this will just store a device pointer.
- * 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)
-{
- if (dev && !device_active(dev)) {
- eth_errno = device_probe(dev);
- if (eth_errno)
- dev = NULL;
- }
-
- eth_get_uclass_priv()->current = dev;
-}
-
-/*
- * Find the udevice that either has the name passed in as devname or has an
- * alias named devname.
- */
-struct udevice *eth_get_dev_by_name(const char *devname)
-{
- int seq = -1;
- char *endp = NULL;
- const char *startp = NULL;
- struct udevice *it;
- struct uclass *uc;
- int len = strlen("eth");
-
- /* Must be longer than 3 to be an alias */
- if (!strncmp(devname, "eth", len) && strlen(devname) > len) {
- startp = devname + len;
- seq = simple_strtoul(startp, &endp, 10);
- }
-
- uclass_get(UCLASS_ETH, &uc);
- uclass_foreach_dev(it, uc) {
- /*
- * We need the seq to be valid, so try to probe it.
- * If the probe fails, the seq will not match since it will be
- * -1 instead of what we are looking for.
- * We don't care about errors from probe here. Either they won't
- * match an alias or it will match a literal name and we'll pick
- * up the error when we try to probe again in eth_set_dev().
- */
- if (device_probe(it))
- continue;
- /* Check for the name or the sequence number to match */
- if (strcmp(it->name, devname) == 0 ||
- (endp > startp && it->seq == seq))
- return it;
- }
-
- return NULL;
-}
-
-unsigned char *eth_get_ethaddr(void)
-{
- struct eth_pdata *pdata;
-
- if (eth_get_dev()) {
- pdata = eth_get_dev()->platdata;
- return pdata->enetaddr;
- }
-
- return NULL;
-}
-
-/* Set active state without calling start on the driver */
-int eth_init_state_only(void)
-{
- struct udevice *current;
- struct eth_device_priv *priv;
-
- current = eth_get_dev();
- if (!current || !device_active(current))
- return -EINVAL;
-
- priv = current->uclass_priv;
- priv->state = ETH_STATE_ACTIVE;
-
- return 0;
-}
-
-/* Set passive state without calling stop on the driver */
-void eth_halt_state_only(void)
-{
- struct udevice *current;
- struct eth_device_priv *priv;
-
- current = eth_get_dev();
- if (!current || !device_active(current))
- return;
-
- priv = current->uclass_priv;
- priv->state = ETH_STATE_PASSIVE;
-}
-
-int eth_get_dev_index(void)
-{
- if (eth_get_dev())
- return eth_get_dev()->seq;
- return -1;
-}
-
-static int eth_write_hwaddr(struct udevice *dev)
-{
- struct eth_pdata *pdata = dev->platdata;
- int ret = 0;
-
- if (!dev || !device_active(dev))
- return -EINVAL;
-
- /* seq is valid since the device is active */
- if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) {
- if (!is_valid_ethaddr(pdata->enetaddr)) {
- printf("\nError: %s address %pM illegal value\n",
- dev->name, pdata->enetaddr);
- return -EINVAL;
- }
-
- /*
- * Drivers are allowed to decide not to implement this at
- * run-time. E.g. Some devices may use it and some may not.
- */
- ret = eth_get_ops(dev)->write_hwaddr(dev);
- if (ret == -ENOSYS)
- ret = 0;
- if (ret)
- printf("\nWarning: %s failed to set MAC address\n",
- dev->name);
- }
-
- return ret;
-}
-
-static int on_ethaddr(const char *name, const char *value, enum env_op op,
- int flags)
-{
- int index;
- int retval;
- struct udevice *dev;
-
- /* look for an index after "eth" */
- index = simple_strtoul(name + 3, NULL, 10);
-
- retval = uclass_find_device_by_seq(UCLASS_ETH, index, false, &dev);
- if (!retval) {
- struct eth_pdata *pdata = dev->platdata;
- switch (op) {
- case env_op_create:
- case env_op_overwrite:
- eth_parse_enetaddr(value, pdata->enetaddr);
- break;
- case env_op_delete:
- memset(pdata->enetaddr, 0, 6);
- }
- }
-
- return 0;
-}
-U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
-
-int eth_init(void)
-{
- char *ethact = getenv("ethact");
- char *ethrotate = getenv("ethrotate");
- struct udevice *current = NULL;
- struct udevice *old_current;
- int ret = -ENODEV;
-
- /*
- * When 'ethrotate' variable is set to 'no' and 'ethact' variable
- * is already set to an ethernet device, we should stick to 'ethact'.
- */
- if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) {
- if (ethact) {
- current = eth_get_dev_by_name(ethact);
- if (!current)
- return -EINVAL;
- }
- }
-
- if (!current) {
- current = eth_get_dev();
- if (!current) {
- printf("No ethernet found.\n");
- return -ENODEV;
- }
- }
-
- old_current = current;
- do {
- if (current) {
- debug("Trying %s\n", current->name);
-
- if (device_active(current)) {
- ret = eth_get_ops(current)->start(current);
- if (ret >= 0) {
- struct eth_device_priv *priv =
- current->uclass_priv;
-
- priv->state = ETH_STATE_ACTIVE;
- return 0;
- }
- } else {
- ret = eth_errno;
- }
-
- debug("FAIL\n");
- } else {
- debug("PROBE FAIL\n");
- }
-
- /*
- * If ethrotate is enabled, this will change "current",
- * otherwise we will drop out of this while loop immediately
- */
- eth_try_another(0);
- /* This will ensure the new "current" attempted to probe */
- current = eth_get_dev();
- } while (old_current != current);
-
- return ret;
-}
-
-void eth_halt(void)
-{
- struct udevice *current;
- struct eth_device_priv *priv;
-
- current = eth_get_dev();
- if (!current || !device_active(current))
- return;
-
- eth_get_ops(current)->stop(current);
- priv = current->uclass_priv;
- priv->state = ETH_STATE_PASSIVE;
-}
-
-int eth_is_active(struct udevice *dev)
-{
- struct eth_device_priv *priv;
-
- if (!dev || !device_active(dev))
- return 0;
-
- priv = dev_get_uclass_priv(dev);
- return priv->state == ETH_STATE_ACTIVE;
-}
-
-int eth_send(void *packet, int length)
-{
- struct udevice *current;
- int ret;
-
- current = eth_get_dev();
- if (!current)
- return -ENODEV;
-
- if (!device_active(current))
- return -EINVAL;
-
- ret = eth_get_ops(current)->send(current, packet, length);
- if (ret < 0) {
- /* We cannot completely return the error at present */
- debug("%s: send() returned error %d\n", __func__, ret);
- }
- return ret;
-}
-
-int eth_rx(void)
-{
- struct udevice *current;
- uchar *packet;
- int flags;
- int ret;
- int i;
-
- current = eth_get_dev();
- if (!current)
- return -ENODEV;
-
- if (!device_active(current))
- return -EINVAL;
-
- /* Process up to 32 packets at one time */
- flags = ETH_RECV_CHECK_DEVICE;
- for (i = 0; i < 32; i++) {
- ret = eth_get_ops(current)->recv(current, flags, &packet);
- flags = 0;
- if (ret > 0)
- net_process_received_packet(packet, ret);
- if (ret >= 0 && eth_get_ops(current)->free_pkt)
- eth_get_ops(current)->free_pkt(current, packet, ret);
- if (ret <= 0)
- break;
- }
- if (ret == -EAGAIN)
- ret = 0;
- if (ret < 0) {
- /* We cannot completely return the error at present */
- debug("%s: recv() returned error %d\n", __func__, ret);
- }
- return ret;
-}
-
-int eth_initialize(void)
-{
- int num_devices = 0;
- struct udevice *dev;
-
- eth_common_init();
-
- /*
- * Devices need to write the hwaddr even if not started so that Linux
- * will have access to the hwaddr that u-boot stored for the device.
- * This is accomplished by attempting to probe each device and calling
- * their write_hwaddr() operation.
- */
- uclass_first_device(UCLASS_ETH, &dev);
- if (!dev) {
- printf("No ethernet found.\n");
- bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
- } else {
- char *ethprime = getenv("ethprime");
- struct udevice *prime_dev = NULL;
-
- if (ethprime)
- prime_dev = eth_get_dev_by_name(ethprime);
- if (prime_dev) {
- eth_set_dev(prime_dev);
- eth_current_changed();
- } else {
- eth_set_dev(NULL);
- }
-
- bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
- do {
- if (num_devices)
- printf(", ");
-
- printf("eth%d: %s", dev->seq, dev->name);
-
- if (ethprime && dev == prime_dev)
- printf(" [PRIME]");
-
- eth_write_hwaddr(dev);
-
- uclass_next_device(&dev);
- num_devices++;
- } while (dev);
-
- putc('\n');
- }
-
- return num_devices;
-}
-
-static int eth_post_bind(struct udevice *dev)
-{
- if (strchr(dev->name, ' ')) {
- printf("\nError: eth device name \"%s\" has a space!\n",
- dev->name);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int eth_pre_unbind(struct udevice *dev)
-{
- /* Don't hang onto a pointer that is going away */
- if (dev == eth_get_uclass_priv()->current)
- eth_set_dev(NULL);
-
- return 0;
-}
-
-static int eth_post_probe(struct udevice *dev)
-{
- struct eth_device_priv *priv = dev->uclass_priv;
- struct eth_pdata *pdata = dev->platdata;
- unsigned char env_enetaddr[6];
-
-#if defined(CONFIG_NEEDS_MANUAL_RELOC)
- struct eth_ops *ops = eth_get_ops(dev);
- static int reloc_done;
-
- if (!reloc_done) {
- if (ops->start)
- ops->start += gd->reloc_off;
- if (ops->send)
- ops->send += gd->reloc_off;
- if (ops->recv)
- ops->recv += gd->reloc_off;
- if (ops->free_pkt)
- ops->free_pkt += gd->reloc_off;
- if (ops->stop)
- ops->stop += gd->reloc_off;
-#ifdef CONFIG_MCAST_TFTP
- if (ops->mcast)
- ops->mcast += gd->reloc_off;
-#endif
- if (ops->write_hwaddr)
- ops->write_hwaddr += gd->reloc_off;
- if (ops->read_rom_hwaddr)
- ops->read_rom_hwaddr += gd->reloc_off;
-
- reloc_done++;
- }
-#endif
-
- priv->state = ETH_STATE_INIT;
-
- /* Check if the device has a MAC address in ROM */
- if (eth_get_ops(dev)->read_rom_hwaddr)
- eth_get_ops(dev)->read_rom_hwaddr(dev);
-
- eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
- if (!is_zero_ethaddr(env_enetaddr)) {
- if (!is_zero_ethaddr(pdata->enetaddr) &&
- memcmp(pdata->enetaddr, env_enetaddr, 6)) {
- printf("\nWarning: %s MAC addresses don't match:\n",
- dev->name);
- printf("Address in SROM is %pM\n",
- pdata->enetaddr);
- printf("Address in environment is %pM\n",
- env_enetaddr);
- }
-
- /* Override the ROM MAC address */
- memcpy(pdata->enetaddr, env_enetaddr, 6);
- } else if (is_valid_ethaddr(pdata->enetaddr)) {
- eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
- printf("\nWarning: %s using MAC address from ROM\n",
- dev->name);
- } else if (is_zero_ethaddr(pdata->enetaddr)) {
-#ifdef CONFIG_NET_RANDOM_ETHADDR
- net_random_ethaddr(pdata->enetaddr);
- printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
- dev->name, dev->seq, pdata->enetaddr);
-#else
- printf("\nError: %s address not set.\n",
- dev->name);
- return -EINVAL;
-#endif
- }
-
- return 0;
-}
-
-static int eth_pre_remove(struct udevice *dev)
-{
- struct eth_pdata *pdata = dev->platdata;
-
- eth_get_ops(dev)->stop(dev);
-
- /* clear the MAC address */
- memset(pdata->enetaddr, 0, 6);
-
- return 0;
-}
-
-UCLASS_DRIVER(eth) = {
- .name = "eth",
- .id = UCLASS_ETH,
- .post_bind = eth_post_bind,
- .pre_unbind = eth_pre_unbind,
- .post_probe = eth_post_probe,
- .pre_remove = eth_pre_remove,
- .priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
- .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";
-}
--- /dev/null
+/*
+ * (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";
+}
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * (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 */