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>
31 #include <drm/drm_probe_helper.h>
32 #include <drm/amdgpu_drm.h>
33 #include <drm/drm_edid.h>
35 #include "dm_services.h"
38 #include "amdgpu_dm.h"
39 #include "amdgpu_dm_irq.h"
40 #include "amdgpu_dm_mst_types.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
);
104 edid_caps
->audio_mode_count
= sad_count
< DC_MAX_AUDIO_DESC_COUNT
? sad_count
: DC_MAX_AUDIO_DESC_COUNT
;
105 for (i
= 0; i
< edid_caps
->audio_mode_count
; ++i
) {
106 struct cea_sad
*sad
= &sads
[i
];
108 edid_caps
->audio_modes
[i
].format_code
= sad
->format
;
109 edid_caps
->audio_modes
[i
].channel_count
= sad
->channels
+ 1;
110 edid_caps
->audio_modes
[i
].sample_rate
= sad
->freq
;
111 edid_caps
->audio_modes
[i
].sample_size
= sad
->byte2
;
114 sadb_count
= drm_edid_to_speaker_allocation((struct edid
*) edid
->raw_edid
, &sadb
);
116 if (sadb_count
< 0) {
117 DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sadb_count
);
122 edid_caps
->speaker_flags
= sadb
[0];
124 edid_caps
->speaker_flags
= DEFAULT_SPEAKER_LOCATION
;
132 static void get_payload_table(
133 struct amdgpu_dm_connector
*aconnector
,
134 struct dp_mst_stream_allocation_table
*proposed_table
)
137 struct drm_dp_mst_topology_mgr
*mst_mgr
=
138 &aconnector
->mst_port
->mst_mgr
;
140 mutex_lock(&mst_mgr
->payload_lock
);
142 proposed_table
->stream_count
= 0;
144 /* number of active streams */
145 for (i
= 0; i
< mst_mgr
->max_payloads
; i
++) {
146 if (mst_mgr
->payloads
[i
].num_slots
== 0)
147 break; /* end of vcp_id table */
149 ASSERT(mst_mgr
->payloads
[i
].payload_state
!=
150 DP_PAYLOAD_DELETE_LOCAL
);
152 if (mst_mgr
->payloads
[i
].payload_state
== DP_PAYLOAD_LOCAL
||
153 mst_mgr
->payloads
[i
].payload_state
==
156 struct dp_mst_stream_allocation
*sa
=
157 &proposed_table
->stream_allocations
[
158 proposed_table
->stream_count
];
160 sa
->slot_count
= mst_mgr
->payloads
[i
].num_slots
;
161 sa
->vcp_id
= mst_mgr
->proposed_vcpis
[i
]->vcpi
;
162 proposed_table
->stream_count
++;
166 mutex_unlock(&mst_mgr
->payload_lock
);
169 void dm_helpers_dp_update_branch_info(
170 struct dc_context
*ctx
,
171 const struct dc_link
*link
)
175 * Writes payload allocation table in immediate downstream device.
177 bool dm_helpers_dp_mst_write_payload_allocation_table(
178 struct dc_context
*ctx
,
179 const struct dc_stream_state
*stream
,
180 struct dp_mst_stream_allocation_table
*proposed_table
,
183 struct amdgpu_dm_connector
*aconnector
;
184 struct dm_connector_state
*dm_conn_state
;
185 struct drm_dp_mst_topology_mgr
*mst_mgr
;
186 struct drm_dp_mst_port
*mst_port
;
189 aconnector
= (struct amdgpu_dm_connector
*)stream
->dm_stream_context
;
190 /* Accessing the connector state is required for vcpi_slots allocation
191 * and directly relies on behaviour in commit check
192 * that blocks before commit guaranteeing that the state
193 * is not gonna be swapped while still in use in commit tail */
195 if (!aconnector
|| !aconnector
->mst_port
)
198 dm_conn_state
= to_dm_connector_state(aconnector
->base
.state
);
200 mst_mgr
= &aconnector
->mst_port
->mst_mgr
;
202 if (!mst_mgr
->mst_state
)
205 mst_port
= aconnector
->port
;
209 ret
= drm_dp_mst_allocate_vcpi(mst_mgr
, mst_port
,
211 dm_conn_state
->vcpi_slots
);
216 drm_dp_mst_reset_vcpi_slots(mst_mgr
, mst_port
);
219 ret
= drm_dp_update_payload_part1(mst_mgr
);
221 /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
222 * AUX message. The sequence is slot 1-63 allocated sequence for each
223 * stream. AMD ASIC stream slot allocation should follow the same
224 * sequence. copy DRM MST allocation to dc */
226 get_payload_table(aconnector
, proposed_table
);
235 * poll pending down reply
237 void dm_helpers_dp_mst_poll_pending_down_reply(
238 struct dc_context
*ctx
,
239 const struct dc_link
*link
)
243 * Clear payload allocation table before enable MST DP link.
245 void dm_helpers_dp_mst_clear_payload_allocation_table(
246 struct dc_context
*ctx
,
247 const struct dc_link
*link
)
251 * Polls for ACT (allocation change trigger) handled and sends
252 * ALLOCATE_PAYLOAD message.
254 enum act_return_status
dm_helpers_dp_mst_poll_for_allocation_change_trigger(
255 struct dc_context
*ctx
,
256 const struct dc_stream_state
*stream
)
258 struct amdgpu_dm_connector
*aconnector
;
259 struct drm_dp_mst_topology_mgr
*mst_mgr
;
262 aconnector
= (struct amdgpu_dm_connector
*)stream
->dm_stream_context
;
264 if (!aconnector
|| !aconnector
->mst_port
)
267 mst_mgr
= &aconnector
->mst_port
->mst_mgr
;
269 if (!mst_mgr
->mst_state
)
272 ret
= drm_dp_check_act_status(mst_mgr
);
280 bool dm_helpers_dp_mst_send_payload_allocation(
281 struct dc_context
*ctx
,
282 const struct dc_stream_state
*stream
,
285 struct amdgpu_dm_connector
*aconnector
;
286 struct drm_dp_mst_topology_mgr
*mst_mgr
;
287 struct drm_dp_mst_port
*mst_port
;
290 aconnector
= (struct amdgpu_dm_connector
*)stream
->dm_stream_context
;
292 if (!aconnector
|| !aconnector
->mst_port
)
295 mst_port
= aconnector
->port
;
297 mst_mgr
= &aconnector
->mst_port
->mst_mgr
;
299 if (!mst_mgr
->mst_state
)
302 ret
= drm_dp_update_payload_part2(mst_mgr
);
308 drm_dp_mst_deallocate_vcpi(mst_mgr
, mst_port
);
313 void dm_dtn_log_begin(struct dc_context
*ctx
,
314 struct dc_log_buffer_ctx
*log_ctx
)
316 static const char msg
[] = "[dtn begin]\n";
323 dm_dtn_log_append_v(ctx
, log_ctx
, "%s", msg
);
326 void dm_dtn_log_append_v(struct dc_context
*ctx
,
327 struct dc_log_buffer_ctx
*log_ctx
,
328 const char *msg
, ...)
335 /* No context, redirect to dmesg. */
336 struct va_format vaf
;
342 pr_info("%pV", &vaf
);
348 /* Measure the output. */
350 n
= vsnprintf(NULL
, 0, msg
, args
);
356 /* Reallocate the string buffer as needed. */
357 total
= log_ctx
->pos
+ n
+ 1;
359 if (total
> log_ctx
->size
) {
360 char *buf
= (char *)kvcalloc(total
, sizeof(char), GFP_KERNEL
);
363 memcpy(buf
, log_ctx
->buf
, log_ctx
->pos
);
367 log_ctx
->size
= total
;
374 /* Write the formatted string to the log buffer. */
377 log_ctx
->buf
+ log_ctx
->pos
,
378 log_ctx
->size
- log_ctx
->pos
,
387 void dm_dtn_log_end(struct dc_context
*ctx
,
388 struct dc_log_buffer_ctx
*log_ctx
)
390 static const char msg
[] = "[dtn end]\n";
397 dm_dtn_log_append_v(ctx
, log_ctx
, "%s", msg
);
400 bool dm_helpers_dp_mst_start_top_mgr(
401 struct dc_context
*ctx
,
402 const struct dc_link
*link
,
405 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
408 DRM_ERROR("Failed to found connector for link!");
413 DRM_INFO("DM_MST: Differing MST start on aconnector: %p [id: %d]\n",
414 aconnector
, aconnector
->base
.base
.id
);
418 DRM_INFO("DM_MST: starting TM on aconnector: %p [id: %d]\n",
419 aconnector
, aconnector
->base
.base
.id
);
421 return (drm_dp_mst_topology_mgr_set_mst(&aconnector
->mst_mgr
, true) == 0);
424 void dm_helpers_dp_mst_stop_top_mgr(
425 struct dc_context
*ctx
,
426 const struct dc_link
*link
)
428 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
431 DRM_ERROR("Failed to found connector for link!");
435 DRM_INFO("DM_MST: stopping TM on aconnector: %p [id: %d]\n",
436 aconnector
, aconnector
->base
.base
.id
);
438 if (aconnector
->mst_mgr
.mst_state
== true)
439 drm_dp_mst_topology_mgr_set_mst(&aconnector
->mst_mgr
, false);
442 bool dm_helpers_dp_read_dpcd(
443 struct dc_context
*ctx
,
444 const struct dc_link
*link
,
450 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
453 DRM_ERROR("Failed to found connector for link!");
457 return drm_dp_dpcd_read(&aconnector
->dm_dp_aux
.aux
, address
,
461 bool dm_helpers_dp_write_dpcd(
462 struct dc_context
*ctx
,
463 const struct dc_link
*link
,
468 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
471 DRM_ERROR("Failed to found connector for link!");
475 return drm_dp_dpcd_write(&aconnector
->dm_dp_aux
.aux
,
476 address
, (uint8_t *)data
, size
) > 0;
479 bool dm_helpers_submit_i2c(
480 struct dc_context
*ctx
,
481 const struct dc_link
*link
,
482 struct i2c_command
*cmd
)
484 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
485 struct i2c_msg
*msgs
;
487 int num
= cmd
->number_of_payloads
;
491 DRM_ERROR("Failed to found connector for link!");
495 msgs
= kcalloc(num
, sizeof(struct i2c_msg
), GFP_KERNEL
);
500 for (i
= 0; i
< num
; i
++) {
501 msgs
[i
].flags
= cmd
->payloads
[i
].write
? 0 : I2C_M_RD
;
502 msgs
[i
].addr
= cmd
->payloads
[i
].address
;
503 msgs
[i
].len
= cmd
->payloads
[i
].length
;
504 msgs
[i
].buf
= cmd
->payloads
[i
].data
;
507 result
= i2c_transfer(&aconnector
->i2c
->base
, msgs
, num
) == num
;
513 bool dm_helpers_dp_write_dsc_enable(
514 struct dc_context
*ctx
,
515 const struct dc_stream_state
*stream
,
519 uint8_t enable_dsc
= enable
? 1 : 0;
520 struct amdgpu_dm_connector
*aconnector
;
525 if (stream
->signal
== SIGNAL_TYPE_DISPLAY_PORT_MST
) {
526 aconnector
= (struct amdgpu_dm_connector
*)stream
->dm_stream_context
;
528 if (!aconnector
->dsc_aux
)
531 return (drm_dp_dpcd_write(aconnector
->dsc_aux
, DP_DSC_ENABLE
, &enable_dsc
, 1) >= 0);
534 if (stream
->signal
== SIGNAL_TYPE_DISPLAY_PORT
)
535 return dm_helpers_dp_write_dpcd(ctx
, stream
->link
, DP_DSC_ENABLE
, &enable_dsc
, 1);
540 bool dm_helpers_is_dp_sink_present(struct dc_link
*link
)
542 bool dp_sink_present
;
543 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
546 BUG_ON("Failed to found connector for link!");
550 mutex_lock(&aconnector
->dm_dp_aux
.aux
.hw_mutex
);
551 dp_sink_present
= dc_link_is_dp_sink_present(link
);
552 mutex_unlock(&aconnector
->dm_dp_aux
.aux
.hw_mutex
);
553 return dp_sink_present
;
556 enum dc_edid_status
dm_helpers_read_local_edid(
557 struct dc_context
*ctx
,
558 struct dc_link
*link
,
559 struct dc_sink
*sink
)
561 struct amdgpu_dm_connector
*aconnector
= link
->priv
;
562 struct i2c_adapter
*ddc
;
564 enum dc_edid_status edid_status
;
568 ddc
= &aconnector
->dm_dp_aux
.aux
.ddc
;
570 ddc
= &aconnector
->i2c
->base
;
572 /* some dongles read edid incorrectly the first time,
573 * do check sum and retry to make sure read correct edid.
577 edid
= drm_get_edid(&aconnector
->base
, ddc
);
580 return EDID_NO_RESPONSE
;
582 sink
->dc_edid
.length
= EDID_LENGTH
* (edid
->extensions
+ 1);
583 memmove(sink
->dc_edid
.raw_edid
, (uint8_t *)edid
, sink
->dc_edid
.length
);
585 /* We don't need the original edid anymore */
588 edid_status
= dm_helpers_parse_edid_caps(
593 } while (edid_status
== EDID_BAD_CHECKSUM
&& --retry
> 0);
595 if (edid_status
!= EDID_OK
)
596 DRM_ERROR("EDID err: %d, on connector: %s",
598 aconnector
->base
.name
);
599 if (link
->aux_mode
) {
600 union test_request test_request
= { {0} };
601 union test_response test_response
= { {0} };
603 dm_helpers_dp_read_dpcd(ctx
,
607 sizeof(union test_request
));
609 if (!test_request
.bits
.EDID_READ
)
612 test_response
.bits
.EDID_CHECKSUM_WRITE
= 1;
614 dm_helpers_dp_write_dpcd(ctx
,
616 DP_TEST_EDID_CHECKSUM
,
617 &sink
->dc_edid
.raw_edid
[sink
->dc_edid
.length
-1],
620 dm_helpers_dp_write_dpcd(ctx
,
624 sizeof(test_response
));
631 void dm_set_dcn_clocks(struct dc_context
*ctx
, struct dc_clocks
*clks
)
633 /* TODO: something */