2 * Copyright 2015 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 <linux/string.h>
27 #include <linux/acpi.h>
28 #include <linux/version.h>
29 #include <linux/i2c.h>
32 #include <drm/drm_crtc_helper.h>
33 #include <drm/amdgpu_drm.h>
34 #include <drm/drm_edid.h>
36 #include "dm_services.h"
39 #include "amdgpu_dm.h"
40 #include "amdgpu_dm_irq.h"
42 #include "dm_helpers.h"
44 /* dm_helpers_parse_edid_caps
48 * @edid: [in] pointer to edid
49 * edid_caps: [in] pointer to edid caps
53 enum dc_edid_status
dm_helpers_parse_edid_caps(
54 struct dc_context
*ctx
,
55 const struct dc_edid
*edid
,
56 struct dc_edid_caps
*edid_caps
)
58 struct edid
*edid_buf
= (struct edid
*) edid
->raw_edid
;
66 enum dc_edid_status result
= EDID_OK
;
68 if (!edid_caps
|| !edid
)
69 return EDID_BAD_INPUT
;
71 if (!drm_edid_is_valid(edid_buf
))
72 result
= EDID_BAD_CHECKSUM
;
74 edid_caps
->manufacturer_id
= (uint16_t) edid_buf
->mfg_id
[0] |
75 ((uint16_t) edid_buf
->mfg_id
[1])<<8;
76 edid_caps
->product_id
= (uint16_t) edid_buf
->prod_code
[0] |
77 ((uint16_t) edid_buf
->prod_code
[1])<<8;
78 edid_caps
->serial_number
= edid_buf
->serial
;
79 edid_caps
->manufacture_week
= edid_buf
->mfg_week
;
80 edid_caps
->manufacture_year
= edid_buf
->mfg_year
;
82 /* One of the four detailed_timings stores the monitor name. It's
83 * stored in an array of length 13. */
84 for (i
= 0; i
< 4; i
++) {
85 if (edid_buf
->detailed_timings
[i
].data
.other_data
.type
== 0xfc) {
86 while (j
< 13 && edid_buf
->detailed_timings
[i
].data
.other_data
.data
.str
.str
[j
]) {
87 if (edid_buf
->detailed_timings
[i
].data
.other_data
.data
.str
.str
[j
] == '\n')
90 edid_caps
->display_name
[j
] =
91 edid_buf
->detailed_timings
[i
].data
.other_data
.data
.str
.str
[j
];
97 edid_caps
->edid_hdmi
= drm_detect_hdmi_monitor(
98 (struct edid
*) edid
->raw_edid
);
100 sad_count
= drm_edid_to_sad((struct edid
*) edid
->raw_edid
, &sads
);
101 if (sad_count
<= 0) {
102 DRM_INFO("SADs count is: %d, don't need to read it\n",
107 edid_caps
->audio_mode_count
= sad_count
< DC_MAX_AUDIO_DESC_COUNT
? sad_count
: DC_MAX_AUDIO_DESC_COUNT
;
108 for (i
= 0; i
< edid_caps
->audio_mode_count
; ++i
) {
109 struct cea_sad
*sad
= &sads
[i
];
111 edid_caps
->audio_modes
[i
].format_code
= sad
->format
;
112 edid_caps
->audio_modes
[i
].channel_count
= sad
->channels
+ 1;
113 edid_caps
->audio_modes
[i
].sample_rate
= sad
->freq
;
114 edid_caps
->audio_modes
[i
].sample_size
= sad
->byte2
;
117 sadb_count
= drm_edid_to_speaker_allocation((struct edid
*) edid
->raw_edid
, &sadb
);
119 if (sadb_count
< 0) {
120 DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sadb_count
);
125 edid_caps
->speaker_flags
= sadb
[0];
127 edid_caps
->speaker_flags
= DEFAULT_SPEAKER_LOCATION
;
135 static void get_payload_table(
136 struct amdgpu_dm_connector
*aconnector
,
137 struct dp_mst_stream_allocation_table
*proposed_table
)
140 struct drm_dp_mst_topology_mgr
*mst_mgr
=
141 &aconnector
->mst_port
->mst_mgr
;
143 mutex_lock(&mst_mgr
->payload_lock
);
145 proposed_table
->stream_count
= 0;
147 /* number of active streams */
148 for (i
= 0; i
< mst_mgr
->max_payloads
; i
++) {
149 if (mst_mgr
->payloads
[i
].num_slots
== 0)
150 break; /* end of vcp_id table */
152 ASSERT(mst_mgr
->payloads
[i
].payload_state
!=
153 DP_PAYLOAD_DELETE_LOCAL
);
155 if (mst_mgr
->payloads
[i
].payload_state
== DP_PAYLOAD_LOCAL
||
156 mst_mgr
->payloads
[i
].payload_state
==
159 struct dp_mst_stream_allocation
*sa
=
160 &proposed_table
->stream_allocations
[
161 proposed_table
->stream_count
];
163 sa
->slot_count
= mst_mgr
->payloads
[i
].num_slots
;
164 sa
->vcp_id
= mst_mgr
->proposed_vcpis
[i
]->vcpi
;
165 proposed_table
->stream_count
++;
169 mutex_unlock(&mst_mgr
->payload_lock
);
172 void dm_helpers_dp_update_branch_info(
173 struct dc_context
*ctx
,
174 const struct dc_link
*link
)
178 * Writes payload allocation table in immediate downstream device.
180 bool dm_helpers_dp_mst_write_payload_allocation_table(
181 struct dc_context
*ctx
,
182 const struct dc_stream_state
*stream
,
183 struct dp_mst_stream_allocation_table
*proposed_table
,
186 struct amdgpu_dm_connector
*aconnector
;
187 struct drm_dp_mst_topology_mgr
*mst_mgr
;
188 struct drm_dp_mst_port
*mst_port
;
195 aconnector
= (struct amdgpu_dm_connector
*)stream
->dm_stream_context
;
197 if (!aconnector
|| !aconnector
->mst_port
)
200 mst_mgr
= &aconnector
->mst_port
->mst_mgr
;
202 if (!mst_mgr
->mst_state
)
205 mst_port
= aconnector
->port
;
208 clock
= stream
->timing
.pix_clk_100hz
/ 10;
210 switch (stream
->timing
.display_color_depth
) {
212 case COLOR_DEPTH_666
:
215 case COLOR_DEPTH_888
:
218 case COLOR_DEPTH_101010
:
221 case COLOR_DEPTH_121212
:
224 case COLOR_DEPTH_141414
:
227 case COLOR_DEPTH_161616
:
237 /* TODO need to know link rate */
239 pbn
= drm_dp_calc_pbn_mode(clock
, bpp
);
241 slots
= drm_dp_find_vcpi_slots(mst_mgr
, pbn
);
242 ret
= drm_dp_mst_allocate_vcpi(mst_mgr
, mst_port
, pbn
, slots
);
248 drm_dp_mst_reset_vcpi_slots(mst_mgr
, mst_port
);
251 ret
= drm_dp_update_payload_part1(mst_mgr
);
253 /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
254 * AUX message. The sequence is slot 1-63 allocated sequence for each
255 * stream. AMD ASIC stream slot allocation should follow the same
256 * sequence. copy DRM MST allocation to dc */
258 get_payload_table(aconnector
, proposed_table
);
267 * poll pending down reply before clear payload allocation table
269 void dm_helpers_dp_mst_poll_pending_down_reply(
270 struct dc_context
*ctx
,
271 const struct dc_link
*link
)
275 * Clear payload allocation table before enable MST DP link.
277 void dm_helpers_dp_mst_clear_payload_allocation_table(
278 struct dc_context
*ctx
,
279 const struct dc_link
*link
)
283 * Polls for ACT (allocation change trigger) handled and sends
284 * ALLOCATE_PAYLOAD message.
286 bool dm_helpers_dp_mst_poll_for_allocation_change_trigger(
287 struct dc_context
*ctx
,
288 const struct dc_stream_state
*stream
)
290 struct amdgpu_dm_connector
*aconnector
;
291 struct drm_dp_mst_topology_mgr
*mst_mgr
;
294 aconnector
= (struct amdgpu_dm_connector
*)stream
->dm_stream_context
;
296 if (!aconnector
|| !aconnector
->mst_port
)
299 mst_mgr
= &aconnector
->mst_port
->mst_mgr
;
301 if (!mst_mgr
->mst_state
)
304 ret
= drm_dp_check_act_status(mst_mgr
);
312 bool dm_helpers_dp_mst_send_payload_allocation(
313 struct dc_context
*ctx
,
314 const struct dc_stream_state
*stream
,
317 struct amdgpu_dm_connector
*aconnector
;
318 struct drm_dp_mst_topology_mgr
*mst_mgr
;
319 struct drm_dp_mst_port
*mst_port
;
322 aconnector
= (struct amdgpu_dm_connector
*)stream
->dm_stream_context
;
324 if (!aconnector
|| !aconnector
->mst_port
)
327 mst_port
= aconnector
->port
;
329 mst_mgr
= &aconnector
->mst_port
->mst_mgr
;
331 if (!mst_mgr
->mst_state
)
334 ret
= drm_dp_update_payload_part2(mst_mgr
);
340 drm_dp_mst_deallocate_vcpi(mst_mgr
, mst_port
);
345 void dm_dtn_log_begin(struct dc_context
*ctx
,
346 struct dc_log_buffer_ctx
*log_ctx
)
348 static const char msg
[] = "[dtn begin]\n";
355 dm_dtn_log_append_v(ctx
, log_ctx
, "%s", msg
);
358 void dm_dtn_log_append_v(struct dc_context
*ctx
,
359 struct dc_log_buffer_ctx
*log_ctx
,
360 const char *msg
, ...)
367 /* No context, redirect to dmesg. */
368 struct va_format vaf
;
374 pr_info("%pV", &vaf
);
380 /* Measure the output. */
382 n
= vsnprintf(NULL
, 0, msg
, args
);
388 /* Reallocate the string buffer as needed. */
389 total
= log_ctx
->pos
+ n
+ 1;
391 if (total
> log_ctx
->size
) {
392 char *buf
= (char *)kvcalloc(total
, sizeof(char), GFP_KERNEL
);
395 memcpy(buf
, log_ctx
->buf
, log_ctx
->pos
);
399 log_ctx
->size
= total
;
406 /* Write the formatted string to the log buffer. */
409 log_ctx
->buf
+ log_ctx
->pos
,
410 log_ctx
->size
- log_ctx
->pos
,
419 void dm_dtn_log_end(struct dc_context
*ctx
,
420 struct dc_log_buffer_ctx
*log_ctx
)
422 static const char msg
[] = "[dtn end]\n";
429 dm_dtn_log_append_v(ctx
, log_ctx
, "%s", msg
);
432 bool dm_helpers_dp_mst_start_top_mgr(
433 struct dc_context
*ctx
,
434 const struct dc_link
*link
,
437 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
440 DRM_ERROR("Failed to found connector for link!");
445 DRM_INFO("DM_MST: Differing MST start on aconnector: %p [id: %d]\n",
446 aconnector
, aconnector
->base
.base
.id
);
450 DRM_INFO("DM_MST: starting TM on aconnector: %p [id: %d]\n",
451 aconnector
, aconnector
->base
.base
.id
);
453 return (drm_dp_mst_topology_mgr_set_mst(&aconnector
->mst_mgr
, true) == 0);
456 void dm_helpers_dp_mst_stop_top_mgr(
457 struct dc_context
*ctx
,
458 const struct dc_link
*link
)
460 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
463 DRM_ERROR("Failed to found connector for link!");
467 DRM_INFO("DM_MST: stopping TM on aconnector: %p [id: %d]\n",
468 aconnector
, aconnector
->base
.base
.id
);
470 if (aconnector
->mst_mgr
.mst_state
== true)
471 drm_dp_mst_topology_mgr_set_mst(&aconnector
->mst_mgr
, false);
474 bool dm_helpers_dp_read_dpcd(
475 struct dc_context
*ctx
,
476 const struct dc_link
*link
,
482 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
485 DRM_ERROR("Failed to found connector for link!");
489 return drm_dp_dpcd_read(&aconnector
->dm_dp_aux
.aux
, address
,
493 bool dm_helpers_dp_write_dpcd(
494 struct dc_context
*ctx
,
495 const struct dc_link
*link
,
500 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
503 DRM_ERROR("Failed to found connector for link!");
507 return drm_dp_dpcd_write(&aconnector
->dm_dp_aux
.aux
,
508 address
, (uint8_t *)data
, size
) > 0;
511 bool dm_helpers_submit_i2c(
512 struct dc_context
*ctx
,
513 const struct dc_link
*link
,
514 struct i2c_command
*cmd
)
516 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
517 struct i2c_msg
*msgs
;
519 int num
= cmd
->number_of_payloads
;
523 DRM_ERROR("Failed to found connector for link!");
527 msgs
= kcalloc(num
, sizeof(struct i2c_msg
), GFP_KERNEL
);
532 for (i
= 0; i
< num
; i
++) {
533 msgs
[i
].flags
= cmd
->payloads
[i
].write
? 0 : I2C_M_RD
;
534 msgs
[i
].addr
= cmd
->payloads
[i
].address
;
535 msgs
[i
].len
= cmd
->payloads
[i
].length
;
536 msgs
[i
].buf
= cmd
->payloads
[i
].data
;
539 result
= i2c_transfer(&aconnector
->i2c
->base
, msgs
, num
) == num
;
546 bool dm_helpers_is_dp_sink_present(struct dc_link
*link
)
548 bool dp_sink_present
;
549 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
552 BUG_ON("Failed to found connector for link!");
556 mutex_lock(&aconnector
->dm_dp_aux
.aux
.hw_mutex
);
557 dp_sink_present
= dc_link_is_dp_sink_present(link
);
558 mutex_unlock(&aconnector
->dm_dp_aux
.aux
.hw_mutex
);
559 return dp_sink_present
;
562 enum dc_edid_status
dm_helpers_read_local_edid(
563 struct dc_context
*ctx
,
564 struct dc_link
*link
,
565 struct dc_sink
*sink
)
567 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
568 struct i2c_adapter
*ddc
;
570 enum dc_edid_status edid_status
;
574 ddc
= &aconnector
->dm_dp_aux
.aux
.ddc
;
576 ddc
= &aconnector
->i2c
->base
;
578 /* some dongles read edid incorrectly the first time,
579 * do check sum and retry to make sure read correct edid.
583 edid
= drm_get_edid(&aconnector
->base
, ddc
);
586 return EDID_NO_RESPONSE
;
588 sink
->dc_edid
.length
= EDID_LENGTH
* (edid
->extensions
+ 1);
589 memmove(sink
->dc_edid
.raw_edid
, (uint8_t *)edid
, sink
->dc_edid
.length
);
591 /* We don't need the original edid anymore */
594 edid_status
= dm_helpers_parse_edid_caps(
599 } while (edid_status
== EDID_BAD_CHECKSUM
&& --retry
> 0);
601 if (edid_status
!= EDID_OK
)
602 DRM_ERROR("EDID err: %d, on connector: %s",
604 aconnector
->base
.name
);
605 if (link
->aux_mode
) {
606 union test_request test_request
= { {0} };
607 union test_response test_response
= { {0} };
609 dm_helpers_dp_read_dpcd(ctx
,
613 sizeof(union test_request
));
615 if (!test_request
.bits
.EDID_READ
)
618 test_response
.bits
.EDID_CHECKSUM_WRITE
= 1;
620 dm_helpers_dp_write_dpcd(ctx
,
622 DP_TEST_EDID_CHECKSUM
,
623 &sink
->dc_edid
.raw_edid
[sink
->dc_edid
.length
-1],
626 dm_helpers_dp_write_dpcd(ctx
,
630 sizeof(test_response
));
637 void dm_set_dcn_clocks(struct dc_context
*ctx
, struct dc_clocks
*clks
)
639 /* TODO: something */