1 /*
2 * Copyright (c) 2021 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 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,struct HdmiVideoDefInfo * videoInfo,struct HdmiAudioAttr * audioAttr,enum HdmiColorSpace colorSpace,enum HdmiDeepColor deepColor)42 void HdmiDfmFillParam(struct HdmiDfmParam *param, struct HdmiVideoDefInfo *videoInfo,
43 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,struct HdmiDfmParam * param)68 static void HdmiDfmBaseInfoInit(struct HdmiDfmInfo *info, 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. */
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. */
95 info->minFrlCharsPerLine = (uint32_t)(info->lineMinTime * info->minFrlCharRate * param->laneNum / 1000000000000);
96 info->maxFrlCharsPerLine = (uint32_t)(info->lineMaxTime * info->maxFrlCharRate * param->laneNum / 1000000000000);
97
98 info->cFrlSb = HDMI_DFM_FRL_SB_LEN(param->laneNum);
99 info->overheadSb = param->laneNum * 100000 / info->cFrlSb;
100 info->overheadRs = HDMI_DFM_RS_NUM_PER_CB * HDMI_DFM_FRL_CB_NUM_PER_SB * 100000 / info->cFrlSb;
101 info->overheadMap = 25 * 10000 / info->cFrlSb; /* FRL map chars per blk. */
102 info->overheadMin = info->overheadSb + info->overheadRs + info->overheadMap;
103 info->overheadMax = info->overheadMin + HDMI_DFM_OVERHEAD_SIZE;
104 }
105
HdmiDfmGetAudioPackets(struct HdmiDfmParam * param)106 static uint32_t HdmiDfmGetAudioPackets(struct HdmiDfmParam *param)
107 {
108 uint32_t ap = 0;
109
110 switch (param->packetType) {
111 case HDMI_AUDIO_SAMPLE_PACKET:
112 case HDMI_ONE_BIT_AUDIO_SAMPLE_PACKET:
113 ap = HDMI_AUDIO_AP_SIZE_100;
114 if (param->layout == false) {
115 ap = HDMI_AUDIO_AP_SIZE_25;
116 }
117 break;
118 case HDMI_DTS_AUDIO_PACKET:
119 case HDMI_HBR_AUDIO_PACKET:
120 case HDMI_MULTI_STREAM_AUDIO_SAMPLE_PACKET:
121 case HDMI_ONE_BIT_MULTI_STREAM_AUDIO_SAMPLE_PACKET:
122 ap = HDMI_AUDIO_AP_SIZE_100;
123 break;
124 case HDMI_AUDIO_3D_SAMPLE_PACKET:
125 case HDMI_ONE_BIT_AUDIO_3D_SAMPLE_PACKET:
126 if (param->acat == HDMI_AUDIO_CHANNEL_ALLOC_TYPE1) {
127 ap = HDMI_AUDIO_AP_SIZE_200;
128 } else if (param->acat == HDMI_AUDIO_CHANNEL_ALLOC_TYPE2) {
129 ap = HDMI_AUDIO_AP_SIZE_300;
130 } else if (param->acat == HDMI_AUDIO_CHANNEL_ALLOC_TYPE3) {
131 ap = HDMI_AUDIO_AP_SIZE_400;
132 }
133 break;
134 default:
135 HDF_LOGE("audio packet type 0x%x, is not support.", param->packetType);
136 break;
137 }
138
139 return ap;
140 }
141
HdmiDfmCaculateAudioInfo(struct HdmiDfmInfo * info,struct HdmiDfmParam * param)142 static void HdmiDfmCaculateAudioInfo(struct HdmiDfmInfo *info, struct HdmiDfmParam *param)
143 {
144 /* 1. Determine the number of audio packets required to carry each sample. */
145 info->audioAp = HdmiDfmGetAudioPackets(param);
146
147 /* 2. Determine Average Audio Related Packet Rate. */
148 info->audioRap = (uint32_t)((uint64_t)param->audioRate * (1000 + HDMI_DFM_FRL_AUDIOCLK_TOLERANCE) *
149 info->audioAp / 100000);
150
151 /* 3. Determine Average Required Packets per line. */
152 info->avgAudioPacketsPerLine = (uint32_t)((uint64_t)info->audioRap * info->lineMinTime / 1000000000);
153
154 /* 4. Determine the Packets per Hblank that must be supportable. */
155 info->audioPacketsLine = (info->avgAudioPacketsPerLine + HDMI_DFM_THOUSAND - 1) / HDMI_DFM_THOUSAND;
156
157 /*
158 * 5. Determine The c_frl_blank_min(64(guard bands, two 12-character control periods, c_frl_active_extra)
159 * and 32 audio_packets).
160 */
161 info->hblankAudioMin = 64 + 32 * info->audioPacketsLine;
162 }
163
HdmiDfmCaculateVideoBorrowInfo(struct HdmiDfmInfo * info)164 static void HdmiDfmCaculateVideoBorrowInfo(struct HdmiDfmInfo *info)
165 {
166 if (info->activeTimeRef >= info->activeTimeMin && info->blankTimeRef >= info->blankTimeMin) {
167 info->tBorrow = 0;
168 } else if (info->activeTimeRef < info->activeTimeMin && info->blankTimeRef >= info->blankTimeMin) {
169 info->tBorrow = (int32_t)(info->activeTimeMin - info->activeTimeRef);
170 } else {
171 info->tBorrow = HDMI_DFM_INVALID_VAL;
172 }
173 if (info->tBorrow == HDMI_DFM_INVALID_VAL) {
174 info->tbBorrow = HDMI_DFM_INVALID_VAL;
175 } else {
176 info->tbBorrow = ((int32_t)(info->tBorrow * info->avgTbRate / 100000000000) + 10 - 1) / 10;
177 }
178 }
179
HdmiDfmCaculateVideoInfo(struct HdmiDfmInfo * info,struct HdmiDfmParam * param)180 static void HdmiDfmCaculateVideoInfo(struct HdmiDfmInfo *info, struct HdmiDfmParam *param)
181 {
182 uint32_t kcd, k420;
183
184 /*
185 * 1. if 4:2:2 pixels, kcd is 1. Otherwise, kcd is CD / 8.
186 * if 4:2:0 pixels, k420 is 2. Otherwise, k420 is 1.
187 */
188 kcd = (param->pixelFormat == 2) ? HDMI_DFM_MAGNIFICATION_8 : param->colorDepth;
189 k420 = (param->pixelFormat == 1) ? 2 : 1;
190
191 /* 2. Determine Bits per Pixel */
192 info->bpp = ((24 * kcd) / k420) / HDMI_DFM_MAGNIFICATION_8;
193
194 /* 3. Determine Video Bytes per line. */
195 info->activeBytesPerLine = info->bpp * param->hactive / HDMI_DFM_MAGNIFICATION_8;
196
197 /*
198 * 4. Determine Required Characters to carry Active Video per line.
199 * 3 is means active_bytes_per_line need 3 characters.
200 */
201 info->activeTbPerLine = (info->activeBytesPerLine + 3 - 1) / 3;
202
203 /* 5. Determine Required Characters to carry H-Blank Video per line. */
204 info->hblankTbPerLine = (param->hblank * kcd / k420 + HDMI_DFM_MAGNIFICATION_8 - 1) / HDMI_DFM_MAGNIFICATION_8;
205
206 /* 6. 32 is FRL characters each packet, 7 is guard bands island(4 FRL char) + video(3 FRL char) */
207 if (((param->hblank * kcd) / k420) / HDMI_DFM_MAGNIFICATION_8 > 32 * (1 + info->audioPacketsLine) + 7) {
208 info->cFrlFree = ((param->hblank * kcd) / k420) / HDMI_DFM_MAGNIFICATION_8 -
209 32 * (1 + info->audioPacketsLine) - 7;
210 }
211
212 /* 7. add 1 character each for RC break caused by 4 */
213 info->cFrlRcMargin = 4;
214 /* 8. RC compression transmit control characters reduce 7/8th total characters. */
215 if (7 * info->cFrlFree / HDMI_DFM_MAGNIFICATION_8 > info->cFrlRcMargin) {
216 info->cFrlRcSavings = 7 * info->cFrlFree / HDMI_DFM_MAGNIFICATION_8 - info->cFrlRcMargin;
217 }
218
219 if (info->htotal == 0) {
220 HDF_LOGE("htotal is 0!");
221 return;
222 }
223 info->avgTbRate = info->maxPixelClk * (info->activeTbPerLine + info->hblankTbPerLine) / info->htotal;
224 info->activeTimeRef = (uint64_t)info->lineMinTime * param->hactive / info->htotal;
225 info->blankTimeRef = (uint64_t)info->lineMinTime * param->hblank / info->htotal;
226
227 /* 9. (3 / 2) is active_tb coefficient in protocol */
228 info->activeTimeMin = (uint64_t)info->activeTbPerLine * 3 * 100000000000000 /
229 (2 * param->laneNum * info->minFrlCharRate * (HDMI_DFM_RATE_MAGNIFICATION - info->overheadMax) /
230 HDMI_DFM_THOUSAND);
231 info->blankTimeMin = (uint64_t)info->hblankTbPerLine * 100000000000000 /
232 (param->laneNum * info->minFrlCharRate * (HDMI_DFM_RATE_MAGNIFICATION - info->overheadMax) /
233 HDMI_DFM_THOUSAND);
234
235 /* 10. Determine Borrow Info */
236 HdmiDfmCaculateVideoBorrowInfo(info);
237
238 /* 11. (3 / 2) is active_tb coefficient in protocol */
239 info->cFrlActualPayload =
240 (3 * info->activeTbPerLine + 2 - 1) / 2 + info->hblankTbPerLine - info->cFrlRcSavings;
241
242 if (info->minFrlCharsPerLine == 0) {
243 HDF_LOGE("min FRL Characters per line is 0!");
244 return;
245 }
246 info->utilization = (uint64_t)info->cFrlActualPayload * 100000 / (uint64_t)info->minFrlCharsPerLine;
247 info->margin = (int32_t)(100000 - (info->utilization + info->overheadMax));
248 }
249
HdmiDfmFillInfo(struct HdmiDfmInfo * info,struct HdmiDfmParam * param)250 static void HdmiDfmFillInfo(struct HdmiDfmInfo *info, struct HdmiDfmParam *param)
251 {
252 HdmiDfmBaseInfoInit(info, param);
253 HdmiDfmCaculateAudioInfo(info, param);
254 HdmiDfmCaculateVideoInfo(info, param);
255
256 /* Check Audio Cap. */
257 info->audioSupport = (info->hblankTbPerLine >= info->hblankAudioMin) ? true : false;
258 /* Check Video Cap. */
259 if (info->tbBorrow == HDMI_DFM_INVALID_VAL) {
260 info->videoSupport = false;
261 } else {
262 info->videoSupport = (info->tbBorrow <= HDMI_DFM_FRL_MAX_TB_BORROW) ? true : false;
263 }
264
265 info->uncompressSupport = (info->margin >= 0) ? true : false;
266 info->canbeTrans = (info->audioSupport && info->videoSupport && info->uncompressSupport) ? true : false;
267 info->isExtraMode = (info->canbeTrans && (info->tbBorrow > 0)) ? true : false;
268 }
269
HdmiDfmFormatSupport(struct HdmiDfmParam * param)270 bool HdmiDfmFormatSupport(struct HdmiDfmParam *param)
271 {
272 struct HdmiDfmInfo info = {0};
273
274 HdmiDfmFillInfo(&info, param);
275 if (info.audioSupport == true && info.videoSupport == true && info.uncompressSupport == true) {
276 return true;
277 }
278 return false;
279 }
280