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