• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #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   char *fmt_str = new char[blob->length + 1];
304   memcpy (fmt_str, blob->data, blob->length);
305   fmt_str[blob->length] = '\0';
306   stringstream stream(fmt_str);
307   DRM_LOGI("stream str %s len %zu blob str %s len %d", stream.str().c_str(), stream.str().length(),
308            blob->data, blob->length);
309   string line = {};
310   string max_blendstages = "max_blendstages=";
311   string qseed_type = "qseed_type=";
312   string has_src_split = "has_src_split=";
313   string sdma_rev = "smart_dma_rev=";
314   string core_ib_ff = "core_ib_ff=";
315   string dest_scale_prefill_lines = "dest_scale_prefill_lines=";
316   string undersized_prefill_lines = "undersized_prefill_lines=";
317   string macrotile_prefill_lines = "macrotile_prefill_lines=";
318   string yuv_nv12_prefill_lines = "yuv_nv12_prefill_lines=";
319   string linear_prefill_lines = "linear_prefill_lines=";
320   string downscaling_prefill_lines = "downscaling_prefill_lines=";
321   string xtra_prefill_lines = "xtra_prefill_lines=";
322   string amortizable_threshold = "amortizable_threshold=";
323   string max_bandwidth_low = "max_bandwidth_low=";
324   string max_bandwidth_high = "max_bandwidth_high=";
325   string max_mdp_clk = "max_mdp_clk=";
326   string core_clk_ff = "core_clk_ff=";
327   string comp_ratio_rt = "comp_ratio_rt=";
328   string comp_ratio_nrt = "comp_ratio_nrt=";
329   string hw_version = "hw_version=";
330   string solidfill_stages = "dim_layer_v1_max_layers=";
331   string has_hdr = "has_hdr=";
332   string has_micro_idle = "has_uidle=";
333   string min_prefill_lines = "min_prefill_lines=";
334   string num_mnocports = "num_mnoc_ports=";
335   string mnoc_bus_width = "axi_bus_width=";
336 
337   crtc_info_.max_solidfill_stages = 0;  // default _
338   string dest_scaler_count = "dest_scaler_count=";
339   string max_dest_scale_up = "max_dest_scale_up=";
340   string max_dest_scaler_input_width = "max_dest_scaler_input_width=";
341   string max_dest_scaler_output_width = "max_dest_scaler_output_width=";
342   string sec_ui_blendstage = "sec_ui_blendstage=";
343   string vig = "vig=";
344   string dma = "dma=";
345   string scaling = "scale=";
346   string rotation = "inline_rot=";
347   string linewidth_constraints = "sspp_linewidth_usecases=";
348   string linewidth_values = "sspp_linewidth_values=";
349   string limit_constraint = "limit_usecase=";
350   string limit_value = "limit_value=";
351   string use_baselayer_for_stage = "use_baselayer_for_stage=";
352   string ubwc_version = "UBWC version=";
353 
354   while (std::getline(stream, line)) {
355     if (line.find(max_blendstages) != string::npos) {
356       crtc_info_.max_blend_stages = std::stoi(string(line, max_blendstages.length()));
357     } else if (line.find(qseed_type) != string::npos) {
358       if (string(line, qseed_type.length()) == "qseed2") {
359         crtc_info_.qseed_version = QSEEDVersion::V2;
360       } else if (string(line, qseed_type.length()) == "qseed3") {
361         crtc_info_.qseed_version = QSEEDVersion::V3;
362       } else if (string(line, qseed_type.length()) == "qseed3lite") {
363         crtc_info_.qseed_version = QSEEDVersion::V3LITE;
364       }
365     } else if (line.find(has_src_split) != string::npos) {
366       crtc_info_.has_src_split = std::stoi(string(line, has_src_split.length()));
367     } else if (line.find(sdma_rev) != string::npos) {
368       if (string(line, sdma_rev.length()) == "smart_dma_v2p5")
369         crtc_info_.smart_dma_rev = SmartDMARevision::V2p5;
370       else if (string(line, sdma_rev.length()) == "smart_dma_v2")
371         crtc_info_.smart_dma_rev = SmartDMARevision::V2;
372       else if (string(line, sdma_rev.length()) == "smart_dma_v1")
373         crtc_info_.smart_dma_rev = SmartDMARevision::V1;
374     } else if (line.find(core_ib_ff) != string::npos) {
375       crtc_info_.ib_fudge_factor = std::stof(string(line, core_ib_ff.length()));
376     } else if (line.find(dest_scale_prefill_lines) != string::npos) {
377       crtc_info_.dest_scale_prefill_lines =
378         std::stoi(string(line, dest_scale_prefill_lines.length()));
379     } else if (line.find(undersized_prefill_lines) != string::npos) {
380       crtc_info_.undersized_prefill_lines =
381         std::stoi(string(line, undersized_prefill_lines.length()));
382     } else if (line.find(macrotile_prefill_lines) != string::npos) {
383       crtc_info_.macrotile_prefill_lines =
384         std::stoi(string(line, macrotile_prefill_lines.length()));
385     } else if (line.find(yuv_nv12_prefill_lines) != string::npos) {
386       crtc_info_.nv12_prefill_lines = std::stoi(string(line, yuv_nv12_prefill_lines.length()));
387     } else if (line.find(linear_prefill_lines) != string::npos) {
388       crtc_info_.linear_prefill_lines = std::stoi(string(line, linear_prefill_lines.length()));
389     } else if (line.find(downscaling_prefill_lines) != string::npos) {
390       crtc_info_.downscale_prefill_lines =
391         std::stoi(string(line, downscaling_prefill_lines.length()));
392     } else if (line.find(xtra_prefill_lines) != string::npos) {
393       crtc_info_.extra_prefill_lines = std::stoi(string(line, xtra_prefill_lines.length()));
394     } else if (line.find(amortizable_threshold) != string::npos) {
395       crtc_info_.amortized_threshold = std::stoi(string(line, amortizable_threshold.length()));
396     } else if (line.find(max_bandwidth_low) != string::npos) {
397       crtc_info_.max_bandwidth_low = std::stoull(string(line, max_bandwidth_low.length()));
398     } else if (line.find(max_bandwidth_high) != string::npos) {
399       crtc_info_.max_bandwidth_high = std::stoull(string(line, max_bandwidth_high.length()));
400     } else if (line.find(max_mdp_clk) != string::npos) {
401       crtc_info_.max_sde_clk = std::stoi(string(line, max_mdp_clk.length()));
402     } else if (line.find(core_clk_ff) != string::npos) {
403       crtc_info_.clk_fudge_factor = std::stof(string(line, core_clk_ff.length()));
404     } else if (line.find(comp_ratio_rt) != string::npos) {
405       ParseCompRatio(line.substr(comp_ratio_rt.length()), true);
406     } else if (line.find(comp_ratio_nrt) != string::npos) {
407       ParseCompRatio(line.substr(comp_ratio_nrt.length()), false);
408     } else if (line.find(hw_version) != string::npos) {
409       crtc_info_.hw_version = std::stoi(string(line, hw_version.length()));
410     } else if (line.find(solidfill_stages) != string::npos) {
411       crtc_info_.max_solidfill_stages =  std::stoi(string(line, solidfill_stages.length()));
412     } else if (line.find(dest_scaler_count) != string::npos) {
413       crtc_info_.dest_scaler_count = std::stoi(string(line, dest_scaler_count.length()));
414     } else if (line.find(max_dest_scale_up) != string::npos) {
415       crtc_info_.max_dest_scale_up = std::stoi(string(line, max_dest_scale_up.length()));
416     } else if (line.find(max_dest_scaler_input_width) != string::npos) {
417       crtc_info_.max_dest_scaler_input_width =
418                           std::stoi(string(line, max_dest_scaler_input_width.length()));
419     } else if (line.find(max_dest_scaler_output_width) != string::npos) {
420       crtc_info_.max_dest_scaler_output_width =
421                          std::stoi(string(line, max_dest_scaler_output_width.length()));
422     } else if (line.find(has_hdr) != string::npos) {
423       crtc_info_.has_hdr = std::stoi(string(line, has_hdr.length()));
424     } else if (line.find(min_prefill_lines) != string::npos) {
425       crtc_info_.min_prefill_lines = std::stoi(string(line, min_prefill_lines.length()));
426     } else if (line.find(sec_ui_blendstage) != string::npos) {
427       crtc_info_.secure_disp_blend_stage = std::stoi(string(line, (sec_ui_blendstage).length()));
428     } else if (line.find(num_mnocports) != string::npos) {
429       crtc_info_.num_mnocports = std::stoi(string(line, num_mnocports.length()));
430     } else if (line.find(mnoc_bus_width) != string::npos) {
431       crtc_info_.mnoc_bus_width = std::stoi(string(line, mnoc_bus_width.length()));
432     } else if (line.find(linewidth_constraints) != string::npos) {
433       crtc_info_.line_width_constraints_count =
434                             std::stoi(string(line, (linewidth_constraints).length()));
435     } else if (line.find(vig) != string::npos) {
436       crtc_info_.vig_limit_index = std::stoi(string(line, (vig).length()));
437     } else if (line.find(dma) != string::npos) {
438       crtc_info_.dma_limit_index = std::stoi(string(line, (dma).length()));
439     } else if (line.find(scaling) != string::npos) {
440       crtc_info_.scaling_limit_index = std::stoi(string(line, (scaling).length()));
441     } else if (line.find(rotation) != string::npos) {
442       crtc_info_.rotation_limit_index = std::stoi(string(line, (rotation).length()));
443     } else if (line.find(linewidth_values) != string::npos) {
444       uint32_t num_linewidth_values = std::stoi(string(line, (linewidth_values).length()));
445       vector< pair <uint32_t,uint32_t> > constraint_vector;
446       for (uint32_t i = 0; i < num_linewidth_values; i++) {
447         uint32_t constraint = 0;
448         uint32_t value  = 0;
449         std::getline(stream, line);
450         if (line.find(limit_constraint) != string::npos) {
451           constraint = std::stoi(string(line, (limit_constraint).length()));
452         }
453         std::getline(stream, line);
454         if (line.find(limit_value) != string::npos) {
455           value = std::stoi(string(line, (limit_value).length()));
456         }
457         if (value) {
458           constraint_vector.push_back(std::make_pair(constraint,value));
459         }
460       }
461       crtc_info_.line_width_limits = std::move(constraint_vector);
462     } else if (line.find(has_micro_idle) != string::npos) {
463       crtc_info_.has_micro_idle = std::stoi(string(line, (has_micro_idle).length()));
464     } else if (line.find(use_baselayer_for_stage) != string::npos) {
465       crtc_info_.use_baselayer_for_stage =
466                          std::stoi(string(line, use_baselayer_for_stage.length()));
467     } else if (line.find(ubwc_version) != string::npos) {
468       crtc_info_.ubwc_version = (std::stoi(string(line, ubwc_version.length()))) >> 28;
469     }
470   }
471   drmModeFreePropertyBlob(blob);
472 }
473 
ParseCompRatio(string line,bool real_time)474 void DRMCrtc::ParseCompRatio(string line, bool real_time) {
475   CompRatioMap &comp_ratio_map =
476     real_time ? crtc_info_.comp_ratio_rt_map : crtc_info_.comp_ratio_nrt_map;
477   std::vector<string> format_cr_list;
478 
479   Tokenize(line, &format_cr_list, ' ');
480 
481   for (uint32_t i = 0; i < format_cr_list.size(); i++) {
482     std::vector<string> format_cr;
483     Tokenize(format_cr_list.at(i), &format_cr, '/');
484     std::string format = format_cr.at(0);
485     uint64_t vendor_code = stoi(format_cr.at(1));
486     uint64_t fmt_modifier = stoi(format_cr.at(2));
487     float comp_ratio = std::stof(format_cr.at(3));
488     uint64_t modifier = 0;
489 
490     if (vendor_code == DRM_FORMAT_MOD_VENDOR_QCOM) {
491       // Macro from drm_fourcc.h to form modifier
492       modifier = fourcc_mod_code(QCOM, fmt_modifier);
493     }
494 
495     std::pair<uint32_t, uint64_t> drm_format =
496       std::make_pair(fourcc_code(format[0], format[1], format[2], format[3]), modifier);
497     comp_ratio_map.insert(std::make_pair(drm_format, comp_ratio));
498   }
499 }
500 
GetInfo(DRMCrtcInfo * info)501 void DRMCrtc::GetInfo(DRMCrtcInfo *info) {
502   *info = crtc_info_;
503 }
504 
Lock()505 void DRMCrtc::Lock() {
506   status_ = DRMStatus::BUSY;
507 }
508 
Unlock()509 void DRMCrtc::Unlock() {
510   if (mode_blob_id_) {
511     drmModeDestroyPropertyBlob(fd_, mode_blob_id_);
512     mode_blob_id_ = 0;
513   }
514 
515   ClearProperties();
516   status_ = DRMStatus::FREE;
517 }
518 
SetModeBlobID(uint64_t blob_id)519 void DRMCrtc::SetModeBlobID(uint64_t blob_id) {
520   if (mode_blob_id_) {
521     drmModeDestroyPropertyBlob(fd_, mode_blob_id_);
522   }
523 
524   mode_blob_id_ = blob_id;
525 }
526 
InitAndParse(drmModeCrtc * crtc)527 void DRMCrtc::InitAndParse(drmModeCrtc *crtc) {
528   drm_crtc_ = crtc;
529   ParseProperties();
530   pp_mgr_ = std::unique_ptr<DRMPPManager>(new DRMPPManager(fd_));
531   pp_mgr_->Init(prop_mgr_, DRM_MODE_OBJECT_CRTC);
532 }
533 
Perform(DRMOps code,drmModeAtomicReq * req,va_list args)534 void DRMCrtc::Perform(DRMOps code, drmModeAtomicReq *req, va_list args) {
535   uint32_t obj_id = drm_crtc_->crtc_id;
536 
537   switch (code) {
538     case DRMOps::CRTC_SET_MODE: {
539       drmModeModeInfo *mode = va_arg(args, drmModeModeInfo *);
540       uint32_t blob_id = 0;
541 
542       if (mode) {
543         if (drmModeCreatePropertyBlob(fd_, (const void *)mode, sizeof(drmModeModeInfo), &blob_id)) {
544           DRM_LOGE("drmModeCreatePropertyBlob failed for CRTC_SET_MODE, crtc %d", obj_id);
545           return;
546         }
547       }
548 
549       AddProperty(DRMProperty::MODE_ID, blob_id, true);
550       SetModeBlobID(blob_id);
551       DRM_LOGD("CRTC %d: Set mode %s", obj_id, mode ? mode->name : "null");
552     } break;
553 
554     case DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET: {
555       uint32_t offset = va_arg(args, uint32_t);
556       AddProperty(DRMProperty::OUTPUT_FENCE_OFFSET, offset);
557     }; break;
558 
559     case DRMOps::CRTC_SET_CORE_CLK: {
560       uint32_t core_clk = va_arg(args, uint32_t);
561       AddProperty(DRMProperty::CORE_CLK, core_clk);
562     }; break;
563 
564     case DRMOps::CRTC_SET_CORE_AB: {
565       uint64_t core_ab = va_arg(args, uint64_t);
566       AddProperty(DRMProperty::CORE_AB, core_ab);
567     }; break;
568 
569     case DRMOps::CRTC_SET_CORE_IB: {
570       uint64_t core_ib = va_arg(args, uint64_t);
571       AddProperty(DRMProperty::CORE_IB, core_ib);
572     }; break;
573 
574     case DRMOps::CRTC_SET_LLCC_AB: {
575       uint64_t llcc_ab = va_arg(args, uint64_t);
576       AddProperty(DRMProperty::LLCC_AB, llcc_ab);
577     }; break;
578 
579     case DRMOps::CRTC_SET_LLCC_IB: {
580       uint64_t llcc_ib = va_arg(args, uint64_t);
581       AddProperty(DRMProperty::LLCC_IB, llcc_ib);
582     }; break;
583 
584     case DRMOps::CRTC_SET_DRAM_AB: {
585       uint64_t dram_ab = va_arg(args, uint64_t);
586       AddProperty(DRMProperty::DRAM_AB, dram_ab);
587     }; break;
588 
589     case DRMOps::CRTC_SET_DRAM_IB: {
590       uint64_t dram_ib = va_arg(args, uint64_t);
591       AddProperty(DRMProperty::DRAM_IB, dram_ib);
592     }; break;
593 
594     case DRMOps::CRTC_SET_ROT_PREFILL_BW: {
595       uint64_t rot_bw = va_arg(args, uint64_t);
596       AddProperty(DRMProperty::ROT_PREFILL_BW, rot_bw);
597     }; break;
598 
599     case DRMOps::CRTC_SET_ROT_CLK: {
600       uint32_t rot_clk = va_arg(args, uint32_t);
601       AddProperty(DRMProperty::ROT_CLK, rot_clk);
602     }; break;
603 
604     case DRMOps::CRTC_GET_RELEASE_FENCE: {
605       int64_t *fence = va_arg(args, int64_t *);
606       *fence = -1;
607       AddProperty(DRMProperty::OUTPUT_FENCE,
608                   reinterpret_cast<uint64_t>(fence), true);
609     } break;
610 
611     case DRMOps::CRTC_SET_ACTIVE: {
612       uint32_t enable = va_arg(args, uint32_t);
613       AddProperty(DRMProperty::ACTIVE, enable);
614       DRM_LOGD("CRTC %d: Set active %d", obj_id, enable);
615       if (enable == 0) {
616         ClearVotesCache();
617       }
618     } break;
619 
620     case DRMOps::CRTC_SET_POST_PROC: {
621       DRMPPFeatureInfo *data = va_arg(args, DRMPPFeatureInfo*);
622       if (data)
623         pp_mgr_->SetPPFeature(req, obj_id, *data);
624       DRM_LOGD("CRTC %d: Set post proc", obj_id);
625     } break;
626 
627     case DRMOps::CRTC_SET_ROI: {
628       uint32_t num_roi = va_arg(args, uint32_t);
629       DRMRect *crtc_rois = va_arg(args, DRMRect*);
630       SetROI(num_roi, crtc_rois);
631     } break;
632 
633     case DRMOps::CRTC_SET_SECURITY_LEVEL: {
634       int security_level = va_arg(args, int);
635       uint32_t crtc_security_level = SECURE_NON_SECURE;
636       if (security_level == (int)DRMSecurityLevel::SECURE_ONLY) {
637         crtc_security_level = SECURE_ONLY;
638       }
639       AddProperty(DRMProperty::SECURITY_LEVEL, crtc_security_level);
640     } break;
641 
642     case DRMOps::CRTC_SET_SOLIDFILL_STAGES: {
643       uint64_t dim_stages = va_arg(args, uint64_t);
644       const std::vector<DRMSolidfillStage> *solid_fills =
645         reinterpret_cast <std::vector <DRMSolidfillStage> *> (dim_stages);
646       SetSolidfillStages(solid_fills);
647     } break;
648 
649     case DRMOps::CRTC_SET_IDLE_TIMEOUT: {
650       uint32_t timeout_ms = va_arg(args, uint32_t);
651       AddProperty(DRMProperty::IDLE_TIME, timeout_ms);
652     } break;
653 
654     case DRMOps::CRTC_SET_DEST_SCALER_CONFIG: {
655       uint64_t dest_scaler = va_arg(args, uint64_t);
656       static sde_drm_dest_scaler_data dest_scale_copy = {};
657       sde_drm_dest_scaler_data *ds_data = reinterpret_cast<sde_drm_dest_scaler_data *>
658                                            (dest_scaler);
659       dest_scale_copy = *ds_data;
660       AddProperty(DRMProperty::DEST_SCALER,
661                   reinterpret_cast<uint64_t>(&dest_scale_copy), true);
662     } break;
663 
664     case DRMOps::CRTC_SET_CAPTURE_MODE: {
665       int capture_mode = va_arg(args, int);
666       uint32_t cwb_capture_mode = CAPTURE_MIXER_OUT;
667       if (capture_mode == (int)DRMCWbCaptureMode::DSPP_OUT) {
668         cwb_capture_mode = CAPTURE_DSPP_OUT;
669       }
670       AddProperty(DRMProperty::CAPTURE_MODE, cwb_capture_mode);
671     } break;
672 
673     case DRMOps::CRTC_SET_IDLE_PC_STATE: {
674       if (!prop_mgr_.IsPropertyAvailable(DRMProperty::IDLE_PC_STATE)) {
675         return;
676       }
677       int drm_idle_pc_state = va_arg(args, int);
678       uint32_t idle_pc_state = IDLE_PC_STATE_NONE;
679       switch (drm_idle_pc_state) {
680         case static_cast<int>(DRMIdlePCState::ENABLE):
681           idle_pc_state = IDLE_PC_STATE_ENABLE;
682           break;
683         case static_cast<int>(DRMIdlePCState::DISABLE):
684           idle_pc_state = IDLE_PC_STATE_DISABLE;
685           break;
686         default:
687           idle_pc_state = IDLE_PC_STATE_NONE;
688           break;
689       }
690       AddProperty(DRMProperty::IDLE_PC_STATE, idle_pc_state);
691       DRM_LOGD("CRTC %d: Set idle_pc_state %d", obj_id, idle_pc_state);
692     }; break;
693 
694     default:
695       DRM_LOGE("Invalid opcode %d to set the property on crtc %d", code, obj_id);
696       break;
697   }
698 }
699 
SetROI(uint32_t num_roi,DRMRect * crtc_rois)700 void DRMCrtc::SetROI(uint32_t num_roi, DRMRect *crtc_rois) {
701 #ifdef SDE_MAX_ROI_V1
702   if (num_roi > SDE_MAX_ROI_V1 || !prop_mgr_.IsPropertyAvailable(DRMProperty::ROI_V1)) {
703     return;
704   }
705   if (!num_roi || !crtc_rois) {
706     AddProperty(DRMProperty::ROI_V1, 0, true);
707     DRM_LOGD("CRTC ROI is set to NULL to indicate full frame update");
708     return;
709   }
710   memset(&roi_v1_, 0, sizeof(roi_v1_));
711   roi_v1_.num_rects = num_roi;
712 
713   for (uint32_t i = 0; i < num_roi; i++) {
714     roi_v1_.roi[i].x1 = crtc_rois[i].left;
715     roi_v1_.roi[i].x2 = crtc_rois[i].right;
716     roi_v1_.roi[i].y1 = crtc_rois[i].top;
717     roi_v1_.roi[i].y2 = crtc_rois[i].bottom;
718     DRM_LOGD("CRTC %d, ROI[l,t,b,r][%d %d %d %d]", GetObjectId(),
719              roi_v1_.roi[i].x1, roi_v1_.roi[i].y1, roi_v1_.roi[i].x2, roi_v1_.roi[i].y2);
720   }
721 
722   AddProperty(DRMProperty::ROI_V1, reinterpret_cast<uint64_t>(&roi_v1_), true);
723 #endif
724 }
725 
SetSolidfillStages(const std::vector<DRMSolidfillStage> * solid_fills)726 void DRMCrtc::SetSolidfillStages(const std::vector<DRMSolidfillStage> *solid_fills) {
727 #if defined  SDE_MAX_DIM_LAYERS
728   memset(&drm_dim_layer_v1_, 0, sizeof(drm_dim_layer_v1_));
729   uint32_t shift;
730 
731   drm_dim_layer_v1_.num_layers = static_cast<uint32_t> (solid_fills->size());
732   for (uint32_t i = 0; i < solid_fills->size(); i++) {
733     const DRMSolidfillStage &sf = solid_fills->at(i);
734     float plane_alpha = (sf.plane_alpha / 255.0f);
735     drm_dim_layer_v1_.layer_cfg[i].stage = sf.z_order;
736     drm_dim_layer_v1_.layer_cfg[i].rect.x1 = (uint16_t)sf.bounding_rect.left;
737     drm_dim_layer_v1_.layer_cfg[i].rect.y1 = (uint16_t)sf.bounding_rect.top;
738     drm_dim_layer_v1_.layer_cfg[i].rect.x2 = (uint16_t)sf.bounding_rect.right;
739     drm_dim_layer_v1_.layer_cfg[i].rect.y2 = (uint16_t)sf.bounding_rect.bottom;
740     drm_dim_layer_v1_.layer_cfg[i].flags =
741       sf.is_exclusion_rect ? SDE_DRM_DIM_LAYER_EXCLUSIVE : SDE_DRM_DIM_LAYER_INCLUSIVE;
742 
743     // @sde_mdss_color: expects in [g b r a] order where as till now solidfill is in [a r g b].
744     // As no support for passing plane alpha, Multiply Alpha color component with plane_alpa.
745     shift = kSolidFillHwBitDepth - sf.color_bit_depth;
746     drm_dim_layer_v1_.layer_cfg[i].color_fill.color_0 = (sf.green & 0x3FF) << shift;
747     drm_dim_layer_v1_.layer_cfg[i].color_fill.color_1 = (sf.blue & 0x3FF) << shift;
748     drm_dim_layer_v1_.layer_cfg[i].color_fill.color_2 = (sf.red & 0x3FF) << shift;
749     // alpha is 8 bit
750     drm_dim_layer_v1_.layer_cfg[i].color_fill.color_3 =
751       ((uint32_t)((((sf.alpha & 0xFF)) * plane_alpha)));
752   }
753 
754   AddProperty(DRMProperty::DIM_STAGES_V1,
755               reinterpret_cast<uint64_t> (&drm_dim_layer_v1_), true);
756 #endif
757 }
758 
Dump()759 void DRMCrtc::Dump() {
760   DRM_LOGE("id: %d\tbuffer_id: %d\tpos:(%d, %d)\tsize:(%dx%d)\n", drm_crtc_->crtc_id,
761            drm_crtc_->buffer_id, drm_crtc_->x, drm_crtc_->y, drm_crtc_->width, drm_crtc_->height);
762 }
763 
ConfigureScalerLUT(uint32_t dir_lut_blob_id,uint32_t cir_lut_blob_id,uint32_t sep_lut_blob_id)764 bool DRMCrtc::ConfigureScalerLUT(uint32_t dir_lut_blob_id,
765                                  uint32_t cir_lut_blob_id, uint32_t sep_lut_blob_id) {
766   if (is_lut_configured_ && is_lut_validated_) {
767     return false;
768   }
769   if (dir_lut_blob_id) {
770     AddProperty(DRMProperty::DS_LUT_ED, dir_lut_blob_id, true);
771   }
772   if (cir_lut_blob_id) {
773     AddProperty(DRMProperty::DS_LUT_CIR, cir_lut_blob_id, true);
774   }
775   if (sep_lut_blob_id) {
776     AddProperty(DRMProperty::DS_LUT_SEP, sep_lut_blob_id, true);
777   }
778   is_lut_validation_in_progress_ = true;
779   return true;
780 }
781 
PostCommit(bool success)782 void DRMCrtc::PostCommit(bool success) {
783   if (success) {
784     if (is_lut_validated_) {
785       is_lut_configured_ = true;
786     }
787     CommitProperties();
788   }
789 }
790 
PostValidate()791 void DRMCrtc::PostValidate() {
792   if (is_lut_validation_in_progress_)  {
793     is_lut_validated_ = true;
794   }
795 }
796 
ClearVotesCache()797 void DRMCrtc::ClearVotesCache() {
798   RemoveProperty(DRMProperty::CORE_CLK);
799   RemoveProperty(DRMProperty::CORE_AB);
800   RemoveProperty(DRMProperty::CORE_IB);
801   RemoveProperty(DRMProperty::LLCC_AB);
802   RemoveProperty(DRMProperty::LLCC_IB);
803   RemoveProperty(DRMProperty::DRAM_AB);
804   RemoveProperty(DRMProperty::DRAM_IB);
805 }
806 
807 }  // namespace sde_drm
808