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