msm: kgsl: Add snapshot and postmortem support for A3XX

Modify postmortem and GPU snapshot to dump A3XX debug sections
and registers.

Change-Id: Ic0dedbadb28be76d5ad2dcf214bc88b15dd7342e
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index 04d53c0..5189388 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -26,6 +26,7 @@
 	adreno_a2xx_trace.o \
 	adreno_a2xx_snapshot.o \
 	adreno_a3xx.o \
+	adreno_a3xx_snapshot.o \
 	adreno.o
 
 msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o
diff --git a/drivers/gpu/msm/a2xx_reg.h b/drivers/gpu/msm/a2xx_reg.h
index 50b2745..4c0bd19 100644
--- a/drivers/gpu/msm/a2xx_reg.h
+++ b/drivers/gpu/msm/a2xx_reg.h
@@ -278,6 +278,7 @@
 #define REG_CP_ME_CNTL                   0x01F6
 #define REG_CP_ME_RAM_DATA               0x01FA
 #define REG_CP_ME_RAM_WADDR              0x01F8
+#define REG_CP_ME_RAM_RADDR              0x01F9
 #define REG_CP_ME_STATUS                 0x01F7
 #define REG_CP_PFP_UCODE_ADDR            0x00C0
 #define REG_CP_PFP_UCODE_DATA            0x00C1
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 84c83b8..1806886 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -67,9 +67,15 @@
 #define A3XX_RBBM_RBBM_CTL 0x100
 #define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC
 #define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED
+#define A3XX_RBBM_DEBUG_BUS_CTL             0x111
+#define A3XX_RBBM_DEBUG_BUS_DATA_STATUS     0x112
 /* Following two are same as on A2XX, just in a different place */
 #define A3XX_CP_PFP_UCODE_ADDR 0x1C9
 #define A3XX_CP_PFP_UCODE_DATA 0x1CA
+#define A3XX_CP_ROQ_ADDR 0x1CC
+#define A3XX_CP_ROQ_DATA 0x1CD
+#define A3XX_CP_MEQ_ADDR 0x1DA
+#define A3XX_CP_MEQ_DATA 0x1DB
 #define A3XX_CP_HW_FAULT  0x45C
 #define A3XX_CP_AHB_FAULT 0x54D
 #define A3XX_CP_PROTECT_CTRL 0x45E
@@ -142,6 +148,8 @@
 #define A3XX_GRAS_CL_USER_PLANE_Y5 0xCB5
 #define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
 #define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
+#define A3XX_VPC_VPC_DEBUG_RAM_SEL 0xE61
+#define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
 #define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
 #define A3XX_GRAS_CL_CLIP_CNTL 0x2040
 #define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
@@ -450,4 +458,34 @@
 #define VPC_VPCVARPSREPLMODE_COMPONENT16 28
 #define VPC_VPCVARPSREPLMODE_COMPONENT17 30
 
+/* RBBM Debug bus block IDs */
+#define RBBM_BLOCK_ID_NONE             0x0
+#define RBBM_BLOCK_ID_CP               0x1
+#define RBBM_BLOCK_ID_RBBM             0x2
+#define RBBM_BLOCK_ID_VBIF             0x3
+#define RBBM_BLOCK_ID_HLSQ             0x4
+#define RBBM_BLOCK_ID_UCHE             0x5
+#define RBBM_BLOCK_ID_PC               0x8
+#define RBBM_BLOCK_ID_VFD              0x9
+#define RBBM_BLOCK_ID_VPC              0xa
+#define RBBM_BLOCK_ID_TSE              0xb
+#define RBBM_BLOCK_ID_RAS              0xc
+#define RBBM_BLOCK_ID_VSC              0xd
+#define RBBM_BLOCK_ID_SP_0             0x10
+#define RBBM_BLOCK_ID_SP_1             0x11
+#define RBBM_BLOCK_ID_SP_2             0x12
+#define RBBM_BLOCK_ID_SP_3             0x13
+#define RBBM_BLOCK_ID_TPL1_0           0x18
+#define RBBM_BLOCK_ID_TPL1_1           0x19
+#define RBBM_BLOCK_ID_TPL1_2           0x1a
+#define RBBM_BLOCK_ID_TPL1_3           0x1b
+#define RBBM_BLOCK_ID_RB_0             0x20
+#define RBBM_BLOCK_ID_RB_1             0x21
+#define RBBM_BLOCK_ID_RB_2             0x22
+#define RBBM_BLOCK_ID_RB_3             0x23
+#define RBBM_BLOCK_ID_MARB_0           0x28
+#define RBBM_BLOCK_ID_MARB_1           0x29
+#define RBBM_BLOCK_ID_MARB_2           0x2a
+#define RBBM_BLOCK_ID_MARB_3           0x2b
+
 #endif
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 95b6253..9c2d704 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -107,6 +107,10 @@
 extern const unsigned int a200_registers_count;
 extern const unsigned int a220_registers_count;
 
+/* A3XX register set defined in adreno_a3xx.c */
+extern const unsigned int a3xx_registers[];
+extern const unsigned int a3xx_registers_count;
+
 int adreno_idle(struct kgsl_device *device, unsigned int timeout);
 void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
 				unsigned int *value);
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
index 30d692b..091db22 100644
--- a/drivers/gpu/msm/adreno_a2xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c
@@ -224,24 +224,6 @@
 	return DEBUG_SECTION_SZ(MIUDEBUG_COUNT);
 }
 
