All of lore.kernel.org
 help / color / mirror / Atom feed
* RE: [PATCH 5/9] Add i.MX5 framebuffer driver
       [not found] <33F32152BE7EC740BC2C838D2836AC8704A957@039-SN1MPN1-002.039d.mgd.msft.net>
@ 2010-12-14 12:38   ` Chen Jie-B02280
  0 siblings, 0 replies; 37+ messages in thread
From: Chen Jie-B02280 @ 2010-12-14 12:38 UTC (permalink / raw)
  To: s.hauer
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Zhang Lily-R58066,
	arnaud.patard

[-- Attachment #1: Type: text/plain, Size: 35014 bytes --]

Hi, Sascha,

Few comments inline with [Jason]

Jason Chen / Chen Jie
NMG / MAD
Freescale Semiconductor (China) Ltd.
2F, Building B, 177#, Bi Bo Rd
Pu Dong New District Shanghai 201203
Tel:     021-28937178
Fax:     021-28937444
E-mail:  Jason.Chen@freescale.com<mailto:Jason.Chen@freescale.com>

From: Jason Chen [mailto:weitway@gmail.com]
Sent: Tuesday, December 14, 2010 3:35 PM
To: Chen Jie-B02280
Subject: Fwd: [PATCH 5/9] Add i.MX5 framebuffer driver


---------- Forwarded message ----------
From: Liu Ying <liu.y.victor@gmail.com<mailto:liu.y.victor@gmail.com>>
Date: 2010/12/12
Subject: Re: [PATCH 5/9] Add i.MX5 framebuffer driver
To: Sascha Hauer <s.hauer@pengutronix.de<mailto:s.hauer@pengutronix.de>>
Cc: linux-arm-kernel@lists.infradead.org<mailto:linux-arm-kernel@lists.infradead.org>, linux-kernel@vger.kernel.org<mailto:linux-kernel@vger.kernel.org>, linux-fbdev@vger.kernel.org<mailto:linux-fbdev@vger.kernel.org>, Zhang Lily-R58066 <r58066@freescale.com<mailto:r58066@freescale.com>>, Arnaud Patard <arnaud.patard@rtp-net.org<mailto:arnaud.patard@rtp-net.org>>


Hello, Sascha,

I have following comments to this patch:
1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
2) ADC is not supported yet in the framebuffer driver, so please
modify this comment:
  > + * Framebuffer Framebuffer Driver for SDC and ADC.
3) 'ipu_dp_set_window_pos()' is called only once in
imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
support to change the overlay framebuffer position. Need a
mechanism/interface for users to change the overlay framebuffer
position.
[Jason] DP-FG should be one fb device, sequence ioctl should be added after it, like global alpha , color key etc.

4) Need to make sure the framebuffer on DP-FG is blanked before the
framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
should be unblanked after the framebuffer on DP-BG is unblanked
5) Need to check the framebuffer on DP-FG doesn't run out of the range
of the framebuffer on DP-BG.
6) I prefer to find the video mode in modedb first, and if we cannot
find the video mode in common video mode data base, we can find a
video mode in custom video mode data base which is defined in platform
data. In this way, we don't need to export common modefb.

Best Regards,
Liu Ying


2010/12/9 Sascha Hauer <s.hauer@pengutronix.de<mailto:s.hauer@pengutronix.de>>:
> This patch adds framebuffer support to the Freescale i.MX SoCs
> equipped with an IPU v3, so far these are the i.MX50/51/53.
>
> This driver has been tested on the i.MX51 babbage board with
> both DVI and analog VGA in different resolutions and color depths.
> It has also been tested on a custom i.MX51 board using a fixed
> resolution panel.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de<mailto:s.hauer@pengutronix.de>>
> ---
>  drivers/video/Kconfig  |   11 +
>  drivers/video/Makefile |    1 +
>  drivers/video/mx5fb.c  |  846 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 858 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/video/mx5fb.c
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 27c1fb4..1901915 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -2236,6 +2236,17 @@ config FB_MX3
>          far only synchronous displays are supported. If you plan to use
>          an LCD display with your i.MX31 system, say Y here.
>
> +config FB_MX5
> +       tristate "MX5 Framebuffer support"
> +       depends on FB && MFD_IMX_IPU_V3
> +       select FB_CFB_FILLRECT
> +       select FB_CFB_COPYAREA
> +       select FB_CFB_IMAGEBLIT
> +       select FB_MODE_HELPERS
> +       help
> +         This is a framebuffer device for the i.MX51 LCD Controller. If you
> +         plan to use an LCD display with your i.MX51 system, say Y here.
> +
>  config FB_BROADSHEET
>        tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
>        depends on FB
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 485e8ed..ad408d2 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043)          += bf54x-lq043fb.o
>  obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
>  obj-$(CONFIG_FB_BFIN_T350MCQB)   += bfin-t350mcqb-fb.o
>  obj-$(CONFIG_FB_MX3)             += mx3fb.o
> +obj-$(CONFIG_FB_MX5)             += mx5fb.o
>  obj-$(CONFIG_FB_DA8XX)           += da8xx-fb.o
>
>  # the test framebuffer is last
> diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
> new file mode 100644
> index 0000000..fd9baf4
> --- /dev/null
> +++ b/drivers/video/mx5fb.c
> @@ -0,0 +1,846 @@
> +/*
> + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + *
> + * Framebuffer Framebuffer Driver for SDC and ADC.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <linux/fb.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/console.h>
> +#include <linux/mfd/imx-ipu-v3.h>
> +#include <asm/uaccess.h>
> +#include <mach/ipu-v3.h>
> +
> +#define DRIVER_NAME "imx-ipuv3-fb"
> +
> +struct imx_ipu_fb_info {
> +       int                     ipu_channel_num;
> +       struct ipu_channel      *ipu_ch;
> +       int                     dc;
> +       int                     ipu_di;
> +       u32                     ipu_di_pix_fmt;
> +       u32                     ipu_in_pix_fmt;
> +
> +       u32                     pseudo_palette[16];
> +
> +       struct ipu_dp           *dp;
> +       struct dmfc_channel     *dmfc;
> +       struct fb_info          *slave;
> +       struct fb_info          *master;
> +       bool                    enabled;
> +};
> +
> +static int imx_ipu_fb_set_fix(struct fb_info *info)
> +{
> +       struct fb_fix_screeninfo *fix = &info->fix;
> +       struct fb_var_screeninfo *var = &info->var;
> +
> +       fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> +       fix->type = FB_TYPE_PACKED_PIXELS;
> +       fix->accel = FB_ACCEL_NONE;
> +       fix->visual = FB_VISUAL_TRUECOLOR;
> +       fix->xpanstep = 1;
> +       fix->ypanstep = 1;
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
> +{
> +       int size;
> +
> +       size = fbi->var.yres_virtual * fbi->fix.line_length;
> +
> +       if (fbi->screen_base) {
> +               if (fbi->fix.smem_len >= size)
> +                       return 0;
> +
> +               dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> +                             fbi->screen_base, fbi->fix.smem_start);
> +       }
> +
> +       fbi->screen_base = dma_alloc_writecombine(fbi->device,
> +                               size,
> +                               (dma_addr_t *)&fbi->fix.smem_start,
> +                               GFP_DMA);
> +       if (fbi->screen_base == 0) {
> +               dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
> +                               fbi->fix.smem_len);
> +               fbi->fix.smem_len = 0;
> +               fbi->fix.smem_start = 0;
> +               return -ENOMEM;
> +       }
> +
> +       fbi->fix.smem_len = size;
> +       fbi->screen_size = fbi->fix.smem_len;
> +
> +       dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
> +               fbi->fix.smem_start, fbi->fix.smem_len);
> +
> +       /* Clear the screen */
> +       memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
> +
> +       return 0;
> +}
> +
> +static void imx_ipu_fb_enable(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       if (mxc_fbi->enabled)
> +               return;
> +
> +       ipu_di_enable(mxc_fbi->ipu_di);
> +       ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> +       ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> +       ipu_dc_enable_channel(mxc_fbi->dc);
> +       ipu_dp_enable_channel(mxc_fbi->dp);
> +       mxc_fbi->enabled = 1;
> +}
> +
> +static void imx_ipu_fb_disable(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       if (!mxc_fbi->enabled)
> +               return;
> +
> +       ipu_dp_disable_channel(mxc_fbi->dp);
> +       ipu_dc_disable_channel(mxc_fbi->dc);
> +       ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> +       ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> +       ipu_di_disable(mxc_fbi->ipu_di);
> +
> +       mxc_fbi->enabled = 0;
> +}
> +
> +static int calc_vref(struct fb_var_screeninfo *var)
> +{
> +       unsigned long htotal, vtotal;
> +
> +       htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
> +       vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
> +
> +       if (!htotal || !vtotal)
> +               return 60;
> +
> +       return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
> +}
> +
> +static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
> +{
> +       return var->xres * var->yres * vref;
> +}
> +
> +static int imx_ipu_fb_set_par(struct fb_info *fbi)
> +{
> +       int ret;
> +       struct ipu_di_signal_cfg sig_cfg;
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       u32 out_pixel_fmt;
> +       int interlaced = 0;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       int enabled = mxc_fbi->enabled;
> +
> +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> +       if (enabled)
> +               imx_ipu_fb_disable(fbi);
> +
> +       fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> +       var->yres_virtual = var->yres;
> +
> +       ret = imx_ipu_fb_map_video_memory(fbi);
> +       if (ret)
> +               return ret;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               sig_cfg.interlaced = 1;
> +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> +               sig_cfg.odd_field_first = 1;
> +       if (var->sync & FB_SYNC_EXT)
> +               sig_cfg.ext_clk = 1;
[Jason] FB_SYNC_EXT has not be used in FSL kernel mainline, it represent SYNC ext, should not be flag of ext clk. Some application for example X-server could not recognize it.

> +       if (var->sync & FB_SYNC_HOR_HIGH_ACT)
> +               sig_cfg.Hsync_pol = 1;
> +       if (var->sync & FB_SYNC_VERT_HIGH_ACT)
> +               sig_cfg.Vsync_pol = 1;
> +       if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
> +               sig_cfg.clk_pol = 1;
> +       if (var->sync & FB_SYNC_DATA_INVERT)
> +               sig_cfg.data_pol = 1;
> +       if (!(var->sync & FB_SYNC_OE_LOW_ACT))
> +               sig_cfg.enable_pol = 1;
> +       if (var->sync & FB_SYNC_CLK_IDLE_EN)
> +               sig_cfg.clkidle_en = 1;
> +
> +       dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
> +               PICOS2KHZ(var->pixclock) / 1000,
> +               PICOS2KHZ(var->pixclock) % 1000);
> +
> +       sig_cfg.width = var->xres;
> +       sig_cfg.height = var->yres;
> +       sig_cfg.pixel_fmt = out_pixel_fmt;
> +       sig_cfg.h_start_width = var->left_margin;
> +       sig_cfg.h_sync_width = var->hsync_len;
> +       sig_cfg.h_end_width = var->right_margin;
> +       sig_cfg.v_start_width = var->upper_margin;
> +       sig_cfg.v_sync_width = var->vsync_len;
> +       sig_cfg.v_end_width = var->lower_margin;
> +       sig_cfg.v_to_h_sync = 0;
> +
> +       if (mxc_fbi->dp) {
> +               ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
> +                               out_pixel_fmt, 1);
> +               if (ret) {
> +                       dev_dbg(fbi->device, "initializing display processor failed with %d\n",
> +                               ret);
> +                       return ret;
> +               }
> +       }
> +
> +       ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->ipu_di, interlaced,
> +                       out_pixel_fmt, fbi->var.xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing display controller failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_di_init_sync_panel(mxc_fbi->ipu_di,
> +                               PICOS2KHZ(var->pixclock) * 1000UL,
> +                               &sig_cfg);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing panel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
> +       var->xoffset = var->yoffset = 0;
> +
> +       if (fbi->var.vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> +                                       mxc_fbi->ipu_in_pix_fmt,
> +                                       var->xres, var->yres,
> +                                       fbi->fix.line_length,
> +                                       IPU_ROTATE_NONE,
> +                                       fbi->fix.smem_start,
> +                                       0,
> +                                       0, 0, interlaced);
> +       if (ret) {
> +               dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
> +       if (ret) {
> +               dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       if (enabled)
> +               imx_ipu_fb_enable(fbi);
> +
> +       return ret;
> +}
> +
> +/*
> + * These are the bitfields for each
> + * display depth that we support.
> + */
> +struct imxfb_rgb {
> +       struct fb_bitfield      red;
> +       struct fb_bitfield      green;
> +       struct fb_bitfield      blue;
> +       struct fb_bitfield      transp;
> +};
> +
> +static struct imxfb_rgb def_rgb_8 = {
> +       .red    = { .offset =  5, .length = 3, },
> +       .green  = { .offset =  2, .length = 3, },
> +       .blue   = { .offset =  0, .length = 2, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_16 = {
> +       .red    = { .offset = 11, .length = 5, },
> +       .green  = { .offset =  5, .length = 6, },
> +       .blue   = { .offset =  0, .length = 5, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_24 = {
> +       .red    = { .offset = 16, .length = 8, },
> +       .green  = { .offset =  8, .length = 8, },
> +       .blue   = { .offset =  0, .length = 8, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_32 = {
> +       .red    = { .offset = 16, .length = 8, },
> +       .green  = { .offset =  8, .length = 8, },
> +       .blue   = { .offset =  0, .length = 8, },
> +       .transp = { .offset = 24, .length = 8, },
> +};
> +
> +/*
> + * Check framebuffer variable parameters and adjust to valid values.
> + *
> + * @param       var      framebuffer variable parameters
> + *
> + * @param       info     framebuffer information pointer
> + */
> +static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> +       struct imxfb_rgb *rgb;
> +
> +       /* we don't support xpan, force xres_virtual to be equal to xres */
> +       var->xres_virtual = var->xres;
> +
> +       if (var->yres_virtual < var->yres)
> +               var->yres_virtual = var->yres;
> +
> +       switch (var->bits_per_pixel) {
> +       case 8:
> +               rgb = &def_rgb_8;
> +               break;
> +       case 16:
> +               rgb = &def_rgb_16;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
> +               break;
> +       case 24:
> +               rgb = &def_rgb_24;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> +               break;
> +       case 32:
> +               rgb = &def_rgb_32;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
> +               break;
> +       default:
> +               var->bits_per_pixel = 24;
> +               rgb = &def_rgb_24;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> +       }
> +
> +       var->red    = rgb->red;
> +       var->green  = rgb->green;
> +       var->blue   = rgb->blue;
> +       var->transp = rgb->transp;
> +
> +       return 0;
> +}
> +
> +static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
> +{
> +       chan &= 0xffff;
> +       chan >>= 16 - bf->length;
> +       return chan << bf->offset;
> +}
> +
> +static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
> +                          u_int trans, struct fb_info *fbi)
> +{
> +       unsigned int val;
> +       int ret = 1;
> +
> +       /*
> +        * If greyscale is true, then we convert the RGB value
> +        * to greyscale no matter what visual we are using.
> +        */
> +       if (fbi->var.grayscale)
> +               red = green = blue = (19595 * red + 38470 * green +
> +                                     7471 * blue) >> 16;
> +       switch (fbi->fix.visual) {
> +       case FB_VISUAL_TRUECOLOR:
> +               /*
> +                * 16-bit True Colour.  We encode the RGB value
> +                * according to the RGB bitfield information.
> +                */
> +               if (regno < 16) {
> +                       u32 *pal = fbi->pseudo_palette;
> +
> +                       val = chan_to_field(red, &fbi->var.red);
> +                       val |= chan_to_field(green, &fbi->var.green);
> +                       val |= chan_to_field(blue, &fbi->var.blue);
> +
> +                       pal[regno] = val;
> +                       ret = 0;
> +               }
> +               break;
> +
> +       case FB_VISUAL_STATIC_PSEUDOCOLOR:
> +       case FB_VISUAL_PSEUDOCOLOR:
> +               break;
> +       }
> +
> +       return ret;
> +}
> +
> +static int imx_ipu_fb_blank(int blank, struct fb_info *info)
> +{
> +       dev_dbg(info->device, "blank = %d\n", blank);
> +
> +       switch (blank) {
> +       case FB_BLANK_POWERDOWN:
> +       case FB_BLANK_VSYNC_SUSPEND:
> +       case FB_BLANK_HSYNC_SUSPEND:
> +       case FB_BLANK_NORMAL:
> +               imx_ipu_fb_disable(info);
> +               break;
> +       case FB_BLANK_UNBLANK:
> +               imx_ipu_fb_enable(info);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> +               struct fb_info *info)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> +       unsigned long base;
> +       int ret;
> +
> +       if (info->var.yoffset == var->yoffset)
> +               return 0;       /* No change, do nothing */
> +
> +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> +       base += info->fix.smem_start;
> +
> +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> +       if (ret)
> +               return ret;
> +
> +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> +               dev_err(info->device,
> +                       "Error updating SDC buf to address=0x%08lX\n", base);
> +       }
[Jason] It's better to enable double -buffer for fb which could avoid tearing issue.

> +
> +       info->var.yoffset = var->yoffset;
> +
> +       return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_ops = {
> +       .owner          = THIS_MODULE,
> +       .fb_set_par     = imx_ipu_fb_set_par,
> +       .fb_check_var   = imx_ipu_fb_check_var,
> +       .fb_setcolreg   = imx_ipu_fb_setcolreg,
> +       .fb_pan_display = imx_ipu_fb_pan_display,
> +       .fb_fillrect    = cfb_fillrect,
> +       .fb_copyarea    = cfb_copyarea,
> +       .fb_imageblit   = cfb_imageblit,
> +       .fb_blank       = imx_ipu_fb_blank,
> +};
> +
> +/*
> + * Overlay functions
> + */
> +static int imx_ipu_fb_enable_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> +       ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> +       ipu_dp_enable_fg(mxc_fbi->dp);
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_disable_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       ipu_dp_disable_fg(mxc_fbi->dp);
> +       ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> +       ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       struct fb_info *fbi_master = mxc_fbi->master;
> +       struct fb_var_screeninfo *var_master = &fbi_master->var;
> +       int ret;
> +       int interlaced = 0;
> +       int enabled = mxc_fbi->enabled;
> +
> +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> +       if (enabled)
> +               imx_ipu_fb_disable_overlay(fbi);
> +
> +       fbi->fix.line_length = var->xres_virtual *
> +                                  var->bits_per_pixel / 8;
> +
> +       ret = imx_ipu_fb_map_video_memory(fbi);
> +       if (ret)
> +               return ret;
> +
> +       ipu_dp_set_window_pos(mxc_fbi->dp, 64, 64);
> +
> +       var->xoffset = var->yoffset = 0;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> +                                       mxc_fbi->ipu_in_pix_fmt,
> +                                       var->xres, var->yres,
> +                                       fbi->fix.line_length,
> +                                       IPU_ROTATE_NONE,
> +                                       fbi->fix.smem_start,
> +                                       0,
> +                                       0, 0, interlaced);
> +       if (ret) {
> +               dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
> +       if (ret) {
> +               dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       if (enabled)
> +               imx_ipu_fb_enable_overlay(fbi);
> +
> +       return ret;
> +}
> +
> +static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
> +{
> +       dev_dbg(fbi->device, "blank = %d\n", blank);
> +
> +       switch (blank) {
> +       case FB_BLANK_POWERDOWN:
> +       case FB_BLANK_VSYNC_SUSPEND:
> +       case FB_BLANK_HSYNC_SUSPEND:
> +       case FB_BLANK_NORMAL:
> +               imx_ipu_fb_disable_overlay(fbi);
> +               break;
> +       case FB_BLANK_UNBLANK:
> +               imx_ipu_fb_enable_overlay(fbi);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_overlay_ops = {
> +       .owner          = THIS_MODULE,
> +       .fb_set_par     = imx_ipu_fb_set_par_overlay,
> +       .fb_check_var   = imx_ipu_fb_check_var,
> +       .fb_setcolreg   = imx_ipu_fb_setcolreg,
> +       .fb_pan_display = imx_ipu_fb_pan_display,
> +       .fb_fillrect    = cfb_fillrect,
> +       .fb_copyarea    = cfb_copyarea,
> +       .fb_imageblit   = cfb_imageblit,
> +       .fb_blank       = imx_ipu_fb_blank_overlay,
> +};
> +
> +static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
> +{
> +       struct fb_info *fbi;
> +       struct imx_ipu_fb_info *mxc_fbi;
> +
> +       fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
> +       if (!fbi)
> +               return NULL;
> +
> +       BUG_ON(fbi->par == NULL);
> +       mxc_fbi = fbi->par;
> +
> +       fbi->var.activate = FB_ACTIVATE_NOW;
> +
> +       fbi->fbops = ops;
> +       fbi->flags = FBINFO_FLAG_DEFAULT;
> +       fbi->pseudo_palette = mxc_fbi->pseudo_palette;
> +
> +       fb_alloc_cmap(&fbi->cmap, 16, 0);
> +
> +       return fbi;
> +}
> +
> +static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
> +               struct fb_info *fbi_master, int ipu_channel)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> +       struct fb_info *ovlfbi;
> +       struct imx_ipu_fb_info *ovl_mxc_fbi;
> +       int ret;
> +
> +       ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
> +       if (!ovlfbi)
> +               return -ENOMEM;
> +
> +       ovl_mxc_fbi = ovlfbi->par;
> +       ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
> +       ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
> +       ovl_mxc_fbi->ipu_di = -1;
> +       ovl_mxc_fbi->dp = mxc_fbi_master->dp;
> +       ovl_mxc_fbi->master = fbi_master;
> +       mxc_fbi_master->slave = ovlfbi;
> +
> +       ovlfbi->var.xres = 240;
> +       ovlfbi->var.yres = 320;
> +       ovlfbi->var.yres_virtual = ovlfbi->var.yres;
> +       ovlfbi->var.xres_virtual = ovlfbi->var.xres;
> +       imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
> +       imx_ipu_fb_set_fix(ovlfbi);
> +
> +       ret = register_framebuffer(ovlfbi);
> +       if (ret) {
> +               framebuffer_release(ovlfbi);
> +               return ret;
> +       }
> +
> +       ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 1, 0x80, 1);
> +       ipu_dp_set_color_key(ovl_mxc_fbi->dp, 0, 0);
> +
> +       imx_ipu_fb_set_par_overlay(ovlfbi);
> +
> +       return 0;
> +}
> +
> +static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
> +               struct fb_info *fbi_master, int ipu_channel)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> +       struct fb_info *ovlfbi = mxc_fbi_master->slave;
> +       struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
> +
> +       imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
> +
> +       unregister_framebuffer(ovlfbi);
> +
> +       ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
> +       ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
> +       ipu_dmfc_put(ovl_mxc_fbi->dmfc);
> +
> +       framebuffer_release(ovlfbi);
> +}
> +
> +static int imx_ipu_fb_find_mode(struct fb_info *fbi)
> +{
> +       int ret;
> +       struct fb_videomode *mode_array;
> +       struct fb_modelist *modelist;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       int i = 0;
> +
> +       list_for_each_entry(modelist, &fbi->modelist, list)
> +               i++;
> +
> +       mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
> +       if (!mode_array)
> +               return -ENOMEM;
> +
> +       i = 0;
> +       list_for_each_entry(modelist, &fbi->modelist, list)
> +               mode_array[i++] = modelist->mode;
> +
> +       ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
> +       if (ret == 0)
> +               return -EINVAL;
> +
> +       dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
> +                       var->xres, var->yres, var->bits_per_pixel,
> +                       var->hsync_len, var->left_margin, var->right_margin,
> +                       var->vsync_len, var->upper_margin, var->lower_margin);
> +
> +       kfree(mode_array);
> +
> +       return 0;
> +}
> +
> +static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
> +{
> +       struct fb_info *fbi;
> +       struct imx_ipu_fb_info *mxc_fbi;
> +       struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> +       int ret = 0, i;
> +
> +       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> +
> +       fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
> +       if (!fbi)
> +               return -ENOMEM;
> +
> +       mxc_fbi = fbi->par;
> +
> +       mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
> +       mxc_fbi->dc = plat_data->dc_channel;
> +       mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
> +       mxc_fbi->ipu_di = pdev->id;
> +
> +       mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
> +       if (IS_ERR(mxc_fbi->ipu_ch)) {
> +               ret = PTR_ERR(mxc_fbi->ipu_ch);
> +               goto failed_request_ipu;
> +       }
> +
> +       mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
> +       if (IS_ERR(mxc_fbi->ipu_ch)) {
> +               ret = PTR_ERR(mxc_fbi->ipu_ch);
> +               goto failed_request_dmfc;
> +       }
> +
> +       if (plat_data->dp_channel >= 0) {
> +               mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
> +               if (IS_ERR(mxc_fbi->dp)) {
> +                       ret = PTR_ERR(mxc_fbi->ipu_ch);
> +                       goto failed_request_dp;
> +               }
> +       }
> +
> +       fbi->var.yres_virtual = fbi->var.yres;
> +
> +       INIT_LIST_HEAD(&fbi->modelist);
> +       for (i = 0; i < plat_data->num_modes; i++)
> +               fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
> +
> +       if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
> +               for (i = 0; i < num_fb_modes; i++)
> +                       fb_add_videomode(&fb_modes[i], &fbi->modelist);
> +       }
> +
> +       imx_ipu_fb_find_mode(fbi);
> +
> +       imx_ipu_fb_check_var(&fbi->var, fbi);
> +       imx_ipu_fb_set_fix(fbi);
> +       ret = register_framebuffer(fbi);
> +       if (ret < 0)
> +               goto failed_register;
> +
> +       imx_ipu_fb_set_par(fbi);
> +       imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
> +
> +       if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> +               imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> +       platform_set_drvdata(pdev, fbi);
> +
> +       return 0;
> +
> +failed_register:
> +       if (plat_data->dp_channel >= 0)
> +               ipu_dp_put(mxc_fbi->dp);
> +failed_request_dp:
> +       ipu_dmfc_put(mxc_fbi->dmfc);
> +failed_request_dmfc:
> +       ipu_idmac_put(mxc_fbi->ipu_ch);
> +failed_request_ipu:
> +       fb_dealloc_cmap(&fbi->cmap);
> +       framebuffer_release(fbi);
> +
> +       return ret;
> +}
> +
> +static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
> +{
> +       struct fb_info *fbi = platform_get_drvdata(pdev);
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> +
> +       if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> +               imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> +       imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
> +
> +       dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> +                             fbi->screen_base, fbi->fix.smem_start);
> +
> +       if (&fbi->cmap)
> +               fb_dealloc_cmap(&fbi->cmap);
> +
> +       unregister_framebuffer(fbi);
> +
> +       if (plat_data->dp_channel >= 0)
> +               ipu_dp_put(mxc_fbi->dp);
> +       ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
> +       ipu_dmfc_put(mxc_fbi->dmfc);
> +       ipu_idmac_put(mxc_fbi->ipu_ch);
> +
> +       framebuffer_release(fbi);
> +
> +       return 0;
> +}
> +
> +static struct platform_driver imx_ipu_fb_driver = {
> +       .driver = {
> +               .name = DRIVER_NAME,
> +       },
> +       .probe = imx_ipu_fb_probe,
> +       .remove = __devexit_p(imx_ipu_fb_remove),
> +};
> +
> +static int __init imx_ipu_fb_init(void)
> +{
> +       return platform_driver_register(&imx_ipu_fb_driver);
> +}
> +
> +static void __exit imx_ipu_fb_exit(void)
> +{
> +       platform_driver_unregister(&imx_ipu_fb_driver);
> +}
> +
> +module_init(imx_ipu_fb_init);
> +module_exit(imx_ipu_fb_exit);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("i.MX framebuffer driver");
> +MODULE_LICENSE("GPL");
> +MODULE_SUPPORTED_DEVICE("fb");
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org<mailto:majordomo@vger.kernel.org>
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org<mailto:majordomo@vger.kernel.org>
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 68297 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-14 12:38   ` Chen Jie-B02280
  0 siblings, 0 replies; 37+ messages in thread
From: Chen Jie-B02280 @ 2010-12-14 12:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Sascha,

Few comments inline with [Jason]

Jason Chen / Chen Jie
NMG / MAD
Freescale Semiconductor (China) Ltd.
2F, Building B, 177#, Bi Bo Rd
Pu Dong New District Shanghai 201203
Tel:     021-28937178
Fax:     021-28937444
E-mail:  Jason.Chen at freescale.com<mailto:Jason.Chen@freescale.com>

From: Jason Chen [mailto:weitway at gmail.com]
Sent: Tuesday, December 14, 2010 3:35 PM
To: Chen Jie-B02280
Subject: Fwd: [PATCH 5/9] Add i.MX5 framebuffer driver


---------- Forwarded message ----------
From: Liu Ying <liu.y.victor at gmail.com<mailto:liu.y.victor@gmail.com>>
Date: 2010/12/12
Subject: Re: [PATCH 5/9] Add i.MX5 framebuffer driver
To: Sascha Hauer <s.hauer at pengutronix.de<mailto:s.hauer@pengutronix.de>>
Cc: linux-arm-kernel at lists.infradead.org<mailto:linux-arm-kernel@lists.infradead.org>, linux-kernel at vger.kernel.org<mailto:linux-kernel@vger.kernel.org>, linux-fbdev at vger.kernel.org<mailto:linux-fbdev@vger.kernel.org>, Zhang Lily-R58066 <r58066 at freescale.com<mailto:r58066@freescale.com>>, Arnaud Patard <arnaud.patard at rtp-net.org<mailto:arnaud.patard@rtp-net.org>>


Hello, Sascha,

I have following comments to this patch:
1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
2) ADC is not supported yet in the framebuffer driver, so please
modify this comment:
  > + * Framebuffer Framebuffer Driver for SDC and ADC.
3) 'ipu_dp_set_window_pos()' is called only once in
imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
support to change the overlay framebuffer position. Need a
mechanism/interface for users to change the overlay framebuffer
position.
[Jason] DP-FG should be one fb device, sequence ioctl should be added after it, like global alpha , color key etc.

4) Need to make sure the framebuffer on DP-FG is blanked before the
framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
should be unblanked after the framebuffer on DP-BG is unblanked
5) Need to check the framebuffer on DP-FG doesn't run out of the range
of the framebuffer on DP-BG.
6) I prefer to find the video mode in modedb first, and if we cannot
find the video mode in common video mode data base, we can find a
video mode in custom video mode data base which is defined in platform
data. In this way, we don't need to export common modefb.

Best Regards,
Liu Ying


