All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] intel_reg: Intel graphics register multitool
@ 2015-04-15 10:15 Jani Nikula
  2015-04-15 10:15 ` [PATCH 1/2] intel_reg: introduce one intel_reg tool to rule them all Jani Nikula
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Jani Nikula @ 2015-04-15 10:15 UTC (permalink / raw)
  To: intel-gfx; +Cc: jani.nikula, Thomas Wood

Hi all, this is v1 after the RFC [1], with polish applied and too many
small changes to list. Go ahead and play with it!

The 2nd patch has a man page written in RST, with conversion done using
rst2man. It lacks proper configure checks for rst2man to push, and I'm
not sure if I'm up for the task. Included for reference anyway; the tool
has some help incorporated anyway.

I was considering Daniel's suggestion to replace the old tools
immediately, but perhaps one IGT release with both the old and new tools
coexisting, old tools deprecated, would be a better idea?

BR,
Jani.

[1] http://mid.gmane.org/cover.1427910607.git.jani.nikula@intel.com

Jani Nikula (2):
  intel_reg: introduce one intel_reg tool to rule them all
  man: add man page for intel_reg in rst format

 man/Makefile.am          |   12 +-
 man/intel_reg.rst        |  229 ++++
 tools/Makefile.sources   |    6 +
 tools/intel_reg.c        |  899 +++++++++++++++
 tools/intel_reg_decode.c | 2713 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/intel_reg_spec.c   |  345 ++++++
 tools/intel_reg_spec.h   |   77 ++
 7 files changed, 4280 insertions(+), 1 deletion(-)
 create mode 100644 man/intel_reg.rst
 create mode 100644 tools/intel_reg.c
 create mode 100644 tools/intel_reg_decode.c
 create mode 100644 tools/intel_reg_spec.c
 create mode 100644 tools/intel_reg_spec.h

-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] intel_reg: introduce one intel_reg tool to rule them all
  2015-04-15 10:15 [PATCH 0/2] intel_reg: Intel graphics register multitool Jani Nikula
@ 2015-04-15 10:15 ` Jani Nikula
  2015-04-15 10:15 ` [PATCH 2/2] man: add man page for intel_reg in rst format Jani Nikula
  2015-04-15 10:23 ` [PATCH 0/2] intel_reg: Intel graphics register multitool Jani Nikula
  2 siblings, 0 replies; 5+ messages in thread
From: Jani Nikula @ 2015-04-15 10:15 UTC (permalink / raw)
  To: intel-gfx; +Cc: jani.nikula, Thomas Wood

	Three Tools for the Elven-kings under the sky,
	Seven for the Dwarf-lords in their halls of stone,
	Nine for Mortal Men doomed to die,
	One for the Dark Lord on his dark throne
	In the Land of Mordor where the Shadows lie.
	One Tool to rule them all, One Tool to find them,
	One Tool to bring them all and in the darkness bind them
	In the Land of Mordor where the Shadows lie.

		J.R.R. Tolkien's epigraph to The Lord of The Tools
		 | sed 's/Ring/Tool/g'

Introduce intel_reg as the one Intel graphics register multitool to
replace intel_reg_read, intel_reg_write, intel_iosf_sb_read,
intel_iosf_sb_write, intel_vga_read, intel_vga_write, intel_reg_dumper,
intel_reg_snapshot, and quick_dump.py.

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
 tools/Makefile.sources   |    6 +
 tools/intel_reg.c        |  899 +++++++++++++++
 tools/intel_reg_decode.c | 2713 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/intel_reg_spec.c   |  345 ++++++
 tools/intel_reg_spec.h   |   77 ++
 5 files changed, 4040 insertions(+)
 create mode 100644 tools/intel_reg.c
 create mode 100644 tools/intel_reg_decode.c
 create mode 100644 tools/intel_reg_spec.c
 create mode 100644 tools/intel_reg_spec.h

diff --git a/tools/Makefile.sources b/tools/Makefile.sources
index 6ca1228b8122..2477eb9bbe86 100644
--- a/tools/Makefile.sources
+++ b/tools/Makefile.sources
@@ -5,6 +5,7 @@ noinst_PROGRAMS = \
 
 bin_PROGRAMS = 				\
 	intel_audio_dump 		\
+	intel_reg			\
 	intel_backlight 		\
 	intel_bios_dumper 		\
 	intel_bios_reader 		\
@@ -40,6 +41,11 @@ dist_bin_SCRIPTS = intel_gpu_abrt
 intel_dump_decode_SOURCES = 	\
 	intel_dump_decode.c
 
+intel_reg_SOURCES =		\
+	intel_reg.c		\
+	intel_reg_decode.c	\
+	intel_reg_spec.c
+
 intel_error_decode_SOURCES =	\
 	intel_error_decode.c
 