-/* Helper function to snapshot a section of indexed registers */
-
-static void *a2xx_snapshot_indexed_registers(struct kgsl_device *device,
-		void *snapshot, int *remain,
-		unsigned int index, unsigned int data, unsigned int start,
-		unsigned int count)
-{
-	struct kgsl_snapshot_indexed_registers iregs;
-	iregs.index = index;
-	iregs.data = data;
-	iregs.start = start;
-	iregs.count = count;
-
-	return kgsl_snapshot_add_section(device,
-		 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
-		 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
-}
-
 /* A2XX GPU snapshot function - this is where all of the A2XX specific
  * bits and pieces are grabbed into the snapshot memory
  */
@@ -269,12 +251,12 @@
 		kgsl_snapshot_dump_regs, &regs);
 
 	/* CP_STATE_DEBUG indexed registers */
-	snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
 			remain, REG_CP_STATE_DEBUG_INDEX,
 			REG_CP_STATE_DEBUG_DATA, 0x0, 0x14);
 
 	/* CP_ME indexed registers */
-	snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
 			remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
 			64, 44);
 
@@ -293,7 +275,7 @@
 
 	/* SU debug indexed registers (only for < 470) */
 	if (!adreno_is_a22x(adreno_dev))
-		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+		snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
 				remain, REG_PA_SU_DEBUG_CNTL,
 				REG_PA_SU_DEBUG_DATA,
 				0, 0x1B);
@@ -304,26 +286,26 @@
 			a2xx_snapshot_cpdebug, NULL);
 
 	/* MH debug indexed registers */
-	snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
 			remain, MH_DEBUG_CTRL, MH_DEBUG_DATA, 0x0, 0x40);
 
 	/* Leia only register sets */
 	if (adreno_is_a22x(adreno_dev)) {
 		/* RB DEBUG indexed regisers */
-		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+		snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
 			remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA, 0, 8);
 
 		/* RB DEBUG indexed registers bank 2 */
-		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+		snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
 			remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA + 0x1000,
 			0, 8);
 
 		/* PC_DEBUG indexed registers */
-		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+		snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
 			remain, REG_PC_DEBUG_CNTL, REG_PC_DEBUG_DATA, 0, 8);
 
 		/* GRAS_DEBUG indexed registers */
-		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+		snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
 			remain, REG_GRAS_DEBUG_CNTL, REG_GRAS_DEBUG_DATA, 0, 4);
 
 		/* MIU debug registers */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index cbc7bed..1bad811 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -19,6 +19,51 @@
 #include "kgsl_cffdump.h"
 #include "a3xx_reg.h"
 
+/*
+ * Set of registers to dump for A3XX on postmortem and snapshot.
+ * Registers in pairs - first value is the start offset, second
+ * is the stop offset (inclusive)
+ */
+
+const unsigned int a3xx_registers[] = {
+	0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027,
+	0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c,
+	0x0060, 0x006c, 0x0080, 0x0082, 0x0084, 0x0088, 0x0090, 0x00e5,
+	0x00ea, 0x00ed, 0x0100, 0x0100, 0x0110, 0x0123, 0x01c0, 0x01c1,
+	0x01c3, 0x01c5, 0x01c7, 0x01c7, 0x01d5, 0x01d9, 0x01dc, 0x01dd,
+	0x01ea, 0x01ea, 0x01ee, 0x01f1, 0x01f5, 0x01f5, 0x01fc, 0x01ff,
+	0x0440, 0x0440, 0x0443, 0x0443, 0x0445, 0x0445, 0x044d, 0x044f,
+	0x0452, 0x0452, 0x0454, 0x046f, 0x047c, 0x047c, 0x047f, 0x047f,
+	0x0579, 0x057f, 0x0600, 0x0602, 0x0605, 0x0607, 0x060a, 0x060e,
+	0x0612, 0x0614, 0x0c01, 0x0c02, 0x0c06, 0x0c1d, 0x0c3d, 0x0c3f,
+	0x0c48, 0x0c4b, 0x0c80, 0x0c80, 0x0c88, 0x0c8b, 0x0ca0, 0x0cb7,
+	0x0cc0, 0x0cc1, 0x0cc6, 0x0cc7, 0x0ce4, 0x0ce5, 0x0e00, 0x0e05,
+	0x0e0c, 0x0e0c, 0x0e22, 0x0e23, 0x0e41, 0x0e45, 0x0e64, 0x0e65,
+	0x0e80, 0x0e82, 0x0e84, 0x0e89, 0x0ea0, 0x0ea1, 0x0ea4, 0x0ea7,
+	0x0ec4, 0x0ecb, 0x0ee0, 0x0ee0, 0x0f00, 0x0f01, 0x0f03, 0x0f09,
+	0x2040, 0x2040, 0x2044, 0x2044, 0x2048, 0x204d, 0x2068, 0x2069,
+	0x206c, 0x206d, 0x2070, 0x2070, 0x2072, 0x2072, 0x2074, 0x2075,
+	0x2079, 0x207a, 0x20c0, 0x20d3, 0x20e4, 0x20ef, 0x2100, 0x2109,
+	0x210c, 0x210c, 0x210e, 0x210e, 0x2110, 0x2111, 0x2114, 0x2115,
+	0x21e4, 0x21e4, 0x21ea, 0x21ea, 0x21ec, 0x21ed, 0x21f0, 0x21f0,
+	0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e,
+	0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8,
+	0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7,
+	0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356,
+	0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d,
+	0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472,
+	0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef,
+	0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511,
+	0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed,
+	0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a,
+	0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce,
+	0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec,
+	0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749,
+	0x2750, 0x2756, 0x2760, 0x2760,
+};
+
+const unsigned int a3xx_registers_count = ARRAY_SIZE(a3xx_registers) / 2;
+
 /* Simple macro to facilitate bit setting in the gmem2sys and sys2gmem
  * functions.
  */
