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