aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2013-10-14 08:43:22 -0400
committerThierry Reding <treding@nvidia.com>2013-10-31 04:55:33 -0400
commit776dc38403676f499a73d32e2e7c61eb5b42f736 (patch)
tree5c9f8d670b51d743c5bbab45ec401e30f22579c1
parent35d747a81d7eb824bd0c3476cd0c564b52ad5353 (diff)
drm/tegra: Move subdevice infrastructure to host1x
The Tegra DRM driver currently uses some infrastructure to defer the DRM core initialization until all required devices have registered. The same infrastructure can potentially be used by any other driver that requires more than a single sub-device of the host1x module. Make the infrastructure more generic and keep only the DRM specific code in the DRM part of the driver. Eventually this will make it easy to move the DRM driver part back to the DRM subsystem. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/host1x/Makefile2
-rw-r--r--drivers/gpu/host1x/bus.c550
-rw-r--r--drivers/gpu/host1x/bus.h (renamed from drivers/gpu/host1x/host1x_client.h)24
-rw-r--r--drivers/gpu/host1x/dev.c60
-rw-r--r--drivers/gpu/host1x/dev.h9
-rw-r--r--drivers/gpu/host1x/drm/bus.c76
-rw-r--r--drivers/gpu/host1x/drm/dc.c30
-rw-r--r--drivers/gpu/host1x/drm/drm.c347
-rw-r--r--drivers/gpu/host1x/drm/drm.h31
-rw-r--r--drivers/gpu/host1x/drm/gr2d.c60
-rw-r--r--drivers/gpu/host1x/drm/hdmi.c28
-rw-r--r--include/drm/drmP.h1
-rw-r--r--include/linux/host1x.h45
13 files changed, 898 insertions, 365 deletions
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile
index 3b037b6e0298..7b781920c58a 100644
--- a/drivers/gpu/host1x/Makefile
+++ b/drivers/gpu/host1x/Makefile
@@ -1,6 +1,7 @@
1ccflags-y = -Idrivers/gpu/host1x 1ccflags-y = -Idrivers/gpu/host1x
2 2
3host1x-y = \ 3host1x-y = \
4 bus.o \
4 syncpt.o \ 5 syncpt.o \
5 dev.o \ 6 dev.o \
6 intr.o \ 7 intr.o \
@@ -17,4 +18,5 @@ host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o
17host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o 18host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o
18host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o 19host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o
19host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o 20host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o
21host1x-$(CONFIG_DRM_TEGRA) += drm/bus.o
20obj-$(CONFIG_TEGRA_HOST1X) += host1x.o 22obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
new file mode 100644
index 000000000000..509383f8be03
--- /dev/null
+++ b/drivers/gpu/host1x/bus.c
@@ -0,0 +1,550 @@
1/*
2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012-2013, NVIDIA Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <linux/host1x.h>
19#include <linux/of.h>
20#include <linux/slab.h>
21
22#include "dev.h"
23
24static DEFINE_MUTEX(clients_lock);
25static LIST_HEAD(clients);
26
27static DEFINE_MUTEX(drivers_lock);
28static LIST_HEAD(drivers);
29
30static DEFINE_MUTEX(devices_lock);
31static LIST_HEAD(devices);
32
33struct host1x_subdev {
34 struct host1x_client *client;
35 struct device_node *np;
36 struct list_head list;
37};
38
39/**
40 * host1x_subdev_add() - add a new subdevice with an associated device node
41 */
42static int host1x_subdev_add(struct host1x_device *device,
43 struct device_node *np)
44{
45 struct host1x_subdev *subdev;
46
47 subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
48 if (!subdev)
49 return -ENOMEM;
50
51 INIT_LIST_HEAD(&subdev->list);
52 subdev->np = of_node_get(np);
53
54 mutex_lock(&device->subdevs_lock);
55 list_add_tail(&subdev->list, &device->subdevs);
56 mutex_unlock(&device->subdevs_lock);
57
58 return 0;
59}
60
61/**
62 * host1x_subdev_del() - remove subdevice
63 */
64static void host1x_subdev_del(struct host1x_subdev *subdev)
65{
66 list_del(&subdev->list);
67 of_node_put(subdev->np);
68 kfree(subdev);
69}
70
71/**
72 * host1x_device_parse_dt() - scan device tree and add matching subdevices
73 */
74static int host1x_device_parse_dt(struct host1x_device *device)
75{
76 struct device_node *np;
77 int err;
78
79 for_each_child_of_node(device->dev.parent->of_node, np) {
80 if (of_match_node(device->driver->subdevs, np) &&
81 of_device_is_available(np)) {
82 err = host1x_subdev_add(device, np);
83 if (err < 0)
84 return err;
85 }
86 }
87
88 return 0;
89}
90
91static void host1x_subdev_register(struct host1x_device *device,
92 struct host1x_subdev *subdev,
93 struct host1x_client *client)
94{
95 int err;
96
97 /*
98 * Move the subdevice to the list of active (registered) subdevices
99 * and associate it with a client. At the same time, associate the
100 * client with its parent device.
101 */
102 mutex_lock(&device->subdevs_lock);
103 mutex_lock(&device->clients_lock);
104 list_move_tail(&client->list, &device->clients);
105 list_move_tail(&subdev->list, &device->active);
106 client->parent = &device->dev;
107 subdev->client = client;
108 mutex_unlock(&device->clients_lock);
109 mutex_unlock(&device->subdevs_lock);
110
111 /*
112 * When all subdevices have been registered, the composite device is
113 * ready to be probed.
114 */
115 if (list_empty(&device->subdevs)) {
116 err = device->driver->probe(device);
117 if (err < 0)
118 dev_err(&device->dev, "probe failed: %d\n", err);
119 }
120}
121
122static void __host1x_subdev_unregister(struct host1x_device *device,
123 struct host1x_subdev *subdev)
124{
125 struct host1x_client *client = subdev->client;
126 int err;
127
128 /*
129 * If all subdevices have been activated, we're about to remove the
130 * first active subdevice, so unload the driver first.
131 */
132 if (list_empty(&device->subdevs)) {
133 err = device->driver->remove(device);
134 if (err < 0)
135 dev_err(&device->dev, "remove failed: %d\n", err);
136 }
137
138 /*
139 * Move the subdevice back to the list of idle subdevices and remove
140 * it from list of clients.
141 */
142 mutex_lock(&device->clients_lock);
143 subdev->client = NULL;
144 client->parent = NULL;
145 list_move_tail(&subdev->list, &device->subdevs);
146 /*
147 * XXX: Perhaps don't do this here, but rather explicitly remove it
148 * when the device is about to be deleted.
149 *
150 * This is somewhat complicated by the fact that this function is
151 * used to remove the subdevice when a client is unregistered but
152 * also when the composite device is about to be removed.
153 */
154 list_del_init(&client->list);
155 mutex_unlock(&device->clients_lock);
156}
157
158static void host1x_subdev_unregister(struct host1x_device *device,
159 struct host1x_subdev *subdev)
160{
161 mutex_lock(&device->subdevs_lock);
162 __host1x_subdev_unregister(device, subdev);
163 mutex_unlock(&device->subdevs_lock);
164}
165
166int host1x_device_init(struct host1x_device *device)
167{
168 struct host1x_client *client;
169 int err;
170
171 mutex_lock(&device->clients_lock);
172
173 list_for_each_entry(client, &device->clients, list) {
174 if (client->ops && client->ops->init) {
175 err = client->ops->init(client);
176 if (err < 0) {
177 dev_err(&device->dev,
178 "failed to initialize %s: %d\n",
179 dev_name(client->dev), err);
180 mutex_unlock(&device->clients_lock);
181 return err;
182 }
183 }
184 }
185
186 mutex_unlock(&device->clients_lock);
187
188 return 0;
189}
190
191int host1x_device_exit(struct host1x_device *device)
192{
193 struct host1x_client *client;
194 int err;
195
196 mutex_lock(&device->clients_lock);
197
198 list_for_each_entry_reverse(client, &device->clients, list) {
199 if (client->ops && client->ops->exit) {
200 err = client->ops->exit(client);
201 if (err < 0) {
202 dev_err(&device->dev,
203 "failed to cleanup %s: %d\n",
204 dev_name(client->dev), err);
205 mutex_unlock(&device->clients_lock);
206 return err;
207 }
208 }
209 }
210
211 mutex_unlock(&device->clients_lock);
212
213 return 0;
214}
215
216static int host1x_register_client(struct host1x *host1x,
217 struct host1x_client *client)
218{
219 struct host1x_device *device;
220 struct host1x_subdev *subdev;
221
222 mutex_lock(&host1x->devices_lock);
223
224 list_for_each_entry(device, &host1x->devices, list) {
225 list_for_each_entry(subdev, &device->subdevs, list) {
226 if (subdev->np == client->dev->of_node) {
227 host1x_subdev_register(device, subdev, client);
228 mutex_unlock(&host1x->devices_lock);
229 return 0;
230 }
231 }
232 }
233
234 mutex_unlock(&host1x->devices_lock);
235 return -ENODEV;
236}
237
238static int host1x_unregister_client(struct host1x *host1x,
239 struct host1x_client *client)
240{
241 struct host1x_device *device, *dt;
242 struct host1x_subdev *subdev;
243
244 mutex_lock(&host1x->devices_lock);
245
246 list_for_each_entry_safe(device, dt, &host1x->devices, list) {
247 list_for_each_entry(subdev, &device->active, list) {
248 if (subdev->client == client) {
249 host1x_subdev_unregister(device, subdev);
250 mutex_unlock(&host1x->devices_lock);
251 return 0;
252 }
253 }
254 }
255
256 mutex_unlock(&host1x->devices_lock);
257 return -ENODEV;
258}
259
260struct bus_type host1x_bus_type = {
261 .name = "host1x",
262};
263
264int host1x_bus_init(void)
265{
266 return bus_register(&host1x_bus_type);
267}
268
269void host1x_bus_exit(void)
270{
271 bus_unregister(&host1x_bus_type);
272}
273
274static void host1x_device_release(struct device *dev)
275{
276 struct host1x_device *device = to_host1x_device(dev);
277
278 kfree(device);
279}
280
281static int host1x_device_add(struct host1x *host1x,
282 struct host1x_driver *driver)
283{
284 struct host1x_client *client, *tmp;
285 struct host1x_subdev *subdev;
286 struct host1x_device *device;
287 int err;
288
289 device = kzalloc(sizeof(*device), GFP_KERNEL);
290 if (!device)
291 return -ENOMEM;
292
293 mutex_init(&device->subdevs_lock);
294 INIT_LIST_HEAD(&device->subdevs);
295 INIT_LIST_HEAD(&device->active);
296 mutex_init(&device->clients_lock);
297 INIT_LIST_HEAD(&device->clients);
298 INIT_LIST_HEAD(&device->list);
299 device->driver = driver;
300
301 device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
302 device->dev.dma_mask = &device->dev.coherent_dma_mask;
303 device->dev.release = host1x_device_release;
304 dev_set_name(&device->dev, driver->name);
305 device->dev.bus = &host1x_bus_type;
306 device->dev.parent = host1x->dev;
307
308 err = device_register(&device->dev);
309 if (err < 0)
310 return err;
311
312 err = host1x_device_parse_dt(device);
313 if (err < 0) {
314 device_unregister(&device->dev);
315 return err;
316 }
317
318 mutex_lock(&host1x->devices_lock);
319 list_add_tail(&device->list, &host1x->devices);
320 mutex_unlock(&host1x->devices_lock);
321
322 mutex_lock(&clients_lock);
323
324 list_for_each_entry_safe(client, tmp, &clients, list) {
325 list_for_each_entry(subdev, &device->subdevs, list) {
326 if (subdev->np == client->dev->of_node) {
327 host1x_subdev_register(device, subdev, client);
328 break;
329 }
330 }
331 }
332
333 mutex_unlock(&clients_lock);
334
335 return 0;
336}
337
338/*
339 * Removes a device by first unregistering any subdevices and then removing
340 * itself from the list of devices.
341 *
342 * This function must be called with the host1x->devices_lock held.
343 */
344static void host1x_device_del(struct host1x *host1x,
345 struct host1x_device *device)
346{
347 struct host1x_subdev *subdev, *sd;
348 struct host1x_client *client, *cl;
349
350 mutex_lock(&device->subdevs_lock);
351
352 /* unregister subdevices */
353 list_for_each_entry_safe(subdev, sd, &device->active, list) {
354 /*
355 * host1x_subdev_unregister() will remove the client from
356 * any lists, so we'll need to manually add it back to the
357 * list of idle clients.
358 *
359 * XXX: Alternatively, perhaps don't remove the client from
360 * any lists in host1x_subdev_unregister() and instead do
361 * that explicitly from host1x_unregister_client()?
362 */
363 client = subdev->client;
364
365 __host1x_subdev_unregister(device, subdev);
366
367 /* add the client to the list of idle clients */
368 mutex_lock(&clients_lock);
369 list_add_tail(&client->list, &clients);
370 mutex_unlock(&clients_lock);
371 }
372
373 /* remove subdevices */
374 list_for_each_entry_safe(subdev, sd, &device->subdevs, list)
375 host1x_subdev_del(subdev);
376
377 mutex_unlock(&device->subdevs_lock);
378
379 /* move clients to idle list */
380 mutex_lock(&clients_lock);
381 mutex_lock(&device->clients_lock);
382
383 list_for_each_entry_safe(client, cl, &device->clients, list)
384 list_move_tail(&client->list, &clients);
385
386 mutex_unlock(&device->clients_lock);
387 mutex_unlock(&clients_lock);
388
389 /* finally remove the device */
390 list_del_init(&device->list);
391 device_unregister(&device->dev);
392}
393
394static void host1x_attach_driver(struct host1x *host1x,
395 struct host1x_driver *driver)
396{
397 struct host1x_device *device;
398 int err;
399
400 mutex_lock(&host1x->devices_lock);
401
402 list_for_each_entry(device, &host1x->devices, list) {
403 if (device->driver == driver) {
404 mutex_unlock(&host1x->devices_lock);
405 return;
406 }
407 }
408
409 mutex_unlock(&host1x->devices_lock);
410
411 err = host1x_device_add(host1x, driver);
412 if (err < 0)
413 dev_err(host1x->dev, "failed to allocate device: %d\n", err);
414}
415
416static void host1x_detach_driver(struct host1x *host1x,
417 struct host1x_driver *driver)
418{
419 struct host1x_device *device, *tmp;
420
421 mutex_lock(&host1x->devices_lock);
422
423 list_for_each_entry_safe(device, tmp, &host1x->devices, list)
424 if (device->driver == driver)
425 host1x_device_del(host1x, device);
426
427 mutex_unlock(&host1x->devices_lock);
428}
429
430int host1x_register(struct host1x *host1x)
431{
432 struct host1x_driver *driver;
433
434 mutex_lock(&devices_lock);
435 list_add_tail(&host1x->list, &devices);
436 mutex_unlock(&devices_lock);
437
438 mutex_lock(&drivers_lock);
439
440 list_for_each_entry(driver, &drivers, list)
441 host1x_attach_driver(host1x, driver);
442
443 mutex_unlock(&drivers_lock);
444
445 return 0;
446}
447
448int host1x_unregister(struct host1x *host1x)
449{
450 struct host1x_driver *driver;
451
452 mutex_lock(&drivers_lock);
453
454 list_for_each_entry(driver, &drivers, list)
455 host1x_detach_driver(host1x, driver);
456
457 mutex_unlock(&drivers_lock);
458
459 mutex_lock(&devices_lock);
460 list_del_init(&host1x->list);
461 mutex_unlock(&devices_lock);
462
463 return 0;
464}
465
466int host1x_driver_register(struct host1x_driver *driver)
467{
468 struct host1x *host1x;
469
470 INIT_LIST_HEAD(&driver->list);
471
472 mutex_lock(&drivers_lock);
473 list_add_tail(&driver->list, &drivers);
474 mutex_unlock(&drivers_lock);
475
476 mutex_lock(&devices_lock);
477
478 list_for_each_entry(host1x, &devices, list)
479 host1x_attach_driver(host1x, driver);
480
481 mutex_unlock(&devices_lock);
482
483 return 0;
484}
485EXPORT_SYMBOL(host1x_driver_register);
486
487void host1x_driver_unregister(struct host1x_driver *driver)
488{
489 mutex_lock(&drivers_lock);
490 list_del_init(&driver->list);
491 mutex_unlock(&drivers_lock);
492}
493EXPORT_SYMBOL(host1x_driver_unregister);
494
495int host1x_client_register(struct host1x_client *client)
496{
497 struct host1x *host1x;
498 int err;
499
500 mutex_lock(&devices_lock);
501
502 list_for_each_entry(host1x, &devices, list) {
503 err = host1x_register_client(host1x, client);
504 if (!err) {
505 mutex_unlock(&devices_lock);
506 return 0;
507 }
508 }
509
510 mutex_unlock(&devices_lock);
511
512 mutex_lock(&clients_lock);
513 list_add_tail(&client->list, &clients);
514 mutex_unlock(&clients_lock);
515
516 return 0;
517}
518EXPORT_SYMBOL(host1x_client_register);
519
520int host1x_client_unregister(struct host1x_client *client)
521{
522 struct host1x_client *c;
523 struct host1x *host1x;
524 int err;
525
526 mutex_lock(&devices_lock);
527
528 list_for_each_entry(host1x, &devices, list) {
529 err = host1x_unregister_client(host1x, client);
530 if (!err) {
531 mutex_unlock(&devices_lock);
532 return 0;
533 }
534 }
535
536 mutex_unlock(&devices_lock);
537 mutex_lock(&clients_lock);
538
539 list_for_each_entry(c, &clients, list) {
540 if (c == client) {
541 list_del_init(&c->list);
542 break;
543 }
544 }
545
546 mutex_unlock(&clients_lock);
547
548 return 0;
549}
550EXPORT_SYMBOL(host1x_client_unregister);
diff --git a/drivers/gpu/host1x/host1x_client.h b/drivers/gpu/host1x/bus.h
index 6a0bd0268042..4099e99212c8 100644
--- a/drivers/gpu/host1x/host1x_client.h
+++ b/drivers/gpu/host1x/bus.h
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2013, NVIDIA Corporation. 2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012-2013, NVIDIA Corporation
3 * 4 *
4 * This program is free software; you can redistribute it and/or modify it 5 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License, 6 * under the terms and conditions of the GNU General Public License,
@@ -14,22 +15,15 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 16 */
16 17
17#ifndef HOST1X_CLIENT_H 18#ifndef HOST1X_BUS_H
18#define HOST1X_CLIENT_H 19#define HOST1X_BUS_H
19 20
20struct device; 21struct host1x;
21struct platform_device;
22 22
23#ifdef CONFIG_DRM_TEGRA 23int host1x_bus_init(void);
24int tegra_drm_alloc(struct platform_device *pdev); 24void host1x_bus_exit(void);
25#else
26static inline int tegra_drm_alloc(struct platform_device *pdev)
27{
28 return 0;
29}
30#endif
31 25
32void host1x_set_drm_data(struct device *dev, void *data); 26int host1x_register(struct host1x *host1x);
33void *host1x_get_drm_data(struct device *dev); 27int host1x_unregister(struct host1x *host1x);
34 28
35#endif 29#endif
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 105aa4ed665a..de0fd552710d 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -27,24 +27,12 @@
27#define CREATE_TRACE_POINTS 27#define CREATE_TRACE_POINTS
28#include <trace/events/host1x.h> 28#include <trace/events/host1x.h>
29 29
30#include "bus.h"
30#include "dev.h" 31#include "dev.h"
31#include "intr.h" 32#include "intr.h"
32#include "channel.h" 33#include "channel.h"
33#include "debug.h" 34#include "debug.h"
34#include "hw/host1x01.h" 35#include "hw/host1x01.h"
35#include "host1x_client.h"
36
37void host1x_set_drm_data(struct device *dev, void *data)
38{
39 struct host1x *host1x = dev_get_drvdata(dev);
40 host1x->drm_data = data;
41}
42
43void *host1x_get_drm_data(struct device *dev)
44{
45 struct host1x *host1x = dev_get_drvdata(dev);
46 return host1x ? host1x->drm_data : NULL;
47}
48 36
49void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) 37void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
50{ 38{
@@ -114,6 +102,9 @@ static int host1x_probe(struct platform_device *pdev)
114 if (!host) 102 if (!host)
115 return -ENOMEM; 103 return -ENOMEM;
116 104
105 mutex_init(&host->devices_lock);
106 INIT_LIST_HEAD(&host->devices);
107 INIT_LIST_HEAD(&host->list);
117 host->dev = &pdev->dev; 108 host->dev = &pdev->dev;
118 host->info = id->data; 109 host->info = id->data;
119 110
@@ -163,10 +154,14 @@ static int host1x_probe(struct platform_device *pdev)
163 154
164 host1x_debug_init(host); 155 host1x_debug_init(host);
165 156
166 tegra_drm_alloc(pdev); 157 err = host1x_register(host);
158 if (err < 0)
159 goto fail_deinit_intr;
167 160
168 return 0; 161 return 0;
169 162
163fail_deinit_intr:
164 host1x_intr_deinit(host);
170fail_deinit_syncpt: 165fail_deinit_syncpt:
171 host1x_syncpt_deinit(host); 166 host1x_syncpt_deinit(host);
172 return err; 167 return err;
@@ -176,6 +171,7 @@ static int host1x_remove(struct platform_device *pdev)
176{ 171{
177 struct host1x *host = platform_get_drvdata(pdev); 172 struct host1x *host = platform_get_drvdata(pdev);
178 173
174 host1x_unregister(host);
179 host1x_intr_deinit(host); 175 host1x_intr_deinit(host);
180 host1x_syncpt_deinit(host); 176 host1x_syncpt_deinit(host);
181 clk_disable_unprepare(host->clk); 177 clk_disable_unprepare(host->clk);
@@ -196,46 +192,24 @@ static int __init tegra_host1x_init(void)
196{ 192{
197 int err; 193 int err;
198 194
199 err = platform_driver_register(&tegra_host1x_driver); 195 err = host1x_bus_init();
200 if (err < 0) 196 if (err < 0)
201 return err; 197 return err;
202 198
203#ifdef CONFIG_DRM_TEGRA 199 err = platform_driver_register(&tegra_host1x_driver);
204 err = platform_driver_register(&tegra_dc_driver); 200 if (err < 0) {
205 if (err < 0) 201 host1x_bus_exit();
206 goto unregister_host1x; 202 return err;
207 203 }
208 err = platform_driver_register(&tegra_hdmi_driver);
209 if (err < 0)
210 goto unregister_dc;
211
212 err = platform_driver_register(&tegra_gr2d_driver);
213 if (err < 0)
214 goto unregister_hdmi;
215#endif
216 204
217 return 0; 205 return 0;
218
219#ifdef CONFIG_DRM_TEGRA
220unregister_hdmi:
221 platform_driver_unregister(&tegra_hdmi_driver);
222unregister_dc:
223 platform_driver_unregister(&tegra_dc_driver);
224unregister_host1x:
225 platform_driver_unregister(&tegra_host1x_driver);
226 return err;
227#endif
228} 206}
229module_init(tegra_host1x_init); 207module_init(tegra_host1x_init);
230 208
231static void __exit tegra_host1x_exit(void) 209static void __exit tegra_host1x_exit(void)
232{ 210{
233#ifdef CONFIG_DRM_TEGRA
234 platform_driver_unregister(&tegra_gr2d_driver);
235 platform_driver_unregister(&tegra_hdmi_driver);
236 platform_driver_unregister(&tegra_dc_driver);
237#endif
238 platform_driver_unregister(&tegra_host1x_driver); 211 platform_driver_unregister(&tegra_host1x_driver);
212 host1x_bus_exit();
239} 213}
240module_exit(tegra_host1x_exit); 214module_exit(tegra_host1x_exit);
241 215
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
index bed90a8131be..6cf689b9e17b 100644
--- a/drivers/gpu/host1x/dev.h
+++ b/drivers/gpu/host1x/dev.h
@@ -125,7 +125,10 @@ struct host1x {
125 125
126 struct dentry *debugfs; 126 struct dentry *debugfs;
127 127
128 void *drm_data; 128 struct mutex devices_lock;
129 struct list_head devices;
130
131 struct list_head list;
129}; 132};
130 133
131void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); 134void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v);
@@ -301,8 +304,4 @@ static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o)
301 host->debug_op->show_mlocks(host, o); 304 host->debug_op->show_mlocks(host, o);
302} 305}
303 306
304extern struct platform_driver tegra_dc_driver;
305extern struct platform_driver tegra_hdmi_driver;
306extern struct platform_driver tegra_gr2d_driver;
307
308#endif 307#endif
diff --git a/drivers/gpu/host1x/drm/bus.c b/drivers/gpu/host1x/drm/bus.c
new file mode 100644
index 000000000000..565f8f7b9a47
--- /dev/null
+++ b/drivers/gpu/host1x/drm/bus.c
@@ -0,0 +1,76 @@
1/*
2 * Copyright (C) 2013 NVIDIA Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "drm.h"
10
11static int drm_host1x_set_busid(struct drm_device *dev,
12 struct drm_master *master)
13{
14 const char *device = dev_name(dev->dev);
15 const char *driver = dev->driver->name;
16 const char *bus = dev->dev->bus->name;
17 int length;
18
19 master->unique_len = strlen(bus) + 1 + strlen(device);
20 master->unique_size = master->unique_len;
21
22 master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL);
23 if (!master->unique)
24 return -ENOMEM;
25
26 snprintf(master->unique, master->unique_len + 1, "%s:%s", bus, device);
27
28 length = strlen(driver) + 1 + master->unique_len;
29
30 dev->devname = kmalloc(length + 1, GFP_KERNEL);
31 if (!dev->devname)
32 return -ENOMEM;
33
34 snprintf(dev->devname, length + 1, "%s@%s", driver, master->unique);
35
36 return 0;
37}
38
39static struct drm_bus drm_host1x_bus = {
40 .bus_type = DRIVER_BUS_HOST1X,
41 .set_busid = drm_host1x_set_busid,
42};
43
44int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device)
45{
46 struct drm_device *drm;
47 int ret;
48
49 INIT_LIST_HEAD(&driver->device_list);
50 driver->bus = &drm_host1x_bus;
51
52 drm = drm_dev_alloc(driver, &device->dev);
53 if (!drm)
54 return -ENOMEM;
55
56 ret = drm_dev_register(drm, 0);
57 if (ret)
58 goto err_free;
59
60 DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name,
61 driver->major, driver->minor, driver->patchlevel,
62 driver->date, drm->primary->index);
63
64 return 0;
65
66err_free:
67 drm_dev_free(drm);
68 return ret;
69}
70
71void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device)
72{
73 struct tegra_drm *tegra = dev_get_drvdata(&device->dev);
74
75 drm_put_dev(tegra->drm);
76}
diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c
index 5106df08f046..588d4ba0d8cf 100644
--- a/drivers/gpu/host1x/drm/dc.c
+++ b/drivers/gpu/host1x/drm/dc.c
@@ -11,7 +11,6 @@
11#include <linux/clk/tegra.h> 11#include <linux/clk/tegra.h>
12#include <linux/debugfs.h> 12#include <linux/debugfs.h>
13 13
14#include "host1x_client.h"
15#include "dc.h" 14#include "dc.h"
16#include "drm.h" 15#include "drm.h"
17#include "gem.h" 16#include "gem.h"
@@ -1040,28 +1039,28 @@ static int tegra_dc_debugfs_exit(struct tegra_dc *dc)
1040 1039
1041static int tegra_dc_init(struct host1x_client *client) 1040static int tegra_dc_init(struct host1x_client *client)
1042{ 1041{
1043 struct tegra_drm_client *drm = to_tegra_drm_client(client); 1042 struct tegra_drm *tegra = dev_get_drvdata(client->parent);
1044 struct tegra_dc *dc = tegra_drm_client_to_dc(drm); 1043 struct tegra_dc *dc = host1x_client_to_dc(client);
1045 int err; 1044 int err;
1046 1045
1047 dc->pipe = drm->drm->mode_config.num_crtc; 1046 dc->pipe = tegra->drm->mode_config.num_crtc;
1048 1047
1049 drm_crtc_init(drm->drm, &dc->base, &tegra_crtc_funcs); 1048 drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs);
1050 drm_mode_crtc_set_gamma_size(&dc->base, 256); 1049 drm_mode_crtc_set_gamma_size(&dc->base, 256);
1051 drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); 1050 drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
1052 1051
1053 err = tegra_dc_rgb_init(drm->drm, dc); 1052 err = tegra_dc_rgb_init(tegra->drm, dc);
1054 if (err < 0 && err != -ENODEV) { 1053 if (err < 0 && err != -ENODEV) {
1055 dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); 1054 dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
1056 return err; 1055 return err;
1057 } 1056 }
1058 1057
1059 err = tegra_dc_add_planes(drm->drm, dc); 1058 err = tegra_dc_add_planes(tegra->drm, dc);
1060 if (err < 0) 1059 if (err < 0)
1061 return err; 1060 return err;
1062 1061
1063 if (IS_ENABLED(CONFIG_DEBUG_FS)) { 1062 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
1064 err = tegra_dc_debugfs_init(dc, drm->drm->primary); 1063 err = tegra_dc_debugfs_init(dc, tegra->drm->primary);
1065 if (err < 0) 1064 if (err < 0)
1066 dev_err(dc->dev, "debugfs setup failed: %d\n", err); 1065 dev_err(dc->dev, "debugfs setup failed: %d\n", err);
1067 } 1066 }
@@ -1079,8 +1078,7 @@ static int tegra_dc_init(struct host1x_client *client)
1079 1078
1080static int tegra_dc_exit(struct host1x_client *client) 1079static int tegra_dc_exit(struct host1x_client *client)
1081{ 1080{
1082 struct tegra_drm_client *drm = to_tegra_drm_client(client); 1081 struct tegra_dc *dc = host1x_client_to_dc(client);
1083 struct tegra_dc *dc = tegra_drm_client_to_dc(drm);
1084 int err; 1082 int err;
1085 1083
1086 devm_free_irq(dc->dev, dc->irq, dc); 1084 devm_free_irq(dc->dev, dc->irq, dc);
@@ -1107,7 +1105,6 @@ static const struct host1x_client_ops dc_client_ops = {
1107 1105
1108static int tegra_dc_probe(struct platform_device *pdev) 1106static int tegra_dc_probe(struct platform_device *pdev)
1109{ 1107{
1110 struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
1111 struct resource *regs; 1108 struct resource *regs;
1112 struct tegra_dc *dc; 1109 struct tegra_dc *dc;
1113 int err; 1110 int err;
@@ -1141,9 +1138,9 @@ static int tegra_dc_probe(struct platform_device *pdev)
1141 return -ENXIO; 1138 return -ENXIO;
1142 } 1139 }
1143 1140
1144 INIT_LIST_HEAD(&dc->client.base.list); 1141 INIT_LIST_HEAD(&dc->client.list);
1145 dc->client.base.ops = &dc_client_ops; 1142 dc->client.ops = &dc_client_ops;
1146 dc->client.base.dev = &pdev->dev; 1143 dc->client.dev = &pdev->dev;
1147 1144
1148 err = tegra_dc_rgb_probe(dc); 1145 err = tegra_dc_rgb_probe(dc);
1149 if (err < 0 && err != -ENODEV) { 1146 if (err < 0 && err != -ENODEV) {
@@ -1151,7 +1148,7 @@ static int tegra_dc_probe(struct platform_device *pdev)
1151 return err; 1148 return err;
1152 } 1149 }
1153 1150
1154 err = host1x_register_client(tegra, &dc->client.base); 1151 err = host1x_client_register(&dc->client);
1155 if (err < 0) { 1152 if (err < 0) {
1156 dev_err(&pdev->dev, "failed to register host1x client: %d\n", 1153 dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1157 err); 1154 err);
@@ -1165,11 +1162,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
1165 1162
1166static int tegra_dc_remove(struct platform_device *pdev) 1163static int tegra_dc_remove(struct platform_device *pdev)
1167{ 1164{
1168 struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
1169 struct tegra_dc *dc = platform_get_drvdata(pdev); 1165 struct tegra_dc *dc = platform_get_drvdata(pdev);
1170 int err; 1166 int err;
1171 1167
1172 err = host1x_unregister_client(tegra, &dc->client.base); 1168 err = host1x_client_unregister(&dc->client);
1173 if (err < 0) { 1169 if (err < 0) {
1174 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 1170 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1175 err); 1171 err);
diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c
index 1abcdbc7f4cd..c2db409bbd63 100644
--- a/drivers/gpu/host1x/drm/drm.c
+++ b/drivers/gpu/host1x/drm/drm.c
@@ -7,7 +7,8 @@
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 */ 8 */
9 9
10#include "host1x_client.h" 10#include <linux/host1x.h>
11
11#include "drm.h" 12#include "drm.h"
12#include "gem.h" 13#include "gem.h"
13 14
@@ -22,239 +23,25 @@ struct tegra_drm_file {
22 struct list_head contexts; 23 struct list_head contexts;
23}; 24};
24 25
25struct host1x_subdev { 26static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
26 struct host1x_client *client;
27 struct device_node *np;
28 struct list_head list;
29};
30
31static int host1x_subdev_add(struct tegra_drm *tegra, struct device_node *np)
32{
33 struct host1x_subdev *subdev;
34
35 subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
36 if (!subdev)
37 return -ENOMEM;
38
39 INIT_LIST_HEAD(&subdev->list);
40 subdev->np = of_node_get(np);
41
42 list_add_tail(&subdev->list, &tegra->subdevs);
43
44 return 0;
45}
46
47static int host1x_subdev_register(struct tegra_drm *tegra,
48 struct host1x_subdev *subdev,
49 struct host1x_client *client)
50{
51 mutex_lock(&tegra->subdevs_lock);
52 list_del_init(&subdev->list);
53 list_add_tail(&subdev->list, &tegra->active);
54 subdev->client = client;
55 mutex_unlock(&tegra->subdevs_lock);
56
57 return 0;
58}
59
60static int host1x_subdev_unregister(struct tegra_drm *tegra,
61 struct host1x_subdev *subdev)
62{
63 mutex_lock(&tegra->subdevs_lock);
64 list_del_init(&subdev->list);
65 mutex_unlock(&tegra->subdevs_lock);
66
67 of_node_put(subdev->np);
68 kfree(subdev);
69
70 return 0;
71}
72
73static int tegra_parse_dt(struct tegra_drm *tegra)
74{
75 static const char * const compat[] = {
76 "nvidia,tegra20-dc",
77 "nvidia,tegra20-hdmi",
78 "nvidia,tegra20-gr2d",
79 "nvidia,tegra30-dc",
80 "nvidia,tegra30-hdmi",
81 "nvidia,tegra30-gr2d",
82 };
83 unsigned int i;
84 int err;
85
86 for (i = 0; i < ARRAY_SIZE(compat); i++) {
87 struct device_node *np;
88
89 for_each_child_of_node(tegra->dev->of_node, np) {
90 if (of_device_is_compatible(np, compat[i]) &&
91 of_device_is_available(np)) {
92 err = host1x_subdev_add(tegra, np);
93 if (err < 0)
94 return err;
95 }
96 }
97 }
98
99 return 0;
100}
101
102int tegra_drm_alloc(struct platform_device *pdev)
103{ 27{
28 struct host1x_device *device = to_host1x_device(drm->dev);
104 struct tegra_drm *tegra; 29 struct tegra_drm *tegra;
105 int err; 30 int err;
106 31
107 tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL); 32 tegra = kzalloc(sizeof(*tegra), GFP_KERNEL);
108 if (!tegra) 33 if (!tegra)
109 return -ENOMEM; 34 return -ENOMEM;
110 35
111 mutex_init(&tegra->subdevs_lock); 36 dev_set_drvdata(drm->dev, tegra);
112 INIT_LIST_HEAD(&tegra->subdevs);
113 INIT_LIST_HEAD(&tegra->active);
114 mutex_init(&tegra->clients_lock); 37 mutex_init(&tegra->clients_lock);
115 INIT_LIST_HEAD(&tegra->clients); 38 INIT_LIST_HEAD(&tegra->clients);
116 tegra->dev = &pdev->dev;
117
118 err = tegra_parse_dt(tegra);
119 if (err < 0) {
120 dev_err(&pdev->dev, "failed to parse DT: %d\n", err);
121 return err;
122 }
123
124 host1x_set_drm_data(&pdev->dev, tegra);
125
126 return 0;
127}
128
129int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm)
130{
131 struct host1x_client *client;
132 int err;
133
134 mutex_lock(&tegra->clients_lock);
135
136 list_for_each_entry(client, &tegra->clients, list) {
137 struct tegra_drm_client *tdc = to_tegra_drm_client(client);
138
139 /* associate client with DRM device */
140 tdc->drm = drm;
141
142 if (client->ops && client->ops->init) {
143 err = client->ops->init(client);
144 if (err < 0) {
145 dev_err(tegra->dev,
146 "DRM setup failed for %s: %d\n",
147 dev_name(client->dev), err);
148 mutex_unlock(&tegra->clients_lock);
149 return err;
150 }
151 }
152 }
153
154 mutex_unlock(&tegra->clients_lock);
155
156 return 0;
157}
158
159int tegra_drm_exit(struct tegra_drm *tegra)
160{
161 struct host1x_client *client;
162 struct platform_device *pdev;
163 int err;
164
165 if (!tegra->drm)
166 return 0;
167
168 mutex_lock(&tegra->clients_lock);
169
170 list_for_each_entry_reverse(client, &tegra->clients, list) {
171 if (client->ops && client->ops->exit) {
172 err = client->ops->exit(client);
173 if (err < 0) {
174 dev_err(tegra->dev,
175 "DRM cleanup failed for %s: %d\n",
176 dev_name(client->dev), err);
177 mutex_unlock(&tegra->clients_lock);
178 return err;
179 }
180 }
181 }
182
183 mutex_unlock(&tegra->clients_lock);
184
185 pdev = to_platform_device(tegra->dev);
186 drm_platform_exit(&tegra_drm_driver, pdev);
187 tegra->drm = NULL;
188
189 return 0;
190}
191
192int host1x_register_client(struct tegra_drm *tegra,
193 struct host1x_client *client)
194{
195 struct host1x_subdev *subdev, *tmp;
196 int err;
197
198 mutex_lock(&tegra->clients_lock);
199 list_add_tail(&client->list, &tegra->clients);
200 mutex_unlock(&tegra->clients_lock);
201
202 list_for_each_entry_safe(subdev, tmp, &tegra->subdevs, list)
203 if (subdev->np == client->dev->of_node)
204 host1x_subdev_register(tegra, subdev, client);
205
206 if (list_empty(&tegra->subdevs)) {
207 struct platform_device *pdev = to_platform_device(tegra->dev);
208
209 err = drm_platform_init(&tegra_drm_driver, pdev);
210 if (err < 0) {
211 dev_err(tegra->dev, "drm_platform_init(): %d\n", err);
212 return err;
213 }
214 }
215
216 return 0;
217}
218
219int host1x_unregister_client(struct tegra_drm *tegra,
220 struct host1x_client *client)
221{
222 struct host1x_subdev *subdev, *tmp;
223 int err;
224
225 list_for_each_entry_safe(subdev, tmp, &tegra->active, list) {
226 if (subdev->client == client) {
227 err = tegra_drm_exit(tegra);
228 if (err < 0) {
229 dev_err(tegra->dev, "tegra_drm_exit(): %d\n",
230 err);
231 return err;
232 }
233
234 host1x_subdev_unregister(tegra, subdev);
235 break;
236 }
237 }
238
239 mutex_lock(&tegra->clients_lock);
240 list_del_init(&client->list);
241 mutex_unlock(&tegra->clients_lock);
242
243 return 0;
244}
245
246static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
247{
248 struct tegra_drm *tegra;
249 int err;
250
251 tegra = host1x_get_drm_data(drm->dev);
252 drm->dev_private = tegra; 39 drm->dev_private = tegra;
253 tegra->drm = drm; 40 tegra->drm = drm;
254 41
255 drm_mode_config_init(drm); 42 drm_mode_config_init(drm);
256 43
257 err = tegra_drm_init(tegra, drm); 44 err = host1x_device_init(device);
258 if (err < 0) 45 if (err < 0)
259 return err; 46 return err;
260 47
@@ -280,9 +67,16 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
280 67
281static int tegra_drm_unload(struct drm_device *drm) 68static int tegra_drm_unload(struct drm_device *drm)
282{ 69{
70 struct host1x_device *device = to_host1x_device(drm->dev);
71 int err;
72
283 drm_kms_helper_poll_fini(drm); 73 drm_kms_helper_poll_fini(drm);
284 tegra_drm_fb_exit(drm); 74 tegra_drm_fb_exit(drm);
285 75
76 err = host1x_device_exit(device);
77 if (err < 0)
78 return err;
79
286 drm_mode_config_cleanup(drm); 80 drm_mode_config_cleanup(drm);
287 81
288 return 0; 82 return 0;
@@ -370,10 +164,11 @@ static int tegra_gem_mmap(struct drm_device *drm, void *data,
370static int tegra_syncpt_read(struct drm_device *drm, void *data, 164static int tegra_syncpt_read(struct drm_device *drm, void *data,
371 struct drm_file *file) 165 struct drm_file *file)
372{ 166{
167 struct host1x *host = dev_get_drvdata(drm->dev->parent);
373 struct drm_tegra_syncpt_read *args = data; 168 struct drm_tegra_syncpt_read *args = data;
374 struct host1x *host = dev_get_drvdata(drm->dev); 169 struct host1x_syncpt *sp;
375 struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);
376 170
171 sp = host1x_syncpt_get(host, args->id);
377 if (!sp) 172 if (!sp)
378 return -EINVAL; 173 return -EINVAL;
379 174
@@ -384,10 +179,11 @@ static int tegra_syncpt_read(struct drm_device *drm, void *data,
384static int tegra_syncpt_incr(struct drm_device *drm, void *data, 179static int tegra_syncpt_incr(struct drm_device *drm, void *data,
385 struct drm_file *file) 180 struct drm_file *file)
386{ 181{
182 struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
387 struct drm_tegra_syncpt_incr *args = data; 183 struct drm_tegra_syncpt_incr *args = data;
388 struct host1x *host = dev_get_drvdata(drm->dev); 184 struct host1x_syncpt *sp;
389 struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);
390 185
186 sp = host1x_syncpt_get(host1x, args->id);
391 if (!sp) 187 if (!sp)
392 return -EINVAL; 188 return -EINVAL;
393 189
@@ -397,10 +193,11 @@ static int tegra_syncpt_incr(struct drm_device *drm, void *data,
397static int tegra_syncpt_wait(struct drm_device *drm, void *data, 193static int tegra_syncpt_wait(struct drm_device *drm, void *data,
398 struct drm_file *file) 194 struct drm_file *file)
399{ 195{
196 struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
400 struct drm_tegra_syncpt_wait *args = data; 197 struct drm_tegra_syncpt_wait *args = data;
401 struct host1x *host = dev_get_drvdata(drm->dev); 198 struct host1x_syncpt *sp;
402 struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);
403 199
200 sp = host1x_syncpt_get(host1x, args->id);
404 if (!sp) 201 if (!sp)
405 return -EINVAL; 202 return -EINVAL;
406 203
@@ -422,7 +219,7 @@ static int tegra_open_channel(struct drm_device *drm, void *data,
422 if (!context) 219 if (!context)
423 return -ENOMEM; 220 return -ENOMEM;
424 221
425 list_for_each_entry(client, &tegra->clients, base.list) 222 list_for_each_entry(client, &tegra->clients, list)
426 if (client->base.class == args->client) { 223 if (client->base.class == args->client) {
427 err = client->ops->open_channel(client, context); 224 err = client->ops->open_channel(client, context);
428 if (err) 225 if (err)
@@ -441,8 +238,8 @@ static int tegra_open_channel(struct drm_device *drm, void *data,
441static int tegra_close_channel(struct drm_device *drm, void *data, 238static int tegra_close_channel(struct drm_device *drm, void *data,
442 struct drm_file *file) 239 struct drm_file *file)
443{ 240{
444 struct drm_tegra_close_channel *args = data;
445 struct tegra_drm_file *fpriv = file->driver_priv; 241 struct tegra_drm_file *fpriv = file->driver_priv;
242 struct drm_tegra_close_channel *args = data;
446 struct tegra_drm_context *context; 243 struct tegra_drm_context *context;
447 244
448 context = tegra_drm_get_context(args->context); 245 context = tegra_drm_get_context(args->context);
@@ -652,3 +449,97 @@ struct drm_driver tegra_drm_driver = {
652 .minor = DRIVER_MINOR, 449 .minor = DRIVER_MINOR,
653 .patchlevel = DRIVER_PATCHLEVEL, 450 .patchlevel = DRIVER_PATCHLEVEL,
654}; 451};
452
453int tegra_drm_register_client(struct tegra_drm *tegra,
454 struct tegra_drm_client *client)
455{
456 mutex_lock(&tegra->clients_lock);
457 list_add_tail(&client->list, &tegra->clients);
458 mutex_unlock(&tegra->clients_lock);
459
460 return 0;
461}
462
463int tegra_drm_unregister_client(struct tegra_drm *tegra,
464 struct tegra_drm_client *client)
465{
466 mutex_lock(&tegra->clients_lock);
467 list_del_init(&client->list);
468 mutex_unlock(&tegra->clients_lock);
469
470 return 0;
471}
472
473static int host1x_drm_probe(struct host1x_device *device)
474{
475 return drm_host1x_init(&tegra_drm_driver, device);
476}
477
478static int host1x_drm_remove(struct host1x_device *device)
479{
480 drm_host1x_exit(&tegra_drm_driver, device);
481
482 return 0;
483}
484
485static 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", },
492 { /* sentinel */ }
493};
494
495static struct host1x_driver host1x_drm_driver = {
496 .name = "drm",
497 .probe = host1x_drm_probe,
498 .remove = host1x_drm_remove,
499 .subdevs = host1x_drm_subdevs,
500};
501
502static int __init host1x_drm_init(void)
503{
504 int err;
505
506 err = host1x_driver_register(&host1x_drm_driver);
507 if (err < 0)
508 return err;
509
510 err = platform_driver_register(&tegra_dc_driver);
511 if (err < 0)
512 goto unregister_host1x;
513
514 err = platform_driver_register(&tegra_hdmi_driver);
515 if (err < 0)
516 goto unregister_dc;
517
518 err = platform_driver_register(&tegra_gr2d_driver);
519 if (err < 0)
520 goto unregister_hdmi;
521
522 return 0;
523
524unregister_hdmi:
525 platform_driver_unregister(&tegra_hdmi_driver);
526unregister_dc:
527 platform_driver_unregister(&tegra_dc_driver);
528unregister_host1x:
529 host1x_driver_unregister(&host1x_drm_driver);
530 return err;
531}
532module_init(host1x_drm_init);
533
534static void __exit host1x_drm_exit(void)
535{
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);
540}
541module_exit(host1x_drm_exit);
542
543MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
544MODULE_DESCRIPTION("NVIDIA Tegra DRM driver");
545MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/host1x/drm/drm.h b/drivers/gpu/host1x/drm/drm.h
index 8c26c6b1f5e1..25522e23c7b8 100644
--- a/drivers/gpu/host1x/drm/drm.h
+++ b/drivers/gpu/host1x/drm/drm.h
@@ -32,11 +32,6 @@ struct tegra_fbdev {
32 32
33struct tegra_drm { 33struct tegra_drm {
34 struct drm_device *drm; 34 struct drm_device *drm;
35 struct device *dev;
36
37 struct mutex subdevs_lock;
38 struct list_head subdevs;
39 struct list_head active;
40 35
41 struct mutex clients_lock; 36 struct mutex clients_lock;
42 struct list_head clients; 37 struct list_head clients;
@@ -63,29 +58,29 @@ struct tegra_drm_client_ops {
63 58
64struct tegra_drm_client { 59struct tegra_drm_client {
65 struct host1x_client base; 60 struct host1x_client base;
66 struct drm_device *drm; 61 struct list_head list;
67 62
68 const struct tegra_drm_client_ops *ops; 63 const struct tegra_drm_client_ops *ops;
69}; 64};
70 65
71static inline struct tegra_drm_client * 66static inline struct tegra_drm_client *
72to_tegra_drm_client(struct host1x_client *client) 67host1x_to_drm_client(struct host1x_client *client)
73{ 68{
74 return container_of(client, struct tegra_drm_client, base); 69 return container_of(client, struct tegra_drm_client, base);
75} 70}
76 71
72extern int tegra_drm_register_client(struct tegra_drm *tegra,
73 struct tegra_drm_client *client);
74extern int tegra_drm_unregister_client(struct tegra_drm *tegra,
75 struct tegra_drm_client *client);
76
77extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); 77extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
78extern int tegra_drm_exit(struct tegra_drm *tegra); 78extern int tegra_drm_exit(struct tegra_drm *tegra);
79 79
80extern int host1x_register_client(struct tegra_drm *tegra,
81 struct host1x_client *client);
82extern int host1x_unregister_client(struct tegra_drm *tegra,
83 struct host1x_client *client);
84
85struct tegra_output; 80struct tegra_output;
86 81
87struct tegra_dc { 82struct tegra_dc {
88 struct tegra_drm_client client; 83 struct host1x_client client;
89 struct device *dev; 84 struct device *dev;
90 spinlock_t lock; 85 spinlock_t lock;
91 86
@@ -109,7 +104,7 @@ struct tegra_dc {
109}; 104};
110 105
111static inline struct tegra_dc * 106static inline struct tegra_dc *
112tegra_drm_client_to_dc(struct tegra_drm_client *client) 107host1x_client_to_dc(struct host1x_client *client)
113{ 108{
114 return container_of(client, struct tegra_dc, client); 109 return container_of(client, struct tegra_dc, client);
115} 110}
@@ -235,6 +230,10 @@ static inline int tegra_output_check_mode(struct tegra_output *output,
235 return output ? -ENOSYS : -EINVAL; 230 return output ? -ENOSYS : -EINVAL;
236} 231}
237 232
233/* from bus.c */
234int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device);
235void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device);
236
238/* from rgb.c */ 237/* from rgb.c */
239extern int tegra_dc_rgb_probe(struct tegra_dc *dc); 238extern int tegra_dc_rgb_probe(struct tegra_dc *dc);
240extern int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc); 239extern int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc);
@@ -252,6 +251,8 @@ extern int tegra_drm_fb_init(struct drm_device *drm);
252extern void tegra_drm_fb_exit(struct drm_device *drm); 251extern void tegra_drm_fb_exit(struct drm_device *drm);
253extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); 252extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
254 253
255extern struct drm_driver tegra_drm_driver; 254extern struct platform_driver tegra_dc_driver;
255extern struct platform_driver tegra_hdmi_driver;
256extern struct platform_driver tegra_gr2d_driver;
256 257
257#endif /* HOST1X_DRM_H */ 258#endif /* HOST1X_DRM_H */
diff --git a/drivers/gpu/host1x/drm/gr2d.c b/drivers/gpu/host1x/drm/gr2d.c
index dfb822428ca0..4e407e30da1c 100644
--- a/drivers/gpu/host1x/drm/gr2d.c
+++ b/drivers/gpu/host1x/drm/gr2d.c
@@ -16,7 +16,6 @@
16 16
17#include <linux/clk.h> 17#include <linux/clk.h>
18 18
19#include "host1x_client.h"
20#include "drm.h" 19#include "drm.h"
21#include "gem.h" 20#include "gem.h"
22 21
@@ -35,19 +34,45 @@ static inline struct gr2d *to_gr2d(struct tegra_drm_client *client)
35 return container_of(client, struct gr2d, client); 34 return container_of(client, struct gr2d, client);
36} 35}
37 36
38static int gr2d_client_init(struct host1x_client *client) 37static int gr2d_init(struct host1x_client *client)
39{ 38{
40 return 0; 39 struct tegra_drm_client *drm = host1x_to_drm_client(client);
40 struct tegra_drm *tegra = dev_get_drvdata(client->parent);
41 struct gr2d *gr2d = to_gr2d(drm);
42
43 gr2d->channel = host1x_channel_request(client->dev);
44 if (!gr2d->channel)
45 return -ENOMEM;
46
47 client->syncpts[0] = host1x_syncpt_request(client->dev, false);
48 if (!client->syncpts[0]) {
49 host1x_channel_free(gr2d->channel);
50 return -ENOMEM;
51 }
52
53 return tegra_drm_register_client(tegra, drm);
41} 54}
42 55
43static int gr2d_client_exit(struct host1x_client *client) 56static int gr2d_exit(struct host1x_client *client)
44{ 57{
58 struct tegra_drm_client *drm = host1x_to_drm_client(client);
59 struct tegra_drm *tegra = dev_get_drvdata(client->parent);
60 struct gr2d *gr2d = to_gr2d(drm);
61 int err;
62
63 err = tegra_drm_unregister_client(tegra, drm);
64 if (err < 0)
65 return err;
66
67 host1x_syncpt_free(client->syncpts[0]);
68 host1x_channel_free(gr2d->channel);
69
45 return 0; 70 return 0;
46} 71}
47 72
48static const struct host1x_client_ops gr2d_client_ops = { 73static const struct host1x_client_ops gr2d_client_ops = {
49 .init = gr2d_client_init, 74 .init = gr2d_init,
50 .exit = gr2d_client_exit, 75 .exit = gr2d_exit,
51}; 76};
52 77
53static int gr2d_open_channel(struct tegra_drm_client *client, 78static int gr2d_open_channel(struct tegra_drm_client *client,
@@ -240,7 +265,6 @@ static const u32 gr2d_addr_regs[] = {
240 265
241static int gr2d_probe(struct platform_device *pdev) 266static int gr2d_probe(struct platform_device *pdev)
242{ 267{
243 struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
244 struct device *dev = &pdev->dev; 268 struct device *dev = &pdev->dev;
245 struct host1x_syncpt **syncpts; 269 struct host1x_syncpt **syncpts;
246 struct gr2d *gr2d; 270 struct gr2d *gr2d;
@@ -267,25 +291,17 @@ static int gr2d_probe(struct platform_device *pdev)
267 return err; 291 return err;
268 } 292 }
269 293
270 gr2d->channel = host1x_channel_request(dev);
271 if (!gr2d->channel)
272 return -ENOMEM;
273
274 *syncpts = host1x_syncpt_request(dev, false);
275 if (!(*syncpts)) {
276 host1x_channel_free(gr2d->channel);
277 return -ENOMEM;
278 }
279
280 INIT_LIST_HEAD(&gr2d->client.base.list); 294 INIT_LIST_HEAD(&gr2d->client.base.list);
281 gr2d->client.base.ops = &gr2d_client_ops; 295 gr2d->client.base.ops = &gr2d_client_ops;
282 gr2d->client.base.dev = dev; 296 gr2d->client.base.dev = dev;
283 gr2d->client.base.class = HOST1X_CLASS_GR2D; 297 gr2d->client.base.class = HOST1X_CLASS_GR2D;
284 gr2d->client.base.syncpts = syncpts; 298 gr2d->client.base.syncpts = syncpts;
285 gr2d->client.base.num_syncpts = 1; 299 gr2d->client.base.num_syncpts = 1;
300
301 INIT_LIST_HEAD(&gr2d->client.list);
286 gr2d->client.ops = &gr2d_ops; 302 gr2d->client.ops = &gr2d_ops;
287 303
288 err = host1x_register_client(tegra, &gr2d->client.base); 304 err = host1x_client_register(&gr2d->client.base);
289 if (err < 0) { 305 if (err < 0) {
290 dev_err(dev, "failed to register host1x client: %d\n", err); 306 dev_err(dev, "failed to register host1x client: %d\n", err);
291 return err; 307 return err;
@@ -302,22 +318,16 @@ static int gr2d_probe(struct platform_device *pdev)
302 318
303static int gr2d_remove(struct platform_device *pdev) 319static int gr2d_remove(struct platform_device *pdev)
304{ 320{
305 struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
306 struct gr2d *gr2d = platform_get_drvdata(pdev); 321 struct gr2d *gr2d = platform_get_drvdata(pdev);
307 unsigned int i;
308 int err; 322 int err;
309 323
310 err = host1x_unregister_client(tegra, &gr2d->client.base); 324 err = host1x_client_unregister(&gr2d->client.base);
311 if (err < 0) { 325 if (err < 0) {
312 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 326 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
313 err); 327 err);
314 return err; 328 return err;
315 } 329 }
316 330
317 for (i = 0; i < gr2d->client.base.num_syncpts; i++)
318 host1x_syncpt_free(gr2d->client.base.syncpts[i]);
319
320 host1x_channel_free(gr2d->channel);
321 clk_disable_unprepare(gr2d->clk); 331 clk_disable_unprepare(gr2d->clk);
322 332
323 return 0; 333 return 0;
diff --git a/drivers/gpu/host1x/drm/hdmi.c b/drivers/gpu/host1x/drm/hdmi.c
index a2370045993c..f5663d15670b 100644
--- a/drivers/gpu/host1x/drm/hdmi.c
+++ b/drivers/gpu/host1x/drm/hdmi.c
@@ -13,13 +13,12 @@
13#include <linux/hdmi.h> 13#include <linux/hdmi.h>
14#include <linux/regulator/consumer.h> 14#include <linux/regulator/consumer.h>
15 15
16#include "host1x_client.h"
17#include "hdmi.h" 16#include "hdmi.h"
18#include "drm.h" 17#include "drm.h"
19#include "dc.h" 18#include "dc.h"
20 19
21struct tegra_hdmi { 20struct tegra_hdmi {
22 struct tegra_drm_client client; 21 struct host1x_client client;
23 struct tegra_output output; 22 struct tegra_output output;
24 struct device *dev; 23 struct device *dev;
25 24
@@ -43,7 +42,7 @@ struct tegra_hdmi {
43}; 42};
44 43
45static inline struct tegra_hdmi * 44static inline struct tegra_hdmi *
46tegra_drm_client_to_hdmi(struct tegra_drm_client *client) 45host1x_client_to_hdmi(struct host1x_client *client)
47{ 46{
48 return container_of(client, struct tegra_hdmi, client); 47 return container_of(client, struct tegra_hdmi, client);
49} 48}
@@ -1118,22 +1117,22 @@ static int tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi)
1118 1117
1119static int tegra_hdmi_init(struct host1x_client *client) 1118static int tegra_hdmi_init(struct host1x_client *client)
1120{ 1119{
1121 struct tegra_drm_client *drm = to_tegra_drm_client(client); 1120 struct tegra_drm *tegra = dev_get_drvdata(client->parent);
1122 struct tegra_hdmi *hdmi = tegra_drm_client_to_hdmi(drm); 1121 struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
1123 int err; 1122 int err;
1124 1123
1125 hdmi->output.type = TEGRA_OUTPUT_HDMI; 1124 hdmi->output.type = TEGRA_OUTPUT_HDMI;
1126 hdmi->output.dev = client->dev; 1125 hdmi->output.dev = client->dev;
1127 hdmi->output.ops = &hdmi_ops; 1126 hdmi->output.ops = &hdmi_ops;
1128 1127
1129 err = tegra_output_init(drm->drm, &hdmi->output); 1128 err = tegra_output_init(tegra->drm, &hdmi->output);
1130 if (err < 0) { 1129 if (err < 0) {
1131 dev_err(client->dev, "output setup failed: %d\n", err); 1130 dev_err(client->dev, "output setup failed: %d\n", err);
1132 return err; 1131 return err;
1133 } 1132 }
1134 1133
1135 if (IS_ENABLED(CONFIG_DEBUG_FS)) { 1134 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
1136 err = tegra_hdmi_debugfs_init(hdmi, drm->drm->primary); 1135 err = tegra_hdmi_debugfs_init(hdmi, tegra->drm->primary);
1137 if (err < 0) 1136 if (err < 0)
1138 dev_err(client->dev, "debugfs setup failed: %d\n", err); 1137 dev_err(client->dev, "debugfs setup failed: %d\n", err);
1139 } 1138 }
@@ -1143,8 +1142,7 @@ static int tegra_hdmi_init(struct host1x_client *client)
1143 1142
1144static int tegra_hdmi_exit(struct host1x_client *client) 1143static int tegra_hdmi_exit(struct host1x_client *client)
1145{ 1144{
1146 struct tegra_drm_client *drm = to_tegra_drm_client(client); 1145 struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
1147 struct tegra_hdmi *hdmi = tegra_drm_client_to_hdmi(drm);
1148 int err; 1146 int err;
1149 1147
1150 if (IS_ENABLED(CONFIG_DEBUG_FS)) { 1148 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
@@ -1176,7 +1174,6 @@ static const struct host1x_client_ops hdmi_client_ops = {
1176 1174
1177static int tegra_hdmi_probe(struct platform_device *pdev) 1175static int tegra_hdmi_probe(struct platform_device *pdev)
1178{ 1176{
1179 struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
1180 struct tegra_hdmi *hdmi; 1177 struct tegra_hdmi *hdmi;
1181 struct resource *regs; 1178 struct resource *regs;
1182 int err; 1179 int err;
@@ -1247,11 +1244,11 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
1247 1244
1248 hdmi->irq = err; 1245 hdmi->irq = err;
1249 1246
1250 INIT_LIST_HEAD(&hdmi->client.base.list); 1247 INIT_LIST_HEAD(&hdmi->client.list);
1251 hdmi->client.base.ops = &hdmi_client_ops; 1248 hdmi->client.ops = &hdmi_client_ops;
1252 hdmi->client.base.dev = &pdev->dev; 1249 hdmi->client.dev = &pdev->dev;
1253 1250
1254 err = host1x_register_client(tegra, &hdmi->client.base); 1251 err = host1x_client_register(&hdmi->client);
1255 if (err < 0) { 1252 if (err < 0) {
1256 dev_err(&pdev->dev, "failed to register host1x client: %d\n", 1253 dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1257 err); 1254 err);
@@ -1265,11 +1262,10 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
1265 1262
1266static int tegra_hdmi_remove(struct platform_device *pdev) 1263static int tegra_hdmi_remove(struct platform_device *pdev)
1267{ 1264{
1268 struct tegra_drm *tegra = host1x_get_drm_data(pdev->dev.parent);
1269 struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); 1265 struct tegra_hdmi *hdmi = platform_get_drvdata(pdev);
1270 int err; 1266 int err;
1271 1267
1272 err = host1x_unregister_client(tegra, &hdmi->client.base); 1268 err = host1x_client_unregister(&hdmi->client);
1273 if (err < 0) { 1269 if (err < 0) {
1274 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 1270 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1275 err); 1271 err);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 2b954adf5bd4..ffd8ad92cdf9 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -150,6 +150,7 @@ int drm_err(const char *func, const char *format, ...);
150#define DRIVER_BUS_PCI 0x1 150#define DRIVER_BUS_PCI 0x1
151#define DRIVER_BUS_PLATFORM 0x2 151#define DRIVER_BUS_PLATFORM 0x2
152#define DRIVER_BUS_USB 0x3 152#define DRIVER_BUS_USB 0x3
153#define DRIVER_BUS_HOST1X 0x4
153 154
154/***********************************************************************/ 155/***********************************************************************/
155/** \name Begin the DRM... */ 156/** \name Begin the DRM... */
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index 7442f2a57039..e62c61a4afa9 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -19,7 +19,7 @@
19#ifndef __LINUX_HOST1X_H 19#ifndef __LINUX_HOST1X_H
20#define __LINUX_HOST1X_H 20#define __LINUX_HOST1X_H
21 21
22#include <linux/kref.h> 22#include <linux/device.h>
23#include <linux/types.h> 23#include <linux/types.h>
24 24
25enum host1x_class { 25enum host1x_class {
@@ -37,6 +37,7 @@ struct host1x_client_ops {
37 37
38struct host1x_client { 38struct host1x_client {
39 struct list_head list; 39 struct list_head list;
40 struct device *parent;
40 struct device *dev; 41 struct device *dev;
41 42
42 const struct host1x_client_ops *ops; 43 const struct host1x_client_ops *ops;
@@ -230,4 +231,46 @@ void host1x_job_put(struct host1x_job *job);
230int host1x_job_pin(struct host1x_job *job, struct device *dev); 231int host1x_job_pin(struct host1x_job *job, struct device *dev);
231void host1x_job_unpin(struct host1x_job *job); 232void host1x_job_unpin(struct host1x_job *job);
232 233
234/*
235 * subdevice probe infrastructure
236 */
237
238struct host1x_device;
239
240struct host1x_driver {
241 const struct of_device_id *subdevs;
242 struct list_head list;
243 const char *name;
244
245 int (*probe)(struct host1x_device *device);
246 int (*remove)(struct host1x_device *device);
247};
248
249int host1x_driver_register(struct host1x_driver *driver);
250void host1x_driver_unregister(struct host1x_driver *driver);
251
252struct host1x_device {
253 struct host1x_driver *driver;
254 struct list_head list;
255 struct device dev;
256
257 struct mutex subdevs_lock;
258 struct list_head subdevs;
259 struct list_head active;
260
261 struct mutex clients_lock;
262 struct list_head clients;
263};
264
265static inline struct host1x_device *to_host1x_device(struct device *dev)
266{
267 return container_of(dev, struct host1x_device, dev);
268}
269
270int host1x_device_init(struct host1x_device *device);
271int host1x_device_exit(struct host1x_device *device);
272
273int host1x_client_register(struct host1x_client *client);
274int host1x_client_unregister(struct host1x_client *client);
275
233#endif 276#endif