~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/video/sa1100fb.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/drivers/video/sa1100fb.c -- StrongARM 1100 LCD Controller Frame Buffer Device
  3  *
  4  *  Copyright (C) 1999 Eric A. Thomas
  5  *  
  6  * This file is subject to the terms and conditions of the GNU General Public
  7  * License.  See the file COPYING in the main directory of this archive
  8  * for more details.
  9  *
 10  */
 11 
 12 
 13 /*
 14  *   Code Status:
 15  * 1999/04/01:
 16  *      Driver appears to be working for Brutus 320x200x8bpp mode.  Other
 17  *      resolutions are working, but only the 8bpp mode is supported.
 18  *      Changes need to be made to the palette encode and decode routines
 19  *      to support 4 and 16 bpp modes.  
 20  *      Driver is not designed to be a module.  The FrameBuffer is statically
 21  *      allocated since dynamic allocation of a 300k buffer cannot be 
 22  *      guaranteed. 
 23  * 
 24  * 1999/06/17:
 25  *      FrameBuffer memory is now allocated at run-time when the
 26  *      driver is initialized.    
 27  *
 28  * 2000/04/10:
 29  *      Big cleanup for dynamic selection of machine type at run time.
 30  *              Nicolas Pitre <nico@cam.org>
 31  * 
 32  * 2000/07/19:
 33  *      Support for Bitsy aka Compaq iPAQ H3600 added.
 34  *              Jamey Hicks <jamey@crl.dec.com>
 35  * 
 36  * 2000/08/07:
 37  *      Resolved an issue caused by a change made to the Assabet's PLD 
 38  *      earlier this year which broke the framebuffer driver for newer 
 39  *      Phase 4 Assabets.  Some other parameters were changed to optimize for
 40  *      the Sharp display.
 41  *              Tak-Shing Chan <tchan.rd@idthk.com>
 42  *              Jeff Sutherland <jsutherland@accelent.com>
 43  * 
 44  * 2000/08/09:
 45  *      XP860 support added
 46  *              Kunihiko IMAI <imai@vasara.co.jp>
 47  *
 48  * 2000/08/19:
 49  *      Allows standard options to be passed on the kernel command line
 50  *      for most common passive displays.
 51  *              Mark Huang <mhuang@livetoy.com>
 52  *
 53  * 2000/08/29:
 54  *      s/save_flags_cli/local_irq_save/
 55  *      remove unneeded extra save_flags_cli in
 56  *       sa1100fb_enable_lcd_controller
 57  */
 58 
 59 #include <linux/config.h>
 60 #include <linux/module.h>
 61 #include <linux/kernel.h>
 62 #include <linux/sched.h>
 63 #include <linux/errno.h>
 64 #include <linux/string.h>
 65 #include <linux/ctype.h>
 66 #include <linux/mm.h>
 67 #include <linux/tty.h>
 68 #include <linux/malloc.h>
 69 #include <linux/init.h>
 70 #include <linux/fb.h>
 71 #include <linux/delay.h>
 72 #include <linux/wrapper.h>
 73 
 74 #include <asm/hardware.h>
 75 #include <asm/io.h>
 76 #include <asm/irq.h>
 77 #include <asm/mach-types.h>
 78 #include <asm/uaccess.h>
 79 #include <asm/proc/pgtable.h>
 80 
 81 #include <video/fbcon.h>
 82 #include <video/fbcon-mfb.h>
 83 #include <video/fbcon-cfb4.h>
 84 #include <video/fbcon-cfb8.h>
 85 #include <video/fbcon-cfb16.h>
 86 
 87 
 88 /*
 89  *  Debug macros 
 90  */
 91 //#define DEBUG 
 92 #ifdef DEBUG
 93 #  define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
 94 #else
 95 #  define DPRINTK(fmt, args...)
 96 #endif
 97 
 98 
 99 /* Memory size macros for determining required FrameBuffer size */
