1 /**************************************************************************
5 Copyright 2017 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 **************************************************************************/
35 #include "tdm_backend_nexell.h"
42 #define HAL_TDM_NEXELL_ENABLE_HWC 1
44 #define HAL_TDM_NEXELL_NAME "nexell"
47 static struct udev_device *
48 _tdm_find_primary_gpu(void)
51 struct udev_enumerate *e;
52 struct udev_list_entry *entry;
53 const char *path, *id;
54 struct udev_device *device, *drm_device, *pci;
58 TDM_BACKEND_ERR("fail to initialize udev context\n");
62 e = udev_enumerate_new(udev);
63 udev_enumerate_add_match_subsystem(e, "drm");
64 udev_enumerate_add_match_sysname(e, "card[0-9]*");
66 udev_enumerate_scan_devices(e);
68 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
69 path = udev_list_entry_get_name(entry);
70 device = udev_device_new_from_syspath(udev, path);
74 pci = udev_device_get_parent_with_subsystem_devtype(device, "pci", NULL);
76 id = udev_device_get_sysattr_value(pci, "boot_vga");
77 if (id && !strcmp(id, "1")) {
79 udev_device_unref(drm_device);
88 udev_device_unref(device);
91 udev_enumerate_unref(e);
97 _tdm_nexell_udev_fd_handler(int fd, hal_tdm_event_loop_mask mask, void *user_data)
99 tdm_nexell_display *display_data = (tdm_nexell_display*)user_data;
100 struct udev_device *dev;
106 dev = udev_monitor_receive_device(display_data->uevent_monitor);
108 TDM_BACKEND_ERR("couldn't receive device");
109 return HAL_TDM_ERROR_OPERATION_FAILED;
112 udev_devnum = udev_device_get_devnum(dev);
114 ret = fstat(display_data->drm_fd, &s);
116 TDM_BACKEND_ERR("fstat failed");
117 udev_device_unref(dev);
118 return HAL_TDM_ERROR_OPERATION_FAILED;
121 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
123 if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
124 hotplug && atoi(hotplug) == 1)
126 TDM_BACKEND_INFO("HotPlug");
127 tdm_nexell_display_update_output_status(display_data);
130 udev_device_unref(dev);
132 return HAL_TDM_ERROR_NONE;
135 static struct udev_monitor *
136 _tdm_nexell_create_udev_monitor()
138 struct udev *u = NULL;
139 struct udev_monitor *mon = NULL;
143 TDM_BACKEND_ERR("couldn't create udev");
147 mon = udev_monitor_new_from_netlink(u, "udev");
149 TDM_BACKEND_ERR("couldn't create udev monitor");
153 if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
154 udev_monitor_enable_receiving(mon) < 0) {
155 TDM_BACKEND_ERR("add match subsystem failed");
159 TDM_BACKEND_INFO("hotplug monitor created");
165 udev_monitor_unref(mon);
173 _tdm_nexell_destroy_udev_monitor(struct udev_monitor *mon)
180 u = udev_monitor_get_udev(mon);
181 udev_monitor_unref(mon);
184 TDM_BACKEND_INFO("hotplug monitor destroyed");
189 _tdm_nexell_open_drm(void)
193 fd = drmOpen(HAL_TDM_NEXELL_NAME, NULL);
195 TDM_BACKEND_WRN("Cannot open '%s' drm", HAL_TDM_NEXELL_NAME);
199 struct udev_device *drm_device = NULL;
200 const char *filename;
201 TDM_BACKEND_WRN("Cannot open drm device.. search by udev");
203 drm_device = _tdm_find_primary_gpu();
204 if (drm_device == NULL) {
205 TDM_BACKEND_ERR("fail to find drm device\n");
209 filename = udev_device_get_devnode(drm_device);
211 fd = open(filename, O_RDWR | O_CLOEXEC);
213 TDM_BACKEND_ERR("Cannot open drm device(%s)\n", filename);
215 TDM_BACKEND_DBG("open drm device (name:%s, fd:%d)", filename, fd);
217 udev_device_unref(drm_device);
226 _tdm_nexell_display_deinitialize(tdm_nexell_display *display_data)
228 tdm_nexell_display_destroy_output_list(display_data);
229 tdm_nexell_display_destroy_buffer_list(display_data);
231 if (display_data->plane_res)
232 drmModeFreePlaneResources(display_data->plane_res);
233 if (display_data->mode_res)
234 drmModeFreeResources(display_data->mode_res);
238 _tdm_nexell_display_initialize(tdm_nexell_display *display_data)
242 display_data->scaler_fd = open("/dev/scaler", O_RDWR);
243 if (display_data->scaler_fd < 0)
244 TDM_BACKEND_ERR("scaler open fail. cannot use pp.");
246 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
247 if (drmSetClientCap(display_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
248 TDM_BACKEND_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
250 TDM_BACKEND_INFO("has universal planes");
251 display_data->has_universal_plane = 1;
254 if (drmSetClientCap(display_data->drm_fd, DRM_CLIENT_CAP_ATOMIC, 1) < 0) {
255 TDM_BACKEND_WRN("Set DRM_CLIENT_CAP_ATOMIC failed");
257 TDM_BACKEND_INFO("has atomic");
258 display_data->has_atomic = 1;
262 display_data->mode_res = drmModeGetResources(display_data->drm_fd);
263 if (!display_data->mode_res) {
264 TDM_BACKEND_ERR("no drm resource: %m");
265 ret = HAL_TDM_ERROR_OPERATION_FAILED;
269 display_data->plane_res = drmModeGetPlaneResources(display_data->drm_fd);
270 if (!display_data->plane_res) {
271 TDM_BACKEND_ERR("no drm plane resource: %m");
272 ret = HAL_TDM_ERROR_OPERATION_FAILED;
276 if (display_data->plane_res->count_planes <= 0) {
277 TDM_BACKEND_ERR("no drm plane resource");
278 ret = HAL_TDM_ERROR_OPERATION_FAILED;
282 ret = tdm_nexell_display_create_output_list(display_data);
283 if (ret != HAL_TDM_ERROR_NONE)
286 ret = tdm_nexell_display_create_layer_list(display_data);
287 if (ret != HAL_TDM_ERROR_NONE)
293 _tdm_nexell_display_deinitialize(display_data);
299 _tdm_nexell_master_drm_fd_handler(hal_tdm_fd master_drm_fd, void *user_data)
301 tdm_nexell_display *display_data = (tdm_nexell_display *) user_data;
304 TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
306 display_data->drm_fd = master_drm_fd;
307 TDM_BACKEND_INFO("Get the master drm_fd(%d)!\n", display_data->drm_fd);
309 // initialize display with a master drm_fd
310 ret = _tdm_nexell_display_initialize(display_data);
311 if (ret != HAL_TDM_ERROR_NONE) {
312 TDM_BACKEND_ERR("fail to _tdm_nexell_display_initialize!\n");
314 return HAL_TDM_ERROR_OPERATION_FAILED;
317 return HAL_TDM_ERROR_NONE;
321 hal_backend_tdm_nexell_exit(void *data)
323 hal_tdm_backend_data *backend_data = (hal_tdm_backend_data *)data;
324 tdm_nexell_display *display_data;
326 TDM_BACKEND_INFO("deinit");
328 TDM_BACKEND_RETURN_VAL_IF_FAIL(backend_data != NULL, -1);
330 display_data = (tdm_nexell_display *)backend_data->display;
331 TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, -1);
333 if (backend_data->pp_funcs) {
334 free(backend_data->pp_funcs);
335 backend_data->pp_funcs = NULL;
337 if (backend_data->hwc_window_funcs) {
338 free(backend_data->hwc_window_funcs);
339 backend_data->hwc_window_funcs = NULL;
341 if (backend_data->hwc_funcs) {
342 free(backend_data->hwc_funcs);
343 backend_data->hwc_funcs = NULL;
345 if (backend_data->output_funcs) {
346 free(backend_data->output_funcs);
347 backend_data->output_funcs = NULL;
349 if (backend_data->display_funcs) {
350 free(backend_data->display_funcs);
351 backend_data->display_funcs = NULL;
354 _tdm_nexell_display_deinitialize(display_data);
357 if (display_data->uevent_monitor)
358 _tdm_nexell_destroy_udev_monitor(display_data->uevent_monitor);
361 if (display_data->drm_fd >= 0)
362 close(display_data->drm_fd);
367 return HAL_TDM_ERROR_NONE;
371 hal_backend_tdm_nexell_init(void **data)
373 hal_tdm_backend_data *backend_data = NULL;
374 hal_tdm_display_funcs *display_funcs = NULL;
375 hal_tdm_output_funcs *output_funcs = NULL;
376 hal_tdm_hwc_funcs *hwc_funcs = NULL;
377 hal_tdm_hwc_window_funcs *hwc_window_funcs = NULL;
379 hal_tdm_pp_funcs *pp_funcs = NULL;
381 tdm_nexell_display *display_data = NULL;
385 static struct udev_monitor *mon;
386 hal_tdm_event_source *udev_event_source;
389 /* allocate a hal_tdm_backend_data */
390 backend_data = calloc(1, sizeof(struct _hal_tdm_backend_data));
392 TDM_BACKEND_ERR("fail to alloc backend_data!\n");
396 *data = backend_data;
398 /* allocate a hal_tdm_display */
399 display_data = calloc(1, sizeof(struct _tdm_nexell_display));
401 TDM_BACKEND_ERR("fail to alloc display_data!\n");
404 backend_data->display = (hal_tdm_display *)display_data;
406 LIST_INITHEAD(&display_data->output_list);
407 LIST_INITHEAD(&display_data->buffer_list);
409 // check if drm_fd is master fd.
410 drm_fd = _tdm_nexell_open_drm();
412 ret = HAL_TDM_ERROR_OPERATION_FAILED;
416 // set true when backend has a drm_device.
417 backend_data->has_drm_device = 1;
419 if (drmIsMaster(drm_fd)) {
420 // drm_fd is a master drm_fd.
421 backend_data->drm_info.drm_fd = drm_fd;
422 backend_data->drm_info.is_master = 1;
424 display_data->drm_fd = drm_fd;
425 TDM_BACKEND_INFO("Get the master drm_fd(%d)!\n", display_data->drm_fd);
427 // initialize display with a master drm_fd
428 ret = _tdm_nexell_display_initialize(display_data);
429 if (ret != HAL_TDM_ERROR_NONE) {
430 TDM_BACKEND_ERR("fail to _tdm_nexell_display_initialize!\n");
434 // drm_fd is not a master drm_fd.
435 // request a master drm_fd
437 backend_data->drm_info.drm_fd = -1;
438 backend_data->drm_info.is_master = 0;
439 backend_data->drm_info.master_drm_fd_func = _tdm_nexell_master_drm_fd_handler;
440 backend_data->drm_info.user_data = display_data;
442 TDM_BACKEND_INFO("A backend requests an master drm_fd.\n");
446 mon = _tdm_nexell_create_udev_monitor();
448 ret = HAL_TDM_ERROR_OPERATION_FAILED;
451 display_data->uevent_monitor = mon;
453 /* alloc and register udev_event_source */
454 udev_event_source = calloc(1, sizeof(struct _hal_tdm_event_source));
455 if (!udev_event_source) {
456 TDM_BACKEND_ERR("fail to alloc udev_event_source!\n");
459 udev_event_source->event_fd = udev_monitor_get_fd(mon);
460 udev_event_source->func = _tdm_nexell_udev_fd_handler;
461 udev_event_source->user_data = display_data;
463 backend_data->event_sources[0] = udev_event_source;
464 backend_data->num_event_sources++;
467 /* alloc and register display_funcs */
468 display_funcs = calloc(1, sizeof(struct _hal_tdm_display_funcs));
469 if (!display_funcs) {
470 TDM_BACKEND_ERR("fail to alloc display_funcs!\n");
473 backend_data->display_funcs = display_funcs;
475 display_funcs->display_get_capability = nexell_display_get_capability;
476 display_funcs->display_get_pp_capability = nexell_display_get_pp_capability;
477 display_funcs->display_get_outputs = nexell_display_get_outputs;
478 display_funcs->display_get_fd = nexell_display_get_fd;
479 display_funcs->display_handle_events = nexell_display_handle_events;
480 display_funcs->display_create_pp = nexell_display_create_pp;
482 /* alloc and register output_funcs */
483 output_funcs = calloc(1, sizeof(struct _hal_tdm_output_funcs));
485 TDM_BACKEND_ERR("fail to alloc output_funcs!\n");
488 backend_data->output_funcs = output_funcs;
490 output_funcs->output_get_capability = nexell_output_get_capability;
491 output_funcs->output_set_property = nexell_output_set_property;
492 output_funcs->output_get_property = nexell_output_get_property;
493 output_funcs->output_wait_vblank = nexell_output_wait_vblank;
494 output_funcs->output_set_vblank_handler = nexell_output_set_vblank_handler;
495 output_funcs->output_set_dpms = nexell_output_set_dpms;
496 output_funcs->output_get_dpms = nexell_output_get_dpms;
497 output_funcs->output_set_mode = nexell_output_set_mode;
498 output_funcs->output_get_mode = nexell_output_get_mode;
499 output_funcs->output_set_mirror = NULL;
500 output_funcs->output_unset_mirror = NULL;
502 output_funcs->output_set_status_handler = nexell_output_set_status_handler;
504 output_funcs->output_get_hwc = nexell_output_get_hwc;
506 /* alloc and register hwc_funcs */
507 hwc_funcs = calloc(1, sizeof(struct _hal_tdm_hwc_funcs));
509 TDM_BACKEND_ERR("fail to alloc hwc_funcs!\n");
512 backend_data->hwc_funcs = hwc_funcs;
514 hwc_funcs->hwc_create_window = nexell_hwc_create_window;
515 hwc_funcs->hwc_get_video_supported_formats = nexell_hwc_get_video_supported_formats;
516 hwc_funcs->hwc_get_video_available_properties = NULL;
517 hwc_funcs->hwc_get_capabilities = nexell_hwc_get_capabilities;
518 hwc_funcs->hwc_get_available_properties = nexell_hwc_get_available_properties;
519 hwc_funcs->hwc_get_client_target_buffer_queue = nexell_hwc_get_client_target_buffer_queue;
520 hwc_funcs->hwc_set_client_target_buffer = nexell_hwc_set_client_target_buffer;
521 hwc_funcs->hwc_set_client_target_acquire_fence = NULL;
522 hwc_funcs->hwc_validate = nexell_hwc_validate;
523 hwc_funcs->hwc_get_changed_composition_types = nexell_hwc_get_changed_composition_types;
524 hwc_funcs->hwc_accept_validation = nexell_hwc_accept_validation;
525 hwc_funcs->hwc_commit = nexell_hwc_commit;
526 hwc_funcs->hwc_set_commit_handler = nexell_hwc_set_commit_handler;
527 hwc_funcs->hwc_get_commit_fence = NULL;
528 hwc_funcs->hwc_get_release_fences = NULL;
530 /* alloc and register hwc_window_funcs */
531 hwc_window_funcs = calloc(1, sizeof(struct _hal_tdm_hwc_window_funcs));
532 if (!hwc_window_funcs) {
533 TDM_BACKEND_ERR("fail to alloc hwc_window_funcs!\n");
536 backend_data->hwc_window_funcs = hwc_window_funcs;
538 hwc_window_funcs->hwc_window_destroy = nexell_hwc_window_destroy;
539 hwc_window_funcs->hwc_window_acquire_buffer_queue = nexell_hwc_window_acquire_buffer_queue;
540 hwc_window_funcs->hwc_window_release_buffer_queue = nexell_hwc_window_release_buffer_queue;
541 hwc_window_funcs->hwc_window_set_composition_type = nexell_hwc_window_set_composition_type;
542 hwc_window_funcs->hwc_window_set_buffer_damage = nexell_hwc_window_set_buffer_damage;
543 hwc_window_funcs->hwc_window_set_info = nexell_hwc_window_set_info;
544 hwc_window_funcs->hwc_window_set_buffer = nexell_hwc_window_set_buffer;
545 hwc_window_funcs->hwc_window_set_property = nexell_hwc_window_set_property;
546 hwc_window_funcs->hwc_window_get_property = nexell_hwc_window_get_property;
547 hwc_window_funcs->hwc_window_get_constraints = nexell_hwc_window_get_constraints;
548 hwc_window_funcs->hwc_window_set_name = nexell_hwc_window_set_name;
549 hwc_window_funcs->hwc_window_set_cursor_image = nexell_hwc_window_set_cursor_image;
552 /* alloc and register pp_funcs */
553 pp_funcs = calloc(1, sizeof(struct _hal_tdm_pp_funcs));
555 TDM_BACKEND_ERR("fail to alloc pp_funcs!\n");
558 backend_data->pp_funcs = pp_funcs;
560 pp_funcs->pp_destroy = nexell_pp_destroy;
561 pp_funcs->pp_set_info = nexell_pp_set_info;
562 pp_funcs->pp_attach = nexell_pp_attach;
563 pp_funcs->pp_commit = nexell_pp_commit;
564 pp_funcs->pp_set_done_handler = nexell_pp_set_done_handler;
567 TDM_BACKEND_INFO("init success!");
569 return HAL_TDM_ERROR_NONE;
572 TDM_BACKEND_ERR("init failed!");
574 hal_backend_tdm_nexell_exit((void *)backend_data);
579 hal_backend hal_backend_tdm_data = {
582 HAL_ABI_VERSION_TIZEN_6_5,
583 hal_backend_tdm_nexell_init,
584 hal_backend_tdm_nexell_exit