[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260203-qcom-socinfo-v2-6-d6719db85637@google.com>
Date: Tue, 03 Feb 2026 15:46:35 +0000
From: Matthew Maurer <mmaurer@...gle.com>
To: Bjorn Andersson <andersson@...nel.org>, Konrad Dybcio <konradybcio@...nel.org>,
Satya Durga Srinivasu Prabhala <satyap@...cinc.com>, Miguel Ojeda <ojeda@...nel.org>, Boqun Feng <boqun.feng@...il.com>,
Gary Guo <gary@...yguo.net>,
"Björn Roy Baron" <bjorn3_gh@...tonmail.com>, Benno Lossin <lossin@...nel.org>,
Andreas Hindborg <a.hindborg@...nel.org>, Alice Ryhl <aliceryhl@...gle.com>,
Trevor Gross <tmgross@...ch.edu>, Danilo Krummrich <dakr@...nel.org>,
Daniel Almeida <daniel.almeida@...labora.com>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>, "Rafael J. Wysocki" <rafael@...nel.org>,
David Airlie <airlied@...il.com>, Simona Vetter <simona@...ll.ch>,
Michal Wilczynski <m.wilczynski@...sung.com>, Dave Ertman <david.m.ertman@...el.com>,
Ira Weiny <ira.weiny@...el.com>, Leon Romanovsky <leon@...nel.org>
Cc: Trilok Soni <tsoni@...cinc.com>, linux-kernel@...r.kernel.org,
linux-arm-msm@...r.kernel.org, rust-for-linux@...r.kernel.org,
driver-core@...ts.linux.dev, dri-devel@...ts.freedesktop.org,
linux-pwm@...r.kernel.org, Matthew Maurer <mmaurer@...gle.com>
Subject: [PATCH v2 6/6] soc: qcom: socinfo: Convert to Rust
Convert the socinfo driver to Rust for a number of improvements:
* Accessing IO mapped regions through the IO subsystem, rather than
through regular memory accesses.
* Binds the device as an auxiliary device rather than a platform device,
ensuring the mapped IO regions cannot be accessed after the smem
device is removed.
* Adds bounds-checking to all accesses, hardening against a repeat of
CVE-2024-58007
Signed-off-by: Matthew Maurer <mmaurer@...gle.com>
---
drivers/soc/qcom/Kconfig | 1 +
drivers/soc/qcom/Makefile | 2 +-
drivers/soc/qcom/smem.c | 42 +-
drivers/soc/qcom/socinfo.c | 931 -----------------------------------
drivers/soc/qcom/socinfo/Makefile | 2 +
drivers/soc/qcom/socinfo/bindings.rs | 123 +++++
drivers/soc/qcom/socinfo/data.rs | 438 ++++++++++++++++
drivers/soc/qcom/socinfo/socinfo.rs | 446 +++++++++++++++++
include/linux/soc/qcom/smem.h | 4 +
rust/bindgen_parameters | 1 +
rust/bindings/bindings_helper.h | 6 +
11 files changed, 1056 insertions(+), 940 deletions(-)
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 2caadbbcf8307ff94f5afbdd1481e5e5e291749f..16d553f66f0cf1101d3a8c7d401d7c4d6a65dac7 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -222,6 +222,7 @@ config QCOM_SMSM
config QCOM_SOCINFO
tristate "Qualcomm socinfo driver"
depends on QCOM_SMEM
+ depends on RUST
select SOC_BUS
help
Say yes here to support the Qualcomm socinfo driver, providing
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index b7f1d2a5736748b8772c090fd24462fa91f321c6..6f6688c76a00a91ce99600f298a8e6e0fefed806 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -28,7 +28,7 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
CFLAGS_smp2p.o := -I$(src)
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
-obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
+obj-$(CONFIG_QCOM_SOCINFO) += socinfo/
obj-$(CONFIG_QCOM_SPM) += spm.o
obj-$(CONFIG_QCOM_STATS) += qcom_stats.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index fef840b5457407a85051ded0e835430dbebfe8bb..dcea2d7f37067b0b6f801b3d2b457422ad9f342c 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -4,6 +4,7 @@
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*/
+#include <linux/auxiliary_bus.h>
#include <linux/hwspinlock.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -279,7 +280,6 @@ struct qcom_smem {
struct hwspinlock *hwlock;
u32 item_count;
- struct platform_device *socinfo;
struct smem_ptable *ptable;
struct smem_partition global_partition;
struct smem_partition partitions[SMEM_HOST_COUNT];
@@ -675,6 +675,32 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
return ERR_PTR(-EINVAL);
}
+/**
+ * qcom_smem_get_aux() - resolve ptr of size of a smem item
+ * @aux: an aux device that should be our child
+ * @host: the remote processor, or -1
+ * @item: smem item handle
+ * @size: pointer to be filled out with size of the item
+ *
+ * Looks up smem item and returns pointer to it. Size of smem
+ * item is returned in @size.
+ *
+ * The caller may take the loaded state of the provided aux device as
+ * an acceptable proxy for this memory being valid.
+ *
+ * Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
+ */
+void *qcom_smem_get_aux(struct auxiliary_device *aux, unsigned int host,
+ unsigned int item, size_t *size)
+{
+ if (IS_ERR(__smem))
+ return __smem;
+ if (aux->dev.parent != __smem->dev)
+ return ERR_PTR(-EINVAL);
+ return qcom_smem_get(host, item, size);
+}
+EXPORT_SYMBOL_GPL(qcom_smem_get_aux);
+
/**
* qcom_smem_get() - resolve ptr of size of a smem item
* @host: the remote processor, or -1
@@ -684,6 +710,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
* Looks up smem item and returns pointer to it. Size of smem
* item is returned in @size.
*
+ * It is up to the caller to ensure that the qcom_smem device remains
+ * loaded by some mechanism when accessing returned memory.
+ *
* Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
*/
void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
@@ -1127,6 +1156,7 @@ static int qcom_smem_probe(struct platform_device *pdev)
struct smem_header *header;
struct reserved_mem *rmem;
struct qcom_smem *smem;
+ struct auxiliary_device *socinfo;
unsigned long flags;
int num_regions;
int hwlock_id;
@@ -1234,19 +1264,15 @@ static int qcom_smem_probe(struct platform_device *pdev)
__smem = smem;
- smem->socinfo = platform_device_register_data(&pdev->dev, "qcom-socinfo",
- PLATFORM_DEVID_NONE, NULL,
- 0);
- if (IS_ERR(smem->socinfo))
- dev_dbg(&pdev->dev, "failed to register socinfo device\n");
+ socinfo = devm_auxiliary_device_create(&pdev->dev, "qcom-socinfo", NULL);
+ if (IS_ERR(socinfo))
+ dev_dbg(&pdev->dev, "failed to create socinfo device\n");
return 0;
}
static void qcom_smem_remove(struct platform_device *pdev)
{
- platform_device_unregister(__smem->socinfo);
-
__smem = NULL;
}
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
deleted file mode 100644
index 003a2304d535c2655db566c644342dbc387e24a9..0000000000000000000000000000000000000000
--- a/drivers/soc/qcom/socinfo.c
+++ /dev/null
@@ -1,931 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017-2019, Linaro Ltd.
- */
-
-#include <linux/debugfs.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/soc/qcom/smem.h>
-#include <linux/soc/qcom/socinfo.h>
-#include <linux/string.h>
-#include <linux/stringify.h>
-#include <linux/sys_soc.h>
-#include <linux/types.h>
-
-#include <linux/unaligned.h>
-
-#include <dt-bindings/arm/qcom,ids.h>
-
-/* Helper macros to create soc_id table */
-#define qcom_board_id(id) QCOM_ID_ ## id, __stringify(id)
-#define qcom_board_id_named(id, name) QCOM_ID_ ## id, (name)
-
-#ifdef CONFIG_DEBUG_FS
-#define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32
-#define SMEM_IMAGE_VERSION_SIZE 4096
-#define SMEM_IMAGE_VERSION_NAME_SIZE 75
-#define SMEM_IMAGE_VERSION_VARIANT_SIZE 20
-#define SMEM_IMAGE_VERSION_OEM_SIZE 32
-
-/*
- * SMEM Image table indices
- */
-#define SMEM_IMAGE_TABLE_BOOT_INDEX 0
-#define SMEM_IMAGE_TABLE_TZ_INDEX 1
-#define SMEM_IMAGE_TABLE_TZSECAPP_INDEX 2
-#define SMEM_IMAGE_TABLE_RPM_INDEX 3
-#define SMEM_IMAGE_TABLE_SDI_INDEX 4
-#define SMEM_IMAGE_TABLE_HYP_INDEX 5
-#define SMEM_IMAGE_TABLE_ADSP1_INDEX 6
-#define SMEM_IMAGE_TABLE_ADSP2_INDEX 7
-#define SMEM_IMAGE_TABLE_CDSP2_INDEX 8
-#define SMEM_IMAGE_TABLE_APPSBL_INDEX 9
-#define SMEM_IMAGE_TABLE_APPS_INDEX 10
-#define SMEM_IMAGE_TABLE_MPSS_INDEX 11
-#define SMEM_IMAGE_TABLE_ADSP_INDEX 12
-#define SMEM_IMAGE_TABLE_CNSS_INDEX 13
-#define SMEM_IMAGE_TABLE_VIDEO_INDEX 14
-#define SMEM_IMAGE_TABLE_DSPS_INDEX 15
-#define SMEM_IMAGE_TABLE_CDSP_INDEX 16
-#define SMEM_IMAGE_TABLE_NPU_INDEX 17
-#define SMEM_IMAGE_TABLE_WPSS_INDEX 18
-#define SMEM_IMAGE_TABLE_CDSP1_INDEX 19
-#define SMEM_IMAGE_TABLE_GPDSP_INDEX 20
-#define SMEM_IMAGE_TABLE_GPDSP1_INDEX 21
-#define SMEM_IMAGE_TABLE_SENSORPD_INDEX 22
-#define SMEM_IMAGE_TABLE_AUDIOPD_INDEX 23
-#define SMEM_IMAGE_TABLE_OEMPD_INDEX 24
-#define SMEM_IMAGE_TABLE_CHARGERPD_INDEX 25
-#define SMEM_IMAGE_TABLE_OISPD_INDEX 26
-#define SMEM_IMAGE_TABLE_SOCCP_INDEX 27
-#define SMEM_IMAGE_TABLE_TME_INDEX 28
-#define SMEM_IMAGE_TABLE_GEARVM_INDEX 29
-#define SMEM_IMAGE_TABLE_UEFI_INDEX 30
-#define SMEM_IMAGE_TABLE_CDSP3_INDEX 31
-#define SMEM_IMAGE_TABLE_AUDIOPD_ADSP1_INDEX 32
-#define SMEM_IMAGE_TABLE_AUDIOPD_ADSP2_INDEX 33
-#define SMEM_IMAGE_TABLE_DCP_INDEX 34
-#define SMEM_IMAGE_TABLE_OOBS_INDEX 35
-#define SMEM_IMAGE_TABLE_OOBNS_INDEX 36
-#define SMEM_IMAGE_TABLE_DEVCFG_INDEX 37
-#define SMEM_IMAGE_TABLE_BTPD_INDEX 38
-#define SMEM_IMAGE_TABLE_QECP_INDEX 39
-
-#define SMEM_IMAGE_VERSION_TABLE 469
-#define SMEM_IMAGE_VERSION_TABLE_2 667
-
-/*
- * SMEM Image table names
- */
-static const char *const socinfo_image_names[] = {
- [SMEM_IMAGE_TABLE_ADSP1_INDEX] = "adsp1",
- [SMEM_IMAGE_TABLE_ADSP2_INDEX] = "adsp2",
- [SMEM_IMAGE_TABLE_ADSP_INDEX] = "adsp",
- [SMEM_IMAGE_TABLE_APPSBL_INDEX] = "appsbl",
- [SMEM_IMAGE_TABLE_APPS_INDEX] = "apps",
- [SMEM_IMAGE_TABLE_AUDIOPD_INDEX] = "audiopd",
- [SMEM_IMAGE_TABLE_AUDIOPD_ADSP1_INDEX] = "audiopd_adsp1",
- [SMEM_IMAGE_TABLE_AUDIOPD_ADSP2_INDEX] = "audiopd_adsp2",
- [SMEM_IMAGE_TABLE_BOOT_INDEX] = "boot",
- [SMEM_IMAGE_TABLE_BTPD_INDEX] = "btpd",
- [SMEM_IMAGE_TABLE_CDSP1_INDEX] = "cdsp1",
- [SMEM_IMAGE_TABLE_CDSP2_INDEX] = "cdsp2",
- [SMEM_IMAGE_TABLE_CDSP3_INDEX] = "cdsp3",
- [SMEM_IMAGE_TABLE_CDSP_INDEX] = "cdsp",
- [SMEM_IMAGE_TABLE_CHARGERPD_INDEX] = "chargerpd",
- [SMEM_IMAGE_TABLE_CNSS_INDEX] = "cnss",
- [SMEM_IMAGE_TABLE_DCP_INDEX] = "dcp",
- [SMEM_IMAGE_TABLE_DEVCFG_INDEX] = "devcfg",
- [SMEM_IMAGE_TABLE_DSPS_INDEX] = "dsps",
- [SMEM_IMAGE_TABLE_GEARVM_INDEX] = "gearvm",
- [SMEM_IMAGE_TABLE_GPDSP1_INDEX] = "gpdsp1",
- [SMEM_IMAGE_TABLE_GPDSP_INDEX] = "gpdsp",
- [SMEM_IMAGE_TABLE_HYP_INDEX] = "hyp",
- [SMEM_IMAGE_TABLE_MPSS_INDEX] = "mpss",
- [SMEM_IMAGE_TABLE_NPU_INDEX] = "npu",
- [SMEM_IMAGE_TABLE_OEMPD_INDEX] = "oempd",
- [SMEM_IMAGE_TABLE_OISPD_INDEX] = "oispd",
- [SMEM_IMAGE_TABLE_OOBNS_INDEX] = "oobns",
- [SMEM_IMAGE_TABLE_OOBS_INDEX] = "oobs",
- [SMEM_IMAGE_TABLE_QECP_INDEX] = "qecp",
- [SMEM_IMAGE_TABLE_RPM_INDEX] = "rpm",
- [SMEM_IMAGE_TABLE_SDI_INDEX] = "sdi",
- [SMEM_IMAGE_TABLE_SENSORPD_INDEX] = "sensorpd",
- [SMEM_IMAGE_TABLE_SOCCP_INDEX] = "soccp",
- [SMEM_IMAGE_TABLE_TME_INDEX] = "tme",
- [SMEM_IMAGE_TABLE_TZ_INDEX] = "tz",
- [SMEM_IMAGE_TABLE_TZSECAPP_INDEX] = "tzsecapp",
- [SMEM_IMAGE_TABLE_UEFI_INDEX] = "uefi",
- [SMEM_IMAGE_TABLE_VIDEO_INDEX] = "video",
- [SMEM_IMAGE_TABLE_WPSS_INDEX] = "wpss",
-};
-
-static const char *const pmic_models[] = {
- [0] = "Unknown PMIC model",
- [1] = "PM8941",
- [2] = "PM8841",
- [3] = "PM8019",
- [4] = "PM8226",
- [5] = "PM8110",
- [6] = "PMA8084",
- [7] = "PMI8962",
- [8] = "PMD9635",
- [9] = "PM8994",
- [10] = "PMI8994",
- [11] = "PM8916",
- [12] = "PM8004",
- [13] = "PM8909/PM8058",
- [14] = "PM8028",
- [15] = "PM8901",
- [16] = "PM8950/PM8027",
- [17] = "PMI8950/ISL9519",
- [18] = "PMK8001/PM8921",
- [19] = "PMI8996/PM8018",
- [20] = "PM8998/PM8015",
- [21] = "PMI8998/PM8014",
- [22] = "PM8821",
- [23] = "PM8038",
- [24] = "PM8005/PM8922",
- [25] = "PM8917/PM8937",
- [26] = "PM660L",
- [27] = "PM660",
- [30] = "PM8150",
- [31] = "PM8150L",
- [32] = "PM8150B",
- [33] = "PMK8002",
- [36] = "PM8009",
- [37] = "PMI632",
- [38] = "PM8150C",
- [40] = "PM6150",
- [41] = "SMB2351",
- [44] = "PM8008",
- [45] = "PM6125",
- [46] = "PM7250B",
- [47] = "PMK8350",
- [48] = "PM8350",
- [49] = "PM8350C",
- [50] = "PM8350B",
- [51] = "PMR735A",
- [52] = "PMR735B",
- [54] = "PM6350",
- [55] = "PM4125",
- [58] = "PM8450",
- [65] = "PM8010",
- [69] = "PM8550VS",
- [70] = "PM8550VE",
- [71] = "PM8550B",
- [72] = "PMR735D",
- [73] = "PM8550",
- [74] = "PMK8550",
- [78] = "PMM8650AU",
- [79] = "PMM8650AU_PSAIL",
- [80] = "PM7550",
- [82] = "PMC8380",
- [83] = "SMB2360",
- [91] = "PMIV0108",
-};
-
-struct socinfo_params {
- u32 raw_device_family;
- u32 hw_plat_subtype;
- u32 accessory_chip;
- u32 raw_device_num;
- u32 chip_family;
- u32 foundry_id;
- u32 plat_ver;
- u32 raw_ver;
- u32 hw_plat;
- u32 fmt;
- u32 nproduct_id;
- u32 num_clusters;
- u32 ncluster_array_offset;
- u32 num_subset_parts;
- u32 nsubset_parts_array_offset;
- u32 nmodem_supported;
- u32 feature_code;
- u32 pcode;
- u32 oem_variant;
- u32 num_func_clusters;
- u32 boot_cluster;
- u32 boot_core;
- u32 raw_package_type;
-};
-
-struct smem_image_version {
- char name[SMEM_IMAGE_VERSION_NAME_SIZE];
- char variant[SMEM_IMAGE_VERSION_VARIANT_SIZE];
- char pad;
- char oem[SMEM_IMAGE_VERSION_OEM_SIZE];
-};
-#endif /* CONFIG_DEBUG_FS */
-
-struct qcom_socinfo {
- struct soc_device *soc_dev;
- struct soc_device_attribute attr;
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dbg_root;
- struct socinfo_params info;
-#endif /* CONFIG_DEBUG_FS */
-};
-
-struct soc_id {
- unsigned int id;
- const char *name;
-};
-
-static const struct soc_id soc_id[] = {
- { qcom_board_id(MSM8260) },
- { qcom_board_id(MSM8660) },
- { qcom_board_id(APQ8060) },
- { qcom_board_id(MSM8960) },
- { qcom_board_id(APQ8064) },
- { qcom_board_id(MSM8930) },
- { qcom_board_id(MSM8630) },
- { qcom_board_id(MSM8230) },
- { qcom_board_id(APQ8030) },
- { qcom_board_id(MSM8627) },
- { qcom_board_id(MSM8227) },
- { qcom_board_id(MSM8660A) },
- { qcom_board_id(MSM8260A) },
- { qcom_board_id(APQ8060A) },
- { qcom_board_id(MSM8974) },
- { qcom_board_id(MSM8225) },
- { qcom_board_id(MSM8625) },
- { qcom_board_id(MPQ8064) },
- { qcom_board_id(MSM8960AB) },
- { qcom_board_id(APQ8060AB) },
- { qcom_board_id(MSM8260AB) },
- { qcom_board_id(MSM8660AB) },
- { qcom_board_id(MSM8930AA) },
- { qcom_board_id(MSM8630AA) },
- { qcom_board_id(MSM8230AA) },
- { qcom_board_id(MSM8626) },
- { qcom_board_id(MSM8610) },
- { qcom_board_id(APQ8064AB) },
- { qcom_board_id(MSM8930AB) },
- { qcom_board_id(MSM8630AB) },
- { qcom_board_id(MSM8230AB) },
- { qcom_board_id(APQ8030AB) },
- { qcom_board_id(MSM8226) },
- { qcom_board_id(MSM8526) },
- { qcom_board_id(APQ8030AA) },
- { qcom_board_id(MSM8110) },
- { qcom_board_id(MSM8210) },
- { qcom_board_id(MSM8810) },
- { qcom_board_id(MSM8212) },
- { qcom_board_id(MSM8612) },
- { qcom_board_id(MSM8112) },
- { qcom_board_id(MSM8125) },
- { qcom_board_id(MSM8225Q) },
- { qcom_board_id(MSM8625Q) },
- { qcom_board_id(MSM8125Q) },
- { qcom_board_id(APQ8064AA) },
- { qcom_board_id(APQ8084) },
- { qcom_board_id(MSM8130) },
- { qcom_board_id(MSM8130AA) },
- { qcom_board_id(MSM8130AB) },
- { qcom_board_id(MSM8627AA) },
- { qcom_board_id(MSM8227AA) },
- { qcom_board_id(APQ8074) },
- { qcom_board_id(MSM8274) },
- { qcom_board_id(MSM8674) },
- { qcom_board_id(MDM9635) },
- { qcom_board_id_named(MSM8974PRO_AC, "MSM8974PRO-AC") },
- { qcom_board_id(MSM8126) },
- { qcom_board_id(APQ8026) },
- { qcom_board_id(MSM8926) },
- { qcom_board_id(IPQ8062) },
- { qcom_board_id(IPQ8064) },
- { qcom_board_id(IPQ8066) },
- { qcom_board_id(IPQ8068) },
- { qcom_board_id(MSM8326) },
- { qcom_board_id(MSM8916) },
- { qcom_board_id(MSM8994) },
- { qcom_board_id_named(APQ8074PRO_AA, "APQ8074PRO-AA") },
- { qcom_board_id_named(APQ8074PRO_AB, "APQ8074PRO-AB") },
- { qcom_board_id_named(APQ8074PRO_AC, "APQ8074PRO-AC") },
- { qcom_board_id_named(MSM8274PRO_AA, "MSM8274PRO-AA") },
- { qcom_board_id_named(MSM8274PRO_AB, "MSM8274PRO-AB") },
- { qcom_board_id_named(MSM8274PRO_AC, "MSM8274PRO-AC") },
- { qcom_board_id_named(MSM8674PRO_AA, "MSM8674PRO-AA") },
- { qcom_board_id_named(MSM8674PRO_AB, "MSM8674PRO-AB") },
- { qcom_board_id_named(MSM8674PRO_AC, "MSM8674PRO-AC") },
- { qcom_board_id_named(MSM8974PRO_AA, "MSM8974PRO-AA") },
- { qcom_board_id_named(MSM8974PRO_AB, "MSM8974PRO-AB") },
- { qcom_board_id(APQ8028) },
- { qcom_board_id(MSM8128) },
- { qcom_board_id(MSM8228) },
- { qcom_board_id(MSM8528) },
- { qcom_board_id(MSM8628) },
- { qcom_board_id(MSM8928) },
- { qcom_board_id(MSM8510) },
- { qcom_board_id(MSM8512) },
- { qcom_board_id(MSM8936) },
- { qcom_board_id(MDM9640) },
- { qcom_board_id(MSM8939) },
- { qcom_board_id(APQ8036) },
- { qcom_board_id(APQ8039) },
- { qcom_board_id(MSM8236) },
- { qcom_board_id(MSM8636) },
- { qcom_board_id(MSM8909) },
- { qcom_board_id(MSM8996) },
- { qcom_board_id(APQ8016) },
- { qcom_board_id(MSM8216) },
- { qcom_board_id(MSM8116) },
- { qcom_board_id(MSM8616) },
- { qcom_board_id(MSM8992) },
- { qcom_board_id(APQ8092) },
- { qcom_board_id(APQ8094) },
- { qcom_board_id(MSM8209) },
- { qcom_board_id(MSM8208) },
- { qcom_board_id(MDM9209) },
- { qcom_board_id(MDM9309) },
- { qcom_board_id(MDM9609) },
- { qcom_board_id(MSM8239) },
- { qcom_board_id(MSM8952) },
- { qcom_board_id(APQ8009) },
- { qcom_board_id(MSM8956) },
- { qcom_board_id(MSM8929) },
- { qcom_board_id(MSM8629) },
- { qcom_board_id(MSM8229) },
- { qcom_board_id(APQ8029) },
- { qcom_board_id(APQ8056) },
- { qcom_board_id(MSM8609) },
- { qcom_board_id(APQ8076) },
- { qcom_board_id(MSM8976) },
- { qcom_board_id(IPQ8065) },
- { qcom_board_id(IPQ8069) },
- { qcom_board_id(MDM9650) },
- { qcom_board_id(MDM9655) },
- { qcom_board_id(MDM9250) },
- { qcom_board_id(MDM9255) },
- { qcom_board_id(MDM9350) },
- { qcom_board_id(APQ8052) },
- { qcom_board_id(MDM9607) },
- { qcom_board_id(APQ8096) },
- { qcom_board_id(MSM8998) },
- { qcom_board_id(MSM8953) },
- { qcom_board_id(MSM8937) },
- { qcom_board_id(APQ8037) },
- { qcom_board_id(MDM8207) },
- { qcom_board_id(MDM9207) },
- { qcom_board_id(MDM9307) },
- { qcom_board_id(MDM9628) },
- { qcom_board_id(MSM8909W) },
- { qcom_board_id(APQ8009W) },
- { qcom_board_id(MSM8996L) },
- { qcom_board_id(MSM8917) },
- { qcom_board_id(APQ8053) },
- { qcom_board_id(MSM8996SG) },
- { qcom_board_id(APQ8017) },
- { qcom_board_id(MSM8217) },
- { qcom_board_id(MSM8617) },
- { qcom_board_id(MSM8996AU) },
- { qcom_board_id(APQ8096AU) },
- { qcom_board_id(APQ8096SG) },
- { qcom_board_id(MSM8940) },
- { qcom_board_id(SDX201) },
- { qcom_board_id(SDM660) },
- { qcom_board_id(SDM630) },
- { qcom_board_id(APQ8098) },
- { qcom_board_id(MSM8920) },
- { qcom_board_id(SDM845) },
- { qcom_board_id(MDM9206) },
- { qcom_board_id(IPQ8074) },
- { qcom_board_id(SDA660) },
- { qcom_board_id(SDM658) },
- { qcom_board_id(SDA658) },
- { qcom_board_id(SDA630) },
- { qcom_board_id(MSM8905) },
- { qcom_board_id(SDX202) },
- { qcom_board_id(SDM670) },
- { qcom_board_id(SDM450) },
- { qcom_board_id(SM8150) },
- { qcom_board_id(SDA845) },
- { qcom_board_id(IPQ8072) },
- { qcom_board_id(IPQ8076) },
- { qcom_board_id(IPQ8078) },
- { qcom_board_id(SDM636) },
- { qcom_board_id(SDA636) },
- { qcom_board_id(SDM632) },
- { qcom_board_id(SDA632) },
- { qcom_board_id(SDA450) },
- { qcom_board_id(SDM439) },
- { qcom_board_id(SDM429) },
- { qcom_board_id(SM8250) },
- { qcom_board_id(SA8155) },
- { qcom_board_id(SDA439) },
- { qcom_board_id(SDA429) },
- { qcom_board_id(SM7150) },
- { qcom_board_id(SM7150P) },
- { qcom_board_id(IPQ8070) },
- { qcom_board_id(IPQ8071) },
- { qcom_board_id(QM215) },
- { qcom_board_id(IPQ8072A) },
- { qcom_board_id(IPQ8074A) },
- { qcom_board_id(IPQ8076A) },
- { qcom_board_id(IPQ8078A) },
- { qcom_board_id(SM6125) },
- { qcom_board_id(IPQ8070A) },
- { qcom_board_id(IPQ8071A) },
- { qcom_board_id(IPQ8172) },
- { qcom_board_id(IPQ8173) },
- { qcom_board_id(IPQ8174) },
- { qcom_board_id(IPQ6018) },
- { qcom_board_id(IPQ6028) },
- { qcom_board_id(SDM429W) },
- { qcom_board_id(SM4250) },
- { qcom_board_id(IPQ6000) },
- { qcom_board_id(IPQ6010) },
- { qcom_board_id(SC7180) },
- { qcom_board_id(SM6350) },
- { qcom_board_id(QCM2150) },
- { qcom_board_id(SDA429W) },
- { qcom_board_id(SM8350) },
- { qcom_board_id(QCM2290) },
- { qcom_board_id(SM7125) },
- { qcom_board_id(SM6115) },
- { qcom_board_id(IPQ5010) },
- { qcom_board_id(IPQ5018) },
- { qcom_board_id(IPQ5028) },
- { qcom_board_id(SC8280XP) },
- { qcom_board_id(IPQ6005) },
- { qcom_board_id(QRB5165) },
- { qcom_board_id(SM8450) },
- { qcom_board_id(SM7225) },
- { qcom_board_id(SA8295P) },
- { qcom_board_id(SA8540P) },
- { qcom_board_id(QCM4290) },
- { qcom_board_id(QCS4290) },
- { qcom_board_id(SM7325) },
- { qcom_board_id_named(SM8450_2, "SM8450") },
- { qcom_board_id_named(SM8450_3, "SM8450") },
- { qcom_board_id(SC7280) },
- { qcom_board_id(SC7180P) },
- { qcom_board_id(QCM6490) },
- { qcom_board_id(QCS6490) },
- { qcom_board_id(SM7325P) },
- { qcom_board_id(IPQ5000) },
- { qcom_board_id(IPQ0509) },
- { qcom_board_id(IPQ0518) },
- { qcom_board_id(SM6375) },
- { qcom_board_id(IPQ9514) },
- { qcom_board_id(IPQ9550) },
- { qcom_board_id(IPQ9554) },
- { qcom_board_id(IPQ9570) },
- { qcom_board_id(IPQ9574) },
- { qcom_board_id(SM8550) },
- { qcom_board_id(IPQ5016) },
- { qcom_board_id(IPQ9510) },
- { qcom_board_id(QRB4210) },
- { qcom_board_id(QRB2210) },
- { qcom_board_id(SAR2130P) },
- { qcom_board_id(SM8475) },
- { qcom_board_id(SM8475P) },
- { qcom_board_id(SA8255P) },
- { qcom_board_id(SA8775P) },
- { qcom_board_id(QRU1000) },
- { qcom_board_id(SM8475_2) },
- { qcom_board_id(QDU1000) },
- { qcom_board_id(X1E80100) },
- { qcom_board_id(SM8650) },
- { qcom_board_id(SM4450) },
- { qcom_board_id(SAR1130P) },
- { qcom_board_id(QDU1010) },
- { qcom_board_id(QRU1032) },
- { qcom_board_id(QRU1052) },
- { qcom_board_id(QRU1062) },
- { qcom_board_id(IPQ5332) },
- { qcom_board_id(IPQ5322) },
- { qcom_board_id(IPQ5312) },
- { qcom_board_id(IPQ5302) },
- { qcom_board_id(QCS8550) },
- { qcom_board_id(QCM8550) },
- { qcom_board_id(SM8750) },
- { qcom_board_id(IPQ5300) },
- { qcom_board_id(SM7635) },
- { qcom_board_id(SM6650) },
- { qcom_board_id(SM6650P) },
- { qcom_board_id(IPQ5321) },
- { qcom_board_id(IPQ5424) },
- { qcom_board_id(QCM6690) },
- { qcom_board_id(QCS6690) },
- { qcom_board_id(SM8850) },
- { qcom_board_id(IPQ5404) },
- { qcom_board_id(QCS9100) },
- { qcom_board_id(QCS8300) },
- { qcom_board_id(QCS8275) },
- { qcom_board_id(QCS9075) },
- { qcom_board_id(QCS615) },
-};
-
-static const char *socinfo_machine(struct device *dev, unsigned int id)
-{
- int idx;
-
- for (idx = 0; idx < ARRAY_SIZE(soc_id); idx++) {
- if (soc_id[idx].id == id)
- return soc_id[idx].name;
- }
-
- return NULL;
-}
-
-#ifdef CONFIG_DEBUG_FS
-
-#define QCOM_OPEN(name, _func) \
-static int qcom_open_##name(struct inode *inode, struct file *file) \
-{ \
- return single_open(file, _func, inode->i_private); \
-} \
- \
-static const struct file_operations qcom_ ##name## _ops = { \
- .open = qcom_open_##name, \
- .read = seq_read, \
- .llseek = seq_lseek, \
- .release = single_release, \
-}
-
-#define DEBUGFS_ADD(info, name) \
- debugfs_create_file(__stringify(name), 0444, \
- qcom_socinfo->dbg_root, \
- info, &qcom_ ##name## _ops)
-
-
-static int qcom_show_build_id(struct seq_file *seq, void *p)
-{
- struct socinfo *socinfo = seq->private;
-
- seq_printf(seq, "%s\n", socinfo->build_id);
-
- return 0;
-}
-
-static int qcom_show_pmic_model(struct seq_file *seq, void *p)
-{
- struct socinfo *socinfo = seq->private;
- int model = SOCINFO_MINOR(le32_to_cpu(socinfo->pmic_model));
-
- if (model < 0)
- return -EINVAL;
-
- if (model < ARRAY_SIZE(pmic_models) && pmic_models[model])
- seq_printf(seq, "%s\n", pmic_models[model]);
- else
- seq_printf(seq, "unknown (%d)\n", model);
-
- return 0;
-}
-
-static int qcom_show_pmic_model_array(struct seq_file *seq, void *p)
-{
- struct socinfo *socinfo = seq->private;
- unsigned int num_pmics = le32_to_cpu(socinfo->num_pmics);
- unsigned int pmic_array_offset = le32_to_cpu(socinfo->pmic_array_offset);
- int i;
- void *ptr = socinfo;
-
- ptr += pmic_array_offset;
-
- /* No need for bounds checking, it happened at socinfo_debugfs_init */
- for (i = 0; i < num_pmics; i++) {
- unsigned int model = SOCINFO_MINOR(get_unaligned_le32(ptr + 2 * i * sizeof(u32)));
- unsigned int die_rev = get_unaligned_le32(ptr + (2 * i + 1) * sizeof(u32));
-
- if (model < ARRAY_SIZE(pmic_models) && pmic_models[model])
- seq_printf(seq, "%s %u.%u\n", pmic_models[model],
- SOCINFO_MAJOR(die_rev),
- SOCINFO_MINOR(die_rev));
- else
- seq_printf(seq, "unknown (%d)\n", model);
- }
-
- return 0;
-}
-
-static int qcom_show_pmic_die_revision(struct seq_file *seq, void *p)
-{
- struct socinfo *socinfo = seq->private;
-
- seq_printf(seq, "%u.%u\n",
- SOCINFO_MAJOR(le32_to_cpu(socinfo->pmic_die_rev)),
- SOCINFO_MINOR(le32_to_cpu(socinfo->pmic_die_rev)));
-
- return 0;
-}
-
-static int qcom_show_chip_id(struct seq_file *seq, void *p)
-{
- struct socinfo *socinfo = seq->private;
-
- seq_printf(seq, "%s\n", socinfo->chip_id);
-
- return 0;
-}
-
-QCOM_OPEN(build_id, qcom_show_build_id);
-QCOM_OPEN(pmic_model, qcom_show_pmic_model);
-QCOM_OPEN(pmic_model_array, qcom_show_pmic_model_array);
-QCOM_OPEN(pmic_die_rev, qcom_show_pmic_die_revision);
-QCOM_OPEN(chip_id, qcom_show_chip_id);
-
-#define DEFINE_IMAGE_OPS(type) \
-static int show_image_##type(struct seq_file *seq, void *p) \
-{ \
- struct smem_image_version *image_version = seq->private; \
- if (image_version->type[0] != '\0') \
- seq_printf(seq, "%s\n", image_version->type); \
- return 0; \
-} \
-static int open_image_##type(struct inode *inode, struct file *file) \
-{ \
- return single_open(file, show_image_##type, inode->i_private); \
-} \
- \
-static const struct file_operations qcom_image_##type##_ops = { \
- .open = open_image_##type, \
- .read = seq_read, \
- .llseek = seq_lseek, \
- .release = single_release, \
-}
-
-DEFINE_IMAGE_OPS(name);
-DEFINE_IMAGE_OPS(variant);
-DEFINE_IMAGE_OPS(oem);
-
-static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
- struct socinfo *info, size_t info_size)
-{
- struct smem_image_version *versions;
- struct dentry *dentry;
- size_t size;
- int i, j;
- unsigned int num_pmics;
- unsigned int pmic_array_offset;
-
- qcom_socinfo->dbg_root = debugfs_create_dir("qcom_socinfo", NULL);
-
- qcom_socinfo->info.fmt = __le32_to_cpu(info->fmt);
-
- debugfs_create_x32("info_fmt", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.fmt);
-
- switch (qcom_socinfo->info.fmt) {
- case SOCINFO_VERSION(0, 23):
- case SOCINFO_VERSION(0, 22):
- case SOCINFO_VERSION(0, 21):
- case SOCINFO_VERSION(0, 20):
- qcom_socinfo->info.raw_package_type = __le32_to_cpu(info->raw_package_type);
- debugfs_create_u32("raw_package_type", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.raw_package_type);
- fallthrough;
- case SOCINFO_VERSION(0, 19):
- qcom_socinfo->info.num_func_clusters = __le32_to_cpu(info->num_func_clusters);
- qcom_socinfo->info.boot_cluster = __le32_to_cpu(info->boot_cluster);
- qcom_socinfo->info.boot_core = __le32_to_cpu(info->boot_core);
-
- debugfs_create_u32("num_func_clusters", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.num_func_clusters);
- debugfs_create_u32("boot_cluster", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.boot_cluster);
- debugfs_create_u32("boot_core", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.boot_core);
- fallthrough;
- case SOCINFO_VERSION(0, 18):
- case SOCINFO_VERSION(0, 17):
- qcom_socinfo->info.oem_variant = __le32_to_cpu(info->oem_variant);
- debugfs_create_u32("oem_variant", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.oem_variant);
- fallthrough;
- case SOCINFO_VERSION(0, 16):
- qcom_socinfo->info.feature_code = __le32_to_cpu(info->feature_code);
- qcom_socinfo->info.pcode = __le32_to_cpu(info->pcode);
-
- debugfs_create_u32("feature_code", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.feature_code);
- debugfs_create_u32("pcode", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.pcode);
- fallthrough;
- case SOCINFO_VERSION(0, 15):
- qcom_socinfo->info.nmodem_supported = __le32_to_cpu(info->nmodem_supported);
-
- debugfs_create_u32("nmodem_supported", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.nmodem_supported);
- fallthrough;
- case SOCINFO_VERSION(0, 14):
- qcom_socinfo->info.num_clusters = __le32_to_cpu(info->num_clusters);
- qcom_socinfo->info.ncluster_array_offset = __le32_to_cpu(info->ncluster_array_offset);
- qcom_socinfo->info.num_subset_parts = __le32_to_cpu(info->num_subset_parts);
- qcom_socinfo->info.nsubset_parts_array_offset =
- __le32_to_cpu(info->nsubset_parts_array_offset);
-
- debugfs_create_u32("num_clusters", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.num_clusters);
- debugfs_create_u32("ncluster_array_offset", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.ncluster_array_offset);
- debugfs_create_u32("num_subset_parts", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.num_subset_parts);
- debugfs_create_u32("nsubset_parts_array_offset", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.nsubset_parts_array_offset);
- fallthrough;
- case SOCINFO_VERSION(0, 13):
- qcom_socinfo->info.nproduct_id = __le32_to_cpu(info->nproduct_id);
-
- debugfs_create_u32("nproduct_id", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.nproduct_id);
- DEBUGFS_ADD(info, chip_id);
- fallthrough;
- case SOCINFO_VERSION(0, 12):
- qcom_socinfo->info.chip_family =
- __le32_to_cpu(info->chip_family);
- qcom_socinfo->info.raw_device_family =
- __le32_to_cpu(info->raw_device_family);
- qcom_socinfo->info.raw_device_num =
- __le32_to_cpu(info->raw_device_num);
-
- debugfs_create_x32("chip_family", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.chip_family);
- debugfs_create_x32("raw_device_family", 0444,
- qcom_socinfo->dbg_root,
- &qcom_socinfo->info.raw_device_family);
- debugfs_create_x32("raw_device_number", 0444,
- qcom_socinfo->dbg_root,
- &qcom_socinfo->info.raw_device_num);
- fallthrough;
- case SOCINFO_VERSION(0, 11):
- num_pmics = le32_to_cpu(info->num_pmics);
- pmic_array_offset = le32_to_cpu(info->pmic_array_offset);
- if (pmic_array_offset + 2 * num_pmics * sizeof(u32) <= info_size)
- DEBUGFS_ADD(info, pmic_model_array);
- fallthrough;
- case SOCINFO_VERSION(0, 10):
- case SOCINFO_VERSION(0, 9):
- qcom_socinfo->info.foundry_id = __le32_to_cpu(info->foundry_id);
-
- debugfs_create_u32("foundry_id", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.foundry_id);
- fallthrough;
- case SOCINFO_VERSION(0, 8):
- case SOCINFO_VERSION(0, 7):
- DEBUGFS_ADD(info, pmic_model);
- DEBUGFS_ADD(info, pmic_die_rev);
- fallthrough;
- case SOCINFO_VERSION(0, 6):
- qcom_socinfo->info.hw_plat_subtype =
- __le32_to_cpu(info->hw_plat_subtype);
-
- debugfs_create_u32("hardware_platform_subtype", 0444,
- qcom_socinfo->dbg_root,
- &qcom_socinfo->info.hw_plat_subtype);
- fallthrough;
- case SOCINFO_VERSION(0, 5):
- qcom_socinfo->info.accessory_chip =
- __le32_to_cpu(info->accessory_chip);
-
- debugfs_create_u32("accessory_chip", 0444,
- qcom_socinfo->dbg_root,
- &qcom_socinfo->info.accessory_chip);
- fallthrough;
- case SOCINFO_VERSION(0, 4):
- qcom_socinfo->info.plat_ver = __le32_to_cpu(info->plat_ver);
-
- debugfs_create_u32("platform_version", 0444,
- qcom_socinfo->dbg_root,
- &qcom_socinfo->info.plat_ver);
- fallthrough;
- case SOCINFO_VERSION(0, 3):
- qcom_socinfo->info.hw_plat = __le32_to_cpu(info->hw_plat);
-
- debugfs_create_u32("hardware_platform", 0444,
- qcom_socinfo->dbg_root,
- &qcom_socinfo->info.hw_plat);
- fallthrough;
- case SOCINFO_VERSION(0, 2):
- qcom_socinfo->info.raw_ver = __le32_to_cpu(info->raw_ver);
-
- debugfs_create_u32("raw_version", 0444, qcom_socinfo->dbg_root,
- &qcom_socinfo->info.raw_ver);
- fallthrough;
- case SOCINFO_VERSION(0, 1):
- DEBUGFS_ADD(info, build_id);
- break;
- }
-
- for (i = 0, j = 0; i < ARRAY_SIZE(socinfo_image_names); i++, j++) {
- if (!socinfo_image_names[i])
- continue;
-
- if (i == 0) {
- versions = qcom_smem_get(QCOM_SMEM_HOST_ANY,
- SMEM_IMAGE_VERSION_TABLE,
- &size);
- } else if (i == 32) {
- versions = qcom_smem_get(QCOM_SMEM_HOST_ANY,
- SMEM_IMAGE_VERSION_TABLE_2,
- &size);
- if (IS_ERR(versions))
- break;
-
- j = 0;
- }
-
- dentry = debugfs_create_dir(socinfo_image_names[i],
- qcom_socinfo->dbg_root);
- debugfs_create_file("name", 0444, dentry, &versions[j],
- &qcom_image_name_ops);
- debugfs_create_file("variant", 0444, dentry, &versions[j],
- &qcom_image_variant_ops);
- debugfs_create_file("oem", 0444, dentry, &versions[j],
- &qcom_image_oem_ops);
- }
-}
-
-static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo)
-{
- debugfs_remove_recursive(qcom_socinfo->dbg_root);
-}
-#else
-static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
- struct socinfo *info, size_t info_size)
-{
-}
-static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo) { }
-#endif /* CONFIG_DEBUG_FS */
-
-static int qcom_socinfo_probe(struct platform_device *pdev)
-{
- struct qcom_socinfo *qs;
- struct socinfo *info;
- size_t item_size;
-
- info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID,
- &item_size);
- if (IS_ERR(info)) {
- dev_err(&pdev->dev, "Couldn't find socinfo\n");
- return PTR_ERR(info);
- }
-
- qs = devm_kzalloc(&pdev->dev, sizeof(*qs), GFP_KERNEL);
- if (!qs)
- return -ENOMEM;
-
- qs->attr.family = "Snapdragon";
- qs->attr.machine = socinfo_machine(&pdev->dev,
- le32_to_cpu(info->id));
- qs->attr.soc_id = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u",
- le32_to_cpu(info->id));
- qs->attr.revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u.%u",
- SOCINFO_MAJOR(le32_to_cpu(info->ver)),
- SOCINFO_MINOR(le32_to_cpu(info->ver)));
- if (!qs->attr.soc_id || !qs->attr.revision)
- return -ENOMEM;
-
- if (offsetofend(struct socinfo, serial_num) <= item_size) {
- qs->attr.serial_number = devm_kasprintf(&pdev->dev, GFP_KERNEL,
- "%u",
- le32_to_cpu(info->serial_num));
- if (!qs->attr.serial_number)
- return -ENOMEM;
- }
-
- qs->soc_dev = soc_device_register(&qs->attr);
- if (IS_ERR(qs->soc_dev))
- return PTR_ERR(qs->soc_dev);
-
- socinfo_debugfs_init(qs, info, item_size);
-
- /* Feed the soc specific unique data into entropy pool */
- add_device_randomness(info, item_size);
-
- platform_set_drvdata(pdev, qs);
-
- return 0;
-}
-
-static void qcom_socinfo_remove(struct platform_device *pdev)
-{
- struct qcom_socinfo *qs = platform_get_drvdata(pdev);
-
- soc_device_unregister(qs->soc_dev);
-
- socinfo_debugfs_exit(qs);
-}
-
-static struct platform_driver qcom_socinfo_driver = {
- .probe = qcom_socinfo_probe,
- .remove = qcom_socinfo_remove,
- .driver = {
- .name = "qcom-socinfo",
- },
-};
-
-module_platform_driver(qcom_socinfo_driver);
-
-MODULE_DESCRIPTION("Qualcomm SoCinfo driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:qcom-socinfo");
diff --git a/drivers/soc/qcom/socinfo/Makefile b/drivers/soc/qcom/socinfo/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8cdd77f46a22aeb97bcf1eeb90418db8f6352d3b
--- /dev/null
+++ b/drivers/soc/qcom/socinfo/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
diff --git a/drivers/soc/qcom/socinfo/bindings.rs b/drivers/soc/qcom/socinfo/bindings.rs
new file mode 100644
index 0000000000000000000000000000000000000000..243fd2adf26ccf417166a08465b2b791030a2364
--- /dev/null
+++ b/drivers/soc/qcom/socinfo/bindings.rs
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2025 Google LLC.
+
+use kernel::{
+ auxiliary,
+ bindings,
+ device::{
+ Bound,
+ Device, //
+ },
+ error::from_err_ptr,
+ ffi::c_char,
+ io::{
+ Io,
+ Mmio,
+ MmioRaw, //
+ },
+ macros::{
+ AsBytes,
+ FromBytes, //
+ },
+ prelude::*,
+ transmute::AsBytes,
+ types::ARef, //
+};
+
+// INVARIANT: raw is a region or subregion returned by get_smem_aux when presented with
+// the auxdev in dev.
+pub(crate) struct Smem {
+ dev: ARef<Device>,
+ raw: MmioRaw,
+}
+
+impl Smem {
+ pub(crate) fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Option<&'a Mmio> {
+ if *dev != *self.dev {
+ return None;
+ }
+
+ // SAFETY: By our invariant, this was a subrange of what was returned by smem_aux_get, for
+ // self.dev, and by our above check, that auxdev is still available.
+ Some(unsafe { Mmio::from_raw(&self.raw) })
+ }
+
+ pub(crate) fn subrange(&self, offset: usize, len: usize) -> Option<Self> {
+ let remaining_len: usize = self.raw.maxsize().checked_sub(offset)?;
+ remaining_len.checked_sub(len)?;
+ // INVARIANT: Maintained because offset is positive, and the length fits.
+ Some(Self {
+ dev: self.dev.clone(),
+ raw: MmioRaw::new(self.raw.addr() + offset, len).ok()?,
+ })
+ }
+
+ pub(crate) fn maxsize(&self) -> usize {
+ self.raw.maxsize()
+ }
+
+ pub(crate) fn get(dev: &auxiliary::Device<Bound>, host: i32, item: u32) -> Result<Self> {
+ let mut size = 0;
+ // SAFETY: qcom_smem_get_aux only requires that the size pointer be a writable size_t,
+ // and that aux be an aux device.
+ let err_ptr =
+ unsafe { bindings::qcom_smem_get_aux(dev.as_raw(), host as u32, item, &mut size) };
+ let ptr = from_err_ptr(err_ptr)?;
+ let base_dev: &Device<Bound> = dev.as_ref();
+ // INVARIANT: If qcom_smem_get_aux does not return an error, the returned pointer points to
+ // a readable IO region that qcom-smem will keep mapped while our provided aux device is
+ // loaded.
+ Ok(Self {
+ dev: base_dev.into(),
+ raw: MmioRaw::new(ptr as usize, size)?,
+ })
+ }
+}
+
+pub(crate) const SMEM_IMAGE_VERSION_TABLE: u32 = 469;
+pub(crate) const SMEM_IMAGE_VERSION_TABLE_2: u32 = 667;
+
+pub(crate) use bindings::socinfo;
+
+/// Produce `socinfo` by initializing from a byte buffer that may be too small.
+/// Code using the resulting value is expected to use the info_fmt field to determine
+/// which fields have meaningful values.
+pub(crate) fn socinfo_from_partial_bytes(soc_info_mem: &Mmio) -> Result<socinfo> {
+ let mut soc_info = socinfo::default();
+ let byte_view: &mut [u8] = soc_info.as_bytes_mut();
+ let len = core::cmp::min(soc_info_mem.maxsize(), byte_view.len());
+ soc_info_mem.try_copy_to(&mut byte_view[..len], 0)?;
+ Ok(soc_info)
+}
+
+#[derive(AsBytes, FromBytes, Default, Copy, Clone)]
+#[repr(C)]
+pub(crate) struct PmicEntry {
+ pub(crate) model: u32,
+ pub(crate) die_rev: u32,
+}
+
+const SMEM_IMAGE_VERSION_NAME_SIZE: usize = 75;
+const SMEM_IMAGE_VERSION_VARIANT_SIZE: usize = 20;
+const SMEM_IMAGE_VERSION_OEM_SIZE: usize = 32;
+
+#[derive(AsBytes, FromBytes)]
+#[repr(C)]
+pub(crate) struct ImageVersion {
+ pub(crate) name: [c_char; SMEM_IMAGE_VERSION_NAME_SIZE],
+ pub(crate) variant: [c_char; SMEM_IMAGE_VERSION_VARIANT_SIZE],
+ pub(crate) pad: c_char,
+ pub(crate) oem: [c_char; SMEM_IMAGE_VERSION_OEM_SIZE],
+}
+
+impl Default for ImageVersion {
+ fn default() -> Self {
+ ImageVersion {
+ name: [0; SMEM_IMAGE_VERSION_NAME_SIZE],
+ variant: [0; SMEM_IMAGE_VERSION_VARIANT_SIZE],
+ pad: 0,
+ oem: [0; SMEM_IMAGE_VERSION_OEM_SIZE],
+ }
+ }
+}
diff --git a/drivers/soc/qcom/socinfo/data.rs b/drivers/soc/qcom/socinfo/data.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e33e040ae34ddfd2acd1e1e64f5e35cc78e85483
--- /dev/null
+++ b/drivers/soc/qcom/socinfo/data.rs
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2025 Google LLC.
+
+//! Data tables for QCom SocInfo driver
+use kernel::{
+ c_str,
+ prelude::*,
+ sparse_array, //
+};
+
+macro_rules! soc_ids {
+ { $( $entry:tt ),* $(,)? } => {
+ pub(crate) static SOC_IDS: &[SocId] = &[
+ $(
+ soc_id_entry!($entry)
+ ),*
+ ];
+ }
+}
+
+macro_rules! soc_id_entry {
+ ($id:ident) => {
+ kernel::macros::paste! {
+ SocId {
+ id: kernel::bindings::[<QCOM_ID_ $id>],
+ name: c_str!(stringify!($id)),
+ }
+ }
+ };
+ (($id:ident, $name:literal)) => {
+ kernel::macros::paste! {
+ SocId {
+ id: kernel::bindings::[<QCOM_ID_ $id>],
+ name: c_str!($name),
+ }
+ }
+ };
+}
+
+pub(crate) struct SocId {
+ pub(crate) id: u32,
+ pub(crate) name: &'static CStr,
+}
+
+soc_ids! {
+ MSM8260,
+ MSM8660,
+ APQ8060,
+ MSM8960,
+ APQ8064,
+ MSM8930,
+ MSM8630,
+ MSM8230,
+ APQ8030,
+ MSM8627,
+ MSM8227,
+ MSM8660A,
+ MSM8260A,
+ APQ8060A,
+ MSM8974,
+ MSM8225,
+ MSM8625,
+ MPQ8064,
+ MSM8960AB,
+ APQ8060AB,
+ MSM8260AB,
+ MSM8660AB,
+ MSM8930AA,
+ MSM8630AA,
+ MSM8230AA,
+ MSM8626,
+ MSM8610,
+ APQ8064AB,
+ MSM8930AB,
+ MSM8630AB,
+ MSM8230AB,
+ APQ8030AB,
+ MSM8226,
+ MSM8526,
+ APQ8030AA,
+ MSM8110,
+ MSM8210,
+ MSM8810,
+ MSM8212,
+ MSM8612,
+ MSM8112,
+ MSM8125,
+ MSM8225Q,
+ MSM8625Q,
+ MSM8125Q,
+ APQ8064AA,
+ APQ8084,
+ MSM8130,
+ MSM8130AA,
+ MSM8130AB,
+ MSM8627AA,
+ MSM8227AA,
+ APQ8074,
+ MSM8274,
+ MSM8674,
+ MDM9635,
+ (MSM8974PRO_AC, "MSM8974PRO-AC"),
+ MSM8126,
+ APQ8026,
+ MSM8926,
+ IPQ8062,
+ IPQ8064,
+ IPQ8066,
+ IPQ8068,
+ MSM8326,
+ MSM8916,
+ MSM8994,
+ (APQ8074PRO_AA, "APQ8074PRO-AA"),
+ (APQ8074PRO_AB, "APQ8074PRO-AB"),
+ (APQ8074PRO_AC, "APQ8074PRO-AC"),
+ (MSM8274PRO_AA, "MSM8274PRO-AA"),
+ (MSM8274PRO_AB, "MSM8274PRO-AB"),
+ (MSM8274PRO_AC, "MSM8274PRO-AC"),
+ (MSM8674PRO_AA, "MSM8674PRO-AA"),
+ (MSM8674PRO_AB, "MSM8674PRO-AB"),
+ (MSM8674PRO_AC, "MSM8674PRO-AC"),
+ (MSM8974PRO_AA, "MSM8974PRO-AA"),
+ (MSM8974PRO_AB, "MSM8974PRO-AB"),
+ APQ8028,
+ MSM8128,
+ MSM8228,
+ MSM8528,
+ MSM8628,
+ MSM8928,
+ MSM8510,
+ MSM8512,
+ MSM8936,
+ MDM9640,
+ MSM8939,
+ APQ8036,
+ APQ8039,
+ MSM8236,
+ MSM8636,
+ MSM8909,
+ MSM8996,
+ APQ8016,
+ MSM8216,
+ MSM8116,
+ MSM8616,
+ MSM8992,
+ APQ8092,
+ APQ8094,
+ MSM8209,
+ MSM8208,
+ MDM9209,
+ MDM9309,
+ MDM9609,
+ MSM8239,
+ MSM8952,
+ APQ8009,
+ MSM8956,
+ MSM8929,
+ MSM8629,
+ MSM8229,
+ APQ8029,
+ APQ8056,
+ MSM8609,
+ APQ8076,
+ MSM8976,
+ IPQ8065,
+ IPQ8069,
+ MDM9650,
+ MDM9655,
+ MDM9250,
+ MDM9255,
+ MDM9350,
+ APQ8052,
+ MDM9607,
+ APQ8096,
+ MSM8998,
+ MSM8953,
+ MSM8937,
+ APQ8037,
+ MDM8207,
+ MDM9207,
+ MDM9307,
+ MDM9628,
+ MSM8909W,
+ APQ8009W,
+ MSM8996L,
+ MSM8917,
+ APQ8053,
+ MSM8996SG,
+ APQ8017,
+ MSM8217,
+ MSM8617,
+ MSM8996AU,
+ APQ8096AU,
+ APQ8096SG,
+ MSM8940,
+ SDX201,
+ SDM660,
+ SDM630,
+ APQ8098,
+ MSM8920,
+ SDM845,
+ MDM9206,
+ IPQ8074,
+ SDA660,
+ SDM658,
+ SDA658,
+ SDA630,
+ MSM8905,
+ SDX202,
+ SDM670,
+ SDM450,
+ SM8150,
+ SDA845,
+ IPQ8072,
+ IPQ8076,
+ IPQ8078,
+ SDM636,
+ SDA636,
+ SDM632,
+ SDA632,
+ SDA450,
+ SDM439,
+ SDM429,
+ SM8250,
+ SA8155,
+ SDA439,
+ SDA429,
+ SM7150,
+ SM7150P,
+ IPQ8070,
+ IPQ8071,
+ QM215,
+ IPQ8072A,
+ IPQ8074A,
+ IPQ8076A,
+ IPQ8078A,
+ SM6125,
+ IPQ8070A,
+ IPQ8071A,
+ IPQ8172,
+ IPQ8173,
+ IPQ8174,
+ IPQ6018,
+ IPQ6028,
+ SDM429W,
+ SM4250,
+ IPQ6000,
+ IPQ6010,
+ SC7180,
+ SM6350,
+ QCM2150,
+ SDA429W,
+ SM8350,
+ QCM2290,
+ SM7125,
+ SM6115,
+ IPQ5010,
+ IPQ5018,
+ IPQ5028,
+ SC8280XP,
+ IPQ6005,
+ QRB5165,
+ SM8450,
+ SM7225,
+ SA8295P,
+ SA8540P,
+ QCM4290,
+ QCS4290,
+ SM7325,
+ (SM8450_2, "SM8450"),
+ (SM8450_3, "SM8450"),
+ SC7280,
+ SC7180P,
+ QCM6490,
+ QCS6490,
+ SM7325P,
+ IPQ5000,
+ IPQ0509,
+ IPQ0518,
+ SM6375,
+ IPQ9514,
+ IPQ9550,
+ IPQ9554,
+ IPQ9570,
+ IPQ9574,
+ SM8550,
+ IPQ5016,
+ IPQ9510,
+ QRB4210,
+ QRB2210,
+ SAR2130P,
+ SM8475,
+ SM8475P,
+ SA8255P,
+ SA8775P,
+ QRU1000,
+ SM8475_2,
+ QDU1000,
+ X1E80100,
+ SM8650,
+ SM4450,
+ SAR1130P,
+ QDU1010,
+ QRU1032,
+ QRU1052,
+ QRU1062,
+ IPQ5332,
+ IPQ5322,
+ IPQ5312,
+ IPQ5302,
+ QCS8550,
+ QCM8550,
+ SM8750,
+ IPQ5300,
+ SM7635,
+ SM6650,
+ SM6650P,
+ IPQ5321,
+ IPQ5424,
+ QCM6690,
+ QCS6690,
+ SM8850,
+ IPQ5404,
+ QCS9100,
+ QCS8300,
+ QCS8275,
+ QCS9075,
+ QCS615,
+}
+
+pub(crate) const PMIC_MODELS: &[Option<&str>] = &sparse_array! {
+ 0: "Unknown PMIC model",
+ 1: "PM8941",
+ 2: "PM8841",
+ 3: "PM8019",
+ 4: "PM8226",
+ 5: "PM8110",
+ 6: "PMA8084",
+ 7: "PMI8962",
+ 8: "PMD9635",
+ 9: "PM8994",
+ 10: "PMI8994",
+ 11: "PM8916",
+ 12: "PM8004",
+ 13: "PM8909/PM8058",
+ 14: "PM8028",
+ 15: "PM8901",
+ 16: "PM8950/PM8027",
+ 17: "PMI8950/ISL9519",
+ 18: "PMK8001/PM8921",
+ 19: "PMI8996/PM8018",
+ 20: "PM8998/PM8015",
+ 21: "PMI8998/PM8014",
+ 22: "PM8821",
+ 23: "PM8038",
+ 24: "PM8005/PM8922",
+ 25: "PM8917/PM8937",
+ 26: "PM660L",
+ 27: "PM660",
+ 30: "PM8150",
+ 31: "PM8150L",
+ 32: "PM8150B",
+ 33: "PMK8002",
+ 36: "PM8009",
+ 37: "PMI632",
+ 38: "PM8150C",
+ 40: "PM6150",
+ 41: "SMB2351",
+ 44: "PM8008",
+ 45: "PM6125",
+ 46: "PM7250B",
+ 47: "PMK8350",
+ 48: "PM8350",
+ 49: "PM8350C",
+ 50: "PM8350B",
+ 51: "PMR735A",
+ 52: "PMR735B",
+ 54: "PM6350",
+ 55: "PM4125",
+ 58: "PM8450",
+ 65: "PM8010",
+ 69: "PM8550VS",
+ 70: "PM8550VE",
+ 71: "PM8550B",
+ 72: "PMR735D",
+ 73: "PM8550",
+ 74: "PMK8550",
+ 78: "PMM8650AU",
+ 79: "PMM8650AU_PSAIL",
+ 80: "PM7550",
+ 82: "PMC8380",
+ 83: "SMB2360",
+ 91: "PMIV0108"
+};
+
+pub(crate) const IMAGE_NAMES: &[&CStr] = &[
+ c"boot",
+ c"tz",
+ c"tzsecapp",
+ c"rpm",
+ c"sdi",
+ c"hyp",
+ c"adsp1",
+ c"adsp2",
+ c"cdsp2",
+ c"appsbl",
+ c"apps",
+ c"mpss",
+ c"adsp",
+ c"cnss",
+ c"video",
+ c"dsps",
+ c"cdsp",
+ c"npu",
+ c"wpss",
+ c"cdsp1",
+ c"gpdsp",
+ c"gpdsp1",
+ c"sensorpd",
+ c"audiopd",
+ c"oempd",
+ c"chargerpd",
+ c"oispd",
+ c"soccp",
+ c"tme",
+ c"gearvm",
+ c"uefi",
+ c"cdsp3",
+ c"audiopd",
+ c"audiopd",
+ c"dcp",
+ c"oobs",
+ c"oobns",
+ c"devcfg",
+ c"btpd",
+ c"qecp",
+];
diff --git a/drivers/soc/qcom/socinfo/socinfo.rs b/drivers/soc/qcom/socinfo/socinfo.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c0791b33232eed9aef01c4db9e2031961fca783f
--- /dev/null
+++ b/drivers/soc/qcom/socinfo/socinfo.rs
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2025 Google LLC.
+
+//! socinfo driver for Qualcomm SoCs.
+
+use core::fmt::{
+ self,
+ Formatter, //
+};
+
+use kernel::{
+ auxiliary,
+ c_str,
+ debugfs::{
+ Scope,
+ ScopedDir, //
+ },
+ device::{
+ Bound,
+ Core,
+ Device, //
+ },
+ devres::Devres,
+ error,
+ io::{
+ Io,
+ Mmio, //
+ },
+ module_auxiliary_driver,
+ pr_warn,
+ prelude::*,
+ soc,
+ str::{
+ CStr,
+ CStrExt,
+ CString, //
+ },
+ transmute::AsBytes,
+ try_pin_init, //
+};
+use pin_init::pin_init_scope;
+
+mod bindings;
+mod data;
+
+use bindings::*;
+use data::{
+ IMAGE_NAMES,
+ PMIC_MODELS,
+ SOC_IDS, //
+};
+
+module_auxiliary_driver! {
+ type: QcomSocInfo,
+ name: "qcom-socinfo",
+ authors: ["Matthew Maurer"],
+ description: "Qualcomm SoCinfo driver",
+ license: "GPL",
+ alias: ["platform:qcom-socinfo"],
+}
+
+#[pin_data]
+struct QcomSocInfo {
+ #[pin]
+ registration: soc::Registration,
+ #[pin]
+ params: Devres<Scope<Params>>,
+}
+
+fn pmic_name(model: u32) -> Option<&'static str> {
+ let idx = SocInfo::version_split(model).1 as usize;
+ PMIC_MODELS.get(idx).copied().flatten()
+}
+
+fn fmt_pmic_model(model: &u32, f: &mut Formatter<'_>) -> fmt::Result {
+ if let Some(model) = pmic_name(*model) {
+ writeln!(f, "{model}")
+ } else {
+ writeln!(f, "unknown ({})", SocInfo::version_split(*model).1)
+ }
+}
+
+fn fmt_pmic_die_rev(rev: &u32, f: &mut Formatter<'_>) -> fmt::Result {
+ let (major, minor) = SocInfo::version_split(*rev);
+ writeln!(f, "{major}.{minor}")
+}
+
+fn fmt_pmic_model_array(array: &KVec<PmicEntry>, f: &mut Formatter<'_>) -> fmt::Result {
+ for pmic_entry in array {
+ let (die_rev_major, die_rev_minor) =
+ SocInfo::version_split(u32::from_le(pmic_entry.die_rev));
+ if let Some(model) = pmic_name(pmic_entry.model) {
+ writeln!(f, "{model} {die_rev_major}.{die_rev_minor}")?
+ } else {
+ writeln!(f, "unknown ({})", pmic_entry.model)?
+ }
+ }
+ Ok(())
+}
+
+#[derive(Default)]
+struct Params {
+ info_fmt: u32,
+ build_id: [u8; 32],
+ raw_version: Option<u32>,
+ hardware_platform: Option<u32>,
+ platform_version: Option<u32>,
+ accessory_chip: Option<u32>,
+ hardware_platform_subtype: Option<u32>,
+ pmic_model: Option<u32>,
+ pmic_die_rev: Option<u32>,
+ foundry_id: Option<u32>,
+ pmic_model_array: Option<KVec<PmicEntry>>,
+ chip_family: Option<u32>,
+ raw_device_family: Option<u32>,
+ raw_device_number: Option<u32>,
+ nproduct_id: Option<u32>,
+ chip_id: Option<[u8; 32]>,
+ num_clusters: Option<u32>,
+ ncluster_array_offset: Option<u32>,
+ num_subset_parts: Option<u32>,
+ nsubset_parts_array_offset: Option<u32>,
+ nmodem_supported: Option<u32>,
+ feature_code: Option<u32>,
+ pcode: Option<u32>,
+ oem_variant: Option<u32>,
+ boot_core: Option<u32>,
+ boot_cluster: Option<u32>,
+ num_func_clusters: Option<u32>,
+ raw_package_type: Option<u32>,
+ versions: KVec<Smem>,
+}
+
+struct SocInfo {
+ soc_info: socinfo,
+ soc_info_mem: Smem,
+ version_mem: Smem,
+ version_mem2: Option<Smem>,
+}
+
+impl SocInfo {
+ fn from_mem(
+ soc_info_mem: Smem,
+ version_mem: Smem,
+ version_mem2: Option<Smem>,
+ dev: &Device<Bound>,
+ ) -> Result<Self> {
+ Ok(Self {
+ soc_info: socinfo_from_partial_bytes(
+ soc_info_mem.access(dev).ok_or(error::code::EINVAL)?,
+ )?,
+ soc_info_mem,
+ version_mem,
+ version_mem2,
+ })
+ }
+ fn id(&self) -> u32 {
+ u32::from_le(self.soc_info.id)
+ }
+ fn version_split(ver: u32) -> (u16, u16) {
+ let major = (ver >> 16) as u16;
+ let minor = (ver & 0xFFFF) as u16;
+ (major, minor)
+ }
+ fn version_fuse(major: u16, minor: u16) -> u32 {
+ (u32::from(major) << 16) | u32::from(minor)
+ }
+ fn version(&self) -> (u16, u16) {
+ Self::version_split(self.soc_info.ver)
+ }
+ fn serial(&self) -> u32 {
+ u32::from_le(self.soc_info.serial_num)
+ }
+ fn machine(&self) -> Result<Option<CString>> {
+ for soc in SOC_IDS {
+ if soc.id == self.id() {
+ return Ok(Some(soc.name.to_cstring()?));
+ }
+ }
+ Ok(None)
+ }
+ fn soc_attributes(&self) -> Result<soc::Attributes> {
+ Ok(soc::Attributes {
+ family: Some(c_str!("Snapdragon").to_cstring()?),
+ machine: self.machine()?,
+ revision: Some(CString::try_from_fmt(fmt!(
+ "{}.{}",
+ self.version().0,
+ self.version().1
+ ))?),
+ serial_number: Some(CString::try_from_fmt(fmt!("{}", self.serial()))?),
+ soc_id: Some(CString::try_from_fmt(fmt!("{}", self.id()))?),
+ })
+ }
+}
+
+macro_rules! u32_le_versioned {
+ { $params:expr, $self:ident,
+ [ $( { $major:expr, $minor:expr, { $( $dst:ident: $src:ident ),* } } ),* ] } => {$(
+ if $params.info_fmt >= SocInfo::version_fuse($major, $minor) {
+ $( $params.$dst = Some(u32::from_le($self.soc_info.$src).into()) );*
+ }
+ )*}
+}
+
+impl SocInfo {
+ fn build_params(self, dev: &Device<Bound>) -> Result<Params> {
+ let mut params = Params {
+ build_id: self.soc_info.build_id,
+ info_fmt: u32::from_le(self.soc_info.fmt),
+ ..Default::default()
+ };
+ u32_le_versioned! { params, self, [
+ {0, 2, { raw_version: raw_ver }},
+ {0, 3, { hardware_platform: hw_plat }},
+ {0, 4, { platform_version: plat_ver }},
+ {0, 5, { accessory_chip: accessory_chip }},
+ {0, 6, { hardware_platform_subtype: hw_plat_subtype }},
+ {0, 7, { pmic_model: pmic_model, pmic_die_rev: pmic_die_rev }},
+ {0, 9, { foundry_id: foundry_id }},
+ {0, 12, {
+ chip_family: chip_family,
+ raw_device_family: raw_device_family,
+ raw_device_number: raw_device_num
+ }},
+ {0, 13, { nproduct_id: nproduct_id }},
+ {0, 14, {
+ num_clusters: num_clusters,
+ ncluster_array_offset: ncluster_array_offset,
+ num_subset_parts: num_subset_parts,
+ nsubset_parts_array_offset: nsubset_parts_array_offset
+ }},
+ {0, 15, { nmodem_supported: nmodem_supported }},
+ {0, 16, { feature_code: feature_code, pcode: pcode }},
+ {0, 17, { oem_variant: oem_variant }},
+ {0, 19, {
+ boot_core: boot_core,
+ boot_cluster: boot_cluster,
+ num_func_clusters: num_func_clusters
+ }},
+ {0, 20, { raw_package_type: raw_package_type }}
+ ]};
+ if params.info_fmt >= SocInfo::version_fuse(0, 11) {
+ let offset = u32::from_le(self.soc_info.pmic_array_offset) as usize;
+ let num_pmics = u32::from_le(self.soc_info.num_pmics) as usize;
+ let mut pmic_model_array =
+ KVec::from_elem(PmicEntry::default(), num_pmics, GFP_KERNEL)?;
+ self.soc_info_mem
+ .access(dev)
+ .ok_or(error::code::EINVAL)?
+ .try_copy_to(pmic_model_array.as_bytes_mut(), offset)?;
+ params.pmic_model_array = Some(pmic_model_array);
+ }
+ if params.info_fmt >= SocInfo::version_fuse(0, 13) {
+ params.chip_id = Some(self.soc_info.chip_id);
+ }
+ load_versions(&mut params.versions, &self.version_mem)?;
+ if let Some(versions) = self.version_mem2.as_ref() {
+ load_versions(&mut params.versions, versions)?;
+ }
+ Ok(params)
+ }
+}
+
+fn load_versions(versions: &mut KVec<Smem>, mem: &Smem) -> Result<()> {
+ const IMAGE_SIZE: usize = core::mem::size_of::<ImageVersion>();
+ for offset in (0..mem.maxsize()).step_by(IMAGE_SIZE) {
+ if let Some(subrange) = mem.subrange(offset, IMAGE_SIZE) {
+ versions.push(subrange, GFP_KERNEL)?;
+ }
+ }
+ Ok(())
+}
+
+macro_rules! value_attrs {
+ ($builder:ident, $params:ident, @) => {};
+ ($builder:ident, $params:ident, @ $s:ident $($rest:tt)*) => {
+ if let Some(v) = $params.$s.as_ref() {
+ $builder.read_only_file(c_str!(stringify!($s)), v);
+ }
+ value_attrs!($builder, $params, @ $($rest)*)
+ };
+ ($builder:ident, $params:ident, @ {$s:ident, $cb:expr} $($rest:tt)*) => {
+ if let Some(v) = $params.$s.as_ref() {
+ $builder.read_callback_file(c_str!(stringify!($s)), v, $cb);
+ }
+ value_attrs!($builder, $params, @ $($rest)*)
+ };
+ ($builder:ident, $params:ident, {$($items:tt),*}) => {
+ value_attrs!($builder, $params, @ $($items)*)
+ };
+}
+
+fn no_quirk<const SIZE: usize>(buf: &[u8; SIZE], f: &mut Formatter<'_>) -> fmt::Result {
+ if buf[0] == 0 {
+ writeln!(f)
+ } else {
+ nul_array(buf, f)
+ }
+}
+
+fn nul_array<const SIZE: usize>(buf: &[u8; SIZE], f: &mut Formatter<'_>) -> fmt::Result {
+ if let Some(end) = buf.iter().position(|x| *x == 0) {
+ if end == 0 {
+ // Match original driver quirk - empty strings don't have a trailing newline
+ return Ok(());
+ }
+ let Ok(c_str) = CStr::from_bytes_with_nul(&buf[0..=end]) else {
+ pr_warn!("Creating CStr from bytes with known first NUL failed?");
+ return Ok(());
+ };
+ let Ok(str) = c_str.to_str() else {
+ pr_warn!("Non-unicode-compatible character in string");
+ return Ok(());
+ };
+ writeln!(f, "{str}")
+ } else {
+ writeln!(f, "Missing NUL: {buf:?}")
+ }
+}
+
+fn build_image_debugfs<'a>(dir: &ScopedDir<'a, '_>, image_name: &CStr, mem: &'a Mmio) {
+ let subdir = dir.dir(image_name);
+ subdir.read_callback_file(c_str!("name"), mem, &debug_name);
+ subdir.read_callback_file(c_str!("variant"), mem, &debug_variant);
+ subdir.read_callback_file(c_str!("oem"), mem, &debug_oem);
+}
+
+fn debug_name(mem: &Mmio, f: &mut Formatter<'_>) -> fmt::Result {
+ let mut iv = ImageVersion::default();
+ mem.try_copy_to(iv.as_bytes_mut(), 0)
+ .map_err(|_| fmt::Error)?;
+ nul_array(&iv.name, f)
+}
+
+fn debug_variant(mem: &Mmio, f: &mut Formatter<'_>) -> fmt::Result {
+ let mut iv = ImageVersion::default();
+ mem.try_copy_to(iv.as_bytes_mut(), 0)
+ .map_err(|_| fmt::Error)?;
+ nul_array(&iv.variant, f)
+}
+
+fn debug_oem(mem: &Mmio, f: &mut Formatter<'_>) -> fmt::Result {
+ let mut iv = ImageVersion::default();
+ mem.try_copy_to(iv.as_bytes_mut(), 0)
+ .map_err(|_| fmt::Error)?;
+ nul_array(&iv.oem, f)
+}
+
+fn hex(x: &u32, f: &mut Formatter<'_>) -> fmt::Result {
+ writeln!(f, "{x:#010x}")
+}
+
+impl Params {
+ fn build_debugfs<'data>(&'data self, dev: &'data Device<Bound>, dir: &ScopedDir<'data, '_>) {
+ dir.read_callback_file(c_str!("info_fmt"), &self.info_fmt, &hex);
+ dir.read_callback_file(c_str!("build_id"), &self.build_id, &no_quirk);
+ value_attrs!(dir, self, {
+ raw_version,
+ hardware_platform,
+ platform_version,
+ accessory_chip,
+ hardware_platform_subtype,
+ {raw_device_number, &hex},
+ {raw_device_family, &hex},
+ {chip_family, &hex},
+ {chip_id, &nul_array},
+ nproduct_id,
+ nsubset_parts_array_offset,
+ num_subset_parts,
+ ncluster_array_offset,
+ num_clusters,
+ nmodem_supported,
+ pcode,
+ feature_code,
+ oem_variant,
+ boot_core,
+ boot_cluster,
+ num_func_clusters,
+ foundry_id,
+ raw_package_type,
+ {pmic_model, &fmt_pmic_model},
+ {pmic_die_rev, &fmt_pmic_die_rev},
+ {pmic_model_array, &fmt_pmic_model_array}
+ });
+ for (version, name) in self.versions.iter().zip(IMAGE_NAMES.iter()) {
+ if let Some(version_mem) = version.access(dev) {
+ build_image_debugfs(dir, name, version_mem);
+ }
+ }
+ }
+}
+
+kernel::auxiliary_device_table! {
+ AUX_TABLE,
+ MODULE_AUX_TABLE,
+ <QcomSocInfo as auxiliary::Driver>::IdInfo,
+ [(auxiliary::DeviceId::new(c_str!("smem"), c_str!("qcom-socinfo")), ())]
+}
+
+impl auxiliary::Driver for QcomSocInfo {
+ type IdInfo = ();
+ const ID_TABLE: auxiliary::IdTable<Self::IdInfo> = &AUX_TABLE;
+ fn probe(dev: &auxiliary::Device<Core>, _id_info: &Self::IdInfo) -> impl PinInit<Self, Error> {
+ pin_init_scope(move || {
+ let soc_info_mem = Smem::get(
+ dev,
+ kernel::bindings::QCOM_SMEM_HOST_ANY,
+ kernel::bindings::SMEM_HW_SW_BUILD_ID,
+ )?;
+ let version_mem = Smem::get(
+ dev,
+ kernel::bindings::QCOM_SMEM_HOST_ANY,
+ bindings::SMEM_IMAGE_VERSION_TABLE,
+ )?;
+ let version_mem2 = Smem::get(
+ dev,
+ kernel::bindings::QCOM_SMEM_HOST_ANY,
+ bindings::SMEM_IMAGE_VERSION_TABLE_2,
+ )
+ .ok();
+ let base_dev = dev.as_ref();
+ let mem = soc_info_mem.access(base_dev).ok_or(error::code::EINVAL)?;
+
+ rand_from_mmio(mem)?;
+
+ let info = SocInfo::from_mem(soc_info_mem, version_mem, version_mem2, base_dev)?;
+ let attributes = info.soc_attributes()?;
+ let backing = info.build_params(base_dev)?;
+
+ Ok(try_pin_init!(Self {
+ registration <- soc::Registration::new(attributes),
+ params <- Devres::dir(base_dev, backing, c_str!("qcom_socinfo"),
+ Params::build_debugfs),
+ }? Error))
+ })
+ }
+}
+
+fn rand_from_mmio(mmio: &Mmio) -> Result<()> {
+ let mut buf: KVec<u8> = KVec::from_elem(0, mmio.maxsize(), GFP_KERNEL)?;
+ mmio.try_copy_to(&mut buf, 0)?;
+ kernel::random::add_device_randomness(&buf);
+ Ok(())
+}
diff --git a/include/linux/soc/qcom/smem.h b/include/linux/soc/qcom/smem.h
index f946e3beca215548ac56dbf779138d05479712f5..1c26f258be1fc1bf34bf3b0112c4a8472e676ed8 100644
--- a/include/linux/soc/qcom/smem.h
+++ b/include/linux/soc/qcom/smem.h
@@ -4,8 +4,12 @@
#define QCOM_SMEM_HOST_ANY -1
+struct auxiliary_device;
+
bool qcom_smem_is_available(void);
int qcom_smem_alloc(unsigned host, unsigned item, size_t size);
+void *qcom_smem_get_aux(struct auxiliary_device *aux, unsigned int host,
+ unsigned int item, size_t *size);
void *qcom_smem_get(unsigned host, unsigned item, size_t *size);
int qcom_smem_get_free_space(unsigned host);
diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters
index d56343ca03979e345f8adb7eb8fd7f2b9d4be6ee..3398a8eff517b71c062fd3e52a4a7895526f64a1 100644
--- a/rust/bindgen_parameters
+++ b/rust/bindgen_parameters
@@ -72,3 +72,4 @@
# We can't auto-derive AsBytes, as we need a const-time check to see if there
# is padding involved. Add it explicitly when you expect no padding.
--with-derive-custom-struct cpumask=AsBytesFfi
+--with-derive-custom-struct socinfo=AsBytesFfi
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 9fdf76ca630e00715503e2a3a809bedc895697fd..b076b847731d97cf345d8ef80df9c315a79c8fab 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -95,6 +95,12 @@
*/
#include <../../drivers/base/base.h>
+#if IS_ENABLED(CONFIG_QCOM_SOCINFO)
+#include <dt-bindings/arm/qcom,ids.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/socinfo.h>
+#endif
+
#if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
// Used by `#[export]` in `drivers/gpu/drm/drm_panic_qr.rs`.
#include <drm/drm_panic.h>
--
2.53.0.rc2.204.g2597b5adb4-goog
Powered by blists - more mailing lists