mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-02-13 13:04:45 +00:00
374 lines
11 KiB
C
374 lines
11 KiB
C
/* vim: set noet ts=8 sts=8 sw=8 : */
|
|
/*
|
|
* Copyright © 2010 Saleem Abdulrasool <compnerd@compnerd.org>.
|
|
* Copyright © 2010 Genesi USA, Inc. <matt@genesi-usa.com>.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef LINUX_EDID_H
|
|
#define LINUX_EDID_H
|
|
|
|
/* EDID constants and Structures */
|
|
#define EDID_I2C_DDC_DATA_ADDRESS (0x50)
|
|
|
|
#define EDID_BLOCK_SIZE (0x80)
|
|
#define EDID_MAX_EXTENSIONS (0xfe)
|
|
|
|
|
|
static const u8 EDID_HEADER[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
|
|
|
|
|
|
enum edid_extension_type {
|
|
EDID_EXTENSION_TIMING = 0x01, // Timing Extension
|
|
EDID_EXTENSION_CEA = 0x02, // Additional Timing Block Data (CEA EDID Timing Extension)
|
|
EDID_EXTENSION_VTB = 0x10, // Video Timing Block Extension (VTB-EXT)
|
|
EDID_EXTENSION_EDID_2_0 = 0x20, // EDID 2.0 Extension
|
|
EDID_EXTENSION_DI = 0x40, // Display Information Extension (DI-EXT)
|
|
EDID_EXTENSION_LS = 0x50, // Localised String Extension (LS-EXT)
|
|
EDID_EXTENSION_MI = 0x60, // Microdisplay Interface Extension (MI-EXT)
|
|
EDID_EXTENSION_DTCDB_1 = 0xa7, // Display Transfer Characteristics Data Block (DTCDB)
|
|
EDID_EXTENSION_DTCDB_2 = 0xaf,
|
|
EDID_EXTENSION_DTCDB_3 = 0xbf,
|
|
EDID_EXTENSION_BLOCK_MAP = 0xf0, // Block Map
|
|
EDID_EXTENSION_DDDB = 0xff, // Display Device Data Block (DDDB)
|
|
};
|
|
|
|
enum edid_display_type {
|
|
EDID_DISPLAY_TYPE_MONOCHROME,
|
|
EDID_DISPLAY_TYPE_RGB,
|
|
EDID_DISPLAY_TYPE_NON_RGB,
|
|
EDID_DISPLAY_TYPE_UNDEFINED,
|
|
};
|
|
|
|
enum edid_aspect_ratio {
|
|
EDID_ASPECT_RATIO_16_10,
|
|
EDID_ASPECT_RATIO_4_3,
|
|
EDID_ASPECT_RATIO_5_4,
|
|
EDID_ASPECT_RATIO_16_9,
|
|
};
|
|
|
|
enum edid_monitor_descriptor_type {
|
|
EDID_MONITOR_DESCRIPTOR_STANDARD_TIMING_IDENTIFIERS = 0xfa,
|
|
EDID_MONITOR_DESCRIPTOR_COLOR_POINT = 0xfb,
|
|
EDID_MONITOR_DESCRIPTOR_MONITOR_NAME = 0xfc,
|
|
EDID_MONITOR_DESCRIPTOR_MONITOR_RANGE_LIMITS = 0xfd,
|
|
EDID_MONITOR_DESCRIPTOR_MONITOR_SERIAL_NUMBER = 0xff,
|
|
};
|
|
|
|
|
|
struct __packed edid_detailed_timing_descriptor {
|
|
u16 pixel_clock; /* = value * 10000 */
|
|
|
|
u8 horizontal_active_lo;
|
|
u8 horizontal_blanking_lo;
|
|
|
|
unsigned horizontal_blanking_hi : 4;
|
|
unsigned horizontal_active_hi : 4;
|
|
|
|
u8 vertical_active_lo;
|
|
u8 vertical_blanking_lo;
|
|
|
|
unsigned vertical_blanking_hi : 4;
|
|
unsigned vertical_active_hi : 4;
|
|
|
|
u8 horizontal_sync_offset_lo;
|
|
u8 horizontal_sync_pulse_width_lo;
|
|
|
|
unsigned vertical_sync_pulse_width_lo : 4;
|
|
unsigned vertical_sync_offset_lo : 4;
|
|
|
|
unsigned vertical_sync_pulse_width_hi : 2;
|
|
unsigned vertical_sync_offset_hi : 2;
|
|
unsigned horizontal_sync_pulse_width_hi : 2;
|
|
unsigned horizontal_sync_offset_hi : 2;
|
|
|
|
u8 horizontal_image_size_lo;
|
|
u8 vertical_image_size_lo;
|
|
|
|
unsigned vertical_image_size_hi : 4;
|
|
unsigned horizontal_image_size_hi : 4;
|
|
|
|
u8 horizontal_border;
|
|
u8 vertical_border;
|
|
|
|
u8 flags;
|
|
};
|
|
|
|
|
|
static inline u16
|
|
edid_timing_pixel_clock(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return dtb->pixel_clock * 10000;
|
|
}
|
|
|
|
static inline u16
|
|
edid_timing_horizontal_blanking(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->horizontal_blanking_hi << 8) | dtb->horizontal_blanking_lo;
|
|
}
|
|
|
|
static inline u16
|
|
edid_timing_horizontal_active(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->horizontal_active_hi << 8) | dtb->horizontal_active_lo;
|
|
}
|
|
|
|
static inline u16
|
|
edid_timing_vertical_blanking(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->vertical_blanking_hi << 8) | dtb->vertical_blanking_lo;
|
|
}
|
|
|
|
static inline u16
|
|
edid_timing_vertical_active(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->vertical_active_hi << 8) | dtb->vertical_active_lo;
|
|
}
|
|
|
|
static inline u8
|
|
edid_timing_vertical_sync_offset(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->vertical_sync_offset_hi << 4) | dtb->vertical_sync_offset_lo;
|
|
}
|
|
|
|
static inline u8
|
|
edid_timing_vertical_sync_pulse_width(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->vertical_sync_pulse_width_hi << 4) | dtb->vertical_sync_pulse_width_lo;
|
|
}
|
|
|
|
static inline u8
|
|
edid_timing_horizontal_sync_offset(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->horizontal_sync_offset_hi << 4) | dtb->horizontal_sync_offset_lo;
|
|
}
|
|
|
|
static inline u8
|
|
edid_timing_horizontal_sync_pulse_width(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->horizontal_sync_pulse_width_hi << 4) | dtb->horizontal_sync_pulse_width_lo;
|
|
}
|
|
|
|
static inline u16
|
|
edid_timing_horizontal_image_size(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->horizontal_image_size_hi << 8) | dtb->horizontal_image_size_lo;
|
|
}
|
|
|
|
static inline u16
|
|
edid_timing_vertical_image_size(const struct edid_detailed_timing_descriptor * const dtb)
|
|
{
|
|
return (dtb->vertical_image_size_hi << 8) | dtb->vertical_image_size_lo;
|
|
}
|
|
|
|
|
|
struct __packed edid_monitor_descriptor {
|
|
u16 flag0;
|
|
u8 flag1;
|
|
u8 tag;
|
|
u8 flag2;
|
|
u8 data[13];
|
|
};
|
|
|
|
struct __packed edid_standard_timing_descriptor {
|
|
u8 horizontal_active_pixels; /* = (value + 31) * 8 */
|
|
|
|
unsigned refresh_rate : 6; /* = value + 60 */
|
|
unsigned image_aspect_ratio : 2;
|
|
};
|
|
|
|
struct __packed edid_block0 {
|
|
/* header information */
|
|
u8 header[8];
|
|
|
|
/* vendor/product identification */
|
|
struct __packed {
|
|
unsigned id2 : 5;
|
|
unsigned id1 : 5;
|
|
unsigned id0 : 5;
|
|
unsigned zero : 1;
|
|
} manufacturer;
|
|
|
|
u8 product[2];
|
|
u8 serial_number[4];
|
|
u8 manufacture_week;
|
|
u8 manufacture_year;
|
|
|
|
/* EDID version */
|
|
u8 version;
|
|
u8 revision;
|
|
|
|
/* basic display parameters and features */
|
|
struct __packed {
|
|
unsigned dfp_1x_vsync_serration : 1; /* VESA DFP 1.x */
|
|
unsigned green_video_sync : 1;
|
|
unsigned composite_sync : 1;
|
|
unsigned separate_sync : 1;
|
|
unsigned blank_to_black_setup : 1;
|
|
unsigned signal_level_standard : 2;
|
|
unsigned digital : 1;
|
|
} video_input_definition;
|
|
|
|
u8 maximum_horizontal_image_size; /* cm */
|
|
u8 maximum_vertical_image_size; /* cm */
|
|
|
|
u8 display_transfer_characteristics; /* gamma = (value + 100) / 100 */
|
|
|
|
struct __packed {
|
|
unsigned default_gtf : 1; /* generalised timing formula */
|
|
unsigned preferred_timing_mode : 1;
|
|
unsigned standard_default_color_space : 1;
|
|
unsigned display_type : 2;
|
|
unsigned active_off : 1;
|
|
unsigned suspend : 1;
|
|
unsigned standby : 1;
|
|
} feature_support;
|
|
|
|
/* color characteristics block */
|
|
unsigned green_y_low : 2;
|
|
unsigned green_x_low : 2;
|
|
unsigned red_y_low : 2;
|
|
unsigned red_x_low : 2;
|
|
|
|
unsigned white_y_low : 2;
|
|
unsigned white_x_low : 2;
|
|
unsigned blue_y_low : 2;
|
|
unsigned blue_x_low : 2;
|
|
|
|
u8 red_x;
|
|
u8 red_y;
|
|
u8 green_x;
|
|
u8 green_y;
|
|
u8 blue_x;
|
|
u8 blue_y;
|
|
u8 white_x;
|
|
u8 white_y;
|
|
|
|
/* established timings */
|
|
struct __packed {
|
|
unsigned timing_800x600_60 : 1;
|
|
unsigned timing_800x600_56 : 1;
|
|
unsigned timing_640x480_75 : 1;
|
|
unsigned timing_640x480_72 : 1;
|
|
unsigned timing_640x480_67 : 1;
|
|
unsigned timing_640x480_60 : 1;
|
|
unsigned timing_720x400_88 : 1;
|
|
unsigned timing_720x400_70 : 1;
|
|
|
|
unsigned timing_1280x1024_75 : 1;
|
|
unsigned timing_1024x768_75 : 1;
|
|
unsigned timing_1024x768_70 : 1;
|
|
unsigned timing_1024x768_60 : 1;
|
|
unsigned timing_1024x768_87 : 1;
|
|
unsigned timing_832x624_75 : 1;
|
|
unsigned timing_800x600_75 : 1;
|
|
unsigned timing_800x600_72 : 1;
|
|
} established_timings;
|
|
|
|
struct __packed {
|
|
unsigned reserved : 7;
|
|
unsigned timing_1152x870_75 : 1;
|
|
} manufacturer_timings;
|
|
|
|
/* standard timing id */
|
|
struct edid_standard_timing_descriptor standard_timing_id[8];
|
|
|
|
/* detailed timing */
|
|
union {
|
|
struct edid_detailed_timing_descriptor detailed_timing[4];
|
|
struct edid_monitor_descriptor monitor_descriptor[4];
|
|
} detailed_timings;
|
|
|
|
u8 extensions;
|
|
u8 checksum;
|
|
};
|
|
|
|
struct __packed edid_color_characteristics_data {
|
|
struct {
|
|
u16 x;
|
|
u16 y;
|
|
} red, green, blue, white;
|
|
};
|
|
|
|
|
|
static inline u16 edid_gamma(const struct edid_block0 * const block0)
|
|
{
|
|
return (block0->display_transfer_characteristics + 100) / 100;
|
|
}
|
|
|
|
static inline struct edid_color_characteristics_data
|
|
edid_color_characteristics(const struct edid_block0 * const block0)
|
|
{
|
|
struct edid_color_characteristics_data characteristics = {
|
|
.red = {
|
|
.x = (block0->red_x << 8) | block0->red_x_low,
|
|
.y = (block0->red_y << 8) | block0->red_y_low,
|
|
},
|
|
.green = {
|
|
.x = (block0->green_x << 8) | block0->green_x_low,
|
|
.y = (block0->green_y << 8) | block0->green_y_low,
|
|
},
|
|
.blue = {
|
|
.x = (block0->blue_x << 8) | block0->blue_x_low,
|
|
.y = (block0->blue_y << 8) | block0->blue_y_low,
|
|
},
|
|
.white = {
|
|
.x = (block0->white_x << 8) | block0->white_x_low,
|
|
.y = (block0->white_y << 8) | block0->white_y_low,
|
|
},
|
|
};
|
|
|
|
return characteristics;
|
|
}
|
|
|
|
struct __packed edid_block_map {
|
|
u8 tag;
|
|
u8 extension_tag[126];
|
|
u8 checksum;
|
|
};
|
|
|
|
struct __packed edid_extension {
|
|
u8 tag;
|
|
u8 revision;
|
|
u8 extension_data[125];
|
|
u8 checksum;
|
|
};
|
|
|
|
static inline bool edid_verify_checksum(const u8 * const block)
|
|
{
|
|
u8 checksum = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < EDID_BLOCK_SIZE; i++)
|
|
checksum += block[i];
|
|
|
|
return (checksum == 0);
|
|
}
|
|
|
|
#endif
|
|
|