• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2017-2019, 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 <core/buffer_allocator.h>
31 #include <utils/debug.h>
32 #include <sync/sync.h>
33 
34 #include "hwc_buffer_sync_handler.h"
35 #include "hwc_session.h"
36 
37 #define __CLASS__ "HWCSession"
38 
39 namespace sdm {
40 
41 using ::android::hardware::Void;
42 
StartServices()43 void HWCSession::StartServices() {
44   android::status_t status = IDisplayConfig::registerAsService();
45   if (status != android::OK) {
46     DLOGW("Could not register IDisplayConfig as service (%d).", status);
47   } else {
48     DLOGI("IDisplayConfig service registration completed.");
49   }
50 }
51 
MapDisplayType(IDisplayConfig::DisplayType dpy)52 int MapDisplayType(IDisplayConfig::DisplayType dpy) {
53   switch (dpy) {
54     case IDisplayConfig::DisplayType::DISPLAY_PRIMARY:
55       return HWC_DISPLAY_PRIMARY;
56 
57     case IDisplayConfig::DisplayType::DISPLAY_EXTERNAL:
58       return HWC_DISPLAY_EXTERNAL;
59 
60     case IDisplayConfig::DisplayType::DISPLAY_VIRTUAL:
61       return HWC_DISPLAY_VIRTUAL;
62 
63     default:
64       break;
65   }
66 
67   return -EINVAL;
68 }
69 
MapExternalStatus(IDisplayConfig::DisplayExternalStatus status)70 HWCDisplay::DisplayStatus MapExternalStatus(IDisplayConfig::DisplayExternalStatus status) {
71   switch (status) {
72     case IDisplayConfig::DisplayExternalStatus::EXTERNAL_OFFLINE:
73       return HWCDisplay::kDisplayStatusOffline;
74 
75     case IDisplayConfig::DisplayExternalStatus::EXTERNAL_ONLINE:
76       return HWCDisplay::kDisplayStatusOnline;
77 
78     case IDisplayConfig::DisplayExternalStatus::EXTERNAL_PAUSE:
79       return HWCDisplay::kDisplayStatusPause;
80 
81     case IDisplayConfig::DisplayExternalStatus::EXTERNAL_RESUME:
82       return HWCDisplay::kDisplayStatusResume;
83 
84     default:
85       break;
86   }
87 
88   return HWCDisplay::kDisplayStatusInvalid;
89 }
90 
91 // Methods from ::vendor::hardware::display::config::V1_0::IDisplayConfig follow.
isDisplayConnected(IDisplayConfig::DisplayType dpy,isDisplayConnected_cb _hidl_cb)92 Return<void> HWCSession::isDisplayConnected(IDisplayConfig::DisplayType dpy,
93                                             isDisplayConnected_cb _hidl_cb) {
94   int32_t error = -EINVAL;
95   bool connected = false;
96   int disp_id = MapDisplayType(dpy);
97 
98   if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
99     _hidl_cb(error, connected);
100     return Void();
101   }
102 
103   SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
104 
105   connected = hwc_display_[disp_id];
106   error = 0;
107 
108   _hidl_cb(error, connected);
109   return Void();
110 }
111 
SetSecondaryDisplayStatus(int disp_id,HWCDisplay::DisplayStatus status)112 int32_t HWCSession::SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status) {
113   if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
114     DLOGE("Invalid display = %d", disp_id);
115     return -EINVAL;
116   }
117 
118   SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
119   DLOGI("Display = %d, Status = %d", disp_id, status);
120 
121   if (disp_id == HWC_DISPLAY_PRIMARY) {
122     DLOGE("Not supported for this display");
123   } else if (!hwc_display_[disp_id]) {
124     DLOGW("Display is not connected");
125   } else {
126     return hwc_display_[disp_id]->SetDisplayStatus(status);
127   }
128 
129   return -EINVAL;
130 }
131 
setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,IDisplayConfig::DisplayExternalStatus status)132 Return<int32_t> HWCSession::setSecondayDisplayStatus(IDisplayConfig::DisplayType dpy,
133                                                   IDisplayConfig::DisplayExternalStatus status) {
134   return SetSecondaryDisplayStatus(MapDisplayType(dpy), MapExternalStatus(status));
135 }
136 
configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,uint32_t refreshRate)137 Return<int32_t> HWCSession::configureDynRefeshRate(IDisplayConfig::DisplayDynRefreshRateOp op,
138                                                    uint32_t refreshRate) {
139   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
140   HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
141 
142   switch (op) {
143     case IDisplayConfig::DisplayDynRefreshRateOp::DISABLE_METADATA_DYN_REFRESH_RATE:
144       return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, false);
145 
146     case IDisplayConfig::DisplayDynRefreshRateOp::ENABLE_METADATA_DYN_REFRESH_RATE:
147       return hwc_display->Perform(HWCDisplayPrimary::SET_METADATA_DYN_REFRESH_RATE, true);
148 
149     case IDisplayConfig::DisplayDynRefreshRateOp::SET_BINDER_DYN_REFRESH_RATE:
150       return hwc_display->Perform(HWCDisplayPrimary::SET_BINDER_DYN_REFRESH_RATE, refreshRate);
151 
152     default:
153       DLOGW("Invalid operation %d", op);
154       return -EINVAL;
155   }
156 
157   return 0;
158 }
159 
GetConfigCount(int disp_id,uint32_t * count)160 int32_t HWCSession::GetConfigCount(int disp_id, uint32_t *count) {
161   if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
162     DLOGE("Invalid display = %d", disp_id);
163     return -EINVAL;
164   }
165 
166   SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
167 
168   if (hwc_display_[disp_id]) {
169     return hwc_display_[disp_id]->GetDisplayConfigCount(count);
170   }
171 
172   return -EINVAL;
173 }
174 
getConfigCount(IDisplayConfig::DisplayType dpy,getConfigCount_cb _hidl_cb)175 Return<void> HWCSession::getConfigCount(IDisplayConfig::DisplayType dpy,
176                                         getConfigCount_cb _hidl_cb) {
177   uint32_t count = 0;
178   int32_t error = GetConfigCount(MapDisplayType(dpy), &count);
179 
180   _hidl_cb(error, count);
181 
182   return Void();
183 }
184 
GetActiveConfigIndex(int disp_id,uint32_t * config)185 int32_t HWCSession::GetActiveConfigIndex(int disp_id, uint32_t *config) {
186   if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
187     DLOGE("Invalid display = %d", disp_id);
188     return -EINVAL;
189   }
190 
191   SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
192 
193   if (hwc_display_[disp_id]) {
194     return hwc_display_[disp_id]->GetActiveDisplayConfig(config);
195   }
196 
197   return -EINVAL;
198 }
199 
getActiveConfig(IDisplayConfig::DisplayType dpy,getActiveConfig_cb _hidl_cb)200 Return<void> HWCSession::getActiveConfig(IDisplayConfig::DisplayType dpy,
201                                          getActiveConfig_cb _hidl_cb) {
202   uint32_t config = 0;
203   int32_t error = GetActiveConfigIndex(MapDisplayType(dpy), &config);
204 
205   _hidl_cb(error, config);
206 
207   return Void();
208 }
209 
SetActiveConfigIndex(int disp_id,uint32_t config)210 int32_t HWCSession::SetActiveConfigIndex(int disp_id, uint32_t config) {
211   if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
212     DLOGE("Invalid display = %d", disp_id);
213     return -EINVAL;
214   }
215 
216   SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
217   int32_t error = -EINVAL;
218   if (hwc_display_[disp_id]) {
219     error = hwc_display_[disp_id]->SetActiveDisplayConfig(config);
220     if (!error) {
221       Refresh(0);
222     }
223   }
224 
225   return error;
226 }
227 
setActiveConfig(IDisplayConfig::DisplayType dpy,uint32_t config)228 Return<int32_t> HWCSession::setActiveConfig(IDisplayConfig::DisplayType dpy, uint32_t config) {
229   return SetActiveConfigIndex(MapDisplayType(dpy), config);
230 }
231 
getDisplayAttributes(uint32_t configIndex,IDisplayConfig::DisplayType dpy,getDisplayAttributes_cb _hidl_cb)232 Return<void> HWCSession::getDisplayAttributes(uint32_t configIndex,
233                                               IDisplayConfig::DisplayType dpy,
234                                               getDisplayAttributes_cb _hidl_cb) {
235   int32_t error = -EINVAL;
236   IDisplayConfig::DisplayAttributes display_attributes = {};
237   int disp_id = MapDisplayType(dpy);
238 
239   if (disp_id >= HWC_DISPLAY_PRIMARY && disp_id < HWC_NUM_DISPLAY_TYPES) {
240     SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
241     if (hwc_display_[disp_id]) {
242       DisplayConfigVariableInfo hwc_display_attributes;
243       error = hwc_display_[disp_id]->GetDisplayAttributesForConfig(static_cast<int>(configIndex),
244                                                                    &hwc_display_attributes);
245       if (!error) {
246         display_attributes.vsyncPeriod = hwc_display_attributes.vsync_period_ns;
247         display_attributes.xRes = hwc_display_attributes.x_pixels;
248         display_attributes.yRes = hwc_display_attributes.y_pixels;
249         display_attributes.xDpi = hwc_display_attributes.x_dpi;
250         display_attributes.yDpi = hwc_display_attributes.y_dpi;
251         display_attributes.panelType = IDisplayConfig::DisplayPortType::DISPLAY_PORT_DEFAULT;
252         display_attributes.isYuv = hwc_display_attributes.is_yuv;
253       }
254     }
255   }
256   _hidl_cb(error, display_attributes);
257 
258   return Void();
259 }
260 
setPanelBrightness(uint32_t level)261 Return<int32_t> HWCSession::setPanelBrightness(uint32_t level) {
262   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
263   int32_t error = -EINVAL;
264 
265   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
266     error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPanelBrightness(static_cast<int>(level));
267     if (error) {
268       DLOGE("Failed to set the panel brightness = %d. Error = %d", level, error);
269     }
270   }
271 
272   return error;
273 }
274 
GetPanelBrightness(int * level)275 int32_t HWCSession::GetPanelBrightness(int *level) {
276   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
277   int32_t error = -EINVAL;
278 
279   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
280     error = hwc_display_[HWC_DISPLAY_PRIMARY]->GetPanelBrightness(level);
281     if (error) {
282       DLOGE("Failed to get the panel brightness. Error = %d", error);
283     }
284   }
285 
286   return error;
287 }
288 
getPanelBrightness(getPanelBrightness_cb _hidl_cb)289 Return<void> HWCSession::getPanelBrightness(getPanelBrightness_cb _hidl_cb) {
290   int level = 0;
291   int32_t error = GetPanelBrightness(&level);
292 
293   _hidl_cb(error, static_cast<uint32_t>(level));
294 
295   return Void();
296 }
297 
MinHdcpEncryptionLevelChanged(int disp_id,uint32_t min_enc_level)298 int32_t HWCSession::MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level) {
299   DLOGI("Display %d", disp_id);
300 
301   if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
302     DLOGE("Invalid display = %d", disp_id);
303     return -EINVAL;
304   }
305 
306   SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
307   if (disp_id != HWC_DISPLAY_EXTERNAL) {
308     DLOGE("Not supported for display");
309   } else if (!hwc_display_[disp_id]) {
310     DLOGW("Display is not connected");
311   } else {
312     return hwc_display_[disp_id]->OnMinHdcpEncryptionLevelChange(min_enc_level);
313   }
314 
315   return -EINVAL;
316 }
317 
minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,uint32_t min_enc_level)318 Return<int32_t> HWCSession::minHdcpEncryptionLevelChanged(IDisplayConfig::DisplayType dpy,
319                                                           uint32_t min_enc_level) {
320   return MinHdcpEncryptionLevelChanged(MapDisplayType(dpy), min_enc_level);
321 }
322 
refreshScreen()323 Return<int32_t> HWCSession::refreshScreen() {
324   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
325   Refresh(HWC_DISPLAY_PRIMARY);
326 
327   return 0;
328 }
329 
ControlPartialUpdate(int disp_id,bool enable)330 int32_t HWCSession::ControlPartialUpdate(int disp_id, bool enable) {
331   if (disp_id < HWC_DISPLAY_PRIMARY || disp_id >= HWC_NUM_DISPLAY_TYPES) {
332     DLOGE("Invalid display = %d", disp_id);
333     return -EINVAL;
334   }
335 
336   if (disp_id != HWC_DISPLAY_PRIMARY) {
337     DLOGW("CONTROL_PARTIAL_UPDATE is not applicable for display = %d", disp_id);
338     return -EINVAL;
339   }
340 
341   SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
342   HWCDisplay *hwc_display = hwc_display_[HWC_DISPLAY_PRIMARY];
343   if (!hwc_display) {
344     DLOGE("primary display object is not instantiated");
345     return -EINVAL;
346   }
347 
348   uint32_t pending = 0;
349   DisplayError hwc_error = hwc_display->ControlPartialUpdate(enable, &pending);
350 
351   if (hwc_error == kErrorNone) {
352     if (!pending) {
353       return 0;
354     }
355   } else if (hwc_error == kErrorNotSupported) {
356     return 0;
357   } else {
358     return -EINVAL;
359   }
360 
361   // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
362   Refresh(HWC_DISPLAY_PRIMARY);
363 
364   // Wait until partial update control is complete
365   int32_t error = locker_[disp_id].WaitFinite(kCommitDoneTimeoutMs);
366 
367   return error;
368 }
369 
controlPartialUpdate(IDisplayConfig::DisplayType dpy,bool enable)370 Return<int32_t> HWCSession::controlPartialUpdate(IDisplayConfig::DisplayType dpy, bool enable) {
371   return ControlPartialUpdate(MapDisplayType(dpy), enable);
372 }
373 
toggleScreenUpdate(bool on)374 Return<int32_t> HWCSession::toggleScreenUpdate(bool on) {
375   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
376 
377   int32_t error = -EINVAL;
378   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
379     error = hwc_display_[HWC_DISPLAY_PRIMARY]->ToggleScreenUpdates(on);
380     if (error) {
381       DLOGE("Failed to toggle screen updates = %d. Error = %d", on, error);
382     }
383   }
384 
385   return error;
386 }
387 
setIdleTimeout(uint32_t value)388 Return<int32_t> HWCSession::setIdleTimeout(uint32_t value) {
389   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
390 
391   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
392     hwc_display_[HWC_DISPLAY_PRIMARY]->SetIdleTimeoutMs(value);
393     return 0;
394   }
395 
396   DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
397   return -ENODEV;
398 }
399 
getHDRCapabilities(IDisplayConfig::DisplayType dpy,getHDRCapabilities_cb _hidl_cb)400 Return<void> HWCSession::getHDRCapabilities(IDisplayConfig::DisplayType dpy,
401                                             getHDRCapabilities_cb _hidl_cb) {
402   int32_t error = -EINVAL;
403   IDisplayConfig::DisplayHDRCapabilities hdr_caps = {};
404 
405   if (!_hidl_cb) {
406     DLOGE("_hidl_cb callback not provided.");
407     return Void();
408   }
409 
410   do {
411     int disp_id = MapDisplayType(dpy);
412     if ((disp_id < 0) || (disp_id >= HWC_NUM_DISPLAY_TYPES)) {
413       DLOGE("Invalid display id = %d", disp_id);
414       break;
415     }
416 
417     SEQUENCE_WAIT_SCOPE_LOCK(locker_[disp_id]);
418     HWCDisplay *hwc_display = hwc_display_[disp_id];
419     if (!hwc_display) {
420       DLOGW("Display = %d is not connected.", disp_id);
421       error = -ENODEV;
422       break;
423     }
424 
425     // query number of hdr types
426     uint32_t out_num_types = 0;
427     if (hwc_display->GetHdrCapabilities(&out_num_types, nullptr, nullptr, nullptr, nullptr)
428         != HWC2::Error::None) {
429       break;
430     }
431 
432     if (!out_num_types) {
433       error = 0;
434       break;
435     }
436 
437     // query hdr caps
438     hdr_caps.supportedHdrTypes.resize(out_num_types);
439 
440     float out_max_luminance = 0.0f;
441     float out_max_average_luminance = 0.0f;
442     float out_min_luminance = 0.0f;
443     if (hwc_display->GetHdrCapabilities(&out_num_types, hdr_caps.supportedHdrTypes.data(),
444                                         &out_max_luminance, &out_max_average_luminance,
445                                         &out_min_luminance)
446         == HWC2::Error::None) {
447       error = 0;
448     }
449   } while (false);
450 
451   _hidl_cb(error, hdr_caps);
452 
453   return Void();
454 }
455 
setCameraLaunchStatus(uint32_t on)456 Return<int32_t> HWCSession::setCameraLaunchStatus(uint32_t on) {
457   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
458 
459   if (!core_intf_) {
460     DLOGW("core_intf_ not initialized.");
461     return -ENOENT;
462   }
463 
464   if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
465     DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
466     return -ENODEV;
467   }
468 
469   HWBwModes mode = on > 0 ? kBwCamera : kBwDefault;
470 
471   // trigger invalidate to apply new bw caps.
472   Refresh(HWC_DISPLAY_PRIMARY);
473 
474   if (core_intf_->SetMaxBandwidthMode(mode) != kErrorNone) {
475     return -EINVAL;
476   }
477 
478   new_bw_mode_ = true;
479   need_invalidate_ = true;
480   hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
481 
482   return 0;
483 }
484 
DisplayBWTransactionPending(bool * status)485 int32_t HWCSession::DisplayBWTransactionPending(bool *status) {
486   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
487 
488   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
489     if (sync_wait(bw_mode_release_fd_, 0) < 0) {
490       DLOGI("bw_transaction_release_fd is not yet signaled: err= %s", strerror(errno));
491       *status = false;
492     }
493 
494     return 0;
495   }
496 
497   DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
498   return -ENODEV;
499 }
500 
displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb)501 Return<void> HWCSession::displayBWTransactionPending(displayBWTransactionPending_cb _hidl_cb) {
502   bool status = true;
503 
504   if (!_hidl_cb) {
505       DLOGE("_hidl_cb callback not provided.");
506       return Void();
507   }
508 
509   int32_t error = DisplayBWTransactionPending(&status);
510 
511   _hidl_cb(error, status);
512 
513   return Void();
514 }
515 #ifdef DISPLAY_CONFIG_1_1
516 // Methods from ::vendor::hardware::display::config::V1_1::IDisplayConfig follow.
setDisplayAnimating(uint64_t display_id,bool animating)517 Return<int32_t> HWCSession::setDisplayAnimating(uint64_t display_id, bool animating ) {
518   return CallDisplayFunction(static_cast<hwc2_device_t *>(this), display_id,
519                              &HWCDisplay::SetDisplayAnimating, animating);
520 }
521 #endif
522 
523 #ifdef DISPLAY_CONFIG_1_3
controlIdlePowerCollapse(bool enable,bool synchronous)524 Return<int32_t> HWCSession::controlIdlePowerCollapse(bool enable, bool synchronous) {
525   SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
526 
527   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
528     if (!enable) {
529       if (!idle_pc_ref_cnt_) {
530         HWC2::Error err =
531             hwc_display_[HWC_DISPLAY_PRIMARY]->ControlIdlePowerCollapse(enable, synchronous);
532         if (err == HWC2::Error::Unsupported) {
533           return 0;
534         }
535         Refresh(HWC_DISPLAY_PRIMARY);
536         int32_t error = locker_[HWC_DISPLAY_PRIMARY].WaitFinite(kCommitDoneTimeoutMs);
537         if (error == ETIMEDOUT) {
538           DLOGE("Timed out!! Next frame commit done event not received!!");
539           return error;
540         }
541         DLOGI("Idle PC disabled!!");
542       }
543       idle_pc_ref_cnt_++;
544     } else if (idle_pc_ref_cnt_ > 0) {
545       if (!(idle_pc_ref_cnt_ - 1)) {
546         HWC2::Error err =
547             hwc_display_[HWC_DISPLAY_PRIMARY]->ControlIdlePowerCollapse(enable, synchronous);
548         if (err == HWC2::Error::Unsupported) {
549           return 0;
550         }
551         DLOGI("Idle PC enabled!!");
552       }
553       idle_pc_ref_cnt_--;
554     }
555     return 0;
556   }
557 
558   DLOGW("Display = %d is not connected.", HWC_DISPLAY_PRIMARY);
559   return -ENODEV;
560 }
561 #endif  // DISPLAY_CONFIG_1_3
562 
563 }  // namespace sdm
564