linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/11] CoreSight framework and drivers
@ 2014-05-30 13:43 mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 01/11] coresight: add CoreSight core layer framework mathieu.poirier
                   ` (10 more replies)
  0 siblings, 11 replies; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

From: Mathieu Poirier <mathieu.poirier@linaro.org>

This RFC is rescucitating the work submitted by Pratik Patel in 
2012 [1].  

This set is addressing comments gathered from the initial RFC
and enhance the framework in a few areas.  More specifically:

. Sysfs entries have been moved to debugfs.
. The removal of the "bus" concept.
. Setting the size of the ETB in accordance to HW capabilities.
. Adding a "status" entry in debugfs to better debug ETM configurations.
. Adding cpu affinity for ETM/PTMs.
. Tying of each IP block to a specific and configurable clock.
. Adjusted the ETM/PTM power up sequence.
. Adding support for beagle/beagleXM and ARM's TC2 platform.

Support for other platforms will be coming shortly but we felt 
confident the current code base was mature enough to suscitate 
comments.  More advanced features like CTI and STMs present in 
the original patchset was intentionally left out to concentrate
on the foundation.  They will be added at a later stage when the 
initial framework has been ironned-out.

Regards,
Mathieu


[1]. http://lists.infradead.org/pipermail/linux-arm-kernel/2012-December/138028.html

Mathieu Poirier (3):
  coresight: adding basic support for Vexpress TC2
  coresight: adding support for beagleXM
  ARM: moving support for etb/etm to the "drivers" directory

Panchaxari Prasannamurthy (1):
  coresight: adding support for beagle board

Pratik Patel (7):
  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 ETM driver

 .../devicetree/bindings/arm/coresight.txt          |  138 ++
 arch/arm/boot/dts/omap3-beagle-xm.dts              |   30 +
 arch/arm/boot/dts/omap3-beagle.dts                 |   30 +
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts         |  122 +
 arch/arm/include/asm/hardware/coresight.h          |  157 --
 arch/arm/include/asm/hardware/cp14.h               |  540 +++++
 arch/arm/kernel/Makefile                           |    1 -
 arch/arm/kernel/etm.c                              |  654 ------
 arch/arm/kernel/hw_breakpoint.c                    |    4 +-
 arch/arm/mach-omap2/Kconfig                        |    8 -
 arch/arm/mach-omap2/Makefile                       |    1 -
 arch/arm/mach-omap2/emu.c                          |   50 -
 drivers/Kconfig                                    |    2 +
 drivers/Makefile                                   |    1 +
 drivers/coresight/Kconfig                          |   37 +
 drivers/coresight/Makefile                         |    8 +
 drivers/coresight/coresight-etb.c                  |  586 +++++
 drivers/coresight/coresight-etm-cp14.c             |  511 +++++
 drivers/coresight/coresight-etm.c                  | 2360 ++++++++++++++++++++
 drivers/coresight/coresight-funnel.c               |  310 +++
 drivers/coresight/coresight-priv.h                 |   46 +
 drivers/coresight/coresight-replicator.c           |  130 ++
 drivers/coresight/coresight-tmc.c                  |  796 +++++++
 drivers/coresight/coresight-tpiu.c                 |  229 ++
 drivers/coresight/coresight.c                      |  739 ++++++
 drivers/coresight/of_coresight.c                   |  124 +
 include/linux/coresight.h                          |  181 ++
 include/linux/of_coresight.h                       |   27 +
 28 files changed, 6949 insertions(+), 873 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/coresight.txt
 delete mode 100644 arch/arm/include/asm/hardware/coresight.h
 create mode 100644 arch/arm/include/asm/hardware/cp14.h
 delete mode 100644 arch/arm/kernel/etm.c
 delete mode 100644 arch/arm/mach-omap2/emu.c
 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-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.h
 create mode 100644 include/linux/of_coresight.h

-- 
1.9.1


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

* [RFC PATCH 01/11] coresight: add CoreSight core layer framework
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-05-30 17:25   ` Rob Herring
  2014-05-30 13:43 ` [RFC PATCH 02/11] coresight: add CoreSight TMC driver mathieu.poirier
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

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 debugfs.

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>
Signed-off-by: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 .../devicetree/bindings/arm/coresight.txt          | 138 ++++
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/coresight/Kconfig                          |   9 +
 drivers/coresight/Makefile                         |   5 +
 drivers/coresight/coresight-priv.h                 |  46 ++
 drivers/coresight/coresight.c                      | 739 +++++++++++++++++++++
 drivers/coresight/of_coresight.c                   | 124 ++++
 include/linux/coresight.h                          | 181 +++++
 include/linux/of_coresight.h                       |  27 +
 10 files changed, 1272 insertions(+)
 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..3e21665
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -0,0 +1,138 @@
+* 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
+- arm,buffer-size : size of contiguous buffer space for TMC ETR
+- arm,cp14 : cp14 access to ETM registers is implemented and should be used
+- clocks : the clock associated to the coresight entity.
+- cpu: only valid for ETM/PTMs - the cpu this ETM/PTM is affined to.
+
+Example:
+
+1. Bus declaration:
+	coresight {
+		compatible = "arm,coresight";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		...
+		...
+		...
+        };
+
+	 coresight {
+		compatible = "arm,coresight";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x20010000 0 0x20010000 0x1000
+			  0x20030000 0 0x20030000 0x1000
+			  0x20040000 0 0x20040000 0x1000
+			  0x2201c000 0 0x2201c000 0x1000
+			  0x2201d000 0 0x2201d000 0x1000
+			  0x2203c000 0 0x2203c000 0x1000
+			  0x2203d000 0 0x2203d000 0x1000
+			  0x2203e000 0 0x2203e000 0x1000>;
+		...
+		...
+		...
+	};
+
+2. Sinks
+	etb: etb@20010000 {
+		compatible = "arm,coresight-etb";
+		reg = <0x20010000 0x1000>;
+
+		coresight-id = <0>;
+		coresight-name = "coresight-etb";
+		coresight-nr-inports = <1>;
+		coresight-default-sink;
+	};
+
+	tpiu: tpiu@20030000 {
+		compatible = "arm,coresight-tpiu";
+		reg = <0x20030000 0x1000>;
+
+		coresight-id = <1>;
+		coresight-name = "coresight-tpiu";
+		coresight-nr-inports = <1>;
+	};
+
+3. Links
+	replicator: replicator {
+		compatible = "arm,coresight-replicator";
+
+		coresight-id = <2>;
+		coresight-name = "coresight-replicator";
+		coresight-nr-inports = <1>;
+		coresight-outports = <0 1>;
+		coresight-child-list = <&etb &tpiu>;
+		coresight-child-ports = <0 0>;
+	};
+
+	funnel: funnel@20040000 {
+		compatible = "arm,coresight-funnel";
+		reg = <0x20040000 0x1000>;
+
+		coresight-id = <3>;
+		coresight-name = "coresight-funnel";
+		coresight-nr-inports = <8>;
+		coresight-outports = <0>;
+		coresight-child-list = <&replicator>;
+		coresight-child-ports = <0>;
+	};
+
+4. Sources
+	ptm0: ptm@2201c000 {
+		compatible = "arm,coresight-etm";
+		reg = <0x2201c000 0x1000>;
+
+		coresight-id = <9>;
+		coresight-name = "coresight-ptm0";
+		cpu = <&cpu0>;
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel>;
+		coresight-child-ports = <0>;
+	};
+
+	etm0: etm@2203c000 {
+		compatible = "arm,coresight-etm";
+		reg = <0x2203c000 0x1000>;
+
+		coresight-id = <10>;
+		coresight-name = "coresight-etm0";
+		cpu = <&cpu1>;
+		coresight-nr-inports = <0>;
+		coresight-outports = <0>;
+		coresight-child-list = <&funnel>;
+		coresight-child-ports = <2>;
+	};
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b3138fb..55e857c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -170,4 +170,6 @@ source "drivers/phy/Kconfig"
 
 source "drivers/powercap/Kconfig"
 
+source "drivers/coresight/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 8e3b8b0..4e561ec 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -155,3 +155,4 @@ obj-$(CONFIG_IPACK_BUS)		+= ipack/
 obj-$(CONFIG_NTB)		+= ntb/
 obj-$(CONFIG_FMC)		+= fmc/
 obj-$(CONFIG_POWERCAP)		+= powercap/
+obj-$(CONFIG_CORESIGHT)		+= coresight/
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
new file mode 100644
index 0000000..88fd44a
--- /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
+	  the debugfs 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..551dbf1
--- /dev/null
+++ b/drivers/coresight/coresight-priv.h
@@ -0,0 +1,46 @@
+/* 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 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..fc8d7b4
--- /dev/null
+++ b/drivers/coresight/coresight.c
@@ -0,0 +1,739 @@
+/* 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 <linux/of_platform.h>
+#include <linux/debugfs.h>
+
+#include "coresight-priv.h"
+
+#define NO_SINK		(-1)
+
+struct dentry *debug_parent;
+
+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 debugfs_curr_sink_write(struct file *file,
+				       const char __user *buf,
+				       size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	struct coresight_device *csdev = file->private_data;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (val) {
+		ret = coresight_switch_sink(csdev);
+		if (ret)
+			return ret;
+	} else
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t debugfs_curr_sink_read(struct file *file, char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	struct coresight_device *csdev = file->private_data;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+	ret =  scnprintf(buf, PAGE_SIZE, "%u\n",
+			 csdev->id == curr_sink ? 1 : 0);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debugfs_curr_sink_ops = {
+	.open = simple_open,
+	.read = debugfs_curr_sink_read,
+	.write = debugfs_curr_sink_write,
+};
+
+static const struct coresight_ops_entry debugfs_curr_sink_entry = {
+	.name = "curr_sink",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_curr_sink_ops,
+};
+
+static ssize_t debugfs_enable_write(struct file *file,
+				    const char __user *buf,
+				    size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	struct coresight_device *csdev = file->private_data;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (val) {
+		ret = coresight_enable(csdev);
+		if (ret)
+			return ret;
+	} else
+		coresight_disable(csdev);
+
+	return count;
+}
+
+static ssize_t debugfs_enable_read(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	int ret;
+	struct coresight_device *csdev = file->private_data;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+	ret = scnprintf(buf, PAGE_SIZE, "%u\n", (unsigned)csdev->enable);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debugfs_enable_ops = {
+	.open = simple_open,
+	.read = debugfs_enable_read,
+	.write = debugfs_enable_write,
+};
+
+static const struct coresight_ops_entry debugfs_enable_entry = {
+	.name = "enable",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_enable_ops,
+};
+
+static const struct coresight_ops_entry *coresight_grps_sink[] = {
+	&debugfs_curr_sink_entry,
+	NULL,
+};
+
+static const struct coresight_ops_entry *coresight_grps_source[] = {
+	&debugfs_enable_entry,
+	NULL,
+};
+
+struct coresight_group_entries {
+	const char *name;
+	const struct coresight_ops_entry **entries;
+};
+
+struct coresight_group_entries coresight_debugfs_entries[] = {
+	{
+		.name = "none",
+	},
+	{
+		.name = "sink",
+		.entries = coresight_grps_sink,
+	},
+	{
+		.name = "link",
+	},
+	{
+		.name = "linksink",
+	},
+	{
+		.name = "source",
+		.entries = coresight_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);
+	}
+}
+
+static struct dentry *coresight_debugfs_desc_init(
+				struct coresight_device *csdev,
+				const struct coresight_ops_entry **debugfs_ops)
+{
+	int i = 0;
+	struct dentry *parent;
+	struct device *dev = &csdev->dev;
+	const struct coresight_ops_entry *ops_entry, **ops_entries;
+
+	parent = debugfs_create_dir(dev_name(dev), debug_parent);
+	if (IS_ERR(parent))
+		return NULL;
+
+	/* device-specific ops */
+	while (debugfs_ops && debugfs_ops[i]) {
+		ops_entry = debugfs_ops[i];
+		debugfs_create_file(ops_entry->name, ops_entry->mode,
+				    parent, dev_get_drvdata(dev->parent),
+				    ops_entry->ops);
+		i++;
+	}
+
+	/* group-specific ops */
+	i = 0;
+	ops_entries = coresight_debugfs_entries[csdev->type].entries;
+
+	while (ops_entries && ops_entries[i]) {
+		debugfs_create_file(ops_entries[i]->name, ops_entries[i]->mode,
+				    parent, csdev, ops_entries[i]->ops);
+		i++;
+	}
+
+	return parent;
+}
+
+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.parent = desc->dev;
+	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;
+
+	csdev->de = coresight_debugfs_desc_init(csdev, desc->debugfs_ops);
+	if (!csdev->de)
+		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);
+	}
+
+	debugfs_remove_recursive(csdev->de);
+}
+EXPORT_SYMBOL_GPL(coresight_unregister);
+
+static int debugfs_coresight_init(void)
+{
+	debug_parent = debugfs_create_dir("coresight", 0);
+	if (IS_ERR(debug_parent))
+		return -1;
+
+	return 0;
+}
+
+static struct of_device_id coresight_match[] = {
+	{.compatible = "arm,coresight"},
+	{}
+};
+
+static int __init coresight_init(void)
+{
+	if (debugfs_coresight_init())
+		pr_info("coresight: problem creating debugfs entry\n");
+
+	return of_platform_bus_probe(NULL, coresight_match, NULL);
+}
+subsys_initcall(coresight_init);
+
+static void __exit coresight_exit(void) {}
+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..34576ea
--- /dev/null
+++ b/drivers/coresight/of_coresight.c
@@ -0,0 +1,124 @@
+/* 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/clk.h>
+#include <linux/of.h>
+#include <linux/coresight.h>
+#include <asm/smp_plat.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 clk *clk;
+	struct device_node *child_node, *cpu;
+	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");
+
+	/* affinity defaults to CPU0 */
+	pdata->cpu = 0;
+	cpu = of_parse_phandle(node, "cpu", 0);
+	if (cpu) {
+		const u32 *mpidr;
+		int len, index;
+
+		mpidr = of_get_property(cpu, "reg", &len);
+		if (mpidr && len == 4) {
+			index = get_logical_index(be32_to_cpup(mpidr));
+			if (index != -EINVAL)
+				pdata->cpu = index;
+		}
+	}
+
+	/* clock specifics */
+	pdata->clk = NULL;
+	clk = of_clk_get(node, 0);
+	if (!IS_ERR(clk))
+		pdata->clk = clk;
+
+	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..e3c9126
--- /dev/null
+++ b/include/linux/coresight.h
@@ -0,0 +1,181 @@
+/* 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 ETM_ARCH_V3_5		(0x25)
+#define PFT_ARCH_V1_1		(0x31)
+
+#define CORESIGHT_UNLOCK	(0xC5ACCE55)
+
+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_ops_entry {
+	const char *name;
+	umode_t mode;
+	const struct file_operations *ops;
+};
+
+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;
+	int cpu;
+	const char *name;
+	int nr_inports;
+	const int *outports;
+	const int *child_ids;
+	const int *child_ports;
+	int nr_outports;
+	bool default_sink;
+	struct clk *clk;
+};
+
+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 coresight_ops_entry **debugfs_ops;
+	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 dentry *de;
+	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);
+extern struct clk *coresight_get_clk(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) {}
+extern struct clk *coresight_get_clk(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
-- 
1.9.1


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

* [RFC PATCH 02/11] coresight: add CoreSight TMC driver
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 01/11] coresight: add CoreSight core layer framework mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-06-03  9:09   ` Linus Walleij
  2014-05-30 13:43 ` [RFC PATCH 03/11] coresight: add CoreSight TPIU driver mathieu.poirier
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

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>
Signed-off-by: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/coresight/Kconfig         |  11 +
 drivers/coresight/Makefile        |   1 +
 drivers/coresight/coresight-tmc.c | 796 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 808 insertions(+)
 create mode 100644 drivers/coresight/coresight-tmc.c

diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 88fd44a..224903b 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
 	  the debugfs 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..afcab7c
--- /dev/null
+++ b/drivers/coresight/coresight-tmc.c
@@ -0,0 +1,796 @@
+/* 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 {									\
+	/* settle everything first */					\
+	mb();								\
+	tmc_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define TMC_UNLOCK(drvdata)						\
+do {									\
+	tmc_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	/* make sure everyone sees this */				\
+	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 debugfs_trigger_cntr_read(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+	struct tmc_drvdata *drvdata = file->private_data;
+	unsigned long val = drvdata->trigger_cntr;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+	ret =  scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+}
+
+static ssize_t debugfs_trigger_cntr_write(struct file *file,
+					  const char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct tmc_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->trigger_cntr = val;
+	return count;
+}
+
+static const struct file_operations debugfs_trigger_cntr_ops = {
+	.open = simple_open,
+	.read = debugfs_trigger_cntr_read,
+	.write =  debugfs_trigger_cntr_write,
+};
+
+static const struct coresight_ops_entry debugfs_trigger_cntr_entry = {
+	.name = "trigger_cntr",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_trigger_cntr_ops,
+};
+
+static const struct coresight_ops_entry *tmc_etb_attr_grps[] = {
+	&debugfs_trigger_cntr_entry,
+	NULL,
+};
+
+static const struct coresight_ops_entry *tmc_etr_attr_grps[] = {
+	&debugfs_trigger_cntr_entry,
+	NULL,
+};
+
+static const struct coresight_ops_entry *tmc_etf_attr_grps[] = {
+	&debugfs_trigger_cntr_entry,
+	NULL,
+};
+
+static int tmc_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	uint32_t devid;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata = NULL;
+	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);
+
+	if (pdata && pdata->clk) {
+		drvdata->clk = pdata->clk;
+		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->debugfs_ops = 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->debugfs_ops = 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->debugfs_ops = 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 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         = 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");
-- 
1.9.1


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

* [RFC PATCH 03/11] coresight: add CoreSight TPIU driver
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 01/11] coresight: add CoreSight core layer framework mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 02/11] coresight: add CoreSight TMC driver mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 04/11] coresight: add CoreSight ETB driver mathieu.poirier
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

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>
Signed-off-by: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/coresight/Makefile         |   2 +-
 drivers/coresight/coresight-tpiu.c | 229 +++++++++++++++++++++++++++++++++++++
 2 files changed, 230 insertions(+), 1 deletion(-)
 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..b552d1e
--- /dev/null
+++ b/drivers/coresight/coresight-tpiu.c
@@ -0,0 +1,229 @@
+/* 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 {									\
+	/* wait for things to settle */					\
+	mb();								\
+	tpiu_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define TPIU_UNLOCK(drvdata)						\
+do {									\
+	tpiu_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	/* make sure everyone has seen this */				\
+	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 tpiu_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata = NULL;
+	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;
+
+	if (pdata && pdata->clk) {
+		drvdata->clk = pdata->clk;
+		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 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         = 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");
-- 
1.9.1


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

* [RFC PATCH 04/11] coresight: add CoreSight ETB driver
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
                   ` (2 preceding siblings ...)
  2014-05-30 13:43 ` [RFC PATCH 03/11] coresight: add CoreSight TPIU driver mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-05-30 13:53   ` Russell King - ARM Linux
  2014-05-30 13:43 ` [RFC PATCH 05/11] coresight: add CoreSight Funnel driver mathieu.poirier
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

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>
Signed-off-by: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/coresight/Makefile        |   3 +-
 drivers/coresight/coresight-etb.c | 586 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 588 insertions(+), 1 deletion(-)
 create mode 100644 drivers/coresight/coresight-etb.c

diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 540df99..8d4443b 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -3,4 +3,5 @@
 #
 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..5cb0dcb
--- /dev/null
+++ b/drivers/coresight/coresight-etb.c
@@ -0,0 +1,586 @@
+/* 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 {									\
+	/* wait for things to settle */					\
+	mb();								\
+	etb_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define ETB_UNLOCK(drvdata)						\
+do {									\
+	etb_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	/* make sure eveyone has seen this */				\
+	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 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;
+	uint32_t		buffer_depth;
+	bool			enable;
+	uint32_t		trigger_cntr;
+};
+
+static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata)
+{
+	int ret;
+	uint32_t depth = 0;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	/* RO registers don't need locking */
+	depth = etb_readl(drvdata, ETB_RAM_DEPTH_REG);
+
+	clk_disable_unprepare(drvdata->clk);
+	return depth;
+}
+
+static void __etb_enable(struct etb_drvdata *drvdata)
+{
+	int i;
+	uint32_t depth;
+
+	ETB_UNLOCK(drvdata);
+
+	depth = drvdata->buffer_depth;
+	etb_writel(drvdata, 0x0, ETB_RAM_WRITE_POINTER);
+	for (i = 0; i < depth; 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, depth;
+	uint32_t read_ptr, write_ptr;
+	uint32_t frame_off, 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);
+
+	depth = drvdata->buffer_depth;
+	buf_ptr = drvdata->buf;
+	for (i = 0; i < depth; 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)
+{
+	uint32_t depth;
+	struct etb_drvdata *drvdata = container_of(file->private_data,
+						   struct etb_drvdata, miscdev);
+
+	if (drvdata->reading == false) {
+		etb_dump(drvdata);
+		drvdata->reading = true;
+	}
+
+	depth = drvdata->buffer_depth;
+	if (*ppos + len > depth * BYTES_PER_WORD)
+		len = depth * 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) (depth * 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 debug_status_show(struct file *file, char __user *user_buf,
+				 size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+	unsigned long flags;
+	uint32_t etb_rdr, etb_sr, etb_rrp, etb_rwp;
+	uint32_t etb_trg, etb_cr, etb_ffsr, etb_ffcr;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etb_drvdata *drvdata = file->private_data;
+
+	if (!buf)
+		return -ENOMEM;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		goto out;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	ETB_UNLOCK(drvdata);
+
+	etb_rdr = etb_readl(drvdata, ETB_RAM_DEPTH_REG);
+	etb_sr = etb_readl(drvdata, ETB_STATUS_REG);
+	etb_rrp = etb_readl(drvdata, ETB_RAM_READ_POINTER);
+	etb_rwp = etb_readl(drvdata, ETB_RAM_WRITE_POINTER);
+	etb_trg = etb_readl(drvdata, ETB_TRG);
+	etb_cr = etb_readl(drvdata, ETB_CTL_REG);
+	etb_ffsr = etb_readl(drvdata, ETB_FFSR);
+	etb_ffcr = etb_readl(drvdata, ETB_FFCR);
+
+	ETB_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	ret = snprintf(buf, PAGE_SIZE,
+		       "Depth:\t\t0x%x\n"
+		       "Status:\t\t0x%x\n"
+		       "RAM read ptr:\t0x%x\n"
+		       "RAM wrt ptr:\t0x%x\n"
+		       "Trigger cnt:\t0x%x\n"
+		       "Control:\t0x%x\n"
+		       "Flush status:\t0x%x\n"
+		       "Flush ctrl:\t0x%x\n",
+			etb_rdr, etb_sr, etb_rrp, etb_rwp,
+			etb_trg, etb_cr, etb_ffsr, etb_ffcr);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+out:
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debug_status_ops = {
+	.open = simple_open,
+	.read = debug_status_show,
+};
+
+static const struct coresight_ops_entry debug_status_entry = {
+	.name = "status",
+	.mode = S_IRUGO,
+	.ops = &debug_status_ops,
+};
+
+static ssize_t debug_trigger_cntr_read(struct file *file, char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+	struct etb_drvdata *drvdata = file->private_data;
+	unsigned long val = drvdata->trigger_cntr;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debug_trigger_cntr_write(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	struct etb_drvdata *drvdata = file->private_data;
+	unsigned long val = 0;
+	char *buf;
+	int ret, len = 0;
+
+	buf = kmalloc(count + 1, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, user_buf, count)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	buf[count] = '\0';
+
+	len = sscanf(buf, "%lx", &val);
+	if (len !=  1) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	drvdata->trigger_cntr = val;
+	return count;
+
+out:
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debug_trigger_cntr_ops = {
+	.open = simple_open,
+	.read = debug_trigger_cntr_read,
+	.write = debug_trigger_cntr_write,
+};
+
+static const struct coresight_ops_entry debug_trigger_cntr_entry = {
+	.name = "trigger_cntr",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debug_trigger_cntr_ops,
+};
+
+static const struct coresight_ops_entry *etb_attr_grps[] = {
+	&debug_trigger_cntr_entry,
+	&debug_status_entry,
+	NULL,
+};
+
+static int etb_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata = NULL;
+	struct etb_drvdata *drvdata;
+	struct resource *res;
+	struct coresight_desc *desc;
+	struct device_node *np = pdev->dev.of_node;
+
+	if (np) {
+		pdata = of_get_coresight_platform_data(dev, np);
+		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);
+
+	if (pdata && pdata->clk) {
+		drvdata->clk = pdata->clk;
+		ret = clk_prepare_enable(drvdata->clk);
+		if (ret)
+			return ret;
+	}
+
+	drvdata->buffer_depth =  etb_get_buffer_depth(drvdata);
+	clk_disable_unprepare(drvdata->clk);
+
+	if (drvdata->buffer_depth < 0)
+		return -EINVAL;
+	drvdata->buf = devm_kzalloc(dev,
+				    drvdata->buffer_depth * 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->debugfs_ops = 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 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         = 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");
-- 
1.9.1


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

* [RFC PATCH 05/11] coresight: add CoreSight Funnel driver
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
                   ` (3 preceding siblings ...)
  2014-05-30 13:43 ` [RFC PATCH 04/11] coresight: add CoreSight ETB driver mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 06/11] coresight: add CoreSight Replicator driver mathieu.poirier
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

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>
Signed-off-by: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/coresight/Makefile           |   2 +-
 drivers/coresight/coresight-funnel.c | 310 +++++++++++++++++++++++++++++++++++
 2 files changed, 311 insertions(+), 1 deletion(-)
 create mode 100644 drivers/coresight/coresight-funnel.c

diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 8d4443b..1f66804 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -4,4 +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-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..c1024df
--- /dev/null
+++ b/drivers/coresight/coresight-funnel.c
@@ -0,0 +1,310 @@
+/* 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/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 {									\
+	/* wait for things to settle */					\
+	mb();								\
+	funnel_writel(drvdata, 0x0, CORESIGHT_LAR);			\
+} while (0)
+#define FUNNEL_UNLOCK(drvdata)						\
+do {									\
+	funnel_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);	\
+	/* make sure everyone has seen this */				\
+	mb();								\
+} while (0)
+
+#define FUNNEL_FUNCTL		(0x000)
+#define FUNNEL_PRICTL		(0x004)
+
+#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 debugfs_show_funnel_priority(struct file *file,
+					    char __user *user_buf,
+					    size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct funnel_drvdata *drvdata = file->private_data;
+
+	val = drvdata->priority;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_funnel_priority(struct file *file,
+					     const char __user *user_buf,
+					     size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct funnel_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->priority = val;
+	return count;
+}
+
+static const struct file_operations debugfs_funnel_priority_ops = {
+	.open = simple_open,
+	.read = debugfs_show_funnel_priority,
+	.write = debugfs_store_funnel_priority,
+};
+
+static const struct coresight_ops_entry debugfs_funnel_priority_entry = {
+	.name = "priority",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_funnel_priority_ops,
+};
+
+static uint32_t __get_funnel_ctrl(struct funnel_drvdata *drvdata)
+{
+	uint32_t functl;
+
+	FUNNEL_UNLOCK(drvdata);
+	functl = funnel_readl(drvdata, FUNNEL_FUNCTL);
+	FUNNEL_LOCK(drvdata);
+
+	return functl;
+}
+
+static ssize_t debugfs_show_funnel_ctrl(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	struct funnel_drvdata *drvdata = file->private_data;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		goto out;
+
+	val = __get_funnel_ctrl(drvdata);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+out:
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debugfs_funnel_ctrl_ops = {
+	.open = simple_open,
+	.read = debugfs_show_funnel_ctrl,
+};
+
+static const struct coresight_ops_entry debugfs_funnel_ctrl_entry = {
+	.name = "funnel_ctrl",
+	.mode =  S_IRUGO,
+	.ops = &debugfs_funnel_ctrl_ops,
+};
+
+static const struct coresight_ops_entry *funnel_attr_grps[] = {
+	&debugfs_funnel_priority_entry,
+	&debugfs_funnel_ctrl_entry,
+	NULL,
+};
+
+static int funnel_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata = NULL;
+	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;
+
+	if (pdata && pdata->clk)
+		drvdata->clk = pdata->clk;
+
+	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->debugfs_ops = 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 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         = 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");
-- 
1.9.1


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

* [RFC PATCH 06/11] coresight: add CoreSight Replicator driver
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
                   ` (4 preceding siblings ...)
  2014-05-30 13:43 ` [RFC PATCH 05/11] coresight: add CoreSight Funnel driver mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 07/11] coresight: add CoreSight ETM driver mathieu.poirier
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

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>
Signed-off-by: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 drivers/coresight/Makefile               |   2 +-
 drivers/coresight/coresight-replicator.c | 130 +++++++++++++++++++++++++++++++
 2 files changed, 131 insertions(+), 1 deletion(-)
 create mode 100644 drivers/coresight/coresight-replicator.c

diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 1f66804..25296a2 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -4,4 +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-etb.o coresight-funnel.o \
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
new file mode 100644
index 0000000..1cbb288
--- /dev/null
+++ b/drivers/coresight/coresight-replicator.c
@@ -0,0 +1,130 @@
+/* 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"
+
+struct replicator_drvdata {
+	struct device		*dev;
+	struct coresight_device	*csdev;
+};
+
+static int replicator_enable(struct coresight_device *csdev, int inport,
+			     int outport)
+{
+	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	dev_info(drvdata->dev, "REPLICATOR enabled\n");
+
+	return 0;
+}
+
+static void replicator_disable(struct coresight_device *csdev, int inport,
+			       int outport)
+{
+	struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	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 replicator_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata;
+	struct replicator_drvdata *drvdata;
+	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);
+
+	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 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 = "arm,coresight-replicator"},
+	{}
+};
+
+static struct platform_driver replicator_driver = {
+	.probe          = replicator_probe,
+	.remove         = 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");
-- 
1.9.1


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

* [RFC PATCH 07/11] coresight: add CoreSight ETM driver
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
                   ` (5 preceding siblings ...)
  2014-05-30 13:43 ` [RFC PATCH 06/11] coresight: add CoreSight Replicator driver mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-06-03 10:26   ` Daniel Thompson
  2014-05-30 13:43 ` [RFC PATCH 08/11] coresight: adding support for beagle board mathieu.poirier
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

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>
Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 arch/arm/include/asm/hardware/cp14.h   |  540 ++++++++
 drivers/coresight/Kconfig              |   17 +
 drivers/coresight/Makefile             |    3 +-
 drivers/coresight/coresight-etm-cp14.c |  511 +++++++
 drivers/coresight/coresight-etm.c      | 2360 ++++++++++++++++++++++++++++++++
 5 files changed, 3430 insertions(+), 1 deletion(-)
 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/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 224903b..f91f3db 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -17,4 +17,21 @@ config CORESIGHT_LINKS_AND_SINKS
 	  responsible for transporting and collecting the trace data
 	  respectively.
 
+config CORESIGHT_SOURCE_ETM
+	bool "CoreSight Embedded Trace Macrocell driver"
+	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
+	  debugfs.
+
+	  If unsure, say 'N' here to avoid unwanted power consumption.
 endif
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 25296a2..2b4f005 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -4,4 +4,5 @@
 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-etb.o coresight-funnel.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..0088bbb
--- /dev/null
+++ b/drivers/coresight/coresight-etm-cp14.c
@@ -0,0 +1,511 @@
+/* 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 <linux/bug.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..59589be
--- /dev/null
+++ b/drivers/coresight/coresight-etm.c
@@ -0,0 +1,2360 @@
+/* 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)
+
+#define PORT_SIZE_MASK		(BM(21, 21) | BM(4, 6))
+
+/*
+ * 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 ETMTECR2		(0x01c)
+#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;
+	int				port_size;
+	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)
+{
+	struct etm_drvdata *drvdata = (struct etm_drvdata *)info;
+	etm_writel(drvdata, 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);
+
+	/* turn engine on */
+	etm_clr_pwrdwn(drvdata);
+	/* apply power to trace registers */
+	etm_set_pwrup(drvdata);
+	/* make sure all registers are accessible */
+	etm_os_unlock(drvdata);
+
+	etm_set_prog(drvdata);
+
+	etmcr = etm_readl(drvdata, ETMCR);
+	etmcr &= (BIT(10) | BIT(0));
+	etmcr |= drvdata->port_size;
+	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);
+
+	/* ensures trace output is enabled from this ETM */
+	etm_writel(drvdata, drvdata->ctrl | BIT(11) | etmcr, ETMCR);
+
+	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 debugfs_show_nr_addr_cmp(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->nr_addr_cmp;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debugfs_nr_addr_cmp_ops = {
+	.open = simple_open,
+	.read = debugfs_show_nr_addr_cmp,
+};
+
+static const struct coresight_ops_entry debugfs_nr_addr_cmp_entry = {
+	.name = "nr_addr_cmp",
+	.mode =  S_IRUGO,
+	.ops = &debugfs_nr_addr_cmp_ops,
+};
+
+static ssize_t debugfs_show_nr_cntr(struct file *file,
+				    char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->nr_cntr;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debugfs_nr_cntr_ops = {
+	.open = simple_open,
+	.read = debugfs_show_nr_cntr,
+};
+
+static const struct coresight_ops_entry debugfs_nr_cntr_entry = {
+	.name = "nr_cntr",
+	.mode =  S_IRUGO,
+	.ops = &debugfs_nr_cntr_ops,
+};
+
+static ssize_t debugfs_show_nr_ctxid_cmp(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->nr_ctxid_cmp;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debugfs_nr_ctxid_cmp_ops = {
+	.open = simple_open,
+	.read = debugfs_show_nr_ctxid_cmp,
+};
+
+static const struct coresight_ops_entry debugfs_nr_ctxid_cmp_entry = {
+	.name = "nr_ctxid_cmp",
+	.mode =  S_IRUGO,
+	.ops = &debugfs_nr_ctxid_cmp_ops,
+};
+
+static ssize_t debugfs_show_reset(struct file *file,
+				  char __user *user_buf,
+				  size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->reset;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+/* Reset to trace everything i.e. exclude nothing. */
+static ssize_t debugfs_store_reset(struct file *file,
+				   const char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	int i;
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_reset_ops = {
+	.open = simple_open,
+	.read = debugfs_show_reset,
+	.write = debugfs_store_reset,
+};
+
+static const struct coresight_ops_entry debugfs_reset_entry = {
+	.name = "reset",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_reset_ops,
+};
+
+static ssize_t debugfs_show_mode(struct file *file,
+				 char __user *user_buf,
+				 size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->mode;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_mode(struct file *file,
+				  const char __user *user_buf,
+				  size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_mode_ops = {
+	.open = simple_open,
+	.read = debugfs_show_mode,
+	.write = debugfs_store_mode,
+};
+
+static const struct coresight_ops_entry debugfs_mode_entry = {
+	.name = "mode",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_mode_ops,
+};
+
+static ssize_t debugfs_show_trigger_event(struct file *file,
+					  char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->trigger_event;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_trigger_event(struct file *file,
+					   const char __user *user_buf,
+					   size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->trigger_event = val & ETM_EVENT_MASK;
+	return count;
+}
+
+static const struct file_operations debugfs_trigger_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_trigger_event,
+	.write = debugfs_store_trigger_event,
+};
+
+static const struct coresight_ops_entry debugfs_trigger_events_entry = {
+	.name = "trigger_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_trigger_event_ops,
+};
+
+static ssize_t debugfs_show_enable_event(struct file *file,
+					 char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->enable_event;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_enable_event(struct file *file,
+					  const char __user *user_buf,
+					  size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->enable_event = val & ETM_EVENT_MASK;
+	return count;
+}
+
+static const struct file_operations debugfs_enable_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_enable_event,
+	.write = debugfs_store_enable_event,
+};
+
+static const struct coresight_ops_entry debugfs_enable_events_entry = {
+	.name = "enable_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_enable_event_ops,
+};
+
+static ssize_t debugfs_show_fifofull_level(struct file *file,
+					   char __user *user_buf,
+					   size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->fifofull_level;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_fifofull_level(struct file *file,
+					    const char __user *user_buf,
+					    size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->fifofull_level = val;
+	return count;
+}
+
+static const struct file_operations debugfs_fifofull_level_ops = {
+	.open = simple_open,
+	.read = debugfs_show_fifofull_level,
+	.write = debugfs_store_fifofull_level,
+};
+
+static const struct coresight_ops_entry debugfs_fifofull_level_entry = {
+	.name = "fifofull_level",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_fifofull_level_ops,
+};
+
+static ssize_t debugfs_show_addr_idx(struct file *file,
+				     char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->addr_idx;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_addr_idx(struct file *file,
+				      const char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_addr_idx_ops = {
+	.open = simple_open,
+	.read = debugfs_show_addr_idx,
+	.write = debugfs_store_addr_idx,
+};
+
+static const struct coresight_ops_entry debugfs_addr_idx_entry = {
+	.name = "addr_idx",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_addr_idx_ops,
+};
+
+static ssize_t debugfs_show_addr_single(struct file *file,
+					char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	int ret;
+	uint8_t idx;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	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);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_addr_single(struct file *file,
+					 const char __user *user_buf,
+					 size_t count, loff_t *ppos)
+{
+	uint8_t idx;
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_addr_single_ops = {
+	.open = simple_open,
+	.read = debugfs_show_addr_single,
+	.write = debugfs_store_addr_single,
+};
+
+static const struct coresight_ops_entry debugfs_addr_single_entry = {
+	.name = "addr_single",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_addr_single_ops,
+};
+
+static ssize_t debugfs_show_addr_range(struct file *file,
+				       char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	int ret;
+	uint8_t idx;
+	unsigned long val1, val2;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	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);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_addr_range(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	uint8_t idx;
+	unsigned long val1, val2;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_addr_range_ops = {
+	.open = simple_open,
+	.read = debugfs_show_addr_range,
+	.write = debugfs_store_addr_range,
+};
+
+static const struct coresight_ops_entry debugfs_addr_range_entry = {
+	.name = "addr_range",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_addr_range_ops,
+};
+
+static ssize_t debugfs_show_addr_start(struct file *file,
+				       char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	int ret;
+	uint8_t idx;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	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);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_addr_start(struct file *file,
+					const char __user *user_buf,
+					size_t count, loff_t *ppos)
+{
+	uint8_t idx;
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_addr_start_ops = {
+	.open = simple_open,
+	.read = debugfs_show_addr_start,
+	.write = debugfs_store_addr_start,
+};
+
+static const struct coresight_ops_entry debugfs_addr_start_entry = {
+	.name = "addr_start",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_addr_start_ops,
+};
+
+static ssize_t debugfs_show_addr_stop(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	uint8_t idx;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	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);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_addr_stop(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	uint8_t idx;
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_addr_stop_ops = {
+	.open = simple_open,
+	.read = debugfs_show_addr_stop,
+	.write = debugfs_store_addr_stop,
+};
+
+static const struct coresight_ops_entry debugfs_addr_stop_entry = {
+	.name = "addr_stop",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_addr_stop_ops,
+};
+
+static ssize_t debugfs_show_addr_acctype(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->addr_acctype[drvdata->addr_idx];
+	spin_unlock(&drvdata->spinlock);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_addr_acctype(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->addr_acctype[drvdata->addr_idx] = val;
+	spin_unlock(&drvdata->spinlock);
+	return count;
+}
+
+static const struct file_operations debugfs_addr_acctype_ops = {
+	.open = simple_open,
+	.read = debugfs_show_addr_acctype,
+	.write = debugfs_store_addr_acctype,
+};
+
+static const struct coresight_ops_entry debugfs_addr_acctype_entry = {
+	.name = "addr_acctype",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_addr_acctype_ops,
+};
+
+static ssize_t debugfs_show_cntr_idx(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->cntr_idx;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_cntr_idx(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_cntr_idx_ops = {
+	.open = simple_open,
+	.read = debugfs_show_cntr_idx,
+	.write = debugfs_store_cntr_idx,
+};
+
+static const struct coresight_ops_entry debugfs_cntr_idx_entry = {
+	.name = "cntr_idx",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_cntr_idx_ops,
+};
+
+static ssize_t debugfs_show_cntr_rld_val(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->cntr_rld_val[drvdata->cntr_idx];
+	spin_unlock(&drvdata->spinlock);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_cntr_rld_val(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->cntr_rld_val[drvdata->cntr_idx] = val;
+	spin_unlock(&drvdata->spinlock);
+	return count;
+}
+
+static const struct file_operations debugfs_cntr_rld_val_ops = {
+	.open = simple_open,
+	.read = debugfs_show_cntr_rld_val,
+	.write = debugfs_store_cntr_rld_val,
+};
+
+static const struct coresight_ops_entry debugfs_cntr_rld_val_entry = {
+	.name = "cntr_rld_val",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_cntr_rld_val_ops,
+};
+
+static ssize_t debugfs_show_cntr_event(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->cntr_event[drvdata->cntr_idx];
+	spin_unlock(&drvdata->spinlock);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_cntr_event(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_cntr_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_cntr_event,
+	.write = debugfs_store_cntr_event,
+};
+
+static const struct coresight_ops_entry debugfs_cntr_event_entry = {
+	.name = "cntr_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_cntr_event_ops,
+};
+
+static ssize_t debugfs_show_cntr_rld_event(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->cntr_rld_event[drvdata->cntr_idx];
+	spin_unlock(&drvdata->spinlock);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_cntr_rld_event(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_cntr_rld_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_cntr_rld_event,
+	.write = debugfs_store_cntr_rld_event,
+};
+
+static const struct coresight_ops_entry debugfs_cntr_rld_event_entry = {
+	.name = "cntr_rld_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_cntr_rld_event_ops,
+};
+
+static ssize_t debugfs_show_cntr_val(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->cntr_val[drvdata->cntr_idx];
+	spin_unlock(&drvdata->spinlock);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_cntr_val(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->cntr_val[drvdata->cntr_idx] = val;
+	spin_unlock(&drvdata->spinlock);
+	return count;
+}
+
+static const struct file_operations debugfs_cntr_val_ops = {
+	.open = simple_open,
+	.read = debugfs_show_cntr_val,
+	.write = debugfs_store_cntr_val,
+};
+
+static const struct coresight_ops_entry debugfs_cntr_val_entry = {
+	.name = "cntr_val",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_cntr_val_ops,
+};
+
+static ssize_t debugfs_show_12_event(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->seq_12_event;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_12_event(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_12_event = val & ETM_EVENT_MASK;
+	return count;
+}
+
+static const struct file_operations debugfs_12_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_12_event,
+	.write = debugfs_store_12_event,
+};
+
+static const struct coresight_ops_entry debugfs_12_event_entry = {
+	.name = "seq_12_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_12_event_ops,
+};
+
+static ssize_t debugfs_show_21_event(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->seq_21_event;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_21_event(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_21_event = val & ETM_EVENT_MASK;
+	return count;
+}
+
+static const struct file_operations debugfs_21_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_21_event,
+	.write = debugfs_store_21_event,
+};
+
+static const struct coresight_ops_entry debugfs_21_event_entry = {
+	.name = "seq_21_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_21_event_ops,
+};
+
+static ssize_t debugfs_show_23_event(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->seq_23_event;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_23_event(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_23_event = val & ETM_EVENT_MASK;
+	return count;
+}
+
+static const struct file_operations debugfs_23_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_23_event,
+	.write = debugfs_store_23_event,
+};
+
+static const struct coresight_ops_entry debugfs_23_event_entry = {
+	.name = "seq_23_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_23_event_ops,
+};
+
+static ssize_t debugfs_show_31_event(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->seq_31_event;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_31_event(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_31_event = val & ETM_EVENT_MASK;
+	return count;
+}
+
+static const struct file_operations debugfs_31_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_31_event,
+	.write = debugfs_store_31_event,
+};
+
+static const struct coresight_ops_entry debugfs_31_event_entry = {
+	.name = "seq_31_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_31_event_ops,
+};
+
+static ssize_t debugfs_show_32_event(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->seq_32_event;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_32_event(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_32_event = val & ETM_EVENT_MASK;
+	return count;
+}
+static const struct file_operations debugfs_32_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_32_event,
+	.write = debugfs_store_32_event,
+};
+
+static const struct coresight_ops_entry debugfs_32_event_entry = {
+	.name = "seq_32_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_32_event_ops,
+};
+
+static ssize_t debugfs_show_13_event(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->seq_13_event;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_13_event(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->seq_13_event = val & ETM_EVENT_MASK;
+	return count;
+}
+static const struct file_operations debugfs_13_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_13_event,
+	.write = debugfs_store_13_event,
+};
+
+static const struct coresight_ops_entry debugfs_13_event_entry = {
+	.name = "seq_13_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_13_event_ops,
+};
+
+static ssize_t debugfs_show_seq_curr_state(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->seq_curr_state;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_seq_curr_state(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+	if (val > ETM_SEQ_STATE_MAX_VAL)
+		return -EINVAL;
+
+	drvdata->seq_curr_state = val;
+	return count;
+}
+
+static const struct file_operations debugfs_seq_curr_state_ops = {
+	.open = simple_open,
+	.read = debugfs_show_seq_curr_state,
+	.write = debugfs_store_seq_curr_state,
+};
+
+static const struct coresight_ops_entry debugfs_seq_curr_state_entry = {
+	.name = "seq_curr_state",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_seq_curr_state_ops,
+};
+
+static ssize_t debugfs_show_ctxid_idx(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->ctxid_idx;
+
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_ctxid_idx(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_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 count;
+}
+
+static const struct file_operations debugfs_ctxid_idx_ops = {
+	.open = simple_open,
+	.read = debugfs_show_ctxid_idx,
+	.write = debugfs_store_ctxid_idx,
+};
+
+static const struct coresight_ops_entry debugfs_ctxid_idx_entry = {
+	.name = "ctxid_idx",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_ctxid_idx_ops,
+};
+
+static ssize_t debugfs_show_ctxid_val(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	spin_lock(&drvdata->spinlock);
+	val = drvdata->ctxid_val[drvdata->ctxid_idx];
+	spin_unlock(&drvdata->spinlock);
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_ctxid_val(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	drvdata->ctxid_val[drvdata->ctxid_idx] = val;
+	spin_unlock(&drvdata->spinlock);
+	return count;
+}
+
+static const struct file_operations debugfs_ctxid_val_ops = {
+	.open = simple_open,
+	.read = debugfs_show_ctxid_val,
+	.write = debugfs_store_ctxid_val,
+};
+
+static const struct coresight_ops_entry debugfs_ctxid_val_entry = {
+	.name = "ctxid_val",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_ctxid_val_ops,
+};
+
+static ssize_t debugfs_show_ctxid_mask(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->ctxid_mask;
+
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_ctxid_mask(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->ctxid_mask = val;
+	return count;
+}
+
+static const struct file_operations debugfs_ctxid_mask_ops = {
+	.open = simple_open,
+	.read = debugfs_show_ctxid_mask,
+	.write = debugfs_store_ctxid_mask,
+};
+
+static const struct coresight_ops_entry debugfs_ctxid_mask_entry = {
+	.name = "ctxid_mask",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_ctxid_mask_ops,
+};
+
+static ssize_t debugfs_show_sync_freq(struct file *file,
+				      char __user *user_buf,
+				      size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->sync_freq;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_sync_freq(struct file *file,
+				       const char __user *user_buf,
+				       size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->sync_freq = val & ETM_SYNC_MASK;
+	return count;
+}
+
+static const struct file_operations debugfs_sync_freq_ops = {
+	.open = simple_open,
+	.read = debugfs_show_sync_freq,
+	.write = debugfs_store_sync_freq,
+};
+
+static const struct coresight_ops_entry debugfs_sync_freq_entry = {
+	.name = "sync_freq",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_sync_freq_ops,
+};
+
+static ssize_t debugfs_show_timestamp_event(struct file *file,
+					    char __user *user_buf,
+					    size_t count, loff_t *ppos)
+{
+	int ret;
+	unsigned long val;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	val = drvdata->timestamp_event;
+	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t debugfs_store_timestamp_event(struct file *file,
+					    const char __user *user_buf,
+					    size_t count, loff_t *ppos)
+{
+	unsigned long val;
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (sscanf(user_buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	drvdata->timestamp_event = val & ETM_EVENT_MASK;
+	return count;
+}
+
+static const struct file_operations debugfs_timestamp_event_ops = {
+	.open = simple_open,
+	.read = debugfs_show_timestamp_event,
+	.write = debugfs_store_timestamp_event,
+};
+
+static const struct coresight_ops_entry debugfs_timestamp_event_entry = {
+	.name = "timestamp_event",
+	.mode =  S_IRUGO | S_IWUSR,
+	.ops = &debugfs_timestamp_event_ops,
+};
+
+static ssize_t debugfs_status_read(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+	uint32_t val;
+	unsigned long flags;
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	struct etm_drvdata *drvdata = file->private_data;
+
+	if (!buf)
+		return -ENOMEM;
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		goto out;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	ETM_UNLOCK(drvdata);
+	val = etm_readl(drvdata, ETMCCR);
+	ret += sprintf(buf, "ETMCCR: 0x%08x\n", val);
+	val = etm_readl(drvdata, ETMCCER);
+	ret += sprintf(buf + ret, "ETMCCER: 0x%08x\n", val);
+	val = etm_readl(drvdata, ETMSCR);
+	ret += sprintf(buf + ret, "ETMSCR: 0x%08x\n", val);
+	val = etm_readl(drvdata, ETMIDR);
+	ret += sprintf(buf + ret, "ETMIDR: 0x%08x\n", val);
+	val = etm_readl(drvdata, ETMCR);
+	ret += sprintf(buf + ret, "ETMCR: 0x%08x\n", val);
+	val = etm_readl(drvdata, ETMTEEVR);
+	ret += sprintf(buf + ret, "Enable event: 0x%08x\n", val);
+	val = etm_readl(drvdata, ETMTSSCR);
+	ret += sprintf(buf + ret, "Enable start/stop: 0x%08x\n", val);
+	ret += sprintf(buf + ret,
+		       "Enable control: CR1 0x%08x CR2 0x%08x\n",
+		       etm_readl(drvdata, ETMTECR1),
+		       etm_readl(drvdata, ETMTECR2));
+
+	ETM_LOCK(drvdata);
+
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	clk_disable_unprepare(drvdata->clk);
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+out:
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations debugfs_status_ops = {
+	.open = simple_open,
+	.read = debugfs_status_read,
+};
+
+static const struct coresight_ops_entry debugfs_status_entry = {
+	.name = "status",
+	.mode =  S_IRUGO,
+	.ops = &debugfs_status_ops,
+};
+
+static const struct coresight_ops_entry *etm_attr_grps[] = {
+	&debugfs_nr_addr_cmp_entry,
+	&debugfs_nr_cntr_entry,
+	&debugfs_nr_ctxid_cmp_entry,
+	&debugfs_reset_entry,
+	&debugfs_mode_entry,
+	&debugfs_trigger_events_entry,
+	&debugfs_enable_events_entry,
+	&debugfs_fifofull_level_entry,
+	&debugfs_addr_idx_entry,
+	&debugfs_addr_single_entry,
+	&debugfs_addr_range_entry,
+	&debugfs_addr_start_entry,
+	&debugfs_addr_stop_entry,
+	&debugfs_addr_acctype_entry,
+	&debugfs_cntr_idx_entry,
+	&debugfs_cntr_rld_val_entry,
+	&debugfs_cntr_event_entry,
+	&debugfs_cntr_rld_event_entry,
+	&debugfs_cntr_val_entry,
+	&debugfs_12_event_entry,
+	&debugfs_21_event_entry,
+	&debugfs_23_event_entry,
+	&debugfs_31_event_entry,
+	&debugfs_32_event_entry,
+	&debugfs_13_event_entry,
+	&debugfs_seq_curr_state_entry,
+	&debugfs_ctxid_idx_entry,
+	&debugfs_ctxid_val_entry,
+	&debugfs_ctxid_mask_entry,
+	&debugfs_sync_freq_entry,
+	&debugfs_timestamp_event_entry,
+	&debugfs_status_entry,
+	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);
+		break;
+
+	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 etm_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case ETM_ARCH_V3_3:
+		break;
+	case ETM_ARCH_V3_5:
+		break;
+	case PFT_ARCH_V1_1:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static void etm_init_arch_data(void *info)
+{
+	uint32_t etmidr;
+	uint32_t etmccr;
+	struct etm_drvdata *drvdata = info;
+
+	ETM_UNLOCK(drvdata);
+
+	/* first dummy read */
+	(void)etm_readl(drvdata, ETMPDSR);
+	/* Provide power to ETM: ETMPDCR[3] == 1 */
+	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);
+	/*
+	 * 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);
+	drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
+
+	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_clr_pwrup(drvdata);
+	ETM_LOCK(drvdata);
+}
+
+static void etm_init_default_data(struct etm_drvdata *drvdata)
+{
+	int i;
+
+	uint32_t flags = (1 << 0 | /* instruction execute*/
+			  3 << 3 | /* ARM instruction */
+			  0 << 5 | /* No data value comparison */
+			  0 << 7 | /* No exact mach */
+			  0 << 8 | /* Ignore context ID */
+			  0 << 10); /* Security ignored */
+
+	drvdata->ctrl = (BIT(12) | /* cycle accurate */
+			 BIT(28)); /* timestamp */
+	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_acctype[0] = flags;
+		drvdata->addr_acctype[1] = flags;
+		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 etm_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct coresight_platform_data *pdata = NULL;
+	struct etm_drvdata *drvdata;
+	struct resource *res;
+	static int count;
+	struct coresight_desc *desc;
+
+	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	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->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);
+
+	if (pdata && pdata->clk) {
+		drvdata->clk = pdata->clk;
+		ret = clk_prepare_enable(drvdata->clk);
+		if (ret)
+			return ret;
+	}
+
+	drvdata->cpu = pdata ? pdata->cpu : 0;
+
+	get_online_cpus();
+	etmdrvdata[drvdata->cpu] = drvdata;
+
+	if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, drvdata, 1))
+		drvdata->os_unlock = true;
+
+	if (smp_call_function_single(drvdata->cpu,
+				     etm_init_arch_data,  drvdata, 1))
+		dev_err(dev, "ETM arch init failed\n");
+
+	if (!count++)
+		register_hotcpu_notifier(&etm_cpu_notifier);
+
+	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->debugfs_ops = 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 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         = 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");
-- 
1.9.1


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

* [RFC PATCH 08/11] coresight: adding support for beagle board
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
                   ` (6 preceding siblings ...)
  2014-05-30 13:43 ` [RFC PATCH 07/11] coresight: add CoreSight ETM driver mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 09/11] coresight: adding basic support for Vexpress TC2 mathieu.poirier
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

From: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>

Added support for coresight device in dts for Beagle Board, by adding
blocks of coresight, ETM, ETB blocks.

Signed-off-by: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
---
 arch/arm/boot/dts/omap3-beagle.dts | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 5053766..0017084 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -80,6 +80,36 @@
 		};
 
 	};
+
+	coresight {
+		compatible = "arm,coresight";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		clocks = <&emu_src_ck>;
+		ranges;
+
+		etb: etb@540000000 {
+			compatible = "arm,coresight-etb";
+			reg = <0x5401b000 0x1000>;
+
+			coresight-id = <0>;
+			coresight-name = "coresight-etb";
+			coresight-nr-inports = <1>;
+			coresight-default-sink;
+		};
+
+		etm@54010000 {
+			compatible = "arm,coresight-etm";
+			reg = <0x54010000 0x1000>;
+
+			coresight-id = <1>;
+			coresight-name = "coresight-etm";
+			coresight-nr-inports = <0>;
+			coresight-outports = <0>;
+			coresight-child-list = <&etb>;
+			coresight-child-ports = <0>;
+		};
+	};
 };
 
 &omap3_pmx_wkup {
-- 
1.9.1


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

* [RFC PATCH 09/11] coresight: adding basic support for Vexpress TC2
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
                   ` (7 preceding siblings ...)
  2014-05-30 13:43 ` [RFC PATCH 08/11] coresight: adding support for beagle board mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 10/11] coresight: adding support for beagleXM mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 11/11] ARM: moving support for etb/etm to the "drivers" directory mathieu.poirier
  10 siblings, 0 replies; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

From: Mathieu Poirier <mathieu.poirier@linaro.org>

Support for the 2 PTMs, 3 ETMs, funnel, TPIU and replicator
connected to the ETB are included.  Proper handling of the
ITM and the replicator linked to it along with the CTIs
and SWO are not included.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 122 +++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
index 15f98cb..18de06e 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -334,6 +334,128 @@
 		};
 	};
 
+	coresight {
+		compatible = "arm,coresight";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x20010000 0 0x20010000 0x1000
+			  0x20030000 0 0x20030000 0x1000
+			  0x20040000 0 0x20040000 0x1000
+			  0x2201c000 0 0x2201c000 0x1000
+			  0x2201d000 0 0x2201d000 0x1000
+			  0x2203c000 0 0x2203c000 0x1000
+			  0x2203d000 0 0x2203d000 0x1000
+			  0x2203e000 0 0x2203e000 0x1000>;
+
+		etb: etb@20010000 {
+			compatible = "arm,coresight-etb";
+			reg = <0x20010000 0x1000>;
+
+			coresight-id = <0>;
+			coresight-name = "coresight-etb";
+			coresight-nr-inports = <1>;
+			coresight-default-sink;
+		};
+
+		etb_replicator: replicator {
+			compatible = "arm,coresight-replicator";
+
+			coresight-id = <1>;
+			coresight-name = "coresight-etb-replicator";
+			coresight-nr-inports = <1>;
+			coresight-outports = <0 1>;
+			coresight-child-list = <&etb &tpiu>;
+			coresight-child-ports = <0 0>;
+		};
+
+		tpiu: tpiu@20030000 {
+			compatible = "arm,coresight-tpiu";
+			reg = <0x20030000 0x1000>;
+
+			coresight-id = <2>;
+			coresight-name = "coresight-tpiu";
+			coresight-nr-inports = <1>;
+		};
+
+		funnel: funnel@20040000 {
+			compatible = "arm,coresight-funnel";
+			reg = <0x20040000 0x1000>;
+
+			coresight-id = <3>;
+			coresight-name = "coresight-funnel";
+			coresight-nr-inports = <1>;
+			coresight-outports = <0>;
+			coresight-child-list = <&etb_replicator>;
+			coresight-child-ports = <0>;
+		};
+
+		ptm0: ptm@2201c000 {
+			compatible = "arm,coresight-etm";
+			reg = <0x2201c000 0x1000>;
+
+			coresight-id = <4>;
+			coresight-name = "coresight-ptm0";
+			cpu = <&cpu0>;
+			coresight-nr-inports = <0>;
+			coresight-outports = <0>;
+			coresight-child-list = <&funnel>;
+			coresight-child-ports = <0>;
+		};
+
+		ptm1: ptm@2201d000 {
+			compatible = "arm,coresight-etm";
+			reg = <0x2201d000 0x1000>;
+
+			coresight-id = <5>;
+			coresight-name = "coresight-ptm1";
+			cpu = <&cpu1>;
+			coresight-nr-inports = <0>;
+			coresight-outports = <0>;
+			coresight-child-list = <&funnel>;
+			coresight-child-ports = <1>;
+		};
+
+		etm0: etm@2203c000 {
+			compatible = "arm,coresight-etm";
+			reg = <0x2203c000 0x1000>;
+
+			coresight-id = <6>;
+			coresight-name = "coresight-etm0";
+			cpu = <&cpu2>;
+			coresight-nr-inports = <0>;
+			coresight-outports = <0>;
+			coresight-child-list = <&funnel>;
+			coresight-child-ports = <2>;
+		};
+
+		etm1: etm@2203d000 {
+			compatible = "arm,coresight-etm";
+			reg = <0x2203d000 0x1000>;
+
+			coresight-id = <7>;
+			coresight-name = "coresight-etm1";
+			cpu = <&cpu3>;
+			coresight-nr-inports = <0>;
+			coresight-outports = <0>;
+			coresight-child-list = <&funnel>;
+			coresight-child-ports = <4>;
+		};
+
+		etm2: etm@2203e000 {
+			compatible = "arm,coresight-etm";
+			reg = <0x2203e000 0x1000>;
+
+			coresight-id = <8>;
+			coresight-name = "coresight-etm2";
+			cpu = <&cpu4>;
+			coresight-nr-inports = <0>;
+			coresight-outports = <0>;
+			coresight-child-list = <&funnel>;
+			coresight-child-ports = <5>;
+		};
+
+	};
+
 	smb {
 		compatible = "simple-bus";
 
-- 
1.9.1


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

* [RFC PATCH 10/11] coresight: adding support for beagleXM
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
                   ` (8 preceding siblings ...)
  2014-05-30 13:43 ` [RFC PATCH 09/11] coresight: adding basic support for Vexpress TC2 mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-05-30 13:43 ` [RFC PATCH 11/11] ARM: moving support for etb/etm to the "drivers" directory mathieu.poirier
  10 siblings, 0 replies; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

