board: phytec: common: Add imx8m specific EEPROM detection support

Add imx8m specific detection part. Which includes checking the
EEPROM data for article number options.

Signed-off-by: Teresa Remmet <t.remmet@phytec.de>
Reviewed-by: Yannic Moog <y.moog@phytec.de>
Tested-by: Yannic Moog <y.moog@phytec.de>
diff --git a/board/phytec/common/Kconfig b/board/phytec/common/Kconfig
index d614d45..3b1c5aa 100644
--- a/board/phytec/common/Kconfig
+++ b/board/phytec/common/Kconfig
@@ -3,3 +3,11 @@
 	select SPL_CRC8 if SPL
 	help
 	   Support of I2C EEPROM based SoM detection.
+
+config PHYTEC_IMX8M_SOM_DETECTION
+	bool "Support SoM detection for i.MX8M PHYTEC platforms"
+	depends on ARCH_IMX8M && PHYTEC_SOM_DETECTION
+	default y
+	help
+	  Support of I2C EEPROM based SoM detection. Supported
+	  for PHYTEC i.MX8MM/i.MX8MP boards
diff --git a/board/phytec/common/Makefile b/board/phytec/common/Makefile
index 5fe8725..fe28964 100644
--- a/board/phytec/common/Makefile
+++ b/board/phytec/common/Makefile
@@ -8,3 +8,4 @@
 endif
 
 obj-$(CONFIG_PHYTEC_SOM_DETECTION) += phytec_som_detection.o
