Files
OpenBMC/meta-luxshare/meta-common/recipes-bsp/u-boot/files/0001-Read-mac-address-from-eeprom.patch
T
2026-04-23 17:07:55 +08:00

381 lines
10 KiB
Diff
Executable File

From 96a4361b92455982ea3e9c71aae436a65a7a6a3e Mon Sep 17 00:00:00 2001
From: "Zhao.Chen" <zhao.chen@luxshare-ict.com>
Date: 10 Sep 2024 14:37:07 +0000
Read the MAC address from EEPROM and set it to env.
Tested:
printenv
ethaddr=88:88:88:88:88:8b
eth1addr=88:88:88:88:88:8d
%% original patch: 0002-read-mac-address-from-eeprom.patch
---
board/aspeed/evb_ast2600/Kconfig | 5 +
board/aspeed/evb_ast2600/evb_ast2600.c | 79 ++++++++++
common/board_r.c | 3 +-
drivers/misc/Kconfig | 6 +
drivers/misc/Makefile | 1 +
drivers/misc/at24.c | 204 +++++++++++++++++++++++++
6 files changed, 297 insertions(+), 1 deletion(-)
create mode 100644 drivers/misc/at24.c
diff --git a/board/aspeed/evb_ast2600/Kconfig b/board/aspeed/evb_ast2600/Kconfig
index a5d105199f..839cd0e649 100644
--- a/board/aspeed/evb_ast2600/Kconfig
+++ b/board/aspeed/evb_ast2600/Kconfig
@@ -10,4 +10,9 @@ config SYS_CONFIG_NAME
string "board configuration name"
default "evb_ast2600"
+config MAC_ADDR_IN_EEPROM
+ bool "MAC address in EEPROM"
+ help
+ Enable this option to read the MAC from the EEPROM
+
endif
diff --git a/board/aspeed/evb_ast2600/evb_ast2600.c b/board/aspeed/evb_ast2600/evb_ast2600.c
index 72ecb18c15..7244686bb1 100644
--- a/board/aspeed/evb_ast2600/evb_ast2600.c
+++ b/board/aspeed/evb_ast2600/evb_ast2600.c
@@ -131,3 +131,82 @@ int board_early_init_f(void)
espi_init();
return 0;
}
+
+#if defined(CONFIG_MAC_ADDR_IN_EEPROM)
+
+#include <dm.h>
+#include <environment.h>
+#include <i2c_eeprom.h>
+
+#define MAC_NUM 2
+#define MAC_BYTE_SIZE 6
+
+static int get_ethaddr_from_eeprom(u8 *addr)
+{
+ struct udevice *dev;
+ u32 mac_offset[MAC_NUM];
+ int i, ret, mac_read;
+
+ uclass_first_device_check(UCLASS_I2C_EEPROM, &dev);
+ if (!dev) {
+ printf("No eeprom found.\n");
+ } else {
+ do {
+ if (dev_read_bool(dev, "ethaddr-in-eeprom")) {
+ char prop_mac_offset[32];
+ mac_read = 0;
+ for (i = 0; i < MAC_NUM; i++) {
+ snprintf(prop_mac_offset, 32, "eth%d-offset", i);
+ ret = dev_read_u32(dev, prop_mac_offset, &mac_offset[i]);
+ if (0 == ret) {
+ ret = i2c_eeprom_read(dev, mac_offset[i],
+ addr+i*MAC_BYTE_SIZE, MAC_BYTE_SIZE);
+ if (ret != 0) {
+ printf("get eth%d from eeprom failed, offset=0x%x\n",
+ i, mac_offset[i]);
+ return -1;
+ } else {
+ mac_read++;
+ }
+ }
+ }
+ if (mac_read > 0)
+ return 0;
+ }
+ uclass_next_device_check(&dev);
+ } while (dev);
+ }
+ return -1;
+}
+
+int mac_read_from_eeprom(void)
+{
+ u8 ethaddr[MAC_NUM*MAC_BYTE_SIZE];
+ char addr_str[100];
+
+ memset(ethaddr, 0, sizeof(ethaddr));
+
+ if (get_ethaddr_from_eeprom(ethaddr)) {
+ printf("get ethaddr from eeprom failed.\n");
+ return 0;
+ }
+ for (int i = 0; i < MAC_NUM; i++) {
+ if (is_valid_ethaddr(&ethaddr[MAC_BYTE_SIZE*i])) {
+ memset(addr_str, 0, sizeof(addr_str));
+ if (i == 0) {
+ snprintf(addr_str, sizeof(addr_str), "ethaddr");
+ } else {
+ snprintf(addr_str, sizeof(addr_str), "eth%daddr", i);
+ }
+ eth_env_set_enetaddr(addr_str, &ethaddr[MAC_BYTE_SIZE*i]);
+ env_save();
+ } else {
+ printf("eeprom mac%d address invaild:%pM\n", i, \
+ &ethaddr[MAC_BYTE_SIZE*i]);
+ }
+ }
+
+ return 0;
+}
+#endif
+
diff --git a/common/board_r.c b/common/board_r.c
index 429b9a2833..f1c98362ac 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -744,7 +744,8 @@ static init_fnc_t init_sequence_r[] = {
#endif
INIT_FUNC_WATCHDOG_RESET
initr_secondary_cpu,
-#if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)
+#if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET) \
+ || defined(CONFIG_MAC_ADDR_IN_EEPROM)
mac_read_from_eeprom,
#endif
INIT_FUNC_WATCHDOG_RESET
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c2a188ac29..69eeaf51fa 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -260,6 +260,12 @@ config SPL_I2C_EEPROM
This option is an SPL-variant of the I2C_EEPROM option.
See the help of I2C_EEPROM for details.
+config EEPROM_AT24
+ bool "Enable driver for AT24 EEPROMs"
+ depends on MISC
+ help
+ Enable a driver for AT24 EEPROMs attached via I2C.
+
config ZYNQ_GEM_I2C_MAC_OFFSET
hex "Set the I2C MAC offset"
default 0x0
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index bee53a3559..4e76c7d398 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o
obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
+obj-$(CONFIG_$(SPL_)EEPROM_AT24) += at24.o
obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
obj-$(CONFIG_IMX8) += imx8/
obj-$(CONFIG_LED_STATUS) += status_led.o
diff --git a/drivers/misc/at24.c b/drivers/misc/at24.c
new file mode 100644
index 0000000000..e117098766
--- /dev/null
+++ b/drivers/misc/at24.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014 Google, Inc
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <dm.h>
+#include <i2c.h>
+#include <i2c_eeprom.h>
+
+/* Address pointer is 16 bit. */
+#define AT24_FLAG_ADDR16 BIT(7)
+/* sysfs-entry will be read-only. */
+#define AT24_FLAG_READONLY BIT(6)
+/* sysfs-entry will be world-readable. */
+#define AT24_FLAG_IRUGO BIT(5)
+/* Take always 8 addresses (24c00). */
+#define AT24_FLAG_TAKE8ADDR BIT(4)
+/* Factory-programmed serial number. */
+#define AT24_FLAG_SERIAL BIT(3)
+/* Factory-programmed mac address. */
+#define AT24_FLAG_MAC BIT(2)
+/* Does not auto-rollover reads to the next slave address. */
+#define AT24_FLAG_NO_RDROL BIT(1)
+
+struct at24_chip_data {
+ struct udevice *dev;
+ u32 byte_len;
+ u8 flags;
+ void (*read_post)(unsigned int off, char *buf, size_t count);
+};
+
+#define AT24_CHIP_DATA(_name, _len, _flags) \
+ static const struct at24_chip_data _name = { \
+ .byte_len = _len, .flags = _flags, \
+ }
+
+AT24_CHIP_DATA(at24_data_24c08, 8192 / 8, AT24_FLAG_NO_RDROL);
+AT24_CHIP_DATA(at24_data_24c16, 16384 / 8, AT24_FLAG_NO_RDROL);
+AT24_CHIP_DATA(at24_data_24c32, 32768 / 8, AT24_FLAG_ADDR16);
+AT24_CHIP_DATA(at24_data_24c64, 65536 / 8, AT24_FLAG_ADDR16);
+
+int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size)
+{
+ const struct i2c_eeprom_ops *ops = device_get_ops(dev);
+
+ if (!ops->read)
+ return -ENOSYS;
+
+ return ops->read(dev, offset, buf, size);
+}
+
+int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size)
+{
+ const struct i2c_eeprom_ops *ops = device_get_ops(dev);
+
+ if (!ops->write)
+ return -ENOSYS;
+
+ return ops->write(dev, offset, buf, size);
+}
+
+/*
+ * This routine supports chips which consume multiple I2C addresses. It
+ * computes the addressing information to be used for a given r/w request.
+ * Assumes that sanity checks for offset happened at sysfs-layer.
+ *
+ * Slave address and byte offset derive from the offset. Always
+ * set the byte address; on a multi-master board, another master
+ * may have changed the chip's "current" address pointer.
+ */
+static unsigned int at24_translate_offset(struct at24_chip_data *at24,
+ unsigned int *offset)
+{
+ unsigned int i = 0;
+
+ if (at24->flags & AT24_FLAG_ADDR16) {
+ i = *offset >> 16;
+ *offset &= 0xffff;
+ } else {
+ i = *offset >> 8;
+ *offset &= 0xff;
+ }
+
+ return i;
+}
+
+static size_t at24_adjust_read_count(struct at24_chip_data *at24,
+ unsigned int offset, size_t count)
+{
+ unsigned int bits;
+ size_t remainder;
+
+ /*
+ * In case of multi-address chips that don't rollover reads to
+ * the next slave address: truncate the count to the slave boundary,
+ * so that the read never straddles slaves.
+ */
+ if (at24->flags & AT24_FLAG_NO_RDROL) {
+ bits = (at24->flags & AT24_FLAG_ADDR16) ? 16 : 8;
+ remainder = BIT(bits) - offset;
+ if (count > remainder)
+ count = remainder;
+ }
+
+ return count;
+}
+
+static ssize_t at24_read(struct at24_chip_data *at24, uint8_t *buf,
+ unsigned int offset, size_t count)
+{
+ int ret;
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(at24->dev);
+ u8 chip_addr = chip->chip_addr;
+ int chip_addr_offset = at24_translate_offset(at24, &offset);
+
+ count = at24_adjust_read_count(at24, offset, count);
+ chip->chip_addr += chip_addr_offset;
+ ret = dm_i2c_read(at24->dev, offset, buf, count);
+ chip->chip_addr = chip_addr;
+
+ if (0 == ret) {
+ return count;
+ } else {
+ return -ETIMEDOUT;
+ }
+}
+
+static int i2c_eeprom_std_read(struct udevice *dev, int off, uint8_t *buf,
+ int size)
+{
+ struct at24_chip_data *at24;
+ int i, ret;
+
+ at24 = (struct at24_chip_data *)dev_get_driver_data(dev);
+
+ if (off + size > at24->byte_len)
+ return -EINVAL;
+
+ for (i = 0; size; i += ret, size -= ret) {
+ ret = at24_read(at24, buf + i, off + i, size);
+ if (ret < 0) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int i2c_eeprom_std_write(struct udevice *dev, int offset,
+ const uint8_t *buf, int size)
+{
+ return -ENODEV;
+}
+
+static const struct i2c_eeprom_ops i2c_eeprom_std_ops = {
+ .read = i2c_eeprom_std_read,
+ .write = i2c_eeprom_std_write,
+};
+
+static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev)
+{
+ struct at24_chip_data *data;
+ struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+
+ data = (struct at24_chip_data *)dev_get_driver_data(dev);
+ data->dev = dev;
+
+ if (data->flags & AT24_FLAG_ADDR16)
+ chip->offset_len = 2;
+ else
+ chip->offset_len = 1;
+
+ return 0;
+}
+
+static int i2c_eeprom_std_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct udevice_id i2c_eeprom_std_ids[] = {
+ { .compatible = "atmel,24c08", .data = (ulong)&at24_data_24c08 },
+ { .compatible = "atmel,24c16", .data = (ulong)&at24_data_24c16 },
+ { .compatible = "atmel,24c32", .data = (ulong)&at24_data_24c32 },
+ { .compatible = "atmel,24c64", .data = (ulong)&at24_data_24c64 },
+ { /* END OF LIST */ },
+};
+
+U_BOOT_DRIVER(i2c_eeprom_std) = {
+ .name = "i2c_eeprom_at24",
+ .id = UCLASS_I2C_EEPROM,
+ .of_match = i2c_eeprom_std_ids,
+ .probe = i2c_eeprom_std_probe,
+ .ofdata_to_platdata = i2c_eeprom_std_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct i2c_eeprom),
+ .ops = &i2c_eeprom_std_ops,
+};
+
+UCLASS_DRIVER(i2c_eeprom) = {
+ .id = UCLASS_I2C_EEPROM,
+ .name = "i2c_eeprom_at24",
+};
--
2.35.3