[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