linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* CoreSight framework and drivers
@ 2012-12-18 19:19 pratikp at codeaurora.org
  2012-12-18 19:19 ` [RFC 1/8] coresight: add CoreSight core layer framework pratikp at codeaurora.org
                   ` (9 more replies)
  0 siblings, 10 replies; 32+ messages in thread
From: pratikp at codeaurora.org @ 2012-12-18 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

This RFC is aimed at introducing CoreSight framework as well as
individual CoreSight trace component drivers adhering to ARM
CoreSight specification. Some prior discussion on this can be
referred at [1].

There are 3 kinds of CoreSight trace components:

* Sources: Responsible for producing trace data to provide
  visibility for the associated entity.

* Links: Transport components that carry trace data.

* Sinks: Collectors for storing trace data or acting as conduits
  for off-chip trace data collection.

These components can be connected in various topologies to suite
a particular SoCs tracing needs.

Framework is responsible for gathering and using the information
about the registered CoreSight components and their connections
to allow it to dynamically deduce the sequence of components
representing a connection from a CoreSight source to the
currently selected CoreSight sink. This helps the framework to
program the correct set of components to satisfy user request.

[1] http://comments.gmane.org/gmane.linux.ports.arm.kernel/204591

Pratik Patel (8):
  coresight: add CoreSight core layer framework
  coresight: add CoreSight TMC driver
  coresight: add CoreSight TPIU driver
  coresight: add CoreSight ETB driver
  coresight: add CoreSight Funnel driver
  coresight: add CoreSight Replicator driver
  coresight: add CoreSight STM driver
  coresight: add CoreSight ETM driver

 Documentation/devicetree/bindings/arm/coresight.txt |  110 ++
 arch/arm/include/asm/hardware/cp14.h                |  540 ++++++
 drivers/Kconfig                                     |    2 +
 drivers/Makefile                                    |    1 +
 drivers/coresight/Kconfig                           |   60 +
 drivers/coresight/Makefile                          |    8 +
 drivers/coresight/coresight-etb.c                   |  467 +++++
 drivers/coresight/coresight-etm-cp14.c              |  510 ++++++
 drivers/coresight/coresight-etm.c                   | 1752 +++++++++++++++++++
 drivers/coresight/coresight-funnel.c                |  260 +++
 drivers/coresight/coresight-priv.h                  |   48 +
 drivers/coresight/coresight-replicator.c            |  211 +++
 drivers/coresight/coresight-stm.c                   |  819 +++++++++
 drivers/coresight/coresight-tmc.c                   |  794 +++++++++
 drivers/coresight/coresight-tpiu.c                  |  232 +++
 drivers/coresight/coresight.c                       |  681 +++++++
 drivers/coresight/of_coresight.c                    |   99 ++
 include/linux/coresight-stm.h                       |   51 +
 include/linux/coresight.h                           |  167 ++
 include/linux/of_coresight.h                        |   27 +
 20 files changed, 6839 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/coresight.txt
 create mode 100644 arch/arm/include/asm/hardware/cp14.h
 create mode 100644 drivers/coresight/Kconfig
 create mode 100644 drivers/coresight/Makefile
 create mode 100644 drivers/coresight/coresight-etb.c
 create mode 100644 drivers/coresight/coresight-etm-cp14.c
 create mode 100644 drivers/coresight/coresight-etm.c
 create mode 100644 drivers/coresight/coresight-funnel.c
 create mode 100644 drivers/coresight/coresight-priv.h
 create mode 100644 drivers/coresight/coresight-replicator.c
 create mode 100644 drivers/coresight/coresight-stm.c
 create mode 100644 drivers/coresight/coresight-tmc.c
 create mode 100644 drivers/coresight/coresight-tpiu.c
 create mode 100644 drivers/coresight/coresight.c
 create mode 100644 drivers/coresight/of_coresight.c
 create mode 100644 include/linux/coresight-stm.h
 create mode 100644 include/linux/coresight.h
 create mode 100644 include/linux/of_coresight.h

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [RFC 1/8] coresight: add CoreSight core layer framework
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
@ 2012-12-18 19:19 ` pratikp at codeaurora.org
  2012-12-18 19:19 ` [RFC 2/8] coresight: add CoreSight TMC driver pratikp at codeaurora.org
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 32+ messages in thread
From: pratikp at codeaurora.org @ 2012-12-18 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Pratik Patel <pratikp@codeaurora.org>

CoreSight components are compliant with the ARM CoreSight
architecture specification and can be connected in various
topologies to suite a particular SoCs tracing needs. These trace
components can generally be classified as sources, links and
sinks. Trace data produced by one or more sources flows through
the intermediate links connecting the source to the currently
selected sink.

CoreSight framework provides an interface for the CoreSight trace
drivers to register themselves with. It's intended to build up a
topological view of the CoreSight components and configure the
right series of components on user input via sysfs.

For eg., when enabling a source, framework builds up a path
consisting of all the components connecting the source to the
currently selected sink and enables all of them.

Framework also supports switching between available sinks and
also provides status information to user space applications
through sysfs interface.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
---
 .../devicetree/bindings/arm/coresight.txt          |  106 +++
 drivers/Kconfig                                    |    2 +
 drivers/Makefile                                   |    1 +
 drivers/coresight/Kconfig                          |    9 +
 drivers/coresight/Makefile                         |    5 +
 drivers/coresight/coresight-priv.h                 |   48 ++
 drivers/coresight/coresight.c                      |  681 ++++++++++++++++++++
 drivers/coresight/of_coresight.c                   |   99 +++
 include/linux/coresight.h                          |  167 +++++
 include/linux/of_coresight.h                       |   27 +
 10 files changed, 1145 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/coresight.txt
 create mode 100644 drivers/coresight/Kconfig
 create mode 100644 drivers/coresight/Makefile
 create mode 100644 drivers/coresight/coresight-priv.h
 create mode 100644 drivers/coresight/coresight.c
 create mode 100644 drivers/coresight/of_coresight.c
 create mode 100644 include/linux/coresight.h
 create mode 100644 include/linux/of_coresight.h

diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
new file mode 100644
index 0000000..c584073
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -0,0 +1,106 @@
+* CoreSight Components
+
+CoreSight components are compliant with the ARM CoreSight architecture
+specification and can be connected in various topologies to suite a particular
+SoCs tracing needs. These trace components can generally be classified as sinks,
+links and sources. Trace data produced by one or more sources flows through the
+intermediate links connecting the source to the currently selected sink. Each
+CoreSight component device should use these properties to describe its hardware
+characteristcs.
+
+Required properties:
+
+- compatible : name of the component used for driver matching
+- reg : physical base address and length of the register set(s) of the component
+- coresight-id : unique integer identifier for the component
+- coresight-name : unique descriptive name of the component
+- coresight-nr-inports : number of input ports on the component
+
+coresight-outports, coresight-child-list and coresight-child-ports lists will
+be of the same length and will have a one to one correspondence among the
+elements at the same list index.
+
+coresight-default-sink must be specified for one of the sink devices that is
+intended to be made the default sink. Other sink devices must not have this
+specified. Not specifying this property on any of the sinks is invalid.
+
+Optional properties:
+
+- coresight-outports : list of output port numbers of this component
+- coresight-child-list : list of phandles pointing to the children of this
+			 component
+- coresight-child-ports : list of input port numbers of the children
+- coresight-default-sink : represents the default compile time CoreSight sink
+
+Examples:
+
+1. Sinks
+	tmc_etr: tmc at fc322000 {
+		compatible = "arm,coresight-tmc";
+		reg = <0xfc322000 0x1000>;
+
+		coresight-id = <0>;
+		coresight-name = "coresight-tmc-etr";
+		coresight-nr-inports = <1>;
+		coresight-default-sink;
+	};
+
+	tpiu: tpiu at fc318000 {
+		compatible = "arm,coresight-tpiu";
+		reg = <0xfc318000 0x1000>;
+
+		coresight-id = <1>;
+		coresight-name = "coresight-tpiu";
+		coresight-nr-inports = <1>;
+	};
+
+2. Links
+	funnel_merg: funnel at fc31b000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc31b000 0x1000>;
+
+		coresight-id = <4>;
+		coresight-name = "coresight-funnel-merg";
+		coresight-nr-inports = <2>;
+		coresight-outports = <0>;
+		coresight-child-list = <&tmc_etf>;
+		coresight-child-ports = <0>;
+	};
+
+	funnel_in0: funnel at fc319000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0xfc319000 0x1000>;
+
+		coresight-id = <5>;
+		coresight-name = "coresight-funnel-in0";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_merg>;
+		coresight-child-ports = <0>;
+	};
+
+3. Sources
+	stm: stm at fc321000 {
+		compatible = "arm,coresight-stm";
+		reg = <0xfc321000 0x1000>,
+		      <0xfa280000 0x180000>;
+
+		coresight-id = <9>;
+		coresight-name = "coresight-stm";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_in1>;
+		coresight-child-ports = <7>;
+	};
+
+	etm0: etm at fc33c000 {
+		compatible = "arm,coresight-etm";
+		reg = <0xfc33c000 0x1000>;
+
+		coresight-id = <10>;
+		coresight-name = "coresight-etm0";
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel_kpss>;
+		coresight-child-ports = <0>;
+	};
diff --git a/drivers/Kconfig b/drivers/Kconfig
index dbdefa3..9b6f810 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -156,4 +156,6 @@ source "drivers/pwm/Kconfig"
 
 source "drivers/irqchip/Kconfig"
 
+source "drivers/coresight/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index a16a8d0..4650105 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -145,3 +145,4 @@ obj-$(CONFIG_EXTCON)		+= extcon/
 obj-$(CONFIG_MEMORY)		+= memory/
 obj-$(CONFIG_IIO)		+= iio/
 obj-$(CONFIG_VME_BUS)		+= vme/
