Commit 3dc8dcb0 authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'qcom-drivers-for-5.4' of...

Merge tag 'qcom-drivers-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/drivers

Qualcomm ARM Based Driver Updates for v5.4

* Add AOSS QMP support
* Various fixups for Qualcomm SCM
* Add socinfo driver
* Add SoC serial number attribute and associated APIs
* Add SM8150 and SC7180 support in Qualcomm SCM
* Fixup max processor count in SMEM

* tag 'qcom-drivers-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux:
  soc: qcom: aoss: Add AOSS QMP support
  dt-bindings: soc: qcom: aoss: Add SM8150 and SC7180 support
  dt-bindings: firmware: scm: Add SM8150 and SC7180 support
  dt-bindings: firmware: scm: re-order compatible list
  soc: qcom: smem: Update max processor count
  soc: qcom: socinfo: Annotate switch cases with fall through
  soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.
  soc: qcom: socinfo: Expose image information
  soc: qcom: socinfo: Expose custom attributes
  soc: qcom: Add socinfo driver
  base: soc: Export soc_device_register/unregister APIs
  base: soc: Add serial_number attribute to soc
  firmware: qcom_scm: Cleanup code in qcom_scm_assign_mem()
  firmware: qcom_scm: Fix some typos in docs and printks
  firmware: qcom_scm: Use proper types for dma mappings
