coresight: Add regulator and clock vote for coresight components

Some coresight components are driven by external regulators and
clocks. Add regulator and clock support in coresight driver so
proper regulators and clocks are voted when components are enabled.

Change-Id: I23e2516c4cb077099dab7cedaacad4aba0b962c6
Signed-off-by: Tingwei Zhang <tingwei@codeaurora.org>
This commit is contained in:
Tingwei Zhang
2019-08-07 18:53:46 +08:00
parent bc78211a5e
commit 22d49bcc8d
3 changed files with 162 additions and 5 deletions

View File

@@ -245,7 +245,60 @@ static int of_coresight_parse_endpoint(struct device *dev,
return ret; return ret;
} }
#ifdef CONFIG_CORESIGHT_QGKI
static struct coresight_reg_clk *
of_coresight_get_reg_clk(struct device *dev, const struct device_node *node)
{
struct coresight_reg_clk *reg_clk;
const char *clk_name, *reg_name;
int nr_reg, nr_clk, i, ret;
nr_reg = of_property_count_strings(node, "qcom,proxy-regs");
nr_clk = of_property_count_strings(node, "qcom,proxy-clks");
if (!nr_reg && !nr_clk)
return NULL;
reg_clk = devm_kzalloc(dev, sizeof(*reg_clk), GFP_KERNEL);
if (!reg_clk)
return ERR_PTR(-ENOMEM);
reg_clk->nr_reg = nr_reg;
reg_clk->nr_clk = nr_clk;
if (nr_reg > 0) {
reg_clk->reg = devm_kzalloc(dev, nr_reg *
sizeof(reg_clk->reg), GFP_KERNEL);
if (!reg_clk->reg)
return ERR_PTR(-ENOMEM);
for (i = 0; i < nr_reg; i++) {
ret = of_property_read_string_index(node,
"qcom,proxy-regs", i, &reg_name);
if (ret)
return ERR_PTR(ret);
reg_clk->reg[i] = devm_regulator_get(dev, reg_name);
if (IS_ERR(reg_clk->reg[i]))
return ERR_PTR(-EINVAL);
}
}
if (nr_clk > 0) {
reg_clk->clk = devm_kzalloc(dev, nr_clk *
sizeof(reg_clk->clk), GFP_KERNEL);
if (!reg_clk->clk)
return ERR_PTR(-ENOMEM);
for (i = 0; i < nr_clk; i++) {
ret = of_property_read_string_index(node,
"qcom,proxy-clks", i, &clk_name);
if (ret)
return ERR_PTR(ret);
reg_clk->clk[i] = devm_clk_get(dev, clk_name);
if (IS_ERR(reg_clk->clk[i]))
return ERR_PTR(-EINVAL);
}
}
return reg_clk;
}
#endif
static int of_get_coresight_platform_data(struct device *dev, static int of_get_coresight_platform_data(struct device *dev,
struct coresight_platform_data *pdata) struct coresight_platform_data *pdata)
{ {
@@ -256,6 +309,11 @@ static int of_get_coresight_platform_data(struct device *dev,
bool legacy_binding = false; bool legacy_binding = false;
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
#ifdef CONFIG_CORESIGHT_QGKI
pdata->reg_clk = of_coresight_get_reg_clk(dev, node);
if (IS_ERR(pdata->reg_clk))
return PTR_ERR(pdata->reg_clk);
#endif
/* Get the number of input and output port for this component */ /* Get the number of input and output port for this component */
of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport); of_coresight_get_ports(node, &pdata->nr_inport, &pdata->nr_outport);

View File

@@ -19,6 +19,7 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include "coresight-etm-perf.h" #include "coresight-etm-perf.h"
#include "coresight-priv.h" #include "coresight-priv.h"
@@ -145,6 +146,60 @@ static void coresight_reset_all_sink(void)
bus_for_each_dev(&coresight_bustype, NULL, NULL, coresight_reset_sink); bus_for_each_dev(&coresight_bustype, NULL, NULL, coresight_reset_sink);
} }
#ifdef CONFIG_CORESIGHT_QGKI
int coresight_enable_reg_clk(struct coresight_device *csdev)
{
struct coresight_reg_clk *reg_clk = csdev->reg_clk;
int ret;
int i, j;
if (IS_ERR_OR_NULL(reg_clk))
return -EINVAL;
for (i = 0; i < reg_clk->nr_reg; i++) {
ret = regulator_enable(reg_clk->reg[i]);
if (ret)
goto err_regs;
}
for (j = 0; j < reg_clk->nr_clk; j++) {
ret = clk_prepare_enable(reg_clk->clk[j]);
if (ret)
goto err_clks;
}
return 0;
err_clks:
for (j--; j >= 0; j--)
clk_disable_unprepare(reg_clk->clk[j]);
err_regs:
for (i--; i >= 0; i--)
regulator_disable(reg_clk->reg[i]);
return ret;
}
EXPORT_SYMBOL(coresight_enable_reg_clk);
void coresight_disable_reg_clk(struct coresight_device *csdev)
{
struct coresight_reg_clk *reg_clk = csdev->reg_clk;
int i;
if (IS_ERR_OR_NULL(reg_clk))
return;
for (i = reg_clk->nr_clk - 1; i >= 0; i--)
clk_disable_unprepare(reg_clk->clk[i]);
for (i = reg_clk->nr_reg - 1; i >= 0; i--)
regulator_disable(reg_clk->reg[i]);
}
EXPORT_SYMBOL(coresight_disable_reg_clk);
#else
int coresight_enable_reg_clk(struct coresight_device *csdev)
{ return 0; }
void coresight_disable_reg_clk(struct coresight_device *csdev) { }
#endif
static int coresight_find_link_inport(struct coresight_device *csdev, static int coresight_find_link_inport(struct coresight_device *csdev,
struct coresight_device *parent, struct coresight_device *parent,
struct list_head *path) struct list_head *path)
@@ -285,9 +340,12 @@ static int coresight_enable_sink(struct coresight_device *csdev,
if (!sink_ops(csdev)->enable) if (!sink_ops(csdev)->enable)
return -EINVAL; return -EINVAL;
coresight_enable_reg_clk(csdev);
ret = sink_ops(csdev)->enable(csdev, mode, data); ret = sink_ops(csdev)->enable(csdev, mode, data);
if (ret) if (ret) {
coresight_disable_reg_clk(csdev);
return ret; return ret;
}
csdev->enable = true; csdev->enable = true;
return 0; return 0;
@@ -303,6 +361,7 @@ static void coresight_disable_sink(struct coresight_device *csdev)
ret = sink_ops(csdev)->disable(csdev); ret = sink_ops(csdev)->disable(csdev);
if (ret) if (ret)
return; return;
coresight_disable_reg_clk(csdev);
csdev->activated = false; csdev->activated = false;
csdev->enable = false; csdev->enable = false;
} }
@@ -335,8 +394,10 @@ static int coresight_enable_link(struct coresight_device *csdev,
if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (atomic_inc_return(&csdev->refcnt[refport]) == 1) {
if (link_ops(csdev)->enable) { if (link_ops(csdev)->enable) {
coresight_enable_reg_clk(csdev);
ret = link_ops(csdev)->enable(csdev, inport, outport); ret = link_ops(csdev)->enable(csdev, inport, outport);
if (ret) { if (ret) {
coresight_disable_reg_clk(csdev);
atomic_dec(&csdev->refcnt[refport]); atomic_dec(&csdev->refcnt[refport]);
return ret; return ret;
} }
@@ -376,8 +437,10 @@ static void coresight_disable_link(struct coresight_device *csdev,
} }
if (atomic_dec_return(&csdev->refcnt[refport]) == 0) { if (atomic_dec_return(&csdev->refcnt[refport]) == 0) {
if (link_ops(csdev)->disable) if (link_ops(csdev)->disable) {
link_ops(csdev)->disable(csdev, inport, outport); link_ops(csdev)->disable(csdev, inport, outport);
coresight_disable_reg_clk(csdev);
}
} }
for (i = 0; i < nr_conns; i++) for (i = 0; i < nr_conns; i++)
@@ -399,9 +462,12 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
if (!csdev->enable) { if (!csdev->enable) {
if (source_ops(csdev)->enable) { if (source_ops(csdev)->enable) {
coresight_enable_reg_clk(csdev);
ret = source_ops(csdev)->enable(csdev, NULL, mode); ret = source_ops(csdev)->enable(csdev, NULL, mode);
if (ret) if (ret) {
coresight_disable_reg_clk(csdev);
return ret; return ret;
}
} }
csdev->enable = true; csdev->enable = true;
} }
@@ -422,8 +488,10 @@ static int coresight_enable_source(struct coresight_device *csdev, u32 mode)
static bool coresight_disable_source(struct coresight_device *csdev) static bool coresight_disable_source(struct coresight_device *csdev)
{ {
if (atomic_dec_return(csdev->refcnt) == 0) { if (atomic_dec_return(csdev->refcnt) == 0) {
if (source_ops(csdev)->disable) if (source_ops(csdev)->disable) {
source_ops(csdev)->disable(csdev, NULL); source_ops(csdev)->disable(csdev, NULL);
coresight_disable_reg_clk(csdev);
}
csdev->enable = false; csdev->enable = false;
} }
return !csdev->enable; return !csdev->enable;
@@ -1352,6 +1420,9 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
csdev->subtype = desc->subtype; csdev->subtype = desc->subtype;
csdev->ops = desc->ops; csdev->ops = desc->ops;
csdev->orphan = false; csdev->orphan = false;
#ifdef CONFIG_CORESIGHT_QGKI
csdev->reg_clk = desc->pdata->reg_clk;
#endif
csdev->dev.type = &coresight_dev_type[desc->type]; csdev->dev.type = &coresight_dev_type[desc->type];
csdev->dev.groups = desc->groups; csdev->dev.groups = desc->groups;

View File

@@ -89,16 +89,34 @@ union coresight_dev_subtype {
enum coresight_dev_subtype_helper helper_subtype; enum coresight_dev_subtype_helper helper_subtype;
}; };
/**
* struct coresight_reg_clk - regulators and clocks need by coresight
* @nr_reg: number of regulators
* @nr_clk: number of clocks
* @reg: regulator list
* @clk: clock list
*/
struct coresight_reg_clk {
int nr_reg;
int nr_clk;
struct regulator **reg;
struct clk **clk;
};
/** /**
* struct coresight_platform_data - data harvested from the DT specification * struct coresight_platform_data - data harvested from the DT specification
* @nr_inport: number of input ports for this component. * @nr_inport: number of input ports for this component.
* @nr_outport: number of output ports for this component. * @nr_outport: number of output ports for this component.
* @conns: Array of nr_outport connections from this component * @conns: Array of nr_outport connections from this component
* @reg_clk: The clock this component is associated to.
*/ */
struct coresight_platform_data { struct coresight_platform_data {
int nr_inport; int nr_inport;
int nr_outport; int nr_outport;
struct coresight_connection *conns; struct coresight_connection *conns;
#ifdef CONFIG_CORESIGHT_QGKI
struct coresight_reg_clk *reg_clk;
#endif
}; };
/** /**
@@ -157,6 +175,7 @@ struct coresight_connection {
* activated but not yet enabled. Enabling for a _sink_ * activated but not yet enabled. Enabling for a _sink_
* appens when a source has been selected for that it. * appens when a source has been selected for that it.
* @ea: Device attribute for sink representation under PMU directory. * @ea: Device attribute for sink representation under PMU directory.
* @reg_clk: clock for this component, as defined by @coresight_reg_clk.
*/ */
struct coresight_device { struct coresight_device {
struct coresight_platform_data *pdata; struct coresight_platform_data *pdata;
@@ -170,6 +189,9 @@ struct coresight_device {
/* sink specific fields */ /* sink specific fields */
bool activated; /* true only if a sink is part of a path */ bool activated; /* true only if a sink is part of a path */
struct dev_ext_attribute *ea; struct dev_ext_attribute *ea;
#ifdef CONFIG_CORESIGHT_QGKI
struct coresight_reg_clk *reg_clk;
#endif
}; };
/* /*
@@ -289,6 +311,8 @@ extern void coresight_disclaim_device(void __iomem *base);
extern void coresight_disclaim_device_unlocked(void __iomem *base); extern void coresight_disclaim_device_unlocked(void __iomem *base);
extern const char *coresight_alloc_device_name(struct coresight_dev_list *devs, extern const char *coresight_alloc_device_name(struct coresight_dev_list *devs,
struct device *dev); struct device *dev);
extern void coresight_disable_reg_clk(struct coresight_device *csdev);
extern int coresight_enable_reg_clk(struct coresight_device *csdev);
#else #else
static inline struct coresight_device * static inline struct coresight_device *
coresight_register(struct coresight_desc *desc) { return NULL; } coresight_register(struct coresight_desc *desc) { return NULL; }
@@ -310,7 +334,11 @@ static inline int coresight_claim_device(void __iomem *base)
static inline void coresight_disclaim_device(void __iomem *base) {} static inline void coresight_disclaim_device(void __iomem *base) {}
static inline void coresight_disclaim_device_unlocked(void __iomem *base) {} static inline void coresight_disclaim_device_unlocked(void __iomem *base) {}
static inline void coresight_disable_reg_clk(struct coresight_device *csdev) {}
static inline int coresight_enable_reg_clk(struct coresight_device *csdev)
{
return -EINVAL;
}
#endif #endif
extern int coresight_get_cpu(struct device *dev); extern int coresight_get_cpu(struct device *dev);