diff options
-rw-r--r-- | drivers/hwtracing/coresight/coresight-etm4x-core.c | 58 | ||||
-rw-r--r-- | drivers/hwtracing/coresight/coresight-etm4x.h | 4 | ||||
-rw-r--r-- | include/linux/coresight.h | 47 |
3 files changed, 107 insertions, 2 deletions
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index e91e59ecec53..43f583987250 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/property.h> +#include <linux/clk/clk-conf.h> #include <asm/barrier.h> #include <asm/sections.h> @@ -1073,11 +1074,21 @@ static bool etm4_init_sysreg_access(struct etmv4_drvdata *drvdata, return true; } +static bool is_devtype_cpu_trace(void __iomem *base) +{ + u32 devtype = readl(base + TRCDEVTYPE); + + return (devtype == CS_DEVTYPE_PE_TRACE); +} + static bool etm4_init_iomem_access(struct etmv4_drvdata *drvdata, struct csdev_access *csa) { u32 devarch = readl_relaxed(drvdata->base + TRCDEVARCH); + if (!is_coresight_device(drvdata->base) || !is_devtype_cpu_trace(drvdata->base)) + return false; + /* * All ETMs must implement TRCDEVARCH to indicate that * the component is an ETMv4. Even though TRCIDR1 also @@ -2135,6 +2146,7 @@ static int etm4_probe_amba(struct amba_device *adev, const struct amba_id *id) static int etm4_probe_platform_dev(struct platform_device *pdev) { + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct etmv4_drvdata *drvdata; int ret; @@ -2142,7 +2154,18 @@ static int etm4_probe_platform_dev(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - drvdata->base = NULL; + drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev); + if (IS_ERR(drvdata->pclk)) + return -ENODEV; + + if (res) { + drvdata->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(drvdata->base)) { + clk_put(drvdata->pclk); + return PTR_ERR(drvdata->base); + } + } + dev_set_drvdata(&pdev->dev, drvdata); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -2188,7 +2211,7 @@ static struct amba_cs_uci_id uci_id_etm4[] = { /* ETMv4 UCI data */ .devarch = ETM_DEVARCH_ETMv4x_ARCH, .devarch_mask = ETM_DEVARCH_ID_MASK, - .devtype = 0x00000013, + .devtype = CS_DEVTYPE_PE_TRACE, } }; @@ -2244,6 +2267,10 @@ static int __exit etm4_remove_platform_dev(struct platform_device *pdev) if (drvdata) etm4_remove_dev(drvdata); pm_runtime_disable(&pdev->dev); + + if (drvdata->pclk) + clk_put(drvdata->pclk); + return 0; } @@ -2288,6 +2315,32 @@ static struct amba_driver etm4x_amba_driver = { .id_table = etm4_ids, }; +#ifdef CONFIG_PM +static int etm4_runtime_suspend(struct device *dev) +{ + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata->pclk && !IS_ERR(drvdata->pclk)) + clk_disable_unprepare(drvdata->pclk); + + return 0; +} + +static int etm4_runtime_resume(struct device *dev) +{ + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata->pclk && !IS_ERR(drvdata->pclk)) + clk_prepare_enable(drvdata->pclk); + + return 0; +} +#endif + +static const struct dev_pm_ops etm4_dev_pm_ops = { + SET_RUNTIME_PM_OPS(etm4_runtime_suspend, etm4_runtime_resume, NULL) +}; + static const struct of_device_id etm4_sysreg_match[] = { { .compatible = "arm,coresight-etm4x-sysreg" }, { .compatible = "arm,embedded-trace-extension" }, @@ -2301,6 +2354,7 @@ static struct platform_driver etm4_platform_driver = { .name = "coresight-etm4x", .of_match_table = etm4_sysreg_match, .suppress_bind_attrs = true, + .pm = &etm4_dev_pm_ops, }, }; diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 27c8a9901868..20e2e4cb7614 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -701,6 +701,8 @@ #define ETM_DEVARCH_ETE_ARCH \ (ETM_DEVARCH_ARCHITECT_ARM | ETM_DEVARCH_ARCHID_ETE | ETM_DEVARCH_PRESENT) +#define CS_DEVTYPE_PE_TRACE 0x00000013 + #define TRCSTATR_IDLE_BIT 0 #define TRCSTATR_PMSTABLE_BIT 1 #define ETM_DEFAULT_ADDR_COMP 0 @@ -944,6 +946,7 @@ struct etmv4_save_state { /** * struct etm4_drvdata - specifics associated to an ETM component + * @pclk APB clock if present, otherwise NULL * @base: Memory mapped base address for this component. * @csdev: Component vitals needed by the framework. * @spinlock: Only one at a time pls. @@ -1009,6 +1012,7 @@ struct etmv4_save_state { * @arch_features: Bitmap of arch features of etmv4 devices. */ struct etmv4_drvdata { + struct clk *pclk; void __iomem *base; struct coresight_device *csdev; spinlock_t spinlock; diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 255cfd283883..a269fffaf991 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -6,6 +6,8 @@ #ifndef _LINUX_CORESIGHT_H #define _LINUX_CORESIGHT_H +#include <linux/amba/bus.h> +#include <linux/clk.h> #include <linux/device.h> #include <linux/io.h> #include <linux/perf_event.h> @@ -386,6 +388,51 @@ static inline u32 csdev_access_relaxed_read32(struct csdev_access *csa, return csa->read(offset, true, false); } +#define CORESIGHT_CIDRn(i) (0xFF0 + ((i) * 4)) + +static inline u32 coresight_get_cid(void __iomem *base) +{ + u32 i, cid = 0; + + for (i = 0; i < 4; i++) + cid |= readl(base + CORESIGHT_CIDRn(i)) << (i * 8); + + return cid; +} + +static inline bool is_coresight_device(void __iomem *base) +{ + u32 cid = coresight_get_cid(base); + + return cid == CORESIGHT_CID; +} + +/* + * Attempt to find and enable "APB clock" for the given device + * + * Returns: + * + * clk - Clock is found and enabled + * NULL - clock is not found + * ERROR - Clock is found but failed to enable + */ +static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev) +{ + struct clk *pclk; + int ret; + + pclk = clk_get(dev, "apb_pclk"); + if (IS_ERR(pclk)) + return NULL; + + ret = clk_prepare_enable(pclk); + if (ret) { + clk_put(pclk); + return ERR_PTR(ret); + } + return pclk; +} + #define CORESIGHT_PIDRn(i) (0xFE0 + ((i) * 4)) static inline u32 coresight_get_pid(struct csdev_access *csa) |