summaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/dc/dp.c
diff options
context:
space:
mode:
authorAnimesh Kishore <ankishore@nvidia.com>2015-08-20 11:44:18 -0400
committerAnimesh Kishore <ankishore@nvidia.com>2015-10-08 08:19:06 -0400
commit4c0d6812bcc97387c81b330963fcec802e741e60 (patch)
treeb75c271b30dfb866616fd98910765bee902c9797 /drivers/video/tegra/dc/dp.c
parentc29244bdfa3a145340510965826a4ca95892106f (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/dp.c')
-rw-r--r--drivers/video/tegra/dc/dp.c93
1 files changed, 61 insertions, 32 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. 594static 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)
596static 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
619static 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