devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] soc: qcom: Add SoC info driver
@ 2016-10-20 14:06 Imran Khan
       [not found] ` <1476972386-28655-1-git-send-email-kimran-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Imran Khan @ 2016-10-20 14:06 UTC (permalink / raw)
  To: andy.gross
  Cc: Imran Khan, David Brown, Rob Herring, Mark Rutland,
	open list:ARM/QUALCOMM SUPPORT, open list:ARM/QUALCOMM SUPPORT,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list

The SoC info driver provides information such as Chip ID,
Chip family, serial number and other such details about
Qualcomm SoCs.

Signed-off-by: Imran Khan <kimran@codeaurora.org>
---
 .../devicetree/bindings/soc/qcom/qcom,socinfo.txt  |   18 +
 drivers/soc/qcom/socinfo.c                         | 1173 ++++++++++++++++++++
 include/linux/soc/qcom/socinfo.h                   |  198 ++++
 3 files changed, 1389 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,socinfo.txt
 create mode 100644 drivers/soc/qcom/socinfo.c
 create mode 100644 include/linux/soc/qcom/socinfo.h

diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,socinfo.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,socinfo.txt
new file mode 100644
index 0000000..1f26299
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,socinfo.txt
@@ -0,0 +1,18 @@
+Qualcomm SoC Information (socinfo) Driver binding
+
+This binding describes the Qualcomm SoC Information Driver, which provides
+information such as chip id, chip family, serial number and other such
+details about Qualcomm SoCs.
+
+- compatible:
+	Usage: required
+	Value type: <stringlist>
+	Definition: must be "qcom,socinfo"
+
+= EXAMPLE
+
+The following example represents a socinfo node.
+
+	socinfo {
+		compatible = "qcom,socinfo";
+	};
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
new file mode 100644
index 0000000..dc26028
--- /dev/null
+++ b/drivers/soc/qcom/socinfo.c
@@ -0,0 +1,1173 @@
+/*
+ * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * SOC Info Routines
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/sys_soc.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/soc/qcom/socinfo.h>
+#include <linux/soc/qcom/smem.h>
+
+#include <asm/system_misc.h>
+
+
+#define BUILD_ID_LENGTH 32
+#define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32
+#define SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE 128
+#define SMEM_IMAGE_VERSION_SIZE 4096
+#define SMEM_IMAGE_VERSION_NAME_SIZE 75
+#define SMEM_IMAGE_VERSION_VARIANT_SIZE 20
+#define SMEM_IMAGE_VERSION_VARIANT_OFFSET 75
+#define SMEM_IMAGE_VERSION_OEM_SIZE 32
+#define SMEM_IMAGE_VERSION_OEM_OFFSET 96
+#define SMEM_IMAGE_VERSION_PARTITION_APPS 10
+#define SMEM_ITEM_SIZE_ALIGN 8
+/*
+ * Shared memory identifiers, used to acquire handles to respective memory
+ * region.
+ */
+#define SMEM_IMAGE_VERSION_TABLE	469
+#define SMEM_HW_SW_BUILD_ID		137
+
+const char *hw_platform[] = {
+	[HW_PLATFORM_UNKNOWN] = "Unknown",
+	[HW_PLATFORM_SURF] = "Surf",
+	[HW_PLATFORM_FFA] = "FFA",
+	[HW_PLATFORM_FLUID] = "Fluid",
+	[HW_PLATFORM_SVLTE_FFA] = "SVLTE_FFA",
+	[HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
+	[HW_PLATFORM_MTP_MDM] = "MDM_MTP_NO_DISPLAY",
+	[HW_PLATFORM_MTP] = "MTP",
+	[HW_PLATFORM_RCM] = "RCM",
+	[HW_PLATFORM_LIQUID] = "Liquid",
+	[HW_PLATFORM_DRAGON] = "Dragon",
+	[HW_PLATFORM_QRD] = "QRD",
+	[HW_PLATFORM_HRD] = "HRD",
+	[HW_PLATFORM_DTV] = "DTV",
+	[HW_PLATFORM_STP] = "STP",
+	[HW_PLATFORM_SBC] = "SBC",
+};
+
+const char *qrd_hw_platform_subtype[] = {
+	[PLATFORM_SUBTYPE_QRD] = "QRD",
+	[PLATFORM_SUBTYPE_SKUAA] = "SKUAA",
+	[PLATFORM_SUBTYPE_SKUF] = "SKUF",
+	[PLATFORM_SUBTYPE_SKUAB] = "SKUAB",
+	[PLATFORM_SUBTYPE_SKUG] = "SKUG",
+	[PLATFORM_SUBTYPE_QRD_INVALID] = "INVALID",
+};
+
+const char *hw_platform_subtype[] = {
+	[PLATFORM_SUBTYPE_UNKNOWN] = "Unknown",
+	[PLATFORM_SUBTYPE_CHARM] = "charm",
+	[PLATFORM_SUBTYPE_STRANGE] = "strange",
+	[PLATFORM_SUBTYPE_STRANGE_2A] = "strange_2a",
+	[PLATFORM_SUBTYPE_INVALID] = "Invalid",
+};
+
+/* Used to parse shared memory. Must match the modem. */
+struct socinfo_v0_1 {
+	uint32_t format;
+	uint32_t id;
+	uint32_t version;
+	char build_id[BUILD_ID_LENGTH];
+};
+
+struct socinfo_v0_2 {
+	struct socinfo_v0_1 v0_1;
+	uint32_t raw_id;
+	uint32_t raw_version;
+};
+
+struct socinfo_v0_3 {
+	struct socinfo_v0_2 v0_2;
+	uint32_t hw_platform;
+};
+
+struct socinfo_v0_4 {
+	struct socinfo_v0_3 v0_3;
+	uint32_t platform_version;
+};
+
+struct socinfo_v0_5 {
+	struct socinfo_v0_4 v0_4;
+	uint32_t accessory_chip;
+};
+
+struct socinfo_v0_6 {
+	struct socinfo_v0_5 v0_5;
+	uint32_t hw_platform_subtype;
+};
+
+struct socinfo_v0_7 {
+	struct socinfo_v0_6 v0_6;
+	uint32_t pmic_model;
+	uint32_t pmic_die_revision;
+};
+
+struct socinfo_v0_8 {
+	struct socinfo_v0_7 v0_7;
+	uint32_t pmic_model_1;
+	uint32_t pmic_die_revision_1;
+	uint32_t pmic_model_2;
+	uint32_t pmic_die_revision_2;
+};
+
+struct socinfo_v0_9 {
+	struct socinfo_v0_8 v0_8;
+	uint32_t foundry_id;
+};
+
+struct socinfo_v0_10 {
+	struct socinfo_v0_9 v0_9;
+	uint32_t serial_number;
+};
+
+struct socinfo_v0_11 {
+	struct socinfo_v0_10 v0_10;
+	uint32_t num_pmics;
+	uint32_t pmic_array_offset;
+};
+
+struct socinfo_v0_12 {
+	struct socinfo_v0_11 v0_11;
+	uint32_t chip_family;
+	uint32_t raw_device_family;
+	uint32_t raw_device_number;
+};
+
+static union {
+	struct socinfo_v0_1 v0_1;
+	struct socinfo_v0_2 v0_2;
+	struct socinfo_v0_3 v0_3;
+	struct socinfo_v0_4 v0_4;
+	struct socinfo_v0_5 v0_5;
+	struct socinfo_v0_6 v0_6;
+	struct socinfo_v0_7 v0_7;
+	struct socinfo_v0_8 v0_8;
+	struct socinfo_v0_9 v0_9;
+	struct socinfo_v0_10 v0_10;
+	struct socinfo_v0_11 v0_11;
+	struct socinfo_v0_12 v0_12;
+} *socinfo;
+
+/* max socinfo format version supported */
+#define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 12)
+
+static struct qcom_soc_info cpu_of_id[] = {
+
+	[MSM_UNKNOWN_ID] = {MSM_CPU_UNKNOWN, "Unknown CPU"},
+
+	/* 8x60 IDs */
+	[MSM_8960_ID] = {MSM_CPU_8960, "MSM8960"},
+
+	/* 8x64 IDs */
+	[APQ_8064_ID] = {MSM_CPU_8064, "APQ8064"},
+	[MPQ_8064_ID] = {MSM_CPU_8064, "MPQ8064"},
+
+	/* 8x60A IDs */
+	[MSM_8660A_ID] = {MSM_CPU_8960, "MSM8660A"},
+	[MSM_8260A_ID] = {MSM_CPU_8960, "MSM8260A"},
+	[APQ_8060A_ID] = {MSM_CPU_8960, "APQ8060A"},
+
+	/* 8x74 IDs */
+	[MSM_8974_ID] = {MSM_CPU_8974, "MSM8974"},
+	[APQ_8074_ID] = {MSM_CPU_8974, "APQ8074"},
+	[MSM_8274_ID] = {MSM_CPU_8974, "MSM8274"},
+	[MSM_8674_ID] = {MSM_CPU_8974, "MSM8674"},
+
+	/* 8x74AA IDs */
+	[APQ_8074_AA_ID] = {MSM_CPU_8974PRO_AA, "APQ8074-AA"},
+	[MSM_8274_AA_ID] = {MSM_CPU_8974PRO_AA, "MSM8274-AA"},
+	[MSM_8674_AA_ID] = {MSM_CPU_8974PRO_AA, "MSM8674-AA"},
+	[MSM_8974_AA_ID] = {MSM_CPU_8974PRO_AA, "MSM8974-AA"},
+
+	/* 8x74AB IDs */
+	[APQ_8074_AB_ID] = {MSM_CPU_8974PRO_AB, "APQ8074-AB"},
+	[MSM_8274_AB_ID] = {MSM_CPU_8974PRO_AB, "MSM8274-AB"},
+	[MSM_8674_AB_ID] = {MSM_CPU_8974PRO_AB, "MSM8674-AB"},
+	[MSM_8974_AB_ID] = {MSM_CPU_8974PRO_AB, "MSM8974-AB"},
+
+	/* 8x74AC IDs */
+	[MSM_8974PRO_ID] = {MSM_CPU_8974PRO_AC, "MSM8974PRO"},
+	[APQ_8074PRO_ID] = {MSM_CPU_8974PRO_AC, "APQ8074PRO"},
+	[MSM_8274PRO_ID] = {MSM_CPU_8974PRO_AC, "MSM8274PRO"},
+	[MSM_8674PRO_ID] = {MSM_CPU_8974PRO_AC, "MSM8674PRO"},
+
+	/* 8x60AB IDs */
+	[MSM_8960AB_ID] = {MSM_CPU_8960AB, "MSM8960AB"},
+	[APQ_8060AB_ID] = {MSM_CPU_8960AB, "APQ8060AB"},
+	[MSM_8260AB_ID] = {MSM_CPU_8960AB, "MSM8260AB"},
+	[MSM_8660AB_ID] = {MSM_CPU_8960AB, "MSM8660AB"},
+
+	/* 8x84 IDs */
+	[APQ_8084_ID] = {MSM_CPU_8084, "APQ8084"},
+
+	/* 8x16 IDs */
+	[MSM_8916_ID] = {MSM_CPU_8916, "MSM8916"},
+	[APQ_8016_ID] = {MSM_CPU_8916, "APQ8016"},
+	[MSM_8216_ID] = {MSM_CPU_8916, "MSM8216"},
+	[MSM_8116_ID] = {MSM_CPU_8916, "MSM8116"},
+	[MSM_8616_ID] = {MSM_CPU_8916, "MSM8616"},
+
+	/* 8x96 IDs */
+	[MSM_8996_ID] = {MSM_CPU_8996, "MSM8996"},
+	[MSM_8996AU_ID] = {MSM_CPU_8996, "MSM8996AU"},
+	[APQ_8096AU_ID] = {MSM_CPU_8996, "APQ8096AU"},
+	[APQ8096_ID] = {MSM_CPU_8996, "APQ8096"},
+	[MSM_8996SG_ID] = {MSM_CPU_8996, "MSM8996SG"},
+	[APQ_8096SG_ID] = {MSM_CPU_8996, "APQ8096SG"},
+
+	/*
+	 * Uninitialized IDs are not known to run Linux.
+	 * MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
+	 * considered as unknown CPU.
+	 */
+};
+
+static enum qcom_cpu cur_cpu;
+static int current_image;
+static uint32_t socinfo_format;
+
+static struct socinfo_v0_1 dummy_socinfo = {
+	.format = SOCINFO_VERSION(0, 1),
+	.version = 1,
+};
+
+static char *socinfo_get_id_string(void)
+{
+	return (socinfo) ? cpu_of_id[socinfo->v0_1.id].soc_id_string : NULL;
+}
+
+static uint32_t socinfo_get_accessory_chip(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 5) ?
+			socinfo->v0_5.accessory_chip : 0)
+		: 0;
+}
+
+static uint32_t socinfo_get_foundry_id(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 9) ?
+			socinfo->v0_9.foundry_id : 0)
+		: 0;
+}
+
+static uint32_t socinfo_get_chip_family(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 12) ?
+			socinfo->v0_12.chip_family : 0)
+		: 0;
+}
+
+static uint32_t socinfo_get_raw_device_family(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 12) ?
+			socinfo->v0_12.raw_device_family : 0)
+		: 0;
+}
+
+static uint32_t socinfo_get_raw_device_number(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 12) ?
+			socinfo->v0_12.raw_device_number : 0)
+		: 0;
+}
+
+static char *socinfo_get_image_version_base_address(struct device *dev)
+{
+	size_t size, size_in;
+	void *ptr;
+
+	ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_IMAGE_VERSION_TABLE,
+			&size);
+	if (!ptr)
+		return 0;
+
+	size_in = ALIGN(SMEM_IMAGE_VERSION_SIZE, SMEM_ITEM_SIZE_ALIGN);
+	if (size_in != size) {
+		dev_err(dev, "Wrong size for smem item\n");
+		return 0;
+	}
+
+	return ptr;
+}
+
+uint32_t socinfo_get_id(void)
+{
+	return (socinfo) ? socinfo->v0_1.id : 0;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_id);
+
+uint32_t socinfo_get_version(void)
+{
+	return (socinfo) ? socinfo->v0_1.version : 0;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_version);
+
+char *socinfo_get_build_id(void)
+{
+	return (socinfo) ? socinfo->v0_1.build_id : NULL;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_build_id);
+
+uint32_t socinfo_get_raw_id(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 2) ?
+			socinfo->v0_2.raw_id : 0)
+		: 0;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_raw_id);
+
+uint32_t socinfo_get_raw_version(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 2) ?
+			socinfo->v0_2.raw_version : 0)
+		: 0;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_raw_version);
+
+uint32_t socinfo_get_platform_type(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 3) ?
+			socinfo->v0_3.hw_platform : 0)
+		: 0;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_platform_type);
+
+uint32_t socinfo_get_platform_version(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 4) ?
+			socinfo->v0_4.platform_version : 0)
+		: 0;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_platform_version);
+
+uint32_t socinfo_get_platform_subtype(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 6) ?
+			socinfo->v0_6.hw_platform_subtype : 0)
+		: 0;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_platform_subtype);
+
+uint32_t socinfo_get_serial_number(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 10) ?
+			socinfo->v0_10.serial_number : 0)
+		: 0;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_serial_number);
+
+enum qcom_pmic_model socinfo_get_pmic_model(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 7) ?
+			socinfo->v0_7.pmic_model : PMIC_MODEL_UNKNOWN)
+		: PMIC_MODEL_UNKNOWN;
+}
+
+uint32_t socinfo_get_pmic_die_revision(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 7) ?
+			socinfo->v0_7.pmic_die_revision : 0)
+		: 0;
+}
+
+enum qcom_cpu socinfo_get_qcom_cpu(void)
+{
+	return cur_cpu;
+}
+EXPORT_SYMBOL_GPL(socinfo_get_qcom_cpu);
+
+/* socinfo: sysfs functions */
+
+static ssize_t
+qcom_get_vendor(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "Qualcomm\n");
+}
+
+static ssize_t
+qcom_get_raw_id(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_raw_id());
+}
+
+static ssize_t
+qcom_get_raw_version(struct device *dev,
+		     struct device_attribute *attr,
+		     char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_raw_version());
+}
+
+static ssize_t
+qcom_get_build_id(struct device *dev,
+		   struct device_attribute *attr,
+		   char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+			socinfo_get_build_id());
+}
+
+static ssize_t
+qcom_get_hw_platform(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	uint32_t hw_type;
+
+	hw_type = socinfo_get_platform_type();
+
+	return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+			hw_platform[hw_type]);
+}
+
+static ssize_t
+qcom_get_platform_version(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_platform_version());
+}
+
+static ssize_t
+qcom_get_accessory_chip(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_accessory_chip());
+}
+
+static ssize_t
+qcom_get_platform_subtype(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	uint32_t hw_subtype;
+
+	hw_subtype = socinfo_get_platform_subtype();
+	if (socinfo_get_platform_type() == HW_PLATFORM_QRD) {
+		if (hw_subtype >= PLATFORM_SUBTYPE_QRD_INVALID) {
+			pr_err("Invalid hardware platform sub type for qrd found\n");
+			hw_subtype = PLATFORM_SUBTYPE_QRD_INVALID;
+		}
+		return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+					qrd_hw_platform_subtype[hw_subtype]);
+	} else {
+		if (hw_subtype >= PLATFORM_SUBTYPE_INVALID) {
+			pr_err("Invalid hardware platform subtype\n");
+			hw_subtype = PLATFORM_SUBTYPE_INVALID;
+		}
+		return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+			hw_platform_subtype[hw_subtype]);
+	}
+}
+
+static ssize_t
+qcom_get_platform_subtype_id(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	uint32_t hw_subtype;
+
+	hw_subtype = socinfo_get_platform_subtype();
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		hw_subtype);
+}
+
+static ssize_t
+qcom_get_foundry_id(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_foundry_id());
+}
+
+static ssize_t
+qcom_get_serial_number(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_serial_number());
+}
+
+static ssize_t
+qcom_get_chip_family(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n",
+		socinfo_get_chip_family());
+}
+
+static ssize_t
+qcom_get_raw_device_family(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n",
+		socinfo_get_raw_device_family());
+}
+
+static ssize_t
+qcom_get_raw_device_number(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n",
+		socinfo_get_raw_device_number());
+}
+
+static ssize_t
+qcom_get_pmic_model(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		socinfo_get_pmic_model());
+}
+
+static ssize_t
+qcom_get_pmic_die_revision(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+			 socinfo_get_pmic_die_revision());
+}
+
+static ssize_t
+qcom_get_image_version(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	char *string_address;
+
+	string_address = socinfo_get_image_version_base_address(dev);
+	if (IS_ERR_OR_NULL(string_address)) {
+		pr_err("Failed to get image version base address");
+		return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "Unknown");
+	}
+	string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s\n",
+			string_address);
+}
+
+static ssize_t
+qcom_set_image_version(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf,
+			size_t count)
+{
+	char *store_address;
+
+	if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+		return count;
+	store_address = socinfo_get_image_version_base_address(dev);
+	if (IS_ERR_OR_NULL(store_address)) {
+		pr_err("Failed to get image version base address");
+		return count;
+	}
+	store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	snprintf(store_address, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s", buf);
+	return count;
+}
+
+static ssize_t
+qcom_get_image_variant(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	char *string_address;
+
+	string_address = socinfo_get_image_version_base_address(dev);
+	if (IS_ERR_OR_NULL(string_address)) {
+		pr_err("Failed to get image version base address");
+		return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE,
+		"Unknown");
+	}
+	string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	string_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
+	return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s\n",
+			string_address);
+}
+
+static ssize_t
+qcom_set_image_variant(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf,
+			size_t count)
+{
+	char *store_address;
+
+	if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+		return count;
+	store_address = socinfo_get_image_version_base_address(dev);
+	if (IS_ERR_OR_NULL(store_address)) {
+		pr_err("Failed to get image version base address");
+		return count;
+	}
+	store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	store_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
+	snprintf(store_address, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s", buf);
+	return count;
+}
+
+static ssize_t
+qcom_get_image_crm_version(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	char *string_address;
+
+	string_address = socinfo_get_image_version_base_address(dev);
+	if (IS_ERR_OR_NULL(string_address)) {
+		pr_err("Failed to get image version base address");
+		return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "Unknown");
+	}
+	string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	string_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
+	return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n",
+			string_address);
+}
+
+static ssize_t
+qcom_set_image_crm_version(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf,
+			size_t count)
+{
+	char *store_address;
+
+	if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+		return count;
+	store_address = socinfo_get_image_version_base_address(dev);
+	if (IS_ERR_OR_NULL(store_address)) {
+		pr_err("Failed to get image version base address");
+		return count;
+	}
+	store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	store_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
+	snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf);
+	return count;
+}
+
+static ssize_t
+qcom_get_image_number(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			current_image);
+}
+
+static ssize_t
+qcom_select_image(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	int ret, digit;
+
+	ret = kstrtoint(buf, 10, &digit);
+	if (ret)
+		return ret;
+	if (digit >= 0 && digit < SMEM_IMAGE_VERSION_BLOCKS_COUNT)
+		current_image = digit;
+	else
+		current_image = 0;
+	return count;
+}
+
+static ssize_t
+qcom_get_images(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int pos = 0;
+	int image;
+	char *image_address;
+
+	image_address = socinfo_get_image_version_base_address(dev);
+	if (IS_ERR_OR_NULL(image_address))
+		return snprintf(buf, PAGE_SIZE, "Unavailable\n");
+
+	*buf = '\0';
+	for (image = 0; image < SMEM_IMAGE_VERSION_BLOCKS_COUNT; image++) {
+		if (*image_address == '\0') {
+			image_address += SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+			continue;
+		}
+
+		pos += snprintf(buf + pos, PAGE_SIZE - pos, "%d:\n",
+				image);
+		pos += snprintf(buf + pos, PAGE_SIZE - pos,
+				"\tCRM:\t\t%-.75s\n", image_address);
+		pos += snprintf(buf + pos, PAGE_SIZE - pos,
+				"\tVariant:\t%-.20s\n", image_address +
+				SMEM_IMAGE_VERSION_VARIANT_OFFSET);
+		pos += snprintf(buf + pos, PAGE_SIZE - pos,
+				"\tVersion:\t%-.32s\n\n",
+				image_address + SMEM_IMAGE_VERSION_OEM_OFFSET);
+
+		image_address += SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+	}
+
+	return pos;
+}
+
+static struct device_attribute qcom_soc_attr_raw_version =
+	__ATTR(raw_version, S_IRUGO, qcom_get_raw_version,  NULL);
+
+static struct device_attribute qcom_soc_attr_raw_id =
+	__ATTR(raw_id, S_IRUGO, qcom_get_raw_id,  NULL);
+
+static struct device_attribute qcom_soc_attr_vendor =
+	__ATTR(vendor, S_IRUGO, qcom_get_vendor,  NULL);
+
+static struct device_attribute qcom_soc_attr_build_id =
+	__ATTR(build_id, S_IRUGO, qcom_get_build_id, NULL);
+
+static struct device_attribute qcom_soc_attr_hw_platform =
+	__ATTR(hw_platform, S_IRUGO, qcom_get_hw_platform, NULL);
+
+
+static struct device_attribute qcom_soc_attr_platform_version =
+	__ATTR(platform_version, S_IRUGO,
+			qcom_get_platform_version, NULL);
+
+static struct device_attribute qcom_soc_attr_accessory_chip =
+	__ATTR(accessory_chip, S_IRUGO,
+			qcom_get_accessory_chip, NULL);
+
+static struct device_attribute qcom_soc_attr_platform_subtype =
+	__ATTR(platform_subtype, S_IRUGO,
+			qcom_get_platform_subtype, NULL);
+
+/* Platform Subtype String is being deprecated. Use Platform
+ * Subtype ID instead.
+ */
+static struct device_attribute qcom_soc_attr_platform_subtype_id =
+	__ATTR(platform_subtype_id, S_IRUGO,
+			qcom_get_platform_subtype_id, NULL);
+
+static struct device_attribute qcom_soc_attr_foundry_id =
+	__ATTR(foundry_id, S_IRUGO,
+			qcom_get_foundry_id, NULL);
+
+static struct device_attribute qcom_soc_attr_serial_number =
+	__ATTR(serial_number, S_IRUGO,
+			qcom_get_serial_number, NULL);
+
+static struct device_attribute qcom_soc_attr_chip_family =
+	__ATTR(chip_family, S_IRUGO,
+			qcom_get_chip_family, NULL);
+
+static struct device_attribute qcom_soc_attr_raw_device_family =
+	__ATTR(raw_device_family, S_IRUGO,
+			qcom_get_raw_device_family, NULL);
+
+static struct device_attribute qcom_soc_attr_raw_device_number =
+	__ATTR(raw_device_number, S_IRUGO,
+			qcom_get_raw_device_number, NULL);
+
+static struct device_attribute qcom_soc_attr_pmic_model =
+	__ATTR(pmic_model, S_IRUGO,
+			qcom_get_pmic_model, NULL);
+
+static struct device_attribute qcom_soc_attr_pmic_die_revision =
+	__ATTR(pmic_die_revision, S_IRUGO,
+			qcom_get_pmic_die_revision, NULL);
+
+static struct device_attribute image_version =
+	__ATTR(image_version, S_IRUGO | S_IWUSR,
+			qcom_get_image_version, qcom_set_image_version);
+
+static struct device_attribute image_variant =
+	__ATTR(image_variant, S_IRUGO | S_IWUSR,
+			qcom_get_image_variant, qcom_set_image_variant);
+
+static struct device_attribute image_crm_version =
+	__ATTR(image_crm_version, S_IRUGO | S_IWUSR,
+			qcom_get_image_crm_version, qcom_set_image_crm_version);
+
+static struct device_attribute select_image =
+	__ATTR(select_image, S_IRUGO | S_IWUSR,
+			qcom_get_image_number, qcom_select_image);
+
+static struct device_attribute images =
+	__ATTR(images, S_IRUGO, qcom_get_images, NULL);
+
+static void * __init setup_dummy_socinfo(void)
+{
+	if (early_machine_is_apq8064()) {
+		dummy_socinfo.id = APQ_8064_ID;
+		strlcpy(dummy_socinfo.build_id, "apq8064",
+			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_apq8084()) {
+		dummy_socinfo.id = APQ_8084_ID;
+		strlcpy(dummy_socinfo.build_id, "apq8084",
+			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8916()) {
+		dummy_socinfo.id = MSM_8916_ID;
+		strlcpy(dummy_socinfo.build_id, "msm8916",
+			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8660()) {
+		dummy_socinfo.id = MSM_8660A_ID;
+		strlcpy(dummy_socinfo.build_id, "msm8660",
+			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8960()) {
+		dummy_socinfo.id = MSM_8960_ID;
+		strlcpy(dummy_socinfo.build_id, "msm8960",
+			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8974()) {
+		dummy_socinfo.id = MSM_8974_ID;
+		strlcpy(dummy_socinfo.build_id, "msm8974",
+			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8996()) {
+		dummy_socinfo.id = MSM_8996_ID;
+		strlcpy(dummy_socinfo.build_id, "msm8996",
+			sizeof(dummy_socinfo.build_id));
+	}
+
+	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
+		sizeof(dummy_socinfo.build_id));
+	return (void *) &dummy_socinfo;
+}
+
+static void socinfo_populate_sysfs_files(struct device *qcom_soc_device)
+{
+	device_create_file(qcom_soc_device, &qcom_soc_attr_vendor);
+	device_create_file(qcom_soc_device, &image_version);
+	device_create_file(qcom_soc_device, &image_variant);
+	device_create_file(qcom_soc_device, &image_crm_version);
+	device_create_file(qcom_soc_device, &select_image);
+	device_create_file(qcom_soc_device, &images);
+
+	switch (socinfo_format) {
+	case SOCINFO_VERSION(0, 12):
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_chip_family);
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_raw_device_family);
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_raw_device_number);
+	case SOCINFO_VERSION(0, 11):
+	case SOCINFO_VERSION(0, 10):
+		 device_create_file(qcom_soc_device,
+					&qcom_soc_attr_serial_number);
+	case SOCINFO_VERSION(0, 9):
+		 device_create_file(qcom_soc_device,
+					&qcom_soc_attr_foundry_id);
+	case SOCINFO_VERSION(0, 8):
+	case SOCINFO_VERSION(0, 7):
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_pmic_model);
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_pmic_die_revision);
+	case SOCINFO_VERSION(0, 6):
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_platform_subtype);
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_platform_subtype_id);
+	case SOCINFO_VERSION(0, 5):
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_accessory_chip);
+	case SOCINFO_VERSION(0, 4):
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_platform_version);
+	case SOCINFO_VERSION(0, 3):
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_hw_platform);
+	case SOCINFO_VERSION(0, 2):
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_raw_id);
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_raw_version);
+	case SOCINFO_VERSION(0, 1):
+		device_create_file(qcom_soc_device,
+					&qcom_soc_attr_build_id);
+		break;
+	default:
+		pr_err("Unknown socinfo format: v%u.%u\n",
+				SOCINFO_VERSION_MAJOR(socinfo_format),
+				SOCINFO_VERSION_MINOR(socinfo_format));
+		break;
+	}
+}
+
+static void socinfo_populate(struct soc_device_attribute *soc_dev_attr)
+{
+	uint32_t soc_version = socinfo_get_version();
+
+	soc_dev_attr->soc_id   = kasprintf(GFP_KERNEL, "%d", socinfo_get_id());
+	soc_dev_attr->family  =  "Snapdragon";
+	soc_dev_attr->machine  = socinfo_get_id_string();
+	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u.%u",
+			SOCINFO_VERSION_MAJOR(soc_version),
+			SOCINFO_VERSION_MINOR(soc_version));
+	return;
+
+}
+
+static int socinfo_init_sysfs(void)
+{
+	struct device *qcom_soc_device;
+	struct soc_device *soc_dev;
+	struct soc_device_attribute *soc_dev_attr;
+
+	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+	if (!soc_dev_attr) {
+		pr_err("Soc Device alloc failed!\n");
+		return -ENOMEM;
+	}
+
+	socinfo_populate(soc_dev_attr);
+	soc_dev = soc_device_register(soc_dev_attr);
+	if (IS_ERR_OR_NULL(soc_dev)) {
+		kfree(soc_dev_attr);
+		pr_err("Soc device register failed\n");
+		return -EIO;
+	}
+
+	qcom_soc_device = soc_device_to_device(soc_dev);
+	socinfo_populate_sysfs_files(qcom_soc_device);
+	return 0;
+}
+
+static void socinfo_print(void)
+{
+	uint32_t f_maj = SOCINFO_VERSION_MAJOR(socinfo_format);
+	uint32_t f_min = SOCINFO_VERSION_MINOR(socinfo_format);
+	uint32_t v_maj = SOCINFO_VERSION_MAJOR(socinfo->v0_1.version);
+	uint32_t v_min = SOCINFO_VERSION_MINOR(socinfo->v0_1.version);
+
+	switch (socinfo_format) {
+	case SOCINFO_VERSION(0, 1):
+		pr_info("v%u.%u, id=%u, ver=%u.%u\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min);
+		break;
+	case SOCINFO_VERSION(0, 2):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version);
+		break;
+	case SOCINFO_VERSION(0, 3):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u\n",
+			f_maj, f_min, socinfo->v0_1.id,
+			v_maj, v_min, socinfo->v0_2.raw_id,
+			socinfo->v0_2.raw_version, socinfo->v0_3.hw_platform);
+		break;
+	case SOCINFO_VERSION(0, 4):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version);
+		break;
+	case SOCINFO_VERSION(0, 5):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u accessory_chip=%u\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version,
+			socinfo->v0_5.accessory_chip);
+		break;
+	case SOCINFO_VERSION(0, 6):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u accessory_chip=%u, hw_plat_subtype=%u\n",
+			f_maj, f_min, socinfo->v0_1.id,
+			v_maj, v_min, socinfo->v0_2.raw_id,
+			socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version,
+			socinfo->v0_5.accessory_chip,
+			socinfo->v0_6.hw_platform_subtype);
+		break;
+	case SOCINFO_VERSION(0, 7):
+	case SOCINFO_VERSION(0, 8):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version,
+			socinfo->v0_5.accessory_chip,
+			socinfo->v0_6.hw_platform_subtype,
+			socinfo->v0_7.pmic_model,
+			socinfo->v0_7.pmic_die_revision);
+		break;
+	case SOCINFO_VERSION(0, 9):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u foundry_id=%u\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version,
+			socinfo->v0_5.accessory_chip,
+			socinfo->v0_6.hw_platform_subtype,
+			socinfo->v0_7.pmic_model,
+			socinfo->v0_7.pmic_die_revision,
+			socinfo->v0_9.foundry_id);
+		break;
+	case SOCINFO_VERSION(0, 10):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u, foundry_id=%u, serial_number=%u\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version,
+			socinfo->v0_5.accessory_chip,
+			socinfo->v0_6.hw_platform_subtype,
+			socinfo->v0_7.pmic_model,
+			socinfo->v0_7.pmic_die_revision,
+			socinfo->v0_9.foundry_id,
+			socinfo->v0_10.serial_number);
+		break;
+	case SOCINFO_VERSION(0, 11):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u, accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u, foundry_id=%u, serial_number=%u num_pmics=%u\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version,
+			socinfo->v0_5.accessory_chip,
+			socinfo->v0_6.hw_platform_subtype,
+			socinfo->v0_7.pmic_model,
+			socinfo->v0_7.pmic_die_revision,
+			socinfo->v0_9.foundry_id,
+			socinfo->v0_10.serial_number,
+			socinfo->v0_11.num_pmics);
+		break;
+	case SOCINFO_VERSION(0, 12):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u, foundry_id=%u, serial_number=%u, num_pmics=%u,	chip_family=0x%x, raw_device_family=0x%x, raw_device_number=0x%x\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version,
+			socinfo->v0_5.accessory_chip,
+			socinfo->v0_6.hw_platform_subtype,
+			socinfo->v0_7.pmic_model,
+			socinfo->v0_7.pmic_die_revision,
+			socinfo->v0_9.foundry_id,
+			socinfo->v0_10.serial_number,
+			socinfo->v0_11.num_pmics,
+			socinfo->v0_12.chip_family,
+			socinfo->v0_12.raw_device_family,
+			socinfo->v0_12.raw_device_number);
+		break;
+
+	default:
+		pr_err("Unknown format found: v%u.%u\n", f_maj, f_min);
+		break;
+	}
+}
+
+static void socinfo_select_format(void)
+{
+	uint32_t f_maj = SOCINFO_VERSION_MAJOR(socinfo->v0_1.format);
+	uint32_t f_min = SOCINFO_VERSION_MINOR(socinfo->v0_1.format);
+
+	if (f_maj != 0) {
+		pr_err("Unsupported format v%u.%u. Falling back to dummy values.\n",
+			f_maj, f_min);
+		socinfo = setup_dummy_socinfo();
+	}
+
+	if (socinfo->v0_1.format > MAX_SOCINFO_FORMAT) {
+		pr_warn("Unsupported format v%u.%u. Falling back to v%u.%u.\n",
+			f_maj, f_min, SOCINFO_VERSION_MAJOR(MAX_SOCINFO_FORMAT),
+			SOCINFO_VERSION_MINOR(MAX_SOCINFO_FORMAT));
+		socinfo_format = MAX_SOCINFO_FORMAT;
+	} else {
+		socinfo_format = socinfo->v0_1.format;
+	}
+}
+
+static int qcom_socinfo_probe(struct platform_device *pdev)
+{
+	size_t size;
+
+	socinfo = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID,
+			&size);
+	if (IS_ERR_OR_NULL(socinfo)) {
+		if (PTR_ERR(socinfo) == -EPROBE_DEFER)
+			return PTR_ERR(socinfo);
+		else {
+			dev_warn(&pdev->dev,
+				"Can't find SMEM_HW_SW_BUILD_ID; falling back on dummy values.\n");
+			socinfo = setup_dummy_socinfo();
+		}
+	}
+
+	socinfo_select_format();
+
+	WARN(!socinfo_get_id(), "Unknown SOC ID!\n");
+
+	if (socinfo_get_id() >= ARRAY_SIZE(cpu_of_id))
+		BUG_ON("New IDs added! ID => CPU mapping needs an update.\n");
+	else
+		cur_cpu = cpu_of_id[socinfo->v0_1.id].generic_soc_type;
+
+	socinfo_print();
+
+	socinfo_init_sysfs();
+
+	return 0;
+}
+
+static const struct of_device_id qcom_socinfo_of_match[] = {
+	{ .compatible = "qcom,socinfo" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, qcom_socinfo_of_match);
+
+static struct platform_driver qcom_socinfo_driver = {
+	.probe = qcom_socinfo_probe,
+	.driver  = {
+		.name  = "qcom-socinfo",
+		.of_match_table = qcom_socinfo_of_match,
+	},
+};
+module_platform_driver(qcom_socinfo_driver);
+
diff --git a/include/linux/soc/qcom/socinfo.h b/include/linux/soc/qcom/socinfo.h
new file mode 100644
index 0000000..17ca50a
--- /dev/null
+++ b/include/linux/soc/qcom/socinfo.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_SOCINFO_H_
+#define _ARCH_ARM_MACH_MSM_SOCINFO_H_
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/of_fdt.h>
+#include <linux/of.h>
+
+#include <asm/cputype.h>
+/*
+ * SOC version type with major number in the upper 16 bits and minor
+ * number in the lower 16 bits.  For example:
+ *   1.0 -> 0x00010000
+ *   2.3 -> 0x00020003
+ */
+#define SOCINFO_VERSION_MAJOR(ver) (((ver) & 0xffff0000) >> 16)
+#define SOCINFO_VERSION_MINOR(ver) ((ver) & 0x0000ffff)
+#define SOCINFO_VERSION(maj, min)  ((((maj) & 0xffff) << 16)|((min) & 0xffff))
+
+#ifdef CONFIG_OF
+#define early_machine_is_apq8064()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,apq8064")
+#define early_machine_is_apq8084()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,apq8084")
+#define early_machine_is_msm8916()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8916")
+#define early_machine_is_msm8660()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8660")
+#define early_machine_is_msm8960()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8960")
+#define early_machine_is_msm8974()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8974")
+#define early_machine_is_msm8996()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8996")
+#else
+#define early_machine_is_apq8064()	0
+#define early_machine_is_apq8084()	0
+#define early_machine_is_msm8916()	0
+#define early_machine_is_msm8660()	0
+#define early_machine_is_msm8960()	0
+#define early_machine_is_msm8974()	0
+#define early_machine_is_msm8996()	0
+#endif
+
+#define PLATFORM_SUBTYPE_MDM	1
+#define PLATFORM_SUBTYPE_INTERPOSERV3 2
+#define PLATFORM_SUBTYPE_SGLTE	6
+
+enum qcom_cpu {
+	MSM_CPU_UNKNOWN = 0,
+	MSM_CPU_8960,
+	MSM_CPU_8960AB,
+	MSM_CPU_8064,
+	MSM_CPU_8974,
+	MSM_CPU_8974PRO_AA,
+	MSM_CPU_8974PRO_AB,
+	MSM_CPU_8974PRO_AC,
+	MSM_CPU_8916,
+	MSM_CPU_8084,
+	MSM_CPU_8996
+};
+
+enum qcom_cpu_id {
+	MSM_UNKNOWN_ID,
+	MSM_8960_ID = 87,
+	APQ_8064_ID = 109,
+	MSM_8660A_ID = 122,
+	MSM_8260A_ID,
+	APQ_8060A_ID,
+	MSM_8974_ID = 126,
+	MPQ_8064_ID = 130,
+	MSM_8960AB_ID = 138,
+	APQ_8060AB_ID,
+	MSM_8260AB_ID,
+	MSM_8660AB_ID,
+	APQ_8084_ID = 178,
+	APQ_8074_ID = 184,
+	MSM_8274_ID,
+	MSM_8674_ID,
+	MSM_8974PRO_ID = 194,
+	MSM_8916_ID = 206,
+	APQ_8074_AA_ID = 208,
+	APQ_8074_AB_ID,
+	APQ_8074PRO_ID,
+	MSM_8274_AA_ID,
+	MSM_8274_AB_ID,
+	MSM_8274PRO_ID,
+	MSM_8674_AA_ID,
+	MSM_8674_AB_ID,
+	MSM_8674PRO_ID,
+	MSM_8974_AA_ID,
+	MSM_8974_AB_ID,
+	MSM_8996_ID = 246,
+	APQ_8016_ID,
+	MSM_8216_ID,
+	MSM_8116_ID,
+	MSM_8616_ID,
+	APQ8096_ID = 291,
+	MSM_8996SG_ID = 305,
+	MSM_8996AU_ID = 310,
+	APQ_8096AU_ID,
+	APQ_8096SG_ID
+};
+
+struct qcom_soc_info {
+	enum qcom_cpu generic_soc_type;
+	char *soc_id_string;
+};
+
+enum qcom_pmic_model {
+	PMIC_MODEL_PM8058 = 13,
+	PMIC_MODEL_PM8028,
+	PMIC_MODEL_PM8901,
+	PMIC_MODEL_PM8027,
+	PMIC_MODEL_ISL_9519,
+	PMIC_MODEL_PM8921,
+	PMIC_MODEL_PM8018,
+	PMIC_MODEL_PM8015,
+	PMIC_MODEL_PM8014,
+	PMIC_MODEL_PM8821,
+	PMIC_MODEL_PM8038,
+	PMIC_MODEL_PM8922,
+	PMIC_MODEL_PM8917,
+	PMIC_MODEL_UNKNOWN = 0xFFFFFFFF
+};
+
+enum hw_platform_type {
+	HW_PLATFORM_UNKNOWN,
+	HW_PLATFORM_SURF,
+	HW_PLATFORM_FFA,
+	HW_PLATFORM_FLUID,
+	HW_PLATFORM_SVLTE_FFA,
+	HW_PLATFORM_SVLTE_SURF,
+	HW_PLATFORM_MTP_MDM = 7,
+	HW_PLATFORM_MTP,
+	HW_PLATFORM_LIQUID,
+	/* Dragonboard platform id is assigned as 10 in CDT */
+	HW_PLATFORM_DRAGON,
+	HW_PLATFORM_QRD,
+	HW_PLATFORM_HRD	= 13,
+	HW_PLATFORM_DTV,
+	HW_PLATFORM_RCM	= 21,
+	HW_PLATFORM_STP = 23,
+	HW_PLATFORM_SBC,
+	HW_PLATFORM_INVALID
+};
+
+enum accessory_chip_type {
+	ACCESSORY_CHIP_UNKNOWN = 0,
+	ACCESSORY_CHIP_CHARM = 58
+};
+
+enum qrd_platform_subtype {
+	PLATFORM_SUBTYPE_QRD,
+	PLATFORM_SUBTYPE_SKUAA,
+	PLATFORM_SUBTYPE_SKUF,
+	PLATFORM_SUBTYPE_SKUAB,
+	PLATFORM_SUBTYPE_SKUG = 0x5,
+	PLATFORM_SUBTYPE_QRD_INVALID
+};
+
+enum platform_subtype {
+	PLATFORM_SUBTYPE_UNKNOWN,
+	PLATFORM_SUBTYPE_CHARM,
+	PLATFORM_SUBTYPE_STRANGE,
+	PLATFORM_SUBTYPE_STRANGE_2A,
+	PLATFORM_SUBTYPE_INVALID
+};
+
+enum msm_cpu socinfo_get_msm_cpu(void);
+uint32_t socinfo_get_id(void);
+uint32_t socinfo_get_version(void);
+uint32_t socinfo_get_raw_id(void);
+char *socinfo_get_build_id(void);
+uint32_t socinfo_get_platform_type(void);
+uint32_t socinfo_get_platform_subtype(void);
+uint32_t socinfo_get_platform_version(void);
+uint32_t socinfo_get_serial_number(void);
+enum qcom_pmic_model socinfo_get_pmic_model(void);
+uint32_t socinfo_get_pmic_die_revision(void);
+int __init socinfo_init(void) __must_check;
+
+#endif
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2016-11-09 14:44 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-10-20 14:06 [PATCH] soc: qcom: Add SoC info driver Imran Khan
     [not found] ` <1476972386-28655-1-git-send-email-kimran-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-10-20 14:09   ` Mark Rutland
2016-10-20 15:20 ` Andy Gross
2016-10-25  9:38   ` Imran Khan
2016-10-21 10:33 ` Arnd Bergmann
2016-10-25  9:53   ` Imran Khan
2016-10-25 20:49     ` Arnd Bergmann
2016-10-26 13:50       ` Imran Khan
2016-10-26 14:05         ` Arnd Bergmann
2016-10-26 14:12           ` Imran Khan
2016-10-26 14:46             ` Arnd Bergmann
2016-10-27 13:10               ` Imran Khan
2016-10-27 13:41                 ` Arnd Bergmann
2016-11-02  7:49                   ` Imran Khan
2016-11-02 13:11                     ` Arnd Bergmann
2016-11-02 16:28           ` Bjorn Andersson
2016-11-09 14:44             ` Geert Uytterhoeven

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).