brintos

brintos / linux-shallow public Read only

0
0
Text · 31.3 KiB · d25dd27 Raw
1188 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2019 Linaro Limited, All rights reserved.4 * Author: Mike Leach <mike.leach@linaro.org>5 */6 7#include <linux/atomic.h>8#include <linux/coresight.h>9#include <linux/device.h>10#include <linux/io.h>11#include <linux/kernel.h>12#include <linux/spinlock.h>13#include <linux/sysfs.h>14 15#include "coresight-cti.h"16 17/*18 * Declare the number of static declared attribute groups19 * Value includes groups + NULL value at end of table.20 */21#define CORESIGHT_CTI_STATIC_GROUPS_MAX 522 23/*24 * List of trigger signal type names. Match the constants declared in25 * include\dt-bindings\arm\coresight-cti-dt.h26 */27static const char * const sig_type_names[] = {28	"genio",	/* GEN_IO */29	"intreq",	/* GEN_INTREQ */30	"intack",	/* GEN_INTACK */31	"haltreq",	/* GEN_HALTREQ */32	"restartreq",	/* GEN_RESTARTREQ */33	"pe_edbgreq",	/* PE_EDBGREQ */34	"pe_dbgrestart",/* PE_DBGRESTART */35	"pe_ctiirq",	/* PE_CTIIRQ */36	"pe_pmuirq",	/* PE_PMUIRQ */37	"pe_dbgtrigger",/* PE_DBGTRIGGER */38	"etm_extout",	/* ETM_EXTOUT */39	"etm_extin",	/* ETM_EXTIN */40	"snk_full",	/* SNK_FULL */41	"snk_acqcomp",	/* SNK_ACQCOMP */42	"snk_flushcomp",/* SNK_FLUSHCOMP */43	"snk_flushin",	/* SNK_FLUSHIN */44	"snk_trigin",	/* SNK_TRIGIN */45	"stm_asyncout",	/* STM_ASYNCOUT */46	"stm_tout_spte",/* STM_TOUT_SPTE */47	"stm_tout_sw",	/* STM_TOUT_SW */48	"stm_tout_hete",/* STM_TOUT_HETE */49	"stm_hwevent",	/* STM_HWEVENT */50	"ela_tstart",	/* ELA_TSTART */51	"ela_tstop",	/* ELA_TSTOP */52	"ela_dbgreq",	/* ELA_DBGREQ */53};54 55/* Show function pointer used in the connections dynamic declared attributes*/56typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr,57			     char *buf);58 59/* Connection attribute types */60enum cti_conn_attr_type {61	CTI_CON_ATTR_NAME,62	CTI_CON_ATTR_TRIGIN_SIG,63	CTI_CON_ATTR_TRIGOUT_SIG,64	CTI_CON_ATTR_TRIGIN_TYPES,65	CTI_CON_ATTR_TRIGOUT_TYPES,66	CTI_CON_ATTR_MAX,67};68 69/* Names for the connection attributes */70static const char * const con_attr_names[CTI_CON_ATTR_MAX] = {71	"name",72	"in_signals",73	"out_signals",74	"in_types",75	"out_types",76};77 78/* basic attributes */79static ssize_t enable_show(struct device *dev,80			   struct device_attribute *attr,81			   char *buf)82{83	int enable_req;84	bool enabled, powered;85	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);86 87	spin_lock(&drvdata->spinlock);88	enable_req = drvdata->config.enable_req_count;89	powered = drvdata->config.hw_powered;90	enabled = drvdata->config.hw_enabled;91	spin_unlock(&drvdata->spinlock);92 93	if (powered)94		return sprintf(buf, "%d\n", enabled);95	else96		return sprintf(buf, "%d\n", !!enable_req);97}98 99static ssize_t enable_store(struct device *dev,100			    struct device_attribute *attr,101			    const char *buf, size_t size)102{103	int ret = 0;104	unsigned long val;105	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);106 107	ret = kstrtoul(buf, 0, &val);108	if (ret)109		return ret;110 111	if (val) {112		ret = pm_runtime_resume_and_get(dev->parent);113		if (ret)114			return ret;115		ret = cti_enable(drvdata->csdev, CS_MODE_SYSFS, NULL);116		if (ret)117			pm_runtime_put(dev->parent);118	} else {119		ret = cti_disable(drvdata->csdev, NULL);120		if (!ret)121			pm_runtime_put(dev->parent);122	}123 124	if (ret)125		return ret;126	return size;127}128static DEVICE_ATTR_RW(enable);129 130static ssize_t powered_show(struct device *dev,131			    struct device_attribute *attr,132			    char *buf)133{134	bool powered;135	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);136 137	spin_lock(&drvdata->spinlock);138	powered = drvdata->config.hw_powered;139	spin_unlock(&drvdata->spinlock);140 141	return sprintf(buf, "%d\n", powered);142}143static DEVICE_ATTR_RO(powered);144 145static ssize_t ctmid_show(struct device *dev,146			  struct device_attribute *attr, char *buf)147{148	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);149 150	return sprintf(buf, "%d\n", drvdata->ctidev.ctm_id);151}152static DEVICE_ATTR_RO(ctmid);153 154static ssize_t nr_trigger_cons_show(struct device *dev,155				    struct device_attribute *attr,156				    char *buf)157{158	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);159 160	return sprintf(buf, "%d\n", drvdata->ctidev.nr_trig_con);161}162static DEVICE_ATTR_RO(nr_trigger_cons);163 164/* attribute and group sysfs tables. */165static struct attribute *coresight_cti_attrs[] = {166	&dev_attr_enable.attr,167	&dev_attr_powered.attr,168	&dev_attr_ctmid.attr,169	&dev_attr_nr_trigger_cons.attr,170	NULL,171};172 173/* register based attributes */174 175/* Read registers with power check only (no enable check). */176static ssize_t coresight_cti_reg_show(struct device *dev,177			   struct device_attribute *attr, char *buf)178{179	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);180	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);181	u32 val = 0;182 183	pm_runtime_get_sync(dev->parent);184	spin_lock(&drvdata->spinlock);185	if (drvdata->config.hw_powered)186		val = readl_relaxed(drvdata->base + cti_attr->off);187	spin_unlock(&drvdata->spinlock);188	pm_runtime_put_sync(dev->parent);189	return sysfs_emit(buf, "0x%x\n", val);190}191 192/* Write registers with power check only (no enable check). */193static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,194						      struct device_attribute *attr,195						      const char *buf, size_t size)196{197	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);198	struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);199	unsigned long val = 0;200 201	if (kstrtoul(buf, 0, &val))202		return -EINVAL;203 204	pm_runtime_get_sync(dev->parent);205	spin_lock(&drvdata->spinlock);206	if (drvdata->config.hw_powered)207		cti_write_single_reg(drvdata, cti_attr->off, val);208	spin_unlock(&drvdata->spinlock);209	pm_runtime_put_sync(dev->parent);210	return size;211}212 213#define coresight_cti_reg(name, offset)					\214	(&((struct cs_off_attribute[]) {				\215	   {								\216		__ATTR(name, 0444, coresight_cti_reg_show, NULL),	\217		offset							\218	   }								\219	})[0].attr.attr)220 221#define coresight_cti_reg_rw(name, offset)				\222	(&((struct cs_off_attribute[]) {				\223	   {								\224		__ATTR(name, 0644, coresight_cti_reg_show,		\225		       coresight_cti_reg_store),			\226		offset							\227	   }								\228	})[0].attr.attr)229 230#define coresight_cti_reg_wo(name, offset)				\231	(&((struct cs_off_attribute[]) {				\232	   {								\233		__ATTR(name, 0200, NULL, coresight_cti_reg_store),	\234		offset							\235	   }								\236	})[0].attr.attr)237 238/* coresight management registers */239static struct attribute *coresight_cti_mgmt_attrs[] = {240	coresight_cti_reg(devaff0, CTIDEVAFF0),241	coresight_cti_reg(devaff1, CTIDEVAFF1),242	coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS),243	coresight_cti_reg(devarch, CORESIGHT_DEVARCH),244	coresight_cti_reg(devid, CORESIGHT_DEVID),245	coresight_cti_reg(devtype, CORESIGHT_DEVTYPE),246	coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0),247	coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1),248	coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2),249	coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3),250	coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4),251	NULL,252};253 254/* CTI low level programming registers */255 256/*257 * Show a simple 32 bit value if enabled and powered.258 * If inaccessible & pcached_val not NULL then show cached value.259 */260static ssize_t cti_reg32_show(struct device *dev, char *buf,261			      u32 *pcached_val, int reg_offset)262{263	u32 val = 0;264	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);265	struct cti_config *config = &drvdata->config;266 267	spin_lock(&drvdata->spinlock);268	if ((reg_offset >= 0) && cti_active(config)) {269		CS_UNLOCK(drvdata->base);270		val = readl_relaxed(drvdata->base + reg_offset);271		if (pcached_val)272			*pcached_val = val;273		CS_LOCK(drvdata->base);274	} else if (pcached_val) {275		val = *pcached_val;276	}277	spin_unlock(&drvdata->spinlock);278	return sprintf(buf, "%#x\n", val);279}280 281/*282 * Store a simple 32 bit value.283 * If pcached_val not NULL, then copy to here too,284 * if reg_offset >= 0 then write through if enabled.285 */286static ssize_t cti_reg32_store(struct device *dev, const char *buf,287			       size_t size, u32 *pcached_val, int reg_offset)288{289	unsigned long val;290	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);291	struct cti_config *config = &drvdata->config;292 293	if (kstrtoul(buf, 0, &val))294		return -EINVAL;295 296	spin_lock(&drvdata->spinlock);297	/* local store */298	if (pcached_val)299		*pcached_val = (u32)val;300 301	/* write through if offset and enabled */302	if ((reg_offset >= 0) && cti_active(config))303		cti_write_single_reg(drvdata, reg_offset, val);304	spin_unlock(&drvdata->spinlock);305	return size;306}307 308/* Standard macro for simple rw cti config registers */309#define cti_config_reg32_rw(name, cfgname, offset)			\310static ssize_t name##_show(struct device *dev,				\311			   struct device_attribute *attr,		\312			   char *buf)					\313{									\314	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);	\315	return cti_reg32_show(dev, buf,					\316			      &drvdata->config.cfgname, offset);	\317}									\318									\319static ssize_t name##_store(struct device *dev,				\320			    struct device_attribute *attr,		\321			    const char *buf, size_t size)		\322{									\323	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);	\324	return cti_reg32_store(dev, buf, size,				\325			       &drvdata->config.cfgname, offset);	\326}									\327static DEVICE_ATTR_RW(name)328 329static ssize_t inout_sel_show(struct device *dev,330			      struct device_attribute *attr,331			      char *buf)332{333	u32 val;334	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);335 336	val = (u32)drvdata->config.ctiinout_sel;337	return sprintf(buf, "%d\n", val);338}339 340static ssize_t inout_sel_store(struct device *dev,341			       struct device_attribute *attr,342			       const char *buf, size_t size)343{344	unsigned long val;345	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);346 347	if (kstrtoul(buf, 0, &val))348		return -EINVAL;349	if (val > (CTIINOUTEN_MAX - 1))350		return -EINVAL;351 352	spin_lock(&drvdata->spinlock);353	drvdata->config.ctiinout_sel = val;354	spin_unlock(&drvdata->spinlock);355	return size;356}357static DEVICE_ATTR_RW(inout_sel);358 359static ssize_t inen_show(struct device *dev,360			 struct device_attribute *attr,361			 char *buf)362{363	unsigned long val;364	int index;365	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);366 367	spin_lock(&drvdata->spinlock);368	index = drvdata->config.ctiinout_sel;369	val = drvdata->config.ctiinen[index];370	spin_unlock(&drvdata->spinlock);371	return sprintf(buf, "%#lx\n", val);372}373 374static ssize_t inen_store(struct device *dev,375			  struct device_attribute *attr,376			  const char *buf, size_t size)377{378	unsigned long val;379	int index;380	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);381	struct cti_config *config = &drvdata->config;382 383	if (kstrtoul(buf, 0, &val))384		return -EINVAL;385 386	spin_lock(&drvdata->spinlock);387	index = config->ctiinout_sel;388	config->ctiinen[index] = val;389 390	/* write through if enabled */391	if (cti_active(config))392		cti_write_single_reg(drvdata, CTIINEN(index), val);393	spin_unlock(&drvdata->spinlock);394	return size;395}396static DEVICE_ATTR_RW(inen);397 398static ssize_t outen_show(struct device *dev,399			  struct device_attribute *attr,400			  char *buf)401{402	unsigned long val;403	int index;404	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);405 406	spin_lock(&drvdata->spinlock);407	index = drvdata->config.ctiinout_sel;408	val = drvdata->config.ctiouten[index];409	spin_unlock(&drvdata->spinlock);410	return sprintf(buf, "%#lx\n", val);411}412 413static ssize_t outen_store(struct device *dev,414			   struct device_attribute *attr,415			   const char *buf, size_t size)416{417	unsigned long val;418	int index;419	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);420	struct cti_config *config = &drvdata->config;421 422	if (kstrtoul(buf, 0, &val))423		return -EINVAL;424 425	spin_lock(&drvdata->spinlock);426	index = config->ctiinout_sel;427	config->ctiouten[index] = val;428 429	/* write through if enabled */430	if (cti_active(config))431		cti_write_single_reg(drvdata, CTIOUTEN(index), val);432	spin_unlock(&drvdata->spinlock);433	return size;434}435static DEVICE_ATTR_RW(outen);436 437static ssize_t intack_store(struct device *dev,438			    struct device_attribute *attr,439			    const char *buf, size_t size)440{441	unsigned long val;442 443	if (kstrtoul(buf, 0, &val))444		return -EINVAL;445 446	cti_write_intack(dev, val);447	return size;448}449static DEVICE_ATTR_WO(intack);450 451cti_config_reg32_rw(gate, ctigate, CTIGATE);452cti_config_reg32_rw(asicctl, asicctl, ASICCTL);453cti_config_reg32_rw(appset, ctiappset, CTIAPPSET);454 455static ssize_t appclear_store(struct device *dev,456			      struct device_attribute *attr,457			      const char *buf, size_t size)458{459	unsigned long val;460	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);461	struct cti_config *config = &drvdata->config;462 463	if (kstrtoul(buf, 0, &val))464		return -EINVAL;465 466	spin_lock(&drvdata->spinlock);467 468	/* a 1'b1 in appclr clears down the same bit in appset*/469	config->ctiappset &= ~val;470 471	/* write through if enabled */472	if (cti_active(config))473		cti_write_single_reg(drvdata, CTIAPPCLEAR, val);474	spin_unlock(&drvdata->spinlock);475	return size;476}477static DEVICE_ATTR_WO(appclear);478 479static ssize_t apppulse_store(struct device *dev,480			      struct device_attribute *attr,481			      const char *buf, size_t size)482{483	unsigned long val;484	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);485	struct cti_config *config = &drvdata->config;486 487	if (kstrtoul(buf, 0, &val))488		return -EINVAL;489 490	spin_lock(&drvdata->spinlock);491 492	/* write through if enabled */493	if (cti_active(config))494		cti_write_single_reg(drvdata, CTIAPPPULSE, val);495	spin_unlock(&drvdata->spinlock);496	return size;497}498static DEVICE_ATTR_WO(apppulse);499 500/*501 * Define CONFIG_CORESIGHT_CTI_INTEGRATION_REGS to enable the access to the502 * integration control registers. Normally only used to investigate connection503 * data.504 */505static struct attribute *coresight_cti_regs_attrs[] = {506	&dev_attr_inout_sel.attr,507	&dev_attr_inen.attr,508	&dev_attr_outen.attr,509	&dev_attr_gate.attr,510	&dev_attr_asicctl.attr,511	&dev_attr_intack.attr,512	&dev_attr_appset.attr,513	&dev_attr_appclear.attr,514	&dev_attr_apppulse.attr,515	coresight_cti_reg(triginstatus, CTITRIGINSTATUS),516	coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),517	coresight_cti_reg(chinstatus, CTICHINSTATUS),518	coresight_cti_reg(choutstatus, CTICHOUTSTATUS),519#ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS520	coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),521	coresight_cti_reg(ittrigin, ITTRIGIN),522	coresight_cti_reg(itchin, ITCHIN),523	coresight_cti_reg_rw(ittrigout, ITTRIGOUT),524	coresight_cti_reg_rw(itchout, ITCHOUT),525	coresight_cti_reg(itchoutack, ITCHOUTACK),526	coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),527	coresight_cti_reg_wo(ittriginack, ITTRIGINACK),528	coresight_cti_reg_wo(itchinack, ITCHINACK),529#endif530	NULL,531};532 533/* CTI channel x-trigger programming */534static int535cti_trig_op_parse(struct device *dev, enum cti_chan_op op,536		  enum cti_trig_dir dir, const char *buf, size_t size)537{538	u32 chan_idx;539	u32 trig_idx;540	int items, err = -EINVAL;541 542	/* extract chan idx and trigger idx */543	items = sscanf(buf, "%d %d", &chan_idx, &trig_idx);544	if (items == 2) {545		err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx);546		if (!err)547			err = size;548	}549	return err;550}551 552static ssize_t trigin_attach_store(struct device *dev,553				   struct device_attribute *attr,554				   const char *buf, size_t size)555{556	return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_IN,557				 buf, size);558}559static DEVICE_ATTR_WO(trigin_attach);560 561static ssize_t trigin_detach_store(struct device *dev,562				   struct device_attribute *attr,563				   const char *buf, size_t size)564{565	return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_IN,566				 buf, size);567}568static DEVICE_ATTR_WO(trigin_detach);569 570static ssize_t trigout_attach_store(struct device *dev,571				    struct device_attribute *attr,572				    const char *buf, size_t size)573{574	return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_OUT,575				 buf, size);576}577static DEVICE_ATTR_WO(trigout_attach);578 579static ssize_t trigout_detach_store(struct device *dev,580				    struct device_attribute *attr,581				    const char *buf, size_t size)582{583	return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_OUT,584				 buf, size);585}586static DEVICE_ATTR_WO(trigout_detach);587 588 589static ssize_t chan_gate_enable_store(struct device *dev,590				      struct device_attribute *attr,591				      const char *buf, size_t size)592{593	int err = 0, channel = 0;594 595	if (kstrtoint(buf, 0, &channel))596		return -EINVAL;597 598	err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel);599	return err ? err : size;600}601 602static ssize_t chan_gate_enable_show(struct device *dev,603				     struct device_attribute *attr,604				     char *buf)605{606	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);607	struct cti_config *cfg = &drvdata->config;608	unsigned long ctigate_bitmask = cfg->ctigate;609	int size = 0;610 611	if (cfg->ctigate == 0)612		size = sprintf(buf, "\n");613	else614		size = bitmap_print_to_pagebuf(true, buf, &ctigate_bitmask,615					       cfg->nr_ctm_channels);616	return size;617}618static DEVICE_ATTR_RW(chan_gate_enable);619 620static ssize_t chan_gate_disable_store(struct device *dev,621				       struct device_attribute *attr,622				       const char *buf, size_t size)623{624	int err = 0, channel = 0;625 626	if (kstrtoint(buf, 0, &channel))627		return -EINVAL;628 629	err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE, channel);630	return err ? err : size;631}632static DEVICE_ATTR_WO(chan_gate_disable);633 634static int635chan_op_parse(struct device *dev, enum cti_chan_set_op op, const char *buf)636{637	int err = 0, channel = 0;638 639	if (kstrtoint(buf, 0, &channel))640		return -EINVAL;641 642	err = cti_channel_setop(dev, op, channel);643	return err;644 645}646 647static ssize_t chan_set_store(struct device *dev,648			      struct device_attribute *attr,649			      const char *buf, size_t size)650{651	int err = chan_op_parse(dev, CTI_CHAN_SET, buf);652 653	return err ? err : size;654}655static DEVICE_ATTR_WO(chan_set);656 657static ssize_t chan_clear_store(struct device *dev,658				struct device_attribute *attr,659				const char *buf, size_t size)660{661	int err = chan_op_parse(dev, CTI_CHAN_CLR, buf);662 663	return err ? err : size;664}665static DEVICE_ATTR_WO(chan_clear);666 667static ssize_t chan_pulse_store(struct device *dev,668				struct device_attribute *attr,669				const char *buf, size_t size)670{671	int err = chan_op_parse(dev, CTI_CHAN_PULSE, buf);672 673	return err ? err : size;674}675static DEVICE_ATTR_WO(chan_pulse);676 677static ssize_t trig_filter_enable_show(struct device *dev,678				       struct device_attribute *attr,679				       char *buf)680{681	u32 val;682	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);683 684	spin_lock(&drvdata->spinlock);685	val = drvdata->config.trig_filter_enable;686	spin_unlock(&drvdata->spinlock);687	return sprintf(buf, "%d\n", val);688}689 690static ssize_t trig_filter_enable_store(struct device *dev,691					struct device_attribute *attr,692					const char *buf, size_t size)693{694	unsigned long val;695	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);696 697	if (kstrtoul(buf, 0, &val))698		return -EINVAL;699 700	spin_lock(&drvdata->spinlock);701	drvdata->config.trig_filter_enable = !!val;702	spin_unlock(&drvdata->spinlock);703	return size;704}705static DEVICE_ATTR_RW(trig_filter_enable);706 707static ssize_t trigout_filtered_show(struct device *dev,708				     struct device_attribute *attr,709				     char *buf)710{711	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);712	struct cti_config *cfg = &drvdata->config;713	int size = 0, nr_trig_max = cfg->nr_trig_max;714	unsigned long mask = cfg->trig_out_filter;715 716	if (mask)717		size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max);718	return size;719}720static DEVICE_ATTR_RO(trigout_filtered);721 722/* clear all xtrigger / channel programming */723static ssize_t chan_xtrigs_reset_store(struct device *dev,724				       struct device_attribute *attr,725				       const char *buf, size_t size)726{727	int i;728	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);729	struct cti_config *config = &drvdata->config;730 731	spin_lock(&drvdata->spinlock);732 733	/* clear the CTI trigger / channel programming registers */734	for (i = 0; i < config->nr_trig_max; i++) {735		config->ctiinen[i] = 0;736		config->ctiouten[i] = 0;737	}738 739	/* clear the other regs */740	config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);741	config->asicctl = 0;742	config->ctiappset = 0;743	config->ctiinout_sel = 0;744	config->xtrig_rchan_sel = 0;745 746	/* if enabled then write through */747	if (cti_active(config))748		cti_write_all_hw_regs(drvdata);749 750	spin_unlock(&drvdata->spinlock);751	return size;752}753static DEVICE_ATTR_WO(chan_xtrigs_reset);754 755/*756 * Write to select a channel to view, read to display the757 * cross triggers for the selected channel.758 */759static ssize_t chan_xtrigs_sel_store(struct device *dev,760				     struct device_attribute *attr,761				     const char *buf, size_t size)762{763	unsigned long val;764	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);765 766	if (kstrtoul(buf, 0, &val))767		return -EINVAL;768	if (val > (drvdata->config.nr_ctm_channels - 1))769		return -EINVAL;770 771	spin_lock(&drvdata->spinlock);772	drvdata->config.xtrig_rchan_sel = val;773	spin_unlock(&drvdata->spinlock);774	return size;775}776 777static ssize_t chan_xtrigs_sel_show(struct device *dev,778				    struct device_attribute *attr,779				    char *buf)780{781	unsigned long val;782	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);783 784	spin_lock(&drvdata->spinlock);785	val = drvdata->config.xtrig_rchan_sel;786	spin_unlock(&drvdata->spinlock);787 788	return sprintf(buf, "%ld\n", val);789}790static DEVICE_ATTR_RW(chan_xtrigs_sel);791 792static ssize_t chan_xtrigs_in_show(struct device *dev,793				   struct device_attribute *attr,794				   char *buf)795{796	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);797	struct cti_config *cfg = &drvdata->config;798	int used = 0, reg_idx;799	int nr_trig_max = drvdata->config.nr_trig_max;800	u32 chan_mask = BIT(cfg->xtrig_rchan_sel);801 802	for (reg_idx = 0; reg_idx < nr_trig_max; reg_idx++) {803		if (chan_mask & cfg->ctiinen[reg_idx])804			used += sprintf(buf + used, "%d ", reg_idx);805	}806 807	used += sprintf(buf + used, "\n");808	return used;809}810static DEVICE_ATTR_RO(chan_xtrigs_in);811 812static ssize_t chan_xtrigs_out_show(struct device *dev,813				    struct device_attribute *attr,814				    char *buf)815{816	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);817	struct cti_config *cfg = &drvdata->config;818	int used = 0, reg_idx;819	int nr_trig_max = drvdata->config.nr_trig_max;820	u32 chan_mask = BIT(cfg->xtrig_rchan_sel);821 822	for (reg_idx = 0; reg_idx < nr_trig_max; reg_idx++) {823		if (chan_mask & cfg->ctiouten[reg_idx])824			used += sprintf(buf + used, "%d ", reg_idx);825	}826 827	used += sprintf(buf + used, "\n");828	return used;829}830static DEVICE_ATTR_RO(chan_xtrigs_out);831 832static ssize_t print_chan_list(struct device *dev,833			       char *buf, bool inuse)834{835	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);836	struct cti_config *config = &drvdata->config;837	int size, i;838	unsigned long inuse_bits = 0, chan_mask;839 840	/* scan regs to get bitmap of channels in use. */841	spin_lock(&drvdata->spinlock);842	for (i = 0; i < config->nr_trig_max; i++) {843		inuse_bits |= config->ctiinen[i];844		inuse_bits |= config->ctiouten[i];845	}846	spin_unlock(&drvdata->spinlock);847 848	/* inverse bits if printing free channels */849	if (!inuse)850		inuse_bits = ~inuse_bits;851 852	/* list of channels, or 'none' */853	chan_mask = GENMASK(config->nr_ctm_channels - 1, 0);854	if (inuse_bits & chan_mask)855		size = bitmap_print_to_pagebuf(true, buf, &inuse_bits,856					       config->nr_ctm_channels);857	else858		size = sprintf(buf, "\n");859	return size;860}861 862static ssize_t chan_inuse_show(struct device *dev,863			       struct device_attribute *attr,864			       char *buf)865{866	return print_chan_list(dev, buf, true);867}868static DEVICE_ATTR_RO(chan_inuse);869 870static ssize_t chan_free_show(struct device *dev,871			      struct device_attribute *attr,872			      char *buf)873{874	return print_chan_list(dev, buf, false);875}876static DEVICE_ATTR_RO(chan_free);877 878static struct attribute *coresight_cti_channel_attrs[] = {879	&dev_attr_trigin_attach.attr,880	&dev_attr_trigin_detach.attr,881	&dev_attr_trigout_attach.attr,882	&dev_attr_trigout_detach.attr,883	&dev_attr_trig_filter_enable.attr,884	&dev_attr_trigout_filtered.attr,885	&dev_attr_chan_gate_enable.attr,886	&dev_attr_chan_gate_disable.attr,887	&dev_attr_chan_set.attr,888	&dev_attr_chan_clear.attr,889	&dev_attr_chan_pulse.attr,890	&dev_attr_chan_inuse.attr,891	&dev_attr_chan_free.attr,892	&dev_attr_chan_xtrigs_sel.attr,893	&dev_attr_chan_xtrigs_in.attr,894	&dev_attr_chan_xtrigs_out.attr,895	&dev_attr_chan_xtrigs_reset.attr,896	NULL,897};898 899/* Create the connections trigger groups and attrs dynamically */900/*901 * Each connection has dynamic group triggers<N> + name, trigin/out sigs/types902 * attributes, + each device has static nr_trigger_cons giving the number903 * of groups. e.g. in sysfs:-904 * /cti_<name>/triggers0905 * /cti_<name>/triggers1906 * /cti_<name>/nr_trigger_cons907 * where nr_trigger_cons = 2908 */909static ssize_t con_name_show(struct device *dev,910			     struct device_attribute *attr,911			     char *buf)912{913	struct dev_ext_attribute *ext_attr =914		container_of(attr, struct dev_ext_attribute, attr);915	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;916 917	return sprintf(buf, "%s\n", con->con_dev_name);918}919 920static ssize_t trigin_sig_show(struct device *dev,921			       struct device_attribute *attr,922			       char *buf)923{924	struct dev_ext_attribute *ext_attr =925		container_of(attr, struct dev_ext_attribute, attr);926	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;927	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);928	struct cti_config *cfg = &drvdata->config;929	unsigned long mask = con->con_in->used_mask;930 931	return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);932}933 934static ssize_t trigout_sig_show(struct device *dev,935				struct device_attribute *attr,936				char *buf)937{938	struct dev_ext_attribute *ext_attr =939		container_of(attr, struct dev_ext_attribute, attr);940	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;941	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);942	struct cti_config *cfg = &drvdata->config;943	unsigned long mask = con->con_out->used_mask;944 945	return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);946}947 948/* convert a sig type id to a name */949static const char *950cti_sig_type_name(struct cti_trig_con *con, int used_count, bool in)951{952	int idx = 0;953	struct cti_trig_grp *grp = in ? con->con_in : con->con_out;954 955	if (used_count < grp->nr_sigs)956		idx = grp->sig_types[used_count];957	return sig_type_names[idx];958}959 960static ssize_t trigin_type_show(struct device *dev,961				struct device_attribute *attr,962				char *buf)963{964	struct dev_ext_attribute *ext_attr =965		container_of(attr, struct dev_ext_attribute, attr);966	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;967	int sig_idx, used = 0;968	const char *name;969 970	for (sig_idx = 0; sig_idx < con->con_in->nr_sigs; sig_idx++) {971		name = cti_sig_type_name(con, sig_idx, true);972		used += sprintf(buf + used, "%s ", name);973	}974	used += sprintf(buf + used, "\n");975	return used;976}977 978static ssize_t trigout_type_show(struct device *dev,979				 struct device_attribute *attr,980				 char *buf)981{982	struct dev_ext_attribute *ext_attr =983		container_of(attr, struct dev_ext_attribute, attr);984	struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;985	int sig_idx, used = 0;986	const char *name;987 988	for (sig_idx = 0; sig_idx < con->con_out->nr_sigs; sig_idx++) {989		name = cti_sig_type_name(con, sig_idx, false);990		used += sprintf(buf + used, "%s ", name);991	}992	used += sprintf(buf + used, "\n");993	return used;994}995 996/*997 * Array of show function names declared above to allow selection998 * for the connection attributes999 */1000static p_show_fn show_fns[CTI_CON_ATTR_MAX] = {1001	con_name_show,1002	trigin_sig_show,1003	trigout_sig_show,1004	trigin_type_show,1005	trigout_type_show,1006};1007 1008static int cti_create_con_sysfs_attr(struct device *dev,1009				     struct cti_trig_con *con,1010				     enum cti_conn_attr_type attr_type,1011				     int attr_idx)1012{1013	struct dev_ext_attribute *eattr;1014	char *name;1015 1016	eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),1017				    GFP_KERNEL);1018	if (eattr) {1019		name = devm_kstrdup(dev, con_attr_names[attr_type],1020				    GFP_KERNEL);1021		if (name) {1022			/* fill out the underlying attribute struct */1023			eattr->attr.attr.name = name;1024			eattr->attr.attr.mode = 0444;1025 1026			/* now the device_attribute struct */1027			eattr->attr.show = show_fns[attr_type];1028		} else {1029			return -ENOMEM;1030		}1031	} else {1032		return -ENOMEM;1033	}1034	eattr->var = con;1035	con->con_attrs[attr_idx] = &eattr->attr.attr;1036	/*1037	 * Initialize the dynamically allocated attribute1038	 * to avoid LOCKDEP splat. See include/linux/sysfs.h1039	 * for more details.1040	 */1041	sysfs_attr_init(con->con_attrs[attr_idx]);1042 1043	return 0;1044}1045 1046static struct attribute_group *1047cti_create_con_sysfs_group(struct device *dev, struct cti_device *ctidev,1048			   int con_idx, struct cti_trig_con *tc)1049{1050	struct attribute_group *group = NULL;1051	int grp_idx;1052 1053	group = devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL);1054	if (!group)1055		return NULL;1056 1057	group->name = devm_kasprintf(dev, GFP_KERNEL, "triggers%d", con_idx);1058	if (!group->name)1059		return NULL;1060 1061	grp_idx = con_idx + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1;1062	ctidev->con_groups[grp_idx] = group;1063	tc->attr_group = group;1064	return group;1065}1066 1067/* create a triggers connection group and the attributes for that group */1068static int cti_create_con_attr_set(struct device *dev, int con_idx,1069				   struct cti_device *ctidev,1070				   struct cti_trig_con *tc)1071{1072	struct attribute_group *attr_group = NULL;1073	int attr_idx = 0;1074	int err = -ENOMEM;1075 1076	attr_group = cti_create_con_sysfs_group(dev, ctidev, con_idx, tc);1077	if (!attr_group)1078		return -ENOMEM;1079 1080	/* allocate NULL terminated array of attributes */1081	tc->con_attrs = devm_kcalloc(dev, CTI_CON_ATTR_MAX + 1,1082				     sizeof(struct attribute *), GFP_KERNEL);1083	if (!tc->con_attrs)1084		return -ENOMEM;1085 1086	err = cti_create_con_sysfs_attr(dev, tc, CTI_CON_ATTR_NAME,1087					attr_idx++);1088	if (err)1089		return err;1090 1091	if (tc->con_in->nr_sigs > 0) {1092		err = cti_create_con_sysfs_attr(dev, tc,1093						CTI_CON_ATTR_TRIGIN_SIG,1094						attr_idx++);1095		if (err)1096			return err;1097 1098		err = cti_create_con_sysfs_attr(dev, tc,1099						CTI_CON_ATTR_TRIGIN_TYPES,1100						attr_idx++);1101		if (err)1102			return err;1103	}1104 1105	if (tc->con_out->nr_sigs > 0) {1106		err = cti_create_con_sysfs_attr(dev, tc,1107						CTI_CON_ATTR_TRIGOUT_SIG,1108						attr_idx++);1109		if (err)1110			return err;1111 1112		err = cti_create_con_sysfs_attr(dev, tc,1113						CTI_CON_ATTR_TRIGOUT_TYPES,1114						attr_idx++);1115		if (err)1116			return err;1117	}1118	attr_group->attrs = tc->con_attrs;1119	return 0;1120}1121 1122/* create the array of group pointers for the CTI sysfs groups */1123static int cti_create_cons_groups(struct device *dev, struct cti_device *ctidev)1124{1125	int nr_groups;1126 1127	/* nr groups = dynamic + static + NULL terminator */1128	nr_groups = ctidev->nr_trig_con + CORESIGHT_CTI_STATIC_GROUPS_MAX;1129	ctidev->con_groups = devm_kcalloc(dev, nr_groups,1130					  sizeof(struct attribute_group *),1131					  GFP_KERNEL);1132	if (!ctidev->con_groups)1133		return -ENOMEM;1134	return 0;1135}1136 1137int cti_create_cons_sysfs(struct device *dev, struct cti_drvdata *drvdata)1138{1139	struct cti_device *ctidev = &drvdata->ctidev;1140	int err, con_idx = 0, i;1141	struct cti_trig_con *tc;1142 1143	err = cti_create_cons_groups(dev, ctidev);1144	if (err)1145		return err;1146 1147	/* populate first locations with the static set of groups */1148	for (i = 0; i < (CORESIGHT_CTI_STATIC_GROUPS_MAX - 1); i++)1149		ctidev->con_groups[i] = coresight_cti_groups[i];1150 1151	/* add dynamic set for each connection */1152	list_for_each_entry(tc, &ctidev->trig_cons, node) {1153		err = cti_create_con_attr_set(dev, con_idx++, ctidev, tc);1154		if (err)1155			break;1156	}1157	return err;1158}1159 1160/* attribute and group sysfs tables. */1161static const struct attribute_group coresight_cti_group = {1162	.attrs = coresight_cti_attrs,1163};1164 1165static const struct attribute_group coresight_cti_mgmt_group = {1166	.attrs = coresight_cti_mgmt_attrs,1167	.name = "mgmt",1168};1169 1170static const struct attribute_group coresight_cti_regs_group = {1171	.attrs = coresight_cti_regs_attrs,1172	.name = "regs",1173};1174 1175static const struct attribute_group coresight_cti_channels_group = {1176	.attrs = coresight_cti_channel_attrs,1177	.name = "channels",1178};1179 1180const struct attribute_group *1181coresight_cti_groups[CORESIGHT_CTI_STATIC_GROUPS_MAX] = {1182	&coresight_cti_group,1183	&coresight_cti_mgmt_group,1184	&coresight_cti_regs_group,1185	&coresight_cti_channels_group,1186	NULL,1187};1188