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 "BrightnessController.h"
18 #include "ExynosDisplayDrmInterfaceModule.h"
19 #include "ExynosPrimaryDisplayModule.h"
20 #include <drm/samsung_drm.h>
21
22 using BrightnessRange = BrightnessController::BrightnessRange;
23
24 template <typename T, typename M>
convertDqeMatrixDataToMatrix(T & colorMatrix,M & mat,uint32_t dimension)25 int32_t convertDqeMatrixDataToMatrix(T &colorMatrix, M &mat,
26 uint32_t dimension) {
27 if (colorMatrix.coeffs.size() != (dimension * dimension)) {
28 HWC_LOGE(nullptr, "Invalid coeff size(%zu)",
29 colorMatrix.coeffs.size());
30 return -EINVAL;
31 }
32 for (uint32_t i = 0; i < (dimension * dimension); i++) {
33 mat.coeffs[i] = colorMatrix.coeffs[i];
34 }
35
36 if (colorMatrix.offsets.size() != dimension) {
37 HWC_LOGE(nullptr, "Invalid offset size(%zu)",
38 colorMatrix.offsets.size());
39 return -EINVAL;
40 }
41 for (uint32_t i = 0; i < dimension; i++) {
42 mat.offsets[i] = colorMatrix.offsets[i];
43 }
44 return NO_ERROR;
45 }
46
47 using namespace gs101;
48
49 /////////////////////////////////////////////////// ExynosDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)50 ExynosDisplayDrmInterfaceModule::ExynosDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
51 : ExynosDisplayDrmInterface(exynosDisplay)
52 {
53 }
54
~ExynosDisplayDrmInterfaceModule()55 ExynosDisplayDrmInterfaceModule::~ExynosDisplayDrmInterfaceModule()
56 {
57 }
58
parseBpcEnums(const DrmProperty & property)59 void ExynosDisplayDrmInterfaceModule::parseBpcEnums(const DrmProperty& property)
60 {
61 const std::vector<std::pair<uint32_t, const char *>> bpcEnums = {
62 {static_cast<uint32_t>(BPC_UNSPECIFIED), "Unspecified"},
63 {static_cast<uint32_t>(BPC_8), "8bpc"},
64 {static_cast<uint32_t>(BPC_10), "10bpc"},
65 };
66
67 ALOGD("Init bpc enums");
68 DrmEnumParser::parseEnums(property, bpcEnums, mBpcEnums);
69 for (auto &e : mBpcEnums) {
70 ALOGD("bpc [bpc: %d, drm: %" PRId64 "]", e.first, e.second);
71 }
72 }
73
initDrmDevice(DrmDevice * drmDevice)74 int32_t ExynosDisplayDrmInterfaceModule::initDrmDevice(DrmDevice *drmDevice)
75 {
76 int ret = NO_ERROR;
77 if ((ret = ExynosDisplayDrmInterface::initDrmDevice(drmDevice)) != NO_ERROR)
78 return ret;
79
80 if (isPrimary() == false)
81 return ret;
82
83 mOldDqeBlobs.init(drmDevice);
84
85 initOldDppBlobs(drmDevice);
86 if (mDrmCrtc->force_bpc_property().id())
87 parseBpcEnums(mDrmCrtc->force_bpc_property());
88
89 mOldHistoBlobs.init(drmDevice);
90
91 return ret;
92 }
93
destroyOldBlobs(std::vector<uint32_t> & oldBlobs)94 void ExynosDisplayDrmInterfaceModule::destroyOldBlobs(
95 std::vector<uint32_t> &oldBlobs)
96 {
97 for (auto &blob : oldBlobs) {
98 mDrmDevice->DestroyPropertyBlob(blob);
99 }
100 oldBlobs.clear();
101 }
102
createCgcBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)103 int32_t ExynosDisplayDrmInterfaceModule::createCgcBlobFromIDqe(
104 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
105 {
106 struct cgc_lut cgc;
107 const IDisplayColorGS101::IDqe::CgcData &cgcData = dqe.Cgc();
108
109 if (cgcData.config == nullptr) {
110 ALOGE("no CGC config");
111 return -EINVAL;
112 }
113
114 if ((cgcData.config->r_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT) ||
115 (cgcData.config->g_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT) ||
116 (cgcData.config->b_values.size() != DRM_SAMSUNG_CGC_LUT_REG_CNT)) {
117 ALOGE("CGC data size is not same (r: %zu, g: %zu: b: %zu)",
118 cgcData.config->r_values.size(),
119 cgcData.config->g_values.size(),
120 cgcData.config->b_values.size());
121 return -EINVAL;
122 }
123
124 for (uint32_t i = 0; i < DRM_SAMSUNG_CGC_LUT_REG_CNT; i++) {
125 cgc.r_values[i] = cgcData.config->r_values[i];
126 cgc.g_values[i] = cgcData.config->g_values[i];
127 cgc.b_values[i] = cgcData.config->b_values[i];
128 }
129 int ret = mDrmDevice->CreatePropertyBlob(&cgc, sizeof(cgc_lut), &blobId);
130 if (ret) {
131 HWC_LOGE(mExynosDisplay, "Failed to create cgc blob %d", ret);
132 return ret;
133 }
134 return NO_ERROR;
135 }
136
createDegammaLutBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)137 int32_t ExynosDisplayDrmInterfaceModule::createDegammaLutBlobFromIDqe(
138 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
139 {
140 int ret = 0;
141 uint64_t lut_size = 0;
142
143 if (dqe.DegammaLut().config == nullptr) {
144 ALOGE("no degamma config");
145 return -EINVAL;
146 }
147
148 std::tie(ret, lut_size) = mDrmCrtc->degamma_lut_size_property().value();
149 if (ret < 0) {
150 HWC_LOGE(mExynosDisplay, "%s: there is no degamma_lut_size (ret = %d)",
151 __func__, ret);
152 return ret;
153 }
154 if (lut_size != IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen) {
155 HWC_LOGE(mExynosDisplay, "%s: invalid lut size (%" PRId64 ")",
156 __func__, lut_size);
157 return -EINVAL;
158 }
159
160 struct drm_color_lut color_lut[IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen];
161 for (uint32_t i = 0; i < lut_size; i++) {
162 color_lut[i].red = dqe.DegammaLut().config->values[i];
163 }
164 ret = mDrmDevice->CreatePropertyBlob(color_lut, sizeof(color_lut), &blobId);
165 if (ret) {
166 HWC_LOGE(mExynosDisplay, "Failed to create degamma lut blob %d", ret);
167 return ret;
168 }
169 return NO_ERROR;
170 }
171
createRegammaLutBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)172 int32_t ExynosDisplayDrmInterfaceModule::createRegammaLutBlobFromIDqe(
173 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
174 {
175 int ret = 0;
176 uint64_t lut_size = 0;
177
178 if (dqe.RegammaLut().config == nullptr) {
179 ALOGE("no regamma config");
180 return -EINVAL;
181 }
182
183 std::tie(ret, lut_size) = mDrmCrtc->gamma_lut_size_property().value();
184 if (ret < 0) {
185 HWC_LOGE(mExynosDisplay, "%s: there is no gamma_lut_size (ret = %d)",
186 __func__, ret);
187 return ret;
188 }
189 if (lut_size != IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen) {
190 HWC_LOGE(mExynosDisplay, "%s: invalid lut size (%" PRId64 ")",
191 __func__, lut_size);
192 return -EINVAL;
193 }
194
195 struct drm_color_lut color_lut[IDisplayColorGS101::IDqe::DegammaLutData::ConfigType::kLutLen];
196 for (uint32_t i = 0; i < lut_size; i++) {
197 color_lut[i].red = dqe.RegammaLut().config->r_values[i];
198 color_lut[i].green = dqe.RegammaLut().config->g_values[i];
199 color_lut[i].blue = dqe.RegammaLut().config->b_values[i];
200 }
201 ret = mDrmDevice->CreatePropertyBlob(color_lut, sizeof(color_lut), &blobId);
202 if (ret) {
203 HWC_LOGE(mExynosDisplay, "Failed to create gamma lut blob %d", ret);
204 return ret;
205 }
206 return NO_ERROR;
207 }
208
createGammaMatBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)209 int32_t ExynosDisplayDrmInterfaceModule::createGammaMatBlobFromIDqe(
210 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
211 {
212 int ret = 0;
213 struct exynos_matrix gamma_matrix;
214 if ((ret = convertDqeMatrixDataToMatrix(
215 dqe.GammaMatrix().config->matrix_data, gamma_matrix, DRM_SAMSUNG_MATRIX_DIMENS)) != NO_ERROR)
216 {
217 HWC_LOGE(mExynosDisplay, "Failed to convert gamma matrix");
218 return ret;
219 }
220 ret = mDrmDevice->CreatePropertyBlob(&gamma_matrix, sizeof(gamma_matrix), &blobId);
221 if (ret) {
222 HWC_LOGE(mExynosDisplay, "Failed to create gamma matrix blob %d", ret);
223 return ret;
224 }
225
226 return NO_ERROR;
227 }
228
createLinearMatBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)229 int32_t ExynosDisplayDrmInterfaceModule::createLinearMatBlobFromIDqe(
230 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
231 {
232 int ret = 0;
233 struct exynos_matrix linear_matrix;
234 if ((ret = convertDqeMatrixDataToMatrix(
235 dqe.LinearMatrix().config->matrix_data, linear_matrix, DRM_SAMSUNG_MATRIX_DIMENS)) != NO_ERROR)
236 {
237 HWC_LOGE(mExynosDisplay, "Failed to convert linear matrix");
238 return ret;
239 }
240 ret = mDrmDevice->CreatePropertyBlob(&linear_matrix, sizeof(linear_matrix), &blobId);
241 if (ret) {
242 HWC_LOGE(mExynosDisplay, "Failed to create linear matrix blob %d", ret);
243 return ret;
244 }
245
246 return NO_ERROR;
247 }
248
createDispDitherBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)249 int32_t ExynosDisplayDrmInterfaceModule::createDispDitherBlobFromIDqe(
250 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
251 {
252 int ret = 0;
253 const IDisplayColorGS101::IDqe::DqeControlData& dqeControl = dqe.DqeControl();
254 if (dqeControl.config->disp_dither_override == false) {
255 blobId = 0;
256 return ret;
257 }
258
259 ret = mDrmDevice->CreatePropertyBlob((void*)&dqeControl.config->disp_dither_reg,
260 sizeof(dqeControl.config->disp_dither_reg), &blobId);
261 if (ret) {
262 HWC_LOGE(mExynosDisplay, "Failed to create disp dither blob %d", ret);
263 return ret;
264 }
265
266 return NO_ERROR;
267 }
268
createCgcDitherBlobFromIDqe(const IDisplayColorGS101::IDqe & dqe,uint32_t & blobId)269 int32_t ExynosDisplayDrmInterfaceModule::createCgcDitherBlobFromIDqe(
270 const IDisplayColorGS101::IDqe &dqe, uint32_t &blobId)
271 {
272 int ret = 0;
273 const IDisplayColorGS101::IDqe::DqeControlData& dqeControl = dqe.DqeControl();
274 if (dqeControl.config->cgc_dither_override == false) {
275 blobId = 0;
276 return ret;
277 }
278
279 ret = mDrmDevice->CreatePropertyBlob((void*)&dqeControl.config->cgc_dither_reg,
280 sizeof(dqeControl.config->cgc_dither_reg), &blobId);
281 if (ret) {
282 HWC_LOGE(mExynosDisplay, "Failed to create disp dither blob %d", ret);
283 return ret;
284 }
285 return NO_ERROR;
286 }
287
createEotfBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)288 int32_t ExynosDisplayDrmInterfaceModule::createEotfBlobFromIDpp(
289 const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
290 {
291 struct hdr_eotf_lut eotf_lut;
292
293 if (dpp.EotfLut().config == nullptr) {
294 ALOGE("no dpp eotf config");
295 return -EINVAL;
296 }
297
298 if ((dpp.EotfLut().config->tf_data.posx.size() != DRM_SAMSUNG_HDR_EOTF_LUT_LEN) ||
299 (dpp.EotfLut().config->tf_data.posy.size() != DRM_SAMSUNG_HDR_EOTF_LUT_LEN)) {
300 HWC_LOGE(mExynosDisplay, "%s: eotf pos size (%zu, %zu)",
301 __func__, dpp.EotfLut().config->tf_data.posx.size(),
302 dpp.EotfLut().config->tf_data.posy.size());
303 return -EINVAL;
304 }
305
306 for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_EOTF_LUT_LEN; i++) {
307 eotf_lut.posx[i] = dpp.EotfLut().config->tf_data.posx[i];
308 eotf_lut.posy[i] = dpp.EotfLut().config->tf_data.posy[i];
309 }
310 int ret = mDrmDevice->CreatePropertyBlob(&eotf_lut, sizeof(eotf_lut), &blobId);
311 if (ret) {
312 HWC_LOGE(mExynosDisplay, "Failed to create eotf lut blob %d", ret);
313 return ret;
314 }
315 return NO_ERROR;
316 }
317
createGmBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)318 int32_t ExynosDisplayDrmInterfaceModule::createGmBlobFromIDpp(
319 const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
320 {
321 int ret = 0;
322 struct hdr_gm_data gm_matrix;
323
324 if (dpp.Gm().config == nullptr) {
325 ALOGE("no dpp GM config");
326 return -EINVAL;
327 }
328
329 if ((ret = convertDqeMatrixDataToMatrix(dpp.Gm().config->matrix_data, gm_matrix,
330 DRM_SAMSUNG_HDR_GM_DIMENS)) != NO_ERROR)
331 {
332 HWC_LOGE(mExynosDisplay, "Failed to convert gm matrix");
333 return ret;
334 }
335 ret = mDrmDevice->CreatePropertyBlob(&gm_matrix, sizeof(gm_matrix), &blobId);
336 if (ret) {
337 HWC_LOGE(mExynosDisplay, "Failed to create gm matrix blob %d", ret);
338 return ret;
339 }
340 return NO_ERROR;
341 }
342
createDtmBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)343 int32_t ExynosDisplayDrmInterfaceModule::createDtmBlobFromIDpp(
344 const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
345 {
346 struct hdr_tm_data tm_data;
347
348 if (dpp.Dtm().config == nullptr) {
349 ALOGE("no dpp DTM config");
350 return -EINVAL;
351 }
352
353 if ((dpp.Dtm().config->tf_data.posx.size() != DRM_SAMSUNG_HDR_TM_LUT_LEN) ||
354 (dpp.Dtm().config->tf_data.posy.size() != DRM_SAMSUNG_HDR_TM_LUT_LEN)) {
355 HWC_LOGE(mExynosDisplay, "%s: dtm pos size (%zu, %zu)",
356 __func__, dpp.Dtm().config->tf_data.posx.size(),
357 dpp.Dtm().config->tf_data.posy.size());
358 return -EINVAL;
359 }
360
361 for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_TM_LUT_LEN; i++) {
362 tm_data.posx[i] = dpp.Dtm().config->tf_data.posx[i];
363 tm_data.posy[i] = dpp.Dtm().config->tf_data.posy[i];
364 }
365
366 tm_data.coeff_r = dpp.Dtm().config->coeff_r;
367 tm_data.coeff_g = dpp.Dtm().config->coeff_g;
368 tm_data.coeff_b = dpp.Dtm().config->coeff_b;
369 tm_data.rng_x_min = dpp.Dtm().config->rng_x_min;
370 tm_data.rng_x_max = dpp.Dtm().config->rng_x_max;
371 tm_data.rng_y_min = dpp.Dtm().config->rng_y_min;
372 tm_data.rng_y_max = dpp.Dtm().config->rng_y_max;
373
374 int ret = mDrmDevice->CreatePropertyBlob(&tm_data, sizeof(tm_data), &blobId);
375 if (ret) {
376 HWC_LOGE(mExynosDisplay, "Failed to create tm_data blob %d", ret);
377 return ret;
378 }
379
380 return NO_ERROR;
381 }
createOetfBlobFromIDpp(const IDisplayColorGS101::IDpp & dpp,uint32_t & blobId)382 int32_t ExynosDisplayDrmInterfaceModule::createOetfBlobFromIDpp(
383 const IDisplayColorGS101::IDpp &dpp, uint32_t &blobId)
384 {
385 struct hdr_oetf_lut oetf_lut;
386
387 if (dpp.OetfLut().config == nullptr) {
388 ALOGE("no dpp OETF config");
389 return -EINVAL;
390 }
391
392 if ((dpp.OetfLut().config->tf_data.posx.size() != DRM_SAMSUNG_HDR_OETF_LUT_LEN) ||
393 (dpp.OetfLut().config->tf_data.posy.size() != DRM_SAMSUNG_HDR_OETF_LUT_LEN)) {
394 HWC_LOGE(mExynosDisplay, "%s: oetf pos size (%zu, %zu)",
395 __func__, dpp.OetfLut().config->tf_data.posx.size(),
396 dpp.OetfLut().config->tf_data.posy.size());
397 return -EINVAL;
398 }
399
400 for (uint32_t i = 0; i < DRM_SAMSUNG_HDR_OETF_LUT_LEN; i++) {
401 oetf_lut.posx[i] = dpp.OetfLut().config->tf_data.posx[i];
402 oetf_lut.posy[i] = dpp.OetfLut().config->tf_data.posy[i];
403 }
404 int ret = mDrmDevice->CreatePropertyBlob(&oetf_lut, sizeof(oetf_lut), &blobId);
405 if (ret) {
406 HWC_LOGE(mExynosDisplay, "Failed to create oetf lut blob %d", ret);
407 return ret;
408 }
409 return NO_ERROR;
410 }
411
412 template<typename StageDataType>
setDisplayColorBlob(const DrmProperty & prop,const uint32_t type,const StageDataType & stage,const IDisplayColorGS101::IDqe & dqe,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)413 int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorBlob(
414 const DrmProperty &prop,
415 const uint32_t type,
416 const StageDataType &stage,
417 const IDisplayColorGS101::IDqe &dqe,
418 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
419 {
420 /* dirty bit is valid only if enable is true */
421 if (!prop.id())
422 return NO_ERROR;
423 if (!mForceDisplayColorSetting && stage.enable && !stage.dirty)
424 return NO_ERROR;
425
426 int32_t ret = 0;
427 uint32_t blobId = 0;
428
429 if (stage.enable) {
430 switch (type) {
431 case DqeBlobs::CGC:
432 ret = createCgcBlobFromIDqe(dqe, blobId);
433 break;
434 case DqeBlobs::DEGAMMA_LUT:
435 ret = createDegammaLutBlobFromIDqe(dqe, blobId);
436 break;
437 case DqeBlobs::REGAMMA_LUT:
438 ret = createRegammaLutBlobFromIDqe(dqe, blobId);
439 break;
440 case DqeBlobs::GAMMA_MAT:
441 ret = createGammaMatBlobFromIDqe(dqe, blobId);
442 break;
443 case DqeBlobs::LINEAR_MAT:
444 ret = createLinearMatBlobFromIDqe(dqe, blobId);
445 break;
446 case DqeBlobs::DISP_DITHER:
447 ret = createDispDitherBlobFromIDqe(dqe, blobId);
448 break;
449 case DqeBlobs::CGC_DITHER:
450 ret = createCgcDitherBlobFromIDqe(dqe, blobId);
451 break;
452 default:
453 ret = -EINVAL;
454 }
455 if (ret != NO_ERROR) {
456 HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
457 return ret;
458 }
459 }
460
461 /* Skip setting when previous and current setting is same with 0 */
462 if ((blobId == 0) && (mOldDqeBlobs.getBlob(type) == 0))
463 return ret;
464
465 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
466 HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
467 __func__);
468 return ret;
469 }
470 mOldDqeBlobs.addBlob(type, blobId);
471
472 // disp_dither and cgc dither are part of DqeCtrl stage and the notification
473 // will be sent after all data in DqeCtrl stage are applied.
474 if (type != DqeBlobs::DISP_DITHER && type != DqeBlobs::CGC_DITHER)
475 stage.NotifyDataApplied();
476
477 return ret;
478 }
setDisplayColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)479 int32_t ExynosDisplayDrmInterfaceModule::setDisplayColorSetting(
480 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq)
481 {
482 if (isPrimary() == false)
483 return NO_ERROR;
484 if (!mForceDisplayColorSetting && !mColorSettingChanged)
485 return NO_ERROR;
486
487 ExynosPrimaryDisplayModule* display =
488 (ExynosPrimaryDisplayModule*)mExynosDisplay;
489
490 int ret = NO_ERROR;
491 const IDisplayColorGS101::IDqe &dqe = display->getDqe();
492
493 if ((mDrmCrtc->cgc_lut_property().id() != 0) &&
494 (ret = setDisplayColorBlob(mDrmCrtc->cgc_lut_property(),
495 static_cast<uint32_t>(DqeBlobs::CGC),
496 dqe.Cgc(), dqe, drmReq) != NO_ERROR)) {
497 HWC_LOGE(mExynosDisplay, "%s: set Cgc blob fail", __func__);
498 return ret;
499 }
500 if ((ret = setDisplayColorBlob(mDrmCrtc->degamma_lut_property(),
501 static_cast<uint32_t>(DqeBlobs::DEGAMMA_LUT),
502 dqe.DegammaLut(), dqe, drmReq) != NO_ERROR)) {
503 HWC_LOGE(mExynosDisplay, "%s: set DegammaLut blob fail", __func__);
504 return ret;
505 }
506 if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_lut_property(),
507 static_cast<uint32_t>(DqeBlobs::REGAMMA_LUT),
508 dqe.RegammaLut(), dqe, drmReq) != NO_ERROR)) {
509 HWC_LOGE(mExynosDisplay, "%s: set RegammaLut blob fail", __func__);
510 return ret;
511 }
512 if ((ret = setDisplayColorBlob(mDrmCrtc->gamma_matrix_property(),
513 static_cast<uint32_t>(DqeBlobs::GAMMA_MAT),
514 dqe.GammaMatrix(), dqe, drmReq) != NO_ERROR)) {
515 HWC_LOGE(mExynosDisplay, "%s: set GammaMatrix blob fail", __func__);
516 return ret;
517 }
518 if ((ret = setDisplayColorBlob(mDrmCrtc->linear_matrix_property(),
519 static_cast<uint32_t>(DqeBlobs::LINEAR_MAT),
520 dqe.LinearMatrix(), dqe, drmReq) != NO_ERROR)) {
521 HWC_LOGE(mExynosDisplay, "%s: set LinearMatrix blob fail", __func__);
522 return ret;
523 }
524 if ((ret = setDisplayColorBlob(mDrmCrtc->disp_dither_property(),
525 static_cast<uint32_t>(DqeBlobs::DISP_DITHER),
526 dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
527 HWC_LOGE(mExynosDisplay, "%s: set DispDither blob fail", __func__);
528 return ret;
529 }
530 if ((ret = setDisplayColorBlob(mDrmCrtc->cgc_dither_property(),
531 static_cast<uint32_t>(DqeBlobs::CGC_DITHER),
532 dqe.DqeControl(), dqe, drmReq) != NO_ERROR)) {
533 HWC_LOGE(mExynosDisplay, "%s: set CgcDither blob fail", __func__);
534 return ret;
535 }
536
537 const DrmProperty &prop_force_bpc = mDrmCrtc->force_bpc_property();
538 if (prop_force_bpc.id()) {
539 uint32_t bpc = static_cast<uint32_t>(BPC_UNSPECIFIED);
540 if (dqe.DqeControl().enable) {
541 if (dqe.DqeControl().config->force_10bpc)
542 bpc = static_cast<uint32_t>(BPC_10);
543 }
544 auto [bpcEnum, ret] = DrmEnumParser::halToDrmEnum(bpc, mBpcEnums);
545 if (ret < 0) {
546 HWC_LOGE(mExynosDisplay, "Fail to convert bpc(%d)", bpc);
547 } else {
548 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_force_bpc,
549 bpcEnum, true)) < 0) {
550 HWC_LOGE(mExynosDisplay, "%s: Fail to set force bpc property",
551 __func__);
552 }
553 }
554 }
555 dqe.DqeControl().NotifyDataApplied();
556
557 return NO_ERROR;
558 }
559
560 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)561 int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorBlob(
562 const std::unique_ptr<DrmPlane> &plane,
563 const DrmProperty &prop,
564 const uint32_t type,
565 const StageDataType &stage,
566 const IDisplayColorGS101::IDpp &dpp,
567 const uint32_t dppIndex,
568 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
569 bool forceUpdate)
570 {
571 /* dirty bit is valid only if enable is true */
572 if (!prop.id() || (stage.enable && !stage.dirty && !forceUpdate))
573 return NO_ERROR;
574
575 uint32_t ix = 0;
576 for (;ix < mOldDppBlobs.size(); ix++) {
577 if (mOldDppBlobs[ix].planeId == plane->id()) {
578 break;
579 }
580 }
581 if (ix >= mOldDppBlobs.size()) {
582 HWC_LOGE(mExynosDisplay, "%s: could not find plane %d", __func__, plane->id());
583 return -EINVAL;
584 }
585 DppBlobs &oldDppBlobs = mOldDppBlobs[ix];
586
587 int32_t ret = 0;
588 uint32_t blobId = 0;
589
590 if (stage.enable) {
591 switch (type) {
592 case DppBlobs::EOTF:
593 ret = createEotfBlobFromIDpp(dpp, blobId);
594 break;
595 case DppBlobs::GM:
596 ret = createGmBlobFromIDpp(dpp, blobId);
597 break;
598 case DppBlobs::DTM:
599 ret = createDtmBlobFromIDpp(dpp, blobId);
600 break;
601 case DppBlobs::OETF:
602 ret = createOetfBlobFromIDpp(dpp, blobId);
603 break;
604 default:
605 ret = -EINVAL;
606 }
607 if (ret != NO_ERROR) {
608 HWC_LOGE(mExynosDisplay, "%s: create blob fail", __func__);
609 return ret;
610 }
611 }
612
613 /* Skip setting when previous and current setting is same with 0 */
614 if ((blobId == 0) && (oldDppBlobs.getBlob(type) == 0) && !forceUpdate)
615 return ret;
616
617 if ((ret = drmReq.atomicAddProperty(plane->id(), prop, blobId)) < 0) {
618 HWC_LOGE(mExynosDisplay, "%s: Fail to set property",
619 __func__);
620 return ret;
621 }
622
623 oldDppBlobs.addBlob(type, blobId);
624 stage.NotifyDataApplied();
625
626 return ret;
627 }
628
setPlaneColorSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq,const std::unique_ptr<DrmPlane> & plane,const exynos_win_config_data & config,uint32_t & solidColor)629 int32_t ExynosDisplayDrmInterfaceModule::setPlaneColorSetting(
630 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
631 const std::unique_ptr<DrmPlane> &plane,
632 const exynos_win_config_data &config, uint32_t &solidColor)
633 {
634 if ((mColorSettingChanged == false) ||
635 (isPrimary() == false))
636 return NO_ERROR;
637
638 if ((config.assignedMPP == nullptr) ||
639 (config.assignedMPP->mAssignedSources.size() == 0)) {
640 HWC_LOGE(mExynosDisplay, "%s:: config's mpp source size is invalid",
641 __func__);
642 return -EINVAL;
643 }
644 ExynosMPPSource* mppSource = config.assignedMPP->mAssignedSources[0];
645 if (mppSource->mSourceType >= MPP_SOURCE_MAX) {
646 HWC_LOGE(mExynosDisplay,
647 "%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
648 return -EINVAL;
649 }
650
651 ExynosPrimaryDisplayModule* display = (ExynosPrimaryDisplayModule*)mExynosDisplay;
652
653 /*
654 * Color conversion of Client and Exynos composition buffer
655 * is already addressed by GLES or G2D. But as of now, 'dim SDR' is only
656 * supported by HWC/displaycolor, we need put client composition under
657 * control of HWC/displaycolor.
658 */
659 if (!display->hasDppForLayer(mppSource)) {
660 if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
661 HWC_LOGE(mExynosDisplay,
662 "%s: layer need color conversion but there is no IDpp",
663 __func__);
664 return -EINVAL;
665 } else if (mppSource->mSourceType == MPP_SOURCE_COMPOSITION_TARGET) {
666 return NO_ERROR;
667 } else {
668 HWC_LOGE(mExynosDisplay,
669 "%s: invalid mpp source type (%d)", __func__, mppSource->mSourceType);
670 return -EINVAL;
671 }
672 }
673
674 if (mppSource->mSourceType == MPP_SOURCE_LAYER) {
675 ExynosLayer* layer = (ExynosLayer*)mppSource;
676
677 /* color conversion was already handled by m2mMPP */
678 if ((layer->mM2mMPP != nullptr) &&
679 (layer->mSrcImg.dataSpace != layer->mMidImg.dataSpace)) {
680 return NO_ERROR;
681 }
682 }
683
684 const IDisplayColorGS101::IDpp &dpp = display->getDppForLayer(mppSource);
685 const uint32_t dppIndex = static_cast<uint32_t>(display->getDppIndexForLayer(mppSource));
686 bool planeChanged = display->checkAndSaveLayerPlaneId(mppSource, plane->id());
687
688 auto &color = dpp.SolidColor();
689 // exynos_win_config_data.color ARGB
690 solidColor = (color.a << 24) | (color.r << 16) | (color.g << 8) | color.b;
691
692 int ret = 0;
693 if ((ret = setPlaneColorBlob(plane, plane->eotf_lut_property(),
694 static_cast<uint32_t>(DppBlobs::EOTF),
695 dpp.EotfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
696 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set oetf blob fail",
697 __func__, dppIndex);
698 return ret;
699 }
700 if ((ret = setPlaneColorBlob(plane, plane->gammut_matrix_property(),
701 static_cast<uint32_t>(DppBlobs::GM),
702 dpp.Gm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
703 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set GM blob fail",
704 __func__, dppIndex);
705 return ret;
706 }
707 if ((ret = setPlaneColorBlob(plane, plane->tone_mapping_property(),
708 static_cast<uint32_t>(DppBlobs::DTM),
709 dpp.Dtm(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
710 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set DTM blob fail",
711 __func__, dppIndex);
712 return ret;
713 }
714 if ((ret = setPlaneColorBlob(plane, plane->oetf_lut_property(),
715 static_cast<uint32_t>(DppBlobs::OETF),
716 dpp.OetfLut(), dpp, dppIndex, drmReq, planeChanged) != NO_ERROR)) {
717 HWC_LOGE(mExynosDisplay, "%s: dpp[%d] set OETF blob fail",
718 __func__, dppIndex);
719 return ret;
720 }
721
722 return 0;
723 }
724
~SaveBlob()725 ExynosDisplayDrmInterfaceModule::SaveBlob::~SaveBlob()
726 {
727 for (auto &it: blobs) {
728 mDrmDevice->DestroyPropertyBlob(it);
729 }
730 blobs.clear();
731 }
732
addBlob(uint32_t type,uint32_t blob)733 void ExynosDisplayDrmInterfaceModule::SaveBlob::addBlob(
734 uint32_t type, uint32_t blob)
735 {
736 if (type >= blobs.size()) {
737 ALOGE("Invalid dqe blop type: %d", type);
738 return;
739 }
740 if (blobs[type] > 0)
741 mDrmDevice->DestroyPropertyBlob(blobs[type]);
742
743 blobs[type] = blob;
744 }
745
getBlob(uint32_t type)746 uint32_t ExynosDisplayDrmInterfaceModule::SaveBlob::getBlob(uint32_t type)
747 {
748 if (type >= blobs.size()) {
749 ALOGE("Invalid dqe blop type: %d", type);
750 return 0;
751 }
752 return blobs[type];
753 }
754
getDisplayInfo(std::vector<displaycolor::DisplayInfo> & display_info)755 void ExynosDisplayDrmInterfaceModule::getDisplayInfo(
756 std::vector<displaycolor::DisplayInfo> &display_info) {
757 displaycolor::DisplayInfo primary_display;
758 auto &tb = primary_display.brightness_table;
759 auto *brightnessTable = mExynosDisplay->mBrightnessController->getBrightnessTable();
760
761 tb.nbm_nits_min = brightnessTable[toUnderlying(BrightnessRange::NORMAL)].mNitsStart;
762 tb.nbm_nits_max = brightnessTable[toUnderlying(BrightnessRange::NORMAL)].mNitsEnd;
763 tb.nbm_dbv_min = brightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklStart;
764 tb.nbm_dbv_max = brightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklEnd;
765
766 tb.hbm_nits_min = brightnessTable[toUnderlying(BrightnessRange::HBM)].mNitsStart;
767 tb.hbm_nits_max = brightnessTable[toUnderlying(BrightnessRange::HBM)].mNitsEnd;
768 tb.hbm_dbv_min = brightnessTable[toUnderlying(BrightnessRange::HBM)].mBklStart;
769 tb.hbm_dbv_max = brightnessTable[toUnderlying(BrightnessRange::HBM)].mBklEnd;
770
771 primary_display.panel_name = GetPanelName();
772 primary_display.panel_serial = GetPanelSerial();
773
774 display_info.push_back(primary_display);
775 }
776
GetPanelInfo(const std::string & sysfs_rel,char delim)777 const std::string ExynosDisplayDrmInterfaceModule::GetPanelInfo(const std::string &sysfs_rel,
778 char delim) {
779 ExynosPrimaryDisplayModule* display = (ExynosPrimaryDisplayModule*)mExynosDisplay;
780 const DisplayType type = display->getBuiltInDisplayType();
781 const std::string &sysfs = display->getPanelSysfsPath(type);
782
783 if (sysfs.empty()) {
784 return "";
785 }
786
787 std::string info;
788 if (readLineFromFile(sysfs + "/" + sysfs_rel, info, delim) != OK) {
789 ALOGE("failed reading %s/%s", sysfs.c_str(), sysfs_rel.c_str());
790 return "";
791 }
792
793 return info;
794 }
795
796 /* For Histogram */
createHistoRoiBlob(uint32_t & blobId)797 int32_t ExynosDisplayDrmInterfaceModule::createHistoRoiBlob(uint32_t &blobId) {
798 struct histogram_roi histo_roi;
799
800 std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
801 histo_roi.start_x = mHistogramInfo->getHistogramROI().start_x;
802 histo_roi.start_y = mHistogramInfo->getHistogramROI().start_y;
803 histo_roi.hsize = mHistogramInfo->getHistogramROI().hsize;
804 histo_roi.vsize = mHistogramInfo->getHistogramROI().vsize;
805
806 int ret = mDrmDevice->CreatePropertyBlob(&histo_roi, sizeof(histo_roi), &blobId);
807 if (ret) {
808 HWC_LOGE(mExynosDisplay, "Failed to create histogram roi blob %d", ret);
809 return ret;
810 }
811
812 return NO_ERROR;
813 }
814
createHistoWeightsBlob(uint32_t & blobId)815 int32_t ExynosDisplayDrmInterfaceModule::createHistoWeightsBlob(uint32_t &blobId) {
816 struct histogram_weights histo_weights;
817
818 std::unique_lock<std::mutex> lk((mHistogramInfo->mSetHistInfoMutex));
819 histo_weights.weight_r = mHistogramInfo->getHistogramWeights().weight_r;
820 histo_weights.weight_g = mHistogramInfo->getHistogramWeights().weight_g;
821 histo_weights.weight_b = mHistogramInfo->getHistogramWeights().weight_b;
822
823 int ret = mDrmDevice->CreatePropertyBlob(&histo_weights, sizeof(histo_weights), &blobId);
824 if (ret) {
825 HWC_LOGE(mExynosDisplay, "Failed to create histogram weights blob %d", ret);
826 return ret;
827 }
828
829 return NO_ERROR;
830 }
831
setDisplayHistoBlob(const DrmProperty & prop,const uint32_t type,ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)832 int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistoBlob(
833 const DrmProperty &prop, const uint32_t type,
834 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
835 if (!prop.id()) return NO_ERROR;
836
837 int32_t ret = NO_ERROR;
838 uint32_t blobId = 0;
839
840 switch (type) {
841 case HistoBlobs::ROI:
842 ret = createHistoRoiBlob(blobId);
843 break;
844 case HistoBlobs::WEIGHTS:
845 ret = createHistoWeightsBlob(blobId);
846 break;
847 default:
848 ret = -EINVAL;
849 }
850 if (ret != NO_ERROR) {
851 HWC_LOGE(mExynosDisplay, "%s: Failed to create blob", __func__);
852 return ret;
853 }
854
855 /* Skip setting when previous and current setting is same with 0 */
856 if ((blobId == 0) && (mOldHistoBlobs.getBlob(type) == 0)) return ret;
857
858 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
859 HWC_LOGE(mExynosDisplay, "%s: Failed to add property", __func__);
860 return ret;
861 }
862 mOldHistoBlobs.addBlob(type, blobId);
863
864 return ret;
865 }
866
setDisplayHistogramSetting(ExynosDisplayDrmInterface::DrmModeAtomicReq & drmReq)867 int32_t ExynosDisplayDrmInterfaceModule::setDisplayHistogramSetting(
868 ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
869 if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
870
871 int ret = NO_ERROR;
872
873 if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_roi_property(),
874 static_cast<uint32_t>(HistoBlobs::ROI), drmReq) != NO_ERROR)) {
875 HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_ROI blob", __func__);
876 return ret;
877 }
878 if ((ret = setDisplayHistoBlob(mDrmCrtc->histogram_weights_property(),
879 static_cast<uint32_t>(HistoBlobs::WEIGHTS),
880 drmReq) != NO_ERROR)) {
881 HWC_LOGE(mExynosDisplay, "%s: Failed to set Histo_Weights blob", __func__);
882 return ret;
883 }
884
885 const DrmProperty &prop_histo_threshold = mDrmCrtc->histogram_threshold_property();
886 if (prop_histo_threshold.id()) {
887 if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop_histo_threshold,
888 (uint64_t)(mHistogramInfo->getHistogramThreshold()),
889 true)) < 0) {
890 HWC_LOGE(mExynosDisplay, "%s: Failed to set histogram thereshold property", __func__);
891 return ret;
892 }
893 }
894
895 return NO_ERROR;
896 }
897
setHistogramControl(hidl_histogram_control_t control)898 int32_t ExynosDisplayDrmInterfaceModule::setHistogramControl(hidl_histogram_control_t control) {
899 if ((isHistogramInfoRegistered() == false) || (isPrimary() == false)) return NO_ERROR;
900
901 int ret = NO_ERROR;
902 uint32_t crtc_id = mDrmCrtc->id();
903
904 if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_REQUEST) {
905 ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_REQUEST, (void *)&crtc_id);
906 } else if (control == hidl_histogram_control_t::HISTOGRAM_CONTROL_CANCEL) {
907 ret = mDrmDevice->CallVendorIoctl(DRM_IOCTL_EXYNOS_HISTOGRAM_CANCEL, (void *)&crtc_id);
908 }
909
910 return ret;
911 }
912
setHistogramData(void * bin)913 int32_t ExynosDisplayDrmInterfaceModule::setHistogramData(void *bin) {
914 if (!bin) return -EINVAL;
915
916 /*
917 * There are two handling methods.
918 * For ContentSampling in HWC_2.3 API, histogram bin needs to be accumulated.
919 * For Histogram IDL, histogram bin need to be sent to IDL block.
920 */
921 if (mHistogramInfo->getHistogramType() == HistogramInfo::HistogramType::HISTOGRAM_HIDL) {
922 (mHistogramInfo.get())->callbackHistogram((char16_t *)bin);
923 } else {
924 /*
925 * ContentSampling in HWC2.3 API is not supported
926 */
927 return -ENOTSUP;
928 }
929
930 return NO_ERROR;
931 }
932
933 //////////////////////////////////////////////////// ExynosPrimaryDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)934 ExynosPrimaryDisplayDrmInterfaceModule::ExynosPrimaryDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
935 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
936 {
937 }
938
~ExynosPrimaryDisplayDrmInterfaceModule()939 ExynosPrimaryDisplayDrmInterfaceModule::~ExynosPrimaryDisplayDrmInterfaceModule()
940 {
941 }
942
943 //////////////////////////////////////////////////// ExynosExternalDisplayDrmInterfaceModule //////////////////////////////////////////////////////////////////
ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay * exynosDisplay)944 ExynosExternalDisplayDrmInterfaceModule::ExynosExternalDisplayDrmInterfaceModule(ExynosDisplay *exynosDisplay)
945 : ExynosDisplayDrmInterfaceModule(exynosDisplay)
946 {
947 }
948
~ExynosExternalDisplayDrmInterfaceModule()949 ExynosExternalDisplayDrmInterfaceModule::~ExynosExternalDisplayDrmInterfaceModule()
950 {
951 }
952