1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev * Copyright 2015 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev *
4b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a
5b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"),
6b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation
7b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the
9b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions:
10b843c749SSergey Zigachev *
11b843c749SSergey Zigachev * The above copyright notice and this permission notice shall be included in
12b843c749SSergey Zigachev * all copies or substantial portions of the Software.
13b843c749SSergey Zigachev *
14b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17b843c749SSergey Zigachev * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18b843c749SSergey Zigachev * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19b843c749SSergey Zigachev * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20b843c749SSergey Zigachev * OTHER DEALINGS IN THE SOFTWARE.
21b843c749SSergey Zigachev *
22b843c749SSergey Zigachev * Authors: AMD
23b843c749SSergey Zigachev *
24b843c749SSergey Zigachev */
25b843c749SSergey Zigachev
26b843c749SSergey Zigachev #include <linux/string.h>
27b843c749SSergey Zigachev #include <linux/acpi.h>
28*78973132SSergey Zigachev #if 0
29b843c749SSergey Zigachev #include <linux/version.h>
30*78973132SSergey Zigachev #endif
31b843c749SSergey Zigachev #include <linux/i2c.h>
32b843c749SSergey Zigachev
33b843c749SSergey Zigachev #include <drm/drmP.h>
34b843c749SSergey Zigachev #include <drm/drm_crtc_helper.h>
35b843c749SSergey Zigachev #include <drm/amdgpu_drm.h>
36b843c749SSergey Zigachev #include <drm/drm_edid.h>
37b843c749SSergey Zigachev
38b843c749SSergey Zigachev #include "dm_services.h"
39b843c749SSergey Zigachev #include "amdgpu.h"
40b843c749SSergey Zigachev #include "dc.h"
41b843c749SSergey Zigachev #include "amdgpu_dm.h"
42b843c749SSergey Zigachev #include "amdgpu_dm_irq.h"
43b843c749SSergey Zigachev
44b843c749SSergey Zigachev #include "dm_helpers.h"
45b843c749SSergey Zigachev
46b843c749SSergey Zigachev /* dm_helpers_parse_edid_caps
47b843c749SSergey Zigachev *
48b843c749SSergey Zigachev * Parse edid caps
49b843c749SSergey Zigachev *
50b843c749SSergey Zigachev * @edid: [in] pointer to edid
51b843c749SSergey Zigachev * edid_caps: [in] pointer to edid caps
52b843c749SSergey Zigachev * @return
53b843c749SSergey Zigachev * void
54b843c749SSergey Zigachev * */
dm_helpers_parse_edid_caps(struct dc_context * ctx,const struct dc_edid * edid,struct dc_edid_caps * edid_caps)55b843c749SSergey Zigachev enum dc_edid_status dm_helpers_parse_edid_caps(
56b843c749SSergey Zigachev struct dc_context *ctx,
57b843c749SSergey Zigachev const struct dc_edid *edid,
58b843c749SSergey Zigachev struct dc_edid_caps *edid_caps)
59b843c749SSergey Zigachev {
60b843c749SSergey Zigachev struct edid *edid_buf = (struct edid *) edid->raw_edid;
61b843c749SSergey Zigachev struct cea_sad *sads;
62b843c749SSergey Zigachev int sad_count = -1;
63b843c749SSergey Zigachev int sadb_count = -1;
64b843c749SSergey Zigachev int i = 0;
65b843c749SSergey Zigachev int j = 0;
66b843c749SSergey Zigachev uint8_t *sadb = NULL;
67b843c749SSergey Zigachev
68b843c749SSergey Zigachev enum dc_edid_status result = EDID_OK;
69b843c749SSergey Zigachev
70b843c749SSergey Zigachev if (!edid_caps || !edid)
71b843c749SSergey Zigachev return EDID_BAD_INPUT;
72b843c749SSergey Zigachev
73b843c749SSergey Zigachev if (!drm_edid_is_valid(edid_buf))
74b843c749SSergey Zigachev result = EDID_BAD_CHECKSUM;
75b843c749SSergey Zigachev
76b843c749SSergey Zigachev edid_caps->manufacturer_id = (uint16_t) edid_buf->mfg_id[0] |
77b843c749SSergey Zigachev ((uint16_t) edid_buf->mfg_id[1])<<8;
78b843c749SSergey Zigachev edid_caps->product_id = (uint16_t) edid_buf->prod_code[0] |
79b843c749SSergey Zigachev ((uint16_t) edid_buf->prod_code[1])<<8;
80b843c749SSergey Zigachev edid_caps->serial_number = edid_buf->serial;
81b843c749SSergey Zigachev edid_caps->manufacture_week = edid_buf->mfg_week;
82b843c749SSergey Zigachev edid_caps->manufacture_year = edid_buf->mfg_year;
83b843c749SSergey Zigachev
84b843c749SSergey Zigachev /* One of the four detailed_timings stores the monitor name. It's
85b843c749SSergey Zigachev * stored in an array of length 13. */
86b843c749SSergey Zigachev for (i = 0; i < 4; i++) {
87b843c749SSergey Zigachev if (edid_buf->detailed_timings[i].data.other_data.type == 0xfc) {
88b843c749SSergey Zigachev while (j < 13 && edid_buf->detailed_timings[i].data.other_data.data.str.str[j]) {
89b843c749SSergey Zigachev if (edid_buf->detailed_timings[i].data.other_data.data.str.str[j] == '\n')
90b843c749SSergey Zigachev break;
91b843c749SSergey Zigachev
92b843c749SSergey Zigachev edid_caps->display_name[j] =
93b843c749SSergey Zigachev edid_buf->detailed_timings[i].data.other_data.data.str.str[j];
94b843c749SSergey Zigachev j++;
95b843c749SSergey Zigachev }
96b843c749SSergey Zigachev }
97b843c749SSergey Zigachev }
98b843c749SSergey Zigachev
99b843c749SSergey Zigachev edid_caps->edid_hdmi = drm_detect_hdmi_monitor(
100b843c749SSergey Zigachev (struct edid *) edid->raw_edid);
101b843c749SSergey Zigachev
102b843c749SSergey Zigachev sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
103b843c749SSergey Zigachev if (sad_count <= 0) {
104b843c749SSergey Zigachev DRM_INFO("SADs count is: %d, don't need to read it\n",
105b843c749SSergey Zigachev sad_count);
106b843c749SSergey Zigachev return result;
107b843c749SSergey Zigachev }
108b843c749SSergey Zigachev
109b843c749SSergey Zigachev edid_caps->audio_mode_count = sad_count < DC_MAX_AUDIO_DESC_COUNT ? sad_count : DC_MAX_AUDIO_DESC_COUNT;
110b843c749SSergey Zigachev for (i = 0; i < edid_caps->audio_mode_count; ++i) {
111b843c749SSergey Zigachev struct cea_sad *sad = &sads[i];
112b843c749SSergey Zigachev
113b843c749SSergey Zigachev edid_caps->audio_modes[i].format_code = sad->format;
114b843c749SSergey Zigachev edid_caps->audio_modes[i].channel_count = sad->channels + 1;
115b843c749SSergey Zigachev edid_caps->audio_modes[i].sample_rate = sad->freq;
116b843c749SSergey Zigachev edid_caps->audio_modes[i].sample_size = sad->byte2;
117b843c749SSergey Zigachev }
118b843c749SSergey Zigachev
119b843c749SSergey Zigachev sadb_count = drm_edid_to_speaker_allocation((struct edid *) edid->raw_edid, &sadb);
120b843c749SSergey Zigachev
121b843c749SSergey Zigachev if (sadb_count < 0) {
122b843c749SSergey Zigachev DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sadb_count);
123b843c749SSergey Zigachev sadb_count = 0;
124b843c749SSergey Zigachev }
125b843c749SSergey Zigachev
126b843c749SSergey Zigachev if (sadb_count)
127b843c749SSergey Zigachev edid_caps->speaker_flags = sadb[0];
128b843c749SSergey Zigachev else
129b843c749SSergey Zigachev edid_caps->speaker_flags = DEFAULT_SPEAKER_LOCATION;
130b843c749SSergey Zigachev
131b843c749SSergey Zigachev kfree(sads);
132b843c749SSergey Zigachev kfree(sadb);
133b843c749SSergey Zigachev
134b843c749SSergey Zigachev return result;
135b843c749SSergey Zigachev }
136b843c749SSergey Zigachev
get_payload_table(struct amdgpu_dm_connector * aconnector,struct dp_mst_stream_allocation_table * proposed_table)137b843c749SSergey Zigachev static void get_payload_table(
138b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector,
139b843c749SSergey Zigachev struct dp_mst_stream_allocation_table *proposed_table)
140b843c749SSergey Zigachev {
141b843c749SSergey Zigachev int i;
142b843c749SSergey Zigachev struct drm_dp_mst_topology_mgr *mst_mgr =
143b843c749SSergey Zigachev &aconnector->mst_port->mst_mgr;
144b843c749SSergey Zigachev
145b843c749SSergey Zigachev mutex_lock(&mst_mgr->payload_lock);
146b843c749SSergey Zigachev
147b843c749SSergey Zigachev proposed_table->stream_count = 0;
148b843c749SSergey Zigachev
149b843c749SSergey Zigachev /* number of active streams */
150b843c749SSergey Zigachev for (i = 0; i < mst_mgr->max_payloads; i++) {
151b843c749SSergey Zigachev if (mst_mgr->payloads[i].num_slots == 0)
152b843c749SSergey Zigachev break; /* end of vcp_id table */
153b843c749SSergey Zigachev
154b843c749SSergey Zigachev ASSERT(mst_mgr->payloads[i].payload_state !=
155b843c749SSergey Zigachev DP_PAYLOAD_DELETE_LOCAL);
156b843c749SSergey Zigachev
157b843c749SSergey Zigachev if (mst_mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL ||
158b843c749SSergey Zigachev mst_mgr->payloads[i].payload_state ==
159b843c749SSergey Zigachev DP_PAYLOAD_REMOTE) {
160b843c749SSergey Zigachev
161b843c749SSergey Zigachev struct dp_mst_stream_allocation *sa =
162b843c749SSergey Zigachev &proposed_table->stream_allocations[
163b843c749SSergey Zigachev proposed_table->stream_count];
164b843c749SSergey Zigachev
165b843c749SSergey Zigachev sa->slot_count = mst_mgr->payloads[i].num_slots;
166b843c749SSergey Zigachev sa->vcp_id = mst_mgr->proposed_vcpis[i]->vcpi;
167b843c749SSergey Zigachev proposed_table->stream_count++;
168b843c749SSergey Zigachev }
169b843c749SSergey Zigachev }
170b843c749SSergey Zigachev
171b843c749SSergey Zigachev mutex_unlock(&mst_mgr->payload_lock);
172b843c749SSergey Zigachev }
173b843c749SSergey Zigachev
dm_helpers_dp_update_branch_info(struct dc_context * ctx,const struct dc_link * link)174b843c749SSergey Zigachev void dm_helpers_dp_update_branch_info(
175b843c749SSergey Zigachev struct dc_context *ctx,
176b843c749SSergey Zigachev const struct dc_link *link)
177b843c749SSergey Zigachev {}
178b843c749SSergey Zigachev
179b843c749SSergey Zigachev /*
180b843c749SSergey Zigachev * Writes payload allocation table in immediate downstream device.
181b843c749SSergey Zigachev */
dm_helpers_dp_mst_write_payload_allocation_table(struct dc_context * ctx,const struct dc_stream_state * stream,struct dp_mst_stream_allocation_table * proposed_table,bool enable)182b843c749SSergey Zigachev bool dm_helpers_dp_mst_write_payload_allocation_table(
183b843c749SSergey Zigachev struct dc_context *ctx,
184b843c749SSergey Zigachev const struct dc_stream_state *stream,
185b843c749SSergey Zigachev struct dp_mst_stream_allocation_table *proposed_table,
186b843c749SSergey Zigachev bool enable)
187b843c749SSergey Zigachev {
188b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector;
189b843c749SSergey Zigachev struct drm_dp_mst_topology_mgr *mst_mgr;
190b843c749SSergey Zigachev struct drm_dp_mst_port *mst_port;
191b843c749SSergey Zigachev int slots = 0;
192b843c749SSergey Zigachev bool ret;
193b843c749SSergey Zigachev int clock;
194b843c749SSergey Zigachev int bpp = 0;
195b843c749SSergey Zigachev int pbn = 0;
196b843c749SSergey Zigachev
197b843c749SSergey Zigachev aconnector = stream->sink->priv;
198b843c749SSergey Zigachev
199b843c749SSergey Zigachev if (!aconnector || !aconnector->mst_port)
200b843c749SSergey Zigachev return false;
201b843c749SSergey Zigachev
202b843c749SSergey Zigachev mst_mgr = &aconnector->mst_port->mst_mgr;
203b843c749SSergey Zigachev
204b843c749SSergey Zigachev if (!mst_mgr->mst_state)
205b843c749SSergey Zigachev return false;
206b843c749SSergey Zigachev
207b843c749SSergey Zigachev mst_port = aconnector->port;
208b843c749SSergey Zigachev
209b843c749SSergey Zigachev if (enable) {
210b843c749SSergey Zigachev clock = stream->timing.pix_clk_khz;
211b843c749SSergey Zigachev
212b843c749SSergey Zigachev switch (stream->timing.display_color_depth) {
213b843c749SSergey Zigachev
214b843c749SSergey Zigachev case COLOR_DEPTH_666:
215b843c749SSergey Zigachev bpp = 6;
216b843c749SSergey Zigachev break;
217b843c749SSergey Zigachev case COLOR_DEPTH_888:
218b843c749SSergey Zigachev bpp = 8;
219b843c749SSergey Zigachev break;
220b843c749SSergey Zigachev case COLOR_DEPTH_101010:
221b843c749SSergey Zigachev bpp = 10;
222b843c749SSergey Zigachev break;
223b843c749SSergey Zigachev case COLOR_DEPTH_121212:
224b843c749SSergey Zigachev bpp = 12;
225b843c749SSergey Zigachev break;
226b843c749SSergey Zigachev case COLOR_DEPTH_141414:
227b843c749SSergey Zigachev bpp = 14;
228b843c749SSergey Zigachev break;
229b843c749SSergey Zigachev case COLOR_DEPTH_161616:
230b843c749SSergey Zigachev bpp = 16;
231b843c749SSergey Zigachev break;
232b843c749SSergey Zigachev default:
233b843c749SSergey Zigachev ASSERT(bpp != 0);
234b843c749SSergey Zigachev break;
235b843c749SSergey Zigachev }
236b843c749SSergey Zigachev
237b843c749SSergey Zigachev bpp = bpp * 3;
238b843c749SSergey Zigachev
239b843c749SSergey Zigachev /* TODO need to know link rate */
240b843c749SSergey Zigachev
241b843c749SSergey Zigachev pbn = drm_dp_calc_pbn_mode(clock, bpp);
242b843c749SSergey Zigachev
243b843c749SSergey Zigachev slots = drm_dp_find_vcpi_slots(mst_mgr, pbn);
244b843c749SSergey Zigachev ret = drm_dp_mst_allocate_vcpi(mst_mgr, mst_port, pbn, slots);
245b843c749SSergey Zigachev
246b843c749SSergey Zigachev if (!ret)
247b843c749SSergey Zigachev return false;
248b843c749SSergey Zigachev
249b843c749SSergey Zigachev } else {
250b843c749SSergey Zigachev drm_dp_mst_reset_vcpi_slots(mst_mgr, mst_port);
251b843c749SSergey Zigachev }
252b843c749SSergey Zigachev
253b843c749SSergey Zigachev /* It's OK for this to fail */
254b843c749SSergey Zigachev drm_dp_update_payload_part1(mst_mgr);
255b843c749SSergey Zigachev
256b843c749SSergey Zigachev /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or
257b843c749SSergey Zigachev * AUX message. The sequence is slot 1-63 allocated sequence for each
258b843c749SSergey Zigachev * stream. AMD ASIC stream slot allocation should follow the same
259b843c749SSergey Zigachev * sequence. copy DRM MST allocation to dc */
260b843c749SSergey Zigachev
261b843c749SSergey Zigachev get_payload_table(aconnector, proposed_table);
262b843c749SSergey Zigachev
263b843c749SSergey Zigachev return true;
264b843c749SSergey Zigachev }
265b843c749SSergey Zigachev
266b843c749SSergey Zigachev
267b843c749SSergey Zigachev /*
268b843c749SSergey Zigachev * Clear payload allocation table before enable MST DP link.
269b843c749SSergey Zigachev */
dm_helpers_dp_mst_clear_payload_allocation_table(struct dc_context * ctx,const struct dc_link * link)270b843c749SSergey Zigachev void dm_helpers_dp_mst_clear_payload_allocation_table(
271b843c749SSergey Zigachev struct dc_context *ctx,
272b843c749SSergey Zigachev const struct dc_link *link)
273b843c749SSergey Zigachev {}
274b843c749SSergey Zigachev
275b843c749SSergey Zigachev /*
276b843c749SSergey Zigachev * Polls for ACT (allocation change trigger) handled and sends
277b843c749SSergey Zigachev * ALLOCATE_PAYLOAD message.
278b843c749SSergey Zigachev */
dm_helpers_dp_mst_poll_for_allocation_change_trigger(struct dc_context * ctx,const struct dc_stream_state * stream)279b843c749SSergey Zigachev bool dm_helpers_dp_mst_poll_for_allocation_change_trigger(
280b843c749SSergey Zigachev struct dc_context *ctx,
281b843c749SSergey Zigachev const struct dc_stream_state *stream)
282b843c749SSergey Zigachev {
283b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector;
284b843c749SSergey Zigachev struct drm_dp_mst_topology_mgr *mst_mgr;
285b843c749SSergey Zigachev int ret;
286b843c749SSergey Zigachev
287b843c749SSergey Zigachev aconnector = stream->sink->priv;
288b843c749SSergey Zigachev
289b843c749SSergey Zigachev if (!aconnector || !aconnector->mst_port)
290b843c749SSergey Zigachev return false;
291b843c749SSergey Zigachev
292b843c749SSergey Zigachev mst_mgr = &aconnector->mst_port->mst_mgr;
293b843c749SSergey Zigachev
294b843c749SSergey Zigachev if (!mst_mgr->mst_state)
295b843c749SSergey Zigachev return false;
296b843c749SSergey Zigachev
297b843c749SSergey Zigachev ret = drm_dp_check_act_status(mst_mgr);
298b843c749SSergey Zigachev
299b843c749SSergey Zigachev if (ret)
300b843c749SSergey Zigachev return false;
301b843c749SSergey Zigachev
302b843c749SSergey Zigachev return true;
303b843c749SSergey Zigachev }
304b843c749SSergey Zigachev
dm_helpers_dp_mst_send_payload_allocation(struct dc_context * ctx,const struct dc_stream_state * stream,bool enable)305b843c749SSergey Zigachev bool dm_helpers_dp_mst_send_payload_allocation(
306b843c749SSergey Zigachev struct dc_context *ctx,
307b843c749SSergey Zigachev const struct dc_stream_state *stream,
308b843c749SSergey Zigachev bool enable)
309b843c749SSergey Zigachev {
310b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector;
311b843c749SSergey Zigachev struct drm_dp_mst_topology_mgr *mst_mgr;
312b843c749SSergey Zigachev struct drm_dp_mst_port *mst_port;
313b843c749SSergey Zigachev
314b843c749SSergey Zigachev aconnector = stream->sink->priv;
315b843c749SSergey Zigachev
316b843c749SSergey Zigachev if (!aconnector || !aconnector->mst_port)
317b843c749SSergey Zigachev return false;
318b843c749SSergey Zigachev
319b843c749SSergey Zigachev mst_port = aconnector->port;
320b843c749SSergey Zigachev
321b843c749SSergey Zigachev mst_mgr = &aconnector->mst_port->mst_mgr;
322b843c749SSergey Zigachev
323b843c749SSergey Zigachev if (!mst_mgr->mst_state)
324b843c749SSergey Zigachev return false;
325b843c749SSergey Zigachev
326b843c749SSergey Zigachev /* It's OK for this to fail */
327b843c749SSergey Zigachev drm_dp_update_payload_part2(mst_mgr);
328b843c749SSergey Zigachev
329b843c749SSergey Zigachev if (!enable)
330b843c749SSergey Zigachev drm_dp_mst_deallocate_vcpi(mst_mgr, mst_port);
331b843c749SSergey Zigachev
332b843c749SSergey Zigachev return true;
333b843c749SSergey Zigachev }
334b843c749SSergey Zigachev
dm_dtn_log_begin(struct dc_context * ctx)335b843c749SSergey Zigachev void dm_dtn_log_begin(struct dc_context *ctx)
336b843c749SSergey Zigachev {}
337b843c749SSergey Zigachev
dm_dtn_log_append_v(struct dc_context * ctx,const char * pMsg,...)338b843c749SSergey Zigachev void dm_dtn_log_append_v(struct dc_context *ctx,
339b843c749SSergey Zigachev const char *pMsg, ...)
340b843c749SSergey Zigachev {}
341b843c749SSergey Zigachev
dm_dtn_log_end(struct dc_context * ctx)342b843c749SSergey Zigachev void dm_dtn_log_end(struct dc_context *ctx)
343b843c749SSergey Zigachev {}
344b843c749SSergey Zigachev
dm_helpers_dp_mst_start_top_mgr(struct dc_context * ctx,const struct dc_link * link,bool boot)345b843c749SSergey Zigachev bool dm_helpers_dp_mst_start_top_mgr(
346b843c749SSergey Zigachev struct dc_context *ctx,
347b843c749SSergey Zigachev const struct dc_link *link,
348b843c749SSergey Zigachev bool boot)
349b843c749SSergey Zigachev {
350b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector = link->priv;
351b843c749SSergey Zigachev
352b843c749SSergey Zigachev if (!aconnector) {
353b843c749SSergey Zigachev DRM_ERROR("Failed to found connector for link!");
354b843c749SSergey Zigachev return false;
355b843c749SSergey Zigachev }
356b843c749SSergey Zigachev
357b843c749SSergey Zigachev if (boot) {
358b843c749SSergey Zigachev DRM_INFO("DM_MST: Differing MST start on aconnector: %p [id: %d]\n",
359b843c749SSergey Zigachev aconnector, aconnector->base.base.id);
360b843c749SSergey Zigachev return true;
361b843c749SSergey Zigachev }
362b843c749SSergey Zigachev
363b843c749SSergey Zigachev DRM_INFO("DM_MST: starting TM on aconnector: %p [id: %d]\n",
364b843c749SSergey Zigachev aconnector, aconnector->base.base.id);
365b843c749SSergey Zigachev
366b843c749SSergey Zigachev return (drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true) == 0);
367b843c749SSergey Zigachev }
368b843c749SSergey Zigachev
dm_helpers_dp_mst_stop_top_mgr(struct dc_context * ctx,const struct dc_link * link)369b843c749SSergey Zigachev void dm_helpers_dp_mst_stop_top_mgr(
370b843c749SSergey Zigachev struct dc_context *ctx,
371b843c749SSergey Zigachev const struct dc_link *link)
372b843c749SSergey Zigachev {
373b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector = link->priv;
374b843c749SSergey Zigachev
375b843c749SSergey Zigachev if (!aconnector) {
376b843c749SSergey Zigachev DRM_ERROR("Failed to found connector for link!");
377b843c749SSergey Zigachev return;
378b843c749SSergey Zigachev }
379b843c749SSergey Zigachev
380b843c749SSergey Zigachev DRM_INFO("DM_MST: stopping TM on aconnector: %p [id: %d]\n",
381b843c749SSergey Zigachev aconnector, aconnector->base.base.id);
382b843c749SSergey Zigachev
383b843c749SSergey Zigachev if (aconnector->mst_mgr.mst_state == true)
384b843c749SSergey Zigachev drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, false);
385b843c749SSergey Zigachev }
386b843c749SSergey Zigachev
dm_helpers_dp_read_dpcd(struct dc_context * ctx,const struct dc_link * link,uint32_t address,uint8_t * data,uint32_t size)387b843c749SSergey Zigachev bool dm_helpers_dp_read_dpcd(
388b843c749SSergey Zigachev struct dc_context *ctx,
389b843c749SSergey Zigachev const struct dc_link *link,
390b843c749SSergey Zigachev uint32_t address,
391b843c749SSergey Zigachev uint8_t *data,
392b843c749SSergey Zigachev uint32_t size)
393b843c749SSergey Zigachev {
394b843c749SSergey Zigachev
395b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector = link->priv;
396b843c749SSergey Zigachev
397b843c749SSergey Zigachev if (!aconnector) {
398b843c749SSergey Zigachev DRM_ERROR("Failed to found connector for link!");
399b843c749SSergey Zigachev return false;
400b843c749SSergey Zigachev }
401b843c749SSergey Zigachev
402b843c749SSergey Zigachev return drm_dp_dpcd_read(&aconnector->dm_dp_aux.aux, address,
403b843c749SSergey Zigachev data, size) > 0;
404b843c749SSergey Zigachev }
405b843c749SSergey Zigachev
dm_helpers_dp_write_dpcd(struct dc_context * ctx,const struct dc_link * link,uint32_t address,const uint8_t * data,uint32_t size)406b843c749SSergey Zigachev bool dm_helpers_dp_write_dpcd(
407b843c749SSergey Zigachev struct dc_context *ctx,
408b843c749SSergey Zigachev const struct dc_link *link,
409b843c749SSergey Zigachev uint32_t address,
410b843c749SSergey Zigachev const uint8_t *data,
411b843c749SSergey Zigachev uint32_t size)
412b843c749SSergey Zigachev {
413b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector = link->priv;
414b843c749SSergey Zigachev
415b843c749SSergey Zigachev if (!aconnector) {
416b843c749SSergey Zigachev DRM_ERROR("Failed to found connector for link!");
417b843c749SSergey Zigachev return false;
418b843c749SSergey Zigachev }
419b843c749SSergey Zigachev
420b843c749SSergey Zigachev return drm_dp_dpcd_write(&aconnector->dm_dp_aux.aux,
421b843c749SSergey Zigachev address, (uint8_t *)data, size) > 0;
422b843c749SSergey Zigachev }
423b843c749SSergey Zigachev
dm_helpers_submit_i2c(struct dc_context * ctx,const struct dc_link * link,struct i2c_command * cmd)424b843c749SSergey Zigachev bool dm_helpers_submit_i2c(
425b843c749SSergey Zigachev struct dc_context *ctx,
426b843c749SSergey Zigachev const struct dc_link *link,
427b843c749SSergey Zigachev struct i2c_command *cmd)
428b843c749SSergey Zigachev {
429b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector = link->priv;
430b843c749SSergey Zigachev struct i2c_msg *msgs;
431b843c749SSergey Zigachev int i = 0;
432b843c749SSergey Zigachev int num = cmd->number_of_payloads;
433b843c749SSergey Zigachev bool result;
434b843c749SSergey Zigachev
435b843c749SSergey Zigachev if (!aconnector) {
436b843c749SSergey Zigachev DRM_ERROR("Failed to found connector for link!");
437b843c749SSergey Zigachev return false;
438b843c749SSergey Zigachev }
439b843c749SSergey Zigachev
440b843c749SSergey Zigachev msgs = kcalloc(num, sizeof(struct i2c_msg), GFP_KERNEL);
441b843c749SSergey Zigachev
442b843c749SSergey Zigachev if (!msgs)
443b843c749SSergey Zigachev return false;
444b843c749SSergey Zigachev
445b843c749SSergey Zigachev for (i = 0; i < num; i++) {
446b843c749SSergey Zigachev msgs[i].flags = cmd->payloads[i].write ? 0 : I2C_M_RD;
447b843c749SSergey Zigachev msgs[i].addr = cmd->payloads[i].address;
448b843c749SSergey Zigachev msgs[i].len = cmd->payloads[i].length;
449b843c749SSergey Zigachev msgs[i].buf = cmd->payloads[i].data;
450b843c749SSergey Zigachev }
451b843c749SSergey Zigachev
452b843c749SSergey Zigachev result = i2c_transfer(&aconnector->i2c->base, msgs, num) == num;
453b843c749SSergey Zigachev
454b843c749SSergey Zigachev kfree(msgs);
455b843c749SSergey Zigachev
456b843c749SSergey Zigachev return result;
457b843c749SSergey Zigachev }
458b843c749SSergey Zigachev
dm_helpers_is_dp_sink_present(struct dc_link * link)459b843c749SSergey Zigachev bool dm_helpers_is_dp_sink_present(struct dc_link *link)
460b843c749SSergey Zigachev {
461b843c749SSergey Zigachev bool dp_sink_present;
462b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector = link->priv;
463b843c749SSergey Zigachev
464b843c749SSergey Zigachev if (!aconnector) {
465b843c749SSergey Zigachev BUG_ON("Failed to found connector for link!");
466b843c749SSergey Zigachev return true;
467b843c749SSergey Zigachev }
468b843c749SSergey Zigachev
469b843c749SSergey Zigachev mutex_lock(&aconnector->dm_dp_aux.aux.hw_mutex);
470b843c749SSergey Zigachev dp_sink_present = dc_link_is_dp_sink_present(link);
471b843c749SSergey Zigachev mutex_unlock(&aconnector->dm_dp_aux.aux.hw_mutex);
472b843c749SSergey Zigachev return dp_sink_present;
473b843c749SSergey Zigachev }
474b843c749SSergey Zigachev
dm_helpers_read_local_edid(struct dc_context * ctx,struct dc_link * link,struct dc_sink * sink)475b843c749SSergey Zigachev enum dc_edid_status dm_helpers_read_local_edid(
476b843c749SSergey Zigachev struct dc_context *ctx,
477b843c749SSergey Zigachev struct dc_link *link,
478b843c749SSergey Zigachev struct dc_sink *sink)
479b843c749SSergey Zigachev {
480b843c749SSergey Zigachev struct amdgpu_dm_connector *aconnector = link->priv;
481b843c749SSergey Zigachev struct i2c_adapter *ddc;
482b843c749SSergey Zigachev int retry = 3;
483b843c749SSergey Zigachev enum dc_edid_status edid_status;
484b843c749SSergey Zigachev struct edid *edid;
485b843c749SSergey Zigachev
486b843c749SSergey Zigachev if (link->aux_mode)
487b843c749SSergey Zigachev ddc = &aconnector->dm_dp_aux.aux.ddc;
488b843c749SSergey Zigachev else
489b843c749SSergey Zigachev ddc = &aconnector->i2c->base;
490b843c749SSergey Zigachev
491b843c749SSergey Zigachev /* some dongles read edid incorrectly the first time,
492b843c749SSergey Zigachev * do check sum and retry to make sure read correct edid.
493b843c749SSergey Zigachev */
494b843c749SSergey Zigachev do {
495b843c749SSergey Zigachev
496b843c749SSergey Zigachev edid = drm_get_edid(&aconnector->base, ddc);
497b843c749SSergey Zigachev
498b843c749SSergey Zigachev if (!edid)
499b843c749SSergey Zigachev return EDID_NO_RESPONSE;
500b843c749SSergey Zigachev
501b843c749SSergey Zigachev sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
502b843c749SSergey Zigachev memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink->dc_edid.length);
503b843c749SSergey Zigachev
504b843c749SSergey Zigachev /* We don't need the original edid anymore */
505b843c749SSergey Zigachev kfree(edid);
506b843c749SSergey Zigachev
507b843c749SSergey Zigachev edid_status = dm_helpers_parse_edid_caps(
508b843c749SSergey Zigachev ctx,
509b843c749SSergey Zigachev &sink->dc_edid,
510b843c749SSergey Zigachev &sink->edid_caps);
511b843c749SSergey Zigachev
512b843c749SSergey Zigachev } while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
513b843c749SSergey Zigachev
514b843c749SSergey Zigachev if (edid_status != EDID_OK)
515b843c749SSergey Zigachev DRM_ERROR("EDID err: %d, on connector: %s",
516b843c749SSergey Zigachev edid_status,
517b843c749SSergey Zigachev aconnector->base.name);
518b843c749SSergey Zigachev if (link->aux_mode) {
519b843c749SSergey Zigachev union test_request test_request = { {0} };
520b843c749SSergey Zigachev union test_response test_response = { {0} };
521b843c749SSergey Zigachev
522b843c749SSergey Zigachev dm_helpers_dp_read_dpcd(ctx,
523b843c749SSergey Zigachev link,
524b843c749SSergey Zigachev DP_TEST_REQUEST,
525b843c749SSergey Zigachev &test_request.raw,
526b843c749SSergey Zigachev sizeof(union test_request));
527b843c749SSergey Zigachev
528b843c749SSergey Zigachev if (!test_request.bits.EDID_READ)
529b843c749SSergey Zigachev return edid_status;
530b843c749SSergey Zigachev
531b843c749SSergey Zigachev test_response.bits.EDID_CHECKSUM_WRITE = 1;
532b843c749SSergey Zigachev
533b843c749SSergey Zigachev dm_helpers_dp_write_dpcd(ctx,
534b843c749SSergey Zigachev link,
535b843c749SSergey Zigachev DP_TEST_EDID_CHECKSUM,
536b843c749SSergey Zigachev &sink->dc_edid.raw_edid[sink->dc_edid.length-1],
537b843c749SSergey Zigachev 1);
538b843c749SSergey Zigachev
539b843c749SSergey Zigachev dm_helpers_dp_write_dpcd(ctx,
540b843c749SSergey Zigachev link,
541b843c749SSergey Zigachev DP_TEST_RESPONSE,
542b843c749SSergey Zigachev &test_response.raw,
543b843c749SSergey Zigachev sizeof(test_response));
544b843c749SSergey Zigachev
545b843c749SSergey Zigachev }
546b843c749SSergey Zigachev
547b843c749SSergey Zigachev return edid_status;
548b843c749SSergey Zigachev }
549b843c749SSergey Zigachev
dm_set_dcn_clocks(struct dc_context * ctx,struct dc_clocks * clks)550b843c749SSergey Zigachev void dm_set_dcn_clocks(struct dc_context *ctx, struct dc_clocks *clks)
551b843c749SSergey Zigachev {
552b843c749SSergey Zigachev /* TODO: something */
553b843c749SSergey Zigachev }
554