aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/drm_edid.c121
-rw-r--r--include/drm/drm_crtc.h3
2 files changed, 95 insertions, 29 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index a839a28d8ee6..fab2bdf9c423 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -550,11 +550,20 @@ static int add_detailed_info(struct drm_connector *connector,
550} 550}
551 551
552#define DDC_ADDR 0x50 552#define DDC_ADDR 0x50
553 553/**
554unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) 554 * Get EDID information via I2C.
555 *
556 * \param adapter : i2c device adaptor
557 * \param buf : EDID data buffer to be filled
558 * \param len : EDID data buffer length
559 * \return 0 on success or -1 on failure.
560 *
561 * Try to fetch EDID information by calling i2c driver function.
562 */
563int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
564 unsigned char *buf, int len)
555{ 565{
556 unsigned char start = 0x0; 566 unsigned char start = 0x0;
557 unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
558 struct i2c_msg msgs[] = { 567 struct i2c_msg msgs[] = {
559 { 568 {
560 .addr = DDC_ADDR, 569 .addr = DDC_ADDR,
@@ -564,31 +573,36 @@ unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
564 }, { 573 }, {
565 .addr = DDC_ADDR, 574 .addr = DDC_ADDR,
566 .flags = I2C_M_RD, 575 .flags = I2C_M_RD,
567 .len = EDID_LENGTH, 576 .len = len,
568 .buf = buf, 577 .buf = buf,
569 } 578 }
570 }; 579 };
571 580
572 if (!buf) {
573 dev_warn(&adapter->dev, "unable to allocate memory for EDID "
574 "block.\n");
575 return NULL;
576 }
577
578 if (i2c_transfer(adapter, msgs, 2) == 2) 581 if (i2c_transfer(adapter, msgs, 2) == 2)
579 return buf; 582 return 0;
580 583
581 dev_info(&adapter->dev, "unable to read EDID block.\n"); 584 dev_info(&adapter->dev, "unable to read EDID block.\n");
582 kfree(buf); 585 return -1;
583 return NULL;
584} 586}
585EXPORT_SYMBOL(drm_do_probe_ddc_edid); 587EXPORT_SYMBOL(drm_do_probe_ddc_edid);
586 588
587static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) 589/**
590 * Get EDID information.
591 *
592 * \param adapter : i2c device adaptor.
593 * \param buf : EDID data buffer to be filled
594 * \param len : EDID data buffer length
595 * \return 0 on success or -1 on failure.
596 *
597 * Initialize DDC, then fetch EDID information
598 * by calling drm_do_probe_ddc_edid function.
599 */
600static int drm_ddc_read(struct i2c_adapter *adapter,
601 unsigned char *buf, int len)
588{ 602{
589 struct i2c_algo_bit_data *algo_data = adapter->algo_data; 603 struct i2c_algo_bit_data *algo_data = adapter->algo_data;
590 unsigned char *edid = NULL;
591 int i, j; 604 int i, j;
605 int ret = -1;
592 606
593 algo_data->setscl(algo_data->data, 1); 607 algo_data->setscl(algo_data->data, 1);
594 608
@@ -616,7 +630,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
616 msleep(15); 630 msleep(15);
617 631
618 /* Do the real work */ 632 /* Do the real work */
619 edid = drm_do_probe_ddc_edid(adapter); 633 ret = drm_do_probe_ddc_edid(adapter, buf, len);
620 algo_data->setsda(algo_data->data, 0); 634 algo_data->setsda(algo_data->data, 0);
621 algo_data->setscl(algo_data->data, 0); 635 algo_data->setscl(algo_data->data, 0);
622 msleep(15); 636 msleep(15);
@@ -632,7 +646,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
632 msleep(15); 646 msleep(15);
633 algo_data->setscl(algo_data->data, 0); 647 algo_data->setscl(algo_data->data, 0);
634 algo_data->setsda(algo_data->data, 0); 648 algo_data->setsda(algo_data->data, 0);
635 if (edid) 649 if (ret == 0)
636 break; 650 break;
637 } 651 }
638 /* Release the DDC lines when done or the Apple Cinema HD display 652 /* Release the DDC lines when done or the Apple Cinema HD display
@@ -641,9 +655,31 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
641 algo_data->setsda(algo_data->data, 1); 655 algo_data->setsda(algo_data->data, 1);
642 algo_data->setscl(algo_data->data, 1); 656 algo_data->setscl(algo_data->data, 1);
643 657
644 return edid; 658 return ret;
659}
660
661static int drm_ddc_read_edid(struct drm_connector *connector,
662 struct i2c_adapter *adapter,
663 char *buf, int len)
664{
665 int ret;
666
667 ret = drm_ddc_read(adapter, buf, len);
668 if (ret != 0) {
669 dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
670 drm_get_connector_name(connector));
671 goto end;
672 }
673 if (!edid_is_valid((struct edid *)buf)) {
674 dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
675 drm_get_connector_name(connector));
676 ret = -1;
677 }
678end:
679 return ret;
645} 680}
646 681
682#define MAX_EDID_EXT_NUM 4
647/** 683/**
648 * drm_get_edid - get EDID data, if available 684 * drm_get_edid - get EDID data, if available
649 * @connector: connector we're probing 685 * @connector: connector we're probing
@@ -656,24 +692,53 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
656struct edid *drm_get_edid(struct drm_connector *connector, 692struct edid *drm_get_edid(struct drm_connector *connector,
657 struct i2c_adapter *adapter) 693 struct i2c_adapter *adapter)
658{ 694{
695 int ret;
659 struct edid *edid; 696 struct edid *edid;
660 697
661 edid = (struct edid *)drm_ddc_read(adapter); 698 edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
662 if (!edid) { 699 GFP_KERNEL);
663 dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n", 700 if (edid == NULL) {
664 drm_get_connector_name(connector)); 701 dev_warn(&connector->dev->pdev->dev,
665 return NULL; 702 "Failed to allocate EDID\n");
703 goto end;
666 } 704 }
667 if (!edid_is_valid(edid)) { 705
668 dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", 706 /* Read first EDID block */
669 drm_get_connector_name(connector)); 707 ret = drm_ddc_read_edid(connector, adapter,
670 kfree(edid); 708 (unsigned char *)edid, EDID_LENGTH);
671 return NULL; 709 if (ret != 0)
710 goto clean_up;
711
712 /* There are EDID extensions to be read */
713 if (edid->extensions != 0) {
714 int edid_ext_num = edid->extensions;
715
716 if (edid_ext_num > MAX_EDID_EXT_NUM) {
717 dev_warn(&connector->dev->pdev->dev,
718 "The number of extension(%d) is "
719 "over max (%d), actually read number (%d)\n",
720 edid_ext_num, MAX_EDID_EXT_NUM,
721 MAX_EDID_EXT_NUM);
722 /* Reset EDID extension number to be read */
723 edid_ext_num = MAX_EDID_EXT_NUM;
724 }
725 /* Read EDID including extensions too */
726 ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
727 EDID_LENGTH * (edid_ext_num + 1));
728 if (ret != 0)
729 goto clean_up;
730
672 } 731 }
673 732
674 connector->display_info.raw_edid = (char *)edid; 733 connector->display_info.raw_edid = (char *)edid;
734 goto end;
675 735
736clean_up:
737 kfree(edid);
738 edid = NULL;
739end:
676 return edid; 740 return edid;
741
677} 742}
678EXPORT_SYMBOL(drm_get_edid); 743EXPORT_SYMBOL(drm_get_edid);
679 744
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 33ae98ced80e..9022b2468182 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -613,7 +613,8 @@ extern void drm_fb_release(struct drm_file *file_priv);
613extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); 613extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
614extern struct edid *drm_get_edid(struct drm_connector *connector, 614extern struct edid *drm_get_edid(struct drm_connector *connector,
615 struct i2c_adapter *adapter); 615 struct i2c_adapter *adapter);
616extern unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter); 616extern int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
617 unsigned char *buf, int len);
617extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); 618extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
618extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); 619extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
619extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode); 620extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode);