diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 149 |
1 files changed, 136 insertions, 13 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 961abf1cf040..67fd9f4ef93e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -60,7 +60,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/version.h> #include <linux/types.h> #include <linux/pm_runtime.h> #include <linux/pci.h> @@ -1016,8 +1015,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.flags.power_down_display_on_boot = true; - init_data.soc_bounding_box = adev->dm.soc_bounding_box; - /* Display Core create. */ adev->dm.dc = dc_create(&init_data); @@ -1778,6 +1775,11 @@ static int dm_suspend(void *handle) if (amdgpu_in_reset(adev)) { mutex_lock(&dm->dc_lock); + +#if defined(CONFIG_DRM_AMD_DC_DCN) + dc_allow_idle_optimizations(adev->dm.dc, false); +#endif + dm->cached_dc_state = dc_copy_state(dm->dc->current_state); dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, false); @@ -3719,10 +3721,53 @@ static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = { }; +static void get_min_max_dc_plane_scaling(struct drm_device *dev, + struct drm_framebuffer *fb, + int *min_downscale, int *max_upscale) +{ + struct amdgpu_device *adev = drm_to_adev(dev); + struct dc *dc = adev->dm.dc; + /* Caps for all supported planes are the same on DCE and DCN 1 - 3 */ + struct dc_plane_cap *plane_cap = &dc->caps.planes[0]; + + switch (fb->format->format) { + case DRM_FORMAT_P010: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + *max_upscale = plane_cap->max_upscale_factor.nv12; + *min_downscale = plane_cap->max_downscale_factor.nv12; + break; + + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + *max_upscale = plane_cap->max_upscale_factor.fp16; + *min_downscale = plane_cap->max_downscale_factor.fp16; + break; + + default: + *max_upscale = plane_cap->max_upscale_factor.argb8888; + *min_downscale = plane_cap->max_downscale_factor.argb8888; + break; + } + + /* + * A factor of 1 in the plane_cap means to not allow scaling, ie. use a + * scaling factor of 1.0 == 1000 units. + */ + if (*max_upscale == 1) + *max_upscale = 1000; + + if (*min_downscale == 1) + *min_downscale = 1000; +} + + static int fill_dc_scaling_info(const struct drm_plane_state *state, struct dc_scaling_info *scaling_info) { - int scale_w, scale_h; + int scale_w, scale_h, min_downscale, max_upscale; memset(scaling_info, 0, sizeof(*scaling_info)); @@ -3754,17 +3799,25 @@ static int fill_dc_scaling_info(const struct drm_plane_state *state, /* DRM doesn't specify clipping on destination output. */ scaling_info->clip_rect = scaling_info->dst_rect; - /* TODO: Validate scaling per-format with DC plane caps */ + /* Validate scaling per-format with DC plane caps */ + if (state->plane && state->plane->dev && state->fb) { + get_min_max_dc_plane_scaling(state->plane->dev, state->fb, + &min_downscale, &max_upscale); + } else { + min_downscale = 250; + max_upscale = 16000; + } + scale_w = scaling_info->dst_rect.width * 1000 / scaling_info->src_rect.width; - if (scale_w < 250 || scale_w > 16000) + if (scale_w < min_downscale || scale_w > max_upscale) return -EINVAL; scale_h = scaling_info->dst_rect.height * 1000 / scaling_info->src_rect.height; - if (scale_h < 250 || scale_h > 16000) + if (scale_h < min_downscale || scale_h > max_upscale) return -EINVAL; /* @@ -5321,6 +5374,9 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); struct amdgpu_device *adev = drm_to_adev(crtc->dev); struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state); +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct amdgpu_display_manager *dm = &adev->dm; +#endif int rc = 0; if (enable) { @@ -5336,7 +5392,32 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) return rc; irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; - return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY; + + if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) + return -EBUSY; + +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (amdgpu_in_reset(adev)) + return 0; + + mutex_lock(&dm->dc_lock); + + if (enable) + dm->active_vblank_irq_count++; + else + dm->active_vblank_irq_count--; + +#if defined(CONFIG_DRM_AMD_DC_DCN) + dc_allow_idle_optimizations( + adev->dm.dc, dm->active_vblank_irq_count == 0 ? true : false); + + DRM_DEBUG_DRIVER("Allow idle optimizations (MALL): %d\n", dm->active_vblank_irq_count == 0); +#endif + + mutex_unlock(&dm->dc_lock); + +#endif + return 0; } static int dm_enable_vblank(struct drm_crtc *crtc) @@ -5353,7 +5434,6 @@ static void dm_disable_vblank(struct drm_crtc *crtc) static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .reset = dm_crtc_reset_state, .destroy = amdgpu_dm_crtc_destroy, - .gamma_set = drm_atomic_helper_legacy_gamma_set, .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .atomic_duplicate_state = dm_crtc_duplicate_state, @@ -6328,12 +6408,51 @@ static void dm_plane_helper_cleanup_fb(struct drm_plane *plane, static int dm_plane_helper_check_state(struct drm_plane_state *state, struct drm_crtc_state *new_crtc_state) { - int max_downscale = 0; - int max_upscale = INT_MAX; + struct drm_framebuffer *fb = state->fb; + int min_downscale, max_upscale; + int min_scale = 0; + int max_scale = INT_MAX; + + /* Plane enabled? Validate viewport and get scaling factors from plane caps. */ + if (fb && state->crtc) { + /* Validate viewport to cover the case when only the position changes */ + if (state->plane->type != DRM_PLANE_TYPE_CURSOR) { + int viewport_width = state->crtc_w; + int viewport_height = state->crtc_h; + + if (state->crtc_x < 0) + viewport_width += state->crtc_x; + else if (state->crtc_x + state->crtc_w > new_crtc_state->mode.crtc_hdisplay) + viewport_width = new_crtc_state->mode.crtc_hdisplay - state->crtc_x; + + if (state->crtc_y < 0) + viewport_height += state->crtc_y; + else if (state->crtc_y + state->crtc_h > new_crtc_state->mode.crtc_vdisplay) + viewport_height = new_crtc_state->mode.crtc_vdisplay - state->crtc_y; + + /* If completely outside of screen, viewport_width and/or viewport_height will be negative, + * which is still OK to satisfy the condition below, thereby also covering these cases + * (when plane is completely outside of screen). + * x2 for width is because of pipe-split. + */ + if (viewport_width < MIN_VIEWPORT_SIZE*2 || viewport_height < MIN_VIEWPORT_SIZE) + return -EINVAL; + } + + /* Get min/max allowed scaling factors from plane caps. */ + get_min_max_dc_plane_scaling(state->crtc->dev, fb, + &min_downscale, &max_upscale); + /* + * Convert to drm convention: 16.16 fixed point, instead of dc's + * 1.0 == 1000. Also drm scaling is src/dst instead of dc's + * dst/src, so min_scale = 1.0 / max_upscale, etc. + */ + min_scale = (1000 << 16) / max_upscale; + max_scale = (1000 << 16) / min_downscale; + } - /* TODO: These should be checked against DC plane caps */ return drm_atomic_helper_check_plane_state( - state, new_crtc_state, max_downscale, max_upscale, true, true); + state, new_crtc_state, min_scale, max_scale, true, true); } static int dm_plane_atomic_check(struct drm_plane *plane, @@ -9588,6 +9707,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, amdgpu_dm_connector->max_vfreq = range->max_vfreq; amdgpu_dm_connector->pixel_clock_mhz = range->pixel_clock_mhz * 10; + + connector->display_info.monitor_range.min_vfreq = range->min_vfreq; + connector->display_info.monitor_range.max_vfreq = range->max_vfreq; + break; } |