aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/mxsfb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/mxsfb')
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_crtc.c53
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.c40
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
196static 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
199static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb) 211static 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
276void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb) 285void 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
282void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb) 302void 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
287void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb, 308void 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
101static const struct drm_mode_config_helper_funcs mxsfb_mode_config_helpers = {
102 .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
103};
104
101static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe, 105static 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,
112static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe) 118static 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
121static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe, 139static 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
437static 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
444static 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
452static const struct dev_pm_ops mxsfb_pm_ops = {
453 SET_SYSTEM_SLEEP_PM_OPS(mxsfb_suspend, mxsfb_resume)
454};
455
417static struct platform_driver mxsfb_platform_driver = { 456static 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