mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 22:21:42 +00:00
soc: qcom: aoss: Add debugfs interface for sending messages
In addition to the normal runtime commands, the Always On Processor (AOP) provides a number of debug commands which can be used during system debugging for things such as preventing power collapse or placing floor votes for certain resources. Some of these are documented in the Robotics RB5 "Debug AOP ADB" linked below. Provide a debugfs interface for the developer/tester to send some of these commands to the AOP, which allow the user to override the DDR frequency, preventing power collapse of cx and ddr, and prevent AOSS from going to sleep. Link: https://docs.qualcomm.com/bundle/publicresource/topics/80-88500-3/85_Debugging_AOP_ADB.html Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com> Reviewed-by: Chris Lew <quic_clew@quicinc.com> Link: https://lore.kernel.org/r/20240117-qcom-aoss-debugfs-v2-v3-1-1aa779124822@quicinc.com [bjorn: Dropped S_IWGRP from the debugfs files] Signed-off-by: Bjorn Andersson <andersson@kernel.org>
This commit is contained in:
parent
27825593c9
commit
d51d984c55
@ -3,6 +3,7 @@
|
||||
* Copyright (c) 2019, Linaro Ltd
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
@ -44,6 +45,8 @@
|
||||
|
||||
#define QMP_NUM_COOLING_RESOURCES 2
|
||||
|
||||
#define QMP_DEBUGFS_FILES 4
|
||||
|
||||
static bool qmp_cdev_max_state = 1;
|
||||
|
||||
struct qmp_cooling_device {
|
||||
@ -82,6 +85,8 @@ struct qmp {
|
||||
|
||||
struct clk_hw qdss_clk;
|
||||
struct qmp_cooling_device *cooling_devs;
|
||||
struct dentry *debugfs_root;
|
||||
struct dentry *debugfs_files[QMP_DEBUGFS_FILES];
|
||||
};
|
||||
|
||||
static void qmp_kick(struct qmp *qmp)
|
||||
@ -475,6 +480,91 @@ void qmp_put(struct qmp *qmp)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qmp_put);
|
||||
|
||||
struct qmp_debugfs_entry {
|
||||
const char *name;
|
||||
const char *fmt;
|
||||
bool is_bool;
|
||||
const char *true_val;
|
||||
const char *false_val;
|
||||
};
|
||||
|
||||
static const struct qmp_debugfs_entry qmp_debugfs_entries[QMP_DEBUGFS_FILES] = {
|
||||
{ "ddr_frequency_mhz", "{class: ddr, res: fixed, val: %u}", false },
|
||||
{ "prevent_aoss_sleep", "{class: aoss_slp, res: sleep: %s}", true, "enable", "disable" },
|
||||
{ "prevent_cx_collapse", "{class: cx_mol, res: cx, val: %s}", true, "mol", "off" },
|
||||
{ "prevent_ddr_collapse", "{class: ddr_mol, res: ddr, val: %s}", true, "mol", "off" },
|
||||
};
|
||||
|
||||
static ssize_t qmp_debugfs_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
const struct qmp_debugfs_entry *entry = NULL;
|
||||
struct qmp *qmp = file->private_data;
|
||||
char buf[QMP_MSG_LEN];
|
||||
unsigned int uint_val;
|
||||
const char *str_val;
|
||||
bool bool_val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(qmp->debugfs_files); i++) {
|
||||
if (qmp->debugfs_files[i] == file->f_path.dentry) {
|
||||
entry = &qmp_debugfs_entries[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (WARN_ON(!entry))
|
||||
return -EFAULT;
|
||||
|
||||
if (entry->is_bool) {
|
||||
ret = kstrtobool_from_user(user_buf, count, &bool_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
str_val = bool_val ? entry->true_val : entry->false_val;
|
||||
|
||||
ret = snprintf(buf, sizeof(buf), entry->fmt, str_val);
|
||||
if (ret >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
ret = kstrtou32_from_user(user_buf, count, 0, &uint_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snprintf(buf, sizeof(buf), entry->fmt, uint_val);
|
||||
if (ret >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = qmp_send(qmp, buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations qmp_debugfs_fops = {
|
||||
.open = simple_open,
|
||||
.write = qmp_debugfs_write,
|
||||
};
|
||||
|
||||
static void qmp_debugfs_create(struct qmp *qmp)
|
||||
{
|
||||
const struct qmp_debugfs_entry *entry;
|
||||
int i;
|
||||
|
||||
qmp->debugfs_root = debugfs_create_dir("qcom_aoss", NULL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(qmp->debugfs_files); i++) {
|
||||
entry = &qmp_debugfs_entries[i];
|
||||
|
||||
qmp->debugfs_files[i] = debugfs_create_file(entry->name, 0200,
|
||||
qmp->debugfs_root,
|
||||
qmp,
|
||||
&qmp_debugfs_fops);
|
||||
}
|
||||
}
|
||||
|
||||
static int qmp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct qmp *qmp;
|
||||
@ -523,6 +613,8 @@ static int qmp_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, qmp);
|
||||
|
||||
qmp_debugfs_create(qmp);
|
||||
|
||||
return 0;
|
||||
|
||||
err_close_qmp:
|
||||
@ -537,6 +629,8 @@ static void qmp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct qmp *qmp = platform_get_drvdata(pdev);
|
||||
|
||||
debugfs_remove_recursive(qmp->debugfs_root);
|
||||
|
||||
qmp_qdss_clk_remove(qmp);
|
||||
qmp_cooling_devices_remove(qmp);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user