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