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
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <drm.h>
33 #include <drm/sde_drm.h>
34 #include <drm_logger.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <algorithm>
38 #include <map>
39 #include <set>
40 #include <utility>
41 #include <vector>
42 #include <iterator>
43
44 #include "drm_encoder.h"
45 #include "drm_utils.h"
46
47 namespace sde_drm {
48
49 using std::unique_ptr;
50 using std::map;
51 using std::pair;
52 using std::make_pair;
53 using std::set;
54 using std::distance;
55
56 #define __CLASS__ "DRMEncoderManager"
57
~DRMEncoderManager()58 DRMEncoderManager::~DRMEncoderManager() {}
59
Init(drmModeRes * resource)60 void DRMEncoderManager::Init(drmModeRes *resource) {
61 for (int i = 0; i < resource->count_encoders; i++) {
62 unique_ptr<DRMEncoder> encoder(new DRMEncoder(fd_));
63 drmModeEncoder *libdrm_encoder = drmModeGetEncoder(fd_, resource->encoders[i]);
64 if (!libdrm_encoder) {
65 DRM_LOGE("Critical error: drmModeGetEncoder() failed for encoder %d.", resource->encoders[i]);
66 continue;
67 }
68 encoder->InitAndParse(libdrm_encoder);
69 encoder_pool_[resource->encoders[i]] = std::move(encoder);
70 }
71
72 // TODO(user): Remove call when driver reporting of encoders is consistent across all use cases
73 InsertSecondaryDSI();
74 }
75
76 /*
77 * This API is a workaround for maintaining appropriate HW port numbers for displays on platforms
78 * that can dynamically change between single panel and secondary panel uses cases. It is required
79 * that the port # for a pixel stream remains consistent, so userspace must account for the
80 * possiblility of the secondary panel use case, even during single panel use case.
81
82 * Driver rearchitecture for encoder creation is under discussion for future chipsets to avoid the
83 * need of this function.
84 */
InsertSecondaryDSI()85 void DRMEncoderManager::InsertSecondaryDSI() {
86 uint32_t first_dsi_id = 0;
87 bool second_dsi_found = false;
88 bool first_dsi_found = false;
89
90 for (auto encoder = encoder_pool_.begin(); encoder != encoder_pool_.end(); encoder++) {
91 std::unique_ptr<DRMEncoder> &encoder_ptr = encoder->second;
92 uint32_t encoder_type;
93 encoder_ptr->GetType(&encoder_type);
94 if (encoder_type == DRM_MODE_ENCODER_DSI) {
95 if (!first_dsi_found) {
96 encoder_ptr->GetId(&first_dsi_id);
97 first_dsi_found = true;
98 } else if (first_dsi_found) {
99 // Secondary panel use case is active, below logic is skipped
100 second_dsi_found = true;
101 break;
102 }
103 }
104 }
105
106 if (first_dsi_found && !second_dsi_found) {
107 // Single panel use case is active, inject new DSI encoder
108 uint32_t enc_id = first_dsi_id + 1;
109 unique_ptr<DRMEncoder> sec_dsi_enc(new DRMEncoder(fd_, enc_id, DRM_MODE_ENCODER_DSI));
110 encoder_pool_[enc_id] = std::move(sec_dsi_enc);
111 DRM_LOGI("Userspace has inserted secondary panel DSI encoder!");
112 } else {
113 DRM_LOGI("Userspace did not need to insert secondary panel DSI encoder, it is present.");
114 }
115 }
116
DumpByID(uint32_t id)117 void DRMEncoderManager::DumpByID(uint32_t id) {
118 encoder_pool_.at(id)->Dump();
119 }
120
DumpAll()121 void DRMEncoderManager::DumpAll() {
122 for (auto &encoder : encoder_pool_) {
123 encoder.second->Dump();
124 }
125 }
126
GetEncoderInfo(uint32_t encoder_id,DRMEncoderInfo * info)127 int DRMEncoderManager::GetEncoderInfo(uint32_t encoder_id, DRMEncoderInfo *info) {
128 int ret = -ENODEV;
129 auto iter = encoder_pool_.find(encoder_id);
130
131 if (iter != encoder_pool_.end()) {
132 encoder_pool_[encoder_id]->GetInfo(info);
133 ret = 0;
134 }
135 return ret;
136 }
137
GetEncoderList(std::vector<uint32_t> * encoder_ids)138 int DRMEncoderManager::GetEncoderList(std::vector<uint32_t> *encoder_ids) {
139 if (!encoder_ids) {
140 return -EINVAL;
141 }
142 encoder_ids->clear();
143 for (auto &encoder : encoder_pool_) {
144 encoder_ids->push_back(encoder.first);
145 }
146 return 0;
147 }
148
Reserve(const std::set<uint32_t> & possible_encoders,DRMDisplayToken * token)149 int DRMEncoderManager::Reserve(const std::set<uint32_t> &possible_encoders, DRMDisplayToken *token) {
150 int ret = -ENODEV;
151 for (auto encoder = encoder_pool_.begin(); encoder != encoder_pool_.end(); encoder++) {
152 const uint32_t &encoder_id = encoder->first;
153 if ((encoder->second)->GetStatus() == DRMStatus::FREE) {
154 // If encoder is found in the set, the encoder is a candidate for selection and the encoder
155 // type for display's connector and encoder-this-iteration are already matched implicitly
156 if (possible_encoders.find(encoder_id) != possible_encoders.end()) {
157 encoder->second->Lock();
158 token->encoder_id = encoder_id;
159 int encoder_index = distance(encoder_pool_.begin(), encoder) + 1; // 1-indexed port
160 // Port id format.
161 // Bit 7 --> Display type 0: Pluggable 1: BuiltIn X:Virtual.
162 // Bit 6 --> Pluggable: 0 for TMDS encoder, 1 for DPMST encoder.
163 // Builtin Or Virtual: X
164 // Bit 5-0 --> Encoder index.
165 uint32_t encoder_type;
166 encoder->second->GetType(&encoder_type);
167 token->hw_port = GetDisplayTypeCode(encoder_type) | encoder_index;
168 ret = 0;
169 break;
170 }
171 }
172 }
173 return ret;
174 }
175
GetDisplayTypeCode(uint32_t encoder_type)176 int DRMEncoderManager::GetDisplayTypeCode(uint32_t encoder_type) {
177 int disp_info = 0x2;
178 switch (encoder_type) {
179 case DRM_MODE_ENCODER_TMDS:
180 disp_info = 0x0;
181 break;
182 case DRM_MODE_ENCODER_DPMST:
183 disp_info = 0x1;
184 break;
185 default:
186 break;
187 }
188
189 return (disp_info << 6);
190 }
191
Free(DRMDisplayToken * token)192 void DRMEncoderManager::Free(DRMDisplayToken *token) {
193 auto iter = encoder_pool_.find(token->encoder_id);
194 if (iter != encoder_pool_.end()) {
195 iter->second->Unlock();
196 } else {
197 DRM_LOGW("Failed! encoder_id %u not found! Cleaning up token anyway...", token->encoder_id);
198 }
199 token->encoder_id = 0;
200 token->hw_port = 0;
201 }
202
GetPossibleCrtcIndices(uint32_t encoder_id,std::set<uint32_t> * possible_crtc_indices)203 int DRMEncoderManager::GetPossibleCrtcIndices(uint32_t encoder_id,
204 std::set<uint32_t> *possible_crtc_indices) {
205 return encoder_pool_[encoder_id]->GetPossibleCrtcIndices(possible_crtc_indices);
206 }
207
208 // ==============================================================================================//
209
210 #undef __CLASS__
211 #define __CLASS__ "DRMEncoder"
212
~DRMEncoder()213 DRMEncoder::~DRMEncoder() {
214 if (drm_encoder_) {
215 drmModeFreeEncoder(drm_encoder_);
216 }
217 }
218
GetInfo(DRMEncoderInfo * info)219 void DRMEncoder::GetInfo(DRMEncoderInfo *info) {
220 *info = encoder_info_;
221 }
222
Lock()223 void DRMEncoder::Lock() {
224 status_ = DRMStatus::BUSY;
225 }
226
Unlock()227 void DRMEncoder::Unlock() {
228 status_ = DRMStatus::FREE;
229 }
230
InitAndParse(drmModeEncoder * encoder)231 void DRMEncoder::InitAndParse(drmModeEncoder *encoder) {
232 drm_encoder_ = encoder;
233 encoder_info_.type = drm_encoder_->encoder_type;
234 }
235
GetPossibleCrtcIndices(std::set<uint32_t> * possible_crtc_indices)236 int DRMEncoder::GetPossibleCrtcIndices(std::set<uint32_t> *possible_crtc_indices) {
237 if (!possible_crtc_indices) {
238 return -EINVAL;
239 }
240
241 (*possible_crtc_indices).clear();
242 std::bitset<32> possible_crtcs = drm_encoder_->possible_crtcs;
243 for (uint32_t i = 0; i < possible_crtcs.size(); i++) {
244 if (possible_crtcs[i]) {
245 (*possible_crtc_indices).insert(i);
246 }
247 }
248
249 return 0;
250 }
251
Dump()252 void DRMEncoder::Dump() {
253 if (drm_encoder_) {
254 DRM_LOGI("[driver-reported] id: %u encoder_type: %u crtc id: %u possible_crtcs: %u"
255 "possible_clones: %u fd = %d",
256 drm_encoder_->encoder_id, drm_encoder_->encoder_type, drm_encoder_->crtc_id,
257 drm_encoder_->possible_crtcs, drm_encoder_->possible_clones, fd_);
258 } else {
259 DRM_LOGI("[userspace-only] id: %u encoder_type: %u fd = %d ", fake_id_, fake_type_, fd_);
260 }
261 }
262
263 } // namespace sde_drm
264