diff options
author | Animesh Kishore <ankishore@nvidia.com> | 2015-08-20 11:44:18 -0400 |
---|---|---|
committer | Animesh Kishore <ankishore@nvidia.com> | 2015-10-08 08:19:06 -0400 |
commit | 4c0d6812bcc97387c81b330963fcec802e741e60 (patch) | |
tree | b75c271b30dfb866616fd98910765bee902c9797 /drivers/video/tegra/dc | |
parent | c29244bdfa3a145340510965826a4ca95892106f (diff) |
video: tegra: dp: Fix CTS 4.2.2.9
CTS description: E-DDC 4 block edid read
Bug 200103501
Change-Id: I76503dc2a21369514816650d308d5b823d4540c7
Signed-off-by: Animesh Kishore <ankishore@nvidia.com>
Reviewed-on: http://git-master/r/786624
(cherry picked from commit d86a9312fbd8d19aaa63615b19e599d122064658)
Reviewed-on: http://git-master/r/812199
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/dc')
-rw-r--r-- | drivers/video/tegra/dc/dp.c | 93 | ||||
-rw-r--r-- | drivers/video/tegra/dc/edid.c | 2 |
2 files changed, 62 insertions, 33 deletions
diff --git a/drivers/video/tegra/dc/dp.c b/drivers/video/tegra/dc/dp.c index 7ea1dfb2c..d7923a7af 100644 --- a/drivers/video/tegra/dc/dp.c +++ b/drivers/video/tegra/dc/dp.c | |||
@@ -590,17 +590,38 @@ int tegra_dc_dpaux_read(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr, | |||
590 | return ret; | 590 | return ret; |
591 | } | 591 | } |
592 | 592 | ||
593 | /* I2C read over DPAUX cannot handle more than 16B per transaction due to | 593 | /* TODO: Handle update status scenario and size > 16 bytes*/ |
594 | * DPAUX transaction limitation. | 594 | static int tegra_dc_dp_i2c_write(struct tegra_dc_dp_data *dp, u32 i2c_addr, |
595 | * This requires breaking each read into multiple i2c write/read transaction */ | 595 | u8 *data, u32 *size, u32 *aux_stat) |
596 | static int tegra_dc_i2c_read(struct tegra_dc_dp_data *dp, u32 i2c_addr, | ||
597 | u32 addr, u8 *data, u32 *size, u32 *aux_stat) | ||
598 | { | 596 | { |
599 | u32 finished = 0; | 597 | int ret = 0; |
600 | u32 cur_size; | 598 | |
601 | int ret = 0; | 599 | if (*size == 0) { |
602 | u32 len; | 600 | dev_err(&dp->dc->ndev->dev, |
603 | u8 iaddr = (u8)addr; | 601 | "dp: i2c write size can't be 0\n"); |
602 | return -EINVAL; | ||
603 | } | ||
604 | |||
605 | if (dp->dc->out->type == TEGRA_DC_OUT_FAKE_DP) | ||
606 | return ret; | ||
607 | |||
608 | mutex_lock(&dp->dpaux_lock); | ||
609 | |||
610 | ret = tegra_dc_dpaux_write_chunk_locked(dp, | ||
611 | DPAUX_DP_AUXCTL_CMD_MOTWR, | ||
612 | i2c_addr, data, size, aux_stat); | ||
613 | |||
614 | mutex_unlock(&dp->dpaux_lock); | ||
615 | |||
616 | return ret; | ||
617 | } | ||
618 | |||
619 | static int tegra_dc_dp_i2c_read(struct tegra_dc_dp_data *dp, u32 i2c_addr, | ||
620 | u8 *data, u32 *size, u32 *aux_stat) | ||
621 | { | ||
622 | u32 finished = 0; | ||
623 | u32 cur_size; | ||
624 | int ret = 0; | ||
604 | 625 | ||
605 | if (*size == 0) { | 626 | if (*size == 0) { |
606 | dev_err(&dp->dc->ndev->dev, | 627 | dev_err(&dp->dc->ndev->dev, |
@@ -612,30 +633,32 @@ static int tegra_dc_i2c_read(struct tegra_dc_dp_data *dp, u32 i2c_addr, | |||
612 | return ret; | 633 | return ret; |
613 | 634 | ||
614 | mutex_lock(&dp->dpaux_lock); | 635 | mutex_lock(&dp->dpaux_lock); |
636 | |||
615 | do { | 637 | do { |
616 | cur_size = *size - finished; | 638 | cur_size = *size - finished; |
639 | |||
617 | if (cur_size > DP_AUX_MAX_BYTES) | 640 | if (cur_size > DP_AUX_MAX_BYTES) |
618 | cur_size = DP_AUX_MAX_BYTES; | 641 | cur_size = DP_AUX_MAX_BYTES; |
619 | 642 | ||
620 | len = 1; | 643 | ret = tegra_dc_dpaux_read_chunk_locked(dp, |
621 | ret = tegra_dc_dpaux_write_chunk_locked(dp, | 644 | DPAUX_DP_AUXCTL_CMD_MOTRD, |
622 | DPAUX_DP_AUXCTL_CMD_MOTWR, | 645 | i2c_addr, data, &cur_size, aux_stat); |
623 | i2c_addr, &iaddr, &len, aux_stat); | ||
624 | if (!ret) { | ||
625 | ret = tegra_dc_dpaux_read_chunk_locked(dp, | ||
626 | DPAUX_DP_AUXCTL_CMD_I2CRD, | ||
627 | i2c_addr, data, &cur_size, aux_stat); | ||
628 | } | ||
629 | if (ret) | 646 | if (ret) |
630 | break; | 647 | break; |
631 | 648 | ||
632 | iaddr += cur_size; | ||
633 | data += cur_size; | 649 | data += cur_size; |
634 | finished += cur_size; | 650 | finished += cur_size; |
635 | } while (*size > finished); | 651 | } while (*size > finished); |
652 | |||
653 | cur_size = 0; | ||
654 | tegra_dc_dpaux_read_chunk_locked(dp, | ||
655 | DPAUX_DP_AUXCTL_CMD_I2CRD, | ||
656 | i2c_addr, data, &cur_size, aux_stat); | ||
657 | |||
636 | mutex_unlock(&dp->dpaux_lock); | 658 | mutex_unlock(&dp->dpaux_lock); |
637 | 659 | ||
638 | *size = finished; | 660 | *size = finished; |
661 | |||
639 | return ret; | 662 | return ret; |
640 | } | 663 | } |
641 | 664 | ||
@@ -669,22 +692,28 @@ static int tegra_dc_dp_i2c_xfer(struct tegra_dc *dc, struct i2c_msg *msgs, | |||
669 | u32 aux_stat; | 692 | u32 aux_stat; |
670 | int status = 0; | 693 | int status = 0; |
671 | u32 len = 0; | 694 | u32 len = 0; |
672 | u32 start_addr = 0; | ||
673 | struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc); | 695 | struct tegra_dc_dp_data *dp = tegra_dc_get_outdata(dc); |
674 | 696 | ||
675 | for (i = 0; i < num; ++i) { | 697 | for (i = 0; i < num; ++i) { |
676 | pmsg = &msgs[i]; | 698 | pmsg = &msgs[i]; |
677 | 699 | ||
678 | if (!pmsg->flags && pmsg->addr == 0x50) { /* write */ | 700 | if (!pmsg->flags) { |
679 | /* | ||
680 | * Ignore writes to I2C addr 0x30 for now. | ||
681 | * This means we can't access 256-byte chunks. | ||
682 | */ | ||
683 | start_addr = pmsg->buf[0]; | ||
684 | } else if (pmsg->flags & I2C_M_RD) { /* Read */ | ||
685 | len = pmsg->len; | 701 | len = pmsg->len; |
686 | status = tegra_dc_i2c_read(dp, pmsg->addr, start_addr, | 702 | |
687 | pmsg->buf, &len, &aux_stat); | 703 | status = tegra_dc_dp_i2c_write(dp, pmsg->addr, |
704 | pmsg->buf, &len, &aux_stat); | ||
705 | if (status) { | ||
706 | dev_err(&dp->dc->ndev->dev, | ||
707 | "dp: Failed for I2C write" | ||
708 | " addr:%d, size:%d, stat:0x%x\n", | ||
709 | pmsg->addr, len, aux_stat); | ||
710 | return status; | ||
711 | } | ||
712 | } else if (pmsg->flags & I2C_M_RD) { | ||
713 | len = pmsg->len; | ||
714 | |||
715 | status = tegra_dc_dp_i2c_read(dp, pmsg->addr, | ||
716 | pmsg->buf, &len, &aux_stat); | ||
688 | if (status) { | 717 | if (status) { |
689 | dev_err(&dp->dc->ndev->dev, | 718 | dev_err(&dp->dc->ndev->dev, |
690 | "dp: Failed for I2C read" | 719 | "dp: Failed for I2C read" |
@@ -693,13 +722,13 @@ static int tegra_dc_dp_i2c_xfer(struct tegra_dc *dc, struct i2c_msg *msgs, | |||
693 | return status; | 722 | return status; |
694 | } | 723 | } |
695 | } else { | 724 | } else { |
696 | /* No other functionalities are supported for now */ | ||
697 | dev_err(&dp->dc->ndev->dev, | 725 | dev_err(&dp->dc->ndev->dev, |
698 | "dp: i2x_xfer: Unknown flag 0x%x\n", | 726 | "dp: i2x_xfer: Invalid i2c flag 0x%x\n", |
699 | pmsg->flags); | 727 | pmsg->flags); |
700 | return -EINVAL; | 728 | return -EINVAL; |
701 | } | 729 | } |
702 | } | 730 | } |
731 | |||
703 | return i; | 732 | return i; |
704 | } | 733 | } |
705 | 734 | ||
diff --git a/drivers/video/tegra/dc/edid.c b/drivers/video/tegra/dc/edid.c index 64720c8fb..135ca9f18 100644 --- a/drivers/video/tegra/dc/edid.c +++ b/drivers/video/tegra/dc/edid.c | |||
@@ -131,7 +131,7 @@ static int tegra_edid_i2c_divide_rate(struct tegra_edid *edid) | |||
131 | int tegra_edid_read_block(struct tegra_edid *edid, int block, u8 *data) | 131 | int tegra_edid_read_block(struct tegra_edid *edid, int block, u8 *data) |
132 | { | 132 | { |
133 | u8 block_buf[] = {block >> 1}; | 133 | u8 block_buf[] = {block >> 1}; |
134 | u8 cmd_buf[] = {(block & 0x1) * 128}; | 134 | u8 cmd_buf[] = {(block % 0x2) * 128}; |
135 | u8 i; | 135 | u8 i; |
136 | u8 last_checksum = 0; | 136 | u8 last_checksum = 0; |
137 | size_t attempt_cnt = 0; | 137 | size_t attempt_cnt = 0; |