@@ -2531,6 +2576,10 @@
 	adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, 0x00003000);
 }
 
+/* Defined in adreno_a3xx_snapshot.c */
+void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
+	int *remain, int hang);
+
 struct adreno_gpudev adreno_a3xx_gpudev = {
 	.reg_rbbm_status = A3XX_RBBM_STATUS,
 	.reg_cp_pfp_ucode_addr = A3XX_CP_PFP_UCODE_ADDR,
@@ -2544,4 +2593,5 @@
 	.irq_handler = a3xx_irq_handler,
 	.busy_cycles = a3xx_busy_cycles,
 	.start = a3xx_start,
+	.snapshot = a3xx_snapshot,
 };
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
new file mode 100644
index 0000000..aade50c
--- /dev/null
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -0,0 +1,296 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "kgsl.h"
+#include "adreno.h"
+#include "kgsl_snapshot.h"
+#include "a3xx_reg.h"
+
+#define DEBUG_SECTION_SZ(_dwords) (((_dwords) * sizeof(unsigned int)) \
+		+ sizeof(struct kgsl_snapshot_debug))
+
+#define VPC_MEMORY_BANKS 4
+#define VPC_MEMORY_SIZE 512
+
+static int a3xx_snapshot_vpc_memory(struct kgsl_device *device, void *snapshot,
+		int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int size = VPC_MEMORY_BANKS * VPC_MEMORY_SIZE;
+	int bank, addr, i = 0;
+
+	if (remain < DEBUG_SECTION_SZ(size)) {
+		SNAPSHOT_ERR_NOMEM(device, "VPC MEMORY");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_VPC_MEMORY;
+	header->size = size;
+
+	for (bank = 0; bank < VPC_MEMORY_BANKS; bank++) {
+		for (addr = 0; addr < VPC_MEMORY_SIZE; addr++) {
+			unsigned int val = bank | (addr << 4);
+			adreno_regwrite(device,
+				A3XX_VPC_VPC_DEBUG_RAM_SEL, val);
+			adreno_regread(device,
+				A3XX_VPC_VPC_DEBUG_RAM_READ, &data[i++]);
+		}
+	}
+
+	return DEBUG_SECTION_SZ(size);
+}
+
+#define CP_MEQ_SIZE 16
+static int a3xx_snapshot_cp_meq(struct kgsl_device *device, void *snapshot,
+		int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < DEBUG_SECTION_SZ(CP_MEQ_SIZE)) {
+		SNAPSHOT_ERR_NOMEM(device, "CP MEQ DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_CP_MEQ;
+	header->size = CP_MEQ_SIZE;
+
+	adreno_regwrite(device, A3XX_CP_MEQ_ADDR, 0x0);
+	for (i = 0; i < CP_MEQ_SIZE; i++)
+		adreno_regread(device, A3XX_CP_MEQ_DATA, &data[i]);
+
+	return DEBUG_SECTION_SZ(CP_MEQ_SIZE);
+}
+
+static int a3xx_snapshot_cp_pm4_ram(struct kgsl_device *device, void *snapshot,
+		int remain, void *priv)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i, size = adreno_dev->pm4_fw_size >> 2;
+
+	if (remain < DEBUG_SECTION_SZ(size)) {
+		SNAPSHOT_ERR_NOMEM(device, "CP PM4 RAM DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_CP_PM4_RAM;
+	header->size = size;
+
+	/*
+	 * Read the firmware from the GPU rather than use our cache in order to
+	 * try to catch mis-programming or corruption in the hardware.  We do
+	 * use the cached version of the size, however, instead of trying to
+	 * maintain always changing hardcoded constants
+	 */
+
+	adreno_regwrite(device, REG_CP_ME_RAM_RADDR, 0x0);
+	for (i = 0; i < adreno_dev->pm4_fw_size >> 2; i++)
+		adreno_regread(device, REG_CP_ME_RAM_DATA, &data[i]);
+
+	return DEBUG_SECTION_SZ(size);
+}
+
+static int a3xx_snapshot_cp_pfp_ram(struct kgsl_device *device, void *snapshot,
+		int remain, void *priv)
+{
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i, size = adreno_dev->pfp_fw_size >> 2;
+
+	if (remain < DEBUG_SECTION_SZ(size)) {
+		SNAPSHOT_ERR_NOMEM(device, "CP PFP RAM DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_CP_PFP_RAM;
+	header->size = size;
+
+	/*
+	 * Read the firmware from the GPU rather than use our cache in order to
+	 * try to catch mis-programming or corruption in the hardware.  We do
+	 * use the cached version of the size, however, instead of trying to
+	 * maintain always changing hardcoded constants
+	 */
+	kgsl_regwrite(device, A3XX_CP_PFP_UCODE_ADDR, 0x0);
+	for (i = 0; i < adreno_dev->pfp_fw_size >> 2; i++)
+		adreno_regread(device, A3XX_CP_PFP_UCODE_DATA, &data[i]);
+
+	return DEBUG_SECTION_SZ(size);
+}
+
+#define CP_ROQ_SIZE 128
+
+static int a3xx_snapshot_cp_roq(struct kgsl_device *device, void *snapshot,
+		int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < DEBUG_SECTION_SZ(CP_ROQ_SIZE)) {
+		SNAPSHOT_ERR_NOMEM(device, "CP ROQ DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_CP_ROQ;
+	header->size = CP_ROQ_SIZE;
+
+	adreno_regwrite(device, A3XX_CP_ROQ_ADDR, 0x0);
+	for (i = 0; i < CP_ROQ_SIZE; i++)
+		adreno_regread(device, A3XX_CP_ROQ_DATA, &data[i]);
+
+	return DEBUG_SECTION_SZ(CP_ROQ_SIZE);
+}
+
+#define DEBUGFS_BLOCK_SIZE 0x40
+
+static int a3xx_snapshot_debugbus_block(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv)
+{
+	struct kgsl_snapshot_debugbus *header = snapshot;
+	unsigned int id = (unsigned int) priv;
+	unsigned int val;
+	int i;
+	unsigned int *data = snapshot + sizeof(*header);
+	int size =
+		(DEBUGFS_BLOCK_SIZE * sizeof(unsigned int)) + sizeof(*header);
+
+	if (remain < size) {
+		SNAPSHOT_ERR_NOMEM(device, "DEBUGBUS");
+		return 0;
+	}
+
+	val = (id << 0x06) | (1 << 0x10);
+
+	header->id = id;
+	header->count = DEBUGFS_BLOCK_SIZE;
+
+	for (i = 0; i < DEBUGFS_BLOCK_SIZE; i++) {
+		adreno_regwrite(device, A3XX_RBBM_DEBUG_BUS_CTL, val | i);
+		adreno_regread(device, A3XX_RBBM_DEBUG_BUS_DATA_STATUS,
+			&data[i]);
+	}
+
+	return size;
+}
+
+static unsigned int debugbus_blocks[] = {
+	RBBM_BLOCK_ID_CP,
+	RBBM_BLOCK_ID_RBBM,
+	RBBM_BLOCK_ID_VBIF,
+	RBBM_BLOCK_ID_HLSQ,
+	RBBM_BLOCK_ID_UCHE,
+	RBBM_BLOCK_ID_PC,
+	RBBM_BLOCK_ID_VFD,
+	RBBM_BLOCK_ID_VPC,
+	RBBM_BLOCK_ID_TSE,
+	RBBM_BLOCK_ID_RAS,
+	RBBM_BLOCK_ID_VSC,
+	RBBM_BLOCK_ID_SP_0,
+	RBBM_BLOCK_ID_SP_1,
+	RBBM_BLOCK_ID_SP_2,
+	RBBM_BLOCK_ID_SP_3,
+	RBBM_BLOCK_ID_TPL1_0,
+	RBBM_BLOCK_ID_TPL1_1,
+	RBBM_BLOCK_ID_TPL1_2,
+	RBBM_BLOCK_ID_TPL1_3,
+	RBBM_BLOCK_ID_RB_0,
+	RBBM_BLOCK_ID_RB_1,
+	RBBM_BLOCK_ID_RB_2,
+	RBBM_BLOCK_ID_RB_3,
+	RBBM_BLOCK_ID_MARB_0,
+	RBBM_BLOCK_ID_MARB_1,
+	RBBM_BLOCK_ID_MARB_2,
+	RBBM_BLOCK_ID_MARB_3,
+};
+
+static void *a3xx_snapshot_debugbus(struct kgsl_device *device,
+	void *snapshot, int *remain)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(debugbus_blocks); i++) {
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUGBUS, snapshot, remain,
+			a3xx_snapshot_debugbus_block,
+			(void *) debugbus_blocks[i]);
+	}
+
+	return snapshot;
+}
+
+/* A3XX GPU snapshot function - this is where all of the A3XX specific
+ * bits and pieces are grabbed into the snapshot memory
+ */
+
+void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
+	int *remain, int hang)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	struct kgsl_snapshot_registers regs;
+
+	regs.regs = (unsigned int *) a3xx_registers;
+	regs.count = a3xx_registers_count;
+
+	/* Master set of (non debug) registers */
+	snapshot = kgsl_snapshot_add_section(device,
+		KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain,
+		kgsl_snapshot_dump_regs, &regs);
+
+	/* CP_STATE_DEBUG indexed registers */
+	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
+			remain, REG_CP_STATE_DEBUG_INDEX,
+			REG_CP_STATE_DEBUG_DATA, 0x0, 0x14);
+
+	/* CP_ME indexed registers */
+	snapshot = kgsl_snapshot_indexed_registers(device, snapshot,
+			remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
+			64, 44);
+
+	/* VPC memory */
+	snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a3xx_snapshot_vpc_memory, NULL);
+
+	/* CP MEQ */
+	snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a3xx_snapshot_cp_meq, NULL);
+
+	/* CP PFP and PM4 */
+	/* Reading these will hang the GPU if it isn't already hung */
+
+	if (hang) {
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a3xx_snapshot_cp_pfp_ram, NULL);
+
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a3xx_snapshot_cp_pm4_ram, NULL);
+	}
+
+	/* CP ROQ */
+	snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a3xx_snapshot_cp_roq, NULL);
+
+	snapshot = a3xx_snapshot_debugbus(device, snapshot, remain);
+
+	return snapshot;
+}
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 7f054b1..98e3810 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -24,6 +24,7 @@
 #include "kgsl_pwrctrl.h"
 
 #include "a2xx_reg.h"
+#include "a3xx_reg.h"
 
 #define INVALID_RB_CMD 0xaaaaaaaa
 #define NUM_DWORDS_OF_RINGBUFFER_HISTORY 100
@@ -362,29 +363,160 @@
 	}
 }
 
-static int adreno_dump(struct kgsl_device *device)
+static void adreno_dump_a3xx(struct kgsl_device *device)
 {
 	unsigned int r1, r2, r3, rbbm_status;
-	unsigned int cp_ib1_base, cp_ib1_bufsz, cp_stat;
-	unsigned int cp_ib2_base, cp_ib2_bufsz;
-	unsigned int pt_base, cur_pt_base;
-	unsigned int cp_rb_base, rb_count;
-	unsigned int cp_rb_wptr, cp_rb_rptr;
-	unsigned int i;
-	int result = 0;
-	uint32_t *rb_copy;
-	const uint32_t *rb_vaddr;
-	int num_item = 0;
-	int read_idx, write_idx;
-	unsigned int ts_processed;
-
-	static struct ib_list ib_list;
-
+	unsigned int cp_stat, rb_count;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	mb();
+	kgsl_regread(device, adreno_dev->gpudev->reg_rbbm_status, &rbbm_status);
+	KGSL_LOG_DUMP(device, "RBBM:   STATUS   = %08X\n", rbbm_status);
 
-	kgsl_regread(device, REG_RBBM_STATUS, &rbbm_status);
+	{
+		struct log_field lines[] = {
+			{rbbm_status & BIT(0),  "HI busy     "},
+			{rbbm_status & BIT(1),  "CP ME busy  "},
+			{rbbm_status & BIT(2),  "CP PFP busy "},
+			{rbbm_status & BIT(14), "CP NRT busy "},
+			{rbbm_status & BIT(15), "VBIF busy   "},
+			{rbbm_status & BIT(16), "TSE busy    "},
+			{rbbm_status & BIT(17), "RAS busy    "},
+			{rbbm_status & BIT(18), "RB busy     "},
+			{rbbm_status & BIT(19), "PC DCALL bsy"},
+			{rbbm_status & BIT(20), "PC VSD busy "},
+			{rbbm_status & BIT(21), "VFD busy    "},
+			{rbbm_status & BIT(22), "VPC busy    "},
+			{rbbm_status & BIT(23), "UCHE busy   "},
+			{rbbm_status & BIT(24), "SP busy     "},
+			{rbbm_status & BIT(25), "TPL1 busy   "},
+			{rbbm_status & BIT(26), "MARB busy   "},
+			{rbbm_status & BIT(27), "VSC busy    "},
+			{rbbm_status & BIT(28), "ARB busy    "},
+			{rbbm_status & BIT(29), "HLSQ busy   "},
+			{rbbm_status & BIT(30), "GPU bsy noHC"},
+			{rbbm_status & BIT(31), "GPU busy    "},
+			};
+		adreno_dump_fields(device, " STATUS=", lines,
+				ARRAY_SIZE(lines));
+	}
+
+	kgsl_regread(device, REG_CP_RB_BASE, &r1);
+	kgsl_regread(device, REG_CP_RB_CNTL, &r2);
+	rb_count = 2 << (r2 & (BIT(6) - 1));
+	kgsl_regread(device, REG_CP_RB_RPTR_ADDR, &r3);
+	KGSL_LOG_DUMP(device,
+		"CP_RB:  BASE = %08X | CNTL   = %08X | RPTR_ADDR = %08X"
+		"| rb_count = %08X\n", r1, r2, r3, rb_count);
+
+	kgsl_regread(device, REG_CP_RB_RPTR, &r1);
+	kgsl_regread(device, REG_CP_RB_WPTR, &r2);
+	kgsl_regread(device, REG_CP_RB_RPTR_WR, &r3);
+	KGSL_LOG_DUMP(device,
+		"        RPTR = %08X | WPTR   = %08X | RPTR_WR   = %08X"
+		"\n", r1, r2, r3);
+
+	kgsl_regread(device, REG_CP_IB1_BASE, &r1);
+	kgsl_regread(device, REG_CP_IB1_BUFSZ, &r2);
+	KGSL_LOG_DUMP(device, "CP_IB1: BASE = %08X | BUFSZ  = %d\n", r1, r2);
+
+	kgsl_regread(device, REG_CP_ME_CNTL, &r1);
+	kgsl_regread(device, REG_CP_ME_STATUS, &r2);
+	KGSL_LOG_DUMP(device, "CP_ME:  CNTL = %08X | STATUS = %08X\n", r1, r2);
+
+	kgsl_regread(device, REG_CP_STAT, &cp_stat);
+	KGSL_LOG_DUMP(device, "CP_STAT      = %08X\n", cp_stat);
+#ifndef CONFIG_MSM_KGSL_PSTMRTMDMP_CP_STAT_NO_DETAIL
+	{
+		struct log_field lns[] = {
+			{cp_stat & BIT(0), "WR_BSY     0"},
+			{cp_stat & BIT(1), "RD_RQ_BSY  1"},
+			{cp_stat & BIT(2), "RD_RTN_BSY 2"},
+		};
+		adreno_dump_fields(device, "    MIU=", lns, ARRAY_SIZE(lns));
+	}
+	{
+		struct log_field lns[] = {
+			{cp_stat & BIT(5), "RING_BUSY  5"},
+			{cp_stat & BIT(6), "NDRCTS_BSY 6"},
+			{cp_stat & BIT(7), "NDRCT2_BSY 7"},
+			{cp_stat & BIT(9), "ST_BUSY    9"},
+			{cp_stat & BIT(10), "BUSY      10"},
+		};
+		adreno_dump_fields(device, "    CSF=", lns, ARRAY_SIZE(lns));
+	}
+	{
+		struct log_field lns[] = {
+			{cp_stat & BIT(11), "RNG_Q_BSY 11"},
+			{cp_stat & BIT(12), "NDRCTS_Q_B12"},
+			{cp_stat & BIT(13), "NDRCT2_Q_B13"},
+			{cp_stat & BIT(16), "ST_QUEUE_B16"},
+			{cp_stat & BIT(17), "PFP_BUSY  17"},
+		};
+		adreno_dump_fields(device, "   RING=", lns, ARRAY_SIZE(lns));
+	}
+	{
+		struct log_field lns[] = {
+			{cp_stat & BIT(3), "RBIU_BUSY  3"},
+			{cp_stat & BIT(4), "RCIU_BUSY  4"},
+			{cp_stat & BIT(8), "EVENT_BUSY 8"},
+			{cp_stat & BIT(18), "MQ_RG_BSY 18"},
+			{cp_stat & BIT(19), "MQ_NDRS_BS19"},
+			{cp_stat & BIT(20), "MQ_NDR2_BS20"},
+			{cp_stat & BIT(21), "MIU_WC_STL21"},
+			{cp_stat & BIT(22), "CP_NRT_BSY22"},
+			{cp_stat & BIT(23), "3D_BUSY   23"},
+			{cp_stat & BIT(26), "ME_BUSY   26"},
+			{cp_stat & BIT(27), "RB_FFO_BSY27"},
+			{cp_stat & BIT(28), "CF_FFO_BSY28"},
+			{cp_stat & BIT(29), "PS_FFO_BSY29"},
+			{cp_stat & BIT(30), "VS_FFO_BSY30"},
+			{cp_stat & BIT(31), "CP_BUSY   31"},
+		};
+		adreno_dump_fields(device, " CP_STT=", lns, ARRAY_SIZE(lns));
+	}
+#endif
+
+	kgsl_regread(device, A3XX_RBBM_INT_0_STATUS, &r1);
+	KGSL_LOG_DUMP(device, "MSTR_INT_SGNL = %08X\n", r1);
+	{
+		struct log_field ints[] = {
+			{r1 & BIT(0),  "RBBM_GPU_IDLE 0"},
+			{r1 & BIT(1),  "RBBM_AHB_ERROR 1"},
+			{r1 & BIT(2),  "RBBM_REG_TIMEOUT 2"},
+			{r1 & BIT(3),  "RBBM_ME_MS_TIMEOUT 3"},
+			{r1 & BIT(4),  "RBBM_PFP_MS_TIMEOUT 4"},
+			{r1 & BIT(5),  "RBBM_ATB_BUS_OVERFLOW 5"},
+			{r1 & BIT(6),  "VFD_ERROR 6"},
+			{r1 & BIT(7),  "CP_SW_INT 7"},
+			{r1 & BIT(8),  "CP_T0_PACKET_IN_IB 8"},
+			{r1 & BIT(9),  "CP_OPCODE_ERROR 9"},
+			{r1 & BIT(10), "CP_RESERVED_BIT_ERROR 10"},
+			{r1 & BIT(11), "CP_HW_FAULT 11"},
+			{r1 & BIT(12), "CP_DMA 12"},
+			{r1 & BIT(13), "CP_IB2_INT 13"},
+			{r1 & BIT(14), "CP_IB1_INT 14"},
+			{r1 & BIT(15), "CP_RB_INT 15"},
+			{r1 & BIT(16), "CP_REG_PROTECT_FAULT 16"},
+			{r1 & BIT(17), "CP_RB_DONE_TS 17"},
+			{r1 & BIT(18), "CP_VS_DONE_TS 18"},
+			{r1 & BIT(19), "CP_PS_DONE_TS 19"},
+			{r1 & BIT(20), "CACHE_FLUSH_TS 20"},
+			{r1 & BIT(21), "CP_AHB_ERROR_HALT 21"},
+			{r1 & BIT(24), "MISC_HANG_DETECT 24"},
+			{r1 & BIT(25), "UCHE_OOB_ACCESS 25"},
+		};
+		adreno_dump_fields(device, "INT_SGNL=", ints, ARRAY_SIZE(ints));
+	}
+}
+
+static void adreno_dump_a2xx(struct kgsl_device *device)
+{
+	unsigned int r1, r2, r3, rbbm_status;
+	unsigned int cp_stat, rb_count;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	kgsl_regread(device, adreno_dev->gpudev->reg_rbbm_status, &rbbm_status);
+
 	kgsl_regread(device, REG_RBBM_PM_OVERRIDE1, &r2);
 	kgsl_regread(device, REG_RBBM_PM_OVERRIDE2, &r3);
 	KGSL_LOG_DUMP(device, "RBBM:   STATUS   = %08X | PM_OVERRIDE1 = %08X | "
@@ -426,37 +558,33 @@
 				ARRAY_SIZE(lines));
 	}
 
