diff options
-rw-r--r-- | arch/arm/mach-tegra/include/mach/dc.h | 15 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 53 | ||||
-rw-r--r-- | drivers/video/tegra/dc/ext/dev.c | 47 | ||||
-rw-r--r-- | include/video/tegra_dc_ext.h | 34 |
4 files changed, 139 insertions, 10 deletions
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index 8500619254e9..2482100c8cbe 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -349,6 +349,17 @@ struct tegra_dc_out { struct tegra_dc; struct nvmap_handle_ref; +struct tegra_dc_csc { + unsigned short yof; + unsigned short kyrgb; + unsigned short kur; + unsigned short kvr; + unsigned short kug; + unsigned short kvg; + unsigned short kub; + unsigned short kvb; +}; + struct tegra_dc_win { u8 idx; u8 fmt; @@ -371,6 +382,8 @@ struct tegra_dc_win { unsigned out_h; unsigned z; + struct tegra_dc_csc csc; + int dirty; int underflows; struct tegra_dc *dc; @@ -482,4 +495,6 @@ struct tegra_dc_pwm_params { 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); + #endif diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index 9657fb5644c6..e4f863d12b02 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -621,18 +621,50 @@ static void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *bl } } -static void tegra_dc_set_csc(struct tegra_dc *dc) +static void tegra_dc_init_csc_defaults(struct tegra_dc_csc *csc) { - tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF); - tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB); - tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR); - tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR); - tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG); - tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG); - tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB); - tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB); + csc->yof = 0x00f0; + csc->kyrgb = 0x012a; + csc->kur = 0x0000; + csc->kvr = 0x0198; + csc->kug = 0x039b; + csc->kvg = 0x032f; + csc->kub = 0x0204; + csc->kvb = 0x0000; } +static void tegra_dc_set_csc(struct tegra_dc *dc, struct tegra_dc_csc *csc) +{ + tegra_dc_writel(dc, csc->yof, DC_WIN_CSC_YOF); + tegra_dc_writel(dc, csc->kyrgb, DC_WIN_CSC_KYRGB); + tegra_dc_writel(dc, csc->kur, DC_WIN_CSC_KUR); + tegra_dc_writel(dc, csc->kvr, DC_WIN_CSC_KVR); + tegra_dc_writel(dc, csc->kug, DC_WIN_CSC_KUG); + tegra_dc_writel(dc, csc->kvg, DC_WIN_CSC_KVG); + tegra_dc_writel(dc, csc->kub, DC_WIN_CSC_KUB); + tegra_dc_writel(dc, csc->kvb, DC_WIN_CSC_KVB); +} + +int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx) +{ + 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_csc(dc, &dc->windows[win_idx].csc); + + mutex_unlock(&dc->lock); + + return 0; +} +EXPORT_SYMBOL(tegra_dc_update_csc); + static void tegra_dc_set_scaling_filter(struct tegra_dc *dc) { unsigned i; @@ -2074,7 +2106,8 @@ static void tegra_dc_init(struct tegra_dc *dc) for (i = 0; i < DC_N_WINDOWS; i++) { tegra_dc_writel(dc, WINDOW_A_SELECT << i, DC_CMD_DISPLAY_WINDOW_HEADER); - tegra_dc_set_csc(dc); + tegra_dc_init_csc_defaults(&dc->windows[i].csc); + tegra_dc_set_csc(dc, &dc->windows[i].csc); 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 788593ea0dcf..b0e8c38626a6 100644 --- a/drivers/video/tegra/dc/ext/dev.c +++ b/drivers/video/tegra/dc/ext/dev.c @@ -439,6 +439,43 @@ fail_pin: return ret; } +static int tegra_dc_ext_set_csc(struct tegra_dc_ext_user *user, + struct tegra_dc_ext_csc *new_csc) +{ + unsigned int index = new_csc->win_index; + struct tegra_dc *dc = user->ext->dc; + struct tegra_dc_ext_win *ext_win; + struct tegra_dc_csc *csc; + + if (index >= DC_N_WINDOWS) + return -EINVAL; + + ext_win = &user->ext->win[index]; + csc = &dc->windows[index].csc; + + mutex_lock(&ext_win->lock); + + if (ext_win->user != user) { + mutex_unlock(&ext_win->lock); + return -EACCES; + } + + csc->yof = new_csc->yof; + csc->kyrgb = new_csc->kyrgb; + csc->kur = new_csc->kur; + csc->kvr = new_csc->kvr; + csc->kug = new_csc->kug; + csc->kvg = new_csc->kvg; + csc->kub = new_csc->kub; + csc->kvb = new_csc->kvb; + + tegra_dc_update_csc(dc, index); + + mutex_unlock(&ext_win->lock); + + return 0; +} + static long tegra_dc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -493,6 +530,16 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd, return tegra_dc_ext_set_cursor(user, &args); } + case TEGRA_DC_EXT_SET_CSC: + { + struct tegra_dc_ext_csc args; + + if (copy_from_user(&args, user_arg, sizeof(args))) + return -EFAULT; + + return tegra_dc_ext_set_csc(user, &args); + } + default: return -EINVAL; } diff --git a/include/video/tegra_dc_ext.h b/include/video/tegra_dc_ext.h index 2e89a12add3e..a7c455ce8b4d 100644 --- a/include/video/tegra_dc_ext.h +++ b/include/video/tegra_dc_ext.h @@ -130,6 +130,37 @@ struct tegra_dc_ext_cursor { __u32 flags; }; +/* + * Color conversion is performed as follows: + * + * r = sat(kyrgb * sat(y + yof) + kur * u + kvr * v) + * g = sat(kyrgb * sat(y + yof) + kug * u + kvg * v) + * b = sat(kyrgb * sat(y + yof) + kub * u + kvb * v) + * + * Coefficients should be specified as fixed-point values; the exact format + * varies for each coefficient. + * The format for each coefficient is listed below with the syntax: + * - A "s." prefix means that the coefficient has a sign bit (twos complement). + * - The first number is the number of bits in the integer component (not + * including the optional sign bit). + * - The second number is the number of bits in the fractional component. + * + * All three fields should be tightly packed, justified to the LSB of the + * 16-bit value. For example, the "s.2.8" value should be packed as: + * (MSB) 5 bits of 0, 1 bit of sign, 2 bits of integer, 8 bits of frac (LSB) + */ +struct tegra_dc_ext_csc { + __u32 win_index; + __u16 yof; /* s.7.0 */ + __u16 kyrgb; /* 2.8 */ + __u16 kur; /* s.2.8 */ + __u16 kvr; /* s.2.8 */ + __u16 kug; /* s.1.8 */ + __u16 kvg; /* s.1.8 */ + __u16 kub; /* s.2.8 */ + __u16 kvb; /* s.2.8 */ +}; + #define TEGRA_DC_EXT_SET_NVMAP_FD \ _IOW('D', 0x00, __s32) @@ -150,6 +181,9 @@ struct tegra_dc_ext_cursor { #define TEGRA_DC_EXT_SET_CURSOR \ _IOW('D', 0x07, struct tegra_dc_ext_cursor) +#define TEGRA_DC_EXT_SET_CSC \ + _IOW('D', 0x08, struct tegra_dc_ext_csc) + enum tegra_dc_ext_control_output_type { TEGRA_DC_EXT_DSI, |