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"
41 #include "amdgpu_dm_types.h"
43 #include "dm_helpers.h"
45 /* dm_helpers_parse_edid_caps
49 * @edid: [in] pointer to edid
50 * edid_caps: [in] pointer to edid caps
54 enum dc_edid_status dm_helpers_parse_edid_caps(
55 struct dc_context *ctx,
56 const struct dc_edid *edid,
57 struct dc_edid_caps *edid_caps)
59 struct edid *edid_buf = (struct edid *) edid->raw_edid;
67 enum dc_edid_status result = EDID_OK;
69 if (!edid_caps || !edid)
70 return EDID_BAD_INPUT;
72 if (!drm_edid_is_valid(edid_buf))
73 result = EDID_BAD_CHECKSUM;
75 edid_caps->manufacturer_id = (uint16_t) edid_buf->mfg_id[0] |
76 ((uint16_t) edid_buf->mfg_id[1])<<8;
77 edid_caps->product_id = (uint16_t) edid_buf->prod_code[0] |
78 ((uint16_t) edid_buf->prod_code[1])<<8;
79 edid_caps->serial_number = edid_buf->serial;
80 edid_caps->manufacture_week = edid_buf->mfg_week;
81 edid_caps->manufacture_year = edid_buf->mfg_year;
83 /* One of the four detailed_timings stores the monitor name. It's
84 * stored in an array of length 13. */
85 for (i = 0; i < 4; i++) {
86 if (edid_buf->detailed_timings[i].data.other_data.type == 0xfc) {
87 while (j < 13 && edid_buf->detailed_timings[i].data.other_data.data.str.str[j]) {
88 if (edid_buf->detailed_timings[i].data.other_data.data.str.str[j] == '\n')
91 edid_caps->display_name[j] =
92 edid_buf->detailed_timings[i].data.other_data.data.str.str[j];
98 edid_caps->edid_hdmi = drm_detect_hdmi_monitor(
99 (struct edid *) edid->raw_edid);
101 sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
102 if (sad_count <= 0) {
103 DRM_INFO("SADs count is: %d, don't need to read it\n",
108 edid_caps->audio_mode_count = sad_count < DC_MAX_AUDIO_DESC_COUNT ? sad_count : DC_MAX_AUDIO_DESC_COUNT;
109 for (i = 0; i < edid_caps->audio_mode_count; ++i) {
110 struct cea_sad *sad = &sads[i];
112 edid_caps->audio_modes[i].format_code = sad->format;
113 edid_caps->audio_modes[i].channel_count = sad->channels;
114 edid_caps->audio_modes[i].sample_rate = sad->freq;
115 edid_caps->audio_modes[i].sample_size = sad->byte2;
118 sadb_count = drm_edid_to_speaker_allocation((struct edid *) edid->raw_edid, &sadb);
120 if (sadb_count < 0) {
121 DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sadb_count);
126 edid_caps->speaker_flags = sadb[0];
128 edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
136 static void get_payload_table(
137 struct amdgpu_connector *aconnector,
138 struct dp_mst_stream_allocation_table *proposed_table)
141 struct drm_dp_mst_topology_mgr *mst_mgr =
142 &aconnector->mst_port->mst_mgr;
144 mutex_lock(&mst_mgr->payload_lock);
146 proposed_table->stream_count = 0;
148 /* number of active streams */
149 for (i = 0; i < mst_mgr->max_payloads; i++) {
150 if (mst_mgr->payloads[i].num_slots == 0)
151 break; /* end of vcp_id table */
153 ASSERT(mst_mgr->payloads[i].payload_state !=
154 DP_PAYLOAD_DELETE_LOCAL);
156 if (mst_mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL ||
157 mst_mgr->payloads[i].payload_state ==
160 struct dp_mst_stream_allocation *sa =
161 &proposed_table->stream_allocations[
162 proposed_table->stream_count];
164 sa->slot_count = mst_mgr->payloads[i].num_slots;
165 sa->vcp_id = mst_mgr->proposed_vcpis[i]->vcpi;
166 proposed_table->stream_count++;
170 mutex_unlock(&mst_mgr->payload_lock);
174 * Writes payload allocation table in immediate downstream device.
176 bool dm_helpers_dp_mst_write_payload_allocation_table(
177 struct dc_context *ctx,
178 const struct dc_stream *stream,
179 struct dp_mst_stream_allocation_table *proposed_table,
182 struct amdgpu_connector *aconnector;
183 struct drm_dp_mst_topology_mgr *mst_mgr;
184 struct drm_dp_mst_port *mst_port;
191 aconnector = stream->sink->priv;
193 if (!aconnector || !aconnector->mst_port)
196 mst_mgr = &aconnector->mst_port->mst_mgr;
198 if (!mst_mgr->mst_state)
201 mst_port = aconnector->port;
204 clock = stream->timing.pix_clk_khz;
206 switch (stream->timing.display_color_depth) {
208 case COLOR_DEPTH_666:
211 case COLOR_DEPTH_888:
214 case COLOR_DEPTH_101010:
217 case COLOR_DEPTH_121212:
220 case COLOR_DEPTH_141414:
223 case COLOR_DEPTH_161616:
233 /* TODO need to know link rate */
235 pbn = drm_dp_calc_pbn_mode(clock, bpp);
237 slots = drm_dp_find_vcpi_slots(mst_mgr, pbn);
238 ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, pbn, slots);
244 drm_dp_mst_reset_vcpi_slots(mst_mgr, mst_port);
247 ret = drm_dp_update_payload_part1(mst_mgr);
249 /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
250 * AUX message. The sequence is slot 1-63 allocated sequence for each
251 * stream. AMD ASIC stream slot allocation should follow the same
252 * sequence. copy DRM MST allocation to dc */
254 get_payload_table(aconnector, proposed_table);
263 * Polls for ACT (allocation change trigger) handled and sends
264 * ALLOCATE_PAYLOAD message.
266 bool dm_helpers_dp_mst_poll_for_allocation_change_trigger(
267 struct dc_context *ctx,
268 const struct dc_stream *stream)
270 struct amdgpu_connector *aconnector;
271 struct drm_dp_mst_topology_mgr *mst_mgr;
274 aconnector = stream->sink->priv;
276 if (!aconnector || !aconnector->mst_port)
279 mst_mgr = &aconnector->mst_port->mst_mgr;
281 if (!mst_mgr->mst_state)
284 ret = drm_dp_check_act_status(mst_mgr);
292 bool dm_helpers_dp_mst_send_payload_allocation(
293 struct dc_context *ctx,
294 const struct dc_stream *stream,
297 struct amdgpu_connector *aconnector;
298 struct drm_dp_mst_topology_mgr *mst_mgr;
299 struct drm_dp_mst_port *mst_port;
302 aconnector = stream->sink->priv;
304 if (!aconnector || !aconnector->mst_port)
307 mst_port = aconnector->port;
309 mst_mgr = &aconnector->mst_port->mst_mgr;
311 if (!mst_mgr->mst_state)
314 ret = drm_dp_update_payload_part2(mst_mgr);
320 drm_dp_mst_deallocate_vcpi(mst_mgr, mst_port);
325 bool dm_helpers_dp_mst_start_top_mgr(
326 struct dc_context *ctx,
327 const struct dc_link *link,
330 struct amdgpu_connector *aconnector = link->priv;
333 DRM_ERROR("Failed to found connector for link!");
338 DRM_INFO("DM_MST: Differing MST start on aconnector: %p [id: %d]\n",
339 aconnector, aconnector->base.base.id);
343 DRM_INFO("DM_MST: starting TM on aconnector: %p [id: %d]\n",
344 aconnector, aconnector->base.base.id);
346 return (drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true) == 0);
349 void dm_helpers_dp_mst_stop_top_mgr(
350 struct dc_context *ctx,
351 const struct dc_link *link)
353 struct amdgpu_connector *aconnector = link->priv;
356 DRM_ERROR("Failed to found connector for link!");
360 DRM_INFO("DM_MST: stopping TM on aconnector: %p [id: %d]\n",
361 aconnector, aconnector->base.base.id);
363 if (aconnector->mst_mgr.mst_state == true)
364 drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, false);
367 bool dm_helpers_dp_read_dpcd(
368 struct dc_context *ctx,
369 const struct dc_link *link,
375 struct amdgpu_connector *aconnector = link->priv;
378 DRM_ERROR("Failed to found connector for link!");
382 return drm_dp_dpcd_read(&aconnector->dm_dp_aux.aux, address,
386 bool dm_helpers_dp_write_dpcd(
387 struct dc_context *ctx,
388 const struct dc_link *link,
393 struct amdgpu_connector *aconnector = link->priv;
396 DRM_ERROR("Failed to found connector for link!");
400 return drm_dp_dpcd_write(&aconnector->dm_dp_aux.aux,
401 address, (uint8_t *)data, size) > 0;
404 bool dm_helpers_submit_i2c(
405 struct dc_context *ctx,
406 const struct dc_link *link,
407 struct i2c_command *cmd)
409 struct amdgpu_connector *aconnector = link->priv;
410 struct i2c_msg *msgs;
412 int num = cmd->number_of_payloads;
416 DRM_ERROR("Failed to found connector for link!");
420 msgs = kzalloc(num * sizeof(struct i2c_msg), GFP_KERNEL);
425 for (i = 0; i < num; i++) {
426 msgs[i].flags = cmd->payloads[i].write ? 0 : I2C_M_RD;
427 msgs[i].addr = cmd->payloads[i].address;
428 msgs[i].len = cmd->payloads[i].length;
429 msgs[i].buf = cmd->payloads[i].data;
432 result = i2c_transfer(&aconnector->i2c->base, msgs, num) == num;