1 /* Copyright (c) 2021, The Linux Foundataion. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30 #include <sstream>
31 #include <errno.h>
32 #include <string>
33 #include <drm_logger.h>
34 #include <cstring>
35 #include <regex>
36 #include <inttypes.h>
37
38 #include "drm_panel_feature_mgr.h"
39
40 #define __CLASS__ "DRMPanelFeatureMgr"
41
42 namespace sde_drm {
43
44 using std::map;
45 using std::vector;
46 using std::mutex;
47 using std::lock_guard;
48
49 static DRMPanelFeatureMgr panel_feature_mgr;
50
GetPanelFeatureManagerIntf()51 DRMPanelFeatureMgrIntf *GetPanelFeatureManagerIntf() {
52 return &panel_feature_mgr;
53 }
54
Init(int fd,drmModeRes * res)55 void DRMPanelFeatureMgr::Init(int fd, drmModeRes* res) {
56 lock_guard<mutex> lock(lock_);
57
58 if (!res || (fd < 0)) {
59 DRM_LOGE("Invalid arguments for init - fd %d and DRM resources pointer 0x%p", fd, (void *)res);
60 return;
61 }
62
63 drm_res_ = res;
64 dev_fd_ = fd;
65
66 for (int i = 0; i < res->count_crtcs; i++) {
67 drmModeCrtc *crtc = drmModeGetCrtc(dev_fd_, res->crtcs[i]);
68 if (crtc) {
69 int err = InitObjectProps(crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
70 if (err) {
71 DRM_LOGE("Failed to get crtc props %d", crtc->crtc_id);
72 }
73 drmModeFreeCrtc(crtc);
74 }
75 }
76
77 for (int i = 0; i < res->count_connectors; i++) {
78 drmModeConnector *conn = drmModeGetConnector(dev_fd_, res->connectors[i]);
79 if (conn) {
80 int err = InitObjectProps(conn->connector_id, DRM_MODE_OBJECT_CONNECTOR);
81 if (err) {
82 DRM_LOGE("Failed to get conn %d properties", conn->connector_id);
83 }
84 drmModeFreeConnector(conn);
85 }
86 }
87
88 drm_property_map_[kDRMPanelFeatureDsppRCInfo] = DRMProperty::DSPP_CAPABILITIES;
89 drm_property_map_[kDRMPanelFeatureRCInit] = DRMProperty::DSPP_RC_MASK_V1;
90 drm_prop_type_map_[kDRMPanelFeatureRCInit] = DRMPropType::kPropBlob;
91 drm_prop_type_map_[kDRMPanelFeatureDsppRCInfo] = DRMPropType::kPropRange;
92
93
94 feature_info_tbl_[kDRMPanelFeatureRCInit] = DRMPanelFeatureInfo {
95 kDRMPanelFeatureRCInit, DRM_MODE_OBJECT_CRTC, UINT32_MAX, 1, sizeof(msm_rc_mask_cfg), 0};
96
97 feature_info_tbl_[kDRMPanelFeatureDsppRCInfo] = DRMPanelFeatureInfo {
98 kDRMPanelFeatureDsppRCInfo, DRM_MODE_OBJECT_CRTC, UINT32_MAX, 1, 64, 0};
99 }
100
DeInit()101 void DRMPanelFeatureMgr::DeInit() {
102 int ret = 0;
103 for (int i = 0; i < kDRMPanelFeatureMax; i++) {
104 DRMPanelFeatureID prop_id = static_cast<DRMPanelFeatureID>(i);
105 if (drm_prop_blob_ids_map_[prop_id]) {
106 ret = drmModeDestroyPropertyBlob(dev_fd_, drm_prop_blob_ids_map_[prop_id]);
107 if (ret) {
108 DRM_LOGE("failed to destroy blob for feature %d, ret = %d", prop_id, ret);
109 return;
110 } else {
111 drm_prop_blob_ids_map_[prop_id] = 0;
112 }
113 }
114 }
115 }
116
InitObjectProps(int obj_id,int obj_type)117 int DRMPanelFeatureMgr::InitObjectProps(int obj_id, int obj_type) {
118 if (dev_fd_ < 0 || obj_id < 0) {
119 DRM_LOGE("Invalid dev_fd_ %d or crtc_id %d", dev_fd_, obj_id);
120 return -EINVAL;
121 }
122
123 drmModeObjectProperties *props =
124 drmModeObjectGetProperties(dev_fd_, obj_id, obj_type);
125 if (!props || !props->props || !props->prop_values) {
126 DRM_LOGE("Failed to get props for obj_id:%d obj_type:%d", obj_id, obj_type);
127 drmModeFreeObjectProperties(props);
128 return -EINVAL;
129 }
130
131 for (uint32_t j = 0; j < props->count_props; j++) {
132 drmModePropertyRes *info = drmModeGetProperty(dev_fd_, props->props[j]);
133 if (!info) {
134 continue;
135 }
136
137 std::string property_name(info->name);
138 DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
139 if (prop_enum == DRMProperty::INVALID) {
140 DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
141 drmModeFreeProperty(info);
142 continue;
143 }
144
145 prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
146 drmModeFreeProperty(info);
147 }
148
149 drmModeFreeObjectProperties(props);
150 return 0;
151 }
152
ParseDsppCapabilities(uint32_t blob_id,std::vector<int> * values,uint32_t * size,const std::string str)153 void DRMPanelFeatureMgr::ParseDsppCapabilities(uint32_t blob_id, std::vector<int> *values,
154 uint32_t *size, const std::string str) {
155 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(dev_fd_, blob_id);
156 if (!blob) {
157 DRM_LOGW("Unable to find blob for id %d", blob_id);
158 return;
159 }
160
161 if (!blob->data) {
162 DRM_LOGW("Invalid blob - no data for for blob-id %d", blob_id);
163 return;
164 }
165
166 char *fmt_str = new char[blob->length + 1];
167 std::memcpy(fmt_str, blob->data, blob->length);
168 fmt_str[blob->length] = '\0';
169 std::stringstream stream(fmt_str);
170 std::string line = {};
171 // Search for panel feature property pattern. Which is defined as rc0=1, rc1=1
172 const std::regex exp(str + "(\\d+)=1");
173 std::smatch sm;
174 while (std::getline(stream, line)) {
175 std::regex_match(line, sm, exp);
176 // smatch shall include full line as a match followed by the hw block # as a match
177 if (sm.size() == 2) {
178 std::string tmpstr(sm[1]);
179 int temp = atoi(tmpstr.c_str()); // atoi safe to use due to regex success
180 values->push_back(temp);
181 }
182 }
183
184 *size = sizeof(int) * values->size();
185 delete[] fmt_str;
186 }
187
ParseCapabilities(uint32_t blob_id,char * value,uint32_t max_len,const std::string str)188 void DRMPanelFeatureMgr::ParseCapabilities(uint32_t blob_id, char* value, uint32_t max_len,
189 const std::string str) {
190 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(dev_fd_, blob_id);
191 if (!blob) {
192 DRM_LOGW("Unable to find blob for id %d", blob_id);
193 return;
194 }
195
196 if (!blob->data) {
197 DRM_LOGW("Invalid blob - no data for for blob-id %d", blob_id);
198 return;
199 }
200
201 char *fmt_str = new char[blob->length + 1];
202 std::memcpy(fmt_str, blob->data, blob->length);
203 fmt_str[blob->length] = '\0';
204 std::stringstream stream(fmt_str);
205 std::string line = {};
206 std::string val = {};
207 const std::string goal = str + "=";
208 while (std::getline(stream, line)) {
209 if (line.find(goal) != std::string::npos) {
210 val = std::string(line, goal.length());
211 }
212 }
213
214 if (max_len <= val.size()) {
215 DRM_LOGW("Insufficient size max_len: %d actual size: %zu", max_len, val.size());
216 return;
217 }
218 std::copy(val.begin(), val.end(), value);
219 value[val.size()] = '\0';
220 delete[] fmt_str;
221 }
222
GetPanelFeatureInfo(DRMPanelFeatureInfo * info)223 void DRMPanelFeatureMgr::GetPanelFeatureInfo(DRMPanelFeatureInfo *info) {
224 lock_guard<mutex> lock(lock_);
225
226 if (!info) {
227 DRM_LOGE("Invalid input, DRMPanelFeatureInfo is NULL");
228 return;
229 }
230
231 if (info->prop_id > kDRMPanelFeatureMax) {
232 DRM_LOGE("Invalid feature id %d", info->prop_id);
233 return;
234 }
235
236 DRMProperty prop_enum = drm_property_map_[info->prop_id];
237 if (!prop_mgr_.IsPropertyAvailable(prop_enum)) {
238 DRM_LOGE("Property id is not available for DRMProperty: %d feature-id: %d",
239 prop_enum, info->prop_id);
240 return;
241 }
242
243 // memory is not allocated by client - populate default property info
244 if (!info->prop_ptr) {
245 *info = feature_info_tbl_[info->prop_id];
246 return;
247 }
248
249 drmModeObjectProperties *props =
250 drmModeObjectGetProperties(dev_fd_, info->obj_id, info->obj_type);
251 if (!props || !props->props || !props->prop_values) {
252 drmModeFreeObjectProperties(props);
253 DRM_LOGE("Failed to Get properties for obj: %d type:%d", info->obj_id, info->obj_type);
254 return;
255 }
256
257 for (uint32_t j = 0; j < props->count_props; j++) {
258 drmModePropertyRes *property = drmModeGetProperty(dev_fd_, props->props[j]);
259 if (!property) {
260 continue;
261 }
262
263 std::string property_name(property->name);
264 if (prop_enum != prop_mgr_.GetPropertyEnum(property_name)) {
265 drmModeFreeProperty(property);
266 continue;
267 }
268 else if (info->prop_id == kDRMPanelFeatureDsppRCInfo) {
269 ParseDsppCapabilities(props->prop_values[j],
270 reinterpret_cast<std::vector<int> *> (info->prop_ptr), &(info->prop_size), "rc");
271 } else if (drm_prop_type_map_[info->prop_id] == DRMPropType::kPropBlob) {
272 drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(dev_fd_, props->prop_values[j]);
273 if (!blob || !blob->data || !blob->length) {
274 return;
275 }
276 uint8_t *src_begin = reinterpret_cast<uint8_t *> (blob->data);
277 uint8_t *src_end = src_begin + blob->length;
278 uint8_t *dst = reinterpret_cast<uint8_t *> (info->prop_ptr);
279 std::copy(src_begin, src_end, dst);
280 } else {
281 uint8_t *src_begin = reinterpret_cast<uint8_t *> (props->prop_values[j]);
282 uint8_t *src_end = src_begin + info->prop_size;
283 uint8_t *dst = reinterpret_cast<uint8_t *> (info->prop_ptr);
284 std::copy(src_begin, src_end, dst);
285 }
286
287 drmModeFreeProperty(property);
288 }
289
290 drmModeFreeObjectProperties(props);
291 }
292
CachePanelFeature(const DRMPanelFeatureInfo & info)293 void DRMPanelFeatureMgr::CachePanelFeature(const DRMPanelFeatureInfo &info) {
294 lock_guard<mutex> lock(lock_);
295
296 if (info.prop_id >= kDRMPanelFeatureMax || info.obj_id == UINT32_MAX) {
297 DRM_LOGE("invalid property info to set id %d value ptr %" PRIu64 , info.prop_id, info.prop_ptr);
298 return;
299 }
300
301 dirty_features_[info.prop_id].first = true;
302 dirty_features_[info.prop_id].second = info;
303 }
304
CommitPanelFeatures(drmModeAtomicReq * req,const DRMDisplayToken & tok)305 void DRMPanelFeatureMgr::CommitPanelFeatures(drmModeAtomicReq *req, const DRMDisplayToken &tok) {
306 int ret = 0;
307
308 lock_guard<mutex> lock(lock_);
309 for (auto it = dirty_features_.begin(); it != dirty_features_.end(); it++) {
310 DRMPanelFeatureInfo &info = it->second;
311
312 if (!it->first)
313 continue;
314
315 if (info.prop_id >= kDRMPanelFeatureMax) {
316 DRM_LOGE("invalid property info to set id %d value ptr %" PRIu64 , info.prop_id, info.prop_ptr);
317 continue;
318 }
319
320 // Commit only features meant for the given DisplayToken
321 if (tok.crtc_id != info.obj_id && tok.conn_id != info.obj_id) {
322 continue;
323 }
324
325 uint32_t prop_id = prop_mgr_.GetPropertyId(drm_property_map_[info.prop_id]);
326 uint64_t value = 0;
327
328 if (DRMPropType::kPropBlob == drm_prop_type_map_[info.prop_id]) {
329 uint32_t blob_id = 0;
330 if (!info.prop_ptr) {
331 // Reset the feature.
332 ret = drmModeAtomicAddProperty(req, info.obj_id, prop_id, 0);
333 if (ret < 0) {
334 DRM_LOGE("failed to add property ret:%d, obj_id:%d prop_id:%u value:%" PRIu64,
335 ret, info.obj_id, prop_id, value);
336 return;
337 }
338 continue;
339 }
340
341 ret = drmModeCreatePropertyBlob(dev_fd_, reinterpret_cast<void *> (info.prop_ptr),
342 info.prop_size, &blob_id);
343 if (ret || blob_id == 0) {
344 DRM_LOGE("failed to create blob ret %d, id = %d prop_ptr:%" PRIu64 " prop_sz:%d",
345 ret, blob_id, info.prop_ptr, info.prop_size);
346 return;
347 }
348
349 if (drm_prop_blob_ids_map_[info.prop_id]) {
350 ret = drmModeDestroyPropertyBlob(dev_fd_, drm_prop_blob_ids_map_[info.prop_id]);
351 if (ret) {
352 DRM_LOGE("failed to destroy blob for feature %d, ret = %d", info.prop_id, ret);
353 return;
354 }
355 }
356 drm_prop_blob_ids_map_[info.prop_id] = blob_id;
357
358 value = blob_id;
359 } else if (info.prop_size == sizeof(uint64_t)) {
360 value = (reinterpret_cast<uint64_t *> (info.prop_ptr))[0];
361 } else {
362 DRM_LOGE("Unsupported property type id = %d size:%d", info.prop_id, info.prop_size);
363 }
364
365 ret = drmModeAtomicAddProperty(req, info.obj_id, prop_id, value);
366 if (ret < 0) {
367 DRM_LOGE("failed to add property ret:%d, obj_id:%d prop_id:%x value:%" PRIu64,
368 ret, info.obj_id, prop_id, value);
369 }
370 *it = {};
371 }
372 }
373
374 } // namespace sde_drm
375
376