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