summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/Makefile.sources6
-rw-r--r--tools/intel_reg.c899
-rw-r--r--tools/intel_reg_decode.c2713
-rw-r--r--tools/intel_reg_spec.c345
-rw-r--r--tools/intel_reg_spec.h77
5 files changed, 4040 insertions, 0 deletions
diff --git a/tools/Makefile.sources b/tools/Makefile.sources
index 6ca1228b..2477eb9b 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 00000000..975529d4
--- /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 00000000..4f97d993
--- /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 00000000..6b7e30c1
--- /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 00000000..26e82523
--- /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__ */