diff options
| -rw-r--r-- | drivers/gpu/drm/drm_edid.c | 121 | ||||
| -rw-r--r-- | include/drm/drm_crtc.h | 3 |
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 | /** | |
| 554 | unsigned 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 | */ | ||
| 563 | int 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 | } |
| 585 | EXPORT_SYMBOL(drm_do_probe_ddc_edid); | 587 | EXPORT_SYMBOL(drm_do_probe_ddc_edid); |
| 586 | 588 | ||
| 587 | static 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 | */ | ||
| 600 | static 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 | |||
| 661 | static 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 | } | ||
| 678 | end: | ||
| 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) | |||
| 656 | struct edid *drm_get_edid(struct drm_connector *connector, | 692 | struct 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 | ||
| 736 | clean_up: | ||
| 737 | kfree(edid); | ||
| 738 | edid = NULL; | ||
| 739 | end: | ||
| 676 | return edid; | 740 | return edid; |
| 741 | |||
| 677 | } | 742 | } |
| 678 | EXPORT_SYMBOL(drm_get_edid); | 743 | EXPORT_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); | |||
| 613 | extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); | 613 | extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); |
| 614 | extern struct edid *drm_get_edid(struct drm_connector *connector, | 614 | extern struct edid *drm_get_edid(struct drm_connector *connector, |
| 615 | struct i2c_adapter *adapter); | 615 | struct i2c_adapter *adapter); |
| 616 | extern unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter); | 616 | extern int drm_do_probe_ddc_edid(struct i2c_adapter *adapter, |
| 617 | unsigned char *buf, int len); | ||
| 617 | extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); | 618 | extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); |
| 618 | extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); | 619 | extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); |
| 619 | extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode); | 620 | extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode); |
