summaryrefslogtreecommitdiffstats
path: root/common/boards
diff options
context:
space:
mode:
Diffstat (limited to 'common/boards')
-rw-r--r--common/boards/Kconfig16
-rw-r--r--common/boards/Makefile5
-rw-r--r--common/boards/phytec/Makefile5
-rw-r--r--common/boards/phytec/phytec-som-detection.c209
-rw-r--r--common/boards/phytec/phytec-som-imx8m-detection.c151
-rw-r--r--common/boards/qemu-virt/Makefile13
-rw-r--r--common/boards/qemu-virt/board.c90
-rw-r--r--common/boards/qemu-virt/fitimage-pubkey.dts7
-rw-r--r--common/boards/qemu-virt/qemu-virt-flash.dtso99
-rw-r--r--common/boards/qemu-virt/qemu-virt-flash.h22
-rw-r--r--common/boards/tq/Makefile1
-rw-r--r--common/boards/tq/tq_eeprom.c139
12 files changed, 757 insertions, 0 deletions
diff --git a/common/boards/Kconfig b/common/boards/Kconfig
new file mode 100644
index 0000000000..f6d4a56f88
--- /dev/null
+++ b/common/boards/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config BOARD_QEMU_VIRT
+ bool
+ select OF_OVERLAY
+
+config BOARD_PHYTEC_SOM_DETECTION
+ bool
+
+config BOARD_PHYTEC_SOM_IMX8M_DETECTION
+ bool
+ select BOARD_PHYTEC_SOM_DETECTION
+
+config BOARD_TQ
+ select CRC_ITU_T
+ bool
diff --git a/common/boards/Makefile b/common/boards/Makefile
new file mode 100644
index 0000000000..147c36643d
--- /dev/null
+++ b/common/boards/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_BOARD_QEMU_VIRT) += qemu-virt/
+obj-$(CONFIG_BOARD_PHYTEC_SOM_DETECTION) += phytec/
+obj-$(CONFIG_BOARD_TQ) += tq/
diff --git a/common/boards/phytec/Makefile b/common/boards/phytec/Makefile
new file mode 100644
index 0000000000..fef6134a16
--- /dev/null
+++ b/common/boards/phytec/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+lwl- += dummy.o
+lwl-$(CONFIG_BOARD_PHYTEC_SOM_DETECTION) += phytec-som-detection.o
+lwl-$(CONFIG_BOARD_PHYTEC_SOM_IMX8M_DETECTION) += phytec-som-imx8m-detection.o
diff --git a/common/boards/phytec/phytec-som-detection.c b/common/boards/phytec/phytec-som-detection.c
new file mode 100644
index 0000000000..e338639d03
--- /dev/null
+++ b/common/boards/phytec/phytec-som-detection.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 PHYTEC Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ */
+
+#include <boards/phytec/phytec-som-imx8m-detection.h>
+#include <common.h>
+#include <pbl/eeprom.h>
+
+struct phytec_eeprom_data eeprom_data;
+
+#define POLY (0x1070U << 3)
+
+static u8 _crc8(u16 data)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (data & 0x8000)
+ data = data ^ POLY;
+ data = data << 1;
+ }
+
+ return data >> 8;
+}
+
+static unsigned int crc8(unsigned int crc, const u8 *vptr, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ crc = _crc8((crc ^ vptr[i]) << 8);
+
+ return crc;
+}
+
+const char *phytec_get_opt(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+
+ if (!data)
+ data = &eeprom_data;
+
+ switch (data->api_rev) {
+ case PHYTEC_API_REV0:
+ case PHYTEC_API_REV1:
+ opt = data->data.data_api0.opt;
+ break;
+ case PHYTEC_API_REV2:
+ opt = data->data.data_api2.opt;
+ break;
+ default:
+ opt = NULL;
+ break;
+ };
+
+ return opt;
+}
+
+static int phytec_eeprom_data_init(struct pbl_i2c *i2c,
+ struct phytec_eeprom_data *data,
+ int addr, u8 phytec_som_type)
+{
+ unsigned int crc;
+ const char *opt;
+ int *ptr;
+ int ret = -1, i;
+ u8 som;
+
+ if (!data)
+ data = &eeprom_data;
+
+ eeprom_read(i2c, addr, I2C_ADDR_16_BIT, data, sizeof(struct phytec_eeprom_data));
+
+ if (data->api_rev == 0xff) {
+ pr_err("%s: EEPROM is not flashed. Prototype?\n", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0, ptr = (int *)data;
+ i < sizeof(struct phytec_eeprom_data);
+ i += sizeof(ptr), 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;
+ }
+
+ if (data->api_rev > PHYTEC_API_REV2) {
+ pr_err("%s: EEPROM API revision %u not supported\n",
+ __func__, data->api_rev);
+ 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));
+ pr_debug("%s: crc: %x\n", __func__, crc);
+
+ if (crc) {
+ pr_err("%s: CRC mismatch. EEPROM data is not usable\n", __func__);
+ return -EINVAL;
+ }
+
+ som = data->data.data_api2.som_no;
+ pr_debug("%s: som id: %u\n", __func__, som);
+ opt = phytec_get_opt(data);
+ if (!opt)
+ return -EINVAL;
+
+ if (IS_ENABLED(CONFIG_BOARD_PHYTEC_SOM_IMX8M_DETECTION))
+ ret = phytec_imx8m_detect(som, opt, phytec_som_type);
+
+ if (ret) {
+ pr_err("%s: SoM ID does not match. Wrong EEPROM data?\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void phytec_print_som_info(const struct phytec_eeprom_data *data)
+{
+ const struct phytec_api2_data *api2;
+ char pcb_sub_rev;
+ unsigned int ksp_no, sub_som_type1 = -1, sub_som_type2 = -1;
+
+ 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) {
+ pr_info("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;
+ pr_info("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;
+ };
+
+ pr_info("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);
+}
+
+int phytec_eeprom_data_setup(struct pbl_i2c *i2c, struct phytec_eeprom_data *data,
+ int addr, int addr_fallback, u8 cpu_type)
+{
+ int ret;
+
+ ret = phytec_eeprom_data_init(i2c, data, addr, cpu_type);
+ if (ret) {
+ pr_err("%s: init failed. Trying fall back address 0x%x\n",
+ __func__, addr_fallback);
+ ret = phytec_eeprom_data_init(i2c, data, addr_fallback, cpu_type);
+ }
+
+ if (ret)
+ pr_err("%s: EEPROM data init failed\n", __func__);
+ else
+ pr_debug("%s: init successful\n", __func__);
+
+ return ret;
+}
diff --git a/common/boards/phytec/phytec-som-imx8m-detection.c b/common/boards/phytec/phytec-som-imx8m-detection.c
new file mode 100644
index 0000000000..495896f5b2
--- /dev/null
+++ b/common/boards/phytec/phytec-som-imx8m-detection.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 PHYTEC Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ */
+
+#include <boards/phytec/phytec-som-imx8m-detection.h>
+#include <common.h>
+#include <mach/imx/generic.h>
+
+extern struct phytec_eeprom_data eeprom_data;
+
+/* Check if the SoM is actually one of the following products:
+ * - i.MX8MM
+ * - i.MX8MN
+ * - i.MX8MP
+ * - i.MX8MQ
+ *
+ * Returns 0 in case it's a known SoM. Otherwise, returns -errno.
+ */
+int phytec_imx8m_detect(u8 som, const char *opt, u8 cpu_type)
+{
+ if (som == PHYTEC_IMX8MP_SOM && cpu_type == IMX_CPU_IMX8MP)
+ return 0;
+
+ if (som == PHYTEC_IMX8MM_SOM) {
+ if (((opt[0] - '0') != 0) &&
+ ((opt[1] - '0') == 0) && cpu_type == IMX_CPU_IMX8MM)
+ return 0;
+ else if (((opt[0] - '0') == 0) &&
+ ((opt[1] - '0') != 0) && cpu_type == IMX_CPU_IMX8MN)
+ return 0;
+ return -EINVAL;
+ }
+
+ if (som == PHYTEC_IMX8MQ_SOM && cpu_type == IMX_CPU_IMX8MQ)
+ return 0;
+
+ return -EINVAL;
+}
+
+/*
+ * So far all PHYTEC i.MX8M boards have RAM size definition at the
+ * same location.
+ */
+enum phytec_imx8m_ddr_size phytec_get_imx8m_ddr_size(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+ u8 ddr_id;
+
+ if (!data)
+ data = &eeprom_data;
+
+ opt = phytec_get_opt(data);
+ if (opt)
+ ddr_id = opt[2] - '0';
+ else
+ ddr_id = PHYTEC_IMX8M_DDR_AUTODETECT;
+
+ pr_debug("%s: ddr id: %u\n", __func__, ddr_id);
+
+ return ddr_id;
+}
+
+/*
+ * Filter SPI-NOR flash information. All i.MX8M boards have this at
+ * the same location.
+ * returns: 0x0 if no SPI is populated. Otherwise a board depended
+ * code for the size. PHYTEC_EEPROM_INVAL when the data is invalid.
+ */
+u8 phytec_get_imx8m_spi(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+ u8 spi;
+
+ if (!data)
+ data = &eeprom_data;
+
+ if (data->api_rev < PHYTEC_API_REV2)
+ return PHYTEC_EEPROM_INVAL;
+
+ opt = phytec_get_opt(data);
+ if (opt)
+ spi = opt[4] - '0';
+ else
+ spi = PHYTEC_EEPROM_INVAL;
+
+ pr_debug("%s: spi: %u\n", __func__, spi);
+
+ return spi;
+}
+
+/*
+ * Filter ethernet phy information. All i.MX8M boards have this at
+ * the same location.
+ * returns: 0x0 if no ethernet phy is poulated. 0x1 if it is populated.
+ * PHYTEC_EEPROM_INVAL when the data is invalid.
+ */
+u8 phytec_get_imx8m_eth(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+ u8 eth;
+
+ if (!data)
+ data = &eeprom_data;
+
+ if (data->api_rev < PHYTEC_API_REV2)
+ return PHYTEC_EEPROM_INVAL;
+
+ opt = phytec_get_opt(data);
+ if (opt) {
+ eth = opt[5] - '0';
+ eth &= 0x1;
+ } else {
+ eth = PHYTEC_EEPROM_INVAL;
+ }
+
+ pr_debug("%s: eth: %u\n", __func__, eth);
+
+ return eth;
+}
+
+/*
+ * Filter RTC information.
+ * returns: 0 if no RTC is poulated. 1 if it is populated.
+ * PHYTEC_EEPROM_INVAL when the data is invalid.
+ */
+u8 phytec_get_imx8mp_rtc(const struct phytec_eeprom_data *data)
+{
+ const char *opt;
+ u8 rtc;
+
+ if (!data)
+ data = &eeprom_data;
+
+ if (data->api_rev < PHYTEC_API_REV2)
+ return PHYTEC_EEPROM_INVAL;
+
+ opt = phytec_get_opt(data);
+ if (opt) {
+ rtc = opt[5] - '0';
+ rtc &= 0x4;
+ rtc = !(rtc >> 2);
+ } else {
+ rtc = PHYTEC_EEPROM_INVAL;
+ }
+
+ pr_debug("%s: rtc: %u\n", __func__, rtc);
+
+ return rtc;
+}
diff --git a/common/boards/qemu-virt/Makefile b/common/boards/qemu-virt/Makefile
new file mode 100644
index 0000000000..30bf4f1955
--- /dev/null
+++ b/common/boards/qemu-virt/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-y += board.o
+obj-y += qemu-virt-flash.dtbo.o fitimage-pubkey.dtb.o
+ifeq ($(CONFIG_RISCV),y)
+DTC_CPP_FLAGS_qemu-virt-flash.dtbo := -DCONFIG_RISCV
+endif
+ifeq ($(CONFIG_ARM),y)
+DTC_CPP_FLAGS_qemu-virt-flash.dtbo := -DCONFIG_ARM
+endif
+
+clean-files := *.dtb *.dtb.S .*.dtc .*.pre .*.dts *.dtb.z
+clean-files += *.dtbo *.dtbo.S .*.dtso
diff --git a/common/boards/qemu-virt/board.c b/common/boards/qemu-virt/board.c
new file mode 100644
index 0000000000..4f2f7374c5
--- /dev/null
+++ b/common/boards/qemu-virt/board.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Pengutronix e.K.
+ *
+ */
+#include <common.h>
+#include <init.h>
+#include <of.h>
+#include <deep-probe.h>
+#include "qemu-virt-flash.h"
+
+#ifdef CONFIG_64BIT
+#define MACHINE "virt64"
+#else
+#define MACHINE "virt"
+#endif
+
+#ifdef CONFIG_ARM
+#include <asm/system_info.h>
+
+static inline void arm_virt_init(void)
+{
+ const char *hostname = MACHINE;
+
+ if (cpu_is_cortex_a7())
+ hostname = "virt-a7";
+ else if (cpu_is_cortex_a15())
+ hostname = "virt-a15";
+
+ barebox_set_model("ARM QEMU " MACHINE);
+ barebox_set_hostname(hostname);
+}
+
+#else
+static inline void arm_virt_init(void) {}
+#endif
+
+extern char __dtbo_qemu_virt_flash_start[];
+extern char __dtb_fitimage_pubkey_start[];
+
+static const struct of_device_id virt_of_match[] = {
+ { .compatible = "linux,dummy-virt", .data = arm_virt_init },
+ { .compatible = "riscv-virtio" },
+ { /* Sentinel */},
+};
+BAREBOX_DEEP_PROBE_ENABLE(virt_of_match);
+
+/*
+ * We don't have a dedicated qemu-virt device tree and instead rely
+ * on what Qemu passes us. To be able to get fundamental changes
+ * in very early, we forego having a board driver here and do this
+ * directly in the initcall.
+ */
+static int virt_board_driver_init(void)
+{
+ struct device_node *root = of_get_root_node();
+ struct device_node *flash, *overlay, *pubkey;
+ const struct of_device_id *id;
+ void (*init)(void);
+
+ id = of_match_node(virt_of_match, root);
+ if (!id)
+ return 0;
+
+ if (id->data) {
+ init = id->data;
+ init();
+ }
+
+ /*
+ * Catch both old Qemu versions that place /flash in /soc and
+ * configurations, where the first flash bank is secure-world only
+ */
+ flash = of_find_node_by_path(PARTS_TARGET_PATH_STR);
+ if (flash && of_device_is_available(flash)) {
+ overlay = of_unflatten_dtb(__dtbo_qemu_virt_flash_start, INT_MAX);
+ of_overlay_apply_tree(root, overlay);
+ }
+
+ pubkey = of_unflatten_dtb(__dtb_fitimage_pubkey_start, INT_MAX);
+ of_merge_nodes(root, pubkey);
+
+ /* fragment may have added aliases to the DT */
+ of_alias_scan();
+
+ /* of_probe() will happen later at of_populate_initcall */
+
+ return 0;
+}
+postcore_initcall(virt_board_driver_init);
diff --git a/common/boards/qemu-virt/fitimage-pubkey.dts b/common/boards/qemu-virt/fitimage-pubkey.dts
new file mode 100644
index 0000000000..497799fa4b
--- /dev/null
+++ b/common/boards/qemu-virt/fitimage-pubkey.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+#ifdef CONFIG_BOOTM_FITIMAGE_PUBKEY
+#include CONFIG_BOOTM_FITIMAGE_PUBKEY
+#endif
+
+/{ };
diff --git a/common/boards/qemu-virt/qemu-virt-flash.dtso b/common/boards/qemu-virt/qemu-virt-flash.dtso
new file mode 100644
index 0000000000..087568a26d
--- /dev/null
+++ b/common/boards/qemu-virt/qemu-virt-flash.dtso
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/dts-v1/;
+/plugin/;
+
+#include "qemu-virt-flash.h"
+
+&{PARTS_TARGET_PATH} {
+#ifdef CONFIG_ARM
+ virtual-reg = <0x1000>;
+#endif
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "initramfs";
+ reg = <0x0 0x3c00000>;
+ };
+
+ environment_flash: partition@3c00000 {
+ label = "barebox-environment";
+ reg = <0x3c00000 0x200000>;
+ };
+
+ backend_state_flash: partition@3e00000 {
+ label = "barebox-state";
+ reg = <0x3e00000 0x200000>;
+ };
+ };
+};
+
+&{/chosen} {
+ environment {
+ compatible = "barebox,environment";
+ device-path = ENV_DEVICE_PATH_STR;
+ };
+};
+
+&{/} {
+ aliases {
+ state = "/state";
+ };
+
+ state {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "barebox,state";
+ magic = <0x290cf8c6>;
+ backend-type = "raw";
+ backend = < &backend_state_flash >;
+ backend-stridesize = <0x200>;
+
+ bootstate {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ system0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@0 {
+ reg = <0x0 0x4>;
+ type = "uint32";
+ default = <3>;
+ };
+
+ priority@4 {
+ reg = <0x4 0x4>;
+ type = "uint32";
+ default = <20>;
+ };
+ };
+
+ system1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ remaining_attempts@8 {
+ reg = <0x8 0x4>;
+ type = "uint32";
+ default = <3>;
+ };
+
+ priority@c {
+ reg = <0xc 0x4>;
+ type = "uint32";
+ default = <21>;
+ };
+ };
+
+ last_chosen@10 {
+ reg = <0x10 0x4>;
+ type = "uint32";
+ };
+ };
+ };
+};
diff --git a/common/boards/qemu-virt/qemu-virt-flash.h b/common/boards/qemu-virt/qemu-virt-flash.h
new file mode 100644
index 0000000000..85f67ff030
--- /dev/null
+++ b/common/boards/qemu-virt/qemu-virt-flash.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __QEMU_VIRT_FLASH_H__
+#define __QEMU_VIRT_FLASH_H__
+
+#include <linux/stringify.h>
+
+#ifdef CONFIG_RISCV
+#define PARTS_TARGET_PATH /flash@20000000
+#define ENV_DEVICE_PATH /flash@20000000/partitions/partition@3c00000
+#elif defined CONFIG_ARM
+#define PARTS_TARGET_PATH /flash@0
+#define ENV_DEVICE_PATH /flash@0/partitions/partition@3c00000
+#else
+#define PARTS_TARGET_PATH
+#define ENV_DEVICE_PATH
+#endif
+
+#define PARTS_TARGET_PATH_STR __stringify(PARTS_TARGET_PATH)
+#define ENV_DEVICE_PATH_STR __stringify(ENV_DEVICE_PATH)
+
+#endif
diff --git a/common/boards/tq/Makefile b/common/boards/tq/Makefile
new file mode 100644
index 0000000000..9950cbdb00
--- /dev/null
+++ b/common/boards/tq/Makefile
@@ -0,0 +1 @@
+obj-pbl-y += tq_eeprom.o
diff --git a/common/boards/tq/tq_eeprom.c b/common/boards/tq/tq_eeprom.c
new file mode 100644
index 0000000000..fe776d6bab
--- /dev/null
+++ b/common/boards/tq/tq_eeprom.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2014-2023 TQ-Systems GmbH <u-boot@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Markus Niebel
+ */
+
+#include <common.h>
+#include <net.h>
+#include <linux/ctype.h>
+#include <crc.h>
+#include <pbl/i2c.h>
+#include <pbl/eeprom.h>
+#include <boards/tq/tq_eeprom.h>
+
+/*
+ * static EEPROM layout
+ */
+#define TQ_EE_HRCW_BYTES 0x20
+#define TQ_EE_RSV1_BYTES 10
+#define TQ_EE_RSV2_BYTES 8
+
+struct __packed tq_eeprom_data {
+ union {
+ struct tq_vard vard;
+ _Static_assert(sizeof(struct tq_vard) == TQ_EE_HRCW_BYTES, \
+ "struct tq_vard has incorrect size");
+ u8 hrcw_primary[TQ_EE_HRCW_BYTES];
+ } tq_hw_data;
+ u8 mac[TQ_EE_MAC_BYTES]; /* 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 bool tq_vard_valid(const struct tq_vard *vard)
+{
+ const unsigned char *start = (const unsigned char *)(vard) +
+ sizeof(vard->crc);
+ u16 crc;
+
+ crc = crc_itu_t(0, start, sizeof(*vard) - sizeof(vard->crc));
+
+ return vard->crc == crc;
+}
+
+phys_size_t tq_vard_memsize(u8 val, unsigned int multiply, unsigned int tmask)
+{
+ phys_size_t result = 0;
+
+ if (val != VARD_MEMSIZE_DEFAULT) {
+ result = 1 << (size_t)(val & VARD_MEMSIZE_MASK_EXP);
+ if (val & tmask)
+ result *= 3;
+ result *= multiply;
+ }
+
+ return result;
+}
+
+void tq_vard_show(const struct tq_vard *vard)
+{
+ /* display data anyway to support developer */
+ printf("HW\tREV.%02uxx\n", (unsigned int)vard->hwrev);
+ printf("RAM\ttype %u, %lu MiB, %s\n",
+ (unsigned int)(vard->memtype & VARD_MEMTYPE_MASK_TYPE),
+ (unsigned long)(tq_vard_ramsize(vard) / (SZ_1M)),
+ (tq_vard_has_ramecc(vard) ? "ECC" : "no ECC"));
+ printf("RTC\t%c\nSPINOR\t%c\ne-MMC\t%c\nSE\t%c\nEEPROM\t%c\n",
+ (tq_vard_has_rtc(vard) ? 'y' : 'n'),
+ (tq_vard_has_spinor(vard) ? 'y' : 'n'),
+ (tq_vard_has_emmc(vard) ? 'y' : 'n'),
+ (tq_vard_has_secelem(vard) ? 'y' : 'n'),
+ (tq_vard_has_eeprom(vard) ? 'y' : 'n'));
+
+ if (tq_vard_has_eeprom(vard))
+ printf("EEPROM\ttype %u, %lu KiB, page %zu\n",
+ (unsigned int)(vard->eepromtype & VARD_EETYPE_MASK_MFR) >> 4,
+ (unsigned long)(tq_vard_eepromsize(vard) / (SZ_1K)),
+ tq_vard_eeprom_pgsize(vard));
+
+ printf("FORMFACTOR: ");
+
+ switch (tq_vard_get_formfactor(vard)) {
+ case VARD_FORMFACTOR_TYPE_LGA:
+ printf("LGA\n");
+ break;
+ case VARD_FORMFACTOR_TYPE_CONNECTOR:
+ printf("CONNECTOR\n");
+ break;
+ case VARD_FORMFACTOR_TYPE_SMARC2:
+ printf("SMARC-2\n");
+ break;
+ case VARD_FORMFACTOR_TYPE_NONE:
+ /*
+ * applies to boards with no variants or older boards
+ * where this field is not written
+ */
+ printf("UNSPECIFIED\n");
+ break;
+ default:
+ /*
+ * generic fall trough
+ * unhandled form factor or invalid data
+ */
+ printf("UNKNOWN\n");
+ break;
+ }
+}
+
+static void tq_read_string(const char *src, char *dst, int len)
+{
+ int i;
+
+ for (i = 0; i < len && isprint(src[i]) && isascii(src[i]); ++i)
+ dst[i] = src[i];
+ dst[i] = '\0';
+}
+
+struct tq_eeprom *pbl_tq_read_eeprom(struct pbl_i2c *i2c, u8 addr, u32 eeprom_addr)
+{
+ struct tq_eeprom_data raw;
+ static struct tq_eeprom eeprom;
+ int ret;
+
+ ret = eeprom_read(i2c, addr, eeprom_addr, &raw, sizeof(raw));
+ if (ret)
+ return NULL;
+
+ if (tq_vard_valid(&raw.tq_hw_data.vard))
+ eeprom.vard = raw.tq_hw_data.vard;
+
+ memcpy(eeprom.mac, raw.mac, TQ_EE_MAC_BYTES);
+ tq_read_string(raw.serial, eeprom.serial, TQ_EE_SERIAL_BYTES);
+ tq_read_string(raw.id, eeprom.id, TQ_EE_BDID_BYTES);
+
+ return &eeprom;
+}