summaryrefslogtreecommitdiff
path: root/board/phytec/common
diff options
context:
space:
mode:
Diffstat (limited to 'board/phytec/common')
-rw-r--r--board/phytec/common/Kconfig11
-rw-r--r--board/phytec/common/Makefile4
-rw-r--r--board/phytec/common/am6_som_detection.c18
-rw-r--r--board/phytec/common/am6_som_detection.h8
-rw-r--r--board/phytec/common/imx8m_som_detection.c1
-rw-r--r--board/phytec/common/k3/Makefile3
-rw-r--r--board/phytec/common/k3/board.c106
-rw-r--r--board/phytec/common/k3/k3_ddrss_patch.c68
-rw-r--r--board/phytec/common/k3/k3_ddrss_patch.h28
-rw-r--r--board/phytec/common/phytec_som_detection.c229
-rw-r--r--board/phytec/common/phytec_som_detection.h9
-rw-r--r--board/phytec/common/phytec_som_detection_blocks.c105
-rw-r--r--board/phytec/common/phytec_som_detection_blocks.h61
13 files changed, 609 insertions, 42 deletions
diff --git a/board/phytec/common/Kconfig b/board/phytec/common/Kconfig
index 1077f0f4b61..f394ace786a 100644
--- a/board/phytec/common/Kconfig
+++ b/board/phytec/common/Kconfig
@@ -4,6 +4,13 @@ config PHYTEC_SOM_DETECTION
help
Support of I2C EEPROM based SoM detection.
+config PHYTEC_SOM_DETECTION_BLOCKS
+ bool "Extend SoM detection with block support"
+ depends on PHYTEC_SOM_DETECTION
+ help
+ Extend the I2C EEPROM based SoM detection with API v3. This API
+ introduces blocks with different payloads.
+
config PHYTEC_IMX8M_SOM_DETECTION
bool "Support SoM detection for i.MX8M PHYTEC platforms"
depends on ARCH_IMX8M && PHYTEC_SOM_DETECTION
@@ -16,6 +23,8 @@ config PHYTEC_AM62_SOM_DETECTION
bool "Support SoM detection for AM62x PHYTEC platforms"
depends on (TARGET_PHYCORE_AM62X_A53 || TARGET_PHYCORE_AM62X_R5) && \
PHYTEC_SOM_DETECTION
+ select PHYTEC_SOM_DETECTION_BLOCKS
+ depends on SPL_I2C && DM_I2C
default y
help
Support of I2C EEPROM based SoM detection. Supported
@@ -25,6 +34,8 @@ config PHYTEC_AM64_SOM_DETECTION
bool "Support SoM detection for AM64x PHYTEC platforms"
depends on (TARGET_PHYCORE_AM64X_A53 || TARGET_PHYCORE_AM64X_R5) && \
PHYTEC_SOM_DETECTION
+ select PHYTEC_SOM_DETECTION_BLOCKS
+ depends on SPL_I2C && DM_I2C
default y
help
Support of I2C EEPROM based SoM detection. Supported
diff --git a/board/phytec/common/Makefile b/board/phytec/common/Makefile
index 3feb00fd1ec..04469d0a924 100644
--- a/board/phytec/common/Makefile
+++ b/board/phytec/common/Makefile
@@ -7,6 +7,6 @@ ifdef CONFIG_SPL_BUILD
obj- := __dummy__.o
endif
-obj-y += phytec_som_detection.o
-obj-$(CONFIG_ARCH_K3) += am6_som_detection.o
+obj-y += phytec_som_detection.o phytec_som_detection_blocks.o
+obj-$(CONFIG_ARCH_K3) += am6_som_detection.o k3/
obj-$(CONFIG_ARCH_IMX8M) += imx8m_som_detection.o
diff --git a/board/phytec/common/am6_som_detection.c b/board/phytec/common/am6_som_detection.c
index 2e9884dab44..7930ab42d1c 100644
--- a/board/phytec/common/am6_som_detection.c
+++ b/board/phytec/common/am6_som_detection.c
@@ -73,7 +73,7 @@ static u8 phytec_check_opt(struct phytec_eeprom_data *data, u8 option)
* - The size
* - PHYTEC_EEPROM_INVAL when the data is invalid.
*/
-u8 __maybe_unused phytec_get_am62_ddr_size(struct phytec_eeprom_data *data)
+u8 __maybe_unused phytec_get_am6_ddr_size(struct phytec_eeprom_data *data)
{
u8 ddr_id = phytec_check_opt(data, 3);
@@ -89,7 +89,7 @@ u8 __maybe_unused phytec_get_am62_ddr_size(struct phytec_eeprom_data *data)
* - Otherwise a board depended code for the size.
* - PHYTEC_EEPROM_INVAL when the data is invalid.
*/
-u8 __maybe_unused phytec_get_am62_spi(struct phytec_eeprom_data *data)
+u8 __maybe_unused phytec_get_am6_spi(struct phytec_eeprom_data *data)
{
u8 spi = phytec_check_opt(data, 5);
@@ -105,7 +105,7 @@ u8 __maybe_unused phytec_get_am62_spi(struct phytec_eeprom_data *data)
* - 0x1 if 10/100/1000 MBit Phy is populated.
* - PHYTEC_EEPROM_INVAL when the data is invalid.
*/
-u8 __maybe_unused phytec_get_am62_eth(struct phytec_eeprom_data *data)
+u8 __maybe_unused phytec_get_am6_eth(struct phytec_eeprom_data *data)
{
u8 eth = phytec_check_opt(data, 6);
@@ -121,7 +121,7 @@ u8 __maybe_unused phytec_get_am62_eth(struct phytec_eeprom_data *data)
* - 1 if it is populated.
* - PHYTEC_EEPROM_INVAL when the data is invalid.
*/
-u8 __maybe_unused phytec_get_am62_rtc(struct phytec_eeprom_data *data)
+u8 __maybe_unused phytec_get_am6_rtc(struct phytec_eeprom_data *data)
{
u8 rtc = phytec_check_opt(data, 7);
@@ -131,28 +131,28 @@ u8 __maybe_unused phytec_get_am62_rtc(struct phytec_eeprom_data *data)
#else
-inline int __maybe_unused phytec_am62_detect(struct phytec_eeprom_data *data)
+inline int __maybe_unused phytec_am6_detect(struct phytec_eeprom_data *data)
{
return -1;
}
inline u8 __maybe_unused
-phytec_get_am62_ddr_size(struct phytec_eeprom_data *data)
+phytec_get_am6_ddr_size(struct phytec_eeprom_data *data)
{
return PHYTEC_EEPROM_INVAL;
}
-inline u8 __maybe_unused phytec_get_am62_spi(struct phytec_eeprom_data *data)
+inline u8 __maybe_unused phytec_get_am6_spi(struct phytec_eeprom_data *data)
{
return PHYTEC_EEPROM_INVAL;
}
-inline u8 __maybe_unused phytec_get_am62_eth(struct phytec_eeprom_data *data)
+inline u8 __maybe_unused phytec_get_am6_eth(struct phytec_eeprom_data *data)
{
return PHYTEC_EEPROM_INVAL;
}
-inline u8 __maybe_unused phytec_get_am62_rtc(struct phytec_eeprom_data *data)
+inline u8 __maybe_unused phytec_get_am6_rtc(struct phytec_eeprom_data *data)
{
return PHYTEC_EEPROM_INVAL;
}
diff --git a/board/phytec/common/am6_som_detection.h b/board/phytec/common/am6_som_detection.h
index 032f9da3aab..c5c6e179da6 100644
--- a/board/phytec/common/am6_som_detection.h
+++ b/board/phytec/common/am6_som_detection.h
@@ -9,11 +9,19 @@
#include "phytec_som_detection.h"
+#define EEPROM_ADDR 0x50
#define PHYTEC_AM62X_SOM 71
#define PHYTEC_AM64X_SOM 72
#define PHYTEC_EEPROM_VALUE_X 0x21
#define PHYTEC_EEPROM_NOR_FLASH_64MB_QSPI 0xC
+enum {
+ EEPROM_RAM_SIZE_512MB = 0,
+ EEPROM_RAM_SIZE_1GB = 1,
+ EEPROM_RAM_SIZE_2GB = 2,
+ EEPROM_RAM_SIZE_4GB = 4
+};
+
int __maybe_unused phytec_am6_detect(struct phytec_eeprom_data *data);
u8 __maybe_unused phytec_get_am6_ddr_size(struct phytec_eeprom_data *data);
u8 __maybe_unused phytec_get_am6_spi(struct phytec_eeprom_data *data);
diff --git a/board/phytec/common/imx8m_som_detection.c b/board/phytec/common/imx8m_som_detection.c
index ee34a5b9579..bfd60ffb777 100644
--- a/board/phytec/common/imx8m_som_detection.c
+++ b/board/phytec/common/imx8m_som_detection.c
@@ -4,7 +4,6 @@
* Author: Teresa Remmet <t.remmet@phytec.de>
*/
-#include <common.h>
#include <asm/arch/sys_proto.h>
#include <dm/device.h>
#include <dm/uclass.h>
diff --git a/board/phytec/common/k3/Makefile b/board/phytec/common/k3/Makefile
new file mode 100644
index 00000000000..40e91a43e99
--- /dev/null
+++ b/board/phytec/common/k3/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+obj-y += board.o
+obj-$(CONFIG_K3_DDRSS) += k3_ddrss_patch.o
diff --git a/board/phytec/common/k3/board.c b/board/phytec/common/k3/board.c
new file mode 100644
index 00000000000..3d7e090ccaa
--- /dev/null
+++ b/board/phytec/common/k3/board.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 PHYTEC Messtechnik GmbH
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ */
+
+#include <env_internal.h>
+#include <fdt_support.h>
+#include <spl.h>
+#include <asm/arch/hardware.h>
+
+#include "../am6_som_detection.h"
+
+#if IS_ENABLED(CONFIG_ENV_IS_IN_FAT) || IS_ENABLED(CONFIG_ENV_IS_IN_MMC)
+int mmc_get_env_dev(void)
+{
+ u32 boot_device = get_boot_device();
+
+ switch (boot_device) {
+ case BOOT_DEVICE_MMC1:
+ return 0;
+ case BOOT_DEVICE_MMC2:
+ return 1;
+ };
+
+ return CONFIG_SYS_MMC_ENV_DEV;
+}
+#endif
+
+enum env_location env_get_location(enum env_operation op, int prio)
+{
+ u32 boot_device = get_boot_device();
+
+ if (prio)
+ return ENVL_UNKNOWN;
+
+ switch (boot_device) {
+ case BOOT_DEVICE_MMC1:
+ case BOOT_DEVICE_MMC2:
+ if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
+ return ENVL_FAT;
+ if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
+ return ENVL_MMC;
+ case BOOT_DEVICE_SPI:
+ if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
+ return ENVL_SPI_FLASH;
+ default:
+ return ENVL_NOWHERE;
+ };
+}
+
+#if IS_ENABLED(CONFIG_BOARD_LATE_INIT)
+int board_late_init(void)
+{
+ u32 boot_device = get_boot_device();
+
+ switch (boot_device) {
+ case BOOT_DEVICE_MMC1:
+ env_set_ulong("mmcdev", 0);
+ env_set("boot", "mmc");
+ break;
+ case BOOT_DEVICE_MMC2:
+ env_set_ulong("mmcdev", 1);
+ env_set("boot", "mmc");
+ break;
+ case BOOT_DEVICE_SPI:
+ env_set("boot", "spi");
+ break;
+ case BOOT_DEVICE_ETHERNET:
+ env_set("boot", "net");
+ break;
+ };
+
+ if (IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION_BLOCKS)) {
+ struct phytec_api3_element *block_element;
+ struct phytec_eeprom_data data;
+ int ret;
+
+ ret = phytec_eeprom_data_setup(&data, 0, EEPROM_ADDR);
+ if (ret || !data.valid)
+ return 0;
+
+ PHYTEC_API3_FOREACH_BLOCK(block_element, &data) {
+ switch (block_element->block_type) {
+ case PHYTEC_API3_BLOCK_MAC:
+ phytec_blocks_add_mac_to_env(block_element);
+ break;
+ default:
+ debug("%s: Unknown block type %i\n", __func__,
+ block_element->block_type);
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_OF_LIBFDT) && IS_ENABLED(CONFIG_OF_BOARD_SETUP)
+int ft_board_setup(void *blob, struct bd_info *bd)
+{
+ fdt_copy_fixed_partitions(blob);
+
+ return 0;
+}
+#endif
diff --git a/board/phytec/common/k3/k3_ddrss_patch.c b/board/phytec/common/k3/k3_ddrss_patch.c
new file mode 100644
index 00000000000..39f7be8dc92
--- /dev/null
+++ b/board/phytec/common/k3/k3_ddrss_patch.c
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2024 PHYTEC Messtechnik GmbH
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ */
+
+#include "k3_ddrss_patch.h"
+
+#include <fdt_support.h>
+#include <linux/errno.h>
+
+#ifdef CONFIG_K3_AM64_DDRSS
+#define LPDDR4_INTR_CTL_REG_COUNT (423U)
+#define LPDDR4_INTR_PHY_INDEP_REG_COUNT (345U)
+#endif
+
+static int fdt_setprop_inplace_idx_u32(void *fdt, int nodeoffset,
+ const char *name, uint32_t idx, u32 val)
+{
+ val = cpu_to_be32(val);
+ return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
+ strlen(name),
+ idx * sizeof(val), &val,
+ sizeof(val));
+}
+
+int fdt_apply_ddrss_timings_patch(void *fdt, struct ddrss *ddrss)
+{
+ int i, j;
+ int ret;
+ int mem_offset;
+
+ mem_offset = fdt_path_offset(fdt, "/memorycontroller@f300000");
+ if (mem_offset < 0)
+ return -ENODEV;
+
+ for (i = 0; i < LPDDR4_INTR_CTL_REG_COUNT; i++)
+ for (j = 0; j < ddrss->ctl_regs_num; j++)
+ if (i == ddrss->ctl_regs[j].off) {
+ ret = fdt_setprop_inplace_idx_u32(fdt,
+ mem_offset, "ti,ctl-data", i,
+ ddrss->ctl_regs[j].val);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < LPDDR4_INTR_PHY_INDEP_REG_COUNT; i++)
+ for (j = 0; j < ddrss->pi_regs_num; j++)
+ if (i == ddrss->pi_regs[j].off) {
+ ret = fdt_setprop_inplace_idx_u32(fdt,
+ mem_offset, "ti,pi-data", i,
+ ddrss->pi_regs[j].val);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < LPDDR4_INTR_PHY_INDEP_REG_COUNT; i++)
+ for (j = 0; j < ddrss->phy_regs_num; j++)
+ if (i == ddrss->phy_regs[j].off) {
+ ret = fdt_setprop_inplace_idx_u32(fdt,
+ mem_offset, "ti,phy-data", i,
+ ddrss->phy_regs[j].val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/board/phytec/common/k3/k3_ddrss_patch.h b/board/phytec/common/k3/k3_ddrss_patch.h
new file mode 100644
index 00000000000..0a47c85116a
--- /dev/null
+++ b/board/phytec/common/k3/k3_ddrss_patch.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2024 PHYTEC Messtechnik GmbH
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ */
+
+#ifndef K3_DDRSS_PATCH
+#define K3_DDRSS_PATCH
+
+#include <linux/types.h>
+
+struct ddr_reg {
+ u32 off;
+ u32 val;
+};
+
+struct ddrss {
+ struct ddr_reg *ctl_regs;
+ u32 ctl_regs_num;
+ struct ddr_reg *pi_regs;
+ u32 pi_regs_num;
+ struct ddr_reg *phy_regs;
+ u32 phy_regs_num;
+};
+
+int fdt_apply_ddrss_timings_patch(void *fdt, struct ddrss *ddrss);
+
+#endif /* K3_DDRSS_PATCH */
diff --git a/board/phytec/common/phytec_som_detection.c b/board/phytec/common/phytec_som_detection.c
index 78c173df20d..166c3eae565 100644
--- a/board/phytec/common/phytec_som_detection.c
+++ b/board/phytec/common/phytec_som_detection.c
@@ -4,7 +4,6 @@
* Author: Teresa Remmet <t.remmet@phytec.de>
*/
-#include <common.h>
#include <dm/device.h>
#include <dm/uclass.h>
#include <i2c.h>
@@ -48,16 +47,9 @@ int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
return ret;
}
-int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
- int bus_num, int addr)
+int phytec_eeprom_read(u8 *data, int bus_num, int addr, int size, int offset)
{
- int ret, i;
- unsigned int crc;
- u8 *ptr;
- const unsigned int payload_size = sizeof(struct phytec_eeprom_payload);
-
- if (!data)
- data = &eeprom_data;
+ int ret;
#if CONFIG_IS_ENABLED(DM_I2C)
struct udevice *dev;
@@ -65,19 +57,182 @@ int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
ret = i2c_get_chip_for_busnum(bus_num, addr, 2, &dev);
if (ret) {
pr_err("%s: i2c EEPROM not found: %i.\n", __func__, ret);
- goto err;
+ return ret;
}
- ret = dm_i2c_read(dev, 0, (uint8_t *)data, payload_size);
+ ret = dm_i2c_read(dev, offset, (uint8_t *)data, size);
if (ret) {
pr_err("%s: Unable to read EEPROM data: %i\n", __func__, ret);
- goto err;
+ return ret;
}
#else
i2c_set_bus_num(bus_num);
- ret = i2c_read(addr, 0, 2, (uint8_t *)data,
- sizeof(struct phytec_eeprom_data));
+ ret = i2c_read(addr, offset, 2, (uint8_t *)data, size);
#endif
+ return ret;
+}
+
+int phytec_eeprom_data_init_v2(struct phytec_eeprom_data *data)
+{
+ unsigned int crc;
+
+ if (!data)
+ return -1;
+
+ crc = crc8(0, (const unsigned char *)&data->payload, PHYTEC_API2_DATA_LEN);
+ 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;
+}
+
+#if IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION_BLOCKS)
+
+int phytec_eeprom_data_init_v3_block(struct phytec_eeprom_data *data,
+ struct phytec_api3_block_header *header,
+ u8 *payload)
+{
+ struct phytec_api3_element *element = NULL;
+ struct phytec_api3_element *list_iterator;
+
+ if (!header)
+ return -1;
+ if (!payload)
+ return -1;
+
+ debug("%s: block type: %i\n", __func__, header->block_type);
+ switch (header->block_type) {
+ case PHYTEC_API3_BLOCK_MAC:
+ element = phytec_blocks_init_mac(header, payload);
+ break;
+ default:
+ debug("%s: Unknown block type %i\n", __func__,
+ header->block_type);
+ }
+ if (!element)
+ return -1;
+
+ if (!data->payload.block_head) {
+ data->payload.block_head = element;
+ return 0;
+ }
+
+ list_iterator = data->payload.block_head;
+ while (list_iterator && list_iterator->next)
+ list_iterator = list_iterator->next;
+ list_iterator->next = element;
+
+ return 0;
+}
+
+int phytec_eeprom_data_init_v3(struct phytec_eeprom_data *data,
+ int bus_num, int addr)
+{
+ int ret, i;
+ struct phytec_api3_header header;
+ unsigned int crc;
+ u8 *payload;
+ int block_addr;
+ struct phytec_api3_block_header *block_header;
+
+ if (!data)
+ return -1;
+
+ ret = phytec_eeprom_read((uint8_t *)&header, bus_num, addr,
+ PHYTEC_API3_DATA_HEADER_LEN,
+ PHYTEC_API2_DATA_LEN);
+ if (ret) {
+ pr_err("%s: Failed to read API v3 data header.\n", __func__);
+ goto err;
+ }
+
+ crc = crc8(0, (const unsigned char *)&header,
+ PHYTEC_API3_DATA_HEADER_LEN);
+ debug("%s: crc: %x\n", __func__, crc);
+ if (crc) {
+ pr_err("%s: CRC mismatch. API3 header is unusable.\n",
+ __func__);
+ goto err;
+ }
+
+ debug("%s: data length: %i\n", __func__, header.data_length);
+ payload = malloc(header.data_length);
+ if (!payload) {
+ pr_err("%s: Unable to allocate memory\n", __func__);
+ goto err_payload;
+ }
+
+ ret = phytec_eeprom_read(payload, bus_num, addr, header.data_length,
+ PHYTEC_API3_DATA_HEADER_LEN +
+ PHYTEC_API2_DATA_LEN);
+ if (ret) {
+ pr_err("%s: Failed to read API v3 data payload.\n", __func__);
+ goto err_payload;
+ }
+
+ block_addr = 0;
+ debug("%s: block count: %i\n", __func__, header.block_count);
+ for (i = 0; i < header.block_count; i++) {
+ debug("%s: block_addr: %i\n", __func__, block_addr);
+ block_header = (struct phytec_api3_block_header *)
+ &payload[block_addr];
+ crc = crc8(0, (const unsigned char *)block_header,
+ PHYTEC_API3_BLOCK_HEADER_LEN);
+
+ debug("%s: crc: %x\n", __func__, crc);
+ if (crc) {
+ pr_err("%s: CRC mismatch. API3 block header is unusable\n",
+ __func__);
+ goto err_payload;
+ }
+
+ ret = phytec_eeprom_data_init_v3_block(data, block_header,
+ &payload[block_addr + PHYTEC_API3_BLOCK_HEADER_LEN]);
+ /* Ignore failed block initialization and continue. */
+ if (ret)
+ debug("%s: Unable to create block with index %i.\n",
+ __func__, i);
+
+ block_addr = block_header->next_block;
+ }
+
+ free(payload);
+ return 0;
+err_payload:
+ free(payload);
+err:
+ return -1;
+}
+
+#else
+
+inline int phytec_eeprom_data_init_v3(struct phytec_eeprom_data *data,
+ int bus_num, int addr)
+{
+ return 0;
+}
+
+#endif
+
+int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
+ int bus_num, int addr)
+{
+ int ret, i;
+ u8 *ptr;
+
+ if (!data)
+ data = &eeprom_data;
+
+ ret = phytec_eeprom_read((u8 *)data, bus_num, addr,
+ PHYTEC_API2_DATA_LEN, 0);
+ if (ret)
+ goto err;
+ data->payload.block_head = NULL;
if (data->payload.api_rev == 0xff) {
pr_err("%s: EEPROM is not flashed. Prototype?\n", __func__);
@@ -86,31 +241,28 @@ int phytec_eeprom_data_init(struct phytec_eeprom_data *data,
}
ptr = (u8 *)data;
- for (i = 0; i < payload_size; ++i)
+ for (i = 0; i < PHYTEC_API2_DATA_LEN; ++i)
if (ptr[i] != 0x0)
break;
- if (i == payload_size) {
+ if (i == PHYTEC_API2_DATA_LEN) {
pr_err("%s: EEPROM data is all zero. Erased?\n", __func__);
ret = -EINVAL;
goto err;
}
- /* We are done here for early revisions */
- if (data->payload.api_rev <= PHYTEC_API_REV1) {
- data->valid = true;
- return 0;
+ if (data->payload.api_rev >= PHYTEC_API_REV2) {
+ ret = phytec_eeprom_data_init_v2(data);
+ if (ret)
+ goto err;
}
- crc = crc8(0, (const unsigned char *)&data->payload, payload_size);
- debug("%s: crc: %x\n", __func__, crc);
-
- if (crc) {
- pr_err("%s: CRC mismatch. EEPROM data is not usable.\n",
- __func__);
- ret = -EINVAL;
- goto err;
- }
+ if (IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION_BLOCKS))
+ if (data->payload.api_rev >= PHYTEC_API_REV3) {
+ ret = phytec_eeprom_data_init_v3(data, bus_num, addr);
+ if (ret)
+ goto err;
+ }
data->valid = true;
return 0;
@@ -249,6 +401,17 @@ struct extension *phytec_add_extension(const char *name, const char *overlay,
}
#endif /* IS_ENABLED(CONFIG_CMD_EXTENSION) */
+struct phytec_api3_element *
+ __maybe_unused phytec_get_block_head(struct phytec_eeprom_data *data)
+{
+ if (!data)
+ data = &eeprom_data;
+ if (!data->valid)
+ return NULL;
+
+ return data->payload.block_head;
+}
+
#else
inline int phytec_eeprom_data_setup(struct phytec_eeprom_data *data,
@@ -289,6 +452,12 @@ u8 __maybe_unused phytec_get_som_type(struct phytec_eeprom_data *data)
return PHYTEC_EEPROM_INVAL;
}
+inline struct phytec_api3_element * __maybe_unused
+ phytec_get_block_head(struct phytec_eeprom_data *data)
+{
+ return NULL;
+}
+
#if IS_ENABLED(CONFIG_CMD_EXTENSION)
inline struct extension *phytec_add_extension(const char *name,
const char *overlay,
diff --git a/board/phytec/common/phytec_som_detection.h b/board/phytec/common/phytec_som_detection.h
index 0ad5c14ef4e..5e35a13cb21 100644
--- a/board/phytec/common/phytec_som_detection.h
+++ b/board/phytec/common/phytec_som_detection.h
@@ -7,9 +7,13 @@
#ifndef _PHYTEC_SOM_DETECTION_H
#define _PHYTEC_SOM_DETECTION_H
+#include "phytec_som_detection_blocks.h"
+
#define PHYTEC_MAX_OPTIONS 17
#define PHYTEC_EEPROM_INVAL 0xff
+#define PHYTEC_API2_DATA_LEN 32
+
#define PHYTEC_GET_OPTION(option) \
(((option) > '9') ? (option) - 'A' + 10 : (option) - '0')
@@ -17,6 +21,7 @@ enum {
PHYTEC_API_REV0 = 0,
PHYTEC_API_REV1,
PHYTEC_API_REV2,
+ PHYTEC_API_REV3,
};
enum phytec_som_type_str {
@@ -61,6 +66,7 @@ struct phytec_eeprom_payload {
struct phytec_api0_data data_api0;
struct phytec_api2_data data_api2;
} data;
+ struct phytec_api3_element *block_head;
} __packed;
struct phytec_eeprom_data {
@@ -86,4 +92,7 @@ struct extension *phytec_add_extension(const char *name, const char *overlay,
const char *other);
#endif /* IS_ENABLED(CONFIG_CMD_EXTENSION) */
+struct phytec_api3_element *
+ __maybe_unused phytec_get_block_head(struct phytec_eeprom_data *data);
+
#endif /* _PHYTEC_SOM_DETECTION_H */
diff --git a/board/phytec/common/phytec_som_detection_blocks.c b/board/phytec/common/phytec_som_detection_blocks.c
new file mode 100644
index 00000000000..5f3c27ef0c2
--- /dev/null
+++ b/board/phytec/common/phytec_som_detection_blocks.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 PHYTEC Messtechnik GmbH
+ * Author: Daniel Schultz <d.schultz@phytec.de>
+ */
+
+#include <malloc.h>
+#include <u-boot/crc.h>
+#include <net.h>
+#include <vsprintf.h>
+
+#include "phytec_som_detection_blocks.h"
+
+#if IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION_BLOCKS)
+
+struct phytec_api3_element *
+ phytec_blocks_init_mac(struct phytec_api3_block_header *header,
+ uint8_t *payload)
+{
+ struct phytec_api3_element *element;
+ struct phytec_api3_block_mac *mac;
+ unsigned int crc;
+ unsigned int len = sizeof(struct phytec_api3_block_mac);
+
+ if (!header)
+ return NULL;
+ if (!payload)
+ return NULL;
+
+ element = (struct phytec_api3_element *)
+ calloc(8, PHYTEC_API3_ELEMENT_HEADER_SIZE + len);
+ if (!element) {
+ pr_err("%s: Unable to allocate memory\n", __func__);
+ return NULL;
+ }
+ element->block_type = header->block_type;
+ memcpy(&element->block.mac, payload, len);
+ mac = &element->block.mac;
+
+ debug("%s: interface: %i\n", __func__, mac->interface);
+ debug("%s: MAC %pM\n", __func__, mac->address);
+
+ crc = crc8(0, (const unsigned char *)mac, len);
+ debug("%s: crc: %x\n", __func__, crc);
+ if (crc) {
+ pr_err("%s: CRC mismatch. API3 block payload is unusable\n",
+ __func__);
+ return NULL;
+ }
+
+ return element;
+}
+
+int __maybe_unused
+ phytec_blocks_add_mac_to_env(struct phytec_api3_element *element)
+{
+ char enetenv[9] = "ethaddr";
+ char buf[ARP_HLEN_ASCII + 1];
+ struct phytec_api3_block_mac *block = &element->block.mac;
+ int ret;
+
+ if (!is_valid_ethaddr(block->address)) {
+ pr_err("%s: Invalid MAC address in block.\n", __func__);
+ return -1;
+ }
+
+ if (block->interface > 0) {
+ ret = sprintf(enetenv, "eth%iaddr", block->interface);
+ if (ret != 8) {
+ pr_err("%s: Unable to create env string\n", __func__);
+ return -1;
+ }
+ }
+
+ ret = sprintf(buf, "%pM", block->address);
+ if (ret != ARP_HLEN_ASCII) {
+ pr_err("%s: Unable to convert MAC address\n", __func__);
+ return -1;
+ }
+ ret = env_set(enetenv, buf);
+ if (ret) {
+ pr_err("%s: Failed to set MAC address to env.\n", __func__);
+ return -1;
+ }
+
+ debug("%s: Added %s to %s\n", __func__, buf, enetenv);
+ return 0;
+}
+
+#else
+
+inline struct phytec_api3_element *
+ phytec_api3_init_mac_block(struct phytec_api3_block_header *header,
+ uint8_t *payload)
+{
+ return NULL;
+}
+
+inline int __maybe_unused
+ phytec_blocks_add_mac_to_env(struct phytec_api3_element *element)
+{
+ return -1;
+}
+
+#endif
diff --git a/board/phytec/common/phytec_som_detection_blocks.h b/board/phytec/common/phytec_som_detection_blocks.h
new file mode 100644
index 00000000000..2a5a83c9039
--- /dev/null
+++ b/board/phytec/common/phytec_som_detection_blocks.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2024 PHYTEC Messtechnik GmbH
+ * Author: Daniel Schultz <d.schultz@phytec.de>
+ */
+
+#ifndef _PHYTEC_SOM_DETECTION_BLOCKS_H
+#define _PHYTEC_SOM_DETECTION_BLOCKS_H
+
+#define PHYTEC_API3_DATA_HEADER_LEN 8
+#define PHYTEC_API3_BLOCK_HEADER_LEN 4
+#define PHYTEC_API3_PAYLOAD_START \
+ (PHYTEC_API2_DATA_LEN + PHYTEC_API3_DATA_HEADER_LEN)
+
+#define PHYTEC_API3_ELEMENT_HEADER_SIZE \
+ (sizeof(struct phytec_api3_element *) + \
+ sizeof(enum phytec_api3_block_types))
+
+#define PHYTEC_API3_FOREACH_BLOCK(elem, data) \
+ for (elem = phytec_get_block_head(data); elem; elem = elem->next)
+
+struct phytec_api3_header {
+ u16 data_length; /* Total length in Bytes of all blocks */
+ u8 block_count; /* Number of blocks */
+ u8 sub_version; /* Block specification version */
+ u8 reserved[3]; /* Reserved */
+ u8 crc8; /* checksum */
+} __packed;
+
+struct phytec_api3_block_header {
+ u8 block_type; /* Block payload identifier */
+ u16 next_block; /* Address of the next block */
+ u8 crc8; /* checksum */
+} __packed;
+
+enum phytec_api3_block_types {
+ PHYTEC_API3_BLOCK_MAC = 0,
+};
+
+struct phytec_api3_block_mac {
+ u8 interface; /* Ethernet interface number */
+ u8 address[6]; /* MAC-Address */
+ u8 crc8; /* checksum */
+} __packed;
+
+struct phytec_api3_element {
+ struct phytec_api3_element *next;
+ enum phytec_api3_block_types block_type;
+ union {
+ struct phytec_api3_block_mac mac;
+ } block;
+} __packed;
+
+struct phytec_api3_element *
+ phytec_blocks_init_mac(struct phytec_api3_block_header *header,
+ uint8_t *payload);
+
+int __maybe_unused
+phytec_blocks_add_mac_to_env(struct phytec_api3_element *element);
+
+#endif /* _PHYTEC_SOM_DETECTION_BLOCKS_H */