aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2010-07-28 08:53:38 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2011-05-11 07:20:13 -0400
commit40885ab31f754426c2e9a40362e568778baa5e82 (patch)
tree8593954df65902178f975a128ba4c502aa5eb341 /drivers
parent95861368e3eb2180dc9f00e916a4ba6f5e1fe4ce (diff)
OMAP: DSS2: DSI: implement ULPS enter and exit
Entering ULPS (Ultra Low Power State) happens by sending ULPS entry sequence to the DSI peripheral and pulling the DSI lines down. Exiting ULPS happens by sending ULPS exit sequence. We can send the ULPS entry sequence by using OMAP DSS HW's ULPS support, but we cannot use the ULPS exit support from DSS HW. DSS HW refuses to send the ULPS exit sequence if it thinks that the lanes are not in ULPS. After being in OFF mode the DSS HW has been reset, and so it does not know that the lanes are actually in ULPS. Thus we need to use the lane override support and manually send the ULPS exit sequence. Luckily the sequence is very simple. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/omap2/dss/dsi.c141
1 files changed, 123 insertions, 18 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 4223164f650..e2ae1e7372f 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -33,6 +33,7 @@
33#include <linux/regulator/consumer.h> 33#include <linux/regulator/consumer.h>
34#include <linux/wait.h> 34#include <linux/wait.h>
35#include <linux/workqueue.h> 35#include <linux/workqueue.h>
36#include <linux/sched.h>
36 37
37#include <video/omapdss.h> 38#include <video/omapdss.h>
38#include <plat/clock.h> 39#include <plat/clock.h>
@@ -268,6 +269,7 @@ static struct
268 struct dsi_update_region update_region; 269 struct dsi_update_region update_region;
269 270
270 bool te_enabled; 271 bool te_enabled;
272 bool ulps_enabled;
271 273
272 struct workqueue_struct *workqueue; 274 struct workqueue_struct *workqueue;
273 275
@@ -1925,9 +1927,13 @@ static void dsi_disable_lane_override(void)
1925static int dsi_complexio_init(struct omap_dss_device *dssdev) 1927static int dsi_complexio_init(struct omap_dss_device *dssdev)
1926{ 1928{
1927 int r = 0; 1929 int r = 0;
1930 u32 l;
1928 1931
1929 DSSDBG("dsi_complexio_init\n"); 1932 DSSDBG("dsi_complexio_init\n");
1930 1933
1934 if (dsi.ulps_enabled)
1935 DSSDBG("manual ulps exit\n");
1936
1931 /* A dummy read using the SCP interface to any DSIPHY register is 1937 /* A dummy read using the SCP interface to any DSIPHY register is
1932 * required after DSIPHY reset to complete the reset of the DSI complex 1938 * required after DSIPHY reset to complete the reset of the DSI complex
1933 * I/O. */ 1939 * I/O. */
@@ -1941,11 +1947,49 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev)
1941 1947
1942 dsi_complexio_config(dssdev); 1948 dsi_complexio_config(dssdev);
1943 1949
1944 r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON); 1950 dsi_if_enable(true);
1951 dsi_if_enable(false);
1952 REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
1953
1954 /* set TX STOP MODE timer to maximum for this operation */
1955 l = dsi_read_reg(DSI_TIMING1);
1956 l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
1957 l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */
1958 l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */
1959 l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */
1960 dsi_write_reg(DSI_TIMING1, l);
1961
1962 if (dsi.ulps_enabled) {
1963 /* ULPS is exited by Mark-1 state for 1ms, followed by
1964 * stop state. DSS HW cannot do this via the normal
1965 * ULPS exit sequence, as after reset the DSS HW thinks
1966 * that we are not in ULPS mode, and refuses to send the
1967 * sequence. So we need to send the ULPS exit sequence
1968 * manually.
1969 */
1970
1971 dsi_enable_lane_override(dssdev,
1972 DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P);
1973 }
1945 1974
1975 r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
1946 if (r) 1976 if (r)
1947 goto err; 1977 goto err;
1948 1978
1979 if (dsi.ulps_enabled) {
1980 /* Keep Mark-1 state for 1ms (as per DSI spec) */
1981 ktime_t wait = ns_to_ktime(1000 * 1000);
1982 set_current_state(TASK_UNINTERRUPTIBLE);
1983 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
1984
1985 /* Disable the override. The lanes should be set to Mark-11
1986 * state by the HW */
1987 dsi_disable_lane_override();
1988 }
1989
1990 /* FORCE_TX_STOP_MODE_IO */
1991 REG_FLD_MOD(DSI_TIMING1, 0, 15, 15);
1992
1949 if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) { 1993 if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
1950 DSSERR("ComplexIO not coming out of reset.\n"); 1994 DSSERR("ComplexIO not coming out of reset.\n");
1951 r = -ENODEV; 1995 r = -ENODEV;
@@ -1954,23 +1998,7 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev)
1954 1998
1955 dsi_complexio_timings(); 1999 dsi_complexio_timings();
1956 2000
1957 /* 2001 dsi.ulps_enabled = false;
1958 The configuration of the DSI complex I/O (number of data lanes,
1959 position, differential order) should not be changed while
1960 DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. For the
1961 hardware to recognize a new configuration of the complex I/O (done
1962 in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to follow
1963 this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, next
1964 reset the DSS.DSI_CTRL[0] IF_EN to 0, then set DSS.DSI_CLK_CTRL[20]
1965 LP_CLK_ENABLE to 1, and finally, set again the DSS.DSI_CTRL[0] IF_EN
1966 bit to 1. If the sequence is not followed, the DSi complex I/O
1967 configuration is undetermined.
1968 */
1969 dsi_if_enable(1);
1970 dsi_if_enable(0);
1971 REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
1972 dsi_if_enable(1);
1973 dsi_if_enable(0);
1974 2002
1975 DSSDBG("CIO init done\n"); 2003 DSSDBG("CIO init done\n");
1976err: 2004err:
@@ -2793,6 +2821,80 @@ int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
2793} 2821}
2794EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); 2822EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
2795 2823
2824static int dsi_enter_ulps(void)
2825{
2826 DECLARE_COMPLETION_ONSTACK(completion);
2827 int r;
2828
2829 DSSDBGF();
2830
2831 WARN_ON(!dsi_bus_is_locked());
2832
2833 WARN_ON(dsi.ulps_enabled);
2834
2835 if (dsi.ulps_enabled)
2836 return 0;
2837
2838 if (REG_GET(DSI_CLK_CTRL, 13, 13)) {
2839 DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n");
2840 return -EIO;
2841 }
2842
2843 dsi_sync_vc(0);
2844 dsi_sync_vc(1);
2845 dsi_sync_vc(2);
2846 dsi_sync_vc(3);
2847
2848 dsi_force_tx_stop_mode_io();
2849
2850 dsi_vc_enable(0, false);
2851 dsi_vc_enable(1, false);
2852 dsi_vc_enable(2, false);
2853 dsi_vc_enable(3, false);
2854
2855 if (REG_GET(DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */
2856 DSSERR("HS busy when enabling ULPS\n");
2857 return -EIO;
2858 }
2859
2860 if (REG_GET(DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */
2861 DSSERR("LP busy when enabling ULPS\n");
2862 return -EIO;
2863 }
2864
2865 r = dsi_register_isr_cio(dsi_completion_handler, &completion,
2866 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
2867 if (r)
2868 return r;
2869
2870 /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
2871 /* LANEx_ULPS_SIG2 */
2872 REG_FLD_MOD(DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2), 7, 5);
2873
2874 if (wait_for_completion_timeout(&completion,
2875 msecs_to_jiffies(1000)) == 0) {
2876 DSSERR("ULPS enable timeout\n");
2877 r = -EIO;
2878 goto err;
2879 }
2880
2881 dsi_unregister_isr_cio(dsi_completion_handler, &completion,
2882 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
2883
2884 dsi_complexio_power(DSI_COMPLEXIO_POWER_ULPS);
2885
2886 dsi_if_enable(false);
2887
2888 dsi.ulps_enabled = true;
2889
2890 return 0;
2891
2892err:
2893 dsi_unregister_isr_cio(dsi_completion_handler, &completion,
2894 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
2895 return r;
2896}
2897
2796static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16) 2898static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
2797{ 2899{
2798 unsigned long fck; 2900 unsigned long fck;
@@ -3547,6 +3649,9 @@ err0:
3547 3649
3548static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev) 3650static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
3549{ 3651{
3652 if (!dsi.ulps_enabled)
3653 dsi_enter_ulps();
3654
3550 /* disable interface */ 3655 /* disable interface */
3551 dsi_if_enable(0); 3656 dsi_if_enable(0);
3552 dsi_vc_enable(0, 0); 3657 dsi_vc_enable(0, 0);