GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / gpu / drm / amd / display / dc / core / dc_link_ddc.c
1 /*
2  * Copyright 2012-15 Advanced Micro Devices, Inc.
3  *
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:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
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.
21  *
22  * Authors: AMD
23  *
24  */
25
26 #include "dm_services.h"
27 #include "dm_helpers.h"
28 #include "gpio_service_interface.h"
29 #include "include/ddc_service_types.h"
30 #include "include/grph_object_id.h"
31 #include "include/dpcd_defs.h"
32 #include "include/logger_interface.h"
33 #include "include/vector.h"
34 #include "core_types.h"
35 #include "dc_link_ddc.h"
36 #include "aux_engine.h"
37
38 #define AUX_POWER_UP_WA_DELAY 500
39 #define I2C_OVER_AUX_DEFER_WA_DELAY 70
40
41 /* CV smart dongle slave address for retrieving supported HDTV modes*/
42 #define CV_SMART_DONGLE_ADDRESS 0x20
43 /* DVI-HDMI dongle slave address for retrieving dongle signature*/
44 #define DVI_HDMI_DONGLE_ADDRESS 0x68
45 static const int8_t dvi_hdmi_dongle_signature_str[] = "6140063500G";
46 struct dvi_hdmi_dongle_signature_data {
47         int8_t vendor[3];/* "AMD" */
48         uint8_t version[2];
49         uint8_t size;
50         int8_t id[11];/* "6140063500G"*/
51 };
52 /* DP-HDMI dongle slave address for retrieving dongle signature*/
53 #define DP_HDMI_DONGLE_ADDRESS 0x40
54 static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR";
55 #define DP_HDMI_DONGLE_SIGNATURE_EOT 0x04
56
57 struct dp_hdmi_dongle_signature_data {
58         int8_t id[15];/* "DP-HDMI ADAPTOR"*/
59         uint8_t eot;/* end of transmition '\x4' */
60 };
61
62 /* SCDC Address defines (HDMI 2.0)*/
63 #define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3
64 #define HDMI_SCDC_ADDRESS  0x54
65 #define HDMI_SCDC_SINK_VERSION 0x01
66 #define HDMI_SCDC_SOURCE_VERSION 0x02
67 #define HDMI_SCDC_UPDATE_0 0x10
68 #define HDMI_SCDC_TMDS_CONFIG 0x20
69 #define HDMI_SCDC_SCRAMBLER_STATUS 0x21
70 #define HDMI_SCDC_CONFIG_0 0x30
71 #define HDMI_SCDC_STATUS_FLAGS 0x40
72 #define HDMI_SCDC_ERR_DETECT 0x50
73 #define HDMI_SCDC_TEST_CONFIG 0xC0
74
75 union hdmi_scdc_update_read_data {
76         uint8_t byte[2];
77         struct {
78                 uint8_t STATUS_UPDATE:1;
79                 uint8_t CED_UPDATE:1;
80                 uint8_t RR_TEST:1;
81                 uint8_t RESERVED:5;
82                 uint8_t RESERVED2:8;
83         } fields;
84 };
85
86 union hdmi_scdc_status_flags_data {
87         uint8_t byte[2];
88         struct {
89                 uint8_t CLOCK_DETECTED:1;
90                 uint8_t CH0_LOCKED:1;
91                 uint8_t CH1_LOCKED:1;
92                 uint8_t CH2_LOCKED:1;
93                 uint8_t RESERVED:4;
94                 uint8_t RESERVED2:8;
95         } fields;
96 };
97
98 union hdmi_scdc_ced_data {
99         uint8_t byte[7];
100         struct {
101                 uint8_t CH0_8LOW:8;
102                 uint8_t CH0_7HIGH:7;
103                 uint8_t CH0_VALID:1;
104                 uint8_t CH1_8LOW:8;
105                 uint8_t CH1_7HIGH:7;
106                 uint8_t CH1_VALID:1;
107                 uint8_t CH2_8LOW:8;
108                 uint8_t CH2_7HIGH:7;
109                 uint8_t CH2_VALID:1;
110                 uint8_t CHECKSUM:8;
111         } fields;
112 };
113
114 union hdmi_scdc_test_config_Data {
115         uint8_t byte;
116         struct {
117                 uint8_t TEST_READ_REQUEST_DELAY:7;
118                 uint8_t TEST_READ_REQUEST: 1;
119         } fields;
120 };
121
122 struct i2c_payloads {
123         struct vector payloads;
124 };
125
126 struct aux_payloads {
127         struct vector payloads;
128 };
129
130 static bool dal_ddc_i2c_payloads_create(
131                 struct dc_context *ctx,
132                 struct i2c_payloads *payloads,
133                 uint32_t count)
134 {
135         if (dal_vector_construct(
136                 &payloads->payloads, ctx, count, sizeof(struct i2c_payload)))
137                 return true;
138
139         return false;
140 }
141
142 static struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p)
143 {
144         return (struct i2c_payload *)p->payloads.container;
145 }
146
147 static uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p)
148 {
149         return p->payloads.count;
150 }
151
152 static void dal_ddc_i2c_payloads_destroy(struct i2c_payloads *p)
153 {
154         if (!p)
155                 return;
156
157         dal_vector_destruct(&p->payloads);
158 }
159
160 static struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count)
161 {
162         struct aux_payloads *payloads;
163
164         payloads = kzalloc(sizeof(struct aux_payloads), GFP_KERNEL);
165
166         if (!payloads)
167                 return NULL;
168
169         if (dal_vector_construct(
170                 &payloads->payloads, ctx, count, sizeof(struct aux_payload)))
171                 return payloads;
172
173         kfree(payloads);
174         return NULL;
175 }
176
177 static struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p)
178 {
179         return (struct aux_payload *)p->payloads.container;
180 }
181
182 static uint32_t  dal_ddc_aux_payloads_get_count(struct aux_payloads *p)
183 {
184         return p->payloads.count;
185 }
186
187 static void dal_ddc_aux_payloads_destroy(struct aux_payloads **p)
188 {
189         if (!p || !*p)
190                 return;
191
192         dal_vector_destruct(&(*p)->payloads);
193         kfree(*p);
194         *p = NULL;
195 }
196
197 #define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b))
198
199 void dal_ddc_i2c_payloads_add(
200         struct i2c_payloads *payloads,
201         uint32_t address,
202         uint32_t len,
203         uint8_t *data,
204         bool write)
205 {
206         uint32_t payload_size = EDID_SEGMENT_SIZE;
207         uint32_t pos;
208
209         for (pos = 0; pos < len; pos += payload_size) {
210                 struct i2c_payload payload = {
211                         .write = write,
212                         .address = address,
213                         .length = DDC_MIN(payload_size, len - pos),
214                         .data = data + pos };
215                 dal_vector_append(&payloads->payloads, &payload);
216         }
217
218 }
219
220 void dal_ddc_aux_payloads_add(
221         struct aux_payloads *payloads,
222         uint32_t address,
223         uint32_t len,
224         uint8_t *data,
225         bool write)
226 {
227         uint32_t payload_size = DEFAULT_AUX_MAX_DATA_SIZE;
228         uint32_t pos;
229
230         for (pos = 0; pos < len; pos += payload_size) {
231                 struct aux_payload payload = {
232                         .i2c_over_aux = true,
233                         .write = write,
234                         .address = address,
235                         .length = DDC_MIN(payload_size, len - pos),
236                         .data = data + pos };
237                 dal_vector_append(&payloads->payloads, &payload);
238         }
239 }
240
241 static void construct(
242         struct ddc_service *ddc_service,
243         struct ddc_service_init_data *init_data)
244 {
245         enum connector_id connector_id =
246                 dal_graphics_object_id_get_connector_id(init_data->id);
247
248         struct gpio_service *gpio_service = init_data->ctx->gpio_service;
249         struct graphics_object_i2c_info i2c_info;
250         struct gpio_ddc_hw_info hw_info;
251         struct dc_bios *dcb = init_data->ctx->dc_bios;
252
253         ddc_service->link = init_data->link;
254         ddc_service->ctx = init_data->ctx;
255
256         if (BP_RESULT_OK != dcb->funcs->get_i2c_info(dcb, init_data->id, &i2c_info)) {
257                 ddc_service->ddc_pin = NULL;
258         } else {
259                 hw_info.ddc_channel = i2c_info.i2c_line;
260                 hw_info.hw_supported = i2c_info.i2c_hw_assist;
261
262                 ddc_service->ddc_pin = dal_gpio_create_ddc(
263                         gpio_service,
264                         i2c_info.gpio_info.clk_a_register_index,
265                         1 << i2c_info.gpio_info.clk_a_shift,
266                         &hw_info);
267         }
268
269         ddc_service->flags.EDID_QUERY_DONE_ONCE = false;
270         ddc_service->flags.FORCE_READ_REPEATED_START = false;
271         ddc_service->flags.EDID_STRESS_READ = false;
272
273         ddc_service->flags.IS_INTERNAL_DISPLAY =
274                 connector_id == CONNECTOR_ID_EDP ||
275                 connector_id == CONNECTOR_ID_LVDS;
276
277         ddc_service->wa.raw = 0;
278 }
279
280 struct ddc_service *dal_ddc_service_create(
281         struct ddc_service_init_data *init_data)
282 {
283         struct ddc_service *ddc_service;
284
285         ddc_service = kzalloc(sizeof(struct ddc_service), GFP_KERNEL);
286
287         if (!ddc_service)
288                 return NULL;
289
290         construct(ddc_service, init_data);
291         return ddc_service;
292 }
293
294 static void destruct(struct ddc_service *ddc)
295 {
296         if (ddc->ddc_pin)
297                 dal_gpio_destroy_ddc(&ddc->ddc_pin);
298 }
299
300 void dal_ddc_service_destroy(struct ddc_service **ddc)
301 {
302         if (!ddc || !*ddc) {
303                 BREAK_TO_DEBUGGER();
304                 return;
305         }
306         destruct(*ddc);
307         kfree(*ddc);
308         *ddc = NULL;
309 }
310
311 enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc)
312 {
313         return DDC_SERVICE_TYPE_CONNECTOR;
314 }
315
316 void dal_ddc_service_set_transaction_type(
317         struct ddc_service *ddc,
318         enum ddc_transaction_type type)
319 {
320         ddc->transaction_type = type;
321 }
322
323 bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc)
324 {
325         switch (ddc->transaction_type) {
326         case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
327         case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
328         case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER:
329                 return true;
330         default:
331                 break;
332         }
333         return false;
334 }
335
336 void ddc_service_set_dongle_type(struct ddc_service *ddc,
337                 enum display_dongle_type dongle_type)
338 {
339         ddc->dongle_type = dongle_type;
340 }
341
342 static uint32_t defer_delay_converter_wa(
343         struct ddc_service *ddc,
344         uint32_t defer_delay)
345 {
346         struct dc_link *link = ddc->link;
347
348         if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_4 &&
349                 !memcmp(link->dpcd_caps.branch_dev_name,
350                         DP_DVI_CONVERTER_ID_4,
351                         sizeof(link->dpcd_caps.branch_dev_name)))
352                 return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY ?
353                         defer_delay : I2C_OVER_AUX_DEFER_WA_DELAY;
354
355         return defer_delay;
356 }
357
358 #define DP_TRANSLATOR_DELAY 5
359
360 uint32_t get_defer_delay(struct ddc_service *ddc)
361 {
362         uint32_t defer_delay = 0;
363
364         switch (ddc->transaction_type) {
365         case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
366                 if ((DISPLAY_DONGLE_DP_VGA_CONVERTER == ddc->dongle_type) ||
367                         (DISPLAY_DONGLE_DP_DVI_CONVERTER == ddc->dongle_type) ||
368                         (DISPLAY_DONGLE_DP_HDMI_CONVERTER ==
369                                 ddc->dongle_type)) {
370
371                         defer_delay = DP_TRANSLATOR_DELAY;
372
373                         defer_delay =
374                                 defer_delay_converter_wa(ddc, defer_delay);
375
376                 } else /*sink has a delay different from an Active Converter*/
377                         defer_delay = 0;
378                 break;
379         case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
380                 defer_delay = DP_TRANSLATOR_DELAY;
381                 break;
382         default:
383                 break;
384         }
385         return defer_delay;
386 }
387
388 static bool i2c_read(
389         struct ddc_service *ddc,
390         uint32_t address,
391         uint8_t *buffer,
392         uint32_t len)
393 {
394         uint8_t offs_data = 0;
395         struct i2c_payload payloads[2] = {
396                 {
397                 .write = true,
398                 .address = address,
399                 .length = 1,
400                 .data = &offs_data },
401                 {
402                 .write = false,
403                 .address = address,
404                 .length = len,
405                 .data = buffer } };
406
407         struct i2c_command command = {
408                 .payloads = payloads,
409                 .number_of_payloads = 2,
410                 .engine = DDC_I2C_COMMAND_ENGINE,
411                 .speed = ddc->ctx->dc->caps.i2c_speed_in_khz };
412
413         return dm_helpers_submit_i2c(
414                         ddc->ctx,
415                         ddc->link,
416                         &command);
417 }
418
419 void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
420         struct ddc_service *ddc,
421         struct display_sink_capability *sink_cap)
422 {
423         uint8_t i;
424         bool is_valid_hdmi_signature;
425         enum display_dongle_type *dongle = &sink_cap->dongle_type;
426         uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE];
427         bool is_type2_dongle = false;
428         int retry_count = 2;
429         struct dp_hdmi_dongle_signature_data *dongle_signature;
430
431         /* Assume we have no valid DP passive dongle connected */
432         *dongle = DISPLAY_DONGLE_NONE;
433         sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK;
434
435         /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/
436         if (!i2c_read(
437                 ddc,
438                 DP_HDMI_DONGLE_ADDRESS,
439                 type2_dongle_buf,
440                 sizeof(type2_dongle_buf))) {
441                 /* Passive HDMI dongles can sometimes fail here without retrying*/
442                 while (retry_count > 0) {
443                         if (i2c_read(ddc,
444                                 DP_HDMI_DONGLE_ADDRESS,
445                                 type2_dongle_buf,
446                                 sizeof(type2_dongle_buf)))
447                                 break;
448                         retry_count--;
449                 }
450                 if (retry_count == 0) {
451                         *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
452                         sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK;
453
454                         CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf),
455                                         "DP-DVI passive dongle %dMhz: ",
456                                         DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000);
457                         return;
458                 }
459         }
460
461         /* Check if Type 2 dongle.*/
462         if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID)
463                 is_type2_dongle = true;
464
465         dongle_signature =
466                 (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf;
467
468         is_valid_hdmi_signature = true;
469
470         /* Check EOT */
471         if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) {
472                 is_valid_hdmi_signature = false;
473         }
474
475         /* Check signature */
476         for (i = 0; i < sizeof(dongle_signature->id); ++i) {
477                 /* If its not the right signature,
478                  * skip mismatch in subversion byte.*/
479                 if (dongle_signature->id[i] !=
480                         dp_hdmi_dongle_signature_str[i] && i != 3) {
481
482                         if (is_type2_dongle) {
483                                 is_valid_hdmi_signature = false;
484                                 break;
485                         }
486
487                 }
488         }
489
490         if (is_type2_dongle) {
491                 uint32_t max_tmds_clk =
492                         type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK];
493
494                 max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2;
495
496                 if (0 == max_tmds_clk ||
497                                 max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK ||
498                                 max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) {
499                         *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
500
501                         CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
502                                         sizeof(type2_dongle_buf),
503                                         "DP-DVI passive dongle %dMhz: ",
504                                         DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000);
505                 } else {
506                         if (is_valid_hdmi_signature == true) {
507                                 *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
508
509                                 CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
510                                                 sizeof(type2_dongle_buf),
511                                                 "Type 2 DP-HDMI passive dongle %dMhz: ",
512                                                 max_tmds_clk);
513                         } else {
514                                 *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
515
516                                 CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
517                                                 sizeof(type2_dongle_buf),
518                                                 "Type 2 DP-HDMI passive dongle (no signature) %dMhz: ",
519                                                 max_tmds_clk);
520
521                         }
522
523                         /* Multiply by 1000 to convert to kHz. */
524                         sink_cap->max_hdmi_pixel_clock =
525                                 max_tmds_clk * 1000;
526                 }
527
528         } else {
529                 if (is_valid_hdmi_signature == true) {
530                         *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
531
532                         CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
533                                         sizeof(type2_dongle_buf),
534                                         "Type 1 DP-HDMI passive dongle %dMhz: ",
535                                         sink_cap->max_hdmi_pixel_clock / 1000);
536                 } else {
537                         *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
538
539                         CONN_DATA_DETECT(ddc->link, type2_dongle_buf,
540                                         sizeof(type2_dongle_buf),
541                                         "Type 1 DP-HDMI passive dongle (no signature) %dMhz: ",
542                                         sink_cap->max_hdmi_pixel_clock / 1000);
543                 }
544         }
545
546         return;
547 }
548
549 enum {
550         DP_SINK_CAP_SIZE =
551                 DP_EDP_CONFIGURATION_CAP - DP_DPCD_REV + 1
552 };
553
554 bool dal_ddc_service_query_ddc_data(
555         struct ddc_service *ddc,
556         uint32_t address,
557         uint8_t *write_buf,
558         uint32_t write_size,
559         uint8_t *read_buf,
560         uint32_t read_size)
561 {
562         bool ret;
563         uint32_t payload_size =
564                 dal_ddc_service_is_in_aux_transaction_mode(ddc) ?
565                         DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE;
566
567         uint32_t write_payloads =
568                 (write_size + payload_size - 1) / payload_size;
569
570         uint32_t read_payloads =
571                 (read_size + payload_size - 1) / payload_size;
572
573         uint32_t payloads_num = write_payloads + read_payloads;
574
575
576         if (write_size > EDID_SEGMENT_SIZE || read_size > EDID_SEGMENT_SIZE)
577                 return false;
578
579         if (!payloads_num)
580                 return false;
581
582         /*TODO: len of payload data for i2c and aux is uint8!!!!,
583          *  but we want to read 256 over i2c!!!!*/
584         if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
585
586                 struct aux_payloads *payloads =
587                         dal_ddc_aux_payloads_create(ddc->ctx, payloads_num);
588
589                 struct aux_command command = {
590                         .payloads = dal_ddc_aux_payloads_get(payloads),
591                         .number_of_payloads = 0,
592                         .defer_delay = get_defer_delay(ddc),
593                         .max_defer_write_retry = 0 };
594
595                 dal_ddc_aux_payloads_add(
596                         payloads, address, write_size, write_buf, true);
597
598                 dal_ddc_aux_payloads_add(
599                         payloads, address, read_size, read_buf, false);
600
601                 command.number_of_payloads =
602                         dal_ddc_aux_payloads_get_count(payloads);
603
604                 ret = dal_i2caux_submit_aux_command(
605                                 ddc->ctx->i2caux,
606                                 ddc->ddc_pin,
607                                 &command);
608
609                 dal_ddc_aux_payloads_destroy(&payloads);
610
611         } else {
612                 struct i2c_command command = {0};
613                 struct i2c_payloads payloads;
614
615                 if (!dal_ddc_i2c_payloads_create(ddc->ctx, &payloads, payloads_num))
616                         return false;
617
618                 command.payloads = dal_ddc_i2c_payloads_get(&payloads);
619                 command.number_of_payloads = 0;
620                 command.engine = DDC_I2C_COMMAND_ENGINE;
621                 command.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
622
623                 dal_ddc_i2c_payloads_add(
624                         &payloads, address, write_size, write_buf, true);
625
626                 dal_ddc_i2c_payloads_add(
627                         &payloads, address, read_size, read_buf, false);
628
629                 command.number_of_payloads =
630                         dal_ddc_i2c_payloads_get_count(&payloads);
631
632                 ret = dm_helpers_submit_i2c(
633                                 ddc->ctx,
634                                 ddc->link,
635                                 &command);
636
637                 dal_ddc_i2c_payloads_destroy(&payloads);
638         }
639
640         return ret;
641 }
642
643 int dc_link_aux_transfer(struct ddc_service *ddc,
644                              unsigned int address,
645                              uint8_t *reply,
646                              void *buffer,
647                              unsigned int size,
648                              enum aux_transaction_type type,
649                              enum i2caux_transaction_action action)
650 {
651         struct ddc *ddc_pin = ddc->ddc_pin;
652         struct aux_engine *aux_engine;
653         enum aux_channel_operation_result operation_result;
654         struct aux_request_transaction_data aux_req;
655         struct aux_reply_transaction_data aux_rep;
656         uint8_t returned_bytes = 0;
657         int res = -1;
658         uint32_t status;
659
660         memset(&aux_req, 0, sizeof(aux_req));
661         memset(&aux_rep, 0, sizeof(aux_rep));
662
663         aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
664         aux_engine->funcs->acquire(aux_engine, ddc_pin);
665
666         aux_req.type = type;
667         aux_req.action = action;
668
669         aux_req.address = address;
670         aux_req.delay = 0;
671         aux_req.length = size;
672         aux_req.data = buffer;
673
674         aux_engine->funcs->submit_channel_request(aux_engine, &aux_req);
675         operation_result = aux_engine->funcs->get_channel_status(aux_engine, &returned_bytes);
676
677         switch (operation_result) {
678         case AUX_CHANNEL_OPERATION_SUCCEEDED:
679                 res = returned_bytes;
680
681                 if (res <= size && res >= 0)
682                         res = aux_engine->funcs->read_channel_reply(aux_engine, size,
683                                                                 buffer, reply,
684                                                                 &status);
685
686                 break;
687         case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
688                 res = 0;
689                 break;
690         case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN:
691         case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
692         case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
693                 res = -1;
694                 break;
695         }
696         aux_engine->funcs->release_engine(aux_engine);
697         return res;
698 }
699
700 /*test only function*/
701 void dal_ddc_service_set_ddc_pin(
702         struct ddc_service *ddc_service,
703         struct ddc *ddc)
704 {
705         ddc_service->ddc_pin = ddc;
706 }
707
708 struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service)
709 {
710         return ddc_service->ddc_pin;
711 }
712
713 void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service,
714                 uint32_t pix_clk,
715                 bool lte_340_scramble)
716 {
717         bool over_340_mhz = pix_clk > 340000 ? 1 : 0;
718         uint8_t slave_address = HDMI_SCDC_ADDRESS;
719         uint8_t offset = HDMI_SCDC_SINK_VERSION;
720         uint8_t sink_version = 0;
721         uint8_t write_buffer[2] = {0};
722         /*Lower than 340 Scramble bit from SCDC caps*/
723
724         dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset,
725                         sizeof(offset), &sink_version, sizeof(sink_version));
726         if (sink_version == 1) {
727                 /*Source Version = 1*/
728                 write_buffer[0] = HDMI_SCDC_SOURCE_VERSION;
729                 write_buffer[1] = 1;
730                 dal_ddc_service_query_ddc_data(ddc_service, slave_address,
731                                 write_buffer, sizeof(write_buffer), NULL, 0);
732                 /*Read Request from SCDC caps*/
733         }
734         write_buffer[0] = HDMI_SCDC_TMDS_CONFIG;
735
736         if (over_340_mhz) {
737                 write_buffer[1] = 3;
738         } else if (lte_340_scramble) {
739                 write_buffer[1] = 1;
740         } else {
741                 write_buffer[1] = 0;
742         }
743         dal_ddc_service_query_ddc_data(ddc_service, slave_address, write_buffer,
744                         sizeof(write_buffer), NULL, 0);
745 }
746
747 void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service)
748 {
749         uint8_t slave_address = HDMI_SCDC_ADDRESS;
750         uint8_t offset = HDMI_SCDC_TMDS_CONFIG;
751         uint8_t tmds_config = 0;
752
753         dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset,
754                         sizeof(offset), &tmds_config, sizeof(tmds_config));
755         if (tmds_config & 0x1) {
756                 union hdmi_scdc_status_flags_data status_data = { {0} };
757                 uint8_t scramble_status = 0;
758
759                 offset = HDMI_SCDC_SCRAMBLER_STATUS;
760                 dal_ddc_service_query_ddc_data(ddc_service, slave_address,
761                                 &offset, sizeof(offset), &scramble_status,
762                                 sizeof(scramble_status));
763                 offset = HDMI_SCDC_STATUS_FLAGS;
764                 dal_ddc_service_query_ddc_data(ddc_service, slave_address,
765                                 &offset, sizeof(offset), status_data.byte,
766                                 sizeof(status_data.byte));
767         }
768 }
769