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 **************************************************************************/
39 #include "tdm_nexell.h"
40 #include <tdm_helper.h>
41 #include <tbm_drm_helper.h>
44 #define TDM_NEXELL_ENABLE_HWC 1
46 #define TDM_NEXELL_NAME "nexell"
48 static tdm_nexell_data *nexell_data;
51 static struct udev_device *
52 _tdm_find_primary_gpu(void)
55 struct udev_enumerate *e;
56 struct udev_list_entry *entry;
57 const char *path, *id;
58 struct udev_device *device, *drm_device, *pci;
62 TDM_ERR("fail to initialize udev context\n");
66 e = udev_enumerate_new(udev);
67 udev_enumerate_add_match_subsystem(e, "drm");
68 udev_enumerate_add_match_sysname(e, "card[0-9]*");
70 udev_enumerate_scan_devices(e);
72 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
73 path = udev_list_entry_get_name(entry);
74 device = udev_device_new_from_syspath(udev, path);
78 pci = udev_device_get_parent_with_subsystem_devtype(device,
81 id = udev_device_get_sysattr_value(pci, "boot_vga");
82 if (id && !strcmp(id, "1")) {
84 udev_device_unref(drm_device);
93 udev_device_unref(device);
96 udev_enumerate_unref(e);
101 _tdm_nexell_udev_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
103 tdm_nexell_data *display_data = (tdm_nexell_data*)user_data;
104 struct udev_device *dev;
110 dev = udev_monitor_receive_device(display_data->uevent_monitor);
112 TDM_ERR("couldn't receive device");
113 return TDM_ERROR_OPERATION_FAILED;
116 udev_devnum = udev_device_get_devnum(dev);
118 ret = fstat(display_data->drm_fd, &s);
120 TDM_ERR("fstat failed");
121 udev_device_unref(dev);
122 return TDM_ERROR_OPERATION_FAILED;
125 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
127 if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
128 hotplug && atoi(hotplug) == 1)
131 tdm_nexell_display_update_output_status(display_data);
134 udev_device_unref(dev);
136 return TDM_ERROR_NONE;
140 _tdm_nexell_udev_init(tdm_nexell_data *display_data)
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 display_data->uevent_source =
164 tdm_event_loop_add_fd_handler(display_data->dpy, udev_monitor_get_fd(mon),
165 TDM_EVENT_LOOP_READABLE,
166 _tdm_nexell_udev_fd_handler,
168 if (!display_data->uevent_source) {
169 TDM_ERR("couldn't create udev event source");
173 display_data->uevent_monitor = mon;
175 TDM_INFO("hotplug monitor created");
180 udev_monitor_unref(mon);
186 _tdm_nexell_udev_deinit(tdm_nexell_data *display_data)
188 if (display_data->uevent_source) {
189 tdm_event_loop_source_remove(display_data->uevent_source);
190 display_data->uevent_source = NULL;
193 if (display_data->uevent_monitor) {
194 struct udev *u = udev_monitor_get_udev(display_data->uevent_monitor);
195 udev_monitor_unref(display_data->uevent_monitor);
197 display_data->uevent_monitor = NULL;
198 TDM_INFO("hotplug monitor destroyed");
204 _tdm_nexell_open_drm(void)
208 fd = drmOpen(TDM_NEXELL_NAME, NULL);
210 TDM_WRN("Cannot open '%s' drm", TDM_NEXELL_NAME);
215 struct udev_device *drm_device = NULL;
216 const char *filename;
217 TDM_WRN("Cannot open drm device.. search by udev");
219 drm_device = _tdm_find_primary_gpu();
220 if (drm_device == NULL) {
221 TDM_ERR("fail to find drm device\n");
225 filename = udev_device_get_devnode(drm_device);
227 fd = open(filename, O_RDWR | O_CLOEXEC);
229 TDM_ERR("Cannot open drm device(%s)\n", filename);
231 TDM_DBG("open drm device (name:%s, fd:%d)", filename, fd);
233 udev_device_unref(drm_device);
241 tdm_nexell_deinit(tdm_backend_data *bdata)
243 if (nexell_data != bdata)
249 _tdm_nexell_udev_deinit(nexell_data);
252 tdm_nexell_display_destroy_output_list(nexell_data);
253 tdm_nexell_data_destroy_buffer_list(nexell_data);
255 if (nexell_data->plane_res)
256 drmModeFreePlaneResources(nexell_data->plane_res);
257 if (nexell_data->mode_res)
258 drmModeFreeResources(nexell_data->mode_res);
259 if (nexell_data->drm_fd >= 0)
260 close(nexell_data->drm_fd);
261 if (nexell_data->scaler_fd >= 0)
262 close(nexell_data->scaler_fd);
269 tdm_nexell_init(tdm_display *dpy, tdm_error *error)
271 tdm_func_display nexell_func_display;
272 tdm_func_output nexell_func_output;
273 tdm_func_layer nexell_func_layer;
274 tdm_func_hwc nexell_func_hwc;
275 tdm_func_hwc_window nexell_func_hwc_window;
277 tdm_func_pp nexell_func_pp;
283 TDM_ERR("display is null");
285 *error = TDM_ERROR_INVALID_PARAMETER;
290 TDM_ERR("failed: init twice");
292 *error = TDM_ERROR_BAD_REQUEST;
296 nexell_data = calloc(1, sizeof(tdm_nexell_data));
298 TDM_ERR("alloc failed");
300 *error = TDM_ERROR_OUT_OF_MEMORY;
304 str = getenv("TDM_HWC");
307 nexell_data->hwc_mode = strtol(str, &end, 10);;
310 /* enable the tdm_hwc */
311 nexell_data->hwc_mode = TDM_NEXELL_ENABLE_HWC;
313 LIST_INITHEAD(&nexell_data->output_list);
314 LIST_INITHEAD(&nexell_data->buffer_list);
316 memset(&nexell_func_display, 0, sizeof(nexell_func_display));
317 nexell_func_display.display_get_capability = nexell_display_get_capability;
318 nexell_func_display.display_get_pp_capability = nexell_display_get_pp_capability;
319 nexell_func_display.display_get_outputs = nexell_display_get_outputs;
320 nexell_func_display.display_get_fd = nexell_display_get_fd;
321 nexell_func_display.display_handle_events = nexell_display_handle_events;
322 nexell_func_display.display_create_pp = nexell_display_create_pp;
324 memset(&nexell_func_output, 0, sizeof(nexell_func_output));
325 nexell_func_output.output_get_capability = nexell_output_get_capability;
326 nexell_func_output.output_get_layers = nexell_output_get_layers;
327 nexell_func_output.output_set_property = nexell_output_set_property;
328 nexell_func_output.output_get_property = nexell_output_get_property;
329 nexell_func_output.output_wait_vblank = nexell_output_wait_vblank;
330 nexell_func_output.output_set_vblank_handler = nexell_output_set_vblank_handler;
331 nexell_func_output.output_commit = nexell_output_commit;
332 nexell_func_output.output_set_commit_handler = nexell_output_set_commit_handler;
333 nexell_func_output.output_set_dpms = nexell_output_set_dpms;
334 nexell_func_output.output_get_dpms = nexell_output_get_dpms;
335 nexell_func_output.output_set_mode = nexell_output_set_mode;
336 nexell_func_output.output_get_mode = nexell_output_get_mode;
337 nexell_func_output.output_set_mirror = NULL;
338 nexell_func_output.output_unset_mirror = NULL;
340 nexell_func_output.output_set_status_handler = nexell_output_set_status_handler;
343 if (nexell_data->hwc_mode) {
344 nexell_func_output.output_get_hwc = nexell_output_get_hwc;
346 memset(&nexell_func_hwc, 0, sizeof(nexell_func_hwc));
347 nexell_func_hwc.hwc_create_window = nexell_hwc_create_window;
348 nexell_func_hwc.hwc_get_video_supported_formats = nexell_hwc_get_video_supported_formats;
349 nexell_func_hwc.hwc_get_video_available_properties = NULL;
350 nexell_func_hwc.hwc_get_capabilities = nexell_hwc_get_capabilities;
351 nexell_func_hwc.hwc_get_available_properties = nexell_hwc_get_available_properties;
352 nexell_func_hwc.hwc_get_client_target_buffer_queue = nexell_hwc_get_client_target_buffer_queue;
353 nexell_func_hwc.hwc_set_client_target_buffer = nexell_hwc_set_client_target_buffer;
354 nexell_func_hwc.hwc_set_client_target_acquire_fence = NULL;
355 nexell_func_hwc.hwc_validate = nexell_hwc_validate;
356 nexell_func_hwc.hwc_get_changed_composition_types = nexell_hwc_get_changed_composition_types;
357 nexell_func_hwc.hwc_accept_validation = nexell_hwc_accept_validation;
358 nexell_func_hwc.hwc_commit = nexell_hwc_commit;
359 nexell_func_hwc.hwc_set_commit_handler = nexell_hwc_set_commit_handler;
360 nexell_func_hwc.hwc_get_commit_fence = NULL;
361 nexell_func_hwc.hwc_get_release_fences = NULL;
363 memset(&nexell_func_hwc_window, 0, sizeof(nexell_func_hwc_window));
364 nexell_func_hwc_window.hwc_window_destroy = nexell_hwc_window_destroy;
365 nexell_func_hwc_window.hwc_window_acquire_buffer_queue = nexell_hwc_window_acquire_buffer_queue;
366 nexell_func_hwc_window.hwc_window_release_buffer_queue = nexell_hwc_window_release_buffer_queue;
367 nexell_func_hwc_window.hwc_window_set_composition_type = nexell_hwc_window_set_composition_type;
368 nexell_func_hwc_window.hwc_window_set_buffer_damage = nexell_hwc_window_set_buffer_damage;
369 nexell_func_hwc_window.hwc_window_set_info = nexell_hwc_window_set_info;
370 nexell_func_hwc_window.hwc_window_set_buffer = nexell_hwc_window_set_buffer;
371 nexell_func_hwc_window.hwc_window_set_property = nexell_hwc_window_set_property;
372 nexell_func_hwc_window.hwc_window_get_property = nexell_hwc_window_get_property;
373 nexell_func_hwc_window.hwc_window_get_constraints = nexell_hwc_window_get_constraints;
374 nexell_func_hwc_window.hwc_window_set_name = nexell_hwc_window_set_name;
375 nexell_func_hwc_window.hwc_window_set_cursor_image = nexell_hwc_window_set_cursor_image;
378 memset(&nexell_func_layer, 0, sizeof(nexell_func_layer));
379 nexell_func_layer.layer_get_capability = nexell_layer_get_capability;
380 nexell_func_layer.layer_set_property = nexell_layer_set_property;
381 nexell_func_layer.layer_get_property = nexell_layer_get_property;
382 nexell_func_layer.layer_set_info = nexell_layer_set_info;
383 nexell_func_layer.layer_get_info = nexell_layer_get_info;
384 nexell_func_layer.layer_set_buffer = nexell_layer_set_buffer;
385 nexell_func_layer.layer_unset_buffer = nexell_layer_unset_buffer;
388 memset(&nexell_func_pp, 0, sizeof(nexell_func_pp));
389 nexell_func_pp.pp_destroy = nexell_pp_destroy;
390 nexell_func_pp.pp_set_info = nexell_pp_set_info;
391 nexell_func_pp.pp_attach = nexell_pp_attach;
392 nexell_func_pp.pp_commit = nexell_pp_commit;
393 nexell_func_pp.pp_set_done_handler = nexell_pp_set_done_handler;
396 ret = tdm_backend_register_func_display(dpy, &nexell_func_display);
397 if (ret != TDM_ERROR_NONE)
400 ret = tdm_backend_register_func_output(dpy, &nexell_func_output);
401 if (ret != TDM_ERROR_NONE)
404 if (nexell_data->hwc_mode) {
405 ret = tdm_backend_register_func_hwc(dpy, &nexell_func_hwc);
406 if (ret != TDM_ERROR_NONE)
409 ret = tdm_backend_register_func_hwc_window(dpy, &nexell_func_hwc_window);
410 if (ret != TDM_ERROR_NONE)
414 ret = tdm_backend_register_func_layer(dpy, &nexell_func_layer);
415 if (ret != TDM_ERROR_NONE)
419 ret = tdm_backend_register_func_pp(dpy, &nexell_func_pp);
420 if (ret != TDM_ERROR_NONE)
424 nexell_data->dpy = dpy;
426 /* The drm master fd can be opened by a tbm backend module in
427 * tbm_bufmgr_init() time. In this case, we just get it from tbm.
429 nexell_data->drm_fd = tbm_drm_helper_get_master_fd();
430 if (nexell_data->drm_fd < 0) {
431 nexell_data->drm_fd = _tdm_nexell_open_drm();
433 if (nexell_data->drm_fd < 0) {
434 ret = TDM_ERROR_OPERATION_FAILED;
438 tbm_drm_helper_set_tbm_master_fd(nexell_data->drm_fd);
441 TDM_INFO("master fd(%d)", nexell_data->drm_fd);
443 nexell_data->scaler_fd = open("/dev/scaler", O_RDWR);
444 if (nexell_data->scaler_fd < 0)
445 TDM_ERR("scaler open fail. cannot use pp.");
448 _tdm_nexell_udev_init(nexell_data);
451 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
452 if (drmSetClientCap(nexell_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
453 TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
455 TDM_INFO("has universal planes");
456 nexell_data->has_universal_plane = 1;
459 if (drmSetClientCap(nexell_data->drm_fd, DRM_CLIENT_CAP_ATOMIC, 1) < 0) {
460 TDM_WRN("Set DRM_CLIENT_CAP_ATOMIC failed");
462 TDM_INFO("has atomic");
463 nexell_data->has_atomic = 1;
467 nexell_data->mode_res = drmModeGetResources(nexell_data->drm_fd);
468 if (!nexell_data->mode_res) {
469 TDM_ERR("no drm resource: %m");
470 ret = TDM_ERROR_OPERATION_FAILED;
474 nexell_data->plane_res = drmModeGetPlaneResources(nexell_data->drm_fd);
475 if (!nexell_data->plane_res) {
476 TDM_ERR("no drm plane resource: %m");
477 ret = TDM_ERROR_OPERATION_FAILED;
481 if (nexell_data->plane_res->count_planes <= 0) {
482 TDM_ERR("no drm plane resource");
483 ret = TDM_ERROR_OPERATION_FAILED;
487 ret = tdm_nexell_display_create_output_list(nexell_data);
488 if (ret != TDM_ERROR_NONE)
491 ret = tdm_nexell_display_create_layer_list(nexell_data);
492 if (ret != TDM_ERROR_NONE)
496 *error = TDM_ERROR_NONE;
498 TDM_INFO("init success!");
500 return (tdm_backend_data *)nexell_data;
505 tdm_nexell_deinit(nexell_data);
507 TDM_ERR("init failed!");
511 tdm_backend_module tdm_backend_module_data = {
514 TDM_BACKEND_SET_ABI_VERSION(2, 0),