blob: d2beb71c68486b7f561f3b2b855af48b8b64ef6c [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2025 Marek Vasut <marek.vasut+renesas@mailbox.org>
*/
#include <dm.h>
#include <i2c.h>
#include <malloc.h>
#include <net-common.h>
#define S4SK_FPGA_I2C_BUS "i2c5"
#define S4SK_FPGA_I2C_DEV_ADDR 0x70
#define S4SK_FPGA_I2C_DEV_WIDTH 2
#define S4SK_FPGA_I2C_MAC_COUNT 4
#define S4SK_FPGA_I2C_MAC_OFFSET 0x58
#define S4SK_FPGA_I2C_MAC_WIDTH 8
int board_late_init(void)
{
/*
* Extract AVB and TSN0,1,2 MAC addresses from FPGA via I2C.
*
* In case a matching ethaddr/ethNaddr environment variable
* is not set, set it, otherwise do not override it. This
* allows users to set their own MAC addresses via ethaddr
* and ethNaddr environment variables.
*
* The ethaddr/ethNaddr mapping follows Linux kernel DT aliases
* ethernetN property assignment:
* - ethaddr ..... TSN0 (IC104 connector)
* - eth1addr .... TSN1 (IC101 connector)
* - eth2addr .... TSN2 (Expansion connector)
* - eth3addr .... AVB (CN1 connector)
*/
ofnode i2c_node = ofnode_path(S4SK_FPGA_I2C_BUS);
struct udevice *bus, *dev;
unsigned char enetaddr[6];
unsigned char macs[32]; /* Four MAC addresses in FPGA in total. */
int i, idx, j, ret;
ret = uclass_get_device_by_ofnode(UCLASS_I2C, i2c_node, &bus);
if (ret < 0) {
printf("s4sk: cannot find i2c bus (%d)\n", ret);
return 0;
}
ret = i2c_get_chip(bus, S4SK_FPGA_I2C_DEV_ADDR,
S4SK_FPGA_I2C_DEV_WIDTH, &dev);
if (ret < 0) {
printf("s4sk: cannot find i2c chip (%d)\n", ret);
return 0;
}
ret = dm_i2c_read(dev, S4SK_FPGA_I2C_MAC_OFFSET, macs, sizeof(macs));
if (ret < 0) {
printf("s4sk: failed to read MAC addresses via i2c (%d)\n", ret);
return 0;
}
for (i = 0; i < S4SK_FPGA_I2C_MAC_COUNT; i++) {
/*
* Remap TSN0,1,2 to ethaddr,eth1addr,eth2addr and
* AVB to eth3addr to match Linux /aliases ethernetN
* assignment, which starts with ethernet0 for TSN.
*/
idx = (i + 3) % 4;
ret = eth_env_get_enetaddr_by_index("eth", idx, enetaddr);
if (ret) /* ethaddr is already set */
continue;
/* Byte-wise reverse the MAC address */
for (j = 0; j < sizeof(enetaddr); j++)
enetaddr[j] = macs[i * S4SK_FPGA_I2C_MAC_WIDTH + (5 - j)];
if (!is_valid_ethaddr(enetaddr)) {
printf("s4sk: MAC address %d in FPGA not valid (%pM)\n",
i, enetaddr);
continue;
}
eth_env_set_enetaddr_by_index("eth", idx, enetaddr);
}
return 0;
}