Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:40

0001 /*
0002  *  FB driver for Cirrus GD5446 graphic hardware.
0003  *  Tested to be compatible with QEMU GD5446 emulation but not on real HW.
0004  *
0005  *  Copyright (c) 2012 - Alexandru-Sever Horin (alex.sever.h@gmail.com).
0006  *
0007  *  The license and distribution terms for this file may be
0008  *  found in the file LICENSE in this distribution or at
0009  *  http://www.rtems.org/license/LICENSE.
0010  *
0011  *  The code is based on next information sources:
0012  *    - CL-GD5446 Technical Reference Manual, 1996, Second Edition
0013  *    - RTEMS fb_vga.c - Rosimildo da Silva ( rdasilva@connecttel.com )
0014  *    - Cirrus xf86 driver - used as VGA hardware setup sequence documentation
0015  */
0016 
0017 #include <stdlib.h>
0018 #include <stdio.h>
0019 #include <errno.h>
0020 #include <sys/types.h>
0021 #include <pthread.h>
0022 
0023 #include <bsp.h>
0024 #include <bsp/irq.h>
0025 #include <rtems/libio.h>
0026 #include <rtems/pci.h>
0027 
0028 #include <rtems/fb.h>
0029 #include <rtems/framebuffer.h>
0030 #include <rtems/score/atomic.h>
0031 
0032 /* flag to limit driver to protect against multiple opens */
0033 static Atomic_Flag driver_mutex;
0034 
0035 /* screen information for the VGA driver
0036  * standard structures
0037  */
0038 static struct fb_var_screeninfo fb_var;
0039 static struct fb_fix_screeninfo fb_fix;
0040 
0041 #define CIRRUS_VENDOR_ID         0x1013
0042 #define CIRRUS_GD5446_DEVICE_ID  0x00b8
0043 
0044 typedef struct _DisplayModeRec {
0045   struct _DisplayModeRec *prev;
0046   struct _DisplayModeRec *next;
0047   char *name;                 /* identifier for the mode */
0048   int type;
0049 
0050   /* These are the values that the user sees/provides */
0051   int Clock;                  /* pixel clock freq (kHz) */
0052   int HDisplay;               /* horizontal timing */
0053   int HSyncStart;
0054   int HSyncEnd;
0055   int HTotal;
0056   int HSkew;
0057   int VDisplay;               /* vertical timing */
0058   int VSyncStart;
0059   int VSyncEnd;
0060   int VTotal;
0061   int VScan;
0062   int Flags;
0063 
0064   /* These are the values the hardware uses */
0065   int ClockIndex;
0066   int SynthClock;             /* Actual clock freq to
0067    * be programmed  (kHz) */
0068   int CrtcHDisplay;
0069   int CrtcHBlankStart;
0070   int CrtcHSyncStart;
0071   int CrtcHSyncEnd;
0072   int CrtcHBlankEnd;
0073   int CrtcHTotal;
0074   int CrtcHSkew;
0075   int CrtcVDisplay;
0076   int CrtcVBlankStart;
0077   int CrtcVSyncStart;
0078   int CrtcVSyncEnd;
0079   int CrtcVBlankEnd;
0080   int CrtcVTotal;
0081   int CrtcHAdjusted;
0082   int CrtcVAdjusted;
0083   int PrivSize;
0084   int32_t *Private;
0085   int PrivFlags;
0086 
0087   float HSync, VRefresh;
0088 } DisplayModeRec, *DisplayModePtr;
0089 
0090 static DisplayModeRec available_modes[] = {
0091     {
0092         .Clock      = 31500 ,
0093         .HDisplay   = 640 ,
0094         .HSyncStart = 664 ,
0095         .HSyncEnd   = 704 ,
0096         .HTotal     = 832 ,
0097         .HSkew      = 0 ,
0098         .VDisplay   = 480 ,       /* vertical timing */
0099         .VSyncStart = 489 ,
0100         .VSyncEnd   = 491 ,
0101         .VTotal     = 520 ,
0102         .VScan      = 0,
0103         .Flags      = 0
0104     },
0105     {
0106         .Clock      = 40000 ,
0107         .HDisplay   = 800 ,
0108         .HSyncStart = 840 ,
0109         .HSyncEnd   = 968 ,
0110         .HTotal     = 1056 ,
0111         .HSkew      = 0 ,
0112         .VDisplay   = 600 ,       /* vertical timing */
0113         .VSyncStart = 601 ,
0114         .VSyncEnd   = 605 ,
0115         .VTotal     = 628 ,
0116         .VScan      = 0,
0117         .Flags      = 0
0118     },
0119 };
0120 static DisplayModePtr active_mode;
0121 
0122 /* The display mode used for the board hardcoded in the following define
0123  * Index in above structure
0124  */
0125 #define CIRRUS_DISPLAY_MODE  0
0126 
0127 /* The display bytes per pixel used for the board hardcoded in the following define
0128  * Index in above structure
0129  */
0130 #define CIRRUS_DEFAULT_BPP 24
0131 
0132 /* cirrus board information */
0133 struct cirrus_board_str{
0134   int    pci_bus;
0135   int    pci_device;
0136   int    pci_function;
0137   void  *reg_base;
0138 };
0139 
0140 static struct cirrus_board_str cirrus_board_info;
0141 
0142 /*
0143  * get information from the board
0144  */
0145 static int
0146 cirrus_pci_read( struct cirrus_board_str *cirrus_board, uint32_t *mem_base, uint32_t *cirrus_register_base)
0147 {
0148   int r;
0149 
0150   r = pci_read_config_dword(
0151       cirrus_board->pci_bus, cirrus_board->pci_device, cirrus_board->pci_function,
0152       PCI_BASE_ADDRESS_0, mem_base);
0153   if( r != PCIB_ERR_SUCCESS)
0154     return RTEMS_UNSATISFIED;
0155 
0156   r = pci_read_config_dword(
0157       cirrus_board->pci_bus, cirrus_board->pci_device, cirrus_board->pci_function,
0158       PCI_BASE_ADDRESS_1, cirrus_register_base);
0159   if( r != PCIB_ERR_SUCCESS)
0160     return RTEMS_UNSATISFIED;
0161 
0162   *mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
0163   *cirrus_register_base     &= PCI_BASE_ADDRESS_MEM_MASK;
0164 
0165   return RTEMS_SUCCESSFUL;
0166 }
0167 
0168 static inline int
0169 fb_cirrus_read_config_dword(
0170     struct cirrus_board_str *fbst,
0171     unsigned char where,
0172     uint32_t     *pval)
0173 {
0174   return pci_read_config_dword(
0175       fbst->pci_bus, fbst->pci_device, fbst->pci_function,
0176       where, pval);
0177 }
0178 
0179 static inline int
0180 fb_cirrus_write_config_dword(
0181     struct cirrus_board_str *fbst,
0182     unsigned char where,
0183     uint32_t     val)
0184 {
0185   return pci_write_config_dword(
0186       fbst->pci_bus, fbst->pci_device, fbst->pci_function,
0187       where, val);
0188 }
0189 
0190 static inline void
0191 fb_cirrus_write_reg8 (
0192     const struct cirrus_board_str *fbst,
0193     unsigned int reg,
0194     unsigned int val)
0195 {
0196   *(volatile uint8_t*)((char *)fbst->reg_base + reg) = val;
0197 }
0198 
0199 static inline unsigned int
0200 fb_cirrus_read_reg8 (
0201     const struct cirrus_board_str *fbst,
0202     unsigned int reg)
0203 {
0204   return *(volatile uint8_t*)((char *)fbst->reg_base + reg);
0205 }
0206 
0207 #define SEQ_INDEX 0x04
0208 #define SEQ_DATA 0x05
0209 
0210 static inline void
0211 fb_cirrus_write_seq_reg (
0212     const struct cirrus_board_str *fbst,
0213     unsigned int reg,
0214     unsigned int val)
0215 {
0216   fb_cirrus_write_reg8(fbst, SEQ_INDEX, reg);
0217   fb_cirrus_write_reg8(fbst, SEQ_DATA, val);
0218 }
0219 
0220 static inline unsigned int
0221 fb_cirrus_read_seq_reg (
0222     const struct cirrus_board_str *fbst,
0223     unsigned int reg)
0224 {
0225   fb_cirrus_write_reg8(fbst, SEQ_INDEX, reg);
0226   return fb_cirrus_read_reg8(fbst, SEQ_DATA);
0227 }
0228 
0229 #define CRT_INDEX 0x14
0230 #define CRT_DATA 0x15
0231 
0232 static inline void
0233 fb_cirrus_write_crt_reg (
0234     const struct cirrus_board_str *fbst,
0235     unsigned int reg,
0236     unsigned int val)
0237 {
0238   fb_cirrus_write_reg8(fbst, CRT_INDEX, reg);
0239   fb_cirrus_write_reg8(fbst, CRT_DATA, val);
0240 }
0241 
0242 static inline unsigned int
0243 fb_cirrus_read_crt_reg (
0244     const struct cirrus_board_str *fbst,
0245     unsigned int reg)
0246 {
0247   fb_cirrus_write_reg8(fbst, CRT_INDEX, reg);
0248   return fb_cirrus_read_reg8(fbst, CRT_DATA);
0249 }
0250 
0251 #define GDC_INDEX 0x0E
0252 #define GDC_DATA 0x0F
0253 
0254 static inline void
0255 fb_cirrus_write_gdc_reg (
0256     const struct cirrus_board_str *fbst,
0257     unsigned int reg,
0258     unsigned int val)
0259 {
0260   fb_cirrus_write_reg8(fbst, GDC_INDEX, reg);
0261   fb_cirrus_write_reg8(fbst, GDC_DATA, val);
0262 }
0263 
0264 static inline unsigned int
0265 fb_cirrus_read_gdc_reg (
0266     const struct cirrus_board_str *fbst,
0267     unsigned int reg)
0268 {
0269   fb_cirrus_write_reg8(fbst, GDC_INDEX, reg);
0270   return fb_cirrus_read_reg8(fbst, GDC_DATA);
0271 }
0272 
0273 #define VGA_DAC_MASK 0x06
0274 
0275 static inline void
0276 fb_cirrus_write_hdr_reg (
0277     const struct cirrus_board_str *fbst,
0278     unsigned int val)
0279 {
0280   volatile unsigned int dummy RTEMS_UNUSED;
0281   dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK);
0282   dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK);
0283   dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK);
0284   dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK);
0285   fb_cirrus_write_reg8(fbst, VGA_DAC_MASK, val);
0286 }
0287 
0288 /* Functionality to support multiple VGA frame buffers can be added easily,
0289  * but is not supported at this moment because there is no need for two or
0290  * more "classic" VGA adapters.  Multiple frame buffer drivers may be
0291  * implemented and If we had implement it they would be named as "/dev/fb0",
0292  * "/dev/fb1", "/dev/fb2" and so on.
0293  */
0294 
0295 /*
0296  * fb_cirrus device driver INITIALIZE entry point.
0297  */
0298 rtems_device_driver
0299 frame_buffer_initialize(
0300     rtems_device_major_number  major,
0301     rtems_device_minor_number  minor,
0302     void                      *arg
0303 )
0304 {
0305   rtems_status_code status;
0306   int res;
0307 
0308   printk( "FB_CIRRUS -- driver initializing..\n" );
0309 
0310   res = pci_find_device(
0311       CIRRUS_VENDOR_ID,
0312       CIRRUS_GD5446_DEVICE_ID,
0313       minor,
0314       &cirrus_board_info.pci_bus,
0315       &cirrus_board_info.pci_device,
0316       &cirrus_board_info.pci_function
0317   );
0318 
0319   if ( res != PCIB_ERR_SUCCESS ) {
0320       printk( "FB_CIRRUS initialize -- device not found\n" );
0321 
0322       return RTEMS_UNSATISFIED;
0323   }
0324   else{
0325       printk( "FB_CIRRUS -- driver initializing..\n" );
0326       /*
0327        * Register the device
0328        */
0329       status = rtems_io_register_name (FRAMEBUFFER_DEVICE_0_NAME, major, 0);
0330       if (status != RTEMS_SUCCESSFUL) {
0331           printk("Error registering " FRAMEBUFFER_DEVICE_0_NAME
0332                  " FB_CIRRUS framebuffer device!\n");
0333           rtems_fatal_error_occurred( status );
0334       }
0335 
0336       _Atomic_Flag_clear(&driver_mutex, ATOMIC_ORDER_RELEASE);
0337 
0338       return RTEMS_SUCCESSFUL;
0339   }
0340 }
0341 
0342 /*
0343  * This function is used to initialize the Start Address - the first
0344  * displayed location in the video memory.
0345  * Usually mandatory
0346  */
0347 static void
0348 cirrus_adjust_frame( struct cirrus_board_str *board, int x, int y)
0349 {
0350   uint32_t Base;
0351   uint8_t tmp;
0352 
0353   Base = ((y * fb_var.xres + x) >> 3);
0354   if (fb_var.bits_per_pixel != 1)
0355     Base *= (fb_var.bits_per_pixel >> 2);
0356 
0357   printk("FB_CIRRUS: cirrus_adjust_frame %d %d >>> %d %x\n", x, y, Base, Base);
0358 
0359   if ((Base & ~0x000FFFFF) != 0) {
0360       printk("FB_CIRRUS: Internal error: cirrus_adjust_frame: cannot handle overflow\n");
0361       return;
0362   }
0363 
0364   fb_cirrus_write_crt_reg( board,  0x0C, (Base >> 8) & 0xff);
0365   fb_cirrus_write_crt_reg( board,  0x0D, Base & 0xff);
0366 
0367   tmp = fb_cirrus_read_crt_reg( board,  0x1B);
0368   tmp &= 0xF2;
0369   tmp |= (Base >> 16) & 0x01;
0370   tmp |= (Base >> 15) & 0x0C;
0371   fb_cirrus_write_crt_reg( board,  0x1B, tmp);
0372 
0373   tmp = fb_cirrus_read_crt_reg( board, 0x1D);
0374   tmp &= 0x7F;
0375   tmp |= (Base >> 12) & 0x80;
0376   fb_cirrus_write_crt_reg( board,  0x1D, tmp);
0377 }
0378 
0379 static int
0380 cirrus_set_mode(DisplayModePtr mode)
0381 {
0382   int depthcode = fb_var.bits_per_pixel;;
0383   int width;
0384   int HDiv2 = 0, VDiv2 = 0;
0385   const struct cirrus_board_str *cirrus_board_ptr = &cirrus_board_info;
0386   int temp;
0387   int hdr = -1;
0388 
0389   printk("FB_CIRRUS: mode  %d bpp, %d Hz    %d %d %d %d   %d %d %d %d\n",
0390       fb_var.bits_per_pixel,
0391       mode->Clock,
0392       mode->HDisplay,
0393       mode->HSyncStart,
0394       mode->HSyncEnd,
0395       mode->HTotal,
0396       mode->VDisplay,
0397       mode->VSyncStart,
0398       mode->VSyncEnd,
0399       mode->VTotal);
0400 
0401   if ( mode->Clock >  85500 ) {
0402       /* The actual DAC register value is set later. */
0403       /* The CRTC is clocked at VCLK / 2, so we must half the */
0404       /* horizontal timings. */
0405       if (!mode->CrtcHAdjusted) {
0406           mode->HDisplay >>= 1;
0407           mode->HSyncStart >>= 1;
0408           mode->HTotal >>= 1;
0409           mode->HSyncEnd >>= 1;
0410           mode->SynthClock >>= 1;
0411           mode->CrtcHAdjusted = TRUE;
0412       }
0413       depthcode += 64;
0414       HDiv2 = 1;
0415   }
0416   if (mode->VTotal >= 1024 ) {
0417       /* For non-interlaced vertical timing >= 1024, the vertical timings */
0418       /* are divided by 2 and VGA CRTC 0x17 bit 2  is set. */
0419       if (!mode->CrtcVAdjusted) {
0420           mode->VDisplay >>= 1;
0421           mode->VSyncStart >>= 1;
0422           mode->VSyncEnd >>= 1;
0423           mode->VTotal >>= 1;
0424           mode->CrtcVAdjusted = TRUE;
0425       }
0426       VDiv2 = 1;
0427   }
0428 
0429   /****************************************************
0430    * Sequential registers
0431    */
0432   fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x00, 0x00);
0433   fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x01, 0x01);
0434   fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x02, 0x0F);
0435   fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x03, 0x00);
0436   fb_cirrus_write_seq_reg(cirrus_board_ptr, 0x04, 0x0E);
0437 
0438   /****************************************************
0439    * CRTC Controller Registers
0440    */
0441   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x00, (mode->HTotal >> 3) - 5 );
0442   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x01, (mode->HDisplay >> 3) - 1);
0443   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x02, (mode->HSyncStart >> 3) - 1);
0444   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x03, ((mode->HSyncEnd >> 3) & 0x1F) | 0x80);
0445   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x04, (mode->HSyncStart >> 3));
0446   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x05,
0447       (((mode->HSyncEnd >> 3) & 0x20 ) << 2 )
0448       | (((mode->HSyncEnd >> 3)) & 0x1F));
0449   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x06, (mode->VTotal - 2) & 0xFF);
0450   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x07,
0451       (((mode->VTotal -2) & 0x100) >> 8 )
0452       | (((mode->VDisplay -1) & 0x100) >> 7 )
0453       | ((mode->VSyncStart & 0x100) >> 6 )
0454       | (((mode->VSyncStart) & 0x100) >> 5 )
0455       | 0x10
0456       | (((mode->VTotal -2) & 0x200)   >> 4 )
0457       | (((mode->VDisplay -1) & 0x200) >> 3 )
0458       | ((mode->VSyncStart & 0x200) >> 2 ));
0459   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x08, 0x00);
0460   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x09, ((mode->VSyncStart & 0x200) >>4) | 0x40);
0461   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0A, 0x00);
0462   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0B, 0x00);
0463   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0C, 0x00);
0464   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0D, 0x00);
0465   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0E, 0x00);
0466   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x0F, 0x00);
0467   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x10, mode->VSyncStart & 0xFF);
0468   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x11, (mode->VSyncEnd & 0x0F) | 0x20);
0469   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x12, (mode->VDisplay -1) & 0xFF);
0470   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x13, 0x00);  /* no interlace */
0471   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x14, 0x00);
0472   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x15, mode->VSyncStart & 0xFF);
0473   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x16, (mode->VSyncStart +1) & 0xFF);
0474 
0475   temp = 0xAF;
0476   if(VDiv2)
0477     temp |= 0x04;
0478   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x17, temp);
0479 
0480   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x18, 0xFF);
0481 
0482   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x1A ,
0483       (((mode->HTotal >> 3) & 0xC0 ) >> 2)
0484       | (((mode->VTotal - 2) & 0x300 ) >> 2));
0485 
0486   width = fb_fix.line_length >> 3;
0487   if (fb_var.bits_per_pixel == 1)
0488     width <<= 2;
0489   if(width >= 0xFF)
0490     printk("FB_CIRRUS: Warning line size over the limit ... reduce bpp or width resolution");
0491   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x13,  width);
0492   /* Offset extension (see CR13) */
0493   temp = fb_cirrus_read_crt_reg( cirrus_board_ptr, 0x1B);
0494   temp &= 0xAF;
0495   temp |= (width >> (3+4)) & 0x10;
0496   temp |= (width >> (3+3)) & 0x40;
0497   temp |= 0x22;
0498   fb_cirrus_write_crt_reg( cirrus_board_ptr, 0x1B,  temp);
0499 
0500   /****************************************************
0501    * Sequential register
0502    * Enable linear mode and high-res packed pixel mode
0503    */
0504   temp = fb_cirrus_read_seq_reg( cirrus_board_ptr, 0x07);
0505   temp &= 0xe0;
0506   switch (depthcode) {
0507   case 1:
0508   case 4:
0509     temp |= 0x10;
0510     break;
0511   case 8:
0512     temp |= 0x11;
0513     break;
0514   case 64+8:
0515   temp |= 0x17;
0516   break;
0517   case 15:
0518     temp |= 0x17;
0519     hdr = 0xC0; /* 5:5:5 Sierra */
0520     break;
0521   case 16:
0522     temp |= 0x17;
0523     hdr = 0xC1; /* 5:6:5 XGA mode */
0524     break;
0525   case 24:
0526     temp |= 0x15;
0527     hdr = 0xC5; /* 8:8:8 16M colors */
0528     break;
0529   case 32:
0530     temp |= 0x19;
0531     hdr = 0xC5; /* 8:8:8 16M colors */
0532     break;
0533   default:
0534     printk("FB_CIRRUS: Cannot Initialize display to requested mode\n");
0535     printk("FB_CIRRUS: returning RTEMS_UNSATISFIED on depthcode %d\n", depthcode);
0536     return RTEMS_UNSATISFIED;
0537   }
0538   fb_cirrus_write_seq_reg( cirrus_board_ptr, 0x07, temp);
0539   /* this just set  packed pixel mode with according bpp */
0540 
0541   /****************************************************
0542    * HDR Register
0543    */
0544   if(hdr > 0)
0545     fb_cirrus_write_hdr_reg( cirrus_board_ptr, hdr);
0546 
0547   /****************************************************
0548    * Graphic Data Controller Registers
0549    */
0550   temp = fb_cirrus_read_gdc_reg( cirrus_board_ptr, 0x12);
0551   if (HDiv2)
0552     temp |= 0x20;
0553   else
0554     temp &= ~0x20;
0555   fb_cirrus_write_gdc_reg( cirrus_board_ptr, 0x12, temp);
0556 
0557   /* Enable high-color modes */
0558   fb_cirrus_write_gdc_reg(cirrus_board_ptr, 0x05, 0x40);
0559 
0560   /* VGA graphics mode */
0561   fb_cirrus_write_gdc_reg(cirrus_board_ptr, 0x06, 0x01);
0562 
0563   return TRUE;
0564 }
0565 
0566 static void
0567 cirrus_prepare_mode( void )
0568 {
0569 
0570   active_mode = &available_modes[CIRRUS_DISPLAY_MODE];
0571 
0572   fb_var.bits_per_pixel = CIRRUS_DEFAULT_BPP;
0573 
0574   fb_var.xres  = active_mode->HDisplay;
0575   fb_var.yres  = active_mode->VDisplay;
0576 
0577   fb_fix.line_length = (fb_var.xres * fb_var.bits_per_pixel + 7) / 8;
0578 
0579   fb_fix.type   = FB_TYPE_PACKED_PIXELS;
0580   fb_fix.visual = FB_VISUAL_TRUECOLOR;
0581 
0582 }
0583 
0584 /*
0585  * fb_cirrus device driver OPEN entry point
0586  */
0587 rtems_device_driver
0588 frame_buffer_open(
0589     rtems_device_major_number  major,
0590     rtems_device_minor_number  minor,
0591     void                      *arg
0592 )
0593 {
0594   int r;
0595   uint32_t smem_start, regs_start;
0596 
0597   if (_Atomic_Flag_test_and_set(&driver_mutex, ATOMIC_ORDER_ACQUIRE) != 0 ) {
0598       printk( "FB_CIRRUS could not lock driver_mutex\n" );
0599 
0600       return RTEMS_UNSATISFIED;
0601   }
0602 
0603   r = cirrus_pci_read(&cirrus_board_info, &smem_start, &regs_start);
0604   if ( r == RTEMS_UNSATISFIED )
0605     return RTEMS_UNSATISFIED;
0606 
0607   fb_fix.smem_start  = (volatile char *)smem_start;
0608   fb_fix.smem_len    = 0x1000000;
0609   cirrus_board_info.reg_base = (void *)regs_start;
0610 
0611   cirrus_prepare_mode();
0612 
0613   cirrus_set_mode( active_mode );
0614 
0615   cirrus_adjust_frame( &cirrus_board_info, 0, 0);
0616 
0617   if (1) {
0618       uint32_t pixmask;
0619       int x, y;
0620 
0621       if(fb_var.bits_per_pixel == 32)
0622         pixmask = 0xffffff;
0623       else
0624         pixmask = (1 << fb_var.bits_per_pixel) - 1;
0625 
0626       printk("FB_CIRRUS: mode set, test patter output\n");
0627 
0628       for(y = 0; y < fb_var.yres; y++) {
0629           for(x = 0; x < fb_var.xres; x++) {
0630               uint32_t color;
0631               char *addr = (char *)fb_fix.smem_start;
0632               addr += y * fb_fix.line_length;
0633               addr += x * fb_var.bits_per_pixel / 8;
0634               color = x & 1 ? 0 : y & 1 ? pixmask & 0x000ff00f : pixmask;
0635               if(y == fb_var.yres - 1) {
0636                   if((x > 0) && (x < fb_var.xres-1))
0637                     color = pixmask & 0x00555555;
0638               }
0639               switch (fb_var.bits_per_pixel) {
0640               case 8:  *(volatile uint8_t*) addr = color;
0641               break;
0642               case 16: *(volatile uint16_t*) addr = color;
0643               break;
0644               case 24: *(volatile uint32_t*) addr =
0645                   (*(volatile uint32_t*) addr & 0xff000000) | color;
0646               break;
0647               case 32: *(volatile uint32_t*) addr = color;
0648               break;
0649               }
0650           }
0651       }
0652   }
0653 
0654   return RTEMS_SUCCESSFUL;
0655 
0656 }
0657 
0658 /*
0659  * fb_cirrus device driver CLOSE entry point
0660  */
0661 rtems_device_driver
0662 frame_buffer_close(
0663     rtems_device_major_number  major,
0664     rtems_device_minor_number  minor,
0665     void                      *arg
0666 )
0667 {
0668   _Atomic_Flag_clear(&driver_mutex, ATOMIC_ORDER_RELEASE);
0669 
0670   /* restore previous state.  for VGA this means return to text mode.
0671    * leave out if graphics hardware has been initialized in
0672    * frame_buffer_initialize() */
0673 
0674   /* VGA text mode */
0675   fb_cirrus_write_gdc_reg(&cirrus_board_info, 0x06, 0x00);
0676 
0677   printk( "FB_CIRRUS: close called.\n" );
0678   return RTEMS_SUCCESSFUL;
0679 }
0680 
0681 /*
0682  * fb_cirrus device driver READ entry point.
0683  */
0684 rtems_device_driver
0685 frame_buffer_read(
0686     rtems_device_major_number  major,
0687     rtems_device_minor_number  minor,
0688     void                      *arg
0689 )
0690 {
0691   rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
0692   rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count;
0693   memcpy(rw_args->buffer, (const void *) (fb_fix.smem_start + rw_args->offset), rw_args->bytes_moved);
0694   return RTEMS_SUCCESSFUL;
0695 }
0696 
0697 /*
0698  * frame_buffer device driver WRITE entry point.
0699  */
0700 rtems_device_driver
0701 frame_buffer_write(
0702     rtems_device_major_number  major,
0703     rtems_device_minor_number  minor,
0704     void                      *arg
0705 )
0706 {
0707   rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
0708   rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? (fb_fix.smem_len - rw_args->offset) : rw_args->count;
0709   memcpy( (void *) (fb_fix.smem_start + rw_args->offset), rw_args->buffer, rw_args->bytes_moved);
0710   return RTEMS_SUCCESSFUL;
0711 }
0712 
0713 static int
0714 get_fix_screen_info( struct fb_fix_screeninfo *info )
0715 {
0716   *info = fb_fix;
0717   return 0;
0718 }
0719 
0720 static int
0721 get_var_screen_info( struct fb_var_screeninfo *info )
0722 {
0723   *info =  fb_var;
0724   return 0;
0725 }
0726 
0727 /*
0728  * IOCTL entry point -- This method is called to carry
0729  * all services of this interface.
0730  */
0731 rtems_device_driver
0732 frame_buffer_control(
0733     rtems_device_major_number  major,
0734     rtems_device_minor_number  minor,
0735     void                      *arg
0736 )
0737 {
0738   rtems_libio_ioctl_args_t *args = arg;
0739 
0740   printk( "FB_CIRRUS ioctl called, cmd=%x\n", args->command  );
0741 
0742   switch( args->command ) {
0743   case FBIOGET_FSCREENINFO:
0744     args->ioctl_return =  get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer );
0745     break;
0746   case FBIOGET_VSCREENINFO:
0747     args->ioctl_return =  get_var_screen_info( ( struct fb_var_screeninfo * ) args->buffer );
0748     break;
0749   case FBIOPUT_VSCREENINFO:
0750     /* not implemented yet */
0751     args->ioctl_return = -1;
0752     return RTEMS_UNSATISFIED;
0753   case FBIOGETCMAP:
0754     /* no palette - truecolor mode */
0755     args->ioctl_return = -1;
0756     return RTEMS_UNSATISFIED;
0757   case FBIOPUTCMAP:
0758     /* no palette - truecolor mode */
0759     args->ioctl_return = -1;
0760     return RTEMS_UNSATISFIED;
0761   default:
0762     args->ioctl_return = 0;
0763     break;
0764   }
0765   return RTEMS_SUCCESSFUL;
0766 }