diff options
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index e2aaf5a167fa..f2d835fc4dc3 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -3665,6 +3665,186 @@ static void dsi_config_blanking_modes(struct omap_dss_device *dssdev) | |||
3665 | dsi_write_reg(dsidev, DSI_CTRL, r); | 3665 | dsi_write_reg(dsidev, DSI_CTRL, r); |
3666 | } | 3666 | } |
3667 | 3667 | ||
3668 | /* | ||
3669 | * According to section 'HS Command Mode Interleaving' in OMAP TRM, Scenario 3 | ||
3670 | * results in maximum transition time for data and clock lanes to enter and | ||
3671 | * exit HS mode. Hence, this is the scenario where the least amount of command | ||
3672 | * mode data can be interleaved. We program the minimum amount of TXBYTECLKHS | ||
3673 | * clock cycles that can be used to interleave command mode data in HS so that | ||
3674 | * all scenarios are satisfied. | ||
3675 | */ | ||
3676 | static int dsi_compute_interleave_hs(int blank, bool ddr_alwon, int enter_hs, | ||
3677 | int exit_hs, int exiths_clk, int ddr_pre, int ddr_post) | ||
3678 | { | ||
3679 | int transition; | ||
3680 | |||
3681 | /* | ||
3682 | * If DDR_CLK_ALWAYS_ON is set, we need to consider HS mode transition | ||
3683 | * time of data lanes only, if it isn't set, we need to consider HS | ||
3684 | * transition time of both data and clock lanes. HS transition time | ||
3685 | * of Scenario 3 is considered. | ||
3686 | */ | ||
3687 | if (ddr_alwon) { | ||
3688 | transition = enter_hs + exit_hs + max(enter_hs, 2) + 1; | ||
3689 | } else { | ||
3690 | int trans1, trans2; | ||
3691 | trans1 = ddr_pre + enter_hs + exit_hs + max(enter_hs, 2) + 1; | ||
3692 | trans2 = ddr_pre + enter_hs + exiths_clk + ddr_post + ddr_pre + | ||
3693 | enter_hs + 1; | ||
3694 | transition = max(trans1, trans2); | ||
3695 | } | ||
3696 | |||
3697 | return blank > transition ? blank - transition : 0; | ||
3698 | } | ||
3699 | |||
3700 | /* | ||
3701 | * According to section 'LP Command Mode Interleaving' in OMAP TRM, Scenario 1 | ||
3702 | * results in maximum transition time for data lanes to enter and exit LP mode. | ||
3703 | * Hence, this is the scenario where the least amount of command mode data can | ||
3704 | * be interleaved. We program the minimum amount of bytes that can be | ||
3705 | * interleaved in LP so that all scenarios are satisfied. | ||
3706 | */ | ||
3707 | static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs, | ||
3708 | int lp_clk_div, int tdsi_fclk) | ||
3709 | { | ||
3710 | int trans_lp; /* time required for a LP transition, in TXBYTECLKHS */ | ||
3711 | int tlp_avail; /* time left for interleaving commands, in CLKIN4DDR */ | ||
3712 | int ttxclkesc; /* period of LP transmit escape clock, in CLKIN4DDR */ | ||
3713 | int thsbyte_clk = 16; /* Period of TXBYTECLKHS clock, in CLKIN4DDR */ | ||
3714 | int lp_inter; /* cmd mode data that can be interleaved, in bytes */ | ||
3715 | |||
3716 | /* maximum LP transition time according to Scenario 1 */ | ||
3717 | trans_lp = exit_hs + max(enter_hs, 2) + 1; | ||
3718 | |||
3719 | /* CLKIN4DDR = 16 * TXBYTECLKHS */ | ||
3720 | tlp_avail = thsbyte_clk * (blank - trans_lp); | ||
3721 | |||
3722 | ttxclkesc = tdsi_fclk / lp_clk_div; | ||
3723 | |||
3724 | lp_inter = ((tlp_avail - 8 * thsbyte_clk - 5 * tdsi_fclk) / ttxclkesc - | ||
3725 | 26) / 16; | ||
3726 | |||
3727 | return max(lp_inter, 0); | ||
3728 | } | ||
3729 | |||
3730 | static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) | ||
3731 | { | ||
3732 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3733 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3734 | int blanking_mode; | ||
3735 | int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode; | ||
3736 | int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div; | ||
3737 | int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat; | ||
3738 | int tclk_trail, ths_exit, exiths_clk; | ||
3739 | bool ddr_alwon; | ||
3740 | struct omap_video_timings *timings = &dssdev->panel.timings; | ||
3741 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | ||
3742 | int ndl = dsi->num_lanes_used - 1; | ||
3743 | int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; | ||
3744 | int hsa_interleave_hs = 0, hsa_interleave_lp = 0; | ||
3745 | int hfp_interleave_hs = 0, hfp_interleave_lp = 0; | ||
3746 | int hbp_interleave_hs = 0, hbp_interleave_lp = 0; | ||
3747 | int bl_interleave_hs = 0, bl_interleave_lp = 0; | ||
3748 | u32 r; | ||
3749 | |||
3750 | r = dsi_read_reg(dsidev, DSI_CTRL); | ||
3751 | blanking_mode = FLD_GET(r, 20, 20); | ||
3752 | hfp_blanking_mode = FLD_GET(r, 21, 21); | ||
3753 | hbp_blanking_mode = FLD_GET(r, 22, 22); | ||
3754 | hsa_blanking_mode = FLD_GET(r, 23, 23); | ||
3755 | |||
3756 | r = dsi_read_reg(dsidev, DSI_VM_TIMING1); | ||
3757 | hbp = FLD_GET(r, 11, 0); | ||
3758 | hfp = FLD_GET(r, 23, 12); | ||
3759 | hsa = FLD_GET(r, 31, 24); | ||
3760 | |||
3761 | r = dsi_read_reg(dsidev, DSI_CLK_TIMING); | ||
3762 | ddr_clk_post = FLD_GET(r, 7, 0); | ||
3763 | ddr_clk_pre = FLD_GET(r, 15, 8); | ||
3764 | |||
3765 | r = dsi_read_reg(dsidev, DSI_VM_TIMING7); | ||
3766 | exit_hs_mode_lat = FLD_GET(r, 15, 0); | ||
3767 | enter_hs_mode_lat = FLD_GET(r, 31, 16); | ||
3768 | |||
3769 | r = dsi_read_reg(dsidev, DSI_CLK_CTRL); | ||
3770 | lp_clk_div = FLD_GET(r, 12, 0); | ||
3771 | ddr_alwon = FLD_GET(r, 13, 13); | ||
3772 | |||
3773 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); | ||
3774 | ths_exit = FLD_GET(r, 7, 0); | ||
3775 | |||
3776 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); | ||
3777 | tclk_trail = FLD_GET(r, 15, 8); | ||
3778 | |||
3779 | exiths_clk = ths_exit + tclk_trail; | ||
3780 | |||
3781 | width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8); | ||
3782 | bllp = hbp + hfp + hsa + DIV_ROUND_UP(width_bytes + 6, ndl); | ||
3783 | |||
3784 | if (!hsa_blanking_mode) { | ||
3785 | hsa_interleave_hs = dsi_compute_interleave_hs(hsa, ddr_alwon, | ||
3786 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3787 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
3788 | hsa_interleave_lp = dsi_compute_interleave_lp(hsa, | ||
3789 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3790 | lp_clk_div, dsi_fclk_hsdiv); | ||
3791 | } | ||
3792 | |||
3793 | if (!hfp_blanking_mode) { | ||
3794 | hfp_interleave_hs = dsi_compute_interleave_hs(hfp, ddr_alwon, | ||
3795 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3796 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
3797 | hfp_interleave_lp = dsi_compute_interleave_lp(hfp, | ||
3798 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3799 | lp_clk_div, dsi_fclk_hsdiv); | ||
3800 | } | ||
3801 | |||
3802 | if (!hbp_blanking_mode) { | ||
3803 | hbp_interleave_hs = dsi_compute_interleave_hs(hbp, ddr_alwon, | ||
3804 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3805 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
3806 | |||
3807 | hbp_interleave_lp = dsi_compute_interleave_lp(hbp, | ||
3808 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3809 | lp_clk_div, dsi_fclk_hsdiv); | ||
3810 | } | ||
3811 | |||
3812 | if (!blanking_mode) { | ||
3813 | bl_interleave_hs = dsi_compute_interleave_hs(bllp, ddr_alwon, | ||
3814 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3815 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
3816 | |||
3817 | bl_interleave_lp = dsi_compute_interleave_lp(bllp, | ||
3818 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3819 | lp_clk_div, dsi_fclk_hsdiv); | ||
3820 | } | ||
3821 | |||
3822 | DSSDBG("DSI HS interleaving(TXBYTECLKHS) HSA %d, HFP %d, HBP %d, BLLP %d\n", | ||
3823 | hsa_interleave_hs, hfp_interleave_hs, hbp_interleave_hs, | ||
3824 | bl_interleave_hs); | ||
3825 | |||
3826 | DSSDBG("DSI LP interleaving(bytes) HSA %d, HFP %d, HBP %d, BLLP %d\n", | ||
3827 | hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp, | ||
3828 | bl_interleave_lp); | ||
3829 | |||
3830 | r = dsi_read_reg(dsidev, DSI_VM_TIMING4); | ||
3831 | r = FLD_MOD(r, hsa_interleave_hs, 23, 16); | ||
3832 | r = FLD_MOD(r, hfp_interleave_hs, 15, 8); | ||
3833 | r = FLD_MOD(r, hbp_interleave_hs, 7, 0); | ||
3834 | dsi_write_reg(dsidev, DSI_VM_TIMING4, r); | ||
3835 | |||
3836 | r = dsi_read_reg(dsidev, DSI_VM_TIMING5); | ||
3837 | r = FLD_MOD(r, hsa_interleave_lp, 23, 16); | ||
3838 | r = FLD_MOD(r, hfp_interleave_lp, 15, 8); | ||
3839 | r = FLD_MOD(r, hbp_interleave_lp, 7, 0); | ||
3840 | dsi_write_reg(dsidev, DSI_VM_TIMING5, r); | ||
3841 | |||
3842 | r = dsi_read_reg(dsidev, DSI_VM_TIMING6); | ||
3843 | r = FLD_MOD(r, bl_interleave_hs, 31, 15); | ||
3844 | r = FLD_MOD(r, bl_interleave_lp, 16, 0); | ||
3845 | dsi_write_reg(dsidev, DSI_VM_TIMING6, r); | ||
3846 | } | ||
3847 | |||
3668 | static int dsi_proto_config(struct omap_dss_device *dssdev) | 3848 | static int dsi_proto_config(struct omap_dss_device *dssdev) |
3669 | { | 3849 | { |
3670 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3850 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
@@ -3723,6 +3903,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
3723 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | 3903 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { |
3724 | dsi_config_vp_sync_events(dssdev); | 3904 | dsi_config_vp_sync_events(dssdev); |
3725 | dsi_config_blanking_modes(dssdev); | 3905 | dsi_config_blanking_modes(dssdev); |
3906 | dsi_config_cmd_mode_interleaving(dssdev); | ||
3726 | } | 3907 | } |
3727 | 3908 | ||
3728 | dsi_vc_initial_config(dsidev, 0); | 3909 | dsi_vc_initial_config(dsidev, 0); |