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 <drm/drm_mode.h>
18 #include "ExynosDeviceDrmInterface.h"
19 #include "ExynosDisplayDrmInterface.h"
20 #include "ExynosHWCDebug.h"
21 #include "ExynosDevice.h"
22 #include "ExynosDisplay.h"
23 #include "ExynosExternalDisplayModule.h"
24 #include <hardware/hwcomposer_defs.h>
25 #include <drm/samsung_drm.h>
26
set_hwc_dpp_size_range(hwc_dpp_size_range & hwc_dpp_range,dpp_size_range & dpp_range)27 void set_hwc_dpp_size_range(hwc_dpp_size_range &hwc_dpp_range, dpp_size_range &dpp_range)
28 {
29 hwc_dpp_range.min = dpp_range.min;
30 hwc_dpp_range.max = dpp_range.max;
31 hwc_dpp_range.align = dpp_range.align;
32 }
33
set_dpp_ch_restriction(struct hwc_dpp_ch_restriction & hwc_dpp_restriction,struct dpp_ch_restriction & drm_restriction)34 static void set_dpp_ch_restriction(struct hwc_dpp_ch_restriction &hwc_dpp_restriction,
35 struct dpp_ch_restriction &drm_restriction)
36 {
37 hwc_dpp_restriction.id = drm_restriction.id;
38 hwc_dpp_restriction.attr = drm_restriction.attr;
39 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.src_f_w, drm_restriction.restriction.src_f_w);
40 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.src_f_h, drm_restriction.restriction.src_f_h);
41 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.src_w, drm_restriction.restriction.src_w);
42 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.src_h, drm_restriction.restriction.src_h);
43 hwc_dpp_restriction.restriction.src_x_align = drm_restriction.restriction.src_x_align;
44 hwc_dpp_restriction.restriction.src_y_align = drm_restriction.restriction.src_y_align;
45 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.dst_f_w, drm_restriction.restriction.dst_f_w);
46 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.dst_f_h, drm_restriction.restriction.dst_f_h);
47 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.dst_w, drm_restriction.restriction.dst_w);
48 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.dst_h, drm_restriction.restriction.dst_h);
49 hwc_dpp_restriction.restriction.dst_x_align = drm_restriction.restriction.dst_x_align;
50 hwc_dpp_restriction.restriction.dst_y_align = drm_restriction.restriction.dst_y_align;
51 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.blk_w, drm_restriction.restriction.blk_w);
52 set_hwc_dpp_size_range(hwc_dpp_restriction.restriction.blk_h, drm_restriction.restriction.blk_h);
53 hwc_dpp_restriction.restriction.blk_x_align = drm_restriction.restriction.blk_x_align;
54 hwc_dpp_restriction.restriction.blk_y_align = drm_restriction.restriction.blk_y_align;
55 hwc_dpp_restriction.restriction.src_h_rot_max = drm_restriction.restriction.src_h_rot_max;
56 hwc_dpp_restriction.restriction.scale_down = drm_restriction.restriction.scale_down;
57 hwc_dpp_restriction.restriction.scale_up = drm_restriction.restriction.scale_up;
58
59 /* scale ratio can't be 0 */
60 if (hwc_dpp_restriction.restriction.scale_down == 0)
61 hwc_dpp_restriction.restriction.scale_down = 1;
62 if (hwc_dpp_restriction.restriction.scale_up == 0)
63 hwc_dpp_restriction.restriction.scale_up = 1;
64 }
65
66 using namespace SOC_VERSION;
67
ExynosDeviceDrmInterface(ExynosDevice * exynosDevice)68 ExynosDeviceDrmInterface::ExynosDeviceDrmInterface(ExynosDevice *exynosDevice)
69 {
70 mType = INTERFACE_TYPE_DRM;
71 }
72
~ExynosDeviceDrmInterface()73 ExynosDeviceDrmInterface::~ExynosDeviceDrmInterface()
74 {
75 mDrmDevice->event_listener()->UnRegisterHotplugHandler(static_cast<DrmEventHandler *>(&mExynosDrmEventHandler));
76 mDrmDevice->event_listener()->UnRegisterTUIHandler(static_cast<DrmTUIEventHandler *>(&mExynosDrmEventHandler));
77 }
78
init(ExynosDevice * exynosDevice)79 void ExynosDeviceDrmInterface::init(ExynosDevice *exynosDevice)
80 {
81 mUseQuery = false;
82 mExynosDevice = exynosDevice;
83 mDrmResourceManager.Init();
84 mDrmDevice = mDrmResourceManager.GetDrmDevice(HWC_DISPLAY_PRIMARY);
85 assert(mDrmDevice != NULL);
86
87 updateRestrictions();
88
89 mExynosDrmEventHandler.init(mExynosDevice, mDrmDevice);
90 mDrmDevice->event_listener()->RegisterHotplugHandler(static_cast<DrmEventHandler *>(&mExynosDrmEventHandler));
91 mDrmDevice->event_listener()->RegisterTUIHandler(static_cast<DrmTUIEventHandler *>(&mExynosDrmEventHandler));
92
93 if (mDrmDevice->event_listener()->IsDrmInTUI()) {
94 mExynosDevice->enterToTUI();
95 ALOGD("%s:: device is already in TUI", __func__);
96 }
97 }
98
initDisplayInterface(std::unique_ptr<ExynosDisplayInterface> & dispInterface)99 int32_t ExynosDeviceDrmInterface::initDisplayInterface(
100 std::unique_ptr<ExynosDisplayInterface> &dispInterface)
101 {
102 ExynosDisplayDrmInterface *displayInterface =
103 static_cast<ExynosDisplayDrmInterface*>(dispInterface.get());
104 return displayInterface->initDrmDevice(mDrmDevice);
105 }
106
updateRestrictions()107 void ExynosDeviceDrmInterface::updateRestrictions()
108 {
109 int32_t ret = 0;
110
111 mDPUInfo.dpuInfo.dpp_chs.resize(mDrmDevice->planes().size());
112 uint32_t channelId = 0;
113
114 for (auto &plane : mDrmDevice->planes()) {
115 /* Set size restriction information */
116 if (plane->hw_restrictions_property().id()) {
117 uint64_t blobId;
118 std::tie(ret, blobId) = plane->hw_restrictions_property().value();
119 if (ret)
120 break;
121 struct dpp_ch_restriction *res;
122 drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(mDrmDevice->fd(), blobId);
123 if (!blob) {
124 ALOGE("Fail to get blob for hw_restrictions(%" PRId64 ")", blobId);
125 ret = HWC2_ERROR_UNSUPPORTED;
126 break;
127 }
128 res = (struct dpp_ch_restriction *)blob->data;
129 set_dpp_ch_restriction(mDPUInfo.dpuInfo.dpp_chs[channelId], *res);
130 drmModeFreePropertyBlob(blob);
131 } else {
132 ALOGI("plane[%d] There is no hw restriction information", channelId);
133 ret = HWC2_ERROR_UNSUPPORTED;
134 break;
135 }
136 /* Set supported format information */
137 for (auto format : plane->formats()) {
138 std::vector<uint32_t> halFormats;
139 if (drmFormatToHalFormats(format, &halFormats) != NO_ERROR) {
140 ALOGE("Fail to convert drm format(%d)", format);
141 continue;
142 }
143 for (auto halFormat : halFormats) {
144 mDPUInfo.dpuInfo.dpp_chs[channelId].restriction.formats.push_back(halFormat);
145 }
146 }
147 if (hwcCheckDebugMessages(eDebugAttrSetting))
148 printDppRestriction(mDPUInfo.dpuInfo.dpp_chs[channelId]);
149
150 channelId++;
151 }
152
153 DrmCrtc *drmCrtc = mDrmDevice->GetCrtcForDisplay(0);
154 if (drmCrtc != nullptr) {
155 /*
156 * Run makeDPURestrictions() even if there is error
157 * in getting the value
158 */
159 if (drmCrtc->ppc_property().id()) {
160 auto [ret_ppc, value] = drmCrtc->ppc_property().value();
161 if (ret_ppc < 0) {
162 ALOGE("Failed to get ppc property");
163 } else {
164 mDPUInfo.dpuInfo.ppc = static_cast<uint32_t>(value);
165 }
166 }
167 if (drmCrtc->max_disp_freq_property().id()) {
168 auto [ret_max_freq, value] = drmCrtc->max_disp_freq_property().value();
169 if (ret_max_freq < 0) {
170 ALOGE("Failed to get max_disp_freq property");
171 } else {
172 mDPUInfo.dpuInfo.max_disp_freq = static_cast<uint32_t>(value);
173 }
174 }
175 } else {
176 ALOGE("%s:: Fail to get DrmCrtc", __func__);
177 }
178
179 if (ret != NO_ERROR) {
180 ALOGI("Fail to get restriction (ret: %d)", ret);
181 mUseQuery = false;
182 return;
183 }
184
185 if ((ret = makeDPURestrictions()) != NO_ERROR) {
186 ALOGE("makeDPURestrictions fail");
187 } else if ((ret = updateFeatureTable()) != NO_ERROR) {
188 ALOGE("updateFeatureTable fail");
189 }
190
191 if (ret == NO_ERROR)
192 mUseQuery = true;
193 else {
194 ALOGI("There is no hw restriction information, use default values");
195 mUseQuery = false;
196 }
197 }
198
init(ExynosDevice * exynosDevice,DrmDevice * drmDevice)199 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::init(ExynosDevice *exynosDevice, DrmDevice *drmDevice)
200 {
201 mExynosDevice = exynosDevice;
202 mDrmDevice = drmDevice;
203 }
204
HandleEvent(uint64_t timestamp_us)205 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::HandleEvent(uint64_t timestamp_us)
206 {
207 hwc2_callback_data_t callbackData =
208 mExynosDevice->mCallbackInfos[HWC2_CALLBACK_HOTPLUG].callbackData;
209 HWC2_PFN_HOTPLUG callbackFunc =
210 (HWC2_PFN_HOTPLUG)mExynosDevice->mCallbackInfos[HWC2_CALLBACK_HOTPLUG].funcPointer;
211
212 if (callbackData == NULL || callbackFunc == NULL)
213 {
214 ALOGE("%s:: callback info is NULL", __func__);
215 return;
216 }
217
218 for (auto it : mExynosDevice->mDisplays) {
219 /* Call UpdateModes to get plug status */
220 uint32_t numConfigs;
221 it->getDisplayConfigs(&numConfigs, NULL);
222
223 callbackFunc(callbackData, getDisplayId(it->mType, it->mIndex),
224 it->mPlugState ? HWC2_CONNECTION_CONNECTED : HWC2_CONNECTION_DISCONNECTED);
225 }
226
227 /* TODO: Check plug status hear or ExynosExternalDisplay::handleHotplugEvent() */
228 ExynosExternalDisplayModule *display =
229 static_cast<ExynosExternalDisplayModule*>(mExynosDevice->getDisplay(getDisplayId(HWC_DISPLAY_EXTERNAL, 0)));
230 if (display != NULL)
231 display->handleHotplugEvent();
232 }
233
HandleTUIEvent()234 void ExynosDeviceDrmInterface::ExynosDrmEventHandler::HandleTUIEvent()
235 {
236 if (mDrmDevice->event_listener()->IsDrmInTUI()) {
237 /* Received TUI Enter event */
238 if (!mExynosDevice->isInTUI()) {
239 mExynosDevice->enterToTUI();
240 ALOGV("%s:: DRM device in TUI", __func__);
241 }
242 } else {
243 /* Received TUI Exit event */
244 if (mExynosDevice->isInTUI()) {
245 mExynosDevice->invalidate();
246 mExynosDevice->exitFromTUI();
247 ALOGV("%s:: DRM device out TUI", __func__);
248 }
249 }
250 }
251