1 /**************************************************************************
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
7 Contact: SooChan Lim <sc1.lim@samsung.com>
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 **************************************************************************/
40 #include <tdm_helper.h>
41 #include <tbm_drm_helper.h>
45 #define TDM_DRM_NAME "vigs"
49 static tdm_drm_data *drm_data;
52 static struct udev_device *
53 _tdm_find_primary_gpu(void)
56 struct udev_enumerate *e;
57 struct udev_list_entry *entry;
58 const char *path, *id;
59 struct udev_device *device, *drm_device, *pci;
63 TDM_ERR("fail to initialize udev context\n");
67 e = udev_enumerate_new(udev);
68 udev_enumerate_add_match_subsystem(e, "drm");
69 udev_enumerate_add_match_sysname(e, "card[0-9]*");
71 udev_enumerate_scan_devices(e);
73 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
74 path = udev_list_entry_get_name(entry);
75 device = udev_device_new_from_syspath(udev, path);
79 pci = udev_device_get_parent_with_subsystem_devtype(device,
82 id = udev_device_get_sysattr_value(pci, "boot_vga");
83 if (id && !strcmp(id, "1")) {
85 udev_device_unref(drm_device);
94 udev_device_unref(device);
97 udev_enumerate_unref(e);
102 _tdm_drm_udev_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
104 tdm_drm_data *edata = (tdm_drm_data*)user_data;
105 struct udev_device *dev;
111 dev = udev_monitor_receive_device(edata->uevent_monitor);
113 TDM_ERR("couldn't receive device");
114 return TDM_ERROR_OPERATION_FAILED;
117 udev_devnum = udev_device_get_devnum(dev);
119 ret = fstat(edata->drm_fd, &s);
121 TDM_ERR("fstat failed");
122 udev_device_unref(dev);
123 return TDM_ERROR_OPERATION_FAILED;
126 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
128 if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
129 hotplug && atoi(hotplug) == 1) {
131 tdm_drm_display_update_output_status(edata);
134 udev_device_unref(dev);
136 return TDM_ERROR_NONE;
140 _tdm_drm_udev_init(tdm_drm_data *edata)
142 struct udev *u = NULL;
143 struct udev_monitor *mon = NULL;
147 TDM_ERR("couldn't create udev");
151 mon = udev_monitor_new_from_netlink(u, "udev");
153 TDM_ERR("couldn't create udev monitor");
157 if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
158 udev_monitor_enable_receiving(mon) < 0) {
159 TDM_ERR("add match subsystem failed");
163 edata->uevent_source =
164 tdm_event_loop_add_fd_handler(edata->dpy, udev_monitor_get_fd(mon),
165 TDM_EVENT_LOOP_READABLE,
166 _tdm_drm_udev_fd_handler,
168 if (!edata->uevent_source) {
169 TDM_ERR("couldn't create udev event source");
173 edata->uevent_monitor = mon;
175 TDM_INFO("hotplug monitor created");
180 udev_monitor_unref(mon);
186 _tdm_drm_udev_deinit(tdm_drm_data *edata)
188 if (edata->uevent_source) {
189 tdm_event_loop_source_remove(edata->uevent_source);
190 edata->uevent_source = NULL;
193 if (edata->uevent_monitor) {
194 struct udev *u = udev_monitor_get_udev(edata->uevent_monitor);
195 udev_monitor_unref(edata->uevent_monitor);
197 edata->uevent_monitor = NULL;
198 TDM_INFO("hotplug monitor destroyed");
204 _tdm_drm_open_drm(void)
208 fd = drmOpen(TDM_DRM_NAME, NULL);
210 TDM_WRN("Cannot open '%s' drm", TDM_DRM_NAME);
214 struct udev_device *drm_device = NULL;
215 const char *filename;
216 TDM_WRN("Cannot open drm device.. search by udev");
218 drm_device = _tdm_find_primary_gpu();
219 if (drm_device == NULL) {
220 TDM_ERR("fail to find drm device\n");
224 filename = udev_device_get_devnode(drm_device);
226 fd = open(filename, O_RDWR | O_CLOEXEC);
228 TDM_ERR("Cannot open drm device(%s)\n", filename);
230 TDM_DBG("open drm device (name:%s, fd:%d)", filename, fd);
232 udev_device_unref(drm_device);
240 tdm_drm_deinit(tdm_backend_data *bdata)
242 if (drm_data != bdata)
248 _tdm_drm_udev_deinit(drm_data);
251 tdm_drm_display_destroy_output_list(drm_data);
253 if (drm_data->plane_res)
254 drmModeFreePlaneResources(drm_data->plane_res);
255 if (drm_data->mode_res)
256 drmModeFreeResources(drm_data->mode_res);
257 if (drm_data->drm_fd >= 0)
258 close(drm_data->drm_fd);
265 tdm_drm_init(tdm_display *dpy, tdm_error *error)
267 tdm_func_display drm_func_display;
268 tdm_func_output drm_func_output;
269 tdm_func_layer drm_func_layer;
270 tdm_func_hwc drm_func_hwc;
271 tdm_func_hwc_window drm_func_hwc_window;
273 tdm_func_pp drm_func_pp;
278 TDM_ERR("display is null");
280 *error = TDM_ERROR_INVALID_PARAMETER;
285 TDM_ERR("failed: init twice");
287 *error = TDM_ERROR_BAD_REQUEST;
291 drm_data = calloc(1, sizeof(tdm_drm_data));
293 TDM_ERR("alloc failed");
295 *error = TDM_ERROR_OUT_OF_MEMORY;
300 /* enable the tdm_hwc */
301 drm_data->hwc_mode = 1;
304 LIST_INITHEAD(&drm_data->output_list);
305 LIST_INITHEAD(&drm_data->buffer_list);
307 memset(&drm_func_display, 0, sizeof(drm_func_display));
308 drm_func_display.display_get_capability = drm_display_get_capability;
309 drm_func_display.display_get_pp_capability = drm_display_get_pp_capability;
310 drm_func_display.display_get_outputs = drm_display_get_outputs;
311 drm_func_display.display_get_fd = drm_display_get_fd;
312 drm_func_display.display_handle_events = drm_display_handle_events;
313 drm_func_display.display_create_pp = drm_display_create_pp;
315 memset(&drm_func_output, 0, sizeof(drm_func_output));
316 drm_func_output.output_get_capability = drm_output_get_capability;
317 drm_func_output.output_get_layers = drm_output_get_layers;
318 drm_func_output.output_set_property = drm_output_set_property;
319 drm_func_output.output_get_property = drm_output_get_property;
320 drm_func_output.output_wait_vblank = drm_output_wait_vblank;
321 drm_func_output.output_set_vblank_handler = drm_output_set_vblank_handler;
322 drm_func_output.output_commit = drm_output_commit;
323 drm_func_output.output_set_commit_handler = drm_output_set_commit_handler;
324 drm_func_output.output_set_dpms = drm_output_set_dpms;
325 drm_func_output.output_get_dpms = drm_output_get_dpms;
326 drm_func_output.output_set_mode = drm_output_set_mode;
327 drm_func_output.output_get_mode = drm_output_get_mode;
329 drm_func_output.output_set_status_handler = drm_output_set_status_handler;
332 if (drm_data->hwc_mode) {
333 drm_func_output.output_get_hwc = drm_output_get_hwc;
335 memset(&drm_func_hwc, 0, sizeof(drm_func_hwc));
336 drm_func_hwc.hwc_create_window = drm_hwc_create_window;
337 drm_func_hwc.hwc_get_video_supported_formats = drm_hwc_get_video_supported_formats;
338 drm_func_hwc.hwc_get_video_available_properties = NULL;
339 drm_func_hwc.hwc_get_capabilities = drm_hwc_get_capabilities;
340 drm_func_hwc.hwc_get_available_properties = drm_hwc_get_available_properties;
341 drm_func_hwc.hwc_get_client_target_buffer_queue = drm_hwc_get_client_target_buffer_queue;
342 drm_func_hwc.hwc_set_client_target_buffer = drm_hwc_set_client_target_buffer;
343 drm_func_hwc.hwc_validate = drm_hwc_validate;
344 drm_func_hwc.hwc_get_changed_composition_types = drm_hwc_get_changed_composition_types;
345 drm_func_hwc.hwc_accept_validation = drm_hwc_accept_validation;
346 drm_func_hwc.hwc_commit = drm_hwc_commit;
347 drm_func_hwc.hwc_set_commit_handler = drm_hwc_set_commit_handler;
349 memset(&drm_func_hwc_window, 0, sizeof(drm_func_hwc_window));
350 drm_func_hwc_window.hwc_window_destroy = drm_hwc_window_destroy;
351 drm_func_hwc_window.hwc_window_acquire_buffer_queue = NULL; // no need
352 drm_func_hwc_window.hwc_window_release_buffer_queue = NULL; // no need
353 drm_func_hwc_window.hwc_window_set_composition_type = drm_hwc_window_set_composition_type;
354 drm_func_hwc_window.hwc_window_set_buffer_damage = drm_hwc_window_set_buffer_damage;
355 drm_func_hwc_window.hwc_window_set_info = drm_hwc_window_set_info;
356 drm_func_hwc_window.hwc_window_set_buffer = drm_hwc_window_set_buffer;
357 drm_func_hwc_window.hwc_window_set_property = drm_hwc_window_set_property;
358 drm_func_hwc_window.hwc_window_get_property = drm_hwc_window_get_property;
359 drm_func_hwc_window.hwc_window_get_constraints = drm_hwc_window_get_constraints;
360 drm_func_hwc_window.hwc_window_set_name = drm_hwc_window_set_name;
361 drm_func_hwc_window.hwc_window_set_cursor_image = drm_hwc_window_set_cursor_image;
364 memset(&drm_func_layer, 0, sizeof(drm_func_layer));
365 drm_func_layer.layer_get_capability = drm_layer_get_capability;
366 drm_func_layer.layer_set_property = drm_layer_set_property;
367 drm_func_layer.layer_get_property = drm_layer_get_property;
368 drm_func_layer.layer_set_info = drm_layer_set_info;
369 drm_func_layer.layer_get_info = drm_layer_get_info;
370 drm_func_layer.layer_set_buffer = drm_layer_set_buffer;
371 drm_func_layer.layer_unset_buffer = drm_layer_unset_buffer;
374 memset(&drm_func_pp, 0, sizeof(drm_func_pp));
375 drm_func_pp.pp_destroy = drm_pp_destroy;
376 drm_func_pp.pp_set_info = drm_pp_set_info;
377 drm_func_pp.pp_attach = drm_pp_attach;
378 drm_func_pp.pp_commit = drm_pp_commit;
379 drm_func_pp.pp_set_done_handler = drm_pp_set_done_handler;
382 ret = tdm_backend_register_func_display(dpy, &drm_func_display);
383 if (ret != TDM_ERROR_NONE)
386 ret = tdm_backend_register_func_output(dpy, &drm_func_output);
387 if (ret != TDM_ERROR_NONE)
390 ret = tdm_backend_register_func_layer(dpy, &drm_func_layer);
391 if (ret != TDM_ERROR_NONE)
394 if (drm_data->hwc_mode) {
395 ret = tdm_backend_register_func_hwc(dpy, &drm_func_hwc);
396 if (ret != TDM_ERROR_NONE)
399 ret = tdm_backend_register_func_hwc_window(dpy, &drm_func_hwc_window);
400 if (ret != TDM_ERROR_NONE)
405 ret = tdm_backend_register_func_pp(dpy, &drm_func_pp);
406 if (ret != TDM_ERROR_NONE)
412 /* The drm master fd can be opened by a tbm backend module in
413 * tbm_bufmgr_init() time. In this case, we just get it from tbm.
415 drm_data->drm_fd = tbm_drm_helper_get_master_fd();
416 if (drm_data->drm_fd < 0) {
417 drm_data->drm_fd = _tdm_drm_open_drm();
419 if (drm_data->drm_fd < 0) {
420 ret = TDM_ERROR_OPERATION_FAILED;
424 tbm_drm_helper_set_tbm_master_fd(drm_data->drm_fd);
427 TDM_INFO("master fd: %d", drm_data->drm_fd);
430 _tdm_drm_udev_init(drm_data);
433 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
434 if (drmSetClientCap(drm_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
435 TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
437 TDM_INFO("has universal planes");
438 drm_data->has_universal_plane = 1;
442 drm_data->mode_res = drmModeGetResources(drm_data->drm_fd);
443 if (!drm_data->mode_res) {
444 TDM_ERR("no drm resource: %m");
445 ret = TDM_ERROR_OPERATION_FAILED;
449 drm_data->plane_res = drmModeGetPlaneResources(drm_data->drm_fd);
450 if (!drm_data->plane_res) {
451 TDM_ERR("no drm plane resource: %m");
452 ret = TDM_ERROR_OPERATION_FAILED;
456 if (drm_data->plane_res->count_planes <= 0) {
457 TDM_ERR("no drm plane resource");
458 ret = TDM_ERROR_OPERATION_FAILED;
462 ret = tdm_drm_display_create_output_list(drm_data);
463 if (ret != TDM_ERROR_NONE)
466 ret = tdm_drm_display_create_layer_list(drm_data);
467 if (ret != TDM_ERROR_NONE)
471 *error = TDM_ERROR_NONE;
473 TDM_INFO("init success!");
475 return (tdm_backend_data *)drm_data;
480 tdm_drm_deinit(drm_data);
482 TDM_ERR("init failed!");
486 tdm_backend_module tdm_backend_module_data = {
489 TDM_BACKEND_SET_ABI_VERSION(1, 1),