diff options
Diffstat (limited to 'drivers/gpu/drm/mxsfb')
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_crtc.c | 53 | ||||
-rw-r--r-- | drivers/gpu/drm/mxsfb/mxsfb_drv.c | 40 |
2 files changed, 74 insertions, 19 deletions
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c index 0abe77675b76..24b1f0c1432e 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c | |||
@@ -129,7 +129,6 @@ static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb) | |||
129 | if (mxsfb->clk_disp_axi) | 129 | if (mxsfb->clk_disp_axi) |
130 | clk_prepare_enable(mxsfb->clk_disp_axi); | 130 | clk_prepare_enable(mxsfb->clk_disp_axi); |
131 | clk_prepare_enable(mxsfb->clk); | 131 | clk_prepare_enable(mxsfb->clk); |
132 | mxsfb_enable_axi_clk(mxsfb); | ||
133 | 132 | ||
134 | /* If it was disabled, re-enable the mode again */ | 133 | /* If it was disabled, re-enable the mode again */ |
135 | writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET); | 134 | writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET); |
@@ -159,8 +158,6 @@ static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb) | |||
159 | reg &= ~VDCTRL4_SYNC_SIGNALS_ON; | 158 | reg &= ~VDCTRL4_SYNC_SIGNALS_ON; |
160 | writel(reg, mxsfb->base + LCDC_VDCTRL4); | 159 | writel(reg, mxsfb->base + LCDC_VDCTRL4); |
161 | 160 | ||
162 | mxsfb_disable_axi_clk(mxsfb); | ||
163 | |||
164 | clk_disable_unprepare(mxsfb->clk); | 161 | clk_disable_unprepare(mxsfb->clk); |
165 | if (mxsfb->clk_disp_axi) | 162 | if (mxsfb->clk_disp_axi) |
166 | clk_disable_unprepare(mxsfb->clk_disp_axi); | 163 | clk_disable_unprepare(mxsfb->clk_disp_axi); |
@@ -196,6 +193,21 @@ static int mxsfb_reset_block(void __iomem *reset_addr) | |||
196 | return clear_poll_bit(reset_addr, MODULE_CLKGATE); | 193 | return clear_poll_bit(reset_addr, MODULE_CLKGATE); |
197 | } | 194 | } |
198 | 195 | ||
196 | static dma_addr_t mxsfb_get_fb_paddr(struct mxsfb_drm_private *mxsfb) | ||
197 | { | ||
198 | struct drm_framebuffer *fb = mxsfb->pipe.plane.state->fb; | ||
199 | struct drm_gem_cma_object *gem; | ||
200 | |||
201 | if (!fb) | ||
202 | return 0; | ||
203 | |||
204 | gem = drm_fb_cma_get_gem_obj(fb, 0); | ||
205 | if (!gem) | ||
206 | return 0; | ||
207 | |||
208 | return gem->paddr; | ||
209 | } | ||
210 | |||
199 | static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) | 211 | static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) |
200 | { | 212 | { |
201 | struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; | 213 | struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode; |
@@ -208,7 +220,6 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) | |||
208 | * running. This may lead to shifted pictures (FIFO issue?), so | 220 | * running. This may lead to shifted pictures (FIFO issue?), so |
209 | * first stop the controller and drain its FIFOs. | 221 | * first stop the controller and drain its FIFOs. |
210 | */ | 222 | */ |
211 | mxsfb_enable_axi_clk(mxsfb); | ||
212 | 223 | ||
213 | /* Mandatory eLCDIF reset as per the Reference Manual */ | 224 | /* Mandatory eLCDIF reset as per the Reference Manual */ |
214 | err = mxsfb_reset_block(mxsfb->base); | 225 | err = mxsfb_reset_block(mxsfb->base); |
@@ -269,19 +280,29 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) | |||
269 | 280 | ||
270 | writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay), | 281 | writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay), |
271 | mxsfb->base + LCDC_VDCTRL4); | 282 | mxsfb->base + LCDC_VDCTRL4); |
272 | |||
273 | mxsfb_disable_axi_clk(mxsfb); | ||
274 | } | 283 | } |
275 | 284 | ||
276 | void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb) | 285 | void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb) |
277 | { | 286 | { |
287 | dma_addr_t paddr; | ||
288 | |||
289 | mxsfb_enable_axi_clk(mxsfb); | ||
278 | mxsfb_crtc_mode_set_nofb(mxsfb); | 290 | mxsfb_crtc_mode_set_nofb(mxsfb); |
291 | |||
292 | /* Write cur_buf as well to avoid an initial corrupt frame */ | ||
293 | paddr = mxsfb_get_fb_paddr(mxsfb); | ||
294 | if (paddr) { | ||
295 | writel(paddr, mxsfb->base + mxsfb->devdata->cur_buf); | ||
296 | writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); | ||
297 | } | ||
298 | |||
279 | mxsfb_enable_controller(mxsfb); | 299 | mxsfb_enable_controller(mxsfb); |
280 | } | 300 | } |
281 | 301 | ||
282 | void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb) | 302 | void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb) |
283 | { | 303 | { |
284 | mxsfb_disable_controller(mxsfb); | 304 | mxsfb_disable_controller(mxsfb); |
305 | mxsfb_disable_axi_clk(mxsfb); | ||
285 | } | 306 | } |
286 | 307 | ||
287 | void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, | 308 | void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, |
@@ -289,12 +310,8 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, | |||
289 | { | 310 | { |
290 | struct drm_simple_display_pipe *pipe = &mxsfb->pipe; | 311 | struct drm_simple_display_pipe *pipe = &mxsfb->pipe; |
291 | struct drm_crtc *crtc = &pipe->crtc; | 312 | struct drm_crtc *crtc = &pipe->crtc; |
292 | struct drm_framebuffer *fb = pipe->plane.state->fb; | ||
293 | struct drm_pending_vblank_event *event; | 313 | struct drm_pending_vblank_event *event; |
294 | struct drm_gem_cma_object *gem; | 314 | dma_addr_t paddr; |
295 | |||
296 | if (!crtc) | ||
297 | return; | ||
298 | 315 | ||
299 | spin_lock_irq(&crtc->dev->event_lock); | 316 | spin_lock_irq(&crtc->dev->event_lock); |
300 | event = crtc->state->event; | 317 | event = crtc->state->event; |
@@ -309,12 +326,10 @@ void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, | |||
309 | } | 326 | } |
310 | spin_unlock_irq(&crtc->dev->event_lock); | 327 | spin_unlock_irq(&crtc->dev->event_lock); |
311 | 328 | ||
312 | if (!fb) | 329 | paddr = mxsfb_get_fb_paddr(mxsfb); |
313 | return; | 330 | if (paddr) { |
314 | 331 | mxsfb_enable_axi_clk(mxsfb); | |
315 | gem = drm_fb_cma_get_gem_obj(fb, 0); | 332 | writel(paddr, mxsfb->base + mxsfb->devdata->next_buf); |
316 | 333 | mxsfb_disable_axi_clk(mxsfb); | |
317 | mxsfb_enable_axi_clk(mxsfb); | 334 | } |
318 | writel(gem->paddr, mxsfb->base + mxsfb->devdata->next_buf); | ||
319 | mxsfb_disable_axi_clk(mxsfb); | ||
320 | } | 335 | } |
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index ffe5137ccaf8..2393e6d16ffd 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c | |||
@@ -98,12 +98,18 @@ static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = { | |||
98 | .atomic_commit = drm_atomic_helper_commit, | 98 | .atomic_commit = drm_atomic_helper_commit, |
99 | }; | 99 | }; |
100 | 100 | ||
101 | static const struct drm_mode_config_helper_funcs mxsfb_mode_config_helpers = { | ||
102 | .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, | ||
103 | }; | ||
104 | |||
101 | static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, | 105 | static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, |
102 | struct drm_crtc_state *crtc_state, | 106 | struct drm_crtc_state *crtc_state, |
103 | struct drm_plane_state *plane_state) | 107 | struct drm_plane_state *plane_state) |
104 | { | 108 | { |
105 | struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | 109 | struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); |
110 | struct drm_device *drm = pipe->plane.dev; | ||
106 | 111 | ||
112 | pm_runtime_get_sync(drm->dev); | ||
107 | drm_panel_prepare(mxsfb->panel); | 113 | drm_panel_prepare(mxsfb->panel); |
108 | mxsfb_crtc_enable(mxsfb); | 114 | mxsfb_crtc_enable(mxsfb); |
109 | drm_panel_enable(mxsfb->panel); | 115 | drm_panel_enable(mxsfb->panel); |
@@ -112,10 +118,22 @@ static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, | |||
112 | static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) | 118 | static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) |
113 | { | 119 | { |
114 | struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); | 120 | struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe); |
121 | struct drm_device *drm = pipe->plane.dev; | ||
122 | struct drm_crtc *crtc = &pipe->crtc; | ||
123 | struct drm_pending_vblank_event *event; | ||
115 | 124 | ||
116 | drm_panel_disable(mxsfb->panel); | 125 | drm_panel_disable(mxsfb->panel); |
117 | mxsfb_crtc_disable(mxsfb); | 126 | mxsfb_crtc_disable(mxsfb); |
118 | drm_panel_unprepare(mxsfb->panel); | 127 | drm_panel_unprepare(mxsfb->panel); |
128 | pm_runtime_put_sync(drm->dev); | ||
129 | |||
130 | spin_lock_irq(&drm->event_lock); | ||
131 | event = crtc->state->event; | ||
132 | if (event) { | ||
133 | crtc->state->event = NULL; | ||
134 | drm_crtc_send_vblank_event(crtc, event); | ||
135 | } | ||
136 | spin_unlock_irq(&drm->event_lock); | ||
119 | } | 137 | } |
120 | 138 | ||
121 | static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe, | 139 | static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe, |
@@ -230,6 +248,7 @@ static int mxsfb_load(struct drm_device *drm, unsigned long flags) | |||
230 | drm->mode_config.max_width = MXSFB_MAX_XRES; | 248 | drm->mode_config.max_width = MXSFB_MAX_XRES; |
231 | drm->mode_config.max_height = MXSFB_MAX_YRES; | 249 | drm->mode_config.max_height = MXSFB_MAX_YRES; |
232 | drm->mode_config.funcs = &mxsfb_mode_config_funcs; | 250 | drm->mode_config.funcs = &mxsfb_mode_config_funcs; |
251 | drm->mode_config.helper_private = &mxsfb_mode_config_helpers; | ||
233 | 252 | ||
234 | drm_mode_config_reset(drm); | 253 | drm_mode_config_reset(drm); |
235 | 254 | ||
@@ -414,6 +433,26 @@ static int mxsfb_remove(struct platform_device *pdev) | |||
414 | return 0; | 433 | return 0; |
415 | } | 434 | } |
416 | 435 | ||
436 | #ifdef CONFIG_PM_SLEEP | ||
437 | static int mxsfb_suspend(struct device *dev) | ||
438 | { | ||
439 | struct drm_device *drm = dev_get_drvdata(dev); | ||
440 | |||
441 | return drm_mode_config_helper_suspend(drm); | ||
442 | } | ||
443 | |||
444 | static int mxsfb_resume(struct device *dev) | ||
445 | { | ||
446 | struct drm_device *drm = dev_get_drvdata(dev); | ||
447 | |||
448 | return drm_mode_config_helper_resume(drm); | ||
449 | } | ||
450 | #endif | ||
451 | |||
452 | static const struct dev_pm_ops mxsfb_pm_ops = { | ||
453 | SET_SYSTEM_SLEEP_PM_OPS(mxsfb_suspend, mxsfb_resume) | ||
454 | }; | ||
455 | |||
417 | static struct platform_driver mxsfb_platform_driver = { | 456 | static struct platform_driver mxsfb_platform_driver = { |
418 | .probe = mxsfb_probe, | 457 | .probe = mxsfb_probe, |
419 | .remove = mxsfb_remove, | 458 | .remove = mxsfb_remove, |
@@ -421,6 +460,7 @@ static struct platform_driver mxsfb_platform_driver = { | |||
421 | .driver = { | 460 | .driver = { |
422 | .name = "mxsfb", | 461 | .name = "mxsfb", |
423 | .of_match_table = mxsfb_dt_ids, | 462 | .of_match_table = mxsfb_dt_ids, |
463 | .pm = &mxsfb_pm_ops, | ||
424 | }, | 464 | }, |
425 | }; | 465 | }; |
426 | 466 | ||