• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 #define LOG_TAG "hwc-drm-device"
18 
19 #include "drmdevice.h"
20 #include "drmconnector.h"
21 #include "drmcrtc.h"
22 #include "drmencoder.h"
23 #include "drmeventlistener.h"
24 #include "drmplane.h"
25 
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdint.h>
29 #include <xf86drm.h>
30 #include <xf86drmMode.h>
31 #include <cinttypes>
32 
33 #include <cutils/properties.h>
34 #include <log/log.h>
35 
36 #ifndef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
37 #define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5
38 #endif
39 
40 namespace android {
41 
DrmDevice()42 DrmDevice::DrmDevice() : event_listener_(this) {
43 }
44 
~DrmDevice()45 DrmDevice::~DrmDevice() {
46   event_listener_.Exit();
47 }
48 
Init(const char * path,int num_displays)49 std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
50   /* TODO: Use drmOpenControl here instead */
51   fd_.Set(open(path, O_RDWR));
52   if (fd() < 0) {
53     ALOGE("Failed to open dri %s: %s", path, strerror(errno));
54     return std::make_tuple(-ENODEV, 0);
55   }
56 
57   int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
58   if (ret) {
59     ALOGE("Failed to set universal plane cap %d", ret);
60     return std::make_tuple(ret, 0);
61   }
62 
63   ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1);
64   if (ret) {
65     ALOGE("Failed to set atomic cap %d", ret);
66     return std::make_tuple(ret, 0);
67   }
68 
69 #ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
70   ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
71   if (ret) {
72     ALOGI("Failed to set writeback cap %d", ret);
73     ret = 0;
74   }
75 #endif
76 
77   drmModeResPtr res = drmModeGetResources(fd());
78   if (!res) {
79     ALOGE("Failed to get DrmDevice resources");
80     return std::make_tuple(-ENODEV, 0);
81   }
82 
83   min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
84                                                   res->min_height);
85   max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
86                                                   res->max_height);
87 
88   for (int i = 0; !ret && i < res->count_crtcs; ++i) {
89     drmModeCrtcPtr c = drmModeGetCrtc(fd(), res->crtcs[i]);
90     if (!c) {
91       ALOGE("Failed to get crtc %d", res->crtcs[i]);
92       ret = -ENODEV;
93       break;
94     }
95 
96     std::unique_ptr<DrmCrtc> crtc(new DrmCrtc(this, c, i));
97     drmModeFreeCrtc(c);
98 
99     ret = crtc->Init();
100     if (ret) {
101       ALOGE("Failed to initialize crtc %d", res->crtcs[i]);
102       break;
103     }
104     crtcs_.emplace_back(std::move(crtc));
105   }
106 
107   std::vector<int> possible_clones;
108   for (int i = 0; !ret && i < res->count_encoders; ++i) {
109     drmModeEncoderPtr e = drmModeGetEncoder(fd(), res->encoders[i]);
110     if (!e) {
111       ALOGE("Failed to get encoder %d", res->encoders[i]);
112       ret = -ENODEV;
113       break;
114     }
115 
116     std::vector<DrmCrtc *> possible_crtcs;
117     DrmCrtc *current_crtc = NULL;
118     for (auto &crtc : crtcs_) {
119       if ((1 << crtc->pipe()) & e->possible_crtcs)
120         possible_crtcs.push_back(crtc.get());
121 
122       if (crtc->id() == e->crtc_id)
123         current_crtc = crtc.get();
124     }
125 
126     std::unique_ptr<DrmEncoder> enc(
127         new DrmEncoder(e, current_crtc, possible_crtcs));
128     possible_clones.push_back(e->possible_clones);
129     drmModeFreeEncoder(e);
130 
131     encoders_.emplace_back(std::move(enc));
132   }
133 
134   for (unsigned int i = 0; i < encoders_.size(); i++) {
135     for (unsigned int j = 0; j < encoders_.size(); j++)
136       if (possible_clones[i] & (1 << j))
137         encoders_[i]->AddPossibleClone(encoders_[j].get());
138   }
139 
140   for (int i = 0; !ret && i < res->count_connectors; ++i) {
141     drmModeConnectorPtr c = drmModeGetConnector(fd(), res->connectors[i]);
142     if (!c) {
143       ALOGE("Failed to get connector %d", res->connectors[i]);
144       ret = -ENODEV;
145       break;
146     }
147 
148     std::vector<DrmEncoder *> possible_encoders;
149     DrmEncoder *current_encoder = NULL;
150     for (int j = 0; j < c->count_encoders; ++j) {
151       for (auto &encoder : encoders_) {
152         if (encoder->id() == c->encoders[j])
153           possible_encoders.push_back(encoder.get());
154         if (encoder->id() == c->encoder_id)
155           current_encoder = encoder.get();
156       }
157     }
158 
159     std::unique_ptr<DrmConnector> conn(
160         new DrmConnector(this, c, current_encoder, possible_encoders));
161 
162     drmModeFreeConnector(c);
163 
164     ret = conn->Init();
165     if (ret) {
166       ALOGE("Init connector %d failed", res->connectors[i]);
167       break;
168     }
169 
170     if (conn->writeback())
171       writeback_connectors_.emplace_back(std::move(conn));
172     else
173       connectors_.emplace_back(std::move(conn));
174   }
175 
176   // First look for primary amongst internal connectors and for
177   // the others assign consecutive display_numbers.
178   for (auto &conn : connectors_) {
179     if (conn->internal() && conn->display() < 0) {
180       conn->set_display(num_displays);
181       displays_[num_displays] = num_displays;
182       ++num_displays;
183     }
184   }
185 
186   // Assign consecutive display_numbers for external connectors.
187   for (auto &conn : connectors_) {
188     if (conn->external() && conn->display() < 0) {
189       conn->set_display(num_displays);
190       displays_[num_displays] = num_displays;
191       ++num_displays;
192     }
193   }
194 
195   if (res)
196     drmModeFreeResources(res);
197 
198   // Catch-all for the above loops
199   if (ret)
200     return std::make_tuple(ret, 0);
201 
202   drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd());
203   if (!plane_res) {
204     ALOGE("Failed to get plane resources");
205     return std::make_tuple(-ENOENT, 0);
206   }
207 
208   for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
209     drmModePlanePtr p = drmModeGetPlane(fd(), plane_res->planes[i]);
210     if (!p) {
211       ALOGE("Failed to get plane %d", plane_res->planes[i]);
212       ret = -ENODEV;
213       break;
214     }
215 
216     std::unique_ptr<DrmPlane> plane(new DrmPlane(this, p));
217 
218     drmModeFreePlane(p);
219 
220     ret = plane->Init();
221     if (ret) {
222       ALOGE("Init plane %d failed", plane_res->planes[i]);
223       break;
224     }
225 
226     planes_.emplace_back(std::move(plane));
227   }
228   drmModeFreePlaneResources(plane_res);
229   if (ret)
230     return std::make_tuple(ret, 0);
231 
232   ret = event_listener_.Init();
233   if (ret) {
234     ALOGE("Can't initialize event listener %d", ret);
235     return std::make_tuple(ret, 0);
236   }
237 
238   for (auto &conn : connectors_) {
239     ret = CreateDisplayPipe(conn.get());
240     if (ret) {
241       ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret);
242       return std::make_tuple(ret, 0);
243     }
244     if (!AttachWriteback(conn.get())) {
245       ALOGI("Display %d has writeback attach to it", conn->display());
246     }
247   }
248   return std::make_tuple(ret, displays_.size());
249 }
250 
HandlesDisplay(int display) const251 bool DrmDevice::HandlesDisplay(int display) const {
252   return displays_.find(display) != displays_.end();
253 }
254 
GetConnectorForDisplay(int display) const255 DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const {
256   for (auto &conn : connectors_) {
257     if (conn->display() == display)
258       return conn.get();
259   }
260   return NULL;
261 }
262 
GetWritebackConnectorForDisplay(int display) const263 DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const {
264   for (auto &conn : writeback_connectors_) {
265     if (conn->display() == display)
266       return conn.get();
267   }
268   return NULL;
269 }
270 
271 // TODO what happens when hotplugging
AvailableWritebackConnector(int display) const272 DrmConnector *DrmDevice::AvailableWritebackConnector(int display) const {
273   DrmConnector *writeback_conn = GetWritebackConnectorForDisplay(display);
274   DrmConnector *display_conn = GetConnectorForDisplay(display);
275   // If we have a writeback already attached to the same CRTC just use that,
276   // if possible.
277   if (display_conn && writeback_conn &&
278       writeback_conn->encoder()->CanClone(display_conn->encoder()))
279     return writeback_conn;
280 
281   // Use another CRTC if available and doesn't have any connector
282   for (auto &crtc : crtcs_) {
283     if (crtc->has_display(display))
284       continue;
285     for (auto it: crtc->displays()) {
286       display_conn = GetConnectorForDisplay(it);
287       // If we have a display connected don't use it for writeback
288       if (display_conn && display_conn->state() == DRM_MODE_CONNECTED)
289         continue;
290       writeback_conn = GetWritebackConnectorForDisplay(it);
291       if (writeback_conn)
292         return writeback_conn;
293     }
294   }
295   return NULL;
296 }
297 
GetCrtcForDisplay(int display) const298 DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
299   for (auto &crtc : crtcs_) {
300     if (crtc->has_display(display))
301       return crtc.get();
302   }
303   return NULL;
304 }
305 
GetPlane(uint32_t id) const306 DrmPlane *DrmDevice::GetPlane(uint32_t id) const {
307   for (auto &plane : planes_) {
308     if (plane->id() == id)
309       return plane.get();
310   }
311   return NULL;
312 }
313 
crtcs() const314 const std::vector<std::unique_ptr<DrmCrtc>> &DrmDevice::crtcs() const {
315   return crtcs_;
316 }
317 
next_mode_id()318 uint32_t DrmDevice::next_mode_id() {
319   return ++mode_id_;
320 }
321 
TryEncoderForDisplay(int display,DrmEncoder * enc)322 int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) {
323   /* First try to use the currently-bound crtc */
324   DrmCrtc *crtc = enc->crtc();
325   if (crtc && crtc->can_bind(display)) {
326     crtc->set_display(display);
327     enc->set_crtc(crtc, display);
328     return 0;
329   }
330 
331   /* Try to find a possible crtc which will work */
332   for (DrmCrtc *crtc : enc->possible_crtcs()) {
333     /* We've already tried this earlier */
334     if (crtc == enc->crtc())
335       continue;
336 
337     if (crtc->can_bind(display)) {
338       crtc->set_display(display);
339       enc->set_crtc(crtc, display);
340       return 0;
341     }
342   }
343 
344   /* We can't use the encoder, but nothing went wrong, try another one */
345   return -EAGAIN;
346 }
347 
CreateDisplayPipe(DrmConnector * connector)348 int DrmDevice::CreateDisplayPipe(DrmConnector *connector) {
349   int display = connector->display();
350   /* Try to use current setup first */
351   if (connector->encoder()) {
352     int ret = TryEncoderForDisplay(display, connector->encoder());
353     if (!ret) {
354       return 0;
355     } else if (ret != -EAGAIN) {
356       ALOGE("Could not set mode %d/%d", display, ret);
357       return ret;
358     }
359   }
360 
361   for (DrmEncoder *enc : connector->possible_encoders()) {
362     int ret = TryEncoderForDisplay(display, enc);
363     if (!ret) {
364       connector->set_encoder(enc);
365       return 0;
366     } else if (ret != -EAGAIN) {
367       ALOGE("Could not set mode %d/%d", display, ret);
368       return ret;
369     }
370   }
371 
372   /* Create pipe with the first crtc */
373   for (DrmEncoder *enc : connector->possible_encoders()) {
374     if (!enc->can_bind(display))
375       continue;
376     if (enc->possible_crtcs().size() > 0) {
377       DrmCrtc *crtc = enc->possible_crtcs().at(0);
378       crtc->set_display(display);
379       enc->set_crtc(crtc, display);
380       ALOGD("crtc is connected to multiple connector (%zu)",
381           crtc->displays().size());
382       connector->set_encoder(enc);
383       return 0;
384     }
385   }
386 
387   ALOGE("Could not find a suitable encoder/crtc for display %d",
388         connector->display());
389   return -ENODEV;
390 }
391 
392 // Attach writeback connector to the CRTC linked to the display_conn
AttachWriteback(DrmConnector * display_conn)393 int DrmDevice::AttachWriteback(DrmConnector *display_conn) {
394   DrmCrtc *display_crtc = display_conn->encoder()->crtc();
395 
396   for (auto it: display_crtc->displays()) {
397     if (GetWritebackConnectorForDisplay(it) != NULL) {
398       ALOGE("Display already has writeback attach to it");
399       return -EINVAL;
400     }
401   }
402 
403   for (auto it: display_crtc->displays()) {
404     for (auto &writeback_conn : writeback_connectors_) {
405       if (writeback_conn->display() >= 0)
406         continue;
407       for (DrmEncoder *writeback_enc : writeback_conn->possible_encoders()) {
408         for (DrmCrtc *possible_crtc : writeback_enc->possible_crtcs()) {
409           if (possible_crtc != display_crtc)
410             continue;
411           // Use just encoders which had not been bound already
412           if (writeback_enc->can_bind(it)) {
413             writeback_enc->set_crtc(display_crtc, it);
414             writeback_conn->set_encoder(writeback_enc);
415             writeback_conn->set_display(it);
416             writeback_conn->UpdateModes();
417             return 0;
418           }
419         }
420       }
421     }
422   }
423   return -EINVAL;
424 }
425 
CreatePropertyBlob(const void * data,size_t length,uint32_t * blob_id)426 int DrmDevice::CreatePropertyBlob(const void *data, size_t length, uint32_t *blob_id) {
427   struct drm_mode_create_blob create_blob;
428   memset(&create_blob, 0, sizeof(create_blob));
429   create_blob.length = length;
430   create_blob.data = (__u64)data;
431 
432   int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
433   if (ret) {
434     ALOGE("Failed to create mode property blob %d", ret);
435     return ret;
436   }
437   *blob_id = create_blob.blob_id;
438   return 0;
439 }
440 
DestroyPropertyBlob(uint32_t blob_id)441 int DrmDevice::DestroyPropertyBlob(uint32_t blob_id) {
442   if (!blob_id)
443     return 0;
444 
445   struct drm_mode_destroy_blob destroy_blob;
446   memset(&destroy_blob, 0, sizeof(destroy_blob));
447   destroy_blob.blob_id = (__u32)blob_id;
448   int ret = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob);
449   if (ret) {
450     ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", blob_id, ret);
451     return ret;
452   }
453   return 0;
454 }
455 
event_listener()456 DrmEventListener *DrmDevice::event_listener() {
457   return &event_listener_;
458 }
459 
GetProperty(uint32_t obj_id,uint32_t obj_type,const char * prop_name,DrmProperty * property)460 int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
461                            const char *prop_name, DrmProperty *property) {
462   drmModeObjectPropertiesPtr props;
463 
464   props = drmModeObjectGetProperties(fd(), obj_id, obj_type);
465   if (!props) {
466     ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
467     return -ENODEV;
468   }
469 
470   bool found = false;
471   for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
472     drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]);
473     if (!strcmp(p->name, prop_name)) {
474       property->init(p, props->prop_values[i]);
475       found = true;
476     }
477     drmModeFreeProperty(p);
478   }
479 
480   if (!found)
481     property->setName(prop_name);
482 
483   drmModeFreeObjectProperties(props);
484   return found ? 0 : -ENOENT;
485 }
486 
GetPlaneProperty(const DrmPlane & plane,const char * prop_name,DrmProperty * property)487 int DrmDevice::GetPlaneProperty(const DrmPlane &plane, const char *prop_name,
488                                 DrmProperty *property) {
489   return GetProperty(plane.id(), DRM_MODE_OBJECT_PLANE, prop_name, property);
490 }
491 
GetCrtcProperty(const DrmCrtc & crtc,const char * prop_name,DrmProperty * property)492 int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
493                                DrmProperty *property) {
494   return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property);
495 }
496 
GetConnectorProperty(const DrmConnector & connector,const char * prop_name,DrmProperty * property)497 int DrmDevice::GetConnectorProperty(const DrmConnector &connector,
498                                     const char *prop_name,
499                                     DrmProperty *property) {
500   return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
501                      property);
502 }
503 
UpdateObjectProperty(int id,int type,DrmProperty * property)504 int DrmDevice::UpdateObjectProperty(int id, int type, DrmProperty *property) {
505     drmModeObjectPropertiesPtr props;
506     props = drmModeObjectGetProperties(fd(), id, type);
507     if (!props) {
508         ALOGE("Failed to get properties for crtc %s", property->name().c_str());
509         return -ENODEV;
510     }
511     bool found = false;
512     for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
513         drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]);
514         if (props->props[i] == property->id()) {
515             property->updateValue(props->prop_values[i]);
516             found = true;
517         }
518         drmModeFreeProperty(p);
519     }
520     drmModeFreeObjectProperties(props);
521     return found ? 0 : -ENOENT;
522 }
523 
UpdateCrtcProperty(const DrmCrtc & crtc,DrmProperty * property)524 int DrmDevice::UpdateCrtcProperty(const DrmCrtc &crtc, DrmProperty *property) {
525     return UpdateObjectProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, property);
526 }
527 
UpdateConnectorProperty(const DrmConnector & conn,DrmProperty * property)528 int DrmDevice::UpdateConnectorProperty(const DrmConnector &conn, DrmProperty *property) {
529     return UpdateObjectProperty(conn.id(), DRM_MODE_OBJECT_CONNECTOR, property);
530 }
531 
CallVendorIoctl(unsigned long request,void * arg)532 int DrmDevice::CallVendorIoctl(unsigned long request, void *arg) {
533     int ret = drmIoctl(fd(), request, arg);
534     if (ret) {
535         ALOGE("Failed to call vendor ioctl %lu ioctl_ret= %d", request, ret);
536         return ret;
537     }
538 
539     return 0;
540 }
541 }  // namespace android
542