diff --git a/tools/intel_reg.c b/tools/intel_reg.c
new file mode 100644
index 000000000000..975529d4555b
--- /dev/null
+++ b/tools/intel_reg.c
@@ -0,0 +1,899 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/io.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "intel_io.h"
+#include "intel_chipset.h"
+
+#include "intel_reg_spec.h"
+
+struct config {
+	struct pci_device *pci_dev;
+	char *mmiofile;
+	uint32_t devid;
+
+	/* read: number of registers to read */
+	uint32_t count;
+
+	/* write: do a posting read */
+	bool post;
+
+	/* decode register for all platforms */
+	bool all_platforms;
+
+	/* spread out bits for convenience */
+	bool binary;
+
+	/* register spec */
+	char *specfile;
+	struct reg *regs;
+	ssize_t regcount;
+
+	int verbosity;
+};
+
+/* port desc must have been set */
+static int set_reg_by_addr(struct config *config, struct reg *reg,
+			   uint32_t addr)
+{
+	int i;
+
+	reg->addr = addr;
+	if (reg->name)
+		free(reg->name);
+	reg->name = NULL;
+
+	for (i = 0; i < config->regcount; i++) {
+		struct reg *r = &config->regs[i];
+
+		if (reg->port_desc.port != r->port_desc.port)
+			continue;
+
+		/* ->mmio_offset should be 0 for non-MMIO ports. */
+		if (addr + reg->mmio_offset == r->addr + r->mmio_offset) {
+			/* Always output the "normalized" offset+addr. */
+			reg->mmio_offset = r->mmio_offset;
+			reg->addr = r->addr;
+
+			reg->name = r->name ? strdup(r->name) : NULL;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/* port desc must have been set */
+static int set_reg_by_name(struct config *config, struct reg *reg,
+			   const char *name)
+{
+	int i;
+
+	reg->name = strdup(name);
+	reg->addr = 0;
+
+	for (i = 0; i < config->regcount; i++) {
+		struct reg *r = &config->regs[i];
+
+		if (reg->port_desc.port != r->port_desc.port)
+			continue;
+
+		if (!r->name)
+			continue;
+
+		if (strcasecmp(name, r->name) == 0) {
+			reg->addr = r->addr;
+
+			/* Also get MMIO offset if not already specified. */
+			if (!reg->mmio_offset && r->mmio_offset)
+				reg->mmio_offset = r->mmio_offset;
+
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static void to_binary(char *buf, size_t buflen, uint32_t val)
+{
+	int i;
+
+	if (!buflen)
+		return;
+
+	*buf = '\0';
+
+	/* XXX: This quick and dirty implementation makes eyes hurt. */
+	for (i = 31; i >= 0; i--) {
+		if (i % 8 == 0)
+			snprintf(buf, buflen, " %2d", i);
+		else
+			snprintf(buf, buflen, "  ");
+		buflen -= strlen(buf);
+		buf += strlen(buf);
+	}
+	snprintf(buf, buflen, "\n");
+	buflen -= strlen(buf);
+	buf += strlen(buf);
+
+	for (i = 31; i >= 0; i--) {
+		snprintf(buf, buflen, " %s%d", i % 8 == 7 ? " " : "",
+			 !!(val & (1 << i)));
+		buflen -= strlen(buf);
+		buf += strlen(buf);
+	}
+	snprintf(buf, buflen, "\n");
+}
+
+static void dump_decode(struct config *config, struct reg *reg, uint32_t val)
+{
+	char decode[1024];
+	char tmp[1024];
+	char bin[1024];
+
+	if (config->binary)
+		to_binary(bin, sizeof(bin), val);
+	else
+		*bin = '\0';
+
+	intel_reg_spec_decode(tmp, sizeof(tmp), reg, val,
+			      config->all_platforms ? 0 : config->devid);
+
+	if (*tmp) {
+		/* We have a decode result, and maybe binary decode. */
+		if (config->all_platforms)
+			snprintf(decode, sizeof(decode), "\n%s%s", tmp, bin);
+		else
+			snprintf(decode, sizeof(decode), " (%s)\n%s", tmp, bin);
+	} else if (*bin) {
+		/* No decode result, but binary decode. */
+		snprintf(decode, sizeof(decode), "\n%s", bin);
+	} else {
+		/* No decode nor binary decode. */
+		snprintf(decode, sizeof(decode), "\n");
+	}
+
+	if (reg->port_desc.port == PORT_MMIO) {
+		/* Omit port name for MMIO, optionally include MMIO offset. */
+		if (reg->mmio_offset)
+			printf("%24s (0x%08x:0x%08x): 0x%08x%s",
+			       reg->name ?: "",
+			       reg->mmio_offset, reg->addr,
+			       val, decode);
+		else
+			printf("%35s (0x%08x): 0x%08x%s",
+			       reg->name ?: "",
+			       reg->addr,
+			       val, decode);
+	} else {
+		char name[100], addr[100];
+
+		/* If no name, use addr as name for easier copy pasting. */
+		if (reg->name)
+			snprintf(name, sizeof(name), "%s:%s",
+				 reg->port_desc.name, reg->name);
+		else
+			snprintf(name, sizeof(name), "%s:0x%08x",
+				 reg->port_desc.name, reg->addr);
+
+		/* Negative port numbers are not real sideband ports. */
+		if (reg->port_desc.port > PORT_NONE)
+			snprintf(addr, sizeof(addr), "0x%02x:0x%08x",
+				 reg->port_desc.port, reg->addr);
+		else
+			snprintf(addr, sizeof(addr), "%s:0x%08x",
+				 reg->port_desc.name, reg->addr);
+
+		printf("%24s (%s): 0x%08x%s", name, addr, val, decode);
+	}
+}
+
+static int read_register(struct config *config, struct reg *reg, uint32_t *valp)
+{
+	uint32_t val = 0;
+
+	switch (reg->port_desc.port) {
+	case PORT_MMIO:
+		val = *(volatile uint32_t *)((volatile char*)mmio +
+					     reg->mmio_offset + reg->addr);
+		break;
+	case PORT_PORTIO_VGA:
+		iopl(3);
+		val = inb(reg->addr);
+		iopl(0);
+		break;
+	case PORT_MMIO_VGA:
+		val = *((volatile uint8_t*)mmio + reg->addr);
+		break;
+	case PORT_BUNIT:
+	case PORT_PUNIT:
+	case PORT_NC:
+	case PORT_DPIO:
+	case PORT_GPIO_NC:
+	case PORT_CCK:
+	case PORT_CCU:
+	case PORT_DPIO2:
+	case PORT_FLISDSI:
+		if (!IS_VALLEYVIEW(config->devid) &&
+		    !IS_CHERRYVIEW(config->devid)) {
+			fprintf(stderr, "port %s only supported on vlv/chv\n",
+				reg->port_desc.name);
+			return -1;
+		}
+		val = intel_iosf_sb_read(reg->port_desc.port, reg->addr);
+		break;
+	default:
+		fprintf(stderr, "port %d not supported\n", reg->port_desc.port);
+		return -1;
+	}
+
+	if (valp)
+		*valp = val;
+
+	return 0;
+}
+
+static void dump_register(struct config *config, struct reg *reg)
+{
+	uint32_t val;
+
+	if (read_register(config, reg, &val) == 0)
+		dump_decode(config, reg, val);
+}
+
+static int write_register(struct config *config, struct reg *reg, uint32_t val)
+{
+	int ret = 0;
+
+	if (config->verbosity > 0) {
+		printf("Before:\n");
+		dump_register(config, reg);
+	}
+
+	switch (reg->port_desc.port) {
+	case PORT_MMIO:
+		*(volatile uint32_t *)((volatile char *)mmio +
+				       reg->mmio_offset + reg->addr) = val;
+		break;
+	case PORT_PORTIO_VGA:
+		if (val > 0xff) {
+			fprintf(stderr, "value 0x%08x out of range for port %s\n",
+				val, reg->port_desc.name);
+			return -1;
+		}
+		iopl(3);
+		outb(val, reg->addr);
+		iopl(0);
+		break;
+	case PORT_MMIO_VGA:
+		if (val > 0xff) {
+			fprintf(stderr, "value 0x%08x out of range for port %s\n",
+				val, reg->port_desc.name);
+			return -1;
+		}
+		*((volatile uint8_t *)mmio + reg->addr) = val;
+		break;
+	case PORT_BUNIT:
+	case PORT_PUNIT:
+	case PORT_NC:
+	case PORT_DPIO:
+	case PORT_GPIO_NC:
+	case PORT_CCK:
+	case PORT_CCU:
+	case PORT_DPIO2:
+	case PORT_FLISDSI:
+		if (!IS_VALLEYVIEW(config->devid) &&
+		    !IS_CHERRYVIEW(config->devid)) {
+			fprintf(stderr, "port %s only supported on vlv/chv\n",
+				reg->port_desc.name);
+			return -1;
+		}
+		intel_iosf_sb_write(reg->port_desc.port, reg->addr, val);
+		break;
+	default:
+		fprintf(stderr, "port %d not supported\n", reg->port_desc.port);
+		ret = -1;
+	}
+
+	if (config->verbosity > 0) {
+		printf("After:\n");
+		dump_register(config, reg);
+	} else if (config->post) {
+		read_register(config, reg, NULL);
+	}
+
+	return ret;
+}
+
+/* s has [(PORTNAME|PORTNUM|MMIO-OFFSET):](REGNAME|REGADDR) */
+static int parse_reg(struct config *config, struct reg *reg, const char *s)
+{
+	unsigned long addr;
+	char *endp;
+	const char *p;
+	int ret;
+
+	memset(reg, 0, sizeof(*reg));
+
+	p = strchr(s, ':');
+	if (p == s) {
+		ret = -1;
+	} else if (p) {
+		char *port_name = strndup(s, p - s);
+
+		ret = parse_port_desc(reg, port_name);
+
+		free(port_name);
+		p++;
+	} else {
+		/*
+		 * XXX: If port is not specified in input, see if the register
+		 * matches by name, and initialize port desc based on that.
+		 */
+		ret = parse_port_desc(reg, NULL);
+		p = s;
+	}
+
+	if (ret) {
+		fprintf(stderr, "invalid port in '%s'\n", s);
+		return ret;
+	}
+
+	addr = strtoul(p, &endp, 16);
+	if (endp > p && *endp == 0) {
+		/* It's a number. */
+		ret = set_reg_by_addr(config, reg, addr);
+	} else {
+		/* Not a number, it's a name. */
+		ret = set_reg_by_name(config, reg, p);
+	}
+
+	return ret;
+}
+
+/* XXX: add support for register ranges, maybe REGISTER..REGISTER */
+static int intel_reg_read(struct config *config, int argc, char *argv[])
+{
+	int i, j;
+
+	if (argc == 1) {
+		fprintf(stderr, "read: no registers specified\n");
+		return EXIT_FAILURE;
+	}
+
+	if (config->mmiofile)
+		intel_mmio_use_dump_file(config->mmiofile);
+	else
+		intel_register_access_init(config->pci_dev, 0);
+
+	for (i = 1; i < argc; i++) {
+		struct reg reg;
+
+		if (parse_reg(config, &reg, argv[i]))
+			continue;
+
+		for (j = 0; j < config->count; j++) {
+			dump_register(config, &reg);
+			/* Update addr and name. */
+			set_reg_by_addr(config, &reg,
+					reg.addr + reg.port_desc.stride);
+		}
+	}
+
+	intel_register_access_fini();
+
+	return EXIT_SUCCESS;
+}
+
+static int intel_reg_write(struct config *config, int argc, char *argv[])
+{
+	int i;
+
+	if (argc == 1) {
+		fprintf(stderr, "write: no registers specified\n");
+		return EXIT_FAILURE;
+	}
+
+	intel_register_access_init(intel_get_pci_device(), 0);
+
+	for (i = 1; i < argc; i += 2) {
+		struct reg reg;
+		uint32_t val;
+		char *endp;
+
+		if (parse_reg(config, &reg, argv[i]))
+			continue;
+
+		if (i + 1 == argc) {
+			fprintf(stderr, "write: no value\n");
+			break;
+		}
+
+		val = strtoul(argv[i + 1], &endp, 16);
+		if (endp == argv[i + 1] || *endp) {
+			fprintf(stderr, "write: invalid value '%s'\n",
+				argv[i + 1]);
+			continue;
+		}
+
+		write_register(config, &reg, val);
+	}
+
+	intel_register_access_fini();
+
+	return EXIT_SUCCESS;
+}
+
+static int intel_reg_dump(struct config *config, int argc, char *argv[])
+{
+	struct reg *reg;
+	int i;
+
+	if (config->mmiofile)
+		intel_mmio_use_dump_file(config->mmiofile);
+	else
+		intel_register_access_init(config->pci_dev, 0);
+
+	for (i = 0; i < config->regcount; i++) {
+		reg = &config->regs[i];
+
+		/* can't dump sideband with mmiofile */
+		if (config->mmiofile && reg->port_desc.port != PORT_MMIO)
+			continue;
+
+		dump_register(config, &config->regs[i]);
+	}
+
+	intel_register_access_fini();
+
+	return EXIT_FAILURE;
+}
+
+static int intel_reg_snapshot(struct config *config, int argc, char *argv[])
+{
+	int mmio_bar = IS_GEN2(config->devid) ? 1 : 0;
+
+	if (config->mmiofile) {
+		fprintf(stderr, "specifying --mmio=FILE is not compatible\n");
+		return EXIT_FAILURE;
+	}
+
+	intel_mmio_use_pci_bar(config->pci_dev);
+
+	/* XXX: error handling */
+	write(1, mmio, config->pci_dev->regions[mmio_bar].size);
+
+	if (config->verbosity > 0)
+		printf("use this with --mmio=FILE --devid=0x%04X\n",
+		       config->devid);
+
+	return EXIT_SUCCESS;
+}
+
+/* XXX: add support for reading and re-decoding a previously done dump */
+static int intel_reg_decode(struct config *config, int argc, char *argv[])
+{
+	int i;
+
+	if (argc == 1) {
+		fprintf(stderr, "decode: no registers specified\n");
+		return EXIT_FAILURE;
+	}
+
+	for (i = 1; i < argc; i += 2) {
+		struct reg reg;
+		uint32_t val;
+		char *endp;
+
+		if (parse_reg(config, &reg, argv[i]))
+			continue;
+
+		if (i + 1 == argc) {
+			fprintf(stderr, "decode: no value\n");
+			break;
+		}
+
+		val = strtoul(argv[i + 1], &endp, 16);
+		if (endp == argv[i + 1] || *endp) {
+			fprintf(stderr, "decode: invalid value '%s'\n",
+				argv[i + 1]);
+			continue;
+		}
+
+		dump_decode(config, &reg, val);
+	}
+
+	return EXIT_SUCCESS;
+}
+
+static int intel_reg_list(struct config *config, int argc, char *argv[])
+{
+	int i;
+
+	for (i = 0; i < config->regcount; i++) {
+		printf("%s\n", config->regs[i].name);
+	}
+
+	return EXIT_SUCCESS;
+}
+
+static int intel_reg_help(struct config *config, int argc, char *argv[]);
+
+struct command {
+	const char *name;
+	const char *description;
+	const char *synopsis;
+	int (*function)(struct config *config, int argc, char *argv[]);
+};
+
+static const struct command commands[] = {
+	{
+		.name = "read",
+		.function = intel_reg_read,
+		.synopsis = "[--count=N] REGISTER [...]",
+		.description = "read and decode specified register(s)",
+	},
+	{
+		.name = "write",
+		.function = intel_reg_write,
+		.synopsis = "[--post] REGISTER VALUE [REGISTER VALUE ...]",
+		.description = "write value(s) to specified register(s)",
+	},
+	{
+		.name = "dump",
+		.function = intel_reg_dump,
+		.description = "dump all known registers",
+	},
+	{
+		.name = "decode",
+		.function = intel_reg_decode,
+		.synopsis = "REGISTER VALUE [REGISTER VALUE ...]",
+		.description = "decode value(s) for specified register(s)",
+	},
+	{
+		.name = "snapshot",
+		.function = intel_reg_snapshot,
+		.description = "create a snapshot of the MMIO bar to stdout",
+	},
+	{
+		.name = "list",
+		.function = intel_reg_list,
+		.description = "list all known register names",
+	},
+	{
+		.name = "help",
+		.function = intel_reg_help,
+		.description = "show this help",
+	},
+};
+
+static int intel_reg_help(struct config *config, int argc, char *argv[])
+{
+	int i;
+
+	printf("Intel graphics register multitool\n\n");
+	printf("Usage: intel_reg [OPTION ...] COMMAND\n\n");
+	printf("COMMAND is one of:\n");
+	for (i = 0; i < ARRAY_SIZE(commands); i++) {
+		printf("  %-14s%s\n", commands[i].name,
+		       commands[i].synopsis ?: "");
+		printf("  %-14s%s\n", "", commands[i].description);
+	}
+
+	printf("\n");
+	printf("REGISTER is defined as:\n");
+        printf("  [(PORTNAME|PORTNUM|MMIO-OFFSET):](REGNAME|REGADDR)\n");
+
+	printf("\n");
+	printf("OPTIONS common to most COMMANDS:\n");
+	printf(" --spec=PATH    Read register spec from directory or file\n");
+	printf(" --mmio=FILE    Use an MMIO snapshot\n");
+	printf(" --devid=DEVID  Specify PCI device ID for --mmio=FILE\n");
+	printf(" --all          Decode registers for all known platforms\n");
+	printf(" --binary       Binary dump registers\n");
+	printf(" --verbose      Increase verbosity\n");
+	printf(" --quiet        Reduce verbosity\n");
+
+	printf("\n");
+	printf("Environment variables:\n");
+	printf(" INTEL_REG_SPEC Read register spec from directory or file\n");
+
+	return EXIT_SUCCESS;
+}
+
+/*
+ * Get codename for a gen5+ platform to be used for finding register spec file.
+ */
+static const char *get_codename(uint32_t devid)
+{
+	if (IS_GEN5(devid))
+		return "ironlake";
+	else if (IS_GEN6(devid))
+		return "sandybridge";
+	else if (IS_IVYBRIDGE(devid))
+		return "ivybridge";
+	else if (IS_HASWELL(devid))
+		return "haswell";
+	else if (IS_BROADWELL(devid))
+		return "broadwell";
+	else if (IS_SKYLAKE(devid))
+		return "skylake";
+	else if (IS_CHERRYVIEW(devid))
+		return "cherryview";
+	else if (IS_VALLEYVIEW(devid))
+		return "valleyview";
+
+	return NULL;
+}
+
+/*
+ * Get register definitions filename for devid in dir. Return 0 if found,
+ * negative error code otherwise.
+ */
+static int get_reg_spec_file(char *buf, size_t buflen, const char *dir,
+			     uint32_t devid)
+{
+	const char *codename;
+
+	/* First, try file named after devid, e.g. "0412" for Haswell GT2. */
+	snprintf(buf, buflen, "%s/%04x", dir, devid);
+	if (!access(buf, F_OK))
+		return 0;
+
+	/*
+	 * Second, for gen5+, try file named after codename, e.g. "haswell" for
+         * Haswell.
+	 */
+	codename = get_codename(devid);
+	if (codename) {
+		snprintf(buf, buflen, "%s/%s", dir, codename);
+		if (!access(buf, F_OK))
+			return 0;
+	}
+
+	/*
+	 * Third, try file named after gen, e.g. "gen7" for Haswell (which is
+	 * technically 7.5 but this is how it works).
+	 */
+	snprintf(buf, buflen, "%s/gen%d", dir, intel_gen(devid));
+	if (!access(buf, F_OK))
+		return 0;
+
+	return -ENOENT;
+}
+
+/*
+ * Read register spec.
+ */
+static int read_reg_spec(struct config *config)
+{
+	char buf[PATH_MAX];
+	char *path;
+	struct stat st;
+	int r;
+
+	path = config->specfile;
+	if (!path)
+		path = getenv("INTEL_REG_SPEC");
+
+	if (!path)
+		goto builtin;
+
+	r = stat(path, &st);
+	if (r) {
+		fprintf(stderr, "Warning: stat '%s' failed: %s. "
+			"Using builtin register spec.\n",
+			path, strerror(errno));
+		goto builtin;
+	}
+
+	if (S_ISDIR(st.st_mode)) {
+		r = get_reg_spec_file(buf, sizeof(buf), path, config->devid);
+		if (r) {
+			fprintf(stderr, "Warning: register spec not found in "
+				"'%s'. Using builtin register spec.\n", path);
+			goto builtin;
+		}
+		path = buf;
+	}
+
+	config->regcount = intel_reg_spec_file(&config->regs, path);
+	if (config->regcount <= 0) {
+		fprintf(stderr, "Warning: reading '%s' failed. "
+			"Using builtin register spec.\n", path);
+		goto builtin;
+	}
+
+	return config->regcount;
+
+builtin:
+	/* Fallback to builtin register spec. */
+	config->regcount = intel_reg_spec_builtin(&config->regs, config->devid);
+
+	return config->regcount;
+}
+
+enum opt {
+	OPT_UNKNOWN = '?',
+	OPT_END = -1,
+	OPT_MMIO,
+	OPT_DEVID,
+	OPT_COUNT,
+	OPT_POST,
+	OPT_ALL,
+	OPT_BINARY,
+	OPT_SPEC,
+	OPT_VERBOSE,
+	OPT_QUIET,
+	OPT_HELP,
+};
+
+int main(int argc, char *argv[])
+{
+	int ret, i, index;
+	char *endp;
+	enum opt opt;
+	const struct command *command = NULL;
+	struct config config = {
+		.count = 1,
+	};
+	bool help = false;
+
+	static struct option options[] = {
+		/* global options */
+		{ "spec",	required_argument,	NULL,	OPT_SPEC },
+		{ "verbose",	no_argument,		NULL,	OPT_VERBOSE },
+		{ "quiet",	no_argument,		NULL,	OPT_QUIET },
+		{ "help",	no_argument,		NULL,	OPT_HELP },
+		/* options specific to read and dump */
+		{ "mmio",	required_argument,	NULL,	OPT_MMIO },
+		{ "devid",	required_argument,	NULL,	OPT_DEVID },
+		/* options specific to read */
+		{ "count",	required_argument,	NULL,	OPT_COUNT },
+		/* options specific to write */
+		{ "post",	no_argument,		NULL,	OPT_POST },
+		/* options specific to read, dump and decode */
+		{ "all",	no_argument,		NULL,	OPT_ALL },
+		{ "binary",	no_argument,		NULL,	OPT_BINARY },
+		{ 0 }
+	};
+
+	for (opt = 0; opt != OPT_END; ) {
+		opt = getopt_long(argc, argv, "", options, &index);
+
+		switch (opt) {
+		case OPT_MMIO:
+			config.mmiofile = strdup(optarg);
+			if (!config.mmiofile) {
+				fprintf(stderr, "strdup: %s\n",
+					strerror(errno));
+				return EXIT_FAILURE;
+			}
+			break;
+		case OPT_DEVID:
+			config.devid = strtoul(optarg, &endp, 16);
+			if (*endp) {
+				fprintf(stderr, "invalid devid '%s'\n", optarg);
+				return EXIT_FAILURE;
+			}
+			break;
+		case OPT_COUNT:
+			config.count = strtol(optarg, &endp, 10);
+			if (*endp) {
+				fprintf(stderr, "invalid count '%s'\n", optarg);
+				return EXIT_FAILURE;
+			}
+			break;
+		case OPT_POST:
+			config.post = true;
+			break;
+		case OPT_SPEC:
+			config.specfile = strdup(optarg);
+			if (!config.specfile) {
+				fprintf(stderr, "strdup: %s\n",
+					strerror(errno));
+				return EXIT_FAILURE;
+			}
+			break;
+		case OPT_ALL:
+			config.all_platforms = true;
+			break;
+		case OPT_BINARY:
+			config.binary = true;
+			break;
+		case OPT_VERBOSE:
+			config.verbosity++;
+			break;
+		case OPT_QUIET:
+			config.verbosity--;
+			break;
+		case OPT_HELP:
+			help = true;
+			break;
+		case OPT_END:
+			break;
+		case OPT_UNKNOWN:
+			return EXIT_FAILURE;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (help)
+		return intel_reg_help(&config, argc, argv);
+
+	if (argc == 0) {
+		fprintf(stderr, "Command missing. Try intel_reg help.\n");
+		return EXIT_FAILURE;
+	}
+
+	if (config.mmiofile) {
+		if (!config.devid) {
+			fprintf(stderr, "--mmio requires --devid\n");
+			return EXIT_FAILURE;
+		}
+	} else {
+		/* XXX: devid without --mmio could be useful for decode. */
+		if (config.devid) {
+			fprintf(stderr, "--devid without --mmio\n");
+			return EXIT_FAILURE;
+		}
+		config.pci_dev = intel_get_pci_device();
+		config.devid = config.pci_dev->device_id;
+	}
+
+	if (read_reg_spec(&config) < 0) {
+		return EXIT_FAILURE;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(commands); i++) {
+		if (strcmp(argv[0], commands[i].name) == 0) {
+			command = &commands[i];
+			break;
+		}
+	}
+
+	if (!command) {
+		fprintf(stderr, "'%s' is not an intel-reg command\n", argv[0]);
+		return EXIT_FAILURE;
+	}
+
+	ret = command->function(&config, argc, argv);
+
+	free(config.mmiofile);
+
+	return ret;
+}
diff --git a/tools/intel_reg_decode.c b/tools/intel_reg_decode.c
new file mode 100644
index 000000000000..4f97d9935965
--- /dev/null
+++ b/tools/intel_reg_decode.c
@@ -0,0 +1,2713 @@
+/*
+ * Copyright © 2006,2009,2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "intel_chipset.h"
+#include "intel_reg.h"
+
+#include "intel_reg_spec.h"
+
+#define _DEBUGSTRING(func) \
+	void func(char *result, int len, int reg, uint32_t val, uint32_t devid)
+#define DEBUGSTRING(func) static _DEBUGSTRING(func)
+
+DEBUGSTRING(i830_16bit_func)
+{
+	snprintf(result, len, "0x%04x", (uint16_t) val);
+}
+
+DEBUGSTRING(i830_debug_dcc)
+{
+	const char *addressing = NULL;
+
+	if (!IS_MOBILE(devid))
+		return;
+
+	if (IS_965(devid)) {
+		if (val & (1 << 1))
+			addressing = "dual channel interleaved";
+		else
+			addressing = "single or dual channel asymmetric";
+	} else {
+		switch (val & 3) {
+		case 0:
+			addressing = "single channel";
+			break;
+		case 1:
+			addressing = "dual channel asymmetric";
+			break;
+		case 2:
+			addressing = "dual channel interleaved";
+			break;
+		case 3:
+			addressing = "unknown channel layout";
+			break;
+		}
+	}
+
+	snprintf(result, len, "%s, XOR randomization: %sabled, XOR bit: %d",
+		 addressing,
+		 (val & (1 << 10)) ? "dis" : "en",
+		 (val & (1 << 9)) ? 17 : 11);
+}
+
+DEBUGSTRING(i830_debug_chdecmisc)
+{
+	const char *enhmodesel = NULL;
+
+	switch ((val >> 5) & 3) {
+	case 1:
+		enhmodesel = "XOR bank/rank";
+		break;
+	case 2:
+		enhmodesel = "swap bank";
+		break;
+	case 3:
+		enhmodesel = "XOR bank";
+		break;
+	case 0:
+		enhmodesel = "none";
+		break;
+	}
+
+	snprintf(result, len,
+		 "%s, ch2 enh %sabled, ch1 enh %sabled, "
+		 "ch0 enh %sabled, "
+		 "flex %sabled, ep %spresent", enhmodesel,
+		 (val & (1 << 4)) ? "en" : "dis",
+		 (val & (1 << 3)) ? "en" : "dis",
+		 (val & (1 << 2)) ? "en" : "dis",
+		 (val & (1 << 1)) ? "en" : "dis",
+		 (val & (1 << 0)) ? "" : "not ");
+}
+
+DEBUGSTRING(i830_debug_xyminus1)
+{
+	snprintf(result, len, "%d, %d", (val & 0xffff) + 1,
+		 ((val & 0xffff0000) >> 16) + 1);
+}
+
+DEBUGSTRING(i830_debug_yxminus1)
+{
+	snprintf(result, len, "%d, %d", ((val & 0xffff0000) >> 16) + 1,
+		 (val & 0xffff) + 1);
+}
+
+DEBUGSTRING(i830_debug_xy)
+{
+	snprintf(result, len, "%d, %d", (val & 0xffff), ((val & 0xffff0000) >> 16));
+}
+
+DEBUGSTRING(i830_debug_dspstride)
+{
+	snprintf(result, len, "%d bytes", val);
+}
+
+DEBUGSTRING(i830_debug_dspcntr)
+{
+	const char *enabled = val & DISPLAY_PLANE_ENABLE ? "enabled" : "disabled";
+	char plane = val & DISPPLANE_SEL_PIPE_B ? 'B' : 'A';
+	if (HAS_PCH_SPLIT(devid) || IS_BROXTON(devid))
+		snprintf(result, len, "%s", enabled);
+	else
+		snprintf(result, len, "%s, pipe %c", enabled, plane);
+}
+
+DEBUGSTRING(i830_debug_pipeconf)
+{
+	const char *enabled = val & PIPEACONF_ENABLE ? "enabled" : "disabled";
+	const char *bit30;
+	char buf[256];
+	int buf_len;
+
+	if (IS_965(devid))
+		bit30 = val & I965_PIPECONF_ACTIVE ? "active" : "inactive";
+	else
+		bit30 =
+		    val & PIPEACONF_DOUBLE_WIDE ? "double-wide" : "single-wide";
+
+	buf_len = snprintf(buf, sizeof(buf), "%s, %s", enabled, bit30);
+
+	if (HAS_PCH_SPLIT(devid) || IS_BROXTON(devid)) {
+		const char *interlace;
+		int interlace_mode;
+
+		if ((IS_IVYBRIDGE(devid) || IS_HASWELL(devid) ||
+		     IS_BROADWELL(devid) || IS_GEN9(devid)))
+			interlace_mode = (val >> 21) & 3;
+		else
+			interlace_mode = (val >> 21) & 7;
+
+		switch (interlace_mode) {
+		case 0:
+			interlace = "pf-pd";
+			break;
+		case 1:
+			interlace = "pf-id";
+			break;
+		case 3:
+			interlace = "if-id";
+			break;
+		case 4:
+			interlace = "if-id-dbl";
+			break;
+		case 5:
+			interlace = "pf-id-dbl";
+			break;
+		default:
+			interlace = "rsvd";
+			break;
+		}
+		if (buf_len < sizeof(buf))
+			buf_len += snprintf(&buf[buf_len], sizeof(buf) - buf_len,
+					    ", %s", interlace);
+	} else if (IS_GEN4(devid) || IS_VALLEYVIEW(devid) ||
+		   IS_CHERRYVIEW(devid)) {
+		const char *interlace;
+
+		switch ((val >> 21) & 7) {
+		case 0:
+		case 1:
+		case 2:
+		case 3:
+			interlace = "progressive";
+			break;
+		case 4:
+			interlace = "interlaced embedded";
+			break;
+		case 5:
+			interlace = "interlaced";
+			break;
+		case 6:
+			interlace = "interlaced sdvo";
+			break;
+		case 7:
+			interlace = "interlaced legacy";
+			break;
+		}
+		if (buf_len < sizeof(buf))
+			buf_len += snprintf(&buf[buf_len], sizeof(buf) - buf_len,
+					    ", %s", interlace);
+	}
+
+	if (IS_HASWELL(devid) || IS_IVYBRIDGE(devid) ||
+	    IS_GEN6(devid) || IS_GEN5(devid)) {
+		const char *rotation;
+
+		switch ((val >> 14) & 3) {
+		case 0:
+			rotation = "rotate 0";
+			break;
+		case 1:
+			rotation = "rotate 90";
+			break;
+		case 2:
+			rotation = "rotate 180";
+			break;
+		case 3:
+			rotation = "rotate 270";
+			break;
+		}
+		if (buf_len < sizeof(buf))
+			buf_len += snprintf(&buf[buf_len], sizeof(buf) - buf_len,
+					    ", %s", rotation);
+	}
+
+	if (IS_IVYBRIDGE(devid) || IS_GEN6(devid) || IS_GEN5(devid)) {
+		const char *bpc;
+
+		switch (val & (7 << 5)) {
+		case PIPECONF_8BPP:
+			bpc = "8bpc";
+			break;
+		case PIPECONF_10BPP:
+			bpc = "10bpc";
+			break;
+		case PIPECONF_6BPP:
+			bpc = "6bpc";
+			break;
+		case PIPECONF_12BPP:
+			bpc = "12bpc";
+			break;
+		default:
+			bpc = "invalid bpc";
+			break;
+		}
+		if (buf_len < sizeof(buf))
+			buf_len += snprintf(&buf[buf_len], sizeof(buf) - buf_len,
+					    ", %s", bpc);
+	}
+
+	snprintf(result, len, "%s", buf);
+}
+
+DEBUGSTRING(i830_debug_pipestat)
+{
+	const char *_FIFO_UNDERRUN = val & FIFO_UNDERRUN ? " FIFO_UNDERRUN" : "";
+	const char *_CRC_ERROR_ENABLE =
+	    val & CRC_ERROR_ENABLE ? " CRC_ERROR_ENABLE" : "";
+	const char *_CRC_DONE_ENABLE =
+	    val & CRC_DONE_ENABLE ? " CRC_DONE_ENABLE" : "";
+	const char *_GMBUS_EVENT_ENABLE =
+	    val & GMBUS_EVENT_ENABLE ? " GMBUS_EVENT_ENABLE" : "";
+	const char *_VSYNC_INT_ENABLE =
+	    val & VSYNC_INT_ENABLE ? " VSYNC_INT_ENABLE" : "";
+	const char *_DLINE_COMPARE_ENABLE =
+	    val & DLINE_COMPARE_ENABLE ? " DLINE_COMPARE_ENABLE" : "";
+	const char *_DPST_EVENT_ENABLE =
+	    val & DPST_EVENT_ENABLE ? " DPST_EVENT_ENABLE" : "";
+	const char *_LBLC_EVENT_ENABLE =
+	    val & LBLC_EVENT_ENABLE ? " LBLC_EVENT_ENABLE" : "";
+	const char *_OFIELD_INT_ENABLE =
+	    val & OFIELD_INT_ENABLE ? " OFIELD_INT_ENABLE" : "";
+	const char *_EFIELD_INT_ENABLE =
+	    val & EFIELD_INT_ENABLE ? " EFIELD_INT_ENABLE" : "";
+	const char *_SVBLANK_INT_ENABLE =
+	    val & SVBLANK_INT_ENABLE ? " SVBLANK_INT_ENABLE" : "";
+	const char *_VBLANK_INT_ENABLE =
+	    val & VBLANK_INT_ENABLE ? " VBLANK_INT_ENABLE" : "";
+	const char *_OREG_UPDATE_ENABLE =
+	    val & OREG_UPDATE_ENABLE ? " OREG_UPDATE_ENABLE" : "";
+	const char *_CRC_ERROR_INT_STATUS =
+	    val & CRC_ERROR_INT_STATUS ? " CRC_ERROR_INT_STATUS" : "";
+	const char *_CRC_DONE_INT_STATUS =
+	    val & CRC_DONE_INT_STATUS ? " CRC_DONE_INT_STATUS" : "";
+	const char *_GMBUS_INT_STATUS =
+	    val & GMBUS_INT_STATUS ? " GMBUS_INT_STATUS" : "";
+	const char *_VSYNC_INT_STATUS =
+	    val & VSYNC_INT_STATUS ? " VSYNC_INT_STATUS" : "";
+	const char *_DLINE_COMPARE_STATUS =
+	    val & DLINE_COMPARE_STATUS ? " DLINE_COMPARE_STATUS" : "";
+	const char *_DPST_EVENT_STATUS =
+	    val & DPST_EVENT_STATUS ? " DPST_EVENT_STATUS" : "";
+	const char *_LBLC_EVENT_STATUS =
+	    val & LBLC_EVENT_STATUS ? " LBLC_EVENT_STATUS" : "";
+	const char *_OFIELD_INT_STATUS =
+	    val & OFIELD_INT_STATUS ? " OFIELD_INT_STATUS" : "";
+	const char *_EFIELD_INT_STATUS =
+	    val & EFIELD_INT_STATUS ? " EFIELD_INT_STATUS" : "";
+	const char *_SVBLANK_INT_STATUS =
+	    val & SVBLANK_INT_STATUS ? " SVBLANK_INT_STATUS" : "";
+	const char *_VBLANK_INT_STATUS =
+	    val & VBLANK_INT_STATUS ? " VBLANK_INT_STATUS" : "";
+	const char *_OREG_UPDATE_STATUS =
+	    val & OREG_UPDATE_STATUS ? " OREG_UPDATE_STATUS" : "";
+	snprintf(result, len,
+		 "status:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+		 _FIFO_UNDERRUN,
+		 _CRC_ERROR_ENABLE,
+		 _CRC_DONE_ENABLE,
+		 _GMBUS_EVENT_ENABLE,
+		 _VSYNC_INT_ENABLE,
+		 _DLINE_COMPARE_ENABLE,
+		 _DPST_EVENT_ENABLE,
+		 _LBLC_EVENT_ENABLE,
+		 _OFIELD_INT_ENABLE,
+		 _EFIELD_INT_ENABLE,
+		 _SVBLANK_INT_ENABLE,
+		 _VBLANK_INT_ENABLE,
+		 _OREG_UPDATE_ENABLE,
+		 _CRC_ERROR_INT_STATUS,
+		 _CRC_DONE_INT_STATUS,
+		 _GMBUS_INT_STATUS,
+		 _VSYNC_INT_STATUS,
+		 _DLINE_COMPARE_STATUS,
+		 _DPST_EVENT_STATUS,
+		 _LBLC_EVENT_STATUS,
+		 _OFIELD_INT_STATUS,
+		 _EFIELD_INT_STATUS,
+		 _SVBLANK_INT_STATUS,
+		 _VBLANK_INT_STATUS,
+		 _OREG_UPDATE_STATUS);
+}
+
+DEBUGSTRING(ivb_debug_port)
+{
+	const char *drrs = NULL;
+	switch (val & (2 << 30)) {
+		case PORT_DBG_DRRS_HW_STATE_OFF:
+			drrs = "off";
+			break;
+		case PORT_DBG_DRRS_HW_STATE_LOW:
+			drrs = "low";
+			break;
+		case PORT_DBG_DRRS_HW_STATE_HIGH:
+			drrs = "high";
+			break;
+	}
+	snprintf(result, len, "HW DRRS %s",
+			drrs);
+}
+
+DEBUGSTRING(i830_debug_hvtotal)
+{
+	snprintf(result, len, "%d active, %d total",
+		 (val & 0xffff) + 1,
+		 ((val & 0xffff0000) >> 16) + 1);
+}
+
+DEBUGSTRING(i830_debug_hvsyncblank)
+{
+	snprintf(result, len, "%d start, %d end",
+		 (val & 0xffff) + 1,
+		 ((val & 0xffff0000) >> 16) + 1);
+}
+
+DEBUGSTRING(i830_debug_vgacntrl)
+{
+	snprintf(result, len, "%s",
+		 val & VGA_DISP_DISABLE ? "disabled" : "enabled");
+}
+
+DEBUGSTRING(i830_debug_fp)
+{
+	if (IS_IGD(devid)) {
+		snprintf(result, len, "n = %d, m1 = %d, m2 = %d",
+			 ffs((val & FP_N_IGD_DIV_MASK) >>
+			     FP_N_DIV_SHIFT) - 1,
+			 ((val & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT),
+			 ((val & FP_M2_IGD_DIV_MASK) >>
+			  FP_M2_DIV_SHIFT));
+	}
+	snprintf(result, len, "n = %d, m1 = %d, m2 = %d",
+		 ((val & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT),
+		 ((val & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT),
+		 ((val & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT));
+}
+
+DEBUGSTRING(i830_debug_vga_pd)
+{
+	int vga0_p1, vga0_p2, vga1_p1, vga1_p2;
+
+	/* XXX: i9xx version */
+
+	if (val & VGA0_PD_P1_DIV_2)
+		vga0_p1 = 2;
+	else
+		vga0_p1 = ((val & VGA0_PD_P1_MASK) >> VGA0_PD_P1_SHIFT) + 2;
+	vga0_p2 = (val & VGA0_PD_P2_DIV_4) ? 4 : 2;
+
+	if (val & VGA1_PD_P1_DIV_2)
+		vga1_p1 = 2;
+	else
+		vga1_p1 = ((val & VGA1_PD_P1_MASK) >> VGA1_PD_P1_SHIFT) + 2;
+	vga1_p2 = (val & VGA1_PD_P2_DIV_4) ? 4 : 2;
+
+	snprintf(result, len, "vga0 p1 = %d, p2 = %d, vga1 p1 = %d, p2 = %d",
+			 vga0_p1, vga0_p2, vga1_p1, vga1_p2);
+}
+
+DEBUGSTRING(i830_debug_pp_status)
+{
+	const char *status = val & PP_ON ? "on" : "off";
+	const char *ready = val & PP_READY ? "ready" : "not ready";
+	const char *seq = "unknown";
+
+	switch (val & PP_SEQUENCE_MASK) {
+	case PP_SEQUENCE_NONE:
+		seq = "idle";
+		break;
+	case PP_SEQUENCE_ON:
+		seq = "on";
+		break;
+	case PP_SEQUENCE_OFF:
+		seq = "off";
+		break;
+	}
+
+	snprintf(result, len, "%s, %s, sequencing %s", status, ready, seq);
+}
+
+DEBUGSTRING(i830_debug_pp_control)
+{
+	snprintf(result, len, "power target: %s",
+			 val & POWER_TARGET_ON ? "on" : "off");
+}
+
+DEBUGSTRING(i830_debug_dpll)
+{
+	const char *enabled = val & DPLL_VCO_ENABLE ? "enabled" : "disabled";
+	const char *dvomode = val & DPLL_DVO_HIGH_SPEED ? "dvo" : "non-dvo";
+	const char *vgamode = val & DPLL_VGA_MODE_DIS ? "" : ", VGA";
+	const char *mode = "unknown";
+	const char *clock = "unknown";
+	const char *fpextra = val & DISPLAY_RATE_SELECT_FPA1 ? ", using FPx1!" : "";
+	char sdvoextra[20];
+	int p1 = 0, p2 = 0;
+
+	if (IS_GEN2(devid)) {
+#if 0 /* removed due to use of INREG */
+		char is_lvds = (INREG(LVDS) & LVDS_PORT_EN) && (reg == DPLL_B);
+
+		if (is_lvds) {
+			mode = "LVDS";
+			p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS)
+				 >> DPLL_FPA01_P1_POST_DIV_SHIFT);
+			if ((INREG(LVDS) & LVDS_CLKB_POWER_MASK) ==
+			    LVDS_CLKB_POWER_UP)
+				p2 = 7;
+			else
+				p2 = 14;
+
+		} else {
+			mode = "DAC/serial";
+			if (val & PLL_P1_DIVIDE_BY_TWO) {
+				p1 = 2;
+			} else {
+				/* Map the number in the field to (3, 33) */
+				p1 = ((val & DPLL_FPA01_P1_POST_DIV_MASK_I830)
+				      >> DPLL_FPA01_P1_POST_DIV_SHIFT) + 2;
+			}
+			if (val & PLL_P2_DIVIDE_BY_4)
+				p2 = 4;
+			else
+				p2 = 2;
+		}
+#endif
+	} else {
+		if (IS_IGD(devid)) {
+			p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK_IGD) >>
+				 DPLL_FPA01_P1_POST_DIV_SHIFT_IGD);
+		} else {
+			p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK) >>
+				 DPLL_FPA01_P1_POST_DIV_SHIFT);
+		}
+		switch (val & DPLL_MODE_MASK) {
+		case DPLLB_MODE_DAC_SERIAL:
+			mode = "DAC/serial";
+			p2 = val & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? 5 : 10;
+			break;
+		case DPLLB_MODE_LVDS:
+			mode = "LVDS";
+			p2 = val & DPLLB_LVDS_P2_CLOCK_DIV_7 ? 7 : 14;
+			break;
+		}
+	}
+
+	switch (val & PLL_REF_INPUT_MASK) {
+	case PLL_REF_INPUT_DREFCLK:
+		clock = "default";
+		break;
+	case PLL_REF_INPUT_TVCLKINA:
+		clock = "TV A";
+		break;
+	case PLL_REF_INPUT_TVCLKINBC:
+		clock = "TV B/C";
+		break;
+	case PLLB_REF_INPUT_SPREADSPECTRUMIN:
+		if (reg == DPLL_B)
+			clock = "spread spectrum";
+		break;
+	}
+
+	if (IS_945(devid)) {
+		sprintf(sdvoextra, ", SDVO mult %d",
+			(int)((val & SDVO_MULTIPLIER_MASK) >>
+			      SDVO_MULTIPLIER_SHIFT_HIRES) + 1);
+	} else {
+		sdvoextra[0] = '\0';
+	}
+
+	snprintf(result, len, "%s, %s%s, %s clock, %s mode, p1 = %d, "
+			 "p2 = %d%s%s",
+			 enabled, dvomode, vgamode, clock, mode, p1, p2,
+			 fpextra, sdvoextra);
+}
+
+DEBUGSTRING(i830_debug_dpll_test)
+{
+	const char *dpllandiv = val & DPLLA_TEST_N_BYPASS ? ", DPLLA N bypassed" : "";
+	const char *dpllamdiv = val & DPLLA_TEST_M_BYPASS ? ", DPLLA M bypassed" : "";
+	const char *dpllainput = val & DPLLA_INPUT_BUFFER_ENABLE ?
+	    "" : ", DPLLA input buffer disabled";
+	const char *dpllbndiv = val & DPLLB_TEST_N_BYPASS ? ", DPLLB N bypassed" : "";
+	const char *dpllbmdiv = val & DPLLB_TEST_M_BYPASS ? ", DPLLB M bypassed" : "";
+	const char *dpllbinput = val & DPLLB_INPUT_BUFFER_ENABLE ?
+	    "" : ", DPLLB input buffer disabled";
+
+	snprintf(result, len, "%s%s%s%s%s%s",
+			 dpllandiv, dpllamdiv, dpllainput,
+			 dpllbndiv, dpllbmdiv, dpllbinput);
+}
+
+DEBUGSTRING(i830_debug_adpa)
+{
+	char disp_pipe = (val & ADPA_PIPE_B_SELECT) ? 'B' : 'A';
+	const char *enable = (val & ADPA_DAC_ENABLE) ? "enabled" : "disabled";
+	char hsync = (val & ADPA_HSYNC_ACTIVE_HIGH) ? '+' : '-';
+	char vsync = (val & ADPA_VSYNC_ACTIVE_HIGH) ? '+' : '-';
+
+	if (HAS_CPT)
+		disp_pipe = val & (1<<29) ? 'B' : 'A';
+
+	if (HAS_PCH_SPLIT(devid))
+		snprintf(result, len, "%s, transcoder %c, %chsync, %cvsync",
+				 enable, disp_pipe, hsync, vsync);
+	else
+		snprintf(result, len, "%s, pipe %c, %chsync, %cvsync",
+				 enable, disp_pipe, hsync, vsync);
+}
+
+DEBUGSTRING(i830_debug_lvds)
+{
+	char disp_pipe = val & LVDS_PIPEB_SELECT ? 'B' : 'A';
+	const char *enable = val & LVDS_PORT_EN ? "enabled" : "disabled";
+	int depth;
+	const char *channels;
+
+	if ((val & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+		depth = 24;
+	else
+		depth = 18;
+	if ((val & LVDS_B0B3_POWER_MASK) == LVDS_B0B3_POWER_UP)
+		channels = "2 channels";
+	else
+		channels = "1 channel";
+
+	if (HAS_CPT)
+		disp_pipe = val & (1<<29) ? 'B' : 'A';
+
+	snprintf(result, len, "%s, pipe %c, %d bit, %s",
+			 enable, disp_pipe, depth, channels);
+}
+
+DEBUGSTRING(i830_debug_dvo)
+{
+	const char *enable = val & DVO_ENABLE ? "enabled" : "disabled";
+	char disp_pipe = val & DVO_PIPE_B_SELECT ? 'B' : 'A';
+	const char *stall;
+	char hsync = val & DVO_HSYNC_ACTIVE_HIGH ? '+' : '-';
+	char vsync = val & DVO_VSYNC_ACTIVE_HIGH ? '+' : '-';
+
+	switch (val & DVO_PIPE_STALL_MASK) {
+	case DVO_PIPE_STALL_UNUSED:
+		stall = "no stall";
+		break;
+	case DVO_PIPE_STALL:
+		stall = "stall";
+		break;
+	case DVO_PIPE_STALL_TV:
+		stall = "TV stall";
+		break;
+	default:
+		stall = "unknown stall";
+		break;
+	}
+
+	snprintf(result, len, "%s, pipe %c, %s, %chsync, %cvsync",
+			 enable, disp_pipe, stall, hsync, vsync);
+}
+
+DEBUGSTRING(i830_debug_sdvo)
+{
+	const char *enable = val & SDVO_ENABLE ? "enabled" : "disabled";
+	char disp_pipe = val & SDVO_PIPE_B_SELECT ? 'B' : 'A';
+	const char *stall = val & SDVO_STALL_SELECT ? "enabled" : "disabled";
+	const char *detected = val & SDVO_DETECTED ? "" : "not ";
+	const char *gang = val & SDVOC_GANG_MODE ? ", gang mode" : "";
+	char sdvoextra[20];
+
+	if (IS_915(devid)) {
+		sprintf(sdvoextra, ", SDVO mult %d",
+			(int)((val & SDVO_PORT_MULTIPLY_MASK) >>
+			      SDVO_PORT_MULTIPLY_SHIFT) + 1);
+	} else {
+		sdvoextra[0] = '\0';
+	}
+
+	snprintf(result, len, "%s, pipe %c, stall %s, %sdetected%s%s",
+			 enable, disp_pipe, stall, detected, sdvoextra, gang);
+}
+
+DEBUGSTRING(i830_debug_dspclk_gate_d)
+{
+	const char *DPUNIT_B = val & DPUNIT_B_CLOCK_GATE_DISABLE ? " DPUNIT_B" : "";
+	const char *VSUNIT = val & VSUNIT_CLOCK_GATE_DISABLE ? " VSUNIT" : "";
+	const char *VRHUNIT = val & VRHUNIT_CLOCK_GATE_DISABLE ? " VRHUNIT" : "";
+	const char *VRDUNIT = val & VRDUNIT_CLOCK_GATE_DISABLE ? " VRDUNIT" : "";
+	const char *AUDUNIT = val & AUDUNIT_CLOCK_GATE_DISABLE ? " AUDUNIT" : "";
+	const char *DPUNIT_A = val & DPUNIT_A_CLOCK_GATE_DISABLE ? " DPUNIT_A" : "";
+	const char *DPCUNIT = val & DPCUNIT_CLOCK_GATE_DISABLE ? " DPCUNIT" : "";
+	const char *TVRUNIT = val & TVRUNIT_CLOCK_GATE_DISABLE ? " TVRUNIT" : "";
+	const char *TVCUNIT = val & TVCUNIT_CLOCK_GATE_DISABLE ? " TVCUNIT" : "";
+	const char *TVFUNIT = val & TVFUNIT_CLOCK_GATE_DISABLE ? " TVFUNIT" : "";
+	const char *TVEUNIT = val & TVEUNIT_CLOCK_GATE_DISABLE ? " TVEUNIT" : "";
+	const char *DVSUNIT = val & DVSUNIT_CLOCK_GATE_DISABLE ? " DVSUNIT" : "";
+	const char *DSSUNIT = val & DSSUNIT_CLOCK_GATE_DISABLE ? " DSSUNIT" : "";
+	const char *DDBUNIT = val & DDBUNIT_CLOCK_GATE_DISABLE ? " DDBUNIT" : "";
+	const char *DPRUNIT = val & DPRUNIT_CLOCK_GATE_DISABLE ? " DPRUNIT" : "";
+	const char *DPFUNIT = val & DPFUNIT_CLOCK_GATE_DISABLE ? " DPFUNIT" : "";
+	const char *DPBMUNIT = val & DPBMUNIT_CLOCK_GATE_DISABLE ? " DPBMUNIT" : "";
+	const char *DPLSUNIT = val & DPLSUNIT_CLOCK_GATE_DISABLE ? " DPLSUNIT" : "";
+	const char *DPLUNIT = val & DPLUNIT_CLOCK_GATE_DISABLE ? " DPLUNIT" : "";
+	const char *DPOUNIT = val & DPOUNIT_CLOCK_GATE_DISABLE ? " DPOUNIT" : "";
+	const char *DPBUNIT = val & DPBUNIT_CLOCK_GATE_DISABLE ? " DPBUNIT" : "";
+	const char *DCUNIT = val & DCUNIT_CLOCK_GATE_DISABLE ? " DCUNIT" : "";
+	const char *DPUNIT = val & DPUNIT_CLOCK_GATE_DISABLE ? " DPUNIT" : "";
+	const char *VRUNIT = val & VRUNIT_CLOCK_GATE_DISABLE ? " VRUNIT" : "";
+	const char *OVHUNIT = val & OVHUNIT_CLOCK_GATE_DISABLE ? " OVHUNIT" : "";
+	const char *DPIOUNIT = val & DPIOUNIT_CLOCK_GATE_DISABLE ? " DPIOUNIT" : "";
+	const char *OVFUNIT = val & OVFUNIT_CLOCK_GATE_DISABLE ? " OVFUNIT" : "";
+	const char *OVBUNIT = val & OVBUNIT_CLOCK_GATE_DISABLE ? " OVBUNIT" : "";
+	const char *OVRUNIT = val & OVRUNIT_CLOCK_GATE_DISABLE ? " OVRUNIT" : "";
+	const char *OVCUNIT = val & OVCUNIT_CLOCK_GATE_DISABLE ? " OVCUNIT" : "";
+	const char *OVUUNIT = val & OVUUNIT_CLOCK_GATE_DISABLE ? " OVUUNIT" : "";
+	const char *OVLUNIT = val & OVLUNIT_CLOCK_GATE_DISABLE ? " OVLUNIT" : "";
+
+	snprintf(result, len,
+		 "clock gates disabled:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+		 DPUNIT_B, VSUNIT, VRHUNIT, VRDUNIT, AUDUNIT, DPUNIT_A, DPCUNIT,
+		 TVRUNIT, TVCUNIT, TVFUNIT, TVEUNIT, DVSUNIT, DSSUNIT, DDBUNIT,
+		 DPRUNIT, DPFUNIT, DPBMUNIT, DPLSUNIT, DPLUNIT, DPOUNIT, DPBUNIT,
+		 DCUNIT, DPUNIT, VRUNIT, OVHUNIT, DPIOUNIT, OVFUNIT, OVBUNIT,
+		 OVRUNIT, OVCUNIT, OVUUNIT, OVLUNIT);
+}
+
+DEBUGSTRING(i810_debug_915_fence)
+{
+	char format = (val & 1 << 12) ? 'Y' : 'X';
+	int pitch = 128 << ((val & 0x70) >> 4);
+	unsigned int offset = val & 0x0ff00000;
+	int size = (1024 * 1024) << ((val & 0x700) >> 8);
+
+	if (IS_965(devid) || (IS_915(devid) && reg >= FENCE_NEW))
+		return;
+
+	if (format == 'X')
+		pitch *= 4;
+	if (val & 1) {
+		snprintf(result, len, "enabled, %c tiled, %4d pitch, 0x%08x - 0x%08x (%dkb)",
+			 format, pitch, offset, offset + size,
+			 size / 1024);
+	} else {
+		snprintf(result, len, "disabled");
+	}
+}
+
+DEBUGSTRING(i810_debug_965_fence_start)
+{
+	const char *enable = (val & FENCE_VALID) ? " enabled" : "disabled";
+	char format = (val & I965_FENCE_Y_MAJOR) ? 'Y' : 'X';
+	int pitch = ((val & 0xffc) >> 2) * 128 + 128;
+	unsigned int offset = val & 0xfffff000;
+
+	if (!IS_965(devid))
+		return;
+
+	snprintf(result, len, "%s, %c tile walk, %4d pitch, 0x%08x start",
+		 enable, format, pitch, offset);
+}
+
+DEBUGSTRING(i810_debug_965_fence_end)
+{
+	unsigned int end = val & 0xfffff000;
+
+	if (!IS_965(devid))
+		return;
+
+	snprintf(result, len, "                                   0x%08x end", end);
+}
+
+#define DEFINEREG(reg) \
+	{ reg, #reg, NULL }
+#define DEFINEREG_16BIT(reg) \
+	{ reg, #reg, i830_16bit_func }
+#define DEFINEREG2(reg, func) \
+	{ reg, #reg, func }
+
+struct reg_debug {
+	int reg;
+	const char *name;
+	_DEBUGSTRING((*debug_output));
+};
+
+static const struct reg_debug intel_debug_regs[] = {
+	DEFINEREG2(DCC, i830_debug_dcc),
+	DEFINEREG2(CHDECMISC, i830_debug_chdecmisc),
+	DEFINEREG_16BIT(C0DRB0),
+	DEFINEREG_16BIT(C0DRB1),
+	DEFINEREG_16BIT(C0DRB2),
+	DEFINEREG_16BIT(C0DRB3),
+	DEFINEREG_16BIT(C1DRB0),
+	DEFINEREG_16BIT(C1DRB1),
+	DEFINEREG_16BIT(C1DRB2),
+	DEFINEREG_16BIT(C1DRB3),
+	DEFINEREG_16BIT(C0DRA01),
+	DEFINEREG_16BIT(C0DRA23),
+	DEFINEREG_16BIT(C1DRA01),
+	DEFINEREG_16BIT(C1DRA23),
+
+	DEFINEREG(PGETBL_CTL),
+
+	DEFINEREG2(VCLK_DIVISOR_VGA0, i830_debug_fp),
+	DEFINEREG2(VCLK_DIVISOR_VGA1, i830_debug_fp),
+	DEFINEREG2(VCLK_POST_DIV, i830_debug_vga_pd),
+	DEFINEREG2(DPLL_TEST, i830_debug_dpll_test),
+	DEFINEREG(CACHE_MODE_0),
+	DEFINEREG(D_STATE),
+	DEFINEREG2(DSPCLK_GATE_D, i830_debug_dspclk_gate_d),
+	DEFINEREG(RENCLK_GATE_D1),
+	DEFINEREG(RENCLK_GATE_D2),
+/*  DEFINEREG(RAMCLK_GATE_D),	CRL only */
+	DEFINEREG2(SDVOB, i830_debug_sdvo),
+	DEFINEREG2(SDVOC, i830_debug_sdvo),
+/*    DEFINEREG(UDIB_SVB_SHB_CODES), CRL only */
+/*    DEFINEREG(UDIB_SHA_BLANK_CODES), CRL only */
+	DEFINEREG(SDVOUDI),
+	DEFINEREG(DSPARB),
+	DEFINEREG(FW_BLC),
+	DEFINEREG(FW_BLC2),
+	DEFINEREG(FW_BLC_SELF),
+	DEFINEREG(DSPFW1),
+	DEFINEREG(DSPFW2),
+	DEFINEREG(DSPFW3),
+
+	DEFINEREG2(ADPA, i830_debug_adpa),
+	DEFINEREG2(LVDS, i830_debug_lvds),
+	DEFINEREG2(DVOA, i830_debug_dvo),
+	DEFINEREG2(DVOB, i830_debug_dvo),
+	DEFINEREG2(DVOC, i830_debug_dvo),
+	DEFINEREG(DVOA_SRCDIM),
+	DEFINEREG(DVOB_SRCDIM),
+	DEFINEREG(DVOC_SRCDIM),
+
+	DEFINEREG(BLC_PWM_CTL),
+	DEFINEREG(BLC_PWM_CTL2),
+
+	DEFINEREG2(PP_CONTROL, i830_debug_pp_control),
+	DEFINEREG2(PP_STATUS, i830_debug_pp_status),
+	DEFINEREG(PP_ON_DELAYS),
+	DEFINEREG(PP_OFF_DELAYS),
+	DEFINEREG(PP_DIVISOR),
+	DEFINEREG(PFIT_CONTROL),
+	DEFINEREG(PFIT_PGM_RATIOS),
+	DEFINEREG(PORT_HOTPLUG_EN),
+	DEFINEREG(PORT_HOTPLUG_STAT),
+
+	DEFINEREG2(DSPACNTR, i830_debug_dspcntr),
+	DEFINEREG2(DSPASTRIDE, i830_debug_dspstride),
+	DEFINEREG2(DSPAPOS, i830_debug_xy),
+	DEFINEREG2(DSPASIZE, i830_debug_xyminus1),
+	DEFINEREG(DSPABASE),
+	DEFINEREG(DSPASURF),
+	DEFINEREG(DSPATILEOFF),
+	DEFINEREG2(PIPEACONF, i830_debug_pipeconf),
+	DEFINEREG2(PIPEASRC, i830_debug_yxminus1),
+	DEFINEREG2(PIPEASTAT, i830_debug_pipestat),
+	DEFINEREG(PIPEA_GMCH_DATA_M),
+	DEFINEREG(PIPEA_GMCH_DATA_N),
+	DEFINEREG(PIPEA_DP_LINK_M),
+	DEFINEREG(PIPEA_DP_LINK_N),
+	DEFINEREG(CURSOR_A_BASE),
+	DEFINEREG(CURSOR_A_CONTROL),
+	DEFINEREG(CURSOR_A_POSITION),
+
+	DEFINEREG2(FPA0, i830_debug_fp),
+	DEFINEREG2(FPA1, i830_debug_fp),
+	DEFINEREG2(DPLL_A, i830_debug_dpll),
+	DEFINEREG(DPLL_A_MD),
+	DEFINEREG2(HTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(HBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(HSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG2(VTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(VBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(VSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG(BCLRPAT_A),
+	DEFINEREG(VSYNCSHIFT_A),
+
+	DEFINEREG2(DSPBCNTR, i830_debug_dspcntr),
+	DEFINEREG2(DSPBSTRIDE, i830_debug_dspstride),
+	DEFINEREG2(DSPBPOS, i830_debug_xy),
+	DEFINEREG2(DSPBSIZE, i830_debug_xyminus1),
+	DEFINEREG(DSPBBASE),
+	DEFINEREG(DSPBSURF),
+	DEFINEREG(DSPBTILEOFF),
+	DEFINEREG2(PIPEBCONF, i830_debug_pipeconf),
+	DEFINEREG2(PIPEBSRC, i830_debug_yxminus1),
+	DEFINEREG2(PIPEBSTAT, i830_debug_pipestat),
+	DEFINEREG(PIPEB_GMCH_DATA_M),
+	DEFINEREG(PIPEB_GMCH_DATA_N),
+	DEFINEREG(PIPEB_DP_LINK_M),
+	DEFINEREG(PIPEB_DP_LINK_N),
+	DEFINEREG(CURSOR_B_BASE),
+	DEFINEREG(CURSOR_B_CONTROL),
+	DEFINEREG(CURSOR_B_POSITION),
+
+	DEFINEREG2(FPB0, i830_debug_fp),
+	DEFINEREG2(FPB1, i830_debug_fp),
+	DEFINEREG2(DPLL_B, i830_debug_dpll),
+	DEFINEREG(DPLL_B_MD),
+	DEFINEREG2(HTOTAL_B, i830_debug_hvtotal),
+	DEFINEREG2(HBLANK_B, i830_debug_hvsyncblank),
+	DEFINEREG2(HSYNC_B, i830_debug_hvsyncblank),
+	DEFINEREG2(VTOTAL_B, i830_debug_hvtotal),
+	DEFINEREG2(VBLANK_B, i830_debug_hvsyncblank),
+	DEFINEREG2(VSYNC_B, i830_debug_hvsyncblank),
+	DEFINEREG(BCLRPAT_B),
+	DEFINEREG(VSYNCSHIFT_B),
+
+	DEFINEREG(VCLK_DIVISOR_VGA0),
+	DEFINEREG(VCLK_DIVISOR_VGA1),
+	DEFINEREG(VCLK_POST_DIV),
+	DEFINEREG2(VGACNTRL, i830_debug_vgacntrl),
+
+	DEFINEREG(TV_CTL),
+	DEFINEREG(TV_DAC),
+	DEFINEREG(TV_CSC_Y),
+	DEFINEREG(TV_CSC_Y2),
+	DEFINEREG(TV_CSC_U),
+	DEFINEREG(TV_CSC_U2),
+	DEFINEREG(TV_CSC_V),
+	DEFINEREG(TV_CSC_V2),
+	DEFINEREG(TV_CLR_KNOBS),
+	DEFINEREG(TV_CLR_LEVEL),
+	DEFINEREG(TV_H_CTL_1),
+	DEFINEREG(TV_H_CTL_2),
+	DEFINEREG(TV_H_CTL_3),
+	DEFINEREG(TV_V_CTL_1),
+	DEFINEREG(TV_V_CTL_2),
+	DEFINEREG(TV_V_CTL_3),
+	DEFINEREG(TV_V_CTL_4),
+	DEFINEREG(TV_V_CTL_5),
+	DEFINEREG(TV_V_CTL_6),
+	DEFINEREG(TV_V_CTL_7),
+	DEFINEREG(TV_SC_CTL_1),
+	DEFINEREG(TV_SC_CTL_2),
+	DEFINEREG(TV_SC_CTL_3),
+	DEFINEREG(TV_WIN_POS),
+	DEFINEREG(TV_WIN_SIZE),
+	DEFINEREG(TV_FILTER_CTL_1),
+	DEFINEREG(TV_FILTER_CTL_2),
+	DEFINEREG(TV_FILTER_CTL_3),
+	DEFINEREG(TV_CC_CONTROL),
+	DEFINEREG(TV_CC_DATA),
+	DEFINEREG(TV_H_LUMA_0),
+	DEFINEREG(TV_H_LUMA_59),
+	DEFINEREG(TV_H_CHROMA_0),
+	DEFINEREG(TV_H_CHROMA_59),
+
+	DEFINEREG(FBC_CFB_BASE),
+	DEFINEREG(FBC_LL_BASE),
+	DEFINEREG(FBC_CONTROL),
+	DEFINEREG(FBC_COMMAND),
+	DEFINEREG(FBC_STATUS),
+	DEFINEREG(FBC_CONTROL2),
+	DEFINEREG(FBC_FENCE_OFF),
+	DEFINEREG(FBC_MOD_NUM),
+
+	DEFINEREG(MI_MODE),
+	/* DEFINEREG(MI_DISPLAY_POWER_DOWN), CRL only */
+	DEFINEREG(MI_ARB_STATE),
+	DEFINEREG(MI_RDRET_STATE),
+	DEFINEREG(ECOSKPD),
+
+	DEFINEREG(DP_B),
+	DEFINEREG(DPB_AUX_CH_CTL),
+	DEFINEREG(DPB_AUX_CH_DATA1),
+	DEFINEREG(DPB_AUX_CH_DATA2),
+	DEFINEREG(DPB_AUX_CH_DATA3),
+	DEFINEREG(DPB_AUX_CH_DATA4),
+	DEFINEREG(DPB_AUX_CH_DATA5),
+
+	DEFINEREG(DP_C),
+	DEFINEREG(DPC_AUX_CH_CTL),
+	DEFINEREG(DPC_AUX_CH_DATA1),
+	DEFINEREG(DPC_AUX_CH_DATA2),
+	DEFINEREG(DPC_AUX_CH_DATA3),
+	DEFINEREG(DPC_AUX_CH_DATA4),
+	DEFINEREG(DPC_AUX_CH_DATA5),
+
+	DEFINEREG(DP_D),
+	DEFINEREG(DPD_AUX_CH_CTL),
+	DEFINEREG(DPD_AUX_CH_DATA1),
+	DEFINEREG(DPD_AUX_CH_DATA2),
+	DEFINEREG(DPD_AUX_CH_DATA3),
+	DEFINEREG(DPD_AUX_CH_DATA4),
+	DEFINEREG(DPD_AUX_CH_DATA5),
+
+	DEFINEREG(AUD_CONFIG),
+	DEFINEREG(AUD_HDMIW_STATUS),
+	DEFINEREG(AUD_CONV_CHCNT),
+	DEFINEREG(VIDEO_DIP_CTL),
+	DEFINEREG(AUD_PINW_CNTR),
+	DEFINEREG(AUD_CNTL_ST),
+	DEFINEREG(AUD_PIN_CAP),
+	DEFINEREG(AUD_PINW_CAP),
+	DEFINEREG(AUD_PINW_UNSOLRESP),
+	DEFINEREG(AUD_OUT_DIG_CNVT),
+	DEFINEREG(AUD_OUT_CWCAP),
+	DEFINEREG(AUD_GRP_CAP),
+
+#define DEFINEFENCE_915(i) \
+	{ FENCE+i*4, "FENCE  " #i, i810_debug_915_fence }
+#define DEFINEFENCE_945(i) \
+	{ FENCE_NEW+(i - 8) * 4, "FENCE  " #i, i810_debug_915_fence }
+
+	DEFINEFENCE_915(0),
+	DEFINEFENCE_915(1),
+	DEFINEFENCE_915(2),
+	DEFINEFENCE_915(3),
+	DEFINEFENCE_915(4),
+	DEFINEFENCE_915(5),
+	DEFINEFENCE_915(6),
+	DEFINEFENCE_915(7),
+	DEFINEFENCE_945(8),
+	DEFINEFENCE_945(9),
+	DEFINEFENCE_945(10),
+	DEFINEFENCE_945(11),
+	DEFINEFENCE_945(12),
+	DEFINEFENCE_945(13),
+	DEFINEFENCE_945(14),
+	DEFINEFENCE_945(15),
+
+#define DEFINEFENCE_965(i) \
+	{ FENCE_NEW+i*8, "FENCE START " #i, i810_debug_965_fence_start }, \
+	{ FENCE_NEW+i*8+4, "FENCE END " #i, i810_debug_965_fence_end }
+
+	DEFINEFENCE_965(0),
+	DEFINEFENCE_965(1),
+	DEFINEFENCE_965(2),
+	DEFINEFENCE_965(3),
+	DEFINEFENCE_965(4),
+	DEFINEFENCE_965(5),
+	DEFINEFENCE_965(6),
+	DEFINEFENCE_965(7),
+	DEFINEFENCE_965(8),
+	DEFINEFENCE_965(9),
+	DEFINEFENCE_965(10),
+	DEFINEFENCE_965(11),
+	DEFINEFENCE_965(12),
+	DEFINEFENCE_965(13),
+	DEFINEFENCE_965(14),
+	DEFINEFENCE_965(15),
+
+	DEFINEREG(INST_PM),
+};
+
+DEBUGSTRING(ironlake_debug_rr_hw_ctl)
+{
+	snprintf(result, len, "low %d, high %d", val & RR_HW_LOW_POWER_FRAMES_MASK,
+		 (val & RR_HW_HIGH_POWER_FRAMES_MASK) >> 8);
+}
+
+DEBUGSTRING(ironlake_debug_m_tu)
+{
+	snprintf(result, len, "TU %d, val 0x%x %d", (val >> 25) + 1, val & 0xffffff,
+		 val & 0xffffff);
+}
+
+DEBUGSTRING(ironlake_debug_n)
+{
+	snprintf(result, len, "val 0x%x %d", val & 0xffffff, val & 0xffffff);
+}
+
+DEBUGSTRING(ironlake_debug_fdi_tx_ctl)
+{
+	const char *train = NULL, *voltage = NULL, *pre_emphasis = NULL, *portw =
+	    NULL;
+
+	switch (val & FDI_LINK_TRAIN_NONE) {
+	case FDI_LINK_TRAIN_PATTERN_1:
+		train = "pattern_1";
+		break;
+	case FDI_LINK_TRAIN_PATTERN_2:
+		train = "pattern_2";
+		break;
+	case FDI_LINK_TRAIN_PATTERN_IDLE:
+		train = "pattern_idle";
+		break;
+	case FDI_LINK_TRAIN_NONE:
+		train = "not train";
+		break;
+	}
+
+	if (HAS_CPT) {
+		/* SNB B0 */
+		switch (val & (0x3f << 22)) {
+		case FDI_LINK_TRAIN_400MV_0DB_SNB_B:
+			voltage = "0.4V";
+			pre_emphasis = "0dB";
+			break;
+		case FDI_LINK_TRAIN_400MV_6DB_SNB_B:
+			voltage = "0.4V";
+			pre_emphasis = "6dB";
+			break;
+		case FDI_LINK_TRAIN_600MV_3_5DB_SNB_B:
+			voltage = "0.6V";
+			pre_emphasis = "3.5dB";
+			break;
+		case FDI_LINK_TRAIN_800MV_0DB_SNB_B:
+			voltage = "0.8V";
+			pre_emphasis = "0dB";
+			break;
+		}
+
+	} else {
+
+		switch (val & (7 << 25)) {
+			case FDI_LINK_TRAIN_VOLTAGE_0_4V:
+				voltage = "0.4V";
+				break;
+			case FDI_LINK_TRAIN_VOLTAGE_0_6V:
+				voltage = "0.6V";
+				break;
+			case FDI_LINK_TRAIN_VOLTAGE_0_8V:
+				voltage = "0.8V";
+				break;
+			case FDI_LINK_TRAIN_VOLTAGE_1_2V:
+				voltage = "1.2V";
+				break;
+			default:
+				voltage = "reserved";
+		}
+
+		switch (val & (7 << 22)) {
+			case FDI_LINK_TRAIN_PRE_EMPHASIS_NONE:
+				pre_emphasis = "none";
+				break;
+			case FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X:
+				pre_emphasis = "1.5x";
+				break;
+			case FDI_LINK_TRAIN_PRE_EMPHASIS_2X:
+				pre_emphasis = "2x";
+				break;
+			case FDI_LINK_TRAIN_PRE_EMPHASIS_3X:
+				pre_emphasis = "3x";
+				break;
+			default:
+				pre_emphasis = "reserved";
+		}
+
+	}
+
+	switch (val & (7 << 19)) {
+	case FDI_DP_PORT_WIDTH_X1:
+		portw = "X1";
+		break;
+	case FDI_DP_PORT_WIDTH_X2:
+		portw = "X2";
+		break;
+	case FDI_DP_PORT_WIDTH_X3:
+		portw = "X3";
+		break;
+	case FDI_DP_PORT_WIDTH_X4:
+		portw = "X4";
+		break;
+	}
+
+	snprintf(result, len, "%s, train pattern %s, voltage swing %s,"
+		 "pre-emphasis %s, port width %s, enhanced framing %s, FDI PLL %s, scrambing %s, master mode %s",
+		 val & FDI_TX_ENABLE ? "enable" : "disable",
+		 train, voltage, pre_emphasis, portw,
+		 val & FDI_TX_ENHANCE_FRAME_ENABLE ? "enable" :
+		 "disable",
+		 val & FDI_TX_PLL_ENABLE ? "enable" : "disable",
+		 val & (1 << 7) ? "disable" : "enable",
+		 val & (1 << 0) ? "enable" : "disable");
+}
+
+DEBUGSTRING(ironlake_debug_fdi_rx_ctl)
+{
+	const char *train = NULL, *portw = NULL, *bpc = NULL;
+
+	if (HAS_CPT) {
+		switch (val & FDI_LINK_TRAIN_PATTERN_MASK_CPT) {
+		case FDI_LINK_TRAIN_PATTERN_1_CPT:
+			train = "pattern_1";
+			break;
+		case FDI_LINK_TRAIN_PATTERN_2_CPT:
+			train = "pattern_2";
+			break;
+		case FDI_LINK_TRAIN_PATTERN_IDLE_CPT:
+			train = "pattern_idle";
+			break;
+		case FDI_LINK_TRAIN_NORMAL_CPT:
+			train = "not train";
+			break;
+		}
+	} else {
+		switch (val & FDI_LINK_TRAIN_NONE) {
+		case FDI_LINK_TRAIN_PATTERN_1:
+			train = "pattern_1";
+			break;
+		case FDI_LINK_TRAIN_PATTERN_2:
+			train = "pattern_2";
+			break;
+		case FDI_LINK_TRAIN_PATTERN_IDLE:
+			train = "pattern_idle";
+			break;
+		case FDI_LINK_TRAIN_NONE:
+			train = "not train";
+			break;
+		}
+	}
+
+	switch (val & (7 << 19)) {
+	case FDI_DP_PORT_WIDTH_X1:
+		portw = "X1";
+		break;
+	case FDI_DP_PORT_WIDTH_X2:
+		portw = "X2";
+		break;
+	case FDI_DP_PORT_WIDTH_X3:
+		portw = "X3";
+		break;
+	case FDI_DP_PORT_WIDTH_X4:
+		portw = "X4";
+		break;
+	}
+
+	switch (val & (7 << 16)) {
+	case FDI_8BPC:
+		bpc = "8bpc";
+		break;
+	case FDI_10BPC:
+		bpc = "10bpc";
+		break;
+	case FDI_6BPC:
+		bpc = "6bpc";
+		break;
+	case FDI_12BPC:
+		bpc = "12bpc";
+		break;
+	}
+
+	snprintf(result, len, "%s, train pattern %s, port width %s, %s,"
+		 "link_reverse_strap_overwrite %s, dmi_link_reverse %s, FDI PLL %s,"
+		 "FS ecc %s, FE ecc %s, FS err report %s, FE err report %s,"
+		 "scrambing %s, enhanced framing %s, %s",
+		 val & FDI_RX_ENABLE ? "enable" : "disable",
+		 train, portw, bpc,
+		 val & FDI_LINK_REVERSE_OVERWRITE ? "yes" : "no",
+		 val & FDI_DMI_LINK_REVERSE_MASK ? "yes" : "no",
+		 val & FDI_RX_PLL_ENABLE ? "enable" : "disable",
+		 val & FDI_FS_ERR_CORRECT_ENABLE ? "enable" : "disable",
+		 val & FDI_FE_ERR_CORRECT_ENABLE ? "enable" : "disable",
+		 val & FDI_FS_ERR_REPORT_ENABLE ? "enable" : "disable",
+		 val & FDI_FE_ERR_REPORT_ENABLE ? "enable" : "disable",
+		 val & (1 << 7) ? "disable" : "enable",
+		 val & FDI_RX_ENHANCE_FRAME_ENABLE ? "enable" :
+		 "disable", val & FDI_SEL_PCDCLK ? "PCDClk" : "RawClk");
+}
+
+DEBUGSTRING(ironlake_debug_dspstride)
+{
+	snprintf(result, len, "%d", val >> 6);
+}
+
+DEBUGSTRING(ironlake_debug_pch_dpll)
+{
+	const char *enable = val & DPLL_VCO_ENABLE ? "enable" : "disable";
+	const char *highspeed = val & DPLL_DVO_HIGH_SPEED ? "yes" : "no";
+	const char *mode = NULL;
+	const char *p2 = NULL;
+	int fpa0_p1, fpa1_p1;
+	const char *refclk = NULL;
+	int sdvo_mul;
+
+	if ((val & DPLLB_MODE_LVDS) == DPLLB_MODE_LVDS) {
+		mode = "LVDS";
+		if (val & DPLLB_LVDS_P2_CLOCK_DIV_7)
+			p2 = "Div 7";
+		else
+			p2 = "Div 14";
+	} else if ((val & DPLLB_MODE_LVDS) == DPLLB_MODE_DAC_SERIAL) {
+		mode = "Non-LVDS";
+		if (val & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5)
+			p2 = "Div 5";
+		else
+			p2 = "Div 10";
+	}
+	fpa0_p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK) >> 16);
+	fpa1_p1 = ffs((val & DPLL_FPA1_P1_POST_DIV_MASK));
+
+	switch (val & PLL_REF_INPUT_MASK) {
+	case PLL_REF_INPUT_DREFCLK:
+		refclk = "default 120Mhz";
+		break;
+	case PLL_REF_INPUT_SUPER_SSC:
+		refclk = "SuperSSC 120Mhz";
+		break;
+	case PLL_REF_INPUT_TVCLKINBC:
+		refclk = "SDVO TVClkIn";
+		break;
+	case PLLB_REF_INPUT_SPREADSPECTRUMIN:
+		refclk = "SSC";
+		break;
+	case PLL_REF_INPUT_DMICLK:
+		refclk = "DMI RefCLK";
+		break;
+	}
+
+	sdvo_mul = ((val & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK) >> 9) + 1;
+
+	snprintf(result, len, "%s, sdvo high speed %s, mode %s, p2 %s, "
+		 "FPA0 P1 %d, FPA1 P1 %d, refclk %s, sdvo/hdmi mul %d",
+		 enable, highspeed, mode, p2, fpa0_p1, fpa1_p1, refclk,
+		 sdvo_mul);
+}
+
+DEBUGSTRING(ironlake_debug_dref_ctl)
+{
+	const char *cpu_source;
+	const char *ssc_source = val & DREF_SSC_SOURCE_ENABLE ? "enable" : "disable";
+	const char *nonspread_source =
+	    val & DREF_NONSPREAD_SOURCE_ENABLE ? "enable" : "disable";
+	const char *superspread_source =
+	    val & DREF_SUPERSPREAD_SOURCE_ENABLE ? "enable" : "disable";
+	const char *ssc4_mode =
+	    val & DREF_SSC4_CENTERSPREAD ? "centerspread" : "downspread";
+	const char *ssc1 = val & DREF_SSC1_ENABLE ? "enable" : "disable";
+	const char *ssc4 = val & DREF_SSC4_ENABLE ? "enable" : "disable";
+
+	switch (val & DREF_CPU_SOURCE_OUTPUT_NONSPREAD) {
+	case DREF_CPU_SOURCE_OUTPUT_DISABLE:
+		cpu_source = "disable";
+		break;
+	case DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD:
+		cpu_source = "downspread";
+		break;
+	case DREF_CPU_SOURCE_OUTPUT_NONSPREAD:
+		cpu_source = "nonspread";
+		break;
+	default:
+		cpu_source = "reserved";
+	}
+	snprintf(result, len, "cpu source %s, ssc_source %s, nonspread_source %s, "
+		 "superspread_source %s, ssc4_mode %s, ssc1 %s, ssc4 %s",
+		 cpu_source, ssc_source, nonspread_source,
+		 superspread_source, ssc4_mode, ssc1, ssc4);
+}
+
+DEBUGSTRING(ironlake_debug_rawclk_freq)
+{
+	const char *tp1 = NULL, *tp2 = NULL;
+
+	switch (val & FDL_TP1_TIMER_MASK) {
+	case 0:
+		tp1 = "0.5us";
+		break;
+	case (1 << 12):
+		tp1 = "1.0us";
+		break;
+	case (2 << 12):
+		tp1 = "2.0us";
+		break;
+	case (3 << 12):
+		tp1 = "4.0us";
+		break;
+	}
+	switch (val & FDL_TP2_TIMER_MASK) {
+	case 0:
+		tp2 = "1.5us";
+		break;
+	case (1 << 10):
+		tp2 = "3.0us";
+		break;
+	case (2 << 10):
+		tp2 = "6.0us";
+		break;
+	case (3 << 10):
+		tp2 = "12.0us";
+		break;
+	}
+	snprintf(result, len, "FDL_TP1 timer %s, FDL_TP2 timer %s, freq %d",
+		 tp1, tp2, val & RAWCLK_FREQ_MASK);
+
+}
+
+DEBUGSTRING(ironlake_debug_fdi_rx_misc)
+{
+	snprintf(result, len, "FDI Delay %d", val & ((1 << 13) - 1));
+}
+
+DEBUGSTRING(ironlake_debug_transconf)
+{
+	const char *enable = val & TRANS_ENABLE ? "enable" : "disable";
+	const char *state = val & TRANS_STATE_ENABLE ? "active" : "inactive";
+	const char *interlace;
+
+	switch ((val >> 21) & 7) {
+	case 0:
+		interlace = "progressive";
+		break;
+	case 2:
+		if (IS_GEN5(devid))
+			interlace = "interlaced sdvo";
+		else
+			interlace = "rsvd";
+		break;
+	case 3:
+		interlace = "interlaced";
+		break;
+	default:
+		interlace = "rsvd";
+	}
+
+	snprintf(result, len, "%s, %s, %s", enable, state, interlace);
+}
+
+DEBUGSTRING(ironlake_debug_panel_fitting)
+{
+	const char *vadapt = NULL, *filter_sel = NULL;
+
+	switch (val & (3 << 25)) {
+	case 0:
+		vadapt = "least";
+		break;
+	case (1 << 25):
+		vadapt = "moderate";
+		break;
+	case (2 << 25):
+		vadapt = "reserved";
+		break;
+	case (3 << 25):
+		vadapt = "most";
+		break;
+	}
+
+	switch (val & (3 << 23)) {
+	case 0:
+		filter_sel = "programmed";
+		break;
+	case (1 << 23):
+		filter_sel = "hardcoded";
+		break;
+	case (2 << 23):
+		filter_sel = "edge_enhance";
+		break;
+	case (3 << 23):
+		filter_sel = "edge_soften";
+		break;
+	}
+
+	snprintf(result, len,
+		 "%s, auto_scale %s, auto_scale_cal %s, v_filter %s, vadapt %s, mode %s, filter_sel %s,"
+		 "chroma pre-filter %s, vert3tap %s, v_inter_invert %s",
+		 val & PF_ENABLE ? "enable" : "disable",
+		 val & (1 << 30) ? "no" : "yes",
+		 val & (1 << 29) ? "yes" : "no",
+		 val & (1 << 28) ? "bypass" : "enable",
+		 val & (1 << 27) ? "enable" : "disable",
+		 vadapt,
+		 filter_sel,
+		 val & (1 << 22) ? "enable" : "disable",
+		 val & (1 << 21) ? "force" : "auto",
+		 val & (1 << 20) ? "field 0" : "field 1");
+}
+
+DEBUGSTRING(ironlake_debug_panel_fitting_2)
+{
+	snprintf(result, len,
+		 "vscale %f",
+		 val / (float) (1<<15));
+}
+
+DEBUGSTRING(ironlake_debug_panel_fitting_3)
+{
+	snprintf(result, len,
+		 "vscale initial phase %f",
+		 val / (float) (1<<15));
+}
+
+DEBUGSTRING(ironlake_debug_panel_fitting_4)
+{
+	snprintf(result, len,
+		 "hscale %f",
+		 val / (float) (1<<15));
+}
+
+DEBUGSTRING(ironlake_debug_pf_win)
+{
+	int a, b;
+
+	a = (val >> 16) & 0x1fff;
+	b = val & 0xfff;
+
+	snprintf(result, len, "%d, %d", a, b);
+}
+
+DEBUGSTRING(ironlake_debug_hdmi)
+{
+	int disp_pipe;
+	const char *enable, *bpc = NULL, *encoding;
+	const char *mode, *audio, *vsync, *hsync, *detect;
+
+	if (val & PORT_ENABLE)
+		enable = "enabled";
+	else
+		enable = "disabled";
+
+	if (HAS_CPT)
+		disp_pipe = (val & (3<<29)) >> 29;
+	else
+		disp_pipe = (val & TRANSCODER_B) >> 29;
+
+	switch (val & (7 << 26)) {
+	case COLOR_FORMAT_8bpc:
+		bpc = "8bpc";
+		break;
+	case COLOR_FORMAT_12bpc:
+		bpc = "12bpc";
+		break;
+	}
+
+	if ((val & (3 << 10)) == TMDS_ENCODING)
+		encoding = "TMDS";
+	else
+		encoding = "SDVO";
+
+	if (val & (1 << 9))
+		mode = "HDMI";
+	else
+		mode = "DVI";
+
+	if (val & AUDIO_ENABLE)
+		audio = "enabled";
+	else
+		audio = "disabled";
+
+	if (val & VSYNC_ACTIVE_HIGH)
+		vsync = "+vsync";
+	else
+		vsync = "-vsync";
+
+	if (val & HSYNC_ACTIVE_HIGH)
+		hsync = "+hsync";
+	else
+		hsync = "-hsync";
+
+	if (val & PORT_DETECTED)
+		detect = "detected";
+	else
+		detect = "non-detected";
+
+	snprintf(result, len, "%s pipe %c %s %s %s audio %s %s %s %s",
+		 enable, disp_pipe + 'A', bpc, encoding, mode, audio, vsync, hsync, detect);
+}
+
+DEBUGSTRING(snb_debug_dpll_sel)
+{
+	const char *transa, *transb;
+	const char *dplla = NULL, *dpllb = NULL;
+
+	if (!HAS_CPT)
+		return;
+
+	if (val & TRANSA_DPLL_ENABLE) {
+		transa = "enable";
+		if (val & TRANSA_DPLLB_SEL)
+			dplla = "B";
+		else
+			dplla = "A";
+	} else
+		transa = "disable";
+
+	if (val & TRANSB_DPLL_ENABLE) {
+		transb = "enable";
+		if (val & TRANSB_DPLLB_SEL)
+			dpllb = "B";
+		else
+			dpllb = "A";
+	} else
+		transb = "disable";
+
+	snprintf(result, len, "TransA DPLL %s (DPLL %s), TransB DPLL %s (DPLL %s)",
+		 transa, dplla, transb, dpllb);
+}
+
+DEBUGSTRING(snb_debug_trans_dp_ctl)
+{
+	const char *enable, *port = NULL, *bpc = NULL, *vsync, *hsync;
+
+	if (!HAS_CPT)
+		return;
+
+	if (val & TRANS_DP_OUTPUT_ENABLE)
+		enable = "enable";
+	else
+		enable = "disable";
+
+	switch (val & TRANS_DP_PORT_SEL_MASK) {
+	case TRANS_DP_PORT_SEL_B:
+		port = "B";
+		break;
+	case TRANS_DP_PORT_SEL_C:
+		port = "C";
+		break;
+	case TRANS_DP_PORT_SEL_D:
+		port = "D";
+		break;
+	default:
+		port = "none";
+		break;
+	}
+
+	switch (val & (7<<9)) {
+	case TRANS_DP_8BPC:
+		bpc = "8bpc";
+		break;
+	case TRANS_DP_10BPC:
+		bpc = "10bpc";
+		break;
+	case TRANS_DP_6BPC:
+		bpc = "6bpc";
+		break;
+	case TRANS_DP_12BPC:
+		bpc = "12bpc";
+		break;
+	}
+
+	if (val & TRANS_DP_VSYNC_ACTIVE_HIGH)
+		vsync = "+vsync";
+	else
+		vsync = "-vsync";
+
+	if (val & TRANS_DP_HSYNC_ACTIVE_HIGH)
+		hsync = "+hsync";
+	else
+		hsync = "-hsync";
+
+	snprintf(result, len, "%s port %s %s %s %s",
+		 enable, port, bpc, vsync, hsync);
+}
+
+DEBUGSTRING(ilk_debug_pp_control)
+{
+	snprintf(result, len, "blacklight %s, %spower down on reset, panel %s",
+		 (val & (1 << 2)) ? "enabled" : "disabled",
+		 (val & (1 << 1)) ? "" : "do not ",
+		 (val & (1 << 0)) ? "on" : "off");
+}
+
+DEBUGSTRING(hsw_debug_port_clk_sel)
+{
+	const char *clock = NULL;
+
+	switch ((val >> 29 ) & 7) {
+	case 0:
+		clock = "LCPLL 2700";
+		break;
+	case 1:
+		clock = "LCPLL 1350";
+		break;
+	case 2:
+		clock = "LCPLL 810";
+		break;
+	case 3:
+		clock = "SPLL";
+		break;
+	case 4:
+		clock = "WRPLL 1";
+		break;
+	case 5:
+		clock = "WRPLL 2";
+		break;
+	case 6:
+		clock = "Reserved";
+		break;
+	case 7:
+		clock = "None";
+		break;
+	}
+
+	snprintf(result, len, "%s", clock);
+}
+
+DEBUGSTRING(hsw_debug_pipe_clk_sel)
+{
+	const char *clock;
+
+	switch ((val >> 29) & 7) {
+	case 0:
+		clock = "None";
+		break;
+	case 2:
+		clock = "DDIB";
+		break;
+	case 3:
+		clock = "DDIC";
+		break;
+	case 4:
+		clock = "DDID";
+		break;
+	case 5:
+		clock = "DDIE";
+		break;
+	default:
+		clock = "Reserved";
+		break;
+	}
+
+	snprintf(result, len, "%s", clock);
+}
+
+DEBUGSTRING(hsw_debug_ddi_buf_ctl)
+{
+	const char *enable, *reversal, *width, *detected;
+
+	enable = (val & (1<<31)) ? "enabled" : "disabled";
+	reversal = (val & (1<<16)) ? "reversed" : "not reversed";
+
+	switch ((val >> 1) & 7) {
+	case 0:
+		width = "x1";
+		break;
+	case 1:
+		width = "x2";
+		break;
+	case 3:
+		width = "x4";
+		break;
+	default:
+		width = "reserved";
+		break;
+	}
+
+	detected = (val & 1) ? "detected" : "not detected";
+
+	snprintf(result, len, "%s %s %s %s", enable, reversal, width, detected);
+}
+
+DEBUGSTRING(hsw_debug_sfuse_strap)
+{
+	const char *display, *crt, *lane_reversal, *portb, *portc, *portd;
+
+	display = (val & (1<<7)) ? "disabled" : "enabled";
+	crt = (val & (1<<6)) ? "yes" : "no";
+	lane_reversal = (val & (1<<4)) ? "yes" : "no";
+	portb = (val & (1<<2)) ? "yes" : "no";
+	portc = (val & (1<<1)) ? "yes" : "no";
+	portd = (val & (1<<0)) ? "yes" : "no";
+
+	snprintf(result, len, "display %s, crt %s, lane reversal %s, "
+		 "port b %s, port c %s, port d %s", display, crt, lane_reversal,
+		 portb, portc, portd);
+}
+
+DEBUGSTRING(hsw_debug_pipe_ddi_func_ctl)
+{
+	const char *enable, *port, *mode, *bpc, *vsync, *hsync, *edp_input;
+	const char *width;
+
+	enable = (val & (1<<31)) ? "enabled" : "disabled";
+
+	switch ((val >> 28) & 7) {
+	case 0:
+		port = "no port";
+		break;
+	case 1:
+		port = "DDIB";
+		break;
+	case 2:
+		port = "DDIC";
+		break;
+	case 3:
+		port = "DDID";
+		break;
+	case 4:
+		port = "DDIE";
+		break;
+	default:
+		port = "port reserved";
+		break;
+	}
+
+	switch ((val >> 24) & 7) {
+	case 0:
+		mode = "HDMI";
+		break;
+	case 1:
+		mode = "DVI";
+		break;
+	case 2:
+		mode = "DP SST";
+		break;
+	case 3:
+		mode = "DP MST";
+		break;
+	case 4:
+		mode = "FDI";
+		break;
+	case 5:
+	default:
+		mode = "mode reserved";
+		break;
+	}
+
+	switch ((val >> 20) & 7) {
+	case 0:
+		bpc = "8 bpc";
+		break;
+	case 1:
+		bpc = "10 bpc";
+		break;
+	case 2:
+		bpc = "6 bpc";
+		break;
+	case 3:
+		bpc = "12 bpc";
+		break;
+	default:
+		bpc = "bpc reserved";
+		break;
+	}
+
+	hsync = (val & (1<<16)) ? "+HSync" : "-HSync";
+	vsync = (val & (1<<17)) ? "+VSync" : "-VSync";
+
+	switch ((val >> 12) & 7) {
+	case 0:
+		edp_input = "EDP A ON";
+		break;
+	case 4:
+		edp_input = "EDP A ONOFF";
+		break;
+	case 5:
+		edp_input = "EDP B ONOFF";
+		break;
+	case 6:
+		edp_input = "EDP C ONOFF";
+		break;
+	default:
+		edp_input = "EDP input reserved";
+		break;
+	}
+
+	switch ((val >> 1) & 7) {
+	case 0:
+		width = "x1";
+		break;
+	case 1:
+		width = "x2";
+		break;
+	case 3:
+		width = "x4";
+		break;
+	default:
+		width = "reserved width";
+		break;
+	}
+
+	snprintf(result, len, "%s, %s, %s, %s, %s, %s, %s, %s", enable,
+		 port, mode, bpc, vsync, hsync, edp_input, width);
+}
+
+DEBUGSTRING(hsw_debug_wm_pipe)
+{
+	uint32_t primary, sprite, cursor;
+
+	primary = (val >> 16) & 0x7F;
+	sprite = (val >> 8) & 0x7F;
+	cursor = val & 0x3F;
+
+	snprintf(result, len, "primary %d, sprite %d, pipe %d", primary,
+		 sprite, cursor);
+}
+
+DEBUGSTRING(hsw_debug_lp_wm)
+{
+	const char *enable;
+	uint32_t latency, fbc, pri, cur;
+
+	enable = ((val >> 31) & 1) ? "enabled" : "disabled";
+	latency = (val >> 24) & 0x7F;
+	fbc = (val >> 20) & 0xF;
+	pri = (val >> 8) & 0x3FF;
+	cur = val & 0xFF;
+
+	snprintf(result, len, "%s, latency %d, fbc %d, pri %d, cur %d",
+		 enable, latency, fbc, pri, cur);
+}
+
+DEBUGSTRING(hsw_debug_sinterrupt)
+{
+	int portd, portc, portb, crt;
+
+	portd = (val >> 23) & 1;
+	portc = (val >> 22) & 1;
+	portb = (val >> 21) & 1;
+	crt = (val >> 19) & 1;
+
+	snprintf(result, len, "port d:%d, port c:%d, port b:%d, crt:%d",
+		 portd, portc, portb, crt);
+}
+
+DEBUGSTRING(ilk_debug_blc_pwm_cpu_ctl2)
+{
+	int enable, blinking, granularity;
+	const char *pipe;
+
+	enable = (val >> 31) & 1;
+
+	if (IS_GEN5(devid) || IS_GEN6(devid)) {
+		pipe = ((val >> 29) & 1) ? "B" : "A";
+	} else {
+		switch ((val >> 29) & 3) {
+		case 0:
+			pipe = "A";
+			break;
+		case 1:
+			pipe = "B";
+			break;
+		case 2:
+			pipe = "C";
+			break;
+		case 3:
+			if (IS_IVYBRIDGE(devid))
+				pipe = "reserved";
+			else
+				pipe = "EDP";
+			break;
+		}
+	}
+
+	if (IS_GEN5(devid) || IS_GEN6(devid) || IS_IVYBRIDGE(devid)) {
+		snprintf(result, len, "enable %d, pipe %s", enable, pipe);
+	} else {
+		blinking = (val >> 28) & 1;
+		granularity = ((val >> 27) & 1) ? 8 : 128;
+
+		snprintf(result, len, "enable %d, pipe %s, blinking %d, "
+			 "granularity %d", enable, pipe, blinking,
+			 granularity);
+	}
+}
+
+DEBUGSTRING(ilk_debug_blc_pwm_cpu_ctl)
+{
+	int cycle, freq;
+
+	cycle = (val & 0xFFFF);
+
+	if (IS_GEN5(devid) || IS_GEN6(devid) || IS_IVYBRIDGE(devid)) {
+		snprintf(result, len, "cycle %d", cycle);
+	} else {
+		freq = (val >> 16) & 0xFFFF;
+
+		snprintf(result, len, "cycle %d, freq %d", cycle, freq);
+	}
+}
+
+DEBUGSTRING(ibx_debug_blc_pwm_ctl1)
+{
+	int enable, override, inverted_polarity;
+
+	enable = (val >> 31) & 1;
+	override = (val >> 30) & 1;
+	inverted_polarity = (val >> 29) & 1;
+
+	snprintf(result, len, "enable %d, override %d, inverted polarity %d",
+		 enable, override, inverted_polarity);
+}
+
+DEBUGSTRING(ibx_debug_blc_pwm_ctl2)
+{
+	int freq, cycle;
+
+	freq = (val >> 16) & 0xFFFF;
+	cycle = val & 0xFFFF;
+
+	snprintf(result, len, "freq %d, cycle %d", freq, cycle);
+}
+
+DEBUGSTRING(hsw_debug_blc_misc_ctl)
+{
+	const char *sel;
+
+	sel = (val & 1) ? "PWM1-CPU PWM2-PCH" : "PWM1-PCH PWM2-CPU";
+
+	snprintf(result, len, "%s", sel);
+}
+
+DEBUGSTRING(hsw_debug_util_pin_ctl)
+{
+	int enable, data, inverted_polarity;
+	const char *transcoder, *mode;
+
+	enable = (val >> 31) & 1;
+
+	switch ((val >> 29) & 3) {
+	case 0:
+		transcoder = "A";
+		break;
+	case 1:
+		transcoder = "B";
+		break;
+	case 2:
+		transcoder = "C";
+		break;
+	case 3:
+		transcoder = "EDP";
+		break;
+	}
+
+	switch ((val >> 24) & 0xF) {
+	case 0:
+		mode = "data";
+		break;
+	case 1:
+		mode = "PWM";
+		break;
+	case 4:
+		mode = "Vblank";
+		break;
+	case 5:
+		mode = "Vsync";
+		break;
+	default:
+		mode = "reserved";
+		break;
+	}
+
+	data = (val >> 23) & 1;
+	inverted_polarity = (val >> 22) & 1;
+
+	snprintf(result, len, "enable %d, transcoder %s, mode %s, data %d "
+		 "inverted polarity %d", enable, transcoder, mode, data,
+		 inverted_polarity);
+}
+
+static const struct reg_debug gen6_fences[] = {
+#define DEFINEFENCE_SNB(i) \
+	{ FENCE_REG_SANDYBRIDGE_0 + (i) * 8, "FENCE START "#i, NULL }, \
+	{ FENCE_REG_SANDYBRIDGE_0 + (i) * 8 + 4, "FENCE END "#i, NULL }
+	DEFINEFENCE_SNB(0),
+	DEFINEFENCE_SNB(1),
+	DEFINEFENCE_SNB(2),
+	DEFINEFENCE_SNB(3),
+	DEFINEFENCE_SNB(4),
+	DEFINEFENCE_SNB(5),
+	DEFINEFENCE_SNB(6),
+	DEFINEFENCE_SNB(7),
+	DEFINEFENCE_SNB(8),
+	DEFINEFENCE_SNB(9),
+	DEFINEFENCE_SNB(10),
+	DEFINEFENCE_SNB(11),
+	DEFINEFENCE_SNB(12),
+	DEFINEFENCE_SNB(13),
+	DEFINEFENCE_SNB(14),
+	DEFINEFENCE_SNB(15),
+	DEFINEFENCE_SNB(16),
+	DEFINEFENCE_SNB(17),
+	DEFINEFENCE_SNB(18),
+	DEFINEFENCE_SNB(19),
+	DEFINEFENCE_SNB(20),
+	DEFINEFENCE_SNB(20),
+	DEFINEFENCE_SNB(21),
+	DEFINEFENCE_SNB(22),
+	DEFINEFENCE_SNB(23),
+	DEFINEFENCE_SNB(24),
+	DEFINEFENCE_SNB(25),
+	DEFINEFENCE_SNB(26),
+	DEFINEFENCE_SNB(27),
+	DEFINEFENCE_SNB(28),
+	DEFINEFENCE_SNB(29),
+	DEFINEFENCE_SNB(30),
+	DEFINEFENCE_SNB(31),
+};
+
+static const struct reg_debug ironlake_debug_regs[] = {
+	DEFINEREG(PGETBL_CTL),
+	DEFINEREG(INSTDONE_I965),
+	DEFINEREG(INSTDONE_1),
+	DEFINEREG2(CPU_VGACNTRL, i830_debug_vgacntrl),
+	DEFINEREG(DIGITAL_PORT_HOTPLUG_CNTRL),
+
+	DEFINEREG2(RR_HW_CTL, ironlake_debug_rr_hw_ctl),
+
+	DEFINEREG(FDI_PLL_BIOS_0),
+	DEFINEREG(FDI_PLL_BIOS_1),
+	DEFINEREG(FDI_PLL_BIOS_2),
+
+	DEFINEREG(DISPLAY_PORT_PLL_BIOS_0),
+	DEFINEREG(DISPLAY_PORT_PLL_BIOS_1),
+	DEFINEREG(DISPLAY_PORT_PLL_BIOS_2),
+
+	DEFINEREG(FDI_PLL_FREQ_CTL),
+
+	/* pipe B */
+
+	DEFINEREG2(PIPEACONF, i830_debug_pipeconf),
+
+	DEFINEREG2(HTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(HBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(HSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG2(VTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(VBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(VSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG(VSYNCSHIFT_A),
+	DEFINEREG2(PIPEASRC, i830_debug_yxminus1),
+
+	DEFINEREG2(PIPEA_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEA_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEA_DATA_M2, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEA_DATA_N2, ironlake_debug_n),
+
+	DEFINEREG2(PIPEA_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(PIPEA_LINK_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEA_LINK_M2, ironlake_debug_n),
+	DEFINEREG2(PIPEA_LINK_N2, ironlake_debug_n),
+
+	DEFINEREG2(DSPACNTR, i830_debug_dspcntr),
+	DEFINEREG(DSPABASE),
+	DEFINEREG2(DSPASTRIDE, ironlake_debug_dspstride),
+	DEFINEREG(DSPASURF),
+	DEFINEREG2(DSPATILEOFF, i830_debug_xy),
+
+	/* pipe B */
+
+	DEFINEREG2(PIPEBCONF, i830_debug_pipeconf),
+
+	DEFINEREG2(HTOTAL_B, i830_debug_hvtotal),
+	DEFINEREG2(HBLANK_B, i830_debug_hvsyncblank),
+	DEFINEREG2(HSYNC_B, i830_debug_hvsyncblank),
+	DEFINEREG2(VTOTAL_B, i830_debug_hvtotal),
+	DEFINEREG2(VBLANK_B, i830_debug_hvsyncblank),
+	DEFINEREG2(VSYNC_B, i830_debug_hvsyncblank),
+	DEFINEREG(VSYNCSHIFT_B),
+	DEFINEREG2(PIPEBSRC, i830_debug_yxminus1),
+
+	DEFINEREG2(PIPEB_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEB_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEB_DATA_M2, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEB_DATA_N2, ironlake_debug_n),
+
+	DEFINEREG2(PIPEB_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(PIPEB_LINK_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEB_LINK_M2, ironlake_debug_n),
+	DEFINEREG2(PIPEB_LINK_N2, ironlake_debug_n),
+
+	DEFINEREG2(DSPBCNTR, i830_debug_dspcntr),
+	DEFINEREG(DSPBBASE),
+	DEFINEREG2(DSPBSTRIDE, ironlake_debug_dspstride),
+	DEFINEREG(DSPBSURF),
+	DEFINEREG2(DSPBTILEOFF, i830_debug_xy),
+
+	/* pipe C */
+
+	DEFINEREG2(PIPECCONF, i830_debug_pipeconf),
+
+	DEFINEREG2(HTOTAL_C, i830_debug_hvtotal),
+	DEFINEREG2(HBLANK_C, i830_debug_hvsyncblank),
+	DEFINEREG2(HSYNC_C, i830_debug_hvsyncblank),
+	DEFINEREG2(VTOTAL_C, i830_debug_hvtotal),
+	DEFINEREG2(VBLANK_C, i830_debug_hvsyncblank),
+	DEFINEREG2(VSYNC_C, i830_debug_hvsyncblank),
+	DEFINEREG(VSYNCSHIFT_C),
+	DEFINEREG2(PIPECSRC, i830_debug_yxminus1),
+
+	DEFINEREG2(PIPEC_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEC_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEC_DATA_M2, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEC_DATA_N2, ironlake_debug_n),
+
+	DEFINEREG2(PIPEC_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(PIPEC_LINK_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEC_LINK_M2, ironlake_debug_n),
+	DEFINEREG2(PIPEC_LINK_N2, ironlake_debug_n),
+
+	DEFINEREG2(DSPCCNTR, i830_debug_dspcntr),
+	DEFINEREG(DSPCBASE),
+	DEFINEREG2(DSPCSTRIDE, ironlake_debug_dspstride),
+	DEFINEREG(DSPCSURF),
+	DEFINEREG2(DSPCTILEOFF, i830_debug_xy),
+
+	/* Panel fitter */
+
+	DEFINEREG2(PFA_CTL_1, ironlake_debug_panel_fitting),
+	DEFINEREG2(PFA_CTL_2, ironlake_debug_panel_fitting_2),
+	DEFINEREG2(PFA_CTL_3, ironlake_debug_panel_fitting_3),
+	DEFINEREG2(PFA_CTL_4, ironlake_debug_panel_fitting_4),
+	DEFINEREG2(PFA_WIN_POS, ironlake_debug_pf_win),
+	DEFINEREG2(PFA_WIN_SIZE, ironlake_debug_pf_win),
+	DEFINEREG2(PFB_CTL_1, ironlake_debug_panel_fitting),
+	DEFINEREG2(PFB_CTL_2, ironlake_debug_panel_fitting_2),
+	DEFINEREG2(PFB_CTL_3, ironlake_debug_panel_fitting_3),
+	DEFINEREG2(PFB_CTL_4, ironlake_debug_panel_fitting_4),
+	DEFINEREG2(PFB_WIN_POS, ironlake_debug_pf_win),
+	DEFINEREG2(PFB_WIN_SIZE, ironlake_debug_pf_win),
+	DEFINEREG2(PFC_CTL_1, ironlake_debug_panel_fitting),
+	DEFINEREG2(PFC_CTL_2, ironlake_debug_panel_fitting_2),
+	DEFINEREG2(PFC_CTL_3, ironlake_debug_panel_fitting_3),
+	DEFINEREG2(PFC_CTL_4, ironlake_debug_panel_fitting_4),
+	DEFINEREG2(PFC_WIN_POS, ironlake_debug_pf_win),
+	DEFINEREG2(PFC_WIN_SIZE, ironlake_debug_pf_win),
+
+	/* PCH */
+
+	DEFINEREG2(PCH_DREF_CONTROL, ironlake_debug_dref_ctl),
+	DEFINEREG2(PCH_RAWCLK_FREQ, ironlake_debug_rawclk_freq),
+	DEFINEREG(PCH_DPLL_TMR_CFG),
+	DEFINEREG(PCH_SSC4_PARMS),
+	DEFINEREG(PCH_SSC4_AUX_PARMS),
+	DEFINEREG2(PCH_DPLL_SEL, snb_debug_dpll_sel),
+	DEFINEREG(PCH_DPLL_ANALOG_CTL),
+
+	DEFINEREG2(PCH_DPLL_A, ironlake_debug_pch_dpll),
+	DEFINEREG2(PCH_DPLL_B, ironlake_debug_pch_dpll),
+	DEFINEREG2(PCH_FPA0, i830_debug_fp),
+	DEFINEREG2(PCH_FPA1, i830_debug_fp),
+	DEFINEREG2(PCH_FPB0, i830_debug_fp),
+	DEFINEREG2(PCH_FPB1, i830_debug_fp),
+
+	DEFINEREG2(TRANS_HTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(TRANS_HBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_HSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_VTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(TRANS_VBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_VSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG(TRANS_VSYNCSHIFT_A),
+
+	DEFINEREG2(TRANSA_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(TRANSA_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(TRANSA_DATA_M2, ironlake_debug_m_tu),
+	DEFINEREG2(TRANSA_DATA_N2, ironlake_debug_n),
+	DEFINEREG2(TRANSA_DP_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(TRANSA_DP_LINK_N1, ironlake_debug_n),
+	DEFINEREG2(TRANSA_DP_LINK_M2, ironlake_debug_n),
+	DEFINEREG2(TRANSA_DP_LINK_N2, ironlake_debug_n),
+
+	DEFINEREG2(TRANS_HTOTAL_B, i830_debug_hvtotal),
+	DEFINEREG2(TRANS_HBLANK_B, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_HSYNC_B, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_VTOTAL_B, i830_debug_hvtotal),
+	DEFINEREG2(TRANS_VBLANK_B, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_VSYNC_B, i830_debug_hvsyncblank),
+	DEFINEREG(TRANS_VSYNCSHIFT_B),
+
+	DEFINEREG2(TRANSB_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(TRANSB_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(TRANSB_DATA_M2, ironlake_debug_m_tu),
+	DEFINEREG2(TRANSB_DATA_N2, ironlake_debug_n),
+	DEFINEREG2(TRANSB_DP_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(TRANSB_DP_LINK_N1, ironlake_debug_n),
+	DEFINEREG2(TRANSB_DP_LINK_M2, ironlake_debug_n),
+	DEFINEREG2(TRANSB_DP_LINK_N2, ironlake_debug_n),
+
+	DEFINEREG2(TRANS_HTOTAL_C, i830_debug_hvtotal),
+	DEFINEREG2(TRANS_HBLANK_C, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_HSYNC_C, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_VTOTAL_C, i830_debug_hvtotal),
+	DEFINEREG2(TRANS_VBLANK_C, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_VSYNC_C, i830_debug_hvsyncblank),
+	DEFINEREG(TRANS_VSYNCSHIFT_C),
+
+	DEFINEREG2(TRANSC_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(TRANSC_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(TRANSC_DATA_M2, ironlake_debug_m_tu),
+	DEFINEREG2(TRANSC_DATA_N2, ironlake_debug_n),
+	DEFINEREG2(TRANSC_DP_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(TRANSC_DP_LINK_N1, ironlake_debug_n),
+	DEFINEREG2(TRANSC_DP_LINK_M2, ironlake_debug_n),
+	DEFINEREG2(TRANSC_DP_LINK_N2, ironlake_debug_n),
+
+	DEFINEREG2(TRANSACONF, ironlake_debug_transconf),
+	DEFINEREG2(TRANSBCONF, ironlake_debug_transconf),
+	DEFINEREG2(TRANSCCONF, ironlake_debug_transconf),
+
+	DEFINEREG2(FDI_TXA_CTL, ironlake_debug_fdi_tx_ctl),
+	DEFINEREG2(FDI_TXB_CTL, ironlake_debug_fdi_tx_ctl),
+	DEFINEREG2(FDI_TXC_CTL, ironlake_debug_fdi_tx_ctl),
+	DEFINEREG2(FDI_RXA_CTL, ironlake_debug_fdi_rx_ctl),
+	DEFINEREG2(FDI_RXB_CTL, ironlake_debug_fdi_rx_ctl),
+	DEFINEREG2(FDI_RXC_CTL, ironlake_debug_fdi_rx_ctl),
+
+	DEFINEREG(DPAFE_BMFUNC),
+	DEFINEREG(DPAFE_DL_IREFCAL0),
+	DEFINEREG(DPAFE_DL_IREFCAL1),
+	DEFINEREG(DPAFE_DP_IREFCAL),
+
+	DEFINEREG(PCH_DSPCLK_GATE_D),
+	DEFINEREG(PCH_DSP_CHICKEN1),
+	DEFINEREG(PCH_DSP_CHICKEN2),
+	DEFINEREG(PCH_DSP_CHICKEN3),
+
+	DEFINEREG2(FDI_RXA_MISC, ironlake_debug_fdi_rx_misc),
+	DEFINEREG2(FDI_RXB_MISC, ironlake_debug_fdi_rx_misc),
+	DEFINEREG2(FDI_RXC_MISC, ironlake_debug_fdi_rx_misc),
+	DEFINEREG(FDI_RXA_TUSIZE1),
+	DEFINEREG(FDI_RXA_TUSIZE2),
+	DEFINEREG(FDI_RXB_TUSIZE1),
+	DEFINEREG(FDI_RXB_TUSIZE2),
+	DEFINEREG(FDI_RXC_TUSIZE1),
+	DEFINEREG(FDI_RXC_TUSIZE2),
+
+	DEFINEREG(FDI_PLL_CTL_1),
+	DEFINEREG(FDI_PLL_CTL_2),
+
+	DEFINEREG(FDI_RXA_IIR),
+	DEFINEREG(FDI_RXA_IMR),
+	DEFINEREG(FDI_RXB_IIR),
+	DEFINEREG(FDI_RXB_IMR),
+
+	DEFINEREG2(PCH_ADPA, i830_debug_adpa),
+	DEFINEREG2(HDMIB, ironlake_debug_hdmi),
+	DEFINEREG2(HDMIC, ironlake_debug_hdmi),
+	DEFINEREG2(HDMID, ironlake_debug_hdmi),
+	DEFINEREG2(PCH_LVDS, i830_debug_lvds),
+	DEFINEREG(CPU_eDP_A),
+	DEFINEREG(PCH_DP_B),
+	DEFINEREG(PCH_DP_C),
+	DEFINEREG(PCH_DP_D),
+	DEFINEREG2(TRANS_DP_CTL_A, snb_debug_trans_dp_ctl),
+	DEFINEREG2(TRANS_DP_CTL_B, snb_debug_trans_dp_ctl),
+	DEFINEREG2(TRANS_DP_CTL_C, snb_debug_trans_dp_ctl),
+
+	DEFINEREG2(BLC_PWM_CPU_CTL2, ilk_debug_blc_pwm_cpu_ctl2),
+	DEFINEREG2(BLC_PWM_CPU_CTL, ilk_debug_blc_pwm_cpu_ctl),
+	DEFINEREG2(BLC_PWM_PCH_CTL1, ibx_debug_blc_pwm_ctl1),
+	DEFINEREG2(BLC_PWM_PCH_CTL2, ibx_debug_blc_pwm_ctl2),
+
+	DEFINEREG2(PCH_PP_STATUS, i830_debug_pp_status),
+	DEFINEREG2(PCH_PP_CONTROL, ilk_debug_pp_control),
+	DEFINEREG(PCH_PP_ON_DELAYS),
+	DEFINEREG(PCH_PP_OFF_DELAYS),
+	DEFINEREG(PCH_PP_DIVISOR),
+
+	DEFINEREG2(PORT_DBG, ivb_debug_port),
+
+	DEFINEREG(RC6_RESIDENCY_TIME),
+	DEFINEREG(RC6p_RESIDENCY_TIME),
+	DEFINEREG(RC6pp_RESIDENCY_TIME),
+};
+
+static const struct reg_debug haswell_debug_regs[] = {
+	/* Power wells */
+	DEFINEREG(HSW_PWR_WELL_CTL1),
+	DEFINEREG(HSW_PWR_WELL_CTL2),
+	DEFINEREG(HSW_PWR_WELL_CTL3),
+	DEFINEREG(HSW_PWR_WELL_CTL4),
+	DEFINEREG(HSW_PWR_WELL_CTL5),
+	DEFINEREG(HSW_PWR_WELL_CTL6),
+
+	/* DDI pipe function */
+	DEFINEREG2(PIPE_DDI_FUNC_CTL_A, hsw_debug_pipe_ddi_func_ctl),
+	DEFINEREG2(PIPE_DDI_FUNC_CTL_B, hsw_debug_pipe_ddi_func_ctl),
+	DEFINEREG2(PIPE_DDI_FUNC_CTL_C, hsw_debug_pipe_ddi_func_ctl),
+	DEFINEREG2(PIPE_DDI_FUNC_CTL_EDP, hsw_debug_pipe_ddi_func_ctl),
+
+	/* DP transport control */
+	DEFINEREG(DP_TP_CTL_A),
+	DEFINEREG(DP_TP_CTL_B),
+	DEFINEREG(DP_TP_CTL_C),
+	DEFINEREG(DP_TP_CTL_D),
+	DEFINEREG(DP_TP_CTL_E),
+
+	/* DP status */
+	DEFINEREG(DP_TP_STATUS_B),
+	DEFINEREG(DP_TP_STATUS_C),
+	DEFINEREG(DP_TP_STATUS_D),
+	DEFINEREG(DP_TP_STATUS_E),
+
+	/* DDI buffer control */
+	DEFINEREG2(DDI_BUF_CTL_A, hsw_debug_ddi_buf_ctl),
+	DEFINEREG2(DDI_BUF_CTL_B, hsw_debug_ddi_buf_ctl),
+	DEFINEREG2(DDI_BUF_CTL_C, hsw_debug_ddi_buf_ctl),
+	DEFINEREG2(DDI_BUF_CTL_D, hsw_debug_ddi_buf_ctl),
+	DEFINEREG2(DDI_BUF_CTL_E, hsw_debug_ddi_buf_ctl),
+
+	/* Clocks */
+	DEFINEREG(SPLL_CTL),
+	DEFINEREG(LCPLL_CTL),
+	DEFINEREG(WRPLL_CTL1),
+	DEFINEREG(WRPLL_CTL2),
+
+	/* DDI port clock control */
+	DEFINEREG2(PORT_CLK_SEL_A, hsw_debug_port_clk_sel),
+	DEFINEREG2(PORT_CLK_SEL_B, hsw_debug_port_clk_sel),
+	DEFINEREG2(PORT_CLK_SEL_C, hsw_debug_port_clk_sel),
+	DEFINEREG2(PORT_CLK_SEL_D, hsw_debug_port_clk_sel),
+	DEFINEREG2(PORT_CLK_SEL_E, hsw_debug_port_clk_sel),
+
+	/* Pipe clock control */
+	DEFINEREG2(PIPE_CLK_SEL_A, hsw_debug_pipe_clk_sel),
+	DEFINEREG2(PIPE_CLK_SEL_B, hsw_debug_pipe_clk_sel),
+	DEFINEREG2(PIPE_CLK_SEL_C, hsw_debug_pipe_clk_sel),
+
+	/* Watermarks */
+	DEFINEREG2(WM_PIPE_A, hsw_debug_wm_pipe),
+	DEFINEREG2(WM_PIPE_B, hsw_debug_wm_pipe),
+	DEFINEREG2(WM_PIPE_C, hsw_debug_wm_pipe),
+	DEFINEREG2(WM_LP1, hsw_debug_lp_wm),
+	DEFINEREG2(WM_LP2, hsw_debug_lp_wm),
+	DEFINEREG2(WM_LP3, hsw_debug_lp_wm),
+	DEFINEREG(WM_LP1_SPR),
+	DEFINEREG(WM_LP2_SPR),
+	DEFINEREG(WM_LP3_SPR),
+	DEFINEREG(WM_MISC),
+	DEFINEREG(WM_SR_CNT),
+	DEFINEREG(PIPE_WM_LINETIME_A),
+	DEFINEREG(PIPE_WM_LINETIME_B),
+	DEFINEREG(PIPE_WM_LINETIME_C),
+	DEFINEREG(WM_DBG),
+
+	/* Fuses */
+	DEFINEREG2(SFUSE_STRAP, hsw_debug_sfuse_strap),
+
+	/* Pipe A */
+	DEFINEREG2(PIPEASRC, i830_debug_yxminus1),
+	DEFINEREG2(DSPACNTR, i830_debug_dspcntr),
+	DEFINEREG2(DSPASTRIDE, ironlake_debug_dspstride),
+	DEFINEREG(DSPASURF),
+	DEFINEREG2(DSPATILEOFF, i830_debug_xy),
+
+	/* Pipe B */
+	DEFINEREG2(PIPEBSRC, i830_debug_yxminus1),
+	DEFINEREG2(DSPBCNTR, i830_debug_dspcntr),
+	DEFINEREG2(DSPBSTRIDE, ironlake_debug_dspstride),
+	DEFINEREG(DSPBSURF),
+	DEFINEREG2(DSPBTILEOFF, i830_debug_xy),
+
+	/* Pipe C */
+	DEFINEREG2(PIPECSRC, i830_debug_yxminus1),
+	DEFINEREG2(DSPCCNTR, i830_debug_dspcntr),
+	DEFINEREG2(DSPCSTRIDE, ironlake_debug_dspstride),
+	DEFINEREG(DSPCSURF),
+	DEFINEREG2(DSPCTILEOFF, i830_debug_xy),
+
+	/* Transcoder A */
+	DEFINEREG2(PIPEACONF, i830_debug_pipeconf),
+	DEFINEREG2(HTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(HBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(HSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG2(VTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(VBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(VSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG(VSYNCSHIFT_A),
+	DEFINEREG2(PIPEA_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEA_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEA_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(PIPEA_LINK_N1, ironlake_debug_n),
+
+	/* Transcoder B */
+	DEFINEREG2(PIPEBCONF, i830_debug_pipeconf),
+	DEFINEREG2(HTOTAL_B, i830_debug_hvtotal),
+	DEFINEREG2(HBLANK_B, i830_debug_hvsyncblank),
+	DEFINEREG2(HSYNC_B, i830_debug_hvsyncblank),
+	DEFINEREG2(VTOTAL_B, i830_debug_hvtotal),
+	DEFINEREG2(VBLANK_B, i830_debug_hvsyncblank),
+	DEFINEREG2(VSYNC_B, i830_debug_hvsyncblank),
+	DEFINEREG(VSYNCSHIFT_B),
+	DEFINEREG2(PIPEB_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEB_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEB_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(PIPEB_LINK_N1, ironlake_debug_n),
+
+	/* Transcoder C */
+	DEFINEREG2(PIPECCONF, i830_debug_pipeconf),
+	DEFINEREG2(HTOTAL_C, i830_debug_hvtotal),
+	DEFINEREG2(HBLANK_C, i830_debug_hvsyncblank),
+	DEFINEREG2(HSYNC_C, i830_debug_hvsyncblank),
+	DEFINEREG2(VTOTAL_C, i830_debug_hvtotal),
+	DEFINEREG2(VBLANK_C, i830_debug_hvsyncblank),
+	DEFINEREG2(VSYNC_C, i830_debug_hvsyncblank),
+	DEFINEREG(VSYNCSHIFT_C),
+	DEFINEREG2(PIPEC_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEC_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEC_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(PIPEC_LINK_N1, ironlake_debug_n),
+
+	/* Transcoder EDP */
+	DEFINEREG2(PIPEEDPCONF, i830_debug_pipeconf),
+	DEFINEREG2(HTOTAL_EDP, i830_debug_hvtotal),
+	DEFINEREG2(HBLANK_EDP, i830_debug_hvsyncblank),
+	DEFINEREG2(HSYNC_EDP, i830_debug_hvsyncblank),
+	DEFINEREG2(VTOTAL_EDP, i830_debug_hvtotal),
+	DEFINEREG2(VBLANK_EDP, i830_debug_hvsyncblank),
+	DEFINEREG2(VSYNC_EDP, i830_debug_hvsyncblank),
+	DEFINEREG(VSYNCSHIFT_EDP),
+	DEFINEREG2(PIPEEDP_DATA_M1, ironlake_debug_m_tu),
+	DEFINEREG2(PIPEEDP_DATA_N1, ironlake_debug_n),
+	DEFINEREG2(PIPEEDP_LINK_M1, ironlake_debug_n),
+	DEFINEREG2(PIPEEDP_LINK_N1, ironlake_debug_n),
+
+	/* Panel fitter */
+	DEFINEREG2(PFA_CTL_1, ironlake_debug_panel_fitting),
+	DEFINEREG2(PFA_WIN_POS, ironlake_debug_pf_win),
+	DEFINEREG2(PFA_WIN_SIZE, ironlake_debug_pf_win),
+
+	DEFINEREG2(PFB_CTL_1, ironlake_debug_panel_fitting),
+	DEFINEREG2(PFB_WIN_POS, ironlake_debug_pf_win),
+	DEFINEREG2(PFB_WIN_SIZE, ironlake_debug_pf_win),
+
+	DEFINEREG2(PFC_CTL_1, ironlake_debug_panel_fitting),
+	DEFINEREG2(PFC_WIN_POS, ironlake_debug_pf_win),
+	DEFINEREG2(PFC_WIN_SIZE, ironlake_debug_pf_win),
+
+	/* LPT */
+
+	DEFINEREG2(TRANS_HTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(TRANS_HBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_HSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_VTOTAL_A, i830_debug_hvtotal),
+	DEFINEREG2(TRANS_VBLANK_A, i830_debug_hvsyncblank),
+	DEFINEREG2(TRANS_VSYNC_A, i830_debug_hvsyncblank),
+	DEFINEREG(TRANS_VSYNCSHIFT_A),
+
+	DEFINEREG2(TRANSACONF, ironlake_debug_transconf),
+
+	DEFINEREG2(FDI_RXA_MISC, ironlake_debug_fdi_rx_misc),
+	DEFINEREG(FDI_RXA_TUSIZE1),
+	DEFINEREG(FDI_RXA_IIR),
+	DEFINEREG(FDI_RXA_IMR),
+
+	DEFINEREG2(BLC_PWM_CPU_CTL2, ilk_debug_blc_pwm_cpu_ctl2),
+	DEFINEREG2(BLC_PWM_CPU_CTL, ilk_debug_blc_pwm_cpu_ctl),
+	DEFINEREG2(BLC_PWM2_CPU_CTL2, ilk_debug_blc_pwm_cpu_ctl2),
+	DEFINEREG2(BLC_PWM2_CPU_CTL, ilk_debug_blc_pwm_cpu_ctl),
+	DEFINEREG2(BLC_MISC_CTL, hsw_debug_blc_misc_ctl),
+	DEFINEREG2(BLC_PWM_PCH_CTL1, ibx_debug_blc_pwm_ctl1),
+	DEFINEREG2(BLC_PWM_PCH_CTL2, ibx_debug_blc_pwm_ctl2),
+
+	DEFINEREG2(UTIL_PIN_CTL, hsw_debug_util_pin_ctl),
+
+	DEFINEREG2(PCH_PP_STATUS, i830_debug_pp_status),
+	DEFINEREG2(PCH_PP_CONTROL, ilk_debug_pp_control),
+	DEFINEREG(PCH_PP_ON_DELAYS),
+	DEFINEREG(PCH_PP_OFF_DELAYS),
+	DEFINEREG(PCH_PP_DIVISOR),
+
+	DEFINEREG(PIXCLK_GATE),
+
+	DEFINEREG2(SDEISR, hsw_debug_sinterrupt),
+
+	DEFINEREG(RC6_RESIDENCY_TIME),
+};
+
+static const struct reg_debug i945gm_mi_regs[] = {
+	DEFINEREG(PGETBL_CTL),
+	DEFINEREG(PGTBL_ER),
+	DEFINEREG(EXCC),
+	DEFINEREG(HWS_PGA),
+	DEFINEREG(IPEIR),
+	DEFINEREG(IPEHR),
+	DEFINEREG(INSTDONE),
+	DEFINEREG(NOP_ID),
+	DEFINEREG(HWSTAM),
+	DEFINEREG(SCPD0),
+	DEFINEREG(IER),
+	DEFINEREG(IIR),
+	DEFINEREG(IMR),
+	DEFINEREG(ISR),
+	DEFINEREG(EIR),
+	DEFINEREG(EMR),
+	DEFINEREG(ESR),
+	DEFINEREG(INST_PM),
+	DEFINEREG(ECOSKPD),
+};
+
+DEBUGSTRING(gen6_rp_control)
+{
+	snprintf(result, len, "%s",
+		 (val & (1 << 7)) ? "enabled" : "disabled");
+}
+
+static const struct reg_debug gen6_rp_debug_regs[] = {
+	DEFINEREG2(GEN6_RP_CONTROL, gen6_rp_control),
+	DEFINEREG(GEN6_RPNSWREQ),
+	DEFINEREG(GEN6_RP_DOWN_TIMEOUT),
+	DEFINEREG(GEN6_RP_INTERRUPT_LIMITS),
+	DEFINEREG(GEN6_RP_UP_THRESHOLD),
+	DEFINEREG(GEN6_RP_UP_EI),
+	DEFINEREG(GEN6_RP_DOWN_EI),
+	DEFINEREG(GEN6_RP_IDLE_HYSTERSIS),
+	DEFINEREG(GEN6_RC_STATE),
+	DEFINEREG(GEN6_RC_CONTROL),
+	DEFINEREG(GEN6_RC1_WAKE_RATE_LIMIT),
+	DEFINEREG(GEN6_RC6_WAKE_RATE_LIMIT),
+	DEFINEREG(GEN6_RC_EVALUATION_INTERVAL),
+	DEFINEREG(GEN6_RC_IDLE_HYSTERSIS),
+	DEFINEREG(GEN6_RC_SLEEP),
+	DEFINEREG(GEN6_RC1e_THRESHOLD),
+	DEFINEREG(GEN6_RC6_THRESHOLD),
+	DEFINEREG(GEN6_RC_VIDEO_FREQ),
+	DEFINEREG(GEN6_PMIER),
+	DEFINEREG(GEN6_PMIMR),
+	DEFINEREG(GEN6_PMINTRMSK),
+};
+
+static bool is_hsw_plus(uint32_t devid, uint32_t pch)
+{
+	return IS_HASWELL(devid) || intel_gen(devid) >= 8;
+}
+
+static bool is_gen6_plus(uint32_t devid, uint32_t pch)
+{
+	return intel_gen(devid) >= 6;
+}
+
+static bool is_gen56ivb(uint32_t devid, uint32_t pch)
+{
+	return IS_GEN5(devid) || IS_GEN6(devid) || IS_IVYBRIDGE(devid);
+}
+
+static bool is_945gm(uint32_t devid, uint32_t pch)
+{
+	return IS_945GM(devid);
+}
+
+static bool is_gen234(uint32_t devid, uint32_t pch)
+{
+	return IS_GEN2(devid) || IS_GEN3(devid) || IS_GEN3(devid);
+}
+
+#define DECLARE_REGS(d,r,m)				\
+	{ .description = d, .regs = r, .count = ARRAY_SIZE(r), .match = m }
+static struct {
+	const char *description;
+	const struct reg_debug *regs;
+	bool (*match)(uint32_t devid, uint32_t pch);
+	int count;
+} known_registers[] = {
+	DECLARE_REGS("Gen2",	intel_debug_regs,	is_gen234),
+	DECLARE_REGS("i945GM",	i945gm_mi_regs,		is_945gm),
+	DECLARE_REGS("Gen5",	ironlake_debug_regs,	is_gen56ivb),
+	DECLARE_REGS("Gen6",	gen6_rp_debug_regs,	is_gen6_plus),
+	DECLARE_REGS("Gen6+",	gen6_fences,		is_gen6_plus),
+	DECLARE_REGS("Gen7.5",	haswell_debug_regs,	is_hsw_plus),
+};
+#undef DECLARE_REGS
+
+/*
+ * Decode register value into buffer for devid.
+ *
+ * If devid is 0, decode for all known platforms, with newline after each
+ * decode.
+ */
+int intel_reg_spec_decode(char *buf, size_t bufsize, const struct reg *reg,
+			  uint32_t val, uint32_t devid)
+{
+	char tmp[1024];
+	int i, j;
+
+	if (!bufsize)
+		return -1;
+
+	*buf = 0;
+
+	for (i = 0; i < ARRAY_SIZE(known_registers); i++) {
+		const struct reg_debug *regs = known_registers[i].regs;
+
+		if (devid) {
+			if (known_registers[i].match &&
+			    !known_registers[i].match(devid, 0))
+				continue;
+		}
+
+		for (j = 0; j < known_registers[i].count; j++) {
+			const struct reg_debug *r = &regs[j];
+			if (reg->addr != r->reg)
+				continue;
+
+			if (r->debug_output)
+				r->debug_output(tmp, sizeof(tmp), r->reg,
+						val, devid);
+			else if (devid)
+				return 0;
+			else
+				continue;
+
+			if (devid) {
+				strncpy(buf, tmp, bufsize);
+				return 0;
+			}
+
+			strncat(buf, known_registers[i].description, bufsize);
+			strncat(buf, "\t", bufsize);
+			strncat(buf, tmp, bufsize);
+			strncat(buf, "\n", bufsize);
+		}
+	}
+
+	return 0;
+}
+
+static ssize_t get_regs(struct reg **regs, size_t *nregs, ssize_t index,
+			uint32_t devid)
+{
+	ssize_t ret = -1;
+	int i, j;
+
+	if (!devid)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(known_registers); i++) {
+		if (known_registers[i].match &&
+		    !known_registers[i].match(devid, 0))
+			continue;
+
+		for (j = 0; j < known_registers[i].count; j++) {
+			const struct reg_debug *reg_in =
+				&known_registers[i].regs[j];
+			struct reg reg;
+
+			/* XXX: Could be optimized. */
+			parse_port_desc(&reg, NULL);
+
+			reg.name = strdup(reg_in->name);
+			reg.addr = reg_in->reg;
+
+			if (!*regs || index >= *nregs) {
+				if (!*regs)
+					*nregs = 64;
+				else
+					*nregs *= 2;
+
+				*regs = recalloc(*regs, *nregs, sizeof(**regs));
+				if (!*regs) {
+					fprintf(stderr, "Error: %s\n", strerror(ENOMEM));
+					goto out;
+				}
+			}
+
+			(*regs)[index++] = reg;
+		}
+	}
+
+	ret = index;
+
+out:
+	return ret;
+}
+
+/*
+ * Get builtin register definitions for devid.
+ */
+ssize_t intel_reg_spec_builtin(struct reg **regs, uint32_t devid)
+{
+	size_t nregs = 0;
+	*regs = NULL;
+
+	return get_regs(regs, &nregs, 0, devid);
+}
diff --git a/tools/intel_reg_spec.c b/tools/intel_reg_spec.c
new file mode 100644
index 000000000000..6b7e30c12fbf
--- /dev/null
+++ b/tools/intel_reg_spec.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <regex.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "intel_reg_spec.h"
+
+static const struct port_desc port_descs[] = {
+	{
+		.name = "mmio",
+		.port = PORT_MMIO,
+		.stride = 4,
+	},
+	{
+		.name = "portio-vga",
+		.port = PORT_PORTIO_VGA,
+		.stride = 4,
+	},
+	{
+		.name = "mmio-vga",
+		.port = PORT_MMIO_VGA,
+		.stride = 4,
+	},
+	{
+		.name = "bunit",
+		.port = PORT_BUNIT,
+		.stride = 1,
+	},
+	{
+		.name = "punit",
+		.port = PORT_PUNIT,
+		.stride = 1,
+	},
+	{
+		.name = "nc",
+		.port = PORT_NC,
+		.stride = 4,
+	},
+	{
+		.name = "dpio",
+		.port = PORT_DPIO,
+		.stride = 4,
+	},
+	{
+		.name = "gpio-nc",
+		.port = PORT_GPIO_NC,
+		.stride = 4,
+	},
+	{
+		.name = "gpio_nc",
+		.port = PORT_GPIO_NC,
+		.stride = 4,
+	},
+	{
+		.name = "cck",
+		.port = PORT_CCK,
+		.stride = 1,
+	},
+	{
+		.name = "ccu",
+		.port = PORT_CCU,
+		.stride = 4,
+	},
+	{
+		.name = "dpio2",
+		.port = PORT_DPIO2,
+		.stride = 4,
+	},
+	{
+		.name = "flisdsi",
+		.port = PORT_FLISDSI,
+		.stride = 1,
+	},
+};
+
+/*
+ * Parse port desc of the form (PORTNAME|PORTNUM|MMIO-OFFSET) into reg. NULL or
+ * zero length s is regarded as MMIO.
+ */
+int parse_port_desc(struct reg *reg, const char *s)
+{
+	enum port_addr port = PORT_NONE;
+	int i;
+
+	if (s && *s) {
+		/* See if port is specified by number. */
+		char *endp;
+		unsigned long n = strtoul(s, &endp, 16);
+		if (endp > s && *endp == 0) {
+			if (n > PORT_MAX) {
+				/* Not a sideband port, assume MMIO offset. */
+				port = PORT_MMIO;
+				reg->mmio_offset = n;
+			} else {
+				port = n;
+				reg->mmio_offset = 0;
+			}
+		} else {
+			reg->mmio_offset = 0;
+		}
+	} else {
+		/* No port, default to searching for MMIO. */
+		port = PORT_MMIO;
+		reg->mmio_offset = 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(port_descs); i++) {
+		if ((port != PORT_NONE && port_descs[i].port == port) ||
+		    (s && strcasecmp(s, port_descs[i].name) == 0)) {
+			reg->port_desc = port_descs[i];
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static const char *skip_space(const char *line)
+{
+	while (*line && isspace(*line))
+		line++;
+
+	return line;
+}
+
+static bool ignore_line(const char *line)
+{
+	line = skip_space(line);
+
+	switch (*line) {
+	case '\0':
+	case '#':
+	case ';':
+		return true;
+	case '/':
+		return *(line + 1) == '/';
+	}
+
+	return false;
+}
+
+static char *include_file(const char *line, const char *source)
+{
+	char *filename, *p;
+
+	line = skip_space(line);
+	if (*line == '(')
+		return NULL;
+
+	/* this'll be plenty */
+	filename = malloc(strlen(source) + strlen(line) + 1);
+	if (!filename)
+		return NULL;
+
+	p = strrchr(source, '/');
+	if (p && *line != '/') {
+		int len = p - source + 1;
+
+		memcpy(filename, source, len);
+		strcpy(filename + len, line);
+	} else {
+		strcpy(filename, line);
+	}
+
+	p = strchr(filename, '\n');
+	if (p)
+		*p = '\0';
+
+	return filename;
+}
+
+#define SPC	"[[:space:]]*"
+#define SEP	SPC "," SPC
+#define BEG	"^" SPC "\\(" SPC
+#define END	SPC "\\)" SPC "$"
+#define VALUE	"([[:print:]]*)"
+#define QVALUE	"'" VALUE "'"
+#define REGEXP	BEG QVALUE SEP QVALUE SEP QVALUE END
+
+static int parse_line(struct reg *reg, const char *line)
+{
+	static regex_t regex;
+	static bool initialized = false;
+	regmatch_t match[4];
+	int i, ret;
+
+	if (!initialized) {
+		if (regcomp (&regex, REGEXP, REG_EXTENDED)) {
+			fprintf(stderr, "regcomp %s\n", REGEXP);
+			return -1;
+		}
+		initialized = true;
+	}
+
+	memset(reg, 0, sizeof(*reg));
+
+	ret = regexec(&regex, line, ARRAY_SIZE(match), match, 0);
+	if (ret)
+		ret = -1;
+
+	for (i = 1; i < ARRAY_SIZE(match) && ret == 0; i++) {
+		char *p, *e;
+
+		p = strndup(line + match[i].rm_so,
+			    match[i].rm_eo - match[i].rm_so);
+
+		if (i == 1) {
+			reg->name = p;
+		} else if (i == 2) {
+			reg->addr = strtoul(p, &e, 16);
+			free(p);
+			if (*e)
+				ret = -1;
+		} else if (i == 3) {
+			ret = parse_port_desc(reg, p);
+			free(p);
+		}
+	}
+
+	if (ret)
+		free(reg->name);
+
+	return ret;
+}
+
+static ssize_t parse_file(struct reg **regs, size_t *nregs,
+			  ssize_t index, const char *filename)
+{
+	FILE *file;
+	char *line = NULL, *include;
+	size_t linesize = 0;
+	int lineno = 0, r;
+	ssize_t ret = -1;
+
+	file = fopen(filename, "r");
+	if (!file) {
+		fprintf(stderr, "Error: fopen '%s': %s\n",
+			filename, strerror(errno));
+		return -1;
+	}
+
+	while (getline(&line, &linesize, file) != -1) {
+		struct reg reg;
+
+		lineno++;
+
+		if (ignore_line(line))
+			continue;
+
+		include = include_file(line, filename);
+		if (include) {
+			index = parse_file(regs, nregs, index, include);
+			free(include);
+			if (index < 0) {
+				fprintf(stderr, "Error: %s:%d: %s",
+					filename, lineno, line);
+				goto out;
+			}
+			continue;
+		}
+
+		r = parse_line(&reg, line);
+		if (r < 0) {
+			fprintf(stderr, "Error: %s:%d: %s",
+				filename, lineno, line);
+			goto out;
+		} else if (r) {
+			continue;
+		}
+
+		if (!*regs || index >= *nregs) {
+			if (!*regs)
+				*nregs = 64;
+			else
+				*nregs *= 2;
+
+			*regs = recalloc(*regs, *nregs, sizeof(**regs));
+			if (!*regs) {
+				fprintf(stderr, "Error: %s\n", strerror(ENOMEM));
+				goto out;
+			}
+		}
+
+		(*regs)[index++] = reg;
+	}
+
+	ret = index;
+
+out:
+	free(line);
+	fclose(file);
+
+	return ret;
+}
+
+/*
+ * Get register definitions from file.
+ */
+ssize_t intel_reg_spec_file(struct reg **regs, const char *file)
+{
+	size_t nregs = 0;
+	*regs = NULL;
+
+	return parse_file(regs, &nregs, 0, file);
+}
+
+/*
+ * Free the memory allocated for register definitions.
+ */
+void intel_reg_spec_free(struct reg *regs, size_t n)
+{
+	size_t i;
+
+	for (i = 0; i < n; i++) {
+		free(regs[i].name);
+	}
+	free(regs);
+}
diff --git a/tools/intel_reg_spec.h b/tools/intel_reg_spec.h
new file mode 100644
index 000000000000..26e82523e1f7
--- /dev/null
+++ b/tools/intel_reg_spec.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __INTEL_REG_SPEC_H__
+#define __INTEL_REG_SPEC_H__
+
+enum port_addr {
+	PORT_NONE = 0,
+	PORT_MMIO = -1,
+	PORT_PORTIO_VGA = -2,	/* see vga reg read/write */
+	PORT_MMIO_VGA = -3,	/* see vga reg read/write */
+
+	/* vlv */
+	PORT_BUNIT = 0x03,
+	PORT_PUNIT = 0x04,
+	PORT_NC = 0x11,
+	PORT_DPIO = 0x12,
+	PORT_GPIO_NC = 0x13,
+	PORT_CCK = 0x14,
+	PORT_CCU = 0xa9,
+	PORT_DPIO2 = 0x1a,
+	PORT_FLISDSI = 0x1b,
+
+	/* threshold for interpreting port as mmio offset */
+	PORT_MAX = 0xff,
+};
+
+struct port_desc {
+	enum port_addr port;
+	const char *name;
+	uint32_t stride;
+};
+
+struct reg {
+	struct port_desc port_desc;
+	uint32_t mmio_offset;
+	uint32_t addr;
+	char *name;
+};
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+static inline void *recalloc(void *ptr, size_t nmemb, size_t size)
+{
+	return realloc(ptr, nmemb * size);
+}
+
+int parse_port_desc(struct reg *reg, const char *s);
+ssize_t intel_reg_spec_builtin(struct reg **regs, uint32_t devid);
+ssize_t intel_reg_spec_file(struct reg **regs, const char *filename);
+void intel_reg_spec_free(struct reg *regs, size_t n);
+int intel_reg_spec_decode(char *buf, size_t bufsize, const struct reg *reg,
+			  uint32_t val, uint32_t devid);
+
+#endif /* __INTEL_REG_SPEC_H__ */
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] man: add man page for intel_reg in rst format
  2015-04-15 10:15 [PATCH 0/2] intel_reg: Intel graphics register multitool Jani Nikula
  2015-04-15 10:15 ` [PATCH 1/2] intel_reg: introduce one intel_reg tool to rule them all Jani Nikula
@ 2015-04-15 10:15 ` Jani Nikula
  2015-04-16 16:10   ` Thomas Wood
  2015-04-15 10:23 ` [PATCH 0/2] intel_reg: Intel graphics register multitool Jani Nikula
  2 siblings, 1 reply; 5+ messages in thread
From: Jani Nikula @ 2015-04-15 10:15 UTC (permalink / raw)
  To: intel-gfx; +Cc: jani.nikula, Thomas Wood

Produce the man page from rst using rst2man.

FIXME: configure support for checking rst2man.

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
 man/Makefile.am   |  12 ++-
 man/intel_reg.rst | 229 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 240 insertions(+), 1 deletion(-)
 create mode 100644 man/intel_reg.rst

diff --git a/man/Makefile.am b/man/Makefile.am
index dcd79528f17b..548e966ba77a 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -19,7 +19,12 @@ appman_PRE = 				\
 	intel_upload_blit_large_map.man \
 	intel_upload_blit_small.man
 
-appman_DATA = $(appman_PRE:man=$(APP_MAN_SUFFIX))
+appman_RST =				\
+	intel_reg.rst
+
+appman_DATA =					\
+	$(appman_PRE:man=$(APP_MAN_SUFFIX))	\
+	$(appman_RST:rst=$(APP_MAN_SUFFIX))
 
 EXTRA_DIST = $(appman_PRE)
 CLEANFILES = $(appman_DATA)
@@ -29,3 +34,8 @@ SUFFIXES = .$(APP_MAN_SUFFIX) .man
 
 .man.$(APP_MAN_SUFFIX):
 	$(AM_V_GEN)$(SED) $(MAN_SUBSTS) < $< > $@
+
+# FIXME: check for rst2man in configure.ac
+# FIXME: handle MAN_SUBST in rst
+.rst.$(APP_MAN_SUFFIX):
+	$(AM_V_GEN)rst2man < $< > $@
diff --git a/man/intel_reg.rst b/man/intel_reg.rst
new file mode 100644
index 000000000000..c6e2feadeab2
--- /dev/null
+++ b/man/intel_reg.rst
@@ -0,0 +1,229 @@
+=========
+intel_reg
+=========
+
+---------------------------------
+Intel graphics register multitool
+---------------------------------
+
+:Author: Jani Nikula <jani.nikula@intel.com>
+:Date: 2015-04-14
+:Version: intel-gpu-tools
+:Copyright: 2015 Intel Corporation
+:Manual section: 1
+:Manual group: General Commands Manual
+
+SYNOPSIS
+========
+
+**intel_reg** [*option* ...] *command*
+
+DESCRIPTION
+===========
+
+Intel graphics register multitool. Read, write, dump, and decode Intel graphics
+MMIO and sideband registers, and more.
+
+OPTIONS
+=======
+
+Some options are global, and some specific to commands.
+
+--verbose
+---------
+
+Increase verbosity.
+
+--quiet
+-------
+
+Decrease verbosity.
+
+--count=N
+---------
+
+Read N registers.
+
+--binary
+--------
+
+Output binary values.
+
+--all
+-----
+
+Decode registers for all known platforms.
+
+--mmio=FILE
+-----------
+
+Use MMIO bar from FILE.
+
+--devid=DEVID
+-------------
+
+Pretend to be PCI ID DEVID. Useful with MMIO bar snapshots from other machines.
+
+--spec=PATH
+-----------
+
+Read register spec from directory or file specified by PATH; see REGISTER SPEC
+DEFINITIONS below for details.
+
+--help
+------
+
+Show brief help.
+
+COMMANDS
+========
+
+See REGISTER REFERENCES below on how to describe registers for the commands.
+
+read [--count=N] REGISTER [...]
+-------------------------------
+
+Dump each specified REGISTER, or N registers starting from each REGISTER.
+
+write REGISTER VALUE [REGISTER VALUE ...]
+-----------------------------------------
+
+Write each VALUE to corresponding REGISTER.
+
+dump [--mmio=FILE --devid=DEVID]
+--------------------------------
+
+Dump all registers specified in the register spec.
+
+decode REGISTER VALUE
+---------------------
+
+Decode REGISTER VALUE.
+
+snapshot
+--------
+
+Output the MMIO bar to stdout. The output can be used for a later invocation of
+dump or read with the --mmio=FILE and --devid=DEVID parameters.
+
+list
+----
+
+List the known registers.
+
+help
+----
+
+Display brief help.
+
+
+REGISTER REFERENCES
+===================
+
+Registers are defined as [(PORTNAME|PORTNUM|MMIO-OFFSET):](REGNAME|REGADDR).
+
+PORTNAME
+--------
+
+The register access method, most often MMIO, which is the default. The methods
+supported on all platforms are "mmio", "portio-vga", and "mmio-vga".
+
+On BYT and CHV, the sideband ports "bunit", "punit", "nc", "dpio", "gpio-nc",
+"cck", "ccu", "dpio2", and "flisdsi" are also supported.
+
+PORTNUM
+-------
+
+Port number for the sideband ports supported on BYT and CHV. Only numbers mapped
+to the supported ports are allowed, arbitrary numbers are not accepted.
+
+Numbers above 0xff are automatically interpreted as MMIO offsets, not port
+numbers.
+
+MMIO-OFFSET
+-----------
+
+Use MMIO, and add this offset to the register address.
+
+Numbers equal to or below 0xff are automatically interpreted as port numbers,
+not MMIO offsets.
+
+REGNAME
+-------
+
+Name of the register as defined in the register spec.
+
+If MMIO offset is not specified, it is picked up from the register
+spec. However, ports are not; the port is a namespace for the register names.
+
+REGADDR
+-------
+
+Register address. The corresponding register name need not be specified in the
+register spec.
+
+ENVIRONMENT
+===========
+
+INTEL_REG_SPEC
+--------------
+
+Path to a directory or a file containing register spec definitions.
+
+REGISTER SPEC DEFINITIONS
+=========================
+
+A register spec associates register names with addresses. The spec is searched
+for in this order:
+
+#. Directory or file specified by the --spec option.
+
+#. Directory or file specified by the INTEL_REG_SPEC environment variable.
+
+#. Builtin register spec. Also used as fallback with a warning if the above are
+   used but fail.
+
+If a directory is specified using --spec option or INTEL_REG_SPEC environment
+variable, the directory is scanned for a spec file in this order:
+
+#. File named after the PCI device id. For example, "0412".
+
+#. File named after the code name in lowercase, without punctuation. For
+   example, "valleyview".
+
+#. File named after generation. For example, "gen7" (note that this matches
+   valleyview, ivybridge and haswell!).
+
+Register Spec File Format
+-------------------------
+
+The register spec format is compatible with the quick_dump.py format, briefly
+described below:
+
+* Empty lines and lines beginning with "#", ";", or "//" are ignored.
+
+* Lines *not* beginning with "(" are interpreted as file names, absolute or
+  relative, to be included.
+
+* Lines beginning with "(" are interpreted as register definitions.
+
+Registers are defined as tuples ('REGNAME', 'REGADDR',
+'PORTNAME|PORTNUM|MMIO-OFFSET'), as in REGISTER REFERENCES above. The port
+description may also be an empty string to denote MMIO.
+
+Examples:
+
+* # this is a comment, below is an include
+
+* vlv_pipe_a.txt
+
+* ('GEN6_PMINTRMSK', '0x0000a168', '')
+
+* ('MIPIA_PORT_CTRL', '0x61190', '0x180000')
+
+* ('PLL1_DW0', '0x8000', 'DPIO')
+
+BUGS
+====
+
+Reading some registers may hang the GPU or the machine.
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] intel_reg: Intel graphics register multitool
  2015-04-15 10:15 [PATCH 0/2] intel_reg: Intel graphics register multitool Jani Nikula
  2015-04-15 10:15 ` [PATCH 1/2] intel_reg: introduce one intel_reg tool to rule them all Jani Nikula
  2015-04-15 10:15 ` [PATCH 2/2] man: add man page for intel_reg in rst format Jani Nikula
@ 2015-04-15 10:23 ` Jani Nikula
  2 siblings, 0 replies; 5+ messages in thread
From: Jani Nikula @ 2015-04-15 10:23 UTC (permalink / raw)
  To: intel-gfx; +Cc: Thomas Wood

On Wed, 15 Apr 2015, Jani Nikula <jani.nikula@intel.com> wrote:
> Hi all, this is v1 after the RFC [1], with polish applied and too many
> small changes to list. Go ahead and play with it!

Thomas, sorry for missing i-g-t in the subject; apparently git
send-email won't add it regardless of the --subject-prefix if the
patches were already produced with git format-patch.

BR,
Jani.


-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] man: add man page for intel_reg in rst format
  2015-04-15 10:15 ` [PATCH 2/2] man: add man page for intel_reg in rst format Jani Nikula
@ 2015-04-16 16:10   ` Thomas Wood
  0 siblings, 0 replies; 5+ messages in thread
From: Thomas Wood @ 2015-04-16 16:10 UTC (permalink / raw)
  To: Jani Nikula; +Cc: Intel Graphics Development

On 15 April 2015 at 11:15, Jani Nikula <jani.nikula@intel.com> wrote:
> Produce the man page from rst using rst2man.
>
> FIXME: configure support for checking rst2man.

I think this can be done with a fairly straightforward AC_CHECK_PROG
and AM_CONDITIONAL in configure.ac:

AC_CHECK_PROG(RST2MAN, rst2man, yes, no)
AM_CONDITIONAL(HAVE_RST2MAN, [test "x$RST2MAN" = xyes])

and then surround the relevant parts in Makefile.am with: if
HAVE_RST2MAN … endif.


>
> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
> ---
>  man/Makefile.am   |  12 ++-
>  man/intel_reg.rst | 229 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 240 insertions(+), 1 deletion(-)
>  create mode 100644 man/intel_reg.rst
>
> diff --git a/man/Makefile.am b/man/Makefile.am
> index dcd79528f17b..548e966ba77a 100644
> --- a/man/Makefile.am
> +++ b/man/Makefile.am
> @@ -19,7 +19,12 @@ appman_PRE =                                 \
>         intel_upload_blit_large_map.man \
>         intel_upload_blit_small.man
>
> -appman_DATA = $(appman_PRE:man=$(APP_MAN_SUFFIX))
> +appman_RST =                           \
> +       intel_reg.rst
> +
> +appman_DATA =                                  \
> +       $(appman_PRE:man=$(APP_MAN_SUFFIX))     \
> +       $(appman_RST:rst=$(APP_MAN_SUFFIX))
>
>  EXTRA_DIST = $(appman_PRE)
>  CLEANFILES = $(appman_DATA)
> @@ -29,3 +34,8 @@ SUFFIXES = .$(APP_MAN_SUFFIX) .man
>
>  .man.$(APP_MAN_SUFFIX):
>         $(AM_V_GEN)$(SED) $(MAN_SUBSTS) < $< > $@
> +
> +# FIXME: check for rst2man in configure.ac
> +# FIXME: handle MAN_SUBST in rst
> +.rst.$(APP_MAN_SUFFIX):
> +       $(AM_V_GEN)rst2man < $< > $@
> diff --git a/man/intel_reg.rst b/man/intel_reg.rst
> new file mode 100644
> index 000000000000..c6e2feadeab2
> --- /dev/null
> +++ b/man/intel_reg.rst
> @@ -0,0 +1,229 @@
> +=========
> +intel_reg
> +=========
> +
> +---------------------------------
> +Intel graphics register multitool
> +---------------------------------
> +
> +:Author: Jani Nikula <jani.nikula@intel.com>
> +:Date: 2015-04-14
> +:Version: intel-gpu-tools
> +:Copyright: 2015 Intel Corporation
> +:Manual section: 1
> +:Manual group: General Commands Manual
> +
> +SYNOPSIS
> +========
> +
> +**intel_reg** [*option* ...] *command*
> +
> +DESCRIPTION
> +===========
> +
> +Intel graphics register multitool. Read, write, dump, and decode Intel graphics
> +MMIO and sideband registers, and more.
> +
> +OPTIONS
> +=======
> +
> +Some options are global, and some specific to commands.
> +
> +--verbose
> +---------
> +
> +Increase verbosity.
> +
> +--quiet
> +-------
> +
> +Decrease verbosity.
> +
> +--count=N
> +---------
> +
> +Read N registers.
> +
> +--binary
> +--------
> +
> +Output binary values.
> +
> +--all
> +-----
> +
> +Decode registers for all known platforms.
> +
> +--mmio=FILE
> +-----------
> +
> +Use MMIO bar from FILE.
> +
> +--devid=DEVID
> +-------------
> +
> +Pretend to be PCI ID DEVID. Useful with MMIO bar snapshots from other machines.
> +
> +--spec=PATH
> +-----------
> +
> +Read register spec from directory or file specified by PATH; see REGISTER SPEC
> +DEFINITIONS below for details.
> +
> +--help
> +------
> +
> +Show brief help.
> +
> +COMMANDS
> +========
> +
> +See REGISTER REFERENCES below on how to describe registers for the commands.
> +
> +read [--count=N] REGISTER [...]
> +-------------------------------
> +
> +Dump each specified REGISTER, or N registers starting from each REGISTER.
> +
> +write REGISTER VALUE [REGISTER VALUE ...]
> +-----------------------------------------
> +
> +Write each VALUE to corresponding REGISTER.
> +
> +dump [--mmio=FILE --devid=DEVID]
> +--------------------------------
> +
> +Dump all registers specified in the register spec.
> +
> +decode REGISTER VALUE
> +---------------------
> +
> +Decode REGISTER VALUE.
> +
> +snapshot
> +--------
> +
> +Output the MMIO bar to stdout. The output can be used for a later invocation of
> +dump or read with the --mmio=FILE and --devid=DEVID parameters.
> +
> +list
> +----
> +
> +List the known registers.
> +
> +help
> +----
> +
> +Display brief help.
> +
> +
> +REGISTER REFERENCES
> +===================
> +
> +Registers are defined as [(PORTNAME|PORTNUM|MMIO-OFFSET):](REGNAME|REGADDR).
> +
> +PORTNAME
> +--------
> +
> +The register access method, most often MMIO, which is the default. The methods
> +supported on all platforms are "mmio", "portio-vga", and "mmio-vga".
> +
> +On BYT and CHV, the sideband ports "bunit", "punit", "nc", "dpio", "gpio-nc",
> +"cck", "ccu", "dpio2", and "flisdsi" are also supported.
> +
> +PORTNUM
> +-------
> +
> +Port number for the sideband ports supported on BYT and CHV. Only numbers mapped
> +to the supported ports are allowed, arbitrary numbers are not accepted.
> +
> +Numbers above 0xff are automatically interpreted as MMIO offsets, not port
> +numbers.
> +
> +MMIO-OFFSET
> +-----------
> +
> +Use MMIO, and add this offset to the register address.
> +
> +Numbers equal to or below 0xff are automatically interpreted as port numbers,
> +not MMIO offsets.
> +
> +REGNAME
> +-------
> +
> +Name of the register as defined in the register spec.
> +
> +If MMIO offset is not specified, it is picked up from the register
> +spec. However, ports are not; the port is a namespace for the register names.
> +
> +REGADDR
> +-------
> +
> +Register address. The corresponding register name need not be specified in the
> +register spec.
> +
> +ENVIRONMENT
> +===========
> +
> +INTEL_REG_SPEC
> +--------------
> +
> +Path to a directory or a file containing register spec definitions.
> +
> +REGISTER SPEC DEFINITIONS
> +=========================
> +
> +A register spec associates register names with addresses. The spec is searched
> +for in this order:
> +
> +#. Directory or file specified by the --spec option.
> +
> +#. Directory or file specified by the INTEL_REG_SPEC environment variable.
> +
> +#. Builtin register spec. Also used as fallback with a warning if the above are
> +   used but fail.
> +
> +If a directory is specified using --spec option or INTEL_REG_SPEC environment
> +variable, the directory is scanned for a spec file in this order:
> +
> +#. File named after the PCI device id. For example, "0412".
> +
> +#. File named after the code name in lowercase, without punctuation. For
> +   example, "valleyview".
> +
> +#. File named after generation. For example, "gen7" (note that this matches
> +   valleyview, ivybridge and haswell!).
> +
> +Register Spec File Format
> +-------------------------
> +
> +The register spec format is compatible with the quick_dump.py format, briefly
> +described below:
> +
> +* Empty lines and lines beginning with "#", ";", or "//" are ignored.
> +
> +* Lines *not* beginning with "(" are interpreted as file names, absolute or
> +  relative, to be included.
> +
> +* Lines beginning with "(" are interpreted as register definitions.
> +
> +Registers are defined as tuples ('REGNAME', 'REGADDR',
> +'PORTNAME|PORTNUM|MMIO-OFFSET'), as in REGISTER REFERENCES above. The port
> +description may also be an empty string to denote MMIO.
> +
> +Examples:
> +
> +* # this is a comment, below is an include
> +
> +* vlv_pipe_a.txt
> +
> +* ('GEN6_PMINTRMSK', '0x0000a168', '')
> +
> +* ('MIPIA_PORT_CTRL', '0x61190', '0x180000')
> +
> +* ('PLL1_DW0', '0x8000', 'DPIO')
> +
> +BUGS
> +====
> +
> +Reading some registers may hang the GPU or the machine.
> --
> 2.1.4
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-04-16 16:11 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-15 10:15 [PATCH 0/2] intel_reg: Intel graphics register multitool Jani Nikula
2015-04-15 10:15 ` [PATCH 1/2] intel_reg: introduce one intel_reg tool to rule them all Jani Nikula
2015-04-15 10:15 ` [PATCH 2/2] man: add man page for intel_reg in rst format Jani Nikula
2015-04-16 16:10   ` Thomas Wood
2015-04-15 10:23 ` [PATCH 0/2] intel_reg: Intel graphics register multitool Jani Nikula

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.