aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/host1x/drm
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 /drivers/gpu/host1x/drm
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>
Diffstat (limited to 'drivers/gpu/host1x/drm')
-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
6 files changed, 271 insertions, 301 deletions
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);