Commit f2136be1 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] mips: GBE Video Driver

From: Ralf Baechle <ralf@linux-mips.org>

This patch adds the GBE video driver for the video system in SGI IP32
aka O2 and it's i386-based equivalent the Visual Workstation.
                                                                              
This driver obsoletes sgivwfb.c; but I'd prefer to play safe and remove
it after some additional time, just in case.
parent 4663d2a4
...@@ -319,6 +319,21 @@ config FB_SGIVW ...@@ -319,6 +319,21 @@ config FB_SGIVW
help help
SGI Visual Workstation support for framebuffer graphics. SGI Visual Workstation support for framebuffer graphics.
config FB_GBE
bool "SGI Graphics Backend frame buffer support"
depends on FB && (SGI_IP32 || X86_VISWS)
help
This is the frame buffer device driver for SGI Graphics Backend.
This chip is used in SGI O2 and Visual Workstation 320/540.
config FB_GBE_MEM
int "Video memory size in MB"
depends on FB_GBE
default 8
help
This is the amount of memory reserved for the framebuffer,
which can be any value between 1MB and 8MB.
config BUS_I2C config BUS_I2C
bool bool
depends on FB && VISWS depends on FB && VISWS
......
...@@ -31,6 +31,7 @@ obj-$(CONFIG_FB_CT65550) += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbim ...@@ -31,6 +31,7 @@ obj-$(CONFIG_FB_CT65550) += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbim
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_CYBER) += cyberfb.o obj-$(CONFIG_FB_CYBER) += cyberfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_GBE) += gbefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o cfbimgblt.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o cfbimgblt.o
obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
......
...@@ -121,6 +121,8 @@ extern int sun3fb_init(void); ...@@ -121,6 +121,8 @@ extern int sun3fb_init(void);
extern int sun3fb_setup(char *); extern int sun3fb_setup(char *);
extern int sgivwfb_init(void); extern int sgivwfb_init(void);
extern int sgivwfb_setup(char*); extern int sgivwfb_setup(char*);
extern int gbefb_init(void);
extern int gbefb_setup(char*);
extern int rivafb_init(void); extern int rivafb_init(void);
extern int rivafb_setup(char*); extern int rivafb_setup(char*);
extern int tdfxfb_init(void); extern int tdfxfb_init(void);
...@@ -307,6 +309,9 @@ static struct { ...@@ -307,6 +309,9 @@ static struct {
#ifdef CONFIG_FB_SGIVW #ifdef CONFIG_FB_SGIVW
{ "sgivwfb", sgivwfb_init, sgivwfb_setup }, { "sgivwfb", sgivwfb_init, sgivwfb_setup },
#endif #endif
#ifdef CONFIG_FB_GBE
{ "gbefb", gbefb_init, gbefb_setup },
#endif
#ifdef CONFIG_FB_ACORN #ifdef CONFIG_FB_ACORN
{ "acornfb", acornfb_init, acornfb_setup }, { "acornfb", acornfb_init, acornfb_setup },
#endif #endif
......
/*
* SGI GBE frame buffer driver
*
* Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist
* Copyright (C) 2002 Vivien Chappelier <vivien.chappelier@linux-mips.org>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#ifdef CONFIG_X86
#include <asm/mtrr.h>
#endif
#ifdef CONFIG_MIPS
#include <asm/addrspace.h>
#endif
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/tlbflush.h>
#include <video/gbe.h>
static struct sgi_gbe *gbe;
struct gbefb_par {
struct fb_var_screeninfo var;
struct gbe_timing_info timing;
int valid;
};
#ifdef CONFIG_SGI_IP32
#define GBE_BASE 0x16000000 /* SGI O2 */
#endif
#ifdef CONFIG_X86_VISWS
#define GBE_BASE 0xd0000000 /* SGI Visual Workstation */
#endif
/* macro for fastest write-though access to the framebuffer */
#ifdef CONFIG_MIPS
#ifdef CONFIG_CPU_R10000
#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)
#else
#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
#endif
#endif
#ifdef CONFIG_X86
#define pgprot_fb(_prot) ((_prot) | _PAGE_PCD)
#endif
/*
* RAM we reserve for the frame buffer. This defines the maximum screen
* size
*/
#if CONFIG_FB_GBE_MEM > 8
#error GBE Framebuffer cannot use more than 8MB of memory
#endif
#define TILE_SHIFT 16
#define TILE_SIZE (1 << TILE_SHIFT)
#define TILE_MASK (TILE_SIZE - 1)
static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;
static void *gbe_mem;
static dma_addr_t gbe_dma_addr;
unsigned long gbe_mem_phys;
static struct {
uint16_t *cpu;
dma_addr_t dma;
} gbe_tiles;
static int gbe_revision;
static struct fb_info fb_info;
static int ypan, ywrap;
static uint32_t pseudo_palette[256];
static char *mode_option __initdata = NULL;
/* default CRT mode */
static struct fb_var_screeninfo default_var_CRT __initdata = {
/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
.xres = 640,
.yres = 480,
.xres_virtual = 640,
.yres_virtual = 480,
.xoffset = 0,
.yoffset = 0,
.bits_per_pixel = 8,
.grayscale = 0,
.red = { 0, 8, 0 },
.green = { 0, 8, 0 },
.blue = { 0, 8, 0 },
.transp = { 0, 0, 0 },
.nonstd = 0,
.activate = 0,
.height = -1,
.width = -1,
.accel_flags = 0,
.pixclock = 39722, /* picoseconds */
.left_margin = 48,
.right_margin = 16,
.upper_margin = 33,
.lower_margin = 10,
.hsync_len = 96,
.vsync_len = 2,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED,
};
/* default LCD mode */
static struct fb_var_screeninfo default_var_LCD __initdata = {
/* 1600x1024, 8 bpp */
.xres = 1600,
.yres = 1024,
.xres_virtual = 1600,
.yres_virtual = 1024,
.xoffset = 0,
.yoffset = 0,
.bits_per_pixel = 8,
.grayscale = 0,
.red = { 0, 8, 0 },
.green = { 0, 8, 0 },
.blue = { 0, 8, 0 },
.transp = { 0, 0, 0 },
.nonstd = 0,
.activate = 0,
.height = -1,
.width = -1,
.accel_flags = 0,
.pixclock = 9353,
.left_margin = 20,
.right_margin = 30,
.upper_margin = 37,
.lower_margin = 3,
.hsync_len = 20,
.vsync_len = 3,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED
};
/* default modedb mode */
/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
static struct fb_videomode default_mode_CRT __initdata = {
.refresh = 60,
.xres = 640,
.yres = 480,
.pixclock = 39722,
.left_margin = 48,
.right_margin = 16,
.upper_margin = 33,
.lower_margin = 10,
.hsync_len = 96,
.vsync_len = 2,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED,
};
/* 1600x1024 SGI flatpanel 1600sw */
static struct fb_videomode default_mode_LCD __initdata = {
/* 1600x1024, 8 bpp */
.xres = 1600,
.yres = 1024,
.pixclock = 9353,
.left_margin = 20,
.right_margin = 30,
.upper_margin = 37,
.lower_margin = 3,
.hsync_len = 20,
.vsync_len = 3,
.vmode = FB_VMODE_NONINTERLACED,
};
struct fb_videomode *default_mode = &default_mode_CRT;
struct fb_var_screeninfo *default_var = &default_var_CRT;
static int flat_panel_enabled = 0;
static struct gbefb_par par_current;
static void gbe_reset(void)
{
/* Turn on dotclock PLL */
gbe->ctrlstat = 0x300aa000;
}
/*
* Function: gbe_turn_off
* Parameters: (None)
* Description: This should turn off the monitor and gbe. This is used
* when switching between the serial console and the graphics
* console.
*/
void gbe_turn_off(void)
{
int i;
unsigned int val, x, y, vpixen_off;
/* check if pixel counter is on */
val = gbe->vt_xy;
if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1)
return;
/* turn off DMA */
val = gbe->ovr_control;
SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0);
gbe->ovr_control = val;
udelay(1000);
val = gbe->frm_control;
SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0);
gbe->frm_control = val;
udelay(1000);
val = gbe->did_control;
SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0);
gbe->did_control = val;
udelay(1000);
/* We have to wait through two vertical retrace periods before
* the pixel DMA is turned off for sure. */
for (i = 0; i < 10000; i++) {
val = gbe->frm_inhwctrl;
if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) {
udelay(10);
} else {
val = gbe->ovr_inhwctrl;
if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) {
udelay(10);
} else {
val = gbe->did_inhwctrl;
if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) {
udelay(10);
} else
break;
}
}
}
if (i == 10000)
printk(KERN_ERR "gbefb: turn off DMA timed out\n");
/* wait for vpixen_off */
val = gbe->vt_vpixen;
vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val);
for (i = 0; i < 100000; i++) {
val = gbe->vt_xy;
x = GET_GBE_FIELD(VT_XY, X, val);
y = GET_GBE_FIELD(VT_XY, Y, val);
if (y < vpixen_off)
break;
udelay(1);
}
if (i == 100000)
printk(KERN_ERR
"gbefb: wait for vpixen_off timed out\n");
for (i = 0; i < 10000; i++) {
val = gbe->vt_xy;
x = GET_GBE_FIELD(VT_XY, X, val);
y = GET_GBE_FIELD(VT_XY, Y, val);
if (y > vpixen_off)
break;
udelay(1);
}
if (i == 10000)
printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n");
/* turn off pixel counter */
val = 0;
SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
gbe->vt_xy = val;
udelay(10000);
for (i = 0; i < 10000; i++) {
val = gbe->vt_xy;
if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
udelay(10);
else
break;
}
if (i == 10000)
printk(KERN_ERR "gbefb: turn off pixel clock timed out\n");
/* turn off dot clock */
val = gbe->dotclock;
SET_GBE_FIELD(DOTCLK, RUN, val, 0);
gbe->dotclock = val;
udelay(10000);
for (i = 0; i < 10000; i++) {
val = gbe->dotclock;
if (GET_GBE_FIELD(DOTCLK, RUN, val))
udelay(10);
else
break;
}
if (i == 10000)
printk(KERN_ERR "gbefb: turn off dotclock timed out\n");
/* reset the frame DMA FIFO */
val = gbe->frm_size_tile;
SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1);
gbe->frm_size_tile = val;
SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0);
gbe->frm_size_tile = val;
}
static void gbe_turn_on(void)
{
unsigned int val, i;
/*
* Check if pixel counter is off, for unknown reason this
* code hangs Visual Workstations
*/
if (gbe_revision < 2) {
val = gbe->vt_xy;
if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0)
return;
}
/* turn on dot clock */
val = gbe->dotclock;
SET_GBE_FIELD(DOTCLK, RUN, val, 1);
gbe->dotclock = val;
udelay(10000);
for (i = 0; i < 10000; i++) {
val = gbe->dotclock;
if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
udelay(10);
else
break;
}
if (i == 10000)
printk(KERN_ERR "gbefb: turn on dotclock timed out\n");
/* turn on pixel counter */
val = 0;
SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
gbe->vt_xy = val;
udelay(10000);
for (i = 0; i < 10000; i++) {
val = gbe->vt_xy;
if (GET_GBE_FIELD(VT_XY, FREEZE, val))
udelay(10);
else
break;
}
if (i == 10000)
printk(KERN_ERR "gbefb: turn on pixel clock timed out\n");
/* turn on DMA */
val = gbe->frm_control;
SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1);
gbe->frm_control = val;
udelay(1000);
for (i = 0; i < 10000; i++) {
val = gbe->frm_inhwctrl;
if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1)
udelay(10);
else
break;
}
if (i == 10000)
printk(KERN_ERR "gbefb: turn on DMA timed out\n");
}
/*
* Blank the display.
*/
static int gbefb_blank(int blank, struct fb_info *info)
{
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
switch (blank) {
case 0: /* unblank */
gbe_turn_on();
break;
case 1: /* blank */
gbe_turn_off();
break;
default:
/* Nothing */
break;
}
return 0;
}
/*
* Setup flatpanel related registers.
*/
static void gbefb_setup_flatpanel(struct gbe_timing_info *timing)
{
int fp_wid, fp_hgt, fp_vbs, fp_vbe;
u32 outputVal = 0;
SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
(timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
(timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
gbe->vt_flags = outputVal;
/* Turn on the flat panel */
fp_wid = 1600;
fp_hgt = 1024;
fp_vbs = 0;
fp_vbe = 1600;
timing->pll_m = 4;
timing->pll_n = 1;
timing->pll_p = 0;
outputVal = 0;
SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs);
SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe);
gbe->fp_de = outputVal;
outputVal = 0;
SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid);
gbe->fp_hdrv = outputVal;
outputVal = 0;
SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1);
SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1);
gbe->fp_vdrv = outputVal;
}
struct gbe_pll_info {
int clock_rate;
int fvco_min;
int fvco_max;
};
static struct gbe_pll_info gbe_pll_table[2] = {
{ 20, 80, 220 },
{ 27, 80, 220 },
};
static int compute_gbe_timing(struct fb_var_screeninfo *var,
struct gbe_timing_info *timing)
{
int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error;
int pixclock;
struct gbe_pll_info *gbe_pll;
if (gbe_revision < 2)
gbe_pll = &gbe_pll_table[0];
else
gbe_pll = &gbe_pll_table[1];
/* Determine valid resolution and timing
* GBE crystal runs at 20Mhz or 27Mhz
* pll_m, pll_n, pll_p define the following frequencies
* fvco = pll_m * 20Mhz / pll_n
* fout = fvco / (2**pll_p) */
best_error = 1000000000;
best_n = best_m = best_p = 0;
for (pll_p = 0; pll_p < 4; pll_p++)
for (pll_m = 1; pll_m < 256; pll_m++)
for (pll_n = 1; pll_n < 64; pll_n++) {
pixclock = (1000000 / gbe_pll->clock_rate) *
(pll_n << pll_p) / pll_m;
error = var->pixclock - pixclock;
if (error < 0)
error = -error;
if (error < best_error &&
pll_m / pll_n >
gbe_pll->fvco_min / gbe_pll->clock_rate &&
pll_m / pll_n <
gbe_pll->fvco_max / gbe_pll->clock_rate) {
best_error = error;
best_m = pll_m;
best_n = pll_n;
best_p = pll_p;
}
}
if (!best_n || !best_m)
return -EINVAL; /* Resolution to high */
pixclock = (1000000 / gbe_pll->clock_rate) *
(best_n << best_p) / best_m;
/* set video timing information */
if (timing) {
timing->width = var->xres;
timing->height = var->yres;
timing->pll_m = best_m;
timing->pll_n = best_n;
timing->pll_p = best_p;
timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m /
(timing->pll_n << timing->pll_p);
timing->htotal = var->left_margin + var->xres +
var->right_margin + var->hsync_len;
timing->vtotal = var->upper_margin + var->yres +
var->lower_margin + var->vsync_len;
timing->fields_sec = 1000 * timing->cfreq / timing->htotal *
1000 / timing->vtotal;
timing->hblank_start = var->xres;
timing->vblank_start = var->yres;
timing->hblank_end = timing->htotal;
timing->hsync_start = var->xres + var->right_margin + 1;
timing->hsync_end = timing->hsync_start + var->hsync_len;
timing->vblank_end = timing->vtotal;
timing->vsync_start = var->yres + var->lower_margin + 1;
timing->vsync_end = timing->vsync_start + var->vsync_len;
}
return pixclock;
}
static void gbe_set_timing_info(struct gbe_timing_info *timing)
{
int temp;
unsigned int val;
/* setup dot clock PLL */
val = 0;
SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1);
SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1);
SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
SET_GBE_FIELD(DOTCLK, RUN, val, 0); /* do not start yet */
gbe->dotclock = val;
udelay(10000);
/* setup pixel counter */
val = 0;
SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal);
SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal);
gbe->vt_xymax = val;
/* setup video timing signals */
val = 0;
SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start);
SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end);
gbe->vt_vsync = val;
val = 0;
SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start);
SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end);
gbe->vt_hsync = val;
val = 0;
SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start);
SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end);
gbe->vt_vblank = val;
val = 0;
SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val,
timing->hblank_start - 5);
SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val,
timing->hblank_end - 3);
gbe->vt_hblank = val;
/* setup internal timing signals */
val = 0;
SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start);
SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end);
gbe->vt_vcmap = val;
val = 0;
SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start);
SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end);
gbe->vt_hcmap = val;
val = 0;
temp = timing->vblank_start - timing->vblank_end - 1;
if (temp > 0)
temp = -temp;
if (flat_panel_enabled)
gbefb_setup_flatpanel(timing);
SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp);
if (timing->hblank_end >= 20)
SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
timing->hblank_end - 20);
else
SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
timing->htotal - (20 - timing->hblank_end));
gbe->did_start_xy = val;
val = 0;
SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1));
if (timing->hblank_end >= GBE_CRS_MAGIC)
SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
timing->hblank_end - GBE_CRS_MAGIC);
else
SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
timing->htotal - (GBE_CRS_MAGIC -
timing->hblank_end));
gbe->crs_start_xy = val;
val = 0;
SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp);
SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4);
gbe->vc_start_xy = val;
val = 0;
temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON;
if (temp < 0)
temp += timing->htotal; /* allow blank to wrap around */
SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp);
SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val,
((temp + timing->width -
GBE_PIXEN_MAGIC_OFF) % timing->htotal));
gbe->vt_hpixen = val;
val = 0;
SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end);
SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start);
gbe->vt_vpixen = val;
/* turn off sync on green */
val = 0;
SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1);
gbe->vt_flags = val;
}
/*
* Set the hardware according to 'par'.
*/
static int gbefb_set_par(struct fb_info *info)
{
int i;
unsigned int val;
int wholeTilesX, partTilesX, maxPixelsPerTileX;
int height_pix;
int xpmax, ypmax; /* Monitor resolution */
int bytesPerPixel; /* Bytes per pixel */
struct gbefb_par *par = (struct gbefb_par *) info->par;
compute_gbe_timing(&info->var, &par->timing);
bytesPerPixel = info->var.bits_per_pixel / 8;
info->fix.line_length = info->var.xres_virtual * bytesPerPixel;
xpmax = par->timing.width;
ypmax = par->timing.height;
/* turn off GBE */
gbe_turn_off();
/* set timing info */
gbe_set_timing_info(&par->timing);
/* initialize DIDs */
val = 0;
switch (bytesPerPixel) {
case 1:
SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
break;
case 2:
SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
break;
case 4:
SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
break;
}
SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
for (i = 0; i < 32; i++)
gbe->mode_regs[i] = val;
/* Initialize interrupts */
gbe->vt_intr01 = 0xffffffff;
gbe->vt_intr23 = 0xffffffff;
/* HACK:
The GBE hardware uses a tiled memory to screen mapping. Tiles are
blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
16bit and 32 bit modes (64 kB). They cover the screen with partial
tiles on the right and/or bottom of the screen if needed.
For exemple in 640x480 8 bit mode the mapping is:
<-------- 640 ----->
<---- 512 ----><128|384 offscreen>
^ ^
| 128 [tile 0] [tile 1]
| v
^
4 128 [tile 2] [tile 3]
8 v
0 ^
128 [tile 4] [tile 5]
| v
| ^
v 96 [tile 6] [tile 7]
32 offscreen
Tiles have the advantage that they can be allocated individually in
memory. However, this mapping is not linear at all, which is not
really convienient. In order to support linear addressing, the GBE
DMA hardware is fooled into thinking the screen is only one tile
large and but has a greater height, so that the DMA transfer covers
the same region.
Tiles are still allocated as independent chunks of 64KB of
continuous physical memory and remapped so that the kernel sees the
framebuffer as a continuous virtual memory. The GBE tile table is
set up so that each tile references one of these 64k blocks:
GBE -> tile list framebuffer TLB <------------ CPU
[ tile 0 ] -> [ 64KB ] <- [ 16x 4KB page entries ] ^
... ... ... linear virtual FB
[ tile n ] -> [ 64KB ] <- [ 16x 4KB page entries ] v
The GBE hardware is then told that the buffer is 512*tweaked_height,
with tweaked_height = real_width*real_height/pixels_per_tile.
Thus the GBE hardware will scan the first tile, filing the first 64k
covered region of the screen, and then will proceed to the next
tile, until the whole screen is covered.
Here is what would happen at 640x480 8bit:
normal tiling linear
^ 11111111111111112222 11111111111111111111 ^
128 11111111111111112222 11111111111111111111 102 lines
11111111111111112222 11111111111111111111 v
V 11111111111111112222 11111111222222222222
33333333333333334444 22222222222222222222
33333333333333334444 22222222222222222222
< 512 > < 256 > 102*640+256 = 64k
NOTE: The only mode for which this is not working is 800x600 8bit,
as 800*600/512 = 937.5 which is not integer and thus causes
flickering.
I guess this is not so important as one can use 640x480 8bit or
800x600 16bit anyway.
*/
/* Tell gbe about the tiles table location */
/* tile_ptr -> [ tile 1 ] -> FB mem */
/* [ tile 2 ] -> FB mem */
/* ... */
val = 0;
SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9);
SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */
SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0);
gbe->frm_control = val;
maxPixelsPerTileX = 512 / bytesPerPixel;
wholeTilesX = 1;
partTilesX = 0;
/* Initialize the framebuffer */
val = 0;
SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX);
SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX);
switch (bytesPerPixel) {
case 1:
SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
GBE_FRM_DEPTH_8);
break;
case 2:
SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
GBE_FRM_DEPTH_16);
break;
case 4:
SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
GBE_FRM_DEPTH_32);
break;
}
gbe->frm_size_tile = val;
/* compute tweaked height */
height_pix = xpmax * ypmax / maxPixelsPerTileX;
val = 0;
SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix);
gbe->frm_size_pixel = val;
/* turn off DID and overlay DMA */
gbe->did_control = 0;
gbe->ovr_width_tile = 0;
/* Turn off mouse cursor */
gbe->crs_ctl = 0;
/* Turn on GBE */
gbe_turn_on();
/* Initialize the gamma map */
udelay(10);
for (i = 0; i < 256; i++)
gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8);
/* Initialize the color map */
for (i = 0; i < 256; i++) {
int j;
for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++)
udelay(10);
if (j == 1000)
printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
gbe->cmap[i] = (i << 8) | (i << 16) | (i << 24);
}
return 0;
}
static void gbefb_encode_fix(struct fb_fix_screeninfo *fix,
struct fb_var_screeninfo *var)
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, "SGI GBE");
fix->smem_start = (unsigned long) gbe_mem;
fix->smem_len = gbe_mem_size;
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
fix->accel = FB_ACCEL_NONE;
switch (var->bits_per_pixel) {
case 8:
fix->visual = FB_VISUAL_PSEUDOCOLOR;
break;
default:
fix->visual = FB_VISUAL_TRUECOLOR;
break;
}
fix->ywrapstep = 0;
fix->xpanstep = 0;
fix->ypanstep = 0;
fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
fix->mmio_start = GBE_BASE;
fix->mmio_len = sizeof(struct sgi_gbe);
}
/*
* Set a single color register. The values supplied are already
* rounded down to the hardware's capabilities (according to the
* entries in the var structure). Return != 0 for invalid regno.
*/
static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
int i;
if (regno > 255)
return 1;
red >>= 8;
green >>= 8;
blue >>= 8;
switch (info->var.bits_per_pixel) {
case 8:
/* wait for the color map FIFO to have a free entry */
for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
udelay(10);
if (i == 1000) {
printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
return 1;
}
gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
break;
case 15:
case 16:
red >>= 3;
green >>= 3;
blue >>= 3;
pseudo_palette[regno] =
(red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
break;
case 32:
pseudo_palette[regno] =
(red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
break;
}
return 0;
}
/*
* Check video mode validity, eventually modify var to best match.
*/
static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
unsigned int line_length;
struct gbe_timing_info timing;
/* Limit bpp to 8, 16, and 32 */
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;
else
return -EINVAL;
/* Check the mode can be mapped linearly with the tile table trick. */
/* This requires width x height x bytes/pixel be a multiple of 512 */
if ((var->xres * var->yres * var->bits_per_pixel) & 4095)
return -EINVAL;
var->grayscale = 0; /* No grayscale for now */
if ((var->pixclock = compute_gbe_timing(var, &timing)) < 0)
return(-EINVAL);
/* Adjust virtual resolution, if necessary */
if (var->xres > var->xres_virtual || (!ywrap && !ypan))
var->xres_virtual = var->xres;
if (var->yres > var->yres_virtual || (!ywrap && !ypan))
var->yres_virtual = var->yres;
if (var->vmode & FB_VMODE_CONUPDATE) {
var->vmode |= FB_VMODE_YWRAP;
var->xoffset = info->var.xoffset;
var->yoffset = info->var.yoffset;
}
/* No grayscale for now */
var->grayscale = 0;
/* Memory limit */
line_length = var->xres_virtual * var->bits_per_pixel / 8;
if (line_length * var->yres_virtual > gbe_mem_size)
return -ENOMEM; /* Virtual resolution too high */
switch (var->bits_per_pixel) {
case 8:
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
break;
case 16: /* RGB 1555 */
var->red.offset = 10;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 5;
var->blue.offset = 0;
var->blue.length = 5;
var->transp.offset = 0;
var->transp.length = 0;
break;
case 32: /* RGB 8888 */
var->red.offset = 24;
var->red.length = 8;
var->green.offset = 16;
var->green.length = 8;
var->blue.offset = 8;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 8;
break;
}
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
var->transp.msb_right = 0;
var->left_margin = timing.htotal - timing.hsync_end;
var->right_margin = timing.hsync_start - timing.width;
var->upper_margin = timing.vtotal - timing.vsync_end;
var->lower_margin = timing.vsync_start - timing.height;
var->hsync_len = timing.hsync_end - timing.hsync_start;
var->vsync_len = timing.vsync_end - timing.vsync_start;
return 0;
}
static int gbefb_mmap(struct fb_info *info, struct file *file,
struct vm_area_struct *vma)
{
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long addr;
unsigned long phys_addr, phys_size;
u16 *tile;
/* check range */
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
if (offset + size > gbe_mem_size)
return -EINVAL;
/* remap using the fastest write-through mode on architecture */
/* try not polluting the cache when possible */
pgprot_val(vma->vm_page_prot) =
pgprot_fb(pgprot_val(vma->vm_page_prot));
vma->vm_flags |= VM_IO | VM_RESERVED;
vma->vm_file = file;
/* look for the starting tile */
tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
addr = vma->vm_start;
offset &= TILE_MASK;
/* remap each tile separately */
do {
phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset;
if ((offset + size) < TILE_SIZE)
phys_size = size;
else
phys_size = TILE_SIZE - offset;
if (remap_page_range
(vma, addr, phys_addr, phys_size, vma->vm_page_prot))
return -EAGAIN;
offset = 0;
size -= phys_size;
addr += phys_size;
tile++;
} while (size);
return 0;
}
static struct fb_ops gbefb_ops = {
.owner = THIS_MODULE,
.fb_check_var = gbefb_check_var,
.fb_set_par = gbefb_set_par,
.fb_setcolreg = gbefb_setcolreg,
.fb_mmap = gbefb_mmap,
.fb_blank = gbefb_blank,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_cursor = soft_cursor,
};
/*
* Initialization
*/
int __init gbefb_setup(char *options)
{
char *this_opt;
if (!options || !*options)
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!strncmp(this_opt, "monitor:", 8)) {
if (!strncmp(this_opt + 8, "crt", 3)) {
flat_panel_enabled = 0;
default_var = &default_var_CRT;
default_mode = &default_mode_CRT;
} else if (!strncmp(this_opt + 8, "1600sw", 6) ||
!strncmp(this_opt + 8, "lcd", 3)) {
flat_panel_enabled = 1;
default_var = &default_var_LCD;
default_mode = &default_mode_LCD;
}
} else if (!strncmp(this_opt, "mem:", 4)) {
gbe_mem_size = memparse(this_opt + 4, &this_opt);
if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024)
gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024;
if (gbe_mem_size < TILE_SIZE)
gbe_mem_size = TILE_SIZE;
} else
mode_option = this_opt;
}
return 0;
}
int __init gbefb_init(void)
{
int i, ret = 0;
if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
return -EBUSY;
}
gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe));
if (!gbe) {
printk(KERN_ERR "gbefb: couldn't map mmio region\n");
ret = -ENXIO;
goto out_release_mem_region;
}
gbe_revision = gbe->ctrlstat & 15;
gbe_tiles.cpu =
dma_alloc_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
&gbe_tiles.dma, GFP_KERNEL);
if (!gbe_tiles.cpu) {
printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
ret = -ENOMEM;
goto out_unmap;
}
if (gbe_mem_phys) {
/* memory was allocated at boot time */
gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size);
gbe_dma_addr = 0;
} else {
/* try to allocate memory with the classical allocator
* this has high chance to fail on low memory machines */
gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr,
GFP_KERNEL);
gbe_mem_phys = (unsigned long) gbe_dma_addr;
}
#ifdef CONFIG_X86
mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1);
#endif
if (!gbe_mem) {
printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
ret = -ENXIO;
goto out_tiles_free;
}
/* map framebuffer memory into tiles table */
for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
fb_info.currcon = -1;
fb_info.fbops = &gbefb_ops;
fb_info.pseudo_palette = pseudo_palette;
fb_info.flags = FBINFO_FLAG_DEFAULT;
fb_info.screen_base = gbe_mem;
fb_alloc_cmap(&fb_info.cmap, 256, 0);
/* reset GBE */
gbe_reset();
/* turn on default video mode */
if (fb_find_mode(&par_current.var, &fb_info, mode_option, NULL, 0,
default_mode, 8) == 0)
par_current.var = *default_var;
fb_info.var = par_current.var;
gbefb_check_var(&par_current.var, &fb_info);
gbefb_encode_fix(&fb_info.fix, &fb_info.var);
fb_info.par = &par_current;
if (register_framebuffer(&fb_info) < 0) {
ret = -ENXIO;
printk(KERN_ERR "gbefb: couldn't register framebuffer\n");
goto out_gbe_unmap;
}
printk(KERN_INFO "fb%d: %s rev %d @ 0x%08x using %dkB memory\n",
fb_info.node, fb_info.fix.id, gbe_revision, (unsigned) GBE_BASE,
gbe_mem_size >> 10);
return 0;
out_gbe_unmap:
if (gbe_dma_addr)
dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
else
iounmap(gbe_mem);
out_tiles_free:
dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
(void *)gbe_tiles.cpu, gbe_tiles.dma);
out_unmap:
iounmap(gbe);
out_release_mem_region:
release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
return ret;
}
void __exit gbefb_exit(void)
{
unregister_framebuffer(&fb_info);
gbe_turn_off();
if (gbe_dma_addr)
dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
else
iounmap(gbe_mem);
dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
(void *)gbe_tiles.cpu, gbe_tiles.dma);
release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
iounmap(gbe);
}
#ifdef MODULE
module_init(gbefb_init);
module_exit(gbefb_exit);
#endif
MODULE_LICENSE("GPL");
/*
* include/video/gbe.h -- SGI GBE (Graphics Back End)
*
* Copyright (C) 1999 Silicon Graphics, Inc. (Jeffrey Newquist)
*
* This file is subject to the terms and conditions of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*/
#ifndef __GBE_H__
#define __GBE_H__
struct sgi_gbe {
volatile uint32_t ctrlstat; /* general control */
volatile uint32_t dotclock; /* dot clock PLL control */
volatile uint32_t i2c; /* crt I2C control */
volatile uint32_t sysclk; /* system clock PLL control */
volatile uint32_t i2cfp; /* flat panel I2C control */
volatile uint32_t id; /* device id/chip revision */
volatile uint32_t config; /* power on configuration [1] */
volatile uint32_t bist; /* internal bist status [1] */
uint32_t _pad0[0x010000/4 - 8];
volatile uint32_t vt_xy; /* current dot coords */
volatile uint32_t vt_xymax; /* maximum dot coords */
volatile uint32_t vt_vsync; /* vsync on/off */
volatile uint32_t vt_hsync; /* hsync on/off */
volatile uint32_t vt_vblank; /* vblank on/off */
volatile uint32_t vt_hblank; /* hblank on/off */
volatile uint32_t vt_flags; /* polarity of vt signals */
volatile uint32_t vt_f2rf_lock; /* f2rf & framelck y coord */
volatile uint32_t vt_intr01; /* intr 0,1 y coords */
volatile uint32_t vt_intr23; /* intr 2,3 y coords */
volatile uint32_t fp_hdrv; /* flat panel hdrv on/off */
volatile uint32_t fp_vdrv; /* flat panel vdrv on/off */
volatile uint32_t fp_de; /* flat panel de on/off */
volatile uint32_t vt_hpixen; /* intrnl horiz pixel on/off */
volatile uint32_t vt_vpixen; /* intrnl vert pixel on/off */
volatile uint32_t vt_hcmap; /* cmap write (horiz) */
volatile uint32_t vt_vcmap; /* cmap write (vert) */
volatile uint32_t did_start_xy; /* eol/f did/xy reset val */
volatile uint32_t crs_start_xy; /* eol/f crs/xy reset val */
volatile uint32_t vc_start_xy; /* eol/f vc/xy reset val */
uint32_t _pad1[0xffb0/4];
volatile uint32_t ovr_width_tile;/*overlay plane ctrl 0 */
volatile uint32_t ovr_inhwctrl; /* overlay plane ctrl 1 */
volatile uint32_t ovr_control; /* overlay plane ctrl 1 */
uint32_t _pad2[0xfff4/4];
volatile uint32_t frm_size_tile;/* normal plane ctrl 0 */
volatile uint32_t frm_size_pixel;/*normal plane ctrl 1 */
volatile uint32_t frm_inhwctrl; /* normal plane ctrl 2 */
volatile uint32_t frm_control; /* normal plane ctrl 3 */
uint32_t _pad3[0xfff0/4];
volatile uint32_t did_inhwctrl; /* DID control */
volatile uint32_t did_control; /* DID shadow */
uint32_t _pad4[0x7ff8/4];
volatile uint32_t mode_regs[32];/* WID table */
uint32_t _pad5[0x7f80/4];
volatile uint32_t cmap[6144]; /* color map */
uint32_t _pad6[0x2000/4];
volatile uint32_t cm_fifo; /* color map fifo status */
uint32_t _pad7[0x7ffc/4];
volatile uint32_t gmap[256]; /* gamma map */
uint32_t _pad8[0x7c00/4];
volatile uint32_t gmap10[1024]; /* gamma map */
uint32_t _pad9[0x7000/4];
volatile uint32_t crs_pos; /* cusror control 0 */
volatile uint32_t crs_ctl; /* cusror control 1 */
volatile uint32_t crs_cmap[3]; /* crs cmap */
uint32_t _pad10[0x7fec/4];
volatile uint32_t crs_glyph[64];/* crs glyph */
uint32_t _pad11[0x7f00/4];
volatile uint32_t vc_0; /* video capture crtl 0 */
volatile uint32_t vc_1; /* video capture crtl 1 */
volatile uint32_t vc_2; /* video capture crtl 2 */
volatile uint32_t vc_3; /* video capture crtl 3 */
volatile uint32_t vc_4; /* video capture crtl 4 */
volatile uint32_t vc_5; /* video capture crtl 5 */
volatile uint32_t vc_6; /* video capture crtl 6 */
volatile uint32_t vc_7; /* video capture crtl 7 */
volatile uint32_t vc_8; /* video capture crtl 8 */
};
#define MASK(msb, lsb) \
( (((u32)1<<((msb)-(lsb)+1))-1) << (lsb) )
#define GET(v, msb, lsb) \
( ((u32)(v) & MASK(msb,lsb)) >> (lsb) )
#define SET(v, f, msb, lsb) \
( (v) = ((v)&~MASK(msb,lsb)) | (( (u32)(f)<<(lsb) ) & MASK(msb,lsb)) )
#define GET_GBE_FIELD(reg, field, v) \
GET((v), GBE_##reg##_##field##_MSB, GBE_##reg##_##field##_LSB)
#define SET_GBE_FIELD(reg, field, v, f) \
SET((v), (f), GBE_##reg##_##field##_MSB, GBE_##reg##_##field##_LSB)
/*
* Bit mask information
*/
#define GBE_CTRLSTAT_CHIPID_MSB 3
#define GBE_CTRLSTAT_CHIPID_LSB 0
#define GBE_CTRLSTAT_SENSE_N_MSB 4
#define GBE_CTRLSTAT_SENSE_N_LSB 4
#define GBE_CTRLSTAT_PCLKSEL_MSB 29
#define GBE_CTRLSTAT_PCLKSEL_LSB 28
#define GBE_DOTCLK_M_MSB 7
#define GBE_DOTCLK_M_LSB 0
#define GBE_DOTCLK_N_MSB 13
#define GBE_DOTCLK_N_LSB 8
#define GBE_DOTCLK_P_MSB 15
#define GBE_DOTCLK_P_LSB 14
#define GBE_DOTCLK_RUN_MSB 20
#define GBE_DOTCLK_RUN_LSB 20
#define GBE_VT_XY_Y_MSB 23
#define GBE_VT_XY_Y_LSB 12
#define GBE_VT_XY_X_MSB 11
#define GBE_VT_XY_X_LSB 0
#define GBE_VT_XY_FREEZE_MSB 31
#define GBE_VT_XY_FREEZE_LSB 31
#define GBE_FP_VDRV_ON_MSB 23
#define GBE_FP_VDRV_ON_LSB 12
#define GBE_FP_VDRV_OFF_MSB 11
#define GBE_FP_VDRV_OFF_LSB 0
#define GBE_FP_HDRV_ON_MSB 23
#define GBE_FP_HDRV_ON_LSB 12
#define GBE_FP_HDRV_OFF_MSB 11
#define GBE_FP_HDRV_OFF_LSB 0
#define GBE_FP_DE_ON_MSB 23
#define GBE_FP_DE_ON_LSB 12
#define GBE_FP_DE_OFF_MSB 11
#define GBE_FP_DE_OFF_LSB 0
#define GBE_VT_VSYNC_VSYNC_ON_MSB 23
#define GBE_VT_VSYNC_VSYNC_ON_LSB 12
#define GBE_VT_VSYNC_VSYNC_OFF_MSB 11
#define GBE_VT_VSYNC_VSYNC_OFF_LSB 0
#define GBE_VT_HSYNC_HSYNC_ON_MSB 23
#define GBE_VT_HSYNC_HSYNC_ON_LSB 12
#define GBE_VT_HSYNC_HSYNC_OFF_MSB 11
#define GBE_VT_HSYNC_HSYNC_OFF_LSB 0
#define GBE_VT_VBLANK_VBLANK_ON_MSB 23
#define GBE_VT_VBLANK_VBLANK_ON_LSB 12
#define GBE_VT_VBLANK_VBLANK_OFF_MSB 11
#define GBE_VT_VBLANK_VBLANK_OFF_LSB 0
#define GBE_VT_HBLANK_HBLANK_ON_MSB 23
#define GBE_VT_HBLANK_HBLANK_ON_LSB 12
#define GBE_VT_HBLANK_HBLANK_OFF_MSB 11
#define GBE_VT_HBLANK_HBLANK_OFF_LSB 0
#define GBE_VT_FLAGS_F2RF_HIGH_MSB 6
#define GBE_VT_FLAGS_F2RF_HIGH_LSB 6
#define GBE_VT_FLAGS_SYNC_LOW_MSB 5
#define GBE_VT_FLAGS_SYNC_LOW_LSB 5
#define GBE_VT_FLAGS_SYNC_HIGH_MSB 4
#define GBE_VT_FLAGS_SYNC_HIGH_LSB 4
#define GBE_VT_FLAGS_HDRV_LOW_MSB 3
#define GBE_VT_FLAGS_HDRV_LOW_LSB 3
#define GBE_VT_FLAGS_HDRV_INVERT_MSB 2
#define GBE_VT_FLAGS_HDRV_INVERT_LSB 2
#define GBE_VT_FLAGS_VDRV_LOW_MSB 1
#define GBE_VT_FLAGS_VDRV_LOW_LSB 1
#define GBE_VT_FLAGS_VDRV_INVERT_MSB 0
#define GBE_VT_FLAGS_VDRV_INVERT_LSB 0
#define GBE_VT_VCMAP_VCMAP_ON_MSB 23
#define GBE_VT_VCMAP_VCMAP_ON_LSB 12
#define GBE_VT_VCMAP_VCMAP_OFF_MSB 11
#define GBE_VT_VCMAP_VCMAP_OFF_LSB 0
#define GBE_VT_HCMAP_HCMAP_ON_MSB 23
#define GBE_VT_HCMAP_HCMAP_ON_LSB 12
#define GBE_VT_HCMAP_HCMAP_OFF_MSB 11
#define GBE_VT_HCMAP_HCMAP_OFF_LSB 0
#define GBE_VT_XYMAX_MAXX_MSB 11
#define GBE_VT_XYMAX_MAXX_LSB 0
#define GBE_VT_XYMAX_MAXY_MSB 23
#define GBE_VT_XYMAX_MAXY_LSB 12
#define GBE_VT_HPIXEN_HPIXEN_ON_MSB 23
#define GBE_VT_HPIXEN_HPIXEN_ON_LSB 12
#define GBE_VT_HPIXEN_HPIXEN_OFF_MSB 11
#define GBE_VT_HPIXEN_HPIXEN_OFF_LSB 0
#define GBE_VT_VPIXEN_VPIXEN_ON_MSB 23
#define GBE_VT_VPIXEN_VPIXEN_ON_LSB 12
#define GBE_VT_VPIXEN_VPIXEN_OFF_MSB 11
#define GBE_VT_VPIXEN_VPIXEN_OFF_LSB 0
#define GBE_OVR_CONTROL_OVR_DMA_ENABLE_MSB 0
#define GBE_OVR_CONTROL_OVR_DMA_ENABLE_LSB 0
#define GBE_OVR_INHWCTRL_OVR_DMA_ENABLE_MSB 0
#define GBE_OVR_INHWCTRL_OVR_DMA_ENABLE_LSB 0
#define GBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_MSB 13
#define GBE_OVR_WIDTH_TILE_OVR_FIFO_RESET_LSB 13
#define GBE_FRM_CONTROL_FRM_DMA_ENABLE_MSB 0
#define GBE_FRM_CONTROL_FRM_DMA_ENABLE_LSB 0
#define GBE_FRM_CONTROL_FRM_TILE_PTR_MSB 31
#define GBE_FRM_CONTROL_FRM_TILE_PTR_LSB 9
#define GBE_FRM_CONTROL_FRM_LINEAR_MSB 1
#define GBE_FRM_CONTROL_FRM_LINEAR_LSB 1
#define GBE_FRM_INHWCTRL_FRM_DMA_ENABLE_MSB 0
#define GBE_FRM_INHWCTRL_FRM_DMA_ENABLE_LSB 0
#define GBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_MSB 12
#define GBE_FRM_SIZE_TILE_FRM_WIDTH_TILE_LSB 5
#define GBE_FRM_SIZE_TILE_FRM_RHS_MSB 4
#define GBE_FRM_SIZE_TILE_FRM_RHS_LSB 0
#define GBE_FRM_SIZE_TILE_FRM_DEPTH_MSB 14
#define GBE_FRM_SIZE_TILE_FRM_DEPTH_LSB 13
#define GBE_FRM_SIZE_TILE_FRM_FIFO_RESET_MSB 15
#define GBE_FRM_SIZE_TILE_FRM_FIFO_RESET_LSB 15
#define GBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_MSB 31
#define GBE_FRM_SIZE_PIXEL_FB_HEIGHT_PIX_LSB 16
#define GBE_DID_CONTROL_DID_DMA_ENABLE_MSB 0
#define GBE_DID_CONTROL_DID_DMA_ENABLE_LSB 0
#define GBE_DID_INHWCTRL_DID_DMA_ENABLE_MSB 0
#define GBE_DID_INHWCTRL_DID_DMA_ENABLE_LSB 0
#define GBE_DID_START_XY_DID_STARTY_MSB 23
#define GBE_DID_START_XY_DID_STARTY_LSB 12
#define GBE_DID_START_XY_DID_STARTX_MSB 11
#define GBE_DID_START_XY_DID_STARTX_LSB 0
#define GBE_CRS_START_XY_CRS_STARTY_MSB 23
#define GBE_CRS_START_XY_CRS_STARTY_LSB 12
#define GBE_CRS_START_XY_CRS_STARTX_MSB 11
#define GBE_CRS_START_XY_CRS_STARTX_LSB 0
#define GBE_WID_AUX_MSB 12
#define GBE_WID_AUX_LSB 11
#define GBE_WID_GAMMA_MSB 10
#define GBE_WID_GAMMA_LSB 10
#define GBE_WID_CM_MSB 9
#define GBE_WID_CM_LSB 5
#define GBE_WID_TYP_MSB 4
#define GBE_WID_TYP_LSB 2
#define GBE_WID_BUF_MSB 1
#define GBE_WID_BUF_LSB 0
#define GBE_VC_START_XY_VC_STARTY_MSB 23
#define GBE_VC_START_XY_VC_STARTY_LSB 12
#define GBE_VC_START_XY_VC_STARTX_MSB 11
#define GBE_VC_START_XY_VC_STARTX_LSB 0
/* Constants */
#define GBE_FRM_DEPTH_8 0
#define GBE_FRM_DEPTH_16 1
#define GBE_FRM_DEPTH_32 2
#define GBE_CMODE_I8 0
#define GBE_CMODE_I12 1
#define GBE_CMODE_RG3B2 2
#define GBE_CMODE_RGB4 3
#define GBE_CMODE_ARGB5 4
#define GBE_CMODE_RGB8 5
#define GBE_CMODE_RGBA5 6
#define GBE_CMODE_RGB10 7
#define GBE_BMODE_BOTH 3
#define GBE_CRS_MAGIC 54
#define GBE_PIXEN_MAGIC_ON 19
#define GBE_PIXEN_MAGIC_OFF 2
#define GBE_TLB_SIZE 128
/* [1] - only GBE revision 2 and later */
/*
* Video Timing Data Structure
*/
struct gbe_timing_info {
int flags;
short width; /* Monitor resolution */
short height;
int fields_sec; /* fields/sec (Hz -3 dec. places */
int cfreq; /* pixel clock frequency (MHz -3 dec. places) */
short htotal; /* Horizontal total pixels */
short hblank_start; /* Horizontal blank start */
short hblank_end; /* Horizontal blank end */
short hsync_start; /* Horizontal sync start */
short hsync_end; /* Horizontal sync end */
short vtotal; /* Vertical total lines */
short vblank_start; /* Vertical blank start */
short vblank_end; /* Vertical blank end */
short vsync_start; /* Vertical sync start */
short vsync_end; /* Vertical sync end */
short pll_m; /* PLL M parameter */
short pll_n; /* PLL P parameter */
short pll_p; /* PLL N parameter */
};
/* Defines for gbe_vof_info_t flags */
#define GBE_VOF_UNKNOWNMON 1
#define GBE_VOF_STEREO 2
#define GBE_VOF_DO_GENSYNC 4 /* enable incoming sync */
#define GBE_VOF_SYNC_ON_GREEN 8 /* sync on green */
#define GBE_VOF_FLATPANEL 0x1000 /* FLATPANEL Timing */
#define GBE_VOF_MAGICKEY 0x2000 /* Backdoor key */
#endif /* ! __GBE_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment