brintos

brintos / linux-shallow public Read only

0
0
Text · 32.1 KiB · b7d99e9 Raw
1331 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.4 */5 6#include <linux/amba/bus.h>7#include <linux/bitfield.h>8#include <linux/bitmap.h>9#include <linux/coresight.h>10#include <linux/coresight-pmu.h>11#include <linux/device.h>12#include <linux/err.h>13#include <linux/fs.h>14#include <linux/io.h>15#include <linux/kernel.h>16#include <linux/module.h>17#include <linux/of.h>18 19#include "coresight-priv.h"20#include "coresight-tpdm.h"21 22DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm");23 24/* Read dataset array member with the index number */25static ssize_t tpdm_simple_dataset_show(struct device *dev,26					struct device_attribute *attr,27					char *buf)28{29	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);30	struct tpdm_dataset_attribute *tpdm_attr =31		container_of(attr, struct tpdm_dataset_attribute, attr);32 33	switch (tpdm_attr->mem) {34	case DSB_EDGE_CTRL:35		if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCR)36			return -EINVAL;37		return sysfs_emit(buf, "0x%x\n",38			drvdata->dsb->edge_ctrl[tpdm_attr->idx]);39	case DSB_EDGE_CTRL_MASK:40		if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCMR)41			return -EINVAL;42		return sysfs_emit(buf, "0x%x\n",43			drvdata->dsb->edge_ctrl_mask[tpdm_attr->idx]);44	case DSB_TRIG_PATT:45		if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)46			return -EINVAL;47		return sysfs_emit(buf, "0x%x\n",48			drvdata->dsb->trig_patt[tpdm_attr->idx]);49	case DSB_TRIG_PATT_MASK:50		if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)51			return -EINVAL;52		return sysfs_emit(buf, "0x%x\n",53			drvdata->dsb->trig_patt_mask[tpdm_attr->idx]);54	case DSB_PATT:55		if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)56			return -EINVAL;57		return sysfs_emit(buf, "0x%x\n",58			drvdata->dsb->patt_val[tpdm_attr->idx]);59	case DSB_PATT_MASK:60		if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)61			return -EINVAL;62		return sysfs_emit(buf, "0x%x\n",63			drvdata->dsb->patt_mask[tpdm_attr->idx]);64	case DSB_MSR:65		if (tpdm_attr->idx >= drvdata->dsb_msr_num)66			return -EINVAL;67		return sysfs_emit(buf, "0x%x\n",68				drvdata->dsb->msr[tpdm_attr->idx]);69	case CMB_TRIG_PATT:70		if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)71			return -EINVAL;72		return sysfs_emit(buf, "0x%x\n",73			drvdata->cmb->trig_patt[tpdm_attr->idx]);74	case CMB_TRIG_PATT_MASK:75		if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)76			return -EINVAL;77		return sysfs_emit(buf, "0x%x\n",78			drvdata->cmb->trig_patt_mask[tpdm_attr->idx]);79	case CMB_PATT:80		if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)81			return -EINVAL;82		return sysfs_emit(buf, "0x%x\n",83			drvdata->cmb->patt_val[tpdm_attr->idx]);84	case CMB_PATT_MASK:85		if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)86			return -EINVAL;87		return sysfs_emit(buf, "0x%x\n",88			drvdata->cmb->patt_mask[tpdm_attr->idx]);89	case CMB_MSR:90		if (tpdm_attr->idx >= drvdata->cmb_msr_num)91			return -EINVAL;92		return sysfs_emit(buf, "0x%x\n",93				drvdata->cmb->msr[tpdm_attr->idx]);94	}95	return -EINVAL;96}97 98/* Write dataset array member with the index number */99static ssize_t tpdm_simple_dataset_store(struct device *dev,100					 struct device_attribute *attr,101					 const char *buf,102					 size_t size)103{104	unsigned long val;105	ssize_t ret = -EINVAL;106 107	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);108	struct tpdm_dataset_attribute *tpdm_attr =109		container_of(attr, struct tpdm_dataset_attribute, attr);110 111	if (kstrtoul(buf, 0, &val))112		return ret;113 114	guard(spinlock)(&drvdata->spinlock);115	switch (tpdm_attr->mem) {116	case DSB_TRIG_PATT:117		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {118			drvdata->dsb->trig_patt[tpdm_attr->idx] = val;119			ret = size;120		}121		break;122	case DSB_TRIG_PATT_MASK:123		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {124			drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val;125			ret = size;126		}127		break;128	case DSB_PATT:129		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {130			drvdata->dsb->patt_val[tpdm_attr->idx] = val;131			ret = size;132		}133		break;134	case DSB_PATT_MASK:135		if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {136			drvdata->dsb->patt_mask[tpdm_attr->idx] = val;137			ret = size;138		}139		break;140	case DSB_MSR:141		if (tpdm_attr->idx < drvdata->dsb_msr_num) {142			drvdata->dsb->msr[tpdm_attr->idx] = val;143			ret = size;144		}145		break;146	case CMB_TRIG_PATT:147		if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {148			drvdata->cmb->trig_patt[tpdm_attr->idx] = val;149			ret = size;150		}151		break;152	case CMB_TRIG_PATT_MASK:153		if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {154			drvdata->cmb->trig_patt_mask[tpdm_attr->idx] = val;155			ret = size;156		}157		break;158	case CMB_PATT:159		if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {160			drvdata->cmb->patt_val[tpdm_attr->idx] = val;161			ret = size;162		}163		break;164	case CMB_PATT_MASK:165		if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {166			drvdata->cmb->patt_mask[tpdm_attr->idx] = val;167			ret = size;168		}169		break;170	case CMB_MSR:171		if (tpdm_attr->idx < drvdata->cmb_msr_num) {172			drvdata->cmb->msr[tpdm_attr->idx] = val;173			ret = size;174		}175		break;176	default:177		break;178	}179 180	return ret;181}182 183static umode_t tpdm_dsb_is_visible(struct kobject *kobj,184				   struct attribute *attr, int n)185{186	struct device *dev = kobj_to_dev(kobj);187	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);188 189	if (drvdata && tpdm_has_dsb_dataset(drvdata))190		return attr->mode;191 192	return 0;193}194 195static umode_t tpdm_cmb_is_visible(struct kobject *kobj,196				   struct attribute *attr, int n)197{198	struct device *dev = kobj_to_dev(kobj);199	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);200 201	if (drvdata && tpdm_has_cmb_dataset(drvdata))202		return attr->mode;203 204	return 0;205}206 207static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj,208				       struct attribute *attr, int n)209{210	struct device *dev = kobj_to_dev(kobj);211	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);212	struct device_attribute *dev_attr =213		container_of(attr, struct device_attribute, attr);214	struct tpdm_dataset_attribute *tpdm_attr =215		container_of(dev_attr, struct tpdm_dataset_attribute, attr);216 217	if (tpdm_attr->idx < drvdata->dsb_msr_num)218		return attr->mode;219 220	return 0;221}222 223static umode_t tpdm_cmb_msr_is_visible(struct kobject *kobj,224				       struct attribute *attr, int n)225{226	struct device *dev = kobj_to_dev(kobj);227	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);228 229	struct device_attribute *dev_attr =230		container_of(attr, struct device_attribute, attr);231	struct tpdm_dataset_attribute *tpdm_attr =232		container_of(dev_attr, struct tpdm_dataset_attribute, attr);233 234	if (tpdm_attr->idx < drvdata->cmb_msr_num)235		return attr->mode;236 237	return 0;238}239 240static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)241{242	if (tpdm_has_dsb_dataset(drvdata)) {243		memset(drvdata->dsb, 0, sizeof(struct dsb_dataset));244 245		drvdata->dsb->trig_ts = true;246		drvdata->dsb->trig_type = false;247	}248 249	if (drvdata->cmb)250		memset(drvdata->cmb, 0, sizeof(struct cmb_dataset));251}252 253static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val)254{255	u32 mode;256 257	/* Set the test accurate mode */258	mode = TPDM_DSB_MODE_TEST(drvdata->dsb->mode);259	*val &= ~TPDM_DSB_CR_TEST_MODE;260	*val |= FIELD_PREP(TPDM_DSB_CR_TEST_MODE, mode);261 262	/* Set the byte lane for high-performance mode */263	mode = TPDM_DSB_MODE_HPBYTESEL(drvdata->dsb->mode);264	*val &= ~TPDM_DSB_CR_HPSEL;265	*val |= FIELD_PREP(TPDM_DSB_CR_HPSEL, mode);266 267	/* Set the performance mode */268	if (drvdata->dsb->mode & TPDM_DSB_MODE_PERF)269		*val |= TPDM_DSB_CR_MODE;270	else271		*val &= ~TPDM_DSB_CR_MODE;272}273 274static void set_dsb_tier(struct tpdm_drvdata *drvdata)275{276	u32 val;277 278	val = readl_relaxed(drvdata->base + TPDM_DSB_TIER);279 280	/* Clear all relevant fields */281	val &= ~(TPDM_DSB_TIER_PATT_TSENAB | TPDM_DSB_TIER_PATT_TYPE |282		 TPDM_DSB_TIER_XTRIG_TSENAB);283 284	/* Set pattern timestamp type and enablement */285	if (drvdata->dsb->patt_ts) {286		val |= TPDM_DSB_TIER_PATT_TSENAB;287		if (drvdata->dsb->patt_type)288			val |= TPDM_DSB_TIER_PATT_TYPE;289		else290			val &= ~TPDM_DSB_TIER_PATT_TYPE;291	} else {292		val &= ~TPDM_DSB_TIER_PATT_TSENAB;293	}294 295	/* Set trigger timestamp */296	if (drvdata->dsb->trig_ts)297		val |= TPDM_DSB_TIER_XTRIG_TSENAB;298	else299		val &= ~TPDM_DSB_TIER_XTRIG_TSENAB;300 301	writel_relaxed(val, drvdata->base + TPDM_DSB_TIER);302}303 304static void set_dsb_msr(struct tpdm_drvdata *drvdata)305{306	int i;307 308	for (i = 0; i < drvdata->dsb_msr_num; i++)309		writel_relaxed(drvdata->dsb->msr[i],310			   drvdata->base + TPDM_DSB_MSR(i));311}312 313static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)314{315	u32 val, i;316 317	if (!tpdm_has_dsb_dataset(drvdata))318		return;319 320	for (i = 0; i < TPDM_DSB_MAX_EDCR; i++)321		writel_relaxed(drvdata->dsb->edge_ctrl[i],322			       drvdata->base + TPDM_DSB_EDCR(i));323	for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++)324		writel_relaxed(drvdata->dsb->edge_ctrl_mask[i],325			       drvdata->base + TPDM_DSB_EDCMR(i));326	for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {327		writel_relaxed(drvdata->dsb->patt_val[i],328			       drvdata->base + TPDM_DSB_TPR(i));329		writel_relaxed(drvdata->dsb->patt_mask[i],330			       drvdata->base + TPDM_DSB_TPMR(i));331		writel_relaxed(drvdata->dsb->trig_patt[i],332			       drvdata->base + TPDM_DSB_XPR(i));333		writel_relaxed(drvdata->dsb->trig_patt_mask[i],334			       drvdata->base + TPDM_DSB_XPMR(i));335	}336 337	set_dsb_tier(drvdata);338	set_dsb_msr(drvdata);339 340	val = readl_relaxed(drvdata->base + TPDM_DSB_CR);341	/* Set the mode of DSB dataset */342	set_dsb_mode(drvdata, &val);343	/* Set trigger type */344	if (drvdata->dsb->trig_type)345		val |= TPDM_DSB_CR_TRIG_TYPE;346	else347		val &= ~TPDM_DSB_CR_TRIG_TYPE;348	/* Set the enable bit of DSB control register to 1 */349	val |= TPDM_DSB_CR_ENA;350	writel_relaxed(val, drvdata->base + TPDM_DSB_CR);351}352 353static void set_cmb_tier(struct tpdm_drvdata *drvdata)354{355	u32 val;356 357	val = readl_relaxed(drvdata->base + TPDM_CMB_TIER);358 359	/* Clear all relevant fields */360	val &= ~(TPDM_CMB_TIER_PATT_TSENAB | TPDM_CMB_TIER_TS_ALL |361		 TPDM_CMB_TIER_XTRIG_TSENAB);362 363	/* Set pattern timestamp type and enablement */364	if (drvdata->cmb->patt_ts)365		val |= TPDM_CMB_TIER_PATT_TSENAB;366 367	/* Set trigger timestamp */368	if (drvdata->cmb->trig_ts)369		val |= TPDM_CMB_TIER_XTRIG_TSENAB;370 371	/* Set all timestamp enablement*/372	if (drvdata->cmb->ts_all)373		val |= TPDM_CMB_TIER_TS_ALL;374 375	writel_relaxed(val, drvdata->base + TPDM_CMB_TIER);376}377 378static void set_cmb_msr(struct tpdm_drvdata *drvdata)379{380	int i;381 382	for (i = 0; i < drvdata->cmb_msr_num; i++)383		writel_relaxed(drvdata->cmb->msr[i],384			   drvdata->base + TPDM_CMB_MSR(i));385}386 387static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata)388{389	u32 val, i;390 391	if (!tpdm_has_cmb_dataset(drvdata))392		return;393 394	/* Configure pattern registers */395	for (i = 0; i < TPDM_CMB_MAX_PATT; i++) {396		writel_relaxed(drvdata->cmb->patt_val[i],397			drvdata->base + TPDM_CMB_TPR(i));398		writel_relaxed(drvdata->cmb->patt_mask[i],399			drvdata->base + TPDM_CMB_TPMR(i));400		writel_relaxed(drvdata->cmb->trig_patt[i],401			drvdata->base + TPDM_CMB_XPR(i));402		writel_relaxed(drvdata->cmb->trig_patt_mask[i],403			drvdata->base + TPDM_CMB_XPMR(i));404	}405 406	set_cmb_tier(drvdata);407	set_cmb_msr(drvdata);408 409	val = readl_relaxed(drvdata->base + TPDM_CMB_CR);410	/*411	 * Set to 0 for continuous CMB collection mode,412	 * 1 for trace-on-change CMB collection mode.413	 */414	if (drvdata->cmb->trace_mode)415		val |= TPDM_CMB_CR_MODE;416	else417		val &= ~TPDM_CMB_CR_MODE;418	/* Set the enable bit of CMB control register to 1 */419	val |= TPDM_CMB_CR_ENA;420	writel_relaxed(val, drvdata->base + TPDM_CMB_CR);421}422 423/*424 * TPDM enable operations425 * The TPDM or Monitor serves as data collection component for various426 * dataset types. It covers Basic Counts(BC), Tenure Counts(TC),427 * Continuous Multi-Bit(CMB), Multi-lane CMB(MCMB) and Discrete Single428 * Bit(DSB). This function will initialize the configuration according429 * to the dataset type supported by the TPDM.430 */431static void __tpdm_enable(struct tpdm_drvdata *drvdata)432{433	CS_UNLOCK(drvdata->base);434 435	tpdm_enable_dsb(drvdata);436	tpdm_enable_cmb(drvdata);437 438	CS_LOCK(drvdata->base);439}440 441static int tpdm_enable(struct coresight_device *csdev, struct perf_event *event,442		       enum cs_mode mode,443		       __maybe_unused struct coresight_trace_id_map *id_map)444{445	struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);446 447	spin_lock(&drvdata->spinlock);448	if (drvdata->enable) {449		spin_unlock(&drvdata->spinlock);450		return -EBUSY;451	}452 453	if (!coresight_take_mode(csdev, mode)) {454		spin_unlock(&drvdata->spinlock);455		return -EBUSY;456	}457 458	__tpdm_enable(drvdata);459	drvdata->enable = true;460	spin_unlock(&drvdata->spinlock);461 462	dev_dbg(drvdata->dev, "TPDM tracing enabled\n");463	return 0;464}465 466static void tpdm_disable_dsb(struct tpdm_drvdata *drvdata)467{468	u32 val;469 470	if (!tpdm_has_dsb_dataset(drvdata))471		return;472 473	/* Set the enable bit of DSB control register to 0 */474	val = readl_relaxed(drvdata->base + TPDM_DSB_CR);475	val &= ~TPDM_DSB_CR_ENA;476	writel_relaxed(val, drvdata->base + TPDM_DSB_CR);477}478 479static void tpdm_disable_cmb(struct tpdm_drvdata *drvdata)480{481	u32 val;482 483	if (!tpdm_has_cmb_dataset(drvdata))484		return;485 486	val = readl_relaxed(drvdata->base + TPDM_CMB_CR);487	/* Set the enable bit of CMB control register to 0 */488	val &= ~TPDM_CMB_CR_ENA;489	writel_relaxed(val, drvdata->base + TPDM_CMB_CR);490}491 492/* TPDM disable operations */493static void __tpdm_disable(struct tpdm_drvdata *drvdata)494{495	CS_UNLOCK(drvdata->base);496 497	tpdm_disable_dsb(drvdata);498	tpdm_disable_cmb(drvdata);499 500	CS_LOCK(drvdata->base);501}502 503static void tpdm_disable(struct coresight_device *csdev,504			 struct perf_event *event)505{506	struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);507 508	spin_lock(&drvdata->spinlock);509	if (!drvdata->enable) {510		spin_unlock(&drvdata->spinlock);511		return;512	}513 514	__tpdm_disable(drvdata);515	coresight_set_mode(csdev, CS_MODE_DISABLED);516	drvdata->enable = false;517	spin_unlock(&drvdata->spinlock);518 519	dev_dbg(drvdata->dev, "TPDM tracing disabled\n");520}521 522static const struct coresight_ops_source tpdm_source_ops = {523	.enable		= tpdm_enable,524	.disable	= tpdm_disable,525};526 527static const struct coresight_ops tpdm_cs_ops = {528	.source_ops	= &tpdm_source_ops,529};530 531static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata)532{533	u32 pidr;534 535	/*  Get the datasets present on the TPDM. */536	pidr = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR0);537	drvdata->datasets |= pidr & GENMASK(TPDM_DATASETS - 1, 0);538 539	if (tpdm_has_dsb_dataset(drvdata) && (!drvdata->dsb)) {540		drvdata->dsb = devm_kzalloc(drvdata->dev,541						sizeof(*drvdata->dsb), GFP_KERNEL);542		if (!drvdata->dsb)543			return -ENOMEM;544	}545	if (tpdm_has_cmb_dataset(drvdata) && (!drvdata->cmb)) {546		drvdata->cmb = devm_kzalloc(drvdata->dev,547						sizeof(*drvdata->cmb), GFP_KERNEL);548		if (!drvdata->cmb)549			return -ENOMEM;550	}551	tpdm_reset_datasets(drvdata);552 553	return 0;554}555 556static ssize_t reset_dataset_store(struct device *dev,557				   struct device_attribute *attr,558				   const char *buf,559				   size_t size)560{561	int ret = 0;562	unsigned long val;563	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);564 565	ret = kstrtoul(buf, 0, &val);566	if (ret || val != 1)567		return -EINVAL;568 569	spin_lock(&drvdata->spinlock);570	tpdm_reset_datasets(drvdata);571	spin_unlock(&drvdata->spinlock);572 573	return size;574}575static DEVICE_ATTR_WO(reset_dataset);576 577/*578 * value 1: 64 bits test data579 * value 2: 32 bits test data580 */581static ssize_t integration_test_store(struct device *dev,582					  struct device_attribute *attr,583					  const char *buf,584					  size_t size)585{586	int i, ret = 0;587	unsigned long val;588	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);589 590	ret = kstrtoul(buf, 10, &val);591	if (ret)592		return ret;593 594	if (val != 1 && val != 2)595		return -EINVAL;596 597	if (!drvdata->enable)598		return -EINVAL;599 600	if (val == 1)601		val = ATBCNTRL_VAL_64;602	else603		val = ATBCNTRL_VAL_32;604	CS_UNLOCK(drvdata->base);605	writel_relaxed(0x1, drvdata->base + TPDM_ITCNTRL);606 607	for (i = 0; i < INTEGRATION_TEST_CYCLE; i++)608		writel_relaxed(val, drvdata->base + TPDM_ITATBCNTRL);609 610	writel_relaxed(0, drvdata->base + TPDM_ITCNTRL);611	CS_LOCK(drvdata->base);612	return size;613}614static DEVICE_ATTR_WO(integration_test);615 616static struct attribute *tpdm_attrs[] = {617	&dev_attr_reset_dataset.attr,618	&dev_attr_integration_test.attr,619	NULL,620};621 622static struct attribute_group tpdm_attr_grp = {623	.attrs = tpdm_attrs,624};625 626static ssize_t dsb_mode_show(struct device *dev,627			     struct device_attribute *attr,628			     char *buf)629{630	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);631 632	return sysfs_emit(buf, "%x\n", drvdata->dsb->mode);633}634 635static ssize_t dsb_mode_store(struct device *dev,636			      struct device_attribute *attr,637			      const char *buf,638			      size_t size)639{640	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);641	unsigned long val;642 643	if ((kstrtoul(buf, 0, &val)) || (val < 0) ||644			(val & ~TPDM_DSB_MODE_MASK))645		return -EINVAL;646 647	spin_lock(&drvdata->spinlock);648	drvdata->dsb->mode = val & TPDM_DSB_MODE_MASK;649	spin_unlock(&drvdata->spinlock);650	return size;651}652static DEVICE_ATTR_RW(dsb_mode);653 654static ssize_t ctrl_idx_show(struct device *dev,655			     struct device_attribute *attr,656			     char *buf)657{658	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);659 660	return sysfs_emit(buf, "%u\n",661			(unsigned int)drvdata->dsb->edge_ctrl_idx);662}663 664/*665 * The EDCR registers can include up to 16 32-bit registers, and each666 * one can be configured to control up to 16 edge detections(2 bits667 * control one edge detection). So a total 256 edge detections can be668 * configured. This function provides a way to set the index number of669 * the edge detection which needs to be configured.670 */671static ssize_t ctrl_idx_store(struct device *dev,672			      struct device_attribute *attr,673			      const char *buf,674			      size_t size)675{676	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);677	unsigned long val;678 679	if ((kstrtoul(buf, 0, &val)) || (val >= TPDM_DSB_MAX_LINES))680		return -EINVAL;681 682	spin_lock(&drvdata->spinlock);683	drvdata->dsb->edge_ctrl_idx = val;684	spin_unlock(&drvdata->spinlock);685 686	return size;687}688static DEVICE_ATTR_RW(ctrl_idx);689 690/*691 * This function is used to control the edge detection according692 * to the index number that has been set.693 * "edge_ctrl" should be one of the following values.694 * 0 - Rising edge detection695 * 1 - Falling edge detection696 * 2 - Rising and falling edge detection (toggle detection)697 */698static ssize_t ctrl_val_store(struct device *dev,699			      struct device_attribute *attr,700			      const char *buf,701			      size_t size)702{703	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);704	unsigned long val, edge_ctrl;705	int reg;706 707	if ((kstrtoul(buf, 0, &edge_ctrl)) || (edge_ctrl > 0x2))708		return -EINVAL;709 710	spin_lock(&drvdata->spinlock);711	/*712	 * There are 2 bit per DSB Edge Control line.713	 * Thus we have 16 lines in a 32bit word.714	 */715	reg = EDCR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);716	val = drvdata->dsb->edge_ctrl[reg];717	val &= ~EDCR_TO_WORD_MASK(drvdata->dsb->edge_ctrl_idx);718	val |= EDCR_TO_WORD_VAL(edge_ctrl, drvdata->dsb->edge_ctrl_idx);719	drvdata->dsb->edge_ctrl[reg] = val;720	spin_unlock(&drvdata->spinlock);721 722	return size;723}724static DEVICE_ATTR_WO(ctrl_val);725 726static ssize_t ctrl_mask_store(struct device *dev,727			       struct device_attribute *attr,728			       const char *buf,729			       size_t size)730{731	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);732	unsigned long val;733	u32 set;734	int reg;735 736	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))737		return -EINVAL;738 739	spin_lock(&drvdata->spinlock);740	/*741	 * There is 1 bit per DSB Edge Control Mark line.742	 * Thus we have 32 lines in a 32bit word.743	 */744	reg = EDCMR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);745	set = drvdata->dsb->edge_ctrl_mask[reg];746	if (val)747		set |= BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx));748	else749		set &= ~BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx));750	drvdata->dsb->edge_ctrl_mask[reg] = set;751	spin_unlock(&drvdata->spinlock);752 753	return size;754}755static DEVICE_ATTR_WO(ctrl_mask);756 757static ssize_t enable_ts_show(struct device *dev,758			      struct device_attribute *attr,759			      char *buf)760{761	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);762	struct tpdm_dataset_attribute *tpdm_attr =763		container_of(attr, struct tpdm_dataset_attribute, attr);764	ssize_t size = -EINVAL;765 766	if (tpdm_attr->mem == DSB_PATT)767		size = sysfs_emit(buf, "%u\n",768				  (unsigned int)drvdata->dsb->patt_ts);769	else if (tpdm_attr->mem == CMB_PATT)770		size = sysfs_emit(buf, "%u\n",771				  (unsigned int)drvdata->cmb->patt_ts);772 773	return size;774}775 776/*777 * value 1: Enable/Disable DSB pattern timestamp778 */779static ssize_t enable_ts_store(struct device *dev,780			       struct device_attribute *attr,781			       const char *buf,782			       size_t size)783{784	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);785	struct tpdm_dataset_attribute *tpdm_attr =786		container_of(attr, struct tpdm_dataset_attribute, attr);787	unsigned long val;788 789	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))790		return -EINVAL;791 792	guard(spinlock)(&drvdata->spinlock);793	if (tpdm_attr->mem == DSB_PATT)794		drvdata->dsb->patt_ts = !!val;795	else if (tpdm_attr->mem == CMB_PATT)796		drvdata->cmb->patt_ts = !!val;797	else798		return -EINVAL;799 800	return size;801}802 803static ssize_t set_type_show(struct device *dev,804			     struct device_attribute *attr,805			     char *buf)806{807	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);808 809	return sysfs_emit(buf, "%u\n",810			 (unsigned int)drvdata->dsb->patt_type);811}812 813/*814 * value 1: Set DSB pattern type815 */816static ssize_t set_type_store(struct device *dev,817			      struct device_attribute *attr,818			      const char *buf, size_t size)819{820	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);821	unsigned long val;822 823	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))824		return -EINVAL;825 826	spin_lock(&drvdata->spinlock);827	drvdata->dsb->patt_type = val;828	spin_unlock(&drvdata->spinlock);829	return size;830}831static DEVICE_ATTR_RW(set_type);832 833static ssize_t dsb_trig_type_show(struct device *dev,834				  struct device_attribute *attr, char *buf)835{836	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);837 838	return sysfs_emit(buf, "%u\n",839			 (unsigned int)drvdata->dsb->trig_type);840}841 842/*843 * Trigger type (boolean):844 * false - Disable trigger type.845 * true  - Enable trigger type.846 */847static ssize_t dsb_trig_type_store(struct device *dev,848				   struct device_attribute *attr,849				   const char *buf,850				   size_t size)851{852	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);853	unsigned long val;854 855	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))856		return -EINVAL;857 858	spin_lock(&drvdata->spinlock);859	if (val)860		drvdata->dsb->trig_type = true;861	else862		drvdata->dsb->trig_type = false;863	spin_unlock(&drvdata->spinlock);864	return size;865}866static DEVICE_ATTR_RW(dsb_trig_type);867 868static ssize_t dsb_trig_ts_show(struct device *dev,869				struct device_attribute *attr,870				char *buf)871{872	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);873 874	return sysfs_emit(buf, "%u\n",875			 (unsigned int)drvdata->dsb->trig_ts);876}877 878/*879 * Trigger timestamp (boolean):880 * false - Disable trigger timestamp.881 * true  - Enable trigger timestamp.882 */883static ssize_t dsb_trig_ts_store(struct device *dev,884				 struct device_attribute *attr,885				 const char *buf,886				 size_t size)887{888	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);889	unsigned long val;890 891	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))892		return -EINVAL;893 894	spin_lock(&drvdata->spinlock);895	if (val)896		drvdata->dsb->trig_ts = true;897	else898		drvdata->dsb->trig_ts = false;899	spin_unlock(&drvdata->spinlock);900	return size;901}902static DEVICE_ATTR_RW(dsb_trig_ts);903 904static ssize_t cmb_mode_show(struct device *dev,905			     struct device_attribute *attr,906			     char *buf)907{908	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);909 910	return sysfs_emit(buf, "%x\n", drvdata->cmb->trace_mode);911 912}913 914static ssize_t cmb_mode_store(struct device *dev,915			      struct device_attribute *attr,916			      const char *buf,917			      size_t size)918{919	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);920	unsigned long trace_mode;921 922	if (kstrtoul(buf, 0, &trace_mode) || (trace_mode & ~1UL))923		return -EINVAL;924 925	spin_lock(&drvdata->spinlock);926	drvdata->cmb->trace_mode = trace_mode;927	spin_unlock(&drvdata->spinlock);928	return size;929}930static DEVICE_ATTR_RW(cmb_mode);931 932static ssize_t cmb_ts_all_show(struct device *dev,933			       struct device_attribute *attr,934			       char *buf)935{936	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);937 938	return sysfs_emit(buf, "%u\n",939			  (unsigned int)drvdata->cmb->ts_all);940}941 942static ssize_t cmb_ts_all_store(struct device *dev,943				struct device_attribute *attr,944				const char *buf,945				size_t size)946{947	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);948	unsigned long val;949 950	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))951		return -EINVAL;952 953	guard(spinlock)(&drvdata->spinlock);954	if (val)955		drvdata->cmb->ts_all = true;956	else957		drvdata->cmb->ts_all = false;958 959	return size;960}961static DEVICE_ATTR_RW(cmb_ts_all);962 963static ssize_t cmb_trig_ts_show(struct device *dev,964				struct device_attribute *attr,965				char *buf)966{967	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);968 969	return sysfs_emit(buf, "%u\n",970			  (unsigned int)drvdata->cmb->trig_ts);971}972 973static ssize_t cmb_trig_ts_store(struct device *dev,974				 struct device_attribute *attr,975				 const char *buf,976				 size_t size)977{978	struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);979	unsigned long val;980 981	if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))982		return -EINVAL;983 984	guard(spinlock)(&drvdata->spinlock);985	if (val)986		drvdata->cmb->trig_ts = true;987	else988		drvdata->cmb->trig_ts = false;989 990	return size;991}992static DEVICE_ATTR_RW(cmb_trig_ts);993 994static struct attribute *tpdm_dsb_edge_attrs[] = {995	&dev_attr_ctrl_idx.attr,996	&dev_attr_ctrl_val.attr,997	&dev_attr_ctrl_mask.attr,998	DSB_EDGE_CTRL_ATTR(0),999	DSB_EDGE_CTRL_ATTR(1),1000	DSB_EDGE_CTRL_ATTR(2),1001	DSB_EDGE_CTRL_ATTR(3),1002	DSB_EDGE_CTRL_ATTR(4),1003	DSB_EDGE_CTRL_ATTR(5),1004	DSB_EDGE_CTRL_ATTR(6),1005	DSB_EDGE_CTRL_ATTR(7),1006	DSB_EDGE_CTRL_ATTR(8),1007	DSB_EDGE_CTRL_ATTR(9),1008	DSB_EDGE_CTRL_ATTR(10),1009	DSB_EDGE_CTRL_ATTR(11),1010	DSB_EDGE_CTRL_ATTR(12),1011	DSB_EDGE_CTRL_ATTR(13),1012	DSB_EDGE_CTRL_ATTR(14),1013	DSB_EDGE_CTRL_ATTR(15),1014	DSB_EDGE_CTRL_MASK_ATTR(0),1015	DSB_EDGE_CTRL_MASK_ATTR(1),1016	DSB_EDGE_CTRL_MASK_ATTR(2),1017	DSB_EDGE_CTRL_MASK_ATTR(3),1018	DSB_EDGE_CTRL_MASK_ATTR(4),1019	DSB_EDGE_CTRL_MASK_ATTR(5),1020	DSB_EDGE_CTRL_MASK_ATTR(6),1021	DSB_EDGE_CTRL_MASK_ATTR(7),1022	NULL,1023};1024 1025static struct attribute *tpdm_dsb_trig_patt_attrs[] = {1026	DSB_TRIG_PATT_ATTR(0),1027	DSB_TRIG_PATT_ATTR(1),1028	DSB_TRIG_PATT_ATTR(2),1029	DSB_TRIG_PATT_ATTR(3),1030	DSB_TRIG_PATT_ATTR(4),1031	DSB_TRIG_PATT_ATTR(5),1032	DSB_TRIG_PATT_ATTR(6),1033	DSB_TRIG_PATT_ATTR(7),1034	DSB_TRIG_PATT_MASK_ATTR(0),1035	DSB_TRIG_PATT_MASK_ATTR(1),1036	DSB_TRIG_PATT_MASK_ATTR(2),1037	DSB_TRIG_PATT_MASK_ATTR(3),1038	DSB_TRIG_PATT_MASK_ATTR(4),1039	DSB_TRIG_PATT_MASK_ATTR(5),1040	DSB_TRIG_PATT_MASK_ATTR(6),1041	DSB_TRIG_PATT_MASK_ATTR(7),1042	NULL,1043};1044 1045static struct attribute *tpdm_dsb_patt_attrs[] = {1046	DSB_PATT_ATTR(0),1047	DSB_PATT_ATTR(1),1048	DSB_PATT_ATTR(2),1049	DSB_PATT_ATTR(3),1050	DSB_PATT_ATTR(4),1051	DSB_PATT_ATTR(5),1052	DSB_PATT_ATTR(6),1053	DSB_PATT_ATTR(7),1054	DSB_PATT_MASK_ATTR(0),1055	DSB_PATT_MASK_ATTR(1),1056	DSB_PATT_MASK_ATTR(2),1057	DSB_PATT_MASK_ATTR(3),1058	DSB_PATT_MASK_ATTR(4),1059	DSB_PATT_MASK_ATTR(5),1060	DSB_PATT_MASK_ATTR(6),1061	DSB_PATT_MASK_ATTR(7),1062	DSB_PATT_ENABLE_TS,1063	&dev_attr_set_type.attr,1064	NULL,1065};1066 1067static struct attribute *tpdm_dsb_msr_attrs[] = {1068	DSB_MSR_ATTR(0),1069	DSB_MSR_ATTR(1),1070	DSB_MSR_ATTR(2),1071	DSB_MSR_ATTR(3),1072	DSB_MSR_ATTR(4),1073	DSB_MSR_ATTR(5),1074	DSB_MSR_ATTR(6),1075	DSB_MSR_ATTR(7),1076	DSB_MSR_ATTR(8),1077	DSB_MSR_ATTR(9),1078	DSB_MSR_ATTR(10),1079	DSB_MSR_ATTR(11),1080	DSB_MSR_ATTR(12),1081	DSB_MSR_ATTR(13),1082	DSB_MSR_ATTR(14),1083	DSB_MSR_ATTR(15),1084	DSB_MSR_ATTR(16),1085	DSB_MSR_ATTR(17),1086	DSB_MSR_ATTR(18),1087	DSB_MSR_ATTR(19),1088	DSB_MSR_ATTR(20),1089	DSB_MSR_ATTR(21),1090	DSB_MSR_ATTR(22),1091	DSB_MSR_ATTR(23),1092	DSB_MSR_ATTR(24),1093	DSB_MSR_ATTR(25),1094	DSB_MSR_ATTR(26),1095	DSB_MSR_ATTR(27),1096	DSB_MSR_ATTR(28),1097	DSB_MSR_ATTR(29),1098	DSB_MSR_ATTR(30),1099	DSB_MSR_ATTR(31),1100	NULL,1101};1102 1103static struct attribute *tpdm_cmb_trig_patt_attrs[] = {1104	CMB_TRIG_PATT_ATTR(0),1105	CMB_TRIG_PATT_ATTR(1),1106	CMB_TRIG_PATT_MASK_ATTR(0),1107	CMB_TRIG_PATT_MASK_ATTR(1),1108	NULL,1109};1110 1111static struct attribute *tpdm_cmb_patt_attrs[] = {1112	CMB_PATT_ATTR(0),1113	CMB_PATT_ATTR(1),1114	CMB_PATT_MASK_ATTR(0),1115	CMB_PATT_MASK_ATTR(1),1116	CMB_PATT_ENABLE_TS,1117	NULL,1118};1119 1120static struct attribute *tpdm_cmb_msr_attrs[] = {1121	CMB_MSR_ATTR(0),1122	CMB_MSR_ATTR(1),1123	CMB_MSR_ATTR(2),1124	CMB_MSR_ATTR(3),1125	CMB_MSR_ATTR(4),1126	CMB_MSR_ATTR(5),1127	CMB_MSR_ATTR(6),1128	CMB_MSR_ATTR(7),1129	CMB_MSR_ATTR(8),1130	CMB_MSR_ATTR(9),1131	CMB_MSR_ATTR(10),1132	CMB_MSR_ATTR(11),1133	CMB_MSR_ATTR(12),1134	CMB_MSR_ATTR(13),1135	CMB_MSR_ATTR(14),1136	CMB_MSR_ATTR(15),1137	CMB_MSR_ATTR(16),1138	CMB_MSR_ATTR(17),1139	CMB_MSR_ATTR(18),1140	CMB_MSR_ATTR(19),1141	CMB_MSR_ATTR(20),1142	CMB_MSR_ATTR(21),1143	CMB_MSR_ATTR(22),1144	CMB_MSR_ATTR(23),1145	CMB_MSR_ATTR(24),1146	CMB_MSR_ATTR(25),1147	CMB_MSR_ATTR(26),1148	CMB_MSR_ATTR(27),1149	CMB_MSR_ATTR(28),1150	CMB_MSR_ATTR(29),1151	CMB_MSR_ATTR(30),1152	CMB_MSR_ATTR(31),1153	NULL,1154};1155 1156static struct attribute *tpdm_dsb_attrs[] = {1157	&dev_attr_dsb_mode.attr,1158	&dev_attr_dsb_trig_ts.attr,1159	&dev_attr_dsb_trig_type.attr,1160	NULL,1161};1162 1163static struct attribute *tpdm_cmb_attrs[] = {1164	&dev_attr_cmb_mode.attr,1165	&dev_attr_cmb_ts_all.attr,1166	&dev_attr_cmb_trig_ts.attr,1167	NULL,1168};1169 1170static struct attribute_group tpdm_dsb_attr_grp = {1171	.attrs = tpdm_dsb_attrs,1172	.is_visible = tpdm_dsb_is_visible,1173};1174 1175static struct attribute_group tpdm_dsb_edge_grp = {1176	.attrs = tpdm_dsb_edge_attrs,1177	.is_visible = tpdm_dsb_is_visible,1178	.name = "dsb_edge",1179};1180 1181static struct attribute_group tpdm_dsb_trig_patt_grp = {1182	.attrs = tpdm_dsb_trig_patt_attrs,1183	.is_visible = tpdm_dsb_is_visible,1184	.name = "dsb_trig_patt",1185};1186 1187static struct attribute_group tpdm_dsb_patt_grp = {1188	.attrs = tpdm_dsb_patt_attrs,1189	.is_visible = tpdm_dsb_is_visible,1190	.name = "dsb_patt",1191};1192 1193static struct attribute_group tpdm_dsb_msr_grp = {1194	.attrs = tpdm_dsb_msr_attrs,1195	.is_visible = tpdm_dsb_msr_is_visible,1196	.name = "dsb_msr",1197};1198 1199static struct attribute_group tpdm_cmb_attr_grp = {1200	.attrs = tpdm_cmb_attrs,1201	.is_visible = tpdm_cmb_is_visible,1202};1203 1204static struct attribute_group tpdm_cmb_trig_patt_grp = {1205	.attrs = tpdm_cmb_trig_patt_attrs,1206	.is_visible = tpdm_cmb_is_visible,1207	.name = "cmb_trig_patt",1208};1209 1210static struct attribute_group tpdm_cmb_patt_grp = {1211	.attrs = tpdm_cmb_patt_attrs,1212	.is_visible = tpdm_cmb_is_visible,1213	.name = "cmb_patt",1214};1215 1216static struct attribute_group tpdm_cmb_msr_grp = {1217	.attrs = tpdm_cmb_msr_attrs,1218	.is_visible = tpdm_cmb_msr_is_visible,1219	.name = "cmb_msr",1220};1221 1222static const struct attribute_group *tpdm_attr_grps[] = {1223	&tpdm_attr_grp,1224	&tpdm_dsb_attr_grp,1225	&tpdm_dsb_edge_grp,1226	&tpdm_dsb_trig_patt_grp,1227	&tpdm_dsb_patt_grp,1228	&tpdm_dsb_msr_grp,1229	&tpdm_cmb_attr_grp,1230	&tpdm_cmb_trig_patt_grp,1231	&tpdm_cmb_patt_grp,1232	&tpdm_cmb_msr_grp,1233	NULL,1234};1235 1236static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)1237{1238	void __iomem *base;1239	struct device *dev = &adev->dev;1240	struct coresight_platform_data *pdata;1241	struct tpdm_drvdata *drvdata;1242	struct coresight_desc desc = { 0 };1243	int ret;1244 1245	pdata = coresight_get_platform_data(dev);1246	if (IS_ERR(pdata))1247		return PTR_ERR(pdata);1248	adev->dev.platform_data = pdata;1249 1250	/* driver data*/1251	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);1252	if (!drvdata)1253		return -ENOMEM;1254	drvdata->dev = &adev->dev;1255	dev_set_drvdata(dev, drvdata);1256 1257	base = devm_ioremap_resource(dev, &adev->res);1258	if (IS_ERR(base))1259		return PTR_ERR(base);1260 1261	drvdata->base = base;1262 1263	ret = tpdm_datasets_setup(drvdata);1264	if (ret)1265		return ret;1266 1267	if (drvdata && tpdm_has_dsb_dataset(drvdata))1268		of_property_read_u32(drvdata->dev->of_node,1269			   "qcom,dsb-msrs-num", &drvdata->dsb_msr_num);1270 1271	if (drvdata && tpdm_has_cmb_dataset(drvdata))1272		of_property_read_u32(drvdata->dev->of_node,1273			   "qcom,cmb-msrs-num", &drvdata->cmb_msr_num);1274 1275	/* Set up coresight component description */1276	desc.name = coresight_alloc_device_name(&tpdm_devs, dev);1277	if (!desc.name)1278		return -ENOMEM;1279	desc.type = CORESIGHT_DEV_TYPE_SOURCE;1280	desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM;1281	desc.ops = &tpdm_cs_ops;1282	desc.pdata = adev->dev.platform_data;1283	desc.dev = &adev->dev;1284	desc.access = CSDEV_ACCESS_IOMEM(base);1285	desc.groups = tpdm_attr_grps;1286	drvdata->csdev = coresight_register(&desc);1287	if (IS_ERR(drvdata->csdev))1288		return PTR_ERR(drvdata->csdev);1289 1290	spin_lock_init(&drvdata->spinlock);1291 1292	/* Decrease pm refcount when probe is done.*/1293	pm_runtime_put(&adev->dev);1294 1295	return 0;1296}1297 1298static void tpdm_remove(struct amba_device *adev)1299{1300	struct tpdm_drvdata *drvdata = dev_get_drvdata(&adev->dev);1301 1302	coresight_unregister(drvdata->csdev);1303}1304 1305/*1306 * Different TPDM has different periph id.1307 * The difference is 0-7 bits' value. So ignore 0-7 bits.1308 */1309static struct amba_id tpdm_ids[] = {1310	{1311		.id = 0x000f0e00,1312		.mask = 0x000fff00,1313	},1314	{ 0, 0, NULL },1315};1316 1317static struct amba_driver tpdm_driver = {1318	.drv = {1319		.name   = "coresight-tpdm",1320		.suppress_bind_attrs = true,1321	},1322	.probe          = tpdm_probe,1323	.id_table	= tpdm_ids,1324	.remove		= tpdm_remove,1325};1326 1327module_amba_driver(tpdm_driver);1328 1329MODULE_LICENSE("GPL");1330MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Monitor driver");1331