2010/12/9 Sascha Hauer <s.hauer at pengutronix.de<mailto:s.hauer@pengutronix.de>>:
> This patch adds framebuffer support to the Freescale i.MX SoCs
> equipped with an IPU v3, so far these are the i.MX50/51/53.
>
> This driver has been tested on the i.MX51 babbage board with
> both DVI and analog VGA in different resolutions and color depths.
> It has also been tested on a custom i.MX51 board using a fixed
> resolution panel.
>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de<mailto:s.hauer@pengutronix.de>>
> ---
>  drivers/video/Kconfig  |   11 +
>  drivers/video/Makefile |    1 +
>  drivers/video/mx5fb.c  |  846 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 858 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/video/mx5fb.c
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 27c1fb4..1901915 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -2236,6 +2236,17 @@ config FB_MX3
>          far only synchronous displays are supported. If you plan to use
>          an LCD display with your i.MX31 system, say Y here.
>
> +config FB_MX5
> +       tristate "MX5 Framebuffer support"
> +       depends on FB && MFD_IMX_IPU_V3
> +       select FB_CFB_FILLRECT
> +       select FB_CFB_COPYAREA
> +       select FB_CFB_IMAGEBLIT
> +       select FB_MODE_HELPERS
> +       help
> +         This is a framebuffer device for the i.MX51 LCD Controller. If you
> +         plan to use an LCD display with your i.MX51 system, say Y here.
> +
>  config FB_BROADSHEET
>        tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
>        depends on FB
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 485e8ed..ad408d2 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043)          += bf54x-lq043fb.o
>  obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
>  obj-$(CONFIG_FB_BFIN_T350MCQB)   += bfin-t350mcqb-fb.o
>  obj-$(CONFIG_FB_MX3)             += mx3fb.o
> +obj-$(CONFIG_FB_MX5)             += mx5fb.o
>  obj-$(CONFIG_FB_DA8XX)           += da8xx-fb.o
>
>  # the test framebuffer is last
> diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
> new file mode 100644
> index 0000000..fd9baf4
> --- /dev/null
> +++ b/drivers/video/mx5fb.c
> @@ -0,0 +1,846 @@
> +/*
> + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + *
> + * Framebuffer Framebuffer Driver for SDC and ADC.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <linux/fb.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/console.h>
> +#include <linux/mfd/imx-ipu-v3.h>
> +#include <asm/uaccess.h>
> +#include <mach/ipu-v3.h>
> +
> +#define DRIVER_NAME "imx-ipuv3-fb"
> +
> +struct imx_ipu_fb_info {
> +       int                     ipu_channel_num;
> +       struct ipu_channel      *ipu_ch;
> +       int                     dc;
> +       int                     ipu_di;
> +       u32                     ipu_di_pix_fmt;
> +       u32                     ipu_in_pix_fmt;
> +
> +       u32                     pseudo_palette[16];
> +
> +       struct ipu_dp           *dp;
> +       struct dmfc_channel     *dmfc;
> +       struct fb_info          *slave;
> +       struct fb_info          *master;
> +       bool                    enabled;
> +};
> +
> +static int imx_ipu_fb_set_fix(struct fb_info *info)
> +{
> +       struct fb_fix_screeninfo *fix = &info->fix;
> +       struct fb_var_screeninfo *var = &info->var;
> +
> +       fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> +       fix->type = FB_TYPE_PACKED_PIXELS;
> +       fix->accel = FB_ACCEL_NONE;
> +       fix->visual = FB_VISUAL_TRUECOLOR;
> +       fix->xpanstep = 1;
> +       fix->ypanstep = 1;
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
> +{
> +       int size;
> +
> +       size = fbi->var.yres_virtual * fbi->fix.line_length;
> +
> +       if (fbi->screen_base) {
> +               if (fbi->fix.smem_len >= size)
> +                       return 0;
> +
> +               dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> +                             fbi->screen_base, fbi->fix.smem_start);
> +       }
> +
> +       fbi->screen_base = dma_alloc_writecombine(fbi->device,
> +                               size,
> +                               (dma_addr_t *)&fbi->fix.smem_start,
> +                               GFP_DMA);
> +       if (fbi->screen_base == 0) {
> +               dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
> +                               fbi->fix.smem_len);
> +               fbi->fix.smem_len = 0;
> +               fbi->fix.smem_start = 0;
> +               return -ENOMEM;
> +       }
> +
> +       fbi->fix.smem_len = size;
> +       fbi->screen_size = fbi->fix.smem_len;
> +
> +       dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
> +               fbi->fix.smem_start, fbi->fix.smem_len);
> +
> +       /* Clear the screen */
> +       memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
> +
> +       return 0;
> +}
> +
> +static void imx_ipu_fb_enable(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       if (mxc_fbi->enabled)
> +               return;
> +
> +       ipu_di_enable(mxc_fbi->ipu_di);
> +       ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> +       ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> +       ipu_dc_enable_channel(mxc_fbi->dc);
> +       ipu_dp_enable_channel(mxc_fbi->dp);
> +       mxc_fbi->enabled = 1;
> +}
> +
> +static void imx_ipu_fb_disable(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       if (!mxc_fbi->enabled)
> +               return;
> +
> +       ipu_dp_disable_channel(mxc_fbi->dp);
> +       ipu_dc_disable_channel(mxc_fbi->dc);
> +       ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> +       ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> +       ipu_di_disable(mxc_fbi->ipu_di);
> +
> +       mxc_fbi->enabled = 0;
> +}
> +
> +static int calc_vref(struct fb_var_screeninfo *var)
> +{
> +       unsigned long htotal, vtotal;
> +
> +       htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
> +       vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
> +
> +       if (!htotal || !vtotal)
> +               return 60;
> +
> +       return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
> +}
> +
> +static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
> +{
> +       return var->xres * var->yres * vref;
> +}
> +
> +static int imx_ipu_fb_set_par(struct fb_info *fbi)
> +{
> +       int ret;
> +       struct ipu_di_signal_cfg sig_cfg;
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       u32 out_pixel_fmt;
> +       int interlaced = 0;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       int enabled = mxc_fbi->enabled;
> +
> +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> +       if (enabled)
> +               imx_ipu_fb_disable(fbi);
> +
> +       fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> +       var->yres_virtual = var->yres;
> +
> +       ret = imx_ipu_fb_map_video_memory(fbi);
> +       if (ret)
> +               return ret;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               sig_cfg.interlaced = 1;
> +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> +               sig_cfg.odd_field_first = 1;
> +       if (var->sync & FB_SYNC_EXT)
> +               sig_cfg.ext_clk = 1;
[Jason] FB_SYNC_EXT has not be used in FSL kernel mainline, it represent SYNC ext, should not be flag of ext clk. Some application for example X-server could not recognize it.

> +       if (var->sync & FB_SYNC_HOR_HIGH_ACT)
> +               sig_cfg.Hsync_pol = 1;
> +       if (var->sync & FB_SYNC_VERT_HIGH_ACT)
> +               sig_cfg.Vsync_pol = 1;
> +       if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
> +               sig_cfg.clk_pol = 1;
> +       if (var->sync & FB_SYNC_DATA_INVERT)
> +               sig_cfg.data_pol = 1;
> +       if (!(var->sync & FB_SYNC_OE_LOW_ACT))
> +               sig_cfg.enable_pol = 1;
> +       if (var->sync & FB_SYNC_CLK_IDLE_EN)
> +               sig_cfg.clkidle_en = 1;
> +
> +       dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
> +               PICOS2KHZ(var->pixclock) / 1000,
> +               PICOS2KHZ(var->pixclock) % 1000);
> +
> +       sig_cfg.width = var->xres;
> +       sig_cfg.height = var->yres;
> +       sig_cfg.pixel_fmt = out_pixel_fmt;
> +       sig_cfg.h_start_width = var->left_margin;
> +       sig_cfg.h_sync_width = var->hsync_len;
> +       sig_cfg.h_end_width = var->right_margin;
> +       sig_cfg.v_start_width = var->upper_margin;
> +       sig_cfg.v_sync_width = var->vsync_len;
> +       sig_cfg.v_end_width = var->lower_margin;
> +       sig_cfg.v_to_h_sync = 0;
> +
> +       if (mxc_fbi->dp) {
> +               ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
> +                               out_pixel_fmt, 1);
> +               if (ret) {
> +                       dev_dbg(fbi->device, "initializing display processor failed with %d\n",
> +                               ret);
> +                       return ret;
> +               }
> +       }
> +
> +       ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->ipu_di, interlaced,
> +                       out_pixel_fmt, fbi->var.xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing display controller failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_di_init_sync_panel(mxc_fbi->ipu_di,
> +                               PICOS2KHZ(var->pixclock) * 1000UL,
> +                               &sig_cfg);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing panel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
> +       var->xoffset = var->yoffset = 0;
> +
> +       if (fbi->var.vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> +                                       mxc_fbi->ipu_in_pix_fmt,
> +                                       var->xres, var->yres,
> +                                       fbi->fix.line_length,
> +                                       IPU_ROTATE_NONE,
> +                                       fbi->fix.smem_start,
> +                                       0,
> +                                       0, 0, interlaced);
> +       if (ret) {
> +               dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
> +       if (ret) {
> +               dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       if (enabled)
> +               imx_ipu_fb_enable(fbi);
> +
> +       return ret;
> +}
> +
> +/*
> + * These are the bitfields for each
> + * display depth that we support.
> + */
> +struct imxfb_rgb {
> +       struct fb_bitfield      red;
> +       struct fb_bitfield      green;
> +       struct fb_bitfield      blue;
> +       struct fb_bitfield      transp;
> +};
> +
> +static struct imxfb_rgb def_rgb_8 = {
> +       .red    = { .offset =  5, .length = 3, },
> +       .green  = { .offset =  2, .length = 3, },
> +       .blue   = { .offset =  0, .length = 2, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_16 = {
> +       .red    = { .offset = 11, .length = 5, },
> +       .green  = { .offset =  5, .length = 6, },
> +       .blue   = { .offset =  0, .length = 5, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_24 = {
> +       .red    = { .offset = 16, .length = 8, },
> +       .green  = { .offset =  8, .length = 8, },
> +       .blue   = { .offset =  0, .length = 8, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_32 = {
> +       .red    = { .offset = 16, .length = 8, },
> +       .green  = { .offset =  8, .length = 8, },
> +       .blue   = { .offset =  0, .length = 8, },
> +       .transp = { .offset = 24, .length = 8, },
> +};
> +
> +/*
> + * Check framebuffer variable parameters and adjust to valid values.
> + *
> + * @param       var      framebuffer variable parameters
> + *
> + * @param       info     framebuffer information pointer
> + */
> +static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> +       struct imxfb_rgb *rgb;
> +
> +       /* we don't support xpan, force xres_virtual to be equal to xres */
> +       var->xres_virtual = var->xres;
> +
> +       if (var->yres_virtual < var->yres)
> +               var->yres_virtual = var->yres;
> +
> +       switch (var->bits_per_pixel) {
> +       case 8:
> +               rgb = &def_rgb_8;
> +               break;
> +       case 16:
> +               rgb = &def_rgb_16;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
> +               break;
> +       case 24:
> +               rgb = &def_rgb_24;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> +               break;
> +       case 32:
> +               rgb = &def_rgb_32;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
> +               break;
> +       default:
> +               var->bits_per_pixel = 24;
> +               rgb = &def_rgb_24;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> +       }
> +
> +       var->red    = rgb->red;
> +       var->green  = rgb->green;
> +       var->blue   = rgb->blue;
> +       var->transp = rgb->transp;
> +
> +       return 0;
> +}
> +
> +static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
> +{
> +       chan &= 0xffff;
> +       chan >>= 16 - bf->length;
> +       return chan << bf->offset;
> +}
> +
> +static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
> +                          u_int trans, struct fb_info *fbi)
> +{
> +       unsigned int val;
> +       int ret = 1;
> +
> +       /*
> +        * If greyscale is true, then we convert the RGB value
> +        * to greyscale no matter what visual we are using.
> +        */
> +       if (fbi->var.grayscale)
> +               red = green = blue = (19595 * red + 38470 * green +
> +                                     7471 * blue) >> 16;
> +       switch (fbi->fix.visual) {
> +       case FB_VISUAL_TRUECOLOR:
> +               /*
> +                * 16-bit True Colour.  We encode the RGB value
> +                * according to the RGB bitfield information.
> +                */
> +               if (regno < 16) {
> +                       u32 *pal = fbi->pseudo_palette;
> +
> +                       val = chan_to_field(red, &fbi->var.red);
> +                       val |= chan_to_field(green, &fbi->var.green);
> +                       val |= chan_to_field(blue, &fbi->var.blue);
> +
> +                       pal[regno] = val;
> +                       ret = 0;
> +               }
> +               break;
> +
> +       case FB_VISUAL_STATIC_PSEUDOCOLOR:
> +       case FB_VISUAL_PSEUDOCOLOR:
> +               break;
> +       }
> +
> +       return ret;
> +}
> +
> +static int imx_ipu_fb_blank(int blank, struct fb_info *info)
> +{
> +       dev_dbg(info->device, "blank = %d\n", blank);
> +
> +       switch (blank) {
> +       case FB_BLANK_POWERDOWN:
> +       case FB_BLANK_VSYNC_SUSPEND:
> +       case FB_BLANK_HSYNC_SUSPEND:
> +       case FB_BLANK_NORMAL:
> +               imx_ipu_fb_disable(info);
> +               break;
> +       case FB_BLANK_UNBLANK:
> +               imx_ipu_fb_enable(info);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> +               struct fb_info *info)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> +       unsigned long base;
> +       int ret;
> +
> +       if (info->var.yoffset == var->yoffset)
> +               return 0;       /* No change, do nothing */
> +
> +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> +       base += info->fix.smem_start;
> +
> +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> +       if (ret)
> +               return ret;
> +
> +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> +               dev_err(info->device,
> +                       "Error updating SDC buf to address=0x%08lX\n", base);
> +       }
[Jason] It's better to enable double -buffer for fb which could avoid tearing issue.

> +
> +       info->var.yoffset = var->yoffset;
> +
> +       return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_ops = {
> +       .owner          = THIS_MODULE,
> +       .fb_set_par     = imx_ipu_fb_set_par,
> +       .fb_check_var   = imx_ipu_fb_check_var,
> +       .fb_setcolreg   = imx_ipu_fb_setcolreg,
> +       .fb_pan_display = imx_ipu_fb_pan_display,
> +       .fb_fillrect    = cfb_fillrect,
> +       .fb_copyarea    = cfb_copyarea,
> +       .fb_imageblit   = cfb_imageblit,
> +       .fb_blank       = imx_ipu_fb_blank,
> +};
> +
> +/*
> + * Overlay functions
> + */
> +static int imx_ipu_fb_enable_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> +       ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> +       ipu_dp_enable_fg(mxc_fbi->dp);
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_disable_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       ipu_dp_disable_fg(mxc_fbi->dp);
> +       ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> +       ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       struct fb_info *fbi_master = mxc_fbi->master;
> +       struct fb_var_screeninfo *var_master = &fbi_master->var;
> +       int ret;
> +       int interlaced = 0;
> +       int enabled = mxc_fbi->enabled;
> +
> +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> +       if (enabled)
> +               imx_ipu_fb_disable_overlay(fbi);
> +
> +       fbi->fix.line_length = var->xres_virtual *
> +                                  var->bits_per_pixel / 8;
> +
> +       ret = imx_ipu_fb_map_video_memory(fbi);
> +       if (ret)
> +               return ret;
> +
> +       ipu_dp_set_window_pos(mxc_fbi->dp, 64, 64);
> +
> +       var->xoffset = var->yoffset = 0;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> +                                       mxc_fbi->ipu_in_pix_fmt,
> +                                       var->xres, var->yres,
> +                                       fbi->fix.line_length,
> +                                       IPU_ROTATE_NONE,
> +                                       fbi->fix.smem_start,
> +                                       0,
> +                                       0, 0, interlaced);
> +       if (ret) {
> +               dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
> +       if (ret) {
> +               dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       if (enabled)
> +               imx_ipu_fb_enable_overlay(fbi);
> +
> +       return ret;
> +}
> +
> +static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
> +{
> +       dev_dbg(fbi->device, "blank = %d\n", blank);
> +
> +       switch (blank) {
> +       case FB_BLANK_POWERDOWN:
> +       case FB_BLANK_VSYNC_SUSPEND:
> +       case FB_BLANK_HSYNC_SUSPEND:
> +       case FB_BLANK_NORMAL:
> +               imx_ipu_fb_disable_overlay(fbi);
> +               break;
> +       case FB_BLANK_UNBLANK:
> +               imx_ipu_fb_enable_overlay(fbi);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_overlay_ops = {
> +       .owner          = THIS_MODULE,
> +       .fb_set_par     = imx_ipu_fb_set_par_overlay,
> +       .fb_check_var   = imx_ipu_fb_check_var,
> +       .fb_setcolreg   = imx_ipu_fb_setcolreg,
> +       .fb_pan_display = imx_ipu_fb_pan_display,
> +       .fb_fillrect    = cfb_fillrect,
> +       .fb_copyarea    = cfb_copyarea,
> +       .fb_imageblit   = cfb_imageblit,
> +       .fb_blank       = imx_ipu_fb_blank_overlay,
> +};
> +
> +static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
> +{
> +       struct fb_info *fbi;
> +       struct imx_ipu_fb_info *mxc_fbi;
> +
> +       fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
> +       if (!fbi)
> +               return NULL;
> +
> +       BUG_ON(fbi->par == NULL);
> +       mxc_fbi = fbi->par;
> +
> +       fbi->var.activate = FB_ACTIVATE_NOW;
> +
> +       fbi->fbops = ops;
> +       fbi->flags = FBINFO_FLAG_DEFAULT;
> +       fbi->pseudo_palette = mxc_fbi->pseudo_palette;
> +
> +       fb_alloc_cmap(&fbi->cmap, 16, 0);
> +
> +       return fbi;
> +}
> +
> +static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
> +               struct fb_info *fbi_master, int ipu_channel)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> +       struct fb_info *ovlfbi;
> +       struct imx_ipu_fb_info *ovl_mxc_fbi;
> +       int ret;
> +
> +       ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
> +       if (!ovlfbi)
> +               return -ENOMEM;
> +
> +       ovl_mxc_fbi = ovlfbi->par;
> +       ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
> +       ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
> +       ovl_mxc_fbi->ipu_di = -1;
> +       ovl_mxc_fbi->dp = mxc_fbi_master->dp;
> +       ovl_mxc_fbi->master = fbi_master;
> +       mxc_fbi_master->slave = ovlfbi;
> +
> +       ovlfbi->var.xres = 240;
> +       ovlfbi->var.yres = 320;
> +       ovlfbi->var.yres_virtual = ovlfbi->var.yres;
> +       ovlfbi->var.xres_virtual = ovlfbi->var.xres;
> +       imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
> +       imx_ipu_fb_set_fix(ovlfbi);
> +
> +       ret = register_framebuffer(ovlfbi);
> +       if (ret) {
> +               framebuffer_release(ovlfbi);
> +               return ret;
> +       }
> +
> +       ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 1, 0x80, 1);
> +       ipu_dp_set_color_key(ovl_mxc_fbi->dp, 0, 0);
> +
> +       imx_ipu_fb_set_par_overlay(ovlfbi);
> +
> +       return 0;
> +}
> +
> +static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
> +               struct fb_info *fbi_master, int ipu_channel)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> +       struct fb_info *ovlfbi = mxc_fbi_master->slave;
> +       struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
> +
> +       imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
> +
> +       unregister_framebuffer(ovlfbi);
> +
> +       ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
> +       ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
> +       ipu_dmfc_put(ovl_mxc_fbi->dmfc);
> +
> +       framebuffer_release(ovlfbi);
> +}
> +
> +static int imx_ipu_fb_find_mode(struct fb_info *fbi)
> +{
> +       int ret;
> +       struct fb_videomode *mode_array;
> +       struct fb_modelist *modelist;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       int i = 0;
> +
> +       list_for_each_entry(modelist, &fbi->modelist, list)
> +               i++;
> +
> +       mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
> +       if (!mode_array)
> +               return -ENOMEM;
> +
> +       i = 0;
> +       list_for_each_entry(modelist, &fbi->modelist, list)
> +               mode_array[i++] = modelist->mode;
> +
> +       ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
> +       if (ret == 0)
> +               return -EINVAL;
> +
> +       dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
> +                       var->xres, var->yres, var->bits_per_pixel,
> +                       var->hsync_len, var->left_margin, var->right_margin,
> +                       var->vsync_len, var->upper_margin, var->lower_margin);
> +
> +       kfree(mode_array);
> +
> +       return 0;
> +}
> +
> +static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
> +{
> +       struct fb_info *fbi;
> +       struct imx_ipu_fb_info *mxc_fbi;
> +       struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> +       int ret = 0, i;
> +
> +       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> +
> +       fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
> +       if (!fbi)
> +               return -ENOMEM;
> +
> +       mxc_fbi = fbi->par;
> +
> +       mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
> +       mxc_fbi->dc = plat_data->dc_channel;
> +       mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
> +       mxc_fbi->ipu_di = pdev->id;
> +
> +       mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
> +       if (IS_ERR(mxc_fbi->ipu_ch)) {
> +               ret = PTR_ERR(mxc_fbi->ipu_ch);
> +               goto failed_request_ipu;
> +       }
> +
> +       mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
> +       if (IS_ERR(mxc_fbi->ipu_ch)) {
> +               ret = PTR_ERR(mxc_fbi->ipu_ch);
> +               goto failed_request_dmfc;
> +       }
> +
> +       if (plat_data->dp_channel >= 0) {
> +               mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
> +               if (IS_ERR(mxc_fbi->dp)) {
> +                       ret = PTR_ERR(mxc_fbi->ipu_ch);
> +                       goto failed_request_dp;
> +               }
> +       }
> +
> +       fbi->var.yres_virtual = fbi->var.yres;
> +
> +       INIT_LIST_HEAD(&fbi->modelist);
> +       for (i = 0; i < plat_data->num_modes; i++)
> +               fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
> +
> +       if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
> +               for (i = 0; i < num_fb_modes; i++)
> +                       fb_add_videomode(&fb_modes[i], &fbi->modelist);
> +       }
> +
> +       imx_ipu_fb_find_mode(fbi);
> +
> +       imx_ipu_fb_check_var(&fbi->var, fbi);
> +       imx_ipu_fb_set_fix(fbi);
> +       ret = register_framebuffer(fbi);
> +       if (ret < 0)
> +               goto failed_register;
> +
> +       imx_ipu_fb_set_par(fbi);
> +       imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
> +
> +       if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> +               imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> +       platform_set_drvdata(pdev, fbi);
> +
> +       return 0;
> +
> +failed_register:
> +       if (plat_data->dp_channel >= 0)
> +               ipu_dp_put(mxc_fbi->dp);
> +failed_request_dp:
> +       ipu_dmfc_put(mxc_fbi->dmfc);
> +failed_request_dmfc:
> +       ipu_idmac_put(mxc_fbi->ipu_ch);
> +failed_request_ipu:
> +       fb_dealloc_cmap(&fbi->cmap);
> +       framebuffer_release(fbi);
> +
> +       return ret;
> +}
> +
> +static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
> +{
> +       struct fb_info *fbi = platform_get_drvdata(pdev);
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> +
> +       if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> +               imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> +       imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
> +
> +       dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> +                             fbi->screen_base, fbi->fix.smem_start);
> +
> +       if (&fbi->cmap)
> +               fb_dealloc_cmap(&fbi->cmap);
> +
> +       unregister_framebuffer(fbi);
> +
> +       if (plat_data->dp_channel >= 0)
> +               ipu_dp_put(mxc_fbi->dp);
> +       ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
> +       ipu_dmfc_put(mxc_fbi->dmfc);
> +       ipu_idmac_put(mxc_fbi->ipu_ch);
> +
> +       framebuffer_release(fbi);
> +
> +       return 0;
> +}
> +
> +static struct platform_driver imx_ipu_fb_driver = {
> +       .driver = {
> +               .name = DRIVER_NAME,
> +       },
> +       .probe = imx_ipu_fb_probe,
> +       .remove = __devexit_p(imx_ipu_fb_remove),
> +};
> +
> +static int __init imx_ipu_fb_init(void)
> +{
> +       return platform_driver_register(&imx_ipu_fb_driver);
> +}
> +
> +static void __exit imx_ipu_fb_exit(void)
> +{
> +       platform_driver_unregister(&imx_ipu_fb_driver);
> +}
> +
> +module_init(imx_ipu_fb_init);
> +module_exit(imx_ipu_fb_exit);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("i.MX framebuffer driver");
> +MODULE_LICENSE("GPL");
> +MODULE_SUPPORTED_DEVICE("fb");
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org<mailto:majordomo@vger.kernel.org>
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo at vger.kernel.org<mailto:majordomo@vger.kernel.org>
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

-------------- next part --------------
A non-text attachment was scrubbed...
Name: winmail.dat
Type: application/ms-tnef
Size: 68297 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20101214/6a8d5440/attachment-0001.bin>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-14 12:38   ` Chen Jie-B02280
  (?)
@ 2010-12-15 14:38     ` s.hauer
  -1 siblings, 0 replies; 37+ messages in thread
From: s.hauer @ 2010-12-15 14:38 UTC (permalink / raw)
  To: Chen Jie-B02280
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Zhang Lily-R58066,
	arnaud.patard

On Tue, Dec 14, 2010 at 12:38:08PM +0000, Chen Jie-B02280 wrote:
> Hi, Sascha,
> 
> Few comments inline with [Jason]

Please consider switching to a sane mailer which is able to quote correctly.

> 
> I have following comments to this patch:
> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> 2) ADC is not supported yet in the framebuffer driver, so please
> modify this comment:
>   > + * Framebuffer Framebuffer Driver for SDC and ADC.
> 3) 'ipu_dp_set_window_pos()' is called only once in
> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> support to change the overlay framebuffer position. Need a
> mechanism/interface for users to change the overlay framebuffer
> position.
> [Jason] DP-FG should be one fb device, sequence ioctl should be added
> after it, like global alpha , color key etc.

As said before, I have no interest in making the overlay fully
functional atm. So either we'll leave it here for reference if someone
ever tries to implement it properly or I'll remove it completely.

> > +static int imx_ipu_fb_set_par(struct fb_info *fbi)
> > +{
> > +       int ret;
> > +       struct ipu_di_signal_cfg sig_cfg;
> > +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> > +       u32 out_pixel_fmt;
> > +       int interlaced = 0;
> > +       struct fb_var_screeninfo *var = &fbi->var;
> > +       int enabled = mxc_fbi->enabled;
> > +
> > +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> > +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> > +
> > +       if (enabled)
> > +               imx_ipu_fb_disable(fbi);
> > +
> > +       fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
> > +
> > +       var->yres_virtual = var->yres;
> > +
> > +       ret = imx_ipu_fb_map_video_memory(fbi);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               interlaced = 1;
> > +
> > +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> > +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               sig_cfg.interlaced = 1;
> > +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> > +               sig_cfg.odd_field_first = 1;
> > +       if (var->sync & FB_SYNC_EXT)
> > +               sig_cfg.ext_clk = 1;
> [Jason] FB_SYNC_EXT has not be used in FSL kernel mainline, it
> represent SYNC ext, should not be flag of ext clk. Some application
> for example X-server could not recognize it.

Ok, I'll remove it.


> > +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> > +               struct fb_info *info)
> > +{
> > +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> > +       unsigned long base;
> > +       int ret;
> > +
> > +       if (info->var.yoffset == var->yoffset)
> > +               return 0;       /* No change, do nothing */
> > +
> > +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> > +       base += info->fix.smem_start;
> > +
> > +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> > +               dev_err(info->device,
> > +                       "Error updating SDC buf to address=0x%08lX\n", base);
> > +       }
> [Jason] It's better to enable double -buffer for fb which could avoid tearing issue.

There is no tearing as the switching is done during vsync.


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-15 14:38     ` s.hauer
  0 siblings, 0 replies; 37+ messages in thread
From: s.hauer @ 2010-12-15 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 14, 2010 at 12:38:08PM +0000, Chen Jie-B02280 wrote:
> Hi, Sascha,
> 
> Few comments inline with [Jason]

Please consider switching to a sane mailer which is able to quote correctly.

> 
> I have following comments to this patch:
> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> 2) ADC is not supported yet in the framebuffer driver, so please
> modify this comment:
>   > + * Framebuffer Framebuffer Driver for SDC and ADC.
> 3) 'ipu_dp_set_window_pos()' is called only once in
> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> support to change the overlay framebuffer position. Need a
> mechanism/interface for users to change the overlay framebuffer
> position.
> [Jason] DP-FG should be one fb device, sequence ioctl should be added
> after it, like global alpha , color key etc.

As said before, I have no interest in making the overlay fully
functional atm. So either we'll leave it here for reference if someone
ever tries to implement it properly or I'll remove it completely.

> > +static int imx_ipu_fb_set_par(struct fb_info *fbi)
> > +{
> > +       int ret;
> > +       struct ipu_di_signal_cfg sig_cfg;
> > +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> > +       u32 out_pixel_fmt;
> > +       int interlaced = 0;
> > +       struct fb_var_screeninfo *var = &fbi->var;
> > +       int enabled = mxc_fbi->enabled;
> > +
> > +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> > +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> > +
> > +       if (enabled)
> > +               imx_ipu_fb_disable(fbi);
> > +
> > +       fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
> > +
> > +       var->yres_virtual = var->yres;
> > +
> > +       ret = imx_ipu_fb_map_video_memory(fbi);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               interlaced = 1;
> > +
> > +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> > +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               sig_cfg.interlaced = 1;
> > +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> > +               sig_cfg.odd_field_first = 1;
> > +       if (var->sync & FB_SYNC_EXT)
> > +               sig_cfg.ext_clk = 1;
> [Jason] FB_SYNC_EXT has not be used in FSL kernel mainline, it
> represent SYNC ext, should not be flag of ext clk. Some application
> for example X-server could not recognize it.

Ok, I'll remove it.


> > +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> > +               struct fb_info *info)
> > +{
> > +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> > +       unsigned long base;
> > +       int ret;
> > +
> > +       if (info->var.yoffset = var->yoffset)
> > +               return 0;       /* No change, do nothing */
> > +
> > +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> > +       base += info->fix.smem_start;
> > +
> > +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> > +               dev_err(info->device,
> > +                       "Error updating SDC buf to address=0x%08lX\n", base);
> > +       }
> [Jason] It's better to enable double -buffer for fb which could avoid tearing issue.

There is no tearing as the switching is done during vsync.


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-15 14:38     ` s.hauer
  0 siblings, 0 replies; 37+ messages in thread
From: s.hauer at pengutronix.de @ 2010-12-15 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 14, 2010 at 12:38:08PM +0000, Chen Jie-B02280 wrote:
> Hi, Sascha,
> 
> Few comments inline with [Jason]

Please consider switching to a sane mailer which is able to quote correctly.

> 
> I have following comments to this patch:
> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> 2) ADC is not supported yet in the framebuffer driver, so please
> modify this comment:
>   > + * Framebuffer Framebuffer Driver for SDC and ADC.
> 3) 'ipu_dp_set_window_pos()' is called only once in
> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> support to change the overlay framebuffer position. Need a
> mechanism/interface for users to change the overlay framebuffer
> position.
> [Jason] DP-FG should be one fb device, sequence ioctl should be added
> after it, like global alpha , color key etc.

As said before, I have no interest in making the overlay fully
functional atm. So either we'll leave it here for reference if someone
ever tries to implement it properly or I'll remove it completely.

> > +static int imx_ipu_fb_set_par(struct fb_info *fbi)
> > +{
> > +       int ret;
> > +       struct ipu_di_signal_cfg sig_cfg;
> > +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> > +       u32 out_pixel_fmt;
> > +       int interlaced = 0;
> > +       struct fb_var_screeninfo *var = &fbi->var;
> > +       int enabled = mxc_fbi->enabled;
> > +
> > +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> > +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> > +
> > +       if (enabled)
> > +               imx_ipu_fb_disable(fbi);
> > +
> > +       fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
> > +
> > +       var->yres_virtual = var->yres;
> > +
> > +       ret = imx_ipu_fb_map_video_memory(fbi);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               interlaced = 1;
> > +
> > +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> > +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               sig_cfg.interlaced = 1;
> > +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> > +               sig_cfg.odd_field_first = 1;
> > +       if (var->sync & FB_SYNC_EXT)
> > +               sig_cfg.ext_clk = 1;
> [Jason] FB_SYNC_EXT has not be used in FSL kernel mainline, it
> represent SYNC ext, should not be flag of ext clk. Some application
> for example X-server could not recognize it.

Ok, I'll remove it.


> > +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> > +               struct fb_info *info)
> > +{
> > +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> > +       unsigned long base;
> > +       int ret;
> > +
> > +       if (info->var.yoffset == var->yoffset)
> > +               return 0;       /* No change, do nothing */
> > +
> > +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> > +       base += info->fix.smem_start;
> > +
> > +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> > +               dev_err(info->device,
> > +                       "Error updating SDC buf to address=0x%08lX\n", base);
> > +       }
> [Jason] It's better to enable double -buffer for fb which could avoid tearing issue.

There is no tearing as the switching is done during vsync.


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* RE: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-15 14:38     ` s.hauer
  (?)
@ 2010-12-16  2:07       ` Chen Jie-B02280
  -1 siblings, 0 replies; 37+ messages in thread
From: Chen Jie-B02280 @ 2010-12-16  2:07 UTC (permalink / raw)
  To: s.hauer
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Zhang Lily-R58066,
	arnaud.patard

Hi, Sascha,



Jason Chen / Chen Jie
NMG / MAD
Freescale Semiconductor (China) Ltd.
2F, Building B, 177#, Bi Bo Rd
Pu Dong New District Shanghai 201203
Tel:     021-28937178 
Fax:     021-28937444
E-mail:  Jason.Chen@freescale.com


-----Original Message-----
From: saschahauer@web.de [mailto:saschahauer@web.de] On Behalf Of s.hauer@pengutronix.de
Sent: Wednesday, December 15, 2010 10:39 PM
To: Chen Jie-B02280
Cc: linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; linux-fbdev@vger.kernel.org; Zhang Lily-R58066; arnaud.patard@rtp-net.org
Subject: Re: [PATCH 5/9] Add i.MX5 framebuffer driver

On Tue, Dec 14, 2010 at 12:38:08PM +0000, Chen Jie-B02280 wrote:
> Hi, Sascha,
> 
> Few comments inline with [Jason]

Please consider switching to a sane mailer which is able to quote correctly.

> 
> I have following comments to this patch:
> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> 2) ADC is not supported yet in the framebuffer driver, so please 
> modify this comment:
>   > + * Framebuffer Framebuffer Driver for SDC and ADC.
> 3) 'ipu_dp_set_window_pos()' is called only once in 
> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't 
> support to change the overlay framebuffer position. Need a 
> mechanism/interface for users to change the overlay framebuffer 
> position.
> [Jason] DP-FG should be one fb device, sequence ioctl should be added 
> after it, like global alpha , color key etc.

As said before, I have no interest in making the overlay fully functional atm. So either we'll leave it here for reference if someone ever tries to implement it properly or I'll remove it completely.
[Jason] Ok, then pls keep it as reference.

> > +static int imx_ipu_fb_set_par(struct fb_info *fbi) {
> > +       int ret;
> > +       struct ipu_di_signal_cfg sig_cfg;
> > +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> > +       u32 out_pixel_fmt;
> > +       int interlaced = 0;
> > +       struct fb_var_screeninfo *var = &fbi->var;
> > +       int enabled = mxc_fbi->enabled;
> > +
> > +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> > +               fbi->var.xres, fbi->var.yres, 
> > + fbi->var.bits_per_pixel);
> > +
> > +       if (enabled)
> > +               imx_ipu_fb_disable(fbi);
> > +
> > +       fbi->fix.line_length = var->xres_virtual * 
> > + var->bits_per_pixel / 8;
> > +
> > +       var->yres_virtual = var->yres;
> > +
> > +       ret = imx_ipu_fb_map_video_memory(fbi);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               interlaced = 1;
> > +
> > +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> > +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               sig_cfg.interlaced = 1;
> > +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> > +               sig_cfg.odd_field_first = 1;
> > +       if (var->sync & FB_SYNC_EXT)
> > +               sig_cfg.ext_clk = 1;
> [Jason] FB_SYNC_EXT has not be used in FSL kernel mainline, it 
> represent SYNC ext, should not be flag of ext clk. Some application 
> for example X-server could not recognize it.

Ok, I'll remove it.


> > +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> > +               struct fb_info *info) {
> > +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> > +       unsigned long base;
> > +       int ret;
> > +
> > +       if (info->var.yoffset == var->yoffset)
> > +               return 0;       /* No change, do nothing */
> > +
> > +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> > +       base += info->fix.smem_start;
> > +
> > +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> > +               dev_err(info->device,
> > +                       "Error updating SDC buf to address=0x%08lX\n", base);
> > +       }
> [Jason] It's better to enable double -buffer for fb which could avoid tearing issue.

There is no tearing as the switching is done during vsync.
[Jason] Yes, you are right.


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 37+ messages in thread

* RE: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-16  2:07       ` Chen Jie-B02280
  0 siblings, 0 replies; 37+ messages in thread
From: Chen Jie-B02280 @ 2010-12-16  2:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Sascha,



Jason Chen / Chen Jie
NMG / MAD
Freescale Semiconductor (China) Ltd.
2F, Building B, 177#, Bi Bo Rd
Pu Dong New District Shanghai 201203
Tel:     021-28937178 
Fax:     021-28937444
E-mail:  Jason.Chen@freescale.com


-----Original Message-----
From: saschahauer@web.de [mailto:saschahauer@web.de] On Behalf Of s.hauer@pengutronix.de
Sent: Wednesday, December 15, 2010 10:39 PM
To: Chen Jie-B02280
Cc: linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; linux-fbdev@vger.kernel.org; Zhang Lily-R58066; arnaud.patard@rtp-net.org
Subject: Re: [PATCH 5/9] Add i.MX5 framebuffer driver

On Tue, Dec 14, 2010 at 12:38:08PM +0000, Chen Jie-B02280 wrote:
> Hi, Sascha,
> 
> Few comments inline with [Jason]

Please consider switching to a sane mailer which is able to quote correctly.

> 
> I have following comments to this patch:
> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> 2) ADC is not supported yet in the framebuffer driver, so please 
> modify this comment:
>   > + * Framebuffer Framebuffer Driver for SDC and ADC.
> 3) 'ipu_dp_set_window_pos()' is called only once in 
> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't 
> support to change the overlay framebuffer position. Need a 
> mechanism/interface for users to change the overlay framebuffer 
> position.
> [Jason] DP-FG should be one fb device, sequence ioctl should be added 
> after it, like global alpha , color key etc.

As said before, I have no interest in making the overlay fully functional atm. So either we'll leave it here for reference if someone ever tries to implement it properly or I'll remove it completely.
[Jason] Ok, then pls keep it as reference.

> > +static int imx_ipu_fb_set_par(struct fb_info *fbi) {
> > +       int ret;
> > +       struct ipu_di_signal_cfg sig_cfg;
> > +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> > +       u32 out_pixel_fmt;
> > +       int interlaced = 0;
> > +       struct fb_var_screeninfo *var = &fbi->var;
> > +       int enabled = mxc_fbi->enabled;
> > +
> > +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> > +               fbi->var.xres, fbi->var.yres, 
> > + fbi->var.bits_per_pixel);
> > +
> > +       if (enabled)
> > +               imx_ipu_fb_disable(fbi);
> > +
> > +       fbi->fix.line_length = var->xres_virtual * 
> > + var->bits_per_pixel / 8;
> > +
> > +       var->yres_virtual = var->yres;
> > +
> > +       ret = imx_ipu_fb_map_video_memory(fbi);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               interlaced = 1;
> > +
> > +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> > +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               sig_cfg.interlaced = 1;
> > +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> > +               sig_cfg.odd_field_first = 1;
> > +       if (var->sync & FB_SYNC_EXT)
> > +               sig_cfg.ext_clk = 1;
> [Jason] FB_SYNC_EXT has not be used in FSL kernel mainline, it 
> represent SYNC ext, should not be flag of ext clk. Some application 
> for example X-server could not recognize it.

Ok, I'll remove it.


> > +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> > +               struct fb_info *info) {
> > +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> > +       unsigned long base;
> > +       int ret;
> > +
> > +       if (info->var.yoffset = var->yoffset)
> > +               return 0;       /* No change, do nothing */
> > +
> > +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> > +       base += info->fix.smem_start;
> > +
> > +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> > +               dev_err(info->device,
> > +                       "Error updating SDC buf to address=0x%08lX\n", base);
> > +       }
> [Jason] It's better to enable double -buffer for fb which could avoid tearing issue.

There is no tearing as the switching is done during vsync.
[Jason] Yes, you are right.


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-16  2:07       ` Chen Jie-B02280
  0 siblings, 0 replies; 37+ messages in thread
From: Chen Jie-B02280 @ 2010-12-16  2:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Sascha,



Jason Chen / Chen Jie
NMG / MAD
Freescale Semiconductor (China) Ltd.
2F, Building B, 177#, Bi Bo Rd
Pu Dong New District Shanghai?201203
Tel:???? 021-28937178?
Fax:???? 021-28937444
E-mail:??Jason.Chen at freescale.com


-----Original Message-----
From: saschahauer@web.de [mailto:saschahauer at web.de] On Behalf Of s.hauer at pengutronix.de
Sent: Wednesday, December 15, 2010 10:39 PM
To: Chen Jie-B02280
Cc: linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org; linux-fbdev at vger.kernel.org; Zhang Lily-R58066; arnaud.patard at rtp-net.org
Subject: Re: [PATCH 5/9] Add i.MX5 framebuffer driver

On Tue, Dec 14, 2010 at 12:38:08PM +0000, Chen Jie-B02280 wrote:
> Hi, Sascha,
> 
> Few comments inline with [Jason]

Please consider switching to a sane mailer which is able to quote correctly.

> 
> I have following comments to this patch:
> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> 2) ADC is not supported yet in the framebuffer driver, so please 
> modify this comment:
>   > + * Framebuffer Framebuffer Driver for SDC and ADC.
> 3) 'ipu_dp_set_window_pos()' is called only once in 
> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't 
> support to change the overlay framebuffer position. Need a 
> mechanism/interface for users to change the overlay framebuffer 
> position.
> [Jason] DP-FG should be one fb device, sequence ioctl should be added 
> after it, like global alpha , color key etc.

As said before, I have no interest in making the overlay fully functional atm. So either we'll leave it here for reference if someone ever tries to implement it properly or I'll remove it completely.
[Jason] Ok, then pls keep it as reference.

> > +static int imx_ipu_fb_set_par(struct fb_info *fbi) {
> > +       int ret;
> > +       struct ipu_di_signal_cfg sig_cfg;
> > +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> > +       u32 out_pixel_fmt;
> > +       int interlaced = 0;
> > +       struct fb_var_screeninfo *var = &fbi->var;
> > +       int enabled = mxc_fbi->enabled;
> > +
> > +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> > +               fbi->var.xres, fbi->var.yres, 
> > + fbi->var.bits_per_pixel);
> > +
> > +       if (enabled)
> > +               imx_ipu_fb_disable(fbi);
> > +
> > +       fbi->fix.line_length = var->xres_virtual * 
> > + var->bits_per_pixel / 8;
> > +
> > +       var->yres_virtual = var->yres;
> > +
> > +       ret = imx_ipu_fb_map_video_memory(fbi);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               interlaced = 1;
> > +
> > +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> > +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> > +
> > +       if (var->vmode & FB_VMODE_INTERLACED)
> > +               sig_cfg.interlaced = 1;
> > +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> > +               sig_cfg.odd_field_first = 1;
> > +       if (var->sync & FB_SYNC_EXT)
> > +               sig_cfg.ext_clk = 1;
> [Jason] FB_SYNC_EXT has not be used in FSL kernel mainline, it 
> represent SYNC ext, should not be flag of ext clk. Some application 
> for example X-server could not recognize it.

Ok, I'll remove it.


> > +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> > +               struct fb_info *info) {
> > +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> > +       unsigned long base;
> > +       int ret;
> > +
> > +       if (info->var.yoffset == var->yoffset)
> > +               return 0;       /* No change, do nothing */
> > +
> > +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> > +       base += info->fix.smem_start;
> > +
> > +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> > +               dev_err(info->device,
> > +                       "Error updating SDC buf to address=0x%08lX\n", base);
> > +       }
> [Jason] It's better to enable double -buffer for fb which could avoid tearing issue.

There is no tearing as the switching is done during vsync.
[Jason] Yes, you are right.


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-20 10:48 [PATCH v2] i.MX51 Framebuffer support Sascha Hauer
@ 2010-12-20 10:48   ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-20 10:48 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, Samuel Ortiz, liu.y.victor, B02280, Sascha Hauer

This patch adds framebuffer support to the Freescale i.MX SoCs
equipped with an IPU v3, so far these are the i.MX50/51/53.

This driver has been tested on the i.MX51 babbage board with
both DVI and analog VGA in different resolutions and color depths.
It has also been tested on a custom i.MX51 board using a fixed
resolution panel.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/video/Kconfig  |   11 +
 drivers/video/Makefile |    1 +
 drivers/video/mx5fb.c  |  934 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 946 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/mx5fb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 27c1fb4..1901915 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2236,6 +2236,17 @@ config FB_MX3
 	  far only synchronous displays are supported. If you plan to use
 	  an LCD display with your i.MX31 system, say Y here.
 
+config FB_MX5
+	tristate "MX5 Framebuffer support"
+	depends on FB && MFD_IMX_IPU_V3
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_MODE_HELPERS
+	help
+	  This is a framebuffer device for the i.MX51 LCD Controller. If you
+	  plan to use an LCD display with your i.MX51 system, say Y here.
+
 config FB_BROADSHEET
 	tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
 	depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 485e8ed..ad408d2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043)	  += bf54x-lq043fb.o
 obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
 obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
+obj-$(CONFIG_FB_MX5)		  += mx5fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
 
 # the test framebuffer is last
diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
new file mode 100644
index 0000000..f7824c9
--- /dev/null
+++ b/drivers/video/mx5fb.c
@@ -0,0 +1,934 @@
+/*
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Framebuffer Framebuffer Driver for SDC
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <asm/uaccess.h>
+#include <mach/ipu-v3.h>
+
+#define DRIVER_NAME "imx-ipuv3-fb"
+
+struct imx_ipu_fb_info {
+	int			ipu_channel_num;
+	struct ipu_channel	*ipu_ch;
+	int			dc;
+	int			di_no;
+	u32			ipu_di_pix_fmt;
+	u32			ipu_in_pix_fmt;
+
+	u32			pseudo_palette[16];
+
+	struct ipu_dp		*dp;
+	struct dmfc_channel	*dmfc;
+	struct ipu_di		*di;
+	struct fb_info		*slave;
+	struct fb_info		*master;
+	bool			enabled;
+
+	/* overlay specific fields */
+	bool			blank_state;
+	int			ovlxres, ovlyres;
+};
+
+static int imx_ipu_fb_set_fix(struct fb_info *info)
+{
+	struct fb_fix_screeninfo *fix = &info->fix;
+	struct fb_var_screeninfo *var = &info->var;
+
+	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->accel = FB_ACCEL_NONE;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+
+	return 0;
+}
+
+static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
+{
+	int size;
+
+	size = fbi->var.yres_virtual * fbi->fix.line_length;
+
+	if (fbi->screen_base) {
+		if (fbi->fix.smem_len >= size)
+			return 0;
+
+		dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+	}
+
+	fbi->screen_base = dma_alloc_writecombine(fbi->device,
+				size,
+				(dma_addr_t *)&fbi->fix.smem_start,
+				GFP_DMA);
+	if (fbi->screen_base == 0) {
+		dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
+				fbi->fix.smem_len);
+		fbi->fix.smem_len = 0;
+		fbi->fix.smem_start = 0;
+		return -ENOMEM;
+	}
+
+	fbi->fix.smem_len = size;
+	fbi->screen_size = fbi->fix.smem_len;
+
+	dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
+		fbi->fix.smem_start, fbi->fix.smem_len);
+
+	/* Clear the screen */
+	memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+	return 0;
+}
+
+static void imx_ipu_fb_enable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (mxc_fbi->enabled)
+		return;
+
+	ipu_di_enable(mxc_fbi->di);
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dc_enable_channel(mxc_fbi->dc);
+	ipu_dp_enable_channel(mxc_fbi->dp);
+	mxc_fbi->enabled = 1;
+}
+
+static void imx_ipu_fb_disable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (!mxc_fbi->enabled)
+		return;
+
+	ipu_dp_disable_channel(mxc_fbi->dp);
+	ipu_dc_disable_channel(mxc_fbi->dc);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+	ipu_di_disable(mxc_fbi->di);
+
+	mxc_fbi->enabled = 0;
+}
+
+static int calc_vref(struct fb_var_screeninfo *var)
+{
+	unsigned long htotal, vtotal;
+
+	htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+	vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+
+	if (!htotal || !vtotal)
+		return 60;
+
+	return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
+}
+
+static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
+{
+	return var->xres * var->yres * vref;
+}
+
+static int imx_ipu_fb_set_par(struct fb_info *fbi)
+{
+	int ret;
+	struct ipu_di_signal_cfg sig_cfg;
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	u32 out_pixel_fmt;
+	int interlaced = 0;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int enabled = mxc_fbi->enabled;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	if (enabled)
+		imx_ipu_fb_disable(fbi);
+
+	fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	ret = imx_ipu_fb_map_video_memory(fbi);
+	if (ret)
+		return ret;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	memset(&sig_cfg, 0, sizeof(sig_cfg));
+	out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		sig_cfg.interlaced = 1;
+	if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
+		sig_cfg.odd_field_first = 1;
+	if (var->sync & FB_SYNC_EXT)
+		sig_cfg.ext_clk = 1;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		sig_cfg.Hsync_pol = 1;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		sig_cfg.Vsync_pol = 1;
+	if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
+		sig_cfg.clk_pol = 1;
+	if (var->sync & FB_SYNC_DATA_INVERT)
+		sig_cfg.data_pol = 1;
+	if (!(var->sync & FB_SYNC_OE_LOW_ACT))
+		sig_cfg.enable_pol = 1;
+	if (var->sync & FB_SYNC_CLK_IDLE_EN)
+		sig_cfg.clkidle_en = 1;
+
+	dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
+		PICOS2KHZ(var->pixclock) / 1000,
+		PICOS2KHZ(var->pixclock) % 1000);
+
+	sig_cfg.width = var->xres;
+	sig_cfg.height = var->yres;
+	sig_cfg.pixel_fmt = out_pixel_fmt;
+	sig_cfg.h_start_width = var->left_margin;
+	sig_cfg.h_sync_width = var->hsync_len;
+	sig_cfg.h_end_width = var->right_margin;
+	sig_cfg.v_start_width = var->upper_margin;
+	sig_cfg.v_sync_width = var->vsync_len;
+	sig_cfg.v_end_width = var->lower_margin;
+	sig_cfg.v_to_h_sync = 0;
+
+	if (mxc_fbi->dp) {
+		ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
+				out_pixel_fmt, 1);
+		if (ret) {
+			dev_dbg(fbi->device, "initializing display processor failed with %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->di_no, interlaced,
+			out_pixel_fmt, fbi->var.xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing display controller failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_di_init_sync_panel(mxc_fbi->di,
+				PICOS2KHZ(var->pixclock) * 1000UL,
+				&sig_cfg);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing panel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
+	var->xoffset = var->yoffset = 0;
+
+	if (fbi->var.vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+	if (ret) {
+		dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
+	if (ret) {
+		dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	if (enabled)
+		imx_ipu_fb_enable(fbi);
+
+	return ret;
+}
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct imxfb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+static struct imxfb_rgb def_rgb_8 = {
+	.red	= { .offset =  5, .length = 3, },
+	.green	= { .offset =  2, .length = 3, },
+	.blue	= { .offset =  0, .length = 2, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_16 = {
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset =  5, .length = 6, },
+	.blue	= { .offset =  0, .length = 5, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_24 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_32 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+};
+
+/*
+ * Check framebuffer variable parameters and adjust to valid values.
+ *
+ * @param       var      framebuffer variable parameters
+ *
+ * @param       info     framebuffer information pointer
+ */
+static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	struct imxfb_rgb *rgb;
+
+	/* we don't support xpan, force xres_virtual to be equal to xres */
+	var->xres_virtual = var->xres;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		rgb = &def_rgb_8;
+		break;
+	case 16:
+		rgb = &def_rgb_16;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
+		break;
+	case 24:
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+		break;
+	case 32:
+		rgb = &def_rgb_32;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
+		break;
+	default:
+		var->bits_per_pixel = 24;
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+	}
+
+	var->red    = rgb->red;
+	var->green  = rgb->green;
+	var->blue   = rgb->blue;
+	var->transp = rgb->transp;
+
+	return 0;
+}
+
+static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int trans, struct fb_info *fbi)
+{
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no matter what visual we are using.
+	 */
+	if (fbi->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+				      7471 * blue) >> 16;
+	switch (fbi->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = fbi->pseudo_palette;
+
+			val = chan_to_field(red, &fbi->var.red);
+			val |= chan_to_field(green, &fbi->var.green);
+			val |= chan_to_field(blue, &fbi->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		break;
+	}
+
+	return ret;
+}
+
+static void imx_ipu_fb_enable_overlay(struct fb_info *fbi);
+static void imx_ipu_fb_disable_overlay(struct fb_info *fbi);
+
+static int imx_ipu_fb_blank(int blank, struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+
+	dev_dbg(info->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		if (mxc_fbi->slave)
+			imx_ipu_fb_disable_overlay(mxc_fbi->slave);
+		imx_ipu_fb_disable(info);
+		break;
+	case FB_BLANK_UNBLANK:
+		imx_ipu_fb_enable(info);
+		if (mxc_fbi->slave)
+			imx_ipu_fb_enable_overlay(mxc_fbi->slave);
+		break;
+	}
+
+	return 0;
+}
+
+static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	unsigned long base;
+	int ret;
+
+	if (info->var.yoffset == var->yoffset)
+		return 0;	/* No change, do nothing */
+
+	base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
+	base += info->fix.smem_start;
+
+	ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
+	if (ret)
+		return ret;
+
+	if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
+		dev_err(info->device,
+			"Error updating SDC buf to address=0x%08lX\n", base);
+	}
+
+	info->var.yoffset = var->yoffset;
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par,
+	.fb_check_var	= imx_ipu_fb_check_var,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank,
+};
+
+/*
+ * Overlay functions
+ */
+static void imx_ipu_fb_enable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	/*
+	 * This function is called unconditionally from imx_ipu_fb_blank to
+	 * enable/disable the overlay when the background is (un)blanked. So
+	 * we decide upon blank_state whether we should actually enable the
+	 * overlay.
+	 */
+	if (!mxc_fbi->blank_state)
+		return;
+
+	if (mxc_fbi->enabled)
+		return;
+
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dp_enable_fg(mxc_fbi->dp);
+	mxc_fbi->enabled = 1;
+	ipu_dp_set_color_key(mxc_fbi->dp, 1, 0x434343);
+}
+
+static void imx_ipu_fb_disable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (!mxc_fbi->enabled)
+		return;
+
+	ipu_dp_disable_fg(mxc_fbi->dp);
+	ipu_wait_for_interrupt(451, 100);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+	mxc_fbi->enabled = 0;
+}
+
+#define NONSTD_TO_XPOS(x)	(((x) >> 0)  & 0xfff)
+#define NONSTD_TO_YPOS(x)	(((x) >> 12) & 0xfff)
+#define NONSTD_TO_ALPHA(x)	(((x) >> 24) & 0xff)
+
+static int imx_ipu_fb_check_var_overlay(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	struct fb_info *fbi_master = mxc_fbi->master;
+	struct fb_var_screeninfo *var_master = &fbi_master->var;
+	int ret;
+	static int xpos, ypos;
+
+	xpos = NONSTD_TO_XPOS(var->nonstd);
+	ypos = NONSTD_TO_YPOS(var->nonstd);
+
+	ret = imx_ipu_fb_check_var(var, info);
+	if (ret)
+		return ret;
+
+	if (var->xres + xpos > var_master->xres)
+		return -EINVAL;
+	if (var->yres + ypos > var_master->yres)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct fb_var_screeninfo *var = &fbi->var;
+	struct fb_info *fbi_master = mxc_fbi->master;
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_var_screeninfo *var_master = &fbi_master->var;
+	int ret;
+	int interlaced = 0;
+	int enabled = mxc_fbi->enabled;
+	int xpos, ypos, alpha;
+	int resolution_change;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	resolution_change = mxc_fbi->ovlxres != var->xres ||
+		mxc_fbi->ovlyres != var->yres;
+
+	if (enabled && resolution_change)
+		imx_ipu_fb_disable_overlay(fbi);
+
+	fbi->fix.line_length = var->xres_virtual *
+                                  var->bits_per_pixel / 8;
+
+	xpos = NONSTD_TO_XPOS(var->nonstd);
+	ypos = NONSTD_TO_YPOS(var->nonstd);
+	alpha = NONSTD_TO_ALPHA(var->nonstd);
+
+	if (resolution_change) {
+		ret = imx_ipu_fb_map_video_memory(fbi);
+		if (ret)
+			return ret;
+	}
+
+	if (!resolution_change && enabled)
+		ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi_master->ipu_channel_num), 100);
+
+	ipu_dp_set_window_pos(mxc_fbi->dp, xpos, ypos);
+	ipu_dp_set_global_alpha(mxc_fbi->dp, 1, alpha, 1);
+
+	var->xoffset = var->yoffset = 0;
+
+	if (resolution_change) {
+		if (var->vmode & FB_VMODE_INTERLACED)
+			interlaced = 1;
+
+		ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+		if (ret) {
+			dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+		if (ret) {
+			dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
+		if (ret) {
+			dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+			return ret;
+		}
+		mxc_fbi->ovlxres = var->xres;
+		mxc_fbi->ovlyres = var->yres;
+	}
+
+	if (enabled && resolution_change)
+		imx_ipu_fb_enable_overlay(fbi);
+
+	return ret;
+}
+
+static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	dev_dbg(fbi->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		mxc_fbi->blank_state = 0;
+		imx_ipu_fb_disable_overlay(fbi);
+		break;
+	case FB_BLANK_UNBLANK:
+		mxc_fbi->blank_state = 1;
+		imx_ipu_fb_enable_overlay(fbi);
+		break;
+	}
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_overlay_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par_overlay,
+	.fb_check_var	= imx_ipu_fb_check_var_overlay,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank_overlay,
+};
+
+static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+
+	fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
+	if (!fbi)
+		return NULL;
+
+	BUG_ON(fbi->par == NULL);
+	mxc_fbi = fbi->par;
+
+	fbi->var.activate = FB_ACTIVATE_NOW;
+
+	fbi->fbops = ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->pseudo_palette = mxc_fbi->pseudo_palette;
+
+	fb_alloc_cmap(&fbi->cmap, 16, 0);
+
+	return fbi;
+}
+
+static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi;
+	struct imx_ipu_fb_info *ovl_mxc_fbi;
+	int ret;
+
+	ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
+	if (!ovlfbi)
+		return -ENOMEM;
+
+	ovl_mxc_fbi = ovlfbi->par;
+	ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
+	ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
+	ovl_mxc_fbi->di = NULL;
+	ovl_mxc_fbi->dp = mxc_fbi_master->dp;
+	ovl_mxc_fbi->master = fbi_master;
+	mxc_fbi_master->slave = ovlfbi;
+
+	ovlfbi->var.xres = 240;
+	ovlfbi->var.yres = 320;
+	ovlfbi->var.yres_virtual = ovlfbi->var.yres;
+	ovlfbi->var.xres_virtual = ovlfbi->var.xres;
+	imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
+	imx_ipu_fb_set_fix(ovlfbi);
+
+	ret = register_framebuffer(ovlfbi);
+	if (ret) {
+		framebuffer_release(ovlfbi);
+		return ret;
+	}
+
+	ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 0, 0, 1);
+	ipu_dp_set_color_key(ovl_mxc_fbi->dp, 1, 0x434343);
+
+	imx_ipu_fb_set_par_overlay(ovlfbi);
+
+	return 0;
+}
+
+static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi = mxc_fbi_master->slave;
+	struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
+
+	imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
+
+	unregister_framebuffer(ovlfbi);
+
+	ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
+	ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
+	ipu_dmfc_put(ovl_mxc_fbi->dmfc);
+
+	framebuffer_release(ovlfbi);
+}
+
+static int imx_ipu_fb_find_mode(struct fb_info *fbi)
+{
+	int ret;
+	struct fb_videomode *mode_array;
+	struct fb_modelist *modelist;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int i = 0;
+
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		i++;
+
+	mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
+	if (!mode_array)
+		return -ENOMEM;
+
+	i = 0;
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		mode_array[i++] = modelist->mode;
+
+	ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
+	if (ret == 0)
+		return -EINVAL;
+
+	dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
+			var->xres, var->yres, var->bits_per_pixel,
+			var->hsync_len, var->left_margin, var->right_margin,
+			var->vsync_len, var->upper_margin, var->lower_margin);
+
+	kfree(mode_array);
+
+	return 0;
+}
+
+static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+	int ret = 0, i;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
+	if (!fbi)
+		return -ENOMEM;
+
+	mxc_fbi = fbi->par;
+
+	mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
+	mxc_fbi->dc = plat_data->dc_channel;
+	mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
+	mxc_fbi->di_no = plat_data->display;
+
+	mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_ipu;
+	}
+
+	mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_dmfc;
+	}
+
+	if (plat_data->dp_channel >= 0) {
+		mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
+		if (IS_ERR(mxc_fbi->dp)) {
+			ret = PTR_ERR(mxc_fbi->ipu_ch);
+			goto failed_request_dp;
+		}
+	}
+
+	mxc_fbi->di = ipu_di_get(plat_data->display);
+	if (IS_ERR(mxc_fbi->di)) {
+		ret = PTR_ERR(mxc_fbi->di);
+		goto failed_request_di;
+	}
+
+	fbi->var.yres_virtual = fbi->var.yres;
+
+	INIT_LIST_HEAD(&fbi->modelist);
+	for (i = 0; i < plat_data->num_modes; i++)
+		fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
+
+	if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
+		for (i = 0; i < num_fb_modes; i++)
+			fb_add_videomode(&fb_modes[i], &fbi->modelist);
+	}
+
+	imx_ipu_fb_find_mode(fbi);
+
+	imx_ipu_fb_check_var(&fbi->var, fbi);
+	imx_ipu_fb_set_fix(fbi);
+	ret = register_framebuffer(fbi);
+	if (ret < 0)
+		goto failed_register;
+
+	imx_ipu_fb_set_par(fbi);
+	imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	platform_set_drvdata(pdev, fbi);
+
+	return 0;
+
+failed_register:
+	ipu_di_put(mxc_fbi->di);
+failed_request_di:
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+failed_request_dp:
+	ipu_dmfc_put(mxc_fbi->dmfc);
+failed_request_dmfc:
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+failed_request_ipu:
+	fb_dealloc_cmap(&fbi->cmap);
+	framebuffer_release(fbi);
+
+	return ret;
+}
+
+static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
+{
+	struct fb_info *fbi = platform_get_drvdata(pdev);
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
+
+	dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+
+	if (&fbi->cmap)
+		fb_dealloc_cmap(&fbi->cmap);
+
+	unregister_framebuffer(fbi);
+
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+	ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
+	ipu_dmfc_put(mxc_fbi->dmfc);
+	ipu_di_put(mxc_fbi->di);
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+
+	framebuffer_release(fbi);
+
+	return 0;
+}
+
+static struct platform_driver imx_ipu_fb_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+	.probe = imx_ipu_fb_probe,
+	.remove = __devexit_p(imx_ipu_fb_remove),
+};
+
+static int __init imx_ipu_fb_init(void)
+{
+	return platform_driver_register(&imx_ipu_fb_driver);
+}
+
+static void __exit imx_ipu_fb_exit(void)
+{
+	platform_driver_unregister(&imx_ipu_fb_driver);
+}
+
+module_init(imx_ipu_fb_init);
+module_exit(imx_ipu_fb_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-20 10:48   ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-20 10:48 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds framebuffer support to the Freescale i.MX SoCs
equipped with an IPU v3, so far these are the i.MX50/51/53.

This driver has been tested on the i.MX51 babbage board with
both DVI and analog VGA in different resolutions and color depths.
It has also been tested on a custom i.MX51 board using a fixed
resolution panel.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/video/Kconfig  |   11 +
 drivers/video/Makefile |    1 +
 drivers/video/mx5fb.c  |  934 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 946 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/mx5fb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 27c1fb4..1901915 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2236,6 +2236,17 @@ config FB_MX3
 	  far only synchronous displays are supported. If you plan to use
 	  an LCD display with your i.MX31 system, say Y here.
 
+config FB_MX5
+	tristate "MX5 Framebuffer support"
+	depends on FB && MFD_IMX_IPU_V3
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_MODE_HELPERS
+	help
+	  This is a framebuffer device for the i.MX51 LCD Controller. If you
+	  plan to use an LCD display with your i.MX51 system, say Y here.
+
 config FB_BROADSHEET
 	tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
 	depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 485e8ed..ad408d2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043)	  += bf54x-lq043fb.o
 obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
 obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
+obj-$(CONFIG_FB_MX5)		  += mx5fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
 
 # the test framebuffer is last
diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
new file mode 100644
index 0000000..f7824c9
--- /dev/null
+++ b/drivers/video/mx5fb.c
@@ -0,0 +1,934 @@
+/*
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Framebuffer Framebuffer Driver for SDC
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <asm/uaccess.h>
+#include <mach/ipu-v3.h>
+
+#define DRIVER_NAME "imx-ipuv3-fb"
+
+struct imx_ipu_fb_info {
+	int			ipu_channel_num;
+	struct ipu_channel	*ipu_ch;
+	int			dc;
+	int			di_no;
+	u32			ipu_di_pix_fmt;
+	u32			ipu_in_pix_fmt;
+
+	u32			pseudo_palette[16];
+
+	struct ipu_dp		*dp;
+	struct dmfc_channel	*dmfc;
+	struct ipu_di		*di;
+	struct fb_info		*slave;
+	struct fb_info		*master;
+	bool			enabled;
+
+	/* overlay specific fields */
+	bool			blank_state;
+	int			ovlxres, ovlyres;
+};
+
+static int imx_ipu_fb_set_fix(struct fb_info *info)
+{
+	struct fb_fix_screeninfo *fix = &info->fix;
+	struct fb_var_screeninfo *var = &info->var;
+
+	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->accel = FB_ACCEL_NONE;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+
+	return 0;
+}
+
+static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
+{
+	int size;
+
+	size = fbi->var.yres_virtual * fbi->fix.line_length;
+
+	if (fbi->screen_base) {
+		if (fbi->fix.smem_len >= size)
+			return 0;
+
+		dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+	}
+
+	fbi->screen_base = dma_alloc_writecombine(fbi->device,
+				size,
+				(dma_addr_t *)&fbi->fix.smem_start,
+				GFP_DMA);
+	if (fbi->screen_base == 0) {
+		dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
+				fbi->fix.smem_len);
+		fbi->fix.smem_len = 0;
+		fbi->fix.smem_start = 0;
+		return -ENOMEM;
+	}
+
+	fbi->fix.smem_len = size;
+	fbi->screen_size = fbi->fix.smem_len;
+
+	dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
+		fbi->fix.smem_start, fbi->fix.smem_len);
+
+	/* Clear the screen */
+	memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+	return 0;
+}
+
+static void imx_ipu_fb_enable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (mxc_fbi->enabled)
+		return;
+
+	ipu_di_enable(mxc_fbi->di);
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dc_enable_channel(mxc_fbi->dc);
+	ipu_dp_enable_channel(mxc_fbi->dp);
+	mxc_fbi->enabled = 1;
+}
+
+static void imx_ipu_fb_disable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (!mxc_fbi->enabled)
+		return;
+
+	ipu_dp_disable_channel(mxc_fbi->dp);
+	ipu_dc_disable_channel(mxc_fbi->dc);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+	ipu_di_disable(mxc_fbi->di);
+
+	mxc_fbi->enabled = 0;
+}
+
+static int calc_vref(struct fb_var_screeninfo *var)
+{
+	unsigned long htotal, vtotal;
+
+	htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+	vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+
+	if (!htotal || !vtotal)
+		return 60;
+
+	return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
+}
+
+static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
+{
+	return var->xres * var->yres * vref;
+}
+
+static int imx_ipu_fb_set_par(struct fb_info *fbi)
+{
+	int ret;
+	struct ipu_di_signal_cfg sig_cfg;
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	u32 out_pixel_fmt;
+	int interlaced = 0;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int enabled = mxc_fbi->enabled;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	if (enabled)
+		imx_ipu_fb_disable(fbi);
+
+	fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	ret = imx_ipu_fb_map_video_memory(fbi);
+	if (ret)
+		return ret;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	memset(&sig_cfg, 0, sizeof(sig_cfg));
+	out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		sig_cfg.interlaced = 1;
+	if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
+		sig_cfg.odd_field_first = 1;
+	if (var->sync & FB_SYNC_EXT)
+		sig_cfg.ext_clk = 1;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		sig_cfg.Hsync_pol = 1;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		sig_cfg.Vsync_pol = 1;
+	if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
+		sig_cfg.clk_pol = 1;
+	if (var->sync & FB_SYNC_DATA_INVERT)
+		sig_cfg.data_pol = 1;
+	if (!(var->sync & FB_SYNC_OE_LOW_ACT))
+		sig_cfg.enable_pol = 1;
+	if (var->sync & FB_SYNC_CLK_IDLE_EN)
+		sig_cfg.clkidle_en = 1;
+
+	dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
+		PICOS2KHZ(var->pixclock) / 1000,
+		PICOS2KHZ(var->pixclock) % 1000);
+
+	sig_cfg.width = var->xres;
+	sig_cfg.height = var->yres;
+	sig_cfg.pixel_fmt = out_pixel_fmt;
+	sig_cfg.h_start_width = var->left_margin;
+	sig_cfg.h_sync_width = var->hsync_len;
+	sig_cfg.h_end_width = var->right_margin;
+	sig_cfg.v_start_width = var->upper_margin;
+	sig_cfg.v_sync_width = var->vsync_len;
+	sig_cfg.v_end_width = var->lower_margin;
+	sig_cfg.v_to_h_sync = 0;
+
+	if (mxc_fbi->dp) {
+		ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
+				out_pixel_fmt, 1);
+		if (ret) {
+			dev_dbg(fbi->device, "initializing display processor failed with %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->di_no, interlaced,
+			out_pixel_fmt, fbi->var.xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing display controller failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_di_init_sync_panel(mxc_fbi->di,
+				PICOS2KHZ(var->pixclock) * 1000UL,
+				&sig_cfg);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing panel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
+	var->xoffset = var->yoffset = 0;
+
+	if (fbi->var.vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+	if (ret) {
+		dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
+	if (ret) {
+		dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	if (enabled)
+		imx_ipu_fb_enable(fbi);
+
+	return ret;
+}
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct imxfb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+static struct imxfb_rgb def_rgb_8 = {
+	.red	= { .offset =  5, .length = 3, },
+	.green	= { .offset =  2, .length = 3, },
+	.blue	= { .offset =  0, .length = 2, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_16 = {
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset =  5, .length = 6, },
+	.blue	= { .offset =  0, .length = 5, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_24 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_32 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+};
+
+/*
+ * Check framebuffer variable parameters and adjust to valid values.
+ *
+ * @param       var      framebuffer variable parameters
+ *
+ * @param       info     framebuffer information pointer
+ */
+static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	struct imxfb_rgb *rgb;
+
+	/* we don't support xpan, force xres_virtual to be equal to xres */
+	var->xres_virtual = var->xres;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		rgb = &def_rgb_8;
+		break;
+	case 16:
+		rgb = &def_rgb_16;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
+		break;
+	case 24:
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+		break;
+	case 32:
+		rgb = &def_rgb_32;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
+		break;
+	default:
+		var->bits_per_pixel = 24;
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+	}
+
+	var->red    = rgb->red;
+	var->green  = rgb->green;
+	var->blue   = rgb->blue;
+	var->transp = rgb->transp;
+
+	return 0;
+}
+
+static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int trans, struct fb_info *fbi)
+{
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no matter what visual we are using.
+	 */
+	if (fbi->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+				      7471 * blue) >> 16;
+	switch (fbi->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = fbi->pseudo_palette;
+
+			val = chan_to_field(red, &fbi->var.red);
+			val |= chan_to_field(green, &fbi->var.green);
+			val |= chan_to_field(blue, &fbi->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		break;
+	}
+
+	return ret;
+}
+
+static void imx_ipu_fb_enable_overlay(struct fb_info *fbi);
+static void imx_ipu_fb_disable_overlay(struct fb_info *fbi);
+
+static int imx_ipu_fb_blank(int blank, struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+
+	dev_dbg(info->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		if (mxc_fbi->slave)
+			imx_ipu_fb_disable_overlay(mxc_fbi->slave);
+		imx_ipu_fb_disable(info);
+		break;
+	case FB_BLANK_UNBLANK:
+		imx_ipu_fb_enable(info);
+		if (mxc_fbi->slave)
+			imx_ipu_fb_enable_overlay(mxc_fbi->slave);
+		break;
+	}
+
+	return 0;
+}
+
+static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	unsigned long base;
+	int ret;
+
+	if (info->var.yoffset == var->yoffset)
+		return 0;	/* No change, do nothing */
+
+	base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
+	base += info->fix.smem_start;
+
+	ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
+	if (ret)
+		return ret;
+
+	if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
+		dev_err(info->device,
+			"Error updating SDC buf to address=0x%08lX\n", base);
+	}
+
+	info->var.yoffset = var->yoffset;
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par,
+	.fb_check_var	= imx_ipu_fb_check_var,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank,
+};
+
+/*
+ * Overlay functions
+ */
+static void imx_ipu_fb_enable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	/*
+	 * This function is called unconditionally from imx_ipu_fb_blank to
+	 * enable/disable the overlay when the background is (un)blanked. So
+	 * we decide upon blank_state whether we should actually enable the
+	 * overlay.
+	 */
+	if (!mxc_fbi->blank_state)
+		return;
+
+	if (mxc_fbi->enabled)
+		return;
+
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dp_enable_fg(mxc_fbi->dp);
+	mxc_fbi->enabled = 1;
+	ipu_dp_set_color_key(mxc_fbi->dp, 1, 0x434343);
+}
+
+static void imx_ipu_fb_disable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (!mxc_fbi->enabled)
+		return;
+
+	ipu_dp_disable_fg(mxc_fbi->dp);
+	ipu_wait_for_interrupt(451, 100);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+	mxc_fbi->enabled = 0;
+}
+
+#define NONSTD_TO_XPOS(x)	(((x) >> 0)  & 0xfff)
+#define NONSTD_TO_YPOS(x)	(((x) >> 12) & 0xfff)
+#define NONSTD_TO_ALPHA(x)	(((x) >> 24) & 0xff)
+
+static int imx_ipu_fb_check_var_overlay(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	struct fb_info *fbi_master = mxc_fbi->master;
+	struct fb_var_screeninfo *var_master = &fbi_master->var;
+	int ret;
+	static int xpos, ypos;
+
+	xpos = NONSTD_TO_XPOS(var->nonstd);
+	ypos = NONSTD_TO_YPOS(var->nonstd);
+
+	ret = imx_ipu_fb_check_var(var, info);
+	if (ret)
+		return ret;
+
+	if (var->xres + xpos > var_master->xres)
+		return -EINVAL;
+	if (var->yres + ypos > var_master->yres)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct fb_var_screeninfo *var = &fbi->var;
+	struct fb_info *fbi_master = mxc_fbi->master;
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_var_screeninfo *var_master = &fbi_master->var;
+	int ret;
+	int interlaced = 0;
+	int enabled = mxc_fbi->enabled;
+	int xpos, ypos, alpha;
+	int resolution_change;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	resolution_change = mxc_fbi->ovlxres != var->xres ||
+		mxc_fbi->ovlyres != var->yres;
+
+	if (enabled && resolution_change)
+		imx_ipu_fb_disable_overlay(fbi);
+
+	fbi->fix.line_length = var->xres_virtual *
+                                  var->bits_per_pixel / 8;
+
+	xpos = NONSTD_TO_XPOS(var->nonstd);
+	ypos = NONSTD_TO_YPOS(var->nonstd);
+	alpha = NONSTD_TO_ALPHA(var->nonstd);
+
+	if (resolution_change) {
+		ret = imx_ipu_fb_map_video_memory(fbi);
+		if (ret)
+			return ret;
+	}
+
+	if (!resolution_change && enabled)
+		ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi_master->ipu_channel_num), 100);
+
+	ipu_dp_set_window_pos(mxc_fbi->dp, xpos, ypos);
+	ipu_dp_set_global_alpha(mxc_fbi->dp, 1, alpha, 1);
+
+	var->xoffset = var->yoffset = 0;
+
+	if (resolution_change) {
+		if (var->vmode & FB_VMODE_INTERLACED)
+			interlaced = 1;
+
+		ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+		if (ret) {
+			dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+		if (ret) {
+			dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
+		if (ret) {
+			dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+			return ret;
+		}
+		mxc_fbi->ovlxres = var->xres;
+		mxc_fbi->ovlyres = var->yres;
+	}
+
+	if (enabled && resolution_change)
+		imx_ipu_fb_enable_overlay(fbi);
+
+	return ret;
+}
+
+static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	dev_dbg(fbi->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		mxc_fbi->blank_state = 0;
+		imx_ipu_fb_disable_overlay(fbi);
+		break;
+	case FB_BLANK_UNBLANK:
+		mxc_fbi->blank_state = 1;
+		imx_ipu_fb_enable_overlay(fbi);
+		break;
+	}
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_overlay_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par_overlay,
+	.fb_check_var	= imx_ipu_fb_check_var_overlay,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank_overlay,
+};
+
+static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+
+	fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
+	if (!fbi)
+		return NULL;
+
+	BUG_ON(fbi->par == NULL);
+	mxc_fbi = fbi->par;
+
+	fbi->var.activate = FB_ACTIVATE_NOW;
+
+	fbi->fbops = ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->pseudo_palette = mxc_fbi->pseudo_palette;
+
+	fb_alloc_cmap(&fbi->cmap, 16, 0);
+
+	return fbi;
+}
+
+static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi;
+	struct imx_ipu_fb_info *ovl_mxc_fbi;
+	int ret;
+
+	ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
+	if (!ovlfbi)
+		return -ENOMEM;
+
+	ovl_mxc_fbi = ovlfbi->par;
+	ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
+	ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
+	ovl_mxc_fbi->di = NULL;
+	ovl_mxc_fbi->dp = mxc_fbi_master->dp;
+	ovl_mxc_fbi->master = fbi_master;
+	mxc_fbi_master->slave = ovlfbi;
+
+	ovlfbi->var.xres = 240;
+	ovlfbi->var.yres = 320;
+	ovlfbi->var.yres_virtual = ovlfbi->var.yres;
+	ovlfbi->var.xres_virtual = ovlfbi->var.xres;
+	imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
+	imx_ipu_fb_set_fix(ovlfbi);
+
+	ret = register_framebuffer(ovlfbi);
+	if (ret) {
+		framebuffer_release(ovlfbi);
+		return ret;
+	}
+
+	ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 0, 0, 1);
+	ipu_dp_set_color_key(ovl_mxc_fbi->dp, 1, 0x434343);
+
+	imx_ipu_fb_set_par_overlay(ovlfbi);
+
+	return 0;
+}
+
+static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi = mxc_fbi_master->slave;
+	struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
+
+	imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
+
+	unregister_framebuffer(ovlfbi);
+
+	ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
+	ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
+	ipu_dmfc_put(ovl_mxc_fbi->dmfc);
+
+	framebuffer_release(ovlfbi);
+}
+
+static int imx_ipu_fb_find_mode(struct fb_info *fbi)
+{
+	int ret;
+	struct fb_videomode *mode_array;
+	struct fb_modelist *modelist;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int i = 0;
+
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		i++;
+
+	mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
+	if (!mode_array)
+		return -ENOMEM;
+
+	i = 0;
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		mode_array[i++] = modelist->mode;
+
+	ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
+	if (ret == 0)
+		return -EINVAL;
+
+	dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
+			var->xres, var->yres, var->bits_per_pixel,
+			var->hsync_len, var->left_margin, var->right_margin,
+			var->vsync_len, var->upper_margin, var->lower_margin);
+
+	kfree(mode_array);
+
+	return 0;
+}
+
+static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+	int ret = 0, i;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
+	if (!fbi)
+		return -ENOMEM;
+
+	mxc_fbi = fbi->par;
+
+	mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
+	mxc_fbi->dc = plat_data->dc_channel;
+	mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
+	mxc_fbi->di_no = plat_data->display;
+
+	mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_ipu;
+	}
+
+	mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_dmfc;
+	}
+
+	if (plat_data->dp_channel >= 0) {
+		mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
+		if (IS_ERR(mxc_fbi->dp)) {
+			ret = PTR_ERR(mxc_fbi->ipu_ch);
+			goto failed_request_dp;
+		}
+	}
+
+	mxc_fbi->di = ipu_di_get(plat_data->display);
+	if (IS_ERR(mxc_fbi->di)) {
+		ret = PTR_ERR(mxc_fbi->di);
+		goto failed_request_di;
+	}
+
+	fbi->var.yres_virtual = fbi->var.yres;
+
+	INIT_LIST_HEAD(&fbi->modelist);
+	for (i = 0; i < plat_data->num_modes; i++)
+		fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
+
+	if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
+		for (i = 0; i < num_fb_modes; i++)
+			fb_add_videomode(&fb_modes[i], &fbi->modelist);
+	}
+
+	imx_ipu_fb_find_mode(fbi);
+
+	imx_ipu_fb_check_var(&fbi->var, fbi);
+	imx_ipu_fb_set_fix(fbi);
+	ret = register_framebuffer(fbi);
+	if (ret < 0)
+		goto failed_register;
+
+	imx_ipu_fb_set_par(fbi);
+	imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	platform_set_drvdata(pdev, fbi);
+
+	return 0;
+
+failed_register:
+	ipu_di_put(mxc_fbi->di);
+failed_request_di:
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+failed_request_dp:
+	ipu_dmfc_put(mxc_fbi->dmfc);
+failed_request_dmfc:
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+failed_request_ipu:
+	fb_dealloc_cmap(&fbi->cmap);
+	framebuffer_release(fbi);
+
+	return ret;
+}
+
+static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
+{
+	struct fb_info *fbi = platform_get_drvdata(pdev);
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
+
+	dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+
+	if (&fbi->cmap)
+		fb_dealloc_cmap(&fbi->cmap);
+
+	unregister_framebuffer(fbi);
+
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+	ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
+	ipu_dmfc_put(mxc_fbi->dmfc);
+	ipu_di_put(mxc_fbi->di);
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+
+	framebuffer_release(fbi);
+
+	return 0;
+}
+
+static struct platform_driver imx_ipu_fb_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+	.probe = imx_ipu_fb_probe,
+	.remove = __devexit_p(imx_ipu_fb_remove),
+};
+
+static int __init imx_ipu_fb_init(void)
+{
+	return platform_driver_register(&imx_ipu_fb_driver);
+}
+
+static void __exit imx_ipu_fb_exit(void)
+{
+	platform_driver_unregister(&imx_ipu_fb_driver);
+}
+
+module_init(imx_ipu_fb_init);
+module_exit(imx_ipu_fb_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-14 13:23             ` Liu Ying
  (?)
@ 2010-12-15 11:17               ` Sascha Hauer
  -1 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-15 11:17 UTC (permalink / raw)
  To: Liu Ying
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Zhang Lily-R58066,
	Arnaud Patard

On Tue, Dec 14, 2010 at 09:23:30PM +0800, Liu Ying wrote:
> 2010/12/14 Sascha Hauer <s.hauer@pengutronix.de>:
> > On Tue, Dec 14, 2010 at 02:40:09PM +0800, Liu Ying wrote:
> >> Hello, Sascha,
> >>
> >> Please find my feedback with [LY] embedded.
> >>
> >> And, a bug related with this patch:
> >> 1) Bootup the babbage board.
> >> 2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
> >> 3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
> >> 4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
> >> yres to be 960.
> >> 5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
> >> I think this is caused by 'var->yres_virtual = var->yres;' in custom
> >> fb_set_par() function(Sorry, I cannot make the comment inline this
> >> time, as I don't find the original code within the mail I am
> >> replying). This makes fb0 use only one block of memory whose size is
> >> equal to screen size, so pan display can not really play her role and
> >> screen tearing issue may happen.
> 
> Sascha,
> 
> Just would like to know if you've caught this bug.

