commit 377df4c3326727764f7401b94db4da8fd97deab1
parent 92a86ad93f305238ce2f4b98f08e0f0e74265e40
Author: Brian Swetland <swetland@frotz.net>
Date:   Tue,  4 Aug 2015 18:00:17 -0700
debugger: initial plumbing for SWO
Diffstat:
6 files changed, 82 insertions(+), 17 deletions(-)
diff --git a/include/protocol/rswdp.h b/include/protocol/rswdp.h
@@ -56,10 +56,12 @@
 #define CMD_TRACE	0x08 /* op=tracebits n=0 */
 #define CMD_BOOTLOADER	0x09 /* return to bootloader for reflashing */
 #define CMD_SET_CLOCK	0x0A /* set SWCLK rate to n khz */
+#define CMD_SWO_CLOCK	0x0B /* set SWOCLK rate to n khz, 0 = disable SWO */
 
 /* valid: target to host */
 #define CMD_STATUS	0x10 /* op=errorcode, arg=commands since last TXN_START */
 #define CMD_SWD_DATA	0x11 /* op=0 arg=count, payload: data x count */
+#define CMD_SWO_DATA	0x12 /* op=0 arg=count, payload: count * 4 bytes */
 
 /* valid: target to host async */
 #define CMD_DEBUG_PRINT	0x20 /* arg*4 bytes of ascii debug output */
diff --git a/tools/debugger-commands.c b/tools/debugger-commands.c
@@ -409,6 +409,12 @@ int do_setclock(int argc, param *argv) {
 	return swdp_set_clock(argv[0].n);
 }
 
+int do_swoclock(int argc, param *argv) {
+	if (argc < 1)
+		return -1;
+	return swo_set_clock(argv[0].n);
+}
+
 int do_help(int argc, param *argv) {
 	struct debugger_command *cmd;
 	for (cmd = debugger_commands; cmd->func != NULL; cmd++) {
@@ -836,7 +842,8 @@ struct debugger_command debugger_commands[] = {
 	{ "print",	"", do_print,		"print numeric arguments" },
 	{ "echo",	"", do_echo,		"echo command line" },
 	{ "bootloader", "", do_bootloader,	"reboot into bootloader" },
-	{ "setclock",	"", do_setclock,	"set clock rate (khz)" },
+	{ "setclock",	"", do_setclock,	"set SWD clock rate (khz)" },
+	{ "swoclock",	"", do_swoclock,	"set SWO clock rate (khz)" },
 	{ "arch",	"", do_setarch,		"set architecture for flash agent" },
 	{ "threads",	"", do_threads,		"thread dump" },
 	{ "text",	"", do_text,		"dump text" },
diff --git a/tools/module.mk b/tools/module.mk
@@ -10,6 +10,7 @@ M_OBJS += tools/usb.o
 M_OBJS += tools/socket.o
 M_OBJS += tools/gdb-bridge.o
 M_OBJS += tools/lkdebug.o
+M_OBJS += tools/swo.o
 M_OBJS += out/debugger-builtins.o
 $(call build-host-executable)
 
diff --git a/tools/rswdp.c b/tools/rswdp.c
@@ -89,18 +89,18 @@ struct txn {
 	unsigned magic;
 };
 
+void process_swo_data(void *data, unsigned count);
+
 static void process_async(u32 *data, unsigned count) {
 	unsigned msg, n;
 	u32 tmp;
-
 	while (count-- > 0) {
 		msg = *data++;
 		switch (RSWD_MSG_CMD(msg)) {
 		case CMD_NULL:
 			continue;
 		case CMD_DEBUG_PRINT:
-		    //op = RSWD_MSG_OP(msg);
-		    n = RSWD_MSG_ARG(msg);
+			n = RSWD_MSG_ARG(msg);
 			if (n > count)
 				return;
 			tmp = data[n];
@@ -110,6 +110,13 @@ static void process_async(u32 *data, unsigned count) {
 			data += n;
 			count -= n;
 			break;
+		case CMD_SWO_DATA:
+			n = RSWD_MSG_ARG(msg);
+			if (n > count)
+				return;
+			process_swo_data(data, n * 4);
+			data += n;
+			count -= n;
 		default:
 			return;
 		}
@@ -312,19 +319,17 @@ restart:
 			query_id = 0;
 			process_query(data + 1, (r / 4) - 1);
 			swd_online = 1;
-		} else if (swd_txn_status == TXN_STATUS_WAIT) {
-			if (data[0] == swd_txn_id) {
-				swd_txn_status = r;
-				memcpy(swd_txn_data, data, r);
-				pthread_cond_broadcast(&swd_event);
-			} else if (data[0] == RSWD_TXN_ASYNC) {
-				pthread_mutex_unlock(&swd_lock);
-				process_async(data + 1, (r / 4) - 1);
-				pthread_mutex_lock(&swd_lock);
-			} else {
-				xprintf(XSWD, "usb: rx: unexpected txn %08x (%d)\n",
-					data[0], r);
-			}
+		} else if (data[0] == RSWD_TXN_ASYNC) {
+			pthread_mutex_unlock(&swd_lock);
+			process_async(data + 1, (r / 4) - 1);
+			pthread_mutex_lock(&swd_lock);
+		} else if ((swd_txn_status == TXN_STATUS_WAIT) &&
+			(data[0] == swd_txn_id)) {
+			swd_txn_status = r;
+			memcpy(swd_txn_data, data, r);
+			pthread_cond_broadcast(&swd_event);
+		} else {
+			xprintf(XSWD, "usb: rx: unexpected txn %08x (%d)\n", data[0], r);
 		}
 	}
 	// wait for a reader to ack the shutdown (and close usb)
@@ -793,6 +798,17 @@ int swdp_set_clock(unsigned khz) {
 	return q_exec(&t);
 }
 
+int swo_set_clock(unsigned khz) {
+	struct txn t;
+	if (khz > 0xFFFF)
+		return -1;
+	if (khz < 1000)
+		khz = 1000;
+	q_init(&t);
+	t.tx[t.txc++] = RSWD_MSG(CMD_SWO_CLOCK, 0, khz);
+	return q_exec(&t);
+}
+
 int swdp_open(void) {
 	pthread_create(&swd_thread, NULL, swd_reader, NULL);
 	return 0;
diff --git a/tools/rswdp.h b/tools/rswdp.h
@@ -62,6 +62,7 @@ void swdp_target_reset(int enable);
 
 int swdp_bootloader(void);
 int swdp_set_clock(unsigned khz);
+int swo_set_clock(unsigned khz);
 
 #endif
 
diff --git a/tools/swo.c b/tools/swo.c
@@ -0,0 +1,38 @@
+/* swo.c
+ *
+ * Copyright 2015 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <pthread.h>
+#include <fw/types.h>
+#include <debugger.h>
+
+void process_swo_data(void *_data, unsigned count) {
+	unsigned char *data = _data;
+	char buf[8192];
+	char *p = buf;
+	while (count-- > 0) {
+		p += sprintf(p, "%02x ", *data++);
+	}
+	*p++ = '\n';
+	*p++ = 0;
+	xprintf(XDATA, buf);
+}
+