2 * linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682
4 * Copyright (C) 1998 Vladimir Roganov and Gleb Raiko
6 * This driver is partly based on the Frame buffer device for ATI Mach64
7 * and partially on VESA-related code.
9 * Copyright (C) 1997-1998 Geert Uytterhoeven
10 * Copyright (C) 1998 Bernd Harries
11 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
13 * This file is subject to the terms and conditions of the GNU General Public
14 * License. See the file COPYING in the main directory of this archive for
18 /******************************************************************************
21 Despite of IGA Card has advanced graphic acceleration,
22 initial version is almost dummy and does not support it.
23 Support for video modes and acceleration must be added
24 together with accelerated X-Windows driver implementation.
26 (Anyone to help with this?)
28 Most important thing at this moment is that we have working
29 JavaEngine1 console & X with new console interface.
31 ******************************************************************************/
33 #include <linux/module.h>
34 #include <linux/kernel.h>
35 #include <linux/errno.h>
36 #include <linux/string.h>
38 #include <linux/tty.h>
39 #include <linux/malloc.h>
40 #include <linux/vmalloc.h>
41 #include <linux/delay.h>
42 #include <linux/interrupt.h>
44 #include <linux/selection.h>
45 #include <linux/console.h>
46 #include <linux/init.h>
47 #include <linux/pci.h>
48 #include <linux/nvram.h>
50 #include <linux/vt_kern.h>
59 #include <video/fbcon.h>
60 #include <video/fbcon-cfb8.h>
61 #include <video/fbcon-cfb16.h>
62 #include <video/fbcon-cfb24.h>
63 #include <video/fbcon-cfb32.h>
67 static char igafb_name
[16] = "IGA 1682";
68 static char fontname
[40] __initdata
= { 0 };
74 unsigned long prot_flag
;
75 unsigned long prot_mask
;
79 struct fb_info fb_info
;
80 unsigned long frame_buffer_phys
;
81 unsigned long frame_buffer
;
82 unsigned long io_base_phys
;
83 unsigned long io_base
;
85 struct pci_mmap_map
*mmap_map
;
86 struct { u_short blue
, green
, red
, pad
; } palette
[256];
90 struct display_switch dispsw
;
92 #ifdef FBCON_HAS_CFB16
95 #ifdef FBCON_HAS_CFB24
98 #ifdef FBCON_HAS_CFB32
110 struct fb_var_screeninfo default_var
= {
111 /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
112 640, 480, 640, 480, 0, 0, 8, 0,
113 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
114 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
115 0, FB_VMODE_NONINTERLACED
119 struct fb_var_screeninfo default_var_1024x768 __initdata
= {
120 /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
121 1024, 768, 1024, 768, 0, 0, 8, 0,
122 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
123 0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3,
124 FB_SYNC_HOR_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
127 struct fb_var_screeninfo default_var_1152x900 __initdata
= {
128 /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
129 1152, 900, 1152, 900, 0, 0, 8, 0,
130 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
131 0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3,
132 FB_SYNC_HOR_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
135 struct fb_var_screeninfo default_var_1280x1024 __initdata
= {
136 /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
137 1280, 1024, 1280, 1024, 0, 0, 8, 0,
138 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
139 0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3,
140 FB_SYNC_HOR_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
144 * Memory-mapped I/O functions for Sparc PCI
146 static inline unsigned char pci_inb (struct fb_info_iga
*info
,
149 return *(volatile unsigned char*)(info
->io_base
+ reg
);
151 static inline void pci_outb (struct fb_info_iga
*info
, unsigned char c
,
154 *(volatile unsigned char*)(info
->io_base
+ reg
) = c
;
156 static inline unsigned int iga_inb(struct fb_info_iga
*info
,
157 unsigned int reg
, unsigned int idx
)
159 pci_outb(info
, idx
, reg
);
160 return pci_inb(info
, reg
+ 1);
162 static inline void iga_outb(struct fb_info_iga
*info
, unsigned char val
,
163 unsigned int reg
, unsigned int idx
)
165 pci_outb(info
, idx
, reg
);
166 pci_outb(info
, val
, reg
+1);
169 #endif /* __sparc__ */
172 * Very important functionality for the JavaEngine1 computer:
173 * make screen border black (usign special IGA registers)
175 static void iga_blank_border(struct fb_info_iga
*info
)
179 for (i
=0; i
< 3; i
++)
180 iga_outb(info
, 0, IGA_EXT_CNTRL
, IGA_IDX_OVERSCAN_COLOR
+ i
);
185 * Frame buffer device API
189 * Open/Release the frame buffer device
192 static int igafb_open(struct fb_info
*info
, int user
)
195 * Nothing, only a usage count for the moment
201 static int igafb_release(struct fb_info
*info
, int user
)
207 static int igafb_update_var(int con
, struct fb_info
*info
)
212 static int igafb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
213 struct fb_info
*info
)
215 struct fb_info_iga
*fb
= (struct fb_info_iga
*)info
;
217 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
218 strcpy(fix
->id
, igafb_name
);
220 fix
->smem_start
= fb
->frame_buffer
;
221 fix
->smem_len
= fb
->total_vram
;
226 fix
->type
= FB_TYPE_PACKED_PIXELS
;
228 fix
->line_length
= default_var
.xres
* (default_var
.bits_per_pixel
/8);
229 fix
->visual
= default_var
.bits_per_pixel
<= 8 ? FB_VISUAL_PSEUDOCOLOR
230 : FB_VISUAL_DIRECTCOLOR
;
234 static int igafb_get_var(struct fb_var_screeninfo
*var
, int con
,
235 struct fb_info
*info
)
238 memcpy(var
, &default_var
, sizeof(struct fb_var_screeninfo
));
240 *var
= fb_display
[con
].var
;
244 static int igafb_set_var(struct fb_var_screeninfo
*var
, int con
,
245 struct fb_info
*info
)
247 memcpy(var
, &default_var
, sizeof(struct fb_var_screeninfo
));
252 static int igafb_mmap(struct fb_info
*info
, struct file
*file
,
253 struct vm_area_struct
*vma
)
255 struct fb_info_iga
*fb
= (struct fb_info_iga
*)info
;
256 unsigned int size
, page
, map_size
= 0;
257 unsigned long map_offset
= 0;
263 size
= vma
->vm_end
- vma
->vm_start
;
264 if (vma
->vm_offset
& ~PAGE_MASK
)
267 /* To stop the swapper from even considering these pages. */
268 vma
->vm_flags
|= (VM_SHM
| VM_LOCKED
);
270 /* Each page, see which map applies */
271 for (page
= 0; page
< size
; ) {
273 for (i
= 0; fb
->mmap_map
[i
].size
; i
++) {
274 unsigned long start
= fb
->mmap_map
[i
].voff
;
275 unsigned long end
= start
+ fb
->mmap_map
[i
].size
;
276 unsigned long offset
= vma
->vm_offset
+ page
;
283 map_size
= fb
->mmap_map
[i
].size
- (offset
- start
);
284 map_offset
= fb
->mmap_map
[i
].poff
+ (offset
- start
);
291 if (page
+ map_size
> size
)
292 map_size
= size
- page
;
294 pgprot_val(vma
->vm_page_prot
) &= ~(fb
->mmap_map
[i
].prot_mask
);
295 pgprot_val(vma
->vm_page_prot
) |= fb
->mmap_map
[i
].prot_flag
;
297 if (remap_page_range(vma
->vm_start
+ page
, map_offset
,
298 map_size
, vma
->vm_page_prot
))
307 vma
->vm_flags
|= VM_IO
;
312 if (info
->display_fg
)
313 lastconsole
= info
->display_fg
->vc_num
;
315 if (fb
->consolecnt
&& fb_display
[lastconsole
].fb_info
==info
) {
316 fb
->vtconsole
= lastconsole
;
317 vt_cons
[lastconsole
]->vc_mode
= KD_GRAPHICS
;
322 #endif /* __sparc__ */
325 static int iga_getcolreg(unsigned regno
, unsigned *red
, unsigned *green
,
326 unsigned *blue
, unsigned *transp
,
327 struct fb_info
*fb_info
)
330 * Read a single color register and split it into colors/transparent.
331 * Return != 0 for invalid regno.
333 struct fb_info_iga
*info
= (struct fb_info_iga
*) fb_info
;
335 if (regno
>= info
->video_cmap_len
)
338 *red
= info
->palette
[regno
].red
;
339 *green
= info
->palette
[regno
].green
;
340 *blue
= info
->palette
[regno
].blue
;
345 static int iga_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
346 unsigned blue
, unsigned transp
,
347 struct fb_info
*fb_info
)
350 * Set a single color register. The values supplied are
351 * already rounded down to the hardware's capabilities
352 * (according to the entries in the `var' structure). Return
353 * != 0 for invalid regno.
356 struct fb_info_iga
*info
= (struct fb_info_iga
*) fb_info
;
358 if (regno
>= info
->video_cmap_len
)
361 info
->palette
[regno
].red
= red
;
362 info
->palette
[regno
].green
= green
;
363 info
->palette
[regno
].blue
= blue
;
365 pci_outb(info
, regno
, DAC_W_INDEX
);
366 pci_outb(info
, red
, DAC_DATA
);
367 pci_outb(info
, green
, DAC_DATA
);
368 pci_outb(info
, blue
, DAC_DATA
);
371 switch (default_var
.bits_per_pixel
) {
372 #ifdef FBCON_HAS_CFB16
374 info
->fbcon_cmap
.cfb16
[regno
] =
375 (regno
<< 10) | (regno
<< 5) | regno
;
378 #ifdef FBCON_HAS_CFB24
380 info
->fbcon_cmap
.cfb24
[regno
] =
381 (regno
<< 16) | (regno
<< 8) | regno
;
384 #ifdef FBCON_HAS_CFB32
386 i
= (regno
<< 8) | regno
;
387 info
->fbcon_cmap
.cfb32
[regno
] = (i
<< 16) | i
;
394 static void do_install_cmap(int con
, struct fb_info
*fb_info
)
396 struct fb_info_iga
*info
= (struct fb_info_iga
*) fb_info
;
398 if (con
!= info
->currcon
)
400 if (fb_display
[con
].cmap
.len
)
401 fb_set_cmap(&fb_display
[con
].cmap
, 1,
402 iga_setcolreg
, &info
->fb_info
);
404 fb_set_cmap(fb_default_cmap(info
->video_cmap_len
), 1,
405 iga_setcolreg
, &info
->fb_info
);
408 static int igafb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
409 struct fb_info
*fb_info
)
411 struct fb_info_iga
*info
= (struct fb_info_iga
*) fb_info
;
413 if (con
== info
->currcon
) /* current console? */
414 return fb_get_cmap(cmap
, kspc
, iga_getcolreg
, &info
->fb_info
);
415 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
416 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
418 fb_copy_cmap(fb_default_cmap(info
->video_cmap_len
),
423 static int igafb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
424 struct fb_info
*info
)
427 struct fb_info_iga
*fb
= (struct fb_info_iga
*) info
;
429 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated? */
430 err
= fb_alloc_cmap(&fb_display
[con
].cmap
,
431 fb
->video_cmap_len
,0);
435 if (con
== fb
->currcon
) /* current console? */
436 return fb_set_cmap(cmap
, kspc
, iga_setcolreg
, info
);
438 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
442 static int igafb_pan_display(struct fb_var_screeninfo
*var
, int con
,
443 struct fb_info
*info
)
449 static int igafb_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
450 u_long arg
, int con
, struct fb_info
*info
)
456 * Framebuffer option structure
458 static struct fb_ops igafb_ops
= {
475 static void igafb_set_disp(int con
, struct fb_info_iga
*info
)
477 struct fb_fix_screeninfo fix
;
478 struct display
*display
;
479 struct display_switch
*sw
;
482 display
= &fb_display
[con
];
484 display
= &info
->disp
; /* used during initialization */
486 igafb_get_fix(&fix
, con
, &info
->fb_info
);
488 memset(display
, 0, sizeof(struct display
));
489 display
->screen_base
= (char*)info
->frame_buffer
;
490 display
->visual
= fix
.visual
;
491 display
->type
= fix
.type
;
492 display
->type_aux
= fix
.type_aux
;
493 display
->ypanstep
= fix
.ypanstep
;
494 display
->ywrapstep
= fix
.ywrapstep
;
495 display
->line_length
= fix
.line_length
;
496 display
->next_line
= fix
.line_length
;
497 display
->can_soft_blank
= 0;
498 display
->inverse
= 0;
499 igafb_get_var(&display
->var
, -1, &info
->fb_info
);
501 switch (default_var
.bits_per_pixel
) {
502 #ifdef FBCON_HAS_CFB8
507 #ifdef FBCON_HAS_CFB16
511 display
->dispsw_data
= fbcon_cmap
.cfb16
;
514 #ifdef FBCON_HAS_CFB24
517 display
->dispsw_data
= fbcon_cmap
.cfb24
;
520 #ifdef FBCON_HAS_CFB32
523 display
->dispsw_data
= fbcon_cmap
.cfb32
;
529 memcpy(&info
->dispsw
, sw
, sizeof(*sw
));
530 display
->dispsw
= &info
->dispsw
;
532 display
->scrollmode
= SCROLL_YREDRAW
;
533 info
->dispsw
.bmove
= fbcon_redraw_bmove
;
536 static int igafb_switch(int con
, struct fb_info
*fb_info
)
538 struct fb_info_iga
*info
= (struct fb_info_iga
*) fb_info
;
540 /* Do we have to save the colormap? */
541 if (fb_display
[info
->currcon
].cmap
.len
)
542 fb_get_cmap(&fb_display
[info
->currcon
].cmap
, 1,
543 iga_getcolreg
, fb_info
);
546 /* Install new colormap */
547 do_install_cmap(con
, fb_info
);
548 igafb_update_var(con
, fb_info
);
554 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
556 static void igafb_blank(int blank
, struct fb_info
*info
)
562 static int __init
iga_init(struct fb_info_iga
*info
)
564 char vramsz
= iga_inb(info
, IGA_EXT_CNTRL
, IGA_IDX_EXT_BUS_CNTL
)
568 info
->total_vram
= 0x100000;
571 info
->total_vram
= 0x200000;
574 case MEM_SIZE_RESERVED
:
575 info
->total_vram
= 0x400000;
579 if (default_var
.bits_per_pixel
> 8) {
580 info
->video_cmap_len
= 16;
583 for(i
= 0; i
< 16; i
++) {
585 info
->palette
[i
].red
= default_red
[j
];
586 info
->palette
[i
].green
= default_grn
[j
];
587 info
->palette
[i
].blue
= default_blu
[j
];
589 info
->video_cmap_len
= 256;
592 strcpy(info
->fb_info
.modename
, igafb_name
);
593 info
->fb_info
.node
= -1;
594 info
->fb_info
.fbops
= &igafb_ops
;
595 info
->fb_info
.disp
= &info
->disp
;
596 strcpy(info
->fb_info
.fontname
, fontname
);
597 info
->fb_info
.changevar
= NULL
;
598 info
->fb_info
.switch_con
= &igafb_switch
;
599 info
->fb_info
.updatevar
= &igafb_update_var
;
600 info
->fb_info
.blank
= &igafb_blank
;
601 info
->fb_info
.flags
=FBINFO_FLAG_DEFAULT
;
605 for (j
= 0; j
< 16; j
++) {
607 info
->palette
[j
].red
= default_red
[k
];
608 info
->palette
[j
].green
= default_grn
[k
];
609 info
->palette
[j
].blue
= default_blu
[k
];
613 igafb_set_disp(-1, info
);
615 if (register_framebuffer(&info
->fb_info
) < 0)
618 printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n",
619 GET_FB_IDX(info
->fb_info
.node
), igafb_name
,
620 info
->frame_buffer_phys
, info
->total_vram
>> 20);
622 iga_blank_border(info
);
627 int __init
igafb_init(void)
629 struct pci_dev
*pdev
;
630 struct fb_info_iga
*info
;
632 extern int con_is_present(void);
635 /* Do not attach when we have a serial console. */
636 if (!con_is_present())
639 pdev
= pci_find_device(PCI_VENDOR_ID_INTERG
,
640 PCI_DEVICE_ID_INTERG_1682
, 0);
642 pdev
= pci_find_device(PCI_VENDOR_ID_INTERG
,
649 info
= kmalloc(sizeof(struct fb_info_iga
), GFP_ATOMIC
);
651 printk("igafb_init: can't alloc fb_info_iga\n");
654 memset(info
, 0, sizeof(struct fb_info_iga
));
656 info
->frame_buffer
= pdev
->resource
[0].start
;
657 if (!info
->frame_buffer
) {
662 pcibios_read_config_dword(0, pdev
->devfn
,
664 (unsigned int*)&addr
);
667 info
->frame_buffer_phys
= addr
& PCI_BASE_ADDRESS_MEM_MASK
;
671 info
->io_base_phys
= info
->frame_buffer_phys
;
674 * The right test would be to look if there is a base I/O address.
675 * But it appears that IGA 1682 reuses _memory_ address as a base
679 info
->io_base
= (int) sparc_alloc_io(info
->frame_buffer_phys
|
680 0x00800000, NULL
, 0x1000, "iga", 0, 0);
682 /* Obtain virtual address and correct physical by PCIC shift */
683 info
->io_base
= pcic_alloc_io(&info
->io_base_phys
);
685 if (!info
->io_base
) {
691 * Figure mmap addresses from PCI config space.
692 * We need two regions: for video memory and for I/O ports.
693 * Later one can add region for video coprocessor registers.
694 * However, mmap routine loops until size != 0, so we put
695 * one additional region with size == 0.
698 info
->mmap_map
= kmalloc(4 * sizeof(*info
->mmap_map
), GFP_ATOMIC
);
699 if (!info
->mmap_map
) {
700 printk("igafb_init: can't alloc mmap_map\n");
701 /* XXX Here we left I/O allocated */
706 memset(info
->mmap_map
, 0, 4 * sizeof(*info
->mmap_map
));
709 * Set default vmode and cmode from PROM properties.
712 struct pcidev_cookie
*cookie
= pdev
->sysdata
;
713 int node
= cookie
->prom_node
;
714 int width
= prom_getintdefault(node
, "width", 1024);
715 int height
= prom_getintdefault(node
, "height", 768);
716 int depth
= prom_getintdefault(node
, "depth", 8);
720 default_var
= default_var_1024x768
;
724 default_var
= default_var_1152x900
;
728 default_var
= default_var_1280x1024
;
736 default_var
.bits_per_pixel
= 8;
739 default_var
.bits_per_pixel
= 16;
742 default_var
.bits_per_pixel
= 24;
745 default_var
.bits_per_pixel
= 32;
753 if (!iga_init(info
)) {
755 kfree(info
->mmap_map
);
761 * Add /dev/fb mmap values.
764 /* First region is for video memory */
765 info
->mmap_map
[0].voff
= 0x0;
766 info
->mmap_map
[0].poff
= info
->frame_buffer_phys
& PAGE_MASK
;
767 info
->mmap_map
[0].size
= info
->total_vram
& PAGE_MASK
;
768 info
->mmap_map
[0].prot_mask
= SRMMU_CACHE
;
769 info
->mmap_map
[0].prot_flag
= SRMMU_WRITE
;
771 /* Second region is for I/O ports */
772 info
->mmap_map
[1].voff
= info
->frame_buffer_phys
& PAGE_MASK
;
773 info
->mmap_map
[1].poff
= info
->io_base_phys
& PAGE_MASK
;
774 info
->mmap_map
[1].size
= PAGE_SIZE
* 2; /* X wants 2 pages */
775 info
->mmap_map
[1].prot_mask
= SRMMU_CACHE
;
776 info
->mmap_map
[1].prot_flag
= SRMMU_WRITE
;
777 #endif /* __sparc__ */
782 int __init
igafb_setup(char *options
)
786 if (!options
|| !*options
)
789 for (this_opt
= strtok(options
, ","); this_opt
;
790 this_opt
= strtok(NULL
, ",")) {
791 if (!strncmp(this_opt
, "font:", 5)) {
796 for (i
= 0; i
< sizeof(fontname
) - 1; i
++)
797 if (!*p
|| *p
== ' ' || *p
== ',')
799 memcpy(fontname
, this_opt
+ 5, i
);