1 /*
2 * Copyright (c) 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 #define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
30
31 #include <cutils/trace.h>
32 #include <drm_logger.h>
33
34 #include "drm_atomic_req.h"
35 #include "drm_connector.h"
36 #include "drm_crtc.h"
37 #include "drm_manager.h"
38 #include "drm_plane.h"
39 #include "string.h"
40
41 #define __CLASS__ "DRMAtomicReq"
42
43 namespace sde_drm {
44
DRMAtomicReq(int fd,DRMManager * drm_mgr)45 DRMAtomicReq::DRMAtomicReq(int fd, DRMManager *drm_mgr) : drm_mgr_(drm_mgr), fd_(fd) {}
46
~DRMAtomicReq()47 DRMAtomicReq::~DRMAtomicReq() {
48 if (drm_atomic_req_) {
49 drmModeAtomicFree(drm_atomic_req_);
50 drm_atomic_req_ = nullptr;
51 }
52 }
53
Init(const DRMDisplayToken & tok)54 int DRMAtomicReq::Init(const DRMDisplayToken &tok) {
55 token_ = tok;
56 drm_atomic_req_ = drmModeAtomicAlloc();
57 if (!drm_atomic_req_) {
58 return -ENOMEM;
59 }
60
61 return 0;
62 }
63
Perform(DRMOps opcode,uint32_t obj_id,...)64 int DRMAtomicReq::Perform(DRMOps opcode, uint32_t obj_id, ...) {
65 va_list args;
66 va_start(args, obj_id);
67 switch (opcode) {
68 case DRMOps::PLANE_SET_SRC_RECT:
69 case DRMOps::PLANE_SET_DST_RECT:
70 case DRMOps::PLANE_SET_ZORDER:
71 case DRMOps::PLANE_SET_ROTATION:
72 case DRMOps::PLANE_SET_ALPHA:
73 case DRMOps::PLANE_SET_BLEND_TYPE:
74 case DRMOps::PLANE_SET_H_DECIMATION:
75 case DRMOps::PLANE_SET_V_DECIMATION:
76 case DRMOps::PLANE_SET_FB_ID:
77 case DRMOps::PLANE_SET_ROT_FB_ID:
78 case DRMOps::PLANE_SET_CRTC:
79 case DRMOps::PLANE_SET_SRC_CONFIG:
80 case DRMOps::PLANE_SET_INPUT_FENCE:
81 case DRMOps::PLANE_SET_SCALER_CONFIG:
82 case DRMOps::PLANE_SET_FB_SECURE_MODE:
83 case DRMOps::PLANE_SET_CSC_CONFIG:
84 case DRMOps::PLANE_SET_MULTIRECT_MODE:
85 case DRMOps::PLANE_SET_EXCL_RECT:
86 case DRMOps::PLANE_SET_INVERSE_PMA:
87 case DRMOps::PLANE_SET_DGM_CSC_CONFIG:
88 case DRMOps::PLANE_SET_POST_PROC:
89 case DRMOps::PLANE_SET_SSPP_LAYOUT: {
90 drm_mgr_->GetPlaneMgr()->Perform(opcode, obj_id, drm_atomic_req_, args);
91 } break;
92 case DRMOps::CRTC_SET_POST_PROC:
93 case DRMOps::CRTC_SET_MODE:
94 case DRMOps::CRTC_SET_ACTIVE:
95 case DRMOps::CRTC_SET_OUTPUT_FENCE_OFFSET:
96 case DRMOps::CRTC_SET_CORE_CLK:
97 case DRMOps::CRTC_SET_CORE_AB:
98 case DRMOps::CRTC_SET_CORE_IB:
99 case DRMOps::CRTC_SET_LLCC_AB:
100 case DRMOps::CRTC_SET_LLCC_IB:
101 case DRMOps::CRTC_SET_DRAM_AB:
102 case DRMOps::CRTC_SET_DRAM_IB:
103 case DRMOps::CRTC_SET_ROT_PREFILL_BW:
104 case DRMOps::CRTC_SET_ROT_CLK:
105 case DRMOps::CRTC_GET_RELEASE_FENCE:
106 case DRMOps::CRTC_SET_ROI:
107 case DRMOps::CRTC_SET_SECURITY_LEVEL:
108 case DRMOps::CRTC_SET_SOLIDFILL_STAGES:
109 case DRMOps::CRTC_SET_IDLE_TIMEOUT:
110 case DRMOps::CRTC_SET_DEST_SCALER_CONFIG:
111 case DRMOps::CRTC_SET_CAPTURE_MODE:
112 case DRMOps::CRTC_SET_IDLE_PC_STATE: {
113 drm_mgr_->GetCrtcMgr()->Perform(opcode, obj_id, drm_atomic_req_, args);
114 } break;
115 case DRMOps::CONNECTOR_SET_CRTC:
116 case DRMOps::CONNECTOR_GET_RETIRE_FENCE:
117 case DRMOps::CONNECTOR_SET_OUTPUT_RECT:
118 case DRMOps::CONNECTOR_SET_OUTPUT_FB_ID:
119 case DRMOps::CONNECTOR_SET_POWER_MODE:
120 case DRMOps::CONNECTOR_SET_ROI:
121 case DRMOps::CONNECTOR_SET_AUTOREFRESH:
122 case DRMOps::CONNECTOR_SET_FB_SECURE_MODE:
123 case DRMOps::CONNECTOR_SET_POST_PROC:
124 case DRMOps::CONNECTOR_SET_HDR_METADATA:
125 case DRMOps::CONNECTOR_SET_QSYNC_MODE:
126 case DRMOps::CONNECTOR_SET_TOPOLOGY_CONTROL:
127 case DRMOps::CONNECTOR_SET_FRAME_TRIGGER:
128 case DRMOps::CONNECTOR_SET_COLORSPACE: {
129 drm_mgr_->GetConnectorMgr()->Perform(opcode, obj_id, drm_atomic_req_, args);
130 } break;
131 case DRMOps::DPPS_CACHE_FEATURE: {
132 drm_mgr_->GetDppsMgrIntf()->CacheDppsFeature(obj_id, args);
133 } break;
134 case DRMOps::DPPS_COMMIT_FEATURE: {
135 drm_mgr_->GetDppsMgrIntf()->CommitDppsFeatures(drm_atomic_req_, token_);
136 } break;
137 default:
138 DRM_LOGE("Invalid opcode %d", opcode);
139 }
140 va_end(args);
141 return 0;
142 }
143
CallAtomic(DRMCrtc * crtc,uint32_t flags)144 int DRMAtomicReq::CallAtomic(DRMCrtc *crtc, uint32_t flags)
145 {
146 auto plane_mgr = drm_mgr_->GetPlaneMgr();
147 size_t cnt;
148
149 cnt = plane_mgr->ApplyDirtyProperties(drm_atomic_req_);
150 ATRACE_INT("dirtyPlaneProps", cnt);
151 cnt = crtc->ApplyDirtyProperties(drm_atomic_req_);
152 ATRACE_INT("dirtyCrtcProps", cnt);
153
154 int ret = drmModeAtomicCommit(fd_, drm_atomic_req_, flags, nullptr);
155 if (ret) {
156 DRM_LOGE("drmModeAtomicCommit failed with error %d (%s).", errno, strerror(errno));
157 /* reset all properties so next atomic commit applies all values */
158 crtc->ClearProperties();
159 plane_mgr->ClearProperties();
160 }
161
162 // reset the drm_atomic_req_ for next call
163 drmModeAtomicSetCursor(drm_atomic_req_, 0);
164
165 return ret;
166 }
167
Validate()168 int DRMAtomicReq::Validate() {
169 auto crtc = drm_mgr_->GetCrtcMgr()->GetObject(token_.crtc_id);
170 if (crtc == nullptr) {
171 DRM_LOGE("Invalid crtc %d", token_.crtc_id);
172 return -EINVAL;
173 }
174
175 drm_mgr_->GetPlaneMgr()->UnsetUnusedResources(token_.crtc_id, false /*is_commit*/,
176 drm_atomic_req_);
177 int ret = CallAtomic(crtc, DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_TEST_ONLY);
178 if (!ret)
179 crtc->PostValidate();
180
181 // reset any dirty properties, all properties should be set again before Commit
182 crtc->DiscardDirtyProperties();
183 drm_mgr_->GetPlaneMgr()->PostValidate(token_.crtc_id);
184
185 return ret;
186 }
187
Commit(bool synchronous,bool retain_planes)188 int DRMAtomicReq::Commit(bool synchronous, bool retain_planes) {
189 DTRACE_SCOPED();
190 auto crtc = drm_mgr_->GetCrtcMgr()->GetObject(token_.crtc_id);
191 if (crtc == nullptr) {
192 DRM_LOGE("Invalid crtc %d", token_.crtc_id);
193 return -EINVAL;
194 }
195
196 if (retain_planes) {
197 // It is not enough to simply avoid calling UnsetUnusedPlanes, since state transitons have to
198 // be correct when CommitPlaneState is called
199 drm_mgr_->GetPlaneMgr()->RetainPlanes(token_.crtc_id);
200 }
201
202 drm_mgr_->GetPlaneMgr()->UnsetUnusedResources(token_.crtc_id, true /*is_commit*/,
203 drm_atomic_req_);
204
205 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
206
207 if (!synchronous) {
208 flags |= DRM_MODE_ATOMIC_NONBLOCK;
209 }
210
211 int ret = CallAtomic(crtc, flags);
212
213 drm_mgr_->GetPlaneMgr()->PostCommit(token_.crtc_id, !ret);
214 crtc->PostCommit(!ret);
215
216 ATRACE_INT("dirtyPlaneProps", 0);
217 ATRACE_INT("dirtyCrtcProps", 0);
218
219 return ret;
220 }
221
222 } // namespace sde_drm
223