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, ¤t_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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.