1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ExynosDisplayDrmInterfaceModule.h"
18 #include "ExynosPrimaryDisplayModule.h"
19 #include <drm/samsung_drm.h>
20
21 template <typename T, typename M>
convertDqeMatrixDataToMatrix(T & colorMatrix,M & mat,uint32_t dimension)22 int32_t convertDqeMatrixDataToMatrix(T &colorMatrix, M &mat,
23 uint32_t dimension) {
24 if (colorMatrix.coeffs.size() != (dimension * dimension)) {
25 HWC_LOGE(nullptr, "Invalid coeff size(%zu)",
26 colorMatrix.coeffs.size());
27 return -EINVAL;
28 }
29 for (uint32_t i = 0; i < (dimension * dimension); i++) {
30 mat.coeffs[i] = colorMatrix.coeffs[i];
31 }
32
33 if (colorMatrix.offsets.size() != dimension) {
34 HWC_LOGE(nullptr, "Invalid offset size(%zu)",
35 colorMatrix.offsets.size());
36 return -EINVAL;
37 }
38 for (uint32_t i = 0; i < dimension; i++) {
39 mat.offsets[i] = colorMatrix.offsets[i];
40 }
41 return NO_ERROR;
42 }
43
44 using namespace gs101;
45
46 /////////////////////////////////////////////////// ExynosDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)47 ExynosDisplayDrmInterfaceModule::ExynosDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
48 : ExynosDisplayDrmInterface(exynosDisplay)
49 {
50 }
51
~ExynosDisplayDrmInterfaceModule()52 ExynosDisplayDrmInterfaceModule::~ExynosDisplayDrmInterfaceModule()
53 {
54 }
55
parseBpcEnums(const DrmProperty & property)56 void ExynosDisplayDrmInterfaceModule::parseBpcEnums(const DrmProperty& property)
57 {
58 const std::vector<std::pair<uint32_t, const char *>> bpcEnums = {
59 {static_cast<uint32_t>(BPC_UNSPECIFIED), "Unspecified"},
60 {static_cast<uint32_t>(BPC_8), "8bpc"},
61 {static_cast<uint32_t>(BPC_10), "10bpc"},
62 };
63
64 ALOGD("Init bpc enums");
65 parseEnums(property, bpcEnums, mBpcEnums);
66 for (auto &e : mBpcEnums) {
67 ALOGD("bpc [bpc: %d, drm: %" PRId64 "]", e.first, e.second);
68 }
69 }
70
initDrmDevice(DrmDevice * drmDevice)71 int32_t ExynosDisplayDrmInterfaceModule::initDrmDevice(DrmDevice *drmDevice)
72 {
73 int ret = NO_ERROR;
74 if ((ret = ExynosDisplayDrmInterface::initDrmDevice(drmDevice)) != NO_ERROR)
75 return ret;
76
77 if (isPrimary() == false)
78 return ret;
79
80 mOldDqeBlobs.init(drmDevice);
81
82 initOldDppBlobs(drmDevice);
83 if (mDrmCrtc->force_bpc_property().id())
84 parseBpcEnums(mDrmCrtc->force_bpc_property());
85 return ret;
86 }
87
destroyOldBlobs(std::vector<uint32_t> & oldBlobs)88 void ExynosDisplayDrmInterfaceModule::destroyOldBlobs(
89 std::vector<uint32_t> &oldBlobs)
90 {
91 for (auto &blob : oldBlobs) {
92 mDrmDevice->DestroyPropertyBlob(blob);
93 }
94 oldBlobs.clear();
95 }
96
createCgcBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)97 int32_t ExynosDisplayDrmInterfaceModule::createCgcBlobFromIDqe(
98 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
99 {
100 struct cgc_lut cgc;
101 const IDisplayColorGS101::IDqe::CgcData &cgcData = dqe.Cgc();
102
103 if (cgcData.config == nullptr) {
104 ALOGE("no CGC config");
105 return -EINVAL;
106 }
107
108 if ((cgcData.config->r_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT) ||
109 (cgcData.config->g_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT) ||
110 (cgcData.config->b_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT)) {
111 ALOGE("CGC data size is not same (r: %zu, g: %zu: b: %zu)",
112 cgcData.config->r_values.size(),
113 cgcData.config->g_values.size(),
114 cgcData.config->b_values.size());
115 return -EINVAL;
116 }
117
118 for (uint32_t i = 0; i < DRM_SAMSUNG_CGC_LUT_REG_CNT; i++) {
119 cgc.r_values[i] = cgcData.config->r_values[i];
120 cgc.g_values[i] = cgcData.config->g_values[i];
121 cgc.b_values[i] = cgcData.config->b_values[i];
122 }
123 int ret = mDrmDevice->CreatePropertyBlob(&cgc, sizeof(cgc_lut), &blobId);
124 if (ret) {
125 HWC_LOGE(mExynosDisplay, "Failed to create cgc blob %d", ret);
126 return ret;
127 }
128 return NO_ERROR;
129 }
130
createDegammaLutBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)131 int32_t ExynosDisplayDrmInterfaceModule::createDegammaLutBlobFromIDqe(
132 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
133 {
134 int ret = 0;
135 uint64_t lut_size = 0;
136
137 if (dqe.DegammaLut().config == nullptr) {
138 ALOGE("no degamma config");
139 return -EINVAL;
140 }
141
142 std::tie(ret, lut_size) = mDrmCrtc->degamma_lut_size_property().value();
143 if (ret < 0) {
144 HWC_LOGE(mExynosDisplay, "%s: there is no degamma_lut_size (ret = %d)",
145 __func__, ret);
146 return ret;
147 }
148 if (lut_size != IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen) {
149 HWC_LOGE(mExynosDisplay, "%s: invalid lut size (%" PRId64 ")",
150 __func__, lut_size);
151 return -EINVAL;
152 }
153
154 struct drm_color_lut color_lut[IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen];
155 for (uint32_t i = 0; i < lut_size; i++) {
156 color_lut[i].red = dqe.DegammaLut().config->values[i];
157 }
158 ret = mDrmDevice->CreatePropertyBlob(color_lut, sizeof(color_lut), &blobId);
159 if (ret) {
160 HWC_LOGE(mExynosDisplay, "Failed to create degamma lut blob %d", ret);
161 return ret;
162 }
163 return NO_ERROR;
164 }
165
createRegammaLutBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)166 int32_t ExynosDisplayDrmInterfaceModule::createRegammaLutBlobFromIDqe(
167 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
168 {
169 int ret = 0;
170 uint64_t lut_size = 0;
171
172 if (dqe.RegammaLut().config == nullptr) {
173 ALOGE("no regamma config");
174 return -EINVAL;
175 }
176
177 std::tie(ret, lut_size) = mDrmCrtc->gamma_lut_size_property().value();
178 if (ret < 0) {
179 HWC_LOGE(mExynosDisplay, "%s: there is no gamma_lut_size (ret = %d)",
180 __func__, ret);
181 return ret;
182 }
183 if (lut_size != IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen) {
184 HWC_LOGE(mExynosDisplay, "%s: invalid lut size (%" PRId64 ")",
185 __func__, lut_size);
186 return -EINVAL;
187 }
188
189 struct drm_color_lut color_lut[IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen];
190 for (uint32_t i = 0; i < lut_size; i++) {
191 color_lut[i].red = dqe.RegammaLut().config->r_values[i];
192 color_lut[i].green = dqe.RegammaLut().config->g_values[i];
193 color_lut[i].blue = dqe.RegammaLut().config->b_values[i];
194 }
195 ret = mDrmDevice->CreatePropertyBlob(color_lut, sizeof(color_lut), &blobId);
196 if (ret) {
197 HWC_LOGE(mExynosDisplay, "Failed to create gamma lut blob %d", ret);
198 return ret;
199 }
200 return NO_ERROR;
201 }
202
createGammaMatBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)203 int32_t ExynosDisplayDrmInterfaceModule::createGammaMatBlobFromIDqe(
204 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
205 {
206 int ret = 0;
207 struct exynos_matrix gamma_matrix;
208 if ((ret = convertDqeMatrixDataToMatrix(
209 dqe.GammaMatrix().config->matrix_data, gamma_matrix, DRM_SAMSUNG_MATRIX_DIMENS)) != NO_ERROR)
210 {
211 HWC_LOGE(mExynosDisplay, "Failed to convert gamma matrix");
212 return ret;
213 }
214 ret = mDrmDevice->CreatePropertyBlob(&gamma_matrix, sizeof(gamma_matrix), &blobId);
215 if (ret) {
216 HWC_LOGE(mExynosDisplay, "Failed to create gamma matrix blob %d", ret);
217 return ret;
218 }
219
220 return NO_ERROR;
221 }
222
createLinearMatBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)223 int32_t ExynosDisplayDrmInterfaceModule::createLinearMatBlobFromIDqe(
224 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
225 {
226 int ret = 0;
227 struct exynos_matrix linear_matrix;
228 if ((ret = convertDqeMatrixDataToMatrix(
229 dqe.LinearMatrix().config->matrix_data, linear_matrix, DRM_SAMSUNG_MATRIX_DIMENS)) != NO_ERROR)
230 {
231 HWC_LOGE(mExynosDisplay, "Failed to convert linear matrix");
232 return ret;
233 }
234 ret = mDrmDevice->CreatePropertyBlob(&linear_matrix, sizeof(linear_matrix), &blobId);
235 if (ret) {
236 HWC_LOGE(mExynosDisplay, "Failed to create linear matrix blob %d", ret);
237 return ret;
238 }
239
240 return NO_ERROR;
241 }
242
createDispDitherBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)243 int32_t ExynosDisplayDrmInterfaceModule::createDispDitherBlobFromIDqe(
244 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
245 {
246 int ret = 0;
247 const IDisplayColorGS101::IDqe::DqeControlData& dqeControl = dqe.DqeControl();
248 if (dqeControl.config->disp_dither_override == false) {
249 blobId = 0;
250 return ret;
251 }
252
253 ret = mDrmDevice->CreatePropertyBlob((void*)&dqeControl.config->disp_dither_reg,
254 sizeof(dqeControl.config->disp_dither_reg), &blobId);
255 if (ret) {
256 HWC_LOGE(mExynosDisplay, "Failed to create disp dither blob %d", ret);
257 return ret;
258 }
259
260 return NO_ERROR;
261 }
262
createCgcDitherBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)263 int32_t ExynosDisplayDrmInterfaceModule::createCgcDitherBlobFromIDqe(
264 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
265 {
266 int ret = 0;
267 const IDisplayColorGS101::IDqe::DqeControlData& dqeControl = dqe.DqeControl();
268 if (dqeControl.config->cgc_dither_override == false) {
269 blobId = 0;
270 return ret;
271 }
272
273 ret = mDrmDevice->CreatePropertyBlob((void*)&dqeControl.config->cgc_dither_reg,
274 sizeof(dqeControl.config->cgc_dither_reg), &blobId);
275 if (ret) {
276 HWC_LOGE(mExynosDisplay, "Failed to create disp dither blob %d", ret);
277 return ret;
278 }
279 return NO_ERROR;
280 }
281
createEotfBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)282 int32_t ExynosDisplayDrmInterfaceModule::createEotfBlobFromIDpp(
283 const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
284 {
285 struct hdr_eotf_lut eotf_lut;
286
287 if (dpp.EotfLut().config == nullptr) {
288 ALOGE("no dpp eotf config");
289 return -EINVAL;
290 }
291
292 if ((dpp.EotfLut().config->tf_data.posx.size() != DRM_SAMSUNG_HDR_EOTF_LUT_LEN) ||
293 (dpp.EotfLut().config->tf_data.posy.size() != DRM_SAMSUNG_HDR_EOTF_LUT_LEN)) {
294 HWC_LOGE(mExynosDisplay, "%s: eotf pos size (%zu, %zu)",
295 __func__, dpp.EotfLut().config->tf_data.posx.size(),
296 dpp.EotfLut().config->tf_data.posy.size());
297 return -EINVAL;
298 }
299
300 for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_EOTF_LUT_LEN; i++) {
301 eotf_lut.posx[i] = dpp.EotfLut().config->tf_data.posx[i];
302 eotf_lut.posy[i] = dpp.EotfLut().config->tf_data.posy[i];
303 }
304 int ret = mDrmDevice->CreatePropertyBlob(&eotf_lut, sizeof(eotf_lut), &blobId);
305 if (ret) {
306 HWC_LOGE(mExynosDisplay, "Failed to create eotf lut blob %d", ret);
307 return ret;
308 }
309 return NO_ERROR;
310 }
311
createGmBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)312 int32_t ExynosDisplayDrmInterfaceModule::createGmBlobFromIDpp(
313 const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
314 {
315 int ret = 0;
316 struct hdr_gm_data gm_matrix;
317
318 if (dpp.Gm().config == nullptr) {
319 ALOGE("no dpp GM config");
320 return -EINVAL;
321 }
322
323 if ((ret = convertDqeMatrixDataToMatrix(dpp.Gm().config->matrix_data, gm_matrix,
324 DRM_SAMSUNG_HDR_GM_DIMENS)) != NO_ERROR)
325 {
326 HWC_LOGE(mExynosDisplay, "Failed to convert gm matrix");
327 return ret;
328 }
329 ret = mDrmDevice->CreatePropertyBlob(&gm_matrix, sizeof(gm_matrix), &blobId);
330 if (ret) {
331 HWC_LOGE(mExynosDisplay, "Failed to create gm matrix blob %d", ret);
332 return ret;
333 }
334 return NO_ERROR;
335 }
336
createDtmBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)337 int32_t ExynosDisplayDrmInterfaceModule::createDtmBlobFromIDpp(
338 const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
339 {
340 struct hdr_tm_data tm_data;
341
342 if (dpp.Dtm().config == nullptr) {
343 ALOGE("no dpp DTM config");
344 return -EINVAL;
345 }
346
347 if ((dpp.Dtm().config->tf_data.posx.size() != DRM_SAMSUNG_HDR_TM_LUT_LEN) ||
348 (dpp.Dtm().config->tf_data.posy.size() != DRM_SAMSUNG_HDR_TM_LUT_LEN)) {
349 HWC_LOGE(mExynosDisplay, "%s: dtm pos size (%zu, %zu)",
350 __func__, dpp.Dtm().config->tf_data.posx.size(),
351 dpp.Dtm().config->tf_data.posy.size());
352 return -EINVAL;
353 }
354
355 for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_TM_LUT_LEN; i++) {
356 tm_data.posx[i] = dpp.Dtm().config->tf_data.posx[i];
357 tm_data.posy[i] = dpp.Dtm().config->tf_data.posy[i];
358 }
359
360 tm_data.coeff_r = dpp.Dtm().config->coeff_r;
361 tm_data.coeff_g = dpp.Dtm().config->coeff_g;
362 tm_data.coeff_b = dpp.Dtm().config->coeff_b;
363 tm_data.rng_x_min = dpp.Dtm().config->rng_x_min;
364 tm_data.rng_x_max = dpp.Dtm().config->rng_x_max;
365 tm_data.rng_y_min = dpp.Dtm().config->rng_y_min;
366 tm_data.rng_y_max = dpp.Dtm().config->rng_y_max;
367
368 int ret = mDrmDevice->CreatePropertyBlob(&tm_data, sizeof(tm_data), &blobId);
369 if (ret) {
370 HWC_LOGE(mExynosDisplay, "Failed to create tm_data blob %d", ret);
371 return ret;
372 }
373
374 return NO_ERROR;
375 }
createOetfBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)376 int32_t ExynosDisplayDrmInterfaceModule::createOetfBlobFromIDpp(
377 const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
378 {
379 struct hdr_oetf_lut oetf_lut;
380
381 if (dpp.OetfLut().config == nullptr) {
382 ALOGE("no dpp OETF config");
383 return -EINVAL;
384 }
385
386 if ((dpp.OetfLut().config->tf_data.posx.size() != DRM_SAMSUNG_HDR_OETF_LUT_LEN) ||
387 (dpp.OetfLut().config->tf_data.posy.size() != DRM_SAMSUNG_HDR_OETF_LUT_LEN)) {
388 HWC_LOGE(mExynosDisplay, "%s: oetf pos size (%zu, %zu)",
389 __func__, dpp.OetfLut().config->tf_data.posx.size(),
390 dpp.OetfLut().config->tf_data.posy.size());
391 return -EINVAL;
392 }
393
394 for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_OETF_LUT_LEN; i++) {
395 oetf_lut.posx[i] = dpp.OetfLut().config->tf_data.posx[i];
396 oetf_lut.posy[i] = dpp.OetfLut().config->tf_data.posy[i];
397 }
398 int ret = mDrmDevice->CreatePropertyBlob(&oetf_lut, sizeof(oetf_lut), &blobId);
399 if (ret) {
400 HWC_LOGE(mExynosDisplay, "Failed to create oetf lut blob %d", ret);
401 return ret;
402 }
403 return NO_ERROR;
404 }
405
406 template<typename StageDataType>
setDisplayColorBlob(const DrmProperty & prop,const uint32_t type,const StageDataType & stage,const IDisplayColorGS101::IDqe & dqe,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)407 int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorBlob(
408 const DrmProperty &prop,
409 const uint32_t type,
410 const StageDataType &stage,
411 const IDisplayColorGS101::IDqe &dqe,
412 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
413 {
414 /* dirty bit is valid only if enable is true */
415 if (!prop.id())
416 return NO_ERROR;
417 if (!mForceDisplayColorSetting && stage.enable && !stage.dirty)
418 return NO_ERROR;
419
420 int32_t ret = 0;
421 uint32_t blobId = 0;
422
423 if (stage.enable) {
424 switch (type) {
425 case DqeBlobs::CGC:
426 ret = createCgcBlobFromIDqe(dqe, blobId);
427 break;
428 case DqeBlobs::DEGAMMA_LUT:
429 ret = createDegammaLutBlobFromIDqe(dqe, blobId);
430 break;
431 case DqeBlobs::REGAMMA_LUT:
432 ret = createRegammaLutBlobFromIDqe(dqe, blobId);
433 break;
434 case DqeBlobs::GAMMA_MAT:
435 ret = createGammaMatBlobFromIDqe(dqe, blobId);
436 break;
437 case DqeBlobs::LINEAR_MAT:
438 ret = createLinearMatBlobFromIDqe(dqe, blobId);
439 break;
440 case DqeBlobs::DISP_DITHER:
441 ret = createDispDitherBlobFromIDqe(dqe, blobId);
442 break;
443 case DqeBlobs::CGC_DITHER:
444 ret = createCgcDitherBlobFromIDqe(dqe, blobId);
445 break;
446 default:
447 ret = -EINVAL;
448 }
449 if (ret != NO_ERROR) {
450 HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
451 return ret;
452 }
453 }
454
455 /* Skip setting when previous and current setting is same with 0 */
456 if ((blobId == 0) && (mOldDqeBlobs.getBlob(type) == 0))
457 return ret;
458
459 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
460 HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
461 __func__);
462 return ret;
463 }
464 mOldDqeBlobs.addBlob(type, blobId);
465
466 // disp_dither and cgc dither are part of DqeCtrl stage and the notification
467 // will be sent after all data in DqeCtrl stage are applied.
468 if (type != DqeBlobs::DISP_DITHER && type != DqeBlobs::CGC_DITHER)
469 stage.NotifyDataApplied();
470
471 return ret;
472 }
setDisplayColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)473 int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorSetting(
474 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
475 {
476 if (isPrimary() == false)
477 return NO_ERROR;
478 if (!mForceDisplayColorSetting && !mColorSettingChanged)
479 return NO_ERROR;
480
481 ExynosPrimaryDisplayModule* display =
482 (ExynosPrimaryDisplayModule*)mExynosDisplay;
483
484 int ret = NO_ERROR;
485 const IDisplayColorGS101::IDqe &dqe = display->getDqe();
486
487 if ((mDrmCrtc->cgc_lut_property().id() != 0) &&
488 (ret = setDisplayColorBlob(mDrmCrtc->cgc_lut_property(),
489 static_cast<uint32_t>(DqeBlobs::CGC),
490 dqe.Cgc(), dqe, drmReq) != NO_ERROR)) {
491 HWC_LOGE(mExynosDisplay, "%s: set Cgc blob fail", __func__);
492 return ret;
493 }
494 if ((ret = setDisplayColorBlob(mDrmCrtc->degamma_lut_property(),
495 static_cast<uint32_t>(DqeBlobs::DEGAMMA_LUT),
496 dqe.DegammaLut(), dqe, drmReq) != NO_ERROR)) {
497 HWC_LOGE(mExynosDisplay, "%s: set DegammaLut blob fail", __func__);
498 return ret;
499 }
500 if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_lut_property(),
501 static_cast<uint32_t>(DqeBlobs::REGAMMA_LUT),
502 dqe.RegammaLut(), dqe, drmReq) != NO_ERROR)) {
503 HWC_LOGE(mExynosDisplay, "%s: set RegammaLut blob fail", __func__);
504 return ret;
505 }
506 if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_matrix_property(),
507 static_cast<uint32_t>(DqeBlobs::GAMMA_MAT),
508 dqe.GammaMatrix(), dqe, drmReq) != NO_ERROR)) {
509 HWC_LOGE(mExynosDisplay, "%s: set GammaMatrix blob fail", __func__);
510 return ret;
511 }
512 if ((ret = setDisplayColorBlob(mDrmCrtc->linear_matrix_property(),
513 static_cast<uint32_t>(DqeBlobs::LINEAR_MAT),
514 dqe.LinearMatrix(), dqe, drmReq) != NO_ERROR)) {
515 HWC_LOGE(mExynosDisplay, "%s: set LinearMatrix blob fail", __func__);
516 return ret;
517 }
518 if ((ret = setDisplayColorBlob(mDrmCrtc->disp_dither_property(),
519 static_cast<uint32_t>(DqeBlobs::DISP_DITHER),
520 dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
521 HWC_LOGE(mExynosDisplay, "%s: set DispDither blob fail", __func__);
522 return ret;
523 }
524 if ((ret = setDisplayColorBlob(mDrmCrtc->cgc_dither_property(),
525 static_cast<uint32_t>(DqeBlobs::CGC_DITHER),
526 dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
527 HWC_LOGE(mExynosDisplay, "%s: set CgcDither blob fail", __func__);
528 return ret;
529 }
530
531 const DrmProperty &prop_force_bpc = mDrmCrtc->force_bpc_property();
532 if (prop_force_bpc.id()) {
533 uint32_t bpc = static_cast<uint32_t>(BPC_UNSPECIFIED);
534 if (dqe.DqeControl().enable) {
535 if (dqe.DqeControl().config->force_10bpc)
536 bpc = static_cast<uint32_t>(BPC_10);
537 }
538 uint64_t bpcEnum = 0;
539 std::tie(bpcEnum, ret) = halToDrmEnum(bpc, mBpcEnums);
540 if (ret < 0) {
541 HWC_LOGE(mExynosDisplay, "Fail to convert bpc(%d)", bpc);
542 } else {
543 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_force_bpc,
544 bpcEnum, true)) < 0) {
545 HWC_LOGE(mExynosDisplay, "%s: Fail to set force bpc property",
546 __func__);
547 }
548 }
549 }
550 dqe.DqeControl().NotifyDataApplied();
551
552 return NO_ERROR;
553 }
554
555 template<typename StageDataType>
setPlaneColorBlob(const std::unique_ptr<DrmPlane> & plane,const DrmProperty & prop,const uint32_t type,const StageDataType & stage,const IDisplayColorGS101::IDpp & dpp,const uint32_t dppIndex,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,bool forceUpdate)556 int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorBlob(
557 const std::unique_ptr<DrmPlane> &plane,
558 const DrmProperty &prop,
559 const uint32_t type,
560 const StageDataType &stage,
561 const IDisplayColorGS101::IDpp &dpp,
562 const uint32_t dppIndex,
563 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
564 bool forceUpdate)
565 {
566 /* dirty bit is valid only if enable is true */
567 if (!prop.id() || (stage.enable && !stage.dirty && !forceUpdate))
568 return NO_ERROR;
569
570 uint32_t ix = 0;
571 for (;ix < mOldDppBlobs.size(); ix++) {
572 if (mOldDppBlobs[ix].planeId == plane->id()) {
573 break;
574 }
575 }
576 if (ix >= mOldDppBlobs.size()) {
577 HWC_LOGE(mExynosDisplay, "%s: could not find plane %d", __func__, plane->id());
578 return -EINVAL;
579 }
580 DppBlobs &oldDppBlobs = mOldDppBlobs[ix];
581
582 int32_t ret = 0;
583 uint32_t blobId = 0;
584
585 if (stage.enable) {
586 switch (type) {
587 case DppBlobs::EOTF:
588 ret = createEotfBlobFromIDpp(dpp, blobId);
589 break;
590 case DppBlobs::GM:
591 ret = createGmBlobFromIDpp(dpp, blobId);
592 break;
593 case DppBlobs::DTM:
594 ret = createDtmBlobFromIDpp(dpp, blobId);
595 break;
596 case DppBlobs::OETF:
597 ret = createOetfBlobFromIDpp(dpp, blobId);
598 break;
599 default:
600 ret = -EINVAL;
601 }
602 if (ret != NO_ERROR) {
603 HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
604 return ret;
605 }
606 }
607
608 /* Skip setting when previous and current setting is same with 0 */
609 if ((blobId == 0) && (oldDppBlobs.getBlob(type) == 0) && !forceUpdate)
610 return ret;
611
612 if ((ret = drmReq.atomicAddProperty(plane->id(), prop, blobId)) < 0) {
613 HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
614 __func__);
615 return ret;
616 }
617
618 oldDppBlobs.addBlob(type, blobId);
619 stage.NotifyDataApplied();
620
621 return ret;
622 }
623
setPlaneColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const std::unique_ptr<DrmPlane> & plane,const exynos_win_config_data & config)624 int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorSetting(
625 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
626 const std::unique_ptr<DrmPlane> &plane,
627 const exynos_win_config_data &config)
628 {
629 if ((mColorSettingChanged == false) ||
630 (isPrimary() == false))
631 return NO_ERROR;
632
633 if ((config.assignedMPP == nullptr) ||
634 (config.assignedMPP->mAssignedSources.size() == 0)) {
635 HWC_LOGE(mExynosDisplay, "%s:: config's mpp source size is invalid",
636 __func__);
637 return -EINVAL;
638 }
639 ExynosMPPSource* mppSource = config.assignedMPP->mAssignedSources[0];
640 if (mppSource->mSourceType >= MPP_SOURCE_MAX) {
641 HWC_LOGE(mExynosDisplay,
642 "%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
643 return -EINVAL;
644 }
645
646 ExynosPrimaryDisplayModule* display = (ExynosPrimaryDisplayModule*)mExynosDisplay;
647
648 /*
649 * Color conversion of Client and Exynos composition buffer
650 * is already addressed by GLES or G2D. But as of now, 'dim SDR' is only
651 * supported by HWC/displaycolor, we need put client composition under
652 * control of HWC/displaycolor.
653 */
654 if (!display->hasDppForLayer(mppSource)) {
655 if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
656 HWC_LOGE(mExynosDisplay,
657 "%s: layer need color conversion but there is no IDpp",
658 __func__);
659 return -EINVAL;
660 } else if (mppSource->mSourceType == MPP_SOURCE_COMPOSITION_TARGET) {
661 return NO_ERROR;
662 } else {
663 HWC_LOGE(mExynosDisplay,
664 "%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
665 return -EINVAL;
666 }
667 }
668
669 if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
670 ExynosLayer* layer = (ExynosLayer*)mppSource;
671
672 /* color conversion was already handled by m2mMPP */
673 if ((layer->mM2mMPP != nullptr) &&
674 (layer->mSrcImg.dataSpace != layer->mMidImg.dataSpace)) {
675 return NO_ERROR;
676 }
677 }
678
679 const IDisplayColorGS101::IDpp &dpp = display->getDppForLayer(mppSource);
680 const uint32_t dppIndex = static_cast<uint32_t>(display->getDppIndexForLayer(mppSource));
681 bool planeChanged = display->checkAndSaveLayerPlaneId(mppSource, plane->id());
682
683 int ret = 0;
684 if ((ret = setPlaneColorBlob(plane, plane->eotf_lut_property(),
685 static_cast<uint32_t>(DppBlobs::EOTF),
686 dpp.EotfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
687 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set oetf blob fail",
688 __func__, dppIndex);
689 return ret;
690 }
691 if ((ret = setPlaneColorBlob(plane, plane->gammut_matrix_property(),
692 static_cast<uint32_t>(DppBlobs::GM),
693 dpp.Gm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
694 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set GM blob fail",
695 __func__, dppIndex);
696 return ret;
697 }
698 if ((ret = setPlaneColorBlob(plane, plane->tone_mapping_property(),
699 static_cast<uint32_t>(DppBlobs::DTM),
700 dpp.Dtm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
701 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set DTM blob fail",
702 __func__, dppIndex);
703 return ret;
704 }
705 if ((ret = setPlaneColorBlob(plane, plane->oetf_lut_property(),
706 static_cast<uint32_t>(DppBlobs::OETF),
707 dpp.OetfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
708 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set OETF blob fail",
709 __func__, dppIndex);
710 return ret;
711 }
712
713 return 0;
714 }
715
~SaveBlob()716 ExynosDisplayDrmInterfaceModule::SaveBlob::~SaveBlob()
717 {
718 for (auto &it: blobs) {
719 mDrmDevice->DestroyPropertyBlob(it);
720 }
721 blobs.clear();
722 }
723
addBlob(uint32_t type,uint32_t blob)724 void ExynosDisplayDrmInterfaceModule::SaveBlob::addBlob(
725 uint32_t type, uint32_t blob)
726 {
727 if (type >= blobs.size()) {
728 ALOGE("Invalid dqe blop type: %d", type);
729 return;
730 }
731 if (blobs[type] > 0)
732 mDrmDevice->DestroyPropertyBlob(blobs[type]);
733
734 blobs[type] = blob;
735 }
736
getBlob(uint32_t type)737 uint32_t ExynosDisplayDrmInterfaceModule::SaveBlob::getBlob(uint32_t type)
738 {
739 if (type >= blobs.size()) {
740 ALOGE("Invalid dqe blop type: %d", type);
741 return 0;
742 }
743 return blobs[type];
744 }
745
getDisplayInfo(std::vector<displaycolor::DisplayInfo> & display_info)746 void ExynosDisplayDrmInterfaceModule::getDisplayInfo(
747 std::vector<displaycolor::DisplayInfo> &display_info) {
748 displaycolor::DisplayInfo primary_display;
749 auto &tb = primary_display.brightness_table;
750
751 tb.nbm_nits_min = mBrightnessTable[BrightnessRange::NORMAL].mNitsStart;
752 tb.nbm_nits_max = mBrightnessTable[BrightnessRange::NORMAL].mNitsEnd;
753 tb.nbm_dbv_min = mBrightnessTable[BrightnessRange::NORMAL].mBklStart;
754 tb.nbm_dbv_max = mBrightnessTable[BrightnessRange::NORMAL].mBklEnd;
755
756 tb.hbm_nits_min = mBrightnessTable[BrightnessRange::HBM].mNitsStart;
757 tb.hbm_nits_max = mBrightnessTable[BrightnessRange::HBM].mNitsEnd;
758 tb.hbm_dbv_min = mBrightnessTable[BrightnessRange::HBM].mBklStart;
759 tb.hbm_dbv_max = mBrightnessTable[BrightnessRange::HBM].mBklEnd;
760
761 display_info.push_back(primary_display);
762 }
763
764 //////////////////////////////////////////////////// ExynosPrimaryDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)765 ExynosPrimaryDisplayDrmInterfaceModule::ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
766 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
767 {
768 }
769
~ExynosPrimaryDisplayDrmInterfaceModule()770 ExynosPrimaryDisplayDrmInterfaceModule::~ExynosPrimaryDisplayDrmInterfaceModule()
771 {
772 }
773
774 //////////////////////////////////////////////////// ExynosExternalDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)775 ExynosExternalDisplayDrmInterfaceModule::ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
776 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
777 {
778 }
779
~ExynosExternalDisplayDrmInterfaceModule()780 ExynosExternalDisplayDrmInterfaceModule::~ExynosExternalDisplayDrmInterfaceModule()
781 {
782 }
783