From: Mathieu Poirier <mathieu.poirier@linaro.org>

Currently supporting ETM and ETB.  Support for TPIU
and SDTI are yet to be added.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 arch/arm/boot/dts/omap3-beagle-xm.dts | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts
index 447e714..b39bede 100644
--- a/arch/arm/boot/dts/omap3-beagle-xm.dts
+++ b/arch/arm/boot/dts/omap3-beagle-xm.dts
@@ -86,6 +86,36 @@
 		reset-gpios = <&gpio5 19 GPIO_ACTIVE_LOW>; /* gpio_147 */
 		vcc-supply = <&hsusb2_power>;
 	};
+
+	coresight {
+		compatible = "arm,coresight";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		clocks = <&emu_src_ck>;
+		ranges;
+
+		etb: etb@540000000 {
+			compatible = "arm,coresight-etb";
+			reg = <0x5401b000 0x1000>;
+
+			coresight-id = <0>;
+			coresight-name = "coresight-etb";
+			coresight-nr-inports = <1>;
+			coresight-default-sink;
+		};
+
+		etm@54010000 {
+			compatible = "arm,coresight-etm";
+			reg = <0x54010000 0x1000>;
+
+			coresight-id = <1>;
+			coresight-name = "coresight-etm";
+			coresight-nr-inports = <0>;
+			coresight-outports = <0>;
+			coresight-child-list = <&etb>;
+			coresight-child-ports = <0>;
+		};
+	};
 };
 
 &omap3_pmx_wkup {
-- 
1.9.1


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

* [RFC PATCH 11/11] ARM: moving support for etb/etm to the "drivers" directory
  2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
                   ` (9 preceding siblings ...)
  2014-05-30 13:43 ` [RFC PATCH 10/11] coresight: adding support for beagleXM mathieu.poirier
@ 2014-05-30 13:43 ` mathieu.poirier
  2014-05-30 13:49   ` Russell King - ARM Linux
  10 siblings, 1 reply; 23+ messages in thread
From: mathieu.poirier @ 2014-05-30 13:43 UTC (permalink / raw)
  To: linus.walleij, will.deacon
  Cc: mathieu.poirier, arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel, daniel.thompson

From: Mathieu Poirier <mathieu.poirier@linaro.org>

Removing minimal support for etb/etm to favour an implentation
that is more flexible, extensible and capable of handling more
platforms.

Also removing the only client of the old driver.  That code can
easily be replaced by entries for etb/etm in the device tree.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
---
 arch/arm/include/asm/hardware/coresight.h | 157 -------
 arch/arm/kernel/Makefile                  |   1 -
 arch/arm/kernel/etm.c                     | 654 ------------------------------
 arch/arm/kernel/hw_breakpoint.c           |   4 +-
 arch/arm/mach-omap2/Kconfig               |   8 -
 arch/arm/mach-omap2/Makefile              |   1 -
 arch/arm/mach-omap2/emu.c                 |  50 ---
 7 files changed, 2 insertions(+), 873 deletions(-)
 delete mode 100644 arch/arm/include/asm/hardware/coresight.h
 delete mode 100644 arch/arm/kernel/etm.c
 delete mode 100644 arch/arm/mach-omap2/emu.c

diff --git a/arch/arm/include/asm/hardware/coresight.h b/arch/arm/include/asm/hardware/coresight.h
deleted file mode 100644
index ad774f3..0000000
--- a/arch/arm/include/asm/hardware/coresight.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * linux/arch/arm/include/asm/hardware/coresight.h
- *
- * CoreSight components' registers
- *
- * Copyright (C) 2009 Nokia Corporation.
- * Alexander Shishkin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_HARDWARE_CORESIGHT_H
-#define __ASM_HARDWARE_CORESIGHT_H
-
-#define TRACER_ACCESSED_BIT	0
-#define TRACER_RUNNING_BIT	1
-#define TRACER_CYCLE_ACC_BIT	2
-#define TRACER_ACCESSED		BIT(TRACER_ACCESSED_BIT)
-#define TRACER_RUNNING		BIT(TRACER_RUNNING_BIT)
-#define TRACER_CYCLE_ACC	BIT(TRACER_CYCLE_ACC_BIT)
-
-#define TRACER_TIMEOUT 10000
-
-#define etm_writel(t, v, x) \
-	(writel_relaxed((v), (t)->etm_regs + (x)))
-#define etm_readl(t, x) (readl_relaxed((t)->etm_regs + (x)))
-
-/* CoreSight Management Registers */
-#define CSMR_LOCKACCESS 0xfb0
-#define CSMR_LOCKSTATUS 0xfb4
-#define CSMR_AUTHSTATUS 0xfb8
-#define CSMR_DEVID	0xfc8
-#define CSMR_DEVTYPE	0xfcc
-/* CoreSight Component Registers */
-#define CSCR_CLASS	0xff4
-
-#define CS_LAR_KEY	0xc5acce55
-
-/* ETM control register, "ETM Architecture", 3.3.1 */
-#define ETMR_CTRL		0
-#define ETMCTRL_POWERDOWN	1
-#define ETMCTRL_PROGRAM		(1 << 10)
-#define ETMCTRL_PORTSEL		(1 << 11)
-#define ETMCTRL_DO_CONTEXTID	(3 << 14)
-#define ETMCTRL_PORTMASK1	(7 << 4)
-#define ETMCTRL_PORTMASK2	(1 << 21)
-#define ETMCTRL_PORTMASK	(ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2)
-#define ETMCTRL_PORTSIZE(x) ((((x) & 7) << 4) | (!!((x) & 8)) << 21)
-#define ETMCTRL_DO_CPRT		(1 << 1)
-#define ETMCTRL_DATAMASK	(3 << 2)
-#define ETMCTRL_DATA_DO_DATA	(1 << 2)
-#define ETMCTRL_DATA_DO_ADDR	(1 << 3)
-#define ETMCTRL_DATA_DO_BOTH	(ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR)
-#define ETMCTRL_BRANCH_OUTPUT	(1 << 8)
-#define ETMCTRL_CYCLEACCURATE	(1 << 12)
-
-/* ETM configuration code register */
-#define ETMR_CONFCODE		(0x04)
-
-/* ETM trace start/stop resource control register */
-#define ETMR_TRACESSCTRL	(0x18)
-
-/* ETM trigger event register */
-#define ETMR_TRIGEVT		(0x08)
-
-/* address access type register bits, "ETM architecture",
- * table 3-27 */
-/* - access type */
-#define ETMAAT_IFETCH		0
-#define ETMAAT_IEXEC		1
-#define ETMAAT_IEXECPASS	2
-#define ETMAAT_IEXECFAIL	3
-#define ETMAAT_DLOADSTORE	4
-#define ETMAAT_DLOAD		5
-#define ETMAAT_DSTORE		6
-/* - comparison access size */
-#define ETMAAT_JAVA		(0 << 3)
-#define ETMAAT_THUMB		(1 << 3)
-#define ETMAAT_ARM		(3 << 3)
-/* - data value comparison control */
-#define ETMAAT_NOVALCMP		(0 << 5)
-#define ETMAAT_VALMATCH		(1 << 5)
-#define ETMAAT_VALNOMATCH	(3 << 5)
-/* - exact match */
-#define ETMAAT_EXACTMATCH	(1 << 7)
-/* - context id comparator control */
-#define ETMAAT_IGNCONTEXTID	(0 << 8)
-#define ETMAAT_VALUE1		(1 << 8)
-#define ETMAAT_VALUE2		(2 << 8)
-#define ETMAAT_VALUE3		(3 << 8)
-/* - security level control */
-#define ETMAAT_IGNSECURITY	(0 << 10)
-#define ETMAAT_NSONLY		(1 << 10)
-#define ETMAAT_SONLY		(2 << 10)
-
-#define ETMR_COMP_VAL(x)	(0x40 + (x) * 4)
-#define ETMR_COMP_ACC_TYPE(x)	(0x80 + (x) * 4)
-
-/* ETM status register, "ETM Architecture", 3.3.2 */
-#define ETMR_STATUS		(0x10)
-#define ETMST_OVERFLOW		BIT(0)
-#define ETMST_PROGBIT		BIT(1)
-#define ETMST_STARTSTOP		BIT(2)
-#define ETMST_TRIGGER		BIT(3)
-
-#define etm_progbit(t)		(etm_readl((t), ETMR_STATUS) & ETMST_PROGBIT)
-#define etm_started(t)		(etm_readl((t), ETMR_STATUS) & ETMST_STARTSTOP)
-#define etm_triggered(t)	(etm_readl((t), ETMR_STATUS) & ETMST_TRIGGER)
-
-#define ETMR_TRACEENCTRL2	0x1c
-#define ETMR_TRACEENCTRL	0x24
-#define ETMTE_INCLEXCL		BIT(24)
-#define ETMR_TRACEENEVT		0x20
-#define ETMCTRL_OPTS		(ETMCTRL_DO_CPRT | \
-				ETMCTRL_DATA_DO_ADDR | \
-				ETMCTRL_BRANCH_OUTPUT | \
-				ETMCTRL_DO_CONTEXTID)
-
-/* ETM management registers, "ETM Architecture", 3.5.24 */
-#define ETMMR_OSLAR	0x300
-#define ETMMR_OSLSR	0x304
-#define ETMMR_OSSRR	0x308
-#define ETMMR_PDSR	0x314
-
-/* ETB registers, "CoreSight Components TRM", 9.3 */
-#define ETBR_DEPTH		0x04
-#define ETBR_STATUS		0x0c
-#define ETBR_READMEM		0x10
-#define ETBR_READADDR		0x14
-#define ETBR_WRITEADDR		0x18
-#define ETBR_TRIGGERCOUNT	0x1c
-#define ETBR_CTRL		0x20
-#define ETBR_FORMATTERCTRL	0x304
-#define ETBFF_ENFTC		1
-#define ETBFF_ENFCONT		BIT(1)
-#define ETBFF_FONFLIN		BIT(4)
-#define ETBFF_MANUAL_FLUSH	BIT(6)
-#define ETBFF_TRIGIN		BIT(8)
-#define ETBFF_TRIGEVT		BIT(9)
-#define ETBFF_TRIGFL		BIT(10)
-
-#define etb_writel(t, v, x) \
-	(writel_relaxed((v), (t)->etb_regs + (x)))
-#define etb_readl(t, x) (readl_relaxed((t)->etb_regs + (x)))
-
-#define etm_lock(t) do { etm_writel((t), 0, CSMR_LOCKACCESS); } while (0)
-#define etm_unlock(t) \
-	do { etm_writel((t), CS_LAR_KEY, CSMR_LOCKACCESS); } while (0)
-
-#define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
-#define etb_unlock(t) \
-	do { etb_writel((t), CS_LAR_KEY, CSMR_LOCKACCESS); } while (0)
-
-#endif /* __ASM_HARDWARE_CORESIGHT_H */
-
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index a30fc9b..b4ea607 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -30,7 +30,6 @@ else
 obj-y		+= entry-armv.o
 endif
 
