mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-17 12:41:32 +00:00
Merge branch 'master' of git://git.denx.de/u-boot-net
This commit is contained in:
commit
82d72a1b99
32 changed files with 1934 additions and 880 deletions
|
@ -30,17 +30,13 @@ void ft_fixup_enet_phy_connect_type(void *fdt)
|
|||
int phy_node;
|
||||
int i = 0;
|
||||
uint32_t ph;
|
||||
char *name[3] = { "eTSEC1", "eTSEC2", "eTSEC3" };
|
||||
|
||||
while ((dev = eth_get_dev_by_index(i++)) != NULL) {
|
||||
if (strstr(dev->name, "eTSEC1")) {
|
||||
strcpy(enet, "ethernet0");
|
||||
strcpy(phy, "enet0_rgmii_phy");
|
||||
} else if (strstr(dev->name, "eTSEC2")) {
|
||||
strcpy(enet, "ethernet1");
|
||||
strcpy(phy, "enet1_rgmii_phy");
|
||||
} else if (strstr(dev->name, "eTSEC3")) {
|
||||
strcpy(enet, "ethernet2");
|
||||
strcpy(phy, "enet2_rgmii_phy");
|
||||
for (; i < ARRAY_SIZE(name); i++) {
|
||||
dev = eth_get_dev_by_name(name[i]);
|
||||
if (dev) {
|
||||
sprintf(enet, "ethernet%d", i);
|
||||
sprintf(phy, "enet%d_rgmii_phy", i);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -227,9 +227,9 @@ int checkboard(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
int board_eth_init(bd_t *bis)
|
||||
{
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
struct fsl_pq_mdio_info mdio_info;
|
||||
struct tsec_info_struct tsec_info[4];
|
||||
int num = 0;
|
||||
|
@ -250,6 +250,7 @@ int board_eth_init(bd_t *bis)
|
|||
|
||||
fsl_pq_mdio_init(bis, &mdio_info);
|
||||
tsec_eth_init(bis, tsec_info, num);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
pci_eth_init(bis);
|
||||
|
@ -257,7 +258,6 @@ int board_eth_init(bd_t *bis)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define USBMUX_SEL_MASK 0xc0
|
||||
#define USBMUX_SEL_UART2 0xc0
|
||||
|
|
|
@ -83,9 +83,9 @@ void pci_init_board(void)
|
|||
}
|
||||
#endif /* ifdef CONFIG_PCI */
|
||||
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
int board_eth_init(bd_t *bis)
|
||||
{
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
struct fsl_pq_mdio_info mdio_info;
|
||||
struct tsec_info_struct tsec_info[2];
|
||||
int num = 0;
|
||||
|
@ -110,10 +110,10 @@ int board_eth_init(bd_t *bis)
|
|||
fsl_pq_mdio_init(bis, &mdio_info);
|
||||
|
||||
tsec_eth_init(bis, tsec_info, num);
|
||||
#endif
|
||||
|
||||
return pci_eth_init(bis);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF_BOARD_SETUP)
|
||||
void fdt_del_sec(void *blob, int offset)
|
||||
|
|
|
@ -244,9 +244,9 @@ int board_mmc_init(bd_t *bis)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
int board_eth_init(bd_t *bis)
|
||||
{
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
struct fsl_pq_mdio_info mdio_info;
|
||||
struct tsec_info_struct tsec_info[4];
|
||||
int num = 0;
|
||||
|
@ -281,10 +281,10 @@ int board_eth_init(bd_t *bis)
|
|||
fsl_pq_mdio_init(bis, &mdio_info);
|
||||
|
||||
tsec_eth_init(bis, tsec_info, num);
|
||||
#endif
|
||||
|
||||
return pci_eth_init(bis);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_QSPI_BOOT) && !defined(CONFIG_SD_BOOT_QSPI)
|
||||
int config_serdes_mux(void)
|
||||
|
|
|
@ -301,9 +301,9 @@ void configure_rgmii(void)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
int board_eth_init(bd_t *bis)
|
||||
{
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
struct fsl_pq_mdio_info mdio_info;
|
||||
struct tsec_info_struct tsec_info[4];
|
||||
int num = 0;
|
||||
|
@ -345,10 +345,10 @@ int board_eth_init(bd_t *bis)
|
|||
|
||||
tsec_eth_init(bis, tsec_info, num);
|
||||
configure_rgmii();
|
||||
#endif
|
||||
|
||||
return pci_eth_init(bis);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF_BOARD_SETUP)
|
||||
void ft_pci_setup(void *blob, bd_t *bd)
|
||||
|
|
|
@ -171,9 +171,9 @@ int board_early_init_r(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
int board_eth_init(bd_t *bis)
|
||||
{
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
struct fsl_pq_mdio_info mdio_info;
|
||||
struct tsec_info_struct tsec_info[4];
|
||||
int num = 0;
|
||||
|
@ -226,10 +226,10 @@ int board_eth_init(bd_t *bis)
|
|||
fsl_pq_mdio_init(bis, &mdio_info);
|
||||
|
||||
tsec_eth_init(bis, tsec_info, num);
|
||||
#endif
|
||||
|
||||
return pci_eth_init(bis);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF_BOARD_SETUP)
|
||||
int ft_board_setup(void *blob, bd_t *bd)
|
||||
|
|
|
@ -326,9 +326,9 @@ int checkboard(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
int board_eth_init(bd_t *bis)
|
||||
{
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
struct fsl_pq_mdio_info mdio_info;
|
||||
struct tsec_info_struct tsec_info[4];
|
||||
struct cpu_type *cpu;
|
||||
|
@ -362,10 +362,10 @@ int board_eth_init(bd_t *bis)
|
|||
fsl_pq_mdio_init(bis, &mdio_info);
|
||||
|
||||
tsec_eth_init(bis, tsec_info, num);
|
||||
#endif
|
||||
|
||||
return pci_eth_init(bis);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF_BOARD_SETUP)
|
||||
void fdt_del_flexcan(void *blob)
|
||||
|
|
78
cmd/ethsw.c
78
cmd/ethsw.c
|
@ -71,7 +71,7 @@ static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd)
|
|||
|
||||
#define ETHSW_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \
|
||||
"{ [help] | show | all | none | pvid } " \
|
||||
" - set egress tagging mod for a port"
|
||||
" - set egress tagging mode for a port"
|
||||
|
||||
static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd)
|
||||
{
|
||||
|
@ -114,6 +114,17 @@ static int ethsw_ingr_fltr_help_key_func(struct ethsw_command_def *parsed_cmd)
|
|||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
#define ETHSW_PORT_AGGR_HELP "ethsw [port <port_no>] aggr" \
|
||||
" { [help] | show | <lag_group_no> } " \
|
||||
"- get/set LAG group for a port"
|
||||
|
||||
static int ethsw_port_aggr_help_key_func(struct ethsw_command_def *parsed_cmd)
|
||||
{
|
||||
printf(ETHSW_PORT_AGGR_HELP"\n");
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static struct keywords_to_function {
|
||||
enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
|
||||
int cmd_func_offset;
|
||||
|
@ -532,6 +543,39 @@ static struct keywords_to_function {
|
|||
.cmd_func_offset = offsetof(struct ethsw_command_func,
|
||||
port_ingr_filt_set),
|
||||
.keyword_function = NULL,
|
||||
}, {
|
||||
.cmd_keyword = {
|
||||
ethsw_id_aggr,
|
||||
ethsw_id_key_end,
|
||||
},
|
||||
.cmd_func_offset = -1,
|
||||
.keyword_function = ð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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -576,6 +620,9 @@ static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
|
|||
static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
|
||||
char *const argv[], int *argc_nr,
|
||||
struct ethsw_command_def *parsed_cmd);
|
||||
static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
|
||||
char *const argv[], int *argc_nr,
|
||||
struct ethsw_command_def *parsed_cmd);
|
||||
|
||||
/*
|
||||
* Define properties for each keyword;
|
||||
|
@ -661,6 +708,9 @@ struct keyword_def {
|
|||
}, {
|
||||
.keyword_name = "filtering",
|
||||
.match = &keyword_match_gen,
|
||||
}, {
|
||||
.keyword_name = "aggr",
|
||||
.match = &keyword_match_aggr,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -826,6 +876,28 @@ static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Function used to match the command's aggregation number */
|
||||
static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
|
||||
char *const argv[], int *argc_nr,
|
||||
struct ethsw_command_def *parsed_cmd)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
|
||||
return 0;
|
||||
|
||||
if (*argc_nr + 1 >= argc)
|
||||
return 1;
|
||||
|
||||
if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
|
||||
parsed_cmd->aggr_grp = val;
|
||||
(*argc_nr)++;
|
||||
parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_aggr_no;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Finds optional keywords and modifies *argc_va to skip them */
|
||||
static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd,
|
||||
int *argc_val)
|
||||
|
@ -984,6 +1056,7 @@ static void command_def_init(struct ethsw_command_def *parsed_cmd)
|
|||
|
||||
parsed_cmd->port = ETHSW_CMD_PORT_ALL;
|
||||
parsed_cmd->vid = ETHSW_CMD_VLAN_ALL;
|
||||
parsed_cmd->aggr_grp = ETHSW_CMD_AGGR_GRP_NONE;
|
||||
parsed_cmd->cmd_function = NULL;
|
||||
|
||||
/* We initialize the MAC address with the Broadcast address */
|
||||
|
@ -1010,7 +1083,7 @@ static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
}
|
||||
|
||||
#define ETHSW_PORT_CONF_HELP "[port <port_no>] { enable | disable | show } " \
|
||||
"- enable/disable a port; show shows a port's configuration"
|
||||
"- enable/disable a port; show a port's configuration"
|
||||
|
||||
U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
|
||||
"Ethernet l2 switch commands",
|
||||
|
@ -1024,4 +1097,5 @@ U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
|
|||
ETHSW_EGR_VLAN_TAG_HELP"\n"
|
||||
ETHSW_VLAN_FDB_HELP"\n"
|
||||
ETHSW_PORT_INGR_FLTR_HELP"\n"
|
||||
ETHSW_PORT_AGGR_HELP"\n"
|
||||
);
|
||||
|
|
|
@ -24,16 +24,31 @@ Switch interfaces:
|
|||
Commands Overview:
|
||||
=============
|
||||
Commands supported
|
||||
- enable/disable a port
|
||||
- check a port's link speed, duplexity and status.
|
||||
- enable/disable a port or show its configuration (speed, duplexity, status, etc.)
|
||||
- port statistics
|
||||
- MAC learning
|
||||
- add/remove FDB entries
|
||||
- Port-based VLAN
|
||||
- Private/Shared VLAN learning
|
||||
- VLAN ingress filtering
|
||||
- Port LAG
|
||||
|
||||
Commands syntax
|
||||
ethsw port <port_nr> enable|disable - enable/disable an l2 switch port
|
||||
ethsw port <port_nr> show - show an l2 switch port's configuration
|
||||
ethsw [port <port_no>] { enable | disable | show } - enable/disable a port; show a port's configuration
|
||||
ethsw [port <port_no>] statistics { [help] | [clear] } - show an l2 switch port's statistics
|
||||
ethsw [port <port_no>] learning { [help] | show | auto | disable } - enable/disable/show learning configuration on a port
|
||||
ethsw [port <port_no>] [vlan <vid>] fdb { [help] | show | flush | { add | del } <mac> } - add/delete a mac entry in FDB; use show to see FDB entries;
|
||||
if [vlan <vid>] is missing, VID 1 will be used
|
||||
ethsw [port <port_no>] pvid { [help] | show | <pvid> } - set/show PVID (ingress and egress VLAN tagging) for a port
|
||||
ethsw [port <port_no>] vlan { [help] | show | add <vid> | del <vid> } - add a VLAN to a port (VLAN members)
|
||||
ethsw [port <port_no>] untagged { [help] | show | all | none | pvid } - set egress tagging mode for a port
|
||||
ethsw [port <port_no>] egress tag { [help] | show | pvid | classified } - configure VID source for egress tag.
|
||||
Tag's VID could be the frame's classified VID or the PVID of the port
|
||||
ethsw vlan fdb { [help] | show | shared | private } - make VLAN learning shared or private
|
||||
ethsw [port <port_no>] ingress filtering { [help] | show | enable | disable } - enable/disable VLAN ingress filtering on port
|
||||
ethsw [port <port_no>] aggr { [help] | show | <lag_group_no> } - get/set LAG group for a port
|
||||
|
||||
port_nr=0..9; use "all" for all ports
|
||||
|
||||
=> ethsw port all show
|
||||
=> ethsw show
|
||||
Port Status Link Speed Duplex
|
||||
0 enabled down 10 half
|
||||
1 enabled down 10 half
|
||||
|
|
64
doc/device-tree-bindings/net/fsl-tsec-phy.txt
Normal file
64
doc/device-tree-bindings/net/fsl-tsec-phy.txt
Normal file
|
@ -0,0 +1,64 @@
|
|||
* TSEC-compatible ethernet nodes
|
||||
|
||||
Properties:
|
||||
|
||||
- compatible : Should be "fsl,tsec"
|
||||
- reg : Offset and length of the register set for the device
|
||||
- phy-handle : See ethernet.txt file in the same directory.
|
||||
- phy-connection-type : See ethernet.txt file in the same directory. This
|
||||
property is only really needed if the connection is of type "rgmii-id",
|
||||
"rgmii-rxid" and "rgmii-txid" as all other connection types are detected
|
||||
by hardware.
|
||||
|
||||
Example:
|
||||
ethernet@24000 {
|
||||
compatible = "fsl,tsec";
|
||||
reg = <0x24000 0x1000>;
|
||||
phy-handle = <&phy0>;
|
||||
phy-connection-type = "sgmii";
|
||||
};
|
||||
|
||||
Child nodes of the TSEC controller are typically the individual PHY devices
|
||||
connected via the MDIO bus (sometimes the MDIO bus controller is separate).
|
||||
|
||||
* MDIO IO device
|
||||
|
||||
The MDIO is a bus to which the PHY devices are connected. For each
|
||||
device that exists on this bus, a PHY node should be created.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should define the compatible device type for the
|
||||
mdio. Currently supported string/device is "fsl,tsec-mdio".
|
||||
- reg : Offset and length of the register set for the device
|
||||
|
||||
Example:
|
||||
|
||||
mdio@24520 {
|
||||
compatible = "fsl,tsec-mdio";
|
||||
reg = <0x24520 0x20>;
|
||||
|
||||
ethernet-phy@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
* TBI Internal MDIO bus
|
||||
|
||||
As of this writing, every tsec is associated with an internal TBI PHY.
|
||||
This PHY is accessed through the local MDIO bus. These buses are defined
|
||||
similarly to the mdio buses. The TBI PHYs underneath them are similar to
|
||||
normal PHYs, but the reg property is considered instructive, rather than
|
||||
descriptive. The reg property should be chosen so it doesn't interfere
|
||||
with other PHYs on the bus. The TBI PHYs are referred to by a "tbi-handle"
|
||||
property under the tsec node, which has a similar meaning of "phy-handle".
|
||||
|
||||
Example:
|
||||
ethernet@24000 {
|
||||
phy-handle = <&tbi1>;
|
||||
};
|
||||
|
||||
mdio@24520 {
|
||||
tbi1: tbi-phy@1f {
|
||||
reg = <0x1f>;
|
||||
};
|
||||
};
|
165
doc/device-tree-bindings/net/micrel-ksz90x1.txt
Normal file
165
doc/device-tree-bindings/net/micrel-ksz90x1.txt
Normal file
|
@ -0,0 +1,165 @@
|
|||
Micrel KSZ9021/KSZ9031 Gigabit Ethernet PHY
|
||||
|
||||
Some boards require special tuning values, particularly when it comes to
|
||||
clock delays. You can specify clock delay values by adding
|
||||
micrel-specific properties to an Ethernet OF device node.
|
||||
|
||||
Note that these settings are applied after any phy-specific fixup from
|
||||
phy_fixup_list (see phy_init_hw() from drivers/net/phy/phy_device.c),
|
||||
and therefore may overwrite them.
|
||||
|
||||
KSZ9021:
|
||||
|
||||
All skew control options are specified in picoseconds. The minimum
|
||||
value is 0, the maximum value is 1800, and it is incremented by 120ps
|
||||
steps.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- rxc-skew-ps : Skew control of RXC pad
|
||||
- rxdv-skew-ps : Skew control of RX CTL pad
|
||||
- txc-skew-ps : Skew control of TXC pad
|
||||
- txen-skew-ps : Skew control of TX CTL pad
|
||||
- rxd0-skew-ps : Skew control of RX data 0 pad
|
||||
- rxd1-skew-ps : Skew control of RX data 1 pad
|
||||
- rxd2-skew-ps : Skew control of RX data 2 pad
|
||||
- rxd3-skew-ps : Skew control of RX data 3 pad
|
||||
- txd0-skew-ps : Skew control of TX data 0 pad
|
||||
- txd1-skew-ps : Skew control of TX data 1 pad
|
||||
- txd2-skew-ps : Skew control of TX data 2 pad
|
||||
- txd3-skew-ps : Skew control of TX data 3 pad
|
||||
|
||||
KSZ9031:
|
||||
|
||||
All skew control options are specified in picoseconds. The minimum
|
||||
value is 0, and the maximum is property-dependent. The increment
|
||||
step is 60ps.
|
||||
|
||||
The KSZ9031 hardware supports a range of skew values from negative to
|
||||
positive, where the specific range is property dependent. All values
|
||||
specified in the devicetree are offset by the minimum value so they
|
||||
can be represented as positive integers in the devicetree since it's
|
||||
difficult to represent a negative number in the devictree.
|
||||
|
||||
The following 5-bit values table apply to rxc-skew-ps and txc-skew-ps.
|
||||
|
||||
Pad Skew Value Delay (ps) Devicetree Value
|
||||
------------------------------------------------------
|
||||
0_0000 -900ps 0
|
||||
0_0001 -840ps 60
|
||||
0_0010 -780ps 120
|
||||
0_0011 -720ps 180
|
||||
0_0100 -660ps 240
|
||||
0_0101 -600ps 300
|
||||
0_0110 -540ps 360
|
||||
0_0111 -480ps 420
|
||||
0_1000 -420ps 480
|
||||
0_1001 -360ps 540
|
||||
0_1010 -300ps 600
|
||||
0_1011 -240ps 660
|
||||
0_1100 -180ps 720
|
||||
0_1101 -120ps 780
|
||||
0_1110 -60ps 840
|
||||
0_1111 0ps 900
|
||||
1_0000 60ps 960
|
||||
1_0001 120ps 1020
|
||||
1_0010 180ps 1080
|
||||
1_0011 240ps 1140
|
||||
1_0100 300ps 1200
|
||||
1_0101 360ps 1260
|
||||
1_0110 420ps 1320
|
||||
1_0111 480ps 1380
|
||||
1_1000 540ps 1440
|
||||
1_1001 600ps 1500
|
||||
1_1010 660ps 1560
|
||||
1_1011 720ps 1620
|
||||
1_1100 780ps 1680
|
||||
1_1101 840ps 1740
|
||||
1_1110 900ps 1800
|
||||
1_1111 960ps 1860
|
||||
|
||||
The following 4-bit values table apply to the txdX-skew-ps, rxdX-skew-ps
|
||||
data pads, and the rxdv-skew-ps, txen-skew-ps control pads.
|
||||
|
||||
Pad Skew Value Delay (ps) Devicetree Value
|
||||
------------------------------------------------------
|
||||
0000 -420ps 0
|
||||
0001 -360ps 60
|
||||
0010 -300ps 120
|
||||
0011 -240ps 180
|
||||
0100 -180ps 240
|
||||
0101 -120ps 300
|
||||
0110 -60ps 360
|
||||
0111 0ps 420
|
||||
1000 60ps 480
|
||||
1001 120ps 540
|
||||
1010 180ps 600
|
||||
1011 240ps 660
|
||||
1100 300ps 720
|
||||
1101 360ps 780
|
||||
1110 420ps 840
|
||||
1111 480ps 900
|
||||
|
||||
Optional properties:
|
||||
|
||||
Maximum value of 1860:
|
||||
|
||||
- rxc-skew-ps : Skew control of RX clock pad
|
||||
- txc-skew-ps : Skew control of TX clock pad
|
||||
|
||||
Maximum value of 900:
|
||||
|
||||
- rxdv-skew-ps : Skew control of RX CTL pad
|
||||
- txen-skew-ps : Skew control of TX CTL pad
|
||||
- rxd0-skew-ps : Skew control of RX data 0 pad
|
||||
- rxd1-skew-ps : Skew control of RX data 1 pad
|
||||
- rxd2-skew-ps : Skew control of RX data 2 pad
|
||||
- rxd3-skew-ps : Skew control of RX data 3 pad
|
||||
- txd0-skew-ps : Skew control of TX data 0 pad
|
||||
- txd1-skew-ps : Skew control of TX data 1 pad
|
||||
- txd2-skew-ps : Skew control of TX data 2 pad
|
||||
- txd3-skew-ps : Skew control of TX data 3 pad
|
||||
|
||||
Examples:
|
||||
|
||||
/* Attach to an Ethernet device with autodetected PHY */
|
||||
&enet {
|
||||
rxc-skew-ps = <1800>;
|
||||
rxdv-skew-ps = <0>;
|
||||
txc-skew-ps = <1800>;
|
||||
txen-skew-ps = <0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* Attach to an explicitly-specified PHY */
|
||||
mdio {
|
||||
phy0: ethernet-phy@0 {
|
||||
rxc-skew-ps = <1800>;
|
||||
rxdv-skew-ps = <0>;
|
||||
txc-skew-ps = <1800>;
|
||||
txen-skew-ps = <0>;
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
ethernet@70000 {
|
||||
status = "okay";
|
||||
phy = <&phy0>;
|
||||
phy-mode = "rgmii-id";
|
||||
};
|
||||
|
||||
References
|
||||
|
||||
Micrel ksz9021rl/rn Data Sheet, Revision 1.2. Dated 2/13/2014.
|
||||
http://www.micrel.com/_PDF/Ethernet/datasheets/ksz9021rl-rn_ds.pdf
|
||||
|
||||
Micrel ksz9031rnx Data Sheet, Revision 2.1. Dated 11/20/2014.
|
||||
http://www.micrel.com/_PDF/Ethernet/datasheets/KSZ9031RNX.pdf
|
||||
|
||||
Notes:
|
||||
|
||||
Note that a previous version of the Micrel ksz9021rl/rn Data Sheet
|
||||
was missing extended register 106 (transmit data pad skews), and
|
||||
incorrectly specified the ps per step as 200ps/step instead of
|
||||
120ps/step. The latest update to this document reflects the latest
|
||||
revision of the Micrel specification even though usage in the kernel
|
||||
still reflects that incorrect document.
|
|
@ -196,6 +196,8 @@ static void dw_adjust_link(struct eth_mac_regs *mac_p,
|
|||
|
||||
if (phydev->speed != 1000)
|
||||
conf |= MII_PORTSELECT;
|
||||
else
|
||||
conf &= ~MII_PORTSELECT;
|
||||
|
||||
if (phydev->speed == 100)
|
||||
conf |= FES_100;
|
||||
|
@ -404,7 +406,7 @@ static int _dw_free_pkt(struct dw_eth_dev *priv)
|
|||
static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
|
||||
{
|
||||
struct phy_device *phydev;
|
||||
int mask = 0xffffffff;
|
||||
int mask = 0xffffffff, ret;
|
||||
|
||||
#ifdef CONFIG_PHY_ADDR
|
||||
mask = 1 << CONFIG_PHY_ADDR;
|
||||
|
@ -417,6 +419,11 @@ static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
|
|||
phy_connect_dev(phydev, dev);
|
||||
|
||||
phydev->supported &= PHY_GBIT_FEATURES;
|
||||
if (priv->max_speed) {
|
||||
ret = phy_set_supported(phydev, priv->max_speed);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
phydev->advertising = phydev->supported;
|
||||
|
||||
priv->phydev = phydev;
|
||||
|
@ -599,6 +606,7 @@ static int designware_eth_probe(struct udevice *dev)
|
|||
priv->mac_regs_p = (struct eth_mac_regs *)iobase;
|
||||
priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET);
|
||||
priv->interface = pdata->phy_interface;
|
||||
priv->max_speed = pdata->max_speed;
|
||||
|
||||
dw_mdio_init(dev->name, priv->mac_regs_p);
|
||||
priv->bus = miiphy_get_dev_by_name(dev->name);
|
||||
|
@ -633,6 +641,7 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
|
|||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
const char *phy_mode;
|
||||
const fdt32_t *cell;
|
||||
|
||||
pdata->iobase = dev_get_addr(dev);
|
||||
pdata->phy_interface = -1;
|
||||
|
@ -644,6 +653,11 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata->max_speed = 0;
|
||||
cell = fdt_getprop(gd->fdt_blob, dev->of_offset, "max-speed", NULL);
|
||||
if (cell)
|
||||
pdata->max_speed = fdt32_to_cpu(*cell);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -223,6 +223,7 @@ struct dw_eth_dev {
|
|||
char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
|
||||
|
||||
u32 interface;
|
||||
u32 max_speed;
|
||||
u32 tx_currdescnum;
|
||||
u32 rx_currdescnum;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <miiphy.h>
|
||||
#include <phy.h>
|
||||
|
@ -32,8 +33,7 @@ int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
|
|||
int value;
|
||||
int timeout = 1000000;
|
||||
|
||||
/* Put the address of the phy, and the register
|
||||
* number into MIIMADD */
|
||||
/* Put the address of the phy, and the register number into MIIMADD */
|
||||
out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
|
||||
|
||||
/* Clear the command register, and wait */
|
||||
|
|
|
@ -257,6 +257,12 @@ int cs4340_config(struct phy_device *phydev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int cs4340_probe(struct phy_device *phydev)
|
||||
{
|
||||
phydev->flags = PHY_FLAG_BROKEN_RESET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cs4340_startup(struct phy_device *phydev)
|
||||
{
|
||||
phydev->link = 1;
|
||||
|
@ -276,6 +282,7 @@ struct phy_driver cs4340_driver = {
|
|||
MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
|
||||
MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
|
||||
.config = &cs4340_config,
|
||||
.probe = &cs4340_probe,
|
||||
.startup = &cs4340_startup,
|
||||
.shutdown = &gen10g_shutdown,
|
||||
};
|
||||
|
|
|
@ -27,12 +27,31 @@ static struct phy_driver KSZ804_driver = {
|
|||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
#define MII_KSZPHY_OMSO 0x16
|
||||
#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
|
||||
|
||||
static int ksz_genconfig_bcastoff(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
|
||||
ret | KSZPHY_OMSO_B_CAST_OFF);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return genphy_config(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver KSZ8031_driver = {
|
||||
.name = "Micrel KSZ8021/KSZ8031",
|
||||
.uid = 0x221550,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &genphy_config,
|
||||
.config = &ksz_genconfig_bcastoff,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
@ -70,7 +89,7 @@ static struct phy_driver KSZ8081_driver = {
|
|||
.uid = 0x221560,
|
||||
.mask = 0xfffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &genphy_config,
|
||||
.config = &ksz_genconfig_bcastoff,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
@ -211,7 +230,7 @@ static int ksz90x1_of_config_group(struct phy_device *phydev,
|
|||
{
|
||||
struct udevice *dev = phydev->dev;
|
||||
struct phy_driver *drv = phydev->drv;
|
||||
const int ps_to_regval = 200;
|
||||
const int ps_to_regval = 60;
|
||||
int val[4];
|
||||
int i, changed = 0, offset, max;
|
||||
u16 regval = 0;
|
||||
|
|
|
@ -38,16 +38,16 @@ DECLARE_GLOBAL_DATA_PTR;
|
|||
static int genphy_config_advert(struct phy_device *phydev)
|
||||
{
|
||||
u32 advertise;
|
||||
int oldadv, adv;
|
||||
int oldadv, adv, bmsr;
|
||||
int err, changed = 0;
|
||||
|
||||
/* Only allow advertising what
|
||||
* this PHY supports */
|
||||
/* Only allow advertising what this PHY supports */
|
||||
phydev->advertising &= phydev->supported;
|
||||
advertise = phydev->advertising;
|
||||
|
||||
/* Setup standard advertisement */
|
||||
oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
|
||||
adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
|
||||
oldadv = adv;
|
||||
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
|
@ -79,30 +79,41 @@ static int genphy_config_advert(struct phy_device *phydev)
|
|||
changed = 1;
|
||||
}
|
||||
|
||||
bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
if (bmsr < 0)
|
||||
return bmsr;
|
||||
|
||||
/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
|
||||
* 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
|
||||
* logical 1.
|
||||
*/
|
||||
if (!(bmsr & BMSR_ESTATEN))
|
||||
return changed;
|
||||
|
||||
/* Configure gigabit if it's supported */
|
||||
adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
|
||||
oldadv = adv;
|
||||
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
|
||||
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
|
||||
if (phydev->supported & (SUPPORTED_1000baseT_Half |
|
||||
SUPPORTED_1000baseT_Full)) {
|
||||
oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
|
||||
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
|
||||
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
||||
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 (err < 0)
|
||||
return err;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (adv != oldadv)
|
||||
changed = 1;
|
||||
|
||||
err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
@ -117,7 +128,7 @@ static int genphy_config_advert(struct phy_device *phydev)
|
|||
static int genphy_setup_forced(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
int ctl = 0;
|
||||
int ctl = BMCR_ANRESTART;
|
||||
|
||||
phydev->pause = phydev->asym_pause = 0;
|
||||
|
||||
|
@ -224,7 +235,8 @@ int genphy_update_link(struct phy_device *phydev)
|
|||
if (phydev->link && mii_reg & BMSR_LSTATUS)
|
||||
return 0;
|
||||
|
||||
if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
|
||||
if ((phydev->autoneg == AUTONEG_ENABLE) &&
|
||||
!(mii_reg & BMSR_ANEGCOMPLETE)) {
|
||||
int i = 0;
|
||||
|
||||
printf("%s Waiting for PHY auto negotiation to complete",
|
||||
|
@ -280,7 +292,7 @@ int genphy_parse_link(struct phy_device *phydev)
|
|||
int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
|
||||
|
||||
/* We're using autonegotiation */
|
||||
if (phydev->supported & SUPPORTED_Autoneg) {
|
||||
if (phydev->autoneg == AUTONEG_ENABLE) {
|
||||
u32 lpa = 0;
|
||||
int gblpa = 0;
|
||||
u32 estatus = 0;
|
||||
|
@ -371,8 +383,6 @@ int genphy_config(struct phy_device *phydev)
|
|||
int val;
|
||||
u32 features;
|
||||
|
||||
/* For now, I'll claim that the generic driver supports
|
||||
* all possible port types */
|
||||
features = (SUPPORTED_TP | SUPPORTED_MII
|
||||
| SUPPORTED_AUI | SUPPORTED_FIBRE |
|
||||
SUPPORTED_BNC);
|
||||
|
@ -411,8 +421,8 @@ int genphy_config(struct phy_device *phydev)
|
|||
features |= SUPPORTED_1000baseX_Half;
|
||||
}
|
||||
|
||||
phydev->supported = features;
|
||||
phydev->advertising = features;
|
||||
phydev->supported &= features;
|
||||
phydev->advertising &= features;
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
|
@ -436,7 +446,9 @@ static struct phy_driver genphy_driver = {
|
|||
.uid = 0xffffffff,
|
||||
.mask = 0xffffffff,
|
||||
.name = "Generic PHY",
|
||||
.features = 0,
|
||||
.features = PHY_GBIT_FEATURES | SUPPORTED_MII |
|
||||
SUPPORTED_AUI | SUPPORTED_FIBRE |
|
||||
SUPPORTED_BNC,
|
||||
.config = genphy_config,
|
||||
.startup = genphy_startup,
|
||||
.shutdown = genphy_shutdown,
|
||||
|
@ -517,6 +529,30 @@ int phy_register(struct phy_driver *drv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int phy_set_supported(struct phy_device *phydev, u32 max_speed)
|
||||
{
|
||||
/* The default values for phydev->supported are provided by the PHY
|
||||
* driver "features" member, we want to reset to sane defaults first
|
||||
* before supporting higher speeds.
|
||||
*/
|
||||
phydev->supported &= PHY_DEFAULT_FEATURES;
|
||||
|
||||
switch (max_speed) {
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
case SPEED_1000:
|
||||
phydev->supported |= PHY_1000BT_FEATURES;
|
||||
/* fall through */
|
||||
case SPEED_100:
|
||||
phydev->supported |= PHY_100BT_FEATURES;
|
||||
/* fall through */
|
||||
case SPEED_10:
|
||||
phydev->supported |= PHY_10BT_FEATURES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int phy_probe(struct phy_device *phydev)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -707,6 +743,9 @@ int phy_reset(struct phy_device *phydev)
|
|||
int timeout = 500;
|
||||
int devad = MDIO_DEVAD_NONE;
|
||||
|
||||
if (phydev->flags & PHY_FLAG_BROKEN_RESET)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_PHYLIB_10G
|
||||
/* If it's 10G, we need to issue reset through one of the MMDs */
|
||||
if (is_10g_interface(phydev->interface)) {
|
||||
|
@ -717,15 +756,7 @@ int phy_reset(struct phy_device *phydev)
|
|||
}
|
||||
#endif
|
||||
|
||||
reg = phy_read(phydev, devad, MII_BMCR);
|
||||
if (reg < 0) {
|
||||
debug("PHY status read failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
reg |= BMCR_RESET;
|
||||
|
||||
if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
|
||||
if (phy_write(phydev, devad, MII_BMCR, BMCR_RESET) < 0) {
|
||||
debug("PHY reset failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -738,6 +769,7 @@ int phy_reset(struct phy_device *phydev)
|
|||
* auto-clearing). This should happen within 0.5 seconds per the
|
||||
* IEEE spec.
|
||||
*/
|
||||
reg = phy_read(phydev, devad, MII_BMCR);
|
||||
while ((reg & BMCR_RESET) && timeout--) {
|
||||
reg = phy_read(phydev, devad, MII_BMCR);
|
||||
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
/*
|
||||
* Freescale Three Speed Ethernet Controller driver
|
||||
*
|
||||
* This software may be used and distributed according to the
|
||||
* terms of the GNU Public License, Version 2, incorporated
|
||||
* herein by reference.
|
||||
*
|
||||
* Copyright 2004-2011, 2013 Freescale Semiconductor, Inc.
|
||||
* (C) Copyright 2003, Motorola, Inc.
|
||||
* author Andy Fleming
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <command.h>
|
||||
|
@ -24,21 +22,7 @@
|
|||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define TX_BUF_CNT 2
|
||||
|
||||
static uint rx_idx; /* index of the current RX buffer */
|
||||
static uint tx_idx; /* index of the current TX buffer */
|
||||
|
||||
#ifdef __GNUC__
|
||||
static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8);
|
||||
static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8);
|
||||
|
||||
#else
|
||||
#error "rtx must be 64-bit aligned"
|
||||
#endif
|
||||
|
||||
static int tsec_send(struct eth_device *dev, void *packet, int length);
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
/* Default initializations for TSEC controllers. */
|
||||
|
||||
static struct tsec_info_struct tsec_info[] = {
|
||||
|
@ -64,6 +48,7 @@ static struct tsec_info_struct tsec_info[] = {
|
|||
STD_TSEC_INFO(4), /* TSEC4 */
|
||||
#endif
|
||||
};
|
||||
#endif /* CONFIG_DM_ETH */
|
||||
|
||||
#define TBIANA_SETTINGS ( \
|
||||
TBIANA_ASYMMETRIC_PAUSE \
|
||||
|
@ -84,8 +69,10 @@ static struct tsec_info_struct tsec_info[] = {
|
|||
/* Configure the TBI for SGMII operation */
|
||||
static void tsec_configure_serdes(struct tsec_private *priv)
|
||||
{
|
||||
/* Access TBI PHY registers at given TSEC register offset as opposed
|
||||
* to the register offset used for external PHY accesses */
|
||||
/*
|
||||
* Access TBI PHY registers at given TSEC register offset as opposed
|
||||
* to the register offset used for external PHY accesses
|
||||
*/
|
||||
tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
|
||||
0, TBI_ANA, TBIANA_SETTINGS);
|
||||
tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
|
||||
|
@ -100,7 +87,8 @@ static void tsec_configure_serdes(struct tsec_private *priv)
|
|||
|
||||
/* Set the appropriate hash bit for the given addr */
|
||||
|
||||
/* The algorithm works like so:
|
||||
/*
|
||||
* The algorithm works like so:
|
||||
* 1) Take the Destination Address (ie the multicast address), and
|
||||
* do a CRC on it (little endian), and reverse the bits of the
|
||||
* result.
|
||||
|
@ -111,9 +99,13 @@ static void tsec_configure_serdes(struct tsec_private *priv)
|
|||
* hash index which gaddr register to use, and the 5 other bits
|
||||
* indicate which bit (assuming an IBM numbering scheme, which
|
||||
* for PowerPC (tm) is usually the case) in the register holds
|
||||
* the entry. */
|
||||
static int
|
||||
tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
|
||||
* the entry.
|
||||
*/
|
||||
#ifndef CONFIG_DM_ETH
|
||||
static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
|
||||
#else
|
||||
static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int set)
|
||||
#endif
|
||||
{
|
||||
struct tsec_private *priv = (struct tsec_private *)dev->priv;
|
||||
struct tsec __iomem *regs = priv->regs;
|
||||
|
@ -135,7 +127,8 @@ tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
|
|||
}
|
||||
#endif /* Multicast TFTP ? */
|
||||
|
||||
/* Initialized required registers to appropriate values, zeroing
|
||||
/*
|
||||
* Initialized required registers to appropriate values, zeroing
|
||||
* those we don't care about (unless zero is bad, in which case,
|
||||
* choose a more appropriate value)
|
||||
*/
|
||||
|
@ -181,7 +174,8 @@ static void init_registers(struct tsec __iomem *regs)
|
|||
|
||||
}
|
||||
|
||||
/* Configure maccfg2 based on negotiated speed and duplex
|
||||
/*
|
||||
* Configure maccfg2 based on negotiated speed and duplex
|
||||
* reported by PHY handling code
|
||||
*/
|
||||
static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
|
||||
|
@ -212,7 +206,8 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
|
|||
case 10:
|
||||
maccfg2 |= MACCFG2_MII;
|
||||
|
||||
/* Set R100 bit in all modes although
|
||||
/*
|
||||
* Set R100 bit in all modes although
|
||||
* it is only used in RGMII mode
|
||||
*/
|
||||
if (phydev->speed == 100)
|
||||
|
@ -231,15 +226,174 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
|
|||
(phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
|
||||
}
|
||||
|
||||
/*
|
||||
* This returns the status bits of the device. The return value
|
||||
* is never checked, and this is what the 8260 driver did, so we
|
||||
* do the same. Presumably, this would be zero if there were no
|
||||
* errors
|
||||
*/
|
||||
#ifndef CONFIG_DM_ETH
|
||||
static int tsec_send(struct eth_device *dev, void *packet, int length)
|
||||
#else
|
||||
static int tsec_send(struct udevice *dev, void *packet, int length)
|
||||
#endif
|
||||
{
|
||||
struct tsec_private *priv = (struct tsec_private *)dev->priv;
|
||||
struct tsec __iomem *regs = priv->regs;
|
||||
uint16_t status;
|
||||
int result = 0;
|
||||
int i;
|
||||
|
||||
/* Find an empty buffer descriptor */
|
||||
for (i = 0;
|
||||
in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
|
||||
i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
debug("%s: tsec: tx buffers full\n", dev->name);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
out_be32(&priv->txbd[priv->tx_idx].bufptr, (u32)packet);
|
||||
out_be16(&priv->txbd[priv->tx_idx].length, length);
|
||||
status = in_be16(&priv->txbd[priv->tx_idx].status);
|
||||
out_be16(&priv->txbd[priv->tx_idx].status, status |
|
||||
(TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
|
||||
|
||||
/* Tell the DMA to go */
|
||||
out_be32(®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;
|
||||
|
@ -274,25 +428,27 @@ void redundant_init(struct eth_device *dev)
|
|||
|
||||
do {
|
||||
uint16_t status;
|
||||
tsec_send(dev, (void *)pkt, sizeof(pkt));
|
||||
tsec_send(priv->dev, (void *)pkt, sizeof(pkt));
|
||||
|
||||
/* Wait for buffer to be received */
|
||||
for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) {
|
||||
for (t = 0;
|
||||
in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY;
|
||||
t++) {
|
||||
if (t >= 10 * TOUT_LOOP) {
|
||||
printf("%s: tsec: rx error\n", dev->name);
|
||||
printf("%s: tsec: rx error\n", priv->dev->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!memcmp(pkt, (void *)net_rx_packets[rx_idx], sizeof(pkt)))
|
||||
if (!memcmp(pkt, net_rx_packets[priv->rx_idx], sizeof(pkt)))
|
||||
fail = 0;
|
||||
|
||||
out_be16(&rxbd[rx_idx].length, 0);
|
||||
out_be16(&priv->rxbd[priv->rx_idx].length, 0);
|
||||
status = RXBD_EMPTY;
|
||||
if ((rx_idx + 1) == PKTBUFSRX)
|
||||
if ((priv->rx_idx + 1) == PKTBUFSRX)
|
||||
status |= RXBD_WRAP;
|
||||
out_be16(&rxbd[rx_idx].status, status);
|
||||
rx_idx = (rx_idx + 1) % PKTBUFSRX;
|
||||
out_be16(&priv->rxbd[priv->rx_idx].status, status);
|
||||
priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
|
||||
|
||||
if (in_be32(®s->ievent) & IEVENT_BSY) {
|
||||
out_be32(®s->ievent, IEVENT_BSY);
|
||||
|
@ -315,49 +471,49 @@ void redundant_init(struct eth_device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Set up the buffers and their descriptors, and bring up the
|
||||
/*
|
||||
* Set up the buffers and their descriptors, and bring up the
|
||||
* interface
|
||||
*/
|
||||
static void startup_tsec(struct eth_device *dev)
|
||||
static void startup_tsec(struct tsec_private *priv)
|
||||
{
|
||||
struct tsec_private *priv = (struct tsec_private *)dev->priv;
|
||||
struct tsec __iomem *regs = priv->regs;
|
||||
uint16_t status;
|
||||
int i;
|
||||
|
||||
/* reset the indices to zero */
|
||||
rx_idx = 0;
|
||||
tx_idx = 0;
|
||||
priv->rx_idx = 0;
|
||||
priv->tx_idx = 0;
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
|
||||
uint svr;
|
||||
#endif
|
||||
|
||||
/* Point to the buffer descriptors */
|
||||
out_be32(®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);
|
||||
|
@ -369,113 +525,22 @@ static void startup_tsec(struct eth_device *dev)
|
|||
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;
|
||||
|
@ -489,17 +554,27 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
|
|||
/* 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);
|
||||
|
||||
|
@ -507,7 +582,7 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
|
|||
init_registers(regs);
|
||||
|
||||
/* Ready the device for tx/rx */
|
||||
startup_tsec(dev);
|
||||
startup_tsec(priv);
|
||||
|
||||
/* Start up the PHY */
|
||||
ret = phy_startup(priv->phydev);
|
||||
|
@ -551,8 +626,8 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
|
|||
* be set by the platform code.
|
||||
*/
|
||||
if ((interface == PHY_INTERFACE_MODE_RGMII_ID) ||
|
||||
(interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
|
||||
(interface == PHY_INTERFACE_MODE_RGMII_RXID))
|
||||
(interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
|
||||
(interface == PHY_INTERFACE_MODE_RGMII_RXID))
|
||||
return interface;
|
||||
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
@ -565,14 +640,13 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
|
|||
return PHY_INTERFACE_MODE_MII;
|
||||
}
|
||||
|
||||
|
||||
/* Discover which PHY is attached to the device, and configure it
|
||||
/*
|
||||
* Discover which PHY is attached to the device, and configure it
|
||||
* properly. If the PHY is not recognized, then return 0
|
||||
* (failure). Otherwise, return 1
|
||||
*/
|
||||
static int init_phy(struct eth_device *dev)
|
||||
static int init_phy(struct tsec_private *priv)
|
||||
{
|
||||
struct tsec_private *priv = (struct tsec_private *)dev->priv;
|
||||
struct phy_device *phydev;
|
||||
struct tsec __iomem *regs = priv->regs;
|
||||
u32 supported = (SUPPORTED_10baseT_Half |
|
||||
|
@ -584,14 +658,15 @@ static int init_phy(struct eth_device *dev)
|
|||
supported |= SUPPORTED_1000baseT_Full;
|
||||
|
||||
/* Assign a Physical address to the TBI */
|
||||
out_be32(®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;
|
||||
|
||||
|
@ -605,7 +680,9 @@ static int init_phy(struct eth_device *dev)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Initialize device structure. Returns success if PHY
|
||||
#ifndef CONFIG_DM_ETH
|
||||
/*
|
||||
* Initialize device structure. Returns success if PHY
|
||||
* initialization succeeded (i.e. if it recognizes the PHY)
|
||||
*/
|
||||
static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
|
||||
|
@ -630,11 +707,13 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
|
|||
priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
|
||||
|
||||
priv->phyaddr = tsec_info->phyaddr;
|
||||
priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
|
||||
priv->flags = tsec_info->flags;
|
||||
|
||||
strcpy(dev->name, tsec_info->devname);
|
||||
priv->interface = tsec_info->interface;
|
||||
priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname);
|
||||
priv->dev = dev;
|
||||
dev->iobase = 0;
|
||||
dev->priv = priv;
|
||||
dev->init = tsec_init;
|
||||
|
@ -645,7 +724,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
|
|||
dev->mcast = tsec_mcast_addr;
|
||||
#endif
|
||||
|
||||
/* Tell u-boot to get the addr from the env */
|
||||
/* Tell U-Boot to get the addr from the env */
|
||||
for (i = 0; i < 6; i++)
|
||||
dev->enetaddr[i] = 0;
|
||||
|
||||
|
@ -657,7 +736,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
|
|||
clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
|
||||
|
||||
/* Try to initialize PHY here, and return */
|
||||
return init_phy(dev);
|
||||
return init_phy(priv);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -690,3 +769,118 @@ int tsec_standard_init(bd_t *bis)
|
|||
|
||||
return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
|
||||
}
|
||||
#else /* CONFIG_DM_ETH */
|
||||
int tsec_probe(struct udevice *dev)
|
||||
{
|
||||
struct tsec_private *priv = dev_get_priv(dev);
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct fsl_pq_mdio_info mdio_info;
|
||||
int offset = 0;
|
||||
int reg;
|
||||
const char *phy_mode;
|
||||
int ret;
|
||||
|
||||
pdata->iobase = (phys_addr_t)dev_get_addr(dev);
|
||||
priv->regs = (struct tsec *)pdata->iobase;
|
||||
|
||||
offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
|
||||
"phy-handle");
|
||||
if (offset > 0) {
|
||||
reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
|
||||
priv->phyaddr = reg;
|
||||
} else {
|
||||
debug("phy-handle does not exist under tsec %s\n", dev->name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
offset = fdt_parent_offset(gd->fdt_blob, offset);
|
||||
if (offset > 0) {
|
||||
reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
|
||||
priv->phyregs_sgmii = (struct tsec_mii_mng *)(reg + 0x520);
|
||||
} else {
|
||||
debug("No parent node for PHY?\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
|
||||
"tbi-handle");
|
||||
if (offset > 0) {
|
||||
reg = fdtdec_get_int(gd->fdt_blob, offset, "reg",
|
||||
CONFIG_SYS_TBIPA_VALUE);
|
||||
priv->tbiaddr = reg;
|
||||
} else {
|
||||
priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
|
||||
}
|
||||
|
||||
phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset,
|
||||
"phy-connection-type", NULL);
|
||||
if (phy_mode)
|
||||
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
|
||||
if (pdata->phy_interface == -1) {
|
||||
debug("Invalid PHY interface '%s'\n", phy_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
priv->interface = pdata->phy_interface;
|
||||
|
||||
/* Initialize flags */
|
||||
priv->flags = TSEC_GIGABIT;
|
||||
if (priv->interface == PHY_INTERFACE_MODE_SGMII)
|
||||
priv->flags |= TSEC_SGMII;
|
||||
|
||||
mdio_info.regs = priv->phyregs_sgmii;
|
||||
mdio_info.name = (char *)dev->name;
|
||||
ret = fsl_pq_mdio_init(NULL, &mdio_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Reset the MAC */
|
||||
setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
|
||||
udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
|
||||
clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
|
||||
|
||||
priv->dev = dev;
|
||||
priv->bus = miiphy_get_dev_by_name(dev->name);
|
||||
|
||||
/* Try to initialize PHY here, and return */
|
||||
return !init_phy(priv);
|
||||
}
|
||||
|
||||
int tsec_remove(struct udevice *dev)
|
||||
{
|
||||
struct tsec_private *priv = dev->priv;
|
||||
|
||||
free(priv->phydev);
|
||||
mdio_unregister(priv->bus);
|
||||
mdio_free(priv->bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct eth_ops tsec_ops = {
|
||||
.start = tsec_init,
|
||||
.send = tsec_send,
|
||||
.recv = tsec_recv,
|
||||
.free_pkt = tsec_free_pkt,
|
||||
.stop = tsec_halt,
|
||||
#ifdef CONFIG_MCAST_TFTP
|
||||
.mcast = tsec_mcast_addr,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct udevice_id tsec_ids[] = {
|
||||
{ .compatible = "fsl,tsec" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(eth_tsec) = {
|
||||
.name = "tsec",
|
||||
.id = UCLASS_ETH,
|
||||
.of_match = tsec_ids,
|
||||
.probe = tsec_probe,
|
||||
.remove = tsec_remove,
|
||||
.ops = &tsec_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct tsec_private),
|
||||
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
|
||||
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
||||
};
|
||||
#endif /* CONFIG_DM_ETH */
|
||||
|
|
|
@ -469,6 +469,47 @@ static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
|
|||
clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
|
||||
}
|
||||
|
||||
enum aggr_code_mode {
|
||||
AGGR_CODE_RAND = 0,
|
||||
AGGR_CODE_ALL, /* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */
|
||||
};
|
||||
|
||||
/* Set aggregation code generation mode */
|
||||
static int vsc9953_aggr_code_set(enum aggr_code_mode ac)
|
||||
{
|
||||
int rc;
|
||||
struct vsc9953_analyzer *l2ana_reg;
|
||||
|
||||
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||
VSC9953_ANA_OFFSET);
|
||||
|
||||
switch (ac) {
|
||||
case AGGR_CODE_RAND:
|
||||
clrsetbits_le32(&l2ana_reg->common.aggr_cfg,
|
||||
VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
|
||||
VSC9953_AC_IP6_LBL_ENA |
|
||||
VSC9953_AC_IP6_TCPUDP_ENA |
|
||||
VSC9953_AC_IP4_SIPDIP_ENA |
|
||||
VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA);
|
||||
rc = 0;
|
||||
break;
|
||||
case AGGR_CODE_ALL:
|
||||
clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA,
|
||||
VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
|
||||
VSC9953_AC_IP6_LBL_ENA |
|
||||
VSC9953_AC_IP6_TCPUDP_ENA |
|
||||
VSC9953_AC_IP4_SIPDIP_ENA |
|
||||
VSC9953_AC_IP4_TCPUDP_ENA);
|
||||
rc = 0;
|
||||
break;
|
||||
default:
|
||||
/* unknown mode for aggregation code */
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Egress untag modes of a VSC9953 port */
|
||||
enum egress_untag_mode {
|
||||
EGRESS_UNTAG_ALL = 0,
|
||||
|
@ -593,6 +634,25 @@ static void vsc9953_port_all_vlan_egress_untagged_set(
|
|||
vsc9953_port_vlan_egr_untag_set(i, mode);
|
||||
}
|
||||
|
||||
static int vsc9953_autoage_time_set(int age_period)
|
||||
{
|
||||
u32 autoage;
|
||||
struct vsc9953_analyzer *l2ana_reg;
|
||||
|
||||
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||
VSC9953_ANA_OFFSET);
|
||||
|
||||
if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
|
||||
VSC9953_AUTOAGE_PERIOD_MASK,
|
||||
age_period);
|
||||
out_le32(&l2ana_reg->ana.auto_age, autoage);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_ETHSW
|
||||
|
||||
/* Enable/disable status of a VSC9953 port */
|
||||
|
@ -1474,6 +1534,224 @@ static int vsc9953_port_ingress_filtering_get(int port_no)
|
|||
return !!(val & (1 << port_no));
|
||||
}
|
||||
|
||||
/* Get the aggregation group of a port */
|
||||
static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp)
|
||||
{
|
||||
u32 val;
|
||||
struct vsc9953_analyzer *l2ana_reg;
|
||||
|
||||
if (!VSC9953_PORT_CHECK(port_no))
|
||||
return -EINVAL;
|
||||
|
||||
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||
VSC9953_ANA_OFFSET);
|
||||
|
||||
val = in_le32(&l2ana_reg->port[port_no].port_cfg);
|
||||
*aggr_grp = bitfield_extract_by_mask(val,
|
||||
VSC9953_PORT_CFG_PORTID_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vsc9953_aggr_grp_members_get(int aggr_grp,
|
||||
u8 aggr_membr[VSC9953_MAX_PORTS])
|
||||
{
|
||||
int port_no;
|
||||
int aggr_membr_grp;
|
||||
|
||||
for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) {
|
||||
aggr_membr[port_no] = 0;
|
||||
|
||||
if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp))
|
||||
continue;
|
||||
|
||||
if (aggr_grp == aggr_membr_grp)
|
||||
aggr_membr[port_no] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old,
|
||||
u32 membr_bitfld_new)
|
||||
{
|
||||
int i;
|
||||
u32 pgid;
|
||||
struct vsc9953_analyzer *l2ana_reg;
|
||||
|
||||
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||
VSC9953_ANA_OFFSET);
|
||||
|
||||
/*
|
||||
* NOTE: Only the unicast destination masks are updated, since
|
||||
* we do not support for now Layer-2 multicast entries
|
||||
*/
|
||||
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
|
||||
if (i == port_no) {
|
||||
clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i],
|
||||
VSC9953_PGID_PORT_MASK,
|
||||
membr_bitfld_new);
|
||||
continue;
|
||||
}
|
||||
|
||||
pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
|
||||
if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
|
||||
pgid &= ~((u32)(1 << port_no));
|
||||
if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
|
||||
pgid |= ((u32)(1 << port_no));
|
||||
|
||||
out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
|
||||
}
|
||||
}
|
||||
|
||||
static void vsc9953_update_source_members_masks(int port_no,
|
||||
u32 membr_bitfld_old,
|
||||
u32 membr_bitfld_new)
|
||||
{
|
||||
int i;
|
||||
int index;
|
||||
u32 pgid;
|
||||
struct vsc9953_analyzer *l2ana_reg;
|
||||
|
||||
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||
VSC9953_ANA_OFFSET);
|
||||
|
||||
for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) {
|
||||
index = PGID_SRC_START + i;
|
||||
pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]);
|
||||
if (i == port_no) {
|
||||
pgid = (pgid | VSC9953_PGID_PORT_MASK) &
|
||||
~membr_bitfld_new;
|
||||
out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index],
|
||||
pgid);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
|
||||
pgid |= (u32)(1 << port_no);
|
||||
|
||||
if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
|
||||
pgid &= ~(u32)(1 << port_no);
|
||||
out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield)
|
||||
{
|
||||
if (!member_bitfield)
|
||||
return 0;
|
||||
|
||||
if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
|
||||
aggr_mask = 1;
|
||||
else
|
||||
aggr_mask <<= 1;
|
||||
|
||||
while (!(aggr_mask & member_bitfield)) {
|
||||
aggr_mask <<= 1;
|
||||
if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
|
||||
aggr_mask = 1;
|
||||
}
|
||||
|
||||
return aggr_mask;
|
||||
}
|
||||
|
||||
static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old,
|
||||
u32 membr_bitfld_new)
|
||||
{
|
||||
int i;
|
||||
u32 pgid;
|
||||
u32 aggr_mask_old = 0;
|
||||
u32 aggr_mask_new = 0;
|
||||
struct vsc9953_analyzer *l2ana_reg;
|
||||
|
||||
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||
VSC9953_ANA_OFFSET);
|
||||
|
||||
/* Update all the PGID aggregation masks */
|
||||
for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) {
|
||||
pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
|
||||
|
||||
aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old,
|
||||
membr_bitfld_old);
|
||||
pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old;
|
||||
|
||||
aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new,
|
||||
membr_bitfld_new);
|
||||
pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new;
|
||||
|
||||
out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])
|
||||
{
|
||||
int i;
|
||||
u32 member_bitfield = 0;
|
||||
|
||||
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
|
||||
if (member[i])
|
||||
member_bitfield |= 1 << i;
|
||||
}
|
||||
member_bitfield &= VSC9953_PGID_PORT_MASK;
|
||||
|
||||
return member_bitfield;
|
||||
}
|
||||
|
||||
static void vsc9953_update_members_masks(int port_no,
|
||||
u8 member_old[VSC9953_MAX_PORTS],
|
||||
u8 member_new[VSC9953_MAX_PORTS])
|
||||
{
|
||||
u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old);
|
||||
u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new);
|
||||
|
||||
vsc9953_update_dest_members_masks(port_no, membr_bitfld_old,
|
||||
membr_bitfld_new);
|
||||
vsc9953_update_source_members_masks(port_no, membr_bitfld_old,
|
||||
membr_bitfld_new);
|
||||
vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old,
|
||||
membr_bitfld_new);
|
||||
}
|
||||
|
||||
/* Set the aggregation group of a port */
|
||||
static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp)
|
||||
{
|
||||
u8 aggr_membr_old[VSC9953_MAX_PORTS];
|
||||
u8 aggr_membr_new[VSC9953_MAX_PORTS];
|
||||
int rc;
|
||||
int aggr_grp_old;
|
||||
u32 val;
|
||||
struct vsc9953_analyzer *l2ana_reg;
|
||||
|
||||
if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp))
|
||||
return -EINVAL;
|
||||
|
||||
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||
VSC9953_ANA_OFFSET);
|
||||
|
||||
rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* get all the members of the old aggregation group */
|
||||
vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old);
|
||||
|
||||
/* get all the members of the same aggregation group */
|
||||
vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new);
|
||||
|
||||
/* add current port as member to the new aggregation group */
|
||||
aggr_membr_old[port_no] = 0;
|
||||
aggr_membr_new[port_no] = 1;
|
||||
|
||||
/* update masks */
|
||||
vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new);
|
||||
|
||||
/* Change logical port number */
|
||||
val = in_le32(&l2ana_reg->port[port_no].port_cfg);
|
||||
val = bitfield_replace_by_mask(val,
|
||||
VSC9953_PORT_CFG_PORTID_MASK, aggr_grp);
|
||||
out_le32(&l2ana_reg->port[port_no].port_cfg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
|
||||
{
|
||||
int i;
|
||||
|
@ -2064,6 +2342,72 @@ static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
|
|||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd)
|
||||
{
|
||||
int i;
|
||||
int aggr_grp;
|
||||
|
||||
if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
|
||||
if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
|
||||
printf("Invalid port number: %d\n", parsed_cmd->port);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp))
|
||||
return CMD_RET_FAILURE;
|
||||
printf("%7s %10s\n", "Port", "Aggr grp");
|
||||
printf("%7d %10d\n", parsed_cmd->port, aggr_grp);
|
||||
} else {
|
||||
printf("%7s %10s\n", "Port", "Aggr grp");
|
||||
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
|
||||
if (vsc9953_port_aggr_grp_get(i, &aggr_grp))
|
||||
continue;
|
||||
printf("%7d %10d\n", i, aggr_grp);
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Aggregation group number should be set in parsed_cmd->aggr_grp */
|
||||
if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) {
|
||||
printf("Please set an aggregation group value\n");
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) {
|
||||
printf("Invalid aggregation group number: %d\n",
|
||||
parsed_cmd->aggr_grp);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
|
||||
if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
|
||||
printf("Invalid port number: %d\n", parsed_cmd->port);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
if (vsc9953_port_aggr_grp_set(parsed_cmd->port,
|
||||
parsed_cmd->aggr_grp)) {
|
||||
printf("Port %d: failed to set aggr group %d\n",
|
||||
parsed_cmd->port, parsed_cmd->aggr_grp);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
|
||||
if (vsc9953_port_aggr_grp_set(i,
|
||||
parsed_cmd->aggr_grp)) {
|
||||
printf("Port %d: failed to set aggr group %d\n",
|
||||
i, parsed_cmd->aggr_grp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
static struct ethsw_command_func vsc9953_cmd_func = {
|
||||
.ethsw_name = "L2 Switch VSC9953",
|
||||
.port_enable = &vsc9953_port_status_key_func,
|
||||
|
@ -2088,7 +2432,9 @@ static struct ethsw_command_func vsc9953_cmd_func = {
|
|||
.vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
|
||||
.vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
|
||||
.port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
|
||||
.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func
|
||||
.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func,
|
||||
.port_aggr_show = &vsc9953_port_aggr_show_key_func,
|
||||
.port_aggr_set = &vsc9953_port_aggr_set_key_func,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_CMD_ETHSW */
|
||||
|
@ -2107,6 +2453,10 @@ void vsc9953_default_configuration(void)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
|
||||
debug("VSC9953: failed to set AGE time to %d\n",
|
||||
VSC9953_DEFAULT_AGE_TIME);
|
||||
|
||||
for (i = 0; i < VSC9953_MAX_VLAN; i++)
|
||||
vsc9953_vlan_table_membership_all_set(i, 0);
|
||||
vsc9953_port_all_vlan_aware_set(1);
|
||||
|
@ -2115,6 +2465,8 @@ void vsc9953_default_configuration(void)
|
|||
vsc9953_vlan_table_membership_all_set(1, 1);
|
||||
vsc9953_vlan_ingr_fltr_learn_drop(1);
|
||||
vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
|
||||
if (vsc9953_aggr_code_set(AGGR_CODE_ALL))
|
||||
debug("VSC9953: failed to set default aggregation code mode\n");
|
||||
}
|
||||
|
||||
void vsc9953_init(bd_t *bis)
|
||||
|
|
|
@ -465,7 +465,11 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
|
|||
return err;
|
||||
}
|
||||
|
||||
tegra_pcie_board_init();
|
||||
err = tegra_pcie_board_init();
|
||||
if (err < 0) {
|
||||
error("tegra_pcie_board_init() failed: err=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE);
|
||||
if (pcie->phy) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#define ETHSW_MAX_CMD_PARAMS 20
|
||||
#define ETHSW_CMD_PORT_ALL -1
|
||||
#define ETHSW_CMD_VLAN_ALL -1
|
||||
#define ETHSW_CMD_AGGR_GRP_NONE -1
|
||||
|
||||
/* IDs used to track keywords in a command */
|
||||
enum ethsw_keyword_id {
|
||||
|
@ -41,6 +42,7 @@ enum ethsw_keyword_id {
|
|||
ethsw_id_private,
|
||||
ethsw_id_ingress,
|
||||
ethsw_id_filtering,
|
||||
ethsw_id_aggr,
|
||||
ethsw_id_count, /* keep last */
|
||||
};
|
||||
|
||||
|
@ -50,6 +52,7 @@ enum ethsw_keyword_opt_id {
|
|||
ethsw_id_pvid_no,
|
||||
ethsw_id_add_del_no,
|
||||
ethsw_id_add_del_mac,
|
||||
ethsw_id_aggr_no,
|
||||
ethsw_id_count_all, /* keep last */
|
||||
};
|
||||
|
||||
|
@ -58,6 +61,7 @@ struct ethsw_command_def {
|
|||
int cmd_keywords_nr;
|
||||
int port;
|
||||
int vid;
|
||||
int aggr_grp;
|
||||
uchar ethaddr[6];
|
||||
int (*cmd_function)(struct ethsw_command_def *parsed_cmd);
|
||||
};
|
||||
|
@ -88,6 +92,8 @@ struct ethsw_command_func {
|
|||
int (*vlan_learn_set)(struct ethsw_command_def *parsed_cmd);
|
||||
int (*port_ingr_filt_show)(struct ethsw_command_def *parsed_cmd);
|
||||
int (*port_ingr_filt_set)(struct ethsw_command_def *parsed_cmd);
|
||||
int (*port_aggr_show)(struct ethsw_command_def *parsed_cmd);
|
||||
int (*port_aggr_set)(struct ethsw_command_def *parsed_cmd);
|
||||
};
|
||||
|
||||
int ethsw_define_functions(const struct ethsw_command_func *cmd_func);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __FSL_PHY_H__
|
||||
#define __FSL_PHY_H__
|
||||
|
||||
|
@ -27,9 +28,9 @@ int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc);
|
|||
#define PHY_EXT_PAGE_ACCESS 0x1f
|
||||
|
||||
/* MII Management Configuration Register */
|
||||
#define MIIMCFG_RESET_MGMT 0x80000000
|
||||
#define MIIMCFG_MGMT_CLOCK_SELECT 0x00000007
|
||||
#define MIIMCFG_INIT_VALUE 0x00000003
|
||||
#define MIIMCFG_RESET_MGMT 0x80000000
|
||||
#define MIIMCFG_MGMT_CLOCK_SELECT 0x00000007
|
||||
#define MIIMCFG_INIT_VALUE 0x00000003
|
||||
|
||||
/* MII Management Command Register */
|
||||
#define MIIMCOM_READ_CYCLE 0x00000001
|
||||
|
|
|
@ -86,11 +86,13 @@ enum eth_state_t {
|
|||
* @iobase: The base address of the hardware registers
|
||||
* @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env
|
||||
* @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_...
|
||||
* @max_speed: Maximum speed of Ethernet connection supported by MAC
|
||||
*/
|
||||
struct eth_pdata {
|
||||
phys_addr_t iobase;
|
||||
unsigned char enetaddr[6];
|
||||
int phy_interface;
|
||||
int max_speed;
|
||||
};
|
||||
|
||||
enum eth_recv_flags {
|
||||
|
|
|
@ -17,18 +17,28 @@
|
|||
|
||||
#define PHY_MAX_ADDR 32
|
||||
|
||||
#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
|
||||
SUPPORTED_10baseT_Full | \
|
||||
SUPPORTED_100baseT_Half | \
|
||||
SUPPORTED_100baseT_Full | \
|
||||
SUPPORTED_Autoneg | \
|
||||
#define PHY_FLAG_BROKEN_RESET (1 << 0) /* soft reset not supported */
|
||||
|
||||
#define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \
|
||||
SUPPORTED_TP | \
|
||||
SUPPORTED_MII)
|
||||
|
||||
#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
|
||||
SUPPORTED_1000baseT_Half | \
|
||||
#define PHY_10BT_FEATURES (SUPPORTED_10baseT_Half | \
|
||||
SUPPORTED_10baseT_Full)
|
||||
|
||||
#define PHY_100BT_FEATURES (SUPPORTED_100baseT_Half | \
|
||||
SUPPORTED_100baseT_Full)
|
||||
|
||||
#define PHY_1000BT_FEATURES (SUPPORTED_1000baseT_Half | \
|
||||
SUPPORTED_1000baseT_Full)
|
||||
|
||||
#define PHY_BASIC_FEATURES (PHY_10BT_FEATURES | \
|
||||
PHY_100BT_FEATURES | \
|
||||
PHY_DEFAULT_FEATURES)
|
||||
|
||||
#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
|
||||
PHY_1000BT_FEATURES)
|
||||
|
||||
#define PHY_10G_FEATURES (PHY_GBIT_FEATURES | \
|
||||
SUPPORTED_10000baseT_Full)
|
||||
|
||||
|
@ -226,6 +236,7 @@ int phy_startup(struct phy_device *phydev);
|
|||
int phy_config(struct phy_device *phydev);
|
||||
int phy_shutdown(struct phy_device *phydev);
|
||||
int phy_register(struct phy_driver *drv);
|
||||
int phy_set_supported(struct phy_device *phydev, u32 max_speed);
|
||||
int genphy_config_aneg(struct phy_device *phydev);
|
||||
int genphy_restart_aneg(struct phy_device *phydev);
|
||||
int genphy_update_link(struct phy_device *phydev);
|
||||
|
|
|
@ -3,15 +3,12 @@
|
|||
*
|
||||
* Driver for the Motorola Triple Speed Ethernet Controller
|
||||
*
|
||||
* This software may be used and distributed according to the
|
||||
* terms of the GNU Public License, Version 2, incorporated
|
||||
* herein by reference.
|
||||
*
|
||||
* Copyright 2004, 2007, 2009, 2011, 2013 Freescale Semiconductor, Inc.
|
||||
* (C) Copyright 2003, Motorola, Inc.
|
||||
* maintained by Xianghua Xiao (x.xiao@motorola.com)
|
||||
* author Andy Fleming
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __TSEC_H
|
||||
|
@ -21,6 +18,8 @@
|
|||
#include <config.h>
|
||||
#include <phy.h>
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
|
||||
#ifdef CONFIG_LS102XA
|
||||
#define TSEC_SIZE 0x40000
|
||||
#define TSEC_MDIO_OFFSET 0x40000
|
||||
|
@ -67,11 +66,13 @@
|
|||
x.mii_devname = DEFAULT_MII_NAME;\
|
||||
}
|
||||
|
||||
#define MAC_ADDR_LEN 6
|
||||
#endif /* CONFIG_DM_ETH */
|
||||
|
||||
#define MAC_ADDR_LEN 6
|
||||
|
||||
/* #define TSEC_TIMEOUT 1000000 */
|
||||
#define TSEC_TIMEOUT 1000
|
||||
#define TOUT_LOOP 1000000
|
||||
#define TSEC_TIMEOUT 1000
|
||||
#define TOUT_LOOP 1000000
|
||||
|
||||
/* TBI register addresses */
|
||||
#define TBI_CR 0x00
|
||||
|
@ -83,8 +84,8 @@
|
|||
|
||||
/* TBI MDIO register bit fields*/
|
||||
#define TBICON_CLK_SELECT 0x0020
|
||||
#define TBIANA_ASYMMETRIC_PAUSE 0x0100
|
||||
#define TBIANA_SYMMETRIC_PAUSE 0x0080
|
||||
#define TBIANA_ASYMMETRIC_PAUSE 0x0100
|
||||
#define TBIANA_SYMMETRIC_PAUSE 0x0080
|
||||
#define TBIANA_HALF_DUPLEX 0x0040
|
||||
#define TBIANA_FULL_DUPLEX 0x0020
|
||||
#define TBICR_PHY_RESET 0x8000
|
||||
|
@ -93,13 +94,12 @@
|
|||
#define TBICR_FULL_DUPLEX 0x0100
|
||||
#define TBICR_SPEED1_SET 0x0040
|
||||
|
||||
|
||||
/* MAC register bits */
|
||||
#define MACCFG1_SOFT_RESET 0x80000000
|
||||
#define MACCFG1_RESET_RX_MC 0x00080000
|
||||
#define MACCFG1_RESET_TX_MC 0x00040000
|
||||
#define MACCFG1_RESET_RX_FUN 0x00020000
|
||||
#define MACCFG1_RESET_TX_FUN 0x00010000
|
||||
#define MACCFG1_RESET_TX_FUN 0x00010000
|
||||
#define MACCFG1_LOOPBACK 0x00000100
|
||||
#define MACCFG1_RX_FLOW 0x00000020
|
||||
#define MACCFG1_TX_FLOW 0x00000010
|
||||
|
@ -122,7 +122,7 @@
|
|||
#define ECNTRL_SGMII_MODE 0x00000002
|
||||
|
||||
#ifndef CONFIG_SYS_TBIPA_VALUE
|
||||
#define CONFIG_SYS_TBIPA_VALUE 0x1f
|
||||
# define CONFIG_SYS_TBIPA_VALUE 0x1f
|
||||
#endif
|
||||
|
||||
#define MRBLR_INIT_SETTINGS PKTSIZE_ALIGN
|
||||
|
@ -137,7 +137,6 @@
|
|||
#define TSTAT_CLEAR_THALT 0x80000000
|
||||
#define RSTAT_CLEAR_RHALT 0x00800000
|
||||
|
||||
|
||||
#define IEVENT_INIT_CLEAR 0xffffffff
|
||||
#define IEVENT_BABR 0x80000000
|
||||
#define IEVENT_RXC 0x40000000
|
||||
|
@ -164,11 +163,9 @@
|
|||
#define IMASK_TXFEN 0x00100000
|
||||
#define IMASK_RXFEN0 0x00000080
|
||||
|
||||
|
||||
/* Default Attribute fields */
|
||||
#define ATTR_INIT_SETTINGS 0x000000c0
|
||||
#define ATTRELI_INIT_SETTINGS 0x00000000
|
||||
|
||||
#define ATTR_INIT_SETTINGS 0x000000c0
|
||||
#define ATTRELI_INIT_SETTINGS 0x00000000
|
||||
|
||||
/* TxBD status field bits */
|
||||
#define TXBD_READY 0x8000
|
||||
|
@ -181,7 +178,7 @@
|
|||
#define TXBD_HUGEFRAME 0x0080
|
||||
#define TXBD_LATECOLLISION 0x0080
|
||||
#define TXBD_RETRYLIMIT 0x0040
|
||||
#define TXBD_RETRYCOUNTMASK 0x003c
|
||||
#define TXBD_RETRYCOUNTMASK 0x003c
|
||||
#define TXBD_UNDERRUN 0x0002
|
||||
#define TXBD_STATS 0x03ff
|
||||
|
||||
|
@ -204,15 +201,15 @@
|
|||
#define RXBD_STATS 0x003f
|
||||
|
||||
struct txbd8 {
|
||||
uint16_t status; /* Status Fields */
|
||||
uint16_t length; /* Buffer length */
|
||||
uint32_t bufptr; /* Buffer Pointer */
|
||||
uint16_t status; /* Status Fields */
|
||||
uint16_t length; /* Buffer length */
|
||||
uint32_t bufptr; /* Buffer Pointer */
|
||||
};
|
||||
|
||||
struct rxbd8 {
|
||||
uint16_t status; /* Status Fields */
|
||||
uint16_t length; /* Buffer Length */
|
||||
uint32_t bufptr; /* Buffer Pointer */
|
||||
uint16_t status; /* Status Fields */
|
||||
uint16_t length; /* Buffer Length */
|
||||
uint32_t bufptr; /* Buffer Pointer */
|
||||
};
|
||||
|
||||
struct tsec_rmon_mib {
|
||||
|
@ -336,15 +333,15 @@ struct tsec {
|
|||
u32 rbdlen; /* RxBD Data Length */
|
||||
u32 res310[4];
|
||||
u32 res320;
|
||||
u32 crbptr; /* Current Receive Buffer Pointer */
|
||||
u32 crbptr; /* Current Receive Buffer Pointer */
|
||||
u32 res328[6];
|
||||
u32 mrblr; /* Maximum Receive Buffer Length */
|
||||
u32 mrblr; /* Maximum Receive Buffer Length */
|
||||
u32 res344[16];
|
||||
u32 rbptr; /* RxBD Pointer */
|
||||
u32 rbptr; /* RxBD Pointer */
|
||||
u32 res388[30];
|
||||
/* (0x2_n400) */
|
||||
u32 res400;
|
||||
u32 rbase; /* RxBD Base Address */
|
||||
u32 rbase; /* RxBD Base Address */
|
||||
u32 res408[62];
|
||||
|
||||
/* MAC Registers (0x2_n500) */
|
||||
|
@ -388,21 +385,33 @@ struct tsec {
|
|||
u32 resc00[256];
|
||||
};
|
||||
|
||||
#define TSEC_GIGABIT (1 << 0)
|
||||
#define TSEC_GIGABIT (1 << 0)
|
||||
|
||||
/* These flags currently only have meaning if we're using the eTSEC */
|
||||
#define TSEC_REDUCED (1 << 1) /* MAC-PHY interface uses RGMII */
|
||||
#define TSEC_SGMII (1 << 2) /* MAC-PHY interface uses SGMII */
|
||||
|
||||
#define TX_BUF_CNT 2
|
||||
|
||||
struct tsec_private {
|
||||
struct txbd8 __iomem txbd[TX_BUF_CNT];
|
||||
struct rxbd8 __iomem rxbd[PKTBUFSRX];
|
||||
struct tsec __iomem *regs;
|
||||
struct tsec_mii_mng __iomem *phyregs_sgmii;
|
||||
struct phy_device *phydev;
|
||||
phy_interface_t interface;
|
||||
struct mii_dev *bus;
|
||||
uint phyaddr;
|
||||
uint tbiaddr;
|
||||
char mii_devname[16];
|
||||
u32 flags;
|
||||
uint rx_idx; /* index of the current RX buffer */
|
||||
uint tx_idx; /* index of the current TX buffer */
|
||||
#ifndef CONFIG_DM_ETH
|
||||
struct eth_device *dev;
|
||||
#else
|
||||
struct udevice *dev;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct tsec_info_struct {
|
||||
|
@ -415,7 +424,9 @@ struct tsec_info_struct {
|
|||
u32 flags;
|
||||
};
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
int tsec_standard_init(bd_t *bis);
|
||||
int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsec_info, int num);
|
||||
#endif
|
||||
|
||||
#endif /* __TSEC_H */
|
||||
|
|
|
@ -126,6 +126,7 @@
|
|||
#define VSC9953_PORT_CFG_LEARN_AUTO 0x00000100
|
||||
#define VSC9953_PORT_CFG_LEARN_CPU 0x00000200
|
||||
#define VSC9953_PORT_CFG_LEARN_DROP 0x00000400
|
||||
#define VSC9953_PORT_CFG_PORTID_MASK 0x0000003c
|
||||
|
||||
/* Macros for vsc9953_qsys_sys.switch_port_mode register */
|
||||
#define VSC9953_PORT_ENA 0x00002000
|
||||
|
@ -136,6 +137,9 @@
|
|||
/* Macros for vsc9953_ana_ana.adv_learn register */
|
||||
#define VSC9953_VLAN_CHK 0x00000400
|
||||
|
||||
/* Macros for vsc9953_ana_ana.auto_age register */
|
||||
#define VSC9953_AUTOAGE_PERIOD_MASK 0x001ffffe
|
||||
|
||||
/* Macros for vsc9953_rew_port.port_tag_cfg register */
|
||||
#define VSC9953_TAG_CFG_MASK 0x00000180
|
||||
#define VSC9953_TAG_CFG_NONE 0x00000000
|
||||
|
@ -153,6 +157,19 @@
|
|||
/* Macros for vsc9953_ana_ana_tables.mach_data register */
|
||||
#define VSC9953_MACHDATA_VID_MASK 0x1fff0000
|
||||
|
||||
/* Macros for vsc9953_ana_common.aggr_cfg register */
|
||||
#define VSC9953_AC_RND_ENA 0x00000080
|
||||
#define VSC9953_AC_DMAC_ENA 0x00000040
|
||||
#define VSC9953_AC_SMAC_ENA 0x00000020
|
||||
#define VSC9953_AC_IP6_LBL_ENA 0x00000010
|
||||
#define VSC9953_AC_IP6_TCPUDP_ENA 0x00000008
|
||||
#define VSC9953_AC_IP4_SIPDIP_ENA 0x00000004
|
||||
#define VSC9953_AC_IP4_TCPUDP_ENA 0x00000002
|
||||
#define VSC9953_AC_MASK 0x000000fe
|
||||
|
||||
/* Macros for vsc9953_ana_pgid.port_grp_id[] registers */
|
||||
#define VSC9953_PGID_PORT_MASK 0x000003ff
|
||||
|
||||
#define VSC9953_MAX_PORTS 10
|
||||
#define VSC9953_PORT_CHECK(port) \
|
||||
(((port) < 0 || (port) >= VSC9953_MAX_PORTS) ? 0 : 1)
|
||||
|
@ -164,6 +181,7 @@
|
|||
#define VSC9953_MAX_VLAN 4096
|
||||
#define VSC9953_VLAN_CHECK(vid) \
|
||||
(((vid) < 0 || (vid) >= VSC9953_MAX_VLAN) ? 0 : 1)
|
||||
#define VSC9953_DEFAULT_AGE_TIME 300
|
||||
|
||||
#define DEFAULT_VSC9953_MDIO_NAME "VSC9953_MDIO0"
|
||||
|
||||
|
@ -235,6 +253,10 @@ struct vsc9953_ana_ana {
|
|||
u32 port_mode[12];
|
||||
};
|
||||
|
||||
#define PGID_DST_START 0
|
||||
#define PGID_AGGR_START 64
|
||||
#define PGID_SRC_START 80
|
||||
|
||||
struct vsc9953_ana_pgid {
|
||||
u32 port_grp_id[91];
|
||||
};
|
||||
|
@ -269,7 +291,7 @@ struct vsc9953_analyzer {
|
|||
struct vsc9953_ana_ana_tables ana_tables;
|
||||
u32 reserved2[14];
|
||||
struct vsc9953_ana_ana ana;
|
||||
u32 reserved3[22];
|
||||
u32 reserved3[21];
|
||||
struct vsc9953_ana_pgid port_id_tbl;
|
||||
u32 reserved4[549];
|
||||
struct vsc9953_ana_pfc pfc[10];
|
||||
|
|
|
@ -12,7 +12,12 @@ obj-$(CONFIG_CMD_NET) += arp.o
|
|||
obj-$(CONFIG_CMD_NET) += bootp.o
|
||||
obj-$(CONFIG_CMD_CDP) += cdp.o
|
||||
obj-$(CONFIG_CMD_DNS) += dns.o
|
||||
obj-$(CONFIG_CMD_NET) += eth.o
|
||||
ifdef CONFIG_DM_ETH
|
||||
obj-$(CONFIG_CMD_NET) += eth-uclass.o
|
||||
else
|
||||
obj-$(CONFIG_CMD_NET) += eth_legacy.o
|
||||
endif
|
||||
obj-$(CONFIG_CMD_NET) += eth_common.o
|
||||
obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
|
||||
obj-$(CONFIG_CMD_NET) += net.o
|
||||
obj-$(CONFIG_CMD_NFS) += nfs.o
|
||||
|
|
|
@ -949,6 +949,7 @@ static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
|
|||
net_write_ip(&bp->bp_giaddr, zero_ip);
|
||||
|
||||
memcpy(bp->bp_chaddr, net_ethaddr, 6);
|
||||
copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file));
|
||||
|
||||
/*
|
||||
* ID is the id of the OFFER packet
|
||||
|
@ -995,6 +996,9 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
|
|||
debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: "
|
||||
"%d\n", src, dest, len, dhcp_state);
|
||||
|
||||
if (net_read_ip(&bp->bp_yiaddr).s_addr == 0)
|
||||
return;
|
||||
|
||||
switch (dhcp_state) {
|
||||
case SELECTING:
|
||||
/*
|
||||
|
|
|
@ -7,113 +7,13 @@
|
|||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <environment.h>
|
||||
#include <net.h>
|
||||
#include <miiphy.h>
|
||||
#include <phy.h>
|
||||
#include <asm/errno.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
#include "eth_internal.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
|
||||
{
|
||||
char *end;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 6; ++i) {
|
||||
enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
|
||||
if (addr)
|
||||
addr = (*end) ? end + 1 : end;
|
||||
}
|
||||
}
|
||||
|
||||
int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
|
||||
{
|
||||
eth_parse_enetaddr(getenv(name), enetaddr);
|
||||
return is_valid_ethaddr(enetaddr);
|
||||
}
|
||||
|
||||
int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
sprintf(buf, "%pM", enetaddr);
|
||||
|
||||
return setenv(name, buf);
|
||||
}
|
||||
|
||||
int eth_getenv_enetaddr_by_index(const char *base_name, int index,
|
||||
uchar *enetaddr)
|
||||
{
|
||||
char enetvar[32];
|
||||
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
|
||||
return eth_getenv_enetaddr(enetvar, enetaddr);
|
||||
}
|
||||
|
||||
static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
|
||||
uchar *enetaddr)
|
||||
{
|
||||
char enetvar[32];
|
||||
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
|
||||
return eth_setenv_enetaddr(enetvar, enetaddr);
|
||||
}
|
||||
|
||||
static int eth_mac_skip(int index)
|
||||
{
|
||||
char enetvar[15];
|
||||
char *skip_state;
|
||||
|
||||
sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
|
||||
skip_state = getenv(enetvar);
|
||||
return skip_state != NULL;
|
||||
}
|
||||
|
||||
static void eth_current_changed(void);
|
||||
|
||||
/*
|
||||
* CPU and board-specific Ethernet initializations. Aliased function
|
||||
* signals caller to move on
|
||||
*/
|
||||
static int __def_eth_init(bd_t *bis)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
|
||||
int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
|
||||
|
||||
static void eth_common_init(void)
|
||||
{
|
||||
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
|
||||
miiphy_init();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PHYLIB
|
||||
phy_init();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If board-specific initialization exists, call it.
|
||||
* If not, call a CPU-specific one
|
||||
*/
|
||||
if (board_eth_init != __def_eth_init) {
|
||||
if (board_eth_init(gd->bd) < 0)
|
||||
printf("Board Net Initialization Failed\n");
|
||||
} else if (cpu_eth_init != __def_eth_init) {
|
||||
if (cpu_eth_init(gd->bd) < 0)
|
||||
printf("CPU Net Initialization Failed\n");
|
||||
} else {
|
||||
#ifndef CONFIG_DM_ETH
|
||||
printf("Net Initialization Skipped\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_ETH
|
||||
/**
|
||||
* struct eth_device_priv - private structure for each Ethernet device
|
||||
*
|
||||
|
@ -144,7 +44,7 @@ static struct eth_uclass_priv *eth_get_uclass_priv(void)
|
|||
return uc->priv;
|
||||
}
|
||||
|
||||
static void eth_set_current_to_next(void)
|
||||
void eth_set_current_to_next(void)
|
||||
{
|
||||
struct eth_uclass_priv *uc_priv;
|
||||
|
||||
|
@ -177,7 +77,7 @@ struct udevice *eth_get_dev(void)
|
|||
* In case it was not probed, we will attempt to do so.
|
||||
* dev may be NULL to unset the active device.
|
||||
*/
|
||||
static void eth_set_dev(struct udevice *dev)
|
||||
void eth_set_dev(struct udevice *dev)
|
||||
{
|
||||
if (dev && !device_active(dev)) {
|
||||
eth_errno = device_probe(dev);
|
||||
|
@ -647,493 +547,3 @@ UCLASS_DRIVER(eth) = {
|
|||
.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
|
||||
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||
};
|
||||
#endif /* #ifdef CONFIG_DM_ETH */
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
|
||||
#ifdef CONFIG_API
|
||||
static struct {
|
||||
uchar data[PKTSIZE];
|
||||
int length;
|
||||
} eth_rcv_bufs[PKTBUFSRX];
|
||||
|
||||
static unsigned int eth_rcv_current, eth_rcv_last;
|
||||
#endif
|
||||
|
||||
static struct eth_device *eth_devices;
|
||||
struct eth_device *eth_current;
|
||||
|
||||
static void eth_set_current_to_next(void)
|
||||
{
|
||||
eth_current = eth_current->next;
|
||||
}
|
||||
|
||||
static void eth_set_dev(struct eth_device *dev)
|
||||
{
|
||||
eth_current = dev;
|
||||
}
|
||||
|
||||
struct eth_device *eth_get_dev_by_name(const char *devname)
|
||||
{
|
||||
struct eth_device *dev, *target_dev;
|
||||
|
||||
BUG_ON(devname == NULL);
|
||||
|
||||
if (!eth_devices)
|
||||
return NULL;
|
||||
|
||||
dev = eth_devices;
|
||||
target_dev = NULL;
|
||||
do {
|
||||
if (strcmp(devname, dev->name) == 0) {
|
||||
target_dev = dev;
|
||||
break;
|
||||
}
|
||||
dev = dev->next;
|
||||
} while (dev != eth_devices);
|
||||
|
||||
return target_dev;
|
||||
}
|
||||
|
||||
struct eth_device *eth_get_dev_by_index(int index)
|
||||
{
|
||||
struct eth_device *dev, *target_dev;
|
||||
|
||||
if (!eth_devices)
|
||||
return NULL;
|
||||
|
||||
dev = eth_devices;
|
||||
target_dev = NULL;
|
||||
do {
|
||||
if (dev->index == index) {
|
||||
target_dev = dev;
|
||||
break;
|
||||
}
|
||||
dev = dev->next;
|
||||
} while (dev != eth_devices);
|
||||
|
||||
return target_dev;
|
||||
}
|
||||
|
||||
int eth_get_dev_index(void)
|
||||
{
|
||||
if (!eth_current)
|
||||
return -1;
|
||||
|
||||
return eth_current->index;
|
||||
}
|
||||
|
||||
static int on_ethaddr(const char *name, const char *value, enum env_op op,
|
||||
int flags)
|
||||
{
|
||||
int index;
|
||||
struct eth_device *dev;
|
||||
|
||||
if (!eth_devices)
|
||||
return 0;
|
||||
|
||||
/* look for an index after "eth" */
|
||||
index = simple_strtoul(name + 3, NULL, 10);
|
||||
|
||||
dev = eth_devices;
|
||||
do {
|
||||
if (dev->index == index) {
|
||||
switch (op) {
|
||||
case env_op_create:
|
||||
case env_op_overwrite:
|
||||
eth_parse_enetaddr(value, dev->enetaddr);
|
||||
break;
|
||||
case env_op_delete:
|
||||
memset(dev->enetaddr, 0, 6);
|
||||
}
|
||||
}
|
||||
dev = dev->next;
|
||||
} while (dev != eth_devices);
|
||||
|
||||
return 0;
|
||||
}
|
||||
U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
|
||||
|
||||
int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
|
||||
int eth_number)
|
||||
{
|
||||
unsigned char env_enetaddr[6];
|
||||
int ret = 0;
|
||||
|
||||
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
|
||||
|
||||
if (!is_zero_ethaddr(env_enetaddr)) {
|
||||
if (!is_zero_ethaddr(dev->enetaddr) &&
|
||||
memcmp(dev->enetaddr, env_enetaddr, 6)) {
|
||||
printf("\nWarning: %s MAC addresses don't match:\n",
|
||||
dev->name);
|
||||
printf("Address in SROM is %pM\n",
|
||||
dev->enetaddr);
|
||||
printf("Address in environment is %pM\n",
|
||||
env_enetaddr);
|
||||
}
|
||||
|
||||
memcpy(dev->enetaddr, env_enetaddr, 6);
|
||||
} else if (is_valid_ethaddr(dev->enetaddr)) {
|
||||
eth_setenv_enetaddr_by_index(base_name, eth_number,
|
||||
dev->enetaddr);
|
||||
} else if (is_zero_ethaddr(dev->enetaddr)) {
|
||||
#ifdef CONFIG_NET_RANDOM_ETHADDR
|
||||
net_random_ethaddr(dev->enetaddr);
|
||||
printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
|
||||
dev->name, eth_number, dev->enetaddr);
|
||||
#else
|
||||
printf("\nError: %s address not set.\n",
|
||||
dev->name);
|
||||
return -EINVAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
|
||||
if (!is_valid_ethaddr(dev->enetaddr)) {
|
||||
printf("\nError: %s address %pM illegal value\n",
|
||||
dev->name, dev->enetaddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = dev->write_hwaddr(dev);
|
||||
if (ret)
|
||||
printf("\nWarning: %s failed to set MAC address\n",
|
||||
dev->name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int eth_register(struct eth_device *dev)
|
||||
{
|
||||
struct eth_device *d;
|
||||
static int index;
|
||||
|
||||
assert(strlen(dev->name) < sizeof(dev->name));
|
||||
|
||||
if (!eth_devices) {
|
||||
eth_devices = dev;
|
||||
eth_current = dev;
|
||||
eth_current_changed();
|
||||
} else {
|
||||
for (d = eth_devices; d->next != eth_devices; d = d->next)
|
||||
;
|
||||
d->next = dev;
|
||||
}
|
||||
|
||||
dev->state = ETH_STATE_INIT;
|
||||
dev->next = eth_devices;
|
||||
dev->index = index++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eth_unregister(struct eth_device *dev)
|
||||
{
|
||||
struct eth_device *cur;
|
||||
|
||||
/* No device */
|
||||
if (!eth_devices)
|
||||
return -ENODEV;
|
||||
|
||||
for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
|
||||
cur = cur->next)
|
||||
;
|
||||
|
||||
/* Device not found */
|
||||
if (cur->next != dev)
|
||||
return -ENODEV;
|
||||
|
||||
cur->next = dev->next;
|
||||
|
||||
if (eth_devices == dev)
|
||||
eth_devices = dev->next == eth_devices ? NULL : dev->next;
|
||||
|
||||
if (eth_current == dev) {
|
||||
eth_current = eth_devices;
|
||||
eth_current_changed();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eth_initialize(void)
|
||||
{
|
||||
int num_devices = 0;
|
||||
|
||||
eth_devices = NULL;
|
||||
eth_current = NULL;
|
||||
eth_common_init();
|
||||
|
||||
if (!eth_devices) {
|
||||
puts("No ethernet found.\n");
|
||||
bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
|
||||
} else {
|
||||
struct eth_device *dev = eth_devices;
|
||||
char *ethprime = getenv("ethprime");
|
||||
|
||||
bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
|
||||
do {
|
||||
if (dev->index)
|
||||
puts(", ");
|
||||
|
||||
printf("%s", dev->name);
|
||||
|
||||
if (ethprime && strcmp(dev->name, ethprime) == 0) {
|
||||
eth_current = dev;
|
||||
puts(" [PRIME]");
|
||||
}
|
||||
|
||||
if (strchr(dev->name, ' '))
|
||||
puts("\nWarning: eth device name has a space!"
|
||||
"\n");
|
||||
|
||||
eth_write_hwaddr(dev, "eth", dev->index);
|
||||
|
||||
dev = dev->next;
|
||||
num_devices++;
|
||||
} while (dev != eth_devices);
|
||||
|
||||
eth_current_changed();
|
||||
putc('\n');
|
||||
}
|
||||
|
||||
return num_devices;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MCAST_TFTP
|
||||
/* Multicast.
|
||||
* mcast_addr: multicast ipaddr from which multicast Mac is made
|
||||
* join: 1=join, 0=leave.
|
||||
*/
|
||||
int eth_mcast_join(struct in_addr mcast_ip, int join)
|
||||
{
|
||||
u8 mcast_mac[6];
|
||||
if (!eth_current || !eth_current->mcast)
|
||||
return -1;
|
||||
mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
|
||||
mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
|
||||
mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
|
||||
mcast_mac[2] = 0x5e;
|
||||
mcast_mac[1] = 0x0;
|
||||
mcast_mac[0] = 0x1;
|
||||
return eth_current->mcast(eth_current, mcast_mac, join);
|
||||
}
|
||||
|
||||
/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
|
||||
* and this is the ethernet-crc method needed for TSEC -- and perhaps
|
||||
* some other adapter -- hash tables
|
||||
*/
|
||||
#define CRCPOLY_LE 0xedb88320
|
||||
u32 ether_crc(size_t len, unsigned char const *p)
|
||||
{
|
||||
int i;
|
||||
u32 crc;
|
||||
crc = ~0;
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
|
||||
}
|
||||
/* an reverse the bits, cuz of way they arrive -- last-first */
|
||||
crc = (crc >> 16) | (crc << 16);
|
||||
crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
|
||||
crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
|
||||
crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
|
||||
crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
|
||||
return crc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int eth_init(void)
|
||||
{
|
||||
struct eth_device *old_current;
|
||||
|
||||
if (!eth_current) {
|
||||
puts("No ethernet found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
old_current = eth_current;
|
||||
do {
|
||||
debug("Trying %s\n", eth_current->name);
|
||||
|
||||
if (eth_current->init(eth_current, gd->bd) >= 0) {
|
||||
eth_current->state = ETH_STATE_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
debug("FAIL\n");
|
||||
|
||||
eth_try_another(0);
|
||||
} while (old_current != eth_current);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
void eth_halt(void)
|
||||
{
|
||||
if (!eth_current)
|
||||
return;
|
||||
|
||||
eth_current->halt(eth_current);
|
||||
|
||||
eth_current->state = ETH_STATE_PASSIVE;
|
||||
}
|
||||
|
||||
int eth_is_active(struct eth_device *dev)
|
||||
{
|
||||
return dev && dev->state == ETH_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
int eth_send(void *packet, int length)
|
||||
{
|
||||
if (!eth_current)
|
||||
return -ENODEV;
|
||||
|
||||
return eth_current->send(eth_current, packet, length);
|
||||
}
|
||||
|
||||
int eth_rx(void)
|
||||
{
|
||||
if (!eth_current)
|
||||
return -ENODEV;
|
||||
|
||||
return eth_current->recv(eth_current);
|
||||
}
|
||||
#endif /* ifndef CONFIG_DM_ETH */
|
||||
|
||||
#ifdef CONFIG_API
|
||||
static void eth_save_packet(void *packet, int length)
|
||||
{
|
||||
char *p = packet;
|
||||
int i;
|
||||
|
||||
if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
|
||||
return;
|
||||
|
||||
if (PKTSIZE < length)
|
||||
return;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
|
||||
|
||||
eth_rcv_bufs[eth_rcv_last].length = length;
|
||||
eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
|
||||
}
|
||||
|
||||
int eth_receive(void *packet, int length)
|
||||
{
|
||||
char *p = packet;
|
||||
void *pp = push_packet;
|
||||
int i;
|
||||
|
||||
if (eth_rcv_current == eth_rcv_last) {
|
||||
push_packet = eth_save_packet;
|
||||
eth_rx();
|
||||
push_packet = pp;
|
||||
|
||||
if (eth_rcv_current == eth_rcv_last)
|
||||
return -1;
|
||||
}
|
||||
|
||||
length = min(eth_rcv_bufs[eth_rcv_current].length, length);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
|
||||
|
||||
eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
|
||||
return length;
|
||||
}
|
||||
#endif /* CONFIG_API */
|
||||
|
||||
static void eth_current_changed(void)
|
||||
{
|
||||
char *act = getenv("ethact");
|
||||
char *ethrotate;
|
||||
|
||||
/*
|
||||
* The call to eth_get_dev() below has a side effect of rotating
|
||||
* ethernet device if uc_priv->current == NULL. This is not what
|
||||
* we want when 'ethrotate' variable is 'no'.
|
||||
*/
|
||||
ethrotate = getenv("ethrotate");
|
||||
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
|
||||
return;
|
||||
|
||||
/* update current ethernet name */
|
||||
if (eth_get_dev()) {
|
||||
if (act == NULL || strcmp(act, eth_get_name()) != 0)
|
||||
setenv("ethact", eth_get_name());
|
||||
}
|
||||
/*
|
||||
* remove the variable completely if there is no active
|
||||
* interface
|
||||
*/
|
||||
else if (act != NULL)
|
||||
setenv("ethact", NULL);
|
||||
}
|
||||
|
||||
void eth_try_another(int first_restart)
|
||||
{
|
||||
static void *first_failed;
|
||||
char *ethrotate;
|
||||
|
||||
/*
|
||||
* Do not rotate between network interfaces when
|
||||
* 'ethrotate' variable is set to 'no'.
|
||||
*/
|
||||
ethrotate = getenv("ethrotate");
|
||||
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
|
||||
return;
|
||||
|
||||
if (!eth_get_dev())
|
||||
return;
|
||||
|
||||
if (first_restart)
|
||||
first_failed = eth_get_dev();
|
||||
|
||||
eth_set_current_to_next();
|
||||
|
||||
eth_current_changed();
|
||||
|
||||
if (first_failed == eth_get_dev())
|
||||
net_restart_wrap = 1;
|
||||
}
|
||||
|
||||
void eth_set_current(void)
|
||||
{
|
||||
static char *act;
|
||||
static int env_changed_id;
|
||||
int env_id;
|
||||
|
||||
env_id = get_env_id();
|
||||
if ((act == NULL) || (env_changed_id != env_id)) {
|
||||
act = getenv("ethact");
|
||||
env_changed_id = env_id;
|
||||
}
|
||||
|
||||
if (act == NULL) {
|
||||
char *ethprime = getenv("ethprime");
|
||||
void *dev = NULL;
|
||||
|
||||
if (ethprime)
|
||||
dev = eth_get_dev_by_name(ethprime);
|
||||
if (dev)
|
||||
eth_set_dev(dev);
|
||||
else
|
||||
eth_set_dev(NULL);
|
||||
} else {
|
||||
eth_set_dev(eth_get_dev_by_name(act));
|
||||
}
|
||||
|
||||
eth_current_changed();
|
||||
}
|
||||
|
||||
const char *eth_get_name(void)
|
||||
{
|
||||
return eth_get_dev() ? eth_get_dev()->name : "unknown";
|
||||
}
|
166
net/eth_common.c
Normal file
166
net/eth_common.c
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* (C) Copyright 2001-2015
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
* Joe Hershberger, National Instruments
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <miiphy.h>
|
||||
#include <net.h>
|
||||
#include "eth_internal.h"
|
||||
|
||||
void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
|
||||
{
|
||||
char *end;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 6; ++i) {
|
||||
enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
|
||||
if (addr)
|
||||
addr = (*end) ? end + 1 : end;
|
||||
}
|
||||
}
|
||||
|
||||
int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
|
||||
{
|
||||
eth_parse_enetaddr(getenv(name), enetaddr);
|
||||
return is_valid_ethaddr(enetaddr);
|
||||
}
|
||||
|
||||
int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
sprintf(buf, "%pM", enetaddr);
|
||||
|
||||
return setenv(name, buf);
|
||||
}
|
||||
|
||||
int eth_getenv_enetaddr_by_index(const char *base_name, int index,
|
||||
uchar *enetaddr)
|
||||
{
|
||||
char enetvar[32];
|
||||
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
|
||||
return eth_getenv_enetaddr(enetvar, enetaddr);
|
||||
}
|
||||
|
||||
int eth_setenv_enetaddr_by_index(const char *base_name, int index,
|
||||
uchar *enetaddr)
|
||||
{
|
||||
char enetvar[32];
|
||||
sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
|
||||
return eth_setenv_enetaddr(enetvar, enetaddr);
|
||||
}
|
||||
|
||||
void eth_common_init(void)
|
||||
{
|
||||
bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
|
||||
miiphy_init();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PHYLIB
|
||||
phy_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
int eth_mac_skip(int index)
|
||||
{
|
||||
char enetvar[15];
|
||||
char *skip_state;
|
||||
|
||||
sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
|
||||
skip_state = getenv(enetvar);
|
||||
return skip_state != NULL;
|
||||
}
|
||||
|
||||
void eth_current_changed(void)
|
||||
{
|
||||
char *act = getenv("ethact");
|
||||
char *ethrotate;
|
||||
|
||||
/*
|
||||
* The call to eth_get_dev() below has a side effect of rotating
|
||||
* ethernet device if uc_priv->current == NULL. This is not what
|
||||
* we want when 'ethrotate' variable is 'no'.
|
||||
*/
|
||||
ethrotate = getenv("ethrotate");
|
||||
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
|
||||
return;
|
||||
|
||||
/* update current ethernet name */
|
||||
if (eth_get_dev()) {
|
||||
if (act == NULL || strcmp(act, eth_get_name()) != 0)
|
||||
setenv("ethact", eth_get_name());
|
||||
}
|
||||
/*
|
||||
* remove the variable completely if there is no active
|
||||
* interface
|
||||
*/
|
||||
else if (act != NULL)
|
||||
setenv("ethact", NULL);
|
||||
}
|
||||
|
||||
void eth_try_another(int first_restart)
|
||||
{
|
||||
static void *first_failed;
|
||||
char *ethrotate;
|
||||
|
||||
/*
|
||||
* Do not rotate between network interfaces when
|
||||
* 'ethrotate' variable is set to 'no'.
|
||||
*/
|
||||
ethrotate = getenv("ethrotate");
|
||||
if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
|
||||
return;
|
||||
|
||||
if (!eth_get_dev())
|
||||
return;
|
||||
|
||||
if (first_restart)
|
||||
first_failed = eth_get_dev();
|
||||
|
||||
eth_set_current_to_next();
|
||||
|
||||
eth_current_changed();
|
||||
|
||||
if (first_failed == eth_get_dev())
|
||||
net_restart_wrap = 1;
|
||||
}
|
||||
|
||||
void eth_set_current(void)
|
||||
{
|
||||
static char *act;
|
||||
static int env_changed_id;
|
||||
int env_id;
|
||||
|
||||
env_id = get_env_id();
|
||||
if ((act == NULL) || (env_changed_id != env_id)) {
|
||||
act = getenv("ethact");
|
||||
env_changed_id = env_id;
|
||||
}
|
||||
|
||||
if (act == NULL) {
|
||||
char *ethprime = getenv("ethprime");
|
||||
void *dev = NULL;
|
||||
|
||||
if (ethprime)
|
||||
dev = eth_get_dev_by_name(ethprime);
|
||||
if (dev)
|
||||
eth_set_dev(dev);
|
||||
else
|
||||
eth_set_dev(NULL);
|
||||
} else {
|
||||
eth_set_dev(eth_get_dev_by_name(act));
|
||||
}
|
||||
|
||||
eth_current_changed();
|
||||
}
|
||||
|
||||
const char *eth_get_name(void)
|
||||
{
|
||||
return eth_get_dev() ? eth_get_dev()->name : "unknown";
|
||||
}
|
40
net/eth_internal.h
Normal file
40
net/eth_internal.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* (C) Copyright 2001-2015
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
* Joe Hershberger, National Instruments
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __ETH_INTERNAL_H
|
||||
#define __ETH_INTERNAL_H
|
||||
|
||||
/* Do init that is common to driver model and legacy networking */
|
||||
void eth_common_init(void);
|
||||
|
||||
/**
|
||||
* eth_setenv_enetaddr_by_index() - set the MAC address envrionment variable
|
||||
*
|
||||
* This sets up an environment variable with the given MAC address (@enetaddr).
|
||||
* The environment variable to be set is defined by <@base_name><@index>addr.
|
||||
* If @index is 0 it is omitted. For common Ethernet this means ethaddr,
|
||||
* eth1addr, etc.
|
||||
*
|
||||
* @base_name: Base name for variable, typically "eth"
|
||||
* @index: Index of interface being updated (>=0)
|
||||
* @enetaddr: Pointer to MAC address to put into the variable
|
||||
* @return 0 if OK, other value on error
|
||||
*/
|
||||
int eth_setenv_enetaddr_by_index(const char *base_name, int index,
|
||||
uchar *enetaddr);
|
||||
|
||||
int eth_mac_skip(int index);
|
||||
void eth_current_changed(void);
|
||||
#ifdef CONFIG_DM_ETH
|
||||
void eth_set_dev(struct udevice *dev);
|
||||
#else
|
||||
void eth_set_dev(struct eth_device *dev);
|
||||
#endif
|
||||
void eth_set_current_to_next(void);
|
||||
|
||||
#endif
|
439
net/eth_legacy.c
Normal file
439
net/eth_legacy.c
Normal file
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
* (C) Copyright 2001-2015
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
* Joe Hershberger, National Instruments
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <environment.h>
|
||||
#include <net.h>
|
||||
#include <phy.h>
|
||||
#include <asm/errno.h>
|
||||
#include "eth_internal.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* CPU and board-specific Ethernet initializations. Aliased function
|
||||
* signals caller to move on
|
||||
*/
|
||||
static int __def_eth_init(bd_t *bis)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
|
||||
int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
|
||||
|
||||
#ifdef CONFIG_API
|
||||
static struct {
|
||||
uchar data[PKTSIZE];
|
||||
int length;
|
||||
} eth_rcv_bufs[PKTBUFSRX];
|
||||
|
||||
static unsigned int eth_rcv_current, eth_rcv_last;
|
||||
#endif
|
||||
|
||||
static struct eth_device *eth_devices;
|
||||
struct eth_device *eth_current;
|
||||
|
||||
void eth_set_current_to_next(void)
|
||||
{
|
||||
eth_current = eth_current->next;
|
||||
}
|
||||
|
||||
void eth_set_dev(struct eth_device *dev)
|
||||
{
|
||||
eth_current = dev;
|
||||
}
|
||||
|
||||
struct eth_device *eth_get_dev_by_name(const char *devname)
|
||||
{
|
||||
struct eth_device *dev, *target_dev;
|
||||
|
||||
BUG_ON(devname == NULL);
|
||||
|
||||
if (!eth_devices)
|
||||
return NULL;
|
||||
|
||||
dev = eth_devices;
|
||||
target_dev = NULL;
|
||||
do {
|
||||
if (strcmp(devname, dev->name) == 0) {
|
||||
target_dev = dev;
|
||||
break;
|
||||
}
|
||||
dev = dev->next;
|
||||
} while (dev != eth_devices);
|
||||
|
||||
return target_dev;
|
||||
}
|
||||
|
||||
struct eth_device *eth_get_dev_by_index(int index)
|
||||
{
|
||||
struct eth_device *dev, *target_dev;
|
||||
|
||||
if (!eth_devices)
|
||||
return NULL;
|
||||
|
||||
dev = eth_devices;
|
||||
target_dev = NULL;
|
||||
do {
|
||||
if (dev->index == index) {
|
||||
target_dev = dev;
|
||||
break;
|
||||
}
|
||||
dev = dev->next;
|
||||
} while (dev != eth_devices);
|
||||
|
||||
return target_dev;
|
||||
}
|
||||
|
||||
int eth_get_dev_index(void)
|
||||
{
|
||||
if (!eth_current)
|
||||
return -1;
|
||||
|
||||
return eth_current->index;
|
||||
}
|
||||
|
||||
static int on_ethaddr(const char *name, const char *value, enum env_op op,
|
||||
int flags)
|
||||
{
|
||||
int index;
|
||||
struct eth_device *dev;
|
||||
|
||||
if (!eth_devices)
|
||||
return 0;
|
||||
|
||||
/* look for an index after "eth" */
|
||||
index = simple_strtoul(name + 3, NULL, 10);
|
||||
|
||||
dev = eth_devices;
|
||||
do {
|
||||
if (dev->index == index) {
|
||||
switch (op) {
|
||||
case env_op_create:
|
||||
case env_op_overwrite:
|
||||
eth_parse_enetaddr(value, dev->enetaddr);
|
||||
break;
|
||||
case env_op_delete:
|
||||
memset(dev->enetaddr, 0, 6);
|
||||
}
|
||||
}
|
||||
dev = dev->next;
|
||||
} while (dev != eth_devices);
|
||||
|
||||
return 0;
|
||||
}
|
||||
U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
|
||||
|
||||
int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
|
||||
int eth_number)
|
||||
{
|
||||
unsigned char env_enetaddr[6];
|
||||
int ret = 0;
|
||||
|
||||
eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
|
||||
|
||||
if (!is_zero_ethaddr(env_enetaddr)) {
|
||||
if (!is_zero_ethaddr(dev->enetaddr) &&
|
||||
memcmp(dev->enetaddr, env_enetaddr, 6)) {
|
||||
printf("\nWarning: %s MAC addresses don't match:\n",
|
||||
dev->name);
|
||||
printf("Address in SROM is %pM\n",
|
||||
dev->enetaddr);
|
||||
printf("Address in environment is %pM\n",
|
||||
env_enetaddr);
|
||||
}
|
||||
|
||||
memcpy(dev->enetaddr, env_enetaddr, 6);
|
||||
} else if (is_valid_ethaddr(dev->enetaddr)) {
|
||||
eth_setenv_enetaddr_by_index(base_name, eth_number,
|
||||
dev->enetaddr);
|
||||
} else if (is_zero_ethaddr(dev->enetaddr)) {
|
||||
#ifdef CONFIG_NET_RANDOM_ETHADDR
|
||||
net_random_ethaddr(dev->enetaddr);
|
||||
printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
|
||||
dev->name, eth_number, dev->enetaddr);
|
||||
#else
|
||||
printf("\nError: %s address not set.\n",
|
||||
dev->name);
|
||||
return -EINVAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
|
||||
if (!is_valid_ethaddr(dev->enetaddr)) {
|
||||
printf("\nError: %s address %pM illegal value\n",
|
||||
dev->name, dev->enetaddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = dev->write_hwaddr(dev);
|
||||
if (ret)
|
||||
printf("\nWarning: %s failed to set MAC address\n",
|
||||
dev->name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int eth_register(struct eth_device *dev)
|
||||
{
|
||||
struct eth_device *d;
|
||||
static int index;
|
||||
|
||||
assert(strlen(dev->name) < sizeof(dev->name));
|
||||
|
||||
if (!eth_devices) {
|
||||
eth_devices = dev;
|
||||
eth_current = dev;
|
||||
eth_current_changed();
|
||||
} else {
|
||||
for (d = eth_devices; d->next != eth_devices; d = d->next)
|
||||
;
|
||||
d->next = dev;
|
||||
}
|
||||
|
||||
dev->state = ETH_STATE_INIT;
|
||||
dev->next = eth_devices;
|
||||
dev->index = index++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eth_unregister(struct eth_device *dev)
|
||||
{
|
||||
struct eth_device *cur;
|
||||
|
||||
/* No device */
|
||||
if (!eth_devices)
|
||||
return -ENODEV;
|
||||
|
||||
for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
|
||||
cur = cur->next)
|
||||
;
|
||||
|
||||
/* Device not found */
|
||||
if (cur->next != dev)
|
||||
return -ENODEV;
|
||||
|
||||
cur->next = dev->next;
|
||||
|
||||
if (eth_devices == dev)
|
||||
eth_devices = dev->next == eth_devices ? NULL : dev->next;
|
||||
|
||||
if (eth_current == dev) {
|
||||
eth_current = eth_devices;
|
||||
eth_current_changed();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int eth_initialize(void)
|
||||
{
|
||||
int num_devices = 0;
|
||||
|
||||
eth_devices = NULL;
|
||||
eth_current = NULL;
|
||||
eth_common_init();
|
||||
/*
|
||||
* If board-specific initialization exists, call it.
|
||||
* If not, call a CPU-specific one
|
||||
*/
|
||||
if (board_eth_init != __def_eth_init) {
|
||||
if (board_eth_init(gd->bd) < 0)
|
||||
printf("Board Net Initialization Failed\n");
|
||||
} else if (cpu_eth_init != __def_eth_init) {
|
||||
if (cpu_eth_init(gd->bd) < 0)
|
||||
printf("CPU Net Initialization Failed\n");
|
||||
} else {
|
||||
printf("Net Initialization Skipped\n");
|
||||
}
|
||||
|
||||
if (!eth_devices) {
|
||||
puts("No ethernet found.\n");
|
||||
bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
|
||||
} else {
|
||||
struct eth_device *dev = eth_devices;
|
||||
char *ethprime = getenv("ethprime");
|
||||
|
||||
bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
|
||||
do {
|
||||
if (dev->index)
|
||||
puts(", ");
|
||||
|
||||
printf("%s", dev->name);
|
||||
|
||||
if (ethprime && strcmp(dev->name, ethprime) == 0) {
|
||||
eth_current = dev;
|
||||
puts(" [PRIME]");
|
||||
}
|
||||
|
||||
if (strchr(dev->name, ' '))
|
||||
puts("\nWarning: eth device name has a space!"
|
||||
"\n");
|
||||
|
||||
eth_write_hwaddr(dev, "eth", dev->index);
|
||||
|
||||
dev = dev->next;
|
||||
num_devices++;
|
||||
} while (dev != eth_devices);
|
||||
|
||||
eth_current_changed();
|
||||
putc('\n');
|
||||
}
|
||||
|
||||
return num_devices;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MCAST_TFTP
|
||||
/* Multicast.
|
||||
* mcast_addr: multicast ipaddr from which multicast Mac is made
|
||||
* join: 1=join, 0=leave.
|
||||
*/
|
||||
int eth_mcast_join(struct in_addr mcast_ip, int join)
|
||||
{
|
||||
u8 mcast_mac[6];
|
||||
if (!eth_current || !eth_current->mcast)
|
||||
return -1;
|
||||
mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
|
||||
mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
|
||||
mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
|
||||
mcast_mac[2] = 0x5e;
|
||||
mcast_mac[1] = 0x0;
|
||||
mcast_mac[0] = 0x1;
|
||||
return eth_current->mcast(eth_current, mcast_mac, join);
|
||||
}
|
||||
|
||||
/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
|
||||
* and this is the ethernet-crc method needed for TSEC -- and perhaps
|
||||
* some other adapter -- hash tables
|
||||
*/
|
||||
#define CRCPOLY_LE 0xedb88320
|
||||
u32 ether_crc(size_t len, unsigned char const *p)
|
||||
{
|
||||
int i;
|
||||
u32 crc;
|
||||
crc = ~0;
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
|
||||
}
|
||||
/* an reverse the bits, cuz of way they arrive -- last-first */
|
||||
crc = (crc >> 16) | (crc << 16);
|
||||
crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
|
||||
crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
|
||||
crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
|
||||
crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
|
||||
return crc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int eth_init(void)
|
||||
{
|
||||
struct eth_device *old_current;
|
||||
|
||||
if (!eth_current) {
|
||||
puts("No ethernet found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
old_current = eth_current;
|
||||
do {
|
||||
debug("Trying %s\n", eth_current->name);
|
||||
|
||||
if (eth_current->init(eth_current, gd->bd) >= 0) {
|
||||
eth_current->state = ETH_STATE_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
debug("FAIL\n");
|
||||
|
||||
eth_try_another(0);
|
||||
} while (old_current != eth_current);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
void eth_halt(void)
|
||||
{
|
||||
if (!eth_current)
|
||||
return;
|
||||
|
||||
eth_current->halt(eth_current);
|
||||
|
||||
eth_current->state = ETH_STATE_PASSIVE;
|
||||
}
|
||||
|
||||
int eth_is_active(struct eth_device *dev)
|
||||
{
|
||||
return dev && dev->state == ETH_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
int eth_send(void *packet, int length)
|
||||
{
|
||||
if (!eth_current)
|
||||
return -ENODEV;
|
||||
|
||||
return eth_current->send(eth_current, packet, length);
|
||||
}
|
||||
|
||||
int eth_rx(void)
|
||||
{
|
||||
if (!eth_current)
|
||||
return -ENODEV;
|
||||
|
||||
return eth_current->recv(eth_current);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_API
|
||||
static void eth_save_packet(void *packet, int length)
|
||||
{
|
||||
char *p = packet;
|
||||
int i;
|
||||
|
||||
if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
|
||||
return;
|
||||
|
||||
if (PKTSIZE < length)
|
||||
return;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
|
||||
|
||||
eth_rcv_bufs[eth_rcv_last].length = length;
|
||||
eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
|
||||
}
|
||||
|
||||
int eth_receive(void *packet, int length)
|
||||
{
|
||||
char *p = packet;
|
||||
void *pp = push_packet;
|
||||
int i;
|
||||
|
||||
if (eth_rcv_current == eth_rcv_last) {
|
||||
push_packet = eth_save_packet;
|
||||
eth_rx();
|
||||
push_packet = pp;
|
||||
|
||||
if (eth_rcv_current == eth_rcv_last)
|
||||
return -1;
|
||||
}
|
||||
|
||||
length = min(eth_rcv_bufs[eth_rcv_current].length, length);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
|
||||
|
||||
eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
|
||||
return length;
|
||||
}
|
||||
#endif /* CONFIG_API */
|
Loading…
Add table
Reference in a new issue