CoreSight drivers enable pclk and atclk conditionally. For example,
pclk is only enabled in the static probe, while atclk is an optional
clock that it is enabled for both dynamic and static probes, if it is
present. In the current CoreSight drivers, these two clocks are
initialized separately. This causes complex and duplicate codes.
CoreSight drivers are refined so that clocks are initialized in one go.
For this purpose, this commit renames coresight_get_enable_apb_pclk() to
coresight_get_enable_clocks() and encapsulates clock initialization
logic:
- If a clock is initialized successfully, its clock pointer is assigned
to the double pointer passed as an argument.
- For ACPI devices, clocks are controlled by firmware, directly bail
out.
- Skip enabling pclk for an AMBA device.
- If atclk is not found, the corresponding double pointer is set to
NULL. The function returns Success (0) to guide callers can proceed
with no error.
- Otherwise, an error number is returned for failures.
The function became complex, move it from the header to the CoreSight
core layer and the symbol is exported. Added comments for recording
details.
Suggested-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Tested-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20250731-arm_cs_fix_clock_v4-v6-7-1dfe10bb3f6f@arm.com
struct coresight_platform_data *pdata = NULL;
void __iomem *base;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
- return PTR_ERR(drvdata->atclk);
+ ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk);
+ if (ret)
+ return ret;
catu_desc.name = coresight_alloc_device_name(&catu_devs, dev);
if (!catu_desc.name)
if (!drvdata)
return -ENOMEM;
- drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev);
- if (IS_ERR(drvdata->pclk))
- return PTR_ERR(drvdata->pclk);
-
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*/
+#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/build_bug.h>
#include <linux/kernel.h>
}
EXPORT_SYMBOL_GPL(coresight_etm_get_trace_id);
+/*
+ * Attempt to find and enable programming clock (pclk) and trace clock (atclk)
+ * for the given device.
+ *
+ * For ACPI devices, clocks are controlled by firmware, so bail out early in
+ * this case. Also, skip enabling pclk if the clock is managed by the AMBA
+ * bus driver instead.
+ *
+ * atclk is an optional clock, it will be only enabled when it is existed.
+ * Otherwise, a NULL pointer will be returned to caller.
+ *
+ * Returns: '0' on Success; Error code otherwise.
+ */
+int coresight_get_enable_clocks(struct device *dev, struct clk **pclk,
+ struct clk **atclk)
+{
+ WARN_ON(!pclk);
+
+ if (has_acpi_companion(dev))
+ return 0;
+
+ if (!dev_is_amba(dev)) {
+ /*
+ * "apb_pclk" is the default clock name for an Arm Primecell
+ * peripheral, while "apb" is used only by the CTCU driver.
+ *
+ * For easier maintenance, CoreSight drivers should use
+ * "apb_pclk" as the programming clock name.
+ */
+ *pclk = devm_clk_get_optional_enabled(dev, "apb_pclk");
+ if (!*pclk)
+ *pclk = devm_clk_get_optional_enabled(dev, "apb");
+ if (IS_ERR(*pclk))
+ return PTR_ERR(*pclk);
+ }
+
+ /* Initialization of atclk is skipped if it is a NULL pointer. */
+ if (atclk) {
+ *atclk = devm_clk_get_optional_enabled(dev, "atclk");
+ if (IS_ERR(*atclk))
+ return PTR_ERR(*atclk);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(coresight_get_enable_clocks);
+
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
void __iomem *base;
int ret;
+ ret = coresight_get_enable_clocks(dev, &drvdata->pclk, NULL);
+ if (ret)
+ return ret;
+
drvdata->cpu = coresight_get_cpu(dev);
if (drvdata->cpu < 0)
return drvdata->cpu;
if (!drvdata)
return -ENOMEM;
- drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev);
- if (IS_ERR(drvdata->pclk))
- return PTR_ERR(drvdata->pclk);
-
dev_set_drvdata(&pdev->dev, drvdata);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
const struct ctcu_config *cfgs;
struct ctcu_drvdata *drvdata;
void __iomem *base;
- int i;
+ int i, ret;
desc.name = coresight_alloc_device_name(&ctcu_devs, dev);
if (!desc.name)
if (IS_ERR(base))
return PTR_ERR(base);
- drvdata->apb_clk = coresight_get_enable_apb_pclk(dev);
- if (IS_ERR(drvdata->apb_clk))
- return PTR_ERR(drvdata->apb_clk);
+ ret = coresight_get_enable_clocks(dev, &drvdata->apb_clk, NULL);
+ if (ret)
+ return ret;
cfgs = of_device_get_match_data(dev);
if (cfgs) {
struct csdev_access access = { 0 };
struct etm4_init_arg init_arg = { 0 };
struct etm4_init_arg *delayed;
+ int ret;
if (WARN_ON(!drvdata))
return -ENOMEM;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
- return PTR_ERR(drvdata->atclk);
+ ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk);
+ if (ret)
+ return ret;
if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE)
pm_save_enable = coresight_loses_context_with_cpu(dev) ?
if (!drvdata)
return -ENOMEM;
- drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev);
- if (IS_ERR(drvdata->pclk))
- return PTR_ERR(drvdata->pclk);
-
if (res) {
drvdata->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(drvdata->base))
struct coresight_platform_data *pdata = NULL;
struct funnel_drvdata *drvdata;
struct coresight_desc desc = { 0 };
+ int ret;
if (is_of_node(dev_fwnode(dev)) &&
of_device_is_compatible(dev->of_node, "arm,coresight-funnel"))
if (!drvdata)
return -ENOMEM;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
- return PTR_ERR(drvdata->atclk);
-
- drvdata->pclk = coresight_get_enable_apb_pclk(dev);
- if (IS_ERR(drvdata->pclk))
- return PTR_ERR(drvdata->pclk);
+ ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk);
+ if (ret)
+ return ret;
/*
* Map the device base for dynamic-funnel, which has been
struct replicator_drvdata *drvdata;
struct coresight_desc desc = { 0 };
void __iomem *base;
+ int ret;
if (is_of_node(dev_fwnode(dev)) &&
of_device_is_compatible(dev->of_node, "arm,coresight-replicator"))
if (!drvdata)
return -ENOMEM;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
- return PTR_ERR(drvdata->atclk);
-
- drvdata->pclk = coresight_get_enable_apb_pclk(dev);
- if (IS_ERR(drvdata->pclk))
- return PTR_ERR(drvdata->pclk);
+ ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk);
+ if (ret)
+ return ret;
/*
* Map the device base for dynamic-replicator, which has been
if (!drvdata)
return -ENOMEM;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
- return PTR_ERR(drvdata->atclk);
+ ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk);
+ if (ret)
+ return ret;
- drvdata->pclk = coresight_get_enable_apb_pclk(dev);
- if (IS_ERR(drvdata->pclk))
- return PTR_ERR(drvdata->pclk);
dev_set_drvdata(dev, drvdata);
base = devm_ioremap_resource(dev, res);
struct coresight_desc desc = { 0 };
struct coresight_dev_list *dev_list = NULL;
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
- return PTR_ERR(drvdata->atclk);
+ ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk);
+ if (ret)
+ return ret;
ret = -ENOMEM;
if (!drvdata)
return -ENOMEM;
- drvdata->pclk = coresight_get_enable_apb_pclk(&pdev->dev);
- if (IS_ERR(drvdata->pclk))
- return PTR_ERR(drvdata->pclk);
-
dev_set_drvdata(&pdev->dev, drvdata);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
struct coresight_platform_data *pdata = NULL;
struct tpiu_drvdata *drvdata;
struct coresight_desc desc = { 0 };
+ int ret;
desc.name = coresight_alloc_device_name(&tpiu_devs, dev);
if (!desc.name)
spin_lock_init(&drvdata->spinlock);
- drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk");
- if (IS_ERR(drvdata->atclk))
- return PTR_ERR(drvdata->atclk);
+ ret = coresight_get_enable_clocks(dev, &drvdata->pclk, &drvdata->atclk);
+ if (ret)
+ return ret;
- drvdata->pclk = coresight_get_enable_apb_pclk(dev);
- if (IS_ERR(drvdata->pclk))
- return PTR_ERR(drvdata->pclk);
dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */
#ifndef _LINUX_CORESIGHT_H
#define _LINUX_CORESIGHT_H
-#include <linux/acpi.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
#include <linux/device.h>
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 controlled by firmware (ACPI device only) or when managed
- * by the AMBA bus driver instead
- * ERROR - Clock is found but failed to enable
- */
-static inline struct clk *coresight_get_enable_apb_pclk(struct device *dev)
-{
- struct clk *pclk = NULL;
-
- /* Firmware controls clocks for an ACPI device. */
- if (has_acpi_companion(dev))
- return NULL;
-
- if (!dev_is_amba(dev)) {
- pclk = devm_clk_get_optional_enabled(dev, "apb_pclk");
- if (!pclk)
- pclk = devm_clk_get_optional_enabled(dev, "apb");
- }
-
- return pclk;
-}
-
#define CORESIGHT_PIDRn(i) (0xFE0 + ((i) * 4))
static inline u32 coresight_get_pid(struct csdev_access *csa)
struct platform_driver *pdev_drv);
int coresight_etm_get_trace_id(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_device *sink);
+int coresight_get_enable_clocks(struct device *dev, struct clk **pclk,
+ struct clk **atclk);
#endif /* _LINUX_COREISGHT_H */