diff options
-rw-r--r-- | tools/Makefile.sources | 6 | ||||
-rw-r--r-- | tools/intel_reg.c | 899 | ||||
-rw-r--r-- | tools/intel_reg_decode.c | 2713 | ||||
-rw-r--r-- | tools/intel_reg_spec.c | 345 | ||||
-rw-r--r-- | tools/intel_reg_spec.h | 77 |
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, ®, argv[i])) + continue; + + for (j = 0; j < config->count; j++) { + dump_register(config, ®); + /* Update addr and name. */ + set_reg_by_addr(config, ®, + 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, ®, 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, ®, 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, ®, 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, ®, 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 = ®s[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(®, 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 (®ex, REGEXP, REG_EXTENDED)) { + fprintf(stderr, "regcomp %s\n", REGEXP); + return -1; + } + initialized = true; + } + + memset(reg, 0, sizeof(*reg)); + + ret = regexec(®ex, 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(®, 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__ */ |