/* * 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/delay.h>#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <linux/dma-direct.h>#include <linux/errno.h>#include <linux/gfp.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>#include <linux/io.h> #ifdef CONFIG_MIPS#include <asm/addrspace.h>#endif#include <asm/byteorder.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 wc_cookie; int valid;}; #define GBE_BASE 0x16000000 /* SGI O2 */ /* 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 /* * 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;static phys_addr_t gbe_mem_phys; static struct { uint16_t *cpu; dma_addr_t dma;} gbe_tiles; static int gbe_revision; static int ypan, ywrap; static uint32_t pseudo_palette[16];static uint32_t gbe_cmap[256];static int gbe_turned_on; /* 0 turned off, 1 turned on */ static char *mode_option = NULL; /* default CRT mode */static struct fb_var_screeninfo default_var_CRT = { /* 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 = { /* 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 = { .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 = { /* 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,}; static struct fb_videomode *default_mode = &default_mode_CRT;static struct fb_var_screeninfo *default_var = &default_var_CRT; static int flat_panel_enabled = 0; 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. */ static void gbe_turn_off(void){ int i; unsigned int val, y, vpixen_off; gbe_turned_on = 0; /* 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; 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; 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; mdelay(10); 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; mdelay(10); 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; mdelay(10); 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; mdelay(10); 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"); gbe_turned_on = 1;} static void gbe_loadcmap(void){ int i, j; for (i = 0; i < 256; i++) { 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] = gbe_cmap[i]; }} /* * 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 FB_BLANK_UNBLANK: /* unblank */ gbe_turn_on(); gbe_loadcmap(); break; case FB_BLANK_NORMAL: /* 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) *Lines 1–500 of 1287. Load more
/* * 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/delay.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/dma-direct.h> #include <linux/errno.h> #include <linux/gfp.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> #include <linux/io.h> #ifdef CONFIG_MIPS #include <asm/addrspace.h> #endif #include <asm/byteorder.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 wc_cookie; int valid; }; #define GBE_BASE 0x16000000 /* SGI O2 */ /* 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 /* * 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; static phys_addr_t gbe_mem_phys; static struct { uint16_t *cpu; dma_addr_t dma; } gbe_tiles; static int gbe_revision; static int ypan, ywrap; static uint32_t pseudo_palette[16]; static uint32_t gbe_cmap[256]; static int gbe_turned_on; /* 0 turned off, 1 turned on */ static char *mode_option = NULL; /* default CRT mode */ static struct fb_var_screeninfo default_var_CRT = { /* 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 = { /* 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 = { .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 = { /* 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, }; static struct fb_videomode *default_mode = &default_mode_CRT; static struct fb_var_screeninfo *default_var = &default_var_CRT; static int flat_panel_enabled = 0; 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. */ static void gbe_turn_off(void) { int i; unsigned int val, y, vpixen_off; gbe_turned_on = 0; /* 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; 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; 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; mdelay(10); 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; mdelay(10); 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; mdelay(10); 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; mdelay(10); 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"); gbe_turned_on = 1; } static void gbe_loadcmap(void) { int i, j; for (i = 0; i < 256; i++) { 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] = gbe_cmap[i]; } } /* * 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 FB_BLANK_UNBLANK: /* unblank */ gbe_turn_on(); gbe_loadcmap(); break; case FB_BLANK_NORMAL: /* 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) *