-	kgsl_regread(device, REG_CP_RB_BASE, &cp_rb_base);
+	kgsl_regread(device, REG_CP_RB_BASE, &r1);
 	kgsl_regread(device, REG_CP_RB_CNTL, &r2);
 	rb_count = 2 << (r2 & (BIT(6)-1));
 	kgsl_regread(device, REG_CP_RB_RPTR_ADDR, &r3);
 	KGSL_LOG_DUMP(device,
 		"CP_RB:  BASE = %08X | CNTL   = %08X | RPTR_ADDR = %08X"
-		" | rb_count = %08X\n", cp_rb_base, r2, r3, rb_count);
+		"| rb_count = %08X\n", r1, r2, r3, rb_count);
 	{
 		struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
 		if (rb->sizedwords != rb_count)
 			rb_count = rb->sizedwords;
 	}
 
-	kgsl_regread(device, REG_CP_RB_RPTR, &cp_rb_rptr);
-	kgsl_regread(device, REG_CP_RB_WPTR, &cp_rb_wptr);
+	kgsl_regread(device, REG_CP_RB_RPTR, &r1);
+	kgsl_regread(device, REG_CP_RB_WPTR, &r2);
 	kgsl_regread(device, REG_CP_RB_RPTR_WR, &r3);
 	KGSL_LOG_DUMP(device,
 		"        RPTR = %08X | WPTR   = %08X | RPTR_WR   = %08X"
-		"\n", cp_rb_rptr, cp_rb_wptr, r3);
+		"\n", r1, r2, r3);
 
