summaryrefslogtreecommitdiff
path: root/drivers/hwtracing/coresight/coresight-stm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwtracing/coresight/coresight-stm.c')
-rw-r--r--drivers/hwtracing/coresight/coresight-stm.c135
1 files changed, 119 insertions, 16 deletions
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index 974d37e5f94c..e45c6c7204b4 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -29,6 +29,7 @@
#include <linux/perf_event.h>
#include <linux/pm_runtime.h>
#include <linux/stm.h>
+#include <linux/platform_device.h>
#include "coresight-priv.h"
#include "coresight-trace-id.h"
@@ -115,6 +116,7 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
* struct stm_drvdata - specifics associated to an STM component
* @base: memory mapped base address for this component.
* @atclk: optional clock for the core parts of the STM.
+ * @pclk: APB clock if present, otherwise NULL
* @csdev: component vitals needed by the framework.
* @spinlock: only one at a time pls.
* @chs: the channels accociated to this STM.
@@ -131,6 +133,7 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
struct stm_drvdata {
void __iomem *base;
struct clk *atclk;
+ struct clk *pclk;
struct coresight_device *csdev;
spinlock_t spinlock;
struct channel_space chs;
@@ -191,7 +194,8 @@ static void stm_enable_hw(struct stm_drvdata *drvdata)
}
static int stm_enable(struct coresight_device *csdev, struct perf_event *event,
- enum cs_mode mode)
+ enum cs_mode mode,
+ __maybe_unused struct coresight_path *path)
{
struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -277,16 +281,27 @@ static void stm_disable(struct coresight_device *csdev,
}
}
+static int stm_trace_id(struct coresight_device *csdev, __maybe_unused enum cs_mode mode,
+ __maybe_unused struct coresight_device *sink)
+{
+ struct stm_drvdata *drvdata;
+
+ drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ return drvdata->traceid;
+}
+
static const struct coresight_ops_source stm_source_ops = {
.enable = stm_enable,
.disable = stm_disable,
};
static const struct coresight_ops stm_cs_ops = {
+ .trace_id = stm_trace_id,
.source_ops = &stm_source_ops,
};
-static inline bool stm_addr_unaligned(const void *addr, u8 write_bytes)
+static bool stm_addr_unaligned(const void *addr, u8 write_bytes)
{
return ((unsigned long)addr & (write_bytes - 1));
}
@@ -670,7 +685,7 @@ static int of_stm_get_stimulus_area(struct device *dev, struct resource *res)
return of_address_to_resource(np, index, res);
}
#else
-static inline int of_stm_get_stimulus_area(struct device *dev,
+static int of_stm_get_stimulus_area(struct device *dev,
struct resource *res)
{
return -ENOENT;
@@ -714,7 +729,7 @@ static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res)
return rc;
}
#else
-static inline int acpi_stm_get_stimulus_area(struct device *dev,
+static int acpi_stm_get_stimulus_area(struct device *dev,
struct resource *res)
{
return -ENOENT;
@@ -800,14 +815,22 @@ static void stm_init_generic_data(struct stm_drvdata *drvdata,
drvdata->stm.set_options = stm_generic_set_options;
}
-static int stm_probe(struct amba_device *adev, const struct amba_id *id)
+static const struct amba_id stm_ids[];
+
+static char *stm_csdev_name(struct coresight_device *csdev)
+{
+ u32 stm_pid = coresight_get_pid(&csdev->access);
+ void *uci_data = coresight_get_uci_data_from_amba(stm_ids, stm_pid);
+
+ return uci_data ? (char *)uci_data : "STM";
+}
+
+static int __stm_probe(struct device *dev, struct resource *res)
{
int ret, trace_id;
void __iomem *base;
- struct device *dev = &adev->dev;
struct coresight_platform_data *pdata = NULL;
struct stm_drvdata *drvdata;
- struct resource *res = &adev->res;
struct resource ch_res;
struct coresight_desc desc = { 0 };
@@ -819,12 +842,16 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
if (!drvdata)
return -ENOMEM;
- drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
+ drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */
if (!IS_ERR(drvdata->atclk)) {
ret = clk_prepare_enable(drvdata->atclk);
if (ret)
return ret;
}
+
+ drvdata->pclk = coresight_get_enable_apb_pclk(dev);
+ if (IS_ERR(drvdata->pclk))
+ return -ENODEV;
dev_set_drvdata(dev, drvdata);
base = devm_ioremap_resource(dev, res);
@@ -872,7 +899,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
ret = PTR_ERR(pdata);
goto stm_unregister;
}
- adev->dev.platform_data = pdata;
+ dev->platform_data = pdata;
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
@@ -893,10 +920,8 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
}
drvdata->traceid = (u8)trace_id;
- pm_runtime_put(&adev->dev);
-
dev_info(&drvdata->csdev->dev, "%s initialized\n",
- (char *)coresight_get_uci_data(id));
+ stm_csdev_name(drvdata->csdev));
return 0;
cs_unregister:
@@ -907,9 +932,20 @@ stm_unregister:
return ret;
}
-static void stm_remove(struct amba_device *adev)
+static int stm_probe(struct amba_device *adev, const struct amba_id *id)
{
- struct stm_drvdata *drvdata = dev_get_drvdata(&adev->dev);
+ int ret;
+
+ ret = __stm_probe(&adev->dev, &adev->res);
+ if (!ret)
+ pm_runtime_put(&adev->dev);
+
+ return ret;
+}
+
+static void __stm_remove(struct device *dev)
+{
+ struct stm_drvdata *drvdata = dev_get_drvdata(dev);
coresight_trace_id_put_system_id(drvdata->traceid);
coresight_unregister(drvdata->csdev);
@@ -917,6 +953,11 @@ static void stm_remove(struct amba_device *adev)
stm_unregister_device(&drvdata->stm);
}
+static void stm_remove(struct amba_device *adev)
+{
+ __stm_remove(&adev->dev);
+}
+
#ifdef CONFIG_PM
static int stm_runtime_suspend(struct device *dev)
{
@@ -925,6 +966,8 @@ static int stm_runtime_suspend(struct device *dev)
if (drvdata && !IS_ERR(drvdata->atclk))
clk_disable_unprepare(drvdata->atclk);
+ if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
+ clk_disable_unprepare(drvdata->pclk);
return 0;
}
@@ -935,6 +978,8 @@ static int stm_runtime_resume(struct device *dev)
if (drvdata && !IS_ERR(drvdata->atclk))
clk_prepare_enable(drvdata->atclk);
+ if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
+ clk_prepare_enable(drvdata->pclk);
return 0;
}
#endif
@@ -954,7 +999,6 @@ MODULE_DEVICE_TABLE(amba, stm_ids);
static struct amba_driver stm_driver = {
.drv = {
.name = "coresight-stm",
- .owner = THIS_MODULE,
.pm = &stm_dev_pm_ops,
.suppress_bind_attrs = true,
},
@@ -963,7 +1007,66 @@ static struct amba_driver stm_driver = {
.id_table = stm_ids,
};
-module_amba_driver(stm_driver);
+static int stm_platform_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int ret = 0;
+
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ ret = __stm_probe(&pdev->dev, res);
+ pm_runtime_put(&pdev->dev);
+ if (ret)
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static void stm_platform_remove(struct platform_device *pdev)
+{
+ struct stm_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
+
+ if (WARN_ON(!drvdata))
+ return;
+
+ __stm_remove(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ if (!IS_ERR_OR_NULL(drvdata->pclk))
+ clk_put(drvdata->pclk);
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id stm_acpi_ids[] = {
+ {"ARMHC502", 0, 0, 0}, /* ARM CoreSight STM */
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, stm_acpi_ids);
+#endif
+
+static struct platform_driver stm_platform_driver = {
+ .probe = stm_platform_probe,
+ .remove = stm_platform_remove,
+ .driver = {
+ .name = "coresight-stm-platform",
+ .acpi_match_table = ACPI_PTR(stm_acpi_ids),
+ .suppress_bind_attrs = true,
+ .pm = &stm_dev_pm_ops,
+ },
+};
+
+static int __init stm_init(void)
+{
+ return coresight_init_driver("stm", &stm_driver, &stm_platform_driver, THIS_MODULE);
+}
+
+static void __exit stm_exit(void)
+{
+ coresight_remove_driver(&stm_driver, &stm_platform_driver);
+}
+module_init(stm_init);
+module_exit(stm_exit);
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
MODULE_DESCRIPTION("Arm CoreSight System Trace Macrocell driver");