On Mon, Aug 19, 2019 at 10:13:49PM +0100, Mike Leach wrote:
Adds in sysfs programming support for the CTI function register sets. Allows direct manipulation of channel / trigger association registers.
Signed-off-by: Mike Leach mike.leach@linaro.org
.../hwtracing/coresight/coresight-cti-sysfs.c | 368 ++++++++++++++++++ drivers/hwtracing/coresight/coresight-cti.c | 19 + drivers/hwtracing/coresight/coresight-cti.h | 5 + 3 files changed, 392 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 20a9b30c9755..4055e392530d 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -119,6 +119,368 @@ static struct attribute *coresight_cti_mgmt_attrs[] = { NULL, }; +/* CTI low level programming registers */
+/*
- Show a simple 32 bit value if enabled and powered.
- If inaccessible & pcached_val not NULL then show cached value.
- */
+static ssize_t cti_reg32_show(struct device *dev, char *buf,
u32 *pcached_val, int reg_offset)
+{
- u32 val = 0;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
- if ((reg_offset >= 0) && CTI_PWR_ENA(config)) {
CS_UNLOCK(drvdata->base);
val = readl_relaxed(drvdata->base + reg_offset);
if (pcached_val)
*pcached_val = val;
CS_LOCK(drvdata->base);
- } else if (pcached_val) {
val = *pcached_val;
- }
- spin_unlock(&drvdata->spinlock);
- return scnprintf(buf, PAGE_SIZE, "%#x\n", val);
+}
+/*
- Store a simple 32 bit value.
- If pcached_val not NULL, then copy to here too,
- if reg_offset >= 0 then write through if enabled.
- */
+static ssize_t cti_reg32_store(struct device *dev, const char *buf,
size_t size, u32 *pcached_val, int reg_offset)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- /* local store */
- if (pcached_val)
*pcached_val = (u32)val;
- /* write through if offset and enabled */
- if ((reg_offset >= 0) && CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, reg_offset, val);
- spin_unlock(&drvdata->spinlock);
- return size;
+}
+/* Standard macro for simple rw cti config registers */ +#define cti_config_reg32_rw(name, cfgname, offset) \ +static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- return cti_reg32_show(dev, buf, \
&drvdata->config.cfgname, offset); \
+} \
\
+static ssize_t name##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t size) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- return cti_reg32_store(dev, buf, size, \
&drvdata->config.cfgname, offset); \
+} \ +static DEVICE_ATTR_RW(name)
+static ssize_t inout_sel_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- u32 val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- val = (u32)drvdata->config.ctiinout_sel;
- return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+static ssize_t inout_sel_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- if (val > (CTIINOUTEN_MAX-1))
s/"CTIINOUTEN_MAX-1"/"CTIINOUTEN_MAX - 1"
With that: Reviewed-by: Mathieu Poirier mathieu.poirier@linaro.org
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- drvdata->config.ctiinout_sel = val;
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_RW(inout_sel);
+static ssize_t inen_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- unsigned long val;
- int index;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
- index = drvdata->config.ctiinout_sel;
- val = drvdata->config.ctiinen[index];
- spin_unlock(&drvdata->spinlock);
- return scnprintf(buf, PAGE_SIZE, "INEN%d %#lx\n", index, val);
+}
+static ssize_t inen_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- int index;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- index = config->ctiinout_sel;
- config->ctiinen[index] = val;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIINEN(index), val);
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_RW(inen);
+static ssize_t outen_show(struct device *dev,
struct device_attribute *attr,
char *buf)
+{
- unsigned long val;
- int index;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- spin_lock(&drvdata->spinlock);
- index = drvdata->config.ctiinout_sel;
- val = drvdata->config.ctiouten[index];
- spin_unlock(&drvdata->spinlock);
- return scnprintf(buf, PAGE_SIZE, "OUTEN%d %#lx\n", index, val);
+}
+static ssize_t outen_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- int index;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- index = config->ctiinout_sel;
- config->ctiouten[index] = val;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIOUTEN(index), val);
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_RW(outen);
+static ssize_t intack_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- cti_write_intack(dev, val);
- return size;
+} +static DEVICE_ATTR_WO(intack);
+cti_config_reg32_rw(gate, ctigate, CTIGATE); +cti_config_reg32_rw(asicctl, asicctl, ASICCTL); +cti_config_reg32_rw(appset, ctiappset, CTIAPPSET);
+static ssize_t appclear_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- /* a 1'b1 in appclr clears down the same bit in appset*/
- config->ctiappset &= ~val;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_WO(appclear);
+static ssize_t apppulse_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
+{
- unsigned long val;
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- if (kstrtoul(buf, 0, &val))
return -EINVAL;
- spin_lock(&drvdata->spinlock);
- /*
* a 1'b1 in apppulse sets then clears the bit,
* effectively clears down the same bit in appset
*/
- config->ctiappset &= ~val;
- /* write through if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIAPPPULSE, val);
- spin_unlock(&drvdata->spinlock);
- return size;
+} +static DEVICE_ATTR_WO(apppulse);
+coresight_cti_reg(triginstatus, CTITRIGINSTATUS); +coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS); +coresight_cti_reg(chinstatus, CTICHINSTATUS); +coresight_cti_reg(choutstatus, CTICHOUTSTATUS);
+/*
- #define CTI_DEBUG_INTEGRATION_CTRL to enable the access to the integration
- control registers. Normally only used to investigate connection data.
- */
+/* #define CTI_DEBUG_INTEGRATION_CTRL */
+#ifdef CTI_DEBUG_INTEGRATION_CTRL
+/* macro to access RW registers with power check only (no enable check). */ +#define coresight_cti_reg_rw(name, offset) \ +static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- u32 val = 0; \
- pm_runtime_get_sync(dev->parent); \
- spin_lock(&drvdata->spinlock); \
- if (drvdata->config.hw_powered) \
val = readl_relaxed(drvdata->base + offset); \
- spin_unlock(&drvdata->spinlock); \
- pm_runtime_put_sync(dev->parent); \
- return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \
+} \
\
+static ssize_t name##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t size) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- unsigned long val = 0; \
- if (kstrtoul(buf, 0, &val)) \
return -EINVAL; \
\
- pm_runtime_get_sync(dev->parent); \
- spin_lock(&drvdata->spinlock); \
- if (drvdata->config.hw_powered) \
cti_write_single_reg(drvdata, reg_offset, val); \
- spin_unlock(&drvdata->spinlock); \
- pm_runtime_put_sync(dev->parent); \
- return size; \
+} \ +static DEVICE_ATTR_RW(name)
+/* macro to access WO registers with power check only (no enable check). */ +#define coresight_cti_reg_wo(name, offset) \ +static ssize_t name##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t size) \
+{ \
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \
- unsigned long val = 0; \
- if (kstrtoul(buf, 0, &val)) \
return -EINVAL; \
\
- pm_runtime_get_sync(dev->parent); \
- spin_lock(&drvdata->spinlock); \
- if (drvdata->config.hw_powered) \
cti_write_single_reg(drvdata, reg_offset, val); \
- spin_unlock(&drvdata->spinlock); \
- pm_runtime_put_sync(dev->parent); \
- return size; \
+} \ +static DEVICE_ATTR_WO(name)
+coresight_cti_reg_rw(itchout, ITCHOUT); +coresight_cti_reg_rw(ittrigout, ITTRIGOUT); +coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL); +coresight_cti_reg_wo(itchinack, ITCHINACK); +coresight_cti_reg_wo(ittriginack, ITTRIGINACK); +coresight_cti_reg(ittrigin, ITTRIGIN); +coresight_cti_reg(itchin, ITCHIN); +coresight_cti_reg(itchoutack, ITCHOUTACK); +coresight_cti_reg(ittrigoutack, ITTRIGOUTACK);
+#endif /* CTI_DEBUG_INTEGRATION_CTRL */
+static struct attribute *coresight_cti_regs_attrs[] = {
- &dev_attr_inout_sel.attr,
- &dev_attr_inen.attr,
- &dev_attr_outen.attr,
- &dev_attr_gate.attr,
- &dev_attr_asicctl.attr,
- &dev_attr_intack.attr,
- &dev_attr_appset.attr,
- &dev_attr_appclear.attr,
- &dev_attr_apppulse.attr,
- &dev_attr_triginstatus.attr,
- &dev_attr_trigoutstatus.attr,
- &dev_attr_chinstatus.attr,
- &dev_attr_choutstatus.attr,
+#ifdef CTI_DEBUG_INTEGRATION_CTRL
- &dev_attr_itctrl.attr,
- &dev_attr_ittrigin.attr,
- &dev_attr_itchin.attr,
- &dev_attr_ittrigout.attr,
- &dev_attr_itchout.attr,
- &dev_attr_itchoutack.attr,
- &dev_attr_ittrigoutack.attr,
- &dev_attr_ittriginack.attr,
- &dev_attr_itchinack.attr,
+#endif
- NULL,
+};
+/* sysfs groups */ static const struct attribute_group coresight_cti_group = { .attrs = coresight_cti_attrs, }; @@ -128,8 +490,14 @@ static const struct attribute_group coresight_cti_mgmt_group = { .name = "mgmt", }; +static const struct attribute_group coresight_cti_regs_group = {
- .attrs = coresight_cti_regs_attrs,
- .name = "regs",
+};
const struct attribute_group *coresight_cti_groups[] = { &coresight_cti_group, &coresight_cti_mgmt_group,
- &coresight_cti_regs_group, NULL,
}; diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index b56d9a02c4b4..0368fa7c6179 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -151,6 +151,25 @@ static int cti_disable_hw(struct cti_drvdata *drvdata, bool update_refcount) return 0; } +void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value) +{
- CS_UNLOCK(drvdata->base);
- writel_relaxed(value, drvdata->base + offset);
- CS_LOCK(drvdata->base);
+}
+void cti_write_intack(struct device *dev, u32 ackval) +{
- struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
- struct cti_config *config = &drvdata->config;
- spin_lock(&drvdata->spinlock);
- /* write if enabled */
- if (CTI_PWR_ENA(config))
cti_write_single_reg(drvdata, CTIINTACK, ackval);
- spin_unlock(&drvdata->spinlock);
+}
/*
- Look at the HW DEVID register for some of the HW settings.
- DEVID[15:8] - max number of in / out triggers.
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h index 717035a9aa72..db8667a2691c 100644 --- a/drivers/hwtracing/coresight/coresight-cti.h +++ b/drivers/hwtracing/coresight/coresight-cti.h @@ -186,7 +186,12 @@ struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs, int out_sigs); int cti_enable(struct coresight_device *csdev); int cti_disable(struct coresight_device *csdev); +void cti_write_intack(struct device *dev, u32 ackval); +void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value); struct coresight_platform_data * coresight_cti_get_platform_data(struct device *dev); +/* cti powered and enabled */ +#define CTI_PWR_ENA(p_cfg) (p_cfg->hw_enabled && p_cfg->hw_powered)
#endif /* _CORESIGHT_CORESIGHT_CTI_H */
2.17.1