-	kgsl_regread(device, REG_CP_IB1_BASE, &cp_ib1_base);
-	kgsl_regread(device, REG_CP_IB1_BUFSZ, &cp_ib1_bufsz);
-	KGSL_LOG_DUMP(device,
-		"CP_IB1: BASE = %08X | BUFSZ  = %d\n", cp_ib1_base,
-		cp_ib1_bufsz);
+	kgsl_regread(device, REG_CP_IB1_BASE, &r1);
+	kgsl_regread(device, REG_CP_IB1_BUFSZ, &r2);
+	KGSL_LOG_DUMP(device, "CP_IB1: BASE = %08X | BUFSZ  = %d\n", r1, r2);
 
-	kgsl_regread(device, REG_CP_IB2_BASE, &cp_ib2_base);
-	kgsl_regread(device, REG_CP_IB2_BUFSZ, &cp_ib2_bufsz);
-	KGSL_LOG_DUMP(device,
-		"CP_IB2: BASE = %08X | BUFSZ  = %d\n", cp_ib2_base,
-		cp_ib2_bufsz);
+	kgsl_regread(device, REG_CP_IB2_BASE, &r1);
+	kgsl_regread(device, REG_CP_IB2_BUFSZ, &r2);
+	KGSL_LOG_DUMP(device, "CP_IB2: BASE = %08X | BUFSZ  = %d\n", r1, r2);
 
 	kgsl_regread(device, REG_CP_INT_CNTL, &r1);
 	kgsl_regread(device, REG_CP_INT_STATUS, &r2);
