diff options
-rw-r--r-- | drivers/soc/qcom/qcom_stats.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 33fd2a157446..2e380faf9080 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/seq_file.h> +#include <linux/soc/qcom/qcom_aoss.h> #include <linux/soc/qcom/smem.h> #include <clocksource/arm_arch_timer.h> @@ -37,6 +38,8 @@ #define DDR_STATS_TYPE(data) FIELD_GET(GENMASK(15, 8), data) #define DDR_STATS_FREQ(data) FIELD_GET(GENMASK(31, 16), data) +static struct qmp *qcom_stats_qmp; + struct subsystem_data { const char *name; u32 smem_item; @@ -188,12 +191,28 @@ static int qcom_ddr_stats_show(struct seq_file *s, void *d) struct ddr_stats_entry data[DDR_STATS_MAX_NUM_MODES]; void __iomem *reg = (void __iomem *)s->private; u32 entry_count; - int i; + int i, ret; entry_count = readl_relaxed(reg + DDR_STATS_NUM_MODES_ADDR); if (entry_count > DDR_STATS_MAX_NUM_MODES) return -EINVAL; + if (qcom_stats_qmp) { + /* + * Recent SoCs (SM8450 onwards) do not have duration field + * populated from boot up onwards for both DDR LPM Stats + * and DDR Frequency Stats. + * + * Send QMP message to Always on processor which will + * populate duration field into MSG RAM area. + * + * Sent every time to read latest data. + */ + ret = qmp_send(qcom_stats_qmp, "{class: ddr, action: freqsync}"); + if (ret) + return ret; + } + reg += DDR_STATS_ENTRY_START_ADDR; memcpy_fromio(data, reg, sizeof(struct ddr_stats_entry) * entry_count); @@ -304,6 +323,21 @@ static int qcom_stats_probe(struct platform_device *pdev) for (i = 0; i < config->num_records; i++) d[i].appended_stats_avail = config->appended_stats_avail; + /* + * QMP is used for DDR stats syncing to MSG RAM for recent SoCs (SM8450 onwards). + * The prior SoCs do not need QMP handle as the required stats are already present + * in MSG RAM, provided the DDR_STATS_MAGIC_KEY matches. + */ + qcom_stats_qmp = qmp_get(&pdev->dev); + if (IS_ERR(qcom_stats_qmp)) { + /* We ignore error if QMP is not defined/needed */ + if (!of_property_present(pdev->dev.of_node, "qcom,qmp")) + qcom_stats_qmp = NULL; + else if (PTR_ERR(qcom_stats_qmp) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else + return PTR_ERR(qcom_stats_qmp); + } root = debugfs_create_dir("qcom_stats", NULL); |