+obj-$(CONFIG_CORESIGHT) 	+= coresight/
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
new file mode 100644
index 0000000..65279c4
--- /dev/null
+++ b/drivers/coresight/Kconfig
@@ -0,0 +1,9 @@
+menuconfig CORESIGHT
+	bool "CoreSight Tracing Support"
+	help
+	  This framework provides an interface for the CoreSight debug and
+	  trace drivers to register themselves with. It's intended to build
+	  up a topological view of the CoreSight components and configure
+	  the right series of components on user input via sysfs. It also
+	  provides status information to user space applications through
+	  sysfs interface.
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
new file mode 100644
index 0000000..218e3b5
--- /dev/null
+++ b/drivers/coresight/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for CoreSight drivers.
+#
+obj-$(CONFIG_CORESIGHT) += coresight.o
+obj-$(CONFIG_OF) += of_coresight.o
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
new file mode 100644
index 0000000..29dbd82
--- /dev/null
+++ b/drivers/coresight/coresight-priv.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CORESIGHT_PRIV_H
+#define _CORESIGHT_PRIV_H
+
+#include <linux/bitops.h>
+
+/*
+ * Coresight management registers (0xF00-0xFCC)
+ * 0xFA0 - 0xFA4: Management	registers in PFTv1.0
+ *		  Trace		registers in PFTv1.1
+ */
+#define CORESIGHT_ITCTRL	(0xF00)
+#define CORESIGHT_CLAIMSET	(0xFA0)
+#define CORESIGHT_CLAIMCLR	(0xFA4)
+#define CORESIGHT_LAR		(0xFB0)
+#define CORESIGHT_LSR		(0xFB4)
+#define CORESIGHT_AUTHSTATUS	(0xFB8)
+#define CORESIGHT_DEVID		(0xFC8)
+#define CORESIGHT_DEVTYPE	(0xFCC)
+
+#define CORESIGHT_UNLOCK	(0xC5ACCE55)
+
+#define TIMEOUT_US		(100)
+
+#define BM(lsb, msb)		((BIT(msb) - BIT(lsb)) + BIT(msb))
+#define BMVAL(val, lsb, msb)	((val & BM(lsb, msb)) >> lsb)
+#define BVAL(val, n)		((val & BIT(n)) >> n)
+
+#ifdef CONFIG_CORESIGHT_SOURCE_ETM
+extern unsigned int etm_readl_cp14(uint32_t off);
+extern void etm_writel_cp14(uint32_t val, uint32_t off);
+#else
+static inline unsigned int etm_readl_cp14(uint32_t off) { return 0; }
+static inline void etm_writel_cp14(uint32_t val, uint32_t off) {}
+#endif
+
+#endif
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
new file mode 100644
index 0000000..66389f7
--- /dev/null
+++ b/drivers/coresight/coresight.c
@@ -0,0 +1,681 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/semaphore.h>
+#include <linux/clk.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define NO_SINK		(-1)
+
+static int curr_sink = NO_SINK;
+static LIST_HEAD(coresight_orph_conns);
+static LIST_HEAD(coresight_devs);
+static DEFINE_SEMAPHORE(coresight_mutex);
+
+static int coresight_find_link_inport(struct coresight_device *csdev)
+{
+	int i;
+	struct coresight_device *parent;
+	struct coresight_connection *conn;
+
+	parent = container_of(csdev->path_link.next, struct coresight_device,
+			     path_link);
+	for (i = 0; i < parent->nr_conns; i++) {
+		conn = &parent->conns[i];
+		if (conn->child_dev == csdev)
+			return conn->child_port;
+	}
+
+	pr_err("coresight: couldn't find inport, parent: %d, child: %d\n",
+	       parent->id, csdev->id);
+	return 0;
+}
+
+static int coresight_find_link_outport(struct coresight_device *csdev)
+{
+	int i;
+	struct coresight_device *child;
+	struct coresight_connection *conn;
+
+	child = container_of(csdev->path_link.prev, struct coresight_device,
+			      path_link);
+	for (i = 0; i < csdev->nr_conns; i++) {
+		conn = &csdev->conns[i];
+		if (conn->child_dev == child)
+			return conn->outport;
+	}
+
+	pr_err("coresight: couldn't find outport, parent: %d, child: %d\n",
+	       csdev->id, child->id);
+	return 0;
+}
+
+static int coresight_enable_sink(struct coresight_device *csdev)
+{
+	int ret;
+
+	if (csdev->refcnt.sink_refcnt == 0) {
+		if (csdev->ops->sink_ops->enable) {
+			ret = csdev->ops->sink_ops->enable(csdev);
+			if (ret)
+				goto err;
+			csdev->enable = true;
+		}
+	}
+	csdev->refcnt.sink_refcnt++;
+
+	return 0;
+err:
+	return ret;
+}
+
+static void coresight_disable_sink(struct coresight_device *csdev)
+{
+	if (csdev->refcnt.sink_refcnt == 1) {
+		if (csdev->ops->sink_ops->disable) {
+			csdev->ops->sink_ops->disable(csdev);
+			csdev->enable = false;
+		}
+	}
+	csdev->refcnt.sink_refcnt--;
+}
+
+static int coresight_enable_link(struct coresight_device *csdev)
+{
+	int ret;
+	int link_subtype;
+	int refport, inport, outport;
+
+	inport = coresight_find_link_inport(csdev);
+	outport = coresight_find_link_outport(csdev);
+
+	link_subtype = csdev->subtype.link_subtype;
+	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
+		refport = inport;
+	else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
+		refport = outport;
+	else
+		refport = 0;
+
+	if (csdev->refcnt.link_refcnts[refport] == 0) {
+		if (csdev->ops->link_ops->enable) {
+			ret = csdev->ops->link_ops->enable(csdev, inport,
+							   outport);
+			if (ret)
+				goto err;
+			csdev->enable = true;
+		}
+	}
+	csdev->refcnt.link_refcnts[refport]++;
+
+	return 0;
+err:
+	return ret;
+}
+
+static void coresight_disable_link(struct coresight_device *csdev)
+{
+	int link_subtype;
+	int refport, inport, outport;
+
+	inport = coresight_find_link_inport(csdev);
+	outport = coresight_find_link_outport(csdev);
+
+	link_subtype = csdev->subtype.link_subtype;
+	if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
+		refport = inport;
+	else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
+		refport = outport;
+	else
+		refport = 0;
+
+	if (csdev->refcnt.link_refcnts[refport] == 1) {
+		if (csdev->ops->link_ops->disable) {
+			csdev->ops->link_ops->disable(csdev, inport, outport);
+			csdev->enable = false;
+		}
+	}
+	csdev->refcnt.link_refcnts[refport]--;
+}
+
+static int coresight_enable_source(struct coresight_device *csdev)
+{
+	int ret;
+
+	if (csdev->refcnt.source_refcnt == 0) {
+		if (csdev->ops->source_ops->enable) {
+			ret = csdev->ops->source_ops->enable(csdev);
+			if (ret)
+				goto err;
+			csdev->enable = true;
+		}
+	}
+	csdev->refcnt.source_refcnt++;
+
+	return 0;
+err:
+	return ret;
+}
+
+static void coresight_disable_source(struct coresight_device *csdev)
+{
+	if (csdev->refcnt.source_refcnt == 1) {
+		if (csdev->ops->source_ops->disable) {
+			csdev->ops->source_ops->disable(csdev);
+			csdev->enable = false;
+		}
+	}
+	csdev->refcnt.source_refcnt--;
+}
+
+static struct list_head *coresight_build_path(struct coresight_device *csdev,
+					      struct list_head *path)
+{
+	int i;
+	struct list_head *p;
+	struct coresight_connection *conn;
+
+	if (csdev->id == curr_sink) {
+		list_add_tail(&csdev->path_link, path);
+		return path;
+	}
+
+	for (i = 0; i < csdev->nr_conns; i++) {
+		conn = &csdev->conns[i];
+		p = coresight_build_path(conn->child_dev, path);
+		if (p) {
+			list_add_tail(&csdev->path_link, p);
+			return p;
+		}
+	}
+	return NULL;
+}
+
+static void coresight_release_path(struct list_head *path)
+{
+	struct coresight_device *cd, *temp;
+
+	list_for_each_entry_safe(cd, temp, path, path_link)
+		list_del(&cd->path_link);
+}
+
+static int coresight_enable_path(struct list_head *path, bool incl_source)
+{
+	int ret = 0;
+	struct coresight_device *cd;
+
+	list_for_each_entry(cd, path, path_link) {
+		if (cd == list_first_entry(path, struct coresight_device,
+					   path_link)) {
+			ret = coresight_enable_sink(cd);
+		} else if (list_is_last(&cd->path_link, path)) {
+			if (incl_source)
+				ret = coresight_enable_source(cd);
+		} else {
+			ret = coresight_enable_link(cd);
+		}
+		if (ret)
+			goto err;
+	}
+	return 0;
+err:
+	list_for_each_entry_continue_reverse(cd, path, path_link) {
+		if (cd == list_first_entry(path, struct coresight_device,
+					   path_link)) {
+			coresight_disable_sink(cd);
+		} else if (list_is_last(&cd->path_link, path)) {
+			if (incl_source)
+				coresight_disable_source(cd);
+		} else {
+			coresight_disable_link(cd);
+		}
+	}
+	return ret;
+}
+
+static void coresight_disable_path(struct list_head *path, bool incl_source)
+{
+	struct coresight_device *cd;
+
+	list_for_each_entry(cd, path, path_link) {
+		if (cd == list_first_entry(path, struct coresight_device,
+					   path_link)) {
+			coresight_disable_sink(cd);
+		} else if (list_is_last(&cd->path_link, path)) {
+			if (incl_source)
+				coresight_disable_source(cd);
+		} else {
+			coresight_disable_link(cd);
+		}
+	}
+}
+
+static int coresight_switch_sink(struct coresight_device *csdev)
+{
+	int ret = 0;
+	LIST_HEAD(path);
+	struct coresight_device *cd;
+
+	if (IS_ERR_OR_NULL(csdev))
+		return -EINVAL;
+
+	down(&coresight_mutex);
+	if (csdev->id == curr_sink)
+		goto out;
+
+	list_for_each_entry(cd, &coresight_devs, dev_link) {
+		if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
+			coresight_build_path(cd, &path);
+			coresight_disable_path(&path, false);
+			coresight_release_path(&path);
+		}
+	}
+	curr_sink = csdev->id;
+	list_for_each_entry(cd, &coresight_devs, dev_link) {
+		if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable) {
+			coresight_build_path(cd, &path);
+			ret = coresight_enable_path(&path, false);
+			coresight_release_path(&path);
+			if (ret)
+				goto err;
+		}
+	}
+out:
+	up(&coresight_mutex);
+	return 0;
+err:
+	list_for_each_entry(cd, &coresight_devs, dev_link) {
+		if (cd->type == CORESIGHT_DEV_TYPE_SOURCE && cd->enable)
+			coresight_disable_source(cd);
+	}
+	pr_err("coresight: sink switch failed, sources disabled; try again\n");
+	return ret;
+}
+
+int coresight_enable(struct coresight_device *csdev)
+{
+	int ret = 0;
+	LIST_HEAD(path);
+
+	if (IS_ERR_OR_NULL(csdev))
+		return -EINVAL;
+
+	down(&coresight_mutex);
+	if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
+		ret = -EINVAL;
+		pr_err("coresight: wrong device type in %s\n", __func__);
+		goto out;
+	}
+	if (csdev->enable)
+		goto out;
+
+	coresight_build_path(csdev, &path);
+	ret = coresight_enable_path(&path, true);
+	coresight_release_path(&path);
+	if (ret)
+		pr_err("coresight: enable failed\n");
+out:
+	up(&coresight_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(coresight_enable);
+
+void coresight_disable(struct coresight_device *csdev)
+{
+	LIST_HEAD(path);
+
+	if (IS_ERR_OR_NULL(csdev))
+		return;
+
+	down(&coresight_mutex);
+	if (csdev->type != CORESIGHT_DEV_TYPE_SOURCE) {
+		pr_err("coresight: wrong device type in %s\n", __func__);
+		goto out;
+	}
+	if (!csdev->enable)
+		goto out;
+
+	coresight_build_path(csdev, &path);
+	coresight_disable_path(&path, true);
+	coresight_release_path(&path);
+out:
+	up(&coresight_mutex);
+}
+EXPORT_SYMBOL_GPL(coresight_disable);
+
+void coresight_abort(void)
+{
+	struct coresight_device *cd;
+
+	if (down_trylock(&coresight_mutex)) {
+		pr_err("coresight: abort could not be processed\n");
+		return;
+	}
+	if (curr_sink == NO_SINK)
+		goto out;
+
+	list_for_each_entry(cd, &coresight_devs, dev_link) {
+		if (cd->id == curr_sink) {
+			if (cd->enable && cd->ops->sink_ops->abort) {
+				cd->ops->sink_ops->abort(cd);
+				cd->enable = false;
+			}
+		}
+	}
+out:
+	up(&coresight_mutex);
+}
+EXPORT_SYMBOL_GPL(coresight_abort);
+
+static ssize_t coresight_show_type(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", dev->type->name);
+}
+
+static struct device_attribute coresight_dev_attrs[] = {
+	__ATTR(type, S_IRUGO, coresight_show_type, NULL),
+	{ },
+};
+
+struct bus_type coresight_bus_type = {
+	.name		= "coresight",
+	.dev_attrs	= coresight_dev_attrs,
+};
+
+static ssize_t coresight_show_curr_sink(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct coresight_device *csdev = to_coresight_device(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n",
+			 csdev->id == curr_sink ? 1 : 0);
+}
+
+static ssize_t coresight_store_curr_sink(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t size)
+{
+	int ret = 0;
+	unsigned long val;
+	struct coresight_device *csdev = to_coresight_device(dev);
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (val)
+		ret = coresight_switch_sink(csdev);
+	else
+		ret = -EINVAL;
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR(curr_sink, S_IRUGO | S_IWUSR, coresight_show_curr_sink,
+		   coresight_store_curr_sink);
+
+static ssize_t coresight_show_enable(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct coresight_device *csdev = to_coresight_device(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->enable);
+}
+
+static ssize_t coresight_store_enable(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	int ret = 0;
+	unsigned long val;
+	struct coresight_device *csdev = to_coresight_device(dev);
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (val)
+		ret = coresight_enable(csdev);
+	else
+		coresight_disable(csdev);
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, coresight_show_enable,
+		   coresight_store_enable);
+
+static struct attribute *coresight_attrs_sink[] = {
+	&dev_attr_curr_sink.attr,
+	NULL,
+};
+
+static struct attribute_group coresight_attr_grp_sink = {
+	.attrs = coresight_attrs_sink,
+};
+
+static const struct attribute_group *coresight_attr_grps_sink[] = {
+	&coresight_attr_grp_sink,
+	NULL,
+};
+
+static struct attribute *coresight_attrs_source[] = {
+	&dev_attr_enable.attr,
+	NULL,
+};
+
+static struct attribute_group coresight_attr_grp_source = {
+	.attrs = coresight_attrs_source,
+};
+
+static const struct attribute_group *coresight_attr_grps_source[] = {
+	&coresight_attr_grp_source,
+	NULL,
+};
+
+static struct device_type coresight_dev_type[] = {
+	{
+		.name = "none",
+	},
+	{
+		.name = "sink",
+		.groups = coresight_attr_grps_sink,
+	},
+	{
+		.name = "link",
+	},
+	{
+		.name = "linksink",
+		.groups = coresight_attr_grps_sink,
+	},
+	{
+		.name = "source",
+		.groups = coresight_attr_grps_source,
+	},
+};
+
+static void coresight_device_release(struct device *dev)
+{
+	struct coresight_device *csdev = to_coresight_device(dev);
+	kfree(csdev);
+}
+
+static void coresight_fixup_orphan_conns(struct coresight_device *csdev)
+{
+	struct coresight_connection *conn, *temp;
+
+	list_for_each_entry_safe(conn, temp, &coresight_orph_conns, link) {
+		if (conn->child_id == csdev->id) {
+			conn->child_dev = csdev;
+			list_del(&conn->link);
+		}
+	}
+}
+
+static void coresight_fixup_device_conns(struct coresight_device *csdev)
+{
+	int i;
+	struct coresight_device *cd;
+	bool found;
+
+	for (i = 0; i < csdev->nr_conns; i++) {
+		found = false;
+		list_for_each_entry(cd, &coresight_devs, dev_link) {
+			if (csdev->conns[i].child_id == cd->id) {
+				csdev->conns[i].child_dev = cd;
+				found = true;
+				break;
+			}
+		}
+		if (!found)
+			list_add_tail(&csdev->conns[i].link,
+				      &coresight_orph_conns);
+	}
+}
+
+struct coresight_device *coresight_register(struct coresight_desc *desc)
+{
+	int i;
+	int ret;
+	int link_subtype;
+	int nr_refcnts;
+	int *refcnts = NULL;
+	struct coresight_device *csdev;
+	struct coresight_connection *conns;
+
+	if (IS_ERR_OR_NULL(desc))
+		return ERR_PTR(-EINVAL);
+
+	csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
+	if (!csdev) {
+		ret = -ENOMEM;
+		goto err_kzalloc_csdev;
+	}
+
+	csdev->id = desc->pdata->id;
+
+	if (desc->type == CORESIGHT_DEV_TYPE_LINK ||
+	    desc->type == CORESIGHT_DEV_TYPE_LINKSINK) {
+		link_subtype = desc->subtype.link_subtype;
+		if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG)
+			nr_refcnts = desc->pdata->nr_inports;
+		else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT)
+			nr_refcnts = desc->pdata->nr_outports;
+		else
+			nr_refcnts = 1;
+
+		refcnts = kzalloc(sizeof(*refcnts) * nr_refcnts, GFP_KERNEL);
+		if (!refcnts) {
+			ret = -ENOMEM;
+			goto err_kzalloc_refcnts;
+		}
+		csdev->refcnt.link_refcnts = refcnts;
+	}
+
+	csdev->nr_conns = desc->pdata->nr_outports;
+	conns = kzalloc(sizeof(*conns) * csdev->nr_conns, GFP_KERNEL);
+	if (!conns) {
+		ret = -ENOMEM;
+		goto err_kzalloc_conns;
+	}
+	for (i = 0; i < csdev->nr_conns; i++) {
+		conns[i].outport = desc->pdata->outports[i];
+		conns[i].child_id = desc->pdata->child_ids[i];
+		conns[i].child_port = desc->pdata->child_ports[i];
+	}
+	csdev->conns = conns;
+
+	csdev->type = desc->type;
+	csdev->subtype = desc->subtype;
+	csdev->ops = desc->ops;
+	csdev->owner = desc->owner;
+
+	csdev->dev.type = &coresight_dev_type[desc->type];
+	csdev->dev.groups = desc->groups;
+	csdev->dev.parent = desc->dev;
+	csdev->dev.bus = &coresight_bus_type;
+	csdev->dev.release = coresight_device_release;
+	dev_set_name(&csdev->dev, "%s", desc->pdata->name);
+
+	down(&coresight_mutex);
+	if (desc->pdata->default_sink) {
+		if (curr_sink == NO_SINK) {
+			curr_sink = csdev->id;
+		} else {
+			ret = -EINVAL;
+			goto err_default_sink;
+		}
+	}
+
+	coresight_fixup_device_conns(csdev);
+	ret = device_register(&csdev->dev);
+	if (ret)
+		goto err_dev_reg;
+	coresight_fixup_orphan_conns(csdev);
+
+	list_add_tail(&csdev->dev_link, &coresight_devs);
+	up(&coresight_mutex);
+
+	return csdev;
+err_dev_reg:
+	put_device(&csdev->dev);
+err_default_sink:
+	up(&coresight_mutex);
+	kfree(conns);
+err_kzalloc_conns:
+	kfree(refcnts);
+err_kzalloc_refcnts:
+	kfree(csdev);
+err_kzalloc_csdev:
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(coresight_register);
+
+void coresight_unregister(struct coresight_device *csdev)
+{
+	if (IS_ERR_OR_NULL(csdev))
+		return;
+
+	if (get_device(&csdev->dev)) {
+		device_unregister(&csdev->dev);
+		put_device(&csdev->dev);
+	}
+}
+EXPORT_SYMBOL_GPL(coresight_unregister);
+
+static int __init coresight_init(void)
+{
+	return bus_register(&coresight_bus_type);
+}
+subsys_initcall(coresight_init);
+
+static void __exit coresight_exit(void)
+{
+	bus_unregister(&coresight_bus_type);
+}
+module_exit(coresight_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c
new file mode 100644
index 0000000..a9d0182
--- /dev/null
+++ b/drivers/coresight/of_coresight.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/coresight.h>
+
+struct coresight_platform_data *of_get_coresight_platform_data(
+				struct device *dev, struct device_node *node)
+{
+	int i, ret = 0;
+	uint32_t outports_len = 0;
+	struct device_node *child_node;
+	struct coresight_platform_data *pdata;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	ret = of_property_read_u32(node, "coresight-id", &pdata->id);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = of_property_read_string(node, "coresight-name", &pdata->name);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = of_property_read_u32(node, "coresight-nr-inports",
+				   &pdata->nr_inports);
+	if (ret)
+		return ERR_PTR(ret);
+
+	pdata->nr_outports = 0;
+	if (of_get_property(node, "coresight-outports", &outports_len))
+		pdata->nr_outports = outports_len/sizeof(uint32_t);
+
+	if (pdata->nr_outports) {
+		pdata->outports = devm_kzalloc(dev, pdata->nr_outports *
+					       sizeof(*pdata->outports),
+					       GFP_KERNEL);
+		if (!pdata->outports)
+			return ERR_PTR(-ENOMEM);
+
+		ret = of_property_read_u32_array(node, "coresight-outports",
+						 (u32 *)pdata->outports,
+						 pdata->nr_outports);
+		if (ret)
+			return ERR_PTR(ret);
+
+		pdata->child_ids = devm_kzalloc(dev, pdata->nr_outports *
+						sizeof(*pdata->child_ids),
+						GFP_KERNEL);
+		if (!pdata->child_ids)
+			return ERR_PTR(-ENOMEM);
+
+		for (i = 0; i < pdata->nr_outports; i++) {
+			child_node = of_parse_phandle(node,
+						      "coresight-child-list",
+						      i);
+			if (!child_node)
+				return ERR_PTR(-EINVAL);
+
+			ret = of_property_read_u32(child_node, "coresight-id",
+						   (u32 *)&pdata->child_ids[i]);
+			of_node_put(child_node);
+			if (ret)
+				return ERR_PTR(ret);
+		}
+
+		pdata->child_ports = devm_kzalloc(dev, pdata->nr_outports *
+						  sizeof(*pdata->child_ports),
+						  GFP_KERNEL);
+		if (!pdata->child_ports)
+			return ERR_PTR(-ENOMEM);
+
+		ret = of_property_read_u32_array(node, "coresight-child-ports",
+						 (u32 *)pdata->child_ports,
+						 pdata->nr_outports);
+		if (ret)
+			return ERR_PTR(ret);
+	}
+
+	pdata->default_sink = of_property_read_bool(node,
+						    "coresight-default-sink");
+	return pdata;
+}
+EXPORT_SYMBOL_GPL(of_get_coresight_platform_data);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
new file mode 100644
index 0000000..f98bd7f
--- /dev/null
+++ b/include/linux/coresight.h
@@ -0,0 +1,167 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_CORESIGHT_H
+#define _LINUX_CORESIGHT_H
+
+#include <linux/device.h>
+
+/* Peripheral id registers (0xFD0-0xFEC) */
+#define CORESIGHT_PERIPHIDR4	(0xFD0)
+#define CORESIGHT_PERIPHIDR5	(0xFD4)
+#define CORESIGHT_PERIPHIDR6	(0xFD8)
+#define CORESIGHT_PERIPHIDR7	(0xFDC)
+#define CORESIGHT_PERIPHIDR0	(0xFE0)
+#define CORESIGHT_PERIPHIDR1	(0xFE4)
+#define CORESIGHT_PERIPHIDR2	(0xFE8)
+#define CORESIGHT_PERIPHIDR3	(0xFEC)
+/* Component id registers (0xFF0-0xFFC) */
+#define CORESIGHT_COMPIDR0	(0xFF0)
+#define CORESIGHT_COMPIDR1	(0xFF4)
+#define CORESIGHT_COMPIDR2	(0xFF8)
+#define CORESIGHT_COMPIDR3	(0xFFC)
+
+#define ETM_ARCH_V3_3		(0x23)
+#define PFT_ARCH_V1_1		(0x31)
+
+enum coresight_clk_rate {
+	CORESIGHT_CLK_RATE_OFF,
+	CORESIGHT_CLK_RATE_TRACE,
+	CORESIGHT_CLK_RATE_HSTRACE,
+};
+
+enum coresight_dev_type {
+	CORESIGHT_DEV_TYPE_NONE,
+	CORESIGHT_DEV_TYPE_SINK,
+	CORESIGHT_DEV_TYPE_LINK,
+	CORESIGHT_DEV_TYPE_LINKSINK,
+	CORESIGHT_DEV_TYPE_SOURCE,
+};
+
+enum coresight_dev_subtype_sink {
+	CORESIGHT_DEV_SUBTYPE_SINK_NONE,
+	CORESIGHT_DEV_SUBTYPE_SINK_PORT,
+	CORESIGHT_DEV_SUBTYPE_SINK_BUFFER,
+};
+
+enum coresight_dev_subtype_link {
+	CORESIGHT_DEV_SUBTYPE_LINK_NONE,
+	CORESIGHT_DEV_SUBTYPE_LINK_MERG,
+	CORESIGHT_DEV_SUBTYPE_LINK_SPLIT,
+	CORESIGHT_DEV_SUBTYPE_LINK_FIFO,
+};
+
+enum coresight_dev_subtype_source {
+	CORESIGHT_DEV_SUBTYPE_SOURCE_NONE,
+	CORESIGHT_DEV_SUBTYPE_SOURCE_PROC,
+	CORESIGHT_DEV_SUBTYPE_SOURCE_BUS,
+	CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE,
+};
+
+struct coresight_dev_subtype {
+	enum coresight_dev_subtype_sink sink_subtype;
+	enum coresight_dev_subtype_link link_subtype;
+	enum coresight_dev_subtype_source source_subtype;
+};
+
+struct coresight_platform_data {
+	int id;
+	const char *name;
+	int nr_inports;
+	const int *outports;
+	const int *child_ids;
+	const int *child_ports;
+	int nr_outports;
+	bool default_sink;
+};
+
+struct coresight_desc {
+	enum coresight_dev_type type;
+	struct coresight_dev_subtype subtype;
+	const struct coresight_ops *ops;
+	struct coresight_platform_data *pdata;
+	struct device *dev;
+	const struct attribute_group **groups;
+	struct module *owner;
+};
+
+struct coresight_connection {
+	int outport;
+	int child_id;
+	int child_port;
+	struct coresight_device *child_dev;
+	struct list_head link;
+};
+
+struct coresight_refcnt {
+	int sink_refcnt;
+	int *link_refcnts;
+	int source_refcnt;
+};
+
+struct coresight_device {
+	int id;
+	struct coresight_connection *conns;
+	int nr_conns;
+	enum coresight_dev_type type;
+	struct coresight_dev_subtype subtype;
+	const struct coresight_ops *ops;
+	struct device dev;
+	struct coresight_refcnt refcnt;
+	struct list_head dev_link;
+	struct list_head path_link;
+	struct module *owner;
+	bool enable;
+};
+
+#define to_coresight_device(d) container_of(d, struct coresight_device, dev)
+
+struct coresight_ops_sink {
+	int (*enable)(struct coresight_device *csdev);
+	void (*disable)(struct coresight_device *csdev);
+	void (*abort)(struct coresight_device *csdev);
+};
+
+struct coresight_ops_link {
+	int (*enable)(struct coresight_device *csdev, int iport, int oport);
+	void (*disable)(struct coresight_device *csdev, int iport, int oport);
+};
+
+struct coresight_ops_source {
+	int (*enable)(struct coresight_device *csdev);
+	void (*disable)(struct coresight_device *csdev);
+};
+
+struct coresight_ops {
+	const struct coresight_ops_sink *sink_ops;
+	const struct coresight_ops_link *link_ops;
+	const struct coresight_ops_source *source_ops;
+};
+
+#ifdef CONFIG_CORESIGHT
+extern struct coresight_device *
+coresight_register(struct coresight_desc *desc);
+extern void coresight_unregister(struct coresight_device *csdev);
+extern int coresight_enable(struct coresight_device *csdev);
+extern void coresight_disable(struct coresight_device *csdev);
+extern void coresight_abort(void);
+#else
+static inline struct coresight_device *
+coresight_register(struct coresight_desc *desc) { return NULL; }
+static inline void coresight_unregister(struct coresight_device *csdev) {}
+static inline int
+coresight_enable(struct coresight_device *csdev) { return -ENOSYS; }
+static inline void coresight_disable(struct coresight_device *csdev) {}
+static inline void coresight_abort(void) {}
+#endif
+
+#endif
diff --git a/include/linux/of_coresight.h b/include/linux/of_coresight.h
new file mode 100644
index 0000000..6a5e4d4
--- /dev/null
+++ b/include/linux/of_coresight.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_OF_CORESIGHT_H
+#define __LINUX_OF_CORESIGHT_H
+
+#ifdef CONFIG_OF
+extern struct coresight_platform_data *of_get_coresight_platform_data(
+				struct device *dev, struct device_node *node);
+#else
+static inline struct coresight_platform_data *of_get_coresight_platform_data(
+				struct device *dev, struct device_node *node)
+{
+	return NULL;
+}
+#endif
+
+#endif
-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC 2/8] coresight: add CoreSight TMC driver
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
  2012-12-18 19:19 ` [RFC 1/8] coresight: add CoreSight core layer framework pratikp at codeaurora.org
@ 2012-12-18 19:19 ` pratikp at codeaurora.org
  2013-02-21 14:20   ` Robert MARKLUND
  2012-12-18 19:19 ` [RFC 3/8] coresight: add CoreSight TPIU driver pratikp at codeaurora.org
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 32+ messages in thread
From: pratikp at codeaurora.org @ 2012-12-18 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Pratik Patel <pratikp@codeaurora.org>

This driver manages CoreSight TMC (Trace Memory Controller) which
can act as a link or a sink depending upon its configuration. It
can present itself as an ETF (Embedded Trace FIFO) or ETR
(Embedded Trace Router).

ETF when configured in circular buffer mode acts as a trace
collection sink. When configured in HW fifo mode it acts as link.
ETR always acts as a sink and can be used to route data to memory
allocated in RAM.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
---
 .../devicetree/bindings/arm/coresight.txt          |    2 +
 drivers/coresight/Kconfig                          |   11 +
 drivers/coresight/Makefile                         |    1 +
 drivers/coresight/coresight-tmc.c                  |  794 ++++++++++++++++++++
 4 files changed, 808 insertions(+), 0 deletions(-)
 create mode 100644 drivers/coresight/coresight-tmc.c

diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index c584073..031f760 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -31,6 +31,7 @@ Optional properties:
 			 component
 - coresight-child-ports : list of input port numbers of the children
 - coresight-default-sink : represents the default compile time CoreSight sink
+- arm,buffer-size : size of contiguous buffer space for TMC ETR
 
 Examples:
 
@@ -43,6 +44,7 @@ Examples:
 		coresight-name = "coresight-tmc-etr";
 		coresight-nr-inports = <1>;
 		coresight-default-sink;
+		arm,buffer-size = <0x100000>;
 	};
 
 	tpiu: tpiu at fc318000 {
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 65279c4..6905ef2 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -7,3 +7,14 @@ menuconfig CORESIGHT
 	  the right series of components on user input via sysfs. It also
 	  provides status information to user space applications through
 	  sysfs interface.
+
+if CORESIGHT
+
+config CORESIGHT_LINKS_AND_SINKS
+	bool "CoreSight Link and Sink drivers"
+	help
+	  This enables support for CoreSight link and sink drivers that are
+	  responsible for transporting and collecting the trace data
+	  respectively.
+
+endif
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 218e3b5..16e26c5 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -3,3 +3,4 @@
 #
 obj-$(CONFIG_CORESIGHT) += coresight.o
 obj-$(CONFIG_OF) += of_coresight.o
+obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
new file mode 100644
index 0000000..c1b7d31
--- /dev/null
+++ b/drivers/coresight/coresight-tmc.c
@@ -0,0 +1,794 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define tmc_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
+#define tmc_readl(drvdata, off)		__raw_readl(drvdata->base + off)
+
+#define TMC_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	tmc_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define TMC_UNLOCK(drvdata)						\
+do {									\
+	tmc_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
+#define TMC_RSZ			(0x004)
+#define TMC_STS			(0x00C)
+#define TMC_RRD			(0x010)
+#define TMC_RRP			(0x014)
+#define TMC_RWP			(0x018)
+#define TMC_TRG			(0x01C)
+#define TMC_CTL			(0x020)
+#define TMC_RWD			(0x024)
+#define TMC_MODE		(0x028)
+#define TMC_LBUFLEVEL		(0x02C)
+#define TMC_CBUFLEVEL		(0x030)
+#define TMC_BUFWM		(0x034)
+#define TMC_RRPHI		(0x038)
+#define TMC_RWPHI		(0x03C)
+#define TMC_AXICTL		(0x110)
+#define TMC_DBALO		(0x118)
+#define TMC_DBAHI		(0x11C)
+#define TMC_FFSR		(0x300)
+#define TMC_FFCR		(0x304)
+#define TMC_PSCR		(0x308)
+#define TMC_ITMISCOP0		(0xEE0)
+#define TMC_ITTRFLIN		(0xEE8)
+#define TMC_ITATBDATA0		(0xEEC)
+#define TMC_ITATBCTR2		(0xEF0)
+#define TMC_ITATBCTR1		(0xEF4)
+#define TMC_ITATBCTR0		(0xEF8)
+
+#define BYTES_PER_WORD		4
+
+enum tmc_config_type {
+	TMC_CONFIG_TYPE_ETB,
+	TMC_CONFIG_TYPE_ETR,
+	TMC_CONFIG_TYPE_ETF,
+};
+
+enum tmc_mode {
+	TMC_MODE_CIRCULAR_BUFFER,
+	TMC_MODE_SOFTWARE_FIFO,
+	TMC_MODE_HARDWARE_FIFO,
+};
+
+enum tmc_mem_intf_width {
+	TMC_MEM_INTF_WIDTH_32BITS	= 0x2,
+	TMC_MEM_INTF_WIDTH_64BITS	= 0x3,
+	TMC_MEM_INTF_WIDTH_128BITS	= 0x4,
+	TMC_MEM_INTF_WIDTH_256BITS	= 0x5,
+};
+
+struct tmc_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct miscdevice	miscdev;
+	struct clk		*clk;
+	spinlock_t		spinlock;
+	int			read_count;
+	bool			reading;
+	char			*buf;
+	dma_addr_t		paddr;
+	void __iomem		*vaddr;
+	uint32_t		size;
+	bool			enable;
+	enum tmc_config_type	config_type;
+	uint32_t		trigger_cntr;
+};
+
+static void tmc_wait_for_ready(struct tmc_drvdata *drvdata)
+{
+	int count;
+
+	/* Ensure formatter, unformatter and hardware fifo are empty */
+	for (count = TIMEOUT_US; BVAL(tmc_readl(drvdata, TMC_STS), 2) != 1
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while waiting for TMC ready, TMC_STS: %#x\n",
+	     tmc_readl(drvdata, TMC_STS));
+}
+
+static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
+{
+	int count;
+	uint32_t ffcr;
+
+	ffcr = tmc_readl(drvdata, TMC_FFCR);
+	ffcr |= BIT(12);
+	tmc_writel(drvdata, ffcr, TMC_FFCR);
+	ffcr |= BIT(6);
+	tmc_writel(drvdata, ffcr, TMC_FFCR);
+	/* Ensure flush completes */
+	for (count = TIMEOUT_US; BVAL(tmc_readl(drvdata, TMC_FFCR), 6) != 0
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while flushing TMC, TMC_FFCR: %#x\n",
+	     tmc_readl(drvdata, TMC_FFCR));
+
+	tmc_wait_for_ready(drvdata);
+}
+
+static void __tmc_enable(struct tmc_drvdata *drvdata)
+{
+	tmc_writel(drvdata, 0x1, TMC_CTL);
+}
+
+static void __tmc_disable(struct tmc_drvdata *drvdata)
+{
+	tmc_writel(drvdata, 0x0, TMC_CTL);
+}
+
+static void __tmc_etb_enable(struct tmc_drvdata *drvdata)
+{
+	/* Zero out the memory to help with debug */
+	memset(drvdata->buf, 0, drvdata->size);
+
+	TMC_UNLOCK(drvdata);
+
+	tmc_writel(drvdata, TMC_MODE_CIRCULAR_BUFFER, TMC_MODE);
+	tmc_writel(drvdata, 0x133, TMC_FFCR);
+	tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
+	__tmc_enable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void __tmc_etr_enable(struct tmc_drvdata *drvdata)
+{
+	uint32_t axictl;
+
+	/* Zero out the memory to help with debug */
+	memset(drvdata->vaddr, 0, drvdata->size);
+
+	TMC_UNLOCK(drvdata);
+
+	tmc_writel(drvdata, drvdata->size / BYTES_PER_WORD, TMC_RSZ);
+	tmc_writel(drvdata, TMC_MODE_CIRCULAR_BUFFER, TMC_MODE);
+
+	axictl = tmc_readl(drvdata, TMC_AXICTL);
+	axictl |= (0xF << 8);
+	tmc_writel(drvdata, axictl, TMC_AXICTL);
+	axictl &= ~(0x1 << 7);
+	tmc_writel(drvdata, axictl, TMC_AXICTL);
+	axictl = (axictl & ~0x3) | 0x2;
+	tmc_writel(drvdata, axictl, TMC_AXICTL);
+
+	tmc_writel(drvdata, drvdata->paddr, TMC_DBALO);
+	tmc_writel(drvdata, 0x0, TMC_DBAHI);
+	tmc_writel(drvdata, 0x133, TMC_FFCR);
+	tmc_writel(drvdata, drvdata->trigger_cntr, TMC_TRG);
+	__tmc_enable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void __tmc_etf_enable(struct tmc_drvdata *drvdata)
+{
+	TMC_UNLOCK(drvdata);
+
+	tmc_writel(drvdata, TMC_MODE_HARDWARE_FIFO, TMC_MODE);
+	tmc_writel(drvdata, 0x3, TMC_FFCR);
+	tmc_writel(drvdata, 0x0, TMC_BUFWM);
+	__tmc_enable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
+{
+	int ret;
+	unsigned long flags;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		clk_disable_unprepare(drvdata->clk);
+		return -EBUSY;
+	}
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_enable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_enable(drvdata);
+	} else {
+		if (mode == TMC_MODE_CIRCULAR_BUFFER)
+			__tmc_etb_enable(drvdata);
+		else
+			__tmc_etf_enable(drvdata);
+	}
+	drvdata->enable = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC enabled\n");
+	return 0;
+}
+
+static int tmc_enable_sink(struct coresight_device *csdev)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	return tmc_enable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
+}
+
+static int tmc_enable_link(struct coresight_device *csdev, int inport,
+			   int outport)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO);
+}
+
+static void __tmc_etb_dump(struct tmc_drvdata *drvdata)
+{
+	enum tmc_mem_intf_width memwidth;
+	uint8_t memwords;
+	char *bufp;
+	uint32_t read_data;
+	int i;
+
+	memwidth = BMVAL(tmc_readl(drvdata, CORESIGHT_DEVID), 8, 10);
+	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
+		memwords = 1;
+	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
+		memwords = 2;
+	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
+		memwords = 4;
+	else
+		memwords = 8;
+
+	bufp = drvdata->buf;
+	while (1) {
+		for (i = 0; i < memwords; i++) {
+			read_data = tmc_readl(drvdata, TMC_RRD);
+			if (read_data == 0xFFFFFFFF)
+				return;
+			memcpy(bufp, &read_data, BYTES_PER_WORD);
+			bufp += BYTES_PER_WORD;
+		}
+	}
+}
+
+static void __tmc_etb_disable(struct tmc_drvdata *drvdata)
+{
+	TMC_UNLOCK(drvdata);
+
+	tmc_flush_and_stop(drvdata);
+	__tmc_etb_dump(drvdata);
+	__tmc_disable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void __tmc_etr_dump(struct tmc_drvdata *drvdata)
+{
+	uint32_t rwp, rwphi;
+
+	rwp = tmc_readl(drvdata, TMC_RWP);
+	rwphi = tmc_readl(drvdata, TMC_RWPHI);
+
+	if (BVAL(tmc_readl(drvdata, TMC_STS), 0))
+		drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
+	else
+		drvdata->buf = drvdata->vaddr;
+}
+
+static void __tmc_etr_disable(struct tmc_drvdata *drvdata)
+{
+	TMC_UNLOCK(drvdata);
+
+	tmc_flush_and_stop(drvdata);
+	__tmc_etr_dump(drvdata);
+	__tmc_disable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void __tmc_etf_disable(struct tmc_drvdata *drvdata)
+{
+	TMC_UNLOCK(drvdata);
+
+	tmc_flush_and_stop(drvdata);
+	__tmc_disable(drvdata);
+
+	TMC_LOCK(drvdata);
+}
+
+static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading)
+		goto out;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_disable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_disable(drvdata);
+	} else {
+		if (mode == TMC_MODE_CIRCULAR_BUFFER)
+			__tmc_etb_disable(drvdata);
+		else
+			__tmc_etf_disable(drvdata);
+	}
+out:
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "TMC disabled\n");
+}
+
+static void tmc_disable_sink(struct coresight_device *csdev)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	tmc_disable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
+}
+
+static void tmc_disable_link(struct coresight_device *csdev, int inport,
+			     int outport)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	tmc_disable(drvdata, TMC_MODE_HARDWARE_FIFO);
+}
+
+static void tmc_abort(struct coresight_device *csdev)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+	enum tmc_mode mode;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->reading)
+		goto out0;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_disable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_disable(drvdata);
+	} else {
+		mode = tmc_readl(drvdata, TMC_MODE);
+		if (mode == TMC_MODE_CIRCULAR_BUFFER)
+			__tmc_etb_disable(drvdata);
+		else
+			goto out1;
+	}
+out0:
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC aborted\n");
+	return;
+out1:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+}
+
+static const struct coresight_ops_sink tmc_sink_ops = {
+	.enable		= tmc_enable_sink,
+	.disable	= tmc_disable_sink,
+	.abort		= tmc_abort,
+};
+
+static const struct coresight_ops_link tmc_link_ops = {
+	.enable		= tmc_enable_link,
+	.disable	= tmc_disable_link,
+};
+
+static const struct coresight_ops tmc_etb_cs_ops = {
+	.sink_ops	= &tmc_sink_ops,
+};
+
+static const struct coresight_ops tmc_etr_cs_ops = {
+	.sink_ops	= &tmc_sink_ops,
+};
+
+static const struct coresight_ops tmc_etf_cs_ops = {
+	.sink_ops	= &tmc_sink_ops,
+	.link_ops	= &tmc_link_ops,
+};
+
+static int tmc_read_prepare(struct tmc_drvdata *drvdata)
+{
+	int ret;
+	unsigned long flags;
+	enum tmc_mode mode;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (!drvdata->enable)
+		goto out;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_disable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_disable(drvdata);
+	} else {
+		mode = tmc_readl(drvdata, TMC_MODE);
+		if (mode == TMC_MODE_CIRCULAR_BUFFER) {
+			__tmc_etb_disable(drvdata);
+		} else {
+			ret = -ENODEV;
+			goto err;
+		}
+	}
+out:
+	drvdata->reading = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC read start\n");
+	return 0;
+err:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	return ret;
+}
+
+static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
+{
+	unsigned long flags;
+	enum tmc_mode mode;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (!drvdata->enable)
+		goto out;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		__tmc_etb_enable(drvdata);
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		__tmc_etr_enable(drvdata);
+	} else {
+		mode = tmc_readl(drvdata, TMC_MODE);
+		if (mode == TMC_MODE_CIRCULAR_BUFFER)
+			__tmc_etb_enable(drvdata);
+	}
+out:
+	drvdata->reading = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "TMC read end\n");
+}
+
+static int tmc_open(struct inode *inode, struct file *file)
+{
+	struct tmc_drvdata *drvdata = container_of(file->private_data,
+						   struct tmc_drvdata, miscdev);
+	int ret = 0;
+
+	if (drvdata->read_count++)
+		goto out;
+
+	ret = tmc_read_prepare(drvdata);
+	if (ret)
+		return ret;
+out:
+	nonseekable_open(inode, file);
+
+	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+	return 0;
+}
+
+static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
+			loff_t *ppos)
+{
+	struct tmc_drvdata *drvdata = container_of(file->private_data,
+						   struct tmc_drvdata, miscdev);
+	char *bufp = drvdata->buf + *ppos;
+
+	if (*ppos + len > drvdata->size)
+		len = drvdata->size - *ppos;
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		if (bufp == (char *)(drvdata->vaddr + drvdata->size))
+			bufp = drvdata->vaddr;
+		else if (bufp > (char *)(drvdata->vaddr + drvdata->size))
+			bufp -= drvdata->size;
+		if ((bufp + len) > (char *)(drvdata->vaddr + drvdata->size))
+			len = (char *)(drvdata->vaddr + drvdata->size) - bufp;
+	}
+
+	if (copy_to_user(data, bufp, len)) {
+		dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+		return -EFAULT;
+	}
+
+	*ppos += len;
+
+	dev_dbg(drvdata->dev, "%s: %d bytes copied, %d bytes left\n",
+		__func__, len, (int) (drvdata->size - *ppos));
+	return len;
+}
+
+static int tmc_release(struct inode *inode, struct file *file)
+{
+	struct tmc_drvdata *drvdata = container_of(file->private_data,
+						   struct tmc_drvdata, miscdev);
+
+	if (--drvdata->read_count) {
+		if (drvdata->read_count < 0) {
+			WARN_ONCE(1, "mismatched close\n");
+			drvdata->read_count = 0;
+		}
+		goto out;
+	}
+
+	tmc_read_unprepare(drvdata);
+out:
+	dev_dbg(drvdata->dev, "%s: released\n", __func__);
+	return 0;
+}
+
+static const struct file_operations tmc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= tmc_open,
+	.read		= tmc_read,
+	.release	= tmc_release,
+	.llseek		= no_llseek,
+};
+
+static ssize_t tmc_show_trigger_cntr(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->trigger_cntr;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t tmc_store_trigger_cntr(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->trigger_cntr = val;
+	return size;
+}
+static DEVICE_ATTR(trigger_cntr, S_IRUGO | S_IWUSR, tmc_show_trigger_cntr,
+		   tmc_store_trigger_cntr);
+
+static struct attribute *tmc_attrs[] = {
+	&dev_attr_trigger_cntr.attr,
+	NULL,
+};
+
+static struct attribute_group tmc_attr_grp = {
+	.attrs = tmc_attrs,
+};
+
+static const struct attribute_group *tmc_etb_attr_grps[] = {
+	&tmc_attr_grp,
+	NULL,
+};
+
+static const struct attribute_group *tmc_etr_attr_grps[] = {
+	&tmc_attr_grp,
+	NULL,
+};
+
+static const struct attribute_group *tmc_etf_attr_grps[] = {
+	&tmc_attr_grp,
+	NULL,
+};
+
+static int __devinit tmc_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	uint32_t devid;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct tmc_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	spin_lock_init(&drvdata->spinlock);
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	devid = tmc_readl(drvdata, CORESIGHT_DEVID);
+	drvdata->config_type = BMVAL(devid, 6, 7);
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		if (pdev->dev.of_node)
+			ret = of_property_read_u32(pdev->dev.of_node,
+				"arm,buffer-size", &drvdata->size);
+		if (ret)
+			drvdata->size = SZ_1M;
+	} else {
+		drvdata->size = tmc_readl(drvdata, TMC_RSZ) * BYTES_PER_WORD;
+	}
+
+	clk_disable_unprepare(drvdata->clk);
+
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		drvdata->vaddr = dma_alloc_coherent(dev, drvdata->size,
+						&drvdata->paddr, GFP_KERNEL);
+		if (!drvdata->vaddr)
+			return -ENOMEM;
+		memset(drvdata->vaddr, 0, drvdata->size);
+		drvdata->buf = drvdata->vaddr;
+	} else {
+		drvdata->buf = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
+		if (!drvdata->buf)
+			return -ENOMEM;
+	}
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc) {
+		ret = -ENOMEM;
+		goto err0;
+	}
+	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
+		desc->type = CORESIGHT_DEV_TYPE_SINK;
+		desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+		desc->ops = &tmc_etb_cs_ops;
+		desc->pdata = pdev->dev.platform_data;
+		desc->dev = &pdev->dev;
+		desc->groups = tmc_etb_attr_grps;
+		desc->owner = THIS_MODULE;
+		drvdata->csdev = coresight_register(desc);
+		if (IS_ERR(drvdata->csdev)) {
+			ret = PTR_ERR(drvdata->csdev);
+			goto err0;
+		}
+	} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
+		desc->type = CORESIGHT_DEV_TYPE_SINK;
+		desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+		desc->ops = &tmc_etr_cs_ops;
+		desc->pdata = pdev->dev.platform_data;
+		desc->dev = &pdev->dev;
+		desc->groups = tmc_etr_attr_grps;
+		desc->owner = THIS_MODULE;
+		drvdata->csdev = coresight_register(desc);
+		if (IS_ERR(drvdata->csdev)) {
+			ret = PTR_ERR(drvdata->csdev);
+			goto err0;
+		}
+	} else {
+		desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
+		desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+		desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
+		desc->ops = &tmc_etf_cs_ops;
+		desc->pdata = pdev->dev.platform_data;
+		desc->dev = &pdev->dev;
+		desc->groups = tmc_etf_attr_grps;
+		desc->owner = THIS_MODULE;
+		drvdata->csdev = coresight_register(desc);
+		if (IS_ERR(drvdata->csdev)) {
+			ret = PTR_ERR(drvdata->csdev);
+			goto err0;
+		}
+	}
+
+	drvdata->miscdev.name = ((struct coresight_platform_data *)
+				 (pdev->dev.platform_data))->name;
+	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+	drvdata->miscdev.fops = &tmc_fops;
+	ret = misc_register(&drvdata->miscdev);
+	if (ret)
+		goto err1;
+
+	dev_info(dev, "TMC initialized\n");
+	return 0;
+err1:
+	coresight_unregister(drvdata->csdev);
+err0:
+	dma_free_coherent(dev, drvdata->size, &drvdata->paddr, GFP_KERNEL);
+	return ret;
+}
+
+static int __devexit tmc_remove(struct platform_device *pdev)
+{
+	struct tmc_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	misc_deregister(&drvdata->miscdev);
+	coresight_unregister(drvdata->csdev);
+	dma_free_coherent(drvdata->dev, drvdata->size, &drvdata->paddr,
+			  GFP_KERNEL);
+	return 0;
+}
+
+static struct of_device_id tmc_match[] = {
+	{.compatible = "arm,coresight-tmc"},
+	{}
+};
+
+static struct platform_driver tmc_driver = {
+	.probe          = tmc_probe,
+	.remove         = __devexit_p(tmc_remove),
+	.driver         = {
+		.name   = "coresight-tmc",
+		.owner	= THIS_MODULE,
+		.of_match_table = tmc_match,
+	},
+};
+
+static int __init tmc_init(void)
+{
+	return platform_driver_register(&tmc_driver);
+}
+module_init(tmc_init);
+
+static void __exit tmc_exit(void)
+{
+	platform_driver_unregister(&tmc_driver);
+}
+module_exit(tmc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Trace Memory Controller driver");
-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC 3/8] coresight: add CoreSight TPIU driver
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
  2012-12-18 19:19 ` [RFC 1/8] coresight: add CoreSight core layer framework pratikp at codeaurora.org
  2012-12-18 19:19 ` [RFC 2/8] coresight: add CoreSight TMC driver pratikp at codeaurora.org
@ 2012-12-18 19:19 ` pratikp at codeaurora.org
  2012-12-18 19:19 ` [RFC 4/8] coresight: add CoreSight ETB driver pratikp at codeaurora.org
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 32+ messages in thread
From: pratikp at codeaurora.org @ 2012-12-18 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Pratik Patel <pratikp@codeaurora.org>

This driver manages CoreSight TPIU (Trace Port Interface Unit)
which acts as a sink. TPIU is typically connected to some offchip
hardware hosting a storage buffer.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
---
 drivers/coresight/Makefile         |    2 +-
 drivers/coresight/coresight-tpiu.c |  232 ++++++++++++++++++++++++++++++++++++
 2 files changed, 233 insertions(+), 1 deletions(-)
 create mode 100644 drivers/coresight/coresight-tpiu.c

diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 16e26c5..540df99 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CORESIGHT) += coresight.o
 obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o
+obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
new file mode 100644
index 0000000..e21b05f
--- /dev/null
+++ b/drivers/coresight/coresight-tpiu.c
@@ -0,0 +1,232 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define tpiu_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
+#define tpiu_readl(drvdata, off)	__raw_readl(drvdata->base + off)
+
+#define TPIU_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	tpiu_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define TPIU_UNLOCK(drvdata)						\
+do {									\
+	tpiu_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
+#define TPIU_SUPP_PORTSZ	(0x000)
+#define TPIU_CURR_PORTSZ	(0x004)
+#define TPIU_SUPP_TRIGMODES	(0x100)
+#define TPIU_TRIG_CNTRVAL	(0x104)
+#define TPIU_TRIG_MULT		(0x108)
+#define TPIU_SUPP_TESTPATM	(0x200)
+#define TPIU_CURR_TESTPATM	(0x204)
+#define TPIU_TEST_PATREPCNTR	(0x208)
+#define TPIU_FFSR		(0x300)
+#define TPIU_FFCR		(0x304)
+#define TPIU_FSYNC_CNTR		(0x308)
+#define TPIU_EXTCTL_INPORT	(0x400)
+#define TPIU_EXTCTL_OUTPORT	(0x404)
+#define TPIU_ITTRFLINACK	(0xEE4)
+#define TPIU_ITTRFLIN		(0xEE8)
+#define TPIU_ITATBDATA0		(0xEEC)
+#define TPIU_ITATBCTR2		(0xEF0)
+#define TPIU_ITATBCTR1		(0xEF4)
+#define TPIU_ITATBCTR0		(0xEF8)
+
+struct tpiu_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct clk		*clk;
+};
+
+static void __tpiu_enable(struct tpiu_drvdata *drvdata)
+{
+	TPIU_UNLOCK(drvdata);
+
+	/* TODO: fill this up */
+
+	TPIU_LOCK(drvdata);
+}
+
+static int tpiu_enable(struct coresight_device *csdev)
+{
+	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	__tpiu_enable(drvdata);
+
+	dev_info(drvdata->dev, "TPIU enabled\n");
+	return 0;
+}
+
+static void __tpiu_disable(struct tpiu_drvdata *drvdata)
+{
+	TPIU_UNLOCK(drvdata);
+
+	tpiu_writel(drvdata, 0x3000, TPIU_FFCR);
+	tpiu_writel(drvdata, 0x3040, TPIU_FFCR);
+
+	TPIU_LOCK(drvdata);
+}
+
+static void tpiu_disable(struct coresight_device *csdev)
+{
+	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	__tpiu_disable(drvdata);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "TPIU disabled\n");
+}
+
+static void tpiu_abort(struct coresight_device *csdev)
+{
+	struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	__tpiu_disable(drvdata);
+
+	dev_info(drvdata->dev, "TPIU aborted\n");
+}
+
+static const struct coresight_ops_sink tpiu_sink_ops = {
+	.enable		= tpiu_enable,
+	.disable	= tpiu_disable,
+	.abort		= tpiu_abort,
+};
+
+static const struct coresight_ops tpiu_cs_ops = {
+	.sink_ops	= &tpiu_sink_ops,
+};
+
+static int __devinit tpiu_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct tpiu_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	/* Disable tpiu to support older devices */
+	__tpiu_disable(drvdata);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_SINK;
+	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
+	desc->ops = &tpiu_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "TPIU initialized\n");
+	return 0;
+}
+
+static int __devexit tpiu_remove(struct platform_device *pdev)
+{
+	struct tpiu_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id tpiu_match[] = {
+	{.compatible = "arm,coresight-tpiu"},
+	{}
+};
+
+static struct platform_driver tpiu_driver = {
+	.probe          = tpiu_probe,
+	.remove         = __devexit_p(tpiu_remove),
+	.driver         = {
+		.name   = "coresight-tpiu",
+		.owner	= THIS_MODULE,
+		.of_match_table = tpiu_match,
+	},
+};
+
+static int __init tpiu_init(void)
+{
+	return platform_driver_register(&tpiu_driver);
+}
+module_init(tpiu_init);
+
+static void __exit tpiu_exit(void)
+{
+	platform_driver_unregister(&tpiu_driver);
+}
+module_exit(tpiu_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");
-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC 4/8] coresight: add CoreSight ETB driver
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
                   ` (2 preceding siblings ...)
  2012-12-18 19:19 ` [RFC 3/8] coresight: add CoreSight TPIU driver pratikp at codeaurora.org
@ 2012-12-18 19:19 ` pratikp at codeaurora.org
  2012-12-20 17:49   ` Jon Hunter
  2012-12-18 19:19 ` [RFC 5/8] coresight: add CoreSight Funnel driver pratikp at codeaurora.org
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 32+ messages in thread
From: pratikp at codeaurora.org @ 2012-12-18 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Pratik Patel <pratikp@codeaurora.org>

This driver manages CoreSight ETB (Embedded Trace Buffer) which
acts as a circular buffer sink collecting generated trace data.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
---
 drivers/coresight/Makefile        |    2 +-
 drivers/coresight/coresight-etb.c |  467 +++++++++++++++++++++++++++++++++++++
 2 files changed, 468 insertions(+), 1 deletions(-)
 create mode 100644 drivers/coresight/coresight-etb.c

diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 540df99..3c1debc 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CORESIGHT) += coresight.o
 obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o
+obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o coresight-etb.o
diff --git a/drivers/coresight/coresight-etb.c b/drivers/coresight/coresight-etb.c
new file mode 100644
index 0000000..d52ab28
--- /dev/null
+++ b/drivers/coresight/coresight-etb.c
@@ -0,0 +1,467 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define etb_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
+#define etb_readl(drvdata, off)		__raw_readl(drvdata->base + off)
+
+#define ETB_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	etb_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define ETB_UNLOCK(drvdata)						\
+do {									\
+	etb_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
+#define ETB_RAM_DEPTH_REG	(0x004)
+#define ETB_STATUS_REG		(0x00C)
+#define ETB_RAM_READ_DATA_REG	(0x010)
+#define ETB_RAM_READ_POINTER	(0x014)
+#define ETB_RAM_WRITE_POINTER	(0x018)
+#define ETB_TRG			(0x01C)
+#define ETB_CTL_REG		(0x020)
+#define ETB_RWD_REG		(0x024)
+#define ETB_FFSR		(0x300)
+#define ETB_FFCR		(0x304)
+#define ETB_ITMISCOP0		(0xEE0)
+#define ETB_ITTRFLINACK		(0xEE4)
+#define ETB_ITTRFLIN		(0xEE8)
+#define ETB_ITATBDATA0		(0xEEC)
+#define ETB_ITATBCTR2		(0xEF0)
+#define ETB_ITATBCTR1		(0xEF4)
+#define ETB_ITATBCTR0		(0xEF8)
+
+#define BYTES_PER_WORD		4
+#define ETB_SIZE_WORDS		4096
+#define FRAME_SIZE_WORDS	4
+
+struct etb_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct miscdevice	miscdev;
+	struct clk		*clk;
+	spinlock_t		spinlock;
+	bool			reading;
+	atomic_t		in_use;
+	uint8_t			*buf;
+	bool			enable;
+	uint32_t		trigger_cntr;
+};
+
+static void __etb_enable(struct etb_drvdata *drvdata)
+{
+	int i;
+
+	ETB_UNLOCK(drvdata);
+
+	etb_writel(drvdata, 0x0, ETB_RAM_WRITE_POINTER);
+	for (i = 0; i < ETB_SIZE_WORDS; i++)
+		etb_writel(drvdata, 0x0, ETB_RWD_REG);
+
+	etb_writel(drvdata, 0x0, ETB_RAM_WRITE_POINTER);
+	etb_writel(drvdata, 0x0, ETB_RAM_READ_POINTER);
+
+	etb_writel(drvdata, drvdata->trigger_cntr, ETB_TRG);
+	etb_writel(drvdata, BIT(13) | BIT(0), ETB_FFCR);
+	etb_writel(drvdata, BIT(0), ETB_CTL_REG);
+
+	ETB_LOCK(drvdata);
+}
+
+static int etb_enable(struct coresight_device *csdev)
+{
+	struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+	unsigned long flags;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	__etb_enable(drvdata);
+	drvdata->enable = true;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "ETB enabled\n");
+	return 0;
+}
+
+static void __etb_disable(struct etb_drvdata *drvdata)
+{
+	int count;
+	uint32_t ffcr;
+
+	ETB_UNLOCK(drvdata);
+
+	ffcr = etb_readl(drvdata, ETB_FFCR);
+	ffcr |= BIT(12);
+	etb_writel(drvdata, ffcr, ETB_FFCR);
+	ffcr |= BIT(6);
+	etb_writel(drvdata, ffcr, ETB_FFCR);
+	for (count = TIMEOUT_US; BVAL(etb_readl(drvdata, ETB_FFCR), 6) != 0
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while flushing DRVDATA, ETB_FFCR: %#x\n",
+	     etb_readl(drvdata, ETB_FFCR));
+
+	etb_writel(drvdata, 0x0, ETB_CTL_REG);
+	for (count = TIMEOUT_US; BVAL(etb_readl(drvdata, ETB_FFSR), 1) != 1
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while disabling DRVDATA, ETB_FFSR: %#x\n",
+	     etb_readl(drvdata, ETB_FFSR));
+
+	ETB_LOCK(drvdata);
+}
+
+static void __etb_dump(struct etb_drvdata *drvdata)
+{
+	int i;
+	uint8_t *buf_ptr;
+	uint32_t read_data;
+	uint32_t read_ptr;
+	uint32_t write_ptr;
+	uint32_t frame_off;
+	uint32_t frame_endoff;
+
+	ETB_UNLOCK(drvdata);
+
+	read_ptr = etb_readl(drvdata, ETB_RAM_READ_POINTER);
+	write_ptr = etb_readl(drvdata, ETB_RAM_WRITE_POINTER);
+
+	frame_off = write_ptr % FRAME_SIZE_WORDS;
+	frame_endoff = FRAME_SIZE_WORDS - frame_off;
+	if (frame_off) {
+		dev_err(drvdata->dev, "write_ptr: %lu not aligned to formatter "
+				"frame size\n", (unsigned long)write_ptr);
+		dev_err(drvdata->dev, "frameoff: %lu, frame_endoff: %lu\n",
+			(unsigned long)frame_off, (unsigned long)frame_endoff);
+		write_ptr += frame_endoff;
+	}
+
+	if ((etb_readl(drvdata, ETB_STATUS_REG) & BIT(0)) == 0)
+		etb_writel(drvdata, 0x0, ETB_RAM_READ_POINTER);
+	else
+		etb_writel(drvdata, write_ptr, ETB_RAM_READ_POINTER);
+
+	buf_ptr = drvdata->buf;
+	for (i = 0; i < ETB_SIZE_WORDS; i++) {
+		read_data = etb_readl(drvdata, ETB_RAM_READ_DATA_REG);
+		*buf_ptr++ = read_data >> 0;
+		*buf_ptr++ = read_data >> 8;
+		*buf_ptr++ = read_data >> 16;
+		*buf_ptr++ = read_data >> 24;
+	}
+
+	if (frame_off) {
+		buf_ptr -= (frame_endoff * BYTES_PER_WORD);
+		for (i = 0; i < frame_endoff; i++) {
+			*buf_ptr++ = 0x0;
+			*buf_ptr++ = 0x0;
+			*buf_ptr++ = 0x0;
+			*buf_ptr++ = 0x0;
+		}
+	}
+
+	etb_writel(drvdata, read_ptr, ETB_RAM_READ_POINTER);
+
+	ETB_LOCK(drvdata);
+}
+
+static void etb_disable(struct coresight_device *csdev)
+{
+	struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	__etb_disable(drvdata);
+	__etb_dump(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "ETB disabled\n");
+}
+
+static void etb_abort(struct coresight_device *csdev)
+{
+	struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	__etb_disable(drvdata);
+	__etb_dump(drvdata);
+	drvdata->enable = false;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "ETB aborted\n");
+}
+
+static const struct coresight_ops_sink etb_sink_ops = {
+	.enable		= etb_enable,
+	.disable	= etb_disable,
+	.abort		= etb_abort,
+};
+
+static const struct coresight_ops etb_cs_ops = {
+	.sink_ops	= &etb_sink_ops,
+};
+
+static void etb_dump(struct etb_drvdata *drvdata)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->enable) {
+		__etb_disable(drvdata);
+		__etb_dump(drvdata);
+		__etb_enable(drvdata);
+	}
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_info(drvdata->dev, "ETB dumped\n");
+}
+
+static int etb_open(struct inode *inode, struct file *file)
+{
+	struct etb_drvdata *drvdata = container_of(file->private_data,
+						   struct etb_drvdata, miscdev);
+
+	if (atomic_cmpxchg(&drvdata->in_use, 0, 1))
+		return -EBUSY;
+
+	dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
+	return 0;
+}
+
+static ssize_t etb_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos)
+{
+	struct etb_drvdata *drvdata = container_of(file->private_data,
+						   struct etb_drvdata, miscdev);
+
+	if (drvdata->reading == false) {
+		etb_dump(drvdata);
+		drvdata->reading = true;
+	}
+
+	if (*ppos + len > ETB_SIZE_WORDS * BYTES_PER_WORD)
+		len = ETB_SIZE_WORDS * BYTES_PER_WORD - *ppos;
+
+	if (copy_to_user(data, drvdata->buf + *ppos, len)) {
+		dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
+		return -EFAULT;
+	}
+
+	*ppos += len;
+
+	dev_dbg(drvdata->dev, "%s: %d bytes copied, %d bytes left\n",
+		__func__, len, (int) (ETB_SIZE_WORDS * BYTES_PER_WORD - *ppos));
+	return len;
+}
+
+static int etb_release(struct inode *inode, struct file *file)
+{
+	struct etb_drvdata *drvdata = container_of(file->private_data,
+						   struct etb_drvdata, miscdev);
+
+	drvdata->reading = false;
+	atomic_set(&drvdata->in_use, 0);
+
+	dev_dbg(drvdata->dev, "%s: released\n", __func__);
+	return 0;
+}
+
+static const struct file_operations etb_fops = {
+	.owner		= THIS_MODULE,
+	.open		= etb_open,
+	.read		= etb_read,
+	.release	= etb_release,
+	.llseek		= no_llseek,
+};
+
+static ssize_t etb_show_trigger_cntr(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->trigger_cntr;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etb_store_trigger_cntr(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->trigger_cntr = val;
+	return size;
+}
+static DEVICE_ATTR(trigger_cntr, S_IRUGO | S_IWUSR, etb_show_trigger_cntr,
+		   etb_store_trigger_cntr);
+
+static struct attribute *etb_attrs[] = {
+	&dev_attr_trigger_cntr.attr,
+	NULL,
+};
+
+static struct attribute_group etb_attr_grp = {
+	.attrs = etb_attrs,
+};
+
+static const struct attribute_group *etb_attr_grps[] = {
+	&etb_attr_grp,
+	NULL,
+};
+
+static int __devinit etb_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct etb_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	spin_lock_init(&drvdata->spinlock);
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	drvdata->buf = devm_kzalloc(dev, ETB_SIZE_WORDS * BYTES_PER_WORD,
+				    GFP_KERNEL);
+	if (!drvdata->buf)
+		return -ENOMEM;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_SINK;
+	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+	desc->ops = &etb_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = etb_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	drvdata->miscdev.name = ((struct coresight_platform_data *)
+				 (pdev->dev.platform_data))->name;
+	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+	drvdata->miscdev.fops = &etb_fops;
+	ret = misc_register(&drvdata->miscdev);
+	if (ret)
+		goto err;
+
+	dev_info(dev, "ETB initialized\n");
+	return 0;
+err:
+	coresight_unregister(drvdata->csdev);
+	return ret;
+}
+
+static int __devexit etb_remove(struct platform_device *pdev)
+{
+	struct etb_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	misc_deregister(&drvdata->miscdev);
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id etb_match[] = {
+	{.compatible = "arm,coresight-etb"},
+	{}
+};
+
+static struct platform_driver etb_driver = {
+	.probe          = etb_probe,
+	.remove         = __devexit_p(etb_remove),
+	.driver         = {
+		.name   = "coresight-etb",
+		.owner	= THIS_MODULE,
+		.of_match_table = etb_match,
+	},
+};
+
+static int __init etb_init(void)
+{
+	return platform_driver_register(&etb_driver);
+}
+module_init(etb_init);
+
+static void __exit etb_exit(void)
+{
+	platform_driver_unregister(&etb_driver);
+}
+module_exit(etb_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");
-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC 5/8] coresight: add CoreSight Funnel driver
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
                   ` (3 preceding siblings ...)
  2012-12-18 19:19 ` [RFC 4/8] coresight: add CoreSight ETB driver pratikp at codeaurora.org
@ 2012-12-18 19:19 ` pratikp at codeaurora.org
  2012-12-18 19:19 ` [RFC 6/8] coresight: add CoreSight Replicator driver pratikp at codeaurora.org
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 32+ messages in thread
From: pratikp at codeaurora.org @ 2012-12-18 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Pratik Patel <pratikp@codeaurora.org>

This driver manages CoreSight Funnel which acts as a link.
Funnels have multiple input ports (typically 8) each of which
represents an input trace data stream. These multiple input trace
data streams are interleaved into a single output stream coming
out of the Funnel.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
---
 drivers/coresight/Makefile           |    2 +-
 drivers/coresight/coresight-funnel.c |  260 ++++++++++++++++++++++++++++++++++
 2 files changed, 261 insertions(+), 1 deletions(-)
 create mode 100644 drivers/coresight/coresight-funnel.c

diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 3c1debc..9f84ad0 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CORESIGHT) += coresight.o
 obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o coresight-etb.o
+obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o
diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c
new file mode 100644
index 0000000..7f39a3e
--- /dev/null
+++ b/drivers/coresight/coresight-funnel.c
@@ -0,0 +1,260 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define funnel_writel(drvdata, val, off)	\
+			__raw_writel((val), drvdata->base + off)
+#define funnel_readl(drvdata, off)		\
+			__raw_readl(drvdata->base + off)
+
+#define FUNNEL_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	funnel_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define FUNNEL_UNLOCK(drvdata)						\
+do {									\
+	funnel_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
+	mb();								\
+} while (0)
+
+#define FUNNEL_FUNCTL		(0x000)
+#define FUNNEL_PRICTL		(0x004)
+#define FUNNEL_ITATBDATA0	(0xEEC)
+#define FUNNEL_ITATBCTR2	(0xEF0)
+#define FUNNEL_ITATBCTR1	(0xEF4)
+#define FUNNEL_ITATBCTR0	(0xEF8)
+
+#define FUNNEL_HOLDTIME_MASK	(0xF00)
+#define FUNNEL_HOLDTIME_SHFT	(0x8)
+#define FUNNEL_HOLDTIME		(0x7 << FUNNEL_HOLDTIME_SHFT)
+
+struct funnel_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct clk		*clk;
+	uint32_t		priority;
+};
+
+static void __funnel_enable(struct funnel_drvdata *drvdata, int port)
+{
+	uint32_t functl;
+
+	FUNNEL_UNLOCK(drvdata);
+
+	functl = funnel_readl(drvdata, FUNNEL_FUNCTL);
+	functl &= ~FUNNEL_HOLDTIME_MASK;
+	functl |= FUNNEL_HOLDTIME;
+	functl |= (1 << port);
+	funnel_writel(drvdata, functl, FUNNEL_FUNCTL);
+	funnel_writel(drvdata, drvdata->priority, FUNNEL_PRICTL);
+
+	FUNNEL_LOCK(drvdata);
+}
+
+static int funnel_enable(struct coresight_device *csdev, int inport,
+			 int outport)
+{
+	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	__funnel_enable(drvdata, inport);
+
+	dev_info(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
+	return 0;
+}
+
+static void __funnel_disable(struct funnel_drvdata *drvdata, int inport)
+{
+	uint32_t functl;
+
+	FUNNEL_UNLOCK(drvdata);
+
+	functl = funnel_readl(drvdata, FUNNEL_FUNCTL);
+	functl &= ~(1 << inport);
+	funnel_writel(drvdata, functl, FUNNEL_FUNCTL);
+
+	FUNNEL_LOCK(drvdata);
+}
+
+static void funnel_disable(struct coresight_device *csdev, int inport,
+			   int outport)
+{
+	struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	__funnel_disable(drvdata, inport);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
+}
+
+static const struct coresight_ops_link funnel_link_ops = {
+	.enable		= funnel_enable,
+	.disable	= funnel_disable,
+};
+
+static const struct coresight_ops funnel_cs_ops = {
+	.link_ops	= &funnel_link_ops,
+};
+
+static ssize_t funnel_show_priority(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->priority;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t funnel_store_priority(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->priority = val;
+	return size;
+}
+static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, funnel_show_priority,
+		   funnel_store_priority);
+
+static struct attribute *funnel_attrs[] = {
+	&dev_attr_priority.attr,
+	NULL,
+};
+
+static struct attribute_group funnel_attr_grp = {
+	.attrs = funnel_attrs,
+};
+
+static const struct attribute_group *funnel_attr_grps[] = {
+	&funnel_attr_grp,
+	NULL,
+};
+
+static int __devinit funnel_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct funnel_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_LINK;
+	desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
+	desc->ops = &funnel_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = funnel_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "FUNNEL initialized\n");
+	return 0;
+}
+
+static int __devexit funnel_remove(struct platform_device *pdev)
+{
+	struct funnel_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id funnel_match[] = {
+	{.compatible = "arm,coresight-funnel"},
+	{}
+};
+
+static struct platform_driver funnel_driver = {
+	.probe          = funnel_probe,
+	.remove         = __devexit_p(funnel_remove),
+	.driver         = {
+		.name   = "coresight-funnel",
+		.owner	= THIS_MODULE,
+		.of_match_table = funnel_match,
+	},
+};
+
+static int __init funnel_init(void)
+{
+	return platform_driver_register(&funnel_driver);
+}
+module_init(funnel_init);
+
+static void __exit funnel_exit(void)
+{
+	platform_driver_unregister(&funnel_driver);
+}
+module_exit(funnel_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Funnel driver");
-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC 6/8] coresight: add CoreSight Replicator driver
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
                   ` (4 preceding siblings ...)
  2012-12-18 19:19 ` [RFC 5/8] coresight: add CoreSight Funnel driver pratikp at codeaurora.org
@ 2012-12-18 19:19 ` pratikp at codeaurora.org
  2012-12-18 19:19 ` [RFC 7/8] coresight: add CoreSight STM driver pratikp at codeaurora.org
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 32+ messages in thread
From: pratikp at codeaurora.org @ 2012-12-18 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Pratik Patel <pratikp@codeaurora.org>

This driver manages CoreSight Replicator that takes single input
trace data stream and replicates it to produce two identical
trace data output streams. Replicators are typically used to
route single interleaved trace data stream to two or more sinks.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
---
 drivers/coresight/Makefile               |    2 +-
 drivers/coresight/coresight-replicator.c |  211 ++++++++++++++++++++++++++++++
 2 files changed, 212 insertions(+), 1 deletions(-)
 create mode 100644 drivers/coresight/coresight-replicator.c

diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 9f84ad0..b385e81 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -3,4 +3,4 @@
 #
 obj-$(CONFIG_CORESIGHT) += coresight.o
 obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o
+obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
new file mode 100644
index 0000000..fe37e5e
--- /dev/null
+++ b/drivers/coresight/coresight-replicator.c
@@ -0,0 +1,211 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+#define replicator_writel(drvdata, val, off)	\
+				__raw_writel((val), drvdata->base + off)
+#define replicator_readl(drvdata, off)		\
+				__raw_readl(drvdata->base + off)
+
+#define REPLICATOR_LOCK(drvdata)					\
+do {									\
+	mb();								\
+	replicator_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define REPLICATOR_UNLOCK(drvdata)					\
+do {									\
+	replicator_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
+	mb();								\
+} while (0)
+
+#define REPLICATOR_IDFILTER0		(0x000)
+#define REPLICATOR_IDFILTER1		(0x004)
+#define REPLICATOR_ITATBCTR0		(0xEFC)
+#define REPLICATOR_ITATBCTR1		(0xEF8)
+
+struct replicator_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct clk		*clk;
+};
+
+static void __replicator_enable(struct replicator_drvdata *drvdata, int outport)
+{
+	REPLICATOR_UNLOCK(drvdata);
+
+	if (outport == 0) {
+		replicator_writel(drvdata, 0x0, REPLICATOR_IDFILTER0);
+		replicator_writel(drvdata, 0xFF, REPLICATOR_IDFILTER1);
+	} else {
+		replicator_writel(drvdata, 0x0, REPLICATOR_IDFILTER1);
+		replicator_writel(drvdata, 0xFF, REPLICATOR_IDFILTER0);
+	}
+
+	REPLICATOR_LOCK(drvdata);
+}
+
+static int replicator_enable(struct coresight_device *csdev, int inport,
+			     int outport)
+{
+	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	__replicator_enable(drvdata, outport);
+
+	dev_info(drvdata->dev, "REPLICATOR enabled\n");
+	return 0;
+}
+
+static void __replicator_disable(struct replicator_drvdata *drvdata,
+				 int outport)
+{
+	REPLICATOR_UNLOCK(drvdata);
+
+	if (outport == 0)
+		replicator_writel(drvdata, 0xFF, REPLICATOR_IDFILTER0);
+	else
+		replicator_writel(drvdata, 0xFF, REPLICATOR_IDFILTER1);
+
+	REPLICATOR_LOCK(drvdata);
+}
+
+static void replicator_disable(struct coresight_device *csdev, int inport,
+			       int outport)
+{
+	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	__replicator_disable(drvdata, outport);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "REPLICATOR disabled\n");
+}
+
+static const struct coresight_ops_link replicator_link_ops = {
+	.enable		= replicator_enable,
+	.disable	= replicator_disable,
+};
+
+static const struct coresight_ops replicator_cs_ops = {
+	.link_ops	= &replicator_link_ops,
+};
+
+static int __devinit replicator_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct replicator_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_LINK;
+	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
+	desc->ops = &replicator_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	dev_info(dev, "REPLICATOR initialized\n");
+	return 0;
+}
+
+static int __devexit replicator_remove(struct platform_device *pdev)
+{
+	struct replicator_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id replicator_match[] = {
+	{.compatible = "qcom,coresight-replicator"},
+	{}
+};
+
+static struct platform_driver replicator_driver = {
+	.probe          = replicator_probe,
+	.remove         = __devexit_p(replicator_remove),
+	.driver         = {
+		.name   = "coresight-replicator",
+		.owner	= THIS_MODULE,
+		.of_match_table = replicator_match,
+	},
+};
+
+static int __init replicator_init(void)
+{
+	return platform_driver_register(&replicator_driver);
+}
+module_init(replicator_init);
+
+static void __exit replicator_exit(void)
+{
+	platform_driver_unregister(&replicator_driver);
+}
+module_exit(replicator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Replicator driver");
-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC 7/8] coresight: add CoreSight STM driver
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
                   ` (5 preceding siblings ...)
  2012-12-18 19:19 ` [RFC 6/8] coresight: add CoreSight Replicator driver pratikp at codeaurora.org
@ 2012-12-18 19:19 ` pratikp at codeaurora.org
  2012-12-18 19:19 ` [RFC 8/8] coresight: add CoreSight ETM driver pratikp at codeaurora.org
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 32+ messages in thread
From: pratikp at codeaurora.org @ 2012-12-18 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Pratik Patel <pratikp@codeaurora.org>

This driver manages CoreSight STM (System Trace Macrocell) and
provides apis and user interface to support software
instrumentation based tracing that takes advantage of the STM
hardware.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
---
 drivers/coresight/Kconfig         |   19 +
 drivers/coresight/Makefile        |    1 +
 drivers/coresight/coresight-stm.c |  819 +++++++++++++++++++++++++++++++++++++
 include/linux/coresight-stm.h     |   51 +++
 4 files changed, 890 insertions(+), 0 deletions(-)
 create mode 100644 drivers/coresight/coresight-stm.c
 create mode 100644 include/linux/coresight-stm.h

diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 6905ef2..5a715e8 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -17,4 +17,23 @@ config CORESIGHT_LINKS_AND_SINKS
 	  responsible for transporting and collecting the trace data
 	  respectively.
 
+config CORESIGHT_SOURCE_STM
+	bool "CoreSight System Trace Macrocell driver"
+	select CORESIGHT_LINKS_AND_SINKS
+	help
+	  This driver provides support for hardware assisted software
+	  instrumentation based tracing. This is primarily useful for
+	  logging useful software events or data.
+
+config CORESIGHT_SOURCE_STM_DEFAULT_ENABLE
+	bool "Turn on CoreSight STM tracing by default"
+	depends on CORESIGHT_SOURCE_STM
+	help
+	  Turns on CoreSight STM tracing (hardware assisted software
+	  instrumentation based tracing) by default. Otherwise, tracing is
+	  disabled by default but can be enabled via sysfs.
+
+	  If unsure, say 'N' here to avoid potential power, performance and
+	  memory penalty.
+
 endif
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index b385e81..750aa7c 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -4,3 +4,4 @@
 obj-$(CONFIG_CORESIGHT) += coresight.o
 obj-$(CONFIG_OF) += of_coresight.o
 obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o
+obj-$(CONFIG_CORESIGHT_SOURCE_STM) += coresight-stm.o
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
new file mode 100644
index 0000000..69966ed
--- /dev/null
+++ b/drivers/coresight/coresight-stm.c
@@ -0,0 +1,819 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/bitmap.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <linux/coresight-stm.h>
+#include <asm/unaligned.h>
+
+#include "coresight-priv.h"
+
+#define stm_writel(drvdata, val, off)	__raw_writel((val), drvdata->base + off)
+#define stm_readl(drvdata, off)		__raw_readl(drvdata->base + off)
+
+#define STM_LOCK(drvdata)						\
+do {									\
+	mb();								\
+	stm_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define STM_UNLOCK(drvdata)						\
+do {									\
+	stm_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb();								\
+} while (0)
+
+#define STMDMASTARTR			(0xC04)
+#define STMDMASTOPR			(0xC08)
+#define STMDMASTATR			(0xC0C)
+#define STMDMACTLR			(0xC10)
+#define STMDMAIDR			(0xCFC)
+#define STMHEER				(0xD00)
+#define STMHETER			(0xD20)
+#define STMHEMCR			(0xD64)
+#define STMHEMASTR			(0xDF4)
+#define STMHEFEAT1R			(0xDF8)
+#define STMHEIDR			(0xDFC)
+#define STMSPER				(0xE00)
+#define STMSPTER			(0xE20)
+#define STMSPSCR			(0xE60)
+#define STMSPMSCR			(0xE64)
+#define STMSPOVERRIDER			(0xE68)
+#define STMSPMOVERRIDER			(0xE6C)
+#define STMSPTRIGCSR			(0xE70)
+#define STMTCSR				(0xE80)
+#define STMTSSTIMR			(0xE84)
+#define STMTSFREQR			(0xE8C)
+#define STMSYNCR			(0xE90)
+#define STMAUXCR			(0xE94)
+#define STMSPFEAT1R			(0xEA0)
+#define STMSPFEAT2R			(0xEA4)
+#define STMSPFEAT3R			(0xEA8)
+#define STMITTRIGGER			(0xEE8)
+#define STMITATBDATA0			(0xEEC)
+#define STMITATBCTR2			(0xEF0)
+#define STMITATBID			(0xEF4)
+#define STMITATBCTR0			(0xEF8)
+
+#define NR_STM_CHANNEL			(32)
+#define BYTES_PER_CHANNEL		(256)
+#define STM_TRACE_BUF_SIZE		(4096)
+#define STM_USERSPACE_HEADER_SIZE	(8)
+#define STM_USERSPACE_MAGIC1_VAL	(0xf0)
+#define STM_USERSPACE_MAGIC2_VAL	(0xf1)
+
+#define OST_START_TOKEN			(0x30)
+#define OST_VERSION			(0x1)
+
+enum stm_pkt_type {
+	STM_PKT_TYPE_DATA	= 0x98,
+	STM_PKT_TYPE_FLAG	= 0xE8,
+	STM_PKT_TYPE_TRIG	= 0xF8,
+};
+
+enum {
+	STM_OPTION_MARKED	= 0x10,
+};
+
+#define stm_channel_addr(drvdata, ch)	(drvdata->chs.base +	\
+					(ch * BYTES_PER_CHANNEL))
+#define stm_channel_off(type, opts)	(type & ~opts)
+
+#ifdef CONFIG_CORESIGHT_SOURCE_STM_DEFAULT_ENABLE
+static int boot_enable = 1;
+#else
+static int boot_enable;
+#endif
+
+module_param_named(
+	boot_enable, boot_enable, int, S_IRUGO
+);
+
+static int boot_nr_channel;
+
+module_param_named(
+	boot_nr_channel, boot_nr_channel, int, S_IRUGO
+);
+
+struct channel_space {
+	void __iomem		*base;
+	unsigned long		*bitmap;
+};
+
+struct stm_drvdata {
+	void __iomem		*base;
+	struct device		*dev;
+	struct coresight_device	*csdev;
+	struct miscdevice	miscdev;
+	struct clk		*clk;
+	spinlock_t		spinlock;
+	struct channel_space	chs;
+	bool			enable;
+	DECLARE_BITMAP(entities, OST_ENTITY_MAX);
+};
+
+static struct stm_drvdata *stmdrvdata;
+
+static int stm_hwevent_isenable(struct stm_drvdata *drvdata)
+{
+	int ret = 0;
+
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		if (BVAL(stm_readl(drvdata, STMHEMCR), 0))
+			ret = stm_readl(drvdata, STMHEER) == 0 ? 0 : 1;
+	spin_unlock(&drvdata->spinlock);
+
+	return ret;
+}
+
+static void __stm_hwevent_enable(struct stm_drvdata *drvdata)
+{
+	STM_UNLOCK(drvdata);
+
+	/*
+	 * Program STMHETER to ensure TRIGOUTHETE (fed to CTI) is asserted
+	 * for HW events.
+	 */
+	stm_writel(drvdata, 0xFFFFFFFF, STMHETER);
+	stm_writel(drvdata, 0xFFFFFFFF, STMHEER);
+	stm_writel(drvdata, 0x5, STMHEMCR);
+
+	STM_LOCK(drvdata);
+}
+
+static int stm_hwevent_enable(struct stm_drvdata *drvdata)
+{
+	int ret = 0;
+
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		__stm_hwevent_enable(drvdata);
+	else
+		ret = -EINVAL;
+	spin_unlock(&drvdata->spinlock);
+
+	return ret;
+}
+
+static int stm_port_isenable(struct stm_drvdata *drvdata)
+{
+	int ret = 0;
+
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		ret = stm_readl(drvdata, STMSPER) == 0 ? 0 : 1;
+	spin_unlock(&drvdata->spinlock);
+
+	return ret;
+}
+
+static void __stm_port_enable(struct stm_drvdata *drvdata)
+{
+	STM_UNLOCK(drvdata);
+
+	stm_writel(drvdata, 0x10, STMSPTRIGCSR);
+	stm_writel(drvdata, 0xFFFFFFFF, STMSPER);
+
+	STM_LOCK(drvdata);
+}
+
+static int stm_port_enable(struct stm_drvdata *drvdata)
+{
+	int ret = 0;
+
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		__stm_port_enable(drvdata);
+	else
+		ret = -EINVAL;
+	spin_unlock(&drvdata->spinlock);
+
+	return ret;
+}
+
+static void __stm_enable(struct stm_drvdata *drvdata)
+{
+	__stm_hwevent_enable(drvdata);
+	__stm_port_enable(drvdata);
+
+	STM_UNLOCK(drvdata);
+
+	stm_writel(drvdata, 0xFFF, STMSYNCR);
+	/* SYNCEN is read-only and HWTEN is not implemented */
+	stm_writel(drvdata, 0x100003, STMTCSR);
+
+	STM_LOCK(drvdata);
+}
+
+static int stm_enable(struct coresight_device *csdev)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	spin_lock(&drvdata->spinlock);
+	__stm_enable(drvdata);
+	drvdata->enable = true;
+	spin_unlock(&drvdata->spinlock);
+
+	dev_info(drvdata->dev, "STM tracing enabled\n");
+	return 0;
+}
+
+static void __stm_hwevent_disable(struct stm_drvdata *drvdata)
+{
+	STM_UNLOCK(drvdata);
+
+	stm_writel(drvdata, 0x0, STMHEMCR);
+	stm_writel(drvdata, 0x0, STMHEER);
+	stm_writel(drvdata, 0x0, STMHETER);
+
+	STM_LOCK(drvdata);
+}
+
+static void stm_hwevent_disable(struct stm_drvdata *drvdata)
+{
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		__stm_hwevent_disable(drvdata);
+	spin_unlock(&drvdata->spinlock);
+}
+
+static void __stm_port_disable(struct stm_drvdata *drvdata)
+{
+	STM_UNLOCK(drvdata);
+
+	stm_writel(drvdata, 0x0, STMSPER);
+	stm_writel(drvdata, 0x0, STMSPTRIGCSR);
+
+	STM_LOCK(drvdata);
+}
+
+static void stm_port_disable(struct stm_drvdata *drvdata)
+{
+	spin_lock(&drvdata->spinlock);
+	if (drvdata->enable)
+		__stm_port_disable(drvdata);
+	spin_unlock(&drvdata->spinlock);
+}
+
+static void __stm_disable(struct stm_drvdata *drvdata)
+{
+	STM_UNLOCK(drvdata);
+
+	stm_writel(drvdata, 0x100000, STMTCSR);
+
+	STM_LOCK(drvdata);
+
+	__stm_hwevent_disable(drvdata);
+	__stm_port_disable(drvdata);
+}
+
+static void stm_disable(struct coresight_device *csdev)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	spin_lock(&drvdata->spinlock);
+	__stm_disable(drvdata);
+	drvdata->enable = false;
+	spin_unlock(&drvdata->spinlock);
+
+	/* Wait for 100ms so that pending data has been written to HW */
+	msleep(100);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "STM tracing disabled\n");
+}
+
+static const struct coresight_ops_source stm_source_ops = {
+	.enable		= stm_enable,
+	.disable	= stm_disable,
+};
+
+static const struct coresight_ops stm_cs_ops = {
+	.source_ops	= &stm_source_ops,
+};
+
+static uint32_t stm_channel_alloc(uint32_t off)
+{
+	struct stm_drvdata *drvdata = stmdrvdata;
+	uint32_t ch;
+
+	do {
+		ch = find_next_zero_bit(drvdata->chs.bitmap,
+					NR_STM_CHANNEL, off);
+	} while ((ch < NR_STM_CHANNEL) &&
+		 test_and_set_bit(ch, drvdata->chs.bitmap));
+
+	return ch;
+}
+
+static void stm_channel_free(uint32_t ch)
+{
+	struct stm_drvdata *drvdata = stmdrvdata;
+
+	clear_bit(ch, drvdata->chs.bitmap);
+}
+
+static int stm_send(void *addr, const void *data, uint32_t size)
+{
+	uint64_t prepad = 0;
+	uint64_t postpad = 0;
+	char *pad;
+	uint8_t off, endoff;
+	uint32_t len = size;
+
+	/*
+	 * Only 64bit writes are supported. We rely on the compiler to
+	 * generate STRD instruction for the casted 64bit assignments.
+	 */
+
+	off = (unsigned long)data & 0x7;
+
+	if (off) {
+		endoff = 8 - off;
+		pad = (char *)&prepad;
+		pad += off;
+
+		while (endoff && size) {
+			*pad++ = *(char *)data++;
+			endoff--;
+			size--;
+		}
+		*(volatile uint64_t __force *)addr = prepad;
+	}
+
+	/* Now we are 64bit aligned */
+	while (size >= 8) {
+		*(volatile uint64_t __force *)addr = *(uint64_t *)data;
+		data += 8;
+		size -= 8;
+	}
+
+	if (size) {
+		pad = (char *)&postpad;
+
+		while (size) {
+			*pad++ = *(char *)data++;
+			size--;
+		}
+		*(volatile uint64_t __force *)addr = postpad;
+	}
+
+	return roundup(len + off, 8);
+}
+
+static int stm_trace_ost_header(unsigned long ch_addr, uint32_t options,
+				uint8_t entity_id, uint8_t proto_id,
+				const void *payload_data, uint32_t payload_size)
+{
+	void *addr;
+	uint8_t prepad_size;
+	uint64_t header;
+	char *hdr;
+
+	hdr = (char *)&header;
+
+	hdr[0] = OST_START_TOKEN;
+	hdr[1] = OST_VERSION;
+	hdr[2] = entity_id;
+	hdr[3] = proto_id;
+	prepad_size = (unsigned long)payload_data & 0x7;
+	*(uint32_t *)(hdr + 4) = (prepad_size << 24) | payload_size;
+
+	/* For 64bit writes, header is expected to be of the D32M, D32M */
+	options |= STM_OPTION_MARKED;
+	options &= ~STM_OPTION_TIMESTAMPED;
+	addr =  (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
+
+	return stm_send(addr, &header, sizeof(header));
+}
+
+static int stm_trace_data(unsigned long ch_addr, uint32_t options,
+			  const void *data, uint32_t size)
+{
+	void *addr;
+
+	options &= ~STM_OPTION_TIMESTAMPED;
+	addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
+
+	return stm_send(addr, data, size);
+}
+
+static int stm_trace_ost_tail(unsigned long ch_addr, uint32_t options)
+{
+	void *addr;
+	uint64_t tail = 0x0;
+
+	addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_FLAG, options));
+
+	return stm_send(addr, &tail, sizeof(tail));
+}
+
+static inline int __stm_trace(uint32_t options, uint8_t entity_id,
+			      uint8_t proto_id, const void *data, uint32_t size)
+{
+	struct stm_drvdata *drvdata = stmdrvdata;
+	int len = 0;
+	uint32_t ch;
+	unsigned long ch_addr;
+
+	/* Allocate channel and get the channel address */
+	ch = stm_channel_alloc(0);
+	ch_addr = (unsigned long)stm_channel_addr(drvdata, ch);
+
+	/* Send the ost header */
+	len += stm_trace_ost_header(ch_addr, options, entity_id, proto_id, data,
+				    size);
+
+	/* Send the payload data */
+	len += stm_trace_data(ch_addr, options, data, size);
+
+	/* Send the ost tail */
+	len += stm_trace_ost_tail(ch_addr, options);
+
+	/* We are done, free the channel */
+	stm_channel_free(ch);
+
+	return len;
+}
+
+/**
+ * stm_trace - trace the binary or string data through STM
+ * @options: tracing options - guaranteed, timestamped, etc
+ * @entity_id: entity representing the trace data
+ * @proto_id: protocol id to distinguish between different binary formats
+ * @data: pointer to binary or string data buffer
+ * @size: size of data to send
+ *
+ * Packetizes the data as the payload to an OST packet and sends it over STM
+ *
+ * CONTEXT:
+ * Can be called from any context.
+ *
+ * RETURNS:
+ * number of bytes transfered over STM
+ */
+int stm_trace(uint32_t options, uint8_t entity_id, uint8_t proto_id,
+			const void *data, uint32_t size)
+{
+	struct stm_drvdata *drvdata = stmdrvdata;
+
+	/* We don't support sizes more than 24bits (0 to 23) */
+	if (!(drvdata && drvdata->enable &&
+	      test_bit(entity_id, drvdata->entities) && size &&
+	      (size < 0x1000000)))
+		return 0;
+
+	return __stm_trace(options, entity_id, proto_id, data, size);
+}
+EXPORT_SYMBOL_GPL(stm_trace);
+
+static ssize_t stm_write(struct file *file, const char __user *data,
+			 size_t size, loff_t *ppos)
+{
+	struct stm_drvdata *drvdata = container_of(file->private_data,
+						   struct stm_drvdata, miscdev);
+	char *buf;
+	uint8_t entity_id, proto_id;
+	uint32_t options;
+
+	if (!drvdata->enable || !size)
+		return -EINVAL;
+
+	if (size > STM_TRACE_BUF_SIZE)
+		size = STM_TRACE_BUF_SIZE;
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, data, size)) {
+		kfree(buf);
+		dev_dbg(drvdata->dev, "%s: copy_from_user failed\n", __func__);
+		return -EFAULT;
+	}
+
+	if (size >= STM_USERSPACE_HEADER_SIZE &&
+	    buf[0] == STM_USERSPACE_MAGIC1_VAL &&
+	    buf[1] == STM_USERSPACE_MAGIC2_VAL) {
+
+		entity_id = buf[2];
+		proto_id = buf[3];
+		options = *(uint32_t *)(buf + 4);
+
+		if (!test_bit(entity_id, drvdata->entities) ||
+		    !(size - STM_USERSPACE_HEADER_SIZE)) {
+			kfree(buf);
+			return size;
+		}
+
+		__stm_trace(options, entity_id, proto_id,
+			    buf + STM_USERSPACE_HEADER_SIZE,
+			    size - STM_USERSPACE_HEADER_SIZE);
+	} else {
+		if (!test_bit(OST_ENTITY_DEV_NODE, drvdata->entities)) {
+			kfree(buf);
+			return size;
+		}
+
+		__stm_trace(STM_OPTION_TIMESTAMPED, OST_ENTITY_DEV_NODE, 0,
+			    buf, size);
+	}
+
+	kfree(buf);
+
+	return size;
+}
+
+static const struct file_operations stm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= nonseekable_open,
+	.write		= stm_write,
+	.llseek		= no_llseek,
+};
+
+static ssize_t stm_show_hwevent_enable(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = stm_hwevent_isenable(drvdata);
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t stm_store_hwevent_enable(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	int ret = 0;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (val)
+		ret = stm_hwevent_enable(drvdata);
+	else
+		stm_hwevent_disable(drvdata);
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR(hwevent_enable, S_IRUGO | S_IWUSR, stm_show_hwevent_enable,
+		   stm_store_hwevent_enable);
+
+static ssize_t stm_show_port_enable(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = stm_port_isenable(drvdata);
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t stm_store_port_enable(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	int ret = 0;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (val)
+		ret = stm_port_enable(drvdata);
+	else
+		stm_port_disable(drvdata);
+
+	if (ret)
+		return ret;
+	return size;
+}
+static DEVICE_ATTR(port_enable, S_IRUGO | S_IWUSR, stm_show_port_enable,
+		   stm_store_port_enable);
+
+static ssize_t stm_show_entities(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	ssize_t len;
+
+	len = bitmap_scnprintf(buf, PAGE_SIZE, drvdata->entities,
+			       OST_ENTITY_MAX);
+
+	if (PAGE_SIZE - len < 2)
+		len = -EINVAL;
+	else
+		len += scnprintf(buf + len, 2, "\n");
+
+	return len;
+}
+
+static ssize_t stm_store_entities(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val1, val2;
+
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+		return -EINVAL;
+
+	if (val1 >= OST_ENTITY_MAX)
+		return -EINVAL;
+
+	if (val2)
+		__set_bit(val1, drvdata->entities);
+	else
+		__clear_bit(val1, drvdata->entities);
+
+	return size;
+}
+static DEVICE_ATTR(entities, S_IRUGO | S_IWUSR, stm_show_entities,
+		   stm_store_entities);
+
+static struct attribute *stm_attrs[] = {
+	&dev_attr_hwevent_enable.attr,
+	&dev_attr_port_enable.attr,
+	&dev_attr_entities.attr,
+	NULL,
+};
+
+static struct attribute_group stm_attr_grp = {
+	.attrs = stm_attrs,
+};
+
+static const struct attribute_group *stm_attr_grps[] = {
+	&stm_attr_grp,
+	NULL,
+};
+
+static int __devinit stm_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct stm_drvdata *drvdata;
+	struct resource *res;
+	size_t res_size, bitmap_size;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	/* Store the driver data pointer for use in exported functions */
+	stmdrvdata = drvdata;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -ENODEV;
+
+	if (boot_nr_channel) {
+		res_size = min((resource_size_t)(boot_nr_channel *
+				  BYTES_PER_CHANNEL), resource_size(res));
+		bitmap_size = boot_nr_channel * sizeof(long);
+	} else {
+		res_size = min((resource_size_t)(NR_STM_CHANNEL *
+				 BYTES_PER_CHANNEL), resource_size(res));
+		bitmap_size = NR_STM_CHANNEL * sizeof(long);
+	}
+	drvdata->chs.base = devm_ioremap(dev, res->start, res_size);
+	if (!drvdata->chs.base)
+		return -ENOMEM;
+	drvdata->chs.bitmap = devm_kzalloc(dev, bitmap_size, GFP_KERNEL);
+	if (!drvdata->chs.bitmap)
+		return -ENOMEM;
+
+	spin_lock_init(&drvdata->spinlock);
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	bitmap_fill(drvdata->entities, OST_ENTITY_MAX);
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
+	desc->ops = &stm_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = stm_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	drvdata->miscdev.name = ((struct coresight_platform_data *)
+				 (pdev->dev.platform_data))->name;
+	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+	drvdata->miscdev.fops = &stm_fops;
+	ret = misc_register(&drvdata->miscdev);
+	if (ret)
+		goto err;
+
+	dev_info(drvdata->dev, "STM initialized\n");
+
+	if (boot_enable)
+		coresight_enable(drvdata->csdev);
+
+	return 0;
+err:
+	coresight_unregister(drvdata->csdev);
+	return ret;
+}
+
+static int __devexit stm_remove(struct platform_device *pdev)
+{
+	struct stm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	misc_deregister(&drvdata->miscdev);
+	coresight_unregister(drvdata->csdev);
+	return 0;
+}
+
+static struct of_device_id stm_match[] = {
+	{.compatible = "arm,coresight-stm"},
+	{}
+};
+
+static struct platform_driver stm_driver = {
+	.probe          = stm_probe,
+	.remove         = __devexit_p(stm_remove),
+	.driver         = {
+		.name   = "coresight-stm",
+		.owner	= THIS_MODULE,
+		.of_match_table = stm_match,
+	},
+};
+
+static int __init stm_init(void)
+{
+	return platform_driver_register(&stm_driver);
+}
+module_init(stm_init);
+
+static void __exit stm_exit(void)
+{
+	platform_driver_unregister(&stm_driver);
+}
+module_exit(stm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight System Trace Macrocell driver");
diff --git a/include/linux/coresight-stm.h b/include/linux/coresight-stm.h
new file mode 100644
index 0000000..15d6f8c
--- /dev/null
+++ b/include/linux/coresight-stm.h
@@ -0,0 +1,51 @@
+#ifndef _LINUX_CORESIGHT_STM_H
+#define _LINUX_CORESIGHT_STM_H
+
+enum {
+	OST_ENTITY_NONE			= 0x00,
+	OST_ENTITY_FTRACE_EVENTS	= 0x01,
+	OST_ENTITY_TRACE_PRINTK		= 0x02,
+	OST_ENTITY_TRACE_MARKER		= 0x04,
+	OST_ENTITY_DEV_NODE		= 0x08,
+	OST_ENTITY_QVIEW		= 0xFE,
+	OST_ENTITY_MAX			= 0xFF,
+};
+
+enum {
+	STM_OPTION_NONE			= 0x0,
+	STM_OPTION_TIMESTAMPED		= 0x08,
+	STM_OPTION_GUARANTEED		= 0x80,
+};
+
+#ifdef __KERNEL__
+#define stm_log_inv(entity_id, proto_id, data, size)			\
+	stm_trace(STM_OPTION_NONE, entity_id, proto_id, data, size)
+
+#define stm_log_inv_ts(entity_id, proto_id, data, size)			\
+	stm_trace(STM_OPTION_TIMESTAMPED, entity_id, proto_id,		\
+		  data, size)
+
+#define stm_log_gtd(entity_id, proto_id, data, size)			\
+	stm_trace(STM_OPTION_GUARANTEED, entity_id, proto_id,		\
+		  data, size)
+
+#define stm_log_gtd_ts(entity_id, proto_id, data, size)			\
+	stm_trace(STM_OPTION_GUARANTEED | STM_OPTION_TIMESTAMPED,	\
+		  entity_id, proto_id, data, size)
+
+#define stm_log(entity_id, data, size)					\
+	stm_log_inv_ts(entity_id, 0, data, size)
+
+#ifdef CONFIG_CORESIGHT_SOURCE_STM
+extern int stm_trace(uint32_t options, uint8_t entity_id, uint8_t proto_id,
+		     const void *data, uint32_t size);
+#else
+static inline int stm_trace(uint32_t options, uint8_t entity_id,
+			    uint8_t proto_id, const void *data, uint32_t size)
+{
+	return 0;
+}
+#endif
+#endif /* __KERNEL__ */
+
+#endif
-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [RFC 8/8] coresight: add CoreSight ETM driver
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
                   ` (6 preceding siblings ...)
  2012-12-18 19:19 ` [RFC 7/8] coresight: add CoreSight STM driver pratikp at codeaurora.org
@ 2012-12-18 19:19 ` pratikp at codeaurora.org
  2012-12-19 11:23 ` CoreSight framework and drivers Will Deacon
  2013-02-21 14:32 ` Robert MARKLUND
  9 siblings, 0 replies; 32+ messages in thread
From: pratikp at codeaurora.org @ 2012-12-18 19:19 UTC (permalink / raw)
  To: linux-arm-kernel

From: Pratik Patel <pratikp@codeaurora.org>

This driver manages CoreSight ETM (Embedded Trace Macrocell) that
supports processor tracing. Currently it supports ARM PFT
(Program Flow Trace) v1.1 specification but can be extended to
support other ETM or PFT versions.

Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
---
 .../devicetree/bindings/arm/coresight.txt          |    2 +
 arch/arm/include/asm/hardware/cp14.h               |  540 ++++++
 drivers/coresight/Kconfig                          |   21 +
 drivers/coresight/Makefile                         |    1 +
 drivers/coresight/coresight-etm-cp14.c             |  510 ++++++
 drivers/coresight/coresight-etm.c                  | 1752 ++++++++++++++++++++
 6 files changed, 2826 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/hardware/cp14.h
 create mode 100644 drivers/coresight/coresight-etm-cp14.c
 create mode 100644 drivers/coresight/coresight-etm.c

diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index 031f760..e3efbe4 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -32,6 +32,7 @@ Optional properties:
 - coresight-child-ports : list of input port numbers of the children
 - coresight-default-sink : represents the default compile time CoreSight sink
 - arm,buffer-size : size of contiguous buffer space for TMC ETR
+- arm,cp14 : cp14 access to ETM registers is implemented and should be used
 
 Examples:
 
@@ -105,4 +106,5 @@ Examples:
 		coresight-outports = <0>;
 		coresight-child-list = <&funnel_kpss>;
 		coresight-child-ports = <0>;
+		arm,cp14;
 	};
