|
13 | 13 | #include <linux/platform_device.h>
|
14 | 14 | #include <linux/seq_file.h>
|
15 | 15 |
|
| 16 | +#include <linux/soc/qcom/qcom_aoss.h> |
16 | 17 | #include <linux/soc/qcom/smem.h>
|
17 | 18 | #include <clocksource/arm_arch_timer.h>
|
18 | 19 |
|
|
37 | 38 | #define DDR_STATS_TYPE(data) FIELD_GET(GENMASK(15, 8), data)
|
38 | 39 | #define DDR_STATS_FREQ(data) FIELD_GET(GENMASK(31, 16), data)
|
39 | 40 |
|
| 41 | +static struct qmp *qcom_stats_qmp; |
| 42 | + |
40 | 43 | struct subsystem_data {
|
41 | 44 | const char *name;
|
42 | 45 | u32 smem_item;
|
@@ -188,12 +191,28 @@ static int qcom_ddr_stats_show(struct seq_file *s, void *d)
|
188 | 191 | struct ddr_stats_entry data[DDR_STATS_MAX_NUM_MODES];
|
189 | 192 | void __iomem *reg = (void __iomem *)s->private;
|
190 | 193 | u32 entry_count;
|
191 |
| - int i; |
| 194 | + int i, ret; |
192 | 195 |
|
193 | 196 | entry_count = readl_relaxed(reg + DDR_STATS_NUM_MODES_ADDR);
|
194 | 197 | if (entry_count > DDR_STATS_MAX_NUM_MODES)
|
195 | 198 | return -EINVAL;
|
196 | 199 |
|
| 200 | + if (qcom_stats_qmp) { |
| 201 | + /* |
| 202 | + * Recent SoCs (SM8450 onwards) do not have duration field |
| 203 | + * populated from boot up onwards for both DDR LPM Stats |
| 204 | + * and DDR Frequency Stats. |
| 205 | + * |
| 206 | + * Send QMP message to Always on processor which will |
| 207 | + * populate duration field into MSG RAM area. |
| 208 | + * |
| 209 | + * Sent every time to read latest data. |
| 210 | + */ |
| 211 | + ret = qmp_send(qcom_stats_qmp, "{class: ddr, action: freqsync}"); |
| 212 | + if (ret) |
| 213 | + return ret; |
| 214 | + } |
| 215 | + |
197 | 216 | reg += DDR_STATS_ENTRY_START_ADDR;
|
198 | 217 | memcpy_fromio(data, reg, sizeof(struct ddr_stats_entry) * entry_count);
|
199 | 218 |
|
@@ -304,6 +323,21 @@ static int qcom_stats_probe(struct platform_device *pdev)
|
304 | 323 |
|
305 | 324 | for (i = 0; i < config->num_records; i++)
|
306 | 325 | d[i].appended_stats_avail = config->appended_stats_avail;
|
| 326 | + /* |
| 327 | + * QMP is used for DDR stats syncing to MSG RAM for recent SoCs (SM8450 onwards). |
| 328 | + * The prior SoCs do not need QMP handle as the required stats are already present |
| 329 | + * in MSG RAM, provided the DDR_STATS_MAGIC_KEY matches. |
| 330 | + */ |
| 331 | + qcom_stats_qmp = qmp_get(&pdev->dev); |
| 332 | + if (IS_ERR(qcom_stats_qmp)) { |
| 333 | + /* We ignore error if QMP is not defined/needed */ |
| 334 | + if (!of_property_present(pdev->dev.of_node, "qcom,qmp")) |
| 335 | + qcom_stats_qmp = NULL; |
| 336 | + else if (PTR_ERR(qcom_stats_qmp) == -EPROBE_DEFER) |
| 337 | + return -EPROBE_DEFER; |
| 338 | + else |
| 339 | + return PTR_ERR(qcom_stats_qmp); |
| 340 | + } |
307 | 341 |
|
308 | 342 | root = debugfs_create_dir("qcom_stats", NULL);
|
309 | 343 |
|
|
0 commit comments