aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/dc/edid.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/video/tegra/dc/edid.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/video/tegra/dc/edid.c')
-rw-r--r--drivers/video/tegra/dc/edid.c619
1 files changed, 619 insertions, 0 deletions
diff --git a/drivers/video/tegra/dc/edid.c b/drivers/video/tegra/dc/edid.c
new file mode 100644
index 00000000000..fbcf2cc8e37
--- /dev/null
+++ b/drivers/video/tegra/dc/edid.c
@@ -0,0 +1,619 @@
1/*
2 * drivers/video/tegra/dc/edid.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * Copyright (C) 2010-2011 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20
21#include <linux/debugfs.h>
22#include <linux/fb.h>
23#include <linux/i2c.h>
24#include <linux/seq_file.h>
25#include <linux/vmalloc.h>
26
27#include "edid.h"
28
29struct tegra_edid_pvt {
30 struct kref refcnt;
31 struct tegra_edid_hdmi_eld eld;
32 bool support_stereo;
33 bool support_underscan;
34 /* Note: dc_edid must remain the last member */
35 struct tegra_dc_edid dc_edid;
36};
37
38struct tegra_edid {
39 struct i2c_client *client;
40 struct i2c_board_info info;
41 int bus;
42
43 struct tegra_edid_pvt *data;
44
45 struct mutex lock;
46};
47
48#if defined(DEBUG) || defined(CONFIG_DEBUG_FS)
49static int tegra_edid_show(struct seq_file *s, void *unused)
50{
51 struct tegra_edid *edid = s->private;
52 struct tegra_dc_edid *data;
53 u8 *buf;
54 int i;
55
56 data = tegra_edid_get_data(edid);
57 if (!data) {
58 seq_printf(s, "No EDID\n");
59 return 0;
60 }
61
62 buf = data->buf;
63
64 for (i = 0; i < data->len; i++) {
65 if (i % 16 == 0)
66 seq_printf(s, "edid[%03x] =", i);
67
68 seq_printf(s, " %02x", buf[i]);
69
70 if (i % 16 == 15)
71 seq_printf(s, "\n");
72 }
73
74 tegra_edid_put_data(data);
75
76 return 0;
77}
78#endif
79
80#ifdef CONFIG_DEBUG_FS
81static int tegra_edid_debug_open(struct inode *inode, struct file *file)
82{
83 return single_open(file, tegra_edid_show, inode->i_private);
84}
85
86static const struct file_operations tegra_edid_debug_fops = {
87 .open = tegra_edid_debug_open,
88 .read = seq_read,
89 .llseek = seq_lseek,
90 .release = single_release,
91};
92
93void tegra_edid_debug_add(struct tegra_edid *edid)
94{
95 char name[] = "edidX";
96
97 snprintf(name, sizeof(name), "edid%1d", edid->bus);
98 debugfs_create_file(name, S_IRUGO, NULL, edid, &tegra_edid_debug_fops);
99}
100#else
101void tegra_edid_debug_add(struct tegra_edid *edid)
102{
103}
104#endif
105
106#ifdef DEBUG
107static char tegra_edid_dump_buff[16 * 1024];
108
109static void tegra_edid_dump(struct tegra_edid *edid)
110{
111 struct seq_file s;
112 int i;
113 char c;
114
115 memset(&s, 0x0, sizeof(s));
116
117 s.buf = tegra_edid_dump_buff;
118 s.size = sizeof(tegra_edid_dump_buff);
119 s.private = edid;
120
121 tegra_edid_show(&s, NULL);
122
123 i = 0;
124 while (i < s.count ) {
125 if ((s.count - i) > 256) {
126 c = s.buf[i + 256];
127 s.buf[i + 256] = 0;
128 printk("%s", s.buf + i);
129 s.buf[i + 256] = c;
130 } else {
131 printk("%s", s.buf + i);
132 }
133 i += 256;
134 }
135}
136#else
137static void tegra_edid_dump(struct tegra_edid *edid)
138{
139}
140#endif
141
142int tegra_edid_read_block(struct tegra_edid *edid, int block, u8 *data)
143{
144 u8 block_buf[] = {block >> 1};
145 u8 cmd_buf[] = {(block & 0x1) * 128};
146 int status;
147 struct i2c_msg msg[] = {
148 {
149 .addr = 0x30,
150 .flags = 0,
151 .len = 1,
152 .buf = block_buf,
153 },
154 {
155 .addr = 0x50,
156 .flags = 0,
157 .len = 1,
158 .buf = cmd_buf,
159 },
160 {
161 .addr = 0x50,
162 .flags = I2C_M_RD,
163 .len = 128,
164 .buf = data,
165 }};
166 struct i2c_msg *m;
167 int msg_len;
168
169 if (block > 1) {
170 msg_len = 3;
171 m = msg;
172 } else {
173 msg_len = 2;
174 m = &msg[1];
175 }
176
177 status = i2c_transfer(edid->client->adapter, m, msg_len);
178
179 if (status < 0)
180 return status;
181
182 if (status != msg_len)
183 return -EIO;
184
185 return 0;
186}
187
188int tegra_edid_parse_ext_block(const u8 *raw, int idx,
189 struct tegra_edid_pvt *edid)
190{
191 const u8 *ptr;
192 u8 tmp;
193 u8 code;
194 int len;
195 int i;
196 bool basic_audio = false;
197
198 ptr = &raw[0];
199
200 /* If CEA 861 block get info for eld struct */
201 if (edid && ptr) {
202 if (*ptr <= 3)
203 edid->eld.eld_ver = 0x02;
204 edid->eld.cea_edid_ver = ptr[1];
205
206 /* check for basic audio support in CEA 861 block */
207 if(raw[3] & (1<<6)) {
208 /* For basic audio, set spk_alloc to Left+Right.
209 * If there is a Speaker Alloc block this will
210 * get over written with that value */
211 basic_audio = true;
212 }
213 }
214
215 if (raw[3] & 0x80)
216 edid->support_underscan = 1;
217 else
218 edid->support_underscan = 0;
219
220 ptr = &raw[4];
221
222 while (ptr < &raw[idx]) {
223 tmp = *ptr;
224 len = tmp & 0x1f;
225
226 /* HDMI Specification v1.4a, section 8.3.2:
227 * see Table 8-16 for HDMI VSDB format.
228 * data blocks have tags in top 3 bits:
229 * tag code 2: video data block
230 * tag code 3: vendor specific data block
231 */
232 code = (tmp >> 5) & 0x7;
233 switch (code) {
234 case 1:
235 {
236 edid->eld.sad_count = len;
237 edid->eld.conn_type = 0x00;
238 edid->eld.support_hdcp = 0x00;
239 for (i = 0; (i < len) && (i < ELD_MAX_SAD); i ++)
240 edid->eld.sad[i] = ptr[i + 1];
241 len++;
242 ptr += len; /* adding the header */
243 /* Got an audio data block so enable audio */
244 if(basic_audio == true)
245 edid->eld.spk_alloc = 1;
246 break;
247 }
248 /* case 2 is commented out for now */
249 case 3:
250 {
251 int j = 0;
252
253 if ((ptr[1] == 0x03) &&
254 (ptr[2] == 0x0c) &&
255 (ptr[3] == 0)) {
256 edid->eld.port_id[0] = ptr[4];
257 edid->eld.port_id[1] = ptr[5];
258 }
259 if ((len >= 8) &&
260 (ptr[1] == 0x03) &&
261 (ptr[2] == 0x0c) &&
262 (ptr[3] == 0)) {
263 j = 8;
264 tmp = ptr[j++];
265 /* HDMI_Video_present? */
266 if (tmp & 0x20) {
267 /* Latency_Fields_present? */
268 if (tmp & 0x80)
269 j += 2;
270 /* I_Latency_Fields_present? */
271 if (tmp & 0x40)
272 j += 2;
273 /* 3D_present? */
274 if (j <= len && (ptr[j] & 0x80))
275 edid->support_stereo = 1;
276 }
277 }
278 if ((len > 5) &&
279 (ptr[1] == 0x03) &&
280 (ptr[2] == 0x0c) &&
281 (ptr[3] == 0)) {
282
283 edid->eld.support_ai = (ptr[6] & 0x80);
284 }
285
286 if ((len > 9) &&
287 (ptr[1] == 0x03) &&
288 (ptr[2] == 0x0c) &&
289 (ptr[3] == 0)) {
290
291 edid->eld.aud_synch_delay = ptr[10];
292 }
293 len++;
294 ptr += len; /* adding the header */
295 break;
296 }
297 case 4:
298 {
299 edid->eld.spk_alloc = ptr[1];
300 len++;
301 ptr += len; /* adding the header */
302 break;
303 }
304 default:
305 len++; /* len does not include header */
306 ptr += len;
307 break;
308 }
309 }
310
311 return 0;
312}
313
314int tegra_edid_mode_support_stereo(struct fb_videomode *mode)
315{
316 if (!mode)
317 return 0;
318
319 if (mode->xres == 1280 &&
320 mode->yres == 720 &&
321 ((mode->refresh == 60) || (mode->refresh == 50)))
322 return 1;
323
324 /* Disabling 1080p stereo mode due to bug 869099. */
325 /* Must re-enable this to 1 once it is fixed. */
326 if (mode->xres == 1920 && mode->yres == 1080 && mode->refresh == 24)
327 return 0;
328
329 return 0;
330}
331
332static void data_release(struct kref *ref)
333{
334 struct tegra_edid_pvt *data =
335 container_of(ref, struct tegra_edid_pvt, refcnt);
336 vfree(data);
337}
338
339int tegra_edid_get_monspecs_test(struct tegra_edid *edid,
340 struct fb_monspecs *specs, unsigned char *edid_ptr)
341{
342 int i, j, ret;
343 int extension_blocks;
344 struct tegra_edid_pvt *new_data, *old_data;
345 u8 *data;
346
347 new_data = vmalloc(SZ_32K + sizeof(struct tegra_edid_pvt));
348 if (!new_data)
349 return -ENOMEM;
350
351 kref_init(&new_data->refcnt);
352
353 new_data->support_stereo = 0;
354 new_data->support_underscan = 0;
355
356 data = new_data->dc_edid.buf;
357 memcpy(data, edid_ptr, 128);
358
359 memset(specs, 0x0, sizeof(struct fb_monspecs));
360 memset(&new_data->eld, 0x0, sizeof(new_data->eld));
361 fb_edid_to_monspecs(data, specs);
362 if (specs->modedb == NULL) {
363 ret = -EINVAL;
364 goto fail;
365 }
366
367 memcpy(new_data->eld.monitor_name, specs->monitor,
368 sizeof(specs->monitor));
369
370 new_data->eld.mnl = strlen(new_data->eld.monitor_name) + 1;
371 new_data->eld.product_id[0] = data[0x8];
372 new_data->eld.product_id[1] = data[0x9];
373 new_data->eld.manufacture_id[0] = data[0xA];
374 new_data->eld.manufacture_id[1] = data[0xB];
375
376 extension_blocks = data[0x7e];
377 for (i = 1; i <= extension_blocks; i++) {
378 memcpy(data+128, edid_ptr+128, 128);
379
380 if (data[i * 128] == 0x2) {
381 fb_edid_add_monspecs(data + i * 128, specs);
382
383 tegra_edid_parse_ext_block(data + i * 128,
384 data[i * 128 + 2], new_data);
385
386 if (new_data->support_stereo) {
387 for (j = 0; j < specs->modedb_len; j++) {
388 if (tegra_edid_mode_support_stereo(
389 &specs->modedb[j]))
390 specs->modedb[j].vmode |=
391#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
392 FB_VMODE_STEREO_FRAME_PACK;
393#else
394 FB_VMODE_STEREO_LEFT_RIGHT;
395#endif
396 }
397 }
398 }
399 }
400
401 new_data->dc_edid.len = i * 128;
402
403 mutex_lock(&edid->lock);
404 old_data = edid->data;
405 edid->data = new_data;
406 mutex_unlock(&edid->lock);
407
408 if (old_data)
409 kref_put(&old_data->refcnt, data_release);
410
411 tegra_edid_dump(edid);
412 return 0;
413fail:
414 vfree(new_data);
415 return ret;
416}
417
418int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs)
419{
420 int i;
421 int j;
422 int ret;
423 int extension_blocks;
424 struct tegra_edid_pvt *new_data, *old_data;
425 u8 *data;
426
427 new_data = vmalloc(SZ_32K + sizeof(struct tegra_edid_pvt));
428 if (!new_data)
429 return -ENOMEM;
430
431 kref_init(&new_data->refcnt);
432
433 new_data->support_stereo = 0;
434
435 data = new_data->dc_edid.buf;
436
437 ret = tegra_edid_read_block(edid, 0, data);
438 if (ret)
439 goto fail;
440
441 memset(specs, 0x0, sizeof(struct fb_monspecs));
442 memset(&new_data->eld, 0x0, sizeof(new_data->eld));
443 fb_edid_to_monspecs(data, specs);
444 if (specs->modedb == NULL) {
445 ret = -EINVAL;
446 goto fail;
447 }
448 memcpy(new_data->eld.monitor_name, specs->monitor, sizeof(specs->monitor));
449 new_data->eld.mnl = strlen(new_data->eld.monitor_name) + 1;
450 new_data->eld.product_id[0] = data[0x8];
451 new_data->eld.product_id[1] = data[0x9];
452 new_data->eld.manufacture_id[0] = data[0xA];
453 new_data->eld.manufacture_id[1] = data[0xB];
454
455 extension_blocks = data[0x7e];
456
457 for (i = 1; i <= extension_blocks; i++) {
458 ret = tegra_edid_read_block(edid, i, data + i * 128);
459 if (ret < 0)
460 break;
461
462 if (data[i * 128] == 0x2) {
463 fb_edid_add_monspecs(data + i * 128, specs);
464
465 tegra_edid_parse_ext_block(data + i * 128,
466 data[i * 128 + 2], new_data);
467
468 if (new_data->support_stereo) {
469 for (j = 0; j < specs->modedb_len; j++) {
470 if (tegra_edid_mode_support_stereo(
471 &specs->modedb[j]))
472 specs->modedb[j].vmode |=
473#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
474 FB_VMODE_STEREO_FRAME_PACK;
475#else
476 FB_VMODE_STEREO_LEFT_RIGHT;
477#endif
478 }
479 }
480 }
481 }
482
483 new_data->dc_edid.len = i * 128;
484
485 mutex_lock(&edid->lock);
486 old_data = edid->data;
487 edid->data = new_data;
488 mutex_unlock(&edid->lock);
489
490 if (old_data)
491 kref_put(&old_data->refcnt, data_release);
492
493 tegra_edid_dump(edid);
494 return 0;
495
496fail:
497 vfree(new_data);
498 return ret;
499}
500
501int tegra_edid_underscan_supported(struct tegra_edid *edid)
502{
503 if ((!edid) || (!edid->data))
504 return 0;
505
506 return edid->data->support_underscan;
507}
508
509int tegra_edid_get_eld(struct tegra_edid *edid, struct tegra_edid_hdmi_eld *elddata)
510{
511 if (!elddata || !edid->data)
512 return -EFAULT;
513
514 memcpy(elddata,&edid->data->eld,sizeof(struct tegra_edid_hdmi_eld));
515
516 return 0;
517}
518
519struct tegra_edid *tegra_edid_create(int bus)
520{
521 struct tegra_edid *edid;
522 struct i2c_adapter *adapter;
523 int err;
524
525 edid = kzalloc(sizeof(struct tegra_edid), GFP_KERNEL);
526 if (!edid)
527 return ERR_PTR(-ENOMEM);
528
529 mutex_init(&edid->lock);
530 strlcpy(edid->info.type, "tegra_edid", sizeof(edid->info.type));
531 edid->bus = bus;
532 edid->info.addr = 0x50;
533 edid->info.platform_data = edid;
534
535 adapter = i2c_get_adapter(bus);
536 if (!adapter) {
537 pr_err("can't get adpater for bus %d\n", bus);
538 err = -EBUSY;
539 goto free_edid;
540 }
541
542 edid->client = i2c_new_device(adapter, &edid->info);
543 i2c_put_adapter(adapter);
544
545 if (!edid->client) {
546 pr_err("can't create new device\n");
547 err = -EBUSY;
548 goto free_edid;
549 }
550
551 tegra_edid_debug_add(edid);
552
553 return edid;
554
555free_edid:
556 kfree(edid);
557
558 return ERR_PTR(err);
559}
560
561void tegra_edid_destroy(struct tegra_edid *edid)
562{
563 i2c_release_client(edid->client);
564 if (edid->data)
565 kref_put(&edid->data->refcnt, data_release);
566 kfree(edid);
567}
568
569struct tegra_dc_edid *tegra_edid_get_data(struct tegra_edid *edid)
570{
571 struct tegra_edid_pvt *data;
572
573 mutex_lock(&edid->lock);
574 data = edid->data;
575 if (data)
576 kref_get(&data->refcnt);
577 mutex_unlock(&edid->lock);
578
579 return data ? &data->dc_edid : NULL;
580}
581
582void tegra_edid_put_data(struct tegra_dc_edid *data)
583{
584 struct tegra_edid_pvt *pvt;
585
586 if (!data)
587 return;
588
589 pvt = container_of(data, struct tegra_edid_pvt, dc_edid);
590
591 kref_put(&pvt->refcnt, data_release);
592}
593
594static const struct i2c_device_id tegra_edid_id[] = {
595 { "tegra_edid", 0 },
596 { }
597};
598
599MODULE_DEVICE_TABLE(i2c, tegra_edid_id);
600
601static struct i2c_driver tegra_edid_driver = {
602 .id_table = tegra_edid_id,
603 .driver = {
604 .name = "tegra_edid",
605 },
606};
607
608static int __init tegra_edid_init(void)
609{
610 return i2c_add_driver(&tegra_edid_driver);
611}
612
613static void __exit tegra_edid_exit(void)
614{
615 i2c_del_driver(&tegra_edid_driver);
616}
617
618module_init(tegra_edid_init);
619module_exit(tegra_edid_exit);