[igt-dev] [PATCH i-g-t v6 6/7] lib/igt_edid: add support for Short Audio Descriptors

Simon Ser
2019-04-17T12:43:53Z

Signed-off-by: Simon Ser <simon.ser@intel.com>
---
lib/igt_edid.c | 73 +++++++++++++++++++++++++++++++++++++++-----
lib/igt_edid.h | 82 ++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 145 insertions(+), 10 deletions(-)

diff --git a/lib/igt_edid.c b/lib/igt_edid.c
index 52e66ab2..3d40d3b3 100644
--- a/lib/igt_edid.c
+++ b/lib/igt_edid.c
@@ -252,19 +252,76 @@ void edid_init_with_mode(struct edid *edid, drmModeModeInfo *mode)
EDID_DETAIL_MONITOR_NAME, "IGT");
}

+static uint8_t compute_checksum(const uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint8_t sum = 0;
+
+ assert(size > 0);
+ for (i = 0; i < size - 1; i++) {
+ sum += buf[i];
+ }
+
+ return 256 - sum;
+}
+
/**
* edid_update_checksum: compute and update the EDID checksum
*/
void edid_update_checksum(struct edid *edid)
{
- size_t i;
- const uint8_t *buf = (const uint8_t *) edid;
- uint8_t sum = 0;
+ edid->checksum = compute_checksum((uint8_t *) edid,
+ sizeof(struct edid));
+}

- /* calculate checksum */
- for (i = 0; i < sizeof(struct edid) - 1; i++) {
- sum = sum + buf[i];
- }
+/**
+ * cea_sad_init_pcm:
+ * @channels: the number of supported channels (max. 8)
+ * @sampling_rates: bitfield of enum cea_sad_sampling_rate
+ * @sample_sizes: bitfield of enum cea_sad_pcm_sample_size
+ *
+ * Initialize a Short Audio Descriptor to advertise PCM support.
+ */
+void cea_sad_init_pcm(struct cea_sad *sad, int channels,
+ uint8_t sampling_rates, uint8_t sample_sizes)
+{
+ assert(channels <= 8);
+ sad->format_channels = CEA_SAD_FORMAT_PCM << 3 | (channels - 1);
+ sad->sampling_rates = sampling_rates;
+ sad->bitrate = sample_sizes;
+}
+
+static void edid_cea_finalize(struct edid_cea *cea)
+{
+ cea->checksum = compute_checksum((uint8_t *) cea,
+ sizeof(struct edid_cea));
+}
+
+/**
+ * edid_ext_set_cea_sad: set an extension block to be CEA SAD
+ */
+void edid_ext_set_cea_sad(struct edid_ext *ext, const struct cea_sad *sads,
+ size_t sads_len)
+{
+ struct edid_cea *cea = &ext->data.cea;
+ struct edid_cea_data_block *data_block;
+ size_t sads_size, data_block_size;
+
+ memset(ext, 0, sizeof(struct edid_ext));
+
+ sads_size = sizeof(struct cea_sad) * sads_len;
+ data_block_size = sizeof(struct edid_cea_data_block) + sads_size;
+
+ ext->tag = EDID_EXT_CEA;
+
+ cea->revision = 3;
+ cea->dtd_start = 4 + data_block_size;
+ cea->misc = 1 << 6; /* basic audio, no DTD */
+
+ assert(sads_size <= 0xFF);
+ data_block = (struct edid_cea_data_block *) cea->data;
+ data_block->type_len = EDID_CEA_DATA_AUDIO << 5 | sads_size;
+ memcpy(data_block->data.sads, sads, sads_size);

- edid->checksum = 256 - sum;
+ edid_cea_finalize(cea);
}
diff --git a/lib/igt_edid.h b/lib/igt_edid.h
index bbcb939a..33fd7bd2 100644
--- a/lib/igt_edid.h
+++ b/lib/igt_edid.h
@@ -142,6 +142,79 @@ struct detailed_timing {
} data;
} __attribute__((packed));

