aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/mcde
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/mcde')
-rw-r--r--drivers/video/mcde/display-ab8500.c1
-rwxr-xr-xdrivers/video/mcde/display-av8100.c2
-rw-r--r--drivers/video/mcde/display-generic_dsi.c17
-rw-r--r--drivers/video/mcde/mcde_display.c6
-rw-r--r--drivers/video/mcde/mcde_fb.c6
-rw-r--r--drivers/video/mcde/mcde_hw.c251
6 files changed, 229 insertions, 54 deletions
diff --git a/drivers/video/mcde/display-ab8500.c b/drivers/video/mcde/display-ab8500.c
index 426e23cbf60..cdce3bfa002 100644
--- a/drivers/video/mcde/display-ab8500.c
+++ b/drivers/video/mcde/display-ab8500.c
@@ -300,6 +300,7 @@ static int set_video_mode(
set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY);
mcde_chnl_set_col_convert(ddev->chnl_state,
&pdata->rgb_2_yCbCr_convert);
+ mcde_chnl_stop_flow(ddev->chnl_state);
res = mcde_chnl_set_video_mode(ddev->chnl_state, &ddev->video_mode);
if (res < 0) {
dev_warn(&ddev->dev, "%s:Failed to set video mode on channel\n",
diff --git a/drivers/video/mcde/display-av8100.c b/drivers/video/mcde/display-av8100.c
index 6de32c3ddf3..96fed0bf8ee 100755
--- a/drivers/video/mcde/display-av8100.c
+++ b/drivers/video/mcde/display-av8100.c
@@ -194,6 +194,8 @@ static int hdmi_set_video_mode(
if (dev->port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422)
mcde_chnl_set_col_convert(dev->chnl_state,
&pdata->rgb_2_yCbCr_convert);
+ mcde_chnl_stop_flow(dev->chnl_state);
+
ret = mcde_chnl_set_video_mode(dev->chnl_state, &dev->video_mode);
if (ret < 0) {
dev_warn(&dev->dev, "Failed to set video mode\n");
diff --git a/drivers/video/mcde/display-generic_dsi.c b/drivers/video/mcde/display-generic_dsi.c
index 15b8ccec59a..d445d806a6a 100644
--- a/drivers/video/mcde/display-generic_dsi.c
+++ b/drivers/video/mcde/display-generic_dsi.c
@@ -13,24 +13,23 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio.h>
+#include <linux/err.h>
#include <video/mcde_display.h>
#include <video/mcde_display-generic_dsi.h>
static int generic_platform_enable(struct mcde_display_device *dev)
{
- int ret = 0;
struct mcde_display_generic_platform_data *pdata =
dev->dev.platform_data;
dev_dbg(&dev->dev, "%s: Reset & power on generic display\n", __func__);
if (pdata->regulator) {
- ret = regulator_enable(pdata->regulator);
- if (ret < 0) {
+ if (regulator_enable(pdata->regulator) < 0) {
dev_err(&dev->dev, "%s:Failed to enable regulator\n"
, __func__);
- goto out;
+ return -EINVAL;
}
}
if (pdata->reset_gpio)
@@ -39,24 +38,24 @@ static int generic_platform_enable(struct mcde_display_device *dev)
if (pdata->reset_gpio)
gpio_set_value(pdata->reset_gpio, !pdata->reset_high);
out:
- return ret;
+ return 0;
}
static int generic_platform_disable(struct mcde_display_device *dev)
{
- int ret = 0;
struct mcde_display_generic_platform_data *pdata =
dev->dev.platform_data;
dev_dbg(&dev->dev, "%s:Reset & power off generic display\n", __func__);
if (pdata->regulator) {
- ret = regulator_disable(pdata->regulator);
- if (ret < 0)
+ if (regulator_disable(pdata->regulator) < 0) {
dev_err(&dev->dev, "%s:Failed to disable regulator\n"
, __func__);
+ return -EINVAL;
+ }
}
- return ret;
+ return 0;
}
static int __devinit generic_probe(struct mcde_display_device *dev)
diff --git a/drivers/video/mcde/mcde_display.c b/drivers/video/mcde/mcde_display.c
index 1537980dcaf..a3aff5021b9 100644
--- a/drivers/video/mcde/mcde_display.c
+++ b/drivers/video/mcde/mcde_display.c
@@ -205,7 +205,7 @@ static int mcde_display_set_synchronized_update_default(
struct mcde_display_device *ddev, bool enable)
{
int ret = 0;
- if (ddev->port->type == MCDE_PORTTYPE_DSI) {
+ if (ddev->port->type == MCDE_PORTTYPE_DSI && enable) {
if (ddev->port->sync_src == MCDE_SYNCSRC_TE0 ||
ddev->port->sync_src == MCDE_SYNCSRC_TE1 ||
ddev->port->sync_src == MCDE_SYNCSRC_BTA) {
@@ -216,7 +216,7 @@ static int mcde_display_set_synchronized_update_default(
ret = -EINVAL;
}
} else {
- ret = -EINVAL;
+ ret = 0;
}
if (ret < 0) {
@@ -253,6 +253,8 @@ static int mcde_display_apply_config_default(struct mcde_display_device *ddev)
}
if (ddev->update_flags) {
+ if (ddev->update_flags & UPDATE_FLAG_VIDEO_MODE)
+ mcde_chnl_stop_flow(ddev->chnl_state);
ret = mcde_chnl_apply(ddev->chnl_state);
if (ret < 0) {
dev_warn(&ddev->dev, "%s:Failed to apply to channel\n",
diff --git a/drivers/video/mcde/mcde_fb.c b/drivers/video/mcde/mcde_fb.c
index f9697d2e9df..b5515b85a18 100644
--- a/drivers/video/mcde/mcde_fb.c
+++ b/drivers/video/mcde/mcde_fb.c
@@ -376,7 +376,7 @@ static int check_var(struct fb_var_screeninfo *var, struct fb_info *fbi,
ret = mcde_dss_try_video_mode(ddev, &vmode);
if (ret < 0) {
dev_vdbg(&(ddev->dev), "check_var failed "
- "mcde_dss_try_video_mode with size = %x \n", ret);
+ "mcde_dss_try_video_mode with size = %x\n", ret);
return ret;
}
vmode_to_var(&vmode, var);
@@ -416,7 +416,7 @@ static int apply_var(struct fb_info *fbi, struct mcde_display_device *ddev)
ret = reallocate_fb_mem(fbi, size);
if (ret) {
dev_vdbg(&(ddev->dev), "apply_var failed with"
- "reallocate mem with size = %d \n", size);
+ "reallocate mem with size = %d\n", size);
return ret;
}
fbi->fix.line_length = line_len;
@@ -579,6 +579,8 @@ struct fb_info *mcde_fb_create(struct mcde_display_device *ddev,
if (ret)
goto ovly_enable_failed;
+ mfb->id = ddev->id;
+
/* Register framebuffer */
ret = register_framebuffer(fbi);
if (ret)
diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c
index 3a8f30aa91e..ef3bd0328d3 100644
--- a/drivers/video/mcde/mcde_hw.c
+++ b/drivers/video/mcde/mcde_hw.c
@@ -30,6 +30,7 @@
#include <mach/prcmu-fw-api.h>
static void disable_channel(struct mcde_chnl_state *chnl);
+static void watchdog_auto_sync_timer_function(unsigned long arg);
#define MSEC_TO_JIFFIES(__x) (((__x) * HZ + HZ - 1) / 1000)
@@ -47,13 +48,13 @@ static struct clk *clock_dsi;
static struct clk *clock_mcde;
static struct clk *clock_dsi_lp;
-static inline u32 dsi_rreg(int __i, u32 __reg)
+static inline u32 dsi_rreg(int i, u32 reg)
{
- return readl(dsiio[__i] + __reg);
+ return readl(dsiio[i] + reg);
}
-static inline void dsi_wreg(int __i, u32 __reg, u32 __val)
+static inline void dsi_wreg(int i, u32 reg, u32 val)
{
- writel(__val, dsiio[__i] + __reg);
+ writel(val, dsiio[i] + reg);
}
#define dsi_rfld(__i, __reg, __fld) \
((dsi_rreg(__i, __reg) & __reg##_##__fld##_MASK) >> \
@@ -63,13 +64,13 @@ static inline void dsi_wreg(int __i, u32 __reg, u32 __val)
~__reg##_##__fld##_MASK) | (((__val) << __reg##_##__fld##_SHIFT) & \
__reg##_##__fld##_MASK))
-static inline u32 mcde_rreg(u32 __reg)
+static inline u32 mcde_rreg(u32 reg)
{
- return readl(mcdeio + __reg);
+ return readl(mcdeio + reg);
}
-static inline void mcde_wreg(u32 __reg, u32 __val)
+static inline void mcde_wreg(u32 reg, u32 val)
{
- writel(__val, mcdeio + __reg);
+ writel(val, mcdeio + reg);
}
#define mcde_rfld(__reg, __fld) \
((mcde_rreg(__reg) & __reg##_##__fld##_MASK) >> \
@@ -200,6 +201,8 @@ struct mcde_chnl_state {
u32 transactionid_regs;
u32 transactionid_hw;
wait_queue_head_t waitq_hw; /* Waitq for transactionid_hw */
+ /* Used as watchdog timer for auto sync feature */
+ struct timer_list auto_sync_timer;
enum mcde_display_power_mode power_mode;
@@ -350,7 +353,6 @@ int mcde_chnl_set_video_mode(struct mcde_chnl_state *chnl,
if (chnl == NULL || vmode == NULL)
return -EINVAL;
- disable_channel(chnl);
chnl->vmode = *vmode;
return 0;
@@ -367,7 +369,7 @@ static void tv_video_mode_apply(struct mcde_chnl_state *chnl)
chnl->tv_regs.fsl2 = chnl->vmode.vbp2;
chnl->tv_regs.interlaced_en = chnl->vmode.interlaced;
- if (chnl->port.phy.dpi.num_data_lanes == 4)
+ if (chnl->port.phy.dpi.bus_width == 4)
chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P_BE;
else
chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P;
@@ -525,6 +527,8 @@ static irqreturn_t mcde_irq_handler(int irq, void *dev)
{
int i;
u32 irq_status;
+ bool trig = false;
+ struct mcde_chnl_state *chnl;
/* Handle overlay irqs */
irq_status = mcde_rfld(MCDE_RISOVL, OVLFDRIS);
@@ -540,32 +544,81 @@ static irqreturn_t mcde_irq_handler(int irq, void *dev)
/* Handle channel irqs */
irq_status = mcde_rreg(MCDE_RISPP);
if (irq_status & MCDE_RISPP_VCMPARIS_MASK) {
- struct mcde_chnl_state *chnl = &channels[MCDE_CHNL_A];
+ chnl = &channels[MCDE_CHNL_A];
chnl->transactionid_hw = chnl->transactionid_regs;
wake_up(&chnl->waitq_hw);
mcde_wfld(MCDE_RISPP, VCMPARIS, 1);
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
}
if (irq_status & MCDE_RISPP_VCMPBRIS_MASK) {
- struct mcde_chnl_state *chnl = &channels[MCDE_CHNL_B];
+ chnl = &channels[MCDE_CHNL_B];
chnl->transactionid_hw = chnl->transactionid_regs;
wake_up(&chnl->waitq_hw);
mcde_wfld(MCDE_RISPP, VCMPBRIS, 1);
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
}
if (irq_status & MCDE_RISPP_VCMPC0RIS_MASK) {
- struct mcde_chnl_state *chnl = &channels[MCDE_CHNL_C0];
+ chnl = &channels[MCDE_CHNL_C0];
chnl->transactionid_hw = chnl->transactionid_regs;
wake_up(&chnl->waitq_hw);
mcde_wfld(MCDE_RISPP, VCMPC0RIS, 1);
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
}
if (irq_status & MCDE_RISPP_VCMPC1RIS_MASK) {
- struct mcde_chnl_state *chnl = &channels[MCDE_CHNL_C1];
+ chnl = &channels[MCDE_CHNL_C1];
chnl->transactionid_hw = chnl->transactionid_regs;
wake_up(&chnl->waitq_hw);
mcde_wfld(MCDE_RISPP, VCMPC1RIS, 1);
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
}
for (i = 0; i < num_dsilinks; i++) {
- bool trig = false;
- struct mcde_chnl_state *chnl;
+ struct mcde_chnl_state *chnl_from_dsi;
+
+ trig = false;
irq_status = dsi_rfld(i, DSI_DIRECT_CMD_STS_FLAG,
TE_RECEIVED_FLAG);
if (irq_status) {
@@ -582,13 +635,14 @@ static irqreturn_t mcde_irq_handler(int irq, void *dev)
}
if (!trig)
continue;
- chnl = find_channel_by_dsilink(i);
- if (chnl) {
+ chnl_from_dsi = find_channel_by_dsilink(i);
+ if (chnl_from_dsi) {
mcde_wreg(MCDE_CHNL0SYNCHSW +
- chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ chnl_from_dsi->id *
+ MCDE_CHNL0SYNCHSW_GROUPOFFSET,
MCDE_CHNL0SYNCHSW_SW_TRIG(true));
dev_vdbg(&mcde_dev->dev, "SW TRIG DSI%d, chnl=%d\n", i,
- chnl->id);
+ chnl_from_dsi->id);
}
}
@@ -797,6 +851,23 @@ static void update_overlay_registers(u8 idx, struct ovly_regs *regs,
#endif /* CONFIG_AV8100_SDTV */
if (regs->reset_buf_id) {
+ u32 sel_mod = MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL;
+ if (port->update_auto_trig && port->type == MCDE_PORTTYPE_DSI) {
+ switch (port->sync_src) {
+ case MCDE_SYNCSRC_OFF:
+ sel_mod = MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL;
+ break;
+ case MCDE_SYNCSRC_TE0:
+ case MCDE_SYNCSRC_TE1:
+ default:
+ sel_mod = MCDE_EXTSRC0CR_SEL_MOD_AUTO_TOGGLE;
+ }
+ } else if (port->type == MCDE_PORTTYPE_DPI) {
+ sel_mod = port->update_auto_trig ?
+ MCDE_EXTSRC0CR_SEL_MOD_AUTO_TOGGLE :
+ MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL;
+ }
+
regs->reset_buf_id = false;
mcde_wreg(MCDE_EXTSRC0CONF + idx * MCDE_EXTSRC0CONF_GROUPOFFSET,
MCDE_EXTSRC0CONF_BUF_ID(0) |
@@ -807,9 +878,7 @@ static void update_overlay_registers(u8 idx, struct ovly_regs *regs,
MCDE_EXTSRC0CONF_BEBO(regs->bebo) |
MCDE_EXTSRC0CONF_BEPO(false));
mcde_wreg(MCDE_EXTSRC0CR + idx * MCDE_EXTSRC0CR_GROUPOFFSET,
- MCDE_EXTSRC0CR_SEL_MOD(port->update_auto_trig ?
- MCDE_EXTSRC0CR_SEL_MOD_AUTO_TOGGLE :
- MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL) |
+ MCDE_EXTSRC0CR_SEL_MOD(sel_mod) |
MCDE_EXTSRC0CR_MULTIOVL_CTRL_ENUM(PRIMARY) |
MCDE_EXTSRC0CR_FS_DIV_DISABLE(false) |
MCDE_EXTSRC0CR_FORCE_FS_DIV(false));
@@ -951,6 +1020,42 @@ static void enable_channel(struct mcde_chnl_state *chnl)
}
}
+static int is_channel_enabled(struct mcde_chnl_state *chnl)
+{
+ switch (chnl->id) {
+ case MCDE_CHNL_A:
+ return mcde_rfld(MCDE_CRA0, FLOEN);
+ case MCDE_CHNL_B:
+ return mcde_rfld(MCDE_CRB0, FLOEN);
+ case MCDE_CHNL_C0:
+ return mcde_rfld(MCDE_CRC, FLOEN);
+ case MCDE_CHNL_C1:
+ return mcde_rfld(MCDE_CRC, FLOEN);
+ }
+ return 0;
+}
+
+static void watchdog_auto_sync_timer_function(unsigned long arg)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(channels); i++) {
+ struct mcde_chnl_state *chnl = &channels[i];
+ if (chnl->port.update_auto_trig &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF &&
+ chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->continous_running) {
+ mcde_wreg(MCDE_CHNL0SYNCHSW +
+ chnl->id
+ * MCDE_CHNL0SYNCHSW_GROUPOFFSET,
+ MCDE_CHNL0SYNCHSW_SW_TRIG(true));
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG
+ * 1000));
+ }
+ }
+}
+
/* TODO get from register */
#define MCDE_CLK_FREQ_MHZ 160
@@ -960,14 +1065,30 @@ void update_channel_registers(enum mcde_chnl chnl_id, struct chnl_regs *regs,
{
u8 idx = chnl_id;
u32 out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER;
+ u32 src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE;
dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
/* Channel */
- if (port->update_auto_trig && port->type != MCDE_PORTTYPE_DPI) {
- out_synch_src = port->sync_src == MCDE_SYNCSRC_TE0 ?
- MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_VSYNC0 :
- MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_VSYNC1;
+ if (port->update_auto_trig && port->type == MCDE_PORTTYPE_DSI) {
+ switch (port->sync_src) {
+ case MCDE_SYNCSRC_TE0:
+ out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_VSYNC0;
+ src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_OUTPUT;
+ break;
+ case MCDE_SYNCSRC_OFF:
+ src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE;
+ break;
+ case MCDE_SYNCSRC_TE1:
+ default:
+ out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_VSYNC1;
+ src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_OUTPUT;
+ }
+ } else if (port->type == MCDE_PORTTYPE_DPI) {
+ src_synch = port->update_auto_trig ?
+ MCDE_CHNL0SYNCHMOD_SRC_SYNCH_OUTPUT :
+ MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE;
}
+
mcde_wreg(MCDE_CHNL0CONF + idx * MCDE_CHNL0CONF_GROUPOFFSET,
MCDE_CHNL0CONF_PPL(regs->ppl-1) |
MCDE_CHNL0CONF_LPF(regs->lpf-1));
@@ -976,9 +1097,7 @@ void update_channel_registers(enum mcde_chnl chnl_id, struct chnl_regs *regs,
MCDE_CHNL0STAT_CHNLRD(true));
mcde_wreg(MCDE_CHNL0SYNCHMOD +
idx * MCDE_CHNL0SYNCHMOD_GROUPOFFSET,
- MCDE_CHNL0SYNCHMOD_SRC_SYNCH(port->update_auto_trig ?
- MCDE_CHNL0SYNCHMOD_SRC_SYNCH_OUTPUT :
- MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE) |
+ MCDE_CHNL0SYNCHMOD_SRC_SYNCH(src_synch) |
MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC(out_synch_src));
mcde_wreg(MCDE_CHNL0BCKGNDCOL + idx * MCDE_CHNL0BCKGNDCOL_GROUPOFFSET,
MCDE_CHNL0BCKGNDCOL_B(255) | /* TODO: Temp */
@@ -1317,7 +1436,9 @@ int mcde_chnl_set_pixel_format(struct mcde_chnl_state *chnl,
{
if (!chnl->inuse)
return -EINVAL;
+
chnl->pix_fmt = pix_fmt;
+
return 0;
}
@@ -1434,8 +1555,19 @@ static void chnl_update_continous(struct mcde_chnl_state *chnl)
mcde_wfld(MCDE_CRC, SYCEN0, true);
else if (chnl->port.sync_src == MCDE_SYNCSRC_TE1)
mcde_wfld(MCDE_CRC, SYCEN1, true);
-
chnl->continous_running = true;
+ /*
+ * For main and secondary display,
+ * FLOWEN has to be set before a SOFTWARE TRIG
+ * Otherwise not overlay interrupt is triggerd
+ */
+ enable_channel(chnl);
+ if (chnl->port.type == MCDE_PORTTYPE_DSI &&
+ chnl->port.sync_src == MCDE_SYNCSRC_OFF) {
+ mod_timer(&chnl->auto_sync_timer,
+ jiffies +
+ msecs_to_jiffies(MCDE_AUTO_SYNC_WATCHDOG * 1000));
+ }
}
}
@@ -1446,6 +1578,18 @@ static void chnl_update_non_continous(struct mcde_chnl_state *chnl)
if (chnl->transactionid_regs < chnl->transactionid)
chnl_update_registers(chnl);
+ /*
+ * For main and secondary display,
+ * FLOWEN has to be set before a SOFTWARE TRIG
+ * Otherwise not overlay interrupt is triggerd
+ * However FLOWEN must not be triggered before SOFTWARE TRIG
+ * if rotation is enabled
+ */
+ if (chnl->power_mode == MCDE_DISPLAY_PM_STANDBY ||
+ (!is_channel_enabled(chnl) && !chnl->regs.roten))
+ enable_channel(chnl);
+
+
/* TODO: look at port sync source and synched_update */
if (chnl->regs.synchronized_update &&
chnl->power_mode == MCDE_DISPLAY_PM_ON) {
@@ -1463,6 +1607,8 @@ static void chnl_update_non_continous(struct mcde_chnl_state *chnl)
dev_vdbg(&mcde_dev->dev, "Channel update (no sync), chnl=%d\n",
chnl->id);
}
+ if (chnl->power_mode == MCDE_DISPLAY_PM_ON)
+ enable_channel(chnl);
}
static void chnl_update_overlay(struct mcde_chnl_state *chnl,
@@ -1474,10 +1620,9 @@ static void chnl_update_overlay(struct mcde_chnl_state *chnl,
update_overlay_address_registers(ovly->idx, &ovly->regs);
if (ovly->regs.reset_buf_id) {
- if (chnl->continous_running)
- disable_channel(chnl);
- else
+ if (!chnl->continous_running)
wait_for_overlay(ovly);
+
update_overlay_registers(ovly->idx, &ovly->regs, &chnl->port,
chnl->fifo, chnl->regs.x, chnl->regs.y,
chnl->regs.ppl, chnl->regs.lpf, ovly->stride,
@@ -1521,8 +1666,6 @@ int mcde_chnl_update(struct mcde_chnl_state *chnl,
else
chnl_update_non_continous(chnl);
- enable_channel(chnl);
-
dev_vdbg(&mcde_dev->dev, "Channel updated, chnl=%d\n", chnl->id);
return 0;
}
@@ -1539,6 +1682,11 @@ void mcde_chnl_put(struct mcde_chnl_state *chnl)
update_channel_static_registers(chnl);
}
+void mcde_chnl_stop_flow(struct mcde_chnl_state *chnl)
+{
+ disable_channel(chnl);
+}
+
/* MCDE overlays */
struct mcde_ovly_state *mcde_ovly_get(struct mcde_chnl_state *chnl)
{
@@ -1634,7 +1782,7 @@ void mcde_ovly_apply(struct mcde_ovly_state *ovly)
ovly->regs.enabled = ovly->paddr != 0;
ovly->regs.baseaddress0 = ovly->paddr;
ovly->regs.baseaddress1 = ovly->paddr + ovly->stride;
-/*TODO set to true if interlaced *//* REVIEW: Video mode interlaced? */
+ /*TODO set to true if interlaced *//* REVIEW: Video mode interlaced? */
ovly->regs.reset_buf_id = !ovly->chnl->continous_running;
switch (ovly->pix_fmt) {/* REVIEW: Extract to table */
case MCDE_OVLYPIXFMT_RGB565:
@@ -2015,8 +2163,16 @@ out:
return ret;
}
+
static int __devexit mcde_remove(struct platform_device *pdev)
{
+ struct mcde_chnl_state *chnl = &channels[0];
+ for (; chnl < &channels[ARRAY_SIZE(channels)]; chnl++) {
+ if (del_timer(&chnl->auto_sync_timer))
+ dev_vdbg(&mcde_dev->dev,
+ "%s timer could not be stopped\n"
+ , __func__);
+ }
remove_clocks_and_power(pdev);
return 0;
}
@@ -2026,7 +2182,7 @@ static int mcde_resume(struct platform_device *pdev)
{
int ret;
struct mcde_chnl_state *chnl = &channels[0];
- dev_info(&pdev->dev, "Resume is called\n");
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
ret = enable_clocks_and_power(pdev);
if (ret < 0) {
dev_dbg(&pdev->dev, "%s: Enable clocks and power failed\n"
@@ -2067,7 +2223,18 @@ clock_err:
#ifdef CONFIG_PM
static int mcde_suspend(struct platform_device *pdev, pm_message_t state)
{
- dev_info(&pdev->dev, "Suspend is called\n");
+ struct mcde_chnl_state *chnl = &channels[0];
+
+ dev_vdbg(&mcde_dev->dev, "%s\n", __func__);
+
+ /* This is added because of the auto sync feature */
+ for (; chnl < &channels[ARRAY_SIZE(channels)]; chnl++) {
+ mcde_chnl_stop_flow(chnl);
+ if (del_timer(&chnl->auto_sync_timer))
+ dev_vdbg(&mcde_dev->dev,
+ "%s timer could not be stopped\n"
+ , __func__);
+ }
return disable_clocks_and_power(pdev);
}
#endif
@@ -2087,8 +2254,7 @@ static struct platform_driver mcde_driver = {
},
};
-/* REVIEW: __init? */
-int mcde_init(void)
+int __init mcde_init(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(channels); i++) {
@@ -2096,6 +2262,9 @@ int mcde_init(void)
if (channels[i].ovly1)
channels[i].ovly1->chnl = &channels[i];
init_waitqueue_head(&channels[i].waitq_hw);
+ init_timer(&channels[i].auto_sync_timer);
+ channels[i].auto_sync_timer.function =
+ watchdog_auto_sync_timer_function;
}
for (i = 0; i < ARRAY_SIZE(overlays); i++)
init_waitqueue_head(&overlays[i].waitq_hw);