summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/ext
diff options
context:
space:
mode:
authorRobert Morell <rmorell@nvidia.com>2011-02-18 15:51:38 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:12 -0800
commitcd42c053c598d720c12ca8d2e13715ee490f6717 (patch)
tree60b8098504ecc8b1ee6524f5df22e1151072a570 /drivers/video/tegra/dc/ext
parent5197ed5e5f11b4f77bdcf9020a01bada5db45f1a (diff)
video: tegra: Add cursor support to dc extensions
This change adds full support for specify the cursor image and manipulating its position. bug 818525 Original-Change-Id: I101a951aff358b0ac0998afc6fe5f6c5c4d37c64 Signed-off-by: Robert Morell <rmorell@nvidia.com> Reviewed-on: http://git-master/r/40518 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: R93f0c68a14e4419f200a77d48a17eb8862f2e4e1
Diffstat (limited to 'drivers/video/tegra/dc/ext')
-rw-r--r--drivers/video/tegra/dc/ext/Makefile1
-rw-r--r--drivers/video/tegra/dc/ext/cursor.c184
-rw-r--r--drivers/video/tegra/dc/ext/dev.c27
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h16
4 files changed, 228 insertions, 0 deletions
diff --git a/drivers/video/tegra/dc/ext/Makefile b/drivers/video/tegra/dc/ext/Makefile
index bd530c2f8164..1a202f95f391 100644
--- a/drivers/video/tegra/dc/ext/Makefile
+++ b/drivers/video/tegra/dc/ext/Makefile
@@ -1,2 +1,3 @@
obj-y += dev.o
obj-y += util.o
+obj-y += cursor.o
diff --git a/drivers/video/tegra/dc/ext/cursor.c b/drivers/video/tegra/dc/ext/cursor.c
new file mode 100644
index 000000000000..e25ca0fd3fc2
--- /dev/null
+++ b/drivers/video/tegra/dc/ext/cursor.c
@@ -0,0 +1,184 @@
+/*
+ * drivers/video/tegra/dc/ext/cursor.c
+ *
+ * Copyright (C) 2011, NVIDIA Corporation
+ *
+ * Author: Robert Morell <rmorell@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#include <video/tegra_dc_ext.h>
+
+#include "tegra_dc_ext_priv.h"
+
+/* ugh */
+#include "../dc_priv.h"
+#include "../dc_reg.h"
+
+int tegra_dc_ext_get_cursor(struct tegra_dc_ext_user *user)
+{
+ struct tegra_dc_ext *ext = user->ext;
+ int ret = 0;
+
+ mutex_lock(&ext->cursor.lock);
+
+ if (!ext->cursor.user)
+ ext->cursor.user = user;
+ else if (ext->cursor.user != user)
+ ret = -EBUSY;
+
+ mutex_unlock(&ext->cursor.lock);
+
+ return ret;
+}
+
+int tegra_dc_ext_put_cursor(struct tegra_dc_ext_user *user)
+{
+ struct tegra_dc_ext *ext = user->ext;
+ int ret = 0;
+
+ mutex_lock(&ext->cursor.lock);
+
+ if (ext->cursor.user == user)
+ ext->cursor.user = 0;
+ else
+ ret = -EACCES;
+
+ mutex_unlock(&ext->cursor.lock);
+
+ return ret;
+}
+
+static void set_cursor_image_hw(struct tegra_dc *dc,
+ struct tegra_dc_ext_cursor_image *args,
+ dma_addr_t phys_addr)
+{
+ tegra_dc_writel(dc,
+ CURSOR_COLOR(args->foreground.r,
+ args->foreground.g,
+ args->foreground.b),
+ DC_DISP_CURSOR_FOREGROUND);
+ tegra_dc_writel(dc,
+ CURSOR_COLOR(args->background.r,
+ args->background.g,
+ args->background.b),
+ DC_DISP_CURSOR_BACKGROUND);
+
+ BUG_ON(phys_addr & ~CURSOR_START_ADDR_MASK);
+
+ tegra_dc_writel(dc,
+ CURSOR_START_ADDR(((unsigned long) phys_addr)) |
+ ((args->flags & TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64) ?
+ CURSOR_SIZE_64 : 0),
+ DC_DISP_CURSOR_START_ADDR);
+}
+
+int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
+ struct tegra_dc_ext_cursor_image *args)
+{
+ struct tegra_dc_ext *ext = user->ext;
+ struct tegra_dc *dc = ext->dc;
+ struct nvmap_handle_ref *handle, *old_handle;
+ dma_addr_t phys_addr;
+ u32 size;
+ int ret;
+
+ if (!user->nvmap)
+ return -EFAULT;
+
+ size = args->flags & (TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 |
+ TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64);
+
+ if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 &&
+ size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64)
+ return -EINVAL;
+
+ mutex_lock(&ext->cursor.lock);
+
+ if (ext->cursor.user != user) {
+ mutex_unlock(&ext->cursor.lock);
+ return -EACCES;
+ }
+
+ old_handle = ext->cursor.cur_handle;
+
+ ret = tegra_dc_ext_pin_window(user, args->buff_id, &handle, &phys_addr);
+ if (ret) {
+ mutex_unlock(&ext->cursor.lock);
+ return -EACCES;
+ }
+
+ ext->cursor.cur_handle = handle;
+
+ mutex_lock(&dc->lock);
+
+ set_cursor_image_hw(dc, args, phys_addr);
+
+ tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+ /* XXX sync here? */
+
+ mutex_unlock(&dc->lock);
+
+ mutex_unlock(&ext->cursor.lock);
+
+ if (old_handle) {
+ nvmap_unpin(ext->nvmap, old_handle);
+ nvmap_free(ext->nvmap, old_handle);
+ }
+
+ return 0;
+}
+
+int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
+ struct tegra_dc_ext_cursor *args)
+{
+ struct tegra_dc_ext *ext = user->ext;
+ struct tegra_dc *dc = ext->dc;
+ u32 win_options;
+ bool enable;
+
+ mutex_lock(&ext->cursor.lock);
+
+ if (ext->cursor.user != user) {
+ mutex_unlock(&ext->cursor.lock);
+ return -EACCES;
+ }
+
+ enable = !!(args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE);
+
+ mutex_lock(&dc->lock);
+
+ win_options = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+ if (!!(win_options & CURSOR_ENABLE) != enable) {
+ win_options &= ~CURSOR_ENABLE;
+ if (enable)
+ win_options |= CURSOR_ENABLE;
+ tegra_dc_writel(dc, win_options, DC_DISP_DISP_WIN_OPTIONS);
+ }
+
+ tegra_dc_writel(dc, CURSOR_POSITION(args->x, args->y),
+ DC_DISP_CURSOR_POSITION);
+
+ tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+ /* TODO: need to sync here? hopefully can avoid this, but need to
+ * figure out interaction w/ rest of GENERAL_ACT_REQ */
+
+ mutex_unlock(&dc->lock);
+
+ mutex_unlock(&ext->cursor.lock);
+
+ return 0;
+}
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 2fa11d9da189..b51b9378c551 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -426,6 +426,29 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
return ret;
}
+ case TEGRA_DC_EXT_GET_CURSOR:
+ return tegra_dc_ext_get_cursor(user);
+ case TEGRA_DC_EXT_PUT_CURSOR:
+ return tegra_dc_ext_put_cursor(user);
+ case TEGRA_DC_EXT_SET_CURSOR_IMAGE:
+ {
+ struct tegra_dc_ext_cursor_image args;
+
+ if (copy_from_user(&args, user_arg, sizeof(args)))
+ return -EFAULT;
+
+ return tegra_dc_ext_set_cursor_image(user, &args);
+ }
+ case TEGRA_DC_EXT_SET_CURSOR:
+ {
+ struct tegra_dc_ext_cursor args;
+
+ if (copy_from_user(&args, user_arg, sizeof(args)))
+ return -EFAULT;
+
+ return tegra_dc_ext_set_cursor(user, &args);
+ }
+
default:
return -EINVAL;
}
@@ -458,6 +481,8 @@ static int tegra_dc_release(struct inode *inode, struct file *filp)
if (ext->win[i].user == user)
tegra_dc_ext_put_window(user, i);
}
+ if (ext->cursor.user == user)
+ tegra_dc_ext_put_cursor(user);
if (user->nvmap)
nvmap_client_put(user->nvmap);
@@ -550,6 +575,8 @@ struct tegra_dc_ext *tegra_dc_ext_register(struct nvhost_device *ndev,
if (ret)
goto cleanup_nvmap;
+ mutex_init(&ext->cursor.lock);
+
tegra_dc_ext_devno++;
return ext;
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
index d7d5e5506718..3040cf7fc601 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -22,8 +22,11 @@
#include <linux/cdev.h>
#include <linux/mutex.h>
+#include <mach/dc.h>
#include <mach/nvmap.h>
+#include <video/tegra_dc_ext.h>
+
struct tegra_dc_ext;
struct tegra_dc_ext_user {
@@ -54,10 +57,23 @@ struct tegra_dc_ext {
struct nvmap_client *nvmap;
struct tegra_dc_ext_win win[DC_N_WINDOWS];
+
+ struct {
+ struct tegra_dc_ext_user *user;
+ struct nvmap_handle_ref *cur_handle;
+ struct mutex lock;
+ } cursor;
};
extern int tegra_dc_ext_pin_window(struct tegra_dc_ext_user *user, u32 id,
struct nvmap_handle_ref **handle,
dma_addr_t *phys_addr);
+extern int tegra_dc_ext_get_cursor(struct tegra_dc_ext_user *user);
+extern int tegra_dc_ext_put_cursor(struct tegra_dc_ext_user *user);
+extern int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
+ struct tegra_dc_ext_cursor_image *);
+extern int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
+ struct tegra_dc_ext_cursor *);
+
#endif /* __TEGRA_DC_EXT_PRIV_H */