[PATCH V2 1/3] soc: qcom: dcc: Add bootconfig support for DCC

From: Souradeep Chowdhury
Date: Mon Jan 23 2023 - 22:54:14 EST


Add bootconfig parser for DCC which is used to configure addresses
in DCC during boot time. This is needed to debug crashes that can happen
during boot-time. The expected format of a bootconfig file is as follows:-

dcc_config {
link_list_<The list number to configure> {
id = <The list number to configure>
items = <Address as same format as dcc separated by '_'>,
}
}

Example:-

dcc_config {
link_list_6 {
id = 6
items = R_0x1781005c_1_apb,
R_0x1782005c_1_apb
}
}

Signed-off-by: Souradeep Chowdhury <quic_schowdhu@xxxxxxxxxxx>
---
drivers/soc/qcom/Kconfig | 1 +
drivers/soc/qcom/dcc.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 21c4ce2..f913b72 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -73,6 +73,7 @@ config QCOM_LLCC
config QCOM_DCC
tristate "Qualcomm Technologies, Inc. Data Capture and Compare(DCC) engine driver"
depends on ARCH_QCOM || COMPILE_TEST
+ select BOOT_CONFIG
help
This option enables driver for Data Capture and Compare engine. DCC
driver provides interface to configure DCC block and read back
diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
index 5b50d63..93e8f86 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -6,6 +6,7 @@

#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/bootconfig.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/fs.h>
@@ -148,6 +149,18 @@ struct dcc_cfg_loop_attr {
bool loop_start;
};

+static char *replace_char(char *str, char find, char replace)
+{
+ char *current_pos = strchr(str, find);
+
+ while (current_pos) {
+ *current_pos = replace;
+ current_pos = strchr(current_pos, find);
+ }
+
+ return str;
+}
+
static inline u32 dcc_list_offset(int version)
{
return version == 1 ? 0x1c : version == 2 ? 0x2c : 0x34;
@@ -1185,13 +1198,62 @@ static void dcc_sram_dev_exit(struct dcc_drvdata *drvdata)
misc_deregister(&drvdata->sram_dev);
}

-static int dcc_probe(struct platform_device *pdev)
+static int __init dcc_bootconfig_parse(struct dcc_drvdata *drvdata, struct xbc_node *dcc_node)
+{
+ struct xbc_node *linked_list, *node;
+ int curr_list, ret;
+ const char *p;
+ char *input, *token;
+ char val[30];
+
+ xbc_node_for_each_subkey(dcc_node, linked_list) {
+ p = xbc_node_find_value(linked_list, "id", &node);
+ if (p) {
+ ret = kstrtoint(p, 0, &curr_list);
+ if (ret)
+ return ret;
+ } else {
+ dev_err(drvdata->dev, "List number not specified\n");
+ continue;
+ }
+
+ p = xbc_node_find_value(linked_list, "items", &node);
+ if (!p)
+ continue;
+ xbc_array_for_each_value(node, p) {
+ strcpy(val, p);
+ input = replace_char(val, '_', ' ');
+ token = strsep(&input, " ");
+
+ if (!strcmp("R", token)) {
+ ret = dcc_config_add_read(drvdata, input, curr_list);
+ } else if (!strcmp("W", token)) {
+ ret = dcc_config_add_write(drvdata, input, curr_list);
+ } else if (!strcmp("RW", token)) {
+ ret = dcc_config_add_read_write(drvdata, input, curr_list);
+ } else if (!strcmp("L", token)) {
+ ret = dcc_config_add_loop(drvdata, input, curr_list);
+ } else {
+ dev_err(drvdata->dev, "%s is not a correct input\n", token);
+ return -EINVAL;
+ }
+ if (ret)
+ return ret;
+ }
+ dcc_enable(drvdata, curr_list);
+ }
+
+ return 0;
+}
+
+static int __init dcc_probe(struct platform_device *pdev)
{
u32 val;
int ret = 0, i;
struct device *dev = &pdev->dev;
struct dcc_drvdata *drvdata;
struct resource *res;
+ struct xbc_node *dcc_node;

drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
@@ -1263,6 +1325,13 @@ static int dcc_probe(struct platform_device *pdev)

dcc_create_debug_dir(drvdata);

+ dcc_node = xbc_find_node("dcc_config");
+ if (dcc_node) {
+ ret = dcc_bootconfig_parse(drvdata, dcc_node);
+ if (ret)
+ dev_err(drvdata->dev, "DCC: Bootconfig parse error.\n");
+ }
+
return 0;
}

@@ -1287,14 +1356,13 @@ static const struct of_device_id dcc_match_table[] = {
MODULE_DEVICE_TABLE(of, dcc_match_table);

static struct platform_driver dcc_driver = {
- .probe = dcc_probe,
.remove = dcc_remove,
.driver = {
.name = "qcom-dcc",
.of_match_table = dcc_match_table,
},
};
-module_platform_driver(dcc_driver);
+module_platform_driver_probe(dcc_driver, dcc_probe);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Qualcomm Technologies Inc. DCC driver");
--
2.7.4