Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  SGI GBE frame buffer driver
0003  *
0004  *  Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist
0005  *  Copyright (C) 2002 Vivien Chappelier <vivien.chappelier@linux-mips.org>
0006  *
0007  *  This file is subject to the terms and conditions of the GNU General Public
0008  *  License. See the file COPYING in the main directory of this archive for
0009  *  more details.
0010  */
0011 
0012 #include <linux/delay.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/dma-mapping.h>
0015 #include <linux/errno.h>
0016 #include <linux/gfp.h>
0017 #include <linux/fb.h>
0018 #include <linux/init.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/kernel.h>
0021 #include <linux/mm.h>
0022 #include <linux/module.h>
0023 #include <linux/io.h>
0024 
0025 #ifdef CONFIG_MIPS
0026 #include <asm/addrspace.h>
0027 #endif
0028 #include <asm/byteorder.h>
0029 #include <asm/tlbflush.h>
0030 
0031 #include <video/gbe.h>
0032 
0033 static struct sgi_gbe *gbe;
0034 
0035 struct gbefb_par {
0036     struct fb_var_screeninfo var;
0037     struct gbe_timing_info timing;
0038     int wc_cookie;
0039     int valid;
0040 };
0041 
0042 #define GBE_BASE    0x16000000 /* SGI O2 */
0043 
0044 /* macro for fastest write-though access to the framebuffer */
0045 #ifdef CONFIG_MIPS
0046 #ifdef CONFIG_CPU_R10000
0047 #define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)
0048 #else
0049 #define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
0050 #endif
0051 #endif
0052 
0053 /*
0054  *  RAM we reserve for the frame buffer. This defines the maximum screen
0055  *  size
0056  */
0057 #if CONFIG_FB_GBE_MEM > 8
0058 #error GBE Framebuffer cannot use more than 8MB of memory
0059 #endif
0060 
0061 #define TILE_SHIFT 16
0062 #define TILE_SIZE (1 << TILE_SHIFT)
0063 #define TILE_MASK (TILE_SIZE - 1)
0064 
0065 static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;
0066 static void *gbe_mem;
0067 static dma_addr_t gbe_dma_addr;
0068 static unsigned long gbe_mem_phys;
0069 
0070 static struct {
0071     uint16_t *cpu;
0072     dma_addr_t dma;
0073 } gbe_tiles;
0074 
0075 static int gbe_revision;
0076 
0077 static int ypan, ywrap;
0078 
0079 static uint32_t pseudo_palette[16];
0080 static uint32_t gbe_cmap[256];
0081 static int gbe_turned_on; /* 0 turned off, 1 turned on */
0082 
0083 static char *mode_option = NULL;
0084 
0085 /* default CRT mode */
0086 static struct fb_var_screeninfo default_var_CRT = {
0087     /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
0088     .xres       = 640,
0089     .yres       = 480,
0090     .xres_virtual   = 640,
0091     .yres_virtual   = 480,
0092     .xoffset    = 0,
0093     .yoffset    = 0,
0094     .bits_per_pixel = 8,
0095     .grayscale  = 0,
0096     .red        = { 0, 8, 0 },
0097     .green      = { 0, 8, 0 },
0098     .blue       = { 0, 8, 0 },
0099     .transp     = { 0, 0, 0 },
0100     .nonstd     = 0,
0101     .activate   = 0,
0102     .height     = -1,
0103     .width      = -1,
0104     .accel_flags    = 0,
0105     .pixclock   = 39722,    /* picoseconds */
0106     .left_margin    = 48,
0107     .right_margin   = 16,
0108     .upper_margin   = 33,
0109     .lower_margin   = 10,
0110     .hsync_len  = 96,
0111     .vsync_len  = 2,
0112     .sync       = 0,
0113     .vmode      = FB_VMODE_NONINTERLACED,
0114 };
0115 
0116 /* default LCD mode */
0117 static struct fb_var_screeninfo default_var_LCD = {
0118     /* 1600x1024, 8 bpp */
0119     .xres       = 1600,
0120     .yres       = 1024,
0121     .xres_virtual   = 1600,
0122     .yres_virtual   = 1024,
0123     .xoffset    = 0,
0124     .yoffset    = 0,
0125     .bits_per_pixel = 8,
0126     .grayscale  = 0,
0127     .red        = { 0, 8, 0 },
0128     .green      = { 0, 8, 0 },
0129     .blue       = { 0, 8, 0 },
0130     .transp     = { 0, 0, 0 },
0131     .nonstd     = 0,
0132     .activate   = 0,
0133     .height     = -1,
0134     .width      = -1,
0135     .accel_flags    = 0,
0136     .pixclock   = 9353,
0137     .left_margin    = 20,
0138     .right_margin   = 30,
0139     .upper_margin   = 37,
0140     .lower_margin   = 3,
0141     .hsync_len  = 20,
0142     .vsync_len  = 3,
0143     .sync       = 0,
0144     .vmode      = FB_VMODE_NONINTERLACED
0145 };
0146 
0147 /* default modedb mode */
0148 /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
0149 static struct fb_videomode default_mode_CRT = {
0150     .refresh    = 60,
0151     .xres       = 640,
0152     .yres       = 480,
0153     .pixclock   = 39722,
0154     .left_margin    = 48,
0155     .right_margin   = 16,
0156     .upper_margin   = 33,
0157     .lower_margin   = 10,
0158     .hsync_len  = 96,
0159     .vsync_len  = 2,
0160     .sync       = 0,
0161     .vmode      = FB_VMODE_NONINTERLACED,
0162 };
0163 /* 1600x1024 SGI flatpanel 1600sw */
0164 static struct fb_videomode default_mode_LCD = {
0165     /* 1600x1024, 8 bpp */
0166     .xres       = 1600,
0167     .yres       = 1024,
0168     .pixclock   = 9353,
0169     .left_margin    = 20,
0170     .right_margin   = 30,
0171     .upper_margin   = 37,
0172     .lower_margin   = 3,
0173     .hsync_len  = 20,
0174     .vsync_len  = 3,
0175     .vmode      = FB_VMODE_NONINTERLACED,
0176 };
0177 
0178 static struct fb_videomode *default_mode = &default_mode_CRT;
0179 static struct fb_var_screeninfo *default_var = &default_var_CRT;
0180 
0181 static int flat_panel_enabled = 0;
0182 
0183 static void gbe_reset(void)
0184 {
0185     /* Turn on dotclock PLL */
0186     gbe->ctrlstat = 0x300aa000;
0187 }
0188 
0189 
0190 /*
0191  * Function:    gbe_turn_off
0192  * Parameters:  (None)
0193  * Description: This should turn off the monitor and gbe.  This is used
0194  *              when switching between the serial console and the graphics
0195  *              console.
0196  */
0197 
0198 static void gbe_turn_off(void)
0199 {
0200     int i;
0201     unsigned int val, y, vpixen_off;
0202 
0203     gbe_turned_on = 0;
0204 
0205     /* check if pixel counter is on */
0206     val = gbe->vt_xy;
0207     if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1)
0208         return;
0209 
0210     /* turn off DMA */
0211     val = gbe->ovr_control;
0212     SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0);
0213     gbe->ovr_control = val;
0214     udelay(1000);
0215     val = gbe->frm_control;
0216     SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0);
0217     gbe->frm_control = val;
0218     udelay(1000);
0219     val = gbe->did_control;
0220     SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0);
0221     gbe->did_control = val;
0222     udelay(1000);
0223 
0224     /* We have to wait through two vertical retrace periods before
0225      * the pixel DMA is turned off for sure. */
0226     for (i = 0; i < 10000; i++) {
0227         val = gbe->frm_inhwctrl;
0228         if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) {
0229             udelay(10);
0230         } else {
0231             val = gbe->ovr_inhwctrl;
0232             if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) {
0233                 udelay(10);
0234             } else {
0235                 val = gbe->did_inhwctrl;
0236                 if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) {
0237                     udelay(10);
0238                 } else
0239                     break;
0240             }
0241         }
0242     }
0243     if (i == 10000)
0244         printk(KERN_ERR "gbefb: turn off DMA timed out\n");
0245 
0246     /* wait for vpixen_off */
0247     val = gbe->vt_vpixen;
0248     vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val);
0249 
0250     for (i = 0; i < 100000; i++) {
0251         val = gbe->vt_xy;
0252         y = GET_GBE_FIELD(VT_XY, Y, val);
0253         if (y < vpixen_off)
0254             break;
0255         udelay(1);
0256     }
0257     if (i == 100000)
0258         printk(KERN_ERR
0259                "gbefb: wait for vpixen_off timed out\n");
0260     for (i = 0; i < 10000; i++) {
0261         val = gbe->vt_xy;
0262         y = GET_GBE_FIELD(VT_XY, Y, val);
0263         if (y > vpixen_off)
0264             break;
0265         udelay(1);
0266     }
0267     if (i == 10000)
0268         printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n");
0269 
0270     /* turn off pixel counter */
0271     val = 0;
0272     SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
0273     gbe->vt_xy = val;
0274     mdelay(10);
0275     for (i = 0; i < 10000; i++) {
0276         val = gbe->vt_xy;
0277         if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
0278             udelay(10);
0279         else
0280             break;
0281     }
0282     if (i == 10000)
0283         printk(KERN_ERR "gbefb: turn off pixel clock timed out\n");
0284 
0285     /* turn off dot clock */
0286     val = gbe->dotclock;
0287     SET_GBE_FIELD(DOTCLK, RUN, val, 0);
0288     gbe->dotclock = val;
0289     mdelay(10);
0290     for (i = 0; i < 10000; i++) {
0291         val = gbe->dotclock;
0292         if (GET_GBE_FIELD(DOTCLK, RUN, val))
0293             udelay(10);
0294         else
0295             break;
0296     }
0297     if (i == 10000)
0298         printk(KERN_ERR "gbefb: turn off dotclock timed out\n");
0299 
0300     /* reset the frame DMA FIFO */
0301     val = gbe->frm_size_tile;
0302     SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1);
0303     gbe->frm_size_tile = val;
0304     SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0);
0305     gbe->frm_size_tile = val;
0306 }
0307 
0308 static void gbe_turn_on(void)
0309 {
0310     unsigned int val, i;
0311 
0312     /*
0313      * Check if pixel counter is off, for unknown reason this
0314      * code hangs Visual Workstations
0315      */
0316     if (gbe_revision < 2) {
0317         val = gbe->vt_xy;
0318         if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0)
0319             return;
0320     }
0321 
0322     /* turn on dot clock */
0323     val = gbe->dotclock;
0324     SET_GBE_FIELD(DOTCLK, RUN, val, 1);
0325     gbe->dotclock = val;
0326     mdelay(10);
0327     for (i = 0; i < 10000; i++) {
0328         val = gbe->dotclock;
0329         if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
0330             udelay(10);
0331         else
0332             break;
0333     }
0334     if (i == 10000)
0335         printk(KERN_ERR "gbefb: turn on dotclock timed out\n");
0336 
0337     /* turn on pixel counter */
0338     val = 0;
0339     SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
0340     gbe->vt_xy = val;
0341     mdelay(10);
0342     for (i = 0; i < 10000; i++) {
0343         val = gbe->vt_xy;
0344         if (GET_GBE_FIELD(VT_XY, FREEZE, val))
0345             udelay(10);
0346         else
0347             break;
0348     }
0349     if (i == 10000)
0350         printk(KERN_ERR "gbefb: turn on pixel clock timed out\n");
0351 
0352     /* turn on DMA */
0353     val = gbe->frm_control;
0354     SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1);
0355     gbe->frm_control = val;
0356     udelay(1000);
0357     for (i = 0; i < 10000; i++) {
0358         val = gbe->frm_inhwctrl;
0359         if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1)
0360             udelay(10);
0361         else
0362             break;
0363     }
0364     if (i == 10000)
0365         printk(KERN_ERR "gbefb: turn on DMA timed out\n");
0366 
0367     gbe_turned_on = 1;
0368 }
0369 
0370 static void gbe_loadcmap(void)
0371 {
0372     int i, j;
0373 
0374     for (i = 0; i < 256; i++) {
0375         for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++)
0376             udelay(10);
0377         if (j == 1000)
0378             printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
0379 
0380         gbe->cmap[i] = gbe_cmap[i];
0381     }
0382 }
0383 
0384 /*
0385  *  Blank the display.
0386  */
0387 static int gbefb_blank(int blank, struct fb_info *info)
0388 {
0389     /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
0390     switch (blank) {
0391     case FB_BLANK_UNBLANK:      /* unblank */
0392         gbe_turn_on();
0393         gbe_loadcmap();
0394         break;
0395 
0396     case FB_BLANK_NORMAL:       /* blank */
0397         gbe_turn_off();
0398         break;
0399 
0400     default:
0401         /* Nothing */
0402         break;
0403     }
0404     return 0;
0405 }
0406 
0407 /*
0408  *  Setup flatpanel related registers.
0409  */
0410 static void gbefb_setup_flatpanel(struct gbe_timing_info *timing)
0411 {
0412     int fp_wid, fp_hgt, fp_vbs, fp_vbe;
0413     u32 outputVal = 0;
0414 
0415     SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
0416         (timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
0417     SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
0418         (timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
0419     gbe->vt_flags = outputVal;
0420 
0421     /* Turn on the flat panel */
0422     fp_wid = 1600;
0423     fp_hgt = 1024;
0424     fp_vbs = 0;
0425     fp_vbe = 1600;
0426     timing->pll_m = 4;
0427     timing->pll_n = 1;
0428     timing->pll_p = 0;
0429 
0430     outputVal = 0;
0431     SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs);
0432     SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe);
0433     gbe->fp_de = outputVal;
0434     outputVal = 0;
0435     SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid);
0436     gbe->fp_hdrv = outputVal;
0437     outputVal = 0;
0438     SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1);
0439     SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1);
0440     gbe->fp_vdrv = outputVal;
0441 }
0442 
0443 struct gbe_pll_info {
0444     int clock_rate;
0445     int fvco_min;
0446     int fvco_max;
0447 };
0448 
0449 static struct gbe_pll_info gbe_pll_table[2] = {
0450     { 20, 80, 220 },
0451     { 27, 80, 220 },
0452 };
0453 
0454 static int compute_gbe_timing(struct fb_var_screeninfo *var,
0455                   struct gbe_timing_info *timing)
0456 {
0457     int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error;
0458     int pixclock;
0459     struct gbe_pll_info *gbe_pll;
0460 
0461     if (gbe_revision < 2)
0462         gbe_pll = &gbe_pll_table[0];
0463     else
0464         gbe_pll = &gbe_pll_table[1];
0465 
0466     /* Determine valid resolution and timing
0467      * GBE crystal runs at 20Mhz or 27Mhz
0468      * pll_m, pll_n, pll_p define the following frequencies
0469      * fvco = pll_m * 20Mhz / pll_n
0470      * fout = fvco / (2**pll_p) */
0471     best_error = 1000000000;
0472     best_n = best_m = best_p = 0;
0473     for (pll_p = 0; pll_p < 4; pll_p++)
0474         for (pll_m = 1; pll_m < 256; pll_m++)
0475             for (pll_n = 1; pll_n < 64; pll_n++) {
0476                 pixclock = (1000000 / gbe_pll->clock_rate) *
0477                         (pll_n << pll_p) / pll_m;
0478 
0479                 error = var->pixclock - pixclock;
0480 
0481                 if (error < 0)
0482                     error = -error;
0483 
0484                 if (error < best_error &&
0485                     pll_m / pll_n >
0486                     gbe_pll->fvco_min / gbe_pll->clock_rate &&
0487                     pll_m / pll_n <
0488                     gbe_pll->fvco_max / gbe_pll->clock_rate) {
0489                     best_error = error;
0490                     best_m = pll_m;
0491                     best_n = pll_n;
0492                     best_p = pll_p;
0493                 }
0494             }
0495 
0496     if (!best_n || !best_m)
0497         return -EINVAL; /* Resolution to high */
0498 
0499     pixclock = (1000000 / gbe_pll->clock_rate) *
0500         (best_n << best_p) / best_m;
0501 
0502     /* set video timing information */
0503     if (timing) {
0504         timing->width = var->xres;
0505         timing->height = var->yres;
0506         timing->pll_m = best_m;
0507         timing->pll_n = best_n;
0508         timing->pll_p = best_p;
0509         timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m /
0510             (timing->pll_n << timing->pll_p);
0511         timing->htotal = var->left_margin + var->xres +
0512                 var->right_margin + var->hsync_len;
0513         timing->vtotal = var->upper_margin + var->yres +
0514                 var->lower_margin + var->vsync_len;
0515         timing->fields_sec = 1000 * timing->cfreq / timing->htotal *
0516                 1000 / timing->vtotal;
0517         timing->hblank_start = var->xres;
0518         timing->vblank_start = var->yres;
0519         timing->hblank_end = timing->htotal;
0520         timing->hsync_start = var->xres + var->right_margin + 1;
0521         timing->hsync_end = timing->hsync_start + var->hsync_len;
0522         timing->vblank_end = timing->vtotal;
0523         timing->vsync_start = var->yres + var->lower_margin + 1;
0524         timing->vsync_end = timing->vsync_start + var->vsync_len;
0525     }
0526 
0527     return pixclock;
0528 }
0529 
0530 static void gbe_set_timing_info(struct gbe_timing_info *timing)
0531 {
0532     int temp;
0533     unsigned int val;
0534 
0535     /* setup dot clock PLL */
0536     val = 0;
0537     SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1);
0538     SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1);
0539     SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
0540     SET_GBE_FIELD(DOTCLK, RUN, val, 0); /* do not start yet */
0541     gbe->dotclock = val;
0542     mdelay(10);
0543 
0544     /* setup pixel counter */
0545     val = 0;
0546     SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal);
0547     SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal);
0548     gbe->vt_xymax = val;
0549 
0550     /* setup video timing signals */
0551     val = 0;
0552     SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start);
0553     SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end);
0554     gbe->vt_vsync = val;
0555     val = 0;
0556     SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start);
0557     SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end);
0558     gbe->vt_hsync = val;
0559     val = 0;
0560     SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start);
0561     SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end);
0562     gbe->vt_vblank = val;
0563     val = 0;
0564     SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val,
0565               timing->hblank_start - 5);
0566     SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val,
0567               timing->hblank_end - 3);
0568     gbe->vt_hblank = val;
0569 
0570     /* setup internal timing signals */
0571     val = 0;
0572     SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start);
0573     SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end);
0574     gbe->vt_vcmap = val;
0575     val = 0;
0576     SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start);
0577     SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end);
0578     gbe->vt_hcmap = val;
0579 
0580     val = 0;
0581     temp = timing->vblank_start - timing->vblank_end - 1;
0582     if (temp > 0)
0583         temp = -temp;
0584 
0585     if (flat_panel_enabled)
0586         gbefb_setup_flatpanel(timing);
0587 
0588     SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp);
0589     if (timing->hblank_end >= 20)
0590         SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
0591                   timing->hblank_end - 20);
0592     else
0593         SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
0594                   timing->htotal - (20 - timing->hblank_end));
0595     gbe->did_start_xy = val;
0596 
0597     val = 0;
0598     SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1));
0599     if (timing->hblank_end >= GBE_CRS_MAGIC)
0600         SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
0601                   timing->hblank_end - GBE_CRS_MAGIC);
0602     else
0603         SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
0604                   timing->htotal - (GBE_CRS_MAGIC -
0605                         timing->hblank_end));
0606     gbe->crs_start_xy = val;
0607 
0608     val = 0;
0609     SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp);
0610     SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4);
0611     gbe->vc_start_xy = val;
0612 
0613     val = 0;
0614     temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON;
0615     if (temp < 0)
0616         temp += timing->htotal; /* allow blank to wrap around */
0617 
0618     SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp);
0619     SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val,
0620               ((temp + timing->width -
0621             GBE_PIXEN_MAGIC_OFF) % timing->htotal));
0622     gbe->vt_hpixen = val;
0623 
0624     val = 0;
0625     SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end);
0626     SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start);
0627     gbe->vt_vpixen = val;
0628 
0629     /* turn off sync on green */
0630     val = 0;
0631     SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1);
0632     gbe->vt_flags = val;
0633 }
0634 
0635 /*
0636  *  Set the hardware according to 'par'.
0637  */
0638 
0639 static int gbefb_set_par(struct fb_info *info)
0640 {
0641     int i;
0642     unsigned int val;
0643     int wholeTilesX, partTilesX, maxPixelsPerTileX;
0644     int height_pix;
0645     int xpmax, ypmax;   /* Monitor resolution */
0646     int bytesPerPixel;  /* Bytes per pixel */
0647     struct gbefb_par *par = (struct gbefb_par *) info->par;
0648 
0649     compute_gbe_timing(&info->var, &par->timing);
0650 
0651     bytesPerPixel = info->var.bits_per_pixel / 8;
0652     info->fix.line_length = info->var.xres_virtual * bytesPerPixel;
0653     xpmax = par->timing.width;
0654     ypmax = par->timing.height;
0655 
0656     /* turn off GBE */
0657     gbe_turn_off();
0658 
0659     /* set timing info */
0660     gbe_set_timing_info(&par->timing);
0661 
0662     /* initialize DIDs */
0663     val = 0;
0664     switch (bytesPerPixel) {
0665     case 1:
0666         SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
0667         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
0668         break;
0669     case 2:
0670         SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
0671         info->fix.visual = FB_VISUAL_TRUECOLOR;
0672         break;
0673     case 4:
0674         SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
0675         info->fix.visual = FB_VISUAL_TRUECOLOR;
0676         break;
0677     }
0678     SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
0679 
0680     for (i = 0; i < 32; i++)
0681         gbe->mode_regs[i] = val;
0682 
0683     /* Initialize interrupts */
0684     gbe->vt_intr01 = 0xffffffff;
0685     gbe->vt_intr23 = 0xffffffff;
0686 
0687     /* HACK:
0688        The GBE hardware uses a tiled memory to screen mapping. Tiles are
0689        blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
0690        16bit and 32 bit modes (64 kB). They cover the screen with partial
0691        tiles on the right and/or bottom of the screen if needed.
0692        For example in 640x480 8 bit mode the mapping is:
0693 
0694        <-------- 640 ----->
0695        <---- 512 ----><128|384 offscreen>
0696        ^  ^
0697        | 128    [tile 0]        [tile 1]
0698        |  v
0699        ^
0700        4 128    [tile 2]        [tile 3]
0701        8  v
0702        0  ^
0703        128    [tile 4]        [tile 5]
0704        |  v
0705        |  ^
0706        v  96    [tile 6]        [tile 7]
0707        32 offscreen
0708 
0709        Tiles have the advantage that they can be allocated individually in
0710        memory. However, this mapping is not linear at all, which is not
0711        really convenient. In order to support linear addressing, the GBE
0712        DMA hardware is fooled into thinking the screen is only one tile
0713        large and but has a greater height, so that the DMA transfer covers
0714        the same region.
0715        Tiles are still allocated as independent chunks of 64KB of
0716        continuous physical memory and remapped so that the kernel sees the
0717        framebuffer as a continuous virtual memory. The GBE tile table is
0718        set up so that each tile references one of these 64k blocks:
0719 
0720        GBE -> tile list    framebuffer           TLB   <------------ CPU
0721               [ tile 0 ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     ^
0722                  ...           ...              ...       linear virtual FB
0723               [ tile n ] -> [ 64KB ]  <- [ 16x 4KB page entries ]     v
0724 
0725 
0726        The GBE hardware is then told that the buffer is 512*tweaked_height,
0727        with tweaked_height = real_width*real_height/pixels_per_tile.
0728        Thus the GBE hardware will scan the first tile, filing the first 64k
0729        covered region of the screen, and then will proceed to the next
0730        tile, until the whole screen is covered.
0731 
0732        Here is what would happen at 640x480 8bit:
0733 
0734        normal tiling               linear
0735        ^   11111111111111112222    11111111111111111111  ^
0736        128 11111111111111112222    11111111111111111111 102 lines
0737            11111111111111112222    11111111111111111111  v
0738        V   11111111111111112222    11111111222222222222
0739            33333333333333334444    22222222222222222222
0740            33333333333333334444    22222222222222222222
0741            <      512     >        <  256 >               102*640+256 = 64k
0742 
0743        NOTE: The only mode for which this is not working is 800x600 8bit,
0744        as 800*600/512 = 937.5 which is not integer and thus causes
0745        flickering.
0746        I guess this is not so important as one can use 640x480 8bit or
0747        800x600 16bit anyway.
0748      */
0749 
0750     /* Tell gbe about the tiles table location */
0751     /* tile_ptr -> [ tile 1 ] -> FB mem */
0752     /*             [ tile 2 ] -> FB mem */
0753     /*               ...                */
0754     val = 0;
0755     SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9);
0756     SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */
0757     SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0);
0758     gbe->frm_control = val;
0759 
0760     maxPixelsPerTileX = 512 / bytesPerPixel;
0761     wholeTilesX = 1;
0762     partTilesX = 0;
0763 
0764     /* Initialize the framebuffer */
0765     val = 0;
0766     SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX);
0767     SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX);
0768 
0769     switch (bytesPerPixel) {
0770     case 1:
0771         SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
0772                   GBE_FRM_DEPTH_8);
0773         break;
0774     case 2:
0775         SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
0776                   GBE_FRM_DEPTH_16);
0777         break;
0778     case 4:
0779         SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
0780                   GBE_FRM_DEPTH_32);
0781         break;
0782     }
0783     gbe->frm_size_tile = val;
0784 
0785     /* compute tweaked height */
0786     height_pix = xpmax * ypmax / maxPixelsPerTileX;
0787 
0788     val = 0;
0789     SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix);
0790     gbe->frm_size_pixel = val;
0791 
0792     /* turn off DID and overlay DMA */
0793     gbe->did_control = 0;
0794     gbe->ovr_width_tile = 0;
0795 
0796     /* Turn off mouse cursor */
0797     gbe->crs_ctl = 0;
0798 
0799     /* Turn on GBE */
0800     gbe_turn_on();
0801 
0802     /* Initialize the gamma map */
0803     udelay(10);
0804     for (i = 0; i < 256; i++)
0805         gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8);
0806 
0807     /* Initialize the color map */
0808     for (i = 0; i < 256; i++)
0809         gbe_cmap[i] = (i << 8) | (i << 16) | (i << 24);
0810 
0811     gbe_loadcmap();
0812 
0813     return 0;
0814 }
0815 
0816 static void gbefb_encode_fix(struct fb_fix_screeninfo *fix,
0817                  struct fb_var_screeninfo *var)
0818 {
0819     memset(fix, 0, sizeof(struct fb_fix_screeninfo));
0820     strcpy(fix->id, "SGI GBE");
0821     fix->smem_start = (unsigned long) gbe_mem;
0822     fix->smem_len = gbe_mem_size;
0823     fix->type = FB_TYPE_PACKED_PIXELS;
0824     fix->type_aux = 0;
0825     fix->accel = FB_ACCEL_NONE;
0826     switch (var->bits_per_pixel) {
0827     case 8:
0828         fix->visual = FB_VISUAL_PSEUDOCOLOR;
0829         break;
0830     default:
0831         fix->visual = FB_VISUAL_TRUECOLOR;
0832         break;
0833     }
0834     fix->ywrapstep = 0;
0835     fix->xpanstep = 0;
0836     fix->ypanstep = 0;
0837     fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
0838     fix->mmio_start = GBE_BASE;
0839     fix->mmio_len = sizeof(struct sgi_gbe);
0840 }
0841 
0842 /*
0843  *  Set a single color register. The values supplied are already
0844  *  rounded down to the hardware's capabilities (according to the
0845  *  entries in the var structure). Return != 0 for invalid regno.
0846  */
0847 
0848 static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
0849                  unsigned blue, unsigned transp,
0850                  struct fb_info *info)
0851 {
0852     int i;
0853 
0854     if (regno > 255)
0855         return 1;
0856     red >>= 8;
0857     green >>= 8;
0858     blue >>= 8;
0859 
0860     if (info->var.bits_per_pixel <= 8) {
0861         gbe_cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
0862         if (gbe_turned_on) {
0863             /* wait for the color map FIFO to have a free entry */
0864             for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
0865                 udelay(10);
0866             if (i == 1000) {
0867                 printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
0868                 return 1;
0869             }
0870             gbe->cmap[regno] = gbe_cmap[regno];
0871         }
0872     } else if (regno < 16) {
0873         switch (info->var.bits_per_pixel) {
0874         case 15:
0875         case 16:
0876             red >>= 3;
0877             green >>= 3;
0878             blue >>= 3;
0879             pseudo_palette[regno] =
0880                 (red << info->var.red.offset) |
0881                 (green << info->var.green.offset) |
0882                 (blue << info->var.blue.offset);
0883             break;
0884         case 32:
0885             pseudo_palette[regno] =
0886                 (red << info->var.red.offset) |
0887                 (green << info->var.green.offset) |
0888                 (blue << info->var.blue.offset);
0889             break;
0890         }
0891     }
0892 
0893     return 0;
0894 }
0895 
0896 /*
0897  *  Check video mode validity, eventually modify var to best match.
0898  */
0899 static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
0900 {
0901     unsigned int line_length;
0902     struct gbe_timing_info timing;
0903     int ret;
0904 
0905     /* Limit bpp to 8, 16, and 32 */
0906     if (var->bits_per_pixel <= 8)
0907         var->bits_per_pixel = 8;
0908     else if (var->bits_per_pixel <= 16)
0909         var->bits_per_pixel = 16;
0910     else if (var->bits_per_pixel <= 32)
0911         var->bits_per_pixel = 32;
0912     else
0913         return -EINVAL;
0914 
0915     /* Check the mode can be mapped linearly with the tile table trick. */
0916     /* This requires width x height x bytes/pixel be a multiple of 512 */
0917     if ((var->xres * var->yres * var->bits_per_pixel) & 4095)
0918         return -EINVAL;
0919 
0920     var->grayscale = 0; /* No grayscale for now */
0921 
0922     ret = compute_gbe_timing(var, &timing);
0923     var->pixclock = ret;
0924     if (ret < 0)
0925         return -EINVAL;
0926 
0927     /* Adjust virtual resolution, if necessary */
0928     if (var->xres > var->xres_virtual || (!ywrap && !ypan))
0929         var->xres_virtual = var->xres;
0930     if (var->yres > var->yres_virtual || (!ywrap && !ypan))
0931         var->yres_virtual = var->yres;
0932 
0933     if (var->vmode & FB_VMODE_CONUPDATE) {
0934         var->vmode |= FB_VMODE_YWRAP;
0935         var->xoffset = info->var.xoffset;
0936         var->yoffset = info->var.yoffset;
0937     }
0938 
0939     /* No grayscale for now */
0940     var->grayscale = 0;
0941 
0942     /* Memory limit */
0943     line_length = var->xres_virtual * var->bits_per_pixel / 8;
0944     if (line_length * var->yres_virtual > gbe_mem_size)
0945         return -ENOMEM; /* Virtual resolution too high */
0946 
0947     switch (var->bits_per_pixel) {
0948     case 8:
0949         var->red.offset = 0;
0950         var->red.length = 8;
0951         var->green.offset = 0;
0952         var->green.length = 8;
0953         var->blue.offset = 0;
0954         var->blue.length = 8;
0955         var->transp.offset = 0;
0956         var->transp.length = 0;
0957         break;
0958     case 16:        /* RGB 1555 */
0959         var->red.offset = 10;
0960         var->red.length = 5;
0961         var->green.offset = 5;
0962         var->green.length = 5;
0963         var->blue.offset = 0;
0964         var->blue.length = 5;
0965         var->transp.offset = 0;
0966         var->transp.length = 0;
0967         break;
0968     case 32:        /* RGB 8888 */
0969         var->red.offset = 24;
0970         var->red.length = 8;
0971         var->green.offset = 16;
0972         var->green.length = 8;
0973         var->blue.offset = 8;
0974         var->blue.length = 8;
0975         var->transp.offset = 0;
0976         var->transp.length = 8;
0977         break;
0978     }
0979     var->red.msb_right = 0;
0980     var->green.msb_right = 0;
0981     var->blue.msb_right = 0;
0982     var->transp.msb_right = 0;
0983 
0984     var->left_margin = timing.htotal - timing.hsync_end;
0985     var->right_margin = timing.hsync_start - timing.width;
0986     var->upper_margin = timing.vtotal - timing.vsync_end;
0987     var->lower_margin = timing.vsync_start - timing.height;
0988     var->hsync_len = timing.hsync_end - timing.hsync_start;
0989     var->vsync_len = timing.vsync_end - timing.vsync_start;
0990 
0991     return 0;
0992 }
0993 
0994 static int gbefb_mmap(struct fb_info *info,
0995             struct vm_area_struct *vma)
0996 {
0997     unsigned long size = vma->vm_end - vma->vm_start;
0998     unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
0999     unsigned long addr;
1000     unsigned long phys_addr, phys_size;
1001     u16 *tile;
1002 
1003     /* check range */
1004     if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1005         return -EINVAL;
1006     if (size > gbe_mem_size)
1007         return -EINVAL;
1008     if (offset > gbe_mem_size - size)
1009         return -EINVAL;
1010 
1011     /* remap using the fastest write-through mode on architecture */
1012     /* try not polluting the cache when possible */
1013 #ifdef CONFIG_MIPS
1014     pgprot_val(vma->vm_page_prot) =
1015         pgprot_fb(pgprot_val(vma->vm_page_prot));
1016 #endif
1017     /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
1018 
1019     /* look for the starting tile */
1020     tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
1021     addr = vma->vm_start;
1022     offset &= TILE_MASK;
1023 
1024     /* remap each tile separately */
1025     do {
1026         phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset;
1027         if ((offset + size) < TILE_SIZE)
1028             phys_size = size;
1029         else
1030             phys_size = TILE_SIZE - offset;
1031 
1032         if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT,
1033                         phys_size, vma->vm_page_prot))
1034             return -EAGAIN;
1035 
1036         offset = 0;
1037         size -= phys_size;
1038         addr += phys_size;
1039         tile++;
1040     } while (size);
1041 
1042     return 0;
1043 }
1044 
1045 static const struct fb_ops gbefb_ops = {
1046     .owner      = THIS_MODULE,
1047     .fb_check_var   = gbefb_check_var,
1048     .fb_set_par = gbefb_set_par,
1049     .fb_setcolreg   = gbefb_setcolreg,
1050     .fb_mmap    = gbefb_mmap,
1051     .fb_blank   = gbefb_blank,
1052     .fb_fillrect    = cfb_fillrect,
1053     .fb_copyarea    = cfb_copyarea,
1054     .fb_imageblit   = cfb_imageblit,
1055 };
1056 
1057 /*
1058  * sysfs
1059  */
1060 
1061 static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
1062 {
1063     return snprintf(buf, PAGE_SIZE, "%u\n", gbe_mem_size);
1064 }
1065 
1066 static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
1067 
1068 static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf)
1069 {
1070     return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision);
1071 }
1072 
1073 static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);
1074 
1075 static void gbefb_remove_sysfs(struct device *dev)
1076 {
1077     device_remove_file(dev, &dev_attr_size);
1078     device_remove_file(dev, &dev_attr_revision);
1079 }
1080 
1081 static void gbefb_create_sysfs(struct device *dev)
1082 {
1083     device_create_file(dev, &dev_attr_size);
1084     device_create_file(dev, &dev_attr_revision);
1085 }
1086 
1087 /*
1088  * Initialization
1089  */
1090 
1091 static int gbefb_setup(char *options)
1092 {
1093     char *this_opt;
1094 
1095     if (!options || !*options)
1096         return 0;
1097 
1098     while ((this_opt = strsep(&options, ",")) != NULL) {
1099         if (!strncmp(this_opt, "monitor:", 8)) {
1100             if (!strncmp(this_opt + 8, "crt", 3)) {
1101                 flat_panel_enabled = 0;
1102                 default_var = &default_var_CRT;
1103                 default_mode = &default_mode_CRT;
1104             } else if (!strncmp(this_opt + 8, "1600sw", 6) ||
1105                    !strncmp(this_opt + 8, "lcd", 3)) {
1106                 flat_panel_enabled = 1;
1107                 default_var = &default_var_LCD;
1108                 default_mode = &default_mode_LCD;
1109             }
1110         } else if (!strncmp(this_opt, "mem:", 4)) {
1111             gbe_mem_size = memparse(this_opt + 4, &this_opt);
1112             if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024)
1113                 gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024;
1114             if (gbe_mem_size < TILE_SIZE)
1115                 gbe_mem_size = TILE_SIZE;
1116         } else
1117             mode_option = this_opt;
1118     }
1119     return 0;
1120 }
1121 
1122 static int gbefb_probe(struct platform_device *p_dev)
1123 {
1124     int i, ret = 0;
1125     struct fb_info *info;
1126     struct gbefb_par *par;
1127 #ifndef MODULE
1128     char *options = NULL;
1129 #endif
1130 
1131     info = framebuffer_alloc(sizeof(struct gbefb_par), &p_dev->dev);
1132     if (!info)
1133         return -ENOMEM;
1134 
1135 #ifndef MODULE
1136     if (fb_get_options("gbefb", &options)) {
1137         ret = -ENODEV;
1138         goto out_release_framebuffer;
1139     }
1140     gbefb_setup(options);
1141 #endif
1142 
1143     if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
1144         printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
1145         ret = -EBUSY;
1146         goto out_release_framebuffer;
1147     }
1148 
1149     gbe = (struct sgi_gbe *) devm_ioremap(&p_dev->dev, GBE_BASE,
1150                           sizeof(struct sgi_gbe));
1151     if (!gbe) {
1152         printk(KERN_ERR "gbefb: couldn't map mmio region\n");
1153         ret = -ENXIO;
1154         goto out_release_mem_region;
1155     }
1156     gbe_revision = gbe->ctrlstat & 15;
1157 
1158     gbe_tiles.cpu = dmam_alloc_coherent(&p_dev->dev,
1159                 GBE_TLB_SIZE * sizeof(uint16_t),
1160                 &gbe_tiles.dma, GFP_KERNEL);
1161     if (!gbe_tiles.cpu) {
1162         printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
1163         ret = -ENOMEM;
1164         goto out_release_mem_region;
1165     }
1166 
1167     if (gbe_mem_phys) {
1168         /* memory was allocated at boot time */
1169         gbe_mem = devm_ioremap_wc(&p_dev->dev, gbe_mem_phys,
1170                       gbe_mem_size);
1171         if (!gbe_mem) {
1172             printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
1173             ret = -ENOMEM;
1174             goto out_release_mem_region;
1175         }
1176 
1177         gbe_dma_addr = 0;
1178     } else {
1179         /* try to allocate memory with the classical allocator
1180          * this has high chance to fail on low memory machines */
1181         gbe_mem = dmam_alloc_attrs(&p_dev->dev, gbe_mem_size,
1182                 &gbe_dma_addr, GFP_KERNEL,
1183                 DMA_ATTR_WRITE_COMBINE);
1184         if (!gbe_mem) {
1185             printk(KERN_ERR "gbefb: couldn't allocate framebuffer memory\n");
1186             ret = -ENOMEM;
1187             goto out_release_mem_region;
1188         }
1189 
1190         gbe_mem_phys = (unsigned long) gbe_dma_addr;
1191     }
1192 
1193     par = info->par;
1194     par->wc_cookie = arch_phys_wc_add(gbe_mem_phys, gbe_mem_size);
1195 
1196     /* map framebuffer memory into tiles table */
1197     for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
1198         gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
1199 
1200     info->fbops = &gbefb_ops;
1201     info->pseudo_palette = pseudo_palette;
1202     info->flags = FBINFO_DEFAULT;
1203     info->screen_base = gbe_mem;
1204     fb_alloc_cmap(&info->cmap, 256, 0);
1205 
1206     /* reset GBE */
1207     gbe_reset();
1208 
1209     /* turn on default video mode */
1210     if (fb_find_mode(&par->var, info, mode_option, NULL, 0,
1211              default_mode, 8) == 0)
1212         par->var = *default_var;
1213     info->var = par->var;
1214     gbefb_check_var(&par->var, info);
1215     gbefb_encode_fix(&info->fix, &info->var);
1216 
1217     if (register_framebuffer(info) < 0) {
1218         printk(KERN_ERR "gbefb: couldn't register framebuffer\n");
1219         ret = -ENXIO;
1220         goto out_gbe_unmap;
1221     }
1222 
1223     platform_set_drvdata(p_dev, info);
1224     gbefb_create_sysfs(&p_dev->dev);
1225 
1226     fb_info(info, "%s rev %d @ 0x%08x using %dkB memory\n",
1227         info->fix.id, gbe_revision, (unsigned)GBE_BASE,
1228         gbe_mem_size >> 10);
1229 
1230     return 0;
1231 
1232 out_gbe_unmap:
1233     arch_phys_wc_del(par->wc_cookie);
1234 out_release_mem_region:
1235     release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
1236 out_release_framebuffer:
1237     framebuffer_release(info);
1238 
1239     return ret;
1240 }
1241 
1242 static int gbefb_remove(struct platform_device* p_dev)
1243 {
1244     struct fb_info *info = platform_get_drvdata(p_dev);
1245     struct gbefb_par *par = info->par;
1246 
1247     unregister_framebuffer(info);
1248     gbe_turn_off();
1249     arch_phys_wc_del(par->wc_cookie);
1250     release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
1251     gbefb_remove_sysfs(&p_dev->dev);
1252     framebuffer_release(info);
1253 
1254     return 0;
1255 }
1256 
1257 static struct platform_driver gbefb_driver = {
1258     .probe = gbefb_probe,
1259     .remove = gbefb_remove,
1260     .driver = {
1261         .name = "gbefb",
1262     },
1263 };
1264 
1265 static struct platform_device *gbefb_device;
1266 
1267 static int __init gbefb_init(void)
1268 {
1269     int ret = platform_driver_register(&gbefb_driver);
1270     if (IS_ENABLED(CONFIG_SGI_IP32) && !ret) {
1271         gbefb_device = platform_device_alloc("gbefb", 0);
1272         if (gbefb_device) {
1273             ret = platform_device_add(gbefb_device);
1274         } else {
1275             ret = -ENOMEM;
1276         }
1277         if (ret) {
1278             platform_device_put(gbefb_device);
1279             platform_driver_unregister(&gbefb_driver);
1280         }
1281     }
1282     return ret;
1283 }
1284 
1285 static void __exit gbefb_exit(void)
1286 {
1287     platform_device_unregister(gbefb_device);
1288     platform_driver_unregister(&gbefb_driver);
1289 }
1290 
1291 module_init(gbefb_init);
1292 module_exit(gbefb_exit);
1293 
1294 MODULE_LICENSE("GPL");