2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include "dm_services.h"
28 #include "core_types.h"
31 #include "timing_generator.h"
33 /*******************************************************************************
35 ******************************************************************************/
36 #define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000
37 static void update_stream_signal(struct dc_stream_state
*stream
)
40 struct dc_sink
*dc_sink
= stream
->sink
;
42 if (dc_sink
->sink_signal
== SIGNAL_TYPE_NONE
)
43 stream
->signal
= stream
->sink
->link
->connector_signal
;
45 stream
->signal
= dc_sink
->sink_signal
;
47 if (dc_is_dvi_signal(stream
->signal
)) {
48 if (stream
->timing
.pix_clk_khz
> TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST
&&
49 stream
->sink
->sink_signal
!= SIGNAL_TYPE_DVI_SINGLE_LINK
)
50 stream
->signal
= SIGNAL_TYPE_DVI_DUAL_LINK
;
52 stream
->signal
= SIGNAL_TYPE_DVI_SINGLE_LINK
;
56 static void construct(struct dc_stream_state
*stream
,
57 struct dc_sink
*dc_sink_data
)
61 stream
->sink
= dc_sink_data
;
62 stream
->ctx
= stream
->sink
->ctx
;
64 dc_sink_retain(dc_sink_data
);
66 /* Copy audio modes */
67 /* TODO - Remove this translation */
68 for (i
= 0; i
< (dc_sink_data
->edid_caps
.audio_mode_count
); i
++)
70 stream
->audio_info
.modes
[i
].channel_count
= dc_sink_data
->edid_caps
.audio_modes
[i
].channel_count
;
71 stream
->audio_info
.modes
[i
].format_code
= dc_sink_data
->edid_caps
.audio_modes
[i
].format_code
;
72 stream
->audio_info
.modes
[i
].sample_rates
.all
= dc_sink_data
->edid_caps
.audio_modes
[i
].sample_rate
;
73 stream
->audio_info
.modes
[i
].sample_size
= dc_sink_data
->edid_caps
.audio_modes
[i
].sample_size
;
75 stream
->audio_info
.mode_count
= dc_sink_data
->edid_caps
.audio_mode_count
;
76 stream
->audio_info
.audio_latency
= dc_sink_data
->edid_caps
.audio_latency
;
77 stream
->audio_info
.video_latency
= dc_sink_data
->edid_caps
.video_latency
;
79 stream
->audio_info
.display_name
,
80 dc_sink_data
->edid_caps
.display_name
,
81 AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS
);
82 stream
->audio_info
.manufacture_id
= dc_sink_data
->edid_caps
.manufacturer_id
;
83 stream
->audio_info
.product_id
= dc_sink_data
->edid_caps
.product_id
;
84 stream
->audio_info
.flags
.all
= dc_sink_data
->edid_caps
.speaker_flags
;
86 if (dc_sink_data
->dc_container_id
!= NULL
) {
87 struct dc_container_id
*dc_container_id
= dc_sink_data
->dc_container_id
;
89 stream
->audio_info
.port_id
[0] = dc_container_id
->portId
[0];
90 stream
->audio_info
.port_id
[1] = dc_container_id
->portId
[1];
92 /* TODO - WindowDM has implemented,
93 other DMs need Unhardcode port_id */
94 stream
->audio_info
.port_id
[0] = 0x5558859e;
95 stream
->audio_info
.port_id
[1] = 0xd989449;
98 /* EDID CAP translation for HDMI 2.0 */
99 stream
->timing
.flags
.LTE_340MCSC_SCRAMBLE
= dc_sink_data
->edid_caps
.lte_340mcsc_scramble
;
101 stream
->status
.link
= stream
->sink
->link
;
103 update_stream_signal(stream
);
106 static void destruct(struct dc_stream_state
*stream
)
108 dc_sink_release(stream
->sink
);
109 if (stream
->out_transfer_func
!= NULL
) {
110 dc_transfer_func_release(
111 stream
->out_transfer_func
);
112 stream
->out_transfer_func
= NULL
;
116 void dc_stream_retain(struct dc_stream_state
*stream
)
118 kref_get(&stream
->refcount
);
121 static void dc_stream_free(struct kref
*kref
)
123 struct dc_stream_state
*stream
= container_of(kref
, struct dc_stream_state
, refcount
);
129 void dc_stream_release(struct dc_stream_state
*stream
)
131 if (stream
!= NULL
) {
132 kref_put(&stream
->refcount
, dc_stream_free
);
136 struct dc_stream_state
*dc_create_stream_for_sink(
137 struct dc_sink
*sink
)
139 struct dc_stream_state
*stream
;
144 stream
= kzalloc(sizeof(struct dc_stream_state
), GFP_KERNEL
);
148 construct(stream
, sink
);
150 kref_init(&stream
->refcount
);
155 struct dc_stream_status
*dc_stream_get_status(
156 struct dc_stream_state
*stream
)
159 struct dc
*dc
= stream
->ctx
->dc
;
161 for (i
= 0; i
< dc
->current_state
->stream_count
; i
++) {
162 if (stream
== dc
->current_state
->streams
[i
])
163 return &dc
->current_state
->stream_status
[i
];
170 * Update the cursor attributes and set cursor surface address
172 bool dc_stream_set_cursor_attributes(
173 struct dc_stream_state
*stream
,
174 const struct dc_cursor_attributes
*attributes
)
178 struct resource_context
*res_ctx
;
180 if (NULL
== stream
) {
181 dm_error("DC: dc_stream is NULL!\n");
184 if (NULL
== attributes
) {
185 dm_error("DC: attributes is NULL!\n");
189 if (attributes
->address
.quad_part
== 0) {
190 dm_output_to_console("DC: Cursor address is 0!\n");
194 core_dc
= stream
->ctx
->dc
;
195 res_ctx
= &core_dc
->current_state
->res_ctx
;
197 for (i
= 0; i
< MAX_PIPES
; i
++) {
198 struct pipe_ctx
*pipe_ctx
= &res_ctx
->pipe_ctx
[i
];
200 if (pipe_ctx
->stream
!= stream
|| (!pipe_ctx
->plane_res
.xfm
&&
201 !pipe_ctx
->plane_res
.dpp
) || !pipe_ctx
->plane_res
.ipp
)
203 if (pipe_ctx
->top_pipe
&& pipe_ctx
->plane_state
!= pipe_ctx
->top_pipe
->plane_state
)
207 if (pipe_ctx
->plane_res
.ipp
->funcs
->ipp_cursor_set_attributes
!= NULL
)
208 pipe_ctx
->plane_res
.ipp
->funcs
->ipp_cursor_set_attributes(
209 pipe_ctx
->plane_res
.ipp
, attributes
);
211 if (pipe_ctx
->plane_res
.hubp
!= NULL
&&
212 pipe_ctx
->plane_res
.hubp
->funcs
->set_cursor_attributes
!= NULL
)
213 pipe_ctx
->plane_res
.hubp
->funcs
->set_cursor_attributes(
214 pipe_ctx
->plane_res
.hubp
, attributes
);
216 if (pipe_ctx
->plane_res
.mi
!= NULL
&&
217 pipe_ctx
->plane_res
.mi
->funcs
->set_cursor_attributes
!= NULL
)
218 pipe_ctx
->plane_res
.mi
->funcs
->set_cursor_attributes(
219 pipe_ctx
->plane_res
.mi
, attributes
);
222 if (pipe_ctx
->plane_res
.xfm
!= NULL
&&
223 pipe_ctx
->plane_res
.xfm
->funcs
->set_cursor_attributes
!= NULL
)
224 pipe_ctx
->plane_res
.xfm
->funcs
->set_cursor_attributes(
225 pipe_ctx
->plane_res
.xfm
, attributes
);
227 if (pipe_ctx
->plane_res
.dpp
!= NULL
&&
228 pipe_ctx
->plane_res
.dpp
->funcs
->set_cursor_attributes
!= NULL
)
229 pipe_ctx
->plane_res
.dpp
->funcs
->set_cursor_attributes(
230 pipe_ctx
->plane_res
.dpp
, attributes
->color_format
);
233 stream
->cursor_attributes
= *attributes
;
238 bool dc_stream_set_cursor_position(
239 struct dc_stream_state
*stream
,
240 const struct dc_cursor_position
*position
)
244 struct resource_context
*res_ctx
;
246 if (NULL
== stream
) {
247 dm_error("DC: dc_stream is NULL!\n");
251 if (NULL
== position
) {
252 dm_error("DC: cursor position is NULL!\n");
256 core_dc
= stream
->ctx
->dc
;
257 res_ctx
= &core_dc
->current_state
->res_ctx
;
259 for (i
= 0; i
< MAX_PIPES
; i
++) {
260 struct pipe_ctx
*pipe_ctx
= &res_ctx
->pipe_ctx
[i
];
261 struct input_pixel_processor
*ipp
= pipe_ctx
->plane_res
.ipp
;
262 struct mem_input
*mi
= pipe_ctx
->plane_res
.mi
;
263 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
264 struct dpp
*dpp
= pipe_ctx
->plane_res
.dpp
;
265 struct dc_cursor_position pos_cpy
= *position
;
266 struct dc_cursor_mi_param param
= {
267 .pixel_clk_khz
= stream
->timing
.pix_clk_khz
,
268 .ref_clk_khz
= core_dc
->res_pool
->ref_clock_inKhz
,
269 .viewport_x_start
= pipe_ctx
->plane_res
.scl_data
.viewport
.x
,
270 .viewport_width
= pipe_ctx
->plane_res
.scl_data
.viewport
.width
,
271 .h_scale_ratio
= pipe_ctx
->plane_res
.scl_data
.ratios
.horz
274 if (pipe_ctx
->stream
!= stream
||
275 (!pipe_ctx
->plane_res
.mi
&& !pipe_ctx
->plane_res
.hubp
) ||
276 !pipe_ctx
->plane_state
||
277 (!pipe_ctx
->plane_res
.xfm
&& !pipe_ctx
->plane_res
.dpp
) ||
278 !pipe_ctx
->plane_res
.ipp
)
281 if (pipe_ctx
->plane_state
->address
.type
282 == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE
)
283 pos_cpy
.enable
= false;
285 if (pipe_ctx
->top_pipe
&& pipe_ctx
->plane_state
!= pipe_ctx
->top_pipe
->plane_state
)
286 pos_cpy
.enable
= false;
289 if (ipp
!= NULL
&& ipp
->funcs
->ipp_cursor_set_position
!= NULL
)
290 ipp
->funcs
->ipp_cursor_set_position(ipp
, &pos_cpy
, ¶m
);
292 if (mi
!= NULL
&& mi
->funcs
->set_cursor_position
!= NULL
)
293 mi
->funcs
->set_cursor_position(mi
, &pos_cpy
, ¶m
);
298 if (hubp
->funcs
->set_cursor_position
!= NULL
)
299 hubp
->funcs
->set_cursor_position(hubp
, &pos_cpy
, ¶m
);
301 if (dpp
!= NULL
&& dpp
->funcs
->set_cursor_position
!= NULL
)
302 dpp
->funcs
->set_cursor_position(dpp
, &pos_cpy
, ¶m
, hubp
->curs_attr
.width
);
306 stream
->cursor_position
= *position
;
311 uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state
*stream
)
314 struct dc
*core_dc
= stream
->ctx
->dc
;
315 struct resource_context
*res_ctx
=
316 &core_dc
->current_state
->res_ctx
;
318 for (i
= 0; i
< MAX_PIPES
; i
++) {
319 struct timing_generator
*tg
= res_ctx
->pipe_ctx
[i
].stream_res
.tg
;
321 if (res_ctx
->pipe_ctx
[i
].stream
!= stream
)
324 return tg
->funcs
->get_frame_count(tg
);
330 bool dc_stream_get_scanoutpos(const struct dc_stream_state
*stream
,
331 uint32_t *v_blank_start
,
332 uint32_t *v_blank_end
,
333 uint32_t *h_position
,
334 uint32_t *v_position
)
338 struct dc
*core_dc
= stream
->ctx
->dc
;
339 struct resource_context
*res_ctx
=
340 &core_dc
->current_state
->res_ctx
;
342 for (i
= 0; i
< MAX_PIPES
; i
++) {
343 struct timing_generator
*tg
= res_ctx
->pipe_ctx
[i
].stream_res
.tg
;
345 if (res_ctx
->pipe_ctx
[i
].stream
!= stream
)
348 tg
->funcs
->get_scanoutpos(tg
,
363 const struct dc_stream_state
*stream
,
364 struct dal_logger
*dm_logger
,
365 enum dc_log_type log_type
)
368 dm_logger_write(dm_logger
,
370 "core_stream 0x%x: src: %d, %d, %d, %d; dst: %d, %d, %d, %d, colorSpace:%d\n",
380 stream
->output_color_space
);
381 dm_logger_write(dm_logger
,
383 "\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixelencoder:%d, displaycolorDepth:%d\n",
384 stream
->timing
.pix_clk_khz
,
385 stream
->timing
.h_total
,
386 stream
->timing
.v_total
,
387 stream
->timing
.pixel_encoding
,
388 stream
->timing
.display_color_depth
);
389 dm_logger_write(dm_logger
,
391 "\tsink name: %s, serial: %d\n",
392 stream
->sink
->edid_caps
.display_name
,
393 stream
->sink
->edid_caps
.serial_number
);
394 dm_logger_write(dm_logger
,
397 stream
->sink
->link
->link_index
);