• 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     mType = INTERFACE_TYPE_DRM;
71 }
72 
~ExynosDeviceDrmInterface()73 ExynosDeviceDrmInterface::~ExynosDeviceDrmInterface() {
74     mDrmDevice->event_listener()->UnRegisterHotplugHandler(
75             static_cast<DrmEventHandler *>(&mExynosDrmEventHandler));
76     mDrmDevice->event_listener()->UnRegisterHistogramHandler(
77             static_cast<DrmHistogramEventHandler *>(&mExynosDrmEventHandler));
78     mDrmDevice->event_listener()->UnRegisterHistogramChannelHandler(
79             static_cast<DrmHistogramChannelEventHandler *>(&mExynosDrmEventHandler));
80     mDrmDevice->event_listener()->UnRegisterTUIHandler(
81             static_cast<DrmTUIEventHandler *>(&mExynosDrmEventHandler));
82     mDrmDevice->event_listener()->UnRegisterPanelIdleHandler(
83             static_cast<DrmPanelIdleEventHandler *>(&mExynosDrmEventHandler));
84 }
85 
init(ExynosDevice * exynosDevice)86 void ExynosDeviceDrmInterface::init(ExynosDevice *exynosDevice) {
87     mUseQuery = false;
88     mExynosDevice = exynosDevice;
89     mDrmResourceManager.Init();
90     mDrmDevice = mDrmResourceManager.GetDrmDevice(HWC_DISPLAY_PRIMARY);
91     assert(mDrmDevice != NULL);
92 
93     updateRestrictions();
94 
95     mExynosDrmEventHandler.init(mExynosDevice, mDrmDevice);
96     mDrmDevice->event_listener()->RegisterHotplugHandler(
97             static_cast<DrmEventHandler *>(&mExynosDrmEventHandler));
98     mDrmDevice->event_listener()->RegisterHistogramHandler(
99             static_cast<DrmHistogramEventHandler *>(&mExynosDrmEventHandler));
100     mDrmDevice->event_listener()->RegisterHistogramChannelHandler(
101             static_cast<DrmHistogramChannelEventHandler *>(&mExynosDrmEventHandler));
102     mDrmDevice->event_listener()->RegisterTUIHandler(
103             static_cast<DrmTUIEventHandler *>(&mExynosDrmEventHandler));
104     mDrmDevice->event_listener()->RegisterPanelIdleHandler(
105             static_cast<DrmPanelIdleEventHandler *>(&mExynosDrmEventHandler));
106 
107     if (mDrmDevice->event_listener()->IsDrmInTUI()) {
108         mExynosDevice->enterToTUI();
109         ALOGD("%s:: device is already in TUI", __func__);
110     }
111 }
112 
postInit()113 void ExynosDeviceDrmInterface::postInit() {
114     mDrmDevice->event_listener()->InitWorker();
115 }
116 
initDisplayInterface(std::unique_ptr<ExynosDisplayInterface> & dispInterface)117 int32_t ExynosDeviceDrmInterface::initDisplayInterface(
118         std::unique_ptr<ExynosDisplayInterface> &dispInterface) {
119     ExynosDisplayDrmInterface *displayInterface =
120         static_cast<ExynosDisplayDrmInterface*>(dispInterface.get());
121     return displayInterface->initDrmDevice(mDrmDevice);
122 }
123 
updateRestrictions()124 void ExynosDeviceDrmInterface::updateRestrictions() {
125     int32_t ret = 0;
126     uint32_t channelId = 0;
127 
128     for (auto &plane : mDrmDevice->planes()) {
129         struct hwc_dpp_ch_restriction hwc_res;
130 
131         /* Set size restriction information */
132         if (plane->hw_restrictions_property().id()) {
133             uint64_t blobId;
134 
135             std::tie(ret, blobId) = plane->hw_restrictions_property().value();
136             if (ret)
137                 break;
138 
139             struct dpp_ch_restriction *res;
140             drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(mDrmDevice->fd(), blobId);
141             if (!blob) {
142                 ALOGE("Fail to get blob for hw_restrictions(%" PRId64 ")", blobId);
143                 ret = HWC2_ERROR_UNSUPPORTED;
144                 break;
145             }
146             res = (struct dpp_ch_restriction *)blob->data;
147             set_dpp_ch_restriction(hwc_res, *res);
148             drmModeFreePropertyBlob(blob);
149         } else {
150             ALOGI("plane[%d] There is no hw restriction information", channelId);
151             ret = HWC2_ERROR_UNSUPPORTED;
152             break;
153         }
154 
155         /* Set supported format information */
156         for (auto format : plane->formats()) {
157             std::vector<uint32_t> halFormats;
158             if (drmFormatToHalFormats(format, &halFormats) != NO_ERROR) {
159                 ALOGE("Fail to convert drm format(%d)", format);
160                 continue;
161             }
162             for (auto halFormat : halFormats) {
163                 hwc_res.restriction.formats.push_back(halFormat);
164             }
165         }
166 
167         if (hwcCheckDebugMessages(eDebugDefault))
168             printDppRestriction(hwc_res);
169 
170         if (plane->isFormatSupported(DRM_FORMAT_C8) && plane->getNumFormatSupported() == 1)
171             mDPUInfo.dpuInfo.spp_chs.push_back(hwc_res);
172         else
173             mDPUInfo.dpuInfo.dpp_chs.push_back(hwc_res);
174 
175         channelId++;
176     }
177 
178     DrmCrtc *drmCrtc = mDrmDevice->GetCrtcForDisplay(0);
179     if (drmCrtc != nullptr) {
180         /*
181          * Run makeDPURestrictions() even if there is error
182          * in getting the value
183          */
184         if (drmCrtc->ppc_property().id()) {
185             auto [ret_ppc, value] = drmCrtc->ppc_property().value();
186             if (ret_ppc < 0) {
187                 ALOGE("Failed to get ppc property");
188             } else {
189                 mDPUInfo.dpuInfo.ppc = static_cast<uint32_t>(value);
190             }
191         }
192         if (drmCrtc->max_disp_freq_property().id()) {
193             auto [ret_max_freq, value] = drmCrtc->max_disp_freq_property().value();
194             if (ret_max_freq < 0) {
195                 ALOGE("Failed to get max_disp_freq property");
196             } else {
197                 mDPUInfo.dpuInfo.max_disp_freq = static_cast<uint32_t>(value);
198             }
199         }
200     } else {
201         ALOGE("%s:: Fail to get DrmCrtc", __func__);
202     }
203 
204     if (ret != NO_ERROR) {
205         ALOGI("Fail to get restriction (ret: %d)", ret);
206         mUseQuery = false;
207         return;
208     }
209 
210     if ((ret = makeDPURestrictions()) != NO_ERROR) {
211         ALOGE("makeDPURestrictions fail");
212     } else if ((ret = updateFeatureTable()) != NO_ERROR) {
213         ALOGE("updateFeatureTable fail");
214     }
215 
216     if (ret == NO_ERROR)
217         mUseQuery = true;
218     else {
219         ALOGI("There is no hw restriction information, use default values");
220         mUseQuery = false;
221     }
222 }
223 
init(ExynosDevice * exynosDevice,DrmDevice * drmDevice)224 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::init(ExynosDevice *exynosDevice,
225                                                            DrmDevice *drmDevice) {
226     mExynosDevice = exynosDevice;
227     mDrmDevice = drmDevice;
228 }
229 
handleEvent(uint64_t timestamp_us)230 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleEvent(uint64_t timestamp_us) {
231     mExynosDevice->handleHotplug();
232 }
233 
handleHistogramEvent(uint32_t crtc_id,void * bin)234 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramEvent(uint32_t crtc_id,
235                                                                            void *bin) {
236     ExynosDisplayDrmInterface *displayInterface;
237     DrmProperty crtc;
238     uint32_t id;
239 
240     for (auto display : mExynosDevice->mDisplays) {
241         displayInterface =
242                 static_cast<ExynosDisplayDrmInterface *>(display->mDisplayInterface.get());
243         id = displayInterface->getCrtcId();
244         if (id == crtc_id) {
245             displayInterface->setHistogramData(bin);
246         }
247     }
248 }
249 
250 #if defined(EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT)
handleHistogramChannelEvent(void * event)251 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramChannelEvent(void *event) {
252     struct exynos_drm_histogram_channel_event *histogram_channel_event =
253             (struct exynos_drm_histogram_channel_event *)event;
254 
255     for (auto display : mExynosDevice->mDisplays) {
256         ExynosDisplayDrmInterface *displayInterface =
257                 static_cast<ExynosDisplayDrmInterface *>(display->mDisplayInterface.get());
258         if (histogram_channel_event->crtc_id == displayInterface->getCrtcId()) {
259             if (display->mHistogramController) {
260                 display->mHistogramController->handleDrmEvent(histogram_channel_event);
261             } else {
262                 ALOGE("%s: no valid mHistogramController for crtc_id (%u)", __func__,
263                       histogram_channel_event->crtc_id);
264             }
265 
266             return;
267         }
268     }
269 
270     ALOGE("%s: no display with crtc_id (%u)", __func__, histogram_channel_event->crtc_id);
271 }
272 #else
handleHistogramChannelEvent(void * event)273 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramChannelEvent(void *event) {}
274 #endif
275 
handleTUIEvent()276 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleTUIEvent() {
277     if (mDrmDevice->event_listener()->IsDrmInTUI()) {
278         /* Received TUI Enter event */
279         if (!mExynosDevice->isInTUI()) {
280             mExynosDevice->enterToTUI();
281             ALOGV("%s:: DRM device in TUI", __func__);
282         }
283     } else {
284         /* Received TUI Exit event */
285         if (mExynosDevice->isInTUI()) {
286             mExynosDevice->onRefreshDisplays();
287             mExynosDevice->exitFromTUI();
288             ALOGV("%s:: DRM device out TUI", __func__);
289         }
290     }
291 }
292 
293 constexpr size_t IDLE_ENTER_EVENT_DATA_SIZE = 3;
handleIdleEnterEvent(char const * event)294 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleIdleEnterEvent(char const *event) {
295     /* PANEL_IDLE_ENTER=<display index>,<vrefresh>,<idle te vrefresh> */
296     std::string_view idle_event_str(event);
297     auto prefix_shift_pos = idle_event_str.find("=");
298     if (prefix_shift_pos == std::string::npos) {
299         ALOGE("%s: idle enter event format is incorrect", __func__);
300     }
301 
302     int count = 0;
303     int value[IDLE_ENTER_EVENT_DATA_SIZE] = {0};
304     const auto &[displayIndex, vrefresh, idleTeVrefresh] = value;
305 
306     auto start_pos = prefix_shift_pos + 1;
307     auto end_pos = idle_event_str.find(",", start_pos);
308     while (end_pos != std::string::npos && count < IDLE_ENTER_EVENT_DATA_SIZE) {
309         auto info = idle_event_str.substr(start_pos, end_pos - start_pos);
310 
311         value[count++] = atoi(info.data());
312         start_pos = end_pos + 1;
313         end_pos = idle_event_str.find(",", start_pos);
314         if (end_pos == std::string::npos) {
315             info = idle_event_str.substr(start_pos, idle_event_str.size() - start_pos);
316             value[count++] = atoi(info.data());
317         }
318     }
319 
320     if (count != IDLE_ENTER_EVENT_DATA_SIZE) {
321         ALOGE("%s: idle enter event is incomplete", __func__);
322         return;
323     }
324 
325     ExynosDisplay *primaryDisplay =
326             mExynosDevice->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, displayIndex));
327     if (primaryDisplay) {
328         /* sending vsyncIdle callback */
329         if (vrefresh != idleTeVrefresh) {
330             mExynosDevice->onVsyncIdle(primaryDisplay->getId());
331         }
332 
333         primaryDisplay->handleDisplayIdleEnter(idleTeVrefresh);
334     }
335 }
336 
registerSysfsEventHandler(std::shared_ptr<DrmSysfsEventHandler> handler)337 int32_t ExynosDeviceDrmInterface::registerSysfsEventHandler(
338         std::shared_ptr<DrmSysfsEventHandler> handler) {
339     return mDrmDevice->event_listener()->RegisterSysfsHandler(std::move(handler));
340 }
341 
unregisterSysfsEventHandler(int sysfsFd)342 int32_t ExynosDeviceDrmInterface::unregisterSysfsEventHandler(int sysfsFd) {
343     return mDrmDevice->event_listener()->UnRegisterSysfsHandler(sysfsFd);
344 }
345