2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
10 #include <linux/host1x.h>
15 #define DRIVER_NAME "tegra"
16 #define DRIVER_DESC "NVIDIA Tegra graphics"
17 #define DRIVER_DATE "20120330"
18 #define DRIVER_MAJOR 0
19 #define DRIVER_MINOR 0
20 #define DRIVER_PATCHLEVEL 0
22 struct tegra_drm_file
{
23 struct list_head contexts
;
26 static int tegra_drm_load(struct drm_device
*drm
, unsigned long flags
)
28 struct host1x_device
*device
= to_host1x_device(drm
->dev
);
29 struct tegra_drm
*tegra
;
32 tegra
= kzalloc(sizeof(*tegra
), GFP_KERNEL
);
36 dev_set_drvdata(drm
->dev
, tegra
);
37 mutex_init(&tegra
->clients_lock
);
38 INIT_LIST_HEAD(&tegra
->clients
);
39 drm
->dev_private
= tegra
;
42 drm_mode_config_init(drm
);
44 err
= host1x_device_init(device
);
49 * We don't use the drm_irq_install() helpers provided by the DRM
50 * core, so we need to set this manually in order to allow the
51 * DRM_IOCTL_WAIT_VBLANK to operate correctly.
53 drm
->irq_enabled
= true;
55 err
= drm_vblank_init(drm
, drm
->mode_config
.num_crtc
);
59 err
= tegra_drm_fb_init(drm
);
63 drm_kms_helper_poll_init(drm
);
68 static int tegra_drm_unload(struct drm_device
*drm
)
70 struct host1x_device
*device
= to_host1x_device(drm
->dev
);
73 drm_kms_helper_poll_fini(drm
);
74 tegra_drm_fb_exit(drm
);
76 err
= host1x_device_exit(device
);
80 drm_mode_config_cleanup(drm
);
85 static int tegra_drm_open(struct drm_device
*drm
, struct drm_file
*filp
)
87 struct tegra_drm_file
*fpriv
;
89 fpriv
= kzalloc(sizeof(*fpriv
), GFP_KERNEL
);
93 INIT_LIST_HEAD(&fpriv
->contexts
);
94 filp
->driver_priv
= fpriv
;
99 static void tegra_drm_context_free(struct tegra_drm_context
*context
)
101 context
->client
->ops
->close_channel(context
);
105 static void tegra_drm_lastclose(struct drm_device
*drm
)
107 struct tegra_drm
*tegra
= drm
->dev_private
;
109 tegra_fbdev_restore_mode(tegra
->fbdev
);
112 #ifdef CONFIG_DRM_TEGRA_STAGING
113 static struct tegra_drm_context
*tegra_drm_get_context(__u64 context
)
115 return (struct tegra_drm_context
*)(uintptr_t)context
;
118 static bool tegra_drm_file_owns_context(struct tegra_drm_file
*file
,
119 struct tegra_drm_context
*context
)
121 struct tegra_drm_context
*ctx
;
123 list_for_each_entry(ctx
, &file
->contexts
, list
)
130 static int tegra_gem_create(struct drm_device
*drm
, void *data
,
131 struct drm_file
*file
)
133 struct drm_tegra_gem_create
*args
= data
;
136 bo
= tegra_bo_create_with_handle(file
, drm
, args
->size
,
144 static int tegra_gem_mmap(struct drm_device
*drm
, void *data
,
145 struct drm_file
*file
)
147 struct drm_tegra_gem_mmap
*args
= data
;
148 struct drm_gem_object
*gem
;
151 gem
= drm_gem_object_lookup(drm
, file
, args
->handle
);
155 bo
= to_tegra_bo(gem
);
157 args
->offset
= drm_vma_node_offset_addr(&bo
->gem
.vma_node
);
159 drm_gem_object_unreference(gem
);
164 static int tegra_syncpt_read(struct drm_device
*drm
, void *data
,
165 struct drm_file
*file
)
167 struct host1x
*host
= dev_get_drvdata(drm
->dev
->parent
);
168 struct drm_tegra_syncpt_read
*args
= data
;
169 struct host1x_syncpt
*sp
;
171 sp
= host1x_syncpt_get(host
, args
->id
);
175 args
->value
= host1x_syncpt_read_min(sp
);
179 static int tegra_syncpt_incr(struct drm_device
*drm
, void *data
,
180 struct drm_file
*file
)
182 struct host1x
*host1x
= dev_get_drvdata(drm
->dev
->parent
);
183 struct drm_tegra_syncpt_incr
*args
= data
;
184 struct host1x_syncpt
*sp
;
186 sp
= host1x_syncpt_get(host1x
, args
->id
);
190 return host1x_syncpt_incr(sp
);
193 static int tegra_syncpt_wait(struct drm_device
*drm
, void *data
,
194 struct drm_file
*file
)
196 struct host1x
*host1x
= dev_get_drvdata(drm
->dev
->parent
);
197 struct drm_tegra_syncpt_wait
*args
= data
;
198 struct host1x_syncpt
*sp
;
200 sp
= host1x_syncpt_get(host1x
, args
->id
);
204 return host1x_syncpt_wait(sp
, args
->thresh
, args
->timeout
,
208 static int tegra_open_channel(struct drm_device
*drm
, void *data
,
209 struct drm_file
*file
)
211 struct tegra_drm_file
*fpriv
= file
->driver_priv
;
212 struct tegra_drm
*tegra
= drm
->dev_private
;
213 struct drm_tegra_open_channel
*args
= data
;
214 struct tegra_drm_context
*context
;
215 struct tegra_drm_client
*client
;
218 context
= kzalloc(sizeof(*context
), GFP_KERNEL
);
222 list_for_each_entry(client
, &tegra
->clients
, list
)
223 if (client
->base
.class == args
->client
) {
224 err
= client
->ops
->open_channel(client
, context
);
228 list_add(&context
->list
, &fpriv
->contexts
);
229 args
->context
= (uintptr_t)context
;
230 context
->client
= client
;
238 static int tegra_close_channel(struct drm_device
*drm
, void *data
,
239 struct drm_file
*file
)
241 struct tegra_drm_file
*fpriv
= file
->driver_priv
;
242 struct drm_tegra_close_channel
*args
= data
;
243 struct tegra_drm_context
*context
;
245 context
= tegra_drm_get_context(args
->context
);
247 if (!tegra_drm_file_owns_context(fpriv
, context
))
250 list_del(&context
->list
);
251 tegra_drm_context_free(context
);
256 static int tegra_get_syncpt(struct drm_device
*drm
, void *data
,
257 struct drm_file
*file
)
259 struct tegra_drm_file
*fpriv
= file
->driver_priv
;
260 struct drm_tegra_get_syncpt
*args
= data
;
261 struct tegra_drm_context
*context
;
262 struct host1x_syncpt
*syncpt
;
264 context
= tegra_drm_get_context(args
->context
);
266 if (!tegra_drm_file_owns_context(fpriv
, context
))
269 if (args
->index
>= context
->client
->base
.num_syncpts
)
272 syncpt
= context
->client
->base
.syncpts
[args
->index
];
273 args
->id
= host1x_syncpt_id(syncpt
);
278 static int tegra_submit(struct drm_device
*drm
, void *data
,
279 struct drm_file
*file
)
281 struct tegra_drm_file
*fpriv
= file
->driver_priv
;
282 struct drm_tegra_submit
*args
= data
;
283 struct tegra_drm_context
*context
;
285 context
= tegra_drm_get_context(args
->context
);
287 if (!tegra_drm_file_owns_context(fpriv
, context
))
290 return context
->client
->ops
->submit(context
, args
, drm
, file
);
294 static const struct drm_ioctl_desc tegra_drm_ioctls
[] = {
295 #ifdef CONFIG_DRM_TEGRA_STAGING
296 DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE
, tegra_gem_create
, DRM_UNLOCKED
| DRM_AUTH
),
297 DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP
, tegra_gem_mmap
, DRM_UNLOCKED
),
298 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ
, tegra_syncpt_read
, DRM_UNLOCKED
),
299 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR
, tegra_syncpt_incr
, DRM_UNLOCKED
),
300 DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT
, tegra_syncpt_wait
, DRM_UNLOCKED
),
301 DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL
, tegra_open_channel
, DRM_UNLOCKED
),
302 DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL
, tegra_close_channel
, DRM_UNLOCKED
),
303 DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT
, tegra_get_syncpt
, DRM_UNLOCKED
),
304 DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT
, tegra_submit
, DRM_UNLOCKED
),
308 static const struct file_operations tegra_drm_fops
= {
309 .owner
= THIS_MODULE
,
311 .release
= drm_release
,
312 .unlocked_ioctl
= drm_ioctl
,
313 .mmap
= tegra_drm_mmap
,
317 .compat_ioctl
= drm_compat_ioctl
,
319 .llseek
= noop_llseek
,
322 static struct drm_crtc
*tegra_crtc_from_pipe(struct drm_device
*drm
, int pipe
)
324 struct drm_crtc
*crtc
;
326 list_for_each_entry(crtc
, &drm
->mode_config
.crtc_list
, head
) {
327 struct tegra_dc
*dc
= to_tegra_dc(crtc
);
329 if (dc
->pipe
== pipe
)
336 static u32
tegra_drm_get_vblank_counter(struct drm_device
*dev
, int crtc
)
338 /* TODO: implement real hardware counter using syncpoints */
339 return drm_vblank_count(dev
, crtc
);
342 static int tegra_drm_enable_vblank(struct drm_device
*drm
, int pipe
)
344 struct drm_crtc
*crtc
= tegra_crtc_from_pipe(drm
, pipe
);
345 struct tegra_dc
*dc
= to_tegra_dc(crtc
);
350 tegra_dc_enable_vblank(dc
);
355 static void tegra_drm_disable_vblank(struct drm_device
*drm
, int pipe
)
357 struct drm_crtc
*crtc
= tegra_crtc_from_pipe(drm
, pipe
);
358 struct tegra_dc
*dc
= to_tegra_dc(crtc
);
361 tegra_dc_disable_vblank(dc
);
364 static void tegra_drm_preclose(struct drm_device
*drm
, struct drm_file
*file
)
366 struct tegra_drm_file
*fpriv
= file
->driver_priv
;
367 struct tegra_drm_context
*context
, *tmp
;
368 struct drm_crtc
*crtc
;
370 list_for_each_entry(crtc
, &drm
->mode_config
.crtc_list
, head
)
371 tegra_dc_cancel_page_flip(crtc
, file
);
373 list_for_each_entry_safe(context
, tmp
, &fpriv
->contexts
, list
)
374 tegra_drm_context_free(context
);
379 #ifdef CONFIG_DEBUG_FS
380 static int tegra_debugfs_framebuffers(struct seq_file
*s
, void *data
)
382 struct drm_info_node
*node
= (struct drm_info_node
*)s
->private;
383 struct drm_device
*drm
= node
->minor
->dev
;
384 struct drm_framebuffer
*fb
;
386 mutex_lock(&drm
->mode_config
.fb_lock
);
388 list_for_each_entry(fb
, &drm
->mode_config
.fb_list
, head
) {
389 seq_printf(s
, "%3d: user size: %d x %d, depth %d, %d bpp, refcount %d\n",
390 fb
->base
.id
, fb
->width
, fb
->height
, fb
->depth
,
392 atomic_read(&fb
->refcount
.refcount
));
395 mutex_unlock(&drm
->mode_config
.fb_lock
);
400 static struct drm_info_list tegra_debugfs_list
[] = {
401 { "framebuffers", tegra_debugfs_framebuffers
, 0 },
404 static int tegra_debugfs_init(struct drm_minor
*minor
)
406 return drm_debugfs_create_files(tegra_debugfs_list
,
407 ARRAY_SIZE(tegra_debugfs_list
),
408 minor
->debugfs_root
, minor
);
411 static void tegra_debugfs_cleanup(struct drm_minor
*minor
)
413 drm_debugfs_remove_files(tegra_debugfs_list
,
414 ARRAY_SIZE(tegra_debugfs_list
), minor
);
418 struct drm_driver tegra_drm_driver
= {
419 .driver_features
= DRIVER_MODESET
| DRIVER_GEM
,
420 .load
= tegra_drm_load
,
421 .unload
= tegra_drm_unload
,
422 .open
= tegra_drm_open
,
423 .preclose
= tegra_drm_preclose
,
424 .lastclose
= tegra_drm_lastclose
,
426 .get_vblank_counter
= tegra_drm_get_vblank_counter
,
427 .enable_vblank
= tegra_drm_enable_vblank
,
428 .disable_vblank
= tegra_drm_disable_vblank
,
430 #if defined(CONFIG_DEBUG_FS)
431 .debugfs_init
= tegra_debugfs_init
,
432 .debugfs_cleanup
= tegra_debugfs_cleanup
,
435 .gem_free_object
= tegra_bo_free_object
,
436 .gem_vm_ops
= &tegra_bo_vm_ops
,
437 .dumb_create
= tegra_bo_dumb_create
,
438 .dumb_map_offset
= tegra_bo_dumb_map_offset
,
439 .dumb_destroy
= drm_gem_dumb_destroy
,
441 .ioctls
= tegra_drm_ioctls
,
442 .num_ioctls
= ARRAY_SIZE(tegra_drm_ioctls
),
443 .fops
= &tegra_drm_fops
,
448 .major
= DRIVER_MAJOR
,
449 .minor
= DRIVER_MINOR
,
450 .patchlevel
= DRIVER_PATCHLEVEL
,
453 int tegra_drm_register_client(struct tegra_drm
*tegra
,
454 struct tegra_drm_client
*client
)
456 mutex_lock(&tegra
->clients_lock
);
457 list_add_tail(&client
->list
, &tegra
->clients
);
458 mutex_unlock(&tegra
->clients_lock
);
463 int tegra_drm_unregister_client(struct tegra_drm
*tegra
,
464 struct tegra_drm_client
*client
)
466 mutex_lock(&tegra
->clients_lock
);
467 list_del_init(&client
->list
);
468 mutex_unlock(&tegra
->clients_lock
);
473 static int host1x_drm_probe(struct host1x_device
*device
)
475 return drm_host1x_init(&tegra_drm_driver
, device
);
478 static int host1x_drm_remove(struct host1x_device
*device
)
480 drm_host1x_exit(&tegra_drm_driver
, device
);
485 static const struct of_device_id host1x_drm_subdevs
[] = {
486 { .compatible
= "nvidia,tegra20-dc", },
487 { .compatible
= "nvidia,tegra20-hdmi", },
488 { .compatible
= "nvidia,tegra20-gr2d", },
489 { .compatible
= "nvidia,tegra30-dc", },
490 { .compatible
= "nvidia,tegra30-hdmi", },
491 { .compatible
= "nvidia,tegra30-gr2d", },
495 static struct host1x_driver host1x_drm_driver
= {
497 .probe
= host1x_drm_probe
,
498 .remove
= host1x_drm_remove
,
499 .subdevs
= host1x_drm_subdevs
,
502 static int __init
host1x_drm_init(void)
506 err
= host1x_driver_register(&host1x_drm_driver
);
510 err
= platform_driver_register(&tegra_dc_driver
);
512 goto unregister_host1x
;
514 err
= platform_driver_register(&tegra_hdmi_driver
);
518 err
= platform_driver_register(&tegra_gr2d_driver
);
520 goto unregister_hdmi
;
525 platform_driver_unregister(&tegra_hdmi_driver
);
527 platform_driver_unregister(&tegra_dc_driver
);
529 host1x_driver_unregister(&host1x_drm_driver
);
532 module_init(host1x_drm_init
);
534 static void __exit
host1x_drm_exit(void)
536 platform_driver_unregister(&tegra_gr2d_driver
);
537 platform_driver_unregister(&tegra_hdmi_driver
);
538 platform_driver_unregister(&tegra_dc_driver
);
539 host1x_driver_unregister(&host1x_drm_driver
);
541 module_exit(host1x_drm_exit
);
543 MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
544 MODULE_DESCRIPTION("NVIDIA Tegra DRM driver");
545 MODULE_LICENSE("GPL v2");