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
)
39 if (stream
->output_signal
== SIGNAL_TYPE_NONE
) {
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 stream
->signal
= stream
->output_signal
;
50 if (dc_is_dvi_signal(stream
->signal
)) {
51 if (stream
->timing
.pix_clk_khz
> TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST
&&
52 stream
->sink
->sink_signal
!= SIGNAL_TYPE_DVI_SINGLE_LINK
)
53 stream
->signal
= SIGNAL_TYPE_DVI_DUAL_LINK
;
55 stream
->signal
= SIGNAL_TYPE_DVI_SINGLE_LINK
;
59 static void construct(struct dc_stream_state
*stream
,
60 struct dc_sink
*dc_sink_data
)
64 stream
->sink
= dc_sink_data
;
65 stream
->ctx
= stream
->sink
->ctx
;
67 dc_sink_retain(dc_sink_data
);
69 /* Copy audio modes */
70 /* TODO - Remove this translation */
71 for (i
= 0; i
< (dc_sink_data
->edid_caps
.audio_mode_count
); i
++)
73 stream
->audio_info
.modes
[i
].channel_count
= dc_sink_data
->edid_caps
.audio_modes
[i
].channel_count
;
74 stream
->audio_info
.modes
[i
].format_code
= dc_sink_data
->edid_caps
.audio_modes
[i
].format_code
;
75 stream
->audio_info
.modes
[i
].sample_rates
.all
= dc_sink_data
->edid_caps
.audio_modes
[i
].sample_rate
;
76 stream
->audio_info
.modes
[i
].sample_size
= dc_sink_data
->edid_caps
.audio_modes
[i
].sample_size
;
78 stream
->audio_info
.mode_count
= dc_sink_data
->edid_caps
.audio_mode_count
;
79 stream
->audio_info
.audio_latency
= dc_sink_data
->edid_caps
.audio_latency
;
80 stream
->audio_info
.video_latency
= dc_sink_data
->edid_caps
.video_latency
;
82 stream
->audio_info
.display_name
,
83 dc_sink_data
->edid_caps
.display_name
,
84 AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS
);
85 stream
->audio_info
.manufacture_id
= dc_sink_data
->edid_caps
.manufacturer_id
;
86 stream
->audio_info
.product_id
= dc_sink_data
->edid_caps
.product_id
;
87 stream
->audio_info
.flags
.all
= dc_sink_data
->edid_caps
.speaker_flags
;
89 if (dc_sink_data
->dc_container_id
!= NULL
) {
90 struct dc_container_id
*dc_container_id
= dc_sink_data
->dc_container_id
;
92 stream
->audio_info
.port_id
[0] = dc_container_id
->portId
[0];
93 stream
->audio_info
.port_id
[1] = dc_container_id
->portId
[1];
95 /* TODO - WindowDM has implemented,
96 other DMs need Unhardcode port_id */
97 stream
->audio_info
.port_id
[0] = 0x5558859e;
98 stream
->audio_info
.port_id
[1] = 0xd989449;
101 /* EDID CAP translation for HDMI 2.0 */
102 stream
->timing
.flags
.LTE_340MCSC_SCRAMBLE
= dc_sink_data
->edid_caps
.lte_340mcsc_scramble
;
104 stream
->status
.link
= stream
->sink
->link
;
106 update_stream_signal(stream
);
109 static void destruct(struct dc_stream_state
*stream
)
111 dc_sink_release(stream
->sink
);
112 if (stream
->out_transfer_func
!= NULL
) {
113 dc_transfer_func_release(
114 stream
->out_transfer_func
);
115 stream
->out_transfer_func
= NULL
;
119 void dc_stream_retain(struct dc_stream_state
*stream
)
121 kref_get(&stream
->refcount
);
124 static void dc_stream_free(struct kref
*kref
)
126 struct dc_stream_state
*stream
= container_of(kref
, struct dc_stream_state
, refcount
);
132 void dc_stream_release(struct dc_stream_state
*stream
)
134 if (stream
!= NULL
) {
135 kref_put(&stream
->refcount
, dc_stream_free
);
139 struct dc_stream_state
*dc_create_stream_for_sink(
140 struct dc_sink
*sink
)
142 struct dc_stream_state
*stream
;
147 stream
= kzalloc(sizeof(struct dc_stream_state
), GFP_KERNEL
);
151 construct(stream
, sink
);
153 kref_init(&stream
->refcount
);
158 struct dc_stream_status
*dc_stream_get_status(
159 struct dc_stream_state
*stream
)
162 struct dc
*dc
= stream
->ctx
->dc
;
164 for (i
= 0; i
< dc
->current_state
->stream_count
; i
++) {
165 if (stream
== dc
->current_state
->streams
[i
])
166 return &dc
->current_state
->stream_status
[i
];
173 * Update the cursor attributes and set cursor surface address
175 bool dc_stream_set_cursor_attributes(
176 struct dc_stream_state
*stream
,
177 const struct dc_cursor_attributes
*attributes
)
181 struct resource_context
*res_ctx
;
183 if (NULL
== stream
) {
184 dm_error("DC: dc_stream is NULL!\n");
187 if (NULL
== attributes
) {
188 dm_error("DC: attributes is NULL!\n");
192 if (attributes
->address
.quad_part
== 0) {
193 dm_output_to_console("DC: Cursor address is 0!\n");
197 core_dc
= stream
->ctx
->dc
;
198 res_ctx
= &core_dc
->current_state
->res_ctx
;
200 for (i
= 0; i
< MAX_PIPES
; i
++) {
201 struct pipe_ctx
*pipe_ctx
= &res_ctx
->pipe_ctx
[i
];
203 if (pipe_ctx
->stream
!= stream
|| (!pipe_ctx
->plane_res
.xfm
&& !pipe_ctx
->plane_res
.dpp
))
205 if (pipe_ctx
->top_pipe
&& pipe_ctx
->plane_state
!= pipe_ctx
->top_pipe
->plane_state
)
209 if (pipe_ctx
->plane_res
.ipp
->funcs
->ipp_cursor_set_attributes
!= NULL
)
210 pipe_ctx
->plane_res
.ipp
->funcs
->ipp_cursor_set_attributes(
211 pipe_ctx
->plane_res
.ipp
, attributes
);
213 if (pipe_ctx
->plane_res
.hubp
!= NULL
&&
214 pipe_ctx
->plane_res
.hubp
->funcs
->set_cursor_attributes
!= NULL
)
215 pipe_ctx
->plane_res
.hubp
->funcs
->set_cursor_attributes(
216 pipe_ctx
->plane_res
.hubp
, attributes
);
218 if (pipe_ctx
->plane_res
.mi
!= NULL
&&
219 pipe_ctx
->plane_res
.mi
->funcs
->set_cursor_attributes
!= NULL
)
220 pipe_ctx
->plane_res
.mi
->funcs
->set_cursor_attributes(
221 pipe_ctx
->plane_res
.mi
, attributes
);
224 if (pipe_ctx
->plane_res
.xfm
!= NULL
&&
225 pipe_ctx
->plane_res
.xfm
->funcs
->set_cursor_attributes
!= NULL
)
226 pipe_ctx
->plane_res
.xfm
->funcs
->set_cursor_attributes(
227 pipe_ctx
->plane_res
.xfm
, attributes
);
229 if (pipe_ctx
->plane_res
.dpp
!= NULL
&&
230 pipe_ctx
->plane_res
.dpp
->funcs
->set_cursor_attributes
!= NULL
)
231 pipe_ctx
->plane_res
.dpp
->funcs
->set_cursor_attributes(
232 pipe_ctx
->plane_res
.dpp
, attributes
);
235 stream
->cursor_attributes
= *attributes
;
240 bool dc_stream_set_cursor_position(
241 struct dc_stream_state
*stream
,
242 const struct dc_cursor_position
*position
)
246 struct resource_context
*res_ctx
;
248 if (NULL
== stream
) {
249 dm_error("DC: dc_stream is NULL!\n");
253 if (NULL
== position
) {
254 dm_error("DC: cursor position is NULL!\n");
258 core_dc
= stream
->ctx
->dc
;
259 res_ctx
= &core_dc
->current_state
->res_ctx
;
261 for (i
= 0; i
< MAX_PIPES
; i
++) {
262 struct pipe_ctx
*pipe_ctx
= &res_ctx
->pipe_ctx
[i
];
263 struct input_pixel_processor
*ipp
= pipe_ctx
->plane_res
.ipp
;
264 struct mem_input
*mi
= pipe_ctx
->plane_res
.mi
;
265 struct hubp
*hubp
= pipe_ctx
->plane_res
.hubp
;
266 struct transform
*xfm
= pipe_ctx
->plane_res
.xfm
;
267 struct dpp
*dpp
= pipe_ctx
->plane_res
.dpp
;
268 struct dc_cursor_position pos_cpy
= *position
;
269 struct dc_cursor_mi_param param
= {
270 .pixel_clk_khz
= stream
->timing
.pix_clk_khz
,
271 .ref_clk_khz
= core_dc
->res_pool
->ref_clock_inKhz
,
272 .viewport_x_start
= pipe_ctx
->plane_res
.scl_data
.viewport
.x
,
273 .viewport_width
= pipe_ctx
->plane_res
.scl_data
.viewport
.width
,
274 .h_scale_ratio
= pipe_ctx
->plane_res
.scl_data
.ratios
.horz
277 if (pipe_ctx
->stream
!= stream
||
278 (!pipe_ctx
->plane_res
.mi
&& !pipe_ctx
->plane_res
.hubp
) ||
279 !pipe_ctx
->plane_state
||
280 (!pipe_ctx
->plane_res
.xfm
&& !pipe_ctx
->plane_res
.dpp
))
283 if (pipe_ctx
->plane_state
->address
.type
284 == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE
)
285 pos_cpy
.enable
= false;
287 if (pipe_ctx
->top_pipe
&& pipe_ctx
->plane_state
!= pipe_ctx
->top_pipe
->plane_state
)
288 pos_cpy
.enable
= false;
291 if (ipp
!=NULL
&& ipp
->funcs
->ipp_cursor_set_position
!= NULL
)
292 ipp
->funcs
->ipp_cursor_set_position(ipp
, &pos_cpy
, ¶m
);
294 if (mi
!= NULL
&& mi
->funcs
->set_cursor_position
!= NULL
)
295 mi
->funcs
->set_cursor_position(mi
, &pos_cpy
, ¶m
);
297 if (hubp
!= NULL
&& hubp
->funcs
->set_cursor_position
!= NULL
)
298 hubp
->funcs
->set_cursor_position(hubp
, &pos_cpy
, ¶m
);
300 if (xfm
!= NULL
&& xfm
->funcs
->set_cursor_position
!= NULL
)
301 xfm
->funcs
->set_cursor_position(xfm
, &pos_cpy
, ¶m
, hubp
->curs_attr
.width
);
303 if (dpp
!= NULL
&& dpp
->funcs
->set_cursor_position
!= NULL
)
304 dpp
->funcs
->set_cursor_position(dpp
, &pos_cpy
, ¶m
, hubp
->curs_attr
.width
);
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
);