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