summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h15
-rw-r--r--drivers/video/tegra/dc/dc.c53
-rw-r--r--drivers/video/tegra/dc/ext/dev.c47
-rw-r--r--include/video/tegra_dc_ext.h34
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,