@@ -541,11 +669,10 @@
 
 	kgsl_regread(device, MH_MMU_MPU_END, &r1);
 	kgsl_regread(device, MH_MMU_VA_RANGE, &r2);
-	pt_base = kgsl_mmu_get_current_ptbase(device);
+	r3 = kgsl_mmu_get_current_ptbase(device);
 	KGSL_LOG_DUMP(device,
 		"        MPU_END    = %08X | VA_RANGE = %08X | PT_BASE  ="
-		" %08X\n", r1, r2, pt_base);
-	cur_pt_base = pt_base;
+		" %08X\n", r1, r2, r3);
 
 	KGSL_LOG_DUMP(device, "PAGETABLE SIZE: %08X ", KGSL_PAGETABLE_SIZE);
 
@@ -556,6 +683,46 @@
 	kgsl_regread(device, MH_INTERRUPT_STATUS, &r2);
 	KGSL_LOG_DUMP(device,
 		"MH_INTERRUPT: MASK = %08X | STATUS   = %08X\n", r1, r2);
+}
+
+static int adreno_dump(struct kgsl_device *device)
+{
+	unsigned int cp_ib1_base, cp_ib1_bufsz;
+	unsigned int cp_ib2_base, cp_ib2_bufsz;
+	unsigned int pt_base, cur_pt_base;
+	unsigned int cp_rb_base, cp_rb_ctrl, rb_count;
+	unsigned int cp_rb_wptr, cp_rb_rptr;
+	unsigned int i;
+	int result = 0;
+	uint32_t *rb_copy;
+	const uint32_t *rb_vaddr;
+	int num_item = 0;
+	int read_idx, write_idx;
+	unsigned int ts_processed;
+
+	static struct ib_list ib_list;
+
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	mb();
+
+	if (adreno_is_a2xx(adreno_dev))
+		adreno_dump_a2xx(device);
+	else if (adreno_is_a3xx(adreno_dev))
+		adreno_dump_a3xx(device);
+
+	pt_base = kgsl_mmu_get_current_ptbase(device);
+	cur_pt_base = pt_base;
+
+	kgsl_regread(device, REG_CP_RB_BASE, &cp_rb_base);
+	kgsl_regread(device, REG_CP_RB_CNTL, &cp_rb_ctrl);
+	rb_count = 2 << (cp_rb_ctrl & (BIT(6) - 1));
+	kgsl_regread(device, REG_CP_RB_RPTR, &cp_rb_rptr);
+	kgsl_regread(device, REG_CP_RB_WPTR, &cp_rb_wptr);
+	kgsl_regread(device, REG_CP_IB1_BASE, &cp_ib1_base);
+	kgsl_regread(device, REG_CP_IB1_BUFSZ, &cp_ib1_bufsz);
+	kgsl_regread(device, REG_CP_IB2_BASE, &cp_ib2_base);
+	kgsl_regread(device, REG_CP_IB2_BUFSZ, &cp_ib2_bufsz);
 
 	ts_processed = device->ftbl->readtimestamp(device,
 		KGSL_TIMESTAMP_RETIRED);
@@ -689,6 +856,9 @@
 	else if (adreno_is_a22x(adreno_dev))
 		adreno_dump_regs(device, a220_registers,
 			a220_registers_count);
+	else if (adreno_is_a3xx(adreno_dev))
+		adreno_dump_regs(device, a3xx_registers,
+			a3xx_registers_count);
 
 error_vfree:
 	vfree(rb_copy);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 72df148b..de39ee4 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -139,7 +139,7 @@
  * register
  */
 
-int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
+static int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
 	void *snapshot, int remain, void *priv)
 {
 	struct kgsl_snapshot_indexed_registers *iregs = priv;
@@ -164,7 +164,6 @@
 
 	return (iregs->count * 4) + sizeof(*header);
 }
