gpu: host1x: Remove second host1x driver
[linux-2.6-block.git] / drivers / gpu / host1x / drm / drm.c
1 /*
2  * Copyright (C) 2012 Avionic Design GmbH
3  * Copyright (C) 2012 NVIDIA CORPORATION.  All rights reserved.
4  *
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.
8  */
9
10 #include <linux/module.h>
11 #include <linux/of_address.h>
12 #include <linux/of_platform.h>
13
14 #include <linux/dma-mapping.h>
15 #include <asm/dma-iommu.h>
16
17 #include "host1x_client.h"
18 #include "drm.h"
19
20 #define DRIVER_NAME "tegra"
21 #define DRIVER_DESC "NVIDIA Tegra graphics"
22 #define DRIVER_DATE "20120330"
23 #define DRIVER_MAJOR 0
24 #define DRIVER_MINOR 0
25 #define DRIVER_PATCHLEVEL 0
26
27 struct host1x_drm_client {
28         struct host1x_client *client;
29         struct device_node *np;
30         struct list_head list;
31 };
32
33 static int host1x_add_drm_client(struct host1x_drm *host1x,
34                                  struct device_node *np)
35 {
36         struct host1x_drm_client *client;
37
38         client = kzalloc(sizeof(*client), GFP_KERNEL);
39         if (!client)
40                 return -ENOMEM;
41
42         INIT_LIST_HEAD(&client->list);
43         client->np = of_node_get(np);
44
45         list_add_tail(&client->list, &host1x->drm_clients);
46
47         return 0;
48 }
49
50 static int host1x_activate_drm_client(struct host1x_drm *host1x,
51                                       struct host1x_drm_client *drm,
52                                       struct host1x_client *client)
53 {
54         mutex_lock(&host1x->drm_clients_lock);
55         list_del_init(&drm->list);
56         list_add_tail(&drm->list, &host1x->drm_active);
57         drm->client = client;
58         mutex_unlock(&host1x->drm_clients_lock);
59
60         return 0;
61 }
62
63 static int host1x_remove_drm_client(struct host1x_drm *host1x,
64                                     struct host1x_drm_client *client)
65 {
66         mutex_lock(&host1x->drm_clients_lock);
67         list_del_init(&client->list);
68         mutex_unlock(&host1x->drm_clients_lock);
69
70         of_node_put(client->np);
71         kfree(client);
72
73         return 0;
74 }
75
76 static int host1x_parse_dt(struct host1x_drm *host1x)
77 {
78         static const char * const compat[] = {
79                 "nvidia,tegra20-dc",
80                 "nvidia,tegra20-hdmi",
81                 "nvidia,tegra30-dc",
82                 "nvidia,tegra30-hdmi",
83         };
84         unsigned int i;
85         int err;
86
87         for (i = 0; i < ARRAY_SIZE(compat); i++) {
88                 struct device_node *np;
89
90                 for_each_child_of_node(host1x->dev->of_node, np) {
91                         if (of_device_is_compatible(np, compat[i]) &&
92                             of_device_is_available(np)) {
93                                 err = host1x_add_drm_client(host1x, np);
94                                 if (err < 0)
95                                         return err;
96                         }
97                 }
98         }
99
100         return 0;
101 }
102
103 int host1x_drm_alloc(struct platform_device *pdev)
104 {
105         struct host1x_drm *host1x;
106         int err;
107
108         host1x = devm_kzalloc(&pdev->dev, sizeof(*host1x), GFP_KERNEL);
109         if (!host1x)
110                 return -ENOMEM;
111
112         mutex_init(&host1x->drm_clients_lock);
113         INIT_LIST_HEAD(&host1x->drm_clients);
114         INIT_LIST_HEAD(&host1x->drm_active);
115         mutex_init(&host1x->clients_lock);
116         INIT_LIST_HEAD(&host1x->clients);
117         host1x->dev = &pdev->dev;
118
119         err = host1x_parse_dt(host1x);
120         if (err < 0) {
121                 dev_err(&pdev->dev, "failed to parse DT: %d\n", err);
122                 return err;
123         }
124
125         host1x_set_drm_data(&pdev->dev, host1x);
126
127         return 0;
128 }
129
130 int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm)
131 {
132         struct host1x_client *client;
133
134         mutex_lock(&host1x->clients_lock);
135
136         list_for_each_entry(client, &host1x->clients, list) {
137                 if (client->ops && client->ops->drm_init) {
138                         int err = client->ops->drm_init(client, drm);
139                         if (err < 0) {
140                                 dev_err(host1x->dev,
141                                         "DRM setup failed for %s: %d\n",
142                                         dev_name(client->dev), err);
143                                 return err;
144                         }
145                 }
146         }
147
148         mutex_unlock(&host1x->clients_lock);
149
150         return 0;
151 }
152
153 int host1x_drm_exit(struct host1x_drm *host1x)
154 {
155         struct platform_device *pdev = to_platform_device(host1x->dev);
156         struct host1x_client *client;
157
158         if (!host1x->drm)
159                 return 0;
160
161         mutex_lock(&host1x->clients_lock);
162
163         list_for_each_entry_reverse(client, &host1x->clients, list) {
164                 if (client->ops && client->ops->drm_exit) {
165                         int err = client->ops->drm_exit(client);
166                         if (err < 0) {
167                                 dev_err(host1x->dev,
168                                         "DRM cleanup failed for %s: %d\n",
169                                         dev_name(client->dev), err);
170                                 return err;
171                         }
172                 }
173         }
174
175         mutex_unlock(&host1x->clients_lock);
176
177         drm_platform_exit(&tegra_drm_driver, pdev);
178         host1x->drm = NULL;
179
180         return 0;
181 }
182
183 int host1x_register_client(struct host1x_drm *host1x,
184                            struct host1x_client *client)
185 {
186         struct host1x_drm_client *drm, *tmp;
187         int err;
188
189         mutex_lock(&host1x->clients_lock);
190         list_add_tail(&client->list, &host1x->clients);
191         mutex_unlock(&host1x->clients_lock);
192
193         list_for_each_entry_safe(drm, tmp, &host1x->drm_clients, list)
194                 if (drm->np == client->dev->of_node)
195                         host1x_activate_drm_client(host1x, drm, client);
196
197         if (list_empty(&host1x->drm_clients)) {
198                 struct platform_device *pdev = to_platform_device(host1x->dev);
199
200                 err = drm_platform_init(&tegra_drm_driver, pdev);
201                 if (err < 0) {
202                         dev_err(host1x->dev, "drm_platform_init(): %d\n", err);
203                         return err;
204                 }
205         }
206
207         return 0;
208 }
209
210 int host1x_unregister_client(struct host1x_drm *host1x,
211                              struct host1x_client *client)
212 {
213         struct host1x_drm_client *drm, *tmp;
214         int err;
215
216         list_for_each_entry_safe(drm, tmp, &host1x->drm_active, list) {
217                 if (drm->client == client) {
218                         err = host1x_drm_exit(host1x);
219                         if (err < 0) {
220                                 dev_err(host1x->dev, "host1x_drm_exit(): %d\n",
221                                         err);
222                                 return err;
223                         }
224
225                         host1x_remove_drm_client(host1x, drm);
226                         break;
227                 }
228         }
229
230         mutex_lock(&host1x->clients_lock);
231         list_del_init(&client->list);
232         mutex_unlock(&host1x->clients_lock);
233
234         return 0;
235 }
236
237 static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
238 {
239         struct host1x_drm *host1x;
240         int err;
241
242         host1x = host1x_get_drm_data(drm->dev);
243         drm->dev_private = host1x;
244         host1x->drm = drm;
245
246         drm_mode_config_init(drm);
247
248         err = host1x_drm_init(host1x, drm);
249         if (err < 0)
250                 return err;
251
252         err = drm_vblank_init(drm, drm->mode_config.num_crtc);
253         if (err < 0)
254                 return err;
255
256         err = tegra_drm_fb_init(drm);
257         if (err < 0)
258                 return err;
259
260         drm_kms_helper_poll_init(drm);
261
262         return 0;
263 }
264
265 static int tegra_drm_unload(struct drm_device *drm)
266 {
267         drm_kms_helper_poll_fini(drm);
268         tegra_drm_fb_exit(drm);
269
270         drm_mode_config_cleanup(drm);
271
272         return 0;
273 }
274
275 static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
276 {
277         return 0;
278 }
279
280 static void tegra_drm_lastclose(struct drm_device *drm)
281 {
282         struct host1x_drm *host1x = drm->dev_private;
283
284         drm_fbdev_cma_restore_mode(host1x->fbdev);
285 }
286
287 static struct drm_ioctl_desc tegra_drm_ioctls[] = {
288 };
289
290 static const struct file_operations tegra_drm_fops = {
291         .owner = THIS_MODULE,
292         .open = drm_open,
293         .release = drm_release,
294         .unlocked_ioctl = drm_ioctl,
295         .mmap = drm_gem_cma_mmap,
296         .poll = drm_poll,
297         .fasync = drm_fasync,
298         .read = drm_read,
299 #ifdef CONFIG_COMPAT
300         .compat_ioctl = drm_compat_ioctl,
301 #endif
302         .llseek = noop_llseek,
303 };
304
305 static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe)
306 {
307         struct drm_crtc *crtc;
308
309         list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) {
310                 struct tegra_dc *dc = to_tegra_dc(crtc);
311
312                 if (dc->pipe == pipe)
313                         return crtc;
314         }
315
316         return NULL;
317 }
318
319 static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc)
320 {
321         /* TODO: implement real hardware counter using syncpoints */
322         return drm_vblank_count(dev, crtc);
323 }
324
325 static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
326 {
327         struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
328         struct tegra_dc *dc = to_tegra_dc(crtc);
329
330         if (!crtc)
331                 return -ENODEV;
332
333         tegra_dc_enable_vblank(dc);
334
335         return 0;
336 }
337
338 static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe)
339 {
340         struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
341         struct tegra_dc *dc = to_tegra_dc(crtc);
342
343         if (crtc)
344                 tegra_dc_disable_vblank(dc);
345 }
346
347 static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
348 {
349         struct drm_crtc *crtc;
350
351         list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
352                 tegra_dc_cancel_page_flip(crtc, file);
353 }
354
355 #ifdef CONFIG_DEBUG_FS
356 static int tegra_debugfs_framebuffers(struct seq_file *s, void *data)
357 {
358         struct drm_info_node *node = (struct drm_info_node *)s->private;
359         struct drm_device *drm = node->minor->dev;
360         struct drm_framebuffer *fb;
361
362         mutex_lock(&drm->mode_config.fb_lock);
363
364         list_for_each_entry(fb, &drm->mode_config.fb_list, head) {
365                 seq_printf(s, "%3d: user size: %d x %d, depth %d, %d bpp, refcount %d\n",
366                            fb->base.id, fb->width, fb->height, fb->depth,
367                            fb->bits_per_pixel,
368                            atomic_read(&fb->refcount.refcount));
369         }
370
371         mutex_unlock(&drm->mode_config.fb_lock);
372
373         return 0;
374 }
375
376 static struct drm_info_list tegra_debugfs_list[] = {
377         { "framebuffers", tegra_debugfs_framebuffers, 0 },
378 };
379
380 static int tegra_debugfs_init(struct drm_minor *minor)
381 {
382         return drm_debugfs_create_files(tegra_debugfs_list,
383                                         ARRAY_SIZE(tegra_debugfs_list),
384                                         minor->debugfs_root, minor);
385 }
386
387 static void tegra_debugfs_cleanup(struct drm_minor *minor)
388 {
389         drm_debugfs_remove_files(tegra_debugfs_list,
390                                  ARRAY_SIZE(tegra_debugfs_list), minor);
391 }
392 #endif
393
394 struct drm_driver tegra_drm_driver = {
395         .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM,
396         .load = tegra_drm_load,
397         .unload = tegra_drm_unload,
398         .open = tegra_drm_open,
399         .preclose = tegra_drm_preclose,
400         .lastclose = tegra_drm_lastclose,
401
402         .get_vblank_counter = tegra_drm_get_vblank_counter,
403         .enable_vblank = tegra_drm_enable_vblank,
404         .disable_vblank = tegra_drm_disable_vblank,
405
406 #if defined(CONFIG_DEBUG_FS)
407         .debugfs_init = tegra_debugfs_init,
408         .debugfs_cleanup = tegra_debugfs_cleanup,
409 #endif
410
411         .gem_free_object = drm_gem_cma_free_object,
412         .gem_vm_ops = &drm_gem_cma_vm_ops,
413         .dumb_create = drm_gem_cma_dumb_create,
414         .dumb_map_offset = drm_gem_cma_dumb_map_offset,
415         .dumb_destroy = drm_gem_cma_dumb_destroy,
416
417         .ioctls = tegra_drm_ioctls,
418         .num_ioctls = ARRAY_SIZE(tegra_drm_ioctls),
419         .fops = &tegra_drm_fops,
420
421         .name = DRIVER_NAME,
422         .desc = DRIVER_DESC,
423         .date = DRIVER_DATE,
424         .major = DRIVER_MAJOR,
425         .minor = DRIVER_MINOR,
426         .patchlevel = DRIVER_PATCHLEVEL,
427 };