aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2013-10-14 08:43:22 -0400
committerThierry Reding <treding@nvidia.com>2013-10-31 04:55:33 -0400
commit776dc38403676f499a73d32e2e7c61eb5b42f736 (patch)
tree5c9f8d670b51d743c5bbab45ec401e30f22579c1
parent35d747a81d7eb824bd0c3476cd0c564b52ad5353 (diff)
drm/tegra: Move subdevice infrastructure to host1x
The Tegra DRM driver currently uses some infrastructure to defer the DRM core initialization until all required devices have registered. The same infrastructure can potentially be used by any other driver that requires more than a single sub-device of the host1x module. Make the infrastructure more generic and keep only the DRM specific code in the DRM part of the driver. Eventually this will make it easy to move the DRM driver part back to the DRM subsystem. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/host1x/Makefile2
-rw-r--r--drivers/gpu/host1x/bus.c550
-rw-r--r--drivers/gpu/host1x/bus.h (renamed from drivers/gpu/host1x/host1x_client.h)24
-rw-r--r--drivers/gpu/host1x/dev.c60
-rw-r--r--drivers/gpu/host1x/dev.h9
-rw-r--r--drivers/gpu/host1x/drm/bus.c76
-rw-r--r--drivers/gpu/host1x/drm/dc.c30
-rw-r--r--drivers/gpu/host1x/drm/drm.c347
-rw-r--r--drivers/gpu/host1x/drm/drm.h31
-rw-r--r--drivers/gpu/host1x/drm/gr2d.c60
-rw-r--r--drivers/gpu/host1x/drm/hdmi.c28
-rw-r--r--include/drm/drmP.h1
-rw-r--r--include/linux/host1x.h45
13 files changed, 898 insertions, 365 deletions
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile
index 3b037b6e0298..7b781920c58a 100644
--- a/drivers/gpu/host1x/Makefile
+++ b/drivers/gpu/host1x/Makefile
@@ -1,6 +1,7 @@
1ccflags-y = -Idrivers/gpu/host1x 1ccflags-y = -Idrivers/gpu/host1x
2 2
3host1x-y = \ 3host1x-y = \
4 bus.o \
4 syncpt.o \ 5 syncpt.o \
5 dev.o \ 6 dev.o \
6 intr.o \ 7 intr.o \
@@ -17,4 +18,5 @@ host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o
17host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o 18host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o
18host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o 19host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o
19host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o 20host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o
21host1x-$(CONFIG_DRM_TEGRA) += drm/bus.o
20obj-$(CONFIG_TEGRA_HOST1X) += host1x.o 22obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
new file mode 100644
index 000000000000..509383f8be03
--- /dev/null
+++ b/drivers/gpu/host1x/bus.c
@@ -0,0 +1,550 @@
1/*
2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012-2013, NVIDIA Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <linux/host1x.h>
19#include <linux/of.h>
20#include <linux/slab.h>
21
22#include "dev.h"
23
24static DEFINE_MUTEX(clients_lock);
25static LIST_HEAD(clients);
26
27static DEFINE_MUTEX(drivers_lock);
28static LIST_HEAD(drivers);
29
30static DEFINE_MUTEX(devices_lock);
31static LIST_HEAD(devices);
32
33struct host1x_subdev {
34 struct host1x_client *client;
35 struct device_node *np;
36 struct list_head list;
37};
38
39/**
40 * host1x_subdev_add() - add a new subdevice with an associated device node
41 */
42static int host1x_subdev_add(struct host1x_device *device,
43 struct device_node *np)
44{
45 struct host1x_subdev *subdev;
46
47 subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
48 if (!subdev)
49 return -ENOMEM;
50
51 INIT_LIST_HEAD(&subdev->list);
52 subdev->np = of_node_get(np);
53
54 mutex_lock(&device->subdevs_lock);
55 list_add_tail(&subdev->list, &device->subdevs);
56 mutex_unlock(&device->subdevs_lock);
57
58 return 0;
59}
60
61/**
62 * host1x_subdev_del() - remove subdevice
63 */
64static void host1x_subdev_del(struct host1x_subdev *subdev)
65{
66 list_del(&subdev->list);
67 of_node_put(subdev->np);
68 kfree(subdev);
69}
70
71/**
72 * host1x_device_parse_dt() - scan device tree and add matching subdevices
73 */
74static int host1x_device_parse_dt(struct host1x_device *device)
75{
76 struct device_node *np;
77 int err;
78
79 for_each_child_of_node(device->dev.parent->of_node, np) {
80 if (of_match_node(device->driver->subdevs, np) &&
81 of_device_is_available(np)) {
82 err = host1x_subdev_add(device, np);
83 if (err < 0)
84 return err;
85 }
86 }
87
88 return 0;
89}
90
91static void host1x_subdev_register(struct host1x_device *device,
92 struct host1x_subdev *subdev,
93 struct host1x_client *client)
94{
95 int err;
96
97 /*
98 * Move the subdevice to the list of active (registered) subdevices
99 * and associate it with a client. At the same time, associate the
100 * client with its parent device.
101 */
102 mutex_lock(&device->subdevs_lock);
103 mutex_lock(&device->clients_lock);
104 list_move_tail(&client->list, &device->clients);
105 list_move_tail(&subdev->list, &device->active);
106 client->parent = &device->dev;
107 subdev->client = client;
108 mutex_unlock(&device->clients_lock);
109 mutex_unlock(&device->subdevs_lock);
110
111 /*
112 * When all subdevices have been registered, the composite device is
113 * ready to be probed.
114 */
115 if (list_empty(&device->subdevs)) {
116 err = device->driver->probe(device);
117 if (err < 0)
118 dev_err(&device->dev, "probe failed: %d\n", err);
119 }
120}
121
122static void __host1x_subdev_unregister(struct host1x_device *device,
123 struct host1x_subdev *subdev)
124{
125 struct host1x_client *client = subdev->client;
126 int err;
127
128 /*
129 * If all subdevices have been activated, we're about to remove the
130 * first active subdevice, so unload the driver first.
131 */
132 if (list_empty(&device->subdevs)) {
133 err = device->driver->remove(device);
134 if (err < 0)
135 dev_err(&device->dev, "remove failed: %d\n", err);
136 }
137
138 /*
139 * Move the subdevice back to the list of idle subdevices and remove
140 * it from list of clients.
141 */
142 mutex_lock(&device->clients_lock);
143 subdev->client = NULL;
144 client->parent = NULL;
145 list_move_tail(&subdev->list, &device->subdevs);
146 /*
147 * XXX: Perhaps don't do this here, but rather explicitly remove it
148 * when the device is about to be deleted.
149 *
150 * This is somewhat complicated by the fact that this function is
151 * used to remove the subdevice when a client is unregistered but
152 * also when the composite device is about to be removed.
153 */
154 list_del_init(&client->list);
155 mutex_unlock(&device->clients_lock);
156}
157
158static void host1x_subdev_unregister(struct host1x_device *device,
159 struct host1x_subdev *subdev)