Re: [PATCH v2] drm/mxsfb: Fix runtime PM for unpowering lcdif block

2018-08-02 Thread Stefan Agner
On 02.08.2018 12:17, Philipp Zabel wrote:
> On Tue, 2018-07-31 at 12:17 +, Leonard Crestez wrote:
>> On Tue, 2018-07-31 at 13:54 +0200, Philipp Zabel wrote:
>> > On Tue, 2018-07-17 at 13:48 +0300, Leonard Crestez wrote:
>> > > Adding lcdif nodes to a power domain currently does work, it results in
>> > > black/corrupted screens or hangs. While the driver does enable runtime
>> > > pm it does not deal correctly with the block being unpowered.
>> > >
>> > > Ensure power is on when required by adding pm_runtime_get/put_sync to
>> > > mxsfb_pipe_enable/disable.
>> > >
>> > > Since power is lost on suspend implement PM_SLEEP_OPS using
>> > > drm_mode_config_helper_suspend/resume.
>> > >
>> > > The mxsfb_plane_atomic_update function can get called before
>> > > mxsfb_pipe_enable while the block is not yet powered. When this happens
>> > > the write to LCDIF_NEXT_BUF is lost causing corrupt display on unblank
>> > > until a refresh.
>> >
>> > Why does this happen?
>>
>> I'm not sure what you're asking but register writes to unpowered or
>> unclocked blocks are not expected to "just work". Here the write is
>> ignored/lost but I think on imx8 it can even cause a bus error.
>>
>> The approach here is to only set the framebuffer address as part of
>> activating the display.
> 
> I wonder why atomic update is called at all while the pipe is not
> enabled.

It can be made to behave differently (see also my review).

However, the default seems also a bit unfortunate to me.

--
Stefan


Re: [PATCH v2] drm/mxsfb: Fix runtime PM for unpowering lcdif block

2018-08-02 Thread Stefan Agner
On 02.08.2018 12:17, Philipp Zabel wrote:
> On Tue, 2018-07-31 at 12:17 +, Leonard Crestez wrote:
>> On Tue, 2018-07-31 at 13:54 +0200, Philipp Zabel wrote:
>> > On Tue, 2018-07-17 at 13:48 +0300, Leonard Crestez wrote:
>> > > Adding lcdif nodes to a power domain currently does work, it results in
>> > > black/corrupted screens or hangs. While the driver does enable runtime
>> > > pm it does not deal correctly with the block being unpowered.
>> > >
>> > > Ensure power is on when required by adding pm_runtime_get/put_sync to
>> > > mxsfb_pipe_enable/disable.
>> > >
>> > > Since power is lost on suspend implement PM_SLEEP_OPS using
>> > > drm_mode_config_helper_suspend/resume.
>> > >
>> > > The mxsfb_plane_atomic_update function can get called before
>> > > mxsfb_pipe_enable while the block is not yet powered. When this happens
>> > > the write to LCDIF_NEXT_BUF is lost causing corrupt display on unblank
>> > > until a refresh.
>> >
>> > Why does this happen?
>>
>> I'm not sure what you're asking but register writes to unpowered or
>> unclocked blocks are not expected to "just work". Here the write is
>> ignored/lost but I think on imx8 it can even cause a bus error.
>>
>> The approach here is to only set the framebuffer address as part of
>> activating the display.
> 
> I wonder why atomic update is called at all while the pipe is not
> enabled.

It can be made to behave differently (see also my review).

However, the default seems also a bit unfortunate to me.

--
Stefan


Re: [PATCH v2] drm/mxsfb: Fix runtime PM for unpowering lcdif block

2018-07-31 Thread Philipp Zabel
On Tue, 2018-07-17 at 13:48 +0300, Leonard Crestez wrote:
> Adding lcdif nodes to a power domain currently does work, it results in
> black/corrupted screens or hangs. While the driver does enable runtime
> pm it does not deal correctly with the block being unpowered.
> 
> Ensure power is on when required by adding pm_runtime_get/put_sync to
> mxsfb_pipe_enable/disable.
> 
> Since power is lost on suspend implement PM_SLEEP_OPS using
> drm_mode_config_helper_suspend/resume.
> 
> The mxsfb_plane_atomic_update function can get called before
> mxsfb_pipe_enable while the block is not yet powered. When this happens
> the write to LCDIF_NEXT_BUF is lost causing corrupt display on unblank
> until a refresh.

Why does this happen?

> Fix this by not writing gem->paddr if the block is not enabled and
> instead delaying the write until the next mxsfb_crtc_mode_set_nofb call.
> At that point also update cur_buf to avoid an initial corrupt frame
> after resume.
> 
> Signed-off-by: Leonard Crestez 

