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

Reply via email to