From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932140AbcLLPSb (ORCPT ); Mon, 12 Dec 2016 10:18:31 -0500 Received: from smtp.codeaurora.org ([198.145.29.96]:44774 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752136AbcLLPS2 (ORCPT ); Mon, 12 Dec 2016 10:18:28 -0500 DMARC-Filter: OpenDMARC Filter v1.3.1 smtp.codeaurora.org 53F7A61400 Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=pass smtp.mailfrom=kimran@codeaurora.org From: Imran Khan To: andy.gross@linaro.org Cc: lee.jones@linaro.org, Imran Khan , David Brown , linux-kernel@vger.kernel.org (open list), linux-arm-msm@vger.kernel.org (open list:ARM/QUALCOMM SUPPORT), linux-soc@vger.kernel.org (open list:ARM/QUALCOMM SUPPORT) Subject: [PATCH v6] soc: qcom: Add SoC info driver Date: Mon, 12 Dec 2016 20:47:45 +0530 Message-Id: <1481555889-29380-1-git-send-email-kimran@codeaurora.org> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- v5 --> v6: - use dev_ext_attribute to represent SMEM image items - Avoid redundant function calls - Avoid use of unnecessary global variables - Remove redundant enums - Avoid redundant checking of socinfo being NULL or not - Avoid redundant checking of socinfo format version - Rename show/store function of attributes as _show/_store rather than _get/_set - Use an array to represent socinfo attributes and create attribute files in a loop depending on the minimum socinfo format version for which these attributes are supported - if obtained socinfo format version is greater than the maximum known version return an error rather than falling back to maximum known version v4 --> v5: - Removed redundant function socinfo_print v3 --> v4: - Corrected makefile so that smem and socinfo are treated as one module - Moved the code snippet to get socinfo smem item into socinfo.c - Removed redundant use of socinfo major version as it is always zero - Removed unused enums - Removed redundant indirections - Use image_version object to store information about each entry in the smem image table - Replaced usage of snprintf with sprintf and scnprintf - Get the address of image version table at the beginning and setup image version attributes only if image version table is available - Do the same for platform_subtype - Make different type of image version objects read only or readable/ writable depending on their types. For example apps image attributes can be modified via sysfs but the same can't be done for modem image - Show PMIC model in a human readable form rather than a numeric number - Avoid using table in single sysfs entry - Removed checkpatch warnings about S_IRUGO v2 --> v3: - Add support to toss soc information data into entropy pool - Since socinfo is rolled into smem driver, compile the relevant portion of socinfo driver with smem driver v1 --> v2: - Removed inclusion of system_misc.h - merged socinfo.h into socinfo.c - made platform type and subtype arrays static - replaced uint32_t with u32 - made functions static to avoid exposing vendor specific interface - Replaced usage of IS_ERR_OR_NULL with IS_ERR. - Remove raw-id attribute usage as human readable soc-id will suffice here - Avoid using a separate platform driver for socinfo by rolling it into smem driver itself. The sysfs setup is being done in a separate file (socinfo.c) - Replaced macro BUILD_ID_LENGTH with SMEM_SOCINFO_BUILD_ID_LENGTH. - For failure cases where socinfo can not be read use a single dummy socinfo with error values. - Removed usage of early_machine_is_xxx. drivers/soc/qcom/Kconfig | 1 + drivers/soc/qcom/Makefile | 3 +- drivers/soc/qcom/smem.c | 5 + drivers/soc/qcom/socinfo.c | 671 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 679 insertions(+), 1 deletion(-) create mode 100644 drivers/soc/qcom/socinfo.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 461b387..f89d34d 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -24,6 +24,7 @@ config QCOM_SMEM tristate "Qualcomm Shared Memory Manager (SMEM)" depends on ARCH_QCOM depends on HWSPINLOCK + select SOC_BUS help Say y here to enable support for the Qualcomm Shared Memory Manager. The driver provides an interface to items in a heap shared among all diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index fdd664e..438efec 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -2,7 +2,8 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_PM) += spm.o obj-$(CONFIG_QCOM_SMD) += smd.o obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o -obj-$(CONFIG_QCOM_SMEM) += smem.o +obj-$(CONFIG_QCOM_SMEM) += qcom_smem.o +qcom_smem-y := smem.o socinfo.o obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 18ec52f..c598cac 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -85,6 +85,9 @@ /* Max number of processors/hosts in a system */ #define SMEM_HOST_COUNT 9 + +extern void qcom_socinfo_init(struct platform_device *pdev); + /** * struct smem_proc_comm - proc_comm communication struct (legacy) * @command: current command to be executed @@ -751,6 +754,8 @@ static int qcom_smem_probe(struct platform_device *pdev) __smem = smem; + qcom_socinfo_init(pdev); + return 0; } diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c new file mode 100644 index 0000000..57e23dfc --- /dev/null +++ b/drivers/soc/qcom/socinfo.c @@ -0,0 +1,671 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PMIC_MODEL_UNKNOWN 0 +#define HW_PLATFORM_QRD 11 +#define PLATFORM_SUBTYPE_QRD_INVALID 6 +#define PLATFORM_SUBTYPE_INVALID 4 +/* + * 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 SOC_VERSION_MAJOR(ver) (((ver) & 0xffff0000) >> 16) +#define SOC_VERSION_MINOR(ver) ((ver) & 0x0000ffff) +#define SOCINFO_VERSION_MAJOR SOC_VERSION_MAJOR +#define SOCINFO_VERSION_MINOR SOC_VERSION_MINOR + +#define SMEM_SOCINFO_BUILD_ID_LENGTH 32 +#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 +#define SMEM_IMAGE_VERSION_PARTITION_APPS 10 + +/* + * SMEM item ids, used to acquire handles to respective + * SMEM region. + */ +#define SMEM_IMAGE_VERSION_TABLE 469 +#define SMEM_HW_SW_BUILD_ID 137 + +#define MAX_ATTR_COUNT 15 + +/* + * SMEM Image table indices + */ +enum smem_image_table_index { + SMEM_IMAGE_TABLE_BOOT_INDEX = 0, + SMEM_IMAGE_TABLE_TZ_INDEX, + SMEM_IMAGE_TABLE_RPM_INDEX = 3, + SMEM_IMAGE_TABLE_APPS_INDEX = 10, + SMEM_IMAGE_TABLE_MPSS_INDEX, + SMEM_IMAGE_TABLE_ADSP_INDEX, + SMEM_IMAGE_TABLE_CNSS_INDEX, + SMEM_IMAGE_TABLE_VIDEO_INDEX +}; + +struct qcom_socinfo_attr { + struct device_attribute attr; + int min_version; +}; + +#define QCOM_SOCINFO_ATTR(_name, _show, _min_version) \ + { __ATTR(_name, 0444, _show, NULL), _min_version } + +#define SMEM_IMG_ATTR_ENTRY(_name, _mode, _show, _store, _index) \ + struct dev_ext_attribute dev_attr_##_name = \ + { __ATTR(_name, _mode, _show, _store), (void *)_index } + +#define QCOM_SMEM_IMG_ITEM(_name, _mode, _index) \ + SMEM_IMG_ATTR_ENTRY(_name##_image_version, _mode, \ + qcom_show_image_version, qcom_store_image_version, \ + (unsigned long)_index); \ + SMEM_IMG_ATTR_ENTRY(_name##_image_variant, _mode, \ + qcom_show_image_variant, qcom_store_image_variant, \ + (unsigned long)_index); \ + SMEM_IMG_ATTR_ENTRY(_name##_image_crm, _mode, \ + qcom_show_image_crm, qcom_store_image_crm, \ + (unsigned long)_index); \ +static struct attribute *_name##_image_attrs[] = { \ + &dev_attr_##_name##_image_version.attr.attr, \ + &dev_attr_##_name##_image_variant.attr.attr, \ + &dev_attr_##_name##_image_crm.attr.attr, \ + NULL, \ +}; \ +static struct attribute_group _name##_image_attr_group = { \ + .attrs = _name##_image_attrs, \ +} + +/* Hardware platform types */ +static const char *const hw_platform[] = { + [0] = "Unknown", + [1] = "Surf", + [2] = "FFA", + [3] = "Fluid", + [4] = "SVLTE_FFA", + [5] = "SLVTE_SURF", + [7] = "MDM_MTP_NO_DISPLAY", + [8] = "MTP", + [9] = "Liquid", + [10] = "Dragon", + [11] = "QRD", + [13] = "HRD", + [14] = "DTV", + [21] = "RCM", + [23] = "STP", + [24] = "SBC", +}; + +static const char *const qrd_hw_platform_subtype[] = { + [0] = "QRD", + [1] = "SKUAA", + [2] = "SKUF", + [3] = "SKUAB", + [5] = "SKUG", + [6] = "INVALID", +}; + +static const char *const hw_platform_subtype[] = { + "Unknown", "charm", "strange", "strange_2a", "Invalid", +}; + +static const char *const pmic_model[] = { + [0] = "Unknown PMIC model", + [13] = "PMIC model: PM8058", + [14] = "PMIC model: PM8028", + [15] = "PMIC model: PM8901", + [16] = "PMIC model: PM8027", + [17] = "PMIC model: ISL9519", + [18] = "PMIC model: PM8921", + [19] = "PMIC model: PM8018", + [20] = "PMIC model: PM8015", + [21] = "PMIC model: PM8014", + [22] = "PMIC model: PM8821", + [23] = "PMIC model: PM8038", + [24] = "PMIC model: PM8922", + [25] = "PMIC model: PM8917", +}; + +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]; +}; + +/* Used to parse shared memory. Must match the modem. */ +struct socinfo_v0_1 { + u32 format; + u32 id; + u32 version; + char build_id[SMEM_SOCINFO_BUILD_ID_LENGTH]; +}; + +struct socinfo_v0_2 { + struct socinfo_v0_1 v0_1; + u32 raw_version; +}; + +struct socinfo_v0_3 { + struct socinfo_v0_2 v0_2; + u32 hw_platform; +}; + +struct socinfo_v0_4 { + struct socinfo_v0_3 v0_3; + u32 platform_version; +}; + +struct socinfo_v0_5 { + struct socinfo_v0_4 v0_4; + u32 accessory_chip; +}; + +struct socinfo_v0_6 { + struct socinfo_v0_5 v0_5; + u32 hw_platform_subtype; +}; + +struct socinfo_v0_7 { + struct socinfo_v0_6 v0_6; + u32 pmic_model; + u32 pmic_die_revision; +}; + +struct socinfo_v0_8 { + struct socinfo_v0_7 v0_7; + u32 pmic_model_1; + u32 pmic_die_revision_1; + u32 pmic_model_2; + u32 pmic_die_revision_2; +}; + +struct socinfo_v0_9 { + struct socinfo_v0_8 v0_8; + u32 foundry_id; +}; + +struct socinfo_v0_10 { + struct socinfo_v0_9 v0_9; + u32 serial_number; +}; + +struct socinfo_v0_11 { + struct socinfo_v0_10 v0_10; + u32 num_pmics; + u32 pmic_array_offset; +}; + +struct socinfo_v0_12 { + struct socinfo_v0_11 v0_11; + u32 chip_family; + u32 raw_device_family; + u32 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; + +static struct smem_image_version *smem_image_version; +static u32 socinfo_format; + +/* max socinfo format version supported */ +#define MAX_SOCINFO_FORMAT 12 + +static const char *const cpu_of_id[] = { + + [0] = "Unknown CPU", + + /* 8x60 IDs */ + [87] = "MSM8960", + + /* 8x64 IDs */ + [109] = "APQ8064", + [130] = "MPQ8064", + + /* 8x60A IDs */ + [122] = "MSM8660A", + [123] = "MSM8260A", + [124] = "APQ8060A", + + /* 8x74 IDs */ + [126] = "MSM8974", + [184] = "APQ8074", + [185] = "MSM8274", + [186] = "MSM8674", + + /* 8x74AA IDs */ + [208] = "APQ8074-AA", + [211] = "MSM8274-AA", + [214] = "MSM8674-AA", + [217] = "MSM8974-AA", + + /* 8x74AB IDs */ + [209] = "APQ8074-AB", + [212] = "MSM8274-AB", + [215] = "MSM8674-AB", + [218] = "MSM8974-AB", + + /* 8x74AC IDs */ + [194] = "MSM8974PRO", + [210] = "APQ8074PRO", + [213] = "MSM8274PRO", + [216] = "MSM8674PRO", + + /* 8x60AB IDs */ + [138] = "MSM8960AB", + [139] = "APQ8060AB", + [140] = "MSM8260AB", + [141] = "MSM8660AB", + + /* 8x84 IDs */ + [178] = "APQ8084", + + /* 8x16 IDs */ + [206] = "MSM8916", + [247] = "APQ8016", + [248] = "MSM8216", + [249] = "MSM8116", + [250] = "MSM8616", + + /* 8x96 IDs */ + [246] = "MSM8996", + [310] = "MSM8996AU", + [311] = "APQ8096AU", + [291] = "APQ8096", + [305] = "MSM8996SG", + [312] = "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. + */ +}; + +/* socinfo: sysfs functions */ + +static ssize_t +qcom_show_vendor(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s", "Qualcomm\n"); +} + +static ssize_t +qcom_show_raw_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", socinfo->v0_2.raw_version); +} + +static ssize_t +qcom_show_build_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", socinfo->v0_1.build_id); +} + +static ssize_t +qcom_show_hw_platform(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", hw_platform[socinfo->v0_3.hw_platform]); +} + +static ssize_t +qcom_show_platform_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", socinfo->v0_4.platform_version); +} + +static ssize_t +qcom_show_accessory_chip(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", socinfo->v0_5.accessory_chip); +} + +static ssize_t +qcom_show_platform_subtype(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u32 hw_subtype = socinfo->v0_6.hw_platform_subtype; + + if (socinfo->v0_3.hw_platform == HW_PLATFORM_QRD) + if (hw_subtype >= 0 && + hw_subtype < PLATFORM_SUBTYPE_QRD_INVALID) + return sprintf(buf, "%s\n", + qrd_hw_platform_subtype[hw_subtype]); + else + return -EINVAL; + else + if (hw_subtype >= 0 && + hw_subtype < PLATFORM_SUBTYPE_INVALID) + return sprintf(buf, "%s\n", + hw_platform_subtype[hw_subtype]); + else + return -EINVAL; +} + +static ssize_t +qcom_show_platform_subtype_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", socinfo->v0_6.hw_platform_subtype); +} + +static ssize_t +qcom_show_foundry_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", socinfo->v0_9.foundry_id); +} + +static ssize_t +qcom_show_serial_number(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", socinfo->v0_10.serial_number); +} + +static ssize_t +qcom_show_chip_family(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "0x%x\n", socinfo->v0_12.chip_family); +} + +static ssize_t +qcom_show_raw_device_family(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "0x%x\n", socinfo->v0_12.raw_device_family); +} + +static ssize_t +qcom_show_raw_device_number(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "0x%x\n", socinfo->v0_12.raw_device_number); +} + +static ssize_t +qcom_show_pmic_model(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", pmic_model[socinfo->v0_7.pmic_model]); +} + +static ssize_t +qcom_show_pmic_die_revision(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", socinfo->v0_7.pmic_die_revision); +} + +static ssize_t +qcom_show_image_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dev_ext_attribute *dev_attr; + int index; + + dev_attr = container_of(attr, struct dev_ext_attribute, attr); + index = (unsigned long)(dev_attr->var); + return scnprintf(buf, PAGE_SIZE, "%s\n", + smem_image_version[index].name); +} + +static ssize_t +qcom_store_image_version(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *dev_attr; + int index; + + dev_attr = container_of(attr, struct dev_ext_attribute, attr); + index = (unsigned long)(dev_attr->var); + return strlcpy(smem_image_version[index].name, buf, + SMEM_IMAGE_VERSION_NAME_SIZE); +} + +static ssize_t +qcom_show_image_variant(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dev_ext_attribute *dev_attr; + int index; + + dev_attr = container_of(attr, struct dev_ext_attribute, attr); + index = (unsigned long)(dev_attr->var); + return scnprintf(buf, PAGE_SIZE, "%s\n", + smem_image_version[index].variant); +} + +static ssize_t +qcom_store_image_variant(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *dev_attr; + int index; + + dev_attr = container_of(attr, struct dev_ext_attribute, attr); + index = (unsigned long)(dev_attr->var); + return strlcpy(smem_image_version[index].variant, buf, + SMEM_IMAGE_VERSION_VARIANT_SIZE); +} + +static ssize_t +qcom_show_image_crm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dev_ext_attribute *dev_attr; + int index; + + dev_attr = container_of(attr, struct dev_ext_attribute, attr); + index = (unsigned long)(dev_attr->var); + return scnprintf(buf, PAGE_SIZE, "%s\n", + smem_image_version[index].oem); +} + +static ssize_t +qcom_store_image_crm(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *dev_attr; + int index; + + dev_attr = container_of(attr, struct dev_ext_attribute, attr); + index = (unsigned long)(dev_attr->var); + return strlcpy(smem_image_version[index].oem, buf, + SMEM_IMAGE_VERSION_OEM_SIZE); +} + +static const struct qcom_socinfo_attr qcom_socinfo_attrs[] = { + QCOM_SOCINFO_ATTR(chip_family, qcom_show_chip_family, 12), + QCOM_SOCINFO_ATTR(raw_device_family, qcom_show_raw_device_family, 12), + QCOM_SOCINFO_ATTR(raw_device_number, qcom_show_raw_device_number, 12), + QCOM_SOCINFO_ATTR(serial_number, qcom_show_serial_number, 10), + QCOM_SOCINFO_ATTR(foundry_id, qcom_show_foundry_id, 9), + QCOM_SOCINFO_ATTR(pmic_model, qcom_show_pmic_model, 7), + QCOM_SOCINFO_ATTR(pmic_die_revision, qcom_show_pmic_die_revision, 7), + QCOM_SOCINFO_ATTR(platform_subtype, qcom_show_platform_subtype, 6), + QCOM_SOCINFO_ATTR(platform_subtype_id, + qcom_show_platform_subtype_id, 6), + QCOM_SOCINFO_ATTR(accessory_chip, qcom_show_accessory_chip, 5), + QCOM_SOCINFO_ATTR(platform_version, qcom_show_platform_version, 4), + QCOM_SOCINFO_ATTR(hw_platform, qcom_show_hw_platform, 3), + QCOM_SOCINFO_ATTR(raw_version, qcom_show_raw_version, 2), + QCOM_SOCINFO_ATTR(build_id, qcom_show_build_id, 1), + QCOM_SOCINFO_ATTR(vendor, qcom_show_vendor, 0), +}; + +QCOM_SMEM_IMG_ITEM(boot, 0444, SMEM_IMAGE_TABLE_BOOT_INDEX); +QCOM_SMEM_IMG_ITEM(tz, 0444, SMEM_IMAGE_TABLE_TZ_INDEX); +QCOM_SMEM_IMG_ITEM(rpm, 0444, SMEM_IMAGE_TABLE_RPM_INDEX); +QCOM_SMEM_IMG_ITEM(apps, 0644, SMEM_IMAGE_TABLE_APPS_INDEX); +QCOM_SMEM_IMG_ITEM(mpss, 0444, SMEM_IMAGE_TABLE_MPSS_INDEX); +QCOM_SMEM_IMG_ITEM(adsp, 0444, SMEM_IMAGE_TABLE_ADSP_INDEX); +QCOM_SMEM_IMG_ITEM(cnss, 0444, SMEM_IMAGE_TABLE_CNSS_INDEX); +QCOM_SMEM_IMG_ITEM(video, 0444, SMEM_IMAGE_TABLE_VIDEO_INDEX); + +static struct attribute_group + *smem_image_table[SMEM_IMAGE_VERSION_BLOCKS_COUNT] = { + [SMEM_IMAGE_TABLE_BOOT_INDEX] = &boot_image_attr_group, + [SMEM_IMAGE_TABLE_TZ_INDEX] = &tz_image_attr_group, + [SMEM_IMAGE_TABLE_RPM_INDEX] = &rpm_image_attr_group, + [SMEM_IMAGE_TABLE_APPS_INDEX] = &apps_image_attr_group, + [SMEM_IMAGE_TABLE_MPSS_INDEX] = &mpss_image_attr_group, + [SMEM_IMAGE_TABLE_ADSP_INDEX] = &adsp_image_attr_group, + [SMEM_IMAGE_TABLE_CNSS_INDEX] = &cnss_image_attr_group, + [SMEM_IMAGE_TABLE_VIDEO_INDEX] = &video_image_attr_group, +}; + +static void socinfo_populate_sysfs_files(struct device *dev) +{ + int idx; + int err; + + /* + * Expose SMEM_IMAGE_TABLE to sysfs only when we have IMAGE_TABLE + * available in SMEM. As IMAGE_TABLE and SOCINFO are two separate + * items within SMEM, we expose the remaining soc information(i.e + * only the SOCINFO item available in SMEM) to sysfs even in the + * absence of an IMAGE_TABLE. + */ + if (smem_image_version) + for (idx = 0; idx < SMEM_IMAGE_VERSION_BLOCKS_COUNT; idx++) + if (smem_image_table[idx]) + err = sysfs_create_group(&dev->kobj, + smem_image_table[idx]); + + for (idx = 0; idx < MAX_ATTR_COUNT; idx++) + if (qcom_socinfo_attrs[idx].min_version <= socinfo_format) + device_create_file(dev, &qcom_socinfo_attrs[idx].attr); +} + +void qcom_socinfo_init(struct platform_device *pdev) +{ + struct soc_device_attribute *attr; + struct device *qcom_soc_device; + struct soc_device *soc_dev; + size_t img_tbl_size; + u32 soc_version; + size_t size; + + socinfo = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, + &size); + if (IS_ERR(socinfo)) { + dev_err(&pdev->dev, "Coudn't find socinfo.\n"); + return; + } + + if ((SOCINFO_VERSION_MAJOR(socinfo->v0_1.format) != 0) || + (SOCINFO_VERSION_MINOR(socinfo->v0_1.format) < 0) || + (socinfo->v0_1.format > MAX_SOCINFO_FORMAT)) { + dev_err(&pdev->dev, "Wrong socinfo format\n"); + return; + } + socinfo_format = socinfo->v0_1.format; + + if (!socinfo->v0_1.id) + dev_err(&pdev->dev, "socinfo: Unknown SoC ID!\n"); + + WARN(socinfo->v0_1.id >= ARRAY_SIZE(cpu_of_id), + "New IDs added! ID => CPU mapping needs an update.\n"); + + smem_image_version = qcom_smem_get(QCOM_SMEM_HOST_ANY, + SMEM_IMAGE_VERSION_TABLE, + &img_tbl_size); + if (IS_ERR(smem_image_version) || + (img_tbl_size != SMEM_IMAGE_VERSION_SIZE)) { + dev_warn(&pdev->dev, "Image version table absent.\n"); + smem_image_version = NULL; + } + + attr = kzalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) { + dev_err(&pdev->dev, "Unable to allocate attributes.\n"); + return; + } + soc_version = socinfo->v0_1.version; + + attr->soc_id = kasprintf(GFP_KERNEL, "%d", socinfo->v0_1.id); + attr->family = "Snapdragon"; + attr->machine = cpu_of_id[socinfo->v0_1.id]; + attr->revision = kasprintf(GFP_KERNEL, "%u.%u", + SOC_VERSION_MAJOR(soc_version), + SOC_VERSION_MINOR(soc_version)); + + soc_dev = soc_device_register(attr); + if (IS_ERR(soc_dev)) { + kfree(attr); + return; + } + + qcom_soc_device = soc_device_to_device(soc_dev); + socinfo_populate_sysfs_files(qcom_soc_device); + + /* Feed the soc specific unique data into entropy pool */ + add_device_randomness(socinfo, size); +} +EXPORT_SYMBOL(qcom_socinfo_init); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project