Yes, it will be fixed in the next series. It was the framebuffer driver
forcing yres_virtual to yres in set_par.

Sascha

> 
> >>
> >> Best Regards,
> >> Liu Ying
> >>
> >> 2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
> >> > On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
> >> >> Hello, Sascha,
> >> >>
> >> >> I have following comments to this patch:
> >> >> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> >> >
> >> > ok.
> >> >
> >> >> 2) ADC is not supported yet in the framebuffer driver, so please
> >> >> modify this comment:
> >> >>    > + * Framebuffer Framebuffer Driver for SDC and ADC.
> >> >
> >> > ok.
> >> >
> >> >> 3) 'ipu_dp_set_window_pos()' is called only once in
> >> >> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> >> >> support to change the overlay framebuffer position. Need a
> >> >> mechanism/interface for users to change the overlay framebuffer
> >> >> position.
> >> >
> >> > Yes. The overlay support is currently only present in the driver because
> >> > I didn't want to break it in general. There is no generic overlay API in
> >> > the kernel and I didn't want to invent the n+1 API. Currently the
> >> > possible use cases of the overlay support are not clear to me. Number
> >> > one use case would probably be to display video output, but the
> >> > corresponding driver would be a v4l2 driver, so in this case we would
> >> > only need an in-kernel API.
> >> > Anyway, I have not the resources to implement complete overlay support.
> >> > So either we keep it like it is and it more has an example character
> >> > or we remove it completely from the driver for now.
> >> >
> >> >> 4) Need to make sure the framebuffer on DP-FG is blanked before the
> >> >> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
> >> >> should be unblanked after the framebuffer on DP-BG is unblanked
> >> >> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
> >> >> of the framebuffer on DP-BG.
> >> >
> >> > I tend to remove the overlay support.
> >> >
> >> >> 6) I prefer to find the video mode in modedb first, and if we cannot
> >> >> find the video mode in common video mode data base, we can find a
> >> >> video mode in custom video mode data base which is defined in platform
> >> >> data. In this way, we don't need to export common modefb.
> >> >
> >> > I exported the modedb to be able to show the different modes under
> >> > /sys/class/graphics/fb0/modes and to set it with
> >> > /sys/class/graphics/fb0/mode. If you want this there is no way around
> >> > exporting it. The ioctl interface for mode setting is independent of the
> >> > specific modes anyway.
> >> [LY]  Just a concern. If a platform choose to add the generic video
> >> mode data base to IPUv3 framebuffer modelist, 'cat
> >> /sys/class/graphics/fb0/modes' will show all the video modes in the
> >> generic data base to users. I am not sure whether showing them to
> >> users means the IPUv3 framebuffer driver acknowledges to support all
> >> of them or not. I tried to do 'echo U:1800x1440p-70 >
> >> /sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
> >> will be a kernel dump(seems it can not allocate enough memory).
> >
> > We'll have to increase the dma coherent size (and max zone order) for
> > these resolutions to work. I have patches for this in my local tree but
> > decided to wait until some contiguous memory allocator hits the tree.
> > Also, the fb driver should sanity check the generic modes before adding
> > them to the list. FOr example the IPU can't do 1920x1200@60. This code
> > is missing currently.
> >
> > Sascha
> >
> >
> > --
> > Pengutronix e.K.                           |                             |
> > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> >
> 
> 
> 
> -- 
> Best Regards,
> Liu Ying
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-15 11:17               ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-15 11:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 14, 2010 at 09:23:30PM +0800, Liu Ying wrote:
> 2010/12/14 Sascha Hauer <s.hauer@pengutronix.de>:
> > On Tue, Dec 14, 2010 at 02:40:09PM +0800, Liu Ying wrote:
> >> Hello, Sascha,
> >>
> >> Please find my feedback with [LY] embedded.
> >>
> >> And, a bug related with this patch:
> >> 1) Bootup the babbage board.
> >> 2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
> >> 3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
> >> 4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
> >> yres to be 960.
> >> 5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
> >> I think this is caused by 'var->yres_virtual = var->yres;' in custom
> >> fb_set_par() function(Sorry, I cannot make the comment inline this
> >> time, as I don't find the original code within the mail I am
> >> replying). This makes fb0 use only one block of memory whose size is
> >> equal to screen size, so pan display can not really play her role and
> >> screen tearing issue may happen.
> 
> Sascha,
> 
> Just would like to know if you've caught this bug.

Yes, it will be fixed in the next series. It was the framebuffer driver
forcing yres_virtual to yres in set_par.

Sascha

> 
> >>
> >> Best Regards,
> >> Liu Ying
> >>
> >> 2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
> >> > On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
> >> >> Hello, Sascha,
> >> >>
> >> >> I have following comments to this patch:
> >> >> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> >> >
> >> > ok.
> >> >
> >> >> 2) ADC is not supported yet in the framebuffer driver, so please
> >> >> modify this comment:
> >> >>    > + * Framebuffer Framebuffer Driver for SDC and ADC.
> >> >
> >> > ok.
> >> >
> >> >> 3) 'ipu_dp_set_window_pos()' is called only once in
> >> >> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> >> >> support to change the overlay framebuffer position. Need a
> >> >> mechanism/interface for users to change the overlay framebuffer
> >> >> position.
> >> >
> >> > Yes. The overlay support is currently only present in the driver because
> >> > I didn't want to break it in general. There is no generic overlay API in
> >> > the kernel and I didn't want to invent the n+1 API. Currently the
> >> > possible use cases of the overlay support are not clear to me. Number
> >> > one use case would probably be to display video output, but the
> >> > corresponding driver would be a v4l2 driver, so in this case we would
> >> > only need an in-kernel API.
> >> > Anyway, I have not the resources to implement complete overlay support.
> >> > So either we keep it like it is and it more has an example character
> >> > or we remove it completely from the driver for now.
> >> >
> >> >> 4) Need to make sure the framebuffer on DP-FG is blanked before the
> >> >> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
> >> >> should be unblanked after the framebuffer on DP-BG is unblanked
> >> >> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
> >> >> of the framebuffer on DP-BG.
> >> >
> >> > I tend to remove the overlay support.
> >> >
> >> >> 6) I prefer to find the video mode in modedb first, and if we cannot
> >> >> find the video mode in common video mode data base, we can find a
> >> >> video mode in custom video mode data base which is defined in platform
> >> >> data. In this way, we don't need to export common modefb.
> >> >
> >> > I exported the modedb to be able to show the different modes under
> >> > /sys/class/graphics/fb0/modes and to set it with
> >> > /sys/class/graphics/fb0/mode. If you want this there is no way around
> >> > exporting it. The ioctl interface for mode setting is independent of the
> >> > specific modes anyway.
> >> [LY]  Just a concern. If a platform choose to add the generic video
> >> mode data base to IPUv3 framebuffer modelist, 'cat
> >> /sys/class/graphics/fb0/modes' will show all the video modes in the
> >> generic data base to users. I am not sure whether showing them to
> >> users means the IPUv3 framebuffer driver acknowledges to support all
> >> of them or not. I tried to do 'echo U:1800x1440p-70 >
> >> /sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
> >> will be a kernel dump(seems it can not allocate enough memory).
> >
> > We'll have to increase the dma coherent size (and max zone order) for
> > these resolutions to work. I have patches for this in my local tree but
> > decided to wait until some contiguous memory allocator hits the tree.
> > Also, the fb driver should sanity check the generic modes before adding
> > them to the list. FOr example the IPU can't do 1920x1200@60. This code
> > is missing currently.
> >
> > Sascha
> >
> >
> > --
> > Pengutronix e.K.                           |                             |
> > Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> > Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> >
> 
> 
> 
> -- 
> Best Regards,
> Liu Ying
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-15 11:17               ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-15 11:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 14, 2010 at 09:23:30PM +0800, Liu Ying wrote:
> 2010/12/14 Sascha Hauer <s.hauer@pengutronix.de>:
> > On Tue, Dec 14, 2010 at 02:40:09PM +0800, Liu Ying wrote:
> >> Hello, Sascha,
> >>
> >> Please find my feedback with [LY] embedded.
> >>
> >> And, a bug related with this patch:
> >> 1) Bootup the babbage board.
> >> 2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
> >> 3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
> >> 4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
> >> yres to be 960.
> >> 5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
> >> I think this is caused by 'var->yres_virtual = var->yres;' in custom
> >> fb_set_par() function(Sorry, I cannot make the comment inline this
> >> time, as I don't find the original code within the mail I am
> >> replying). This makes fb0 use only one block of memory whose size is
> >> equal to screen size, so pan display can not really play her role and
> >> screen tearing issue may happen.
> 
> Sascha,
> 
> Just would like to know if you've caught this bug.

Yes, it will be fixed in the next series. It was the framebuffer driver
forcing yres_virtual to yres in set_par.

Sascha

> 
> >>
> >> Best Regards,
> >> Liu Ying
> >>
> >> 2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
> >> > On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
> >> >> Hello, Sascha,
> >> >>
> >> >> I have following comments to this patch:
> >> >> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> >> >
> >> > ok.
> >> >
> >> >> 2) ADC is not supported yet in the framebuffer driver, so please
> >> >> modify this comment:
> >> >> ? ?> + * Framebuffer Framebuffer Driver for SDC and ADC.
> >> >
> >> > ok.
> >> >
> >> >> 3) 'ipu_dp_set_window_pos()' is called only once in
> >> >> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> >> >> support to change the overlay framebuffer position. Need a
> >> >> mechanism/interface for users to change the overlay framebuffer
> >> >> position.
> >> >
> >> > Yes. The overlay support is currently only present in the driver because
> >> > I didn't want to break it in general. There is no generic overlay API in
> >> > the kernel and I didn't want to invent the n+1 API. Currently the
> >> > possible use cases of the overlay support are not clear to me. Number
> >> > one use case would probably be to display video output, but the
> >> > corresponding driver would be a v4l2 driver, so in this case we would
> >> > only need an in-kernel API.
> >> > Anyway, I have not the resources to implement complete overlay support.
> >> > So either we keep it like it is and it more has an example character
> >> > or we remove it completely from the driver for now.
> >> >
> >> >> 4) Need to make sure the framebuffer on DP-FG is blanked before the
> >> >> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
> >> >> should be unblanked after the framebuffer on DP-BG is unblanked
> >> >> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
> >> >> of the framebuffer on DP-BG.
> >> >
> >> > I tend to remove the overlay support.
> >> >
> >> >> 6) I prefer to find the video mode in modedb first, and if we cannot
> >> >> find the video mode in common video mode data base, we can find a
> >> >> video mode in custom video mode data base which is defined in platform
> >> >> data. In this way, we don't need to export common modefb.
> >> >
> >> > I exported the modedb to be able to show the different modes under
> >> > /sys/class/graphics/fb0/modes and to set it with
> >> > /sys/class/graphics/fb0/mode. If you want this there is no way around
> >> > exporting it. The ioctl interface for mode setting is independent of the
> >> > specific modes anyway.
> >> [LY] ?Just a concern. If a platform choose to add the generic video
> >> mode data base to IPUv3 framebuffer modelist, 'cat
> >> /sys/class/graphics/fb0/modes' will show all the video modes in the
> >> generic data base to users. I am not sure whether showing them to
> >> users means the IPUv3 framebuffer driver acknowledges to support all
> >> of them or not. I tried to do 'echo U:1800x1440p-70 >
> >> /sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
> >> will be a kernel dump(seems it can not allocate enough memory).
> >
> > We'll have to increase the dma coherent size (and max zone order) for
> > these resolutions to work. I have patches for this in my local tree but
> > decided to wait until some contiguous memory allocator hits the tree.
> > Also, the fb driver should sanity check the generic modes before adding
> > them to the list. FOr example the IPU can't do 1920x1200 at 60. This code
> > is missing currently.
> >
> > Sascha
> >
> >
> > --
> > Pengutronix e.K. ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
> > Industrial Linux Solutions ? ? ? ? ? ? ? ? | http://www.pengutronix.de/ ?|
> > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 ? ?|
> > Amtsgericht Hildesheim, HRA 2686 ? ? ? ? ? | Fax: ? +49-5121-206917-5555 |
> >
> 
> 
> 
> -- 
> Best Regards,
> Liu Ying
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-14  8:45           ` Sascha Hauer
  (?)
@ 2010-12-14 13:23             ` Liu Ying
  -1 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-14 13:23 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Zhang Lily-R58066,
	Arnaud Patard

2010/12/14 Sascha Hauer <s.hauer@pengutronix.de>:
> On Tue, Dec 14, 2010 at 02:40:09PM +0800, Liu Ying wrote:
>> Hello, Sascha,
>>
>> Please find my feedback with [LY] embedded.
>>
>> And, a bug related with this patch:
>> 1) Bootup the babbage board.
>> 2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
>> 3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
>> 4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
>> yres to be 960.
>> 5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
>> I think this is caused by 'var->yres_virtual = var->yres;' in custom
>> fb_set_par() function(Sorry, I cannot make the comment inline this
>> time, as I don't find the original code within the mail I am
>> replying). This makes fb0 use only one block of memory whose size is
>> equal to screen size, so pan display can not really play her role and
>> screen tearing issue may happen.

Sascha,

Just would like to know if you've caught this bug.

>>
>> Best Regards,
>> Liu Ying
>>
>> 2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
>> > On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
>> >> Hello, Sascha,
>> >>
>> >> I have following comments to this patch:
>> >> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
>> >
>> > ok.
>> >
>> >> 2) ADC is not supported yet in the framebuffer driver, so please
>> >> modify this comment:
>> >>    > + * Framebuffer Framebuffer Driver for SDC and ADC.
>> >
>> > ok.
>> >
>> >> 3) 'ipu_dp_set_window_pos()' is called only once in
>> >> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
>> >> support to change the overlay framebuffer position. Need a
>> >> mechanism/interface for users to change the overlay framebuffer
>> >> position.
>> >
>> > Yes. The overlay support is currently only present in the driver because
>> > I didn't want to break it in general. There is no generic overlay API in
>> > the kernel and I didn't want to invent the n+1 API. Currently the
>> > possible use cases of the overlay support are not clear to me. Number
>> > one use case would probably be to display video output, but the
>> > corresponding driver would be a v4l2 driver, so in this case we would
>> > only need an in-kernel API.
>> > Anyway, I have not the resources to implement complete overlay support.
>> > So either we keep it like it is and it more has an example character
>> > or we remove it completely from the driver for now.
>> >
>> >> 4) Need to make sure the framebuffer on DP-FG is blanked before the
>> >> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
>> >> should be unblanked after the framebuffer on DP-BG is unblanked
>> >> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
>> >> of the framebuffer on DP-BG.
>> >
>> > I tend to remove the overlay support.
>> >
>> >> 6) I prefer to find the video mode in modedb first, and if we cannot
>> >> find the video mode in common video mode data base, we can find a
>> >> video mode in custom video mode data base which is defined in platform
>> >> data. In this way, we don't need to export common modefb.
>> >
>> > I exported the modedb to be able to show the different modes under
>> > /sys/class/graphics/fb0/modes and to set it with
>> > /sys/class/graphics/fb0/mode. If you want this there is no way around
>> > exporting it. The ioctl interface for mode setting is independent of the
>> > specific modes anyway.
>> [LY]  Just a concern. If a platform choose to add the generic video
>> mode data base to IPUv3 framebuffer modelist, 'cat
>> /sys/class/graphics/fb0/modes' will show all the video modes in the
>> generic data base to users. I am not sure whether showing them to
>> users means the IPUv3 framebuffer driver acknowledges to support all
>> of them or not. I tried to do 'echo U:1800x1440p-70 >
>> /sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
>> will be a kernel dump(seems it can not allocate enough memory).
>
> We'll have to increase the dma coherent size (and max zone order) for
> these resolutions to work. I have patches for this in my local tree but
> decided to wait until some contiguous memory allocator hits the tree.
> Also, the fb driver should sanity check the generic modes before adding
> them to the list. FOr example the IPU can't do 1920x1200@60. This code
> is missing currently.
>
> Sascha
>
>
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>



-- 
Best Regards,
Liu Ying

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-14 13:23             ` Liu Ying
  0 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-14 13:23 UTC (permalink / raw)
  To: linux-arm-kernel

2010/12/14 Sascha Hauer <s.hauer@pengutronix.de>:
> On Tue, Dec 14, 2010 at 02:40:09PM +0800, Liu Ying wrote:
>> Hello, Sascha,
>>
>> Please find my feedback with [LY] embedded.
>>
>> And, a bug related with this patch:
>> 1) Bootup the babbage board.
>> 2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
>> 3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
>> 4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
>> yres to be 960.
>> 5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
>> I think this is caused by 'var->yres_virtual = var->yres;' in custom
>> fb_set_par() function(Sorry, I cannot make the comment inline this
>> time, as I don't find the original code within the mail I am
>> replying). This makes fb0 use only one block of memory whose size is
>> equal to screen size, so pan display can not really play her role and
>> screen tearing issue may happen.

Sascha,

Just would like to know if you've caught this bug.

>>
>> Best Regards,
>> Liu Ying
>>
>> 2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
>> > On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
>> >> Hello, Sascha,
>> >>
>> >> I have following comments to this patch:
>> >> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
>> >
>> > ok.
>> >
>> >> 2) ADC is not supported yet in the framebuffer driver, so please
>> >> modify this comment:
>> >>    > + * Framebuffer Framebuffer Driver for SDC and ADC.
>> >
>> > ok.
>> >
>> >> 3) 'ipu_dp_set_window_pos()' is called only once in
>> >> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
>> >> support to change the overlay framebuffer position. Need a
>> >> mechanism/interface for users to change the overlay framebuffer
>> >> position.
>> >
>> > Yes. The overlay support is currently only present in the driver because
>> > I didn't want to break it in general. There is no generic overlay API in
>> > the kernel and I didn't want to invent the n+1 API. Currently the
>> > possible use cases of the overlay support are not clear to me. Number
>> > one use case would probably be to display video output, but the
>> > corresponding driver would be a v4l2 driver, so in this case we would
>> > only need an in-kernel API.
>> > Anyway, I have not the resources to implement complete overlay support.
>> > So either we keep it like it is and it more has an example character
>> > or we remove it completely from the driver for now.
>> >
>> >> 4) Need to make sure the framebuffer on DP-FG is blanked before the
>> >> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
>> >> should be unblanked after the framebuffer on DP-BG is unblanked
>> >> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
>> >> of the framebuffer on DP-BG.
>> >
>> > I tend to remove the overlay support.
>> >
>> >> 6) I prefer to find the video mode in modedb first, and if we cannot
>> >> find the video mode in common video mode data base, we can find a
>> >> video mode in custom video mode data base which is defined in platform
>> >> data. In this way, we don't need to export common modefb.
>> >
>> > I exported the modedb to be able to show the different modes under
>> > /sys/class/graphics/fb0/modes and to set it with
>> > /sys/class/graphics/fb0/mode. If you want this there is no way around
>> > exporting it. The ioctl interface for mode setting is independent of the
>> > specific modes anyway.
>> [LY]  Just a concern. If a platform choose to add the generic video
>> mode data base to IPUv3 framebuffer modelist, 'cat
>> /sys/class/graphics/fb0/modes' will show all the video modes in the
>> generic data base to users. I am not sure whether showing them to
>> users means the IPUv3 framebuffer driver acknowledges to support all
>> of them or not. I tried to do 'echo U:1800x1440p-70 >
>> /sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
>> will be a kernel dump(seems it can not allocate enough memory).
>
> We'll have to increase the dma coherent size (and max zone order) for
> these resolutions to work. I have patches for this in my local tree but
> decided to wait until some contiguous memory allocator hits the tree.
> Also, the fb driver should sanity check the generic modes before adding
> them to the list. FOr example the IPU can't do 1920x1200@60. This code
> is missing currently.
>
> Sascha
>
>
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>



-- 
Best Regards,
Liu Ying

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-14 13:23             ` Liu Ying
  0 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-14 13:23 UTC (permalink / raw)
  To: linux-arm-kernel

2010/12/14 Sascha Hauer <s.hauer@pengutronix.de>:
> On Tue, Dec 14, 2010 at 02:40:09PM +0800, Liu Ying wrote:
>> Hello, Sascha,
>>
>> Please find my feedback with [LY] embedded.
>>
>> And, a bug related with this patch:
>> 1) Bootup the babbage board.
>> 2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
>> 3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
>> 4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
>> yres to be 960.
>> 5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
>> I think this is caused by 'var->yres_virtual = var->yres;' in custom
>> fb_set_par() function(Sorry, I cannot make the comment inline this
>> time, as I don't find the original code within the mail I am
>> replying). This makes fb0 use only one block of memory whose size is
>> equal to screen size, so pan display can not really play her role and
>> screen tearing issue may happen.

Sascha,

Just would like to know if you've caught this bug.

>>
>> Best Regards,
>> Liu Ying
>>
>> 2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
>> > On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
>> >> Hello, Sascha,
>> >>
>> >> I have following comments to this patch:
>> >> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
>> >
>> > ok.
>> >
>> >> 2) ADC is not supported yet in the framebuffer driver, so please
>> >> modify this comment:
>> >> ? ?> + * Framebuffer Framebuffer Driver for SDC and ADC.
>> >
>> > ok.
>> >
>> >> 3) 'ipu_dp_set_window_pos()' is called only once in
>> >> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
>> >> support to change the overlay framebuffer position. Need a
>> >> mechanism/interface for users to change the overlay framebuffer
>> >> position.
>> >
>> > Yes. The overlay support is currently only present in the driver because
>> > I didn't want to break it in general. There is no generic overlay API in
>> > the kernel and I didn't want to invent the n+1 API. Currently the
>> > possible use cases of the overlay support are not clear to me. Number
>> > one use case would probably be to display video output, but the
>> > corresponding driver would be a v4l2 driver, so in this case we would
>> > only need an in-kernel API.
>> > Anyway, I have not the resources to implement complete overlay support.
>> > So either we keep it like it is and it more has an example character
>> > or we remove it completely from the driver for now.
>> >
>> >> 4) Need to make sure the framebuffer on DP-FG is blanked before the
>> >> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
>> >> should be unblanked after the framebuffer on DP-BG is unblanked
>> >> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
>> >> of the framebuffer on DP-BG.
>> >
>> > I tend to remove the overlay support.
>> >
>> >> 6) I prefer to find the video mode in modedb first, and if we cannot
>> >> find the video mode in common video mode data base, we can find a
>> >> video mode in custom video mode data base which is defined in platform
>> >> data. In this way, we don't need to export common modefb.
>> >
>> > I exported the modedb to be able to show the different modes under
>> > /sys/class/graphics/fb0/modes and to set it with
>> > /sys/class/graphics/fb0/mode. If you want this there is no way around
>> > exporting it. The ioctl interface for mode setting is independent of the
>> > specific modes anyway.
>> [LY] ?Just a concern. If a platform choose to add the generic video
>> mode data base to IPUv3 framebuffer modelist, 'cat
>> /sys/class/graphics/fb0/modes' will show all the video modes in the
>> generic data base to users. I am not sure whether showing them to
>> users means the IPUv3 framebuffer driver acknowledges to support all
>> of them or not. I tried to do 'echo U:1800x1440p-70 >
>> /sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
>> will be a kernel dump(seems it can not allocate enough memory).
>
> We'll have to increase the dma coherent size (and max zone order) for
> these resolutions to work. I have patches for this in my local tree but
> decided to wait until some contiguous memory allocator hits the tree.
> Also, the fb driver should sanity check the generic modes before adding
> them to the list. FOr example the IPU can't do 1920x1200 at 60. This code
> is missing currently.
>
> Sascha
>
>
> --
> Pengutronix e.K. ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
> Industrial Linux Solutions ? ? ? ? ? ? ? ? | http://www.pengutronix.de/ ?|
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 ? ?|
> Amtsgericht Hildesheim, HRA 2686 ? ? ? ? ? | Fax: ? +49-5121-206917-5555 |
>



-- 
Best Regards,
Liu Ying

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-14  6:40         ` Liu Ying
  (?)
@ 2010-12-14  8:45           ` Sascha Hauer
  -1 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-14  8:45 UTC (permalink / raw)
  To: Liu Ying
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Zhang Lily-R58066,
	Arnaud Patard

On Tue, Dec 14, 2010 at 02:40:09PM +0800, Liu Ying wrote:
> Hello, Sascha,
> 
> Please find my feedback with [LY] embedded.
> 
> And, a bug related with this patch:
> 1) Bootup the babbage board.
> 2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
> 3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
> 4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
> yres to be 960.
> 5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
> I think this is caused by 'var->yres_virtual = var->yres;' in custom
> fb_set_par() function(Sorry, I cannot make the comment inline this
> time, as I don't find the original code within the mail I am
> replying). This makes fb0 use only one block of memory whose size is
> equal to screen size, so pan display can not really play her role and
> screen tearing issue may happen.
> 
> Best Regards,
> Liu Ying
> 
> 2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
> > On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
> >> Hello, Sascha,
> >>
> >> I have following comments to this patch:
> >> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> >
> > ok.
> >
> >> 2) ADC is not supported yet in the framebuffer driver, so please
> >> modify this comment:
> >>    > + * Framebuffer Framebuffer Driver for SDC and ADC.
> >
> > ok.
> >
> >> 3) 'ipu_dp_set_window_pos()' is called only once in
> >> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> >> support to change the overlay framebuffer position. Need a
> >> mechanism/interface for users to change the overlay framebuffer
> >> position.
> >
> > Yes. The overlay support is currently only present in the driver because
> > I didn't want to break it in general. There is no generic overlay API in
> > the kernel and I didn't want to invent the n+1 API. Currently the
> > possible use cases of the overlay support are not clear to me. Number
> > one use case would probably be to display video output, but the
> > corresponding driver would be a v4l2 driver, so in this case we would
> > only need an in-kernel API.
> > Anyway, I have not the resources to implement complete overlay support.
> > So either we keep it like it is and it more has an example character
> > or we remove it completely from the driver for now.
> >
> >> 4) Need to make sure the framebuffer on DP-FG is blanked before the
> >> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
> >> should be unblanked after the framebuffer on DP-BG is unblanked
> >> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
> >> of the framebuffer on DP-BG.
> >
> > I tend to remove the overlay support.
> >
> >> 6) I prefer to find the video mode in modedb first, and if we cannot
> >> find the video mode in common video mode data base, we can find a
> >> video mode in custom video mode data base which is defined in platform
> >> data. In this way, we don't need to export common modefb.
> >
> > I exported the modedb to be able to show the different modes under
> > /sys/class/graphics/fb0/modes and to set it with
> > /sys/class/graphics/fb0/mode. If you want this there is no way around
> > exporting it. The ioctl interface for mode setting is independent of the
> > specific modes anyway.
> [LY]  Just a concern. If a platform choose to add the generic video
> mode data base to IPUv3 framebuffer modelist, 'cat
> /sys/class/graphics/fb0/modes' will show all the video modes in the
> generic data base to users. I am not sure whether showing them to
> users means the IPUv3 framebuffer driver acknowledges to support all
> of them or not. I tried to do 'echo U:1800x1440p-70 >
> /sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
> will be a kernel dump(seems it can not allocate enough memory).

We'll have to increase the dma coherent size (and max zone order) for
these resolutions to work. I have patches for this in my local tree but
decided to wait until some contiguous memory allocator hits the tree.
Also, the fb driver should sanity check the generic modes before adding
them to the list. FOr example the IPU can't do 1920x1200@60. This code
is missing currently.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-14  8:45           ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-14  8:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 14, 2010 at 02:40:09PM +0800, Liu Ying wrote:
> Hello, Sascha,
> 
> Please find my feedback with [LY] embedded.
> 
> And, a bug related with this patch:
> 1) Bootup the babbage board.
> 2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
> 3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
> 4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
> yres to be 960.
> 5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
> I think this is caused by 'var->yres_virtual = var->yres;' in custom
> fb_set_par() function(Sorry, I cannot make the comment inline this
> time, as I don't find the original code within the mail I am
> replying). This makes fb0 use only one block of memory whose size is
> equal to screen size, so pan display can not really play her role and
> screen tearing issue may happen.
> 
> Best Regards,
> Liu Ying
> 
> 2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
> > On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
> >> Hello, Sascha,
> >>
> >> I have following comments to this patch:
> >> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> >
> > ok.
> >
> >> 2) ADC is not supported yet in the framebuffer driver, so please
> >> modify this comment:
> >>    > + * Framebuffer Framebuffer Driver for SDC and ADC.
> >
> > ok.
> >
> >> 3) 'ipu_dp_set_window_pos()' is called only once in
> >> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> >> support to change the overlay framebuffer position. Need a
> >> mechanism/interface for users to change the overlay framebuffer
> >> position.
> >
> > Yes. The overlay support is currently only present in the driver because
> > I didn't want to break it in general. There is no generic overlay API in
> > the kernel and I didn't want to invent the n+1 API. Currently the
> > possible use cases of the overlay support are not clear to me. Number
> > one use case would probably be to display video output, but the
> > corresponding driver would be a v4l2 driver, so in this case we would
> > only need an in-kernel API.
> > Anyway, I have not the resources to implement complete overlay support.
> > So either we keep it like it is and it more has an example character
> > or we remove it completely from the driver for now.
> >
> >> 4) Need to make sure the framebuffer on DP-FG is blanked before the
> >> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
> >> should be unblanked after the framebuffer on DP-BG is unblanked
> >> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
> >> of the framebuffer on DP-BG.
> >
> > I tend to remove the overlay support.
> >
> >> 6) I prefer to find the video mode in modedb first, and if we cannot
> >> find the video mode in common video mode data base, we can find a
> >> video mode in custom video mode data base which is defined in platform
> >> data. In this way, we don't need to export common modefb.
> >
> > I exported the modedb to be able to show the different modes under
> > /sys/class/graphics/fb0/modes and to set it with
> > /sys/class/graphics/fb0/mode. If you want this there is no way around
> > exporting it. The ioctl interface for mode setting is independent of the
> > specific modes anyway.
> [LY]  Just a concern. If a platform choose to add the generic video
> mode data base to IPUv3 framebuffer modelist, 'cat
> /sys/class/graphics/fb0/modes' will show all the video modes in the
> generic data base to users. I am not sure whether showing them to
> users means the IPUv3 framebuffer driver acknowledges to support all
> of them or not. I tried to do 'echo U:1800x1440p-70 >
> /sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
> will be a kernel dump(seems it can not allocate enough memory).

We'll have to increase the dma coherent size (and max zone order) for
these resolutions to work. I have patches for this in my local tree but
decided to wait until some contiguous memory allocator hits the tree.
Also, the fb driver should sanity check the generic modes before adding
them to the list. FOr example the IPU can't do 1920x1200@60. This code
is missing currently.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-14  8:45           ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-14  8:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 14, 2010 at 02:40:09PM +0800, Liu Ying wrote:
> Hello, Sascha,
> 
> Please find my feedback with [LY] embedded.
> 
> And, a bug related with this patch:
> 1) Bootup the babbage board.
> 2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
> 3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
> 4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
> yres to be 960.
> 5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
> I think this is caused by 'var->yres_virtual = var->yres;' in custom
> fb_set_par() function(Sorry, I cannot make the comment inline this
> time, as I don't find the original code within the mail I am
> replying). This makes fb0 use only one block of memory whose size is
> equal to screen size, so pan display can not really play her role and
> screen tearing issue may happen.
> 
> Best Regards,
> Liu Ying
> 
> 2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
> > On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
> >> Hello, Sascha,
> >>
> >> I have following comments to this patch:
> >> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
> >
> > ok.
> >
> >> 2) ADC is not supported yet in the framebuffer driver, so please
> >> modify this comment:
> >> ? ?> + * Framebuffer Framebuffer Driver for SDC and ADC.
> >
> > ok.
> >
> >> 3) 'ipu_dp_set_window_pos()' is called only once in
> >> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> >> support to change the overlay framebuffer position. Need a
> >> mechanism/interface for users to change the overlay framebuffer
> >> position.
> >
> > Yes. The overlay support is currently only present in the driver because
> > I didn't want to break it in general. There is no generic overlay API in
> > the kernel and I didn't want to invent the n+1 API. Currently the
> > possible use cases of the overlay support are not clear to me. Number
> > one use case would probably be to display video output, but the
> > corresponding driver would be a v4l2 driver, so in this case we would
> > only need an in-kernel API.
> > Anyway, I have not the resources to implement complete overlay support.
> > So either we keep it like it is and it more has an example character
> > or we remove it completely from the driver for now.
> >
> >> 4) Need to make sure the framebuffer on DP-FG is blanked before the
> >> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
> >> should be unblanked after the framebuffer on DP-BG is unblanked
> >> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
> >> of the framebuffer on DP-BG.
> >
> > I tend to remove the overlay support.
> >
> >> 6) I prefer to find the video mode in modedb first, and if we cannot
> >> find the video mode in common video mode data base, we can find a
> >> video mode in custom video mode data base which is defined in platform
> >> data. In this way, we don't need to export common modefb.
> >
> > I exported the modedb to be able to show the different modes under
> > /sys/class/graphics/fb0/modes and to set it with
> > /sys/class/graphics/fb0/mode. If you want this there is no way around
> > exporting it. The ioctl interface for mode setting is independent of the
> > specific modes anyway.
> [LY]  Just a concern. If a platform choose to add the generic video
> mode data base to IPUv3 framebuffer modelist, 'cat
> /sys/class/graphics/fb0/modes' will show all the video modes in the
> generic data base to users. I am not sure whether showing them to
> users means the IPUv3 framebuffer driver acknowledges to support all
> of them or not. I tried to do 'echo U:1800x1440p-70 >
> /sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
> will be a kernel dump(seems it can not allocate enough memory).

We'll have to increase the dma coherent size (and max zone order) for
these resolutions to work. I have patches for this in my local tree but
decided to wait until some contiguous memory allocator hits the tree.
Also, the fb driver should sanity check the generic modes before adding
them to the list. FOr example the IPU can't do 1920x1200 at 60. This code
is missing currently.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-13 11:38       ` Sascha Hauer
  (?)
@ 2010-12-14  6:40         ` Liu Ying
  -1 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-14  6:40 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Zhang Lily-R58066,
	Arnaud Patard

Hello, Sascha,

Please find my feedback with [LY] embedded.

And, a bug related with this patch:
1) Bootup the babbage board.
2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
yres to be 960.
5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
I think this is caused by 'var->yres_virtual = var->yres;' in custom
fb_set_par() function(Sorry, I cannot make the comment inline this
time, as I don't find the original code within the mail I am
replying). This makes fb0 use only one block of memory whose size is
equal to screen size, so pan display can not really play her role and
screen tearing issue may happen.

Best Regards,
Liu Ying

2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
> On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
>> Hello, Sascha,
>>
>> I have following comments to this patch:
>> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
>
> ok.
>
>> 2) ADC is not supported yet in the framebuffer driver, so please
>> modify this comment:
>>    > + * Framebuffer Framebuffer Driver for SDC and ADC.
>
> ok.
>
>> 3) 'ipu_dp_set_window_pos()' is called only once in
>> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
>> support to change the overlay framebuffer position. Need a
>> mechanism/interface for users to change the overlay framebuffer
>> position.
>
> Yes. The overlay support is currently only present in the driver because
> I didn't want to break it in general. There is no generic overlay API in
> the kernel and I didn't want to invent the n+1 API. Currently the
> possible use cases of the overlay support are not clear to me. Number
> one use case would probably be to display video output, but the
> corresponding driver would be a v4l2 driver, so in this case we would
> only need an in-kernel API.
> Anyway, I have not the resources to implement complete overlay support.
> So either we keep it like it is and it more has an example character
> or we remove it completely from the driver for now.
>
>> 4) Need to make sure the framebuffer on DP-FG is blanked before the
>> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
>> should be unblanked after the framebuffer on DP-BG is unblanked
>> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
>> of the framebuffer on DP-BG.
>
> I tend to remove the overlay support.
>
>> 6) I prefer to find the video mode in modedb first, and if we cannot
>> find the video mode in common video mode data base, we can find a
>> video mode in custom video mode data base which is defined in platform
>> data. In this way, we don't need to export common modefb.
>
> I exported the modedb to be able to show the different modes under
> /sys/class/graphics/fb0/modes and to set it with
> /sys/class/graphics/fb0/mode. If you want this there is no way around
> exporting it. The ioctl interface for mode setting is independent of the
> specific modes anyway.
[LY]  Just a concern. If a platform choose to add the generic video
mode data base to IPUv3 framebuffer modelist, 'cat
/sys/class/graphics/fb0/modes' will show all the video modes in the
generic data base to users. I am not sure whether showing them to
users means the IPUv3 framebuffer driver acknowledges to support all
of them or not. I tried to do 'echo U:1800x1440p-70 >
/sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
will be a kernel dump(seems it can not allocate enough memory).
>
> BTW please make comments specific to specific code inline.
[LY] Ok.
>
> Sascha
>
>
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-14  6:40         ` Liu Ying
  0 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-14  6:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hello, Sascha,

Please find my feedback with [LY] embedded.

And, a bug related with this patch:
1) Bootup the babbage board.
2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
yres to be 960.
5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
I think this is caused by 'var->yres_virtual = var->yres;' in custom
fb_set_par() function(Sorry, I cannot make the comment inline this
time, as I don't find the original code within the mail I am
replying). This makes fb0 use only one block of memory whose size is
equal to screen size, so pan display can not really play her role and
screen tearing issue may happen.

Best Regards,
Liu Ying

2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
> On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
>> Hello, Sascha,
>>
>> I have following comments to this patch:
>> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
>
> ok.
>
>> 2) ADC is not supported yet in the framebuffer driver, so please
>> modify this comment:
>>    > + * Framebuffer Framebuffer Driver for SDC and ADC.
>
> ok.
>
>> 3) 'ipu_dp_set_window_pos()' is called only once in
>> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
>> support to change the overlay framebuffer position. Need a
>> mechanism/interface for users to change the overlay framebuffer
>> position.
>
> Yes. The overlay support is currently only present in the driver because
> I didn't want to break it in general. There is no generic overlay API in
> the kernel and I didn't want to invent the n+1 API. Currently the
> possible use cases of the overlay support are not clear to me. Number
> one use case would probably be to display video output, but the
> corresponding driver would be a v4l2 driver, so in this case we would
> only need an in-kernel API.
> Anyway, I have not the resources to implement complete overlay support.
> So either we keep it like it is and it more has an example character
> or we remove it completely from the driver for now.
>
>> 4) Need to make sure the framebuffer on DP-FG is blanked before the
>> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
>> should be unblanked after the framebuffer on DP-BG is unblanked
>> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
>> of the framebuffer on DP-BG.
>
> I tend to remove the overlay support.
>
>> 6) I prefer to find the video mode in modedb first, and if we cannot
>> find the video mode in common video mode data base, we can find a
>> video mode in custom video mode data base which is defined in platform
>> data. In this way, we don't need to export common modefb.
>
> I exported the modedb to be able to show the different modes under
> /sys/class/graphics/fb0/modes and to set it with
> /sys/class/graphics/fb0/mode. If you want this there is no way around
> exporting it. The ioctl interface for mode setting is independent of the
> specific modes anyway.
[LY]  Just a concern. If a platform choose to add the generic video
mode data base to IPUv3 framebuffer modelist, 'cat
/sys/class/graphics/fb0/modes' will show all the video modes in the
generic data base to users. I am not sure whether showing them to
users means the IPUv3 framebuffer driver acknowledges to support all
of them or not. I tried to do 'echo U:1800x1440p-70 >
/sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
will be a kernel dump(seems it can not allocate enough memory).
>
> BTW please make comments specific to specific code inline.
[LY] Ok.
>
> Sascha
>
>
> --
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-14  6:40         ` Liu Ying
  0 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-14  6:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hello, Sascha,

