From f80e81610f4e2e3a9051b465a9176ac70f6913f1 Mon Sep 17 00:00:00 2001 From: David Schalig Date: Tue, 25 Oct 2011 19:28:24 +0900 Subject: 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 Tested-by: Varun Colbert Rebase-Id: R7e613b1c8ac469242172bd81db9dfba25176e0c3 --- drivers/video/tegra/dc/dc.c | 80 +++++++++++++++++++++++++++++----------- drivers/video/tegra/dc/dc_priv.h | 1 + drivers/video/tegra/fb.c | 35 +++++++++--------- 3 files changed, 77 insertions(+), 39 deletions(-) (limited to 'drivers/video/tegra') diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index b1c441390ce4..4f8da4e4735e 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 5eaa8be7dafd..83f26b8dd543 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 7b01f1ef72a2..44be01013beb 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, -- cgit v1.2.3