blob: 12165e8b99e32dac2f0d003409ee2ed65de5ecaa [file] [log] [blame]
Padmanabhan Komandurucc9a18512017-05-03 13:59:02 -07001/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <drm/drm_edid.h>
14
15#include "sde_kms.h"
16#include "sde_edid_parser.h"
17
18#define DBC_START_OFFSET 4
19#define EDID_DTD_LEN 18
20
21enum data_block_types {
22 RESERVED,
23 AUDIO_DATA_BLOCK,
24 VIDEO_DATA_BLOCK,
25 VENDOR_SPECIFIC_DATA_BLOCK,
26 SPEAKER_ALLOCATION_DATA_BLOCK,
27 VESA_DTC_DATA_BLOCK,
28 RESERVED2,
29 USE_EXTENDED_TAG
30};
31
32static u8 *sde_find_edid_extension(struct edid *edid, int ext_id)
33{
34 u8 *edid_ext = NULL;
35 int i;
36
37 /* No EDID or EDID extensions */
38 if (edid == NULL || edid->extensions == 0)
39 return NULL;
40
41 /* Find CEA extension */
42 for (i = 0; i < edid->extensions; i++) {
43 edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
44 if (edid_ext[0] == ext_id)
45 break;
46 }
47
48 if (i == edid->extensions)
49 return NULL;
50
51 return edid_ext;
52}
53
54static u8 *sde_find_cea_extension(struct edid *edid)
55{
56 return sde_find_edid_extension(edid, SDE_CEA_EXT);
57}
58
59static int
60sde_cea_db_payload_len(const u8 *db)
61{
62 return db[0] & 0x1f;
63}
64
65static int
66sde_cea_db_tag(const u8 *db)
67{
68 return db[0] >> 5;
69}
70
71static int
72sde_cea_revision(const u8 *cea)
73{
74 return cea[1];
75}
76
77static int
78sde_cea_db_offsets(const u8 *cea, int *start, int *end)
79{
80 /* Data block offset in CEA extension block */
81 *start = 4;
82 *end = cea[2];
83 if (*end == 0)
84 *end = 127;
85 if (*end < 4 || *end > 127)
86 return -ERANGE;
87 return 0;
88}
89
90#define sde_for_each_cea_db(cea, i, start, end) \
91for ((i) = (start); \
92(i) < (end) && (i) + sde_cea_db_payload_len(&(cea)[(i)]) < (end); \
93(i) += sde_cea_db_payload_len(&(cea)[(i)]) + 1)
94
95static u8 *sde_edid_find_extended_tag_block(struct edid *edid, int blk_id)
96{
97 u8 *db = NULL;
98 u8 *cea = NULL;
99
100 if (!edid) {
101 SDE_ERROR("%s: invalid input\n", __func__);
102 return NULL;
103 }
104
105 cea = sde_find_cea_extension(edid);
106
107 if (cea && sde_cea_revision(cea) >= 3) {
108 int i, start, end;
109
110 if (sde_cea_db_offsets(cea, &start, &end))
111 return NULL;
112
113 sde_for_each_cea_db(cea, i, start, end) {
114 db = &cea[i];
115 if ((sde_cea_db_tag(db) == SDE_EXTENDED_TAG) &&
116 (db[1] == blk_id))
117 return db;
118 }
119 }
120 return NULL;
121}
122
123static u8 *
124sde_edid_find_block(struct edid *edid, int blk_id)
125{
126 u8 *db = NULL;
127 u8 *cea = NULL;
128
129 if (!edid) {
130 SDE_ERROR("%s: invalid input\n", __func__);
131 return NULL;
132 }
133
134 cea = sde_find_cea_extension(edid);
135
136 if (cea && sde_cea_revision(cea) >= 3) {
137 int i, start, end;
138
139 if (sde_cea_db_offsets(cea, &start, &end))
140 return NULL;
141
142 sde_for_each_cea_db(cea, i, start, end) {
143 db = &cea[i];
144 if (sde_cea_db_tag(db) == blk_id)
145 return db;
146 }
147 }
148 return NULL;
149}
150
151
152static const u8 *_sde_edid_find_block(const u8 *in_buf, u32 start_offset,
153 u8 type, u8 *len)
154{
155 /* the start of data block collection, start of Video Data Block */
156 u32 offset = start_offset;
157 u32 dbc_offset = in_buf[2];
158
159 SDE_EDID_DEBUG("%s +", __func__);
160 /*
161 * * edid buffer 1, byte 2 being 4 means no non-DTD/Data block
162 * collection present.
163 * * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block
164 * collection present and no DTD data present.
165 */
166 if ((dbc_offset == 0) || (dbc_offset == 4)) {
167 SDE_ERROR("EDID: no DTD or non-DTD data present\n");
168 return NULL;
169 }
170
171 while (offset < dbc_offset) {
172 u8 block_len = in_buf[offset] & 0x1F;
173
174 if ((offset + block_len <= dbc_offset) &&
175 (in_buf[offset] >> 5) == type) {
176 *len = block_len;
177 SDE_EDID_DEBUG("block=%d found @ 0x%x w/ len=%d\n",
178 type, offset, block_len);
179
180 return in_buf + offset;
181 }
182 offset += 1 + block_len;
183 }
184
185 return NULL;
186}
187
188static void sde_edid_extract_vendor_id(struct sde_edid_ctrl *edid_ctrl)
189{
190 char *vendor_id;
191 u32 id_codes;
192
193 SDE_EDID_DEBUG("%s +", __func__);
194 if (!edid_ctrl) {
195 SDE_ERROR("%s: invalid input\n", __func__);
196 return;
197 }
198
199 vendor_id = edid_ctrl->vendor_id;
200 id_codes = ((u32)edid_ctrl->edid->mfg_id[0] << 8) +
201 edid_ctrl->edid->mfg_id[1];
202
203 vendor_id[0] = 'A' - 1 + ((id_codes >> 10) & 0x1F);
204 vendor_id[1] = 'A' - 1 + ((id_codes >> 5) & 0x1F);
205 vendor_id[2] = 'A' - 1 + (id_codes & 0x1F);
206 vendor_id[3] = 0;
207 SDE_EDID_DEBUG("vendor id is %s ", vendor_id);
208 SDE_EDID_DEBUG("%s -", __func__);
209}
210
211static void sde_edid_set_y420_support(struct drm_connector *connector,
212u32 video_format)
213{
214 u8 cea_mode = 0;
215 struct drm_display_mode *mode;
216
217 /* Need to add Y420 support flag to the modes */
218 list_for_each_entry(mode, &connector->probed_modes, head) {
219 cea_mode = drm_match_cea_mode(mode);
220 if ((cea_mode != 0) && (cea_mode == video_format)) {
221 SDE_EDID_DEBUG("%s found match for %d ", __func__,
222 video_format);
223 mode->flags |= DRM_MODE_FLAG_SUPPORTS_YUV;
224 }
225 }
226}
227
228static void sde_edid_parse_Y420CMDB(
229struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl,
230const u8 *db)
231{
232 u32 offset = 0;
233 u8 len = 0;
234 u8 svd_len = 0;
235 const u8 *svd = NULL;
236 u32 i = 0, j = 0;
237 u32 video_format = 0;
238
239 if (!edid_ctrl) {
240 SDE_ERROR("%s: edid_ctrl is NULL\n", __func__);
241 return;
242 }
243
244 if (!db) {
245 SDE_ERROR("%s: invalid input\n", __func__);
246 return;
247 }
248 SDE_EDID_DEBUG("%s +\n", __func__);
249 len = db[0] & 0x1f;
250
251 if (len < 7)
252 return;
253 /* Byte 3 to L+1 contain SVDs */
254 offset += 2;
255
256 svd = sde_edid_find_block(edid_ctrl->edid, VIDEO_DATA_BLOCK);
257
258 if (svd) {
259 /*moving to the next byte as vic info begins there*/
260 ++svd;
261 svd_len = svd[0] & 0x1f;
262 }
263
264 for (i = 0; i < svd_len; i++, j++) {
265 video_format = *svd & 0x7F;
266 if (db[offset] & (1 << j))
267 sde_edid_set_y420_support(connector, video_format);
268
269 if (j & 0x80) {
270 j = j/8;
271 offset++;
272 if (offset >= len)
273 break;
274 }
275 }
276
277 SDE_EDID_DEBUG("%s -\n", __func__);
278
279}
280
281static void sde_edid_parse_Y420VDB(
282struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl,
283const u8 *db)
284{
285 u8 len = db[0] & 0x1f;
286 u32 i = 0;
287 u32 video_format = 0;
288
289 if (!edid_ctrl) {
290 SDE_ERROR("%s: invalid input\n", __func__);
291 return;
292 }
293
294 SDE_EDID_DEBUG("%s +\n", __func__);
295
296 /* Offset to byte 3 */
297 db += 2;
298 for (i = 0; i < len - 1; i++) {
299 video_format = *(db + i) & 0x7F;
300 /*
301 * mode was already added in get_modes()
302 * only need to set the Y420 support flag
303 */
304 sde_edid_set_y420_support(connector, video_format);
305 }
306 SDE_EDID_DEBUG("%s -", __func__);
307}
308
309static void sde_edid_set_mode_format(
310struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl)
311{
312 const u8 *db = NULL;
313 struct drm_display_mode *mode;
314
315 SDE_EDID_DEBUG("%s +\n", __func__);
316 /* Set YUV mode support flags for YCbcr420VDB */
317 db = sde_edid_find_extended_tag_block(edid_ctrl->edid,
318 Y420_VIDEO_DATA_BLOCK);
319 if (db)
320 sde_edid_parse_Y420VDB(connector, edid_ctrl, db);
321 else
322 SDE_EDID_DEBUG("YCbCr420 VDB is not present\n");
323
324 /* Set RGB supported on all modes where YUV is not set */
325 list_for_each_entry(mode, &connector->probed_modes, head) {
326 if (!(mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV))
327 mode->flags |= DRM_MODE_FLAG_SUPPORTS_RGB;
328 }
329
330
331 db = sde_edid_find_extended_tag_block(edid_ctrl->edid,
332 Y420_CAPABILITY_MAP_DATA_BLOCK);
333 if (db)
334 sde_edid_parse_Y420CMDB(connector, edid_ctrl, db);
335 else
336 SDE_EDID_DEBUG("YCbCr420 CMDB is not present\n");
337
338 SDE_EDID_DEBUG("%s -\n", __func__);
339}
340
341static void _sde_edid_extract_audio_data_blocks(
342 struct sde_edid_ctrl *edid_ctrl)
343{
344 u8 len = 0;
345 u8 adb_max = 0;
346 const u8 *adb = NULL;
347 u32 offset = DBC_START_OFFSET;
348 u8 *cea = NULL;
349
350 if (!edid_ctrl) {
351 SDE_ERROR("invalid edid_ctrl\n");
352 return;
353 }
354 SDE_EDID_DEBUG("%s +", __func__);
355 cea = sde_find_cea_extension(edid_ctrl->edid);
356 if (!cea) {
357 SDE_DEBUG("CEA extension not found\n");
358 return;
359 }
360
361 edid_ctrl->adb_size = 0;
362
363 memset(edid_ctrl->audio_data_block, 0,
364 sizeof(edid_ctrl->audio_data_block));
365
366 do {
367 len = 0;
368 adb = _sde_edid_find_block(cea, offset, AUDIO_DATA_BLOCK,
369 &len);
370
371 if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE ||
372 adb_max >= MAX_NUMBER_ADB)) {
373 if (!edid_ctrl->adb_size) {
374 SDE_DEBUG("No/Invalid Audio Data Block\n");
375 return;
376 }
377
378 continue;
379 }
380
381 memcpy(edid_ctrl->audio_data_block + edid_ctrl->adb_size,
382 adb + 1, len);
383 offset = (adb - cea) + 1 + len;
384
385 edid_ctrl->adb_size += len;
386 adb_max++;
387 } while (adb);
388 SDE_EDID_DEBUG("%s -", __func__);
389}
390
391static void _sde_edid_extract_speaker_allocation_data(
392 struct sde_edid_ctrl *edid_ctrl)
393{
394 u8 len;
395 const u8 *sadb = NULL;
396 u8 *cea = NULL;
397
398 if (!edid_ctrl) {
399 SDE_ERROR("invalid edid_ctrl\n");
400 return;
401 }
402 SDE_EDID_DEBUG("%s +", __func__);
403 cea = sde_find_cea_extension(edid_ctrl->edid);
404 if (!cea) {
405 SDE_DEBUG("CEA extension not found\n");
406 return;
407 }
408
409 sadb = _sde_edid_find_block(cea, DBC_START_OFFSET,
410 SPEAKER_ALLOCATION_DATA_BLOCK, &len);
411 if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) {
412 SDE_DEBUG("No/Invalid Speaker Allocation Data Block\n");
413 return;
414 }
415
416 memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len);
417 edid_ctrl->sadb_size = len;
418
419 SDE_EDID_DEBUG("speaker alloc data SP byte = %08x %s%s%s%s%s%s%s\n",
420 sadb[1],
421 (sadb[1] & BIT(0)) ? "FL/FR," : "",
422 (sadb[1] & BIT(1)) ? "LFE," : "",
423 (sadb[1] & BIT(2)) ? "FC," : "",
424 (sadb[1] & BIT(3)) ? "RL/RR," : "",
425 (sadb[1] & BIT(4)) ? "RC," : "",
426 (sadb[1] & BIT(5)) ? "FLC/FRC," : "",
427 (sadb[1] & BIT(6)) ? "RLC/RRC," : "");
428 SDE_EDID_DEBUG("%s -", __func__);
429}
430
431struct sde_edid_ctrl *sde_edid_init(void)
432{
433 struct sde_edid_ctrl *edid_ctrl = NULL;
434
435 SDE_EDID_DEBUG("%s +\n", __func__);
436 edid_ctrl = kzalloc(sizeof(*edid_ctrl), GFP_KERNEL);
437 if (!edid_ctrl) {
438 SDE_ERROR("edid_ctrl alloc failed\n");
439 return NULL;
440 }
441 memset((edid_ctrl), 0, sizeof(*edid_ctrl));
442 SDE_EDID_DEBUG("%s -\n", __func__);
443 return edid_ctrl;
444}
445
446void sde_free_edid(void **input)
447{
448 struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(*input);
449
450 SDE_EDID_DEBUG("%s +", __func__);
451 kfree(edid_ctrl->edid);
452 edid_ctrl->edid = NULL;
453}
454
455void sde_edid_deinit(void **input)
456{
457 struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(*input);
458
459 SDE_EDID_DEBUG("%s +", __func__);
460 sde_free_edid((void *)&edid_ctrl);
461 kfree(edid_ctrl);
462 SDE_EDID_DEBUG("%s -", __func__);
463}
464
465int _sde_edid_update_modes(struct drm_connector *connector,
466 void *input)
467{
468 int rc = 0;
469 struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input);
470
471 SDE_EDID_DEBUG("%s +", __func__);
472 if (edid_ctrl->edid) {
473 drm_mode_connector_update_edid_property(connector,
474 edid_ctrl->edid);
475
476 rc = drm_add_edid_modes(connector, edid_ctrl->edid);
477 sde_edid_set_mode_format(connector, edid_ctrl);
478 SDE_EDID_DEBUG("%s -", __func__);
479 return rc;
480 }
481
482 drm_mode_connector_update_edid_property(connector, NULL);
483 SDE_EDID_DEBUG("%s null edid -", __func__);
484 return rc;
485}
486
487bool sde_detect_hdmi_monitor(void *input)
488{
489 struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input);
490
491 return drm_detect_hdmi_monitor(edid_ctrl->edid);
492}
493
494void sde_get_edid(struct drm_connector *connector,
495 struct i2c_adapter *adapter, void **input)
496{
497 struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(*input);
498
499 edid_ctrl->edid = drm_get_edid(connector, adapter);
500 SDE_EDID_DEBUG("%s +\n", __func__);
501
502 if (!edid_ctrl->edid)
503 SDE_ERROR("EDID read failed\n");
504
505 if (edid_ctrl->edid) {
506 sde_edid_extract_vendor_id(edid_ctrl);
507 _sde_edid_extract_audio_data_blocks(edid_ctrl);
508 _sde_edid_extract_speaker_allocation_data(edid_ctrl);
509 }
510 SDE_EDID_DEBUG("%s -\n", __func__);
511};