Skip to content

Commit

Permalink
gpu: host1x: Remove second host1x driver
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Terje Bergstrom authored and Thierry Reding committed Apr 22, 2013
1 parent c89c0ea commit 692e6d7
Show file tree
Hide file tree
Showing 10 changed files with 317 additions and 342 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/host1x/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
58 changes: 56 additions & 2 deletions drivers/gpu/host1x/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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:
Expand All @@ -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 = {
Expand All @@ -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");
6 changes: 6 additions & 0 deletions drivers/gpu/host1x/dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion drivers/gpu/host1x/drm/Kconfig
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 3 additions & 2 deletions drivers/gpu/host1x/drm/dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "drm.h"
#include "dc.h"
#include "host1x_client.h"

struct tegra_plane {
struct drm_plane base;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
214 changes: 212 additions & 2 deletions drivers/gpu/host1x/drm/drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -23,13 +24,222 @@
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 0

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 host1x_drm *host1x;
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_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 device *dev = drm->dev;
struct host1x_drm *host1x;
int err;

host1x = dev_get_drvdata(dev);
host1x = host1x_get_drm_data(drm->dev);
drm->dev_private = host1x;
host1x->drm = drm;

Expand Down
3 changes: 0 additions & 3 deletions drivers/gpu/host1x/drm/drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Loading

0 comments on commit 692e6d7

Please sign in to comment.