Please find my feedback with [LY] embedded.

And, a bug related with this patch:
1) Bootup the babbage board.
2) echo U:640x480p-60 > /sys/class/graphics/fb0/mode
3) cat /sys/class/graphics/fb0/virtual_size, it shows '640,480'.
4) echo 640,960 > /sys/class/graphics/fb0/virtual_size, change virtual
yres to be 960.
5) cat /sys/class/graphics/fb0/virtual_size, it still shows '640,480'.
I think this is caused by 'var->yres_virtual = var->yres;' in custom
fb_set_par() function(Sorry, I cannot make the comment inline this
time, as I don't find the original code within the mail I am
replying). This makes fb0 use only one block of memory whose size is
equal to screen size, so pan display can not really play her role and
screen tearing issue may happen.

Best Regards,
Liu Ying

2010/12/13 Sascha Hauer <s.hauer@pengutronix.de>:
> On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
>> Hello, Sascha,
>>
>> I have following comments to this patch:
>> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
>
> ok.
>
>> 2) ADC is not supported yet in the framebuffer driver, so please
>> modify this comment:
>> ? ?> + * Framebuffer Framebuffer Driver for SDC and ADC.
>
> ok.
>
>> 3) 'ipu_dp_set_window_pos()' is called only once in
>> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
>> support to change the overlay framebuffer position. Need a
>> mechanism/interface for users to change the overlay framebuffer
>> position.
>
> Yes. The overlay support is currently only present in the driver because
> I didn't want to break it in general. There is no generic overlay API in
> the kernel and I didn't want to invent the n+1 API. Currently the
> possible use cases of the overlay support are not clear to me. Number
> one use case would probably be to display video output, but the
> corresponding driver would be a v4l2 driver, so in this case we would
> only need an in-kernel API.
> Anyway, I have not the resources to implement complete overlay support.
> So either we keep it like it is and it more has an example character
> or we remove it completely from the driver for now.
>
>> 4) Need to make sure the framebuffer on DP-FG is blanked before the
>> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
>> should be unblanked after the framebuffer on DP-BG is unblanked
>> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
>> of the framebuffer on DP-BG.
>
> I tend to remove the overlay support.
>
>> 6) I prefer to find the video mode in modedb first, and if we cannot
>> find the video mode in common video mode data base, we can find a
>> video mode in custom video mode data base which is defined in platform
>> data. In this way, we don't need to export common modefb.
>
> I exported the modedb to be able to show the different modes under
> /sys/class/graphics/fb0/modes and to set it with
> /sys/class/graphics/fb0/mode. If you want this there is no way around
> exporting it. The ioctl interface for mode setting is independent of the
> specific modes anyway.
[LY]  Just a concern. If a platform choose to add the generic video
mode data base to IPUv3 framebuffer modelist, 'cat
/sys/class/graphics/fb0/modes' will show all the video modes in the
generic data base to users. I am not sure whether showing them to
users means the IPUv3 framebuffer driver acknowledges to support all
of them or not. I tried to do 'echo U:1800x1440p-70 >
/sys/class/graphics/fb0/mode' with the kernel on ipuv3 branch, there
will be a kernel dump(seems it can not allocate enough memory).
>
> BTW please make comments specific to specific code inline.
[LY] Ok.
>
> Sascha
>
>
> --
> Pengutronix e.K. ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
> Industrial Linux Solutions ? ? ? ? ? ? ? ? | http://www.pengutronix.de/ ?|
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 ? ?|
> Amtsgericht Hildesheim, HRA 2686 ? ? ? ? ? | Fax: ? +49-5121-206917-5555 |
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-12  6:13     ` Liu Ying
  (?)
@ 2010-12-13 11:38       ` Sascha Hauer
  -1 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-13 11:38 UTC (permalink / raw)
  To: Liu Ying
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Zhang Lily-R58066,
	Arnaud Patard

On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
> Hello, Sascha,
> 
> I have following comments to this patch:
> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.

ok.

> 2) ADC is not supported yet in the framebuffer driver, so please
> modify this comment:
>    > + * Framebuffer Framebuffer Driver for SDC and ADC.

ok.

> 3) 'ipu_dp_set_window_pos()' is called only once in
> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> support to change the overlay framebuffer position. Need a
> mechanism/interface for users to change the overlay framebuffer
> position.

Yes. The overlay support is currently only present in the driver because
I didn't want to break it in general. There is no generic overlay API in
the kernel and I didn't want to invent the n+1 API. Currently the
possible use cases of the overlay support are not clear to me. Number
one use case would probably be to display video output, but the
corresponding driver would be a v4l2 driver, so in this case we would
only need an in-kernel API.
Anyway, I have not the resources to implement complete overlay support.
So either we keep it like it is and it more has an example character
or we remove it completely from the driver for now.

> 4) Need to make sure the framebuffer on DP-FG is blanked before the
> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
> should be unblanked after the framebuffer on DP-BG is unblanked
> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
> of the framebuffer on DP-BG.

I tend to remove the overlay support.

> 6) I prefer to find the video mode in modedb first, and if we cannot
> find the video mode in common video mode data base, we can find a
> video mode in custom video mode data base which is defined in platform
> data. In this way, we don't need to export common modefb.

I exported the modedb to be able to show the different modes under
/sys/class/graphics/fb0/modes and to set it with
/sys/class/graphics/fb0/mode. If you want this there is no way around
exporting it. The ioctl interface for mode setting is independent of the
specific modes anyway.

BTW please make comments specific to specific code inline.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-13 11:38       ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-13 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
> Hello, Sascha,
> 
> I have following comments to this patch:
> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.

ok.

> 2) ADC is not supported yet in the framebuffer driver, so please
> modify this comment:
>    > + * Framebuffer Framebuffer Driver for SDC and ADC.

ok.

> 3) 'ipu_dp_set_window_pos()' is called only once in
> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> support to change the overlay framebuffer position. Need a
> mechanism/interface for users to change the overlay framebuffer
> position.

Yes. The overlay support is currently only present in the driver because
I didn't want to break it in general. There is no generic overlay API in
the kernel and I didn't want to invent the n+1 API. Currently the
possible use cases of the overlay support are not clear to me. Number
one use case would probably be to display video output, but the
corresponding driver would be a v4l2 driver, so in this case we would
only need an in-kernel API.
Anyway, I have not the resources to implement complete overlay support.
So either we keep it like it is and it more has an example character
or we remove it completely from the driver for now.

> 4) Need to make sure the framebuffer on DP-FG is blanked before the
> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
> should be unblanked after the framebuffer on DP-BG is unblanked
> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
> of the framebuffer on DP-BG.

I tend to remove the overlay support.

> 6) I prefer to find the video mode in modedb first, and if we cannot
> find the video mode in common video mode data base, we can find a
> video mode in custom video mode data base which is defined in platform
> data. In this way, we don't need to export common modefb.

I exported the modedb to be able to show the different modes under
/sys/class/graphics/fb0/modes and to set it with
/sys/class/graphics/fb0/mode. If you want this there is no way around
exporting it. The ioctl interface for mode setting is independent of the
specific modes anyway.

BTW please make comments specific to specific code inline.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-13 11:38       ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-13 11:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Dec 12, 2010 at 02:13:40PM +0800, Liu Ying wrote:
> Hello, Sascha,
> 
> I have following comments to this patch:
> 1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.

ok.

> 2) ADC is not supported yet in the framebuffer driver, so please
> modify this comment:
>    > + * Framebuffer Framebuffer Driver for SDC and ADC.

ok.

> 3) 'ipu_dp_set_window_pos()' is called only once in
> imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
> support to change the overlay framebuffer position. Need a
> mechanism/interface for users to change the overlay framebuffer
> position.

Yes. The overlay support is currently only present in the driver because
I didn't want to break it in general. There is no generic overlay API in
the kernel and I didn't want to invent the n+1 API. Currently the
possible use cases of the overlay support are not clear to me. Number
one use case would probably be to display video output, but the
corresponding driver would be a v4l2 driver, so in this case we would
only need an in-kernel API.
Anyway, I have not the resources to implement complete overlay support.
So either we keep it like it is and it more has an example character
or we remove it completely from the driver for now.

> 4) Need to make sure the framebuffer on DP-FG is blanked before the
> framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
> should be unblanked after the framebuffer on DP-BG is unblanked
> 5) Need to check the framebuffer on DP-FG doesn't run out of the range
> of the framebuffer on DP-BG.

I tend to remove the overlay support.

> 6) I prefer to find the video mode in modedb first, and if we cannot
> find the video mode in common video mode data base, we can find a
> video mode in custom video mode data base which is defined in platform
> data. In this way, we don't need to export common modefb.

I exported the modedb to be able to show the different modes under
/sys/class/graphics/fb0/modes and to set it with
/sys/class/graphics/fb0/mode. If you want this there is no way around
exporting it. The ioctl interface for mode setting is independent of the
specific modes anyway.

BTW please make comments specific to specific code inline.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-13  7:23       ` Lothar Waßmann
  (?)
@ 2010-12-13 11:35         ` Liu Ying
  -1 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-13 11:35 UTC (permalink / raw)
  To: Lothar Waßmann
  Cc: Sascha Hauer, Arnaud Patard, linux-fbdev, Zhang Lily-R58066,
	linux-kernel, linux-arm-kernel

Hello, Lothar Waßmann,

I think your opinion is reasonable and better.
So, first, we can find the video mode in the video mode data base
defined in platform data, and then, if this fails, we can find it in
common video mode data base.

Best Regards,
Liu Ying

2010/12/13 Lothar Waßmann <LW@karo-electronics.de>:
> Hi,
>
> Liu Ying writes:
>> 6) I prefer to find the video mode in modedb first, and if we cannot
>> find the video mode in common video mode data base, we can find a
>> video mode in custom video mode data base which is defined in platform
>> data. In this way, we don't need to export common modefb.
>>
> IMO platform specific video modes should take precedence over generic
> ones, so the platform data should be evaluated first.
>
>
> Lothar Waßmann
> --
> ___________________________________________________________
>
> Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
> Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
> Geschäftsführer: Matthias Kaussen
> Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
>
> www.karo-electronics.de | info@karo-electronics.de
> ___________________________________________________________
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-13 11:35         ` Liu Ying
  0 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-13 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hello, Lothar Waßmann,

I think your opinion is reasonable and better.
So, first, we can find the video mode in the video mode data base
defined in platform data, and then, if this fails, we can find it in
common video mode data base.

Best Regards,
Liu Ying

2010/12/13 Lothar Waßmann <LW@karo-electronics.de>:
> Hi,
>
> Liu Ying writes:
>> 6) I prefer to find the video mode in modedb first, and if we cannot
>> find the video mode in common video mode data base, we can find a
>> video mode in custom video mode data base which is defined in platform
>> data. In this way, we don't need to export common modefb.
>>
> IMO platform specific video modes should take precedence over generic
> ones, so the platform data should be evaluated first.
>
>
> Lothar Waßmann
> --
> ___________________________________________________________
>
> Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
> Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
> Geschäftsführer: Matthias Kaussen
> Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
>
> www.karo-electronics.de | info@karo-electronics.de
> ___________________________________________________________
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-13 11:35         ` Liu Ying
  0 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-13 11:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hello, Lothar Wa?mann,

I think your opinion is reasonable and better.
So, first, we can find the video mode in the video mode data base
defined in platform data, and then, if this fails, we can find it in
common video mode data base.

Best Regards,
Liu Ying

2010/12/13 Lothar Wa?mann <LW@karo-electronics.de>:
> Hi,
>
> Liu Ying writes:
>> 6) I prefer to find the video mode in modedb first, and if we cannot
>> find the video mode in common video mode data base, we can find a
>> video mode in custom video mode data base which is defined in platform
>> data. In this way, we don't need to export common modefb.
>>
> IMO platform specific video modes should take precedence over generic
> ones, so the platform data should be evaluated first.
>
>
> Lothar Wa?mann
> --
> ___________________________________________________________
>
> Ka-Ro electronics GmbH | Pascalstra?e 22 | D - 52076 Aachen
> Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
> Gesch?ftsf?hrer: Matthias Kaussen
> Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
>
> www.karo-electronics.de | info at karo-electronics.de
> ___________________________________________________________
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-12  6:13     ` Liu Ying
  (?)
@ 2010-12-13  7:23       ` Lothar Waßmann
  -1 siblings, 0 replies; 37+ messages in thread
From: Lothar Waßmann @ 2010-12-13  7:23 UTC (permalink / raw)
  To: Liu Ying
  Cc: Sascha Hauer, Arnaud Patard, linux-fbdev, Zhang Lily-R58066,
	linux-kernel, linux-arm-kernel

Hi,

Liu Ying writes:
> 6) I prefer to find the video mode in modedb first, and if we cannot
> find the video mode in common video mode data base, we can find a
> video mode in custom video mode data base which is defined in platform
> data. In this way, we don't need to export common modefb.
> 
IMO platform specific video modes should take precedence over generic
ones, so the platform data should be evaluated first.


Lothar Waßmann
-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info@karo-electronics.de
___________________________________________________________

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-13  7:23       ` Lothar Waßmann
  0 siblings, 0 replies; 37+ messages in thread
From: Lothar Waßmann @ 2010-12-13  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Liu Ying writes:
> 6) I prefer to find the video mode in modedb first, and if we cannot
> find the video mode in common video mode data base, we can find a
> video mode in custom video mode data base which is defined in platform
> data. In this way, we don't need to export common modefb.
> 
IMO platform specific video modes should take precedence over generic
ones, so the platform data should be evaluated first.


Lothar Waßmann
-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info@karo-electronics.de
___________________________________________________________

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-13  7:23       ` Lothar Waßmann
  0 siblings, 0 replies; 37+ messages in thread
From: Lothar Waßmann @ 2010-12-13  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Liu Ying writes:
> 6) I prefer to find the video mode in modedb first, and if we cannot
> find the video mode in common video mode data base, we can find a
> video mode in custom video mode data base which is defined in platform
> data. In this way, we don't need to export common modefb.
> 
IMO platform specific video modes should take precedence over generic
ones, so the platform data should be evaluated first.


Lothar Wa?mann
-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstra?e 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Gesch?ftsf?hrer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-09 13:47   ` Sascha Hauer
  (?)
@ 2010-12-12  6:13     ` Liu Ying
  -1 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-12  6:13 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Zhang Lily-R58066,
	Arnaud Patard

Hello, Sascha,

I have following comments to this patch:
1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
2) ADC is not supported yet in the framebuffer driver, so please
modify this comment:
   > + * Framebuffer Framebuffer Driver for SDC and ADC.
3) 'ipu_dp_set_window_pos()' is called only once in
imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
support to change the overlay framebuffer position. Need a
mechanism/interface for users to change the overlay framebuffer
position.
4) Need to make sure the framebuffer on DP-FG is blanked before the
framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
should be unblanked after the framebuffer on DP-BG is unblanked
5) Need to check the framebuffer on DP-FG doesn't run out of the range
of the framebuffer on DP-BG.
6) I prefer to find the video mode in modedb first, and if we cannot
find the video mode in common video mode data base, we can find a
video mode in custom video mode data base which is defined in platform
data. In this way, we don't need to export common modefb.

Best Regards,
Liu Ying


