Index: sys/arm64/coresight/coresight.h
===================================================================
--- sys/arm64/coresight/coresight.h
+++ sys/arm64/coresight/coresight.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by SRI International and the University of
@@ -48,6 +48,8 @@
 #include 
 #endif
 
+#include 
+
 #define	CORESIGHT_ITCTRL	0xf00
 #define	CORESIGHT_CLAIMSET	0xfa0
 #define	CORESIGHT_CLAIMCLR	0xfa4
@@ -60,7 +62,8 @@
 
 enum cs_dev_type {
 	CORESIGHT_ETMV4,
-	CORESIGHT_TMC,
+	CORESIGHT_TMC_ETF,
+	CORESIGHT_TMC_ETR,
 	CORESIGHT_DYNAMIC_REPLICATOR,
 	CORESIGHT_FUNNEL,
 	CORESIGHT_CPU_DEBUG,
@@ -92,7 +95,7 @@
 	boolean_t input;
 	int reg;
 	struct coresight_device *cs_dev;
-	LIST_ENTRY(endpoint) endplink;
+	TAILQ_ENTRY(endpoint) endplink;
 };
 
 struct coresight_platform_data {
@@ -119,19 +122,20 @@
 };
 
 struct etr_state {
-	boolean_t started;
-	uint32_t cycle;
-	uint32_t offset;
 	uint32_t low;
 	uint32_t high;
 	uint32_t bufsize;
-	uint32_t flags;
-#define	ETR_FLAG_ALLOCATE	(1 << 0)
-#define	ETR_FLAG_RELEASE	(1 << 1)
+	vm_page_t *pages;
+	int npages;
+	int curpage;
+	vm_offset_t curpage_offset;
+
+	vm_page_t *pt_dir;
+	int npt;
 };
 