Tested-by: Philipp Zabel 

on imx6ull-evk, this fixes the initial corrupt frame.

regards
Philipp

> 
> ---
> 
> The purpose of this patch is to prepare for enabling power gating on
> DISPLAY power domains.
> 
> Changes since v1:
> * Drop mxsfb_runtime_suspend/mxsfb_runtime_resume, calling
> pm_runtime_get/put in pipe enable/disable is enough.
> * Use drm_mode_config_helper_suspend/resume instead of attempting to
> track state manually.
> * Don't touch NEXT_BUF if atomic_update called with crtc disabled
> * Also update CUR_BUF on enable, this avoids initial corrupt frames.
> 
> Previous discussion: https://lkml.org/lkml/2018/7/17/329
> ---
>  drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 51 +++---
>  drivers/gpu/drm/mxsfb/mxsfb_drv.c  | 25 +++
>  drivers/gpu/drm/mxsfb/mxsfb_drv.h  |  2 ++
>  3 files changed, 67 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c 
> b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> index 0abe77675b76..10153da77c40 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> @@ -194,15 +194,31 @@ static int mxsfb_reset_block(void __iomem *reset_addr)
>   return ret;
>  
>   return clear_poll_bit(reset_addr, MODULE_CLKGATE);
>  }
>  
> +static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb)
> +{
> + struct drm_framebuffer *fb = mxsfb->pipe.plane.state->fb;
> + struct drm_gem_cma_object *gem;
> +
> + if (!fb)
> + return 0;
> +
> + gem = drm_fb_cma_get_gem_obj(fb, 0);
> + if (!gem)
> + return 0;
> +
> + return gem->paddr;
> +}
> +
>  static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
>  {
>   struct drm_display_mode *m = >pipe.crtc.state->adjusted_mode;
>   const u32 bus_flags = mxsfb->connector.display_info.bus_flags;
>   u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
> + dma_addr_t paddr;
>   int err;
>  
>   /*
>* It seems, you can't re-program the controller if it is still
>* running. This may lead to shifted pictures (FIFO issue?), so
> @@ -268,35 +284,47 @@ static void mxsfb_crtc_mode_set_nofb(struct 
> mxsfb_drm_private *mxsfb)
>  mxsfb->base + LCDC_VDCTRL3);
>  
>   writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
>  mxsfb->base + LCDC_VDCTRL4);
>  
> + /* Update cur_buf as well to avoid an initial corrupt frame */
> + paddr = mxsfb_get_fb_paddr(mxsfb);
> + if (paddr) {
> + writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
> + writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
> + }
>   mxsfb_disable_axi_clk(mxsfb);
>  }
>  
>  void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
>  {
> + if (mxsfb->enabled)
> + return;
> +
>   mxsfb_crtc_mode_set_nofb(mxsfb);
>   mxsfb_enable_controller(mxsfb);
> +
> + mxsfb->enabled = true;
>  }
>  
>  void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
>  {
> + if (!mxsfb->enabled)
> + return;
> +
>   mxsfb_disable_controller(mxsfb);
> +
> + mxsfb->enabled = false;
>  }
>  
>  void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
>  struct drm_plane_state *state)
>  {
>   struct drm_simple_display_pipe *pipe = >pipe;
>   struct drm_crtc *crtc = >crtc;
> - struct drm_framebuffer *fb = pipe->plane.state->fb;
>   struct drm_pending_vblank_event *event;
> - struct drm_gem_cma_object *gem;
> -
> - if (!crtc)
> - return;
> + dma_addr_t paddr;
>  
>   spin_lock_irq(>dev->event_lock);
>   event = crtc->state->event;
>   if (event) {
>   crtc->state->event = NULL;
> @@ -307,14 +335,15 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private 
> *mxsfb,
>   drm_crtc_send_vblank_event(crtc, event);
>   }
>   }
>   spin_unlock_irq(>dev->event_lock);
>  
> - if 

Re: [PATCH v2] drm/mxsfb: Fix runtime PM for unpowering lcdif block

2018-07-31 Thread Philipp Zabel
On Tue, 2018-07-17 at 13:48 +0300, Leonard Crestez wrote:
> Adding lcdif nodes to a power domain currently does work, it results in
> black/corrupted screens or hangs. While the driver does enable runtime
> pm it does not deal correctly with the block being unpowered.
> 
> Ensure power is on when required by adding pm_runtime_get/put_sync to
> mxsfb_pipe_enable/disable.
> 
> Since power is lost on suspend implement PM_SLEEP_OPS using
> drm_mode_config_helper_suspend/resume.
> 
> The mxsfb_plane_atomic_update function can get called before
> mxsfb_pipe_enable while the block is not yet powered. When this happens
> the write to LCDIF_NEXT_BUF is lost causing corrupt display on unblank
> until a refresh.

