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 | */ |
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: &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, ¶ms); |
132 | compr->funcs->set_fbc_invalidation_triggers(compr, 1); |
133 | |
134 | compr->funcs->enable_fbc(compr, ¶ms); |
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: &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 | |
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(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 | |
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 | |