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>
This commit is contained in:
parent
c89c0ea63f
commit
692e6d7be8
|
@ -13,6 +13,6 @@ host1x-y = \
|
|||
ccflags-y += -Iinclude/drm
|
||||
ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG
|
||||
|
||||
host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o drm/host1x.o
|
||||
host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o
|
||||
host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o
|
||||
obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
|
||||
|
|
|
@ -32,6 +32,19 @@
|
|||
#include "channel.h"
|
||||
#include "debug.h"
|
||||
#include "hw/host1x01.h"
|
||||
#include "host1x_client.h"
|
||||
|
||||
void host1x_set_drm_data(struct device *dev, void *data)
|
||||
{
|
||||
struct host1x *host1x = dev_get_drvdata(dev);
|
||||
host1x->drm_data = data;
|
||||
}
|
||||
|
||||
void *host1x_get_drm_data(struct device *dev)
|
||||
{
|
||||
struct host1x *host1x = dev_get_drvdata(dev);
|
||||
return host1x->drm_data;
|
||||
}
|
||||
|
||||
void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
|
||||
{
|
||||
|
@ -150,6 +163,8 @@ static int host1x_probe(struct platform_device *pdev)
|
|||
|
||||
host1x_debug_init(host);
|
||||
|
||||
host1x_drm_alloc(pdev);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_deinit_syncpt:
|
||||
|
@ -168,7 +183,7 @@ static int __exit host1x_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver platform_driver = {
|
||||
static struct platform_driver tegra_host1x_driver = {
|
||||
.probe = host1x_probe,
|
||||
.remove = __exit_p(host1x_remove),
|
||||
.driver = {
|
||||
|
@ -178,8 +193,47 @@ static struct platform_driver platform_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
module_platform_driver(platform_driver);
|
||||
static int __init tegra_host1x_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = platform_driver_register(&tegra_host1x_driver);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
#ifdef CONFIG_DRM_TEGRA
|
||||
err = platform_driver_register(&tegra_dc_driver);
|
||||
if (err < 0)
|
||||
goto unregister_host1x;
|
||||
|
||||
err = platform_driver_register(&tegra_hdmi_driver);
|
||||
if (err < 0)
|
||||
goto unregister_dc;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_DRM_TEGRA
|
||||
unregister_dc:
|
||||
platform_driver_unregister(&tegra_dc_driver);
|
||||
unregister_host1x:
|
||||
platform_driver_unregister(&tegra_host1x_driver);
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
module_init(tegra_host1x_init);
|
||||
|
||||
static void __exit tegra_host1x_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_DRM_TEGRA
|
||||
platform_driver_unregister(&tegra_hdmi_driver);
|
||||
platform_driver_unregister(&tegra_dc_driver);
|
||||
#endif
|
||||
platform_driver_unregister(&tegra_host1x_driver);
|
||||
}
|
||||
module_exit(tegra_host1x_exit);
|
||||
|
||||
MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
|
||||
MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Host1x driver for Tegra products");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -124,6 +124,8 @@ struct host1x {
|
|||
unsigned int num_allocated_channels;
|
||||
|
||||
struct dentry *debugfs;
|
||||
|
||||
void *drm_data;
|
||||
};
|
||||
|
||||
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)
|
|||
host->debug_op->show_mlocks(host, o);
|
||||
}
|
||||
|
||||
extern struct platform_driver tegra_hdmi_driver;
|
||||
extern struct platform_driver tegra_dc_driver;
|
||||
extern struct platform_driver tegra_gr2d_driver;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
config DRM_TEGRA
|
||||
tristate "NVIDIA Tegra DRM"
|
||||
bool "NVIDIA Tegra DRM"
|
||||
depends on DRM && OF
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_CMA_HELPER
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "drm.h"
|
||||
#include "dc.h"
|
||||
#include "host1x_client.h"
|
||||
|
||||
struct tegra_plane {
|
||||
struct drm_plane base;
|
||||
|
@ -1097,7 +1098,7 @@ static const struct host1x_client_ops dc_client_ops = {
|
|||
|
||||
static int tegra_dc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct host1x_drm *host1x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
|
||||
struct resource *regs;
|
||||
struct tegra_dc *dc;
|
||||
int err;
|
||||
|
@ -1160,7 +1161,7 @@ static int tegra_dc_probe(struct platform_device *pdev)
|
|||
|
||||
static int tegra_dc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct host1x_drm *host1x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
|
||||
struct tegra_dc *dc = platform_get_drvdata(pdev);
|
||||
int err;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <asm/dma-iommu.h>
|
||||
|
||||
#include "host1x_client.h"
|
||||
#include "drm.h"
|
||||
|
||||
#define DRIVER_NAME "tegra"
|
||||
|
@ -23,13 +24,222 @@
|
|||
#define DRIVER_MINOR 0
|
||||
#define DRIVER_PATCHLEVEL 0
|
||||
|
||||
static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
|
||||
struct host1x_drm_client {
|
||||
struct host1x_client *client;
|
||||
struct device_node *np;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static int host1x_add_drm_client(struct host1x_drm *host1x,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct host1x_drm_client *client;
|
||||
|
||||
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&client->list);
|
||||
client->np = of_node_get(np);
|
||||
|
||||
list_add_tail(&client->list, &host1x->drm_clients);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host1x_activate_drm_client(struct host1x_drm *host1x,
|
||||
struct host1x_drm_client *drm,
|
||||
struct host1x_client *client)
|
||||
{
|
||||
mutex_lock(&host1x->drm_clients_lock);
|
||||
list_del_init(&drm->list);
|
||||
list_add_tail(&drm->list, &host1x->drm_active);
|
||||
drm->client = client;
|
||||
mutex_unlock(&host1x->drm_clients_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host1x_remove_drm_client(struct host1x_drm *host1x,
|
||||
struct host1x_drm_client *client)
|
||||
{
|
||||
mutex_lock(&host1x->drm_clients_lock);
|
||||
list_del_init(&client->list);
|
||||
mutex_unlock(&host1x->drm_clients_lock);
|
||||
|
||||
of_node_put(client->np);
|
||||
kfree(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host1x_parse_dt(struct host1x_drm *host1x)
|
||||
{
|
||||
static const char * const compat[] = {
|
||||
"nvidia,tegra20-dc",
|
||||
"nvidia,tegra20-hdmi",
|
||||
"nvidia,tegra30-dc",
|
||||
"nvidia,tegra30-hdmi",
|
||||
};
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(compat); i++) {
|
||||
struct device_node *np;
|
||||
|
||||
for_each_child_of_node(host1x->dev->of_node, np) {
|
||||
if (of_device_is_compatible(np, compat[i]) &&
|
||||
of_device_is_available(np)) {
|
||||
err = host1x_add_drm_client(host1x, np);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host1x_drm_alloc(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = drm->dev;
|
||||
struct host1x_drm *host1x;
|
||||
int err;
|
||||
|
||||
host1x = dev_get_drvdata(dev);
|
||||
host1x = devm_kzalloc(&pdev->dev, sizeof(*host1x), GFP_KERNEL);
|
||||
if (!host1x)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&host1x->drm_clients_lock);
|
||||
INIT_LIST_HEAD(&host1x->drm_clients);
|
||||
INIT_LIST_HEAD(&host1x->drm_active);
|
||||
mutex_init(&host1x->clients_lock);
|
||||
INIT_LIST_HEAD(&host1x->clients);
|
||||
host1x->dev = &pdev->dev;
|
||||
|
||||
err = host1x_parse_dt(host1x);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to parse DT: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
host1x_set_drm_data(&pdev->dev, host1x);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm)
|
||||
{
|
||||
struct host1x_client *client;
|
||||
|
||||
mutex_lock(&host1x->clients_lock);
|
||||
|
||||
list_for_each_entry(client, &host1x->clients, list) {
|
||||
if (client->ops && client->ops->drm_init) {
|
||||
int err = client->ops->drm_init(client, drm);
|
||||
if (err < 0) {
|
||||
dev_err(host1x->dev,
|
||||
"DRM setup failed for %s: %d\n",
|
||||
dev_name(client->dev), err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&host1x->clients_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host1x_drm_exit(struct host1x_drm *host1x)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(host1x->dev);
|
||||
struct host1x_client *client;
|
||||
|
||||
if (!host1x->drm)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&host1x->clients_lock);
|
||||
|
||||
list_for_each_entry_reverse(client, &host1x->clients, list) {
|
||||
if (client->ops && client->ops->drm_exit) {
|
||||
int err = client->ops->drm_exit(client);
|
||||
if (err < 0) {
|
||||
dev_err(host1x->dev,
|
||||
"DRM cleanup failed for %s: %d\n",
|
||||
dev_name(client->dev), err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&host1x->clients_lock);
|
||||
|
||||
drm_platform_exit(&tegra_drm_driver, pdev);
|
||||
host1x->drm = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host1x_register_client(struct host1x_drm *host1x,
|
||||
struct host1x_client *client)
|
||||
{
|
||||
struct host1x_drm_client *drm, *tmp;
|
||||
int err;
|
||||
|
||||
mutex_lock(&host1x->clients_lock);
|
||||
list_add_tail(&client->list, &host1x->clients);
|
||||
mutex_unlock(&host1x->clients_lock);
|
||||
|
||||
list_for_each_entry_safe(drm, tmp, &host1x->drm_clients, list)
|
||||
if (drm->np == client->dev->of_node)
|
||||
host1x_activate_drm_client(host1x, drm, client);
|
||||
|
||||
if (list_empty(&host1x->drm_clients)) {
|
||||
struct platform_device *pdev = to_platform_device(host1x->dev);
|
||||
|
||||
err = drm_platform_init(&tegra_drm_driver, pdev);
|
||||
if (err < 0) {
|
||||
dev_err(host1x->dev, "drm_platform_init(): %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host1x_unregister_client(struct host1x_drm *host1x,
|
||||
struct host1x_client *client)
|
||||
{
|
||||
struct host1x_drm_client *drm, *tmp;
|
||||
int err;
|
||||
|
||||
list_for_each_entry_safe(drm, tmp, &host1x->drm_active, list) {
|
||||
if (drm->client == client) {
|
||||
err = host1x_drm_exit(host1x);
|
||||
if (err < 0) {
|
||||
dev_err(host1x->dev, "host1x_drm_exit(): %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
host1x_remove_drm_client(host1x, drm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&host1x->clients_lock);
|
||||
list_del_init(&client->list);
|
||||
mutex_unlock(&host1x->clients_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
|
||||
{
|
||||
struct host1x_drm *host1x;
|
||||
int err;
|
||||
|
||||
host1x = host1x_get_drm_data(drm->dev);
|
||||
drm->dev_private = host1x;
|
||||
host1x->drm = drm;
|
||||
|
||||
|
|
|
@ -229,9 +229,6 @@ extern int tegra_output_exit(struct tegra_output *output);
|
|||
extern int tegra_drm_fb_init(struct drm_device *drm);
|
||||
extern void tegra_drm_fb_exit(struct drm_device *drm);
|
||||
|
||||
extern struct platform_driver tegra_host1x_driver;
|
||||
extern struct platform_driver tegra_hdmi_driver;
|
||||
extern struct platform_driver tegra_dc_driver;
|
||||
extern struct drm_driver tegra_drm_driver;
|
||||
|
||||
#endif /* HOST1X_DRM_H */
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "hdmi.h"
|
||||
#include "drm.h"
|
||||
#include "dc.h"
|
||||
#include "host1x_client.h"
|
||||
|
||||
struct tegra_hdmi {
|
||||
struct host1x_client client;
|
||||
|
@ -1189,7 +1190,7 @@ static const struct host1x_client_ops hdmi_client_ops = {
|
|||
|
||||
static int tegra_hdmi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct host1x_drm *host1x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
|
||||
struct tegra_hdmi *hdmi;
|
||||
struct resource *regs;
|
||||
int err;
|
||||
|
@ -1278,7 +1279,7 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
|
|||
|
||||
static int tegra_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct host1x_drm *host1x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct host1x_drm *host1x = host1x_get_drm_data(pdev->dev.parent);
|
||||
struct tegra_hdmi *hdmi = platform_get_drvdata(pdev);
|
||||
int err;
|
||||
|
||||
|
|
|
@ -1,329 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Avionic Design GmbH
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "drm.h"
|
||||
|
||||
struct host1x_drm_client {
|
||||
struct host1x_client *client;
|
||||
struct device_node *np;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static int host1x_add_drm_client(struct host1x_drm *host1x,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct host1x_drm_client *client;
|
||||
|
||||
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&client->list);
|
||||
client->np = of_node_get(np);
|
||||
|
||||
list_add_tail(&client->list, &host1x->drm_clients);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host1x_activate_drm_client(struct host1x_drm *host1x,
|
||||
struct host1x_drm_client *drm,
|
||||
struct host1x_client *client)
|
||||
{
|
||||
mutex_lock(&host1x->drm_clients_lock);
|
||||
list_del_init(&drm->list);
|
||||
list_add_tail(&drm->list, &host1x->drm_active);
|
||||
drm->client = client;
|
||||
mutex_unlock(&host1x->drm_clients_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host1x_remove_drm_client(struct host1x_drm *host1x,
|
||||
struct host1x_drm_client *client)
|
||||
{
|
||||
mutex_lock(&host1x->drm_clients_lock);
|
||||
list_del_init(&client->list);
|
||||
mutex_unlock(&host1x->drm_clients_lock);
|
||||
|
||||
of_node_put(client->np);
|
||||
kfree(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int host1x_parse_dt(struct host1x_drm *host1x)
|
||||
{
|
||||
static const char * const compat[] = {
|
||||
"nvidia,tegra20-dc",
|
||||
"nvidia,tegra20-hdmi",
|
||||
"nvidia,tegra30-dc",
|
||||
"nvidia,tegra30-hdmi",
|
||||
};
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(compat); i++) {
|
||||
struct device_node *np;
|
||||
|
||||
for_each_child_of_node(host1x->dev->of_node, np) {
|
||||
if (of_device_is_compatible(np, compat[i]) &&
|
||||
of_device_is_available(np)) {
|
||||
err = host1x_add_drm_client(host1x, np);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_host1x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct host1x_drm *host1x;
|
||||
struct resource *regs;
|
||||
int err;
|
||||
|
||||
host1x = devm_kzalloc(&pdev->dev, sizeof(*host1x), GFP_KERNEL);
|
||||
if (!host1x)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&host1x->drm_clients_lock);
|
||||
INIT_LIST_HEAD(&host1x->drm_clients);
|
||||
INIT_LIST_HEAD(&host1x->drm_active);
|
||||
mutex_init(&host1x->clients_lock);
|
||||
INIT_LIST_HEAD(&host1x->clients);
|
||||
host1x->dev = &pdev->dev;
|
||||
|
||||
err = host1x_parse_dt(host1x);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to parse DT: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
host1x->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(host1x->clk))
|
||||
return PTR_ERR(host1x->clk);
|
||||
|
||||
err = clk_prepare_enable(host1x->clk);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!regs) {
|
||||
err = -ENXIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err = platform_get_irq(pdev, 0);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
|
||||
host1x->syncpt = err;
|
||||
|
||||
err = platform_get_irq(pdev, 1);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
|
||||
host1x->irq = err;
|
||||
|
||||
host1x->regs = devm_ioremap_resource(&pdev->dev, regs);
|
||||
if (IS_ERR(host1x->regs)) {
|
||||
err = PTR_ERR(host1x->regs);
|
||||
goto err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, host1x);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
clk_disable_unprepare(host1x->clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tegra_host1x_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct host1x_drm *host1x = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(host1x->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm)
|
||||
{
|
||||
struct host1x_client *client;
|
||||
|
||||
mutex_lock(&host1x->clients_lock);
|
||||
|
||||
list_for_each_entry(client, &host1x->clients, list) {
|
||||
if (client->ops && client->ops->drm_init) {
|
||||
int err = client->ops->drm_init(client, drm);
|
||||
if (err < 0) {
|
||||
dev_err(host1x->dev,
|
||||
"DRM setup failed for %s: %d\n",
|
||||
dev_name(client->dev), err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&host1x->clients_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host1x_drm_exit(struct host1x_drm *host1x)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(host1x->dev);
|
||||
struct host1x_client *client;
|
||||
|
||||
if (!host1x->drm)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&host1x->clients_lock);
|
||||
|
||||
list_for_each_entry_reverse(client, &host1x->clients, list) {
|
||||
if (client->ops && client->ops->drm_exit) {
|
||||
int err = client->ops->drm_exit(client);
|
||||
if (err < 0) {
|
||||
dev_err(host1x->dev,
|
||||
"DRM cleanup failed for %s: %d\n",
|
||||
dev_name(client->dev), err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&host1x->clients_lock);
|
||||
|
||||
drm_platform_exit(&tegra_drm_driver, pdev);
|
||||
host1x->drm = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host1x_register_client(struct host1x_drm *host1x,
|
||||
struct host1x_client *client)
|
||||
{
|
||||
struct host1x_drm_client *drm, *tmp;
|
||||
int err;
|
||||
|
||||
mutex_lock(&host1x->clients_lock);
|
||||
list_add_tail(&client->list, &host1x->clients);
|
||||
mutex_unlock(&host1x->clients_lock);
|
||||
|
||||
list_for_each_entry_safe(drm, tmp, &host1x->drm_clients, list)
|
||||
if (drm->np == client->dev->of_node)
|
||||
host1x_activate_drm_client(host1x, drm, client);
|
||||
|
||||
if (list_empty(&host1x->drm_clients)) {
|
||||
struct platform_device *pdev = to_platform_device(host1x->dev);
|
||||
|
||||
err = drm_platform_init(&tegra_drm_driver, pdev);
|
||||
if (err < 0) {
|
||||
dev_err(host1x->dev, "drm_platform_init(): %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
client->host1x = host1x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host1x_unregister_client(struct host1x_drm *host1x,
|
||||
struct host1x_client *client)
|
||||
{
|
||||
struct host1x_drm_client *drm, *tmp;
|
||||
int err;
|
||||
|
||||
list_for_each_entry_safe(drm, tmp, &host1x->drm_active, list) {
|
||||
if (drm->client == client) {
|
||||
err = host1x_drm_exit(host1x);
|
||||
if (err < 0) {
|
||||
dev_err(host1x->dev, "host1x_drm_exit(): %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
host1x_remove_drm_client(host1x, drm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&host1x->clients_lock);
|
||||
list_del_init(&client->list);
|
||||
mutex_unlock(&host1x->clients_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id tegra_host1x_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra30-host1x", },
|
||||
{ .compatible = "nvidia,tegra20-host1x", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_host1x_of_match);
|
||||
|
||||
struct platform_driver tegra_host1x_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-host1x",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = tegra_host1x_of_match,
|
||||
},
|
||||
.probe = tegra_host1x_probe,
|
||||
.remove = tegra_host1x_remove,
|
||||
};
|
||||
|
||||
static int __init tegra_host1x_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = platform_driver_register(&tegra_host1x_driver);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = platform_driver_register(&tegra_dc_driver);
|
||||
if (err < 0)
|
||||
goto unregister_host1x;
|
||||
|
||||
err = platform_driver_register(&tegra_hdmi_driver);
|
||||
if (err < 0)
|
||||
goto unregister_dc;
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_dc:
|
||||
platform_driver_unregister(&tegra_dc_driver);
|
||||
unregister_host1x:
|
||||
platform_driver_unregister(&tegra_host1x_driver);
|
||||
return err;
|
||||
}
|
||||
module_init(tegra_host1x_init);
|
||||
|
||||
static void __exit tegra_host1x_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tegra_hdmi_driver);
|
||||
platform_driver_unregister(&tegra_dc_driver);
|
||||
platform_driver_unregister(&tegra_host1x_driver);
|
||||
}
|
||||
module_exit(tegra_host1x_exit);
|
||||
|
||||
MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra DRM driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2013, NVIDIA Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HOST1X_CLIENT_H
|
||||
#define HOST1X_CLIENT_H
|
||||
|
||||
struct device;
|
||||
struct platform_device;
|
||||
|
||||
#ifdef CONFIG_DRM_TEGRA
|
||||
int host1x_drm_alloc(struct platform_device *pdev);
|
||||
#else
|
||||
static inline int host1x_drm_alloc(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void host1x_set_drm_data(struct device *dev, void *data);
|
||||
void *host1x_get_drm_data(struct device *dev);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue