1 /*
2 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <drm.h>
33 // The 3 headers above are a workaround to prevent kernel drm.h from being used that has the
34 // "virtual" keyword used for a variable. In future replace libdrm version drm.h with kernel
35 // version drm/drm.h
36 #include <drm_logger.h>
37 #include <drm/drm_fourcc.h>
38 #include <drm/sde_drm.h>
39
40 #include <cstring>
41 #include <sstream>
42 #include <string>
43 #include <tuple>
44 #include <utility>
45 #include <vector>
46 #include <algorithm>
47
48 #include "drm_utils.h"
49 #include "drm_plane.h"
50 #include "drm_property.h"
51
52 namespace sde_drm {
53
54 using std::string;
55 using std::pair;
56 using std::vector;
57 using std::unique_ptr;
58 using std::tuple;
59 using std::stringstream;
60 using std::mutex;
61 using std::lock_guard;
62
63 #define MAX_SCALER_LINEWIDTH 2560
64
65 static struct sde_drm_csc_v1 csc_10bit_convert[kCscTypeMax] = {
66 [kCscYuv2Rgb601L] = {
67 {
68 0x12A000000, 0x000000000, 0x198800000,
69 0x12A000000, 0x7F9B800000, 0x7F30000000,
70 0x12A000000, 0x204800000, 0x000000000,
71 },
72 { 0xffc0, 0xfe00, 0xfe00,},
73 { 0x0, 0x0, 0x0,},
74 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
75 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
76 },
77 [kCscYuv2Rgb601FR] = {
78 {
79 0x100000000, 0x0, 0x167000000,
80 0x100000000, 0x7fa8000000, 0x7f49000000,
81 0x100000000, 0x1c5800000, 0x0,
82 },
83 { 0x0000, 0xfe00, 0xfe00,},
84 { 0x0, 0x0, 0x0,},
85 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
86 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
87 },
88 [kCscYuv2Rgb709L] = {
89 {
90 0x12a000000, 0x0, 0x1cb000000,
91 0x12a000000, 0x7fc9800000, 0x7f77800000,
92 0x12a000000, 0x21d000000, 0x0,
93 },
94 { 0xffc0, 0xfe00, 0xfe00,},
95 { 0x0, 0x0, 0x0,},
96 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
97 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
98 },
99 [kCscYuv2Rgb2020L] = {
100 {
101 0x12b000000, 0x0, 0x1af000000,
102 0x12b000000, 0x7fd0000000, 0x7f59000000,
103 0x12b000000, 0x226000000, 0x0,
104 },
105 { 0xffc0, 0xfe00, 0xfe00,},
106 { 0x0, 0x0, 0x0,},
107 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
108 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
109 },
110 [kCscYuv2Rgb2020FR] = {
111 {
112 0x100000000, 0x0, 0x179800000,
113 0x100000000, 0x7fd6000000, 0x7f6d800000,
114 0x100000000, 0x1e1800000, 0x0,
115 },
116 { 0x0000, 0xfe00, 0xfe00,},
117 { 0x0, 0x0, 0x0,},
118 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
119 { 0x0, 0x3ff, 0x0, 0x3ff, 0x0, 0x3ff,},
120 },
121 };
122
123 static uint8_t REFLECT_X = 0;
124 static uint8_t REFLECT_Y = 0;
125 static uint8_t ROTATE_90 = 0;
126 static uint8_t ROTATE_0 = 0;
127
128 // FB Secure Modes
129 static uint8_t NON_SECURE = 0;
130 static uint8_t SECURE = 1;
131 static uint8_t NON_SECURE_DIR_TRANSLATION = 2;
132 static uint8_t SECURE_DIR_TRANSLATION = 3;
133
134 // Multi rect modes
135 static uint8_t MULTIRECT_NONE = 0;
136 static uint8_t MULTIRECT_PARALLEL = 1;
137 static uint8_t MULTIRECT_SERIAL = 2;
138
SetRect(DRMRect & source,drm_clip_rect * target)139 static void SetRect(DRMRect &source, drm_clip_rect *target) {
140 target->x1 = uint16_t(source.left);
141 target->y1 = uint16_t(source.top);
142 target->x2 = uint16_t(source.right);
143 target->y2 = uint16_t(source.bottom);
144 }
145
PopulateReflect(drmModePropertyRes * prop)146 static void PopulateReflect(drmModePropertyRes *prop) {
147 if (REFLECT_X) {
148 return;
149 }
150
151 if (!drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) {
152 return;
153 }
154
155 for (auto i = 0; i < prop->count_enums; i++) {
156 string enum_name(prop->enums[i].name);
157 if (enum_name == "reflect-x") {
158 REFLECT_X = prop->enums[i].value;
159 } else if (enum_name == "reflect-y") {
160 REFLECT_Y = prop->enums[i].value;
161 } else if (enum_name == "rotate-90") {
162 ROTATE_90 = prop->enums[i].value;
163 } else if (enum_name == "rotate-0") {
164 ROTATE_0 = prop->enums[i].value;
165 }
166 }
167 }
168
PopulateSecureModes(drmModePropertyRes * prop)169 static void PopulateSecureModes(drmModePropertyRes *prop) {
170 static bool secure_modes_populated = false;
171 if (!secure_modes_populated) {
172 for (auto i = 0; i < prop->count_enums; i++) {
173 string enum_name(prop->enums[i].name);
174 if (enum_name == "non_sec") {
175 NON_SECURE = prop->enums[i].value;
176 } else if (enum_name == "sec") {
177 SECURE = prop->enums[i].value;
178 } else if (enum_name == "non_sec_direct_translation") {
179 NON_SECURE_DIR_TRANSLATION = prop->enums[i].value;
180 } else if (enum_name == "sec_direct_translation") {
181 SECURE_DIR_TRANSLATION = prop->enums[i].value;
182 }
183 }
184 secure_modes_populated = true;
185 }
186 }
187
PopulateInlineRotationVersion(uint32_t ver)188 static InlineRotationVersion PopulateInlineRotationVersion(uint32_t ver) {
189 switch (ver) {
190 case 0x0000: return InlineRotationVersion::kInlineRotationNone;
191 case 0x0001:
192 case 0x0100: return InlineRotationVersion::kInlineRotationV1;
193 case 0x0200: return InlineRotationVersion::kInlineRotationV2;
194 default: return InlineRotationVersion::kInlineRotationNone;
195 }
196 }
197
PopulateQseedStepVersion(uint32_t hw_ver)198 static QSEEDStepVersion PopulateQseedStepVersion(uint32_t hw_ver) {
199 switch (hw_ver) {
200 case 0x1003: return QSEEDStepVersion::V3;
201 case 0x1004: return QSEEDStepVersion::V4;
202 case 0x2004: return QSEEDStepVersion::V3LITE_V4;
203 case 0x3000: return QSEEDStepVersion::V3LITE_V5;
204 // default value. also corresponds to (hw_ver == 0x1002)
205 default: return QSEEDStepVersion::V2;
206 }
207 }
208
PopulateMultiRectModes(drmModePropertyRes * prop)209 static void PopulateMultiRectModes(drmModePropertyRes *prop) {
210 static bool multirect_modes_populated = false;
211 if (!multirect_modes_populated) {
212 for (auto i = 0; i < prop->count_enums; i++) {
213 string enum_name(prop->enums[i].name);
214 if (enum_name == "none") {
215 MULTIRECT_NONE = prop->enums[i].value;
216 } else if (enum_name == "parallel") {
217 MULTIRECT_PARALLEL = prop->enums[i].value;
218 } else if (enum_name == "serial") {
219 MULTIRECT_SERIAL = prop->enums[i].value;
220 }
221 }
222 multirect_modes_populated = true;
223 }
224 }
225
GetColorLutString(DRMTonemapLutType lut_type)226 static const char *GetColorLutString(DRMTonemapLutType lut_type) {
227 switch (lut_type) {
228 case DRMTonemapLutType::DMA_1D_IGC:
229 return "DMA IGC";
230 case DRMTonemapLutType::DMA_1D_GC:
231 return "DMA GC";
232 case DRMTonemapLutType::VIG_1D_IGC:
233 return "VIG IGC";
234 case DRMTonemapLutType::VIG_3D_GAMUT:
235 return "VIG 3D";
236 default:
237 return "Unknown Lut";
238 }
239 }
240
241 #define __CLASS__ "DRMPlaneManager"
242
GetDRMonemapLutTypeFromPPFeatureID(DRMPPFeatureID id,DRMTonemapLutType * lut_type)243 static bool GetDRMonemapLutTypeFromPPFeatureID(DRMPPFeatureID id, DRMTonemapLutType *lut_type) {
244 switch (id) {
245 case kFeatureDgmIgc:
246 *lut_type = DRMTonemapLutType::DMA_1D_IGC;
247 break;
248 case kFeatureDgmGc:
249 *lut_type = DRMTonemapLutType::DMA_1D_GC;
250 break;
251 case kFeatureVigIgc:
252 *lut_type = DRMTonemapLutType::VIG_1D_IGC;
253 break;
254 case kFeatureVigGamut:
255 *lut_type = DRMTonemapLutType::VIG_3D_GAMUT;
256 break;
257 default:
258 DRM_LOGE("Invalid DRMPPFeature id = %d", id);
259 return false;
260 }
261 return true;
262 }
263
DRMPlaneManager(int fd)264 DRMPlaneManager::DRMPlaneManager(int fd) : fd_(fd) {}
265
Init()266 void DRMPlaneManager::Init() {
267 drmModePlaneRes *resource = drmModeGetPlaneResources(fd_);
268 if (!resource) {
269 return;
270 }
271
272 for (uint32_t i = 0; i < resource->count_planes; i++) {
273 // The enumeration order itself is the priority from high to low
274 unique_ptr<DRMPlane> plane(new DRMPlane(fd_, i));
275 drmModePlane *libdrm_plane = drmModeGetPlane(fd_, resource->planes[i]);
276 if (libdrm_plane) {
277 plane->InitAndParse(libdrm_plane);
278 object_pool_[resource->planes[i]] = std::move(plane);
279 } else {
280 DRM_LOGE("Critical error: drmModeGetPlane() failed for plane %d.", resource->planes[i]);
281 }
282 }
283
284 drmModeFreePlaneResources(resource);
285 }
286
Perform(DRMOps code,uint32_t obj_id,drmModeAtomicReq * req,va_list args)287 void DRMPlaneManager::Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req, va_list args) {
288 auto plane = GetObject(obj_id);
289 if (plane == nullptr) {
290 DRM_LOGE("Invalid plane id %d", obj_id);
291 return;
292 }
293
294 if (code == DRMOps::PLANE_SET_SCALER_CONFIG) {
295 if (plane->ConfigureScalerLUT(dir_lut_blob_id_, cir_lut_blob_id_,
296 sep_lut_blob_id_)) {
297 DRM_LOGD("Plane %d: Configuring scaler LUTs", obj_id);
298 }
299 }
300
301 plane->Perform(code, req, args);
302 }
303
Perform(DRMOps code,drmModeAtomicReq * req,uint32_t obj_id,...)304 void DRMPlaneManager::Perform(DRMOps code, drmModeAtomicReq *req, uint32_t obj_id, ...) {
305 lock_guard<mutex> lock(lock_);
306 va_list args;
307 va_start(args, obj_id);
308 Perform(code, obj_id, req, args);
309 va_end(args);
310 }
311
GetPlanesInfo(DRMPlanesInfo * info)312 void DRMPlaneManager::GetPlanesInfo(DRMPlanesInfo *info) {
313 for (auto &plane : object_pool_) {
314 info->push_back(std::make_pair(plane.first, plane.second->GetPlaneTypeInfo()));
315 }
316 }
317
UnsetUnusedResources(uint32_t crtc_id,bool is_commit,drmModeAtomicReq * req)318 void DRMPlaneManager::UnsetUnusedResources(uint32_t crtc_id, bool is_commit, drmModeAtomicReq *req) {
319 // Unset planes that were assigned to the crtc referred to by crtc_id but are not requested
320 // in this round
321 lock_guard<mutex> lock(lock_);
322 for (auto &plane : object_pool_) {
323 uint32_t assigned_crtc = 0;
324 uint32_t requested_crtc = 0;
325 plane.second->GetAssignedCrtc(&assigned_crtc);
326 plane.second->GetRequestedCrtc(&requested_crtc);
327 if (assigned_crtc == crtc_id && requested_crtc == 0) {
328 plane.second->Unset(is_commit, req);
329 } else if (requested_crtc == crtc_id) {
330 // Plane is acquired, call reset color luts, which will reset if needed
331 plane.second->ResetColorLUTs(is_commit, req);
332 }
333 }
334 }
335
RetainPlanes(uint32_t crtc_id)336 void DRMPlaneManager::RetainPlanes(uint32_t crtc_id) {
337 for (auto &plane : object_pool_) {
338 uint32_t assigned_crtc = 0;
339 plane.second->GetAssignedCrtc(&assigned_crtc);
340 if (assigned_crtc == crtc_id) {
341 // Pretend this plane was requested by client
342 plane.second->SetRequestedCrtc(crtc_id);
343 const uint32_t plane_id = plane.first;
344 DRM_LOGD("Plane %d: Retaining on CRTC %d", plane_id, crtc_id);
345 }
346 }
347 }
348
PostValidate(uint32_t crtc_id)349 void DRMPlaneManager::PostValidate(uint32_t crtc_id) {
350 lock_guard<mutex> lock(lock_);
351 for (auto &plane : object_pool_) {
352 plane.second->PostValidate(crtc_id);
353 }
354 }
355
PostCommit(uint32_t crtc_id,bool success)356 void DRMPlaneManager::PostCommit(uint32_t crtc_id, bool success) {
357 lock_guard<mutex> lock(lock_);
358 DRM_LOGD("crtc %d", crtc_id);
359 for (auto &plane : object_pool_) {
360 plane.second->PostCommit(crtc_id, success);
361 }
362 }
363
SetScalerLUT(const DRMScalerLUTInfo & lut_info)364 void DRMPlaneManager::SetScalerLUT(const DRMScalerLUTInfo &lut_info) {
365 if (lut_info.dir_lut_size) {
366 drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.dir_lut),
367 lut_info.dir_lut_size, &dir_lut_blob_id_);
368 }
369 if (lut_info.cir_lut_size) {
370 drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.cir_lut),
371 lut_info.cir_lut_size, &cir_lut_blob_id_);
372 }
373 if (lut_info.sep_lut_size) {
374 drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.sep_lut),
375 lut_info.sep_lut_size, &sep_lut_blob_id_);
376 }
377 }
378
UnsetScalerLUT()379 void DRMPlaneManager::UnsetScalerLUT() {
380 if (dir_lut_blob_id_) {
381 drmModeDestroyPropertyBlob(fd_, dir_lut_blob_id_);
382 dir_lut_blob_id_ = 0;
383 }
384 if (cir_lut_blob_id_) {
385 drmModeDestroyPropertyBlob(fd_, cir_lut_blob_id_);
386 cir_lut_blob_id_ = 0;
387 }
388 if (sep_lut_blob_id_) {
389 drmModeDestroyPropertyBlob(fd_, sep_lut_blob_id_);
390 sep_lut_blob_id_ = 0;
391 }
392 }
393
394 // ==============================================================================================//
395
396 #undef __CLASS__
397 #define __CLASS__ "DRMPlane"
398
DRMPlane(int fd,uint32_t priority)399 DRMPlane::DRMPlane(int fd, uint32_t priority)
400 : DRMObject(prop_mgr_), fd_(fd), priority_(priority) {}
401
~DRMPlane()402 DRMPlane::~DRMPlane() {
403 drmModeFreePlane(drm_plane_);
404 }
405
GetTypeInfo(const PropertyMap & prop_map)406 void DRMPlane::GetTypeInfo(const PropertyMap &prop_map) {
407 uint64_t blob_id;
408 drmModePropertyRes *prop;
409 DRMPlaneTypeInfo *info = &plane_type_info_;
410 // Ideally we should check if this property type is a blob and then proceed.
411 std::tie(blob_id, prop) = prop_map.at(DRMProperty::CAPABILITIES);
412 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
413 if (!blob) {
414 return;
415 }
416
417 char *fmt_str = new char[blob->length + 1];
418 memcpy (fmt_str, blob->data, blob->length);
419 fmt_str[blob->length] = '\0';
420
421 info->max_linewidth = 2560;
422 info->max_scaler_linewidth = MAX_SCALER_LINEWIDTH;
423 info->max_upscale = 1;
424 info->max_downscale = 1;
425 info->max_horizontal_deci = 0;
426 info->max_vertical_deci = 0;
427 info->master_plane_id = 0;
428 if (info->type == DRMPlaneType::CURSOR) {
429 info->max_linewidth = 128;
430 }
431 // TODO(user): change default to V2 once we start getting V3 via capabilities blob
432 info->qseed3_version = QSEEDStepVersion::V3;
433 info->has_excl_rect = has_excl_rect_;
434
435 // We may have multiple lines with each one dedicated for something specific
436 // like formats etc
437 stringstream stream(fmt_str);
438 DRM_LOGI("stream str %s len %zu blob str %s len %d", stream.str().c_str(), stream.str().length(),
439 blob->data, blob->length);
440
441 string line = {};
442 string pixel_formats = "pixel_formats=";
443 string max_linewidth = "max_linewidth=";
444 string max_upscale = "max_upscale=";
445 string max_downscale = "max_downscale=";
446 string max_horizontal_deci = "max_horizontal_deci=";
447 string max_vertical_deci = "max_vertical_deci=";
448 string master_plane_id = "primary_smart_plane_id=";
449 string max_pipe_bw = "max_per_pipe_bw=";
450 string max_pipe_bw_high = "max_per_pipe_bw_high=";
451 string scaler_version = "scaler_step_ver=";
452 string block_sec_ui = "block_sec_ui=";
453 string true_inline_rot_rev = "true_inline_rot_rev=";
454 string inline_rot_pixel_formats = "inline_rot_pixel_formats=";
455 string true_inline_dwnscale_rt_numerator = "true_inline_dwnscale_rt_numerator=";
456 string true_inline_dwnscale_rt_denominator = "true_inline_dwnscale_rt_denominator=";
457 string true_inline_max_height = "true_inline_max_height=";
458
459 while (std::getline(stream, line)) {
460 if (line.find(inline_rot_pixel_formats) != string::npos) {
461 vector<pair<uint32_t, uint64_t>> inrot_formats_supported;
462 ParseFormats(line.erase(0, inline_rot_pixel_formats.length()), &inrot_formats_supported);
463 info->inrot_fmts_supported = std::move(inrot_formats_supported);
464 } else if (line.find(pixel_formats) != string::npos) {
465 vector<pair<uint32_t, uint64_t>> formats_supported;
466 ParseFormats(line.erase(0, pixel_formats.length()), &formats_supported);
467 info->formats_supported = std::move(formats_supported);
468 } else if (line.find(max_linewidth) != string::npos) {
469 info->max_linewidth = std::stoi(line.erase(0, max_linewidth.length()));
470 } else if (line.find(max_upscale) != string::npos) {
471 info->max_upscale = std::stoi(line.erase(0, max_upscale.length()));
472 } else if (line.find(max_downscale) != string::npos) {
473 info->max_downscale = std::stoi(line.erase(0, max_downscale.length()));
474 } else if (line.find(max_horizontal_deci) != string::npos) {
475 info->max_horizontal_deci = std::stoi(line.erase(0, max_horizontal_deci.length()));
476 } else if (line.find(max_vertical_deci) != string::npos) {
477 info->max_vertical_deci = std::stoi(line.erase(0, max_vertical_deci.length()));
478 } else if (line.find(master_plane_id) != string::npos) {
479 info->master_plane_id = std::stoi(line.erase(0, master_plane_id.length()));
480 DRM_LOGI("info->master_plane_id: detected master_plane=%d", info->master_plane_id);
481 } else if (line.find(max_pipe_bw) != string::npos) {
482 info->max_pipe_bandwidth = std::stoull(line.erase(0, max_pipe_bw.length()));
483 } else if (line.find(max_pipe_bw_high) != string::npos) {
484 info->max_pipe_bandwidth_high = std::stoull(line.erase(0, max_pipe_bw_high.length()));
485 } else if (line.find(scaler_version) != string::npos) {
486 info->qseed3_version =
487 PopulateQseedStepVersion(std::stoi(line.erase(0, scaler_version.length())));
488 } else if (line.find(block_sec_ui) != string::npos) {
489 info->block_sec_ui = !!(std::stoi(line.erase(0, block_sec_ui.length())));
490 } else if (line.find(true_inline_rot_rev) != string::npos) {
491 info->inrot_version =
492 PopulateInlineRotationVersion(std::stoi(line.erase(0, true_inline_rot_rev.length())));
493 } else if (line.find(true_inline_dwnscale_rt_numerator) != string::npos) {
494 info->true_inline_dwnscale_rt_num = std::stof(line.erase(0,
495 true_inline_dwnscale_rt_numerator.length()));
496 } else if (line.find(true_inline_dwnscale_rt_denominator) != string::npos) {
497 info->true_inline_dwnscale_rt_denom = std::stof(line.erase(0,
498 true_inline_dwnscale_rt_denominator.length()));
499 } else if (line.find(true_inline_max_height) != string::npos) {
500 info->max_rotation_linewidth = std::stoi(line.erase(0, true_inline_max_height.length()));
501 }
502 }
503
504 // TODO(user): Get max_scaler_linewidth and non_scaler_linewidth from driver
505 // max_linewidth can be smaller than 2560 for few target, so make sure to assign the minimum of both
506 info->max_scaler_linewidth = (info->qseed3_version < QSEEDStepVersion::V4) ? info->max_linewidth :
507 std::min((uint32_t)MAX_SCALER_LINEWIDTH, info->max_linewidth);
508
509 drmModeFreePropertyBlob(blob);
510 }
511
ParseProperties()512 void DRMPlane::ParseProperties() {
513 // Map of property name to current value and property info pointer
514 PropertyMap prop_map;
515 bool csc = false;
516 bool scaler = false;
517 bool cursor = false;
518 drmModeObjectProperties *props =
519 drmModeObjectGetProperties(fd_, drm_plane_->plane_id, DRM_MODE_OBJECT_PLANE);
520 if (!props || !props->props || !props->prop_values) {
521 drmModeFreeObjectProperties(props);
522 return;
523 }
524
525 for (uint32_t j = 0; j < props->count_props; j++) {
526 drmModePropertyRes *info = drmModeGetProperty(fd_, props->props[j]);
527 if (!info) {
528 continue;
529 }
530
531 string property_name(info->name);
532 DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
533 if (prop_enum == DRMProperty::INVALID) {
534 DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
535 drmModeFreeProperty(info);
536 continue;
537 }
538
539 if (prop_enum == DRMProperty::EXCL_RECT) {
540 has_excl_rect_ = true;
541 }
542 if (prop_enum == DRMProperty::ROTATION) {
543 PopulateReflect(info);
544 } else if (prop_enum == DRMProperty::FB_TRANSLATION_MODE) {
545 PopulateSecureModes(info);
546 } else if (prop_enum == DRMProperty::MULTIRECT_MODE) {
547 PopulateMultiRectModes(info);
548 plane_type_info_.multirect_prop_present = true;
549 }
550
551 prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
552 prop_map[prop_enum] = std::make_tuple(props->prop_values[j], info);
553 csc = prop_enum == DRMProperty::CSC_V1 ? true : csc;
554 scaler = (prop_enum == DRMProperty::SCALER_V1 || prop_enum == DRMProperty::SCALER_V2) \
555 ? true : scaler;
556 cursor = (prop_enum == DRMProperty::TYPE && props->prop_values[j] == DRM_PLANE_TYPE_CURSOR) \
557 ? true : cursor;
558
559 // Tone mapping properties.
560 if (prop_enum == DRMProperty::INVERSE_PMA) {
561 plane_type_info_.inverse_pma = true;
562 }
563
564 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::CSC_DMA_V1 &&
565 (uint32_t)prop_enum <= (uint32_t)DRMProperty::CSC_DMA_V1) {
566 plane_type_info_.dgm_csc_version =
567 ((uint32_t)prop_enum - (uint32_t)DRMProperty::CSC_DMA_V1 + 1);
568 }
569
570 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 &&
571 (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5) {
572 plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::DMA_1D_IGC] =
573 ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_IGC_V5 + 5);
574 }
575 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 &&
576 (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5) {
577 plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::DMA_1D_GC] =
578 ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_DGM_1D_LUT_GC_V5 + 5);
579 }
580 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 &&
581 (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V6) {
582 plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::VIG_1D_IGC] =
583 ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_VIG_1D_LUT_IGC_V5 + 5);
584 }
585 if ((uint32_t)prop_enum >= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 &&
586 (uint32_t)prop_enum <= (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V6) {
587 plane_type_info_.tonemap_lut_version_map[DRMTonemapLutType::VIG_3D_GAMUT] =
588 ((uint32_t)prop_enum - (uint32_t)DRMProperty::SDE_VIG_3D_LUT_GAMUT_V5 + 5);
589 }
590 }
591
592 DRMPlaneType type = DRMPlaneType::DMA;
593 if (csc && scaler) {
594 type = DRMPlaneType::VIG;
595 } else if (cursor) {
596 type = DRMPlaneType::CURSOR;
597 }
598
599 plane_type_info_.type = type;
600 GetTypeInfo(prop_map);
601
602 for (auto &prop : prop_map) {
603 drmModeFreeProperty(std::get<1>(prop.second));
604 }
605
606 drmModeFreeObjectProperties(props);
607 }
608
InitAndParse(drmModePlane * plane)609 void DRMPlane::InitAndParse(drmModePlane *plane) {
610 drm_plane_ = plane;
611 ParseProperties();
612
613 unique_ptr<DRMPPManager> pp_mgr(new DRMPPManager(fd_));
614 pp_mgr_ = std::move(pp_mgr);
615 pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_PLANE);
616 }
617
ConfigureScalerLUT(uint32_t dir_lut_blob_id,uint32_t cir_lut_blob_id,uint32_t sep_lut_blob_id)618 bool DRMPlane::ConfigureScalerLUT(uint32_t dir_lut_blob_id,
619 uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id) {
620 if (plane_type_info_.type != DRMPlaneType::VIG || is_lut_configured_) {
621 return false;
622 }
623
624 if (dir_lut_blob_id) {
625 AddProperty(DRMProperty::LUT_ED, dir_lut_blob_id, true);
626 }
627 if (cir_lut_blob_id) {
628 AddProperty(DRMProperty::LUT_CIR, cir_lut_blob_id, true);
629 }
630 if (sep_lut_blob_id) {
631 AddProperty(DRMProperty::LUT_SEP, sep_lut_blob_id, true);
632 }
633
634 return true;
635 }
636
SetExclRect(DRMRect rect)637 void DRMPlane::SetExclRect(DRMRect rect) {
638 drm_clip_rect clip_rect;
639 SetRect(rect, &clip_rect);
640 excl_rect_copy_ = clip_rect;
641 AddProperty(DRMProperty::EXCL_RECT,
642 reinterpret_cast<uint64_t>(&excl_rect_copy_), true);
643 DRM_LOGD("Plane %d: Setting exclusion rect [x,y,w,h][%d,%d,%d,%d]", drm_plane_->plane_id,
644 clip_rect.x1, clip_rect.y1, (clip_rect.x2 - clip_rect.x1),
645 (clip_rect.y2 - clip_rect.y1));
646 }
647
SetCscConfig(DRMCscType csc_type)648 bool DRMPlane::SetCscConfig(DRMCscType csc_type) {
649 if (plane_type_info_.type != DRMPlaneType::VIG) {
650 return false;
651 }
652
653 if (csc_type > kCscTypeMax) {
654 return false;
655 }
656
657 if (!prop_mgr_.IsPropertyAvailable(DRMProperty::CSC_V1)) {
658 return false;
659 }
660
661 if (csc_type == kCscTypeMax) {
662 AddProperty(DRMProperty::CSC_V1, 0);
663 } else {
664 csc_config_copy_ = csc_10bit_convert[csc_type];
665 AddProperty(DRMProperty::CSC_V1,
666 reinterpret_cast<uint64_t>(&csc_config_copy_), true);
667 }
668
669 return true;
670 }
671
SetScalerConfig(uint64_t handle)672 bool DRMPlane::SetScalerConfig(uint64_t handle) {
673 if (plane_type_info_.type != DRMPlaneType::VIG) {
674 return false;
675 }
676
677 if (prop_mgr_.IsPropertyAvailable(DRMProperty::SCALER_V2)) {
678 sde_drm_scaler_v2 *scaler_v2_config = reinterpret_cast<sde_drm_scaler_v2 *>(handle);
679 uint64_t scaler_data = 0;
680 // The address needs to be valid even after async commit, since we are sending address to
681 // driver directly, instead of blob. So we need to copy over contents that client sent. Client
682 // may have sent an address of object on stack which will be released after this call.
683 scaler_v2_config_copy_ = *scaler_v2_config;
684 if (scaler_v2_config_copy_.enable) {
685 scaler_data = reinterpret_cast<uint64_t>(&scaler_v2_config_copy_);
686 }
687 AddProperty(DRMProperty::SCALER_V2, scaler_data, scaler_data != 0);
688 return true;
689 }
690
691 return false;
692 }
693
SetDecimation(DRMProperty prop,uint32_t prop_value)694 void DRMPlane::SetDecimation(DRMProperty prop, uint32_t prop_value) {
695 if (plane_type_info_.type == DRMPlaneType::DMA || plane_type_info_.master_plane_id) {
696 // if value is 0, client is just trying to clear previous decimation, so bail out silently
697 if (prop_value > 0) {
698 DRM_LOGE("Plane %d: Setting decimation %d is not supported.", drm_plane_->plane_id,
699 prop_value);
700 }
701 return;
702 }
703
704 // TODO(user): Currently a ViG plane in smart DMA mode could receive a non-zero decimation value
705 // but there is no good way to catch. In any case fix will be in client
706 AddProperty(prop, prop_value);
707 DRM_LOGD("Plane %d: Setting decimation %d", drm_plane_->plane_id, prop_value);
708 }
709
PostValidate(uint32_t crtc_id)710 void DRMPlane::PostValidate(uint32_t crtc_id) {
711 DiscardDirtyProperties();
712 if (requested_crtc_id_ == crtc_id) {
713 SetRequestedCrtc(0);
714 }
715 }
716
PostCommit(uint32_t crtc_id,bool success)717 void DRMPlane::PostCommit(uint32_t crtc_id, bool success) {
718 DRM_LOGD("crtc %d", crtc_id);
719 if (!success) {
720 // To reset
721 PostValidate(crtc_id);
722 return;
723 }
724
725 uint32_t assigned_crtc = 0;
726 uint32_t requested_crtc = 0;
727
728 CommitProperties();
729 GetAssignedCrtc(&assigned_crtc);
730 GetRequestedCrtc(&requested_crtc);
731
732 // In future, it is possible that plane is already attached in case of continuous splash. This
733 // will cause the first commit to only unstage pipes. We want to mark luts as configured only
734 // when they really are, which typically happens if a crtc is requested for a plane
735 if (requested_crtc == crtc_id && !is_lut_configured_) {
736 is_lut_configured_ = true;
737 }
738
739 if (requested_crtc && assigned_crtc && requested_crtc != assigned_crtc) {
740 // We should never be here
741 DRM_LOGE("Found plane %d switching from crtc %d to crtc %d", drm_plane_->plane_id,
742 assigned_crtc, requested_crtc);
743 }
744
745 // If we have set a pipe OR unset a pipe during commit, update states
746 if (requested_crtc == crtc_id || assigned_crtc == crtc_id) {
747 SetAssignedCrtc(requested_crtc);
748 SetRequestedCrtc(0);
749 }
750 }
751
Perform(DRMOps code,drmModeAtomicReq * req,va_list args)752 void DRMPlane::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) {
753 uint32_t obj_id = drm_plane_->plane_id;
754
755 switch (code) {
756 // TODO(user): Check if these exist in map before attempting to access
757 case DRMOps::PLANE_SET_SRC_RECT: {
758 DRMRect rect = va_arg(args, DRMRect);
759 // source co-ordinates accepted by DRM are 16.16 fixed point
760 AddProperty(DRMProperty::SRC_X, rect.left << 16);
761 AddProperty(DRMProperty::SRC_Y, rect.top << 16);
762 AddProperty(DRMProperty::SRC_W, (rect.right - rect.left) << 16);
763 AddProperty(DRMProperty::SRC_H, (rect.bottom - rect.top) << 16);
764 DRM_LOGV("Plane %d: Setting crop [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
765 rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
766 } break;
767
768 case DRMOps::PLANE_SET_DST_RECT: {
769 DRMRect rect = va_arg(args, DRMRect);
770 AddProperty(DRMProperty::CRTC_X, rect.left);
771 AddProperty(DRMProperty::CRTC_Y, rect.top);
772 AddProperty(DRMProperty::CRTC_W, (rect.right - rect.left));
773 AddProperty(DRMProperty::CRTC_H, (rect.bottom - rect.top));
774 DRM_LOGV("Plane %d: Setting dst [x,y,w,h][%d,%d,%d,%d]", obj_id, rect.left,
775 rect.top, (rect.right - rect.left), (rect.bottom - rect.top));
776 } break;
777 case DRMOps::PLANE_SET_EXCL_RECT: {
778 DRMRect excl_rect = va_arg(args, DRMRect);
779 SetExclRect(excl_rect);
780 } break;
781
782 case DRMOps::PLANE_SET_ZORDER: {
783 uint32_t zpos = va_arg(args, uint32_t);
784 AddProperty(DRMProperty::ZPOS, zpos);
785 DRM_LOGD("Plane %d: Setting z %d", obj_id, zpos);
786 } break;
787
788 case DRMOps::PLANE_SET_ROTATION: {
789 uint32_t rot_bit_mask = va_arg(args, uint32_t);
790 uint32_t drm_rot_bit_mask = 0;
791 if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::FLIP_H)) {
792 drm_rot_bit_mask |= 1 << REFLECT_X;
793 }
794 if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::FLIP_V)) {
795 drm_rot_bit_mask |= 1 << REFLECT_Y;
796 }
797 if (rot_bit_mask & static_cast<uint32_t>(DRMRotation::ROT_90)) {
798 drm_rot_bit_mask |= 1 << ROTATE_90;
799 } else {
800 drm_rot_bit_mask |= 1 << ROTATE_0;
801 }
802 AddProperty(DRMProperty::ROTATION, drm_rot_bit_mask);
803 DRM_LOGV("Plane %d: Setting rotation mask %x", obj_id, drm_rot_bit_mask);
804 } break;
805
806 case DRMOps::PLANE_SET_ALPHA: {
807 uint32_t alpha = va_arg(args, uint32_t);
808 AddProperty(DRMProperty::ALPHA, alpha);
809 DRM_LOGV("Plane %d: Setting alpha %d", obj_id, alpha);
810 } break;
811
812 case DRMOps::PLANE_SET_BLEND_TYPE: {
813 uint32_t blending = va_arg(args, uint32_t);
814 AddProperty(DRMProperty::BLEND_OP, blending);
815 DRM_LOGV("Plane %d: Setting blending %d", obj_id, blending);
816 } break;
817
818 case DRMOps::PLANE_SET_H_DECIMATION: {
819 uint32_t deci = va_arg(args, uint32_t);
820 SetDecimation(DRMProperty::H_DECIMATE, deci);
821 } break;
822
823 case DRMOps::PLANE_SET_V_DECIMATION: {
824 uint32_t deci = va_arg(args, uint32_t);
825 SetDecimation(DRMProperty::V_DECIMATE, deci);
826 } break;
827
828 case DRMOps::PLANE_SET_SRC_CONFIG: {
829 bool src_config = va_arg(args, uint32_t);
830 AddProperty(DRMProperty::SRC_CONFIG, src_config);
831 DRM_LOGV("Plane %d: Setting src_config flags-%x", obj_id, src_config);
832 } break;
833
834 case DRMOps::PLANE_SET_CRTC: {
835 uint32_t crtc_id = va_arg(args, uint32_t);
836 AddProperty(DRMProperty::CRTC_ID, crtc_id);
837 SetRequestedCrtc(crtc_id);
838 DRM_LOGV("Plane %d: Setting crtc %d", obj_id, crtc_id);
839 } break;
840
841 case DRMOps::PLANE_SET_FB_ID: {
842 uint32_t fb_id = va_arg(args, uint32_t);
843 AddProperty(DRMProperty::FB_ID, fb_id);
844 DRM_LOGV("Plane %d: Setting fb_id %d", obj_id, fb_id);
845 } break;
846
847 case DRMOps::PLANE_SET_ROT_FB_ID: {
848 uint32_t fb_id = va_arg(args, uint32_t);
849 AddProperty(DRMProperty::ROT_FB_ID, fb_id, true);
850 DRM_LOGV("Plane %d: Setting rot_fb_id %d", obj_id, fb_id);
851 } break;
852
853 case DRMOps::PLANE_SET_INPUT_FENCE: {
854 int fence = va_arg(args, int);
855 AddProperty(DRMProperty::INPUT_FENCE, fence, true);
856 DRM_LOGV("Plane %d: Setting input fence %d", obj_id, fence);
857 } break;
858
859 case DRMOps::PLANE_SET_SCALER_CONFIG: {
860 uint64_t handle = va_arg(args, uint64_t);
861 if (SetScalerConfig(handle)) {
862 DRM_LOGV("Plane %d: Setting scaler config", obj_id);
863 }
864 } break;
865
866 case DRMOps::PLANE_SET_FB_SECURE_MODE: {
867 int secure_mode = va_arg(args, int);
868 uint32_t fb_secure_mode = NON_SECURE;
869 switch (secure_mode) {
870 case (int)DRMSecureMode::NON_SECURE:
871 fb_secure_mode = NON_SECURE;
872 break;
873 case (int)DRMSecureMode::SECURE:
874 fb_secure_mode = SECURE;
875 break;
876 case (int)DRMSecureMode::NON_SECURE_DIR_TRANSLATION:
877 fb_secure_mode = NON_SECURE_DIR_TRANSLATION;
878 break;
879 case (int)DRMSecureMode::SECURE_DIR_TRANSLATION:
880 fb_secure_mode = SECURE_DIR_TRANSLATION;
881 break;
882 default:
883 DRM_LOGE("Invalid secure mode %d to set on plane %d", secure_mode, obj_id);
884 break;
885 }
886
887 AddProperty(DRMProperty::FB_TRANSLATION_MODE, fb_secure_mode);
888 DRM_LOGD("Plane %d: Setting FB secure mode %d", obj_id, fb_secure_mode);
889 } break;
890
891 case DRMOps::PLANE_SET_CSC_CONFIG: {
892 uint32_t* csc_type = va_arg(args, uint32_t*);
893 if (csc_type) {
894 SetCscConfig((DRMCscType)*csc_type);
895 }
896 } break;
897
898 case DRMOps::PLANE_SET_MULTIRECT_MODE: {
899 DRMMultiRectMode drm_multirect_mode = (DRMMultiRectMode)va_arg(args, uint32_t);
900 SetMultiRectMode(drm_multirect_mode);
901 } break;
902
903 case DRMOps::PLANE_SET_INVERSE_PMA: {
904 uint32_t pma = va_arg(args, uint32_t);
905 AddProperty(DRMProperty::INVERSE_PMA, pma);
906 DRM_LOGD("Plane %d: %s inverse pma", obj_id, pma ? "Setting" : "Resetting");
907 } break;
908
909 case DRMOps::PLANE_SET_DGM_CSC_CONFIG: {
910 uint64_t handle = va_arg(args, uint64_t);
911 if (SetDgmCscConfig(handle)) {
912 DRM_LOGD("Plane %d: Setting Csc Lut config", obj_id);
913 }
914 } break;
915
916 case DRMOps::PLANE_SET_POST_PROC: {
917 DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*);
918 if (data) {
919 DRM_LOGD("Plane %d: Set post proc feature id - %d", obj_id, data->id);
920 pp_mgr_->SetPPFeature(req, obj_id, *data);
921 UpdatePPLutFeatureInuse(data);
922 }
923 } break;
924
925 case DRMOps::PLANE_SET_SSPP_LAYOUT: {
926 if (!prop_mgr_.IsPropertyAvailable(DRMProperty::SDE_SSPP_LAYOUT)) {
927 DRM_LOGD("SSPP_LAYOUT property isn't exposed");
928 break;
929 }
930 DRMSSPPLayoutIndex layout_index = (DRMSSPPLayoutIndex) va_arg(args, uint32_t);
931 AddProperty(DRMProperty::SDE_SSPP_LAYOUT, (uint32_t)layout_index);
932 DRM_LOGD("Plane %d: Setting SSPP Layout to %d", obj_id, layout_index);
933 } break;
934
935 default:
936 DRM_LOGE("Invalid opcode %d for DRM Plane %d", code, obj_id);
937 }
938 }
939
UpdatePPLutFeatureInuse(DRMPPFeatureInfo * data)940 void DRMPlane::UpdatePPLutFeatureInuse(DRMPPFeatureInfo *data) {
941 DRMTonemapLutType lut_type = {};
942 bool ret = GetDRMonemapLutTypeFromPPFeatureID(data->id, &lut_type);
943 if (ret == false) {
944 DRM_LOGE("Failed to get the lut type from PPFeatureID = %d", data->id);
945 return;
946 }
947
948 const auto state = data->payload ? kActive : kInactive;
949
950 switch (lut_type) {
951 case DRMTonemapLutType::DMA_1D_GC:
952 dgm_1d_lut_gc_state_ = state;
953 break;
954 case DRMTonemapLutType::DMA_1D_IGC:
955 dgm_1d_lut_igc_state_ = state;
956 break;
957 case DRMTonemapLutType::VIG_1D_IGC:
958 vig_1d_lut_igc_state_ = state;
959 break;
960 case DRMTonemapLutType::VIG_3D_GAMUT:
961 vig_3d_lut_gamut_state_ = state;
962 break;
963 default:
964 DRM_LOGE("Invalid lut_type = %d state = %d", lut_type, state);
965 }
966 return;
967 }
968
PerformWrapper(DRMOps code,drmModeAtomicReq * req,...)969 void DRMPlane::PerformWrapper(DRMOps code, drmModeAtomicReq *req, ...) {
970 va_list args;
971 va_start(args, req);
972 Perform(code, req, args);
973 va_end(args);
974 }
975
Dump()976 void DRMPlane::Dump() {
977 DRM_LOGE(
978 "id: %d\tcrtc id: %d\tfb id: %d\tCRTC_xy: %dx%d\txy: %dx%d\tgamma "
979 "size: %d\tpossible crtc: 0x%x\n",
980 drm_plane_->plane_id, drm_plane_->crtc_id, drm_plane_->fb_id, drm_plane_->crtc_x,
981 drm_plane_->crtc_y, drm_plane_->x, drm_plane_->y, drm_plane_->gamma_size,
982 drm_plane_->possible_crtcs);
983 DRM_LOGE("Format Suported: \n");
984 for (uint32_t i = 0; i < (uint32_t)drm_plane_->count_formats; i++)
985 DRM_LOGE(" %4.4s", (char *)&drm_plane_->formats[i]);
986 }
987
SetMultiRectMode(DRMMultiRectMode drm_multirect_mode)988 void DRMPlane::SetMultiRectMode(DRMMultiRectMode drm_multirect_mode) {
989 if (!plane_type_info_.multirect_prop_present) {
990 return;
991 }
992 uint32_t obj_id = drm_plane_->plane_id;
993 uint32_t multirect_mode = MULTIRECT_NONE;
994 switch (drm_multirect_mode) {
995 case DRMMultiRectMode::NONE:
996 multirect_mode = MULTIRECT_NONE;
997 break;
998 case DRMMultiRectMode::PARALLEL:
999 multirect_mode = MULTIRECT_PARALLEL;
1000 break;
1001 case DRMMultiRectMode::SERIAL:
1002 multirect_mode = MULTIRECT_SERIAL;
1003 break;
1004 default:
1005 DRM_LOGE("Invalid multirect mode %d to set on plane %d", drm_multirect_mode, GetObjectId());
1006 break;
1007 }
1008 AddProperty(DRMProperty::MULTIRECT_MODE, multirect_mode);
1009 DRM_LOGD("Plane %d: Setting multirect_mode %d", obj_id, multirect_mode);
1010 }
1011
Unset(bool is_commit,drmModeAtomicReq * req)1012 void DRMPlane::Unset(bool is_commit, drmModeAtomicReq *req) {
1013 DRM_LOGD("Plane %d: Unsetting from crtc %d", drm_plane_->plane_id, assigned_crtc_id_);
1014 PerformWrapper(DRMOps::PLANE_SET_FB_ID, req, 0);
1015 PerformWrapper(DRMOps::PLANE_SET_CRTC, req, 0);
1016 DRMRect rect = {0, 0, 0, 0};
1017 PerformWrapper(DRMOps::PLANE_SET_SRC_RECT, req, rect);
1018 PerformWrapper(DRMOps::PLANE_SET_DST_RECT, req, rect);
1019 PerformWrapper(DRMOps::PLANE_SET_EXCL_RECT, req, rect);
1020 if (plane_type_info_.inverse_pma) {
1021 PerformWrapper(DRMOps::PLANE_SET_INVERSE_PMA, req, 0);
1022 }
1023
1024 // Reset the sspp tonemap properties if they were set and update the in-use only if
1025 // its a Commit as Unset is called in Validate as well.
1026 if (dgm_csc_in_use_) {
1027 uint64_t csc_v1 = 0;
1028 AddProperty(DRMProperty::CSC_DMA_V1, csc_v1, true);
1029 DRM_LOGV("Plane %d Clearing DGM CSC", drm_plane_->plane_id);
1030 dgm_csc_in_use_ = !is_commit;
1031 }
1032 ResetColorLUTs(is_commit, req);
1033 }
1034
SetDgmCscConfig(uint64_t handle)1035 bool DRMPlane::SetDgmCscConfig(uint64_t handle) {
1036 if (plane_type_info_.type == DRMPlaneType::DMA &&
1037 prop_mgr_.IsPropertyAvailable(DRMProperty::CSC_DMA_V1)) {
1038 sde_drm_csc_v1 *csc_v1 = reinterpret_cast<sde_drm_csc_v1 *>(handle);
1039 uint64_t csc_v1_data = 0;
1040 sde_drm_csc_v1 csc_v1_tmp = {};
1041 csc_config_copy_ = *csc_v1;
1042 if (std::memcmp(&csc_config_copy_, &csc_v1_tmp, sizeof(sde_drm_csc_v1)) != 0) {
1043 csc_v1_data = reinterpret_cast<uint64_t>(&csc_config_copy_);
1044 }
1045 AddProperty(DRMProperty::CSC_DMA_V1, csc_v1_data, true);
1046 dgm_csc_in_use_ = (csc_v1_data != 0);
1047 DRM_LOGV("Plane %d in_use = %d", drm_plane_->plane_id, dgm_csc_in_use_);
1048
1049 return true;
1050 }
1051
1052 return false;
1053 }
1054
ResetColorLUTs(bool is_commit,drmModeAtomicReq * req)1055 void DRMPlane::ResetColorLUTs(bool is_commit, drmModeAtomicReq *req) {
1056 // Reset the color luts if they were set and update the state only if its a Commit as Unset
1057 // is called in Validate as well.
1058 for (int i = 0; i <= static_cast<int>(DRMTonemapLutType::VIG_3D_GAMUT); i++) {
1059 auto itr = plane_type_info_.tonemap_lut_version_map.find(static_cast<DRMTonemapLutType>(i));
1060 if (itr != plane_type_info_.tonemap_lut_version_map.end()) {
1061 ResetColorLUTState(static_cast<DRMTonemapLutType>(i), is_commit, req);
1062 }
1063 }
1064 }
1065
ResetColorLUTState(DRMTonemapLutType lut_type,bool is_commit,drmModeAtomicReq * req)1066 void DRMPlane::ResetColorLUTState(DRMTonemapLutType lut_type, bool is_commit,
1067 drmModeAtomicReq *req) {
1068 DRMPlaneLutState *lut_state = nullptr;
1069 DRMPPFeatureID feature_id = {};
1070 switch (lut_type) {
1071 case DRMTonemapLutType::DMA_1D_GC:
1072 lut_state = &dgm_1d_lut_gc_state_;
1073 feature_id = kFeatureDgmGc;
1074 break;
1075 case DRMTonemapLutType::DMA_1D_IGC:
1076 lut_state = &dgm_1d_lut_igc_state_;
1077 feature_id = kFeatureDgmIgc;
1078 break;
1079 case DRMTonemapLutType::VIG_1D_IGC:
1080 lut_state = &vig_1d_lut_igc_state_;
1081 feature_id = kFeatureVigIgc;
1082 break;
1083 case DRMTonemapLutType::VIG_3D_GAMUT:
1084 lut_state = &vig_3d_lut_gamut_state_;
1085 feature_id = kFeatureVigGamut;
1086 break;
1087 default:
1088 DLOGE("Invalid lut type = %d", lut_type);
1089 return;
1090 }
1091
1092 if (*lut_state == kInactive) {
1093 DRM_LOGV("Plane %d %s Lut not used", drm_plane_->plane_id, GetColorLutString(lut_type));
1094 return;
1095 }
1096
1097 DRMPlaneLutState target_state;
1098 // If plane is getting unset, clearing of LUT will not be applied in hw.
1099 // In that case, mark LUT as dirty and make sure that these are cleared the
1100 // next time the plane gets used
1101 if (*lut_state == kActive && requested_crtc_id_ == 0) {
1102 target_state = kDirty;
1103 } else if (*lut_state == kDirty && requested_crtc_id_ != 0) {
1104 // If plane is getting activated while LUT is in dirty state, the new state
1105 // should be inactive but still need to clear exiting LUT config in hw
1106 target_state = kInactive;
1107 } else {
1108 return;
1109 }
1110
1111 if (is_commit) {
1112 DRM_LOGD("Plane %d Clearing %s Lut, moving from (%d) -> (%d)", drm_plane_->plane_id,
1113 GetColorLutString(lut_type), *lut_state, target_state);
1114
1115 *lut_state = target_state;
1116 }
1117
1118 ResetColorLUT(feature_id, req);
1119 }
1120
ResetColorLUT(DRMPPFeatureID id,drmModeAtomicReq * req)1121 void DRMPlane::ResetColorLUT(DRMPPFeatureID id, drmModeAtomicReq *req) {
1122 DRMPPFeatureInfo pp_feature_info = {};
1123 pp_feature_info.type = kPropBlob;
1124 pp_feature_info.payload = nullptr;
1125 pp_feature_info.id = id;
1126 pp_mgr_->SetPPFeature(req, drm_plane_->plane_id, pp_feature_info);
1127 }
1128
1129 } // namespace sde_drm
1130