aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c83
1 files changed, 79 insertions, 4 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 0d1aa050d41d..7b253815a323 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -30,6 +30,7 @@
30#include "atom.h" 30#include "atom.h"
31#include <asm/div64.h> 31#include <asm/div64.h>
32 32
33#include <linux/pm_runtime.h>
33#include <drm/drm_crtc_helper.h> 34#include <drm/drm_crtc_helper.h>
34#include <drm/drm_edid.h> 35#include <drm/drm_edid.h>
35 36
@@ -306,7 +307,7 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
306 */ 307 */
307 if (update_pending && 308 if (update_pending &&
308 (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 309 (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id,
309 &vpos, &hpos)) && 310 &vpos, &hpos, NULL, NULL)) &&
310 ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) || 311 ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
311 (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) { 312 (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) {
312 /* crtc didn't flip in this target vblank interval, 313 /* crtc didn't flip in this target vblank interval,
@@ -494,11 +495,55 @@ unlock_free:
494 return r; 495 return r;
495} 496}
496 497
498static int
499radeon_crtc_set_config(struct drm_mode_set *set)
500{
501 struct drm_device *dev;
502 struct radeon_device *rdev;
503 struct drm_crtc *crtc;
504 bool active = false;
505 int ret;
506
507 if (!set || !set->crtc)
508 return -EINVAL;
509
510 dev = set->crtc->dev;
511
512 ret = pm_runtime_get_sync(dev->dev);
513 if (ret < 0)
514 return ret;
515
516 ret = drm_crtc_helper_set_config(set);
517
518 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
519 if (crtc->enabled)
520 active = true;
521
522 pm_runtime_mark_last_busy(dev->dev);
523
524 rdev = dev->dev_private;
525 /* if we have active crtcs and we don't have a power ref,
526 take the current one */
527 if (active && !rdev->have_disp_power_ref) {
528 rdev->have_disp_power_ref = true;
529 return ret;
530 }
531 /* if we have no active crtcs, then drop the power ref
532 we got before */
533 if (!active && rdev->have_disp_power_ref) {
534 pm_runtime_put_autosuspend(dev->dev);
535 rdev->have_disp_power_ref = false;
536 }
537
538 /* drop the power reference we got coming in here */
539 pm_runtime_put_autosuspend(dev->dev);
540 return ret;
541}
497static const struct drm_crtc_funcs radeon_crtc_funcs = { 542static const struct drm_crtc_funcs radeon_crtc_funcs = {
498 .cursor_set = radeon_crtc_cursor_set, 543 .cursor_set = radeon_crtc_cursor_set,
499 .cursor_move = radeon_crtc_cursor_move, 544 .cursor_move = radeon_crtc_cursor_move,
500 .gamma_set = radeon_crtc_gamma_set, 545 .gamma_set = radeon_crtc_gamma_set,
501 .set_config = drm_crtc_helper_set_config, 546 .set_config = radeon_crtc_set_config,
502 .destroy = radeon_crtc_destroy, 547 .destroy = radeon_crtc_destroy,
503 .page_flip = radeon_crtc_page_flip, 548 .page_flip = radeon_crtc_page_flip,
504}; 549};
@@ -1178,6 +1223,12 @@ static struct drm_prop_enum_list radeon_audio_enum_list[] =
1178 { RADEON_AUDIO_AUTO, "auto" }, 1223 { RADEON_AUDIO_AUTO, "auto" },
1179}; 1224};
1180 1225
1226/* XXX support different dither options? spatial, temporal, both, etc. */
1227static struct drm_prop_enum_list radeon_dither_enum_list[] =
1228{ { RADEON_FMT_DITHER_DISABLE, "off" },
1229 { RADEON_FMT_DITHER_ENABLE, "on" },
1230};
1231
1181static int radeon_modeset_create_props(struct radeon_device *rdev) 1232static int radeon_modeset_create_props(struct radeon_device *rdev)
1182{ 1233{
1183 int sz; 1234 int sz;
@@ -1234,6 +1285,12 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
1234 "audio", 1285 "audio",
1235 radeon_audio_enum_list, sz); 1286 radeon_audio_enum_list, sz);
1236 1287
1288 sz = ARRAY_SIZE(radeon_dither_enum_list);
1289 rdev->mode_info.dither_property =
1290 drm_property_create_enum(rdev->ddev, 0,
1291 "dither",
1292 radeon_dither_enum_list, sz);
1293
1237 return 0; 1294 return 0;
1238} 1295}
1239 1296
@@ -1539,12 +1596,17 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
1539} 1596}
1540 1597
1541/* 1598/*
1542 * Retrieve current video scanout position of crtc on a given gpu. 1599 * Retrieve current video scanout position of crtc on a given gpu, and
1600 * an optional accurate timestamp of when query happened.
1543 * 1601 *
1544 * \param dev Device to query. 1602 * \param dev Device to query.
1545 * \param crtc Crtc to query. 1603 * \param crtc Crtc to query.
1546 * \param *vpos Location where vertical scanout position should be stored. 1604 * \param *vpos Location where vertical scanout position should be stored.
1547 * \param *hpos Location where horizontal scanout position should go. 1605 * \param *hpos Location where horizontal scanout position should go.
1606 * \param *stime Target location for timestamp taken immediately before
1607 * scanout position query. Can be NULL to skip timestamp.
1608 * \param *etime Target location for timestamp taken immediately after
1609 * scanout position query. Can be NULL to skip timestamp.
1548 * 1610 *
1549 * Returns vpos as a positive number while in active scanout area. 1611 * Returns vpos as a positive number while in active scanout area.
1550 * Returns vpos as a negative number inside vblank, counting the number 1612 * Returns vpos as a negative number inside vblank, counting the number
@@ -1560,7 +1622,8 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
1560 * unknown small number of scanlines wrt. real scanout position. 1622 * unknown small number of scanlines wrt. real scanout position.
1561 * 1623 *
1562 */ 1624 */
1563int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos) 1625int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos,
1626 ktime_t *stime, ktime_t *etime)
1564{ 1627{
1565 u32 stat_crtc = 0, vbl = 0, position = 0; 1628 u32 stat_crtc = 0, vbl = 0, position = 0;
1566 int vbl_start, vbl_end, vtotal, ret = 0; 1629 int vbl_start, vbl_end, vtotal, ret = 0;
@@ -1568,6 +1631,12 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int
1568 1631
1569 struct radeon_device *rdev = dev->dev_private; 1632 struct radeon_device *rdev = dev->dev_private;
1570 1633
1634 /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
1635
1636 /* Get optional system timestamp before query. */
1637 if (stime)
1638 *stime = ktime_get();
1639
1571 if (ASIC_IS_DCE4(rdev)) { 1640 if (ASIC_IS_DCE4(rdev)) {
1572 if (crtc == 0) { 1641 if (crtc == 0) {
1573 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + 1642 vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
@@ -1650,6 +1719,12 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int
1650 } 1719 }
1651 } 1720 }
1652 1721
1722 /* Get optional system timestamp after query. */
1723 if (etime)
1724 *etime = ktime_get();
1725
1726 /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
1727
1653 /* Decode into vertical and horizontal scanout position. */ 1728 /* Decode into vertical and horizontal scanout position. */
1654 *vpos = position & 0x1fff; 1729 *vpos = position & 0x1fff;
1655 *hpos = (position >> 16) & 0x1fff; 1730 *hpos = (position >> 16) & 0x1fff;