• 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_dfm.h"
19 #include "hdmi_product_define.h"
20 #include "drv_hdmi_common.h"
21 
22 #define FRLCHAR_PER_CB_NUM  510
23 #define RS_PER_CB_NUM       8
24 #define CB_PER_SB_NUM       4
25 #define PIXELCLK_TOLERANCE  5
26 #define AUDIOCLK_TOLERANCE  1
27 #define BITRATE_TOLERANCE   3
28 #define TB_BORROW_MAX       400
29 #define AUDIO_AP_SIZE_25    25
30 #define AUDIO_AP_SIZE_100   100
31 #define AUDIO_AP_SIZE_200   200
32 #define AUDIO_AP_SIZE_300   300
33 #define AUDIO_AP_SIZE_400   400
34 #define DFM_MAGNIFICATION_8 8
35 #define RATE_MAGNIFICATION  100000
36 #define OVERHEAD_SIZE       300
37 
38 #define get_k420(pixelformat)            (((pixelformat) == 1) ? 2 : 1)
39 #define get_kcd(pixelformat, colorspace) (((pixelformat) == 2) ? 8 : (colorspace))
40 
41 static dfm_info g_dfm_info;
42 
dfm_div(hi_s64 div_a,hi_s64 div_b)43 static hi_s64 dfm_div(hi_s64 div_a, hi_s64 div_b)
44 {
45     hi_s64 div_result;
46     div_result = osal_div64_s64(div_a, div_b);
47     return div_result;
48 }
49 
get_dfm_info(hi_void)50 static dfm_info *get_dfm_info(hi_void)
51 {
52     return &g_dfm_info;
53 }
54 
dfm_get_audio_ap(dfm_in * in)55 static hi_s32 dfm_get_audio_ap(dfm_in *in)
56 {
57     hi_s32 audio_ap = 0;
58 
59     if (in->packet_type == AUDIO_SAMPLE_PACKET || in->packet_type == ONE_BIT_AUDIO_SAMPLE_PACKET) {
60         if (in->layout == 0) {
61             audio_ap = AUDIO_AP_SIZE_25; /* AP eq audio_ap / 100 */
62         } else {
63             audio_ap = AUDIO_AP_SIZE_100; /* AP eq audio_ap / 100 */
64         }
65     } else if (in->packet_type == DTS_AUDIO_PACKET) {
66         audio_ap = AUDIO_AP_SIZE_100; /* AP eq audio_ap / 100 */
67     } else if (in->packet_type == HBR_AUDIO_PACKET ||
68                in->packet_type == MULTI_STREAM_AUDIO_SAMPLE_PACKET ||
69                in->packet_type == ONE_BIT_MULTI_STREAM_AUDIO_SAMPLE_PACKET) {
70         audio_ap = AUDIO_AP_SIZE_100; /* AP eq audio_ap / 100 */
71     } else if (in->packet_type == AUDIO_3D_SAMPLE_PACKET || in->packet_type == ONE_BIT_AUDIO_3D_SAMPLE_PACKET) {
72         if (in->acat == AUDIO_CHANNEL_ALLOC_TYPE1) {
73             audio_ap = AUDIO_AP_SIZE_200; /* AP eq audio_ap / 100 */
74         } else if (in->acat == AUDIO_CHANNEL_ALLOC_TYPE2) {
75             audio_ap = AUDIO_AP_SIZE_300; /* AP eq audio_ap / 100 */
76         } else if (in->acat == AUDIO_CHANNEL_ALLOC_TYPE3) {
77             audio_ap = AUDIO_AP_SIZE_400; /* AP eq audio_ap / 100 */
78         }
79     }
80 
81     return audio_ap;
82 }
83 
84 #ifdef DEBUG
dfm_info_debug(const dfm_info * info)85 static hi_void dfm_info_debug(const dfm_info *info)
86 {
87     hdmi_info("start\n");
88     hdmi_info("htotal = %d\nvtotal = %d\n", info->htotal, info->vtotal);
89     hdmi_info("pixel_clk = %lld\n", info->pixel_clk);
90     hdmi_info("bpp = %d\n", info->bpp);
91     hdmi_info("c_frl_sb = %d\n", info->c_frl_sb);
92     hdmi_info("overhead_sb = %d\n", info->overhead_sb);
93     hdmi_info("overhead_rs = %d\n", info->overhead_rs);
94     hdmi_info("overhead_map = %d\n", info->overhead_map);
95     hdmi_info("overhead_min = %d\n", info->overhead_min);
96     hdmi_info("overhead_m = %d\n", info->overhead_m);
97     hdmi_info("overhead_max = %d\n", info->overhead_max);
98     hdmi_info("max_pixel_clk = %lld\n", info->max_pixel_clk);
99     hdmi_info("min_pixel_clk = %lld\n", info->min_pixel_clk);
100     hdmi_info("max_time_line = %d\n", info->max_time_line);
101     hdmi_info("min_time_line = %d\n", info->min_time_line);
102     hdmi_info("max_bit_rate = %lld\n", info->max_bit_rate);
103     hdmi_info("min_bit_rate = %lld\n", info->min_bit_rate);
104     hdmi_info("max_frl_char_rate = %lld\n", info->max_frl_char_rate);
105     hdmi_info("min_frl_char_rate = %lld\n", info->min_frl_char_rate);
106     hdmi_info("max_frl_chars_per_line = %d\n", info->max_frl_chars_per_line);
107     hdmi_info("min_frl_chars_per_line = %d\n", info->min_frl_chars_per_line);
108     hdmi_info("audio_ap = %d\naudio_rap = %d\n", info->audio_ap, info->audio_rap);
109     hdmi_info("avg_audio_packets = %d\n", info->avg_audio_packets);
110     hdmi_info("audio_packets = %d\n", info->audio_packets);
111     hdmi_info("blank_audio_min = %d\n", info->blank_audio_min);
112     hdmi_info("c_frl_free = %d\n", info->c_frl_free);
113     hdmi_info("c_frl_rc_margin = %d\n", info->c_frl_rc_margin);
114     hdmi_info("c_frl_rc_savings = %d\n", info->c_frl_rc_savings);
115     hdmi_info("active_bytes_per_line = %d\n", info->active_bytes_per_line);
116     hdmi_info("active_tb_per_line = %d\n", info->active_tb_per_line);
117     hdmi_info("blank_tb_per_line = %d\n", info->blank_tb_per_line);
118     hdmi_info("audio_support = %s\n", info->audio_support ? "TRUE" : "FALSE");
119     hdmi_info("avg_tb_rate = %lld\n", info->avg_tb_rate);
120     hdmi_info("active_time_ref = %d\n", info->active_time_ref);
121     hdmi_info("blank_time_ref = %d\n", info->blank_time_ref);
122     hdmi_info("active_time_min = %d\n", info->active_time_min);
123     hdmi_info("blank_time_min = %d\n", info->blank_time_min);
124     hdmi_info("t_borrow = %d\ntb_borrow = %d\n", info->t_borrow, info->tb_borrow);
125     hdmi_info("video_support = %s\n", info->video_support ? "TRUE" : "FALSE");
126     hdmi_info("c_frl_actual_payload = %d\n", info->c_frl_actual_payload);
127     hdmi_info("utilization = %d\n", info->utilization);
128     hdmi_info("margin = %d\n", info->margin);
129     hdmi_info("uncompress_support = %s\n", info->uncompress_support ? "TRUE" : "FALSE");
130     hdmi_info("canbe_trans = %s\n", info->canbe_trans ? "TRUE" : "FALSE");
131     hdmi_info("is_extra_mode = %s\n", info->is_extra_mode ? "TRUE" : "FALSE");
132 
133     return;
134 }
135 #endif
136 
dfm_base_info_init(const dfm_in * in,dfm_info * info)137 static hi_void dfm_base_info_init(const dfm_in *in, dfm_info *info)
138 {
139     info->htotal = in->hactive + in->hblank;
140     info->vtotal = in->vactive + in->vblank;
141     info->pixel_clk = dfm_div((hi_s64)info->htotal * info->vtotal * in->v_freq, HDMI_THOUSAND);
142 
143     /* specification assume, c_frl_sb eq 4 * C_FRL_CB + Lanes, in protocol  */
144     info->c_frl_sb = FRLCHAR_PER_CB_NUM * 4 + in->lane_num;
145     hdmi_if_zero_return_void(info->c_frl_sb);
146 
147     info->overhead_sb = in->lane_num * 100000 / info->c_frl_sb;                      /* step1.01 x100000 */
148     info->overhead_rs = RS_PER_CB_NUM * CB_PER_SB_NUM * 100000 / info->c_frl_sb;     /* step1.02 x100000 */
149     info->overhead_map = 25 * 10000 / info->c_frl_sb; /* 25, 10000: step1.03 x100000, 2.5 FRL map chars per blk. */
150     info->overhead_min = info->overhead_sb + info->overhead_rs + info->overhead_map; /* step1.04 x100000 */
151     info->overhead_m = OVERHEAD_SIZE;                                                /* step1.05 x100000 */
152     info->overhead_max = info->overhead_min + info->overhead_m;                      /* step1.06 x100000 */
153     info->max_pixel_clk = dfm_div(info->pixel_clk * (HDMI_THOUSAND + PIXELCLK_TOLERANCE), HDMI_THOUSAND); /* step1.07 */
154 
155     hdmi_if_zero_return_void(info->max_pixel_clk);
156     info->min_pixel_clk = dfm_div(info->pixel_clk * (HDMI_THOUSAND - PIXELCLK_TOLERANCE), HDMI_THOUSAND);
157     hdmi_if_zero_return_void(info->min_pixel_clk);
158     info->max_time_line = dfm_div((hi_s64)info->htotal * 1000000000000, info->min_pixel_clk); /* x1000000000000 */
159     /* step1.08 x1000000000000 */
160     info->min_time_line = dfm_div((hi_s64)info->htotal * 1000000000000, info->max_pixel_clk);
161     /* 1000000000,10000: step1.09, Determine the worst-case slow FRL bit rate, bit_rate * (1 - tolerance / 1000000 ) */
162     info->min_bit_rate = dfm_div((hi_s64)in->bit_rate * 1000000000 * (10000 - BITRATE_TOLERANCE), 10000); /* x10000 */
163     /* 1000000000,10000: x10000, bit_rate calculate 1000000000 / 10000 = 100000bit = 100M */
164     info->max_bit_rate = dfm_div((hi_s64)in->bit_rate * 1000000000 * (10000 + BITRATE_TOLERANCE), 10000);
165     info->max_frl_char_rate = dfm_div(info->max_bit_rate, 18); /* max_frl_char_rate, max_bit_rate / 18 */
166     info->min_frl_char_rate = dfm_div(info->min_bit_rate, 18); /* min_frl_char_rate, min_bit_rate / 18 */
167 
168     info->max_frl_chars_per_line = (hi_s32)dfm_div(info->max_time_line *
169         info->max_frl_char_rate * in->lane_num, 1000000000000); /* x1000000000000 */
170     info->min_frl_chars_per_line = (hi_s32)dfm_div(info->min_time_line *
171         info->min_frl_char_rate * in->lane_num, 1000000000000); /* step1.11 x1000000000000 */
172 
173     hdmi_if_zero_return_void(info->min_frl_chars_per_line);
174 
175     return;
176 }
177 
dfm_borrow_info_init(dfm_info * info)178 static hi_void dfm_borrow_info_init(dfm_info *info)
179 {
180     if (info->active_time_ref >= info->active_time_min && info->blank_time_ref >= info->blank_time_min) {
181         info->t_borrow = 0; /* step1.30 */
182     } else if (info->active_time_ref < info->active_time_min && info->blank_time_ref >= info->blank_time_min) {
183         info->t_borrow = info->active_time_min - info->active_time_ref; /* step1.31 */
184     } else {
185         info->t_borrow = -1;
186     }
187     if (info->t_borrow == -1) {
188         info->tb_borrow = -1;
189     } else {
190         /* step1.32 x100000000000, tb_borrow is the number of 3 Bytes required to be transmitted during blk period. */
191         info->tb_borrow = ((hi_s32)dfm_div(info->t_borrow * info->avg_tb_rate, 100000000000) + 10 - 1) / 10;
192     }
193 
194     return;
195 }
196 
dfm_info_init(dfm_in * in,dfm_info * info)197 static hi_void dfm_info_init(dfm_in *in, dfm_info *info)
198 {
199     hi_s32 kcd;
200     hi_s32 k420;
201 
202     kcd = get_kcd(in->pixel_format, in->color_depth);
203     k420 = get_k420(in->pixel_format);
204 
205     dfm_base_info_init(in, info); /* step1.01 - step1.11 */
206     info->audio_ap = dfm_get_audio_ap(in); /* step1.12 */
207      /* step1.13 x1000, rap eq audio_rate * (1 + tolerance_audioclock / 1000000) * AP */
208     info->audio_rap = (hi_s32)dfm_div((hi_s64)in->audio_rate * (1000 + AUDIOCLK_TOLERANCE) * info->audio_ap, 100000);
209     /* step1.14 x1000, 1000000000 is 1000 *1000000, avg_audio_packets is rap * time_line */
210     info->avg_audio_packets = (hi_s32)dfm_div((hi_s64)info->audio_rap * info->min_time_line, 1000000000);
211     info->audio_packets = (info->avg_audio_packets + HDMI_THOUSAND - 1) / HDMI_THOUSAND; /* step1.15 */
212     /* step1.16, hblank_min includes 64(guard bands, two 12-character control periods) + 32 * audio_packets */
213     info->blank_audio_min = 64 + 32 * info->audio_packets;
214     /* step1.17, 32 is FRL characters each packet, 7 is guard bands island(4 FRL char) + video(3 FRL char) */
215     info->c_frl_free = max(((in->hblank * kcd) / k420) / DFM_MAGNIFICATION_8 - 32 * (1 + info->audio_packets) - 7, 0);
216     info->c_frl_rc_margin = 4; /* step1.18, add 1 character each for RC break caused by 4 */
217     /* step1.19, RC compression transmit control characters reduce 7/8th total characters. */
218     info->c_frl_rc_savings = max((7 * info->c_frl_free / DFM_MAGNIFICATION_8 - info->c_frl_rc_margin), 0);
219     info->bpp = ((24 * kcd) / k420) / DFM_MAGNIFICATION_8; /* step1.20, dpp eq (24 * kcd) / k420) in protocol */
220 
221     info->active_bytes_per_line = info->bpp * in->hactive / DFM_MAGNIFICATION_8; /* step1.21 */
222     /* step1.22, 3 is means active_bytes_per_line need 3 characters */
223     info->active_tb_per_line = (info->active_bytes_per_line + 3 - 1) / 3;
224     info->blank_tb_per_line = (in->hblank * kcd / k420 + DFM_MAGNIFICATION_8 - 1) / DFM_MAGNIFICATION_8; /* step1.23 */
225     info->audio_support = (info->blank_tb_per_line >= info->blank_audio_min) ? HI_TRUE : HI_FALSE; /* step1.24 */
226 
227     hdmi_if_zero_return_void(info->htotal);
228     /* step1.25 */
229     info->avg_tb_rate =
230         dfm_div(info->max_pixel_clk * (info->active_tb_per_line + info->blank_tb_per_line), info->htotal);
231     /* step1.26 x1000000000000 */
232     info->active_time_ref = dfm_div((hi_s64)info->min_time_line * in->hactive, info->htotal);
233     /* step1.27 x1000000000000 */
234     info->blank_time_ref = dfm_div((hi_s64)info->min_time_line * in->hblank, info->htotal);
235     /* step1.28, 100000000000000 is 100000000000 * 1000 multiple, (3 / 2) is active_tb coefficient in protocol */
236     info->active_time_min = dfm_div((hi_s64)info->active_tb_per_line * 3 * 100000000000000,
237         dfm_div(2 * in->lane_num * info->min_frl_char_rate * (RATE_MAGNIFICATION - info->overhead_max), HDMI_THOUSAND));
238     /* step1.29 100000000000000 is 100000000000 * 1000 blank_tb_per_line active coefficient multiple */
239     info->blank_time_min = dfm_div((hi_s64)info->blank_tb_per_line * 100000000000000,
240         dfm_div(in->lane_num * info->min_frl_char_rate * (RATE_MAGNIFICATION - info->overhead_max), HDMI_THOUSAND));
241     dfm_borrow_info_init(info); /* step1.30 step1.32 */
242     if (info->tb_borrow == -1) {
243         info->video_support = HI_FALSE;
244     } else {
245         info->video_support = (info->tb_borrow <= TB_BORROW_MAX) ? HI_TRUE : HI_FALSE; /* step1.33 */
246     }
247     /* step1.34, 3, 2: (3 / 2) is active_tb coefficient in protocol */
248     info->c_frl_actual_payload =
249         (3 * info->active_tb_per_line + 2 - 1) / 2 + info->blank_tb_per_line - info->c_frl_rc_savings;
250     /* step1.35  x100000 */
251     info->utilization = dfm_div((hi_s64)info->c_frl_actual_payload * 100000, (hi_s64)info->min_frl_chars_per_line);
252     info->margin = 100000 - (info->utilization + info->overhead_max); /* step1.36 x100000 */
253     info->uncompress_support = (info->margin >= 0) ? HI_TRUE : HI_FALSE; /* step1.37 */
254     info->canbe_trans = (info->audio_support && info->video_support && info->uncompress_support) ? HI_TRUE : HI_FALSE;
255     info->is_extra_mode = (info->canbe_trans && (info->tb_borrow > 0)) ? HI_TRUE : HI_FALSE;
256 
257 #ifdef DEBUG
258     dfm_info_debug(info);
259 #endif
260 
261     return;
262 }
263 
drv_hdmi_dfm_format_support(dfm_in * dfm)264 hi_bool drv_hdmi_dfm_format_support(dfm_in *dfm)
265 {
266     hi_bool ret = HI_FALSE;
267     dfm_info *info = HI_NULL;
268 
269     hdmi_if_null_return(dfm, HI_FALSE);
270     info = get_dfm_info();
271     hdmi_if_null_return(info, HI_FALSE);
272 
273     dfm_info_init(dfm, info);
274     ret = (info->audio_support && info->video_support && info->uncompress_support) ? HI_TRUE : HI_FALSE;
275 
276     return ret;
277 }
278 
279