Assign MAC address to main CPU interface and switch ports. Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx> --- arch/arm/boards/skov-imx8mp/board.c | 131 ++++++++++++++++++++++++++++ arch/arm/dts/imx8mp-skov.dts | 1 + 2 files changed, 132 insertions(+) diff --git a/arch/arm/boards/skov-imx8mp/board.c b/arch/arm/boards/skov-imx8mp/board.c index 3b6eb7b080..94d0bc75f9 100644 --- a/arch/arm/boards/skov-imx8mp/board.c +++ b/arch/arm/boards/skov-imx8mp/board.c @@ -10,9 +10,12 @@ #include <gpio.h> #include <init.h> #include <io.h> +#include <linux/nvmem-consumer.h> #include <mach/imx/bbu.h> #include <mach/imx/generic.h> #include <mach/imx/iomux-mx8mp.h> +#include <net.h> +#include <of_net.h> struct skov_imx8mp_priv { struct device *dev; @@ -85,6 +88,134 @@ static const struct board_description imx8mp_variants[] = { }, }; +static void skov_imx8mp_get_src_mac(struct skov_imx8mp_priv *priv, + struct device_node *s_np, u8 *mac, + int dst_id) +{ + char str[sizeof("xx:xx:xx:xx:xx:xx")]; + struct eth_device *s_edev; + int ret; + + s_edev = of_find_eth_device_by_node(s_np); + if (s_edev && is_valid_ether_addr(s_edev->ethaddr)) { + /* If the source device has a valid MAC address, use it in + * case address is overwritten by user. + */ + memcpy(mac, s_edev->ethaddr, ETH_ALEN); + return; + } + + /* if the source device has no valid MAC address, try to get it from + * nvmem if it configured in the devicetree. + */ + ret = of_get_mac_addr_nvmem(s_np, mac); + if (!ret) + return; + + /* if the source device has no valid MAC address, generate one with + * vendor OUI. + */ + ret = generate_ether_addr(mac, dst_id); + if (ret) + random_ether_addr(mac); + + /* set SKOV OUI */ + mac[0] = 0x00; + mac[1] = 0x0e; + mac[2] = 0xcd; + ethaddr_to_string(mac, str); + dev_warn(priv->dev, "Failed to get eth addr for idx=%d. Generating one: %s\n", + dst_id, str); +} + +static int skov_imx8mp_eth_register_ethaddr(struct skov_imx8mp_priv *priv, + struct device_node *d_np, + struct device_node *s_np, + int dst_id) +{ + struct eth_device *d_edev; + u8 mac[ETH_ALEN] = { 0 }; + + d_edev = of_find_eth_device_by_node(d_np); + if (d_edev) { + /* If the destination device already has a valid MAC address, do + * nothing, it was probably set to nv by user. + */ + if (is_valid_ether_addr(d_edev->ethaddr)) + return 0; + } + + skov_imx8mp_get_src_mac(priv, s_np, mac, dst_id); + + of_eth_register_ethaddr(d_np, mac); + + return 0; +} + +/* We have following requirements for the ethernet MAC addresses: + * - LAN1 MAC address should be the same as the MAC address stored in the FEC + * slot (FEC is not used on this board). + * - LAN2 MAC address should be the same as the EQOS MAC address. (EQOS is + * the master interface for the switch on this board, LAN2 and LAN1 are + * external ports of this switch). + * - LAN2 MAC address is usually higher than LAN1 MAC address. But production + * process do not guarantee this. So, we can't calculate LAN2 MAC address + * from LAN1 MAC address. + */ +static void skov_imx8mp_ethernet_init(struct skov_imx8mp_priv *priv) +{ + struct device_node *root; + unsigned int i; + struct eth_node_info { + const char *s_alias; + const char *d_alias; + } eth_node_info[] = { + { "ethernet0", "ethernet0" }, /* EQOS -> EQOS */ + { "ethernet0", "ethernet2" }, /* EQOS -> LAN2 */ + { "ethernet3", "ethernet1" }, /* FEC -> LAN1 */ + }; + + root = of_get_root_node(); + + for (i = 0; i < ARRAY_SIZE(eth_node_info); i++) { + const char *s_alias = eth_node_info[i].s_alias; + const char *d_alias = eth_node_info[i].d_alias; + struct device_node *s_np, *d_np; + int ret; + + s_np = of_find_node_by_alias(root, s_alias); + if (!s_np) { + dev_warn(priv->dev, "Failed to find src ethernet node by alias: %s\n", + s_alias); + continue; + } + + d_np = of_find_node_by_alias(root, d_alias); + if (!d_np) { + dev_warn(priv->dev, "Failed to find dst ethernet node by alias: %s\n", + d_alias); + continue; + } + + ret = skov_imx8mp_eth_register_ethaddr(priv, d_np, s_np, i); + if (ret) { + dev_warn(priv->dev, "Failed to transfer MAC address from alias %s to %s\n", + s_alias, d_alias); + continue; + } + } +} + +static int skov_imx8mp_populate_ethaddr(void) +{ + struct skov_imx8mp_priv *priv = skov_imx8mp_priv; + + skov_imx8mp_ethernet_init(priv); + + return 0; +} +postenvironment_initcall(skov_imx8mp_populate_ethaddr); + static int skov_imx8mp_fixup(struct device_node *root, void *data) { struct device_node *chosen = of_create_node(root, "/chosen"); diff --git a/arch/arm/dts/imx8mp-skov.dts b/arch/arm/dts/imx8mp-skov.dts index 3243a41697..063861427c 100644 --- a/arch/arm/dts/imx8mp-skov.dts +++ b/arch/arm/dts/imx8mp-skov.dts @@ -31,6 +31,7 @@ aliases { ethernet0 = &eqos; ethernet1 = &lan1; ethernet2 = &lan2; + ethernet3 = &fec; state = &state; }; -- 2.39.2