2010/12/9 Sascha Hauer <s.hauer@pengutronix.de>:
> This patch adds framebuffer support to the Freescale i.MX SoCs
> equipped with an IPU v3, so far these are the i.MX50/51/53.
>
> This driver has been tested on the i.MX51 babbage board with
> both DVI and analog VGA in different resolutions and color depths.
> It has also been tested on a custom i.MX51 board using a fixed
> resolution panel.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/video/Kconfig  |   11 +
>  drivers/video/Makefile |    1 +
>  drivers/video/mx5fb.c  |  846 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 858 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/video/mx5fb.c
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 27c1fb4..1901915 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -2236,6 +2236,17 @@ config FB_MX3
>          far only synchronous displays are supported. If you plan to use
>          an LCD display with your i.MX31 system, say Y here.
>
> +config FB_MX5
> +       tristate "MX5 Framebuffer support"
> +       depends on FB && MFD_IMX_IPU_V3
> +       select FB_CFB_FILLRECT
> +       select FB_CFB_COPYAREA
> +       select FB_CFB_IMAGEBLIT
> +       select FB_MODE_HELPERS
> +       help
> +         This is a framebuffer device for the i.MX51 LCD Controller. If you
> +         plan to use an LCD display with your i.MX51 system, say Y here.
> +
>  config FB_BROADSHEET
>        tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
>        depends on FB
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 485e8ed..ad408d2 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043)          += bf54x-lq043fb.o
>  obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
>  obj-$(CONFIG_FB_BFIN_T350MCQB)   += bfin-t350mcqb-fb.o
>  obj-$(CONFIG_FB_MX3)             += mx3fb.o
> +obj-$(CONFIG_FB_MX5)             += mx5fb.o
>  obj-$(CONFIG_FB_DA8XX)           += da8xx-fb.o
>
>  # the test framebuffer is last
> diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
> new file mode 100644
> index 0000000..fd9baf4
> --- /dev/null
> +++ b/drivers/video/mx5fb.c
> @@ -0,0 +1,846 @@
> +/*
> + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + *
> + * Framebuffer Framebuffer Driver for SDC and ADC.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <linux/fb.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/console.h>
> +#include <linux/mfd/imx-ipu-v3.h>
> +#include <asm/uaccess.h>
> +#include <mach/ipu-v3.h>
> +
> +#define DRIVER_NAME "imx-ipuv3-fb"
> +
> +struct imx_ipu_fb_info {
> +       int                     ipu_channel_num;
> +       struct ipu_channel      *ipu_ch;
> +       int                     dc;
> +       int                     ipu_di;
> +       u32                     ipu_di_pix_fmt;
> +       u32                     ipu_in_pix_fmt;
> +
> +       u32                     pseudo_palette[16];
> +
> +       struct ipu_dp           *dp;
> +       struct dmfc_channel     *dmfc;
> +       struct fb_info          *slave;
> +       struct fb_info          *master;
> +       bool                    enabled;
> +};
> +
> +static int imx_ipu_fb_set_fix(struct fb_info *info)
> +{
> +       struct fb_fix_screeninfo *fix = &info->fix;
> +       struct fb_var_screeninfo *var = &info->var;
> +
> +       fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> +       fix->type = FB_TYPE_PACKED_PIXELS;
> +       fix->accel = FB_ACCEL_NONE;
> +       fix->visual = FB_VISUAL_TRUECOLOR;
> +       fix->xpanstep = 1;
> +       fix->ypanstep = 1;
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
> +{
> +       int size;
> +
> +       size = fbi->var.yres_virtual * fbi->fix.line_length;
> +
> +       if (fbi->screen_base) {
> +               if (fbi->fix.smem_len >= size)
> +                       return 0;
> +
> +               dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> +                             fbi->screen_base, fbi->fix.smem_start);
> +       }
> +
> +       fbi->screen_base = dma_alloc_writecombine(fbi->device,
> +                               size,
> +                               (dma_addr_t *)&fbi->fix.smem_start,
> +                               GFP_DMA);
> +       if (fbi->screen_base == 0) {
> +               dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
> +                               fbi->fix.smem_len);
> +               fbi->fix.smem_len = 0;
> +               fbi->fix.smem_start = 0;
> +               return -ENOMEM;
> +       }
> +
> +       fbi->fix.smem_len = size;
> +       fbi->screen_size = fbi->fix.smem_len;
> +
> +       dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
> +               fbi->fix.smem_start, fbi->fix.smem_len);
> +
> +       /* Clear the screen */
> +       memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
> +
> +       return 0;
> +}
> +
> +static void imx_ipu_fb_enable(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       if (mxc_fbi->enabled)
> +               return;
> +
> +       ipu_di_enable(mxc_fbi->ipu_di);
> +       ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> +       ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> +       ipu_dc_enable_channel(mxc_fbi->dc);
> +       ipu_dp_enable_channel(mxc_fbi->dp);
> +       mxc_fbi->enabled = 1;
> +}
> +
> +static void imx_ipu_fb_disable(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       if (!mxc_fbi->enabled)
> +               return;
> +
> +       ipu_dp_disable_channel(mxc_fbi->dp);
> +       ipu_dc_disable_channel(mxc_fbi->dc);
> +       ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> +       ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> +       ipu_di_disable(mxc_fbi->ipu_di);
> +
> +       mxc_fbi->enabled = 0;
> +}
> +
> +static int calc_vref(struct fb_var_screeninfo *var)
> +{
> +       unsigned long htotal, vtotal;
> +
> +       htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
> +       vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
> +
> +       if (!htotal || !vtotal)
> +               return 60;
> +
> +       return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
> +}
> +
> +static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
> +{
> +       return var->xres * var->yres * vref;
> +}
> +
> +static int imx_ipu_fb_set_par(struct fb_info *fbi)
> +{
> +       int ret;
> +       struct ipu_di_signal_cfg sig_cfg;
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       u32 out_pixel_fmt;
> +       int interlaced = 0;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       int enabled = mxc_fbi->enabled;
> +
> +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> +       if (enabled)
> +               imx_ipu_fb_disable(fbi);
> +
> +       fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> +       var->yres_virtual = var->yres;
> +
> +       ret = imx_ipu_fb_map_video_memory(fbi);
> +       if (ret)
> +               return ret;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               sig_cfg.interlaced = 1;
> +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> +               sig_cfg.odd_field_first = 1;
> +       if (var->sync & FB_SYNC_EXT)
> +               sig_cfg.ext_clk = 1;
> +       if (var->sync & FB_SYNC_HOR_HIGH_ACT)
> +               sig_cfg.Hsync_pol = 1;
> +       if (var->sync & FB_SYNC_VERT_HIGH_ACT)
> +               sig_cfg.Vsync_pol = 1;
> +       if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
> +               sig_cfg.clk_pol = 1;
> +       if (var->sync & FB_SYNC_DATA_INVERT)
> +               sig_cfg.data_pol = 1;
> +       if (!(var->sync & FB_SYNC_OE_LOW_ACT))
> +               sig_cfg.enable_pol = 1;
> +       if (var->sync & FB_SYNC_CLK_IDLE_EN)
> +               sig_cfg.clkidle_en = 1;
> +
> +       dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
> +               PICOS2KHZ(var->pixclock) / 1000,
> +               PICOS2KHZ(var->pixclock) % 1000);
> +
> +       sig_cfg.width = var->xres;
> +       sig_cfg.height = var->yres;
> +       sig_cfg.pixel_fmt = out_pixel_fmt;
> +       sig_cfg.h_start_width = var->left_margin;
> +       sig_cfg.h_sync_width = var->hsync_len;
> +       sig_cfg.h_end_width = var->right_margin;
> +       sig_cfg.v_start_width = var->upper_margin;
> +       sig_cfg.v_sync_width = var->vsync_len;
> +       sig_cfg.v_end_width = var->lower_margin;
> +       sig_cfg.v_to_h_sync = 0;
> +
> +       if (mxc_fbi->dp) {
> +               ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
> +                               out_pixel_fmt, 1);
> +               if (ret) {
> +                       dev_dbg(fbi->device, "initializing display processor failed with %d\n",
> +                               ret);
> +                       return ret;
> +               }
> +       }
> +
> +       ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->ipu_di, interlaced,
> +                       out_pixel_fmt, fbi->var.xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing display controller failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_di_init_sync_panel(mxc_fbi->ipu_di,
> +                               PICOS2KHZ(var->pixclock) * 1000UL,
> +                               &sig_cfg);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing panel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
> +       var->xoffset = var->yoffset = 0;
> +
> +       if (fbi->var.vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> +                                       mxc_fbi->ipu_in_pix_fmt,
> +                                       var->xres, var->yres,
> +                                       fbi->fix.line_length,
> +                                       IPU_ROTATE_NONE,
> +                                       fbi->fix.smem_start,
> +                                       0,
> +                                       0, 0, interlaced);
> +       if (ret) {
> +               dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
> +       if (ret) {
> +               dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       if (enabled)
> +               imx_ipu_fb_enable(fbi);
> +
> +       return ret;
> +}
> +
> +/*
> + * These are the bitfields for each
> + * display depth that we support.
> + */
> +struct imxfb_rgb {
> +       struct fb_bitfield      red;
> +       struct fb_bitfield      green;
> +       struct fb_bitfield      blue;
> +       struct fb_bitfield      transp;
> +};
> +
> +static struct imxfb_rgb def_rgb_8 = {
> +       .red    = { .offset =  5, .length = 3, },
> +       .green  = { .offset =  2, .length = 3, },
> +       .blue   = { .offset =  0, .length = 2, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_16 = {
> +       .red    = { .offset = 11, .length = 5, },
> +       .green  = { .offset =  5, .length = 6, },
> +       .blue   = { .offset =  0, .length = 5, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_24 = {
> +       .red    = { .offset = 16, .length = 8, },
> +       .green  = { .offset =  8, .length = 8, },
> +       .blue   = { .offset =  0, .length = 8, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_32 = {
> +       .red    = { .offset = 16, .length = 8, },
> +       .green  = { .offset =  8, .length = 8, },
> +       .blue   = { .offset =  0, .length = 8, },
> +       .transp = { .offset = 24, .length = 8, },
> +};
> +
> +/*
> + * Check framebuffer variable parameters and adjust to valid values.
> + *
> + * @param       var      framebuffer variable parameters
> + *
> + * @param       info     framebuffer information pointer
> + */
> +static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> +       struct imxfb_rgb *rgb;
> +
> +       /* we don't support xpan, force xres_virtual to be equal to xres */
> +       var->xres_virtual = var->xres;
> +
> +       if (var->yres_virtual < var->yres)
> +               var->yres_virtual = var->yres;
> +
> +       switch (var->bits_per_pixel) {
> +       case 8:
> +               rgb = &def_rgb_8;
> +               break;
> +       case 16:
> +               rgb = &def_rgb_16;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
> +               break;
> +       case 24:
> +               rgb = &def_rgb_24;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> +               break;
> +       case 32:
> +               rgb = &def_rgb_32;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
> +               break;
> +       default:
> +               var->bits_per_pixel = 24;
> +               rgb = &def_rgb_24;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> +       }
> +
> +       var->red    = rgb->red;
> +       var->green  = rgb->green;
> +       var->blue   = rgb->blue;
> +       var->transp = rgb->transp;
> +
> +       return 0;
> +}
> +
> +static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
> +{
> +       chan &= 0xffff;
> +       chan >>= 16 - bf->length;
> +       return chan << bf->offset;
> +}
> +
> +static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
> +                          u_int trans, struct fb_info *fbi)
> +{
> +       unsigned int val;
> +       int ret = 1;
> +
> +       /*
> +        * If greyscale is true, then we convert the RGB value
> +        * to greyscale no matter what visual we are using.
> +        */
> +       if (fbi->var.grayscale)
> +               red = green = blue = (19595 * red + 38470 * green +
> +                                     7471 * blue) >> 16;
> +       switch (fbi->fix.visual) {
> +       case FB_VISUAL_TRUECOLOR:
> +               /*
> +                * 16-bit True Colour.  We encode the RGB value
> +                * according to the RGB bitfield information.
> +                */
> +               if (regno < 16) {
> +                       u32 *pal = fbi->pseudo_palette;
> +
> +                       val = chan_to_field(red, &fbi->var.red);
> +                       val |= chan_to_field(green, &fbi->var.green);
> +                       val |= chan_to_field(blue, &fbi->var.blue);
> +
> +                       pal[regno] = val;
> +                       ret = 0;
> +               }
> +               break;
> +
> +       case FB_VISUAL_STATIC_PSEUDOCOLOR:
> +       case FB_VISUAL_PSEUDOCOLOR:
> +               break;
> +       }
> +
> +       return ret;
> +}
> +
> +static int imx_ipu_fb_blank(int blank, struct fb_info *info)
> +{
> +       dev_dbg(info->device, "blank = %d\n", blank);
> +
> +       switch (blank) {
> +       case FB_BLANK_POWERDOWN:
> +       case FB_BLANK_VSYNC_SUSPEND:
> +       case FB_BLANK_HSYNC_SUSPEND:
> +       case FB_BLANK_NORMAL:
> +               imx_ipu_fb_disable(info);
> +               break;
> +       case FB_BLANK_UNBLANK:
> +               imx_ipu_fb_enable(info);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> +               struct fb_info *info)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> +       unsigned long base;
> +       int ret;
> +
> +       if (info->var.yoffset == var->yoffset)
> +               return 0;       /* No change, do nothing */
> +
> +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> +       base += info->fix.smem_start;
> +
> +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> +       if (ret)
> +               return ret;
> +
> +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> +               dev_err(info->device,
> +                       "Error updating SDC buf to address=0x%08lX\n", base);
> +       }
> +
> +       info->var.yoffset = var->yoffset;
> +
> +       return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_ops = {
> +       .owner          = THIS_MODULE,
> +       .fb_set_par     = imx_ipu_fb_set_par,
> +       .fb_check_var   = imx_ipu_fb_check_var,
> +       .fb_setcolreg   = imx_ipu_fb_setcolreg,
> +       .fb_pan_display = imx_ipu_fb_pan_display,
> +       .fb_fillrect    = cfb_fillrect,
> +       .fb_copyarea    = cfb_copyarea,
> +       .fb_imageblit   = cfb_imageblit,
> +       .fb_blank       = imx_ipu_fb_blank,
> +};
> +
> +/*
> + * Overlay functions
> + */
> +static int imx_ipu_fb_enable_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> +       ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> +       ipu_dp_enable_fg(mxc_fbi->dp);
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_disable_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       ipu_dp_disable_fg(mxc_fbi->dp);
> +       ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> +       ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       struct fb_info *fbi_master = mxc_fbi->master;
> +       struct fb_var_screeninfo *var_master = &fbi_master->var;
> +       int ret;
> +       int interlaced = 0;
> +       int enabled = mxc_fbi->enabled;
> +
> +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> +       if (enabled)
> +               imx_ipu_fb_disable_overlay(fbi);
> +
> +       fbi->fix.line_length = var->xres_virtual *
> +                                  var->bits_per_pixel / 8;
> +
> +       ret = imx_ipu_fb_map_video_memory(fbi);
> +       if (ret)
> +               return ret;
> +
> +       ipu_dp_set_window_pos(mxc_fbi->dp, 64, 64);
> +
> +       var->xoffset = var->yoffset = 0;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> +                                       mxc_fbi->ipu_in_pix_fmt,
> +                                       var->xres, var->yres,
> +                                       fbi->fix.line_length,
> +                                       IPU_ROTATE_NONE,
> +                                       fbi->fix.smem_start,
> +                                       0,
> +                                       0, 0, interlaced);
> +       if (ret) {
> +               dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
> +       if (ret) {
> +               dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       if (enabled)
> +               imx_ipu_fb_enable_overlay(fbi);
> +
> +       return ret;
> +}
> +
> +static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
> +{
> +       dev_dbg(fbi->device, "blank = %d\n", blank);
> +
> +       switch (blank) {
> +       case FB_BLANK_POWERDOWN:
> +       case FB_BLANK_VSYNC_SUSPEND:
> +       case FB_BLANK_HSYNC_SUSPEND:
> +       case FB_BLANK_NORMAL:
> +               imx_ipu_fb_disable_overlay(fbi);
> +               break;
> +       case FB_BLANK_UNBLANK:
> +               imx_ipu_fb_enable_overlay(fbi);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_overlay_ops = {
> +       .owner          = THIS_MODULE,
> +       .fb_set_par     = imx_ipu_fb_set_par_overlay,
> +       .fb_check_var   = imx_ipu_fb_check_var,
> +       .fb_setcolreg   = imx_ipu_fb_setcolreg,
> +       .fb_pan_display = imx_ipu_fb_pan_display,
> +       .fb_fillrect    = cfb_fillrect,
> +       .fb_copyarea    = cfb_copyarea,
> +       .fb_imageblit   = cfb_imageblit,
> +       .fb_blank       = imx_ipu_fb_blank_overlay,
> +};
> +
> +static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
> +{
> +       struct fb_info *fbi;
> +       struct imx_ipu_fb_info *mxc_fbi;
> +
> +       fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
> +       if (!fbi)
> +               return NULL;
> +
> +       BUG_ON(fbi->par == NULL);
> +       mxc_fbi = fbi->par;
> +
> +       fbi->var.activate = FB_ACTIVATE_NOW;
> +
> +       fbi->fbops = ops;
> +       fbi->flags = FBINFO_FLAG_DEFAULT;
> +       fbi->pseudo_palette = mxc_fbi->pseudo_palette;
> +
> +       fb_alloc_cmap(&fbi->cmap, 16, 0);
> +
> +       return fbi;
> +}
> +
> +static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
> +               struct fb_info *fbi_master, int ipu_channel)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> +       struct fb_info *ovlfbi;
> +       struct imx_ipu_fb_info *ovl_mxc_fbi;
> +       int ret;
> +
> +       ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
> +       if (!ovlfbi)
> +               return -ENOMEM;
> +
> +       ovl_mxc_fbi = ovlfbi->par;
> +       ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
> +       ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
> +       ovl_mxc_fbi->ipu_di = -1;
> +       ovl_mxc_fbi->dp = mxc_fbi_master->dp;
> +       ovl_mxc_fbi->master = fbi_master;
> +       mxc_fbi_master->slave = ovlfbi;
> +
> +       ovlfbi->var.xres = 240;
> +       ovlfbi->var.yres = 320;
> +       ovlfbi->var.yres_virtual = ovlfbi->var.yres;
> +       ovlfbi->var.xres_virtual = ovlfbi->var.xres;
> +       imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
> +       imx_ipu_fb_set_fix(ovlfbi);
> +
> +       ret = register_framebuffer(ovlfbi);
> +       if (ret) {
> +               framebuffer_release(ovlfbi);
> +               return ret;
> +       }
> +
> +       ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 1, 0x80, 1);
> +       ipu_dp_set_color_key(ovl_mxc_fbi->dp, 0, 0);
> +
> +       imx_ipu_fb_set_par_overlay(ovlfbi);
> +
> +       return 0;
> +}
> +
> +static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
> +               struct fb_info *fbi_master, int ipu_channel)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> +       struct fb_info *ovlfbi = mxc_fbi_master->slave;
> +       struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
> +
> +       imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
> +
> +       unregister_framebuffer(ovlfbi);
> +
> +       ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
> +       ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
> +       ipu_dmfc_put(ovl_mxc_fbi->dmfc);
> +
> +       framebuffer_release(ovlfbi);
> +}
> +
> +static int imx_ipu_fb_find_mode(struct fb_info *fbi)
> +{
> +       int ret;
> +       struct fb_videomode *mode_array;
> +       struct fb_modelist *modelist;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       int i = 0;
> +
> +       list_for_each_entry(modelist, &fbi->modelist, list)
> +               i++;
> +
> +       mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
> +       if (!mode_array)
> +               return -ENOMEM;
> +
> +       i = 0;
> +       list_for_each_entry(modelist, &fbi->modelist, list)
> +               mode_array[i++] = modelist->mode;
> +
> +       ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
> +       if (ret == 0)
> +               return -EINVAL;
> +
> +       dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
> +                       var->xres, var->yres, var->bits_per_pixel,
> +                       var->hsync_len, var->left_margin, var->right_margin,
> +                       var->vsync_len, var->upper_margin, var->lower_margin);
> +
> +       kfree(mode_array);
> +
> +       return 0;
> +}
> +
> +static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
> +{
> +       struct fb_info *fbi;
> +       struct imx_ipu_fb_info *mxc_fbi;
> +       struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> +       int ret = 0, i;
> +
> +       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> +
> +       fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
> +       if (!fbi)
> +               return -ENOMEM;
> +
> +       mxc_fbi = fbi->par;
> +
> +       mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
> +       mxc_fbi->dc = plat_data->dc_channel;
> +       mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
> +       mxc_fbi->ipu_di = pdev->id;
> +
> +       mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
> +       if (IS_ERR(mxc_fbi->ipu_ch)) {
> +               ret = PTR_ERR(mxc_fbi->ipu_ch);
> +               goto failed_request_ipu;
> +       }
> +
> +       mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
> +       if (IS_ERR(mxc_fbi->ipu_ch)) {
> +               ret = PTR_ERR(mxc_fbi->ipu_ch);
> +               goto failed_request_dmfc;
> +       }
> +
> +       if (plat_data->dp_channel >= 0) {
> +               mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
> +               if (IS_ERR(mxc_fbi->dp)) {
> +                       ret = PTR_ERR(mxc_fbi->ipu_ch);
> +                       goto failed_request_dp;
> +               }
> +       }
> +
> +       fbi->var.yres_virtual = fbi->var.yres;
> +
> +       INIT_LIST_HEAD(&fbi->modelist);
> +       for (i = 0; i < plat_data->num_modes; i++)
> +               fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
> +
> +       if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
> +               for (i = 0; i < num_fb_modes; i++)
> +                       fb_add_videomode(&fb_modes[i], &fbi->modelist);
> +       }
> +
> +       imx_ipu_fb_find_mode(fbi);
> +
> +       imx_ipu_fb_check_var(&fbi->var, fbi);
> +       imx_ipu_fb_set_fix(fbi);
> +       ret = register_framebuffer(fbi);
> +       if (ret < 0)
> +               goto failed_register;
> +
> +       imx_ipu_fb_set_par(fbi);
> +       imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
> +
> +       if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> +               imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> +       platform_set_drvdata(pdev, fbi);
> +
> +       return 0;
> +
> +failed_register:
> +       if (plat_data->dp_channel >= 0)
> +               ipu_dp_put(mxc_fbi->dp);
> +failed_request_dp:
> +       ipu_dmfc_put(mxc_fbi->dmfc);
> +failed_request_dmfc:
> +       ipu_idmac_put(mxc_fbi->ipu_ch);
> +failed_request_ipu:
> +       fb_dealloc_cmap(&fbi->cmap);
> +       framebuffer_release(fbi);
> +
> +       return ret;
> +}
> +
> +static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
> +{
> +       struct fb_info *fbi = platform_get_drvdata(pdev);
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> +
> +       if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> +               imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> +       imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
> +
> +       dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> +                             fbi->screen_base, fbi->fix.smem_start);
> +
> +       if (&fbi->cmap)
> +               fb_dealloc_cmap(&fbi->cmap);
> +
> +       unregister_framebuffer(fbi);
> +
> +       if (plat_data->dp_channel >= 0)
> +               ipu_dp_put(mxc_fbi->dp);
> +       ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
> +       ipu_dmfc_put(mxc_fbi->dmfc);
> +       ipu_idmac_put(mxc_fbi->ipu_ch);
> +
> +       framebuffer_release(fbi);
> +
> +       return 0;
> +}
> +
> +static struct platform_driver imx_ipu_fb_driver = {
> +       .driver = {
> +               .name = DRIVER_NAME,
> +       },
> +       .probe = imx_ipu_fb_probe,
> +       .remove = __devexit_p(imx_ipu_fb_remove),
> +};
> +
> +static int __init imx_ipu_fb_init(void)
> +{
> +       return platform_driver_register(&imx_ipu_fb_driver);
> +}
> +
> +static void __exit imx_ipu_fb_exit(void)
> +{
> +       platform_driver_unregister(&imx_ipu_fb_driver);
> +}
> +
> +module_init(imx_ipu_fb_init);
> +module_exit(imx_ipu_fb_exit);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("i.MX framebuffer driver");
> +MODULE_LICENSE("GPL");
> +MODULE_SUPPORTED_DEVICE("fb");
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-12  6:13     ` Liu Ying
  0 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-12  6:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hello, Sascha,

I have following comments to this patch:
1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
2) ADC is not supported yet in the framebuffer driver, so please
modify this comment:
   > + * Framebuffer Framebuffer Driver for SDC and ADC.
3) 'ipu_dp_set_window_pos()' is called only once in
imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
support to change the overlay framebuffer position. Need a
mechanism/interface for users to change the overlay framebuffer
position.
4) Need to make sure the framebuffer on DP-FG is blanked before the
framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
should be unblanked after the framebuffer on DP-BG is unblanked
5) Need to check the framebuffer on DP-FG doesn't run out of the range
of the framebuffer on DP-BG.
6) I prefer to find the video mode in modedb first, and if we cannot
find the video mode in common video mode data base, we can find a
video mode in custom video mode data base which is defined in platform
data. In this way, we don't need to export common modefb.

Best Regards,
Liu Ying


2010/12/9 Sascha Hauer <s.hauer@pengutronix.de>:
> This patch adds framebuffer support to the Freescale i.MX SoCs
> equipped with an IPU v3, so far these are the i.MX50/51/53.
>
> This driver has been tested on the i.MX51 babbage board with
> both DVI and analog VGA in different resolutions and color depths.
> It has also been tested on a custom i.MX51 board using a fixed
> resolution panel.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
>  drivers/video/Kconfig  |   11 +
>  drivers/video/Makefile |    1 +
>  drivers/video/mx5fb.c  |  846 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 858 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/video/mx5fb.c
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 27c1fb4..1901915 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -2236,6 +2236,17 @@ config FB_MX3
>          far only synchronous displays are supported. If you plan to use
>          an LCD display with your i.MX31 system, say Y here.
>
> +config FB_MX5
> +       tristate "MX5 Framebuffer support"
> +       depends on FB && MFD_IMX_IPU_V3
> +       select FB_CFB_FILLRECT
> +       select FB_CFB_COPYAREA
> +       select FB_CFB_IMAGEBLIT
> +       select FB_MODE_HELPERS
> +       help
> +         This is a framebuffer device for the i.MX51 LCD Controller. If you
> +         plan to use an LCD display with your i.MX51 system, say Y here.
> +
>  config FB_BROADSHEET
>        tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
>        depends on FB
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 485e8ed..ad408d2 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043)          += bf54x-lq043fb.o
>  obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
>  obj-$(CONFIG_FB_BFIN_T350MCQB)   += bfin-t350mcqb-fb.o
>  obj-$(CONFIG_FB_MX3)             += mx3fb.o
> +obj-$(CONFIG_FB_MX5)             += mx5fb.o
>  obj-$(CONFIG_FB_DA8XX)           += da8xx-fb.o
>
>  # the test framebuffer is last
> diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
> new file mode 100644
> index 0000000..fd9baf4
> --- /dev/null
> +++ b/drivers/video/mx5fb.c
> @@ -0,0 +1,846 @@
> +/*
> + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + *
> + * Framebuffer Framebuffer Driver for SDC and ADC.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <linux/fb.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/console.h>
> +#include <linux/mfd/imx-ipu-v3.h>
> +#include <asm/uaccess.h>
> +#include <mach/ipu-v3.h>
> +
> +#define DRIVER_NAME "imx-ipuv3-fb"
> +
> +struct imx_ipu_fb_info {
> +       int                     ipu_channel_num;
> +       struct ipu_channel      *ipu_ch;
> +       int                     dc;
> +       int                     ipu_di;
> +       u32                     ipu_di_pix_fmt;
> +       u32                     ipu_in_pix_fmt;
> +
> +       u32                     pseudo_palette[16];
> +
> +       struct ipu_dp           *dp;
> +       struct dmfc_channel     *dmfc;
> +       struct fb_info          *slave;
> +       struct fb_info          *master;
> +       bool                    enabled;
> +};
> +
> +static int imx_ipu_fb_set_fix(struct fb_info *info)
> +{
> +       struct fb_fix_screeninfo *fix = &info->fix;
> +       struct fb_var_screeninfo *var = &info->var;
> +
> +       fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> +       fix->type = FB_TYPE_PACKED_PIXELS;
> +       fix->accel = FB_ACCEL_NONE;
> +       fix->visual = FB_VISUAL_TRUECOLOR;
> +       fix->xpanstep = 1;
> +       fix->ypanstep = 1;
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
> +{
> +       int size;
> +
> +       size = fbi->var.yres_virtual * fbi->fix.line_length;
> +
> +       if (fbi->screen_base) {
> +               if (fbi->fix.smem_len >= size)
> +                       return 0;
> +
> +               dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> +                             fbi->screen_base, fbi->fix.smem_start);
> +       }
> +
> +       fbi->screen_base = dma_alloc_writecombine(fbi->device,
> +                               size,
> +                               (dma_addr_t *)&fbi->fix.smem_start,
> +                               GFP_DMA);
> +       if (fbi->screen_base = 0) {
> +               dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
> +                               fbi->fix.smem_len);
> +               fbi->fix.smem_len = 0;
> +               fbi->fix.smem_start = 0;
> +               return -ENOMEM;
> +       }
> +
> +       fbi->fix.smem_len = size;
> +       fbi->screen_size = fbi->fix.smem_len;
> +
> +       dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
> +               fbi->fix.smem_start, fbi->fix.smem_len);
> +
> +       /* Clear the screen */
> +       memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
> +
> +       return 0;
> +}
> +
> +static void imx_ipu_fb_enable(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       if (mxc_fbi->enabled)
> +               return;
> +
> +       ipu_di_enable(mxc_fbi->ipu_di);
> +       ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> +       ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> +       ipu_dc_enable_channel(mxc_fbi->dc);
> +       ipu_dp_enable_channel(mxc_fbi->dp);
> +       mxc_fbi->enabled = 1;
> +}
> +
> +static void imx_ipu_fb_disable(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       if (!mxc_fbi->enabled)
> +               return;
> +
> +       ipu_dp_disable_channel(mxc_fbi->dp);
> +       ipu_dc_disable_channel(mxc_fbi->dc);
> +       ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> +       ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> +       ipu_di_disable(mxc_fbi->ipu_di);
> +
> +       mxc_fbi->enabled = 0;
> +}
> +
> +static int calc_vref(struct fb_var_screeninfo *var)
> +{
> +       unsigned long htotal, vtotal;
> +
> +       htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
> +       vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
> +
> +       if (!htotal || !vtotal)
> +               return 60;
> +
> +       return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
> +}
> +
> +static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
> +{
> +       return var->xres * var->yres * vref;
> +}
> +
> +static int imx_ipu_fb_set_par(struct fb_info *fbi)
> +{
> +       int ret;
> +       struct ipu_di_signal_cfg sig_cfg;
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       u32 out_pixel_fmt;
> +       int interlaced = 0;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       int enabled = mxc_fbi->enabled;
> +
> +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> +       if (enabled)
> +               imx_ipu_fb_disable(fbi);
> +
> +       fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> +       var->yres_virtual = var->yres;
> +
> +       ret = imx_ipu_fb_map_video_memory(fbi);
> +       if (ret)
> +               return ret;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       memset(&sig_cfg, 0, sizeof(sig_cfg));
> +       out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               sig_cfg.interlaced = 1;
> +       if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> +               sig_cfg.odd_field_first = 1;
> +       if (var->sync & FB_SYNC_EXT)
> +               sig_cfg.ext_clk = 1;
> +       if (var->sync & FB_SYNC_HOR_HIGH_ACT)
> +               sig_cfg.Hsync_pol = 1;
> +       if (var->sync & FB_SYNC_VERT_HIGH_ACT)
> +               sig_cfg.Vsync_pol = 1;
> +       if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
> +               sig_cfg.clk_pol = 1;
> +       if (var->sync & FB_SYNC_DATA_INVERT)
> +               sig_cfg.data_pol = 1;
> +       if (!(var->sync & FB_SYNC_OE_LOW_ACT))
> +               sig_cfg.enable_pol = 1;
> +       if (var->sync & FB_SYNC_CLK_IDLE_EN)
> +               sig_cfg.clkidle_en = 1;
> +
> +       dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
> +               PICOS2KHZ(var->pixclock) / 1000,
> +               PICOS2KHZ(var->pixclock) % 1000);
> +
> +       sig_cfg.width = var->xres;
> +       sig_cfg.height = var->yres;
> +       sig_cfg.pixel_fmt = out_pixel_fmt;
> +       sig_cfg.h_start_width = var->left_margin;
> +       sig_cfg.h_sync_width = var->hsync_len;
> +       sig_cfg.h_end_width = var->right_margin;
> +       sig_cfg.v_start_width = var->upper_margin;
> +       sig_cfg.v_sync_width = var->vsync_len;
> +       sig_cfg.v_end_width = var->lower_margin;
> +       sig_cfg.v_to_h_sync = 0;
> +
> +       if (mxc_fbi->dp) {
> +               ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
> +                               out_pixel_fmt, 1);
> +               if (ret) {
> +                       dev_dbg(fbi->device, "initializing display processor failed with %d\n",
> +                               ret);
> +                       return ret;
> +               }
> +       }
> +
> +       ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->ipu_di, interlaced,
> +                       out_pixel_fmt, fbi->var.xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing display controller failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_di_init_sync_panel(mxc_fbi->ipu_di,
> +                               PICOS2KHZ(var->pixclock) * 1000UL,
> +                               &sig_cfg);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing panel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
> +       var->xoffset = var->yoffset = 0;
> +
> +       if (fbi->var.vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> +                                       mxc_fbi->ipu_in_pix_fmt,
> +                                       var->xres, var->yres,
> +                                       fbi->fix.line_length,
> +                                       IPU_ROTATE_NONE,
> +                                       fbi->fix.smem_start,
> +                                       0,
> +                                       0, 0, interlaced);
> +       if (ret) {
> +               dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
> +       if (ret) {
> +               dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       if (enabled)
> +               imx_ipu_fb_enable(fbi);
> +
> +       return ret;
> +}
> +
> +/*
> + * These are the bitfields for each
> + * display depth that we support.
> + */
> +struct imxfb_rgb {
> +       struct fb_bitfield      red;
> +       struct fb_bitfield      green;
> +       struct fb_bitfield      blue;
> +       struct fb_bitfield      transp;
> +};
> +
> +static struct imxfb_rgb def_rgb_8 = {
> +       .red    = { .offset =  5, .length = 3, },
> +       .green  = { .offset =  2, .length = 3, },
> +       .blue   = { .offset =  0, .length = 2, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_16 = {
> +       .red    = { .offset = 11, .length = 5, },
> +       .green  = { .offset =  5, .length = 6, },
> +       .blue   = { .offset =  0, .length = 5, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_24 = {
> +       .red    = { .offset = 16, .length = 8, },
> +       .green  = { .offset =  8, .length = 8, },
> +       .blue   = { .offset =  0, .length = 8, },
> +       .transp = { .offset =  0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_32 = {
> +       .red    = { .offset = 16, .length = 8, },
> +       .green  = { .offset =  8, .length = 8, },
> +       .blue   = { .offset =  0, .length = 8, },
> +       .transp = { .offset = 24, .length = 8, },
> +};
> +
> +/*
> + * Check framebuffer variable parameters and adjust to valid values.
> + *
> + * @param       var      framebuffer variable parameters
> + *
> + * @param       info     framebuffer information pointer
> + */
> +static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> +       struct imxfb_rgb *rgb;
> +
> +       /* we don't support xpan, force xres_virtual to be equal to xres */
> +       var->xres_virtual = var->xres;
> +
> +       if (var->yres_virtual < var->yres)
> +               var->yres_virtual = var->yres;
> +
> +       switch (var->bits_per_pixel) {
> +       case 8:
> +               rgb = &def_rgb_8;
> +               break;
> +       case 16:
> +               rgb = &def_rgb_16;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
> +               break;
> +       case 24:
> +               rgb = &def_rgb_24;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> +               break;
> +       case 32:
> +               rgb = &def_rgb_32;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
> +               break;
> +       default:
> +               var->bits_per_pixel = 24;
> +               rgb = &def_rgb_24;
> +               mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> +       }
> +
> +       var->red    = rgb->red;
> +       var->green  = rgb->green;
> +       var->blue   = rgb->blue;
> +       var->transp = rgb->transp;
> +
> +       return 0;
> +}
> +
> +static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
> +{
> +       chan &= 0xffff;
> +       chan >>= 16 - bf->length;
> +       return chan << bf->offset;
> +}
> +
> +static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
> +                          u_int trans, struct fb_info *fbi)
> +{
> +       unsigned int val;
> +       int ret = 1;
> +
> +       /*
> +        * If greyscale is true, then we convert the RGB value
> +        * to greyscale no matter what visual we are using.
> +        */
> +       if (fbi->var.grayscale)
> +               red = green = blue = (19595 * red + 38470 * green +
> +                                     7471 * blue) >> 16;
> +       switch (fbi->fix.visual) {
> +       case FB_VISUAL_TRUECOLOR:
> +               /*
> +                * 16-bit True Colour.  We encode the RGB value
> +                * according to the RGB bitfield information.
> +                */
> +               if (regno < 16) {
> +                       u32 *pal = fbi->pseudo_palette;
> +
> +                       val = chan_to_field(red, &fbi->var.red);
> +                       val |= chan_to_field(green, &fbi->var.green);
> +                       val |= chan_to_field(blue, &fbi->var.blue);
> +
> +                       pal[regno] = val;
> +                       ret = 0;
> +               }
> +               break;
> +
> +       case FB_VISUAL_STATIC_PSEUDOCOLOR:
> +       case FB_VISUAL_PSEUDOCOLOR:
> +               break;
> +       }
> +
> +       return ret;
> +}
> +
> +static int imx_ipu_fb_blank(int blank, struct fb_info *info)
> +{
> +       dev_dbg(info->device, "blank = %d\n", blank);
> +
> +       switch (blank) {
> +       case FB_BLANK_POWERDOWN:
> +       case FB_BLANK_VSYNC_SUSPEND:
> +       case FB_BLANK_HSYNC_SUSPEND:
> +       case FB_BLANK_NORMAL:
> +               imx_ipu_fb_disable(info);
> +               break;
> +       case FB_BLANK_UNBLANK:
> +               imx_ipu_fb_enable(info);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> +               struct fb_info *info)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = info->par;
> +       unsigned long base;
> +       int ret;
> +
> +       if (info->var.yoffset = var->yoffset)
> +               return 0;       /* No change, do nothing */
> +
> +       base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> +       base += info->fix.smem_start;
> +
> +       ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> +       if (ret)
> +               return ret;
> +
> +       if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> +               dev_err(info->device,
> +                       "Error updating SDC buf to address=0x%08lX\n", base);
> +       }
> +
> +       info->var.yoffset = var->yoffset;
> +
> +       return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_ops = {
> +       .owner          = THIS_MODULE,
> +       .fb_set_par     = imx_ipu_fb_set_par,
> +       .fb_check_var   = imx_ipu_fb_check_var,
> +       .fb_setcolreg   = imx_ipu_fb_setcolreg,
> +       .fb_pan_display = imx_ipu_fb_pan_display,
> +       .fb_fillrect    = cfb_fillrect,
> +       .fb_copyarea    = cfb_copyarea,
> +       .fb_imageblit   = cfb_imageblit,
> +       .fb_blank       = imx_ipu_fb_blank,
> +};
> +
> +/*
> + * Overlay functions
> + */
> +static int imx_ipu_fb_enable_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> +       ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> +       ipu_dp_enable_fg(mxc_fbi->dp);
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_disable_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> +       ipu_dp_disable_fg(mxc_fbi->dp);
> +       ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> +       ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> +
> +       return 0;
> +}
> +
> +static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       struct fb_info *fbi_master = mxc_fbi->master;
> +       struct fb_var_screeninfo *var_master = &fbi_master->var;
> +       int ret;
> +       int interlaced = 0;
> +       int enabled = mxc_fbi->enabled;
> +
> +       dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> +               fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> +       if (enabled)
> +               imx_ipu_fb_disable_overlay(fbi);
> +
> +       fbi->fix.line_length = var->xres_virtual *
> +                                  var->bits_per_pixel / 8;
> +
> +       ret = imx_ipu_fb_map_video_memory(fbi);
> +       if (ret)
> +               return ret;
> +
> +       ipu_dp_set_window_pos(mxc_fbi->dp, 64, 64);
> +
> +       var->xoffset = var->yoffset = 0;
> +
> +       if (var->vmode & FB_VMODE_INTERLACED)
> +               interlaced = 1;
> +
> +       ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> +                                       mxc_fbi->ipu_in_pix_fmt,
> +                                       var->xres, var->yres,
> +                                       fbi->fix.line_length,
> +                                       IPU_ROTATE_NONE,
> +                                       fbi->fix.smem_start,
> +                                       0,
> +                                       0, 0, interlaced);
> +       if (ret) {
> +               dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> +       if (ret) {
> +               dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
> +       if (ret) {
> +               dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> +                               ret);
> +               return ret;
> +       }
> +
> +       if (enabled)
> +               imx_ipu_fb_enable_overlay(fbi);
> +
> +       return ret;
> +}
> +
> +static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
> +{
> +       dev_dbg(fbi->device, "blank = %d\n", blank);
> +
> +       switch (blank) {
> +       case FB_BLANK_POWERDOWN:
> +       case FB_BLANK_VSYNC_SUSPEND:
> +       case FB_BLANK_HSYNC_SUSPEND:
> +       case FB_BLANK_NORMAL:
> +               imx_ipu_fb_disable_overlay(fbi);
> +               break;
> +       case FB_BLANK_UNBLANK:
> +               imx_ipu_fb_enable_overlay(fbi);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_overlay_ops = {
> +       .owner          = THIS_MODULE,
> +       .fb_set_par     = imx_ipu_fb_set_par_overlay,
> +       .fb_check_var   = imx_ipu_fb_check_var,
> +       .fb_setcolreg   = imx_ipu_fb_setcolreg,
> +       .fb_pan_display = imx_ipu_fb_pan_display,
> +       .fb_fillrect    = cfb_fillrect,
> +       .fb_copyarea    = cfb_copyarea,
> +       .fb_imageblit   = cfb_imageblit,
> +       .fb_blank       = imx_ipu_fb_blank_overlay,
> +};
> +
> +static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
> +{
> +       struct fb_info *fbi;
> +       struct imx_ipu_fb_info *mxc_fbi;
> +
> +       fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
> +       if (!fbi)
> +               return NULL;
> +
> +       BUG_ON(fbi->par = NULL);
> +       mxc_fbi = fbi->par;
> +
> +       fbi->var.activate = FB_ACTIVATE_NOW;
> +
> +       fbi->fbops = ops;
> +       fbi->flags = FBINFO_FLAG_DEFAULT;
> +       fbi->pseudo_palette = mxc_fbi->pseudo_palette;
> +
> +       fb_alloc_cmap(&fbi->cmap, 16, 0);
> +
> +       return fbi;
> +}
> +
> +static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
> +               struct fb_info *fbi_master, int ipu_channel)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> +       struct fb_info *ovlfbi;
> +       struct imx_ipu_fb_info *ovl_mxc_fbi;
> +       int ret;
> +
> +       ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
> +       if (!ovlfbi)
> +               return -ENOMEM;
> +
> +       ovl_mxc_fbi = ovlfbi->par;
> +       ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
> +       ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
> +       ovl_mxc_fbi->ipu_di = -1;
> +       ovl_mxc_fbi->dp = mxc_fbi_master->dp;
> +       ovl_mxc_fbi->master = fbi_master;
> +       mxc_fbi_master->slave = ovlfbi;
> +
> +       ovlfbi->var.xres = 240;
> +       ovlfbi->var.yres = 320;
> +       ovlfbi->var.yres_virtual = ovlfbi->var.yres;
> +       ovlfbi->var.xres_virtual = ovlfbi->var.xres;
> +       imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
> +       imx_ipu_fb_set_fix(ovlfbi);
> +
> +       ret = register_framebuffer(ovlfbi);
> +       if (ret) {
> +               framebuffer_release(ovlfbi);
> +               return ret;
> +       }
> +
> +       ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 1, 0x80, 1);
> +       ipu_dp_set_color_key(ovl_mxc_fbi->dp, 0, 0);
> +
> +       imx_ipu_fb_set_par_overlay(ovlfbi);
> +
> +       return 0;
> +}
> +
> +static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
> +               struct fb_info *fbi_master, int ipu_channel)
> +{
> +       struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> +       struct fb_info *ovlfbi = mxc_fbi_master->slave;
> +       struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
> +
> +       imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
> +
> +       unregister_framebuffer(ovlfbi);
> +
> +       ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
> +       ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
> +       ipu_dmfc_put(ovl_mxc_fbi->dmfc);
> +
> +       framebuffer_release(ovlfbi);
> +}
> +
> +static int imx_ipu_fb_find_mode(struct fb_info *fbi)
> +{
> +       int ret;
> +       struct fb_videomode *mode_array;
> +       struct fb_modelist *modelist;
> +       struct fb_var_screeninfo *var = &fbi->var;
> +       int i = 0;
> +
> +       list_for_each_entry(modelist, &fbi->modelist, list)
> +               i++;
> +
> +       mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
> +       if (!mode_array)
> +               return -ENOMEM;
> +
> +       i = 0;
> +       list_for_each_entry(modelist, &fbi->modelist, list)
> +               mode_array[i++] = modelist->mode;
> +
> +       ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
> +       if (ret = 0)
> +               return -EINVAL;
> +
> +       dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
> +                       var->xres, var->yres, var->bits_per_pixel,
> +                       var->hsync_len, var->left_margin, var->right_margin,
> +                       var->vsync_len, var->upper_margin, var->lower_margin);
> +
> +       kfree(mode_array);
> +
> +       return 0;
> +}
> +
> +static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
> +{
> +       struct fb_info *fbi;
> +       struct imx_ipu_fb_info *mxc_fbi;
> +       struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> +       int ret = 0, i;
> +
> +       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> +
> +       fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
> +       if (!fbi)
> +               return -ENOMEM;
> +
> +       mxc_fbi = fbi->par;
> +
> +       mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
> +       mxc_fbi->dc = plat_data->dc_channel;
> +       mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
> +       mxc_fbi->ipu_di = pdev->id;
> +
> +       mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
> +       if (IS_ERR(mxc_fbi->ipu_ch)) {
> +               ret = PTR_ERR(mxc_fbi->ipu_ch);
> +               goto failed_request_ipu;
> +       }
> +
> +       mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
> +       if (IS_ERR(mxc_fbi->ipu_ch)) {
> +               ret = PTR_ERR(mxc_fbi->ipu_ch);
> +               goto failed_request_dmfc;
> +       }
> +
> +       if (plat_data->dp_channel >= 0) {
> +               mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
> +               if (IS_ERR(mxc_fbi->dp)) {
> +                       ret = PTR_ERR(mxc_fbi->ipu_ch);
> +                       goto failed_request_dp;
> +               }
> +       }
> +
> +       fbi->var.yres_virtual = fbi->var.yres;
> +
> +       INIT_LIST_HEAD(&fbi->modelist);
> +       for (i = 0; i < plat_data->num_modes; i++)
> +               fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
> +
> +       if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
> +               for (i = 0; i < num_fb_modes; i++)
> +                       fb_add_videomode(&fb_modes[i], &fbi->modelist);
> +       }
> +
> +       imx_ipu_fb_find_mode(fbi);
> +
> +       imx_ipu_fb_check_var(&fbi->var, fbi);
> +       imx_ipu_fb_set_fix(fbi);
> +       ret = register_framebuffer(fbi);
> +       if (ret < 0)
> +               goto failed_register;
> +
> +       imx_ipu_fb_set_par(fbi);
> +       imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
> +
> +       if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> +               imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> +       platform_set_drvdata(pdev, fbi);
> +
> +       return 0;
> +
> +failed_register:
> +       if (plat_data->dp_channel >= 0)
> +               ipu_dp_put(mxc_fbi->dp);
> +failed_request_dp:
> +       ipu_dmfc_put(mxc_fbi->dmfc);
> +failed_request_dmfc:
> +       ipu_idmac_put(mxc_fbi->ipu_ch);
> +failed_request_ipu:
> +       fb_dealloc_cmap(&fbi->cmap);
> +       framebuffer_release(fbi);
> +
> +       return ret;
> +}
> +
> +static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
> +{
> +       struct fb_info *fbi = platform_get_drvdata(pdev);
> +       struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +       struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> +
> +       if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> +               imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> +       imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
> +
> +       dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> +                             fbi->screen_base, fbi->fix.smem_start);
> +
> +       if (&fbi->cmap)
> +               fb_dealloc_cmap(&fbi->cmap);
> +
> +       unregister_framebuffer(fbi);
> +
> +       if (plat_data->dp_channel >= 0)
> +               ipu_dp_put(mxc_fbi->dp);
> +       ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
> +       ipu_dmfc_put(mxc_fbi->dmfc);
> +       ipu_idmac_put(mxc_fbi->ipu_ch);
> +
> +       framebuffer_release(fbi);
> +
> +       return 0;
> +}
> +
> +static struct platform_driver imx_ipu_fb_driver = {
> +       .driver = {
> +               .name = DRIVER_NAME,
> +       },
> +       .probe = imx_ipu_fb_probe,
> +       .remove = __devexit_p(imx_ipu_fb_remove),
> +};
> +
> +static int __init imx_ipu_fb_init(void)
> +{
> +       return platform_driver_register(&imx_ipu_fb_driver);
> +}
> +
> +static void __exit imx_ipu_fb_exit(void)
> +{
> +       platform_driver_unregister(&imx_ipu_fb_driver);
> +}
> +
> +module_init(imx_ipu_fb_init);
> +module_exit(imx_ipu_fb_exit);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("i.MX framebuffer driver");
> +MODULE_LICENSE("GPL");
> +MODULE_SUPPORTED_DEVICE("fb");
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-12  6:13     ` Liu Ying
  0 siblings, 0 replies; 37+ messages in thread
From: Liu Ying @ 2010-12-12  6:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hello, Sascha,

I have following comments to this patch:
1) Please modify the commit message, as IPUv3 is not embedded in i.MX50 SoC.
2) ADC is not supported yet in the framebuffer driver, so please
modify this comment:
   > + * Framebuffer Framebuffer Driver for SDC and ADC.
3) 'ipu_dp_set_window_pos()' is called only once in
imx_ipu_fb_set_par_overlay(). So, the framebuffer driver doesn't
support to change the overlay framebuffer position. Need a
mechanism/interface for users to change the overlay framebuffer
position.
4) Need to make sure the framebuffer on DP-FG is blanked before the
framebuffer on DP-BG is blanked. Meanwhile, the framebuffer on DP-FG
should be unblanked after the framebuffer on DP-BG is unblanked
5) Need to check the framebuffer on DP-FG doesn't run out of the range
of the framebuffer on DP-BG.
6) I prefer to find the video mode in modedb first, and if we cannot
find the video mode in common video mode data base, we can find a
video mode in custom video mode data base which is defined in platform
data. In this way, we don't need to export common modefb.

Best Regards,
Liu Ying


