aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
diff options
context:
space:
mode:
authorJyri Sarha <jsarha@ti.com>2016-11-24 16:25:08 -0500
committerJyri Sarha <jsarha@ti.com>2016-11-30 07:19:53 -0500
commit75d7f277eefcbd25c154d81f6836d7fdefaba89c (patch)
tree349da7ee8a062fff0ef1fec293c839418f406987 /drivers/gpu/drm/tilcdc/tilcdc_crtc.c
parent274c34dbe756d441e2c1925465569ef93d380541 (diff)
drm/tilcdc: Configure video mode to HW in enable() not in mode_set_nofb()
Configure video mode to HW in enable() call back. There is no reason to do it before that. This makes PM functions way easier because there is no HW context to save when screen is for instance blanked. This patch removes mode_set_nofb() call back from tilcdc. Signed-off-by: Jyri Sarha <jsarha@ti.com> Tested-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_crtc.c')
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c426
1 files changed, 212 insertions, 214 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 4472540d6bc0..fb2442205424 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -215,214 +215,6 @@ static void reset(struct drm_crtc *crtc)
215 tilcdc_clear(dev, LCDC_CLK_RESET_REG, LCDC_CLK_MAIN_RESET); 215 tilcdc_clear(dev, LCDC_CLK_RESET_REG, LCDC_CLK_MAIN_RESET);
216} 216}
217 217
218static void tilcdc_crtc_enable(struct drm_crtc *crtc)
219{
220 struct drm_device *dev = crtc->dev;
221 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
222
223 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
224 mutex_lock(&tilcdc_crtc->enable_lock);
225 if (tilcdc_crtc->enabled || tilcdc_crtc->shutdown) {
226 mutex_unlock(&tilcdc_crtc->enable_lock);
227 return;
228 }
229
230 pm_runtime_get_sync(dev->dev);
231
232 reset(crtc);
233
234 tilcdc_crtc_enable_irqs(dev);
235
236 tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE);
237 tilcdc_write_mask(dev, LCDC_RASTER_CTRL_REG,
238 LCDC_PALETTE_LOAD_MODE(DATA_ONLY),
239 LCDC_PALETTE_LOAD_MODE_MASK);
240 tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
241
242 drm_crtc_vblank_on(crtc);
243
244 tilcdc_crtc->enabled = true;
245 mutex_unlock(&tilcdc_crtc->enable_lock);
246}
247
248static void tilcdc_crtc_off(struct drm_crtc *crtc, bool shutdown)
249{
250 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
251 struct drm_device *dev = crtc->dev;
252 struct tilcdc_drm_private *priv = dev->dev_private;
253
254 mutex_lock(&tilcdc_crtc->enable_lock);
255 if (shutdown)
256 tilcdc_crtc->shutdown = true;
257 if (!tilcdc_crtc->enabled) {
258 mutex_unlock(&tilcdc_crtc->enable_lock);
259 return;
260 }
261 tilcdc_crtc->frame_done = false;
262 tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
263
264 /*
265 * if necessary wait for framedone irq which will still come
266 * before putting things to sleep..
267 */
268 if (priv->rev == 2) {
269 int ret = wait_event_timeout(tilcdc_crtc->frame_done_wq,
270 tilcdc_crtc->frame_done,
271 msecs_to_jiffies(500));
272 if (ret == 0)
273 dev_err(dev->dev, "%s: timeout waiting for framedone\n",
274 __func__);
275 }
276
277 drm_crtc_vblank_off(crtc);
278
279 tilcdc_crtc_disable_irqs(dev);
280
281 pm_runtime_put_sync(dev->dev);
282
283 if (tilcdc_crtc->next_fb) {
284 drm_flip_work_queue(&tilcdc_crtc->unref_work,
285 tilcdc_crtc->next_fb);
286 tilcdc_crtc->next_fb = NULL;
287 }
288
289 if (tilcdc_crtc->curr_fb) {
290 drm_flip_work_queue(&tilcdc_crtc->unref_work,
291 tilcdc_crtc->curr_fb);
292 tilcdc_crtc->curr_fb = NULL;
293 }
294
295 drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
296 tilcdc_crtc->last_vblank = ktime_set(0, 0);
297
298 tilcdc_crtc->enabled = false;
299 mutex_unlock(&tilcdc_crtc->enable_lock);
300}
301
302static void tilcdc_crtc_disable(struct drm_crtc *crtc)
303{
304 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
305 tilcdc_crtc_off(crtc, false);
306}
307
308void tilcdc_crtc_shutdown(struct drm_crtc *crtc)
309{
310 tilcdc_crtc_off(crtc, true);
311}
312
313static bool tilcdc_crtc_is_on(struct drm_crtc *crtc)
314{
315 return crtc->state && crtc->state->enable && crtc->state->active;
316}
317
318static void tilcdc_crtc_recover_work(struct work_struct *work)
319{
320 struct tilcdc_crtc *tilcdc_crtc =
321 container_of(work, struct tilcdc_crtc, recover_work);
322 struct drm_crtc *crtc = &tilcdc_crtc->base;
323
324 dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__);
325
326 drm_modeset_lock_crtc(crtc, NULL);
327
328 if (!tilcdc_crtc_is_on(crtc))
329 goto out;
330
331 tilcdc_crtc_disable(crtc);
332 tilcdc_crtc_enable(crtc);
333out:
334 drm_modeset_unlock_crtc(crtc);
335}
336
337static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
338{
339 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
340 struct tilcdc_drm_private *priv = crtc->dev->dev_private;
341
342 drm_modeset_lock_crtc(crtc, NULL);
343 tilcdc_crtc_disable(crtc);
344 drm_modeset_unlock_crtc(crtc);
345
346 flush_workqueue(priv->wq);
347
348 of_node_put(crtc->port);
349 drm_crtc_cleanup(crtc);
350 drm_flip_work_cleanup(&tilcdc_crtc->unref_work);
351}
352
353int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
354 struct drm_framebuffer *fb,
355 struct drm_pending_vblank_event *event)
356{
357 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
358 struct drm_device *dev = crtc->dev;
359 unsigned long flags;
360
361 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
362
363 if (tilcdc_crtc->event) {
364 dev_err(dev->dev, "already pending page flip!\n");
365 return -EBUSY;
366 }
367
368 drm_framebuffer_reference(fb);
369
370 crtc->primary->fb = fb;
371
372 spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
373
374 if (crtc->hwmode.vrefresh && ktime_to_ns(tilcdc_crtc->last_vblank)) {
375 ktime_t next_vblank;
376 s64 tdiff;
377
378 next_vblank = ktime_add_us(tilcdc_crtc->last_vblank,
379 1000000 / crtc->hwmode.vrefresh);
380
381 tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get()));
382
383 if (tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US)
384 tilcdc_crtc->next_fb = fb;
385 }
386
387 if (tilcdc_crtc->next_fb != fb)
388 set_scanout(crtc, fb);
389
390 tilcdc_crtc->event = event;
391
392 spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags);
393
394 return 0;
395}
396
397static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc,
398 const struct drm_display_mode *mode,
399 struct drm_display_mode *adjusted_mode)
400{
401 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
402
403 if (!tilcdc_crtc->simulate_vesa_sync)
404 return true;
405
406 /*
407 * tilcdc does not generate VESA-compliant sync but aligns
408 * VS on the second edge of HS instead of first edge.
409 * We use adjusted_mode, to fixup sync by aligning both rising
410 * edges and add HSKEW offset to fix the sync.
411 */
412 adjusted_mode->hskew = mode->hsync_end - mode->hsync_start;
413 adjusted_mode->flags |= DRM_MODE_FLAG_HSKEW;
414
415 if (mode->flags & DRM_MODE_FLAG_NHSYNC) {
416 adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC;
417 adjusted_mode->flags &= ~DRM_MODE_FLAG_NHSYNC;
418 } else {
419 adjusted_mode->flags |= DRM_MODE_FLAG_NHSYNC;
420 adjusted_mode->flags &= ~DRM_MODE_FLAG_PHSYNC;
421 }
422
423 return true;
424}
425
426/* 218/*
427 * Calculate the percentage difference between the requested pixel clock rate 219 * Calculate the percentage difference between the requested pixel clock rate
428 * and the effective rate resulting from calculating the clock divider value. 220 * and the effective rate resulting from calculating the clock divider value.
@@ -499,7 +291,7 @@ static void tilcdc_crtc_set_clk(struct drm_crtc *crtc)
499 LCDC_V2_CORE_CLK_EN); 291 LCDC_V2_CORE_CLK_EN);
500} 292}
501 293
502static void tilcdc_crtc_mode_set_nofb(struct drm_crtc *crtc) 294static void tilcdc_crtc_set_mode(struct drm_crtc *crtc)
503{ 295{
504 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); 296 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
505 struct drm_device *dev = crtc->dev; 297 struct drm_device *dev = crtc->dev;
@@ -509,8 +301,6 @@ static void tilcdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
509 struct drm_display_mode *mode = &crtc->state->adjusted_mode; 301 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
510 struct drm_framebuffer *fb = crtc->primary->state->fb; 302 struct drm_framebuffer *fb = crtc->primary->state->fb;
511 303
512 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
513
514 if (WARN_ON(!info)) 304 if (WARN_ON(!info))
515 return; 305 return;
516 306
@@ -659,17 +449,226 @@ static void tilcdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
659 else 449 else
660 tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER); 450 tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER);
661 451
662 drm_framebuffer_reference(fb);
663
664 tilcdc_crtc_set_clk(crtc); 452 tilcdc_crtc_set_clk(crtc);
665 453
666 tilcdc_crtc_load_palette(crtc); 454 tilcdc_crtc_load_palette(crtc);
667 455
668 set_scanout(crtc, fb); 456 set_scanout(crtc, fb);
669 457
458 drm_framebuffer_reference(fb);
459
670 crtc->hwmode = crtc->state->adjusted_mode; 460 crtc->hwmode = crtc->state->adjusted_mode;
671} 461}
672 462
463static void tilcdc_crtc_enable(struct drm_crtc *crtc)
464{
465 struct drm_device *dev = crtc->dev;
466 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
467
468 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
469 mutex_lock(&tilcdc_crtc->enable_lock);
470 if (tilcdc_crtc->enabled || tilcdc_crtc->shutdown) {
471 mutex_unlock(&tilcdc_crtc->enable_lock);
472 return;
473 }
474
475 pm_runtime_get_sync(dev->dev);
476
477 reset(crtc);
478
479 tilcdc_crtc_set_mode(crtc);
480
481 tilcdc_crtc_enable_irqs(dev);
482
483 tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE);
484 tilcdc_write_mask(dev, LCDC_RASTER_CTRL_REG,
485 LCDC_PALETTE_LOAD_MODE(DATA_ONLY),
486 LCDC_PALETTE_LOAD_MODE_MASK);
487 tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
488
489 drm_crtc_vblank_on(crtc);
490
491 tilcdc_crtc->enabled = true;
492 mutex_unlock(&tilcdc_crtc->enable_lock);
493}
494
495static void tilcdc_crtc_off(struct drm_crtc *crtc, bool shutdown)
496{
497 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
498 struct drm_device *dev = crtc->dev;
499 struct tilcdc_drm_private *priv = dev->dev_private;
500 int ret;
501
502 mutex_lock(&tilcdc_crtc->enable_lock);
503 if (shutdown)
504 tilcdc_crtc->shutdown = true;
505 if (!tilcdc_crtc->enabled) {
506 mutex_unlock(&tilcdc_crtc->enable_lock);
507 return;
508 }
509 tilcdc_crtc->frame_done = false;
510 tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
511
512 /*
513 * Wait for framedone irq which will still come before putting
514 * things to sleep..
515 */
516 ret = wait_event_timeout(tilcdc_crtc->frame_done_wq,
517 tilcdc_crtc->frame_done,
518 msecs_to_jiffies(500));
519 if (ret == 0)
520 dev_err(dev->dev, "%s: timeout waiting for framedone\n",
521 __func__);
522
523 drm_crtc_vblank_off(crtc);
524
525 tilcdc_crtc_disable_irqs(dev);
526
527 pm_runtime_put_sync(dev->dev);
528
529 if (tilcdc_crtc->next_fb) {
530 drm_flip_work_queue(&tilcdc_crtc->unref_work,
531 tilcdc_crtc->next_fb);
532 tilcdc_crtc->next_fb = NULL;
533 }
534
535 if (tilcdc_crtc->curr_fb) {
536 drm_flip_work_queue(&tilcdc_crtc->unref_work,
537 tilcdc_crtc->curr_fb);
538 tilcdc_crtc->curr_fb = NULL;
539 }
540
541 drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
542 tilcdc_crtc->last_vblank = ktime_set(0, 0);
543
544 tilcdc_crtc->enabled = false;
545 mutex_unlock(&tilcdc_crtc->enable_lock);
546}
547
548static void tilcdc_crtc_disable(struct drm_crtc *crtc)
549{
550 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
551 tilcdc_crtc_off(crtc, false);
552}
553
554void tilcdc_crtc_shutdown(struct drm_crtc *crtc)
555{
556 tilcdc_crtc_off(crtc, true);
557}
558
559static bool tilcdc_crtc_is_on(struct drm_crtc *crtc)
560{
561 return crtc->state && crtc->state->enable && crtc->state->active;
562}
563
564static void tilcdc_crtc_recover_work(struct work_struct *work)
565{
566 struct tilcdc_crtc *tilcdc_crtc =
567 container_of(work, struct tilcdc_crtc, recover_work);
568 struct drm_crtc *crtc = &tilcdc_crtc->base;
569
570 dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__);
571
572 drm_modeset_lock_crtc(crtc, NULL);
573
574 if (!tilcdc_crtc_is_on(crtc))
575 goto out;
576
577 tilcdc_crtc_disable(crtc);
578 tilcdc_crtc_enable(crtc);
579out:
580 drm_modeset_unlock_crtc(crtc);
581}
582
583static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
584{
585 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
586 struct tilcdc_drm_private *priv = crtc->dev->dev_private;
587
588 drm_modeset_lock_crtc(crtc, NULL);
589 tilcdc_crtc_disable(crtc);
590 drm_modeset_unlock_crtc(crtc);
591
592 flush_workqueue(priv->wq);
593
594 of_node_put(crtc->port);
595 drm_crtc_cleanup(crtc);
596 drm_flip_work_cleanup(&tilcdc_crtc->unref_work);
597}
598
599int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
600 struct drm_framebuffer *fb,
601 struct drm_pending_vblank_event *event)
602{
603 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
604 struct drm_device *dev = crtc->dev;
605 unsigned long flags;
606
607 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
608
609 if (tilcdc_crtc->event) {
610 dev_err(dev->dev, "already pending page flip!\n");
611 return -EBUSY;
612 }
613
614 drm_framebuffer_reference(fb);
615
616 crtc->primary->fb = fb;
617
618 spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags);
619
620 if (crtc->hwmode.vrefresh && ktime_to_ns(tilcdc_crtc->last_vblank)) {
621 ktime_t next_vblank;
622 s64 tdiff;
623
624 next_vblank = ktime_add_us(tilcdc_crtc->last_vblank,
625 1000000 / crtc->hwmode.vrefresh);
626
627 tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get()));
628
629 if (tdiff < TILCDC_VBLANK_SAFETY_THRESHOLD_US)
630 tilcdc_crtc->next_fb = fb;
631 }
632
633 if (tilcdc_crtc->next_fb != fb)
634 set_scanout(crtc, fb);
635
636 tilcdc_crtc->event = event;
637
638 spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags);
639
640 return 0;
641}
642
643static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc,
644 const struct drm_display_mode *mode,
645 struct drm_display_mode *adjusted_mode)
646{
647 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
648
649 if (!tilcdc_crtc->simulate_vesa_sync)
650 return true;
651
652 /*
653 * tilcdc does not generate VESA-compliant sync but aligns
654 * VS on the second edge of HS instead of first edge.
655 * We use adjusted_mode, to fixup sync by aligning both rising
656 * edges and add HSKEW offset to fix the sync.
657 */
658 adjusted_mode->hskew = mode->hsync_end - mode->hsync_start;
659 adjusted_mode->flags |= DRM_MODE_FLAG_HSKEW;
660
661 if (mode->flags & DRM_MODE_FLAG_NHSYNC) {
662 adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC;
663 adjusted_mode->flags &= ~DRM_MODE_FLAG_NHSYNC;
664 } else {
665 adjusted_mode->flags |= DRM_MODE_FLAG_NHSYNC;
666 adjusted_mode->flags &= ~DRM_MODE_FLAG_PHSYNC;
667 }
668
669 return true;
670}
671
673static int tilcdc_crtc_atomic_check(struct drm_crtc *crtc, 672static int tilcdc_crtc_atomic_check(struct drm_crtc *crtc,
674 struct drm_crtc_state *state) 673 struct drm_crtc_state *state)
675{ 674{
@@ -710,7 +709,6 @@ static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = {
710 .enable = tilcdc_crtc_enable, 709 .enable = tilcdc_crtc_enable,
711 .disable = tilcdc_crtc_disable, 710 .disable = tilcdc_crtc_disable,
712 .atomic_check = tilcdc_crtc_atomic_check, 711 .atomic_check = tilcdc_crtc_atomic_check,
713 .mode_set_nofb = tilcdc_crtc_mode_set_nofb,
714}; 712};
715 713
716int tilcdc_crtc_max_width(struct drm_crtc *crtc) 714int tilcdc_crtc_max_width(struct drm_crtc *crtc)