[PATCH] Add new framebuffer driver for Fujitsu MB862xx GDCs

Matteo Fortini m.fortini at selcomgroup.com
Thu Oct 16 00:40:15 EST 2008


What about the mb86290 framebuffer driver directly from Fujitsu which is 
in the mainline kernel?
It's from 2003 and supports only until 86293, but can it be used as a 
basis for a proper fb driver? It has a lot of features indeed...

M

Anatolij Gustschin ha scritto:
> This patch adds framebuffer driver for Fujitsu
> Carmine/Coral-P(A)/Lime graphics controllers.
> Lime GDC support is known to work on PPC440EPx
> based lwmon5 and MPC8544E based socrates embedded
> boards, both equipped with Lime GDC. Carmine/Coral-P
> PCI GDC support is known to work on PPC440EPx based
> Sequoia board and also on x86 platform.
>
> Signed-off-by: Anatolij Gustschin <agust at denx.de>
> ---
> There are some PPC OF bits, so I'm cc'ing linuxppc-dev list.
>
>  drivers/video/Kconfig               |   31 +
>  drivers/video/Makefile              |    1 +
>  drivers/video/mb862xx/Makefile      |    5 +
>  drivers/video/mb862xx/mb862xx_reg.h |  138 +++++
>  drivers/video/mb862xx/mb862xxfb.c   | 1061 +++++++++++++++++++++++++++++++++++
>  drivers/video/mb862xx/mb862xxfb.h   |   83 +++
>  6 files changed, 1319 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/video/mb862xx/Makefile
>  create mode 100644 drivers/video/mb862xx/mb862xx_reg.h
>  create mode 100644 drivers/video/mb862xx/mb862xxfb.c
>  create mode 100644 drivers/video/mb862xx/mb862xxfb.h
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index f79c204..f13182a 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -2034,6 +2034,37 @@ config FB_METRONOME
>  	  controller. The pre-release name for this device was 8track
>  	  and could also have been called by some vendors as PVI-nnnn.
>  
> +config FB_MB862XX
> +	tristate "Fujitsu MB862xx GDC support"
> +	depends on FB
> +	select FB_CFB_FILLRECT
> +	select FB_CFB_COPYAREA
> +	select FB_CFB_IMAGEBLIT
> +	---help---
> +	  Frame buffer driver for Fujitsu Carmine/Coral-P(A)/Lime controllers.
> +
> +config FB_MB862XX_PCI_GDC
> +	bool "Carmine/Coral-P(A) GDC"
> +	depends on FB_MB862XX
> +	---help---
> +	  This enables framebuffer support for Fujitsu Carmine/Coral-P(A)
> +	  PCI graphics controller devices.
> +
> +config FB_MB862XX_LIME
> +	bool "Lime GDC"
> +	depends on FB_MB862XX
> +	select FB_FOREIGN_ENDIAN
> +	select FB_LITTLE_ENDIAN
> +	---help---
> +	  Framebuffer support for Fujitsu Lime GDC on host CPU bus.
> +
> +config FB_PRE_INIT_FB
> +	bool "Don't reinitialize, use bootloader's GDC/Display configuration"
> +	depends on FB_MB862XX_LIME
> +	---help---
> +	  Select this option if display contents should be inherited as set by
> +	  the bootloader.
> +
>  source "drivers/video/omap/Kconfig"
>  
>  source "drivers/video/backlight/Kconfig"
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index ad0330b..218fe56 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -120,6 +120,7 @@ obj-$(CONFIG_FB_SH_MOBILE_LCDC)	  += sh_mobile_lcdcfb.o
>  obj-$(CONFIG_FB_OMAP)             += omap/
>  obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
>  obj-$(CONFIG_FB_CARMINE)          += carminefb.o
> +obj-$(CONFIG_FB_MB862XX)	  += mb862xx/
>  
>  # Platform or fallback drivers go here
>  obj-$(CONFIG_FB_UVESA)            += uvesafb.o
> diff --git a/drivers/video/mb862xx/Makefile b/drivers/video/mb862xx/Makefile
> new file mode 100644
> index 0000000..0766481
> --- /dev/null
> +++ b/drivers/video/mb862xx/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for the MB862xx framebuffer driver
> +#
> +
> +obj-$(CONFIG_FB_MB862XX)	:= mb862xxfb.o
> diff --git a/drivers/video/mb862xx/mb862xx_reg.h b/drivers/video/mb862xx/mb862xx_reg.h
> new file mode 100644
> index 0000000..2ba65e1
> --- /dev/null
> +++ b/drivers/video/mb862xx/mb862xx_reg.h
> @@ -0,0 +1,138 @@
> +/*
> + * Fujitsu MB862xx Graphics Controller Registers/Bits
> + */
> +
> +#ifndef _MB862XX_REG_H
> +#define _MB862XX_REG_H
> +
> +#ifdef MB862XX_MMIO_BOTTOM
> +#define MB862XX_MMIO_BASE	0x03fc0000
> +#else
> +#define MB862XX_MMIO_BASE	0x01fc0000
> +#endif
> +#define MB862XX_I2C_BASE	0x0000c000
> +#define MB862XX_DISP_BASE	0x00010000
> +#define MB862XX_CAP_BASE	0x00018000
> +#define MB862XX_DRAW_BASE	0x00030000
> +#define MB862XX_GEO_BASE	0x00038000
> +#define MB862XX_PIO_BASE	0x00038000
> +#define MB862XX_MMIO_SIZE	0x40000
> +
> +/* Host interface/pio registers */
> +#define GC_IST			0x00000020
> +#define GC_IMASK		0x00000024
> +#define GC_SRST			0x0000002c
> +#define GC_CCF			0x00000038
> +#define GC_CID			0x000000f0
> +#define GC_REVISION		0x00000084
> +
> +#define GC_CCF_CGE_100		0x00000000
> +#define GC_CCF_CGE_133		0x00040000
> +#define GC_CCF_CGE_166		0x00080000
> +#define GC_CCF_COT_100		0x00000000
> +#define GC_CCF_COT_133		0x00010000
> +#define GC_CID_CNAME_MSK	0x0000ff00
> +#define GC_CID_VERSION_MSK	0x000000ff
> +
> +/* define enabled interrupts hereby */
> +#define GC_INT_EN		0x00000000
> +
> +/* Memory interface mode register */
> +#define GC_MMR			0x0000fffc
> +
> +/* Display Controller registers */
> +#define GC_DCM0			0x00000000
> +#define GC_HTP			0x00000004
> +#define GC_HDB_HDP		0x00000008
> +#define GC_VSW_HSW_HSP		0x0000000c
> +#define GC_VTR			0x00000010
> +#define GC_VDP_VSP		0x00000014
> +#define GC_WY_WX		0x00000018
> +#define GC_WH_WW		0x0000001c
> +#define GC_L0M			0x00000020
> +#define GC_L0OA0		0x00000024
> +#define GC_L0DA0		0x00000028
> +#define GC_L0DY_L0DX		0x0000002c
> +#define GC_DCM1			0x00000100
> +#define GC_L0EM			0x00000110
> +#define GC_L0WY_L0WX		0x00000114
> +#define GC_L0WH_L0WW		0x00000118
> +#define GC_DCM2			0x00000104
> +#define GC_DCM3			0x00000108
> +#define GC_CPM_CUTC		0x000000a0
> +#define GC_CUOA0		0x000000a4
> +#define GC_CUY0_CUX0		0x000000a8
> +#define GC_CUOA1		0x000000ac
> +#define GC_CUY1_CUX1		0x000000b0
> +#define GC_L0PAL0		0x00000400
> +
> +#define GC_CPM_CEN0		0x00100000
> +#define GC_CPM_CEN1		0x00200000
> +
> +#define GC_DCM01_ESY		0x00000004
> +#define GC_DCM01_SC		0x00003f00
> +#define GC_DCM01_RESV		0x00004000
> +#define GC_DCM01_CKS		0x00008000
> +#define GC_DCM01_L0E		0x00010000
> +#define GC_DCM01_DEN		0x80000000
> +#define GC_L0M_L0C_8		0x00000000
> +#define GC_L0M_L0C_16		0x80000000
> +#define GC_L0EM_L0EC_24		0x40000000
> +#define GC_L0M_L0W_UNIT		64
> +
> +#define GC_DISP_REFCLK_400	400
> +
> +/* Carmine specific */
> +#define MB86297_DRAW_BASE		0x00020000
> +#define MB86297_DISP0_BASE		0x00100000
> +#define MB86297_DISP1_BASE		0x00140000
> +#define MB86297_WRBACK_BASE		0x00180000
> +#define MB86297_CAP0_BASE		0x00200000
> +#define MB86297_CAP1_BASE		0x00280000
> +#define MB86297_DRAMCTRL_BASE		0x00300000
> +#define MB86297_CTRL_BASE		0x00400000
> +#define MB86297_I2C_BASE		0x00500000
> +
> +#define GC_CTRL_STATUS			0x00000000
> +#define GC_CTRL_INT_MASK		0x00000004
> +#define GC_CTRL_CLK_ENABLE		0x0000000c
> +#define GC_CTRL_SOFT_RST		0x00000010
> +
> +#define GC_CTRL_CLK_EN_DRAM		0x00000001
> +#define GC_CTRL_CLK_EN_2D3D		0x00000002
> +#define GC_CTRL_CLK_EN_DISP0		0x00000020
> +#define GC_CTRL_CLK_EN_DISP1		0x00000040
> +
> +#define GC_2D3D_REV			0x000004b4
> +#define GC_RE_REVISION			0x24240200
> +
> +/* define enabled interrupts hereby */
> +#define GC_CARMINE_INT_EN		0x00000004
> +
> +/* DRAM controller */
> +#define GC_DCTL_MODE_ADD		0x00000000
> +#define GC_DCTL_SETTIME1_EMODE		0x00000004
> +#define GC_DCTL_REFRESH_SETTIME2	0x00000008
> +#define GC_DCTL_RSV0_STATES		0x0000000C
> +#define GC_DCTL_RSV2_RSV1		0x00000010
> +#define GC_DCTL_DDRIF2_DDRIF1		0x00000014
> +#define GC_DCTL_IOCONT1_IOCONT0		0x00000024
> +
> +#define GC_DCTL_STATES_MSK		0x0000000f
> +#define GC_DCTL_INIT_WAIT_CNT		3000
> +#define GC_DCTL_INIT_WAIT_INTERVAL	1
> +
> +/* DRAM ctrl values for Carmine PCI Eval. board */
> +#define GC_EVB_DCTL_MODE_ADD		0x012105c3
> +#define GC_EVB_DCTL_MODE_ADD_AFT_RST	0x002105c3
> +#define GC_EVB_DCTL_SETTIME1_EMODE	0x47498000
> +#define GC_EVB_DCTL_REFRESH_SETTIME2	0x00422a22
> +#define GC_EVB_DCTL_RSV0_STATES		0x00200003
> +#define GC_EVB_DCTL_RSV0_STATES_AFT_RST	0x00200002
> +#define GC_EVB_DCTL_RSV2_RSV1		0x0000000f
> +#define GC_EVB_DCTL_DDRIF2_DDRIF1	0x00556646
> +#define GC_EVB_DCTL_IOCONT1_IOCONT0	0x05550555
> +
> +#define GC_DISP_REFCLK_533		533
> +
> +#endif
> diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c
> new file mode 100644
> index 0000000..26b66cb
> --- /dev/null
> +++ b/drivers/video/mb862xx/mb862xxfb.c
> @@ -0,0 +1,1061 @@
> +/*
> + * drivers/mb862xx/mb862xxfb.c
> + *
> + * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver
> + *
> + * (C) 2008 Anatolij Gustschin <agust at denx.de>
> + * DENX Software Engineering
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#undef DEBUG
> +
> +#include <linux/fb.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/pci.h>
> +#if defined(CONFIG_PPC_OF)
> +#include <linux/of_platform.h>
> +#endif
> +#include "mb862xxfb.h"
> +#include "mb862xx_reg.h"
> +
> +#define NR_PALETTE		256
> +#define MB862XX_MEM_SIZE	0x1000000
> +#define CORALP_MEM_SIZE		0x4000000
> +#define CARMINE_MEM_SIZE	0x8000000
> +#define DRV_NAME		"mb862xxfb"
> +
> +#if defined(CONFIG_LWMON5)
> +static struct mb862xx_gc_mode lwmon5_gc_mode = {
> +	/* Mode for Sharp LQ104V1DG61 TFT LCD Panel */
> +	{ "640x480", 60, 640, 480, 40000, 48, 16, 32, 11, 96, 2, 0, 0, 0 },
> +	/* 16 bits/pixel, 32MB, 100MHz, SDRAM memory mode value */
> +	16, 0x2000000, GC_CCF_COT_100, 0x414fb7f2
> +};
> +#endif
> +
> +#if defined(CONFIG_SOCRATES)
> +static struct mb862xx_gc_mode socrates_gc_mode = {
> +	/* Mode for Prime View PM070WL4 TFT LCD Panel */
> +	{ "800x480", 45, 800, 480, 40000, 86, 42, 33, 10, 128, 2, 0, 0, 0 },
> +	/* 16 bits/pixel, 16MB, 133MHz, SDRAM memory mode value */
> +	16, 0x1000000, GC_CCF_COT_133, 0x4157ba63
> +};
> +#endif
> +
> +/* Helpers */
> +static inline int h_total(struct fb_var_screeninfo *var)
> +{
> +	return var->xres + var->left_margin +
> +		var->right_margin + var->hsync_len;
> +}
> +
> +static inline int v_total(struct fb_var_screeninfo *var)
> +{
> +	return var->yres + var->upper_margin +
> +		var->lower_margin + var->vsync_len;
> +}
> +
> +static inline int hsp(struct fb_var_screeninfo *var)
> +{
> +	return var->xres + var->right_margin - 1;
> +}
> +
> +static inline int vsp(struct fb_var_screeninfo *var)
> +{
> +	return var->yres + var->lower_margin - 1;
> +}
> +
> +static inline int d_pitch(struct fb_var_screeninfo *var)
> +{
> +	return var->xres * var->bits_per_pixel / 8;
> +}
> +
> +static inline unsigned int chan_to_field(unsigned int chan,
> +					 struct fb_bitfield *bf)
> +{
> +	chan &= 0xffff;
> +	chan >>= 16 - bf->length;
> +	return chan << bf->offset;
> +}
> +
> +static int mb862xxfb_setcolreg(unsigned regno,
> +			       unsigned red, unsigned green, unsigned blue,
> +			       unsigned transp, struct fb_info *info)
> +{
> +	struct mb862xxfb_par *par = info->par;
> +	unsigned int val;
> +
> +	switch (info->fix.visual) {
> +	case FB_VISUAL_TRUECOLOR:
> +		if (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);
> +			par->pseudo_palette[regno] = val;
> +		}
> +		break;
> +	case FB_VISUAL_PSEUDOCOLOR:
> +		if (regno < 256) {
> +			val = (red >> 8) << 16;
> +			val |= (green >> 8) << 8;
> +			val |= blue >> 8;
> +			outreg(disp, GC_L0PAL0 + (regno * 4), val);
> +		}
> +		break;
> +	default:
> +		return 1;   /* unsupported type */
> +	}
> +	return 0;
> +}
> +
> +static int mb862xxfb_check_var(struct fb_var_screeninfo *var,
> +			       struct fb_info *fbi)
> +{
> +	unsigned long tmp;
> +
> +	if (fbi->dev)
> +		dev_dbg(fbi->dev, "%s\n", __func__);
> +
> +	/* check if these values fit into the registers */
> +	if (var->hsync_len > 255 || var->vsync_len > 255)
> +		return -EINVAL;
> +
> +	if ((var->xres + var->right_margin) >= 4096)
> +		return -EINVAL;
> +
> +	if ((var->yres + var->lower_margin) > 4096)
> +		return -EINVAL;
> +
> +	if (h_total(var) > 4096 || v_total(var) > 4096)
> +		return -EINVAL;
> +
> +	if (var->xres_virtual > 4096 || var->yres_virtual > 4096)
> +		return -EINVAL;
> +
> +	if (var->bits_per_pixel <= 8)
> +		var->bits_per_pixel = 8;
> +	else if (var->bits_per_pixel <= 16)
> +		var->bits_per_pixel = 16;
> +	else if (var->bits_per_pixel <= 32)
> +		var->bits_per_pixel = 32;
> +
> +	/*
> +	 * can cope with 8,16 or 24/32bpp if resulting
> +	 * pitch is divisible by 64 without remainder
> +	 */
> +	if (d_pitch(&fbi->var) % GC_L0M_L0W_UNIT) {
> +		int r;
> +
> +		var->bits_per_pixel = 0;
> +		do {
> +			var->bits_per_pixel += 8;
> +			r = d_pitch(&fbi->var) % GC_L0M_L0W_UNIT;
> +		} while (r && var->bits_per_pixel <= 32);
> +
> +		if (d_pitch(&fbi->var) % GC_L0M_L0W_UNIT)
> +			return -EINVAL;
> +	}
> +
> +	/* line length is going to be 128 bit aligned */
> +	tmp = (var->xres * var->bits_per_pixel) / 8;
> +	if ((tmp & 15) != 0)
> +		return -EINVAL;
> +
> +	/* set r/g/b positions and validate bpp */
> +	switch (var->bits_per_pixel) {
> +	case 8:
> +		var->red.length		= var->bits_per_pixel;
> +		var->green.length	= var->bits_per_pixel;
> +		var->blue.length	= var->bits_per_pixel;
> +		var->red.offset		= 0;
> +		var->green.offset	= 0;
> +		var->blue.offset	= 0;
> +		var->transp.length	= 0;
> +		break;
> +	case 16:
> +		var->red.length		= 5;
> +		var->green.length	= 5;
> +		var->blue.length	= 5;
> +		var->red.offset		= 10;
> +		var->green.offset	= 5;
> +		var->blue.offset	= 0;
> +		var->transp.length	= 0;
> +		break;
> +	case 24:
> +	case 32:
> +		var->transp.length	= 8;
> +		var->red.length		= 8;
> +		var->green.length	= 8;
> +		var->blue.length	= 8;
> +		var->transp.offset	= 24;
> +		var->red.offset		= 16;
> +		var->green.offset	= 8;
> +		var->blue.offset	= 0;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * set display parameters
> + */
> +static int mb862xxfb_set_par(struct fb_info *fbi)
> +{
> +	struct mb862xxfb_par *par = fbi->par;
> +	unsigned long reg, sc;
> +
> +	dev_dbg(par->dev, "%s\n", __func__);
> +
> +	if (par->pre_init)
> +		return 0;
> +
> +	/* disp off */
> +	reg = inreg(disp, GC_DCM1);
> +	reg &= ~GC_DCM01_DEN;
> +	outreg(disp, GC_DCM1, reg);
> +
> +	/* set display reference clock div. */
> +	sc = par->refclk / (1000000 / fbi->var.pixclock) - 1;
> +	reg = inreg(disp, GC_DCM1);
> +	reg &= ~(GC_DCM01_CKS | GC_DCM01_RESV | GC_DCM01_SC);
> +	reg |= sc << 8;
> +	outreg(disp, GC_DCM1, reg);
> +	dev_dbg(par->dev, "SC 0x%lx\n", sc);
> +
> +	/* disp dimension, format */
> +	reg =  pack(d_pitch(&fbi->var) / GC_L0M_L0W_UNIT,
> +		    (fbi->var.yres - 1));
> +	if (fbi->var.bits_per_pixel == 16)
> +		reg |= GC_L0M_L0C_16;
> +	outreg(disp, GC_L0M, reg);
> +
> +	if (fbi->var.bits_per_pixel == 32) {
> +		reg = inreg(disp, GC_L0EM);
> +		outreg(disp, GC_L0EM, reg | GC_L0EM_L0EC_24);
> +	}
> +	outreg(disp, GC_WY_WX, 0);
> +	reg = pack(fbi->var.yres - 1, fbi->var.xres);
> +	outreg(disp, GC_WH_WW, reg);
> +	outreg(disp, GC_L0OA0, 0);
> +	outreg(disp, GC_L0DA0, 0);
> +	outreg(disp, GC_L0DY_L0DX, 0);
> +	outreg(disp, GC_L0WY_L0WX, 0);
> +	outreg(disp, GC_L0WH_L0WW, reg);
> +
> +	/* both HW-cursors off */
> +	reg = inreg(disp, GC_CPM_CUTC);
> +	reg &= ~(GC_CPM_CEN0 | GC_CPM_CEN1);
> +	outreg(disp, GC_CPM_CUTC, reg);
> +
> +	/* timings */
> +	reg = pack(fbi->var.xres - 1, fbi->var.xres - 1);
> +	outreg(disp, GC_HDB_HDP, reg);
> +	reg = pack((fbi->var.yres - 1), vsp(&fbi->var));
> +	outreg(disp, GC_VDP_VSP, reg);
> +	reg = ((fbi->var.vsync_len - 1) << 24) |
> +	      pack((fbi->var.hsync_len - 1), hsp(&fbi->var));
> +	outreg(disp, GC_VSW_HSW_HSP, reg);
> +	outreg(disp, GC_HTP, pack(h_total(&fbi->var) - 1, 0));
> +	outreg(disp, GC_VTR, pack(v_total(&fbi->var) - 1, 0));
> +
> +	/* display on */
> +	reg = inreg(disp, GC_DCM1);
> +	reg |= GC_DCM01_DEN | GC_DCM01_L0E;
> +	reg &= ~GC_DCM01_ESY;
> +	outreg(disp, GC_DCM1, reg);
> +	return 0;
> +}
> +
> +static int mb862xxfb_pan(struct fb_var_screeninfo *var,
> +			 struct fb_info *info)
> +{
> +	struct mb862xxfb_par *par = info->par;
> +	unsigned long reg;
> +
> +	reg = pack(var->yoffset, var->xoffset);
> +	outreg(disp, GC_L0WY_L0WX, reg);
> +
> +	reg = pack(var->yres_virtual, var->xres_virtual);
> +	outreg(disp, GC_L0WH_L0WW, reg);
> +	return 0;
> +}
> +
> +static int mb862xxfb_blank(int mode, struct fb_info *fbi)
> +{
> +	struct mb862xxfb_par  *par = fbi->par;
> +	unsigned long reg;
> +
> +	dev_dbg(fbi->dev, "blank mode=%d\n", mode);
> +
> +	switch (mode) {
> +	case FB_BLANK_POWERDOWN:
> +		reg = inreg(disp, GC_DCM1);
> +		reg &= ~GC_DCM01_DEN;
> +		outreg(disp, GC_DCM1, reg);
> +		break;
> +	case FB_BLANK_UNBLANK:
> +		reg = inreg(disp, GC_DCM1);
> +		reg |= GC_DCM01_DEN;
> +		outreg(disp, GC_DCM1, reg);
> +		break;
> +	case FB_BLANK_NORMAL:
> +	case FB_BLANK_VSYNC_SUSPEND:
> +	case FB_BLANK_HSYNC_SUSPEND:
> +	default:
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +/* framebuffer ops */
> +static struct fb_ops mb862xxfb_ops = {
> +	.owner		= THIS_MODULE,
> +	.fb_check_var	= mb862xxfb_check_var,
> +	.fb_set_par	= mb862xxfb_set_par,
> +	.fb_setcolreg	= mb862xxfb_setcolreg,
> +	.fb_blank	= mb862xxfb_blank,
> +	.fb_pan_display	= mb862xxfb_pan,
> +	.fb_fillrect	= cfb_fillrect,
> +	.fb_copyarea	= cfb_copyarea,
> +	.fb_imageblit	= cfb_imageblit,
> +};
> +
> +/* initialize fb_info data */
> +static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
> +{
> +	struct mb862xxfb_par *par = fbi->par;
> +	struct mb862xx_gc_mode *mode = par->gc_mode;
> +	unsigned long reg;
> +
> +	fbi->fbops = &mb862xxfb_ops;
> +	fbi->pseudo_palette = par->pseudo_palette;
> +	fbi->screen_base = par->fb_base;
> +	fbi->screen_size = par->mapped_vram;
> +
> +	strcpy(fbi->fix.id, DRV_NAME);
> +	fbi->fix.smem_start = (unsigned long)par->fb_base_phys;
> +	fbi->fix.smem_len = par->mapped_vram;
> +	fbi->fix.mmio_start = (unsigned long)par->mmio_base_phys;
> +	fbi->fix.mmio_len = par->mmio_len;
> +	fbi->fix.accel = FB_ACCEL_NONE;
> +	fbi->fix.type = FB_TYPE_PACKED_PIXELS;
> +	fbi->fix.type_aux = 0;
> +	fbi->fix.xpanstep = 1;
> +	fbi->fix.ypanstep = 1;
> +	fbi->fix.ywrapstep = 0;
> +
> +	reg = inreg(disp, GC_DCM1);
> +	if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E) {
> +		/* get the disp mode from active display cfg */
> +		unsigned long sc = ((reg & GC_DCM01_SC) >> 8) + 1;
> +		unsigned long hsp, vsp, ht, vt;
> +
> +		dev_dbg(par->dev, "using bootloader's disp. mode\n");
> +		fbi->var.pixclock = (sc * 1000000) / par->refclk;
> +		fbi->var.xres = (inreg(disp, GC_HDB_HDP) & 0x0fff) + 1;
> +		reg = inreg(disp, GC_VDP_VSP);
> +		fbi->var.yres = ((reg >> 16) & 0x0fff) + 1;
> +		vsp = (reg & 0x0fff) + 1;
> +		fbi->var.xres_virtual = fbi->var.xres;
> +		fbi->var.yres_virtual = fbi->var.yres;
> +		reg = inreg(disp, GC_L0EM);
> +		if (reg & GC_L0EM_L0EC_24) {
> +			fbi->var.bits_per_pixel = 32;
> +		} else {
> +			reg = inreg(disp, GC_L0M);
> +			if (reg & GC_L0M_L0C_16)
> +				fbi->var.bits_per_pixel = 16;
> +			else
> +				fbi->var.bits_per_pixel = 8;
> +		}
> +		reg = inreg(disp, GC_VSW_HSW_HSP);
> +		fbi->var.hsync_len = ((reg & 0xff0000) >> 16) + 1;
> +		fbi->var.vsync_len = ((reg & 0x3f000000) >> 24) + 1;
> +		hsp = (reg & 0xffff) + 1;
> +		ht = ((inreg(disp, GC_HTP) & 0xfff0000) >> 16) + 1;
> +		fbi->var.right_margin = hsp - fbi->var.xres;
> +		fbi->var.left_margin = ht - hsp - fbi->var.hsync_len;
> +		vt = ((inreg(disp, GC_VTR) & 0xfff0000) >> 16) + 1;
> +		fbi->var.lower_margin = vsp - fbi->var.yres;
> +		fbi->var.upper_margin = vt - vsp - fbi->var.vsync_len;
> +	} else if (mode) {
> +		dev_dbg(par->dev, "using supplied mode\n");
> +		fb_videomode_to_var(&fbi->var, (struct fb_videomode *)mode);
> +		fbi->var.bits_per_pixel = mode->def_bpp ? mode->def_bpp : 8;
> +	} else {
> +		int ret;
> +
> +		ret = fb_find_mode(&fbi->var, fbi, "640x480-16 at 60",
> +				   NULL, 0, NULL, 16);
> +		if (ret == 0 || ret == 4) {
> +			dev_err(par->dev,
> +				"failed to get initial mode\n");
> +			return -EINVAL;
> +		}
> +	}
> +
> +	fbi->var.xoffset = 0;
> +	fbi->var.yoffset = 0;
> +	fbi->var.grayscale = 0;
> +	fbi->var.nonstd = 0;
> +	fbi->var.height = -1;
> +	fbi->var.width = -1;
> +	fbi->var.accel_flags = 0;
> +	fbi->var.vmode = FB_VMODE_NONINTERLACED;
> +	fbi->var.activate = FB_ACTIVATE_NOW;
> +	fbi->flags = FBINFO_DEFAULT |
> +#ifdef __BIG_ENDIAN
> +		     FBINFO_FOREIGN_ENDIAN |
> +#endif
> +		     FBINFO_HWACCEL_XPAN |
> +		     FBINFO_HWACCEL_YPAN;
> +
> +	/* check and possibly fix bpp */
> +	if ((fbi->fbops->fb_check_var)(&fbi->var, fbi))
> +		dev_err(par->dev, "check_var() failed on initial setup?\n");
> +
> +	fbi->fix.visual = fbi->var.bits_per_pixel == 8 ?
> +			 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
> +	fbi->fix.line_length = (fbi->var.xres_virtual *
> +				fbi->var.bits_per_pixel) / 8;
> +	return 0;
> +}
> +
> +/*
> + * show some display controller and cursor registers
> + */
> +static ssize_t mb862xxfb_show_dispregs(struct device *dev,
> +				       struct device_attribute *attr, char *buf)
> +{
> +	struct fb_info *fbi = dev_get_drvdata(dev);
> +	struct mb862xxfb_par *par = fbi->par;
> +	char *ptr = buf;
> +	unsigned int reg;
> +
> +	for (reg = GC_DCM0; reg <= GC_L0DY_L0DX; reg += 4)
> +		ptr += sprintf(ptr, "%08x = %08x\n",
> +			       reg, inreg(disp, reg));
> +
> +	for (reg = GC_CPM_CUTC; reg <= GC_CUY1_CUX1; reg += 4)
> +		ptr += sprintf(ptr, "%08x = %08x\n",
> +			       reg, inreg(disp, reg));
> +
> +	for (reg = GC_DCM1; reg <= GC_L0WH_L0WW; reg += 4)
> +		ptr += sprintf(ptr, "%08x = %08x\n",
> +			       reg, inreg(disp, reg));
> +
> +	return ptr - buf;
> +}
> +
> +static DEVICE_ATTR(dispregs, 0444, mb862xxfb_show_dispregs, NULL);
> +
> +irqreturn_t mb862xx_intr(int irq, void *dev_id)
> +{
> +	struct mb862xxfb_par *par = (struct mb862xxfb_par *) dev_id;
> +	unsigned long reg_ist, mask;
> +
> +	if (!par)
> +		return IRQ_NONE;
> +
> +	if (par->type == BT_CARMINE) {
> +		/* Get Interrupt Status */
> +		reg_ist = inreg(ctrl, GC_CTRL_STATUS);
> +		mask = inreg(ctrl, GC_CTRL_INT_MASK);
> +		if (reg_ist == 0)
> +			return IRQ_HANDLED;
> +
> +		reg_ist &= mask;
> +		if (reg_ist == 0)
> +			return IRQ_HANDLED;
> +
> +		/* Clear interrupt status */
> +		outreg(ctrl, 0x0, reg_ist);
> +	} else {
> +		/* Get status */
> +		reg_ist = inreg(host, GC_IST);
> +		mask = inreg(host, GC_IMASK);
> +
> +		reg_ist &= mask;
> +		if (reg_ist == 0)
> +			return IRQ_HANDLED;
> +
> +		/* Clear status */
> +		outreg(host, GC_IST, ~reg_ist);
> +	}
> +	return IRQ_HANDLED;
> +}
> +
> +#if defined(CONFIG_FB_MB862XX_LIME)
> +/*
> + * GDC (Lime, Coral(B/Q), Mint, ...) on host bus
> + */
> +static int mb862xx_gdc_init(struct mb862xxfb_par *par)
> +{
> +	unsigned long ccf, mmr;
> +	unsigned long ver, rev;
> +
> +	if (!par)
> +		return -ENODEV;
> +
> +#if defined(CONFIG_FB_PRE_INIT_FB)
> +	par->pre_init = 1;
> +#endif
> +	par->host = par->mmio_base;
> +	par->i2c = par->mmio_base + MB862XX_I2C_BASE;
> +	par->disp = par->mmio_base + MB862XX_DISP_BASE;
> +	par->cap = par->mmio_base + MB862XX_CAP_BASE;
> +	par->draw = par->mmio_base + MB862XX_DRAW_BASE;
> +	par->geo = par->mmio_base + MB862XX_GEO_BASE;
> +	par->pio = par->mmio_base + MB862XX_PIO_BASE;
> +
> +	par->refclk = GC_DISP_REFCLK_400;
> +
> +	ver = inreg(host, GC_CID);
> +	rev = inreg(pio, GC_REVISION);
> +	if ((ver == 0x303) && (rev & 0xffffff00) == 0x20050100) {
> +		dev_info(par->dev, "Fujitsu Lime v1.%d found\n",
> +			 (int)rev & 0xff);
> +		par->type = BT_LIME;
> +		ccf = par->gc_mode ? par->gc_mode->ccf : GC_CCF_COT_100;
> +		mmr = par->gc_mode ? par->gc_mode->mmr : 0x414fb7f2;
> +	} else {
> +		dev_info(par->dev, "? GDC, CID/Rev.: 0x%lx/0x%lx \n", ver, rev);
> +		return -ENODEV;
> +	}
> +
> +	if (!par->pre_init) {
> +		outreg(host, GC_CCF, ccf);
> +		udelay(200);
> +		outreg(host, GC_MMR, mmr);
> +		udelay(10);
> +	}
> +
> +	/* interrupt status */
> +	outreg(host, GC_IST, 0);
> +	outreg(host, GC_IMASK, GC_INT_EN);
> +	return 0;
> +}
> +
> +static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev,
> +					       const struct of_device_id *id)
> +{
> +	struct device_node *np = ofdev->node;
> +	struct device *dev = &ofdev->dev;
> +	struct mb862xxfb_par *par;
> +	struct fb_info *info;
> +	struct resource res;
> +	resource_size_t res_size;
> +	unsigned long ret;
> +
> +	if (of_address_to_resource(np, 0, &res)) {
> +		dev_err(dev, "Invalid address\n");
> +		return -ENXIO;
> +	}
> +
> +	info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev);
> +	if (info == NULL) {
> +		dev_err(dev, "cannot allocate framebuffer\n");
> +		return -ENOMEM;
> +	}
> +
> +	par = info->par;
> +	par->info = info;
> +	par->dev = dev;
> +
> +	par->irq = irq_of_parse_and_map(np, 0);
> +	if (par->irq == NO_IRQ) {
> +		dev_err(dev, "failed to map irq\n");
> +		ret = -ENODEV;
> +		goto fbrel;
> +	}
> +
> +	res_size = 1 + res.end - res.start;
> +	par->res = request_mem_region(res.start, res_size, DRV_NAME);
> +	if (par->res == NULL) {
> +		dev_err(dev, "Cannot claim framebuffer/mmio\n");
> +		ret = -ENXIO;
> +		goto irqdisp;
> +	}
> +
> +#if defined(CONFIG_LWMON5)
> +	par->gc_mode = &lwmon5_gc_mode;
> +#endif
> +
> +#if defined(CONFIG_SOCRATES)
> +	par->gc_mode = &socrates_gc_mode;
> +#endif
> +
> +	par->fb_base_phys = res.start;
> +	par->mmio_base_phys = res.start + MB862XX_MMIO_BASE;
> +	par->mmio_len = MB862XX_MMIO_SIZE;
> +	if (par->gc_mode)
> +		par->mapped_vram = par->gc_mode->max_vram;
> +	else
> +		par->mapped_vram = MB862XX_MEM_SIZE;
> +
> +	par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram);
> +	if (par->fb_base == NULL) {
> +		dev_err(dev, "Cannot map framebuffer\n");
> +		goto rel_reg;
> +	}
> +
> +	par->mmio_base = ioremap(par->mmio_base_phys, par->mmio_len);
> +	if (par->mmio_base == NULL) {
> +		dev_err(dev, "Cannot map registers\n");
> +		goto fb_unmap;
> +	}
> +
> +	dev_dbg(dev, "fb phys 0x%llx 0x%lx\n",
> +		(u64)par->fb_base_phys, (ulong)par->mapped_vram);
> +	dev_dbg(dev, "mmio phys 0x%llx 0x%lx, (irq = %d)\n",
> +		(u64)par->mmio_base_phys, (ulong)par->mmio_len, par->irq);
> +
> +	if (mb862xx_gdc_init(par))
> +		goto io_unmap;
> +
> +	if (request_irq(par->irq, mb862xx_intr, IRQF_DISABLED,
> +			DRV_NAME, (void *)par)) {
> +		dev_err(dev, "Cannot request irq\n");
> +		goto io_unmap;
> +	}
> +
> +	mb862xxfb_init_fbinfo(info);
> +
> +	if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0) < 0) {
> +		dev_err(dev, "Could not allocate cmap for fb_info.\n");
> +		goto free_irq;
> +	}
> +
> +	if ((info->fbops->fb_set_par)(info))
> +		dev_err(dev, "set_var() failed on initial setup?\n");
> +
> +	if (register_framebuffer(info)) {
> +		dev_err(dev, "failed to register framebuffer\n");
> +		goto rel_cmap;
> +	}
> +
> +	dev_set_drvdata(dev, info);
> +
> +	if (device_create_file(dev, &dev_attr_dispregs))
> +		dev_err(dev, "Can't create sysfs regdump file\n");
> +	return 0;
> +
> +rel_cmap:
> +	fb_dealloc_cmap(&info->cmap);
> +free_irq:
> +	outreg(host, GC_IMASK, 0);
> +	free_irq(par->irq, (void *)par);
> +io_unmap:
> +	iounmap(par->mmio_base);
> +fb_unmap:
> +	iounmap(par->fb_base);
> +rel_reg:
> +	release_mem_region(res.start, res_size);
> +irqdisp:
> +	irq_dispose_mapping(par->irq);
> +fbrel:
> +	dev_set_drvdata(dev, NULL);
> +	framebuffer_release(info);
> +	return ret;
> +}
> +
> +static int __devexit of_platform_mb862xx_remove(struct of_device *ofdev)
> +{
> +	struct fb_info *fbi = dev_get_drvdata(&ofdev->dev);
> +	struct mb862xxfb_par *par = fbi->par;
> +	resource_size_t res_size = 1 + par->res->end - par->res->start;
> +	unsigned long reg;
> +
> +	dev_dbg(fbi->dev, "%s release\n", fbi->fix.id);
> +
> +	/* display off */
> +	reg = inreg(disp, GC_DCM1);
> +	reg &= ~(GC_DCM01_DEN | GC_DCM01_L0E);
> +	outreg(disp, GC_DCM1, reg);
> +
> +	/* disable interrupts */
> +	outreg(host, GC_IMASK, 0);
> +
> +	free_irq(par->irq, (void *)par);
> +	irq_dispose_mapping(par->irq);
> +
> +	device_remove_file(&ofdev->dev, &dev_attr_dispregs);
> +
> +	unregister_framebuffer(fbi);
> +	fb_dealloc_cmap(&fbi->cmap);
> +
> +	iounmap(par->mmio_base);
> +	iounmap(par->fb_base);
> +
> +	dev_set_drvdata(&ofdev->dev, NULL);
> +	release_mem_region(par->res->start, res_size);
> +	framebuffer_release(fbi);
> +	return 0;
> +}
> +
> +/*
> + * common types
> + */
> +static struct of_device_id __devinitdata of_platform_mb862xx_tbl[] = {
> +	{ .compatible = "fujitsu,MB86276", },
> +	{ .compatible = "fujitsu,lime", },
> +	{ .compatible = "fujitsu,MB86277", },
> +	{ .compatible = "fujitsu,mint", },
> +	{ .compatible = "fujitsu,MB86293", },
> +	{ .compatible = "fujitsu,MB86294", },
> +	{ .compatible = "fujitsu,coral", },
> +	{ /* end */ }
> +};
> +
> +static struct of_platform_driver of_platform_mb862xxfb_driver = {
> +	.owner		= THIS_MODULE,
> +	.name		= DRV_NAME,
> +	.match_table	= of_platform_mb862xx_tbl,
> +	.probe		= of_platform_mb862xx_probe,
> +	.remove		= __devexit_p(of_platform_mb862xx_remove),
> +};
> +#endif
> +
> +#if defined(CONFIG_FB_MB862XX_PCI_GDC)
> +static int coralp_init(struct mb862xxfb_par *par)
> +{
> +	int cn, ver;
> +
> +	par->host = par->mmio_base;
> +	par->i2c = par->mmio_base + MB862XX_I2C_BASE;
> +	par->disp = par->mmio_base + MB862XX_DISP_BASE;
> +	par->cap = par->mmio_base + MB862XX_CAP_BASE;
> +	par->draw = par->mmio_base + MB862XX_DRAW_BASE;
> +	par->geo = par->mmio_base + MB862XX_GEO_BASE;
> +	par->pio = par->mmio_base + MB862XX_PIO_BASE;
> +
> +	par->refclk = GC_DISP_REFCLK_400;
> +
> +	ver = inreg(host, GC_CID);
> +	cn = (ver & GC_CID_CNAME_MSK) >> 8;
> +	ver = ver & GC_CID_VERSION_MSK;
> +	if (cn == 3) {
> +		dev_info(par->dev, "Fujitsu Coral-%s GDC Rev.%d found\n",\
> +			 (ver == 6) ? "P" : (ver == 8) ? "PA" : "?",
> +			 par->pdev->revision);
> +		outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133);
> +		udelay(200);
> +		outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL);
> +		udelay(10);
> +		/* Clear interrupt status */
> +		outreg(host, GC_IST, 0);
> +	} else {
> +		return -ENODEV;
> +	}
> +	return 0;
> +}
> +
> +static int init_dram_ctrl(struct mb862xxfb_par *par)
> +{
> +	unsigned long i = 0;
> +
> +	/*
> +	 * Set io mode first! Spec. says IC may be destroyed
> +	 * if not set to SSTL2/LVCMOS before init.
> +	 */
> +	outreg(dram_ctrl, GC_DCTL_IOCONT1_IOCONT0, GC_EVB_DCTL_IOCONT1_IOCONT0);
> +
> +	/* DRAM init */
> +	outreg(dram_ctrl, GC_DCTL_MODE_ADD, GC_EVB_DCTL_MODE_ADD);
> +	outreg(dram_ctrl, GC_DCTL_SETTIME1_EMODE, GC_EVB_DCTL_SETTIME1_EMODE);
> +	outreg(dram_ctrl, GC_DCTL_REFRESH_SETTIME2,
> +	       GC_EVB_DCTL_REFRESH_SETTIME2);
> +	outreg(dram_ctrl, GC_DCTL_RSV2_RSV1, GC_EVB_DCTL_RSV2_RSV1);
> +	outreg(dram_ctrl, GC_DCTL_DDRIF2_DDRIF1, GC_EVB_DCTL_DDRIF2_DDRIF1);
> +	outreg(dram_ctrl, GC_DCTL_RSV0_STATES, GC_EVB_DCTL_RSV0_STATES);
> +
> +	/* DLL reset done? */
> +	while ((inreg(dram_ctrl, GC_DCTL_RSV0_STATES) & GC_DCTL_STATES_MSK)) {
> +		udelay(GC_DCTL_INIT_WAIT_INTERVAL);
> +		if (i++ > GC_DCTL_INIT_WAIT_CNT) {
> +			dev_err(par->dev, "VRAM init failed.\n");
> +			return -EINVAL;
> +		}
> +	}
> +	outreg(dram_ctrl, GC_DCTL_MODE_ADD, GC_EVB_DCTL_MODE_ADD_AFT_RST);
> +	outreg(dram_ctrl, GC_DCTL_RSV0_STATES, GC_EVB_DCTL_RSV0_STATES_AFT_RST);
> +	return 0;
> +}
> +
> +static int carmine_init(struct mb862xxfb_par *par)
> +{
> +	unsigned long reg;
> +
> +	par->ctrl = par->mmio_base + MB86297_CTRL_BASE;
> +	par->i2c = par->mmio_base + MB86297_I2C_BASE;
> +	par->disp = par->mmio_base + MB86297_DISP0_BASE;
> +	par->disp1 = par->mmio_base + MB86297_DISP1_BASE;
> +	par->cap = par->mmio_base + MB86297_CAP0_BASE;
> +	par->cap1 = par->mmio_base + MB86297_CAP1_BASE;
> +	par->draw = par->mmio_base + MB86297_DRAW_BASE;
> +	par->dram_ctrl = par->mmio_base + MB86297_DRAMCTRL_BASE;
> +	par->wrback = par->mmio_base + MB86297_WRBACK_BASE;
> +
> +	par->refclk = GC_DISP_REFCLK_533;
> +
> +	/* warm up */
> +	reg = GC_CTRL_CLK_EN_DRAM | GC_CTRL_CLK_EN_2D3D | GC_CTRL_CLK_EN_DISP0;
> +	outreg(ctrl, GC_CTRL_CLK_ENABLE, reg);
> +
> +	/* check for engine module revision */
> +	if (inreg(draw, GC_2D3D_REV) == GC_RE_REVISION)
> +		dev_info(par->dev, "Fujitsu Carmine GDC Rev.%d found\n",
> +			 par->pdev->revision);
> +	else
> +		goto err_init;
> +
> +	reg &= ~GC_CTRL_CLK_EN_2D3D;
> +	outreg(ctrl, GC_CTRL_CLK_ENABLE, reg);
> +
> +	/* set up vram */
> +	if (init_dram_ctrl(par) < 0)
> +		goto err_init;
> +
> +	outreg(ctrl, GC_CTRL_INT_MASK, 0);
> +	return 0;
> +
> +err_init:
> +	outreg(ctrl, GC_CTRL_CLK_ENABLE, 0);
> +	return -EINVAL;
> +}
> +
> +static inline int mb862xx_pci_gdc_init(struct mb862xxfb_par *par)
> +{
> +	switch (par->type) {
> +	case BT_CORALP:
> +		return coralp_init(par);
> +	case BT_CARMINE:
> +		return carmine_init(par);
> +	default:
> +		return -ENODEV;
> +	}
> +}
> +
> +#define CHIP_ID(id)	\
> +	{ PCI_DEVICE(PCI_VENDOR_ID_FUJITSU_LIMITED, id) }
> +
> +static struct pci_device_id mb862xx_pci_tbl[] __devinitdata = {
> +	/* MB86295/MB86296 */
> +	CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALP),
> +	CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALPA),
> +	/* MB86297 */
> +	CHIP_ID(PCI_DEVICE_ID_FUJITSU_CARMINE),
> +	{ 0, }
> +};
> +
> +MODULE_DEVICE_TABLE(pci, mb862xx_pci_tbl);
> +
> +static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
> +				       const struct pci_device_id *ent)
> +{
> +	struct mb862xxfb_par *par;
> +	struct fb_info *info;
> +	struct device *dev = &pdev->dev;
> +	int ret;
> +
> +	ret = pci_enable_device(pdev);
> +	if (ret < 0) {
> +		dev_err(dev, "Cannot enable PCI device\n");
> +		goto out;
> +	}
> +
> +	info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev);
> +	if (!info) {
> +		dev_err(dev, "framebuffer alloc failed\n");
> +		ret = -ENOMEM;
> +		goto dis_dev;
> +	}
> +
> +	par = info->par;
> +	par->info = info;
> +	par->dev = dev;
> +	par->pdev = pdev;
> +	par->irq = pdev->irq;
> +
> +	ret = pci_request_regions(pdev, DRV_NAME);
> +	if (ret < 0) {
> +		dev_err(dev, "Cannot reserve region(s) for PCI device\n");
> +		goto rel_fb;
> +	}
> +
> +	switch (pdev->device) {
> +	case PCI_DEVICE_ID_FUJITSU_CORALP:
> +	case PCI_DEVICE_ID_FUJITSU_CORALPA:
> +		par->fb_base_phys = pci_resource_start(par->pdev, 0);
> +		par->mapped_vram = CORALP_MEM_SIZE;
> +		par->mmio_base_phys = par->fb_base_phys + MB862XX_MMIO_BASE;
> +		par->mmio_len = MB862XX_MMIO_SIZE;
> +		par->type = BT_CORALP;
> +		break;
> +	case PCI_DEVICE_ID_FUJITSU_CARMINE:
> +		par->fb_base_phys = pci_resource_start(par->pdev, 2);
> +		par->mmio_base_phys = pci_resource_start(par->pdev, 3);
> +		par->mmio_len = pci_resource_len(par->pdev, 3);
> +		par->mapped_vram = CARMINE_MEM_SIZE;
> +		par->type = BT_CARMINE;
> +		break;
> +	default:
> +		/* should never occur */
> +		goto rel_reg;
> +	}
> +
> +	par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram);
> +	if (par->fb_base == NULL) {
> +		dev_err(dev, "Cannot map framebuffer\n");
> +		goto rel_reg;
> +	}
> +
> +	par->mmio_base = ioremap(par->mmio_base_phys, par->mmio_len);
> +	if (par->mmio_base == NULL) {
> +		dev_err(dev, "Cannot map registers\n");
> +		ret = -EIO;
> +		goto fb_unmap;
> +	}
> +
> +	dev_dbg(dev, "fb phys 0x%llx 0x%lx\n",
> +		(u64)par->fb_base_phys, (ulong)par->mapped_vram);
> +	dev_dbg(dev, "mmio phys 0x%llx 0x%lx\n",
> +		(u64)par->mmio_base_phys, (ulong)par->mmio_len);
> +
> +	if (mb862xx_pci_gdc_init(par))
> +		goto io_unmap;
> +
> +	if (request_irq(par->irq, mb862xx_intr, IRQF_DISABLED | IRQF_SHARED,
> +			DRV_NAME, (void *)par)) {
> +		dev_err(dev, "Cannot request irq\n");
> +		goto io_unmap;
> +	}
> +
> +	mb862xxfb_init_fbinfo(info);
> +
> +	if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0) < 0) {
> +		dev_err(dev, "Could not allocate cmap for fb_info.\n");
> +		ret = -ENOMEM;
> +		goto free_irq;
> +	}
> +
> +	if ((info->fbops->fb_set_par)(info))
> +		dev_err(dev, "set_var() failed on initial setup?\n");
> +
> +	ret = register_framebuffer(info);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to register framebuffer\n");
> +		goto rel_cmap;
> +	}
> +
> +	pci_set_drvdata(pdev, info);
> +
> +	if (device_create_file(dev, &dev_attr_dispregs))
> +		dev_err(dev, "Can't create sysfs regdump file\n");
> +
> +	if (par->type == BT_CARMINE)
> +		outreg(ctrl, GC_CTRL_INT_MASK, GC_CARMINE_INT_EN);
> +	else
> +		outreg(host, GC_IMASK, GC_INT_EN);
> +
> +	return 0;
> +
> +rel_cmap:
> +	fb_dealloc_cmap(&info->cmap);
> +free_irq:
> +	free_irq(par->irq, (void *)par);
> +io_unmap:
> +	iounmap(par->mmio_base);
> +fb_unmap:
> +	iounmap(par->fb_base);
> +rel_reg:
> +	pci_release_regions(pdev);
> +rel_fb:
> +	framebuffer_release(info);
> +dis_dev:
> +	pci_disable_device(pdev);
> +out:
> +	return ret;
> +}
> +
> +static void __devexit mb862xx_pci_remove(struct pci_dev *pdev)
> +{
> +	struct fb_info *fbi = pci_get_drvdata(pdev);
> +	struct mb862xxfb_par *par = fbi->par;
> +	unsigned long reg;
> +
> +	dev_dbg(fbi->dev, "%s release\n", fbi->fix.id);
> +
> +	/* display off */
> +	reg = inreg(disp, GC_DCM1);
> +	reg &= ~(GC_DCM01_DEN | GC_DCM01_L0E);
> +	outreg(disp, GC_DCM1, reg);
> +
> +	if (par->type == BT_CARMINE) {
> +		outreg(ctrl, GC_CTRL_INT_MASK, 0);
> +		outreg(ctrl, GC_CTRL_CLK_ENABLE, 0);
> +	} else {
> +		outreg(host, GC_IMASK, 0);
> +	}
> +
> +	device_remove_file(&pdev->dev, &dev_attr_dispregs);
> +
> +	pci_set_drvdata(pdev, NULL);
> +	unregister_framebuffer(fbi);
> +	fb_dealloc_cmap(&fbi->cmap);
> +
> +	free_irq(par->irq, (void *)par);
> +	iounmap(par->mmio_base);
> +	iounmap(par->fb_base);
> +
> +	pci_release_regions(pdev);
> +	framebuffer_release(fbi);
> +	pci_disable_device(pdev);
> +}
> +
> +static struct pci_driver mb862xxfb_pci_driver = {
> +	.name		= DRV_NAME,
> +	.id_table	= mb862xx_pci_tbl,
> +	.probe		= mb862xx_pci_probe,
> +	.remove		= __devexit_p(mb862xx_pci_remove),
> +};
> +#endif
> +
> +static int __devinit mb862xxfb_init(void)
> +{
> +	int ret = -ENODEV;
> +
> +#if defined(CONFIG_FB_MB862XX_LIME)
> +	ret = of_register_platform_driver(&of_platform_mb862xxfb_driver);
> +#endif
> +#if defined(CONFIG_FB_MB862XX_PCI_GDC)
> +	ret = pci_register_driver(&mb862xxfb_pci_driver);
> +#endif
> +	return ret;
> +}
> +
> +static void __exit mb862xxfb_exit(void)
> +{
> +#if defined(CONFIG_FB_MB862XX_LIME)
> +	of_unregister_platform_driver(&of_platform_mb862xxfb_driver);
> +#endif
> +#if defined(CONFIG_FB_MB862XX_PCI_GDC)
> +	pci_unregister_driver(&mb862xxfb_pci_driver);
> +#endif
> +}
> +
> +module_init(mb862xxfb_init);
> +module_exit(mb862xxfb_exit);
> +
> +MODULE_DESCRIPTION("Fujitsu MB862xx Framebuffer driver");
> +MODULE_AUTHOR("Anatolij Gustschin <agust at denx.de>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/video/mb862xx/mb862xxfb.h b/drivers/video/mb862xx/mb862xxfb.h
> new file mode 100644
> index 0000000..c4c8f4d
> --- /dev/null
> +++ b/drivers/video/mb862xx/mb862xxfb.h
> @@ -0,0 +1,83 @@
> +#ifndef __MB862XX_H__
> +#define __MB862XX_H__
> +
> +#define PCI_VENDOR_ID_FUJITSU_LIMITED	0x10cf
> +#define PCI_DEVICE_ID_FUJITSU_CORALP	0x2019
> +#define PCI_DEVICE_ID_FUJITSU_CORALPA	0x201e
> +#define PCI_DEVICE_ID_FUJITSU_CARMINE	0x202b
> +
> +#define GC_MMR_CORALP_EVB_VAL		0x11d7fa13
> +
> +enum gdctype {
> +	BT_NONE,
> +	BT_LIME,
> +	BT_MINT,
> +	BT_CORAL,
> +	BT_CORALP,
> +	BT_CARMINE,
> +};
> +
> +struct mb862xx_gc_mode {
> +	struct fb_videomode	def_mode;	/* mode of connected display */
> +	unsigned int		def_bpp;	/* default depth */
> +	unsigned long		max_vram;	/* connected SDRAM size */
> +	unsigned long		ccf;		/* gdc clk */
> +	unsigned long		mmr;		/* memory mode for SDRAM */
> +};
> +
> +/* private data */
> +struct mb862xxfb_par {
> +	struct fb_info		*info;		/* fb info head */
> +	struct device		*dev;
> +	struct pci_dev		*pdev;
> +	struct resource		*res;		/* framebuffer/mmio resource */
> +
> +	resource_size_t		fb_base_phys;	/* fb base, 36-bit PPC440EPx */
> +	resource_size_t		mmio_base_phys;	/* io base addr */
> +	void __iomem		*fb_base;	/* remapped framebuffer */
> +	void __iomem		*mmio_base;	/* remapped registers */
> +	size_t			mapped_vram;	/* length of remapped vram */
> +	size_t			mmio_len;	/* length of register region */
> +
> +	void __iomem		*host;		/* relocatable reg. bases */
> +	void __iomem		*i2c;
> +	void __iomem		*disp;
> +	void __iomem		*disp1;
> +	void __iomem		*cap;
> +	void __iomem		*cap1;
> +	void __iomem		*draw;
> +	void __iomem		*geo;
> +	void __iomem		*pio;
> +	void __iomem		*ctrl;
> +	void __iomem		*dram_ctrl;
> +	void __iomem		*wrback;
> +
> +	unsigned int		irq;
> +	unsigned int		type;		/* GDC type */
> +	unsigned int		refclk;		/* disp. reference clock */
> +	struct mb862xx_gc_mode	*gc_mode;	/* GDC mode init data */
> +	int			pre_init;	/* don't init display if 1 */
> +
> +	u32			pseudo_palette[16];
> +};
> +
> +#if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC)
> +#error	"Select Lime GDC or CoralP/Carmine support, but not both together"
> +#endif
> +#if defined(CONFIG_FB_MB862XX_LIME)
> +#define gdc_read	__raw_readl
> +#define gdc_write	__raw_writel
> +#else
> +#define gdc_read	readl
> +#define gdc_write	writel
> +#endif
> +
> +#define inreg(type, off)	\
> +	gdc_read((par->type + (off)))
> +
> +#define outreg(type, off, val)	\
> +	gdc_write((val), (par->type + (off)))
> +
> +#define pack(a, b)	(((a) << 16) | (b))
> +
> +#endif
>   




More information about the Linuxppc-dev mailing list