+obj-$(CONFIG_PHYTEC_IMX8M_SOM_DETECTION) += imx8m_som_detection.o
diff --git a/board/phytec/common/imx8m_som_detection.c b/board/phytec/common/imx8m_som_detection.c
new file mode 100644
index 0000000..c6c96ed
--- /dev/null
+++ b/board/phytec/common/imx8m_som_detection.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2023 PHYTEC Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ */
+
+#include <common.h>
+#include <asm/arch/sys_proto.h>
+#include <dm/device.h>
+#include <dm/uclass.h>
+#include <i2c.h>
+#include <u-boot/crc.h>
+
+#include "imx8m_som_detection.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 -1.
+ */
+u8 __maybe_unused phytec_imx8m_detect(struct phytec_eeprom_data *data)
+{
+	char *opt;
+	u8 som;
+
+	/* We can not do the check for early API revisions */
+	if (data->api_rev < PHYTEC_API_REV2)
+		return -1;
+
+	if (!data)
+		data = &eeprom_data;
+
+	som = data->data.data_api2.som_no;
+	debug("%s: som id: %u\n", __func__, som);
+
+	opt = phytec_get_opt(data);
+	if (!opt)
+		return -1;
+
+	if (som == PHYTEC_IMX8MP_SOM && is_imx8mp())
+		return 0;
+
+	if (som == PHYTEC_IMX8MM_SOM) {
+		if ((PHYTEC_GET_OPTION(opt[0]) != 0) &&
+		    (PHYTEC_GET_OPTION(opt[1]) == 0) && is_imx8mm())
+			return 0;
+		else if ((PHYTEC_GET_OPTION(opt[0]) == 0) &&
+			 (PHYTEC_GET_OPTION(opt[1]) != 0) && is_imx8mn())
+			return 0;
+	}
+
+	if (som == PHYTEC_IMX8MQ_SOM && is_imx8mq())
+		return 0;
+
+	pr_err("%s: SoM ID does not match. Wrong EEPROM data?\n", __func__);
+	return -1;
+}
+
+/*
+ * All PHYTEC i.MX8M boards have RAM size definition at the
+ * same location.
+ */
+u8 __maybe_unused phytec_get_imx8m_ddr_size(struct phytec_eeprom_data *data)
+{
+	char *opt;
+	u8 ddr_id;
+
+	if (!data)
+		data = &eeprom_data;
+
+	opt = phytec_get_opt(data);
+	if (opt)
+		ddr_id = PHYTEC_GET_OPTION(opt[2]);
+	else
+		ddr_id = PHYTEC_EEPROM_INVAL;
+
+	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 __maybe_unused phytec_get_imx8m_spi(struct phytec_eeprom_data *data)
+{
+	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 = PHYTEC_GET_OPTION(opt[4]);
+	else
+		spi = PHYTEC_EEPROM_INVAL;
+
+	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 populated. 0x1 if it is populated.
+ * PHYTEC_EEPROM_INVAL when the data is invalid.
+ */
+u8 __maybe_unused phytec_get_imx8m_eth(struct phytec_eeprom_data *data)
+{
+	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 = PHYTEC_GET_OPTION(opt[5]);
+		eth &= 0x1;
+	} else {
+		eth = PHYTEC_EEPROM_INVAL;
+	}
+
+	debug("%s: eth: %u\n", __func__, eth);
+	return eth;
+}
+
+/*
+ * Filter RTC information for phyCORE-i.MX8MP.
+ * returns: 0 if no RTC is populated. 1 if it is populated.
+ * PHYTEC_EEPROM_INVAL when the data is invalid.
+ */
+u8 __maybe_unused phytec_get_imx8mp_rtc(struct phytec_eeprom_data *data)
+{
+	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 = PHYTEC_GET_OPTION(opt[5]);
+		rtc &= 0x4;
+		rtc = !(rtc >> 2);
+	} else {
+		rtc = PHYTEC_EEPROM_INVAL;
+	}
+	debug("%s: rtc: %u\n", __func__, rtc);
+	return rtc;
+}
diff --git a/board/phytec/common/imx8m_som_detection.h b/board/phytec/common/imx8m_som_detection.h
new file mode 100644
index 0000000..88d3037
--- /dev/null
+++ b/board/phytec/common/imx8m_som_detection.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2023 PHYTEC Messtechnik GmbH
+ * Author: Teresa Remmet <t.remmet@phytec.de>
+ */
+
+#ifndef _PHYTEC_IMX8M_SOM_DETECTION_H
+#define _PHYTEC_IMX8M_SOM_DETECTION_H
+
+#include "phytec_som_detection.h"
+
+#define PHYTEC_IMX8MQ_SOM       66
+#define PHYTEC_IMX8MM_SOM       69
+#define PHYTEC_IMX8MP_SOM       70
+
+#if IS_ENABLED(CONFIG_PHYTEC_IMX8M_SOM_DETECTION)
+
+u8 __maybe_unused phytec_imx8m_detect(struct phytec_eeprom_data *data);
+u8 __maybe_unused phytec_get_imx8m_ddr_size(struct phytec_eeprom_data *data);
+u8 __maybe_unused phytec_get_imx8mp_rtc(struct phytec_eeprom_data *data);
+u8 __maybe_unused phytec_get_imx8m_spi(struct phytec_eeprom_data *data);
+u8 __maybe_unused phytec_get_imx8m_eth(struct phytec_eeprom_data *data);
+
+#else
+
+inline u8 __maybe_unused phytec_imx8m_detect(struct phytec_eeprom_data *data)
+{
+	return -1;
+}
+
+inline u8 __maybe_unused
+phytec_get_imx8m_ddr_size(struct phytec_eeprom_data *data)
+{
+	return PHYTEC_EEPROM_INVAL;
+}
+
+inline u8 __maybe_unused phytec_get_imx8mp_rtc(struct phytec_eeprom_data *data)
+{
+	return PHYTEC_EEPROM_INVAL;
+}
+
+inline u8 __maybe_unused phytec_get_imx8m_spi(struct phytec_eeprom_data *data)
+{
+	return PHYTEC_EEPROM_INVAL;
+}
+
+inline u8 __maybe_unused phytec_get_imx8m_eth(struct phytec_eeprom_data *data)
+{
+	return PHYTEC_EEPROM_INVAL;
+}
+
+#endif /* IS_ENABLED(CONFIG_PHYTEC_IMX8M_SOM_DETECTION) */
+
+#endif /* _PHYTEC_IMX8M_SOM_DETECTION_H */