All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Vetter <daniel@ffwll.ch>
To: Paulo Zanoni <przanoni@gmail.com>
Cc: intel-gfx@lists.freedesktop.org, Paulo Zanoni <paulo.r.zanoni@intel.com>
Subject: Re: [PATCH] Add tools/intel_infoframes
Date: Fri, 13 Apr 2012 15:49:19 +0200	[thread overview]
Message-ID: <20120413134919.GH4525@phenom.ffwll.local> (raw)
In-Reply-To: <1334323621-13475-1-git-send-email-przanoni@gmail.com>

On Fri, Apr 13, 2012 at 10:27:01AM -0300, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni@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@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@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@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Mail: daniel@ffwll.ch
Mobile: +41 (0)79 365 57 48

  reply	other threads:[~2012-04-13 13:48 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-13 13:27 [PATCH] Add tools/intel_infoframes Paulo Zanoni
2012-04-13 13:49 ` Daniel Vetter [this message]
  -- strict thread matches above, loose matches on Subject: below --
2012-01-09 14:03 przanoni
2012-01-09 14:42 ` Eugeni Dodonov
2012-01-09 16:59   ` Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120413134919.GH4525@phenom.ffwll.local \
    --to=daniel@ffwll.ch \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=paulo.r.zanoni@intel.com \
    --cc=przanoni@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.