xref: /linux/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 #include "dc_spl_translate.h"
6 #include "dcn20/dcn20_dpp.h"
7 #include "dcn32/dcn32_dpp.h"
8 #include "dcn401/dcn401_dpp.h"
9 
10 static struct spl_callbacks dcn2_spl_callbacks = {
11 	.spl_calc_lb_num_partitions = dscl2_spl_calc_lb_num_partitions,
12 };
13 static struct spl_callbacks dcn32_spl_callbacks = {
14 	.spl_calc_lb_num_partitions = dscl32_spl_calc_lb_num_partitions,
15 };
16 static struct spl_callbacks dcn401_spl_callbacks = {
17 	.spl_calc_lb_num_partitions = dscl401_spl_calc_lb_num_partitions,
18 };
19 static struct spl_callbacks dcn50_spl_callbacks = {
20 	.spl_calc_lb_num_partitions = dscl401_spl_calc_lb_num_partitions,
21 };
22 static void populate_splrect_from_rect(struct spl_rect *spl_rect, const struct rect *rect)
23 {
24 	spl_rect->x = rect->x;
25 	spl_rect->y = rect->y;
26 	spl_rect->width = rect->width;
27 	spl_rect->height = rect->height;
28 }
29 static void populate_rect_from_splrect(struct rect *rect, const struct spl_rect *spl_rect)
30 {
31 	rect->x = spl_rect->x;
32 	rect->y = spl_rect->y;
33 	rect->width = spl_rect->width;
34 	rect->height = spl_rect->height;
35 }
36 static void populate_spltaps_from_taps(struct spl_taps *spl_scaling_quality,
37 		const struct scaling_taps *scaling_quality)
38 {
39 	spl_scaling_quality->h_taps_c = scaling_quality->h_taps_c;
40 	spl_scaling_quality->h_taps = scaling_quality->h_taps;
41 	spl_scaling_quality->v_taps_c = scaling_quality->v_taps_c;
42 	spl_scaling_quality->v_taps = scaling_quality->v_taps;
43 	spl_scaling_quality->integer_scaling = scaling_quality->integer_scaling;
44 }
45 static void populate_taps_from_spltaps(struct scaling_taps *scaling_quality,
46 		const struct spl_taps *spl_scaling_quality)
47 {
48 	scaling_quality->h_taps_c = spl_scaling_quality->h_taps_c + 1;
49 	scaling_quality->h_taps = spl_scaling_quality->h_taps + 1;
50 	scaling_quality->v_taps_c = spl_scaling_quality->v_taps_c + 1;
51 	scaling_quality->v_taps = spl_scaling_quality->v_taps + 1;
52 }
53 static void populate_ratios_from_splratios(struct scaling_ratios *ratios,
54 		const struct ratio *spl_ratios)
55 {
56 	ratios->horz = dc_fixpt_from_ux_dy(spl_ratios->h_scale_ratio >> 5, 3, 19);
57 	ratios->vert = dc_fixpt_from_ux_dy(spl_ratios->v_scale_ratio >> 5, 3, 19);
58 	ratios->horz_c = dc_fixpt_from_ux_dy(spl_ratios->h_scale_ratio_c >> 5, 3, 19);
59 	ratios->vert_c = dc_fixpt_from_ux_dy(spl_ratios->v_scale_ratio_c >> 5, 3, 19);
60 }
61 static void populate_inits_from_splinits(struct scl_inits *inits,
62 		const struct init *spl_inits)
63 {
64 	inits->h = dc_fixpt_from_int_dy(spl_inits->h_filter_init_int, spl_inits->h_filter_init_frac >> 5, 0, 19);
65 	inits->v = dc_fixpt_from_int_dy(spl_inits->v_filter_init_int, spl_inits->v_filter_init_frac >> 5, 0, 19);
66 	inits->h_c = dc_fixpt_from_int_dy(spl_inits->h_filter_init_int_c, spl_inits->h_filter_init_frac_c >> 5, 0, 19);
67 	inits->v_c = dc_fixpt_from_int_dy(spl_inits->v_filter_init_int_c, spl_inits->v_filter_init_frac_c >> 5, 0, 19);
68 }
69 static void populate_splformat_from_format(enum spl_pixel_format *spl_pixel_format,
70 					   const enum dc_pixel_format pixel_format)
71 {
72 	if (pixel_format < PIXEL_FORMAT_INVALID)
73 		*spl_pixel_format = (enum spl_pixel_format)pixel_format;
74 	else
75 		*spl_pixel_format = SPL_PIXEL_FORMAT_INVALID;
76 }
77 static void set_linear_light_scaling_preference(const struct dc_plane_state *plane_state, struct spl_in *spl_in)
78 {
79 	if (plane_state != NULL) {
80 		switch (plane_state->scaling_linearity) {
81 		case DC_SCALING_LINEARITY_LINEAR:
82 			spl_in->lls_pref = LLS_PREF_YES;
83 			break;
84 		case DC_SCALING_LINEARITY_SOURCE:
85 			spl_in->lls_pref = LLS_PREF_NO;
86 			break;
87 		default:
88 			spl_in->lls_pref = LLS_PREF_DONT_CARE;
89 			break;
90 		}
91 	} else
92 		spl_in->lls_pref = LLS_PREF_DONT_CARE;
93 }
94 /// @brief Translate SPL input parameters from pipe context
95 /// @param pipe_ctx
96 /// @param spl_in
97 void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl_in *spl_in)
98 {
99 	const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
100 	const struct dc_stream_state *stream = pipe_ctx->stream;
101 	struct rect odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx);
102 
103 	// Assign the function to calculate the number of partitions in the line buffer
104 	// This is used to determine the vtap support
105 	switch (plane_state->ctx->dce_version)	{
106 	case DCN_VERSION_2_0:
107 		spl_in->callbacks = dcn2_spl_callbacks;
108 		break;
109 	case DCN_VERSION_3_2:
110 		spl_in->callbacks = dcn32_spl_callbacks;
111 		break;
112 	case DCN_VERSION_4_01:
113 	case DCN_VERSION_4_2:
114 	case DCN_VERSION_4_2B:
115 		spl_in->callbacks = dcn401_spl_callbacks;
116 		break;
117 	case DCN_VERSION_6_0:
118 		spl_in->callbacks = dcn50_spl_callbacks;
119 		break;
120 	default:
121 		spl_in->callbacks = dcn2_spl_callbacks;
122 	}
123 	// Make format field from spl_in point to plane_res scl_data format
124 	populate_splformat_from_format(&spl_in->basic_in.format, pipe_ctx->plane_res.scl_data.format);
125 	// Make view_format from basic_out point to view_format from stream
126 	spl_in->basic_out.view_format = (enum spl_view_3d)stream->view_format;
127 	// Populate spl input basic input clip rect from plane state clip rect
128 	populate_splrect_from_rect(&spl_in->basic_in.clip_rect, &plane_state->clip_rect);
129 	// Populate spl input basic out src rect from stream src rect
130 	populate_splrect_from_rect(&spl_in->basic_out.src_rect, &stream->src);
131 	// Populate spl input basic out dst rect from stream dst rect
132 	populate_splrect_from_rect(&spl_in->basic_out.dst_rect, &stream->dst);
133 	// Make spl input basic input info rotation field point to plane state rotation
134 	spl_in->basic_in.rotation = (enum spl_rotation_angle)plane_state->rotation;
135 	// Populate spl input basic input src rect from plane state src rect
136 	populate_splrect_from_rect(&spl_in->basic_in.src_rect, &plane_state->src_rect);
137 	// Populate spl input basic input dst rect from plane state dst rect
138 	populate_splrect_from_rect(&spl_in->basic_in.dst_rect, &plane_state->dst_rect);
139 	// Make spl input basic input info horiz mirror field point to plane state horz mirror
140 	spl_in->basic_in.horizontal_mirror = plane_state->horizontal_mirror;
141 
142 	// Calculate horizontal splits and split index
143 	spl_in->basic_in.num_h_slices_recout_width_align.use_recout_width_aligned = false;
144 	spl_in->basic_in.num_h_slices_recout_width_align.num_slices_recout_width.mpc_num_h_slices =
145 		resource_get_mpc_slice_count(pipe_ctx);
146 
147 	if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
148 		spl_in->basic_in.mpc_h_slice_index = 0;
149 	else
150 		spl_in->basic_in.mpc_h_slice_index = resource_get_mpc_slice_index(pipe_ctx);
151 
152 	populate_splrect_from_rect(&spl_in->basic_out.odm_slice_rect, &odm_slice_src);
153 	spl_in->basic_out.odm_combine_factor = 0;
154 	spl_in->odm_slice_index = resource_get_odm_slice_index(pipe_ctx);
155 	// Make spl input basic out info output_size width point to stream h active
156 	spl_in->basic_out.output_size.width =
157 		stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right + pipe_ctx->dsc_padding_params.dsc_hactive_padding;
158 	// Make spl input basic out info output_size height point to v active
159 	spl_in->basic_out.output_size.height =
160 		stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top;
161 	spl_in->basic_out.max_downscale_src_width =
162 			pipe_ctx->stream->ctx->dc->debug.max_downscale_src_width;
163 	spl_in->basic_out.always_scale = pipe_ctx->stream->ctx->dc->debug.always_scale;
164 	// Make spl input basic output info alpha_en field point to plane res scl_data lb_params alpha_en
165 	spl_in->basic_out.alpha_en = pipe_ctx->plane_res.scl_data.lb_params.alpha_en;
166 	spl_in->basic_out.use_two_pixels_per_container = pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
167 	// Make spl input basic input info scaling quality field point to plane state scaling_quality
168 	populate_spltaps_from_taps(&spl_in->scaling_quality, &plane_state->scaling_quality);
169 	// Translate edge adaptive scaler preference
170 	spl_in->prefer_easf = pipe_ctx->stream->ctx->dc->config.prefer_easf;
171 	spl_in->disable_easf = false;
172 	if (pipe_ctx->stream->ctx->dc->debug.force_easf == 1)
173 		spl_in->prefer_easf = false;
174 	else if (pipe_ctx->stream->ctx->dc->debug.force_easf == 2)
175 		spl_in->disable_easf = true;
176 	else if (pipe_ctx->stream->ctx->dc->debug.force_easf == 3)
177 		spl_in->override_easf = true;
178 	/* Translate adaptive sharpening preference */
179 	unsigned int sharpness_setting = pipe_ctx->stream->ctx->dc->debug.force_sharpness;
180 	unsigned int force_sharpness_level = pipe_ctx->stream->ctx->dc->debug.force_sharpness_level;
181 	if (sharpness_setting == SHARPNESS_HW_OFF)
182 		spl_in->adaptive_sharpness.enable = false;
183 	else if (sharpness_setting == SHARPNESS_ZERO) {
184 		spl_in->adaptive_sharpness.enable = true;
185 		spl_in->adaptive_sharpness.sharpness_level = 0;
186 	} else if (sharpness_setting == SHARPNESS_CUSTOM) {
187 		/* SAT: read harpness_range from dc_plane_state */
188 		spl_in->adaptive_sharpness.sharpness_range.sdr_rgb_min = plane_state->sharpness_range.sdr_rgb_min;
189 		spl_in->adaptive_sharpness.sharpness_range.sdr_rgb_max = plane_state->sharpness_range.sdr_rgb_max;
190 		spl_in->adaptive_sharpness.sharpness_range.sdr_rgb_mid = plane_state->sharpness_range.sdr_rgb_mid;
191 		spl_in->adaptive_sharpness.sharpness_range.sdr_yuv_min = plane_state->sharpness_range.sdr_yuv_min;
192 		spl_in->adaptive_sharpness.sharpness_range.sdr_yuv_max = plane_state->sharpness_range.sdr_yuv_max;
193 		spl_in->adaptive_sharpness.sharpness_range.sdr_yuv_mid = plane_state->sharpness_range.sdr_yuv_mid;
194 		spl_in->adaptive_sharpness.sharpness_range.hdr_rgb_min = plane_state->sharpness_range.hdr_rgb_min;
195 		spl_in->adaptive_sharpness.sharpness_range.hdr_rgb_max = plane_state->sharpness_range.hdr_rgb_max;
196 		spl_in->adaptive_sharpness.sharpness_range.hdr_rgb_mid = plane_state->sharpness_range.hdr_rgb_mid;
197 
198 		if (force_sharpness_level > 0) {
199 			if (force_sharpness_level > 10)
200 				force_sharpness_level = 10;
201 			spl_in->adaptive_sharpness.enable = true;
202 			spl_in->adaptive_sharpness.sharpness_level = force_sharpness_level;
203 		} else if (!plane_state->adaptive_sharpness_en) {
204 			spl_in->adaptive_sharpness.enable = false;
205 			spl_in->adaptive_sharpness.sharpness_level = 0;
206 		} else {
207 			spl_in->adaptive_sharpness.enable = true;
208 			spl_in->adaptive_sharpness.sharpness_level = plane_state->sharpness_level;
209 		}
210 	}
211 	// Translate linear light scaling preference
212 	if (pipe_ctx->stream->ctx->dc->debug.force_lls > 0)
213 		spl_in->lls_pref = pipe_ctx->stream->ctx->dc->debug.force_lls;
214 	else
215 		if ((plane_state->ctx->dce_version == DCN_VERSION_4_01) ||
216 			(plane_state->ctx->dce_version == DCN_VERSION_4_2) ||
217 			(plane_state->ctx->dce_version == DCN_VERSION_4_2B))
218 			spl_in->lls_pref = LLS_PREF_DONT_CARE;
219 		else
220 			set_linear_light_scaling_preference(plane_state, spl_in);
221 	/* Translate upsampling mode*/
222 	spl_in->upsp_mode = pipe_ctx->plane_res.scl_data.upsp;
223 	/* Translate chroma subsampling offset ( cositing ) */
224 	if (pipe_ctx->stream->ctx->dc->debug.force_cositing)
225 		spl_in->basic_in.cositing = pipe_ctx->stream->ctx->dc->debug.force_cositing - 1;
226 	else
227 		spl_in->basic_in.cositing = plane_state->cositing;
228 	/* Translate transfer function */
229 	spl_in->basic_in.tf_type = (enum spl_transfer_func_type) plane_state->in_transfer_func.type;
230 	spl_in->basic_in.tf_predefined_type = (enum spl_transfer_func_predefined) plane_state->in_transfer_func.tf;
231 
232 	spl_in->h_active = pipe_ctx->plane_res.scl_data.h_active;
233 	spl_in->v_active = pipe_ctx->plane_res.scl_data.v_active;
234 
235 	spl_in->sharpen_policy = (enum sharpen_policy)plane_state->adaptive_sharpness_policy;
236 	spl_in->debug.scale_to_sharpness_policy =
237 		(enum scale_to_sharpness_policy)pipe_ctx->stream->ctx->dc->debug.scale_to_sharpness_policy;
238 
239 	/* Check if it is stream is in fullscreen and if its HDR.
240 	 * Use this to determine sharpness levels
241 	 */
242 	spl_in->is_fullscreen = pipe_ctx->stream->sharpening_required;
243 	spl_in->is_hdr_on = dm_helpers_is_hdr_on(pipe_ctx->stream->ctx, pipe_ctx->stream);
244 	spl_in->sdr_white_level_nits = plane_state->sdr_white_level_nits;
245 }
246 
247 /// @brief Translate SPL output parameters to pipe context
248 /// @param pipe_ctx
249 /// @param spl_out
250 void translate_SPL_out_params_to_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl_out *spl_out)
251 {
252 	// Make scaler data recout point to spl output field recout
253 	populate_rect_from_splrect(&pipe_ctx->plane_res.scl_data.recout, &spl_out->dscl_prog_data->recout);
254 	// Make scaler data ratios point to spl output field ratios
255 	populate_ratios_from_splratios(&pipe_ctx->plane_res.scl_data.ratios, &spl_out->dscl_prog_data->ratios);
256 	// Make scaler data viewport point to spl output field viewport
257 	populate_rect_from_splrect(&pipe_ctx->plane_res.scl_data.viewport, &spl_out->dscl_prog_data->viewport);
258 	// Make scaler data viewport_c point to spl output field viewport_c
259 	populate_rect_from_splrect(&pipe_ctx->plane_res.scl_data.viewport_c, &spl_out->dscl_prog_data->viewport_c);
260 	// Make scaler data taps point to spl output field scaling taps
261 	populate_taps_from_spltaps(&pipe_ctx->plane_res.scl_data.taps, &spl_out->dscl_prog_data->taps);
262 	// Make scaler data init point to spl output field init
263 	populate_inits_from_splinits(&pipe_ctx->plane_res.scl_data.inits, &spl_out->dscl_prog_data->init);
264 }
265