Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 371517
b: refs/heads/master
c: d43f81c
h: refs/heads/master
i:
  371515: a2701b6
v: v3
  • Loading branch information
Terje Bergstrom authored and Thierry Reding committed Apr 22, 2013
1 parent a9dd985 commit 76a2d79
Show file tree
Hide file tree
Showing 10 changed files with 733 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: de2ba664c30fcdb0f678ab6cbb57e01a0b206085
refs/heads/master: d43f81cbaf43531a977e8b4c4427f19acf8a5061
1 change: 1 addition & 0 deletions trunk/drivers/gpu/host1x/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG
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
host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o
host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o
obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
7 changes: 7 additions & 0 deletions trunk/drivers/gpu/host1x/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,17 @@ static int __init tegra_host1x_init(void)
err = platform_driver_register(&tegra_hdmi_driver);
if (err < 0)
goto unregister_dc;

err = platform_driver_register(&tegra_gr2d_driver);
if (err < 0)
goto unregister_hdmi;
#endif

return 0;

#ifdef CONFIG_DRM_TEGRA
unregister_hdmi:
platform_driver_unregister(&tegra_hdmi_driver);
unregister_dc:
platform_driver_unregister(&tegra_dc_driver);
unregister_host1x:
Expand All @@ -226,6 +232,7 @@ module_init(tegra_host1x_init);
static void __exit tegra_host1x_exit(void)
{
#ifdef CONFIG_DRM_TEGRA
platform_driver_unregister(&tegra_gr2d_driver);
platform_driver_unregister(&tegra_hdmi_driver);
platform_driver_unregister(&tegra_dc_driver);
#endif
Expand Down
8 changes: 8 additions & 0 deletions trunk/drivers/gpu/host1x/drm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ config DRM_TEGRA

if DRM_TEGRA

config DRM_TEGRA_STAGING
bool "Enable HOST1X interface"
depends on STAGING
help
Say yes if HOST1X should be available for userspace DRM users.

If unsure, choose N.

config DRM_TEGRA_DEBUG
bool "NVIDIA Tegra DRM debug support"
help
Expand Down
212 changes: 211 additions & 1 deletion trunk/drivers/gpu/host1x/drm/drm.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2012-2013 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
Expand All @@ -14,6 +14,9 @@
#include <linux/dma-mapping.h>
#include <asm/dma-iommu.h>

#include <drm/drm.h>
#include <drm/drmP.h>

#include "host1x_client.h"
#include "dev.h"
#include "drm.h"
Expand Down Expand Up @@ -81,8 +84,10 @@ static int host1x_parse_dt(struct host1x_drm *host1x)
static const char * const compat[] = {
"nvidia,tegra20-dc",
"nvidia,tegra20-hdmi",
"nvidia,tegra20-gr2d",
"nvidia,tegra30-dc",
"nvidia,tegra30-hdmi",
"nvidia,tegra30-gr2d",
};
unsigned int i;
int err;
Expand Down Expand Up @@ -277,17 +282,215 @@ static int tegra_drm_unload(struct drm_device *drm)

static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
{
struct host1x_drm_file *fpriv;

fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL);
if (!fpriv)
return -ENOMEM;

INIT_LIST_HEAD(&fpriv->contexts);
filp->driver_priv = fpriv;

return 0;
}

static void host1x_drm_context_free(struct host1x_drm_context *context)
{
context->client->ops->close_channel(context);
kfree(context);
}

static void tegra_drm_lastclose(struct drm_device *drm)
{
struct host1x_drm *host1x = drm->dev_private;

tegra_fbdev_restore_mode(host1x->fbdev);
}

#ifdef CONFIG_DRM_TEGRA_STAGING
static bool host1x_drm_file_owns_context(struct host1x_drm_file *file,
struct host1x_drm_context *context)
{
struct host1x_drm_context *ctx;

list_for_each_entry(ctx, &file->contexts, list)
if (ctx == context)
return true;

return false;
}

static int tegra_gem_create(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct drm_tegra_gem_create *args = data;
struct tegra_bo *bo;

bo = tegra_bo_create_with_handle(file, drm, args->size,
&args->handle);
if (IS_ERR(bo))
return PTR_ERR(bo);

return 0;
}

static int tegra_gem_mmap(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct drm_tegra_gem_mmap *args = data;
struct drm_gem_object *gem;
struct tegra_bo *bo;

gem = drm_gem_object_lookup(drm, file, args->handle);
if (!gem)
return -EINVAL;

bo = to_tegra_bo(gem);

args->offset = tegra_bo_get_mmap_offset(bo);

drm_gem_object_unreference(gem);

return 0;
}

static int tegra_syncpt_read(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct drm_tegra_syncpt_read *args = data;
struct host1x *host = dev_get_drvdata(drm->dev);
struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);

if (!sp)
return -EINVAL;

args->value = host1x_syncpt_read_min(sp);
return 0;
}

