381 lines
10 KiB
Diff
Executable File
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(ðaddr[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, ðaddr[MAC_BYTE_SIZE*i]);
|
|
+ env_save();
|
|
+ } else {
|
|
+ printf("eeprom mac%d address invaild:%pM\n", i, \
|
|
+ ðaddr[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
|
|
|