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 <nora.schiffer@ew.tq-group.com> Signed-off-by: Max Merchel <Max.Merchel@ew.tq-group.com> Reviewed-by: Simon Glass <sjg@chromium.org> Signed-off-by: Alexander Feilke <alexander.feilke@ew.tq-group.com>
This commit is contained in:
committed by
Fabio Estevam
parent
0ef21dd37d
commit
a30556bc42
@@ -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/*
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2014-2026 TQ-Systems GmbH <u-boot@ew.tq-group.com>,
|
||||
* D-82229 Seefeld, Germany.
|
||||
* Author: Nora Schiffer
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
#include <net.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <nvmem.h>
|
||||
#include <sysinfo/tq_eeprom.h>
|
||||
|
||||
#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 : "<invalid>");
|
||||
printf(" SN: %s\n", priv->serial[0] ? priv->serial : "<invalid>");
|
||||
printf(" MAC: ");
|
||||
if (is_valid_ethaddr(priv->mac))
|
||||
printf("%pM\n", priv->mac);
|
||||
else
|
||||
printf("<invalid>\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,
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2023-2026 TQ-Systems GmbH <u-boot@ew.tq-group.com>,
|
||||
* D-82229 Seefeld, Germany.
|
||||
* Author: Nora Schiffer
|
||||
*/
|
||||
|
||||
#ifndef __SYSINFO_TQ_EEPROM_H__
|
||||
#define __SYSINFO_TQ_EEPROM_H__
|
||||
|
||||
#include <sysinfo.h>
|
||||
|
||||
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__ */
|
||||
Reference in New Issue
Block a user