[PATCH v5 2/5] mach-snapdragon: Add hardware detection helper

Aswin Murugan via U-Boot <[email protected]>
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <[email protected]>
Add qcom_hwdetect, a helper that aggregates hardware parameters
(chip ID, chip version, board version, platform, subtype, OEM
variant, foundry ID, DDR size type, storage type) from SMEM, TCSR,
and IMEM into a single struct qcom_hw_params. This is intended for
consumption by FIT multi-DTB selection and other subsystems that
need a unified view of hardware identification data.

Depends on the qcom,hwinfo driver for IMEM/TCSR register access.

Signed-off-by: Aswin Murugan <[email protected]>
---
 arch/arm/mach-snapdragon/Kconfig         |   8 ++
 arch/arm/mach-snapdragon/Makefile        |   1 +
 arch/arm/mach-snapdragon/qcom_hwdetect.c | 167 +++++++++++++++++++++++
 arch/arm/mach-snapdragon/qcom_hwdetect.h |  52 +++++++
 4 files changed, 228 insertions(+)
 create mode 100644 arch/arm/mach-snapdragon/qcom_hwdetect.c
 create mode 100644 arch/arm/mach-snapdragon/qcom_hwdetect.h

diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig
index ddded0029ef..5911e76dc1e 100644
--- a/arch/arm/mach-snapdragon/Kconfig
+++ b/arch/arm/mach-snapdragon/Kconfig
@@ -59,6 +59,14 @@ config QCOM_GENERATE_MBN
 	  New platforms can be added to tools/qcom/mkmbn/mkmbn.py if they aren't already
 	  supported.
 
+config QCOM_HWDETECT
+	bool "Qualcomm Hardware Detection"
+	depends on QCOM_SMEM
+	select QCOM_HWINFO
+	help
+	  Hardware parameter detection from SMEM and TCSR for
+	  DTB selection and other platform subsystems.
+
 choice
 	prompt "Qualcomm boot0.h workaround"
 	optional
diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile
index 2360b7c658e..6132847d7f4 100644
--- a/arch/arm/mach-snapdragon/Makefile
+++ b/arch/arm/mach-snapdragon/Makefile
@@ -10,6 +10,7 @@ obj-y += board_spl.o
 else
 obj-y += board.o
 obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o
+obj-$(CONFIG_QCOM_HWDETECT) += qcom_hwdetect.o
 endif
 
 obj-$(CONFIG_OF_LIVE) += of_fixup.o
