diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2013-03-22 10:34:07 -0400 |
---|---|---|
committer | Thierry Reding <thierry.reding@avionic-design.de> | 2013-04-22 06:39:59 -0400 |
commit | 692e6d7be8099225f04b2d97299bc03479a5fcdb (patch) | |
tree | 13e5a72eeaca72c0b73a668f5f683df6e01619d0 | |
parent | c89c0ea63fcd045bdc17076fd078676e1da0c41a (diff) |
gpu: host1x: Remove second host1x driver
Remove second host1x driver, and bind tegra-drm to the new host1x
driver. The logic to parse device tree and track clients is moved
to drm.c.
Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Erik Faye-Lund <kusmabite@gmail.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
-rw-r--r-- | drivers/gpu/host1x/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/host1x/dev.c | 58 | ||||
-rw-r--r-- | drivers/gpu/host1x/dev.h | 6 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/dc.c | 5 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/drm.c | 214 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/drm.h | 3 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/hdmi.c | 5 | ||||
-rw-r--r-- | drivers/gpu/host1x/drm/host1x.c | 329 | ||||
-rw-r--r-- | drivers/gpu/host1x/host1x_client.h | 35 |
10 files changed, 317 insertions, 342 deletions
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile index 4761e8af7bdc..9a6fc767f6b8 100644 --- a/drivers/gpu/host1x/Makefile +++ b/drivers/gpu/host1x/Makefile | |||
@@ -13,6 +13,6 @@ host1x-y = \ | |||
13 | ccflags-y += -Iinclude/drm | 13 | ccflags-y += -Iinclude/drm |
14 | ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG | 14 | ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG |
15 | 15 | ||
16 | host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o drm/host1x.o | 16 | 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 | 17 | host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o |
18 | obj-$(CONFIG_TEGRA_HOST1X) += host1x.o | 18 | obj-$(CONFIG_TEGRA_HOST1X) += host1x.o |
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 96897242fcc2..8ce9889cefd5 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c | |||
@@ -32,6 +32,19 @@ | |||
32 | #include "channel.h" | 32 | #include "channel.h" |
33 | #include "debug.h" | 33 | #include "debug.h" |
34 | #include "hw/host1x01.h" | 34 | #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->drm_data; | ||
47 | } | ||
35 | 48 | ||
36 | void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) | 49 | void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) |
37 | { | 50 | { |
@@ -150,6 +163,8 @@ static int host1x_probe(struct platform_device *pdev) | |||
150 | 163 | ||
151 | host1x_debug_init(host); | 164 | host1x_debug_init(host); |
152 | 165 | ||
166 | host1x_drm_alloc(pdev); | ||
167 | |||
153 | return 0; | 168 | return 0; |
154 | 169 | ||
155 | fail_deinit_syncpt: | 170 | fail_deinit_syncpt: |
@@ -168,7 +183,7 @@ static int __exit host1x_remove(struct platform_device *pdev) | |||
168 | return 0; | 183 | return 0; |
169 | } | 184 | } |
170 | 185 | ||
171 | static struct platform_driver platform_driver = { | 186 | static struct platform_driver tegra_host1x_driver = { |
172 | .probe = host1x_probe, | 187 | .probe = host1x_probe, |
173 | .remove = __exit_p(host1x_remove), | 188 | .remove = __exit_p(host1x_remove), |
174 | .driver = { | 189 | .driver = { |
@@ -178,8 +193,47 @@ static struct platform_driver platform_driver = { | |||
178 | }, | 193 | }, |
179 | }; | 194 | }; |
180 | 195 | ||
181 | module_platform_driver(platform_driver); | 196 | static int __init tegra_host1x_init(void) |
197 | { | ||
198 | int err; | ||
199 | |||
200 | err = platform_driver_register(&tegra_host1x_driver); | ||
201 | if (err < 0) | ||
202 | return err; | ||
203 | |||
204 | #ifdef CONFIG_DRM_TEGRA | ||
205 | err = platform_driver_register(&tegra_dc_driver); | ||
206 | if (err < 0) | ||
207 | goto unregister_host1x; | ||
208 | |||
209 | err = platform_driver_register(&tegra_hdmi_driver); | ||
210 | if (err < 0) | ||
211 | goto unregister_dc; | ||
212 | #endif | ||
213 | |||
214 | return 0; | ||
215 | |||
216 | #ifdef CONFIG_DRM_TEGRA | ||
217 | unregister_dc: | ||
218 | platform_driver_unregister(&tegra_dc_driver); | ||
219 | unregister_host1x: | ||
220 | platform_driver_unregister(&tegra_host1x_driver); | ||
221 | return err; | ||
222 | #endif | ||
223 | } | ||
224 | module_init(tegra_host1x_init); | ||
225 | |||
226 | static void __exit tegra_host1x_exit(void) | ||
227 | { | ||
228 | #ifdef CONFIG_DRM_TEGRA | ||
229 | platform_driver_unregister(&tegra_hdmi_driver); | ||
230 | platform_driver_unregister(&tegra_dc_driver); | ||
231 | #endif | ||
232 | platform_driver_unregister(&tegra_host1x_driver); | ||
233 | } | ||
234 | module_exit(tegra_host1x_exit); | ||
182 | 235 | ||
236 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | ||
183 | MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>"); | 237 | MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>"); |
184 | MODULE_DESCRIPTION("Host1x driver for Tegra products"); | 238 | MODULE_DESCRIPTION("Host1x driver for Tegra products"); |
185 | MODULE_LICENSE("GPL"); | 239 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index 4d16fe92400a..a1607d6e135b 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h | |||
@@ -124,6 +124,8 @@ struct host1x { | |||
124 | unsigned int num_allocated_channels; | 124 | unsigned int num_allocated_channels; |
125 | 125 | ||
126 | struct dentry *debugfs; | 126 | struct dentry *debugfs; |
127 | |||
128 | void *drm_data; | ||
127 | }; | 129 | }; |
128 | 130 | ||
129 | void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); | 131 | void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); |
@@ -299,4 +301,8 @@ static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o) | |||
299 | host->debug_op->show_mlocks(host, o); | 301 | host->debug_op->show_mlocks(host, o); |
300 | } | 302 | } |
301 | 303 | ||
304 | extern struct platform_driver tegra_hdmi_driver; | ||
305 | extern struct platform_driver tegra_dc_driver; | ||
306 | extern struct platform_driver tegra_gr2d_driver; | ||
307 | |||
302 | #endif | 308 | #endif |
diff --git a/drivers/gpu/host1x/drm/Kconfig b/drivers/gpu/host1x/drm/Kconfig index 8267691b7aa3..33f8f7a39196 100644 --- a/drivers/gpu/host1x/drm/Kconfig +++ b/drivers/gpu/host1x/drm/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | config DRM_TEGRA | 1 | config DRM_TEGRA |
2 | tristate "NVIDIA Tegra DRM" | 2 | bool "NVIDIA Tegra DRM" |
3 | depends on DRM && OF | 3 | depends on DRM && OF |
4 | select DRM_KMS_HELPER | 4 | select DRM_KMS_HELPER |
5 | select DRM_GEM_CMA_HELPER | 5 | select DRM_GEM_CMA_HELPER |
diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c index d1f66099826f..29a79b66f36c 100644 --- a/drivers/gpu/host1x/drm/dc.c +++ b/drivers/gpu/host1x/drm/dc.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include "drm.h" | 17 | #include "drm.h" |
18 | #include "dc.h" | 18 | #include "dc.h" |
19 | #include "host1x_client.h" | ||
19 | 20 | ||
20 | struct tegra_plane { | 21 | struct tegra_plane { |
21 | struct drm_plane base; | 22 | struct drm_plane base; |
@@ -1097,7 +1098,7 @@ static const struct host1x_client_ops dc_client_ops = { | |||
1097 | 1098 | ||
1098 | static int tegra_dc_probe(struct platform_device *pdev) | 1099 | static int tegra_dc_probe(struct platform_device *pdev) |
1099 | { | 1100 | { |
1100 | struct host1x_drm *host1x = dev_get_drvdata(pdev->dev.parent); | 1101 | struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent); |
1101 | struct resource *regs; | 1102 | struct resource *regs; |
1102 | struct tegra_dc *dc; | 1103 | struct tegra_dc *dc; |
1103 | int err; | 1104 | int err; |
@@ -1160,7 +1161,7 @@ static int tegra_dc_probe(struct platform_device *pdev) | |||
1160 | 1161 | ||
1161 | static int tegra_dc_remove(struct platform_device *pdev) | 1162 | static int tegra_dc_remove(struct platform_device *pdev) |
1162 | { | 1163 | { |
1163 | struct host1x_drm *host1x = dev_get_drvdata(pdev->dev.parent); | 1164 | struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent); |
1164 | struct tegra_dc *dc = platform_get_drvdata(pdev); | 1165 | struct tegra_dc *dc = platform_get_drvdata(pdev); |
1165 | int err; | 1166 | int err; |
1166 | 1167 | ||
diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c index 6c59bcdb65e6..901f0b47815c 100644 --- a/drivers/gpu/host1x/drm/drm.c +++ b/drivers/gpu/host1x/drm/drm.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/dma-mapping.h> | 14 | #include <linux/dma-mapping.h> |
15 | #include <asm/dma-iommu.h> | 15 | #include <asm/dma-iommu.h> |
16 | 16 | ||
17 | #include "host1x_client.h" | ||
17 | #include "drm.h" | 18 | #include "drm.h" |
18 | 19 | ||
19 | #define DRIVER_NAME "tegra" | 20 | #define DRIVER_NAME "tegra" |
@@ -23,13 +24,222 @@ | |||
23 | #define DRIVER_MINOR 0 | 24 | #define DRIVER_MINOR 0 |
24 | #define DRIVER_PATCHLEVEL 0 | 25 | #define DRIVER_PATCHLEVEL 0 |
25 | 26 | ||
27 | struct host1x_drm_client { | ||
28 | struct host1x_client *client; | ||
29 | struct device_node *np; | ||
30 | struct list_head list; | ||
31 | }; | ||
32 | |||
33 | static int host1x_add_drm_client(struct host1x_drm *host1x, | ||
34 | struct device_node *np) | ||
35 | { | ||
36 | struct host1x_drm_client *client; | ||
37 | |||
38 | client = kzalloc(sizeof(*client), GFP_KERNEL); | ||
39 | if (!client) | ||
40 | return -ENOMEM; | ||
41 | |||
42 | INIT_LIST_HEAD(&client->list); | ||
43 | client->np = of_node_get(np); | ||
44 | |||
45 | list_add_tail(&client->list, &host1x->drm_clients); | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static int host1x_activate_drm_client(struct host1x_drm *host1x, | ||
51 | struct host1x_drm_client *drm, | ||
52 | struct host1x_client *client) | ||
53 | { | ||
54 | mutex_lock(&host1x->drm_clients_lock); | ||
55 | list_del_init(&drm->list); | ||
56 | list_add_tail(&drm->list, &host1x->drm_active); | ||
57 | drm->client = client; | ||
58 | mutex_unlock(&host1x->drm_clients_lock); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int host1x_remove_drm_client(struct host1x_drm *host1x, | ||
64 | struct host1x_drm_client *client) | ||
65 | { | ||
66 | mutex_lock(&host1x->drm_clients_lock); | ||
67 | list_del_init(&client->list); | ||
68 | mutex_unlock(&host1x->drm_clients_lock); | ||
69 | |||
70 | of_node_put(client->np); | ||
71 | kfree(client); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int host1x_parse_dt(struct host1x_drm *host1x) | ||
77 | { | ||
78 | static const char * const compat[] = { | ||
79 | "nvidia,tegra20-dc", | ||
80 | "nvidia,tegra20-hdmi", | ||
81 | "nvidia,tegra30-dc", | ||
82 | "nvidia,tegra30-hdmi", | ||
83 | }; | ||
84 | unsigned int i; | ||
85 | int err; | ||
86 | |||
87 | for (i = 0; i < ARRAY_SIZE(compat); i++) { | ||
88 | struct device_node *np; | ||
89 | |||
90 | for_each_child_of_node(host1x->dev->of_node, np) { | ||
91 | if (of_device_is_compatible(np, compat[i]) && | ||
92 | of_device_is_available(np)) { | ||
93 | err = host1x_add_drm_client(host1x, np); | ||
94 | if (err < 0) | ||
95 | return err; | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | int host1x_drm_alloc(struct platform_device *pdev) | ||
104 | { | ||
105 | struct host1x_drm *host1x; | ||
106 | int err; | ||
107 | |||
108 | host1x = devm_kzalloc(&pdev->dev, sizeof(*host1x), GFP_KERNEL); | ||
109 | if (!host1x) | ||
110 | return -ENOMEM; | ||
111 | |||
112 | mutex_init(&host1x->drm_clients_lock); | ||
113 | INIT_LIST_HEAD(&host1x->drm_clients); | ||
114 | INIT_LIST_HEAD(&host1x->drm_active); | ||
115 | mutex_init(&host1x->clients_lock); | ||
116 | INIT_LIST_HEAD(&host1x->clients); | ||
117 | host1x->dev = &pdev->dev; | ||
118 | |||
119 | err = host1x_parse_dt(host1x); | ||
120 | if (err < 0) { | ||
121 | dev_err(&pdev->dev, "failed to parse DT: %d\n", err); | ||
122 | return err; | ||
123 | } | ||
124 | |||
125 | host1x_set_drm_data(&pdev->dev, host1x); | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm) | ||
131 | { | ||
132 | struct host1x_client *client; | ||
133 | |||
134 | mutex_lock(&host1x->clients_lock); | ||
135 | |||
136 | list_for_each_entry(client, &host1x->clients, list) { | ||
137 | if (client->ops && client->ops->drm_init) { | ||
138 | int err = client->ops->drm_init(client, drm); | ||
139 | if (err < 0) { | ||
140 | dev_err(host1x->dev, | ||
141 | "DRM setup failed for %s: %d\n", | ||
142 | dev_name(client->dev), err); | ||
143 | return err; | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | |||
148 | mutex_unlock(&host1x->clients_lock); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | int host1x_drm_exit(struct host1x_drm *host1x) | ||
154 | { | ||
155 | struct platform_device *pdev = to_platform_device(host1x->dev); | ||
156 | struct host1x_client *client; | ||
157 | |||
158 | if (!host1x->drm) | ||
159 | return 0; | ||
160 | |||
161 | mutex_lock(&host1x->clients_lock); | ||
162 | |||
163 | list_for_each_entry_reverse(client, &host1x->clients, list) { | ||
164 | if (client->ops && client->ops->drm_exit) { | ||
165 | int err = client->ops->drm_exit(client); | ||
166 | if (err < 0) { | ||
167 | dev_err(host1x->dev, | ||
168 | "DRM cleanup failed for %s: %d\n", | ||
169 | dev_name(client->dev), err); | ||
170 | return err; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | mutex_unlock(&host1x->clients_lock); | ||
176 | |||
177 | drm_platform_exit(&tegra_drm_driver, pdev); | ||
178 | host1x->drm = NULL; | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | int host1x_register_client(struct host1x_drm *host1x, | ||
184 | struct host1x_client *client) | ||
185 | { | ||
186 | struct host1x_drm_client *drm, *tmp; | ||
187 | int err; | ||
188 | |||
189 | mutex_lock(&host1x->clients_lock); | ||
190 | list_add_tail(&client->list, &host1x->clients); | ||
191 | mutex_unlock(&host1x->clients_lock); | ||
192 | |||
193 | list_for_each_entry_safe(drm, tmp, &host1x->drm_clients, list) | ||
194 | if (drm->np == client->dev->of_node) | ||
195 | host1x_activate_drm_client(host1x, drm, client); | ||
196 | |||
197 | if (list_empty(&host1x->drm_clients)) { | ||
198 | struct platform_device *pdev = to_platform_device(host1x->dev); | ||
199 | |||
200 | err = drm_platform_init(&tegra_drm_driver, pdev); | ||
201 | if (err < 0) { | ||
202 | dev_err(host1x->dev, "drm_platform_init(): %d\n", err); | ||
203 | return err; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int host1x_unregister_client(struct host1x_drm *host1x, | ||
211 | struct host1x_client *client) | ||
212 | { | ||
213 | struct host1x_drm_client *drm, *tmp; | ||
214 | int err; | ||
215 | |||
216 | list_for_each_entry_safe(drm, tmp, &host1x->drm_active, list) { | ||
217 | if (drm->client == client) { | ||
218 | err = host1x_drm_exit(host1x); | ||
219 | if (err < 0) { | ||
220 | dev_err(host1x->dev, "host1x_drm_exit(): %d\n", | ||
221 | err); | ||
222 | return err; | ||
223 | } | ||
224 | |||
225 | host1x_remove_drm_client(host1x, drm); | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | mutex_lock(&host1x->clients_lock); | ||
231 | list_del_init(&client->list); | ||
232 | mutex_unlock(&host1x->clients_lock); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
26 | static int tegra_drm_load(struct drm_device *drm, unsigned long flags) | 237 | static int tegra_drm_load(struct drm_device *drm, unsigned long flags) |
27 | { | 238 | { |
28 | struct device *dev = drm->dev; | ||
29 | struct host1x_drm *host1x; | 239 | struct host1x_drm *host1x; |
30 | int err; | 240 | int err; |
31 | 241 | ||
32 | host1x = dev_get_drvdata(dev); | 242 | host1x = host1x_get_drm_data(drm->dev); |
33 | drm->dev_private = host1x; | 243 | drm->dev_private = host1x; |
34 | host1x->drm = drm; | 244 | host1x->drm = drm; |
35 | 245 | ||
diff --git a/drivers/gpu/host1x/drm/drm.h b/drivers/gpu/host1x/drm/drm.h index 7fedb6c63191..0b8738fc444c 100644 --- a/drivers/gpu/host1x/drm/drm.h +++ b/drivers/gpu/host1x/drm/drm.h | |||
@@ -229,9 +229,6 @@ extern int tegra_output_exit(struct tegra_output *output); | |||
229 | extern int tegra_drm_fb_init(struct drm_device *drm); | 229 | extern int tegra_drm_fb_init(struct drm_device *drm); |
230 | extern void tegra_drm_fb_exit(struct drm_device *drm); | 230 | extern void tegra_drm_fb_exit(struct drm_device *drm); |
231 | 231 | ||
232 | extern struct platform_driver tegra_host1x_driver; | ||
233 | extern struct platform_driver tegra_hdmi_driver; | ||
234 | extern struct platform_driver tegra_dc_driver; | ||
235 | extern struct drm_driver tegra_drm_driver; | 232 | extern struct drm_driver tegra_drm_driver; |
236 | 233 | ||
237 | #endif /* HOST1X_DRM_H */ | 234 | #endif /* HOST1X_DRM_H */ |
diff --git a/drivers/gpu/host1x/drm/hdmi.c b/drivers/gpu/host1x/drm/hdmi.c index f438f805b767..01097da09f7f 100644 --- a/drivers/gpu/host1x/drm/hdmi.c +++ b/drivers/gpu/host1x/drm/hdmi.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "hdmi.h" | 22 | #include "hdmi.h" |
23 | #include "drm.h" | 23 | #include "drm.h" |
24 | #include "dc.h" | 24 | #include "dc.h" |
25 | #include "host1x_client.h" | ||
25 | 26 | ||
26 | struct tegra_hdmi { | 27 | struct tegra_hdmi { |
27 | struct host1x_client client; | 28 | struct host1x_client client; |
@@ -1189,7 +1190,7 @@ static const struct host1x_client_ops hdmi_client_ops = { | |||
1189 | 1190 | ||
1190 | static int tegra_hdmi_probe(struct platform_device *pdev) | 1191 | static int tegra_hdmi_probe(struct platform_device *pdev) |
1191 | { | 1192 | { |
1192 | struct host1x_drm *host1x = dev_get_drvdata(pdev->dev.parent); | 1193 | struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent); |
1193 | struct tegra_hdmi *hdmi; | 1194 | struct tegra_hdmi *hdmi; |
1194 | struct resource *regs; | 1195 | struct resource *regs; |
1195 | int err; | 1196 | int err; |
@@ -1278,7 +1279,7 @@ static int tegra_hdmi_probe(struct platform_device *pdev) | |||
1278 | 1279 | ||
1279 | static int tegra_hdmi_remove(struct platform_device *pdev) | 1280 | static int tegra_hdmi_remove(struct platform_device *pdev) |
1280 | { | 1281 | { |
1281 | struct host1x_drm *host1x = dev_get_drvdata(pdev->dev.parent); | 1282 | struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent); |
1282 | struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); | 1283 | struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); |
1283 | int err; | 1284 | int err; |
1284 | 1285 | ||
diff --git a/drivers/gpu/host1x/drm/host1x.c b/drivers/gpu/host1x/drm/host1x.c deleted file mode 100644 index c3d8ee54d2fd..000000000000 --- a/drivers/gpu/host1x/drm/host1x.c +++ /dev/null | |||
@@ -1,329 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Avionic Design GmbH | ||
3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/err.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/of.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | #include "drm.h" | ||
17 | |||
18 | struct host1x_drm_client { | ||
19 | struct host1x_client *client; | ||
20 | struct device_node *np; | ||
21 | struct list_head list; | ||
22 | }; | ||
23 | |||
24 | static int host1x_add_drm_client(struct host1x_drm *host1x, | ||
25 | struct device_node *np) | ||
26 | { | ||
27 | struct host1x_drm_client *client; | ||
28 | |||
29 | client = kzalloc(sizeof(*client), GFP_KERNEL); | ||
30 | if (!client) | ||
31 | return -ENOMEM; | ||
32 | |||
33 | INIT_LIST_HEAD(&client->list); | ||
34 | client->np = of_node_get(np); | ||
35 | |||
36 | list_add_tail(&client->list, &host1x->drm_clients); | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int host1x_activate_drm_client(struct host1x_drm *host1x, | ||
42 | struct host1x_drm_client *drm, | ||
43 | struct host1x_client *client) | ||
44 | { | ||
45 | mutex_lock(&host1x->drm_clients_lock); | ||
46 | list_del_init(&drm->list); | ||
47 | list_add_tail(&drm->list, &host1x->drm_active); | ||
48 | drm->client = client; | ||
49 | mutex_unlock(&host1x->drm_clients_lock); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static int host1x_remove_drm_client(struct host1x_drm *host1x, | ||
55 | struct host1x_drm_client *client) | ||
56 | { | ||
57 | mutex_lock(&host1x->drm_clients_lock); | ||
58 | list_del_init(&client->list); | ||
59 | mutex_unlock(&host1x->drm_clients_lock); | ||
60 | |||
61 | of_node_put(client->np); | ||
62 | kfree(client); | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int host1x_parse_dt(struct host1x_drm *host1x) | ||
68 | { | ||
69 | static const char * const compat[] = { | ||
70 | "nvidia,tegra20-dc", | ||
71 | "nvidia,tegra20-hdmi", | ||
72 | "nvidia,tegra30-dc", | ||
73 | "nvidia,tegra30-hdmi", | ||
74 | }; | ||
75 | unsigned int i; | ||
76 | int err; | ||
77 | |||
78 | for (i = 0; i < ARRAY_SIZE(compat); i++) { | ||
79 | struct device_node *np; | ||
80 | |||
81 | for_each_child_of_node(host1x->dev->of_node, np) { | ||
82 | if (of_device_is_compatible(np, compat[i]) && | ||
83 | of_device_is_available(np)) { | ||
84 | err = host1x_add_drm_client(host1x, np); | ||
85 | if (err < 0) | ||
86 | return err; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int tegra_host1x_probe(struct platform_device *pdev) | ||
95 | { | ||
96 | struct host1x_drm *host1x; | ||
97 | struct resource *regs; | ||
98 | int err; | ||
99 | |||
100 | host1x = devm_kzalloc(&pdev->dev, sizeof(*host1x), GFP_KERNEL); | ||
101 | if (!host1x) | ||
102 | return -ENOMEM; | ||
103 | |||
104 | mutex_init(&host1x->drm_clients_lock); | ||
105 | INIT_LIST_HEAD(&host1x->drm_clients); | ||
106 | INIT_LIST_HEAD(&host1x->drm_active); | ||
107 | mutex_init(&host1x->clients_lock); | ||
108 | INIT_LIST_HEAD(&host1x->clients); | ||
109 | host1x->dev = &pdev->dev; | ||
110 | |||
111 | err = host1x_parse_dt(host1x); | ||
112 | if (err < 0) { | ||
113 | dev_err(&pdev->dev, "failed to parse DT: %d\n", err); | ||
114 | return err; | ||
115 | } | ||
116 | |||
117 | host1x->clk = devm_clk_get(&pdev->dev, NULL); | ||
118 | if (IS_ERR(host1x->clk)) | ||
119 | return PTR_ERR(host1x->clk); | ||
120 | |||
121 | err = clk_prepare_enable(host1x->clk); | ||
122 | if (err < 0) | ||
123 | return err; | ||
124 | |||
125 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
126 | if (!regs) { | ||
127 | err = -ENXIO; | ||
128 | goto err; | ||
129 | } | ||
130 | |||
131 | err = platform_get_irq(pdev, 0); | ||
132 | if (err < 0) | ||
133 | goto err; | ||
134 | |||
135 | host1x->syncpt = err; | ||
136 | |||
137 | err = platform_get_irq(pdev, 1); | ||
138 | if (err < 0) | ||
139 | goto err; | ||
140 | |||
141 | host1x->irq = err; | ||
142 | |||
143 | host1x->regs = devm_ioremap_resource(&pdev->dev, regs); | ||
144 | if (IS_ERR(host1x->regs)) { | ||
145 | err = PTR_ERR(host1x->regs); | ||
146 | goto err; | ||
147 | } | ||
148 | |||
149 | platform_set_drvdata(pdev, host1x); | ||
150 | |||
151 | return 0; | ||
152 | |||
153 | err: | ||
154 | clk_disable_unprepare(host1x->clk); | ||
155 | return err; | ||
156 | } | ||
157 | |||
158 | static int tegra_host1x_remove(struct platform_device *pdev) | ||
159 | { | ||
160 | struct host1x_drm *host1x = platform_get_drvdata(pdev); | ||
161 | |||
162 | clk_disable_unprepare(host1x->clk); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm) | ||
168 | { | ||
169 | struct host1x_client *client; | ||
170 | |||
171 | mutex_lock(&host1x->clients_lock); | ||
172 | |||
173 | list_for_each_entry(client, &host1x->clients, list) { | ||
174 | if (client->ops && client->ops->drm_init) { | ||
175 | int err = client->ops->drm_init(client, drm); | ||
176 | if (err < 0) { | ||
177 | dev_err(host1x->dev, | ||
178 | "DRM setup failed for %s: %d\n", | ||
179 | dev_name(client->dev), err); | ||
180 | return err; | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | mutex_unlock(&host1x->clients_lock); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | int host1x_drm_exit(struct host1x_drm *host1x) | ||
191 | { | ||
192 | struct platform_device *pdev = to_platform_device(host1x->dev); | ||
193 | struct host1x_client *client; | ||
194 | |||
195 | if (!host1x->drm) | ||
196 | return 0; | ||
197 | |||
198 | mutex_lock(&host1x->clients_lock); | ||
199 | |||
200 | list_for_each_entry_reverse(client, &host1x->clients, list) { | ||
201 | if (client->ops && client->ops->drm_exit) { | ||
202 | int err = client->ops->drm_exit(client); | ||
203 | if (err < 0) { | ||
204 | dev_err(host1x->dev, | ||
205 | "DRM cleanup failed for %s: %d\n", | ||
206 | dev_name(client->dev), err); | ||
207 | return err; | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | |||
212 | mutex_unlock(&host1x->clients_lock); | ||
213 | |||
214 | drm_platform_exit(&tegra_drm_driver, pdev); | ||
215 | host1x->drm = NULL; | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | int host1x_register_client(struct host1x_drm *host1x, | ||
221 | struct host1x_client *client) | ||
222 | { | ||
223 | struct host1x_drm_client *drm, *tmp; | ||
224 | int err; | ||
225 | |||
226 | mutex_lock(&host1x->clients_lock); | ||
227 | list_add_tail(&client->list, &host1x->clients); | ||
228 | mutex_unlock(&host1x->clients_lock); | ||
229 | |||
230 | list_for_each_entry_safe(drm, tmp, &host1x->drm_clients, list) | ||
231 | if (drm->np == client->dev->of_node) | ||
232 | host1x_activate_drm_client(host1x, drm, client); | ||
233 | |||
234 | if (list_empty(&host1x->drm_clients)) { | ||
235 | struct platform_device *pdev = to_platform_device(host1x->dev); | ||
236 | |||
237 | err = drm_platform_init(&tegra_drm_driver, pdev); | ||
238 | if (err < 0) { | ||
239 | dev_err(host1x->dev, "drm_platform_init(): %d\n", err); | ||
240 | return err; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | client->host1x = host1x; | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | int host1x_unregister_client(struct host1x_drm *host1x, | ||
250 | struct host1x_client *client) | ||
251 | { | ||
252 | struct host1x_drm_client *drm, *tmp; | ||
253 | int err; | ||
254 | |||
255 | list_for_each_entry_safe(drm, tmp, &host1x->drm_active, list) { | ||
256 | if (drm->client == client) { | ||
257 | err = host1x_drm_exit(host1x); | ||
258 | if (err < 0) { | ||
259 | dev_err(host1x->dev, "host1x_drm_exit(): %d\n", | ||
260 | err); | ||
261 | return err; | ||
262 | } | ||
263 | |||
264 | host1x_remove_drm_client(host1x, drm); | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | mutex_lock(&host1x->clients_lock); | ||
270 | list_del_init(&client->list); | ||
271 | mutex_unlock(&host1x->clients_lock); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static struct of_device_id tegra_host1x_of_match[] = { | ||
277 | { .compatible = "nvidia,tegra30-host1x", }, | ||
278 | { .compatible = "nvidia,tegra20-host1x", }, | ||
279 | { }, | ||
280 | }; | ||
281 | MODULE_DEVICE_TABLE(of, tegra_host1x_of_match); | ||
282 | |||
283 | struct platform_driver tegra_host1x_driver = { | ||
284 | .driver = { | ||
285 | .name = "tegra-host1x", | ||
286 | .owner = THIS_MODULE, | ||
287 | .of_match_table = tegra_host1x_of_match, | ||
288 | }, | ||
289 | .probe = tegra_host1x_probe, | ||
290 | .remove = tegra_host1x_remove, | ||
291 | }; | ||
292 | |||
293 | static int __init tegra_host1x_init(void) | ||
294 | { | ||
295 | int err; | ||
296 | |||
297 | err = platform_driver_register(&tegra_host1x_driver); | ||
298 | if (err < 0) | ||
299 | return err; | ||
300 | |||
301 | err = platform_driver_register(&tegra_dc_driver); | ||
302 | if (err < 0) | ||
303 | goto unregister_host1x; | ||
304 | |||
305 | err = platform_driver_register(&tegra_hdmi_driver); | ||
306 | if (err < 0) | ||
307 | goto unregister_dc; | ||
308 | |||
309 | return 0; | ||
310 | |||
311 | unregister_dc: | ||
312 | platform_driver_unregister(&tegra_dc_driver); | ||
313 | unregister_host1x: | ||
314 | platform_driver_unregister(&tegra_host1x_driver); | ||
315 | return err; | ||
316 | } | ||
317 | module_init(tegra_host1x_init); | ||
318 | |||
319 | static void __exit tegra_host1x_exit(void) | ||
320 | { | ||
321 | platform_driver_unregister(&tegra_hdmi_driver); | ||
322 | platform_driver_unregister(&tegra_dc_driver); | ||
323 | platform_driver_unregister(&tegra_host1x_driver); | ||
324 | } | ||
325 | module_exit(tegra_host1x_exit); | ||
326 | |||
327 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | ||
328 | MODULE_DESCRIPTION("NVIDIA Tegra DRM driver"); | ||
329 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpu/host1x/host1x_client.h b/drivers/gpu/host1x/host1x_client.h new file mode 100644 index 000000000000..9b85f10f4a44 --- /dev/null +++ b/drivers/gpu/host1x/host1x_client.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013, NVIDIA Corporation. | ||
3 | * | ||
4 | * 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 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef HOST1X_CLIENT_H | ||
18 | #define HOST1X_CLIENT_H | ||
19 | |||
20 | struct device; | ||
21 | struct platform_device; | ||
22 | |||
23 | #ifdef CONFIG_DRM_TEGRA | ||
24 | int host1x_drm_alloc(struct platform_device *pdev); | ||
25 | #else | ||
26 | static inline int host1x_drm_alloc(struct platform_device *pdev) | ||
27 | { | ||
28 | return 0; | ||
29 | } | ||
30 | #endif | ||
31 | |||
32 | void host1x_set_drm_data(struct device *dev, void *data); | ||
33 | void *host1x_get_drm_data(struct device *dev); | ||
34 | |||
35 | #endif | ||