-struct coresight_event {
-	LIST_HEAD(, endpoint) endplist;
+struct coresight_pipeline {
+	TAILQ_HEAD(endplistname, endpoint) endplist;
 
 	uint64_t addr[ETM_N_COMPRATOR];
 	uint32_t naddr;
@@ -149,16 +153,36 @@
 	uint8_t excp_level;
 };
 
-static MALLOC_DEFINE(M_CORESIGHT, "coresight", "ARM Coresight");
+MALLOC_DECLARE(M_CORESIGHT);
 
 struct coresight_platform_data *coresight_fdt_get_platform_data(device_t dev);
+void coresight_fdt_release_platform_data(struct coresight_platform_data *pdata);
+
 struct coresight_platform_data *coresight_acpi_get_platform_data(device_t dev);
-struct endpoint * coresight_get_output_endpoint(struct coresight_platform_data *pdata);
-struct coresight_device * coresight_get_output_device(struct endpoint *endp, struct endpoint **);
+struct endpoint *
+    coresight_get_output_endpoint(struct coresight_platform_data *pdata);
+struct coresight_device *
+    coresight_get_output_device(struct coresight_device *cs_dev,
+    struct endpoint *endp, struct endpoint **);
 int coresight_register(struct coresight_desc *desc);
-int coresight_init_event(int cpu, struct coresight_event *event);
-void coresight_enable(int cpu, struct coresight_event *event);
-void coresight_disable(int cpu, struct coresight_event *event);
-void coresight_read(int cpu, struct coresight_event *event);
+
+int coresight_init_pipeline(struct coresight_pipeline *pipeline, int cpu);
+void coresight_deinit_pipeline(struct coresight_pipeline *pipeline);
+
+int coresight_setup(struct coresight_pipeline *pipeline);
+int coresight_configure(struct coresight_pipeline *pipeline,
+    struct hwt_context *ctx);
+void coresight_deconfigure(struct coresight_pipeline *pipeline);
+
+int coresight_start(struct coresight_pipeline *pipeline);
+void coresight_stop(struct coresight_pipeline *pipeline);
+
+void coresight_enable(struct coresight_pipeline *pipeline);
+void coresight_disable(struct coresight_pipeline *pipeline);
+
+int coresight_read(struct coresight_pipeline *pipeline);
+void coresight_dump(struct coresight_pipeline *pipeline);
+
+int coresight_unregister(device_t dev);
 
 #endif /* !_ARM64_CORESIGHT_CORESIGHT_H_ */
Index: sys/arm64/coresight/coresight.c
===================================================================
--- sys/arm64/coresight/coresight.c
+++ sys/arm64/coresight/coresight.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by SRI International and the University of
@@ -39,17 +39,279 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 
 #include 
 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define	CORESIGHT_DEBUG
+#undef CORESIGHT_DEBUG
+
+#ifdef CORESIGHT_DEBUG
+#define	dprintf(fmt, ...)	printf(fmt, ##__VA_ARGS__)
+#else
+#define	dprintf(fmt, ...)
+#endif
+
+MALLOC_DEFINE(M_CORESIGHT, "coresight", "ARM Coresight");
+
 static struct mtx cs_mtx;
 struct coresight_device_list cs_devs;
+static struct hwt_backend_ops coresight_ops;
+
+static struct hwt_backend backend = {
+		.ops = &coresight_ops,
+		.name = "coresight",
+};
+static struct coresight_pipeline cs_pipeline[MAXCPU];
+
+/*
+ * Example pipeline (SoC-dependent).
+ * https://people.freebsd.org/~br/coresight_diagram.png
+ */
+
+static int
+coresight_backend_init_thread(struct hwt_context *ctx)
+{
+	struct coresight_pipeline *pipeline;
+	struct hwt_thread *thr;
+	struct hwt_vm *vm;
+	int cpu_id;
+	int error;
+
+	/*
+	 * 1. Use buffer from the first thread as Funnel merges traces from
+	 * all CPUs to a single place.
+	 *
+	 * 2. Ctx was just allocated, so the lock is not really needed.
+	 */
+	HWT_CTX_LOCK(ctx);
+	thr = hwt_thread_first(ctx);
+	HWT_CTX_UNLOCK(ctx);
+
+	vm = thr->vm;
+
+	for (cpu_id = 0; cpu_id < mp_ncpus; cpu_id++) {
+		pipeline = &cs_pipeline[cpu_id];
+		memset(pipeline, 0, sizeof(struct coresight_pipeline));
+		pipeline->excp_level = 0;
+		pipeline->src = CORESIGHT_ETMV4;
+		pipeline->sink = CORESIGHT_TMC_ETR;
+
+		error = coresight_init_pipeline(pipeline, cpu_id);
+		if (error)
+			return (error);
+	}
+
+	/*
+	 * These methods are TMC-ETR only. We have single
+	 * TMC-ETR per system, so call them on first pipeline
+	 * only. The request will reach destination.
+	 */
+	pipeline = &cs_pipeline[0];
+	pipeline->etr.low = 0;
+	pipeline->etr.high = 0;
+	pipeline->etr.pages = vm->pages;
+	pipeline->etr.npages = vm->npages;
+	pipeline->etr.bufsize = vm->npages * PAGE_SIZE;
+
+	error = coresight_setup(pipeline);
+	if (error)
+		return (error);
+
+	error = coresight_start(pipeline);
+	if (error)
+		return (error);
+
+	return (0);
+}
+
+static int
+coresight_backend_init_cpu(struct hwt_context *ctx)
+{
+	struct coresight_pipeline *pipeline;
+	struct hwt_vm *vm;
+	int error;
+	int cpu_id;
+
+	CPU_FOREACH(cpu_id) {
+		pipeline = &cs_pipeline[cpu_id];
+		memset(pipeline, 0, sizeof(struct coresight_pipeline));
+
+		pipeline->excp_level = 1;
+		pipeline->src = CORESIGHT_ETMV4;
+		pipeline->sink = CORESIGHT_TMC_ETR;
+
+		error = coresight_init_pipeline(pipeline, cpu_id);
+		if (error)
+			return (error);
+	}
+
+	/*
+	 * The following is TMC (ETR) only, so pick vm from the first CPU.
+	 */
+	pipeline = &cs_pipeline[0];
+
+	HWT_CTX_LOCK(ctx);
+	vm = hwt_cpu_first(ctx)->vm;
+	HWT_CTX_UNLOCK(ctx);
+
+	/* TMC(ETR) configuration. */
+	pipeline->etr.low = 0;
+	pipeline->etr.high = 0;
+	pipeline->etr.pages = vm->pages;
+	pipeline->etr.npages = vm->npages;
+	pipeline->etr.bufsize = vm->npages * PAGE_SIZE;
+
+	error = coresight_setup(pipeline);
+	if (error)
+		return (error);
+
+	error = coresight_start(pipeline);
+	if (error)
+		return (error);
+
+	return (0);
+}
+
+static int
+coresight_backend_init(struct hwt_context *ctx)
+{
+	int error;
+
+	if (ctx->mode == HWT_MODE_THREAD)
+		error = coresight_backend_init_thread(ctx);
+	else
+		error = coresight_backend_init_cpu(ctx);
+
+	return (error);
+}
+
+static void
+coresight_backend_deinit(void)
+{
+	struct coresight_pipeline *pipeline;
+	int cpu_id;
+
+	for (cpu_id = 0; cpu_id < mp_ncpus; cpu_id++) {
+		pipeline = &cs_pipeline[cpu_id];
+		coresight_disable(pipeline);
+	}
+
+	/* Now as TMC-ETF buffers flushed, stop TMC-ETR. */
+	pipeline = &cs_pipeline[0];
+	coresight_stop(pipeline);
+
+	for (cpu_id = 0; cpu_id < mp_ncpus; cpu_id++) {
+		pipeline = &cs_pipeline[cpu_id];
+		coresight_deinit_pipeline(pipeline);
+	}
+}
+
+static int
+coresight_backend_configure(struct hwt_context *ctx, int cpu_id, int session_id)
+{
+	struct coresight_pipeline *pipeline;
+	int error;
+
+	pipeline = &cs_pipeline[cpu_id];
+
+	/*
+	 * OpenCSD needs a trace ID to distinguish trace sessions
+	 * as they are merged to a single buffer by using funnel
+	 * device.
+	 *
+	 * etmv4 session_id can't be 0.
+	 */
+	pipeline->etm.trace_id = session_id + 1;
+
+	error = coresight_configure(pipeline, ctx);
+
+	return (error);
+}
+
+static void
+coresight_backend_enable(int cpu_id)
+{
+	struct coresight_pipeline *pipeline;
+
+	pipeline = &cs_pipeline[cpu_id];
+
+	coresight_enable(pipeline);
+}
+
+static void
+coresight_backend_disable(int cpu_id)
+{
+	struct coresight_pipeline *pipeline;
+
+	pipeline = &cs_pipeline[cpu_id];
+
+	coresight_disable(pipeline);
+}
+
+static int
+coresight_backend_read(int cpu_id, int *curpage, vm_offset_t *curpage_offset)
+{
+	struct coresight_pipeline *pipeline;
+	int error;
+
+	/*
+	 * coresight_read() is TMC(ETR) only method. Also, we have a single
+	 * TMC(ETR) per system configured from pipeline 0. So read data from
+	 * pipeline 0.
+	 */
+
+	pipeline = &cs_pipeline[0];
+
+	KASSERT(pipeline != NULL, ("No pipeline found"));
+
+	error = coresight_read(pipeline);
+	if (error == 0) {
+		*curpage = pipeline->etr.curpage;
+		*curpage_offset = pipeline->etr.curpage_offset;
+	}
+
+	return (error);
+}
+
+static void
+coresight_backend_dump(int cpu_id)
+{
+	struct coresight_pipeline *pipeline;
+
+	pipeline = &cs_pipeline[cpu_id];
+
+	coresight_dump(pipeline);
+}
+
+static struct hwt_backend_ops coresight_ops = {
+	.hwt_backend_init = coresight_backend_init,
+	.hwt_backend_deinit = coresight_backend_deinit,
+
+	.hwt_backend_configure = coresight_backend_configure,
+
+	.hwt_backend_enable = coresight_backend_enable,
+	.hwt_backend_disable = coresight_backend_disable,
+
+	.hwt_backend_read = coresight_backend_read,
+	.hwt_backend_dump = coresight_backend_dump,
+};
 
 int
 coresight_register(struct coresight_desc *desc)
 {
 	struct coresight_device *cs_dev;
+	int error;
 
 	cs_dev = malloc(sizeof(struct coresight_device),
 	    M_CORESIGHT, M_WAITOK | M_ZERO);
@@ -57,6 +319,14 @@
 	cs_dev->pdata = desc->pdata;
 	cs_dev->dev_type = desc->dev_type;
 
+	if (desc->dev_type == CORESIGHT_TMC_ETR) {
+		error = hwt_backend_register(&backend);
+		if (error != 0) {
+			free(cs_dev, M_CORESIGHT);
+			return (error);
+		}
+	}
+
 	mtx_lock(&cs_mtx);
 	TAILQ_INSERT_TAIL(&cs_devs, cs_dev, link);
 	mtx_unlock(&cs_mtx);
@@ -64,6 +334,27 @@
 	return (0);
 }
 
+int
+coresight_unregister(device_t dev)
+{
+	struct coresight_device *cs_dev, *tmp;
+
+	mtx_lock(&cs_mtx);
+	TAILQ_FOREACH_SAFE(cs_dev, &cs_devs, link, tmp) {
+		if (cs_dev->dev == dev) {
+			TAILQ_REMOVE(&cs_devs, cs_dev, link);
+			mtx_unlock(&cs_mtx);
+			if (cs_dev->dev_type == CORESIGHT_TMC_ETR)
+				hwt_backend_unregister(&backend);
+			free(cs_dev, M_CORESIGHT);
+			return (0);
+		}
+	}
+	mtx_unlock(&cs_mtx);
+
+	return (ENOENT);
+}
+
 struct endpoint *
 coresight_get_output_endpoint(struct coresight_platform_data *pdata)
 {
@@ -81,7 +372,8 @@
 }
 
 struct coresight_device *
-coresight_get_output_device(struct endpoint *endp, struct endpoint **out_endp)
+coresight_get_output_device(struct coresight_device *cs_dev0,
+    struct endpoint *endp, struct endpoint **out_endp)
 {
 	struct coresight_platform_data *pdata;
 	struct coresight_device *cs_dev;
@@ -94,7 +386,11 @@
 			case CORESIGHT_BUS_FDT:
 #ifdef FDT
 				if (endp->their_node == endp2->my_node) {
-					*out_endp = endp2;
+					*out_endp =
+					    malloc(sizeof(struct endpoint),
+						M_CORESIGHT, M_WAITOK | M_ZERO);
+					memcpy(*out_endp, endp2,
+					    sizeof(struct endpoint));
 					return (cs_dev);
 				}
 #endif
@@ -103,7 +399,11 @@
 			case CORESIGHT_BUS_ACPI:
 #ifdef DEV_ACPI
 				if (endp->their_handle == endp2->my_handle) {
-					*out_endp = endp2;
+					*out_endp =
+					    malloc(sizeof(struct endpoint),
+						M_CORESIGHT, M_WAITOK | M_ZERO);
+					memcpy(*out_endp, endp2,
+					    sizeof(struct endpoint));
 					return (cs_dev);
 				}
 #endif
@@ -115,12 +415,31 @@
 	return (NULL);
 }
 
-static void
-coresight_init(void)
+static int
+coresight_modevent(module_t mod, int type, void *data)
 {
 
-	mtx_init(&cs_mtx, "ARM Coresight", NULL, MTX_DEF);
-	TAILQ_INIT(&cs_devs);
+	switch (type) {
+	case MOD_LOAD:
+		mtx_init(&cs_mtx, "ARM Coresight", NULL, MTX_DEF);
+		TAILQ_INIT(&cs_devs);
+		break;
+	case MOD_UNLOAD:
+		mtx_destroy(&cs_mtx);
+		break;
+	default:
+		break;
+	}
+ 
+        return (0);
 }
-
-SYSINIT(coresight, SI_SUB_DRIVERS, SI_ORDER_FIRST, coresight_init, NULL);
+ 
+static moduledata_t coresight_mod = {
+	"coresight",
+        coresight_modevent,
+        NULL
+};
+   
+DECLARE_MODULE(coresight, coresight_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_DEPEND(coresight, hwt, 1, 1, 1);
+MODULE_VERSION(coresight, 1);
Index: sys/arm64/coresight/coresight_cmd.c
===================================================================
--- sys/arm64/coresight/coresight_cmd.c
+++ sys/arm64/coresight/coresight_cmd.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by SRI International and the University of
@@ -47,22 +47,27 @@
 
 static struct coresight_device *
 coresight_next_device(struct coresight_device *cs_dev,
-    struct coresight_event *event)
+    struct coresight_pipeline *pipeline)
 {
 	struct coresight_device *out;
-	struct endpoint *out_endp;
+	struct endpoint *out_endp, *src_endp;
 	struct endpoint *endp;
 
 	TAILQ_FOREACH(endp, &cs_dev->pdata->endpoints, link) {
 		if (endp->input != 0)
 			continue;
 
-		out = coresight_get_output_device(endp, &out_endp);
+		out = coresight_get_output_device(cs_dev, endp, &out_endp);
 		if (out != NULL) {
-			if (LIST_EMPTY(&event->endplist)) {
+			if (TAILQ_EMPTY(&pipeline->endplist)) {
+
 				/* Add source device */
-				endp->cs_dev = cs_dev;
-				LIST_INSERT_HEAD(&event->endplist, endp,
+				src_endp = malloc(sizeof(struct endpoint),
+				    M_CORESIGHT, M_WAITOK | M_ZERO);
+				memcpy(src_endp, endp, sizeof(struct endpoint));
+
+				src_endp->cs_dev = cs_dev;
+				TAILQ_INSERT_TAIL(&pipeline->endplist, src_endp,
 				    endplink);
 			}
 
@@ -71,7 +76,8 @@
 				printf("Adding device %s to the chain\n",
 				    device_get_nameunit(out->dev));
 			out_endp->cs_dev = out;
-			LIST_INSERT_HEAD(&event->endplist, out_endp, endplink);
+			TAILQ_INSERT_TAIL(&pipeline->endplist, out_endp,
+			    endplink);
 
 			return (out);
 		}
@@ -81,30 +87,31 @@
 }
 
 static int
-coresight_build_list(struct coresight_device *cs_dev,
-    struct coresight_event *event)
+coresight_build_pipeline(struct coresight_device *cs_dev,
+    struct coresight_pipeline *pipeline)
 {
 	struct coresight_device *out;
 
 	out = cs_dev;
 	while (out != NULL)
-		out = coresight_next_device(out, event);
+		out = coresight_next_device(out, pipeline);
 
 	return (0);
 }
 
 int
-coresight_init_event(int cpu, struct coresight_event *event)
+coresight_init_pipeline(struct coresight_pipeline *pipeline, int cpu)
 {
 	struct coresight_device *cs_dev;
 	struct endpoint *endp;
+	int error;
 
 	/* Start building path from source device */
 	TAILQ_FOREACH(cs_dev, &cs_devs, link) {
-		if (cs_dev->dev_type == event->src &&
+		if (cs_dev->dev_type == pipeline->src &&
 		    cs_dev->pdata->cpu == cpu) {
-			LIST_INIT(&event->endplist);
-			coresight_build_list(cs_dev, event);
+			TAILQ_INIT(&pipeline->endplist);
+			coresight_build_pipeline(cs_dev, pipeline);
 			break;
 		}
 	}
@@ -112,48 +119,153 @@
 	/* Ensure Coresight is initialized for the CPU */
 	TAILQ_FOREACH(cs_dev, &cs_devs, link) {
 		if (cs_dev->dev_type == CORESIGHT_CPU_DEBUG &&
-		    cs_dev->pdata->cpu == cpu)
-			CORESIGHT_INIT(cs_dev->dev);
+		    cs_dev->pdata->cpu == cpu) {
+			error = CORESIGHT_INIT(cs_dev->dev);
+			if (error != ENXIO && error != 0)
+				return (error);
+		}
 	}
 
 	/* Init all devices in the path */
-	LIST_FOREACH(endp, &event->endplist, endplink) {
+	TAILQ_FOREACH(endp, &pipeline->endplist, endplink) {
 		cs_dev = endp->cs_dev;
-		CORESIGHT_INIT(cs_dev->dev);
+		error = CORESIGHT_INIT(cs_dev->dev);
+		if (error != ENXIO && error != 0)
+			return (error);
 	}
 
 	return (0);
 }
 
 void
-coresight_enable(int cpu, struct coresight_event *event)
+coresight_deinit_pipeline(struct coresight_pipeline *pipeline)
+{
+	struct coresight_device *cs_dev;
+	struct endpoint *endp, *tmp;
+
+	TAILQ_FOREACH_SAFE(endp, &pipeline->endplist, endplink, tmp) {
+		cs_dev = endp->cs_dev;
+		CORESIGHT_DEINIT(cs_dev->dev);
+
+		TAILQ_REMOVE(&pipeline->endplist, endp, endplink);
+		free(endp, M_CORESIGHT);
+	}
+}
+
+int
+coresight_setup(struct coresight_pipeline *pipeline)
 {
 	struct coresight_device *cs_dev;
 	struct endpoint *endp;
+	int error;
 
-	LIST_FOREACH(endp, &event->endplist, endplink) {
+	TAILQ_FOREACH(endp, &pipeline->endplist, endplink) {
 		cs_dev = endp->cs_dev;
-		CORESIGHT_ENABLE(cs_dev->dev, endp, event);
+		error = CORESIGHT_SETUP(cs_dev->dev, endp, pipeline);
+		if (error != ENXIO && error != 0)
+			return (error);
+	}
+
+	return (0);
+}
+
+int
+coresight_configure(struct coresight_pipeline *pipeline,
+    struct hwt_context *ctx)
+{
+	struct coresight_device *cs_dev;
+	struct endpoint *endp;
+	int error;
+
+	TAILQ_FOREACH(endp, &pipeline->endplist, endplink) {
+		cs_dev = endp->cs_dev;
+		error = CORESIGHT_CONFIGURE(cs_dev->dev, endp, pipeline, ctx);
+		if (error != ENXIO && error != 0)
+			return (error);
+	}
+
+	return (0);
+}
+
+int
+coresight_start(struct coresight_pipeline *pipeline)
+{
+	struct coresight_device *cs_dev;
+	struct endpoint *endp;
+	int error;
+
+	TAILQ_FOREACH_REVERSE(endp, &pipeline->endplist, endplistname,
+	    endplink) {
+		cs_dev = endp->cs_dev;
+		error = CORESIGHT_START(cs_dev->dev, endp, pipeline);
+		if (error != ENXIO && error != 0)
+			return (error);
+	}
+
+	return (0);
+}
+
+void
+coresight_stop(struct coresight_pipeline *pipeline)
+{
+	struct coresight_device *cs_dev;
+	struct endpoint *endp;
+
+	TAILQ_FOREACH(endp, &pipeline->endplist, endplink) {
+		cs_dev = endp->cs_dev;
+		CORESIGHT_STOP(cs_dev->dev, endp, pipeline);
+	}
+}
+
+void
+coresight_enable(struct coresight_pipeline *pipeline)
+{
+	struct coresight_device *cs_dev;
+	struct endpoint *endp;
+
+	TAILQ_FOREACH(endp, &pipeline->endplist, endplink) {
+		cs_dev = endp->cs_dev;
+		CORESIGHT_ENABLE(cs_dev->dev, endp, pipeline);
 	}
 }
 
 void
-coresight_disable(int cpu, struct coresight_event *event)
+coresight_disable(struct coresight_pipeline *pipeline)
 {
 	struct coresight_device *cs_dev;
 	struct endpoint *endp;
 
-	LIST_FOREACH(endp, &event->endplist, endplink) {
+	TAILQ_FOREACH(endp, &pipeline->endplist, endplink) {
 		cs_dev = endp->cs_dev;
-		CORESIGHT_DISABLE(cs_dev->dev, endp, event);
+		CORESIGHT_DISABLE(cs_dev->dev, endp, pipeline);
 	}
 }
 
 void
-coresight_read(int cpu, struct coresight_event *event)
+coresight_dump(struct coresight_pipeline *pipeline)
 {
+	struct coresight_device *cs_dev;
 	struct endpoint *endp;
 
-	LIST_FOREACH(endp, &event->endplist, endplink)
-		CORESIGHT_READ(endp->cs_dev->dev, endp, event);
+	TAILQ_FOREACH(endp, &pipeline->endplist, endplink) {
+		cs_dev = endp->cs_dev;
+		CORESIGHT_DUMP(cs_dev->dev);
+	}
+}
+
+int
+coresight_read(struct coresight_pipeline *pipeline)
+{
+	struct coresight_device *cs_dev;
+	struct endpoint *endp;
+	int error;
+
+	TAILQ_FOREACH(endp, &pipeline->endplist, endplink) {
+		cs_dev = endp->cs_dev;
+		error = CORESIGHT_READ(cs_dev->dev, endp, pipeline);
+		if (error != ENXIO && error != 0)
+			return (error);
+	}
+
+	return (0);
 }
Index: sys/arm64/coresight/coresight_cpu_debug.c
===================================================================
--- sys/arm64/coresight/coresight_cpu_debug.c
+++ sys/arm64/coresight/coresight_cpu_debug.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -79,6 +79,7 @@
 {
 	struct debug_softc *sc;
 	uint32_t reg;
+	int timeout;
 
 	sc = device_get_softc(dev);
 
@@ -97,9 +98,14 @@
 	reg |= EDPRCR_COREPURQ;
 	bus_write_4(sc->res, EDPRCR, reg);
 
+	timeout = 10000;
+
 	do {
 		reg = bus_read_4(sc->res, EDPRSR);
-	} while ((reg & EDPRCR_CORENPDRQ) == 0);
+	} while ((reg & EDPRCR_CORENPDRQ) == 0 && timeout--);
+
+	if (timeout <= 0)
+		return (EINTEGRITY);
 
 	return (0);
 }
@@ -141,10 +147,32 @@
 	return (0);
 }
 
+static int
+debug_detach(device_t dev)
+{
+	struct debug_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	error = coresight_unregister(dev);
+	if (error)
+		return (error);
+
+	coresight_fdt_release_platform_data(sc->pdata);
+
+	sc->pdata = NULL;
+
+	bus_release_resources(dev, debug_spec, &sc->res);
+
+	return (0);
+}
+
 static device_method_t debug_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		debug_probe),
 	DEVMETHOD(device_attach,	debug_attach),
+	DEVMETHOD(device_detach,	debug_detach),
 
 	/* Coresight interface */
 	DEVMETHOD(coresight_init,	debug_init),
@@ -152,11 +180,12 @@
 };
 
 static driver_t debug_driver = {
-	"debug",
+	"coresight_cpu_debug",
 	debug_methods,
 	sizeof(struct debug_softc),
 };
 
-EARLY_DRIVER_MODULE(debug, simplebus, debug_driver, 0, 0,
+EARLY_DRIVER_MODULE(coresight_cpu_debug, simplebus, debug_driver, 0, 0,
     BUS_PASS_BUS + BUS_PASS_ORDER_LATE);
-MODULE_VERSION(debug, 1);
+MODULE_VERSION(coresight_cpu_debug, 1);
+MODULE_DEPEND(coresight_cpu_debug, coresight, 1, 1, 1);
Index: sys/arm64/coresight/coresight_etm4x.h
===================================================================
--- sys/arm64/coresight/coresight_etm4x.h
+++ sys/arm64/coresight/coresight_etm4x.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -172,13 +172,76 @@
 #define	TRCPIDR567(n)		(0xFD4 + ((n) - 5) * 0x4) /*  Management Peripheral ID5 to Peripheral ID7 Registers */
 #define	TRCCIDR(n)		(0xFF0 + (n) * 0x4)	/* Management Component IDn Register [n=0-4] */
 
-DECLARE_CLASS(etm_driver);
+/* ETMv4 resources */
+#define ETM_MAX_NR_PE			8
+#define ETMv4_MAX_CNTR			4
+#define ETM_MAX_SEQ_STATES		4
+#define ETM_MAX_EXT_INP_SEL		4
+#define ETM_MAX_EXT_INP			256
+#define ETM_MAX_EXT_OUT			4
+#define ETM_MAX_SINGLE_ADDR_CMP		16
+#define ETM_MAX_ADDR_RANGE_CMP		(ETM_MAX_SINGLE_ADDR_CMP / 2)
+#define ETM_MAX_DATA_VAL_CMP		8
+#define ETMv4_MAX_CTXID_CMP		8
+#define ETM_MAX_VMID_CMP		8
+#define ETM_MAX_PE_CMP			8
+#define ETM_MAX_RES_SEL			32
+#define ETM_MAX_SS_CMP			8
+
+struct etmv4_config {
+	uint32_t		mode;
+	uint32_t		pe_sel;
+	uint32_t		cfg;
+	uint32_t		eventctrl0;
+	uint32_t		eventctrl1;
+	uint32_t		stall_ctrl;
+	uint32_t		ts_ctrl;
+	uint32_t		syncfreq;
+	uint32_t		ccctlr;
+	uint32_t		bb_ctrl;
+	uint32_t		vinst_ctrl;
+	uint32_t		viiectlr;
+	uint32_t		vissctlr;
+	uint32_t		vipcssctlr;
+	uint8_t			seq_idx;
+	uint32_t		seq_ctrl[ETM_MAX_SEQ_STATES];
+	uint32_t		seq_rst;
+	uint32_t		seq_state;
+	uint8_t			cntr_idx;
+	uint32_t		cntrldvr[ETMv4_MAX_CNTR];
+	uint32_t		cntr_ctrl[ETMv4_MAX_CNTR];
+	uint32_t		cntr_val[ETMv4_MAX_CNTR];
+	uint8_t			res_idx;
+	uint32_t		res_ctrl[ETM_MAX_RES_SEL];
+	uint8_t			ss_idx;
+	uint32_t		ss_ctrl[ETM_MAX_SS_CMP];
+	uint32_t		ss_status[ETM_MAX_SS_CMP];
+	uint32_t		ss_pe_cmp[ETM_MAX_SS_CMP];
+	uint8_t			addr_idx;
+	uint64_t		addr_val[ETM_MAX_SINGLE_ADDR_CMP];
+	uint64_t		addr_acc[ETM_MAX_SINGLE_ADDR_CMP];
+	uint8_t			addr_type[ETM_MAX_SINGLE_ADDR_CMP];
+	uint8_t			ctxid_idx;
+	uint64_t		ctxid_pid[ETMv4_MAX_CTXID_CMP];
+	uint32_t		ctxid_mask0;
+	uint32_t		ctxid_mask1;
+	uint8_t			vmid_idx;
+	uint64_t		vmid_val[ETM_MAX_VMID_CMP];
+	uint32_t		vmid_mask0;
+	uint32_t		vmid_mask1;
+	uint32_t		ext_inp;
+	uint8_t			s_ex_level;
+};
 
 struct etm_softc {
 	struct resource			*res;
 	struct coresight_platform_data	*pdata;
+	uint32_t id_regs[14];
 };
 
 int etm_attach(device_t dev);
+int etm_detach(device_t dev);
+
+DECLARE_CLASS(coresight_etm4x_driver);
 
 #endif /* !_ARM64_CORESIGHT_ETM4X_H_ */
Index: sys/arm64/coresight/coresight_etm4x.c
===================================================================
--- sys/arm64/coresight/coresight_etm4x.c
+++ sys/arm64/coresight/coresight_etm4x.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -43,6 +43,8 @@
 #include 
 #include 
 
+#include 
+
 #include "coresight_if.h"
 
 #define	ETM_DEBUG
@@ -69,12 +71,97 @@
 };
 
 static int
-etm_prepare(device_t dev, struct coresight_event *event)
+etm_configure_etmv4(device_t dev, struct etmv4_config *config)
+{
+	struct etm_softc *sc;
+	int cpu;
+	int i;
+
+	sc = device_get_softc(dev);
+
+	cpu = PCPU_GET(cpuid);
+
+	dprintf("%s_%d\n", __func__, device_get_unit(dev));
+
+	bus_write_4(sc->res, TRCCONFIGR, config->cfg);
+	bus_write_4(sc->res, TRCEVENTCTL0R, config->eventctrl0);
+	bus_write_4(sc->res, TRCEVENTCTL1R, config->eventctrl1);
+	bus_write_4(sc->res, TRCSTALLCTLR, config->stall_ctrl);
+	bus_write_4(sc->res, TRCTSCTLR, config->ts_ctrl);
+	bus_write_4(sc->res, TRCSYNCPR, config->syncfreq);
+	bus_write_4(sc->res, TRCVICTLR, config->vinst_ctrl);
+	bus_write_4(sc->res, TRCPROCSELR, cpu); /* Not sure if this is needed.*/
+
+	/* Address-range filtering. */
+	for (i = 0; i < ETM_MAX_SINGLE_ADDR_CMP; i++) {
+		bus_write_8(sc->res, TRCACVR(i), config->addr_val[i]);
+		bus_write_8(sc->res, TRCACATR(i), config->addr_acc[i]);
+	}
+	bus_write_4(sc->res, TRCVIIECTLR, config->viiectlr);
+
+	bus_write_4(sc->res, TRCVDARCCTLR, 0);
+	bus_write_4(sc->res, TRCSSCSR(0), 0);
+	bus_write_4(sc->res, TRCVISSCTLR, config->vissctlr);
+	bus_write_4(sc->res, TRCVDCTLR, 0);
+	bus_write_4(sc->res, TRCVDSACCTLR, 0);
+
+#if 0
+        uint32_t                mode;
+        uint32_t                pe_sel;
+        uint32_t                cfg;
+        uint32_t                eventctrl0;
+        uint32_t                eventctrl1;
+        uint32_t                stall_ctrl;
+        uint32_t                ts_ctrl;
+        uint32_t                syncfreq;
+        uint32_t                ccctlr;
+        uint32_t                bb_ctrl;
+        uint32_t                vinst_ctrl;
+        uint32_t                viiectlr;
+        uint32_t                vissctlr;
+        uint32_t                vipcssctlr;
+        uint8_t                 seq_idx;
+        uint32_t                seq_ctrl[ETM_MAX_SEQ_STATES];
+        uint32_t                seq_rst;
+        uint32_t                seq_state;
+        uint8_t                 cntr_idx;
+        uint32_t                cntrldvr[ETMv4_MAX_CNTR];
+        uint32_t                cntr_ctrl[ETMv4_MAX_CNTR];
+        uint32_t                cntr_val[ETMv4_MAX_CNTR];
+        uint8_t                 res_idx;
+        uint32_t                res_ctrl[ETM_MAX_RES_SEL];
+        uint8_t                 ss_idx;
+        uint32_t                ss_ctrl[ETM_MAX_SS_CMP];
+        uint32_t                ss_status[ETM_MAX_SS_CMP];
+        uint32_t                ss_pe_cmp[ETM_MAX_SS_CMP];
+        uint8_t                 addr_idx;
+        uint64_t                addr_val[ETM_MAX_SINGLE_ADDR_CMP];
+        uint64_t                addr_acc[ETM_MAX_SINGLE_ADDR_CMP];
+        uint8_t                 addr_type[ETM_MAX_SINGLE_ADDR_CMP];
+        uint8_t                 ctxid_idx;
+        uint64_t                ctxid_pid[ETMv4_MAX_CTXID_CMP];
+        uint32_t                ctxid_mask0;
+        uint32_t                ctxid_mask1;
+        uint8_t                 vmid_idx;
+        uint64_t                vmid_val[ETM_MAX_VMID_CMP];
+        uint32_t                vmid_mask0;
+        uint32_t                vmid_mask1;
+        uint32_t                ext_inp; 
+        uint8_t                 s_ex_level;
+#endif
+
+	return (0);
+}
+
+static int
+etm_configure_etmv4_default(device_t dev, struct coresight_pipeline *pipeline)
 {
 	struct etm_softc *sc;
 	uint32_t reg;
 	int i;
 
+	dprintf("%s%d\n", __func__, device_get_unit(dev));
+
 	sc = device_get_softc(dev);
 
 	/* Configure ETM */
@@ -88,6 +175,7 @@
 	reg |= TRCCONFIGR_INSTP0_LDRSTR;
 	reg |= TRCCONFIGR_COND_ALL;
 	bus_write_4(sc->res, TRCCONFIGR, reg);
+	dprintf("%s: TRCCONFIGR is %x\n", __func__, reg);
 
 	/* Disable all event tracing. */
 	bus_write_4(sc->res, TRCEVENTCTL0R, 0);
@@ -99,8 +187,10 @@
 	/* Enable trace synchronization every 4096 bytes of trace. */
 	bus_write_4(sc->res, TRCSYNCPR, TRCSYNCPR_4K);
 
-	/* Set a value for the trace ID */
-	bus_write_4(sc->res, TRCTRACEIDR, event->etm.trace_id);
+	dprintf("%s: IDR0 is %x\n", __func__, bus_read_4(sc->res, TRCIDR(0)));
+	dprintf("%s: IDR1 is %x\n", __func__, bus_read_4(sc->res, TRCIDR(1)));
+	dprintf("%s: IDR2 is %x\n", __func__, bus_read_4(sc->res, TRCIDR(2)));
+	dprintf("%s: IDR8 is %x\n", __func__, bus_read_4(sc->res, TRCIDR(8)));
 
 	/*
 	 * Disable the timestamp event. The trace unit still generates
@@ -117,27 +207,27 @@
 	/* The number of the single resource used to activate the event. */
 	reg |= (1 << EVENT_SEL_S);
 
-	if (event->excp_level > 2)
+	if (pipeline->excp_level > 2)
 		return (-1);
 
 	reg |= TRCVICTLR_EXLEVEL_NS_M;
-	reg &= ~TRCVICTLR_EXLEVEL_NS(event->excp_level);
+	reg &= ~TRCVICTLR_EXLEVEL_NS(pipeline->excp_level);
 	reg |= TRCVICTLR_EXLEVEL_S_M;
-	reg &= ~TRCVICTLR_EXLEVEL_S(event->excp_level);
+	reg &= ~TRCVICTLR_EXLEVEL_S(pipeline->excp_level);
 	bus_write_4(sc->res, TRCVICTLR, reg);
 
-	for (i = 0; i < event->naddr * 2; i++) {
+	for (i = 0; i < pipeline->naddr * 2; i++) {
 		dprintf("configure range %d, address %lx\n",
-		    i, event->addr[i]);
-		bus_write_8(sc->res, TRCACVR(i), event->addr[i]);
+		    i, pipeline->addr[i]);
+		bus_write_8(sc->res, TRCACVR(i), pipeline->addr[i]);
 
 		reg = 0;
 		/* Secure state */
 		reg |= TRCACATR_EXLEVEL_S_M;
-		reg &= ~TRCACATR_EXLEVEL_S(event->excp_level);
+		reg &= ~TRCACATR_EXLEVEL_S(pipeline->excp_level);
 		/* Non-secure state */
 		reg |= TRCACATR_EXLEVEL_NS_M;
-		reg &= ~TRCACATR_EXLEVEL_NS(event->excp_level);
+		reg &= ~TRCACATR_EXLEVEL_NS(pipeline->excp_level);
 		bus_write_4(sc->res, TRCACATR(i), reg);
 
 		/* Address range is included */
@@ -152,7 +242,7 @@
 	/* Clear the STATUS bit to zero */
 	bus_write_4(sc->res, TRCSSCSR(0), 0);
 
-	if (event->naddr == 0) {
+	if (pipeline->naddr == 0) {
 		/* No address range filtering for ViewInst. */
 		bus_write_4(sc->res, TRCVIIECTLR, 0);
 	}
@@ -169,6 +259,26 @@
 	return (0);
 }
 
+static int
+etm_configure(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline, struct hwt_context *ctx)
+{
+	struct etmv4_config *config;
+	int error;
+
+	dprintf("%s%d\n", __func__, device_get_unit(dev));
+
+	if (ctx->config &&
+	    ctx->config_size == sizeof(struct etmv4_config) &&
+	    ctx->config_version == 1) {
+		config = (struct etmv4_config *)ctx->config;
+		error = etm_configure_etmv4(dev, config);
+	} else
+		error = etm_configure_etmv4_default(dev, pipeline);
+
+	return (error);
+}
+
 static int
 etm_init(device_t dev)
 {
@@ -177,6 +287,8 @@
 
 	sc = device_get_softc(dev);
 
+	dprintf("%s%d\n", __func__, device_get_unit(dev));
+
 	/* Unlocking Coresight */
 	bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK);
 
@@ -193,40 +305,53 @@
 
 static int
 etm_enable(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+    struct coresight_pipeline *pipeline)
 {
 	struct etm_softc *sc;
 	uint32_t reg;
 
 	sc = device_get_softc(dev);
 
-	etm_prepare(dev, event);
+	dprintf("%s%d\n", __func__, device_get_unit(dev));
+
+	/* Set a value for the trace ID */
+	bus_write_4(sc->res, TRCTRACEIDR, pipeline->etm.trace_id);
 
 	/* Enable the trace unit */
-	bus_write_4(sc->res, TRCPRGCTLR, TRCPRGCTLR_EN);
+	reg = bus_read_4(sc->res, TRCPRGCTLR);
+	reg |= TRCPRGCTLR_EN;
+	bus_write_4(sc->res, TRCPRGCTLR, reg);
 
 	/* Wait for an IDLE bit to be LOW */
+
+	/* TODO: add timeout */
 	do {
 		reg = bus_read_4(sc->res, TRCSTATR);
-	} while ((reg & TRCSTATR_IDLE) == 1);
+	} while (reg & TRCSTATR_IDLE);
 
-	if ((bus_read_4(sc->res, TRCPRGCTLR) & TRCPRGCTLR_EN) == 0)
-		panic("etm is not enabled\n");
+	if ((bus_read_4(sc->res, TRCPRGCTLR) & TRCPRGCTLR_EN) == 0) {
+		printf("%s: etm is not enabled\n", __func__);
+		return (ENXIO);
+	}
 
 	return (0);
 }
 
 static void
 etm_disable(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+    struct coresight_pipeline *pipeline)
 {
 	struct etm_softc *sc;
 	uint32_t reg;
 
 	sc = device_get_softc(dev);
 
+	dprintf("%s%d\n", __func__, device_get_unit(dev));
+
 	/* Disable the trace unit */
-	bus_write_4(sc->res, TRCPRGCTLR, 0);
+	reg = bus_read_4(sc->res, TRCPRGCTLR);
+	reg &= ~TRCPRGCTLR_EN;
+	bus_write_4(sc->res, TRCPRGCTLR, reg);
 
 	/* Wait for an IDLE bit */
 	do {
@@ -239,6 +364,8 @@
 {
 	struct coresight_desc desc;
 	struct etm_softc *sc;
+	char name[16];
+	int i;
 
 	sc = device_get_softc(dev);
 
@@ -252,15 +379,43 @@
 	desc.dev_type = CORESIGHT_ETMV4;
 	coresight_register(&desc);
 
+	for (i = 0; i < 14; i++) {
+		snprintf(name, 16, "idr%d", i);
+		sc->id_regs[i] = bus_read_4(sc->res, TRCIDR(i));
+		SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+		    OID_AUTO, name, CTLFLAG_RD,
+		    &sc->id_regs[i], 0, "id register");
+	}
+
+	return (0);
+}
+
+int
+etm_detach(device_t dev)
+{
+	struct etm_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+ 
+	error = coresight_unregister(dev);
+	if (error)
+		return (error);
+
+	bus_release_resources(dev, etm_spec, &sc->res);
+
 	return (0);
 }
 
 static device_method_t etm_methods[] = {
 	/* Coresight interface */
 	DEVMETHOD(coresight_init,	etm_init),
+	DEVMETHOD(coresight_configure,	etm_configure),
 	DEVMETHOD(coresight_enable,	etm_enable),
 	DEVMETHOD(coresight_disable,	etm_disable),
 	DEVMETHOD_END
 };
 
-DEFINE_CLASS_0(etm, etm_driver, etm_methods, sizeof(struct etm_softc));
+DEFINE_CLASS_0(coresight_etm4x, coresight_etm4x_driver, etm_methods,
+    sizeof(struct etm_softc));
Index: sys/arm64/coresight/coresight_etm4x_fdt.c
===================================================================
--- sys/arm64/coresight/coresight_etm4x_fdt.c
+++ sys/arm64/coresight/coresight_etm4x_fdt.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -78,15 +78,32 @@
 	return (etm_attach(dev));
 }
 
+static int
+etm_fdt_detach(device_t dev)
+{
+	struct etm_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	coresight_fdt_release_platform_data(sc->pdata);
+
+	sc->pdata = NULL;
+
+	return (etm_detach(dev));
+}
+
 static device_method_t etm_fdt_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		etm_fdt_probe),
 	DEVMETHOD(device_attach,	etm_fdt_attach),
+	DEVMETHOD(device_detach,	etm_fdt_detach),
 	DEVMETHOD_END
 };
 
-DEFINE_CLASS_1(etm, etm_fdt_driver, etm_fdt_methods,
-    sizeof(struct etm_softc), etm_driver);
+DEFINE_CLASS_1(coresight_etm4x, coresight_etm4x_fdt_driver, etm_fdt_methods,
+    sizeof(struct etm_softc), coresight_etm4x_driver);
 
-EARLY_DRIVER_MODULE(etm, simplebus, etm_fdt_driver, 0, 0,
-    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(coresight_etm4x, simplebus, coresight_etm4x_fdt_driver,
+    0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+MODULE_DEPEND(coresight_etm4x, coresight, 1, 1, 1);
+MODULE_VERSION(coresight_etm4x, 1);
Index: sys/arm64/coresight/coresight_fdt.c
===================================================================
--- sys/arm64/coresight/coresight_fdt.c
+++ sys/arm64/coresight/coresight_fdt.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by SRI International and the University of
@@ -39,6 +39,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -47,10 +48,10 @@
 #include 
 
 static int
-coresight_fdt_get_ports(phandle_t dev_node,
-    struct coresight_platform_data *pdata)
+coresight_fdt_get_ports(phandle_t dev_node, phandle_t node,
+    struct coresight_platform_data *pdata, bool input)
 {
-	phandle_t node, child;
+	phandle_t child;
 	pcell_t port_reg;
 	phandle_t xref;
 	char *name;
@@ -58,12 +59,6 @@
 	phandle_t endpoint_child;
 	struct endpoint *endp;
 
-	child = ofw_bus_find_child(dev_node, "ports");
-	if (child)
-		node = child;
-	else
-		node = dev_node;
-
 	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
 		ret = OF_getprop_alloc(child, "name", (void **)&name);
 		if (ret == -1)
@@ -89,8 +84,8 @@
 				endp->their_node = OF_node_from_xref(xref);
 				endp->dev_node = dev_node;
 				endp->reg = port_reg;
-				if (OF_getproplen(endpoint_child,
-				    "slave-mode") >= 0) {
+
+				if (input) {
 					pdata->in_ports++;
 					endp->input = 1;
 				} else
@@ -108,19 +103,28 @@
 }
 
 static int
-coresight_fdt_get_cpu(phandle_t node,
-    struct coresight_platform_data *pdata)
+coresight_fdt_get_cpu(phandle_t node, struct coresight_platform_data *pdata)
 {
+	struct pcpu *pcpu;
 	phandle_t cpu_node;
 	pcell_t xref;
-	pcell_t cpu_reg;
+	pcell_t cpu_reg[2];
+	uint64_t mpidr;
+	int i;
 
 	if (OF_getencprop(node, "cpu", &xref, sizeof(xref)) != -1) {
 		cpu_node = OF_node_from_xref(xref);
 		if (OF_getencprop(cpu_node, "reg", (void *)&cpu_reg,
-			sizeof(cpu_reg)) > 0) {
-			pdata->cpu = cpu_reg;
-			return (0);
+		    sizeof(cpu_reg)) > 0) {
+			mpidr = cpu_reg[1];
+			mpidr |= ((uint64_t)cpu_reg[0] << 32);
+			for (i = 0; i < mp_ncpus; i++) {
+				pcpu = cpuid_to_pcpu[i];
+				if (pcpu->pc_mpidr == mpidr) {
+					pdata->cpu = pcpu->pc_cpuid;
+					return (0);
+				}
+			}
 		}
 	}
 
@@ -131,7 +135,7 @@
 coresight_fdt_get_platform_data(device_t dev)
 {
 	struct coresight_platform_data *pdata;
-	phandle_t node;
+	phandle_t node, child;
 
 	node = ofw_bus_get_node(dev);
 
@@ -143,7 +147,14 @@
 	TAILQ_INIT(&pdata->endpoints);
 
 	coresight_fdt_get_cpu(node, pdata);
-	coresight_fdt_get_ports(node, pdata);
+
+	child = ofw_bus_find_child(node, "in-ports");
+	if (child)
+		coresight_fdt_get_ports(node, child, pdata, true);
+
+	child = ofw_bus_find_child(node, "out-ports");
+	if (child)
+		coresight_fdt_get_ports(node, child, pdata, false);
 
 	if (bootverbose)
 		printf("Total ports: in %d out %d\n",
@@ -151,3 +162,16 @@
 
 	return (pdata);
 }
+
+void
+coresight_fdt_release_platform_data(struct coresight_platform_data *pdata)
+{
+	struct endpoint *endp, *tmp;
+
+	TAILQ_FOREACH_SAFE(endp, &pdata->endpoints, link, tmp) {
+		TAILQ_REMOVE(&pdata->endpoints, endp, link);
+		free(endp, M_CORESIGHT);
+	}
+
+	free(pdata, M_CORESIGHT);
+}
Index: sys/arm64/coresight/coresight_funnel.h
===================================================================
--- sys/arm64/coresight/coresight_funnel.h
+++ sys/arm64/coresight/coresight_funnel.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -67,7 +67,7 @@
 #define	HWTYPE_FUNNEL		1
 #define	HWTYPE_STATIC_FUNNEL	2
 
-DECLARE_CLASS(funnel_driver);
+DECLARE_CLASS(coresight_funnel_driver);
 
 struct funnel_softc {
 	struct resource			*res;
@@ -76,5 +76,6 @@
 };
 
 int funnel_attach(device_t dev);
+int funnel_detach(device_t dev);
 
 #endif /* !_ARM64_CORESIGHT_CORESIGHT_FUNNEL_H_ */
Index: sys/arm64/coresight/coresight_funnel.c
===================================================================
--- sys/arm64/coresight/coresight_funnel.c
+++ sys/arm64/coresight/coresight_funnel.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -76,8 +76,8 @@
 }
 
 static int
-funnel_enable(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+funnel_configure(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline, struct hwt_context *ctx)
 {
 	struct funnel_softc *sc;
 	uint32_t reg;
@@ -96,8 +96,8 @@
 }
 
 static void
-funnel_disable(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+funnel_deconfigure(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline)
 {
 	struct funnel_softc *sc;
 	uint32_t reg;
@@ -132,13 +132,30 @@
 	return (0);
 }
 
+int
+funnel_detach(device_t dev)
+{
+	struct funnel_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+ 
+	error = coresight_unregister(dev);
+	if (error)
+		return (error);
+
+	bus_release_resources(dev, funnel_spec, &sc->res);
+
+	return (0);
+}
+
 static device_method_t funnel_methods[] = {
 	/* Coresight interface */
 	DEVMETHOD(coresight_init,	funnel_init),
-	DEVMETHOD(coresight_enable,	funnel_enable),
-	DEVMETHOD(coresight_disable,	funnel_disable),
+	DEVMETHOD(coresight_configure,	funnel_configure),
+	DEVMETHOD(coresight_deconfigure,funnel_deconfigure),
 	DEVMETHOD_END
 };
 
-DEFINE_CLASS_0(funnel, funnel_driver, funnel_methods,
+DEFINE_CLASS_0(coresight_funnel, coresight_funnel_driver, funnel_methods,
     sizeof(struct funnel_softc));
Index: sys/arm64/coresight/coresight_funnel_fdt.c
===================================================================
--- sys/arm64/coresight/coresight_funnel_fdt.c
+++ sys/arm64/coresight/coresight_funnel_fdt.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -49,7 +49,7 @@
 #include "coresight_if.h"
 
 static struct ofw_compat_data compat_data[] = {
-	{ "arm,coresight-funnel",		HWTYPE_FUNNEL },
+	{ "arm,coresight-dynamic-funnel",	HWTYPE_FUNNEL },
 	{ "arm,coresight-static-funnel",	HWTYPE_STATIC_FUNNEL },
 	{ NULL,					HWTYPE_NONE }
 };
@@ -90,15 +90,32 @@
 	return (funnel_attach(dev));
 }
 
+static int
+funnel_fdt_detach(device_t dev)
+{
+	struct funnel_softc *sc;
+
+	sc = device_get_softc(dev);
+	coresight_fdt_release_platform_data(sc->pdata);
+
+	sc->pdata = NULL;
+
+	return (funnel_detach(dev));
+}
+
 static device_method_t funnel_fdt_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		funnel_fdt_probe),
 	DEVMETHOD(device_attach,	funnel_fdt_attach),
+	DEVMETHOD(device_detach,	funnel_fdt_detach),
 	DEVMETHOD_END
 };
 
-DEFINE_CLASS_1(funnel, funnel_fdt_driver, funnel_fdt_methods,
-    sizeof(struct funnel_softc), funnel_driver);
+DEFINE_CLASS_1(coresight_funnel, coresight_funnel_fdt_driver,
+    funnel_fdt_methods, sizeof(struct funnel_softc),
+    coresight_funnel_driver);
 
-EARLY_DRIVER_MODULE(funnel, simplebus, funnel_fdt_driver, 0, 0,
-    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(coresight_funnel, simplebus, coresight_funnel_fdt_driver,
+    0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+MODULE_DEPEND(coresight_funnel, coresight, 1, 1, 1);
+MODULE_VERSION(coresight_funnel, 1);
Index: sys/arm64/coresight/coresight_if.m
===================================================================
--- sys/arm64/coresight/coresight_if.m
+++ sys/arm64/coresight/coresight_if.m
@@ -1,5 +1,5 @@
 #-
-# Copyright (c) 2018 Ruslan Bukin 
+# Copyright (c) 2018-2023 Ruslan Bukin 
 # All rights reserved.
 #
 # This software was developed by SRI International and the University of
@@ -39,20 +39,59 @@
 	device_t dev;
 };
 
+METHOD int deinit {
+	device_t dev;
+};
+
+METHOD int setup {
+	device_t dev;
+	struct endpoint *endp;
+	struct coresight_pipeline *pipeline;
+};
+
+METHOD int configure {
+	device_t dev;
+	struct endpoint *endp;
+	struct coresight_pipeline *pipeline;
+	struct hwt_context *ctx;
+};
+
+METHOD void deconfigure {
+	device_t dev;
+	struct endpoint *endp;
+	struct coresight_pipeline *pipeline;
+};
+
+METHOD int start {
+	device_t dev;
+	struct endpoint *endp;
+	struct coresight_pipeline *pipeline;
+};
+
+METHOD void stop {
+	device_t dev;
+	struct endpoint *endp;
+	struct coresight_pipeline *pipeline;
+}
+
 METHOD int enable {
 	device_t dev;
 	struct endpoint *endp;
-	struct coresight_event *event;
+	struct coresight_pipeline *pipeline;
 };
 
 METHOD void disable {
 	device_t dev;
 	struct endpoint *endp;
-	struct coresight_event *event;
+	struct coresight_pipeline *pipeline;
+};
+
+METHOD void dump {
+	device_t dev;
 };
 
 METHOD int read {
 	device_t dev;
 	struct endpoint *endp;
-	struct coresight_event *event;
+	struct coresight_pipeline *pipeline;
 };
Index: sys/arm64/coresight/coresight_replicator.h
===================================================================
--- sys/arm64/coresight/coresight_replicator.h
+++ sys/arm64/coresight/coresight_replicator.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2020 Ruslan Bukin 
+ * Copyright (c) 2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by SRI International and the University of
@@ -36,7 +36,7 @@
 #define	REPLICATOR_IDFILTER0	0x00
 #define	REPLICATOR_IDFILTER1	0x04
 
-DECLARE_CLASS(replicator_driver);
+DECLARE_CLASS(coresight_replicator_driver);
 
 struct replicator_softc {
 	struct resource			*res;
@@ -44,5 +44,6 @@
 };
 
 int replicator_attach(device_t dev);
+int replicator_detach(device_t dev);
 
 #endif /* !_ARM64_CORESIGHT_CORESIGHT_REPLICATOR_H_ */
Index: sys/arm64/coresight/coresight_replicator.c
===================================================================
--- sys/arm64/coresight/coresight_replicator.c
+++ sys/arm64/coresight/coresight_replicator.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -64,8 +64,8 @@
 }
 
 static int
-replicator_enable(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+replicator_configure(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline, struct hwt_context *ctx)
 {
 	struct replicator_softc *sc;
 
@@ -84,8 +84,8 @@
 }
 
 static void
-replicator_disable(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+replicator_deconfigure(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline)
 {
 	struct replicator_softc *sc;
 
@@ -116,13 +116,30 @@
 	return (0);
 }
 
+int
+replicator_detach(device_t dev)
+{
+	struct replicator_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	error = coresight_unregister(dev);
+	if (error)
+		return (error);
+
+	bus_release_resources(dev, replicator_spec, &sc->res);
+
+	return (0);
+}
+
 static device_method_t replicator_methods[] = {
 	/* Coresight interface */
 	DEVMETHOD(coresight_init,	replicator_init),
-	DEVMETHOD(coresight_enable,	replicator_enable),
-	DEVMETHOD(coresight_disable,	replicator_disable),
+	DEVMETHOD(coresight_configure,	replicator_configure),
+	DEVMETHOD(coresight_deconfigure,replicator_deconfigure),
 	DEVMETHOD_END
 };
 
-DEFINE_CLASS_0(replicator, replicator_driver, replicator_methods,
-    sizeof(struct replicator_softc));
+DEFINE_CLASS_0(coresight_replicator, coresight_replicator_driver,
+    replicator_methods, sizeof(struct replicator_softc));
Index: sys/arm64/coresight/coresight_replicator_fdt.c
===================================================================
--- sys/arm64/coresight/coresight_replicator_fdt.c
+++ sys/arm64/coresight/coresight_replicator_fdt.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -78,15 +78,34 @@
 	return (replicator_attach(dev));
 }
 
+static int
+replicator_fdt_detach(device_t dev)
+{
+	struct replicator_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	coresight_fdt_release_platform_data(sc->pdata);
+
+	sc->pdata = NULL;
+
+	return (replicator_detach(dev));
+}
+
 static device_method_t replicator_fdt_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		replicator_fdt_probe),
 	DEVMETHOD(device_attach,	replicator_fdt_attach),
+	DEVMETHOD(device_detach,	replicator_fdt_detach),
 	DEVMETHOD_END
 };
 
-DEFINE_CLASS_1(replicator, replicator_fdt_driver, replicator_fdt_methods,
-    sizeof(struct replicator_softc), replicator_driver);
+DEFINE_CLASS_1(coresight_replicator, coresight_replicator_fdt_driver,
+    replicator_fdt_methods, sizeof(struct replicator_softc),
+    coresight_replicator_driver);
 
-EARLY_DRIVER_MODULE(replicator, simplebus, replicator_fdt_driver, 0, 0,
+EARLY_DRIVER_MODULE(coresight_replicator, simplebus,
+    coresight_replicator_fdt_driver, 0, 0,
     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+MODULE_DEPEND(coresight_replicator, coresight, 1, 1, 1);
+MODULE_VERSION(coresight_replicator, 1);
Index: sys/arm64/coresight/coresight_tmc.h
===================================================================
--- sys/arm64/coresight/coresight_tmc.h
+++ sys/arm64/coresight/coresight_tmc.h
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by SRI International and the University of
@@ -79,6 +79,7 @@
 #define	 FFCR_FON_TRIG_EVT	(1 << 5)
 #define	 FFCR_FLUSH_MAN		(1 << 6)
 #define	 FFCR_TRIGON_TRIGIN	(1 << 8)
+#define	 FFCR_STOP_ON_FLUSH	(1 << 12)
 #define	TMC_PSCR	0x308 /* Periodic Synchronization Counter Register */
 #define	TMC_ITATBMDATA0	0xED0 /* Integration Test ATB Master Data Register 0 */
 #define	TMC_ITATBMCTR2	0xED4 /* Integration Test ATB Master Interface Control 2 Register */
@@ -116,22 +117,25 @@
 #define	TMC_COMPID2	0xFF8 /* Component ID2 Register */
 #define	TMC_COMPID3	0xFFC /* Component ID3 Register */
 
-DECLARE_CLASS(tmc_driver);
+DECLARE_CLASS(coresight_tmc_driver);
 
 struct tmc_softc {
-	struct resource			*res;
+	struct resource			*res[2];
 	device_t			dev;
-	uint64_t			cycle;
 	struct coresight_platform_data	*pdata;
 	uint32_t			dev_type;
 #define	CORESIGHT_UNKNOWN		0
 #define	CORESIGHT_ETR			1
 #define	CORESIGHT_ETF			2
 	uint32_t			nev;
-	struct coresight_event		*event;
 	boolean_t			etf_configured;
+	boolean_t			scatter_gather;
+	void				*intrhand;
 };
 
+typedef uint32_t sgte_t;
+
 int tmc_attach(device_t dev);
+int tmc_detach(device_t dev);
 
 #endif /* !_ARM64_CORESIGHT_CORESIGHT_TMC_H_ */
Index: sys/arm64/coresight/coresight_tmc.c
===================================================================
--- sys/arm64/coresight/coresight_tmc.c
+++ sys/arm64/coresight/coresight_tmc.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by SRI International and the University of
@@ -39,6 +39,15 @@
 #include 
 #include 
 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
 #include 
 #include 
 
@@ -46,140 +55,390 @@
 
 #define	TMC_DEBUG
 #undef TMC_DEBUG
-        
+
 #ifdef TMC_DEBUG
 #define	dprintf(fmt, ...)	printf(fmt, ##__VA_ARGS__)
 #else
 #define	dprintf(fmt, ...)
 #endif
 
+#define	SG_PT_ENTIRES_PER_PAGE	(PAGE_SIZE / sizeof(sgte_t))
+#define	ETR_SG_ET_MASK			0x3
+#define	ETR_SG_ET_LAST			0x1
+#define	ETR_SG_ET_NORMAL		0x2
+#define	ETR_SG_ET_LINK			0x3
+
+#define	ETR_SG_PAGE_SHIFT		12
+#define	ETR_SG_ADDR_SHIFT		4
+
+#define	ETR_SG_ENTRY(addr, type) \
+	(sgte_t)((((addr) >> ETR_SG_PAGE_SHIFT) << ETR_SG_ADDR_SHIFT) | \
+	    (type & ETR_SG_ET_MASK))
+
+static MALLOC_DEFINE(M_CORESIGHT_TMC, "coresight_tmc", "Coresight TMC");
+
 static struct resource_spec tmc_spec[] = {
 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE | RF_OPTIONAL },
 	{ -1, 0 }
 };
 
 static int
-tmc_start(device_t dev)
+tmc_wait_for_tmcready(struct tmc_softc *sc)
 {
-	struct tmc_softc *sc;
 	uint32_t reg;
+	int timeout;
 
-	sc = device_get_softc(dev);
+	timeout = 10000;
 
-	if (bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN)
-		return (-1);
+	do {
+		reg = bus_read_4(sc->res[0], TMC_STS);
+		if (reg & STS_TMCREADY)
+			break;
+	} while (timeout--);
+
+	if (timeout <= 0) {
+		printf("%s: Error: TMC type %d is running\n", __func__,
+		    sc->dev_type);
+		return (EINTEGRITY);
+	}
 
-	/* Enable TMC */
-	bus_write_4(sc->res, TMC_CTL, CTL_TRACECAPTEN);
-	if ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0)
-		panic("Not enabled\n");
+	return (0);
+}
 
-	do {
-		reg = bus_read_4(sc->res, TMC_STS);
-	} while ((reg & STS_TMCREADY) == 1);
+static int
+tmc_alloc_pages(struct tmc_softc *sc, vm_page_t *pages, int npages)
+{
+	vm_paddr_t low, high, boundary;
+	vm_memattr_t memattr;
+	int alignment;
+	vm_pointer_t va;
+	int pflags;
+	vm_page_t m;
+	int tries;
+	int i;
+
+	alignment = PAGE_SIZE;
+	low = 0;
+	high = -1UL;
+	boundary = 0;
+	pflags = VM_ALLOC_NORMAL | VM_ALLOC_NOBUSY | VM_ALLOC_WIRED |
+	    VM_ALLOC_ZERO;
+	memattr = VM_MEMATTR_DEFAULT;
+
+	for (i = 0; i < npages; i++) {
+		tries = 0;
+retry:
+		m = vm_page_alloc_noobj_contig(pflags, 1, low, high,
+		    alignment, boundary, memattr);
+		if (m == NULL) {
+			if (tries < 3) {
+				if (!vm_page_reclaim_contig(pflags, 1, low,
+				    high, alignment, boundary))
+					vm_wait(NULL);
+				tries++;
+				goto retry;
+			}
+
+			return (ENOMEM);
+		}
 
-	if ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0)
-		panic("Not enabled\n");
+		if ((m->flags & PG_ZERO) == 0)
+			pmap_zero_page(m);
+
+		va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
+		cpu_dcache_wb_range(va, PAGE_SIZE);
+		cpu_dcache_inv_range(va, PAGE_SIZE);
+		m->valid = VM_PAGE_BITS_ALL;
+		m->oflags &= ~VPO_UNMANAGED;
+		m->flags |= PG_FICTITIOUS;
+
+		pages[i] = m;
+	}
 
 	return (0);
 }
 
+static void
+tmc_dump(device_t dev)
+{
+	struct tmc_softc *sc;
+	uint32_t reg;
+	size_t hi, lo;
+	size_t rrp, rwp;
+
+	sc = device_get_softc(dev);
+	if (sc->dev_type == CORESIGHT_ETF)
+		return;
+
+	lo = bus_read_4(sc->res[0], TMC_RRP);
+	hi = bus_read_4(sc->res[0], TMC_RRPHI);
+	rrp = lo | (hi << 32);
+
+	lo = bus_read_4(sc->res[0], TMC_RWP);
+	hi = bus_read_4(sc->res[0], TMC_RWPHI);
+	rwp = lo | (hi << 32);
+
+	reg = bus_read_4(sc->res[0], TMC_DEVID);
+	if ((reg & DEVID_CONFIGTYPE_M) == DEVID_CONFIGTYPE_ETR)
+		printf("%s%d: STS %x CTL %x RSZ %x RRP %lx RWP %lx AXICTL %x\n",
+		    __func__,
+		    device_get_unit(dev),
+		    bus_read_4(sc->res[0], TMC_STS),
+		    bus_read_4(sc->res[0], TMC_CTL),
+		    bus_read_4(sc->res[0], TMC_RSZ),
+		    rrp, rwp,
+		    bus_read_4(sc->res[0], TMC_AXICTL));
+}
+
 static int
-tmc_stop(device_t dev)
+tmc_configure_etf(device_t dev)
 {
 	struct tmc_softc *sc;
 	uint32_t reg;
 
 	sc = device_get_softc(dev);
 
-	reg = bus_read_4(sc->res, TMC_CTL);
-	reg &= ~CTL_TRACECAPTEN;
-	bus_write_4(sc->res, TMC_CTL, reg);
+	dprintf("%s%d\n", __func__, device_get_unit(dev));
 
-	do {
-		reg = bus_read_4(sc->res, TMC_STS);
-	} while ((reg & STS_TMCREADY) == 1);
+	bus_write_4(sc->res[0], TMC_MODE, MODE_HW_FIFO);
+	reg = FFCR_EN_FMT | FFCR_EN_TI;
+	bus_write_4(sc->res[0], TMC_FFCR, reg);
 
 	return (0);
 }
 
 static int
-tmc_configure_etf(device_t dev)
+tmc_configure_etr(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline)
 {
 	struct tmc_softc *sc;
 	uint32_t reg;
 
 	sc = device_get_softc(dev);
 
-	do {
-		reg = bus_read_4(sc->res, TMC_STS);
-	} while ((reg & STS_TMCREADY) == 0);
+	dprintf("%s%d\n", __func__, device_get_unit(dev));
+
+	/* Configure TMC */
+	bus_write_4(sc->res[0], TMC_MODE, MODE_CIRCULAR_BUFFER);
+
+	reg = AXICTL_PROT_CTRL_BIT1;
+	reg |= AXICTL_WRBURSTLEN_16;
+	if (sc->scatter_gather)
+		reg |= AXICTL_SG_MODE;
+	/* reg |= AXICTL_AXCACHE_OS; */
+	bus_write_4(sc->res[0], TMC_AXICTL, reg);
 
-	bus_write_4(sc->res, TMC_MODE, MODE_HW_FIFO);
-	bus_write_4(sc->res, TMC_FFCR, FFCR_EN_FMT | FFCR_EN_TI);
+	reg = FFCR_EN_FMT | FFCR_EN_TI | FFCR_FON_FLIN |
+	    FFCR_FON_TRIG_EVT | FFCR_TRIGON_TRIGIN;
+	bus_write_4(sc->res[0], TMC_FFCR, reg);
 
-	tmc_start(dev);
+	bus_write_4(sc->res[0], TMC_TRG, 0x3ff);
 
-	dprintf("%s: STS %x, CTL %x, RSZ %x, RRP %x, RWP %x, "
-	    "LBUFLEVEL %x, CBUFLEVEL %x\n", __func__,
-	    bus_read_4(sc->res, TMC_STS),
-	    bus_read_4(sc->res, TMC_CTL),
-	    bus_read_4(sc->res, TMC_RSZ),
-	    bus_read_4(sc->res, TMC_RRP),
-	    bus_read_4(sc->res, TMC_RWP),
-	    bus_read_4(sc->res, TMC_CBUFLEVEL),
-	    bus_read_4(sc->res, TMC_LBUFLEVEL));
+	if (sc->scatter_gather) {
+		dprintf("%s: pipeline->etr.pages %p\n", __func__,
+		    pipeline->etr.pages);
+		dprintf("%s: pipeline->etr.npages %d\n", __func__,
+		    pipeline->etr.npages);
+	} else {
+		bus_write_4(sc->res[0], TMC_DBALO, pipeline->etr.low);
+		bus_write_4(sc->res[0], TMC_DBAHI, pipeline->etr.high);
+		bus_write_4(sc->res[0], TMC_RSZ, pipeline->etr.bufsize / 4);
+		bus_write_4(sc->res[0], TMC_RRP, pipeline->etr.low);
+		bus_write_4(sc->res[0], TMC_RWP, pipeline->etr.low);
+	}
+
+	reg = bus_read_4(sc->res[0], TMC_STS);
+	reg &= ~STS_FULL;
+	bus_write_4(sc->res[0], TMC_STS, reg);
 
 	return (0);
 }
 
+static vm_page_t *
+tmc_allocate_pgdir(struct tmc_softc *sc, vm_page_t *pages, int nentries,
+    int npt)
+{
+	vm_page_t *pt_dir;
+	vm_paddr_t paddr;
+	int sgtentry;
+	sgte_t *ptr;
+	uint32_t dirpg;
+	int curpg;
+	int type;
+	int error;
+	int i;
+
+	pt_dir = malloc(sizeof(struct vm_page *) * npt, M_CORESIGHT_TMC,
+	    M_WAITOK | M_ZERO);
+	error = tmc_alloc_pages(sc, pt_dir, npt);
+	if (error) {
+		printf("%s: could not allocate pages\n", __func__);
+		return (NULL);
+	}
+
+	sgtentry = 0;
+	curpg = 0;
+	ptr = (sgte_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pt_dir[0]));
+	dirpg = 1;
+
+	for (i = 0; i < nentries - 1; i++) {
+		dprintf("entry %d dirpg %d\n", i, dirpg);
+
+		if (sgtentry == (SG_PT_ENTIRES_PER_PAGE - 1)) {
+			type = ETR_SG_ET_LINK;
+			paddr = VM_PAGE_TO_PHYS(pt_dir[dirpg]);
+		} else {
+			type = ETR_SG_ET_NORMAL;
+			paddr = VM_PAGE_TO_PHYS(pages[curpg]);
+
+#ifdef TMC_DEBUG
+			if ((i % 100) == 0)
+				dprintf("%s: entry (%d/%d) type %d dirpg %d "
+				    "curpg %d paddr %lx\n", __func__, i,
+				    nentries, type, dirpg, curpg, paddr);
+#endif
+
+			curpg++;
+		}
+
+		*ptr = ETR_SG_ENTRY(paddr, type);
+		cpu_dcache_wb_range((vm_pointer_t)ptr, sizeof(sgte_t));
+		ptr++;
+
+		/* Take next directory page. */
+		if (type == ETR_SG_ET_LINK) {
+			ptr = (sgte_t *)PHYS_TO_DMAP(
+				VM_PAGE_TO_PHYS(pt_dir[dirpg]));
+			dirpg++;
+		}
+
+		sgtentry = (sgtentry + 1) % SG_PT_ENTIRES_PER_PAGE;
+	}
+
+	/* Last entry. */
+	paddr = VM_PAGE_TO_PHYS(pages[curpg]);
+	*ptr = ETR_SG_ENTRY(paddr, ETR_SG_ET_LAST);
+	cpu_dcache_wb_range((vm_pointer_t)ptr, sizeof(sgte_t));
+
+	return (pt_dir);
+}
+
+static void
+tmc_deallocate_pgdir(struct coresight_pipeline *pipeline)
+{
+	vm_page_t *pg_dir;
+	vm_page_t m;
+	int npages;
+	int i;
+
+	pg_dir = pipeline->etr.pt_dir;
+	npages = pipeline->etr.npt;
+
+	for (i = 0; i < npages; i++) {
+		m = pg_dir[i];
+		if (m == NULL)
+			break;
+
+		vm_page_lock(m);
+		m->oflags |= VPO_UNMANAGED;
+		m->flags &= ~PG_FICTITIOUS;
+		vm_page_unwire_noq(m);
+		vm_page_free(m);
+		vm_page_unlock(m);
+	}
+
+	free(pg_dir, M_CORESIGHT_TMC);
+}
+
 static int
-tmc_configure_etr(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+tmc_setup(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline)
 {
 	struct tmc_softc *sc;
-	uint32_t reg;
+	vm_page_t *pt_dir;
+	vm_page_t *pages;
+	uint64_t pbase;
+	int nentries;
+	int nlinks;
+	int npages;
+	int npt;
+	int error;
 
 	sc = device_get_softc(dev);
+	if (sc->dev_type == CORESIGHT_ETF)
+		return (0);
 
-	tmc_stop(dev);
+	if (!sc->scatter_gather)
+		return (0);
 
-	do {
-		reg = bus_read_4(sc->res, TMC_STS);
-	} while ((reg & STS_TMCREADY) == 0);
+	error = tmc_wait_for_tmcready(sc);
+	if (error)
+		return (error);
 
-	/* Configure TMC */
-	bus_write_4(sc->res, TMC_MODE, MODE_CIRCULAR_BUFFER);
+	npages = pipeline->etr.npages;
+	pages = pipeline->etr.pages;
 
-	reg = AXICTL_PROT_CTRL_BIT1;
-	reg |= AXICTL_WRBURSTLEN_16;
+	if (npages == 0 || pages == NULL)
+		return (EINVAL);
 
-	/*
-	 * SG operation is broken on DragonBoard 410c
-	 * reg |= AXICTL_SG_MODE;
-	 */
+	nlinks = npages / (SG_PT_ENTIRES_PER_PAGE - 1);
+	if (nlinks && ((npages % (SG_PT_ENTIRES_PER_PAGE - 1)) < 2))
+		nlinks--;
+	nentries = nlinks + npages;
 
-	reg |= AXICTL_AXCACHE_OS;
-	bus_write_4(sc->res, TMC_AXICTL, reg);
+	npt = howmany(nentries, SG_PT_ENTIRES_PER_PAGE);
 
-	reg = FFCR_EN_FMT | FFCR_EN_TI | FFCR_FON_FLIN |
-	    FFCR_FON_TRIG_EVT | FFCR_TRIGON_TRIGIN;
-	bus_write_4(sc->res, TMC_FFCR, reg);
+	dprintf("%s: nentries %d, npt %d\n", __func__, nentries, npt);
 
-	bus_write_4(sc->res, TMC_TRG, 8);
+	pt_dir = tmc_allocate_pgdir(sc, pages, nentries, npt);
+	if (pt_dir == NULL)
+		return (ENOMEM);
+	pipeline->etr.pt_dir = pt_dir;
+	pipeline->etr.npt = npt;
 
-	bus_write_4(sc->res, TMC_DBALO, event->etr.low);
-	bus_write_4(sc->res, TMC_DBAHI, event->etr.high);
-	bus_write_4(sc->res, TMC_RSZ, event->etr.bufsize / 4);
+#ifdef TMC_DEBUG
+	ptr = (sgte_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pt_dir[0]));
+	for (i = 0; i < nentries; i++)
+		dprintf("%s: entry %x\n", __func__, *ptr++);
+#endif
 
-	bus_write_4(sc->res, TMC_RRP, event->etr.low);
-	bus_write_4(sc->res, TMC_RWP, event->etr.low);
+	dprintf("%s: pipeline->etr.pages %p\n", __func__, pipeline->etr.pages);
+	dprintf("%s: pipeline->etr.npages %d\n", __func__,
+	    pipeline->etr.npages);
 
-	reg = bus_read_4(sc->res, TMC_STS);
-	reg &= ~STS_FULL;
-	bus_write_4(sc->res, TMC_STS, reg);
+	pbase = (uint64_t)VM_PAGE_TO_PHYS(pt_dir[0]);
+
+	dprintf("%s: pbase %lx\n", __func__, pbase);
 
-	tmc_start(dev);
+	bus_write_4(sc->res[0], TMC_DBALO, pbase & 0xffffffff);
+	bus_write_4(sc->res[0], TMC_DBAHI, pbase >> 32);
+	bus_write_4(sc->res[0], TMC_RSZ, (pipeline->etr.npages * 4096) / 4);
+
+	return (0);
+}
+
+static int
+tmc_enable_hw(device_t dev)
+{
+	struct tmc_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (bus_read_4(sc->res[0], TMC_CTL) & CTL_TRACECAPTEN) {
+		printf("%s: TMC is already enabled\n", __func__);
+		return (ENXIO);
+	}
+
+	/* Enable TMC */
+	bus_write_4(sc->res[0], TMC_CTL, CTL_TRACECAPTEN);
+
+	if ((bus_read_4(sc->res[0], TMC_CTL) & CTL_TRACECAPTEN) == 0) {
+		printf("%s: could not enable TMC\n", __func__);
+		return (ENXIO);
+	}
+
+	dprintf("%s: tmc type %d enabled\n", __func__, sc->dev_type);
 
 	return (0);
 }
@@ -192,13 +451,15 @@
 
 	sc = device_get_softc(dev);
 
+	dprintf("%s%d\n", __func__, device_get_unit(dev));
+
 	/* Unlock Coresight */
-	bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK);
+	bus_write_4(sc->res[0], CORESIGHT_LAR, CORESIGHT_UNLOCK);
 
 	/* Unlock TMC */
-	bus_write_4(sc->res, TMC_LAR, CORESIGHT_UNLOCK);
+	bus_write_4(sc->res[0], TMC_LAR, CORESIGHT_UNLOCK);
 
-	reg = bus_read_4(sc->res, TMC_DEVID);
+	reg = bus_read_4(sc->res[0], TMC_DEVID);
 	reg &= DEVID_CONFIGTYPE_M;
 	switch (reg) {
 	case DEVID_CONFIGTYPE_ETR:
@@ -210,6 +471,7 @@
 		dprintf(dev, "ETF configuration found\n");
 		if (sc->etf_configured == false) {
 			tmc_configure_etf(dev);
+			tmc_enable_hw(dev);
 			sc->etf_configured = true;
 		}
 		break;
@@ -222,128 +484,260 @@
 }
 
 static int
-tmc_enable(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+tmc_flush(struct tmc_softc *sc, int stop_on_flush)
 {
-	struct tmc_softc *sc;
-	uint32_t nev;
+	uint32_t reg;
+	int timeout;
 
-	sc = device_get_softc(dev);
+	reg = bus_read_4(sc->res[0], TMC_FFCR);
 
-	if (sc->dev_type == CORESIGHT_ETF)
-		return (0);
+	if (stop_on_flush) {
+		reg |= FFCR_STOP_ON_FLUSH;
+		bus_write_4(sc->res[0], TMC_FFCR, reg);
+	}
 
-	KASSERT(sc->dev_type == CORESIGHT_ETR,
-	    ("Wrong dev_type"));
-
-	/*
-	 * Multiple CPUs can call this same time.
-	 * We allow only one running configuration.
-	 */
-
-	if (event->etr.flags & ETR_FLAG_ALLOCATE) {
-		event->etr.flags &= ~ETR_FLAG_ALLOCATE;
-		nev = atomic_fetchadd_int(&sc->nev, 1);
-		if (nev == 0) {
-			sc->event = event;
-			tmc_stop(dev);
-			tmc_configure_etr(dev, endp, event);
-			tmc_start(dev);
-		}
+	reg |= FFCR_FLUSH_MAN;
+	bus_write_4(sc->res[0], TMC_FFCR, reg);
+
+	/* Wait for the flush to complete. */
+	timeout = 10000;
+
+	do {
+		reg = bus_read_4(sc->res[0], TMC_FFCR);
+		if ((reg & FFCR_FLUSH_MAN) == 0)
+			break;
+	} while (timeout--);
+
+	if (timeout <= 0) {
+		printf("%s: could not flush TMC\n", __func__);
+		return (EINTEGRITY);
 	}
 
 	return (0);
 }
 
+static void
+tmc_disable_hw(device_t dev)
+{
+	struct tmc_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	error = tmc_flush(sc, 1);
+	if (error)
+		printf("%s: could not flush TMC\n", __func__);
+
+	error = tmc_wait_for_tmcready(sc);
+	if (error)
+		printf("%s: could not get TMC ready\n", __func__);
+
+	bus_write_4(sc->res[0], TMC_CTL, 0);
+
+	dprintf("%s: tmc type %d disabled\n", __func__, sc->dev_type);
+}
+
 static void
 tmc_disable(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+    struct coresight_pipeline *pipeline)
 {
 	struct tmc_softc *sc;
-	uint32_t nev;
 
 	sc = device_get_softc(dev);
 
-	/* ETF configuration is static */
-	if (sc->dev_type == CORESIGHT_ETF)
+	if (sc->dev_type == CORESIGHT_ETR)
 		return;
 
-	KASSERT(sc->dev_type == CORESIGHT_ETR, ("Wrong dev_type"));
+	tmc_flush(sc, 0);
+}
 
-	if (event->etr.flags & ETR_FLAG_RELEASE) {
-		event->etr.flags &= ~ETR_FLAG_RELEASE;
-		nev = atomic_fetchadd_int(&sc->nev, -1);
-		if (nev == 1) {
-			tmc_stop(dev);
-			sc->event = NULL;
-		}
+static int
+tmc_deinit(device_t dev)
+{
+	struct tmc_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (sc->dev_type == CORESIGHT_ETR)
+		return (0);
+
+	if (sc->etf_configured == true) {
+		sc->etf_configured = false;
+		tmc_disable_hw(dev);
 	}
+
+	return (0);
 }
 
 static int
-tmc_read(device_t dev, struct endpoint *endp,
-    struct coresight_event *event)
+tmc_start(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline)
 {
 	struct tmc_softc *sc;
-	uint32_t cur_ptr;
+	int error;
 
 	sc = device_get_softc(dev);
-
 	if (sc->dev_type == CORESIGHT_ETF)
 		return (0);
 
-	/*
-	 * Ensure the event we are reading information for
-	 * is currently configured one.
-	 */
-	if (sc->event != event)
-		return (0);
+	dprintf("%s%d type %d\n", __func__, device_get_unit(dev), sc->dev_type);
 
-	if (bus_read_4(sc->res, TMC_STS) & STS_FULL) {
-		event->etr.offset = 0;
-		event->etr.cycle++;
-		tmc_stop(dev);
-		tmc_start(dev);
-	} else {
-		cur_ptr = bus_read_4(sc->res, TMC_RWP);
-		event->etr.offset = (cur_ptr - event->etr.low);
-	}
+	error = tmc_wait_for_tmcready(sc);
+	if (error)
+		return (error);
+
+	tmc_configure_etr(dev, endp, pipeline);
+	tmc_enable_hw(dev);
 
 	return (0);
 }
 
+static int
+tmc_read(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline)
+{
+	struct tmc_softc *sc;
+	vm_page_t page;
+	bool found;
+	uint64_t lo, hi;
+	uint64_t ptr;
+	int i;
+
+	sc = device_get_softc(dev);
+	if (sc->dev_type == CORESIGHT_ETF)
+		return (ENXIO);
+
+	lo = bus_read_4(sc->res[0], TMC_RWP);
+	hi = bus_read_4(sc->res[0], TMC_RWPHI);
+	ptr = lo | (hi << 32);
+
+	page = PHYS_TO_VM_PAGE(ptr);
+
+	found = false;
+
+	for (i = 0; i < pipeline->etr.npages; i++) {
+		if (pipeline->etr.pages[i] == page) {
+			found = true;
+			break;
+		}
+	}
+
+	if (found) {
+		pipeline->etr.curpage = i;
+		pipeline->etr.curpage_offset = ptr & 0xfff;
+		dprintf("CUR_PTR %lx, page %d of %d, offset %ld\n",
+		    ptr, i, pipeline->etr.npages, pipeline->etr.curpage_offset);
+
+		return (0);
+	} else
+		dprintf("CUR_PTR not found\n");
+
+	return (ENOENT);
+}
+
+static void
+tmc_stop(device_t dev, struct endpoint *endp,
+    struct coresight_pipeline *pipeline)
+{
+	struct tmc_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (sc->dev_type == CORESIGHT_ETF)
+		return;
+
+	dprintf("%s%d type %d\n", __func__, device_get_unit(dev), sc->dev_type);
+
+	/* Make final readings before we stop TMC-ETR. */
+	tmc_read(dev, endp, pipeline);
+	tmc_disable_hw(dev);
+	tmc_deallocate_pgdir(pipeline);
+}
+
+static void
+tmc_intr(void *arg)
+{
+
+	/* TODO */
+
+	panic("unhandled interrupt");
+}
+
 int
 tmc_attach(device_t dev)
 {
 	struct coresight_desc desc;
 	struct tmc_softc *sc;
+	uint32_t reg;
 
 	sc = device_get_softc(dev);
 	sc->dev = dev;
 
-	if (bus_alloc_resources(dev, tmc_spec, &sc->res) != 0) {
+	if (bus_alloc_resources(dev, tmc_spec, sc->res) != 0) {
 		device_printf(dev, "cannot allocate resources for device\n");
 		return (ENXIO);
 	}
 
+	if (sc->res[1] != NULL) {
+		if (bus_setup_intr(dev, sc->res[1],
+		    INTR_TYPE_MISC | INTR_MPSAFE, NULL, tmc_intr, sc,
+		    &sc->intrhand)) {
+			bus_release_resources(dev, tmc_spec, sc->res);
+			device_printf(dev, "cannot setup interrupt handler\n");
+			return (ENXIO);
+		}
+	}
+
 	desc.pdata = sc->pdata;
 	desc.dev = dev;
-	desc.dev_type = CORESIGHT_TMC;
+
+	reg = bus_read_4(sc->res[0], TMC_DEVID);
+	reg &= DEVID_CONFIGTYPE_M;
+	if (reg == DEVID_CONFIGTYPE_ETR)
+		desc.dev_type = CORESIGHT_TMC_ETR;
+	else
+		desc.dev_type = CORESIGHT_TMC_ETF;
+
 	coresight_register(&desc);
 
 	return (0);
 }
 
-static device_method_t tmc_methods[] = {
-	/* Device interface */
-	DEVMETHOD(device_attach,	tmc_attach),
+int
+tmc_detach(device_t dev)
+{
+	struct tmc_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	error = coresight_unregister(dev);
+	if (error)
+		return (error);
+
+	if (sc->intrhand != NULL)
+		bus_teardown_intr(dev, sc->res[1], sc->intrhand);
+
+	bus_release_resources(dev, tmc_spec, sc->res);
 
+	return (0);
+}
+
+static device_method_t tmc_methods[] = {
 	/* Coresight interface */
 	DEVMETHOD(coresight_init,	tmc_init),
-	DEVMETHOD(coresight_enable,	tmc_enable),
+
+	/* ETF only. */
+	DEVMETHOD(coresight_deinit,	tmc_deinit),
 	DEVMETHOD(coresight_disable,	tmc_disable),
+
+	/* ETR only. */
+	DEVMETHOD(coresight_setup,	tmc_setup),
+	DEVMETHOD(coresight_start,	tmc_start),
+	DEVMETHOD(coresight_stop,	tmc_stop),
 	DEVMETHOD(coresight_read,	tmc_read),
+	DEVMETHOD(coresight_dump,	tmc_dump),
 	DEVMETHOD_END
 };
 
-DEFINE_CLASS_0(tmc, tmc_driver, tmc_methods, sizeof(struct tmc_softc));
+DEFINE_CLASS_0(coresight_tmc, coresight_tmc_driver, tmc_methods,
+    sizeof(struct tmc_softc));
Index: sys/arm64/coresight/coresight_tmc_fdt.c
===================================================================
--- sys/arm64/coresight/coresight_tmc_fdt.c
+++ sys/arm64/coresight/coresight_tmc_fdt.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2018-2020 Ruslan Bukin 
+ * Copyright (c) 2018-2023 Ruslan Bukin 
  * All rights reserved.
  *
  * This software was developed by BAE Systems, the University of Cambridge
@@ -71,22 +71,56 @@
 tmc_fdt_attach(device_t dev)
 {
 	struct tmc_softc *sc;
+	phandle_t node;
+	ssize_t len;
 
 	sc = device_get_softc(dev);
 	sc->pdata = coresight_fdt_get_platform_data(dev);
 
+	node = ofw_bus_get_node(dev);
+
+	len = OF_getproplen(node, "arm,scatter-gather");
+	if (len >= 0)
+		sc->scatter_gather = true;
+	else
+		sc->scatter_gather = false;
+
 	return (tmc_attach(dev));
 }
 
+static int
+tmc_fdt_detach(device_t dev)
+{
+	struct tmc_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+ 
+	coresight_fdt_release_platform_data(sc->pdata);
+
+	sc->pdata = NULL;
+
+	error = tmc_detach(dev);
+
+	return (error);
+}
+
 static device_method_t tmc_fdt_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		tmc_fdt_probe),
 	DEVMETHOD(device_attach,	tmc_fdt_attach),
+	DEVMETHOD(device_detach,	tmc_fdt_detach),
 	DEVMETHOD_END
 };
 
-DEFINE_CLASS_1(tmc, tmc_fdt_driver, tmc_fdt_methods,
-    sizeof(struct tmc_softc), tmc_driver);
+DEFINE_CLASS_1(coresight_tmc, tmc_fdt_driver, tmc_fdt_methods,
+    sizeof(struct tmc_softc), coresight_tmc_driver);
 
-EARLY_DRIVER_MODULE(tmc, simplebus, tmc_fdt_driver, 0, 0,
+EARLY_DRIVER_MODULE(coresight_tmc, simplebus, tmc_fdt_driver, 0, 0,
     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+MODULE_DEPEND(coresight_tmc, coresight, 1, 1, 1);
+MODULE_DEPEND(coresight_tmc, coresight_cpu_debug, 1, 1, 1);
+MODULE_DEPEND(coresight_tmc, coresight_etm4x, 1, 1, 1);
+MODULE_DEPEND(coresight_tmc, coresight_funnel, 1, 1, 1);
+MODULE_DEPEND(coresight_tmc, coresight_replicator, 1, 1, 1);
+MODULE_VERSION(coresight_tmc, 1);
Index: sys/conf/files.arm64
===================================================================
--- sys/conf/files.arm64
+++ sys/conf/files.arm64
@@ -139,24 +139,24 @@
 # ANX6345 RGB to eDP bridge
 dev/drm/bridges/anx6345/anx6345.c		optional fdt anx6345 compile-with "${DRM_C}"
 
-arm64/coresight/coresight.c			standard
-arm64/coresight/coresight_acpi.c		optional acpi
-arm64/coresight/coresight_fdt.c			optional fdt
-arm64/coresight/coresight_if.m			standard
-arm64/coresight/coresight_cmd.c			standard
-arm64/coresight/coresight_cpu_debug.c		optional fdt
-arm64/coresight/coresight_etm4x.c		standard
-arm64/coresight/coresight_etm4x_acpi.c		optional acpi
-arm64/coresight/coresight_etm4x_fdt.c		optional fdt
-arm64/coresight/coresight_funnel.c		standard
-arm64/coresight/coresight_funnel_acpi.c		optional acpi
-arm64/coresight/coresight_funnel_fdt.c		optional fdt
-arm64/coresight/coresight_replicator.c		standard
-arm64/coresight/coresight_replicator_acpi.c	optional acpi
-arm64/coresight/coresight_replicator_fdt.c	optional fdt
-arm64/coresight/coresight_tmc.c			standard
-arm64/coresight/coresight_tmc_acpi.c		optional acpi
-arm64/coresight/coresight_tmc_fdt.c		optional fdt
+arm64/coresight/coresight.c			optional hwt coresight
+arm64/coresight/coresight_acpi.c		optional hwt coresight acpi
+arm64/coresight/coresight_fdt.c			optional hwt coresight fdt
+arm64/coresight/coresight_if.m			optional hwt coresight
+arm64/coresight/coresight_cmd.c			optional hwt coresight
+arm64/coresight/coresight_cpu_debug.c		optional hwt coresight fdt
+arm64/coresight/coresight_etm4x.c		optional hwt coresight
+arm64/coresight/coresight_etm4x_acpi.c		optional hwt coresight acpi
+arm64/coresight/coresight_etm4x_fdt.c		optional hwt coresight fdt
+arm64/coresight/coresight_funnel.c		optional hwt coresight
+arm64/coresight/coresight_funnel_acpi.c		optional hwt coresight acpi
+arm64/coresight/coresight_funnel_fdt.c		optional hwt coresight fdt
+arm64/coresight/coresight_replicator.c		optional hwt coresight
+arm64/coresight/coresight_replicator_acpi.c	optional hwt coresight acpi
+arm64/coresight/coresight_replicator_fdt.c	optional hwt coresight fdt
+arm64/coresight/coresight_tmc.c			optional hwt coresight
+arm64/coresight/coresight_tmc_acpi.c		optional hwt coresight acpi
+arm64/coresight/coresight_tmc_fdt.c		optional hwt coresight fdt
 
 dev/smbios/smbios_subr.c			standard
 
Index: sys/dts/arm64/arm/morello-coresight.dtsi
===================================================================
--- /dev/null
+++ sys/dts/arm64/arm/morello-coresight.dtsi
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+#include 
+
+/ {
+	cpu_debug0: cpu-debug@402010000 {
+		compatible = "arm,coresight-cpu-debug", "arm,primecell";
+		cpu = <&cpu0>;
+		reg = <0x4 0x02010000 0x0 0x1000>;
+	};
+
+	etm0: etm@402040000 {
+		compatible = "arm,coresight-etm4x", "arm,primecell";
+		cpu = <&cpu0>;
+		reg = <0x4 0x02040000 0 0x1000>;
+
+		out-ports {
+			port {
+				cluster0_etm0_out_port: endpoint {
+					remote-endpoint = <&cluster0_static_funnel_in_port0>;
+				};
+			};
+		};
+	};
+
+	cpu_debug1: cpu-debug@402110000 {
+		compatible = "arm,coresight-cpu-debug", "arm,primecell";
+		cpu = <&cpu1>;
+		reg = <0x4 0x02110000 0x0 0x1000>;
+	};
+	etm1: etm@402140000 {
+		compatible = "arm,coresight-etm4x", "arm,primecell";
+		cpu = <&cpu1>;
+		reg = <0x4 0x02140000 0 0x1000>;
+
+		out-ports {
+			port {
+				cluster0_etm1_out_port: endpoint {
+					remote-endpoint = <&cluster0_static_funnel_in_port1>;
+				};
+			};
+		};
+	};
+
+	cpu_debug2: cpu-debug@403010000 {
+		compatible = "arm,coresight-cpu-debug", "arm,primecell";
+		cpu = <&cpu2>;
+		reg = <0x4 0x03010000 0x0 0x1000>;
+	};
+
+	etm2: etm@403040000 {
+		compatible = "arm,coresight-etm4x", "arm,primecell";
+		cpu = <&cpu2>;
+		reg = <0x4 0x03040000 0 0x1000>;
+
+		out-ports {
+			port {
+				cluster1_etm0_out_port: endpoint {
+					remote-endpoint = <&cluster1_static_funnel_in_port0>;
+				};
+			};
+		};
+	};
+
+	cpu_debug3: cpu-debug@403110000 {
+		compatible = "arm,coresight-cpu-debug", "arm,primecell";
+		cpu = <&cpu3>;
+		reg = <0x4 0x03110000 0x0 0x1000>;
+	};
+
+	etm3: etm@403140000 {
+		compatible = "arm,coresight-etm4x", "arm,primecell";
+		cpu = <&cpu3>;
+		reg = <0x4 0x03140000 0 0x1000>;
+
+		out-ports {
+			port {
+				cluster1_etm1_out_port: endpoint {
+					remote-endpoint = <&cluster1_static_funnel_in_port1>;
+				};
+			};
+		};
+	};
+
+	sfunnel0: funnel@0 {
+		compatible = "arm,coresight-static-funnel";
+
+		out-ports {
+			port {
+				cluster0_static_funnel_out_port: endpoint {
+					remote-endpoint = <&etf0_in_port>;
+				};
+			};
+		};
+
+		in-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				cluster0_static_funnel_in_port0: endpoint {
+					remote-endpoint = <&cluster0_etm0_out_port>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				cluster0_static_funnel_in_port1: endpoint {
+					remote-endpoint = <&cluster0_etm1_out_port>;
+				};
+			};
+		};
+	};
+
+	sfunnel1: funnel@1 {
+		compatible = "arm,coresight-static-funnel";
+
+		out-ports {
+			port {
+				cluster1_static_funnel_out_port: endpoint {
+					remote-endpoint = <&etf1_in_port>;
+				};
+			};
+		};
+
+		in-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				cluster1_static_funnel_in_port0: endpoint {
+					remote-endpoint = <&cluster1_etm0_out_port>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				cluster1_static_funnel_in_port1: endpoint {
+					remote-endpoint = <&cluster1_etm1_out_port>;
+				};
+			};
+		};
+	};
+
+	tpiu@400130000 {
+		compatible = "arm,coresight-tpiu", "arm,primecell";
+		reg = <0x4 0x00130000 0 0x1000>;
+
+		in-ports {
+			port {
+				tpiu_in_port: endpoint {
+					remote-endpoint = <&replicator_out_port0>;
+				};
+			};
+		};
+	};
+
+	master_funnel: funnel@4000a0000 {
+		compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+		reg = <0x4 0x000a0000 0 0x1000>;
+
+		out-ports {
+			port {
+				master_funnel_out_port: endpoint {
+					remote-endpoint = <&replicator_in_port>;
+				};
+			};
+		};
+
+		master_funnel_in_ports: in-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				master_funnel_in_port0: endpoint {
+					remote-endpoint = <&cluster_funnel_out_port>;
+				};
+			};
+
+			port@5 {
+				reg = <5>;
+				master_funnel_in_port5: endpoint {
+					remote-endpoint = <&etf2_out_port>;
+				};
+			};
+		};
+	};
+
+	etr@400120000 {
+		compatible = "arm,coresight-tmc", "arm,primecell";
+		reg = <0x4 0x00120000 0 0x1000>;
+		interrupts = ;
+		interrupt-names = "etrbufint";
+
+		arm,scatter-gather;
+		in-ports {
+			port {
+				etr_in_port: endpoint {
+					remote-endpoint = <&replicator_out_port1>;
+				};
+			};
+		};
+	};
+
+	replicator@400110000 {
+		compatible = "arm,coresight-dynamic-replicator", "arm,primecell";
+		reg = <0x4 0x00110000 0 0x1000>;
+
+		out-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				replicator_out_port0: endpoint {
+					remote-endpoint = <&tpiu_in_port>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				replicator_out_port1: endpoint {
+					remote-endpoint = <&etr_in_port>;
+				};
+			};
+		};
+		in-ports {
+			port {
+				replicator_in_port: endpoint {
+					remote-endpoint = <&master_funnel_out_port>;
+				};
+			};
+		};
+	};
+
+	cluster_funnel: funnel@4000b0000 {
+		compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
+		reg = <0x4 0x000b0000 0 0x1000>;
+
+		out-ports {
+			port {
+				cluster_funnel_out_port: endpoint {
+					remote-endpoint = <&master_funnel_in_port0>;
+				};
+			};
+		};
+
+		in-ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				cluster_funnel_in_port0: endpoint {
+					remote-endpoint = <&etf0_out_port>;
+				};
+			};
+
+			port@1 {
+				reg = <1>;
+				cluster_funnel_in_port1: endpoint {
+					remote-endpoint = <&etf1_out_port>;
+				};
+			};
+		};
+	};
+
+	etf0: etf@400410000 {
+		compatible = "arm,coresight-tmc", "arm,primecell";
+		reg = <0x4 0x00410000 0 0x1000>;
+
+		in-ports {
+			port {
+				etf0_in_port: endpoint {
+					remote-endpoint = <&cluster0_static_funnel_out_port>;
+				};
+			};
+		};
+
+		out-ports {
+			port {
+				etf0_out_port: endpoint {
+					remote-endpoint = <&cluster_funnel_in_port0>;
+				};
+			};
+		};
+	};
+
+	etf1: etf@400420000 {
+		compatible = "arm,coresight-tmc", "arm,primecell";
+		reg = <0x4 0x00420000 0 0x1000>;
+
+		in-ports {
+			port {
+				etf1_in_port: endpoint {
+					remote-endpoint = <&cluster1_static_funnel_out_port>;
+				};
+			};
+		};
+
+		out-ports {
+			port {
+				etf1_out_port: endpoint {
+					remote-endpoint = <&cluster_funnel_in_port1>;
+				};
+			};
+		};
+	};
+
+	stm_etf: etf@400010000 {
+		compatible = "arm,coresight-tmc", "arm,primecell";
+		reg = <0x4 0x00010000 0 0x1000>;
+
+		in-ports {
+			port {
+				etf2_in_port: endpoint {
+					remote-endpoint = <&stm_out_port>;
+				};
+			};
+		};
+
+		out-ports {
+			port {
+				etf2_out_port: endpoint {
+					remote-endpoint = <&master_funnel_in_port5>;
+				};
+			};
+		};
+	};
+
+	stm@400800000 {
+		compatible = "arm,coresight-stm", "arm,primecell";
+		reg = <4 0x00800000 0 0x1000>,
+		      <0 0x4d000000 0 0x1000000>;
+		reg-names = "stm-base", "stm-stimulus-base";
+
+		out-ports {
+			port {
+				stm_out_port: endpoint {
+					remote-endpoint = <&etf2_in_port>;
+				};
+			};
+		};
+	};
+};
Index: sys/dts/arm64/arm/morello-soc.dts
===================================================================
--- sys/dts/arm64/arm/morello-soc.dts
+++ sys/dts/arm64/arm/morello-soc.dts
@@ -6,6 +6,7 @@
 
 /dts-v1/;
 #include "morello.dtsi"
