xref: /linux/drivers/hwtracing/coresight/coresight-cti-sysfs.c (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
1835d722bSMike Leach // SPDX-License-Identifier: GPL-2.0
2835d722bSMike Leach /*
3835d722bSMike Leach  * Copyright (c) 2019 Linaro Limited, All rights reserved.
4835d722bSMike Leach  * Author: Mike Leach <mike.leach@linaro.org>
5835d722bSMike Leach  */
6835d722bSMike Leach 
7298754c5SStephen Boyd #include <linux/atomic.h>
8835d722bSMike Leach #include <linux/coresight.h>
9298754c5SStephen Boyd #include <linux/device.h>
10298754c5SStephen Boyd #include <linux/io.h>
11298754c5SStephen Boyd #include <linux/kernel.h>
12298754c5SStephen Boyd #include <linux/spinlock.h>
13298754c5SStephen Boyd #include <linux/sysfs.h>
14835d722bSMike Leach 
15835d722bSMike Leach #include "coresight-cti.h"
16835d722bSMike Leach 
173c5597e3SMike Leach /*
183c5597e3SMike Leach  * Declare the number of static declared attribute groups
193c5597e3SMike Leach  * Value includes groups + NULL value at end of table.
203c5597e3SMike Leach  */
213c5597e3SMike Leach #define CORESIGHT_CTI_STATIC_GROUPS_MAX 5
223c5597e3SMike Leach 
233c5597e3SMike Leach /*
243c5597e3SMike Leach  * List of trigger signal type names. Match the constants declared in
253c5597e3SMike Leach  * include\dt-bindings\arm\coresight-cti-dt.h
263c5597e3SMike Leach  */
273c5597e3SMike Leach static const char * const sig_type_names[] = {
283c5597e3SMike Leach 	"genio",	/* GEN_IO */
293c5597e3SMike Leach 	"intreq",	/* GEN_INTREQ */
303c5597e3SMike Leach 	"intack",	/* GEN_INTACK */
313c5597e3SMike Leach 	"haltreq",	/* GEN_HALTREQ */
323c5597e3SMike Leach 	"restartreq",	/* GEN_RESTARTREQ */
333c5597e3SMike Leach 	"pe_edbgreq",	/* PE_EDBGREQ */
343c5597e3SMike Leach 	"pe_dbgrestart",/* PE_DBGRESTART */
353c5597e3SMike Leach 	"pe_ctiirq",	/* PE_CTIIRQ */
363c5597e3SMike Leach 	"pe_pmuirq",	/* PE_PMUIRQ */
373c5597e3SMike Leach 	"pe_dbgtrigger",/* PE_DBGTRIGGER */
383c5597e3SMike Leach 	"etm_extout",	/* ETM_EXTOUT */
393c5597e3SMike Leach 	"etm_extin",	/* ETM_EXTIN */
403c5597e3SMike Leach 	"snk_full",	/* SNK_FULL */
413c5597e3SMike Leach 	"snk_acqcomp",	/* SNK_ACQCOMP */
423c5597e3SMike Leach 	"snk_flushcomp",/* SNK_FLUSHCOMP */
433c5597e3SMike Leach 	"snk_flushin",	/* SNK_FLUSHIN */
443c5597e3SMike Leach 	"snk_trigin",	/* SNK_TRIGIN */
453c5597e3SMike Leach 	"stm_asyncout",	/* STM_ASYNCOUT */
463c5597e3SMike Leach 	"stm_tout_spte",/* STM_TOUT_SPTE */
473c5597e3SMike Leach 	"stm_tout_sw",	/* STM_TOUT_SW */
483c5597e3SMike Leach 	"stm_tout_hete",/* STM_TOUT_HETE */
493c5597e3SMike Leach 	"stm_hwevent",	/* STM_HWEVENT */
503c5597e3SMike Leach 	"ela_tstart",	/* ELA_TSTART */
513c5597e3SMike Leach 	"ela_tstop",	/* ELA_TSTOP */
523c5597e3SMike Leach 	"ela_dbgreq",	/* ELA_DBGREQ */
533c5597e3SMike Leach };
543c5597e3SMike Leach 
553c5597e3SMike Leach /* Show function pointer used in the connections dynamic declared attributes*/
563c5597e3SMike Leach typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr,
573c5597e3SMike Leach 			     char *buf);
583c5597e3SMike Leach 
593c5597e3SMike Leach /* Connection attribute types */
603c5597e3SMike Leach enum cti_conn_attr_type {
613c5597e3SMike Leach 	CTI_CON_ATTR_NAME,
623c5597e3SMike Leach 	CTI_CON_ATTR_TRIGIN_SIG,
633c5597e3SMike Leach 	CTI_CON_ATTR_TRIGOUT_SIG,
643c5597e3SMike Leach 	CTI_CON_ATTR_TRIGIN_TYPES,
653c5597e3SMike Leach 	CTI_CON_ATTR_TRIGOUT_TYPES,
663c5597e3SMike Leach 	CTI_CON_ATTR_MAX,
673c5597e3SMike Leach };
683c5597e3SMike Leach 
693c5597e3SMike Leach /* Names for the connection attributes */
703c5597e3SMike Leach static const char * const con_attr_names[CTI_CON_ATTR_MAX] = {
713c5597e3SMike Leach 	"name",
723c5597e3SMike Leach 	"in_signals",
733c5597e3SMike Leach 	"out_signals",
743c5597e3SMike Leach 	"in_types",
753c5597e3SMike Leach 	"out_types",
763c5597e3SMike Leach };
773c5597e3SMike Leach 
78835d722bSMike Leach /* basic attributes */
enable_show(struct device * dev,struct device_attribute * attr,char * buf)79835d722bSMike Leach static ssize_t enable_show(struct device *dev,
80835d722bSMike Leach 			   struct device_attribute *attr,
81835d722bSMike Leach 			   char *buf)
82835d722bSMike Leach {
83835d722bSMike Leach 	int enable_req;
84835d722bSMike Leach 	bool enabled, powered;
85835d722bSMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
86835d722bSMike Leach 
87835d722bSMike Leach 	spin_lock(&drvdata->spinlock);
88479043b7SJames Clark 	enable_req = drvdata->config.enable_req_count;
89835d722bSMike Leach 	powered = drvdata->config.hw_powered;
90835d722bSMike Leach 	enabled = drvdata->config.hw_enabled;
91835d722bSMike Leach 	spin_unlock(&drvdata->spinlock);
92835d722bSMike Leach 
93835d722bSMike Leach 	if (powered)
94835d722bSMike Leach 		return sprintf(buf, "%d\n", enabled);
95835d722bSMike Leach 	else
96835d722bSMike Leach 		return sprintf(buf, "%d\n", !!enable_req);
97835d722bSMike Leach }
98835d722bSMike Leach 
enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)99835d722bSMike Leach static ssize_t enable_store(struct device *dev,
100835d722bSMike Leach 			    struct device_attribute *attr,
101835d722bSMike Leach 			    const char *buf, size_t size)
102835d722bSMike Leach {
103835d722bSMike Leach 	int ret = 0;
104835d722bSMike Leach 	unsigned long val;
105835d722bSMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
106835d722bSMike Leach 
107835d722bSMike Leach 	ret = kstrtoul(buf, 0, &val);
108835d722bSMike Leach 	if (ret)
109835d722bSMike Leach 		return ret;
110835d722bSMike Leach 
111eff674a9SMao Jinlong 	if (val) {
112eff674a9SMao Jinlong 		ret = pm_runtime_resume_and_get(dev->parent);
113eff674a9SMao Jinlong 		if (ret)
114eff674a9SMao Jinlong 			return ret;
115*1b5b1646SJames Clark 		ret = cti_enable(drvdata->csdev, CS_MODE_SYSFS, NULL);
116eff674a9SMao Jinlong 		if (ret)
117eff674a9SMao Jinlong 			pm_runtime_put(dev->parent);
118eff674a9SMao Jinlong 	} else {
119*1b5b1646SJames Clark 		ret = cti_disable(drvdata->csdev, NULL);
120eff674a9SMao Jinlong 		if (!ret)
121eff674a9SMao Jinlong 			pm_runtime_put(dev->parent);
122eff674a9SMao Jinlong 	}
123eff674a9SMao Jinlong 
124835d722bSMike Leach 	if (ret)
125835d722bSMike Leach 		return ret;
126835d722bSMike Leach 	return size;
127835d722bSMike Leach }
128835d722bSMike Leach static DEVICE_ATTR_RW(enable);
129835d722bSMike Leach 
powered_show(struct device * dev,struct device_attribute * attr,char * buf)130835d722bSMike Leach static ssize_t powered_show(struct device *dev,
131835d722bSMike Leach 			    struct device_attribute *attr,
132835d722bSMike Leach 			    char *buf)
133835d722bSMike Leach {
134835d722bSMike Leach 	bool powered;
135835d722bSMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
136835d722bSMike Leach 
137835d722bSMike Leach 	spin_lock(&drvdata->spinlock);
138835d722bSMike Leach 	powered = drvdata->config.hw_powered;
139835d722bSMike Leach 	spin_unlock(&drvdata->spinlock);
140835d722bSMike Leach 
141835d722bSMike Leach 	return sprintf(buf, "%d\n", powered);
142835d722bSMike Leach }
143835d722bSMike Leach static DEVICE_ATTR_RO(powered);
144835d722bSMike Leach 
ctmid_show(struct device * dev,struct device_attribute * attr,char * buf)145a5614770SMike Leach static ssize_t ctmid_show(struct device *dev,
146a5614770SMike Leach 			  struct device_attribute *attr, char *buf)
147a5614770SMike Leach {
148a5614770SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
149a5614770SMike Leach 
150a5614770SMike Leach 	return sprintf(buf, "%d\n", drvdata->ctidev.ctm_id);
151a5614770SMike Leach }
152a5614770SMike Leach static DEVICE_ATTR_RO(ctmid);
153a5614770SMike Leach 
nr_trigger_cons_show(struct device * dev,struct device_attribute * attr,char * buf)1543c5597e3SMike Leach static ssize_t nr_trigger_cons_show(struct device *dev,
1553c5597e3SMike Leach 				    struct device_attribute *attr,
1563c5597e3SMike Leach 				    char *buf)
1573c5597e3SMike Leach {
1583c5597e3SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
1593c5597e3SMike Leach 
1603c5597e3SMike Leach 	return sprintf(buf, "%d\n", drvdata->ctidev.nr_trig_con);
1613c5597e3SMike Leach }
1623c5597e3SMike Leach static DEVICE_ATTR_RO(nr_trigger_cons);
1633c5597e3SMike Leach 
164835d722bSMike Leach /* attribute and group sysfs tables. */
165835d722bSMike Leach static struct attribute *coresight_cti_attrs[] = {
166835d722bSMike Leach 	&dev_attr_enable.attr,
167835d722bSMike Leach 	&dev_attr_powered.attr,
168a5614770SMike Leach 	&dev_attr_ctmid.attr,
1693c5597e3SMike Leach 	&dev_attr_nr_trigger_cons.attr,
170835d722bSMike Leach 	NULL,
171835d722bSMike Leach };
172835d722bSMike Leach 
1731a556ca6SMike Leach /* register based attributes */
1741a556ca6SMike Leach 
175fbca79e5SJames Clark /* Read registers with power check only (no enable check). */
coresight_cti_reg_show(struct device * dev,struct device_attribute * attr,char * buf)176fbca79e5SJames Clark static ssize_t coresight_cti_reg_show(struct device *dev,
177fbca79e5SJames Clark 			   struct device_attribute *attr, char *buf)
178fbca79e5SJames Clark {
179fbca79e5SJames Clark 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
180fbca79e5SJames Clark 	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
181fbca79e5SJames Clark 	u32 val = 0;
182fbca79e5SJames Clark 
183fbca79e5SJames Clark 	pm_runtime_get_sync(dev->parent);
184fbca79e5SJames Clark 	spin_lock(&drvdata->spinlock);
185fbca79e5SJames Clark 	if (drvdata->config.hw_powered)
186fbca79e5SJames Clark 		val = readl_relaxed(drvdata->base + cti_attr->off);
187fbca79e5SJames Clark 	spin_unlock(&drvdata->spinlock);
188fbca79e5SJames Clark 	pm_runtime_put_sync(dev->parent);
189fbca79e5SJames Clark 	return sysfs_emit(buf, "0x%x\n", val);
190fbca79e5SJames Clark }
191fbca79e5SJames Clark 
192fbca79e5SJames Clark /* Write registers with power check only (no enable check). */
coresight_cti_reg_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)193269e633dSNathan Chancellor static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,
194fbca79e5SJames Clark 						      struct device_attribute *attr,
195fbca79e5SJames Clark 						      const char *buf, size_t size)
196fbca79e5SJames Clark {
197fbca79e5SJames Clark 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
198fbca79e5SJames Clark 	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);
199fbca79e5SJames Clark 	unsigned long val = 0;
200fbca79e5SJames Clark 
201fbca79e5SJames Clark 	if (kstrtoul(buf, 0, &val))
202fbca79e5SJames Clark 		return -EINVAL;
203fbca79e5SJames Clark 
204fbca79e5SJames Clark 	pm_runtime_get_sync(dev->parent);
205fbca79e5SJames Clark 	spin_lock(&drvdata->spinlock);
206fbca79e5SJames Clark 	if (drvdata->config.hw_powered)
207fbca79e5SJames Clark 		cti_write_single_reg(drvdata, cti_attr->off, val);
208fbca79e5SJames Clark 	spin_unlock(&drvdata->spinlock);
209fbca79e5SJames Clark 	pm_runtime_put_sync(dev->parent);
210fbca79e5SJames Clark 	return size;
211fbca79e5SJames Clark }
212fbca79e5SJames Clark 
2131a556ca6SMike Leach #define coresight_cti_reg(name, offset)					\
214fbca79e5SJames Clark 	(&((struct cs_off_attribute[]) {				\
2151a556ca6SMike Leach 	   {								\
216fbca79e5SJames Clark 		__ATTR(name, 0444, coresight_cti_reg_show, NULL),	\
217fbca79e5SJames Clark 		offset							\
2181a556ca6SMike Leach 	   }								\
219fbca79e5SJames Clark 	})[0].attr.attr)
220fbca79e5SJames Clark 
221fbca79e5SJames Clark #define coresight_cti_reg_rw(name, offset)				\
222fbca79e5SJames Clark 	(&((struct cs_off_attribute[]) {				\
223fbca79e5SJames Clark 	   {								\
224fbca79e5SJames Clark 		__ATTR(name, 0644, coresight_cti_reg_show,		\
225fbca79e5SJames Clark 		       coresight_cti_reg_store),			\
226fbca79e5SJames Clark 		offset							\
227fbca79e5SJames Clark 	   }								\
228fbca79e5SJames Clark 	})[0].attr.attr)
229fbca79e5SJames Clark 
230fbca79e5SJames Clark #define coresight_cti_reg_wo(name, offset)				\
231fbca79e5SJames Clark 	(&((struct cs_off_attribute[]) {				\
232fbca79e5SJames Clark 	   {								\
233fbca79e5SJames Clark 		__ATTR(name, 0200, NULL, coresight_cti_reg_store),	\
234fbca79e5SJames Clark 		offset							\
235fbca79e5SJames Clark 	   }								\
236fbca79e5SJames Clark 	})[0].attr.attr)
2371a556ca6SMike Leach 
2381a556ca6SMike Leach /* coresight management registers */
2391a556ca6SMike Leach static struct attribute *coresight_cti_mgmt_attrs[] = {
240fbca79e5SJames Clark 	coresight_cti_reg(devaff0, CTIDEVAFF0),
241fbca79e5SJames Clark 	coresight_cti_reg(devaff1, CTIDEVAFF1),
242fbca79e5SJames Clark 	coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS),
243fbca79e5SJames Clark 	coresight_cti_reg(devarch, CORESIGHT_DEVARCH),
244fbca79e5SJames Clark 	coresight_cti_reg(devid, CORESIGHT_DEVID),
245fbca79e5SJames Clark 	coresight_cti_reg(devtype, CORESIGHT_DEVTYPE),
246fbca79e5SJames Clark 	coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0),
247fbca79e5SJames Clark 	coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1),
248fbca79e5SJames Clark 	coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2),
249fbca79e5SJames Clark 	coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3),
250fbca79e5SJames Clark 	coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4),
2511a556ca6SMike Leach 	NULL,
2521a556ca6SMike Leach };
2531a556ca6SMike Leach 
254b5213376SMike Leach /* CTI low level programming registers */
255b5213376SMike Leach 
256b5213376SMike Leach /*
257b5213376SMike Leach  * Show a simple 32 bit value if enabled and powered.
258b5213376SMike Leach  * If inaccessible & pcached_val not NULL then show cached value.
259b5213376SMike Leach  */
cti_reg32_show(struct device * dev,char * buf,u32 * pcached_val,int reg_offset)260b5213376SMike Leach static ssize_t cti_reg32_show(struct device *dev, char *buf,
261b5213376SMike Leach 			      u32 *pcached_val, int reg_offset)
262b5213376SMike Leach {
263b5213376SMike Leach 	u32 val = 0;
264b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
265b5213376SMike Leach 	struct cti_config *config = &drvdata->config;
266b5213376SMike Leach 
267b5213376SMike Leach 	spin_lock(&drvdata->spinlock);
268b5213376SMike Leach 	if ((reg_offset >= 0) && cti_active(config)) {
269b5213376SMike Leach 		CS_UNLOCK(drvdata->base);
270b5213376SMike Leach 		val = readl_relaxed(drvdata->base + reg_offset);
271b5213376SMike Leach 		if (pcached_val)
272b5213376SMike Leach 			*pcached_val = val;
273b5213376SMike Leach 		CS_LOCK(drvdata->base);
274b5213376SMike Leach 	} else if (pcached_val) {
275b5213376SMike Leach 		val = *pcached_val;
276b5213376SMike Leach 	}
277b5213376SMike Leach 	spin_unlock(&drvdata->spinlock);
278b5213376SMike Leach 	return sprintf(buf, "%#x\n", val);
279b5213376SMike Leach }
280b5213376SMike Leach 
281b5213376SMike Leach /*
282b5213376SMike Leach  * Store a simple 32 bit value.
283b5213376SMike Leach  * If pcached_val not NULL, then copy to here too,
284b5213376SMike Leach  * if reg_offset >= 0 then write through if enabled.
285b5213376SMike Leach  */
cti_reg32_store(struct device * dev,const char * buf,size_t size,u32 * pcached_val,int reg_offset)286b5213376SMike Leach static ssize_t cti_reg32_store(struct device *dev, const char *buf,
287b5213376SMike Leach 			       size_t size, u32 *pcached_val, int reg_offset)
288b5213376SMike Leach {
289b5213376SMike Leach 	unsigned long val;
290b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
291b5213376SMike Leach 	struct cti_config *config = &drvdata->config;
292b5213376SMike Leach 
293b5213376SMike Leach 	if (kstrtoul(buf, 0, &val))
294b5213376SMike Leach 		return -EINVAL;
295b5213376SMike Leach 
296b5213376SMike Leach 	spin_lock(&drvdata->spinlock);
297b5213376SMike Leach 	/* local store */
298b5213376SMike Leach 	if (pcached_val)
299b5213376SMike Leach 		*pcached_val = (u32)val;
300b5213376SMike Leach 
301b5213376SMike Leach 	/* write through if offset and enabled */
302b5213376SMike Leach 	if ((reg_offset >= 0) && cti_active(config))
303b5213376SMike Leach 		cti_write_single_reg(drvdata, reg_offset, val);
304b5213376SMike Leach 	spin_unlock(&drvdata->spinlock);
305b5213376SMike Leach 	return size;
306b5213376SMike Leach }
307b5213376SMike Leach 
308b5213376SMike Leach /* Standard macro for simple rw cti config registers */
309b5213376SMike Leach #define cti_config_reg32_rw(name, cfgname, offset)			\
310b5213376SMike Leach static ssize_t name##_show(struct device *dev,				\
311b5213376SMike Leach 			   struct device_attribute *attr,		\
312b5213376SMike Leach 			   char *buf)					\
313b5213376SMike Leach {									\
314b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);	\
315b5213376SMike Leach 	return cti_reg32_show(dev, buf,					\
316b5213376SMike Leach 			      &drvdata->config.cfgname, offset);	\
317b5213376SMike Leach }									\
318b5213376SMike Leach 									\
319b5213376SMike Leach static ssize_t name##_store(struct device *dev,				\
320b5213376SMike Leach 			    struct device_attribute *attr,		\
321b5213376SMike Leach 			    const char *buf, size_t size)		\
322b5213376SMike Leach {									\
323b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);	\
324b5213376SMike Leach 	return cti_reg32_store(dev, buf, size,				\
325b5213376SMike Leach 			       &drvdata->config.cfgname, offset);	\
326b5213376SMike Leach }									\
327b5213376SMike Leach static DEVICE_ATTR_RW(name)
328b5213376SMike Leach 
inout_sel_show(struct device * dev,struct device_attribute * attr,char * buf)329b5213376SMike Leach static ssize_t inout_sel_show(struct device *dev,
330b5213376SMike Leach 			      struct device_attribute *attr,
331b5213376SMike Leach 			      char *buf)
332b5213376SMike Leach {
333b5213376SMike Leach 	u32 val;
334b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
335b5213376SMike Leach 
336b5213376SMike Leach 	val = (u32)drvdata->config.ctiinout_sel;
337b5213376SMike Leach 	return sprintf(buf, "%d\n", val);
338b5213376SMike Leach }
339b5213376SMike Leach 
inout_sel_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)340b5213376SMike Leach static ssize_t inout_sel_store(struct device *dev,
341b5213376SMike Leach 			       struct device_attribute *attr,
342b5213376SMike Leach 			       const char *buf, size_t size)
343b5213376SMike Leach {
344b5213376SMike Leach 	unsigned long val;
345b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
346b5213376SMike Leach 
347b5213376SMike Leach 	if (kstrtoul(buf, 0, &val))
348b5213376SMike Leach 		return -EINVAL;
349b5213376SMike Leach 	if (val > (CTIINOUTEN_MAX - 1))
350b5213376SMike Leach 		return -EINVAL;
351b5213376SMike Leach 
352b5213376SMike Leach 	spin_lock(&drvdata->spinlock);
353b5213376SMike Leach 	drvdata->config.ctiinout_sel = val;
354b5213376SMike Leach 	spin_unlock(&drvdata->spinlock);
355b5213376SMike Leach 	return size;
356b5213376SMike Leach }
357b5213376SMike Leach static DEVICE_ATTR_RW(inout_sel);
358b5213376SMike Leach 
inen_show(struct device * dev,struct device_attribute * attr,char * buf)359b5213376SMike Leach static ssize_t inen_show(struct device *dev,
360b5213376SMike Leach 			 struct device_attribute *attr,
361b5213376SMike Leach 			 char *buf)
362b5213376SMike Leach {
363b5213376SMike Leach 	unsigned long val;
364b5213376SMike Leach 	int index;
365b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
366b5213376SMike Leach 
367b5213376SMike Leach 	spin_lock(&drvdata->spinlock);
368b5213376SMike Leach 	index = drvdata->config.ctiinout_sel;
369b5213376SMike Leach 	val = drvdata->config.ctiinen[index];
370b5213376SMike Leach 	spin_unlock(&drvdata->spinlock);
371b5213376SMike Leach 	return sprintf(buf, "%#lx\n", val);
372b5213376SMike Leach }
373b5213376SMike Leach 
inen_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)374b5213376SMike Leach static ssize_t inen_store(struct device *dev,
375b5213376SMike Leach 			  struct device_attribute *attr,
376b5213376SMike Leach 			  const char *buf, size_t size)
377b5213376SMike Leach {
378b5213376SMike Leach 	unsigned long val;
379b5213376SMike Leach 	int index;
380b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
381b5213376SMike Leach 	struct cti_config *config = &drvdata->config;
382b5213376SMike Leach 
383b5213376SMike Leach 	if (kstrtoul(buf, 0, &val))
384b5213376SMike Leach 		return -EINVAL;
385b5213376SMike Leach 
386b5213376SMike Leach 	spin_lock(&drvdata->spinlock);
387b5213376SMike Leach 	index = config->ctiinout_sel;
388b5213376SMike Leach 	config->ctiinen[index] = val;
389b5213376SMike Leach 
390b5213376SMike Leach 	/* write through if enabled */
391b5213376SMike Leach 	if (cti_active(config))
392b5213376SMike Leach 		cti_write_single_reg(drvdata, CTIINEN(index), val);
393b5213376SMike Leach 	spin_unlock(&drvdata->spinlock);
394b5213376SMike Leach 	return size;
395b5213376SMike Leach }
396b5213376SMike Leach static DEVICE_ATTR_RW(inen);
397b5213376SMike Leach 
outen_show(struct device * dev,struct device_attribute * attr,char * buf)398b5213376SMike Leach static ssize_t outen_show(struct device *dev,
399b5213376SMike Leach 			  struct device_attribute *attr,
400b5213376SMike Leach 			  char *buf)
401b5213376SMike Leach {
402b5213376SMike Leach 	unsigned long val;
403b5213376SMike Leach 	int index;
404b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
405b5213376SMike Leach 
406b5213376SMike Leach 	spin_lock(&drvdata->spinlock);
407b5213376SMike Leach 	index = drvdata->config.ctiinout_sel;
408b5213376SMike Leach 	val = drvdata->config.ctiouten[index];
409b5213376SMike Leach 	spin_unlock(&drvdata->spinlock);
410b5213376SMike Leach 	return sprintf(buf, "%#lx\n", val);
411b5213376SMike Leach }
412b5213376SMike Leach 
outen_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)413b5213376SMike Leach static ssize_t outen_store(struct device *dev,
414b5213376SMike Leach 			   struct device_attribute *attr,
415b5213376SMike Leach 			   const char *buf, size_t size)
416b5213376SMike Leach {
417b5213376SMike Leach 	unsigned long val;
418b5213376SMike Leach 	int index;
419b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
420b5213376SMike Leach 	struct cti_config *config = &drvdata->config;
421b5213376SMike Leach 
422b5213376SMike Leach 	if (kstrtoul(buf, 0, &val))
423b5213376SMike Leach 		return -EINVAL;
424b5213376SMike Leach 
425b5213376SMike Leach 	spin_lock(&drvdata->spinlock);
426b5213376SMike Leach 	index = config->ctiinout_sel;
427b5213376SMike Leach 	config->ctiouten[index] = val;
428b5213376SMike Leach 
429b5213376SMike Leach 	/* write through if enabled */
430b5213376SMike Leach 	if (cti_active(config))
431b5213376SMike Leach 		cti_write_single_reg(drvdata, CTIOUTEN(index), val);
432b5213376SMike Leach 	spin_unlock(&drvdata->spinlock);
433b5213376SMike Leach 	return size;
434b5213376SMike Leach }
435b5213376SMike Leach static DEVICE_ATTR_RW(outen);
436b5213376SMike Leach 
intack_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)437b5213376SMike Leach static ssize_t intack_store(struct device *dev,
438b5213376SMike Leach 			    struct device_attribute *attr,
439b5213376SMike Leach 			    const char *buf, size_t size)
440b5213376SMike Leach {
441b5213376SMike Leach 	unsigned long val;
442b5213376SMike Leach 
443b5213376SMike Leach 	if (kstrtoul(buf, 0, &val))
444b5213376SMike Leach 		return -EINVAL;
445b5213376SMike Leach 
446b5213376SMike Leach 	cti_write_intack(dev, val);
447b5213376SMike Leach 	return size;
448b5213376SMike Leach }
449b5213376SMike Leach static DEVICE_ATTR_WO(intack);
450b5213376SMike Leach 
451b5213376SMike Leach cti_config_reg32_rw(gate, ctigate, CTIGATE);
452b5213376SMike Leach cti_config_reg32_rw(asicctl, asicctl, ASICCTL);
453b5213376SMike Leach cti_config_reg32_rw(appset, ctiappset, CTIAPPSET);
454b5213376SMike Leach 
appclear_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)455b5213376SMike Leach static ssize_t appclear_store(struct device *dev,
456b5213376SMike Leach 			      struct device_attribute *attr,
457b5213376SMike Leach 			      const char *buf, size_t size)
458b5213376SMike Leach {
459b5213376SMike Leach 	unsigned long val;
460b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
461b5213376SMike Leach 	struct cti_config *config = &drvdata->config;
462b5213376SMike Leach 
463b5213376SMike Leach 	if (kstrtoul(buf, 0, &val))
464b5213376SMike Leach 		return -EINVAL;
465b5213376SMike Leach 
466b5213376SMike Leach 	spin_lock(&drvdata->spinlock);
467b5213376SMike Leach 
468b5213376SMike Leach 	/* a 1'b1 in appclr clears down the same bit in appset*/
469b5213376SMike Leach 	config->ctiappset &= ~val;
470b5213376SMike Leach 
471b5213376SMike Leach 	/* write through if enabled */
472b5213376SMike Leach 	if (cti_active(config))
473b5213376SMike Leach 		cti_write_single_reg(drvdata, CTIAPPCLEAR, val);
474b5213376SMike Leach 	spin_unlock(&drvdata->spinlock);
475b5213376SMike Leach 	return size;
476b5213376SMike Leach }
477b5213376SMike Leach static DEVICE_ATTR_WO(appclear);
478b5213376SMike Leach 
apppulse_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)479b5213376SMike Leach static ssize_t apppulse_store(struct device *dev,
480b5213376SMike Leach 			      struct device_attribute *attr,
481b5213376SMike Leach 			      const char *buf, size_t size)
482b5213376SMike Leach {
483b5213376SMike Leach 	unsigned long val;
484b5213376SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
485b5213376SMike Leach 	struct cti_config *config = &drvdata->config;
486b5213376SMike Leach 
487b5213376SMike Leach 	if (kstrtoul(buf, 0, &val))
488b5213376SMike Leach 		return -EINVAL;
489b5213376SMike Leach 
490b5213376SMike Leach 	spin_lock(&drvdata->spinlock);
491b5213376SMike Leach 
492b5213376SMike Leach 	/* write through if enabled */
493b5213376SMike Leach 	if (cti_active(config))
494b5213376SMike Leach 		cti_write_single_reg(drvdata, CTIAPPPULSE, val);
495b5213376SMike Leach 	spin_unlock(&drvdata->spinlock);
496b5213376SMike Leach 	return size;
497b5213376SMike Leach }
498b5213376SMike Leach static DEVICE_ATTR_WO(apppulse);
499b5213376SMike Leach 
500b5213376SMike Leach /*
501b5213376SMike Leach  * Define CONFIG_CORESIGHT_CTI_INTEGRATION_REGS to enable the access to the
502b5213376SMike Leach  * integration control registers. Normally only used to investigate connection
503b5213376SMike Leach  * data.
504b5213376SMike Leach  */
505b5213376SMike Leach static struct attribute *coresight_cti_regs_attrs[] = {
506b5213376SMike Leach 	&dev_attr_inout_sel.attr,
507b5213376SMike Leach 	&dev_attr_inen.attr,
508b5213376SMike Leach 	&dev_attr_outen.attr,
509b5213376SMike Leach 	&dev_attr_gate.attr,
510b5213376SMike Leach 	&dev_attr_asicctl.attr,
511b5213376SMike Leach 	&dev_attr_intack.attr,
512b5213376SMike Leach 	&dev_attr_appset.attr,
513b5213376SMike Leach 	&dev_attr_appclear.attr,
514b5213376SMike Leach 	&dev_attr_apppulse.attr,
515fbca79e5SJames Clark 	coresight_cti_reg(triginstatus, CTITRIGINSTATUS),
516fbca79e5SJames Clark 	coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),
517fbca79e5SJames Clark 	coresight_cti_reg(chinstatus, CTICHINSTATUS),
518fbca79e5SJames Clark 	coresight_cti_reg(choutstatus, CTICHOUTSTATUS),
519b5213376SMike Leach #ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS
520fbca79e5SJames Clark 	coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),
521fbca79e5SJames Clark 	coresight_cti_reg(ittrigin, ITTRIGIN),
522fbca79e5SJames Clark 	coresight_cti_reg(itchin, ITCHIN),
523fbca79e5SJames Clark 	coresight_cti_reg_rw(ittrigout, ITTRIGOUT),
524fbca79e5SJames Clark 	coresight_cti_reg_rw(itchout, ITCHOUT),
525fbca79e5SJames Clark 	coresight_cti_reg(itchoutack, ITCHOUTACK),
526fbca79e5SJames Clark 	coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),
527fbca79e5SJames Clark 	coresight_cti_reg_wo(ittriginack, ITTRIGINACK),
528fbca79e5SJames Clark 	coresight_cti_reg_wo(itchinack, ITCHINACK),
529b5213376SMike Leach #endif
530b5213376SMike Leach 	NULL,
531b5213376SMike Leach };
532b5213376SMike Leach 
5331bf82857SMike Leach /* CTI channel x-trigger programming */
5341bf82857SMike Leach static int
cti_trig_op_parse(struct device * dev,enum cti_chan_op op,enum cti_trig_dir dir,const char * buf,size_t size)5351bf82857SMike Leach cti_trig_op_parse(struct device *dev, enum cti_chan_op op,
5361bf82857SMike Leach 		  enum cti_trig_dir dir, const char *buf, size_t size)
5371bf82857SMike Leach {
5381bf82857SMike Leach 	u32 chan_idx;
5391bf82857SMike Leach 	u32 trig_idx;
5401bf82857SMike Leach 	int items, err = -EINVAL;
5411bf82857SMike Leach 
5421bf82857SMike Leach 	/* extract chan idx and trigger idx */
5431bf82857SMike Leach 	items = sscanf(buf, "%d %d", &chan_idx, &trig_idx);
5441bf82857SMike Leach 	if (items == 2) {
5451bf82857SMike Leach 		err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx);
5461bf82857SMike Leach 		if (!err)
5471bf82857SMike Leach 			err = size;
5481bf82857SMike Leach 	}
5491bf82857SMike Leach 	return err;
5501bf82857SMike Leach }
5511bf82857SMike Leach 
trigin_attach_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)5521bf82857SMike Leach static ssize_t trigin_attach_store(struct device *dev,
5531bf82857SMike Leach 				   struct device_attribute *attr,
5541bf82857SMike Leach 				   const char *buf, size_t size)
5551bf82857SMike Leach {
5561bf82857SMike Leach 	return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_IN,
5571bf82857SMike Leach 				 buf, size);
5581bf82857SMike Leach }
5591bf82857SMike Leach static DEVICE_ATTR_WO(trigin_attach);
5601bf82857SMike Leach 
trigin_detach_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)5611bf82857SMike Leach static ssize_t trigin_detach_store(struct device *dev,
5621bf82857SMike Leach 				   struct device_attribute *attr,
5631bf82857SMike Leach 				   const char *buf, size_t size)
5641bf82857SMike Leach {
5651bf82857SMike Leach 	return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_IN,
5661bf82857SMike Leach 				 buf, size);
5671bf82857SMike Leach }
5681bf82857SMike Leach static DEVICE_ATTR_WO(trigin_detach);
5691bf82857SMike Leach 
trigout_attach_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)5701bf82857SMike Leach static ssize_t trigout_attach_store(struct device *dev,
5711bf82857SMike Leach 				    struct device_attribute *attr,
5721bf82857SMike Leach 				    const char *buf, size_t size)
5731bf82857SMike Leach {
5741bf82857SMike Leach 	return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_OUT,
5751bf82857SMike Leach 				 buf, size);
5761bf82857SMike Leach }
5771bf82857SMike Leach static DEVICE_ATTR_WO(trigout_attach);
5781bf82857SMike Leach 
trigout_detach_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)5791bf82857SMike Leach static ssize_t trigout_detach_store(struct device *dev,
5801bf82857SMike Leach 				    struct device_attribute *attr,
5811bf82857SMike Leach 				    const char *buf, size_t size)
5821bf82857SMike Leach {
5831bf82857SMike Leach 	return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_OUT,
5841bf82857SMike Leach 				 buf, size);
5851bf82857SMike Leach }
5861bf82857SMike Leach static DEVICE_ATTR_WO(trigout_detach);
5871bf82857SMike Leach 
5881bf82857SMike Leach 
chan_gate_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)5891bf82857SMike Leach static ssize_t chan_gate_enable_store(struct device *dev,
5901bf82857SMike Leach 				      struct device_attribute *attr,
5911bf82857SMike Leach 				      const char *buf, size_t size)
5921bf82857SMike Leach {
5931bf82857SMike Leach 	int err = 0, channel = 0;
5941bf82857SMike Leach 
5951bf82857SMike Leach 	if (kstrtoint(buf, 0, &channel))
5961bf82857SMike Leach 		return -EINVAL;
5971bf82857SMike Leach 
5981bf82857SMike Leach 	err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel);
5991bf82857SMike Leach 	return err ? err : size;
6001bf82857SMike Leach }
6011bf82857SMike Leach 
chan_gate_enable_show(struct device * dev,struct device_attribute * attr,char * buf)6021bf82857SMike Leach static ssize_t chan_gate_enable_show(struct device *dev,
6031bf82857SMike Leach 				     struct device_attribute *attr,
6041bf82857SMike Leach 				     char *buf)
6051bf82857SMike Leach {
6061bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
6071bf82857SMike Leach 	struct cti_config *cfg = &drvdata->config;
6081bf82857SMike Leach 	unsigned long ctigate_bitmask = cfg->ctigate;
6091bf82857SMike Leach 	int size = 0;
6101bf82857SMike Leach 
6111bf82857SMike Leach 	if (cfg->ctigate == 0)
6121bf82857SMike Leach 		size = sprintf(buf, "\n");
6131bf82857SMike Leach 	else
6141bf82857SMike Leach 		size = bitmap_print_to_pagebuf(true, buf, &ctigate_bitmask,
6151bf82857SMike Leach 					       cfg->nr_ctm_channels);
6161bf82857SMike Leach 	return size;
6171bf82857SMike Leach }
6181bf82857SMike Leach static DEVICE_ATTR_RW(chan_gate_enable);
6191bf82857SMike Leach 
chan_gate_disable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)6201bf82857SMike Leach static ssize_t chan_gate_disable_store(struct device *dev,
6211bf82857SMike Leach 				       struct device_attribute *attr,
6221bf82857SMike Leach 				       const char *buf, size_t size)
6231bf82857SMike Leach {
6241bf82857SMike Leach 	int err = 0, channel = 0;
6251bf82857SMike Leach 
6261bf82857SMike Leach 	if (kstrtoint(buf, 0, &channel))
6271bf82857SMike Leach 		return -EINVAL;
6281bf82857SMike Leach 
6291bf82857SMike Leach 	err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE, channel);
6301bf82857SMike Leach 	return err ? err : size;
6311bf82857SMike Leach }
6321bf82857SMike Leach static DEVICE_ATTR_WO(chan_gate_disable);
6331bf82857SMike Leach 
6341bf82857SMike Leach static int
chan_op_parse(struct device * dev,enum cti_chan_set_op op,const char * buf)6351bf82857SMike Leach chan_op_parse(struct device *dev, enum cti_chan_set_op op, const char *buf)
6361bf82857SMike Leach {
6371bf82857SMike Leach 	int err = 0, channel = 0;
6381bf82857SMike Leach 
6391bf82857SMike Leach 	if (kstrtoint(buf, 0, &channel))
6401bf82857SMike Leach 		return -EINVAL;
6411bf82857SMike Leach 
6421bf82857SMike Leach 	err = cti_channel_setop(dev, op, channel);
6431bf82857SMike Leach 	return err;
6441bf82857SMike Leach 
6451bf82857SMike Leach }
6461bf82857SMike Leach 
chan_set_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)6471bf82857SMike Leach static ssize_t chan_set_store(struct device *dev,
6481bf82857SMike Leach 			      struct device_attribute *attr,
6491bf82857SMike Leach 			      const char *buf, size_t size)
6501bf82857SMike Leach {
6511bf82857SMike Leach 	int err = chan_op_parse(dev, CTI_CHAN_SET, buf);
6521bf82857SMike Leach 
6531bf82857SMike Leach 	return err ? err : size;
6541bf82857SMike Leach }
6551bf82857SMike Leach static DEVICE_ATTR_WO(chan_set);
6561bf82857SMike Leach 
chan_clear_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)6571bf82857SMike Leach static ssize_t chan_clear_store(struct device *dev,
6581bf82857SMike Leach 				struct device_attribute *attr,
6591bf82857SMike Leach 				const char *buf, size_t size)
6601bf82857SMike Leach {
6611bf82857SMike Leach 	int err = chan_op_parse(dev, CTI_CHAN_CLR, buf);
6621bf82857SMike Leach 
6631bf82857SMike Leach 	return err ? err : size;
6641bf82857SMike Leach }
6651bf82857SMike Leach static DEVICE_ATTR_WO(chan_clear);
6661bf82857SMike Leach 
chan_pulse_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)6671bf82857SMike Leach static ssize_t chan_pulse_store(struct device *dev,
6681bf82857SMike Leach 				struct device_attribute *attr,
6691bf82857SMike Leach 				const char *buf, size_t size)
6701bf82857SMike Leach {
6711bf82857SMike Leach 	int err = chan_op_parse(dev, CTI_CHAN_PULSE, buf);
6721bf82857SMike Leach 
6731bf82857SMike Leach 	return err ? err : size;
6741bf82857SMike Leach }
6751bf82857SMike Leach static DEVICE_ATTR_WO(chan_pulse);
6761bf82857SMike Leach 
trig_filter_enable_show(struct device * dev,struct device_attribute * attr,char * buf)6771bf82857SMike Leach static ssize_t trig_filter_enable_show(struct device *dev,
6781bf82857SMike Leach 				       struct device_attribute *attr,
6791bf82857SMike Leach 				       char *buf)
6801bf82857SMike Leach {
6811bf82857SMike Leach 	u32 val;
6821bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
6831bf82857SMike Leach 
6841bf82857SMike Leach 	spin_lock(&drvdata->spinlock);
6851bf82857SMike Leach 	val = drvdata->config.trig_filter_enable;
6861bf82857SMike Leach 	spin_unlock(&drvdata->spinlock);
6871bf82857SMike Leach 	return sprintf(buf, "%d\n", val);
6881bf82857SMike Leach }
6891bf82857SMike Leach 
trig_filter_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)6901bf82857SMike Leach static ssize_t trig_filter_enable_store(struct device *dev,
6911bf82857SMike Leach 					struct device_attribute *attr,
6921bf82857SMike Leach 					const char *buf, size_t size)
6931bf82857SMike Leach {
6941bf82857SMike Leach 	unsigned long val;
6951bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
6961bf82857SMike Leach 
6971bf82857SMike Leach 	if (kstrtoul(buf, 0, &val))
6981bf82857SMike Leach 		return -EINVAL;
6991bf82857SMike Leach 
7001bf82857SMike Leach 	spin_lock(&drvdata->spinlock);
7011bf82857SMike Leach 	drvdata->config.trig_filter_enable = !!val;
7021bf82857SMike Leach 	spin_unlock(&drvdata->spinlock);
7031bf82857SMike Leach 	return size;
7041bf82857SMike Leach }
7051bf82857SMike Leach static DEVICE_ATTR_RW(trig_filter_enable);
7061bf82857SMike Leach 
trigout_filtered_show(struct device * dev,struct device_attribute * attr,char * buf)7071bf82857SMike Leach static ssize_t trigout_filtered_show(struct device *dev,
7081bf82857SMike Leach 				     struct device_attribute *attr,
7091bf82857SMike Leach 				     char *buf)
7101bf82857SMike Leach {
7111bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
7121bf82857SMike Leach 	struct cti_config *cfg = &drvdata->config;
7131bf82857SMike Leach 	int size = 0, nr_trig_max = cfg->nr_trig_max;
7141bf82857SMike Leach 	unsigned long mask = cfg->trig_out_filter;
7151bf82857SMike Leach 
7161bf82857SMike Leach 	if (mask)
7171bf82857SMike Leach 		size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max);
7181bf82857SMike Leach 	return size;
7191bf82857SMike Leach }
7201bf82857SMike Leach static DEVICE_ATTR_RO(trigout_filtered);
7211bf82857SMike Leach 
7221bf82857SMike Leach /* clear all xtrigger / channel programming */
chan_xtrigs_reset_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)7231bf82857SMike Leach static ssize_t chan_xtrigs_reset_store(struct device *dev,
7241bf82857SMike Leach 				       struct device_attribute *attr,
7251bf82857SMike Leach 				       const char *buf, size_t size)
7261bf82857SMike Leach {
7271bf82857SMike Leach 	int i;
7281bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
7291bf82857SMike Leach 	struct cti_config *config = &drvdata->config;
7301bf82857SMike Leach 
7311bf82857SMike Leach 	spin_lock(&drvdata->spinlock);
7321bf82857SMike Leach 
7331bf82857SMike Leach 	/* clear the CTI trigger / channel programming registers */
7341bf82857SMike Leach 	for (i = 0; i < config->nr_trig_max; i++) {
7351bf82857SMike Leach 		config->ctiinen[i] = 0;
7361bf82857SMike Leach 		config->ctiouten[i] = 0;
7371bf82857SMike Leach 	}
7381bf82857SMike Leach 
7391bf82857SMike Leach 	/* clear the other regs */
7401bf82857SMike Leach 	config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);
7411bf82857SMike Leach 	config->asicctl = 0;
7421bf82857SMike Leach 	config->ctiappset = 0;
7431bf82857SMike Leach 	config->ctiinout_sel = 0;
7441bf82857SMike Leach 	config->xtrig_rchan_sel = 0;
7451bf82857SMike Leach 
7461bf82857SMike Leach 	/* if enabled then write through */
7471bf82857SMike Leach 	if (cti_active(config))
7481bf82857SMike Leach 		cti_write_all_hw_regs(drvdata);
7491bf82857SMike Leach 
7501bf82857SMike Leach 	spin_unlock(&drvdata->spinlock);
7511bf82857SMike Leach 	return size;
7521bf82857SMike Leach }
7531bf82857SMike Leach static DEVICE_ATTR_WO(chan_xtrigs_reset);
7541bf82857SMike Leach 
7551bf82857SMike Leach /*
7561bf82857SMike Leach  * Write to select a channel to view, read to display the
7571bf82857SMike Leach  * cross triggers for the selected channel.
7581bf82857SMike Leach  */
chan_xtrigs_sel_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)7591bf82857SMike Leach static ssize_t chan_xtrigs_sel_store(struct device *dev,
7601bf82857SMike Leach 				     struct device_attribute *attr,
7611bf82857SMike Leach 				     const char *buf, size_t size)
7621bf82857SMike Leach {
7631bf82857SMike Leach 	unsigned long val;
7641bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
7651bf82857SMike Leach 
7661bf82857SMike Leach 	if (kstrtoul(buf, 0, &val))
7671bf82857SMike Leach 		return -EINVAL;
7681bf82857SMike Leach 	if (val > (drvdata->config.nr_ctm_channels - 1))
7691bf82857SMike Leach 		return -EINVAL;
7701bf82857SMike Leach 
7711bf82857SMike Leach 	spin_lock(&drvdata->spinlock);
7721bf82857SMike Leach 	drvdata->config.xtrig_rchan_sel = val;
7731bf82857SMike Leach 	spin_unlock(&drvdata->spinlock);
7741bf82857SMike Leach 	return size;
7751bf82857SMike Leach }
7761bf82857SMike Leach 
chan_xtrigs_sel_show(struct device * dev,struct device_attribute * attr,char * buf)7771bf82857SMike Leach static ssize_t chan_xtrigs_sel_show(struct device *dev,
7781bf82857SMike Leach 				    struct device_attribute *attr,
7791bf82857SMike Leach 				    char *buf)
7801bf82857SMike Leach {
7811bf82857SMike Leach 	unsigned long val;
7821bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
7831bf82857SMike Leach 
7841bf82857SMike Leach 	spin_lock(&drvdata->spinlock);
7851bf82857SMike Leach 	val = drvdata->config.xtrig_rchan_sel;
7861bf82857SMike Leach 	spin_unlock(&drvdata->spinlock);
7871bf82857SMike Leach 
7881bf82857SMike Leach 	return sprintf(buf, "%ld\n", val);
7891bf82857SMike Leach }
7901bf82857SMike Leach static DEVICE_ATTR_RW(chan_xtrigs_sel);
7911bf82857SMike Leach 
chan_xtrigs_in_show(struct device * dev,struct device_attribute * attr,char * buf)7921bf82857SMike Leach static ssize_t chan_xtrigs_in_show(struct device *dev,
7931bf82857SMike Leach 				   struct device_attribute *attr,
7941bf82857SMike Leach 				   char *buf)
7951bf82857SMike Leach {
7961bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
7971bf82857SMike Leach 	struct cti_config *cfg = &drvdata->config;
7981bf82857SMike Leach 	int used = 0, reg_idx;
7991bf82857SMike Leach 	int nr_trig_max = drvdata->config.nr_trig_max;
8001bf82857SMike Leach 	u32 chan_mask = BIT(cfg->xtrig_rchan_sel);
8011bf82857SMike Leach 
8021bf82857SMike Leach 	for (reg_idx = 0; reg_idx < nr_trig_max; reg_idx++) {
8031bf82857SMike Leach 		if (chan_mask & cfg->ctiinen[reg_idx])
8041bf82857SMike Leach 			used += sprintf(buf + used, "%d ", reg_idx);
8051bf82857SMike Leach 	}
8061bf82857SMike Leach 
8071bf82857SMike Leach 	used += sprintf(buf + used, "\n");
8081bf82857SMike Leach 	return used;
8091bf82857SMike Leach }
8101bf82857SMike Leach static DEVICE_ATTR_RO(chan_xtrigs_in);
8111bf82857SMike Leach 
chan_xtrigs_out_show(struct device * dev,struct device_attribute * attr,char * buf)8121bf82857SMike Leach static ssize_t chan_xtrigs_out_show(struct device *dev,
8131bf82857SMike Leach 				    struct device_attribute *attr,
8141bf82857SMike Leach 				    char *buf)
8151bf82857SMike Leach {
8161bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
8171bf82857SMike Leach 	struct cti_config *cfg = &drvdata->config;
8181bf82857SMike Leach 	int used = 0, reg_idx;
8191bf82857SMike Leach 	int nr_trig_max = drvdata->config.nr_trig_max;
8201bf82857SMike Leach 	u32 chan_mask = BIT(cfg->xtrig_rchan_sel);
8211bf82857SMike Leach 
8221bf82857SMike Leach 	for (reg_idx = 0; reg_idx < nr_trig_max; reg_idx++) {
8231bf82857SMike Leach 		if (chan_mask & cfg->ctiouten[reg_idx])
8241bf82857SMike Leach 			used += sprintf(buf + used, "%d ", reg_idx);
8251bf82857SMike Leach 	}
8261bf82857SMike Leach 
8271bf82857SMike Leach 	used += sprintf(buf + used, "\n");
8281bf82857SMike Leach 	return used;
8291bf82857SMike Leach }
8301bf82857SMike Leach static DEVICE_ATTR_RO(chan_xtrigs_out);
8311bf82857SMike Leach 
print_chan_list(struct device * dev,char * buf,bool inuse)8321bf82857SMike Leach static ssize_t print_chan_list(struct device *dev,
8331bf82857SMike Leach 			       char *buf, bool inuse)
8341bf82857SMike Leach {
8351bf82857SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
8361bf82857SMike Leach 	struct cti_config *config = &drvdata->config;
8371bf82857SMike Leach 	int size, i;
8381bf82857SMike Leach 	unsigned long inuse_bits = 0, chan_mask;
8391bf82857SMike Leach 
8401bf82857SMike Leach 	/* scan regs to get bitmap of channels in use. */
8411bf82857SMike Leach 	spin_lock(&drvdata->spinlock);
8421bf82857SMike Leach 	for (i = 0; i < config->nr_trig_max; i++) {
8431bf82857SMike Leach 		inuse_bits |= config->ctiinen[i];
8441bf82857SMike Leach 		inuse_bits |= config->ctiouten[i];
8451bf82857SMike Leach 	}
8461bf82857SMike Leach 	spin_unlock(&drvdata->spinlock);
8471bf82857SMike Leach 
8481bf82857SMike Leach 	/* inverse bits if printing free channels */
8491bf82857SMike Leach 	if (!inuse)
8501bf82857SMike Leach 		inuse_bits = ~inuse_bits;
8511bf82857SMike Leach 
8521bf82857SMike Leach 	/* list of channels, or 'none' */
8531bf82857SMike Leach 	chan_mask = GENMASK(config->nr_ctm_channels - 1, 0);
8541bf82857SMike Leach 	if (inuse_bits & chan_mask)
8551bf82857SMike Leach 		size = bitmap_print_to_pagebuf(true, buf, &inuse_bits,
8561bf82857SMike Leach 					       config->nr_ctm_channels);
8571bf82857SMike Leach 	else
8581bf82857SMike Leach 		size = sprintf(buf, "\n");
8591bf82857SMike Leach 	return size;
8601bf82857SMike Leach }
8611bf82857SMike Leach 
chan_inuse_show(struct device * dev,struct device_attribute * attr,char * buf)8621bf82857SMike Leach static ssize_t chan_inuse_show(struct device *dev,
8631bf82857SMike Leach 			       struct device_attribute *attr,
8641bf82857SMike Leach 			       char *buf)
8651bf82857SMike Leach {
8661bf82857SMike Leach 	return print_chan_list(dev, buf, true);
8671bf82857SMike Leach }
8681bf82857SMike Leach static DEVICE_ATTR_RO(chan_inuse);
8691bf82857SMike Leach 
chan_free_show(struct device * dev,struct device_attribute * attr,char * buf)8701bf82857SMike Leach static ssize_t chan_free_show(struct device *dev,
8711bf82857SMike Leach 			      struct device_attribute *attr,
8721bf82857SMike Leach 			      char *buf)
8731bf82857SMike Leach {
8741bf82857SMike Leach 	return print_chan_list(dev, buf, false);
8751bf82857SMike Leach }
8761bf82857SMike Leach static DEVICE_ATTR_RO(chan_free);
8771bf82857SMike Leach 
8781bf82857SMike Leach static struct attribute *coresight_cti_channel_attrs[] = {
8791bf82857SMike Leach 	&dev_attr_trigin_attach.attr,
8801bf82857SMike Leach 	&dev_attr_trigin_detach.attr,
8811bf82857SMike Leach 	&dev_attr_trigout_attach.attr,
8821bf82857SMike Leach 	&dev_attr_trigout_detach.attr,
8831bf82857SMike Leach 	&dev_attr_trig_filter_enable.attr,
8841bf82857SMike Leach 	&dev_attr_trigout_filtered.attr,
8851bf82857SMike Leach 	&dev_attr_chan_gate_enable.attr,
8861bf82857SMike Leach 	&dev_attr_chan_gate_disable.attr,
8871bf82857SMike Leach 	&dev_attr_chan_set.attr,
8881bf82857SMike Leach 	&dev_attr_chan_clear.attr,
8891bf82857SMike Leach 	&dev_attr_chan_pulse.attr,
8901bf82857SMike Leach 	&dev_attr_chan_inuse.attr,
8911bf82857SMike Leach 	&dev_attr_chan_free.attr,
8921bf82857SMike Leach 	&dev_attr_chan_xtrigs_sel.attr,
8931bf82857SMike Leach 	&dev_attr_chan_xtrigs_in.attr,
8941bf82857SMike Leach 	&dev_attr_chan_xtrigs_out.attr,
8951bf82857SMike Leach 	&dev_attr_chan_xtrigs_reset.attr,
8961bf82857SMike Leach 	NULL,
8971bf82857SMike Leach };
8981bf82857SMike Leach 
8993c5597e3SMike Leach /* Create the connections trigger groups and attrs dynamically */
9003c5597e3SMike Leach /*
9013c5597e3SMike Leach  * Each connection has dynamic group triggers<N> + name, trigin/out sigs/types
9023c5597e3SMike Leach  * attributes, + each device has static nr_trigger_cons giving the number
9033c5597e3SMike Leach  * of groups. e.g. in sysfs:-
9043c5597e3SMike Leach  * /cti_<name>/triggers0
9053c5597e3SMike Leach  * /cti_<name>/triggers1
9063c5597e3SMike Leach  * /cti_<name>/nr_trigger_cons
9073c5597e3SMike Leach  * where nr_trigger_cons = 2
9083c5597e3SMike Leach  */
con_name_show(struct device * dev,struct device_attribute * attr,char * buf)9093c5597e3SMike Leach static ssize_t con_name_show(struct device *dev,
9103c5597e3SMike Leach 			     struct device_attribute *attr,
9113c5597e3SMike Leach 			     char *buf)
9123c5597e3SMike Leach {
9133c5597e3SMike Leach 	struct dev_ext_attribute *ext_attr =
9143c5597e3SMike Leach 		container_of(attr, struct dev_ext_attribute, attr);
9153c5597e3SMike Leach 	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
9163c5597e3SMike Leach 
9173c5597e3SMike Leach 	return sprintf(buf, "%s\n", con->con_dev_name);
9183c5597e3SMike Leach }
9193c5597e3SMike Leach 
trigin_sig_show(struct device * dev,struct device_attribute * attr,char * buf)9203c5597e3SMike Leach static ssize_t trigin_sig_show(struct device *dev,
9213c5597e3SMike Leach 			       struct device_attribute *attr,
9223c5597e3SMike Leach 			       char *buf)
9233c5597e3SMike Leach {
9243c5597e3SMike Leach 	struct dev_ext_attribute *ext_attr =
9253c5597e3SMike Leach 		container_of(attr, struct dev_ext_attribute, attr);
9263c5597e3SMike Leach 	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
9273c5597e3SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
9283c5597e3SMike Leach 	struct cti_config *cfg = &drvdata->config;
9293c5597e3SMike Leach 	unsigned long mask = con->con_in->used_mask;
9303c5597e3SMike Leach 
9313c5597e3SMike Leach 	return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
9323c5597e3SMike Leach }
9333c5597e3SMike Leach 
trigout_sig_show(struct device * dev,struct device_attribute * attr,char * buf)9343c5597e3SMike Leach static ssize_t trigout_sig_show(struct device *dev,
9353c5597e3SMike Leach 				struct device_attribute *attr,
9363c5597e3SMike Leach 				char *buf)
9373c5597e3SMike Leach {
9383c5597e3SMike Leach 	struct dev_ext_attribute *ext_attr =
9393c5597e3SMike Leach 		container_of(attr, struct dev_ext_attribute, attr);
9403c5597e3SMike Leach 	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
9413c5597e3SMike Leach 	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
9423c5597e3SMike Leach 	struct cti_config *cfg = &drvdata->config;
9433c5597e3SMike Leach 	unsigned long mask = con->con_out->used_mask;
9443c5597e3SMike Leach 
9453c5597e3SMike Leach 	return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);
9463c5597e3SMike Leach }
9473c5597e3SMike Leach 
9483c5597e3SMike Leach /* convert a sig type id to a name */
9493c5597e3SMike Leach static const char *
cti_sig_type_name(struct cti_trig_con * con,int used_count,bool in)9503c5597e3SMike Leach cti_sig_type_name(struct cti_trig_con *con, int used_count, bool in)
9513c5597e3SMike Leach {
9523c5597e3SMike Leach 	int idx = 0;
9533c5597e3SMike Leach 	struct cti_trig_grp *grp = in ? con->con_in : con->con_out;
9543c5597e3SMike Leach 
9553c5597e3SMike Leach 	if (used_count < grp->nr_sigs)
9563c5597e3SMike Leach 		idx = grp->sig_types[used_count];
9573c5597e3SMike Leach 	return sig_type_names[idx];
9583c5597e3SMike Leach }
9593c5597e3SMike Leach 
trigin_type_show(struct device * dev,struct device_attribute * attr,char * buf)9603c5597e3SMike Leach static ssize_t trigin_type_show(struct device *dev,
9613c5597e3SMike Leach 				struct device_attribute *attr,
9623c5597e3SMike Leach 				char *buf)
9633c5597e3SMike Leach {
9643c5597e3SMike Leach 	struct dev_ext_attribute *ext_attr =
9653c5597e3SMike Leach 		container_of(attr, struct dev_ext_attribute, attr);
9663c5597e3SMike Leach 	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
9673c5597e3SMike Leach 	int sig_idx, used = 0;
9683c5597e3SMike Leach 	const char *name;
9693c5597e3SMike Leach 
9703c5597e3SMike Leach 	for (sig_idx = 0; sig_idx < con->con_in->nr_sigs; sig_idx++) {
9713c5597e3SMike Leach 		name = cti_sig_type_name(con, sig_idx, true);
9723c5597e3SMike Leach 		used += sprintf(buf + used, "%s ", name);
9733c5597e3SMike Leach 	}
9743c5597e3SMike Leach 	used += sprintf(buf + used, "\n");
9753c5597e3SMike Leach 	return used;
9763c5597e3SMike Leach }
9773c5597e3SMike Leach 
trigout_type_show(struct device * dev,struct device_attribute * attr,char * buf)9783c5597e3SMike Leach static ssize_t trigout_type_show(struct device *dev,
9793c5597e3SMike Leach 				 struct device_attribute *attr,
9803c5597e3SMike Leach 				 char *buf)
9813c5597e3SMike Leach {
9823c5597e3SMike Leach 	struct dev_ext_attribute *ext_attr =
9833c5597e3SMike Leach 		container_of(attr, struct dev_ext_attribute, attr);
9843c5597e3SMike Leach 	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;
9853c5597e3SMike Leach 	int sig_idx, used = 0;
9863c5597e3SMike Leach 	const char *name;
9873c5597e3SMike Leach 
9883c5597e3SMike Leach 	for (sig_idx = 0; sig_idx < con->con_out->nr_sigs; sig_idx++) {
9893c5597e3SMike Leach 		name = cti_sig_type_name(con, sig_idx, false);
9903c5597e3SMike Leach 		used += sprintf(buf + used, "%s ", name);
9913c5597e3SMike Leach 	}
9923c5597e3SMike Leach 	used += sprintf(buf + used, "\n");
9933c5597e3SMike Leach 	return used;
9943c5597e3SMike Leach }
9953c5597e3SMike Leach 
9963c5597e3SMike Leach /*
9973c5597e3SMike Leach  * Array of show function names declared above to allow selection
9983c5597e3SMike Leach  * for the connection attributes
9993c5597e3SMike Leach  */
10003c5597e3SMike Leach static p_show_fn show_fns[CTI_CON_ATTR_MAX] = {
10013c5597e3SMike Leach 	con_name_show,
10023c5597e3SMike Leach 	trigin_sig_show,
10033c5597e3SMike Leach 	trigout_sig_show,
10043c5597e3SMike Leach 	trigin_type_show,
10053c5597e3SMike Leach 	trigout_type_show,
10063c5597e3SMike Leach };
10073c5597e3SMike Leach 
cti_create_con_sysfs_attr(struct device * dev,struct cti_trig_con * con,enum cti_conn_attr_type attr_type,int attr_idx)10083c5597e3SMike Leach static int cti_create_con_sysfs_attr(struct device *dev,
10093c5597e3SMike Leach 				     struct cti_trig_con *con,
10103c5597e3SMike Leach 				     enum cti_conn_attr_type attr_type,
10113c5597e3SMike Leach 				     int attr_idx)
10123c5597e3SMike Leach {
10130e34dc76SStephen Boyd 	struct dev_ext_attribute *eattr;
10140e34dc76SStephen Boyd 	char *name;
10153c5597e3SMike Leach 
10163c5597e3SMike Leach 	eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),
10173c5597e3SMike Leach 				    GFP_KERNEL);
10183c5597e3SMike Leach 	if (eattr) {
10193c5597e3SMike Leach 		name = devm_kstrdup(dev, con_attr_names[attr_type],
10203c5597e3SMike Leach 				    GFP_KERNEL);
10213c5597e3SMike Leach 		if (name) {
10223c5597e3SMike Leach 			/* fill out the underlying attribute struct */
10233c5597e3SMike Leach 			eattr->attr.attr.name = name;
10243c5597e3SMike Leach 			eattr->attr.attr.mode = 0444;
10253c5597e3SMike Leach 
10263c5597e3SMike Leach 			/* now the device_attribute struct */
10273c5597e3SMike Leach 			eattr->attr.show = show_fns[attr_type];
10283c5597e3SMike Leach 		} else {
10293c5597e3SMike Leach 			return -ENOMEM;
10303c5597e3SMike Leach 		}
10313c5597e3SMike Leach 	} else {
10323c5597e3SMike Leach 		return -ENOMEM;
10333c5597e3SMike Leach 	}
10343c5597e3SMike Leach 	eattr->var = con;
10353c5597e3SMike Leach 	con->con_attrs[attr_idx] = &eattr->attr.attr;
103680624263SSuzuki K Poulose 	/*
103780624263SSuzuki K Poulose 	 * Initialize the dynamically allocated attribute
103880624263SSuzuki K Poulose 	 * to avoid LOCKDEP splat. See include/linux/sysfs.h
103980624263SSuzuki K Poulose 	 * for more details.
104080624263SSuzuki K Poulose 	 */
104180624263SSuzuki K Poulose 	sysfs_attr_init(con->con_attrs[attr_idx]);
104280624263SSuzuki K Poulose 
10433c5597e3SMike Leach 	return 0;
10443c5597e3SMike Leach }
10453c5597e3SMike Leach 
10463c5597e3SMike Leach static struct attribute_group *
cti_create_con_sysfs_group(struct device * dev,struct cti_device * ctidev,int con_idx,struct cti_trig_con * tc)10473c5597e3SMike Leach cti_create_con_sysfs_group(struct device *dev, struct cti_device *ctidev,
10483c5597e3SMike Leach 			   int con_idx, struct cti_trig_con *tc)
10493c5597e3SMike Leach {
10503c5597e3SMike Leach 	struct attribute_group *group = NULL;
10513c5597e3SMike Leach 	int grp_idx;
10523c5597e3SMike Leach 
10533c5597e3SMike Leach 	group = devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL);
10543c5597e3SMike Leach 	if (!group)
10553c5597e3SMike Leach 		return NULL;
10563c5597e3SMike Leach 
10573c5597e3SMike Leach 	group->name = devm_kasprintf(dev, GFP_KERNEL, "triggers%d", con_idx);
10583c5597e3SMike Leach 	if (!group->name)
10593c5597e3SMike Leach 		return NULL;
10603c5597e3SMike Leach 
10613c5597e3SMike Leach 	grp_idx = con_idx + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1;
10623c5597e3SMike Leach 	ctidev->con_groups[grp_idx] = group;
10633c5597e3SMike Leach 	tc->attr_group = group;
10643c5597e3SMike Leach 	return group;
10653c5597e3SMike Leach }
10663c5597e3SMike Leach 
10673c5597e3SMike Leach /* create a triggers connection group and the attributes for that group */
cti_create_con_attr_set(struct device * dev,int con_idx,struct cti_device * ctidev,struct cti_trig_con * tc)10683c5597e3SMike Leach static int cti_create_con_attr_set(struct device *dev, int con_idx,
10693c5597e3SMike Leach 				   struct cti_device *ctidev,
10703c5597e3SMike Leach 				   struct cti_trig_con *tc)
10713c5597e3SMike Leach {
10723c5597e3SMike Leach 	struct attribute_group *attr_group = NULL;
10733c5597e3SMike Leach 	int attr_idx = 0;
10743c5597e3SMike Leach 	int err = -ENOMEM;
10753c5597e3SMike Leach 
10763c5597e3SMike Leach 	attr_group = cti_create_con_sysfs_group(dev, ctidev, con_idx, tc);
10773c5597e3SMike Leach 	if (!attr_group)
10783c5597e3SMike Leach 		return -ENOMEM;
10793c5597e3SMike Leach 
10803c5597e3SMike Leach 	/* allocate NULL terminated array of attributes */
10813c5597e3SMike Leach 	tc->con_attrs = devm_kcalloc(dev, CTI_CON_ATTR_MAX + 1,
10823c5597e3SMike Leach 				     sizeof(struct attribute *), GFP_KERNEL);
10833c5597e3SMike Leach 	if (!tc->con_attrs)
10843c5597e3SMike Leach 		return -ENOMEM;
10853c5597e3SMike Leach 
10863c5597e3SMike Leach 	err = cti_create_con_sysfs_attr(dev, tc, CTI_CON_ATTR_NAME,
10873c5597e3SMike Leach 					attr_idx++);
10883c5597e3SMike Leach 	if (err)
10893c5597e3SMike Leach 		return err;
10903c5597e3SMike Leach 
10913c5597e3SMike Leach 	if (tc->con_in->nr_sigs > 0) {
10923c5597e3SMike Leach 		err = cti_create_con_sysfs_attr(dev, tc,
10933c5597e3SMike Leach 						CTI_CON_ATTR_TRIGIN_SIG,
10943c5597e3SMike Leach 						attr_idx++);
10953c5597e3SMike Leach 		if (err)
10963c5597e3SMike Leach 			return err;
10973c5597e3SMike Leach 
10983c5597e3SMike Leach 		err = cti_create_con_sysfs_attr(dev, tc,
10993c5597e3SMike Leach 						CTI_CON_ATTR_TRIGIN_TYPES,
11003c5597e3SMike Leach 						attr_idx++);
11013c5597e3SMike Leach 		if (err)
11023c5597e3SMike Leach 			return err;
11033c5597e3SMike Leach 	}
11043c5597e3SMike Leach 
11053c5597e3SMike Leach 	if (tc->con_out->nr_sigs > 0) {
11063c5597e3SMike Leach 		err = cti_create_con_sysfs_attr(dev, tc,
11073c5597e3SMike Leach 						CTI_CON_ATTR_TRIGOUT_SIG,
11083c5597e3SMike Leach 						attr_idx++);
11093c5597e3SMike Leach 		if (err)
11103c5597e3SMike Leach 			return err;
11113c5597e3SMike Leach 
11123c5597e3SMike Leach 		err = cti_create_con_sysfs_attr(dev, tc,
11133c5597e3SMike Leach 						CTI_CON_ATTR_TRIGOUT_TYPES,
11143c5597e3SMike Leach 						attr_idx++);
11153c5597e3SMike Leach 		if (err)
11163c5597e3SMike Leach 			return err;
11173c5597e3SMike Leach 	}
11183c5597e3SMike Leach 	attr_group->attrs = tc->con_attrs;
11193c5597e3SMike Leach 	return 0;
11203c5597e3SMike Leach }
11213c5597e3SMike Leach 
11223c5597e3SMike Leach /* create the array of group pointers for the CTI sysfs groups */
cti_create_cons_groups(struct device * dev,struct cti_device * ctidev)1123e54d9c77SStephen Boyd static int cti_create_cons_groups(struct device *dev, struct cti_device *ctidev)
11243c5597e3SMike Leach {
11253c5597e3SMike Leach 	int nr_groups;
11263c5597e3SMike Leach 
11273c5597e3SMike Leach 	/* nr groups = dynamic + static + NULL terminator */
11283c5597e3SMike Leach 	nr_groups = ctidev->nr_trig_con + CORESIGHT_CTI_STATIC_GROUPS_MAX;
11293c5597e3SMike Leach 	ctidev->con_groups = devm_kcalloc(dev, nr_groups,
11303c5597e3SMike Leach 					  sizeof(struct attribute_group *),
11313c5597e3SMike Leach 					  GFP_KERNEL);
11323c5597e3SMike Leach 	if (!ctidev->con_groups)
11333c5597e3SMike Leach 		return -ENOMEM;
11343c5597e3SMike Leach 	return 0;
11353c5597e3SMike Leach }
11363c5597e3SMike Leach 
cti_create_cons_sysfs(struct device * dev,struct cti_drvdata * drvdata)11373c5597e3SMike Leach int cti_create_cons_sysfs(struct device *dev, struct cti_drvdata *drvdata)
11383c5597e3SMike Leach {
11393c5597e3SMike Leach 	struct cti_device *ctidev = &drvdata->ctidev;
11400e34dc76SStephen Boyd 	int err, con_idx = 0, i;
11410e34dc76SStephen Boyd 	struct cti_trig_con *tc;
11423c5597e3SMike Leach 
11433c5597e3SMike Leach 	err = cti_create_cons_groups(dev, ctidev);
11443c5597e3SMike Leach 	if (err)
11453c5597e3SMike Leach 		return err;
11463c5597e3SMike Leach 
11473c5597e3SMike Leach 	/* populate first locations with the static set of groups */
11483c5597e3SMike Leach 	for (i = 0; i < (CORESIGHT_CTI_STATIC_GROUPS_MAX - 1); i++)
11493c5597e3SMike Leach 		ctidev->con_groups[i] = coresight_cti_groups[i];
11503c5597e3SMike Leach 
11513c5597e3SMike Leach 	/* add dynamic set for each connection */
11523c5597e3SMike Leach 	list_for_each_entry(tc, &ctidev->trig_cons, node) {
11533c5597e3SMike Leach 		err = cti_create_con_attr_set(dev, con_idx++, ctidev, tc);
11543c5597e3SMike Leach 		if (err)
11553c5597e3SMike Leach 			break;
11563c5597e3SMike Leach 	}
11573c5597e3SMike Leach 	return err;
11583c5597e3SMike Leach }
11593c5597e3SMike Leach 
11603c5597e3SMike Leach /* attribute and group sysfs tables. */
1161835d722bSMike Leach static const struct attribute_group coresight_cti_group = {
1162835d722bSMike Leach 	.attrs = coresight_cti_attrs,
1163835d722bSMike Leach };
1164835d722bSMike Leach 
11651a556ca6SMike Leach static const struct attribute_group coresight_cti_mgmt_group = {
11661a556ca6SMike Leach 	.attrs = coresight_cti_mgmt_attrs,
11671a556ca6SMike Leach 	.name = "mgmt",
11681a556ca6SMike Leach };
11691a556ca6SMike Leach 
1170b5213376SMike Leach static const struct attribute_group coresight_cti_regs_group = {
1171b5213376SMike Leach 	.attrs = coresight_cti_regs_attrs,
1172b5213376SMike Leach 	.name = "regs",
1173b5213376SMike Leach };
1174b5213376SMike Leach 
11751bf82857SMike Leach static const struct attribute_group coresight_cti_channels_group = {
11761bf82857SMike Leach 	.attrs = coresight_cti_channel_attrs,
11771bf82857SMike Leach 	.name = "channels",
11781bf82857SMike Leach };
11791bf82857SMike Leach 
11803c5597e3SMike Leach const struct attribute_group *
11813c5597e3SMike Leach coresight_cti_groups[CORESIGHT_CTI_STATIC_GROUPS_MAX] = {
1182835d722bSMike Leach 	&coresight_cti_group,
11831a556ca6SMike Leach 	&coresight_cti_mgmt_group,
1184b5213376SMike Leach 	&coresight_cti_regs_group,
11851bf82857SMike Leach 	&coresight_cti_channels_group,
1186835d722bSMike Leach 	NULL,
1187835d722bSMike Leach };
1188