-obj-$(CONFIG_OC_ETM)		+= etm.o
 obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
 obj-$(CONFIG_FIQ)		+= fiq.o fiqasm.o
diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
deleted file mode 100644
index 131a6ab..0000000
--- a/arch/arm/kernel/etm.c
+++ /dev/null
@@ -1,654 +0,0 @@
-/*
- * linux/arch/arm/kernel/etm.c
- *
- * Driver for ARM's Embedded Trace Macrocell and Embedded Trace Buffer.
- *
- * Copyright (C) 2009 Nokia Corporation.
- * Alexander Shishkin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <linux/sysrq.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/amba/bus.h>
-#include <linux/fs.h>
-#include <linux/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/vmalloc.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <asm/hardware/coresight.h>
-#include <asm/sections.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alexander Shishkin");
-
-/*
- * ETM tracer state
- */
-struct tracectx {
-	unsigned int	etb_bufsz;
-	void __iomem	*etb_regs;
-	void __iomem	*etm_regs;
-	unsigned long	flags;
-	int		ncmppairs;
-	int		etm_portsz;
-	struct device	*dev;
-	struct clk	*emu_clk;
-	struct mutex	mutex;
-};
-
-static struct tracectx tracer;
-
-static inline bool trace_isrunning(struct tracectx *t)
-{
-	return !!(t->flags & TRACER_RUNNING);
-}
-
-static int etm_setup_address_range(struct tracectx *t, int n,
-		unsigned long start, unsigned long end, int exclude, int data)
-{
-	u32 flags = ETMAAT_ARM | ETMAAT_IGNCONTEXTID | ETMAAT_NSONLY | \
-		    ETMAAT_NOVALCMP;
-
-	if (n < 1 || n > t->ncmppairs)
-		return -EINVAL;
-
-	/* comparators and ranges are numbered starting with 1 as opposed
-	 * to bits in a word */
-	n--;
-
-	if (data)
-		flags |= ETMAAT_DLOADSTORE;
-	else
-		flags |= ETMAAT_IEXEC;
-
-	/* first comparator for the range */
-	etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2));
-	etm_writel(t, start, ETMR_COMP_VAL(n * 2));
-
-	/* second comparator is right next to it */
-	etm_writel(t, flags, ETMR_COMP_ACC_TYPE(n * 2 + 1));
-	etm_writel(t, end, ETMR_COMP_VAL(n * 2 + 1));
-
-	flags = exclude ? ETMTE_INCLEXCL : 0;
-	etm_writel(t, flags | (1 << n), ETMR_TRACEENCTRL);
-
-	return 0;
-}
-
-static int trace_start(struct tracectx *t)
-{
-	u32 v;
-	unsigned long timeout = TRACER_TIMEOUT;
-
-	etb_unlock(t);
-
-	etb_writel(t, 0, ETBR_FORMATTERCTRL);
-	etb_writel(t, 1, ETBR_CTRL);
-
-	etb_lock(t);
-
-	/* configure etm */
-	v = ETMCTRL_OPTS | ETMCTRL_PROGRAM | ETMCTRL_PORTSIZE(t->etm_portsz);
-
-	if (t->flags & TRACER_CYCLE_ACC)
-		v |= ETMCTRL_CYCLEACCURATE;
-
-	etm_unlock(t);
-
-	etm_writel(t, v, ETMR_CTRL);
-
-	while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
-		;
-	if (!timeout) {
-		dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
-		etm_lock(t);
-		return -EFAULT;
-	}
-
-	etm_setup_address_range(t, 1, (unsigned long)_stext,
-			(unsigned long)_etext, 0, 0);
-	etm_writel(t, 0, ETMR_TRACEENCTRL2);
-	etm_writel(t, 0, ETMR_TRACESSCTRL);
-	etm_writel(t, 0x6f, ETMR_TRACEENEVT);
-
-	v &= ~ETMCTRL_PROGRAM;
-	v |= ETMCTRL_PORTSEL;
-
-	etm_writel(t, v, ETMR_CTRL);
-
-	timeout = TRACER_TIMEOUT;
-	while (etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM && --timeout)
-		;
-	if (!timeout) {
-		dev_dbg(t->dev, "Waiting for progbit to deassert timed out\n");
-		etm_lock(t);
-		return -EFAULT;
-	}
-
-	etm_lock(t);
-
-	t->flags |= TRACER_RUNNING;
-
-	return 0;
-}
-
-static int trace_stop(struct tracectx *t)
-{
-	unsigned long timeout = TRACER_TIMEOUT;
-
-	etm_unlock(t);
-
-	etm_writel(t, 0x440, ETMR_CTRL);
-	while (!(etm_readl(t, ETMR_CTRL) & ETMCTRL_PROGRAM) && --timeout)
-		;
-	if (!timeout) {
-		dev_dbg(t->dev, "Waiting for progbit to assert timed out\n");
-		etm_lock(t);
-		return -EFAULT;
-	}
-
-	etm_lock(t);
-
-	etb_unlock(t);
-	etb_writel(t, ETBFF_MANUAL_FLUSH, ETBR_FORMATTERCTRL);
-
-	timeout = TRACER_TIMEOUT;
-	while (etb_readl(t, ETBR_FORMATTERCTRL) &
-			ETBFF_MANUAL_FLUSH && --timeout)
-		;
-	if (!timeout) {
-		dev_dbg(t->dev, "Waiting for formatter flush to commence "
-				"timed out\n");
-		etb_lock(t);
-		return -EFAULT;
-	}
-
-	etb_writel(t, 0, ETBR_CTRL);
-
-	etb_lock(t);
-
-	t->flags &= ~TRACER_RUNNING;
-
-	return 0;
-}
-
-static int etb_getdatalen(struct tracectx *t)
-{
-	u32 v;
-	int rp, wp;
-
-	v = etb_readl(t, ETBR_STATUS);
-
-	if (v & 1)
-		return t->etb_bufsz;
-
-	rp = etb_readl(t, ETBR_READADDR);
-	wp = etb_readl(t, ETBR_WRITEADDR);
-
-	if (rp > wp) {
-		etb_writel(t, 0, ETBR_READADDR);
-		etb_writel(t, 0, ETBR_WRITEADDR);
-
-		return 0;
-	}
-
-	return wp - rp;
-}
-
-/* sysrq+v will always stop the running trace and leave it at that */
-static void etm_dump(void)
-{
-	struct tracectx *t = &tracer;
-	u32 first = 0;
-	int length;
-
-	if (!t->etb_regs) {
-		printk(KERN_INFO "No tracing hardware found\n");
-		return;
-	}
-
-	if (trace_isrunning(t))
-		trace_stop(t);
-
-	etb_unlock(t);
-
-	length = etb_getdatalen(t);
-
-	if (length == t->etb_bufsz)
-		first = etb_readl(t, ETBR_WRITEADDR);
-
-	etb_writel(t, first, ETBR_READADDR);
-
-	printk(KERN_INFO "Trace buffer contents length: %d\n", length);
-	printk(KERN_INFO "--- ETB buffer begin ---\n");
-	for (; length; length--)
-		printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
-	printk(KERN_INFO "\n--- ETB buffer end ---\n");
-
-	/* deassert the overflow bit */
-	etb_writel(t, 1, ETBR_CTRL);
-	etb_writel(t, 0, ETBR_CTRL);
-
-	etb_writel(t, 0, ETBR_TRIGGERCOUNT);
-	etb_writel(t, 0, ETBR_READADDR);
-	etb_writel(t, 0, ETBR_WRITEADDR);
-
-	etb_lock(t);
-}
-
-static void sysrq_etm_dump(int key)
-{
-	dev_dbg(tracer.dev, "Dumping ETB buffer\n");
-	etm_dump();
-}
-
-static struct sysrq_key_op sysrq_etm_op = {
-	.handler = sysrq_etm_dump,
-	.help_msg = "etm-buffer-dump(v)",
-	.action_msg = "etm",
-};
-
-static int etb_open(struct inode *inode, struct file *file)
-{
-	if (!tracer.etb_regs)
-		return -ENODEV;
-
-	file->private_data = &tracer;
-
-	return nonseekable_open(inode, file);
-}
-
-static ssize_t etb_read(struct file *file, char __user *data,
-		size_t len, loff_t *ppos)
-{
-	int total, i;
-	long length;
-	struct tracectx *t = file->private_data;
-	u32 first = 0;
-	u32 *buf;
-
-	mutex_lock(&t->mutex);
-
-	if (trace_isrunning(t)) {
-		length = 0;
-		goto out;
-	}
-
-	etb_unlock(t);
-
-	total = etb_getdatalen(t);
-	if (total == t->etb_bufsz)
-		first = etb_readl(t, ETBR_WRITEADDR);
-
-	etb_writel(t, first, ETBR_READADDR);
-
-	length = min(total * 4, (int)len);
-	buf = vmalloc(length);
-
-	dev_dbg(t->dev, "ETB buffer length: %d\n", total);
-	dev_dbg(t->dev, "ETB status reg: %x\n", etb_readl(t, ETBR_STATUS));
-	for (i = 0; i < length / 4; i++)
-		buf[i] = etb_readl(t, ETBR_READMEM);
-
-	/* the only way to deassert overflow bit in ETB status is this */
-	etb_writel(t, 1, ETBR_CTRL);
-	etb_writel(t, 0, ETBR_CTRL);
-
-	etb_writel(t, 0, ETBR_WRITEADDR);
-	etb_writel(t, 0, ETBR_READADDR);
-	etb_writel(t, 0, ETBR_TRIGGERCOUNT);
-
-	etb_lock(t);
-
-	length -= copy_to_user(data, buf, length);
-	vfree(buf);
-
-out:
-	mutex_unlock(&t->mutex);
-
-	return length;
-}
-
-static int etb_release(struct inode *inode, struct file *file)
-{
-	/* there's nothing to do here, actually */
-	return 0;
-}
-
-static const struct file_operations etb_fops = {
-	.owner = THIS_MODULE,
-	.read = etb_read,
-	.open = etb_open,
-	.release = etb_release,
-	.llseek = no_llseek,
-};
-
-static struct miscdevice etb_miscdev = {
-	.name = "tracebuf",
-	.minor = 0,
-	.fops = &etb_fops,
-};
-
-static int etb_probe(struct amba_device *dev, const struct amba_id *id)
-{
-	struct tracectx *t = &tracer;
-	int ret = 0;
-
-	ret = amba_request_regions(dev, NULL);
-	if (ret)
-		goto out;
-
-	t->etb_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
-	if (!t->etb_regs) {
-		ret = -ENOMEM;
-		goto out_release;
-	}
-
-	amba_set_drvdata(dev, t);
-
-	etb_miscdev.parent = &dev->dev;
-
-	ret = misc_register(&etb_miscdev);
-	if (ret)
-		goto out_unmap;
-
-	t->emu_clk = clk_get(&dev->dev, "emu_src_ck");
-	if (IS_ERR(t->emu_clk)) {
-		dev_dbg(&dev->dev, "Failed to obtain emu_src_ck.\n");
-		return -EFAULT;
-	}
-
-	clk_enable(t->emu_clk);
-
-	etb_unlock(t);
-	t->etb_bufsz = etb_readl(t, ETBR_DEPTH);
-	dev_dbg(&dev->dev, "Size: %x\n", t->etb_bufsz);
-
-	/* make sure trace capture is disabled */
-	etb_writel(t, 0, ETBR_CTRL);
-	etb_writel(t, 0x1000, ETBR_FORMATTERCTRL);
-	etb_lock(t);
-
-	dev_dbg(&dev->dev, "ETB AMBA driver initialized.\n");
-
-out:
-	return ret;
-
-out_unmap:
-	iounmap(t->etb_regs);
-
-out_release:
-	amba_release_regions(dev);
-
-	return ret;
-}
-
-static int etb_remove(struct amba_device *dev)
-{
-	struct tracectx *t = amba_get_drvdata(dev);
-
-	iounmap(t->etb_regs);
-	t->etb_regs = NULL;
-
-	clk_disable(t->emu_clk);
-	clk_put(t->emu_clk);
-
-	amba_release_regions(dev);
-
-	return 0;
-}
-
-static struct amba_id etb_ids[] = {
-	{
-		.id	= 0x0003b907,
-		.mask	= 0x0007ffff,
-	},
-	{ 0, 0 },
-};
-
-static struct amba_driver etb_driver = {
-	.drv		= {
-		.name	= "etb",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= etb_probe,
-	.remove		= etb_remove,
-	.id_table	= etb_ids,
-};
-
-/* use a sysfs file "trace_running" to start/stop tracing */
-static ssize_t trace_running_show(struct kobject *kobj,
-				  struct kobj_attribute *attr,
-				  char *buf)
-{
-	return sprintf(buf, "%x\n", trace_isrunning(&tracer));
-}
-
-static ssize_t trace_running_store(struct kobject *kobj,
-				   struct kobj_attribute *attr,
-				   const char *buf, size_t n)
-{
-	unsigned int value;
-	int ret;
-
-	if (sscanf(buf, "%u", &value) != 1)
-		return -EINVAL;
-
-	mutex_lock(&tracer.mutex);
-	ret = value ? trace_start(&tracer) : trace_stop(&tracer);
-	mutex_unlock(&tracer.mutex);
-
-	return ret ? : n;
-}
-
-static struct kobj_attribute trace_running_attr =
-	__ATTR(trace_running, 0644, trace_running_show, trace_running_store);
-
-static ssize_t trace_info_show(struct kobject *kobj,
-				  struct kobj_attribute *attr,
-				  char *buf)
-{
-	u32 etb_wa, etb_ra, etb_st, etb_fc, etm_ctrl, etm_st;
-	int datalen;
-
-	etb_unlock(&tracer);
-	datalen = etb_getdatalen(&tracer);
-	etb_wa = etb_readl(&tracer, ETBR_WRITEADDR);
-	etb_ra = etb_readl(&tracer, ETBR_READADDR);
-	etb_st = etb_readl(&tracer, ETBR_STATUS);
-	etb_fc = etb_readl(&tracer, ETBR_FORMATTERCTRL);
-	etb_lock(&tracer);
-
-	etm_unlock(&tracer);
-	etm_ctrl = etm_readl(&tracer, ETMR_CTRL);
-	etm_st = etm_readl(&tracer, ETMR_STATUS);
-	etm_lock(&tracer);
-
-	return sprintf(buf, "Trace buffer len: %d\nComparator pairs: %d\n"
-			"ETBR_WRITEADDR:\t%08x\n"
-			"ETBR_READADDR:\t%08x\n"
-			"ETBR_STATUS:\t%08x\n"
-			"ETBR_FORMATTERCTRL:\t%08x\n"
-			"ETMR_CTRL:\t%08x\n"
-			"ETMR_STATUS:\t%08x\n",
-			datalen,
-			tracer.ncmppairs,
-			etb_wa,
-			etb_ra,
-			etb_st,
-			etb_fc,
-			etm_ctrl,
-			etm_st
-			);
-}
-
-static struct kobj_attribute trace_info_attr =
-	__ATTR(trace_info, 0444, trace_info_show, NULL);
-
-static ssize_t trace_mode_show(struct kobject *kobj,
-				  struct kobj_attribute *attr,
-				  char *buf)
-{
-	return sprintf(buf, "%d %d\n",
-			!!(tracer.flags & TRACER_CYCLE_ACC),
-			tracer.etm_portsz);
-}
-
-static ssize_t trace_mode_store(struct kobject *kobj,
-				   struct kobj_attribute *attr,
-				   const char *buf, size_t n)
-{
-	unsigned int cycacc, portsz;
-
-	if (sscanf(buf, "%u %u", &cycacc, &portsz) != 2)
-		return -EINVAL;
-
-	mutex_lock(&tracer.mutex);
-	if (cycacc)
-		tracer.flags |= TRACER_CYCLE_ACC;
-	else
-		tracer.flags &= ~TRACER_CYCLE_ACC;
-
-	tracer.etm_portsz = portsz & 0x0f;
-	mutex_unlock(&tracer.mutex);
-
-	return n;
-}
-
-static struct kobj_attribute trace_mode_attr =
-	__ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
-
-static int etm_probe(struct amba_device *dev, const struct amba_id *id)
-{
-	struct tracectx *t = &tracer;
-	int ret = 0;
-
-	if (t->etm_regs) {
-		dev_dbg(&dev->dev, "ETM already initialized\n");
-		ret = -EBUSY;
-		goto out;
-	}
-
-	ret = amba_request_regions(dev, NULL);
-	if (ret)
-		goto out;
-
-	t->etm_regs = ioremap_nocache(dev->res.start, resource_size(&dev->res));
-	if (!t->etm_regs) {
-		ret = -ENOMEM;
-		goto out_release;
-	}
-
-	amba_set_drvdata(dev, t);
-
-	mutex_init(&t->mutex);
-	t->dev = &dev->dev;
-	t->flags = TRACER_CYCLE_ACC;
-	t->etm_portsz = 1;
-
-	etm_unlock(t);
-	(void)etm_readl(t, ETMMR_PDSR);
-	/* dummy first read */
-	(void)etm_readl(&tracer, ETMMR_OSSRR);
-
-	t->ncmppairs = etm_readl(t, ETMR_CONFCODE) & 0xf;
-	etm_writel(t, 0x440, ETMR_CTRL);
-	etm_lock(t);
-
-	ret = sysfs_create_file(&dev->dev.kobj,
-			&trace_running_attr.attr);
-	if (ret)
-		goto out_unmap;
-
-	/* failing to create any of these two is not fatal */
-	ret = sysfs_create_file(&dev->dev.kobj, &trace_info_attr.attr);
-	if (ret)
-		dev_dbg(&dev->dev, "Failed to create trace_info in sysfs\n");
-
-	ret = sysfs_create_file(&dev->dev.kobj, &trace_mode_attr.attr);
-	if (ret)
-		dev_dbg(&dev->dev, "Failed to create trace_mode in sysfs\n");
-
-	dev_dbg(t->dev, "ETM AMBA driver initialized.\n");
-
-out:
-	return ret;
-
-out_unmap:
-	iounmap(t->etm_regs);
-
-out_release:
-	amba_release_regions(dev);
-
-	return ret;
-}
-
-static int etm_remove(struct amba_device *dev)
-{
-	struct tracectx *t = amba_get_drvdata(dev);
-
-	iounmap(t->etm_regs);
-	t->etm_regs = NULL;
-
-	amba_release_regions(dev);
-
-	sysfs_remove_file(&dev->dev.kobj, &trace_running_attr.attr);
-	sysfs_remove_file(&dev->dev.kobj, &trace_info_attr.attr);
-	sysfs_remove_file(&dev->dev.kobj, &trace_mode_attr.attr);
-
-	return 0;
-}
-
-static struct amba_id etm_ids[] = {
-	{
-		.id	= 0x0003b921,
-		.mask	= 0x0007ffff,
-	},
-	{ 0, 0 },
-};
-
-static struct amba_driver etm_driver = {
-	.drv		= {
-		.name   = "etm",
-		.owner  = THIS_MODULE,
-	},
-	.probe		= etm_probe,
-	.remove		= etm_remove,
-	.id_table	= etm_ids,
-};
-
-static int __init etm_init(void)
-{
-	int retval;
-
-	retval = amba_driver_register(&etb_driver);
-	if (retval) {
-		printk(KERN_ERR "Failed to register etb\n");
-		return retval;
-	}
-
-	retval = amba_driver_register(&etm_driver);
-	if (retval) {
-		amba_driver_unregister(&etb_driver);
-		printk(KERN_ERR "Failed to probe etm\n");
-		return retval;
-	}
-
-	/* not being able to install this handler is not fatal */
-	(void)register_sysrq_key('v', &sysrq_etm_op);
-
-	return 0;
-}
-
-device_initcall(etm_init);
-
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index 3d44660..c609f67 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -29,6 +29,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/smp.h>
 #include <linux/cpu_pm.h>
+#include <linux/coresight.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cputype.h>
@@ -36,7 +37,6 @@
 #include <asm/hw_breakpoint.h>
 #include <asm/kdebug.h>
 #include <asm/traps.h>
-#include <asm/hardware/coresight.h>
 
 /* Breakpoint currently in use for each BRP. */
 static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
@@ -975,7 +975,7 @@ static void reset_ctrl_regs(void *unused)
 	 * Unconditionally clear the OS lock by writing a value
 	 * other than CS_LAR_KEY to the access register.
 	 */
-	ARM_DBG_WRITE(c1, c0, 4, ~CS_LAR_KEY);
+	ARM_DBG_WRITE(c1, c0, 4, ~CORESIGHT_UNLOCK);
 	isb();
 
 	/*
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 0af7ca0..011a71c 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -324,14 +324,6 @@ config MACH_TI8148EVM
 	depends on SOC_TI81XX
 	default y
 
-config OMAP3_EMU
-	bool "OMAP3 debugging peripherals"
-	depends on ARCH_OMAP3
-	select ARM_AMBA
-	select OC_ETM
-	help
-	  Say Y here to enable debugging hardware of omap3
-
 config OMAP3_SDRC_AC_TIMING
 	bool "Enable SDRC AC timing register changes"
 	depends on ARCH_OMAP3
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index e6eec6f..8abb3d8 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -223,7 +223,6 @@ obj-$(CONFIG_SOC_OMAP5)			+= omap_hwmod_54xx_data.o
 obj-$(CONFIG_SOC_DRA7XX)		+= omap_hwmod_7xx_data.o
 
 # EMU peripherals
-obj-$(CONFIG_OMAP3_EMU)			+= emu.o
 obj-$(CONFIG_HW_PERF_EVENTS)		+= pmu.o
 
 iommu-$(CONFIG_OMAP_IOMMU)		:= omap-iommu.o
diff --git a/arch/arm/mach-omap2/emu.c b/arch/arm/mach-omap2/emu.c
deleted file mode 100644
index cbeaca2..0000000
--- a/arch/arm/mach-omap2/emu.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * emu.c
- *
- * ETM and ETB CoreSight components' resources as found in OMAP3xxx.
- *
- * Copyright (C) 2009 Nokia Corporation.
- * Alexander Shishkin
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-
-#include "soc.h"
-#include "iomap.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alexander Shishkin");
-
-/* Cortex CoreSight components within omap3xxx EMU */
-#define ETM_BASE	(L4_EMU_34XX_PHYS + 0x10000)
-#define DBG_BASE	(L4_EMU_34XX_PHYS + 0x11000)
-#define ETB_BASE	(L4_EMU_34XX_PHYS + 0x1b000)
-#define DAPCTL		(L4_EMU_34XX_PHYS + 0x1d000)
-
-static AMBA_APB_DEVICE(omap3_etb, "etb", 0x000bb907, ETB_BASE, { }, NULL);
-static AMBA_APB_DEVICE(omap3_etm, "etm", 0x102bb921, ETM_BASE, { }, NULL);
-
-static int __init emu_init(void)
-{
-	if (!cpu_is_omap34xx())
-		return -ENODEV;
-
-	amba_device_register(&omap3_etb_device, &iomem_resource);
-	amba_device_register(&omap3_etm_device, &iomem_resource);
-
-	return 0;
-}
-
-omap_subsys_initcall(emu_init);
-- 
1.9.1


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

* Re: [RFC PATCH 11/11] ARM: moving support for etb/etm to the "drivers" directory
  2014-05-30 13:43 ` [RFC PATCH 11/11] ARM: moving support for etb/etm to the "drivers" directory mathieu.poirier
@ 2014-05-30 13:49   ` Russell King - ARM Linux
  0 siblings, 0 replies; 23+ messages in thread
From: Russell King - ARM Linux @ 2014-05-30 13:49 UTC (permalink / raw)
  To: mathieu.poirier
  Cc: linus.walleij, will.deacon, arve, john.stultz, pratikp, varshney,
	Al.Grant, jonas.svennebring, james.king,
	panchaxari.prasannamurthy, arnd, marcin.jabrzyk, r.sengupta,
	robbelibobban, patches, linux-arm-kernel, linux-kernel,
	daniel.thompson

On Fri, May 30, 2014 at 07:43:11AM -0600, mathieu.poirier@linaro.org wrote:
> From: Mathieu Poirier <mathieu.poirier@linaro.org>
> 
> Removing minimal support for etb/etm to favour an implentation
> that is more flexible, extensible and capable of handling more
> platforms.
> 
> Also removing the only client of the old driver.  That code can
> easily be replaced by entries for etb/etm in the device tree.
> 
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

You say "moving" in the subject, but you are *re*moving it.  This is
misleading.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

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

* Re: [RFC PATCH 04/11] coresight: add CoreSight ETB driver
  2014-05-30 13:43 ` [RFC PATCH 04/11] coresight: add CoreSight ETB driver mathieu.poirier
@ 2014-05-30 13:53   ` Russell King - ARM Linux
  2014-05-30 16:28     ` Mathieu Poirier
  0 siblings, 1 reply; 23+ messages in thread
From: Russell King - ARM Linux @ 2014-05-30 13:53 UTC (permalink / raw)
  To: mathieu.poirier
  Cc: linus.walleij, will.deacon, arve, john.stultz, pratikp, varshney,
	Al.Grant, jonas.svennebring, james.king,
	panchaxari.prasannamurthy, arnd, marcin.jabrzyk, r.sengupta,
	robbelibobban, patches, linux-arm-kernel, linux-kernel,
	daniel.thompson

NAK for all the reasons I mentioned in the previous submission in 2012.

You partially did the right thing - you read through the previous
submission, and you said in your cover message that you had addressed
some of the comments from that submission.

What I find extremely distasteful is that you seem to have chosen to
completely ignore my comments - you haven't mentioned them in your
covering message at all, and you've just gone ahead and converted ETM
and ETB to be platform devices.

That gets you a NAK for that change, because you have done nothing what
so ever to address the concerns I raised.

Since you seem to have ignored my comments, this is as far as I'm looking
at your submission, and you can consider the entire submission NAK'd by
me.

Thanks.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

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

* Re: [RFC PATCH 04/11] coresight: add CoreSight ETB driver
  2014-05-30 13:53   ` Russell King - ARM Linux
@ 2014-05-30 16:28     ` Mathieu Poirier
  0 siblings, 0 replies; 23+ messages in thread
From: Mathieu Poirier @ 2014-05-30 16:28 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Linus Walleij, Will Deacon, Arve Hjønnevåg,
	John Stultz, Pratik Patel, Vikas Varshney, Al Grant,
	Jonas Svennebring, James King, Panchaxari Prasannamurthy Tumkur,
	arnd, Marcin Jabrzyk, r.sengupta, Robert Marklund,
	Patch Tracking, linux-arm-kernel, linux-kernel, Daniel Thompson

On 30 May 2014 07:53, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> NAK for all the reasons I mentioned in the previous submission in 2012.
>
> You partially did the right thing - you read through the previous
> submission, and you said in your cover message that you had addressed
> some of the comments from that submission.
>
> What I find extremely distasteful is that you seem to have chosen to
> completely ignore my comments - you haven't mentioned them in your
> covering message at all, and you've just gone ahead and converted ETM
> and ETB to be platform devices.
>
> That gets you a NAK for that change, because you have done nothing what
> so ever to address the concerns I raised.

>From my initial reading of your assessment it wasn't clear to me that
your opinion leaned toward registering with the AMBA bus.  Now that
this point has been clarified I will go back to the AMBA interface for
my next submission.

Is there anything else not AMBA releated that you'd like to see modified?

Thanks,
Mathieu

>
> Since you seem to have ignored my comments, this is as far as I'm looking
> at your submission, and you can consider the entire submission NAK'd by
> me.
>
> Thanks.
>
> --
> FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
> improving, and getting towards what was expected from it.

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

* Re: [RFC PATCH 01/11] coresight: add CoreSight core layer framework
  2014-05-30 13:43 ` [RFC PATCH 01/11] coresight: add CoreSight core layer framework mathieu.poirier
@ 2014-05-30 17:25   ` Rob Herring
  2014-05-30 18:02     ` Mathieu Poirier
  0 siblings, 1 reply; 23+ messages in thread
From: Rob Herring @ 2014-05-30 17:25 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Linus Walleij, Will Deacon, Daniel Thompson, robbelibobban,
	Al.Grant, Linaro Patches, marcin.jabrzyk, linux-kernel, arnd,
	panchaxari.prasannamurthy, r.sengupta, arve, John Stultz,
	linux-arm-kernel, james.king, Russell King - ARM Linux, pratikp,
	varshney, jonas.svennebring

On Fri, May 30, 2014 at 8:43 AM,  <mathieu.poirier@linaro.org> wrote:
> 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 debugfs.
>
> 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>
> Signed-off-by: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> ---
>  .../devicetree/bindings/arm/coresight.txt          | 138 ++++
>  drivers/Kconfig                                    |   2 +
>  drivers/Makefile                                   |   1 +
>  drivers/coresight/Kconfig                          |   9 +
>  drivers/coresight/Makefile                         |   5 +
>  drivers/coresight/coresight-priv.h                 |  46 ++
>  drivers/coresight/coresight.c                      | 739 +++++++++++++++++++++
>  drivers/coresight/of_coresight.c                   | 124 ++++
>  include/linux/coresight.h                          | 181 +++++
>  include/linux/of_coresight.h                       |  27 +
>  10 files changed, 1272 insertions(+)
>  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..3e21665
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/coresight.txt
> @@ -0,0 +1,138 @@
> +* 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

Where are the specific strings for components?

> +- reg : physical base address and length of the register set(s) of the component
> +- coresight-id : unique integer identifier for the component

compatible + reg is a unique id.

> +- coresight-name : unique descriptive name of the component

compatible is a descriptive name.

> +- 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.

Why do you need the default-sink in DT? Isn't the configuration going
to depend on the user?

> +
> +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

Seems like the OF graph helpers being defined for V4L2 could be useful
here to describe the connections. We should not invent something new
to describe arbitrary connections.

> +- arm,buffer-size : size of contiguous buffer space for TMC ETR

TMC ETR?

> +- arm,cp14 : cp14 access to ETM registers is implemented and should be used
> +- clocks : the clock associated to the coresight entity.
> +- cpu: only valid for ETM/PTMs - the cpu this ETM/PTM is affined to.

I think you need some separation of bindings by component rather than
saying which components certain properties apply to.

> +
> +Example:
> +
> +1. Bus declaration:
> +       coresight {
> +               compatible = "arm,coresight";
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +               ranges;
> +               ...
> +               ...
> +               ...
> +        };
> +
> +        coresight {
> +               compatible = "arm,coresight";
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +               ranges = <0x20010000 0 0x20010000 0x1000
> +                         0x20030000 0 0x20030000 0x1000
> +                         0x20040000 0 0x20040000 0x1000
> +                         0x2201c000 0 0x2201c000 0x1000
> +                         0x2201d000 0 0x2201d000 0x1000
> +                         0x2203c000 0 0x2203c000 0x1000
> +                         0x2203d000 0 0x2203d000 0x1000
> +                         0x2203e000 0 0x2203e000 0x1000>;

This is not how ranges generally work. For no translation, use just
"ranges;". Otherwise you should have base address and reg properties
are just offsets from the base. Anyway, it's not really pertinent to
your example.

> +               ...
> +               ...
> +               ...
> +       };
> +
> +2. Sinks
> +       etb: etb@20010000 {
> +               compatible = "arm,coresight-etb";
> +               reg = <0x20010000 0x1000>;
> +
> +               coresight-id = <0>;
> +               coresight-name = "coresight-etb";
> +               coresight-nr-inports = <1>;
> +               coresight-default-sink;
> +       };
> +
> +       tpiu: tpiu@20030000 {
> +               compatible = "arm,coresight-tpiu";
> +               reg = <0x20030000 0x1000>;
> +
> +               coresight-id = <1>;
> +               coresight-name = "coresight-tpiu";
> +               coresight-nr-inports = <1>;
> +       };
> +
> +3. Links
> +       replicator: replicator {
> +               compatible = "arm,coresight-replicator";
> +
> +               coresight-id = <2>;
> +               coresight-name = "coresight-replicator";
> +               coresight-nr-inports = <1>;
> +               coresight-outports = <0 1>;
> +               coresight-child-list = <&etb &tpiu>;
> +               coresight-child-ports = <0 0>;

This could be one property instead of 2: <&etb 0>, <&tpiu 0>;

Then add a #coresight-cells.

> +       };
> +
> +       funnel: funnel@20040000 {
> +               compatible = "arm,coresight-funnel";
> +               reg = <0x20040000 0x1000>;
> +
> +               coresight-id = <3>;
> +               coresight-name = "coresight-funnel";
> +               coresight-nr-inports = <8>;
> +               coresight-outports = <0>;
> +               coresight-child-list = <&replicator>;
> +               coresight-child-ports = <0>;
> +       };
> +
> +4. Sources
> +       ptm0: ptm@2201c000 {
> +               compatible = "arm,coresight-etm";
> +               reg = <0x2201c000 0x1000>;
> +
> +               coresight-id = <9>;
> +               coresight-name = "coresight-ptm0";
> +               cpu = <&cpu0>;
> +               coresight-nr-inports = <0>;

A source can be implied by no inports property. Likewise for a sink.

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

* Re: [RFC PATCH 01/11] coresight: add CoreSight core layer framework
  2014-05-30 17:25   ` Rob Herring
@ 2014-05-30 18:02     ` Mathieu Poirier
  0 siblings, 0 replies; 23+ messages in thread
From: Mathieu Poirier @ 2014-05-30 18:02 UTC (permalink / raw)
  To: Rob Herring
  Cc: Linus Walleij, Will Deacon, Daniel Thompson, Robert Marklund,
	Al Grant, Linaro Patches, Marcin Jabrzyk, linux-kernel,
	Arnd Bergmann, Panchaxari Prasannamurthy Tumkur, r.sengupta,
	Arve Hjønnevåg, John Stultz, linux-arm-kernel,
	James King, Russell King - ARM Linux, Pratik Patel,
	Vikas Varshney, Jonas Svennebring

On 30 May 2014 11:25, Rob Herring <robherring2@gmail.com> wrote:
> On Fri, May 30, 2014 at 8:43 AM,  <mathieu.poirier@linaro.org> wrote:
>> 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 debugfs.
>>
>> 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>
>> Signed-off-by: Panchaxari Prasannamurthy <panchaxari.prasannamurthy@linaro.org>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>  .../devicetree/bindings/arm/coresight.txt          | 138 ++++
>>  drivers/Kconfig                                    |   2 +
>>  drivers/Makefile                                   |   1 +
>>  drivers/coresight/Kconfig                          |   9 +
>>  drivers/coresight/Makefile                         |   5 +
>>  drivers/coresight/coresight-priv.h                 |  46 ++
>>  drivers/coresight/coresight.c                      | 739 +++++++++++++++++++++
>>  drivers/coresight/of_coresight.c                   | 124 ++++
>>  include/linux/coresight.h                          | 181 +++++
>>  include/linux/of_coresight.h                       |  27 +
>>  10 files changed, 1272 insertions(+)
>>  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..3e21665
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/arm/coresight.txt
>> @@ -0,0 +1,138 @@
>> +* 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
>
> Where are the specific strings for components?

"Coresight" is made of multiple components with each component needing
a different driver.
>
>> +- reg : physical base address and length of the register set(s) of the component
>> +- coresight-id : unique integer identifier for the component
>
> compatible + reg is a unique id.

Some coresight IP blocks like the replicator don't have a reg property
- the "coresight-id" and "coresight-name" are the only way to identify
them properly.

>
>> +- coresight-name : unique descriptive name of the component
>
> compatible is a descriptive name.

That is what ends up under /sys/kernel/debug/coresight/.  Since there
can be multiple entity of the same type it is easier and more
convivial for users.  For instance: "coresight-etb-replicator" and
"coresight-tpiu-replicator" are easier to identify than
"coresight-replicator0" and "coresight-replicator1".

We need to keep "coresight-id" or "coresight-name" - I prefer the
former.  What is your take on this?

>
>> +- 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.
>
> Why do you need the default-sink in DT? Isn't the configuration going
> to depend on the user?

Users can change this at will via debugfs.  It's a default boot time
configuration and can be removed if you're absolutely keen on it.
Please advise.

>
>> +
>> +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
>
> Seems like the OF graph helpers being defined for V4L2 could be useful
> here to describe the connections. We should not invent something new
> to describe arbitrary connections.

Very well, I'll take a look.

>
>> +- arm,buffer-size : size of contiguous buffer space for TMC ETR
>
> TMC ETR?

Trace Memory Controller in Embedded Trace Router configuration.

>
>> +- arm,cp14 : cp14 access to ETM registers is implemented and should be used
>> +- clocks : the clock associated to the coresight entity.
>> +- cpu: only valid for ETM/PTMs - the cpu this ETM/PTM is affined to.
>
> I think you need some separation of bindings by component rather than
> saying which components certain properties apply to.

Ok.

>
>> +
>> +Example:
>> +
>> +1. Bus declaration:
>> +       coresight {
>> +               compatible = "arm,coresight";
>> +               #address-cells = <1>;
>> +               #size-cells = <1>;
>> +               ranges;
>> +               ...
>> +               ...
>> +               ...
>> +        };
>> +
>> +        coresight {
>> +               compatible = "arm,coresight";
>> +               #address-cells = <1>;
>> +               #size-cells = <1>;
>> +               ranges = <0x20010000 0 0x20010000 0x1000
>> +                         0x20030000 0 0x20030000 0x1000
>> +                         0x20040000 0 0x20040000 0x1000
>> +                         0x2201c000 0 0x2201c000 0x1000
>> +                         0x2201d000 0 0x2201d000 0x1000
>> +                         0x2203c000 0 0x2203c000 0x1000
>> +                         0x2203d000 0 0x2203d000 0x1000
>> +                         0x2203e000 0 0x2203e000 0x1000>;
>
> This is not how ranges generally work. For no translation, use just
> "ranges;". Otherwise you should have base address and reg properties
> are just offsets from the base. Anyway, it's not really pertinent to
> your example.

In the case of that specific board doing a one-to-one mapping in
"ranges" was mandatory.  Otherwise the mapping wasn't done at all.

>
>> +               ...
>> +               ...
>> +               ...
>> +       };
>> +
>> +2. Sinks
>> +       etb: etb@20010000 {
>> +               compatible = "arm,coresight-etb";
>> +               reg = <0x20010000 0x1000>;
>> +
>> +               coresight-id = <0>;
>> +               coresight-name = "coresight-etb";
>> +               coresight-nr-inports = <1>;
>> +               coresight-default-sink;
>> +       };
>> +
>> +       tpiu: tpiu@20030000 {
>> +               compatible = "arm,coresight-tpiu";
>> +               reg = <0x20030000 0x1000>;
>> +
>> +               coresight-id = <1>;
>> +               coresight-name = "coresight-tpiu";
>> +               coresight-nr-inports = <1>;
>> +       };
>> +
>> +3. Links
>> +       replicator: replicator {
>> +               compatible = "arm,coresight-replicator";
>> +
>> +               coresight-id = <2>;
>> +               coresight-name = "coresight-replicator";
>> +               coresight-nr-inports = <1>;
>> +               coresight-outports = <0 1>;
>> +               coresight-child-list = <&etb &tpiu>;
>> +               coresight-child-ports = <0 0>;
>
> This could be one property instead of 2: <&etb 0>, <&tpiu 0>;
>

But then we'd have to do the parsing of said property in the code -
isn't that less desirable?

> Then add a #coresight-cells
>
>> +       };
>> +
>> +       funnel: funnel@20040000 {
>> +               compatible = "arm,coresight-funnel";
>> +               reg = <0x20040000 0x1000>;
>> +
>> +               coresight-id = <3>;
>> +               coresight-name = "coresight-funnel";
>> +               coresight-nr-inports = <8>;
>> +               coresight-outports = <0>;
>> +               coresight-child-list = <&replicator>;
>> +               coresight-child-ports = <0>;
>> +       };
>> +
>> +4. Sources
>> +       ptm0: ptm@2201c000 {
>> +               compatible = "arm,coresight-etm";
>> +               reg = <0x2201c000 0x1000>;
>> +
>> +               coresight-id = <9>;
>> +               coresight-name = "coresight-ptm0";
>> +               cpu = <&cpu0>;
>> +               coresight-nr-inports = <0>;
>
> A source can be implied by no inports property. Likewise for a sink.

Sources have  a compatible property to identify them.  A sink has a
single input port.  Did I get your comment right?

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

* Re: [RFC PATCH 02/11] coresight: add CoreSight TMC driver
  2014-05-30 13:43 ` [RFC PATCH 02/11] coresight: add CoreSight TMC driver mathieu.poirier
@ 2014-06-03  9:09   ` Linus Walleij
  2014-06-16 23:12     ` Mathieu Poirier
  0 siblings, 1 reply; 23+ messages in thread
From: Linus Walleij @ 2014-06-03  9:09 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Will Deacon, Arve Hjønnevåg, John Stultz, Pratik Patel,
	varshney, Al.Grant, jonas.svennebring, James King,
	Panchaxari Prasannamurthy Tumkur, Arnd Bergmann, marcin.jabrzyk,
	r.sengupta, Robert Marklund, Patch Tracking,
	Russell King - ARM Linux, linux-arm-kernel, linux-kernel,
	daniel.thompson

On Fri, May 30, 2014 at 3:43 PM,  <mathieu.poirier@linaro.org> wrote:

> +#define tmc_writel(drvdata, val, off)  __raw_writel((val), drvdata->base + off)
> +#define tmc_readl(drvdata, off)                __raw_readl(drvdata->base + off)

Why not writel_relaxed()/readl_relaxed()?

Using __raw* accessors seem a bit thick. (Applies to all such defines.)

> +#define TMC_LOCK(drvdata)                                              \
> +do {                                                                   \
> +       /* settle everything first */                                   \
> +       mb();                                                           \
> +       tmc_writel(drvdata, 0x0, CORESIGHT_LAR);                        \
> +} while (0)
> +#define TMC_UNLOCK(drvdata)                                            \
> +do {                                                                   \
> +       tmc_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);           \
> +       /* make sure everyone sees this */                              \
> +       mb();                                                           \
> +} while (0)

Convert these to static inlines. No need for them to be #defines
at all really.

> +#define BYTES_PER_WORD         4

But please. Just using the number 4 everywhere is clear enough.

> +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;

Can this really be negative?

> +       bool                    reading;
> +       char                    *buf;
> +       dma_addr_t              paddr;
> +       void __iomem            *vaddr;
> +       uint32_t                size;

Use u32

> +       bool                    enable;
> +       enum tmc_config_type    config_type;
> +       uint32_t                trigger_cntr;

Use u32

> +};

This struct overall could use some kerneldoc.

> +static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
> +{
> +       int count;

Why not call this variable "i" as per convention.

> +       uint32_t ffcr;

u32

> +
> +       ffcr = tmc_readl(drvdata, TMC_FFCR);
> +       ffcr |= BIT(12);
> +       tmc_writel(drvdata, ffcr, TMC_FFCR);
> +       ffcr |= BIT(6);

A bit unclear what bit 12 and 6 does. Either #define them or add comments.

> +       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);
> +}

I actually understand what bit 0 does in this register, but could
also be #defined.

> +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);

0x133? Que ce que c'est?

> +       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;

u32

> +       /* 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);

I don't understand these bits and shifts either.

> +       tmc_writel(drvdata, drvdata->paddr, TMC_DBALO);
> +       tmc_writel(drvdata, 0x0, TMC_DBAHI);
> +       tmc_writel(drvdata, 0x133, TMC_FFCR);

More magic...

> +       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);

More magic.

> +       __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)

I'm no fan of prefixing functions with __underscores and cannot see why
this is done here even, just seems like force of habit. Please cut them.
Rename the function slightly to correspond to what it does if it collides
with another function.

> +{
> +       enum tmc_mem_intf_width memwidth;
> +       uint8_t memwords;

u8

> +       char *bufp;
> +       uint32_t read_data;

u32

(...)
> +       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;

Use 4 rather than BYTES_PER_WORD please.

(...)
> +static void __tmc_etr_dump(struct tmc_drvdata *drvdata)

Cut __

> +{
> +       uint32_t rwp, rwphi;

u32

> +       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)

Cut __

> +{
> +       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)

Cut __

(...)
> +static int tmc_probe(struct platform_device *pdev)
> +{
> +       int ret = 0;
> +       uint32_t devid;

u32

> +       struct device *dev = &pdev->dev;
> +       struct coresight_platform_data *pdata = NULL;
> +       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));

Use devm_ioremap_resource() instead.

> +       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->debugfs_ops = 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->debugfs_ops = 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->debugfs_ops = 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;
> +               }
> +       }

Actually you set some stuff like desc->dev and pdata to the
same thing in all three clauses... Do it before the if/else-ladder
and cut the repititions.

> +       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);

Miscdev really? Well, not that I know any better.

> +static struct platform_driver tmc_driver = {
> +       .probe          = tmc_probe,
> +       .remove         = 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);

Convert to use module_platform_driver()

I think these review comments apply to many of the patches,
so please take each comment and iterate over the code.

Yours,
Linus Walleij

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

* Re: [RFC PATCH 07/11] coresight: add CoreSight ETM driver
  2014-05-30 13:43 ` [RFC PATCH 07/11] coresight: add CoreSight ETM driver mathieu.poirier
@ 2014-06-03 10:26   ` Daniel Thompson
  2014-06-03 16:37     ` Mathieu Poirier
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Thompson @ 2014-06-03 10:26 UTC (permalink / raw)
  To: mathieu.poirier, linus.walleij, will.deacon
  Cc: arve, john.stultz, pratikp, varshney, Al.Grant,
	jonas.svennebring, james.king, panchaxari.prasannamurthy, arnd,
	marcin.jabrzyk, r.sengupta, robbelibobban, patches, linux,
	linux-arm-kernel, linux-kernel

On 30/05/14 14:43, mathieu.poirier@linaro.org wrote:
> diff --git a/drivers/coresight/coresight-etm-cp14.c b/drivers/coresight/coresight-etm-cp14.c
> new file mode 100644
> index 0000000..0088bbb
> --- /dev/null
> +++ b/drivers/coresight/coresight-etm-cp14.c
> @@ -0,0 +1,511 @@
> +/* 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 <linux/bug.h>
> +#include <asm/hardware/cp14.h>
> +
> +static unsigned int etm_read_reg(uint32_t reg)
> +{
> +	switch (reg) {
> +	case 0x0:

Shouldn't this be:

case ETMCR/4:

Or an equivalent macro? Given the memory mappings are already spelt out
in another file it seems a shame to restate them again.

> +		return etm_read(ETMCR);

Maybe we could even condense the mapping with something like:

#define CASE_MAP_MM_READ_TO_CPIO(x) case (x)/4: return etm_read(x)

CASE_MAP_MM_READ_TO_CPIO(ETMCR);
CASE_MAP_MM_READ_TO_CPIO(ETMCCR);
CASE_MAP_MM_READ_TO_CPIO(ETMTRIGGER);
...

Note that the macro may not be perfect since it untested and I can't
remember how it will interact with the token pasting in etm_read(x).
Howevver but a macro with this interface can definitely be written.

> +	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);

Same comment as etm_read_reg but with a different macro.

> +		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);
> +}

Revisiting previous comments... maybe we don't have to divide the MM
constants by four either? We could just not divide them by four here.


> diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
> new file mode 100644
> index 0000000..59589be
> --- /dev/null
> +++ b/drivers/coresight/coresight-etm.c
> @@ -0,0 +1,2360 @@
> +/* 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;								\
> +})

Why macros rather than inlines?


> +
> +#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)

Why macros rather than inlines?


> +
> +#define PORT_SIZE_MASK		(BM(21, 21) | BM(4, 6))
> +
> +/*
> + * 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 ETMTECR2		(0x01c)
> +#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)

Move to a header file so the CP14 code can use them ;-)

> +
> +#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;
> +	int				port_size;
> +	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)
> +{
> +	struct etm_drvdata *drvdata = (struct etm_drvdata *)info;
> +	etm_writel(drvdata, 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);

Why are register accesses _mm here? They are not in pwrdown.


> +	/* 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);
> +}

Same here. Why _mm?


> +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);
> +
> +	/* turn engine on */
> +	etm_clr_pwrdwn(drvdata);
> +	/* apply power to trace registers */
> +	etm_set_pwrup(drvdata);
> +	/* make sure all registers are accessible */
> +	etm_os_unlock(drvdata);
> +
> +	etm_set_prog(drvdata);
> +
> +	etmcr = etm_readl(drvdata, ETMCR);
> +	etmcr &= (BIT(10) | BIT(0));
> +	etmcr |= drvdata->port_size;
> +	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);
> +
> +	/* ensures trace output is enabled from this ETM */
> +	etm_writel(drvdata, drvdata->ctrl | BIT(11) | etmcr, ETMCR);
> +
> +	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 debugfs_show_nr_addr_cmp(struct file *file,
> +					char __user *user_buf,
> +					size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	val = drvdata->nr_addr_cmp;
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static const struct file_operations debugfs_nr_addr_cmp_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_nr_addr_cmp,
> +};


DEFINE_SIMPLE_ATTRIBUTE() would acheive the above with smaller code size
and no bugs.


> +static const struct coresight_ops_entry debugfs_nr_addr_cmp_entry = {
> +	.name = "nr_addr_cmp",
> +	.mode =  S_IRUGO,
> +	.ops = &debugfs_nr_addr_cmp_ops,
> +};

This (and its friends futher down) look samey enough to merit a
DEFINE_CORESIGHT_ENTRY() macro.


> +static ssize_t debugfs_show_nr_cntr(struct file *file,
> +				    char __user *user_buf,
> +				    size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	val = drvdata->nr_cntr;
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static const struct file_operations debugfs_nr_cntr_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_nr_cntr,
> +};
> +
> +static const struct coresight_ops_entry debugfs_nr_cntr_entry = {
> +	.name = "nr_cntr",
> +	.mode =  S_IRUGO,
> +	.ops = &debugfs_nr_cntr_ops,
> +};

DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()

> +
> +static ssize_t debugfs_show_nr_ctxid_cmp(struct file *file,
> +					 char __user *user_buf,
> +					 size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	val = drvdata->nr_ctxid_cmp;
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static const struct file_operations debugfs_nr_ctxid_cmp_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_nr_ctxid_cmp,
> +};
> +
> +static const struct coresight_ops_entry debugfs_nr_ctxid_cmp_entry = {
> +	.name = "nr_ctxid_cmp",
> +	.mode =  S_IRUGO,
> +	.ops = &debugfs_nr_ctxid_cmp_ops,
> +};

DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()

> +static ssize_t debugfs_show_reset(struct file *file,
> +				  char __user *user_buf,
> +				  size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	val = drvdata->reset;
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +/* Reset to trace everything i.e. exclude nothing. */
> +static ssize_t debugfs_store_reset(struct file *file,
> +				   const char __user *user_buf,
> +				   size_t count, loff_t *ppos)
> +{
> +	int i;
> +	unsigned long val;
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	if (sscanf(user_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 count;
> +}

This smells like it shared lots of code with __etm_enable(). Not sure
though with all those 0x406F.

Whatever the case, this code should probably be hoisted out of the
debugfs code and into a named function.

> +
> +static const struct file_operations debugfs_reset_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_reset,
> +	.write = debugfs_store_reset,
> +};
> +
> +static const struct coresight_ops_entry debugfs_reset_entry = {
> +	.name = "reset",
> +	.mode =  S_IRUGO | S_IWUSR,
> +	.ops = &debugfs_reset_ops,
> +};
> +
> +static ssize_t debugfs_show_mode(struct file *file,
> +				 char __user *user_buf,
> +				 size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	val = drvdata->mode;
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static ssize_t debugfs_store_mode(struct file *file,
> +				  const char __user *user_buf,
> +				  size_t count, loff_t *ppos)
> +{
> +	unsigned long val;
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	if (sscanf(user_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 count;
> +}
> +
> +static const struct file_operations debugfs_mode_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_mode,
> +	.write = debugfs_store_mode,
> +};
> +
> +static const struct coresight_ops_entry debugfs_mode_entry = {
> +	.name = "mode",
> +	.mode =  S_IRUGO | S_IWUSR,
> +	.ops = &debugfs_mode_ops,
> +};

DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()

> +
> +static ssize_t debugfs_show_trigger_event(struct file *file,
> +					  char __user *user_buf,
> +					  size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	val = drvdata->trigger_event;
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static ssize_t debugfs_store_trigger_event(struct file *file,
> +					   const char __user *user_buf,
> +					   size_t count, loff_t *ppos)
> +{
> +	unsigned long val;
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	if (sscanf(user_buf, "%lx", &val) != 1)
> +		return -EINVAL;
> +
> +	drvdata->trigger_event = val & ETM_EVENT_MASK;
> +	return count;
> +}
> +
> +static const struct file_operations debugfs_trigger_event_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_trigger_event,
> +	.write = debugfs_store_trigger_event,
> +};
> +
> +static const struct coresight_ops_entry debugfs_trigger_events_entry = {
> +	.name = "trigger_event",
> +	.mode =  S_IRUGO | S_IWUSR,
> +	.ops = &debugfs_trigger_event_ops,
> +};

DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()

> +
> +static ssize_t debugfs_show_enable_event(struct file *file,
> +					 char __user *user_buf,
> +					 size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	val = drvdata->enable_event;
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static ssize_t debugfs_store_enable_event(struct file *file,
> +					  const char __user *user_buf,
> +					  size_t count, loff_t *ppos)
> +{
> +	unsigned long val;
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	if (sscanf(user_buf, "%lx", &val) != 1)
> +		return -EINVAL;
> +
> +	drvdata->enable_event = val & ETM_EVENT_MASK;
> +	return count;
> +}
> +
> +static const struct file_operations debugfs_enable_event_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_enable_event,
> +	.write = debugfs_store_enable_event,
> +};
> +
> +static const struct coresight_ops_entry debugfs_enable_events_entry = {
> +	.name = "enable_event",
> +	.mode =  S_IRUGO | S_IWUSR,
> +	.ops = &debugfs_enable_event_ops,
> +};
> +

DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()

> +static ssize_t debugfs_show_fifofull_level(struct file *file,
> +					   char __user *user_buf,
> +					   size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	val = drvdata->fifofull_level;
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static ssize_t debugfs_store_fifofull_level(struct file *file,
> +					    const char __user *user_buf,
> +					    size_t count, loff_t *ppos)
> +{
> +	unsigned long val;
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	if (sscanf(user_buf, "%lx", &val) != 1)
> +		return -EINVAL;
> +
> +	drvdata->fifofull_level = val;
> +	return count;
> +}
> +
> +static const struct file_operations debugfs_fifofull_level_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_fifofull_level,
> +	.write = debugfs_store_fifofull_level,
> +};
> +
> +static const struct coresight_ops_entry debugfs_fifofull_level_entry = {
> +	.name = "fifofull_level",
> +	.mode =  S_IRUGO | S_IWUSR,
> +	.ops = &debugfs_fifofull_level_ops,
> +};
> +

DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()

> +static ssize_t debugfs_show_addr_idx(struct file *file,
> +				     char __user *user_buf,
> +				     size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	val = drvdata->addr_idx;
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static ssize_t debugfs_store_addr_idx(struct file *file,
> +				      const char __user *user_buf,
> +				      size_t count, loff_t *ppos)
> +{
> +	unsigned long val;
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	if (sscanf(user_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 count;
> +}
> +
> +static const struct file_operations debugfs_addr_idx_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_addr_idx,
> +	.write = debugfs_store_addr_idx,
> +};
> +
> +static const struct coresight_ops_entry debugfs_addr_idx_entry = {
> +	.name = "addr_idx",
> +	.mode =  S_IRUGO | S_IWUSR,
> +	.ops = &debugfs_addr_idx_ops,
> +};
> +

DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()

> +static ssize_t debugfs_show_addr_single(struct file *file,
> +					char __user *user_buf,
> +					size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	uint8_t idx;
> +	unsigned long val;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	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;

-EPERM?

Is this really a permissions check.

> +	}
> +
> +	val = drvdata->addr_val[idx];
> +	spin_unlock(&drvdata->spinlock);
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static ssize_t debugfs_store_addr_single(struct file *file,
> +					 const char __user *user_buf,
> +					 size_t count, loff_t *ppos)
> +{
> +	uint8_t idx;
> +	unsigned long val;
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	if (sscanf(user_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;

-EPERM?

> +	}
> +
> +	drvdata->addr_val[idx] = val;
> +	drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
> +	spin_unlock(&drvdata->spinlock);
> +	return count;
> +}
> +
> +static const struct file_operations debugfs_addr_single_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_addr_single,
> +	.write = debugfs_store_addr_single,
> +};
> +
> +static const struct coresight_ops_entry debugfs_addr_single_entry = {
> +	.name = "addr_single",
> +	.mode =  S_IRUGO | S_IWUSR,
> +	.ops = &debugfs_addr_single_ops,
> +};

DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()

> +static ssize_t debugfs_show_addr_range(struct file *file,
> +				       char __user *user_buf,
> +				       size_t count, loff_t *ppos)
> +{
> +	int ret;
> +	uint8_t idx;
> +	unsigned long val1, val2;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	spin_lock(&drvdata->spinlock);
> +	idx = drvdata->addr_idx;
> +	if (idx % 2 != 0) {
> +		spin_unlock(&drvdata->spinlock);
> +		return -EPERM;

-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;

-EPERM?

> +	}
> +
> +	val1 = drvdata->addr_val[idx];
> +	val2 = drvdata->addr_val[idx + 1];
> +	spin_unlock(&drvdata->spinlock);
> +	ret = scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +
> +	kfree(buf);
> +	return ret;
> +}
> +
> +static ssize_t debugfs_store_addr_range(struct file *file,
> +					const char __user *user_buf,
> +					size_t count, loff_t *ppos)
> +{
> +	uint8_t idx;
> +	unsigned long val1, val2;
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	if (sscanf(user_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;

-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;

-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 count;
> +}
> +
> +static const struct file_operations debugfs_addr_range_ops = {
> +	.open = simple_open,
> +	.read = debugfs_show_addr_range,
> +	.write = debugfs_store_addr_range,
> +};
> +
> +static const struct coresight_ops_entry debugfs_addr_range_entry = {
> +	.name = "addr_range",
> +	.mode =  S_IRUGO | S_IWUSR,
> +	.ops = &debugfs_addr_range_ops,
> +};

DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()

SNIP!!!

My comments of debugfs get a bit samey from here on down so I've deleted
a big chunk.


> +static ssize_t debugfs_status_read(struct file *file, char __user *user_buf,
> +				   size_t count, loff_t *ppos)
> +{
> +	ssize_t ret;
> +	uint32_t val;
> +	unsigned long flags;
> +	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
> +	struct etm_drvdata *drvdata = file->private_data;
> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	ret = clk_prepare_enable(drvdata->clk);
> +	if (ret)
> +		goto out;
> +
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +
> +	ETM_UNLOCK(drvdata);
> +	val = etm_readl(drvdata, ETMCCR);
> +	ret += sprintf(buf, "ETMCCR: 0x%08x\n", val);
> +	val = etm_readl(drvdata, ETMCCER);
> +	ret += sprintf(buf + ret, "ETMCCER: 0x%08x\n", val);
> +	val = etm_readl(drvdata, ETMSCR);
> +	ret += sprintf(buf + ret, "ETMSCR: 0x%08x\n", val);
> +	val = etm_readl(drvdata, ETMIDR);
> +	ret += sprintf(buf + ret, "ETMIDR: 0x%08x\n", val);
> +	val = etm_readl(drvdata, ETMCR);
> +	ret += sprintf(buf + ret, "ETMCR: 0x%08x\n", val);
> +	val = etm_readl(drvdata, ETMTEEVR);
> +	ret += sprintf(buf + ret, "Enable event: 0x%08x\n", val);
> +	val = etm_readl(drvdata, ETMTSSCR);
> +	ret += sprintf(buf + ret, "Enable start/stop: 0x%08x\n", val);
> +	ret += sprintf(buf + ret,
> +		       "Enable control: CR1 0x%08x CR2 0x%08x\n",
> +		       etm_readl(drvdata, ETMTECR1),
> +		       etm_readl(drvdata, ETMTECR2));
> +
> +	ETM_LOCK(drvdata);
> +
> +	spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +	clk_disable_unprepare(drvdata->clk);
> +
> +	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> +out:
> +	kfree(buf);
> +	return ret;
> +}

Really not sure whether this should be in the read method. If we don't
read the file in one go the spin_lock() we'll not get a cohesive set of
registers.


> +
> +static const struct file_operations debugfs_status_ops = {
> +	.open = simple_open,
> +	.read = debugfs_status_read,
> +};
> +
> +static const struct coresight_ops_entry debugfs_status_entry = {
> +	.name = "status",
> +	.mode =  S_IRUGO,
> +	.ops = &debugfs_status_ops,
> +};
> +
> +static const struct coresight_ops_entry *etm_attr_grps[] = {
> +	&debugfs_nr_addr_cmp_entry,
> +	&debugfs_nr_cntr_entry,
> +	&debugfs_nr_ctxid_cmp_entry,
> +	&debugfs_reset_entry,
> +	&debugfs_mode_entry,
> +	&debugfs_trigger_events_entry,
> +	&debugfs_enable_events_entry,
> +	&debugfs_fifofull_level_entry,
> +	&debugfs_addr_idx_entry,
> +	&debugfs_addr_single_entry,
> +	&debugfs_addr_range_entry,
> +	&debugfs_addr_start_entry,
> +	&debugfs_addr_stop_entry,
> +	&debugfs_addr_acctype_entry,
> +	&debugfs_cntr_idx_entry,
> +	&debugfs_cntr_rld_val_entry,
> +	&debugfs_cntr_event_entry,
> +	&debugfs_cntr_rld_event_entry,
> +	&debugfs_cntr_val_entry,
> +	&debugfs_12_event_entry,
> +	&debugfs_21_event_entry,
> +	&debugfs_23_event_entry,
> +	&debugfs_31_event_entry,
> +	&debugfs_32_event_entry,
> +	&debugfs_13_event_entry,
> +	&debugfs_seq_curr_state_entry,
> +	&debugfs_ctxid_idx_entry,
> +	&debugfs_ctxid_val_entry,
> +	&debugfs_ctxid_mask_entry,
> +	&debugfs_sync_freq_entry,
> +	&debugfs_timestamp_event_entry,
> +	&debugfs_status_entry,
> +	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);
> +		break;
> +
> +	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 etm_arch_supported(uint8_t arch)
> +{
> +	switch (arch) {
> +	case ETM_ARCH_V3_3:
> +		break;
> +	case ETM_ARCH_V3_5:
> +		break;
> +	case PFT_ARCH_V1_1:
> +		break;
> +	default:
> +		return false;
> +	}
> +	return true;
> +}
> +
> +static void etm_init_arch_data(void *info)
> +{
> +	uint32_t etmidr;
> +	uint32_t etmccr;
> +	struct etm_drvdata *drvdata = info;
> +
> +	ETM_UNLOCK(drvdata);
> +
> +	/* first dummy read */
> +	(void)etm_readl(drvdata, ETMPDSR);
> +	/* Provide power to ETM: ETMPDCR[3] == 1 */
> +	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);
> +	/*
> +	 * 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);
> +	drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
> +
> +	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_clr_pwrup(drvdata);
> +	ETM_LOCK(drvdata);
> +}
> +
> +static void etm_init_default_data(struct etm_drvdata *drvdata)
> +{
> +	int i;
> +
> +	uint32_t flags = (1 << 0 | /* instruction execute*/
> +			  3 << 3 | /* ARM instruction */
> +			  0 << 5 | /* No data value comparison */
> +			  0 << 7 | /* No exact mach */
> +			  0 << 8 | /* Ignore context ID */
> +			  0 << 10); /* Security ignored */
> +
> +	drvdata->ctrl = (BIT(12) | /* cycle accurate */
> +			 BIT(28)); /* timestamp */
> +	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_acctype[0] = flags;
> +		drvdata->addr_acctype[1] = flags;
> +		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;
> +}

Ah... here's all those 0x406F I thought looked odd in the implementation
of the reset attribute. This code should be commoned up as much as
possible with the reset code.

Also perhaps a #define to explain what 0x406F means?


> +
> +static int etm_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct device *dev = &pdev->dev;
> +	struct coresight_platform_data *pdata = NULL;
> +	struct etm_drvdata *drvdata;
> +	struct resource *res;
> +	static int count;

That "static" is very well concealed. I missed that until I started
studying the error paths.

> +	struct coresight_desc *desc;
> +
> +	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
> +	if (!drvdata)
> +		return -ENOMEM;
> +
> +	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->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));

Leak on error paths?

> +	if (!drvdata->base)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&drvdata->spinlock);
> +
> +	if (pdata && pdata->clk) {
> +		drvdata->clk = pdata->clk;
> +		ret = clk_prepare_enable(drvdata->clk);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	drvdata->cpu = pdata ? pdata->cpu : 0;
> +
> +	get_online_cpus();
> +	etmdrvdata[drvdata->cpu] = drvdata;
> +
> +	if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, drvdata, 1))
> +		drvdata->os_unlock = true;
> +
> +	if (smp_call_function_single(drvdata->cpu,
> +				     etm_init_arch_data,  drvdata, 1))
> +		dev_err(dev, "ETM arch init failed\n");
> +
> +	if (!count++)

count is mishandled on the error paths?

> +		register_hotcpu_notifier(&etm_cpu_notifier);

Leak on (some of the) error paths?

> +
> +	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);

Leak on error paths?

> +	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->debugfs_ops = 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 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         = 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");
> 


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

* Re: [RFC PATCH 07/11] coresight: add CoreSight ETM driver
  2014-06-03 10:26   ` Daniel Thompson
@ 2014-06-03 16:37     ` Mathieu Poirier
  2014-06-03 17:04       ` Daniel Thompson
  0 siblings, 1 reply; 23+ messages in thread
From: Mathieu Poirier @ 2014-06-03 16:37 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Linus Walleij, Will Deacon, Arve Hjønnevåg,
	John Stultz, Pratik Patel, Vikas Varshney, Al Grant,
	Jonas Svennebring, James King, Panchaxari Prasannamurthy Tumkur,
	Arnd Bergmann, Marcin Jabrzyk, r.sengupta, Robert Marklund,
	Patch Tracking, Russell King - ARM Linux, linux-arm-kernel,
	linux-kernel

Thanks for the review.  Please see comments in-lined.

Mathieu

On 3 June 2014 04:26, Daniel Thompson <daniel.thompson@linaro.org> wrote:
> On 30/05/14 14:43, mathieu.poirier@linaro.org wrote:
>> diff --git a/drivers/coresight/coresight-etm-cp14.c b/drivers/coresight/coresight-etm-cp14.c
>> new file mode 100644
>> index 0000000..0088bbb
>> --- /dev/null
>> +++ b/drivers/coresight/coresight-etm-cp14.c
>> @@ -0,0 +1,511 @@
>> +/* 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 <linux/bug.h>
>> +#include <asm/hardware/cp14.h>
>> +
>> +static unsigned int etm_read_reg(uint32_t reg)
>> +{
>> +     switch (reg) {
>> +     case 0x0:
>
> Shouldn't this be:
>
> case ETMCR/4:
>
> Or an equivalent macro? Given the memory mappings are already spelt out
> in another file it seems a shame to restate them again.
>
>> +             return etm_read(ETMCR);
>
> Maybe we could even condense the mapping with something like:
>
> #define CASE_MAP_MM_READ_TO_CPIO(x) case (x)/4: return etm_read(x)
>
> CASE_MAP_MM_READ_TO_CPIO(ETMCR);
> CASE_MAP_MM_READ_TO_CPIO(ETMCCR);
> CASE_MAP_MM_READ_TO_CPIO(ETMTRIGGER);
> ...
>
> Note that the macro may not be perfect since it untested and I can't
> remember how it will interact with the token pasting in etm_read(x).
> Howevver but a macro with this interface can definitely be written.

I agree, we can do better.

>
>> +     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);
>
> Same comment as etm_read_reg but with a different macro.
>
>> +             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);
>> +}
>
> Revisiting previous comments... maybe we don't have to divide the MM
> constants by four either? We could just not divide them by four here.
>
>
>> diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
>> new file mode 100644
>> index 0000000..59589be
>> --- /dev/null
>> +++ b/drivers/coresight/coresight-etm.c
>> @@ -0,0 +1,2360 @@
>> +/* 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;                                                            \
>> +})
>
> Why macros rather than inlines?

Linus W. had the same comment - ACK.

>
>
>> +
>> +#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)
>
> Why macros rather than inlines?
>
>
>> +
>> +#define PORT_SIZE_MASK               (BM(21, 21) | BM(4, 6))
>> +
>> +/*
>> + * 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 ETMTECR2             (0x01c)
>> +#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)
>
> Move to a header file so the CP14 code can use them ;-)
>
>> +
>> +#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;
>> +     int                             port_size;
>> +     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)
>> +{
>> +     struct etm_drvdata *drvdata = (struct etm_drvdata *)info;
>> +     etm_writel(drvdata, 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);
>
> Why are register accesses _mm here? They are not in pwrdown.

Designers can mandate that management registers be access via cp14
only (when supported) but looking at the TRM I just noticed that
coprocessor access to ETMPDCR is "unpredictable".  I'll fix that right
away.

>
>
>> +     /* 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);
>> +}
>
> Same here. Why _mm?
>
>
>> +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);
>> +
>> +     /* turn engine on */
>> +     etm_clr_pwrdwn(drvdata);
>> +     /* apply power to trace registers */
>> +     etm_set_pwrup(drvdata);
>> +     /* make sure all registers are accessible */
>> +     etm_os_unlock(drvdata);
>> +
>> +     etm_set_prog(drvdata);
>> +
>> +     etmcr = etm_readl(drvdata, ETMCR);
>> +     etmcr &= (BIT(10) | BIT(0));
>> +     etmcr |= drvdata->port_size;
>> +     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);
>> +
>> +     /* ensures trace output is enabled from this ETM */
>> +     etm_writel(drvdata, drvdata->ctrl | BIT(11) | etmcr, ETMCR);
>> +
>> +     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 debugfs_show_nr_addr_cmp(struct file *file,
>> +                                     char __user *user_buf,
>> +                                     size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     val = drvdata->nr_addr_cmp;
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static const struct file_operations debugfs_nr_addr_cmp_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_nr_addr_cmp,
>> +};
>
>
> DEFINE_SIMPLE_ATTRIBUTE() would acheive the above with smaller code size
> and no bugs.

I was actually debating doing something like this before or after the
initial RFC.  I agree, the syntax can be lightened.

>
>
>> +static const struct coresight_ops_entry debugfs_nr_addr_cmp_entry = {
>> +     .name = "nr_addr_cmp",
>> +     .mode =  S_IRUGO,
>> +     .ops = &debugfs_nr_addr_cmp_ops,
>> +};
>
> This (and its friends futher down) look samey enough to merit a
> DEFINE_CORESIGHT_ENTRY() macro.
>
>
>> +static ssize_t debugfs_show_nr_cntr(struct file *file,
>> +                                 char __user *user_buf,
>> +                                 size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     val = drvdata->nr_cntr;
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static const struct file_operations debugfs_nr_cntr_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_nr_cntr,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_nr_cntr_entry = {
>> +     .name = "nr_cntr",
>> +     .mode =  S_IRUGO,
>> +     .ops = &debugfs_nr_cntr_ops,
>> +};
>
> DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()
>
>> +
>> +static ssize_t debugfs_show_nr_ctxid_cmp(struct file *file,
>> +                                      char __user *user_buf,
>> +                                      size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     val = drvdata->nr_ctxid_cmp;
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static const struct file_operations debugfs_nr_ctxid_cmp_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_nr_ctxid_cmp,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_nr_ctxid_cmp_entry = {
>> +     .name = "nr_ctxid_cmp",
>> +     .mode =  S_IRUGO,
>> +     .ops = &debugfs_nr_ctxid_cmp_ops,
>> +};
>
> DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()
>
>> +static ssize_t debugfs_show_reset(struct file *file,
>> +                               char __user *user_buf,
>> +                               size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     val = drvdata->reset;
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +/* Reset to trace everything i.e. exclude nothing. */
>> +static ssize_t debugfs_store_reset(struct file *file,
>> +                                const char __user *user_buf,
>> +                                size_t count, loff_t *ppos)
>> +{
>> +     int i;
>> +     unsigned long val;
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     if (sscanf(user_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 count;
>> +}
>
> This smells like it shared lots of code with __etm_enable(). Not sure
> though with all those 0x406F.
>
> Whatever the case, this code should probably be hoisted out of the
> debugfs code and into a named function.
>
>> +
>> +static const struct file_operations debugfs_reset_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_reset,
>> +     .write = debugfs_store_reset,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_reset_entry = {
>> +     .name = "reset",
>> +     .mode =  S_IRUGO | S_IWUSR,
>> +     .ops = &debugfs_reset_ops,
>> +};
>> +
>> +static ssize_t debugfs_show_mode(struct file *file,
>> +                              char __user *user_buf,
>> +                              size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     val = drvdata->mode;
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static ssize_t debugfs_store_mode(struct file *file,
>> +                               const char __user *user_buf,
>> +                               size_t count, loff_t *ppos)
>> +{
>> +     unsigned long val;
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     if (sscanf(user_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 count;
>> +}
>> +
>> +static const struct file_operations debugfs_mode_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_mode,
>> +     .write = debugfs_store_mode,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_mode_entry = {
>> +     .name = "mode",
>> +     .mode =  S_IRUGO | S_IWUSR,
>> +     .ops = &debugfs_mode_ops,
>> +};
>
> DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()
>
>> +
>> +static ssize_t debugfs_show_trigger_event(struct file *file,
>> +                                       char __user *user_buf,
>> +                                       size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     val = drvdata->trigger_event;
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static ssize_t debugfs_store_trigger_event(struct file *file,
>> +                                        const char __user *user_buf,
>> +                                        size_t count, loff_t *ppos)
>> +{
>> +     unsigned long val;
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     if (sscanf(user_buf, "%lx", &val) != 1)
>> +             return -EINVAL;
>> +
>> +     drvdata->trigger_event = val & ETM_EVENT_MASK;
>> +     return count;
>> +}
>> +
>> +static const struct file_operations debugfs_trigger_event_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_trigger_event,
>> +     .write = debugfs_store_trigger_event,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_trigger_events_entry = {
>> +     .name = "trigger_event",
>> +     .mode =  S_IRUGO | S_IWUSR,
>> +     .ops = &debugfs_trigger_event_ops,
>> +};
>
> DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()
>
>> +
>> +static ssize_t debugfs_show_enable_event(struct file *file,
>> +                                      char __user *user_buf,
>> +                                      size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     val = drvdata->enable_event;
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static ssize_t debugfs_store_enable_event(struct file *file,
>> +                                       const char __user *user_buf,
>> +                                       size_t count, loff_t *ppos)
>> +{
>> +     unsigned long val;
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     if (sscanf(user_buf, "%lx", &val) != 1)
>> +             return -EINVAL;
>> +
>> +     drvdata->enable_event = val & ETM_EVENT_MASK;
>> +     return count;
>> +}
>> +
>> +static const struct file_operations debugfs_enable_event_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_enable_event,
>> +     .write = debugfs_store_enable_event,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_enable_events_entry = {
>> +     .name = "enable_event",
>> +     .mode =  S_IRUGO | S_IWUSR,
>> +     .ops = &debugfs_enable_event_ops,
>> +};
>> +
>
> DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()
>
>> +static ssize_t debugfs_show_fifofull_level(struct file *file,
>> +                                        char __user *user_buf,
>> +                                        size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     val = drvdata->fifofull_level;
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static ssize_t debugfs_store_fifofull_level(struct file *file,
>> +                                         const char __user *user_buf,
>> +                                         size_t count, loff_t *ppos)
>> +{
>> +     unsigned long val;
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     if (sscanf(user_buf, "%lx", &val) != 1)
>> +             return -EINVAL;
>> +
>> +     drvdata->fifofull_level = val;
>> +     return count;
>> +}
>> +
>> +static const struct file_operations debugfs_fifofull_level_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_fifofull_level,
>> +     .write = debugfs_store_fifofull_level,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_fifofull_level_entry = {
>> +     .name = "fifofull_level",
>> +     .mode =  S_IRUGO | S_IWUSR,
>> +     .ops = &debugfs_fifofull_level_ops,
>> +};
>> +
>
> DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()
>
>> +static ssize_t debugfs_show_addr_idx(struct file *file,
>> +                                  char __user *user_buf,
>> +                                  size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     val = drvdata->addr_idx;
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static ssize_t debugfs_store_addr_idx(struct file *file,
>> +                                   const char __user *user_buf,
>> +                                   size_t count, loff_t *ppos)
>> +{
>> +     unsigned long val;
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     if (sscanf(user_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 count;
>> +}
>> +
>> +static const struct file_operations debugfs_addr_idx_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_addr_idx,
>> +     .write = debugfs_store_addr_idx,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_addr_idx_entry = {
>> +     .name = "addr_idx",
>> +     .mode =  S_IRUGO | S_IWUSR,
>> +     .ops = &debugfs_addr_idx_ops,
>> +};
>> +
>
> DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()
>
>> +static ssize_t debugfs_show_addr_single(struct file *file,
>> +                                     char __user *user_buf,
>> +                                     size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     uint8_t idx;
>> +     unsigned long val;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     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;
>
> -EPERM?
>
> Is this really a permissions check.

That is debatable - you don't have permission because 'addr_type'
doesn't correspond to a single address comparator.  "-EINVAL" could
also be returned...

>
>> +     }
>> +
>> +     val = drvdata->addr_val[idx];
>> +     spin_unlock(&drvdata->spinlock);
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static ssize_t debugfs_store_addr_single(struct file *file,
>> +                                      const char __user *user_buf,
>> +                                      size_t count, loff_t *ppos)
>> +{
>> +     uint8_t idx;
>> +     unsigned long val;
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     if (sscanf(user_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;
>
> -EPERM?
>
>> +     }
>> +
>> +     drvdata->addr_val[idx] = val;
>> +     drvdata->addr_type[idx] = ETM_ADDR_TYPE_SINGLE;
>> +     spin_unlock(&drvdata->spinlock);
>> +     return count;
>> +}
>> +
>> +static const struct file_operations debugfs_addr_single_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_addr_single,
>> +     .write = debugfs_store_addr_single,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_addr_single_entry = {
>> +     .name = "addr_single",
>> +     .mode =  S_IRUGO | S_IWUSR,
>> +     .ops = &debugfs_addr_single_ops,
>> +};
>
> DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()
>
>> +static ssize_t debugfs_show_addr_range(struct file *file,
>> +                                    char __user *user_buf,
>> +                                    size_t count, loff_t *ppos)
>> +{
>> +     int ret;
>> +     uint8_t idx;
>> +     unsigned long val1, val2;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     spin_lock(&drvdata->spinlock);
>> +     idx = drvdata->addr_idx;
>> +     if (idx % 2 != 0) {
>> +             spin_unlock(&drvdata->spinlock);
>> +             return -EPERM;
>
> -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;
>
> -EPERM?
>
>> +     }
>> +
>> +     val1 = drvdata->addr_val[idx];
>> +     val2 = drvdata->addr_val[idx + 1];
>> +     spin_unlock(&drvdata->spinlock);
>> +     ret = scnprintf(buf, PAGE_SIZE, "%#lx %#lx\n", val1, val2);
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +
>> +     kfree(buf);
>> +     return ret;
>> +}
>> +
>> +static ssize_t debugfs_store_addr_range(struct file *file,
>> +                                     const char __user *user_buf,
>> +                                     size_t count, loff_t *ppos)
>> +{
>> +     uint8_t idx;
>> +     unsigned long val1, val2;
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     if (sscanf(user_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;
>
> -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;
>
> -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 count;
>> +}
>> +
>> +static const struct file_operations debugfs_addr_range_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_show_addr_range,
>> +     .write = debugfs_store_addr_range,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_addr_range_entry = {
>> +     .name = "addr_range",
>> +     .mode =  S_IRUGO | S_IWUSR,
>> +     .ops = &debugfs_addr_range_ops,
>> +};
>
> DEFINE_SIMPLE_ATTRIBITE() and DEFINE_CORESIGHT_ENTRY()
>
> SNIP!!!
>
> My comments of debugfs get a bit samey from here on down so I've deleted
> a big chunk.
>
>
>> +static ssize_t debugfs_status_read(struct file *file, char __user *user_buf,
>> +                                size_t count, loff_t *ppos)
>> +{
>> +     ssize_t ret;
>> +     uint32_t val;
>> +     unsigned long flags;
>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +     struct etm_drvdata *drvdata = file->private_data;
>> +
>> +     if (!buf)
>> +             return -ENOMEM;
>> +
>> +     ret = clk_prepare_enable(drvdata->clk);
>> +     if (ret)
>> +             goto out;
>> +
>> +     spin_lock_irqsave(&drvdata->spinlock, flags);
>> +
>> +     ETM_UNLOCK(drvdata);
>> +     val = etm_readl(drvdata, ETMCCR);
>> +     ret += sprintf(buf, "ETMCCR: 0x%08x\n", val);
>> +     val = etm_readl(drvdata, ETMCCER);
>> +     ret += sprintf(buf + ret, "ETMCCER: 0x%08x\n", val);
>> +     val = etm_readl(drvdata, ETMSCR);
>> +     ret += sprintf(buf + ret, "ETMSCR: 0x%08x\n", val);
>> +     val = etm_readl(drvdata, ETMIDR);
>> +     ret += sprintf(buf + ret, "ETMIDR: 0x%08x\n", val);
>> +     val = etm_readl(drvdata, ETMCR);
>> +     ret += sprintf(buf + ret, "ETMCR: 0x%08x\n", val);
>> +     val = etm_readl(drvdata, ETMTEEVR);
>> +     ret += sprintf(buf + ret, "Enable event: 0x%08x\n", val);
>> +     val = etm_readl(drvdata, ETMTSSCR);
>> +     ret += sprintf(buf + ret, "Enable start/stop: 0x%08x\n", val);
>> +     ret += sprintf(buf + ret,
>> +                    "Enable control: CR1 0x%08x CR2 0x%08x\n",
>> +                    etm_readl(drvdata, ETMTECR1),
>> +                    etm_readl(drvdata, ETMTECR2));
>> +
>> +     ETM_LOCK(drvdata);
>> +
>> +     spin_unlock_irqrestore(&drvdata->spinlock, flags);
>> +     clk_disable_unprepare(drvdata->clk);
>> +
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>> +out:
>> +     kfree(buf);
>> +     return ret;
>> +}
>
> Really not sure whether this should be in the read method. If we don't
> read the file in one go the spin_lock() we'll not get a cohesive set of
> registers.

I get your point but since there is a possibility (even very remove)
that any of these registers can be changed between the two read
operations, the only reasonable solution I see is to return an error
if  (ret > size).  What your opinion on that?

>
>
>> +
>> +static const struct file_operations debugfs_status_ops = {
>> +     .open = simple_open,
>> +     .read = debugfs_status_read,
>> +};
>> +
>> +static const struct coresight_ops_entry debugfs_status_entry = {
>> +     .name = "status",
>> +     .mode =  S_IRUGO,
>> +     .ops = &debugfs_status_ops,
>> +};
>> +
>> +static const struct coresight_ops_entry *etm_attr_grps[] = {
>> +     &debugfs_nr_addr_cmp_entry,
>> +     &debugfs_nr_cntr_entry,
>> +     &debugfs_nr_ctxid_cmp_entry,
>> +     &debugfs_reset_entry,
>> +     &debugfs_mode_entry,
>> +     &debugfs_trigger_events_entry,
>> +     &debugfs_enable_events_entry,
>> +     &debugfs_fifofull_level_entry,
>> +     &debugfs_addr_idx_entry,
>> +     &debugfs_addr_single_entry,
>> +     &debugfs_addr_range_entry,
>> +     &debugfs_addr_start_entry,
>> +     &debugfs_addr_stop_entry,
>> +     &debugfs_addr_acctype_entry,
>> +     &debugfs_cntr_idx_entry,
>> +     &debugfs_cntr_rld_val_entry,
>> +     &debugfs_cntr_event_entry,
>> +     &debugfs_cntr_rld_event_entry,
>> +     &debugfs_cntr_val_entry,
>> +     &debugfs_12_event_entry,
>> +     &debugfs_21_event_entry,
>> +     &debugfs_23_event_entry,
>> +     &debugfs_31_event_entry,
>> +     &debugfs_32_event_entry,
>> +     &debugfs_13_event_entry,
>> +     &debugfs_seq_curr_state_entry,
>> +     &debugfs_ctxid_idx_entry,
>> +     &debugfs_ctxid_val_entry,
>> +     &debugfs_ctxid_mask_entry,
>> +     &debugfs_sync_freq_entry,
>> +     &debugfs_timestamp_event_entry,
>> +     &debugfs_status_entry,
>> +     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);
>> +             break;
>> +
>> +     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 etm_arch_supported(uint8_t arch)
>> +{
>> +     switch (arch) {
>> +     case ETM_ARCH_V3_3:
>> +             break;
>> +     case ETM_ARCH_V3_5:
>> +             break;
>> +     case PFT_ARCH_V1_1:
>> +             break;
>> +     default:
>> +             return false;
>> +     }
>> +     return true;
>> +}
>> +
>> +static void etm_init_arch_data(void *info)
>> +{
>> +     uint32_t etmidr;
>> +     uint32_t etmccr;
>> +     struct etm_drvdata *drvdata = info;
>> +
>> +     ETM_UNLOCK(drvdata);
>> +
>> +     /* first dummy read */
>> +     (void)etm_readl(drvdata, ETMPDSR);
>> +     /* Provide power to ETM: ETMPDCR[3] == 1 */
>> +     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);
>> +     /*
>> +      * 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);
>> +     drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
>> +
>> +     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_clr_pwrup(drvdata);
>> +     ETM_LOCK(drvdata);
>> +}
>> +
>> +static void etm_init_default_data(struct etm_drvdata *drvdata)
>> +{
>> +     int i;
>> +
>> +     uint32_t flags = (1 << 0 | /* instruction execute*/
>> +                       3 << 3 | /* ARM instruction */
>> +                       0 << 5 | /* No data value comparison */
>> +                       0 << 7 | /* No exact mach */
>> +                       0 << 8 | /* Ignore context ID */
>> +                       0 << 10); /* Security ignored */
>> +
>> +     drvdata->ctrl = (BIT(12) | /* cycle accurate */
>> +                      BIT(28)); /* timestamp */
>> +     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_acctype[0] = flags;
>> +             drvdata->addr_acctype[1] = flags;
>> +             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;
>> +}
>
> Ah... here's all those 0x406F I thought looked odd in the implementation
> of the reset attribute. This code should be commoned up as much as
> possible with the reset code.
>
> Also perhaps a #define to explain what 0x406F means?
>
>
>> +
>> +static int etm_probe(struct platform_device *pdev)
>> +{
>> +     int ret;
>> +     struct device *dev = &pdev->dev;
>> +     struct coresight_platform_data *pdata = NULL;
>> +     struct etm_drvdata *drvdata;
>> +     struct resource *res;
>> +     static int count;
>
> That "static" is very well concealed. I missed that until I started
> studying the error paths.
>
>> +     struct coresight_desc *desc;
>> +
>> +     drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
>> +     if (!drvdata)
>> +             return -ENOMEM;
>> +
>> +     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->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));
>
> Leak on error paths?

Yes definitely - I'll fix that.

>
>> +     if (!drvdata->base)
>> +             return -ENOMEM;
>> +
>> +     spin_lock_init(&drvdata->spinlock);
>> +
>> +     if (pdata && pdata->clk) {
>> +             drvdata->clk = pdata->clk;
>> +             ret = clk_prepare_enable(drvdata->clk);
>> +             if (ret)
>> +                     return ret;
>> +     }
>> +
>> +     drvdata->cpu = pdata ? pdata->cpu : 0;
>> +
>> +     get_online_cpus();
>> +     etmdrvdata[drvdata->cpu] = drvdata;
>> +
>> +     if (!smp_call_function_single(drvdata->cpu, etm_os_unlock, drvdata, 1))
>> +             drvdata->os_unlock = true;
>> +
>> +     if (smp_call_function_single(drvdata->cpu,
>> +                                  etm_init_arch_data,  drvdata, 1))
>> +             dev_err(dev, "ETM arch init failed\n");
>> +
>> +     if (!count++)
>
> count is mishandled on the error paths?

Humm... I see your point - if this is the ETM that registers the
notifier and "etm_arch_supported()" below fails, we have a dead
notifier.  I'll fix that.

>
>> +             register_hotcpu_notifier(&etm_cpu_notifier);
>
> Leak on (some of the) error paths?
>
>> +
>> +     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);
>
> Leak on error paths?
>
>> +     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->debugfs_ops = 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 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         = 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");
>>
>

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

* Re: [RFC PATCH 07/11] coresight: add CoreSight ETM driver
  2014-06-03 16:37     ` Mathieu Poirier
@ 2014-06-03 17:04       ` Daniel Thompson
  0 siblings, 0 replies; 23+ messages in thread
From: Daniel Thompson @ 2014-06-03 17:04 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Linus Walleij, Will Deacon, Arve Hjønnevåg,
	John Stultz, Pratik Patel, Vikas Varshney, Al Grant,
	Jonas Svennebring, James King, Panchaxari Prasannamurthy Tumkur,
	Arnd Bergmann, Marcin Jabrzyk, r.sengupta, Robert Marklund,
	Patch Tracking, Russell King - ARM Linux, linux-arm-kernel,
	linux-kernel

On 03/06/14 17:37, Mathieu Poirier wrote:
>>> +static ssize_t debugfs_status_read(struct file *file, char __user *user_buf,
>>> +                                size_t count, loff_t *ppos)
>>> +{
>>> +     ssize_t ret;
>>> +     uint32_t val;
>>> +     unsigned long flags;
>>> +     char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
>>> +     struct etm_drvdata *drvdata = file->private_data;
>>> +
>>> +     if (!buf)
>>> +             return -ENOMEM;
>>> +
>>> +     ret = clk_prepare_enable(drvdata->clk);
>>> +     if (ret)
>>> +             goto out;
>>> +
>>> +     spin_lock_irqsave(&drvdata->spinlock, flags);
>>> +
>>> +     ETM_UNLOCK(drvdata);
>>> +     val = etm_readl(drvdata, ETMCCR);
>>> +     ret += sprintf(buf, "ETMCCR: 0x%08x\n", val);
>>> +     val = etm_readl(drvdata, ETMCCER);
>>> +     ret += sprintf(buf + ret, "ETMCCER: 0x%08x\n", val);
>>> +     val = etm_readl(drvdata, ETMSCR);
>>> +     ret += sprintf(buf + ret, "ETMSCR: 0x%08x\n", val);
>>> +     val = etm_readl(drvdata, ETMIDR);
>>> +     ret += sprintf(buf + ret, "ETMIDR: 0x%08x\n", val);
>>> +     val = etm_readl(drvdata, ETMCR);
>>> +     ret += sprintf(buf + ret, "ETMCR: 0x%08x\n", val);
>>> +     val = etm_readl(drvdata, ETMTEEVR);
>>> +     ret += sprintf(buf + ret, "Enable event: 0x%08x\n", val);
>>> +     val = etm_readl(drvdata, ETMTSSCR);
>>> +     ret += sprintf(buf + ret, "Enable start/stop: 0x%08x\n", val);
>>> +     ret += sprintf(buf + ret,
>>> +                    "Enable control: CR1 0x%08x CR2 0x%08x\n",
>>> +                    etm_readl(drvdata, ETMTECR1),
>>> +                    etm_readl(drvdata, ETMTECR2));
>>> +
>>> +     ETM_LOCK(drvdata);
>>> +
>>> +     spin_unlock_irqrestore(&drvdata->spinlock, flags);
>>> +     clk_disable_unprepare(drvdata->clk);
>>> +
>>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>>> +out:
>>> +     kfree(buf);
>>> +     return ret;
>>> +}
>>
>> Really not sure whether this should be in the read method. If we don't
>> read the file in one go the spin_lock() we'll not get a cohesive set of
>> registers.
> 
> I get your point but since there is a possibility (even very remove)
> that any of these registers can be changed between the two read
> operations, the only reasonable solution I see is to return an error
> if  (ret > size).  What your opinion on that?

I'd prefer that we simply copy the approach used by simple_attr_read().


Daniel.

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

* Re: [RFC PATCH 02/11] coresight: add CoreSight TMC driver
  2014-06-03  9:09   ` Linus Walleij
@ 2014-06-16 23:12     ` Mathieu Poirier
  2014-07-07 10:53       ` Linus Walleij
  0 siblings, 1 reply; 23+ messages in thread
From: Mathieu Poirier @ 2014-06-16 23:12 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Will Deacon, Arve Hjønnevåg, John Stultz, Pratik Patel,
	Vikas Varshney, Al Grant, Jonas Svennebring, James King,
	Panchaxari Prasannamurthy Tumkur, Arnd Bergmann, Marcin Jabrzyk,
	r.sengupta, Robert Marklund, Patch Tracking,
	Russell King - ARM Linux, linux-arm-kernel, linux-kernel,
	Daniel Thompson

Thanks for the review - please see comments in-lined.

Mathieu

On 3 June 2014 03:09, Linus Walleij <linus.walleij@linaro.org> wrote:
> On Fri, May 30, 2014 at 3:43 PM,  <mathieu.poirier@linaro.org> wrote:
>
>> +#define tmc_writel(drvdata, val, off)  __raw_writel((val), drvdata->base + off)
>> +#define tmc_readl(drvdata, off)                __raw_readl(drvdata->base + off)
>
> Why not writel_relaxed()/readl_relaxed()?

Done.

>
> Using __raw* accessors seem a bit thick. (Applies to all such defines.)
>
>> +#define TMC_LOCK(drvdata)                                              \
>> +do {                                                                   \
>> +       /* settle everything first */                                   \
>> +       mb();                                                           \
>> +       tmc_writel(drvdata, 0x0, CORESIGHT_LAR);                        \
>> +} while (0)
>> +#define TMC_UNLOCK(drvdata)                                            \
>> +do {                                                                   \
>> +       tmc_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR);           \
>> +       /* make sure everyone sees this */                              \
>> +       mb();                                                           \
>> +} while (0)
>
> Convert these to static inlines. No need for them to be #defines
> at all really.

Done.

>
>> +#define BYTES_PER_WORD         4
>
> But please. Just using the number 4 everywhere is clear enough.
>
>> +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;
>
> Can this really be negative?

It is useful for debugging, as an example see "tmc_release()".  If the
count drops below '0' there is obviously a problem.  Do you see a cost
in keeping this as an 'int'?  What do you advise here?

>
>> +       bool                    reading;
>> +       char                    *buf;
>> +       dma_addr_t              paddr;
>> +       void __iomem            *vaddr;
>> +       uint32_t                size;
>
> Use u32
>
>> +       bool                    enable;
>> +       enum tmc_config_type    config_type;
>> +       uint32_t                trigger_cntr;
>
> Use u32
>
>> +};
>
> This struct overall could use some kerneldoc.

Would writing a comment for each field qualify?

>
>> +static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
>> +{
>> +       int count;
>
> Why not call this variable "i" as per convention.
>
>> +       uint32_t ffcr;
>
> u32
>
>> +
>> +       ffcr = tmc_readl(drvdata, TMC_FFCR);
>> +       ffcr |= BIT(12);
>> +       tmc_writel(drvdata, ffcr, TMC_FFCR);
>> +       ffcr |= BIT(6);
>
> A bit unclear what bit 12 and 6 does. Either #define them or add comments.
>
>> +       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);
>> +}
>
> I actually understand what bit 0 does in this register, but could
> also be #defined.
>
>> +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);
>
> 0x133? Que ce que c'est?
>
>> +       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;
>
> u32
>
>> +       /* 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);
>
> I don't understand these bits and shifts either.
>
>> +       tmc_writel(drvdata, drvdata->paddr, TMC_DBALO);
>> +       tmc_writel(drvdata, 0x0, TMC_DBAHI);
>> +       tmc_writel(drvdata, 0x133, TMC_FFCR);
>
> More magic...
>
>> +       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);
>
> More magic.
>
>> +       __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)
>
> I'm no fan of prefixing functions with __underscores and cannot see why
> this is done here even, just seems like force of habit. Please cut them.
> Rename the function slightly to correspond to what it does if it collides
> with another function.

Done.

>
>> +{
>> +       enum tmc_mem_intf_width memwidth;
>> +       uint8_t memwords;
>
> u8
>
>> +       char *bufp;
>> +       uint32_t read_data;
>
> u32
>
> (...)
>> +       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;
>
> Use 4 rather than BYTES_PER_WORD please.
>
> (...)
>> +static void __tmc_etr_dump(struct tmc_drvdata *drvdata)
>
> Cut __
>
>> +{
>> +       uint32_t rwp, rwphi;
>
> u32
>
>> +       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)
>
> Cut __
>
>> +{
>> +       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)
>
> Cut __
>
> (...)
>> +static int tmc_probe(struct platform_device *pdev)
>> +{
>> +       int ret = 0;
>> +       uint32_t devid;
>
> u32
>
>> +       struct device *dev = &pdev->dev;
>> +       struct coresight_platform_data *pdata = NULL;
>> +       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));
>
> Use devm_ioremap_resource() instead.

I'm working on it.

>
>> +       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->debugfs_ops = 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->debugfs_ops = 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->debugfs_ops = 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;
>> +               }
>> +       }
>
> Actually you set some stuff like desc->dev and pdata to the
> same thing in all three clauses... Do it before the if/else-ladder
> and cut the repititions.

Sure thing.

>
>> +       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);
>
> Miscdev really? Well, not that I know any better.
>
>> +static struct platform_driver tmc_driver = {
>> +       .probe          = tmc_probe,
>> +       .remove         = 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);
>
> Convert to use module_platform_driver()

Very well.

>
> I think these review comments apply to many of the patches,
> so please take each comment and iterate over the code.
>
> Yours,
> Linus Walleij

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

* Re: [RFC PATCH 02/11] coresight: add CoreSight TMC driver
  2014-06-16 23:12     ` Mathieu Poirier
@ 2014-07-07 10:53       ` Linus Walleij
  0 siblings, 0 replies; 23+ messages in thread
From: Linus Walleij @ 2014-07-07 10:53 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Will Deacon, Arve Hjønnevåg, John Stultz, Pratik Patel,
	Vikas Varshney, Al Grant, Jonas Svennebring, James King,
	Panchaxari Prasannamurthy Tumkur, Arnd Bergmann, Marcin Jabrzyk,
	r.sengupta, Robert Marklund, Patch Tracking,
	Russell King - ARM Linux, linux-arm-kernel, linux-kernel,
	Daniel Thompson

On Tue, Jun 17, 2014 at 1:12 AM, Mathieu Poirier
<mathieu.poirier@linaro.org> wrote:
> On 3 June 2014 03:09, Linus Walleij <linus.walleij@linaro.org> wrote:
>> On Fri, May 30, 2014 at 3:43 PM,  <mathieu.poirier@linaro.org> wrote:

>>> +       int                     read_count;
>>
>> Can this really be negative?
>
> It is useful for debugging, as an example see "tmc_release()".  If the
> count drops below '0' there is obviously a problem.  Do you see a cost
> in keeping this as an 'int'?  What do you advise here?

No big deal, keep it.

>> This struct overall could use some kerneldoc.
>
> Would writing a comment for each field qualify?

Like above the struct, see Documentation/kernel-doc-nano-HOWTO.txt

>>> +       drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
>>
>> Use devm_ioremap_resource() instead.
>
> I'm working on it.

Bet it's fininshed now ;-)

Yours,
Linus Walleij

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

end of thread, other threads:[~2014-07-07 10:53 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-30 13:43 [RFC PATCH 00/11] CoreSight framework and drivers mathieu.poirier
2014-05-30 13:43 ` [RFC PATCH 01/11] coresight: add CoreSight core layer framework mathieu.poirier
2014-05-30 17:25   ` Rob Herring
2014-05-30 18:02     ` Mathieu Poirier
2014-05-30 13:43 ` [RFC PATCH 02/11] coresight: add CoreSight TMC driver mathieu.poirier
2014-06-03  9:09   ` Linus Walleij
2014-06-16 23:12     ` Mathieu Poirier
2014-07-07 10:53       ` Linus Walleij
2014-05-30 13:43 ` [RFC PATCH 03/11] coresight: add CoreSight TPIU driver mathieu.poirier
2014-05-30 13:43 ` [RFC PATCH 04/11] coresight: add CoreSight ETB driver mathieu.poirier
2014-05-30 13:53   ` Russell King - ARM Linux
2014-05-30 16:28     ` Mathieu Poirier
2014-05-30 13:43 ` [RFC PATCH 05/11] coresight: add CoreSight Funnel driver mathieu.poirier
2014-05-30 13:43 ` [RFC PATCH 06/11] coresight: add CoreSight Replicator driver mathieu.poirier
2014-05-30 13:43 ` [RFC PATCH 07/11] coresight: add CoreSight ETM driver mathieu.poirier
2014-06-03 10:26   ` Daniel Thompson
2014-06-03 16:37     ` Mathieu Poirier
2014-06-03 17:04       ` Daniel Thompson
2014-05-30 13:43 ` [RFC PATCH 08/11] coresight: adding support for beagle board mathieu.poirier
2014-05-30 13:43 ` [RFC PATCH 09/11] coresight: adding basic support for Vexpress TC2 mathieu.poirier
2014-05-30 13:43 ` [RFC PATCH 10/11] coresight: adding support for beagleXM mathieu.poirier
2014-05-30 13:43 ` [RFC PATCH 11/11] ARM: moving support for etb/etm to the "drivers" directory mathieu.poirier
2014-05-30 13:49   ` Russell King - ARM Linux

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).