2010/12/9 Sascha Hauer <s.hauer@pengutronix.de>:
> This patch adds framebuffer support to the Freescale i.MX SoCs
> equipped with an IPU v3, so far these are the i.MX50/51/53.
>
> This driver has been tested on the i.MX51 babbage board with
> both DVI and analog VGA in different resolutions and color depths.
> It has also been tested on a custom i.MX51 board using a fixed
> resolution panel.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> ?drivers/video/Kconfig ?| ? 11 +
> ?drivers/video/Makefile | ? ?1 +
> ?drivers/video/mx5fb.c ?| ?846 ++++++++++++++++++++++++++++++++++++++++++++++++
> ?3 files changed, 858 insertions(+), 0 deletions(-)
> ?create mode 100644 drivers/video/mx5fb.c
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 27c1fb4..1901915 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -2236,6 +2236,17 @@ config FB_MX3
> ? ? ? ? ?far only synchronous displays are supported. If you plan to use
> ? ? ? ? ?an LCD display with your i.MX31 system, say Y here.
>
> +config FB_MX5
> + ? ? ? tristate "MX5 Framebuffer support"
> + ? ? ? depends on FB && MFD_IMX_IPU_V3
> + ? ? ? select FB_CFB_FILLRECT
> + ? ? ? select FB_CFB_COPYAREA
> + ? ? ? select FB_CFB_IMAGEBLIT
> + ? ? ? select FB_MODE_HELPERS
> + ? ? ? help
> + ? ? ? ? This is a framebuffer device for the i.MX51 LCD Controller. If you
> + ? ? ? ? plan to use an LCD display with your i.MX51 system, say Y here.
> +
> ?config FB_BROADSHEET
> ? ? ? ?tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
> ? ? ? ?depends on FB
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 485e8ed..ad408d2 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043) ? ? ? ? ?+= bf54x-lq043fb.o
> ?obj-$(CONFIG_FB_BFIN_LQ035Q1) ? ? += bfin-lq035q1-fb.o
> ?obj-$(CONFIG_FB_BFIN_T350MCQB) ? += bfin-t350mcqb-fb.o
> ?obj-$(CONFIG_FB_MX3) ? ? ? ? ? ? += mx3fb.o
> +obj-$(CONFIG_FB_MX5) ? ? ? ? ? ? += mx5fb.o
> ?obj-$(CONFIG_FB_DA8XX) ? ? ? ? ? += da8xx-fb.o
>
> ?# the test framebuffer is last
> diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
> new file mode 100644
> index 0000000..fd9baf4
> --- /dev/null
> +++ b/drivers/video/mx5fb.c
> @@ -0,0 +1,846 @@
> +/*
> + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + *
> + * Framebuffer Framebuffer Driver for SDC and ADC.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <linux/fb.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/console.h>
> +#include <linux/mfd/imx-ipu-v3.h>
> +#include <asm/uaccess.h>
> +#include <mach/ipu-v3.h>
> +
> +#define DRIVER_NAME "imx-ipuv3-fb"
> +
> +struct imx_ipu_fb_info {
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? ipu_channel_num;
> + ? ? ? struct ipu_channel ? ? ?*ipu_ch;
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? dc;
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? ipu_di;
> + ? ? ? u32 ? ? ? ? ? ? ? ? ? ? ipu_di_pix_fmt;
> + ? ? ? u32 ? ? ? ? ? ? ? ? ? ? ipu_in_pix_fmt;
> +
> + ? ? ? u32 ? ? ? ? ? ? ? ? ? ? pseudo_palette[16];
> +
> + ? ? ? struct ipu_dp ? ? ? ? ? *dp;
> + ? ? ? struct dmfc_channel ? ? *dmfc;
> + ? ? ? struct fb_info ? ? ? ? ?*slave;
> + ? ? ? struct fb_info ? ? ? ? ?*master;
> + ? ? ? bool ? ? ? ? ? ? ? ? ? ?enabled;
> +};
> +
> +static int imx_ipu_fb_set_fix(struct fb_info *info)
> +{
> + ? ? ? struct fb_fix_screeninfo *fix = &info->fix;
> + ? ? ? struct fb_var_screeninfo *var = &info->var;
> +
> + ? ? ? fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> + ? ? ? fix->type = FB_TYPE_PACKED_PIXELS;
> + ? ? ? fix->accel = FB_ACCEL_NONE;
> + ? ? ? fix->visual = FB_VISUAL_TRUECOLOR;
> + ? ? ? fix->xpanstep = 1;
> + ? ? ? fix->ypanstep = 1;
> +
> + ? ? ? return 0;
> +}
> +
> +static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
> +{
> + ? ? ? int size;
> +
> + ? ? ? size = fbi->var.yres_virtual * fbi->fix.line_length;
> +
> + ? ? ? if (fbi->screen_base) {
> + ? ? ? ? ? ? ? if (fbi->fix.smem_len >= size)
> + ? ? ? ? ? ? ? ? ? ? ? return 0;
> +
> + ? ? ? ? ? ? ? dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? fbi->screen_base, fbi->fix.smem_start);
> + ? ? ? }
> +
> + ? ? ? fbi->screen_base = dma_alloc_writecombine(fbi->device,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (dma_addr_t *)&fbi->fix.smem_start,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? GFP_DMA);
> + ? ? ? if (fbi->screen_base == 0) {
> + ? ? ? ? ? ? ? dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fbi->fix.smem_len);
> + ? ? ? ? ? ? ? fbi->fix.smem_len = 0;
> + ? ? ? ? ? ? ? fbi->fix.smem_start = 0;
> + ? ? ? ? ? ? ? return -ENOMEM;
> + ? ? ? }
> +
> + ? ? ? fbi->fix.smem_len = size;
> + ? ? ? fbi->screen_size = fbi->fix.smem_len;
> +
> + ? ? ? dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
> + ? ? ? ? ? ? ? fbi->fix.smem_start, fbi->fix.smem_len);
> +
> + ? ? ? /* Clear the screen */
> + ? ? ? memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
> +
> + ? ? ? return 0;
> +}
> +
> +static void imx_ipu_fb_enable(struct fb_info *fbi)
> +{
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> + ? ? ? if (mxc_fbi->enabled)
> + ? ? ? ? ? ? ? return;
> +
> + ? ? ? ipu_di_enable(mxc_fbi->ipu_di);
> + ? ? ? ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> + ? ? ? ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> + ? ? ? ipu_dc_enable_channel(mxc_fbi->dc);
> + ? ? ? ipu_dp_enable_channel(mxc_fbi->dp);
> + ? ? ? mxc_fbi->enabled = 1;
> +}
> +
> +static void imx_ipu_fb_disable(struct fb_info *fbi)
> +{
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> + ? ? ? if (!mxc_fbi->enabled)
> + ? ? ? ? ? ? ? return;
> +
> + ? ? ? ipu_dp_disable_channel(mxc_fbi->dp);
> + ? ? ? ipu_dc_disable_channel(mxc_fbi->dc);
> + ? ? ? ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> + ? ? ? ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> + ? ? ? ipu_di_disable(mxc_fbi->ipu_di);
> +
> + ? ? ? mxc_fbi->enabled = 0;
> +}
> +
> +static int calc_vref(struct fb_var_screeninfo *var)
> +{
> + ? ? ? unsigned long htotal, vtotal;
> +
> + ? ? ? htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
> + ? ? ? vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
> +
> + ? ? ? if (!htotal || !vtotal)
> + ? ? ? ? ? ? ? return 60;
> +
> + ? ? ? return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
> +}
> +
> +static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
> +{
> + ? ? ? return var->xres * var->yres * vref;
> +}
> +
> +static int imx_ipu_fb_set_par(struct fb_info *fbi)
> +{
> + ? ? ? int ret;
> + ? ? ? struct ipu_di_signal_cfg sig_cfg;
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> + ? ? ? u32 out_pixel_fmt;
> + ? ? ? int interlaced = 0;
> + ? ? ? struct fb_var_screeninfo *var = &fbi->var;
> + ? ? ? int enabled = mxc_fbi->enabled;
> +
> + ? ? ? dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> + ? ? ? ? ? ? ? fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> + ? ? ? if (enabled)
> + ? ? ? ? ? ? ? imx_ipu_fb_disable(fbi);
> +
> + ? ? ? fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +
> + ? ? ? var->yres_virtual = var->yres;
> +
> + ? ? ? ret = imx_ipu_fb_map_video_memory(fbi);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? return ret;
> +
> + ? ? ? if (var->vmode & FB_VMODE_INTERLACED)
> + ? ? ? ? ? ? ? interlaced = 1;
> +
> + ? ? ? memset(&sig_cfg, 0, sizeof(sig_cfg));
> + ? ? ? out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
> +
> + ? ? ? if (var->vmode & FB_VMODE_INTERLACED)
> + ? ? ? ? ? ? ? sig_cfg.interlaced = 1;
> + ? ? ? if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
> + ? ? ? ? ? ? ? sig_cfg.odd_field_first = 1;
> + ? ? ? if (var->sync & FB_SYNC_EXT)
> + ? ? ? ? ? ? ? sig_cfg.ext_clk = 1;
> + ? ? ? if (var->sync & FB_SYNC_HOR_HIGH_ACT)
> + ? ? ? ? ? ? ? sig_cfg.Hsync_pol = 1;
> + ? ? ? if (var->sync & FB_SYNC_VERT_HIGH_ACT)
> + ? ? ? ? ? ? ? sig_cfg.Vsync_pol = 1;
> + ? ? ? if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
> + ? ? ? ? ? ? ? sig_cfg.clk_pol = 1;
> + ? ? ? if (var->sync & FB_SYNC_DATA_INVERT)
> + ? ? ? ? ? ? ? sig_cfg.data_pol = 1;
> + ? ? ? if (!(var->sync & FB_SYNC_OE_LOW_ACT))
> + ? ? ? ? ? ? ? sig_cfg.enable_pol = 1;
> + ? ? ? if (var->sync & FB_SYNC_CLK_IDLE_EN)
> + ? ? ? ? ? ? ? sig_cfg.clkidle_en = 1;
> +
> + ? ? ? dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
> + ? ? ? ? ? ? ? PICOS2KHZ(var->pixclock) / 1000,
> + ? ? ? ? ? ? ? PICOS2KHZ(var->pixclock) % 1000);
> +
> + ? ? ? sig_cfg.width = var->xres;
> + ? ? ? sig_cfg.height = var->yres;
> + ? ? ? sig_cfg.pixel_fmt = out_pixel_fmt;
> + ? ? ? sig_cfg.h_start_width = var->left_margin;
> + ? ? ? sig_cfg.h_sync_width = var->hsync_len;
> + ? ? ? sig_cfg.h_end_width = var->right_margin;
> + ? ? ? sig_cfg.v_start_width = var->upper_margin;
> + ? ? ? sig_cfg.v_sync_width = var->vsync_len;
> + ? ? ? sig_cfg.v_end_width = var->lower_margin;
> + ? ? ? sig_cfg.v_to_h_sync = 0;
> +
> + ? ? ? if (mxc_fbi->dp) {
> + ? ? ? ? ? ? ? ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? out_pixel_fmt, 1);
> + ? ? ? ? ? ? ? if (ret) {
> + ? ? ? ? ? ? ? ? ? ? ? dev_dbg(fbi->device, "initializing display processor failed with %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? ? ? ? ? return ret;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> +
> + ? ? ? ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->ipu_di, interlaced,
> + ? ? ? ? ? ? ? ? ? ? ? out_pixel_fmt, fbi->var.xres);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_dbg(fbi->device, "initializing display controller failed with %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? ret = ipu_di_init_sync_panel(mxc_fbi->ipu_di,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? PICOS2KHZ(var->pixclock) * 1000UL,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &sig_cfg);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_dbg(fbi->device, "initializing panel failed with %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
> + ? ? ? var->xoffset = var->yoffset = 0;
> +
> + ? ? ? if (fbi->var.vmode & FB_VMODE_INTERLACED)
> + ? ? ? ? ? ? ? interlaced = 1;
> +
> + ? ? ? ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mxc_fbi->ipu_in_pix_fmt,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? var->xres, var->yres,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fbi->fix.line_length,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IPU_ROTATE_NONE,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fbi->fix.smem_start,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, 0, interlaced);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? if (enabled)
> + ? ? ? ? ? ? ? imx_ipu_fb_enable(fbi);
> +
> + ? ? ? return ret;
> +}
> +
> +/*
> + * These are the bitfields for each
> + * display depth that we support.
> + */
> +struct imxfb_rgb {
> + ? ? ? struct fb_bitfield ? ? ?red;
> + ? ? ? struct fb_bitfield ? ? ?green;
> + ? ? ? struct fb_bitfield ? ? ?blue;
> + ? ? ? struct fb_bitfield ? ? ?transp;
> +};
> +
> +static struct imxfb_rgb def_rgb_8 = {
> + ? ? ? .red ? ?= { .offset = ?5, .length = 3, },
> + ? ? ? .green ?= { .offset = ?2, .length = 3, },
> + ? ? ? .blue ? = { .offset = ?0, .length = 2, },
> + ? ? ? .transp = { .offset = ?0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_16 = {
> + ? ? ? .red ? ?= { .offset = 11, .length = 5, },
> + ? ? ? .green ?= { .offset = ?5, .length = 6, },
> + ? ? ? .blue ? = { .offset = ?0, .length = 5, },
> + ? ? ? .transp = { .offset = ?0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_24 = {
> + ? ? ? .red ? ?= { .offset = 16, .length = 8, },
> + ? ? ? .green ?= { .offset = ?8, .length = 8, },
> + ? ? ? .blue ? = { .offset = ?0, .length = 8, },
> + ? ? ? .transp = { .offset = ?0, .length = 0, },
> +};
> +
> +static struct imxfb_rgb def_rgb_32 = {
> + ? ? ? .red ? ?= { .offset = 16, .length = 8, },
> + ? ? ? .green ?= { .offset = ?8, .length = 8, },
> + ? ? ? .blue ? = { .offset = ?0, .length = 8, },
> + ? ? ? .transp = { .offset = 24, .length = 8, },
> +};
> +
> +/*
> + * Check framebuffer variable parameters and adjust to valid values.
> + *
> + * @param ? ? ? var ? ? ?framebuffer variable parameters
> + *
> + * @param ? ? ? info ? ? framebuffer information pointer
> + */
> +static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
> +{
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi = info->par;
> + ? ? ? struct imxfb_rgb *rgb;
> +
> + ? ? ? /* we don't support xpan, force xres_virtual to be equal to xres */
> + ? ? ? var->xres_virtual = var->xres;
> +
> + ? ? ? if (var->yres_virtual < var->yres)
> + ? ? ? ? ? ? ? var->yres_virtual = var->yres;
> +
> + ? ? ? switch (var->bits_per_pixel) {
> + ? ? ? case 8:
> + ? ? ? ? ? ? ? rgb = &def_rgb_8;
> + ? ? ? ? ? ? ? break;
> + ? ? ? case 16:
> + ? ? ? ? ? ? ? rgb = &def_rgb_16;
> + ? ? ? ? ? ? ? mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
> + ? ? ? ? ? ? ? break;
> + ? ? ? case 24:
> + ? ? ? ? ? ? ? rgb = &def_rgb_24;
> + ? ? ? ? ? ? ? mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> + ? ? ? ? ? ? ? break;
> + ? ? ? case 32:
> + ? ? ? ? ? ? ? rgb = &def_rgb_32;
> + ? ? ? ? ? ? ? mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
> + ? ? ? ? ? ? ? break;
> + ? ? ? default:
> + ? ? ? ? ? ? ? var->bits_per_pixel = 24;
> + ? ? ? ? ? ? ? rgb = &def_rgb_24;
> + ? ? ? ? ? ? ? mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
> + ? ? ? }
> +
> + ? ? ? var->red ? ?= rgb->red;
> + ? ? ? var->green ?= rgb->green;
> + ? ? ? var->blue ? = rgb->blue;
> + ? ? ? var->transp = rgb->transp;
> +
> + ? ? ? return 0;
> +}
> +
> +static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
> +{
> + ? ? ? chan &= 0xffff;
> + ? ? ? chan >>= 16 - bf->length;
> + ? ? ? return chan << bf->offset;
> +}
> +
> +static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
> + ? ? ? ? ? ? ? ? ? ? ? ? ?u_int trans, struct fb_info *fbi)
> +{
> + ? ? ? unsigned int val;
> + ? ? ? int ret = 1;
> +
> + ? ? ? /*
> + ? ? ? ?* If greyscale is true, then we convert the RGB value
> + ? ? ? ?* to greyscale no matter what visual we are using.
> + ? ? ? ?*/
> + ? ? ? if (fbi->var.grayscale)
> + ? ? ? ? ? ? ? red = green = blue = (19595 * red + 38470 * green +
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 7471 * blue) >> 16;
> + ? ? ? switch (fbi->fix.visual) {
> + ? ? ? case FB_VISUAL_TRUECOLOR:
> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* 16-bit True Colour. ?We encode the RGB value
> + ? ? ? ? ? ? ? ?* according to the RGB bitfield information.
> + ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? if (regno < 16) {
> + ? ? ? ? ? ? ? ? ? ? ? u32 *pal = fbi->pseudo_palette;
> +
> + ? ? ? ? ? ? ? ? ? ? ? val = chan_to_field(red, &fbi->var.red);
> + ? ? ? ? ? ? ? ? ? ? ? val |= chan_to_field(green, &fbi->var.green);
> + ? ? ? ? ? ? ? ? ? ? ? val |= chan_to_field(blue, &fbi->var.blue);
> +
> + ? ? ? ? ? ? ? ? ? ? ? pal[regno] = val;
> + ? ? ? ? ? ? ? ? ? ? ? ret = 0;
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? break;
> +
> + ? ? ? case FB_VISUAL_STATIC_PSEUDOCOLOR:
> + ? ? ? case FB_VISUAL_PSEUDOCOLOR:
> + ? ? ? ? ? ? ? break;
> + ? ? ? }
> +
> + ? ? ? return ret;
> +}
> +
> +static int imx_ipu_fb_blank(int blank, struct fb_info *info)
> +{
> + ? ? ? dev_dbg(info->device, "blank = %d\n", blank);
> +
> + ? ? ? switch (blank) {
> + ? ? ? case FB_BLANK_POWERDOWN:
> + ? ? ? case FB_BLANK_VSYNC_SUSPEND:
> + ? ? ? case FB_BLANK_HSYNC_SUSPEND:
> + ? ? ? case FB_BLANK_NORMAL:
> + ? ? ? ? ? ? ? imx_ipu_fb_disable(info);
> + ? ? ? ? ? ? ? break;
> + ? ? ? case FB_BLANK_UNBLANK:
> + ? ? ? ? ? ? ? imx_ipu_fb_enable(info);
> + ? ? ? ? ? ? ? break;
> + ? ? ? }
> +
> + ? ? ? return 0;
> +}
> +
> +static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
> + ? ? ? ? ? ? ? struct fb_info *info)
> +{
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi = info->par;
> + ? ? ? unsigned long base;
> + ? ? ? int ret;
> +
> + ? ? ? if (info->var.yoffset == var->yoffset)
> + ? ? ? ? ? ? ? return 0; ? ? ? /* No change, do nothing */
> +
> + ? ? ? base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
> + ? ? ? base += info->fix.smem_start;
> +
> + ? ? ? ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? return ret;
> +
> + ? ? ? if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
> + ? ? ? ? ? ? ? dev_err(info->device,
> + ? ? ? ? ? ? ? ? ? ? ? "Error updating SDC buf to address=0x%08lX\n", base);
> + ? ? ? }
> +
> + ? ? ? info->var.yoffset = var->yoffset;
> +
> + ? ? ? return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_ops = {
> + ? ? ? .owner ? ? ? ? ?= THIS_MODULE,
> + ? ? ? .fb_set_par ? ? = imx_ipu_fb_set_par,
> + ? ? ? .fb_check_var ? = imx_ipu_fb_check_var,
> + ? ? ? .fb_setcolreg ? = imx_ipu_fb_setcolreg,
> + ? ? ? .fb_pan_display = imx_ipu_fb_pan_display,
> + ? ? ? .fb_fillrect ? ?= cfb_fillrect,
> + ? ? ? .fb_copyarea ? ?= cfb_copyarea,
> + ? ? ? .fb_imageblit ? = cfb_imageblit,
> + ? ? ? .fb_blank ? ? ? = imx_ipu_fb_blank,
> +};
> +
> +/*
> + * Overlay functions
> + */
> +static int imx_ipu_fb_enable_overlay(struct fb_info *fbi)
> +{
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> + ? ? ? ipu_dmfc_enable_channel(mxc_fbi->dmfc);
> + ? ? ? ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
> + ? ? ? ipu_dp_enable_fg(mxc_fbi->dp);
> +
> + ? ? ? return 0;
> +}
> +
> +static int imx_ipu_fb_disable_overlay(struct fb_info *fbi)
> +{
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> +
> + ? ? ? ipu_dp_disable_fg(mxc_fbi->dp);
> + ? ? ? ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
> + ? ? ? ipu_dmfc_disable_channel(mxc_fbi->dmfc);
> +
> + ? ? ? return 0;
> +}
> +
> +static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
> +{
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> + ? ? ? struct fb_var_screeninfo *var = &fbi->var;
> + ? ? ? struct fb_info *fbi_master = mxc_fbi->master;
> + ? ? ? struct fb_var_screeninfo *var_master = &fbi_master->var;
> + ? ? ? int ret;
> + ? ? ? int interlaced = 0;
> + ? ? ? int enabled = mxc_fbi->enabled;
> +
> + ? ? ? dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
> + ? ? ? ? ? ? ? fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
> +
> + ? ? ? if (enabled)
> + ? ? ? ? ? ? ? imx_ipu_fb_disable_overlay(fbi);
> +
> + ? ? ? fbi->fix.line_length = var->xres_virtual *
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?var->bits_per_pixel / 8;
> +
> + ? ? ? ret = imx_ipu_fb_map_video_memory(fbi);
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? return ret;
> +
> + ? ? ? ipu_dp_set_window_pos(mxc_fbi->dp, 64, 64);
> +
> + ? ? ? var->xoffset = var->yoffset = 0;
> +
> + ? ? ? if (var->vmode & FB_VMODE_INTERLACED)
> + ? ? ? ? ? ? ? interlaced = 1;
> +
> + ? ? ? ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mxc_fbi->ipu_in_pix_fmt,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? var->xres, var->yres,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fbi->fix.line_length,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IPU_ROTATE_NONE,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? fbi->fix.smem_start,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, 0, interlaced);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_dbg(fbi->device, "init channel buffer failed with %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ret);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? if (enabled)
> + ? ? ? ? ? ? ? imx_ipu_fb_enable_overlay(fbi);
> +
> + ? ? ? return ret;
> +}
> +
> +static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
> +{
> + ? ? ? dev_dbg(fbi->device, "blank = %d\n", blank);
> +
> + ? ? ? switch (blank) {
> + ? ? ? case FB_BLANK_POWERDOWN:
> + ? ? ? case FB_BLANK_VSYNC_SUSPEND:
> + ? ? ? case FB_BLANK_HSYNC_SUSPEND:
> + ? ? ? case FB_BLANK_NORMAL:
> + ? ? ? ? ? ? ? imx_ipu_fb_disable_overlay(fbi);
> + ? ? ? ? ? ? ? break;
> + ? ? ? case FB_BLANK_UNBLANK:
> + ? ? ? ? ? ? ? imx_ipu_fb_enable_overlay(fbi);
> + ? ? ? ? ? ? ? break;
> + ? ? ? }
> +
> + ? ? ? return 0;
> +}
> +
> +static struct fb_ops imx_ipu_fb_overlay_ops = {
> + ? ? ? .owner ? ? ? ? ?= THIS_MODULE,
> + ? ? ? .fb_set_par ? ? = imx_ipu_fb_set_par_overlay,
> + ? ? ? .fb_check_var ? = imx_ipu_fb_check_var,
> + ? ? ? .fb_setcolreg ? = imx_ipu_fb_setcolreg,
> + ? ? ? .fb_pan_display = imx_ipu_fb_pan_display,
> + ? ? ? .fb_fillrect ? ?= cfb_fillrect,
> + ? ? ? .fb_copyarea ? ?= cfb_copyarea,
> + ? ? ? .fb_imageblit ? = cfb_imageblit,
> + ? ? ? .fb_blank ? ? ? = imx_ipu_fb_blank_overlay,
> +};
> +
> +static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
> +{
> + ? ? ? struct fb_info *fbi;
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi;
> +
> + ? ? ? fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
> + ? ? ? if (!fbi)
> + ? ? ? ? ? ? ? return NULL;
> +
> + ? ? ? BUG_ON(fbi->par == NULL);
> + ? ? ? mxc_fbi = fbi->par;
> +
> + ? ? ? fbi->var.activate = FB_ACTIVATE_NOW;
> +
> + ? ? ? fbi->fbops = ops;
> + ? ? ? fbi->flags = FBINFO_FLAG_DEFAULT;
> + ? ? ? fbi->pseudo_palette = mxc_fbi->pseudo_palette;
> +
> + ? ? ? fb_alloc_cmap(&fbi->cmap, 16, 0);
> +
> + ? ? ? return fbi;
> +}
> +
> +static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
> + ? ? ? ? ? ? ? struct fb_info *fbi_master, int ipu_channel)
> +{
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> + ? ? ? struct fb_info *ovlfbi;
> + ? ? ? struct imx_ipu_fb_info *ovl_mxc_fbi;
> + ? ? ? int ret;
> +
> + ? ? ? ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
> + ? ? ? if (!ovlfbi)
> + ? ? ? ? ? ? ? return -ENOMEM;
> +
> + ? ? ? ovl_mxc_fbi = ovlfbi->par;
> + ? ? ? ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
> + ? ? ? ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
> + ? ? ? ovl_mxc_fbi->ipu_di = -1;
> + ? ? ? ovl_mxc_fbi->dp = mxc_fbi_master->dp;
> + ? ? ? ovl_mxc_fbi->master = fbi_master;
> + ? ? ? mxc_fbi_master->slave = ovlfbi;
> +
> + ? ? ? ovlfbi->var.xres = 240;
> + ? ? ? ovlfbi->var.yres = 320;
> + ? ? ? ovlfbi->var.yres_virtual = ovlfbi->var.yres;
> + ? ? ? ovlfbi->var.xres_virtual = ovlfbi->var.xres;
> + ? ? ? imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
> + ? ? ? imx_ipu_fb_set_fix(ovlfbi);
> +
> + ? ? ? ret = register_framebuffer(ovlfbi);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? framebuffer_release(ovlfbi);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
> +
> + ? ? ? ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 1, 0x80, 1);
> + ? ? ? ipu_dp_set_color_key(ovl_mxc_fbi->dp, 0, 0);
> +
> + ? ? ? imx_ipu_fb_set_par_overlay(ovlfbi);
> +
> + ? ? ? return 0;
> +}
> +
> +static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
> + ? ? ? ? ? ? ? struct fb_info *fbi_master, int ipu_channel)
> +{
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
> + ? ? ? struct fb_info *ovlfbi = mxc_fbi_master->slave;
> + ? ? ? struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
> +
> + ? ? ? imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
> +
> + ? ? ? unregister_framebuffer(ovlfbi);
> +
> + ? ? ? ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
> + ? ? ? ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
> + ? ? ? ipu_dmfc_put(ovl_mxc_fbi->dmfc);
> +
> + ? ? ? framebuffer_release(ovlfbi);
> +}
> +
> +static int imx_ipu_fb_find_mode(struct fb_info *fbi)
> +{
> + ? ? ? int ret;
> + ? ? ? struct fb_videomode *mode_array;
> + ? ? ? struct fb_modelist *modelist;
> + ? ? ? struct fb_var_screeninfo *var = &fbi->var;
> + ? ? ? int i = 0;
> +
> + ? ? ? list_for_each_entry(modelist, &fbi->modelist, list)
> + ? ? ? ? ? ? ? i++;
> +
> + ? ? ? mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
> + ? ? ? if (!mode_array)
> + ? ? ? ? ? ? ? return -ENOMEM;
> +
> + ? ? ? i = 0;
> + ? ? ? list_for_each_entry(modelist, &fbi->modelist, list)
> + ? ? ? ? ? ? ? mode_array[i++] = modelist->mode;
> +
> + ? ? ? ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
> + ? ? ? if (ret == 0)
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
> + ? ? ? ? ? ? ? ? ? ? ? var->xres, var->yres, var->bits_per_pixel,
> + ? ? ? ? ? ? ? ? ? ? ? var->hsync_len, var->left_margin, var->right_margin,
> + ? ? ? ? ? ? ? ? ? ? ? var->vsync_len, var->upper_margin, var->lower_margin);
> +
> + ? ? ? kfree(mode_array);
> +
> + ? ? ? return 0;
> +}
> +
> +static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
> +{
> + ? ? ? struct fb_info *fbi;
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi;
> + ? ? ? struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> + ? ? ? int ret = 0, i;
> +
> + ? ? ? pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> +
> + ? ? ? fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
> + ? ? ? if (!fbi)
> + ? ? ? ? ? ? ? return -ENOMEM;
> +
> + ? ? ? mxc_fbi = fbi->par;
> +
> + ? ? ? mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
> + ? ? ? mxc_fbi->dc = plat_data->dc_channel;
> + ? ? ? mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
> + ? ? ? mxc_fbi->ipu_di = pdev->id;
> +
> + ? ? ? mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
> + ? ? ? if (IS_ERR(mxc_fbi->ipu_ch)) {
> + ? ? ? ? ? ? ? ret = PTR_ERR(mxc_fbi->ipu_ch);
> + ? ? ? ? ? ? ? goto failed_request_ipu;
> + ? ? ? }
> +
> + ? ? ? mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
> + ? ? ? if (IS_ERR(mxc_fbi->ipu_ch)) {
> + ? ? ? ? ? ? ? ret = PTR_ERR(mxc_fbi->ipu_ch);
> + ? ? ? ? ? ? ? goto failed_request_dmfc;
> + ? ? ? }
> +
> + ? ? ? if (plat_data->dp_channel >= 0) {
> + ? ? ? ? ? ? ? mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
> + ? ? ? ? ? ? ? if (IS_ERR(mxc_fbi->dp)) {
> + ? ? ? ? ? ? ? ? ? ? ? ret = PTR_ERR(mxc_fbi->ipu_ch);
> + ? ? ? ? ? ? ? ? ? ? ? goto failed_request_dp;
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> +
> + ? ? ? fbi->var.yres_virtual = fbi->var.yres;
> +
> + ? ? ? INIT_LIST_HEAD(&fbi->modelist);
> + ? ? ? for (i = 0; i < plat_data->num_modes; i++)
> + ? ? ? ? ? ? ? fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
> +
> + ? ? ? if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
> + ? ? ? ? ? ? ? for (i = 0; i < num_fb_modes; i++)
> + ? ? ? ? ? ? ? ? ? ? ? fb_add_videomode(&fb_modes[i], &fbi->modelist);
> + ? ? ? }
> +
> + ? ? ? imx_ipu_fb_find_mode(fbi);
> +
> + ? ? ? imx_ipu_fb_check_var(&fbi->var, fbi);
> + ? ? ? imx_ipu_fb_set_fix(fbi);
> + ? ? ? ret = register_framebuffer(fbi);
> + ? ? ? if (ret < 0)
> + ? ? ? ? ? ? ? goto failed_register;
> +
> + ? ? ? imx_ipu_fb_set_par(fbi);
> + ? ? ? imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
> +
> + ? ? ? if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> + ? ? ? ? ? ? ? imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> + ? ? ? platform_set_drvdata(pdev, fbi);
> +
> + ? ? ? return 0;
> +
> +failed_register:
> + ? ? ? if (plat_data->dp_channel >= 0)
> + ? ? ? ? ? ? ? ipu_dp_put(mxc_fbi->dp);
> +failed_request_dp:
> + ? ? ? ipu_dmfc_put(mxc_fbi->dmfc);
> +failed_request_dmfc:
> + ? ? ? ipu_idmac_put(mxc_fbi->ipu_ch);
> +failed_request_ipu:
> + ? ? ? fb_dealloc_cmap(&fbi->cmap);
> + ? ? ? framebuffer_release(fbi);
> +
> + ? ? ? return ret;
> +}
> +
> +static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
> +{
> + ? ? ? struct fb_info *fbi = platform_get_drvdata(pdev);
> + ? ? ? struct imx_ipu_fb_info *mxc_fbi = fbi->par;
> + ? ? ? struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
> +
> + ? ? ? if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
> + ? ? ? ? ? ? ? imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
> +
> + ? ? ? imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
> +
> + ? ? ? dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? fbi->screen_base, fbi->fix.smem_start);
> +
> + ? ? ? if (&fbi->cmap)
> + ? ? ? ? ? ? ? fb_dealloc_cmap(&fbi->cmap);
> +
> + ? ? ? unregister_framebuffer(fbi);
> +
> + ? ? ? if (plat_data->dp_channel >= 0)
> + ? ? ? ? ? ? ? ipu_dp_put(mxc_fbi->dp);
> + ? ? ? ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
> + ? ? ? ipu_dmfc_put(mxc_fbi->dmfc);
> + ? ? ? ipu_idmac_put(mxc_fbi->ipu_ch);
> +
> + ? ? ? framebuffer_release(fbi);
> +
> + ? ? ? return 0;
> +}
> +
> +static struct platform_driver imx_ipu_fb_driver = {
> + ? ? ? .driver = {
> + ? ? ? ? ? ? ? .name = DRIVER_NAME,
> + ? ? ? },
> + ? ? ? .probe = imx_ipu_fb_probe,
> + ? ? ? .remove = __devexit_p(imx_ipu_fb_remove),
> +};
> +
> +static int __init imx_ipu_fb_init(void)
> +{
> + ? ? ? return platform_driver_register(&imx_ipu_fb_driver);
> +}
> +
> +static void __exit imx_ipu_fb_exit(void)
> +{
> + ? ? ? platform_driver_unregister(&imx_ipu_fb_driver);
> +}
> +
> +module_init(imx_ipu_fb_init);
> +module_exit(imx_ipu_fb_exit);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("i.MX framebuffer driver");
> +MODULE_LICENSE("GPL");
> +MODULE_SUPPORTED_DEVICE("fb");
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at ?http://www.tux.org/lkml/
>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
  2010-12-09 13:47 [PATCH RFC] i.MX51 Framebuffer support Sascha Hauer
  2010-12-09 13:47   ` Sascha Hauer
@ 2010-12-09 13:47   ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-09 13:47 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-kernel, linux-fbdev, Zhang Lily-R58066, Arnaud Patard,
	Sascha Hauer

This patch adds framebuffer support to the Freescale i.MX SoCs
equipped with an IPU v3, so far these are the i.MX50/51/53.

This driver has been tested on the i.MX51 babbage board with
both DVI and analog VGA in different resolutions and color depths.
It has also been tested on a custom i.MX51 board using a fixed
resolution panel.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/video/Kconfig  |   11 +
 drivers/video/Makefile |    1 +
 drivers/video/mx5fb.c  |  846 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 858 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/mx5fb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 27c1fb4..1901915 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2236,6 +2236,17 @@ config FB_MX3
 	  far only synchronous displays are supported. If you plan to use
 	  an LCD display with your i.MX31 system, say Y here.
 
+config FB_MX5
+	tristate "MX5 Framebuffer support"
+	depends on FB && MFD_IMX_IPU_V3
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_MODE_HELPERS
+	help
+	  This is a framebuffer device for the i.MX51 LCD Controller. If you
+	  plan to use an LCD display with your i.MX51 system, say Y here.
+
 config FB_BROADSHEET
 	tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
 	depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 485e8ed..ad408d2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043)	  += bf54x-lq043fb.o
 obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
 obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
+obj-$(CONFIG_FB_MX5)		  += mx5fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
 
 # the test framebuffer is last
diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
new file mode 100644
index 0000000..fd9baf4
--- /dev/null
+++ b/drivers/video/mx5fb.c
@@ -0,0 +1,846 @@
+/*
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Framebuffer Framebuffer Driver for SDC and ADC.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <asm/uaccess.h>
+#include <mach/ipu-v3.h>
+
+#define DRIVER_NAME "imx-ipuv3-fb"
+
+struct imx_ipu_fb_info {
+	int			ipu_channel_num;
+	struct ipu_channel	*ipu_ch;
+	int			dc;
+	int			ipu_di;
+	u32			ipu_di_pix_fmt;
+	u32			ipu_in_pix_fmt;
+
+	u32			pseudo_palette[16];
+
+	struct ipu_dp		*dp;
+	struct dmfc_channel	*dmfc;
+	struct fb_info		*slave;
+	struct fb_info		*master;
+	bool			enabled;
+};
+
+static int imx_ipu_fb_set_fix(struct fb_info *info)
+{
+	struct fb_fix_screeninfo *fix = &info->fix;
+	struct fb_var_screeninfo *var = &info->var;
+
+	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->accel = FB_ACCEL_NONE;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+
+	return 0;
+}
+
+static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
+{
+	int size;
+
+	size = fbi->var.yres_virtual * fbi->fix.line_length;
+
+	if (fbi->screen_base) {
+		if (fbi->fix.smem_len >= size)
+			return 0;
+
+		dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+	}
+
+	fbi->screen_base = dma_alloc_writecombine(fbi->device,
+				size,
+				(dma_addr_t *)&fbi->fix.smem_start,
+				GFP_DMA);
+	if (fbi->screen_base == 0) {
+		dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
+				fbi->fix.smem_len);
+		fbi->fix.smem_len = 0;
+		fbi->fix.smem_start = 0;
+		return -ENOMEM;
+	}
+
+	fbi->fix.smem_len = size;
+	fbi->screen_size = fbi->fix.smem_len;
+
+	dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
+		fbi->fix.smem_start, fbi->fix.smem_len);
+
+	/* Clear the screen */
+	memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+	return 0;
+}
+
+static void imx_ipu_fb_enable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (mxc_fbi->enabled)
+		return;
+
+	ipu_di_enable(mxc_fbi->ipu_di);
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dc_enable_channel(mxc_fbi->dc);
+	ipu_dp_enable_channel(mxc_fbi->dp);
+	mxc_fbi->enabled = 1;
+}
+
+static void imx_ipu_fb_disable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (!mxc_fbi->enabled)
+		return;
+
+	ipu_dp_disable_channel(mxc_fbi->dp);
+	ipu_dc_disable_channel(mxc_fbi->dc);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+	ipu_di_disable(mxc_fbi->ipu_di);
+
+	mxc_fbi->enabled = 0;
+}
+
+static int calc_vref(struct fb_var_screeninfo *var)
+{
+	unsigned long htotal, vtotal;
+
+	htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+	vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+
+	if (!htotal || !vtotal)
+		return 60;
+
+	return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
+}
+
+static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
+{
+	return var->xres * var->yres * vref;
+}
+
+static int imx_ipu_fb_set_par(struct fb_info *fbi)
+{
+	int ret;
+	struct ipu_di_signal_cfg sig_cfg;
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	u32 out_pixel_fmt;
+	int interlaced = 0;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int enabled = mxc_fbi->enabled;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	if (enabled)
+		imx_ipu_fb_disable(fbi);
+
+	fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	var->yres_virtual = var->yres;
+
+	ret = imx_ipu_fb_map_video_memory(fbi);
+	if (ret)
+		return ret;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	memset(&sig_cfg, 0, sizeof(sig_cfg));
+	out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		sig_cfg.interlaced = 1;
+	if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
+		sig_cfg.odd_field_first = 1;
+	if (var->sync & FB_SYNC_EXT)
+		sig_cfg.ext_clk = 1;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		sig_cfg.Hsync_pol = 1;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		sig_cfg.Vsync_pol = 1;
+	if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
+		sig_cfg.clk_pol = 1;
+	if (var->sync & FB_SYNC_DATA_INVERT)
+		sig_cfg.data_pol = 1;
+	if (!(var->sync & FB_SYNC_OE_LOW_ACT))
+		sig_cfg.enable_pol = 1;
+	if (var->sync & FB_SYNC_CLK_IDLE_EN)
+		sig_cfg.clkidle_en = 1;
+
+	dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
+		PICOS2KHZ(var->pixclock) / 1000,
+		PICOS2KHZ(var->pixclock) % 1000);
+
+	sig_cfg.width = var->xres;
+	sig_cfg.height = var->yres;
+	sig_cfg.pixel_fmt = out_pixel_fmt;
+	sig_cfg.h_start_width = var->left_margin;
+	sig_cfg.h_sync_width = var->hsync_len;
+	sig_cfg.h_end_width = var->right_margin;
+	sig_cfg.v_start_width = var->upper_margin;
+	sig_cfg.v_sync_width = var->vsync_len;
+	sig_cfg.v_end_width = var->lower_margin;
+	sig_cfg.v_to_h_sync = 0;
+
+	if (mxc_fbi->dp) {
+		ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
+				out_pixel_fmt, 1);
+		if (ret) {
+			dev_dbg(fbi->device, "initializing display processor failed with %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->ipu_di, interlaced,
+			out_pixel_fmt, fbi->var.xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing display controller failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_di_init_sync_panel(mxc_fbi->ipu_di,
+				PICOS2KHZ(var->pixclock) * 1000UL,
+				&sig_cfg);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing panel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
+	var->xoffset = var->yoffset = 0;
+
+	if (fbi->var.vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+	if (ret) {
+		dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
+	if (ret) {
+		dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	if (enabled)
+		imx_ipu_fb_enable(fbi);
+
+	return ret;
+}
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct imxfb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+static struct imxfb_rgb def_rgb_8 = {
+	.red	= { .offset =  5, .length = 3, },
+	.green	= { .offset =  2, .length = 3, },
+	.blue	= { .offset =  0, .length = 2, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_16 = {
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset =  5, .length = 6, },
+	.blue	= { .offset =  0, .length = 5, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_24 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_32 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+};
+
+/*
+ * Check framebuffer variable parameters and adjust to valid values.
+ *
+ * @param       var      framebuffer variable parameters
+ *
+ * @param       info     framebuffer information pointer
+ */
+static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	struct imxfb_rgb *rgb;
+
+	/* we don't support xpan, force xres_virtual to be equal to xres */
+	var->xres_virtual = var->xres;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		rgb = &def_rgb_8;
+		break;
+	case 16:
+		rgb = &def_rgb_16;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
+		break;
+	case 24:
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+		break;
+	case 32:
+		rgb = &def_rgb_32;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
+		break;
+	default:
+		var->bits_per_pixel = 24;
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+	}
+
+	var->red    = rgb->red;
+	var->green  = rgb->green;
+	var->blue   = rgb->blue;
+	var->transp = rgb->transp;
+
+	return 0;
+}
+
+static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int trans, struct fb_info *fbi)
+{
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no matter what visual we are using.
+	 */
+	if (fbi->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+				      7471 * blue) >> 16;
+	switch (fbi->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = fbi->pseudo_palette;
+
+			val = chan_to_field(red, &fbi->var.red);
+			val |= chan_to_field(green, &fbi->var.green);
+			val |= chan_to_field(blue, &fbi->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		break;
+	}
+
+	return ret;
+}
+
+static int imx_ipu_fb_blank(int blank, struct fb_info *info)
+{
+	dev_dbg(info->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		imx_ipu_fb_disable(info);
+		break;
+	case FB_BLANK_UNBLANK:
+		imx_ipu_fb_enable(info);
+		break;
+	}
+
+	return 0;
+}
+
+static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	unsigned long base;
+	int ret;
+
+	if (info->var.yoffset == var->yoffset)
+		return 0;	/* No change, do nothing */
+
+	base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
+	base += info->fix.smem_start;
+
+	ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
+	if (ret)
+		return ret;
+
+	if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
+		dev_err(info->device,
+			"Error updating SDC buf to address=0x%08lX\n", base);
+	}
+
+	info->var.yoffset = var->yoffset;
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par,
+	.fb_check_var	= imx_ipu_fb_check_var,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank,
+};
+
+/*
+ * Overlay functions
+ */
+static int imx_ipu_fb_enable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dp_enable_fg(mxc_fbi->dp);
+
+	return 0;
+}
+
+static int imx_ipu_fb_disable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	ipu_dp_disable_fg(mxc_fbi->dp);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+
+	return 0;
+}
+
+static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct fb_var_screeninfo *var = &fbi->var;
+	struct fb_info *fbi_master = mxc_fbi->master;
+	struct fb_var_screeninfo *var_master = &fbi_master->var;
+	int ret;
+	int interlaced = 0;
+	int enabled = mxc_fbi->enabled;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	if (enabled)
+		imx_ipu_fb_disable_overlay(fbi);
+
+	fbi->fix.line_length = var->xres_virtual *
+                                  var->bits_per_pixel / 8;
+
+	ret = imx_ipu_fb_map_video_memory(fbi);
+	if (ret)
+		return ret;
+
+	ipu_dp_set_window_pos(mxc_fbi->dp, 64, 64);
+
+	var->xoffset = var->yoffset = 0;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+	if (ret) {
+		dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
+	if (ret) {
+		dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	if (enabled)
+		imx_ipu_fb_enable_overlay(fbi);
+
+	return ret;
+}
+
+static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
+{
+	dev_dbg(fbi->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		imx_ipu_fb_disable_overlay(fbi);
+		break;
+	case FB_BLANK_UNBLANK:
+		imx_ipu_fb_enable_overlay(fbi);
+		break;
+	}
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_overlay_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par_overlay,
+	.fb_check_var	= imx_ipu_fb_check_var,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank_overlay,
+};
+
+static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+
+	fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
+	if (!fbi)
+		return NULL;
+
+	BUG_ON(fbi->par == NULL);
+	mxc_fbi = fbi->par;
+
+	fbi->var.activate = FB_ACTIVATE_NOW;
+
+	fbi->fbops = ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->pseudo_palette = mxc_fbi->pseudo_palette;
+
+	fb_alloc_cmap(&fbi->cmap, 16, 0);
+
+	return fbi;
+}
+
+static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi;
+	struct imx_ipu_fb_info *ovl_mxc_fbi;
+	int ret;
+
+	ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
+	if (!ovlfbi)
+		return -ENOMEM;
+
+	ovl_mxc_fbi = ovlfbi->par;
+	ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
+	ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
+	ovl_mxc_fbi->ipu_di = -1;
+	ovl_mxc_fbi->dp = mxc_fbi_master->dp;
+	ovl_mxc_fbi->master = fbi_master;
+	mxc_fbi_master->slave = ovlfbi;
+
+	ovlfbi->var.xres = 240;
+	ovlfbi->var.yres = 320;
+	ovlfbi->var.yres_virtual = ovlfbi->var.yres;
+	ovlfbi->var.xres_virtual = ovlfbi->var.xres;
+	imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
+	imx_ipu_fb_set_fix(ovlfbi);
+
+	ret = register_framebuffer(ovlfbi);
+	if (ret) {
+		framebuffer_release(ovlfbi);
+		return ret;
+	}
+
+	ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 1, 0x80, 1);
+	ipu_dp_set_color_key(ovl_mxc_fbi->dp, 0, 0);
+
+	imx_ipu_fb_set_par_overlay(ovlfbi);
+
+	return 0;
+}
+
+static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi = mxc_fbi_master->slave;
+	struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
+
+	imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
+
+	unregister_framebuffer(ovlfbi);
+
+	ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
+	ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
+	ipu_dmfc_put(ovl_mxc_fbi->dmfc);
+
+	framebuffer_release(ovlfbi);
+}
+
+static int imx_ipu_fb_find_mode(struct fb_info *fbi)
+{
+	int ret;
+	struct fb_videomode *mode_array;
+	struct fb_modelist *modelist;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int i = 0;
+
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		i++;
+
+	mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
+	if (!mode_array)
+		return -ENOMEM;
+
+	i = 0;
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		mode_array[i++] = modelist->mode;
+
+	ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
+	if (ret == 0)
+		return -EINVAL;
+
+	dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
+			var->xres, var->yres, var->bits_per_pixel,
+			var->hsync_len, var->left_margin, var->right_margin,
+			var->vsync_len, var->upper_margin, var->lower_margin);
+
+	kfree(mode_array);
+
+	return 0;
+}
+
+static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+	int ret = 0, i;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
+	if (!fbi)
+		return -ENOMEM;
+
+	mxc_fbi = fbi->par;
+
+	mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
+	mxc_fbi->dc = plat_data->dc_channel;
+	mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
+	mxc_fbi->ipu_di = pdev->id;
+
+	mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_ipu;
+	}
+
+	mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_dmfc;
+	}
+
+	if (plat_data->dp_channel >= 0) {
+		mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
+		if (IS_ERR(mxc_fbi->dp)) {
+			ret = PTR_ERR(mxc_fbi->ipu_ch);
+			goto failed_request_dp;
+		}
+	}
+
+	fbi->var.yres_virtual = fbi->var.yres;
+
+	INIT_LIST_HEAD(&fbi->modelist);
+	for (i = 0; i < plat_data->num_modes; i++)
+		fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
+
+	if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
+		for (i = 0; i < num_fb_modes; i++)
+			fb_add_videomode(&fb_modes[i], &fbi->modelist);
+	}
+
+	imx_ipu_fb_find_mode(fbi);
+
+	imx_ipu_fb_check_var(&fbi->var, fbi);
+	imx_ipu_fb_set_fix(fbi);
+	ret = register_framebuffer(fbi);
+	if (ret < 0)
+		goto failed_register;
+
+	imx_ipu_fb_set_par(fbi);
+	imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	platform_set_drvdata(pdev, fbi);
+
+	return 0;
+
+failed_register:
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+failed_request_dp:
+	ipu_dmfc_put(mxc_fbi->dmfc);
+failed_request_dmfc:
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+failed_request_ipu:
+	fb_dealloc_cmap(&fbi->cmap);
+	framebuffer_release(fbi);
+
+	return ret;
+}
+
+static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
+{
+	struct fb_info *fbi = platform_get_drvdata(pdev);
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
+
+	dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+
+	if (&fbi->cmap)
+		fb_dealloc_cmap(&fbi->cmap);
+
+	unregister_framebuffer(fbi);
+
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+	ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
+	ipu_dmfc_put(mxc_fbi->dmfc);
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+
+	framebuffer_release(fbi);
+
+	return 0;
+}
+
+static struct platform_driver imx_ipu_fb_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+	.probe = imx_ipu_fb_probe,
+	.remove = __devexit_p(imx_ipu_fb_remove),
+};
+
+static int __init imx_ipu_fb_init(void)
+{
+	return platform_driver_register(&imx_ipu_fb_driver);
+}
+
+static void __exit imx_ipu_fb_exit(void)
+{
+	platform_driver_unregister(&imx_ipu_fb_driver);
+}
+
+module_init(imx_ipu_fb_init);
+module_exit(imx_ipu_fb_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-09 13:47   ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-09 13:47 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds framebuffer support to the Freescale i.MX SoCs
equipped with an IPU v3, so far these are the i.MX50/51/53.

This driver has been tested on the i.MX51 babbage board with
both DVI and analog VGA in different resolutions and color depths.
It has also been tested on a custom i.MX51 board using a fixed
resolution panel.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/video/Kconfig  |   11 +
 drivers/video/Makefile |    1 +
 drivers/video/mx5fb.c  |  846 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 858 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/mx5fb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 27c1fb4..1901915 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2236,6 +2236,17 @@ config FB_MX3
 	  far only synchronous displays are supported. If you plan to use
 	  an LCD display with your i.MX31 system, say Y here.
 
+config FB_MX5
+	tristate "MX5 Framebuffer support"
+	depends on FB && MFD_IMX_IPU_V3
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_MODE_HELPERS
+	help
+	  This is a framebuffer device for the i.MX51 LCD Controller. If you
+	  plan to use an LCD display with your i.MX51 system, say Y here.
+
 config FB_BROADSHEET
 	tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
 	depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 485e8ed..ad408d2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043)	  += bf54x-lq043fb.o
 obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
 obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
+obj-$(CONFIG_FB_MX5)		  += mx5fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
 
 # the test framebuffer is last
diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
new file mode 100644
index 0000000..fd9baf4
--- /dev/null
+++ b/drivers/video/mx5fb.c
@@ -0,0 +1,846 @@
+/*
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Framebuffer Framebuffer Driver for SDC and ADC.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <asm/uaccess.h>
+#include <mach/ipu-v3.h>
+
+#define DRIVER_NAME "imx-ipuv3-fb"
+
+struct imx_ipu_fb_info {
+	int			ipu_channel_num;
+	struct ipu_channel	*ipu_ch;
+	int			dc;
+	int			ipu_di;
+	u32			ipu_di_pix_fmt;
+	u32			ipu_in_pix_fmt;
+
+	u32			pseudo_palette[16];
+
+	struct ipu_dp		*dp;
+	struct dmfc_channel	*dmfc;
+	struct fb_info		*slave;
+	struct fb_info		*master;
+	bool			enabled;
+};
+
+static int imx_ipu_fb_set_fix(struct fb_info *info)
+{
+	struct fb_fix_screeninfo *fix = &info->fix;
+	struct fb_var_screeninfo *var = &info->var;
+
+	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->accel = FB_ACCEL_NONE;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+
+	return 0;
+}
+
+static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
+{
+	int size;
+
+	size = fbi->var.yres_virtual * fbi->fix.line_length;
+
+	if (fbi->screen_base) {
+		if (fbi->fix.smem_len >= size)
+			return 0;
+
+		dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+	}
+
+	fbi->screen_base = dma_alloc_writecombine(fbi->device,
+				size,
+				(dma_addr_t *)&fbi->fix.smem_start,
+				GFP_DMA);
+	if (fbi->screen_base = 0) {
+		dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
+				fbi->fix.smem_len);
+		fbi->fix.smem_len = 0;
+		fbi->fix.smem_start = 0;
+		return -ENOMEM;
+	}
+
+	fbi->fix.smem_len = size;
+	fbi->screen_size = fbi->fix.smem_len;
+
+	dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
+		fbi->fix.smem_start, fbi->fix.smem_len);
+
+	/* Clear the screen */
+	memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+	return 0;
+}
+
+static void imx_ipu_fb_enable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (mxc_fbi->enabled)
+		return;
+
+	ipu_di_enable(mxc_fbi->ipu_di);
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dc_enable_channel(mxc_fbi->dc);
+	ipu_dp_enable_channel(mxc_fbi->dp);
+	mxc_fbi->enabled = 1;
+}
+
+static void imx_ipu_fb_disable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (!mxc_fbi->enabled)
+		return;
+
+	ipu_dp_disable_channel(mxc_fbi->dp);
+	ipu_dc_disable_channel(mxc_fbi->dc);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+	ipu_di_disable(mxc_fbi->ipu_di);
+
+	mxc_fbi->enabled = 0;
+}
+
+static int calc_vref(struct fb_var_screeninfo *var)
+{
+	unsigned long htotal, vtotal;
+
+	htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+	vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+
+	if (!htotal || !vtotal)
+		return 60;
+
+	return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
+}
+
+static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
+{
+	return var->xres * var->yres * vref;
+}
+
+static int imx_ipu_fb_set_par(struct fb_info *fbi)
+{
+	int ret;
+	struct ipu_di_signal_cfg sig_cfg;
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	u32 out_pixel_fmt;
+	int interlaced = 0;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int enabled = mxc_fbi->enabled;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	if (enabled)
+		imx_ipu_fb_disable(fbi);
+
+	fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	var->yres_virtual = var->yres;
+
+	ret = imx_ipu_fb_map_video_memory(fbi);
+	if (ret)
+		return ret;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	memset(&sig_cfg, 0, sizeof(sig_cfg));
+	out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		sig_cfg.interlaced = 1;
+	if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
+		sig_cfg.odd_field_first = 1;
+	if (var->sync & FB_SYNC_EXT)
+		sig_cfg.ext_clk = 1;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		sig_cfg.Hsync_pol = 1;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		sig_cfg.Vsync_pol = 1;
+	if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
+		sig_cfg.clk_pol = 1;
+	if (var->sync & FB_SYNC_DATA_INVERT)
+		sig_cfg.data_pol = 1;
+	if (!(var->sync & FB_SYNC_OE_LOW_ACT))
+		sig_cfg.enable_pol = 1;
+	if (var->sync & FB_SYNC_CLK_IDLE_EN)
+		sig_cfg.clkidle_en = 1;
+
+	dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
+		PICOS2KHZ(var->pixclock) / 1000,
+		PICOS2KHZ(var->pixclock) % 1000);
+
+	sig_cfg.width = var->xres;
+	sig_cfg.height = var->yres;
+	sig_cfg.pixel_fmt = out_pixel_fmt;
+	sig_cfg.h_start_width = var->left_margin;
+	sig_cfg.h_sync_width = var->hsync_len;
+	sig_cfg.h_end_width = var->right_margin;
+	sig_cfg.v_start_width = var->upper_margin;
+	sig_cfg.v_sync_width = var->vsync_len;
+	sig_cfg.v_end_width = var->lower_margin;
+	sig_cfg.v_to_h_sync = 0;
+
+	if (mxc_fbi->dp) {
+		ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
+				out_pixel_fmt, 1);
+		if (ret) {
+			dev_dbg(fbi->device, "initializing display processor failed with %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->ipu_di, interlaced,
+			out_pixel_fmt, fbi->var.xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing display controller failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_di_init_sync_panel(mxc_fbi->ipu_di,
+				PICOS2KHZ(var->pixclock) * 1000UL,
+				&sig_cfg);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing panel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
+	var->xoffset = var->yoffset = 0;
+
+	if (fbi->var.vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+	if (ret) {
+		dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
+	if (ret) {
+		dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	if (enabled)
+		imx_ipu_fb_enable(fbi);
+
+	return ret;
+}
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct imxfb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+static struct imxfb_rgb def_rgb_8 = {
+	.red	= { .offset =  5, .length = 3, },
+	.green	= { .offset =  2, .length = 3, },
+	.blue	= { .offset =  0, .length = 2, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_16 = {
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset =  5, .length = 6, },
+	.blue	= { .offset =  0, .length = 5, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_24 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_32 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+};
+
+/*
+ * Check framebuffer variable parameters and adjust to valid values.
+ *
+ * @param       var      framebuffer variable parameters
+ *
+ * @param       info     framebuffer information pointer
+ */
+static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	struct imxfb_rgb *rgb;
+
+	/* we don't support xpan, force xres_virtual to be equal to xres */
+	var->xres_virtual = var->xres;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		rgb = &def_rgb_8;
+		break;
+	case 16:
+		rgb = &def_rgb_16;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
+		break;
+	case 24:
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+		break;
+	case 32:
+		rgb = &def_rgb_32;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
+		break;
+	default:
+		var->bits_per_pixel = 24;
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+	}
+
+	var->red    = rgb->red;
+	var->green  = rgb->green;
+	var->blue   = rgb->blue;
+	var->transp = rgb->transp;
+
+	return 0;
+}
+
+static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int trans, struct fb_info *fbi)
+{
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no matter what visual we are using.
+	 */
+	if (fbi->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+				      7471 * blue) >> 16;
+	switch (fbi->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = fbi->pseudo_palette;
+
+			val = chan_to_field(red, &fbi->var.red);
+			val |= chan_to_field(green, &fbi->var.green);
+			val |= chan_to_field(blue, &fbi->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		break;
+	}
+
+	return ret;
+}
+
+static int imx_ipu_fb_blank(int blank, struct fb_info *info)
+{
+	dev_dbg(info->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		imx_ipu_fb_disable(info);
+		break;
+	case FB_BLANK_UNBLANK:
+		imx_ipu_fb_enable(info);
+		break;
+	}
+
+	return 0;
+}
+
+static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	unsigned long base;
+	int ret;
+
+	if (info->var.yoffset = var->yoffset)
+		return 0;	/* No change, do nothing */
+
+	base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
+	base += info->fix.smem_start;
+
+	ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
+	if (ret)
+		return ret;
+
+	if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
+		dev_err(info->device,
+			"Error updating SDC buf to address=0x%08lX\n", base);
+	}
+
+	info->var.yoffset = var->yoffset;
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par,
+	.fb_check_var	= imx_ipu_fb_check_var,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank,
+};
+
+/*
+ * Overlay functions
+ */
+static int imx_ipu_fb_enable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dp_enable_fg(mxc_fbi->dp);
+
+	return 0;
+}
+
+static int imx_ipu_fb_disable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	ipu_dp_disable_fg(mxc_fbi->dp);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+
+	return 0;
+}
+
+static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct fb_var_screeninfo *var = &fbi->var;
+	struct fb_info *fbi_master = mxc_fbi->master;
+	struct fb_var_screeninfo *var_master = &fbi_master->var;
+	int ret;
+	int interlaced = 0;
+	int enabled = mxc_fbi->enabled;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	if (enabled)
+		imx_ipu_fb_disable_overlay(fbi);
+
+	fbi->fix.line_length = var->xres_virtual *
+                                  var->bits_per_pixel / 8;
+
+	ret = imx_ipu_fb_map_video_memory(fbi);
+	if (ret)
+		return ret;
+
+	ipu_dp_set_window_pos(mxc_fbi->dp, 64, 64);
+
+	var->xoffset = var->yoffset = 0;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+	if (ret) {
+		dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
+	if (ret) {
+		dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	if (enabled)
+		imx_ipu_fb_enable_overlay(fbi);
+
+	return ret;
+}
+
+static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
+{
+	dev_dbg(fbi->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		imx_ipu_fb_disable_overlay(fbi);
+		break;
+	case FB_BLANK_UNBLANK:
+		imx_ipu_fb_enable_overlay(fbi);
+		break;
+	}
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_overlay_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par_overlay,
+	.fb_check_var	= imx_ipu_fb_check_var,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank_overlay,
+};
+
+static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+
+	fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
+	if (!fbi)
+		return NULL;
+
+	BUG_ON(fbi->par = NULL);
+	mxc_fbi = fbi->par;
+
+	fbi->var.activate = FB_ACTIVATE_NOW;
+
+	fbi->fbops = ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->pseudo_palette = mxc_fbi->pseudo_palette;
+
+	fb_alloc_cmap(&fbi->cmap, 16, 0);
+
+	return fbi;
+}
+
+static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi;
+	struct imx_ipu_fb_info *ovl_mxc_fbi;
+	int ret;
+
+	ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
+	if (!ovlfbi)
+		return -ENOMEM;
+
+	ovl_mxc_fbi = ovlfbi->par;
+	ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
+	ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
+	ovl_mxc_fbi->ipu_di = -1;
+	ovl_mxc_fbi->dp = mxc_fbi_master->dp;
+	ovl_mxc_fbi->master = fbi_master;
+	mxc_fbi_master->slave = ovlfbi;
+
+	ovlfbi->var.xres = 240;
+	ovlfbi->var.yres = 320;
+	ovlfbi->var.yres_virtual = ovlfbi->var.yres;
+	ovlfbi->var.xres_virtual = ovlfbi->var.xres;
+	imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
+	imx_ipu_fb_set_fix(ovlfbi);
+
+	ret = register_framebuffer(ovlfbi);
+	if (ret) {
+		framebuffer_release(ovlfbi);
+		return ret;
+	}
+
+	ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 1, 0x80, 1);
+	ipu_dp_set_color_key(ovl_mxc_fbi->dp, 0, 0);
+
+	imx_ipu_fb_set_par_overlay(ovlfbi);
+
+	return 0;
+}
+
+static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi = mxc_fbi_master->slave;
+	struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
+
+	imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
+
+	unregister_framebuffer(ovlfbi);
+
+	ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
+	ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
+	ipu_dmfc_put(ovl_mxc_fbi->dmfc);
+
+	framebuffer_release(ovlfbi);
+}
+
+static int imx_ipu_fb_find_mode(struct fb_info *fbi)
+{
+	int ret;
+	struct fb_videomode *mode_array;
+	struct fb_modelist *modelist;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int i = 0;
+
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		i++;
+
+	mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
+	if (!mode_array)
+		return -ENOMEM;
+
+	i = 0;
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		mode_array[i++] = modelist->mode;
+
+	ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
+	if (ret = 0)
+		return -EINVAL;
+
+	dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
+			var->xres, var->yres, var->bits_per_pixel,
+			var->hsync_len, var->left_margin, var->right_margin,
+			var->vsync_len, var->upper_margin, var->lower_margin);
+
+	kfree(mode_array);
+
+	return 0;
+}
+
+static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+	int ret = 0, i;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
+	if (!fbi)
+		return -ENOMEM;
+
+	mxc_fbi = fbi->par;
+
+	mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
+	mxc_fbi->dc = plat_data->dc_channel;
+	mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
+	mxc_fbi->ipu_di = pdev->id;
+
+	mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_ipu;
+	}
+
+	mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_dmfc;
+	}
+
+	if (plat_data->dp_channel >= 0) {
+		mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
+		if (IS_ERR(mxc_fbi->dp)) {
+			ret = PTR_ERR(mxc_fbi->ipu_ch);
+			goto failed_request_dp;
+		}
+	}
+
+	fbi->var.yres_virtual = fbi->var.yres;
+
+	INIT_LIST_HEAD(&fbi->modelist);
+	for (i = 0; i < plat_data->num_modes; i++)
+		fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
+
+	if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
+		for (i = 0; i < num_fb_modes; i++)
+			fb_add_videomode(&fb_modes[i], &fbi->modelist);
+	}
+
+	imx_ipu_fb_find_mode(fbi);
+
+	imx_ipu_fb_check_var(&fbi->var, fbi);
+	imx_ipu_fb_set_fix(fbi);
+	ret = register_framebuffer(fbi);
+	if (ret < 0)
+		goto failed_register;
+
+	imx_ipu_fb_set_par(fbi);
+	imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	platform_set_drvdata(pdev, fbi);
+
+	return 0;
+
+failed_register:
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+failed_request_dp:
+	ipu_dmfc_put(mxc_fbi->dmfc);
+failed_request_dmfc:
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+failed_request_ipu:
+	fb_dealloc_cmap(&fbi->cmap);
+	framebuffer_release(fbi);
+
+	return ret;
+}
+
+static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
+{
+	struct fb_info *fbi = platform_get_drvdata(pdev);
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
+
+	dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+
+	if (&fbi->cmap)
+		fb_dealloc_cmap(&fbi->cmap);
+
+	unregister_framebuffer(fbi);
+
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+	ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
+	ipu_dmfc_put(mxc_fbi->dmfc);
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+
+	framebuffer_release(fbi);
+
+	return 0;
+}
+
+static struct platform_driver imx_ipu_fb_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+	.probe = imx_ipu_fb_probe,
+	.remove = __devexit_p(imx_ipu_fb_remove),
+};
+
+static int __init imx_ipu_fb_init(void)
+{
+	return platform_driver_register(&imx_ipu_fb_driver);
+}
+
+static void __exit imx_ipu_fb_exit(void)
+{
+	platform_driver_unregister(&imx_ipu_fb_driver);
+}
+
+module_init(imx_ipu_fb_init);
+module_exit(imx_ipu_fb_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
-- 
1.7.2.3


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 5/9] Add i.MX5 framebuffer driver
@ 2010-12-09 13:47   ` Sascha Hauer
  0 siblings, 0 replies; 37+ messages in thread