static int tegra_syncpt_incr(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct drm_tegra_syncpt_incr *args = data;
struct host1x *host = dev_get_drvdata(drm->dev);
struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);

if (!sp)
return -EINVAL;

host1x_syncpt_incr(sp);
return 0;
}

static int tegra_syncpt_wait(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct drm_tegra_syncpt_wait *args = data;
struct host1x *host = dev_get_drvdata(drm->dev);
struct host1x_syncpt *sp = host1x_syncpt_get(host, args->id);

if (!sp)
return -EINVAL;

return host1x_syncpt_wait(sp, args->thresh, args->timeout,
&args->value);
}

static int tegra_open_channel(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct drm_tegra_open_channel *args = data;
struct host1x_client *client;
struct host1x_drm_context *context;
struct host1x_drm_file *fpriv = file->driver_priv;
struct host1x_drm *host1x = drm->dev_private;
int err = -ENODEV;

context = kzalloc(sizeof(*context), GFP_KERNEL);
if (!context)
return -ENOMEM;

list_for_each_entry(client, &host1x->clients, list)
if (client->class == args->client) {
err = client->ops->open_channel(client, context);
if (err)
break;

context->client = client;
list_add(&context->list, &fpriv->contexts);
args->context = (uintptr_t)context;
return 0;
}

kfree(context);
return err;
}

static int tegra_close_channel(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct drm_tegra_close_channel *args = data;
struct host1x_drm_file *fpriv = file->driver_priv;
struct host1x_drm_context *context =
(struct host1x_drm_context *)(uintptr_t)args->context;

if (!host1x_drm_file_owns_context(fpriv, context))
return -EINVAL;

list_del(&context->list);
host1x_drm_context_free(context);

return 0;
}

static int tegra_get_syncpt(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct drm_tegra_get_syncpt *args = data;
struct host1x_drm_file *fpriv = file->driver_priv;
struct host1x_drm_context *context =
(struct host1x_drm_context *)(uintptr_t)args->context;
struct host1x_syncpt *syncpt;

if (!host1x_drm_file_owns_context(fpriv, context))
return -ENODEV;

if (args->index >= context->client->num_syncpts)
return -EINVAL;

syncpt = context->client->syncpts[args->index];
args->id = host1x_syncpt_id(syncpt);

return 0;
}

static int tegra_submit(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct drm_tegra_submit *args = data;
struct host1x_drm_file *fpriv = file->driver_priv;
struct host1x_drm_context *context =
(struct host1x_drm_context *)(uintptr_t)args->context;

if (!host1x_drm_file_owns_context(fpriv, context))
return -ENODEV;

return context->client->ops->submit(context, args, drm, file);
}
#endif

static struct drm_ioctl_desc tegra_drm_ioctls[] = {
#ifdef CONFIG_DRM_TEGRA_STAGING
DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED),
#endif
};

static const struct file_operations tegra_drm_fops = {
Expand Down Expand Up @@ -349,10 +552,17 @@ static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe)

static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
{
struct host1x_drm_file *fpriv = file->driver_priv;
struct host1x_drm_context *context, *tmp;
struct drm_crtc *crtc;

list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
tegra_dc_cancel_page_flip(crtc, file);

list_for_each_entry_safe(context, tmp, &fpriv->contexts, list)
host1x_drm_context_free(context);

kfree(fpriv);
}

#ifdef CONFIG_DEBUG_FS
Expand Down
27 changes: 26 additions & 1 deletion trunk/drivers/gpu/host1x/drm/drm.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2012-2013 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
Expand All @@ -15,6 +15,9 @@
#include <drm/drm_edid.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fixed.h>
#include <uapi/drm/tegra_drm.h>

#include "host1x.h"

struct tegra_fb {
struct drm_framebuffer base;
Expand Down Expand Up @@ -47,9 +50,25 @@ struct host1x_drm {

struct host1x_client;

struct host1x_drm_context {
struct host1x_client *client;
struct host1x_channel *channel;
struct list_head list;
};

struct host1x_client_ops {
int (*drm_init)(struct host1x_client *client, struct drm_device *drm);
int (*drm_exit)(struct host1x_client *client);
int (*open_channel)(struct host1x_client *client,
struct host1x_drm_context *context);
void (*close_channel)(struct host1x_drm_context *context);
int (*submit)(struct host1x_drm_context *context,
struct drm_tegra_submit *args, struct drm_device *drm,
struct drm_file *file);
};

struct host1x_drm_file {
struct list_head contexts;
};

struct host1x_client {
Expand All @@ -58,6 +77,12 @@ struct host1x_client {

const struct host1x_client_ops *ops;

enum host1x_class class;
struct host1x_channel *channel;

struct host1x_syncpt **syncpts;
unsigned int num_syncpts;

struct list_head list;
};

Expand Down
Loading

0 comments on commit 76a2d79

Please sign in to comment.