From 485329fc6d1a98007d99f42286796bb1d640f65b Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Thu, 12 Sep 2019 13:11:11 +0800 Subject: [PATCH 1/2] coresight: csr: Add multiple CSR devices support Add a CSR device list in CSR driver to support multiple CSR devices. CSR device structure is initialized in probe and added to the list. Add CSR device structure as parameter of CSR function. Change the caller of CSR functions to align with this change. Change-Id: I15e979a517204ac37dbcc5defd78a0214f44ade8 Signed-off-by: Tingwei Zhang --- drivers/hwtracing/coresight/coresight-common.h | 10 ++++++++++ drivers/hwtracing/coresight/coresight-csr.c | 15 +++++++++++++++ drivers/hwtracing/coresight/coresight-tmc.c | 13 ++++++++++++- drivers/hwtracing/coresight/coresight-tmc.h | 2 ++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-common.h b/drivers/hwtracing/coresight/coresight-common.h index 5fa45c1c1d95..99f427d2d302 100644 --- a/drivers/hwtracing/coresight/coresight-common.h +++ b/drivers/hwtracing/coresight/coresight-common.h @@ -23,6 +23,14 @@ extern int coresight_csr_hwctrl_set(struct coresight_csr *csr, uint64_t addr, extern void coresight_csr_set_byte_cntr(struct coresight_csr *csr, uint32_t count); extern struct coresight_csr *coresight_csr_get(const char *name); +#if IS_ENABLED(CONFIG_OF) +extern int of_get_coresight_csr_name(struct device_node *node, + const char **csr_name); +#else +static inline int of_get_coresight_csr_name(struct device_node *node, + const char **csr_name){ return -EINVAL; } +#endif + #else static inline void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr) {} static inline void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr) {} @@ -33,6 +41,8 @@ static inline void coresight_csr_set_byte_cntr(struct coresight_csr *csr, uint32_t count) {} static inline struct coresight_csr *coresight_csr_get(const char *name) { return NULL; } +static inline int of_get_coresight_csr_name(struct device_node *node, + const char **csr_name){ return -EINVAL; } #endif #endif diff --git a/drivers/hwtracing/coresight/coresight-csr.c b/drivers/hwtracing/coresight/coresight-csr.c index 6b2a4aa76c62..3f48fe4ed1b2 100644 --- a/drivers/hwtracing/coresight/coresight-csr.c +++ b/drivers/hwtracing/coresight/coresight-csr.c @@ -248,6 +248,21 @@ struct coresight_csr *coresight_csr_get(const char *name) } EXPORT_SYMBOL(coresight_csr_get); +int of_get_coresight_csr_name(struct device_node *node, const char **csr_name) +{ + int ret; + struct device_node *csr_node; + + csr_node = of_parse_phandle(node, "coresight-csr", 0); + if (!csr_node) + return -EINVAL; + + ret = of_property_read_string(csr_node, "coresight-name", csr_name); + of_node_put(csr_node); + return ret; +} +EXPORT_SYMBOL(of_get_coresight_csr_name); + static ssize_t timestamp_show(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index be37aff573b4..2c67d489ea29 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012,2017,2019 The Linux Foundation. All rights reserved. * * Description: CoreSight Trace Memory Controller driver */ @@ -432,6 +432,17 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) else drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; + ret = of_get_coresight_csr_name(adev->dev.of_node, &drvdata->csr_name); + if (ret) + dev_dbg(dev, "No csr data\n"); + else { + drvdata->csr = coresight_csr_get(drvdata->csr_name); + if (IS_ERR(drvdata->csr)) { + dev_dbg(dev, "failed to get csr, defer probe\n"); + return -EPROBE_DEFER; + } + } + desc.dev = dev; desc.groups = coresight_tmc_groups; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 1ed50411cc3c..ac129cfe3487 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -203,6 +203,8 @@ struct tmc_drvdata { struct mutex idr_mutex; struct etr_buf *sysfs_buf; void *perf_data; + struct coresight_csr *csr; + const char *csr_name; }; struct etr_buf_operations { From fdc522c90f488c0dddb781ad36ec330b3cf696c8 Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Tue, 17 Sep 2019 19:03:59 +0800 Subject: [PATCH 2/2] coresight: Add snapshot of Coresight hwevent driver Add snapshot for coresight hwevent driver from msm-4.19 commit 64be469bda3ae ("power: smb1390-psy: Configure IREV and main's ICL to prevent IREV condition"). Make necessary change to adopt coresight framework change. Change-Id: I3f0d9259d4d0f5dd12d76b7fbdde92fcb681f4b6 Signed-off-by: Tingwei Zhang --- drivers/hwtracing/coresight/Kconfig | 10 + drivers/hwtracing/coresight/Makefile | 1 + .../hwtracing/coresight/coresight-hwevent.c | 350 ++++++++++++++++++ 3 files changed, 361 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-hwevent.c diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 621e8e18dde5..35ea35f79444 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -145,6 +145,16 @@ config CORESIGHT_CSR Those configuration registers can be used to control, various coresight configurations. +config CORESIGHT_HWEVENT + bool "CoreSight Hardware Event driver" + depends on CORESIGHT_STM + select CORESIGHT_CSR + help + This driver provides support for monitoring and tracing CoreSight + Hardware Event across STM interface. It configures Coresight + Hardware Event mux control registers to select hardware events + based on user input. + config CORESIGHT_DUMMY bool "Dummy driver support" help diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 96d3c7871696..00b64f9b2297 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o obj-$(CONFIG_CORESIGHT_TPDA) += coresight-tpda.o obj-$(CONFIG_CORESIGHT_TPDM) += coresight-tpdm.o +obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o obj-$(CONFIG_CORESIGHT_TGU) += coresight-tgu.o diff --git a/drivers/hwtracing/coresight/coresight-hwevent.c b/drivers/hwtracing/coresight/coresight-hwevent.c new file mode 100644 index 000000000000..13ba68adf3f1 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-hwevent.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2017, 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coresight-priv.h" + +struct hwevent_mux { + phys_addr_t start; + phys_addr_t end; +}; + +struct hwevent_drvdata { + struct device *dev; + struct coresight_device *csdev; + struct clk *clk; + struct mutex mutex; + int nr_hclk; + struct clk **hclk; + int nr_hreg; + struct regulator **hreg; + int nr_hmux; + struct hwevent_mux *hmux; + struct coresight_csr *csr; + const char *csr_name; +}; + +DEFINE_CORESIGHT_DEVLIST(hwevent_devs, "hwevent"); + +static int hwevent_enable(struct hwevent_drvdata *drvdata) +{ + int ret, i, j; + + ret = clk_prepare_enable(drvdata->clk); + if (ret) + return ret; + + for (i = 0; i < drvdata->nr_hreg; i++) { + ret = regulator_enable(drvdata->hreg[i]); + if (ret) + goto err0; + } + + for (j = 0; j < drvdata->nr_hclk; j++) { + ret = clk_prepare_enable(drvdata->hclk[j]); + if (ret) + goto err1; + } + return 0; +err1: + for (j--; j >= 0; j--) + clk_disable_unprepare(drvdata->hclk[j]); +err0: + for (i--; i >= 0; i--) + regulator_disable(drvdata->hreg[i]); + + clk_disable_unprepare(drvdata->clk); + return ret; +} + +static void hwevent_disable(struct hwevent_drvdata *drvdata) +{ + int i; + + clk_disable_unprepare(drvdata->clk); + for (i = 0; i < drvdata->nr_hclk; i++) + clk_disable_unprepare(drvdata->hclk[i]); + for (i = 0; i < drvdata->nr_hreg; i++) + regulator_disable(drvdata->hreg[i]); +} + +static ssize_t setreg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent); + void *hwereg; + unsigned long long addr; + unsigned long val; + int ret, i; + + if (sscanf(buf, "%llx %lx", &addr, &val) != 2) + return -EINVAL; + + mutex_lock(&drvdata->mutex); + ret = hwevent_enable(drvdata); + if (ret) { + mutex_unlock(&drvdata->mutex); + return ret; + } + + for (i = 0; i < drvdata->nr_hmux; i++) { + if ((addr >= drvdata->hmux[i].start) && + (addr < drvdata->hmux[i].end)) { + hwereg = ioremap(drvdata->hmux[i].start, + drvdata->hmux[i].end - + drvdata->hmux[i].start); + if (!hwereg) { + dev_err(dev, "unable to map address 0x%llx\n", + addr); + ret = -ENOMEM; + goto err; + } + writel_relaxed(val, hwereg + addr - + drvdata->hmux[i].start); + /* + * Ensure writes to hwevent control registers + * are completed before unmapping the address + */ + mb(); + iounmap(hwereg); + break; + } + } + + if (i == drvdata->nr_hmux) { + ret = coresight_csr_hwctrl_set(drvdata->csr, addr, val); + if (ret) { + dev_err(dev, "invalid mux control register address\n"); + ret = -EINVAL; + goto err; + } + } + + hwevent_disable(drvdata); + mutex_unlock(&drvdata->mutex); + return size; +err: + hwevent_disable(drvdata); + mutex_unlock(&drvdata->mutex); + return ret; +} +static DEVICE_ATTR_WO(setreg); + +static struct attribute *hwevent_attrs[] = { + &dev_attr_setreg.attr, + NULL, +}; + +static struct attribute_group hwevent_attr_grp = { + .attrs = hwevent_attrs, +}; + +static const struct attribute_group *hwevent_attr_grps[] = { + &hwevent_attr_grp, + NULL, +}; + +static int hwevent_init_hmux(struct hwevent_drvdata *drvdata, + struct platform_device *pdev) +{ + int ret, i; + struct resource *res; + const char *hmux_name; + struct device_node *node = drvdata->dev->of_node; + + drvdata->nr_hmux = of_property_count_strings(node, + "reg-names"); + + if (drvdata->nr_hmux < 0) + drvdata->nr_hmux = 0; + + if (drvdata->nr_hmux > 0) { + drvdata->hmux = devm_kzalloc(drvdata->dev, drvdata->nr_hmux * + sizeof(*drvdata->hmux), + GFP_KERNEL); + if (!drvdata->hmux) + return -ENOMEM; + for (i = 0; i < drvdata->nr_hmux; i++) { + ret = of_property_read_string_index(node, + "reg-names", i, + &hmux_name); + if (ret) + return ret; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + hmux_name); + if (!res) + return -ENODEV; + drvdata->hmux[i].start = res->start; + drvdata->hmux[i].end = res->end; + + } + } + + return 0; +} + +static int hwevent_init_clk(struct hwevent_drvdata *drvdata) +{ + int ret, i; + const char *hclk_name, *hreg_name; + struct device_node *node = drvdata->dev->of_node; + + drvdata->nr_hclk = of_property_count_strings(node, + "qcom,hwevent-clks"); + drvdata->nr_hreg = of_property_count_strings(node, + "qcom,hwevent-regs"); + + if (drvdata->nr_hclk > 0) { + drvdata->hclk = devm_kzalloc(drvdata->dev, drvdata->nr_hclk * + sizeof(*drvdata->hclk), + GFP_KERNEL); + if (!drvdata->hclk) + return -ENOMEM; + + for (i = 0; i < drvdata->nr_hclk; i++) { + ret = of_property_read_string_index(node, + "qcom,hwevent-clks", + i, &hclk_name); + if (ret) + return ret; + + drvdata->hclk[i] = devm_clk_get(drvdata->dev, + hclk_name); + if (IS_ERR(drvdata->hclk[i])) + return PTR_ERR(drvdata->hclk[i]); + } + } + if (drvdata->nr_hreg > 0) { + drvdata->hreg = devm_kzalloc(drvdata->dev, drvdata->nr_hreg * + sizeof(*drvdata->hreg), + GFP_KERNEL); + if (!drvdata->hreg) + return -ENOMEM; + + for (i = 0; i < drvdata->nr_hreg; i++) { + ret = of_property_read_string_index(node, + "qcom,hwevent-regs", + i, &hreg_name); + if (ret) + return ret; + + drvdata->hreg[i] = devm_regulator_get(drvdata->dev, + hreg_name); + if (IS_ERR(drvdata->hreg[i])) + return PTR_ERR(drvdata->hreg[i]); + } + } + + return 0; +} + +static int hwevent_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct hwevent_drvdata *drvdata; + struct coresight_desc desc = { 0 }; + struct coresight_platform_data *pdata; + int ret; + + desc.name = coresight_alloc_device_name(&hwevent_devs, dev); + if (!desc.name) + return -ENOMEM; + pdata = coresight_get_platform_data(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + pdev->dev.platform_data = pdata; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + drvdata->dev = &pdev->dev; + platform_set_drvdata(pdev, drvdata); + mutex_init(&drvdata->mutex); + + ret = of_get_coresight_csr_name(dev->of_node, &drvdata->csr_name); + if (ret) + dev_err(dev, "No csr data\n"); + else { + drvdata->csr = coresight_csr_get(drvdata->csr_name); + if (IS_ERR(drvdata->csr)) { + dev_dbg(dev, "failed to get csr, defer probe\n"); + return -EPROBE_DEFER; + } + } + + drvdata->clk = devm_clk_get(dev, "apb_pclk"); + if (IS_ERR(drvdata->clk)) + return PTR_ERR(drvdata->clk); + + ret = hwevent_init_hmux(drvdata, pdev); + if (ret) + return ret; + + ret = hwevent_init_clk(drvdata); + if (ret) + return ret; + + desc.type = CORESIGHT_DEV_TYPE_NONE; + desc.pdata = pdev->dev.platform_data; + desc.dev = &pdev->dev; + desc.groups = hwevent_attr_grps; + drvdata->csdev = coresight_register(&desc); + if (IS_ERR(drvdata->csdev)) + return PTR_ERR(drvdata->csdev); + + dev_dbg(dev, "Hardware Event driver initialized\n"); + return 0; +} + +static int hwevent_remove(struct platform_device *pdev) +{ + struct hwevent_drvdata *drvdata = platform_get_drvdata(pdev); + + coresight_unregister(drvdata->csdev); + return 0; +} + +static const struct of_device_id hwevent_match[] = { + {.compatible = "qcom,coresight-hwevent"}, + {}, +}; + +static struct platform_driver hwevent_driver = { + .probe = hwevent_probe, + .remove = hwevent_remove, + .driver = { + .name = "coresight-hwevent", + .of_match_table = hwevent_match, + }, +}; + +static int __init hwevent_init(void) +{ + return platform_driver_register(&hwevent_driver); +} +module_init(hwevent_init); + +static void __exit hwevent_exit(void) +{ + platform_driver_unregister(&hwevent_driver); +} +module_exit(hwevent_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CoreSight Hardware Event driver");