From: Hitesh K. Patel <[email protected]> Display Self Refresh & Display Partial update feature is validated and needs to be enabled in kernel. Updated DPU code to adopt to TE interrupt. Added new kernel Kconfig option to disable/enable DSR in kernel.
Signed-off-by: Jackie Li <[email protected]> Signed-off-by: Hitesh K. Patel <[email protected]> --- drivers/staging/mrst/Kconfig | 14 +++++ drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.c | 68 +++++++++++++++++++++++-- drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.h | 1 + drivers/staging/mrst/drv/psb_drv.c | 29 ++++++++--- drivers/staging/mrst/drv/psb_drv.h | 3 +- drivers/staging/mrst/drv/psb_irq.c | 30 ++++++++++-- 6 files changed, 126 insertions(+), 19 deletions(-) diff --git a/drivers/staging/mrst/Kconfig b/drivers/staging/mrst/Kconfig index d27f7d5..1c174da 100644 --- a/drivers/staging/mrst/Kconfig +++ b/drivers/staging/mrst/Kconfig @@ -57,6 +57,20 @@ config DRM_MDFLD Choose this option if you have a Medfield platform. If M is selected the module will be called mid_gfx. +config MDFLD_DSI_DSR + bool "Support DSI Display Self Refreshment" + depends on MDFLD_DSI_DBI + default n + help + Choose this option if you have a Type1 MIPI panel. + +config MDFLD_DSI_DPU + bool "Support DSI Display Partial Update" + depends on MDFLD_DSI_DBI + default n + help + Choose this option to enable DPU + config MDFLD_DSI_DBI bool "Support DSI Command Mode" depends on DRM_MDFLD diff --git a/drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.c b/drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.c index 9558d42..106ec19 100644 --- a/drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.c +++ b/drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.c @@ -407,24 +407,53 @@ static int mdfld_dpu_update_fb(struct drm_device * dev) { struct mdfld_dbi_dpu_info * dpu_info = dev_priv->dbi_dpu_info; bool pipe_updated[2]; unsigned long irq_flags; + u32 dpll_reg = MRST_DPLL_A; + u32 dspcntr_reg = DSPACNTR; + u32 pipeconf_reg = PIPEACONF; + u32 dsplinoff_reg = DSPALINOFF; + u32 dspsurf_reg = DSPASURF; + u32 mipi_state_reg = MIPIA_INTR_STAT_REG; + u32 reg_offset = 0; + int pipe; int i; int ret; - + dbi_output = dpu_info->dbi_outputs; pipe_updated[0] = pipe_updated[1] = false; if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, true)) return -EAGAIN; - + /*try to prevent any new damage reports*/ if(!spin_trylock_irqsave(&dpu_info->dpu_update_lock, irq_flags)) { return -EAGAIN; } - + for(i=0; i<dpu_info->dbi_output_num; i++) { crtc = dbi_output[i]->base.base.crtc; psb_crtc = (crtc) ? to_psb_intel_crtc(crtc) : NULL; - + + pipe = dbi_output[i]->channel_num ? 2 : 0; + + if(pipe == 2) { + dspcntr_reg = DSPCCNTR; + pipeconf_reg = PIPECCONF; + dsplinoff_reg = DSPCLINOFF; + dspsurf_reg = DSPCSURF; + + reg_offset = MIPIC_REG_OFFSET; + } + + if(!(REG_READ((MIPIA_GEN_FIFO_STAT_REG + reg_offset)) & BIT27) || + !(REG_READ(dpll_reg) & DPLL_VCO_ENABLE) || + !(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) || + !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE)) { + PSB_DEBUG_ENTRY("DBI FIFO is busy, DSI %d state %x\n", + pipe, + REG_READ(mipi_state_reg + reg_offset)); + continue; + } + /*if dbi output is in a exclusive state, pipe change won't be updated*/ if(dbi_output[i]->dbi_panel_on && !(dbi_output[i]->mode_flags & MODE_SETTING_ON_GOING) && @@ -442,7 +471,7 @@ static int mdfld_dpu_update_fb(struct drm_device * dev) { mdfld_dbi_flush_cb(dbi_output[i], dbi_output[i]->channel_num ? 2 : 0); } } - + spin_unlock_irqrestore(&dpu_info->dpu_update_lock, irq_flags); ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); @@ -551,7 +580,14 @@ int mdfld_dpu_exit_dsr(struct drm_device * dev) } /*start dpu timer*/ - mdfld_dbi_dpu_timer_start(dpu_info); + if (dev_priv->platform_rev_id == MDFLD_PNW_A0) + mdfld_dbi_dpu_timer_start(dpu_info); + else { + /*enable te interrupt*/ + mdfld_enable_te(dev, 0); + mdfld_enable_te(dev, 2); + } + return 0; } @@ -611,6 +647,26 @@ static void mdfld_dbi_dpu_timer_func(unsigned long data) spin_unlock_irqrestore(&dpu_info->dpu_timer_lock, flags); } +void mdfld_dpu_update_panel(struct drm_device * dev) +{ + struct drm_psb_private * dev_priv = dev->dev_private; + struct mdfld_dbi_dpu_info * dpu_info = dev_priv->dbi_dpu_info; + + if(dpu_info->pending) { + dpu_info->idle_count = 0; + + /*update panel fb with damaged area*/ + mdfld_dpu_update_fb(dev); + } else { + dpu_info->idle_count++; + } + + if(dpu_info->idle_count >= MDFLD_MAX_IDLE_COUNT) { + /*enter dsr*/ + mdfld_dpu_enter_dsr(dev); + } +} + static int mdfld_dbi_dpu_timer_init(struct drm_device * dev, struct mdfld_dbi_dpu_info * dpu_info) { struct timer_list * dpu_timer = &dpu_info->dpu_timer; diff --git a/drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.h b/drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.h index c3b2bf2..f480a42 100644 --- a/drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.h +++ b/drivers/staging/mrst/drv/mdfld_dsi_dbi_dpu.h @@ -153,5 +153,6 @@ extern int mdfld_dpu_exit_dsr(struct drm_device * dev); extern void mdfld_dbi_dpu_timer_start(struct mdfld_dbi_dpu_info * dpu_info); extern int mdfld_dbi_dpu_init(struct drm_device * dev); extern void mdfld_dbi_dpu_exit(struct drm_device * dev); +extern void mdfld_dpu_update_panel(struct drm_device * dev); #endif /*__MDFLD_DSI_DBI_DPU_H__*/ diff --git a/drivers/staging/mrst/drv/psb_drv.c b/drivers/staging/mrst/drv/psb_drv.c index 8d91ae0..10ac8c7 100644 --- a/drivers/staging/mrst/drv/psb_drv.c +++ b/drivers/staging/mrst/drv/psb_drv.c @@ -2038,19 +2038,32 @@ static int psb_dpu_query_ioctl(struct drm_device *dev, void *arg, IMG_INT *data = (IMG_INT*)arg; DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private; + /*reject requests from non-mdfld platforms*/ + if(!IS_MDFLD(dev)) { + DRM_INFO("Not Medfield platform! return."); + return -ENOTSUPP; + } + DRM_INFO("dsr query. \n"); +#ifdef CONFIG_MDFLD_DSI_DSR dev_priv->b_dsr_enable = true; -#if MDFLD_JLIU7_DPU - dev_priv->damage_rect_2d_3d.x = 0; - dev_priv->damage_rect_2d_3d.y = 0; - dev_priv->damage_rect_2d_3d.width = 864; - dev_priv->damage_rect_2d_3d.height = 480; - dev_priv->b_dpu_enable = true; -#endif /* MDFLD_JLIU7_DPU */ - /*DEADBEEF if disabled else F*/ + +#ifdef CONFIG_MDFLD_DSI_DPU *data = MDFLD_DSR_RR | MDFLD_DPU_ENABLE; +#else /*CONFIG_MDFLD_DSI_DPU*/ + *data = MDFLD_DSR_RR | MDFLD_DSR_FULLSCREEN; +#endif /*CONFIG_MDFLD_DSI_DPU*/ + + DRM_INFO("Support DSR in kernel, flag 0x%08x\n", (u32)*data); + + +#else /*DSR was not define or in video mode*/ + DRM_INFO("DSR is disabled by kernel configuration.\n"); + dev_priv->b_dsr_enable = false; + *data = 0; +#endif /*CONFIG_MDFLD_DSI_DSR*/ return 0; } diff --git a/drivers/staging/mrst/drv/psb_drv.h b/drivers/staging/mrst/drv/psb_drv.h index 3a9280d..13f996b 100644 --- a/drivers/staging/mrst/drv/psb_drv.h +++ b/drivers/staging/mrst/drv/psb_drv.h @@ -256,7 +256,8 @@ enum { #define MDFLD_DSR_OVERLAY_2 BIT5 #endif /* MDFLD_JLIU7_DPU_2 */ #define MDFLD_DSR_RR 45 -#define MDFLD_DPU_ENABLE BIT31 +#define MDFLD_DPU_ENABLE BIT31 +#define MDFLD_DSR_FULLSCREEN BIT30 #define MDFLD_DSR_DELAY (DRM_HZ / MDFLD_DSR_RR) #endif /* MDFLD_JLIU7_DSR */ diff --git a/drivers/staging/mrst/drv/psb_irq.c b/drivers/staging/mrst/drv/psb_irq.c index f85f671..46b31d2 100644 --- a/drivers/staging/mrst/drv/psb_irq.c +++ b/drivers/staging/mrst/drv/psb_irq.c @@ -31,6 +31,8 @@ #include "psb_intel_reg.h" #include "psb_powermgmt.h" +#include "mdfld_dsi_dbi_dpu.h" + /* * inline functions */ @@ -211,6 +213,7 @@ static void mdfld_pipe_hdmi_audio_buffer_done(struct drm_device *dev) * Display controller interrupt handler for pipe event. * */ +#define WAIT_STATUS_CLEAR_LOOP_COUNT 0xffff static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) { struct drm_psb_private *dev_priv = @@ -220,6 +223,7 @@ static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) uint32_t pipe_stat_reg = psb_pipestat(pipe); uint32_t pipe_enable = dev_priv->pipestat[pipe]; uint32_t pipe_status = dev_priv->pipestat[pipe] >> 16; + uint32_t i = 0; spin_lock(&dev_priv->irqmask_lock); @@ -229,6 +233,24 @@ static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) spin_unlock(&dev_priv->irqmask_lock); + /* clear the 2nd level interrupt status bits */ + /** + * FIXME: shouldn't use while loop here. However, the interrupt + * status 'sticky' bits cannot be cleared by setting '1' to that + * bit once... + */ + for (i = 0; i < WAIT_STATUS_CLEAR_LOOP_COUNT; i ++) { + PSB_WVDC32(PSB_RVDC32(pipe_stat_reg), pipe_stat_reg); + (void) PSB_RVDC32(pipe_stat_reg); + + if ((PSB_RVDC32(pipe_stat_reg) & pipe_status) == 0) + break; + } + + if (i == WAIT_STATUS_CLEAR_LOOP_COUNT) + DRM_ERROR("%s, can't clear the status bits in pipe_stat_reg, its value = 0x%x. \n", + __FUNCTION__, PSB_RVDC32(pipe_stat_reg)); + if (pipe_stat_val & PIPE_DPST_EVENT_STATUS) { } @@ -238,7 +260,11 @@ static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) } if (pipe_stat_val & PIPE_TE_STATUS) { +#ifdef CONFIG_MDFLD_DSI_DPU + mdfld_dpu_update_panel(dev); +#else mdfld_dbi_update_panel (dev, pipe); +#endif } #ifdef MDFLD_HDCP @@ -250,10 +276,6 @@ static void mid_pipe_event_handler(struct drm_device *dev, uint32_t pipe) mdfld_pipe_hdmi_audio_buffer_done(dev); } #endif /* MDFLD_HDCP */ - - /* clear the 2nd level interrupt status bits */ - PSB_WVDC32(PSB_RVDC32(pipe_stat_reg), pipe_stat_reg); - (void) PSB_RVDC32(pipe_stat_reg); } /** -- 1.7.1 _______________________________________________ MeeGo-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
