1 /*
2 * Copyright (c) 2019-2021, 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 #include <drm/sde_drm.h>
34 #include <drm_logger.h>
35 #include <drm/drm_fourcc.h>
36 #include <string.h>
37
38 #include <algorithm>
39 #include <sstream>
40 #include <string>
41 #include <vector>
42 #include <utility>
43
44 #include "drm_utils.h"
45 #include "drm_crtc.h"
46 #include "drm_property.h"
47
48 namespace sde_drm {
49
50 using std::string;
51 using std::stringstream;
52 using std::unique_ptr;
53 using std::mutex;
54 using std::lock_guard;
55 using std::pair;
56 using std::vector;
57
58 // CRTC Security Levels
59 static uint8_t SECURE_NON_SECURE = 0;
60 static uint8_t SECURE_ONLY = 1;
61
62 // CWB Capture Modes
63 static uint8_t CAPTURE_MIXER_OUT = 0;
64 static uint8_t CAPTURE_DSPP_OUT = 1;
65
66 // Idle PC states
67 static uint8_t IDLE_PC_STATE_NONE = 0;
68 static uint8_t IDLE_PC_STATE_ENABLE = 1;
69 static uint8_t IDLE_PC_STATE_DISABLE = 2;
70
PopulateSecurityLevels(drmModePropertyRes * prop)71 static void PopulateSecurityLevels(drmModePropertyRes *prop) {
72 static bool security_levels_populated = false;
73 if (!security_levels_populated) {
74 for (auto i = 0; i < prop->count_enums; i++) {
75 string enum_name(prop->enums[i].name);
76 if (enum_name == "sec_and_non_sec") {
77 SECURE_NON_SECURE = prop->enums[i].value;
78 } else if (enum_name == "sec_only") {
79 SECURE_ONLY = prop->enums[i].value;
80 }
81 }
82 security_levels_populated = true;
83 }
84 }
85
PopulateCWbCaptureModes(drmModePropertyRes * prop)86 static void PopulateCWbCaptureModes(drmModePropertyRes *prop) {
87 static bool capture_modes_populated = false;
88 if (!capture_modes_populated) {
89 for (auto i = 0; i < prop->count_enums; i++) {
90 string enum_name(prop->enums[i].name);
91 if (enum_name == "capture_mixer_out") {
92 CAPTURE_MIXER_OUT = prop->enums[i].value;
93 } else if (enum_name == "capture_pp_out") {
94 CAPTURE_DSPP_OUT = prop->enums[i].value;
95 }
96 }
97 capture_modes_populated = true;
98 }
99 }
100
PopulateIdlePCStates(drmModePropertyRes * prop)101 static void PopulateIdlePCStates(drmModePropertyRes *prop) {
102 static bool idle_pc_state_populated = false;
103 if (!idle_pc_state_populated) {
104 for (auto i = 0; i < prop->count_enums; i++) {
105 string enum_name(prop->enums[i].name);
106 if (enum_name == "idle_pc_none") {
107 IDLE_PC_STATE_NONE = prop->enums[i].value;
108 } else if (enum_name == "idle_pc_enable") {
109 IDLE_PC_STATE_ENABLE = prop->enums[i].value;
110 } else if (enum_name == "idle_pc_disable") {
111 IDLE_PC_STATE_DISABLE = prop->enums[i].value;
112 }
113 }
114 idle_pc_state_populated = true;
115 }
116 }
117
118 #define __CLASS__ "DRMCrtcManager"
119
Init(drmModeRes * resource)120 void DRMCrtcManager::Init(drmModeRes *resource) {
121 for (int i = 0; i < resource->count_crtcs; i++) {
122 unique_ptr<DRMCrtc> crtc(new DRMCrtc(fd_, i));
123 drmModeCrtc *libdrm_crtc = drmModeGetCrtc(fd_, resource->crtcs[i]);
124 if (libdrm_crtc) {
125 crtc->InitAndParse(libdrm_crtc);
126 object_pool_[resource->crtcs[i]] = std::move(crtc);
127 } else {
128 DRM_LOGE("Critical error: drmModeGetCrtc() failed for crtc %d.", resource->crtcs[i]);
129 }
130 }
131 }
132
Perform(DRMOps code,uint32_t obj_id,drmModeAtomicReq * req,va_list args)133 void DRMCrtcManager::Perform(DRMOps code, uint32_t obj_id, drmModeAtomicReq *req,
134 va_list args) {
135 lock_guard<mutex> lock(lock_);
136 auto crtc = GetObject(obj_id);
137 if (crtc == nullptr) {
138 DRM_LOGE("Invalid crtc id %d", obj_id);
139 return;
140 }
141
142 if (code == DRMOps::CRTC_SET_DEST_SCALER_CONFIG) {
143 if (crtc->ConfigureScalerLUT(dir_lut_blob_id_, cir_lut_blob_id_,
144 sep_lut_blob_id_)) {
145 DRM_LOGD("CRTC %d: Configuring scaler LUTs", obj_id);
146 }
147 }
148
149 crtc->Perform(code, req, args);
150 }
151
SetScalerLUT(const DRMScalerLUTInfo & lut_info)152 void DRMCrtcManager::SetScalerLUT(const DRMScalerLUTInfo &lut_info) {
153 // qseed3lite lut is hardcoded in HW. No need to program from sw.
154 DRMCrtcInfo info;
155 object_pool_.begin()->second->GetInfo(&info);
156 if (info.qseed_version == QSEEDVersion::V3LITE) {
157 return;
158 }
159
160 if (lut_info.dir_lut_size) {
161 drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.dir_lut),
162 lut_info.dir_lut_size, &dir_lut_blob_id_);
163 }
164 if (lut_info.cir_lut_size) {
165 drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.cir_lut),
166 lut_info.cir_lut_size, &cir_lut_blob_id_);
167 }
168 if (lut_info.sep_lut_size) {
169 drmModeCreatePropertyBlob(fd_, reinterpret_cast<void *>(lut_info.sep_lut),
170 lut_info.sep_lut_size, &sep_lut_blob_id_);
171 }
172 }
173
UnsetScalerLUT()174 void DRMCrtcManager::UnsetScalerLUT() {
175 if (dir_lut_blob_id_) {
176 drmModeDestroyPropertyBlob(fd_, dir_lut_blob_id_);
177 dir_lut_blob_id_ = 0;
178 }
179 if (cir_lut_blob_id_) {
180 drmModeDestroyPropertyBlob(fd_, cir_lut_blob_id_);
181 cir_lut_blob_id_ = 0;
182 }
183 if (sep_lut_blob_id_) {
184 drmModeDestroyPropertyBlob(fd_, sep_lut_blob_id_);
185 sep_lut_blob_id_ = 0;
186 }
187 }
188
GetCrtcInfo(uint32_t crtc_id,DRMCrtcInfo * info)189 int DRMCrtcManager::GetCrtcInfo(uint32_t crtc_id, DRMCrtcInfo *info) {
190 if (crtc_id == 0) {
191 object_pool_.begin()->second->GetInfo(info);
192 } else {
193 auto crtc = GetObject(crtc_id);
194 if (crtc == nullptr) {
195 DRM_LOGE("Invalid crtc id %d", crtc_id);
196 return -ENODEV;
197 } else {
198 crtc->GetInfo(info);
199 }
200 }
201
202 return 0;
203 }
204
GetPPInfo(uint32_t crtc_id,DRMPPFeatureInfo * info)205 void DRMCrtcManager::GetPPInfo(uint32_t crtc_id, DRMPPFeatureInfo *info) {
206 auto crtc = GetObject(crtc_id);
207 if (crtc == nullptr) {
208 DRM_LOGE("Invalid crtc id %d", crtc_id);
209 return;
210 }
211
212 crtc->GetPPInfo(info);
213 }
214
Reserve(const std::set<uint32_t> & possible_crtc_indices,DRMDisplayToken * token)215 int DRMCrtcManager::Reserve(const std::set<uint32_t> &possible_crtc_indices,
216 DRMDisplayToken *token) {
217 for (auto &item : object_pool_) {
218 if (item.second->GetStatus() == DRMStatus::FREE) {
219 if (possible_crtc_indices.find(item.second->GetIndex()) != possible_crtc_indices.end()) {
220 item.second->Lock();
221 token->crtc_id = item.first;
222 token->crtc_index = item.second->GetIndex();
223 return 0;
224 }
225 }
226 }
227
228 return -ENODEV;
229 }
230
Free(DRMDisplayToken * token)231 void DRMCrtcManager::Free(DRMDisplayToken *token) {
232 lock_guard<mutex> lock(lock_);
233 object_pool_.at(token->crtc_id)->Unlock();
234 token->crtc_id = 0;
235 token->crtc_index = 0;
236 }
237
238 // ==============================================================================================//
239
240 #undef __CLASS__
241 #define __CLASS__ "DRMCrtc"
242
DRMCrtc(int fd,uint32_t crtc_index)243 DRMCrtc::DRMCrtc(int fd, uint32_t crtc_index)
244 : DRMObject(prop_mgr_), fd_(fd), crtc_index_(crtc_index) {}
245
~DRMCrtc()246 DRMCrtc::~DRMCrtc() {
247 if (drm_crtc_) {
248 drmModeFreeCrtc(drm_crtc_);
249 }
250 }
251
ParseProperties()252 void DRMCrtc::ParseProperties() {
253 drmModeObjectProperties *props =
254 drmModeObjectGetProperties(fd_, drm_crtc_->crtc_id, DRM_MODE_OBJECT_CRTC);
255 if (!props || !props->props || !props->prop_values) {
256 drmModeFreeObjectProperties(props);
257 return;
258 }
259
260 for (uint32_t j = 0; j < props->count_props; j++) {
261 drmModePropertyRes *info = drmModeGetProperty(fd_, props->props[j]);
262 if (!info) {
263 continue;
264 }
265
266 string property_name(info->name);
267 DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
268 if (prop_enum == DRMProperty::INVALID) {
269 DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
270 drmModeFreeProperty(info);
271 continue;
272 }
273
274 if (prop_enum == DRMProperty::SECURITY_LEVEL) {
275 PopulateSecurityLevels(info);
276 }
277
278 if (prop_enum == DRMProperty::CAPTURE_MODE) {
279 crtc_info_.concurrent_writeback = true;
280 PopulateCWbCaptureModes(info);
281 }
282
283 if (prop_enum == DRMProperty::IDLE_PC_STATE) {
284 PopulateIdlePCStates(info);
285 }
286
287 prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
288 if (prop_enum == DRMProperty::CAPABILITIES) {
289 ParseCapabilities(props->prop_values[j]);
290 }
291 drmModeFreeProperty(info);
292 }
293
294 drmModeFreeObjectProperties(props);
295 }
296
ParseCapabilities(uint64_t blob_id)297 void DRMCrtc::ParseCapabilities(uint64_t blob_id) {
298 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd_, blob_id);
299 if (!blob) {
300 return;
301 }
302
303 if (!blob->data) {
304 return;
305 }
306
307 char *fmt_str = new char[blob->length + 1];
308 memcpy (fmt_str, blob->data, blob->length);
309 fmt_str[blob->length] = '\0';
310 stringstream stream(fmt_str);
311 DRM_LOGI("stream str %s len %zu blob str %s len %d", stream.str().c_str(), stream.str().length(),
312 static_cast<const char *>(blob->data), blob->length);
313 string line = {};
314 string max_blendstages = "max_blendstages=";
315 string qseed_type = "qseed_type=";
316 string has_src_split = "has_src_split=";
317 string sdma_rev = "smart_dma_rev=";
318 string core_ib_ff = "core_ib_ff=";
319 string dest_scale_prefill_lines = "dest_scale_prefill_lines=";
320 string undersized_prefill_lines = "undersized_prefill_lines=";
321 string macrotile_prefill_lines = "macrotile_prefill_lines=";
322 string yuv_nv12_prefill_lines = "yuv_nv12_prefill_lines=";
323 string linear_prefill_lines = "linear_prefill_lines=";
324 string downscaling_prefill_lines = "downscaling_prefill_lines=";
325 string xtra_prefill_lines = "xtra_prefill_lines=";
326 string amortizable_threshold = "amortizable_threshold=";
327 string max_bandwidth_low = "max_bandwidth_low=";
328 string max_bandwidth_high = "max_bandwidth_high=";
329 string max_mdp_clk = "max_mdp_clk=";
330 string core_clk_ff = "core_clk_ff=";
331 string comp_ratio_rt = "comp_ratio_rt=";
332 string comp_ratio_nrt = "comp_ratio_nrt=";
333 string hw_version = "hw_version=";
334 string solidfill_stages = "dim_layer_v1_max_layers=";
335 string has_hdr = "has_hdr=";
336 string has_micro_idle = "has_uidle=";
337 string min_prefill_lines = "min_prefill_lines=";
338 string num_mnocports = "num_mnoc_ports=";
339 string mnoc_bus_width = "axi_bus_width=";
340
341 crtc_info_.max_solidfill_stages = 0; // default _
342 string dest_scaler_count = "dest_scaler_count=";
343 string max_dest_scale_up = "max_dest_scale_up=";
344 string max_dest_scaler_input_width = "max_dest_scaler_input_width=";
345 string max_dest_scaler_output_width = "max_dest_scaler_output_width=";
346 string sec_ui_blendstage = "sec_ui_blendstage=";
347 string vig = "vig=";
348 string dma = "dma=";
349 string scaling = "scale=";
350 string rotation = "inline_rot=";
351 string linewidth_constraints = "sspp_linewidth_usecases=";
352 string linewidth_values = "sspp_linewidth_values=";
353 string limit_constraint = "limit_usecase=";
354 string limit_value = "limit_value=";
355 string use_baselayer_for_stage = "use_baselayer_for_stage=";
356 string ubwc_version = "UBWC version=";
357 string rc_total_mem_size = "rc_mem_size=";
358
359 while (std::getline(stream, line)) {
360 if (line.find(max_blendstages) != string::npos) {
361 crtc_info_.max_blend_stages = std::stoi(string(line, max_blendstages.length()));
362 } else if (line.find(qseed_type) != string::npos) {
363 if (string(line, qseed_type.length()) == "qseed2") {
364 crtc_info_.qseed_version = QSEEDVersion::V2;
365 } else if (string(line, qseed_type.length()) == "qseed3") {
366 crtc_info_.qseed_version = QSEEDVersion::V3;
367 } else if (string(line, qseed_type.length()) == "qseed3lite") {
368 crtc_info_.qseed_version = QSEEDVersion::V3LITE;
369 }
370 } else if (line.find(has_src_split) != string::npos) {
371 crtc_info_.has_src_split = std::stoi(string(line, has_src_split.length()));
372 } else if (line.find(sdma_rev) != string::npos) {
373 if (string(line, sdma_rev.length()) == "smart_dma_v2p5")
374 crtc_info_.smart_dma_rev = SmartDMARevision::V2p5;
375 else if (string(line, sdma_rev.length()) == "smart_dma_v2")
376 crtc_info_.smart_dma_rev = SmartDMARevision::V2;
377 else if (string(line, sdma_rev.length()) == "smart_dma_v1")
378 crtc_info_.smart_dma_rev = SmartDMARevision::V1;
379 } else if (line.find(core_ib_ff) != string::npos) {
380 crtc_info_.ib_fudge_factor = std::stof(string(line, core_ib_ff.length()));
381 } else if (line.find(dest_scale_prefill_lines) != string::npos) {
382 crtc_info_.dest_scale_prefill_lines =
383 std::stoi(string(line, dest_scale_prefill_lines.length()));
384 } else if (line.find(undersized_prefill_lines) != string::npos) {
385 crtc_info_.undersized_prefill_lines =
386 std::stoi(string(line, undersized_prefill_lines.length()));
387 } else if (line.find(macrotile_prefill_lines) != string::npos) {
388 crtc_info_.macrotile_prefill_lines =
389 std::stoi(string(line, macrotile_prefill_lines.length()));
390 } else if (line.find(yuv_nv12_prefill_lines) != string::npos) {
391 crtc_info_.nv12_prefill_lines = std::stoi(string(line, yuv_nv12_prefill_lines.length()));
392 } else if (line.find(linear_prefill_lines) != string::npos) {
393 crtc_info_.linear_prefill_lines = std::stoi(string(line, linear_prefill_lines.length()));
394 } else if (line.find(downscaling_prefill_lines) != string::npos) {
395 crtc_info_.downscale_prefill_lines =
396 std::stoi(string(line, downscaling_prefill_lines.length()));
397 } else if (line.find(xtra_prefill_lines) != string::npos) {
398 crtc_info_.extra_prefill_lines = std::stoi(string(line, xtra_prefill_lines.length()));
399 } else if (line.find(amortizable_threshold) != string::npos) {
400 crtc_info_.amortized_threshold = std::stoi(string(line, amortizable_threshold.length()));
401 } else if (line.find(max_bandwidth_low) != string::npos) {
402 crtc_info_.max_bandwidth_low = std::stoull(string(line, max_bandwidth_low.length()));
403 } else if (line.find(max_bandwidth_high) != string::npos) {
404 crtc_info_.max_bandwidth_high = std::stoull(string(line, max_bandwidth_high.length()));
405 } else if (line.find(max_mdp_clk) != string::npos) {
406 crtc_info_.max_sde_clk = std::stoi(string(line, max_mdp_clk.length()));
407 } else if (line.find(core_clk_ff) != string::npos) {
408 crtc_info_.clk_fudge_factor = std::stof(string(line, core_clk_ff.length()));
409 } else if (line.find(comp_ratio_rt) != string::npos) {
410 ParseCompRatio(line.substr(comp_ratio_rt.length()), true);
411 } else if (line.find(comp_ratio_nrt) != string::npos) {
412 ParseCompRatio(line.substr(comp_ratio_nrt.length()), false);
413 } else if (line.find(hw_version) != string::npos) {
414 crtc_info_.hw_version = std::stoi(string(line, hw_version.length()));
415 } else if (line.find(solidfill_stages) != string::npos) {
416 crtc_info_.max_solidfill_stages = std::stoi(string(line, solidfill_stages.length()));
417 } else if (line.find(dest_scaler_count) != string::npos) {
418 crtc_info_.dest_scaler_count = std::stoi(string(line, dest_scaler_count.length()));
419 } else if (line.find(max_dest_scale_up) != string::npos) {
420 crtc_info_.max_dest_scale_up = std::stoi(string(line, max_dest_scale_up.length()));
421 } else if (line.find(max_dest_scaler_input_width) != string::npos) {
422 crtc_info_.max_dest_scaler_input_width =
423 std::stoi(string(line, max_dest_scaler_input_width.length()));
424 } else if (line.find(max_dest_scaler_output_width) != string::npos) {
425 crtc_info_.max_dest_scaler_output_width =
426 std::stoi(string(line, max_dest_scaler_output_width.length()));
427 } else if (line.find(has_hdr) != string::npos) {
428 crtc_info_.has_hdr = std::stoi(string(line, has_hdr.length()));
429 } else if (line.find(min_prefill_lines) != string::npos) {
430 crtc_info_.min_prefill_lines = std::stoi(string(line, min_prefill_lines.length()));
431 } else if (line.find(sec_ui_blendstage) != string::npos) {
432 crtc_info_.secure_disp_blend_stage = std::stoi(string(line, (sec_ui_blendstage).length()));
433 } else if (line.find(num_mnocports) != string::npos) {
434 crtc_info_.num_mnocports = std::stoi(string(line, num_mnocports.length()));
435 } else if (line.find(mnoc_bus_width) != string::npos) {
436 crtc_info_.mnoc_bus_width = std::stoi(string(line, mnoc_bus_width.length()));
437 } else if (line.find(linewidth_constraints) != string::npos) {
438 crtc_info_.line_width_constraints_count =
439 std::stoi(string(line, (linewidth_constraints).length()));
440 } else if (line.find(vig) != string::npos) {
441 crtc_info_.vig_limit_index = std::stoi(string(line, (vig).length()));
442 } else if (line.find(dma) != string::npos) {
443 crtc_info_.dma_limit_index = std::stoi(string(line, (dma).length()));
444 } else if (line.find(scaling) != string::npos) {
445 crtc_info_.scaling_limit_index = std::stoi(string(line, (scaling).length()));
446 } else if (line.find(rotation) != string::npos) {
447 crtc_info_.rotation_limit_index = std::stoi(string(line, (rotation).length()));
448 } else if (line.find(linewidth_values) != string::npos) {
449 uint32_t num_linewidth_values = std::stoi(string(line, (linewidth_values).length()));
450 vector< pair <uint32_t,uint32_t> > constraint_vector;
451 for (uint32_t i = 0; i < num_linewidth_values; i++) {
452 uint32_t constraint = 0;
453 uint32_t value = 0;
454 std::getline(stream, line);
455 if (line.find(limit_constraint) != string::npos) {
456 constraint = std::stoi(string(line, (limit_constraint).length()));
457 }
458 std::getline(stream, line);
459 if (line.find(limit_value) != string::npos) {
460 value = std::stoi(string(line, (limit_value).length()));
461 }
462 if (value) {
463 constraint_vector.push_back(std::make_pair(constraint,value));
464 }
465 }
466 crtc_info_.line_width_limits = std::move(constraint_vector);
467 } else if (line.find(has_micro_idle) != string::npos) {
468 crtc_info_.has_micro_idle = std::stoi(string(line, (has_micro_idle).length()));
469 } else if (line.find(use_baselayer_for_stage) != string::npos) {
470 crtc_info_.use_baselayer_for_stage =
471 std::stoi(string(line, use_baselayer_for_stage.length()));
472 } else if (line.find(ubwc_version) != string::npos) {
473 crtc_info_.ubwc_version = (std::stoi(string(line, ubwc_version.length()))) >> 28;
474 } else if (line.find(rc_total_mem_size) != string::npos) {
475 crtc_info_.rc_total_mem_size = std::stoi(string(line, rc_total_mem_size.length()));
476 }
477 }
478 drmModeFreePropertyBlob(blob);
479 delete[] fmt_str;
480 }
481
ParseCompRatio(string line,bool real_time)482 void DRMCrtc::ParseCompRatio(string line, bool real_time) {
483 CompRatioMap &comp_ratio_map =
484 real_time ? crtc_info_.comp_ratio_rt_map : crtc_info_.comp_ratio_nrt_map;
485 std::vector<string> format_cr_list;
486
487 Tokenize(line, &format_cr_list, ' ');
488
489 for (uint32_t i = 0; i < format_cr_list.size(); i++) {
490 std::vector<string> format_cr;
491 Tokenize(format_cr_list.at(i), &format_cr, '/');
492 std::string format = format_cr.at(0);
493 uint64_t vendor_code = stoi(format_cr.at(1));
494 uint64_t fmt_modifier = stoi(format_cr.at(2));
495 float comp_ratio = std::stof(format_cr.at(3));
496 uint64_t modifier = 0;
497
498 if (vendor_code == DRM_FORMAT_MOD_VENDOR_QCOM) {
499 // Macro from drm_fourcc.h to form modifier
500 modifier = fourcc_mod_code(QCOM, fmt_modifier);
501 }
502
503 std::pair<uint32_t, uint64_t> drm_format =
504 std::make_pair(fourcc_code(format[0], format[1], format[2], format[3]), modifier);
505 comp_ratio_map.insert(std::make_pair(drm_format, comp_ratio));
506 }
507 }
508
GetInfo(DRMCrtcInfo * info)509 void DRMCrtc::GetInfo(DRMCrtcInfo *info) {
510 *info = crtc_info_;
511 }
512
Lock()513 void DRMCrtc::Lock() {
514 status_ = DRMStatus::BUSY;
515 }
516
Unlock()517 void DRMCrtc::Unlock() {
518 if (mode_blob_id_) {
519 drmModeDestroyPropertyBlob(fd_, mode_blob_id_);
520 mode_blob_id_ = 0;
521 }
522
523 ClearProperties();
524 status_ = DRMStatus::FREE;
525 }
526
SetModeBlobID(uint64_t blob_id)527 void DRMCrtc::SetModeBlobID(uint64_t blob_id) {
528 if (mode_blob_id_) {
529 drmModeDestroyPropertyBlob(fd_, mode_blob_id_);
530 }
531
532 mode_blob_id_ = blob_id;
533 }
534
InitAndParse(drmModeCrtc * crtc)535 void DRMCrtc::InitAndParse(drmModeCrtc *crtc) {
536 drm_crtc_ = crtc;
537 ParseProperties();
538 pp_mgr_ = std::unique_ptr<DRMPPManager>(new DRMPPManager(fd_));
539 pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_CRTC);
540 }
541
Perform(DRMOps code,drmModeAtomicReq * req,va_list args)542 void DRMCrtc::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) {
543 uint32_t obj_id = drm_crtc_->crtc_id;
544
545 switch (code) {
546 case DRMOps::CRTC_SET_MODE: {
547 drmModeModeInfo *mode = va_arg(args, drmModeModeInfo *);
548 uint32_t blob_id = 0;
549
550 if (mode) {
551 if (drmModeCreatePropertyBlob(fd_, (const void *)mode, sizeof(drmModeModeInfo), &blob_id)) {
552 DRM_LOGE("drmModeCreatePropertyBlob failed for CRTC_SET_MODE, crtc %d", obj_id);
553 return;
554 }
555 }
556
557 AddProperty(DRMProperty::MODE_ID, blob_id, true);
558 SetModeBlobID(blob_id);
559 DRM_LOGD("CRTC %d: Set mode %s", obj_id, mode ? mode->name : "null");
560 } break;
561
562 case DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET: {
563 uint32_t offset = va_arg(args, uint32_t);
564 AddProperty(DRMProperty::OUTPUT_FENCE_OFFSET, offset);
565 }; break;
566
567 case DRMOps::CRTC_SET_CORE_CLK: {
568 uint32_t core_clk = va_arg(args, uint32_t);
569 AddProperty(DRMProperty::CORE_CLK, core_clk);
570 }; break;
571
572 case DRMOps::CRTC_SET_CORE_AB: {
573 uint64_t core_ab = va_arg(args, uint64_t);
574 AddProperty(DRMProperty::CORE_AB, core_ab);
575 }; break;
576
577 case DRMOps::CRTC_SET_CORE_IB: {
578 uint64_t core_ib = va_arg(args, uint64_t);
579 AddProperty(DRMProperty::CORE_IB, core_ib);
580 }; break;
581
582 case DRMOps::CRTC_SET_LLCC_AB: {
583 uint64_t llcc_ab = va_arg(args, uint64_t);
584 AddProperty(DRMProperty::LLCC_AB, llcc_ab);
585 }; break;
586
587 case DRMOps::CRTC_SET_LLCC_IB: {
588 uint64_t llcc_ib = va_arg(args, uint64_t);
589 AddProperty(DRMProperty::LLCC_IB, llcc_ib);
590 }; break;
591
592 case DRMOps::CRTC_SET_DRAM_AB: {
593 uint64_t dram_ab = va_arg(args, uint64_t);
594 AddProperty(DRMProperty::DRAM_AB, dram_ab);
595 }; break;
596
597 case DRMOps::CRTC_SET_DRAM_IB: {
598 uint64_t dram_ib = va_arg(args, uint64_t);
599 AddProperty(DRMProperty::DRAM_IB, dram_ib);
600 }; break;
601
602 case DRMOps::CRTC_SET_ROT_PREFILL_BW: {
603 uint64_t rot_bw = va_arg(args, uint64_t);
604 AddProperty(DRMProperty::ROT_PREFILL_BW, rot_bw);
605 }; break;
606
607 case DRMOps::CRTC_SET_ROT_CLK: {
608 uint32_t rot_clk = va_arg(args, uint32_t);
609 AddProperty(DRMProperty::ROT_CLK, rot_clk);
610 }; break;
611
612 case DRMOps::CRTC_GET_RELEASE_FENCE: {
613 int64_t *fence = va_arg(args, int64_t *);
614 *fence = -1;
615 AddProperty(DRMProperty::OUTPUT_FENCE,
616 reinterpret_cast<uint64_t>(fence), true);
617 } break;
618
619 case DRMOps::CRTC_SET_ACTIVE: {
620 uint32_t enable = va_arg(args, uint32_t);
621 AddProperty(DRMProperty::ACTIVE, enable);
622 DRM_LOGD("CRTC %d: Set active %d", obj_id, enable);
623 if (enable == 0) {
624 ClearVotesCache();
625 }
626 } break;
627
628 case DRMOps::CRTC_SET_POST_PROC: {
629 DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*);
630 if (data)
631 pp_mgr_->SetPPFeature(req, obj_id, *data);
632 DRM_LOGD("CRTC %d: Set post proc", obj_id);
633 } break;
634
635 case DRMOps::CRTC_SET_ROI: {
636 uint32_t num_roi = va_arg(args, uint32_t);
637 DRMRect *crtc_rois = va_arg(args, DRMRect*);
638 SetROI(num_roi, crtc_rois);
639 } break;
640
641 case DRMOps::CRTC_SET_SECURITY_LEVEL: {
642 int security_level = va_arg(args, int);
643 uint32_t crtc_security_level = SECURE_NON_SECURE;
644 if (security_level == (int)DRMSecurityLevel::SECURE_ONLY) {
645 crtc_security_level = SECURE_ONLY;
646 }
647 AddProperty(DRMProperty::SECURITY_LEVEL, crtc_security_level);
648 } break;
649
650 case DRMOps::CRTC_SET_SOLIDFILL_STAGES: {
651 uint64_t dim_stages = va_arg(args, uint64_t);
652 const std::vector<DRMSolidfillStage> *solid_fills =
653 reinterpret_cast <std::vector <DRMSolidfillStage> *> (dim_stages);
654 SetSolidfillStages(solid_fills);
655 } break;
656
657 case DRMOps::CRTC_SET_IDLE_TIMEOUT: {
658 uint32_t timeout_ms = va_arg(args, uint32_t);
659 AddProperty(DRMProperty::IDLE_TIME, timeout_ms);
660 } break;
661
662 case DRMOps::CRTC_SET_DEST_SCALER_CONFIG: {
663 uint64_t dest_scaler = va_arg(args, uint64_t);
664 static sde_drm_dest_scaler_data dest_scale_copy = {};
665 sde_drm_dest_scaler_data *ds_data = reinterpret_cast<sde_drm_dest_scaler_data *>
666 (dest_scaler);
667 dest_scale_copy = *ds_data;
668 AddProperty(DRMProperty::DEST_SCALER,
669 reinterpret_cast<uint64_t>(&dest_scale_copy), true);
670 } break;
671
672 case DRMOps::CRTC_SET_CAPTURE_MODE: {
673 int capture_mode = va_arg(args, int);
674 uint32_t cwb_capture_mode = CAPTURE_MIXER_OUT;
675 if (capture_mode == (int)DRMCWbCaptureMode::DSPP_OUT) {
676 cwb_capture_mode = CAPTURE_DSPP_OUT;
677 }
678 AddProperty(DRMProperty::CAPTURE_MODE, cwb_capture_mode);
679 } break;
680
681 case DRMOps::CRTC_SET_IDLE_PC_STATE: {
682 if (!prop_mgr_.IsPropertyAvailable(DRMProperty::IDLE_PC_STATE)) {
683 return;
684 }
685 int drm_idle_pc_state = va_arg(args, int);
686 uint32_t idle_pc_state = IDLE_PC_STATE_NONE;
687 switch (drm_idle_pc_state) {
688 case static_cast<int>(DRMIdlePCState::ENABLE):
689 idle_pc_state = IDLE_PC_STATE_ENABLE;
690 break;
691 case static_cast<int>(DRMIdlePCState::DISABLE):
692 idle_pc_state = IDLE_PC_STATE_DISABLE;
693 break;
694 default:
695 idle_pc_state = IDLE_PC_STATE_NONE;
696 break;
697 }
698 AddProperty(DRMProperty::IDLE_PC_STATE, idle_pc_state);
699 DRM_LOGD("CRTC %d: Set idle_pc_state %d", obj_id, idle_pc_state);
700 }; break;
701
702 default:
703 DRM_LOGE("Invalid opcode %d to set the property on crtc %d", code, obj_id);
704 break;
705 }
706 }
707
SetROI(uint32_t num_roi,DRMRect * crtc_rois)708 void DRMCrtc::SetROI(uint32_t num_roi, DRMRect *crtc_rois) {
709 #ifdef SDE_MAX_ROI_V1
710 if (num_roi > SDE_MAX_ROI_V1 || !prop_mgr_.IsPropertyAvailable(DRMProperty::ROI_V1)) {
711 return;
712 }
713 if (!num_roi || !crtc_rois) {
714 AddProperty(DRMProperty::ROI_V1, 0, true);
715 DRM_LOGD("CRTC ROI is set to NULL to indicate full frame update");
716 return;
717 }
718 memset(&roi_v1_, 0, sizeof(roi_v1_));
719 roi_v1_.num_rects = num_roi;
720
721 for (uint32_t i = 0; i < num_roi; i++) {
722 roi_v1_.roi[i].x1 = crtc_rois[i].left;
723 roi_v1_.roi[i].x2 = crtc_rois[i].right;
724 roi_v1_.roi[i].y1 = crtc_rois[i].top;
725 roi_v1_.roi[i].y2 = crtc_rois[i].bottom;
726 DRM_LOGD("CRTC %d, ROI[l,t,b,r][%d %d %d %d]", GetObjectId(),
727 roi_v1_.roi[i].x1, roi_v1_.roi[i].y1, roi_v1_.roi[i].x2, roi_v1_.roi[i].y2);
728 }
729
730 AddProperty(DRMProperty::ROI_V1, reinterpret_cast<uint64_t>(&roi_v1_), true);
731 #endif
732 }
733
SetSolidfillStages(const std::vector<DRMSolidfillStage> * solid_fills)734 void DRMCrtc::SetSolidfillStages(const std::vector<DRMSolidfillStage> *solid_fills) {
735 #if defined SDE_MAX_DIM_LAYERS
736 memset(&drm_dim_layer_v1_, 0, sizeof(drm_dim_layer_v1_));
737 uint32_t shift;
738
739 drm_dim_layer_v1_.num_layers = static_cast<uint32_t> (solid_fills->size());
740 for (uint32_t i = 0; i < solid_fills->size(); i++) {
741 const DRMSolidfillStage &sf = solid_fills->at(i);
742 float plane_alpha = (sf.plane_alpha / 255.0f);
743 drm_dim_layer_v1_.layer_cfg[i].stage = sf.z_order;
744 drm_dim_layer_v1_.layer_cfg[i].rect.x1 = (uint16_t)sf.bounding_rect.left;
745 drm_dim_layer_v1_.layer_cfg[i].rect.y1 = (uint16_t)sf.bounding_rect.top;
746 drm_dim_layer_v1_.layer_cfg[i].rect.x2 = (uint16_t)sf.bounding_rect.right;
747 drm_dim_layer_v1_.layer_cfg[i].rect.y2 = (uint16_t)sf.bounding_rect.bottom;
748 drm_dim_layer_v1_.layer_cfg[i].flags =
749 sf.is_exclusion_rect ? SDE_DRM_DIM_LAYER_EXCLUSIVE : SDE_DRM_DIM_LAYER_INCLUSIVE;
750
751 // @sde_mdss_color: expects in [g b r a] order where as till now solidfill is in [a r g b].
752 // As no support for passing plane alpha, Multiply Alpha color component with plane_alpa.
753 shift = kSolidFillHwBitDepth - sf.color_bit_depth;
754 drm_dim_layer_v1_.layer_cfg[i].color_fill.color_0 = (sf.green & 0x3FF) << shift;
755 drm_dim_layer_v1_.layer_cfg[i].color_fill.color_1 = (sf.blue & 0x3FF) << shift;
756 drm_dim_layer_v1_.layer_cfg[i].color_fill.color_2 = (sf.red & 0x3FF) << shift;
757 // alpha is 8 bit
758 drm_dim_layer_v1_.layer_cfg[i].color_fill.color_3 =
759 ((uint32_t)((((sf.alpha & 0xFF)) * plane_alpha)));
760 }
761
762 AddProperty(DRMProperty::DIM_STAGES_V1,
763 reinterpret_cast<uint64_t> (&drm_dim_layer_v1_), true);
764 #endif
765 }
766
Dump()767 void DRMCrtc::Dump() {
768 DRM_LOGE("id: %d\tbuffer_id: %d\tpos:(%d, %d)\tsize:(%dx%d)\n", drm_crtc_->crtc_id,
769 drm_crtc_->buffer_id, drm_crtc_->x, drm_crtc_->y, drm_crtc_->width, drm_crtc_->height);
770 }
771
ConfigureScalerLUT(uint32_t dir_lut_blob_id,uint32_t cir_lut_blob_id,uint32_t sep_lut_blob_id)772 bool DRMCrtc::ConfigureScalerLUT(uint32_t dir_lut_blob_id,
773 uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id) {
774 if (is_lut_configured_ && is_lut_validated_) {
775 return false;
776 }
777 if (dir_lut_blob_id) {
778 AddProperty(DRMProperty::DS_LUT_ED, dir_lut_blob_id, true);
779 }
780 if (cir_lut_blob_id) {
781 AddProperty(DRMProperty::DS_LUT_CIR, cir_lut_blob_id, true);
782 }
783 if (sep_lut_blob_id) {
784 AddProperty(DRMProperty::DS_LUT_SEP, sep_lut_blob_id, true);
785 }
786 is_lut_validation_in_progress_ = true;
787 return true;
788 }
789
PostCommit(bool success)790 void DRMCrtc::PostCommit(bool success) {
791 if (success) {
792 if (is_lut_validated_) {
793 is_lut_configured_ = true;
794 }
795 CommitProperties();
796 }
797 }
798
PostValidate()799 void DRMCrtc::PostValidate() {
800 if (is_lut_validation_in_progress_) {
801 is_lut_validated_ = true;
802 }
803 }
804
ClearVotesCache()805 void DRMCrtc::ClearVotesCache() {
806 RemoveProperty(DRMProperty::CORE_CLK);
807 RemoveProperty(DRMProperty::CORE_AB);
808 RemoveProperty(DRMProperty::CORE_IB);
809 RemoveProperty(DRMProperty::LLCC_AB);
810 RemoveProperty(DRMProperty::LLCC_IB);
811 RemoveProperty(DRMProperty::DRAM_AB);
812 RemoveProperty(DRMProperty::DRAM_IB);
813 }
814
815 } // namespace sde_drm
816