diff options
author | Danny Nold <dannynold@freescale.com> | 2011-08-11 20:07:59 -0500 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-07-20 13:16:15 +0800 |
commit | 44ddcb10254d5ed3978ccaea1f9801063e1fd54d (patch) | |
tree | 231c3d04e98068628cb04d1758b19757f8613fc5 | |
parent | 6d6fc0d96fcd7bae184533f496872cf84fab4c24 (diff) |
ENGR00156420 - EPDC/PxP: Add support for color map
- Add support for 8-bit grayscale colormaps to be used
during EPDC update processing
- Add support in PxP for programming of colormaps
Signed-off-by: Danny Nold <dannynold@freescale.com>
-rw-r--r-- | drivers/dma/pxp/pxp_dma.c | 38 | ||||
-rw-r--r-- | drivers/video/mxc/mxc_epdc_fb.c | 140 | ||||
-rw-r--r-- | include/linux/mxcfb.h | 1 | ||||
-rw-r--r-- | include/linux/pxp_dma.h | 3 |
4 files changed, 142 insertions, 40 deletions
diff --git a/drivers/dma/pxp/pxp_dma.c b/drivers/dma/pxp/pxp_dma.c index de3ba395e9da..eb5b4fb60306 100644 --- a/drivers/dma/pxp/pxp_dma.c +++ b/drivers/dma/pxp/pxp_dma.c @@ -20,6 +20,7 @@ * Based on STMP378X PxP driver * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved. */ + #include <linux/dma-mapping.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -429,9 +430,16 @@ static void pxp_set_lut(struct pxps *pxp) int lut_op = pxp_conf->proc_data.lut_transform; u32 reg_val; int i; + bool use_cmap = (lut_op & PXP_LUT_USE_CMAP) ? true : false; + u8 *cmap = pxp_conf->proc_data.lut_map; + u32 entry_src; - /* If LUT already configured as needed, return */ - if (pxp->lut_state == lut_op) + /* + * If LUT already configured as needed, return... + * Unless CMAP is needed and it has been updated. + */ + if ((pxp->lut_state == lut_op) && + !(use_cmap && pxp_conf->proc_data.lut_map_updated)) return; if (lut_op == PXP_LUT_NONE) { @@ -449,11 +457,12 @@ static void pxp_set_lut(struct pxps *pxp) reg_val = __raw_readl(pxp->base + HW_PXP_LUT_CTRL) & BM_PXP_LUT_CTRL_ADDR; - reg_val = (reg_val < 0x80) ? 0x00 : 0xFF; + entry_src = use_cmap ? cmap[i] : reg_val; + reg_val = (entry_src < 0x80) ? 0x00 : 0xFF; reg_val = ~reg_val & BM_PXP_LUT_DATA; __raw_writel(reg_val, pxp->base + HW_PXP_LUT); } - } else if (lut_op == PXP_LUT_INVERT) { + } else if ((lut_op & PXP_LUT_INVERT) != 0) { /* Fill out LUT table with 8-bit inverted values */ /* Initialize LUT address to 0 and clear bypass bit */ @@ -464,10 +473,11 @@ static void pxp_set_lut(struct pxps *pxp) reg_val = __raw_readl(pxp->base + HW_PXP_LUT_CTRL) & BM_PXP_LUT_CTRL_ADDR; - reg_val = ~reg_val & BM_PXP_LUT_DATA; + entry_src = use_cmap ? cmap[i] : reg_val; + reg_val = ~entry_src & BM_PXP_LUT_DATA; __raw_writel(reg_val, pxp->base + HW_PXP_LUT); } - } else if (lut_op == PXP_LUT_BLACK_WHITE) { + } else if ((lut_op & PXP_LUT_BLACK_WHITE) != 0) { /* Fill out LUT table with 8-bit monochromized values */ /* Initialize LUT address to 0 and clear bypass bit */ @@ -478,8 +488,20 @@ static void pxp_set_lut(struct pxps *pxp) reg_val = __raw_readl(pxp->base + HW_PXP_LUT_CTRL) & BM_PXP_LUT_CTRL_ADDR; - reg_val = (reg_val < 0x80) ? 0xFF : 0x00; - reg_val = ~reg_val & BM_PXP_LUT_DATA; + entry_src = use_cmap ? cmap[i] : reg_val; + reg_val = (entry_src < 0x80) ? 0x00 : 0xFF; + reg_val = reg_val & BM_PXP_LUT_DATA; + __raw_writel(reg_val, pxp->base + HW_PXP_LUT); + } + } else if (use_cmap) { + /* Fill out LUT table using colormap values */ + + /* Initialize LUT address to 0 and clear bypass bit */ + __raw_writel(0, pxp->base + HW_PXP_LUT_CTRL); + + /* LUT address pointer auto-increments after each data write */ + for (i = 0; i < 256; i++) { + reg_val = cmap[i] & BM_PXP_LUT_DATA; __raw_writel(reg_val, pxp->base + HW_PXP_LUT); } } diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c index 3b5c34ac39d7..6e7ac35882d9 100644 --- a/drivers/video/mxc/mxc_epdc_fb.c +++ b/drivers/video/mxc/mxc_epdc_fb.c @@ -942,9 +942,11 @@ static void epdc_init_sequence(struct mxc_epdc_fb_data *fb_data) epdc_init_settings(fb_data); __raw_writel(fb_data->waveform_buffer_phys, EPDC_WVADDR); __raw_writel(fb_data->working_buffer_phys, EPDC_WB_ADDR); + fb_data->in_init = true; epdc_powerup(fb_data); draw_mode0(fb_data); epdc_powerdown(fb_data); + fb_data->updates_active = false; } static int mxc_epdc_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) @@ -977,51 +979,100 @@ static int mxc_epdc_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) return 0; } +static inline u_int _chan_to_field(u_int chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + static int mxc_epdc_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { - if (regno >= 256) /* no. of hw registers */ - return 1; + unsigned int val; + int ret = 1; + /* - * Program hardware... do anything you want with transp + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. */ - - /* grayscale works only partially under directcolor */ - if (info->var.grayscale) { - /* grayscale = 0.30*R + 0.59*G + 0.11*B */ - red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; - } - -#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: - case FB_VISUAL_PSEUDOCOLOR: - red = CNVT_TOHW(red, info->var.red.length); - green = CNVT_TOHW(green, info->var.green.length); - blue = CNVT_TOHW(blue, info->var.blue.length); - transp = CNVT_TOHW(transp, info->var.transp.length); + /* + * 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = info->pseudo_palette; + + val = _chan_to_field(red, &info->var.red); + val |= _chan_to_field(green, &info->var.green); + val |= _chan_to_field(blue, &info->var.blue); + + pal[regno] = val; + ret = 0; + } break; - case FB_VISUAL_DIRECTCOLOR: - red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ - green = CNVT_TOHW(green, 8); - blue = CNVT_TOHW(blue, 8); - /* hey, there is bug in transp handling... */ - transp = CNVT_TOHW(transp, 8); + + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: break; } -#undef CNVT_TOHW - /* Truecolor has hardware independent palette */ - if (info->fix.visual == FB_VISUAL_TRUECOLOR) { - if (regno >= 16) + return ret; +} + +static int mxc_epdc_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info) +{ + int count, index, r; + u16 *red, *green, *blue, *transp; + u16 trans = 0xffff; + struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info; + int i; + + dev_dbg(fb_data->dev, "setcmap\n"); + + if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) { + /* Only support an 8-bit, 256 entry lookup */ + if (cmap->len != 256) return 1; - ((u32 *) (info->pseudo_palette))[regno] = - (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset) | - (transp << info->var.transp.offset); + mxc_epdc_fb_flush_updates(fb_data); + + mutex_lock(&fb_data->pxp_mutex); + /* + * Store colormap in pxp_conf structure for later transmit + * to PxP during update process to convert gray pixels. + * + * Since red=blue=green for pseudocolor visuals, we can + * just use red values. + */ + for (i = 0; i < 256; i++) + fb_data->pxp_conf.proc_data.lut_map[i] = cmap->red[i] & 0xFF; + + fb_data->pxp_conf.proc_data.lut_map_updated = true; + + mutex_unlock(&fb_data->pxp_mutex); + } else { + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + index = cmap->start; + + for (count = 0; count < cmap->len; count++) { + if (transp) + trans = *transp++; + r = mxc_epdc_fb_setcolreg(index++, *red++, *green++, *blue++, + trans, info); + if (r != 0) + return r; + } } + return 0; } @@ -1798,6 +1849,10 @@ static int epdc_process_update(struct update_data_list *upd_data_list, if (upd_desc_list->upd_data.flags & EPDC_FLAG_FORCE_MONOCHROME) fb_data->pxp_conf.proc_data.lut_transform |= PXP_LUT_BLACK_WHITE; + if (upd_desc_list->upd_data.flags & EPDC_FLAG_USE_CMAP) { + fb_data->pxp_conf.proc_data.lut_transform |= + PXP_LUT_USE_CMAP; + } /* * Toggle inversion processing if 8-bit @@ -2697,6 +2752,10 @@ static void mxc_epdc_fb_deferred_io(struct fb_info *info, void mxc_epdc_fb_flush_updates(struct mxc_epdc_fb_data *fb_data) { int ret; + + if (fb_data->in_init) + return; + /* Grab queue lock to prevent any new updates from being submitted */ mutex_lock(&fb_data->queue_mutex); @@ -2838,6 +2897,7 @@ static struct fb_ops mxc_epdc_fb_ops = { .owner = THIS_MODULE, .fb_check_var = mxc_epdc_fb_check_var, .fb_set_par = mxc_epdc_fb_set_par, + .fb_setcmap = mxc_epdc_fb_setcmap, .fb_setcolreg = mxc_epdc_fb_setcolreg, .fb_pan_display = mxc_epdc_fb_pan_display, .fb_ioctl = mxc_epdc_fb_ioctl, @@ -3292,7 +3352,6 @@ static void draw_mode0(struct mxc_epdc_fb_data *fb_data) epdc_working_buf_intr(true); epdc_lut_complete_intr(0, true); - fb_data->in_init = true; /* Use unrotated (native) width/height */ if ((screeninfo->rotate == FB_ROTATE_CW) || @@ -3932,6 +3991,7 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev) proc_data->bgcolor = 0; proc_data->overlay_state = 0; proc_data->lut_transform = PXP_LUT_NONE; + proc_data->lut_map = NULL; /* * We initially configure PxP for RGB->YUV conversion, @@ -3973,6 +4033,18 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev) pxp_conf->out_param.height = fb_data->info.var.yres; pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_GREY; + /* Initialize color map for conversion of 8-bit gray pixels */ + fb_data->pxp_conf.proc_data.lut_map = kmalloc(256, GFP_KERNEL); + if (fb_data->pxp_conf.proc_data.lut_map == NULL) { + dev_err(&pdev->dev, "Can't allocate mem for lut map!\n"); + ret = -ENOMEM; + goto out_dmaengine; + } + for (i = 0; i < 256; i++) + fb_data->pxp_conf.proc_data.lut_map[i] = i; + + fb_data->pxp_conf.proc_data.lut_map_updated = true; + /* * Ensure this is set to NULL here...we will initialize pxp_chan * later in our thread. @@ -4361,6 +4433,10 @@ static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat) return ret ? : -ETIMEDOUT; } + if ((fb_data->pxp_conf.proc_data.lut_transform & EPDC_FLAG_USE_CMAP) && + fb_data->pxp_conf.proc_data.lut_map_updated) + fb_data->pxp_conf.proc_data.lut_map_updated = false; + *hist_stat = to_tx_desc(fb_data->txd)->hist_status; dma_release_channel(&fb_data->pxp_chan->dma_chan); fb_data->pxp_chan = NULL; diff --git a/include/linux/mxcfb.h b/include/linux/mxcfb.h index 817bda95c353..3bc7c05310db 100644 --- a/include/linux/mxcfb.h +++ b/include/linux/mxcfb.h @@ -86,6 +86,7 @@ struct mxcfb_rect { #define EPDC_FLAG_ENABLE_INVERSION 0x01 #define EPDC_FLAG_FORCE_MONOCHROME 0x02 +#define EPDC_FLAG_USE_CMAP 0x04 #define EPDC_FLAG_USE_ALT_BUFFER 0x100 #define FB_POWERDOWN_DISABLE -1 diff --git a/include/linux/pxp_dma.h b/include/linux/pxp_dma.h index f78e56003753..867afbe084e7 100644 --- a/include/linux/pxp_dma.h +++ b/include/linux/pxp_dma.h @@ -78,6 +78,7 @@ typedef unsigned char bool; #define PXP_LUT_NONE 0x0 #define PXP_LUT_INVERT 0x1 #define PXP_LUT_BLACK_WHITE 0x2 +#define PXP_LUT_USE_CMAP 0x4 #define NR_PXP_VIRT_CHANNEL 16 @@ -150,6 +151,8 @@ struct pxp_proc_data { /* LUT transformation on Y data */ int lut_transform; + u8 *lut_map; /* 256 entries */ + bool lut_map_updated; /* Map recently changed */ }; struct pxp_config_data { |