]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/drm/amd/display/dc/core/dc_stream.c
drm/amd/display: Rename more dc_surface stuff to plane_state
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / amd / display / dc / core / dc_stream.c
1 /*
2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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 "resource.h"
30 #include "ipp.h"
31 #include "timing_generator.h"
32
33 /*******************************************************************************
34 * Private functions
35 ******************************************************************************/
36
37 static bool construct(struct dc_stream_state *stream,
38 struct dc_sink *dc_sink_data)
39 {
40 uint32_t i = 0;
41
42 stream->sink = dc_sink_data;
43 stream->ctx = stream->sink->ctx;
44 stream->sink = dc_sink_data;
45
46 dc_sink_retain(dc_sink_data);
47
48 /* Copy audio modes */
49 /* TODO - Remove this translation */
50 for (i = 0; i < (dc_sink_data->edid_caps.audio_mode_count); i++)
51 {
52 stream->audio_info.modes[i].channel_count = dc_sink_data->edid_caps.audio_modes[i].channel_count;
53 stream->audio_info.modes[i].format_code = dc_sink_data->edid_caps.audio_modes[i].format_code;
54 stream->audio_info.modes[i].sample_rates.all = dc_sink_data->edid_caps.audio_modes[i].sample_rate;
55 stream->audio_info.modes[i].sample_size = dc_sink_data->edid_caps.audio_modes[i].sample_size;
56 }
57 stream->audio_info.mode_count = dc_sink_data->edid_caps.audio_mode_count;
58 stream->audio_info.audio_latency = dc_sink_data->edid_caps.audio_latency;
59 stream->audio_info.video_latency = dc_sink_data->edid_caps.video_latency;
60 memmove(
61 stream->audio_info.display_name,
62 dc_sink_data->edid_caps.display_name,
63 AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
64 stream->audio_info.manufacture_id = dc_sink_data->edid_caps.manufacturer_id;
65 stream->audio_info.product_id = dc_sink_data->edid_caps.product_id;
66 stream->audio_info.flags.all = dc_sink_data->edid_caps.speaker_flags;
67
68 if (dc_sink_data->dc_container_id != NULL) {
69 struct dc_container_id *dc_container_id = dc_sink_data->dc_container_id;
70
71 stream->audio_info.port_id[0] = dc_container_id->portId[0];
72 stream->audio_info.port_id[1] = dc_container_id->portId[1];
73 } else {
74 /* TODO - WindowDM has implemented,
75 other DMs need Unhardcode port_id */
76 stream->audio_info.port_id[0] = 0x5558859e;
77 stream->audio_info.port_id[1] = 0xd989449;
78 }
79
80 /* EDID CAP translation for HDMI 2.0 */
81 stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble;
82
83 stream->status.link = stream->sink->link;
84 return true;
85 }
86
87 static void destruct(struct dc_stream_state *stream)
88 {
89 dc_sink_release(stream->sink);
90 if (stream->out_transfer_func != NULL) {
91 dc_transfer_func_release(
92 stream->out_transfer_func);
93 stream->out_transfer_func = NULL;
94 }
95 }
96
97 void dc_stream_retain(struct dc_stream_state *stream)
98 {
99
100 ASSERT(stream->ref_count > 0);
101 stream->ref_count++;
102 }
103
104 void dc_stream_release(struct dc_stream_state *stream)
105 {
106
107 if (stream != NULL) {
108 ASSERT(stream->ref_count > 0);
109 stream->ref_count--;
110
111 if (stream->ref_count == 0) {
112 destruct(stream);
113 dm_free(stream);
114 }
115 }
116 }
117
118 struct dc_stream_state *dc_create_stream_for_sink(
119 struct dc_sink *sink)
120 {
121 struct dc_stream_state *stream;
122
123 if (sink == NULL)
124 goto alloc_fail;
125
126 stream = dm_alloc(sizeof(struct dc_stream_state));
127
128 if (NULL == stream)
129 goto alloc_fail;
130
131 if (false == construct(stream, sink))
132 goto construct_fail;
133
134 stream->ref_count++;
135
136 return stream;
137
138 construct_fail:
139 dm_free(stream);
140
141 alloc_fail:
142 return NULL;
143 }
144
145 struct dc_stream_status *dc_stream_get_status(
146 struct dc_stream_state *stream)
147 {
148 uint8_t i;
149 struct core_dc *dc = DC_TO_CORE(stream->ctx->dc);
150
151 for (i = 0; i < dc->current_context->stream_count; i++) {
152 if (stream == dc->current_context->streams[i]) {
153 return &dc->current_context->stream_status[i];
154 }
155 }
156
157 return NULL;
158 }
159
160 /**
161 * Update the cursor attributes and set cursor surface address
162 */
163 bool dc_stream_set_cursor_attributes(
164 const struct dc_stream_state *stream,
165 const struct dc_cursor_attributes *attributes)
166 {
167 int i;
168 struct core_dc *core_dc;
169 struct resource_context *res_ctx;
170
171 if (NULL == stream) {
172 dm_error("DC: dc_stream is NULL!\n");
173 return false;
174 }
175 if (NULL == attributes) {
176 dm_error("DC: attributes is NULL!\n");
177 return false;
178 }
179
180 core_dc = DC_TO_CORE(stream->ctx->dc);
181 res_ctx = &core_dc->current_context->res_ctx;
182
183 for (i = 0; i < MAX_PIPES; i++) {
184 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
185
186 if (pipe_ctx->stream != stream || !pipe_ctx->ipp)
187 continue;
188 if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)
189 continue;
190
191 pipe_ctx->ipp->funcs->ipp_cursor_set_attributes(
192 pipe_ctx->ipp, attributes);
193 }
194
195 return true;
196 }
197
198 bool dc_stream_set_cursor_position(
199 struct dc_stream_state *stream,
200 const struct dc_cursor_position *position)
201 {
202 int i;
203 struct core_dc *core_dc;
204 struct resource_context *res_ctx;
205
206 if (NULL == stream) {
207 dm_error("DC: dc_stream is NULL!\n");
208 return false;
209 }
210
211 if (NULL == position) {
212 dm_error("DC: cursor position is NULL!\n");
213 return false;
214 }
215
216 core_dc = DC_TO_CORE(stream->ctx->dc);
217 res_ctx = &core_dc->current_context->res_ctx;
218
219 for (i = 0; i < MAX_PIPES; i++) {
220 struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
221 struct input_pixel_processor *ipp = pipe_ctx->ipp;
222 struct dc_cursor_position pos_cpy = *position;
223 struct dc_cursor_mi_param param = {
224 .pixel_clk_khz = stream->timing.pix_clk_khz,
225 .ref_clk_khz = core_dc->res_pool->ref_clock_inKhz,
226 .viewport_x_start = pipe_ctx->scl_data.viewport.x,
227 .viewport_width = pipe_ctx->scl_data.viewport.width,
228 .h_scale_ratio = pipe_ctx->scl_data.ratios.horz
229 };
230
231 if (pipe_ctx->stream != stream ||
232 !pipe_ctx->ipp || !pipe_ctx->plane_state)
233 continue;
234
235 if (pipe_ctx->plane_state->address.type
236 == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
237 pos_cpy.enable = false;
238
239 if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)
240 pos_cpy.enable = false;
241
242 ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, &param);
243 }
244
245 return true;
246 }
247
248 uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream)
249 {
250 uint8_t i;
251 struct core_dc *core_dc = DC_TO_CORE(stream->ctx->dc);
252 struct resource_context *res_ctx =
253 &core_dc->current_context->res_ctx;
254
255 for (i = 0; i < MAX_PIPES; i++) {
256 struct timing_generator *tg = res_ctx->pipe_ctx[i].tg;
257
258 if (res_ctx->pipe_ctx[i].stream != stream)
259 continue;
260
261 return tg->funcs->get_frame_count(tg);
262 }
263
264 return 0;
265 }
266
267 bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream,
268 uint32_t *v_blank_start,
269 uint32_t *v_blank_end,
270 uint32_t *h_position,
271 uint32_t *v_position)
272 {
273 uint8_t i;
274 bool ret = false;
275 struct core_dc *core_dc = DC_TO_CORE(stream->ctx->dc);
276 struct resource_context *res_ctx =
277 &core_dc->current_context->res_ctx;
278
279 for (i = 0; i < MAX_PIPES; i++) {
280 struct timing_generator *tg = res_ctx->pipe_ctx[i].tg;
281
282 if (res_ctx->pipe_ctx[i].stream != stream)
283 continue;
284
285 tg->funcs->get_scanoutpos(tg,
286 v_blank_start,
287 v_blank_end,
288 h_position,
289 v_position);
290
291 ret = true;
292 break;
293 }
294
295 return ret;
296 }
297
298
299 void dc_stream_log(
300 const struct dc_stream_state *stream,
301 struct dal_logger *dm_logger,
302 enum dc_log_type log_type)
303 {
304
305 dm_logger_write(dm_logger,
306 log_type,
307 "core_stream 0x%x: src: %d, %d, %d, %d; dst: %d, %d, %d, %d, colorSpace:%d\n",
308 stream,
309 stream->src.x,
310 stream->src.y,
311 stream->src.width,
312 stream->src.height,
313 stream->dst.x,
314 stream->dst.y,
315 stream->dst.width,
316 stream->dst.height,
317 stream->output_color_space);
318 dm_logger_write(dm_logger,
319 log_type,
320 "\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixelencoder:%d, displaycolorDepth:%d\n",
321 stream->timing.pix_clk_khz,
322 stream->timing.h_total,
323 stream->timing.v_total,
324 stream->timing.pixel_encoding,
325 stream->timing.display_color_depth);
326 dm_logger_write(dm_logger,
327 log_type,
328 "\tsink name: %s, serial: %d\n",
329 stream->sink->edid_caps.display_name,
330 stream->sink->edid_caps.serial_number);
331 dm_logger_write(dm_logger,
332 log_type,
333 "\tlink: %d\n",
334 stream->sink->link->link_index);
335 }