summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Schalig <dschalig@nvidia.com>2011-10-06 20:24:07 +0900
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:14 -0800
commit80225d4761a7afb4ad16cc2a15e5c5ac16283d30 (patch)
tree2153cc57461ceb3eb0cbab664c67f2b3c3b533c4
parentf8b65fb54494b360a3263cc4176a7f1f47277c45 (diff)
video: tegra: dc: add ioctl for setting gamma lut
Adds ioctl TEGRA_DC_EXT_SET_LUT to dc_ext driver for setting a DC window's color palette. Bug 868060 Change-Id: I57ffcf3a3f91e76efd1c7f1f972b73c2edbaed82 Reviewed-on: http://git-master/r/56392 Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com> Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com> Rebase-Id: R712c71151d0c3e3d274279f334bedf312e26e75d
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h10
-rw-r--r--drivers/video/tegra/dc/dc.c46
-rw-r--r--drivers/video/tegra/dc/ext/dev.c71
-rw-r--r--include/video/tegra_dc_ext.h25
4 files changed, 151 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index 277c38df4d8c..72d6750d24e7 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -364,6 +364,13 @@ struct tegra_dc_csc {
unsigned short kvb;
};
+/* palette lookup table */
+struct tegra_dc_lut {
+ u8 r[256];
+ u8 g[256];
+ u8 b[256];
+};
+
struct tegra_dc_win {
u8 idx;
u8 fmt;
@@ -394,6 +401,7 @@ struct tegra_dc_win {
struct nvmap_handle_ref *cur_handle;
unsigned bandwidth;
unsigned new_bandwidth;
+ struct tegra_dc_lut lut;
};
@@ -502,6 +510,8 @@ void tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg);
int tegra_dc_update_csc(struct tegra_dc *dc, int win_index);
+int tegra_dc_update_lut(struct tegra_dc *dc, int win_index, int start, int len);
+
/*
* In order to get a dc's current EDID, first call tegra_dc_get_edid() from an
* interruptible context. The returned value (if non-NULL) points to a
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index f40e8cac44b9..2c85a488bbe6 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -665,6 +665,48 @@ int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx)
}
EXPORT_SYMBOL(tegra_dc_update_csc);
+static void tegra_dc_init_lut_defaults(struct tegra_dc_lut *lut)
+{
+ int i;
+ for(i=0; i<256; i++) {
+ lut->r[i] = lut->g[i] = lut->b[i] = (u8)i;
+ }
+}
+
+static void tegra_dc_set_lut(struct tegra_dc *dc,
+ struct tegra_dc_lut *lut,
+ int start,
+ int len)
+{
+ int i;
+ for (i = start, len += start; i < len; i++) {
+ u32 rgb = ((u32)lut->r[i]) |
+ ((u32)lut->g[i]<<8) |
+ ((u32)lut->b[i]<<16);
+ tegra_dc_writel(dc, rgb, DC_WIN_COLOR_PALETTE(i));
+ }
+}
+
+int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int start, int len)
+{
+ mutex_lock(&dc->lock);
+
+ if (!dc->enabled) {
+ mutex_unlock(&dc->lock);
+ return -EFAULT;
+ }
+
+ tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+
+ tegra_dc_set_lut(dc, &dc->windows[win_idx].lut, start, len);
+
+ mutex_unlock(&dc->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_update_lut);
+
static void tegra_dc_set_scaling_filter(struct tegra_dc *dc)
{
unsigned i;
@@ -1075,7 +1117,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
DC_WIN_BUFFER_ADDR_MODE);
- val = WIN_ENABLE;
+ val = WIN_ENABLE | CP_ENABLE;
if (yuvp)
val |= CSC_ENABLE;
else if (tegra_dc_fmt_bpp(win->fmt) < 24)
@@ -2185,6 +2227,8 @@ static void tegra_dc_init(struct tegra_dc *dc)
DC_CMD_DISPLAY_WINDOW_HEADER);
tegra_dc_init_csc_defaults(&dc->windows[i].csc);
tegra_dc_set_csc(dc, &dc->windows[i].csc);
+ tegra_dc_init_lut_defaults(&dc->windows[i].lut);
+ tegra_dc_set_lut(dc, &dc->windows[i].lut, 0, 256);
tegra_dc_set_scaling_filter(dc);
}
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;
}
diff --git a/include/video/tegra_dc_ext.h b/include/video/tegra_dc_ext.h
index bdfebaeb3c9a..77d4e62d70f6 100644
--- a/include/video/tegra_dc_ext.h
+++ b/include/video/tegra_dc_ext.h
@@ -164,6 +164,29 @@ struct tegra_dc_ext_csc {
__u16 kvb; /* s.2.8 */
};
+/*
+ * RGB Lookup table
+ *
+ * In true-color and YUV modes this is used for post-CSC RGB->RGB lookup, i.e.
+ * gamma-correction. In palette-indexed RGB modes, this table designates the
+ * mode's color palette.
+ *
+ * To convert 8-bit per channel RGB values to 16-bit, duplicate the 8 bits
+ * in low and high byte, e.g. r=r|(r<<8)
+ *
+ * Current Tegra DC hardware supports 8-bit per channel to 8-bit per channel,
+ * and each hardware window (overlay) uses its own lookup table.
+ *
+ */
+struct tegra_dc_ext_lut {
+ __u32 win_index; /* window index to set lut for */
+ __u32 start; /* start index to update lut from */
+ __u32 len; /* number of valid lut entries */
+ __u16* r; /* array of size 16-bit red values */
+ __u16* g; /* array of size 16-bit green values */
+ __u16* b; /* array of size 16-bit blue values */
+};
+
#define TEGRA_DC_EXT_FLAGS_ENABLED 1
struct tegra_dc_ext_status {
@@ -205,6 +228,8 @@ struct tegra_dc_ext_status {
#define TEGRA_DC_EXT_GET_VBLANK_SYNCPT \
_IOR('D', 0x09, __u32)
+#define TEGRA_DC_EXT_SET_LUT \
+ _IOR('D', 0x0A, struct tegra_dc_ext_lut)
enum tegra_dc_ext_control_output_type {
TEGRA_DC_EXT_DSI,