Adding dri-devel.

On Tue, Mar 22, 2011 at 1:32 PM, Mythri P K <mythripk at ti.com> wrote:
> Adding support for common EDID parsing in kernel.
>
> EDID - Extended display identification data is a data structure provided by
> a digital display to describe its capabilities to a video source, This a
> standard supported by CEA and VESA.
>
> There are several custom implementations for parsing EDID in kernel, some
> of them are present in fbmon.c, drm_edid.c, sh_mobile_hdmi.c, Ideally
> parsing of EDID should be done in a library, which is agnostic of the
> framework (V4l2, DRM, FB) ?which is using the functionality, just based on
> the raw EDID pointer with size/segment information.
>
> With other RFC's such as the one below, which tries to standardize HDMI API's
> It would be better to have a common EDID code in one place.It also helps to
> provide better interoperability with variety of TV/Monitor may be even by
> listing out quirks which might get missed with several custom implementation
> of EDID.
> http://permalink.gmane.org/gmane.linux.drivers.video-input-infrastructure/30401
>
> This patch tries to add functions to parse some portion EDID (detailed timing,
> monitor limits, AV delay information, deep color mode support, Audio and VSDB)
> If we can align on this library approach i can enhance this library to parse
> other blocks and probably we could also add quirks from other implementation
> as well.
>
> Signed-off-by: Mythri P K <mythripk at ti.com>
> ---
> ?arch/arm/include/asm/edid.h | ?243 ++++++++++++++++++++++++++++++
> ?drivers/video/edid.c ? ? ? ?| ?340 
> +++++++++++++++++++++++++++++++++++++++++++
> ?2 files changed, 583 insertions(+), 0 deletions(-)
> ?create mode 100644 arch/arm/include/asm/edid.h
> ?create mode 100644 drivers/video/edid.c
>
> diff --git a/arch/arm/include/asm/edid.h b/arch/arm/include/asm/edid.h
> new file mode 100644
> index 0000000..843346a
> --- /dev/null
> +++ b/arch/arm/include/asm/edid.h
> @@ -0,0 +1,243 @@
> +/*
> + * edid.h
> + *
> + * Copyright (C) 2011 Texas Instruments
> + * Author: Mythri P K <mythripk at ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published 
> by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but 
> WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. ?See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along 
> with
> + * this program. ?If not, see <http://www.gnu.org/licenses/>.
> + * History:
> + */
> +
> +#ifndef _EDID_H_
> +#define _EDID_H_
> +
> +/* HDMI EDID Length */
> +#define HDMI_EDID_MAX_LENGTH ? ? ? ? ? ? ? ? ? 512
> +
> +/* HDMI EDID Extension Data Block Tags ?*/
> +#define HDMI_EDID_EX_DATABLOCK_TAG_MASK ? ? ? ? ? ? ? ?0xE0
> +#define HDMI_EDID_EX_DATABLOCK_LEN_MASK ? ? ? ? ? ? ? ?0x1F
> +
> +#define EDID_TIMING_DESCRIPTOR_SIZE ? ? ? ? ? ?0x12
> +#define EDID_DESCRIPTOR_BLOCK0_ADDRESS ? ? ? ? 0x36
> +#define EDID_DESCRIPTOR_BLOCK1_ADDRESS ? ? ? ? 0x80
> +#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR ? ? 4
> +#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR ? ? 4
> +
> +/* EDID Detailed Timing ? ? ? ?Info 0 begin offset */
> +#define HDMI_EDID_DETAILED_TIMING_OFFSET ? ? ? 0x36
> +
> +#define HDMI_EDID_PIX_CLK_OFFSET ? ? ? ? ? ? ? 0
> +#define HDMI_EDID_H_ACTIVE_OFFSET ? ? ? ? ? ? ?2
> +#define HDMI_EDID_H_BLANKING_OFFSET ? ? ? ? ? ?3
> +#define HDMI_EDID_V_ACTIVE_OFFSET ? ? ? ? ? ? ?5
> +#define HDMI_EDID_V_BLANKING_OFFSET ? ? ? ? ? ?6
> +#define HDMI_EDID_H_SYNC_OFFSET ? ? ? ? ? ? ? ? ? ? ? ?8
> +#define HDMI_EDID_H_SYNC_PW_OFFSET ? ? ? ? ? ? 9
> +#define HDMI_EDID_V_SYNC_OFFSET ? ? ? ? ? ? ? ? ? ? ? ?10
> +#define HDMI_EDID_V_SYNC_PW_OFFSET ? ? ? ? ? ? 11
> +#define HDMI_EDID_H_IMAGE_SIZE_OFFSET ? ? ? ? ?12
> +#define HDMI_EDID_V_IMAGE_SIZE_OFFSET ? ? ? ? ?13
> +#define HDMI_EDID_H_BORDER_OFFSET ? ? ? ? ? ? ?15
> +#define HDMI_EDID_V_BORDER_OFFSET ? ? ? ? ? ? ?16
> +#define HDMI_EDID_FLAGS_OFFSET ? ? ? ? ? ? ? ? 17
> +
> +/* HDMI EDID DTDs */
> +#define HDMI_EDID_MAX_DTDS ? ? ? ? ? ? ? ? ? ? 4
> +
> +/* HDMI EDID DTD Tags */
> +#define HDMI_EDID_DTD_TAG_MONITOR_NAME ? ? ? ? 0xFC
> +#define HDMI_EDID_DTD_TAG_MONITOR_SERIALNUM ? ?0xFF
> +#define HDMI_EDID_DTD_TAG_MONITOR_LIMITS ? ? ? 0xFD
> +#define HDMI_EDID_DTD_TAG_STANDARD_TIMING_DATA 0xFA
> +#define HDMI_EDID_DTD_TAG_COLOR_POINT_DATA ? ? 0xFB
> +#define HDMI_EDID_DTD_TAG_ASCII_STRING ? ? ? ? 0xFE
> +
> +#define HDMI_IMG_FORMAT_MAX_LENGTH ? ? ? ? ? ? 20
> +#define HDMI_AUDIO_FORMAT_MAX_LENGTH ? ? ? ? ? 10
> +
> +/* HDMI EDID Extenion Data Block Values: Video */
> +#define HDMI_EDID_EX_VIDEO_NATIVE ? ? ? ? ? ? ?0x80
> +#define HDMI_EDID_EX_VIDEO_MASK ? ? ? ? ? ? ? ? ? ? ? ?0x7F
> +#define HDMI_EDID_EX_VIDEO_MAX ? ? ? ? ? ? ? ? 35
> +
> +#define STANDARD_HDMI_TIMINGS_NB ? ? ? ? ? ? ? 34
> +#define STANDARD_HDMI_TIMINGS_VESA_START ? ? ? 15
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +enum extension_edid_db {
> + ? ? ? DATABLOCK_AUDIO = 1,
> + ? ? ? DATABLOCK_VIDEO = 2,
> + ? ? ? DATABLOCK_VENDOR = 3,
> + ? ? ? DATABLOCK_SPEAKERS = 4,
> +};
> +
> +struct img_edid {
> + ? ? ? bool pref;
> + ? ? ? int code;
> +};
> +
> +struct image_format {
> + ? ? ? int length;
> + ? ? ? struct img_edid fmt[HDMI_IMG_FORMAT_MAX_LENGTH];
> +};
> +
> +struct audio_edid {
> + ? ? ? int num_of_ch;
> + ? ? ? int format;
> +};
> +
> +struct audio_format {
> + ? ? ? int length;
> + ? ? ? struct audio_edid fmt[HDMI_AUDIO_FORMAT_MAX_LENGTH];
> +};
> +
> +struct latency {
> + ? ? ? /* vid: if indicated, value=1+ms/2 with a max of 251 meaning 500ms */
> + ? ? ? int vid_latency;
> + ? ? ? int aud_latency;
> + ? ? ? int int_vid_latency;
> + ? ? ? int int_aud_latency;
> +};
> +
> +struct deep_color {
> + ? ? ? bool bit_30;
> + ? ? ? bool bit_36;
> + ? ? ? int max_tmds_freq;
> +};
> +
> +/* ?Video Descriptor Block ?*/
> +struct HDMI_EDID_DTD_VIDEO {
> + ? ? ? u16 ? ? pixel_clock; ? ? ? ? ? ?/* 54-55 */
> + ? ? ? u8 ? ? ?horiz_active; ? ? ? ? ? /* 56 */
> + ? ? ? u8 ? ? ?horiz_blanking; ? ? ? ? /* 57 */
> + ? ? ? u8 ? ? ?horiz_high; ? ? ? ? ? ? /* 58 */
> + ? ? ? u8 ? ? ?vert_active; ? ? ? ? ? ?/* 59 */
> + ? ? ? u8 ? ? ?vert_blanking; ? ? ? ? ?/* 60 */
> + ? ? ? u8 ? ? ?vert_high; ? ? ? ? ? ? ?/* 61 */
> + ? ? ? u8 ? ? ?horiz_sync_offset; ? ? ?/* 62 */
> + ? ? ? u8 ? ? ?horiz_sync_pulse; ? ? ? /* 63 */
> + ? ? ? u8 ? ? ?vert_sync_pulse; ? ? ? ?/* 64 */
> + ? ? ? u8 ? ? ?sync_pulse_high; ? ? ? ?/* 65 */
> + ? ? ? u8 ? ? ?horiz_image_size; ? ? ? /* 66 */
> + ? ? ? u8 ? ? ?vert_image_size; ? ? ? ?/* 67 */
> + ? ? ? u8 ? ? ?image_size_high; ? ? ? ?/* 68 */
> + ? ? ? u8 ? ? ?horiz_border; ? ? ? ? ? /* 69 */
> + ? ? ? u8 ? ? ?vert_border; ? ? ? ? ? ?/* 70 */
> + ? ? ? u8 ? ? ?misc_settings; ? ? ? ? ?/* 71 */
> +};
> +
> +/* ? ? Monitor Limits Descriptor Block */
> +struct HDMI_EDID_DTD_MONITOR {
> + ? ? ? u16 ? ? pixel_clock; ? ? ? ? ? ?/* 54-55*/
> + ? ? ? u8 ? ? ?_reserved1; ? ? ? ? ? ? /* 56 */
> + ? ? ? u8 ? ? ?block_type; ? ? ? ? ? ? /* 57 */
> + ? ? ? u8 ? ? ?_reserved2; ? ? ? ? ? ? /* 58 */
> + ? ? ? u8 ? ? ?min_vert_freq; ? ? ? ? ?/* 59 */
> + ? ? ? u8 ? ? ?max_vert_freq; ? ? ? ? ?/* 60 */
> + ? ? ? u8 ? ? ?min_horiz_freq; ? ? ? ? /* 61 */
> + ? ? ? u8 ? ? ?max_horiz_freq; ? ? ? ? /* 62 */
> + ? ? ? u8 ? ? ?pixel_clock_mhz; ? ? ? ?/* 63 */
> + ? ? ? u8 ? ? ?GTF[2]; ? ? ? ? ? ? ? ? /* 64 -65 */
> + ? ? ? u8 ? ? ?start_horiz_freq; ? ? ? /* 66 ? */
> + ? ? ? u8 ? ? ?C; ? ? ? ? ? ? ? ? ? ? ?/* 67 */
> + ? ? ? u8 ? ? ?M[2]; ? ? ? ? ? ? ? ? ? /* 68-69 */
> + ? ? ? u8 ? ? ?K; ? ? ? ? ? ? ? ? ? ? ?/* 70 */
> + ? ? ? u8 ? ? ?J; ? ? ? ? ? ? ? ? ? ? ?/* 71 */
> +
> +} __packed;
> +
> +/* Text Descriptor Block */
> +struct HDMI_EDID_DTD_TEXT {
> + ? ? ? u16 ? ? pixel_clock; ? ? ? ? ? ?/* 54-55 */
> + ? ? ? u8 ? ? ?_reserved1; ? ? ? ? ? ? /* 56 */
> + ? ? ? u8 ? ? ?block_type; ? ? ? ? ? ? /* 57 */
> + ? ? ? u8 ? ? ?_reserved2; ? ? ? ? ? ? /* 58 */
> + ? ? ? u8 ? ? ?text[13]; ? ? ? ? ? ? ? /* 59-71 */
> +} __packed;
> +
> +/* DTD Union */
> +union HDMI_EDID_DTD {
> + ? ? ? struct HDMI_EDID_DTD_VIDEO ? ? ?video;
> + ? ? ? struct HDMI_EDID_DTD_TEXT ? ? ? monitor_name;
> + ? ? ? struct HDMI_EDID_DTD_TEXT ? ? ? monitor_serial_number;
> + ? ? ? struct HDMI_EDID_DTD_TEXT ? ? ? ascii;
> + ? ? ? struct HDMI_EDID_DTD_MONITOR ? ?monitor_limits;
> +} __packed;
> +
> +/* ? ? EDID struct ? ? */
> +struct HDMI_EDID {
> + ? ? ? u8 ? ? ?header[8]; ? ? ? ? ? ? ?/* 00-07 */
> + ? ? ? u16 ? ? manufacturerID; ? ? ? ? /* 08-09 */
> + ? ? ? u16 ? ? product_id; ? ? ? ? ? ? /* 10-11 */
> + ? ? ? u32 ? ? serial_number; ? ? ? ? ?/* 12-15 */
> + ? ? ? u8 ? ? ?week_manufactured; ? ? ?/* 16 */
> + ? ? ? u8 ? ? ?year_manufactured; ? ? ?/* 17 */
> + ? ? ? u8 ? ? ?edid_version; ? ? ? ? ? /* 18 */
> + ? ? ? u8 ? ? ?edid_revision; ? ? ? ? ?/* 19 */
> + ? ? ? u8 ? ? ?video_in_definition; ? ?/* 20 */
> + ? ? ? u8 ? ? ?max_horiz_image_size; ? /* 21 */
> + ? ? ? u8 ? ? ?max_vert_image_size; ? ?/* 22 */
> + ? ? ? u8 ? ? ?display_gamma; ? ? ? ? ?/* 23 */
> + ? ? ? u8 ? ? ?power_features; ? ? ? ? /* 24 */
> + ? ? ? u8 ? ? ?chroma_info[10]; ? ? ? ?/* 25-34 */
> + ? ? ? u8 ? ? ?timing_1; ? ? ? ? ? ? ? /* 35 */
> + ? ? ? u8 ? ? ?timing_2; ? ? ? ? ? ? ? /* 36 */
> + ? ? ? u8 ? ? ?timing_3; ? ? ? ? ? ? ? /* 37 */
> + ? ? ? u8 ? ? ?std_timings[16]; ? ? ? ?/* 38-53 */
> + ? ? ? union ? HDMI_EDID_DTD DTD[4]; ? /* 54-125 */
> + ? ? ? u8 ? ? ?extension_edid; ? ? ? ? /* 126 */
> + ? ? ? u8 ? ? ?checksum; ? ? ? ? ? ? ? /* 127 */
> + ? ? ? u8 ? ? ?extension_tag; ? ? ? ? ?/* 00 (extensions follow EDID) */
> + ? ? ? u8 ? ? ?extention_rev; ? ? ? ? ?/* 01 */
> + ? ? ? u8 ? ? ?offset_dtd; ? ? ? ? ? ? /* 02 */
> + ? ? ? u8 ? ? ?num_dtd; ? ? ? ? ? ? ? ?/* 03 */
> + ? ? ? u8 ? ? ?data_block[123]; ? ? ? ?/* 04 - 126 */
> + ? ? ? u8 ? ? ?extension_checksum; ? ? /* 127 */
> +
> + ? ? ? u8 ? ? ?ext_datablock[256];
> +} __packed;
> +
> +struct hdmi_timings {
> +
> + ? ? ? u16 x_res;
> + ? ? ? u16 y_res;
> + ? ? ? u32 pixel_clock; ? ? ? ?/* pixel clock in KHz */
> + ? ? ? u16 hsw; ? ? ? ? ? ? ? ?/* Horizontal synchronization pulse width */
> + ? ? ? u16 hfp; ? ? ? ? ? ? ? ?/* Horizontal front porch */
> + ? ? ? u16 hbp; ? ? ? ? ? ? ? ?/* Horizontal back porch */
> + ? ? ? u16 vsw; ? ? ? ? ? ? ? ?/* Vertical synchronization pulse width */
> + ? ? ? u16 vfp; ? ? ? ? ? ? ? ?/* Vertical front porch */
> + ? ? ? u16 vbp; ? ? ? ? ? ? ? ?/* Vertical back porch */
> +};
> +
> +int get_edid_timing_info(union HDMI_EDID_DTD *edid_dtd,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct hdmi_timings *timings);
> +void get_eedid_timing_info(int current_descriptor_addrs, u8 *edid ,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct hdmi_timings *timings);
> +int hdmi_get_datablock_offset(u8 *edid, enum extension_edid_db datablock,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int *offset);
> +int hdmi_get_image_format(u8 *edid, struct image_format *format);
> +int hdmi_get_audio_format(u8 *edid, struct audio_format *format);
> +void hdmi_get_av_delay(u8 *edid, struct latency *lat);
> +void hdmi_deep_color_support_info(u8 *edid, struct deep_color *format);
> +bool hdmi_tv_yuv_supported(u8 *edid);
> +
> +#ifdef __cplusplus
> +};
> +#endif
> +
> +#endif
> diff --git a/drivers/video/edid.c b/drivers/video/edid.c
> new file mode 100644
> index 0000000..4eb2074
> --- /dev/null
> +++ b/drivers/video/edid.c
> @@ -0,0 +1,340 @@
> +/*
> + * edid.c
> + *
> + * Copyright (C) 2011 Texas Instruments
> + * Author: Mythri P K <mythripk at ti.com>
> + * ? ? ? ? With EDID parsing for DVI Monitor from Rob Clark <rob at ti.com>
> + *
> + * EDID.c to parse the EDID content.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published 
> by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but 
> WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. ?See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along 
> with
> + * this program. ?If not, see <http://www.gnu.org/licenses/>.
> + * History:
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +#include <asm/edid.h>
> +
> +/* Standard HDMI/VESA timings */
> +const struct hdmi_timings standard_hdmi_timings[STANDARD_HDMI_TIMINGS_NB] = {
> + ? ? ? {640, 480, 25200, 96, 16, 48, 2, 10, 33},
> + ? ? ? {1280, 720, 74250, 40, 440, 220, 5, 5, 20},
> + ? ? ? {1280, 720, 74250, 40, 110, 220, 5, 5, 20},
> + ? ? ? {720, 480, 27027, 62, 16, 60, 6, 9, 30},
> + ? ? ? {2880, 576, 108000, 256, 48, 272, 5, 5, 39},
> + ? ? ? {1440, 240, 27027, 124, 38, 114, 3, 4, 15},
> + ? ? ? {1440, 288, 27000, 126, 24, 138, 3, 2, 19},
> + ? ? ? {1920, 540, 74250, 44, 528, 148, 5, 2, 15},
> + ? ? ? {1920, 540, 74250, 44, 88, 148, 5, 2, 15},
> + ? ? ? {1920, 1080, 148500, 44, 88, 148, 5, 4, 36},
> + ? ? ? {720, 576, 27000, 64, 12, 68, 5, 5, 39},
> + ? ? ? {1440, 576, 54000, 128, 24, 136, 5, 5, 39},
> + ? ? ? {1920, 1080, 148500, 44, 528, 148, 5, 4, 36},
> + ? ? ? {2880, 480, 108108, 248, 64, 240, 6, 9, 30},
> + ? ? ? {1920, 1080, 74250, 44, 638, 148, 5, 4, 36},
> + ? ? ? /* Vesa frome here */
> + ? ? ? {640, 480, 25175, 96, 16, 48, 2 , 11, 31},
> + ? ? ? {800, 600, 40000, 128, 40, 88, 4 , 1, 23},
> + ? ? ? {848, 480, 33750, 112, 16, 112, 8 , 6, 23},
> + ? ? ? {1280, 768, 79500, 128, 64, 192, 7 , 3, 20},
> + ? ? ? {1280, 800, 83500, 128, 72, 200, 6 , 3, 22},
> + ? ? ? {1360, 768, 85500, 112, 64, 256, 6 , 3, 18},
> + ? ? ? {1280, 960, 108000, 112, 96, 312, 3 , 1, 36},
> + ? ? ? {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38},
> + ? ? ? {1024, 768, 65000, 136, 24, 160, 6, 3, 29},
> + ? ? ? {1400, 1050, 121750, 144, 88, 232, 4, 3, 32},
> + ? ? ? {1440, 900, 106500, 152, 80, 232, 6, 3, 25},
> + ? ? ? {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30},
> + ? ? ? {1366, 768, 85500, 143, 70, 213, 3, 3, 24},
> + ? ? ? {1920, 1080, 148500, 44, 88, 80, 5, 4, 36},
> + ? ? ? {1280, 768, 68250, 32, 48, 80, 7, 3, 12},
> + ? ? ? {1400, 1050, 101000, 32, 48, 80, 4, 3, 23},
> + ? ? ? {1680, 1050, 119000, 32, 48, 80, 6, 3, 21},
> + ? ? ? {1280, 800, 79500, 32, 48, 80, 6, 3, 14},
> + ? ? ? {1280, 720, 74250, 40, 110, 220, 5, 5, 20}
> +};
> +
> +int get_edid_timing_info(union HDMI_EDID_DTD *edid_dtd,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct hdmi_timings *timings)
> +{
> + ? ? ? if (edid_dtd->video.pixel_clock) {
> + ? ? ? ? ? ? ? struct HDMI_EDID_DTD_VIDEO *vid = &edid_dtd->video;
> +
> + ? ? ? ? ? ? ? timings->pixel_clock = 10 * vid->pixel_clock;
> + ? ? ? ? ? ? ? timings->x_res = vid->horiz_active |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (((u16)vid->horiz_high & 0xf0) << 4);
> + ? ? ? ? ? ? ? timings->y_res = vid->vert_active |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (((u16)vid->vert_high & 0xf0) << 4);
> + ? ? ? ? ? ? ? timings->hfp = vid->horiz_sync_offset |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (((u16)vid->sync_pulse_high & 0xc0) << 2);
> + ? ? ? ? ? ? ? timings->hsw = vid->horiz_sync_pulse |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (((u16)vid->sync_pulse_high & 0x30) << 4);
> + ? ? ? ? ? ? ? timings->hbp = (vid->horiz_blanking |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (((u16)vid->horiz_high & 0x0f) << 8)) -
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (timings->hfp + timings->hsw);
> + ? ? ? ? ? ? ? timings->vfp = ((vid->vert_sync_pulse & 0xf0) >> 4) |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ((vid->sync_pulse_high & 0x0f) << 2);
> + ? ? ? ? ? ? ? timings->vsw = (vid->vert_sync_pulse & 0x0f) |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ((vid->sync_pulse_high & 0x03) << 4);
> + ? ? ? ? ? ? ? timings->vbp = (vid->vert_blanking |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (((u16)vid->vert_high & 0x0f) << 8)) -
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (timings->vfp + timings->vsw);
> + ? ? ? ? ? ? ? return 0;
> + ? ? ? }
> +
> + ? ? ? switch (edid_dtd->monitor_name.block_type) {
> + ? ? ? case HDMI_EDID_DTD_TAG_STANDARD_TIMING_DATA:
> + ? ? ? ? ? ? ? printk(KERN_INFO "standard timing data\n");
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? case HDMI_EDID_DTD_TAG_COLOR_POINT_DATA:
> + ? ? ? ? ? ? ? printk(KERN_INFO "color point data\n");
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? case HDMI_EDID_DTD_TAG_MONITOR_NAME:
> + ? ? ? ? ? ? ? printk(KERN_INFO "monitor name: %s\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? edid_dtd->monitor_name.text);
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? case HDMI_EDID_DTD_TAG_MONITOR_LIMITS:
> + ? ? ? {
> + ? ? ? ? ? ? ? int i, max_area = 0, best_idx = -1;
> + ? ? ? ? ? ? ? struct HDMI_EDID_DTD_MONITOR *limits =
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &edid_dtd->monitor_limits;
> +
> + ? ? ? ? ? ? ? printk(KERN_DEBUG " ?monitor limits\n");
> + ? ? ? ? ? ? ? printk(KERN_DEBUG " ?min_vert_freq=%d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? limits->min_vert_freq);
> + ? ? ? ? ? ? ? printk(KERN_DEBUG " ?max_vert_freq=%d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? limits->max_vert_freq);
> + ? ? ? ? ? ? ? printk(KERN_DEBUG " ?min_horiz_freq=%d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? limits->min_horiz_freq);
> + ? ? ? ? ? ? ? printk(KERN_DEBUG " ?max_horiz_freq=%d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? limits->max_horiz_freq);
> + ? ? ? ? ? ? ? printk(KERN_DEBUG " ?pixel_clock_mhz=%d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? limits->pixel_clock_mhz * 10);
> +
> + ? ? ? ? ? ? ? /* find the highest matching resolution (w*h) */
> +
> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* XXX since this is mainly for DVI monitors, should we only
> + ? ? ? ? ? ? ? ?* support VESA timings? ?My monitor at home would pick
> + ? ? ? ? ? ? ? ?* 1920x1080 otherwise, but that seems to not work well 
> (monitor
> + ? ? ? ? ? ? ? ?* blanks out and comes back, and picture doesn't fill full
> + ? ? ? ? ? ? ? ?* screen, but leaves a black bar on left (native res is
> + ? ? ? ? ? ? ? ?* 2048x1152). However if I only consider VESA timings, it 
> picks
> + ? ? ? ? ? ? ? ?* 1680x1050 and the picture is stable and fills whole screen
> + ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? for (i = STANDARD_HDMI_TIMINGS_VESA_START;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i < STANDARD_HDMI_TIMINGS_NB; i++) {
> + ? ? ? ? ? ? ? ? ? ? ? const struct hdmi_timings *timings =
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?&standard_hdmi_timings[i];
> + ? ? ? ? ? ? ? ? ? ? ? int hz, hscan, pixclock;
> + ? ? ? ? ? ? ? ? ? ? ? int vtotal, htotal;
> + ? ? ? ? ? ? ? ? ? ? ? htotal = timings->hbp + timings->hfp +
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timings->hsw + timings->x_res;
> + ? ? ? ? ? ? ? ? ? ? ? vtotal = timings->vbp + timings->vfp +
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timings->vsw + timings->y_res;
> +
> + ? ? ? ? ? ? ? ? ? ? ? /* NOTE: We don't support interlaced mode for VESA */
> + ? ? ? ? ? ? ? ? ? ? ? pixclock = timings->pixel_clock * 1000;
> + ? ? ? ? ? ? ? ? ? ? ? hscan = (pixclock + htotal / 2) / htotal;
> + ? ? ? ? ? ? ? ? ? ? ? hscan = (hscan + 500) / 1000 * 1000;
> + ? ? ? ? ? ? ? ? ? ? ? hz = (hscan + vtotal / 2) / vtotal;
> + ? ? ? ? ? ? ? ? ? ? ? hscan /= 1000;
> + ? ? ? ? ? ? ? ? ? ? ? pixclock /= 1000000;
> + ? ? ? ? ? ? ? ? ? ? ? if ((pixclock < (limits->pixel_clock_mhz * 10)) &&
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (limits->min_horiz_freq <= hscan) &&
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (hscan <= limits->max_horiz_freq) &&
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (limits->min_vert_freq <= hz) &&
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (hz <= limits->max_vert_freq)) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int area = timings->x_res * timings->y_res;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printk(KERN_INFO " -> %d: %dx%d\n", i,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timings->x_res, timings->y_res);
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (area > max_area) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? max_area = area;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? best_idx = i;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? if (best_idx > 0) {
> + ? ? ? ? ? ? ? ? ? ? ? *timings = standard_hdmi_timings[best_idx];
> + ? ? ? ? ? ? ? ? ? ? ? printk(KERN_DEBUG "found best resolution: %dx%d 
> (%d)\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? timings->x_res, timings->y_res, best_idx);
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? return 0;
> + ? ? ? }
> + ? ? ? case HDMI_EDID_DTD_TAG_ASCII_STRING:
> + ? ? ? ? ? ? ? printk(KERN_INFO "ascii string: %s\n", edid_dtd->ascii.text);
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? case HDMI_EDID_DTD_TAG_MONITOR_SERIALNUM:
> + ? ? ? ? ? ? ? printk(KERN_INFO "monitor serialnum: %s\n",
> + ? ? ? ? ? ? ? ? ? ? ? edid_dtd->monitor_serial_number.text);
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? default:
> + ? ? ? ? ? ? ? printk(KERN_INFO "unsupported EDID descriptor block 
> format\n");
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? }
> +}
> +
> +void get_eedid_timing_info(int current_descriptor_addrs, u8 *edid ,
> + ? ? ? ? ? ? ? ? ? ? ? struct hdmi_timings *timings)
> +{
> + ? ? ? timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | edid[current_descriptor_addrs + 2]);
> + ? ? ? timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | edid[current_descriptor_addrs + 5]);
> + ? ? ? timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | edid[current_descriptor_addrs]);
> + ? ? ? timings->pixel_clock = 10 * timings->pixel_clock;
> + ? ? ? timings->hfp = edid[current_descriptor_addrs + 8];
> + ? ? ? timings->hsw = edid[current_descriptor_addrs + 9];
> + ? ? ? timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | edid[current_descriptor_addrs + 3]) -
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (timings->hfp + timings->hsw);
> + ? ? ? timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4);
> + ? ? ? timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F);
> + ? ? ? timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | edid[current_descriptor_addrs + 6]) -
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (timings->vfp + timings->vsw);
> +}
> +
> +int hdmi_get_datablock_offset(u8 *edid, enum extension_edid_db datablock,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int *offset)
> +{
> + ? ? ? int current_byte, disp, i = 0, length = 0;
> +
> + ? ? ? if (edid[0x7e] == 0x00)
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? disp = edid[(0x80) + 2];
> + ? ? ? if (disp == 0x4)
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? i = 0x80 + 0x4;
> + ? ? ? printk(KERN_INFO "%x\n", i);
> + ? ? ? while (i < (0x80 + disp)) {
> + ? ? ? ? ? ? ? current_byte = edid[i];
> + ? ? ? ? ? ? ? if ((current_byte >> 5) == datablock) {
> + ? ? ? ? ? ? ? ? ? ? ? *offset = i;
> + ? ? ? ? ? ? ? ? ? ? ? printk(KERN_INFO "datablock %d %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? datablock, *offset);
> + ? ? ? ? ? ? ? ? ? ? ? return 0;
> + ? ? ? ? ? ? ? } else {
> + ? ? ? ? ? ? ? ? ? ? ? length = (current_byte &
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? HDMI_EDID_EX_DATABLOCK_LEN_MASK) + 1;
> + ? ? ? ? ? ? ? ? ? ? ? i += length;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> + ? ? ? return -EINVAL;
> +}
> +
> +int hdmi_get_image_format(u8 *edid, struct image_format *format)
> +{
> + ? ? ? int offset, current_byte, j = 0, length = 0;
> + ? ? ? enum extension_edid_db vsdb = ?DATABLOCK_VIDEO;
> + ? ? ? format->length = 0;
> +
> + ? ? ? memset(format->fmt, 0, sizeof(format->fmt));
> + ? ? ? if (!hdmi_get_datablock_offset(edid, vsdb, &offset)) {
> + ? ? ? ? ? ? ? current_byte = edid[offset];
> + ? ? ? ? ? ? ? length = current_byte & HDMI_EDID_EX_DATABLOCK_LEN_MASK;
> +
> + ? ? ? ? ? ? ? if (length >= HDMI_IMG_FORMAT_MAX_LENGTH)
> + ? ? ? ? ? ? ? ? ? ? ? format->length = HDMI_IMG_FORMAT_MAX_LENGTH;
> + ? ? ? ? ? ? ? else
> + ? ? ? ? ? ? ? ? ? ? ? format->length = length;
> +
> + ? ? ? ? ? ? ? for (j = 1 ; j < length ; j++) {
> + ? ? ? ? ? ? ? ? ? ? ? current_byte = edid[offset+j];
> + ? ? ? ? ? ? ? ? ? ? ? format->fmt[j-1].code = current_byte & 0x7F;
> + ? ? ? ? ? ? ? ? ? ? ? format->fmt[j-1].pref = current_byte & 0x80;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> + ? ? ? return 0;
> +}
> +
> +int hdmi_get_audio_format(u8 *edid, struct audio_format *format)
> +{
> + ? ? ? int offset, current_byte, j = 0, length = 0;
> + ? ? ? enum extension_edid_db vsdb = ?DATABLOCK_AUDIO;
> +
> + ? ? ? format->length = 0;
> + ? ? ? memset(format->fmt, 0, sizeof(format->fmt));
> +
> + ? ? ? if (!hdmi_get_datablock_offset(edid, vsdb, &offset)) {
> + ? ? ? ? ? ? ? current_byte = edid[offset];
> + ? ? ? ? ? ? ? length = current_byte & HDMI_EDID_EX_DATABLOCK_LEN_MASK;
> +
> + ? ? ? ? ? ? ? if (length >= HDMI_AUDIO_FORMAT_MAX_LENGTH)
> + ? ? ? ? ? ? ? ? ? ? ? format->length = HDMI_AUDIO_FORMAT_MAX_LENGTH;
> + ? ? ? ? ? ? ? else
> + ? ? ? ? ? ? ? ? ? ? ? format->length = length;
> +
> + ? ? ? ? ? ? ? for (j = 1 ; j < length ; j++) {
> + ? ? ? ? ? ? ? ? ? ? ? if (j%3 == 1) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? current_byte = edid[offset + j];
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? format->fmt[j-1].format = current_byte & 0x78;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? format->fmt[j-1].num_of_ch =
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (current_byte & 0x07) + 1;
> + ? ? ? ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> + ? ? ? return 0;
> +}
> +
> +void hdmi_get_av_delay(u8 *edid, struct latency *lat)
> +{
> + ? ? ? int offset, current_byte, length = 0;
> + ? ? ? enum extension_edid_db vsdb = ?DATABLOCK_VENDOR;
> +
> + ? ? ? if (!hdmi_get_datablock_offset(edid, vsdb, &offset)) {
> + ? ? ? ? ? ? ? current_byte = edid[offset];
> + ? ? ? ? ? ? ? length = current_byte & HDMI_EDID_EX_DATABLOCK_LEN_MASK;
> + ? ? ? ? ? ? ? if (length >= 8 && ((current_byte + 8) & 0x80)) {
> + ? ? ? ? ? ? ? ? ? ? ? lat->vid_latency = (edid[offset + 8] - 1) * 2;
> + ? ? ? ? ? ? ? ? ? ? ? lat->aud_latency = (edid[offset + 9] - 1) * 2;
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? if (length >= 8 && ((current_byte + 8) & 0xC0)) {
> + ? ? ? ? ? ? ? ? ? ? ? lat->int_vid_latency = (edid[offset + 10] - 1) * 2;
> + ? ? ? ? ? ? ? ? ? ? ? lat->int_aud_latency = (edid[offset + 11] - 1) * 2;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> +}
> +
> +void hdmi_deep_color_support_info(u8 *edid, struct deep_color *format)
> +{
> + ? ? ? int offset, current_byte, length = 0;
> + ? ? ? enum extension_edid_db vsdb = DATABLOCK_VENDOR;
> + ? ? ? memset(format, 0, sizeof(*format));
> +
> + ? ? ? if (!hdmi_get_datablock_offset(edid, vsdb, &offset)) {
> + ? ? ? ? ? ? ? current_byte = edid[offset];
> + ? ? ? ? ? ? ? length = current_byte & HDMI_EDID_EX_DATABLOCK_LEN_MASK;
> + ? ? ? ? ? ? ? if (length >= 6) {
> + ? ? ? ? ? ? ? ? ? ? ? format->bit_30 = (edid[offset + 6] & 0x10);
> + ? ? ? ? ? ? ? ? ? ? ? format->bit_36 = (edid[offset + 6] & 0x20);
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? if (length >= 7)
> + ? ? ? ? ? ? ? ? ? ? ? format->max_tmds_freq = (edid[offset + 7]) * 5;
> + ? ? ? }
> +}
> +
> +bool hdmi_tv_yuv_supported(u8 *edid)
> +{
> + ? ? ? if (edid[0x7e] != 0x00 && edid[0x83] & 0x30) {
> + ? ? ? ? ? ? ? printk(KERN_INFO "YUV supported");
> + ? ? ? ? ? ? ? return true;
> + ? ? ? }
> + ? ? ? return false;
> +}
> --
> 1.5.6.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>

Reply via email to