1 /*
2  * Copyright 2020 Mauro Rossi <issor.oruam@gmail.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 
26 #include "dm_services.h"
27 #include "dc.h"
28 #include "core_types.h"
29 #include "dce60_hw_sequencer.h"
30 
31 #include "dce/dce_hwseq.h"
32 #include "dce110/dce110_hw_sequencer.h"
33 #include "dce100/dce100_hw_sequencer.h"
34 
35 /* include DCE6 register header files */
36 #include "dce/dce_6_0_d.h"
37 #include "dce/dce_6_0_sh_mask.h"
38 
39 #define DC_LOGGER_INIT()
40 
41 /*******************************************************************************
42  * Private definitions
43  ******************************************************************************/
44 
45 /***************************PIPE_CONTROL***********************************/
46 
47 /*
48  *  Check if FBC can be enabled
49  */
50 static bool dce60_should_enable_fbc(struct dc *dc,
51 		struct dc_state *context,
52 		uint32_t *pipe_idx)
53 {
54 	uint32_t i;
55 	struct pipe_ctx *pipe_ctx = NULL;
56 	struct resource_context *res_ctx = &context->res_ctx;
57 	unsigned int underlay_idx = dc->res_pool->underlay_pipe_index;
58 
59 
60 	ASSERT(dc->fbc_compressor);
61 
62 	/* FBC memory should be allocated */
63 	if (!dc->ctx->fbc_gpu_addr)
64 		return false;
65 
66 	/* Only supports single display */
67 	if (context->stream_count != 1)
68 		return false;
69 
70 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
71 		if (res_ctx->pipe_ctx[i].stream) {
72 
73 			pipe_ctx = &res_ctx->pipe_ctx[i];
74 
75 			if (!pipe_ctx)
76 				continue;
77 
78 			/* fbc not applicable on underlay pipe */
79 			if (pipe_ctx->pipe_idx != underlay_idx) {
80 				*pipe_idx = i;
81 				break;
82 			}
83 		}
84 	}
85 
86 	if (i == dc->res_pool->pipe_count)
87 		return false;
88 
89 	if (!pipe_ctx->stream->link)
90 		return false;
91 
92 	/* Only supports eDP */
93 	if (pipe_ctx->stream->link->connector_signal != SIGNAL_TYPE_EDP)
94 		return false;
95 
96 	/* PSR should not be enabled */
97 	if (pipe_ctx->stream->link->psr_settings.psr_feature_enabled)
98 		return false;
99 
100 	/* Nothing to compress */
101 	if (!pipe_ctx->plane_state)
102 		return false;
103 
104 	/* Only for non-linear tiling */
105 	if (pipe_ctx->plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL)
106 		return false;
107 
108 	return true;
109 }
110 
111 /*
112  *  Enable FBC
113  */
114 static void dce60_enable_fbc(
115 		struct dc *dc,
116 		struct dc_state *context)
117 {
118 	uint32_t pipe_idx = 0;
119 
120 	if (dce60_should_enable_fbc(dc, context, &pipe_idx)) {
121 		/* Program GRPH COMPRESSED ADDRESS and PITCH */
122 		struct compr_addr_and_pitch_params params = {0, 0, 0};
123 		struct compressor *compr = dc->fbc_compressor;
124 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
125 
126 		params.source_view_width = pipe_ctx->stream->timing.h_addressable;
127 		params.source_view_height = pipe_ctx->stream->timing.v_addressable;
128 		params.inst = pipe_ctx->stream_res.tg->inst;
129 		compr->compr_surface_address.quad_part = dc->ctx->fbc_gpu_addr;
130 
131 		compr->funcs->surface_address_and_pitch(compr, &params);
132 		compr->funcs->set_fbc_invalidation_triggers(compr, 1);
133 
134 		compr->funcs->enable_fbc(compr, &params);
135 	}
136 }
137 
138 
139 /*******************************************************************************
140  * Front End programming
141  ******************************************************************************/
142 
143 static void dce60_set_default_colors(struct pipe_ctx *pipe_ctx)
144 {
145 	struct default_adjustment default_adjust = { 0 };
146 
147 	default_adjust.force_hw_default = false;
148 	default_adjust.in_color_space = pipe_ctx->plane_state->color_space;
149 	default_adjust.out_color_space = pipe_ctx->stream->output_color_space;
150 	default_adjust.csc_adjust_type = GRAPHICS_CSC_ADJUST_TYPE_SW;
151 	default_adjust.surface_pixel_format = pipe_ctx->plane_res.scl_data.format;
152 
153 	/* display color depth */
154 	default_adjust.color_depth =
155 		pipe_ctx->stream->timing.display_color_depth;
156 
157 	/* Lb color depth */
158 	default_adjust.lb_color_depth = pipe_ctx->plane_res.scl_data.lb_params.depth;
159 
160 	pipe_ctx->plane_res.xfm->funcs->opp_set_csc_default(
161 					pipe_ctx->plane_res.xfm, &default_adjust);
162 }
163 
164 /*******************************************************************************
165  * In order to turn on surface we will program
166  * CRTC
167  *
168  * DCE6 has no bottom_pipe and no Blender HW
169  * We need to set 'blank_target' to false in order to turn on the display
170  *
171  * |-----------|------------|---------|
172  * |curr pipe  | set_blank  |         |
173  * |Surface    |blank_target|  CRCT   |
174  * |visibility |  argument  |         |
175  * |-----------|------------|---------|
176  * |    off    |   true     | blank   |
177  * |    on     |   false    | unblank |
178  * |-----------|------------|---------|
179  *
180  ******************************************************************************/
181 static void dce60_program_surface_visibility(const struct dc *dc,
182 		struct pipe_ctx *pipe_ctx)
183 {
184 	bool blank_target = false;
185 
186 	/* DCE6 has no bottom_pipe and no Blender HW */
187 
188 	if (!pipe_ctx->plane_state->visible)
189 		blank_target = true;
190 
191 	/* DCE6 skip dce_set_blender_mode() but then proceed to 'unblank' CRTC */
192 	pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, blank_target);
193 
194 }
195 
196 
197 static void dce60_get_surface_visual_confirm_color(const struct pipe_ctx *pipe_ctx,
198 		struct tg_color *color)
199 {
200 	uint32_t color_value = MAX_TG_COLOR_VALUE * (4 - pipe_ctx->stream_res.tg->inst) / 4;
201 
202 	switch (pipe_ctx->plane_res.scl_data.format) {
203 	case PIXEL_FORMAT_ARGB8888:
204 		/* set boarder color to red */
205 		color->color_r_cr = color_value;
206 		break;
207 
208 	case PIXEL_FORMAT_ARGB2101010:
209 		/* set boarder color to blue */
210 		color->color_b_cb = color_value;
211 		break;
212 	case PIXEL_FORMAT_420BPP8:
213 		/* set boarder color to green */
214 		color->color_g_y = color_value;
215 		break;
216 	case PIXEL_FORMAT_420BPP10:
217 		/* set boarder color to yellow */
218 		color->color_g_y = color_value;
219 		color->color_r_cr = color_value;
220 		break;
221 	case PIXEL_FORMAT_FP16:
222 		/* set boarder color to white */
223 		color->color_r_cr = color_value;
224 		color->color_b_cb = color_value;
225 		color->color_g_y = color_value;
226 		break;
227 	default:
228 		break;
229 	}
230 }
231 
232 static void dce60_program_scaler(const struct dc *dc,
233 		const struct pipe_ctx *pipe_ctx)
234 {
235 	struct tg_color color = {0};
236 
237 	/* DCE6 skips DCN TOFPGA check for transform_set_pixel_storage_depth == NULL */
238 
239 	if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE)
240 		dce60_get_surface_visual_confirm_color(pipe_ctx, &color);
241 	else
242 		color_space_to_black_color(dc,
243 				pipe_ctx->stream->output_color_space,
244 				&color);
245 
246 	pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth(
247 		pipe_ctx->plane_res.xfm,
248 		pipe_ctx->plane_res.scl_data.lb_params.depth,
249 		&pipe_ctx->stream->bit_depth_params);
250 
251 	if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) {
252 		/*
253 		 * The way 420 is packed, 2 channels carry Y component, 1 channel
254 		 * alternate between Cb and Cr, so both channels need the pixel
255 		 * value for Y
256 		 */
257 		if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
258 			color.color_r_cr = color.color_g_y;
259 
260 		pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color(
261 				pipe_ctx->stream_res.tg,
262 				&color);
263 	}
264 
265 	pipe_ctx->plane_res.xfm->funcs->transform_set_scaler(pipe_ctx->plane_res.xfm,
266 		&pipe_ctx->plane_res.scl_data);
267 }
268 
269 static void
270 dce60_program_front_end_for_pipe(
271 		struct dc *dc, struct pipe_ctx *pipe_ctx)
272 {
273 	struct mem_input *mi = pipe_ctx->plane_res.mi;
274 	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
275 	struct xfm_grph_csc_adjustment adjust;
276 	struct out_csc_color_matrix tbl_entry;
277 	unsigned int i;
278 	struct dce_hwseq *hws = dc->hwseq;
279 
280 	DC_LOGGER_INIT();
281 	memset(&tbl_entry, 0, sizeof(tbl_entry));
282 
283 	memset(&adjust, 0, sizeof(adjust));
284 	adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
285 
286 	dce_enable_fe_clock(dc->hwseq, mi->inst, true);
287 
288 	dce60_set_default_colors(pipe_ctx);
289 	if (pipe_ctx->stream->csc_color_matrix.enable_adjustment
290 			== true) {
291 		tbl_entry.color_space =
292 			pipe_ctx->stream->output_color_space;
293 
294 		for (i = 0; i < 12; i++)
295 			tbl_entry.regval[i] =
296 			pipe_ctx->stream->csc_color_matrix.matrix[i];
297 
298 		pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment
299 				(pipe_ctx->plane_res.xfm, &tbl_entry);
300 	}
301 
302 	if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
303 		adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
304 
305 		for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
306 			adjust.temperature_matrix[i] =
307 				pipe_ctx->stream->gamut_remap_matrix.matrix[i];
308 	}
309 
310 	pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust);
311 
312 	pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
313 
314 	dce60_program_scaler(dc, pipe_ctx);
315 
316 	mi->funcs->mem_input_program_surface_config(
317 			mi,
318 			plane_state->format,
319 			&plane_state->tiling_info,
320 			&plane_state->plane_size,
321 			plane_state->rotation,
322 			NULL,
323 			false);
324 	if (mi->funcs->set_blank)
325 		mi->funcs->set_blank(mi, pipe_ctx->plane_state->visible);
326 
327 	if (dc->config.gpu_vm_support)
328 		mi->funcs->mem_input_program_pte_vm(
329 				pipe_ctx->plane_res.mi,
330 				plane_state->format,
331 				&plane_state->tiling_info,
332 				plane_state->rotation);
333 
334 	/* Moved programming gamma from dc to hwss */
335 	if (pipe_ctx->plane_state->update_flags.bits.full_update ||
336 			pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
337 			pipe_ctx->plane_state->update_flags.bits.gamma_change)
338 		hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
339 
340 	if (pipe_ctx->plane_state->update_flags.bits.full_update)
341 		hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
342 
343 	DC_LOG_SURFACE(
344 			"Pipe:%d %p: addr hi:0x%x, "
345 			"addr low:0x%x, "
346 			"src: %d, %d, %d,"
347 			" %d; dst: %d, %d, %d, %d;"
348 			"clip: %d, %d, %d, %d\n",
349 			pipe_ctx->pipe_idx,
350 			(void *) pipe_ctx->plane_state,
351 			pipe_ctx->plane_state->address.grph.addr.high_part,
352 			pipe_ctx->plane_state->address.grph.addr.low_part,
353 			pipe_ctx->plane_state->src_rect.x,
354 			pipe_ctx->plane_state->src_rect.y,
355 			pipe_ctx->plane_state->src_rect.width,
356 			pipe_ctx->plane_state->src_rect.height,
357 			pipe_ctx->plane_state->dst_rect.x,
358 			pipe_ctx->plane_state->dst_rect.y,
359 			pipe_ctx->plane_state->dst_rect.width,
360 			pipe_ctx->plane_state->dst_rect.height,
361 			pipe_ctx->plane_state->clip_rect.x,
362 			pipe_ctx->plane_state->clip_rect.y,
363 			pipe_ctx->plane_state->clip_rect.width,
364 			pipe_ctx->plane_state->clip_rect.height);
365 
366 	DC_LOG_SURFACE(
367 			"Pipe %d: width, height, x, y\n"
368 			"viewport:%d, %d, %d, %d\n"
369 			"recout:  %d, %d, %d, %d\n",
370 			pipe_ctx->pipe_idx,
371 			pipe_ctx->plane_res.scl_data.viewport.width,
372 			pipe_ctx->plane_res.scl_data.viewport.height,
373 			pipe_ctx->plane_res.scl_data.viewport.x,
374 			pipe_ctx->plane_res.scl_data.viewport.y,
375 			pipe_ctx->plane_res.scl_data.recout.width,
376 			pipe_ctx->plane_res.scl_data.recout.height,
377 			pipe_ctx->plane_res.scl_data.recout.x,
378 			pipe_ctx->plane_res.scl_data.recout.y);
379 }
380 
381 static void dce60_apply_ctx_for_surface(
382 		struct dc *dc,
383 		const struct dc_stream_state *stream,
384 		int num_planes,
385 		struct dc_state *context)
386 {
387 	int i;
388 
389 	if (num_planes == 0)
390 		return;
391 
392 	if (dc->fbc_compressor)
393 		dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
394 
395 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
396 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
397 
398 		if (pipe_ctx->stream != stream)
399 			continue;
400 
401 		/* Need to allocate mem before program front end for Fiji */
402 		pipe_ctx->plane_res.mi->funcs->allocate_mem_input(
403 				pipe_ctx->plane_res.mi,
404 				pipe_ctx->stream->timing.h_total,
405 				pipe_ctx->stream->timing.v_total,
406 				pipe_ctx->stream->timing.pix_clk_100hz / 10,
407 				context->stream_count);
408 
409 		dce60_program_front_end_for_pipe(dc, pipe_ctx);
410 
411 		dc->hwss.update_plane_addr(dc, pipe_ctx);
412 
413 		dce60_program_surface_visibility(dc, pipe_ctx);
414 
415 	}
416 
417 	if (dc->fbc_compressor)
418 		dce60_enable_fbc(dc, context);
419 }
420 
421 void dce60_hw_sequencer_construct(struct dc *dc)
422 {
423 	dce110_hw_sequencer_construct(dc);
424 
425 	dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating;
426 	dc->hwss.apply_ctx_for_surface = dce60_apply_ctx_for_surface;
427 	dc->hwss.cursor_lock = dce60_pipe_control_lock;
428 	dc->hwss.pipe_control_lock = dce60_pipe_control_lock;
429 	dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth;
430 	dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth;
431 }
432 
433