100 #define MAX_PALETTE_NUM_ENTRIES         256
101 #define MAX_PALETTE_MEM_SIZE            (MAX_PALETTE_NUM_ENTRIES * 2)
102 #define MAX_PIXEL_MEM_SIZE \
103         ((current_par.max_xres * current_par.max_yres * current_par.max_bpp)/8)
104 #define MAX_FRAMEBUFFER_MEM_SIZE \
105         (MAX_PIXEL_MEM_SIZE + MAX_PALETTE_MEM_SIZE + 32)
106 #define ALLOCATED_FB_MEM_SIZE \
107         (PAGE_ALIGN(MAX_FRAMEBUFFER_MEM_SIZE + PAGE_SIZE * 2))
108 
109 #define SA1100_PALETTE_MEM_SIZE(bpp)    (((bpp)==8?256:16)*2)
110 #define SA1100_PALETTE_MODE_VAL(bpp)    (((bpp) & 0x018) << 9)
111 
112 /* Minimum X and Y resolutions */
113 #define MIN_XRES        64
114 #define MIN_YRES        64
115 
116 /* Possible controller_state modes */
117 #define LCD_MODE_DISABLED               0    // Controller is disabled and Disable Done received
118 #define LCD_MODE_DISABLE_BEFORE_ENABLE  1    // Re-enable after Disable Done IRQ is received
119 #define LCD_MODE_ENABLED                2    // Controller is enabled
120 
121 #define SA1100_NAME     "SA1100"
122 #define NR_MONTYPES     1
123 
124 static inline void
125 sa1100fb_assabet_set_truecolor(u_int is_true_color)
126 {
127 #ifdef CONFIG_SA1100_ASSABET
128 #if 1
129         // phase 4 or newer Assabet's
130         if (is_true_color)
131                 BCR_set(BCR_LCD_12RGB);
132         else
133                 BCR_clear(BCR_LCD_12RGB);
134 #else
135         // older Assabet's
136         if (is_true_color)
137                 BCR_clear(BCR_LCD_12RGB);
138         else
139                 BCR_set(BCR_LCD_12RGB);
140 #endif
141 #endif
142 }
143 
144 static u_char *VideoMemRegion;
145 static u_char *VideoMemRegion_phys;
146 
147 /* Local LCD controller parameters */
148 /* These can be reduced by making better use of fb_var_screeninfo parameters.  */
149 /* Several duplicates exist in the two structures. */
150 struct sa1100fb_par {
151         u_char          *p_screen_base;
152         u_char          *v_screen_base;
153         u_short         *p_palette_base;
154         u_short         *v_palette_base;
155         unsigned long   screen_size;
156         unsigned int    palette_size;
157         unsigned int    max_xres;
158         unsigned int    max_yres;
159         unsigned int    xres;
160         unsigned int    yres;
161         unsigned int    xres_virtual;
162         unsigned int    yres_virtual;
163         unsigned int    max_bpp;
164         unsigned int    bits_per_pixel;
165           signed int    montype;
166         unsigned int    currcon;
167         unsigned int    visual;
168         unsigned int    allow_modeset : 1;
169         unsigned int    active_lcd : 1;
170         unsigned int    inv_4bpp : 1;
171         volatile u_char controller_state;
172 };
173 
174 /* Shadows for LCD controller registers */
175 struct sa1100fb_lcd_reg {
176         Address dbar1;
177         Address dbar2;
178         Word    lccr0;
179         Word    lccr1;
180         Word    lccr2;
181         Word    lccr3;
182 };
183 
184 /* Fake monspecs to fill in fbinfo structure */
185 static struct fb_monspecs monspecs __initdata = {
186          30000, 70000, 50, 65, 0        /* Generic */
187 };
188 
189 static struct display global_disp;      /* Initial (default) Display Settings */
190 static struct fb_info fb_info;
191 static struct sa1100fb_par current_par;
192 static struct fb_var_screeninfo __initdata init_var = {};
193 static struct sa1100fb_lcd_reg lcd_shadow;
194 
195 
196 static int  sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);
197 static int  sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
198 static int  sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
199 static int  sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
200 static int  sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
201  
202 static int  sa1100fb_switch(int con, struct fb_info *info);
203 static void sa1100fb_blank(int blank, struct fb_info *info);
204 static int  sa1100fb_map_video_memory(void);
205 static int  sa1100fb_activate_var(struct fb_var_screeninfo *var);
206 static void sa1100fb_enable_lcd_controller(void);
207 static void sa1100fb_disable_lcd_controller(void);
208 
209 static struct fb_ops sa1100fb_ops = {
210         owner:          THIS_MODULE,
211         fb_get_fix:     sa1100fb_get_fix,
212         fb_get_var:     sa1100fb_get_var,
213         fb_set_var:     sa1100fb_set_var,
214         fb_get_cmap:    sa1100fb_get_cmap,
215         fb_set_cmap:    sa1100fb_set_cmap,
216 };
217 
218 
219 /*
220  * sa1100fb_palette_write:
221  *    Write palette data to the LCD frame buffer's palette area
222  */
223 static inline void
224 sa1100fb_palette_write(u_int regno, u_short pal)
225 {
226         current_par.v_palette_base[regno] = (regno ? pal : pal | 
227                                              SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel));
228 }
229 
230 
231 static inline u_short
232 sa1100fb_palette_encode(u_int regno, u_int red, u_int green, u_int blue, u_int trans)
233 {
234         u_int pal;
235 
236         if(current_par.bits_per_pixel == 4){
237                 /*
238                  * RGB -> luminance is defined to be
239                  * Y =  0.299 * R + 0.587 * G + 0.114 * B
240                  */
241                 pal = (19595 * red + 38470 * green + 7471 * blue) >> 28;
242                 if( current_par.inv_4bpp )
243                         pal = 15 - pal;
244         }
245         else{
246                 pal   = ((red   >>  4) & 0xf00);
247                 pal  |= ((green >>  8) & 0x0f0);
248                 pal  |= ((blue  >> 12) & 0x00f);
249         }
250 
251         return pal;
252 }
253             
254 static inline u_short
255 sa1100fb_palette_read(u_int regno)
256 {
257         return (current_par.v_palette_base[regno] & 0x0FFF);
258 }
259 
260 
261 static void
262 sa1100fb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans)
263 {
264         u_short pal;
265 
266         pal = sa1100fb_palette_read(regno);
267 
268         if( current_par.bits_per_pixel == 4){
269                 if( current_par.inv_4bpp )
270                         pal = 15 - pal;
271                 pal &= 0x000f;
272                 pal |= pal << 4;
273                 pal |= pal << 8;
274                 *blue = *green = *red = pal;
275         }
276         else{
277                 *blue   = (pal & 0x000f) << 12;
278                 *green  = (pal & 0x00f0) << 8;
279                 *red    = (pal & 0x0f00) << 4;
280         }
281         *trans  = 0;
282 }
283 
284 static int
285 sa1100fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info)
286 {
287         if (regno >= current_par.palette_size)
288                 return 1;
289         
290         sa1100fb_palette_decode(regno, red, green, blue, trans);
291 
292         return 0;
293 }
294 
295 
296 static int
297 sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info)
298 {
299         u_short pal;
300 
301         if (regno >= current_par.palette_size)
302                 return 1;
303 
304         pal = sa1100fb_palette_encode(regno, red, green, blue, trans);
305 
306         sa1100fb_palette_write(regno, pal);
307 
308         return 0;
309 }
310 
311 static int
312 sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
313                  struct fb_info *info)
314 {
315         int err = 0;
316 
317         DPRINTK("current_par.visual=%d\n", current_par.visual);
318         if (con == current_par.currcon)
319                 err = fb_get_cmap(cmap, kspc, sa1100fb_getcolreg, info);
320         else if (fb_display[con].cmap.len)
321                 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
322         else
323                 fb_copy_cmap(fb_default_cmap(current_par.palette_size),
324                              cmap, kspc ? 0 : 2);
325         return err;
326 }
327 
328 static int
329 sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
330                   struct fb_info *info)
331 {
332         int err = 0;
333 
334         DPRINTK("current_par.visual=%d\n", current_par.visual);
335         if (!fb_display[con].cmap.len)
336                 err = fb_alloc_cmap(&fb_display[con].cmap,
337                                     current_par.palette_size, 0);
338         if (!err) {
339                 if (con == current_par.currcon)
340                         err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg,
341                                           info);
342                 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
343         }
344         return err;
345 }
346 
347 static void inline
348 sa1100fb_get_par(struct sa1100fb_par *par)
349 {
350         *par = current_par;
351 }
352 
353 
354 /*
355  * sa1100fb_encode_var():
356  *      Modify var structure using values in par
357  */
358 static int 
359 sa1100fb_encode_var(struct fb_var_screeninfo *var,
360                     struct sa1100fb_par *par)
361 {
362         // Don't know if really want to zero var on entry.
363         // Look at set_var to see.  If so, may need to add extra params to par     
364 //      memset(var, 0, sizeof(struct fb_var_screeninfo));
365  
366         var->xres = par->xres;
367         var->yres = par->yres;
368         var->xres_virtual = par->xres_virtual;
369         var->yres_virtual = par->yres_virtual;
370 
371         var->bits_per_pixel = par->bits_per_pixel;
372 
373         DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
374         switch(var->bits_per_pixel) {
375         case 2:
376         case 4:
377         case 8:
378                 var->red.length    = 4;
379                 var->green         = var->red;
380                 var->blue          = var->red;
381                 var->transp.length = 0;
382                 break;
383         case 12:          // This case should differ for Active/Passive mode  
384         case 16:
385                 if (machine_is_bitsy()) {
386                         var->red.length    = 4;
387                         var->blue.length   = 4;
388                         var->green.length  = 4;
389                         var->transp.length = 0;
390                         var->red.offset    = 12;
391                         var->green.offset  = 7;
392                         var->blue.offset   = 1;
393                         var->transp.offset = 0;
394                 } else {
395                         var->red.length    = 5;
396                         var->blue.length   = 5;
397                         var->green.length  = 6;
398                         var->transp.length = 0;
399                         var->red.offset    = 11;
400                         var->green.offset  = 5;
401                         var->blue.offset   = 0;
402                         var->transp.offset = 0;
403                 }
404                 break;
405         }
406         return 0;
407 }
408  
409 /*
410  *  sa1100fb_decode_var():
411  *    Get the video params out of 'var'. If a value doesn't fit, round it up,
412  *    if it's too big, return -EINVAL.
413  *
414  *    Suggestion: Round up in the following order: bits_per_pixel, xres,
415  *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
416  *    bitfields, horizontal timing, vertical timing.
417  */
418 static int
419 sa1100fb_decode_var(struct fb_var_screeninfo *var, 
420                     struct sa1100fb_par *par)
421 {
422         u_long palette_mem_phys;
423         u_long palette_mem_size;
424 
425         *par = current_par;
426 
427         if ((par->xres = var->xres) < MIN_XRES)
428                 par->xres = MIN_XRES; 
429         if ((par->yres = var->yres) < MIN_YRES)
430                 par->yres = MIN_YRES;
431         if (par->xres > current_par.max_xres)
432                 par->xres = current_par.max_xres;
433         if (par->yres > current_par.max_yres)
434                 par->yres = current_par.max_yres; 
435         par->xres_virtual = 
436                 var->xres_virtual < par->xres ? par->xres : var->xres_virtual;
437         par->yres_virtual = 
438                 var->yres_virtual < par->yres ? par->yres : var->yres_virtual;
439         par->bits_per_pixel = var->bits_per_pixel;
440 
441         DPRINTK("par->bits_per_pixel=%d\n", par->bits_per_pixel);
442         switch (par->bits_per_pixel) {
443 #ifdef FBCON_HAS_CFB4
444         case 4:
445                 par->visual = FB_VISUAL_PSEUDOCOLOR;
446                 par->palette_size = 16; 
447                 break;
448 #endif
449 #ifdef FBCON_HAS_CFB8
450         case 8:
451                 par->visual = FB_VISUAL_PSEUDOCOLOR;
452                 par->palette_size = 256; 
453                 break;
454 #endif
455 #ifdef FBCON_HAS_CFB16
456         case 16:  /* RGB 565 */
457                 par->visual = FB_VISUAL_TRUECOLOR;
458                 par->palette_size = 0; 
459                 break;
460 #endif
461         default:
462                 return -EINVAL;
463         }
464 
465         palette_mem_size = SA1100_PALETTE_MEM_SIZE(par->bits_per_pixel);
466         palette_mem_phys = (u_long)VideoMemRegion_phys + PAGE_SIZE - palette_mem_size;
467         par->p_palette_base = (u_short *)palette_mem_phys;
468         par->v_palette_base = (u_short *)((u_long)VideoMemRegion + PAGE_SIZE - palette_mem_size);
469         par->p_screen_base  = (u_char *)((u_long)VideoMemRegion_phys + PAGE_SIZE); 
470         par->v_screen_base  = (u_char *)((u_long)VideoMemRegion      + PAGE_SIZE); 
471 
472         DPRINTK("p_palette_base = 0x%08lx\n",(u_long)par->p_palette_base);
473         DPRINTK("v_palette_base = 0x%08lx\n",(u_long)par->v_palette_base);
474         DPRINTK("palette_size = 0x%08lx\n",(u_long)par->palette_size);
475         DPRINTK("palette_mem_size = 0x%08lx\n",(u_long)palette_mem_size);
476         DPRINTK("p_screen_base  = 0x%08lx\n",(u_long)par->p_screen_base);
477         DPRINTK("v_screen_base  = 0x%08lx\n",(u_long)par->v_screen_base);
478         DPRINTK("VideoMemRegion = 0x%08lx\n",(u_long)VideoMemRegion);
479         DPRINTK("VideoMemRegion_phys = 0x%08lx\n",(u_long)VideoMemRegion_phys);
480 
481         return 0;
482 }
483 
484 static int
485 sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
486 {
487         struct sa1100fb_par par;
488 
489         DPRINTK("con=%d\n", con);
490         if (con == -1) {
491                 sa1100fb_get_par(&par);
492                 sa1100fb_encode_var(var, &par);
493         } else
494                 *var = fb_display[con].var;
495 
496         return 0;
497 }
498 
499 /*
500  * sa1100fb_set_var():
501  *      Set the user defined part of the display for the specified console
502  */
503 static int
504 sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
505 {
506         struct display *display;
507         int err, chgvar = 0;
508         struct sa1100fb_par par;
509 
510         if (con >= 0)
511                 display = &fb_display[con]; /* Display settings for console */
512         else
513                 display = &global_disp;     /* Default display settings */
514 
515         /* Decode var contents into a par structure, adjusting any */
516         /* out of range values. */
517         if ((err = sa1100fb_decode_var(var, &par)))
518                 return err;
519         // Store adjusted par values into var structure
520         sa1100fb_encode_var(var, &par);
521        
522         if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
523                 return 0;
524         else if (((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) && 
525                  ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NXTOPEN))
526                 return -EINVAL;
527 
528         if (con >= 0) {
529                 if ((display->var.xres != var->xres) ||
530                     (display->var.yres != var->yres) ||
531                     (display->var.xres_virtual != var->xres_virtual) ||
532                     (display->var.yres_virtual != var->yres_virtual) ||
533                     (display->var.sync != var->sync)                 ||
534                     (display->var.bits_per_pixel != var->bits_per_pixel) ||
535                     (memcmp(&display->var.red, &var->red, sizeof(var->red))) ||
536                     (memcmp(&display->var.green, &var->green, sizeof(var->green))) ||
537                     (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))) 
538                         chgvar = 1;
539         }
540 
541         display->var = *var;
542         display->screen_base    = par.v_screen_base;
543         display->visual         = par.visual;
544         display->type           = FB_TYPE_PACKED_PIXELS;
545         display->type_aux       = 0;
546         display->ypanstep       = 0;
547         display->ywrapstep      = 0;
548         display->line_length    = 
549         display->next_line      = (var->xres * var->bits_per_pixel) / 8;
550 
551         display->can_soft_blank = 1;
552         display->inverse        = 0;
553 
554         switch (display->var.bits_per_pixel) {
555 #ifdef FBCON_HAS_CFB4
556         case 4:
557                 display->dispsw = &fbcon_cfb4;
558                 break;
559 #endif
560 #ifdef FBCON_HAS_CFB8
561         case 8: 
562                 display->dispsw = &fbcon_cfb8;
563                 break;
564 #endif
565 #ifdef FBCON_HAS_CFB16
566         case 16:
567                 display->dispsw = &fbcon_cfb16;
568                 break;
569 #endif
570         default:
571                 display->dispsw = &fbcon_dummy;
572                 break;
573         }
574 
575         /* If the console has changed and the console has defined */
576         /* a changevar function, call that function. */
577         if (chgvar && info && info->changevar)
578                 info->changevar(con);
579 
580         /* If the current console is selected and it's not truecolor, 
581          *  update the palette 
582          */
583         if ((con == current_par.currcon) &&
584             (current_par.visual != FB_VISUAL_TRUECOLOR)) {
585                 struct fb_cmap *cmap;
586                 
587                 current_par = par;
588                 if (display->cmap.len)
589                         cmap = &display->cmap;
590                 else
591                         cmap = fb_default_cmap(current_par.palette_size);
592 
593                 fb_set_cmap(cmap, 1, sa1100fb_setcolreg, info);
594         }
595 
596         /* If the current console is selected, activate the new var. */
597         if (con == current_par.currcon)
598                 sa1100fb_activate_var(var);
599         
600         return 0;
601 }
602 
603 static int
604 sa1100fb_updatevar(int con, struct fb_info *info)
605 {
606         DPRINTK("entered\n");
607         return 0;
608 }
609 
610 static int
611 sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
612 {
613         struct display *display;
614 
615         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
616         strcpy(fix->id, SA1100_NAME);
617 
618         if (con >= 0)
619         {
620                 DPRINTK("Using console specific display for con=%d\n",con);
621                 display = &fb_display[con];  /* Display settings for console */
622         }
623         else
624                 display = &global_disp;      /* Default display settings */
625 
626         fix->smem_start  = (unsigned long)current_par.p_screen_base;
627         fix->smem_len    = current_par.screen_size;
628         fix->type        = display->type;
629         fix->type_aux    = display->type_aux;
630         fix->xpanstep    = 0;
631         fix->ypanstep    = display->ypanstep;
632         fix->ywrapstep   = display->ywrapstep;
633         fix->visual      = display->visual;
634         fix->line_length = display->line_length;
635         fix->accel       = FB_ACCEL_NONE;
636 
637         return 0;
638 }
639 
640 
641 static void
642 __init sa1100fb_init_fbinfo(void)
643 {
644         strcpy(fb_info.modename, SA1100_NAME);
645         strcpy(fb_info.fontname, "Acorn8x8");
646 
647         fb_info.node            = -1;
648         fb_info.flags           = FBINFO_FLAG_DEFAULT;
649         fb_info.fbops           = &sa1100fb_ops;
650         fb_info.monspecs        = monspecs;
651         fb_info.disp            = &global_disp;
652         fb_info.changevar       = NULL;
653         fb_info.switch_con      = sa1100fb_switch;
654         fb_info.updatevar       = sa1100fb_updatevar;
655         fb_info.blank           = sa1100fb_blank;
656 
657         /*
658          * setup initial parameters
659          */
660         memset(&init_var, 0, sizeof(init_var));
661 
662         init_var.transp.length  = 0;
663         init_var.nonstd         = 0;
664         init_var.activate       = FB_ACTIVATE_NOW;
665         init_var.xoffset        = 0;
666         init_var.yoffset        = 0;
667         init_var.height         = -1;
668         init_var.width          = -1;
669         init_var.vmode          = FB_VMODE_NONINTERLACED;
670 
671         if (machine_is_assabet()) {
672                 current_par.max_xres    = 320;
673                 current_par.max_yres    = 240;
674                 current_par.max_bpp     = 16;
675                 init_var.red.length     = 5;                            
676                 init_var.green.length   = 6;
677                 init_var.blue.length    = 5;
678                 init_var.grayscale      = 0;
679                 init_var.sync           = 0;
680                 init_var.pixclock       = 171521;
681         } else if (machine_is_cerf()) {
682                 current_par.max_xres    = 320;
683                 current_par.max_yres    = 240;
684                 current_par.max_bpp     = 8;
685                 init_var.red.length     = 4;                            
686                 init_var.green.length   = 4;
687                 init_var.blue.length    = 4;
688                 init_var.grayscale      = 0;
689                 init_var.sync           = 0;
690                 init_var.pixclock       = 171521;
691         } else if (machine_is_bitsy()) {
692                 current_par.max_xres    = 320;
693                 current_par.max_yres    = 240;
694                 current_par.max_bpp     = 16;
695                 init_var.red.length     = 4;
696                 init_var.green.length   = 4;
697                 init_var.blue.length    = 4;
698                 init_var.red.offset     = 12;
699                 init_var.green.offset   = 7;
700                 init_var.blue.offset    = 1;
701                 init_var.grayscale      = 0;
702         } else if (machine_is_brutus()) {
703                 current_par.max_xres    = 320;
704                 current_par.max_yres    = 240;
705                 current_par.max_bpp     = 8;
706                 init_var.red.length     = 4;                            
707                 init_var.green          = init_var.red;
708                 init_var.blue           = init_var.red;
709                 init_var.sync           = 0;
710         } else if (machine_is_lart()) {
711                 current_par.max_xres    = 320;
712                 current_par.max_yres    = 240;
713                 current_par.max_bpp     = 4;
714                 init_var.red.length     = 4;                            
715                 init_var.green          = init_var.red;
716                 init_var.blue           = init_var.red;
717                 init_var.grayscale      = 1;
718                 init_var.pixclock       = 150000;       
719                 init_var.sync           = 0;
720         } else if (machine_is_penny()) {
721                 current_par.max_xres    = 640;
722                 current_par.max_yres    = 480;
723                 current_par.max_bpp     = 8;
724                 init_var.red.length     = 4;                            
725                 init_var.green          = init_var.red;
726                 init_var.blue           = init_var.red;
727                 init_var.sync           = 0;
728         } else if (machine_is_thinclient() || machine_is_graphicsclient()) {
729                 current_par.max_xres    = 640;
730                 current_par.max_yres    = 480;
731                 current_par.max_bpp     = 8;
732                 init_var.red.length     = 4;                            
733                 init_var.green          = init_var.red;
734                 init_var.blue           = init_var.red;
735                 init_var.sync           = 0;
736         } else if (machine_is_tifon()) {
737                 current_par.max_xres    = 640;
738                 current_par.max_yres    = 200;
739                 current_par.max_bpp     = 4;
740                 current_par.inv_4bpp    = 1;
741                 init_var.red.length     = 4;                            
742                 init_var.green          = init_var.red;
743                 init_var.blue           = init_var.red;
744                 init_var.grayscale      = 1;
745                 init_var.pixclock       = 150000;       
746                 init_var.left_margin    = 20;
747                 init_var.right_margin   = 255;
748                 init_var.upper_margin   = 20;
749                 init_var.lower_margin   = 0;
750                 init_var.hsync_len      = 2;
751                 init_var.vsync_len      = 1;
752                 init_var.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
753                 init_var.vmode          = 0;
754         } else if (machine_is_xp860()) {
755                 current_par.max_xres    = 1024;
756                 current_par.max_yres    = 768;
757 
758                 current_par.max_bpp     = 8;
759                 init_var.red.length     = 4;
760                 init_var.green          = init_var.red;
761                 init_var.blue           = init_var.red;
762 
763                 init_var.hsync_len      = 4;
764                 init_var.left_margin    = 3;
765                 init_var.right_margin   = 2;
766 
767                 init_var.vsync_len      = 3;
768                 init_var.upper_margin   = 2;
769                 init_var.lower_margin   = 1;
770                 
771         }
772 
773         current_par.p_palette_base      = NULL;
774         current_par.v_palette_base      = NULL;
775         current_par.p_screen_base       = NULL;
776         current_par.v_screen_base       = NULL;
777         current_par.palette_size        = MAX_PALETTE_NUM_ENTRIES;
778         current_par.screen_size         = MAX_PIXEL_MEM_SIZE;
779         current_par.montype             = -1;
780         current_par.currcon             = -1;
781         current_par.allow_modeset       =  1;
782         current_par.controller_state    = LCD_MODE_DISABLED;
783 
784         init_var.xres                   = current_par.max_xres;
785         init_var.yres                   = current_par.max_yres;
786         init_var.xres_virtual           = init_var.xres;
787         init_var.yres_virtual           = init_var.yres;
788         init_var.bits_per_pixel         = current_par.max_bpp;
789                         
790 }
791 
792 
793 
794 /*
795  * sa1100fb_map_video_memory():
796  *      Allocates the DRAM memory for the frame buffer.  This buffer is  
797  *      remapped into a non-cached, non-buffered, memory region to  
798  *      allow palette and pixel writes to occur without flushing the 
799  *      cache.  Once this area is remapped, all virtual memory
800  *      access to the video memory should occur at the new region.
801  */
802 static int
803 __init sa1100fb_map_video_memory(void)
804 {
805         u_int  required_pages;
806         u_int  extra_pages;
807         u_int  order;
808         struct page *page;
809         char   *allocated_region;
810 
811         if (VideoMemRegion != NULL)
812                 return -EINVAL;
813 
814         DPRINTK("-1-");
815 
816         /* Find order required to allocate enough memory for framebuffer */
817         required_pages = ALLOCATED_FB_MEM_SIZE >> PAGE_SHIFT;
818         for (order = 0 ; required_pages >> order ; order++) {;}
819         extra_pages = (1 << order) - required_pages;
820 
821         if ((allocated_region = 
822              (char *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)) == NULL)
823            return -ENOMEM;
824 
825         VideoMemRegion = (u_char *)allocated_region + (extra_pages << PAGE_SHIFT); 
826         VideoMemRegion_phys = (u_char *)__virt_to_phys((u_long)VideoMemRegion);
827 
828         /* Free all pages that we don't need but were given to us because */
829         /* __get_free_pages() works on powers of 2. */
830         for (;extra_pages;extra_pages--)
831           free_page((u_int)allocated_region + ((extra_pages-1) << PAGE_SHIFT));
832 
833         /* Set reserved flag for fb memory to allow it to be remapped into */
834         /* user space by the common fbmem driver using remap_page_range(). */
835         for(page = virt_to_page(VideoMemRegion); 
836             page < virt_to_page(VideoMemRegion + ALLOCATED_FB_MEM_SIZE); page++)
837           mem_map_reserve(page);
838 
839         /* Remap the fb memory to a non-buffered, non-cached region */
840         VideoMemRegion = (u_char *)__ioremap((u_long)VideoMemRegion_phys,
841                                              ALLOCATED_FB_MEM_SIZE,
842                                              L_PTE_PRESENT  |
843                                              L_PTE_YOUNG    |
844                                              L_PTE_DIRTY    |
845                                              L_PTE_WRITE);
846         return (VideoMemRegion == NULL ? -EINVAL : 0);
847 }
848 
849 static const int frequency[16] = {
850         59000000,
851         73700000,
852         88500000,
853         103200000,
854         118000000,
855         132700000,
856         147500000,
857         162200000,
858         176900000,
859         191700000,
860         206400000, 
861         230000000,
862         245000000,
863         260000000,
864         275000000,
865         290000000
866 };
867 
868 
869 static inline int get_pcd(unsigned int pixclock)
870 {
871         unsigned int pcd = 0;
872 
873         if (machine_is_tifon()) {
874                 pcd = frequency[PPCR &0xf] / 1000;
875                 pcd *= pixclock/1000;
876                 pcd = pcd / 10000000 * 12;
877                 /* the last multiplication by 1.2 is to handle */
878                 /* sync problems */
879         }
880         if (machine_is_assabet()) {
881                 pcd = frequency[PPCR & 0xf] / 1000;
882                 pcd *= pixclock / 1000;
883                 pcd = pcd / 1000000;
884                 pcd++; /* make up for integer math truncations */
885         }
886         return pcd;
887 }
888 
889 
890 /*
891  * sa1100fb_activate_var():
892  *      Configures LCD Controller based on entries in var parameter.  Settings are      
893  *      only written to the controller if changes were made.  
894  */
895 static int
896 sa1100fb_activate_var(struct fb_var_screeninfo *var)
897 {                                                      
898         u_long  flags;
899         int pcd = get_pcd(var->pixclock);
900 
901         DPRINTK("Configuring  SA1100 LCD\n");
902 
903         if (current_par.p_palette_base == NULL)
904                 return -EINVAL;
905 
906         DPRINTK("activating\n");
907 
908         /* Disable interrupts and save status */
909         local_irq_save(flags);          // disable the interrupts and save flags
910 
911         /* Reset the LCD Controller's DMA address if it has changed */
912         lcd_shadow.dbar1 = (Address)current_par.p_palette_base;
913         lcd_shadow.dbar2 = (Address)(current_par.p_screen_base + (current_par.xres * current_par.yres * current_par.bits_per_pixel / 8 / 2));
914 
915         DPRINTK("Configuring xres = %d, yres = %d\n",var->xres, var->yres);
916 
917         if (machine_is_assabet()) {
918                 DPRINTK("Configuring  Assabet LCD\n");
919                 lcd_shadow.lccr0 = 
920                         LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + 
921                         LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Act +
922                         LCCR0_LtlEnd + LCCR0_DMADel(0);
923                 lcd_shadow.lccr1 = 
924                         LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) + 
925                         LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
926                 lcd_shadow.lccr2 = 
927                         LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + 
928                         LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
929                 lcd_shadow.lccr3 = 
930                         LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + 
931                         LCCR3_HorSnchH + LCCR3_ACBsCntOff + 
932                         LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd);
933 
934                 /* Set board control register to handle new color depth */
935                 sa1100fb_assabet_set_truecolor(var->bits_per_pixel >= 16);
936         } else if (machine_is_bitsy()) {
937                 DPRINTK("Configuring  Bitsy LCD\n");
938                 lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
939                                    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
940                                    LCCR0_DMADel(0);
941                 lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) +
942                                    LCCR1_HorSnchWdth( 4 ) +
943                                    LCCR1_BegLnDel( 0xC ) +
944                                    LCCR1_EndLnDel( 0x11 );
945                 lcd_shadow.lccr2 = LCCR2_DisHght( var->yres + 1 ) +
946                                    LCCR2_VrtSnchWdth( 3 )+
947                                    LCCR2_BegFrmDel( 10 ) +
948                                    LCCR2_EndFrmDel( 1 );
949                 lcd_shadow.lccr3 = (/* PCD */ 0x10
950                                     | /* ACB */ 0
951                                     | /* API */ 0
952                                     | LCCR3_VrtSnchL
953                                     | LCCR3_HorSnchL);
954         } else if (machine_is_brutus()) {
955                 DPRINTK("Configuring  Brutus LCD\n");
956                 lcd_shadow.lccr0 = 
957                         LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas + 
958                         LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
959                         LCCR0_DMADel(0);
960                 lcd_shadow.lccr1 = 
961                         LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) + 
962                         LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
963                 lcd_shadow.lccr2 = 
964                         LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + 
965                         LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
966                 lcd_shadow.lccr3 = 
967                         LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + 
968                         LCCR3_HorSnchH + LCCR3_ACBsCntOff + 
969                         LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
970         } else if (machine_is_cerf()) {
971                 DPRINTK("Configuring Cerf LCD\n");
972                 lcd_shadow.lccr0 = 
973                         LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + 
974                         LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
975                         LCCR0_LtlEnd + LCCR0_DMADel(0);
976                 lcd_shadow.lccr1 = 
977                         LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) + 
978                         LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
979                 lcd_shadow.lccr2 = 
980                         LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + 
981                         LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
982                 lcd_shadow.lccr3 = 
983                         LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + 
984                         LCCR3_HorSnchH + LCCR3_ACBsCntOff + 
985                         LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
986         } else if (machine_is_lart()) {
987                 DPRINTK("Configuring LART LCD\n");
988                 lcd_shadow.lccr0 = 
989                         LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
990                         LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
991                         LCCR0_DMADel(0);
992                 lcd_shadow.lccr1 = 
993                         LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(2) +
994                         LCCR1_BegLnDel(4) + LCCR1_EndLnDel(2);
995                 lcd_shadow.lccr2 = 
996                         LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
997                         LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
998                 lcd_shadow.lccr3 = 
999                         LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
1000                         LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH;
1001         } else if (machine_is_penny()) {
1002                 DPRINTK("Configuring  Penny LCD\n");
1003                 lcd_shadow.lccr0 = 
1004                         LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + 
1005                         LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
1006                         LCCR0_DMADel(0); 
1007                 lcd_shadow.lccr1 = 
1008                         LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(65) +
1009                         LCCR1_EndLnDel(43) + LCCR1_BegLnDel(43);
1010                 lcd_shadow.lccr2 = 
1011                         LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(35) + 
1012                         LCCR2_EndFrmDel(0) + LCCR2_BegFrmDel(0);
1013                 lcd_shadow.lccr3 = 
1014                         LCCR3_PixClkDiv(16) + LCCR3_ACBsDiv (2) + LCCR3_ACBsCntOff +
1015                         ((var->sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HorSnchH : LCCR3_HorSnchL) +
1016                         ((var->sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
1017         } else if (machine_is_thinclient() || machine_is_graphicsclient()) {
1018                 DPRINTK("Configuring ThinClient LCD\n");
1019                 lcd_shadow.lccr0 = 
1020                         LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act;
1021                 lcd_shadow.lccr1 = 
1022                         LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(10) +
1023                         LCCR1_EndLnDel(81) + LCCR1_BegLnDel(81);
1024                 lcd_shadow.lccr2 = 
1025                         LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(9) + 
1026                         LCCR2_EndFrmDel (20) + LCCR2_BegFrmDel(20);
1027                 lcd_shadow.lccr3 = 
1028                         LCCR3_PixClkDiv(6) + LCCR3_ACBsDiv(2) + 
1029                         LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL;
1030         } else if (machine_is_tifon()) {
1031                 DPRINTK("Configuring TIFON LCD\n");
1032                 lcd_shadow.lccr0 = 
1033                         LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
1034                         LCCR0_BigEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + 
1035                         LCCR0_8PixMono + LCCR0_DMADel(0);
1036                 lcd_shadow.lccr1 = 
1037                         LCCR1_DisWdth(var->xres) + 
1038                         LCCR1_HorSnchWdth(var->hsync_len) +
1039                         LCCR1_BegLnDel(var->left_margin) +
1040                         LCCR1_EndLnDel(var->right_margin);
1041                 lcd_shadow.lccr2 = 
1042                         LCCR2_DisHght(var->yres) + 
1043                         LCCR2_VrtSnchWdth(var->vsync_len) +
1044                         LCCR2_BegFrmDel(var->upper_margin) +
1045                         LCCR2_EndFrmDel(var->lower_margin);
1046                 lcd_shadow.lccr3 = 
1047                         LCCR3_PixClkDiv(pcd) + LCCR3_ACBsDiv(512) +
1048                         LCCR3_ACBsCnt(0) + LCCR3_HorSnchH + LCCR3_VrtSnchH;
1049                 /*
1050                         ((current_var.sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HorSnchH : LCCR3_HorSnchL) +
1051                         ((current_var.sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
1052                 */
1053         } else if (machine_is_xp860()) {
1054                 DPRINTK("Configuring XP860 LCD\n");
1055                 lcd_shadow.lccr0 = 
1056                         LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
1057                         LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM +
1058                         LCCR0_DMADel(0);
1059                 lcd_shadow.lccr1 = 
1060                         LCCR1_DisWdth(var->xres) + 
1061                         LCCR1_HorSnchWdth(var->hsync_len) +
1062                         LCCR1_BegLnDel(var->left_margin) +
1063                         LCCR1_EndLnDel(var->right_margin);
1064                 lcd_shadow.lccr2 = 
1065                         LCCR2_DisHght(var->yres) + 
1066                         LCCR2_VrtSnchWdth(var->vsync_len) +
1067                         LCCR2_BegFrmDel(var->upper_margin) +
1068                         LCCR2_EndFrmDel(var->lower_margin);
1069                 lcd_shadow.lccr3 = 
1070                         LCCR3_PixClkDiv(6) +
1071                         LCCR3_HorSnchL + LCCR3_VrtSnchL;
1072         }
1073 
1074         /* Restore interrupt status */
1075         local_irq_restore(flags);
1076 
1077         if (( LCCR0 != lcd_shadow.lccr0 ) ||
1078             ( LCCR1 != lcd_shadow.lccr1 ) ||
1079             ( LCCR2 != lcd_shadow.lccr2 ) ||
1080             ( LCCR3 != lcd_shadow.lccr3 ) ||
1081             ( DBAR1 != lcd_shadow.dbar1 ) ||
1082             ( DBAR2 != lcd_shadow.dbar2 ))
1083         {
1084                 sa1100fb_enable_lcd_controller();
1085         }
1086 
1087         return 0;
1088 }
1089 
1090 
1091 /*
1092  *  sa1100fb_inter_handler():
1093  *      Interrupt handler for LCD controller.  Processes disable done interrupt (LDD)
1094  *      to reenable controller if controller was disabled to change register values.
1095  */
1096 static void sa1100fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs)
1097 {
1098         if (LCSR & LCSR_LDD) {
1099                 int controller_state = current_par.controller_state;
1100                 /* Disable Done Flag is set */
1101                 LCCR0 |= LCCR0_LDM;           /* Mask LCD Disable Done Interrupt */
1102                 current_par.controller_state = LCD_MODE_DISABLED;
1103                 if (controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) {
1104                         DPRINTK("sa1100fb_inter_handler: re-enabling LCD controller\n");
1105                         sa1100fb_enable_lcd_controller();
1106                 } else {
1107                         /*
1108                          * Second half of sa1100fb_disable_lcd_controller()
1109                          */
1110                         if (machine_is_assabet()) {
1111 #ifdef CONFIG_SA1100_ASSABET
1112                                 BCR_clear(BCR_LCD_ON);
1113 #endif
1114                         } else if (machine_is_bitsy()) {
1115 #ifdef CONFIG_SA1100_BITSY
1116                                 if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE)
1117                                         clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
1118 #endif
1119                         } else if (machine_is_penny()) {
1120 #ifdef CONFIG_SA1100_PENNY
1121                                 FpgaLcdCS1 = 0x000;     /* LCD Backlight to 0%    */
1122                                 FpgaPortI &= ~LCD_ON;   /* Turn off LCD Backlight */
1123 #endif
1124                         } else if (machine_is_tifon()) {
1125                                 GPCR = GPIO_GPIO(24);   /* turn off display */
1126                         }
1127                 }
1128         }
1129         LCSR = 0;                     /* Clear LCD Status Register */
1130 }
1131 
1132 
1133 /*
1134  *  sa1100fb_disable_lcd_controller():
1135  *      Disables LCD controller by and enables LDD interrupt.  The controller_state
1136  *      is not changed until the LDD interrupt is received to indicate the current
1137  *      frame has completed.  Platform specific hardware disabling is also included.
1138  */
1139 static void sa1100fb_disable_lcd_controller(void)
1140 {
1141         DPRINTK("Disabling LCD controller\n");
1142 
1143         /* Exit if already LCD disabled, or LDD IRQ unmasked */
1144         if ((current_par.controller_state == LCD_MODE_DISABLED) ||
1145             (!(LCCR0 & LCCR0_LDM))) {
1146                 DPRINTK("LCD already disabled\n");
1147                 return;
1148         }
1149 
1150         LCSR = 0;       /* Clear LCD Status Register */
1151         LCCR0 &= ~(LCCR0_LDM);  /* Enable LCD Disable Done Interrupt */
1152         enable_irq(IRQ_LCD);          /* Enable LCD IRQ */
1153         LCCR0 &= ~(LCCR0_LEN);  /* Disable LCD Controller */
1154 }
1155 
1156 /*
1157  *  sa1100fb_enable_lcd_controller():
1158  *      Enables LCD controller.  If the controller is already enabled, it is first disabled.
1159  *      This forces all changes to the LCD controller registers to be done when the 
1160  *      controller is disabled.  Platform specific hardware enabling is also included.
1161  */
1162 static void sa1100fb_enable_lcd_controller(void)
1163 {
1164         u_long  flags;
1165 
1166         local_irq_save(flags);          
1167 
1168         /* Disable controller before changing parameters */
1169         if (current_par.controller_state == LCD_MODE_ENABLED)   {
1170                 current_par.controller_state = LCD_MODE_DISABLE_BEFORE_ENABLE;
1171                 sa1100fb_disable_lcd_controller();
1172         } else {
1173                 DPRINTK("Enabling LCD controller\n");
1174 
1175                 /* Make sure the mode bits are present in the first palette entry */
1176                 current_par.v_palette_base[0] &= 0x0FFF;                   
1177                 current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel);    
1178 
1179                 /* Enable GPIO<9:2> for LCD usage if dual-scan */
1180                 if (lcd_shadow.lccr0 & LCCR0_SDS) {
1181                   GPDR |= 0x3fc;
1182                   GAFR |= 0x3fc;
1183                 }
1184 
1185                 /* Sequence from 11.7.10 */
1186                 LCCR3 = lcd_shadow.lccr3;
1187                 LCCR2 = lcd_shadow.lccr2;
1188                 LCCR1 = lcd_shadow.lccr1;
1189                 LCCR0 = lcd_shadow.lccr0 & ~LCCR0_LEN;
1190                 DBAR1 = lcd_shadow.dbar1;
1191                 DBAR2 = lcd_shadow.dbar2;
1192                 LCCR0 |= LCCR0_LEN;
1193 
1194                 if (machine_is_assabet()) {
1195 #ifdef CONFIG_SA1100_ASSABET
1196                         BCR_set(BCR_LCD_ON);
1197 #endif
1198                 } else if (machine_is_bitsy()) {
1199 #ifdef CONFIG_SA1100_BITSY
1200                   set_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
1201                         DPRINTK("DBAR1=%p\n", DBAR1);
1202                         DPRINTK("LCCR0=%x\n", LCCR0);
1203                         DPRINTK("LCCR1=%x\n", LCCR1);
1204                         DPRINTK("LCCR2=%x\n", LCCR2);
1205                         DPRINTK("LCCR3=%x\n", LCCR3);
1206 #endif
1207                 } else if (machine_is_penny()) {
1208 #ifdef CONFIG_SA1100_PENNY
1209                         FpgaLcdCS1 = 0x0FF;     /* LCD Backlight to 100% */
1210                         FpgaPortI  |= LCD_ON;   /* Turn on LCD Backlight */
1211 #endif
1212                 } else if (machine_is_tifon()) {
1213                         GPCR = GPIO_GPIO(24);   /* cycle on/off-switch */
1214                         udelay(150);
1215                         GPSR = GPIO_GPIO(24);   /* turn on display */
1216                 }
1217 
1218                 current_par.controller_state = LCD_MODE_ENABLED;
1219 
1220         }
1221         /* Restore interrupt status */
1222         local_irq_restore(flags);
1223 }
1224 
1225 /*
1226  * sa1100fb_blank():
1227  *      Blank the display by setting all palette values to zero.  Note, the 
1228  *      12 and 16 bpp modes don't really use the palette, so this will not
1229  *      blank the display in all modes.  
1230  */
1231 static void
1232 sa1100fb_blank(int blank, struct fb_info *info)
1233 {
1234         int i;
1235 
1236         DPRINTK("blank=%d info->modename=%s\n", blank, info->modename);
1237         if (blank) {
1238                 if (current_par.visual != FB_VISUAL_TRUECOLOR)
1239                 for (i = 0; i < current_par.palette_size; i++)
1240                         sa1100fb_palette_write(i, sa1100fb_palette_encode(i, 0, 0, 0, 0));
1241                 sa1100fb_disable_lcd_controller();
1242         }
1243         else {
1244                 if (current_par.visual != FB_VISUAL_TRUECOLOR)
1245                 sa1100fb_set_cmap(&fb_display[current_par.currcon].cmap, 1, 
1246                                   current_par.currcon, info); 
1247                 sa1100fb_enable_lcd_controller();
1248         }
1249         /* TODO: Bitsy support for blanking display */
1250 }
1251 
1252 
1253 /*
1254  *  sa1100fb_switch():       
1255  *      Change to the specified console.  Palette and video mode
1256  *      are changed to the console's stored parameters. 
1257  */
1258 static int
1259 sa1100fb_switch(int con, struct fb_info *info)
1260 {
1261 
1262         DPRINTK("con=%d info->modename=%s\n", con, info->modename);
1263         if (current_par.visual != FB_VISUAL_TRUECOLOR) {
1264                 struct fb_cmap *cmap;
1265                 if (current_par.currcon >= 0) {
1266                         // Get the colormap for the selected console 
1267                         cmap = &fb_display[current_par.currcon].cmap;
1268                         
1269                         if (cmap->len)
1270                                 fb_get_cmap(cmap, 1, sa1100fb_getcolreg, info);
1271                 }
1272         }
1273 
1274         current_par.currcon = con;
1275         fb_display[con].var.activate = FB_ACTIVATE_NOW;
1276         DPRINTK("fb_display[%d].var.activate=%x\n", con, fb_display[con].var.activate);
1277         sa1100fb_set_var(&fb_display[con].var, con, info);
1278         current_par.v_palette_base[0] = (current_par.v_palette_base[0] &
1279                 0xcfff) | SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel);
1280 
1281         return 0;
1282 }
1283 
1284 
1285 int __init sa1100fb_init(void)
1286 {
1287         int ret;
1288 
1289         sa1100fb_init_fbinfo();
1290 
1291         /* Initialize video memory */
1292         if ((ret = sa1100fb_map_video_memory()) != 0)
1293                 return ret;
1294 
1295         if (current_par.montype < 0 || current_par.montype > NR_MONTYPES)
1296                 current_par.montype = 1;
1297 
1298         if (request_irq(IRQ_LCD, sa1100fb_inter_handler, SA_INTERRUPT, "SA1100 LCD", NULL) != 0) {
1299                 printk(KERN_ERR "sa1100fb: failed in request_irq\n");
1300                 return -EBUSY;
1301         }
1302         DPRINTK("sa1100fb: request_irq succeeded\n");
1303         disable_irq(IRQ_LCD);
1304 
1305         if (machine_is_assabet()) {
1306                 GPDR |= 0x3fc;
1307                 GAFR |= 0x3fc;
1308                 sa1100fb_assabet_set_truecolor(current_par.visual ==
1309                                                FB_VISUAL_TRUECOLOR);
1310         } else if (machine_is_bitsy()) {
1311                 GPDR = (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8);
1312                 GAFR |= (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8);
1313         } else if (machine_is_cerf()) {
1314                 GPDR |= 0x3fc;
1315                 GAFR |= 0x3fc;
1316         } else if (machine_is_penny()) {
1317 #ifdef CONFIG_SA1100_PENNY
1318                 GPDR |= GPIO_GPDR_GFX;  /* GPIO Data Direction register for LCD data bits 8-11 */
1319                 GAFR |= GPIO_GAFR_GFX;  /* GPIO Alternate Function register for LCD data bits 8-11 */
1320 #endif
1321         } else if (machine_is_tifon()) {
1322                 GPDR |= GPIO_GPIO(24);  /* set GPIO24 to output */
1323         } else if (machine_is_xp860()) {
1324                 GPDR |= 0x3fc;
1325                 GAFR |= 0x3fc;
1326         }
1327 
1328         if (sa1100fb_set_var(&init_var, -1, &fb_info))
1329                 current_par.allow_modeset = 0;
1330         sa1100fb_decode_var(&init_var, &current_par);
1331 
1332         register_framebuffer(&fb_info);
1333 
1334         /* This driver cannot be unloaded at the moment */
1335         MOD_INC_USE_COUNT;
1336 
1337         return 0;
1338 }
1339 
1340 int __init sa1100fb_setup(char *options)
1341 {
1342         char *this_opt;
1343 
1344         if (!options || !*options)
1345                 return 0;
1346 
1347         for (this_opt = strtok(options, ","); this_opt;
1348              this_opt = strtok(NULL, ",")) {
1349 
1350           if (!strncmp(this_opt, "bpp:", 4))
1351             current_par.max_bpp = simple_strtoul(this_opt+4, NULL, 0);
1352 
1353           if (!strncmp(this_opt, "lccr0:", 6))
1354             lcd_shadow.lccr0 = simple_strtoul(this_opt+6, NULL, 0);
1355           if (!strncmp(this_opt, "lccr1:", 6)) {
1356             lcd_shadow.lccr1 = simple_strtoul(this_opt+6, NULL, 0);
1357             current_par.max_xres = (lcd_shadow.lccr1 & 0x3ff) + 16;
1358           }
1359           if (!strncmp(this_opt, "lccr2:", 6)) {
1360             lcd_shadow.lccr2 = simple_strtoul(this_opt+6, NULL, 0);
1361             current_par.max_yres = (lcd_shadow.lccr0 & LCCR0_SDS) ? 
1362               ((lcd_shadow.lccr2 & 0x3ff) + 1) * 2 :
1363               ((lcd_shadow.lccr2 & 0x3ff) + 1);
1364           }
1365           if (!strncmp(this_opt, "lccr3:", 6))
1366             lcd_shadow.lccr3 = simple_strtoul(this_opt+6, NULL, 0);
1367         }
1368         return 0;
1369 }
1370 
1371 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.