diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index ab2b54be26fa..1ae35a767c56 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -114,6 +114,7 @@ static const char *const pmic_models[] = { #endif /* CONFIG_DEBUG_FS */ static uint32_t socinfo_format; +static const char *sku; enum { HW_PLATFORM_UNKNOWN = 0, @@ -195,6 +196,37 @@ static const char * const hw_platform_subtype[] = { [PLATFORM_SUBTYPE_INVALID] = "Invalid", }; +static const char * const hw_platform_feature_code[] = { + [SOCINFO_FC_UNKNOWN] = "Unknown", + [SOCINFO_FC_AA] = "AA", + [SOCINFO_FC_AB] = "AB", + [SOCINFO_FC_AC] = "AC", + [SOCINFO_FC_AD] = "AD", + [SOCINFO_FC_AE] = "AE", + [SOCINFO_FC_AF] = "AF", + [SOCINFO_FC_AG] = "AG", + [SOCINFO_FC_AH] = "AH", +}; + +static const char * const hw_platform_ifeature_code[] = { + [SOCINFO_FC_Y0 - SOCINFO_FC_Y0] = "Y0", + [SOCINFO_FC_Y1 - SOCINFO_FC_Y0] = "Y1", + [SOCINFO_FC_Y2 - SOCINFO_FC_Y0] = "Y2", + [SOCINFO_FC_Y3 - SOCINFO_FC_Y0] = "Y3", + [SOCINFO_FC_Y4 - SOCINFO_FC_Y0] = "Y4", + [SOCINFO_FC_Y5 - SOCINFO_FC_Y0] = "Y5", + [SOCINFO_FC_Y6 - SOCINFO_FC_Y0] = "Y6", + [SOCINFO_FC_Y7 - SOCINFO_FC_Y0] = "Y7", + [SOCINFO_FC_Y8 - SOCINFO_FC_Y0] = "Y8", + [SOCINFO_FC_Y9 - SOCINFO_FC_Y0] = "Y9", + [SOCINFO_FC_YA - SOCINFO_FC_Y0] = "YA", + [SOCINFO_FC_YB - SOCINFO_FC_Y0] = "YB", + [SOCINFO_FC_YC - SOCINFO_FC_Y0] = "YC", + [SOCINFO_FC_YD - SOCINFO_FC_Y0] = "YD", + [SOCINFO_FC_YE - SOCINFO_FC_Y0] = "YE", + [SOCINFO_FC_YF - SOCINFO_FC_Y0] = "YF", +}; + /* Socinfo SMEM item structure */ struct socinfo { __le32 fmt; @@ -242,12 +274,20 @@ struct socinfo { /* Version 15 */ __le32 nmodem_supported; /* Version 16 */ - __le32 esku; - __le32 nproduct_code; + __le32 feature_code; + __le32 pcode; __le32 npartnamemap_offset; __le32 nnum_partname_mapping; } *socinfo; +#define PART_NAME_MAX 32 +struct socinfo_partinfo { + __le32 part_type; + char part_name[PART_NAME_MAX]; + __le32 part_name_len; +}; +struct socinfo_partinfo partinfo[SOCINFO_PART_MAX_PARTTYPE]; + #ifdef CONFIG_DEBUG_FS struct socinfo_params { u32 raw_device_family; @@ -444,6 +484,47 @@ static uint32_t socinfo_get_nmodem_supported(void) : 0; } +/* Version 16 */ +static uint32_t socinfo_get_feature_code_id(void) +{ + uint32_t fc_id; + + if (!socinfo || socinfo_format < SOCINFO_VERSION(0, 16)) + return SOCINFO_FC_UNKNOWN; + + fc_id = le32_to_cpu(socinfo->feature_code); + if (fc_id <= SOCINFO_FC_UNKNOWN || fc_id >= SOCINFO_FC_INT_RESERVE) + return SOCINFO_FC_UNKNOWN; + + return fc_id; +} + +static const char *socinfo_get_feature_code_mapping(void) +{ + uint32_t id = socinfo_get_feature_code_id(); + + if (id > SOCINFO_FC_UNKNOWN && id < SOCINFO_FC_EXT_RESERVE) + return hw_platform_feature_code[id]; + else if (id >= SOCINFO_FC_Y0 && id < SOCINFO_FC_INT_RESERVE) + return hw_platform_ifeature_code[id - SOCINFO_FC_Y0]; + + return NULL; +} + +static uint32_t socinfo_get_pcode_id(void) +{ + uint32_t pcode; + + if (!socinfo || socinfo_format < SOCINFO_VERSION(0, 16)) + return SOCINFO_PCODE_RESERVE; + + pcode = le32_to_cpu(socinfo->pcode); + if (pcode <= SOCINFO_PCODE_UNKNOWN || pcode >= SOCINFO_PCODE_RESERVE) + return SOCINFO_PCODE_UNKNOWN; + + return pcode; +} + /* Version 2 */ static ssize_t msm_get_raw_id(struct device *dev, @@ -680,6 +761,36 @@ msm_get_nmodem_supported(struct device *dev, } ATTR_DEFINE(nmodem_supported); +/* Version 16 */ +static ssize_t +msm_get_sku(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%s\n", sku ? sku : "Unknown"); +} +ATTR_DEFINE(sku); + +static ssize_t +msm_get_pcode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "0x%x\n", socinfo_get_pcode_id()); +} +ATTR_DEFINE(pcode); + +static ssize_t +msm_get_feature_code(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const char *feature_code = socinfo_get_feature_code_mapping(); + + return sysfs_emit(buf, "%s\n", feature_code ? feature_code : "Unknown"); +} +ATTR_DEFINE(feature_code); + struct qcom_socinfo { struct soc_device *soc_dev; struct soc_device_attribute attr; @@ -1076,6 +1187,9 @@ static void socinfo_populate_sysfs(struct qcom_socinfo *qcom_socinfo) switch (socinfo_format) { case SOCINFO_VERSION(0, 16): + msm_custom_socinfo_attrs[i++] = &dev_attr_sku.attr; + msm_custom_socinfo_attrs[i++] = &dev_attr_feature_code.attr; + msm_custom_socinfo_attrs[i++] = &dev_attr_pcode.attr; fallthrough; case SOCINFO_VERSION(0, 15): msm_custom_socinfo_attrs[i++] = &dev_attr_nmodem_supported.attr; @@ -1363,7 +1477,7 @@ static void socinfo_print(void) break; case SOCINFO_VERSION(0, 16): - pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n 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 nproduct_id=0x%x num_clusters=0x%x ncluster_array_offset=0x%x num_defective_parts=0x%x ndefective_parts_array_offset=0x%x nmodem_supported=0x%x\n", + pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n 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 nproduct_id=0x%x num_clusters=0x%x ncluster_array_offset=0x%x num_defective_parts=0x%x ndefective_parts_array_offset=0x%x nmodem_supported=0x%x feature_code=0x%x pcode=0x%x sku=%s\n", f_maj, f_min, socinfo->id, v_maj, v_min, socinfo->raw_id, socinfo->raw_ver, socinfo->hw_plat, @@ -1383,7 +1497,10 @@ static void socinfo_print(void) socinfo->ncluster_array_offset, socinfo->num_defective_parts, socinfo->ndefective_parts_array_offset, - socinfo->nmodem_supported); + socinfo->nmodem_supported, + socinfo->feature_code, + socinfo->pcode, + sku ? sku : "Unknown"); break; default: @@ -1424,6 +1541,74 @@ uint32_t socinfo_get_serial_number(void) } EXPORT_SYMBOL(socinfo_get_serial_number); +int socinfo_get_feature_code(void) +{ + if (socinfo_format < SOCINFO_VERSION(0, 16)) { + pr_warn("socinfo: Feature code is not supported by bootloaders\n"); + return -EINVAL; + } + + return socinfo_get_feature_code_id(); +} +EXPORT_SYMBOL(socinfo_get_feature_code); + +int socinfo_get_pcode(void) +{ + if (socinfo_format < SOCINFO_VERSION(0, 16)) { + pr_warn("socinfo: pcode is not supported by bootloaders\n"); + return -EINVAL; + } + + return socinfo_get_pcode_id(); +} +EXPORT_SYMBOL(socinfo_get_pcode); + +char *socinfo_get_partinfo_details(unsigned int part_id) +{ + if (socinfo_format < SOCINFO_VERSION(0, 16) || part_id >= SOCINFO_PART_MAX_PARTTYPE) + return NULL; + + return partinfo[part_id].part_name; +} +EXPORT_SYMBOL(socinfo_get_partinfo_details); + +void socinfo_enumerate_partinfo_details(void) +{ + unsigned int partinfo_array_offset; + unsigned int nnum_partname_mapping; + void *ptr = socinfo; + int i, part_type, part_name_len; + + if (socinfo_format < SOCINFO_VERSION(0, 16)) + return; + + partinfo_array_offset = le32_to_cpu(socinfo->npartnamemap_offset); + nnum_partname_mapping = le32_to_cpu(socinfo->nnum_partname_mapping); + + if (nnum_partname_mapping > SOCINFO_PART_MAX_PARTTYPE) { + pr_warn("socinfo: Mismatch between bootloaders and hlos\n"); + return; + } + + ptr += partinfo_array_offset; + for (i = 0; i < nnum_partname_mapping; i++) { + part_type = get_unaligned_le32(ptr); + if (part_type > SOCINFO_PART_MAX_PARTTYPE) + pr_warn("socinfo: part type mismatch\n"); + + partinfo[part_type].part_type = part_type; + ptr += sizeof(u32); + strscpy(partinfo[part_type].part_name, ptr, PART_NAME_MAX); + part_name_len = strlen(partinfo[part_type].part_name); + ptr += PART_NAME_MAX; + if (part_name_len != get_unaligned_le32(ptr)) + pr_warn("socinfo: part info string length mismatch\n"); + + partinfo[part_type].part_name_len = part_name_len; + ptr += sizeof(u32); + } +} + #ifdef CONFIG_DEBUG_FS #define QCOM_OPEN(name, _func) \ @@ -1703,6 +1888,7 @@ static int qcom_socinfo_probe(struct platform_device *pdev) struct qcom_socinfo *qs; struct socinfo *info; size_t item_size; + const char *machine, *fc; info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, &item_size); @@ -1730,6 +1916,14 @@ static int qcom_socinfo_probe(struct platform_device *pdev) if (offsetof(struct socinfo, serial_num) <= item_size) qs->attr.serial_number = kasprintf(GFP_KERNEL, "%u", socinfo_get_serial_number()); + if (socinfo_format >= SOCINFO_VERSION(0, 16)) { + socinfo_enumerate_partinfo_details(); + machine = socinfo_machine(&pdev->dev, le32_to_cpu(info->id)); + fc = socinfo_get_feature_code_mapping(); + sku = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-%u-%s", + machine, socinfo_get_pcode_id(), fc); + } + qsocinfo = qs; init_rwsem(&qs->current_image_rwsem); socinfo_populate_sysfs(qs); diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 3f458a511322..f702515f0d48 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __SOC_QCOM_SOCINFO_H__ @@ -8,10 +9,78 @@ #include +enum feature_code { + /* External feature code */ + SOCINFO_FC_UNKNOWN = 0x0, + SOCINFO_FC_AA, + SOCINFO_FC_AB, + SOCINFO_FC_AC, + SOCINFO_FC_AD, + SOCINFO_FC_AE, + SOCINFO_FC_AF, + SOCINFO_FC_AG, + SOCINFO_FC_AH, + SOCINFO_FC_EXT_RESERVE, + + /* Internal feature code */ + SOCINFO_FC_Y0 = 0xf1, + SOCINFO_FC_Y1, + SOCINFO_FC_Y2, + SOCINFO_FC_Y3, + SOCINFO_FC_Y4, + SOCINFO_FC_Y5, + SOCINFO_FC_Y6, + SOCINFO_FC_Y7, + SOCINFO_FC_Y8, + SOCINFO_FC_Y9, + SOCINFO_FC_YA, + SOCINFO_FC_YB, + SOCINFO_FC_YC, + SOCINFO_FC_YD, + SOCINFO_FC_YE, + SOCINFO_FC_YF, + SOCINFO_FC_INT_RESERVE +}; + +enum pcode { + SOCINFO_PCODE_UNKNOWN = 0, + SOCINFO_PCODE_0, + SOCINFO_PCODE_1, + SOCINFO_PCODE_2, + SOCINFO_PCODE_3, + SOCINFO_PCODE_4, + SOCINFO_PCODE_5, + SOCINFO_PCODE_6, + SOCINFO_PCODE_7, + SOCINFO_PCODE_8, + SOCINFO_PCODE_RESERVE = 0x7fffffff +}; + +enum socinfo_parttype { + SOCINFO_PART_GPU, + SOCINFO_PART_VIDEO, + SOCINFO_PART_CAMERA, + SOCINFO_PART_DISPLAY, + SOCINFO_PART_AUDIO, + SOCINFO_PART_MODEM, + SOCINFO_PART_WLAN, + SOCINFO_PART_COMP, + SOCINFO_PART_SENSORS, + SOCINFO_PART_NPU, + SOCINFO_PART_SPSS, + SOCINFO_PART_NAV, + SOCINFO_PART_COMPUTE_1, + SOCINFO_PART_DISPLAY_1, + SOCINFO_PART_MAX_PARTTYPE +}; + #if IS_ENABLED(CONFIG_QCOM_SOCINFO) uint32_t socinfo_get_id(void); uint32_t socinfo_get_serial_number(void); const char *socinfo_get_id_string(void); +int socinfo_get_feature_code(void); +int socinfo_get_pcode(void); +char *socinfo_get_partinfo_details(unsigned int part_id); #else static inline uint32_t socinfo_get_id(void) { @@ -27,6 +96,18 @@ static inline const char *socinfo_get_id_string(void) { return "N/A"; } +int socinfo_get_feature_code(void) +{ + return -EINVAL; +} +int socinfo_get_pcode(void) +{ + return -EINVAL; +} +const char *socinfo_get_partinfo_details(unsigned int part_id) +{ + return NULL; +} #endif /* CONFIG_QCOM_SOCINFO */ #endif /* __SOC_QCOM_SOCINFO_H__ */