1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18 #include "drv_hdmi_frl.h"
19 #include "drv_hdmi_compatibility.h"
20 #include "hdmi_osal.h"
21 #include "drv_hdmi_edid.h"
22 #include "hdmi_hal_frl.h"
23
24 #define DATAFLOW_METERING_THR 492
25 #define LINK_TRAINING_TIMEOUT 200
26 #define FRL_MACH_START 0
27 #define FRL_MACH_STOP 1
28 #define FRL_MACH_BUTT 2
29
30 static hi_u32 g_frl_stop = FRL_MACH_BUTT;
31
frl_rate_info_get(hi_u32 frl_rate,hi_u32 * frl_bit_rate,hi_u32 * frl_lane_num)32 static hi_void frl_rate_info_get(hi_u32 frl_rate, hi_u32 *frl_bit_rate, hi_u32 *frl_lane_num)
33 {
34 if (frl_rate <= FRL_WORK_MODE_3L6G) {
35 *frl_lane_num = FRL_3_LANES;
36 } else {
37 *frl_lane_num = FRL_4_LANES;
38 }
39
40 switch (frl_rate) {
41 case FRL_WORK_MODE_3L3G:
42 *frl_bit_rate = DFM_BIT_RATE_3;
43 break;
44 case FRL_WORK_MODE_3L6G:
45 case FRL_WORK_MODE_4L6G:
46 *frl_bit_rate = DFM_BIT_RATE_6;
47 break;
48 case FRL_WORK_MODE_4L8G:
49 *frl_bit_rate = DFM_BIT_RATE_8;
50 break;
51 case FRL_WORK_MODE_4L10G:
52 *frl_bit_rate = DFM_BIT_RATE_10;
53 break;
54 case FRL_WORK_MODE_4L12G:
55 *frl_bit_rate = DFM_BIT_RATE_12;
56 break;
57 default:
58 break;
59 }
60
61 return;
62 }
63
sample_fs_convert_to_audio_rate(hdmi_sample_rate sample_fs)64 static hi_s32 sample_fs_convert_to_audio_rate(hdmi_sample_rate sample_fs)
65 {
66 hi_s32 audio_rate;
67
68 switch (sample_fs) {
69 case HDMI_SAMPLE_RATE_32K:
70 audio_rate = AUDIO_SAMPLE_RATE_32K;
71 break;
72 case HDMI_SAMPLE_RATE_44K:
73 audio_rate = AUDIO_SAMPLE_RATE_44K;
74 break;
75 case HDMI_SAMPLE_RATE_48K:
76 audio_rate = AUDIO_SAMPLE_RATE_48K;
77 break;
78 default:
79 hdmi_warn("error sample fs: %u\n", sample_fs);
80 audio_rate = AUDIO_SAMPLE_RATE_UNKNOWN;
81 break;
82 }
83
84 return audio_rate;
85 }
86
deep_clolor_convert_to_color_depth(hdmi_deep_color deep_color)87 static hi_s32 deep_clolor_convert_to_color_depth(hdmi_deep_color deep_color)
88 {
89 hi_s32 color_depth;
90
91 switch (deep_color) {
92 case HDMI_DEEP_COLOR_24BIT:
93 color_depth = DFM_COLOR_DEPTH_8;
94 break;
95 case HDMI_DEEP_COLOR_30BIT:
96 color_depth = DFM_COLOR_DEPTH_10;
97 break;
98 case HDMI_DEEP_COLOR_36BIT:
99 color_depth = DFM_COLOR_DEPTH_12;
100 break;
101 case HDMI_DEEP_COLOR_48BIT:
102 color_depth = DFM_COLOR_DEPTH_16;
103 break;
104 default:
105 color_depth = DFM_COLOR_DEPTH_8;
106 break;
107 }
108
109 return color_depth;
110 }
111
color_space_convert_to_pixel_format(hdmi_colorspace color_space)112 static hi_s32 color_space_convert_to_pixel_format(hdmi_colorspace color_space)
113 {
114 hi_s32 pixel_format;
115
116 switch (color_space) {
117 case HDMI_COLORSPACE_RGB:
118 pixel_format = DFM_PIXEL_FORMAT_MODE_0;
119 break;
120 case HDMI_COLORSPACE_YCBCR420:
121 pixel_format = DFM_PIXEL_FORMAT_MODE_1;
122 break;
123 case HDMI_COLORSPACE_YCBCR422:
124 pixel_format = DFM_PIXEL_FORMAT_MODE_2;
125 break;
126 case HDMI_COLORSPACE_YCBCR444:
127 pixel_format = DFM_PIXEL_FORMAT_MODE_3;
128 break;
129 default:
130 pixel_format = DFM_PIXEL_FORMAT_MODE_0;
131 break;
132 }
133
134 return pixel_format;
135 }
136
frl_get_format_param(hdmi_video_timing timing,hdmi_picture_aspect aspect,hi_bool _3d_enable)137 static hdmi_video_def *frl_get_format_param(hdmi_video_timing timing,
138 hdmi_picture_aspect aspect, hi_bool _3d_enable)
139 {
140 hdmi_video_code_vic vic;
141 hdmi_video_def *tmp_fmt = HI_NULL;
142
143 if (timing < HDMI_VIDEO_TIMING_VESA_DEFINE) {
144 vic = drv_hdmi_vic_search(timing, aspect, _3d_enable);
145 tmp_fmt = drv_hdmi_comm_format_param_get(vic);
146 } else if (timing < HDMI_VIDEO_TIMING_USER_DEFINE) {
147 tmp_fmt = drv_hdmi_vesa_format_param_get(timing);
148 }
149
150 return tmp_fmt;
151 }
152
frl_tx_ffe_set(const hdmi_device * hdmi_dev)153 static hi_s32 frl_tx_ffe_set(const hdmi_device *hdmi_dev)
154 {
155 hi_s32 ret = HI_SUCCESS;
156 hdmi_phy_cfg phy_cfg = {0};
157
158 phy_cfg.mode_cfg = HDMI_PHY_MODE_CFG_TXFFE;
159 phy_cfg.rate = (hdmi_work_mode)hdmi_dev->frl_info.rate_info.cur_rate;
160
161 #ifndef HDMI_FPGA_SUPPORT
162 hal_call_void(hal_hdmi_phy_set, hdmi_dev->hal, &phy_cfg);
163 #endif
164
165 return ret;
166 }
167
frl_phy_set(hdmi_device * hdmi_dev)168 static hi_void frl_phy_set(hdmi_device *hdmi_dev)
169 {
170 hdmi_phy_cfg phy_cfg = {0};
171 hdmi_app_attr *app_attr = HI_NULL;
172 hdmi_vo_attr *vo_attr = HI_NULL;
173
174 app_attr = &hdmi_dev->attr.app_attr;
175 vo_attr = &hdmi_dev->attr.vo_attr;
176
177 /* PHY config */
178 phy_cfg.emi_enable = hdmi_dev->emi_enable;
179 phy_cfg.pixel_clk = vo_attr->clk_fs;
180 phy_cfg.tmds_clk = vo_attr->hdmi_adapt_pix_clk;
181 phy_cfg.deep_color = app_attr->deep_color_mode;
182 phy_cfg.color_space = app_attr->out_color_space;
183 phy_cfg.trace_len = hdmi_dev->mode_param.trace_len;
184
185 hdmi_info("start mode: %u\n", hdmi_dev->frl_info.mode);
186 if (hdmi_dev->frl_info.mode == HDMI_FRL_MODE_FRL) {
187 phy_cfg.mode_cfg = HDMI_PHY_MODE_CFG_FRL;
188 (hi_void)memset_s(phy_cfg.aen_tx_ffe, sizeof(phy_cfg.aen_tx_ffe), FRL_TXFFE_MODE_0, sizeof(phy_cfg.aen_tx_ffe));
189 phy_cfg.rate = (hdmi_work_mode)hdmi_dev->frl_info.rate_info.cur_rate;
190 }
191
192 hal_call_void(hal_hdmi_phy_output_enable_set, hdmi_dev->hal, HI_FALSE);
193 hal_call_void(hal_hdmi_phy_set, hdmi_dev->hal, &phy_cfg);
194 if (hdmi_dev->frl_info.mode == HDMI_FRL_MODE_TMDS) {
195 hdmi_mode_strategy(hdmi_dev);
196 }
197 hal_call_void(hal_hdmi_ctrl_reset, hdmi_dev->hal);
198 hal_call_void(hal_hdmi_phy_output_enable_set, hdmi_dev->hal, HI_TRUE);
199
200 return;
201 }
202
frl_dfm_construct(dfm_in * dfm,const hdmi_ao_attr * ao_attr,const hdmi_app_attr * app_attr,const hdmi_video_def * video_def)203 static hi_void frl_dfm_construct(dfm_in *dfm, const hdmi_ao_attr *ao_attr,
204 const hdmi_app_attr *app_attr, const hdmi_video_def *video_def)
205 {
206 dfm->hactive = video_def->hactive;
207 dfm->vactive = video_def->vactive;
208 dfm->hblank = video_def->hblank;
209 dfm->vblank = video_def->vblank;
210 dfm->hfront = video_def->hfront;
211 dfm->hsync = video_def->hsync;
212 dfm->hback = video_def->hback;
213 dfm->vfront = video_def->vfront;
214 dfm->vsync = video_def->vsync;
215 dfm->vback = video_def->vback;
216 dfm->v_freq = video_def->rate;
217 dfm->color_depth = deep_clolor_convert_to_color_depth(app_attr->deep_color_mode);
218 dfm->pixel_format = color_space_convert_to_pixel_format(app_attr->out_color_space);
219 dfm->audio_rate = sample_fs_convert_to_audio_rate(ao_attr->sample_fs);
220 dfm->layout = (ao_attr->channels > HDMI_AUDIO_FORMAT_2CH) ? HI_TRUE : HI_FALSE;
221 /* ACAT packet_type */
222 dfm->acat = AUDIO_CHANNEL_ALLOC_TYPE3;
223 dfm->packet_type = AUDIO_SAMPLE_PACKET;
224
225 return;
226 }
227
frl_get_sink_version(hdmi_device_id hdmi_id)228 static hi_u8 frl_get_sink_version(hdmi_device_id hdmi_id)
229 {
230 hi_s32 ret;
231 hi_u8 sink_ver = 0;
232 hdmi_device *hdmi_dev = HI_NULL;
233
234 hdmi_dev = get_hdmi_device(hdmi_id);
235 hal_call_ret(ret, hal_hdmi_scdc_process, hdmi_dev->hal, SCDC_CMD_GET_SINK_VER, &sink_ver);
236 sink_ver = (ret != HI_SUCCESS) ? 0 : sink_ver;
237
238 return sink_ver;
239 }
240
frl_get_flt_update(hdmi_device * hdmi_dev)241 static hi_bool frl_get_flt_update(hdmi_device *hdmi_dev)
242 {
243 hi_s32 ret;
244 hi_bool flt_update = HI_FALSE;
245
246 hal_call_ret(ret, hal_hdmi_scdc_process, hdmi_dev->hal, SCDC_CMD_GET_FLT_UPDATE, &flt_update);
247 flt_update = (ret != HI_SUCCESS) ? HI_FALSE : flt_update;
248
249 return flt_update;
250 }
251
frl_set_flt_update(hdmi_device * hdmi_dev,hi_bool flt_update)252 static hi_void frl_set_flt_update(hdmi_device *hdmi_dev, hi_bool flt_update)
253 {
254 hal_call_void(hal_hdmi_scdc_process, hdmi_dev->hal, SCDC_CMD_SET_FLT_UPDATE, &flt_update);
255 return;
256 }
257
frl_get_frl_start(hdmi_device * hdmi_dev)258 static hi_bool frl_get_frl_start(hdmi_device *hdmi_dev)
259 {
260 hi_bool flt_start = HI_FALSE;
261 hal_call_void(hal_hdmi_scdc_process, hdmi_dev->hal, SCDC_CMD_GET_FRL_START, &flt_start);
262 return flt_start;
263 }
264
frl_set_frl_start(hdmi_device * hdmi_dev,hi_bool flt_start)265 static hi_void frl_set_frl_start(hdmi_device *hdmi_dev, hi_bool flt_start)
266 {
267 hal_call_void(hal_hdmi_scdc_process, hdmi_dev->hal, SCDC_CMD_SET_FRL_START, &flt_start);
268 return;
269 }
270
frl_get_test_config(hdmi_device * hdmi_dev,scdc_test_config * test_cfg)271 static hi_void frl_get_test_config(hdmi_device *hdmi_dev, scdc_test_config *test_cfg)
272 {
273 hal_call_void(hal_hdmi_scdc_process, hdmi_dev->hal, SCDC_CMD_GET_TEST_CONFIG, test_cfg);
274 return;
275 }
276
frl_set_config1(hdmi_device * hdmi_dev,scdc_config1 * cfg)277 static hi_void frl_set_config1(hdmi_device *hdmi_dev, scdc_config1 *cfg)
278 {
279 hal_call_void(hal_hdmi_scdc_process, hdmi_dev->hal, SCDC_CMD_SET_CONFIG1, cfg);
280 return;
281 }
282
frl_get_flt_ready(hdmi_device * hdmi_dev)283 static hi_bool frl_get_flt_ready(hdmi_device *hdmi_dev)
284 {
285 hi_bool flt_ready = HI_FALSE;
286 hal_call_void(hal_hdmi_scdc_process, hdmi_dev->hal, SCDC_CMD_GET_FLT_READY, &flt_ready);
287 return flt_ready;
288 }
289
frl_check_capability(hdmi_device * hdmi_dev)290 static hi_s32 frl_check_capability(hdmi_device *hdmi_dev)
291 {
292 hdmi_tx_capability_data tx_cap = {0};
293 hdmi_sink_capability *sink_cap = HI_NULL;
294 hdmi_frl_info *curr_frl_info = HI_NULL;
295 hdmi_edid_data edid_ret;
296 hi_s32 ret;
297 hi_bool support_frl = HI_FALSE;
298 hi_u32 sink_scdc_ver;
299
300 curr_frl_info = &hdmi_dev->frl_info;
301 hal_call_void(hal_hdmi_tx_capability_get, hdmi_dev->hal, &tx_cap);
302 edid_ret = drv_hdmi_edid_capability_get(&hdmi_dev->edid_info, &sink_cap);
303 if (edid_ret == HDMI_EDID_DATA_INVALID) {
304 hdmi_warn("invalid edid_capability from sink!\n");
305 return (hi_s32)edid_ret;
306 }
307 sink_scdc_ver = frl_get_sink_version(hdmi_dev->hdmi_dev_id);
308 hdmi_info("tx_hdmi_21:%u, max_frl_rate:%u, support_scdc:%u, scdc_version:%u\n",
309 tx_cap.tx_hdmi_21, sink_cap->max_frl_rate, sink_cap->support_scdc, sink_scdc_ver);
310
311 support_frl = ((tx_cap.tx_hdmi_21) && (sink_cap->max_frl_rate > 0) &&
312 (sink_cap->support_scdc) && (sink_scdc_ver != 0)) ? HI_TRUE : HI_FALSE;
313
314 if (support_frl || hdmi_dev->attr.app_attr.auth_mode == HI_TRUE) {
315 if (hdmi_dev->attr.app_attr.auth_mode == HI_TRUE) {
316 curr_frl_info->rate_info.max_rate = tx_cap.tx_max_frl_rate;
317 } else {
318 curr_frl_info->rate_info.max_rate = (sink_cap->max_frl_rate > tx_cap.tx_max_frl_rate) ?
319 tx_cap.tx_max_frl_rate : sink_cap->max_frl_rate;
320 }
321 ret = HI_SUCCESS;
322 hdmi_info("frl check capability success\n");
323 } else {
324 curr_frl_info->rate_info.max_rate = 0;
325 ret = HI_FAILURE;
326 hdmi_info("frl check capability fail\n");
327 }
328 curr_frl_info->scdc_present = sink_cap->support_scdc;
329
330 return ret;
331 }
332
frl_strategy_check_fmt(hdmi_frl_strategy_mode mode,const hdmi_vo_attr * vo_attr,hdmi_video_format_type type)333 static hi_bool frl_strategy_check_fmt(hdmi_frl_strategy_mode mode, const hdmi_vo_attr *vo_attr,
334 hdmi_video_format_type type)
335 {
336 hi_bool frl_fmt = HI_TRUE;
337
338 switch (mode) {
339 case HDMI_FRL_STRATEGY_MODE_1:
340 if (vo_attr->hdmi_adapt_pix_clk <= HDMI_EDID_MAX_HDMI20_TMDS_RATE &&
341 vo_attr->clk_fs <= HDMI_EDID_MAX_HDMI20_TMDS_RATE) {
342 hdmi_info("hdmi_adapt_pix_clk(%u) pixel clk(%u)\n", vo_attr->hdmi_adapt_pix_clk, vo_attr->clk_fs);
343 frl_fmt = HI_FALSE;
344 }
345 break;
346 case HDMI_FRL_STRATEGY_MODE_2:
347 if (vo_attr->hdmi_adapt_pix_clk <= HDMI_EDID_MAX_HDMI14_TMDS_RATE) {
348 frl_fmt = HI_FALSE;
349 }
350 break;
351 case HDMI_FRL_STRATEGY_MODE_3:
352 if (type == HDMI_VIDEO_INTERLACE) {
353 frl_fmt = HI_FALSE;
354 }
355 break;
356 default:
357 break;
358 }
359
360 return frl_fmt;
361 }
362
frl_check_format(hdmi_frl_info * curr_frl_info,const hdmi_attr * attr)363 static hi_bool frl_check_format(hdmi_frl_info *curr_frl_info, const hdmi_attr *attr)
364 {
365 hi_u32 i;
366 hi_u8 max_rate;
367 hi_bool _3d_enable = HI_FALSE;
368 hi_bool capable = HI_FALSE;
369 dfm_in dfm = {0};
370 const hdmi_vo_attr *vo_attr = HI_NULL;
371 const hdmi_ao_attr *ao_attr = HI_NULL;
372 const hdmi_app_attr *app_attr = HI_NULL;
373 hdmi_video_def *video_def = HI_NULL;
374
375 vo_attr = &attr->vo_attr;
376 ao_attr = &attr->ao_attr;
377 app_attr = &attr->app_attr;
378 max_rate = curr_frl_info->rate_info.max_rate;
379
380 _3d_enable = (vo_attr->stereo_mode == HDMI_3D_BUTT) ? HI_FALSE : HI_TRUE;
381 video_def = frl_get_format_param(vo_attr->video_timing, vo_attr->picture_aspect, _3d_enable);
382 if (video_def == HI_NULL) {
383 hdmi_warn("no this fmt's param, transmit by tmds.\n");
384 return HI_FALSE;
385 }
386
387 hdmi_info("video_code: %u\n", video_def->video_code);
388 curr_frl_info->tmds_clk = vo_attr->hdmi_adapt_pix_clk;
389 if (frl_strategy_check_fmt(curr_frl_info->strategy_mode, vo_attr, video_def->pi_type) == HI_FALSE) {
390 return HI_FALSE;
391 }
392
393 frl_dfm_construct(&dfm, ao_attr, app_attr, video_def);
394 if (max_rate > FRL_WORK_MODE_4L12G) {
395 max_rate = FRL_WORK_MODE_4L12G;
396 hdmi_info("sink's max FRL rate maybe wrong(%u)\n", curr_frl_info->rate_info.max_rate);
397 return HI_TRUE;
398 }
399
400 for (i = max_rate; i > 0; i--) {
401 frl_rate_info_get(i, &dfm.bit_rate, &dfm.lane_num);
402 if (drv_hdmi_dfm_format_support(&dfm) == HI_TRUE) {
403 curr_frl_info->rate_info.min_rate = i;
404 hdmi_info("min_rate: %u\n", curr_frl_info->rate_info.min_rate);
405 } else {
406 break;
407 }
408 }
409
410 capable = (i == max_rate) ? HI_FALSE : HI_TRUE;
411 hdmi_info("max FRL rate(%u), video_code(%u) can %s be transmitted.\n",
412 max_rate, video_def->video_code, (capable == HI_FALSE) ? "not" : "");
413
414 return capable;
415 }
416
frl_set_train_rate(hdmi_device * hdmi_dev)417 static hi_void frl_set_train_rate(hdmi_device *hdmi_dev)
418 {
419 hdmi_frl_info *curr_frl_info = HI_NULL;
420 scdc_config1 cfg = {0};
421
422 curr_frl_info = &hdmi_dev->frl_info;
423
424 if (curr_frl_info->mode == HDMI_FRL_MODE_FRL) {
425 cfg.ffe_levels = FRL_TXFFE_MODE_0;
426 cfg.frl_rate = curr_frl_info->rate_info.cur_rate;
427 } else {
428 cfg.ffe_levels = 0;
429 cfg.frl_rate = 0;
430 }
431 frl_set_config1(hdmi_dev, &cfg);
432
433 return;
434 }
435
frl_is_cts_mode(hdmi_device * hdmi_dev)436 static hi_bool frl_is_cts_mode(hdmi_device *hdmi_dev)
437 {
438 hi_bool ret = HI_FALSE;
439 scdc_test_config test_cfg = {0};
440
441 frl_get_test_config(hdmi_dev, &test_cfg);
442 ret = ((test_cfg.frl_max == 1 && test_cfg.dsc_frl_max == 0) ||
443 (test_cfg.frl_max == 0 && test_cfg.dsc_frl_max == 1)) ? HI_TRUE : HI_FALSE;
444
445 return ret;
446 }
447
frl_get_cur_rate(hdmi_frl_info * curr_frl_info)448 static hi_s32 frl_get_cur_rate(hdmi_frl_info *curr_frl_info)
449 {
450 hi_s32 ret = HI_SUCCESS;
451 hi_u8 cur_frl_rate;
452 static hi_u8 pre_rate;
453
454 cur_frl_rate = curr_frl_info->rate_info.cur_rate;
455 if (curr_frl_info->cts_mode == HI_TRUE) {
456 pre_rate = cur_frl_rate;
457 cur_frl_rate = curr_frl_info->rate_info.max_rate;
458 } else {
459 if (pre_rate != 0) {
460 cur_frl_rate = pre_rate;
461 pre_rate = 0;
462 } else {
463 if (curr_frl_info->rate_select == HDMI_FRL_RATE_SELECT_BIG) {
464 cur_frl_rate--;
465 } else {
466 cur_frl_rate++;
467 }
468 if ((cur_frl_rate > curr_frl_info->rate_info.max_rate) ||
469 (cur_frl_rate < curr_frl_info->rate_info.min_rate)) {
470 return HI_FAILURE;
471 }
472 }
473 }
474 curr_frl_info->rate_info.cur_rate = cur_frl_rate;
475
476 return ret;
477 }
478
frl_n_cts_config(hdmi_device * hdmi_dev)479 static hi_void frl_n_cts_config(hdmi_device *hdmi_dev)
480 {
481 hdmi_audio_ncts audio_cfg = {0};
482
483 audio_cfg.hdmi_mode = hdmi_dev->frl_info.mode;
484 audio_cfg.sample_rate = hdmi_dev->attr.ao_attr.sample_fs;
485
486 if (audio_cfg.hdmi_mode == HDMI_FRL_MODE_FRL) {
487 audio_cfg.frl_rate = hdmi_dev->frl_info.rate_info.cur_rate;
488 } else {
489 audio_cfg.pixel_clk = hdmi_dev->attr.vo_attr.clk_fs;
490 }
491 hal_call_void(hal_hdmi_audio_n_cts_set, hdmi_dev->hal, &audio_cfg);
492
493 return;
494 }
495
frl_train_exception(hdmi_device * hdmi_dev)496 static hi_void frl_train_exception(hdmi_device *hdmi_dev)
497 {
498 hdmi_phy_cfg phy_cfg = {0};
499 hdmi_frl_info *curr_frl_info = HI_NULL;
500 hdmi_app_attr *app_attr = HI_NULL;
501 hdmi_vo_attr *vo_attr = HI_NULL;
502 hdmi_frl_state_mach_info *mach_info = HI_NULL;
503
504 curr_frl_info = &hdmi_dev->frl_info;
505 mach_info = &curr_frl_info->state_mach_info;
506 app_attr = &hdmi_dev->attr.app_attr;
507 vo_attr = &hdmi_dev->attr.vo_attr;
508
509 hdmi_err("FRL error!\n");
510 #ifndef HDMI_FPGA_SUPPORT
511 hal_call_void(hal_hdmi_phy_output_enable_set, hdmi_dev->hal, HI_FALSE);
512 #endif
513 mach_info->train_status = HDMI_FRL_TRAIN_STEP_STOP;
514 curr_frl_info->start = HI_FALSE;
515 mach_info->start_time = hdmi_osal_get_time_in_ms();
516
517 if (curr_frl_info->fail_strategy != HDMI_FRL_FAIL_TMDS) {
518 hdmi_err("FRL error, nothing to do!\n");
519 return;
520 }
521 /* PHY configs */
522 phy_cfg.emi_enable = hdmi_dev->emi_enable;
523 phy_cfg.pixel_clk = vo_attr->clk_fs;
524 phy_cfg.tmds_clk = vo_attr->hdmi_adapt_pix_clk;
525 phy_cfg.deep_color = app_attr->deep_color_mode;
526 phy_cfg.mode_cfg = HDMI_FRL_MODE_TMDS;
527 phy_cfg.color_space = app_attr->out_color_space;
528 hdmi_err("FRL error, change to TMDS!\n");
529 if (phy_cfg.tmds_clk > HDMI_EDID_MAX_HDMI20_TMDS_RATE) {
530 hdmi_err("TMDS clk > 600M. can't work TMDS mode. \n");
531 return;
532 }
533 curr_frl_info->mode = HDMI_FRL_MODE_TMDS;
534 if (curr_frl_info->scdc_present == HI_TRUE) {
535 frl_set_train_rate(hdmi_dev);
536 }
537 frl_n_cts_config(hdmi_dev);
538 #ifndef HDMI_FPGA_SUPPORT
539 hal_call_void(hal_hdmi_phy_set, hdmi_dev->hal, &phy_cfg);
540 hdmi_mode_strategy(hdmi_dev);
541 hal_call_void(hal_hdmi_phy_output_enable_set, hdmi_dev->hal, HI_TRUE);
542 #endif
543
544 return;
545 }
546
frl_config_and_start_train(hdmi_device * hdmi_dev)547 static hi_void frl_config_and_start_train(hdmi_device *hdmi_dev)
548 {
549 hi_u32 frl_rate;
550 hdmi_frl_train_config train_config = {0};
551 hdmi_frl_info *curr_frl_info = HI_NULL;
552 scdc_test_config test_cfg = {0};
553 compatibility_info *compat_info = HI_NULL;
554
555 compat_info = compat_info_get(hdmi_dev->hdmi_dev_id);
556 hdmi_if_null_return_void(compat_info);
557
558 curr_frl_info = &hdmi_dev->frl_info;
559 frl_rate = curr_frl_info->rate_info.cur_rate;
560
561 train_config.frl_rate = frl_rate;
562 train_config.ffe_levels = FRL_TXFFE_MODE_0;
563 frl_get_test_config(hdmi_dev, &test_cfg);
564 train_config.frl_no_timeout = test_cfg.flt_no_timeout;
565 hdmi_info("frl_rate %u, frl_no_timeout %u.\n", frl_rate, train_config.frl_no_timeout);
566 train_config.mach_mode = hdmi_dev->frl_info.state_mach_info.mach_mode;
567 train_config.train_timeout = hdmi_dev->frl_info.state_mach_info.train_timeout;
568 train_config.sw_train_mode = hdmi_dev->frl_info.state_mach_info.sw_train_mode;
569 train_config.ctl_type_config = compat_info->ctl_type_config;
570
571 hal_call_void(hal_hdmi_frl_train_config, hdmi_dev->hal, &train_config);
572 hal_call_void(hal_hdmi_frl_enable, hdmi_dev->hal, HI_FALSE);
573 hal_call_void(hal_hdmi_frl_train_start, hdmi_dev->hal);
574
575 return;
576 }
577
frl_get_train_result(hdmi_device * hdmi_dev,hdmi_frl_train * train_status)578 static hi_void frl_get_train_result(hdmi_device *hdmi_dev, hdmi_frl_train *train_status)
579 {
580 hdmi_if_null_return_void(hdmi_dev);
581 hdmi_if_null_return_void(train_status);
582 hal_call_void(hal_hdmi_frl_get_train_status, hdmi_dev->hal, train_status);
583 return;
584 }
585
frl_enable_output(hdmi_device * hdmi_dev,hi_bool enable)586 static hi_void frl_enable_output(hdmi_device *hdmi_dev, hi_bool enable)
587 {
588 hdmi_if_null_return_void(hdmi_dev);
589 hal_call_void(hal_hdmi_frl_enable, hdmi_dev->hal, enable);
590 return;
591 }
592
drv_hdmi_frl_mach_init(hdmi_device_id hdmi_id)593 hi_void drv_hdmi_frl_mach_init(hdmi_device_id hdmi_id)
594 {
595 hdmi_device *hdmi_dev = HI_NULL;
596 hdmi_frl_info *curr_frl_info = HI_NULL;
597 hdmi_frl_state_mach_info *mach_info = HI_NULL;
598
599 hdmi_dev = get_hdmi_device(hdmi_id);
600 hdmi_if_null_return_void(hdmi_dev);
601
602 curr_frl_info = &hdmi_dev->frl_info;
603 mach_info = &curr_frl_info->state_mach_info;
604
605 if (mach_info->start_mach != HI_TRUE) {
606 curr_frl_info->strategy_mode = HDMI_FRL_STRATEGY_MODE_1;
607 mach_info->start_mach = HI_TRUE;
608 mach_info->start_time = hdmi_osal_get_time_in_ms();
609 mach_info->wait_handle_ms = 100; /* 100: FRL training machine RESULT_HANDLE timeout interval */
610 mach_info->wait_ready_ms = 20; /* 20: FRL training machine READY_CHECK timeout interval */
611 mach_info->wait_retrain_ms = 500; /* 500: FRL training machine RETRAIN_CHECK timeout interval */
612 mach_info->train_status = HDMI_FRL_TRAIN_STEP_BUTT;
613 curr_frl_info->rate_select = HDMI_FRL_RATE_SELECT_LITTLE;
614 curr_frl_info->max_fail_times = 3; /* 3: max training times if training failed */
615 curr_frl_info->work_en = HI_FALSE;
616 curr_frl_info->fail_strategy = HDMI_FRL_FAIL_NONE;
617 curr_frl_info->state_mach_info.mach_mode = HDMI_FRL_MACH_MODE_TIMEOUT;
618 curr_frl_info->state_mach_info.train_timeout = LINK_TRAINING_TIMEOUT;
619 curr_frl_info->state_mach_info.sw_train_mode = FRL_SW_TRAIN_TIMER;
620 curr_frl_info->rate_info.debug_rate = FRL_WORK_MODE_NONE;
621 curr_frl_info->mode = HDMI_FRL_MODE_TMDS;
622 (hi_void)memset_s(curr_frl_info->aen_cur_tx_ffe, sizeof(curr_frl_info->aen_cur_tx_ffe),
623 FRL_TXFFE_MODE_0, sizeof(curr_frl_info->aen_cur_tx_ffe));
624 }
625
626 return;
627 }
628
drv_hdmi_frl_enable(hdmi_device_id hdmi_id,hi_bool enable)629 hi_void drv_hdmi_frl_enable(hdmi_device_id hdmi_id, hi_bool enable)
630 {
631 hdmi_device *hdmi_dev = HI_NULL;
632 hdmi_frl_info *curr_frl_info = HI_NULL;
633 hdmi_frl_state_mach_info *mach_info = HI_NULL;
634
635 hdmi_dev = get_hdmi_device(hdmi_id);
636 hdmi_if_null_return_void(hdmi_dev);
637
638 curr_frl_info = &hdmi_dev->frl_info;
639 mach_info = &curr_frl_info->state_mach_info;
640
641 curr_frl_info->start = enable;
642 if (curr_frl_info->rate_info.debug_rate != 0) {
643 hdmi_info("debug mode, use the rate:%u\n", curr_frl_info->rate_info.cur_rate);
644 curr_frl_info->rate_info.cur_rate = curr_frl_info->rate_info.debug_rate;
645 }
646
647 curr_frl_info->cts_mode = frl_is_cts_mode(hdmi_dev);
648 if (curr_frl_info->cts_mode == HI_TRUE) {
649 frl_get_cur_rate(curr_frl_info);
650 hdmi_info("cts mode, use the maxmum rate:%u\n", curr_frl_info->rate_info.cur_rate);
651 }
652
653 g_frl_stop = (enable == HI_TRUE) ? FRL_MACH_START : FRL_MACH_STOP;
654 mach_info->start_time = hdmi_osal_get_time_in_ms();
655 hdmi_info("cur_rate(%u), enable: %u, train_status:%u, start_time:%llu\n",
656 curr_frl_info->rate_info.cur_rate, enable,
657 mach_info->train_status, mach_info->start_time);
658
659 return;
660 }
661
drv_hdmi_frl_mode_strategy(hdmi_device_id hdmi_id)662 hi_s32 drv_hdmi_frl_mode_strategy(hdmi_device_id hdmi_id)
663 {
664 hi_s32 ret;
665 hdmi_device *hdmi_dev = HI_NULL;
666 hdmi_attr *attr = HI_NULL;
667 hdmi_frl_info *curr_frl_info = HI_NULL;
668 hi_u8 *cur_frl_rate = HI_NULL;
669
670 hdmi_dev = get_hdmi_device(hdmi_id);
671 hdmi_if_null_return(hdmi_dev, HI_FAILURE);
672
673 attr = &hdmi_dev->attr;
674 curr_frl_info = &hdmi_dev->frl_info;
675 cur_frl_rate = &curr_frl_info->rate_info.cur_rate;
676
677 ret = frl_check_capability(hdmi_dev);
678 if (ret == HDMI_EDID_DATA_INVALID) {
679 return ret;
680 } else if (ret != HI_SUCCESS) {
681 hdmi_info("frl_check_capability fail, change to TMDS\n");
682 curr_frl_info->mode = HDMI_FRL_MODE_TMDS;
683 } else {
684 if (frl_check_format(curr_frl_info, attr) != HI_TRUE) {
685 hdmi_info("frl_check_format fail, change to TMDS\n");
686 curr_frl_info->mode = HDMI_FRL_MODE_TMDS;
687 } else {
688 hdmi_info("frl_check_capability success, FRL mode\n");
689 curr_frl_info->mode = HDMI_FRL_MODE_FRL;
690 }
691 }
692
693 if (curr_frl_info->mode == HDMI_FRL_MODE_TMDS) {
694 if (attr->vo_attr.hdmi_adapt_pix_clk > HDMI_EDID_MAX_HDMI20_TMDS_RATE) {
695 hdmi_err("this format not support!\n");
696 return HI_FAILURE;
697 }
698 if (curr_frl_info->scdc_present == HI_TRUE) {
699 frl_set_train_rate(hdmi_dev);
700 }
701 } else {
702 if (curr_frl_info->rate_info.debug_rate != FRL_WORK_MODE_NONE) {
703 *cur_frl_rate = curr_frl_info->rate_info.debug_rate;
704 } else {
705 *cur_frl_rate = (curr_frl_info->rate_select == HDMI_FRL_RATE_SELECT_BIG) ?
706 curr_frl_info->rate_info.max_rate : curr_frl_info->rate_info.min_rate;
707 }
708 hdmi_dev->tmds_mode = HDMI_TMDS_MODE_HDMI_2_0;
709 hal_call_void(hal_hdmi_tmds_mode_set, hdmi_dev->hal, hdmi_dev->tmds_mode);
710 curr_frl_info->cts_mode = HI_FALSE;
711 }
712
713 return HI_SUCCESS;
714 }
715
frl_training_result_check_step(hdmi_device * hdmi_dev,hdmi_frl_train_step * train_step)716 static hi_void frl_training_result_check_step(hdmi_device *hdmi_dev, hdmi_frl_train_step *train_step)
717 {
718 hdmi_frl_info *curr_frl_info = HI_NULL;
719 hdmi_frl_train *train_status = HI_NULL;
720
721 curr_frl_info = &hdmi_dev->frl_info;
722 train_status = &curr_frl_info->train_status;
723
724 frl_get_train_result(hdmi_dev, train_status);
725 if (train_status->frl_train_status == HDMI_FRL_TRAIN_SUCCESS) {
726 *train_step = HDMI_FRL_TRAIN_STEP_RESULT_HANDLE;
727 curr_frl_info->fail_count = 0;
728 } else if (train_status->train_fail_res == HDMI_FRL_TRAIN_FAIL_FFECHANGE) {
729 hdmi_err("TXFFE change\n");
730 frl_tx_ffe_set(hdmi_dev);
731 *train_step = HDMI_FRL_TRAIN_STEP_TRAIN_START;
732 curr_frl_info->fail_count = 0;
733 } else if (train_status->train_fail_res == HDMI_FRL_TRAIN_FAIL_RATECHANGE) {
734 *train_step = HDMI_FRL_TRAIN_STEP_RATE_CHANGE;
735 curr_frl_info->fail_count = 0;
736 } else {
737 curr_frl_info->fail_count++;
738 }
739
740 return;
741 }
742
frl_training_rate_change_step(hdmi_device * hdmi_dev,hdmi_frl_train_step * train_step)743 static hi_void frl_training_rate_change_step(hdmi_device *hdmi_dev, hdmi_frl_train_step *train_step)
744 {
745 hdmi_frl_info *curr_frl_info = HI_NULL;
746 hdmi_frl_state_mach_info *mach_info = HI_NULL;
747
748 curr_frl_info = &hdmi_dev->frl_info;
749 mach_info = &curr_frl_info->state_mach_info;
750
751 curr_frl_info->cts_mode = frl_is_cts_mode(hdmi_dev);
752 if (frl_get_cur_rate(curr_frl_info) != HI_SUCCESS) {
753 hdmi_err("FRL rate %u get failed!\n", curr_frl_info->rate_info.cur_rate);
754 frl_train_exception(hdmi_dev);
755 *train_step = mach_info->train_status;
756 return;
757 }
758 /* FRL rate change */
759 frl_phy_set(hdmi_dev);
760 frl_set_train_rate(hdmi_dev);
761 *train_step = HDMI_FRL_TRAIN_STEP_TRAIN_START;
762
763 return;
764 }
765
frl_start_check_step(hdmi_device * hdmi_dev,hi_u32 * timeout,hdmi_frl_train_step * train_step)766 static hi_void frl_start_check_step(hdmi_device *hdmi_dev, hi_u32 *timeout, hdmi_frl_train_step *train_step)
767 {
768 hdmi_frl_info *curr_frl_info = HI_NULL;
769
770 curr_frl_info = &hdmi_dev->frl_info;
771 if (frl_get_frl_start(hdmi_dev) == HI_TRUE) {
772 hdmi_info("frl_start get...\n");
773 if (curr_frl_info->start) {
774 hdmi_info("training pass...\n");
775 curr_frl_info->work_en = HI_TRUE;
776 /* n/cts config */
777 frl_n_cts_config(hdmi_dev);
778 osal_msleep(1);
779 frl_enable_output(hdmi_dev, curr_frl_info->work_en);
780 osal_msleep(1);
781 frl_set_frl_start(hdmi_dev, HI_TRUE);
782 *timeout = 0;
783 *train_step = HDMI_FRL_TRAIN_STEP_RETRAIN_CHECK;
784 }
785 }
786
787 return;
788 }
789
frl_retraining_check_step(hdmi_device * hdmi_dev)790 static hi_void frl_retraining_check_step(hdmi_device *hdmi_dev)
791 {
792 hdmi_frl_info *curr_frl_info = HI_NULL;
793 hdmi_frl_state_mach_info *mach_info = HI_NULL;
794
795 curr_frl_info = &hdmi_dev->frl_info;
796 mach_info = &curr_frl_info->state_mach_info;
797 if (frl_get_flt_update(hdmi_dev) == HI_TRUE) {
798 hdmi_info("RETRAIN_CHECK flt_update get...\n");
799 frl_set_flt_update(hdmi_dev, HI_TRUE);
800 curr_frl_info->work_en = HI_FALSE;
801 frl_enable_output(hdmi_dev, curr_frl_info->work_en);
802 mach_info->train_status = HDMI_FRL_TRAIN_STEP_TRAIN_START;
803 }
804
805 return;
806 }
807
frl_training_ready_check_step(hdmi_device * hdmi_dev)808 static hi_void frl_training_ready_check_step(hdmi_device *hdmi_dev)
809 {
810 hdmi_frl_state_mach_info *mach_info = HI_NULL;
811
812 mach_info = &hdmi_dev->frl_info.state_mach_info;
813 if (frl_get_flt_ready(hdmi_dev) == HI_TRUE) {
814 hdmi_info("READY_CHECK, start training.\n");
815 frl_phy_set(hdmi_dev);
816 frl_set_train_rate(hdmi_dev);
817 mach_info->train_status = HDMI_FRL_TRAIN_STEP_TRAIN_START;
818 }
819
820 return;
821 }
822
frl_training_step_mode(hdmi_device * hdmi_dev)823 static hi_void frl_training_step_mode(hdmi_device *hdmi_dev)
824 {
825 hi_u64 start_time;
826 static hi_u32 timeout;
827 hdmi_frl_info *curr_frl_info = HI_NULL;
828 hdmi_frl_state_mach_info *mach_info = HI_NULL;
829
830 curr_frl_info = &hdmi_dev->frl_info;
831 mach_info = &curr_frl_info->state_mach_info;
832 start_time = mach_info->start_time;
833 switch (mach_info->train_status) {
834 case HDMI_FRL_TRAIN_STEP_READY_CHECK:
835 frl_training_ready_check_step(hdmi_dev);
836 break;
837 case HDMI_FRL_TRAIN_STEP_TRAIN_START:
838 frl_config_and_start_train(hdmi_dev);
839 mach_info->train_status = HDMI_FRL_TRAIN_STEP_RESULT_CHECK;
840 break;
841 case HDMI_FRL_TRAIN_STEP_RESULT_CHECK:
842 frl_training_result_check_step(hdmi_dev, &mach_info->train_status);
843 break;
844 case HDMI_FRL_TRAIN_STEP_RATE_CHANGE:
845 frl_training_rate_change_step(hdmi_dev, &mach_info->train_status);
846 break;
847 case HDMI_FRL_TRAIN_STEP_RESULT_HANDLE:
848 frl_start_check_step(hdmi_dev, &timeout, &mach_info->train_status);
849 break;
850 case HDMI_FRL_TRAIN_STEP_RETRAIN_CHECK:
851 frl_retraining_check_step(hdmi_dev);
852 break;
853 case HDMI_FRL_TRAIN_STEP_STOP:
854 curr_frl_info->work_en = HI_FALSE;
855 frl_enable_output(hdmi_dev, curr_frl_info->work_en);
856 start_time = hdmi_osal_get_time_in_ms();
857 mach_info->train_status = HDMI_FRL_TRAIN_STEP_BUTT;
858 break;
859 default:
860 break;
861 }
862 mach_info->start_time = start_time;
863
864 return;
865 }
866
frl_training_ready_check_timeout(hdmi_device * hdmi_dev,hi_u64 * start_time,hi_u32 * timeout)867 static hi_void frl_training_ready_check_timeout(hdmi_device *hdmi_dev, hi_u64 *start_time, hi_u32 *timeout)
868 {
869 hdmi_frl_info *curr_frl_info = HI_NULL;
870 hdmi_frl_state_mach_info *mach_info = HI_NULL;
871
872 curr_frl_info = &hdmi_dev->frl_info;
873 mach_info = &curr_frl_info->state_mach_info;
874
875 if ((hdmi_osal_get_time_in_ms() - *start_time) > mach_info->wait_ready_ms) {
876 if (frl_get_flt_ready(hdmi_dev) == HI_TRUE) {
877 hdmi_info("start training\n");
878 frl_phy_set(hdmi_dev);
879 frl_set_train_rate(hdmi_dev);
880 *timeout = 0;
881 mach_info->train_status = HDMI_FRL_TRAIN_STEP_TRAIN_START;
882 } else {
883 *timeout += 1;
884 }
885 *start_time = hdmi_osal_get_time_in_ms();
886 } else {
887 /* wait for a maximum of 10 times, (wait_ready_ms * 10) ms */
888 if (*timeout < 10) {
889 return;
890 }
891
892 hdmi_info("READY_CHECK exception: %u\n", *timeout);
893 *timeout = 0;
894 if (curr_frl_info->bypass & FRL_BYPASS_READY_CHECK) {
895 hdmi_info("READY_CHECK bypass, goto TRAIN_START!\n");
896 mach_info->train_status = HDMI_FRL_TRAIN_STEP_TRAIN_START;
897 return;
898 }
899 frl_train_exception(hdmi_dev);
900 }
901
902 return;
903 }
904
frl_training_result_check_timeout(hdmi_device * hdmi_dev)905 static hi_void frl_training_result_check_timeout(hdmi_device *hdmi_dev)
906 {
907 hdmi_frl_info *curr_frl_info = HI_NULL;
908 hdmi_frl_train *train_status = HI_NULL;
909 hdmi_frl_state_mach_info *mach_info = HI_NULL;
910
911 curr_frl_info = &hdmi_dev->frl_info;
912 mach_info = &curr_frl_info->state_mach_info;
913 train_status = &curr_frl_info->train_status;
914
915 frl_get_train_result(hdmi_dev, train_status);
916 if (train_status->frl_train_status == HDMI_FRL_TRAIN_SUCCESS) {
917 mach_info->train_status = HDMI_FRL_TRAIN_STEP_RESULT_HANDLE;
918 curr_frl_info->fail_count = 0;
919 } else if (train_status->train_fail_res == HDMI_FRL_TRAIN_FAIL_FFECHANGE) {
920 hdmi_err("TXFFE change\n");
921 frl_tx_ffe_set(hdmi_dev);
922 mach_info->train_status = HDMI_FRL_TRAIN_STEP_TRAIN_START;
923 curr_frl_info->fail_count = 0;
924 } else if (train_status->train_fail_res == HDMI_FRL_TRAIN_FAIL_RATECHANGE) {
925 mach_info->train_status = HDMI_FRL_TRAIN_STEP_RATE_CHANGE;
926 curr_frl_info->fail_count = 0;
927 } else {
928 mach_info->train_status = HDMI_FRL_TRAIN_STEP_TRAIN_START;
929 curr_frl_info->fail_count++;
930 if (curr_frl_info->max_fail_times <= curr_frl_info->fail_count) {
931 curr_frl_info->fail_count = 0;
932 if (curr_frl_info->bypass & FRL_BYPASS_RESULT_CHECK) {
933 hdmi_info("RESULT_CHECK bypass, goto RESULT_HANDLE!\n");
934 mach_info->train_status = HDMI_FRL_TRAIN_STEP_RESULT_HANDLE;
935 return;
936 }
937 frl_train_exception(hdmi_dev);
938 }
939 }
940
941 return;
942 }
943
frl_training_rate_change_timeout(hdmi_device * hdmi_dev,hi_u64 * start_time)944 static hi_void frl_training_rate_change_timeout(hdmi_device *hdmi_dev, hi_u64 *start_time)
945 {
946 hdmi_frl_info *curr_frl_info = HI_NULL;
947 hdmi_frl_state_mach_info *mach_info = HI_NULL;
948
949 curr_frl_info = &hdmi_dev->frl_info;
950 mach_info = &curr_frl_info->state_mach_info;
951
952 curr_frl_info->cts_mode = frl_is_cts_mode(hdmi_dev);
953 if (frl_get_cur_rate(curr_frl_info) != HI_SUCCESS) {
954 hdmi_err("FRL rate(%u) get failed!\n", curr_frl_info->rate_info.cur_rate);
955 frl_train_exception(hdmi_dev);
956 return;
957 }
958 /* FRL rate change */
959 frl_phy_set(hdmi_dev);
960 frl_set_train_rate(hdmi_dev);
961 mach_info->train_status = HDMI_FRL_TRAIN_STEP_TRAIN_START;
962 *start_time = hdmi_osal_get_time_in_ms();
963
964 return;
965 }
966
frl_start_check_timeout(hdmi_device * hdmi_dev,hi_u32 * timeout,hi_u64 * start_time)967 static hi_void frl_start_check_timeout(hdmi_device *hdmi_dev, hi_u32 *timeout, hi_u64 *start_time)
968 {
969 hdmi_frl_info *curr_frl_info = HI_NULL;
970 hdmi_frl_state_mach_info *mach_info = HI_NULL;
971
972 curr_frl_info = &hdmi_dev->frl_info;
973 mach_info = &curr_frl_info->state_mach_info;
974
975 do {
976 if (frl_get_frl_start(hdmi_dev) == HI_TRUE) {
977 if (curr_frl_info->start) {
978 curr_frl_info->work_en = HI_TRUE;
979 /* n/cts config */
980 frl_n_cts_config(hdmi_dev);
981 frl_enable_output(hdmi_dev, curr_frl_info->work_en);
982 frl_set_frl_start(hdmi_dev, HI_TRUE);
983 *timeout = 0;
984 mach_info->train_status = HDMI_FRL_TRAIN_STEP_RETRAIN_CHECK;
985 break;
986 }
987 } else if (frl_get_flt_update(hdmi_dev) == HI_TRUE) {
988 *timeout = 0;
989 frl_set_flt_update(hdmi_dev, HI_TRUE);
990 mach_info->train_status = HDMI_FRL_TRAIN_STEP_TRAIN_START;
991 break;
992 }
993
994 if ((hdmi_osal_get_time_in_ms() - *start_time) > mach_info->wait_handle_ms) {
995 *timeout += 1;
996 break;
997 }
998 /* 2000: check the sink's status every 2ms required by protocol */
999 osal_udelay(2000);
1000 } while (1);
1001
1002 *start_time = hdmi_osal_get_time_in_ms();
1003 /* Maximum check 3 times */
1004 if (*timeout >= 3) {
1005 hdmi_err("training timeout!\n");
1006 *timeout = 0;
1007 frl_train_exception(hdmi_dev);
1008 }
1009
1010 return;
1011 }
1012
frl_retraining_check_timeout(hdmi_device * hdmi_dev,hi_u64 * start_time)1013 static hi_void frl_retraining_check_timeout(hdmi_device *hdmi_dev, hi_u64 *start_time)
1014 {
1015 hdmi_frl_info *curr_frl_info = HI_NULL;
1016 hdmi_frl_state_mach_info *mach_info = HI_NULL;
1017
1018 curr_frl_info = &hdmi_dev->frl_info;
1019 mach_info = &curr_frl_info->state_mach_info;
1020
1021 if ((hdmi_osal_get_time_in_ms() - *start_time) <= mach_info->wait_retrain_ms) {
1022 return;
1023 }
1024 if (frl_get_flt_update(hdmi_dev) != HI_TRUE) {
1025 return;
1026 }
1027 if (curr_frl_info->bypass & FRL_BYPASS_RETRAIN_CHECK) {
1028 hdmi_info("RETRAIN_CHECK bypass!\n");
1029 return;
1030 }
1031
1032 frl_set_flt_update(hdmi_dev, HI_TRUE);
1033 curr_frl_info->work_en = HI_FALSE;
1034 frl_enable_output(hdmi_dev, curr_frl_info->work_en);
1035 mach_info->train_status = HDMI_FRL_TRAIN_STEP_TRAIN_START;
1036 *start_time = hdmi_osal_get_time_in_ms();
1037
1038 return;
1039 }
1040
frl_training_timeout_mode(hdmi_device * hdmi_dev)1041 static hi_void frl_training_timeout_mode(hdmi_device *hdmi_dev)
1042 {
1043 hi_u64 start_time;
1044 static hi_u32 timeout;
1045 hdmi_frl_info *curr_frl_info = HI_NULL;
1046 hdmi_frl_state_mach_info *mach_info = HI_NULL;
1047
1048 curr_frl_info = &hdmi_dev->frl_info;
1049 mach_info = &curr_frl_info->state_mach_info;
1050 start_time = mach_info->start_time;
1051 switch (mach_info->train_status) {
1052 case HDMI_FRL_TRAIN_STEP_READY_CHECK:
1053 frl_training_ready_check_timeout(hdmi_dev, &start_time, &timeout);
1054 break;
1055 case HDMI_FRL_TRAIN_STEP_TRAIN_START:
1056 frl_config_and_start_train(hdmi_dev);
1057 start_time = hdmi_osal_get_time_in_ms();
1058 mach_info->train_status = HDMI_FRL_TRAIN_STEP_RESULT_CHECK;
1059 break;
1060 case HDMI_FRL_TRAIN_STEP_RESULT_CHECK:
1061 frl_training_result_check_timeout(hdmi_dev);
1062 start_time = hdmi_osal_get_time_in_ms();
1063 break;
1064 case HDMI_FRL_TRAIN_STEP_RATE_CHANGE:
1065 frl_training_rate_change_timeout(hdmi_dev, &start_time);
1066 break;
1067 case HDMI_FRL_TRAIN_STEP_RESULT_HANDLE:
1068 frl_start_check_timeout(hdmi_dev, &timeout, &start_time);
1069 break;
1070 case HDMI_FRL_TRAIN_STEP_RETRAIN_CHECK:
1071 frl_retraining_check_timeout(hdmi_dev, &start_time);
1072 break;
1073 case HDMI_FRL_TRAIN_STEP_STOP:
1074 curr_frl_info->work_en = HI_FALSE;
1075 frl_enable_output(hdmi_dev, curr_frl_info->work_en);
1076 start_time = hdmi_osal_get_time_in_ms();
1077 mach_info->train_status = HDMI_FRL_TRAIN_STEP_BUTT;
1078 break;
1079 default:
1080 break;
1081 }
1082 mach_info->start_time = start_time;
1083
1084 return;
1085 }
1086
drv_hdmi_frl_train_mach(hdmi_device_id hdmi_id)1087 hi_void drv_hdmi_frl_train_mach(hdmi_device_id hdmi_id)
1088 {
1089 hdmi_device *hdmi_dev = HI_NULL;
1090 hdmi_frl_info *curr_frl_info = HI_NULL;
1091 hdmi_frl_train *train_status = HI_NULL;
1092 hdmi_frl_state_mach_info *mach_info = HI_NULL;
1093
1094 hdmi_dev = get_hdmi_device(hdmi_id);
1095 hdmi_if_null_return_void(hdmi_dev);
1096
1097 curr_frl_info = &hdmi_dev->frl_info;
1098 mach_info = &curr_frl_info->state_mach_info;
1099 train_status = &curr_frl_info->train_status;
1100 if (g_frl_stop == FRL_MACH_STOP) {
1101 mach_info->train_status = HDMI_FRL_TRAIN_STEP_STOP;
1102 g_frl_stop = FRL_MACH_BUTT;
1103 train_status->frl_train_status = HDMI_FRL_TRAIN_NONE;
1104 } else if (g_frl_stop == FRL_MACH_START) {
1105 mach_info->train_status = HDMI_FRL_TRAIN_STEP_READY_CHECK;
1106 g_frl_stop = FRL_MACH_BUTT;
1107 }
1108
1109 if (mach_info->mach_mode == HDMI_FRL_MACH_MODE_STEP) {
1110 frl_training_step_mode(hdmi_dev);
1111 } else {
1112 frl_training_timeout_mode(hdmi_dev);
1113 }
1114
1115 return;
1116 }
1117
dfm_calculate(hdmi_frl_info * curr_frl_info,hdmi_attr * attr)1118 hi_bool dfm_calculate(hdmi_frl_info *curr_frl_info, hdmi_attr *attr)
1119 {
1120 hi_u8 max_rate;
1121 dfm_in dfm = {0};
1122 hi_bool _3d_enable = HI_FALSE;
1123 hi_bool capable = HI_FALSE;
1124 const hdmi_vo_attr *vo_attr = HI_NULL;
1125 const hdmi_ao_attr *ao_attr = HI_NULL;
1126 const hdmi_app_attr *app_attr = HI_NULL;
1127 hdmi_video_def *video_def = HI_NULL;
1128
1129 hdmi_if_null_return(curr_frl_info, HI_FALSE);
1130 hdmi_if_null_return(attr, HI_FALSE);
1131
1132 vo_attr = &attr->vo_attr;
1133 ao_attr = &attr->ao_attr;
1134 app_attr = &attr->app_attr;
1135 max_rate = curr_frl_info->rate_info.max_rate;
1136 _3d_enable = (vo_attr->stereo_mode == HDMI_3D_BUTT) ? HI_FALSE : HI_TRUE;
1137 video_def = frl_get_format_param(vo_attr->video_timing, vo_attr->picture_aspect, _3d_enable);
1138 hdmi_if_null_return(video_def, HI_FALSE);
1139
1140 hdmi_info("video_code: %u\n", video_def->video_code);
1141 curr_frl_info->tmds_clk = vo_attr->hdmi_adapt_pix_clk;
1142 frl_dfm_construct(&dfm, ao_attr, app_attr, video_def);
1143
1144 if (max_rate > FRL_WORK_MODE_4L12G) {
1145 capable = HI_FALSE;
1146 goto finish;
1147 }
1148
1149 frl_rate_info_get(curr_frl_info->rate_info.cur_rate, &dfm.bit_rate, &dfm.lane_num);
1150 if (drv_hdmi_dfm_format_support(&dfm) == HI_TRUE) {
1151 capable = HI_TRUE;
1152 } else {
1153 capable = HI_FALSE;
1154 }
1155 hdmi_err("this fmt can %s be trans\n", (capable == HI_TRUE) ? "" : "not");
1156
1157 finish:
1158 return capable;
1159 }
1160
drv_hdmi_frl_mode_change(hdmi_device_id hdmi_id,const hdmi_frl_debug * debug)1161 hi_s32 drv_hdmi_frl_mode_change(hdmi_device_id hdmi_id, const hdmi_frl_debug *debug)
1162 {
1163 hdmi_device *hdmi_dev = HI_NULL;
1164 hdmi_frl_info *curr_frl_info = HI_NULL;
1165 frl_debug debug_cfg = {0};
1166 hdmi_frl_train_config train_config = {0};
1167 hdmi_tx_capability_data tx_cap = {0};
1168 compatibility_info *compat_info = HI_NULL;
1169
1170 hdmi_if_null_return(debug, HI_FAILURE);
1171
1172 compat_info = compat_info_get(hdmi_id);
1173 hdmi_if_null_return(compat_info, HI_FAILURE);
1174
1175 hdmi_dev = get_hdmi_device(hdmi_id);
1176 hdmi_if_null_return(hdmi_dev, HI_FAILURE);
1177 curr_frl_info = &hdmi_dev->frl_info;
1178
1179 hdmi_dev->frl_info.mode = debug->hdmi_mode;
1180 if (debug->hdmi_mode == HDMI_FRL_MODE_FRL) {
1181 hal_call_void(hal_hdmi_tx_capability_get, hdmi_dev->hal, &tx_cap);
1182 curr_frl_info->rate_info.cur_rate = debug->rate;
1183 curr_frl_info->rate_info.max_rate = tx_cap.tx_max_frl_rate;
1184 if (dfm_calculate(curr_frl_info, &(hdmi_dev->attr)) == HI_FALSE) {
1185 hdmi_err("can not trans\n");
1186 return HI_FAILURE;
1187 }
1188 train_config.frl_rate = debug->rate;
1189 train_config.ffe_levels = FRL_TXFFE_MODE_0;
1190 train_config.frl_no_timeout = HI_FALSE;
1191 train_config.ctl_type_config = compat_info->ctl_type_config;
1192 /* set frl rate to rx by scdc. */
1193 frl_set_train_rate(hdmi_dev);
1194 hal_call_void(hal_hdmi_frl_train_config, hdmi_dev->hal, &train_config);
1195 frl_phy_set(hdmi_dev);
1196 /* LM config & channel config */
1197 debug_cfg.debug_cmd = FRL_DEBUG_RATE;
1198 debug_cfg.rate = train_config.frl_rate;
1199 hal_call_void(hal_hdmi_debug, hdmi_dev->hal, HDMI_DEBUG_CMD_FRL, &debug_cfg);
1200 hal_call_void(hal_hdmi_frl_enable, hdmi_dev->hal, HI_TRUE); /* enable worken */
1201 } else {
1202 /* TMDS mode */
1203 frl_phy_set(hdmi_dev);
1204 }
1205 frl_n_cts_config(hdmi_dev);
1206
1207 return HI_SUCCESS;
1208 }
1209
1210