+#include "morello-coresight.dtsi"
 
 / {
 
@@ -27,28 +28,28 @@
 	cpus {
 		#address-cells = <2>;
 		#size-cells = <0>;
-		cpu0@0 {
+		cpu0: cpu0@0 {
 			compatible = "arm,armv8";
 			reg = <0x0 0x0>;
 			device_type = "cpu";
 			enable-method = "psci";
 			clocks = <&scmi_dvfs 0>;
 		};
-		cpu1@100 {
+		cpu1: cpu1@100 {
 			compatible = "arm,armv8";
 			reg = <0x0 0x100>;
 			device_type = "cpu";
 			enable-method = "psci";
 			clocks = <&scmi_dvfs 0>;
 		};
-		cpu2@10000 {
+		cpu2: cpu2@10000 {
 			compatible = "arm,armv8";
 			reg = <0x0 0x10000>;
 			device_type = "cpu";
 			enable-method = "psci";
 			clocks = <&scmi_dvfs 1>;
 		};
-		cpu3@10100 {
+		cpu3: cpu3@10100 {
 			compatible = "arm,armv8";
 			reg = <0x0 0x10100>;
 			device_type = "cpu";
Index: sys/modules/Makefile
===================================================================
--- sys/modules/Makefile
+++ sys/modules/Makefile
@@ -85,6 +85,7 @@
 	${_cfi} \
 	${_chromebook_platform} \
 	${_ciss} \
+	${_coresight} \
 	${_coretemp} \
 	${_cpsw} \
 	${_cpuctl} \
@@ -140,6 +141,7 @@
 	${_hptnr} \
 	${_hptrr} \
 	hwpmc \
+	hwt \
 	${_hyperv} \
 	i2c \
 	${_iavf} \
@@ -653,6 +655,12 @@
 .endif
 .endif
 
+.if ${MACHINE_CPUARCH} == "aarch64"
+.if !empty(OPT_FDT)
+_coresight=	coresight
+.endif
+.endif
+
 .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" || \
 	${MACHINE_CPUARCH} == "riscv"
 .if !empty(OPT_FDT)
Index: sys/modules/coresight/Makefile
===================================================================
--- /dev/null
+++ sys/modules/coresight/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+SUBDIR = \
+	coresight	\
+	cpu_debug	\
+	etm4x		\
+	funnel		\
+	replicator	\
+	tmc
+
+.include 
Index: sys/modules/coresight/coresight/Makefile
===================================================================
--- /dev/null
+++ sys/modules/coresight/coresight/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+.PATH:	${SRCTOP}/sys/arm64/coresight
+
+KMOD	= coresight
+SRCS	=			\
+	coresight.c		\
+	coresight_acpi.c	\
+	coresight_cmd.c		\
+	coresight_fdt.c		\
+	coresight_if.c		\
+	coresight_if.h
+
+.include 
Index: sys/modules/coresight/cpu_debug/Makefile
===================================================================
--- /dev/null
+++ sys/modules/coresight/cpu_debug/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH:	${SRCTOP}/sys/arm64/coresight
+
+KMOD	= coresight_cpu_debug
+SRCS	= coresight_cpu_debug.c coresight_if.h
+
+.include 
Index: sys/modules/coresight/etm4x/Makefile
===================================================================
--- /dev/null
+++ sys/modules/coresight/etm4x/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH:	${SRCTOP}/sys/arm64/coresight
+
+KMOD	= coresight_etm4x
+SRCS	= coresight_etm4x.c coresight_etm4x_fdt.c coresight_if.h
+
+.include 
Index: sys/modules/coresight/funnel/Makefile
===================================================================
--- /dev/null
+++ sys/modules/coresight/funnel/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH:	${SRCTOP}/sys/arm64/coresight
+
+KMOD	= coresight_funnel
+SRCS	= coresight_funnel.c coresight_funnel_fdt.c coresight_if.h
+
+.include 
Index: sys/modules/coresight/replicator/Makefile
===================================================================
--- /dev/null
+++ sys/modules/coresight/replicator/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH:	${SRCTOP}/sys/arm64/coresight
+
+KMOD	= coresight_replicator
+SRCS	= coresight_replicator.c coresight_replicator_fdt.c coresight_if.h
+
+.include 
Index: sys/modules/coresight/tmc/Makefile
===================================================================
--- /dev/null
+++ sys/modules/coresight/tmc/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH:	${SRCTOP}/sys/arm64/coresight
+
+KMOD	= coresight_tmc
+SRCS	= coresight_tmc.c coresight_tmc_fdt.c coresight_if.h
+
+.include