parents ef92bfda 17095102
...@@ -26,6 +26,13 @@ Description: ...@@ -26,6 +26,13 @@ Description:
Read-only attribute common to all SoCs. Contains SoC family name Read-only attribute common to all SoCs. Contains SoC family name
(e.g. DB8500). (e.g. DB8500).
What: /sys/devices/socX/serial_number
Date: January 2019
contact: Bjorn Andersson <bjorn.andersson@linaro.org>
Description:
Read-only attribute supported by most SoCs. Contains the SoC's
serial number, if available.
What: /sys/devices/socX/soc_id What: /sys/devices/socX/soc_id
Date: January 2012 Date: January 2012
contact: Lee Jones <lee.jones@linaro.org> contact: Lee Jones <lee.jones@linaro.org>
......
...@@ -9,14 +9,16 @@ Required properties: ...@@ -9,14 +9,16 @@ Required properties:
- compatible: must contain one of the following: - compatible: must contain one of the following:
* "qcom,scm-apq8064" * "qcom,scm-apq8064"
* "qcom,scm-apq8084" * "qcom,scm-apq8084"
* "qcom,scm-ipq4019"
* "qcom,scm-msm8660" * "qcom,scm-msm8660"
* "qcom,scm-msm8916" * "qcom,scm-msm8916"
* "qcom,scm-msm8960" * "qcom,scm-msm8960"
* "qcom,scm-msm8974" * "qcom,scm-msm8974"
* "qcom,scm-msm8996" * "qcom,scm-msm8996"
* "qcom,scm-msm8998" * "qcom,scm-msm8998"
* "qcom,scm-ipq4019" * "qcom,scm-sc7180"
* "qcom,scm-sdm845" * "qcom,scm-sdm845"
* "qcom,scm-sm8150"
and: and:
* "qcom,scm" * "qcom,scm"
- clocks: Specifies clocks needed by the SCM interface, if any: - clocks: Specifies clocks needed by the SCM interface, if any:
......
...@@ -15,7 +15,10 @@ power-domains. ...@@ -15,7 +15,10 @@ power-domains.
- compatible: - compatible:
Usage: required Usage: required
Value type: <string> Value type: <string>
Definition: must be "qcom,sdm845-aoss-qmp" Definition: must be one of:
"qcom,sc7180-aoss-qmp"
"qcom,sdm845-aoss-qmp"
"qcom,sm8150-aoss-qmp"
- reg: - reg:
Usage: required Usage: required
......
...@@ -33,6 +33,7 @@ static struct bus_type soc_bus_type = { ...@@ -33,6 +33,7 @@ static struct bus_type soc_bus_type = {
static DEVICE_ATTR(machine, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(machine, S_IRUGO, soc_info_get, NULL);
static DEVICE_ATTR(family, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(family, S_IRUGO, soc_info_get, NULL);
static DEVICE_ATTR(serial_number, S_IRUGO, soc_info_get, NULL);
static DEVICE_ATTR(soc_id, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(soc_id, S_IRUGO, soc_info_get, NULL);
static DEVICE_ATTR(revision, S_IRUGO, soc_info_get, NULL); static DEVICE_ATTR(revision, S_IRUGO, soc_info_get, NULL);
...@@ -57,6 +58,9 @@ static umode_t soc_attribute_mode(struct kobject *kobj, ...@@ -57,6 +58,9 @@ static umode_t soc_attribute_mode(struct kobject *kobj,
if ((attr == &dev_attr_revision.attr) if ((attr == &dev_attr_revision.attr)
&& (soc_dev->attr->revision != NULL)) && (soc_dev->attr->revision != NULL))
return attr->mode; return attr->mode;
if ((attr == &dev_attr_serial_number.attr)
&& (soc_dev->attr->serial_number != NULL))
return attr->mode;
if ((attr == &dev_attr_soc_id.attr) if ((attr == &dev_attr_soc_id.attr)
&& (soc_dev->attr->soc_id != NULL)) && (soc_dev->attr->soc_id != NULL))
return attr->mode; return attr->mode;
...@@ -77,6 +81,8 @@ static ssize_t soc_info_get(struct device *dev, ...@@ -77,6 +81,8 @@ static ssize_t soc_info_get(struct device *dev,
return sprintf(buf, "%s\n", soc_dev->attr->family); return sprintf(buf, "%s\n", soc_dev->attr->family);
if (attr == &dev_attr_revision) if (attr == &dev_attr_revision)
return sprintf(buf, "%s\n", soc_dev->attr->revision); return sprintf(buf, "%s\n", soc_dev->attr->revision);
if (attr == &dev_attr_serial_number)
return sprintf(buf, "%s\n", soc_dev->attr->serial_number);
if (attr == &dev_attr_soc_id) if (attr == &dev_attr_soc_id)
return sprintf(buf, "%s\n", soc_dev->attr->soc_id); return sprintf(buf, "%s\n", soc_dev->attr->soc_id);
...@@ -87,6 +93,7 @@ static ssize_t soc_info_get(struct device *dev, ...@@ -87,6 +93,7 @@ static ssize_t soc_info_get(struct device *dev,
static struct attribute *soc_attr[] = { static struct attribute *soc_attr[] = {
&dev_attr_machine.attr, &dev_attr_machine.attr,
&dev_attr_family.attr, &dev_attr_family.attr,
&dev_attr_serial_number.attr,
&dev_attr_soc_id.attr, &dev_attr_soc_id.attr,
&dev_attr_revision.attr, &dev_attr_revision.attr,
NULL, NULL,
...@@ -157,6 +164,7 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr ...@@ -157,6 +164,7 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
out1: out1:
return ERR_PTR(ret); return ERR_PTR(ret);
} }
EXPORT_SYMBOL_GPL(soc_device_register);
/* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */ /* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
void soc_device_unregister(struct soc_device *soc_dev) void soc_device_unregister(struct soc_device *soc_dev)
...@@ -166,6 +174,7 @@ void soc_device_unregister(struct soc_device *soc_dev) ...@@ -166,6 +174,7 @@ void soc_device_unregister(struct soc_device *soc_dev)
device_unregister(&soc_dev->dev); device_unregister(&soc_dev->dev);
early_soc_dev_attr = NULL; early_soc_dev_attr = NULL;
} }
EXPORT_SYMBOL_GPL(soc_device_unregister);
static int __init soc_bus_register(void) static int __init soc_bus_register(void)
{ {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/dma-direct.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -425,21 +426,23 @@ EXPORT_SYMBOL(qcom_scm_set_remote_state); ...@@ -425,21 +426,23 @@ EXPORT_SYMBOL(qcom_scm_set_remote_state);
* @mem_sz: size of the region. * @mem_sz: size of the region.
* @srcvm: vmid for current set of owners, each set bit in * @srcvm: vmid for current set of owners, each set bit in
* flag indicate a unique owner * flag indicate a unique owner
* @newvm: array having new owners and corrsponding permission * @newvm: array having new owners and corresponding permission
* flags * flags
* @dest_cnt: number of owners in next set. * @dest_cnt: number of owners in next set.
* *
* Return negative errno on failure, 0 on success, with @srcvm updated. * Return negative errno on failure or 0 on success with @srcvm updated.
*/ */
int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
unsigned int *srcvm, unsigned int *srcvm,
struct qcom_scm_vmperm *newvm, int dest_cnt) const struct qcom_scm_vmperm *newvm,
unsigned int dest_cnt)
{ {
struct qcom_scm_current_perm_info *destvm; struct qcom_scm_current_perm_info *destvm;
struct qcom_scm_mem_map_info *mem_to_map; struct qcom_scm_mem_map_info *mem_to_map;
phys_addr_t mem_to_map_phys; phys_addr_t mem_to_map_phys;
phys_addr_t dest_phys; phys_addr_t dest_phys;
phys_addr_t ptr_phys; phys_addr_t ptr_phys;
dma_addr_t ptr_dma;
size_t mem_to_map_sz; size_t mem_to_map_sz;
size_t dest_sz; size_t dest_sz;
size_t src_sz; size_t src_sz;
...@@ -447,52 +450,50 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, ...@@ -447,52 +450,50 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
int next_vm; int next_vm;
__le32 *src; __le32 *src;
void *ptr; void *ptr;
int ret; int ret, i, b;
int len; unsigned long srcvm_bits = *srcvm;
int i;
src_sz = hweight_long(*srcvm) * sizeof(*src); src_sz = hweight_long(srcvm_bits) * sizeof(*src);
mem_to_map_sz = sizeof(*mem_to_map); mem_to_map_sz = sizeof(*mem_to_map);
dest_sz = dest_cnt * sizeof(*destvm); dest_sz = dest_cnt * sizeof(*destvm);
ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) + ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) +
ALIGN(dest_sz, SZ_64); ALIGN(dest_sz, SZ_64);
ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL); ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_dma, GFP_KERNEL);
if (!ptr) if (!ptr)
return -ENOMEM; return -ENOMEM;
ptr_phys = dma_to_phys(__scm->dev, ptr_dma);
/* Fill source vmid detail */ /* Fill source vmid detail */
src = ptr; src = ptr;
len = hweight_long(*srcvm); i = 0;
for (i = 0; i < len; i++) { for_each_set_bit(b, &srcvm_bits, BITS_PER_LONG)
src[i] = cpu_to_le32(ffs(*srcvm) - 1); src[i++] = cpu_to_le32(b);
*srcvm ^= 1 << (ffs(*srcvm) - 1);
}
/* Fill details of mem buff to map */ /* Fill details of mem buff to map */
mem_to_map = ptr + ALIGN(src_sz, SZ_64); mem_to_map = ptr + ALIGN(src_sz, SZ_64);
mem_to_map_phys = ptr_phys + ALIGN(src_sz, SZ_64); mem_to_map_phys = ptr_phys + ALIGN(src_sz, SZ_64);
mem_to_map[0].mem_addr = cpu_to_le64(mem_addr); mem_to_map->mem_addr = cpu_to_le64(mem_addr);
mem_to_map[0].mem_size = cpu_to_le64(mem_sz); mem_to_map->mem_size = cpu_to_le64(mem_sz);
next_vm = 0; next_vm = 0;
/* Fill details of next vmid detail */ /* Fill details of next vmid detail */
destvm = ptr + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64); destvm = ptr + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64);
dest_phys = ptr_phys + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64); dest_phys = ptr_phys + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64);
for (i = 0; i < dest_cnt; i++) { for (i = 0; i < dest_cnt; i++, destvm++, newvm++) {
destvm[i].vmid = cpu_to_le32(newvm[i].vmid); destvm->vmid = cpu_to_le32(newvm->vmid);
destvm[i].perm = cpu_to_le32(newvm[i].perm); destvm->perm = cpu_to_le32(newvm->perm);
destvm[i].ctx = 0; destvm->ctx = 0;
destvm[i].ctx_size = 0; destvm->ctx_size = 0;
next_vm |= BIT(newvm[i].vmid); next_vm |= BIT(newvm->vmid);
} }
ret = __qcom_scm_assign_mem(__scm->dev, mem_to_map_phys, mem_to_map_sz, ret = __qcom_scm_assign_mem(__scm->dev, mem_to_map_phys, mem_to_map_sz,
ptr_phys, src_sz, dest_phys, dest_sz); ptr_phys, src_sz, dest_phys, dest_sz);
dma_free_coherent(__scm->dev, ALIGN(ptr_sz, SZ_64), ptr, ptr_phys); dma_free_coherent(__scm->dev, ptr_sz, ptr, ptr_dma);
if (ret) { if (ret) {
dev_err(__scm->dev, dev_err(__scm->dev,
"Assign memory protection call failed %d.\n", ret); "Assign memory protection call failed %d\n", ret);
return -EINVAL; return -EINVAL;
} }
......
...@@ -175,6 +175,14 @@ config QCOM_SMSM ...@@ -175,6 +175,14 @@ config QCOM_SMSM
Say yes here to support the Qualcomm Shared Memory State Machine. Say yes here to support the Qualcomm Shared Memory State Machine.
The state machine is represented by bits in shared memory. The state machine is represented by bits in shared memory.
config QCOM_SOCINFO
tristate "Qualcomm socinfo driver"
depends on QCOM_SMEM
select SOC_BUS
help
Say yes here to support the Qualcomm socinfo driver, providing
information about the SoC to user space.
config QCOM_WCNSS_CTRL config QCOM_WCNSS_CTRL
tristate "Qualcomm WCNSS control driver" tristate "Qualcomm WCNSS control driver"
depends on ARCH_QCOM || COMPILE_TEST depends on ARCH_QCOM || COMPILE_TEST
......
...@@ -18,6 +18,7 @@ obj-$(CONFIG_QCOM_SMEM) += smem.o ...@@ -18,6 +18,7 @@ obj-$(CONFIG_QCOM_SMEM) += smem.o
obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
obj-$(CONFIG_QCOM_APR) += apr.o obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/thermal.h>
#include <linux/slab.h>
#define QMP_DESC_MAGIC 0x0 #define QMP_DESC_MAGIC 0x0
#define QMP_DESC_VERSION 0x4 #define QMP_DESC_VERSION 0x4
...@@ -40,6 +42,17 @@ ...@@ -40,6 +42,17 @@
/* 64 bytes is enough to store the requests and provides padding to 4 bytes */ /* 64 bytes is enough to store the requests and provides padding to 4 bytes */
#define QMP_MSG_LEN 64 #define QMP_MSG_LEN 64
#define QMP_NUM_COOLING_RESOURCES 2
static bool qmp_cdev_init_state = 1;
struct qmp_cooling_device {
struct thermal_cooling_device *cdev;
struct qmp *qmp;
char *name;
bool state;
};
/** /**
* struct qmp - driver state for QMP implementation * struct qmp - driver state for QMP implementation
* @msgram: iomem referencing the message RAM used for communication * @msgram: iomem referencing the message RAM used for communication
...@@ -69,6 +82,7 @@ struct qmp { ...@@ -69,6 +82,7 @@ struct qmp {
struct clk_hw qdss_clk; struct clk_hw qdss_clk;
struct genpd_onecell_data pd_data; struct genpd_onecell_data pd_data;
struct qmp_cooling_device *cooling_devs;
}; };
struct qmp_pd { struct qmp_pd {
...@@ -385,6 +399,118 @@ static void qmp_pd_remove(struct qmp *qmp) ...@@ -385,6 +399,118 @@ static void qmp_pd_remove(struct qmp *qmp)
pm_genpd_remove(data->domains[i]); pm_genpd_remove(data->domains[i]);
} }
static int qmp_cdev_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
*state = qmp_cdev_init_state;
return 0;
}
static int qmp_cdev_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct qmp_cooling_device *qmp_cdev = cdev->devdata;
*state = qmp_cdev->state;
return 0;
}
static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct qmp_cooling_device *qmp_cdev = cdev->devdata;
char buf[QMP_MSG_LEN] = {};
bool cdev_state;
int ret;
/* Normalize state */
cdev_state = !!state;
if (qmp_cdev->state == state)
return 0;
snprintf(buf, sizeof(buf),
"{class: volt_flr, event:zero_temp, res:%s, value:%s}",
qmp_cdev->name,
cdev_state ? "off" : "on");
ret = qmp_send(qmp_cdev->qmp, buf, sizeof(buf));
if (!ret)
qmp_cdev->state = cdev_state;
return ret;
}
static struct thermal_cooling_device_ops qmp_cooling_device_ops = {
.get_max_state = qmp_cdev_get_max_state,
.get_cur_state = qmp_cdev_get_cur_state,
.set_cur_state = qmp_cdev_set_cur_state,
};
static int qmp_cooling_device_add(struct qmp *qmp,
struct qmp_cooling_device *qmp_cdev,
struct device_node *node)
{
char *cdev_name = (char *)node->name;
qmp_cdev->qmp = qmp;
qmp_cdev->state = qmp_cdev_init_state;
qmp_cdev->name = cdev_name;
qmp_cdev->cdev = devm_thermal_of_cooling_device_register
(qmp->dev, node,
cdev_name,
qmp_cdev, &qmp_cooling_device_ops);
if (IS_ERR(qmp_cdev->cdev))
dev_err(qmp->dev, "unable to register %s cooling device\n",
cdev_name);
return PTR_ERR_OR_ZERO(qmp_cdev->cdev);
}
static int qmp_cooling_devices_register(struct qmp *qmp)
{
struct device_node *np, *child;
int count = QMP_NUM_COOLING_RESOURCES;
int ret;
np = qmp->dev->of_node;
qmp->cooling_devs = devm_kcalloc(qmp->dev, count,
sizeof(*qmp->cooling_devs),
GFP_KERNEL);
if (!qmp->cooling_devs)
return -ENOMEM;
for_each_available_child_of_node(np, child) {
if (!of_find_property(child, "#cooling-cells", NULL))
continue;
ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++],
child);
if (ret)
goto unroll;
}
return 0;
unroll:
while (--count >= 0)
thermal_cooling_device_unregister
(qmp->cooling_devs[count].cdev);
return ret;
}
static void qmp_cooling_devices_remove(struct qmp *qmp)
{
int i;
for (i = 0; i < QMP_NUM_COOLING_RESOURCES; i++)
thermal_cooling_device_unregister(qmp->cooling_devs[i].cdev);
}
static int qmp_probe(struct platform_device *pdev) static int qmp_probe(struct platform_device *pdev)
{ {
struct resource *res; struct resource *res;
...@@ -433,6 +559,10 @@ static int qmp_probe(struct platform_device *pdev) ...@@ -433,6 +559,10 @@ static int qmp_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_remove_qdss_clk; goto err_remove_qdss_clk;
ret = qmp_cooling_devices_register(qmp);
if (ret)
dev_err(&pdev->dev, "failed to register aoss cooling devices\n");
platform_set_drvdata(pdev, qmp); platform_set_drvdata(pdev, qmp);
return 0; return 0;
...@@ -453,6 +583,7 @@ static int qmp_remove(struct platform_device *pdev) ...@@ -453,6 +583,7 @@ static int qmp_remove(struct platform_device *pdev)
qmp_qdss_clk_remove(qmp); qmp_qdss_clk_remove(qmp);
qmp_pd_remove(qmp); qmp_pd_remove(qmp);
qmp_cooling_devices_remove(qmp);
qmp_close(qmp); qmp_close(qmp);
mbox_free_channel(qmp->mbox_chan); mbox_free_channel(qmp->mbox_chan);
...@@ -461,7 +592,9 @@ static int qmp_remove(struct platform_device *pdev) ...@@ -461,7 +592,9 @@ static int qmp_remove(struct platform_device *pdev)
} }
static const struct of_device_id qmp_dt_match[] = { static const struct of_device_id qmp_dt_match[] = {
{ .compatible = "qcom,sc7180-aoss-qmp", },
{ .compatible = "qcom,sdm845-aoss-qmp", }, { .compatible = "qcom,sdm845-aoss-qmp", },
{ .compatible = "qcom,sm8150-aoss-qmp", },
{} {}
}; };
MODULE_DEVICE_TABLE(of, qmp_dt_match); MODULE_DEVICE_TABLE(of, qmp_dt_match);
......
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
#define SMEM_GLOBAL_HOST 0xfffe #define SMEM_GLOBAL_HOST 0xfffe
/* Max number of processors/hosts in a system */ /* Max number of processors/hosts in a system */
#define SMEM_HOST_COUNT 10 #define SMEM_HOST_COUNT 11
/** /**
* struct smem_proc_comm - proc_comm communication struct (legacy) * struct smem_proc_comm - proc_comm communication struct (legacy)
...@@ -268,6 +268,7 @@ struct qcom_smem { ...@@ -268,6 +268,7 @@ struct qcom_smem {
struct smem_partition_header *partitions[SMEM_HOST_COUNT]; struct smem_partition_header *partitions[SMEM_HOST_COUNT];
size_t cacheline[SMEM_HOST_COUNT]; size_t cacheline[SMEM_HOST_COUNT];
u32 item_count; u32 item_count;
struct platform_device *socinfo;
unsigned num_regions; unsigned num_regions;
struct smem_region regions[]; struct smem_region regions[];
...@@ -963,11 +964,19 @@ static int qcom_smem_probe(struct platform_device *pdev) ...@@ -963,11 +964,19 @@ static int qcom_smem_probe(struct platform_device *pdev)
__smem = smem; __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");
return 0; return 0;
} }
static int qcom_smem_remove(struct platform_device *pdev) static int qcom_smem_remove(struct platform_device *pdev)
{ {
platform_device_unregister(__smem->socinfo);
hwspin_lock_free(__smem->hwlock); hwspin_lock_free(__smem->hwlock);
__smem = NULL; __smem = NULL;
......
// 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/string.h>
#include <linux/sys_soc.h>
#include <linux/types.h>
/*
* SoC version type with major number in the upper 16 bits and minor
* number in the lower 16 bits.
*/
#define SOCINFO_MAJOR(ver) (((ver) >> 16) & 0xffff)
#define SOCINFO_MINOR(ver) ((ver) & 0xffff)
#define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16)|((min) & 0xffff))
#define SMEM_SOCINFO_BUILD_ID_LENGTH 32
/*
* SMEM item id, used to acquire handles to respective
* SMEM region.
*/
#define SMEM_HW_SW_BUILD_ID 137
#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_RPM_INDEX 3
#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_VERSION_TABLE 469
/*
* SMEM Image table names
*/
static const char *const socinfo_image_names[] = {
[SMEM_IMAGE_TABLE_ADSP_INDEX] = "adsp",
[SMEM_IMAGE_TABLE_APPS_INDEX] = "apps",
[SMEM_IMAGE_TABLE_BOOT_INDEX] = "boot",
[SMEM_IMAGE_TABLE_CNSS_INDEX] = "cnss",
[SMEM_IMAGE_TABLE_MPSS_INDEX] = "mpss",
[SMEM_IMAGE_TABLE_RPM_INDEX] = "rpm",
[SMEM_IMAGE_TABLE_TZ_INDEX] = "tz",
[SMEM_IMAGE_TABLE_VIDEO_INDEX] = "video",
};
static const char *const pmic_models[] = {
[0] = "Unknown PMIC model",
[9] = "PM8994",
[11] = "PM8916",
[13] = "PM8058",
[14] = "PM8028",
[15] = "PM8901",
[16] = "PM8027",
[17] = "ISL9519",
[18] = "PM8921",
[19] = "PM8018",
[20] = "PM8015",
[21] = "PM8014",
[22] = "PM8821",
[23] = "PM8038",
[24] = "PM8922",
[25] = "PM8917",
};
#endif /* CONFIG_DEBUG_FS */
/* Socinfo SMEM item structure */
struct socinfo {
__le32 fmt;
__le32 id;
__le32 ver;
char build_id[SMEM_SOCINFO_BUILD_ID_LENGTH];
/* Version 2 */
__le32 raw_id;
__le32 raw_ver;
/* Version 3 */
__le32 hw_plat;
/* Version 4 */
__le32 plat_ver;
/* Version 5 */
__le32 accessory_chip;
/* Version 6 */
__le32 hw_plat_subtype;
/* Version 7 */
__le32 pmic_model;
__le32 pmic_die_rev;
/* Version 8 */
__le32 pmic_model_1;
__le32 pmic_die_rev_1;
__le32 pmic_model_2;
__le32 pmic_die_rev_2;
/* Version 9 */
__le32 foundry_id;
/* Version 10 */
__le32 serial_num;
/* Version 11 */
__le32 num_pmics;
__le32 pmic_array_offset;
/* Version 12 */
__le32 chip_family;
__le32 raw_device_family;
__le32 raw_device_num;
};
#ifdef CONFIG_DEBUG_FS
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;
};
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[] = {
{ 87, "MSM8960" },
{ 109, "APQ8064" },
{ 122, "MSM8660A" },
{ 123, "MSM8260A" },
{ 124, "APQ8060A" },
{ 126, "MSM8974" },
{ 130, "MPQ8064" },
{ 138, "MSM8960AB" },
{ 139, "APQ8060AB" },
{ 140, "MSM8260AB" },
{ 141, "MSM8660AB" },
{ 178, "APQ8084" },
{ 184, "APQ8074" },
{ 185, "MSM8274" },
{ 186, "MSM8674" },
{ 194, "MSM8974PRO" },
{ 206, "MSM8916" },
{ 208, "APQ8074-AA" },
{ 209, "APQ8074-AB" },
{ 210, "APQ8074PRO" },
{ 211, "MSM8274-AA" },
{ 212, "MSM8274-AB" },
{ 213, "MSM8274PRO" },
{ 214, "MSM8674-AA" },
{ 215, "MSM8674-AB" },
{ 216, "MSM8674PRO" },
{ 217, "MSM8974-AA" },
{ 218, "MSM8974-AB" },
{ 246, "MSM8996" },
{ 247, "APQ8016" },
{ 248, "MSM8216" },
{ 249, "MSM8116" },
{ 250, "MSM8616" },
{ 291, "APQ8096" },
{ 305, "MSM8996SG" },
{ 310, "MSM8996AU" },
{ 311, "APQ8096AU" },
{ 312, "APQ8096SG" },
};
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), 0400, \
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;
seq_printf(seq, "%s\n", pmic_models[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;
}
QCOM_OPEN(build_id, qcom_show_build_id);
QCOM_OPEN(pmic_model, qcom_show_pmic_model);
QCOM_OPEN(pmic_die_rev, qcom_show_pmic_die_revision);
#define DEFINE_IMAGE_OPS(type) \
static int show_image_##type(struct seq_file *seq, void *p) \
{ \
struct smem_image_version *image_version = seq->private; \
seq_puts(seq, image_version->type); \
seq_puts(seq, "\n"); \
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)
{
struct smem_image_version *versions;
struct dentry *dentry;
size_t size;
int i;
qcom_socinfo->dbg_root = debugfs_create_dir("qcom_socinfo", NULL);
qcom_socinfo->info.fmt = __le32_to_cpu(info->fmt);
switch (qcom_socinfo->info.fmt) {
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", 0400, qcom_socinfo->dbg_root,
&qcom_socinfo->info.chip_family);
debugfs_create_x32("raw_device_family", 0400,
qcom_socinfo->dbg_root,
&qcom_socinfo->info.raw_device_family);
debugfs_create_x32("raw_device_number", 0400,
qcom_socinfo->dbg_root,
&qcom_socinfo->info.raw_device_num);
/* Fall through */
case SOCINFO_VERSION(0, 11):
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", 0400, qcom_socinfo->dbg_root,
&qcom_socinfo->info.foundry_id);
/* Fall through */
case SOCINFO_VERSION(0, 8):
case SOCINFO_VERSION(0, 7):
DEBUGFS_ADD(info, pmic_model);
DEBUGFS_ADD(info, pmic_die_rev);
/* Fall through */
case SOCINFO_VERSION(0, 6):
qcom_socinfo->info.hw_plat_subtype =
__le32_to_cpu(info->hw_plat_subtype);
debugfs_create_u32("hardware_platform_subtype", 0400,
qcom_socinfo->dbg_root,
&qcom_socinfo->info.hw_plat_subtype);
/* Fall through */
case SOCINFO_VERSION(0, 5):
qcom_socinfo->info.accessory_chip =
__le32_to_cpu(info->accessory_chip);
debugfs_create_u32("accessory_chip", 0400,
qcom_socinfo->dbg_root,
&qcom_socinfo->info.accessory_chip);
/* Fall through */
case SOCINFO_VERSION(0, 4):
qcom_socinfo->info.plat_ver = __le32_to_cpu(info->plat_ver);
debugfs_create_u32("platform_version", 0400,
qcom_socinfo->dbg_root,
&qcom_socinfo->info.plat_ver);
/* Fall through */
case SOCINFO_VERSION(0, 3):
qcom_socinfo->info.hw_plat = __le32_to_cpu(info->hw_plat);
debugfs_create_u32("hardware_platform", 0400,
qcom_socinfo->dbg_root,
&qcom_socinfo->info.hw_plat);
/* Fall through */
case SOCINFO_VERSION(0, 2):
qcom_socinfo->info.raw_ver = __le32_to_cpu(info->raw_ver);
debugfs_create_u32("raw_version", 0400, qcom_socinfo->dbg_root,
&qcom_socinfo->info.raw_ver);
/* Fall through */
case SOCINFO_VERSION(0, 1):
DEBUGFS_ADD(info, build_id);
break;
}
versions = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_IMAGE_VERSION_TABLE,
&size);
for (i = 0; i < ARRAY_SIZE(socinfo_image_names); i++) {
if (!socinfo_image_names[i])
continue;
dentry = debugfs_create_dir(socinfo_image_names[i],
qcom_socinfo->dbg_root);
debugfs_create_file("name", 0400, dentry, &versions[i],
&qcom_image_name_ops);
debugfs_create_file("variant", 0400, dentry, &versions[i],
&qcom_image_variant_ops);
debugfs_create_file("oem", 0400, dentry, &versions[i],
&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)
{
}
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.revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u.%u",
SOCINFO_MAJOR(le32_to_cpu(info->ver)),
SOCINFO_MINOR(le32_to_cpu(info->ver)));
if (offsetof(struct socinfo, serial_num) <= item_size)
qs->attr.serial_number = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%u",
le32_to_cpu(info->serial_num));
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);
/* Feed the soc specific unique data into entropy pool */
add_device_randomness(info, item_size);
platform_set_drvdata(pdev, qs->soc_dev);
return 0;
}
static int 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);
return 0;
}
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");
...@@ -49,8 +49,9 @@ extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, ...@@ -49,8 +49,9 @@ extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
extern int qcom_scm_pas_auth_and_reset(u32 peripheral); extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
extern int qcom_scm_pas_shutdown(u32 peripheral); extern int qcom_scm_pas_shutdown(u32 peripheral);
extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
unsigned int *src, struct qcom_scm_vmperm *newvm, unsigned int *src,
int dest_cnt); const struct qcom_scm_vmperm *newvm,
unsigned int dest_cnt);
extern void qcom_scm_cpu_power_down(u32 flags); extern void qcom_scm_cpu_power_down(u32 flags);
extern u32 qcom_scm_get_version(void); extern u32 qcom_scm_get_version(void);
extern int qcom_scm_set_remote_state(u32 state, u32 id); extern int qcom_scm_set_remote_state(u32 state, u32 id);
...@@ -87,8 +88,8 @@ qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; } ...@@ -87,8 +88,8 @@ qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; }
static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; } static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; }
static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
unsigned int *src, unsigned int *src,
struct qcom_scm_vmperm *newvm, const struct qcom_scm_vmperm *newvm,
int dest_cnt) { return -ENODEV; } unsigned int dest_cnt) { return -ENODEV; }
static inline void qcom_scm_cpu_power_down(u32 flags) {} static inline void qcom_scm_cpu_power_down(u32 flags) {}
static inline u32 qcom_scm_get_version(void) { return 0; } static inline u32 qcom_scm_get_version(void) { return 0; }
static inline u32 static inline u32
......
...@@ -12,6 +12,7 @@ struct soc_device_attribute { ...@@ -12,6 +12,7 @@ struct soc_device_attribute {
const char *machine; const char *machine;
const char *family; const char *family;
const char *revision; const char *revision;
const char *serial_number;
const char *soc_id; const char *soc_id;
const void *data; const void *data;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment