blob: d2beb71c68486b7f561f3b2b855af48b8b64ef6c [file] [log] [blame]
Marek Vasute1e7af42025-01-31 02:19:57 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2025 Marek Vasut <marek.vasut+renesas@mailbox.org>
4 */
5
6#include <dm.h>
7#include <i2c.h>
8#include <malloc.h>
9#include <net-common.h>
10
11#define S4SK_FPGA_I2C_BUS "i2c5"
12#define S4SK_FPGA_I2C_DEV_ADDR 0x70
13#define S4SK_FPGA_I2C_DEV_WIDTH 2
14#define S4SK_FPGA_I2C_MAC_COUNT 4
15#define S4SK_FPGA_I2C_MAC_OFFSET 0x58
16#define S4SK_FPGA_I2C_MAC_WIDTH 8
17
18int board_late_init(void)
19{
20 /*
21 * Extract AVB and TSN0,1,2 MAC addresses from FPGA via I2C.
22 *
23 * In case a matching ethaddr/ethNaddr environment variable
24 * is not set, set it, otherwise do not override it. This
25 * allows users to set their own MAC addresses via ethaddr
26 * and ethNaddr environment variables.
27 *
28 * The ethaddr/ethNaddr mapping follows Linux kernel DT aliases
29 * ethernetN property assignment:
30 * - ethaddr ..... TSN0 (IC104 connector)
31 * - eth1addr .... TSN1 (IC101 connector)
32 * - eth2addr .... TSN2 (Expansion connector)
33 * - eth3addr .... AVB (CN1 connector)
34 */
35 ofnode i2c_node = ofnode_path(S4SK_FPGA_I2C_BUS);
36 struct udevice *bus, *dev;
37 unsigned char enetaddr[6];
38 unsigned char macs[32]; /* Four MAC addresses in FPGA in total. */
39 int i, idx, j, ret;
40
41 ret = uclass_get_device_by_ofnode(UCLASS_I2C, i2c_node, &bus);
42 if (ret < 0) {
43 printf("s4sk: cannot find i2c bus (%d)\n", ret);
44 return 0;
45 }
46
47 ret = i2c_get_chip(bus, S4SK_FPGA_I2C_DEV_ADDR,
48 S4SK_FPGA_I2C_DEV_WIDTH, &dev);
49 if (ret < 0) {
50 printf("s4sk: cannot find i2c chip (%d)\n", ret);
51 return 0;
52 }
53
54 ret = dm_i2c_read(dev, S4SK_FPGA_I2C_MAC_OFFSET, macs, sizeof(macs));
55 if (ret < 0) {
56 printf("s4sk: failed to read MAC addresses via i2c (%d)\n", ret);
57 return 0;
58 }
59
60 for (i = 0; i < S4SK_FPGA_I2C_MAC_COUNT; i++) {
61 /*
62 * Remap TSN0,1,2 to ethaddr,eth1addr,eth2addr and
63 * AVB to eth3addr to match Linux /aliases ethernetN
64 * assignment, which starts with ethernet0 for TSN.
65 */
66 idx = (i + 3) % 4;
67 ret = eth_env_get_enetaddr_by_index("eth", idx, enetaddr);
68 if (ret) /* ethaddr is already set */
69 continue;
70
71 /* Byte-wise reverse the MAC address */
72 for (j = 0; j < sizeof(enetaddr); j++)
73 enetaddr[j] = macs[i * S4SK_FPGA_I2C_MAC_WIDTH + (5 - j)];
74
75 if (!is_valid_ethaddr(enetaddr)) {
76 printf("s4sk: MAC address %d in FPGA not valid (%pM)\n",
77 i, enetaddr);
78 continue;
79 }
80
81 eth_env_set_enetaddr_by_index("eth", idx, enetaddr);
82 }
83
84 return 0;
85}