Why does this happen?

> Fix this by not writing gem->paddr if the block is not enabled and
> instead delaying the write until the next mxsfb_crtc_mode_set_nofb call.
> At that point also update cur_buf to avoid an initial corrupt frame
> after resume.
> 
> Signed-off-by: Leonard Crestez 

Tested-by: Philipp Zabel 

on imx6ull-evk, this fixes the initial corrupt frame.

regards
Philipp

> 
> ---
> 
> The purpose of this patch is to prepare for enabling power gating on
> DISPLAY power domains.
> 
> Changes since v1:
> * Drop mxsfb_runtime_suspend/mxsfb_runtime_resume, calling
> pm_runtime_get/put in pipe enable/disable is enough.
> * Use drm_mode_config_helper_suspend/resume instead of attempting to
> track state manually.
> * Don't touch NEXT_BUF if atomic_update called with crtc disabled
> * Also update CUR_BUF on enable, this avoids initial corrupt frames.
> 
> Previous discussion: https://lkml.org/lkml/2018/7/17/329
> ---
>  drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 51 +++---
>  drivers/gpu/drm/mxsfb/mxsfb_drv.c  | 25 +++
>  drivers/gpu/drm/mxsfb/mxsfb_drv.h  |  2 ++
>  3 files changed, 67 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c 
> b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> index 0abe77675b76..10153da77c40 100644
> --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
> @@ -194,15 +194,31 @@ static int mxsfb_reset_block(void __iomem *reset_addr)
>   return ret;
>  
>   return clear_poll_bit(reset_addr, MODULE_CLKGATE);
>  }
>  
> +static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb)
> +{
> + struct drm_framebuffer *fb = mxsfb->pipe.plane.state->fb;
> + struct drm_gem_cma_object *gem;
> +
> + if (!fb)
> + return 0;
> +
> + gem = drm_fb_cma_get_gem_obj(fb, 0);
> + if (!gem)
> + return 0;
> +
> + return gem->paddr;
> +}
> +
>  static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
>  {
>   struct drm_display_mode *m = >pipe.crtc.state->adjusted_mode;
>   const u32 bus_flags = mxsfb->connector.display_info.bus_flags;
>   u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
> + dma_addr_t paddr;
>   int err;
>  
>   /*
>* It seems, you can't re-program the controller if it is still
>* running. This may lead to shifted pictures (FIFO issue?), so
> @@ -268,35 +284,47 @@ static void mxsfb_crtc_mode_set_nofb(struct 
> mxsfb_drm_private *mxsfb)
>  mxsfb->base + LCDC_VDCTRL3);
>  
>   writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
>  mxsfb->base + LCDC_VDCTRL4);
>  
> + /* Update cur_buf as well to avoid an initial corrupt frame */
> + paddr = mxsfb_get_fb_paddr(mxsfb);
> + if (paddr) {
> + writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf);
> + writel(paddr, mxsfb->base + mxsfb->devdata->next_buf);
> + }
>   mxsfb_disable_axi_clk(mxsfb);
>  }
>  
>  void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
>  {
> + if (mxsfb->enabled)
> + return;
> +
>   mxsfb_crtc_mode_set_nofb(mxsfb);
>   mxsfb_enable_controller(mxsfb);
> +
> + mxsfb->enabled = true;
>  }
>  
>  void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
>  {
> + if (!mxsfb->enabled)
> + return;
> +
>   mxsfb_disable_controller(mxsfb);
> +
> + mxsfb->enabled = false;
>  }
>  
>  void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
>  struct drm_plane_state *state)
>  {
>   struct drm_simple_display_pipe *pipe = >pipe;
>   struct drm_crtc *crtc = >crtc;
> - struct drm_framebuffer *fb = pipe->plane.state->fb;
>   struct drm_pending_vblank_event *event;
> - struct drm_gem_cma_object *gem;
> -
> - if (!crtc)
> - return;
> + dma_addr_t paddr;
>  
>   spin_lock_irq(>dev->event_lock);
>   event = crtc->state->event;
>   if (event) {
>   crtc->state->event = NULL;
> @@ -307,14 +335,15 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private 
> *mxsfb,
>   drm_crtc_send_vblank_event(crtc, event);
>   }
>   }
>   spin_unlock_irq(>dev->event_lock);
>  
> - if