diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_display.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 83 |
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 | ||
498 | static int | ||
499 | radeon_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 | } | ||
497 | static const struct drm_crtc_funcs radeon_crtc_funcs = { | 542 | static 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. */ | ||
1227 | static struct drm_prop_enum_list radeon_dither_enum_list[] = | ||
1228 | { { RADEON_FMT_DITHER_DISABLE, "off" }, | ||
1229 | { RADEON_FMT_DITHER_ENABLE, "on" }, | ||
1230 | }; | ||
1231 | |||
1181 | static int radeon_modeset_create_props(struct radeon_device *rdev) | 1232 | static 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 | */ |
1563 | int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos) | 1625 | int 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; |