msm: kgsl: Add the GMU TCM registers to snapshot

Dump the GMU instruction TCM and data TCM in the A6XX
snapshot if a GMU exists and is enabled.

CRs-Fixed: 2017390
Change-Id: Ia2cda6ff5299ed03a17ce3f3540729f57266248f
Signed-off-by: Kyle Piefer <kpiefer@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index e82975e..7d87096 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -18,7 +18,7 @@
 #include "adreno_snapshot.h"
 #include "a6xx_reg.h"
 #include "adreno_a6xx.h"
-
+#include "kgsl_gmu.h"
 
 #define A6XX_NUM_CTXTS 2
 
@@ -202,6 +202,11 @@
 	0x3410, 0x3410, 0x3800, 0x3801,
 };
 
+static const unsigned int a6xx_gmu_registers[] = {
+	/* GMU */
+	0x1B400, 0x1C3FF, 0x1C400, 0x1D3FF,
+};
+
 static const struct adreno_vbif_snapshot_registers
 a6xx_vbif_snapshot_registers[] = {
 	{ 0x20040000, 0xFF000000, a6xx_vbif_ver_20xxxxxx_registers,
@@ -950,6 +955,61 @@
 	}
 }
 
+static size_t a6xx_snapshot_dump_gmu_registers(struct kgsl_device *device,
+		u8 *buf, size_t remain, void *priv)
+{
+	struct kgsl_snapshot_regs *header = (struct kgsl_snapshot_regs *)buf;
+	struct kgsl_snapshot_registers *regs = priv;
+	unsigned int *data = (unsigned int *)(buf + sizeof(*header));
+	int count = 0, j, k;
+
+	/* Figure out how many registers we are going to dump */
+	for (j = 0; j < regs->count; j++) {
+		int start = regs->regs[j * 2];
+		int end = regs->regs[j * 2 + 1];
+
+		count += (end - start + 1);
+	}
+
+	if (remain < (count * 8) + sizeof(*header)) {
+		SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+		return 0;
+	}
+
+	for (j = 0; j < regs->count; j++) {
+		unsigned int start = regs->regs[j * 2];
+		unsigned int end = regs->regs[j * 2 + 1];
+
+		for (k = start; k <= end; k++) {
+			unsigned int val;
+
+			kgsl_gmu_regread(device, k, &val);
+			*data++ = k;
+			*data++ = val;
+		}
+	}
+
+	header->count = count;
+
+	/* Return the size of the section */
+	return (count * 8) + sizeof(*header);
+}
+
+static void a6xx_snapshot_gmu(struct kgsl_device *device,
+		struct kgsl_snapshot *snapshot)
+{
+	struct kgsl_snapshot_registers gmu_regs = {
+		.regs = a6xx_gmu_registers,
+		.count = ARRAY_SIZE(a6xx_gmu_registers) / 2,
+	};
+
+	if (!kgsl_gmu_isenabled(device))
+		return;
+
+	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
+			snapshot, a6xx_snapshot_dump_gmu_registers, &gmu_regs);
+}
+
 static void _a6xx_do_crashdump(struct kgsl_device *device)
 {
 	unsigned long wait_time;
@@ -1052,6 +1112,9 @@
 	a6xx_snapshot_dbgahb_regs(device, snapshot);
 
 	a6xx_snapshot_debugbus(device, snapshot);
+
+	/* GMU TCM data dumped through AHB */
+	a6xx_snapshot_gmu(device, snapshot);
 }
 
 static int _a6xx_crashdump_init_mvc(uint64_t *ptr, uint64_t *offset)