+enum cea_sad_format {
+ CEA_SAD_FORMAT_PCM = 1,
+ CEA_SAD_FORMAT_AC3 = 2,
+ CEA_SAD_FORMAT_MPEG1 = 3, /* Layers 1 & 2 */
+ CEA_SAD_FORMAT_MP3 = 4,
+ CEA_SAD_FORMAT_MPEG2 = 5,
+ CEA_SAD_FORMAT_AAC = 6,
+ CEA_SAD_FORMAT_DTS = 7,
+ CEA_SAD_FORMAT_ATRAC = 8,
+ CEA_SAD_FORMAT_SACD = 9, /* One-bit audio */
+ CEA_SAD_FORMAT_DD_PLUS = 10,
+ CEA_SAD_FORMAT_DTS_HD = 11,
+ CEA_SAD_FORMAT_DOLBY = 12, /* MLP/Dolby TrueHD */
+ CEA_SAD_FORMAT_DST = 13,
+ CEA_SAD_FORMAT_WMA = 14, /* Microsoft WMA Pro */
+};
+
+enum cea_sad_sampling_rate {
+ CEA_SAD_SAMPLING_32KHZ = 1 << 0,
+ CEA_SAD_SAMPLING_44KHZ = 1 << 1,
+ CEA_SAD_SAMPLING_48KHZ = 1 << 2,
+ CEA_SAD_SAMPLING_88KHZ = 1 << 3,
+ CEA_SAD_SAMPLING_96KHZ = 1 << 4,
+ CEA_SAD_SAMPLING_176KHZ = 1 << 5,
+ CEA_SAD_SAMPLING_192KHZ = 1 << 6,
+};
+
+/* for PCM only */
+enum cea_sad_pcm_sample_size {
+ CEA_SAD_BITRATE_16 = 1 << 0,
+ CEA_SAD_BITRATE_20 = 1 << 1,
+ CEA_SAD_BITRATE_24 = 1 << 2,
+};
+
+struct cea_sad {
+ uint8_t format_channels;
+ uint8_t sampling_rates;
+ uint8_t bitrate;
+};
+
+enum edid_cea_data_type {
+ EDID_CEA_DATA_AUDIO = 1,
+ EDID_CEA_DATA_VIDEO = 2,
+ EDID_CEA_DATA_VENDOR_SPECIFIC = 3,
+ EDID_CEA_DATA_SPEAKER_ALLOC = 4,
+};
+
+struct edid_cea_data_block {
+ uint8_t type_len; /* type is from enum edid_cea_data_type */
+ union {
+ struct cea_sad sads[0];
+ } data;
+} __attribute__((packed));
+
+struct edid_cea {
+ uint8_t revision;
+ uint8_t dtd_start;
+ uint8_t misc;
+ char data[123]; /* DBC & DTD collection, padded with zeros */
+ uint8_t checksum;
+} __attribute__((packed));
+
+enum edid_ext_tag {
+ EDID_EXT_CEA = 0x02,
+};
+
+struct edid_ext {
+ uint8_t tag; /* enum edid_ext_tag */
+ union {
+ struct edid_cea cea;
+ } data;
+} __attribute__((packed));
+
struct edid {
char header[8];
/* Vendor & product info */
@@ -177,9 +250,9 @@ struct edid {
/* Detailing timings 1-4 */
struct detailed_timing detailed_timings[DETAILED_TIMINGS_LEN];
/* Number of 128 byte ext. blocks */
- uint8_t extensions;
- /* Checksum */
+ uint8_t extensions_len;
uint8_t checksum;
+ struct edid_ext extensions[];
} __attribute__((packed));

void edid_init(struct edid *edid);
@@ -193,4 +266,9 @@ void detailed_timing_set_string(struct detailed_timing *dt,
enum detailed_non_pixel_type type,
const char *str);

+void cea_sad_init_pcm(struct cea_sad *sad, int channels,
+ uint8_t sampling_rates, uint8_t sample_sizes);
+void edid_ext_set_cea_sad(struct edid_ext *ext, const struct cea_sad *sads,
+ size_t sads_len);
+
#endif
--
2.21.0