2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
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.
10 #include <linux/clk.h>
11 #include <linux/err.h>
12 #include <linux/module.h>
14 #include <linux/platform_device.h>
18 struct host1x_drm_client
{
19 struct host1x_client
*client
;
20 struct device_node
*np
;
21 struct list_head list
;
24 static int host1x_add_drm_client(struct host1x_drm
*host1x
,
25 struct device_node
*np
)
27 struct host1x_drm_client
*client
;
29 client
= kzalloc(sizeof(*client
), GFP_KERNEL
);
33 INIT_LIST_HEAD(&client
->list
);
34 client
->np
= of_node_get(np
);
36 list_add_tail(&client
->list
, &host1x
->drm_clients
);
41 static int host1x_activate_drm_client(struct host1x_drm
*host1x
,
42 struct host1x_drm_client
*drm
,
43 struct host1x_client
*client
)
45 mutex_lock(&host1x
->drm_clients_lock
);
46 list_del_init(&drm
->list
);
47 list_add_tail(&drm
->list
, &host1x
->drm_active
);
49 mutex_unlock(&host1x
->drm_clients_lock
);
54 static int host1x_remove_drm_client(struct host1x_drm
*host1x
,
55 struct host1x_drm_client
*client
)
57 mutex_lock(&host1x
->drm_clients_lock
);
58 list_del_init(&client
->list
);
59 mutex_unlock(&host1x
->drm_clients_lock
);
61 of_node_put(client
->np
);
67 static int host1x_parse_dt(struct host1x_drm
*host1x
)
69 static const char * const compat
[] = {
71 "nvidia,tegra20-hdmi",
73 "nvidia,tegra30-hdmi",
78 for (i
= 0; i
< ARRAY_SIZE(compat
); i
++) {
79 struct device_node
*np
;
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
);
94 static int tegra_host1x_probe(struct platform_device
*pdev
)
96 struct host1x_drm
*host1x
;
97 struct resource
*regs
;
100 host1x
= devm_kzalloc(&pdev
->dev
, sizeof(*host1x
), GFP_KERNEL
);
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
;
111 err
= host1x_parse_dt(host1x
);
113 dev_err(&pdev
->dev
, "failed to parse DT: %d\n", err
);
117 host1x
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
118 if (IS_ERR(host1x
->clk
))
119 return PTR_ERR(host1x
->clk
);
121 err
= clk_prepare_enable(host1x
->clk
);
125 regs
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
131 err
= platform_get_irq(pdev
, 0);
135 host1x
->syncpt
= err
;
137 err
= platform_get_irq(pdev
, 1);
143 host1x
->regs
= devm_ioremap_resource(&pdev
->dev
, regs
);
144 if (IS_ERR(host1x
->regs
)) {
145 err
= PTR_ERR(host1x
->regs
);
149 platform_set_drvdata(pdev
, host1x
);
154 clk_disable_unprepare(host1x
->clk
);
158 static int tegra_host1x_remove(struct platform_device
*pdev
)
160 struct host1x_drm
*host1x
= platform_get_drvdata(pdev
);
162 clk_disable_unprepare(host1x
->clk
);
167 int host1x_drm_init(struct host1x_drm
*host1x
, struct drm_device
*drm
)
169 struct host1x_client
*client
;
171 mutex_lock(&host1x
->clients_lock
);
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
);
178 "DRM setup failed for %s: %d\n",
179 dev_name(client
->dev
), err
);
185 mutex_unlock(&host1x
->clients_lock
);
190 int host1x_drm_exit(struct host1x_drm
*host1x
)
192 struct platform_device
*pdev
= to_platform_device(host1x
->dev
);
193 struct host1x_client
*client
;
198 mutex_lock(&host1x
->clients_lock
);
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
);
205 "DRM cleanup failed for %s: %d\n",
206 dev_name(client
->dev
), err
);
212 mutex_unlock(&host1x
->clients_lock
);
214 drm_platform_exit(&tegra_drm_driver
, pdev
);
220 int host1x_register_client(struct host1x_drm
*host1x
,
221 struct host1x_client
*client
)
223 struct host1x_drm_client
*drm
, *tmp
;
226 mutex_lock(&host1x
->clients_lock
);
227 list_add_tail(&client
->list
, &host1x
->clients
);
228 mutex_unlock(&host1x
->clients_lock
);
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
);
234 if (list_empty(&host1x
->drm_clients
)) {
235 struct platform_device
*pdev
= to_platform_device(host1x
->dev
);
237 err
= drm_platform_init(&tegra_drm_driver
, pdev
);
239 dev_err(host1x
->dev
, "drm_platform_init(): %d\n", err
);
244 client
->host1x
= host1x
;
249 int host1x_unregister_client(struct host1x_drm
*host1x
,
250 struct host1x_client
*client
)
252 struct host1x_drm_client
*drm
, *tmp
;
255 list_for_each_entry_safe(drm
, tmp
, &host1x
->drm_active
, list
) {
256 if (drm
->client
== client
) {
257 err
= host1x_drm_exit(host1x
);
259 dev_err(host1x
->dev
, "host1x_drm_exit(): %d\n",
264 host1x_remove_drm_client(host1x
, drm
);
269 mutex_lock(&host1x
->clients_lock
);
270 list_del_init(&client
->list
);
271 mutex_unlock(&host1x
->clients_lock
);
276 static struct of_device_id tegra_host1x_of_match
[] = {
277 { .compatible
= "nvidia,tegra30-host1x", },
278 { .compatible
= "nvidia,tegra20-host1x", },
281 MODULE_DEVICE_TABLE(of
, tegra_host1x_of_match
);
283 struct platform_driver tegra_host1x_driver
= {
285 .name
= "tegra-host1x",
286 .owner
= THIS_MODULE
,
287 .of_match_table
= tegra_host1x_of_match
,
289 .probe
= tegra_host1x_probe
,
290 .remove
= tegra_host1x_remove
,
293 static int __init
tegra_host1x_init(void)
297 err
= platform_driver_register(&tegra_host1x_driver
);
301 err
= platform_driver_register(&tegra_dc_driver
);
303 goto unregister_host1x
;
305 err
= platform_driver_register(&tegra_hdmi_driver
);
312 platform_driver_unregister(&tegra_dc_driver
);
314 platform_driver_unregister(&tegra_host1x_driver
);
317 module_init(tegra_host1x_init
);
319 static void __exit
tegra_host1x_exit(void)
321 platform_driver_unregister(&tegra_hdmi_driver
);
322 platform_driver_unregister(&tegra_dc_driver
);
323 platform_driver_unregister(&tegra_host1x_driver
);
325 module_exit(tegra_host1x_exit
);
327 MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
328 MODULE_DESCRIPTION("NVIDIA Tegra DRM driver");
329 MODULE_LICENSE("GPL");