aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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