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 <cstring>
31 #include <errno.h>
32 #include <drm_logger.h>
33 
34 #include "libdrm_macros.h"
35 #include "drm/drm_fourcc.h"
36 #include "drm_dpps_mgr_imp.h"
37 
38 #define __CLASS__ "DRMDppsManagerImp"
39 namespace sde_drm {
40 
41 static DRMDppsManagerImp dpps_mgr;
42 static DRMDppsManagerDummyImp dpps_dummy_mgr;
43 
GetDppsManagerIntf()44 DRMDppsManagerIntf* GetDppsManagerIntf()
45 {
46 #if (defined(__ANDROID__))
47     return &dpps_mgr;
48 #else
49     return &dpps_dummy_mgr;
50 #endif
51 }
52 
~DRMDppsManagerImp()53 DRMDppsManagerImp::~DRMDppsManagerImp() {
54   /* clean up the ION buffers for LTM */
55   DeInitLtmBuffers();
56 
57   conn_id_ = -1;
58   crtc_id_ = -1;
59   drm_fd_ = -1;
60 }
61 
GetDrmResources(drmModeRes * res)62 int DRMDppsManagerImp::GetDrmResources(drmModeRes* res) {
63   int enc_id = -1;
64   drmModeConnector *conn = NULL;
65   drmModeEncoder *enc = NULL;
66   drmModeCrtc *crtc = NULL;
67 
68   if (drm_fd_ < 0 ) {
69     DRM_LOGE("Invalid drm_fd_ %d", drm_fd_);
70     return -EINVAL;
71   }
72 
73   for (auto i = 0; i < res->count_connectors; i++) {
74     conn = drmModeGetConnector(drm_fd_, res->connectors[i]);
75     if (conn && conn->connector_type == DRM_MODE_CONNECTOR_DSI &&
76         conn->count_modes && conn->connection == DRM_MODE_CONNECTED) {
77       DRM_LOGI("Found connector %d", conn->connector_id);
78       conn_id_ = conn->connector_id;
79       break;
80     }
81     drmModeFreeConnector(conn);
82     conn = NULL;
83   }
84   if (conn_id_ < 0 || !conn) {
85     DRM_LOGE("Cannot find valid connector");
86     conn_id_ = -1;
87     return -EINVAL;
88   }
89 
90   for (auto i = 0; i < conn->count_encoders; i++) {
91     enc = drmModeGetEncoder(drm_fd_, conn->encoders[i]);
92     if (enc && enc->encoder_type == DRM_MODE_ENCODER_DSI) {
93       DRM_LOGI("Found encoder %d", enc->encoder_id);
94       enc_id = enc->encoder_id;
95       break;
96     }
97     drmModeFreeEncoder(enc);
98     enc = NULL;
99   }
100   if (enc_id < 0 || !enc) {
101     DRM_LOGE("Cannot find valid encoder");
102     drmModeFreeConnector(conn);
103     conn = NULL;
104     res = NULL;
105     conn_id_ = -1;
106     return -EINVAL;
107   }
108 
109   for (auto i = 0; i < res->count_crtcs; i++) {
110     if (enc->possible_crtcs & (1 << i)) {
111       crtc = drmModeGetCrtc(drm_fd_, res->crtcs[i]);
112       if (crtc) {
113         DRM_LOGI("Found crtc %d", crtc->crtc_id);
114         crtc_id_ = crtc->crtc_id;
115         break;
116       }
117       drmModeFreeCrtc(crtc);
118       crtc = NULL;
119     }
120   }
121   if (crtc_id_ < 0 || !crtc) {
122     DRM_LOGE("Cannot find valid crtc");
123     drmModeFreeEncoder(enc);
124     drmModeFreeConnector(conn);
125     enc = NULL;
126     conn = NULL;
127     conn_id_ = -1;
128     crtc_id_ = -1;
129     return -EINVAL;
130   }
131   return 0;
132 }
133 
InitCrtcProps()134 int DRMDppsManagerImp::InitCrtcProps() {
135   if (drm_fd_ < 0 || crtc_id_ < 0) {
136     DRM_LOGE("Invalid drm_fd_ %d or crtc_id_ %d", drm_fd_, crtc_id_);
137     return -EINVAL;
138   }
139 
140   drmModeObjectProperties *props =
141     drmModeObjectGetProperties(drm_fd_, crtc_id_, DRM_MODE_OBJECT_CRTC);
142   if (!props || !props->props || !props->prop_values) {
143     drmModeFreeObjectProperties(props);
144     return -EINVAL;
145   }
146 
147   for (uint32_t j = 0; j < props->count_props; j++) {
148     drmModePropertyRes *info = drmModeGetProperty(drm_fd_, props->props[j]);
149     if (!info) {
150       continue;
151     }
152 
153     std::string property_name(info->name);
154     DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
155     if (prop_enum == DRMProperty::INVALID) {
156       DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
157       drmModeFreeProperty(info);
158       continue;
159     }
160 
161     prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
162     drmModeFreeProperty(info);
163   }
164 
165   drmModeFreeObjectProperties(props);
166   return 0;
167 }
168 
InitConnProps()169 int DRMDppsManagerImp::InitConnProps()
170 {
171   if (drm_fd_ < 0 || conn_id_ < 0) {
172     DRM_LOGE("Invalid drm_fd_ %d or conn_id_ %d", drm_fd_, conn_id_);
173     return -EINVAL;
174   }
175 
176   drmModeObjectProperties *props =
177       drmModeObjectGetProperties(drm_fd_, conn_id_, DRM_MODE_OBJECT_CONNECTOR);
178   if (!props || !props->props || !props->prop_values) {
179     drmModeFreeObjectProperties(props);
180     return -EINVAL;
181   }
182 
183   for (uint32_t j = 0; j < props->count_props; j++) {
184     drmModePropertyRes *info = drmModeGetProperty(drm_fd_, props->props[j]);
185     if (!info) {
186       continue;
187     }
188 
189     std::string property_name(info->name);
190     DRMProperty prop_enum = prop_mgr_.GetPropertyEnum(property_name);
191     if (prop_enum == DRMProperty::INVALID) {
192       DRM_LOGD("DRMProperty %s missing from global property mapping", info->name);
193       drmModeFreeProperty(info);
194       continue;
195     }
196 
197     prop_mgr_.SetPropertyId(prop_enum, info->prop_id);
198     drmModeFreeProperty(info);
199   }
200 
201   drmModeFreeObjectProperties(props);
202   return 0;
203 }
204 
Init(int fd,drmModeRes * res)205 void DRMDppsManagerImp::Init(int fd, drmModeRes* res) {
206   std::lock_guard<std::mutex> guard(api_lock_);
207   int ret = 0;
208 
209   if (fd < 0 || !res) {
210     DRM_LOGE("Invalid drm fd %d or res %p", fd, res);
211     return;
212   }
213 
214   drm_fd_ = fd;
215   ret = GetDrmResources(res);
216   if (ret) {
217     DRM_LOGE("Failed to get DRM resources %d", ret);
218     return;
219   } else {
220     ret = InitCrtcProps();
221     if (ret) {
222       DRM_LOGE("Failed to initialize crtc properties %d", ret);
223       return;
224     }
225     ret = InitConnProps();
226     if (ret) {
227       DRM_LOGE("Failed to initialize conn properties %d", ret);
228       return;
229     }
230   }
231 
232   memset(&dpps_feature_, 0, sizeof(dpps_feature_));
233   dpps_feature_[kFeatureAd4Mode] = DRMDppsPropInfo {
234     (prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_MODE) == 0 ? 0U : 4U) /* version */,
235     DRMProperty::SDE_DSPP_AD4_MODE, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_MODE),
236     false /* is_event */};
237   dpps_feature_[kFeatureAd4Init] = DRMDppsPropInfo {4 /* version */,
238     DRMProperty::SDE_DSPP_AD4_INIT, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_INIT),
239     false /* is_event */};
240   dpps_feature_[kFeatureAd4Cfg] = DRMDppsPropInfo { 4 /* version */,
241     DRMProperty::SDE_DSPP_AD4_CFG, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_CFG),
242     false /* is_event */};
243   dpps_feature_[kFeatureAd4Input] = DRMDppsPropInfo {4 /* version */,
244     DRMProperty::SDE_DSPP_AD4_INPUT, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_INPUT),
245     false /* is_event */};
246   dpps_feature_[kFeatureAd4Backlight] = DRMDppsPropInfo {4 /* version */,
247     DRMProperty::SDE_DSPP_AD4_BACKLIGHT, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_BACKLIGHT),
248     false /* is_event */};
249   dpps_feature_[kFeatureAd4Assertiveness] = DRMDppsPropInfo {4 /* version */,
250     DRMProperty::SDE_DSPP_AD4_ASSERTIVENESS, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_ASSERTIVENESS),
251     false /* is_event */};
252   dpps_feature_[kFeatureAd4Roi] = DRMDppsPropInfo {4 /* version */,
253     DRMProperty::SDE_DSPP_AD4_ROI, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_ROI),
254     false /* is_event */};
255   dpps_feature_[kFeatureAd4ManualStrength] = DRMDppsPropInfo {4 /* version */,
256     DRMProperty::SDE_DSPP_AD4_STRENGTH, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_AD4_STRENGTH),
257     false /* is_event */};
258   dpps_feature_[kFeatureAbaHistCtrl] = DRMDppsPropInfo {1 /* version */,
259     DRMProperty::SDE_DSPP_ABA_HIST_CTRL, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_ABA_HIST_CTRL),
260     false /* is_event */};
261   dpps_feature_[kFeatureAbaHistIRQ] = DRMDppsPropInfo {1 /* version */,
262     DRMProperty::SDE_DSPP_ABA_HIST_IRQ, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_ABA_HIST_IRQ),
263     false /* is_event */};
264   dpps_feature_[kFeatureAbaLut] = DRMDppsPropInfo {1 /* version */,
265     DRMProperty::SDE_DSPP_ABA_LUT, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_ABA_LUT),
266     false /* is_event */};
267   dpps_feature_[kFeatureSvBlScale] = DRMDppsPropInfo {1 /* version */,
268     DRMProperty::SDE_DSPP_SV_BL_SCALE, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_SV_BL_SCALE),
269     false /* is_event */};
270   dpps_feature_[kFeatureBacklightScale] = DRMDppsPropInfo {1 /* version */,
271     DRMProperty::SDE_DSPP_BL_SCALE, prop_mgr_.GetPropertyId(DRMProperty::SDE_DSPP_BL_SCALE),
272     false /* is_event */};
273 
274   if (prop_mgr_.IsPropertyAvailable(DRMProperty::SDE_LTM_VERSION)) {
275     dpps_feature_[kFeatureLtm] = DRMDppsPropInfo {1 /* version */,
276       DRMProperty::SDE_LTM_VERSION, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_VERSION),
277       false /* is_event */};
278     dpps_feature_[kFeatureLtmInit] = DRMDppsPropInfo {1 /* version */,
279       DRMProperty::SDE_LTM_INIT, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_INIT),
280       false /* is_event */};
281     dpps_feature_[kFeatureLtmCfg] = DRMDppsPropInfo {1 /* version */,
282       DRMProperty::SDE_LTM_CFG, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_CFG),
283       false /* is_event */};
284     dpps_feature_[kFeatureLtmNoiseThresh] = DRMDppsPropInfo {1 /* version */,
285       DRMProperty::SDE_LTM_NOISE_THRESH, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_NOISE_THRESH),
286       false /* is_event */};
287     dpps_feature_[kFeatureLtmBufferCtrl] = DRMDppsPropInfo {1 /* version */,
288       DRMProperty::SDE_LTM_BUFFER_CTRL, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_BUFFER_CTRL),
289       false /* is_event */};
290     dpps_feature_[kFeatureLtmQueueBuffer] = DRMDppsPropInfo {1 /* version */,
291       DRMProperty::SDE_LTM_QUEUE_BUFFER, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_QUEUE_BUFFER),
292       false /* is_event */};
293     dpps_feature_[kFeatureLtmQueueBuffer2] = DRMDppsPropInfo {1 /* version */,
294       DRMProperty::SDE_LTM_QUEUE_BUFFER2, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_QUEUE_BUFFER2),
295       false /* is_event */};
296     dpps_feature_[kFeatureLtmQueueBuffer3] = DRMDppsPropInfo {1 /* version */,
297       DRMProperty::SDE_LTM_QUEUE_BUFFER3, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_QUEUE_BUFFER3),
298       false /* is_event */};
299     dpps_feature_[kFeatureLtmHistCtrl] = DRMDppsPropInfo {1 /* version */,
300       DRMProperty::SDE_LTM_HIST_CTRL, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_HIST_CTRL),
301       false /* is_event */};
302     dpps_feature_[kFeatureLtmVlut] = DRMDppsPropInfo {1 /* version */,
303       DRMProperty::SDE_LTM_VLUT, prop_mgr_.GetPropertyId(DRMProperty::SDE_LTM_VLUT),
304       false /* is_event */};
305   } else {
306     DRM_LOGI("LTM properties are not available");
307   }
308 
309   dpps_feature_[kFeaturePowerEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
310   dpps_feature_[kFeatureAbaHistEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
311   dpps_feature_[kFeatureBackLightEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
312   dpps_feature_[kFeatureAdAttBlEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
313   dpps_feature_[kFeatureLtmHistEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
314   dpps_feature_[kFeatureLtmWbPbEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
315   dpps_feature_[kFeatureLtmOffEvent] = DRMDppsPropInfo{1, DRMProperty::INVALID, 0, true /* is_event */};
316 }
317 
CacheDppsFeature(uint32_t obj_id,va_list args)318 void DRMDppsManagerImp::CacheDppsFeature(uint32_t obj_id, va_list args) {
319   std::lock_guard<std::mutex> guard(api_lock_);
320   uint32_t feature_id = va_arg(args, uint32_t);
321   uint64_t value = va_arg(args, uint64_t);
322   struct DRMDppsPropInfo* info;
323 
324   if (feature_id >= kDppsFeaturesMax) {
325     DRM_LOGE("Invalid feature id %d for obj_id 0x%x", feature_id, obj_id);
326     return;
327   }
328 
329   info = &dpps_feature_[feature_id];
330   info->obj_id = obj_id;
331   info->value = value;
332   if (info->is_event) {
333     dpps_dirty_event_.push_back(*info);
334   } else {
335     for (auto &it : dpps_dirty_prop_) {
336       if ((it.obj_id == info->obj_id) && (it.prop_id == info->prop_id)) {
337         it.value = info->value;
338         return;
339       }
340     }
341     dpps_dirty_prop_.push_back(*info);
342   }
343 }
344 
CommitDppsFeatures(drmModeAtomicReq * req,const DRMDisplayToken & tok)345 void DRMDppsManagerImp::CommitDppsFeatures(drmModeAtomicReq *req, const DRMDisplayToken &tok) {
346   std::lock_guard<std::mutex> guard(api_lock_);
347   int ret = 0;
348 
349   if (!req)
350     return;
351 
352   // Set Dpps properties
353   if (!dpps_dirty_prop_.empty()) {
354     for (auto it = dpps_dirty_prop_.begin(); it != dpps_dirty_prop_.end();) {
355       if (it->obj_id == tok.crtc_id || it->obj_id == tok.conn_id) {
356         ret = drmModeAtomicAddProperty(req, it->obj_id, it->prop_id, it->value);
357         if (ret < 0)
358           DRM_LOGE("AtomicAddProperty failed obj_id 0x%x, prop_id %d ret %d ", it->obj_id,
359                    it->prop_id, ret);
360         else
361           it = dpps_dirty_prop_.erase(it);
362       } else {
363         it++;
364       }
365     }
366   }
367 
368   // Set Dpps events
369   if (!dpps_dirty_event_.empty()) {
370     for (auto it = dpps_dirty_event_.begin(); it != dpps_dirty_event_.end();) {
371       if (!it->value)
372         continue;
373 
374       struct DRMDppsEventInfo info = *(struct DRMDppsEventInfo*)it->value;
375       struct drm_msm_event_req event_req = {};
376       int ret;
377       if (it->obj_id == tok.crtc_id || it->obj_id == tok.conn_id) {
378         event_req.object_id = it->obj_id;
379         event_req.object_type = info.object_type;
380         event_req.event = info.event_type;
381         if (info.enable)
382           ret = drmIoctl(info.drm_fd, DRM_IOCTL_MSM_REGISTER_EVENT, &event_req);
383         else
384           ret = drmIoctl(info.drm_fd, DRM_IOCTL_MSM_DEREGISTER_EVENT, &event_req);
385         if (ret) {
386           ret = -errno;
387           if (ret == -EALREADY) {
388             DRM_LOGI("Duplicated request to set event 0x%x, object_id %u, object_type 0x%x, enable %d",
389                       event_req.event, event_req.object_id, info.object_type, info.enable);
390           } else {
391             DRM_LOGE("Failed to set event 0x%x, object_id %u, object_type 0x%x, enable %d, ret %d",
392                       event_req.event, event_req.object_id, info.object_type, info.enable, ret);
393           }
394         }
395         if (ret != -ENODEV)
396           it = dpps_dirty_event_.erase(it);
397         else
398           it++;
399       } else {
400         it++;
401       }
402     }
403   }
404 }
405 
GetDppsFeatureInfo(DRMDppsFeatureInfo * info)406 void DRMDppsManagerImp::GetDppsFeatureInfo(DRMDppsFeatureInfo *info)
407 {
408   std::lock_guard<std::mutex> guard(api_lock_);
409   int ret = 0;
410   struct DRMDppsPropInfo* prop_info;
411 
412   if (!info) {
413     DRM_LOGE("Invalid info NULL");
414     return;
415   }
416 
417   DRMDPPSFeatureID id = info->id;
418   if (id >= kDppsFeaturesMax) {
419     DRM_LOGE("Invalid feature id %d", id);
420     return;
421   }
422   info->version = dpps_feature_[id].version;
423 
424   if ((id == kFeatureLtmBufferCtrl) && (dpps_feature_[kFeatureLtm].prop_id != 0)) {
425     /* setup ION buffers for LTM */
426     ret = InitLtmBuffers(info);
427     if (ret) {
428       DRM_LOGE("Failed to init LTM buffers %d", ret);
429       return;
430     } else {
431       prop_info = &dpps_feature_[kFeatureLtmBufferCtrl];
432       prop_info->obj_id = info->obj_id;
433       for (const auto& it : ltm_buffers_ctrl_map_) {
434         if (it.first == info->obj_id)
435           prop_info->value = (uint64_t)&(it.second);
436       }
437       dpps_dirty_prop_.push_back(*prop_info);
438     }
439   }
440 }
441 
InitLtmBuffers(struct DRMDppsFeatureInfo * info)442 int DRMDppsManagerImp::InitLtmBuffers(struct DRMDppsFeatureInfo *info) {
443   int ret = 0;
444   uint32_t buffer_size, i = 0, bpp = 0;
445   void* uva;
446   struct DRMDppsLtmBuffers *buffers;
447   DRMDppsLtmBuffers ltm_buffers = {};
448   drm_msm_ltm_buffers_ctrl ltm_buffers_ctrl = {};
449   struct drm_prime_handle prime_req;
450   struct drm_mode_fb_cmd2 fb_obj;
451   struct drm_gem_close gem_close;
452 
453   if (drm_fd_ < 0) {
454     DRM_LOGE("Invalid drm_fd_ %d", drm_fd_);
455     return -EINVAL;
456   }
457 
458   for (const auto& it : ltm_buffers_map_) {
459     if (it.first == info->obj_id) {
460       DRM_LOGE("LTM buffer already initialized, obj id %d", info->obj_id);
461       return -EALREADY;
462     }
463   }
464 
465   if (!info->payload || info->payload_size != sizeof(struct DRMDppsLtmBuffers)) {
466     DRM_LOGE("Invalid payload %p size %d expected %zu", info->payload, info->payload_size,
467        sizeof(struct DRMDppsLtmBuffers));
468     return -EINVAL;
469   }
470 
471   buffers = (struct DRMDppsLtmBuffers *)info->payload;
472   if (buffers->num_of_buffers <= 0 || buffers->num_of_buffers > LTM_BUFFER_SIZE) {
473     DRM_LOGE("Invalid number of buffers %d", buffers->num_of_buffers);
474     return -EINVAL;
475   }
476 
477   std::memset(&ltm_buffers, 0, sizeof(ltm_buffers));
478   std::memset(&ltm_buffers_ctrl, 0, sizeof(ltm_buffers_ctrl));
479 
480   ltm_buffers.num_of_buffers = buffers->num_of_buffers;
481 
482   buffer_size = sizeof(struct drm_msm_ltm_stats_data) + LTM_GUARD_BYTES;
483   std::memset(&fb_obj, 0, sizeof(drm_mode_fb_cmd2));
484   fb_obj.pixel_format = DRM_FORMAT_YVYU;
485   /* YVYU gives us a bpp of 16 (2 bytes) so we must take that into account */
486   fb_obj.height = 2;
487   /* add extra one to compensate integer rounding */
488   fb_obj.width = buffer_size / (2 * fb_obj.height) + 1;
489   /* bpp for YVYU is 16 */
490   bpp = 16;
491   fb_obj.flags = DRM_MODE_FB_MODIFIERS;
492   fb_obj.pitches[0] = fb_obj.width * bpp / 8;
493 
494   for (i = 0; i < buffers->num_of_buffers && !ret; i++) {
495     std::memset(&prime_req, 0, sizeof(drm_prime_handle));
496     prime_req.fd = buffers->ion_buffer_fd[i];
497     ret = drmIoctl(drm_fd_, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_req);
498     if (ret) {
499       ret = -errno;
500       DRM_LOGE("failed get prime handle: %d", ret);
501       break;
502     }
503     ltm_buffers.ion_buffer_fd[i] = buffers->ion_buffer_fd[i];
504 
505     fb_obj.handles[0] = prime_req.handle;
506     ret = drmIoctl(drm_fd_, DRM_IOCTL_MODE_ADDFB2, &fb_obj);
507     if (ret) {
508       ret = -errno;
509       DRM_LOGE("return value from addFB2: %d", ret);
510       break;
511     }
512     ltm_buffers.drm_fb_id[i] = buffers->drm_fb_id[i] = fb_obj.fb_id;
513     ltm_buffers_ctrl.fds[i] = ltm_buffers.drm_fb_id[i];
514 
515     /**
516      * ADDFB2 will take reference to GEM handles,
517      * so drop reference taken by PrimeFDtoHandle now
518      */
519     std::memset(&gem_close, 0, sizeof(gem_close));
520     gem_close.handle = prime_req.handle;
521     ret = drmIoctl(drm_fd_, DRM_IOCTL_GEM_CLOSE, &gem_close);
522     if(ret) {
523       ret = -errno;
524       DRM_LOGE("return value from GEM_CLOSE: %d\n", ret);
525       break;
526     }
527 
528     uva = drm_mmap(0, buffers->buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED,
529                    buffers->ion_buffer_fd[i], 0);
530     if (uva == MAP_FAILED) {
531       ret = -errno;
532       DRM_LOGE("failed to get uva: %d", ret);
533       break;
534     }
535     ltm_buffers.uva[i] = buffers->uva[i] = uva;
536   }
537 
538   if (!ret) {
539     buffers->status = 0;
540     ltm_buffers.buffer_size = buffers->buffer_size;
541     ltm_buffers_ctrl.num_of_buffers = ltm_buffers.num_of_buffers;
542     DRM_LOGV("InitLtmBuffers return successful");
543   } else {
544     DeInitLtmBuffers();
545     buffers->status = ret;
546     return ret;
547   }
548 
549   ltm_buffers_map_.push_back(std::make_pair(info->obj_id, std::move(ltm_buffers)));
550   ltm_buffers_ctrl_map_.push_back(std::make_pair(info->obj_id, std::move(ltm_buffers_ctrl)));
551   return ret;
552 }
553 
DeInitLtmBuffers()554 int DRMDppsManagerImp::DeInitLtmBuffers() {
555   int ret = 0;
556   uint32_t i = 0;
557 
558   if (drm_fd_ < 0) {
559     return -EINVAL;
560   }
561 
562   for (auto& it : ltm_buffers_map_) {
563     DRMDppsLtmBuffers& ltm_buffers = it.second;
564     for (i = 0; i < ltm_buffers.num_of_buffers; i++) {
565       if (ltm_buffers.uva[i]) {
566         drm_munmap(ltm_buffers.uva[i], ltm_buffers.buffer_size);
567         ltm_buffers.uva[i] = NULL;
568       }
569 
570       if (ltm_buffers.drm_fb_id[i] >= 0) {
571 #ifdef DRM_IOCTL_MSM_RMFB2
572         ret = drmIoctl(drm_fd_, DRM_IOCTL_MSM_RMFB2, &ltm_buffers.drm_fb_id[i]);
573         if (ret) {
574           ret = errno;
575           DRM_LOGE("RMFB2 failed for fb_id %d with error %d", ltm_buffers.drm_fb_id[i], ret);
576         }
577 #endif
578         ltm_buffers.drm_fb_id[i] = -1;
579       }
580       ltm_buffers.ion_buffer_fd[i] = -1;
581     }
582 
583     ltm_buffers.num_of_buffers = 0;
584     ltm_buffers.buffer_size = 0;
585   }
586 
587   for (auto& it : ltm_buffers_ctrl_map_) {
588     drm_msm_ltm_buffers_ctrl& ltm_buffers_ctrl = it.second;
589     std::memset(&ltm_buffers_ctrl, 0, sizeof(ltm_buffers_ctrl));
590   }
591 
592   ltm_buffers_map_.clear();
593   ltm_buffers_ctrl_map_.clear();
594   return 0;
595 }
596 
597 }  // namespace sde_drm
598