[Intel-gfx] [PATCH] Add tools/intel_infoframes

Daniel Vetter daniel at ffwll.ch
Fri Apr 13 15:49:19 CEST 2012


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 = &current[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,
> +					     &current))
> +			frame.avi.S = option_val;
> +		else if (parse_infoframe_option_u("B", option, 0, 3,
> +						  &option_val, &current))
> +			frame.avi.B = option_val;
> +		else if (parse_infoframe_option_u("A", option, 0, 1,
> +						  &option_val, &current))
> +			frame.avi.A = option_val;
> +		else if (parse_infoframe_option_u("Y", option, 0, 2,
> +						  &option_val, &current))
> +			frame.avi.Y = option_val;
> +		else if (parse_infoframe_option_u("R", option, 0, 15,
> +						  &option_val, &current))
> +			frame.avi.R = option_val;
> +		else if (parse_infoframe_option_u("M", option, 0, 2,
> +						  &option_val, &current))
> +			frame.avi.M = option_val;
> +		else if (parse_infoframe_option_u("C", option, 0, 3,
> +						  &option_val, &current))
> +			frame.avi.C = option_val;
> +		else if (parse_infoframe_option_u("SC", option, 0, 3,
> +						  &option_val, &current))
> +			frame.avi.SC = option_val;
> +		else if (parse_infoframe_option_u("Q", option, 0, 2,
> +						  &option_val, &current))
> +			frame.avi.Q = option_val;
> +		else if (parse_infoframe_option_u("EC", option, 0, 1,
> +						  &option_val,&current))
> +			frame.avi.EC = option_val;
> +		else if (parse_infoframe_option_u("ITC", option, 0, 1,
> +						  &option_val, &current))
> +			frame.avi.ITC = option_val;
> +		else if (parse_infoframe_option_u("VIC", option, 0, 127,
> +						  &option_val, &current))
> +			frame.avi.VIC = option_val;
> +		else if (parse_infoframe_option_u("PR", option, 0, 15,
> +						  &option_val, &current))
> +			frame.avi.PR = option_val;
> +		else if (parse_infoframe_option_u("top", option, 0, 65535,
> +						  &option_val, &current))
> +			frame.avi.top = option_val;
> +		else if (parse_infoframe_option_u("bottom", option, 0, 65535,
> +						  &option_val, &current))
> +			frame.avi.bottom = option_val;
> +		else if (parse_infoframe_option_u("left", option, 0, 65535,
> +						  &option_val, &current))
> +			frame.avi.left = option_val;
> +		else if (parse_infoframe_option_u("right", option, 0, 65535,
> +						  &option_val, &current))
> +			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 = &current[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, &current))
> +			memcpy(frame.spd.vendor, option_val_s, 8);
> +		else if (parse_infoframe_option_s("description", option, 0, 16,
> +						  option_val_s, &current))
> +			memcpy(frame.spd.description, option_val_s, 16);
> +		else if (parse_infoframe_option_u("source", option, 0, 0x0c,
> +						  &option_val_i, &current))
> +			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



More information about the Intel-gfx mailing list