diff options
author | David Schalig <dschalig@nvidia.com> | 2011-10-06 20:24:07 +0900 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:49:14 -0800 |
commit | 80225d4761a7afb4ad16cc2a15e5c5ac16283d30 (patch) | |
tree | 2153cc57461ceb3eb0cbab664c67f2b3c3b533c4 | |
parent | f8b65fb54494b360a3263cc4176a7f1f47277c45 (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.h | 10 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 46 | ||||
-rw-r--r-- | drivers/video/tegra/dc/ext/dev.c | 71 | ||||
-rw-r--r-- | include/video/tegra_dc_ext.h | 25 |
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, |