diff options
-rw-r--r-- | drivers/gpu/host1x/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/host1x/bus.c | 550 | ||||
-rw-r--r-- | drivers/gpu/host1x/bus.h (renamed from drivers/gpu/host1x/host1x_client.h) | 24 | ||||
-rw-r--r-- | drivers/gpu/host1x/dev.c | 60 | ||||
-rw-r--r-- | drivers/gpu/host1x/dev.h | 9 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/bus.c | 76 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/dc.c | 30 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/drm.c | 347 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/drm.h | 31 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/gr2d.c | 60 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/hdmi.c | 28 | ||||
-rw-r--r-- | include/drm/drmP.h | 1 | ||||
-rw-r--r-- | include/linux/host1x.h | 45 |
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 @@ | |||
1 | ccflags-y = -Idrivers/gpu/host1x | 1 | ccflags-y = -Idrivers/gpu/host1x |
2 | 2 | ||
3 | host1x-y = \ | 3 | host1x-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 | |||
17 | host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o | 18 | host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o |
18 | host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o | 19 | host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o |
19 | host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o | 20 | host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o |
21 | host1x-$(CONFIG_DRM_TEGRA) += drm/bus.o | ||
20 | obj-$(CONFIG_TEGRA_HOST1X) += host1x.o | 22 | obj-$(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 | |||
24 | static DEFINE_MUTEX(clients_lock); | ||
25 | static LIST_HEAD(clients); | ||
26 | |||
27 | static DEFINE_MUTEX(drivers_lock); | ||
28 | static LIST_HEAD(drivers); | ||
29 | |||
30 | static DEFINE_MUTEX(devices_lock); | ||
31 | static LIST_HEAD(devices); | ||
32 | |||
33 | struct 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 | */ | ||
42 | static 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 | */ | ||
64 | static 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 | */ | ||
74 | static 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 | |||
91 | static 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 | |||
122 | static 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 | |||
158 | static 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 | |||
166 | int 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 | |||
191 | int 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 | |||
216 | static 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 | |||
238 | static 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 | |||
260 | struct bus_type host1x_bus_type = { | ||
261 | .name = "host1x", | ||
262 | }; | ||
263 | |||
264 | int host1x_bus_init(void) | ||
265 | { | ||
266 | return bus_register(&host1x_bus_type); | ||
267 | } | ||
268 | |||
269 | void host1x_bus_exit(void) | ||
270 | { | ||
271 | bus_unregister(&host1x_bus_type); | ||
272 | } | ||
273 | |||
274 | static void host1x_device_release(struct device *dev) | ||
275 | { | ||
276 | struct host1x_device *device = to_host1x_device(dev); | ||
277 | |||
278 | kfree(device); | ||
279 | } | ||
280 | |||
281 | static 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 | */ | ||
344 | static 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 | |||
394 | static 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 | |||
416 | static 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 | |||
430 | int 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 | |||
448 | int 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 | |||
466 | int 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 | } | ||
485 | EXPORT_SYMBOL(host1x_driver_register); | ||
486 | |||
487 | void 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 | } | ||
493 | EXPORT_SYMBOL(host1x_driver_unregister); | ||
494 | |||
495 | int 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 | } | ||
518 | EXPORT_SYMBOL(host1x_client_register); | ||
519 | |||
520 | int 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 | } | ||
550 | EXPORT_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 | ||
20 | struct device; | 21 | struct host1x; |
21 | struct platform_device; | ||
22 | 22 | ||
23 | #ifdef CONFIG_DRM_TEGRA | 23 | int host1x_bus_init(void); |
24 | int tegra_drm_alloc(struct platform_device *pdev); | 24 | void host1x_bus_exit(void); |
25 | #else | ||
26 | static inline int tegra_drm_alloc(struct platform_device *pdev) | ||
27 | { | ||
28 | return 0; | ||
29 | } | ||
30 | #endif | ||
31 | 25 | ||
32 | void host1x_set_drm_data(struct device *dev, void *data); | 26 | int host1x_register(struct host1x *host1x); |
33 | void *host1x_get_drm_data(struct device *dev); | 27 | int 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 | |||
37 | void 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 | |||
43 | void *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 | ||
49 | void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) | 37 | void 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 | ||
163 | fail_deinit_intr: | ||
164 | host1x_intr_deinit(host); | ||
170 | fail_deinit_syncpt: | 165 | fail_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 | ||
220 | unregister_hdmi: | ||
221 | platform_driver_unregister(&tegra_hdmi_driver); | ||
222 | unregister_dc: | ||
223 | platform_driver_unregister(&tegra_dc_driver); | ||
224 | unregister_host1x: | ||
225 | platform_driver_unregister(&tegra_host1x_driver); | ||
226 | return err; | ||
227 | #endif | ||
228 | } | 206 | } |
229 | module_init(tegra_host1x_init); | 207 | module_init(tegra_host1x_init); |
230 | 208 | ||
231 | static void __exit tegra_host1x_exit(void) | 209 | static 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 | } |
240 | module_exit(tegra_host1x_exit); | 214 | module_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 | ||
131 | void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); | 134 | void 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 | ||
304 | extern struct platform_driver tegra_dc_driver; | ||
305 | extern struct platform_driver tegra_hdmi_driver; | ||
306 | extern 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 | |||
11 | static 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 | |||
39 | static struct drm_bus drm_host1x_bus = { | ||
40 | .bus_type = DRIVER_BUS_HOST1X, | ||
41 | .set_busid = drm_host1x_set_busid, | ||
42 | }; | ||
43 | |||
44 | int 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 | |||
66 | err_free: | ||
67 | drm_dev_free(drm); | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | void 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 | ||
1041 | static int tegra_dc_init(struct host1x_client *client) | 1040 | static 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 | ||
1080 | static int tegra_dc_exit(struct host1x_client *client) | 1079 | static 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 | ||
1108 | static int tegra_dc_probe(struct platform_device *pdev) | 1106 | static 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 | ||
1166 | static int tegra_dc_remove(struct platform_device *pdev) | 1163 | static 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 | ||
25 | struct host1x_subdev { | 26 | static 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 | |||
31 | static 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 | |||
47 | static 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 | |||
60 | static 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 | |||
73 | static 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 | |||
102 | int 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 | |||
129 | int 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 | |||
159 | int 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 | |||
192 | int 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 | |||
219 | int 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 | |||
246 | static 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 | ||
281 | static int tegra_drm_unload(struct drm_device *drm) | 68 | static 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, | |||
370 | static int tegra_syncpt_read(struct drm_device *drm, void *data, | 164 | static 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, | |||
384 | static int tegra_syncpt_incr(struct drm_device *drm, void *data, | 179 | static 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, | |||
397 | static int tegra_syncpt_wait(struct drm_device *drm, void *data, | 193 | static 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, | |||
441 | static int tegra_close_channel(struct drm_device *drm, void *data, | 238 | static 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 | |||
453 | int 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 | |||
463 | int 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 | |||
473 | static int host1x_drm_probe(struct host1x_device *device) | ||
474 | { | ||
475 | return drm_host1x_init(&tegra_drm_driver, device); | ||
476 | } | ||
477 | |||
478 | static int host1x_drm_remove(struct host1x_device *device) | ||
479 | { | ||
480 | drm_host1x_exit(&tegra_drm_driver, device); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static const struct of_device_id host1x_drm_subdevs[] = { | ||
486 | { .compatible = "nvidia,tegra20-dc", }, | ||
487 | { .compatible = "nvidia,tegra20-hdmi", }, | ||
488 | { .compatible = "nvidia,tegra20-gr2d", }, | ||
489 | { .compatible = "nvidia,tegra30-dc", }, | ||
490 | { .compatible = "nvidia,tegra30-hdmi", }, | ||
491 | { .compatible = "nvidia,tegra30-gr2d", }, | ||
492 | { /* sentinel */ } | ||
493 | }; | ||
494 | |||
495 | static 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 | |||
502 | static 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 | |||
524 | unregister_hdmi: | ||
525 | platform_driver_unregister(&tegra_hdmi_driver); | ||
526 | unregister_dc: | ||
527 | platform_driver_unregister(&tegra_dc_driver); | ||
528 | unregister_host1x: | ||
529 | host1x_driver_unregister(&host1x_drm_driver); | ||
530 | return err; | ||
531 | } | ||
532 | module_init(host1x_drm_init); | ||
533 | |||
534 | static 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 | } | ||
541 | module_exit(host1x_drm_exit); | ||
542 | |||
543 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | ||
544 | MODULE_DESCRIPTION("NVIDIA Tegra DRM driver"); | ||
545 | MODULE_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 | ||
33 | struct tegra_drm { | 33 | struct 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 | ||
64 | struct tegra_drm_client { | 59 | struct 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 | ||
71 | static inline struct tegra_drm_client * | 66 | static inline struct tegra_drm_client * |
72 | to_tegra_drm_client(struct host1x_client *client) | 67 | host1x_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 | ||
72 | extern int tegra_drm_register_client(struct tegra_drm *tegra, | ||
73 | struct tegra_drm_client *client); | ||
74 | extern int tegra_drm_unregister_client(struct tegra_drm *tegra, | ||
75 | struct tegra_drm_client *client); | ||
76 | |||
77 | extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); | 77 | extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); |
78 | extern int tegra_drm_exit(struct tegra_drm *tegra); | 78 | extern int tegra_drm_exit(struct tegra_drm *tegra); |
79 | 79 | ||
80 | extern int host1x_register_client(struct tegra_drm *tegra, | ||
81 | struct host1x_client *client); | ||
82 | extern int host1x_unregister_client(struct tegra_drm *tegra, | ||
83 | struct host1x_client *client); | ||
84 | |||
85 | struct tegra_output; | 80 | struct tegra_output; |
86 | 81 | ||
87 | struct tegra_dc { | 82 | struct 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 | ||
111 | static inline struct tegra_dc * | 106 | static inline struct tegra_dc * |
112 | tegra_drm_client_to_dc(struct tegra_drm_client *client) | 107 | host1x_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 */ | ||
234 | int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device); | ||
235 | void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device); | ||
236 | |||
238 | /* from rgb.c */ | 237 | /* from rgb.c */ |
239 | extern int tegra_dc_rgb_probe(struct tegra_dc *dc); | 238 | extern int tegra_dc_rgb_probe(struct tegra_dc *dc); |
240 | extern int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc); | 239 | extern 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); | |||
252 | extern void tegra_drm_fb_exit(struct drm_device *drm); | 251 | extern void tegra_drm_fb_exit(struct drm_device *drm); |
253 | extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); | 252 | extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); |
254 | 253 | ||
255 | extern struct drm_driver tegra_drm_driver; | 254 | extern struct platform_driver tegra_dc_driver; |
255 | extern struct platform_driver tegra_hdmi_driver; | ||
256 | extern 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 | ||
38 | static int gr2d_client_init(struct host1x_client *client) | 37 | static 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 | ||
43 | static int gr2d_client_exit(struct host1x_client *client) | 56 | static 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 | ||
48 | static const struct host1x_client_ops gr2d_client_ops = { | 73 | static 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 | ||
53 | static int gr2d_open_channel(struct tegra_drm_client *client, | 78 | static int gr2d_open_channel(struct tegra_drm_client *client, |
@@ -240,7 +265,6 @@ static const u32 gr2d_addr_regs[] = { | |||
240 | 265 | ||
241 | static int gr2d_probe(struct platform_device *pdev) | 266 | static 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 | ||
303 | static int gr2d_remove(struct platform_device *pdev) | 319 | static 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 | ||
21 | struct tegra_hdmi { | 20 | struct 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 | ||
45 | static inline struct tegra_hdmi * | 44 | static inline struct tegra_hdmi * |
46 | tegra_drm_client_to_hdmi(struct tegra_drm_client *client) | 45 | host1x_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 | ||
1119 | static int tegra_hdmi_init(struct host1x_client *client) | 1118 | static 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 | ||
1144 | static int tegra_hdmi_exit(struct host1x_client *client) | 1143 | static 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 | ||
1177 | static int tegra_hdmi_probe(struct platform_device *pdev) | 1175 | static 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 | ||
1266 | static int tegra_hdmi_remove(struct platform_device *pdev) | 1263 | static 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 | ||
25 | enum host1x_class { | 25 | enum host1x_class { |
@@ -37,6 +37,7 @@ struct host1x_client_ops { | |||
37 | 37 | ||
38 | struct host1x_client { | 38 | struct 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); | |||
230 | int host1x_job_pin(struct host1x_job *job, struct device *dev); | 231 | int host1x_job_pin(struct host1x_job *job, struct device *dev); |
231 | void host1x_job_unpin(struct host1x_job *job); | 232 | void host1x_job_unpin(struct host1x_job *job); |
232 | 233 | ||
234 | /* | ||
235 | * subdevice probe infrastructure | ||
236 | */ | ||
237 | |||
238 | struct host1x_device; | ||
239 | |||
240 | struct 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 | |||
249 | int host1x_driver_register(struct host1x_driver *driver); | ||
250 | void host1x_driver_unregister(struct host1x_driver *driver); | ||
251 | |||
252 | struct 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 | |||
265 | static inline struct host1x_device *to_host1x_device(struct device *dev) | ||
266 | { | ||
267 | return container_of(dev, struct host1x_device, dev); | ||
268 | } | ||
269 | |||
270 | int host1x_device_init(struct host1x_device *device); | ||
271 | int host1x_device_exit(struct host1x_device *device); | ||
272 | |||
273 | int host1x_client_register(struct host1x_client *client); | ||
274 | int host1x_client_unregister(struct host1x_client *client); | ||
275 | |||
233 | #endif | 276 | #endif |