Skip to content

Commit 33301e5

Browse files
maulik-k-shahandersson
authored andcommitted
soc: qcom: qcom_stats: Add support to read DDR statistic
DDR statistic provide different DDR LPM and DDR frequency statistic. Add support to read from MSGRAM and display via debugfs. Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Signed-off-by: Maulik Shah <maulik.shah@oss.qualcomm.com> Link: https://lore.kernel.org/r/20250611-ddr_stats_-v5-1-24b16dd67c9c@oss.qualcomm.com Signed-off-by: Bjorn Andersson <andersson@kernel.org>
1 parent 47e339c commit 33301e5

1 file changed

Lines changed: 99 additions & 0 deletions

File tree

drivers/soc/qcom/qcom_stats.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/*
33
* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved.
4+
* Copyright (c) 2022-2025, Qualcomm Innovation Center, Inc. All rights reserved.
45
*/
56

7+
#include <linux/bitfield.h>
68
#include <linux/debugfs.h>
79
#include <linux/device.h>
810
#include <linux/io.h>
@@ -24,6 +26,17 @@
2426
#define ACCUMULATED_OFFSET 0x18
2527
#define CLIENT_VOTES_OFFSET 0x20
2628

29+
#define DDR_STATS_MAGIC_KEY 0xA1157A75
30+
#define DDR_STATS_MAX_NUM_MODES 20
31+
#define DDR_STATS_MAGIC_KEY_ADDR 0x0
32+
#define DDR_STATS_NUM_MODES_ADDR 0x4
33+
#define DDR_STATS_ENTRY_START_ADDR 0x8
34+
35+
#define DDR_STATS_CP_IDX(data) FIELD_GET(GENMASK(4, 0), data)
36+
#define DDR_STATS_LPM_NAME(data) FIELD_GET(GENMASK(7, 0), data)
37+
#define DDR_STATS_TYPE(data) FIELD_GET(GENMASK(15, 8), data)
38+
#define DDR_STATS_FREQ(data) FIELD_GET(GENMASK(31, 16), data)
39+
2740
struct subsystem_data {
2841
const char *name;
2942
u32 smem_item;
@@ -48,12 +61,19 @@ static const struct subsystem_data subsystems[] = {
4861

4962
struct stats_config {
5063
size_t stats_offset;
64+
size_t ddr_stats_offset;
5165
size_t num_records;
5266
bool appended_stats_avail;
5367
bool dynamic_offset;
5468
bool subsystem_stats_in_smem;
5569
};
5670

71+
struct ddr_stats_entry {
72+
u32 name;
73+
u32 count;
74+
u64 duration;
75+
};
76+
5777
struct stats_data {
5878
bool appended_stats_avail;
5979
void __iomem *base;
@@ -122,8 +142,85 @@ static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused)
122142
return 0;
123143
}
124144

145+
static void qcom_ddr_stats_print(struct seq_file *s, struct ddr_stats_entry *data)
146+
{
147+
u32 cp_idx;
148+
149+
/*
150+
* DDR statistic have two different types of details encoded.
151+
* (1) DDR LPM Stats
152+
* (2) DDR Frequency Stats
153+
*
154+
* The name field have details like which type of DDR stat (bits 8:15)
155+
* along with other details as explained below
156+
*
157+
* In case of DDR LPM stat, name field will be encoded as,
158+
* Bits - Meaning
159+
* 0:7 - DDR LPM name, can be of 0xd4, 0xd3, 0x11 and 0xd0.
160+
* 8:15 - 0x0 (indicates its a LPM stat)
161+
* 16:31 - Unused
162+
*
163+
* In case of DDR FREQ stats, name field will be encoded as,
164+
* Bits - Meaning
165+
* 0:4 - DDR Clock plan index (CP IDX)
166+
* 5:7 - Unused
167+
* 8:15 - 0x1 (indicates its Freq stat)
168+
* 16:31 - Frequency value in Mhz
169+
*/
170+
switch (DDR_STATS_TYPE(data->name)) {
171+
case 0:
172+
seq_printf(s, "DDR LPM Stat Name:0x%lx\tcount:%u\tDuration (ticks):%llu\n",
173+
DDR_STATS_LPM_NAME(data->name), data->count, data->duration);
174+
break;
175+
case 1:
176+
if (!data->count || !DDR_STATS_FREQ(data->name))
177+
return;
178+
179+
cp_idx = DDR_STATS_CP_IDX(data->name);
180+
seq_printf(s, "DDR Freq %luMhz:\tCP IDX:%u\tcount:%u\tDuration (ticks):%llu\n",
181+
DDR_STATS_FREQ(data->name), cp_idx, data->count, data->duration);
182+
break;
183+
}
184+
}
185+
186+
static int qcom_ddr_stats_show(struct seq_file *s, void *d)
187+
{
188+
struct ddr_stats_entry data[DDR_STATS_MAX_NUM_MODES];
189+
void __iomem *reg = (void __iomem *)s->private;
190+
u32 entry_count;
191+
int i;
192+
193+
entry_count = readl_relaxed(reg + DDR_STATS_NUM_MODES_ADDR);
194+
if (entry_count > DDR_STATS_MAX_NUM_MODES)
195+
return -EINVAL;
196+
197+
reg += DDR_STATS_ENTRY_START_ADDR;
198+
memcpy_fromio(data, reg, sizeof(struct ddr_stats_entry) * entry_count);
199+
200+
for (i = 0; i < entry_count; i++)
201+
qcom_ddr_stats_print(s, &data[i]);
202+
203+
return 0;
204+
}
205+
125206
DEFINE_SHOW_ATTRIBUTE(qcom_soc_sleep_stats);
126207
DEFINE_SHOW_ATTRIBUTE(qcom_subsystem_sleep_stats);
208+
DEFINE_SHOW_ATTRIBUTE(qcom_ddr_stats);
209+
210+
static void qcom_create_ddr_stat_files(struct dentry *root, void __iomem *reg,
211+
const struct stats_config *config)
212+
{
213+
u32 key;
214+
215+
if (!config->ddr_stats_offset)
216+
return;
217+
218+
key = readl_relaxed(reg + config->ddr_stats_offset + DDR_STATS_MAGIC_KEY_ADDR);
219+
if (key == DDR_STATS_MAGIC_KEY)
220+
debugfs_create_file("ddr_stats", 0400, root,
221+
(__force void *)reg + config->ddr_stats_offset,
222+
&qcom_ddr_stats_fops);
223+
}
127224

128225
static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *reg,
129226
struct stats_data *d,
@@ -212,6 +309,7 @@ static int qcom_stats_probe(struct platform_device *pdev)
212309

213310
qcom_create_subsystem_stat_files(root, config);
214311
qcom_create_soc_sleep_stat_files(root, reg, d, config);
312+
qcom_create_ddr_stat_files(root, reg, config);
215313

216314
platform_set_drvdata(pdev, root);
217315

@@ -254,6 +352,7 @@ static const struct stats_config rpmh_data_sdm845 = {
254352

255353
static const struct stats_config rpmh_data = {
256354
.stats_offset = 0x48,
355+
.ddr_stats_offset = 0xb8,
257356
.num_records = 3,
258357
.appended_stats_avail = false,
259358
.dynamic_offset = false,

0 commit comments

Comments
 (0)