From mboxrd@z Thu Jan 1 00:00:00 1970 From: Matteo Fortini Subject: Re: [PATCH] Add new framebuffer driver for Fujitsu MB862xx GDCs Date: Wed, 15 Oct 2008 15:40:15 +0200 Message-ID: <48F5F2BF.2040805@selcomgroup.com> References: <1223997906-19900-1-git-send-email-agust@denx.de> Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1223997906-19900-1-git-send-email-agust@denx.de> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linuxppc-dev-bounces+glppd-linuxppc64-dev=m.gmane.org@ozlabs.org Errors-To: linuxppc-dev-bounces+glppd-linuxppc64-dev=m.gmane.org@ozlabs.org Content-Type: text/plain; charset="us-ascii"; format="flowed" To: Anatolij Gustschin Cc: linuxppc-dev@ozlabs.org, akpm@linux-foundation.org, linux-fbdev-devel@lists.sourceforge.net 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 > --- > 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 > + * 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 > +#include > +#include > +#include > +#include > +#if defined(CONFIG_PPC_OF) > +#include > +#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@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 "); > +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 >