Re: [PATCH 2/4] video: mmp fb support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2012/8/29 Zhou Zhu <zzhu3@xxxxxxxxxxx>:
> Added fb support for Marvell mmp display subsystem.
> This driver is configured using "buffer driver mach info".
> With configured name of path, this driver get path using
> using exported interface of mmp display driver.
> Then this driver get ovly using configured id and operates
> on this ovly to show buffers on display devices.
>
> Change-Id: I1a6fb4f89ac933e1364a4511dd3ec1463463d9c8
> Signed-off-by: Zhou Zhu <zzhu3@xxxxxxxxxxx>
> Signed-off-by: Lisa Du <cldu@xxxxxxxxxxx>
> ---
>  drivers/video/mmp/Kconfig     |    4 +
>  drivers/video/mmp/Makefile    |    2 +-
>  drivers/video/mmp/fb/Kconfig  |   13 +
>  drivers/video/mmp/fb/Makefile |    1 +
>  drivers/video/mmp/fb/mmpfb.c  |  663 +++++++++++++++++++++++++++++++++++++++++
>  drivers/video/mmp/fb/mmpfb.h  |   51 ++++
>  6 files changed, 733 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/video/mmp/fb/Kconfig
>  create mode 100644 drivers/video/mmp/fb/Makefile
>  create mode 100644 drivers/video/mmp/fb/mmpfb.c
>  create mode 100644 drivers/video/mmp/fb/mmpfb.h
>
> diff --git a/drivers/video/mmp/Kconfig b/drivers/video/mmp/Kconfig
> index 0554336..6a0b056 100644
> --- a/drivers/video/mmp/Kconfig
> +++ b/drivers/video/mmp/Kconfig
> @@ -3,3 +3,7 @@ menuconfig MMP_DISP
>          depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988
>          help
>           Marvell Display Subsystem support.
> +
> +if MMP_DISP
> +source "drivers/video/mmp/fb/Kconfig"
> +endif
> diff --git a/drivers/video/mmp/Makefile b/drivers/video/mmp/Makefile
> index 820eb10..fdcd833 100644
> --- a/drivers/video/mmp/Makefile
> +++ b/drivers/video/mmp/Makefile
> @@ -1 +1 @@
> -obj-y += core.o
> +obj-y += core.o fb/
> diff --git a/drivers/video/mmp/fb/Kconfig b/drivers/video/mmp/fb/Kconfig
> new file mode 100644
> index 0000000..9b0141f
> --- /dev/null
> +++ b/drivers/video/mmp/fb/Kconfig
> @@ -0,0 +1,13 @@
> +if MMP_DISP
> +
> +config MMP_FB
> +       bool "fb driver for Marvell MMP Display Subsystem"
> +       depends on FB
> +       select FB_CFB_FILLRECT
> +       select FB_CFB_COPYAREA
> +       select FB_CFB_IMAGEBLIT
> +       default y
> +       help
> +               fb driver for Marvell MMP Display Subsystem
> +
> +endif
> diff --git a/drivers/video/mmp/fb/Makefile b/drivers/video/mmp/fb/Makefile
> new file mode 100644
> index 0000000..709fd1f
> --- /dev/null
> +++ b/drivers/video/mmp/fb/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_MMP_FB)  += mmpfb.o
> diff --git a/drivers/video/mmp/fb/mmpfb.c b/drivers/video/mmp/fb/mmpfb.c
> new file mode 100644
> index 0000000..83e4a0c
> --- /dev/null
> +++ b/drivers/video/mmp/fb/mmpfb.c
> @@ -0,0 +1,663 @@
> +/*
> + * linux/drivers/video/mmp/fb/mmpfb.c
> + * Framebuffer driver for Marvell Display controller.
> + *
> + * Copyright (C) 2012 Marvell Technology Group Ltd.
> + * Authors: Zhou Zhu <zzhu3@xxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +#include <linux/module.h>
> +#include <linux/vmalloc.h>
> +#include <asm/cacheflush.h>
> +#include "mmpfb.h"
> +
> +static int var_to_pixfmt(struct fb_var_screeninfo *var)
> +{
> +       /*
> +        * Pseudocolor mode?
> +        */
> +       if (var->bits_per_pixel == 8)
> +               return PIXFMT_PSEUDOCOLOR;
> +
> +       /*
> +        * Check for YUV422PLANAR.
> +        */
> +       if (var->bits_per_pixel == 16 && var->red.length == 8 &&
> +                       var->green.length == 4 && var->blue.length == 4) {
> +               if (var->green.offset >= var->blue.offset)
> +                       return PIXFMT_YUV422P;
> +               else
> +                       return PIXFMT_YVU422P;
> +       }
> +
> +       /*
> +        * Check for YUV420PLANAR.
> +        */
> +       if (var->bits_per_pixel == 12 && var->red.length == 8 &&
> +                       var->green.length == 2 && var->blue.length == 2) {
> +               if (var->green.offset >= var->blue.offset)
> +                       return PIXFMT_YUV420P;
> +               else
> +                       return PIXFMT_YVU420P;
> +       }
> +
> +       /*
> +        * Check for YUV422PACK.
> +        */
> +       if (var->bits_per_pixel == 16 && var->red.length == 16 &&
> +                       var->green.length == 16 && var->blue.length == 16) {
> +               if (var->red.offset == 0)
> +                       return PIXFMT_YUYV;
> +               else if (var->green.offset >= var->blue.offset)
> +                       return PIXFMT_UYVY;
> +               else
> +                       return PIXFMT_VYUY;
> +       }
> +
> +       /*
> +        * Check for 565/1555.
> +        */
> +       if (var->bits_per_pixel == 16 && var->red.length <= 5 &&
> +                       var->green.length <= 6 && var->blue.length <= 5) {
> +               if (var->transp.length == 0) {
> +                       if (var->red.offset >= var->blue.offset)
> +                               return PIXFMT_RGB565;
> +                       else
> +                               return PIXFMT_BGR565;
> +               }
> +       }
> +
> +       /*
> +        * Check for 888/A888.
> +        */
> +       if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
> +                       var->green.length <= 8 && var->blue.length <= 8) {
> +               if (var->bits_per_pixel == 24 && var->transp.length == 0) {
> +                       if (var->red.offset >= var->blue.offset)
> +                               return PIXFMT_RGB888PACK;
> +                       else
> +                               return PIXFMT_BGR888PACK;
> +               }
> +
> +               if (var->bits_per_pixel == 32 && var->transp.offset == 24) {
> +                       if (var->red.offset >= var->blue.offset)
> +                               return PIXFMT_RGBA888;
> +                       else
> +                               return PIXFMT_BGRA888;
> +               } else {
> +                       if (var->red.offset >= var->blue.offset)
> +                               return PIXFMT_RGB888UNPACK;
> +                       else
> +                               return PIXFMT_BGR888UNPACK;
> +               }
> +
> +               /* fall through */
> +       }
> +
> +       return -EINVAL;
> +
> +}
> +
> +static void pixfmt_to_var(struct fb_var_screeninfo *var, int pix_fmt)
> +{
> +       switch (pix_fmt) {
> +       case PIXFMT_RGB565:
> +               var->bits_per_pixel = 16;
> +               var->red.offset = 11;   var->red.length = 5;
> +               var->green.offset = 5;   var->green.length = 6;
> +               var->blue.offset = 0;   var->blue.length = 5;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_BGR565:
> +               var->bits_per_pixel = 16;
> +               var->red.offset = 0;    var->red.length = 5;
> +               var->green.offset = 5;   var->green.length = 6;
> +               var->blue.offset = 11;  var->blue.length = 5;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_RGB888UNPACK:
> +               var->bits_per_pixel = 32;
> +               var->red.offset = 16;   var->red.length = 8;
> +               var->green.offset = 8;   var->green.length = 8;
> +               var->blue.offset = 0;   var->blue.length = 8;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_BGR888UNPACK:
> +               var->bits_per_pixel = 32;
> +               var->red.offset = 0;    var->red.length = 8;
> +               var->green.offset = 8;   var->green.length = 8;
> +               var->blue.offset = 16;  var->blue.length = 8;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_RGBA888:
> +               var->bits_per_pixel = 32;
> +               var->red.offset = 16;   var->red.length = 8;
> +               var->green.offset = 8;   var->green.length = 8;
> +               var->blue.offset = 0;   var->blue.length = 8;
> +               var->transp.offset = 24; var->transp.length = 8;
> +               break;
> +       case PIXFMT_BGRA888:
> +               var->bits_per_pixel = 32;
> +               var->red.offset = 0;    var->red.length = 8;
> +               var->green.offset = 8;   var->green.length = 8;
> +               var->blue.offset = 16;  var->blue.length = 8;
> +               var->transp.offset = 24; var->transp.length = 8;
> +               break;
> +       case PIXFMT_RGB888PACK:
> +               var->bits_per_pixel = 24;
> +               var->red.offset = 16;   var->red.length = 8;
> +               var->green.offset = 8;   var->green.length = 8;
> +               var->blue.offset = 0;   var->blue.length = 8;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_BGR888PACK:
> +               var->bits_per_pixel = 24;
> +               var->red.offset = 0;    var->red.length = 8;
> +               var->green.offset = 8;   var->green.length = 8;
> +               var->blue.offset = 16;  var->blue.length = 8;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_YUV420P:
> +               var->bits_per_pixel = 12;
> +               var->red.offset = 4;     var->red.length = 8;
> +               var->green.offset = 2;   var->green.length = 2;
> +               var->blue.offset = 0;   var->blue.length = 2;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_YVU420P:
> +               var->bits_per_pixel = 12;
> +               var->red.offset = 4;     var->red.length = 8;
> +               var->green.offset = 0;   var->green.length = 2;
> +               var->blue.offset = 2;   var->blue.length = 2;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_YUV422P:
> +               var->bits_per_pixel = 16;
> +               var->red.offset = 8;     var->red.length = 8;
> +               var->green.offset = 4;   var->green.length = 4;
> +               var->blue.offset = 0;   var->blue.length = 4;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_YVU422P:
> +               var->bits_per_pixel = 16;
> +               var->red.offset = 8;     var->red.length = 8;
> +               var->green.offset = 0;   var->green.length = 4;
> +               var->blue.offset = 4;   var->blue.length = 4;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_UYVY:
> +               var->bits_per_pixel = 16;
> +               var->red.offset = 8;     var->red.length = 16;
> +               var->green.offset = 4;   var->green.length = 16;
> +               var->blue.offset = 0;   var->blue.length = 16;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_VYUY:
> +               var->bits_per_pixel = 16;
> +               var->red.offset = 8;     var->red.length = 16;
> +               var->green.offset = 0;   var->green.length = 16;
> +               var->blue.offset = 4;   var->blue.length = 16;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_YUYV:
> +               var->bits_per_pixel = 16;
> +               var->red.offset = 0;     var->red.length = 16;
> +               var->green.offset = 4;   var->green.length = 16;
> +               var->blue.offset = 8;   var->blue.length = 16;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       case PIXFMT_PSEUDOCOLOR:
> +               var->bits_per_pixel = 8;
> +               var->red.offset = 0;     var->red.length = 8;
> +               var->green.offset = 0;   var->green.length = 8;
> +               var->blue.offset = 0;   var->blue.length = 8;
> +               var->transp.offset = 0;  var->transp.length = 0;
> +               break;
> +       }
> +}
> +
> +/*
> + * fb framework has its limitation:
> + * 1. input color/output color is not seprated
> + * 2. fb_videomode not include output color
> + * so for fb usage, we keep a output format which is not changed
> + *  then it's added for mmpmode
> + */
> +static void fbmode_to_mmpmode(struct mmp_mode *mode,
> +               struct fb_videomode *videomode, int output_fmt)
> +{
> +       u64 div_result = 1000000000000ll;
> +       mode->name = videomode->name;
> +       mode->refresh = videomode->refresh;
> +       mode->xres = videomode->xres;
> +       mode->yres = videomode->yres;
> +
> +       do_div(div_result, videomode->pixclock);
> +       mode->pixclock_freq = (u32)div_result;
> +
> +       mode->left_margin = videomode->left_margin;
> +       mode->right_margin = videomode->right_margin;
> +       mode->upper_margin = videomode->upper_margin;
> +       mode->lower_margin = videomode->lower_margin;
> +       mode->hsync_len = videomode->hsync_len;
> +       mode->vsync_len = videomode->vsync_len;
> +       mode->hsync_invert = !!(videomode->sync & FB_SYNC_HOR_HIGH_ACT);
> +       mode->vsync_invert = !!(videomode->sync & FB_SYNC_VERT_HIGH_ACT);
> +       /* no defined flag in fb, use vmode>>3*/
> +       mode->invert_pixclock = !!(videomode->vmode & 8);
> +       mode->pix_fmt_out = output_fmt;
> +}
> +
> +static void mmpmode_to_fbmode(struct fb_videomode *videomode,
> +               struct mmp_mode *mode)
> +{
> +       u64 div_result = 1000000000000ll;
> +
> +       videomode->name = mode->name;
> +       videomode->refresh = mode->refresh;
> +       videomode->xres = mode->xres;
> +       videomode->yres = mode->yres;
> +
> +       do_div(div_result, mode->pixclock_freq);
> +       videomode->pixclock = (u32)div_result;
> +
> +       videomode->left_margin = mode->left_margin;
> +       videomode->right_margin = mode->right_margin;
> +       videomode->upper_margin = mode->upper_margin;
> +       videomode->lower_margin = mode->lower_margin;
> +       videomode->hsync_len = mode->hsync_len;
> +       videomode->vsync_len = mode->vsync_len;
> +       videomode->sync = (mode->hsync_invert ? FB_SYNC_HOR_HIGH_ACT : 0)
> +               | (mode->vsync_invert ? FB_SYNC_VERT_HIGH_ACT : 0);
> +       videomode->vmode = mode->invert_pixclock ? 8 : 0;
> +}
> +
> +
> +static void *alloc_framebuffer(size_t size, dma_addr_t *dma)
> +{
> +       int nr, i = 0;
> +       struct page **pages;
> +       void *start;
> +
> +       nr = size >> PAGE_SHIFT;
> +       start = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
> +       if (start == NULL)
> +               return NULL;
> +
> +       *dma = virt_to_phys(start);
> +       pages = vmalloc(sizeof(struct page *) * nr);
> +       if (pages == NULL)
> +               return NULL;
> +
> +       while (i < nr) {
> +               pages[i] = phys_to_page(*dma + (i << PAGE_SHIFT));
> +               i++;
> +       }
> +       start = vmap(pages, nr, 0, pgprot_writecombine(pgprot_kernel));
> +
> +       vfree(pages);
> +       return start;
> +}
> +
> +static int mmpfb_check_var(struct fb_var_screeninfo *var,
> +               struct fb_info *info)
> +{
> +       struct mmpfb_info *fbi = info->par;
> +
> +       if (var->bits_per_pixel == 8)
> +               return -EINVAL;
> +       /*
> +        * Basic geometry sanity checks.
> +        */
> +       if (var->xoffset + var->xres > var->xres_virtual)
> +               return -EINVAL;
> +       if (var->yoffset + var->yres > var->yres_virtual)
> +               return -EINVAL;
> +
> +       /*
> +        * Check size of framebuffer.
> +        */
> +       if (var->xres_virtual * var->yres_virtual *
> +                       (var->bits_per_pixel >> 3) > fbi->fb_size)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
> +{
> +       return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
> +}
> +
> +static u32 to_rgb(u16 red, u16 green, u16 blue)
> +{
> +       red >>= 8;
> +       green >>= 8;
> +       blue >>= 8;
> +
> +       return (red << 16) | (green << 8) | blue;
> +}
> +
> +static int mmpfb_setcolreg(unsigned int regno, unsigned int red,
> +               unsigned int green, unsigned int blue,
> +               unsigned int trans, struct fb_info *info)
> +{
> +       struct mmpfb_info *fbi = info->par;
> +       u32 val;
> +
> +       if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
> +               val =  chan_to_field(red,   &info->var.red);
> +               val |= chan_to_field(green, &info->var.green);
> +               val |= chan_to_field(blue , &info->var.blue);
> +               fbi->pseudo_palette[regno] = val;
> +       }
> +
> +       if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
> +               val = to_rgb(red, green, blue);
> +               /* TODO */
> +       }
> +
> +       return 0;
> +}
> +
> +static int mmpfb_pan_display(struct fb_var_screeninfo *var,
> +               struct fb_info *info)
> +{
> +       struct mmpfb_info *fbi = (struct mmpfb_info *)info->par;
> +       struct mmp_addr addr;
> +
> +       addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset)
> +               * var->bits_per_pixel / 8 + fbi->fb_start_dma;
> +       mmp_ovly_set_addr(fbi->ovly, &addr);
> +
> +       return 0;
> +}
> +
> +static int var_update(struct fb_info *info)
> +{
> +       struct mmpfb_info *fbi = info->par;
> +       struct fb_var_screeninfo *var = &info->var;
> +       struct fb_videomode *m;
> +       int pix_fmt;
> +
> +       /* set pix_fmt */
> +       pix_fmt = var_to_pixfmt(var);
> +       if (pix_fmt < 0)
> +               return -EINVAL;
> +       pixfmt_to_var(var, pix_fmt);
> +       fbi->pix_fmt = pix_fmt;
> +
> +       /* set var according to best video mode*/
> +       m = (struct fb_videomode *)fb_match_mode(var, &info->modelist);
> +       if (!m) {
> +               dev_err(fbi->dev, "set par: no match mode, use best mode\n");
> +               m = (struct fb_videomode *)fb_find_best_mode(var,
> +                               &info->modelist);
> +               fb_videomode_to_var(var, m);
> +       }
> +       memcpy(&fbi->mode, m, sizeof(struct fb_videomode));
> +
> +       /* fix to 2* yres */
> +       var->yres_virtual = var->yres * 2;
> +       info->fix.visual = (pix_fmt == PIXFMT_PSEUDOCOLOR) ?
> +               FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
> +       info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
> +       info->fix.ypanstep = var->yres;
> +       return 0;
> +}
> +
> +static int mmpfb_set_par(struct fb_info *info)
> +{
> +       struct mmpfb_info *fbi = info->par;
> +       struct fb_var_screeninfo *var = &info->var;
> +       struct mmp_addr addr;
> +       struct mmp_win win;
> +       struct mmp_mode mode;
> +
> +       int ret = var_update(info);
> +       if (ret != 0)
> +               return ret;
> +
> +       /* set window/path according to new videomode */
> +       fbmode_to_mmpmode(&mode, &fbi->mode, fbi->output_fmt);
> +       mmp_path_set_mode(fbi->path, &mode);
> +
> +       win.xsrc = win.xdst = fbi->mode.xres;
> +       win.ysrc = win.ydst = fbi->mode.yres;
> +       win.pix_fmt = fbi->pix_fmt;
> +       mmp_ovly_set_win(fbi->ovly, &win);
> +
> +       /* set address always */
> +       addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset)
> +               * var->bits_per_pixel / 8 + fbi->fb_start_dma;
> +       mmp_ovly_set_addr(fbi->ovly, &addr);
> +
> +       return 0;
> +}
> +
> +static void mmpfb_gfx_power(struct mmpfb_info *fbi, int power)
> +{
> +       mmp_ovly_set_onoff(fbi->ovly, power);
> +}
> +
> +static int mmpfb_gfx_blank(int blank, struct fb_info *info)
> +{
> +       struct mmpfb_info *fbi = info->par;
> +
> +       mmpfb_gfx_power(fbi, (blank == FB_BLANK_UNBLANK));
> +
> +       return 0;
> +}
> +
> +static struct fb_ops mmpfb_gfx_ops = {
> +       .owner          = THIS_MODULE,
> +       .fb_blank       = mmpfb_gfx_blank,
> +       .fb_check_var   = mmpfb_check_var,
> +       .fb_set_par     = mmpfb_set_par,
> +       .fb_setcolreg   = mmpfb_setcolreg,
> +       .fb_pan_display = mmpfb_pan_display,
> +       .fb_fillrect    = cfb_fillrect,
> +       .fb_copyarea    = cfb_copyarea,
> +       .fb_imageblit   = cfb_imageblit,
> +};
> +
> +static int __devinit mmpfb_probe(struct platform_device *pdev)
> +{
> +       struct mmp_buffer_driver_mach_info *mi;
> +       struct fb_info *info = 0;
> +       struct mmpfb_info *fbi = 0;
> +       int ret, videomode_num, i;
> +       struct fb_videomode *videomodes;
> +       struct mmp_mode *mmp_modes;
> +       struct mmp_win win;
> +       struct mmp_addr addr;
> +
> +       mi = pdev->dev.platform_data;
> +       if (mi == NULL) {
> +               dev_err(&pdev->dev, "no platform data defined\n");
> +               return -EINVAL;
> +       }
> +
> +       /* initialize fb */
> +       info = framebuffer_alloc(sizeof(struct mmpfb_info), &pdev->dev);
> +       if (info == NULL)
> +               return -ENOMEM;
> +       fbi = info->par;
> +       if (!fbi) {
> +               ret = -EINVAL;
> +               goto failed;
> +       }
> +
> +       /* init fb */
> +       fbi->fb_info = info;
> +       platform_set_drvdata(pdev, fbi);
> +       fbi->dev = &pdev->dev;
> +       fbi->pix_fmt = mi->default_pixfmt;
> +       mutex_init(&fbi->access_ok);
> +
> +       /* get display path by name */
> +       fbi->path = mmp_get_path(mi->path_name);
> +       if (!fbi->path) {
> +               dev_err(&pdev->dev, "can't get the path %s\n", mi->path_name);
> +               ret = -EINVAL;
> +               goto failed_destroy_mutex;
> +       }
> +
> +       dev_info(fbi->dev, "path %s get\n", fbi->path->name);
> +
> +       /* get videomodes from path */
> +       videomode_num = mmp_path_get_modelist(fbi->path, &mmp_modes);
> +       if (!videomode_num) {
> +               dev_err(&pdev->dev, "can't get videomode num\n");
> +               ret = -EINVAL;
> +               goto failed_destroy_mutex;
> +       }
Can you just print warning if mode number is 0, instead of failure?
Plug-able panel is likely not ready when probe and panel driver has to
return no mode info.

> +       /* put videomode list to info structure */
> +       videomodes = kzalloc(sizeof(struct fb_videomode) * videomode_num,
> +                       GFP_KERNEL);
> +       if (!videomodes) {
> +               dev_err(&pdev->dev, "can't malloc video modes\n");
> +               ret = -ENOMEM;
> +               goto failed_destroy_mutex;
> +       }
> +       for (i = 0; i < videomode_num; i++)
> +               mmpmode_to_fbmode(&videomodes[i], &mmp_modes[i]);
> +       fb_videomode_to_modelist(videomodes, videomode_num, &info->modelist);
> +
> +       /* set videomode[0] as default mode */
> +       memcpy(&fbi->mode, &videomodes[0], sizeof(struct fb_videomode));
> +       fbi->output_fmt = mmp_modes[0].pix_fmt_out;
> +       fb_videomode_to_var(&info->var, &fbi->mode);
> +       mmp_path_set_mode(fbi->path, &mmp_modes[0]);
> +       /* fix to 2* yres */
> +       info->var.yres_virtual = info->var.yres * 2;
> +       pixfmt_to_var(&info->var, fbi->pix_fmt);
> +
> +       /* Allocate framebuffer memory: size = modes xy *4 .*/
> +       fbi->fb_size = PAGE_ALIGN(info->var.xres_virtual *
> +               info->var.yres_virtual * info->var.bits_per_pixel / 8);
> +       fbi->fb_start = alloc_framebuffer(fbi->fb_size + PAGE_SIZE,
> +                               &fbi->fb_start_dma);
> +
> +       if (fbi->fb_start == NULL) {
> +               dev_err(&pdev->dev, "can't alloc framebuffer\n");
> +               ret = -ENOMEM;
> +               goto failed_destroy_mutex;
> +       }
> +       memset(fbi->fb_start, 0, fbi->fb_size);
> +
> +       dev_info(fbi->dev, "fb %dk allocated\n", fbi->fb_size/1024);
> +
> +       /* get ovly */
> +       fbi->ovly = mmp_path_get_ovly(fbi->path, mi->ovly_id);
> +       if (!fbi->ovly) {
> +               ret = -EINVAL;
> +               goto failed_destroy_mutex;
> +       }
> +       /* set fetch used */
> +       mmp_ovly_set_fetch(fbi->ovly, mi->dmafetch_id);
> +
> +       /* set win */
> +       memset(&win, 0, sizeof(win));
> +       win.pix_fmt = fbi->pix_fmt;
> +       win.xsrc = win.xdst = fbi->mode.xres;
> +       win.ysrc = win.ydst = fbi->mode.yres;
> +       mmp_ovly_set_win(fbi->ovly, &win);
> +       /* set addr */
> +       memset(&addr, 0, sizeof(addr));
> +       addr.phys[0] = fbi->fb_start_dma;
> +       mmp_ovly_set_addr(fbi->ovly, &addr);
> +       mmp_ovly_set_onoff(fbi->ovly, 1);
> +
> +       /* Initialise static fb parameters.*/
> +       info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
> +               FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
> +       info->node = -1;
> +       strcpy(info->fix.id, mi->name);
> +       info->fix.type = FB_TYPE_PACKED_PIXELS;
> +       info->fix.type_aux = 0;
> +       info->fix.xpanstep = 0;
> +       info->fix.ypanstep = info->var.yres;
> +       info->fix.ywrapstep = 0;
> +       info->fix.accel = FB_ACCEL_NONE;
> +       info->fix.smem_start = fbi->fb_start_dma;
> +       info->fix.smem_len = fbi->fb_size;
> +       info->fix.visual = (fbi->pix_fmt == PIXFMT_PSEUDOCOLOR) ?
> +               FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
> +       info->fix.line_length = info->var.xres_virtual *
> +               info->var.bits_per_pixel / 8;
> +       info->fbops = &mmpfb_gfx_ops;
> +       info->pseudo_palette = fbi->pseudo_palette;
> +       info->screen_base = fbi->fb_start;
> +       info->screen_size = fbi->fb_size;
> +
> +       /* For FB framework: Allocate color map and Register framebuffer*/
> +       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
> +               ret = -ENOMEM;
> +               goto failed_free_buff;
> +       }
> +       ret = register_framebuffer(info);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Failed to register fb: %d\n", ret);
> +               ret = -ENXIO;
> +               goto failed_free_cmap;
> +       }
> +
> +       dev_info(fbi->dev, "loaded to /dev/fb%d <%s>.\n",
> +               info->node, info->fix.id);
> +
> +#ifdef CONFIG_ANDROID
> +       if (fbi->fb_start) {
> +               fb_prepare_logo(info, 0);
> +               fb_show_logo(info, 0);
> +       }
> +#endif
> +
> +       return 0;
> +
> +failed_free_cmap:
> +       fb_dealloc_cmap(&info->cmap);
> +failed_free_buff:
> +       vfree(fbi->fb_start);
> +       kfree(videomodes);
> +failed_destroy_mutex:
> +       mutex_destroy(&fbi->access_ok);
> +failed:
> +       dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n");
> +       platform_set_drvdata(pdev, NULL);
> +
> +       framebuffer_release(info);
> +
> +       return ret;
> +}
> +
> +static struct platform_driver mmpfb_driver = {
> +       .driver         = {
> +               .name   = "mmp-fb",
> +               .owner  = THIS_MODULE,
> +       },
> +       .probe          = mmpfb_probe,
> +};
> +
> +static int __devinit mmpfb_init(void)
> +{
> +       return platform_driver_register(&mmpfb_driver);
> +}
> +module_init(mmpfb_init);
> +
> +MODULE_AUTHOR("Zhou Zhu <zhou.zhu@xxxxxxxxxxx>");
> +MODULE_DESCRIPTION("Framebuffer driver for Marvell displays");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/video/mmp/fb/mmpfb.h b/drivers/video/mmp/fb/mmpfb.h
> new file mode 100644
> index 0000000..7f8a71d
> --- /dev/null
> +++ b/drivers/video/mmp/fb/mmpfb.h
> @@ -0,0 +1,51 @@
> +/*
> + * linux/drivers/video/mmp/fb/mmpfb.h
> + * Framebuffer driver for Marvell Display controller.
> + *
> + * Copyright (C) 2012 Marvell Technology Group Ltd.
> + * Authors: Zhou Zhu <zzhu3@xxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#ifndef _MMP_FB_H_
> +#define _MMP_FB_H_
> +
> +#include <video/mmp_disp.h>
> +#include <linux/fb.h>
> +
> +/* LCD controller private state. */
> +struct mmpfb_info {
> +       struct device   *dev;
> +       int     id;
> +
> +       struct fb_info  *fb_info;
> +       /* basicaly videomode is for output */
> +       struct fb_videomode     mode;
> +       int     pix_fmt;
> +
> +       void    *fb_start;
> +       int     fb_size;
> +       dma_addr_t      fb_start_dma;
> +
> +       struct mmp_ovly *ovly;
> +       struct mmp_path *path;
> +
> +       struct mutex    access_ok;
> +
> +       unsigned int            pseudo_palette[16];
> +       int output_fmt;
> +};
> +#endif /* _MMP_FB_H_ */
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Tourism]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux