mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-09-24 23:54:24 +00:00
cea861: improve CEA EDID extension block definition
Improve the CEA861 EDID block definition so that we can use it ot properly identify a HDMI sink.
This commit is contained in:
@@ -256,70 +256,19 @@ static int siihdmi_read_edid(struct siihdmi_tx *tx, u8 *edid, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void siihdmi_parse_cea_extension(struct siihdmi_tx *tx,
|
||||
struct cea_timing_block *ctb)
|
||||
{
|
||||
tx->enable_audio = ctb->basic_audio_supported;
|
||||
|
||||
if (ctb->underscan_supported)
|
||||
tx->pixel_mapping = PIXEL_MAPPING_UNDERSCANNED;
|
||||
|
||||
if (ctb->dtd_start_offset == CTB_DTD_INVALID)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
/* okay DTD data is off in the wild reaches so the next blocks
|
||||
* will be audio, video, vendor and speaker configuration
|
||||
*/
|
||||
u8 length, offset = 0x5;
|
||||
struct cea_dbc_header *dbc_header = (struct cea_dbc_header *) &ctb->dbc_start_offset;
|
||||
|
||||
while (offset <= 127) {
|
||||
switch(dbc_header->block_type_tag) {
|
||||
case CEA_DATA_BLOCK_TAG_AUDIO:
|
||||
length = dbc_header->length;
|
||||
siihdmi_parse_audio(tx, (struct cea_dbc_audio *) &edid[EEDID_EXTENSION_DATA_OFFSET + offset]);
|
||||
offset += length;
|
||||
break;
|
||||
case CEA_DATA_BLOCK_TAG_VIDEO:
|
||||
length = dbc_header->length;
|
||||
siihdmi_parse_video(tx, (struct cea_dbc_video *) &edid[EEDID_EXTENSION_DATA_OFFSET + offset]);
|
||||
offset += length;
|
||||
break;
|
||||
case CEA_DATA_BLOCK_TAG_SPEAKER:
|
||||
length = dbc_header->length;
|
||||
siihdmi_parse_speaker(tx, (struct cea_dbc_speaker *) &edid[EEDID_EXTENSION_DATA_OFFSET + offset]);
|
||||
offset += length;
|
||||
break;
|
||||
case CEA_DATA_BLOCK_TAG_VENDOR:
|
||||
length = dbc_header->length;
|
||||
siihdmi_parse_vendor(tx, (struct cea_dbc_vendor *) &edid[EEDID_EXTENSION_DATA_OFFSET + offset]);
|
||||
offset += length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void siihdmi_detect_sink(struct siihdmi_tx *tx)
|
||||
{
|
||||
/*
|
||||
* Sink detection is a fairly simple matter. Assume that we are
|
||||
* connected to a DVI sink (video only, no audio support). Check the
|
||||
* EDID for the presence of the CEA extension (which is guaranteed to be
|
||||
* the first extension blob, if present). If it is present, and the CEA
|
||||
* timing block data reports support for audio, then the sink is HDMI.
|
||||
*/
|
||||
|
||||
u8 edid[EDID_BLOCK_SIZE << 1];
|
||||
const struct edid_block0 * const block0 = (struct edid_block0 *) edid;
|
||||
const struct edid_extension * const block1 =
|
||||
(struct edid_extension *) edid + EDID_BLOCK_SIZE;
|
||||
|
||||
/* defaults */
|
||||
tx->connection_type = CONNECTION_TYPE_DVI;
|
||||
tx->pixel_mapping = PIXEL_MAPPING_EXACT;
|
||||
tx->enable_audio = false;
|
||||
|
||||
/* use EDID to identify sink characteristics */
|
||||
if (siihdmi_read_edid(tx, edid, sizeof(edid)) < 0)
|
||||
return;
|
||||
|
||||
@@ -327,9 +276,20 @@ static void siihdmi_detect_sink(struct siihdmi_tx *tx)
|
||||
return;
|
||||
|
||||
switch (block1->tag) {
|
||||
case EDID_EXTENSION_CEA:
|
||||
siihdmi_parse_cea_extension(tx,
|
||||
(struct cea_timing_block *) block1);
|
||||
case EDID_EXTENSION_CEA: {
|
||||
const struct cea_timing_block *ctb =
|
||||
(struct cea_timing_block *) block1;
|
||||
|
||||
tx->enable_audio = ctb->basic_audio_supported;
|
||||
|
||||
if (ctb->underscan_supported)
|
||||
tx->pixel_mapping = PIXEL_MAPPING_UNDERSCANNED;
|
||||
|
||||
if (!memcmp(ctb->ieee_registration,
|
||||
CEA861_OUI_REGISTRATION_ID_HDMI,
|
||||
sizeof(ctb->ieee_registration)))
|
||||
tx->connection_type = CONNECTION_TYPE_HDMI;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -444,7 +404,7 @@ static int siihdmi_set_avi_info_frame(struct siihdmi_tx *tx,
|
||||
break;
|
||||
}
|
||||
|
||||
cea861_checksum_info_frame((u8 *) &avi);
|
||||
cea861_checksum_hdmi_info_frame((u8 *) &avi);
|
||||
|
||||
BUILD_BUG_ON(sizeof(avi) - SIIHDMI_AVI_INFO_FRAME_OFFSET != SIIHDMI_TPI_REG_AVI_INFO_FRAME_LENGTH);
|
||||
ret = i2c_smbus_write_i2c_block_data(tx->client,
|
||||
@@ -483,7 +443,7 @@ static int siihdmi_set_spd_info_frame(struct siihdmi_tx *tx,
|
||||
},
|
||||
};
|
||||
|
||||
cea861_checksum_info_frame((u8 *) &packet.spd);
|
||||
cea861_checksum_hdmi_info_frame((u8 *) &packet.spd);
|
||||
|
||||
BUILD_BUG_ON(sizeof(packet) != SIIHDMI_INFO_FRAME_BUFFER_LENGTH);
|
||||
ret = i2c_smbus_write_i2c_block_data(tx->client,
|
||||
|
||||
@@ -34,120 +34,66 @@
|
||||
|
||||
/* Header file for EIA CEA 861-E structures and definitions */
|
||||
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
#include <linux/edid.h>
|
||||
|
||||
#define CEA861_DTD_NOT_PRESENT (0x04)
|
||||
|
||||
/* NOTE: This is placed inot the EDID in little-endian order */
|
||||
static const u8 CEA861_OUI_REGISTRATION_ID_HDMI[] = { 0x00, 0x0C, 0x03 };
|
||||
|
||||
/* EDID timing extension block */
|
||||
struct __packed cea_timing_block {
|
||||
u8 extension_tag;
|
||||
u8 revision_number;
|
||||
/* CEA Extension Header */
|
||||
u8 tag;
|
||||
u8 revision;
|
||||
u8 dtd_start_offset;
|
||||
|
||||
/* Global Declarations */
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
unsigned dtd_block_count : 4;
|
||||
unsigned yuv_422_supported : 1;
|
||||
unsigned yuv_444_supported : 1;
|
||||
unsigned basic_audio_supported : 1;
|
||||
unsigned underscan_supported : 1;
|
||||
u8 dbc_start_offset; // data block collection offset
|
||||
#else
|
||||
unsigned underscan_supported : 1;
|
||||
unsigned basic_audio_supported : 1;
|
||||
unsigned yuv_444_supported : 1;
|
||||
unsigned yuv_422_supported : 1;
|
||||
unsigned dtd_block_count : 4;
|
||||
#endif
|
||||
|
||||
/* CEA Data Block Collection */
|
||||
/* Video Data Block */
|
||||
u8 video_data_start_offset;
|
||||
u8 short_video_descriptor[7];
|
||||
|
||||
/* Audio Data Block */
|
||||
u8 audio_data_start_offset;
|
||||
u8 audio_format;
|
||||
u8 frequency;
|
||||
u8 bit_rate;
|
||||
|
||||
/* Speaker Allocation Block */
|
||||
u8 speaker_allocation_start_offset;
|
||||
u8 speaker_designation;
|
||||
u8 reserved[2];
|
||||
|
||||
/* Vendor Specific Data Block */
|
||||
u8 vendor_specific_offset;
|
||||
u8 ieee_registration[3];
|
||||
u8 component_source[2];
|
||||
|
||||
struct edid_detailed_timing_descriptor dtb[4];
|
||||
|
||||
u8 padding[29];
|
||||
|
||||
u8 checksum;
|
||||
};
|
||||
|
||||
struct __packed cea_dbc_header {
|
||||
unsigned length : 5;
|
||||
unsigned block_type_tag : 3;
|
||||
};
|
||||
|
||||
#define CEA_DATA_BLOCK_TAG_AUDIO (0x1)
|
||||
|
||||
enum cea_dbc_audio_format {
|
||||
CEA_AUDIO_FORMAT_RESERVED0,
|
||||
CEA_AUDIO_FORMAT_LPCM,
|
||||
CEA_AUDIO_FORMAT_AC3,
|
||||
CEA_AUDIO_FORMAT_MPEG1,
|
||||
CEA_AUDIO_FORMAT_MP3,
|
||||
CEA_AUDIO_FORMAT_MPEG2,
|
||||
CEA_AUDIO_FORMAT_AAC,
|
||||
CEA_AUDIO_FORMAT_DTS,
|
||||
CEA_AUDIO_FORMAT_ATRAC,
|
||||
CEA_AUDIO_FORMAT_SACD_1BIT,
|
||||
CEA_AUDIO_FORMAT_DOLBYDIGITALPLUS,
|
||||
CEA_AUDIO_FORMAT_DTSHD,
|
||||
CEA_AUDIO_FORMAT_MLP_DOLBYTRUEHD,
|
||||
CEA_AUDIO_FORMAT_DST_AUDIO,
|
||||
CEA_AUDIO_FORMAT_WMA_PRO,
|
||||
CEA_AUDIO_FORMAT_RESERVED15,
|
||||
};
|
||||
|
||||
struct __packed cea_dbc_audio {
|
||||
unsigned channels : 3;
|
||||
unsigned audio_format : 4;
|
||||
unsigned audio_reserved : 1;
|
||||
|
||||
unsigned freq_32kHz : 1;
|
||||
unsigned freq_44kHz : 1;
|
||||
unsigned freq_48kHz : 1;
|
||||
unsigned freq_88kHz : 1;
|
||||
unsigned freq_96kHz : 1;
|
||||
unsigned freq_176kHz : 1;
|
||||
unsigned freq_192kHz : 1;
|
||||
unsigned freq_reserved : 1;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned bits_16 : 1;
|
||||
unsigned bits_20 : 1;
|
||||
unsigned bits_24 : 1;
|
||||
unsigned bits_reserved : 5;
|
||||
} lpcm_bits;
|
||||
u8 rate_div_8kbps;
|
||||
} bitrate;
|
||||
};
|
||||
|
||||
#define CEA_DATA_BLOCK_TAG_VIDEO (0x2)
|
||||
|
||||
struct __packed cea_dbc_video {
|
||||
unsigned cea_mode_index : 7;
|
||||
unsigned native : 1;
|
||||
};
|
||||
|
||||
#define CEA_DATA_BLOCK_TAG_VENDOR (0x3)
|
||||
|
||||
struct __packed cea_dbc_vendor {
|
||||
u8 ieee_identifier[3]; // 0x03 0x0C 0x00 == HDMI Licensing, LLC.
|
||||
u8 cec_address[2];
|
||||
|
||||
unsigned dvi_dual_link : 1;
|
||||
unsigned reserved : 2;
|
||||
unsigned dc_y444 : 1;
|
||||
unsigned dc_30bit : 1;
|
||||
unsigned dc_36bit : 1;
|
||||
unsigned dc_48bit : 1;
|
||||
unsigned supports_ai : 1;
|
||||
|
||||
u8 max_tmds_freqency; // divided by 5Mhz
|
||||
|
||||
unsigned latency_reserved : 6;
|
||||
unsigned latency_fields_il : 1;
|
||||
unsigned latency_fields : 1;
|
||||
|
||||
u8 video_latency;
|
||||
u8 audio_latency;
|
||||
u8 video_latency_il;
|
||||
u8 audio_latency_il;
|
||||
};
|
||||
|
||||
#define CEA_DATA_BLOCK_TAG_SPEAKER (0x4)
|
||||
|
||||
struct __packed cea_dbc_speaker {
|
||||
|
||||
unsigned front_lr_present : 1; /* 2 channels */
|
||||
unsigned lfe_present : 1; /* X.1 channels */
|
||||
unsigned front_center_present : 1; /* standard center speaker */
|
||||
unsigned rear_lr_present : 1; /* surround */
|
||||
unsigned rear_center_present : 1; /* for 6.1 */
|
||||
unsigned fcenter_lr_present : 1; /* for 7.1 */
|
||||
unsigned rcenter_lr_present : 1; /* for 7.1 */
|
||||
unsigned speaker_reserved : 1;
|
||||
|
||||
u8 reserved[2];
|
||||
};
|
||||
#if !defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
#warning "structures defined and packed for little-endian byte order"
|
||||
#endif
|
||||
|
||||
/* HDMI Constants and Structures */
|
||||
#define HDMI_PACKET_TYPE_INFO_FRAME (0x80)
|
||||
@@ -337,7 +283,6 @@ enum audio_sample_size {
|
||||
};
|
||||
|
||||
enum audio_coding_extended_type {
|
||||
/* CODING TYPE_REFER_STREAM_HEADER */
|
||||
CODING_TYPE_HE_AAC = 1,
|
||||
CODING_TYPE_HE_AACv2,
|
||||
CODING_TYPE_MPEG_SURROUND,
|
||||
@@ -392,11 +337,7 @@ struct __packed audio_info_frame {
|
||||
u8 future_byte_6_10[5];
|
||||
};
|
||||
|
||||
#else /* == !__LITTLE_ENDIAN_BITFIELD */
|
||||
#warning "structures defined and packed for little-endian byte order"
|
||||
#endif
|
||||
|
||||
static inline void cea861_checksum_info_frame(u8 * const info_frame)
|
||||
static inline void cea861_checksum_hdmi_info_frame(u8 * const info_frame)
|
||||
{
|
||||
struct info_frame_header * const header =
|
||||
(struct info_frame_header *) info_frame;
|
||||
|
||||
Reference in New Issue
Block a user