6b2ff40cb1a4cde1a4b00f9f5d48c01666e39af5
[platform/adaptation/nexell/libtdm-nexell.git] / src / tdm_nexell.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #if HAVE_UDEV
6 #include <libudev.h>
7 #endif
8
9 #include "tdm_nexell.h"
10 #include <tdm_helper.h>
11 #include <tbm_drm_helper.h>
12
13 #define ENABLE_PP
14 #define TDM_NEXELL_ENABLE_HWC 0 // disable tdm_hwc
15
16 #define TDM_NEXELL_NAME "vigs"
17
18 static tdm_nexell_data *nexell_data;
19
20 #ifdef HAVE_UDEV
21 static struct udev_device *
22 _tdm_find_primary_gpu(void)
23 {
24         struct udev *udev;
25         struct udev_enumerate *e;
26         struct udev_list_entry *entry;
27         const char *path, *id;
28         struct udev_device *device, *drm_device, *pci;
29
30         udev = udev_new();
31         if (!udev) {
32                 TDM_ERR("fail to initialize udev context\n");
33                 return NULL;
34         }
35
36         e = udev_enumerate_new(udev);
37         udev_enumerate_add_match_subsystem(e, "drm");
38         udev_enumerate_add_match_sysname(e, "card[0-9]*");
39
40         udev_enumerate_scan_devices(e);
41         drm_device = NULL;
42         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
43                 path = udev_list_entry_get_name(entry);
44                 device = udev_device_new_from_syspath(udev, path);
45                 if (!device)
46                         continue;
47
48                 pci = udev_device_get_parent_with_subsystem_devtype(device,
49                                 "pci", NULL);
50                 if (pci) {
51                         id = udev_device_get_sysattr_value(pci, "boot_vga");
52                         if (id && !strcmp(id, "1")) {
53                                 if (drm_device)
54                                         udev_device_unref(drm_device);
55                                 drm_device = device;
56                                 break;
57                         }
58                 }
59
60                 if (!drm_device)
61                         drm_device = device;
62                 else
63                         udev_device_unref(device);
64         }
65
66         udev_enumerate_unref(e);
67         return drm_device;
68 }
69
70 static tdm_error
71 _tdm_nexell_udev_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
72 {
73         tdm_nexell_data *edata = (tdm_nexell_data*)user_data;
74         struct udev_device *dev;
75         const char *hotplug;
76         struct stat s;
77         dev_t udev_devnum;
78         int ret;
79
80         dev = udev_monitor_receive_device(edata->uevent_monitor);
81         if (!dev) {
82                 TDM_ERR("couldn't receive device");
83                 return TDM_ERROR_OPERATION_FAILED;
84         }
85
86         udev_devnum = udev_device_get_devnum(dev);
87
88         ret = fstat(edata->drm_fd, &s);
89         if (ret == -1) {
90                 TDM_ERR("fstat failed");
91                 udev_device_unref(dev);
92                 return TDM_ERROR_OPERATION_FAILED;
93         }
94
95         hotplug = udev_device_get_property_value(dev, "HOTPLUG");
96
97         if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
98                 hotplug && atoi(hotplug) == 1)
99         {
100                 TDM_INFO("HotPlug");
101                 tdm_nexell_display_update_output_status(edata);
102         }
103
104         udev_device_unref(dev);
105
106         return TDM_ERROR_NONE;
107 }
108
109 static void
110 _tdm_nexell_udev_init(tdm_nexell_data *edata)
111 {
112         struct udev *u = NULL;
113         struct udev_monitor *mon = NULL;
114
115         u = udev_new();
116         if (!u) {
117                 TDM_ERR("couldn't create udev");
118                 goto failed;
119         }
120
121         mon = udev_monitor_new_from_netlink(u, "udev");
122         if (!mon) {
123                 TDM_ERR("couldn't create udev monitor");
124                 goto failed;
125         }
126
127         if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
128             udev_monitor_enable_receiving(mon) < 0) {
129                 TDM_ERR("add match subsystem failed");
130                 goto failed;
131         }
132
133         edata->uevent_source =
134                 tdm_event_loop_add_fd_handler(edata->dpy, udev_monitor_get_fd(mon),
135                                               TDM_EVENT_LOOP_READABLE,
136                                               _tdm_nexell_udev_fd_handler,
137                                               edata, NULL);
138         if (!edata->uevent_source) {
139                 TDM_ERR("couldn't create udev event source");
140                 goto failed;
141         }
142
143         edata->uevent_monitor = mon;
144
145         TDM_INFO("hotplug monitor created");
146
147         return;
148 failed:
149         if (mon)
150                 udev_monitor_unref(mon);
151         if (u)
152                 udev_unref(u);
153 }
154
155 static void
156 _tdm_nexell_udev_deinit(tdm_nexell_data *edata)
157 {
158         if (edata->uevent_source) {
159                 tdm_event_loop_source_remove(edata->uevent_source);
160                 edata->uevent_source = NULL;
161         }
162
163         if (edata->uevent_monitor) {
164                 struct udev *u = udev_monitor_get_udev(edata->uevent_monitor);
165                 udev_monitor_unref(edata->uevent_monitor);
166                 udev_unref(u);
167                 edata->uevent_monitor = NULL;
168                 TDM_INFO("hotplug monitor destroyed");
169         }
170 }
171 #endif
172
173 static int
174 _tdm_nexell_open_drm(void)
175 {
176         int fd = -1;
177
178         fd = drmOpen(TDM_NEXELL_NAME, NULL);
179         if (fd < 0) {
180                 TDM_WRN("Cannot open '%s' drm", TDM_NEXELL_NAME);
181         }
182
183 #ifdef HAVE_UDEV
184         if (fd < 0) {
185                 struct udev_device *drm_device = NULL;
186                 const char *filename;
187                 TDM_WRN("Cannot open drm device.. search by udev");
188
189                 drm_device = _tdm_find_primary_gpu();
190                 if (drm_device == NULL) {
191                         TDM_ERR("fail to find drm device\n");
192                         goto close_l;
193                 }
194
195                 filename = udev_device_get_devnode(drm_device);
196
197                 fd = open(filename, O_RDWR | O_CLOEXEC);
198                 if (fd < 0)
199                         TDM_ERR("Cannot open drm device(%s)\n", filename);
200
201                 TDM_DBG("open drm device (name:%s, fd:%d)", filename, fd);
202
203                 udev_device_unref(drm_device);
204         }
205 close_l:
206 #endif
207         return fd;
208 }
209
210 void
211 tdm_nexell_deinit(tdm_backend_data *bdata)
212 {
213         if (nexell_data != bdata)
214                 return;
215
216         TDM_INFO("deinit");
217
218 #ifdef HAVE_UDEV
219         _tdm_nexell_udev_deinit(nexell_data);
220 #endif
221
222         tdm_nexell_display_destroy_output_list(nexell_data);
223         tdm_nexell_data_destroy_buffer_list(nexell_data);
224
225         if (nexell_data->plane_res)
226                 drmModeFreePlaneResources(nexell_data->plane_res);
227         if (nexell_data->mode_res)
228                 drmModeFreeResources(nexell_data->mode_res);
229         if (nexell_data->drm_fd >= 0)
230                 close(nexell_data->drm_fd);
231         if (nexell_data->scaler_fd >= 0)
232                 close(nexell_data->scaler_fd);
233
234         free(nexell_data);
235         nexell_data = NULL;
236 }
237
238 tdm_backend_data *
239 tdm_nexell_init(tdm_display *dpy, tdm_error *error)
240 {
241         tdm_func_display nexell_func_display;
242         tdm_func_output nexell_func_output;
243         tdm_func_layer nexell_func_layer;
244         tdm_func_hwc nexell_func_hwc;
245         tdm_func_hwc_window nexell_func_hwc_window;
246 #ifdef ENABLE_PP
247         tdm_func_pp nexell_func_pp;
248 #endif
249         tdm_error ret;
250         char *str;
251
252 #define TDM_CHANGE_DEBUG_LOGLEVEL
253 #ifdef TDM_CHANGE_DEBUG_LOGLEVEL
254         // show DBG log level
255         tdm_log_set_debug_level(4);
256 #endif
257
258         if (!dpy) {
259                 TDM_ERR("display is null");
260                 if (error)
261                         *error = TDM_ERROR_INVALID_PARAMETER;
262                 return NULL;
263         }
264
265         if (nexell_data) {
266                 TDM_ERR("failed: init twice");
267                 if (error)
268                         *error = TDM_ERROR_BAD_REQUEST;
269                 return NULL;
270         }
271
272         nexell_data = calloc(1, sizeof(tdm_nexell_data));
273         if (!nexell_data) {
274                 TDM_ERR("alloc failed");
275                 if (error)
276                         *error = TDM_ERROR_OUT_OF_MEMORY;
277                 return NULL;
278         }
279
280         str = getenv("TDM_HWC");
281         if (str) {
282                 char *end;
283                 nexell_data->hwc_mode = strtol(str, &end, 10);;
284         }
285
286         /* enable the tdm_hwc */
287         nexell_data->hwc_mode = TDM_NEXELL_ENABLE_HWC;
288
289         LIST_INITHEAD(&nexell_data->output_list);
290         LIST_INITHEAD(&nexell_data->buffer_list);
291
292         memset(&nexell_func_display, 0, sizeof(nexell_func_display));
293         nexell_func_display.display_get_capability = nexell_display_get_capability;
294         nexell_func_display.display_get_pp_capability = nexell_display_get_pp_capability;
295         nexell_func_display.display_get_outputs = nexell_display_get_outputs;
296         nexell_func_display.display_get_fd = nexell_display_get_fd;
297         nexell_func_display.display_handle_events = nexell_display_handle_events;
298         nexell_func_display.display_create_pp = nexell_display_create_pp;
299
300         memset(&nexell_func_output, 0, sizeof(nexell_func_output));
301         nexell_func_output.output_get_capability = nexell_output_get_capability;
302         nexell_func_output.output_get_layers = nexell_output_get_layers;
303         nexell_func_output.output_set_property = nexell_output_set_property;
304         nexell_func_output.output_get_property = nexell_output_get_property;
305         nexell_func_output.output_wait_vblank = nexell_output_wait_vblank;
306         nexell_func_output.output_set_vblank_handler = nexell_output_set_vblank_handler;
307         nexell_func_output.output_commit = nexell_output_commit;
308         nexell_func_output.output_set_commit_handler = nexell_output_set_commit_handler;
309         nexell_func_output.output_set_dpms = nexell_output_set_dpms;
310         nexell_func_output.output_get_dpms = nexell_output_get_dpms;
311         nexell_func_output.output_set_mode = nexell_output_set_mode;
312         nexell_func_output.output_get_mode = nexell_output_get_mode;
313         nexell_func_output.output_set_mirror = NULL;
314         nexell_func_output.output_unset_mirror = NULL;
315 #ifdef HAVE_UDEV
316         nexell_func_output.output_set_status_handler = nexell_output_set_status_handler;
317 #endif
318
319         if (nexell_data->hwc_mode) {
320                 nexell_func_output.output_get_hwc = nexell_output_get_hwc;
321
322                 memset(&nexell_func_hwc, 0, sizeof(nexell_func_hwc));
323                 nexell_func_hwc.hwc_create_window = nexell_hwc_create_window;
324                 nexell_func_hwc.hwc_get_video_supported_formats = nexell_hwc_get_video_supported_formats;
325                 nexell_func_hwc.hwc_get_video_available_properties = NULL;
326                 nexell_func_hwc.hwc_get_capabilities = nexell_hwc_get_capabilities;
327                 nexell_func_hwc.hwc_get_available_properties = nexell_hwc_get_available_properties;
328                 nexell_func_hwc.hwc_get_client_target_buffer_queue = nexell_hwc_get_client_target_buffer_queue;
329                 nexell_func_hwc.hwc_set_client_target_buffer = nexell_hwc_set_client_target_buffer;
330                 nexell_func_hwc.hwc_set_client_target_acquire_fence = NULL;
331                 nexell_func_hwc.hwc_validate = nexell_hwc_validate;
332                 nexell_func_hwc.hwc_get_changed_composition_types = nexell_hwc_get_changed_composition_types;
333                 nexell_func_hwc.hwc_accept_validation = nexell_hwc_accept_validation;
334                 nexell_func_hwc.hwc_commit = nexell_hwc_commit;
335                 nexell_func_hwc.hwc_set_commit_handler = nexell_hwc_set_commit_handler;
336                 nexell_func_hwc.hwc_get_commit_fence = NULL;
337                 nexell_func_hwc.hwc_get_release_fences = NULL;
338
339                 memset(&nexell_func_hwc_window, 0, sizeof(nexell_func_hwc_window));
340                 nexell_func_hwc_window.hwc_window_destroy = nexell_hwc_window_destroy;
341                 nexell_func_hwc_window.hwc_window_acquire_buffer_queue = nexell_hwc_window_acquire_buffer_queue;
342                 nexell_func_hwc_window.hwc_window_release_buffer_queue = nexell_hwc_window_release_buffer_queue;
343                 nexell_func_hwc_window.hwc_window_set_composition_type = nexell_hwc_window_set_composition_type;
344                 nexell_func_hwc_window.hwc_window_set_buffer_damage = nexell_hwc_window_set_buffer_damage;
345                 nexell_func_hwc_window.hwc_window_set_info = nexell_hwc_window_set_info;
346                 nexell_func_hwc_window.hwc_window_set_buffer = nexell_hwc_window_set_buffer;
347                 nexell_func_hwc_window.hwc_window_set_property = nexell_hwc_window_set_property;
348                 nexell_func_hwc_window.hwc_window_get_property = nexell_hwc_window_get_property;
349                 nexell_func_hwc_window.hwc_window_get_constraints = nexell_hwc_window_get_constraints;
350                 nexell_func_hwc_window.hwc_window_set_name = nexell_hwc_window_set_name;
351                 nexell_func_hwc_window.hwc_window_set_cursor_image = nexell_hwc_window_set_cursor_image;
352         }
353
354         memset(&nexell_func_layer, 0, sizeof(nexell_func_layer));
355         nexell_func_layer.layer_get_capability = nexell_layer_get_capability;
356         nexell_func_layer.layer_set_property = nexell_layer_set_property;
357         nexell_func_layer.layer_get_property = nexell_layer_get_property;
358         nexell_func_layer.layer_set_info = nexell_layer_set_info;
359         nexell_func_layer.layer_get_info = nexell_layer_get_info;
360         nexell_func_layer.layer_set_buffer = nexell_layer_set_buffer;
361         nexell_func_layer.layer_unset_buffer = nexell_layer_unset_buffer;
362
363 #ifdef ENABLE_PP
364         memset(&nexell_func_pp, 0, sizeof(nexell_func_pp));
365         nexell_func_pp.pp_destroy = nexell_pp_destroy;
366         nexell_func_pp.pp_set_info = nexell_pp_set_info;
367         nexell_func_pp.pp_attach = nexell_pp_attach;
368         nexell_func_pp.pp_commit = nexell_pp_commit;
369         nexell_func_pp.pp_set_done_handler = nexell_pp_set_done_handler;
370 #endif
371
372         ret = tdm_backend_register_func_display(dpy, &nexell_func_display);
373         if (ret != TDM_ERROR_NONE)
374                 goto failed;
375
376         ret = tdm_backend_register_func_output(dpy, &nexell_func_output);
377         if (ret != TDM_ERROR_NONE)
378                 goto failed;
379
380         if (nexell_data->hwc_mode) {
381                 ret = tdm_backend_register_func_hwc(dpy, &nexell_func_hwc);
382                 if (ret != TDM_ERROR_NONE)
383                         goto failed;
384
385                 ret = tdm_backend_register_func_hwc_window(dpy, &nexell_func_hwc_window);
386                 if (ret != TDM_ERROR_NONE)
387                         goto failed;
388         }
389
390         ret = tdm_backend_register_func_layer(dpy, &nexell_func_layer);
391         if (ret != TDM_ERROR_NONE)
392                 goto failed;
393
394 #ifdef ENABLE_PP
395         ret = tdm_backend_register_func_pp(dpy, &nexell_func_pp);
396         if (ret != TDM_ERROR_NONE)
397                 goto failed;
398 #endif
399
400         nexell_data->dpy = dpy;
401
402         /* The drm master fd can be opened by a tbm backend module in
403          * tbm_bufmgr_init() time. In this case, we just get it from tbm.
404          */
405         nexell_data->drm_fd = tbm_drm_helper_get_master_fd();
406         if (nexell_data->drm_fd < 0) {
407                 nexell_data->drm_fd = _tdm_nexell_open_drm();
408
409                 if (nexell_data->drm_fd < 0) {
410                         ret = TDM_ERROR_OPERATION_FAILED;
411                         goto failed;
412                 }
413
414                 tbm_drm_helper_set_tbm_master_fd(nexell_data->drm_fd);
415         }
416
417         TDM_INFO("master fd(%d)", nexell_data->drm_fd);
418
419         nexell_data->scaler_fd = open("/dev/scaler", O_RDWR);
420         if (nexell_data->scaler_fd < 0)
421                 TDM_ERR("scaler open fail. cannot use pp.");
422
423 #ifdef HAVE_UDEV
424         _tdm_nexell_udev_init(nexell_data);
425 #endif
426
427 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
428         if (drmSetClientCap(nexell_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
429                 TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
430         } else {
431                 TDM_INFO("has universal planes");
432                 nexell_data->has_universal_plane = 1;
433         }
434 #endif
435
436         nexell_data->mode_res = drmModeGetResources(nexell_data->drm_fd);
437         if (!nexell_data->mode_res) {
438                 TDM_ERR("no drm resource: %m");
439                 ret = TDM_ERROR_OPERATION_FAILED;
440                 goto failed;
441         }
442
443         nexell_data->plane_res = drmModeGetPlaneResources(nexell_data->drm_fd);
444         if (!nexell_data->plane_res) {
445                 TDM_ERR("no drm plane resource: %m");
446                 ret = TDM_ERROR_OPERATION_FAILED;
447                 goto failed;
448         }
449
450         if (nexell_data->plane_res->count_planes <= 0) {
451                 TDM_ERR("no drm plane resource");
452                 ret = TDM_ERROR_OPERATION_FAILED;
453                 goto failed;
454         }
455
456         ret = tdm_nexell_display_create_output_list(nexell_data);
457         if (ret != TDM_ERROR_NONE)
458                 goto failed;
459
460         ret = tdm_nexell_display_create_layer_list(nexell_data);
461         if (ret != TDM_ERROR_NONE)
462                 goto failed;
463
464         if (error)
465                 *error = TDM_ERROR_NONE;
466
467         TDM_INFO("init success!");
468
469         return (tdm_backend_data *)nexell_data;
470 failed:
471         if (error)
472                 *error = ret;
473
474         tdm_nexell_deinit(nexell_data);
475
476         TDM_ERR("init failed!");
477         return NULL;
478 }
479
480 tdm_backend_module tdm_backend_module_data = {
481         "drm",
482         "Samsung",
483         TDM_BACKEND_SET_ABI_VERSION(2, 0),
484         tdm_nexell_init,
485         tdm_nexell_deinit
486 };