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>
48 #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_open(struct fb_info
*info
, int user
);
114 static int control_release(struct fb_info
*info
, int user
);
115 static int control_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
116 struct fb_info
*info
);
117 static int control_get_var(struct fb_var_screeninfo
*var
, int con
,
118 struct fb_info
*info
);
119 static int control_set_var(struct fb_var_screeninfo
*var
, int con
,
120 struct fb_info
*info
);
121 static int control_pan_display(struct fb_var_screeninfo
*var
, int con
,
122 struct fb_info
*info
);
123 static int control_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
124 struct fb_info
*info
);
125 static int control_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
126 struct fb_info
*info
);
127 static int control_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
128 u_long arg
, int con
, struct fb_info
*info
);
131 static int controlfb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
,
132 u_int
*blue
, u_int
*transp
, struct fb_info
*info
);
133 static int controlfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
134 u_int transp
, struct fb_info
*info
);
136 /******************** Prototypes for internal functions ********************/
137 static void control_par_to_fix(struct fb_par_control
*par
, struct fb_fix_screeninfo
*fix
,
138 struct fb_info_control
*p
);
139 static void do_install_cmap(int con
, struct fb_info
*info
);
140 static void control_set_dispsw(struct display
*disp
, int cmode
, struct fb_info_control
*p
);
142 /************************* Internal variables *****************************/
143 static int currcon
= 0;
144 static int par_set
= 0;
145 static char fontname
[40] __initdata
= { 0 };
146 static int default_vmode
= VMODE_NVRAM
;
147 static int default_cmode
= CMODE_NVRAM
;
152 int control_init(void);
154 void control_of_init(struct device_node
*dp
);
156 void control_setup(char *);
158 static int read_control_sense(struct fb_info_control
*p
);
159 static inline int control_vram_reqd(int video_mode
, int color_mode
);
160 static void set_control_clock(unsigned char *params
);
161 static void control_set_hardware(struct fb_info_control
*p
, struct fb_par_control
*par
);
162 static inline void control_par_to_var(struct fb_par_control
*par
, struct fb_var_screeninfo
*var
);
163 static int control_var_to_par(struct fb_var_screeninfo
*var
,
164 struct fb_par_control
*par
, const struct fb_info
*fb_info
);
166 static void control_init_info(struct fb_info
*info
, struct fb_info_control
*p
);
167 static void control_par_to_display(struct fb_par_control
*par
,
168 struct display
*disp
, struct fb_fix_screeninfo
*fix
, struct fb_info_control
*p
);
170 static int controlfb_updatevar(int con
, struct fb_info
*info
);
172 static struct fb_ops controlfb_ops
= {
186 /******************** The functions for controlfb_ops ********************/
188 /********** Dummies for loading control as a module **********/
190 int control_open(struct fb_info
*info
, int user
)
196 static int control_release(struct fb_info
*info
, int user
)
203 int init_module(void)
205 struct device_node
*dp
;
207 printk("Loading...\n");
208 dp
= find_devices("control");
216 void cleanup_module(void)
221 /*********** Providing our information to the user ************/
223 static int control_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
224 struct fb_info
*info
)
226 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
229 printk(KERN_ERR
"control_get_fix called with unset par!\n");
231 control_par_to_fix(&p
->par
, fix
, p
);
233 struct fb_par_control par
;
235 control_var_to_par(&fb_display
[con
].var
, &par
, info
);
236 control_par_to_fix(&par
, fix
, p
);
241 static int control_get_var(struct fb_var_screeninfo
*var
, int con
,
242 struct fb_info
*info
)
244 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
247 printk(KERN_ERR
"control_get_var called with unset par!\n");
249 control_par_to_var(&p
->par
, var
);
251 *var
= fb_display
[con
].var
;
256 /* Sets everything according to var */
257 /* No longer safe for use in console switching */
258 static int control_set_var(struct fb_var_screeninfo
*var
, int con
,
259 struct fb_info
*info
)
261 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
262 struct display
*disp
;
263 struct fb_par_control par
;
264 int depthchange
, err
;
265 int activate
= var
->activate
;
267 disp
= (con
>= 0) ? &fb_display
[con
] : info
->disp
;
269 if((err
= control_var_to_par(var
, &par
, info
))) {
270 printk (KERN_ERR
"control_set_var: error calling control_var_to_par: %d.\n", err
);
274 control_par_to_var(&par
, var
);
276 if ((activate
& FB_ACTIVATE_MASK
) != FB_ACTIVATE_NOW
)
279 /* I know, we want to use fb_display[con], but grab certain info from p->var instead. */
280 /* [above no longer true] */
281 depthchange
= (disp
->var
.bits_per_pixel
!= var
->bits_per_pixel
);
282 if(!VAR_MATCH(&disp
->var
, var
)) {
283 struct fb_fix_screeninfo fix
;
284 control_par_to_fix(&par
, &fix
, p
);
285 control_par_to_display(&par
, disp
, &fix
, p
);
287 (*info
->changevar
)(con
);
293 if(con
== currcon
|| con
== -1) {
294 control_set_hardware(p
, &par
);
297 if((err
= fb_alloc_cmap(&disp
->cmap
, 0, 0)))
299 do_install_cmap(con
, info
);
304 static int control_pan_display(struct fb_var_screeninfo
*var
, int con
,
305 struct fb_info
*info
)
307 struct fb_info_control
*p
= (struct fb_info_control
*)info
;
308 struct fb_par_control
*par
= &p
->par
;
310 if (var
->xoffset
!= 0 || var
->yoffset
+var
->yres
> var
->yres_virtual
)
312 fb_display
[con
].var
.yoffset
= par
->yoffset
= var
->yoffset
;
314 out_le32(&p
->control_regs
->start_addr
.r
,
315 par
->yoffset
* (par
->vxres
<< par
->cmode
));
319 static int control_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
320 struct fb_info
*info
)
322 if (con
== currcon
) /* current console? */
323 return fb_get_cmap(cmap
, kspc
, controlfb_getcolreg
, info
);
324 if (fb_display
[con
].cmap
.len
) /* non default colormap? */
325 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0: 2);
327 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
328 fb_copy_cmap(fb_default_cmap(size
), cmap
, kspc
? 0 : 2);
333 static int control_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
334 struct fb_info
*info
)
336 struct display
*disp
= &fb_display
[con
];
339 if (disp
->cmap
.len
== 0) {
340 int size
= disp
->var
.bits_per_pixel
== 16 ? 32 : 256;
341 err
= fb_alloc_cmap(&disp
->cmap
, size
, 0);
346 return fb_set_cmap(cmap
, kspc
, controlfb_setcolreg
, info
);
347 fb_copy_cmap(cmap
, &disp
->cmap
, kspc
? 0 : 1);
351 static int control_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
352 u_long arg
, int con
, struct fb_info
*info
)
357 /******************** End of controlfb_ops implementation ********************/
358 /* (new one that is) */
361 static int controlfb_switch(int con
, struct fb_info
*info
)
363 struct fb_info_control
*p
= (struct fb_info_control
*)info
;
364 struct fb_par_control par
;
365 int oldcon
= currcon
;
367 if (fb_display
[currcon
].cmap
.len
)
368 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, controlfb_getcolreg
,
372 control_var_to_par(&fb_display
[con
].var
, &par
, info
);
373 control_set_hardware(p
, &par
);
374 control_set_dispsw(&fb_display
[con
], par
.cmode
, p
);
376 if(fb_display
[oldcon
].var
.yoffset
!= fb_display
[con
].var
.yoffset
)
377 controlfb_updatevar(con
, info
);
379 do_install_cmap(con
, info
);
383 static int controlfb_updatevar(int con
, struct fb_info
*info
)
385 struct fb_info_control
*p
= (struct fb_info_control
*)info
;
389 /* imsttfb blanks the unused bottom of the screen here...hmm. */
390 out_le32(&p
->control_regs
->start_addr
.r
,
391 fb_display
[con
].var
.yoffset
* fb_display
[con
].line_length
);
396 static void controlfb_blank(int blank_mode
, struct fb_info
*info
)
399 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
400 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
401 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
402 * to e.g. a video mode which doesn't support it. Implements VESA suspend
403 * and powerdown modes on hardware that supports disabling hsync/vsync:
404 * blank_mode == 2: suspend vsync
405 * blank_mode == 3: suspend hsync
406 * blank_mode == 4: powerdown
408 /* A blank_mode of 1+VESA_NO_BLANKING or 1+VESA_POWERDOWN act alike... */
409 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
412 if(blank_mode
== 1+VESA_NO_BLANKING
)
413 blank_mode
= 1+VESA_POWERDOWN
;
414 ctrl
= ld_le32(&p
->control_regs
->ctrl
.r
) | 0x33;
417 if (blank_mode
& VESA_VSYNC_SUSPEND
)
419 if (blank_mode
& VESA_HSYNC_SUSPEND
)
421 out_le32(&p
->control_regs
->ctrl
.r
, ctrl
);
423 /* TODO: Figure out how the heck to powerdown this thing! */
428 static int controlfb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
,
429 u_int
*blue
, u_int
*transp
, struct fb_info
*info
)
431 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
435 *red
= (p
->palette
[regno
].red
<<8) | p
->palette
[regno
].red
;
436 *green
= (p
->palette
[regno
].green
<<8) | p
->palette
[regno
].green
;
437 *blue
= (p
->palette
[regno
].blue
<<8) | p
->palette
[regno
].blue
;
442 static int controlfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
443 u_int transp
, struct fb_info
*info
)
445 struct fb_info_control
*p
= (struct fb_info_control
*) info
;
456 p
->palette
[regno
].red
= r
;
457 p
->palette
[regno
].green
= g
;
458 p
->palette
[regno
].blue
= b
;
460 out_8(&p
->cmap_regs
->addr
, regno
); /* tell clut what addr to fill */
461 out_8(&p
->cmap_regs
->lut
, r
); /* send one color channel at */
462 out_8(&p
->cmap_regs
->lut
, g
); /* a time... */
463 out_8(&p
->cmap_regs
->lut
, b
);
466 switch (p
->par
.cmode
) {
467 #ifdef FBCON_HAS_CFB16
469 p
->fbcon_cmap
.cfb16
[regno
] = (regno
<< 10) | (regno
<< 5) | regno
;
472 #ifdef FBCON_HAS_CFB32
474 i
= (regno
<< 8) | regno
;
475 p
->fbcon_cmap
.cfb32
[regno
] = (i
<< 16) | i
;
482 static void do_install_cmap(int con
, struct fb_info
*info
)
486 if (fb_display
[con
].cmap
.len
)
487 fb_set_cmap(&fb_display
[con
].cmap
, 1, controlfb_setcolreg
,
490 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
491 fb_set_cmap(fb_default_cmap(size
), 1, controlfb_setcolreg
,
496 #ifdef CONFIG_FB_COMPAT_XPMAC
497 extern struct vc_mode display_info
;
498 extern struct fb_info
*console_fb_info
;
499 #endif /* CONFIG_FB_COMPAT_XPMAC */
501 static inline int control_vram_reqd(int video_mode
, int color_mode
)
503 return (control_reg_init
[video_mode
-1]->vres
504 * control_reg_init
[video_mode
-1]->hres
<< color_mode
)
505 + control_reg_init
[video_mode
-1]->offset
[color_mode
];
508 static void set_control_clock(unsigned char *params
)
510 struct adb_request req
;
513 for (i
= 0; i
< 3; ++i
) {
514 cuda_request(&req
, NULL
, 5, CUDA_PACKET
, CUDA_GET_SET_IIC
,
515 0x50, i
+ 1, params
[i
]);
516 while (!req
.complete
)
522 static void __init
init_control(struct fb_info_control
*p
)
524 struct fb_par_control parstruct
;
525 struct fb_par_control
*par
= &parstruct
;
526 struct fb_var_screeninfo var
;
528 p
->sense
= read_control_sense(p
);
529 printk(KERN_INFO
"Monitor sense value = 0x%x, ", p
->sense
);
530 /* Try to pick a video mode out of NVRAM if we have one. */
531 par
->vmode
= nvram_read_byte(NV_VMODE
);
532 if(par
->vmode
<= 0 || par
->vmode
> VMODE_MAX
|| !control_reg_init
[par
->vmode
- 1])
533 par
->vmode
= VMODE_CHOOSE
;
534 if(par
->vmode
== VMODE_CHOOSE
)
535 par
->vmode
= mac_map_monitor_sense(p
->sense
);
536 if(!control_reg_init
[par
->vmode
- 1])
537 par
->vmode
= VMODE_640_480_60
;
539 par
->cmode
= nvram_read_byte(NV_CMODE
);
540 if(par
->cmode
< CMODE_8
|| par
->cmode
> CMODE_32
)
541 par
->cmode
= CMODE_8
;
543 * Reduce the pixel size if we don't have enough VRAM.
545 while(par
->cmode
> CMODE_8
&& control_vram_reqd(par
->vmode
, par
->cmode
) > p
->total_vram
)
548 printk("using video mode %d and color mode %d.\n", par
->vmode
, par
->cmode
);
550 par
->vxres
= par
->xres
= control_reg_init
[par
->vmode
- 1]->hres
;
551 par
->yres
= control_reg_init
[par
->vmode
- 1]->vres
;
552 par
->vyres
= p
->total_vram
/ (par
->vxres
<< par
->cmode
);
553 par
->xoffset
= par
->yoffset
= 0;
555 control_init_info(&p
->info
, p
);
557 par_set
= 1; /* Debug */
559 control_par_to_var(par
, &var
);
560 var
.activate
= FB_ACTIVATE_NOW
;
561 control_set_var(&var
, -1, &p
->info
);
563 p
->info
.flags
= FBINFO_FLAG_DEFAULT
;
564 if (register_framebuffer(&p
->info
) < 0) {
569 printk(KERN_INFO
"fb%d: control display adapter\n", GET_FB_IDX(p
->info
.node
));
572 #define STORE_D2(a,d) \
573 out_8(&p->cmap_regs->addr, (a)); \
574 out_8(&p->cmap_regs->d2, (d))
576 /* Now how about actually saying, Make it so! */
577 /* Some things in here probably don't need to be done each time. */
578 static void control_set_hardware(struct fb_info_control
*p
, struct fb_par_control
*par
)
580 struct control_regvals
*init
;
581 volatile struct preg
*rp
;
585 if(PAR_EQUAL(&p
->par
, par
))
590 vmode
= p
->par
.vmode
;
591 cmode
= p
->par
.cmode
;
593 init
= control_reg_init
[vmode
- 1];
595 if (control_vram_reqd(vmode
, cmode
) > 0x200000)
597 else if (p
->control_use_bank2
)
601 if (vmode
>= VMODE_1280_960_75
&& cmode
>= CMODE_16
)
606 /* Initialize display timing registers */
607 out_le32(&p
->control_regs
->ctrl
.r
, 0x43b);
609 set_control_clock(init
->clock_params
);
611 STORE_D2(0x20, init
->radacal_ctrl
[cmode
]);
612 STORE_D2(0x21, p
->control_use_bank2
? 0 : 1);
616 rp
= &p
->control_regs
->vswin
;
617 for (i
= 0; i
< 16; ++i
, ++rp
)
618 out_le32(&rp
->r
, init
->regs
[i
]);
620 out_le32(&p
->control_regs
->pitch
.r
, par
->vxres
<< cmode
);
621 out_le32(&p
->control_regs
->mode
.r
, init
->mode
[cmode
]);
622 out_le32(&p
->control_regs
->flags
.r
, flags
);
623 out_le32(&p
->control_regs
->start_addr
.r
,
624 par
->yoffset
* (par
->vxres
<< cmode
));
625 out_le32(&p
->control_regs
->reg18
.r
, 0x1e5);
626 out_le32(&p
->control_regs
->reg19
.r
, 0);
628 for (i
= 0; i
< 16; ++i
) {
629 controlfb_setcolreg(color_table
[i
], default_red
[i
]<<8,
630 default_grn
[i
]<<8, default_blu
[i
]<<8,
631 0, (struct fb_info
*)p
);
633 /* Does the above need to be here each time? -- danj */
635 /* Turn on display */
636 out_le32(&p
->control_regs
->ctrl
.r
, ctrl
);
638 #ifdef CONFIG_FB_COMPAT_XPMAC
639 /* And let the world know the truth. */
640 if (!console_fb_info
|| console_fb_info
== &p
->info
) {
641 display_info
.height
= p
->par
.yres
;
642 display_info
.width
= p
->par
.xres
;
643 display_info
.depth
= (cmode
== CMODE_32
) ? 32 :
644 ((cmode
== CMODE_16
) ? 16 : 8);
645 display_info
.pitch
= p
->par
.vxres
<< p
->par
.cmode
;
646 display_info
.mode
= vmode
;
647 strncpy(display_info
.name
, "control",
648 sizeof(display_info
.name
));
649 display_info
.fb_address
= p
->frame_buffer_phys
650 + control_reg_init
[vmode
-1]->offset
[cmode
];
651 display_info
.cmap_adr_address
= p
->cmap_regs_phys
;
652 display_info
.cmap_data_address
= p
->cmap_regs_phys
+ 0x30;
653 display_info
.disp_reg_address
= p
->control_regs_phys
;
654 console_fb_info
= &p
->info
;
656 #endif /* CONFIG_FB_COMPAT_XPMAC */
659 int __init
control_init(void)
662 struct device_node
*dp
;
664 dp
= find_devices("control");
667 #endif /* CONFIG_FB_OF */
671 void __init
control_of_init(struct device_node
*dp
)
673 struct fb_info_control
*p
;
674 unsigned long addr
, size
;
677 if(dp
->n_addrs
!= 2) {
678 printk(KERN_ERR
"expecting 2 address for control (got %d)", dp
->n_addrs
);
681 p
= kmalloc(sizeof(*p
), GFP_ATOMIC
);
684 memset(p
, 0, sizeof(*p
));
686 /* Map in frame buffer and registers */
687 for (i
= 0; i
< dp
->n_addrs
; ++i
) {
688 addr
= dp
->addrs
[i
].address
;
689 size
= dp
->addrs
[i
].size
;
690 if (size
>= 0x800000) {
691 /* use the big-endian aperture (??) */
693 /* map at most 8MB for the frame buffer */
694 p
->frame_buffer_phys
= addr
;
695 p
->frame_buffer
= __ioremap(addr
, 0x800000, _PAGE_WRITETHRU
);
697 p
->control_regs_phys
= addr
;
698 p
->control_regs
= ioremap(addr
, size
);
701 p
->cmap_regs_phys
= 0xf301b000; /* XXX not in prom? */
702 p
->cmap_regs
= ioremap(p
->cmap_regs_phys
, 0x1000);
704 /* Work out which banks of VRAM we have installed. */
705 /* danj: I guess the card just ignores writes to nonexistant VRAM... */
706 out_8(&p
->frame_buffer
[0], 0x5a);
707 out_8(&p
->frame_buffer
[1], 0xc7);
708 asm volatile("eieio; dcbi 0,%0" : : "r" (&p
->frame_buffer
[0]) : "memory" );
709 bank1
= (in_8(&p
->frame_buffer
[0]) == 0x5a) && (in_8(&p
->frame_buffer
[1]) == 0xc7);
711 out_8(&p
->frame_buffer
[0x600000], 0xa5);
712 out_8(&p
->frame_buffer
[0x600001], 0x38);
713 asm volatile("eieio; dcbi 0,%0" : : "r" (&p
->frame_buffer
[0x600000]) : "memory" );
714 bank2
= (in_8(&p
->frame_buffer
[0x600000]) == 0xa5)
715 && (in_8(&p
->frame_buffer
[0x600001]) == 0x38);
717 p
->total_vram
= (bank1
+ bank2
) * 0x200000;
718 /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
719 p
->control_use_bank2
= !bank1
;
720 if (p
->control_use_bank2
) {
721 p
->frame_buffer
+= 0x600000;
722 p
->frame_buffer_phys
+= 0x600000;
729 * Get the monitor sense value.
730 * Note that this can be called before calibrate_delay,
731 * so we can't use udelay.
733 static int read_control_sense(struct fb_info_control
*p
)
737 out_le32(&p
->control_regs
->mon_sense
.r
, 7); /* drive all lines high */
739 out_le32(&p
->control_regs
->mon_sense
.r
, 077); /* turn off drivers */
741 sense
= (in_le32(&p
->control_regs
->mon_sense
.r
) & 0x1c0) << 2;
743 /* drive each sense line low in turn and collect the other 2 */
744 out_le32(&p
->control_regs
->mon_sense
.r
, 033); /* drive A low */
746 sense
|= (in_le32(&p
->control_regs
->mon_sense
.r
) & 0xc0) >> 2;
747 out_le32(&p
->control_regs
->mon_sense
.r
, 055); /* drive B low */
749 sense
|= ((in_le32(&p
->control_regs
->mon_sense
.r
) & 0x100) >> 5)
750 | ((in_le32(&p
->control_regs
->mon_sense
.r
) & 0x40) >> 4);
751 out_le32(&p
->control_regs
->mon_sense
.r
, 066); /* drive C low */
753 sense
|= (in_le32(&p
->control_regs
->mon_sense
.r
) & 0x180) >> 7;
755 out_le32(&p
->control_regs
->mon_sense
.r
, 077); /* turn off drivers */
760 /*********************** Various translation functions ***********************/
762 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
763 static int control_var_to_par(struct fb_var_screeninfo
*var
,
764 struct fb_par_control
*par
, const struct fb_info
*fb_info
)
766 int xres
= var
->xres
;
767 int yres
= var
->yres
;
768 int bpp
= var
->bits_per_pixel
;
769 struct fb_info_control
*p
= (struct fb_info_control
*) fb_info
;
772 * Get the video params out of 'var'. If a value doesn't fit, round it up,
773 * if it's too big, return -EINVAL.
775 * Suggestion: Round up in the following order: bits_per_pixel, xres,
776 * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
777 * bitfields, horizontal timing, vertical timing.
779 /* swiped by jonh from atyfb.c */
780 if (xres
<= 512 && yres
<= 384)
781 par
->vmode
= VMODE_512_384_60
; /* 512x384, 60Hz */
782 else 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
<= 768 && yres
<= 576)
787 par
->vmode
= VMODE_768_576_50I
; /* 768x576, 50Hz (PAL full frame) */
788 else if (xres
<= 800 && yres
<= 600)
789 par
->vmode
= VMODE_800_600_75
; /* 800x600, 75Hz */
790 else if (xres
<= 832 && yres
<= 624)
791 par
->vmode
= VMODE_832_624_75
; /* 832x624, 75Hz */
792 else if (xres
<= 1024 && yres
<= 768)
793 par
->vmode
= VMODE_1024_768_75
; /* 1024x768, 75Hz */
794 else if (xres
<= 1152 && yres
<= 870)
795 par
->vmode
= VMODE_1152_870_75
; /* 1152x870, 75Hz */
796 else if (xres
<= 1280 && yres
<= 960)
797 par
->vmode
= VMODE_1280_960_75
; /* 1280x960, 75Hz */
798 else if (xres
<= 1280 && yres
<= 1024)
799 par
->vmode
= VMODE_1280_1024_75
; /* 1280x1024, 75Hz */
801 printk(KERN_ERR
"Bad x/y res in var_to_par\n");
805 xres
= control_reg_init
[par
->vmode
-1]->hres
;
806 yres
= control_reg_init
[par
->vmode
-1]->vres
;
811 if (var
->xres_virtual
<= xres
)
813 else if(var
->xres_virtual
> xres
) {
815 } else /* NotReached at present */
816 par
->vxres
= (var
->xres_virtual
+7) & ~7;
818 if (var
->yres_virtual
<= yres
)
821 par
->vyres
= var
->yres_virtual
;
823 if (var
->xoffset
> 0 || var
->yoffset
+yres
> par
->vyres
) {
824 printk(KERN_ERR
"Bad offsets in var_to_par\n");
828 par
->xoffset
= (var
->xoffset
+7) & ~7;
829 par
->yoffset
= var
->yoffset
;
833 par
->cmode
= CMODE_8
;
835 par
->cmode
= CMODE_16
;
837 par
->cmode
= CMODE_32
;
839 printk(KERN_ERR
"Bad bpp in var_to_par\n");
843 if (control_vram_reqd(par
->vmode
, par
->cmode
) > p
->total_vram
) {
844 printk(KERN_ERR
"Too much VRAM required for vmode %d cmode %d.\n", par
->vmode
, par
->cmode
);
848 /* Check if we know about the wanted video mode */
849 if (control_reg_init
[par
->vmode
- 1] == NULL
) {
850 printk(KERN_ERR
"init is null in control_var_to_par().\n");
851 /* I'm not sure if control has any specific requirements -- */
852 /* if we have a regvals struct, we're good to go? */
859 /* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */
860 static int control_var_to_par(struct fb_var_screeninfo
*var
,
861 struct fb_par_control
*par
, const struct fb_info
*fb_info
)
863 struct fb_info_control
*p
= (struct fb_info_control
*) fb_info
;
865 if(mac_var_to_vmode(var
, &par
->vmode
, &par
->cmode
) != 0)
867 par
->xres
= par
->vxres
= vmode_attrs
[par
->vmode
- 1].hres
;
868 par
->yres
= par
->vyres
= vmode_attrs
[par
->vmode
- 1].vres
;
869 par
->xoffset
= par
->yoffset
= 0;
871 if (control_vram_reqd(par
->vmode
, par
->cmode
) > p
->total_vram
)
874 /* Check if we know about the wanted video mode */
875 if(!control_reg_init
[par
->vmode
-1]) {
876 /* I'm not sure if control has any specific requirements -- */
877 /* if we have a regvals struct, we're good to go? */
884 /*********** Convert hardware data in par to an fb_var_screeninfo ***********/
886 static void control_par_to_var(struct fb_par_control
*par
, struct fb_var_screeninfo
*var
)
888 struct control_regints
*rv
;
890 rv
= (struct control_regints
*) control_reg_init
[par
->vmode
- 1]->regs
;
892 memset(var
, 0, sizeof(*var
));
893 var
->xres
= control_reg_init
[par
->vmode
- 1]->hres
;
894 var
->yres
= control_reg_init
[par
->vmode
- 1]->vres
;
895 var
->xres_virtual
= par
->vxres
;
896 var
->yres_virtual
= par
->vyres
;
897 var
->xoffset
= par
->xoffset
;
898 var
->yoffset
= par
->yoffset
;
901 if(par
->cmode
!= CMODE_8
&& par
->cmode
!= CMODE_16
&& par
->cmode
!= CMODE_32
) {
902 printk(KERN_ERR
"Bad color mode in control_par_to_var()!\n");
903 par
->cmode
= CMODE_8
;
907 var
->bits_per_pixel
= 8;
910 var
->green
.offset
= 0;
911 var
->green
.length
= 8;
912 var
->blue
.offset
= 0;
913 var
->blue
.length
= 8;
914 var
->transp
.offset
= 0;
915 var
->transp
.length
= 0;
917 case CMODE_16
: /* RGB 555 */
918 var
->bits_per_pixel
= 16;
919 var
->red
.offset
= 10;
921 var
->green
.offset
= 5;
922 var
->green
.length
= 5;
923 var
->blue
.offset
= 0;
924 var
->blue
.length
= 5;
925 var
->transp
.offset
= 0;
926 var
->transp
.length
= 0;
928 case CMODE_32
: /* RGB 888 */
929 var
->bits_per_pixel
= 32;
930 var
->red
.offset
= 16;
932 var
->green
.offset
= 8;
933 var
->green
.length
= 8;
934 var
->blue
.offset
= 0;
935 var
->blue
.length
= 8;
936 var
->transp
.offset
= 24;
937 var
->transp
.length
= 8;
940 var
->red
.msb_right
= 0;
941 var
->green
.msb_right
= 0;
942 var
->blue
.msb_right
= 0;
943 var
->transp
.msb_right
= 0;
948 var
->vmode
= FB_VMODE_NONINTERLACED
;
950 var
->left_margin
= (rv
->heblank
- rv
->hesync
)
951 << ((par
->vmode
> 18) ? 2 : 1);
952 var
->right_margin
= (rv
->hssync
- rv
->hsblank
)
953 << ((par
->vmode
> 18) ? 2 : 1);
954 var
->hsync_len
= (rv
->hperiod
+ 2 - rv
->hssync
+ rv
->hesync
)
955 << ((par
->vmode
> 18) ? 2 : 1);
957 var
->upper_margin
= (rv
->veblank
- rv
->vesync
) >> 1;
958 var
->lower_margin
= (rv
->vssync
- rv
->vsblank
) >> 1;
959 var
->vsync_len
= (rv
->vperiod
- rv
->vssync
+ rv
->vesync
) >> 1;
961 /* Acording to macmodes.c... */
962 if((par
->vmode
>= 9 && par
->vmode
<= 12) ||
963 (par
->vmode
>= 16 && par
->vmode
<= 18) ||
966 var
->sync
= FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
;
968 var
->sync
= 0; /* I suppose */
971 /* The reason these are both here: with my revised margin calculations, */
972 /* these SHOULD both give the same answer for each mode. Some day I */
973 /* will sit down and check the rest. Works perfectly for vmode 13. */
976 /* jonh's pixclocks...*/
977 /* no long long support in the kernel :-( */
978 /* this splittig trick will work if xres > 232 */
979 var
->pixclock
= 1000000000/
980 (var
->left_margin
+var
->xres
+var
->right_margin
+var
->hsync_len
);
981 var
->pixclock
*= 1000;
982 var
->pixclock
/= vmode_attrs
[par
->vmode
-1].vfreq
*
983 (var
->upper_margin
+var
->yres
+var
->lower_margin
+var
->vsync_len
);
986 /* 10^12 * clock_params[0] / (3906400 * clock_params[1] * 2^clock_params[2]) */
987 /* (10^12 * clock_params[0] / (3906400 * clock_params[1])) >> clock_params[2] */
988 /* (255990.17 * clock_params[0] / clock_params[1]) >> clock_params[2] */
989 var
->pixclock
= 255990 * control_reg_init
[par
->vmode
-1]->clock_params
[0];
990 var
->pixclock
/= control_reg_init
[par
->vmode
-1]->clock_params
[1];
991 var
->pixclock
>>= control_reg_init
[par
->vmode
-1]->clock_params
[2];
995 static void control_par_to_fix(struct fb_par_control
*par
, struct fb_fix_screeninfo
*fix
,
996 struct fb_info_control
*p
)
998 memset(fix
, 0, sizeof(*fix
));
999 strcpy(fix
->id
, "control");
1000 fix
->mmio_start
= p
->control_regs_phys
;
1001 fix
->mmio_len
= sizeof(struct control_regs
);
1002 fix
->type
= FB_TYPE_PACKED_PIXELS
;
1012 fix
->smem_start
= (p
->frame_buffer_phys
1013 + control_reg_init
[par
->vmode
-1]->offset
[par
->cmode
]);
1014 fix
->smem_len
= p
->total_vram
- control_reg_init
[par
->vmode
-1]->offset
[par
->cmode
];
1015 fix
->visual
= (par
->cmode
== CMODE_8
) ?
1016 FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_DIRECTCOLOR
;
1017 fix
->line_length
= par
->vxres
<< par
->cmode
;
1020 /* We never initialize any display except for p->disp.
1021 And p->disp is already memset to 0. So no memset here.
1022 [Found by Takashi Oe]
1024 static void control_par_to_display(struct fb_par_control
*par
,
1025 struct display
*disp
, struct fb_fix_screeninfo
*fix
, struct fb_info_control
*p
)
1027 /* memset(disp, 0, sizeof(*disp)); */
1028 disp
->type
= fix
->type
;
1029 disp
->can_soft_blank
= 1;
1030 disp
->scrollmode
= SCROLL_YNOMOVE
| SCROLL_YNOPARTIAL
;
1031 disp
->ypanstep
= fix
->ypanstep
;
1032 disp
->ywrapstep
= fix
->ywrapstep
;
1034 disp
->type_aux
= fix
->type_aux
;
1035 disp
->cmap
.red
= NULL
; /* ??? danj */
1036 disp
->cmap
.green
= NULL
;
1037 disp
->cmap
.blue
= NULL
;
1038 disp
->cmap
.transp
= NULL
;
1039 /* Yeah, I realize I just set 0 = 0. */
1042 control_par_to_var(par
, &disp
->var
);
1043 disp
->screen_base
= (char *) p
->frame_buffer
1044 + control_reg_init
[par
->vmode
-1]->offset
[par
->cmode
];
1045 disp
->visual
= fix
->visual
;
1046 disp
->line_length
= fix
->line_length
;
1047 control_set_dispsw(disp
, par
->cmode
, p
);
1050 static void control_cfb16_revc(struct display
*p
, int xx
, int yy
)
1053 int bytes
= p
->next_line
, rows
;
1055 dest
= p
->screen_base
+ yy
* fontheight(p
) * bytes
+ xx
* fontwidth(p
)*2;
1056 for (rows
= fontheight(p
); rows
--; dest
+= bytes
) {
1057 switch (fontwidth(p
)) {
1059 ((u32
*)dest
)[6] ^= 0x3def3def; ((u32
*)dest
)[7] ^= 0x3def3def;
1062 ((u32
*)dest
)[4] ^= 0x3def3def; ((u32
*)dest
)[5] ^= 0x3def3def;
1065 ((u32
*)dest
)[2] ^= 0x3def3def; ((u32
*)dest
)[3] ^= 0x3def3def;
1068 ((u32
*)dest
)[0] ^= 0x3def3def; ((u32
*)dest
)[1] ^= 0x3def3def;
1073 static void control_cfb32_revc(struct display
*p
, int xx
, int yy
)
1076 int bytes
= p
->next_line
, rows
;
1078 dest
= p
->screen_base
+ yy
* fontheight(p
) * bytes
+ xx
* fontwidth(p
) * 4;
1079 for (rows
= fontheight(p
); rows
--; dest
+= bytes
) {
1080 switch (fontwidth(p
)) {
1082 ((u32
*)dest
)[12] ^= 0x0f0f0f0f; ((u32
*)dest
)[13] ^= 0x0f0f0f0f;
1083 ((u32
*)dest
)[14] ^= 0x0f0f0f0f; ((u32
*)dest
)[15] ^= 0x0f0f0f0f;
1086 ((u32
*)dest
)[8] ^= 0x0f0f0f0f; ((u32
*)dest
)[9] ^= 0x0f0f0f0f;
1087 ((u32
*)dest
)[10] ^= 0x0f0f0f0f; ((u32
*)dest
)[11] ^= 0x0f0f0f0f;
1090 ((u32
*)dest
)[4] ^= 0x0f0f0f0f; ((u32
*)dest
)[5] ^= 0x0f0f0f0f;
1091 ((u32
*)dest
)[6] ^= 0x0f0f0f0f; ((u32
*)dest
)[7] ^= 0x0f0f0f0f;
1094 ((u32
*)dest
)[0] ^= 0x0f0f0f0f; ((u32
*)dest
)[1] ^= 0x0f0f0f0f;
1095 ((u32
*)dest
)[2] ^= 0x0f0f0f0f; ((u32
*)dest
)[3] ^= 0x0f0f0f0f;
1101 static struct display_switch control_cfb16
= {
1102 fbcon_cfb16_setup
, fbcon_cfb16_bmove
, fbcon_cfb16_clear
, fbcon_cfb16_putc
,
1103 fbcon_cfb16_putcs
, control_cfb16_revc
, NULL
, NULL
, fbcon_cfb16_clear_margins
,
1104 FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1107 static struct display_switch control_cfb32
= {
1108 fbcon_cfb32_setup
, fbcon_cfb32_bmove
, fbcon_cfb32_clear
, fbcon_cfb32_putc
,
1109 fbcon_cfb32_putcs
, control_cfb32_revc
, NULL
, NULL
, fbcon_cfb32_clear_margins
,
1110 FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1114 static void control_set_dispsw(struct display
*disp
, int cmode
, struct fb_info_control
*p
)
1117 #ifdef FBCON_HAS_CFB8
1119 disp
->dispsw
= &fbcon_cfb8
;
1122 #ifdef FBCON_HAS_CFB16
1124 disp
->dispsw
= &control_cfb16
;
1125 disp
->dispsw_data
= p
->fbcon_cmap
.cfb16
;
1128 #ifdef FBCON_HAS_CFB32
1130 disp
->dispsw
= &control_cfb32
;
1131 disp
->dispsw_data
= p
->fbcon_cmap
.cfb32
;
1135 disp
->dispsw
= &fbcon_dummy
;
1140 static void control_init_info(struct fb_info
*info
, struct fb_info_control
*p
)
1142 strcpy(info
->modename
, "control");
1143 info
->node
= -1; /* ??? danj */
1144 info
->fbops
= &controlfb_ops
;
1145 info
->disp
= &p
->display
;
1146 strcpy(info
->fontname
, fontname
);
1147 info
->changevar
= NULL
;
1148 info
->switch_con
= &controlfb_switch
;
1149 info
->updatevar
= &controlfb_updatevar
;
1150 info
->blank
= &controlfb_blank
;
1153 /* Parse user speficied options (`video=controlfb:') */
1154 void __init
control_setup(char *options
)
1158 if (!options
|| !*options
)
1161 for (this_opt
= strtok(options
, ","); this_opt
;
1162 this_opt
= strtok(NULL
, ",")) {
1163 if (!strncmp(this_opt
, "font:", 5)) {
1168 for (i
= 0; i
< sizeof(fontname
) - 1; i
++)
1169 if (!*p
|| *p
== ' ' || *p
== ',')
1171 memcpy(fontname
, this_opt
+ 5, i
);
1174 if (!strncmp(this_opt
, "vmode:", 6)) {
1175 int vmode
= simple_strtoul(this_opt
+6, NULL
, 0);
1176 if (vmode
> 0 && vmode
<= VMODE_MAX
)
1177 default_vmode
= vmode
;
1178 } else if (!strncmp(this_opt
, "cmode:", 6)) {
1179 int depth
= simple_strtoul(this_opt
+6, NULL
, 0);
1184 default_cmode
= depth
;
1187 default_cmode
= CMODE_8
;
1191 default_cmode
= CMODE_16
;
1195 default_cmode
= CMODE_32
;
1203 static int controlfb_pan_display(struct fb_var_screeninfo
*var
,
1204 struct controlfb_par
*par
,
1205 const struct fb_info
*fb_info
)
1208 * Pan (or wrap, depending on the `vmode' field) the display using the
1209 * `xoffset' and `yoffset' fields of the `var' structure.
1210 * If the values don't fit, return -EINVAL.