18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2010 Google, Inc.
48c2ecf20Sopenharmony_ci * Author: Erik Gilling <konkers@android.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2011-2013 NVIDIA Corporation
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "../dev.h"
108c2ecf20Sopenharmony_ci#include "../debug.h"
118c2ecf20Sopenharmony_ci#include "../cdma.h"
128c2ecf20Sopenharmony_ci#include "../channel.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cienum {
178c2ecf20Sopenharmony_ci	HOST1X_OPCODE_SETCLASS	= 0x00,
188c2ecf20Sopenharmony_ci	HOST1X_OPCODE_INCR	= 0x01,
198c2ecf20Sopenharmony_ci	HOST1X_OPCODE_NONINCR	= 0x02,
208c2ecf20Sopenharmony_ci	HOST1X_OPCODE_MASK	= 0x03,
218c2ecf20Sopenharmony_ci	HOST1X_OPCODE_IMM	= 0x04,
228c2ecf20Sopenharmony_ci	HOST1X_OPCODE_RESTART	= 0x05,
238c2ecf20Sopenharmony_ci	HOST1X_OPCODE_GATHER	= 0x06,
248c2ecf20Sopenharmony_ci	HOST1X_OPCODE_SETSTRMID = 0x07,
258c2ecf20Sopenharmony_ci	HOST1X_OPCODE_SETAPPID  = 0x08,
268c2ecf20Sopenharmony_ci	HOST1X_OPCODE_SETPYLD   = 0x09,
278c2ecf20Sopenharmony_ci	HOST1X_OPCODE_INCR_W    = 0x0a,
288c2ecf20Sopenharmony_ci	HOST1X_OPCODE_NONINCR_W = 0x0b,
298c2ecf20Sopenharmony_ci	HOST1X_OPCODE_GATHER_W  = 0x0c,
308c2ecf20Sopenharmony_ci	HOST1X_OPCODE_RESTART_W = 0x0d,
318c2ecf20Sopenharmony_ci	HOST1X_OPCODE_EXTEND	= 0x0e,
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cienum {
358c2ecf20Sopenharmony_ci	HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK	= 0x00,
368c2ecf20Sopenharmony_ci	HOST1X_OPCODE_EXTEND_RELEASE_MLOCK	= 0x01,
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define INVALID_PAYLOAD				0xffffffff
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic unsigned int show_channel_command(struct output *o, u32 val,
428c2ecf20Sopenharmony_ci					 u32 *payload)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	unsigned int mask, subop, num, opcode;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	opcode = val >> 28;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	switch (opcode) {
498c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_SETCLASS:
508c2ecf20Sopenharmony_ci		mask = val & 0x3f;
518c2ecf20Sopenharmony_ci		if (mask) {
528c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [",
538c2ecf20Sopenharmony_ci					    val >> 6 & 0x3ff,
548c2ecf20Sopenharmony_ci					    val >> 16 & 0xfff, mask);
558c2ecf20Sopenharmony_ci			return hweight8(mask);
568c2ecf20Sopenharmony_ci		}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "SETCL(class=%03x)\n", val >> 6 & 0x3ff);
598c2ecf20Sopenharmony_ci		return 0;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_INCR:
628c2ecf20Sopenharmony_ci		num = val & 0xffff;
638c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "INCR(offset=%03x, [",
648c2ecf20Sopenharmony_ci				    val >> 16 & 0xfff);
658c2ecf20Sopenharmony_ci		if (!num)
668c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "])\n");
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci		return num;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_NONINCR:
718c2ecf20Sopenharmony_ci		num = val & 0xffff;
728c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "NONINCR(offset=%03x, [",
738c2ecf20Sopenharmony_ci				    val >> 16 & 0xfff);
748c2ecf20Sopenharmony_ci		if (!num)
758c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "])\n");
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci		return num;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_MASK:
808c2ecf20Sopenharmony_ci		mask = val & 0xffff;
818c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "MASK(offset=%03x, mask=%03x, [",
828c2ecf20Sopenharmony_ci				    val >> 16 & 0xfff, mask);
838c2ecf20Sopenharmony_ci		if (!mask)
848c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "])\n");
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		return hweight16(mask);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_IMM:
898c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "IMM(offset=%03x, data=%03x)\n",
908c2ecf20Sopenharmony_ci				    val >> 16 & 0xfff, val & 0xffff);
918c2ecf20Sopenharmony_ci		return 0;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_RESTART:
948c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "RESTART(offset=%08x)\n", val << 4);
958c2ecf20Sopenharmony_ci		return 0;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_GATHER:
988c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
998c2ecf20Sopenharmony_ci				    val >> 16 & 0xfff, val >> 15 & 0x1,
1008c2ecf20Sopenharmony_ci				    val >> 14 & 0x1, val & 0x3fff);
1018c2ecf20Sopenharmony_ci		return 1;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#if HOST1X_HW >= 6
1048c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_SETSTRMID:
1058c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "SETSTRMID(offset=%06x)\n",
1068c2ecf20Sopenharmony_ci				  val & 0x3fffff);
1078c2ecf20Sopenharmony_ci		return 0;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_SETAPPID:
1108c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "SETAPPID(appid=%02x)\n", val & 0xff);
1118c2ecf20Sopenharmony_ci		return 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_SETPYLD:
1148c2ecf20Sopenharmony_ci		*payload = val & 0xffff;
1158c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "SETPYLD(data=%04x)\n", *payload);
1168c2ecf20Sopenharmony_ci		return 0;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_INCR_W:
1198c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_NONINCR_W:
1208c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "%s(offset=%06x, ",
1218c2ecf20Sopenharmony_ci				  opcode == HOST1X_OPCODE_INCR_W ?
1228c2ecf20Sopenharmony_ci					"INCR_W" : "NONINCR_W",
1238c2ecf20Sopenharmony_ci				  val & 0x3fffff);
1248c2ecf20Sopenharmony_ci		if (*payload == 0) {
1258c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "[])\n");
1268c2ecf20Sopenharmony_ci			return 0;
1278c2ecf20Sopenharmony_ci		} else if (*payload == INVALID_PAYLOAD) {
1288c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "unknown)\n");
1298c2ecf20Sopenharmony_ci			return 0;
1308c2ecf20Sopenharmony_ci		} else {
1318c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "[");
1328c2ecf20Sopenharmony_ci			return *payload;
1338c2ecf20Sopenharmony_ci		}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_GATHER_W:
1368c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "GATHER_W(count=%04x, addr=[",
1378c2ecf20Sopenharmony_ci				  val & 0x3fff);
1388c2ecf20Sopenharmony_ci		return 2;
1398c2ecf20Sopenharmony_ci#endif
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	case HOST1X_OPCODE_EXTEND:
1428c2ecf20Sopenharmony_ci		subop = val >> 24 & 0xf;
1438c2ecf20Sopenharmony_ci		if (subop == HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK)
1448c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "ACQUIRE_MLOCK(index=%d)\n",
1458c2ecf20Sopenharmony_ci					    val & 0xff);
1468c2ecf20Sopenharmony_ci		else if (subop == HOST1X_OPCODE_EXTEND_RELEASE_MLOCK)
1478c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "RELEASE_MLOCK(index=%d)\n",
1488c2ecf20Sopenharmony_ci					    val & 0xff);
1498c2ecf20Sopenharmony_ci		else
1508c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "EXTEND_UNKNOWN(%08x)\n", val);
1518c2ecf20Sopenharmony_ci		return 0;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	default:
1548c2ecf20Sopenharmony_ci		host1x_debug_cont(o, "UNKNOWN\n");
1558c2ecf20Sopenharmony_ci		return 0;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic void show_gather(struct output *o, phys_addr_t phys_addr,
1608c2ecf20Sopenharmony_ci			unsigned int words, struct host1x_cdma *cdma,
1618c2ecf20Sopenharmony_ci			phys_addr_t pin_addr, u32 *map_addr)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	/* Map dmaget cursor to corresponding mem handle */
1648c2ecf20Sopenharmony_ci	u32 offset = phys_addr - pin_addr;
1658c2ecf20Sopenharmony_ci	unsigned int data_count = 0, i;
1668c2ecf20Sopenharmony_ci	u32 payload = INVALID_PAYLOAD;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/*
1698c2ecf20Sopenharmony_ci	 * Sometimes we're given different hardware address to the same
1708c2ecf20Sopenharmony_ci	 * page - in these cases the offset will get an invalid number and
1718c2ecf20Sopenharmony_ci	 * we just have to bail out.
1728c2ecf20Sopenharmony_ci	 */
1738c2ecf20Sopenharmony_ci	if (offset > HOST1X_DEBUG_MAX_PAGE_OFFSET) {
1748c2ecf20Sopenharmony_ci		host1x_debug_output(o, "[address mismatch]\n");
1758c2ecf20Sopenharmony_ci		return;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	for (i = 0; i < words; i++) {
1798c2ecf20Sopenharmony_ci		u32 addr = phys_addr + i * 4;
1808c2ecf20Sopenharmony_ci		u32 val = *(map_addr + offset / 4 + i);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		if (!data_count) {
1838c2ecf20Sopenharmony_ci			host1x_debug_output(o, "%08x: %08x: ", addr, val);
1848c2ecf20Sopenharmony_ci			data_count = show_channel_command(o, val, &payload);
1858c2ecf20Sopenharmony_ci		} else {
1868c2ecf20Sopenharmony_ci			host1x_debug_cont(o, "%08x%s", val,
1878c2ecf20Sopenharmony_ci					    data_count > 1 ? ", " : "])\n");
1888c2ecf20Sopenharmony_ci			data_count--;
1898c2ecf20Sopenharmony_ci		}
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct push_buffer *pb = &cdma->push_buffer;
1968c2ecf20Sopenharmony_ci	struct host1x_job *job;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	host1x_debug_output(o, "PUSHBUF at %pad, %u words\n",
1998c2ecf20Sopenharmony_ci			    &pb->dma, pb->size / 4);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	show_gather(o, pb->dma, pb->size / 4, cdma, pb->dma, pb->mapped);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	list_for_each_entry(job, &cdma->sync_queue, list) {
2048c2ecf20Sopenharmony_ci		unsigned int i;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci		host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n",
2078c2ecf20Sopenharmony_ci				    job, job->syncpt_id, job->syncpt_end,
2088c2ecf20Sopenharmony_ci				    job->first_get, job->timeout,
2098c2ecf20Sopenharmony_ci				    job->num_slots, job->num_unpins);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		for (i = 0; i < job->num_gathers; i++) {
2128c2ecf20Sopenharmony_ci			struct host1x_job_gather *g = &job->gathers[i];
2138c2ecf20Sopenharmony_ci			u32 *mapped;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci			if (job->gather_copy_mapped)
2168c2ecf20Sopenharmony_ci				mapped = (u32 *)job->gather_copy_mapped;
2178c2ecf20Sopenharmony_ci			else
2188c2ecf20Sopenharmony_ci				mapped = host1x_bo_mmap(g->bo);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci			if (!mapped) {
2218c2ecf20Sopenharmony_ci				host1x_debug_output(o, "[could not mmap]\n");
2228c2ecf20Sopenharmony_ci				continue;
2238c2ecf20Sopenharmony_ci			}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci			host1x_debug_output(o, "    GATHER at %pad+%#x, %d words\n",
2268c2ecf20Sopenharmony_ci					    &g->base, g->offset, g->words);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci			show_gather(o, g->base + g->offset, g->words, cdma,
2298c2ecf20Sopenharmony_ci				    g->base, mapped);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci			if (!job->gather_copy_mapped)
2328c2ecf20Sopenharmony_ci				host1x_bo_munmap(g->bo, mapped);
2338c2ecf20Sopenharmony_ci		}
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci#if HOST1X_HW >= 6
2388c2ecf20Sopenharmony_ci#include "debug_hw_1x06.c"
2398c2ecf20Sopenharmony_ci#else
2408c2ecf20Sopenharmony_ci#include "debug_hw_1x01.c"
2418c2ecf20Sopenharmony_ci#endif
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic const struct host1x_debug_ops host1x_debug_ops = {
2448c2ecf20Sopenharmony_ci	.show_channel_cdma = host1x_debug_show_channel_cdma,
2458c2ecf20Sopenharmony_ci	.show_channel_fifo = host1x_debug_show_channel_fifo,
2468c2ecf20Sopenharmony_ci	.show_mlocks = host1x_debug_show_mlocks,
2478c2ecf20Sopenharmony_ci};
248