• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "ExynosDeviceDrmInterface.h"
18 
19 #include <drm/drm_mode.h>
20 #include <drm/samsung_drm.h>
21 #include <hardware/hwcomposer_defs.h>
22 
23 #include "ExynosDevice.h"
24 #include "ExynosDisplay.h"
25 #include "ExynosDisplayDrmInterface.h"
26 #include "ExynosExternalDisplayModule.h"
27 #include "ExynosHWCDebug.h"
28 #include "HistogramController.h"
29 
set_hwc_dpp_size_range(hwc_dpp_size_range & hwc_dpp_range,dpp_size_range & dpp_range)30 void set_hwc_dpp_size_range(hwc_dpp_size_range &hwc_dpp_range, dpp_size_range &dpp_range) {
31     hwc_dpp_range.min = dpp_range.min;
32     hwc_dpp_range.max = dpp_range.max;
33     hwc_dpp_range.align = dpp_range.align;
34 }
35 
set_dpp_ch_restriction(struct hwc_dpp_ch_restriction & hwc_dpp_restriction,struct dpp_ch_restriction & drm_restriction)36 static void set_dpp_ch_restriction(struct hwc_dpp_ch_restriction &hwc_dpp_restriction,
37                                    struct dpp_ch_restriction &drm_restriction) {
38     hwc_dpp_restriction.id = drm_restriction.id;
39     hwc_dpp_restriction.attr = drm_restriction.attr;
40     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.src_f_w, drm_restriction.restriction.src_f_w);
41     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.src_f_h, drm_restriction.restriction.src_f_h);
42     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.src_w, drm_restriction.restriction.src_w);
43     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.src_h, drm_restriction.restriction.src_h);
44     hwc_dpp_restriction.restriction.src_x_align = drm_restriction.restriction.src_x_align;
45     hwc_dpp_restriction.restriction.src_y_align = drm_restriction.restriction.src_y_align;
46     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.dst_f_w, drm_restriction.restriction.dst_f_w);
47     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.dst_f_h, drm_restriction.restriction.dst_f_h);
48     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.dst_w, drm_restriction.restriction.dst_w);
49     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.dst_h, drm_restriction.restriction.dst_h);
50     hwc_dpp_restriction.restriction.dst_x_align = drm_restriction.restriction.dst_x_align;
51     hwc_dpp_restriction.restriction.dst_y_align = drm_restriction.restriction.dst_y_align;
52     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.blk_w, drm_restriction.restriction.blk_w);
53     set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.blk_h, drm_restriction.restriction.blk_h);
54     hwc_dpp_restriction.restriction.blk_x_align = drm_restriction.restriction.blk_x_align;
55     hwc_dpp_restriction.restriction.blk_y_align = drm_restriction.restriction.blk_y_align;
56     hwc_dpp_restriction.restriction.src_h_rot_max = drm_restriction.restriction.src_h_rot_max;
57     hwc_dpp_restriction.restriction.scale_down = drm_restriction.restriction.scale_down;
58     hwc_dpp_restriction.restriction.scale_up = drm_restriction.restriction.scale_up;
59 
60     /* scale ratio can't be 0 */
61     if (hwc_dpp_restriction.restriction.scale_down == 0)
62         hwc_dpp_restriction.restriction.scale_down = 1;
63     if (hwc_dpp_restriction.restriction.scale_up == 0)
64         hwc_dpp_restriction.restriction.scale_up = 1;
65 }
66 
67 using namespace SOC_VERSION;
68 
ExynosDeviceDrmInterface(ExynosDevice * exynosDevice)69 ExynosDeviceDrmInterface::ExynosDeviceDrmInterface(ExynosDevice* exynosDevice)
70       : mExynosDrmEventHandler(std::make_shared<ExynosDrmEventHandler>()) {
71     if (!mExynosDrmEventHandler) ALOGE("mExynosDrmEventHandler failed to create!");
72     mType = INTERFACE_TYPE_DRM;
73 }
74 
~ExynosDeviceDrmInterface()75 ExynosDeviceDrmInterface::~ExynosDeviceDrmInterface() {
76     mDrmDevice->event_listener()->UnRegisterPropertyUpdateHandler(
77             std::static_pointer_cast<DrmPropertyUpdateHandler>(mExynosDrmEventHandler));
78     mDrmDevice->event_listener()->UnRegisterHotplugHandler(
79             std::static_pointer_cast<DrmEventHandler>(mExynosDrmEventHandler));
80     mDrmDevice->event_listener()->UnRegisterHistogramHandler(
81             std::static_pointer_cast<DrmHistogramEventHandler>(mExynosDrmEventHandler));
82     mDrmDevice->event_listener()->UnRegisterHistogramChannelHandler(
83             std::static_pointer_cast<DrmHistogramChannelEventHandler>(mExynosDrmEventHandler));
84     mDrmDevice->event_listener()->UnRegisterContextHistogramHandler(
85             std::static_pointer_cast<DrmContextHistogramEventHandler>(mExynosDrmEventHandler));
86     mDrmDevice->event_listener()->UnRegisterTUIHandler(
87             std::static_pointer_cast<DrmTUIEventHandler>(mExynosDrmEventHandler));
88     mDrmDevice->event_listener()->UnRegisterPanelIdleHandler(
89             std::static_pointer_cast<DrmPanelIdleEventHandler>(mExynosDrmEventHandler));
90 }
91 
init(ExynosDevice * exynosDevice)92 void ExynosDeviceDrmInterface::init(ExynosDevice *exynosDevice) {
93     mUseQuery = false;
94     mExynosDevice = exynosDevice;
95     mDrmResourceManager.Init();
96     mDrmDevice = mDrmResourceManager.GetDrmDevice(HWC_DISPLAY_PRIMARY);
97     assert(mDrmDevice != NULL);
98 
99     updateRestrictions();
100 
101     if (mExynosDrmEventHandler) {
102         mExynosDrmEventHandler->init(mExynosDevice, mDrmDevice);
103         mDrmDevice->event_listener()->RegisterHotplugHandler(
104                 std::static_pointer_cast<DrmEventHandler>(mExynosDrmEventHandler));
105         mDrmDevice->event_listener()->RegisterHistogramHandler(
106                 std::static_pointer_cast<DrmHistogramEventHandler>(mExynosDrmEventHandler));
107         mDrmDevice->event_listener()->RegisterHistogramChannelHandler(
108                 std::static_pointer_cast<DrmHistogramChannelEventHandler>(mExynosDrmEventHandler));
109         mDrmDevice->event_listener()->RegisterContextHistogramHandler(
110                 std::static_pointer_cast<DrmContextHistogramEventHandler>(mExynosDrmEventHandler));
111         mDrmDevice->event_listener()->RegisterTUIHandler(
112                 std::static_pointer_cast<DrmTUIEventHandler>(mExynosDrmEventHandler));
113         mDrmDevice->event_listener()->RegisterPanelIdleHandler(
114                 std::static_pointer_cast<DrmPanelIdleEventHandler>(mExynosDrmEventHandler));
115         mDrmDevice->event_listener()->RegisterPropertyUpdateHandler(
116                 std::static_pointer_cast<DrmPropertyUpdateHandler>(mExynosDrmEventHandler));
117     } else {
118         ALOGE("mExynosDrmEventHandler is not available!");
119     }
120 
121     if (mDrmDevice->event_listener()->IsDrmInTUI()) {
122         mExynosDevice->enterToTUI();
123         ALOGD("%s:: device is already in TUI", __func__);
124     }
125 }
126 
postInit()127 void ExynosDeviceDrmInterface::postInit() {
128     mDrmDevice->event_listener()->InitWorker();
129 }
130 
initDisplayInterface(std::unique_ptr<ExynosDisplayInterface> & dispInterface)131 int32_t ExynosDeviceDrmInterface::initDisplayInterface(
132         std::unique_ptr<ExynosDisplayInterface> &dispInterface) {
133     ExynosDisplayDrmInterface *displayInterface =
134         static_cast<ExynosDisplayDrmInterface*>(dispInterface.get());
135     return displayInterface->initDrmDevice(mDrmDevice);
136 }
137 
updateRestrictions()138 void ExynosDeviceDrmInterface::updateRestrictions() {
139     int32_t ret = 0;
140     uint32_t channelId = 0;
141 
142     for (auto &plane : mDrmDevice->planes()) {
143         struct hwc_dpp_ch_restriction hwc_res;
144 
145         /* Set size restriction information */
146         if (plane->hw_restrictions_property().id()) {
147             uint64_t blobId;
148 
149             std::tie(ret, blobId) = plane->hw_restrictions_property().value();
150             if (ret)
151                 break;
152 
153             struct dpp_ch_restriction *res;
154             drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(mDrmDevice->fd(), blobId);
155             if (!blob) {
156                 ALOGE("Fail to get blob for hw_restrictions(%" PRId64 ")", blobId);
157                 ret = HWC2_ERROR_UNSUPPORTED;
158                 break;
159             }
160             res = (struct dpp_ch_restriction *)blob->data;
161             set_dpp_ch_restriction(hwc_res, *res);
162             drmModeFreePropertyBlob(blob);
163         } else {
164             ALOGI("plane[%d] There is no hw restriction information", channelId);
165             ret = HWC2_ERROR_UNSUPPORTED;
166             break;
167         }
168 
169         /* Set supported format information */
170         for (auto format : plane->formats()) {
171             std::vector<uint32_t> halFormats;
172             if (drmFormatToHalFormats(format, &halFormats) != NO_ERROR) {
173                 ALOGE("Fail to convert drm format(%d)", format);
174                 continue;
175             }
176             for (auto halFormat : halFormats) {
177                 hwc_res.restriction.formats.push_back(halFormat);
178             }
179         }
180 
181         if (hwcCheckDebugMessages(eDebugDefault))
182             printDppRestriction(hwc_res);
183 
184         if (plane->isFormatSupported(DRM_FORMAT_C8) && plane->getNumFormatSupported() == 1)
185             mDPUInfo.dpuInfo.spp_chs.push_back(hwc_res);
186         else
187             mDPUInfo.dpuInfo.dpp_chs.push_back(hwc_res);
188 
189         channelId++;
190     }
191 
192     DrmCrtc *drmCrtc = mDrmDevice->GetCrtcForDisplay(0);
193     if (drmCrtc != nullptr) {
194         /*
195          * Run makeDPURestrictions() even if there is error
196          * in getting the value
197          */
198         if (drmCrtc->ppc_property().id()) {
199             auto [ret_ppc, value] = drmCrtc->ppc_property().value();
200             if (ret_ppc < 0) {
201                 ALOGE("Failed to get ppc property");
202             } else {
203                 mDPUInfo.dpuInfo.ppc = static_cast<uint32_t>(value);
204             }
205         }
206         if (drmCrtc->max_disp_freq_property().id()) {
207             auto [ret_max_freq, value] = drmCrtc->max_disp_freq_property().value();
208             if (ret_max_freq < 0) {
209                 ALOGE("Failed to get max_disp_freq property");
210             } else {
211                 mDPUInfo.dpuInfo.max_disp_freq = static_cast<uint32_t>(value);
212             }
213         }
214     } else {
215         ALOGE("%s:: Fail to get DrmCrtc", __func__);
216     }
217 
218     if (ret != NO_ERROR) {
219         ALOGI("Fail to get restriction (ret: %d)", ret);
220         mUseQuery = false;
221         return;
222     }
223 
224     if ((ret = makeDPURestrictions()) != NO_ERROR) {
225         ALOGE("makeDPURestrictions fail");
226     } else if ((ret = updateFeatureTable()) != NO_ERROR) {
227         ALOGE("updateFeatureTable fail");
228     }
229 
230     if (ret == NO_ERROR)
231         mUseQuery = true;
232     else {
233         ALOGI("There is no hw restriction information, use default values");
234         mUseQuery = false;
235     }
236 }
237 
init(ExynosDevice * exynosDevice,DrmDevice * drmDevice)238 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::init(ExynosDevice *exynosDevice,
239                                                            DrmDevice *drmDevice) {
240     mExynosDevice = exynosDevice;
241     mDrmDevice = drmDevice;
242 }
243 
handleEvent(uint64_t timestamp_us)244 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleEvent(uint64_t timestamp_us) {
245     mExynosDevice->handleHotplug();
246 }
247 
handleHistogramEvent(uint32_t crtc_id,void * bin)248 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramEvent(uint32_t crtc_id,
249                                                                            void *bin) {
250     ExynosDisplayDrmInterface *displayInterface;
251     DrmProperty crtc;
252     uint32_t id;
253 
254     for (auto display : mExynosDevice->mDisplays) {
255         displayInterface =
256                 static_cast<ExynosDisplayDrmInterface *>(display->mDisplayInterface.get());
257         id = displayInterface->getCrtcId();
258         if (id == crtc_id) {
259             displayInterface->setHistogramData(bin);
260         }
261     }
262 }
263 
264 #if defined(EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT)
handleHistogramChannelEvent(void * event)265 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramChannelEvent(void *event) {
266     struct exynos_drm_histogram_channel_event *histogram_channel_event =
267             (struct exynos_drm_histogram_channel_event *)event;
268 
269     for (auto display : mExynosDevice->mDisplays) {
270         ExynosDisplayDrmInterface *displayInterface =
271                 static_cast<ExynosDisplayDrmInterface *>(display->mDisplayInterface.get());
272         if (histogram_channel_event->crtc_id == displayInterface->getCrtcId()) {
273             if (display->mHistogramController) {
274                 display->mHistogramController->handleDrmEvent(histogram_channel_event);
275             } else {
276                 ALOGE("%s: no valid mHistogramController for crtc_id (%u)", __func__,
277                       histogram_channel_event->crtc_id);
278             }
279 
280             return;
281         }
282     }
283 
284     ALOGE("%s: no display with crtc_id (%u)", __func__, histogram_channel_event->crtc_id);
285 }
286 #else
handleHistogramChannelEvent(void * event)287 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramChannelEvent(void *event) {}
288 #endif
289 
290 #if defined(EXYNOS_DRM_CONTEXT_HISTOGRAM_EVENT)
handleContextHistogramEvent(void * event)291 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleContextHistogramEvent(void* event) {
292     struct exynos_drm_context_histogram_event* context_histogram_event =
293             (struct exynos_drm_context_histogram_event*)event;
294 
295     for (auto display : mExynosDevice->mDisplays) {
296         ExynosDisplayDrmInterface* displayInterface =
297                 static_cast<ExynosDisplayDrmInterface*>(display->mDisplayInterface.get());
298         if (context_histogram_event->crtc_id == displayInterface->getCrtcId()) {
299             if (display->mHistogramController) {
300                 display->mHistogramController->handleContextDrmEvent(context_histogram_event);
301             } else {
302                 ALOGE("%s: no valid mHistogramController for crtc_id (%u)", __func__,
303                       context_histogram_event->crtc_id);
304             }
305 
306             return;
307         }
308     }
309 
310     ALOGE("%s: no display with crtc_id (%u)", __func__, context_histogram_event->crtc_id);
311 }
312 #else
handleContextHistogramEvent(void * event)313 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleContextHistogramEvent(void* event) {}
314 #endif
315 
handleTUIEvent()316 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleTUIEvent() {
317     if (mDrmDevice->event_listener()->IsDrmInTUI()) {
318         /* Received TUI Enter event */
319         if (!mExynosDevice->isInTUI()) {
320             mExynosDevice->enterToTUI();
321             ALOGV("%s:: DRM device in TUI", __func__);
322         }
323     } else {
324         /* Received TUI Exit event */
325         if (mExynosDevice->isInTUI()) {
326             mExynosDevice->onRefreshDisplays();
327             mExynosDevice->exitFromTUI();
328             ALOGV("%s:: DRM device out TUI", __func__);
329         }
330     }
331 }
332 
333 constexpr size_t IDLE_ENTER_EVENT_DATA_SIZE = 3;
handleIdleEnterEvent(char const * event)334 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleIdleEnterEvent(char const *event) {
335     /* PANEL_IDLE_ENTER=<display index>,<vrefresh>,<idle te vrefresh> */
336     std::string_view idle_event_str(event);
337     auto prefix_shift_pos = idle_event_str.find("=");
338     if (prefix_shift_pos == std::string::npos) {
339         ALOGE("%s: idle enter event format is incorrect", __func__);
340     }
341 
342     int count = 0;
343     int value[IDLE_ENTER_EVENT_DATA_SIZE] = {0};
344     const auto &[displayIndex, vrefresh, idleTeVrefresh] = value;
345 
346     auto start_pos = prefix_shift_pos + 1;
347     auto end_pos = idle_event_str.find(",", start_pos);
348     while (end_pos != std::string::npos && count < IDLE_ENTER_EVENT_DATA_SIZE) {
349         auto info = idle_event_str.substr(start_pos, end_pos - start_pos);
350 
351         value[count++] = atoi(info.data());
352         start_pos = end_pos + 1;
353         end_pos = idle_event_str.find(",", start_pos);
354         if (end_pos == std::string::npos) {
355             info = idle_event_str.substr(start_pos, idle_event_str.size() - start_pos);
356             value[count++] = atoi(info.data());
357         }
358     }
359 
360     if (count != IDLE_ENTER_EVENT_DATA_SIZE) {
361         ALOGE("%s: idle enter event is incomplete", __func__);
362         return;
363     }
364 
365     ExynosDisplay *primaryDisplay =
366             mExynosDevice->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, displayIndex));
367     if (primaryDisplay) {
368         /* sending vsyncIdle callback */
369         if (vrefresh != idleTeVrefresh) {
370             mExynosDevice->onVsyncIdle(primaryDisplay->getId());
371         }
372 
373         primaryDisplay->handleDisplayIdleEnter(idleTeVrefresh);
374     }
375 }
376 
handleDrmPropertyUpdate(unsigned connector_id,unsigned prop_id)377 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleDrmPropertyUpdate(unsigned connector_id,
378                                                                               unsigned prop_id) {
379     ALOGD("%s: connector_id=%u prop_id=%u", __func__, connector_id, prop_id);
380     for (auto display : mExynosDevice->mDisplays) {
381         ExynosDisplayDrmInterface* displayInterface =
382                 static_cast<ExynosDisplayDrmInterface*>(display->mDisplayInterface.get());
383         if (displayInterface) displayInterface->handleDrmPropertyUpdate(connector_id, prop_id);
384     }
385 }
386 
registerSysfsEventHandler(std::shared_ptr<DrmSysfsEventHandler> handler)387 int32_t ExynosDeviceDrmInterface::registerSysfsEventHandler(
388         std::shared_ptr<DrmSysfsEventHandler> handler) {
389     return mDrmDevice->event_listener()->RegisterSysfsHandler(std::move(handler));
390 }
391 
unregisterSysfsEventHandler(int sysfsFd)392 int32_t ExynosDeviceDrmInterface::unregisterSysfsEventHandler(int sysfsFd) {
393     return mDrmDevice->event_listener()->UnRegisterSysfsHandler(sysfsFd);
394 }
395