From: Sasha Levin Date: Tue, 18 Mar 2025 00:58:39 +0000 (-0400) Subject: Fixes for 5.10 X-Git-Tag: v6.6.84~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=eabd8e9de6dd12b3bfd8897f13ffe10efc46f2cf;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.10 Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/drm-amd-display-check-for-invalid-input-params-when-.patch b/queue-5.10/drm-amd-display-check-for-invalid-input-params-when-.patch new file mode 100644 index 0000000000..27e0970798 --- /dev/null +++ b/queue-5.10/drm-amd-display-check-for-invalid-input-params-when-.patch @@ -0,0 +1,52 @@ +From b2a4ccbb5c1cc12b83b126cba65f715ecd910e47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Mar 2022 16:06:25 -0400 +Subject: drm/amd/display: Check for invalid input params when building scaling + params + +From: Michael Strauss + +[ Upstream commit 73b1da69f5314d96e1f963468863eaa884ee1030 ] + +[WHY] +Function to calculate scaling ratios can be called with invalid plane +src/dest, causing a divide by zero. + +[HOW] +Fail building scaling params if plane state src/dest rects are +unpopulated + +Tested-by: Daniel Wheeler +Reviewed-by: Charlene Liu +Acked-by: Tom Chung +Signed-off-by: Michael Strauss +Signed-off-by: Alex Deucher +Stable-dep-of: 374c9faac5a7 ("drm/amd/display: Fix null check for pipe_ctx->plane_state in resource_build_scaling_params") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index 0a2b3703be537..9564905c2c797 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -951,6 +951,15 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) + bool res = false; + DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); + ++ /* Invalid input */ ++ if (!plane_state->dst_rect.width || ++ !plane_state->dst_rect.height || ++ !plane_state->src_rect.width || ++ !plane_state->src_rect.height) { ++ ASSERT(0); ++ return false; ++ } ++ + pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface( + pipe_ctx->plane_state->format); + +-- +2.39.5 + diff --git a/queue-5.10/drm-amd-display-check-plane-scaling-against-format-s.patch b/queue-5.10/drm-amd-display-check-plane-scaling-against-format-s.patch new file mode 100644 index 0000000000..3abaadaad4 --- /dev/null +++ b/queue-5.10/drm-amd-display-check-plane-scaling-against-format-s.patch @@ -0,0 +1,147 @@ +From 8b9a2151fa9bfbeb283cbf13c1a469a835318393 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Dec 2020 19:50:58 +0100 +Subject: drm/amd/display: Check plane scaling against format specific hw plane + caps. + +From: Mario Kleiner + +[ Upstream commit 6300b3bd9d0d7afaf085dd086ce6258511c3f057 ] + +This takes hw constraints specific to pixel formats into account, +e.g., the inability of older hw to scale fp16 format framebuffers. + +It should now allow safely to enable fp16 formats also on DCE-8, +DCE-10, DCE-11.0 + +Reviewed-by: Nicholas Kazlauskas +Signed-off-by: Mario Kleiner +Signed-off-by: Alex Deucher +Stable-dep-of: 374c9faac5a7 ("drm/amd/display: Fix null check for pipe_ctx->plane_state in resource_build_scaling_params") +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 81 +++++++++++++++++-- + 1 file changed, 73 insertions(+), 8 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 50921b340b886..4b4de1751c53f 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -3719,10 +3719,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)); + +@@ -3788,17 +3831,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; + + /* +@@ -6010,12 +6061,26 @@ 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? Get min/max allowed scaling factors from plane caps. */ ++ if (fb && state->crtc) { ++ 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, +-- +2.39.5 + diff --git a/queue-5.10/drm-amd-display-dc-core-dc_resource-staticify-local-.patch b/queue-5.10/drm-amd-display-dc-core-dc_resource-staticify-local-.patch new file mode 100644 index 0000000000..dcc9798769 --- /dev/null +++ b/queue-5.10/drm-amd-display-dc-core-dc_resource-staticify-local-.patch @@ -0,0 +1,60 @@ +From 7c81547a4f05490294fa59431c4655f02e7aa8a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Jan 2021 08:07:28 +0000 +Subject: drm/amd/display/dc/core/dc_resource: Staticify local functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Lee Jones + +[ Upstream commit c88855f3a50903721c4e1dda16cb42b5f5432b5c ] + +Fixes the following W=1 kernel build warning(s): + + drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc_resource.c:1120:5: warning: no previous prototype for ‘shift_border_left_to_dst’ [-Wmissing-prototypes] + drivers/gpu/drm/amd/amdgpu/../display/dc/core/dc_resource.c:1131:6: warning: no previous prototype for ‘restore_border_left_from_dst’ [-Wmissing-prototypes] + +Cc: Harry Wentland +Cc: Leo Li +Cc: Alex Deucher +Cc: "Christian König" +Cc: David Airlie +Cc: Daniel Vetter +Cc: amd-gfx@lists.freedesktop.org +Cc: dri-devel@lists.freedesktop.org +Signed-off-by: Lee Jones +Signed-off-by: Alex Deucher +Stable-dep-of: 374c9faac5a7 ("drm/amd/display: Fix null check for pipe_ctx->plane_state in resource_build_scaling_params") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index b619ebd452ad4..5dc6840cea248 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -1108,7 +1108,7 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) + * We also need to make sure pipe_ctx->plane_res.scl_data.h_active uses the + * original h_border_left value in its calculation. + */ +-int shift_border_left_to_dst(struct pipe_ctx *pipe_ctx) ++static int shift_border_left_to_dst(struct pipe_ctx *pipe_ctx) + { + int store_h_border_left = pipe_ctx->stream->timing.h_border_left; + +@@ -1119,8 +1119,8 @@ int shift_border_left_to_dst(struct pipe_ctx *pipe_ctx) + return store_h_border_left; + } + +-void restore_border_left_from_dst(struct pipe_ctx *pipe_ctx, +- int store_h_border_left) ++static void restore_border_left_from_dst(struct pipe_ctx *pipe_ctx, ++ int store_h_border_left) + { + pipe_ctx->stream->dst.x -= store_h_border_left; + pipe_ctx->stream->timing.h_border_left = store_h_border_left; +-- +2.39.5 + diff --git a/queue-5.10/drm-amd-display-fix-null-check-for-pipe_ctx-plane_st.patch b/queue-5.10/drm-amd-display-fix-null-check-for-pipe_ctx-plane_st.patch new file mode 100644 index 0000000000..b98ff9380a --- /dev/null +++ b/queue-5.10/drm-amd-display-fix-null-check-for-pipe_ctx-plane_st.patch @@ -0,0 +1,44 @@ +From 75d2caf39b8e8099ce17fac479b26a87009f666d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Feb 2025 16:37:31 +0800 +Subject: drm/amd/display: Fix null check for pipe_ctx->plane_state in + resource_build_scaling_params + +From: Ma Ke + +[ Upstream commit 374c9faac5a763a05bc3f68ad9f73dab3c6aec90 ] + +Null pointer dereference issue could occur when pipe_ctx->plane_state +is null. The fix adds a check to ensure 'pipe_ctx->plane_state' is not +null before accessing. This prevents a null pointer dereference. + +Found by code review. + +Fixes: 3be5262e353b ("drm/amd/display: Rename more dc_surface stuff to plane_state") +Reviewed-by: Alex Hung +Signed-off-by: Ma Ke +Signed-off-by: Alex Deucher +(cherry picked from commit 63e6a77ccf239337baa9b1e7787cde9fa0462092) +Cc: stable@vger.kernel.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index 9564905c2c797..8dace2e401bbd 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -952,7 +952,8 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) + DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); + + /* Invalid input */ +- if (!plane_state->dst_rect.width || ++ if (!plane_state || ++ !plane_state->dst_rect.width || + !plane_state->dst_rect.height || + !plane_state->src_rect.width || + !plane_state->src_rect.height) { +-- +2.39.5 + diff --git a/queue-5.10/drm-amd-display-fix-odm-scaling.patch b/queue-5.10/drm-amd-display-fix-odm-scaling.patch new file mode 100644 index 0000000000..f08e34a894 --- /dev/null +++ b/queue-5.10/drm-amd-display-fix-odm-scaling.patch @@ -0,0 +1,868 @@ +From 43861af8f73add0ced7fe9a1fac5a0fcd54b1ca8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 May 2021 10:19:18 -0400 +Subject: drm/amd/display: fix odm scaling + +From: Dmytro Laktyushkin + +[ Upstream commit 6566cae7aef30da8833f1fa0eb854baf33b96676 ] + +There are two issues with scaling calculations, odm recout +calculation and matching viewport to actual recout. + +This change fixes both issues. Odm recout calculation via +special casing and viewport matching issue by reworking +the viewport calcualtion to use scaling ratios and recout +to derrive the required offset and size. + +Signed-off-by: Dmytro Laktyushkin +Reviewed-by: Jun Lei +Acked-by: Qingqing Zhuo +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Stable-dep-of: 374c9faac5a7 ("drm/amd/display: Fix null check for pipe_ctx->plane_state in resource_build_scaling_params") +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/dc/core/dc_resource.c | 568 +++++++----------- + drivers/gpu/drm/amd/display/dc/dc_types.h | 5 - + .../drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c | 12 +- + .../drm/amd/display/dc/dcn20/dcn20_resource.c | 14 +- + .../amd/display/dc/dml/display_mode_structs.h | 2 + + .../drm/amd/display/dc/dml/display_mode_vba.c | 13 + + .../gpu/drm/amd/display/dc/inc/hw/transform.h | 4 - + 7 files changed, 232 insertions(+), 386 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index d77001b2e106b..0a2b3703be537 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -647,124 +647,23 @@ static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *spli + } + } + +-static void calculate_viewport(struct pipe_ctx *pipe_ctx) ++/* ++ * This is a preliminary vp size calculation to allow us to check taps support. ++ * The result is completely overridden afterwards. ++ */ ++static void calculate_viewport_size(struct pipe_ctx *pipe_ctx) + { +- const struct dc_plane_state *plane_state = pipe_ctx->plane_state; +- const struct dc_stream_state *stream = pipe_ctx->stream; + struct scaler_data *data = &pipe_ctx->plane_res.scl_data; +- struct rect surf_src = plane_state->src_rect; +- struct rect clip, dest; +- int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 +- || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; +- int split_count = 0; +- int split_idx = 0; +- bool orthogonal_rotation, flip_y_start, flip_x_start; +- +- calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); + +- if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE || +- stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) { +- split_count = 0; +- split_idx = 0; +- } +- +- /* The actual clip is an intersection between stream +- * source and surface clip +- */ +- dest = plane_state->dst_rect; +- clip.x = stream->src.x > plane_state->clip_rect.x ? +- stream->src.x : plane_state->clip_rect.x; +- +- clip.width = stream->src.x + stream->src.width < +- plane_state->clip_rect.x + plane_state->clip_rect.width ? +- stream->src.x + stream->src.width - clip.x : +- plane_state->clip_rect.x + plane_state->clip_rect.width - clip.x ; +- +- clip.y = stream->src.y > plane_state->clip_rect.y ? +- stream->src.y : plane_state->clip_rect.y; +- +- clip.height = stream->src.y + stream->src.height < +- plane_state->clip_rect.y + plane_state->clip_rect.height ? +- stream->src.y + stream->src.height - clip.y : +- plane_state->clip_rect.y + plane_state->clip_rect.height - clip.y ; +- +- /* +- * Need to calculate how scan origin is shifted in vp space +- * to correctly rotate clip and dst +- */ +- get_vp_scan_direction( +- plane_state->rotation, +- plane_state->horizontal_mirror, +- &orthogonal_rotation, +- &flip_y_start, +- &flip_x_start); +- +- if (orthogonal_rotation) { +- swap(clip.x, clip.y); +- swap(clip.width, clip.height); +- swap(dest.x, dest.y); +- swap(dest.width, dest.height); +- } +- if (flip_x_start) { +- clip.x = dest.x + dest.width - clip.x - clip.width; +- dest.x = 0; +- } +- if (flip_y_start) { +- clip.y = dest.y + dest.height - clip.y - clip.height; +- dest.y = 0; +- } +- +- /* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio +- * num_pixels = clip.num_pix * scl_ratio +- */ +- data->viewport.x = surf_src.x + (clip.x - dest.x) * surf_src.width / dest.width; +- data->viewport.width = clip.width * surf_src.width / dest.width; +- +- data->viewport.y = surf_src.y + (clip.y - dest.y) * surf_src.height / dest.height; +- data->viewport.height = clip.height * surf_src.height / dest.height; +- +- /* Handle split */ +- if (split_count) { +- /* extra pixels in the division remainder need to go to pipes after +- * the extra pixel index minus one(epimo) defined here as: +- */ +- int epimo = 0; +- +- if (orthogonal_rotation) { +- if (flip_y_start) +- split_idx = split_count - split_idx; +- +- epimo = split_count - data->viewport.height % (split_count + 1); +- +- data->viewport.y += (data->viewport.height / (split_count + 1)) * split_idx; +- if (split_idx > epimo) +- data->viewport.y += split_idx - epimo - 1; +- data->viewport.height = data->viewport.height / (split_count + 1) + (split_idx > epimo ? 1 : 0); +- } else { +- if (flip_x_start) +- split_idx = split_count - split_idx; +- +- epimo = split_count - data->viewport.width % (split_count + 1); +- +- data->viewport.x += (data->viewport.width / (split_count + 1)) * split_idx; +- if (split_idx > epimo) +- data->viewport.x += split_idx - epimo - 1; +- data->viewport.width = data->viewport.width / (split_count + 1) + (split_idx > epimo ? 1 : 0); +- } ++ data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width)); ++ data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height)); ++ data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width)); ++ data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height)); ++ if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || ++ pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { ++ swap(data->viewport.width, data->viewport.height); ++ swap(data->viewport_c.width, data->viewport_c.height); + } +- +- /* Round down, compensate in init */ +- data->viewport_c.x = data->viewport.x / vpc_div; +- data->viewport_c.y = data->viewport.y / vpc_div; +- data->inits.h_c = (data->viewport.x % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero; +- data->inits.v_c = (data->viewport.y % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero; +- +- /* Round up, assume original video size always even dimensions */ +- data->viewport_c.width = (data->viewport.width + vpc_div - 1) / vpc_div; +- data->viewport_c.height = (data->viewport.height + vpc_div - 1) / vpc_div; +- +- data->viewport_unadjusted = data->viewport; +- data->viewport_c_unadjusted = data->viewport_c; + } + + static void calculate_recout(struct pipe_ctx *pipe_ctx) +@@ -773,26 +672,21 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx) + const struct dc_stream_state *stream = pipe_ctx->stream; + struct scaler_data *data = &pipe_ctx->plane_res.scl_data; + struct rect surf_clip = plane_state->clip_rect; +- bool pri_split_tb = pipe_ctx->bottom_pipe && +- pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state && +- stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; +- bool sec_split_tb = pipe_ctx->top_pipe && +- pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state && +- stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; +- int split_count = 0; +- int split_idx = 0; ++ bool split_tb = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; ++ int split_count, split_idx; + + calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); ++ if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) ++ split_idx = 0; + + /* + * Only the leftmost ODM pipe should be offset by a nonzero distance + */ +- if (!pipe_ctx->prev_odm_pipe) { ++ if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) { + data->recout.x = stream->dst.x; + if (stream->src.x < surf_clip.x) + data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width + / stream->src.width; +- + } else + data->recout.x = 0; + +@@ -809,26 +703,31 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx) + if (data->recout.height + data->recout.y > stream->dst.y + stream->dst.height) + data->recout.height = stream->dst.y + stream->dst.height - data->recout.y; + +- /* Handle h & v split, handle rotation using viewport */ +- if (sec_split_tb) { +- data->recout.y += data->recout.height / 2; +- /* Floor primary pipe, ceil 2ndary pipe */ +- data->recout.height = (data->recout.height + 1) / 2; +- } else if (pri_split_tb) ++ /* Handle h & v split */ ++ if (split_tb) { ++ ASSERT(data->recout.height % 2 == 0); + data->recout.height /= 2; +- else if (split_count) { +- /* extra pixels in the division remainder need to go to pipes after +- * the extra pixel index minus one(epimo) defined here as: +- */ +- int epimo = split_count - data->recout.width % (split_count + 1); +- +- /*no recout offset due to odm */ ++ } else if (split_count) { + if (!pipe_ctx->next_odm_pipe && !pipe_ctx->prev_odm_pipe) { ++ /* extra pixels in the division remainder need to go to pipes after ++ * the extra pixel index minus one(epimo) defined here as: ++ */ ++ int epimo = split_count - data->recout.width % (split_count + 1); ++ + data->recout.x += (data->recout.width / (split_count + 1)) * split_idx; + if (split_idx > epimo) + data->recout.x += split_idx - epimo - 1; ++ ASSERT(stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE || data->recout.width % 2 == 0); ++ data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0); ++ } else { ++ /* odm */ ++ if (split_idx == split_count) { ++ /* rightmost pipe is the remainder recout */ ++ data->recout.width -= data->h_active * split_count - data->recout.x; ++ data->recout.x = 0; ++ } else ++ data->recout.width = data->h_active - data->recout.x; + } +- data->recout.width = data->recout.width / (split_count + 1) + (split_idx > epimo ? 1 : 0); + } + } + +@@ -882,9 +781,15 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) + pipe_ctx->plane_res.scl_data.ratios.vert_c, 19); + } + +-static inline void adjust_vp_and_init_for_seamless_clip( ++ ++/* ++ * We completely calculate vp offset, size and inits here based entirely on scaling ++ * ratios and recout for pixel perfect pipe combine. ++ */ ++static void calculate_init_and_vp( + bool flip_scan_dir, +- int recout_skip, ++ int recout_offset_within_recout_full, ++ int recout_size, + int src_size, + int taps, + struct fixed31_32 ratio, +@@ -892,91 +797,87 @@ static inline void adjust_vp_and_init_for_seamless_clip( + int *vp_offset, + int *vp_size) + { +- if (!flip_scan_dir) { +- /* Adjust for viewport end clip-off */ +- if ((*vp_offset + *vp_size) < src_size) { +- int vp_clip = src_size - *vp_size - *vp_offset; +- int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio)); +- +- int_part = int_part > 0 ? int_part : 0; +- *vp_size += int_part < vp_clip ? int_part : vp_clip; +- } +- +- /* Adjust for non-0 viewport offset */ +- if (*vp_offset) { +- int int_part; +- +- *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip)); +- int_part = dc_fixpt_floor(*init) - *vp_offset; +- if (int_part < taps) { +- int int_adj = *vp_offset >= (taps - int_part) ? +- (taps - int_part) : *vp_offset; +- *vp_offset -= int_adj; +- *vp_size += int_adj; +- int_part += int_adj; +- } else if (int_part > taps) { +- *vp_offset += int_part - taps; +- *vp_size -= int_part - taps; +- int_part = taps; +- } +- init->value &= 0xffffffff; +- *init = dc_fixpt_add_int(*init, int_part); +- } +- } else { +- /* Adjust for non-0 viewport offset */ +- if (*vp_offset) { +- int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio)); +- +- int_part = int_part > 0 ? int_part : 0; +- *vp_size += int_part < *vp_offset ? int_part : *vp_offset; +- *vp_offset -= int_part < *vp_offset ? int_part : *vp_offset; +- } ++ struct fixed31_32 temp; ++ int int_part; + +- /* Adjust for viewport end clip-off */ +- if ((*vp_offset + *vp_size) < src_size) { +- int int_part; +- int end_offset = src_size - *vp_offset - *vp_size; +- +- /* +- * this is init if vp had no offset, keep in mind this is from the +- * right side of vp due to scan direction +- */ +- *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip)); +- /* +- * this is the difference between first pixel of viewport available to read +- * and init position, takning into account scan direction +- */ +- int_part = dc_fixpt_floor(*init) - end_offset; +- if (int_part < taps) { +- int int_adj = end_offset >= (taps - int_part) ? +- (taps - int_part) : end_offset; +- *vp_size += int_adj; +- int_part += int_adj; +- } else if (int_part > taps) { +- *vp_size += int_part - taps; +- int_part = taps; +- } +- init->value &= 0xffffffff; +- *init = dc_fixpt_add_int(*init, int_part); +- } ++ /* ++ * First of the taps starts sampling pixel number corresponding to recout ++ * pixel 1. Next recout pixel samples int part of and so on. ++ * All following calculations are based on this logic. ++ * ++ * Init calculated according to formula: ++ * init = (scaling_ratio + number_of_taps + 1) / 2 ++ * init_bot = init + scaling_ratio ++ * to get pixel perfect combine add the fraction from calculating vp offset ++ */ ++ temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full); ++ *vp_offset = dc_fixpt_floor(temp); ++ temp.value &= 0xffffffff; ++ *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int( ++ dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19); ++ /* ++ * If viewport has non 0 offset and there are more taps than covered by init then ++ * we should decrease the offset and increase init so we are never sampling ++ * outside of viewport. ++ */ ++ int_part = dc_fixpt_floor(*init); ++ if (int_part < taps) { ++ int_part = taps - int_part; ++ if (int_part > *vp_offset) ++ int_part = *vp_offset; ++ *vp_offset -= int_part; ++ *init = dc_fixpt_add_int(*init, int_part); + } ++ /* ++ * If taps are sampling outside of viewport at end of recout and there are more pixels ++ * available in the surface we should increase the viewport size, regardless set vp to ++ * only what is used. ++ */ ++ temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1)); ++ *vp_size = dc_fixpt_floor(temp); ++ if (*vp_size + *vp_offset > src_size) ++ *vp_size = src_size - *vp_offset; ++ ++ /* We did all the math assuming we are scanning same direction as display does, ++ * however mirror/rotation changes how vp scans vs how it is offset. If scan direction ++ * is flipped we simply need to calculate offset from the other side of plane. ++ * Note that outside of viewport all scaling hardware works in recout space. ++ */ ++ if (flip_scan_dir) ++ *vp_offset = src_size - *vp_offset - *vp_size; + } + +-static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) ++static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx) + { + const struct dc_plane_state *plane_state = pipe_ctx->plane_state; + const struct dc_stream_state *stream = pipe_ctx->stream; +- struct pipe_ctx *odm_pipe = pipe_ctx; + struct scaler_data *data = &pipe_ctx->plane_res.scl_data; +- struct rect src = pipe_ctx->plane_state->src_rect; +- int recout_skip_h, recout_skip_v, surf_size_h, surf_size_v; ++ struct rect src = plane_state->src_rect; + int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 +- || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; ++ || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; ++ int split_count, split_idx, ro_lb, ro_tb, recout_full_x, recout_full_y; + bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir; +- int odm_idx = 0; + ++ calculate_split_count_and_index(pipe_ctx, &split_count, &split_idx); + /* +- * Need to calculate the scan direction for viewport to make adjustments ++ * recout full is what the recout would have been if we didnt clip ++ * the source plane at all. We only care about left(ro_lb) and top(ro_tb) ++ * offsets of recout within recout full because those are the directions ++ * we scan from and therefore the only ones that affect inits. ++ */ ++ recout_full_x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x) ++ * stream->dst.width / stream->src.width; ++ recout_full_y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y) ++ * stream->dst.height / stream->src.height; ++ if (pipe_ctx->prev_odm_pipe && split_idx) ++ ro_lb = data->h_active * split_idx - recout_full_x; ++ else ++ ro_lb = data->recout.x - recout_full_x; ++ ro_tb = data->recout.y - recout_full_y; ++ ASSERT(ro_lb >= 0 && ro_tb >= 0); ++ ++ /* ++ * Work in recout rotation since that requires less transformations + */ + get_vp_scan_direction( + plane_state->rotation, +@@ -985,145 +886,62 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) + &flip_vert_scan_dir, + &flip_horz_scan_dir); + +- /* Calculate src rect rotation adjusted to recout space */ +- surf_size_h = src.x + src.width; +- surf_size_v = src.y + src.height; +- if (flip_horz_scan_dir) +- src.x = 0; +- if (flip_vert_scan_dir) +- src.y = 0; + if (orthogonal_rotation) { +- swap(src.x, src.y); + swap(src.width, src.height); ++ swap(flip_vert_scan_dir, flip_horz_scan_dir); + } + +- /*modified recout_skip_h calculation due to odm having no recout offset*/ +- while (odm_pipe->prev_odm_pipe) { +- odm_idx++; +- odm_pipe = odm_pipe->prev_odm_pipe; +- } +- /*odm_pipe is the leftmost pipe in the ODM group*/ +- recout_skip_h = odm_idx * data->recout.width; +- +- /* Recout matching initial vp offset = recout_offset - (stream dst offset + +- * ((surf dst offset - stream src offset) * 1/ stream scaling ratio) +- * - (surf surf_src offset * 1/ full scl ratio)) +- */ +- recout_skip_h += odm_pipe->plane_res.scl_data.recout.x +- - (stream->dst.x + (plane_state->dst_rect.x - stream->src.x) +- * stream->dst.width / stream->src.width - +- src.x * plane_state->dst_rect.width / src.width +- * stream->dst.width / stream->src.width); +- +- +- recout_skip_v = data->recout.y - (stream->dst.y + (plane_state->dst_rect.y - stream->src.y) +- * stream->dst.height / stream->src.height - +- src.y * plane_state->dst_rect.height / src.height +- * stream->dst.height / stream->src.height); +- if (orthogonal_rotation) +- swap(recout_skip_h, recout_skip_v); +- /* +- * Init calculated according to formula: +- * init = (scaling_ratio + number_of_taps + 1) / 2 +- * init_bot = init + scaling_ratio +- * init_c = init + truncated_vp_c_offset(from calculate viewport) +- */ +- data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int( +- dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19); +- +- data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int( +- dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19); +- +- data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int( +- dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19); +- +- data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int( +- dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19); +- +- /* +- * Taps, inits and scaling ratios are in recout space need to rotate +- * to viewport rotation before adjustment +- */ +- adjust_vp_and_init_for_seamless_clip( ++ calculate_init_and_vp( + flip_horz_scan_dir, +- recout_skip_h, +- surf_size_h, +- orthogonal_rotation ? data->taps.v_taps : data->taps.h_taps, +- orthogonal_rotation ? data->ratios.vert : data->ratios.horz, +- orthogonal_rotation ? &data->inits.v : &data->inits.h, ++ ro_lb, ++ data->recout.width, ++ src.width, ++ data->taps.h_taps, ++ data->ratios.horz, ++ &data->inits.h, + &data->viewport.x, + &data->viewport.width); +- adjust_vp_and_init_for_seamless_clip( ++ calculate_init_and_vp( + flip_horz_scan_dir, +- recout_skip_h, +- surf_size_h / vpc_div, +- orthogonal_rotation ? data->taps.v_taps_c : data->taps.h_taps_c, +- orthogonal_rotation ? data->ratios.vert_c : data->ratios.horz_c, +- orthogonal_rotation ? &data->inits.v_c : &data->inits.h_c, ++ ro_lb, ++ data->recout.width, ++ src.width / vpc_div, ++ data->taps.h_taps_c, ++ data->ratios.horz_c, ++ &data->inits.h_c, + &data->viewport_c.x, + &data->viewport_c.width); +- adjust_vp_and_init_for_seamless_clip( ++ calculate_init_and_vp( + flip_vert_scan_dir, +- recout_skip_v, +- surf_size_v, +- orthogonal_rotation ? data->taps.h_taps : data->taps.v_taps, +- orthogonal_rotation ? data->ratios.horz : data->ratios.vert, +- orthogonal_rotation ? &data->inits.h : &data->inits.v, ++ ro_tb, ++ data->recout.height, ++ src.height, ++ data->taps.v_taps, ++ data->ratios.vert, ++ &data->inits.v, + &data->viewport.y, + &data->viewport.height); +- adjust_vp_and_init_for_seamless_clip( ++ calculate_init_and_vp( + flip_vert_scan_dir, +- recout_skip_v, +- surf_size_v / vpc_div, +- orthogonal_rotation ? data->taps.h_taps_c : data->taps.v_taps_c, +- orthogonal_rotation ? data->ratios.horz_c : data->ratios.vert_c, +- orthogonal_rotation ? &data->inits.h_c : &data->inits.v_c, ++ ro_tb, ++ data->recout.height, ++ src.height / vpc_div, ++ data->taps.v_taps_c, ++ data->ratios.vert_c, ++ &data->inits.v_c, + &data->viewport_c.y, + &data->viewport_c.height); +- +- /* Interlaced inits based on final vert inits */ +- data->inits.v_bot = dc_fixpt_add(data->inits.v, data->ratios.vert); +- data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c); +- +-} +- +-/* +- * When handling 270 rotation in mixed SLS mode, we have +- * stream->timing.h_border_left that is non zero. If we are doing +- * pipe-splitting, this h_border_left value gets added to recout.x and when it +- * calls calculate_inits_and_adj_vp() and +- * adjust_vp_and_init_for_seamless_clip(), it can cause viewport.height for a +- * pipe to be incorrect. +- * +- * To fix this, instead of using stream->timing.h_border_left, we can use +- * stream->dst.x to represent the border instead. So we will set h_border_left +- * to 0 and shift the appropriate amount in stream->dst.x. We will then +- * perform all calculations in resource_build_scaling_params() based on this +- * and then restore the h_border_left and stream->dst.x to their original +- * values. +- * +- * shift_border_left_to_dst() will shift the amount of h_border_left to +- * stream->dst.x and set h_border_left to 0. restore_border_left_from_dst() +- * will restore h_border_left and stream->dst.x back to their original values +- * We also need to make sure pipe_ctx->plane_res.scl_data.h_active uses the +- * original h_border_left value in its calculation. +- */ +-static int shift_border_left_to_dst(struct pipe_ctx *pipe_ctx) +-{ +- int store_h_border_left = pipe_ctx->stream->timing.h_border_left; +- +- if (store_h_border_left) { +- pipe_ctx->stream->timing.h_border_left = 0; +- pipe_ctx->stream->dst.x += store_h_border_left; ++ if (orthogonal_rotation) { ++ swap(data->viewport.x, data->viewport.y); ++ swap(data->viewport.width, data->viewport.height); ++ swap(data->viewport_c.x, data->viewport_c.y); ++ swap(data->viewport_c.width, data->viewport_c.height); + } +- return store_h_border_left; +-} +- +-static void restore_border_left_from_dst(struct pipe_ctx *pipe_ctx, +- int store_h_border_left) +-{ +- pipe_ctx->stream->dst.x -= store_h_border_left; +- pipe_ctx->stream->timing.h_border_left = store_h_border_left; ++ data->viewport.x += src.x; ++ data->viewport.y += src.y; ++ ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0); ++ data->viewport_c.x += src.x / vpc_div; ++ data->viewport_c.y += src.y / vpc_div; + } + + bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) +@@ -1131,48 +949,42 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) + const struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + bool res = false; +- int store_h_border_left = shift_border_left_to_dst(pipe_ctx); + DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); +- /* Important: scaling ratio calculation requires pixel format, +- * lb depth calculation requires recout and taps require scaling ratios. +- * Inits require viewport, taps, ratios and recout of split pipe +- */ ++ + pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface( + pipe_ctx->plane_state->format); + +- calculate_scaling_ratios(pipe_ctx); +- +- calculate_viewport(pipe_ctx); ++ /* Timing borders are part of vactive that we are also supposed to skip in addition ++ * to any stream dst offset. Since dm logic assumes dst is in addressable ++ * space we need to add the the left and top borders to dst offsets temporarily. ++ * TODO: fix in DM, stream dst is supposed to be in vactive ++ */ ++ pipe_ctx->stream->dst.x += timing->h_border_left; ++ pipe_ctx->stream->dst.y += timing->v_border_top; + +- if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE || +- pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) { +- if (store_h_border_left) { +- restore_border_left_from_dst(pipe_ctx, +- store_h_border_left); +- } +- return false; +- } ++ /* Calculate H and V active size */ ++ pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable + ++ timing->h_border_left + timing->h_border_right; ++ pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable + ++ timing->v_border_top + timing->v_border_bottom; ++ if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe) ++ pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1; + ++ /* depends on h_active */ + calculate_recout(pipe_ctx); ++ /* depends on pixel format */ ++ calculate_scaling_ratios(pipe_ctx); ++ /* depends on scaling ratios and recout, does not calculate offset yet */ ++ calculate_viewport_size(pipe_ctx); + +- /** ++ /* ++ * LB calculations depend on vp size, h/v_active and scaling ratios + * Setting line buffer pixel depth to 24bpp yields banding + * on certain displays, such as the Sharp 4k + */ + pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha; + +- pipe_ctx->plane_res.scl_data.recout.x += timing->h_border_left; +- pipe_ctx->plane_res.scl_data.recout.y += timing->v_border_top; +- +- pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable + +- store_h_border_left + timing->h_border_right; +- pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable + +- timing->v_border_top + timing->v_border_bottom; +- if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe) +- pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1; +- +- /* Taps calculations */ + if (pipe_ctx->plane_res.xfm != NULL) + res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( + pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); +@@ -1199,9 +1011,31 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) + &plane_state->scaling_quality); + } + ++ /* ++ * Depends on recout, scaling ratios, h_active and taps ++ * May need to re-check lb size after this in some obscure scenario ++ */ + if (res) +- /* May need to re-check lb size after this in some obscure scenario */ +- calculate_inits_and_adj_vp(pipe_ctx); ++ calculate_inits_and_viewports(pipe_ctx); ++ ++ /* ++ * Handle side by side and top bottom 3d recout offsets after vp calculation ++ * since 3d is special and needs to calculate vp as if there is no recout offset ++ * This may break with rotation, good thing we aren't mixing hw rotation and 3d ++ */ ++ if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) { ++ ASSERT(plane_state->rotation == ROTATION_ANGLE_0 || ++ (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM && ++ pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE)); ++ if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) ++ pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height; ++ else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE) ++ pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width; ++ } ++ ++ if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE || ++ pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) ++ res = false; + + DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d Recout: height:%d width:%d x:%d y:%d HACTIVE:%d VACTIVE:%d\n" + "src_rect: height:%d width:%d x:%d y:%d dst_rect: height:%d width:%d x:%d y:%d clip_rect: height:%d width:%d x:%d y:%d\n", +@@ -1230,8 +1064,8 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) + plane_state->clip_rect.x, + plane_state->clip_rect.y); + +- if (store_h_border_left) +- restore_border_left_from_dst(pipe_ctx, store_h_border_left); ++ pipe_ctx->stream->dst.x -= timing->h_border_left; ++ pipe_ctx->stream->dst.y -= timing->v_border_top; + + return res; + } +diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h +index c47a19719de2c..c8c2ba7e7b05c 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dc_types.h +@@ -268,11 +268,6 @@ struct dc_edid_caps { + struct dc_panel_patch panel_patch; + }; + +-struct view { +- uint32_t width; +- uint32_t height; +-}; +- + struct dc_mode_flags { + /* note: part of refresh rate flag*/ + uint32_t INTERLACE :1; +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c +index 8bb5912d837d4..bd842055ea95b 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c +@@ -617,8 +617,10 @@ static void dpp1_dscl_set_manual_ratio_init( + SCL_V_INIT_INT, init_int); + + if (REG(SCL_VERT_FILTER_INIT_BOT)) { +- init_frac = dc_fixpt_u0d19(data->inits.v_bot) << 5; +- init_int = dc_fixpt_floor(data->inits.v_bot); ++ struct fixed31_32 bot = dc_fixpt_add(data->inits.v, data->ratios.vert); ++ ++ init_frac = dc_fixpt_u0d19(bot) << 5; ++ init_int = dc_fixpt_floor(bot); + REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0, + SCL_V_INIT_FRAC_BOT, init_frac, + SCL_V_INIT_INT_BOT, init_int); +@@ -631,8 +633,10 @@ static void dpp1_dscl_set_manual_ratio_init( + SCL_V_INIT_INT_C, init_int); + + if (REG(SCL_VERT_FILTER_INIT_BOT_C)) { +- init_frac = dc_fixpt_u0d19(data->inits.v_c_bot) << 5; +- init_int = dc_fixpt_floor(data->inits.v_c_bot); ++ struct fixed31_32 bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c); ++ ++ init_frac = dc_fixpt_u0d19(bot) << 5; ++ init_int = dc_fixpt_floor(bot); + REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0, + SCL_V_INIT_FRAC_BOT_C, init_frac, + SCL_V_INIT_INT_BOT_C, init_int); +diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +index 53ac826935328..b4bff3b3d842d 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +@@ -2281,12 +2281,14 @@ int dcn20_populate_dml_pipes_from_context( + + pipes[pipe_cnt].pipe.src.source_scan = pln->rotation == ROTATION_ANGLE_90 + || pln->rotation == ROTATION_ANGLE_270 ? dm_vert : dm_horz; +- pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport_unadjusted.y; +- pipes[pipe_cnt].pipe.src.viewport_y_c = scl->viewport_c_unadjusted.y; +- pipes[pipe_cnt].pipe.src.viewport_width = scl->viewport_unadjusted.width; +- pipes[pipe_cnt].pipe.src.viewport_width_c = scl->viewport_c_unadjusted.width; +- pipes[pipe_cnt].pipe.src.viewport_height = scl->viewport_unadjusted.height; +- pipes[pipe_cnt].pipe.src.viewport_height_c = scl->viewport_c_unadjusted.height; ++ pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport.y; ++ pipes[pipe_cnt].pipe.src.viewport_y_c = scl->viewport_c.y; ++ pipes[pipe_cnt].pipe.src.viewport_width = scl->viewport.width; ++ pipes[pipe_cnt].pipe.src.viewport_width_c = scl->viewport_c.width; ++ pipes[pipe_cnt].pipe.src.viewport_height = scl->viewport.height; ++ pipes[pipe_cnt].pipe.src.viewport_height_c = scl->viewport_c.height; ++ pipes[pipe_cnt].pipe.src.viewport_width_max = pln->src_rect.width; ++ pipes[pipe_cnt].pipe.src.viewport_height_max = pln->src_rect.height; + pipes[pipe_cnt].pipe.src.surface_width_y = pln->plane_size.surface_size.width; + pipes[pipe_cnt].pipe.src.surface_height_y = pln->plane_size.surface_size.height; + pipes[pipe_cnt].pipe.src.surface_width_c = pln->plane_size.chroma_size.width; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +index 6ab74640c0da7..a86b821d61c82 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h ++++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +@@ -255,6 +255,8 @@ struct _vcs_dpi_display_pipe_source_params_st { + unsigned int viewport_y_c; + unsigned int viewport_width_c; + unsigned int viewport_height_c; ++ unsigned int viewport_width_max; ++ unsigned int viewport_height_max; + unsigned int data_pitch; + unsigned int data_pitch_c; + unsigned int meta_pitch; +diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +index b320931360893..079fa52a73791 100644 +--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c ++++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +@@ -628,6 +628,19 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) + } + } + } ++ if (src->viewport_width_max) { ++ int hdiv_c = src->source_format >= dm_420_8 && src->source_format <= dm_422_10 ? 2 : 1; ++ int vdiv_c = src->source_format >= dm_420_8 && src->source_format <= dm_420_12 ? 2 : 1; ++ ++ if (mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] > src->viewport_width_max) ++ mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] = src->viewport_width_max; ++ if (mode_lib->vba.ViewportHeight[mode_lib->vba.NumberOfActivePlanes] > src->viewport_height_max) ++ mode_lib->vba.ViewportHeight[mode_lib->vba.NumberOfActivePlanes] = src->viewport_height_max; ++ if (mode_lib->vba.ViewportWidthChroma[mode_lib->vba.NumberOfActivePlanes] > src->viewport_width_max / hdiv_c) ++ mode_lib->vba.ViewportWidthChroma[mode_lib->vba.NumberOfActivePlanes] = src->viewport_width_max / hdiv_c; ++ if (mode_lib->vba.ViewportHeightChroma[mode_lib->vba.NumberOfActivePlanes] > src->viewport_height_max / vdiv_c) ++ mode_lib->vba.ViewportHeightChroma[mode_lib->vba.NumberOfActivePlanes] = src->viewport_height_max / vdiv_c; ++ } + + if (pipes[k].pipe.src.immediate_flip) { + mode_lib->vba.ImmediateFlipSupport = true; +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h +index 2947d1b155129..2a0db2b03047e 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/transform.h +@@ -162,9 +162,7 @@ struct scl_inits { + struct fixed31_32 h; + struct fixed31_32 h_c; + struct fixed31_32 v; +- struct fixed31_32 v_bot; + struct fixed31_32 v_c; +- struct fixed31_32 v_c_bot; + }; + + struct scaler_data { +@@ -173,8 +171,6 @@ struct scaler_data { + struct scaling_taps taps; + struct rect viewport; + struct rect viewport_c; +- struct rect viewport_unadjusted; +- struct rect viewport_c_unadjusted; + struct rect recout; + struct scaling_ratios ratios; + struct scl_inits inits; +-- +2.39.5 + diff --git a/queue-5.10/drm-amd-display-reject-too-small-viewport-size-when-.patch b/queue-5.10/drm-amd-display-reject-too-small-viewport-size-when-.patch new file mode 100644 index 0000000000..1ff9d75d89 --- /dev/null +++ b/queue-5.10/drm-amd-display-reject-too-small-viewport-size-when-.patch @@ -0,0 +1,103 @@ +From 2062cc888befbf073a452dccf5235478ad943099 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 22:35:54 -0500 +Subject: drm/amd/display: Reject too small viewport size when validating plane + +From: Nikola Cornij + +[ Upstream commit 40d916a2602c8920e0f04a49abfd1ff7c1e54e91 ] + +[why] +Overlay won't move to a new positon if viewport size is smaller than +what can be handled. It'd either disappear or stay at the old +position. This condition is for example hit if overlay is moved too +much outside of left or top edge of the screen, but it applies to +any non-cursor plane type. + +[how] +Reject this contidion at validation time. This gives the calling +level a chance to handle this gracefully and avoid inconsistent +behaivor. + +Signed-off-by: Nikola Cornij +Reviewed-by: Nicholas Kazlauskas +Acked-by: Anson Jacob +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Stable-dep-of: 374c9faac5a7 ("drm/amd/display: Fix null check for pipe_ctx->plane_state in resource_build_scaling_params") +Signed-off-by: Sasha Levin +--- + .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 27 ++++++++++++++++++- + .../gpu/drm/amd/display/dc/core/dc_resource.c | 4 +-- + drivers/gpu/drm/amd/display/dc/dc.h | 1 + + 3 files changed, 29 insertions(+), 3 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 4b4de1751c53f..786cd892f1797 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +@@ -6066,8 +6066,33 @@ static int dm_plane_helper_check_state(struct drm_plane_state *state, + int min_scale = 0; + int max_scale = INT_MAX; + +- /* Plane enabled? Get min/max allowed scaling factors from plane caps. */ ++ /* 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); + /* +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index 5dc6840cea248..d77001b2e106b 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -1144,8 +1144,8 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) + + calculate_viewport(pipe_ctx); + +- if (pipe_ctx->plane_res.scl_data.viewport.height < 12 || +- pipe_ctx->plane_res.scl_data.viewport.width < 12) { ++ if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE || ++ pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE) { + if (store_h_border_left) { + restore_border_left_from_dst(pipe_ctx, + store_h_border_left); +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index 1df7c49ac8d77..d3a4a55f3f1fa 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -48,6 +48,7 @@ + #define MAX_PLANES 6 + #define MAX_STREAMS 6 + #define MAX_SINKS_PER_LINK 4 ++#define MIN_VIEWPORT_SIZE 12 + + /******************************************************************************* + * Display Core Interfaces +-- +2.39.5 + diff --git a/queue-5.10/i2c-ali1535-fix-an-error-handling-path-in-ali1535_pr.patch b/queue-5.10/i2c-ali1535-fix-an-error-handling-path-in-ali1535_pr.patch new file mode 100644 index 0000000000..cf2ccc7d87 --- /dev/null +++ b/queue-5.10/i2c-ali1535-fix-an-error-handling-path-in-ali1535_pr.patch @@ -0,0 +1,55 @@ +From bd0a89a159d1ec5c6c15fed1fdc6145107b62766 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Mar 2025 20:53:08 +0100 +Subject: i2c: ali1535: Fix an error handling path in ali1535_probe() + +From: Christophe JAILLET + +[ Upstream commit 9b5463f349d019a261f1e80803447efca3126151 ] + +If i2c_add_adapter() fails, the request_region() call in ali1535_setup() +must be undone by a corresponding release_region() call, as done in the +remove function. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Christophe JAILLET +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/0daf63d7a2ce74c02e2664ba805bbfadab7d25e5.1741031571.git.christophe.jaillet@wanadoo.fr +Signed-off-by: Sasha Levin +--- + drivers/i2c/busses/i2c-ali1535.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c +index fb93152845f43..b36b75fc5b089 100644 +--- a/drivers/i2c/busses/i2c-ali1535.c ++++ b/drivers/i2c/busses/i2c-ali1535.c +@@ -490,6 +490,8 @@ MODULE_DEVICE_TABLE(pci, ali1535_ids); + + static int ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id) + { ++ int ret; ++ + if (ali1535_setup(dev)) { + dev_warn(&dev->dev, + "ALI1535 not detected, module not inserted.\n"); +@@ -501,7 +503,15 @@ static int ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id) + + snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name), + "SMBus ALI1535 adapter at %04x", ali1535_offset); +- return i2c_add_adapter(&ali1535_adapter); ++ ret = i2c_add_adapter(&ali1535_adapter); ++ if (ret) ++ goto release_region; ++ ++ return 0; ++ ++release_region: ++ release_region(ali1535_smba, ALI1535_SMB_IOSIZE); ++ return ret; + } + + static void ali1535_remove(struct pci_dev *dev) +-- +2.39.5 + diff --git a/queue-5.10/i2c-ali15x3-fix-an-error-handling-path-in-ali15x3_pr.patch b/queue-5.10/i2c-ali15x3-fix-an-error-handling-path-in-ali15x3_pr.patch new file mode 100644 index 0000000000..b857afec8a --- /dev/null +++ b/queue-5.10/i2c-ali15x3-fix-an-error-handling-path-in-ali15x3_pr.patch @@ -0,0 +1,55 @@ +From 073a4b895b28a4e59566f75b4171ada4df2e17dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Mar 2025 20:58:06 +0100 +Subject: i2c: ali15x3: Fix an error handling path in ali15x3_probe() + +From: Christophe JAILLET + +[ Upstream commit 6e55caaf30c88209d097e575a169b1dface1ab69 ] + +If i2c_add_adapter() fails, the request_region() call in ali15x3_setup() +must be undone by a corresponding release_region() call, as done in the +remove function. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Christophe JAILLET +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/9b2090cbcc02659f425188ea05f2e02745c4e67b.1741031878.git.christophe.jaillet@wanadoo.fr +Signed-off-by: Sasha Levin +--- + drivers/i2c/busses/i2c-ali15x3.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c +index cc58feacd0821..28a57cb6efb99 100644 +--- a/drivers/i2c/busses/i2c-ali15x3.c ++++ b/drivers/i2c/busses/i2c-ali15x3.c +@@ -473,6 +473,8 @@ MODULE_DEVICE_TABLE (pci, ali15x3_ids); + + static int ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id) + { ++ int ret; ++ + if (ali15x3_setup(dev)) { + dev_err(&dev->dev, + "ALI15X3 not detected, module not inserted.\n"); +@@ -484,7 +486,15 @@ static int ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id) + + snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name), + "SMBus ALI15X3 adapter at %04x", ali15x3_smba); +- return i2c_add_adapter(&ali15x3_adapter); ++ ret = i2c_add_adapter(&ali15x3_adapter); ++ if (ret) ++ goto release_region; ++ ++ return 0; ++ ++release_region: ++ release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); ++ return ret; + } + + static void ali15x3_remove(struct pci_dev *dev) +-- +2.39.5 + diff --git a/queue-5.10/i2c-sis630-fix-an-error-handling-path-in-sis630_prob.patch b/queue-5.10/i2c-sis630-fix-an-error-handling-path-in-sis630_prob.patch new file mode 100644 index 0000000000..e23744da9b --- /dev/null +++ b/queue-5.10/i2c-sis630-fix-an-error-handling-path-in-sis630_prob.patch @@ -0,0 +1,55 @@ +From c3c5af5afe55c5cf5b8839b68e592ba7e457cfe3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Mar 2025 21:26:54 +0100 +Subject: i2c: sis630: Fix an error handling path in sis630_probe() + +From: Christophe JAILLET + +[ Upstream commit 2b22459792fcb4def9f0936d64575ac11a95a58d ] + +If i2c_add_adapter() fails, the request_region() call in sis630_setup() +must be undone by a corresponding release_region() call, as done in the +remove function. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Christophe JAILLET +Link: https://lore.kernel.org/r/3d607601f2c38e896b10207963c6ab499ca5c307.1741033587.git.christophe.jaillet@wanadoo.fr +Signed-off-by: Andi Shyti +Signed-off-by: Sasha Levin +--- + drivers/i2c/busses/i2c-sis630.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c +index cfb8e04a2a831..6befa6ff83f26 100644 +--- a/drivers/i2c/busses/i2c-sis630.c ++++ b/drivers/i2c/busses/i2c-sis630.c +@@ -509,6 +509,8 @@ MODULE_DEVICE_TABLE(pci, sis630_ids); + + static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id) + { ++ int ret; ++ + if (sis630_setup(dev)) { + dev_err(&dev->dev, + "SIS630 compatible bus not detected, " +@@ -522,7 +524,15 @@ static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id) + snprintf(sis630_adapter.name, sizeof(sis630_adapter.name), + "SMBus SIS630 adapter at %04x", smbus_base + SMB_STS); + +- return i2c_add_adapter(&sis630_adapter); ++ ret = i2c_add_adapter(&sis630_adapter); ++ if (ret) ++ goto release_region; ++ ++ return 0; ++ ++release_region: ++ release_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION); ++ return ret; + } + + static void sis630_remove(struct pci_dev *dev) +-- +2.39.5 + diff --git a/queue-5.10/series b/queue-5.10/series index 35eeeaba9c..6eb9ef1add 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -56,3 +56,12 @@ drm-amd-display-fix-slab-use-after-free-on-hdcp_work.patch qlcnic-fix-memory-leak-issues-in-qlcnic_sriov_common.c.patch drm-gma500-add-null-check-for-pci_gfx_root-in-mid_ge.patch asoc-codecs-wm0010-fix-error-handling-path-in-wm0010.patch +i2c-ali1535-fix-an-error-handling-path-in-ali1535_pr.patch +i2c-ali15x3-fix-an-error-handling-path-in-ali15x3_pr.patch +i2c-sis630-fix-an-error-handling-path-in-sis630_prob.patch +drm-amd-display-check-plane-scaling-against-format-s.patch +drm-amd-display-dc-core-dc_resource-staticify-local-.patch +drm-amd-display-reject-too-small-viewport-size-when-.patch +drm-amd-display-fix-odm-scaling.patch +drm-amd-display-check-for-invalid-input-params-when-.patch +drm-amd-display-fix-null-check-for-pipe_ctx-plane_st.patch