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 "hdf_log.h"
10 #include "hdmi_core.h"
11
12 #define HDF_LOG_TAG hdmi_scdc_c
13
14 #define HDMI_SCDC_READ_SOURCE_VERSION_TIMES 2
15
HdmiScdcRead(const struct HdmiScdc * scdc,enum HdmiScdcsOffset offset,uint8_t * buffer,uint32_t len)16 static int32_t HdmiScdcRead(const struct HdmiScdc *scdc, enum HdmiScdcsOffset offset, uint8_t *buffer, uint32_t len)
17 {
18 struct HdmiDdcCfg cfg = {0};
19 struct HdmiCntlr *cntlr = NULL;
20
21 if (scdc == NULL || scdc->priv == NULL) {
22 return HDF_ERR_INVALID_PARAM;
23 }
24
25 cntlr = (struct HdmiCntlr *)scdc->priv;
26 cfg.type = HDMI_DDC_DEV_SCDC;
27 cfg.readFlag = true;
28 cfg.devAddr = HDMI_DDC_SCDC_DEV_ADDRESS;
29 cfg.data = buffer;
30 cfg.dataLen = len;
31 cfg.offset = offset;
32 cfg.mode = HDMI_DDC_MODE_READ_MUTIL_NO_ACK;
33 return HdmiDdcTransfer(&(cntlr->ddc), &cfg);
34 }
35
HdmiScdcWrite(const struct HdmiScdc * scdc,enum HdmiScdcsOffset offset,uint8_t * buffer,uint32_t len)36 static int32_t HdmiScdcWrite(const struct HdmiScdc *scdc, enum HdmiScdcsOffset offset, uint8_t *buffer, uint32_t len)
37 {
38 struct HdmiDdcCfg cfg = {0};
39 struct HdmiCntlr *cntlr = NULL;
40
41 if (scdc == NULL || scdc->priv == NULL) {
42 return HDF_ERR_INVALID_PARAM;
43 }
44
45 cntlr = (struct HdmiCntlr *)scdc->priv;
46 cfg.type = HDMI_DDC_DEV_SCDC;
47 cfg.readFlag = false;
48 cfg.devAddr = HDMI_DDC_SCDC_DEV_ADDRESS;
49 cfg.data = buffer;
50 cfg.dataLen = len;
51 cfg.offset = offset;
52 cfg.mode = HDMI_DDC_MODE_WRITE_MUTIL_ACK;
53 return HdmiDdcTransfer(&(cntlr->ddc), &cfg);
54 }
55
HdmiScdcReadByte(const struct HdmiScdc * scdc,enum HdmiScdcsOffset offset,uint8_t * byte)56 static int32_t HdmiScdcReadByte(const struct HdmiScdc *scdc, enum HdmiScdcsOffset offset, uint8_t *byte)
57 {
58 return HdmiScdcRead(scdc, offset, byte, sizeof(*byte));
59 }
60
HdmiScdcWriteByte(const struct HdmiScdc * scdc,enum HdmiScdcsOffset offset,uint8_t * byte)61 static int32_t HdmiScdcWriteByte(const struct HdmiScdc *scdc, enum HdmiScdcsOffset offset, uint8_t *byte)
62 {
63 return HdmiScdcWrite(scdc, offset, byte, sizeof(*byte));
64 }
65
66 /* read opt */
HdmiScdcReadSinkVersion(const struct HdmiScdc * scdc,uint8_t * sinkVer)67 static int32_t HdmiScdcReadSinkVersion(const struct HdmiScdc *scdc, uint8_t *sinkVer)
68 {
69 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_SINK_VERSION, sinkVer);
70 }
71
HdmiScdcReadSourceVersion(const struct HdmiScdc * scdc,uint8_t * srcVer)72 static int32_t HdmiScdcReadSourceVersion(const struct HdmiScdc *scdc, uint8_t *srcVer)
73 {
74 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_SOURCE_VERSION, srcVer);
75 }
76
HdmiScdcReadUpdate0(const struct HdmiScdc * scdc,uint8_t * flag)77 static int32_t HdmiScdcReadUpdate0(const struct HdmiScdc *scdc, uint8_t *flag)
78 {
79 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_UPDATE_0, flag);
80 }
81
HdmiScdcReadScramblerStatus(const struct HdmiScdc * scdc,uint8_t * status)82 static int32_t HdmiScdcReadScramblerStatus(const struct HdmiScdc *scdc, uint8_t *status)
83 {
84 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_SCRAMBLER_STATUS, status);
85 }
86
HdmiScdcReadTmdsConfig(const struct HdmiScdc * scdc,uint8_t * tmdsCfg)87 static int32_t HdmiScdcReadTmdsConfig(const struct HdmiScdc *scdc, uint8_t *tmdsCfg)
88 {
89 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_TMDS_CONFIG, tmdsCfg);
90 }
91
HdmiScdcReadConfig0(const struct HdmiScdc * scdc,uint8_t * cfg)92 int32_t HdmiScdcReadConfig0(const struct HdmiScdc *scdc, uint8_t *cfg)
93 {
94 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_CONFIG_0, cfg);
95 }
96
HdmiScdcReadConfig1(const struct HdmiScdc * scdc,uint8_t * cfg)97 static int32_t HdmiScdcReadConfig1(const struct HdmiScdc *scdc, uint8_t *cfg)
98 {
99 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_CONFIG_1, cfg);
100 }
101
HdmiScdcReadTestConfig0(const struct HdmiScdc * scdc,uint8_t * testCfg)102 int32_t HdmiScdcReadTestConfig0(const struct HdmiScdc *scdc, uint8_t *testCfg)
103 {
104 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_TEST_CONFIG_0, testCfg);
105 }
106
HdmiScdcReadTestConfig1(const struct HdmiScdc * scdc,uint8_t * testCfg)107 static int32_t HdmiScdcReadTestConfig1(const struct HdmiScdc *scdc, uint8_t *testCfg)
108 {
109 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_TEST_CONFIG_1, testCfg);
110 }
111
HdmiScdcReadStatusFlag0(const struct HdmiScdc * scdc,uint8_t * flag)112 static int32_t HdmiScdcReadStatusFlag0(const struct HdmiScdc *scdc, uint8_t *flag)
113 {
114 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_STASTUS_FLAG_0, flag);
115 }
116
HdmiScdcReadStatusFlag1(const struct HdmiScdc * scdc,uint8_t * flag)117 int32_t HdmiScdcReadStatusFlag1(const struct HdmiScdc *scdc, uint8_t *flag)
118 {
119 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_STASTUS_FLAG_1, flag);
120 }
121
HdmiScdcReadStatusFlag2(const struct HdmiScdc * scdc,uint8_t * flag)122 int32_t HdmiScdcReadStatusFlag2(const struct HdmiScdc *scdc, uint8_t *flag)
123 {
124 return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_STASTUS_FLAG_2, flag);
125 }
126
127 /* write opt */
HdmiScdcWriteSourceVersion(const struct HdmiScdc * scdc,uint8_t * srcVer)128 static int32_t HdmiScdcWriteSourceVersion(const struct HdmiScdc *scdc, uint8_t *srcVer)
129 {
130 return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_SOURCE_VERSION, srcVer);
131 }
132
HdmiScdcWriteUpdate0(const struct HdmiScdc * scdc,uint8_t * flag)133 static int32_t HdmiScdcWriteUpdate0(const struct HdmiScdc *scdc, uint8_t *flag)
134 {
135 return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_UPDATE_0, flag);
136 }
137
HdmiScdcWriteTmdsConfig(const struct HdmiScdc * scdc,uint8_t * tmdsCfg)138 static int32_t HdmiScdcWriteTmdsConfig(const struct HdmiScdc *scdc, uint8_t *tmdsCfg)
139 {
140 return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_TMDS_CONFIG, tmdsCfg);
141 }
142
HdmiScdcWriteConfig0(const struct HdmiScdc * scdc,uint8_t * cfg)143 static int32_t HdmiScdcWriteConfig0(const struct HdmiScdc *scdc, uint8_t *cfg)
144 {
145 return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_CONFIG_0, cfg);
146 }
147
HdmiScdcWriteConfig1(const struct HdmiScdc * scdc,uint8_t * cfg)148 static int32_t HdmiScdcWriteConfig1(const struct HdmiScdc *scdc, uint8_t *cfg)
149 {
150 return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_CONFIG_1, cfg);
151 }
152
HdmiScdcWriteTestConfig0(const struct HdmiScdc * scdc,uint8_t * testCfg)153 static int32_t HdmiScdcWriteTestConfig0(const struct HdmiScdc *scdc, uint8_t *testCfg)
154 {
155 return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_TEST_CONFIG_0, testCfg);
156 }
157
158 /* cntlr ops */
HdmiCntlrScdcSourceScrambleGet(struct HdmiCntlr * cntlr)159 static bool HdmiCntlrScdcSourceScrambleGet(struct HdmiCntlr *cntlr)
160 {
161 bool ret = false;
162
163 if (cntlr == NULL || cntlr->ops == NULL || cntlr->ops->scdcSourceScrambleGet == NULL) {
164 return ret;
165 }
166 HdmiCntlrLock(cntlr);
167 ret = cntlr->ops->scdcSourceScrambleGet(cntlr);
168 HdmiCntlrUnlock(cntlr);
169 return ret;
170 }
171
HdmiCntlrScdcSourceScrambleSet(struct HdmiCntlr * cntlr,bool enable)172 static int32_t HdmiCntlrScdcSourceScrambleSet(struct HdmiCntlr *cntlr, bool enable)
173 {
174 int32_t ret;
175
176 if (cntlr == NULL || cntlr->ops == NULL || cntlr->ops->scdcSourceScrambleSet == NULL) {
177 return HDF_ERR_INVALID_OBJECT;
178 }
179 HdmiCntlrLock(cntlr);
180 ret = cntlr->ops->scdcSourceScrambleSet(cntlr, enable);
181 HdmiCntlrUnlock(cntlr);
182 return ret;
183 }
184
185 /* scdc opt */
HdmiScdcRrDisable(struct HdmiScdc * scdc)186 int32_t HdmiScdcRrDisable(struct HdmiScdc *scdc)
187 {
188 union HdmiScdcsConfig0 cfg = {0};
189 union HdmiScdcsTestConfig0 testCfg = {0};
190 int32_t ret;
191
192 if (scdc == NULL) {
193 return HDF_ERR_INVALID_PARAM;
194 }
195
196 ret = HdmiScdcWriteConfig0(scdc, &(cfg.data));
197 if (ret != HDF_SUCCESS) {
198 HDF_LOGE("scdc write config0 fail");
199 return ret;
200 }
201 scdc->status.cfg0 = cfg;
202
203 ret = HdmiScdcWriteTestConfig0(scdc, &(testCfg.data));
204 if (ret != HDF_SUCCESS) {
205 HDF_LOGE("scdc write test config0 fail");
206 return ret;
207 }
208 scdc->status.testCfg0 = testCfg;
209 return HDF_SUCCESS;
210 }
211
HdmiScdcScrambleSet(struct HdmiScdc * scdc,struct HdmiScdcScrambleCap * scramble)212 int32_t HdmiScdcScrambleSet(struct HdmiScdc *scdc, struct HdmiScdcScrambleCap *scramble)
213 {
214 union HdmiScdcsTmdsConfig cfg = {0};
215 int32_t ret;
216
217 if (scdc == NULL) {
218 return HDF_ERR_INVALID_PARAM;
219 }
220
221 ret = HdmiCntlrScdcSourceScrambleSet((struct HdmiCntlr *)scdc->priv, scramble->sourceScramble);
222 if (ret != HDF_SUCCESS) {
223 HDF_LOGE("scdc source scrambler set fail");
224 return ret;
225 }
226
227 if (scramble->sinkScramble == true) {
228 cfg.bits.scramblingEnable = 1;
229 }
230 if (scramble->tmdsBitClockRatio40 == true) {
231 cfg.bits.tmdsBitClockRatio = 1;
232 }
233 ret = HdmiScdcWriteTmdsConfig(scdc, &(cfg.data));
234 if (ret != HDF_SUCCESS) {
235 HDF_LOGE("scdc write tmds config fail");
236 return ret;
237 }
238 return HDF_SUCCESS;
239 }
240
HdmiScdcScrambleGet(struct HdmiScdc * scdc,struct HdmiScdcScrambleCap * scramble)241 int32_t HdmiScdcScrambleGet(struct HdmiScdc *scdc, struct HdmiScdcScrambleCap *scramble)
242 {
243 union HdmiScdcsScramblerStatus status = {0};
244 union HdmiScdcsTmdsConfig cfg = {0};
245 int32_t ret;
246
247 if (scdc == NULL) {
248 return HDF_ERR_INVALID_PARAM;
249 }
250
251 ret = HdmiScdcReadScramblerStatus(scdc, &(status.data));
252 if (ret != HDF_SUCCESS) {
253 HDF_LOGE("scdc read scrambler status fail");
254 return ret;
255 }
256 scramble->sinkScramble = (status.bits.scramblingStatus ? true : false);
257
258 ret = HdmiScdcReadTmdsConfig(scdc, &(cfg.data));
259 if (ret != HDF_SUCCESS) {
260 HDF_LOGE("scdc read tmds config fail");
261 return ret;
262 }
263 scramble->tmdsBitClockRatio40 = (cfg.bits.tmdsBitClockRatio ? true : false);
264 scramble->sourceScramble = HdmiCntlrScdcSourceScrambleGet(scdc->priv);
265
266 scdc->status.tmdsCfg = cfg;
267 scdc->status.scramblerStatus = status;
268 return HDF_SUCCESS;
269 }
270
HdmiScdcSinkSupport(struct HdmiScdc * scdc)271 bool HdmiScdcSinkSupport(struct HdmiScdc *scdc)
272 {
273 uint8_t srcVer;
274 uint8_t i;
275 int32_t ret;
276
277 if (scdc == NULL) {
278 return HDF_ERR_INVALID_PARAM;
279 }
280
281 for (i = 0; i < HDMI_SCDC_READ_SOURCE_VERSION_TIMES; i++) {
282 srcVer = HDMI_SCDC_HDMI20_VERSION;
283 ret = HdmiScdcWriteSourceVersion(scdc, &srcVer);
284 if (ret != HDF_SUCCESS) {
285 HDF_LOGE("scdc write source version fail");
286 return false;
287 }
288 ret = HdmiScdcReadSourceVersion(scdc, &srcVer);
289 if (ret != HDF_SUCCESS) {
290 HDF_LOGE("scdc read source version fail");
291 return false;
292 }
293 }
294 scdc->status.sourceVersion = HDMI_SCDC_HDMI20_VERSION;
295 return true;
296 }
297
HdmiScdcOptMsgHandle(const struct HdmiScdc * scdc,enum HdmiScdcOptMsg msg,uint8_t * buffer,uint32_t len)298 int32_t HdmiScdcOptMsgHandle(const struct HdmiScdc *scdc, enum HdmiScdcOptMsg msg, uint8_t *buffer, uint32_t len)
299 {
300 int32_t ret;
301
302 if (scdc == NULL || buffer == NULL || len == 0) {
303 return HDF_ERR_INVALID_PARAM;
304 }
305
306 switch (msg) {
307 case HDMI_SCDC_OPT_SET_SOURCE_VER:
308 ret = HdmiScdcWriteSourceVersion(scdc, buffer);
309 break;
310 case HDMI_SCDC_OPT_GET_SOURCE_VER:
311 ret = HdmiScdcReadSourceVersion(scdc, buffer);
312 break;
313 case HDMI_SCDC_OPT_GET_SINK_VER:
314 ret = HdmiScdcReadSinkVersion(scdc, buffer);
315 break;
316 case HDMI_SCDC_OPT_SET_FLT_UPDATE:
317 case HDMI_SCDC_OPT_SET_FRL_START:
318 ret = HdmiScdcWriteUpdate0(scdc, buffer);
319 break;
320 case HDMI_SCDC_OPT_GET_FLT_UPDATE:
321 case HDMI_SCDC_OPT_GET_FRL_START:
322 ret = HdmiScdcReadUpdate0(scdc, buffer);
323 break;
324 case HDMI_SCDC_OPT_SET_CONFIG1:
325 ret = HdmiScdcWriteConfig1(scdc, buffer);
326 break;
327 case HDMI_SCDC_OPT_GET_CONFIG1:
328 ret = HdmiScdcReadConfig1(scdc, buffer);
329 break;
330 case HDMI_SCDC_OPT_GET_TEST_CONFIG_1:
331 ret = HdmiScdcReadTestConfig1(scdc, buffer);
332 break;
333 case HDMI_SCDC_OPT_GET_FLT_READY:
334 ret = HdmiScdcReadStatusFlag0(scdc, buffer);
335 break;
336 case HDMI_SCDC_OPT_GET_LTP_REQ:
337 ret = HdmiScdcRead(scdc, HDMI_SCDCS_OFFSET_STASTUS_FLAG_1, buffer, len);
338 break;
339 default:
340 HDF_LOGE("scdc msg handle, msg %d not support.", msg);
341 ret = HDF_ERR_NOT_SUPPORT;
342 break;
343 }
344
345 return ret;
346 }
347
HdmiScdcFillScrambleCap(struct HdmiScdc * scdc,struct HdmiScdcScrambleCap * scramble,enum HdmiTmdsModeType * tmdsMode)348 int32_t HdmiScdcFillScrambleCap(struct HdmiScdc *scdc, struct HdmiScdcScrambleCap *scramble,
349 enum HdmiTmdsModeType *tmdsMode)
350 {
351 struct HdmiCntlr *cntlr = NULL;
352 struct HdmiCommonAttr *commAttr = NULL;
353 struct HdmiVideoAttr *videoAttr = NULL;
354
355 if (scdc == NULL || scdc->priv == NULL || scramble == NULL || tmdsMode == NULL) {
356 HDF_LOGD("scdc fill scramble cap: param is null");
357 return HDF_ERR_INVALID_PARAM;
358 }
359
360 cntlr = (struct HdmiCntlr *)scdc->priv;
361 commAttr = &(cntlr->attr.commAttr);
362 videoAttr = &(cntlr->attr.videoAttr);
363 if (commAttr->enableHdmi == false) {
364 /* DVI mode */
365 *tmdsMode = HDMI_TMDS_MODE_DVI;
366 scramble->sinkScramble = false;
367 scramble->sourceScramble = false;
368 scramble->tmdsBitClockRatio40 = false;
369 if (videoAttr->tmdsClock > HDMI_HDMI14_MAX_TMDS_RATE) {
370 HDF_LOGE("tmds clock %u can't support in DVI mode.", videoAttr->tmdsClock);
371 return HDF_ERR_INVALID_PARAM;
372 }
373 } else if (videoAttr->tmdsClock > HDMI_HDMI14_MAX_TMDS_RATE) {
374 *tmdsMode = HDMI_TMDS_MODE_HDMI_2_0;
375 scramble->sinkScramble = true;
376 scramble->sourceScramble = true;
377 scramble->tmdsBitClockRatio40 = true;
378 } else {
379 *tmdsMode = HDMI_TMDS_MODE_HDMI_1_4;
380 scramble->sinkScramble = false;
381 scramble->sourceScramble = false;
382 scramble->tmdsBitClockRatio40 = false;
383 }
384 return HDF_SUCCESS;
385 }
386