Re: [PATCH] soc: qcom: Add SoC info driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Thu, Oct 20, 2016 at 07:36:22PM +0530, Imran Khan wrote:
> 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@xxxxxxxxxxxxxx>
> ---
>  .../devicetree/bindings/soc/qcom/qcom,socinfo.txt  |   18 +
>  drivers/soc/qcom/socinfo.c                         | 1173 ++++++++++++++++++++

1173 lines!!!!!!  To latch smem entry and read/process those contents?

>  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";
> +	};

Let's drop adding a new binding.  Let's roll this into the smem driver itself.

> 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

This needs to be more specific.  SMEM_SOCINFO_XXX

> +#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
> +

<snip>

> +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,
> +};

Instead of having a dummy, can we just fail if we don't find a match?  And by
fail, I mean having an 'unknown' cpu?

> +
> +static char *socinfo_get_id_string(void)
> +{
> +	return (socinfo) ? cpu_of_id[socinfo->v0_1.id].soc_id_string : NULL;
> +}
> +

<snip>

> +uint32_t socinfo_get_id(void)
> +{
> +	return (socinfo) ? socinfo->v0_1.id : 0;
> +}
> +EXPORT_SYMBOL_GPL(socinfo_get_id);

Why do we have EXPORTS at all?  Drivers should be using compatibles to figure
out what they are.

<snip>

> +/* 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());
> +}
> +

<snip>

> +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;
> +}

Can we just remove this and just return whatever unknown values for the sysfs
entries?

> +
> +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;
> +	}
> +}
> +

<snip>

> +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,
> +	},
> +};

As mentioned above:
Perhaps we can forgo the separate platform driver and just roll this into the
smem driver that already exists.  You can create a device there and get the
right attributes for the system and setup your sysfs entries.

Maybe splitting off the sysfs into a separate file would also be good.  That
keeps it nice and clean and away from the main smem code.


> +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

You don't need this mess.  You could just build a compat match and match against
the root compatible.

> +
> +#define PLATFORM_SUBTYPE_MDM	1
> +#define PLATFORM_SUBTYPE_INTERPOSERV3 2
> +#define PLATFORM_SUBTYPE_SGLTE	6
> +

<snip>

> +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;

We shouldn't have APIs for this.  This was supposed to be userspace access only,
correct?


Andy
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux