summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Schalig <dschalig@nvidia.com>2011-10-25 19:28:24 +0900
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:35 -0800
commitf80e81610f4e2e3a9051b465a9176ac70f6913f1 (patch)
tree87e9e17de05b511dc97b6c1c9a0fb3b92ee69732
parentc48cfa76bc9c61ae99b663519075283bd8e290c1 (diff)
video: tegra: dc: support global fbdev gamma table
Add support to set a global gamma correction table via fbdev cmap API. The 3 Tegra DC windows have their own local gamma tables, which can either override or alter the global table. Bug 868060 Change-Id: I0be1c5e4afa8fd8c010b772c7808c883c0848ab4 Reviewed-on: http://git-master/r/60201 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: R7e613b1c8ac469242172bd81db9dfba25176e0c3
-rw-r--r--drivers/video/tegra/dc/dc.c80
-rw-r--r--drivers/video/tegra/dc/dc_priv.h1
-rw-r--r--drivers/video/tegra/fb.c35
-rw-r--r--include/video/tegra_dc_ext.h6
4 files changed, 82 insertions, 40 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index b1c4413..4f8da4e 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -672,29 +672,49 @@ static void tegra_dc_init_lut_defaults(struct tegra_dc_lut *lut)
lut->r[i] = lut->g[i] = lut->b[i] = (u8)i;
}
-static int tegra_dc_lut_is_defaults(struct tegra_dc_lut *lut)
+static int tegra_dc_loop_lut(struct tegra_dc *dc,
+ struct tegra_dc_win *win,
+ int(*lambda)(struct tegra_dc *dc, int i, u32 rgb))
{
- unsigned int i;
- for (i = 0; i < 256; i++)
- if ((lut->r[i] != i) || (lut->g[i] != i) || (lut->b[i] != i))
+ struct tegra_dc_lut *lut = &win->lut;
+ struct tegra_dc_lut *global_lut = &dc->fb_lut;
+ int i;
+ for (i = 0; i < 256; i++) {
+
+ u32 r = (u32)lut->r[i];
+ u32 g = (u32)lut->g[i];
+ u32 b = (u32)lut->b[i];
+
+ if (!(win->ppflags & TEGRA_WIN_PPFLAG_CP_FBOVERRIDE)) {
+ r = (u32)global_lut->r[r];
+ g = (u32)global_lut->g[g];
+ b = (u32)global_lut->b[b];
+ }
+
+ if (!lambda(dc, i, r | (g<<8) | (b<<16)))
return 0;
+ }
return 1;
}
-static void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win* win)
+static int tegra_dc_lut_isdefaults_lambda(struct tegra_dc *dc, int i, u32 rgb)
{
- unsigned int i;
- unsigned long val;
- struct tegra_dc_lut *lut = &win->lut;
+ if (rgb != (i | (i<<8) | (i<<16)))
+ return 0;
+ return 1;
+}
- for (i = 0; i < 256; 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));
- }
+static int tegra_dc_set_lut_setreg_lambda(struct tegra_dc *dc, int i, u32 rgb)
+{
+ tegra_dc_writel(dc, rgb, DC_WIN_COLOR_PALETTE(i));
+ return 1;
+}
+
+static void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win* win)
+{
+ unsigned long val = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
- val = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
+ tegra_dc_loop_lut(dc, win, tegra_dc_set_lut_setreg_lambda);
if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
val |= CP_ENABLE;
@@ -704,7 +724,7 @@ static void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win* win)
tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
}
-int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int fboveride)
+static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr)
{
struct tegra_dc_win *win = &dc->windows[win_idx];
@@ -715,16 +735,16 @@ int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int fboveride)
return -EFAULT;
}
- if (!tegra_dc_lut_is_defaults(&win->lut))
+ if (fbovr > 0)
+ win->ppflags |= TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
+ else if (fbovr == 0)
+ win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
+
+ if (!tegra_dc_loop_lut(dc, win, tegra_dc_lut_isdefaults_lambda))
win->ppflags |= TEGRA_WIN_PPFLAG_CP_ENABLE;
else
win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_ENABLE;
- if (fboveride)
- win->ppflags |= TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
- else
- win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
-
tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
DC_CMD_DISPLAY_WINDOW_HEADER);
@@ -734,6 +754,20 @@ int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int fboveride)
return 0;
}
+
+int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int fboveride)
+{
+ if (win_idx > -1)
+ return tegra_dc_update_winlut(dc, win_idx, fboveride);
+
+ for (win_idx = 0; win_idx < DC_N_WINDOWS; win_idx++) {
+ int err = tegra_dc_update_winlut(dc, win_idx, fboveride);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
EXPORT_SYMBOL(tegra_dc_update_lut);
static void tegra_dc_set_scaling_filter(struct tegra_dc *dc)
@@ -2656,6 +2690,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
#endif
INIT_WORK(&dc->vblank_work, tegra_dc_vblank);
+ tegra_dc_init_lut_defaults(&dc->fb_lut);
+
dc->n_windows = DC_N_WINDOWS;
for (i = 0; i < dc->n_windows; i++) {
struct tegra_dc_win *win = &dc->windows[i];
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 5eaa8be..83f26b8 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -132,6 +132,7 @@ struct tegra_dc {
#ifdef CONFIG_DEBUG_FS
struct dentry *debugdir;
#endif
+ struct tegra_dc_lut fb_lut;
};
static inline void tegra_dc_io_start(struct tegra_dc *dc)
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index 7b01f1e..44be010 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -146,27 +146,28 @@ static int tegra_fb_set_par(struct fb_info *info)
return 0;
}
-static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info *info)
+static int tegra_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
{
- struct fb_var_screeninfo *var = &info->var;
+ struct tegra_fb_info *tegra_fb = info->par;
+ struct tegra_dc *dc = tegra_fb->win->dc;
+ int i;
+ u16 *red = cmap->red;
+ u16 *green = cmap->green;
+ u16 *blue = cmap->blue;
+ int start = cmap->start;
+
+ if (((unsigned)start > 255) || ((start + cmap->len) > 255))
+ return -EINVAL;
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
- u32 v;
-
- if (regno >= 16)
- return -EINVAL;
-
- red = (red >> (16 - info->var.red.length));
- green = (green >> (16 - info->var.green.length));
- blue = (blue >> (16 - info->var.blue.length));
-
- v = (red << var->red.offset) |
- (green << var->green.offset) |
- (blue << var->blue.offset);
+ for (i = 0; i < cmap->len; i++) {
+ dc->fb_lut.r[start+i] = *red++ >> 8;
+ dc->fb_lut.g[start+i] = *green++ >> 8;
+ dc->fb_lut.b[start+i] = *blue++ >> 8;
+ }
- ((u32 *)info->pseudo_palette)[regno] = v;
+ tegra_dc_update_lut(dc, -1, -1);
}
return 0;
@@ -302,7 +303,7 @@ static struct fb_ops tegra_fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = tegra_fb_check_var,
.fb_set_par = tegra_fb_set_par,
- .fb_setcolreg = tegra_fb_setcolreg,
+ .fb_setcmap = tegra_fb_setcmap,
.fb_blank = tegra_fb_blank,
.fb_pan_display = tegra_fb_pan_display,
.fb_fillrect = tegra_fb_fillrect,
diff --git a/include/video/tegra_dc_ext.h b/include/video/tegra_dc_ext.h
index 6c1a4e3..380b026 100644
--- a/include/video/tegra_dc_ext.h
+++ b/include/video/tegra_dc_ext.h
@@ -174,6 +174,8 @@ struct tegra_dc_ext_csc {
* 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)
*
+ * To just update flags, set len to 0.
+ *
* Current Tegra DC hardware supports 8-bit per channel to 8-bit per channel,
* and each hardware window (overlay) uses its own lookup table.
*
@@ -188,7 +190,9 @@ struct tegra_dc_ext_lut {
__u16 *b; /* array of 16-bit blue values, 0 to reset */
};
-/* tegra_dc_ext_lut.flags - override fb device palette. Default is multiply. */
+/* tegra_dc_ext_lut.flags - override global fb device lookup table.
+ * Default behaviour is double-lookup.
+ */
#define TEGRA_DC_EXT_LUT_FLAGS_FBOVERRIDE 0x01
#define TEGRA_DC_EXT_FLAGS_ENABLED 1