diff --git a/arch/arm/mach-snapdragon/qcom_hwdetect.c b/arch/arm/mach-snapdragon/qcom_hwdetect.c
new file mode 100644
index 00000000000..a3a3a26556d
--- /dev/null
+++ b/arch/arm/mach-snapdragon/qcom_hwdetect.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Qualcomm Hardware Detection
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * Detects hardware parameters from SMEM, TCSR registers, and IMEM
+ * for use by DTB selection and other subsystems.
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <qcom_hwinfo.h>
+#include <asm/global_data.h>
+#include <dm/uclass.h>
+#include <linux/errno.h>
+#include <linux/sizes.h>
+#include <soc/qcom/smem.h>
+#include <soc/qcom/socinfo.h>
+
+#include "qcom_hwdetect.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* TCSR SOC HW Version register field masks */
+#define TCSR_MAJOR_VERSION_MASK    0x0000ff00
+#define TCSR_MAJOR_VERSION_SHIFT   8
+#define TCSR_MINOR_VERSION_MASK    0x000000ff
+#define TCSR_MINOR_VERSION_SHIFT   0
+
+/* DDR type enum */
+enum ddr_type {
+	DDRTYPE_256MB = 1,
+	DDRTYPE_512MB,
+	DDRTYPE_1024MB,
+	DDRTYPE_2048MB,
+	DDRTYPE_3072MB,
+	DDRTYPE_4096MB,
+	DDRTYPE_128MB,
+};
+
+/**
+ * qcom_get_hwinfo_dev() - Look up the qcom,hwinfo device
+ * @devp: Returns the qcom_hwinfo udevice
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_get_hwinfo_dev(struct udevice **devp)
+{
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(qcom_hwinfo),
+					  devp);
+	if (ret)
+		log_warning("qcom,hwinfo device not found/probed: %d\n", ret);
+
+	return ret;
+}
+
+/**
+ * qcom_get_ddr_size_type() - Get DDR size type from gd->ram_size
+ * @ddr_type: Pointer to store DDR type
+ *
+ * Uses gd->ram_size which is calculated by dram.c from SMEM/FDT
+ * during early boot. Avoids redundant SMEM re-parsing.
+ *
+ * Return: 0 on success
+ */
+static int qcom_get_ddr_size_type(u32 *ddr_type)
+{
+	u64 total_ddr_size = gd->ram_size;
+
+	log_debug("Total DDR Size: 0x%llx (%llu MB)\n",
+		  total_ddr_size, total_ddr_size / SZ_1M);
+
+	*ddr_type = 0;
+	if (total_ddr_size <= SZ_128M)
+		*ddr_type = DDRTYPE_128MB;
+	else if (total_ddr_size <= SZ_256M)
+		*ddr_type = DDRTYPE_256MB;
+	else if (total_ddr_size <= SZ_512M)
+		*ddr_type = DDRTYPE_512MB;
+	else if (total_ddr_size <= SZ_1G)
+		*ddr_type = DDRTYPE_1024MB;
+	else if (total_ddr_size <= SZ_2G)
+		*ddr_type = DDRTYPE_2048MB;
+	else if (total_ddr_size <= (SZ_2G + SZ_1G))
+		*ddr_type = DDRTYPE_3072MB;
+	else if (total_ddr_size <= SZ_4G)
+		*ddr_type = DDRTYPE_4096MB;
+
+	log_debug("DDR Type: %u\n", *ddr_type);
+
+	return 0;
+}
+
+int qcom_hwdetect_get_params(struct qcom_hw_params *params)
+{
+	struct udevice *hwinfo;
+	struct socinfo *soc_info;
+	size_t size;
+	int ret;
+	u32 raw_version, reg_val, major, minor;
+
+	if (!params)
+		return -EINVAL;
+
+	memset(params, 0, sizeof(*params));
+
+	ret = qcom_get_hwinfo_dev(&hwinfo);
+	if (ret) {
+		log_err("qcom,hwinfo device not available\n");
+		return ret;
+	}
+
+	soc_info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, &size);
+	if (IS_ERR_OR_NULL(soc_info)) {
+		log_err("Failed to get SOC info from SMEM\n");
+		return -ENODEV;
+	}
+
+	params->chip_id = le32_to_cpu(soc_info->id) & 0xffff;
+
+	raw_version = le32_to_cpu(soc_info->plat_ver);
+	params->board_version = (SOCINFO_MAJOR(raw_version) << 4) | SOCINFO_MINOR(raw_version);
+
+	ret = qcom_hwinfo_get_tcsr_hw_version(hwinfo, &reg_val);
+	if (ret) {
+		log_err("Failed to read TCSR HW version via qcom,hwinfo: %d\n", ret);
+		return ret;
+	}
+	major = (reg_val & TCSR_MAJOR_VERSION_MASK) >> TCSR_MAJOR_VERSION_SHIFT;
+	minor = (reg_val & TCSR_MINOR_VERSION_MASK) >> TCSR_MINOR_VERSION_SHIFT;
+	params->chip_version = (major << 4) | minor;
+
+	params->platform = le32_to_cpu(soc_info->hw_plat);
+	params->subtype = le32_to_cpu(soc_info->hw_plat_subtype);
+
+	if (le32_to_cpu(soc_info->fmt) >= 17)
+		params->oem_variant_id = le32_to_cpu(soc_info->oem_variant);
+
+	if (le32_to_cpu(soc_info->fmt) >= 9)
+		params->foundry_id = le32_to_cpu(soc_info->foundry_id);
+
+	ret = qcom_get_ddr_size_type(&params->ddr_size_type);
+	if (ret)
+		log_warning("Failed to get DDR size, defaulting to 0\n");
+
+	ret = qcom_hwinfo_get_storage_type(hwinfo, &params->storage_type);
+	if (ret) {
+		log_warning("Failed to detect storage type via qcom,hwinfo, defaulting to UFS\n");
+		params->storage_type = QCOM_HWINFO_STORAGE_UFS;
+	}
+
+	log_debug("Hardware Parameters:\n");
+	log_debug("  Chip ID: 0x%x\n", params->chip_id);
+	log_debug("  Chip Version: 0x%x\n", params->chip_version);
+	log_debug("  Board Version: 0x%x\n", params->board_version);
+	log_debug("  Platform: 0x%x\n", params->platform);
+	log_debug("  Subtype: 0x%x\n", params->subtype);
+	log_debug("  OEM Variant ID: 0x%x\n", params->oem_variant_id);
+	log_debug("  DDR Size Type: %u\n", params->ddr_size_type);
+	log_debug("  Storage Type: %u\n", params->storage_type);
+	log_debug("  Foundry ID: 0x%x\n", params->foundry_id);
+
+	return 0;
+}
diff --git a/arch/arm/mach-snapdragon/qcom_hwdetect.h b/arch/arm/mach-snapdragon/qcom_hwdetect.h
new file mode 100644
index 00000000000..cb75f565756
--- /dev/null
+++ b/arch/arm/mach-snapdragon/qcom_hwdetect.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Qualcomm Hardware Detection
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef __QCOM_HWDETECT_H__
+#define __QCOM_HWDETECT_H__
+
+#include <linux/types.h>
+
+/**
+ * struct qcom_hw_params - Hardware parameters
+ * @chip_id: SoC chip ID
+ * @chip_version: SoC version from TCSR
+ * @platform: Hardware platform ID
+ * @board_version: Board version
+ * @subtype: Hardware platform subtype
+ * @oem_variant_id: OEM variant ID
+ * @foundry_id: Foundry ID
+ * @softsku_id: Software SKU ID
+ * @ddr_size_type: DDR size type (0-7)
+ * @storage_type: Storage type (UFS/EMMC/NAND)
+ *
+ * Contains all hardware parameters detected from SMEM, TCSR, and IMEM.
+ */
+struct qcom_hw_params {
+	u32 chip_id;
+	u32 chip_version;
+	u32 platform;
+	u32 board_version;
+	u32 subtype;
+	u32 oem_variant_id;
+	u32 foundry_id;
+	u32 softsku_id;
+	u32 ddr_size_type;
+	u32 storage_type;
+};
+
+/**
+ * qcom_hwdetect_get_params() - Get hardware parameters
+ * @params: Pointer to store hardware parameters
+ *
+ * Detects all hardware parameters from SMEM, TCSR, and IMEM.
+ * Returns a complete structure ready for use by any subsystem.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int qcom_hwdetect_get_params(struct qcom_hw_params *params);
+
+#endif /* __QCOM_HWDETECT_H__ */
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.