1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "hdmi_dfm.h"
10 #include "hdf_log.h"
11 #include "hdmi_common.h"
12
13 #define HDF_LOG_TAG hdmi_dfm_c
14
15 #define HDMI_DFM_THOUSAND 1000
16 #define HDMI_DFM_INVALID_VAL (-1)
17
HdmiDfmGetPixelFormat(enum HdmiColorSpace colorSpace)18 static uint32_t HdmiDfmGetPixelFormat(enum HdmiColorSpace colorSpace)
19 {
20 uint32_t pixelFormat;
21
22 switch (colorSpace) {
23 case HDMI_COLOR_SPACE_RGB:
24 pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_0;
25 break;
26 case HDMI_COLOR_SPACE_YCBCR420:
27 pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_1;
28 break;
29 case HDMI_COLOR_SPACE_YCBCR422:
30 pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_2;
31 break;
32 case HDMI_COLOR_SPACE_YCBCR444:
33 pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_3;
34 break;
35 default:
36 pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_0;
37 break;
38 }
39 return pixelFormat;
40 }
41
HdmiDfmFillParam(struct HdmiDfmParam * param,const struct HdmiVideoDefInfo * videoInfo,const struct HdmiAudioAttr * audioAttr,enum HdmiColorSpace colorSpace,enum HdmiDeepColor deepColor)42 void HdmiDfmFillParam(struct HdmiDfmParam *param, const struct HdmiVideoDefInfo *videoInfo,
43 const struct HdmiAudioAttr *audioAttr, enum HdmiColorSpace colorSpace, enum HdmiDeepColor deepColor)
44 {
45 if (param == NULL || videoInfo == NULL || audioAttr == NULL) {
46 return;
47 }
48 param->hactive = videoInfo->hactive;
49 param->vactive = videoInfo->vactive;
50 param->hblank = videoInfo->hblank;
51 param->vblank = videoInfo->vblank;
52 param->hsync = videoInfo->hsync;
53 param->hback = videoInfo->hback;
54 param->hfront = videoInfo->hfront;
55 param->vsync = videoInfo->vsync;
56 param->vback = videoInfo->vback;
57 param->vfront = videoInfo->vfront;
58 param->vfreq = videoInfo->rate;
59 param->colorDepth = HdmiCommonDeepClolorConvertToColorDepth(deepColor);
60 param->pixelFormat = HdmiDfmGetPixelFormat(colorSpace);
61 param->audioRate = (uint32_t)audioAttr->sampleRate;
62 param->layout = (audioAttr->channels > HDMI_AUDIO_FORMAT_CHANNEL_2) ? true : false;
63 /* ACAT packet_type */
64 param->acat = HDMI_AUDIO_CHANNEL_ALLOC_TYPE3;
65 param->packetType = HDMI_AUDIO_SAMPLE_PACKET;
66 }
67
HdmiDfmBaseInfoInit(struct HdmiDfmInfo * info,const struct HdmiDfmParam * param)68 static void HdmiDfmBaseInfoInit(struct HdmiDfmInfo *info, const struct HdmiDfmParam *param)
69 {
70 info->htotal = param->hactive + param->hblank;
71 info->vtotal = param->vactive + param->vblank;
72 info->pixelClk = (uint64_t)(info->htotal) * info->vtotal * param->vfreq / HDMI_DFM_THOUSAND;
73
74 /* 1. Determine the maximum legal pixel rate. */
75 info->maxPixelClk = info->pixelClk * (HDMI_DFM_THOUSAND + HDMI_DFM_FRL_PIXELCLK_TOLERANCE) / HDMI_DFM_THOUSAND;
76 info->minPixelClk = info->pixelClk * (HDMI_DFM_THOUSAND - HDMI_DFM_FRL_PIXELCLK_TOLERANCE) / HDMI_DFM_THOUSAND;
77 if (info->maxPixelClk == 0 || info->minPixelClk == 0) {
78 HDF_LOGE("max or min pixel clock is 0!");
79 return;
80 }
81
82 /* 2. Determine the minimum Video Line period. the coefficient for converting from Mbps to bps.1000000000000*/
83 info->lineMinTime = (uint64_t)info->htotal * 1000000000000 / info->maxPixelClk;
84 info->lineMaxTime = (uint64_t)info->htotal * 1000000000000 / info->minPixelClk;
85
86 /* 3. Determine the Worst Case Slow Bit Rate. x10000 */
87 info->minBitRate = (uint64_t)param->bitRate * 1000000000 * (10000 - HDMI_DFM_FRL_BITRATE_TOLERANCE) / 10000;
88 info->maxBitRate = (uint64_t)param->bitRate * 1000000000 * (10000 + HDMI_DFM_FRL_BITRATE_TOLERANCE) / 10000;
89
90 /* 4. Determine the FRL Character Rate */
91 info->minFrlCharRate = info->minBitRate / 18;
92 info->maxFrlCharRate = info->maxBitRate / 18;
93
94 /* 5. Determine the Total FRL Characters per line Period. the coefficient for converting from Mbps to bps.
95 1000000000000*/
96 info->minFrlCharsPerLine = (uint32_t)(info->lineMinTime * info->minFrlCharRate * param->laneNum / 1000000000000);
97 info->maxFrlCharsPerLine = (uint32_t)(info->lineMaxTime * info->maxFrlCharRate * param->laneNum / 1000000000000);
98
99 info->cFrlSb = HDMI_DFM_FRL_SB_LEN(param->laneNum);
100 info->overheadSb = param->laneNum * 100000 / info->cFrlSb;
101 info->overheadRs = HDMI_DFM_RS_NUM_PER_CB * HDMI_DFM_FRL_CB_NUM_PER_SB * 100000 / info->cFrlSb;
102 info->overheadMap = 25 * 10000 / info->cFrlSb; /* FRL map chars per blk. */
103 info->overheadMin = info->overheadSb + info->overheadRs + info->overheadMap;
104 info->overheadMax = info->overheadMin + HDMI_DFM_OVERHEAD_SIZE;
105 }
106
HdmiDfmGetAudioPackets(const struct HdmiDfmParam * param)107 static uint32_t HdmiDfmGetAudioPackets(const struct HdmiDfmParam *param)
108 {
109 uint32_t ap = 0;
110
111 switch (param->packetType) {
112 case HDMI_AUDIO_SAMPLE_PACKET:
113 case HDMI_ONE_BIT_AUDIO_SAMPLE_PACKET:
114 ap = HDMI_AUDIO_AP_SIZE_100;
115 if (param->layout == false) {
116 ap = HDMI_AUDIO_AP_SIZE_25;
117 }
118 break;
119 case HDMI_DTS_AUDIO_PACKET:
120 case HDMI_HBR_AUDIO_PACKET:
121 case HDMI_MULTI_STREAM_AUDIO_SAMPLE_PACKET:
122 case HDMI_ONE_BIT_MULTI_STREAM_AUDIO_SAMPLE_PACKET:
123 ap = HDMI_AUDIO_AP_SIZE_100;
124 break;
125 case HDMI_AUDIO_3D_SAMPLE_PACKET:
126 case HDMI_ONE_BIT_AUDIO_3D_SAMPLE_PACKET:
127 if (param->acat == HDMI_AUDIO_CHANNEL_ALLOC_TYPE1) {
128 ap = HDMI_AUDIO_AP_SIZE_200;
129 } else if (param->acat == HDMI_AUDIO_CHANNEL_ALLOC_TYPE2) {
130 ap = HDMI_AUDIO_AP_SIZE_300;
131 } else if (param->acat == HDMI_AUDIO_CHANNEL_ALLOC_TYPE3) {
132 ap = HDMI_AUDIO_AP_SIZE_400;
133 }
134 break;
135 default:
136 HDF_LOGE("audio packet type 0x%x, is not support.", param->packetType);
137 break;
138 }
139
140 return ap;
141 }
142
HdmiDfmCaculateAudioInfo(struct HdmiDfmInfo * info,const struct HdmiDfmParam * param)143 static void HdmiDfmCaculateAudioInfo(struct HdmiDfmInfo *info, const struct HdmiDfmParam *param)
144 {
145 /* 1. Determine the number of audio packets required to carry each sample. */
146 info->audioAp = HdmiDfmGetAudioPackets(param);
147
148 /* 2. Determine Average Audio Related Packet Rate. */
149 info->audioRap = (uint32_t)((uint64_t)param->audioRate * (1000 + HDMI_DFM_FRL_AUDIOCLK_TOLERANCE) *
150 info->audioAp / 100000);
151
152 /* 3. Determine Average Required Packets per line. */
153 info->avgAudioPacketsPerLine = (uint32_t)((uint64_t)info->audioRap * info->lineMinTime / 1000000000);
154
155 /* 4. Determine the Packets per Hblank that must be supportable. */
156 info->audioPacketsLine = (info->avgAudioPacketsPerLine + HDMI_DFM_THOUSAND - 1) / HDMI_DFM_THOUSAND;
157
158 /*
159 * 5. Determine The c_frl_blank_min(64(guard bands, two 12-character control periods, c_frl_active_extra)
160 * and 32 audio_packets).
161 */
162 info->hblankAudioMin = 64 + 32 * info->audioPacketsLine;
163 }
164
HdmiDfmCaculateVideoBorrowInfo(struct HdmiDfmInfo * info)165 static void HdmiDfmCaculateVideoBorrowInfo(struct HdmiDfmInfo *info)
166 {
167 if (info->activeTimeRef >= info->activeTimeMin && info->blankTimeRef >= info->blankTimeMin) {
168 info->tBorrow = 0;
169 } else if (info->activeTimeRef < info->activeTimeMin && info->blankTimeRef >= info->blankTimeMin) {
170 info->tBorrow = (int32_t)(info->activeTimeMin - info->activeTimeRef);
171 } else {
172 info->tBorrow = HDMI_DFM_INVALID_VAL;
173 }
174 if (info->tBorrow == HDMI_DFM_INVALID_VAL) {
175 info->tbBorrow = HDMI_DFM_INVALID_VAL;
176 } else {
177 info->tbBorrow = ((int32_t)(info->tBorrow * info->avgTbRate / 100000000000) + 10 - 1) / 10;
178 }
179 }
180
HdmiDfmCaculateVideoInfo(struct HdmiDfmInfo * info,const struct HdmiDfmParam * param)181 static void HdmiDfmCaculateVideoInfo(struct HdmiDfmInfo *info, const struct HdmiDfmParam *param)
182 {
183 uint32_t kcd;
184 uint32_t k420;
185
186 /*
187 * 1. if 4:2:2 pixels, kcd is 1. Otherwise, kcd is CD / 8.
188 * if 4:2:0 pixels, k420 is 2. Otherwise, k420 is 1.
189 */
190 kcd = (param->pixelFormat == 2) ? HDMI_DFM_MAGNIFICATION_8 : param->colorDepth;
191 k420 = (param->pixelFormat == 1) ? 2 : 1;
192
193 /* 2. Determine Bits per Pixel */
194 info->bpp = ((24 * kcd) / k420) / HDMI_DFM_MAGNIFICATION_8;
195
196 /* 3. Determine Video Bytes per line. */
197 info->activeBytesPerLine = info->bpp * param->hactive / HDMI_DFM_MAGNIFICATION_8;
198
199 /*
200 * 4. Determine Required Characters to carry Active Video per line.
201 * 3 is means active_bytes_per_line need 3 characters.
202 */
203 info->activeTbPerLine = (info->activeBytesPerLine + 3 - 1) / 3;
204
205 /* 5. Determine Required Characters to carry H-Blank Video per line. */
206 info->hblankTbPerLine = (param->hblank * kcd / k420 + HDMI_DFM_MAGNIFICATION_8 - 1) / HDMI_DFM_MAGNIFICATION_8;
207
208 /* 6. 32 is FRL characters each packet, 7 is guard bands island(4 FRL char) + video(3 FRL char) */
209 if (((param->hblank * kcd) / k420) / HDMI_DFM_MAGNIFICATION_8 > 32 * (1 + info->audioPacketsLine) + 7) {
210 info->cFrlFree = ((param->hblank * kcd) / k420) / HDMI_DFM_MAGNIFICATION_8 -
211 32 * (1 + info->audioPacketsLine) - 7;
212 }
213
214 /* 7. add 1 character each for RC break caused by 4 */
215 info->cFrlRcMargin = 4;
216 /* 8. RC compression transmit control characters reduce 7/8th total characters. */
217 if (7 * info->cFrlFree / HDMI_DFM_MAGNIFICATION_8 > info->cFrlRcMargin) {
218 info->cFrlRcSavings = 7 * info->cFrlFree / HDMI_DFM_MAGNIFICATION_8 - info->cFrlRcMargin;
219 }
220
221 if (info->htotal == 0) {
222 HDF_LOGE("htotal is 0!");
223 return;
224 }
225 info->avgTbRate = info->maxPixelClk * (info->activeTbPerLine + info->hblankTbPerLine) / info->htotal;
226 info->activeTimeRef = (uint64_t)info->lineMinTime * param->hactive / info->htotal;
227 info->blankTimeRef = (uint64_t)info->lineMinTime * param->hblank / info->htotal;
228
229 /* 9. (3 / 2) is active_tb coefficient in protocol */
230 info->activeTimeMin = (uint64_t)info->activeTbPerLine * 3 * 100000000000000 /
231 (2 * param->laneNum * info->minFrlCharRate * (HDMI_DFM_RATE_MAGNIFICATION - info->overheadMax) /
232 HDMI_DFM_THOUSAND);
233 info->blankTimeMin = (uint64_t)info->hblankTbPerLine * 100000000000000 /
234 (param->laneNum * info->minFrlCharRate * (HDMI_DFM_RATE_MAGNIFICATION - info->overheadMax) /
235 HDMI_DFM_THOUSAND);
236
237 /* 10. Determine Borrow Info */
238 HdmiDfmCaculateVideoBorrowInfo(info);
239
240 /* 11. (3 / 2) is active_tb coefficient in protocol */
241 info->cFrlActualPayload =
242 (3 * info->activeTbPerLine + 2 - 1) / 2 + info->hblankTbPerLine - info->cFrlRcSavings;
243
244 if (info->minFrlCharsPerLine == 0) {
245 HDF_LOGE("min FRL Characters per line is 0!");
246 return;
247 }
248 /* 100000 is used to calculate utilization and margin */
249 info->utilization = (uint64_t)info->cFrlActualPayload * 100000 / (uint64_t)info->minFrlCharsPerLine;
250 info->margin = (int32_t)(100000 - (info->utilization + info->overheadMax));
251 }
252
HdmiDfmFillInfo(struct HdmiDfmInfo * info,struct HdmiDfmParam * param)253 static void HdmiDfmFillInfo(struct HdmiDfmInfo *info, struct HdmiDfmParam *param)
254 {
255 HdmiDfmBaseInfoInit(info, param);
256 HdmiDfmCaculateAudioInfo(info, param);
257 HdmiDfmCaculateVideoInfo(info, param);
258
259 /* Check Audio Cap. */
260 info->audioSupport = (info->hblankTbPerLine >= info->hblankAudioMin) ? true : false;
261 /* Check Video Cap. */
262 if (info->tbBorrow == HDMI_DFM_INVALID_VAL) {
263 info->videoSupport = false;
264 } else {
265 info->videoSupport = (info->tbBorrow <= HDMI_DFM_FRL_MAX_TB_BORROW) ? true : false;
266 }
267
268 info->uncompressSupport = (info->margin >= 0) ? true : false;
269 info->canbeTrans = (info->audioSupport && info->videoSupport && info->uncompressSupport) ? true : false;
270 info->isExtraMode = (info->canbeTrans && (info->tbBorrow > 0)) ? true : false;
271 }
272
HdmiDfmFormatSupport(struct HdmiDfmParam * param)273 bool HdmiDfmFormatSupport(struct HdmiDfmParam *param)
274 {
275 struct HdmiDfmInfo info = {0};
276
277 HdmiDfmFillInfo(&info, param);
278 if (info.audioSupport == true && info.videoSupport == true && info.uncompressSupport == true) {
279 return true;
280 }
281 return false;
282 }
283