-EXPORT_SYMBOL(kgsl_snapshot_dump_indexed_regs);
 
 /*
  * kgsl_snapshot_dump_regs - helper function to dump device registers
@@ -220,6 +219,23 @@
 }
 EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
 
+void *kgsl_snapshot_indexed_registers(struct kgsl_device *device,
+		void *snapshot, int *remain,
+		unsigned int index, unsigned int data, unsigned int start,
+		unsigned int count)
+{
+	struct kgsl_snapshot_indexed_registers iregs;
+	iregs.index = index;
+	iregs.data = data;
+	iregs.start = start;
+	iregs.count = count;
+
+	return kgsl_snapshot_add_section(device,
+		 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
+		 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
+}
+EXPORT_SYMBOL(kgsl_snapshot_indexed_registers);
+
 /*
  * kgsl_snapshot - construct a device snapshot
  * @device - device to snapshot
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index 4fdc8a1..3b72b0f 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -47,6 +47,7 @@
 #define KGSL_SNAPSHOT_SECTION_INDEXED_REGS 0x0501
 #define KGSL_SNAPSHOT_SECTION_ISTORE       0x0801
 #define KGSL_SNAPSHOT_SECTION_DEBUG        0x0901
+#define KGSL_SNAPSHOT_SECTION_DEBUGBUS     0x0A01
 #define KGSL_SNAPSHOT_SECTION_END          0xFFFF
 
 /* OS sub-section header */
@@ -124,15 +125,28 @@
 
 /* Debug data sub-section header */
 
+/* A2XX debug sections */
 #define SNAPSHOT_DEBUG_SX         1
 #define SNAPSHOT_DEBUG_CP         2
 #define SNAPSHOT_DEBUG_SQ         3
 #define SNAPSHOT_DEBUG_SQTHREAD   4
 #define SNAPSHOT_DEBUG_MIU        5
 
+/* A3XX debug sections */
+#define SNAPSHOT_DEBUG_VPC_MEMORY 6
+#define SNAPSHOT_DEBUG_CP_MEQ     7
+#define SNAPSHOT_DEBUG_CP_PM4_RAM 8
+#define SNAPSHOT_DEBUG_CP_PFP_RAM 9
+#define SNAPSHOT_DEBUG_CP_ROQ     10
+
 struct kgsl_snapshot_debug {
 	int type;    /* Type identifier for the attached tata */
-	int size;   /* Size of the section in bytes */
+	int size;   /* Size of the section in dwords */
+} __packed;
+
+struct kgsl_snapshot_debugbus {
+	int id;	   /* Debug bus ID */
+	int count; /* Number of dwords in the dump */
 } __packed;
 
 #ifdef __KERNEL__
@@ -252,8 +266,12 @@
 	unsigned int count; /* Number of values to read from the pair */
 };
 
-int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
-	void *snapshot, int remain, void *priv);
+/* Helper function to snapshot a section of indexed registers */
+
+void *kgsl_snapshot_indexed_registers(struct kgsl_device *device,
+	void *snapshot, int *remain, unsigned int index,
+	unsigned int data, unsigned int start, unsigned int count);
+
 
 #endif
 #endif