• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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