aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorArchit Taneja <archit@ti.com>2012-05-15 02:02:18 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2012-05-21 05:21:18 -0400
commit6f28c2964b535f9439d52c437aa2fbfef7ed149c (patch)
treed46ed3e233b954425ec9a74e0c33a6fd62cb0eb6 /drivers/video
parent05dd0f5308213e169b02458a7f3a61362e581e14 (diff)
OMAPDSS: DSI: Support command mode interleaving during video mode blanking periods
DSI supports interleaving of command mode packets during the HSA, HFP, HBP and BLLP blanking intervals in a video mode stream. This is useful as a user may want to read or change the configuration of a panel without stopping the video stream. On OMAP DSI, we can queue HS or LP command mode packets in the TX FIFO, and the DSI HW takes care of interleaving this data during the one of the blanking intervals. The DSI HW needs to be programmed with the maximum amount of data that can be interleaved in a particular blanking period. A blanking period cannot be used to send command mode data for it's complete duration, there is some amount of time required for the DSI data and clock lanes to transition to the desired LP or HS state. Based on the state of the lanes at the beginning and end of the blanking period, we have different scenarios, with each scenario having a different value of time required to transition to HS or LP. Refer to the section 'Interleaving Mode' in OMAP TRM for more info on the scenarios and the equations to calculate the time required for HS or LP transitions. We use the scenarios which takes the maximum time for HS or LP transition, this gives us the minimum amount of time that can be used to interleave command mode data. The amount of data that can be sent during this minimum time is calculated for command mode packets both in LP and HS. These are written to the registers DSI_VM_TIMING4 to DSI_VM_TIMING6. The calculations don't take into account the time required of transmitting BTA when doing a DSI read, or verifying if a DSI write went through correctly. Until these latencies aren't considered, the behaviour of DSI is unpredictable when a BTA is interleaved during a blanking period. Enhancement of these calculations is a TODO item. The calculations are derived from DSI parameter calculation tools written by Sebastien Fagard <s-fagard@ti.com> Signed-off-by: Archit Taneja <archit@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/omap2/dss/dsi.c181
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 */
3676static 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 */
3707static 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
3730static 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
3668static int dsi_proto_config(struct omap_dss_device *dssdev) 3848static 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);