diff --git a/arch/arm/include/asm/hardware/cp14.h b/arch/arm/include/asm/hardware/cp14.h
new file mode 100644
index 0000000..8acf0c7
--- /dev/null
+++ b/arch/arm/include/asm/hardware/cp14.h
@@ -0,0 +1,540 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_HARDWARE_CP14_H
+#define __ASM_HARDWARE_CP14_H
+
+#include <linux/types.h>
+
+/* Accessors for CP14 registers */
+#define dbg_read(reg)			RCP14_##reg()
+#define dbg_write(val, reg)		WCP14_##reg(val)
+#define etm_read(reg)			RCP14_##reg()
+#define etm_write(val, reg)		WCP14_##reg(val)
+
+/* MRC14 and MCR14 */
+#define MRC14(op1, crn, crm, op2)					\
+({									\
+uint32_t val;								\
+asm volatile("mrc p14, "#op1", %0, "#crn", "#crm", "#op2 : "=r" (val));	\
+val;									\
+})
+
+#define MCR14(val, op1, crn, crm, op2)					\
+({									\
+asm volatile("mcr p14, "#op1", %0, "#crn", "#crm", "#op2 : : "r" (val));\
+})
+
+/* Debug Registers
+ *
+ * Available only in DBGv7
+ * DBGECR, DBGDSCCR, DBGDSMCR, DBGDRCR
+ *
+ * Available only in DBGv7.1
+ * DBGBXVRm, DBGOSDLR, DBGDEVID2, DBGDEVID1
+ *
+ * Read only
+ * DBGDIDR, DBGDSCRint, DBGDTRRXint, DBGDRAR, DBGOSLSR, DBGOSSRR, DBGPRSR,
+ * DBGPRSR, DBGDSAR, DBGAUTHSTATUS, DBGDEVID2, DBGDEVID1, DBGDEVID
+ *
+ * Write only
+ * DBGDTRTXint, DBGOSLAR
+ */
+#define RCP14_DBGDIDR()			MRC14(0, c0, c0, 0)
+#define RCP14_DBGDSCRint()		MRC14(0, c0, c1, 0)
+#define RCP14_DBGDTRRXint()		MRC14(0, c0, c5, 0)
+#define RCP14_DBGWFAR()			MRC14(0, c0, c6, 0)
+#define RCP14_DBGVCR()			MRC14(0, c0, c7, 0)
+#define RCP14_DBGECR()			MRC14(0, c0, c9, 0)
+#define RCP14_DBGDSCCR()		MRC14(0, c0, c10, 0)
+#define RCP14_DBGDSMCR()		MRC14(0, c0, c11, 0)
+#define RCP14_DBGDTRRXext()		MRC14(0, c0, c0, 2)
+#define RCP14_DBGDSCRext()		MRC14(0, c0, c2, 2)
+#define RCP14_DBGDTRTXext()		MRC14(0, c0, c3, 2)
+#define RCP14_DBGDRCR()			MRC14(0, c0, c4, 2)
+#define RCP14_DBGBVR0()			MRC14(0, c0, c0, 4)
+#define RCP14_DBGBVR1()			MRC14(0, c0, c1, 4)
+#define RCP14_DBGBVR2()			MRC14(0, c0, c2, 4)
+#define RCP14_DBGBVR3()			MRC14(0, c0, c3, 4)
+#define RCP14_DBGBVR4()			MRC14(0, c0, c4, 4)
+#define RCP14_DBGBVR5()			MRC14(0, c0, c5, 4)
+#define RCP14_DBGBVR6()			MRC14(0, c0, c6, 4)
+#define RCP14_DBGBVR7()			MRC14(0, c0, c7, 4)
+#define RCP14_DBGBVR8()			MRC14(0, c0, c8, 4)
+#define RCP14_DBGBVR9()			MRC14(0, c0, c9, 4)
+#define RCP14_DBGBVR10()		MRC14(0, c0, c10, 4)
+#define RCP14_DBGBVR11()		MRC14(0, c0, c11, 4)
+#define RCP14_DBGBVR12()		MRC14(0, c0, c12, 4)
+#define RCP14_DBGBVR13()		MRC14(0, c0, c13, 4)
+#define RCP14_DBGBVR14()		MRC14(0, c0, c14, 4)
+#define RCP14_DBGBVR15()		MRC14(0, c0, c15, 4)
+#define RCP14_DBGBCR0()			MRC14(0, c0, c0, 5)
+#define RCP14_DBGBCR1()			MRC14(0, c0, c1, 5)
+#define RCP14_DBGBCR2()			MRC14(0, c0, c2, 5)
+#define RCP14_DBGBCR3()			MRC14(0, c0, c3, 5)
+#define RCP14_DBGBCR4()			MRC14(0, c0, c4, 5)
+#define RCP14_DBGBCR5()			MRC14(0, c0, c5, 5)
+#define RCP14_DBGBCR6()			MRC14(0, c0, c6, 5)
+#define RCP14_DBGBCR7()			MRC14(0, c0, c7, 5)
+#define RCP14_DBGBCR8()			MRC14(0, c0, c8, 5)
+#define RCP14_DBGBCR9()			MRC14(0, c0, c9, 5)
+#define RCP14_DBGBCR10()		MRC14(0, c0, c10, 5)
+#define RCP14_DBGBCR11()		MRC14(0, c0, c11, 5)
+#define RCP14_DBGBCR12()		MRC14(0, c0, c12, 5)
+#define RCP14_DBGBCR13()		MRC14(0, c0, c13, 5)
+#define RCP14_DBGBCR14()		MRC14(0, c0, c14, 5)
+#define RCP14_DBGBCR15()		MRC14(0, c0, c15, 5)
+#define RCP14_DBGWVR0()			MRC14(0, c0, c0, 6)
+#define RCP14_DBGWVR1()			MRC14(0, c0, c1, 6)
+#define RCP14_DBGWVR2()			MRC14(0, c0, c2, 6)
+#define RCP14_DBGWVR3()			MRC14(0, c0, c3, 6)
+#define RCP14_DBGWVR4()			MRC14(0, c0, c4, 6)
+#define RCP14_DBGWVR5()			MRC14(0, c0, c5, 6)
+#define RCP14_DBGWVR6()			MRC14(0, c0, c6, 6)
+#define RCP14_DBGWVR7()			MRC14(0, c0, c7, 6)
+#define RCP14_DBGWVR8()			MRC14(0, c0, c8, 6)
+#define RCP14_DBGWVR9()			MRC14(0, c0, c9, 6)
+#define RCP14_DBGWVR10()		MRC14(0, c0, c10, 6)
+#define RCP14_DBGWVR11()		MRC14(0, c0, c11, 6)
+#define RCP14_DBGWVR12()		MRC14(0, c0, c12, 6)
+#define RCP14_DBGWVR13()		MRC14(0, c0, c13, 6)
+#define RCP14_DBGWVR14()		MRC14(0, c0, c14, 6)
+#define RCP14_DBGWVR15()		MRC14(0, c0, c15, 6)
+#define RCP14_DBGWCR0()			MRC14(0, c0, c0, 7)
+#define RCP14_DBGWCR1()			MRC14(0, c0, c1, 7)
+#define RCP14_DBGWCR2()			MRC14(0, c0, c2, 7)
+#define RCP14_DBGWCR3()			MRC14(0, c0, c3, 7)
+#define RCP14_DBGWCR4()			MRC14(0, c0, c4, 7)
+#define RCP14_DBGWCR5()			MRC14(0, c0, c5, 7)
+#define RCP14_DBGWCR6()			MRC14(0, c0, c6, 7)
+#define RCP14_DBGWCR7()			MRC14(0, c0, c7, 7)
+#define RCP14_DBGWCR8()			MRC14(0, c0, c8, 7)
+#define RCP14_DBGWCR9()			MRC14(0, c0, c9, 7)
+#define RCP14_DBGWCR10()		MRC14(0, c0, c10, 7)
+#define RCP14_DBGWCR11()		MRC14(0, c0, c11, 7)
+#define RCP14_DBGWCR12()		MRC14(0, c0, c12, 7)
+#define RCP14_DBGWCR13()		MRC14(0, c0, c13, 7)
+#define RCP14_DBGWCR14()		MRC14(0, c0, c14, 7)
+#define RCP14_DBGWCR15()		MRC14(0, c0, c15, 7)
+#define RCP14_DBGDRAR()			MRC14(0, c1, c0, 0)
+#define RCP14_DBGBXVR0()		MRC14(0, c1, c0, 1)
+#define RCP14_DBGBXVR1()		MRC14(0, c1, c1, 1)
+#define RCP14_DBGBXVR2()		MRC14(0, c1, c2, 1)
+#define RCP14_DBGBXVR3()		MRC14(0, c1, c3, 1)
+#define RCP14_DBGBXVR4()		MRC14(0, c1, c4, 1)
+#define RCP14_DBGBXVR5()		MRC14(0, c1, c5, 1)
+#define RCP14_DBGBXVR6()		MRC14(0, c1, c6, 1)
+#define RCP14_DBGBXVR7()		MRC14(0, c1, c7, 1)
+#define RCP14_DBGBXVR8()		MRC14(0, c1, c8, 1)
+#define RCP14_DBGBXVR9()		MRC14(0, c1, c9, 1)
+#define RCP14_DBGBXVR10()		MRC14(0, c1, c10, 1)
+#define RCP14_DBGBXVR11()		MRC14(0, c1, c11, 1)
+#define RCP14_DBGBXVR12()		MRC14(0, c1, c12, 1)
+#define RCP14_DBGBXVR13()		MRC14(0, c1, c13, 1)
+#define RCP14_DBGBXVR14()		MRC14(0, c1, c14, 1)
+#define RCP14_DBGBXVR15()		MRC14(0, c1, c15, 1)
+#define RCP14_DBGOSLSR()		MRC14(0, c1, c1, 4)
+#define RCP14_DBGOSSRR()		MRC14(0, c1, c2, 4)
+#define RCP14_DBGOSDLR()		MRC14(0, c1, c3, 4)
+#define RCP14_DBGPRCR()			MRC14(0, c1, c4, 4)
+#define RCP14_DBGPRSR()			MRC14(0, c1, c5, 4)
+#define RCP14_DBGDSAR()			MRC14(0, c2, c0, 0)
+#define RCP14_DBGITCTRL()		MRC14(0, c7, c0, 4)
+#define RCP14_DBGCLAIMSET()		MRC14(0, c7, c8, 6)
+#define RCP14_DBGCLAIMCLR()		MRC14(0, c7, c9, 6)
+#define RCP14_DBGAUTHSTATUS()		MRC14(0, c7, c14, 6)
+#define RCP14_DBGDEVID2()		MRC14(0, c7, c0, 7)
+#define RCP14_DBGDEVID1()		MRC14(0, c7, c1, 7)
+#define RCP14_DBGDEVID()		MRC14(0, c7, c2, 7)
+
+#define WCP14_DBGDTRTXint(val)		MCR14(val, 0, c0, c5, 0)
+#define WCP14_DBGWFAR(val)		MCR14(val, 0, c0, c6, 0)
+#define WCP14_DBGVCR(val)		MCR14(val, 0, c0, c7, 0)
+#define WCP14_DBGECR(val)		MCR14(val, 0, c0, c9, 0)
+#define WCP14_DBGDSCCR(val)		MCR14(val, 0, c0, c10, 0)
+#define WCP14_DBGDSMCR(val)		MCR14(val, 0, c0, c11, 0)
+#define WCP14_DBGDTRRXext(val)		MCR14(val, 0, c0, c0, 2)
+#define WCP14_DBGDSCRext(val)		MCR14(val, 0, c0, c2, 2)
+#define WCP14_DBGDTRTXext(val)		MCR14(val, 0, c0, c3, 2)
+#define WCP14_DBGDRCR(val)		MCR14(val, 0, c0, c4, 2)
+#define WCP14_DBGBVR0(val)		MCR14(val, 0, c0, c0, 4)
+#define WCP14_DBGBVR1(val)		MCR14(val, 0, c0, c1, 4)
+#define WCP14_DBGBVR2(val)		MCR14(val, 0, c0, c2, 4)
+#define WCP14_DBGBVR3(val)		MCR14(val, 0, c0, c3, 4)
+#define WCP14_DBGBVR4(val)		MCR14(val, 0, c0, c4, 4)
+#define WCP14_DBGBVR5(val)		MCR14(val, 0, c0, c5, 4)
+#define WCP14_DBGBVR6(val)		MCR14(val, 0, c0, c6, 4)
+#define WCP14_DBGBVR7(val)		MCR14(val, 0, c0, c7, 4)
+#define WCP14_DBGBVR8(val)		MCR14(val, 0, c0, c8, 4)
+#define WCP14_DBGBVR9(val)		MCR14(val, 0, c0, c9, 4)
+#define WCP14_DBGBVR10(val)		MCR14(val, 0, c0, c10, 4)
+#define WCP14_DBGBVR11(val)		MCR14(val, 0, c0, c11, 4)
+#define WCP14_DBGBVR12(val)		MCR14(val, 0, c0, c12, 4)
+#define WCP14_DBGBVR13(val)		MCR14(val, 0, c0, c13, 4)
+#define WCP14_DBGBVR14(val)		MCR14(val, 0, c0, c14, 4)
+#define WCP14_DBGBVR15(val)		MCR14(val, 0, c0, c15, 4)
+#define WCP14_DBGBCR0(val)		MCR14(val, 0, c0, c0, 5)
+#define WCP14_DBGBCR1(val)		MCR14(val, 0, c0, c1, 5)
+#define WCP14_DBGBCR2(val)		MCR14(val, 0, c0, c2, 5)
+#define WCP14_DBGBCR3(val)		MCR14(val, 0, c0, c3, 5)
+#define WCP14_DBGBCR4(val)		MCR14(val, 0, c0, c4, 5)
+#define WCP14_DBGBCR5(val)		MCR14(val, 0, c0, c5, 5)
+#define WCP14_DBGBCR6(val)		MCR14(val, 0, c0, c6, 5)
+#define WCP14_DBGBCR7(val)		MCR14(val, 0, c0, c7, 5)
+#define WCP14_DBGBCR8(val)		MCR14(val, 0, c0, c8, 5)
+#define WCP14_DBGBCR9(val)		MCR14(val, 0, c0, c9, 5)
+#define WCP14_DBGBCR10(val)		MCR14(val, 0, c0, c10, 5)
+#define WCP14_DBGBCR11(val)		MCR14(val, 0, c0, c11, 5)
+#define WCP14_DBGBCR12(val)		MCR14(val, 0, c0, c12, 5)
+#define WCP14_DBGBCR13(val)		MCR14(val, 0, c0, c13, 5)
+#define WCP14_DBGBCR14(val)		MCR14(val, 0, c0, c14, 5)
+#define WCP14_DBGBCR15(val)		MCR14(val, 0, c0, c15, 5)
+#define WCP14_DBGWVR0(val)		MCR14(val, 0, c0, c0, 6)
+#define WCP14_DBGWVR1(val)		MCR14(val, 0, c0, c1, 6)
+#define WCP14_DBGWVR2(val)		MCR14(val, 0, c0, c2, 6)
+#define WCP14_DBGWVR3(val)		MCR14(val, 0, c0, c3, 6)
+#define WCP14_DBGWVR4(val)		MCR14(val, 0, c0, c4, 6)
+#define WCP14_DBGWVR5(val)		MCR14(val, 0, c0, c5, 6)
+#define WCP14_DBGWVR6(val)		MCR14(val, 0, c0, c6, 6)
+#define WCP14_DBGWVR7(val)		MCR14(val, 0, c0, c7, 6)
+#define WCP14_DBGWVR8(val)		MCR14(val, 0, c0, c8, 6)
+#define WCP14_DBGWVR9(val)		MCR14(val, 0, c0, c9, 6)
+#define WCP14_DBGWVR10(val)		MCR14(val, 0, c0, c10, 6)
+#define WCP14_DBGWVR11(val)		MCR14(val, 0, c0, c11, 6)
+#define WCP14_DBGWVR12(val)		MCR14(val, 0, c0, c12, 6)
+#define WCP14_DBGWVR13(val)		MCR14(val, 0, c0, c13, 6)
+#define WCP14_DBGWVR14(val)		MCR14(val, 0, c0, c14, 6)
+#define WCP14_DBGWVR15(val)		MCR14(val, 0, c0, c15, 6)
+#define WCP14_DBGWCR0(val)		MCR14(val, 0, c0, c0, 7)
+#define WCP14_DBGWCR1(val)		MCR14(val, 0, c0, c1, 7)
+#define WCP14_DBGWCR2(val)		MCR14(val, 0, c0, c2, 7)
+#define WCP14_DBGWCR3(val)		MCR14(val, 0, c0, c3, 7)
+#define WCP14_DBGWCR4(val)		MCR14(val, 0, c0, c4, 7)
+#define WCP14_DBGWCR5(val)		MCR14(val, 0, c0, c5, 7)
+#define WCP14_DBGWCR6(val)		MCR14(val, 0, c0, c6, 7)
+#define WCP14_DBGWCR7(val)		MCR14(val, 0, c0, c7, 7)
+#define WCP14_DBGWCR8(val)		MCR14(val, 0, c0, c8, 7)
+#define WCP14_DBGWCR9(val)		MCR14(val, 0, c0, c9, 7)
+#define WCP14_DBGWCR10(val)		MCR14(val, 0, c0, c10, 7)
+#define WCP14_DBGWCR11(val)		MCR14(val, 0, c0, c11, 7)
+#define WCP14_DBGWCR12(val)		MCR14(val, 0, c0, c12, 7)
+#define WCP14_DBGWCR13(val)		MCR14(val, 0, c0, c13, 7)
+#define WCP14_DBGWCR14(val)		MCR14(val, 0, c0, c14, 7)
+#define WCP14_DBGWCR15(val)		MCR14(val, 0, c0, c15, 7)
+#define WCP14_DBGBXVR0(val)		MCR14(val, 0, c1, c0, 1)
+#define WCP14_DBGBXVR1(val)		MCR14(val, 0, c1, c1, 1)
+#define WCP14_DBGBXVR2(val)		MCR14(val, 0, c1, c2, 1)
+#define WCP14_DBGBXVR3(val)		MCR14(val, 0, c1, c3, 1)
+#define WCP14_DBGBXVR4(val)		MCR14(val, 0, c1, c4, 1)
+#define WCP14_DBGBXVR5(val)		MCR14(val, 0, c1, c5, 1)
+#define WCP14_DBGBXVR6(val)		MCR14(val, 0, c1, c6, 1)
+#define WCP14_DBGBXVR7(val)		MCR14(val, 0, c1, c7, 1)
+#define WCP14_DBGBXVR8(val)		MCR14(val, 0, c1, c8, 1)
+#define WCP14_DBGBXVR9(val)		MCR14(val, 0, c1, c9, 1)
+#define WCP14_DBGBXVR10(val)		MCR14(val, 0, c1, c10, 1)
+#define WCP14_DBGBXVR11(val)		MCR14(val, 0, c1, c11, 1)
+#define WCP14_DBGBXVR12(val)		MCR14(val, 0, c1, c12, 1)
+#define WCP14_DBGBXVR13(val)		MCR14(val, 0, c1, c13, 1)
+#define WCP14_DBGBXVR14(val)		MCR14(val, 0, c1, c14, 1)
+#define WCP14_DBGBXVR15(val)		MCR14(val, 0, c1, c15, 1)
+#define WCP14_DBGOSLAR(val)		MCR14(val, 0, c1, c0, 4)
+#define WCP14_DBGOSSRR(val)		MCR14(val, 0, c1, c2, 4)
+#define WCP14_DBGOSDLR(val)		MCR14(val, 0, c1, c3, 4)
+#define WCP14_DBGPRCR(val)		MCR14(val, 0, c1, c4, 4)
+#define WCP14_DBGITCTRL(val)		MCR14(val, 0, c7, c0, 4)
+#define WCP14_DBGCLAIMSET(val)		MCR14(val, 0, c7, c8, 6)
+#define WCP14_DBGCLAIMCLR(val)		MCR14(val, 0, c7, c9, 6)
+
+/* ETM Registers
+ *
+ * Available only in ETMv3.3, 3.4, 3.5
+ * ETMASICCR, ETMTECR2, ETMFFRR, ETMVDEVR, ETMVDCR1, ETMVDCR2, ETMVDCR3,
+ * ETMDCVRn, ETMDCMRn
+ *
+ * Available only in ETMv3.5 as read only
+ * ETMIDR2
+ *
+ * Available only in ETMv3.5, PFTv1.0, 1.1
+ * ETMTSEVR, ETMVMIDCVR, ETMPDCR
+ *
+ * Read only
+ * ETMCCR, ETMSCR, ETMIDR, ETMCCER, ETMOSLSR
+ * ETMLSR, ETMAUTHSTATUS, ETMDEVID, ETMDEVTYPE, ETMPIDR4, ETMPIDR5, ETMPIDR6,
+ * ETMPIDR7, ETMPIDR0, ETMPIDR1, ETMPIDR2, ETMPIDR2, ETMPIDR3, ETMCIDR0,
+ * ETMCIDR1, ETMCIDR2, ETMCIDR3
+ *
+ * Write only
+ * ETMOSLAR, ETMLAR
+ * Note: ETMCCER[11] controls WO nature of certain regs. Refer ETM arch spec.
+ */
+#define RCP14_ETMCR()			MRC14(1, c0, c0, 0)
+#define RCP14_ETMCCR()			MRC14(1, c0, c1, 0)
+#define RCP14_ETMTRIGGER()		MRC14(1, c0, c2, 0)
+#define RCP14_ETMASICCR()		MRC14(1, c0, c3, 0)
+#define RCP14_ETMSR()			MRC14(1, c0, c4, 0)
+#define RCP14_ETMSCR()			MRC14(1, c0, c5, 0)
+#define RCP14_ETMTSSCR()		MRC14(1, c0, c6, 0)
+#define RCP14_ETMTECR2()		MRC14(1, c0, c7, 0)
+#define RCP14_ETMTEEVR()		MRC14(1, c0, c8, 0)
+#define RCP14_ETMTECR1()		MRC14(1, c0, c9, 0)
+#define RCP14_ETMFFRR()			MRC14(1, c0, c10, 0)
+#define RCP14_ETMFFLR()			MRC14(1, c0, c11, 0)
+#define RCP14_ETMVDEVR()		MRC14(1, c0, c12, 0)
+#define RCP14_ETMVDCR1()		MRC14(1, c0, c13, 0)
+#define RCP14_ETMVDCR2()		MRC14(1, c0, c14, 0)
+#define RCP14_ETMVDCR3()		MRC14(1, c0, c15, 0)
+#define RCP14_ETMACVR0()		MRC14(1, c0, c0, 1)
+#define RCP14_ETMACVR1()		MRC14(1, c0, c1, 1)
+#define RCP14_ETMACVR2()		MRC14(1, c0, c2, 1)
+#define RCP14_ETMACVR3()		MRC14(1, c0, c3, 1)
+#define RCP14_ETMACVR4()		MRC14(1, c0, c4, 1)
+#define RCP14_ETMACVR5()		MRC14(1, c0, c5, 1)
+#define RCP14_ETMACVR6()		MRC14(1, c0, c6, 1)
+#define RCP14_ETMACVR7()		MRC14(1, c0, c7, 1)
+#define RCP14_ETMACVR8()		MRC14(1, c0, c8, 1)
+#define RCP14_ETMACVR9()		MRC14(1, c0, c9, 1)
+#define RCP14_ETMACVR10()		MRC14(1, c0, c10, 1)
+#define RCP14_ETMACVR11()		MRC14(1, c0, c11, 1)
+#define RCP14_ETMACVR12()		MRC14(1, c0, c12, 1)
+#define RCP14_ETMACVR13()		MRC14(1, c0, c13, 1)
+#define RCP14_ETMACVR14()		MRC14(1, c0, c14, 1)
+#define RCP14_ETMACVR15()		MRC14(1, c0, c15, 1)
+#define RCP14_ETMACTR0()		MRC14(1, c0, c0, 2)
+#define RCP14_ETMACTR1()		MRC14(1, c0, c1, 2)
+#define RCP14_ETMACTR2()		MRC14(1, c0, c2, 2)
+#define RCP14_ETMACTR3()		MRC14(1, c0, c3, 2)
+#define RCP14_ETMACTR4()		MRC14(1, c0, c4, 2)
+#define RCP14_ETMACTR5()		MRC14(1, c0, c5, 2)
+#define RCP14_ETMACTR6()		MRC14(1, c0, c6, 2)
+#define RCP14_ETMACTR7()		MRC14(1, c0, c7, 2)
+#define RCP14_ETMACTR8()		MRC14(1, c0, c8, 2)
+#define RCP14_ETMACTR9()		MRC14(1, c0, c9, 2)
+#define RCP14_ETMACTR10()		MRC14(1, c0, c10, 2)
+#define RCP14_ETMACTR11()		MRC14(1, c0, c11, 2)
+#define RCP14_ETMACTR12()		MRC14(1, c0, c12, 2)
+#define RCP14_ETMACTR13()		MRC14(1, c0, c13, 2)
+#define RCP14_ETMACTR14()		MRC14(1, c0, c14, 2)
+#define RCP14_ETMACTR15()		MRC14(1, c0, c15, 2)
+#define RCP14_ETMDCVR0()		MRC14(1, c0, c0, 3)
+#define RCP14_ETMDCVR2()		MRC14(1, c0, c2, 3)
+#define RCP14_ETMDCVR4()		MRC14(1, c0, c4, 3)
+#define RCP14_ETMDCVR6()		MRC14(1, c0, c6, 3)
+#define RCP14_ETMDCVR8()		MRC14(1, c0, c8, 3)
+#define RCP14_ETMDCVR10()		MRC14(1, c0, c10, 3)
+#define RCP14_ETMDCVR12()		MRC14(1, c0, c12, 3)
+#define RCP14_ETMDCVR14()		MRC14(1, c0, c14, 3)
+#define RCP14_ETMDCMR0()		MRC14(1, c0, c0, 4)
+#define RCP14_ETMDCMR2()		MRC14(1, c0, c2, 4)
+#define RCP14_ETMDCMR4()		MRC14(1, c0, c4, 4)
+#define RCP14_ETMDCMR6()		MRC14(1, c0, c6, 4)
+#define RCP14_ETMDCMR8()		MRC14(1, c0, c8, 4)
+#define RCP14_ETMDCMR10()		MRC14(1, c0, c10, 4)
+#define RCP14_ETMDCMR12()		MRC14(1, c0, c12, 4)
+#define RCP14_ETMDCMR14()		MRC14(1, c0, c14, 4)
+#define RCP14_ETMCNTRLDVR0()		MRC14(1, c0, c0, 5)
+#define RCP14_ETMCNTRLDVR1()		MRC14(1, c0, c1, 5)
+#define RCP14_ETMCNTRLDVR2()		MRC14(1, c0, c2, 5)
+#define RCP14_ETMCNTRLDVR3()		MRC14(1, c0, c3, 5)
+#define RCP14_ETMCNTENR0()		MRC14(1, c0, c4, 5)
+#define RCP14_ETMCNTENR1()		MRC14(1, c0, c5, 5)
+#define RCP14_ETMCNTENR2()		MRC14(1, c0, c6, 5)
+#define RCP14_ETMCNTENR3()		MRC14(1, c0, c7, 5)
+#define RCP14_ETMCNTRLDEVR0()		MRC14(1, c0, c8, 5)
+#define RCP14_ETMCNTRLDEVR1()		MRC14(1, c0, c9, 5)
+#define RCP14_ETMCNTRLDEVR2()		MRC14(1, c0, c10, 5)
+#define RCP14_ETMCNTRLDEVR3()		MRC14(1, c0, c11, 5)
+#define RCP14_ETMCNTVR0()		MRC14(1, c0, c12, 5)
+#define RCP14_ETMCNTVR1()		MRC14(1, c0, c13, 5)
+#define RCP14_ETMCNTVR2()		MRC14(1, c0, c14, 5)
+#define RCP14_ETMCNTVR3()		MRC14(1, c0, c15, 5)
+#define RCP14_ETMSQ12EVR()		MRC14(1, c0, c0, 6)
+#define RCP14_ETMSQ21EVR()		MRC14(1, c0, c1, 6)
+#define RCP14_ETMSQ23EVR()		MRC14(1, c0, c2, 6)
+#define RCP14_ETMSQ31EVR()		MRC14(1, c0, c3, 6)
+#define RCP14_ETMSQ32EVR()		MRC14(1, c0, c4, 6)
+#define RCP14_ETMSQ13EVR()		MRC14(1, c0, c5, 6)
+#define RCP14_ETMSQR()			MRC14(1, c0, c7, 6)
+#define RCP14_ETMEXTOUTEVR0()		MRC14(1, c0, c8, 6)
+#define RCP14_ETMEXTOUTEVR1()		MRC14(1, c0, c9, 6)
+#define RCP14_ETMEXTOUTEVR2()		MRC14(1, c0, c10, 6)
+#define RCP14_ETMEXTOUTEVR3()		MRC14(1, c0, c11, 6)
+#define RCP14_ETMCIDCVR0()		MRC14(1, c0, c12, 6)
+#define RCP14_ETMCIDCVR1()		MRC14(1, c0, c13, 6)
+#define RCP14_ETMCIDCVR2()		MRC14(1, c0, c14, 6)
+#define RCP14_ETMCIDCMR()		MRC14(1, c0, c15, 6)
+#define RCP14_ETMIMPSPEC0()		MRC14(1, c0, c0, 7)
+#define RCP14_ETMIMPSPEC1()		MRC14(1, c0, c1, 7)
+#define RCP14_ETMIMPSPEC2()		MRC14(1, c0, c2, 7)
+#define RCP14_ETMIMPSPEC3()		MRC14(1, c0, c3, 7)
+#define RCP14_ETMIMPSPEC4()		MRC14(1, c0, c4, 7)
+#define RCP14_ETMIMPSPEC5()		MRC14(1, c0, c5, 7)
+#define RCP14_ETMIMPSPEC6()		MRC14(1, c0, c6, 7)
+#define RCP14_ETMIMPSPEC7()		MRC14(1, c0, c7, 7)
+#define RCP14_ETMSYNCFR()		MRC14(1, c0, c8, 7)
+#define RCP14_ETMIDR()			MRC14(1, c0, c9, 7)
+#define RCP14_ETMCCER()			MRC14(1, c0, c10, 7)
+#define RCP14_ETMEXTINSELR()		MRC14(1, c0, c11, 7)
+#define RCP14_ETMTESSEICR()		MRC14(1, c0, c12, 7)
+#define RCP14_ETMEIBCR()		MRC14(1, c0, c13, 7)
+#define RCP14_ETMTSEVR()		MRC14(1, c0, c14, 7)
+#define RCP14_ETMAUXCR()		MRC14(1, c0, c15, 7)
+#define RCP14_ETMTRACEIDR()		MRC14(1, c1, c0, 0)
+#define RCP14_ETMIDR2()			MRC14(1, c1, c2, 0)
+#define RCP14_ETMVMIDCVR()		MRC14(1, c1, c0, 1)
+#define RCP14_ETMOSLSR()		MRC14(1, c1, c1, 4)
+/* not available in PFTv1.1 */
+#define RCP14_ETMOSSRR()		MRC14(1, c1, c2, 4)
+#define RCP14_ETMPDCR()			MRC14(1, c1, c4, 4)
+#define RCP14_ETMPDSR()			MRC14(1, c1, c5, 4)
+#define RCP14_ETMITCTRL()		MRC14(1, c7, c0, 4)
+#define RCP14_ETMCLAIMSET()		MRC14(1, c7, c8, 6)
+#define RCP14_ETMCLAIMCLR()		MRC14(1, c7, c9, 6)
+#define RCP14_ETMLSR()			MRC14(1, c7, c13, 6)
+#define RCP14_ETMAUTHSTATUS()		MRC14(1, c7, c14, 6)
+#define RCP14_ETMDEVID()		MRC14(1, c7, c2, 7)
+#define RCP14_ETMDEVTYPE()		MRC14(1, c7, c3, 7)
+#define RCP14_ETMPIDR4()		MRC14(1, c7, c4, 7)
+#define RCP14_ETMPIDR5()		MRC14(1, c7, c5, 7)
+#define RCP14_ETMPIDR6()		MRC14(1, c7, c6, 7)
+#define RCP14_ETMPIDR7()		MRC14(1, c7, c7, 7)
+#define RCP14_ETMPIDR0()		MRC14(1, c7, c8, 7)
+#define RCP14_ETMPIDR1()		MRC14(1, c7, c9, 7)
+#define RCP14_ETMPIDR2()		MRC14(1, c7, c10, 7)
+#define RCP14_ETMPIDR3()		MRC14(1, c7, c11, 7)
+#define RCP14_ETMCIDR0()		MRC14(1, c7, c12, 7)
+#define RCP14_ETMCIDR1()		MRC14(1, c7, c13, 7)
+#define RCP14_ETMCIDR2()		MRC14(1, c7, c14, 7)
+#define RCP14_ETMCIDR3()		MRC14(1, c7, c15, 7)
+
+#define WCP14_ETMCR(val)		MCR14(val, 1, c0, c0, 0)
+#define WCP14_ETMTRIGGER(val)		MCR14(val, 1, c0, c2, 0)
+#define WCP14_ETMASICCR(val)		MCR14(val, 1, c0, c3, 0)
+#define WCP14_ETMSR(val)		MCR14(val, 1, c0, c4, 0)
+#define WCP14_ETMTSSCR(val)		MCR14(val, 1, c0, c6, 0)
+#define WCP14_ETMTECR2(val)		MCR14(val, 1, c0, c7, 0)
+#define WCP14_ETMTEEVR(val)		MCR14(val, 1, c0, c8, 0)
+#define WCP14_ETMTECR1(val)		MCR14(val, 1, c0, c9, 0)
+#define WCP14_ETMFFRR(val)		MCR14(val, 1, c0, c10, 0)
+#define WCP14_ETMFFLR(val)		MCR14(val, 1, c0, c11, 0)
+#define WCP14_ETMVDEVR(val)		MCR14(val, 1, c0, c12, 0)
+#define WCP14_ETMVDCR1(val)		MCR14(val, 1, c0, c13, 0)
+#define WCP14_ETMVDCR2(val)		MCR14(val, 1, c0, c14, 0)
+#define WCP14_ETMVDCR3(val)		MCR14(val, 1, c0, c15, 0)
+#define WCP14_ETMACVR0(val)		MCR14(val, 1, c0, c0, 1)
+#define WCP14_ETMACVR1(val)		MCR14(val, 1, c0, c1, 1)
+#define WCP14_ETMACVR2(val)		MCR14(val, 1, c0, c2, 1)
+#define WCP14_ETMACVR3(val)		MCR14(val, 1, c0, c3, 1)
+#define WCP14_ETMACVR4(val)		MCR14(val, 1, c0, c4, 1)
+#define WCP14_ETMACVR5(val)		MCR14(val, 1, c0, c5, 1)
+#define WCP14_ETMACVR6(val)		MCR14(val, 1, c0, c6, 1)
+#define WCP14_ETMACVR7(val)		MCR14(val, 1, c0, c7, 1)
+#define WCP14_ETMACVR8(val)		MCR14(val, 1, c0, c8, 1)
+#define WCP14_ETMACVR9(val)		MCR14(val, 1, c0, c9, 1)
+#define WCP14_ETMACVR10(val)		MCR14(val, 1, c0, c10, 1)
+#define WCP14_ETMACVR11(val)		MCR14(val, 1, c0, c11, 1)
+#define WCP14_ETMACVR12(val)		MCR14(val, 1, c0, c12, 1)
+#define WCP14_ETMACVR13(val)		MCR14(val, 1, c0, c13, 1)
+#define WCP14_ETMACVR14(val)		MCR14(val, 1, c0, c14, 1)
+#define WCP14_ETMACVR15(val)		MCR14(val, 1, c0, c15, 1)
+#define WCP14_ETMACTR0(val)		MCR14(val, 1, c0, c0, 2)
+#define WCP14_ETMACTR1(val)		MCR14(val, 1, c0, c1, 2)
+#define WCP14_ETMACTR2(val)		MCR14(val, 1, c0, c2, 2)
+#define WCP14_ETMACTR3(val)		MCR14(val, 1, c0, c3, 2)
+#define WCP14_ETMACTR4(val)		MCR14(val, 1, c0, c4, 2)
+#define WCP14_ETMACTR5(val)		MCR14(val, 1, c0, c5, 2)
+#define WCP14_ETMACTR6(val)		MCR14(val, 1, c0, c6, 2)
+#define WCP14_ETMACTR7(val)		MCR14(val, 1, c0, c7, 2)
+#define WCP14_ETMACTR8(val)		MCR14(val, 1, c0, c8, 2)
+#define WCP14_ETMACTR9(val)		MCR14(val, 1, c0, c9, 2)
+#define WCP14_ETMACTR10(val)		MCR14(val, 1, c0, c10, 2)
+#define WCP14_ETMACTR11(val)		MCR14(val, 1, c0, c11, 2)
+#define WCP14_ETMACTR12(val)		MCR14(val, 1, c0, c12, 2)
+#define WCP14_ETMACTR13(val)		MCR14(val, 1, c0, c13, 2)
+#define WCP14_ETMACTR14(val)		MCR14(val, 1, c0, c14, 2)
+#define WCP14_ETMACTR15(val)		MCR14(val, 1, c0, c15, 2)
+#define WCP14_ETMDCVR0(val)		MCR14(val, 1, c0, c0, 3)
+#define WCP14_ETMDCVR2(val)		MCR14(val, 1, c0, c2, 3)
+#define WCP14_ETMDCVR4(val)		MCR14(val, 1, c0, c4, 3)
+#define WCP14_ETMDCVR6(val)		MCR14(val, 1, c0, c6, 3)
+#define WCP14_ETMDCVR8(val)		MCR14(val, 1, c0, c8, 3)
+#define WCP14_ETMDCVR10(val)		MCR14(val, 1, c0, c10, 3)
+#define WCP14_ETMDCVR12(val)		MCR14(val, 1, c0, c12, 3)
+#define WCP14_ETMDCVR14(val)		MCR14(val, 1, c0, c14, 3)
+#define WCP14_ETMDCMR0(val)		MCR14(val, 1, c0, c0, 4)
+#define WCP14_ETMDCMR2(val)		MCR14(val, 1, c0, c2, 4)
+#define WCP14_ETMDCMR4(val)		MCR14(val, 1, c0, c4, 4)
+#define WCP14_ETMDCMR6(val)		MCR14(val, 1, c0, c6, 4)
+#define WCP14_ETMDCMR8(val)		MCR14(val, 1, c0, c8, 4)
+#define WCP14_ETMDCMR10(val)		MCR14(val, 1, c0, c10, 4)
+#define WCP14_ETMDCMR12(val)		MCR14(val, 1, c0, c12, 4)
+#define WCP14_ETMDCMR14(val)		MCR14(val, 1, c0, c14, 4)
+#define WCP14_ETMCNTRLDVR0(val)		MCR14(val, 1, c0, c0, 5)
+#define WCP14_ETMCNTRLDVR1(val)		MCR14(val, 1, c0, c1, 5)
+#define WCP14_ETMCNTRLDVR2(val)		MCR14(val, 1, c0, c2, 5)
+#define WCP14_ETMCNTRLDVR3(val)		MCR14(val, 1, c0, c3, 5)
+#define WCP14_ETMCNTENR0(val)		MCR14(val, 1, c0, c4, 5)
+#define WCP14_ETMCNTENR1(val)		MCR14(val, 1, c0, c5, 5)
+#define WCP14_ETMCNTENR2(val)		MCR14(val, 1, c0, c6, 5)
+#define WCP14_ETMCNTENR3(val)		MCR14(val, 1, c0, c7, 5)
+#define WCP14_ETMCNTRLDEVR0(val)	MCR14(val, 1, c0, c8, 5)
+#define WCP14_ETMCNTRLDEVR1(val)	MCR14(val, 1, c0, c9, 5)
+#define WCP14_ETMCNTRLDEVR2(val)	MCR14(val, 1, c0, c10, 5)
+#define WCP14_ETMCNTRLDEVR3(val)	MCR14(val, 1, c0, c11, 5)
+#define WCP14_ETMCNTVR0(val)		MCR14(val, 1, c0, c12, 5)
+#define WCP14_ETMCNTVR1(val)		MCR14(val, 1, c0, c13, 5)
+#define WCP14_ETMCNTVR2(val)		MCR14(val, 1, c0, c14, 5)
+#define WCP14_ETMCNTVR3(val)		MCR14(val, 1, c0, c15, 5)
+#define WCP14_ETMSQ12EVR(val)		MCR14(val, 1, c0, c0, 6)
+#define WCP14_ETMSQ21EVR(val)		MCR14(val, 1, c0, c1, 6)
+#define WCP14_ETMSQ23EVR(val)		MCR14(val, 1, c0, c2, 6)
+#define WCP14_ETMSQ31EVR(val)		MCR14(val, 1, c0, c3, 6)
+#define WCP14_ETMSQ32EVR(val)		MCR14(val, 1, c0, c4, 6)
+#define WCP14_ETMSQ13EVR(val)		MCR14(val, 1, c0, c5, 6)
+#define WCP14_ETMSQR(val)		MCR14(val, 1, c0, c7, 6)
+#define WCP14_ETMEXTOUTEVR0(val)	MCR14(val, 1, c0, c8, 6)
+#define WCP14_ETMEXTOUTEVR1(val)	MCR14(val, 1, c0, c9, 6)
+#define WCP14_ETMEXTOUTEVR2(val)	MCR14(val, 1, c0, c10, 6)
+#define WCP14_ETMEXTOUTEVR3(val)	MCR14(val, 1, c0, c11, 6)
+#define WCP14_ETMCIDCVR0(val)		MCR14(val, 1, c0, c12, 6)
+#define WCP14_ETMCIDCVR1(val)		MCR14(val, 1, c0, c13, 6)
+#define WCP14_ETMCIDCVR2(val)		MCR14(val, 1, c0, c14, 6)
+#define WCP14_ETMCIDCMR(val)		MCR14(val, 1, c0, c15, 6)
+#define WCP14_ETMIMPSPEC0(val)		MCR14(val, 1, c0, c0, 7)
+#define WCP14_ETMIMPSPEC1(val)		MCR14(val, 1, c0, c1, 7)
+#define WCP14_ETMIMPSPEC2(val)		MCR14(val, 1, c0, c2, 7)
+#define WCP14_ETMIMPSPEC3(val)		MCR14(val, 1, c0, c3, 7)
+#define WCP14_ETMIMPSPEC4(val)		MCR14(val, 1, c0, c4, 7)
+#define WCP14_ETMIMPSPEC5(val)		MCR14(val, 1, c0, c5, 7)
+#define WCP14_ETMIMPSPEC6(val)		MCR14(val, 1, c0, c6, 7)
+#define WCP14_ETMIMPSPEC7(val)		MCR14(val, 1, c0, c7, 7)
+/* can be read only in ETMv3.4, ETMv3.5 */
+#define WCP14_ETMSYNCFR(val)		MCR14(val, 1, c0, c8, 7)
+#define WCP14_ETMEXTINSELR(val)		MCR14(val, 1, c0, c11, 7)
+#define WCP14_ETMTESSEICR(val)		MCR14(val, 1, c0, c12, 7)
+#define WCP14_ETMEIBCR(val)		MCR14(val, 1, c0, c13, 7)
+#define WCP14_ETMTSEVR(val)		MCR14(val, 1, c0, c14, 7)
+#define WCP14_ETMAUXCR(val)		MCR14(val, 1, c0, c15, 7)
+#define WCP14_ETMTRACEIDR(val)		MCR14(val, 1, c1, c0, 0)
+#define WCP14_ETMIDR2(val)		MCR14(val, 1, c1, c2, 0)
+#define WCP14_ETMVMIDCVR(val)		MCR14(val, 1, c1, c0, 1)
+#define WCP14_ETMOSLAR(val)		MCR14(val, 1, c1, c0, 4)
+/* not available in PFTv1.1 */
+#define WCP14_ETMOSSRR(val)		MCR14(val, 1, c1, c2, 4)
+#define WCP14_ETMPDCR(val)		MCR14(val, 1, c1, c4, 4)
+#define WCP14_ETMPDSR(val)		MCR14(val, 1, c1, c5, 4)
+#define WCP14_ETMITCTRL(val)		MCR14(val, 1, c7, c0, 4)
+#define WCP14_ETMCLAIMSET(val)		MCR14(val, 1, c7, c8, 6)
+#define WCP14_ETMCLAIMCLR(val)		MCR14(val, 1, c7, c9, 6)
+/* writes to this from CP14 interface are ignored */
+#define WCP14_ETMLAR(val)		MCR14(val, 1, c7, c12, 6)
+
+#endif
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 5a715e8..196f16b 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -36,4 +36,25 @@ config CORESIGHT_SOURCE_STM_DEFAULT_ENABLE
 	  If unsure, say 'N' here to avoid potential power, performance and
 	  memory penalty.
 
+config CORESIGHT_SOURCE_ETM
+	bool "CoreSight Embedded Trace Macrocell driver"
+	depends on !OC_ETM
+	select CORESIGHT_LINKS_AND_SINKS
+	help
+	  This driver provides support for processor tracing which allows
+	  tracing the instructions that the processor is executing. This is
+	  primarily useful for instruction level tracing.
+
+
+config CORESIGHT_SOURCE_ETM_DEFAULT_ENABLE
+	bool "Turn on CoreSight ETM tracing by default"
+	depends on CORESIGHT_SOURCE_ETM
+	help
+	  Turns on CoreSight ETM tracing (processor tracing) by default.
+	  Otherwise, tracing is disabled by default but can be enabled via
+	  sysfs.
+
+	  If unsure, say 'N' here to avoid potential power, performance and
+	  memory penalty.
+
 endif
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 750aa7c..ccbbd59 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_CORESIGHT) += coresight.o
 obj-$(CONFIG_OF) += of_coresight.o
 obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o
 obj-$(CONFIG_CORESIGHT_SOURCE_STM) += coresight-stm.o
+obj-$(CONFIG_CORESIGHT_SOURCE_ETM) += coresight-etm.o coresight-etm-cp14.o
diff --git a/drivers/coresight/coresight-etm-cp14.c b/drivers/coresight/coresight-etm-cp14.c
new file mode 100644
index 0000000..9a6c13a
--- /dev/null
+++ b/drivers/coresight/coresight-etm-cp14.c
@@ -0,0 +1,510 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/hardware/cp14.h>
+
+static unsigned int etm_read_reg(uint32_t reg)
+{
+	switch (reg) {
+	case 0x0:
+		return etm_read(ETMCR);
+	case 0x1:
+		return etm_read(ETMCCR);
+	case 0x2:
+		return etm_read(ETMTRIGGER);
+	case 0x4:
+		return etm_read(ETMSR);
+	case 0x5:
+		return etm_read(ETMSCR);
+	case 0x6:
+		return etm_read(ETMTSSCR);
+	case 0x8:
+		return etm_read(ETMTEEVR);
+	case 0x9:
+		return etm_read(ETMTECR1);
+	case 0xB:
+		return etm_read(ETMFFLR);
+	case 0x10:
+		return etm_read(ETMACVR0);
+	case 0x11:
+		return etm_read(ETMACVR1);
+	case 0x12:
+		return etm_read(ETMACVR2);
+	case 0x13:
+		return etm_read(ETMACVR3);
+	case 0x14:
+		return etm_read(ETMACVR4);
+	case 0x15:
+		return etm_read(ETMACVR5);
+	case 0x16:
+		return etm_read(ETMACVR6);
+	case 0x17:
+		return etm_read(ETMACVR7);
+	case 0x18:
+		return etm_read(ETMACVR8);
+	case 0x19:
+		return etm_read(ETMACVR9);
+	case 0x1A:
+		return etm_read(ETMACVR10);
+	case 0x1B:
+		return etm_read(ETMACVR11);
+	case 0x1C:
+		return etm_read(ETMACVR12);
+	case 0x1D:
+		return etm_read(ETMACVR13);
+	case 0x1E:
+		return etm_read(ETMACVR14);
+	case 0x1F:
+		return etm_read(ETMACVR15);
+	case 0x20:
+		return etm_read(ETMACTR0);
+	case 0x21:
+		return etm_read(ETMACTR1);
+	case 0x22:
+		return etm_read(ETMACTR2);
+	case 0x23:
+		return etm_read(ETMACTR3);
+	case 0x24:
+		return etm_read(ETMACTR4);
+	case 0x25:
+		return etm_read(ETMACTR5);
+	case 0x26:
+		return etm_read(ETMACTR6);
+	case 0x27:
+		return etm_read(ETMACTR7);
+	case 0x28:
+		return etm_read(ETMACTR8);
+	case 0x29:
+		return etm_read(ETMACTR9);
+	case 0x2A:
+		return etm_read(ETMACTR10);
+	case 0x2B:
+		return etm_read(ETMACTR11);
+	case 0x2C:
+		return etm_read(ETMACTR12);
+	case 0x2D:
+		return etm_read(ETMACTR13);
+	case 0x2E:
+		return etm_read(ETMACTR14);
+	case 0x2F:
+		return etm_read(ETMACTR15);
+	case 0x50:
+		return etm_read(ETMCNTRLDVR0);
+	case 0x51:
+		return etm_read(ETMCNTRLDVR1);
+	case 0x52:
+		return etm_read(ETMCNTRLDVR2);
+	case 0x53:
+		return etm_read(ETMCNTRLDVR3);
+	case 0x54:
+		return etm_read(ETMCNTENR0);
+	case 0x55:
+		return etm_read(ETMCNTENR1);
+	case 0x56:
+		return etm_read(ETMCNTENR2);
+	case 0x57:
+		return etm_read(ETMCNTENR3);
+	case 0x58:
+		return etm_read(ETMCNTRLDEVR0);
+	case 0x59:
+		return etm_read(ETMCNTRLDEVR1);
+	case 0x5A:
+		return etm_read(ETMCNTRLDEVR2);
+	case 0x5B:
+		return etm_read(ETMCNTRLDEVR3);
+	case 0x5C:
+		return etm_read(ETMCNTVR0);
+	case 0x5D:
+		return etm_read(ETMCNTVR1);
+	case 0x5E:
+		return etm_read(ETMCNTVR2);
+	case 0x5F:
+		return etm_read(ETMCNTVR3);
+	case 0x60:
+		return etm_read(ETMSQ12EVR);
+	case 0x61:
+		return etm_read(ETMSQ21EVR);
+	case 0x62:
+		return etm_read(ETMSQ23EVR);
+	case 0x63:
+		return etm_read(ETMSQ31EVR);
+	case 0x64:
+		return etm_read(ETMSQ32EVR);
+	case 0x65:
+		return etm_read(ETMSQ13EVR);
+	case 0x67:
+		return etm_read(ETMSQR);
+	case 0x68:
+		return etm_read(ETMEXTOUTEVR0);
+	case 0x69:
+		return etm_read(ETMEXTOUTEVR1);
+	case 0x6A:
+		return etm_read(ETMEXTOUTEVR2);
+	case 0x6B:
+		return etm_read(ETMEXTOUTEVR3);
+	case 0x6C:
+		return etm_read(ETMCIDCVR0);
+	case 0x6D:
+		return etm_read(ETMCIDCVR1);
+	case 0x6E:
+		return etm_read(ETMCIDCVR2);
+	case 0x6F:
+		return etm_read(ETMCIDCMR);
+	case 0x70:
+		return etm_read(ETMIMPSPEC0);
+	case 0x71:
+		return etm_read(ETMIMPSPEC1);
+	case 0x72:
+		return etm_read(ETMIMPSPEC2);
+	case 0x73:
+		return etm_read(ETMIMPSPEC3);
+	case 0x74:
+		return etm_read(ETMIMPSPEC4);
+	case 0x75:
+		return etm_read(ETMIMPSPEC5);
+	case 0x76:
+		return etm_read(ETMIMPSPEC6);
+	case 0x77:
+		return etm_read(ETMIMPSPEC7);
+	case 0x78:
+		return etm_read(ETMSYNCFR);
+	case 0x79:
+		return etm_read(ETMIDR);
+	case 0x7A:
+		return etm_read(ETMCCER);
+	case 0x7B:
+		return etm_read(ETMEXTINSELR);
+	case 0x7C:
+		return etm_read(ETMTESSEICR);
+	case 0x7D:
+		return etm_read(ETMEIBCR);
+	case 0x7E:
+		return etm_read(ETMTSEVR);
+	case 0x7F:
+		return etm_read(ETMAUXCR);
+	case 0x80:
+		return etm_read(ETMTRACEIDR);
+	case 0x90:
+		return etm_read(ETMVMIDCVR);
+	case 0xC1:
+		return etm_read(ETMOSLSR);
+	case 0xC2:
+		return etm_read(ETMOSSRR);
+	case 0xC4:
+		return etm_read(ETMPDCR);
+	case 0xC5:
+		return etm_read(ETMPDSR);
+	default:
+		WARN(1, "invalid CP14 access to ETM reg: %lx",
+							(unsigned long)reg);
+		return 0;
+	}
+}
+
+static void etm_write_reg(uint32_t val, uint32_t reg)
+{
+	switch (reg) {
+	case 0x0:
+		etm_write(val, ETMCR);
+		return;
+	case 0x2:
+		etm_write(val, ETMTRIGGER);
+		return;
+	case 0x4:
+		etm_write(val, ETMSR);
+		return;
+	case 0x6:
+		etm_write(val, ETMTSSCR);
+		return;
+	case 0x8:
+		etm_write(val, ETMTEEVR);
+		return;
+	case 0x9:
+		etm_write(val, ETMTECR1);
+		return;
+	case 0xB:
+		etm_write(val, ETMFFLR);
+		return;
+	case 0x10:
+		etm_write(val, ETMACVR0);
+		return;
+	case 0x11:
+		etm_write(val, ETMACVR1);
+		return;
+	case 0x12:
+		etm_write(val, ETMACVR2);
+		return;
+	case 0x13:
+		etm_write(val, ETMACVR3);
+		return;
+	case 0x14:
+		etm_write(val, ETMACVR4);
+		return;
+	case 0x15:
+		etm_write(val, ETMACVR5);
+		return;
+	case 0x16:
+		etm_write(val, ETMACVR6);
+		return;
+	case 0x17:
+		etm_write(val, ETMACVR7);
+		return;
+	case 0x18:
+		etm_write(val, ETMACVR8);
+		return;
+	case 0x19:
+		etm_write(val, ETMACVR9);
+		return;
+	case 0x1A:
+		etm_write(val, ETMACVR10);
+		return;
+	case 0x1B:
+		etm_write(val, ETMACVR11);
+		return;
+	case 0x1C:
+		etm_write(val, ETMACVR12);
+		return;
+	case 0x1D:
+		etm_write(val, ETMACVR13);
+		return;
+	case 0x1E:
+		etm_write(val, ETMACVR14);
+		return;
+	case 0x1F:
+		etm_write(val, ETMACVR15);
+		return;
+	case 0x20:
+		etm_write(val, ETMACTR0);
+		return;
+	case 0x21:
+		etm_write(val, ETMACTR1);
+		return;
+	case 0x22:
+		etm_write(val, ETMACTR2);
+		return;
+	case 0x23:
+		etm_write(val, ETMACTR3);
+		return;
+	case 0x24:
+		etm_write(val, ETMACTR4);
+		return;
+	case 0x25:
+		etm_write(val, ETMACTR5);
+		return;
+	case 0x26:
+		etm_write(val, ETMACTR6);
+		return;
+	case 0x27:
+		etm_write(val, ETMACTR7);
+		return;
+	case 0x28:
+		etm_write(val, ETMACTR8);
+		return;
+	case 0x29:
+		etm_write(val, ETMACTR9);
+		return;
+	case 0x2A:
+		etm_write(val, ETMACTR10);
+		return;
+	case 0x2B:
+		etm_write(val, ETMACTR11);
+		return;
+	case 0x2C:
+		etm_write(val, ETMACTR12);
+		return;
+	case 0x2D:
+		etm_write(val, ETMACTR13);
+		return;
+	case 0x2E:
+		etm_write(val, ETMACTR14);
+		return;
+	case 0x2F:
+		etm_write(val, ETMACTR15);
+		return;
+	case 0x50:
+		etm_write(val, ETMCNTRLDVR0);
+		return;
+	case 0x51:
+		etm_write(val, ETMCNTRLDVR1);
+		return;
+	case 0x52:
+		etm_write(val, ETMCNTRLDVR2);
+		return;
+	case 0x53:
+		etm_write(val, ETMCNTRLDVR3);
+		return;
+	case 0x54:
+		etm_write(val, ETMCNTENR0);
+		return;
+	case 0x55:
+		etm_write(val, ETMCNTENR1);
+		return;
+	case 0x56:
+		etm_write(val, ETMCNTENR2);
+		return;
+	case 0x57:
+		etm_write(val, ETMCNTENR3);
+		return;
+	case 0x58:
+		etm_write(val, ETMCNTRLDEVR0);
+		return;
+	case 0x59:
+		etm_write(val, ETMCNTRLDEVR1);
+		return;
+	case 0x5A:
+		etm_write(val, ETMCNTRLDEVR2);
+		return;
+	case 0x5B:
+		etm_write(val, ETMCNTRLDEVR3);
+		return;
+	case 0x5C:
+		etm_write(val, ETMCNTVR0);
+		return;
+	case 0x5D:
+		etm_write(val, ETMCNTVR1);
+		return;
+	case 0x5E:
+		etm_write(val, ETMCNTVR2);
+		return;
+	case 0x5F:
+		etm_write(val, ETMCNTVR3);
+		return;
+	case 0x60:
+		etm_write(val, ETMSQ12EVR);
+		return;
+	case 0x61:
+		etm_write(val, ETMSQ21EVR);
+		return;
+	case 0x62:
+		etm_write(val, ETMSQ23EVR);
+		return;
+	case 0x63:
+		etm_write(val, ETMSQ31EVR);
+		return;
+	case 0x64:
+		etm_write(val, ETMSQ32EVR);
+		return;
+	case 0x65:
+		etm_write(val, ETMSQ13EVR);
+		return;
+	case 0x67:
+		etm_write(val, ETMSQR);
+		return;
+	case 0x68:
+		etm_write(val, ETMEXTOUTEVR0);
+		return;
+	case 0x69:
+		etm_write(val, ETMEXTOUTEVR1);
+		return;
+	case 0x6A:
+		etm_write(val, ETMEXTOUTEVR2);
+		return;
+	case 0x6B:
+		etm_write(val, ETMEXTOUTEVR3);
+		return;
+	case 0x6C:
+		etm_write(val, ETMCIDCVR0);
+		return;
+	case 0x6D:
+		etm_write(val, ETMCIDCVR1);
+		return;
+	case 0x6E:
+		etm_write(val, ETMCIDCVR2);
+		return;
+	case 0x6F:
+		etm_write(val, ETMCIDCMR);
+		return;
+	case 0x70:
+		etm_write(val, ETMIMPSPEC0);
+		return;
+	case 0x71:
+		etm_write(val, ETMIMPSPEC1);
+		return;
+	case 0x72:
+		etm_write(val, ETMIMPSPEC2);
+		return;
+	case 0x73:
+		etm_write(val, ETMIMPSPEC3);
+		return;
+	case 0x74:
+		etm_write(val, ETMIMPSPEC4);
+		return;
+	case 0x75:
+		etm_write(val, ETMIMPSPEC5);
+		return;
+	case 0x76:
+		etm_write(val, ETMIMPSPEC6);
+		return;
+	case 0x77:
+		etm_write(val, ETMIMPSPEC7);
+		return;
+	case 0x78:
+		etm_write(val, ETMSYNCFR);
+		return;
+	case 0x7B:
+		etm_write(val, ETMEXTINSELR);
+		return;
+	case 0x7C:
+		etm_write(val, ETMTESSEICR);
+		return;
+	case 0x7D:
+		etm_write(val, ETMEIBCR);
+		return;
+	case 0x7E:
+		etm_write(val, ETMTSEVR);
+		return;
+	case 0x7F:
+		etm_write(val, ETMAUXCR);
+		return;
+	case 0x80:
+		etm_write(val, ETMTRACEIDR);
+		return;
+	case 0x90:
+		etm_write(val, ETMVMIDCVR);
+		return;
+	case 0xC0:
+		etm_write(val, ETMOSLAR);
+		return;
+	case 0xC2:
+		etm_write(val, ETMOSSRR);
+		return;
+	case 0xC4:
+		etm_write(val, ETMPDCR);
+		return;
+	case 0xC5:
+		etm_write(val, ETMPDSR);
+		return;
+	default:
+		WARN(1, "invalid CP14 access to ETM reg: %lx",
+							(unsigned long)reg);
+		return;
+	}
+}
+
+static inline uint32_t offset_to_reg_num(uint32_t off)
+{
+	return off >> 2;
+}
+
+unsigned int etm_readl_cp14(uint32_t off)
+{
+	uint32_t reg = offset_to_reg_num(off);
+	return etm_read_reg(reg);
+}
+
+void etm_writel_cp14(uint32_t val, uint32_t off)
+{
+	uint32_t reg = offset_to_reg_num(off);
+	etm_write_reg(val, reg);
+}
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
new file mode 100644
index 0000000..e15763f
--- /dev/null
+++ b/drivers/coresight/coresight-etm.c
@@ -0,0 +1,1752 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/sysfs.h>
+#include <linux/stat.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/of.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <asm/sections.h>
+
+#include "coresight-priv.h"
+
+#define etm_writel_mm(drvdata, val, off)  \
+			__raw_writel((val), drvdata->base + off)
+#define etm_readl_mm(drvdata, off)        \
+			__raw_readl(drvdata->base + off)
+
+#define etm_writel(drvdata, val, off)					\
+({									\
+	if (drvdata->use_cp14)						\
+		etm_writel_cp14(val, off);				\
+	else								\
+		etm_writel_mm(drvdata, val, off);			\
+})
+#define etm_readl(drvdata, off)						\
+({									\
+	uint32_t val;							\
+	if (drvdata->use_cp14)						\
+		val = etm_readl_cp14(off);				\
+	else								\
+		val = etm_readl_mm(drvdata, off);			\
+	val;								\
+})
+
+#define ETM_LOCK(drvdata)						\
+do {									\
+	/*
+	 * Recommended by spec to ensure ETM writes are committed prior
+	 * to resuming execution
+	 */								\
+	mb();								\
+	isb();								\
+	etm_writel_mm(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define ETM_UNLOCK(drvdata)						\
+do {									\
+	etm_writel_mm(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
+	/*
+	 * Ensure unlock and any pending writes are committed prior to
+	 * programming ETM registers
+	 */								\
+	mb();								\
+	isb();								\
+} while (0)
+
+/*
+ * Device registers:
+ * 0x000 - 0x2FC: Trace		registers
+ * 0x300 - 0x314: Management	registers
+ * 0x318 - 0xEFC: Trace		registers
+ *
+ * Coresight registers
+ * 0xF00 - 0xF9C: Management	registers
+ * 0xFA0 - 0xFA4: Management	registers in PFTv1.0
+ *		  Trace		registers in PFTv1.1
+ * 0xFA8 - 0xFFC: Management	registers
+ */
+
+/* Trace registers (0x000-0x2FC) */
+#define ETMCR			(0x000)
+#define ETMCCR			(0x004)
+#define ETMTRIGGER		(0x008)
+#define ETMSR			(0x010)
+#define ETMSCR			(0x014)
+#define ETMTSSCR		(0x018)
+#define ETMTEEVR		(0x020)
+#define ETMTECR1		(0x024)
+#define ETMFFLR			(0x02C)
+#define ETMACVRn(n)		(0x040 + (n * 4))
+#define ETMACTRn(n)		(0x080 + (n * 4))
+#define ETMCNTRLDVRn(n)		(0x140 + (n * 4))
+#define ETMCNTENRn(n)		(0x150 + (n * 4))
+#define ETMCNTRLDEVRn(n)	(0x160 + (n * 4))
+#define ETMCNTVRn(n)		(0x170 + (n * 4))
+#define ETMSQ12EVR		(0x180)
+#define ETMSQ21EVR		(0x184)
+#define ETMSQ23EVR		(0x188)
+#define ETMSQ31EVR		(0x18C)
+#define ETMSQ32EVR		(0x190)
+#define ETMSQ13EVR		(0x194)
+#define ETMSQR			(0x19C)
+#define ETMEXTOUTEVRn(n)	(0x1A0 + (n * 4))
+#define ETMCIDCVRn(n)		(0x1B0 + (n * 4))
+#define ETMCIDCMR		(0x1BC)
+#define ETMIMPSPEC0		(0x1C0)
+#define ETMIMPSPEC1		(0x1C4)
+#define ETMIMPSPEC2		(0x1C8)
+#define ETMIMPSPEC3		(0x1CC)
+#define ETMIMPSPEC4		(0x1D0)
+#define ETMIMPSPEC5		(0x1D4)
+#define ETMIMPSPEC6		(0x1D8)
+#define ETMIMPSPEC7		(0x1DC)
+#define ETMSYNCFR		(0x1E0)
+#define ETMIDR			(0x1E4)
+#define ETMCCER			(0x1E8)
+#define ETMEXTINSELR		(0x1EC)
+#define ETMTESSEICR		(0x1F0)
+#define ETMEIBCR		(0x1F4)
+#define ETMTSEVR		(0x1F8)
+#define ETMAUXCR		(0x1FC)
+#define ETMTRACEIDR		(0x200)
+#define ETMVMIDCVR		(0x240)
+/* Management registers (0x300-0x314) */
+#define ETMOSLAR		(0x300)
+#define ETMOSLSR		(0x304)
+#define ETMOSSRR		(0x308)
+#define ETMPDCR			(0x310)
+#define ETMPDSR			(0x314)
+
+#define ETM_MAX_ADDR_CMP	(16)
+#define ETM_MAX_CNTR		(4)
+#define ETM_MAX_CTXID_CMP	(3)
+
+#define ETM_MODE_EXCLUDE	BIT(0)
+#define ETM_MODE_CYCACC		BIT(1)
+#define ETM_MODE_STALL		BIT(2)
+#define ETM_MODE_TIMESTAMP	BIT(3)
+#define ETM_MODE_CTXID		BIT(4)
+#define ETM_MODE_ALL		(0x1F)
+
+#define ETM_EVENT_MASK		(0x1FFFF)
+#define ETM_SYNC_MASK		(0xFFF)
+#define ETM_ALL_MASK		(0xFFFFFFFF)
+
+#define ETM_SEQ_STATE_MAX_VAL	(0x2)
+
+enum etm_addr_type {
+	ETM_ADDR_TYPE_NONE,
+	ETM_ADDR_TYPE_SINGLE,
+	ETM_ADDR_TYPE_RANGE,
+	ETM_ADDR_TYPE_START,
+	ETM_ADDR_TYPE_STOP,
+};
+
+#ifdef CONFIG_CORESIGHT_SOURCE_ETM_DEFAULT_ENABLE
+static int boot_enable = 1;
+#else
+static int boot_enable;
+#endif
+module_param_named(
+	boot_enable, boot_enable, int, S_IRUGO
+);
+
+struct etm_drvdata {
+	void __iomem			*base;
+	struct device			*dev;
+	struct coresight_device		*csdev;
+	struct clk			*clk;
+	spinlock_t			spinlock;
+	int				cpu;
+	uint8_t				arch;
+	bool				use_cp14;
+	bool				enable;
+	bool				sticky_enable;
+	bool				boot_enable;
+	bool				os_unlock;
+	uint8_t				nr_addr_cmp;
+	uint8_t				nr_cntr;
+	uint8_t				nr_ext_inp;
+	uint8_t				nr_ext_out;
+	uint8_t				nr_ctxid_cmp;
+	uint8_t				reset;
+	uint32_t			mode;
+	uint32_t			ctrl;
+	uint32_t			trigger_event;
+	uint32_t			startstop_ctrl;
+	uint32_t			enable_event;
+	uint32_t			enable_ctrl1;
+	uint32_t			fifofull_level;
+	uint8_t				addr_idx;
+	uint32_t			addr_val[ETM_MAX_ADDR_CMP];
+	uint32_t			addr_acctype[ETM_MAX_ADDR_CMP];
+	uint32_t			addr_type[ETM_MAX_ADDR_CMP];
+	uint8_t				cntr_idx;
+	uint32_t			cntr_rld_val[ETM_MAX_CNTR];
+	uint32_t			cntr_event[ETM_MAX_CNTR];
+	uint32_t			cntr_rld_event[ETM_MAX_CNTR];
+	uint32_t			cntr_val[ETM_MAX_CNTR];
+	uint32_t			seq_12_event;
+	uint32_t			seq_21_event;
+	uint32_t			seq_23_event;
+	uint32_t			seq_31_event;
+	uint32_t			seq_32_event;
+	uint32_t			seq_13_event;
+	uint32_t			seq_curr_state;
+	uint8_t				ctxid_idx;
+	uint32_t			ctxid_val[ETM_MAX_CTXID_CMP];
+	uint32_t			ctxid_mask;
+	uint32_t			sync_freq;
+	uint32_t			timestamp_event;
+};
+
+static struct etm_drvdata *etmdrvdata[NR_CPUS];
+
+/*
+ * Memory mapped writes to clear os lock are not supported on some processors
+ * and OS lock must be unlocked before any memory mapped access on such
+ * processors, otherwise memory mapped reads/writes will be invalid.
+ */
+static void etm_os_unlock(void *info)
+{
+	etm_writel_cp14(0x0, ETMOSLAR);
+	isb();
+}
+
+static void etm_set_pwrdwn(struct etm_drvdata *drvdata)
+{
+	uint32_t etmcr;
+
+	/* Ensure pending cp14 accesses complete before setting pwrdwn */
+	mb();
+	isb();
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr |= BIT(0);
+	etm_writel(drvdata, etmcr, ETMCR);
+}
+
+static void etm_clr_pwrdwn(struct etm_drvdata *drvdata)
+{
+	uint32_t etmcr;
+
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr &= ~BIT(0);
+	etm_writel(drvdata, etmcr, ETMCR);
+	/* Ensure pwrup completes before subsequent cp14 accesses */
+	mb();
+	isb();
+}
+
+static void etm_set_pwrup(struct etm_drvdata *drvdata)
+{
+	uint32_t etmpdcr;
+
+	etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
+	etmpdcr |= BIT(3);
+	etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
+	/* Ensure pwrup completes before subsequent cp14 accesses */
+	mb();
+	isb();
+}
+
+static void etm_clr_pwrup(struct etm_drvdata *drvdata)
+{
+	uint32_t etmpdcr;
+
+	/* Ensure pending cp14 accesses complete before clearing pwrup */
+	mb();
+	isb();
+	etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
+	etmpdcr &= ~BIT(3);
+	etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
+}
+
+static void etm_set_prog(struct etm_drvdata *drvdata)
+{
+	uint32_t etmcr;
+	int count;
+
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr |= BIT(10);
+	etm_writel(drvdata, etmcr, ETMCR);
+	/*
+	 * Recommended by spec for cp14 accesses to ensure etmcr write is
+	 * complete before polling etmsr
+	 */
+	isb();
+	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 1
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while setting prog bit, ETMSR: %#x\n",
+	     etm_readl(drvdata, ETMSR));
+}
+
+static void etm_clr_prog(struct etm_drvdata *drvdata)
+{
+	uint32_t etmcr;
+	int count;
+
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr &= ~BIT(10);
+	etm_writel(drvdata, etmcr, ETMCR);
+	/*
+	 * Recommended by spec for cp14 accesses to ensure etmcr write is
+	 * complete before polling etmsr
+	 */
+	isb();
+	for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 0
+				&& count > 0; count--)
+		udelay(1);
+	WARN(count == 0, "timeout while clearing prog bit, ETMSR: %#x\n",
+	     etm_readl(drvdata, ETMSR));
+}
+
+static void __etm_enable(void *info)
+{
+	int i;
+	uint32_t etmcr;
+	struct etm_drvdata *drvdata = info;
+
+	ETM_UNLOCK(drvdata);
+	/* Vote for ETM power/clock enable */
+	etm_set_pwrup(drvdata);
+	/*
+	 * Clear power down bit since when this bit is set writes to
+	 * certain registers might be ignored. This is also a pre-requisite
+	 * for trace enable.
+	 */
+	etm_clr_pwrdwn(drvdata);
+	etm_clr_pwrup(drvdata);
+	etm_set_prog(drvdata);
+
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr &= (BIT(10) | BIT(0));
+	etm_writel(drvdata, drvdata->ctrl | etmcr, ETMCR);
+	etm_writel(drvdata, drvdata->trigger_event, ETMTRIGGER);
+	etm_writel(drvdata, drvdata->startstop_ctrl, ETMTSSCR);
+	etm_writel(drvdata, drvdata->enable_event, ETMTEEVR);
+	etm_writel(drvdata, drvdata->enable_ctrl1, ETMTECR1);
+	etm_writel(drvdata, drvdata->fifofull_level, ETMFFLR);
+	for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+		etm_writel(drvdata, drvdata->addr_val[i], ETMACVRn(i));
+		etm_writel(drvdata, drvdata->addr_acctype[i], ETMACTRn(i));
+	}
+	for (i = 0; i < drvdata->nr_cntr; i++) {
+		etm_writel(drvdata, drvdata->cntr_rld_val[i], ETMCNTRLDVRn(i));
+		etm_writel(drvdata, drvdata->cntr_event[i], ETMCNTENRn(i));
+		etm_writel(drvdata, drvdata->cntr_rld_event[i],
+			   ETMCNTRLDEVRn(i));
+		etm_writel(drvdata, drvdata->cntr_val[i], ETMCNTVRn(i));
+	}
+	etm_writel(drvdata, drvdata->seq_12_event, ETMSQ12EVR);
+	etm_writel(drvdata, drvdata->seq_21_event, ETMSQ21EVR);
+	etm_writel(drvdata, drvdata->seq_23_event, ETMSQ23EVR);
+	etm_writel(drvdata, drvdata->seq_31_event, ETMSQ31EVR);
+	etm_writel(drvdata, drvdata->seq_32_event, ETMSQ32EVR);
+	etm_writel(drvdata, drvdata->seq_13_event, ETMSQ13EVR);
+	etm_writel(drvdata, drvdata->seq_curr_state, ETMSQR);
+	for (i = 0; i < drvdata->nr_ext_out; i++)
+		etm_writel(drvdata, 0x0000406F, ETMEXTOUTEVRn(i));
+	for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
+		etm_writel(drvdata, drvdata->ctxid_val[i], ETMCIDCVRn(i));
+	etm_writel(drvdata, drvdata->ctxid_mask, ETMCIDCMR);
+	etm_writel(drvdata, drvdata->sync_freq, ETMSYNCFR);
+	etm_writel(drvdata, 0x00000000, ETMEXTINSELR);
+	etm_writel(drvdata, drvdata->timestamp_event, ETMTSEVR);
+	etm_writel(drvdata, 0x00000000, ETMAUXCR);
+	etm_writel(drvdata, drvdata->cpu + 1, ETMTRACEIDR);
+	etm_writel(drvdata, 0x00000000, ETMVMIDCVR);
+
+	etm_clr_prog(drvdata);
+	ETM_LOCK(drvdata);
+
+	dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
+}
+
+static int etm_enable(struct coresight_device *csdev)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	int ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		goto err_clk;
+
+	spin_lock(&drvdata->spinlock);
+
+	/*
+	 * Executing __etm_enable on the cpu whose ETM is being enabled
+	 * ensures that register writes occur when cpu is powered.
+	 */
+	ret = smp_call_function_single(drvdata->cpu, __etm_enable, drvdata, 1);
+	if (ret)
+		goto err;
+	drvdata->enable = true;
+	drvdata->sticky_enable = true;
+
+	spin_unlock(&drvdata->spinlock);
+
+	dev_info(drvdata->dev, "ETM tracing enabled\n");
+	return 0;
+err:
+	spin_unlock(&drvdata->spinlock);
+	clk_disable_unprepare(drvdata->clk);
+err_clk:
+	return ret;
+}
+
+static void __etm_disable(void *info)
+{
+	struct etm_drvdata *drvdata = info;
+
+	ETM_UNLOCK(drvdata);
+	etm_set_prog(drvdata);
+
+	/* Program trace enable to low by using always false event */
+	etm_writel(drvdata, 0x6F | BIT(14), ETMTEEVR);
+
+	etm_set_pwrdwn(drvdata);
+	ETM_LOCK(drvdata);
+
+	dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
+}
+
+static void etm_disable(struct coresight_device *csdev)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+	/*
+	 * Taking hotplug lock here protects from clocks getting disabled
+	 * with tracing being left on (crash scenario) if user disable occurs
+	 * after cpu online mask indicates the cpu is offline but before the
+	 * DYING hotplug callback is serviced by the ETM driver.
+	 */
+	get_online_cpus();
+	spin_lock(&drvdata->spinlock);
+
+	/*
+	 * Executing __etm_disable on the cpu whose ETM is being disabled
+	 * ensures that register writes occur when cpu is powered.
+	 */
+	smp_call_function_single(drvdata->cpu, __etm_disable, drvdata, 1);
+	drvdata->enable = false;
+
+	spin_unlock(&drvdata->spinlock);
+	put_online_cpus();
+
+	clk_disable_unprepare(drvdata->clk);
+
+	dev_info(drvdata->dev, "ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source etm_source_ops = {
+	.enable		= etm_enable,
+	.disable	= etm_disable,
+};
+
+static const struct coresight_ops etm_cs_ops = {
+	.source_ops	= &etm_source_ops,
+};
+
+static ssize_t etm_show_nr_addr_cmp(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->nr_addr_cmp;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR(nr_addr_cmp, S_IRUGO, etm_show_nr_addr_cmp, NULL);
+
+static ssize_t etm_show_nr_cntr(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->nr_cntr;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR(nr_cntr, S_IRUGO, etm_show_nr_cntr, NULL);
+
+static ssize_t etm_show_nr_ctxid_cmp(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->nr_ctxid_cmp;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR(nr_ctxid_cmp, S_IRUGO, etm_show_nr_ctxid_cmp, NULL);
+
+static ssize_t etm_show_reset(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->reset;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+/* Reset to trace everything i.e. exclude nothing. */
+static ssize_t etm_store_reset(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	int i;
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	if (val) {
+		drvdata->mode = ETM_MODE_EXCLUDE;
+		drvdata->ctrl = 0x0;
+		drvdata->trigger_event = 0x406F;
+		drvdata->startstop_ctrl = 0x0;
+		drvdata->enable_event = 0x6F;
+		drvdata->enable_ctrl1 = 0x1000000;
+		drvdata->fifofull_level = 0x28;
+		drvdata->addr_idx = 0x0;
+		for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+			drvdata->addr_val[i] = 0x0;
+			drvdata->addr_acctype[i] = 0x0;
+			drvdata->addr_type[i] = ETM_ADDR_TYPE_NONE;
+		}
+		drvdata->cntr_idx = 0x0;
+		for (i = 0; i < drvdata->nr_cntr; i++) {
+			drvdata->cntr_rld_val[i] = 0x0;
+			drvdata->cntr_event[i] = 0x406F;
+			drvdata->cntr_rld_event[i] = 0x406F;
+			drvdata->cntr_val[i] = 0x0;
+		}
+		drvdata->seq_12_event = 0x406F;
+		drvdata->seq_21_event = 0x406F;
+		drvdata->seq_23_event = 0x406F;
+		drvdata->seq_31_event = 0x406F;
+		drvdata->seq_32_event = 0x406F;
+		drvdata->seq_13_event = 0x406F;
+		drvdata->seq_curr_state = 0x0;
+		drvdata->ctxid_idx = 0x0;
+		for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
+			drvdata->ctxid_val[i] = 0x0;
+		drvdata->ctxid_mask = 0x0;
+		drvdata->sync_freq = 0x100;
+		drvdata->timestamp_event = 0x406F;
+	}
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(reset, S_IRUGO | S_IWUSR, etm_show_reset, etm_store_reset);
+
+static ssize_t etm_show_mode(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->mode;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_mode(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->mode = val & ETM_MODE_ALL;
+
+	if (drvdata->mode & ETM_MODE_EXCLUDE)
+		drvdata->enable_ctrl1 |= BIT(24);
+	else
+		drvdata->enable_ctrl1 &= ~BIT(24);
+
+	if (drvdata->mode & ETM_MODE_CYCACC)
+		drvdata->ctrl |= BIT(12);
+	else
+		drvdata->ctrl &= ~BIT(12);
+
+	if (drvdata->mode & ETM_MODE_STALL)
+		drvdata->ctrl |= BIT(7);
+	else
+		drvdata->ctrl &= ~BIT(7);
+
+	if (drvdata->mode & ETM_MODE_TIMESTAMP)
+		drvdata->ctrl |= BIT(28);
+	else
+		drvdata->ctrl &= ~BIT(28);
+
+	if (drvdata->mode & ETM_MODE_CTXID)
+		drvdata->ctrl |= (BIT(14) | BIT(15));
+	else
+		drvdata->ctrl &= ~(BIT(14) | BIT(15));
+	spin_unlock(&drvdata->spinlock);
+
+	return size;
+}
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, etm_show_mode, etm_store_mode);
+
+static ssize_t etm_show_trigger_event(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->trigger_event;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_trigger_event(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->trigger_event = val & ETM_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR(trigger_event, S_IRUGO | S_IWUSR, etm_show_trigger_event,
+		   etm_store_trigger_event);
+
+static ssize_t etm_show_enable_event(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->enable_event;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_enable_event(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->enable_event = val & ETM_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR(enable_event, S_IRUGO | S_IWUSR, etm_show_enable_event,
+		   etm_store_enable_event);
+
+static ssize_t etm_show_fifofull_level(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->fifofull_level;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_fifofull_level(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->fifofull_level = val;
+	return size;
+}
+static DEVICE_ATTR(fifofull_level, S_IRUGO | S_IWUSR, etm_show_fifofull_level,
+		   etm_store_fifofull_level);
+
+static ssize_t etm_show_addr_idx(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->addr_idx;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_addr_idx(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val >= drvdata->nr_addr_cmp)
+		return -EINVAL;
+
+	/*
+	 * Use spinlock to ensure index doesn't change while it gets
+	 * dereferenced multiple times within a spinlock block elsewhere.
+	 */
+	spin_lock(&drvdata->spinlock);
+	drvdata->addr_idx = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(addr_idx, S_IRUGO | S_IWUSR, etm_show_addr_idx,
+		   etm_store_addr_idx);
+
+static ssize_t etm_show_addr_single(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	uint8_t idx;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	val = drvdata->addr_val[idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_addr_single(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_SINGLE)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	drvdata->addr_val[idx] = val;
+	drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(addr_single, S_IRUGO | S_IWUSR, etm_show_addr_single,
+		   etm_store_addr_single);
+
+static ssize_t etm_show_addr_range(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val1, val2;
+	uint8_t idx;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (idx % 2 != 0) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+	if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+	      (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	val1 = drvdata->addr_val[idx];
+	val2 = drvdata->addr_val[idx + 1];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
+}
+
+static ssize_t etm_store_addr_range(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val1, val2;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx %lx", &val1, &val2) != 2)
+		return -EINVAL;
+	/* Lower address comparator cannot have a higher address value */
+	if (val1 > val2)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (idx % 2 != 0) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+	if (!((drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE &&
+	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_NONE) ||
+	      (drvdata->addr_type[idx] == ETM_ADDR_TYPE_RANGE &&
+	       drvdata->addr_type[idx + 1] == ETM_ADDR_TYPE_RANGE))) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	drvdata->addr_val[idx] = val1;
+	drvdata->addr_type[idx] = ETM_ADDR_TYPE_RANGE;
+	drvdata->addr_val[idx + 1] = val2;
+	drvdata->addr_type[idx + 1] = ETM_ADDR_TYPE_RANGE;
+	drvdata->enable_ctrl1 |= (1 << (idx/2));
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(addr_range, S_IRUGO | S_IWUSR, etm_show_addr_range,
+		   etm_store_addr_range);
+
+static ssize_t etm_show_addr_start(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	uint8_t idx;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	val = drvdata->addr_val[idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_addr_start(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_START)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	drvdata->addr_val[idx] = val;
+	drvdata->addr_type[idx] = ETM_ADDR_TYPE_START;
+	drvdata->startstop_ctrl |= (1 << idx);
+	drvdata->enable_ctrl1 |= BIT(25);
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(addr_start, S_IRUGO | S_IWUSR, etm_show_addr_start,
+		   etm_store_addr_start);
+
+static ssize_t etm_show_addr_stop(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	uint8_t idx;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	val = drvdata->addr_val[idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_addr_stop(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+	uint8_t idx;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = drvdata->addr_idx;
+	if (!(drvdata->addr_type[idx] == ETM_ADDR_TYPE_NONE ||
+	      drvdata->addr_type[idx] == ETM_ADDR_TYPE_STOP)) {
+		spin_unlock(&drvdata->spinlock);
+		return -EPERM;
+	}
+
+	drvdata->addr_val[idx] = val;
+	drvdata->addr_type[idx] = ETM_ADDR_TYPE_STOP;
+	drvdata->startstop_ctrl |= (1 << (idx + 16));
+	drvdata->enable_ctrl1 |= BIT(25);
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(addr_stop, S_IRUGO | S_IWUSR, etm_show_addr_stop,
+		   etm_store_addr_stop);
+
+static ssize_t etm_show_addr_acctype(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->addr_acctype[drvdata->addr_idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_addr_acctype(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->addr_acctype[drvdata->addr_idx] = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(addr_acctype, S_IRUGO | S_IWUSR, etm_show_addr_acctype,
+		   etm_store_addr_acctype);
+
+static ssize_t etm_show_cntr_idx(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->addr_idx;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_cntr_idx(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val >= drvdata->nr_cntr)
+		return -EINVAL;
+
+	/*
+	 * Use spinlock to ensure index doesn't change while it gets
+	 * dereferenced multiple times within a spinlock block elsewhere.
+	 */
+	spin_lock(&drvdata->spinlock);
+	drvdata->cntr_idx = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(cntr_idx, S_IRUGO | S_IWUSR, etm_show_cntr_idx,
+		   etm_store_cntr_idx);
+
+static ssize_t etm_show_cntr_rld_val(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->cntr_rld_val[drvdata->cntr_idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_cntr_rld_val(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->cntr_rld_val[drvdata->cntr_idx] = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(cntr_rld_val, S_IRUGO | S_IWUSR, etm_show_cntr_rld_val,
+		   etm_store_cntr_rld_val);
+
+static ssize_t etm_show_cntr_event(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->cntr_event[drvdata->cntr_idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_cntr_event(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->cntr_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(cntr_event, S_IRUGO | S_IWUSR, etm_show_cntr_event,
+		   etm_store_cntr_event);
+
+static ssize_t etm_show_cntr_rld_event(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->cntr_rld_event[drvdata->cntr_idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_cntr_rld_event(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->cntr_rld_event[drvdata->cntr_idx] = val & ETM_EVENT_MASK;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(cntr_rld_event, S_IRUGO | S_IWUSR, etm_show_cntr_rld_event,
+		   etm_store_cntr_rld_event);
+
+static ssize_t etm_show_cntr_val(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->cntr_val[drvdata->cntr_idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_cntr_val(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->cntr_val[drvdata->cntr_idx] = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(cntr_val, S_IRUGO | S_IWUSR, etm_show_cntr_val,
+		   etm_store_cntr_val);
+
+static ssize_t etm_show_seq_12_event(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->seq_12_event;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_seq_12_event(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_12_event = val & ETM_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR(seq_12_event, S_IRUGO | S_IWUSR, etm_show_seq_12_event,
+		   etm_store_seq_12_event);
+
+static ssize_t etm_show_seq_21_event(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->seq_21_event;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_seq_21_event(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_21_event = val & ETM_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR(seq_21_event, S_IRUGO | S_IWUSR, etm_show_seq_21_event,
+		   etm_store_seq_21_event);
+
+static ssize_t etm_show_seq_23_event(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->seq_23_event;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_seq_23_event(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_23_event = val & ETM_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR(seq_23_event, S_IRUGO | S_IWUSR, etm_show_seq_23_event,
+		   etm_store_seq_23_event);
+
+static ssize_t etm_show_seq_31_event(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->seq_31_event;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_seq_31_event(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_31_event = val & ETM_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR(seq_31_event, S_IRUGO | S_IWUSR, etm_show_seq_31_event,
+		   etm_store_seq_31_event);
+
+static ssize_t etm_show_seq_32_event(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->seq_32_event;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_seq_32_event(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_32_event = val & ETM_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR(seq_32_event, S_IRUGO | S_IWUSR, etm_show_seq_32_event,
+		   etm_store_seq_32_event);
+
+static ssize_t etm_show_seq_13_event(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->seq_13_event;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_seq_13_event(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_13_event = val & ETM_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR(seq_13_event, S_IRUGO | S_IWUSR, etm_show_seq_13_event,
+		   etm_store_seq_13_event);
+
+static ssize_t etm_show_seq_curr_state(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->seq_curr_state;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_seq_curr_state(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val > ETM_SEQ_STATE_MAX_VAL)
+		return -EINVAL;
+
+	drvdata->seq_curr_state = val;
+	return size;
+}
+static DEVICE_ATTR(seq_curr_state, S_IRUGO | S_IWUSR, etm_show_seq_curr_state,
+		   etm_store_seq_curr_state);
+
+static ssize_t etm_show_ctxid_idx(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->ctxid_idx;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_ctxid_idx(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val >= drvdata->nr_ctxid_cmp)
+		return -EINVAL;
+
+	/*
+	 * Use spinlock to ensure index doesn't change while it gets
+	 * dereferenced multiple times within a spinlock block elsewhere.
+	 */
+	spin_lock(&drvdata->spinlock);
+	drvdata->ctxid_idx = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(ctxid_idx, S_IRUGO | S_IWUSR, etm_show_ctxid_idx,
+		   etm_store_ctxid_idx);
+
+static ssize_t etm_show_ctxid_val(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->ctxid_val[drvdata->ctxid_idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_ctxid_val(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->ctxid_val[drvdata->ctxid_idx] = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR(ctxid_val, S_IRUGO | S_IWUSR, etm_show_ctxid_val,
+		   etm_store_ctxid_val);
+
+static ssize_t etm_show_ctxid_mask(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->ctxid_mask;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_ctxid_mask(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->ctxid_mask = val;
+	return size;
+}
+static DEVICE_ATTR(ctxid_mask, S_IRUGO | S_IWUSR, etm_show_ctxid_mask,
+		   etm_store_ctxid_mask);
+
+static ssize_t etm_show_sync_freq(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->sync_freq;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_sync_freq(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->sync_freq = val & ETM_SYNC_MASK;
+	return size;
+}
+static DEVICE_ATTR(sync_freq, S_IRUGO | S_IWUSR, etm_show_sync_freq,
+		   etm_store_sync_freq);
+
+static ssize_t etm_show_timestamp_event(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val = drvdata->timestamp_event;
+
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t etm_store_timestamp_event(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t size)
+{
+	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->timestamp_event = val & ETM_EVENT_MASK;
+	return size;
+}
+static DEVICE_ATTR(timestamp_event, S_IRUGO | S_IWUSR, etm_show_timestamp_event,
+		   etm_store_timestamp_event);
+
+static struct attribute *etm_attrs[] = {
+	&dev_attr_nr_addr_cmp.attr,
+	&dev_attr_nr_cntr.attr,
+	&dev_attr_nr_ctxid_cmp.attr,
+	&dev_attr_reset.attr,
+	&dev_attr_mode.attr,
+	&dev_attr_trigger_event.attr,
+	&dev_attr_enable_event.attr,
+	&dev_attr_fifofull_level.attr,
+	&dev_attr_addr_idx.attr,
+	&dev_attr_addr_single.attr,
+	&dev_attr_addr_range.attr,
+	&dev_attr_addr_start.attr,
+	&dev_attr_addr_stop.attr,
+	&dev_attr_addr_acctype.attr,
+	&dev_attr_cntr_idx.attr,
+	&dev_attr_cntr_rld_val.attr,
+	&dev_attr_cntr_event.attr,
+	&dev_attr_cntr_rld_event.attr,
+	&dev_attr_cntr_val.attr,
+	&dev_attr_seq_12_event.attr,
+	&dev_attr_seq_21_event.attr,
+	&dev_attr_seq_23_event.attr,
+	&dev_attr_seq_31_event.attr,
+	&dev_attr_seq_32_event.attr,
+	&dev_attr_seq_13_event.attr,
+	&dev_attr_seq_curr_state.attr,
+	&dev_attr_ctxid_idx.attr,
+	&dev_attr_ctxid_val.attr,
+	&dev_attr_ctxid_mask.attr,
+	&dev_attr_sync_freq.attr,
+	&dev_attr_timestamp_event.attr,
+	NULL,
+};
+
+static struct attribute_group etm_attr_grp = {
+	.attrs = etm_attrs,
+};
+
+static const struct attribute_group *etm_attr_grps[] = {
+	&etm_attr_grp,
+	NULL,
+};
+
+static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
+			    void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+
+	if (!etmdrvdata[cpu])
+		goto out;
+
+	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_STARTING:
+		spin_lock(&etmdrvdata[cpu]->spinlock);
+		if (!etmdrvdata[cpu]->os_unlock) {
+			etm_os_unlock(etmdrvdata[cpu]);
+			etmdrvdata[cpu]->os_unlock = true;
+		}
+
+		if (etmdrvdata[cpu]->enable)
+			__etm_enable(etmdrvdata[cpu]);
+		spin_unlock(&etmdrvdata[cpu]->spinlock);
+		break;
+
+	case CPU_ONLINE:
+		if (etmdrvdata[cpu]->boot_enable &&
+		    !etmdrvdata[cpu]->sticky_enable)
+			coresight_enable(etmdrvdata[cpu]->csdev);
+
+	case CPU_DYING:
+		spin_lock(&etmdrvdata[cpu]->spinlock);
+		if (etmdrvdata[cpu]->enable)
+			__etm_disable(etmdrvdata[cpu]);
+		spin_unlock(&etmdrvdata[cpu]->spinlock);
+		break;
+	}
+out:
+	return NOTIFY_OK;
+}
+
+static struct notifier_block etm_cpu_notifier = {
+	.notifier_call = etm_cpu_callback,
+};
+
+static bool __devinit etm_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case PFT_ARCH_V1_1:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static void __devinit etm_init_arch_data(void *info)
+{
+	uint32_t etmidr;
+	uint32_t etmccr;
+	struct etm_drvdata *drvdata = info;
+
+	ETM_UNLOCK(drvdata);
+	/* Vote for ETM power/clock enable */
+	etm_set_pwrup(drvdata);
+	/*
+	 * Clear power down bit since when this bit is set writes to
+	 * certain registers might be ignored.
+	 */
+	etm_clr_pwrdwn(drvdata);
+	etm_clr_pwrup(drvdata);
+	/*
+	 * Set prog bit. It will be set from reset but this is included to
+	 * ensure it is set
+	 */
+	etm_set_prog(drvdata);
+
+	/* Find all capabilities */
+	etmidr = etm_readl(drvdata, ETMIDR);
+	drvdata->arch = BMVAL(etmidr, 4, 11);
+
+	etmccr = etm_readl(drvdata, ETMCCR);
+	drvdata->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
+	drvdata->nr_cntr = BMVAL(etmccr, 13, 15);
+	drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19);
+	drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
+	drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+
+	etm_set_pwrdwn(drvdata);
+	ETM_LOCK(drvdata);
+}
+
+static void __devinit etm_copy_arch_data(struct etm_drvdata *drvdata)
+{
+	drvdata->arch = etmdrvdata[0]->arch;
+	drvdata->nr_addr_cmp = etmdrvdata[0]->nr_addr_cmp;
+	drvdata->nr_cntr = etmdrvdata[0]->nr_cntr;
+	drvdata->nr_ext_inp = etmdrvdata[0]->nr_ext_inp;
+	drvdata->nr_ext_out = etmdrvdata[0]->nr_ext_out;
+	drvdata->nr_ctxid_cmp = etmdrvdata[0]->nr_ctxid_cmp;
+}
+
+static void __devinit etm_init_default_data(struct etm_drvdata *drvdata)
+{
+	int i;
+
+	drvdata->trigger_event = 0x406F;
+	drvdata->enable_event = 0x6F;
+	drvdata->enable_ctrl1 = 0x1;
+	drvdata->fifofull_level	= 0x28;
+	if (drvdata->nr_addr_cmp >= 2) {
+		drvdata->addr_val[0] = (uint32_t) _stext;
+		drvdata->addr_val[1] = (uint32_t) _etext;
+		drvdata->addr_type[0] = ETM_ADDR_TYPE_RANGE;
+		drvdata->addr_type[1] = ETM_ADDR_TYPE_RANGE;
+	}
+	for (i = 0; i < drvdata->nr_cntr; i++) {
+		drvdata->cntr_event[i] = 0x406F;
+		drvdata->cntr_rld_event[i] = 0x406F;
+	}
+	drvdata->seq_12_event = 0x406F;
+	drvdata->seq_21_event = 0x406F;
+	drvdata->seq_23_event = 0x406F;
+	drvdata->seq_31_event = 0x406F;
+	drvdata->seq_32_event = 0x406F;
+	drvdata->seq_13_event = 0x406F;
+	drvdata->sync_freq = 0x100;
+	drvdata->timestamp_event = 0x406F;
+}
+
+static int __devinit etm_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct etm_drvdata *drvdata;
+	struct resource *res;
+	static int count;
+	struct coresight_desc *desc;
+
+	if (pdev->dev.of_node) {
+		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+		pdev->dev.platform_data = pdata;
+		drvdata->use_cp14 = of_property_read_bool(pdev->dev.of_node,
+							  "arm,cp14");
+	}
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	platform_set_drvdata(pdev, drvdata);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!drvdata->base)
+		return -ENOMEM;
+
+	spin_lock_init(&drvdata->spinlock);
+
+	drvdata->clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(drvdata->clk))
+		return PTR_ERR(drvdata->clk);
+
+	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	drvdata->cpu = count++;
+
+	get_online_cpus();
+	etmdrvdata[drvdata->cpu] = drvdata;
+
+	if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, NULL, 1))
+		drvdata->os_unlock = true;
+	/*
+	 * Use CPU0 to populate read-only configuration data for ETM0. For
+	 * other ETMs copy it over from ETM0.
+	 */
+	if (drvdata->cpu == 0) {
+		register_hotcpu_notifier(&etm_cpu_notifier);
+		if (smp_call_function_single(drvdata->cpu, etm_init_arch_data,
+					     drvdata, 1))
+			dev_err(dev, "ETM arch init failed\n");
+	} else {
+		etm_copy_arch_data(drvdata);
+	}
+
+	put_online_cpus();
+
+	if (etm_arch_supported(drvdata->arch) == false) {
+		clk_disable_unprepare(drvdata->clk);
+		return -EINVAL;
+	}
+	etm_init_default_data(drvdata);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+	desc->ops = &etm_cs_ops;
+	desc->pdata = pdev->dev.platform_data;
+	desc->dev = &pdev->dev;
+	desc->groups = etm_attr_grps;
+	desc->owner = THIS_MODULE;
+	drvdata->csdev = coresight_register(desc);
+	if (IS_ERR(drvdata->csdev)) {
+		ret = PTR_ERR(drvdata->csdev);
+		goto err;
+	}
+
+	dev_info(dev, "ETM initialized\n");
+
+	if (boot_enable) {
+		coresight_enable(drvdata->csdev);
+		drvdata->boot_enable = true;
+	}
+
+	return 0;
+err:
+	if (drvdata->cpu == 0)
+		unregister_hotcpu_notifier(&etm_cpu_notifier);
+	return ret;
+}
+
+static int __devexit etm_remove(struct platform_device *pdev)
+{
+	struct etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+	coresight_unregister(drvdata->csdev);
+	if (drvdata->cpu == 0)
+		unregister_hotcpu_notifier(&etm_cpu_notifier);
+	return 0;
+}
+
+static struct of_device_id etm_match[] = {
+	{.compatible = "arm,coresight-etm"},
+	{}
+};
+
+static struct platform_driver etm_driver = {
+	.probe          = etm_probe,
+	.remove         = __devexit_p(etm_remove),
+	.driver         = {
+		.name   = "coresight-etm",
+		.owner	= THIS_MODULE,
+		.of_match_table = etm_match,
+	},
+};
+
+int __init etm_init(void)
+{
+	return platform_driver_register(&etm_driver);
+}
+module_init(etm_init);
+
+void __exit etm_exit(void)
+{
+	platform_driver_unregister(&etm_driver);
+}
+module_exit(etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Program Flow Trace driver");
-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
                   ` (7 preceding siblings ...)
  2012-12-18 19:19 ` [RFC 8/8] coresight: add CoreSight ETM driver pratikp at codeaurora.org
@ 2012-12-19 11:23 ` Will Deacon
  2012-12-19 17:03   ` Jon Hunter
  2012-12-19 21:06   ` Pratik Patel
  2013-02-21 14:32 ` Robert MARKLUND
  9 siblings, 2 replies; 32+ messages in thread
From: Will Deacon @ 2012-12-19 11:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Pratik,

On Tue, Dec 18, 2012 at 07:19:17PM +0000, pratikp at codeaurora.org wrote:
> This RFC is aimed at introducing CoreSight framework as well as
> individual CoreSight trace component drivers adhering to ARM
> CoreSight specification. Some prior discussion on this can be
> referred at [1].
> 
> There are 3 kinds of CoreSight trace components:
> 
> * Sources: Responsible for producing trace data to provide
>   visibility for the associated entity.
> 
> * Links: Transport components that carry trace data.
> 
> * Sinks: Collectors for storing trace data or acting as conduits
>   for off-chip trace data collection.
> 
> These components can be connected in various topologies to suite
> a particular SoCs tracing needs.
> 
> Framework is responsible for gathering and using the information
> about the registered CoreSight components and their connections
> to allow it to dynamically deduce the sequence of components
> representing a connection from a CoreSight source to the
> currently selected CoreSight sink. This helps the framework to
> program the correct set of components to satisfy user request.

>From a million miles up, this looks like a sensible sort of design but I
really think you need to talk to Jon Hunter (he's at least on CC) about
this, especially where bindings are concerned. If we can get something that
you both agree on, then we can include the CTI with the other coresight
components and do a more in-depth review at that point.

Finally, how do you plan on exposing this data to the user? I think the only
sane way is to have per-device file descriptors which act as pipes to the raw
data but this means we need some readily available, open-source tooling (or
at least public specifications of the trace formats).

Will

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-19 11:23 ` CoreSight framework and drivers Will Deacon
@ 2012-12-19 17:03   ` Jon Hunter
  2012-12-19 21:24     ` Pratik Patel
  2012-12-19 21:06   ` Pratik Patel
  1 sibling, 1 reply; 32+ messages in thread
From: Jon Hunter @ 2012-12-19 17:03 UTC (permalink / raw)
  To: linux-arm-kernel


On 12/19/2012 05:23 AM, Will Deacon wrote:
> Hi Pratik,
> 
> On Tue, Dec 18, 2012 at 07:19:17PM +0000, pratikp at codeaurora.org wrote:
>> This RFC is aimed at introducing CoreSight framework as well as
>> individual CoreSight trace component drivers adhering to ARM
>> CoreSight specification. Some prior discussion on this can be
>> referred at [1].
>>
>> There are 3 kinds of CoreSight trace components:
>>
>> * Sources: Responsible for producing trace data to provide
>>   visibility for the associated entity.
>>
>> * Links: Transport components that carry trace data.
>>
>> * Sinks: Collectors for storing trace data or acting as conduits
>>   for off-chip trace data collection.
>>
>> These components can be connected in various topologies to suite
>> a particular SoCs tracing needs.
>>
>> Framework is responsible for gathering and using the information
>> about the registered CoreSight components and their connections
>> to allow it to dynamically deduce the sequence of components
>> representing a connection from a CoreSight source to the
>> currently selected CoreSight sink. This helps the framework to
>> program the correct set of components to satisfy user request.
> 
> From a million miles up, this looks like a sensible sort of design but I
> really think you need to talk to Jon Hunter (he's at least on CC) about
> this, especially where bindings are concerned. If we can get something that
> you both agree on, then we can include the CTI with the other coresight
> components and do a more in-depth review at that point.

I need to look at these in closer detail, but there are a couple
high-level items that need to be aligned on which are ...

1. Why not use the AMBA bus framework?

You mentioned before that "AMBA bus is for PrimeCell devices (class 0xF)
as opposed to CoreSight devices (class 0x9)". I will not claim to be
that familiar with primecell and coresight devices and there
differences, but this statement does not help me understand why a new
bus type is needed. Furthermore, the existing ETM and ETB driver in
arch/arm/kernel/etm.c uses the AMBA bus today and so at least those
coresight devices are able to use the AMBA bus type.

2. What about the existing ETM/ETB drivers?

We have existing drivers for ETM and ETB in arch/arm/kernel/etm.c. We
should either move those drivers to the drivers directory or replace
them with the new one. However, no point in having two drivers for the
same coresight device.

Cheers
Jon

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-19 11:23 ` CoreSight framework and drivers Will Deacon
  2012-12-19 17:03   ` Jon Hunter
@ 2012-12-19 21:06   ` Pratik Patel
  1 sibling, 0 replies; 32+ messages in thread
From: Pratik Patel @ 2012-12-19 21:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Dec 19, 2012 at 11:23:14AM +0000, Will Deacon wrote:
> Hi Pratik,
> 
> On Tue, Dec 18, 2012 at 07:19:17PM +0000, pratikp at codeaurora.org wrote:
> > This RFC is aimed at introducing CoreSight framework as well as
> > individual CoreSight trace component drivers adhering to ARM
> > CoreSight specification. Some prior discussion on this can be
> > referred at [1].
> > 
> > There are 3 kinds of CoreSight trace components:
> > 
> > * Sources: Responsible for producing trace data to provide
> >   visibility for the associated entity.
> > 
> > * Links: Transport components that carry trace data.
> > 
> > * Sinks: Collectors for storing trace data or acting as conduits
> >   for off-chip trace data collection.
> > 
> > These components can be connected in various topologies to suite
> > a particular SoCs tracing needs.
> > 
> > Framework is responsible for gathering and using the information
> > about the registered CoreSight components and their connections
> > to allow it to dynamically deduce the sequence of components
> > representing a connection from a CoreSight source to the
> > currently selected CoreSight sink. This helps the framework to
> > program the correct set of components to satisfy user request.
> 
> From a million miles up, this looks like a sensible sort of design but I
> really think you need to talk to Jon Hunter (he's at least on CC) about
> this, especially where bindings are concerned. If we can get something that
> you both agree on, then we can include the CTI with the other coresight
> components and do a more in-depth review at that point.
> 

Thanks for the feedback.

> Finally, how do you plan on exposing this data to the user? I think the only
> sane way is to have per-device file descriptors which act as pipes to the raw
> data but this means we need some readily available, open-source tooling (or
> at least public specifications of the trace formats).
> 

The sink drivers (ETB, TMC), expose a device node per device that
is used to collect the raw data.

Eg:, we have:
/dev/coresight-etb
/dev/coresight-tmc-etf
/dev/coresight-tmc-etr

where reading /dev/coresight-tmc-etf only works when the ETF is
in circular buffer mode.

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-19 17:03   ` Jon Hunter
@ 2012-12-19 21:24     ` Pratik Patel
  2012-12-20 17:46       ` Jon Hunter
  0 siblings, 1 reply; 32+ messages in thread
From: Pratik Patel @ 2012-12-19 21:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Dec 19, 2012 at 11:03:58AM -0600, Jon Hunter wrote:
> 
> On 12/19/2012 05:23 AM, Will Deacon wrote:
> > Hi Pratik,
> > 
> > On Tue, Dec 18, 2012 at 07:19:17PM +0000, pratikp at codeaurora.org wrote:
> >> This RFC is aimed at introducing CoreSight framework as well as
> >> individual CoreSight trace component drivers adhering to ARM
> >> CoreSight specification. Some prior discussion on this can be
> >> referred at [1].
> >>
> >> There are 3 kinds of CoreSight trace components:
> >>
> >> * Sources: Responsible for producing trace data to provide
> >>   visibility for the associated entity.
> >>
> >> * Links: Transport components that carry trace data.
> >>
> >> * Sinks: Collectors for storing trace data or acting as conduits
> >>   for off-chip trace data collection.
> >>
> >> These components can be connected in various topologies to suite
> >> a particular SoCs tracing needs.
> >>
> >> Framework is responsible for gathering and using the information
> >> about the registered CoreSight components and their connections
> >> to allow it to dynamically deduce the sequence of components
> >> representing a connection from a CoreSight source to the
> >> currently selected CoreSight sink. This helps the framework to
> >> program the correct set of components to satisfy user request.
> > 
> > From a million miles up, this looks like a sensible sort of design but I
> > really think you need to talk to Jon Hunter (he's at least on CC) about
> > this, especially where bindings are concerned. If we can get something that
> > you both agree on, then we can include the CTI with the other coresight
> > components and do a more in-depth review at that point.
> 
> I need to look at these in closer detail, but there are a couple
> high-level items that need to be aligned on which are ...
> 
> 1. Why not use the AMBA bus framework?
> 
> You mentioned before that "AMBA bus is for PrimeCell devices (class 0xF)
> as opposed to CoreSight devices (class 0x9)". I will not claim to be
> that familiar with primecell and coresight devices and there
> differences, but this statement does not help me understand why a new
> bus type is needed. Furthermore, the existing ETM and ETB driver in
> arch/arm/kernel/etm.c uses the AMBA bus today and so at least those
> coresight devices are able to use the AMBA bus type.
> 

Currently we use the CoreSight virtual bus to conveniently list
sysfs configuration attributes for all the registered CoreSight
devices.

For eg:
/sys/bus/coresight/devices/coresight-etm0/<attribute>
/sys/bus/coresight/devices/coresight-etm1/<attribute>
/sys/bus/coresight/devices/coresight-stm/<attribute>
/sys/bus/coresight/devices/coresight-tmc-etf/<attribute>
...
...

Some of the attributes are based on device type (i.e. source,
link or sink) so they will exist for all devices of that type
while some are device specific.

Maybe I am misunderstanding the question but are you suggesting
to register CoreSight devices to the AMBA bus instead of the
CoreSight core layer code?

Will Deacon mentioned earlier that AMBA framework can be changed
to accomodate devices with a different class but I am more
concerned with losing some of the stuff that the core layer code
does (eg. coresight_register, coresight_enable, coresight_disable
in coresight.c) if we register CoreSight drivers to the AMBA bus
without letting the core layer know about the device connections.

BTW, sorry the patches didn't get posted to the list since they
are apparently awaiting moderator approval.

> 2. What about the existing ETM/ETB drivers?
> 
> We have existing drivers for ETM and ETB in arch/arm/kernel/etm.c. We
> should either move those drivers to the drivers directory or replace
> them with the new one. However, no point in having two drivers for the
> same coresight device.
> 

Agree we should ensure we don't lose any existing functionality.

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-19 21:24     ` Pratik Patel
@ 2012-12-20 17:46       ` Jon Hunter
  2012-12-20 19:51         ` Pratik Patel
  0 siblings, 1 reply; 32+ messages in thread
From: Jon Hunter @ 2012-12-20 17:46 UTC (permalink / raw)
  To: linux-arm-kernel


On 12/19/2012 03:24 PM, Pratik Patel wrote:

[snip]

> Currently we use the CoreSight virtual bus to conveniently list
> sysfs configuration attributes for all the registered CoreSight
> devices.
> 
> For eg:
> /sys/bus/coresight/devices/coresight-etm0/<attribute>
> /sys/bus/coresight/devices/coresight-etm1/<attribute>
> /sys/bus/coresight/devices/coresight-stm/<attribute>
> /sys/bus/coresight/devices/coresight-tmc-etf/<attribute>
> ...
> ...
> 
> Some of the attributes are based on device type (i.e. source,
> link or sink) so they will exist for all devices of that type
> while some are device specific.
> 
> Maybe I am misunderstanding the question but are you suggesting
> to register CoreSight devices to the AMBA bus instead of the
> CoreSight core layer code?

Yes exactly.

> Will Deacon mentioned earlier that AMBA framework can be changed
> to accomodate devices with a different class but I am more
> concerned with losing some of the stuff that the core layer code
> does (eg. coresight_register, coresight_enable, coresight_disable
> in coresight.c) if we register CoreSight drivers to the AMBA bus
> without letting the core layer know about the device connections.

I may be missing something, but couldn't you keep all the
register/enable/disable stuff but just register the device with the amba
bus? Obviously some changes would need to be made.

Personally, I don't have strong feeling either way, but we have ETM/ETB
drivers using AMBA today and so I am hoping we can come to agreement on
this going forward.

Russell, Will, what are your thoughts?

Otherwise, looking at the code, I like what you have implemented. I
still need to look closer, but I am struggling to figure out how a
coresight device such as the cross-trigger-interface fits with this
model. This model appears to be geared towards coresight devices used
for traces purposes and are either source, links or sinks. The
cross-trigger-interface is not a source or a sink. However, although you
it could be considered as a link (routing events), it is not really, as
it may not link to other coresight sinks/source.

In my case, I have PMU-IRQ --> CTI --> GIC. So a non-coresight source
and sink. In away the CTI looks more like a 2nd-level interrupt
controller than anything else. Hence, another type of coresight device
may be needed in addition to source, links and sinks. Or link is
extended in some way to connect to non-coresight sources/sinks.

Let me know if you have any thoughts.

Cheers
Jon

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [RFC 4/8] coresight: add CoreSight ETB driver
  2012-12-18 19:19 ` [RFC 4/8] coresight: add CoreSight ETB driver pratikp at codeaurora.org
@ 2012-12-20 17:49   ` Jon Hunter
  2012-12-20 19:54     ` Pratik Patel
  0 siblings, 1 reply; 32+ messages in thread
From: Jon Hunter @ 2012-12-20 17:49 UTC (permalink / raw)
  To: linux-arm-kernel


On 12/18/2012 01:19 PM, pratikp at codeaurora.org wrote:
> From: Pratik Patel <pratikp@codeaurora.org>
> 
> This driver manages CoreSight ETB (Embedded Trace Buffer) which
> acts as a circular buffer sink collecting generated trace data.
> 
> Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
> ---
>  drivers/coresight/Makefile        |    2 +-
>  drivers/coresight/coresight-etb.c |  467 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 468 insertions(+), 1 deletions(-)

[snip]

> +static int __devinit etb_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct device *dev = &pdev->dev;
> +	struct coresight_platform_data *pdata;
> +	struct etb_drvdata *drvdata;
> +	struct resource *res;
> +	struct coresight_desc *desc;
> +
> +	if (pdev->dev.of_node) {
> +		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
> +		if (IS_ERR(pdata))
> +			return PTR_ERR(pdata);
> +		pdev->dev.platform_data = pdata;
> +	}
> +
> +	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
> +	if (!drvdata)
> +		return -ENOMEM;
> +	drvdata->dev = &pdev->dev;
> +	platform_set_drvdata(pdev, drvdata);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
> +	if (!drvdata->base)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&drvdata->spinlock);
> +
> +	drvdata->clk = devm_clk_get(dev, "core_clk");
> +	if (IS_ERR(drvdata->clk))
> +		return PTR_ERR(drvdata->clk);
> +
> +	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
> +	if (ret)
> +		return ret;
> +
> +	drvdata->buf = devm_kzalloc(dev, ETB_SIZE_WORDS * BYTES_PER_WORD,
> +				    GFP_KERNEL);
> +	if (!drvdata->buf)
> +		return -ENOMEM;
> +
> +	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
> +	if (!desc)
> +		return -ENOMEM;
> +	desc->type = CORESIGHT_DEV_TYPE_SINK;
> +	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;

Can a source be directly connected to a sink or do you need to have a
link in between?

The reason, I ask is because on some Cortex-A8 devices we have ETM
directly connected to ETB and there is no link per-se to configure.

Cheers
Jon

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-20 17:46       ` Jon Hunter
@ 2012-12-20 19:51         ` Pratik Patel
  2012-12-20 20:16           ` Jean Pihet
  2012-12-20 22:54           ` Jon Hunter
  0 siblings, 2 replies; 32+ messages in thread
From: Pratik Patel @ 2012-12-20 19:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 20, 2012 at 11:46:13AM -0600, Jon Hunter wrote:
> 
> On 12/19/2012 03:24 PM, Pratik Patel wrote:
> 
> [snip]
> 
> > Currently we use the CoreSight virtual bus to conveniently list
> > sysfs configuration attributes for all the registered CoreSight
> > devices.
> > 
> > For eg:
> > /sys/bus/coresight/devices/coresight-etm0/<attribute>
> > /sys/bus/coresight/devices/coresight-etm1/<attribute>
> > /sys/bus/coresight/devices/coresight-stm/<attribute>
> > /sys/bus/coresight/devices/coresight-tmc-etf/<attribute>
> > ...
> > ...
> > 
> > Some of the attributes are based on device type (i.e. source,
> > link or sink) so they will exist for all devices of that type
> > while some are device specific.
> > 
> > Maybe I am misunderstanding the question but are you suggesting
> > to register CoreSight devices to the AMBA bus instead of the
> > CoreSight core layer code?
> 
> Yes exactly.
> 
> > Will Deacon mentioned earlier that AMBA framework can be changed
> > to accomodate devices with a different class but I am more
> > concerned with losing some of the stuff that the core layer code
> > does (eg. coresight_register, coresight_enable, coresight_disable
> > in coresight.c) if we register CoreSight drivers to the AMBA bus
> > without letting the core layer know about the device connections.
> 
> I may be missing something, but couldn't you keep all the
> register/enable/disable stuff but just register the device with the amba
> bus? Obviously some changes would need to be made.
> 

Ok, so are you referring to making CoreSight devices register
with AMBA bus instead of platform bus keeping everything else
intact?

> Personally, I don't have strong feeling either way, but we have ETM/ETB
> drivers using AMBA today and so I am hoping we can come to agreement on
> this going forward.
> 
> Russell, Will, what are your thoughts?
> 
> Otherwise, looking at the code, I like what you have implemented. I
> still need to look closer, but I am struggling to figure out how a
> coresight device such as the cross-trigger-interface fits with this
> model. This model appears to be geared towards coresight devices used
> for traces purposes and are either source, links or sinks. The
> cross-trigger-interface is not a source or a sink. However, although you
> it could be considered as a link (routing events), it is not really, as
> it may not link to other coresight sinks/source.
> 
> In my case, I have PMU-IRQ --> CTI --> GIC. So a non-coresight source
> and sink. In away the CTI looks more like a 2nd-level interrupt
> controller than anything else. Hence, another type of coresight device
> may be needed in addition to source, links and sinks. Or link is
> extended in some way to connect to non-coresight sources/sinks.
> 
> Let me know if you have any thoughts.
> 

I had left the "None" type for miscellaneous stuff but I agree it
should be a separate type - maybe "debug".

Having said that I like the CTI driver you have uploaded. Need to
look at it in more detail. Since CTI connections can vary between
chip to chip, we need a generic way to deal with it.

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [RFC 4/8] coresight: add CoreSight ETB driver
  2012-12-20 17:49   ` Jon Hunter
@ 2012-12-20 19:54     ` Pratik Patel
  0 siblings, 0 replies; 32+ messages in thread
From: Pratik Patel @ 2012-12-20 19:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 20, 2012 at 11:49:03AM -0600, Jon Hunter wrote:
> 
> On 12/18/2012 01:19 PM, pratikp at codeaurora.org wrote:
> > From: Pratik Patel <pratikp@codeaurora.org>
> > 
> > This driver manages CoreSight ETB (Embedded Trace Buffer) which
> > acts as a circular buffer sink collecting generated trace data.
> > 
> > Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
> > ---
> >  drivers/coresight/Makefile        |    2 +-
> >  drivers/coresight/coresight-etb.c |  467 +++++++++++++++++++++++++++++++++++++
> >  2 files changed, 468 insertions(+), 1 deletions(-)
> 
> [snip]
> 
> > +static int __devinit etb_probe(struct platform_device *pdev)
> > +{
> > +	int ret;
> > +	struct device *dev = &pdev->dev;
> > +	struct coresight_platform_data *pdata;
> > +	struct etb_drvdata *drvdata;
> > +	struct resource *res;
> > +	struct coresight_desc *desc;
> > +
> > +	if (pdev->dev.of_node) {
> > +		pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
> > +		if (IS_ERR(pdata))
> > +			return PTR_ERR(pdata);
> > +		pdev->dev.platform_data = pdata;
> > +	}
> > +
> > +	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
> > +	if (!drvdata)
> > +		return -ENOMEM;
> > +	drvdata->dev = &pdev->dev;
> > +	platform_set_drvdata(pdev, drvdata);
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (!res)
> > +		return -ENODEV;
> > +
> > +	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
> > +	if (!drvdata->base)
> > +		return -ENOMEM;
> > +
> > +	spin_lock_init(&drvdata->spinlock);
> > +
> > +	drvdata->clk = devm_clk_get(dev, "core_clk");
> > +	if (IS_ERR(drvdata->clk))
> > +		return PTR_ERR(drvdata->clk);
> > +
> > +	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
> > +	if (ret)
> > +		return ret;
> > +
> > +	drvdata->buf = devm_kzalloc(dev, ETB_SIZE_WORDS * BYTES_PER_WORD,
> > +				    GFP_KERNEL);
> > +	if (!drvdata->buf)
> > +		return -ENOMEM;
> > +
> > +	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
> > +	if (!desc)
> > +		return -ENOMEM;
> > +	desc->type = CORESIGHT_DEV_TYPE_SINK;
> > +	desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
> 
> Can a source be directly connected to a sink or do you need to have a
> link in between?
> 
> The reason, I ask is because on some Cortex-A8 devices we have ETM
> directly connected to ETB and there is no link per-se to configure.
> 

Source can be directly connected to a sink. I believe the current
code should be able to take care of that but I haven't tried it
since we didn't have such a case.

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-20 19:51         ` Pratik Patel
@ 2012-12-20 20:16           ` Jean Pihet
  2012-12-21 22:12             ` Pratik Patel
  2012-12-20 22:54           ` Jon Hunter
  1 sibling, 1 reply; 32+ messages in thread
From: Jean Pihet @ 2012-12-20 20:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Pratik,

On Thu, Dec 20, 2012 at 8:51 PM, Pratik Patel <pratikp@codeaurora.org> wrote:
> On Thu, Dec 20, 2012 at 11:46:13AM -0600, Jon Hunter wrote:
>>
>> On 12/19/2012 03:24 PM, Pratik Patel wrote:
>>
>> [snip]
>>
>> > Currently we use the CoreSight virtual bus to conveniently list
>> > sysfs configuration attributes for all the registered CoreSight
>> > devices.
>> >
>> > For eg:
>> > /sys/bus/coresight/devices/coresight-etm0/<attribute>
>> > /sys/bus/coresight/devices/coresight-etm1/<attribute>
>> > /sys/bus/coresight/devices/coresight-stm/<attribute>
>> > /sys/bus/coresight/devices/coresight-tmc-etf/<attribute>
>> > ...
>> > ...
>> >
>> > Some of the attributes are based on device type (i.e. source,
>> > link or sink) so they will exist for all devices of that type
>> > while some are device specific.
>> >
>> > Maybe I am misunderstanding the question but are you suggesting
>> > to register CoreSight devices to the AMBA bus instead of the
>> > CoreSight core layer code?
>>
>> Yes exactly.
>>
>> > Will Deacon mentioned earlier that AMBA framework can be changed
>> > to accomodate devices with a different class but I am more
>> > concerned with losing some of the stuff that the core layer code
>> > does (eg. coresight_register, coresight_enable, coresight_disable
>> > in coresight.c) if we register CoreSight drivers to the AMBA bus
>> > without letting the core layer know about the device connections.
>>
>> I may be missing something, but couldn't you keep all the
>> register/enable/disable stuff but just register the device with the amba
>> bus? Obviously some changes would need to be made.
>>
>
> Ok, so are you referring to making CoreSight devices register
> with AMBA bus instead of platform bus keeping everything else
> intact?
>
>> Personally, I don't have strong feeling either way, but we have ETM/ETB
>> drivers using AMBA today and so I am hoping we can come to agreement on
>> this going forward.
>>
>> Russell, Will, what are your thoughts?
>>
>> Otherwise, looking at the code, I like what you have implemented. I
>> still need to look closer, but I am struggling to figure out how a
>> coresight device such as the cross-trigger-interface fits with this
>> model. This model appears to be geared towards coresight devices used
>> for traces purposes and are either source, links or sinks. The
>> cross-trigger-interface is not a source or a sink. However, although you
>> it could be considered as a link (routing events), it is not really, as
>> it may not link to other coresight sinks/source.
>>
>> In my case, I have PMU-IRQ --> CTI --> GIC. So a non-coresight source
>> and sink. In away the CTI looks more like a 2nd-level interrupt
>> controller than anything else. Hence, another type of coresight device
>> may be needed in addition to source, links and sinks. Or link is
>> extended in some way to connect to non-coresight sources/sinks.
>>
>> Let me know if you have any thoughts.
>>
>
> I had left the "None" type for miscellaneous stuff but I agree it
> should be a separate type - maybe "debug".
>
> Having said that I like the CTI driver you have uploaded. Need to
> look at it in more detail. Since CTI connections can vary between
> chip to chip, we need a generic way to deal with it.
I am also interested to look at such a framework in order to have a
clean implementation of the ETM, PMI/CMI (HW tracing IP on OMAP4+).
I am currently busy on a driver for PMI/CMI which requires some
configuration of the Coresight, ETM, ETB, ATB etc. IP blocks.

Could you send your patches to linux-arm and linux-omap mailing lists?
I will be pleased to review them.

Regards,
Jean

>
> --
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> hosted by The Linux Foundation
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-20 19:51         ` Pratik Patel
  2012-12-20 20:16           ` Jean Pihet
@ 2012-12-20 22:54           ` Jon Hunter
  2012-12-20 23:40             ` Russell King - ARM Linux
  2012-12-21 22:18             ` Pratik Patel
  1 sibling, 2 replies; 32+ messages in thread
From: Jon Hunter @ 2012-12-20 22:54 UTC (permalink / raw)
  To: linux-arm-kernel


On 12/20/2012 01:51 PM, Pratik Patel wrote:
> On Thu, Dec 20, 2012 at 11:46:13AM -0600, Jon Hunter wrote:
>>
>> On 12/19/2012 03:24 PM, Pratik Patel wrote:
>>
>> [snip]
>>
>>> Currently we use the CoreSight virtual bus to conveniently list
>>> sysfs configuration attributes for all the registered CoreSight
>>> devices.
>>>
>>> For eg:
>>> /sys/bus/coresight/devices/coresight-etm0/<attribute>
>>> /sys/bus/coresight/devices/coresight-etm1/<attribute>
>>> /sys/bus/coresight/devices/coresight-stm/<attribute>
>>> /sys/bus/coresight/devices/coresight-tmc-etf/<attribute>
>>> ...
>>> ...
>>>
>>> Some of the attributes are based on device type (i.e. source,
>>> link or sink) so they will exist for all devices of that type
>>> while some are device specific.
>>>
>>> Maybe I am misunderstanding the question but are you suggesting
>>> to register CoreSight devices to the AMBA bus instead of the
>>> CoreSight core layer code?
>>
>> Yes exactly.
>>
>>> Will Deacon mentioned earlier that AMBA framework can be changed
>>> to accomodate devices with a different class but I am more
>>> concerned with losing some of the stuff that the core layer code
>>> does (eg. coresight_register, coresight_enable, coresight_disable
>>> in coresight.c) if we register CoreSight drivers to the AMBA bus
>>> without letting the core layer know about the device connections.
>>
>> I may be missing something, but couldn't you keep all the
>> register/enable/disable stuff but just register the device with the amba
>> bus? Obviously some changes would need to be made.
>>
> 
> Ok, so are you referring to making CoreSight devices register
> with AMBA bus instead of platform bus keeping everything else
> intact?

Yes exactly. However, please note I am not saying that we should do
this, and I asking what direction does the community want us to take
here? Platform bus or AMBA bus?

>> Personally, I don't have strong feeling either way, but we have ETM/ETB
>> drivers using AMBA today and so I am hoping we can come to agreement on
>> this going forward.
>>
>> Russell, Will, what are your thoughts?
>>
>> Otherwise, looking at the code, I like what you have implemented. I
>> still need to look closer, but I am struggling to figure out how a
>> coresight device such as the cross-trigger-interface fits with this
>> model. This model appears to be geared towards coresight devices used
>> for traces purposes and are either source, links or sinks. The
>> cross-trigger-interface is not a source or a sink. However, although you
>> it could be considered as a link (routing events), it is not really, as
>> it may not link to other coresight sinks/source.
>>
>> In my case, I have PMU-IRQ --> CTI --> GIC. So a non-coresight source
>> and sink. In away the CTI looks more like a 2nd-level interrupt
>> controller than anything else. Hence, another type of coresight device
>> may be needed in addition to source, links and sinks. Or link is
>> extended in some way to connect to non-coresight sources/sinks.
>>
>> Let me know if you have any thoughts.
>>
> 
> I had left the "None" type for miscellaneous stuff but I agree it
> should be a separate type - maybe "debug".
> 
> Having said that I like the CTI driver you have uploaded. Need to
> look at it in more detail. Since CTI connections can vary between
> chip to chip, we need a generic way to deal with it.

Yes if you have any ideas let me know. As Will had mentioned it would be
good to have a common function table all these devices could use too. I
will take a closer look at what you have.

Cheers
Jon

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-20 22:54           ` Jon Hunter
@ 2012-12-20 23:40             ` Russell King - ARM Linux
  2012-12-21 22:17               ` Pratik Patel
  2012-12-21 22:18             ` Pratik Patel
  1 sibling, 1 reply; 32+ messages in thread
From: Russell King - ARM Linux @ 2012-12-20 23:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 20, 2012 at 04:54:38PM -0600, Jon Hunter wrote:
> On 12/20/2012 01:51 PM, Pratik Patel wrote:
> > Ok, so are you referring to making CoreSight devices register
> > with AMBA bus instead of platform bus keeping everything else
> > intact?
> 
> Yes exactly. However, please note I am not saying that we should do
> this, and I asking what direction does the community want us to take
> here? Platform bus or AMBA bus?

One of the issues which worries me about mixing peripheral drivers on
random different buses is... what happens when we end up with a SoC
which gates the APB clock at bus level (there are SoCs which gate the
APB clock at peripheral level.)  In other words, an APB bus only gets
clocked upon request.

We can deal with that with the infrastructure we have in place in the
AMBA bus layer, but not with the platform bus - we'd have to teach the
platform bus driver about the special APB clock instead of having it
handled primerily at the bus layer.

At least the coresight ETM peripherals make use of the APB bus.  They
have a whole pile of registers on the APB bus, and they have the
primecell IDs stored in the last words of the peripheral, again just
like the other primecell devices we have using the AMBA bus layer.

What I'd say is... why stick it on a different bus type from the other
peripherals which might make things harder in the future?

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-20 20:16           ` Jean Pihet
@ 2012-12-21 22:12             ` Pratik Patel
  0 siblings, 0 replies; 32+ messages in thread
From: Pratik Patel @ 2012-12-21 22:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 20, 2012 at 09:16:15PM +0100, Jean Pihet wrote:
> Hi Pratik,
> 
> On Thu, Dec 20, 2012 at 8:51 PM, Pratik Patel <pratikp@codeaurora.org> wrote:
> > On Thu, Dec 20, 2012 at 11:46:13AM -0600, Jon Hunter wrote:
> >>
> >> On 12/19/2012 03:24 PM, Pratik Patel wrote:
> >>
> >> [snip]
> >>
> >> > Currently we use the CoreSight virtual bus to conveniently list
> >> > sysfs configuration attributes for all the registered CoreSight
> >> > devices.
> >> >
> >> > For eg:
> >> > /sys/bus/coresight/devices/coresight-etm0/<attribute>
> >> > /sys/bus/coresight/devices/coresight-etm1/<attribute>
> >> > /sys/bus/coresight/devices/coresight-stm/<attribute>
> >> > /sys/bus/coresight/devices/coresight-tmc-etf/<attribute>
> >> > ...
> >> > ...
> >> >
> >> > Some of the attributes are based on device type (i.e. source,
> >> > link or sink) so they will exist for all devices of that type
> >> > while some are device specific.
> >> >
> >> > Maybe I am misunderstanding the question but are you suggesting
> >> > to register CoreSight devices to the AMBA bus instead of the
> >> > CoreSight core layer code?
> >>
> >> Yes exactly.
> >>
> >> > Will Deacon mentioned earlier that AMBA framework can be changed
> >> > to accomodate devices with a different class but I am more
> >> > concerned with losing some of the stuff that the core layer code
> >> > does (eg. coresight_register, coresight_enable, coresight_disable
> >> > in coresight.c) if we register CoreSight drivers to the AMBA bus
> >> > without letting the core layer know about the device connections.
> >>
> >> I may be missing something, but couldn't you keep all the
> >> register/enable/disable stuff but just register the device with the amba
> >> bus? Obviously some changes would need to be made.
> >>
> >
> > Ok, so are you referring to making CoreSight devices register
> > with AMBA bus instead of platform bus keeping everything else
> > intact?
> >
> >> Personally, I don't have strong feeling either way, but we have ETM/ETB
> >> drivers using AMBA today and so I am hoping we can come to agreement on
> >> this going forward.
> >>
> >> Russell, Will, what are your thoughts?
> >>
> >> Otherwise, looking at the code, I like what you have implemented. I
> >> still need to look closer, but I am struggling to figure out how a
> >> coresight device such as the cross-trigger-interface fits with this
> >> model. This model appears to be geared towards coresight devices used
> >> for traces purposes and are either source, links or sinks. The
> >> cross-trigger-interface is not a source or a sink. However, although you
> >> it could be considered as a link (routing events), it is not really, as
> >> it may not link to other coresight sinks/source.
> >>
> >> In my case, I have PMU-IRQ --> CTI --> GIC. So a non-coresight source
> >> and sink. In away the CTI looks more like a 2nd-level interrupt
> >> controller than anything else. Hence, another type of coresight device
> >> may be needed in addition to source, links and sinks. Or link is
> >> extended in some way to connect to non-coresight sources/sinks.
> >>
> >> Let me know if you have any thoughts.
> >>
> >
> > I had left the "None" type for miscellaneous stuff but I agree it
> > should be a separate type - maybe "debug".
> >
> > Having said that I like the CTI driver you have uploaded. Need to
> > look at it in more detail. Since CTI connections can vary between
> > chip to chip, we need a generic way to deal with it.
> I am also interested to look at such a framework in order to have a
> clean implementation of the ETM, PMI/CMI (HW tracing IP on OMAP4+).
> I am currently busy on a driver for PMI/CMI which requires some
> configuration of the Coresight, ETM, ETB, ATB etc. IP blocks.
> 
> Could you send your patches to linux-arm and linux-omap mailing lists?
> I will be pleased to review them.
> 

Thanks. I did post them to linux-arm-kernel but they are waiting
on moderator approval. Hopefully they will get posted soon.

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-20 23:40             ` Russell King - ARM Linux
@ 2012-12-21 22:17               ` Pratik Patel
  0 siblings, 0 replies; 32+ messages in thread
From: Pratik Patel @ 2012-12-21 22:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 20, 2012 at 11:40:11PM +0000, Russell King - ARM Linux wrote:
> On Thu, Dec 20, 2012 at 04:54:38PM -0600, Jon Hunter wrote:
> > On 12/20/2012 01:51 PM, Pratik Patel wrote:
> > > Ok, so are you referring to making CoreSight devices register
> > > with AMBA bus instead of platform bus keeping everything else
> > > intact?
> > 
> > Yes exactly. However, please note I am not saying that we should do
> > this, and I asking what direction does the community want us to take
> > here? Platform bus or AMBA bus?
> 
> One of the issues which worries me about mixing peripheral drivers on
> random different buses is... what happens when we end up with a SoC
> which gates the APB clock at bus level (there are SoCs which gate the
> APB clock at peripheral level.)  In other words, an APB bus only gets
> clocked upon request.
> 
> We can deal with that with the infrastructure we have in place in the
> AMBA bus layer, but not with the platform bus - we'd have to teach the
> platform bus driver about the special APB clock instead of having it
> handled primerily at the bus layer.
> 
> At least the coresight ETM peripherals make use of the APB bus.  They
> have a whole pile of registers on the APB bus, and they have the
> primecell IDs stored in the last words of the peripheral, again just
> like the other primecell devices we have using the AMBA bus layer.
> 
> What I'd say is... why stick it on a different bus type from the other
> peripherals which might make things harder in the future?

Thanks for the info. I will look into using the AMBA bus instead
of the platform bus but one issue I notice is that AMBA framework
seems to support one contiguous register space.

CoreSight STM typically has a config register space and a
stimulus port/channel register space and these can be
non-contiguous in the chip memory map.

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-20 22:54           ` Jon Hunter
  2012-12-20 23:40             ` Russell King - ARM Linux
@ 2012-12-21 22:18             ` Pratik Patel
  2012-12-23 11:32               ` Will Deacon
  2013-01-02 20:00               ` Jon Hunter
  1 sibling, 2 replies; 32+ messages in thread
From: Pratik Patel @ 2012-12-21 22:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 20, 2012 at 04:54:38PM -0600, Jon Hunter wrote:
> 
> On 12/20/2012 01:51 PM, Pratik Patel wrote:
> > On Thu, Dec 20, 2012 at 11:46:13AM -0600, Jon Hunter wrote:
> >>
> >> On 12/19/2012 03:24 PM, Pratik Patel wrote:
> >>
> >> [snip]
> >>
> >>> Currently we use the CoreSight virtual bus to conveniently list
> >>> sysfs configuration attributes for all the registered CoreSight
> >>> devices.
> >>>
> >>> For eg:
> >>> /sys/bus/coresight/devices/coresight-etm0/<attribute>
> >>> /sys/bus/coresight/devices/coresight-etm1/<attribute>
> >>> /sys/bus/coresight/devices/coresight-stm/<attribute>
> >>> /sys/bus/coresight/devices/coresight-tmc-etf/<attribute>
> >>> ...
> >>> ...
> >>>
> >>> Some of the attributes are based on device type (i.e. source,
> >>> link or sink) so they will exist for all devices of that type
> >>> while some are device specific.
> >>>
> >>> Maybe I am misunderstanding the question but are you suggesting
> >>> to register CoreSight devices to the AMBA bus instead of the
> >>> CoreSight core layer code?
> >>
> >> Yes exactly.
> >>
> >>> Will Deacon mentioned earlier that AMBA framework can be changed
> >>> to accomodate devices with a different class but I am more
> >>> concerned with losing some of the stuff that the core layer code
> >>> does (eg. coresight_register, coresight_enable, coresight_disable
> >>> in coresight.c) if we register CoreSight drivers to the AMBA bus
> >>> without letting the core layer know about the device connections.
> >>
> >> I may be missing something, but couldn't you keep all the
> >> register/enable/disable stuff but just register the device with the amba
> >> bus? Obviously some changes would need to be made.
> >>
> > 
> > Ok, so are you referring to making CoreSight devices register
> > with AMBA bus instead of platform bus keeping everything else
> > intact?
> 
> Yes exactly. However, please note I am not saying that we should do
> this, and I asking what direction does the community want us to take
> here? Platform bus or AMBA bus?
> 
> >> Personally, I don't have strong feeling either way, but we have ETM/ETB
> >> drivers using AMBA today and so I am hoping we can come to agreement on
> >> this going forward.
> >>
> >> Russell, Will, what are your thoughts?
> >>
> >> Otherwise, looking at the code, I like what you have implemented. I
> >> still need to look closer, but I am struggling to figure out how a
> >> coresight device such as the cross-trigger-interface fits with this
> >> model. This model appears to be geared towards coresight devices used
> >> for traces purposes and are either source, links or sinks. The
> >> cross-trigger-interface is not a source or a sink. However, although you
> >> it could be considered as a link (routing events), it is not really, as
> >> it may not link to other coresight sinks/source.
> >>
> >> In my case, I have PMU-IRQ --> CTI --> GIC. So a non-coresight source
> >> and sink. In away the CTI looks more like a 2nd-level interrupt
> >> controller than anything else. Hence, another type of coresight device
> >> may be needed in addition to source, links and sinks. Or link is
> >> extended in some way to connect to non-coresight sources/sinks.
> >>
> >> Let me know if you have any thoughts.
> >>
> > 
> > I had left the "None" type for miscellaneous stuff but I agree it
> > should be a separate type - maybe "debug".
> > 
> > Having said that I like the CTI driver you have uploaded. Need to
> > look at it in more detail. Since CTI connections can vary between
> > chip to chip, we need a generic way to deal with it.
> 
> Yes if you have any ideas let me know. As Will had mentioned it would be
> good to have a common function table all these devices could use too. I
> will take a closer look at what you have.
> 

I had started on a CTI driver much in line with your current
implementation but your approach looks good to me.

Looking at the code though, I couldn't find a way to perform a
mapping between two different CTIs. Reason I ask is because we
have use cases where we need to map one CTIs input to another
CTIs output on the same channel.

Do you intend to support different entities within kernel to map
different trig_in or trig_out on the same CTI? If so, it might
probably require reference counting for the enable/disable.

What user interface do you plan to provide for the CTI? Maybe
something consistent with other CoreSight components in sysfs to
allow users to enable, disable, map and unmap ???

Please let me know your thoughts.

CTIs can easily be made part of the CoreSight core layer using a
different type but apart from being part of the CoreSight list
containing all the trace and CTI components, not sure if there is
anything that is useful to do in the core layer. Need to think
about this.

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-21 22:18             ` Pratik Patel
@ 2012-12-23 11:32               ` Will Deacon
  2013-01-03 18:06                 ` Pratik Patel
  2013-01-02 20:00               ` Jon Hunter
  1 sibling, 1 reply; 32+ messages in thread
From: Will Deacon @ 2012-12-23 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Dec 21, 2012 at 10:18:28PM +0000, Pratik Patel wrote:
> What user interface do you plan to provide for the CTI? Maybe
> something consistent with other CoreSight components in sysfs to
> allow users to enable, disable, map and unmap ???
> 
> Please let me know your thoughts.

Rather than have your current approach of dev nodes + sysfs config files for
each coresight device, I think it might be better to follow something closer
to ftrace and stick per-device directories under debugfs/coresight/. Then you
can have a pipe file and some config files in the same directory for each
component. You also don't need to do any mapping operations with this (just
post-process the stream directly).

It might also be fun to play with file redirection for sources and sinks, but
that's probably a bit too invasive.

Will

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-21 22:18             ` Pratik Patel
  2012-12-23 11:32               ` Will Deacon
@ 2013-01-02 20:00               ` Jon Hunter
  2013-01-03 19:32                 ` Pratik Patel
  1 sibling, 1 reply; 32+ messages in thread
From: Jon Hunter @ 2013-01-02 20:00 UTC (permalink / raw)
  To: linux-arm-kernel


On 12/21/2012 04:18 PM, Pratik Patel wrote:
> On Thu, Dec 20, 2012 at 04:54:38PM -0600, Jon Hunter wrote:
>>
>> On 12/20/2012 01:51 PM, Pratik Patel wrote:
>>> On Thu, Dec 20, 2012 at 11:46:13AM -0600, Jon Hunter wrote:
>>>>
>>>> On 12/19/2012 03:24 PM, Pratik Patel wrote:
>>>>
>>>> [snip]
>>>>
>>>>> Currently we use the CoreSight virtual bus to conveniently list
>>>>> sysfs configuration attributes for all the registered CoreSight
>>>>> devices.
>>>>>
>>>>> For eg:
>>>>> /sys/bus/coresight/devices/coresight-etm0/<attribute>
>>>>> /sys/bus/coresight/devices/coresight-etm1/<attribute>
>>>>> /sys/bus/coresight/devices/coresight-stm/<attribute>
>>>>> /sys/bus/coresight/devices/coresight-tmc-etf/<attribute>
>>>>> ...
>>>>> ...
>>>>>
>>>>> Some of the attributes are based on device type (i.e. source,
>>>>> link or sink) so they will exist for all devices of that type
>>>>> while some are device specific.
>>>>>
>>>>> Maybe I am misunderstanding the question but are you suggesting
>>>>> to register CoreSight devices to the AMBA bus instead of the
>>>>> CoreSight core layer code?
>>>>
>>>> Yes exactly.
>>>>
>>>>> Will Deacon mentioned earlier that AMBA framework can be changed
>>>>> to accomodate devices with a different class but I am more
>>>>> concerned with losing some of the stuff that the core layer code
>>>>> does (eg. coresight_register, coresight_enable, coresight_disable
>>>>> in coresight.c) if we register CoreSight drivers to the AMBA bus
>>>>> without letting the core layer know about the device connections.
>>>>
>>>> I may be missing something, but couldn't you keep all the
>>>> register/enable/disable stuff but just register the device with the amba
>>>> bus? Obviously some changes would need to be made.
>>>>
>>>
>>> Ok, so are you referring to making CoreSight devices register
>>> with AMBA bus instead of platform bus keeping everything else
>>> intact?
>>
>> Yes exactly. However, please note I am not saying that we should do
>> this, and I asking what direction does the community want us to take
>> here? Platform bus or AMBA bus?
>>
>>>> Personally, I don't have strong feeling either way, but we have ETM/ETB
>>>> drivers using AMBA today and so I am hoping we can come to agreement on
>>>> this going forward.
>>>>
>>>> Russell, Will, what are your thoughts?
>>>>
>>>> Otherwise, looking at the code, I like what you have implemented. I
>>>> still need to look closer, but I am struggling to figure out how a
>>>> coresight device such as the cross-trigger-interface fits with this
>>>> model. This model appears to be geared towards coresight devices used
>>>> for traces purposes and are either source, links or sinks. The
>>>> cross-trigger-interface is not a source or a sink. However, although you
>>>> it could be considered as a link (routing events), it is not really, as
>>>> it may not link to other coresight sinks/source.
>>>>
>>>> In my case, I have PMU-IRQ --> CTI --> GIC. So a non-coresight source
>>>> and sink. In away the CTI looks more like a 2nd-level interrupt
>>>> controller than anything else. Hence, another type of coresight device
>>>> may be needed in addition to source, links and sinks. Or link is
>>>> extended in some way to connect to non-coresight sources/sinks.
>>>>
>>>> Let me know if you have any thoughts.
>>>>
>>>
>>> I had left the "None" type for miscellaneous stuff but I agree it
>>> should be a separate type - maybe "debug".
>>>
>>> Having said that I like the CTI driver you have uploaded. Need to
>>> look at it in more detail. Since CTI connections can vary between
>>> chip to chip, we need a generic way to deal with it.
>>
>> Yes if you have any ideas let me know. As Will had mentioned it would be
>> good to have a common function table all these devices could use too. I
>> will take a closer look at what you have.
>>
> 
> I had started on a CTI driver much in line with your current
> implementation but your approach looks good to me.
> 
> Looking at the code though, I couldn't find a way to perform a
> mapping between two different CTIs. Reason I ask is because we
> have use cases where we need to map one CTIs input to another
> CTIs output on the same channel.

The code is largely based upon the existing cti helpers, which just had
a cti_map_trigger() function. The use-case you described is not
supported by the current helpers and so also not supported in my initial
implementation (although we should add this). Hence, it would be
probably best to split the cti_map_trigger() into two functions say,
cti_map_triggerin() and cti_map_triggerout(), to map a trigger
input/output to a channel.

> Do you intend to support different entities within kernel to map
> different trig_in or trig_out on the same CTI? If so, it might
> probably require reference counting for the enable/disable.

I need to think about this some more, as this does make it a little more
complex. Right now only one entity can use a cti module at a time.

> What user interface do you plan to provide for the CTI? Maybe
> something consistent with other CoreSight components in sysfs to
> allow users to enable, disable, map and unmap ???

Yes that's possible.

> Please let me know your thoughts.
> 
> CTIs can easily be made part of the CoreSight core layer using a
> different type but apart from being part of the CoreSight list
> containing all the trace and CTI components, not sure if there is
> anything that is useful to do in the core layer. Need to think
> about this.

Yes it would be good to make this all part of the same coresight framework.

Cheers
Jon

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-23 11:32               ` Will Deacon
@ 2013-01-03 18:06                 ` Pratik Patel
  2013-01-07 11:58                   ` Will Deacon
  0 siblings, 1 reply; 32+ messages in thread
From: Pratik Patel @ 2013-01-03 18:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Dec 23, 2012 at 11:32:39AM +0000, Will Deacon wrote:
> On Fri, Dec 21, 2012 at 10:18:28PM +0000, Pratik Patel wrote:
> > What user interface do you plan to provide for the CTI? Maybe
> > something consistent with other CoreSight components in sysfs to
> > allow users to enable, disable, map and unmap ???
> > 
> > Please let me know your thoughts.
> 
> Rather than have your current approach of dev nodes + sysfs config files for
> each coresight device, I think it might be better to follow something closer
> to ftrace and stick per-device directories under debugfs/coresight/. Then you
> can have a pipe file and some config files in the same directory for each
> component. You also don't need to do any mapping operations with this (just
> post-process the stream directly).
> 

Thanks for the suggestion. I had initially debated between debugfs
and sysfs but chose sysfs + dev nodes since using device attributes
relieves the drivers from manually managing directories and files,
its taken care of by the device and sysfs layers. Moreover, since
these are physical devices, device attributes made sense at the
time.

The map and unmap I was referring to was for the CTI trigger
mappings. Dev nodes are currently intended to provide the raw
data collected in the sinks.

Whats the advantage in using debugfs here?

> It might also be fun to play with file redirection for sources and sinks, but
> that's probably a bit too invasive.
> 
> Will

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2013-01-02 20:00               ` Jon Hunter
@ 2013-01-03 19:32                 ` Pratik Patel
  0 siblings, 0 replies; 32+ messages in thread
From: Pratik Patel @ 2013-01-03 19:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 02, 2013 at 02:00:21PM -0600, Jon Hunter wrote:
> 
> The code is largely based upon the existing cti helpers, which just had
> a cti_map_trigger() function. The use-case you described is not
> supported by the current helpers and so also not supported in my initial
> implementation (although we should add this). Hence, it would be
> probably best to split the cti_map_trigger() into two functions say,
> cti_map_triggerin() and cti_map_triggerout(), to map a trigger
> input/output to a channel.
> 

Yes, splitting the map function will provide more flexibility.
One possibility is to cue the enable and disable functions from
the mapping reference count for the CTI so that enable and
disable are internal only functions.

In this case the flow would look something like:

cti_get(cti1)
cti_map_triggerin(cti1) -> enable cti1
cti_get(cti2)
cti_map_triggerin(cti2) -> enable cti2
cti_map_triggerout(cti1) -> increment cti1 refcount

cti_unmap_triggerin(cti2) -> disable cti2
cti_put(cti2)
cti_unmap_triggerout(cti1) -> decrement cti1 refcount
cti_unmap_triggerin(cti1) -> disable cti1
cti_put(cti1)

With this, it is possible to push clock management inside enable
and disable as opposed to get and put though it would imply
enable being done before the actual mapping inside
cti_map_triggerin/out and disable after unmapping in
cti_unmap_triggerin/out. It might also mean cti_map_triggerin/out
and cti_unmap_triggerin/out having a non-atomic context call
semantics.

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2013-01-03 18:06                 ` Pratik Patel
@ 2013-01-07 11:58                   ` Will Deacon
  2013-01-16  0:14                     ` Pratik Patel
  0 siblings, 1 reply; 32+ messages in thread
From: Will Deacon @ 2013-01-07 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 03, 2013 at 06:06:43PM +0000, Pratik Patel wrote:
> On Sun, Dec 23, 2012 at 11:32:39AM +0000, Will Deacon wrote:
> > On Fri, Dec 21, 2012 at 10:18:28PM +0000, Pratik Patel wrote:
> > > What user interface do you plan to provide for the CTI? Maybe
> > > something consistent with other CoreSight components in sysfs to
> > > allow users to enable, disable, map and unmap ???
> > > 
> > > Please let me know your thoughts.
> > 
> > Rather than have your current approach of dev nodes + sysfs config files for
> > each coresight device, I think it might be better to follow something closer
> > to ftrace and stick per-device directories under debugfs/coresight/. Then you
> > can have a pipe file and some config files in the same directory for each
> > component. You also don't need to do any mapping operations with this (just
> > post-process the stream directly).
> > 
> 
> Thanks for the suggestion. I had initially debated between debugfs
> and sysfs but chose sysfs + dev nodes since using device attributes
> relieves the drivers from manually managing directories and files,
> its taken care of by the device and sysfs layers. Moreover, since
> these are physical devices, device attributes made sense at the
> time.
> 
> The map and unmap I was referring to was for the CTI trigger
> mappings. Dev nodes are currently intended to provide the raw
> data collected in the sinks.
> 
> Whats the advantage in using debugfs here?

The main things I like about debugfs are (a) it's a text-driven interface
and easy to script with and (b) it matches what we do for ftrace.

Furthermore, it means that subtle differences between devices can be hidden
in the driver and not require different vendor tools for parsing the trace
data.

Will

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2013-01-07 11:58                   ` Will Deacon
@ 2013-01-16  0:14                     ` Pratik Patel
  2013-01-17 10:55                       ` Will Deacon
  0 siblings, 1 reply; 32+ messages in thread
From: Pratik Patel @ 2013-01-16  0:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 07, 2013 at 11:58:36AM +0000, Will Deacon wrote:
> On Thu, Jan 03, 2013 at 06:06:43PM +0000, Pratik Patel wrote:
> > On Sun, Dec 23, 2012 at 11:32:39AM +0000, Will Deacon wrote:
> > > On Fri, Dec 21, 2012 at 10:18:28PM +0000, Pratik Patel wrote:
> > > > What user interface do you plan to provide for the CTI? Maybe
> > > > something consistent with other CoreSight components in sysfs to
> > > > allow users to enable, disable, map and unmap ???
> > > > 
> > > > Please let me know your thoughts.
> > > 
> > > Rather than have your current approach of dev nodes + sysfs config files for
> > > each coresight device, I think it might be better to follow something closer
> > > to ftrace and stick per-device directories under debugfs/coresight/. Then you
> > > can have a pipe file and some config files in the same directory for each
> > > component. You also don't need to do any mapping operations with this (just
> > > post-process the stream directly).
> > > 
> > 
> > Thanks for the suggestion. I had initially debated between debugfs
> > and sysfs but chose sysfs + dev nodes since using device attributes
> > relieves the drivers from manually managing directories and files,
> > its taken care of by the device and sysfs layers. Moreover, since
> > these are physical devices, device attributes made sense at the
> > time.
> > 
> > The map and unmap I was referring to was for the CTI trigger
> > mappings. Dev nodes are currently intended to provide the raw
> > data collected in the sinks.
> > 
> > Whats the advantage in using debugfs here?
> 
> The main things I like about debugfs are (a) it's a text-driven interface
> and easy to script with and (b) it matches what we do for ftrace.
> 
> Furthermore, it means that subtle differences between devices can be hidden
> in the driver and not require different vendor tools for parsing the trace
> data.
> 
Sorry for the delay and maybe I am missing something but it seems
we can take care of such protocol or parsing/decoding differences
even with device nodes since that seems independent of the
interface used - per device debugfs attributes or per device
device nodes.

CoreSight trace solution is typically a SoC wide solution and
hence can get used by non-Linux processors or hardware. Using
debugfs would imply compiling it and exposing all the debug
knobs even if the use case was to use the CoreSight solution for
something that didn't need all that.

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2013-01-16  0:14                     ` Pratik Patel
@ 2013-01-17 10:55                       ` Will Deacon
  0 siblings, 0 replies; 32+ messages in thread
From: Will Deacon @ 2013-01-17 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 16, 2013 at 12:14:59AM +0000, Pratik Patel wrote:
> On Mon, Jan 07, 2013 at 11:58:36AM +0000, Will Deacon wrote:
> > On Thu, Jan 03, 2013 at 06:06:43PM +0000, Pratik Patel wrote:
> > > Whats the advantage in using debugfs here?
> > 
> > The main things I like about debugfs are (a) it's a text-driven interface
> > and easy to script with and (b) it matches what we do for ftrace.
> > 
> > Furthermore, it means that subtle differences between devices can be hidden
> > in the driver and not require different vendor tools for parsing the trace
> > data.
> > 
> Sorry for the delay and maybe I am missing something but it seems
> we can take care of such protocol or parsing/decoding differences
> even with device nodes since that seems independent of the
> interface used - per device debugfs attributes or per device
> device nodes.

You seem to be arguing that the two interfaces are equivalent, in which case
I say that we should follow ftrace's lead and use debugfs for this...

...but I still maintain that debugfs is also far easier to work with from
userspace.

> CoreSight trace solution is typically a SoC wide solution and
> hence can get used by non-Linux processors or hardware. Using
> debugfs would imply compiling it and exposing all the debug
> knobs even if the use case was to use the CoreSight solution for
> something that didn't need all that.

Many debug features require debugfs to be compiled, so I don't buy that as a
show-stopping argument in favour of using dev nodes. I also think that exposing
all of the debug knobs is actually a good thing, given the low-level nature of
coresight devices (where we're offloading most of the knowledge to userspace
anyway).

Will

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [RFC 2/8] coresight: add CoreSight TMC driver
  2012-12-18 19:19 ` [RFC 2/8] coresight: add CoreSight TMC driver pratikp at codeaurora.org
@ 2013-02-21 14:20   ` Robert MARKLUND
  0 siblings, 0 replies; 32+ messages in thread
From: Robert MARKLUND @ 2013-02-21 14:20 UTC (permalink / raw)
  To: linux-arm-kernel

There is something fishy here.

> +static void __tmc_etb_dump(struct tmc_drvdata *drvdata)
> +{
> +	enum tmc_mem_intf_width memwidth;
> +	uint8_t memwords;
> +	char *bufp;
> +	uint32_t read_data;
> +	int i;
> +
> +	memwidth = BMVAL(tmc_readl(drvdata, CORESIGHT_DEVID), 8, 10);
> +	if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
> +		memwords = 1;
> +	else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
> +		memwords = 2;
> +	else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
> +		memwords = 4;
> +	else
> +		memwords = 8;
> +
> +	bufp = drvdata->buf;
> +	while (1) {
> +		for (i = 0; i < memwords; i++) {
> +			read_data = tmc_readl(drvdata, TMC_RRD);
> +			if (read_data == 0xFFFFFFFF)
> +				return;
> +			memcpy(bufp, &read_data, BYTES_PER_WORD);
> +			bufp += BYTES_PER_WORD;
> +		}
This will loop for every if in ETB mode because it will trace the reading because we have not disabled it before this.
So maybe disable it first and as a security check for buffer size you have it in the drvdata I think.

> +	}
> +}
> +
> --
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

BR
Robert

^ permalink raw reply	[flat|nested] 32+ messages in thread

* CoreSight framework and drivers
  2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
                   ` (8 preceding siblings ...)
  2012-12-19 11:23 ` CoreSight framework and drivers Will Deacon
@ 2013-02-21 14:32 ` Robert MARKLUND
  9 siblings, 0 replies; 32+ messages in thread
From: Robert MARKLUND @ 2013-02-21 14:32 UTC (permalink / raw)
  To: linux-arm-kernel

Would it be easy to add dummy sources to control data coming from other ETM sources not controlled by the kernel.
Also I want the ability to have multiple sinks enabled at one time and just control the flow from the sources to direct where the data goes.
Not that clear but I hope you understand :)

BR
Robert

> -----Original Message-----
> From: linux-arm-kernel-bounces at lists.infradead.org [mailto:linux-arm-kernel-bounces at lists.infradead.org] On Behalf Of
> pratikp at codeaurora.org
> Sent: den 18 december 2012 20:19
> To: linux-arm-kernel at lists.infradead.org
> Cc: linux at arm.linux.org.uk; linus.walleij at linaro.org; will.deacon at arm.com; Magnus PERSSON; david.rusling at linaro.org;
> arve at android.com; dsaxena at linaro.org; john.stultz at linaro.org; jon-hunter at ti.com; d-deao at ti.com; Christian BEJRAM; devicetree-
> discuss at lists.ozlabs.org
> Subject: CoreSight framework and drivers
> 
> This RFC is aimed at introducing CoreSight framework as well as
> individual CoreSight trace component drivers adhering to ARM
> CoreSight specification. Some prior discussion on this can be
> referred at [1].
> 
> There are 3 kinds of CoreSight trace components:
> 
> * Sources: Responsible for producing trace data to provide
>   visibility for the associated entity.
> 
> * Links: Transport components that carry trace data.
> 
> * Sinks: Collectors for storing trace data or acting as conduits
>   for off-chip trace data collection.
> 
> These components can be connected in various topologies to suite
> a particular SoCs tracing needs.
> 
> Framework is responsible for gathering and using the information
> about the registered CoreSight components and their connections
> to allow it to dynamically deduce the sequence of components
> representing a connection from a CoreSight source to the
> currently selected CoreSight sink. This helps the framework to
> program the correct set of components to satisfy user request.
> 
> [1] http://comments.gmane.org/gmane.linux.ports.arm.kernel/204591
> 
> Pratik Patel (8):
>   coresight: add CoreSight core layer framework
>   coresight: add CoreSight TMC driver
>   coresight: add CoreSight TPIU driver
>   coresight: add CoreSight ETB driver
>   coresight: add CoreSight Funnel driver
>   coresight: add CoreSight Replicator driver
>   coresight: add CoreSight STM driver
>   coresight: add CoreSight ETM driver
> 
>  Documentation/devicetree/bindings/arm/coresight.txt |  110 ++
>  arch/arm/include/asm/hardware/cp14.h                |  540 ++++++
>  drivers/Kconfig                                     |    2 +
>  drivers/Makefile                                    |    1 +
>  drivers/coresight/Kconfig                           |   60 +
>  drivers/coresight/Makefile                          |    8 +
>  drivers/coresight/coresight-etb.c                   |  467 +++++
>  drivers/coresight/coresight-etm-cp14.c              |  510 ++++++
>  drivers/coresight/coresight-etm.c                   | 1752 +++++++++++++++++++
>  drivers/coresight/coresight-funnel.c                |  260 +++
>  drivers/coresight/coresight-priv.h                  |   48 +
>  drivers/coresight/coresight-replicator.c            |  211 +++
>  drivers/coresight/coresight-stm.c                   |  819 +++++++++
>  drivers/coresight/coresight-tmc.c                   |  794 +++++++++
>  drivers/coresight/coresight-tpiu.c                  |  232 +++
>  drivers/coresight/coresight.c                       |  681 +++++++
>  drivers/coresight/of_coresight.c                    |   99 ++
>  include/linux/coresight-stm.h                       |   51 +
>  include/linux/coresight.h                           |  167 ++
>  include/linux/of_coresight.h                        |   27 +
>  20 files changed, 6839 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/coresight.txt
>  create mode 100644 arch/arm/include/asm/hardware/cp14.h
>  create mode 100644 drivers/coresight/Kconfig
>  create mode 100644 drivers/coresight/Makefile
>  create mode 100644 drivers/coresight/coresight-etb.c
>  create mode 100644 drivers/coresight/coresight-etm-cp14.c
>  create mode 100644 drivers/coresight/coresight-etm.c
>  create mode 100644 drivers/coresight/coresight-funnel.c
>  create mode 100644 drivers/coresight/coresight-priv.h
>  create mode 100644 drivers/coresight/coresight-replicator.c
>  create mode 100644 drivers/coresight/coresight-stm.c
>  create mode 100644 drivers/coresight/coresight-tmc.c
>  create mode 100644 drivers/coresight/coresight-tpiu.c
>  create mode 100644 drivers/coresight/coresight.c
>  create mode 100644 drivers/coresight/of_coresight.c
>  create mode 100644 include/linux/coresight-stm.h
>  create mode 100644 include/linux/coresight.h
>  create mode 100644 include/linux/of_coresight.h
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2013-02-21 14:32 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-18 19:19 CoreSight framework and drivers pratikp at codeaurora.org
2012-12-18 19:19 ` [RFC 1/8] coresight: add CoreSight core layer framework pratikp at codeaurora.org
2012-12-18 19:19 ` [RFC 2/8] coresight: add CoreSight TMC driver pratikp at codeaurora.org
2013-02-21 14:20   ` Robert MARKLUND
2012-12-18 19:19 ` [RFC 3/8] coresight: add CoreSight TPIU driver pratikp at codeaurora.org
2012-12-18 19:19 ` [RFC 4/8] coresight: add CoreSight ETB driver pratikp at codeaurora.org
2012-12-20 17:49   ` Jon Hunter
2012-12-20 19:54     ` Pratik Patel
2012-12-18 19:19 ` [RFC 5/8] coresight: add CoreSight Funnel driver pratikp at codeaurora.org
2012-12-18 19:19 ` [RFC 6/8] coresight: add CoreSight Replicator driver pratikp at codeaurora.org
2012-12-18 19:19 ` [RFC 7/8] coresight: add CoreSight STM driver pratikp at codeaurora.org
2012-12-18 19:19 ` [RFC 8/8] coresight: add CoreSight ETM driver pratikp at codeaurora.org
2012-12-19 11:23 ` CoreSight framework and drivers Will Deacon
2012-12-19 17:03   ` Jon Hunter
2012-12-19 21:24     ` Pratik Patel
2012-12-20 17:46       ` Jon Hunter
2012-12-20 19:51         ` Pratik Patel
2012-12-20 20:16           ` Jean Pihet
2012-12-21 22:12             ` Pratik Patel
2012-12-20 22:54           ` Jon Hunter
2012-12-20 23:40             ` Russell King - ARM Linux
2012-12-21 22:17               ` Pratik Patel
2012-12-21 22:18             ` Pratik Patel
2012-12-23 11:32               ` Will Deacon
2013-01-03 18:06                 ` Pratik Patel
2013-01-07 11:58                   ` Will Deacon
2013-01-16  0:14                     ` Pratik Patel
2013-01-17 10:55                       ` Will Deacon
2013-01-02 20:00               ` Jon Hunter
2013-01-03 19:32                 ` Pratik Patel
2012-12-19 21:06   ` Pratik Patel
2013-02-21 14:32 ` Robert MARKLUND

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).