diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/.gitignore | 24 | ||||
-rw-r--r-- | tools/Makefile.am | 42 | ||||
-rw-r--r-- | tools/intel_audio_dump.c | 1969 | ||||
-rw-r--r-- | tools/intel_backlight.c | 69 | ||||
-rw-r--r-- | tools/intel_bios.h | 731 | ||||
-rw-r--r-- | tools/intel_bios_dumper.c | 112 | ||||
-rw-r--r-- | tools/intel_bios_reader.c | 947 | ||||
-rw-r--r-- | tools/intel_disable_clock_gating.c | 71 | ||||
-rw-r--r-- | tools/intel_dpio_read.c | 68 | ||||
-rw-r--r-- | tools/intel_dpio_write.c | 67 | ||||
-rw-r--r-- | tools/intel_dump_decode.c | 211 | ||||
-rw-r--r-- | tools/intel_error_decode.c | 515 | ||||
-rw-r--r-- | tools/intel_forcewaked.c | 106 | ||||
-rwxr-xr-x | tools/intel_gpu_abrt | 45 | ||||
-rw-r--r-- | tools/intel_gpu_time.c | 110 | ||||
-rw-r--r-- | tools/intel_gpu_top.c | 716 | ||||
-rw-r--r-- | tools/intel_gtt.c | 134 | ||||
-rw-r--r-- | tools/intel_infoframes.c | 1142 | ||||
-rw-r--r-- | tools/intel_l3_parity.c | 159 | ||||
-rw-r--r-- | tools/intel_lid.c | 144 | ||||
-rw-r--r-- | tools/intel_panel_fitter.c | 344 | ||||
-rw-r--r-- | tools/intel_reg_checker.c | 399 | ||||
-rw-r--r-- | tools/intel_reg_dumper.c | 2246 | ||||
-rw-r--r-- | tools/intel_reg_read.c | 142 | ||||
-rw-r--r-- | tools/intel_reg_snapshot.c | 48 | ||||
-rw-r--r-- | tools/intel_reg_write.c | 58 | ||||
-rw-r--r-- | tools/intel_stepping.c | 294 |
27 files changed, 10913 insertions, 0 deletions
diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 00000000..c15e3c36 --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,24 @@ +forcewaked +intel_audio_dump +intel_backlight +intel_bios_dumper +intel_bios_reader +intel_disable_clock_gating +intel_dump_decode +intel_error_decode +intel_forcewaked +intel_gpu_dump +intel_gpu_time +intel_gpu_top +intel_gtt +intel_infoframes +intel_l3_parity +intel_lid +intel_panel_fitter +intel_reg_checker +intel_reg_dumper +intel_reg_read +intel_reg_snapshot +intel_reg_write +intel_stepping +# Please keep sorted alphabetically diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 00000000..71fb087f --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,42 @@ +bin_PROGRAMS = \ + intel_disable_clock_gating \ + intel_audio_dump \ + intel_backlight \ + intel_bios_dumper \ + intel_bios_reader \ + intel_error_decode \ + intel_gpu_top \ + intel_gpu_time \ + intel_gtt \ + intel_stepping \ + intel_reg_checker \ + intel_reg_dumper \ + intel_reg_snapshot \ + intel_reg_write \ + intel_reg_read \ + intel_forcewaked \ + intel_dpio_read \ + intel_dpio_write \ + intel_l3_parity + +noinst_PROGRAMS = \ + intel_dump_decode \ + intel_infoframes \ + intel_lid \ + intel_panel_fitter + +dist_bin_SCRIPTS = intel_gpu_abrt + +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib +AM_CFLAGS = $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS) +LDADD = $(top_builddir)/lib/libintel_tools.la $(DRM_LIBS) $(PCIACCESS_LIBS) $(CAIRO_LIBS) + +intel_dump_decode_SOURCES = \ + intel_dump_decode.c + +intel_error_decode_SOURCES = \ + intel_error_decode.c + +intel_bios_reader_SOURCES = \ + intel_bios_reader.c \ + intel_bios.h diff --git a/tools/intel_audio_dump.c b/tools/intel_audio_dump.c new file mode 100644 index 00000000..8b9da303 --- /dev/null +++ b/tools/intel_audio_dump.c @@ -0,0 +1,1969 @@ +/* + * Copyright © 2009 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: + * Zhenyu Wang <zhenyu.z.wang@intel.com> + * Wu Fengguang <fengguang.wu@intel.com> + * + */ + +#define _GNU_SOURCE +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <arpa/inet.h> +#include "intel_gpu_tools.h" + +static uint32_t devid; + + +#define BITSTO(n) (n >= sizeof(long) * 8 ? ~0 : (1UL << (n)) - 1) +#define BITMASK(high, low) (BITSTO(high+1) & ~BITSTO(low)) +#define BITS(reg, high, low) (((reg) & (BITMASK(high, low))) >> (low)) +#define BIT(reg, n) BITS(reg, n, n) + +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1: __min2; }) + +#define OPNAME(names, index) \ + names[min_t(unsigned int, index, ARRAY_SIZE(names) - 1)] + +#define dump_reg(reg, desc) \ + do { \ + dword = INREG(reg); \ + printf("%-21s 0x%08x %s\n", # reg, dword, desc); \ + } while (0) + + +static const char *pixel_clock[] = { + [0] = "25.2 / 1.001 MHz", + [1] = "25.2 MHz", + [2] = "27 MHz", + [3] = "27 * 1.001 MHz", + [4] = "54 MHz", + [5] = "54 * 1.001 MHz", + [6] = "74.25 / 1.001 MHz", + [7] = "74.25 MHz", + [8] = "148.5 / 1.001 MHz", + [9] = "148.5 MHz", + [10] = "Reserved", +}; + +static const char *power_state[] = { + [0] = "D0", + [1] = "D1", + [2] = "D2", + [3] = "D3", +}; + +static const char *stream_type[] = { + [0] = "default samples", + [1] = "one bit stream", + [2] = "DST stream", + [3] = "MLP stream", + [4] = "Reserved", +}; + +static const char *dip_port[] = { + [0] = "Reserved", + [1] = "Digital Port B", + [2] = "Digital Port C", + [3] = "Digital Port D", +}; + +static const char *dip_type[] = { + [0] = "Audio DIP Disabled", + [1] = "Audio DIP Enabled", +}; + +static const char *dip_index[] = { + [0] = "Audio DIP", + [1] = "ACP DIP", + [2] = "ISRC1 DIP", + [3] = "ISRC2 DIP", + [4] = "Reserved", +}; + +static const char *dip_trans[] = { + [0] = "disabled", + [1] = "reserved", + [2] = "send once", + [3] = "best effort", +}; + +static const char *video_dip_index[] = { + [0] = "AVI DIP", + [1] = "Vendor-specific DIP", + [2] = "Gamut Metadata DIP", + [3] = "Source Product Description DIP", +}; + +static const char *video_dip_trans[] = { + [0] = "send once", + [1] = "send every vsync", + [2] = "send at least every other vsync", + [3] = "reserved", +}; + +static const char *trans_to_port_sel[] = { + [0] = "no port", + [1] = "Digital Port B", + [2] = "Digital Port C", + [3] = "Digital Port D", + [4] = "reserved", + [5] = "reserved", + [6] = "reserved", + [7] = "reserved", +}; + +static const char *ddi_mode[] = { + [0] = "HDMI mode", + [1] = "DVI mode", + [2] = "DP SST mode", + [3] = "DP MST mode", + [4] = "DP FDI mode", + [5] = "reserved", + [6] = "reserved", + [7] = "reserved", +}; + +static const char *transcoder_select[] = { + [0] = "Transcoder A", + [1] = "Transcoder B", + [2] = "Transcoder C", + [3] = "reserved", +}; + +static const char *dp_port_width[] = { + [0] = "x1 mode", + [1] = "x2 mode", + [2] = "reserved", + [3] = "x4 mode", + [4] = "reserved", + [5] = "reserved", + [6] = "reserved", + [7] = "reserved", +}; + +static const char *bits_per_sample[] = { + [0] = "reserved", + [1] = "16 bits", + [2] = "24 bits", + [3] = "32 bits", + [4] = "20 bits", + [5] = "reserved", +}; + +static const char *sdvo_hdmi_encoding[] = { + [0] = "SDVO", + [1] = "reserved", + [2] = "TMDS", + [3] = "reserved", +}; + +static const char *n_index_value[] = { + [0] = "HDMI", + [1] = "DisplayPort", +}; + +static void do_self_tests(void) +{ + if (BIT(1, 0) != 1) + exit(1); + if (BIT(0x80000000, 31) != 1) + exit(2); + if (BITS(0xc0000000, 31, 30) != 3) + exit(3); +} + +/* + * EagleLake registers + */ +#define AUD_CONFIG 0x62000 +#define AUD_DEBUG 0x62010 +#define AUD_VID_DID 0x62020 +#define AUD_RID 0x62024 +#define AUD_SUBN_CNT 0x62028 +#define AUD_FUNC_GRP 0x62040 +#define AUD_SUBN_CNT2 0x62044 +#define AUD_GRP_CAP 0x62048 +#define AUD_PWRST 0x6204c +#define AUD_SUPPWR 0x62050 +#define AUD_SID 0x62054 +#define AUD_OUT_CWCAP 0x62070 +#define AUD_OUT_PCMSIZE 0x62074 +#define AUD_OUT_STR 0x62078 +#define AUD_OUT_DIG_CNVT 0x6207c +#define AUD_OUT_CH_STR 0x62080 +#define AUD_OUT_STR_DESC 0x62084 +#define AUD_PINW_CAP 0x620a0 +#define AUD_PIN_CAP 0x620a4 +#define AUD_PINW_CONNLNG 0x620a8 +#define AUD_PINW_CONNLST 0x620ac +#define AUD_PINW_CNTR 0x620b0 +#define AUD_PINW_UNSOLRESP 0x620b8 +#define AUD_CNTL_ST 0x620b4 +#define AUD_PINW_CONFIG 0x620bc +#define AUD_HDMIW_STATUS 0x620d4 +#define AUD_HDMIW_HDMIEDID 0x6210c +#define AUD_HDMIW_INFOFR 0x62118 +#define AUD_CONV_CHCNT 0x62120 +#define AUD_CTS_ENABLE 0x62128 + +#define VIDEO_DIP_CTL 0x61170 +#define VIDEO_DIP_ENABLE (1<<31) +#define VIDEO_DIP_ENABLE_AVI (1<<21) +#define VIDEO_DIP_ENABLE_VENDOR (1<<22) +#define VIDEO_DIP_ENABLE_SPD (1<<24) +#define VIDEO_DIP_BUF_AVI (0<<19) +#define VIDEO_DIP_BUF_VENDOR (1<<19) +#define VIDEO_DIP_BUF_SPD (3<<19) +#define VIDEO_DIP_TRANS_ONCE (0<<16) +#define VIDEO_DIP_TRANS_1 (1<<16) +#define VIDEO_DIP_TRANS_2 (2<<16) + +#define AUDIO_HOTPLUG_EN (1<<24) + + +static void dump_eaglelake(void) +{ + uint32_t dword; + int i; + + /* printf("%-18s %8s %s\n\n", "register name", "raw value", "description"); */ + + dump_reg(VIDEO_DIP_CTL, "Video DIP Control"); + dump_reg(SDVOB, "Digital Display Port B Control Register"); + dump_reg(SDVOC, "Digital Display Port C Control Register"); + dump_reg(PORT_HOTPLUG_EN, "Hot Plug Detect Enable"); + + dump_reg(AUD_CONFIG, "Audio Configuration"); + dump_reg(AUD_DEBUG, "Audio Debug"); + dump_reg(AUD_VID_DID, "Audio Vendor ID / Device ID"); + dump_reg(AUD_RID, "Audio Revision ID"); + dump_reg(AUD_SUBN_CNT, "Audio Subordinate Node Count"); + dump_reg(AUD_FUNC_GRP, "Audio Function Group Type"); + dump_reg(AUD_SUBN_CNT2, "Audio Subordinate Node Count"); + dump_reg(AUD_GRP_CAP, "Audio Function Group Capabilities"); + dump_reg(AUD_PWRST, "Audio Power State"); + dump_reg(AUD_SUPPWR, "Audio Supported Power States"); + dump_reg(AUD_SID, "Audio Root Node Subsystem ID"); + dump_reg(AUD_OUT_CWCAP, "Audio Output Converter Widget Capabilities"); + dump_reg(AUD_OUT_PCMSIZE, "Audio PCM Size and Rates"); + dump_reg(AUD_OUT_STR, "Audio Stream Formats"); + dump_reg(AUD_OUT_DIG_CNVT, "Audio Digital Converter"); + dump_reg(AUD_OUT_CH_STR, "Audio Channel ID and Stream ID"); + dump_reg(AUD_OUT_STR_DESC, "Audio Stream Descriptor Format"); + dump_reg(AUD_PINW_CAP, "Audio Pin Complex Widget Capabilities"); + dump_reg(AUD_PIN_CAP, "Audio Pin Capabilities"); + dump_reg(AUD_PINW_CONNLNG, "Audio Connection List Length"); + dump_reg(AUD_PINW_CONNLST, "Audio Connection List Entry"); + dump_reg(AUD_PINW_CNTR, "Audio Pin Widget Control"); + dump_reg(AUD_PINW_UNSOLRESP,"Audio Unsolicited Response Enable"); + dump_reg(AUD_CNTL_ST, "Audio Control State Register"); + dump_reg(AUD_PINW_CONFIG, "Audio Configuration Default"); + dump_reg(AUD_HDMIW_STATUS, "Audio HDMI Status"); + dump_reg(AUD_HDMIW_HDMIEDID,"Audio HDMI Data EDID Block"); + dump_reg(AUD_HDMIW_INFOFR, "Audio HDMI Widget Data Island Packet"); + dump_reg(AUD_CONV_CHCNT, "Audio Converter Channel Count"); + dump_reg(AUD_CTS_ENABLE, "Audio CTS Programming Enable"); + + printf("\nDetails:\n\n"); + + dword = INREG(AUD_VID_DID); + printf("AUD_VID_DID vendor id\t\t\t0x%x\n", dword >> 16); + printf("AUD_VID_DID device id\t\t\t0x%x\n", dword & 0xffff); + + dword = INREG(AUD_RID); + printf("AUD_RID major revision\t\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_RID minor revision\t\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_RID revision id\t\t\t0x%lx\n", BITS(dword, 15, 8)); + printf("AUD_RID stepping id\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(SDVOB); + printf("SDVOB enable\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("SDVOB HDMI encoding\t\t\t%u\n", !!(dword & SDVO_ENCODING_HDMI)); + printf("SDVOB SDVO encoding\t\t\t%u\n", !!(dword & SDVO_ENCODING_SDVO)); + printf("SDVOB null packets\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("SDVOB audio enabled\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(SDVOC); + printf("SDVOC enable\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("SDVOC HDMI encoding\t\t\t%u\n", !!(dword & SDVO_ENCODING_HDMI)); + printf("SDVOC SDVO encoding\t\t\t%u\n", !!(dword & SDVO_ENCODING_SDVO)); + printf("SDVOC null packets\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("SDVOC audio enabled\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(PORT_HOTPLUG_EN); + printf("PORT_HOTPLUG_EN DisplayPort/HDMI port B\t%ld\n", BIT(dword, 29)), + printf("PORT_HOTPLUG_EN DisplayPort/HDMI port C\t%ld\n", BIT(dword, 28)), + printf("PORT_HOTPLUG_EN DisplayPort port D\t%ld\n", BIT(dword, 27)), + printf("PORT_HOTPLUG_EN SDVOB\t\t\t%ld\n", BIT(dword, 26)), + printf("PORT_HOTPLUG_EN SDVOC\t\t\t%ld\n", BIT(dword, 25)), + printf("PORT_HOTPLUG_EN audio\t\t\t%ld\n", BIT(dword, 24)), + printf("PORT_HOTPLUG_EN TV\t\t\t%ld\n", BIT(dword, 23)), + printf("PORT_HOTPLUG_EN CRT\t\t\t%ld\n", BIT(dword, 9)), + + dword = INREG(VIDEO_DIP_CTL); + printf("VIDEO_DIP_CTL enable graphics DIP\t%ld\n", BIT(dword, 31)), + printf("VIDEO_DIP_CTL port select\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("VIDEO_DIP_CTL DIP buffer trans active\t%lu\n", BIT(dword, 28)); + printf("VIDEO_DIP_CTL AVI DIP enabled\t\t%lu\n", BIT(dword, 21)); + printf("VIDEO_DIP_CTL vendor DIP enabled\t%lu\n", BIT(dword, 22)); + printf("VIDEO_DIP_CTL SPD DIP enabled\t\t%lu\n", BIT(dword, 24)); + printf("VIDEO_DIP_CTL DIP buffer index\t\t[0x%lx] %s\n", + BITS(dword, 20, 19), video_dip_index[BITS(dword, 20, 19)]); + printf("VIDEO_DIP_CTL DIP trans freq\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), video_dip_trans[BITS(dword, 17, 16)]); + printf("VIDEO_DIP_CTL DIP buffer size\t\t%lu\n", BITS(dword, 11, 8)); + printf("VIDEO_DIP_CTL DIP address\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(AUD_CONFIG); + printf("AUD_CONFIG pixel clock\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG fabrication enabled\t\t%lu\n", BITS(dword, 2, 2)); + printf("AUD_CONFIG professional use allowed\t%lu\n", BIT(dword, 1)); + printf("AUD_CONFIG fuse enabled\t\t\t%lu\n", BIT(dword, 0)); + + dword = INREG(AUD_DEBUG); + printf("AUD_DEBUG function reset\t\t%lu\n", BIT(dword, 0)); + + dword = INREG(AUD_SUBN_CNT); + printf("AUD_SUBN_CNT starting node number\t0x%lx\n", BITS(dword, 23, 16)); + printf("AUD_SUBN_CNT total number of nodes\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(AUD_SUBN_CNT2); + printf("AUD_SUBN_CNT2 starting node number\t0x%lx\n", BITS(dword, 24, 16)); + printf("AUD_SUBN_CNT2 total number of nodes\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(AUD_FUNC_GRP); + printf("AUD_FUNC_GRP unsol capable\t\t%lu\n", BIT(dword, 8)); + printf("AUD_FUNC_GRP node type\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(AUD_GRP_CAP); + printf("AUD_GRP_CAP beep 0\t\t\t%lu\n", BIT(dword, 16)); + printf("AUD_GRP_CAP input delay\t\t\t%lu\n", BITS(dword, 11, 8)); + printf("AUD_GRP_CAP output delay\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(AUD_PWRST); + printf("AUD_PWRST device power state\t\t%s\n", + power_state[BITS(dword, 5, 4)]); + printf("AUD_PWRST device power state setting\t%s\n", + power_state[BITS(dword, 1, 0)]); + + dword = INREG(AUD_SUPPWR); + printf("AUD_SUPPWR support D0\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_SUPPWR support D1\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_SUPPWR support D2\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_SUPPWR support D3\t\t\t%lu\n", BIT(dword, 3)); + + dword = INREG(AUD_OUT_CWCAP); + printf("AUD_OUT_CWCAP widget type\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_OUT_CWCAP sample delay\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_OUT_CWCAP channel count\t\t%lu\n", + BITS(dword, 15, 13) * 2 + BIT(dword, 0) + 1); + printf("AUD_OUT_CWCAP L-R swap\t\t\t%lu\n", BIT(dword, 11)); + printf("AUD_OUT_CWCAP power control\t\t%lu\n", BIT(dword, 10)); + printf("AUD_OUT_CWCAP digital\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_OUT_CWCAP conn list\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_OUT_CWCAP unsol\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_CWCAP mute\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_CWCAP format override\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_CWCAP amp param override\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_CWCAP out amp present\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_CWCAP in amp present\t\t%lu\n", BIT(dword, 1)); + + dword = INREG(AUD_OUT_DIG_CNVT); + printf("AUD_OUT_DIG_CNVT SPDIF category\t\t0x%lx\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT SPDIF level\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT professional\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT non PCM\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT copyright asserted\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT filter preemphasis\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT validity config\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT validity flag\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT digital enable\t\t%lu\n", BIT(dword, 0)); + + dword = INREG(AUD_OUT_CH_STR); + printf("AUD_OUT_CH_STR stream id\t\t0x%lx\n", BITS(dword, 7, 4)); + printf("AUD_OUT_CH_STR lowest channel\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC); + printf("AUD_OUT_STR_DESC stream channels\t%lu\n", BITS(dword, 3, 0) + 1); + printf("AUD_OUT_STR_DESC Bits per Sample\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + + dword = INREG(AUD_PINW_CAP); + printf("AUD_PINW_CAP widget type\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_PINW_CAP sample delay\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_PINW_CAP channel count\t\t%lu\n", + BITS(dword, 15, 13) * 2 + BIT(dword, 0) + 1); + printf("AUD_PINW_CAP HDCP\t\t\t%lu\n", BIT(dword, 12)); + printf("AUD_PINW_CAP L-R swap\t\t\t%lu\n", BIT(dword, 11)); + printf("AUD_PINW_CAP power control\t\t%lu\n", BIT(dword, 10)); + printf("AUD_PINW_CAP digital\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_PINW_CAP conn list\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_PINW_CAP unsol\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_PINW_CAP mute\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_PINW_CAP format override\t\t%lu\n", BIT(dword, 4)); + printf("AUD_PINW_CAP amp param override\t\t%lu\n", BIT(dword, 3)); + printf("AUD_PINW_CAP out amp present\t\t%lu\n", BIT(dword, 2)); + printf("AUD_PINW_CAP in amp present\t\t%lu\n", BIT(dword, 1)); + + + dword = INREG(AUD_PIN_CAP); + printf("AUD_PIN_CAP EAPD\t\t\t%lu\n", BIT(dword, 16)); + printf("AUD_PIN_CAP HDMI\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_PIN_CAP output\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_PIN_CAP presence detect\t\t%lu\n", BIT(dword, 2)); + + dword = INREG(AUD_PINW_CNTR); + printf("AUD_PINW_CNTR mute status\t\t%lu\n", BIT(dword, 8)); + printf("AUD_PINW_CNTR out enable\t\t%lu\n", BIT(dword, 6)); + printf("AUD_PINW_CNTR amp mute status\t\t%lu\n", BIT(dword, 8)); + printf("AUD_PINW_CNTR amp mute status\t\t%lu\n", BIT(dword, 8)); + printf("AUD_PINW_CNTR stream type\t\t[0x%lx] %s\n", + BITS(dword, 2, 0), + OPNAME(stream_type, BITS(dword, 2, 0))); + + dword = INREG(AUD_PINW_UNSOLRESP); + printf("AUD_PINW_UNSOLRESP enable unsol resp\t%lu\n", BIT(dword, 31)); + + dword = INREG(AUD_CNTL_ST); + printf("AUD_CNTL_ST DIP audio enabled\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST DIP ACP enabled\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST DIP ISRCx enabled\t\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST DIP port select\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST DIP buffer index\t\t[0x%lx] %s\n", + BITS(dword, 20, 18), OPNAME(dip_index, BITS(dword, 20, 18))); + printf("AUD_CNTL_ST DIP trans freq\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST DIP address\t\t\t%lu\n", BITS(dword, 3, 0)); + printf("AUD_CNTL_ST CP ready\t\t\t%lu\n", BIT(dword, 15)); + printf("AUD_CNTL_ST ELD valid\t\t\t%lu\n", BIT(dword, 14)); + printf("AUD_CNTL_ST ELD ack\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST ELD bufsize\t\t\t%lu\n", BITS(dword, 13, 9)); + printf("AUD_CNTL_ST ELD address\t\t\t%lu\n", BITS(dword, 8, 5)); + + dword = INREG(AUD_HDMIW_STATUS); + printf("AUD_HDMIW_STATUS CDCLK/DOTCLK underrun\t%lu\n", BIT(dword, 31)); + printf("AUD_HDMIW_STATUS CDCLK/DOTCLK overrun\t%lu\n", BIT(dword, 30)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK underrun\t%lu\n", BIT(dword, 29)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK overrun\t%lu\n", BIT(dword, 28)); + + dword = INREG(AUD_CONV_CHCNT); + printf("AUD_CONV_CHCNT HDMI HBR enabled\t\t%lu\n", BITS(dword, 15, 14)); + printf("AUD_CONV_CHCNT HDMI channel count\t%lu\n", BITS(dword, 11, 8) + 1); + + printf("AUD_CONV_CHCNT HDMI channel mapping:\n"); + for (i = 0; i < 8; i++) { + OUTREG(AUD_CONV_CHCNT, i); + dword = INREG(AUD_CONV_CHCNT); + printf("\t\t\t\t\t[0x%x] %u => %lu \n", dword, i, BITS(dword, 7, 4)); + } + + printf("AUD_HDMIW_HDMIEDID HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST); + dword &= ~BITMASK(8, 5); + OUTREG(AUD_CNTL_ST, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR))); + printf("\n"); +} + +#undef AUD_RID +#undef AUD_VID_DID +#undef AUD_PWRST +#undef AUD_OUT_CH_STR +#undef AUD_HDMIW_STATUS + +/* + * IronLake registers + */ +#define AUD_CONFIG_A 0xE2000 +#define AUD_CONFIG_B 0xE2100 +#define AUD_CTS_ENABLE_A 0xE2028 +#define AUD_CTS_ENABLE_B 0xE2128 +#define AUD_MISC_CTRL_A 0xE2010 +#define AUD_MISC_CTRL_B 0xE2110 +#define AUD_VID_DID 0xE2020 +#define AUD_RID 0xE2024 +#define AUD_PWRST 0xE204C +#define AUD_PORT_EN_HD_CFG 0xE207C +#define AUD_OUT_DIG_CNVT_A 0xE2080 +#define AUD_OUT_DIG_CNVT_B 0xE2180 +#define AUD_OUT_CH_STR 0xE2088 +#define AUD_OUT_STR_DESC_A 0xE2084 +#define AUD_OUT_STR_DESC_B 0xE2184 +#define AUD_PINW_CONNLNG_LIST 0xE20A8 +#define AUD_PINW_CONNLNG_SEL 0xE20AC +#define AUD_CNTL_ST_A 0xE20B4 +#define AUD_CNTL_ST_B 0xE21B4 +#define AUD_CNTL_ST2 0xE20C0 +#define AUD_HDMIW_STATUS 0xE20D4 +#define AUD_HDMIW_HDMIEDID_A 0xE2050 +#define AUD_HDMIW_HDMIEDID_B 0xE2150 +#define AUD_HDMIW_INFOFR_A 0xE2054 +#define AUD_HDMIW_INFOFR_B 0xE2154 + +static void dump_ironlake(void) +{ + uint32_t dword; + int i; + + dump_reg(HDMIB, "sDVO/HDMI Port B Control"); + dump_reg(HDMIC, "HDMI Port C Control"); + dump_reg(HDMID, "HDMI Port D Control"); + dump_reg(PCH_DP_B, "DisplayPort B Control Register"); + dump_reg(PCH_DP_C, "DisplayPort C Control Register"); + dump_reg(PCH_DP_D, "DisplayPort D Control Register"); + dump_reg(AUD_CONFIG_A, "Audio Configuration - Transcoder A"); + dump_reg(AUD_CONFIG_B, "Audio Configuration - Transcoder B"); + dump_reg(AUD_CTS_ENABLE_A, "Audio CTS Programming Enable - Transcoder A"); + dump_reg(AUD_CTS_ENABLE_B, "Audio CTS Programming Enable - Transcoder B"); + dump_reg(AUD_MISC_CTRL_A, "Audio MISC Control for Transcoder A"); + dump_reg(AUD_MISC_CTRL_B, "Audio MISC Control for Transcoder B"); + dump_reg(AUD_VID_DID, "Audio Vendor ID / Device ID"); + dump_reg(AUD_RID, "Audio Revision ID"); + dump_reg(AUD_PWRST, "Audio Power State (Function Group, Convertor, Pin Widget)"); + dump_reg(AUD_PORT_EN_HD_CFG, "Audio Port Enable HDAudio Config"); + dump_reg(AUD_OUT_DIG_CNVT_A, "Audio Digital Converter - Conv A"); + dump_reg(AUD_OUT_DIG_CNVT_B, "Audio Digital Converter - Conv B"); + dump_reg(AUD_OUT_CH_STR, "Audio Channel ID and Stream ID"); + dump_reg(AUD_OUT_STR_DESC_A, "Audio Stream Descriptor Format - Conv A"); + dump_reg(AUD_OUT_STR_DESC_B, "Audio Stream Descriptor Format - Conv B"); + dump_reg(AUD_PINW_CONNLNG_LIST, "Audio Connection List"); + dump_reg(AUD_PINW_CONNLNG_SEL, "Audio Connection Select"); + dump_reg(AUD_CNTL_ST_A, "Audio Control State Register - Transcoder A"); + dump_reg(AUD_CNTL_ST_B, "Audio Control State Register - Transcoder B"); + dump_reg(AUD_CNTL_ST2, "Audio Control State 2"); + dump_reg(AUD_HDMIW_STATUS, "Audio HDMI Status"); + dump_reg(AUD_HDMIW_HDMIEDID_A, "HDMI Data EDID Block - Transcoder A"); + dump_reg(AUD_HDMIW_HDMIEDID_B, "HDMI Data EDID Block - Transcoder B"); + dump_reg(AUD_HDMIW_INFOFR_A, "Audio Widget Data Island Packet - Transcoder A"); + dump_reg(AUD_HDMIW_INFOFR_B, "Audio Widget Data Island Packet - Transcoder B"); + + printf("\nDetails:\n\n"); + + dword = INREG(AUD_VID_DID); + printf("AUD_VID_DID vendor id\t\t\t\t\t0x%x\n", dword >> 16); + printf("AUD_VID_DID device id\t\t\t\t\t0x%x\n", dword & 0xffff); + + dword = INREG(AUD_RID); + printf("AUD_RID Major_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_RID Minor_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_RID Revision_Id\t\t\t\t\t0x%lx\n", BITS(dword, 15, 8)); + printf("AUD_RID Stepping_Id\t\t\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(HDMIB); + printf("HDMIB HDMIB_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMIB Transcoder_Select\t\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("HDMIB HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMIB SDVOB Hot Plug Interrupt Detect Enable\t\t%lu\n", BIT(dword, 23)); + printf("HDMIB Digital_Port_B_Detected\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMIB Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMIB Null_packets_enabled_during_Vsync\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("HDMIB Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(HDMIC); + printf("HDMIC HDMIC_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMIC Transcoder_Select\t\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("HDMIC HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMIC Digital_Port_C_Detected\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMIC Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMIC Null_packets_enabled_during_Vsync\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("HDMIC Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(HDMID); + printf("HDMID HDMID_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMID Transcoder_Select\t\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("HDMID HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMID Digital_Port_D_Detected\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMID Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMID Null_packets_enabled_during_Vsync\t\t\t%u\n", !!(dword & SDVO_NULL_PACKETS_DURING_VSYNC)); + printf("HDMID Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(PCH_DP_B); + printf("PCH_DP_B DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("PCH_DP_B Transcoder_Select\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("PCH_DP_B Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("PCH_DP_B Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("PCH_DP_B HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("PCH_DP_B Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(PCH_DP_C); + printf("PCH_DP_C DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("PCH_DP_C Transcoder_Select\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("PCH_DP_C Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("PCH_DP_C Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("PCH_DP_C HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("PCH_DP_C Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(PCH_DP_D); + printf("PCH_DP_D DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("PCH_DP_D Transcoder_Select\t\t\t\t%s\n", BIT(dword, 30) ? "Transcoder B" : "Transcoder A"); + printf("PCH_DP_D Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("PCH_DP_D Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("PCH_DP_D HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("PCH_DP_D Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(AUD_CONFIG_A); + printf("AUD_CONFIG_A N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_A N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_A Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_A Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_A Pixel_Clock\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_A Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_B); + printf("AUD_CONFIG_B N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_B N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_B Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_B Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_B Pixel_Clock\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_B Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + + dword = INREG(AUD_CTS_ENABLE_A); + printf("AUD_CTS_ENABLE_A Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_A CTS/M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_A CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_B); + printf("AUD_CTS_ENABLE_B Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_B CTS/M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_B CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + + dword = INREG(AUD_MISC_CTRL_A); + printf("AUD_MISC_CTRL_A Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_A Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_A Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_A Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_B); + printf("AUD_MISC_CTRL_B Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_B Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_B Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_B Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + + dword = INREG(AUD_PWRST); + printf("AUD_PWRST Function_Group_Device_Power_State_Current\t%s\n", power_state[BITS(dword, 23, 22)]); + printf("AUD_PWRST Function_Group_Device_Power_State_Set \t%s\n", power_state[BITS(dword, 21, 20)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 19, 18)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Requested \t%s\n", power_state[BITS(dword, 17, 16)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 15, 14)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Requsted \t%s\n", power_state[BITS(dword, 13, 12)]); + printf("AUD_PWRST PinD_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 11, 10)]); + printf("AUD_PWRST PinD_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 9, 8)]); + printf("AUD_PWRST PinC_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 7, 6)]); + printf("AUD_PWRST PinC_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 5, 4)]); + printf("AUD_PWRST PinB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 3, 2)]); + printf("AUD_PWRST PinB_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 1, 0)]); + + dword = INREG(AUD_PORT_EN_HD_CFG); + printf("AUD_PORT_EN_HD_CFG Convertor_A_Digen\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_PORT_EN_HD_CFG Convertor_B_Digen\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_PORT_EN_HD_CFG ConvertorA_Stream_ID\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_PORT_EN_HD_CFG ConvertorB_Stream_ID\t\t%lu\n", BITS(dword, 11, 8)); + printf("AUD_PORT_EN_HD_CFG Port_B_Out_Enable\t\t\t%lu\n", BIT(dword, 12)); + printf("AUD_PORT_EN_HD_CFG Port_C_Out_Enable\t\t\t%lu\n", BIT(dword, 13)); + printf("AUD_PORT_EN_HD_CFG Port_D_Out_Enable\t\t\t%lu\n", BIT(dword, 14)); + printf("AUD_PORT_EN_HD_CFG Port_B_Amp_Mute_Status\t\t%lu\n", BIT(dword, 16)); + printf("AUD_PORT_EN_HD_CFG Port_C_Amp_Mute_Status\t\t%lu\n", BIT(dword, 17)); + printf("AUD_PORT_EN_HD_CFG Port_D_Amp_Mute_Status\t\t%lu\n", BIT(dword, 18)); + + dword = INREG(AUD_OUT_DIG_CNVT_A); + printf("AUD_OUT_DIG_CNVT_A V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_A VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_A PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_A Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_A NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_A PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_A Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_A Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_A Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_A Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_B); + printf("AUD_OUT_DIG_CNVT_B V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_B VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_B PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_B Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_B NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_B PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_B Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_B Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_B Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_B Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + printf("AUD_OUT_CH_STR Converter_Channel_MAP PORTB PORTC PORTD\n"); + for (i = 0; i < 8; i++) { + OUTREG(AUD_OUT_CH_STR, i | (i << 8) | (i << 16)); + dword = INREG(AUD_OUT_CH_STR); + printf("\t\t\t\t%lu\t%lu\t%lu\t%lu\n", + 1 + BITS(dword, 3, 0), + 1 + BITS(dword, 7, 4), + 1 + BITS(dword, 15, 12), + 1 + BITS(dword, 23, 20)); + } + + dword = INREG(AUD_OUT_STR_DESC_A); + printf("AUD_OUT_STR_DESC_A HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_A Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_A Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_A Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_B); + printf("AUD_OUT_STR_DESC_B HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_B Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_B Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_B Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_PINW_CONNLNG_SEL); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_B\t%lu\n", BITS(dword, 7, 0)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_C\t%lu\n", BITS(dword, 15, 8)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_D\t%lu\n", BITS(dword, 23, 16)); + + dword = INREG(AUD_CNTL_ST_A); + printf("AUD_CNTL_ST_A DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_A DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_A DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_A DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_A DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_A ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_A ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + printf("AUD_CNTL_ST_A ELD_access_address\t\t\t%lu\n", BITS(dword, 9, 5)); + + dword = INREG(AUD_CNTL_ST_B); + printf("AUD_CNTL_ST_B DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_B DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_B DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_B DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_B DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_B ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_B ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + printf("AUD_CNTL_ST_B ELD_access_address\t\t\t%lu\n", BITS(dword, 9, 5)); + + dword = INREG(AUD_CNTL_ST2); + printf("AUD_CNTL_ST2 CP_ReadyB\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_CNTL_ST2 ELD_validB\t\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_CNTL_ST2 CP_ReadyC\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_CNTL_ST2 ELD_validC\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST2 CP_ReadyD\t\t\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_CNTL_ST2 ELD_validD\t\t\t\t%lu\n", BIT(dword, 8)); + + dword = INREG(AUD_HDMIW_STATUS); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 31)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 30)); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 29)); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 28)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK_FIFO_Overrun\t\t%lu\n", BIT(dword, 25)); + printf("AUD_HDMIW_STATUS Function_Reset\t\t\t%lu\n", BIT(dword, 29)); + + printf("AUD_HDMIW_HDMIEDID_A HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_A); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_A, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_A))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_B HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_B); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_B, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_B))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_A HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_A); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_A, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_A))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_B HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_B); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_B, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_B))); + printf("\n"); + +} + + +#undef AUD_CONFIG_A +#undef AUD_MISC_CTRL_A +#undef AUD_VID_DID +#undef AUD_RID +#undef AUD_CTS_ENABLE_A +#undef AUD_PWRST +#undef AUD_HDMIW_HDMIEDID_A +#undef AUD_HDMIW_INFOFR_A +#undef AUD_PORT_EN_HD_CFG +#undef AUD_OUT_DIG_CNVT_A +#undef AUD_OUT_STR_DESC_A +#undef AUD_OUT_CH_STR +#undef AUD_PINW_CONNLNG_LIST +#undef AUD_CNTL_ST_A +#undef AUD_HDMIW_STATUS +#undef AUD_CONFIG_B +#undef AUD_MISC_CTRL_B +#undef AUD_CTS_ENABLE_B +#undef AUD_HDMIW_HDMIEDID_B +#undef AUD_HDMIW_INFOFR_B +#undef AUD_OUT_DIG_CNVT_B +#undef AUD_OUT_STR_DESC_B +#undef AUD_CNTL_ST_B + +/* + * CougarPoint registers + */ +#define DP_CTL_B 0xE4100 +#define DP_CTL_C 0xE4200 +#define DP_AUX_CTL_C 0xE4210 +#define DP_AUX_TST_C 0xE4228 +#define SPORT_DDI_CRC_C 0xE4250 +#define SPORT_DDI_CRC_R 0xE4264 +#define DP_CTL_D 0xE4300 +#define DP_AUX_CTL_D 0xE4310 +#define DP_AUX_TST_D 0xE4328 +#define SPORT_DDI_CRC_CTL_D 0xE4350 +#define AUD_CONFIG_A 0xE5000 +#define AUD_MISC_CTRL_A 0xE5010 +#define AUD_VID_DID 0xE5020 +#define AUD_RID 0xE5024 +#define AUD_CTS_ENABLE_A 0xE5028 +#define AUD_PWRST 0xE504C +#define AUD_HDMIW_HDMIEDID_A 0xE5050 +#define AUD_HDMIW_INFOFR_A 0xE5054 +#define AUD_PORT_EN_HD_CFG 0xE507C +#define AUD_OUT_DIG_CNVT_A 0xE5080 +#define AUD_OUT_STR_DESC_A 0xE5084 +#define AUD_OUT_CH_STR 0xE5088 +#define AUD_PINW_CONNLNG_LIST 0xE50A8 +#define AUD_PINW_CONNLNG_SELA 0xE50AC +#define AUD_CNTL_ST_A 0xE50B4 +#define AUD_CNTRL_ST2 0xE50C0 +#define AUD_CNTRL_ST3 0xE50C4 +#define AUD_HDMIW_STATUS 0xE50D4 +#define AUD_CONFIG_B 0xE5100 +#define AUD_MISC_CTRL_B 0xE5110 +#define AUD_CTS_ENABLE_B 0xE5128 +#define AUD_HDMIW_HDMIEDID_B 0xE5150 +#define AUD_HDMIW_INFOFR_B 0xE5154 +#define AUD_OUT_DIG_CNVT_B 0xE5180 +#define AUD_OUT_STR_DESC_B 0xE5184 +#define AUD_CNTL_ST_B 0xE51B4 +#define AUD_CONFIG_C 0xE5200 +#define AUD_MISC_CTRL_C 0xE5210 +#define AUD_CTS_ENABLE_C 0xE5228 +#define AUD_HDMIW_HDMIEDID_C 0xE5250 +#define AUD_HDMIW_INFOFR_C 0xE5254 +#define AUD_OUT_DIG_CNVT_C 0xE5280 +#define AUD_OUT_STR_DESC_C 0xE5284 +#define AUD_CNTL_ST_C 0xE52B4 +#define AUD_CONFIG_D 0xE5300 +#define AUD_MISC_CTRL_D 0xE5310 +#define AUD_CTS_ENABLE_D 0xE5328 +#define AUD_HDMIW_HDMIEDID_D 0xE5350 +#define AUD_HDMIW_INFOFR_D 0xE5354 +#define AUD_OUT_DIG_CNVT_D 0xE5380 +#define AUD_OUT_STR_DESC_D 0xE5384 +#define AUD_CNTL_ST_D 0xE53B4 + +#define VIDEO_DIP_CTL_A 0xE0200 +#define VIDEO_DIP_CTL_B 0xE1200 +#define VIDEO_DIP_CTL_C 0xE2200 +#define VIDEO_DIP_CTL_D 0xE3200 + + +static void dump_cpt(void) +{ + uint32_t dword; + int i; + + dump_reg(HDMIB, "sDVO/HDMI Port B Control"); + dump_reg(HDMIC, "HDMI Port C Control"); + dump_reg(HDMID, "HDMI Port D Control"); + dump_reg(DP_CTL_B, "DisplayPort B Control"); + dump_reg(DP_CTL_C, "DisplayPort C Control"); + dump_reg(DP_CTL_D, "DisplayPort D Control"); + dump_reg(TRANS_DP_CTL_A, "Transcoder A DisplayPort Control"); + dump_reg(TRANS_DP_CTL_B, "Transcoder B DisplayPort Control"); + dump_reg(TRANS_DP_CTL_C, "Transcoder C DisplayPort Control"); + dump_reg(AUD_CONFIG_A, "Audio Configuration - Transcoder A"); + dump_reg(AUD_CONFIG_B, "Audio Configuration - Transcoder B"); + dump_reg(AUD_CONFIG_C, "Audio Configuration - Transcoder C"); + dump_reg(AUD_CTS_ENABLE_A, "Audio CTS Programming Enable - Transcoder A"); + dump_reg(AUD_CTS_ENABLE_B, "Audio CTS Programming Enable - Transcoder B"); + dump_reg(AUD_CTS_ENABLE_C, "Audio CTS Programming Enable - Transcoder C"); + dump_reg(AUD_MISC_CTRL_A, "Audio MISC Control for Transcoder A"); + dump_reg(AUD_MISC_CTRL_B, "Audio MISC Control for Transcoder B"); + dump_reg(AUD_MISC_CTRL_C, "Audio MISC Control for Transcoder C"); + dump_reg(AUD_VID_DID, "Audio Vendor ID / Device ID"); + dump_reg(AUD_RID, "Audio Revision ID"); + dump_reg(AUD_PWRST, "Audio Power State (Function Group, Convertor, Pin Widget)"); + dump_reg(AUD_PORT_EN_HD_CFG, "Audio Port Enable HDAudio Config"); + dump_reg(AUD_OUT_DIG_CNVT_A, "Audio Digital Converter - Conv A"); + dump_reg(AUD_OUT_DIG_CNVT_B, "Audio Digital Converter - Conv B"); + dump_reg(AUD_OUT_DIG_CNVT_C, "Audio Digital Converter - Conv C"); + dump_reg(AUD_OUT_CH_STR, "Audio Channel ID and Stream ID"); + dump_reg(AUD_OUT_STR_DESC_A, "Audio Stream Descriptor Format - Conv A"); + dump_reg(AUD_OUT_STR_DESC_B, "Audio Stream Descriptor Format - Conv B"); + dump_reg(AUD_OUT_STR_DESC_C, "Audio Stream Descriptor Format - Conv C"); + dump_reg(AUD_PINW_CONNLNG_LIST, "Audio Connection List"); + dump_reg(AUD_PINW_CONNLNG_SEL, "Audio Connection Select"); + dump_reg(AUD_CNTL_ST_A, "Audio Control State Register - Transcoder A"); + dump_reg(AUD_CNTL_ST_B, "Audio Control State Register - Transcoder B"); + dump_reg(AUD_CNTL_ST_C, "Audio Control State Register - Transcoder C"); + dump_reg(AUD_CNTRL_ST2, "Audio Control State 2"); + dump_reg(AUD_CNTRL_ST3, "Audio Control State 3"); + dump_reg(AUD_HDMIW_STATUS, "Audio HDMI Status"); + dump_reg(AUD_HDMIW_HDMIEDID_A, "HDMI Data EDID Block - Transcoder A"); + dump_reg(AUD_HDMIW_HDMIEDID_B, "HDMI Data EDID Block - Transcoder B"); + dump_reg(AUD_HDMIW_HDMIEDID_C, "HDMI Data EDID Block - Transcoder C"); + dump_reg(AUD_HDMIW_INFOFR_A, "Audio Widget Data Island Packet - Transcoder A"); + dump_reg(AUD_HDMIW_INFOFR_B, "Audio Widget Data Island Packet - Transcoder B"); + dump_reg(AUD_HDMIW_INFOFR_C, "Audio Widget Data Island Packet - Transcoder C"); + + printf("\nDetails:\n\n"); + + dword = INREG(VIDEO_DIP_CTL_A); + printf("VIDEO_DIP_CTL_A Enable_Graphics_DIP\t\t\t%ld\n", BIT(dword, 31)), + printf("VIDEO_DIP_CTL_A GCP_DIP_enable\t\t\t\t%ld\n", BIT(dword, 25)), + printf("VIDEO_DIP_CTL_A Video_DIP_type_enable AVI\t\t%lu\n", BIT(dword, 21)); + printf("VIDEO_DIP_CTL_A Video_DIP_type_enable Vendor\t\t%lu\n", BIT(dword, 22)); + printf("VIDEO_DIP_CTL_A Video_DIP_type_enable Gamut\t\t%lu\n", BIT(dword, 23)); + printf("VIDEO_DIP_CTL_A Video_DIP_type_enable Source \t\t%lu\n", BIT(dword, 24)); + printf("VIDEO_DIP_CTL_A Video_DIP_buffer_index\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 19), video_dip_index[BITS(dword, 20, 19)]); + printf("VIDEO_DIP_CTL_A Video_DIP_frequency\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), video_dip_trans[BITS(dword, 17, 16)]); + printf("VIDEO_DIP_CTL_A Video_DIP_buffer_size\t\t\t%lu\n", BITS(dword, 11, 8)); + printf("VIDEO_DIP_CTL_A Video_DIP_access_address\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(VIDEO_DIP_CTL_B); + printf("VIDEO_DIP_CTL_B Enable_Graphics_DIP\t\t\t%ld\n", BIT(dword, 31)), + printf("VIDEO_DIP_CTL_B GCP_DIP_enable\t\t\t\t%ld\n", BIT(dword, 25)), + printf("VIDEO_DIP_CTL_B Video_DIP_type_enable AVI\t\t%lu\n", BIT(dword, 21)); + printf("VIDEO_DIP_CTL_B Video_DIP_type_enable Vendor\t\t%lu\n", BIT(dword, 22)); + printf("VIDEO_DIP_CTL_B Video_DIP_type_enable Gamut\t\t%lu\n", BIT(dword, 23)); + printf("VIDEO_DIP_CTL_B Video_DIP_type_enable Source \t\t%lu\n", BIT(dword, 24)); + printf("VIDEO_DIP_CTL_B Video_DIP_buffer_index\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 19), video_dip_index[BITS(dword, 20, 19)]); + printf("VIDEO_DIP_CTL_B Video_DIP_frequency\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), video_dip_trans[BITS(dword, 17, 16)]); + printf("VIDEO_DIP_CTL_B Video_DIP_buffer_size\t\t\t%lu\n", BITS(dword, 11, 8)); + printf("VIDEO_DIP_CTL_B Video_DIP_access_address\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(VIDEO_DIP_CTL_C); + printf("VIDEO_DIP_CTL_C Enable_Graphics_DIP\t\t\t%ld\n", BIT(dword, 31)), + printf("VIDEO_DIP_CTL_C GCP_DIP_enable\t\t\t\t%ld\n", BIT(dword, 25)), + printf("VIDEO_DIP_CTL_C Video_DIP_type_enable AVI\t\t%lu\n", BIT(dword, 21)); + printf("VIDEO_DIP_CTL_C Video_DIP_type_enable Vendor\t\t%lu\n", BIT(dword, 22)); + printf("VIDEO_DIP_CTL_C Video_DIP_type_enable Gamut\t\t%lu\n", BIT(dword, 23)); + printf("VIDEO_DIP_CTL_C Video_DIP_type_enable Source \t\t%lu\n", BIT(dword, 24)); + printf("VIDEO_DIP_CTL_C Video_DIP_buffer_index\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 19), video_dip_index[BITS(dword, 20, 19)]); + printf("VIDEO_DIP_CTL_C Video_DIP_frequency\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), video_dip_trans[BITS(dword, 17, 16)]); + printf("VIDEO_DIP_CTL_C Video_DIP_buffer_size\t\t\t%lu\n", BITS(dword, 11, 8)); + printf("VIDEO_DIP_CTL_C Video_DIP_access_address\t\t%lu\n", BITS(dword, 3, 0)); + + dword = INREG(AUD_VID_DID); + printf("AUD_VID_DID vendor id\t\t\t\t\t0x%x\n", dword >> 16); + printf("AUD_VID_DID device id\t\t\t\t\t0x%x\n", dword & 0xffff); + + dword = INREG(AUD_RID); + printf("AUD_RID Major_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_RID Minor_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_RID Revision_Id\t\t\t\t\t0x%lx\n", BITS(dword, 15, 8)); + printf("AUD_RID Stepping_Id\t\t\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(HDMIB); + printf("HDMIB Port_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMIB Transcoder_Select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), transcoder_select[BITS(dword, 30, 29)]); + printf("HDMIB sDVO_Border_Enable\t\t\t\t%lu\n", BIT(dword, 7)); + printf("HDMIB HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMIB SDVO_HPD_Interrupt_Enable\t\t\t\t%lu\n", BIT(dword, 23)); + printf("HDMIB Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMIB Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMIB HDMI_or_DVI_Select\t\t\t\t%s\n", BIT(dword, 9) ? "HDMI" : "DVI"); + printf("HDMIB Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(HDMIC); + printf("HDMIC Port_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMIC Transcoder_Select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), transcoder_select[BITS(dword, 30, 29)]); + printf("HDMIC sDVO_Border_Enable\t\t\t\t%lu\n", BIT(dword, 7)); + printf("HDMIC HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMIC SDVO_HPD_Interrupt_Enable\t\t\t\t%lu\n", BIT(dword, 23)); + printf("HDMIC Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMIC Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMIC HDMI_or_DVI_Select\t\t\t\t%s\n", BIT(dword, 9) ? "HDMI" : "DVI"); + printf("HDMIC Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(HDMID); + printf("HDMID Port_Enable\t\t\t\t\t%u\n", !!(dword & SDVO_ENABLE)); + printf("HDMID Transcoder_Select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), transcoder_select[BITS(dword, 30, 29)]); + printf("HDMID sDVO_Border_Enable\t\t\t\t%lu\n", BIT(dword, 7)); + printf("HDMID HDCP_Port_Select\t\t\t\t\t%lu\n", BIT(dword, 5)); + printf("HDMID SDVO_HPD_Interrupt_Enable\t\t\t\t%lu\n", BIT(dword, 23)); + printf("HDMID Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("HDMID Encoding\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 11, 10), sdvo_hdmi_encoding[BITS(dword, 11, 10)]); + printf("HDMID HDMI_or_DVI_Select\t\t\t\t%s\n", BIT(dword, 9) ? "HDMI" : "DVI"); + printf("HDMID Audio_Output_Enable\t\t\t\t%u\n", !!(dword & SDVO_AUDIO_ENABLE)); + + dword = INREG(DP_CTL_B); + printf("DP_CTL_B DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("DP_CTL_B Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("DP_CTL_B Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("DP_CTL_B HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("DP_CTL_B Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(DP_CTL_C); + printf("DP_CTL_C DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("DP_CTL_C Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("DP_CTL_C Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("DP_CTL_C HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("DP_CTL_C Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(DP_CTL_D); + printf("DP_CTL_D DisplayPort_Enable\t\t\t\t%lu\n", BIT(dword, 31)); + printf("DP_CTL_D Port_Width_Selection\t\t\t\t[0x%lx] %s\n", + BITS(dword, 21, 19), dp_port_width[BITS(dword, 21, 19)]); + printf("DP_CTL_D Port_Detected\t\t\t\t\t%lu\n", BIT(dword, 2)); + printf("DP_CTL_D HDCP_Port_Select\t\t\t\t%lu\n", BIT(dword, 5)); + printf("DP_CTL_D Audio_Output_Enable\t\t\t\t%lu\n", BIT(dword, 6)); + + dword = INREG(AUD_CONFIG_A); + printf("AUD_CONFIG_A N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_A N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_A Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_A Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_A Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_A Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_B); + printf("AUD_CONFIG_B N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_B N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_B Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_B Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_B Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_B Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_C); + printf("AUD_CONFIG_C N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_C N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_C Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_C Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_C Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_C Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + + dword = INREG(AUD_CTS_ENABLE_A); + printf("AUD_CTS_ENABLE_A Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_A CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_A CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_B); + printf("AUD_CTS_ENABLE_B Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_B CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_B CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_C); + printf("AUD_CTS_ENABLE_C Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_C CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_C CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + + dword = INREG(AUD_MISC_CTRL_A); + printf("AUD_MISC_CTRL_A Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_A Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_A Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_A Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_B); + printf("AUD_MISC_CTRL_B Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_B Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_B Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_B Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_C); + printf("AUD_MISC_CTRL_C Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_C Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_C Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_C Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + + dword = INREG(AUD_PWRST); + printf("AUD_PWRST Func_Grp_Dev_PwrSt_Curr \t%s\n", power_state[BITS(dword, 27, 26)]); + printf("AUD_PWRST Func_Grp_Dev_PwrSt_Set \t%s\n", power_state[BITS(dword, 25, 24)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 15, 14)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Requsted \t%s\n", power_state[BITS(dword, 13, 12)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 19, 18)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Requested \t%s\n", power_state[BITS(dword, 17, 16)]); + printf("AUD_PWRST ConvC_Widget_PwrSt_Curr \t%s\n", power_state[BITS(dword, 23, 22)]); + printf("AUD_PWRST ConvC_Widget_PwrSt_Req \t%s\n", power_state[BITS(dword, 21, 20)]); + printf("AUD_PWRST PinB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 3, 2)]); + printf("AUD_PWRST PinB_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 1, 0)]); + printf("AUD_PWRST PinC_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 7, 6)]); + printf("AUD_PWRST PinC_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 5, 4)]); + printf("AUD_PWRST PinD_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 11, 10)]); + printf("AUD_PWRST PinD_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 9, 8)]); + + dword = INREG(AUD_PORT_EN_HD_CFG); + printf("AUD_PORT_EN_HD_CFG Convertor_A_Digen\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_PORT_EN_HD_CFG Convertor_B_Digen\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_PORT_EN_HD_CFG Convertor_C_Digen\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_PORT_EN_HD_CFG ConvertorA_Stream_ID\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_PORT_EN_HD_CFG ConvertorB_Stream_ID\t\t%lu\n", BITS(dword, 11, 8)); + printf("AUD_PORT_EN_HD_CFG ConvertorC_Stream_ID\t\t%lu\n", BITS(dword, 15, 12)); + printf("AUD_PORT_EN_HD_CFG Port_B_Out_Enable\t\t\t%lu\n", BIT(dword, 16)); + printf("AUD_PORT_EN_HD_CFG Port_C_Out_Enable\t\t\t%lu\n", BIT(dword, 17)); + printf("AUD_PORT_EN_HD_CFG Port_D_Out_Enable\t\t\t%lu\n", BIT(dword, 18)); + printf("AUD_PORT_EN_HD_CFG Port_B_Amp_Mute_Status\t\t%lu\n", BIT(dword, 20)); + printf("AUD_PORT_EN_HD_CFG Port_C_Amp_Mute_Status\t\t%lu\n", BIT(dword, 21)); + printf("AUD_PORT_EN_HD_CFG Port_D_Amp_Mute_Status\t\t%lu\n", BIT(dword, 22)); + + dword = INREG(AUD_OUT_DIG_CNVT_A); + printf("AUD_OUT_DIG_CNVT_A V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_A VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_A PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_A Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_A NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_A PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_A Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_A Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_A Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_A Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_B); + printf("AUD_OUT_DIG_CNVT_B V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_B VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_B PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_B Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_B NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_B PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_B Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_B Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_B Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_B Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_C); + printf("AUD_OUT_DIG_CNVT_C V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_C VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_C PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_C Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_C NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_C PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_C Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_C Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_C Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_C Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + printf("AUD_OUT_CH_STR Converter_Channel_MAP PORTB PORTC PORTD\n"); + for (i = 0; i < 8; i++) { + OUTREG(AUD_OUT_CH_STR, i | (i << 8) | (i << 16)); + dword = INREG(AUD_OUT_CH_STR); + printf("\t\t\t\t%lu\t%lu\t%lu\t%lu\n", + 1 + BITS(dword, 3, 0), + 1 + BITS(dword, 7, 4), + 1 + BITS(dword, 15, 12), + 1 + BITS(dword, 23, 20)); + } + + dword = INREG(AUD_OUT_STR_DESC_A); + printf("AUD_OUT_STR_DESC_A HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_A Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_A Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_A Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_B); + printf("AUD_OUT_STR_DESC_B HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_B Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_B Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_B Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_C); + printf("AUD_OUT_STR_DESC_C HBR_enable\t\t\t\t%lu\n", BITS(dword, 28, 27)); + printf("AUD_OUT_STR_DESC_C Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_C Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_C Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_PINW_CONNLNG_SEL); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_B\t%#lx\n", BITS(dword, 7, 0)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_C\t%#lx\n", BITS(dword, 15, 8)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_D\t%#lx\n", BITS(dword, 23, 16)); + + dword = INREG(AUD_CNTL_ST_A); + printf("AUD_CNTL_ST_A DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_A DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_A DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_A DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_A DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_A ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_A ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_CNTL_ST_B); + printf("AUD_CNTL_ST_B DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_B DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_B DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_B DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_B DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_B ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_B ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_CNTL_ST_C); + printf("AUD_CNTL_ST_C DIP_Port_Select\t\t\t\t[%#lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + printf("AUD_CNTL_ST_C DIP_type_enable_status Audio DIP\t\t%lu\n", BIT(dword, 21)); + printf("AUD_CNTL_ST_C DIP_type_enable_status ACP DIP\t\t%lu\n", BIT(dword, 22)); + printf("AUD_CNTL_ST_C DIP_type_enable_status Generic 2 DIP\t%lu\n", BIT(dword, 23)); + printf("AUD_CNTL_ST_C DIP_transmission_frequency\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("AUD_CNTL_ST_C ELD_ACK\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTL_ST_C ELD_buffer_size\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_CNTRL_ST2); + printf("AUD_CNTRL_ST2 CP_ReadyB\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_CNTRL_ST2 ELD_validB\t\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_CNTRL_ST2 CP_ReadyC\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_CNTRL_ST2 ELD_validC\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTRL_ST2 CP_ReadyD\t\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_CNTRL_ST2 ELD_validD\t\t\t\t%lu\n", BIT(dword, 8)); + + dword = INREG(AUD_CNTRL_ST3); + printf("AUD_CNTRL_ST3 TransA_DPT_Audio_Output_En\t\t%lu\n", BIT(dword, 3)); + printf("AUD_CNTRL_ST3 TransA_to_Port_Sel\t\t\t[%#lx] %s\n", + BITS(dword, 2, 0), trans_to_port_sel[BITS(dword, 2, 0)]); + printf("AUD_CNTRL_ST3 TransB_DPT_Audio_Output_En\t\t%lu\n", BIT(dword, 7)); + printf("AUD_CNTRL_ST3 TransB_to_Port_Sel\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), trans_to_port_sel[BITS(dword, 6, 4)]); + printf("AUD_CNTRL_ST3 TransC_DPT_Audio_Output_En\t\t%lu\n", BIT(dword, 11)); + printf("AUD_CNTRL_ST3 TransC_to_Port_Sel\t\t\t[%#lx] %s\n", + BITS(dword, 10, 8), trans_to_port_sel[BITS(dword, 10, 8)]); + + dword = INREG(AUD_HDMIW_STATUS); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 27)); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 26)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 29)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 28)); + printf("AUD_HDMIW_STATUS Conv_C_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 31)); + printf("AUD_HDMIW_STATUS Conv_C_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 30)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK_FIFO_Overrun\t\t%lu\n", BIT(dword, 25)); + printf("AUD_HDMIW_STATUS Function_Reset\t\t\t%lu\n", BIT(dword, 24)); + + printf("AUD_HDMIW_HDMIEDID_A HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_A); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_A, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_A))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_B HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_B); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_B, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_B))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_C HDMI ELD:\n\t"); + dword = INREG(AUD_CNTL_ST_C); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_CNTL_ST_C, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_C))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_A HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_A); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_A, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_A))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_B HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_B); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_B, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_B))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_C HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_CNTL_ST_C); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_CNTL_ST_C, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_C))); + printf("\n"); + +} + +#undef AUD_CONFIG_A +#undef AUD_MISC_CTRL_A +#undef AUD_VID_DID +#undef AUD_RID +#undef AUD_CTS_ENABLE_A +#undef AUD_PWRST +#undef AUD_HDMIW_HDMIEDID_A +#undef AUD_HDMIW_INFOFR_A +#undef AUD_PORT_EN_HD_CFG +#undef AUD_OUT_DIG_CNVT_A +#undef AUD_OUT_STR_DESC_A +#undef AUD_OUT_CH_STR +#undef AUD_PINW_CONNLNG_LIST +#undef AUD_CNTL_ST_A +#undef AUD_HDMIW_STATUS +#undef AUD_CONFIG_B +#undef AUD_MISC_CTRL_B +#undef AUD_CTS_ENABLE_B +#undef AUD_HDMIW_HDMIEDID_B +#undef AUD_HDMIW_INFOFR_B +#undef AUD_OUT_DIG_CNVT_B +#undef AUD_OUT_STR_DESC_B +#undef AUD_CNTL_ST_B +#undef AUD_CONFIG_C +#undef AUD_MISC_CTRL_C +#undef AUD_CTS_ENABLE_C +#undef AUD_HDMIW_HDMIEDID_C +#undef AUD_HDMIW_INFOFR_C +#undef AUD_OUT_DIG_CNVT_C +#undef AUD_OUT_STR_DESC_C + +#undef VIDEO_DIP_CTL_A +#undef VIDEO_DIP_CTL_B +#undef VIDEO_DIP_CTL_C +#undef VIDEO_DIP_CTL_D +#undef VIDEO_DIP_DATA + +/* + * Haswell registers + */ + +/* DisplayPort Transport Control */ +#define DP_TP_CTL_A 0x64040 +#define DP_TP_CTL_B 0x64140 +#define DP_TP_CTL_C 0x64240 +#define DP_TP_CTL_D 0x64340 +#define DP_TP_CTL_E 0x64440 + +/* DisplayPort Transport Status */ +#define DP_TP_ST_A 0x64044 +#define DP_TP_ST_B 0x64144 +#define DP_TP_ST_C 0x64244 +#define DP_TP_ST_D 0x64344 +#define DP_TP_ST_E 0x64444 + +/* Transcoder configuration */ +#define TRANS_CONF_A 0xF0008 +#define TRANS_CONF_B 0xF1008 +#define TRANS_CONF_C 0xF2008 + +/* DDI Buffer Control */ +#define DDI_BUF_CTL_A 0x64000 +#define DDI_BUF_CTL_B 0x64100 +#define DDI_BUF_CTL_C 0x64200 +#define DDI_BUF_CTL_D 0x64300 +#define DDI_BUF_CTL_E 0x64400 + +/* DDI Buffer Translation */ +#define DDI_BUF_TRANS_A 0x64e00 +#define DDI_BUF_TRANS_B 0x64e60 +#define DDI_BUF_TRANS_C 0x64ec0 +#define DDI_BUF_TRANS_D 0x64f20 +#define DDI_BUF_TRANS_E 0x64f80 + +/* DDI Aux Channel */ +#define DDI_AUX_CHANNEL_CTRL 0x64010 +#define DDI_AUX_DATA 0x64014 +#define DDI_AUX_TST 0x64028 + +/* DDI CRC Control */ +#define DDI_CRC_CTL_A 0x64050 +#define DDI_CRC_CTL_B 0x64150 +#define DDI_CRC_CTL_C 0x64250 +#define DDI_CRC_CTL_D 0x64350 +#define DDI_CRC_CTL_E 0x64450 + +/* Pipe DDI Function Control */ +#define PIPE_DDI_FUNC_CTL_A 0x60400 +#define PIPE_DDI_FUNC_CTL_B 0x61400 +#define PIPE_DDI_FUNC_CTL_C 0x62400 +#define PIPE_DDI_FUNC_CTL_EDP 0x6F400 + +/* Pipe Configuration */ +#define PIPE_CONF_A 0x70008 +#define PIPE_CONF_B 0x71008 +#define PIPE_CONF_C 0x72008 +#define PIPE_CONF_EDP 0x7F008 + +/* Audio registers */ +#define AUD_CONFIG_A 0x65000 +#define AUD_MISC_CTRL_A 0x65010 +#define AUD_VID_DID 0x65020 +#define AUD_RID 0x65024 +#define AUD_CTS_ENABLE_A 0x65028 +#define AUD_PWRST 0x6504C +#define AUD_HDMIW_HDMIEDID_A 0x65050 +#define AUD_HDMIW_INFOFR_A 0x65054 +#define AUD_PORT_EN_HD_CFG 0x6507C +#define AUD_OUT_DIG_CNVT_A 0x65080 +#define AUD_OUT_STR_DESC_A 0x65084 +#define AUD_OUT_CHAN_MAP 0x65088 +#define AUD_PINW_CONNLNG_LIST_A 0x650A8 +#define AUD_PINW_CONNLNG_LIST_B 0x651A8 +#define AUD_PINW_CONNLNG_LIST_C 0x652A8 +#define AUD_PIPE_CONN_SEL_CTRL 0x650AC +#define AUD_PIN_ELD_CP_VLD 0x650C0 +#define AUD_HDMIW_STATUS 0x650D4 +#define AUD_CONFIG_B 0x65100 +#define AUD_MISC_CTRL_B 0x65110 +#define AUD_CTS_ENABLE_B 0x65128 +#define AUD_HDMIW_HDMIEDID_B 0x65150 +#define AUD_HDMIW_INFOFR_B 0x65154 +#define AUD_OUT_DIG_CNVT_B 0x65180 +#define AUD_OUT_STR_DESC_B 0x65184 +#define AUD_CONFIG_C 0x65200 +#define AUD_MISC_CTRL_C 0x65210 +#define AUD_CTS_ENABLE_C 0x65228 +#define AUD_HDMIW_HDMIEDID_C 0x65250 +#define AUD_HDMIW_INFOFR_C 0x65254 +#define AUD_OUT_DIG_CNVT_C 0x65280 +#define AUD_OUT_STR_DESC_C 0x65284 +#define AUD_DIP_ELD_CTRL_ST_A 0x650b4 +#define AUD_DIP_ELD_CTRL_ST_B 0x651b4 +#define AUD_DIP_ELD_CTRL_ST_C 0x652b4 + +/* Video DIP Control */ +#define VIDEO_DIP_CTL_A 0x60200 +#define VIDEO_DIP_CTL_B 0x61200 +#define VIDEO_DIP_CTL_C 0x62200 +#define VIDEO_DIP_CTL_D 0x63200 + +#define VIDEO_DIP_DATA 0x60220 +#define VIDEO_DIP_ECC 0x60240 + +#define AUD_DP_DIP_STATUS 0x65f20 + + +static void dump_hsw(void) +{ + uint32_t dword; + int i; + + /* HSW DDI Buffer */ + dump_reg(DDI_BUF_CTL_A, "DDI Buffer Controler A"); + dump_reg(DDI_BUF_CTL_B, "DDI Buffer Controler B"); + dump_reg(DDI_BUF_CTL_C, "DDI Buffer Controler C"); + dump_reg(DDI_BUF_CTL_D, "DDI Buffer Controler D"); + dump_reg(DDI_BUF_CTL_E, "DDI Buffer Controler E"); + + /* HSW Pipe Function */ + dump_reg(PIPE_CONF_A, "PIPE Configuration A"); + dump_reg(PIPE_CONF_B, "PIPE Configuration B"); + dump_reg(PIPE_CONF_C, "PIPE Configuration C"); + dump_reg(PIPE_CONF_EDP, "PIPE Configuration EDP"); + + dump_reg(PIPE_DDI_FUNC_CTL_A, "PIPE DDI Function Control A"); + dump_reg(PIPE_DDI_FUNC_CTL_B, "PIPE DDI Function Control B"); + dump_reg(PIPE_DDI_FUNC_CTL_C, "PIPE DDI Function Control C"); + dump_reg(PIPE_DDI_FUNC_CTL_EDP, "PIPE DDI Function Control EDP"); + + /* HSW Display port */ + dump_reg(DP_TP_CTL_A, "DisplayPort Transport A Control"); + dump_reg(DP_TP_CTL_B, "DisplayPort Transport B Control"); + dump_reg(DP_TP_CTL_C, "DisplayPort Transport C Control"); + dump_reg(DP_TP_CTL_D, "DisplayPort Transport D Control"); + dump_reg(DP_TP_CTL_E, "DisplayPort Transport E Control"); + + dump_reg(DP_TP_ST_A, "DisplayPort Transport A Status"); + dump_reg(DP_TP_ST_B, "DisplayPort Transport B Status"); + dump_reg(DP_TP_ST_C, "DisplayPort Transport C Status"); + dump_reg(DP_TP_ST_D, "DisplayPort Transport D Status"); + dump_reg(DP_TP_ST_E, "DisplayPort Transport E Status"); + + /* HSW Transcoder A configuration */ + dump_reg(TRANS_CONF_A, "Transcoder A Configuration"); + dump_reg(TRANS_CONF_B, "Transcoder B Configuration"); + dump_reg(TRANS_CONF_C, "Transcoder C Configuration"); + + /* HSW North Display Audio */ + dump_reg(AUD_CONFIG_A, "Audio Configuration - Transcoder A"); + dump_reg(AUD_CONFIG_B, "Audio Configuration - Transcoder B"); + dump_reg(AUD_CONFIG_C, "Audio Configuration - Transcoder C"); + dump_reg(AUD_MISC_CTRL_A, "Audio MISC Control for Transcoder A"); + dump_reg(AUD_MISC_CTRL_B, "Audio MISC Control for Transcoder B"); + dump_reg(AUD_MISC_CTRL_C, "Audio MISC Control for Transcoder C"); + dump_reg(AUD_VID_DID, "Audio Vendor ID / Device ID"); + dump_reg(AUD_RID, "Audio Revision ID"); + dump_reg(AUD_CTS_ENABLE_A, "Audio CTS Programming Enable - Transcoder A"); + dump_reg(AUD_CTS_ENABLE_B, "Audio CTS Programming Enable - Transcoder B"); + dump_reg(AUD_CTS_ENABLE_C, "Audio CTS Programming Enable - Transcoder C"); + dump_reg(AUD_PWRST, "Audio Power State (Function Group, Convertor, Pin Widget)"); + dump_reg(AUD_HDMIW_HDMIEDID_A, "HDMI Data EDID Block - Transcoder A"); + dump_reg(AUD_HDMIW_HDMIEDID_B, "HDMI Data EDID Block - Transcoder B"); + dump_reg(AUD_HDMIW_HDMIEDID_C, "HDMI Data EDID Block - Transcoder C"); + dump_reg(AUD_HDMIW_INFOFR_A, "Audio Widget Data Island Packet - Transcoder A"); + dump_reg(AUD_HDMIW_INFOFR_B, "Audio Widget Data Island Packet - Transcoder B"); + dump_reg(AUD_HDMIW_INFOFR_C, "Audio Widget Data Island Packet - Transcoder C"); + + dump_reg(AUD_PORT_EN_HD_CFG, "Audio Pipe and Convert Configs"); + dump_reg(AUD_OUT_DIG_CNVT_A, "Audio Digital Converter - Conv A"); + dump_reg(AUD_OUT_DIG_CNVT_B, "Audio Digital Converter - Conv B"); + dump_reg(AUD_OUT_DIG_CNVT_C, "Audio Digital Converter - Conv C"); + dump_reg(AUD_OUT_CHAN_MAP, "Audio Output Channel Mapping"); + dump_reg(AUD_OUT_STR_DESC_A, "Audio Stream Descriptor Format - Conv A"); + dump_reg(AUD_OUT_STR_DESC_B, "Audio Stream Descriptor Format - Conv B"); + dump_reg(AUD_OUT_STR_DESC_C, "Audio Stream Descriptor Format - Conv C"); + dump_reg(AUD_PINW_CONNLNG_LIST_A, "Audio Connection List entry and Length - Transcoder A"); + dump_reg(AUD_PINW_CONNLNG_LIST_B, "Audio Connection List entry and Length - Transcoder B"); + dump_reg(AUD_PINW_CONNLNG_LIST_C, "Audio Connection List entry and Length - Transcoder C"); + dump_reg(AUD_PIPE_CONN_SEL_CTRL, "Audio Pipe Connection Select Control"); + dump_reg(AUD_DIP_ELD_CTRL_ST_A, "Audio DIP and ELD control state - Transcoder A"); + dump_reg(AUD_DIP_ELD_CTRL_ST_B, "Audio DIP and ELD control state - Transcoder B"); + dump_reg(AUD_DIP_ELD_CTRL_ST_C, "Audio DIP and ELD control state - Transcoder C"); + dump_reg(AUD_PIN_ELD_CP_VLD, "audio pin eld valid status"); + dump_reg(AUD_HDMIW_STATUS, "Audio HDMI FIFO Status"); + + printf("\nDetails:\n\n"); + + dword = INREG(AUD_VID_DID); + printf("AUD_VID_DID vendor id\t\t\t\t\t0x%x\n", dword >> 16); + printf("AUD_VID_DID device id\t\t\t\t\t0x%x\n", dword & 0xffff); + + dword = INREG(AUD_RID); + printf("AUD_RID Major_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 23, 20)); + printf("AUD_RID Minor_Revision\t\t\t\t\t0x%lx\n", BITS(dword, 19, 16)); + printf("AUD_RID Revision_Id\t\t\t\t\t0x%lx\n", BITS(dword, 15, 8)); + printf("AUD_RID Stepping_Id\t\t\t\t\t0x%lx\n", BITS(dword, 7, 0)); + + dword = INREG(AUD_DIP_ELD_CTRL_ST_A); + printf("Audio DIP and ELD control state for TranscoderA\n"); + printf("Audio DIP port select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + + printf("Audio DIP type enable status\t\t\t\t[0x%lx] %s\n", + BITS(dword, 24, 21), dip_type[BIT(dword, 21)]); + + printf("DIP Buffer Index \t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 18), dip_index[BITS(dword, 20, 18)]); + printf("DIP_transmission_frequency\t\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("ELD_ACK\t\t\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("ELD_buffer_size\t\t\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_DIP_ELD_CTRL_ST_B); + printf("Audio DIP and ELD control state for TranscoderB\n"); + printf("Audio DIP port select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + + printf("Audio DIP type enable status\t\t\t\t[0x%lx] %s\n", + BITS(dword, 24, 21), dip_type[BIT(dword, 21)]); + + printf("DIP Buffer Index \t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 18), dip_index[BITS(dword, 20, 18)]); + printf("DIP_transmission_frequency\t\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("ELD_ACK\t\t\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("ELD_buffer_size\t\t\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(AUD_DIP_ELD_CTRL_ST_C); + printf("Audio DIP and ELD control state for TranscoderC\n"); + printf("Audio DIP port select\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 30, 29), dip_port[BITS(dword, 30, 29)]); + + printf("Audio DIP type enable status\t\t\t\t[0x%lx] %s\n", + BITS(dword, 24, 21), dip_type[BIT(dword, 21)]); + + printf("DIP Buffer Index \t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 20, 18), dip_index[BITS(dword, 20, 18)]); + printf("DIP_transmission_frequency\t\t\t\t[0x%lx] %s\n", + BITS(dword, 17, 16), dip_trans[BITS(dword, 17, 16)]); + printf("ELD_ACK\t\t\t\t\t\t\t%lu\n", BIT(dword, 4)); + printf("ELD_buffer_size\t\t\t\t\t\t%lu\n", BITS(dword, 14, 10)); + + dword = INREG(DDI_BUF_CTL_A); + printf("DDI A Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + dword = INREG(DDI_BUF_CTL_B); + printf("DDI B Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + dword = INREG(DDI_BUF_CTL_C); + printf("DDI C Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + dword = INREG(DDI_BUF_CTL_D); + printf("DDI D Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + dword = INREG(DDI_BUF_CTL_E); + printf("DDI E Buffer control\n"); + printf("DDI Buffer Enable\t\t\t\t\t%ld\n", BIT(dword, 31)); + printf("DP port width\t\t\t\t\t\t[0x%lx] %s\n", + BITS(dword, 3, 1), dp_port_width[BITS(dword, 3, 1)]); + + dword = INREG(PIPE_DDI_FUNC_CTL_A); + printf("Pipe A DDI Function Control\n"); + printf("PIPE DDI Function Enable\t\t\t\t[0x%lx]\n", BIT(dword, 31)); + printf("PIPE DDI selection\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 30, 28), + trans_to_port_sel[BITS(dword, 30, 28)]); + printf("PIPE DDI Mode\t\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 26, 24), ddi_mode[BITS(dword, 26, 24)]); + printf("BITS per color\t\t\t\t\t\t[0x%lx]\n", BITS(dword, 22, 20)); + + dword = INREG(PIPE_DDI_FUNC_CTL_B); + printf("Pipe B DDI Function Control\n"); + printf("PIPE DDI Function Enable\t\t\t\t[0x%lx]\n", BIT(dword, 31)); + printf("PIPE DDI selection\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 30, 28), + trans_to_port_sel[BITS(dword, 30, 28)]); + printf("PIPE DDI Mode \t\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 26, 24), ddi_mode[BITS(dword, 26, 24)]); + printf("BITS per color\t\t\t\t\t\t[0x%lx]\n", BITS(dword, 22, 20)); + + dword = INREG(PIPE_DDI_FUNC_CTL_C); + printf("Pipe C DDI Function Control\n"); + printf("PIPE DDI Function Enable\t\t\t\t[0x%lx]\n", BIT(dword, 31)); + printf("PIPE DDI selection\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 30, 28), + trans_to_port_sel[BITS(dword, 30, 28)]); + printf("PIPE DDI Mode \t\t\t\t\t\t[0x%lx] %s\n", BITS(dword, 26, 24), ddi_mode[BITS(dword, 26, 24)]); + printf("BITS per color\t\t\t\t\t\t[0x%lx]\n", BITS(dword, 22, 20)); + + dword = INREG(AUD_CONFIG_A); + printf("AUD_CONFIG_A N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_A N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_A Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_A Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_A Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_A Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_B); + printf("AUD_CONFIG_B N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_B N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_B Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_B Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_B Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_B Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + dword = INREG(AUD_CONFIG_C); + printf("AUD_CONFIG_C N_index_value\t\t\t\t[0x%lx] %s\n", BIT(dword, 29), + n_index_value[BIT(dword, 29)]); + printf("AUD_CONFIG_C N_programming_enable\t\t\t%lu\n", BIT(dword, 28)); + printf("AUD_CONFIG_C Upper_N_value\t\t\t\t0x%02lx\n", BITS(dword, 27, 20)); + printf("AUD_CONFIG_C Lower_N_value\t\t\t\t0x%03lx\n", BITS(dword, 15, 4)); + printf("AUD_CONFIG_C Pixel_Clock_HDMI\t\t\t\t[0x%lx] %s\n", BITS(dword, 19, 16), + OPNAME(pixel_clock, BITS(dword, 19, 16))); + printf("AUD_CONFIG_C Disable_NCTS\t\t\t\t%lu\n", BIT(dword, 3)); + + dword = INREG(AUD_CTS_ENABLE_A); + printf("AUD_CTS_ENABLE_A Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_A CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_A CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_B); + printf("AUD_CTS_ENABLE_B Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_B CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_B CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + dword = INREG(AUD_CTS_ENABLE_C); + printf("AUD_CTS_ENABLE_C Enable_CTS_or_M_programming\t\t%lu\n", BIT(dword, 20)); + printf("AUD_CTS_ENABLE_C CTS_M value Index\t\t\t%s\n", BIT(dword, 21) ? "CTS" : "M"); + printf("AUD_CTS_ENABLE_C CTS_programming\t\t\t%#lx\n", BITS(dword, 19, 0)); + + dword = INREG(AUD_MISC_CTRL_A); + printf("AUD_MISC_CTRL_A Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_A Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_A Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_A Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_B); + printf("AUD_MISC_CTRL_B Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_B Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_B Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_B Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + dword = INREG(AUD_MISC_CTRL_C); + printf("AUD_MISC_CTRL_C Sample_Fabrication_EN_bit\t\t%lu\n", BIT(dword, 2)); + printf("AUD_MISC_CTRL_C Sample_present_Disable\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_MISC_CTRL_C Output_Delay\t\t\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_MISC_CTRL_C Pro_Allowed\t\t\t\t%lu\n", BIT(dword, 1)); + + dword = INREG(AUD_PWRST); + printf("AUD_PWRST Func_Grp_Dev_PwrSt_Curr \t%s\n", power_state[BITS(dword, 27, 26)]); + printf("AUD_PWRST Func_Grp_Dev_PwrSt_Set \t%s\n", power_state[BITS(dword, 25, 24)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 15, 14)]); + printf("AUD_PWRST ConvertorA_Widget_Power_State_Requsted \t%s\n", power_state[BITS(dword, 13, 12)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 19, 18)]); + printf("AUD_PWRST ConvertorB_Widget_Power_State_Requested \t%s\n", power_state[BITS(dword, 17, 16)]); + printf("AUD_PWRST ConvC_Widget_PwrSt_Curr \t%s\n", power_state[BITS(dword, 23, 22)]); + printf("AUD_PWRST ConvC_Widget_PwrSt_Req \t%s\n", power_state[BITS(dword, 21, 20)]); + printf("AUD_PWRST PinB_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 3, 2)]); + printf("AUD_PWRST PinB_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 1, 0)]); + printf("AUD_PWRST PinC_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 7, 6)]); + printf("AUD_PWRST PinC_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 5, 4)]); + printf("AUD_PWRST PinD_Widget_Power_State_Current \t%s\n", power_state[BITS(dword, 11, 10)]); + printf("AUD_PWRST PinD_Widget_Power_State_Set \t%s\n", power_state[BITS(dword, 9, 8)]); + + dword = INREG(AUD_PORT_EN_HD_CFG); + printf("AUD_PORT_EN_HD_CFG Convertor_A_Digen\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_PORT_EN_HD_CFG Convertor_B_Digen\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_PORT_EN_HD_CFG Convertor_C_Digen\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_PORT_EN_HD_CFG ConvertorA_Stream_ID\t\t%lu\n", BITS(dword, 7, 4)); + printf("AUD_PORT_EN_HD_CFG ConvertorB_Stream_ID\t\t%lu\n", BITS(dword, 11, 8)); + printf("AUD_PORT_EN_HD_CFG ConvertorC_Stream_ID\t\t%lu\n", BITS(dword, 15, 12)); + printf("AUD_PORT_EN_HD_CFG Port_B_Out_Enable\t\t\t%lu\n", BIT(dword, 16)); + printf("AUD_PORT_EN_HD_CFG Port_C_Out_Enable\t\t\t%lu\n", BIT(dword, 17)); + printf("AUD_PORT_EN_HD_CFG Port_D_Out_Enable\t\t\t%lu\n", BIT(dword, 18)); + printf("AUD_PORT_EN_HD_CFG Port_B_Amp_Mute_Status\t\t%lu\n", BIT(dword, 20)); + printf("AUD_PORT_EN_HD_CFG Port_C_Amp_Mute_Status\t\t%lu\n", BIT(dword, 21)); + printf("AUD_PORT_EN_HD_CFG Port_D_Amp_Mute_Status\t\t%lu\n", BIT(dword, 22)); + + dword = INREG(AUD_OUT_DIG_CNVT_A); + printf("AUD_OUT_DIG_CNVT_A V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_A VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_A PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_A Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_A NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_A PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_A Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_A Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_A Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_A Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_B); + printf("AUD_OUT_DIG_CNVT_B V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_B VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_B PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_B Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_B NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_B PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_B Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_B Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_B Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_B Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + dword = INREG(AUD_OUT_DIG_CNVT_C); + printf("AUD_OUT_DIG_CNVT_C V\t\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_OUT_DIG_CNVT_C VCFG\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_OUT_DIG_CNVT_C PRE\t\t\t\t\t%lu\n", BIT(dword, 3)); + printf("AUD_OUT_DIG_CNVT_C Copy\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_OUT_DIG_CNVT_C NonAudio\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_OUT_DIG_CNVT_C PRO\t\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_OUT_DIG_CNVT_C Level\t\t\t\t%lu\n", BIT(dword, 7)); + printf("AUD_OUT_DIG_CNVT_C Category_Code\t\t\t%lu\n", BITS(dword, 14, 8)); + printf("AUD_OUT_DIG_CNVT_C Lowest_Channel_Number\t\t%lu\n",BITS(dword, 19, 16)); + printf("AUD_OUT_DIG_CNVT_C Stream_ID\t\t\t\t%lu\n", BITS(dword, 23, 20)); + + printf("AUD_OUT_CHAN_MAP Converter_Channel_MAP PORTB PORTC PORTD\n"); + for (i = 0; i < 8; i++) { + OUTREG(AUD_OUT_CHAN_MAP, i | (i << 8) | (i << 16)); + dword = INREG(AUD_OUT_CHAN_MAP); + printf("\t\t\t\t%lu\t%lu\t%lu\t%lu\n", + 1 + BITS(dword, 3, 0), + 1 + BITS(dword, 7, 4), + 1 + BITS(dword, 15, 12), + 1 + BITS(dword, 23, 20)); + } + + dword = INREG(AUD_OUT_STR_DESC_A); + printf("AUD_OUT_STR_DESC_A Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_A Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_A Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_B); + printf("AUD_OUT_STR_DESC_B Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_B Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_B Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_OUT_STR_DESC_C); + printf("AUD_OUT_STR_DESC_C Convertor_Channel_Count\t\t%lu\n", BITS(dword, 20, 16) + 1); + printf("AUD_OUT_STR_DESC_C Bits_per_Sample\t\t\t[%#lx] %s\n", + BITS(dword, 6, 4), OPNAME(bits_per_sample, BITS(dword, 6, 4))); + printf("AUD_OUT_STR_DESC_C Number_of_Channels_in_a_Stream\t%lu\n", 1 + BITS(dword, 3, 0)); + + dword = INREG(AUD_PINW_CONNLNG_SEL); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_B\t%#lx\n", BITS(dword, 7, 0)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_C\t%#lx\n", BITS(dword, 15, 8)); + printf("AUD_PINW_CONNLNG_SEL Connection_select_Control_D\t%#lx\n", BITS(dword, 23, 16)); + + dword = INREG(AUD_PIN_ELD_CP_VLD); + printf("AUD_CNTRL_ST2 CP_ReadyB\t\t\t\t%lu\n", BIT(dword, 1)); + printf("AUD_CNTRL_ST2 ELD_validB\t\t\t\t%lu\n", BIT(dword, 0)); + printf("AUD_CNTRL_ST2 OUT_enableB\t\t\t\t%lu\n", BIT(dword, 2)); + printf("AUD_CNTRL_ST2 CP_ReadyC\t\t\t\t%lu\n", BIT(dword, 5)); + printf("AUD_CNTRL_ST2 ELD_validC\t\t\t\t%lu\n", BIT(dword, 4)); + printf("AUD_CNTRL_ST2 OUT_enableC\t\t\t\t%lu\n", BIT(dword, 6)); + printf("AUD_CNTRL_ST2 CP_ReadyD\t\t\t\t%lu\n", BIT(dword, 9)); + printf("AUD_CNTRL_ST2 ELD_validD\t\t\t\t%lu\n", BIT(dword, 8)); + printf("AUD_CNTRL_ST2 OUT_enableD\t\t\t\t%lu\n", BIT(dword, 10)); + + dword = INREG(AUD_HDMIW_STATUS); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 27)); + printf("AUD_HDMIW_STATUS Conv_A_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 26)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 29)); + printf("AUD_HDMIW_STATUS Conv_B_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 28)); + printf("AUD_HDMIW_STATUS Conv_C_CDCLK/DOTCLK_FIFO_Underrun\t%lu\n", BIT(dword, 31)); + printf("AUD_HDMIW_STATUS Conv_C_CDCLK/DOTCLK_FIFO_Overrun\t%lu\n", BIT(dword, 30)); + printf("AUD_HDMIW_STATUS BCLK/CDCLK_FIFO_Overrun\t\t%lu\n", BIT(dword, 25)); + printf("AUD_HDMIW_STATUS Function_Reset\t\t\t%lu\n", BIT(dword, 24)); + + printf("AUD_HDMIW_HDMIEDID_A HDMI ELD:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_A); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_DIP_ELD_CTRL_ST_A, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_A))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_B HDMI ELD:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_B); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_DIP_ELD_CTRL_ST_B, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_B))); + printf("\n"); + + printf("AUD_HDMIW_HDMIEDID_C HDMI ELD:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_C); + dword &= ~BITMASK(9, 5); + OUTREG(AUD_DIP_ELD_CTRL_ST_C, dword); + for (i = 0; i < BITS(dword, 14, 10) / 4; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_HDMIEDID_C))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_A HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_A); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_DIP_ELD_CTRL_ST_A, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_A))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_B HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_B); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_DIP_ELD_CTRL_ST_B, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_B))); + printf("\n"); + + printf("AUD_HDMIW_INFOFR_C HDMI audio Infoframe:\n\t"); + dword = INREG(AUD_DIP_ELD_CTRL_ST_C); + dword &= ~BITMASK(20, 18); + dword &= ~BITMASK(3, 0); + OUTREG(AUD_DIP_ELD_CTRL_ST_C, dword); + for (i = 0; i < 8; i++) + printf("%08x ", htonl(INREG(AUD_HDMIW_INFOFR_C))); + printf("\n"); +} + +int main(int argc, char **argv) +{ + struct pci_device *pci_dev; + + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; /* XXX not true when mapping! */ + + do_self_tests(); + + if (argc == 2) + intel_map_file(argv[1]); + else + intel_get_mmio(pci_dev); + + if (IS_GEN6(devid) || IS_GEN7(devid) || getenv("HAS_PCH_SPLIT")) { + if (IS_HASWELL(devid)) { + printf("Haswell audio registers:\n\n"); + dump_hsw(); + return 0; + } + printf("%s audio registers:\n\n", + IS_GEN6(devid) ? "SandyBridge" : "IvyBridge"); + intel_check_pch(); + dump_cpt(); + } else if (IS_GEN5(devid)) { + printf("Ironlake audio registers:\n\n"); + dump_ironlake(); + } else if (IS_G4X(devid)) { + printf("G45 audio registers:\n\n"); + dump_eaglelake(); + } + + return 0; +} diff --git a/tools/intel_backlight.c b/tools/intel_backlight.c new file mode 100644 index 00000000..bd7c813b --- /dev/null +++ b/tools/intel_backlight.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2011 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "intel_gpu_tools.h" + +/* XXX PCH only today */ + +static uint32_t reg_read(uint32_t reg) +{ + return *(volatile uint32_t *)((volatile char*)mmio + reg); +} + +static void reg_write(uint32_t reg, uint32_t val) +{ + *(volatile uint32_t *)((volatile char*)mmio + reg) = val; +} + +int main(int argc, char** argv) +{ + uint32_t current, max; + + intel_get_mmio(intel_get_pci_device()); + + current = reg_read(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; + max = reg_read(BLC_PWM_PCH_CTL2) >> 16; + + printf ("current backlight value: %d%%\n", current * 100 / max); + + if (argc > 1) { + uint32_t v = atoi (argv[1]) * max / 100; + if (v > max) + v = max; + reg_write(BLC_PWM_CPU_CTL, + (reg_read(BLC_PWM_CPU_CTL) &~ BACKLIGHT_DUTY_CYCLE_MASK) | v); + (void) reg_read(BLC_PWM_CPU_CTL); + printf ("set backlight to %d%%\n", v * 100 / max); + } + + return 0; +} diff --git a/tools/intel_bios.h b/tools/intel_bios.h new file mode 100644 index 00000000..12850203 --- /dev/null +++ b/tools/intel_bios.h @@ -0,0 +1,731 @@ +/* + * Copyright 2006 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> + * + */ + +#ifndef _INTEL_BIOS_H_ +#define _INTEL_BIOS_H_ + +#include <stdint.h> + +struct vbt_header { + char signature[20]; /**< Always starts with 'VBT$' */ + uint16_t version; /**< decimal */ + uint16_t header_size; /**< in bytes */ + uint16_t vbt_size; /**< in bytes */ + uint8_t vbt_checksum; + uint8_t reserved0; + uint32_t bdb_offset; /**< from beginning of VBT */ + uint32_t aim_offset[4]; /**< from beginning of VBT */ +} __attribute__ ((packed)); + +struct bdb_header { + char signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ + uint16_t version; /**< decimal */ + uint16_t header_size; /**< in bytes */ + uint16_t bdb_size; /**< in bytes */ +} __attribute__ ((packed)); + +/* + * There are several types of BIOS data blocks (BDBs), each block has + * an ID and size in the first 3 bytes (ID in first, size in next 2). + * Known types are listed below. + */ +#define BDB_GENERAL_FEATURES 1 +#define BDB_GENERAL_DEFINITIONS 2 +#define BDB_OLD_TOGGLE_LIST 3 +#define BDB_MODE_SUPPORT_LIST 4 +#define BDB_GENERIC_MODE_TABLE 5 +#define BDB_EXT_MMIO_REGS 6 +#define BDB_SWF_IO 7 +#define BDB_SWF_MMIO 8 +#define BDB_DOT_CLOCK_TABLE 9 +#define BDB_MODE_REMOVAL_TABLE 10 +#define BDB_CHILD_DEVICE_TABLE 11 +#define BDB_DRIVER_FEATURES 12 +#define BDB_DRIVER_PERSISTENCE 13 +#define BDB_EXT_TABLE_PTRS 14 +#define BDB_DOT_CLOCK_OVERRIDE 15 +#define BDB_DISPLAY_SELECT 16 +/* 17 rsvd */ +#define BDB_DRIVER_ROTATION 18 +#define BDB_DISPLAY_REMOVE 19 +#define BDB_OEM_CUSTOM 20 +#define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */ +#define BDB_SDVO_LVDS_OPTIONS 22 +#define BDB_SDVO_PANEL_DTDS 23 +#define BDB_SDVO_LVDS_PNP_IDS 24 +#define BDB_SDVO_LVDS_POWER_SEQ 25 +#define BDB_TV_OPTIONS 26 +#define BDB_EDP 27 +#define BDB_LVDS_OPTIONS 40 +#define BDB_LVDS_LFP_DATA_PTRS 41 +#define BDB_LVDS_LFP_DATA 42 +#define BDB_LVDS_BACKLIGHT 43 +#define BDB_LVDS_POWER 44 +#define BDB_SKIP 254 /* VBIOS private block, ignore */ + +struct bdb_general_features { + /* bits 1 */ + unsigned char panel_fitting:2; + unsigned char flexaim:1; + unsigned char msg_enable:1; + unsigned char clear_screen:3; + unsigned char color_flip:1; + + /* bits 2 */ + unsigned char download_ext_vbt:1; + unsigned char enable_ssc:1; + unsigned char ssc_freq:1; + unsigned char enable_lfp_on_override:1; + unsigned char disable_ssc_ddt:1; + unsigned char rsvd8:3; /* finish byte */ + + /* bits 3 */ + unsigned char disable_smooth_vision:1; + unsigned char single_dvi:1; + unsigned char rsvd9:6; /* finish byte */ + + /* bits 4 */ + unsigned char legacy_monitor_detect; + + /* bits 5 */ + unsigned char int_crt_support:1; + unsigned char int_tv_support:1; + unsigned char rsvd11:6; /* finish byte */ +} __attribute__ ((packed)); + +#define GPIO_PIN_NONE 0x00 /* "N/A" */ +#define GPIO_PIN_I2C 0x01 /* "I2C GPIO pins" */ +#define GPIO_PIN_CRT_DDC 0x02 /* "Analog CRT DDC GPIO pins" */ +/* 915+ */ +#define GPIO_PIN_LVDS 0x03 /* "Integrated LVDS DDC GPIO pins" */ +#define GPIO_PIN_SDVO_I2C 0x05 /* "sDVO I2C GPIO pins" */ +#define GPIO_PIN_SDVO_DDC1 0x1D /* "SDVO DDC1 GPIO pins" */ +#define GPIO_PIN_SDVO_DDC2 0x2D /* "SDVO DDC2 GPIO pins" */ +/* pre-915 */ +#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ +#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */ +#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */ +#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */ + +/* Pre 915 */ +#define DEVICE_TYPE_NONE 0x00 +#define DEVICE_TYPE_CRT 0x01 +#define DEVICE_TYPE_TV 0x09 +#define DEVICE_TYPE_EFP 0x12 +#define DEVICE_TYPE_LFP 0x22 +/* On 915+ */ +#define DEVICE_TYPE_CRT_DPMS 0x6001 +#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001 +#define DEVICE_TYPE_TV_COMPOSITE 0x0209 +#define DEVICE_TYPE_TV_MACROVISION 0x0289 +#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c +#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609 +#define DEVICE_TYPE_TV_SCART 0x0209 +#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009 +#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012 +#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052 +#define DEVICE_TYPE_EFP_DVI_I 0x6053 +#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152 +#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2 +#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062 +#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162 +#define DEVICE_TYPE_LFP_PANELLINK 0x5012 +#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042 +#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062 +#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162 +#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2 +#define DEVICE_TYPE_INT_HDMI 0xf0D2 + +#define DEVICE_TYPE_INT_LFP 0x1022 +#define DEVICE_TYPE_INT_TV 0x1009 +#define DEVICE_TYPE_DP 0x68C6 +#define DEVICE_TYPE_DP_HDMI_DVI 0x60d6 +#define DEVICE_TYPE_DP_DVI 0x68d6 +#define DEVICE_TYPE_HDMI_DVI 0x60d2 +#define DEVICE_TYPE_DVI 0x68d2 +#define DEVICE_TYPE_eDP 0x78C6 + +#define DEVICE_CFG_NONE 0x00 +#define DEVICE_CFG_12BIT_DVOB 0x01 +#define DEVICE_CFG_12BIT_DVOC 0x02 +#define DEVICE_CFG_24BIT_DVOBC 0x09 +#define DEVICE_CFG_24BIT_DVOCB 0x0a +#define DEVICE_CFG_DUAL_DVOB 0x11 +#define DEVICE_CFG_DUAL_DVOC 0x12 +#define DEVICE_CFG_DUAL_DVOBC 0x13 +#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19 +#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a + +#define DEVICE_WIRE_NONE 0x00 +#define DEVICE_WIRE_DVOB 0x01 +#define DEVICE_WIRE_DVOC 0x02 +#define DEVICE_WIRE_DVOBC 0x03 +#define DEVICE_WIRE_DVOBB 0x05 +#define DEVICE_WIRE_DVOCC 0x06 +#define DEVICE_WIRE_DVOB_MASTER 0x0d +#define DEVICE_WIRE_DVOC_MASTER 0x0e + +#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */ +#define DEVICE_PORT_DVOB 0x01 +#define DEVICE_PORT_DVOC 0x02 + +#define DEVICE_PORT_NONE 0 +#define DEVICE_PORT_HDMIB 1 +#define DEVICE_PORT_HDMIC 2 +#define DEVICE_PORT_HDMID 3 +#define DEVICE_PORT_DPB 7 +#define DEVICE_PORT_DPC 8 +#define DEVICE_PORT_DPD 9 + +#define DEVICE_INFO_NONE 0 +#define DEVICE_INFO_HDMI_CERT 1 +#define DEVICE_INFO_DP 2 +#define DEVICE_INFO_DVI 3 + +struct child_device_config { + uint16_t handle; + uint16_t device_type; /* See DEVICE_TYPE_* above */ + uint8_t device_id[10]; + uint16_t addin_offset; + uint8_t dvo_port; /* See DEVICE_PORT_* above */ + uint8_t i2c_pin; + uint8_t slave_addr; + uint8_t ddc_pin; + uint16_t edid_ptr; + uint8_t dvo_cfg; /* See DEVICE_CFG_* above */ + uint8_t dvo2_port; + uint8_t i2c2_pin; + uint8_t slave2_addr; + uint8_t ddc2_pin; + uint8_t capabilities; + uint8_t dvo_wiring; /* See DEVICE_WIRE_* above */ + uint8_t dvo2_wiring; + uint16_t extended_type; + uint8_t dvo_function; +} __attribute__ ((packed)); + +struct efp_child_device_config { + uint16_t handle; + uint16_t device_type; + uint8_t skip1[12]; + uint8_t port; + uint8_t skip2[2]; + uint8_t ddc_pin; + uint8_t skip3[3]; + uint8_t docked_port; + uint8_t hdmi_compat:1; + uint8_t conn_info:3; + uint8_t skip4:4; + uint8_t aux_chan; + uint8_t dongle_detect; + uint8_t skip5[6]; +} __attribute__ ((packed)); + +struct bdb_general_definitions { + unsigned char crt_ddc_gmbus_pin; /* see GPIO_PIN_* above */ + + /* DPMS bits */ + unsigned char dpms_acpi:1; + unsigned char skip_boot_crt_detect:1; + unsigned char dpms_aim:1; + unsigned char rsvd1:5; /* finish byte */ + + /* boot device bits */ + unsigned char boot_display[2]; + unsigned char child_dev_size; + + /* + * Device info: + * If TV is present, it'll be at devices[0] + * LVDS will be next, either devices[0] or [1], if present + * Max total will be 6, but could be as few as 4 if both + * TV and LVDS are missing, so be careful when interpreting + * [4] and [5]. + */ + struct child_device_config devices[0]; + /* may be another device block here on some platforms */ +} __attribute__ ((packed)); + +#define DEVICE_CHILD_SIZE 7 + +struct bdb_child_devices { + uint8_t child_structure_size; + struct child_device_config children[DEVICE_CHILD_SIZE]; +} __attribute__ ((packed)); + +struct bdb_lvds_options { + uint8_t panel_type; + uint8_t rsvd1; + /* LVDS capabilities, stored in a dword */ + uint8_t pfit_mode:2; + uint8_t pfit_text_mode_enhanced:1; + uint8_t pfit_gfx_mode_enhanced:1; + uint8_t pfit_ratio_auto:1; + uint8_t pixel_dither:1; + uint8_t lvds_edid:1; + uint8_t rsvd2:1; + uint8_t rsvd4; +} __attribute__ ((packed)); + +/* 915+ only */ +struct bdb_tv_features { + /* need to verify bit ordering */ + uint16_t under_over_scan_via_yprpb:2; + uint16_t rsvd1:10; + uint16_t under_over_scan_via_dvi:2; + uint16_t add_overscan_mode:1; + uint16_t rsvd2:1; +} __attribute__ ((packed)); + +struct lvds_fp_timing { + uint16_t x_res; + uint16_t y_res; + uint32_t lvds_reg; + uint32_t lvds_reg_val; + uint32_t pp_on_reg; + uint32_t pp_on_reg_val; + uint32_t pp_off_reg; + uint32_t pp_off_reg_val; + uint32_t pp_cycle_reg; + uint32_t pp_cycle_reg_val; + uint32_t pfit_reg; + uint32_t pfit_reg_val; + uint16_t terminator; +} __attribute__ ((packed)); + +struct lvds_dvo_timing { + uint16_t dclk; /**< In 10khz */ + uint8_t hactive; + uint8_t hblank; + uint8_t high_h; /**< 7:4 = hactive 11:8, 3:0 = hblank 11:8 */ + uint8_t vactive; + uint8_t vblank; + uint8_t high_v; /**< 7:4 = vactive 11:8, 3:0 = vblank 11:8 */ + uint8_t hsync_off; + uint8_t hsync_pulse_width; + uint8_t vsync_off; + uint8_t high_hsync_off; /**< 7:6 = hsync off 9:8 */ + uint8_t h_image; + uint8_t v_image; + uint8_t max_hv; + uint8_t h_border; + uint8_t v_border; + uint8_t flags; +} __attribute__ ((packed)); +struct lvds_dvo_timing2 { + uint16_t clock; /**< In 10khz */ + uint8_t hactive_lo; + uint8_t hblank_lo; + uint8_t hblank_hi:4; + uint8_t hactive_hi:4; + uint8_t vactive_lo; + uint8_t vblank_lo; + uint8_t vblank_hi:4; + uint8_t vactive_hi:4; + uint8_t hsync_off_lo; + uint8_t hsync_pulse_width; + uint8_t vsync_pulse_width:4; + uint8_t vsync_off:4; + uint8_t rsvd0:6; + uint8_t hsync_off_hi:2; + uint8_t h_image; + uint8_t v_image; + uint8_t max_hv; + uint8_t h_border; + uint8_t v_border; + uint8_t rsvd1:3; + uint8_t digital:2; + uint8_t vsync_positive:1; + uint8_t hsync_positive:1; + uint8_t rsvd2:1; +} __attribute__((packed)); + +struct lvds_pnp_id { + uint16_t mfg_name; + uint16_t product_code; + uint32_t serial; + uint8_t mfg_week; + uint8_t mfg_year; +} __attribute__ ((packed));; + +/* LFP pointer table contains entries to the struct below */ +struct bdb_lvds_lfp_data_ptr { + uint16_t fp_timing_offset; /* offsets are from start of bdb */ + uint8_t fp_table_size; + uint16_t dvo_timing_offset; + uint8_t dvo_table_size; + uint16_t panel_pnp_id_offset; + uint8_t pnp_table_size; +} __attribute__ ((packed)); + +struct bdb_lvds_lfp_data_ptrs { + uint8_t lvds_entries; + struct bdb_lvds_lfp_data_ptr ptr[16]; +} __attribute__ ((packed)); + +struct bdb_lvds_lfp_data_entry { + struct lvds_fp_timing fp_timing; + struct lvds_dvo_timing dvo_timing; + struct lvds_pnp_id pnp_id; +} __attribute__ ((packed)); + +struct bdb_lvds_lfp_data { + struct bdb_lvds_lfp_data_entry data[16]; +} __attribute__ ((packed)); + +#define BACKLIGHT_TYPE_NONE 0 +#define BACKLIGHT_TYPE_I2C 1 +#define BACKLIGHT_TYPE_PWM 2 + +#define BACKLIGHT_GMBUS_100KHZ 0 +#define BACKLIGHT_GMBUS_50KHZ 1 +#define BACKLIGHT_GMBUS_400KHZ 2 +#define BACKLIGHT_GMBUS_1MHZ 3 + +struct backlight_info { + uint8_t inverter_type:2; /* see BACKLIGHT_TYPE_* above */ + uint8_t inverter_polarity:1; /* 1 means 0 is max, 255 is min */ + uint8_t gpio_pins:3; /* see GPIO_PIN_* above */ + uint8_t gmbus_speed:2; + uint16_t pwm_frequency; /* in Hz */ + uint8_t min_brightness; + /* Next two are only for 915+ systems */ + uint8_t i2c_addr; + uint8_t i2c_cmd; +} __attribute((packed)); + +struct bdb_backlight_control { + uint8_t row_size; + struct backlight_info lfps[16]; +} __attribute__ ((packed)); + +struct bdb_bia { + uint8_t bia_enable:1; + uint8_t bia_level:3; + uint8_t rsvd1:3; + uint8_t als_enable:1; + uint8_t als_response_data[20]; +} __attribute((packed)); + +struct aimdb_header { + char signature[16]; + char oem_device[20]; + uint16_t aimdb_version; + uint16_t aimdb_header_size; + uint16_t aimdb_size; +} __attribute__ ((packed)); + +struct aimdb_block { + uint8_t aimdb_id; + uint16_t aimdb_size; +} __attribute__ ((packed)); + +struct vch_panel_data { + uint16_t fp_timing_offset; + uint8_t fp_timing_size; + uint16_t dvo_timing_offset; + uint8_t dvo_timing_size; + uint16_t text_fitting_offset; + uint8_t text_fitting_size; + uint16_t graphics_fitting_offset; + uint8_t graphics_fitting_size; +} __attribute__ ((packed)); + +struct vch_bdb_22 { + struct aimdb_block aimdb_block; + struct vch_panel_data panels[16]; +} __attribute__ ((packed)); + +#define BLC_INVERTER_TYPE_NONE 0 +#define BLC_INVERTER_TYPE_I2C 1 +#define BLC_INVERTER_TYPE_PWM 2 + +#define BLC_GPIO_NONE 0 +#define BLC_GPIO_I2C 1 +#define BLC_GPIO_CRT_DDC 2 +#define BLC_GPIO_DVI_DDC 3 +#define BLC_GPIO_SDVO_I2C 5 + +struct blc_struct { + uint8_t inverter_type:2; + uint8_t inverter_polarity:1; /* 1 means inverted (0 = max brightness) */ + uint8_t gpio_pins:3; + uint8_t gmbus_speed:2; + uint16_t pwm_freq; /* in Hz */ + uint8_t min_brightness; /* (0-255) */ + uint8_t i2c_slave_addr; + uint8_t i2c_cmd; +} __attribute__ ((packed)); + +struct bdb_lvds_backlight { + uint8_t blcstruct_size; + struct blc_struct panels[16]; +} __attribute__ ((packed)); + +struct bdb_lvds_power { + uint8_t dpst_enabled:1; + uint8_t pwr_prefs:3; + uint8_t rsvd1:3; + uint8_t als_enabled:1; + uint16_t als_backlight1; + uint16_t als_backlight2; + uint16_t als_backlight3; + uint16_t als_backlight4; + uint16_t als_backlight5; +} __attribute__ ((packed)); + +#define BDB_DRIVER_NO_LVDS 0 +#define BDB_DRIVER_INT_LVDS 1 +#define BDB_DRIVER_SDVO_LVDS 2 +#define BDB_DRIVER_EDP 3 + +struct bdb_driver_feature { + uint8_t boot_dev_algorithm:1; + uint8_t block_display_switch:1; + uint8_t allow_display_switch:1; + uint8_t hotplug_dvo:1; + uint8_t dual_view_zoom:1; + uint8_t int15h_hook:1; + uint8_t sprite_in_clone:1; + uint8_t primary_lfp_id:1; + + uint16_t boot_mode_x; + uint16_t boot_mode_y; + uint8_t boot_mode_bpp; + uint8_t boot_mode_refresh; + + uint16_t enable_lfp_primary:1; + uint16_t selective_mode_pruning:1; + uint16_t dual_frequency:1; + uint16_t render_clock_freq:1; /* 0: high freq; 1: low freq */ + uint16_t nt_clone_support:1; + uint16_t power_scheme_ui:1; /* 0: CUI; 1: 3rd party */ + uint16_t sprite_display_assign:1; /* 0: secondary; 1: primary */ + uint16_t cui_aspect_scaling:1; + uint16_t preserve_aspect_ratio:1; + uint16_t sdvo_device_power_down:1; + uint16_t crt_hotplug:1; + uint16_t lvds_config:2; + uint16_t reserved:3; + + uint8_t static_display:1; + uint8_t reserved2:7; + uint16_t legacy_crt_max_x; + uint16_t legacy_crt_max_y; + uint8_t legacy_crt_max_refresh; +} __attribute__ ((packed)); + +struct bdb_sdvo_lvds_options { + uint8_t panel_backlight; + uint8_t h40_set_panel_type; + uint8_t panel_type; + uint8_t ssc_clk_freq; + uint16_t als_low_trip; + uint16_t als_high_trip; + uint8_t sclalarcoeff_tab_row_num; + uint8_t sclalarcoeff_tab_row_size; + uint8_t coefficient[8]; + uint8_t panel_misc_bits_1; + uint8_t panel_misc_bits_2; + uint8_t panel_misc_bits_3; + uint8_t panel_misc_bits_4; +} __attribute__ ((packed)); + +#define EDP_18BPP 0 +#define EDP_24BPP 1 +#define EDP_30BPP 2 +#define EDP_RATE_1_62 0 +#define EDP_RATE_2_7 1 +#define EDP_LANE_1 0 +#define EDP_LANE_2 1 +#define EDP_LANE_4 3 +#define EDP_PREEMPHASIS_NONE 0 +#define EDP_PREEMPHASIS_3_5dB 1 +#define EDP_PREEMPHASIS_6dB 2 +#define EDP_PREEMPHASIS_9_5dB 3 +#define EDP_VSWING_0_4V 0 +#define EDP_VSWING_0_6V 1 +#define EDP_VSWING_0_8V 2 +#define EDP_VSWING_1_2V 3 + +struct edp_power_seq { + uint16_t t3; + uint16_t t7; + uint16_t t9; + uint16_t t10; + uint16_t t12; +} __attribute__ ((packed)); + +struct edp_link_params { + uint8_t rate:4; + uint8_t lanes:4; + uint8_t preemphasis:4; + uint8_t vswing:4; +} __attribute__ ((packed)); + +struct bdb_edp { + struct edp_power_seq power_seqs[16]; + uint32_t color_depth; + uint32_t sdrrs_msa_timing_delay; + struct edp_link_params link_params[16]; +} __attribute__ ((packed)); + +/* + * Driver<->VBIOS interaction occurs through scratch bits in + * GR18 & SWF*. + * + * The VBIOS/firmware will signal to the gfx driver through the ASLE interrupt + * (visible in the interupt regs at bit 0) when it wants something done. + * + * Pre-965: + * The gfx driver can make calls to the VBIOS/firmware through an SMI request, + * generated by writing to offset 0xe0 of the device's config space (see the + * publically available 915 PRM for details). + * + * 965 and above: + * IGD OpRegion requests to the VBIOS/firmware are made using SWSCI, which can + * be triggered by writing to offset 0xe4 (see the publically available + * 965 graphics PRM for details). + */ + +/* GR18 bits are set on display switch and hotkey events */ +#define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */ +#define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */ +#define GR18_HK_NONE (0x0<<3) +#define GR18_HK_LFP_STRETCH (0x1<<3) +#define GR18_HK_TOGGLE_DISP (0x2<<3) +#define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */ +#define GR18_HK_POPUP_DISABLED (0x6<<3) +#define GR18_HK_POPUP_ENABLED (0x7<<3) +#define GR18_HK_PFIT (0x8<<3) +#define GR18_HK_APM_CHANGE (0xa<<3) +#define GR18_HK_MULTIPLE (0xc<<3) +#define GR18_USER_INT_EN (1<<2) +#define GR18_A0000_FLUSH_EN (1<<1) +#define GR18_SMM_EN (1<<0) + +/* Set by driver, cleared by VBIOS */ +#define SWF00_YRES_SHIFT 16 +#define SWF00_XRES_SHIFT 0 +#define SWF00_RES_MASK 0xffff + +/* Set by VBIOS at boot time and driver at runtime */ +#define SWF01_TV2_FORMAT_SHIFT 8 +#define SWF01_TV1_FORMAT_SHIFT 0 +#define SWF01_TV_FORMAT_MASK 0xffff + +#define SWF10_VBIOS_BLC_I2C_EN (1<<29) +#define SWF10_GTT_OVERRIDE_EN (1<<28) +#define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */ +#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24) +#define SWF10_OLD_TOGGLE 0x0 +#define SWF10_TOGGLE_LIST_1 0x1 +#define SWF10_TOGGLE_LIST_2 0x2 +#define SWF10_TOGGLE_LIST_3 0x3 +#define SWF10_TOGGLE_LIST_4 0x4 +#define SWF10_PANNING_EN (1<<23) +#define SWF10_DRIVER_LOADED (1<<22) +#define SWF10_EXTENDED_DESKTOP (1<<21) +#define SWF10_EXCLUSIVE_MODE (1<<20) +#define SWF10_OVERLAY_EN (1<<19) +#define SWF10_PLANEB_HOLDOFF (1<<18) +#define SWF10_PLANEA_HOLDOFF (1<<17) +#define SWF10_VGA_HOLDOFF (1<<16) +#define SWF10_ACTIVE_DISP_MASK 0xffff +#define SWF10_PIPEB_LFP2 (1<<15) +#define SWF10_PIPEB_EFP2 (1<<14) +#define SWF10_PIPEB_TV2 (1<<13) +#define SWF10_PIPEB_CRT2 (1<<12) +#define SWF10_PIPEB_LFP (1<<11) +#define SWF10_PIPEB_EFP (1<<10) +#define SWF10_PIPEB_TV (1<<9) +#define SWF10_PIPEB_CRT (1<<8) +#define SWF10_PIPEA_LFP2 (1<<7) +#define SWF10_PIPEA_EFP2 (1<<6) +#define SWF10_PIPEA_TV2 (1<<5) +#define SWF10_PIPEA_CRT2 (1<<4) +#define SWF10_PIPEA_LFP (1<<3) +#define SWF10_PIPEA_EFP (1<<2) +#define SWF10_PIPEA_TV (1<<1) +#define SWF10_PIPEA_CRT (1<<0) + +#define SWF11_MEMORY_SIZE_SHIFT 16 +#define SWF11_SV_TEST_EN (1<<15) +#define SWF11_IS_AGP (1<<14) +#define SWF11_DISPLAY_HOLDOFF (1<<13) +#define SWF11_DPMS_REDUCED (1<<12) +#define SWF11_IS_VBE_MODE (1<<11) +#define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */ +#define SWF11_DPMS_MASK 0x07 +#define SWF11_DPMS_OFF (1<<2) +#define SWF11_DPMS_SUSPEND (1<<1) +#define SWF11_DPMS_STANDBY (1<<0) +#define SWF11_DPMS_ON 0 + +#define SWF14_GFX_PFIT_EN (1<<31) +#define SWF14_TEXT_PFIT_EN (1<<30) +#define SWF14_LID_SWITCH_EN (1<<29) +#define SWF14_POPUP_EN (1<<28) +#define SWF14_DISPLAY_HOLDOFF (1<<27) +#define SWF14_DISP_DETECT_EN (1<<26) +#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */ +#define SWF14_DRIVER_STATUS (1<<24) +#define SWF14_OS_TYPE_WIN9X (1<<23) +#define SWF14_OS_TYPE_WINNT (1<<22) +/* 21:19 rsvd */ +#define SWF14_PM_TYPE_MASK 0x00070000 +#define SWF14_PM_ACPI_VIDEO (0x4 << 16) +#define SWF14_PM_ACPI (0x3 << 16) +#define SWF14_PM_APM_12 (0x2 << 16) +#define SWF14_PM_APM_11 (0x1 << 16) +#define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */ + /* if GR18 indicates a display switch */ +#define SWF14_DS_PIPEB_LFP2_EN (1<<15) +#define SWF14_DS_PIPEB_EFP2_EN (1<<14) +#define SWF14_DS_PIPEB_TV2_EN (1<<13) +#define SWF14_DS_PIPEB_CRT2_EN (1<<12) +#define SWF14_DS_PIPEB_LFP_EN (1<<11) +#define SWF14_DS_PIPEB_EFP_EN (1<<10) +#define SWF14_DS_PIPEB_TV_EN (1<<9) +#define SWF14_DS_PIPEB_CRT_EN (1<<8) +#define SWF14_DS_PIPEA_LFP2_EN (1<<7) +#define SWF14_DS_PIPEA_EFP2_EN (1<<6) +#define SWF14_DS_PIPEA_TV2_EN (1<<5) +#define SWF14_DS_PIPEA_CRT2_EN (1<<4) +#define SWF14_DS_PIPEA_LFP_EN (1<<3) +#define SWF14_DS_PIPEA_EFP_EN (1<<2) +#define SWF14_DS_PIPEA_TV_EN (1<<1) +#define SWF14_DS_PIPEA_CRT_EN (1<<0) + /* if GR18 indicates a panel fitting request */ +#define SWF14_PFIT_EN (1<<0) /* 0 means disable */ + /* if GR18 indicates an APM change request */ +#define SWF14_APM_HIBERNATE 0x4 +#define SWF14_APM_SUSPEND 0x3 +#define SWF14_APM_STANDBY 0x1 +#define SWF14_APM_RESTORE 0x0 + +#endif /* _INTEL_BIOS_H_ */ diff --git a/tools/intel_bios_dumper.c b/tools/intel_bios_dumper.c new file mode 100644 index 00000000..6455689f --- /dev/null +++ b/tools/intel_bios_dumper.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2007 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <pciaccess.h> +#include <err.h> + +#ifndef DEFFILEMODE +#define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /* 0666 */ +#endif + +static void usage(void) +{ + fprintf(stderr, "usage: bios_dumper <filename>\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + struct pci_device *dev; + void *bios; + int error, fd; + + if (argc != 2) + usage(); + + error = pci_system_init(); + if (error != 0) { + fprintf(stderr, "Couldn't initialize PCI system: %s\n", + strerror(error)); + exit(1); + } + + /* Grab the graphics card */ + dev = pci_device_find_by_slot(0, 0, 2, 0); + if (dev == NULL) + errx(1, "Couldn't find graphics card"); + + error = pci_device_probe(dev); + if (error != 0) { + fprintf(stderr, "Couldn't probe graphics card: %s\n", + strerror(error)); + exit(1); + } + + if (dev->vendor_id != 0x8086) + errx(1, "Graphics card is non-intel"); + + /* Some versions of libpciaccess correct this automatically, but some + * don't. */ + if (dev->rom_size == 0) + dev->rom_size = 64 * 1024; + + bios = malloc(dev->rom_size); + if (bios == NULL) + errx(1, "Couldn't allocate memory for BIOS data\n"); + + error = pci_device_read_rom(dev, bios); + if (error != 0) { + fprintf(stderr, "Couldn't read graphics card ROM: %s\n", + strerror(error)); + exit(1); + } + + fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, DEFFILEMODE); + if (fd < 0) { + fprintf(stderr, "Couldn't open output: %s\n", strerror(errno)); + exit(1); + } + + if (write(fd, bios, dev->rom_size) < dev->rom_size) { + fprintf(stderr, "Couldn't write BIOS data: %s\n", + strerror(errno)); + exit(1); + } + + close(fd); + pci_system_cleanup(); + + return 0; +} diff --git a/tools/intel_bios_reader.c b/tools/intel_bios_reader.c new file mode 100644 index 00000000..493fb637 --- /dev/null +++ b/tools/intel_bios_reader.c @@ -0,0 +1,947 @@ +/* + * Copyright 2006 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 <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "intel_bios.h" +#include "intel_gpu_tools.h" + +static uint32_t devid = -1; + +/* no bother to include "edid.h" */ +#define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4)) +#define _H_SYNC_OFF(x) (x[8] + ((x[11] & 0xC0) << 2)) +#define _H_SYNC_WIDTH(x) (x[9] + ((x[11] & 0x30) << 4)) +#define _H_BLANK(x) (x[3] + ((x[4] & 0x0F) << 8)) +#define _V_ACTIVE(x) (x[5] + ((x[7] & 0xF0) << 4)) +#define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2)) +#define _V_SYNC_WIDTH(x) ((x[10] & 0x0F) + ((x[11] & 0x03) << 4)) +#define _V_BLANK(x) (x[6] + ((x[7] & 0x0F) << 8)) +#define _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000 + +uint8_t *VBIOS; + +#define INTEL_BIOS_8(_addr) (VBIOS[_addr]) +#define INTEL_BIOS_16(_addr) (VBIOS[_addr] | \ + (VBIOS[_addr + 1] << 8)) +#define INTEL_BIOS_32(_addr) (VBIOS[_addr] | \ + (VBIOS[_addr + 1] << 8) | \ + (VBIOS[_addr + 2] << 16) | \ + (VBIOS[_addr + 3] << 24)) + +#define YESNO(val) ((val) ? "yes" : "no") + +struct bdb_block { + uint8_t id; + uint16_t size; + void *data; +}; + +struct bdb_header *bdb; +static int tv_present; +static int lvds_present; +static int panel_type; + +static struct bdb_block *find_section(int section_id, int length) +{ + struct bdb_block *block; + unsigned char *base = (unsigned char *)bdb; + int idx = 0; + uint16_t total, current_size; + unsigned char current_id; + + /* skip to first section */ + idx += bdb->header_size; + total = bdb->bdb_size; + if (total > length) + total = length; + + block = malloc(sizeof(*block)); + if (!block) { + fprintf(stderr, "out of memory\n"); + exit(-1); + } + + /* walk the sections looking for section_id */ + while (idx + 3 < total) { + current_id = *(base + idx); + current_size = *(uint16_t *)(base + idx + 1); + if (idx + current_size > total) + return NULL; + + if (current_id == section_id) { + block->id = current_id; + block->size = current_size; + block->data = base + idx + 3; + return block; + } + + idx += current_size + 3; + } + + free(block); + return NULL; +} + +static void dump_general_features(int length) +{ + struct bdb_general_features *features; + struct bdb_block *block; + + block = find_section(BDB_GENERAL_FEATURES, length); + + if (!block) + return; + + features = block->data; + + printf("General features block:\n"); + + printf("\tPanel fitting: "); + switch (features->panel_fitting) { + case 0: + printf("disabled\n"); + break; + case 1: + printf("text only\n"); + break; + case 2: + printf("graphics only\n"); + break; + case 3: + printf("text & graphics\n"); + break; + } + printf("\tFlexaim: %s\n", YESNO(features->flexaim)); + printf("\tMessage: %s\n", YESNO(features->msg_enable)); + printf("\tClear screen: %d\n", features->clear_screen); + printf("\tDVO color flip required: %s\n", YESNO(features->color_flip)); + printf("\tExternal VBT: %s\n", YESNO(features->download_ext_vbt)); + printf("\tEnable SSC: %s\n", YESNO(features->enable_ssc)); + if (features->enable_ssc) { + if (HAS_PCH_SPLIT(devid)) + printf("\tSSC frequency: %s\n", features->ssc_freq ? + "100 MHz" : "120 MHz"); + else + printf("\tSSC frequency: %s\n", features->ssc_freq ? + "100 MHz (66 MHz on 855)" : "96 MHz (48 MHz on 855)"); + } + printf("\tLFP on override: %s\n", + YESNO(features->enable_lfp_on_override)); + printf("\tDisable SSC on clone: %s\n", + YESNO(features->disable_ssc_ddt)); + printf("\tDisable smooth vision: %s\n", + YESNO(features->disable_smooth_vision)); + printf("\tSingle DVI for CRT/DVI: %s\n", YESNO(features->single_dvi)); + printf("\tLegacy monitor detect: %s\n", + YESNO(features->legacy_monitor_detect)); + printf("\tIntegrated CRT: %s\n", YESNO(features->int_crt_support)); + printf("\tIntegrated TV: %s\n", YESNO(features->int_tv_support)); + + tv_present = 1; /* should be based on whether TV DAC exists */ + lvds_present = 1; /* should be based on IS_MOBILE() */ + + free(block); +} + +static void dump_backlight_info(int length) +{ + struct bdb_block *block; + struct bdb_lvds_backlight *backlight; + struct blc_struct *blc; + + block = find_section(BDB_LVDS_BACKLIGHT, length); + + if (!block) + return; + + backlight = block->data; + + printf("Backlight info block (len %d):\n", block->size); + + if (sizeof(struct blc_struct) != backlight->blcstruct_size) { + printf("\tBacklight struct sizes don't match (expected %zu, got %u), skipping\n", + sizeof(struct blc_struct), backlight->blcstruct_size); + return; + } + + blc = &backlight->panels[panel_type]; + + printf("\tInverter type: %d\n", blc->inverter_type); + printf("\t polarity: %d\n", blc->inverter_polarity); + printf("\t GPIO pins: %d\n", blc->gpio_pins); + printf("\t GMBUS speed: %d\n", blc->gmbus_speed); + printf("\t PWM freq: %d\n", blc->pwm_freq); + printf("\tMinimum brightness: %d\n", blc->min_brightness); + printf("\tI2C slave addr: 0x%02x\n", blc->i2c_slave_addr); + printf("\tI2C command: 0x%02x\n", blc->i2c_cmd); +} + +static const struct { + unsigned short type; + const char *name; +} child_device_types[] = { + { DEVICE_TYPE_NONE, "none" }, + { DEVICE_TYPE_CRT, "CRT" }, + { DEVICE_TYPE_TV, "TV" }, + { DEVICE_TYPE_EFP, "EFP" }, + { DEVICE_TYPE_LFP, "LFP" }, + { DEVICE_TYPE_CRT_DPMS, "CRT" }, + { DEVICE_TYPE_CRT_DPMS_HOTPLUG, "CRT" }, + { DEVICE_TYPE_TV_COMPOSITE, "TV composite" }, + { DEVICE_TYPE_TV_MACROVISION, "TV" }, + { DEVICE_TYPE_TV_RF_COMPOSITE, "TV" }, + { DEVICE_TYPE_TV_SVIDEO_COMPOSITE, "TV S-Video" }, + { DEVICE_TYPE_TV_SCART, "TV SCART" }, + { DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR, "TV" }, + { DEVICE_TYPE_EFP_HOTPLUG_PWR, "EFP" }, + { DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR, "DVI" }, + { DEVICE_TYPE_EFP_DVI_I, "DVI-I" }, + { DEVICE_TYPE_EFP_DVI_D_DUAL, "DL-DVI-D" }, + { DEVICE_TYPE_EFP_DVI_D_HDCP, "DVI-D" }, + { DEVICE_TYPE_OPENLDI_HOTPLUG_PWR, "OpenLDI" }, + { DEVICE_TYPE_OPENLDI_DUALPIX, "OpenLDI" }, + { DEVICE_TYPE_LFP_PANELLINK, "PanelLink" }, + { DEVICE_TYPE_LFP_CMOS_PWR, "CMOS LFP" }, + { DEVICE_TYPE_LFP_LVDS_PWR, "LVDS" }, + { DEVICE_TYPE_LFP_LVDS_DUAL, "LVDS" }, + { DEVICE_TYPE_LFP_LVDS_DUAL_HDCP, "LVDS" }, + { DEVICE_TYPE_INT_LFP, "LFP" }, + { DEVICE_TYPE_INT_TV, "TV" }, + { DEVICE_TYPE_DP, "DisplayPort" }, + { DEVICE_TYPE_DP_HDMI_DVI, "DisplayPort/HDMI/DVI" }, + { DEVICE_TYPE_DP_DVI, "DisplayPort/DVI" }, + { DEVICE_TYPE_HDMI_DVI, "HDMI/DVI" }, + { DEVICE_TYPE_DVI, "DVI" }, + { DEVICE_TYPE_eDP, "eDP" }, +}; +static const int num_child_device_types = + sizeof(child_device_types) / sizeof(child_device_types[0]); + +static const char *child_device_type(unsigned short type) +{ + int i; + + for (i = 0; i < num_child_device_types; i++) + if (child_device_types[i].type == type) + return child_device_types[i].name; + + return "unknown"; +} + +static const struct { + unsigned short type; + const char *name; +} efp_ports[] = { + { DEVICE_PORT_NONE, "N/A" }, + { DEVICE_PORT_HDMIB, "HDMI-B" }, + { DEVICE_PORT_HDMIC, "HDMI-C" }, + { DEVICE_PORT_HDMID, "HDMI-D" }, + { DEVICE_PORT_DPB, "DP-B" }, + { DEVICE_PORT_DPC, "DP-C" }, + { DEVICE_PORT_DPD, "DP-D" }, +}; +static const int num_efp_ports = sizeof(efp_ports) / sizeof(efp_ports[0]); + +static const char *efp_port(uint8_t type) +{ + int i; + + for (i = 0; i < num_efp_ports; i++) + if (efp_ports[i].type == type) + return efp_ports[i].name; + + return "unknown"; +} + +static const struct { + unsigned short type; + const char *name; +} efp_conn_info[] = { + { DEVICE_INFO_NONE, "N/A" }, + { DEVICE_INFO_HDMI_CERT, "HDMI certified" }, + { DEVICE_INFO_DP, "DisplayPort" }, + { DEVICE_INFO_DVI, "DVI" }, +}; +static const int num_efp_conn_info = sizeof(efp_conn_info) / sizeof(efp_conn_info[0]); + +static const char *efp_conn(uint8_t type) +{ + int i; + + for (i = 0; i < num_efp_conn_info; i++) + if (efp_conn_info[i].type == type) + return efp_conn_info[i].name; + + return "unknown"; +} + + + +static void dump_child_device(struct child_device_config *child) +{ + char child_id[11]; + + if (!child->device_type) + return; + + if (bdb->version < 152) { + strncpy(child_id, (char *)child->device_id, 10); + child_id[10] = 0; + + printf("\tChild device info:\n"); + printf("\t\tDevice type: %04x (%s)\n", child->device_type, + child_device_type(child->device_type)); + printf("\t\tSignature: %s\n", child_id); + printf("\t\tAIM offset: %d\n", child->addin_offset); + printf("\t\tDVO port: 0x%02x\n", child->dvo_port); + } else { /* 152+ have EFP blocks here */ + struct efp_child_device_config *efp = + (struct efp_child_device_config *)child; + printf("\tEFP device info:\n"); + printf("\t\tDevice type: 0x%04x (%s)\n", efp->device_type, + child_device_type(efp->device_type)); + printf("\t\tPort: 0x%02x (%s)\n", efp->port, + efp_port(efp->port)); + printf("\t\tDDC pin: 0x%02x\n", efp->ddc_pin); + printf("\t\tDock port: 0x%02x (%s)\n", efp->docked_port, + efp_port(efp->docked_port)); + printf("\t\tHDMI compatible? %s\n", efp->hdmi_compat ? "Yes" : "No"); + printf("\t\tInfo: %s\n", efp_conn(efp->conn_info)); + printf("\t\tAux channel: 0x%02x\n", efp->aux_chan); + printf("\t\tDongle detect: 0x%02x\n", efp->dongle_detect); + } +} + +static void dump_general_definitions(int length) +{ + struct bdb_block *block; + struct bdb_general_definitions *defs; + struct child_device_config *child; + int i; + int child_device_num; + + block = find_section(BDB_GENERAL_DEFINITIONS, length); + + if (!block) + return; + + defs = block->data; + + printf("General definitions block:\n"); + + printf("\tCRT DDC GMBUS addr: 0x%02x\n", defs->crt_ddc_gmbus_pin); + printf("\tUse ACPI DPMS CRT power states: %s\n", + YESNO(defs->dpms_acpi)); + printf("\tSkip CRT detect at boot: %s\n", + YESNO(defs->skip_boot_crt_detect)); + printf("\tUse DPMS on AIM devices: %s\n", YESNO(defs->dpms_aim)); + printf("\tBoot display type: 0x%02x%02x\n", defs->boot_display[1], + defs->boot_display[0]); + printf("\tTV data block present: %s\n", YESNO(tv_present)); + child_device_num = (block->size - sizeof(*defs)) / sizeof(*child); + for (i = 0; i < child_device_num; i++) + dump_child_device(&defs->devices[i]); + free(block); +} + +static void dump_child_devices(int length) +{ + struct bdb_block *block; + struct bdb_child_devices *child_devs; + struct child_device_config *child; + int i; + + block = find_section(BDB_CHILD_DEVICE_TABLE, length); + if (!block) { + printf("No child device table found\n"); + return; + } + + child_devs = block->data; + + printf("Child devices block:\n"); + for (i = 0; i < DEVICE_CHILD_SIZE; i++) { + child = &child_devs->children[i]; + /* Skip nonexistent children */ + if (!child->device_type) + continue; + printf("\tChild device %d\n", i); + printf("\t\tType: 0x%04x (%s)\n", child->device_type, + child_device_type(child->device_type)); + printf("\t\tDVO port: 0x%02x\n", child->dvo_port); + printf("\t\tI2C pin: 0x%02x\n", child->i2c_pin); + printf("\t\tSlave addr: 0x%02x\n", child->slave_addr); + printf("\t\tDDC pin: 0x%02x\n", child->ddc_pin); + printf("\t\tDVO config: 0x%02x\n", child->dvo_cfg); + printf("\t\tDVO wiring: 0x%02x\n", child->dvo_wiring); + } + + free(block); +} + +static void dump_lvds_options(int length) +{ + struct bdb_block *block; + struct bdb_lvds_options *options; + + block = find_section(BDB_LVDS_OPTIONS, length); + if (!block) { + printf("No LVDS options block\n"); + return; + } + + options = block->data; + + printf("LVDS options block:\n"); + + panel_type = options->panel_type; + printf("\tPanel type: %d\n", panel_type); + printf("\tLVDS EDID available: %s\n", YESNO(options->lvds_edid)); + printf("\tPixel dither: %s\n", YESNO(options->pixel_dither)); + printf("\tPFIT auto ratio: %s\n", YESNO(options->pfit_ratio_auto)); + printf("\tPFIT enhanced graphics mode: %s\n", + YESNO(options->pfit_gfx_mode_enhanced)); + printf("\tPFIT enhanced text mode: %s\n", + YESNO(options->pfit_text_mode_enhanced)); + printf("\tPFIT mode: %d\n", options->pfit_mode); + + free(block); +} + +static void dump_lvds_ptr_data(int length) +{ + struct bdb_block *block; + struct bdb_lvds_lfp_data *lvds_data; + struct bdb_lvds_lfp_data_ptrs *ptrs; + struct lvds_fp_timing *fp_timing; + struct bdb_lvds_lfp_data_entry *entry; + int lfp_data_size; + + block = find_section(BDB_LVDS_LFP_DATA_PTRS, length); + if (!block) { + printf("No LFP data pointers block\n"); + return; + } + ptrs = block->data; + + block = find_section(BDB_LVDS_LFP_DATA, length); + if (!block) { + printf("No LVDS data block\n"); + return; + } + lvds_data = block->data; + + lfp_data_size = + ptrs->ptr[1].fp_timing_offset - ptrs->ptr[0].fp_timing_offset; + entry = + (struct bdb_lvds_lfp_data_entry *)((uint8_t *) lvds_data->data + + (lfp_data_size * panel_type)); + fp_timing = &entry->fp_timing; + + printf("LVDS timing pointer data:\n"); + printf(" Number of entries: %d\n", ptrs->lvds_entries); + + printf("\tpanel type %02i: %dx%d\n", panel_type, fp_timing->x_res, + fp_timing->y_res); + + free(block); +} + +static void dump_lvds_data(int length) +{ + struct bdb_block *block; + struct bdb_lvds_lfp_data *lvds_data; + struct bdb_lvds_lfp_data_ptrs *ptrs; + int num_entries; + int i; + int hdisplay, hsyncstart, hsyncend, htotal; + int vdisplay, vsyncstart, vsyncend, vtotal; + float clock; + int lfp_data_size, dvo_offset; + + block = find_section(BDB_LVDS_LFP_DATA_PTRS, length); + if (!block) { + printf("No LVDS ptr block\n"); + return; + } + ptrs = block->data; + lfp_data_size = + ptrs->ptr[1].fp_timing_offset - ptrs->ptr[0].fp_timing_offset; + dvo_offset = + ptrs->ptr[0].dvo_timing_offset - ptrs->ptr[0].fp_timing_offset; + free(block); + + block = find_section(BDB_LVDS_LFP_DATA, length); + if (!block) { + printf("No LVDS data block\n"); + return; + } + + lvds_data = block->data; + num_entries = block->size / lfp_data_size; + + printf("LVDS panel data block (preferred block marked with '*'):\n"); + printf(" Number of entries: %d\n", num_entries); + + for (i = 0; i < num_entries; i++) { + uint8_t *lfp_data_ptr = + (uint8_t *) lvds_data->data + lfp_data_size * i; + uint8_t *timing_data = lfp_data_ptr + dvo_offset; + struct bdb_lvds_lfp_data_entry *lfp_data = + (struct bdb_lvds_lfp_data_entry *)lfp_data_ptr; + char marker; + + if (i == panel_type) + marker = '*'; + else + marker = ' '; + + hdisplay = _H_ACTIVE(timing_data); + hsyncstart = hdisplay + _H_SYNC_OFF(timing_data); + hsyncend = hsyncstart + _H_SYNC_WIDTH(timing_data); + htotal = hdisplay + _H_BLANK(timing_data); + + vdisplay = _V_ACTIVE(timing_data); + vsyncstart = vdisplay + _V_SYNC_OFF(timing_data); + vsyncend = vsyncstart + _V_SYNC_WIDTH(timing_data); + vtotal = vdisplay + _V_BLANK(timing_data); + clock = _PIXEL_CLOCK(timing_data) / 1000; + + printf("%c\tpanel type %02i: %dx%d clock %d\n", marker, + i, lfp_data->fp_timing.x_res, lfp_data->fp_timing.y_res, + _PIXEL_CLOCK(timing_data)); + printf("\t\tinfo:\n"); + printf("\t\t LVDS: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.lvds_reg_val); + printf("\t\t PP_ON_DELAYS: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.pp_on_reg_val); + printf("\t\t PP_OFF_DELAYS: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.pp_off_reg_val); + printf("\t\t PP_DIVISOR: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.pp_cycle_reg_val); + printf("\t\t PFIT: 0x%08lx\n", + (unsigned long)lfp_data->fp_timing.pfit_reg_val); + printf("\t\ttimings: %d %d %d %d %d %d %d %d %.2f (%s)\n", + hdisplay, hsyncstart, hsyncend, htotal, + vdisplay, vsyncstart, vsyncend, vtotal, clock, + (hsyncend > htotal || vsyncend > vtotal) ? + "BAD!" : "good"); + } + free(block); +} + +static void dump_driver_feature(int length) +{ + struct bdb_block *block; + struct bdb_driver_feature *feature; + + block = find_section(BDB_DRIVER_FEATURES, length); + if (!block) { + printf("No Driver feature data block\n"); + return; + } + feature = block->data; + + printf("Driver feature Data Block:\n"); + printf("\tBoot Device Algorithm: %s\n", feature->boot_dev_algorithm ? + "driver default" : "os default"); + printf("\tBlock display switching when DVD active: %s\n", + YESNO(feature->block_display_switch)); + printf("\tAllow display switching when in Full Screen DOS: %s\n", + YESNO(feature->allow_display_switch)); + printf("\tHot Plug DVO: %s\n", YESNO(feature->hotplug_dvo)); + printf("\tDual View Zoom: %s\n", YESNO(feature->dual_view_zoom)); + printf("\tDriver INT 15h hook: %s\n", YESNO(feature->int15h_hook)); + printf("\tEnable Sprite in Clone Mode: %s\n", + YESNO(feature->sprite_in_clone)); + printf("\tUse 00000110h ID for Primary LFP: %s\n", + YESNO(feature->primary_lfp_id)); + printf("\tBoot Mode X: %u\n", feature->boot_mode_x); + printf("\tBoot Mode Y: %u\n", feature->boot_mode_y); + printf("\tBoot Mode Bpp: %u\n", feature->boot_mode_bpp); + printf("\tBoot Mode Refresh: %u\n", feature->boot_mode_refresh); + printf("\tEnable LFP as primary: %s\n", + YESNO(feature->enable_lfp_primary)); + printf("\tSelective Mode Pruning: %s\n", + YESNO(feature->selective_mode_pruning)); + printf("\tDual-Frequency Graphics Technology: %s\n", + YESNO(feature->dual_frequency)); + printf("\tDefault Render Clock Frequency: %s\n", + feature->render_clock_freq ? "low" : "high"); + printf("\tNT 4.0 Dual Display Clone Support: %s\n", + YESNO(feature->nt_clone_support)); + printf("\tDefault Power Scheme user interface: %s\n", + feature->power_scheme_ui ? "3rd party" : "CUI"); + printf + ("\tSprite Display Assignment when Overlay is Active in Clone Mode: %s\n", + feature->sprite_display_assign ? "primary" : "secondary"); + printf("\tDisplay Maintain Aspect Scaling via CUI: %s\n", + YESNO(feature->cui_aspect_scaling)); + printf("\tPreserve Aspect Ratio: %s\n", + YESNO(feature->preserve_aspect_ratio)); + printf("\tEnable SDVO device power down: %s\n", + YESNO(feature->sdvo_device_power_down)); + printf("\tCRT hotplug: %s\n", YESNO(feature->crt_hotplug)); + printf("\tLVDS config: "); + switch (feature->lvds_config) { + case BDB_DRIVER_NO_LVDS: + printf("No LVDS\n"); + break; + case BDB_DRIVER_INT_LVDS: + printf("Integrated LVDS\n"); + break; + case BDB_DRIVER_SDVO_LVDS: + printf("SDVO LVDS\n"); + break; + case BDB_DRIVER_EDP: + printf("Embedded DisplayPort\n"); + break; + } + printf("\tDefine Display statically: %s\n", + YESNO(feature->static_display)); + printf("\tLegacy CRT max X: %d\n", feature->legacy_crt_max_x); + printf("\tLegacy CRT max Y: %d\n", feature->legacy_crt_max_y); + printf("\tLegacy CRT max refresh: %d\n", + feature->legacy_crt_max_refresh); + free(block); +} + +static void dump_edp(int length) +{ + struct bdb_block *block; + struct bdb_edp *edp; + int bpp; + + block = find_section(BDB_EDP, length); + if (!block) { + printf("No EDP data block\n"); + return; + } + edp = block->data; + + printf("eDP block: type %d\n", panel_type); + printf("\tPower Sequence: T3 %d T7 %d T9 %d T10 %d T12 %d\n", + edp->power_seqs[panel_type].t3, + edp->power_seqs[panel_type].t7, + edp->power_seqs[panel_type].t9, + edp->power_seqs[panel_type].t10, + edp->power_seqs[panel_type].t12); + + bpp = (edp->color_depth >> (panel_type * 2)) & 3; + + printf("\tPanel color depth: "); + switch (bpp) { + case EDP_18BPP: + printf("18bpp\n"); + break; + case EDP_24BPP: + printf("24bpp\n"); + break; + case EDP_30BPP: + printf("30bpp\n"); + break; + } + printf("\teDP sDRRs MSA timing delay: %d\n", edp->sdrrs_msa_timing_delay); + printf("\tLink params:\n"); + printf("\t\trate: "); + if (edp->link_params[panel_type].rate == EDP_RATE_1_62) + printf("1.62G\n"); + else if (edp->link_params[panel_type].rate == EDP_RATE_2_7) + printf("2.7G\n"); + printf("\t\tlanes: "); + switch (edp->link_params[panel_type].lanes) { + case EDP_LANE_1: + printf("x1 mode\n"); + break; + case EDP_LANE_2: + printf("x2 mode\n"); + break; + case EDP_LANE_4: + printf("x4 mode\n"); + break; + } + printf("\t\tpre-emphasis: "); + switch (edp->link_params[panel_type].preemphasis) { + case EDP_PREEMPHASIS_NONE: + printf("none\n"); + break; + case EDP_PREEMPHASIS_3_5dB: + printf("3.5dB\n"); + break; + case EDP_PREEMPHASIS_6dB: + printf("6dB\n"); + break; + case EDP_PREEMPHASIS_9_5dB: + printf("9.5dB\n"); + break; + } + printf("\t\tvswing: "); + switch (edp->link_params[panel_type].vswing) { + case EDP_VSWING_0_4V: + printf("0.4V\n"); + break; + case EDP_VSWING_0_6V: + printf("0.6V\n"); + break; + case EDP_VSWING_0_8V: + printf("0.8V\n"); + break; + case EDP_VSWING_1_2V: + printf("1.2V\n"); + break; + } + free(block); +} + +static void +print_detail_timing_data(struct lvds_dvo_timing2 *dvo_timing) +{ + int display, sync_start, sync_end, total; + + display = (dvo_timing->hactive_hi << 8) | dvo_timing->hactive_lo; + sync_start = display + + ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); + sync_end = sync_start + dvo_timing->hsync_pulse_width; + total = display + + ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); + printf("\thdisplay: %d\n", display); + printf("\thsync [%d, %d] %s\n", sync_start, sync_end, + dvo_timing->hsync_positive ? "+sync" : "-sync"); + printf("\thtotal: %d\n", total); + + display = (dvo_timing->vactive_hi << 8) | dvo_timing->vactive_lo; + sync_start = display + dvo_timing->vsync_off; + sync_end = sync_start + dvo_timing->vsync_pulse_width; + total = display + + ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); + printf("\tvdisplay: %d\n", display); + printf("\tvsync [%d, %d] %s\n", sync_start, sync_end, + dvo_timing->vsync_positive ? "+sync" : "-sync"); + printf("\tvtotal: %d\n", total); + + printf("\tclock: %d\n", dvo_timing->clock * 10); +} + +static void dump_sdvo_panel_dtds(int length) +{ + struct bdb_block *block; + struct lvds_dvo_timing2 *dvo_timing; + int n, count; + + block = find_section(BDB_SDVO_PANEL_DTDS, length); + if (!block) { + printf("No SDVO panel dtds block\n"); + return; + } + + printf("SDVO panel dtds:\n"); + count = block->size / sizeof(struct lvds_dvo_timing2); + dvo_timing = block->data; + for (n = 0; n < count; n++) { + printf("%d:\n", n); + print_detail_timing_data(dvo_timing++); + } + + free(block); +} + +static void dump_sdvo_lvds_options(int length) +{ + struct bdb_block *block; + struct bdb_sdvo_lvds_options *options; + + block = find_section(BDB_SDVO_LVDS_OPTIONS, length); + if (!block) { + printf("No SDVO LVDS options block\n"); + return; + } + + options = block->data; + + printf("SDVO LVDS options block:\n"); + printf("\tbacklight: %d\n", options->panel_backlight); + printf("\th40 type: %d\n", options->h40_set_panel_type); + printf("\ttype: %d\n", options->panel_type); + printf("\tssc_clk_freq: %d\n", options->ssc_clk_freq); + printf("\tals_low_trip: %d\n", options->als_low_trip); + printf("\tals_high_trip: %d\n", options->als_high_trip); + /* + u8 sclalarcoeff_tab_row_num; + u8 sclalarcoeff_tab_row_size; + u8 coefficient[8]; + */ + printf("\tmisc[0]: %x\n", options->panel_misc_bits_1); + printf("\tmisc[1]: %x\n", options->panel_misc_bits_2); + printf("\tmisc[2]: %x\n", options->panel_misc_bits_3); + printf("\tmisc[3]: %x\n", options->panel_misc_bits_4); + + free(block); +} + +static int +get_device_id(unsigned char *bios) +{ + int device; + int offset = (bios[0x19] << 8) + bios[0x18]; + + if (bios[offset] != 'P' || + bios[offset+1] != 'C' || + bios[offset+2] != 'I' || + bios[offset+3] != 'R') + return -1; + + device = (bios[offset+7] << 8) + bios[offset+6]; + + return device; +} + +int main(int argc, char **argv) +{ + int fd; + struct vbt_header *vbt = NULL; + int vbt_off, bdb_off, i; + const char *filename = "bios"; + struct stat finfo; + struct bdb_block *block; + char signature[17]; + char *devid_string; + + if (argc != 2) { + printf("usage: %s <rom file>\n", argv[0]); + return 1; + } + + if ((devid_string = getenv("DEVICE"))) + devid = strtoul(devid_string, NULL, 0); + + filename = argv[1]; + + fd = open(filename, O_RDONLY); + if (fd == -1) { + printf("Couldn't open \"%s\": %s\n", filename, strerror(errno)); + return 1; + } + + if (stat(filename, &finfo)) { + printf("failed to stat \"%s\": %s\n", filename, + strerror(errno)); + return 1; + } + + if (finfo.st_size == 0) { + int len = 0, ret; + finfo.st_size = 8192; + VBIOS = malloc (finfo.st_size); + while ((ret = read(fd, VBIOS + len, finfo.st_size - len))) { + if (ret < 0) { + printf("failed to read \"%s\": %s\n", filename, + strerror(errno)); + return 1; + } + + len += ret; + if (len == finfo.st_size) { + finfo.st_size *= 2; + VBIOS = realloc(VBIOS, finfo.st_size); + } + } + } else { + VBIOS = mmap(NULL, finfo.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (VBIOS == MAP_FAILED) { + printf("failed to map \"%s\": %s\n", filename, strerror(errno)); + return 1; + } + } + + /* Scour memory looking for the VBT signature */ + for (i = 0; i + 4 < finfo.st_size; i++) { + if (!memcmp(VBIOS + i, "$VBT", 4)) { + vbt_off = i; + vbt = (struct vbt_header *)(VBIOS + i); + break; + } + } + + if (!vbt) { + printf("VBT signature missing\n"); + return 1; + } + + printf("VBT vers: %d.%d\n", vbt->version / 100, vbt->version % 100); + + bdb_off = vbt_off + vbt->bdb_offset; + if (bdb_off >= finfo.st_size - sizeof(struct bdb_header)) { + printf("Invalid VBT found, BDB points beyond end of data block\n"); + return 1; + } + + bdb = (struct bdb_header *)(VBIOS + bdb_off); + strncpy(signature, (char *)bdb->signature, 16); + signature[16] = 0; + printf("BDB sig: %s\n", signature); + printf("BDB vers: %d\n", bdb->version); + + printf("Available sections: "); + for (i = 0; i < 256; i++) { + block = find_section(i, finfo.st_size); + if (!block) + continue; + printf("%d ", i); + free(block); + } + printf("\n"); + + if (devid == -1) + devid = get_device_id(VBIOS); + if (devid == -1) + printf("Warning: could not find PCI device ID!\n"); + + dump_general_features(finfo.st_size); + dump_general_definitions(finfo.st_size); + dump_child_devices(finfo.st_size); + dump_lvds_options(finfo.st_size); + dump_lvds_data(finfo.st_size); + dump_lvds_ptr_data(finfo.st_size); + dump_backlight_info(finfo.st_size); + + dump_sdvo_lvds_options(finfo.st_size); + dump_sdvo_panel_dtds(finfo.st_size); + + dump_driver_feature(finfo.st_size); + dump_edp(finfo.st_size); + + return 0; +} diff --git a/tools/intel_disable_clock_gating.c b/tools/intel_disable_clock_gating.c new file mode 100644 index 00000000..8dde3e18 --- /dev/null +++ b/tools/intel_disable_clock_gating.c @@ -0,0 +1,71 @@ +/* + * Copyright © 2010 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: + * Zhenyu Wang <zhenyuw@linux.intel.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include "intel_gpu_tools.h" + +int main(int argc, char** argv) +{ + struct pci_device *pci_dev; + + pci_dev = intel_get_pci_device(); + intel_get_mmio(pci_dev); + + if (IS_GEN5(pci_dev->device_id)) { + printf("Restore method:\n"); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_3DCGDIS0, INREG(PCH_3DCGDIS0)); + OUTREG(PCH_3DCGDIS0, 0xffffffff); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_3DCGDIS1, INREG(PCH_3DCGDIS1)); + OUTREG(PCH_3DCGDIS1, 0xffffffff); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_3DRAMCGDIS0, INREG(PCH_3DRAMCGDIS0)); + OUTREG(PCH_3DRAMCGDIS0, 0xffffffff); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_DSPCLK_GATE_D, INREG(PCH_DSPCLK_GATE_D)); + OUTREG(PCH_DSPCLK_GATE_D, 0xffffffff); + + printf("intel_reg_write 0x%x 0x%08x\n", + PCH_DSPRAMCLK_GATE_D, INREG(PCH_DSPRAMCLK_GATE_D)); + OUTREG(PCH_DSPRAMCLK_GATE_D, 0xffffffff); + } else { + fprintf(stderr, "unsupported chipset\n"); + } + + + return 0; +} + diff --git a/tools/intel_dpio_read.c b/tools/intel_dpio_read.c new file mode 100644 index 00000000..c0c904a6 --- /dev/null +++ b/tools/intel_dpio_read.c @@ -0,0 +1,68 @@ +/* + * Copyright © 2012 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: + * Vijay Purushothaman <vijay.a.purushothaman@intel.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include "intel_gpu_tools.h" + +static void usage(char *cmdname) +{ + printf("Warning : This program will work only on Valleyview\n"); + printf("Usage: %s [addr]\n", cmdname); + printf("\t addr : in 0xXXXX format\n"); +} + +int main(int argc, char** argv) +{ + int ret = 0; + uint32_t reg, val; + char *cmdname = strdup(argv[0]); + struct pci_device *dev = intel_get_pci_device(); + + if (argc != 2 || !IS_VALLEYVIEW(dev->device_id)) { + usage(cmdname); + ret = 1; + goto out; + } + + sscanf(argv[1], "0x%x", ®); + + intel_register_access_init(dev, 0); + + val = intel_dpio_reg_read(reg); + + printf("Read DPIO register: 0x%x - Value : 0x%x\n", reg, val); + + intel_register_access_fini(); + +out: + free(cmdname); + return ret; +} diff --git a/tools/intel_dpio_write.c b/tools/intel_dpio_write.c new file mode 100644 index 00000000..f8429990 --- /dev/null +++ b/tools/intel_dpio_write.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2012 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: + * Vijay Purushothaman <vijay.a.purushothaman@intel.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include "intel_gpu_tools.h" + +static void usage(char *cmdname) +{ + printf("Warning : This program will work only on Valleyview\n"); + printf("Usage: %s [addr] [val]\n", cmdname); + printf("\t addr : in 0xXXXX format\n"); +} + +int main(int argc, char** argv) +{ + int ret = 0; + uint32_t reg, val; + char *cmdname = strdup(argv[0]); + struct pci_device *dev = intel_get_pci_device(); + + if (argc != 3 || !IS_VALLEYVIEW(dev->device_id)) { + usage(cmdname); + ret = 1; + goto out; + } + + sscanf(argv[1], "0x%x", ®); + sscanf(argv[2], "0x%x", &val); + + intel_register_access_init(dev, 0); + + intel_dpio_reg_write(reg, val); + + intel_register_access_fini(); + +out: + free(cmdname); + return ret; +} diff --git a/tools/intel_dump_decode.c b/tools/intel_dump_decode.c new file mode 100644 index 00000000..a3cd2e59 --- /dev/null +++ b/tools/intel_dump_decode.c @@ -0,0 +1,211 @@ +/* + * Copyright © 2010 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#define _GNU_SOURCE +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <getopt.h> + +#include <intel_bufmgr.h> + +struct drm_intel_decode *ctx; + +static void +read_bin_file(const char * filename) +{ + uint32_t buf[16384]; + int fd, offset, ret; + + if (!strcmp(filename, "-")) + fd = fileno(stdin); + else + fd = open (filename, O_RDONLY); + if (fd < 0) { + fprintf (stderr, "Failed to open %s: %s\n", + filename, strerror (errno)); + exit (1); + } + + drm_intel_decode_set_dump_past_end(ctx, 1); + + offset = 0; + while ((ret = read (fd, buf, sizeof(buf))) > 0) { + drm_intel_decode_set_batch_pointer(ctx, buf, offset, ret/4); + drm_intel_decode(ctx); + offset += ret; + } + close (fd); +} + +static void +read_data_file(const char * filename) +{ + FILE *file; + uint32_t *data = NULL; + int data_size = 0, count = 0, line_number = 0, matched; + char *line = NULL; + size_t line_size; + uint32_t offset, value; + uint32_t gtt_offset = 0; + + if (!strcmp(filename, "-")) + file = stdin; + else + file = fopen (filename, "r"); + + if (file == NULL) { + fprintf (stderr, "Failed to open %s: %s\n", + filename, strerror (errno)); + exit (1); + } + + while (getline (&line, &line_size, file) > 0) { + line_number++; + + matched = sscanf (line, "%08x : %08x", &offset, &value); + if (matched != 2) { + printf("ignoring line %s", line); + + continue; + } + + count++; + + if (count > data_size) { + data_size = data_size ? data_size * 2 : 1024; + data = realloc (data, data_size * sizeof (uint32_t)); + if (data == NULL) { + fprintf (stderr, "Out of memory.\n"); + exit (1); + } + } + + data[count-1] = value; + } + + if (count) { + drm_intel_decode_set_batch_pointer(ctx, data, gtt_offset, count); + drm_intel_decode(ctx); + } + + free (data); + free (line); + + fclose (file); +} + +static void +read_autodetect_file(const char * filename) +{ + int binary = 0, c; + FILE *file; + + file = fopen (filename, "r"); + if (file == NULL) { + fprintf (stderr, "Failed to open %s: %s\n", + filename, strerror (errno)); + exit (1); + } + + while ((c = fgetc(file)) != EOF) { + /* totally lazy binary detector */ + if (c < 10) { + binary = 1; + break; + } + } + + fclose(file); + + if (binary == 1) + read_bin_file(filename); + else + read_data_file(filename); + +} + + +int +main (int argc, char *argv[]) +{ + uint32_t devid = 0xa011; + int i, c; + int option_index = 0; + int binary = -1; + + static struct option long_options[] = { + {"devid", 1, 0, 'd'}, + {"ascii", 0, 0, 'a'}, + {"binary", 0, 0, 'b'} + }; + + while((c = getopt_long(argc, argv, "ab", + long_options, &option_index)) != -1) { + switch(c) { + case 'd': + devid = strtoul(optarg, NULL, 0); + break; + case 'b': + binary = 1; + break; + case 'a': + binary = 0; + break; + default: + printf("unkown command options\n"); + break; + } + } + + ctx = drm_intel_decode_context_alloc(devid); + + if (optind == argc) { + fprintf(stderr, "no input file given\n"); + exit(-1); + } + + for (i = optind; i < argc; i++) { + /* For stdin input, let's read as data file */ + if (!strcmp(argv[i], "-")) { + read_data_file(argv[i]); + continue; + } + if (binary == 1) + read_bin_file(argv[i]); + else if (binary == 0) + read_data_file(argv[i]); + else + read_autodetect_file(argv[i]); + } + + return 0; +} diff --git a/tools/intel_error_decode.c b/tools/intel_error_decode.c new file mode 100644 index 00000000..e0ec8f60 --- /dev/null +++ b/tools/intel_error_decode.c @@ -0,0 +1,515 @@ +/* -*- c-basic-offset: 4 -*- */ +/* + * Copyright © 2007 Intel Corporation + * Copyright © 2009 Intel Corporation + * Copyright © 2010 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> + * Carl Worth <cworth@cworth.org> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** @file intel_decode.c + * This file contains code to print out batchbuffer contents in a + * human-readable format. + * + * The current version only supports i915 packets, and only pretty-prints a + * subset of them. The intention is for it to make just a best attempt to + * decode, but never crash in the process. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <err.h> +#include <intel_bufmgr.h> + +#include "intel_chipset.h" +#include "intel_gpu_tools.h" +#include "instdone.h" + +static void +print_instdone (uint32_t devid, unsigned int instdone, unsigned int instdone1) +{ + int i; + static int once; + + if (!once) { + init_instdone_definitions(devid); + once = 1; + } + + for (i = 0; i < num_instdone_bits; i++) { + int busy = 0; + + if (instdone_bits[i].reg == INST_DONE_1) { + if (!(instdone1 & instdone_bits[i].bit)) + busy = 1; + } else { + if (!(instdone & instdone_bits[i].bit)) + busy = 1; + } + + if (busy) + printf(" busy: %s\n", instdone_bits[i].name); + } +} + +static void +print_i830_pgtbl_err(unsigned int reg) +{ + const char *str; + + switch((reg >> 3) & 0xf) { + case 0x1: str = "Overlay TLB"; break; + case 0x2: str = "Display A TLB"; break; + case 0x3: str = "Host TLB"; break; + case 0x4: str = "Render TLB"; break; + case 0x5: str = "Display C TLB"; break; + case 0x6: str = "Mapping TLB"; break; + case 0x7: str = "Command Stream TLB"; break; + case 0x8: str = "Vertex Buffer TLB"; break; + case 0x9: str = "Display B TLB"; break; + case 0xa: str = "Reserved System Memory"; break; + case 0xb: str = "Compressor TLB"; break; + case 0xc: str = "Binner TLB"; break; + default: str = "unknown"; break; + } + + if (str) + printf (" source = %s\n", str); + + switch(reg & 0x7) { + case 0x0: str = "Invalid GTT"; break; + case 0x1: str = "Invalid GTT PTE"; break; + case 0x2: str = "Invalid Memory"; break; + case 0x3: str = "Invalid TLB miss"; break; + case 0x4: str = "Invalid PTE data"; break; + case 0x5: str = "Invalid LocalMemory not present"; break; + case 0x6: str = "Invalid Tiling"; break; + case 0x7: str = "Host to CAM"; break; + } + printf (" error = %s\n", str); +} + +static void +print_i915_pgtbl_err(unsigned int reg) +{ + if (reg & (1 << 29)) + printf (" Cursor A: Invalid GTT PTE\n"); + if (reg & (1 << 28)) + printf (" Cursor B: Invalid GTT PTE\n"); + if (reg & (1 << 27)) + printf (" MT: Invalid tiling\n"); + if (reg & (1 << 26)) + printf (" MT: Invalid GTT PTE\n"); + if (reg & (1 << 25)) + printf (" LC: Invalid tiling\n"); + if (reg & (1 << 24)) + printf (" LC: Invalid GTT PTE\n"); + if (reg & (1 << 23)) + printf (" BIN VertexData: Invalid GTT PTE\n"); + if (reg & (1 << 22)) + printf (" BIN Instruction: Invalid GTT PTE\n"); + if (reg & (1 << 21)) + printf (" CS VertexData: Invalid GTT PTE\n"); + if (reg & (1 << 20)) + printf (" CS Instruction: Invalid GTT PTE\n"); + if (reg & (1 << 19)) + printf (" CS: Invalid GTT\n"); + if (reg & (1 << 18)) + printf (" Overlay: Invalid tiling\n"); + if (reg & (1 << 16)) + printf (" Overlay: Invalid GTT PTE\n"); + if (reg & (1 << 14)) + printf (" Display C: Invalid tiling\n"); + if (reg & (1 << 12)) + printf (" Display C: Invalid GTT PTE\n"); + if (reg & (1 << 10)) + printf (" Display B: Invalid tiling\n"); + if (reg & (1 << 8)) + printf (" Display B: Invalid GTT PTE\n"); + if (reg & (1 << 6)) + printf (" Display A: Invalid tiling\n"); + if (reg & (1 << 4)) + printf (" Display A: Invalid GTT PTE\n"); + if (reg & (1 << 1)) + printf (" Host Invalid PTE data\n"); + if (reg & (1 << 0)) + printf (" Host Invalid GTT PTE\n"); +} + +static void +print_i965_pgtbl_err(unsigned int reg) +{ + if (reg & (1 << 26)) + printf (" Invalid Sampler Cache GTT entry\n"); + if (reg & (1 << 24)) + printf (" Invalid Render Cache GTT entry\n"); + if (reg & (1 << 23)) + printf (" Invalid Instruction/State Cache GTT entry\n"); + if (reg & (1 << 22)) + printf (" There is no ROC, this cannot occur!\n"); + if (reg & (1 << 21)) + printf (" Invalid GTT entry during Vertex Fetch\n"); + if (reg & (1 << 20)) + printf (" Invalid GTT entry during Command Fetch\n"); + if (reg & (1 << 19)) + printf (" Invalid GTT entry during CS\n"); + if (reg & (1 << 18)) + printf (" Invalid GTT entry during Cursor Fetch\n"); + if (reg & (1 << 17)) + printf (" Invalid GTT entry during Overlay Fetch\n"); + if (reg & (1 << 8)) + printf (" Invalid GTT entry during Display B Fetch\n"); + if (reg & (1 << 4)) + printf (" Invalid GTT entry during Display A Fetch\n"); + if (reg & (1 << 1)) + printf (" Valid PTE references illegal memory\n"); + if (reg & (1 << 0)) + printf (" Invalid GTT entry during fetch for host\n"); +} + +static void +print_pgtbl_err(unsigned int reg, unsigned int devid) +{ + if (IS_965(devid)) { + return print_i965_pgtbl_err(reg); + } else if (IS_GEN3(devid)) { + return print_i915_pgtbl_err(reg); + } else { + return print_i830_pgtbl_err(reg); + } +} + +static void +print_snb_fence(unsigned int devid, uint64_t fence) +{ + printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n", + fence & 1 ? "" : "in", + fence & (1<<1) ? 'y' : 'x', + (int)(((fence>>32)&0xfff)+1)*128, + (uint32_t)fence & 0xfffff000, + (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096)); +} + +static void +print_i965_fence(unsigned int devid, uint64_t fence) +{ + printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %u\n", + fence & 1 ? "" : "in", + fence & (1<<1) ? 'y' : 'x', + (int)(((fence>>2)&0x1ff)+1)*128, + (uint32_t)fence & 0xfffff000, + (uint32_t)(((fence>>32)&0xfffff000) - (fence&0xfffff000) + 4096)); +} + +static void +print_i915_fence(unsigned int devid, uint64_t fence) +{ + unsigned tile_width; + if ((fence & 12) && !IS_915(devid)) + tile_width = 128; + else + tile_width = 512; + + printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %i\n", + fence & 1 ? "" : "in", + fence & 12 ? 'y' : 'x', + (1<<((fence>>4)&0xf))*tile_width, + (uint32_t)fence & 0xff00000, + 1<<(20 + ((fence>>8)&0xf))); +} + +static void +print_i830_fence(unsigned int devid, uint64_t fence) +{ + printf(" %svalid, %c-tiled, pitch: %i, start: 0x%08x, size: %i\n", + fence & 1 ? "" : "in", + fence & 12 ? 'y' : 'x', + (1<<((fence>>4)&0xf))*128, + (uint32_t)fence & 0x7f80000, + 1<<(19 + ((fence>>8)&0xf))); +} + +static void +print_fence(unsigned int devid, uint64_t fence) +{ + if (IS_GEN6(devid) || IS_GEN7(devid)) { + return print_snb_fence(devid, fence); + } else if (IS_GEN4(devid) || IS_GEN5(devid)) { + return print_i965_fence(devid, fence); + } else if (IS_GEN3(devid)) { + return print_i915_fence(devid, fence); + } else { + return print_i830_fence(devid, fence); + } +} + +static void +read_data_file (FILE *file) +{ + struct drm_intel_decode *decode_ctx = NULL; + uint32_t devid = PCI_CHIP_I855_GM; + uint32_t *data = NULL; + long long unsigned fence; + int data_size = 0, count = 0, line_number = 0, matched; + char *line = NULL; + size_t line_size; + uint32_t offset, value; + uint32_t gtt_offset = 0, new_gtt_offset; + const char *buffer_type[2] = { "ringbuffer", "batchbuffer" }; + char *ring_name = NULL; + int is_batch = 1; + + while (getline (&line, &line_size, file) > 0) { + char *dashes; + line_number++; + + dashes = strstr(line, "---"); + if (dashes) { + char *new_ring_name = malloc(dashes - line); + strncpy(new_ring_name, line, dashes - line); + new_ring_name[dashes - line - 1] = '\0'; + + matched = sscanf (dashes, "--- gtt_offset = 0x%08x\n", + &new_gtt_offset); + if (matched == 1) { + if (count) { + printf("%s (%s) at 0x%08x:\n", + buffer_type[is_batch], + ring_name, + gtt_offset); + drm_intel_decode_set_batch_pointer(decode_ctx, + data, gtt_offset, + count); + drm_intel_decode(decode_ctx); + count = 0; + } + gtt_offset = new_gtt_offset; + is_batch = 1; + free(ring_name); + ring_name = new_ring_name; + continue; + } + + matched = sscanf (dashes, "--- ringbuffer = 0x%08x\n", + &new_gtt_offset); + if (matched == 1) { + if (count) { + printf("%s (%s) at 0x%08x:\n", + buffer_type[is_batch], + ring_name, + gtt_offset); + drm_intel_decode_set_batch_pointer(decode_ctx, + data, gtt_offset, + count); + drm_intel_decode(decode_ctx); + count = 0; + } + gtt_offset = new_gtt_offset; + is_batch = 0; + free(ring_name); + ring_name = new_ring_name; + continue; + } + } + + matched = sscanf (line, "%08x : %08x", &offset, &value); + if (matched != 2) { + unsigned int reg; + + /* display reg section is after the ringbuffers, don't mix them */ + if (count) { + printf("%s (%s) at 0x%08x:\n", + buffer_type[is_batch], + ring_name, + gtt_offset); + drm_intel_decode_set_batch_pointer(decode_ctx, + data, gtt_offset, + count); + drm_intel_decode(decode_ctx); + count = 0; + } + + printf("%s", line); + + matched = sscanf (line, "PCI ID: 0x%04x\n", ®); + if (matched == 0) + matched = sscanf (line, " PCI ID: 0x%04x\n", ®); + if (matched == 1) { + devid = reg; + printf("Detected GEN%i chipset\n", + intel_gen(devid)); + + decode_ctx = drm_intel_decode_context_alloc(devid); + } + + matched = sscanf (line, " ACTHD: 0x%08x\n", ®); + if (matched == 1) + drm_intel_decode_set_head_tail(decode_ctx, reg, 0xffffffff); + + matched = sscanf (line, " PGTBL_ER: 0x%08x\n", ®); + if (matched == 1 && reg) + print_pgtbl_err(reg, devid); + + matched = sscanf (line, " INSTDONE: 0x%08x\n", ®); + if (matched == 1) + print_instdone (devid, reg, -1); + + matched = sscanf (line, " INSTDONE1: 0x%08x\n", ®); + if (matched == 1) + print_instdone (devid, -1, reg); + + matched = sscanf (line, " fence[%i] = %Lx\n", ®, &fence); + if (matched == 2) + print_fence (devid, fence); + + continue; + } + + count++; + + if (count > data_size) { + data_size = data_size ? data_size * 2 : 1024; + data = realloc (data, data_size * sizeof (uint32_t)); + if (data == NULL) { + fprintf (stderr, "Out of memory.\n"); + exit (1); + } + } + + data[count-1] = value; + } + + if (count) { + printf("%s (%s) at 0x%08x:\n", + buffer_type[is_batch], + ring_name, + gtt_offset); + drm_intel_decode_set_batch_pointer(decode_ctx, + data, gtt_offset, + count); + drm_intel_decode(decode_ctx); + } + + free (data); + free (line); + free (ring_name); +} + +int +main (int argc, char *argv[]) +{ + FILE *file; + const char *path; + char *filename = NULL; + struct stat st; + int error; + + if (argc > 2) { + fprintf (stderr, + "intel_gpu_decode: Parse an Intel GPU i915_error_state\n" + "Usage:\n" + "\t%s [<file>]\n" + "\n" + "With no arguments, debugfs-dri-directory is probed for in " + "/debug and \n" + "/sys/kernel/debug. Otherwise, it may be " + "specified. If a file is given,\n" + "it is parsed as an GPU dump in the format of " + "/debug/dri/0/i915_error_state.\n", + argv[0]); + return 1; + } + + if (argc == 1) { + if (isatty(0)) { + path = "/debug/dri"; + error = stat (path, &st); + if (error != 0) { + path = "/sys/kernel/debug/dri"; + error = stat (path, &st); + if (error != 0) { + errx(1, + "Couldn't find i915 debugfs directory.\n\n" + "Is debugfs mounted? You might try mounting it with a command such as:\n\n" + "\tsudo mount -t debugfs debugfs /sys/kernel/debug\n"); + } + } + } else { + read_data_file(stdin); + exit(0); + } + } else { + path = argv[1]; + error = stat (path, &st); + if (error != 0) { + fprintf (stderr, "Error opening %s: %s\n", + path, strerror (errno)); + exit (1); + } + } + + if (S_ISDIR (st.st_mode)) { + asprintf (&filename, "%s/i915_error_state", path); + file = fopen(filename, "r"); + if (!file) { + int minor; + for (minor = 0; minor < 64; minor++) { + free(filename); + asprintf(&filename, "%s/%d/i915_error_state", path, minor); + file = fopen(filename, "r"); + if (file) + break; + } + } + if (!file) { + fprintf (stderr, "Failed to find i915_error_state beneath %s\n", + path); + exit (1); + } + } else { + file = fopen(path, "r"); + if (!file) { + fprintf (stderr, "Failed to open %s: %s\n", + path, strerror (errno)); + exit (1); + } + } + + read_data_file (file); + fclose (file); + + if (filename != path) + free (filename); + + return 0; +} diff --git a/tools/intel_forcewaked.c b/tools/intel_forcewaked.c new file mode 100644 index 00000000..3ab2d6f8 --- /dev/null +++ b/tools/intel_forcewaked.c @@ -0,0 +1,106 @@ +/* + * Copyright © 2011 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: + * Ben Widawsky <ben@bwidawsk.net> + * + */ + +#include <assert.h> +#include <err.h> +#include <string.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <unistd.h> +#include "intel_gpu_tools.h" + +bool daemonized; + +#define INFO_PRINT(...) \ + do { \ + if (daemonized) \ + syslog(LOG_INFO, ##__VA_ARGS__); \ + else \ + fprintf(stdout, ##__VA_ARGS__); \ + } while(0) + +static void +help(char *prog) { + printf("%s Prevents the GT from sleeping.\n\n", prog); + printf("usage: %s [options] \n\n", prog); + printf("Options: \n"); + printf(" -b Run in background/daemon mode\n"); +} + +static int +is_alive(void) { + /* Read the timestamp, which should *almost* always be !0 */ + return (intel_register_read(0x2358) != 0); +} + +int main(int argc, char *argv[]) +{ + int ret; + + if (argc > 2 || (argc == 2 && !strncmp(argv[1], "-h", 2))) { + help(argv[1]); + exit(0); + } + + if (argc == 2 && (!strncmp(argv[1], "-b", 2))) + daemonized = true; + + if (daemonized) { + assert(daemon(0, 0) == 0); + openlog(argv[0], LOG_CONS | LOG_PID, LOG_USER); + INFO_PRINT("started daemon"); + } + + ret = intel_register_access_init(intel_get_pci_device(), 1); + if (ret) { + INFO_PRINT("Couldn't init register access\n"); + exit(1); + } else { + INFO_PRINT("Forcewake locked\n"); + } + while(1) { + if (!is_alive()) { + INFO_PRINT("gpu reset? restarting daemon\n"); + intel_register_access_fini(); + ret = intel_register_access_init(intel_get_pci_device(), + 1); + } + sleep(1); + } + intel_register_access_fini(); + INFO_PRINT("Forcewake unlock\n"); + + if (daemonized) { + INFO_PRINT("finished\n"); + closelog(); + } + + return 0; +} diff --git a/tools/intel_gpu_abrt b/tools/intel_gpu_abrt new file mode 100755 index 00000000..141a5246 --- /dev/null +++ b/tools/intel_gpu_abrt @@ -0,0 +1,45 @@ +#!/bin/sh + +if [ -d /debug/dri ] ; then + debugfs_path=/debug_dri +fi + +if [ -d /sys/kernel/debug/dri ] ; then + debugfs_path=/sys/kernel/debug/dri +fi + +i915_debugfs=x +for dir in `ls $debugfs_path` ; do + if [ -f $debugfs_path/$dir/i915_error_state ] ; then + i915_debugfs=$debugfs_path/$dir + break + fi +done + +if [ $i915_debugfs = "x" ] ; then + echo i915 debugfs path not found. + exit 1 +fi + +tmpdir=`mktemp -d` +tardir=$tmpdir/intel_gpu_abrt +mkdir $tardir + +mkdir $tardir/debugfs +cp $i915_debugfs/* $tardir/debugfs + +mkdir $tardir/mod_opts +cp /sys/module/i915/parameters/* $tardir/mod_opts + +mkdir $tardir/X +cp /var/log/Xorg.*.log $tardir/X +cp /etc/X11/xorg.conf $tardir/X + +dmesg > $tardir/dmesg +lspci -nn > $tardir/lspci + +(cd $tmpdir; tar -c intel_gpu_abrt ) > intel_gpu_abrt.tar + +rm $tmpdir -Rf + +exit 0 diff --git a/tools/intel_gpu_time.c b/tools/intel_gpu_time.c new file mode 100644 index 00000000..c30b84d2 --- /dev/null +++ b/tools/intel_gpu_time.c @@ -0,0 +1,110 @@ +/* + * Copyright © 2007,2009 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> + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> + +#include "intel_gpu_tools.h" + +#define SAMPLES_PER_SEC 10000 + +static volatile int goddo; + +static pid_t spawn(char **argv) +{ + pid_t pid; + + pid = fork(); + if (pid != 0) + return pid; + + execvp(argv[0], argv); + exit(1); +} + +static void sighandler(int sig) +{ + goddo = sig; +} + +int main(int argc, char **argv) +{ + pid_t child; + uint64_t ring_idle = 0, ring_time = 0; + struct timeval start, end; + static struct rusage rusage; + int status; + + intel_get_mmio(intel_get_pci_device()); + + if (argc == 1) { + fprintf(stderr, "usage: %s cmd [args...]\n", argv[0]); + return 1; + } + + signal(SIGCHLD, sighandler); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + + gettimeofday(&start, NULL); + child = spawn(argv+1); + if (child < 0) + return 127; + + while (!goddo) { + uint32_t ring_head, ring_tail; + + ring_head = INREG(LP_RING + RING_HEAD) & HEAD_ADDR; + ring_tail = INREG(LP_RING + RING_TAIL) & TAIL_ADDR; + + if (ring_tail == ring_head) + ring_idle++; + ring_time++; + + usleep(1000000 / SAMPLES_PER_SEC); + } + gettimeofday(&end, NULL); + timersub(&end, &start, &end); + + waitpid(child, &status, 0); + + getrusage(RUSAGE_CHILDREN, &rusage); + printf("user: %ld.%06lds, sys: %ld.%06lds, elapsed: %ld.%06lds, CPU: %.1f%%, GPU: %.1f%%\n", + rusage.ru_utime.tv_sec, rusage.ru_utime.tv_usec, + rusage.ru_stime.tv_sec, rusage.ru_stime.tv_usec, + end.tv_sec, end.tv_usec, + 100*(rusage.ru_utime.tv_sec + 1e-6*rusage.ru_utime.tv_usec + rusage.ru_stime.tv_sec + 1e-6*rusage.ru_stime.tv_usec) / (end.tv_sec + 1e-6*end.tv_usec), + 100 - ring_idle * 100. / ring_time); + + return WEXITSTATUS(status); +} diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c new file mode 100644 index 00000000..e561865c --- /dev/null +++ b/tools/intel_gpu_top.c @@ -0,0 +1,716 @@ +/* + * Copyright © 2007 Intel Corporation + * Copyright © 2011 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> + * Eugeni Dodonov <eugeni.dodonov@intel.com> + * + */ + +#include "config.h" + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <string.h> +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#endif +#include "intel_gpu_tools.h" +#include "instdone.h" + +#define FORCEWAKE 0xA18C +#define FORCEWAKE_ACK 0x130090 + +#define SAMPLES_PER_SEC 10000 +#define SAMPLES_TO_PERCENT_RATIO (SAMPLES_PER_SEC / 100) + +#define MAX_NUM_TOP_BITS 100 + +#define HAS_STATS_REGS(devid) IS_965(devid) + +struct top_bit { + struct instdone_bit *bit; + int count; +} top_bits[MAX_NUM_TOP_BITS]; +struct top_bit *top_bits_sorted[MAX_NUM_TOP_BITS]; + +static uint32_t instdone, instdone1; + +static const char *bars[] = { + " ", + "▏", + "▎", + "▍", + "▌", + "▋", + "▊", + "▉", + "█" +}; + +enum stats_counts { + IA_VERTICES, + IA_PRIMITIVES, + VS_INVOCATION, + GS_INVOCATION, + GS_PRIMITIVES, + CL_INVOCATION, + CL_PRIMITIVES, + PS_INVOCATION, + PS_DEPTH, + STATS_COUNT +}; + +const uint32_t stats_regs[STATS_COUNT] = { + IA_VERTICES_COUNT_QW, + IA_PRIMITIVES_COUNT_QW, + VS_INVOCATION_COUNT_QW, + GS_INVOCATION_COUNT_QW, + GS_PRIMITIVES_COUNT_QW, + CL_INVOCATION_COUNT_QW, + CL_PRIMITIVES_COUNT_QW, + PS_INVOCATION_COUNT_QW, + PS_DEPTH_COUNT_QW, +}; + +const char *stats_reg_names[STATS_COUNT] = { + "vert fetch", + "prim fetch", + "VS invocations", + "GS invocations", + "GS prims", + "CL invocations", + "CL prims", + "PS invocations", + "PS depth pass", +}; + +uint64_t stats[STATS_COUNT]; +uint64_t last_stats[STATS_COUNT]; + +static unsigned long +gettime(void) +{ + struct timeval t; + gettimeofday(&t, NULL); + return (t.tv_usec + (t.tv_sec * 1000000)); +} + +static int +top_bits_sort(const void *a, const void *b) +{ + struct top_bit * const *bit_a = a; + struct top_bit * const *bit_b = b; + int a_count = (*bit_a)->count; + int b_count = (*bit_b)->count; + + if (a_count < b_count) + return 1; + else if (a_count == b_count) + return 0; + else + return -1; +} + +static void +update_idle_bit(struct top_bit *top_bit) +{ + uint32_t reg_val; + + if (top_bit->bit->reg == INST_DONE_1) + reg_val = instdone1; + else + reg_val = instdone; + + if ((reg_val & top_bit->bit->bit) == 0) + top_bit->count++; +} + +static void +print_clock(const char *name, int clock) { + if (clock == -1) + printf("%s clock: unknown", name); + else + printf("%s clock: %d Mhz", name, clock); +} + +static int +print_clock_info(struct pci_device *pci_dev) +{ + uint32_t devid = pci_dev->device_id; + uint16_t gcfgc; + + if (IS_GM45(devid)) { + int core_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0xf) { + case 8: + core_clock = 266; + break; + case 9: + core_clock = 320; + break; + case 11: + core_clock = 400; + break; + case 13: + core_clock = 533; + break; + } + print_clock("core", core_clock); + } else if (IS_965(devid) && IS_MOBILE(devid)) { + int render_clock = -1, sampler_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0xf) { + case 2: + render_clock = 250; sampler_clock = 267; + break; + case 3: + render_clock = 320; sampler_clock = 333; + break; + case 4: + render_clock = 400; sampler_clock = 444; + break; + case 5: + render_clock = 500; sampler_clock = 533; + break; + } + + print_clock("render", render_clock); + printf(" "); + print_clock("sampler", sampler_clock); + } else if (IS_945(devid) && IS_MOBILE(devid)) { + int render_clock = -1, display_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0x7) { + case 0: + render_clock = 166; + break; + case 1: + render_clock = 200; + break; + case 3: + render_clock = 250; + break; + case 5: + render_clock = 400; + break; + } + + switch (gcfgc & 0x70) { + case 0: + display_clock = 200; + break; + case 4: + display_clock = 320; + break; + } + if (gcfgc & (1 << 7)) + display_clock = 133; + + print_clock("render", render_clock); + printf(" "); + print_clock("display", display_clock); + } else if (IS_915(devid) && IS_MOBILE(devid)) { + int render_clock = -1, display_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0x7) { + case 0: + render_clock = 160; + break; + case 1: + render_clock = 190; + break; + case 4: + render_clock = 333; + break; + } + if (gcfgc & (1 << 13)) + render_clock = 133; + + switch (gcfgc & 0x70) { + case 0: + display_clock = 190; + break; + case 4: + display_clock = 333; + break; + } + if (gcfgc & (1 << 7)) + display_clock = 133; + + print_clock("render", render_clock); + printf(" "); + print_clock("display", display_clock); + } + + + printf("\n"); + return -1; +} + +#define STATS_LEN (20) +#define PERCENTAGE_BAR_END (79 - STATS_LEN) + +static void +print_percentage_bar(float percent, int cur_line_len) +{ + int bar_avail_len = (PERCENTAGE_BAR_END - cur_line_len - 1) * 8; + int bar_len = bar_avail_len * (percent + .5) / 100.0; + int i; + + for (i = bar_len; i >= 8; i -= 8) { + printf("%s", bars[8]); + cur_line_len++; + } + if (i) { + printf("%s", bars[i]); + cur_line_len++; + } + + /* NB: We can't use a field width with utf8 so we manually + * guarantee a field with of 45 chars for any bar. */ + printf("%*s", PERCENTAGE_BAR_END - cur_line_len, ""); +} + +struct ring { + const char *name; + uint32_t mmio; + int head, tail, size; + uint64_t full; + int idle; +}; + +static uint32_t ring_read(struct ring *ring, uint32_t reg) +{ + return INREG(ring->mmio + reg); +} + +static void ring_init(struct ring *ring) +{ + ring->size = (((ring_read(ring, RING_LEN) & RING_NR_PAGES) >> 12) + 1) * 4096; +} + +static void ring_reset(struct ring *ring) +{ + ring->idle = ring->full = 0; +} + +static void ring_sample(struct ring *ring) +{ + int full; + + if (!ring->size) + return; + + ring->head = ring_read(ring, RING_HEAD) & HEAD_ADDR; + ring->tail = ring_read(ring, RING_TAIL) & TAIL_ADDR; + + if (ring->tail == ring->head) + ring->idle++; + + full = ring->tail - ring->head; + if (full < 0) + full += ring->size; + ring->full += full; +} + +static void ring_print_header(FILE *out, struct ring *ring) +{ + fprintf(out, "%.6s%%\tops\t", + ring->name + ); +} + +static void ring_print(struct ring *ring, unsigned long samples_per_sec) +{ + int percent_busy, len; + + if (!ring->size) + return; + + percent_busy = 100 - 100 * ring->idle / samples_per_sec; + + len = printf("%25s busy: %3d%%: ", ring->name, percent_busy); + print_percentage_bar (percent_busy, len); + printf("%24s space: %d/%d\n", + ring->name, + (int)(ring->full / samples_per_sec), + ring->size); +} + +static void ring_log(struct ring *ring, unsigned long samples_per_sec, + FILE *output) +{ + if (ring->size) + fprintf(output, "%3d\t%d\t", + (int)(100 - 100 * ring->idle / samples_per_sec), + (int)(ring->full / samples_per_sec)); + else + fprintf(output, "-1\t-1\t"); +} + +static void +usage(const char *appname) +{ + printf("intel_gpu_top - Display a top-like summary of Intel GPU usage\n" + "\n" + "usage: %s [parameters]\n" + "\n" + "The following parameters apply:\n" + "[-s <samples>] samples per seconds (default %d)\n" + "[-e <command>] command to profile\n" + "[-o <file>] output statistics to file. If file is '-'," + " run in batch mode and output statistics to stdio only \n" + "[-h] show this help screen\n" + "\n", + appname, + SAMPLES_PER_SEC + ); + return; +} + +int main(int argc, char **argv) +{ + uint32_t devid; + struct pci_device *pci_dev; + struct ring render_ring = { + .name = "render", + .mmio = 0x2030, + }, bsd_ring = { + .name = "bitstream", + .mmio = 0x4030, + }, bsd6_ring = { + .name = "bitstream", + .mmio = 0x12030, + }, blt_ring = { + .name = "blitter", + .mmio = 0x22030, + }; + int i, ch; + int samples_per_sec = SAMPLES_PER_SEC; + FILE *output = NULL; + double elapsed_time=0; + int print_headers=1; + pid_t child_pid=-1; + int child_stat; + char *cmd=NULL; + int interactive=1; + + /* Parse options? */ + while ((ch = getopt(argc, argv, "s:o:e:h")) != -1) { + switch (ch) { + case 'e': cmd = strdup(optarg); + break; + case 's': samples_per_sec = atoi(optarg); + if (samples_per_sec < 100) { + fprintf(stderr, "Error: samples per second must be >= 100\n"); + exit(1); + } + break; + case 'o': + if (!strcmp(optarg, "-")) { + /* Running in non-interactive mode */ + interactive = 0; + output = stdout; + } + else + output = fopen(optarg, "w"); + if (!output) + { + perror("fopen"); + exit(1); + } + break; + case 'h': + usage(argv[0]); + exit(0); + break; + default: + fprintf(stderr, "Invalid flag %c!\n", (char)optopt); + usage(argv[0]); + exit(1); + break; + } + } + argc -= optind; + argv += optind; + + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; + intel_get_mmio(pci_dev); + init_instdone_definitions(devid); + + /* Do we have a command to run? */ + if (cmd != NULL) { + if (output) { + fprintf(output, "# Profiling: %s\n", cmd); + fflush(output); + } + child_pid = fork(); + if (child_pid < 0) { + perror("fork"); + exit(1); + } + else if (child_pid == 0) { + int res; + res = system(cmd); + if (res < 0) + perror("running command"); + if (output) { + fflush(output); + fprintf(output, "# %s exited with status %d\n", cmd, res); + fflush(output); + } + free(cmd); + exit(0); + } else { + free(cmd); + } + } + + for (i = 0; i < num_instdone_bits; i++) { + top_bits[i].bit = &instdone_bits[i]; + top_bits[i].count = 0; + top_bits_sorted[i] = &top_bits[i]; + } + + /* Grab access to the registers */ + intel_register_access_init(pci_dev, 0); + + ring_init(&render_ring); + if (IS_GEN4(devid) || IS_GEN5(devid)) + ring_init(&bsd_ring); + if (IS_GEN6(devid) || IS_GEN7(devid)) { + ring_init(&bsd6_ring); + ring_init(&blt_ring); + } + + /* Initialize GPU stats */ + if (HAS_STATS_REGS(devid)) { + for (i = 0; i < STATS_COUNT; i++) { + uint32_t stats_high, stats_low, stats_high_2; + + do { + stats_high = INREG(stats_regs[i] + 4); + stats_low = INREG(stats_regs[i]); + stats_high_2 = INREG(stats_regs[i] + 4); + } while (stats_high != stats_high_2); + + last_stats[i] = (uint64_t)stats_high << 32 | + stats_low; + } + } + + for (;;) { + int j; + unsigned long long t1, ti, tf, t2; + unsigned long long def_sleep = 1000000 / samples_per_sec; + unsigned long long last_samples_per_sec = samples_per_sec; + unsigned short int max_lines; + struct winsize ws; + char clear_screen[] = {0x1b, '[', 'H', + 0x1b, '[', 'J', + 0x0}; + int percent; + int len; + + t1 = gettime(); + + ring_reset(&render_ring); + ring_reset(&bsd_ring); + ring_reset(&bsd6_ring); + ring_reset(&blt_ring); + + for (i = 0; i < samples_per_sec; i++) { + long long interval; + ti = gettime(); + if (IS_965(devid)) { + instdone = INREG(INST_DONE_I965); + instdone1 = INREG(INST_DONE_1); + } else + instdone = INREG(INST_DONE); + + for (j = 0; j < num_instdone_bits; j++) + update_idle_bit(&top_bits[j]); + + ring_sample(&render_ring); + ring_sample(&bsd_ring); + ring_sample(&bsd6_ring); + ring_sample(&blt_ring); + + tf = gettime(); + if (tf - t1 >= 1000000) { + /* We are out of sync, bail out */ + last_samples_per_sec = i+1; + break; + } + interval = def_sleep - (tf - ti); + if (interval > 0) + usleep(interval); + } + + if (HAS_STATS_REGS(devid)) { + for (i = 0; i < STATS_COUNT; i++) { + uint32_t stats_high, stats_low, stats_high_2; + + do { + stats_high = INREG(stats_regs[i] + 4); + stats_low = INREG(stats_regs[i]); + stats_high_2 = INREG(stats_regs[i] + 4); + } while (stats_high != stats_high_2); + + stats[i] = (uint64_t)stats_high << 32 | + stats_low; + } + } + + qsort(top_bits_sorted, num_instdone_bits, + sizeof(struct top_bit *), top_bits_sort); + + /* Limit the number of lines printed to the terminal height so the + * most important info (at the top) will stay on screen. */ + max_lines = -1; + if (ioctl(0, TIOCGWINSZ, &ws) != -1) + max_lines = ws.ws_row - 6; /* exclude header lines */ + if (max_lines >= num_instdone_bits) + max_lines = num_instdone_bits; + + t2 = gettime(); + elapsed_time += (t2 - t1) / 1000000.0; + + if (interactive) { + printf("%s", clear_screen); + print_clock_info(pci_dev); + + ring_print(&render_ring, last_samples_per_sec); + ring_print(&bsd_ring, last_samples_per_sec); + ring_print(&bsd6_ring, last_samples_per_sec); + ring_print(&blt_ring, last_samples_per_sec); + + printf("\n%30s %s\n", "task", "percent busy"); + for (i = 0; i < max_lines; i++) { + if (top_bits_sorted[i]->count > 0) { + percent = (top_bits_sorted[i]->count * 100) / + last_samples_per_sec; + len = printf("%30s: %3d%%: ", + top_bits_sorted[i]->bit->name, + percent); + print_percentage_bar (percent, len); + } else { + printf("%*s", PERCENTAGE_BAR_END, ""); + } + + if (i < STATS_COUNT && HAS_STATS_REGS(devid)) { + printf("%13s: %llu (%lld/sec)", + stats_reg_names[i], + (long long)stats[i], + (long long)(stats[i] - last_stats[i])); + last_stats[i] = stats[i]; + } else { + if (!top_bits_sorted[i]->count) + break; + } + printf("\n"); + } + } + if (output) { + /* Print headers for columns at first run */ + if (print_headers) { + fprintf(output, "# time\t"); + ring_print_header(output, &render_ring); + ring_print_header(output, &bsd_ring); + ring_print_header(output, &bsd6_ring); + ring_print_header(output, &blt_ring); + for (i = 0; i < MAX_NUM_TOP_BITS; i++) { + if (i < STATS_COUNT && HAS_STATS_REGS(devid)) { + fprintf(output, "%.6s\t", + stats_reg_names[i] + ); + } + if (!top_bits[i].count) + continue; + } + fprintf(output, "\n"); + print_headers = 0; + } + + /* Print statistics */ + fprintf(output, "%.2f\t", elapsed_time); + ring_log(&render_ring, last_samples_per_sec, output); + ring_log(&bsd_ring, last_samples_per_sec, output); + ring_log(&bsd6_ring, last_samples_per_sec, output); + ring_log(&blt_ring, last_samples_per_sec, output); + + for (i = 0; i < MAX_NUM_TOP_BITS; i++) { + if (i < STATS_COUNT && HAS_STATS_REGS(devid)) { + fprintf(output, "%lu\t", + stats[i] - last_stats[i]); + last_stats[i] = stats[i]; + } + if (!top_bits[i].count) + continue; + } + fprintf(output, "\n"); + fflush(output); + } + + for (i = 0; i < num_instdone_bits; i++) { + top_bits_sorted[i]->count = 0; + + if (i < STATS_COUNT) + last_stats[i] = stats[i]; + } + + /* Check if child has gone */ + if (child_pid > 0) { + int res; + if ((res = waitpid(child_pid, &child_stat, WNOHANG)) == -1) { + perror("waitpid"); + exit(1); + } + if (res == 0) + continue; + if (WIFEXITED(child_stat)) + break; + } + } + + fclose(output); + + intel_register_access_fini(); + return 0; +} diff --git a/tools/intel_gtt.c b/tools/intel_gtt.c new file mode 100644 index 00000000..05d36d71 --- /dev/null +++ b/tools/intel_gtt.c @@ -0,0 +1,134 @@ +/* + * Copyright © 2008 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <pciaccess.h> +#include <unistd.h> + +#include "intel_gpu_tools.h" + +#define INGTT(offset) (*(volatile uint32_t *)(gtt + (offset) / (KB(4) / 4))) + +#define KB(x) ((x) * 1024) +#define MB(x) ((x) * 1024 * 1024) + +int main(int argc, char **argv) +{ + struct pci_device *pci_dev; + int start, aper_size; + unsigned char *gtt; + uint32_t devid; + int flag[] = { + PCI_DEV_MAP_FLAG_WRITE_COMBINE, + PCI_DEV_MAP_FLAG_WRITABLE, + 0 + }, f; + + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; + + if (IS_GEN2(devid)) { + printf("Unsupported chipset for gtt dumper\n"); + exit(1); + } + + for (f = 0; flag[f] != 0; f++) { + if (IS_GEN3(devid)) { + /* 915/945 chips has GTT range in bar 3 */ + if (pci_device_map_range(pci_dev, + pci_dev->regions[3].base_addr, + pci_dev->regions[3].size, + flag[f], + (void **)>t) == 0) + break; + } else { + int offset; + if (IS_G4X(devid) || IS_GEN5(devid)) + offset = MB(2); + else + offset = KB(512); + if (pci_device_map_range(pci_dev, + pci_dev->regions[0].base_addr + offset, + offset, + flag[f], + (void **)>t) == 0) + break; + } + } + if (flag[f] == 0) { + printf("Failed to map gtt\n"); + exit(1); + } + + aper_size = pci_dev->regions[2].size; + + for (start = 0; start < aper_size; start += KB(4)) { + uint32_t start_pte = INGTT(start); + uint32_t end; + int constant_length = 0; + int linear_length = 0; + + /* Check if it's a linear sequence */ + for (end = start + KB(4); end < aper_size; end += KB(4)) { + uint32_t end_pte = INGTT(end); + if (end_pte == start_pte + (end - start)) + linear_length++; + else + break; + } + if (linear_length > 0) { + printf("0x%08x - 0x%08x: linear from " + "0x%08x to 0x%08x\n", + start, end - KB(4), + start_pte, start_pte + (end - start) - KB(4)); + start = end - KB(4); + continue; + } + + /* Check if it's a constant sequence */ + for (end = start + KB(4); end < aper_size; end += KB(4)) { + uint32_t end_pte = INGTT(end); + if (end_pte == start_pte) + constant_length++; + else + break; + } + if (constant_length > 0) { + printf("0x%08x - 0x%08x: constant 0x%08x\n", + start, end - KB(4), start_pte); + start = end - KB(4); + continue; + } + + printf("0x%08x: 0x%08x\n", start, start_pte); + } + + return 0; +} diff --git a/tools/intel_infoframes.c b/tools/intel_infoframes.c new file mode 100644 index 00000000..f5a40067 --- /dev/null +++ b/tools/intel_infoframes.c @@ -0,0 +1,1142 @@ +/* + * Copyright © 2012 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: + * Paulo Zanoni <paulo.r.zanoni@intel.com> + * + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include "intel_gpu_tools.h" + +typedef enum { + TRANSC_A = 0, + TRANSC_B = 1, + TRANSC_C = 2, + TRANSC_INVALID +} Transcoder; + +typedef enum { + REG_HDMIB_GEN4 = 0x61140, + REG_HDMIC_GEN4 = 0x61160, + REG_HDMIB_PCH = 0xe1140, + REG_HDMIC_PCH = 0xe1150, + REG_HDMID_PCH = 0xe1160, + REG_DIP_CTL_GEN4 = 0x61170, + REG_DIP_CTL_A = 0xe0200, + REG_DIP_CTL_B = 0xe1200, + REG_DIP_CTL_C = 0xe2200, + REG_DIP_DATA_GEN4 = 0x61178, + REG_DIP_DATA_A = 0xe0208, + REG_DIP_DATA_B = 0xe1208, + REG_DIP_DATA_C = 0xe2208, +} Register; + +typedef enum { + DIP_AVI = 0, + DIP_VENDOR = 1, + DIP_GAMUT = 2, + DIP_SPD = 3, + DIP_INVALID, +} DipType; + +typedef enum { + DIP_FREQ_ONCE = 0, + DIP_FREQ_EVERY_VSYNC = 1, + DIP_FREQ_EVERY_OTHER_VSYNC = 2, + DIP_FREQ_RESERVED = 3, +} DipFrequency; + +typedef enum { + SOURCE_DEVICE_UNKNOWN = 0x00, + SOURCE_DEVICE_DIGITAL_STB = 0x01, + SOURCE_DEVICE_DVD_PLAYER = 0x02, + SOURCE_DEVICE_D_VHS = 0x03, + SOURCE_DEVICE_HDD_VIDEORECORDER = 0x04, + SOURCE_DEVICE_DVC = 0x05, + SOURCE_DEVICE_DSC = 0x06, + SOURCE_DEVICE_VIDEO_CD = 0x07, + SOURCE_DEVICE_GAME = 0x08, + SOURCE_DEVICE_PC_GENERAL = 0x09, + SOURCE_DEVICE_BLU_RAY_DISK = 0x0a, + SOURCE_DEVICE_SUPER_AUDIO_CD = 0x0b, + SOURCE_DEVICE_RESERVED = 0x0c +} SourceDevice; + +#define HDMI_PORT_ENABLE (1 << 31) +#define HDMI_PORT_TRANSCODER_GEN4 (1 << 30) +#define HDMI_PORT_TRANSCODER_IBX (1 << 30) +#define HDMI_PORT_TRANSCODER_CPT (3 << 29) +#define HDMI_PORT_ENCODING (3 << 10) +#define HDMI_PORT_MODE (1 << 9) +#define HDMI_PORT_AUDIO (1 << 6) +#define HDMI_PORT_DETECTED (1 << 2) + +#define DIP_CTL_ENABLE (1 << 31) +#define DIP_CTL_GCP_ENABLE (1 << 25) +#define DIP_CTL_SPD_ENABLE (1 << 24) +#define DIP_CTL_GAMUT_ENABLE (1 << 23) +#define DIP_CTL_VENDOR_ENABLE (1 << 22) +#define DIP_CTL_AVI_ENABLE (1 << 21) +#define DIP_CTL_BUFFER_INDEX (3 << 19) +#define DIP_CTL_BUFFER_AVI (0 << 19) +#define DIP_CTL_BUFFER_VENDOR (1 << 19) +#define DIP_CTL_BUFFER_GAMUT (2 << 19) +#define DIP_CTL_BUFFER_SPD (3 << 19) +#define DIP_CTL_FREQUENCY (3 << 16) +#define DIP_CTL_FREQ_ONCE (0 << 16) +#define DIP_CTL_FREQ_EVERY (1 << 16) +#define DIP_CTL_FREQ_EVERY_OTHER (2 << 16) +#define DIP_CTL_BUFFER_SIZE (15 << 8) +#define DIP_CTL_ACCESS_ADDR (15 << 0) + +#define DIP_CTL_PORT_SEL_MASK_GEN4 (3 << 29) +#define DIP_CTL_PORT_SEL_B_GEN4 (1 << 29) +#define DIP_CTL_PORT_SEL_C_GEN4 (2 << 29) +#define DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 (1 << 28) + +#define AVI_INFOFRAME_TYPE 0x82 +#define AVI_INFOFRAME_VERSION 0x02 +#define AVI_INFOFRAME_LENGTH 0x0d +#define SPD_INFOFRAME_TYPE 0x83 +#define SPD_INFOFRAME_VERSION 0x01 +#define SPD_INFOFRAME_LENGTH 0x19 + +typedef struct { + uint8_t type; + uint8_t version; + uint8_t length; + uint8_t ecc; +} DipInfoFrameHeader; + +typedef union { + struct { + DipInfoFrameHeader header; + uint8_t checksum; + + uint8_t S :2; + uint8_t B :2; + uint8_t A :1; + uint8_t Y :2; + uint8_t Rsvd0 :1; + + uint8_t R :4; + uint8_t M :2; + uint8_t C :2; + + uint8_t SC :2; + uint8_t Q :2; + uint8_t EC :3; + uint8_t ITC :1; + + uint8_t VIC :7; + uint8_t Rsvd1 :1; + + uint8_t PR :4; + uint8_t Rsvd2 :4; + + uint16_t top; + uint16_t bottom; + uint16_t left; + uint16_t right; + + uint16_t Rsvd3; + uint32_t Rsvd4[3]; + } avi; + struct { + DipInfoFrameHeader header; + uint8_t checksum; + uint8_t vendor[8]; + uint8_t description[16]; + uint8_t source; + } __attribute__((packed)) spd; + struct { + DipInfoFrameHeader header; + uint8_t body[27]; + } generic; + uint8_t data8[128]; + uint32_t data32[16]; +} DipInfoFrame; + +Register gen4_hdmi_ports[] = { + REG_HDMIB_GEN4, + REG_HDMIC_GEN4, +}; +Register pch_hdmi_ports[] = { + REG_HDMIB_PCH, + REG_HDMIC_PCH, + REG_HDMID_PCH +}; +Register pch_dip_ctl_regs[] = { + REG_DIP_CTL_A, + REG_DIP_CTL_B, + REG_DIP_CTL_C +}; +Register pch_dip_data_regs[] = { + REG_DIP_DATA_A, + REG_DIP_DATA_B, + REG_DIP_DATA_C +}; +const char *hdmi_port_names[] = { + "HDMIB", + "HDMIC", + "HDMID" +}; +const char *transcoder_names[] = { + "A", + "B", + "C" +}; +const char *dip_frequency_names[] = { + "once", + "every vsync", + "every other vsync", + "reserved (invalid)" +}; + +int gen = 0; + +static const char *spd_source_to_string(SourceDevice source) +{ + switch (source) { + case SOURCE_DEVICE_UNKNOWN: + return "unknown"; + case SOURCE_DEVICE_DIGITAL_STB: + return "digital stb"; + case SOURCE_DEVICE_DVD_PLAYER: + return "dvd player"; + case SOURCE_DEVICE_D_VHS: + return "d vhs"; + case SOURCE_DEVICE_HDD_VIDEORECORDER: + return "hdd videorecorder"; + case SOURCE_DEVICE_DVC: + return "dvc"; + case SOURCE_DEVICE_DSC: + return "dsc"; + case SOURCE_DEVICE_VIDEO_CD: + return "video cd"; + case SOURCE_DEVICE_GAME: + return "game"; + case SOURCE_DEVICE_PC_GENERAL: + return "pc general"; + case SOURCE_DEVICE_BLU_RAY_DISK: + return "blu-ray disk"; + case SOURCE_DEVICE_SUPER_AUDIO_CD: + return "super audio cd"; + default: + return "reserved"; + } +} + +static Register get_dip_ctl_reg(Transcoder transcoder) +{ + if (gen == 4) + return REG_DIP_CTL_GEN4; + else + return pch_dip_ctl_regs[transcoder]; +} + +static Register get_dip_data_reg(Transcoder transcoder) +{ + if (gen == 4) + return REG_DIP_DATA_GEN4; + else + return pch_dip_data_regs[transcoder]; +} + +static Register get_hdmi_port(int hdmi_port_index) +{ + if (gen == 4) { + assert(hdmi_port_index < 2); + return gen4_hdmi_ports[hdmi_port_index]; + } else { + return pch_hdmi_ports[hdmi_port_index]; + } +} + +static void load_infoframe(Transcoder transcoder, DipInfoFrame *frame, + DipType type) +{ + Register ctl_reg = get_dip_ctl_reg(transcoder); + Register data_reg = get_dip_data_reg(transcoder); + uint32_t ctl_val; + uint32_t i; + + ctl_val = INREG(ctl_reg); + + ctl_val &= ~DIP_CTL_BUFFER_INDEX; + ctl_val |= type << 19; + OUTREG(ctl_reg, ctl_val); + ctl_val = INREG(ctl_reg); + + ctl_val &= ~DIP_CTL_ACCESS_ADDR; + OUTREG(ctl_reg, ctl_val); + + for (i = 0; i < 16; i++) { + ctl_val = INREG(ctl_reg); + assert((ctl_val & DIP_CTL_ACCESS_ADDR) == i); + frame->data32[i] = INREG(data_reg); + } +} + +static int infoframe_valid_checksum(DipInfoFrame *frame) +{ + int i; + int length = frame->generic.header.length; + uint8_t csum; + + csum = frame->generic.header.type + frame->generic.header.version + + frame->generic.header.length; /* no ecc */ + for (i = 0; i < length + 1; i++) + csum += frame->generic.body[i]; + + return (csum == 0); +} + +static void infoframe_fix_checksum(DipInfoFrame *frame) +{ + int i; + int length = frame->generic.header.length; + uint8_t csum; + + csum = frame->generic.header.type + frame->generic.header.version + + frame->generic.header.length; /* no ecc */ + /* Length does not include the header field nor the checksum */ + for (i = 1; i < length + 1; i++) + csum += frame->generic.body[i]; + frame->generic.body[0] = 0x100 - csum; +} + +static void dump_port_info(int hdmi_port_index) +{ + Register port = get_hdmi_port(hdmi_port_index); + uint32_t val = INREG(port); + Transcoder transcoder; + + printf("\nPort %s:\n", hdmi_port_names[hdmi_port_index]); + printf("- %sdetected\n", val & HDMI_PORT_DETECTED ? "" : "not "); + printf("- %s\n", val & HDMI_PORT_ENABLE ? "enabled" : "disabled"); + + if (!(val & HDMI_PORT_ENABLE)) + return; + + if (gen == 4) + transcoder = (val & HDMI_PORT_TRANSCODER_GEN4) >> 30; + else if (pch >= PCH_CPT) + transcoder = (val & HDMI_PORT_TRANSCODER_CPT) >> 29; + else + transcoder = (val & HDMI_PORT_TRANSCODER_IBX) >> 30; + printf("- transcoder: %s\n", transcoder_names[transcoder]); + + switch ((val & HDMI_PORT_ENCODING) >> 10) { + case 0: + printf("- mode: SDVO\n"); + break; + case 2: + printf("- mode: TMDS\n"); + break; + default: + printf("- mode: INVALID!\n"); + } + + printf("- mode: %s\n", val & HDMI_PORT_MODE ? "HDMI" : "DVI"); + printf("- audio: %s\n", val & HDMI_PORT_AUDIO ? "enabled" : "disabled"); +} + +static void dump_raw_infoframe(DipInfoFrame *frame) +{ + unsigned int i; + printf("- raw:"); + for (i = 0; i < 16; i++) { + if (i % 4 == 0) + printf("\n "); + printf(" %08x", frame->data32[i]); + } + printf("\n"); +} + +static void dump_avi_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipFrequency freq; + DipInfoFrame frame; + + load_infoframe(transcoder, &frame, DIP_AVI); + val = INREG(reg); + + printf("AVI InfoFrame:\n"); + + if (gen == 4) { + printf("- %sbeing transmitted\n", + val & DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 ? "" : "not "); + } + + freq = (val & DIP_CTL_FREQUENCY) >> 16; + printf("- frequency: %s\n", dip_frequency_names[freq]); + + dump_raw_infoframe(&frame); + + printf("- type: %x, version: %x, length: %x, ecc: %x, checksum: %x\n", + frame.avi.header.type, frame.avi.header.version, + frame.avi.header.length, frame.avi.header.ecc, + frame.avi.checksum); + printf("- S: %x, B: %x, A: %x, Y: %x, Rsvd0: %x\n", + frame.avi.S, frame.avi.B, frame.avi.A, frame.avi.Y, + frame.avi.Rsvd0); + printf("- R: %x, M: %x, C: %x\n", + frame.avi.R, frame.avi.M, frame.avi.C); + printf("- SC: %x, Q: %x, EC: %x, ITC: %x\n", + frame.avi.SC, frame.avi.Q, frame.avi.EC, frame.avi.ITC); + printf("- VIC: %x, Rsvd1: %x\n", frame.avi.VIC, frame.avi.Rsvd1); + printf("- PR: %x, Rsvd2: %x\n", frame.avi.PR, frame.avi.Rsvd2); + printf("- top: %x, bottom: %x, left: %x, right: %x\n", + frame.avi.top, frame.avi.bottom, frame.avi.left, + frame.avi.right); + printf("- Rsvd3: %x, Rsvd4[0]: %x, Rsvd4[1]: %x, Rsvd4[2]: %x\n", + frame.avi.Rsvd3, frame.avi.Rsvd4[0], frame.avi.Rsvd4[1], + frame.avi.Rsvd4[2]); + + if (!infoframe_valid_checksum(&frame)) + printf("Invalid InfoFrame checksum!\n"); +} + +static void dump_vendor_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipFrequency freq; + DipInfoFrame frame; + + load_infoframe(transcoder, &frame, DIP_VENDOR); + val = INREG(reg); + + printf("Vendor InfoFrame:\n"); + + if (gen == 4) { + printf("- %sbeing transmitted\n", + val & DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 ? "" : "not "); + } + + freq = (val & DIP_CTL_FREQUENCY) >> 16; + printf("- frequency: %s\n", dip_frequency_names[freq]); + + dump_raw_infoframe(&frame); + + if (!infoframe_valid_checksum(&frame)) + printf("Invalid InfoFrame checksum!\n"); +} + +static void dump_gamut_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipFrequency freq; + DipInfoFrame frame; + + load_infoframe(transcoder, &frame, DIP_GAMUT); + val = INREG(reg); + + printf("Gamut InfoFrame:\n"); + + if (gen == 4) { + printf("- %sbeing transmitted\n", + val & DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 ? "" : "not "); + } + + freq = (val & DIP_CTL_FREQUENCY) >> 16; + printf("- frequency: %s\n", dip_frequency_names[freq]); + + dump_raw_infoframe(&frame); + + if (!infoframe_valid_checksum(&frame)) + printf("Invalid InfoFrame checksum!\n"); +} + +static void dump_spd_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipFrequency freq; + DipInfoFrame frame; + char vendor[9]; + char description[17]; + + load_infoframe(transcoder, &frame, DIP_SPD); + val = INREG(reg); + + printf("SPD InfoFrame:\n"); + + if (gen == 4) { + printf("- %sbeing transmitted\n", + val & DIP_CTL_BUFFER_TRANS_ACTIVE_GEN4 ? "" : "not "); + } + + freq = (val & DIP_CTL_FREQUENCY) >> 16; + printf("- frequency: %s\n", dip_frequency_names[freq]); + + dump_raw_infoframe(&frame); + + printf("- type: %x, version: %x, length: %x, ecc: %x, checksum: %x\n", + frame.spd.header.type, frame.spd.header.version, + frame.spd.header.length, frame.spd.header.ecc, + frame.spd.checksum); + + memcpy(vendor, frame.spd.vendor, 8); + vendor[8] = '\0'; + memcpy(description, frame.spd.description, 16); + description[16] = '\0'; + + printf("- vendor: %s\n", vendor); + printf("- description: %s\n", description); + printf("- source: %s\n", spd_source_to_string(frame.spd.source)); + + if (!infoframe_valid_checksum(&frame)) + printf("Invalid InfoFrame checksum!\n"); +} + +static void dump_transcoder_info(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + + if (gen == 4) { + printf("\nDIP information:\n"); + switch (val & DIP_CTL_PORT_SEL_MASK_GEN4) { + case DIP_CTL_PORT_SEL_B_GEN4: + printf("- port B\n"); + break; + case DIP_CTL_PORT_SEL_C_GEN4: + printf("- port C\n"); + break; + default: + printf("- INVALID port!\n"); + } + } else { + printf("\nTranscoder %s:\n", transcoder_names[transcoder]); + } + printf("- %s\n", val & DIP_CTL_ENABLE ? "enabled" : "disabled"); + if (!(val & DIP_CTL_ENABLE)) + return; + + printf("- GCP: %s\n", val & DIP_CTL_GCP_ENABLE ? + "enabled" : "disabled"); + + if (val & DIP_CTL_AVI_ENABLE) + dump_avi_info(transcoder); + if (val & DIP_CTL_VENDOR_ENABLE) + dump_vendor_info(transcoder); + if (val & DIP_CTL_GAMUT_ENABLE) + dump_gamut_info(transcoder); + if (val & DIP_CTL_SPD_ENABLE) + dump_spd_info(transcoder); +} + +static void dump_all_info(void) +{ + unsigned int i; + + if (gen == 4) { + for (i = 0; i < ARRAY_SIZE(gen4_hdmi_ports); i++) + dump_port_info(i); + dump_transcoder_info(0); + } else { + for (i = 0; i < ARRAY_SIZE(pch_hdmi_ports); i++) + dump_port_info(i); + for (i = 0; i < ARRAY_SIZE(pch_dip_ctl_regs); i++) + dump_transcoder_info(i); + } +} + +static void write_infoframe(Transcoder transcoder, DipType type, + DipInfoFrame *frame) +{ + Register ctl_reg = get_dip_ctl_reg(transcoder); + Register data_reg = get_dip_data_reg(transcoder); + uint32_t ctl_val; + unsigned int i; + + ctl_val = INREG(ctl_reg); + ctl_val &= ~DIP_CTL_BUFFER_INDEX; + ctl_val |= (type << 19); + ctl_val &= ~DIP_CTL_ACCESS_ADDR; + OUTREG(ctl_reg, ctl_val); + + for (i = 0; i < 8; i++) { + ctl_val = INREG(ctl_reg); + assert((ctl_val & DIP_CTL_ACCESS_ADDR) == i); + OUTREG(data_reg, frame->data32[i]); + } +} + +static void disable_infoframe(Transcoder transcoder, DipType type) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + if (gen != 4 && type == DIP_AVI) + val &= ~DIP_CTL_ENABLE; + val &= ~(1 << (21 + type)); + OUTREG(reg, val); +} + +static void enable_infoframe(Transcoder transcoder, DipType type) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + if (gen != 4 && type == DIP_AVI) + val |= DIP_CTL_ENABLE; + val |= (1 << (21 + type)); + OUTREG(reg, val); +} + +static int parse_infoframe_option_u(const char *name, const char *s, + uint32_t min, uint32_t max, + uint32_t *value, char **commands) +{ + int read, rc; + if (!strcmp(name, s)) { + rc = sscanf(*commands, "%x%n", value, &read); + *commands = &(*commands)[read]; + if (rc != 1) { + printf("Invalid value.\n"); + return 0; + } + + if (*value < min || *value > max) { + printf("Value outside allowed range.\n"); + return 0; + } + return 1; + } + return 0; +} + +static int parse_infoframe_option_s(const char *name, const char *s, + int min_size, int max_size, + char *value, char **commands) +{ + int size, read, rc; + if (!strcmp(name, s)) { + rc = sscanf(*commands, "%31s%n", value, &read); + *commands = &(*commands)[read]; + if (rc != 1) { + printf("Invalid value.\n"); + return 0; + } + + size = strlen(value); + if (size < min_size || size > max_size) { + printf("String either too big or too small.\n"); + return 0; + } + return 1; + } + return 0; +} + +static void change_avi_infoframe(Transcoder transcoder, char *commands) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipInfoFrame frame; + char option[32]; + uint32_t option_val; + int rc, read; + char *current = commands; + + load_infoframe(transcoder, &frame, DIP_AVI); + val = INREG(reg); + + while (1) { + rc = sscanf(current, "%31s%n", option, &read); + current = ¤t[read]; + if (rc == EOF) { + break; + } else if (rc != 1) { + printf("Invalid option: %s\n", option); + continue; + } + + if (parse_infoframe_option_u("S", option, 0, 2, &option_val, + ¤t)) + frame.avi.S = option_val; + else if (parse_infoframe_option_u("B", option, 0, 3, + &option_val, ¤t)) + frame.avi.B = option_val; + else if (parse_infoframe_option_u("A", option, 0, 1, + &option_val, ¤t)) + frame.avi.A = option_val; + else if (parse_infoframe_option_u("Y", option, 0, 2, + &option_val, ¤t)) + frame.avi.Y = option_val; + else if (parse_infoframe_option_u("R", option, 0, 15, + &option_val, ¤t)) + frame.avi.R = option_val; + else if (parse_infoframe_option_u("M", option, 0, 2, + &option_val, ¤t)) + frame.avi.M = option_val; + else if (parse_infoframe_option_u("C", option, 0, 3, + &option_val, ¤t)) + frame.avi.C = option_val; + else if (parse_infoframe_option_u("SC", option, 0, 3, + &option_val, ¤t)) + frame.avi.SC = option_val; + else if (parse_infoframe_option_u("Q", option, 0, 2, + &option_val, ¤t)) + frame.avi.Q = option_val; + else if (parse_infoframe_option_u("EC", option, 0, 1, + &option_val,¤t)) + frame.avi.EC = option_val; + else if (parse_infoframe_option_u("ITC", option, 0, 1, + &option_val, ¤t)) + frame.avi.ITC = option_val; + else if (parse_infoframe_option_u("VIC", option, 0, 127, + &option_val, ¤t)) + frame.avi.VIC = option_val; + else if (parse_infoframe_option_u("PR", option, 0, 15, + &option_val, ¤t)) + frame.avi.PR = option_val; + else if (parse_infoframe_option_u("top", option, 0, 65535, + &option_val, ¤t)) + frame.avi.top = option_val; + else if (parse_infoframe_option_u("bottom", option, 0, 65535, + &option_val, ¤t)) + frame.avi.bottom = option_val; + else if (parse_infoframe_option_u("left", option, 0, 65535, + &option_val, ¤t)) + frame.avi.left = option_val; + else if (parse_infoframe_option_u("right", option, 0, 65535, + &option_val, ¤t)) + frame.avi.right = option_val; + else + printf("Unrecognized option: %s\n", option); + } + + val &= ~DIP_CTL_FREQUENCY; + val |= DIP_CTL_FREQ_EVERY; + OUTREG(reg, val); + + frame.avi.header.type = AVI_INFOFRAME_TYPE; + frame.avi.header.version = AVI_INFOFRAME_VERSION; + frame.avi.header.length = AVI_INFOFRAME_LENGTH; + frame.avi.Rsvd0 = 0; + frame.avi.Rsvd1 = 0; + frame.avi.Rsvd2 = 0; + frame.avi.Rsvd3 = 0; + frame.avi.Rsvd4[0] = 0; + frame.avi.Rsvd4[1] = 0; + frame.avi.Rsvd4[2] = 0; + + infoframe_fix_checksum(&frame); + + disable_infoframe(transcoder, DIP_AVI); + write_infoframe(transcoder, DIP_AVI, &frame); + enable_infoframe(transcoder, DIP_AVI); +} + +static void change_spd_infoframe(Transcoder transcoder, char *commands) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + DipInfoFrame frame; + char option[16]; + char option_val_s[32]; + uint32_t option_val_i; + int rc, read; + char *current = commands; + + load_infoframe(transcoder, &frame, DIP_SPD); + val = INREG(reg); + + while (1) { + rc = sscanf(current, "%31s%n", option, &read); + current = ¤t[read]; + if (rc == EOF) { + break; + } else if (rc != 1) { + printf("Invalid option: %s\n", option); + continue; + } + + memset(option_val_s, 0, 32); + + if (parse_infoframe_option_s("vendor", option, 0, 8, + option_val_s, ¤t)) + memcpy(frame.spd.vendor, option_val_s, 8); + else if (parse_infoframe_option_s("description", option, 0, 16, + option_val_s, ¤t)) + memcpy(frame.spd.description, option_val_s, 16); + else if (parse_infoframe_option_u("source", option, 0, 0x0c, + &option_val_i, ¤t)) + frame.spd.source = option_val_i; + else + printf("Unrecognized option: %s\n", option); + } + + val &= ~DIP_CTL_FREQUENCY; + val |= DIP_CTL_FREQ_EVERY_OTHER; + OUTREG(reg, val); + + frame.spd.header.type = SPD_INFOFRAME_TYPE; + frame.spd.header.version = SPD_INFOFRAME_VERSION; + frame.spd.header.length = SPD_INFOFRAME_LENGTH; + + infoframe_fix_checksum(&frame); + + disable_infoframe(transcoder, DIP_SPD); + write_infoframe(transcoder, DIP_SPD, &frame); + enable_infoframe(transcoder, DIP_SPD); +} + +static void change_infoframe_checksum(Transcoder transcoder, DipType type, + uint32_t selected_csum) +{ + DipInfoFrame frame; + + load_infoframe(transcoder, &frame, type); + frame.generic.body[0] = selected_csum; + disable_infoframe(transcoder, type); + write_infoframe(transcoder, type, &frame); + enable_infoframe(transcoder, type); +} + +static void change_infoframe_frequency(Transcoder transcoder, DipType type, + DipFrequency frequency) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + + if (type == DIP_AVI && frequency != DIP_FREQ_EVERY_VSYNC) { + printf("Error: AVI infoframe must be sent every VSync!\n"); + frequency = DIP_FREQ_EVERY_VSYNC; + } + + val &= ~DIP_CTL_FREQUENCY; + val |= (frequency << 16); + OUTREG(reg, val); +} + +static void disable_dip(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + val &= ~DIP_CTL_ENABLE; + OUTREG(reg, val); +} + +static void enable_dip(Transcoder transcoder) +{ + Register reg = get_dip_ctl_reg(transcoder); + uint32_t val = INREG(reg); + val |= DIP_CTL_ENABLE; + OUTREG(reg, val); +} + +static void disable_hdmi_port(Register reg) +{ + uint32_t val = INREG(reg); + val &= ~HDMI_PORT_ENABLE; + OUTREG(reg, val); +} + +static void enable_hdmi_port(Register reg) +{ + uint32_t val = INREG(reg); + val |= HDMI_PORT_ENABLE; + OUTREG(reg, val); +} + +static void print_usage(void) +{ +printf("Options:\n" +" -d, --dump\n" +" dump information about all transcoders\n" +" -c, --change-fields [fields]\n" +" change infoframe fields from selected transcoder\n" +" -k, --change-checksum [checksum]\n" +" change infoframe checksum (value in hex)\n" +" -q, --change-frequency [frequency]\n" +" change infoframe frequency (once, everyvsync or everyothervsync)\n" +" -n, --disable\n" +" disable the selected infoframe from the selected transcoder\n" +" -N, --enable\n" +" enable the selected infoframe from the selected transcoder\n" +" -x, --disable-infoframes\n" +" disable all infoframes from selected transcoder\n" +" -X, --enable-infoframes\n" +" enable sending infoframes on the selected transcoder\n" +" -p, --disable-hdmi-port [port]\n" +" disable hdmi port on the selected transcoder (B, C or D)\n" +" -P, --enable-hdmi-port [port]\n" +" enable hdmi port on the selected transcoder (B, C or D)\n" +" -t, --transcoder\n" +" select transcoder (A, B or C)\n" +" -f, --infoframe\n" +" select infoframe (AVI, Vendor, Gamut or SPD)\n" +" -h, --help\n" +" prints this message\n" +"\n" +"Examples:\n" +"\n" +" Dump information:\n" +" intel_infoframes\n" +"\n" +" Disable overscan and set ITC on transcoder B:\n" +" intel_infoframes -t B -f AVI -c 'S 2 ITC 1'\n" +"\n" +" Many actions on the same command:\n" +" - enable overscan on transcoder A\n" +" - enable overscan and change description on transcoder B\n" +" - disable all infoframes on transcoder C\n" +" - dump the resulting state:\n" +" intel_infoframes -t A -f AVI -c 'S 1' \\\n" +" -t B -f AVI -c 'S 2' \\\n" +" -f SPD -c 'description Linux' \\\n" +" -t C --disable-infoframes \\\n" +" -d\n" +"\n" +" Even more:\n" +" - print the help message\n" +" - completely disable all infoframes on all transcoders\n" +" - dump the state" +" - enable sending infoframes on transcoder B, but disable all infoframes\n" +" - enable AVI infoframes transcoder B, use underscan and declare ITC\n" +" - also enable SPD infoframes on the same transcoder, change frequency to\n" +" every vsync and change vendor, description and source\n" +" - dump the state again\n" +" intel_infoframes -h \\\n" +" -t A -x -t B -x -t C -x \\\n" +" -d \\\n" +" -t A -X -f AVI -n -f Vendor -n \\\n" +" -f Gamut -n -f SPD -n \\\n" +" -f AVI -N -c 'S 2 ITC 1'\\\n" +" -f SPD -q everyvsync \\\n" +" -c 'vendor me description mine source 0x09' \\\n" +" -d\n" +"\n" +"Infoframe fields used by the --change-fields option:\n" +" - AVI infoframe fields:\n" +" S B A Y R M C SC Q EC ITC VIC PR top bottom left right\n" +" - SPD infoframe fields:\n" +" vendor description source\n" +" - Other infoframe fields are not implemented yet.\n"); +} + +#define CHECK_TRANSCODER(transcoder) \ + if (transcoder == TRANSC_INVALID) { \ + printf("Transcoder not selected.\n"); \ + ret = 1; \ + goto out; \ + } + +#define CHECK_DIP(dip) \ + if (dip == DIP_INVALID) { \ + printf("Infoframe not selected.\n"); \ + ret = 1; \ + goto out; \ + } + +int main(int argc, char *argv[]) +{ + int opt; + int ret = 0; + struct pci_device *pci_dev; + Transcoder transcoder = TRANSC_INVALID; + DipType dip = DIP_INVALID; + Register hdmi_port; + + char short_opts[] = "dc:k:q:nNxXp:P:t:f:h"; + struct option long_opts[] = { + { "dump", no_argument, NULL, 'd' }, + { "change-fields", required_argument, NULL, 'c' }, + { "change-checksum", required_argument, NULL, 'k' }, + { "change-frequency", required_argument, NULL, 'q' }, + { "disable", no_argument, NULL, 'n' }, + { "enable", no_argument, NULL, 'N' }, + { "disable-infoframes", no_argument, NULL, 'x' }, + { "enable-infoframes", no_argument, NULL, 'X' }, + { "disable-hdmi-port", required_argument, NULL, 'p' }, + { "enable-hdmi-port", required_argument, NULL, 'P' }, + { "transcoder" , required_argument, NULL, 't' }, + { "infoframe", required_argument, NULL, 'f' }, + { "help", no_argument, NULL, 'h' }, + }; + + printf("WARNING: This is just a debugging tool! Don't expect it to work" + " perfectly: the Kernel might undo our changes.\n"); + + pci_dev = intel_get_pci_device(); + intel_register_access_init(pci_dev, 0); + intel_check_pch(); + + if (IS_GEN4(pci_dev->device_id)) + gen = 4; + else if (IS_GEN5(pci_dev->device_id)) + gen = 5; + else if (IS_GEN6(pci_dev->device_id)) + gen = 6; + else if (IS_GEN7(pci_dev->device_id)) + gen = 7; + else { + printf("This program does not support your hardware yet.\n"); + ret = 1; + goto out; + } + + while (1) { + opt = getopt_long(argc, argv, short_opts, long_opts, NULL); + if (opt == -1) + break; + + switch (opt) { + case 'd': + dump_all_info(); + break; + case 'c': + if (transcoder == TRANSC_INVALID) { + printf("Transcoder not selected.\n"); + ret = 1; + goto out; + } + switch (dip) { + case DIP_AVI: + change_avi_infoframe(transcoder, optarg); + break; + case DIP_VENDOR: + case DIP_GAMUT: + printf("Option not implemented yet.\n"); + ret = 1; + goto out; + case DIP_SPD: + change_spd_infoframe(transcoder, optarg); + break; + case DIP_INVALID: + printf("Infoframe not selected.\n"); + ret = 1; + goto out; + } + break; + case 'k': + CHECK_TRANSCODER(transcoder); + CHECK_DIP(dip); + change_infoframe_checksum(transcoder, dip, atoi(optarg)); + break; + case 'q': + CHECK_TRANSCODER(transcoder); + CHECK_DIP(dip); + if (!strcmp(optarg, "once")) + change_infoframe_frequency(transcoder, dip, + DIP_FREQ_ONCE); + else if (!strcmp(optarg, "everyvsync")) + change_infoframe_frequency(transcoder, dip, + DIP_FREQ_EVERY_VSYNC); + else if (!strcmp(optarg, "everyothervsync")) + change_infoframe_frequency(transcoder, dip, + DIP_FREQ_EVERY_OTHER_VSYNC); + else { + printf("Invalid frequency.\n"); + ret = 1; + goto out; + } + break; + case 'n': + CHECK_TRANSCODER(transcoder); + CHECK_DIP(dip); + disable_infoframe(transcoder, dip); + break; + case 'N': + CHECK_TRANSCODER(transcoder); + CHECK_DIP(dip); + enable_infoframe(transcoder, dip); + break; + case 'x': + CHECK_TRANSCODER(transcoder); + disable_dip(transcoder); + break; + case 'X': + CHECK_TRANSCODER(transcoder); + enable_dip(transcoder); + break; + case 'p': + case 'P': + if (!strcmp(optarg, "B")) + hdmi_port = get_hdmi_port(0); + else if (!strcmp(optarg, "C")) + hdmi_port = get_hdmi_port(1); + else if (!strcmp(optarg, "D")) + hdmi_port = get_hdmi_port(2); + else { + printf("Invalid HDMI port.\n"); + ret = 1; + goto out; + } + if (opt == 'p') + disable_hdmi_port(hdmi_port); + else + enable_hdmi_port(hdmi_port); + break; + case 't': + if (!strcmp(optarg, "A")) + transcoder = TRANSC_A; + else if (!strcmp(optarg, "B")) + transcoder = TRANSC_B; + else if (pch >= PCH_CPT && !strcmp(optarg, "C")) { + transcoder = TRANSC_C; + } else { + printf("Invalid transcoder.\n"); + ret = 1; + goto out; + } + break; + case 'f': + if (!strcmp(optarg, "AVI")) + dip = DIP_AVI; + else if (!strcmp(optarg, "Vendor")) + dip = DIP_VENDOR; + else if (!strcmp(optarg, "Gamut")) + dip = DIP_GAMUT; + else if (!strcmp(optarg, "SPD")) + dip = DIP_SPD; + else { + printf("Invalid infoframe.\n"); + ret = 1; + goto out; + } + break; + case 'h': + print_usage(); + break; + default: + print_usage(); + ret = 1; + goto out; + } + } + +out: + intel_register_access_fini(); + return ret; +} diff --git a/tools/intel_l3_parity.c b/tools/intel_l3_parity.c new file mode 100644 index 00000000..260c3d0c --- /dev/null +++ b/tools/intel_l3_parity.c @@ -0,0 +1,159 @@ +/* + * Copyright © 2012 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: + * Ben Widawsky <ben@bwidawsk.net> + * + */ + +#define _GNU_SOURCE +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "intel_chipset.h" +#include "intel_gpu_tools.h" +#include "drmtest.h" + +#define NUM_BANKS 4 +#define NUM_SUBBANKS 8 +#define NUM_REGS (NUM_BANKS * NUM_SUBBANKS) + +struct __attribute__ ((__packed__)) l3_log_register { + uint32_t row0_enable : 1; + uint32_t rsvd2 : 4; + uint32_t row0 : 11; + uint32_t row1_enable : 1; + uint32_t rsvd1 : 4; + uint32_t row1 : 11; +} l3log[NUM_BANKS][NUM_SUBBANKS]; + +static void dumpit(void) +{ + int i, j; + + for (i = 0; i < NUM_BANKS; i++) { + for (j = 0; j < NUM_SUBBANKS; j++) { + struct l3_log_register *reg = &l3log[i][j]; + + if (reg->row0_enable) + printf("Row %d, Bank %d, Subbank %d is disabled\n", + reg->row0, i, j); + if (reg->row1_enable) + printf("Row %d, Bank %d, Subbank %d is disabled\n", + reg->row1, i, j); + } + } +} + +static int disable_rbs(int row, int bank, int sbank) +{ + struct l3_log_register *reg = &l3log[bank][sbank]; + + // can't map more than 2 rows + if (reg->row0_enable && reg->row1_enable) + return -1; + + // can't remap the same row twice + if ((reg->row0_enable && reg->row0 == row) || + (reg->row1_enable && reg->row1 == row)) { + return -1; + } + + if (reg->row0_enable) { + reg->row1 = row; + reg->row1_enable = 1; + } else { + reg->row0 = row; + reg->row0_enable = 1; + } + + return 0; +} + +static int do_parse(int argc, char *argv[]) +{ + int row, bank, sbank, i, ret; + + for (i = 1; i < argc; i++) { + ret = sscanf(argv[i], "%d,%d,%d", &row, &bank, &sbank); + if (ret != 3) + return i; + assert(disable_rbs(row, bank, sbank) == 0); + } + return 0; +} + +int main(int argc, char *argv[]) +{ + const int device = drm_get_card(0); + char *path; + unsigned int devid; + int drm_fd, fd, ret; + + drm_fd = drm_open_any(); + devid = intel_get_drm_devid(drm_fd); + + ret = asprintf(&path, "/sys/class/drm/card%d/l3_parity", device); + assert(ret != -1); + + fd = open(path, O_RDWR); + if (fd == -1 && IS_IVYBRIDGE(devid)) { + perror("Opening sysfs"); + exit(EXIT_FAILURE); + } else if (fd == -1) + exit(EXIT_SUCCESS); + + ret = read(fd, l3log, NUM_REGS * sizeof(uint32_t)); + if (ret == -1) { + perror("Reading sysfs"); + exit(EXIT_FAILURE); + } + + assert(lseek(fd, 0, SEEK_SET) == 0); + + if (argc == 1) { + dumpit(); + exit(EXIT_SUCCESS); + } else if (!strncmp("-c", argv[1], 2)) { + memset(l3log, 0, sizeof(l3log)); + } else { + ret = do_parse(argc, argv); + if (ret != 0) { + fprintf(stderr, "Malformed command line at %s\n", argv[ret]); + exit(EXIT_FAILURE); + } + } + + ret = write(fd, l3log, NUM_REGS * sizeof(uint32_t)); + if (ret == -1) { + perror("Writing sysfs"); + exit(EXIT_FAILURE); + } + + close(fd); + + exit(EXIT_SUCCESS); +} diff --git a/tools/intel_lid.c b/tools/intel_lid.c new file mode 100644 index 00000000..908224ee --- /dev/null +++ b/tools/intel_lid.c @@ -0,0 +1,144 @@ +/* + * Copyright © 2009 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: + * Zhenyu Wang <zhenyu.z.wang@intel.com> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <pciaccess.h> +#include <err.h> +#include <fcntl.h> +#include <unistd.h> +#include <dirent.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "intel_gpu_tools.h" +#include "intel_reg.h" +#include "intel_bios.h" + +enum lid_status { + LID_UNKNOWN = -1, + LID_OPEN, + LID_CLOSE, +}; + +#define ACPI_BUTTON "/proc/acpi/button/" +#define ACPI_LID "/proc/acpi/button/lid/" + +static int i830_lvds_acpi_lid_state(void) +{ + int fd; + DIR *button_dir; + DIR *lid_dir; + struct dirent *lid_dent; + char *state_name; + char state[64]; + enum lid_status ret = LID_UNKNOWN; + + button_dir = opendir(ACPI_BUTTON); + /* If acpi button driver is not loaded, bypass ACPI check method */ + if (button_dir == NULL) + goto out; + closedir(button_dir); + + lid_dir = opendir(ACPI_LID); + + /* no acpi lid object found */ + if (lid_dir == NULL) + goto out; + + while (1) { + lid_dent = readdir(lid_dir); + if (lid_dent == NULL) { + /* no LID object */ + closedir(lid_dir); + goto out; + } + if (strcmp(lid_dent->d_name, ".") && + strcmp(lid_dent->d_name, "..")) { + break; + } + } + state_name = malloc(strlen(ACPI_LID) + strlen(lid_dent->d_name) + 7); + memset(state_name, 0, sizeof(state_name)); + strcat(state_name, ACPI_LID); + strcat(state_name, lid_dent->d_name); + strcat(state_name, "/state"); + + closedir(lid_dir); + + if ((fd = open(state_name, O_RDONLY)) == -1) { + free(state_name); + goto out; + } + free(state_name); + if (read(fd, state, 64) == -1) { + close(fd); + goto out; + } + close(fd); + if (strstr(state, "open")) + ret = LID_OPEN; + else if (strstr(state, "closed")) + ret = LID_CLOSE; + else /* "unsupported" */ + ret = LID_UNKNOWN; + +out: + return ret; +} + +int main(int argc, char **argv) +{ + int swf14, acpi_lid; + + intel_get_mmio(intel_get_pci_device()); + + while (1) { + swf14 = INREG(SWF14); + + printf("Intel LVDS Lid status:\n"); + printf("\tSWF14(0x%x) : %s\n", swf14, + swf14 & SWF14_LID_SWITCH_EN ? "close" : "open"); + + acpi_lid = i830_lvds_acpi_lid_state(); + switch (acpi_lid) { + case LID_UNKNOWN: + printf("\tACPI Lid state : unknown\n"); + break; + case LID_OPEN: + printf("\tACPI Lid state : open\n"); + break; + case LID_CLOSE: + printf("\tACPI Lid state : close\n"); + break; + } + sleep(2); + } + return 0; +} diff --git a/tools/intel_panel_fitter.c b/tools/intel_panel_fitter.c new file mode 100644 index 00000000..f6723d17 --- /dev/null +++ b/tools/intel_panel_fitter.c @@ -0,0 +1,344 @@ +/* + * Copyright © 2012 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: + * Paulo Zanoni <paulo.r.zanoni@intel.com> + */ + +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include "intel_gpu_tools.h" + +int gen; + +uint32_t HTOTAL[] = { 0x60000, 0x61000, 0x62000 }; +uint32_t VTOTAL[] = { 0x6000C, 0x6100C, 0x6200C }; +uint32_t PIPECONF[] = { 0x70008, 0x71008, 0x72008 }; +uint32_t PIPESRC[] = { 0x6001C, 0x6101C, 0x6201C }; +uint32_t PF_CTRL1[] = { 0x68080, 0x68880, 0x69080 }; +uint32_t PF_WIN_POS[] = { 0x68070, 0x68870, 0x69070 }; +uint32_t PF_WIN_SZ[] = { 0x68074, 0x68874, 0x69074 }; + +#define PIPECONF_ENABLE (1 << 31) +#define PIPECONF_INTERLACE_MASK (7 << 21) +#define PIPECONF_PF_PD (0 << 21) +#define PIPECONF_PF_ID (1 << 21) +#define PIPECONF_IF_ID (3 << 21) + +#define HTOTAL_ACTIVE_MASK (0xFFF << 0) +#define VTOTAL_ACTIVE_MASK (0xFFF << 0) + +#define PIPESRC_HORIZ_MASK (0xFFF << 16) +#define PIPESRC_VERT_MASK (0xFFF << 0) + +/*#define PF_ENABLE (1 << 31)*/ +#define PF_PIPE_MASK (3 << 29) +#define PF_FILTER_MASK (3 << 23) +#define PF_FILTER_MED (1 << 23) +#define PF_PIPE_A (0 << 29) +#define PF_PIPE_B (1 << 29) +#define PF_PIPE_C (2 << 29) + +#define PF_WIN_SZ_X_MASK (0x1FFF << 16) +#define PF_WIN_SZ_Y_MASK (0xFFF << 0) + +struct pipe_info { + bool enabled; + bool pf_enabled; + uint32_t interlace_mode; + uint32_t tot_width; /* htotal */ + uint32_t tot_height; /* vtotal */ + uint32_t src_width; /* pipesrc.x */ + uint32_t src_height; /* pipesrc.y */ + uint32_t dst_width; /* pf_win_sz.x */ + uint32_t dst_height; /* pf_win_sz.y */ +}; + +static void read_pipe_info(int intel_pipe, struct pipe_info *info) +{ + uint32_t conf, vtotal, htotal, src, ctrl1, win_sz; + + conf = INREG(PIPECONF[intel_pipe]); + htotal = INREG(HTOTAL[intel_pipe]); + vtotal = INREG(VTOTAL[intel_pipe]); + src = INREG(PIPESRC[intel_pipe]); + ctrl1 = INREG(PF_CTRL1[intel_pipe]); + win_sz = INREG(PF_WIN_SZ[intel_pipe]); + + info->enabled = (conf & PIPECONF_ENABLE) ? true : false; + info->tot_width = (htotal & HTOTAL_ACTIVE_MASK) + 1; + info->tot_height = (vtotal & VTOTAL_ACTIVE_MASK) + 1; + info->src_width = ((src & PIPESRC_HORIZ_MASK) >> 16) + 1; + info->src_height = (src & PIPESRC_VERT_MASK) + 1; + info->interlace_mode = conf & PIPECONF_INTERLACE_MASK; + info->pf_enabled = ctrl1 & PF_ENABLE; + info->dst_width = (win_sz & PF_WIN_SZ_X_MASK) >> 16; + info->dst_height = win_sz & PF_WIN_SZ_Y_MASK; +} + +static void dump_pipe(int intel_pipe) +{ + struct pipe_info info; + + read_pipe_info(intel_pipe, &info); + + printf("\nPipe %c:\n", intel_pipe + 'A'); + + printf("- %s\n", info.enabled ? "enabled" : "disabled"); + if (!info.enabled) + return; + + switch (info.interlace_mode) { + case PIPECONF_PF_PD: + printf("- progressive\n"); + break; + case PIPECONF_PF_ID: + printf("- interlaced (progressive fetch)\n"); + break; + case PIPECONF_IF_ID: + printf("- interlaced (interlaced fetch)\n"); + break; + default: + assert(0); + } + + printf("- pf %s\n", info.pf_enabled ? "enabled" : "disabled"); + if (!info.pf_enabled) + return; + + printf("- tot %dx%d\n", info.tot_width, info.tot_height); + printf("- src %dx%d\n", info.src_width, info.src_height); + printf("- dst %dx%d\n", info.dst_width, info.dst_height); +} + +static void dump_info(void) +{ + int i; + int pipes; + + if (gen < 7) + pipes = 2; + else + pipes = 3; + + for (i = 0; i < pipes; i++) { + dump_pipe(i); + } +} + +static int change_screen_size(int intel_pipe, int x, int y) +{ + struct pipe_info info; + uint32_t dst_width, dst_height, pos_x, pos_y; + uint32_t ctrl1_val; + uint32_t win_pos_val; + uint32_t win_sz_val; + + read_pipe_info(intel_pipe, &info); + + if (x == 0) { + if (info.dst_width != 0) + dst_width = info.dst_width; + else + dst_width = info.src_width; + } else { + dst_width = x; + } + + if (y == 0) { + if (info.dst_height != 0) + dst_height = info.dst_height; + else + dst_height = info.src_height; + } else { + dst_height = y; + } + + pos_x = abs((info.tot_width - dst_width)) / 2; + pos_y = abs((info.tot_height - dst_height)) / 2; + + if (pos_x == 1) + pos_x = 0; + + if (info.src_width / (double) dst_width > 1.125) { + printf("X is too small\n"); + return 1; + } else if (info.tot_width < dst_width) { + printf("X is too big\n"); + return 1; + } else if (dst_width & 1) { + printf("X must be even\n"); + return 1; + } else if (info.src_height / (double) dst_height > 1.125) { + printf("Y is too small\n"); + return 1; + } else if (info.tot_height < dst_height) { + printf("Y is too big\n"); + return 1; + } else if (dst_height & 1) { + printf("Y must be even\n"); + return 1; + } + + printf("Changing size for pipe %c:\n" + "- width: %d -> %d\n" + "- height: %d -> %d\n" + "- pos: %dx%d\n", + intel_pipe + 'A', info.src_width, dst_width, info.src_height, + dst_height, pos_x, pos_y); + + ctrl1_val = PF_ENABLE | PF_FILTER_MED; + + /* This can break stuff if the panel fitter is already enabled for + * another pipe */ + if (gen >= 7) { + switch (intel_pipe) { + case 0: + ctrl1_val |= PF_PIPE_A; + break; + case 1: + ctrl1_val |= PF_PIPE_B; + break; + case 2: + ctrl1_val |= PF_PIPE_C; + break; + default: + assert(0); + } + } + OUTREG(PF_CTRL1[intel_pipe], ctrl1_val); + + win_pos_val = pos_x << 16; + win_pos_val |= pos_y; + OUTREG(PF_WIN_POS[intel_pipe], win_pos_val); + + win_sz_val = dst_width << 16; + win_sz_val |= dst_height; + OUTREG(PF_WIN_SZ[intel_pipe], win_sz_val); + + return 0; +} + +static int disable_panel_fitter(int intel_pipe) +{ + OUTREG(PF_CTRL1[intel_pipe], 0); + OUTREG(PF_WIN_POS[intel_pipe], 0); + OUTREG(PF_WIN_SZ[intel_pipe], 0); + return 0; +} + +static void print_usage(void) +{ + printf("Options:\n" +" -p pipe: pipe to be used (A, B or C)\n" +" -x value: final screen width size in pixels\n" +" -y value: final screen height size in pixels\n" +" -d: disable panel fitter\n" +" -l: list the current state of each pipe\n" +" -h: prints this message\n"); +} + +int main (int argc, char *argv[]) +{ + int opt; + int ret = 0; + char intel_pipe = '\0'; + int x = 0, y = 0; + bool do_disable = false, do_dump = false, do_usage = false; + struct pci_device *pci_dev; + uint32_t devid; + + printf("WARNING:\n" + "This tool is a workaround for people that don't have a Kernel " + "with overscan compensation properties: it is just a temporary " + "solution that may or may not work. Use it at your own risk.\n"); + + pci_dev = intel_get_pci_device(); + intel_register_access_init(pci_dev, 0); + devid = pci_dev->device_id; + + if (!HAS_PCH_SPLIT(devid)) { + printf("This tool was only tested on Ironlake and newer\n"); + ret = 1; + goto out; + } + if (IS_GEN5(devid)) + gen = 5; + else if (IS_GEN6(devid)) + gen = 6; + else + gen = 7; + + while ((opt = getopt(argc, argv, "p:x:y:dlh")) != -1) { + switch (opt) { + case 'p': + intel_pipe = optarg[0]; + if (intel_pipe != 'A' && intel_pipe != 'B' && + (gen <= 6 || intel_pipe != 'C')) { + printf("Invalid pipe\n"); + ret = 1; + goto out; + } + break; + case 'x': + x = atoi(optarg); + break; + case 'y': + y = atoi(optarg); + break; + case 'd': + do_disable = true; + break; + case 'l': + do_dump = true; + break; + case 'h': + do_usage = true; + break; + default: + do_usage = true; + ret = 1; + } + } + + if (do_usage) { + print_usage(); + } else if (do_dump) { + dump_info(); + } else if (intel_pipe) { + if (do_disable) + ret = disable_panel_fitter(intel_pipe - 'A'); + else + ret = change_screen_size(intel_pipe - 'A', x, y); + } else { + print_usage(); + ret = 1; + } + +out: + intel_register_access_fini(); + return ret; +} diff --git a/tools/intel_reg_checker.c b/tools/intel_reg_checker.c new file mode 100644 index 00000000..daa8d0fb --- /dev/null +++ b/tools/intel_reg_checker.c @@ -0,0 +1,399 @@ +/* Copyright © 2011 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 <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include <stdbool.h> +#include "intel_gpu_tools.h" + +static uint32_t devid; +static int gen; + +static inline uint32_t +read_reg(uint32_t reg) +{ + return *(volatile uint32_t *)((volatile char *)mmio + reg); +} + +static uint32_t +read_and_print_reg(const char *name, uint32_t reg) +{ + uint32_t val = read_reg(reg); + + printf("%s (0x%x): 0x%08x\n", name, reg, val); + + return val; +} + +static void +check_chicken_unset(const char *name, uint32_t reg) +{ + uint32_t val = read_and_print_reg(name, reg); + + + if (val != 0) { + fprintf(stderr, " WARN: chicken bits set\n"); + } else { + printf(" OK: chicken bits unset\n"); + } +} + +static void +check_bit(uint32_t val, int bit, const char *bitname, bool set) +{ + if (!!(val & (1 << bit)) != set) { + fprintf(stderr, " (bit %2d) FAIL: %s must be %s\n", + bit, bitname, set ? "set" : "unset"); + } else { + printf(" (bit %2d) OK: %s\n", bit, bitname); + } +} + +static void +check_perf_bit(uint32_t val, int bit, const char *bitname, bool set) +{ + if (!!(val & (1 << bit)) != set) { + printf(" (bit %2d) PERF: %s should be %s\n", + bit, bitname, set ? "set" : "unset"); + } else { + printf(" (bit %2d) OK: %s\n", bit, bitname); + } +} + +static void +check_mi_mode(void) +{ + /* Described in page 14-16 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + + uint32_t mi_mode = read_and_print_reg("MI_MODE", 0x209c); + + /* From page 14: + * + * Async Flip Performance mode + * Project: All + * Default Value: 0h + * Format: U1 + * [DevSNB] This bit must be set to ‘1’ + */ + if (gen == 6) + check_bit(mi_mode, 14, "Async Flip Performance mode", true); + else + check_perf_bit(mi_mode, 14, "Async Flip Performance mode", + false); + + check_perf_bit(mi_mode, 13, "Flush Performance Mode", false); + + /* Our driver relies on MI_FLUSH, unfortunately. */ + if (gen >= 6) + check_bit(mi_mode, 12, "MI_FLUSH enable", true); + + /* From page 15: + * + * "1h: LRA mode of allocation. Used for validation purposes" + */ + if (gen < 7) + check_bit(mi_mode, 7, "Vertex Shader Cache Mode", false); + + /* From page 16: + * + * "To avoid deadlock conditions in hardware this bit + * needs to be set for normal operation. + */ + check_bit(mi_mode, 6, "Vertex Shader Timer Dispatch Enable", true); +} + +static void +check_gfx_mode(void) +{ + /* Described in page 17-19 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t gfx_mode; + + if (gen < 6) + return; + + if (gen == 6) + gfx_mode = read_and_print_reg("GFX_MODE", 0x2520); + else + gfx_mode = read_and_print_reg("GFX_MODE", 0x229c); + + /* Our driver only updates page tables at batchbuffer + * boundaries, so we don't need TLB flushes at other times. + */ + check_perf_bit(gfx_mode, 13, "Flush TLB Invalidation Mode", true); +} + +static void +check_gt_mode(void) +{ + /* Described in page 20-22 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t gt_mode; + + if (gen < 6) + return; + + if (gen == 6) + gt_mode = read_and_print_reg("GT_MODE", 0x20d0); + else + gt_mode = read_and_print_reg("GT_MODE", 0x7008); + + if (gen == 6) + check_perf_bit(gt_mode, 8, "Full Rate Sampler Disable", false); + + /* For DevSmallGT, this bit must be set, which means disable + * hashing. + */ + if (devid == PCI_CHIP_SANDYBRIDGE_GT1 || + devid == PCI_CHIP_SANDYBRIDGE_M_GT1) + check_bit(gt_mode, 6, "WIZ Hashing disable", true); + else if (gen == 6) + check_perf_bit(gt_mode, 6, "WIZ Hashing disable", false); + + if (gen == 6) { + check_perf_bit(gt_mode, 5, "TD Four Row Dispatch Disable", + false); + check_perf_bit(gt_mode, 4, "Full Size URB Disable", false); + check_perf_bit(gt_mode, 3, "Full Size SF FIFO Disable", false); + check_perf_bit(gt_mode, 1, "VS Quad Thread Dispatch Disable", + false); + } +} + +static void +check_cache_mode_0(void) +{ + /* Described in page 23-25 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t cache_mode_0; + + if (gen >= 7) + cache_mode_0 = read_and_print_reg("CACHE_MODE_0", 0x7000); + else + cache_mode_0 = read_and_print_reg("CACHE_MODE_0", 0x2120); + + check_perf_bit(cache_mode_0, 15, "Sampler L2 Disable", false); + check_perf_bit(cache_mode_0, 9, "Sampler L2 TLB Prefetch Enable", true); + check_perf_bit(cache_mode_0, 8, + "Depth Related Cache Pipelined Flush Disable", false); + + /* From page 24: + * + * "If this bit is set, RCCunit will have LRA as + * replacement policy. The default value i.e. ( when this + * bit is reset ) indicates that non-LRA eviction + * policy. This bit must be reset. LRA replacement policy + * is not supported." + * + * And the same for STC Eviction Policy. + */ + check_bit(cache_mode_0, 5, "STC LRA Eviction Policy", false); + if (gen >= 6) + check_bit(cache_mode_0, 4, "RCC LRA Eviction Policy", false); + + check_perf_bit(cache_mode_0, 3, "Hierarchical Z Disable", false); + + if (gen == 6) { + check_perf_bit(cache_mode_0, 2, + "Hierarchical Z RAW Stall Optimization " + "Disable", false); + } + + /* From page 25: + * + * "This bit must be 0. Operational Flushes [DevSNB] are + * not supported in [DevSNB]. SW must flush the render + * target after front buffer rendering." + */ + check_bit(cache_mode_0, 0, "Render Cache Operational Flush", false); +} + + +static void +check_cache_mode_1(void) +{ + /* Described in page 23-25 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t cache_mode_1; + + if (gen >= 7) + cache_mode_1 = read_and_print_reg("CACHE_MODE_1", 0x7004); + else + cache_mode_1 = read_and_print_reg("CACHE_MODE_1", 0x2124); + + if (gen >= 7) { + check_perf_bit(cache_mode_1, 13, + "STC Address Lookup Optimization Disable", + false); + } + + /* From page 24: + * + * "If this bit is set, Hizunit will have LRA as + * replacement policy. The default value i.e. (when this + * bit is reset) indicates the non-LRA eviction + * policy. For performance reasons, this bit must be + * reset." + */ + check_bit(cache_mode_1, 12, "HIZ LRA Eviction Policy", false); + + /* Page 26 describes these bits as reserved (debug only). */ + check_bit(cache_mode_1, 11, + "DAP Instruction and State Cache Invalidate", false); + check_bit(cache_mode_1, 10, + "Instruction L1 Cache and In-Flight Queue Disable", + false); + check_bit(cache_mode_1, 9, "Instruction L2 Cache Fill Buffers Disable", + false); + + + if (gen >= 7) { + check_perf_bit(cache_mode_1, 6, + "Pixel Backend sub-span collection " + "Optimization Disable", + false); + check_perf_bit(cache_mode_1, 5, "MCS Cache Disable", false); + } + check_perf_bit(cache_mode_1, 4, "Data Disable", false); + + if (gen == 6) { + /* In a later update of the documentation, it says: + * + * "[DevSNB:A0{WKA1}] [DevSNB]: This bit must be + * set for depth buffer format + * D24_UNORM_S8_UINT." + * + * XXX: Does that mean A0 only, or all DevSNB? + */ + check_perf_bit(cache_mode_1, 3, + "Depth Read Hit Write-Only Optimization " + "Disable", false); + + check_perf_bit(cache_mode_1, 2, + "Depth Cache LRA Hunt Feature Disable", + false); + } + + check_bit(cache_mode_1, 1, "Instruction and State L2 Cache Disable", + false); + check_bit(cache_mode_1, 0, "Instruction and State L1 Cache Disable", + false); +} + + +static void +check_3d_chicken4(void) +{ + /* Described in page 23-25 of the IHD_OS_Vol1_Part3.pdf + * specification. + */ + uint32_t _3d_chicken4 = read_and_print_reg("3D_CHICKEN4", 0x20d4); + + check_perf_bit(_3d_chicken4, 6, "3D Scoreboard Hashing Enable", true); + + if (_3d_chicken4 & 0x0fbf) { + fprintf(stderr, + " WARN: other non-thread deps bits set\n"); + } else { + printf(" OK: other non-thread deps bits unset\n"); + } +} + +static void +check_dpfc_control_sa(void) +{ + uint32_t dpfc_control_sa; + + if (gen != 6) + return; + + dpfc_control_sa = read_and_print_reg("DPFC_CONTROL_SA", 0x100100); + + /* This is needed for framebuffer compression for us to be + * able to access the framebuffer by the CPU through the GTT. + */ + check_bit(dpfc_control_sa, 29, "CPU Fence Enable", true); +} + +int main(int argc, char** argv) +{ + struct pci_device *dev; + + dev = intel_get_pci_device(); + devid = dev->device_id; + intel_get_mmio(dev); + + if (IS_GEN7(devid)) + gen = 7; + else if (IS_GEN6(devid)) + gen = 6; + else if (IS_GEN5(devid)) + gen = 5; + else + gen = 4; + + check_mi_mode(); + check_gfx_mode(); + check_gt_mode(); + check_cache_mode_0(); + check_cache_mode_1(); + + if (gen < 7) { + check_chicken_unset("3D_CHICKEN", 0x2084); + check_chicken_unset("3D_CHICKEN2", 0x208c); + } else { + check_chicken_unset("FF_SLICE_CHICKEN", 0x2088); + } + if (gen >= 6) + check_chicken_unset("3D_CHICKEN3", 0x2090); + if (gen == 6) + check_3d_chicken4(); + + if (gen >= 7) { + check_chicken_unset("FF_SLICE_CS_CHICKEN1", 0x20e0); + check_chicken_unset("FF_SLICE_CS_CHICKEN2", 0x20e4); + check_chicken_unset("FF_SLICE_CS_CHICKEN3", 0x20e8); + check_chicken_unset("COMMON_SLICE_CHICKEN1", 0x7010); + check_chicken_unset("COMMON_SLICE_CHICKEN2", 0x7014); + check_chicken_unset("WM_CHICKEN", 0x5580); + check_chicken_unset("HALF_SLICE_CHICKEN", 0xe100); + check_chicken_unset("HALF_SLICE_CHICKEN2", 0xe180); + check_chicken_unset("ROW_CHICKEN", 0xe4f0); + check_chicken_unset("ROW_CHICKEN2", 0xe4f4); + } + + check_chicken_unset("ECOSKPD", 0x21d0); + + check_dpfc_control_sa(); + + return 0; +} + diff --git a/tools/intel_reg_dumper.c b/tools/intel_reg_dumper.c new file mode 100644 index 00000000..b49d967b --- /dev/null +++ b/tools/intel_reg_dumper.c @@ -0,0 +1,2246 @@ +/* + * Copyright © 2006,2009 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> + * + */ + +#define _GNU_SOURCE +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <unistd.h> +#include "intel_gpu_tools.h" + +static uint32_t devid = 0; + +#define DEBUGSTRING(func) static void func(char *result, int len, int reg, uint32_t val) + +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)) + 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, *interlace; + + if (IS_965(devid)) + bit30 = val & I965_PIPECONF_ACTIVE ? "active" : "inactive"; + else + bit30 = + val & PIPEACONF_DOUBLE_WIDE ? "double-wide" : "single-wide"; + + if (HAS_PCH_SPLIT(devid)) { + const char *bpc, *rotation; + + switch ((val >> 21) & 7) { + 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; + } + + 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; + } + + 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; + } + snprintf(result, len, "%s, %s, %s, %s, %s", enabled, bit30, + interlace, rotation, bpc); + } else if (IS_GEN4(devid)) { + 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; + } + snprintf(result, len, "%s, %s, %s", enabled, bit30, interlace); + } else + snprintf(result, len, "%s, %s", enabled, bit30); +} + +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, p2 = 0; + + if (IS_GEN2(devid)) { + 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; + } + } 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, 0 } +#define DEFINEREG_16BIT(reg) \ + { reg, #reg, i830_16bit_func, 0 } +#define DEFINEREG2(reg, func) \ + { reg, #reg, func, 0 } + +struct reg_debug { + int reg; + const char *name; + void (*debug_output) (char *result, int len, int reg, uint32_t val); + uint32_t val; +}; + +static 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(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, 0 } +#define DEFINEFENCE_945(i) \ + { FENCE_NEW+(i - 8) * 4, "FENCE " #i, i810_debug_915_fence, 0 } + + 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, 0 }, \ + { FENCE_NEW+i*8+4, "FENCE END " #i, i810_debug_965_fence_end, 0 } + + 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"); +} + +static struct reg_debug ironlake_debug_regs[] = { + DEFINEREG(PGETBL_CTL), + DEFINEREG(GEN6_INSTDONE_1), + DEFINEREG(GEN6_INSTDONE_2), + 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), + + 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), + + DEFINEREG(BLC_PWM_CPU_CTL2), + DEFINEREG(BLC_PWM_CPU_CTL), + DEFINEREG(BLC_PWM_PCH_CTL1), + DEFINEREG(BLC_PWM_PCH_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 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 */ + DEFINEREG(PIPE_DDI_FUNC_CTL_A), + DEFINEREG(PIPE_DDI_FUNC_CTL_B), + DEFINEREG(PIPE_DDI_FUNC_CTL_C), + DEFINEREG(PIPE_DDI_FUNC_CTL_EDP), + + /* 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_A), + DEFINEREG(DP_TP_STATUS_B), + DEFINEREG(DP_TP_STATUS_C), + DEFINEREG(DP_TP_STATUS_D), + DEFINEREG(DP_TP_STATUS_E), + + /* DDI buffer control */ + DEFINEREG(DDI_BUF_CTL_A), + DEFINEREG(DDI_BUF_CTL_B), + DEFINEREG(DDI_BUF_CTL_C), + DEFINEREG(DDI_BUF_CTL_D), + DEFINEREG(DDI_BUF_CTL_E), + + /* Clocks */ + DEFINEREG(PIXCLK_GATE), + DEFINEREG(SPLL_CTL), + DEFINEREG(LCPLL_CTL), + DEFINEREG(WRPLL_CTL1), + DEFINEREG(WRPLL_CTL2), + + /* DDI port clock control */ + DEFINEREG(PORT_CLK_SEL_A), + DEFINEREG(PORT_CLK_SEL_B), + DEFINEREG(PORT_CLK_SEL_C), + DEFINEREG(PORT_CLK_SEL_D), + DEFINEREG(PORT_CLK_SEL_E), + + /* Pipe clock control */ + DEFINEREG(PIPE_CLK_SEL_A), + DEFINEREG(PIPE_CLK_SEL_B), + DEFINEREG(PIPE_CLK_SEL_C), + + /* Pipe line time */ + DEFINEREG(PIPE_WM_LINETIME_A), + DEFINEREG(PIPE_WM_LINETIME_B), + DEFINEREG(PIPE_WM_LINETIME_C), + + /* Fuses */ + DEFINEREG(SFUSE_STRAP), + +}; + +static struct reg_debug i945gm_mi_regs[] = { + DEFINEREG(PGETBL_CTL), + DEFINEREG(PGTBL_ER), + DEFINEREG(EXCC), + DEFINEREG(HWS_PGA), + DEFINEREG(IPEIR), + DEFINEREG(IPEHR), + DEFINEREG(INST_DONE), + 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), +}; + +#define intel_dump_regs(regs) _intel_dump_regs(regs, ARRAY_SIZE(regs)) + +static void +_intel_dump_regs(struct reg_debug *regs, int count) +{ + char debug[1024]; + int i; + + for (i = 0; i < count; i++) { + uint32_t val = INREG(regs[i].reg); + + if (regs[i].debug_output != NULL) { + regs[i].debug_output(debug, sizeof(debug), regs[i].reg, val); + printf("%30.30s: 0x%08x (%s)\n", + regs[i].name, + (unsigned int)val, debug); + } else { + printf("%30.30s: 0x%08x\n", regs[i].name, + (unsigned int)val); + } + } +} + +DEBUGSTRING(gen6_rp_control) +{ + snprintf(result, len, "%s", + (val & (1 << 7)) ? "enabled" : "disabled"); +} + +static 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 void +intel_dump_other_regs(void) +{ + int i; + int fp, dpll; + int disp_pipe; + int n, m1, m2, m, p1, p2; + int ref; + int dot; + int phase; +#if 0 + int msr; + int crt; +#endif + +#if 0 + i830DumpIndexed(pScrn, "SR", 0x3c4, 0x3c5, 0, 7); + msr = INREG8(0x3cc); + printf("%20.20s: 0x%02x\n", + "MSR", (unsigned int)msr); + + i830DumpAR(pScrn); + if (msr & 1) + crt = 0x3d0; + else + crt = 0x3b0; + i830DumpIndexed(pScrn, "CR", crt + 4, crt + 5, 0, 0x24); +#endif + for (disp_pipe = 0; disp_pipe <= 1; disp_pipe++) { + fp = INREG(disp_pipe == 0 ? FPA0 : FPB0); + dpll = INREG(disp_pipe == 0 ? DPLL_A : DPLL_B); + if (IS_GEN2(devid)) { + uint32_t lvds = INREG(LVDS); + if (devid == PCI_CHIP_I855_GM && + (lvds & LVDS_PORT_EN) && + (lvds & LVDS_PIPEB_SELECT) == (disp_pipe << 30)) { + if ((lvds & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) + p2 = 7; + else + p2 = 14; + switch ((dpll >> 16) & 0x3f) { + case 0x01: + p1 = 1; + break; + case 0x02: + p1 = 2; + break; + case 0x04: + p1 = 3; + break; + case 0x08: + p1 = 4; + break; + case 0x10: + p1 = 5; + break; + case 0x20: + p1 = 6; + break; + default: + p1 = 1; + printf("LVDS P1 0x%x invalid encoding\n", + (dpll >> 16) & 0x3f); + break; + } + } else { + if (dpll & (1 << 23)) + p2 = 4; + else + p2 = 2; + if (dpll & PLL_P1_DIVIDE_BY_TWO) + p1 = 2; + else + p1 = ((dpll >> 16) & 0x3f) + 2; + } + + switch ((dpll >> 13) & 0x3) { + case 0: + ref = 48000; + break; + case 3: + ref = 66000; + break; + default: + ref = 0; + printf("ref out of range\n"); + break; + } + } else { + uint32_t lvds = INREG(LVDS); + if ((lvds & LVDS_PORT_EN) && + (lvds & LVDS_PIPEB_SELECT) == (disp_pipe << 30)) { + if ((lvds & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) + p2 = 7; + else + p2 = 14; + } else { + switch ((dpll >> 24) & 0x3) { + case 0: + p2 = 10; + break; + case 1: + p2 = 5; + break; + default: + p2 = 1; + printf("p2 out of range\n"); + break; + } + } + if (IS_IGD(devid)) + i = (dpll >> DPLL_FPA01_P1_POST_DIV_SHIFT_IGD) & + 0x1ff; + else + i = (dpll >> DPLL_FPA01_P1_POST_DIV_SHIFT) & + 0xff; + switch (i) { + case 1: + p1 = 1; + break; + case 2: + p1 = 2; + break; + case 4: + p1 = 3; + break; + case 8: + p1 = 4; + break; + case 16: + p1 = 5; + break; + case 32: + p1 = 6; + break; + case 64: + p1 = 7; + break; + case 128: + p1 = 8; + break; + case 256: + if (IS_IGD(devid)) { + p1 = 9; + break; + } /* fallback */ + default: + p1 = 1; + printf("p1 out of range\n"); + break; + } + + switch ((dpll >> 13) & 0x3) { + case 0: + ref = 96000; + break; + case 3: + ref = 100000; + break; + default: + ref = 0; + printf("ref out of range\n"); + break; + } + } + if (IS_965(devid)) { + phase = (dpll >> 9) & 0xf; + switch (phase) { + case 6: + break; + default: + printf("SDVO phase shift %d out of range -- probobly not " + "an issue.\n", phase); + break; + } + } + switch ((dpll >> 8) & 1) { + case 0: + break; + default: + printf("fp select out of range\n"); + break; + } + m1 = ((fp >> 8) & 0x3f); + if (IS_IGD(devid)) { + n = ffs((fp & FP_N_IGD_DIV_MASK) >> FP_N_DIV_SHIFT) - 1; + m2 = (fp & FP_M2_IGD_DIV_MASK) >> FP_M2_DIV_SHIFT; + m = m2 + 2; + dot = (ref * m) / n / (p1 * p2); + } else { + n = ((fp >> 16) & 0x3f); + m2 = ((fp >> 0) & 0x3f); + m = 5 * (m1 + 2) + (m2 + 2); + dot = + (ref * (5 * (m1 + 2) + (m2 + 2)) / (n + 2)) / (p1 * + p2); + } + + printf("pipe %s dot %d n %d m1 %d m2 %d p1 %d p2 %d\n", + disp_pipe == 0 ? "A" : "B", dot, n, m1, m2, p1, p2); + } +} + +static void print_usage(void) +{ + printf("Usage: intel_reg_dumper [options] [file]\n" + "Options:\n" + " -d id when a dump file is used, use 'id' as device id (in " + "hex)\n" + " -h prints this help\n"); +} + +int main(int argc, char** argv) +{ + struct pci_device *pci_dev; + int opt; + char *file = NULL; + + while ((opt = getopt(argc, argv, "d:h")) != -1) { + switch (opt) { + case 'd': + devid = strtol(optarg, NULL, 16); + break; + case 'h': + print_usage(); + return 0; + default: + print_usage(); + return 1; + } + } + if (optind < argc) + file = argv[optind]; + + if (file) { + intel_map_file(file); + if (devid) { + if (IS_GEN5(devid)) + pch = PCH_IBX; + else + pch = PCH_CPT; + } else { + printf("Dumping from file without -d argument. " + "Assuming Ironlake machine.\n"); + devid = 0x0042; + pch = PCH_IBX; + } + } else { + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; + + intel_register_access_init(pci_dev, 1); + + if (HAS_PCH_SPLIT(devid)) + intel_check_pch(); + } + + if (HAS_PCH_SPLIT(devid)) { + intel_dump_regs(ironlake_debug_regs); + } else if (IS_945GM(devid)) { + intel_dump_regs(i945gm_mi_regs); + intel_dump_regs(intel_debug_regs); + intel_dump_other_regs(); + } else { + intel_dump_regs(intel_debug_regs); + intel_dump_other_regs(); + } + + if (IS_GEN6(devid) || IS_GEN7(devid)) + intel_dump_regs(gen6_rp_debug_regs); + + if (IS_HASWELL(devid)) + intel_dump_regs(haswell_debug_regs); + + + intel_register_access_fini(); + return 0; +} diff --git a/tools/intel_reg_read.c b/tools/intel_reg_read.c new file mode 100644 index 00000000..ae631be0 --- /dev/null +++ b/tools/intel_reg_read.c @@ -0,0 +1,142 @@ +/* + * Copyright © 2010 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: + * Zhenyu Wang <zhenyuw@linux.intel.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <string.h> +#include "intel_gpu_tools.h" + +static void bit_decode(uint32_t reg) +{ + int i; + + for (i=31; i >= 0; i--) + printf(" %2d", i); + printf("\n"); + + for (i=31; i >= 0; i--) + printf(" %2d", (reg & (1 << i)) && 1); + printf("\n"); +} + +static void dump_range(uint32_t start, uint32_t end) +{ + int i; + + for (i = start; i < end; i += 4) + printf("0x%X : 0x%X\n", i, + *(volatile uint32_t *)((volatile char*)mmio + i)); +} + +static void usage(char *cmdname) +{ + printf("Usage: %s [-f|-d] [addr1] [addr2] .. [addrN]\n", cmdname); + printf("\t -f : read back full range of registers.\n"); + printf("\t WARNING! This option may result in a machine hang!\n"); + printf("\t -d : decode register bits.\n"); + printf("\t -c : number of dwords to dump (can't be used with -f/-d).\n"); + printf("\t addr : in 0xXXXX format\n"); +} + +int main(int argc, char** argv) +{ + int ret = 0; + uint32_t reg; + int i, ch; + char *cmdname = strdup(argv[0]); + int full_dump = 0; + int decode_bits = 0; + int dwords = 1; + + while ((ch = getopt(argc, argv, "dfhc:")) != -1) { + switch(ch) { + case 'd': + decode_bits = 1; + break; + case 'f': + full_dump = 1; + break; + case 'h': + usage(cmdname); + ret = 1; + goto out; + case 'c': + dwords = strtol(optarg, NULL, 0); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(cmdname); + ret = 1; + goto out; + } + + if ((dwords > 1) && (argc != 1 || full_dump || decode_bits)) { + usage(cmdname); + ret = 1; + goto out; + } + + intel_register_access_init(intel_get_pci_device(), 0); + + if (full_dump) { + dump_range(0x00000, 0x00fff); /* VGA registers */ + dump_range(0x02000, 0x02fff); /* instruction, memory, interrupt control registers */ + dump_range(0x03000, 0x031ff); /* FENCE and PPGTT control registers */ + dump_range(0x03200, 0x03fff); /* frame buffer compression registers */ + dump_range(0x05000, 0x05fff); /* I/O control registers */ + dump_range(0x06000, 0x06fff); /* clock control registers */ + dump_range(0x07000, 0x07fff); /* 3D internal debug registers */ + dump_range(0x07400, 0x088ff); /* GPE debug registers */ + dump_range(0x0a000, 0x0afff); /* display palette registers */ + dump_range(0x10000, 0x13fff); /* MMIO MCHBAR */ + dump_range(0x30000, 0x3ffff); /* overlay registers */ + dump_range(0x60000, 0x6ffff); /* display engine pipeline registers */ + dump_range(0x70000, 0x72fff); /* display and cursor registers */ + dump_range(0x73000, 0x73fff); /* performance counters */ + } else { + for (i=0; i < argc; i++) { + sscanf(argv[i], "0x%x", ®); + dump_range(reg, reg + (dwords * 4)); + + if (decode_bits) + bit_decode(*(volatile uint32_t *)((volatile char*)mmio + reg)); + } + } + + intel_register_access_fini(); + +out: + free(cmdname); + return ret; +} + diff --git a/tools/intel_reg_snapshot.c b/tools/intel_reg_snapshot.c new file mode 100644 index 00000000..83e76e5c --- /dev/null +++ b/tools/intel_reg_snapshot.c @@ -0,0 +1,48 @@ +/* + * Copyright © 2010 Red Hat, Inc. + * + * 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: + * Adam Jackson <ajax@redhat.com> + */ + +#include <unistd.h> +#include "intel_gpu_tools.h" + +int main(int argc, char** argv) +{ + struct pci_device *pci_dev; + uint32_t devid; + int mmio_bar; + + pci_dev = intel_get_pci_device(); + devid = pci_dev->device_id; + intel_get_mmio(pci_dev); + + if (IS_GEN2(devid)) + mmio_bar = 1; + else + mmio_bar = 0; + + write(1, mmio, pci_dev->regions[mmio_bar].size); + + return 0; +} diff --git a/tools/intel_reg_write.c b/tools/intel_reg_write.c new file mode 100644 index 00000000..dd636f65 --- /dev/null +++ b/tools/intel_reg_write.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2007 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: + * Ben Gamari <bgamari.foss@gmail.com> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include "intel_gpu_tools.h" + +int main(int argc, char** argv) +{ + uint32_t reg, value; + volatile uint32_t *ptr; + + if (argc < 3) { + printf("Usage: %s addr value\n", argv[0]); + printf(" WARNING: This is dangerous to you and your system's health.\n"); + printf(" Only for use in debugging.\n"); + exit(1); + } + + intel_register_access_init(intel_get_pci_device(), 0); + sscanf(argv[1], "0x%x", ®); + sscanf(argv[2], "0x%x", &value); + ptr = (volatile uint32_t *)((volatile char *)mmio + reg); + + printf("Value before: 0x%X\n", *ptr); + *ptr = value; + printf("Value after: 0x%X\n", *ptr); + + intel_register_access_fini(); + return 0; +} + diff --git a/tools/intel_stepping.c b/tools/intel_stepping.c new file mode 100644 index 00000000..f6f15d1a --- /dev/null +++ b/tools/intel_stepping.c @@ -0,0 +1,294 @@ +/* + * Copyright © 2007 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <pciaccess.h> +#include <err.h> +#include "intel_chipset.h" +#include "intel_gpu_tools.h" + +static void +print_clock(const char *name, int clock) { + if (clock == -1) + printf("%s clock: unknown", name); + else + printf("%s clock: %d Mhz", name, clock); +} + +static int +print_clock_info(struct pci_device *pci_dev) +{ + uint32_t devid = pci_dev->device_id; + uint16_t gcfgc; + + if (IS_GM45(devid)) { + int core_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0xf) { + case 8: + core_clock = 266; + break; + case 9: + core_clock = 320; + break; + case 11: + core_clock = 400; + break; + case 13: + core_clock = 533; + break; + } + print_clock("core", core_clock); + } else if (IS_965(devid) && IS_MOBILE(devid)) { + int render_clock = -1, sampler_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0xf) { + case 2: + render_clock = 250; sampler_clock = 267; + break; + case 3: + render_clock = 320; sampler_clock = 333; + break; + case 4: + render_clock = 400; sampler_clock = 444; + break; + case 5: + render_clock = 500; sampler_clock = 533; + break; + } + + print_clock("render", render_clock); + printf(" "); + print_clock("sampler", sampler_clock); + } else if (IS_945(devid) && IS_MOBILE(devid)) { + int render_clock = -1, display_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0x7) { + case 0: + render_clock = 166; + break; + case 1: + render_clock = 200; + break; + case 3: + render_clock = 250; + break; + case 5: + render_clock = 400; + break; + } + + switch (gcfgc & 0x70) { + case 0: + display_clock = 200; + break; + case 4: + display_clock = 320; + break; + } + if (gcfgc & (1 << 7)) + display_clock = 133; + + print_clock("render", render_clock); + printf(" "); + print_clock("display", display_clock); + } else if (IS_915(devid) && IS_MOBILE(devid)) { + int render_clock = -1, display_clock = -1; + + pci_device_cfg_read_u16(pci_dev, &gcfgc, I915_GCFGC); + + switch (gcfgc & 0x7) { + case 0: + render_clock = 160; + break; + case 1: + render_clock = 190; + break; + case 4: + render_clock = 333; + break; + } + if (gcfgc & (1 << 13)) + render_clock = 133; + + switch (gcfgc & 0x70) { + case 0: + display_clock = 190; + break; + case 4: + display_clock = 333; + break; + } + if (gcfgc & (1 << 7)) + display_clock = 133; + + print_clock("render", render_clock); + printf(" "); + print_clock("display", display_clock); + } + + printf("\n"); + return -1; +} + +int main(int argc, char **argv) +{ + struct pci_device *dev, *bridge; + int error; + uint8_t stepping; + const char *step_desc = "??"; + + error = pci_system_init(); + if (error != 0) { + fprintf(stderr, "Couldn't initialize PCI system: %s\n", + strerror(error)); + exit(1); + } + + /* Grab the graphics card */ + dev = pci_device_find_by_slot(0, 0, 2, 0); + if (dev == NULL) + errx(1, "Couldn't find graphics card"); + + error = pci_device_probe(dev); + if (error != 0) { + fprintf(stderr, "Couldn't probe graphics card: %s\n", + strerror(error)); + exit(1); + } + + if (dev->vendor_id != 0x8086) + errx(1, "Graphics card is non-intel"); + + bridge = pci_device_find_by_slot(0, 0, 0, 0); + if (dev == NULL) + errx(1, "Couldn't bridge"); + + error = pci_device_cfg_read_u8(bridge, &stepping, 8); + if (error != 0) { + fprintf(stderr, "Couldn't read revision ID: %s\n", + strerror(error)); + exit(1); + } + + switch (dev->device_id) { + case PCI_CHIP_I915_G: + if (stepping < 0x04) + step_desc = "<B1"; + else if (stepping == 0x04) + step_desc = "B1"; + else if (stepping == 0x0e) + step_desc = "C2"; + else if (stepping > 0x0e) + step_desc = ">C2"; + else + step_desc = ">B1 <C2"; + break; + case PCI_CHIP_I915_GM: + if (stepping < 0x03) + step_desc = "<B1"; + else if (stepping == 0x03) + step_desc = "B1/C0"; + else if (stepping == 0x04) + step_desc = "C1/C2"; + else + step_desc = ">C2"; + break; + case PCI_CHIP_I945_GM: + if (stepping < 0x03) + step_desc = "<A3"; + else if (stepping == 0x03) + step_desc = "A3"; + else + step_desc = ">A3"; + break; + case PCI_CHIP_I965_G: + case PCI_CHIP_I965_Q: + if (stepping < 0x02) + step_desc = "<C1"; + else if (stepping == 0x02) + step_desc = "C1/C2"; + else + step_desc = ">C2"; + break; + case PCI_CHIP_I965_GM: + if (stepping < 0x03) + step_desc = "<C0"; + else if (stepping == 0x03) + step_desc = "C0"; + else + step_desc = ">C0"; + break; + case PCI_CHIP_I965_G_1: + if (stepping < 0x03) + step_desc = "<E0"; + else if (stepping == 0x03) + step_desc = "E0"; + else + step_desc = ">E0"; + break; + case PCI_CHIP_GM45_GM: + if (stepping < 0x07) + step_desc = "<B3"; + else if (stepping == 0x03) + step_desc = "B3"; + else + step_desc = ">B3"; + break; + case PCI_CHIP_G45_G: + case PCI_CHIP_Q45_G: + case PCI_CHIP_G41_G: + if (stepping < 0x02) + step_desc = "<A2"; + else if (stepping == 0x02) + step_desc = "A2"; + else if (stepping == 0x03) + step_desc = "A3"; + else + step_desc = ">A3"; + break; + } + + printf("Vendor: 0x%04x, Device: 0x%04x, Revision: 0x%02x (%s)\n", + dev->vendor_id, + dev->device_id, + stepping, + step_desc); + + print_clock_info(dev); + + return 0; +} |