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