|
@@ -33,6 +33,7 @@
|
|
|
#include <linux/regulator/consumer.h>
|
|
|
#include <linux/wait.h>
|
|
|
#include <linux/workqueue.h>
|
|
|
+#include <linux/sched.h>
|
|
|
|
|
|
#include <video/omapdss.h>
|
|
|
#include <plat/clock.h>
|
|
@@ -268,6 +269,7 @@ static struct
|
|
|
struct dsi_update_region update_region;
|
|
|
|
|
|
bool te_enabled;
|
|
|
+ bool ulps_enabled;
|
|
|
|
|
|
struct workqueue_struct *workqueue;
|
|
|
|
|
@@ -1925,9 +1927,13 @@ static void dsi_disable_lane_override(void)
|
|
|
static int dsi_complexio_init(struct omap_dss_device *dssdev)
|
|
|
{
|
|
|
int r = 0;
|
|
|
+ u32 l;
|
|
|
|
|
|
DSSDBG("dsi_complexio_init\n");
|
|
|
|
|
|
+ if (dsi.ulps_enabled)
|
|
|
+ DSSDBG("manual ulps exit\n");
|
|
|
+
|
|
|
/* A dummy read using the SCP interface to any DSIPHY register is
|
|
|
* required after DSIPHY reset to complete the reset of the DSI complex
|
|
|
* I/O. */
|
|
@@ -1941,11 +1947,49 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev)
|
|
|
|
|
|
dsi_complexio_config(dssdev);
|
|
|
|
|
|
- r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
|
|
|
+ dsi_if_enable(true);
|
|
|
+ dsi_if_enable(false);
|
|
|
+ REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
|
|
|
+
|
|
|
+ /* set TX STOP MODE timer to maximum for this operation */
|
|
|
+ l = dsi_read_reg(DSI_TIMING1);
|
|
|
+ l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
|
|
|
+ l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */
|
|
|
+ l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */
|
|
|
+ l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */
|
|
|
+ dsi_write_reg(DSI_TIMING1, l);
|
|
|
+
|
|
|
+ if (dsi.ulps_enabled) {
|
|
|
+ /* ULPS is exited by Mark-1 state for 1ms, followed by
|
|
|
+ * stop state. DSS HW cannot do this via the normal
|
|
|
+ * ULPS exit sequence, as after reset the DSS HW thinks
|
|
|
+ * that we are not in ULPS mode, and refuses to send the
|
|
|
+ * sequence. So we need to send the ULPS exit sequence
|
|
|
+ * manually.
|
|
|
+ */
|
|
|
+
|
|
|
+ dsi_enable_lane_override(dssdev,
|
|
|
+ DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P);
|
|
|
+ }
|
|
|
|
|
|
+ r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
|
|
|
if (r)
|
|
|
goto err;
|
|
|
|
|
|
+ if (dsi.ulps_enabled) {
|
|
|
+ /* Keep Mark-1 state for 1ms (as per DSI spec) */
|
|
|
+ ktime_t wait = ns_to_ktime(1000 * 1000);
|
|
|
+ set_current_state(TASK_UNINTERRUPTIBLE);
|
|
|
+ schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
|
|
|
+
|
|
|
+ /* Disable the override. The lanes should be set to Mark-11
|
|
|
+ * state by the HW */
|
|
|
+ dsi_disable_lane_override();
|
|
|
+ }
|
|
|
+
|
|
|
+ /* FORCE_TX_STOP_MODE_IO */
|
|
|
+ REG_FLD_MOD(DSI_TIMING1, 0, 15, 15);
|
|
|
+
|
|
|
if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
|
|
|
DSSERR("ComplexIO not coming out of reset.\n");
|
|
|
r = -ENODEV;
|
|
@@ -1954,23 +1998,7 @@ static int dsi_complexio_init(struct omap_dss_device *dssdev)
|
|
|
|
|
|
dsi_complexio_timings();
|
|
|
|
|
|
- /*
|
|
|
- The configuration of the DSI complex I/O (number of data lanes,
|
|
|
- position, differential order) should not be changed while
|
|
|
- DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. For the
|
|
|
- hardware to recognize a new configuration of the complex I/O (done
|
|
|
- in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to follow
|
|
|
- this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, next
|
|
|
- reset the DSS.DSI_CTRL[0] IF_EN to 0, then set DSS.DSI_CLK_CTRL[20]
|
|
|
- LP_CLK_ENABLE to 1, and finally, set again the DSS.DSI_CTRL[0] IF_EN
|
|
|
- bit to 1. If the sequence is not followed, the DSi complex I/O
|
|
|
- configuration is undetermined.
|
|
|
- */
|
|
|
- dsi_if_enable(1);
|
|
|
- dsi_if_enable(0);
|
|
|
- REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
|
|
|
- dsi_if_enable(1);
|
|
|
- dsi_if_enable(0);
|
|
|
+ dsi.ulps_enabled = false;
|
|
|
|
|
|
DSSDBG("CIO init done\n");
|
|
|
err:
|
|
@@ -2793,6 +2821,80 @@ int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
|
|
|
}
|
|
|
EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
|
|
|
|
|
|
+static int dsi_enter_ulps(void)
|
|
|
+{
|
|
|
+ DECLARE_COMPLETION_ONSTACK(completion);
|
|
|
+ int r;
|
|
|
+
|
|
|
+ DSSDBGF();
|
|
|
+
|
|
|
+ WARN_ON(!dsi_bus_is_locked());
|
|
|
+
|
|
|
+ WARN_ON(dsi.ulps_enabled);
|
|
|
+
|
|
|
+ if (dsi.ulps_enabled)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (REG_GET(DSI_CLK_CTRL, 13, 13)) {
|
|
|
+ DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n");
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ dsi_sync_vc(0);
|
|
|
+ dsi_sync_vc(1);
|
|
|
+ dsi_sync_vc(2);
|
|
|
+ dsi_sync_vc(3);
|
|
|
+
|
|
|
+ dsi_force_tx_stop_mode_io();
|
|
|
+
|
|
|
+ dsi_vc_enable(0, false);
|
|
|
+ dsi_vc_enable(1, false);
|
|
|
+ dsi_vc_enable(2, false);
|
|
|
+ dsi_vc_enable(3, false);
|
|
|
+
|
|
|
+ if (REG_GET(DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */
|
|
|
+ DSSERR("HS busy when enabling ULPS\n");
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (REG_GET(DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */
|
|
|
+ DSSERR("LP busy when enabling ULPS\n");
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ r = dsi_register_isr_cio(dsi_completion_handler, &completion,
|
|
|
+ DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
|
|
|
+ if (r)
|
|
|
+ return r;
|
|
|
+
|
|
|
+ /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
|
|
|
+ /* LANEx_ULPS_SIG2 */
|
|
|
+ REG_FLD_MOD(DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2), 7, 5);
|
|
|
+
|
|
|
+ if (wait_for_completion_timeout(&completion,
|
|
|
+ msecs_to_jiffies(1000)) == 0) {
|
|
|
+ DSSERR("ULPS enable timeout\n");
|
|
|
+ r = -EIO;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ dsi_unregister_isr_cio(dsi_completion_handler, &completion,
|
|
|
+ DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
|
|
|
+
|
|
|
+ dsi_complexio_power(DSI_COMPLEXIO_POWER_ULPS);
|
|
|
+
|
|
|
+ dsi_if_enable(false);
|
|
|
+
|
|
|
+ dsi.ulps_enabled = true;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err:
|
|
|
+ dsi_unregister_isr_cio(dsi_completion_handler, &completion,
|
|
|
+ DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
|
|
|
+ return r;
|
|
|
+}
|
|
|
+
|
|
|
static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
|
|
|
{
|
|
|
unsigned long fck;
|
|
@@ -3547,6 +3649,9 @@ err0:
|
|
|
|
|
|
static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
|
|
|
{
|
|
|
+ if (!dsi.ulps_enabled)
|
|
|
+ dsi_enter_ulps();
|
|
|
+
|
|
|
/* disable interface */
|
|
|
dsi_if_enable(0);
|
|
|
dsi_vc_enable(0, 0);
|