10 #include <tdm_helper.h>
11 #include <tbm_drm_helper.h>
13 #define TDM_DRM_NAME "vc4-drm"
15 static tdm_vc4_data *vc4_data;
18 static struct udev_device *
19 _tdm_find_primary_gpu(void)
22 struct udev_enumerate *e;
23 struct udev_list_entry *entry;
24 const char *path, *id;
25 struct udev_device *device, *drm_device, *pci;
29 TDM_ERR("fail to initialize udev context\n");
33 e = udev_enumerate_new(udev);
34 udev_enumerate_add_match_subsystem(e, "drm");
35 udev_enumerate_add_match_sysname(e, "card[0-9]*");
37 udev_enumerate_scan_devices(e);
39 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
40 path = udev_list_entry_get_name(entry);
41 device = udev_device_new_from_syspath(udev, path);
45 pci = udev_device_get_parent_with_subsystem_devtype(device, "pci", NULL);
47 id = udev_device_get_sysattr_value(pci, "boot_vga");
48 if (id && !strcmp(id, "1")) {
50 udev_device_unref(drm_device);
59 udev_device_unref(device);
62 udev_enumerate_unref(e);
67 _tdm_vc4_udev_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
69 tdm_vc4_data *edata = (tdm_vc4_data*)user_data;
70 struct udev_device *dev;
76 dev = udev_monitor_receive_device(edata->uevent_monitor);
78 TDM_ERR("couldn't receive device");
79 return TDM_ERROR_OPERATION_FAILED;
82 udev_devnum = udev_device_get_devnum(dev);
84 ret = fstat(edata->drm_fd, &s);
86 TDM_ERR("fstat failed");
87 return TDM_ERROR_OPERATION_FAILED;
90 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
92 if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
93 hotplug && atoi(hotplug) == 1) {
95 tdm_vc4_display_update_output_status(edata);
98 udev_device_unref(dev);
100 return TDM_ERROR_NONE;
104 _tdm_vc4_udev_init(tdm_vc4_data *edata)
106 struct udev *u = NULL;
107 struct udev_monitor *mon = NULL;
111 TDM_ERR("couldn't create udev");
115 mon = udev_monitor_new_from_netlink(u, "udev");
117 TDM_ERR("couldn't create udev monitor");
121 if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
122 udev_monitor_enable_receiving(mon) < 0) {
123 TDM_ERR("add match subsystem failed");
127 edata->uevent_source =
128 tdm_event_loop_add_fd_handler(edata->dpy, udev_monitor_get_fd(mon),
129 TDM_EVENT_LOOP_READABLE,
130 _tdm_vc4_udev_fd_handler,
132 if (!edata->uevent_source) {
133 TDM_ERR("couldn't create udev event source");
137 edata->uevent_monitor = mon;
139 TDM_INFO("hotplug monitor created");
144 udev_monitor_unref(mon);
150 _tdm_vc4_udev_deinit(tdm_vc4_data *edata)
152 if (edata->uevent_source) {
153 tdm_event_loop_source_remove(edata->uevent_source);
154 edata->uevent_source = NULL;
157 if (edata->uevent_monitor) {
158 struct udev *u = udev_monitor_get_udev(edata->uevent_monitor);
159 udev_monitor_unref(edata->uevent_monitor);
161 edata->uevent_monitor = NULL;
162 TDM_INFO("hotplug monitor destroyed");
168 _tdm_vc4_open_drm(void)
172 fd = drmOpen(TDM_DRM_NAME, NULL);
174 TDM_WRN("Cannot open '%s' drm", TDM_DRM_NAME);
178 struct udev_device *drm_device = NULL;
179 const char *filename;
180 TDM_WRN("Cannot open drm device.. search by udev");
182 drm_device = _tdm_find_primary_gpu();
183 if (drm_device == NULL) {
184 TDM_ERR("fail to find drm device\n");
188 filename = udev_device_get_devnode(drm_device);
190 fd = open(filename, O_RDWR | O_CLOEXEC);
192 TDM_ERR("Cannot open drm device(%s)\n", filename);
194 TDM_DBG("open drm device (name:%s, fd:%d)", filename, fd);
196 udev_device_unref(drm_device);
204 tdm_vc4_deinit(tdm_backend_data *bdata)
206 if (vc4_data != bdata)
212 _tdm_vc4_udev_deinit(vc4_data);
215 tdm_vc4_display_destroy_output_list(vc4_data);
217 if (vc4_data->plane_res)
218 drmModeFreePlaneResources(vc4_data->plane_res);
219 if (vc4_data->mode_res)
220 drmModeFreeResources(vc4_data->mode_res);
221 if (vc4_data->drm_fd >= 0)
222 close(vc4_data->drm_fd);
229 tdm_vc4_init(tdm_display *dpy, tdm_error *error)
231 tdm_func_display vc4_func_display;
232 tdm_func_output vc4_func_output;
233 tdm_func_layer vc4_func_layer;
234 tdm_func_hwc_window vc4_func_hwc_window;
239 TDM_ERR("display is null");
241 *error = TDM_ERROR_INVALID_PARAMETER;
246 TDM_ERR("failed: init twice");
248 *error = TDM_ERROR_BAD_REQUEST;
252 vc4_data = calloc(1, sizeof(tdm_vc4_data));
254 TDM_ERR("alloc failed");
256 *error = TDM_ERROR_OUT_OF_MEMORY;
260 str = getenv("TDM_HWC");
263 vc4_data->hwc_mode = strtol(str, &end, 10);;
266 LIST_INITHEAD(&vc4_data->output_list);
267 LIST_INITHEAD(&vc4_data->buffer_list);
269 memset(&vc4_func_display, 0, sizeof(vc4_func_display));
270 vc4_func_display.display_get_capability = vc4_display_get_capability;
271 vc4_func_display.display_get_outputs = vc4_display_get_outputs;
272 vc4_func_display.display_get_fd = vc4_display_get_fd;
273 vc4_func_display.display_handle_events = vc4_display_handle_events;
275 memset(&vc4_func_output, 0, sizeof(vc4_func_output));
276 vc4_func_output.output_get_capability = vc4_output_get_capability;
277 vc4_func_output.output_get_layers = vc4_output_get_layers;
278 vc4_func_output.output_set_property = vc4_output_set_property;
279 vc4_func_output.output_get_property = vc4_output_get_property;
280 vc4_func_output.output_wait_vblank = vc4_output_wait_vblank;
281 vc4_func_output.output_set_vblank_handler = vc4_output_set_vblank_handler;
282 vc4_func_output.output_commit = vc4_output_commit;
283 vc4_func_output.output_set_commit_handler = vc4_output_set_commit_handler;
284 vc4_func_output.output_set_dpms = vc4_output_set_dpms;
285 vc4_func_output.output_get_dpms = vc4_output_get_dpms;
286 vc4_func_output.output_set_mode = vc4_output_set_mode;
287 vc4_func_output.output_get_mode = vc4_output_get_mode;
289 vc4_func_output.output_set_status_handler = vc4_output_set_status_handler;
291 if (vc4_data->hwc_mode) {
292 vc4_func_output.output_hwc_create_window = vc4_output_hwc_window_create;
293 vc4_func_output.output_hwc_destroy_window = vc4_output_hwc_window_destroy;
294 vc4_func_output.output_hwc_validate = vc4_output_hwc_validate;
295 vc4_func_output.output_hwc_get_changed_composition_types = vc4_output_hwc_get_changed_composition_types;
296 vc4_func_output.output_hwc_accept_changes = vc4_output_hwc_accept_changes;
297 vc4_func_output.output_hwc_get_target_buffer_queue = vc4_output_hwc_get_target_buffer_queue;
298 vc4_func_output.output_hwc_set_client_target_buffer = vc4_output_hwc_set_client_target_buffer;
300 memset(&vc4_func_hwc_window, 0, sizeof(vc4_func_hwc_window));
301 vc4_func_hwc_window.hwc_window_get_tbm_buffer_queue = vc4_hwc_window_get_tbm_buffer_queue;
302 vc4_func_hwc_window.hwc_window_set_buffer = vc4_hwc_window_set_buffer;
303 vc4_func_hwc_window.hwc_window_set_composition_type = vc4_hwc_window_set_composition_type;
304 vc4_func_hwc_window.hwc_window_set_info = vc4_hwc_window_set_info;
305 vc4_func_hwc_window.hwc_window_set_buffer_damage = vc4_hwc_window_set_buffer_damage;
306 vc4_func_hwc_window.hwc_window_set_zpos = vc4_hwc_window_set_zpos;
309 memset(&vc4_func_layer, 0, sizeof(vc4_func_layer));
310 vc4_func_layer.layer_get_capability = vc4_layer_get_capability;
311 vc4_func_layer.layer_set_property = vc4_layer_set_property;
312 vc4_func_layer.layer_get_property = vc4_layer_get_property;
313 vc4_func_layer.layer_set_info = vc4_layer_set_info;
314 vc4_func_layer.layer_get_info = vc4_layer_get_info;
315 vc4_func_layer.layer_set_buffer = vc4_layer_set_buffer;
316 vc4_func_layer.layer_unset_buffer = vc4_layer_unset_buffer;
318 ret = tdm_backend_register_func_display(dpy, &vc4_func_display);
319 if (ret != TDM_ERROR_NONE)
322 ret = tdm_backend_register_func_output(dpy, &vc4_func_output);
323 if (ret != TDM_ERROR_NONE)
326 ret = tdm_backend_register_func_layer(dpy, &vc4_func_layer);
327 if (ret != TDM_ERROR_NONE)
330 if (vc4_data->hwc_mode) {
331 ret = tdm_backend_register_func_hwc_window(dpy, &vc4_func_hwc_window);
332 if (ret != TDM_ERROR_NONE)
337 /* The drm master fd can be opened by a tbm backend module in
338 * tbm_bufmgr_init() time. In this case, we just get it from tbm.
340 vc4_data->drm_fd = tbm_drm_helper_get_master_fd();
341 if (vc4_data->drm_fd < 0) {
342 vc4_data->drm_fd = _tdm_vc4_open_drm();
344 if (vc4_data->drm_fd < 0) {
345 ret = TDM_ERROR_OPERATION_FAILED;
349 tbm_drm_helper_set_tbm_master_fd(vc4_data->drm_fd);
352 TDM_INFO("master fd(%d)", vc4_data->drm_fd);
355 _tdm_vc4_udev_init(vc4_data);
358 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
359 if (drmSetClientCap(vc4_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
360 TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
362 TDM_INFO("has universal planes");
363 vc4_data->has_universal_plane = 1;
367 vc4_data->mode_res = drmModeGetResources(vc4_data->drm_fd);
368 if (!vc4_data->mode_res) {
369 TDM_ERR("no drm resource: %m");
370 ret = TDM_ERROR_OPERATION_FAILED;
374 vc4_data->plane_res = drmModeGetPlaneResources(vc4_data->drm_fd);
375 if (!vc4_data->plane_res) {
376 TDM_ERR("no drm plane resource: %m");
377 ret = TDM_ERROR_OPERATION_FAILED;
381 if (vc4_data->plane_res->count_planes <= 0) {
382 TDM_ERR("no drm plane resource");
383 ret = TDM_ERROR_OPERATION_FAILED;
387 ret = tdm_vc4_display_create_output_list(vc4_data);
388 if (ret != TDM_ERROR_NONE)
391 ret = tdm_vc4_display_create_layer_list(vc4_data);
392 if (ret != TDM_ERROR_NONE)
396 *error = TDM_ERROR_NONE;
398 TDM_INFO("init success!");
400 return (tdm_backend_data *)vc4_data;
405 tdm_vc4_deinit(vc4_data);
407 TDM_ERR("init failed!");
411 tdm_backend_module tdm_backend_module_data = {
414 TDM_BACKEND_SET_ABI_VERSION(1, 1),