diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_legacy_crtc.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 106 |
1 files changed, 77 insertions, 29 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 7cb178a34a0f..825b351ff53c 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -23,12 +23,16 @@ * Authors: Dave Airlie * Alex Deucher */ -#include <drm/drmP.h> -#include <drm/drm_crtc_helper.h> -#include <drm/radeon_drm.h> + #include <drm/drm_fixed.h> -#include "radeon.h" +#include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_vblank.h> +#include <drm/radeon_drm.h> + #include "atom.h" +#include "radeon.h" static void radeon_overscan_setup(struct drm_crtc *crtc, struct drm_display_mode *mode) @@ -317,7 +321,7 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) */ if (rdev->flags & RADEON_SINGLE_CRTC) crtc_ext_cntl = RADEON_CRTC_CRT_ON; - + switch (mode) { case DRM_MODE_DPMS_ON: radeon_crtc->enabled = true; @@ -330,13 +334,15 @@ static void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) RADEON_CRTC_DISP_REQ_EN_B)); WREG32_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, ~(mask | crtc_ext_cntl)); } - drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); + if (dev->num_crtcs > radeon_crtc->crtc_id) + drm_crtc_vblank_on(crtc); radeon_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); + if (dev->num_crtcs > radeon_crtc->crtc_id) + drm_crtc_vblank_off(crtc); if (radeon_crtc->crtc_id) WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~(RADEON_CRTC2_EN | mask)); else { @@ -371,7 +377,6 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct radeon_framebuffer *radeon_fb; struct drm_framebuffer *target_fb; struct drm_gem_object *obj; struct radeon_bo *rbo; @@ -385,21 +390,17 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, DRM_DEBUG_KMS("\n"); /* no fb bound */ - if (!atomic && !crtc->fb) { + if (!atomic && !crtc->primary->fb) { DRM_DEBUG_KMS("No FB bound\n"); return 0; } - if (atomic) { - radeon_fb = to_radeon_framebuffer(fb); + if (atomic) target_fb = fb; - } - else { - radeon_fb = to_radeon_framebuffer(crtc->fb); - target_fb = crtc->fb; - } + else + target_fb = crtc->primary->fb; - switch (target_fb->bits_per_pixel) { + switch (target_fb->format->cpp[0] * 8) { case 8: format = 2; break; @@ -420,8 +421,9 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, } /* Pin framebuffer & get tilling informations */ - obj = radeon_fb->obj; + obj = target_fb->obj[0]; rbo = gem_to_radeon_bo(obj); +retry: r = radeon_bo_reserve(rbo, false); if (unlikely(r != 0)) return r; @@ -430,6 +432,33 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, &base); if (unlikely(r != 0)) { radeon_bo_unreserve(rbo); + + /* On old GPU like RN50 with little vram pining can fails because + * current fb is taking all space needed. So instead of unpining + * the old buffer after pining the new one, first unpin old one + * and then retry pining new one. + * + * As only master can set mode only master can pin and it is + * unlikely the master client will race with itself especialy + * on those old gpu with single crtc. + * + * We don't shutdown the display controller because new buffer + * will end up in same spot. + */ + if (!atomic && fb && fb != crtc->primary->fb) { + struct radeon_bo *old_rbo; + unsigned long nsize, osize; + + old_rbo = gem_to_radeon_bo(fb->obj[0]); + osize = radeon_bo_size(old_rbo); + nsize = radeon_bo_size(rbo); + if (nsize <= osize && !radeon_bo_reserve(old_rbo, false)) { + radeon_bo_unpin(old_rbo); + radeon_bo_unreserve(old_rbo); + fb = NULL; + goto retry; + } + } return -EINVAL; } radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); @@ -445,10 +474,9 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, crtc_offset_cntl = 0; - pitch_pixels = target_fb->pitches[0] / (target_fb->bits_per_pixel / 8); - crtc_pitch = (((pitch_pixels * target_fb->bits_per_pixel) + - ((target_fb->bits_per_pixel * 8) - 1)) / - (target_fb->bits_per_pixel * 8)); + pitch_pixels = target_fb->pitches[0] / target_fb->format->cpp[0]; + crtc_pitch = DIV_ROUND_UP(pitch_pixels * target_fb->format->cpp[0] * 8, + target_fb->format->cpp[0] * 8 * 8); crtc_pitch |= crtc_pitch << 16; crtc_offset_cntl |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN; @@ -473,14 +501,14 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, crtc_tile_x0_y0 = x | (y << 16); base &= ~0x7ff; } else { - int byteshift = target_fb->bits_per_pixel >> 4; + int byteshift = target_fb->format->cpp[0] * 8 >> 4; int tile_addr = (((y >> 3) * pitch_pixels + x) >> (8 - byteshift)) << 11; base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); crtc_offset_cntl |= (y % 16); } } else { int offset = y * pitch_pixels + x; - switch (target_fb->bits_per_pixel) { + switch (target_fb->format->cpp[0] * 8) { case 8: offset *= 1; break; @@ -527,9 +555,8 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset); WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); - if (!atomic && fb && fb != crtc->fb) { - radeon_fb = to_radeon_framebuffer(fb); - rbo = gem_to_radeon_bo(radeon_fb->obj); + if (!atomic && fb && fb != crtc->primary->fb) { + rbo = gem_to_radeon_bo(fb->obj[0]); r = radeon_bo_reserve(rbo, false); if (unlikely(r != 0)) return r; @@ -548,6 +575,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + const struct drm_framebuffer *fb = crtc->primary->fb; struct drm_encoder *encoder; int format; int hsync_start; @@ -571,7 +599,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod } } - switch (crtc->fb->bits_per_pixel) { + switch (fb->format->cpp[0] * 8) { case 8: format = 2; break; @@ -1026,6 +1054,7 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc, DRM_ERROR("Mode need scaling but only first crtc can do that.\n"); } } + radeon_cursor_reset(crtc); return 0; } @@ -1056,6 +1085,24 @@ static void radeon_crtc_commit(struct drm_crtc *crtc) } } +static void radeon_crtc_disable(struct drm_crtc *crtc) +{ + radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + if (crtc->primary->fb) { + int r; + struct radeon_bo *rbo; + + rbo = gem_to_radeon_bo(crtc->primary->fb->obj[0]); + r = radeon_bo_reserve(rbo, false); + if (unlikely(r)) + DRM_ERROR("failed to reserve rbo before unpin\n"); + else { + radeon_bo_unpin(rbo); + radeon_bo_unreserve(rbo); + } + } +} + static const struct drm_crtc_helper_funcs legacy_helper_funcs = { .dpms = radeon_crtc_dpms, .mode_fixup = radeon_crtc_mode_fixup, @@ -1064,7 +1111,8 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = { .mode_set_base_atomic = radeon_crtc_set_base_atomic, .prepare = radeon_crtc_prepare, .commit = radeon_crtc_commit, - .load_lut = radeon_crtc_load_lut, + .disable = radeon_crtc_disable, + .get_scanout_position = radeon_get_crtc_scanout_position, }; |
