On Fri, Apr 13, 2012 at 10:27:01AM -0300, Paulo Zanoni wrote: > From: Paulo Zanoni <paulo.r.zanoni at intel.com> > > This is a command-line tool that allows us to display and modify the > InfoFrames we send. > > v2: use argv instead of stdin > > Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com> Merged, thanks for the patch. -Daniel > --- > > Hi > > I sent this tool a long time ago, received reviews (asking to read > input from argv instead of stdin), but then kinda gave up on it since > I thought it was not that useful. I was wrong: this tool has already > helped investigating kernel.org bug #25732 (just running the tool > fixes the problem! but why?) and a few minutes ago it has just helped > me finding the fix for freedesktop.org bug #45729 (by quickly changing > the AVI InfoFrame without recompiling the Kernel). > > I hope it will also help us solving future problems, so I guess it > might be worth having the tool on the main I-G-T repository. > > > man/Makefile.am | 1 + > man/intel_infoframes.man | 26 ++ > tools/.gitignore | 1 + > tools/Makefile.am | 1 + > tools/intel_infoframes.c | 1050 ++++++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 1079 insertions(+) > create mode 100644 man/intel_infoframes.man > create mode 100644 tools/intel_infoframes.c > > diff --git a/man/Makefile.am b/man/Makefile.am > index 0f197a9..0d04f93 100644 > --- a/man/Makefile.am > +++ b/man/Makefile.am > @@ -6,6 +6,7 @@ appman_PRE = \ > intel_error_decode.man \ > intel_gpu_top.man \ > intel_gtt.man \ > + intel_infoframes.man \ > intel_lid.man \ > intel_panel_fitter.man \ > intel_reg_dumper.man \ > diff --git a/man/intel_infoframes.man b/man/intel_infoframes.man > new file mode 100644 > index 0000000..c20d4b4 > --- /dev/null > +++ b/man/intel_infoframes.man > @@ -0,0 +1,26 @@ > +.\" shorthand for double quote that works everywhere. > +.ds q \N'34' > +.TH intel_infoframes __appmansuffix__ __xorgversion__ > +.SH NAME > +intel_infoframes \- View and change HDMI InfoFrames > +.SH SYNOPSIS > +.B intel_infoframes > +.SH DESCRIPTION > +.B intel_infoframes > +is a tool to view and change the HDMI InfoFrames sent by the GPU. Its main > +purpose is to be used as a debugging tool. In some cases (e.g., when > +changing modes) the Kernel will undo the changes made by this tool. > + > +Descriptions of the InfoFrame fields can be found on the HDMI and CEA-861 > +specifications. > + > +Use the > +.B -h > +or > +.B --help > +options to learn how to use the command > +.SH LIMITATIONS > +Not all HDMI monitors respect the InfoFrames sent to them. Only Iron Lake > +or newer hardware is supported yet. > +.SH SEE ALSO > +HDMI specification, CEA-861 specification. > diff --git a/tools/.gitignore b/tools/.gitignore > index 44959fb..4d1b37b 100644 > --- a/tools/.gitignore > +++ b/tools/.gitignore > @@ -11,6 +11,7 @@ intel_gpu_dump > intel_gpu_time > intel_gpu_top > intel_gtt > +intel_infoframes > intel_lid > intel_panel_fitter > intel_reg_checker > diff --git a/tools/Makefile.am b/tools/Makefile.am > index a368130..058835c 100644 > --- a/tools/Makefile.am > +++ b/tools/Makefile.am > @@ -18,6 +18,7 @@ bin_PROGRAMS = \ > > noinst_PROGRAMS = \ > intel_dump_decode \ > + intel_infoframes \ > intel_lid \ > intel_panel_fitter > > diff --git a/tools/intel_infoframes.c b/tools/intel_infoframes.c > new file mode 100644 > index 0000000..bd8d66e > --- /dev/null > +++ b/tools/intel_infoframes.c > @@ -0,0 +1,1050 @@ > +/* > + * 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 at 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 = 0xe1140, > + REG_HDMIC = 0xe1150, > + REG_HDMID = 0xe1160, > + REG_DIP_CTL_A = 0xe0200, > + REG_DIP_CTL_B = 0xe1200, > + REG_DIP_CTL_C = 0xe2200, > + 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_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 AVI_INFOFRAME_TYPE 0x82 > +#define AVI_INFOFRAME_VERSION 0x01 > +#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 hdmi_ports[] = { > + REG_HDMIB, > + REG_HDMIC, > + REG_HDMID > +}; > +Register dip_ctl_regs[] = { > + REG_DIP_CTL_A, > + REG_DIP_CTL_B, > + REG_DIP_CTL_C > +}; > +Register 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)" > +}; > + > +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 void load_infoframe(Transcoder transcoder, DipInfoFrame *frame, > + DipType type) > +{ > + Register ctl_reg = dip_ctl_regs[transcoder]; > + Register data_reg = dip_data_regs[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 = hdmi_ports[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 (pch >= PCH_CPT) > + transcoder = (val & HDMI_PORT_TRANSCODER_CPT) >> 29; > + else > + transcoder = (val & HDMI_PORT_TRANSCODER_CPT) >> 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 = dip_ctl_regs[transcoder]; > + uint32_t val = INREG(reg); > + DipFrequency freq; > + DipInfoFrame frame; > + > + load_infoframe(transcoder, &frame, DIP_AVI); > + val = INREG(reg); > + > + printf("AVI InfoFrame:\n"); > + > + 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 = dip_ctl_regs[transcoder]; > + uint32_t val = INREG(reg); > + DipFrequency freq; > + DipInfoFrame frame; > + > + load_infoframe(transcoder, &frame, DIP_VENDOR); > + val = INREG(reg); > + > + printf("Vendor InfoFrame:\n"); > + > + 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 = dip_ctl_regs[transcoder]; > + uint32_t val = INREG(reg); > + DipFrequency freq; > + DipInfoFrame frame; > + > + load_infoframe(transcoder, &frame, DIP_GAMUT); > + val = INREG(reg); > + > + printf("Gamut InfoFrame:\n"); > + > + 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 = dip_ctl_regs[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"); > + > + 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 = dip_ctl_regs[transcoder]; > + uint32_t val = INREG(reg); > + > + 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; > + > + for (i = 0; i < ARRAY_SIZE(hdmi_ports); i++) > + dump_port_info(i); > + for (i = 0; i < ARRAY_SIZE(dip_ctl_regs); i++) > + dump_transcoder_info(i); > +} > + > +static void write_infoframe(Transcoder transcoder, DipType type, > + DipInfoFrame *frame) > +{ > + Register ctl_reg = dip_ctl_regs[transcoder]; > + Register data_reg = dip_data_regs[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 = dip_ctl_regs[transcoder]; > + uint32_t val = INREG(reg); > + if (type == DIP_AVI) > + val &= ~DIP_CTL_ENABLE; > + val &= ~(1 << (21 + type)); > + OUTREG(reg, val); > +} > + > +static void enable_infoframe(Transcoder transcoder, DipType type) > +{ > + Register reg = dip_ctl_regs[transcoder]; > + uint32_t val = INREG(reg); > + if (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 = dip_ctl_regs[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 = dip_ctl_regs[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 = dip_ctl_regs[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 = dip_ctl_regs[transcoder]; > + uint32_t val = INREG(reg); > + val &= ~DIP_CTL_ENABLE; > + OUTREG(reg, val); > +} > + > +static void enable_dip(Transcoder transcoder) > +{ > + Register reg = dip_ctl_regs[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:nNxXpPt: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", no_argument, NULL, 'p' }, > + { "enable-hdmi-port", no_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 (!HAS_PCH_SPLIT(pci_dev->device_id)) { > + printf("This program still only supports ILK or newer.\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 = REG_HDMIB; > + else if (!strcmp(optarg, "C")) > + hdmi_port = REG_HDMIC; > + else if (!strcmp(optarg, "D")) > + hdmi_port = REG_HDMID; > + 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; > +} > -- > 1.7.9.5 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Daniel Vetter Mail: daniel at ffwll.ch Mobile: +41 (0)79 365 57 48