[PATCH v2 1/6] board: phytec: Add common PHYTEC SoM detection
Yannic Moog
Y.Moog at phytec.de
Mon Aug 28 14:32:05 CEST 2023
On Thu, 2023-08-17 at 10:57 +0200, Teresa Remmet wrote:
> Recent shipped PHYTEC SoMs come with an i2c EEPROM containing
> information about the hardware such as board revision and variant.
> This can be used for RAM detection and loading device tree overlays
> during kernel start.
>
> Signed-off-by: Teresa Remmet <t.remmet at phytec.de>
Reviewed-by: Yannic Moog <y.moog at phytec.de>
Tested-by: Yannic Moog <y.moog at phytec.de>
> ---
> Changes in v2:
> - none
> ---
> board/phytec/common/Kconfig | 5 +
> board/phytec/common/Makefile | 10 ++
> board/phytec/common/phytec_som_detection.c | 188
> +++++++++++++++++++++
> board/phytec/common/phytec_som_detection.h | 104 ++++++++++++
> 4 files changed, 307 insertions(+)
> create mode 100644 board/phytec/common/Kconfig
> create mode 100644 board/phytec/common/Makefile
> create mode 100644 board/phytec/common/phytec_som_detection.c
> create mode 100644 board/phytec/common/phytec_som_detection.h
>
> diff --git a/board/phytec/common/Kconfig b/board/phytec/common/Kconfig
> new file mode 100644
> index 000000000000..d614d45b1d60
> --- /dev/null
> +++ b/board/phytec/common/Kconfig
> @@ -0,0 +1,5 @@
> +config PHYTEC_SOM_DETECTION
> + bool "Support SoM detection for PHYTEC platforms"
> + select SPL_CRC8 if SPL
> + help
> + Support of I2C EEPROM based SoM detection.
> diff --git a/board/phytec/common/Makefile
> b/board/phytec/common/Makefile
> new file mode 100644
> index 000000000000..5fe8725ef684
> --- /dev/null
> +++ b/board/phytec/common/Makefile
> @@ -0,0 +1,10 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +# Copyright (C) 2023 PHYTEC Messtechnik GmbH
> +# Author: Teresa Remmet <t.remmet at phytec.de>
> +
> +ifdef CONFIG_SPL_BUILD
> +# necessary to create built-in.o
> +obj- := __dummy__.o
> +endif
> +
> +obj-$(CONFIG_PHYTEC_SOM_DETECTION) += phytec_som_detection.o
> diff --git a/board/phytec/common/phytec_som_detection.c
> b/board/phytec/common/phytec_som_detection.c
> new file mode 100644
> index 000000000000..366bdd4ace4b
> --- /dev/null
> +++ b/board/phytec/common/phytec_som_detection.c
> @@ -0,0 +1,188 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2023 PHYTEC Messtechnik GmbH
> + * Author: Teresa Remmet <t.remmet at phytec.de>
> + */
> +
> +#include <common.h>
> +#include <asm/mach-imx/mxc_i2c.h>
> +#include <asm/arch/sys_proto.h>
> +#include <dm/device.h>
> +#include <dm/uclass.h>
> +#include <i2c.h>
> +#include <u-boot/crc.h>
> +
> +#include "phytec_som_detection.h"
> +
> +struct phytec_eeprom_data eeprom_data;
> +
> +int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data
> *data,
> + int bus_num, int addr, int
> addr_fallback)
> +{
> + int ret;
> +
> + ret = phytec_eeprom_data_init(data, bus_num, addr);
> + if (ret) {
> + pr_err("%s: init failed. Trying fall back address
> 0x%x\n",
> + __func__, addr_fallback);
> + ret = phytec_eeprom_data_init(data, bus_num,
> addr_fallback);
> + }
> +
> + if (ret)
> + pr_err("%s: EEPROM data init failed\n", __func__);
> +
> + return ret;
> +}
> +
> +int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
> + int bus_num, int addr)
> +{
> + int ret;
> +
> + ret = phytec_eeprom_data_init(data, bus_num, addr);
> + if (ret)
> + pr_err("%s: EEPROM data init failed\n", __func__);
> +
> + return ret;
> +}
> +
> +int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
> + int bus_num, int addr)
> +{
> + int ret, i;
> + unsigned int crc;
> + int *ptr;
> +
> + if (!data)
> + data = &eeprom_data;
> +
> +#if CONFIG_IS_ENABLED(DM_I2C)
> + struct udevice *dev;
> +
> + ret = i2c_get_chip_for_busnum(bus_num, addr, 2, &dev);
> + if (ret) {
> + pr_err("%s: i2c EEPROM not found: %i.\n", __func__,
> ret);
> + return ret;
> + }
> +
> + ret = dm_i2c_read(dev, 0, (uint8_t *)data,
> + sizeof(struct phytec_eeprom_data));
> + if (ret) {
> + pr_err("%s: Unable to read EEPROM data\n", __func__);
> + return ret;
> + }
> +#else
> + i2c_set_bus_num(bus_num);
> + ret = i2c_read(addr, 0, 2, (uint8_t *)data,
> + sizeof(struct phytec_eeprom_data));
> +#endif
> +
> + if (data->api_rev == 0xff) {
> + pr_err("%s: EEPROM is not flashed. Prototype?\n",
> __func__);
> + return -EINVAL;
> + }
> +
> + ptr = (int *)data;
> + for (i = 0; i < sizeof(struct phytec_eeprom_data); i +=
> sizeof(ptr))
> + if (*ptr != 0x0)
> + break;
> +
> + if (i == sizeof(struct phytec_eeprom_data)) {
> + pr_err("%s: EEPROM data is all zero. Erased?\n",
> __func__);
> + return -EINVAL;
> + }
> +
> + /* We are done here for early revisions */
> + if (data->api_rev <= PHYTEC_API_REV1)
> + return 0;
> +
> + crc = crc8(0, (const unsigned char *)data,
> + sizeof(struct phytec_eeprom_data));
> + debug("%s: crc: %x\n", __func__, crc);
> +
> + if (crc) {
> + pr_err("%s: CRC mismatch. EEPROM data is not
> usable\n",
> + __func__);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data
> *data)
> +{
> + struct phytec_api2_data *api2;
> + char pcb_sub_rev;
> + unsigned int ksp_no, sub_som_type1, sub_som_type2;
> +
> + if (!data)
> + data = &eeprom_data;
> +
> + if (data->api_rev < PHYTEC_API_REV2)
> + return;
> +
> + api2 = &data->data.data_api2;
> +
> + /* Calculate PCB subrevision */
> + pcb_sub_rev = api2->pcb_sub_opt_rev & 0x0f;
> + pcb_sub_rev = pcb_sub_rev ? ((pcb_sub_rev - 1) + 'a') : ' ';
> +
> + /* print standard product string */
> + if (api2->som_type <= 1) {
> + printf("SoM: %s-%03u-%s.%s PCB rev: %u%c\n",
> + phytec_som_type_str[api2->som_type], api2-
> >som_no,
> + api2->opt, api2->bom_rev, api2->pcb_rev,
> pcb_sub_rev);
> + return;
> + }
> + /* print KSP/KSM string */
> + if (api2->som_type <= 3) {
> + ksp_no = (api2->ksp_no << 8) | api2->som_no;
> + printf("SoM: %s-%u ",
> + phytec_som_type_str[api2->som_type], ksp_no);
> + /* print standard product based KSP/KSM strings */
> + } else {
> + switch (api2->som_type) {
> + case 4:
> + sub_som_type1 = 0;
> + sub_som_type2 = 3;
> + break;
> + case 5:
> + sub_som_type1 = 0;
> + sub_som_type2 = 2;
> + break;
> + case 6:
> + sub_som_type1 = 1;
> + sub_som_type2 = 3;
> + break;
> + case 7:
> + sub_som_type1 = 1;
> + sub_som_type2 = 2;
> + break;
> + default:
> + break;
> + };
> +
> + printf("SoM: %s-%03u-%s-%03u ",
> + phytec_som_type_str[sub_som_type1],
> + api2->som_no,
> phytec_som_type_str[sub_som_type2],
> + api2->ksp_no);
> + }
> +
> + printf("Option: %s BOM rev: %s PCB rev: %u%c\n", api2->opt,
> + api2->bom_rev, api2->pcb_rev, pcb_sub_rev);
> +}
> +
> +char * __maybe_unused phytec_get_opt(struct phytec_eeprom_data *data)
> +{
> + char *opt;
> +
> + if (!data)
> + data = &eeprom_data;
> +
> + if (data->api_rev < PHYTEC_API_REV2)
> + opt = data->data.data_api0.opt;
> + else
> + opt = data->data.data_api2.opt;
> +
> + return opt;
> +}
> diff --git a/board/phytec/common/phytec_som_detection.h
> b/board/phytec/common/phytec_som_detection.h
> new file mode 100644
> index 000000000000..01f7e4652ddb
> --- /dev/null
> +++ b/board/phytec/common/phytec_som_detection.h
> @@ -0,0 +1,104 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2023 PHYTEC Messtechnik GmbH
> + * Author: Teresa Remmet <t.remmet at phytec.de>
> + */
> +
> +#ifndef _PHYTEC_SOM_DETECTION_H
> +#define _PHYTEC_SOM_DETECTION_H
> +
> +#define PHYTEC_MAX_OPTIONS 17
> +#define PHYTEC_EEPROM_INVAL 0xff
> +
> +#define PHYTEC_GET_OPTION(option) \
> + (((option) > '9') ? (option) - 'A' + 10 : (option) - '0')
> +
> +enum {
> + PHYTEC_API_REV0 = 0,
> + PHYTEC_API_REV1,
> + PHYTEC_API_REV2,
> +};
> +
> +static const char * const phytec_som_type_str[] = {
> + "PCM",
> + "PCL",
> + "KSM",
> + "KSP",
> +};
> +
> +struct phytec_api0_data {
> + u8 pcb_rev; /* PCB revision of SoM */
> + u8 som_type; /* SoM type */
> + u8 ksp_no; /* KSP no */
> + char opt[16]; /* SoM options */
> + u8 mac[6]; /* MAC address (optional) */
> + u8 pad[5]; /* padding */
> + u8 cksum; /* checksum */
> +} __packed;
> +
> +struct phytec_api2_data {
> + u8 pcb_rev; /* PCB revision of SoM */
> + u8 pcb_sub_opt_rev; /* PCB subrevision and opt revision */
> + u8 som_type; /* SoM type */
> + u8 som_no; /* SoM number */
> + u8 ksp_no; /* KSP information */
> + char opt[PHYTEC_MAX_OPTIONS]; /* SoM options */
> + char bom_rev[2]; /* BOM revision */
> + u8 mac[6]; /* MAC address (optional) */
> + u8 crc8; /* checksum */
> +} __packed;
> +
> +struct phytec_eeprom_data {
> + u8 api_rev;
> + union {
> + struct phytec_api0_data data_api0;
> + struct phytec_api2_data data_api2;
> + } data;
> +} __packed;
> +
> +#if IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION)
> +
> +int phytec_eeprom_data_setup_fallback(struct phytec_eeprom_data
> *data,
> + int bus_num, int addr,
> + int addr_fallback);
> +int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
> + int bus_num, int addr);
> +int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
> + int bus_num, int addr);
> +void __maybe_unused phytec_print_som_info(struct phytec_eeprom_data
> *data);
> +
> +char * __maybe_unused phytec_get_opt(struct phytec_eeprom_data
> *data);
> +
> +#else
> +
> +inline int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
> + int bus_num, int addr)
> +{
> + return PHYTEC_EEPROM_INVAL;
> +}
> +
> +inline int phytec_eeprom_data_setup_fallback(struct
> phytec_eeprom_data *data,
> + int bus_num, int addr,
> + int addr_fallback)
> +{
> + return PHYTEC_EEPROM_INVAL;
> +}
> +
> +inline int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
> + int bus_num, int addr)
> +{
> + return PHYTEC_EEPROM_INVAL;
> +}
> +
> +inline void __maybe_unused phytec_print_som_info(struct
> phytec_eeprom_data *data)
> +{
> +}
> +
> +inline char *__maybe_unused phytec_get_opt(struct phytec_eeprom_data
> *data)
> +{
> + return NULL;
> +}
> +
> +#endif /* IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION) */
> +
> +#endif /* _PHYTEC_SOM_DETECTION_H */
More information about the U-Boot
mailing list