summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc/ext/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/dc/ext/dev.c')
-rw-r--r--drivers/video/tegra/dc/ext/dev.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 01454f5a8235..b8993dd350f6 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -520,6 +520,67 @@ static int tegra_dc_ext_set_csc(struct tegra_dc_ext_user *user,
return 0;
}
+static int set_lut_channel(u16 *channel_from_user,
+ u8 *channel_to,
+ u32 start,
+ u32 len)
+{
+ int i;
+ u16 lut16bpp[256];
+
+ if (copy_from_user(lut16bpp, channel_from_user, len<<1))
+ return 1;
+
+ for (i=0; i<len; i++)
+ channel_to[start+i] = lut16bpp[i]>>8;
+
+ return 0;
+}
+
+static int tegra_dc_ext_set_lut(struct tegra_dc_ext_user *user,
+ struct tegra_dc_ext_lut *new_lut)
+{
+ int err;
+ unsigned int index = new_lut->win_index;
+ u32 start = new_lut->start;
+ u32 len = new_lut->len;
+
+ struct tegra_dc *dc = user->ext->dc;
+ struct tegra_dc_ext_win *ext_win;
+ struct tegra_dc_lut *lut;
+
+ if (index >= DC_N_WINDOWS)
+ return -EINVAL;
+
+ if ((start >= 256) || (len > 256) || ((start + len) > 256))
+ return -EINVAL;
+
+ ext_win = &user->ext->win[index];
+ lut = &dc->windows[index].lut;
+
+ mutex_lock(&ext_win->lock);
+
+ if (ext_win->user != user) {
+ mutex_unlock(&ext_win->lock);
+ return -EACCES;
+ }
+
+ err = set_lut_channel(new_lut->r, lut->r, start, len) |
+ set_lut_channel(new_lut->g, lut->g, start, len) |
+ set_lut_channel(new_lut->b, lut->b, start, len);
+
+ if (err) {
+ mutex_unlock(&ext_win->lock);
+ return -EFAULT;
+ }
+
+ tegra_dc_update_lut(dc, index, start, len);
+
+ mutex_unlock(&ext_win->lock);
+
+ return 0;
+}
+
static u32 tegra_dc_ext_get_vblank_syncpt(struct tegra_dc_ext_user *user)
{
struct tegra_dc *dc = user->ext->dc;
@@ -627,6 +688,16 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
return ret;
}
+ case TEGRA_DC_EXT_SET_LUT:
+ {
+ struct tegra_dc_ext_lut args;
+
+ if (copy_from_user(&args, user_arg, sizeof(args)))
+ return -EFAULT;
+
+ return tegra_dc_ext_set_lut(user, &args);
+ }
+
default:
return -EINVAL;
}