• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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