From fa03ee371de84b512e6f941395d4e13040eedd17 Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Tue, 2 Jun 2026 13:57:49 +0200 Subject: sysinfo: uclass: use sysinfo_priv size for per_device_auto Reference the struct itself for the size as it is more robust, even if it contains just a bool at the moment. Signed-off-by: Nora Schiffer Reviewed-by: Simon Glass Signed-off-by: Alexander Feilke --- drivers/sysinfo/sysinfo-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/sysinfo') diff --git a/drivers/sysinfo/sysinfo-uclass.c b/drivers/sysinfo/sysinfo-uclass.c index f04998ef8bb..bf0f664e8dc 100644 --- a/drivers/sysinfo/sysinfo-uclass.c +++ b/drivers/sysinfo/sysinfo-uclass.c @@ -152,5 +152,5 @@ UCLASS_DRIVER(sysinfo) = { .id = UCLASS_SYSINFO, .name = "sysinfo", .post_bind = dm_scan_fdt_dev, - .per_device_auto = sizeof(bool), + .per_device_auto = sizeof(struct sysinfo_priv), }; -- cgit v1.3.1 From 0ef21dd37dc1779293a101413a7ce32bd63870bb Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Tue, 2 Jun 2026 13:57:50 +0200 Subject: sysinfo: add sysinfo_get_and_detect() helper sysinfo_detect() is commonly called after sysinfo_get(). Make the API a bit more convenient to use by introducing a helper. Signed-off-by: Nora Schiffer Signed-off-by: Alexander Feilke Reviewed-by: Simon Glass --- drivers/sysinfo/sysinfo-uclass.c | 10 ++++++++++ include/sysinfo.h | 17 +++++++++++++++++ test/dm/sysinfo.c | 16 ++++++++++++++++ 3 files changed, 43 insertions(+) (limited to 'drivers/sysinfo') diff --git a/drivers/sysinfo/sysinfo-uclass.c b/drivers/sysinfo/sysinfo-uclass.c index bf0f664e8dc..d18a168614e 100644 --- a/drivers/sysinfo/sysinfo-uclass.c +++ b/drivers/sysinfo/sysinfo-uclass.c @@ -42,6 +42,16 @@ int sysinfo_detect(struct udevice *dev) return ret; } +int sysinfo_get_and_detect(struct udevice **devp) +{ + int ret = sysinfo_get(devp); + + if (!ret) + ret = sysinfo_detect(*devp); + + return ret; +} + int sysinfo_get_fit_loadable(struct udevice *dev, int index, const char *type, const char **strp) { diff --git a/include/sysinfo.h b/include/sysinfo.h index 54eb64a204a..7ca396b2ee4 100644 --- a/include/sysinfo.h +++ b/include/sysinfo.h @@ -373,6 +373,18 @@ int sysinfo_get_data_by_index(struct udevice *dev, int id, int index, */ int sysinfo_get(struct udevice **devp); +/** + * sysinfo_get_and_detect() - Get the sysinfo device and detect it. + * + * @devp: Pointer to structure to receive the sysinfo device. + * + * This is a convenience wrapper around sysinfo_get() followed by + * sysinfo_detect() + * + * Return: 0 if OK, -ve on error. + */ +int sysinfo_get_and_detect(struct udevice **devp); + /** * sysinfo_get_fit_loadable - Get the name of an image to load from FIT * This function can be used to provide the image names based on runtime @@ -438,6 +450,11 @@ static inline int sysinfo_get(struct udevice **devp) return -ENOSYS; } +static inline int sysinfo_get_and_detect(struct udevice **devp) +{ + return -ENOSYS; +} + static inline int sysinfo_get_fit_loadable(struct udevice *dev, int index, const char *type, const char **strp) { diff --git a/test/dm/sysinfo.c b/test/dm/sysinfo.c index 14ebe6b42e7..611f2e98d14 100644 --- a/test/dm/sysinfo.c +++ b/test/dm/sysinfo.c @@ -66,3 +66,19 @@ static int dm_test_sysinfo(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_sysinfo, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_sysinfo_get_and_detect(struct unit_test_state *uts) +{ + struct udevice *sysinfo; + bool called_detect = false; + + ut_assertok(sysinfo_get_and_detect(&sysinfo)); + ut_assert(sysinfo); + + ut_assertok(sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT, + &called_detect)); + ut_assert(called_detect); + + return 0; +} +DM_TEST(dm_test_sysinfo_get_and_detect, UTF_SCAN_PDATA | UTF_SCAN_FDT); -- cgit v1.3.1 From a30556bc4249b4154f86c9460da740ff86d30807 Mon Sep 17 00:00:00 2001 From: Nora Schiffer Date: Tue, 2 Jun 2026 13:57:51 +0200 Subject: sysinfo: tq_eeprom: new driver Introduce a sysinfo driver that can be instantiated from the device, which will provide information from the EEPROM found on all TQ-Systems SoMs. Signed-off-by: Nora Schiffer Signed-off-by: Max Merchel Reviewed-by: Simon Glass Signed-off-by: Alexander Feilke --- MAINTAINERS | 1 + configs/tqma7_common.config | 1 + .../sysinfo/tq,eeprom-sysinfo.txt | 36 ++++ drivers/sysinfo/Kconfig | 8 + drivers/sysinfo/Makefile | 1 + drivers/sysinfo/tq_eeprom.c | 203 +++++++++++++++++++++ include/sysinfo/tq_eeprom.h | 24 +++ 7 files changed, 274 insertions(+) create mode 100644 doc/device-tree-bindings/sysinfo/tq,eeprom-sysinfo.txt create mode 100644 drivers/sysinfo/tq_eeprom.c create mode 100644 include/sysinfo/tq_eeprom.h (limited to 'drivers/sysinfo') diff --git a/MAINTAINERS b/MAINTAINERS index a55742a0baf..ec7217f39f4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1865,6 +1865,7 @@ S: Maintained W: https://www.tq-group.com/en/products/tq-embedded/ F: board/tq/* F: doc/board/tq/* +F: drivers/sysinfo/tq_eeprom.c F: include/configs/tq*.h F: include/env/tq/* diff --git a/configs/tqma7_common.config b/configs/tqma7_common.config index 7e5e31a14ab..9b055849ad1 100644 --- a/configs/tqma7_common.config +++ b/configs/tqma7_common.config @@ -77,6 +77,7 @@ CONFIG_I2C_DEFAULT_BUS_NUMBER=0x3 CONFIG_SYS_I2C_MXC=y CONFIG_LED=y CONFIG_LED_GPIO=y +CONFIG_NVMEM=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_FSL_USDHC=y CONFIG_MTD=y diff --git a/doc/device-tree-bindings/sysinfo/tq,eeprom-sysinfo.txt b/doc/device-tree-bindings/sysinfo/tq,eeprom-sysinfo.txt new file mode 100644 index 00000000000..678fff0e812 --- /dev/null +++ b/doc/device-tree-bindings/sysinfo/tq,eeprom-sysinfo.txt @@ -0,0 +1,36 @@ +TQ EEPROM Sysinfo Driver +------------------------ + +This binding describes a sysinfo provider which retrieves system +identification information from an I2C EEPROM device. + +Required properties: + +- compatible: "tq,eeprom-sysinfo" +- nvmem-cells: phandle referencing the nvmem cell +- nvmem-cell-names: string, should be "device_info" + +Example: + +&i2c1 { + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + module_info: module-info@20 { + reg = <0x20 0x60>; + }; + }; + }; +}; + +sysinfo { + compatible = "tq,eeprom-sysinfo"; + nvmem-cells = <&module_info>; + nvmem-cell-names = "device_info"; +}; diff --git a/drivers/sysinfo/Kconfig b/drivers/sysinfo/Kconfig index df83df69ffb..6922dac9170 100644 --- a/drivers/sysinfo/Kconfig +++ b/drivers/sysinfo/Kconfig @@ -59,4 +59,12 @@ config SYSINFO_GPIO This ternary number is then mapped to a board revision name using device tree properties. +config SYSINFO_TQ_EEPROM + bool "Enable TQ-Systems EEPROM sysinfo driver" + depends on I2C_EEPROM + depends on SPL_I2C_EEPROM || !SPL_SYSINFO + help + Support querying EEPROM of TQ-Systems SOMs to determine board + information. + endif diff --git a/drivers/sysinfo/Makefile b/drivers/sysinfo/Makefile index 26ca3150999..d21fb3c2270 100644 --- a/drivers/sysinfo/Makefile +++ b/drivers/sysinfo/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_SYSINFO_IOT2050) += iot2050.o obj-$(CONFIG_SYSINFO_RCAR3) += rcar3.o obj-$(CONFIG_SYSINFO_SANDBOX) += sandbox.o obj-$(CONFIG_SYSINFO_SMBIOS) += smbios.o +obj-$(CONFIG_SYSINFO_TQ_EEPROM) += tq_eeprom.o diff --git a/drivers/sysinfo/tq_eeprom.c b/drivers/sysinfo/tq_eeprom.c new file mode 100644 index 00000000000..63be07b664e --- /dev/null +++ b/drivers/sysinfo/tq_eeprom.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014-2026 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Nora Schiffer + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TQ_EE_RSV1_BYTES 10 +#define TQ_EE_SERIAL_BYTES 8 +#define TQ_EE_RSV2_BYTES 8 +#define TQ_EE_BDID_BYTES 0x40 + +struct tq_eeprom_data { + u8 mac[ETH_ALEN]; /* 0x20 ... 0x25 */ + u8 rsv1[TQ_EE_RSV1_BYTES]; + u8 serial[TQ_EE_SERIAL_BYTES]; /* 0x30 ... 0x37 */ + u8 rsv2[TQ_EE_RSV2_BYTES]; + u8 id[TQ_EE_BDID_BYTES]; /* 0x40 ... 0x7f */ +}; + +static_assert(sizeof(struct tq_eeprom_data) == 0x60, + "struct tq_eeprom_data has incorrect size"); + +/** + * struct sysinfo_tq_eeprom_priv - sysinfo private data + */ +struct sysinfo_tq_eeprom_priv { + struct nvmem_cell device_info_cell; + + /* Reserve extra space for \0 in id and serial */ + char id[TQ_EE_BDID_BYTES + 1]; + char serial[TQ_EE_SERIAL_BYTES + 1]; + u8 mac[ETH_ALEN]; +}; + +static void tq_eeprom_parse_id(struct udevice *dev, const struct tq_eeprom_data *data) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < sizeof(data->id); i++) { + if (!(isprint(data->id[i]) && isascii(data->id[i]))) + break; + } + + if (i == 0) + dev_warn(dev, "no valid model name in EEPROM\n"); + + snprintf(priv->id, sizeof(priv->id), "%.*s", i, data->id); +} + +static int tq_eeprom_serial_len(const struct tq_eeprom_data *data, bool allow_upper) +{ + int i; + + for (i = 0; i < sizeof(data->serial); i++) { + if (!(isdigit(data->serial[i]) || (allow_upper && isupper(data->serial[i])))) + break; + } + + return i; +} + +static void tq_eeprom_parse_serial(struct udevice *dev, const struct tq_eeprom_data *data) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + bool use_new_format; + int len; + + use_new_format = data->serial[0] == 'T' && data->serial[1] == 'Q'; + + len = tq_eeprom_serial_len(data, use_new_format); + + /* For now, only serial numbers with the exact size of the field are accepted */ + if (len != sizeof(data->serial)) { + dev_warn(dev, "no valid serial number in EEPROM\n"); + len = 0; + } + + snprintf(priv->serial, sizeof(priv->serial), "%.*s", len, data->serial); +} + +static int tq_eeprom_dump(const struct sysinfo_tq_eeprom_priv *priv) +{ + printf("TQ EEPROM:\n"); + printf(" ID: %s\n", priv->id[0] ? priv->id : ""); + printf(" SN: %s\n", priv->serial[0] ? priv->serial : ""); + printf(" MAC: "); + if (is_valid_ethaddr(priv->mac)) + printf("%pM\n", priv->mac); + else + printf("\n"); + + return 0; +} + +static int sysinfo_tq_eeprom_detect(struct udevice *dev) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + struct tq_eeprom_data data; + int ret; + + ret = nvmem_cell_read(&priv->device_info_cell, (u8 *)&data, sizeof(data)); + if (ret < 0) { + dev_err(dev, "EEPROM read failed: %d\n", ret); + return ret; + } + + tq_eeprom_parse_id(dev, &data); + tq_eeprom_parse_serial(dev, &data); + memcpy(priv->mac, data.mac, ETH_ALEN); + + if (!IS_ENABLED(CONFIG_SPL_BUILD)) + tq_eeprom_dump(priv); + + return 0; +} + +static int sysinfo_tq_eeprom_get_str(struct udevice *dev, int id, size_t size, char *val) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + + switch (id) { + case SYSID_TQ_MODEL: + if (!priv->id[0]) + return -ENODATA; + + strlcpy(val, priv->id, size); + return 0; + + case SYSID_TQ_SERIAL: + if (!priv->serial[0]) + return -ENODATA; + + strlcpy(val, priv->serial, size); + return 0; + + default: + return -EINVAL; + } +} + +static int sysinfo_tq_eeprom_get_data(struct udevice *dev, int id, void **data, size_t *size) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + + switch (id) { + case SYSID_TQ_MAC_ADDR: + if (!is_valid_ethaddr(priv->mac)) + return -ENODATA; + + *data = priv->mac; + *size = sizeof(priv->mac); + + return 0; + + default: + return -EINVAL; + } +} + +static const struct sysinfo_ops sysinfo_tq_eeprom_ops = { + .detect = sysinfo_tq_eeprom_detect, + .get_str = sysinfo_tq_eeprom_get_str, + .get_data = sysinfo_tq_eeprom_get_data, +}; + +static int sysinfo_tq_eeprom_probe(struct udevice *dev) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + int ret; + + ret = nvmem_cell_get_by_name(dev, "device_info", &priv->device_info_cell); + if (ret) { + dev_err(dev, "device_info not found: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct udevice_id sysinfo_tq_eeprom_ids[] = { + { .compatible = "tq,eeprom-sysinfo" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(sysinfo_tq_eeprom) = { + .name = "sysinfo_tq_eeprom", + .id = UCLASS_SYSINFO, + .of_match = sysinfo_tq_eeprom_ids, + .ops = &sysinfo_tq_eeprom_ops, + .priv_auto = sizeof(struct sysinfo_tq_eeprom_priv), + .probe = sysinfo_tq_eeprom_probe, +}; diff --git a/include/sysinfo/tq_eeprom.h b/include/sysinfo/tq_eeprom.h new file mode 100644 index 00000000000..6b1bddd7ce0 --- /dev/null +++ b/include/sysinfo/tq_eeprom.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023-2026 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Nora Schiffer + */ + +#ifndef __SYSINFO_TQ_EEPROM_H__ +#define __SYSINFO_TQ_EEPROM_H__ + +#include + +enum { + /* Model string of TQ-Systems SOM. This is different from BOARD_MODEL, + * which usually combines SOM and baseboard names for TQ hardware + */ + SYSID_TQ_MODEL = SYSID_USER, + /* SOM serial number */ + SYSID_TQ_SERIAL, + /* MAC address */ + SYSID_TQ_MAC_ADDR, +}; + +#endif /* __SYSINFO_TQ_EEPROM_H__ */ -- cgit v1.3.1