From: Sascha Hauer @ 2010-12-09 13:47 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds framebuffer support to the Freescale i.MX SoCs
equipped with an IPU v3, so far these are the i.MX50/51/53.

This driver has been tested on the i.MX51 babbage board with
both DVI and analog VGA in different resolutions and color depths.
It has also been tested on a custom i.MX51 board using a fixed
resolution panel.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/video/Kconfig  |   11 +
 drivers/video/Makefile |    1 +
 drivers/video/mx5fb.c  |  846 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 858 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/mx5fb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 27c1fb4..1901915 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2236,6 +2236,17 @@ config FB_MX3
 	  far only synchronous displays are supported. If you plan to use
 	  an LCD display with your i.MX31 system, say Y here.
 
+config FB_MX5
+	tristate "MX5 Framebuffer support"
+	depends on FB && MFD_IMX_IPU_V3
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_MODE_HELPERS
+	help
+	  This is a framebuffer device for the i.MX51 LCD Controller. If you
+	  plan to use an LCD display with your i.MX51 system, say Y here.
+
 config FB_BROADSHEET
 	tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
 	depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 485e8ed..ad408d2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -145,6 +145,7 @@ obj-$(CONFIG_FB_BF54X_LQ043)	  += bf54x-lq043fb.o
 obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
 obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
+obj-$(CONFIG_FB_MX5)		  += mx5fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
 
 # the test framebuffer is last
diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
new file mode 100644
index 0000000..fd9baf4
--- /dev/null
+++ b/drivers/video/mx5fb.c
@@ -0,0 +1,846 @@
+/*
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Framebuffer Framebuffer Driver for SDC and ADC.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <asm/uaccess.h>
+#include <mach/ipu-v3.h>
+
+#define DRIVER_NAME "imx-ipuv3-fb"
+
+struct imx_ipu_fb_info {
+	int			ipu_channel_num;
+	struct ipu_channel	*ipu_ch;
+	int			dc;
+	int			ipu_di;
+	u32			ipu_di_pix_fmt;
+	u32			ipu_in_pix_fmt;
+
+	u32			pseudo_palette[16];
+
+	struct ipu_dp		*dp;
+	struct dmfc_channel	*dmfc;
+	struct fb_info		*slave;
+	struct fb_info		*master;
+	bool			enabled;
+};
+
+static int imx_ipu_fb_set_fix(struct fb_info *info)
+{
+	struct fb_fix_screeninfo *fix = &info->fix;
+	struct fb_var_screeninfo *var = &info->var;
+
+	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->accel = FB_ACCEL_NONE;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+
+	return 0;
+}
+
+static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
+{
+	int size;
+
+	size = fbi->var.yres_virtual * fbi->fix.line_length;
+
+	if (fbi->screen_base) {
+		if (fbi->fix.smem_len >= size)
+			return 0;
+
+		dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+	}
+
+	fbi->screen_base = dma_alloc_writecombine(fbi->device,
+				size,
+				(dma_addr_t *)&fbi->fix.smem_start,
+				GFP_DMA);
+	if (fbi->screen_base == 0) {
+		dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
+				fbi->fix.smem_len);
+		fbi->fix.smem_len = 0;
+		fbi->fix.smem_start = 0;
+		return -ENOMEM;
+	}
+
+	fbi->fix.smem_len = size;
+	fbi->screen_size = fbi->fix.smem_len;
+
+	dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
+		fbi->fix.smem_start, fbi->fix.smem_len);
+
+	/* Clear the screen */
+	memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+	return 0;
+}
+
+static void imx_ipu_fb_enable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (mxc_fbi->enabled)
+		return;
+
+	ipu_di_enable(mxc_fbi->ipu_di);
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dc_enable_channel(mxc_fbi->dc);
+	ipu_dp_enable_channel(mxc_fbi->dp);
+	mxc_fbi->enabled = 1;
+}
+
+static void imx_ipu_fb_disable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (!mxc_fbi->enabled)
+		return;
+
+	ipu_dp_disable_channel(mxc_fbi->dp);
+	ipu_dc_disable_channel(mxc_fbi->dc);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+	ipu_di_disable(mxc_fbi->ipu_di);
+
+	mxc_fbi->enabled = 0;
+}
+
+static int calc_vref(struct fb_var_screeninfo *var)
+{
+	unsigned long htotal, vtotal;
+
+	htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+	vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+
+	if (!htotal || !vtotal)
+		return 60;
+
+	return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
+}
+
+static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
+{
+	return var->xres * var->yres * vref;
+}
+
+static int imx_ipu_fb_set_par(struct fb_info *fbi)
+{
+	int ret;
+	struct ipu_di_signal_cfg sig_cfg;
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	u32 out_pixel_fmt;
+	int interlaced = 0;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int enabled = mxc_fbi->enabled;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	if (enabled)
+		imx_ipu_fb_disable(fbi);
+
+	fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	var->yres_virtual = var->yres;
+
+	ret = imx_ipu_fb_map_video_memory(fbi);
+	if (ret)
+		return ret;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	memset(&sig_cfg, 0, sizeof(sig_cfg));
+	out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		sig_cfg.interlaced = 1;
+	if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
+		sig_cfg.odd_field_first = 1;
+	if (var->sync & FB_SYNC_EXT)
+		sig_cfg.ext_clk = 1;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		sig_cfg.Hsync_pol = 1;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		sig_cfg.Vsync_pol = 1;
+	if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
+		sig_cfg.clk_pol = 1;
+	if (var->sync & FB_SYNC_DATA_INVERT)
+		sig_cfg.data_pol = 1;
+	if (!(var->sync & FB_SYNC_OE_LOW_ACT))
+		sig_cfg.enable_pol = 1;
+	if (var->sync & FB_SYNC_CLK_IDLE_EN)
+		sig_cfg.clkidle_en = 1;
+
+	dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
+		PICOS2KHZ(var->pixclock) / 1000,
+		PICOS2KHZ(var->pixclock) % 1000);
+
+	sig_cfg.width = var->xres;
+	sig_cfg.height = var->yres;
+	sig_cfg.pixel_fmt = out_pixel_fmt;
+	sig_cfg.h_start_width = var->left_margin;
+	sig_cfg.h_sync_width = var->hsync_len;
+	sig_cfg.h_end_width = var->right_margin;
+	sig_cfg.v_start_width = var->upper_margin;
+	sig_cfg.v_sync_width = var->vsync_len;
+	sig_cfg.v_end_width = var->lower_margin;
+	sig_cfg.v_to_h_sync = 0;
+
+	if (mxc_fbi->dp) {
+		ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
+				out_pixel_fmt, 1);
+		if (ret) {
+			dev_dbg(fbi->device, "initializing display processor failed with %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	ret = ipu_dc_init_sync(mxc_fbi->dc, mxc_fbi->ipu_di, interlaced,
+			out_pixel_fmt, fbi->var.xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing display controller failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_di_init_sync_panel(mxc_fbi->ipu_di,
+				PICOS2KHZ(var->pixclock) * 1000UL,
+				&sig_cfg);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing panel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
+	var->xoffset = var->yoffset = 0;
+
+	if (fbi->var.vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+	if (ret) {
+		dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
+	if (ret) {
+		dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	if (enabled)
+		imx_ipu_fb_enable(fbi);
+
+	return ret;
+}
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct imxfb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+static struct imxfb_rgb def_rgb_8 = {
+	.red	= { .offset =  5, .length = 3, },
+	.green	= { .offset =  2, .length = 3, },
+	.blue	= { .offset =  0, .length = 2, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_16 = {
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset =  5, .length = 6, },
+	.blue	= { .offset =  0, .length = 5, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_24 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_32 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+};
+
+/*
+ * Check framebuffer variable parameters and adjust to valid values.
+ *
+ * @param       var      framebuffer variable parameters
+ *
+ * @param       info     framebuffer information pointer
+ */
+static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	struct imxfb_rgb *rgb;
+
+	/* we don't support xpan, force xres_virtual to be equal to xres */
+	var->xres_virtual = var->xres;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		rgb = &def_rgb_8;
+		break;
+	case 16:
+		rgb = &def_rgb_16;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
+		break;
+	case 24:
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+		break;
+	case 32:
+		rgb = &def_rgb_32;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
+		break;
+	default:
+		var->bits_per_pixel = 24;
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+	}
+
+	var->red    = rgb->red;
+	var->green  = rgb->green;
+	var->blue   = rgb->blue;
+	var->transp = rgb->transp;
+
+	return 0;
+}
+
+static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int trans, struct fb_info *fbi)
+{
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no matter what visual we are using.
+	 */
+	if (fbi->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+				      7471 * blue) >> 16;
+	switch (fbi->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = fbi->pseudo_palette;
+
+			val = chan_to_field(red, &fbi->var.red);
+			val |= chan_to_field(green, &fbi->var.green);
+			val |= chan_to_field(blue, &fbi->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		break;
+	}
+
+	return ret;
+}
+
+static int imx_ipu_fb_blank(int blank, struct fb_info *info)
+{
+	dev_dbg(info->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		imx_ipu_fb_disable(info);
+		break;
+	case FB_BLANK_UNBLANK:
+		imx_ipu_fb_enable(info);
+		break;
+	}
+
+	return 0;
+}
+
+static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	unsigned long base;
+	int ret;
+
+	if (info->var.yoffset == var->yoffset)
+		return 0;	/* No change, do nothing */
+
+	base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
+	base += info->fix.smem_start;
+
+	ret = ipu_wait_for_interrupt(IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
+	if (ret)
+		return ret;
+
+	if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
+		dev_err(info->device,
+			"Error updating SDC buf to address=0x%08lX\n", base);
+	}
+
+	info->var.yoffset = var->yoffset;
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par,
+	.fb_check_var	= imx_ipu_fb_check_var,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank,
+};
+
+/*
+ * Overlay functions
+ */
+static int imx_ipu_fb_enable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dp_enable_fg(mxc_fbi->dp);
+
+	return 0;
+}
+
+static int imx_ipu_fb_disable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	ipu_dp_disable_fg(mxc_fbi->dp);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+
+	return 0;
+}
+
+static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct fb_var_screeninfo *var = &fbi->var;
+	struct fb_info *fbi_master = mxc_fbi->master;
+	struct fb_var_screeninfo *var_master = &fbi_master->var;
+	int ret;
+	int interlaced = 0;
+	int enabled = mxc_fbi->enabled;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	if (enabled)
+		imx_ipu_fb_disable_overlay(fbi);
+
+	fbi->fix.line_length = var->xres_virtual *
+                                  var->bits_per_pixel / 8;
+
+	ret = imx_ipu_fb_map_video_memory(fbi);
+	if (ret)
+		return ret;
+
+	ipu_dp_set_window_pos(mxc_fbi->dp, 64, 64);
+
+	var->xoffset = var->yoffset = 0;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+	if (ret) {
+		dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
+	if (ret) {
+		dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	if (enabled)
+		imx_ipu_fb_enable_overlay(fbi);
+
+	return ret;
+}
+
+static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
+{
+	dev_dbg(fbi->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		imx_ipu_fb_disable_overlay(fbi);
+		break;
+	case FB_BLANK_UNBLANK:
+		imx_ipu_fb_enable_overlay(fbi);
+		break;
+	}
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_overlay_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par_overlay,
+	.fb_check_var	= imx_ipu_fb_check_var,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank_overlay,
+};
+
+static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+
+	fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
+	if (!fbi)
+		return NULL;
+
+	BUG_ON(fbi->par == NULL);
+	mxc_fbi = fbi->par;
+
+	fbi->var.activate = FB_ACTIVATE_NOW;
+
+	fbi->fbops = ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->pseudo_palette = mxc_fbi->pseudo_palette;
+
+	fb_alloc_cmap(&fbi->cmap, 16, 0);
+
+	return fbi;
+}
+
+static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi;
+	struct imx_ipu_fb_info *ovl_mxc_fbi;
+	int ret;
+
+	ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
+	if (!ovlfbi)
+		return -ENOMEM;
+
+	ovl_mxc_fbi = ovlfbi->par;
+	ovl_mxc_fbi->ipu_ch = ipu_idmac_get(ipu_channel);
+	ovl_mxc_fbi->dmfc = ipu_dmfc_get(ipu_channel);
+	ovl_mxc_fbi->ipu_di = -1;
+	ovl_mxc_fbi->dp = mxc_fbi_master->dp;
+	ovl_mxc_fbi->master = fbi_master;
+	mxc_fbi_master->slave = ovlfbi;
+
+	ovlfbi->var.xres = 240;
+	ovlfbi->var.yres = 320;
+	ovlfbi->var.yres_virtual = ovlfbi->var.yres;
+	ovlfbi->var.xres_virtual = ovlfbi->var.xres;
+	imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
+	imx_ipu_fb_set_fix(ovlfbi);
+
+	ret = register_framebuffer(ovlfbi);
+	if (ret) {
+		framebuffer_release(ovlfbi);
+		return ret;
+	}
+
+	ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 1, 0x80, 1);
+	ipu_dp_set_color_key(ovl_mxc_fbi->dp, 0, 0);
+
+	imx_ipu_fb_set_par_overlay(ovlfbi);
+
+	return 0;
+}
+
+static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi = mxc_fbi_master->slave;
+	struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
+
+	imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
+
+	unregister_framebuffer(ovlfbi);
+
+	ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
+	ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
+	ipu_dmfc_put(ovl_mxc_fbi->dmfc);
+
+	framebuffer_release(ovlfbi);
+}
+
+static int imx_ipu_fb_find_mode(struct fb_info *fbi)
+{
+	int ret;
+	struct fb_videomode *mode_array;
+	struct fb_modelist *modelist;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int i = 0;
+
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		i++;
+
+	mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
+	if (!mode_array)
+		return -ENOMEM;
+
+	i = 0;
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		mode_array[i++] = modelist->mode;
+
+	ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
+	if (ret == 0)
+		return -EINVAL;
+
+	dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
+			var->xres, var->yres, var->bits_per_pixel,
+			var->hsync_len, var->left_margin, var->right_margin,
+			var->vsync_len, var->upper_margin, var->lower_margin);
+
+	kfree(mode_array);
+
+	return 0;
+}
+
+static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+	int ret = 0, i;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
+	if (!fbi)
+		return -ENOMEM;
+
+	mxc_fbi = fbi->par;
+
+	mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
+	mxc_fbi->dc = plat_data->dc_channel;
+	mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
+	mxc_fbi->ipu_di = pdev->id;
+
+	mxc_fbi->ipu_ch = ipu_idmac_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_ipu;
+	}
+
+	mxc_fbi->dmfc = ipu_dmfc_get(plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_dmfc;
+	}
+
+	if (plat_data->dp_channel >= 0) {
+		mxc_fbi->dp = ipu_dp_get(plat_data->dp_channel);
+		if (IS_ERR(mxc_fbi->dp)) {
+			ret = PTR_ERR(mxc_fbi->ipu_ch);
+			goto failed_request_dp;
+		}
+	}
+
+	fbi->var.yres_virtual = fbi->var.yres;
+
+	INIT_LIST_HEAD(&fbi->modelist);
+	for (i = 0; i < plat_data->num_modes; i++)
+		fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
+
+	if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
+		for (i = 0; i < num_fb_modes; i++)
+			fb_add_videomode(&fb_modes[i], &fbi->modelist);
+	}
+
+	imx_ipu_fb_find_mode(fbi);
+
+	imx_ipu_fb_check_var(&fbi->var, fbi);
+	imx_ipu_fb_set_fix(fbi);
+	ret = register_framebuffer(fbi);
+	if (ret < 0)
+		goto failed_register;
+
+	imx_ipu_fb_set_par(fbi);
+	imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	platform_set_drvdata(pdev, fbi);
+
+	return 0;
+
+failed_register:
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+failed_request_dp:
+	ipu_dmfc_put(mxc_fbi->dmfc);
+failed_request_dmfc:
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+failed_request_ipu:
+	fb_dealloc_cmap(&fbi->cmap);
+	framebuffer_release(fbi);
+
+	return ret;
+}
+
+static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
+{
+	struct fb_info *fbi = platform_get_drvdata(pdev);
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
+
+	dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+
+	if (&fbi->cmap)
+		fb_dealloc_cmap(&fbi->cmap);
+
+	unregister_framebuffer(fbi);
+
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+	ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
+	ipu_dmfc_put(mxc_fbi->dmfc);
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+
+	framebuffer_release(fbi);
+
+	return 0;
+}
+
+static struct platform_driver imx_ipu_fb_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+	.probe = imx_ipu_fb_probe,
+	.remove = __devexit_p(imx_ipu_fb_remove),
+};
+
+static int __init imx_ipu_fb_init(void)
+{
+	return platform_driver_register(&imx_ipu_fb_driver);
+}
+
+static void __exit imx_ipu_fb_exit(void)
+{
+	platform_driver_unregister(&imx_ipu_fb_driver);
+}
+
+module_init(imx_ipu_fb_init);
+module_exit(imx_ipu_fb_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2010-12-20 10:49 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <33F32152BE7EC740BC2C838D2836AC8704A957@039-SN1MPN1-002.039d.mgd.msft.net>
2010-12-14 12:38 ` [PATCH 5/9] Add i.MX5 framebuffer driver Chen Jie-B02280
2010-12-14 12:38   ` Chen Jie-B02280
2010-12-15 14:38   ` s.hauer
2010-12-15 14:38     ` s.hauer at pengutronix.de
2010-12-15 14:38     ` s.hauer
2010-12-16  2:07     ` Chen Jie-B02280
2010-12-16  2:07       ` Chen Jie-B02280
2010-12-16  2:07       ` Chen Jie-B02280
2010-12-20 10:48 [PATCH v2] i.MX51 Framebuffer support Sascha Hauer
2010-12-20 10:48 ` [PATCH 5/9] Add i.MX5 framebuffer driver Sascha Hauer
2010-12-20 10:48   ` Sascha Hauer
  -- strict thread matches above, loose matches on Subject: below --
2010-12-09 13:47 [PATCH RFC] i.MX51 Framebuffer support Sascha Hauer
2010-12-09 13:47 ` [PATCH 5/9] Add i.MX5 framebuffer driver Sascha Hauer
2010-12-09 13:47   ` Sascha Hauer
2010-12-09 13:47   ` Sascha Hauer
2010-12-12  6:13   ` Liu Ying
2010-12-12  6:13     ` Liu Ying
2010-12-12  6:13     ` Liu Ying
2010-12-13  7:23     ` Lothar Waßmann
2010-12-13  7:23       ` Lothar Waßmann
2010-12-13  7:23       ` Lothar Waßmann
2010-12-13 11:35       ` Liu Ying
2010-12-13 11:35         ` Liu Ying
2010-12-13 11:35         ` Liu Ying
2010-12-13 11:38     ` Sascha Hauer
2010-12-13 11:38       ` Sascha Hauer
2010-12-13 11:38       ` Sascha Hauer
2010-12-14  6:40       ` Liu Ying
2010-12-14  6:40         ` Liu Ying
2010-12-14  6:40         ` Liu Ying
2010-12-14  8:45         ` Sascha Hauer
2010-12-14  8:45           ` Sascha Hauer
2010-12-14  8:45           ` Sascha Hauer
2010-12-14 13:23           ` Liu Ying
2010-12-14 13:23             ` Liu Ying
2010-12-14 13:23             ` Liu Ying
2010-12-15 11:17             ` Sascha Hauer
2010-12-15 11:17               ` Sascha Hauer
2010-12-15 11:17               ` Sascha Hauer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.