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_hwseq.h"
33#include "dce100/dce100_hwseq.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 */
50static 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 */
114static 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: &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
143static 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 ******************************************************************************/
181static 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
197static 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
232static 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: &color);
241 else
242 color_space_to_black_color(dc,
243 colorspace: pipe_ctx->stream->output_color_space,
244 black_color: &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
269static void
270dce60_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(hwss: dc->hwseq, inst: mi->inst, enable: 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
381static 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
421void 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

source code of linux/drivers/gpu/drm/amd/display/dc/dce60/dce60_hw_sequencer.c