2 * controlfb.c -- frame buffer device for the PowerMac 'control' display
4 * Created 12 July 1998 by Dan Jacobowitz <dan@debian.org>
5 * Copyright (C) 1998 Dan Jacobowitz
7 * Frame buffer structure from:
8 * drivers/video/chipsfb.c -- frame buffer device for
9 * Chips & Technologies 65550 chip.
11 * Copyright (C) 1998 Paul Mackerras
13 * This file is derived from the Powermac "chips" driver:
14 * Copyright (C) 1997 Fabio Riccardi.
15 * And from the frame buffer device for Open Firmware-initialized devices:
16 * Copyright (C) 1997 Geert Uytterhoeven.
18 * Hardware information from:
19 * control.c: Console support for PowerMac "control" display adaptor.
20 * Copyright (C) 1996 Paul Mackerras
22 * This file is subject to the terms and conditions of the GNU General Public
23 * License. See the file COPYING in the main directory of this archive for
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/errno.h>
31 #include <linux/string.h>
33 #include <linux/tty.h>
34 #include <linux/malloc.h>
35 #include <linux/vmalloc.h>
36 #include <linux/delay.h>
37 #include <linux/interrupt.h>
39 #include <linux/selection.h>
40 #include <linux/init.h>
41 #include <linux/pci.h>
42 #include <linux/nvram.h>
43 #ifdef CONFIG_FB_COMPAT_XPMAC
44 #include <asm/vc_ioctl.h>
46 #include <linux/adb.h>
47 #include <linux/cuda.h>
50 #include <asm/pgtable.h>
52 #include <video/fbcon.h>
53 #include <video/fbcon-cfb8.h>
54 #include <video/fbcon-cfb16.h>
55 #include <video/fbcon-cfb32.h>
56 #include <video/macmodes.h>
58 #include "controlfb.h"
60 struct fb_par_control
{
67 #define DIRTY(z) ((x)->z != (y)->z)
68 static inline int PAR_EQUAL(struct fb_par_control
*x
, struct fb_par_control
*y
)
70 return (!DIRTY(vmode
) && !DIRTY(cmode
) && !DIRTY(xres
)
71 && !DIRTY(yres
) && !DIRTY(vxres
) && !DIRTY(vyres
)
72 && !DIRTY(xoffset
) && !DIRTY(yoffset
));
74 static inline int VAR_MATCH(struct fb_var_screeninfo
*x
, struct fb_var_screeninfo
*y
)
76 return (!DIRTY(bits_per_pixel
) && !DIRTY(xres
)
77 && !DIRTY(yres
) && !DIRTY(xres_virtual
)
78 && !DIRTY(yres_virtual
));
81 struct fb_info_control
{
83 /* struct fb_fix_screeninfo fix;
84 struct fb_var_screeninfo var;*/
85 struct display display
;
86 struct fb_par_control par
;
88 __u8 red
, green
, blue
;
91 struct cmap_regs
*cmap_regs
;
92 unsigned long cmap_regs_phys
;
94 struct control_regs
*control_regs
;
95 unsigned long control_regs_phys
;
98 unsigned long frame_buffer_phys
;
100 int sense
, control_use_bank2
;
101 unsigned long total_vram
;
103 #ifdef FBCON_HAS_CFB16
106 #ifdef FBCON_HAS_CFB32
112 /******************** Prototypes for exported functions ********************/
113 static int control_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
114 struct fb_info
*info
);
115 static int control_get_var(struct fb_var_screeninfo
*var
, int con
,
116 struct fb_info
*info
);
117 static int control_set_var(struct fb_var_screeninfo
*var
, int con
,
118 struct fb_info
*info
);
119 static int control_pan_display(struct fb_var_screeninfo
*var
, int con
,
120 struct fb_info
*info
);
121 static int control_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
122 struct fb_info
*info
);
123 static int control_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
124 struct fb_info
*info
);
127 static int controlfb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
,
128 u_int
*blue
, u_int
*transp
, struct fb_info
*info
);
129 static int controlfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
130 u_int transp
, struct fb_info
*info
);
132 /******************** Prototypes for internal functions ********************/
133 static void control_par_to_fix(struct fb_par_control
*par
, struct fb_fix_screeninfo
*fix
,
134 struct fb_info_control
*p
);
135 static void do_install_cmap(int con
, struct fb_info
*info
);
136 static void control_set_dispsw(struct display
*disp
, int cmode
, struct fb_info_control
*p
);
138 /************************* Internal variables *****************************/
139 static int currcon
= 0;
140 static int par_set
= 0;
141 static char fontname
[40] __initdata
= { 0 };
142 static int default_vmode
= VMODE_NVRAM
;
143 static int default_cmode
= CMODE_NVRAM
;
148 int control_init(void);
150 void control_of_init(struct device_node
*dp
);
152 void control_setup(char *);
154 static int read_control_sense(struct fb_info_control
*p
);
155 static inline int control_vram_reqd(int video_mode
, int color_mode
);
156 static void set_control_clock(unsigned char *params
);
157 static void control_set_hardware(struct fb_info_control
*p
, struct fb_par_control
*par
);
158 static inline void control_par_to_var(struct fb_par_control
*par
, struct fb_var_screeninfo
*var
);
159 static int control_var_to_par(struct fb_var_screeninfo
*var
,
160 struct fb_par_control
*par
, const struct fb_info
*fb_info
);
162 static void control_init_info(struct fb_info
*info
, struct fb_info_control
*p
);
163 static void control_par_to_display(struct fb_par_control
*par
,
164 struct display
*disp
, struct fb_fix_screeninfo
*fix
, struct fb_info_control
*p
);
166 static int controlfb_updatevar(int con
, struct fb_info
*info
);
168 static struct fb_ops controlfb_ops
= {
170 fb_get_fix
: control_get_fix
,
171 fb_get_var
: control_get_var
,
172 fb_set_var
: control_set_var
,
173 fb_get_cmap
: control_get_cmap
,
174 fb_set_cmap
: control_set_cmap
,
175 fb_pan_display
: control_pan_display
,
180 /******************** The functions for controlfb_ops ********************/
183 int init_module(void)
185 struct device_node
*dp
;
187 printk("Loading...\n");
188 dp
= find_devices("control");
196 void cleanup_module(void)
201 /*********** Providing our information to the user ************/
203 static int control_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
204 struct fb_info
*info
)
206 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
209 printk(KERN_ERR
"control_get_fix called with unset par!\n");
211 control_par_to_fix(&p
->par
, fix
, p
);
213 struct fb_par_control par
;
215 control_var_to_par(&fb_display
[con
].var
, &par
, info
);
216 control_par_to_fix(&par
, fix
, p
);
221 static int control_get_var(struct fb_var_screeninfo
*var
, int con
,
222 struct fb_info
*info
)
224 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
227 printk(KERN_ERR
"control_get_var called with unset par!\n");
229 control_par_to_var(&p
->par
, var
);
231 *var
= fb_display
[con
].var
;
236 /* Sets everything according to var */
237 /* No longer safe for use in console switching */
238 static int control_set_var(struct fb_var_screeninfo
*var
, int con
,
239 struct fb_info
*info
)
241 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
242 struct display
*disp
;
243 struct fb_par_control par
;
244 int depthchange
, err
;
245 int activate
= var
->activate
;
247 disp
= (con
>= 0) ? &fb_display
[con
] : info
->disp
;
249 if((err
= control_var_to_par(var
, &par
, info
))) {
250 printk (KERN_ERR
"control_set_var: error calling control_var_to_par: %d.\n", err
);
254 control_par_to_var(&par
, var
);
256 if ((activate
& FB_ACTIVATE_MASK
) != FB_ACTIVATE_NOW
)
259 /* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
260 /* [above no longer true] */
261 depthchange
= (disp
->var
.bits_per_pixel
!= var
->bits_per_pixel
);
262 if(!VAR_MATCH(&disp
->var
, var
)) {
263 struct fb_fix_screeninfo fix
;
264 control_par_to_fix(&par
, &fix
, p
);
265 control_par_to_display(&par
, disp
, &fix
, p
);
267 (*info
->changevar
)(con
);
273 if(con
== currcon
|| con
== -1) {
274 control_set_hardware(p
, &par
);
277 if((err
= fb_alloc_cmap(&disp
->cmap
, 0, 0)))
279 do_install_cmap(con
, info
);
284 static int control_pan_display(struct fb_var_screeninfo
*var
, int con
,
285 struct fb_info
*info
)
287 struct fb_info_control
*p
= (struct fb_info_control
*)info
;
288 struct fb_par_control
*par
= &p
->par
;
290 if (var
->xoffset
!= 0 || var
->yoffset
+var
->yres
> var
->yres_virtual
)
292 fb_display
[con
].var
.yoffset
= par
->yoffset
= var
->yoffset
;
294 out_le32(&p
->control_regs
->start_addr
.r
,
295 par
->yoffset
* (par
->vxres
<< par
->cmode
));
299 static int control_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
300 struct fb_info
*info
)
302 if (con
== currcon
) /* current console? */
303 return fb_get_cmap(cmap
, kspc
, controlfb_getcolreg
, info
);
304 if (fb_display
[con
].cmap
.len
) /* non default colormap? */
305 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0: 2);
307 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
308 fb_copy_cmap(fb_default_cmap(size
), cmap
, kspc
? 0 : 2);
313 static int control_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
314 struct fb_info
*info
)
316 struct display
*disp
= &fb_display
[con
];
319 if (disp
->cmap
.len
== 0) {
320 int size
= disp
->var
.bits_per_pixel
== 16 ? 32 : 256;
321 err
= fb_alloc_cmap(&disp
->cmap
, size
, 0);
326 return fb_set_cmap(cmap
, kspc
, controlfb_setcolreg
, info
);
327 fb_copy_cmap(cmap
, &disp
->cmap
, kspc
? 0 : 1);
331 /******************** End of controlfb_ops implementation ********************/
332 /* (new one that is) */
335 static int controlfb_switch(int con
, struct fb_info
*info
)
337 struct fb_info_control
*p
= (struct fb_info_control
*)info
;
338 struct fb_par_control par
;
339 int oldcon
= currcon
;
341 if (fb_display
[currcon
].cmap
.len
)
342 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, controlfb_getcolreg
,
346 control_var_to_par(&fb_display
[con
].var
, &par
, info
);
347 control_set_hardware(p
, &par
);
348 control_set_dispsw(&fb_display
[con
], par
.cmode
, p
);
350 if(fb_display
[oldcon
].var
.yoffset
!= fb_display
[con
].var
.yoffset
)
351 controlfb_updatevar(con
, info
);
353 do_install_cmap(con
, info
);
357 static int controlfb_updatevar(int con
, struct fb_info
*info
)
359 struct fb_info_control
*p
= (struct fb_info_control
*)info
;
363 /* imsttfb blanks the unused bottom of the screen here...hmm. */
364 out_le32(&p
->control_regs
->start_addr
.r
,
365 fb_display
[con
].var
.yoffset
* fb_display
[con
].line_length
);
370 static void controlfb_blank(int blank_mode
, struct fb_info
*info
)
373 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
374 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
375 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
376 * to e.g. a video mode which doesn't support it. Implements VESA suspend
377 * and powerdown modes on hardware that supports disabling hsync/vsync:
378 * blank_mode == 2: suspend vsync
379 * blank_mode == 3: suspend hsync
380 * blank_mode == 4: powerdown
382 /* A blank_mode of 1+VESA_NO_BLANKING or 1+VESA_POWERDOWN act alike... */
383 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
386 if(blank_mode
== 1+VESA_NO_BLANKING
)
387 blank_mode
= 1+VESA_POWERDOWN
;
388 ctrl
= ld_le32(&p
->control_regs
->ctrl
.r
) | 0x33;
391 if (blank_mode
& VESA_VSYNC_SUSPEND
)
393 if (blank_mode
& VESA_HSYNC_SUSPEND
)
395 out_le32(&p
->control_regs
->ctrl
.r
, ctrl
);
397 /* TODO: Figure out how the heck to powerdown this thing! */
402 static int controlfb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
,
403 u_int
*blue
, u_int
*transp
, struct fb_info
*info
)
405 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
409 *red
= (p
->palette
[regno
].red
<<8) | p
->palette
[regno
].red
;
410 *green
= (p
->palette
[regno
].green
<<8) | p
->palette
[regno
].green
;
411 *blue
= (p
->palette
[regno
].blue
<<8) | p
->palette
[regno
].blue
;
416 static int controlfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
417 u_int transp
, struct fb_info
*info
)
419 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
430 p
->palette
[regno
].red
= r
;
431 p
->palette
[regno
].green
= g
;
432 p
->palette
[regno
].blue
= b
;
434 out_8(&p
->cmap_regs
->addr
, regno
); /* tell clut what addr to fill */
435 out_8(&p
->cmap_regs
->lut
, r
); /* send one color channel at */
436 out_8(&p
->cmap_regs
->lut
, g
); /* a time... */
437 out_8(&p
->cmap_regs
->lut
, b
);
440 switch (p
->par
.cmode
) {
441 #ifdef FBCON_HAS_CFB16
443 p
->fbcon_cmap
.cfb16
[regno
] = (regno
<< 10) | (regno
<< 5) | regno
;
446 #ifdef FBCON_HAS_CFB32
448 i
= (regno
<< 8) | regno
;
449 p
->fbcon_cmap
.cfb32
[regno
] = (i
<< 16) | i
;
456 static void do_install_cmap(int con
, struct fb_info
*info
)
460 if (fb_display
[con
].cmap
.len
)
461 fb_set_cmap(&fb_display
[con
].cmap
, 1, controlfb_setcolreg
,
464 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
465 fb_set_cmap(fb_default_cmap(size
), 1, controlfb_setcolreg
,
470 #ifdef CONFIG_FB_COMPAT_XPMAC
471 extern struct vc_mode display_info
;
472 extern struct fb_info
*console_fb_info
;
473 #endif /* CONFIG_FB_COMPAT_XPMAC */
475 static inline int control_vram_reqd(int video_mode
, int color_mode
)
477 return (control_reg_init
[video_mode
-1]->vres
478 * control_reg_init
[video_mode
-1]->hres
<< color_mode
)
479 + control_reg_init
[video_mode
-1]->offset
[color_mode
];
482 static void set_control_clock(unsigned char *params
)
484 struct adb_request req
;
487 for (i
= 0; i
< 3; ++i
) {
488 cuda_request(&req
, NULL
, 5, CUDA_PACKET
, CUDA_GET_SET_IIC
,
489 0x50, i
+ 1, params
[i
]);
490 while (!req
.complete
)
496 static void __init
init_control(struct fb_info_control
*p
)
498 struct fb_par_control parstruct
;
499 struct fb_par_control
*par
= &parstruct
;
500 struct fb_var_screeninfo var
;
502 p
->sense
= read_control_sense(p
);
503 printk(KERN_INFO
"Monitor sense value = 0x%x, ", p
->sense
);
504 /* Try to pick a video mode out of NVRAM if we have one. */
505 if (default_vmode
== VMODE_NVRAM
) {
506 par
->vmode
= nvram_read_byte(NV_VMODE
);
507 if(par
->vmode
<= 0 || par
->vmode
> VMODE_MAX
|| !control_reg_init
[par
->vmode
- 1])
508 par
->vmode
= VMODE_CHOOSE
;
509 if(par
->vmode
== VMODE_CHOOSE
)
510 par
->vmode
= mac_map_monitor_sense(p
->sense
);
511 if(!control_reg_init
[par
->vmode
- 1])
512 par
->vmode
= VMODE_640_480_60
;
514 par
->vmode
=default_vmode
;
516 if (default_cmode
== CMODE_NVRAM
){
517 par
->cmode
= nvram_read_byte(NV_CMODE
);
518 if(par
->cmode
< CMODE_8
|| par
->cmode
> CMODE_32
)
519 par
->cmode
= CMODE_8
;}
521 par
->cmode
=default_cmode
;
523 * Reduce the pixel size if we don't have enough VRAM.
525 while(par
->cmode
> CMODE_8
&& control_vram_reqd(par
->vmode
, par
->cmode
) > p
->total_vram
)
528 printk("using video mode %d and color mode %d.\n", par
->vmode
, par
->cmode
);
530 par
->vxres
= par
->xres
= control_reg_init
[par
->vmode
- 1]->hres
;
531 par
->yres
= control_reg_init
[par
->vmode
- 1]->vres
;
532 par
->vyres
= p
->total_vram
/ (par
->vxres
<< par
->cmode
);
533 par
->xoffset
= par
->yoffset
= 0;
535 control_init_info(&p
->info
, p
);
537 par_set
= 1; /* Debug */
539 control_par_to_var(par
, &var
);
540 var
.activate
= FB_ACTIVATE_NOW
;
541 control_set_var(&var
, -1, &p
->info
);
543 p
->info
.flags
= FBINFO_FLAG_DEFAULT
;
544 if (register_framebuffer(&p
->info
) < 0) {
549 printk(KERN_INFO
"fb%d: control display adapter\n", GET_FB_IDX(p
->info
.node
));
552 #define STORE_D2(a,d) \
553 out_8(&p->cmap_regs->addr, (a)); \
554 out_8(&p->cmap_regs->d2, (d))
556 /* Now how about actually saying, Make it so! */
557 /* Some things in here probably don't need to be done each time. */
558 static void control_set_hardware(struct fb_info_control
*p
, struct fb_par_control
*par
)
560 struct control_regvals
*init
;
561 volatile struct preg
*rp
;
565 if(PAR_EQUAL(&p
->par
, par
))
570 vmode
= p
->par
.vmode
;
571 cmode
= p
->par
.cmode
;
573 init
= control_reg_init
[vmode
- 1];
575 if (control_vram_reqd(vmode
, cmode
) > 0x200000)
577 else if (p
->control_use_bank2
)
581 if (vmode
>= VMODE_1280_960_75
&& cmode
>= CMODE_16
)
586 /* Initialize display timing registers */
587 out_le32(&p
->control_regs
->ctrl
.r
, 0x43b);
589 set_control_clock(init
->clock_params
);
591 STORE_D2(0x20, init
->radacal_ctrl
[cmode
]);
592 STORE_D2(0x21, p
->control_use_bank2
? 0 : 1);
596 rp
= &p
->control_regs
->vswin
;
597 for (i
= 0; i
< 16; ++i
, ++rp
)
598 out_le32(&rp
->r
, init
->regs
[i
]);
600 out_le32(&p
->control_regs
->pitch
.r
, par
->vxres
<< cmode
);
601 out_le32(&p
->control_regs
->mode
.r
, init
->mode
[cmode
]);
602 out_le32(&p
->control_regs
->flags
.r
, flags
);
603 out_le32(&p
->control_regs
->start_addr
.r
,
604 par
->yoffset
* (par
->vxres
<< cmode
));
605 out_le32(&p
->control_regs
->reg18
.r
, 0x1e5);
606 out_le32(&p
->control_regs
->reg19
.r
, 0);
608 for (i
= 0; i
< 16; ++i
) {
609 controlfb_setcolreg(color_table
[i
], default_red
[i
]<<8,
610 default_grn
[i
]<<8, default_blu
[i
]<<8,
611 0, (struct fb_info
*)p
);
613 /* Does the above need to be here each time? -- danj */
615 /* Turn on display */
616 out_le32(&p
->control_regs
->ctrl
.r
, ctrl
);
618 #ifdef CONFIG_FB_COMPAT_XPMAC
619 /* And let the world know the truth. */
620 if (!console_fb_info
|| console_fb_info
== &p
->info
) {
621 display_info
.height
= p
->par
.yres
;
622 display_info
.width
= p
->par
.xres
;
623 display_info
.depth
= (cmode
== CMODE_32
) ? 32 :
624 ((cmode
== CMODE_16
) ? 16 : 8);
625 display_info
.pitch
= p
->par
.vxres
<< p
->par
.cmode
;
626 display_info
.mode
= vmode
;
627 strncpy(display_info
.name
, "control",
628 sizeof(display_info
.name
));
629 display_info
.fb_address
= p
->frame_buffer_phys
630 + control_reg_init
[vmode
-1]->offset
[cmode
];
631 display_info
.cmap_adr_address
= p
->cmap_regs_phys
;
632 display_info
.cmap_data_address
= p
->cmap_regs_phys
+ 0x30;
633 display_info
.disp_reg_address
= p
->control_regs_phys
;
634 console_fb_info
= &p
->info
;
636 #endif /* CONFIG_FB_COMPAT_XPMAC */
639 int __init
control_init(void)
642 struct device_node
*dp
;
644 dp
= find_devices("control");
647 #endif /* CONFIG_FB_OF */
651 void __init
control_of_init(struct device_node
*dp
)
653 struct fb_info_control
*p
;
654 unsigned long addr
, size
;
657 if(dp
->n_addrs
!= 2) {
658 printk(KERN_ERR
"expecting 2 address for control (got %d)", dp
->n_addrs
);
661 p
= kmalloc(sizeof(*p
), GFP_ATOMIC
);
664 memset(p
, 0, sizeof(*p
));
666 /* Map in frame buffer and registers */
667 for (i
= 0; i
< dp
->n_addrs
; ++i
) {
668 addr
= dp
->addrs
[i
].address
;
669 size
= dp
->addrs
[i
].size
;
670 if (size
>= 0x800000) {
671 /* use the big-endian aperture (??) */
673 /* map at most 8MB for the frame buffer */
674 p
->frame_buffer_phys
= addr
;
675 p
->frame_buffer
= __ioremap(addr
, 0x800000, _PAGE_WRITETHRU
);
677 p
->control_regs_phys
= addr
;
678 p
->control_regs
= ioremap(addr
, size
);
681 p
->cmap_regs_phys
= 0xf301b000; /* XXX not in prom? */
682 p
->cmap_regs
= ioremap(p
->cmap_regs_phys
, 0x1000);
684 /* Work out which banks of VRAM we have installed. */
685 /* According to Andrew Fyfe <bandr@best.com>, the VRAM behaves like so: */
686 /* afyfe: observations from an 8500:
687 * - with 2M vram in bank 1, it appears at offsets 0, 2M and 4M
688 * - with 2M vram in bank 2, it appears only at offset 6M
689 * - with 4M vram, it appears only as a 4M block at offset 0.
692 /* We know there is something at 2M if there is something at 0M. */
693 out_8(&p
->frame_buffer
[0x200000], 0xa5);
694 out_8(&p
->frame_buffer
[0x200001], 0x38);
695 asm volatile("eieio; dcbi 0,%0" : : "r" (&p
->frame_buffer
[0x200000]) : "memory" );
697 out_8(&p
->frame_buffer
[0], 0x5a);
698 out_8(&p
->frame_buffer
[1], 0xc7);
699 asm volatile("eieio; dcbi 0,%0" : : "r" (&p
->frame_buffer
[0]) : "memory" );
701 bank1
= (in_8(&p
->frame_buffer
[0x000000]) == 0x5a)
702 && (in_8(&p
->frame_buffer
[0x000001]) == 0xc7);
703 bank2
= (in_8(&p
->frame_buffer
[0x200000]) == 0xa5)
704 && (in_8(&p
->frame_buffer
[0x200001]) == 0x38);
707 printk(KERN_INFO
"controlfb: Found memory at 2MB but not at 0! Please contact dan@debian.org\n");
710 out_8(&p
->frame_buffer
[0x600000], 0xa5);
711 out_8(&p
->frame_buffer
[0x600001], 0x38);
712 asm volatile("eieio; dcbi 0,%0" : : "r" (&p
->frame_buffer
[0x600000]) : "memory" );
713 bank2
= (in_8(&p
->frame_buffer
[0x600000]) == 0xa5)
714 && (in_8(&p
->frame_buffer
[0x600001]) == 0x38);
715 /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
716 p
->control_use_bank2
= 1;
717 p
->frame_buffer
+= 0x600000;
718 p
->frame_buffer_phys
+= 0x600000;
721 p
->total_vram
= (bank1
+ bank2
) * 0x200000;
723 printk(KERN_INFO
"controlfb: Memory bank 1 %s, bank 2 %s, total VRAM %dMB\n",
724 bank1
? "present" : "absent", bank2
? "present" : "absent",
725 2 * (bank1
+ bank2
));
731 * Get the monitor sense value.
732 * Note that this can be called before calibrate_delay,
733 * so we can't use udelay.
735 static int read_control_sense(struct fb_info_control
*p
)
739 out_le32(&p
->control_regs
->mon_sense
.r
, 7); /* drive all lines high */
741 out_le32(&p
->control_regs
->mon_sense
.r
, 077); /* turn off drivers */
743 sense
= (in_le32(&p
->control_regs
->mon_sense
.r
) & 0x1c0) << 2;
745 /* drive each sense line low in turn and collect the other 2 */
746 out_le32(&p
->control_regs
->mon_sense
.r
, 033); /* drive A low */
748 sense
|= (in_le32(&p
->control_regs
->mon_sense
.r
) & 0xc0) >> 2;
749 out_le32(&p
->control_regs
->mon_sense
.r
, 055); /* drive B low */
751 sense
|= ((in_le32(&p
->control_regs
->mon_sense
.r
) & 0x100) >> 5)
752 | ((in_le32(&p
->control_regs
->mon_sense
.r
) & 0x40) >> 4);
753 out_le32(&p
->control_regs
->mon_sense
.r
, 066); /* drive C low */
755 sense
|= (in_le32(&p
->control_regs
->mon_sense
.r
) & 0x180) >> 7;
757 out_le32(&p
->control_regs
->mon_sense
.r
, 077); /* turn off drivers */
762 /*********************** Various translation functions ***********************/
764 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
765 static int control_var_to_par(struct fb_var_screeninfo
*var
,
766 struct fb_par_control
*par
, const struct fb_info
*fb_info
)
768 int xres
= var
->xres
;
769 int yres
= var
->yres
;
770 int bpp
= var
->bits_per_pixel
;
771 struct fb_info_control
*p
= (struct fb_info_control
*) fb_info
;
774 * Get the video params out of 'var'. If a value doesn't fit, round it up,
775 * if it's too big, return -EINVAL.
777 * Suggestion: Round up in the following order: bits_per_pixel, xres,
778 * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
779 * bitfields, horizontal timing, vertical timing.
781 /* swiped by jonh from atyfb.c */
782 if (xres
<= 640 && yres
<= 480)
783 par
->vmode
= VMODE_640_480_67
; /* 640x480, 67Hz */
784 else if (xres
<= 640 && yres
<= 870)
785 par
->vmode
= VMODE_640_870_75P
; /* 640x870, 75Hz (portrait) */
786 else if (xres
<= 800 && yres
<= 600)
787 par
->vmode
= VMODE_800_600_75
; /* 800x600, 75Hz */
788 else if (xres
<= 832 && yres
<= 624)
789 par
->vmode
= VMODE_832_624_75
; /* 832x624, 75Hz */
790 else if (xres
<= 1024 && yres
<= 768)
791 par
->vmode
= VMODE_1024_768_75
; /* 1024x768, 75Hz */
792 else if (xres
<= 1152 && yres
<= 870)
793 par
->vmode
= VMODE_1152_870_75
; /* 1152x870, 75Hz */
794 else if (xres
<= 1280 && yres
<= 960)
795 par
->vmode
= VMODE_1280_960_75
; /* 1280x960, 75Hz */
796 else if (xres
<= 1280 && yres
<= 1024)
797 par
->vmode
= VMODE_1280_1024_75
; /* 1280x1024, 75Hz */
799 printk(KERN_ERR
"Bad x/y res in var_to_par\n");
803 xres
= control_reg_init
[par
->vmode
-1]->hres
;
804 yres
= control_reg_init
[par
->vmode
-1]->vres
;
809 if (var
->xres_virtual
<= xres
)
811 else if(var
->xres_virtual
> xres
) {
813 } else /* NotReached at present */
814 par
->vxres
= (var
->xres_virtual
+7) & ~7;
816 if (var
->yres_virtual
<= yres
)
819 par
->vyres
= var
->yres_virtual
;
821 if (var
->xoffset
> 0 || var
->yoffset
+yres
> par
->vyres
) {
822 printk(KERN_ERR
"Bad offsets in var_to_par\n");
826 par
->xoffset
= (var
->xoffset
+7) & ~7;
827 par
->yoffset
= var
->yoffset
;
831 par
->cmode
= CMODE_8
;
833 par
->cmode
= CMODE_16
;
835 par
->cmode
= CMODE_32
;
837 printk(KERN_ERR
"Bad bpp in var_to_par\n");
841 if (control_vram_reqd(par
->vmode
, par
->cmode
) > p
->total_vram
) {
842 printk(KERN_ERR
"Too much VRAM required for vmode %d cmode %d.\n", par
->vmode
, par
->cmode
);
846 /* Check if we know about the wanted video mode */
847 if (control_reg_init
[par
->vmode
- 1] == NULL
) {
848 printk(KERN_ERR
"init is null in control_var_to_par().\n");
849 /* I'm not sure if control has any specific requirements -- */
850 /* if we have a regvals struct, we're good to go? */
857 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
858 static int control_var_to_par(struct fb_var_screeninfo
*var
,
859 struct fb_par_control
*par
, const struct fb_info
*fb_info
)
861 struct fb_info_control
*p
= (struct fb_info_control
*) fb_info
;
863 if(mac_var_to_vmode(var
, &par
->vmode
, &par
->cmode
) != 0)
865 par
->xres
= par
->vxres
= vmode_attrs
[par
->vmode
- 1].hres
;
866 par
->yres
= par
->vyres
= vmode_attrs
[par
->vmode
- 1].vres
;
867 par
->xoffset
= par
->yoffset
= 0;
869 if (control_vram_reqd(par
->vmode
, par
->cmode
) > p
->total_vram
)
872 /* Check if we know about the wanted video mode */
873 if(!control_reg_init
[par
->vmode
-1]) {
874 /* I'm not sure if control has any specific requirements -- */
875 /* if we have a regvals struct, we're good to go? */
882 /*********** Convert hardware data in par to an fb_var_screeninfo ***********/
884 static void control_par_to_var(struct fb_par_control
*par
, struct fb_var_screeninfo
*var
)
886 struct control_regints
*rv
;
888 rv
= (struct control_regints
*) control_reg_init
[par
->vmode
- 1]->regs
;
890 memset(var
, 0, sizeof(*var
));
891 var
->xres
= control_reg_init
[par
->vmode
- 1]->hres
;
892 var
->yres
= control_reg_init
[par
->vmode
- 1]->vres
;
893 var
->xres_virtual
= par
->vxres
;
894 var
->yres_virtual
= par
->vyres
;
895 var
->xoffset
= par
->xoffset
;
896 var
->yoffset
= par
->yoffset
;
899 if(par
->cmode
!= CMODE_8
&& par
->cmode
!= CMODE_16
&& par
->cmode
!= CMODE_32
) {
900 printk(KERN_ERR
"Bad color mode in control_par_to_var()!\n");
901 par
->cmode
= CMODE_8
;
905 var
->bits_per_pixel
= 8;
908 var
->green
.offset
= 0;
909 var
->green
.length
= 8;
910 var
->blue
.offset
= 0;
911 var
->blue
.length
= 8;
912 var
->transp
.offset
= 0;
913 var
->transp
.length
= 0;
915 case CMODE_16
: /* RGB 555 */
916 var
->bits_per_pixel
= 16;
917 var
->red
.offset
= 10;
919 var
->green
.offset
= 5;
920 var
->green
.length
= 5;
921 var
->blue
.offset
= 0;
922 var
->blue
.length
= 5;
923 var
->transp
.offset
= 0;
924 var
->transp
.length
= 0;
926 case CMODE_32
: /* RGB 888 */
927 var
->bits_per_pixel
= 32;
928 var
->red
.offset
= 16;
930 var
->green
.offset
= 8;
931 var
->green
.length
= 8;
932 var
->blue
.offset
= 0;
933 var
->blue
.length
= 8;
934 var
->transp
.offset
= 24;
935 var
->transp
.length
= 8;
938 var
->red
.msb_right
= 0;
939 var
->green
.msb_right
= 0;
940 var
->blue
.msb_right
= 0;
941 var
->transp
.msb_right
= 0;
946 var
->vmode
= FB_VMODE_NONINTERLACED
;
948 var
->left_margin
= (rv
->heblank
- rv
->hesync
)
949 << ((par
->vmode
> 18) ? 2 : 1);
950 var
->right_margin
= (rv
->hssync
- rv
->hsblank
)
951 << ((par
->vmode
> 18) ? 2 : 1);
952 var
->hsync_len
= (rv
->hperiod
+ 2 - rv
->hssync
+ rv
->hesync
)
953 << ((par
->vmode
> 18) ? 2 : 1);
955 var
->upper_margin
= (rv
->veblank
- rv
->vesync
) >> 1;
956 var
->lower_margin
= (rv
->vssync
- rv
->vsblank
) >> 1;
957 var
->vsync_len
= (rv
->vperiod
- rv
->vssync
+ rv
->vesync
) >> 1;
959 /* Acording to macmodes.c... */
960 if((par
->vmode
>= 9 && par
->vmode
<= 12) ||
961 (par
->vmode
>= 16 && par
->vmode
<= 18) ||
964 var
->sync
= FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
;
966 var
->sync
= 0; /* I suppose */
969 /* The reason these are both here: with my revised margin calculations, */
970 /* these SHOULD both give the same answer for each mode. Some day I */
971 /* will sit down and check the rest. Works perfectly for vmode 13. */
974 /* jonh's pixclocks...*/
975 /* no long long support in the kernel :-( */
976 /* this splittig trick will work if xres > 232 */
977 var
->pixclock
= 1000000000/
978 (var
->left_margin
+var
->xres
+var
->right_margin
+var
->hsync_len
);
979 var
->pixclock
*= 1000;
980 var
->pixclock
/= vmode_attrs
[par
->vmode
-1].vfreq
*
981 (var
->upper_margin
+var
->yres
+var
->lower_margin
+var
->vsync_len
);
984 /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
985 /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
986 /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
987 var
->pixclock
= 255990 * control_reg_init
[par
->vmode
-1]->clock_params
[0];
988 var
->pixclock
/= control_reg_init
[par
->vmode
-1]->clock_params
[1];
989 var
->pixclock
>>= control_reg_init
[par
->vmode
-1]->clock_params
[2];
993 static void control_par_to_fix(struct fb_par_control
*par
, struct fb_fix_screeninfo
*fix
,
994 struct fb_info_control
*p
)
996 memset(fix
, 0, sizeof(*fix
));
997 strcpy(fix
->id
, "control");
998 fix
->mmio_start
= p
->control_regs_phys
;
999 fix
->mmio_len
= sizeof(struct control_regs
);
1000 fix
->type
= FB_TYPE_PACKED_PIXELS
;
1010 fix
->smem_start
= (p
->frame_buffer_phys
1011 + control_reg_init
[par
->vmode
-1]->offset
[par
->cmode
]);
1012 fix
->smem_len
= p
->total_vram
- control_reg_init
[par
->vmode
-1]->offset
[par
->cmode
];
1013 fix
->visual
= (par
->cmode
== CMODE_8
) ?
1014 FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_DIRECTCOLOR
;
1015 fix
->line_length
= par
->vxres
<< par
->cmode
;
1018 /* We never initialize any display except for p->disp.
1019 And p->disp is already memset to 0. So no memset here.
1020 [Found by Takashi Oe]
1022 static void control_par_to_display(struct fb_par_control
*par
,
1023 struct display
*disp
, struct fb_fix_screeninfo
*fix
, struct fb_info_control
*p
)
1025 /* memset(disp, 0, sizeof(*disp)); */
1026 disp
->type
= fix
->type
;
1027 disp
->can_soft_blank
= 1;
1028 disp
->scrollmode
= SCROLL_YNOMOVE
| SCROLL_YNOPARTIAL
;
1029 disp
->ypanstep
= fix
->ypanstep
;
1030 disp
->ywrapstep
= fix
->ywrapstep
;
1032 disp
->type_aux
= fix
->type_aux
;
1033 disp
->cmap
.red
= NULL
; /* ??? danj */
1034 disp
->cmap
.green
= NULL
;
1035 disp
->cmap
.blue
= NULL
;
1036 disp
->cmap
.transp
= NULL
;
1037 /* Yeah, I realize I just set 0 = 0. */
1040 control_par_to_var(par
, &disp
->var
);
1041 disp
->screen_base
= (char *) p
->frame_buffer
1042 + control_reg_init
[par
->vmode
-1]->offset
[par
->cmode
];
1043 disp
->visual
= fix
->visual
;
1044 disp
->line_length
= fix
->line_length
;
1045 control_set_dispsw(disp
, par
->cmode
, p
);
1048 static void control_cfb16_revc(struct display
*p
, int xx
, int yy
)
1051 int bytes
= p
->next_line
, rows
;
1053 dest
= p
->screen_base
+ yy
* fontheight(p
) * bytes
+ xx
* fontwidth(p
)*2;
1054 for (rows
= fontheight(p
); rows
--; dest
+= bytes
) {
1055 switch (fontwidth(p
)) {
1057 ((u32
*)dest
)[6] ^= 0x3def3def; ((u32
*)dest
)[7] ^= 0x3def3def;
1060 ((u32
*)dest
)[4] ^= 0x3def3def; ((u32
*)dest
)[5] ^= 0x3def3def;
1063 ((u32
*)dest
)[2] ^= 0x3def3def; ((u32
*)dest
)[3] ^= 0x3def3def;
1066 ((u32
*)dest
)[0] ^= 0x3def3def; ((u32
*)dest
)[1] ^= 0x3def3def;
1071 static void control_cfb32_revc(struct display
*p
, int xx
, int yy
)
1074 int bytes
= p
->next_line
, rows
;
1076 dest
= p
->screen_base
+ yy
* fontheight(p
) * bytes
+ xx
* fontwidth(p
) * 4;
1077 for (rows
= fontheight(p
); rows
--; dest
+= bytes
) {
1078 switch (fontwidth(p
)) {
1080 ((u32
*)dest
)[12] ^= 0x0f0f0f0f; ((u32
*)dest
)[13] ^= 0x0f0f0f0f;
1081 ((u32
*)dest
)[14] ^= 0x0f0f0f0f; ((u32
*)dest
)[15] ^= 0x0f0f0f0f;
1084 ((u32
*)dest
)[8] ^= 0x0f0f0f0f; ((u32
*)dest
)[9] ^= 0x0f0f0f0f;
1085 ((u32
*)dest
)[10] ^= 0x0f0f0f0f; ((u32
*)dest
)[11] ^= 0x0f0f0f0f;
1088 ((u32
*)dest
)[4] ^= 0x0f0f0f0f; ((u32
*)dest
)[5] ^= 0x0f0f0f0f;
1089 ((u32
*)dest
)[6] ^= 0x0f0f0f0f; ((u32
*)dest
)[7] ^= 0x0f0f0f0f;
1092 ((u32
*)dest
)[0] ^= 0x0f0f0f0f; ((u32
*)dest
)[1] ^= 0x0f0f0f0f;
1093 ((u32
*)dest
)[2] ^= 0x0f0f0f0f; ((u32
*)dest
)[3] ^= 0x0f0f0f0f;
1099 static struct display_switch control_cfb16
= {
1100 setup
: fbcon_cfb16_setup
,
1101 bmove
: fbcon_cfb16_bmove
,
1102 clear
: fbcon_cfb16_clear
,
1103 putc
: fbcon_cfb16_putc
,
1104 putcs
: fbcon_cfb16_putcs
,
1105 revc
: control_cfb16_revc
,
1106 clear_margins
: fbcon_cfb16_clear_margins
,
1107 fontwidthmask
: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1110 static struct display_switch control_cfb32
= {
1111 setup
: fbcon_cfb32_setup
,
1112 bmove
: fbcon_cfb32_bmove
,
1113 clear
: fbcon_cfb32_clear
,
1114 putc
: fbcon_cfb32_putc
,
1115 putcs
: fbcon_cfb32_putcs
,
1116 revc
: control_cfb32_revc
,
1117 clear_margins
: fbcon_cfb32_clear_margins
,
1118 fontwidthmask
: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1122 static void control_set_dispsw(struct display
*disp
, int cmode
, struct fb_info_control
*p
)
1125 #ifdef FBCON_HAS_CFB8
1127 disp
->dispsw
= &fbcon_cfb8
;
1130 #ifdef FBCON_HAS_CFB16
1132 disp
->dispsw
= &control_cfb16
;
1133 disp
->dispsw_data
= p
->fbcon_cmap
.cfb16
;
1136 #ifdef FBCON_HAS_CFB32
1138 disp
->dispsw
= &control_cfb32
;
1139 disp
->dispsw_data
= p
->fbcon_cmap
.cfb32
;
1143 disp
->dispsw
= &fbcon_dummy
;
1148 static void control_init_info(struct fb_info
*info
, struct fb_info_control
*p
)
1150 strcpy(info
->modename
, "control");
1151 info
->node
= -1; /* ??? danj */
1152 info
->fbops
= &controlfb_ops
;
1153 info
->disp
= &p
->display
;
1154 strcpy(info
->fontname
, fontname
);
1155 info
->changevar
= NULL
;
1156 info
->switch_con
= &controlfb_switch
;
1157 info
->updatevar
= &controlfb_updatevar
;
1158 info
->blank
= &controlfb_blank
;
1161 /* Parse user speficied options (`video=controlfb:') */
1162 void __init
control_setup(char *options
)
1166 if (!options
|| !*options
)
1169 for (this_opt
= strtok(options
, ","); this_opt
;
1170 this_opt
= strtok(NULL
, ",")) {
1171 if (!strncmp(this_opt
, "font:", 5)) {
1176 for (i
= 0; i
< sizeof(fontname
) - 1; i
++)
1177 if (!*p
|| *p
== ' ' || *p
== ',')
1179 memcpy(fontname
, this_opt
+ 5, i
);
1182 if (!strncmp(this_opt
, "vmode:", 6)) {
1183 int vmode
= simple_strtoul(this_opt
+6, NULL
, 0);
1184 if (vmode
> 0 && vmode
<= VMODE_MAX
)
1185 default_vmode
= vmode
;
1186 } else if (!strncmp(this_opt
, "cmode:", 6)) {
1187 int depth
= simple_strtoul(this_opt
+6, NULL
, 0);
1192 default_cmode
= depth
;
1195 default_cmode
= CMODE_8
;
1199 default_cmode
= CMODE_16
;
1203 default_cmode
= CMODE_32
;
1211 static int controlfb_pan_display(struct fb_var_screeninfo
*var
,
1212 struct controlfb_par
*par
,
1213 const struct fb_info
*fb_info
)
1216 * Pan (or wrap, depending on the `vmode' field) the display using the
1217 * `xoffset' and `yoffset' fields of the `var' structure.
1218 * If the values don't fit, return -EINVAL.