make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / video / igafb.c
1 /*
2  *  linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682
3  *
4  *      Copyright (C) 1998  Vladimir Roganov and Gleb Raiko
5  *
6  *  This driver is partly based on the Frame buffer device for ATI Mach64
7  *  and partially on VESA-related code.
8  *
9  *      Copyright (C) 1997-1998  Geert Uytterhoeven
10  *      Copyright (C) 1998  Bernd Harries
11  *      Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
12  *
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
15  *  more details.
16  */
17
18 /******************************************************************************
19
20   TODO:
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.
25
26        Most important thing at this moment is that we have working
27        JavaEngine1  console & X  with new console interface.
28
29 ******************************************************************************/
30
31 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/errno.h>
34 #include <linux/string.h>
35 #include <linux/mm.h>
36 #include <linux/tty.h>
37 #include <linux/slab.h>
38 #include <linux/vmalloc.h>
39 #include <linux/delay.h>
40 #include <linux/interrupt.h>
41 #include <linux/fb.h>
42 #include <linux/selection.h>
43 #include <linux/console.h>
44 #include <linux/init.h>
45 #include <linux/pci.h>
46 #include <linux/nvram.h>
47 #include <linux/kd.h>
48 #include <linux/vt_kern.h>
49
50 #include <asm/io.h>
51
52 #ifdef __sparc__
53 #include <asm/pbm.h>
54 #include <asm/pcic.h>
55 #endif
56
57 #include <video/fbcon.h>
58 #include <video/fbcon-cfb8.h>
59 #include <video/fbcon-cfb16.h>
60 #include <video/fbcon-cfb24.h>
61 #include <video/fbcon-cfb32.h>
62
63 #include "iga.h"
64
65 static char igafb_name[16] = "IGA 1682";
66 static char fontname[40] __initdata = { 0 };
67
68 struct pci_mmap_map {
69     unsigned long voff;
70     unsigned long poff;
71     unsigned long size;
72     unsigned long prot_flag;
73     unsigned long prot_mask;
74 };
75
76 struct fb_info_iga {
77     struct fb_info fb_info;
78     unsigned long frame_buffer_phys;
79     char *frame_buffer;
80     unsigned long io_base_phys;
81     unsigned long io_base;
82     u32 total_vram;
83     struct pci_mmap_map *mmap_map;
84     struct { u_short blue, green, red, pad; } palette[256];
85     int video_cmap_len;
86     int currcon;
87     struct display disp;
88     struct display_switch dispsw; 
89     union {
90 #ifdef FBCON_HAS_CFB16
91             u16 cfb16[16];  
92 #endif
93 #ifdef FBCON_HAS_CFB24
94             u32 cfb24[16];
95 #endif
96 #ifdef FBCON_HAS_CFB32
97             u32 cfb32[16];
98 #endif
99     } fbcon_cmap;
100 #ifdef __sparc__
101     u8 open;
102     u8 mmaped;
103     int vtconsole;
104     int consolecnt;
105 #endif
106 };
107
108 struct fb_var_screeninfo default_var = {
109     /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
110     640, 480, 640, 480, 0, 0, 8, 0,
111     {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
112     0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
113     0, FB_VMODE_NONINTERLACED
114 };
115
116 #ifdef __sparc__
117 struct fb_var_screeninfo default_var_1024x768 __initdata = {
118     /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
119     1024, 768, 1024, 768, 0, 0, 8, 0,
120     {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
121     0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3,
122     FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
123 };
124
125 struct fb_var_screeninfo default_var_1152x900 __initdata = {
126     /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
127     1152, 900, 1152, 900, 0, 0, 8, 0,
128     {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
129     0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3,
130     FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
131 };
132
133 struct fb_var_screeninfo default_var_1280x1024 __initdata = {
134     /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
135     1280, 1024, 1280, 1024, 0, 0, 8, 0,
136     {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
137     0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3,
138     FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
139 };
140
141 /*
142  *   Memory-mapped I/O functions for Sparc PCI
143  *
144  * On sparc we happen to access I/O with memory mapped functions too.
145  */ 
146 #define pci_inb(info, reg)        readb(info->io_base+(reg))
147 #define pci_outb(info, val, reg)  writeb(val, info->io_base+(reg))
148
149 static inline unsigned int iga_inb(struct fb_info_iga *info,
150                                    unsigned int reg, unsigned int idx )
151 {
152         pci_outb(info, idx, reg);
153         return pci_inb(info, reg + 1);
154 }
155
156 static inline void iga_outb(struct fb_info_iga *info, unsigned char val,
157                             unsigned int reg, unsigned int idx )
158 {
159         pci_outb(info, idx, reg);
160         pci_outb(info, val, reg+1);
161 }
162
163 #endif /* __sparc__ */
164
165 /*
166  *  Very important functionality for the JavaEngine1 computer:
167  *  make screen border black (usign special IGA registers) 
168  */
169 static void iga_blank_border(struct fb_info_iga *info)
170 {
171         int i;
172
173 #if 0
174         /*
175          * PROM does this for us, so keep this code as a reminder
176          * about required read from 0x3DA and writing of 0x20 in the end.
177          */
178         (void) pci_inb(info, 0x3DA);            /* required for every access */
179         pci_outb(info, IGA_IDX_VGA_OVERSCAN, IGA_ATTR_CTL);
180         (void) pci_inb(info, IGA_ATTR_CTL+1);
181         pci_outb(info, 0x38, IGA_ATTR_CTL);
182         pci_outb(info, 0x20, IGA_ATTR_CTL);     /* re-enable visual */
183 #endif
184         /*
185          * This does not work as it was designed because the overscan
186          * color is looked up in the palette. Therefore, under X11
187          * overscan changes color.
188          */
189         for (i=0; i < 3; i++)
190                 iga_outb(info, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
191 }
192
193
194 /*
195  *  Frame buffer device API
196  */
197
198 static int igafb_update_var(int con, struct fb_info *info)
199 {
200         return 0;
201 }
202
203 static int igafb_get_fix(struct fb_fix_screeninfo *fix, int con,
204                          struct fb_info *info)
205 {
206         struct fb_info_iga *fb = (struct fb_info_iga*)info;
207
208         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
209         strcpy(fix->id, igafb_name);
210
211         fix->smem_start = (unsigned long) fb->frame_buffer;
212         fix->smem_len = fb->total_vram;
213         fix->xpanstep = 0;
214         fix->ypanstep = 0;
215         fix->ywrapstep = 0;
216
217         fix->type = FB_TYPE_PACKED_PIXELS;
218         fix->type_aux = 0;
219         fix->line_length = default_var.xres * (default_var.bits_per_pixel/8);
220         fix->visual = default_var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR
221                                                       : FB_VISUAL_DIRECTCOLOR;
222         return 0;
223 }
224
225 static int igafb_get_var(struct fb_var_screeninfo *var, int con,
226                          struct fb_info *info)
227 {
228         if(con == -1)
229                 memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
230         else
231                 *var = fb_display[con].var;
232         return 0;
233 }
234
235 static int igafb_set_var(struct fb_var_screeninfo *var, int con,
236                          struct fb_info *info)
237 {
238         memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
239         return 0;
240 }
241
242 #ifdef __sparc__
243 static int igafb_mmap(struct fb_info *info, struct file *file,
244                       struct vm_area_struct *vma)
245 {
246         struct fb_info_iga *fb = (struct fb_info_iga *)info;
247         unsigned int size, page, map_size = 0;
248         unsigned long map_offset = 0;
249         int i;
250
251         if (!fb->mmap_map)
252                 return -ENXIO;
253
254         size = vma->vm_end - vma->vm_start;
255
256         /* To stop the swapper from even considering these pages. */
257         vma->vm_flags |= (VM_SHM | VM_LOCKED);
258
259         /* Each page, see which map applies */
260         for (page = 0; page < size; ) {
261                 map_size = 0;
262                 for (i = 0; fb->mmap_map[i].size; i++) {
263                         unsigned long start = fb->mmap_map[i].voff;
264                         unsigned long end = start + fb->mmap_map[i].size;
265                         unsigned long offset = (vma->vm_pgoff << PAGE_SHIFT) + page;
266
267                         if (start > offset)
268                                 continue;
269                         if (offset >= end)
270                                 continue;
271
272                         map_size = fb->mmap_map[i].size - (offset - start);
273                         map_offset = fb->mmap_map[i].poff + (offset - start);
274                         break;
275                 }
276                 if (!map_size) {
277                         page += PAGE_SIZE;
278                         continue;
279                 }
280                 if (page + map_size > size)
281                         map_size = size - page;
282
283                 pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
284                 pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
285
286                 if (remap_page_range(vma->vm_start + page, map_offset,
287                                      map_size, vma->vm_page_prot))
288                         return -EAGAIN;
289
290                 page += map_size;
291         }
292
293         if (!map_size)
294                 return -EINVAL;
295
296         if (!fb->mmaped) {
297                 int lastconsole = 0;
298
299                 if (info->display_fg)
300                         lastconsole = info->display_fg->vc_num;
301                 fb->mmaped = 1;
302                 if (fb->consolecnt && fb_display[lastconsole].fb_info ==info) {
303                         fb->vtconsole = lastconsole;
304                         vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
305                 }
306         }
307         return 0;
308 }
309 #endif /* __sparc__ */
310
311
312 static int iga_getcolreg(unsigned regno, unsigned *red, unsigned *green,
313                           unsigned *blue, unsigned *transp,
314                           struct fb_info *fb_info)
315 {
316         /*
317          *  Read a single color register and split it into colors/transparent.
318          *  Return != 0 for invalid regno.
319          */
320         struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
321
322         if (regno >= info->video_cmap_len)
323                 return 1;
324
325         *red    = info->palette[regno].red;
326         *green  = info->palette[regno].green;
327         *blue   = info->palette[regno].blue;
328         *transp = 0;
329         return 0;
330 }
331
332 static int iga_setcolreg(unsigned regno, unsigned red, unsigned green,
333                           unsigned blue, unsigned transp,
334                           struct fb_info *fb_info)
335 {
336         /*
337          *  Set a single color register. The values supplied are
338          *  already rounded down to the hardware's capabilities
339          *  (according to the entries in the `var' structure). Return
340          *  != 0 for invalid regno.
341          */
342         
343         struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
344
345         if (regno >= info->video_cmap_len)
346                 return 1;
347
348         info->palette[regno].red   = red;
349         info->palette[regno].green = green;
350         info->palette[regno].blue  = blue;
351
352         pci_outb(info, regno, DAC_W_INDEX);
353         pci_outb(info, red,   DAC_DATA);
354         pci_outb(info, green, DAC_DATA);
355         pci_outb(info, blue,  DAC_DATA);
356
357         if (regno < 16) {
358                 switch (default_var.bits_per_pixel) {
359 #ifdef FBCON_HAS_CFB16
360                 case 16:
361                         info->fbcon_cmap.cfb16[regno] = 
362                                 (regno << 10) | (regno << 5) | regno;
363                         break;
364 #endif
365 #ifdef FBCON_HAS_CFB24
366                 case 24:
367                         info->fbcon_cmap.cfb24[regno] = 
368                                 (regno << 16) | (regno << 8) | regno;
369                 break;
370 #endif
371 #ifdef FBCON_HAS_CFB32
372                 case 32:
373                         { int i;
374                         i = (regno << 8) | regno;
375                         info->fbcon_cmap.cfb32[regno] = (i << 16) | i;
376                         }
377                         break;
378 #endif
379                 }
380         }
381         return 0;
382 }
383
384 static void do_install_cmap(int con, struct fb_info *fb_info)
385 {
386         struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
387
388         if (con != info->currcon)
389                 return;
390         if (fb_display[con].cmap.len)
391                 fb_set_cmap(&fb_display[con].cmap, 1,
392                             iga_setcolreg, &info->fb_info);
393         else
394                 fb_set_cmap(fb_default_cmap(info->video_cmap_len), 1, 
395                             iga_setcolreg, &info->fb_info);
396 }
397
398 static int igafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
399                            struct fb_info *fb_info)
400 {
401         struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
402         
403         if (con == info->currcon) /* current console? */
404                 return fb_get_cmap(cmap, kspc, iga_getcolreg, &info->fb_info);
405         else if (fb_display[con].cmap.len) /* non default colormap? */
406                 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
407         else
408                 fb_copy_cmap(fb_default_cmap(info->video_cmap_len),
409                      cmap, kspc ? 0 : 2);
410         return 0;
411 }
412
413 static int igafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
414                           struct fb_info *info)
415 {
416         int err;
417         struct fb_info_iga *fb = (struct fb_info_iga*) info;
418
419         if (!fb_display[con].cmap.len) {        /* no colormap allocated? */
420                 err = fb_alloc_cmap(&fb_display[con].cmap,
421                                     fb->video_cmap_len,0);
422                 if (err)
423                         return err;
424         }
425         if (con == fb->currcon)                     /* current console? */
426                 return fb_set_cmap(cmap, kspc, iga_setcolreg, info);
427         else
428                 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
429         return 0;
430 }
431
432 /*
433  * Framebuffer option structure
434  */
435 static struct fb_ops igafb_ops = {
436         owner:          THIS_MODULE,
437         fb_get_fix:     igafb_get_fix,
438         fb_get_var:     igafb_get_var,
439         fb_set_var:     igafb_set_var,
440         fb_get_cmap:    igafb_get_cmap,
441         fb_set_cmap:    igafb_set_cmap,
442 #ifdef __sparc__
443         fb_mmap:        igafb_mmap,
444 #endif
445 };
446
447 static void igafb_set_disp(int con, struct fb_info_iga *info)
448 {
449         struct fb_fix_screeninfo fix;
450         struct display *display;
451         struct display_switch *sw;
452
453         if (con >= 0)
454                 display = &fb_display[con];
455         else 
456                 display = &info->disp;        /* used during initialization */
457
458         igafb_get_fix(&fix, con, &info->fb_info);
459
460         memset(display, 0, sizeof(struct display));
461         display->screen_base = info->frame_buffer;
462         display->visual = fix.visual;
463         display->type = fix.type;
464         display->type_aux = fix.type_aux;
465         display->ypanstep = fix.ypanstep;
466         display->ywrapstep = fix.ywrapstep;
467         display->line_length = fix.line_length;
468         display->next_line = fix.line_length;
469         display->can_soft_blank = 0; 
470         display->inverse = 0;
471         igafb_get_var(&display->var, -1, &info->fb_info);
472
473         switch (default_var.bits_per_pixel) {
474 #ifdef FBCON_HAS_CFB8
475         case 8:
476                 sw = &fbcon_cfb8;
477                 break;
478 #endif
479 #ifdef FBCON_HAS_CFB16
480         case 15:
481         case 16:
482                 sw = &fbcon_cfb16;
483                 display->dispsw_data = info->fbcon_cmap.cfb16;
484                 break;
485 #endif
486 #ifdef FBCON_HAS_CFB24
487         case 24:
488                 sw = &fbcon_cfb24;
489                 display->dispsw_data = info->fbcon_cmap.cfb24;
490                 break;
491 #endif
492 #ifdef FBCON_HAS_CFB32
493         case 32:
494                 sw = &fbcon_cfb32;
495                 display->dispsw_data = info->fbcon_cmap.cfb32;
496                 break;
497 #endif
498         default:
499                 printk(KERN_WARNING "igafb_set_disp: unknown resolution %d\n",
500                     default_var.bits_per_pixel);
501                 return;
502         }
503         memcpy(&info->dispsw, sw, sizeof(*sw));
504         display->dispsw = &info->dispsw;
505
506         display->scrollmode = SCROLL_YREDRAW;
507         info->dispsw.bmove = fbcon_redraw_bmove;
508 }
509
510 static int igafb_switch(int con, struct fb_info *fb_info)
511 {
512         struct fb_info_iga *info = (struct fb_info_iga*) fb_info;
513
514         /* Do we have to save the colormap? */
515         if (fb_display[info->currcon].cmap.len)
516                 fb_get_cmap(&fb_display[info->currcon].cmap, 1,
517                             iga_getcolreg, fb_info);
518
519         info->currcon = con;
520         /* Install new colormap */
521         do_install_cmap(con, fb_info);
522         igafb_update_var(con, fb_info);
523         return 1;
524 }
525
526
527
528 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
529
530 static void igafb_blank(int blank, struct fb_info *info)
531 {
532         /* Not supported */
533 }
534
535
536 static int __init iga_init(struct fb_info_iga *info)
537 {
538         char vramsz = iga_inb(info, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) 
539                                                          & MEM_SIZE_ALIAS;
540         switch (vramsz) {
541         case MEM_SIZE_1M:
542                 info->total_vram = 0x100000;
543                 break;
544         case MEM_SIZE_2M:
545                 info->total_vram = 0x200000;
546                 break;
547         case MEM_SIZE_4M:
548         case MEM_SIZE_RESERVED:
549                 info->total_vram = 0x400000;
550                 break;
551         }
552
553         if (default_var.bits_per_pixel > 8) {
554                 info->video_cmap_len = 16;
555         } else {
556                 info->video_cmap_len = 256;
557         }
558         {
559                 int j, k;
560                 for (j = 0; j < 16; j++) {
561                         k = color_table[j];
562                         info->palette[j].red = default_red[k];
563                         info->palette[j].green = default_grn[k];
564                         info->palette[j].blue = default_blu[k];
565                 }
566         }
567
568         strcpy(info->fb_info.modename, igafb_name);
569         info->fb_info.node = -1;
570         info->fb_info.fbops = &igafb_ops;
571         info->fb_info.disp = &info->disp;
572         strcpy(info->fb_info.fontname, fontname);
573         info->fb_info.changevar = NULL;
574         info->fb_info.switch_con = &igafb_switch;
575         info->fb_info.updatevar = &igafb_update_var;
576         info->fb_info.blank = &igafb_blank;
577         info->fb_info.flags=FBINFO_FLAG_DEFAULT;
578
579         igafb_set_disp(-1, info);
580
581         if (register_framebuffer(&info->fb_info) < 0)
582                 return 0;
583
584         printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n",
585                GET_FB_IDX(info->fb_info.node), igafb_name, 
586                info->frame_buffer_phys, info->total_vram >> 20);
587
588         iga_blank_border(info); 
589         return 1;
590 }
591
592 int __init igafb_init(void)
593 {
594         struct pci_dev *pdev;
595         struct fb_info_iga *info;
596         unsigned long addr;
597         extern int con_is_present(void);
598         int iga2000 = 0;
599
600         /* Do not attach when we have a serial console. */
601         if (!con_is_present())
602                 return -ENXIO;
603
604         pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 
605                                PCI_DEVICE_ID_INTERG_1682, 0);
606         if (pdev == NULL) {
607                 /*
608                  * XXX We tried to use cyber2000fb.c for IGS 2000.
609                  * But it does not initialize the chip in JavaStation-E, alas.
610                  */
611                 pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, 0);
612                 if(pdev == NULL) {
613                         return -ENXIO;
614                 }
615                 iga2000 = 1;
616         }
617
618         info = kmalloc(sizeof(struct fb_info_iga), GFP_ATOMIC);
619         if (!info) {
620                 printk("igafb_init: can't alloc fb_info_iga\n");
621                 return -ENOMEM;
622         }
623         memset(info, 0, sizeof(struct fb_info_iga));
624
625         if ((addr = pdev->resource[0].start) == 0) {
626                 printk("igafb_init: no memory start\n");
627                 kfree(info);
628                 return -ENXIO;
629         }
630
631         if ((info->frame_buffer = ioremap(addr, 1024*1024*2)) == 0) {
632                 printk("igafb_init: can't remap %lx[2M]\n", addr);
633                 kfree(info);
634                 return -ENXIO;
635         }
636
637         info->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
638
639 #ifdef __sparc__
640         /*
641          * The following is sparc specific and this is why:
642          *
643          * IGS2000 has its I/O memory mapped and we want
644          * to generate memory cycles on PCI, e.g. do ioremap(),
645          * then readb/writeb() as in Documentation/IO-mapping.txt.
646          *
647          * IGS1682 is more traditional, it responds to PCI I/O
648          * cycles, so we want to access it with inb()/outb().
649          *
650          * On sparc, PCIC converts CPU memory access within
651          * phys window 0x3000xxxx into PCI I/O cycles. Therefore
652          * we may use readb/writeb to access them with IGS1682.
653          *
654          * We do not take io_base_phys from resource[n].start
655          * on IGS1682 because that chip is BROKEN. It does not
656          * have a base register for I/O. We just "know" what its
657          * I/O addresses are.
658          */
659         if (iga2000) {
660                 info->io_base_phys = info->frame_buffer_phys | 0x00800000;
661         } else {
662                 info->io_base_phys = 0x30000000;        /* XXX */
663         }
664         if ((info->io_base = (int) ioremap(info->io_base_phys, 0x1000)) == 0) {
665                 printk("igafb_init: can't remap %lx[4K]\n", info->io_base_phys);
666                 iounmap((void *)info->frame_buffer);
667                 kfree(info);
668                 return -ENXIO;
669         }
670
671         /*
672          * Figure mmap addresses from PCI config space.
673          * We need two regions: for video memory and for I/O ports.
674          * Later one can add region for video coprocessor registers.
675          * However, mmap routine loops until size != 0, so we put
676          * one additional region with size == 0. 
677          */
678
679         info->mmap_map = kmalloc(4 * sizeof(*info->mmap_map), GFP_ATOMIC);
680         if (!info->mmap_map) {
681                 printk("igafb_init: can't alloc mmap_map\n");
682                 iounmap((void *)info->io_base);
683                 iounmap(info->frame_buffer);
684                 kfree(info);
685                 return -ENOMEM;
686         }
687
688         memset(info->mmap_map, 0, 4 * sizeof(*info->mmap_map));
689
690         /*
691          * Set default vmode and cmode from PROM properties.
692          */
693         {
694                 struct pcidev_cookie *cookie = pdev->sysdata;
695                 int node = cookie->prom_node;
696                 int width = prom_getintdefault(node, "width", 1024);
697                 int height = prom_getintdefault(node, "height", 768);
698                 int depth = prom_getintdefault(node, "depth", 8);
699                 switch (width) {
700                     case 1024:
701                         if (height == 768)
702                             default_var = default_var_1024x768;
703                         break;
704                     case 1152:
705                         if (height == 900)
706                             default_var = default_var_1152x900;
707                         break;
708                     case 1280:
709                         if (height == 1024)
710                             default_var = default_var_1280x1024;
711                         break;
712                     default:
713                         break;
714                 }
715
716                 switch (depth) {
717                     case 8:
718                         default_var.bits_per_pixel = 8;
719                         break;
720                     case 16:
721                         default_var.bits_per_pixel = 16;
722                         break;
723                     case 24:
724                         default_var.bits_per_pixel = 24;
725                         break;
726                     case 32:
727                         default_var.bits_per_pixel = 32;
728                         break;
729                     default:
730                         break;
731                 }
732             }
733
734 #endif
735
736         if (!iga_init(info)) {
737                 iounmap((void *)info->io_base);
738                 iounmap(info->frame_buffer);
739                 if (info->mmap_map)
740                         kfree(info->mmap_map);
741                 kfree(info);
742         }
743
744 #ifdef __sparc__
745             /*
746              * Add /dev/fb mmap values.
747              */
748             
749             /* First region is for video memory */
750             info->mmap_map[0].voff = 0x0;  
751             info->mmap_map[0].poff = info->frame_buffer_phys & PAGE_MASK;
752             info->mmap_map[0].size = info->total_vram   & PAGE_MASK;
753             info->mmap_map[0].prot_mask = SRMMU_CACHE;
754             info->mmap_map[0].prot_flag = SRMMU_WRITE;
755
756             /* Second region is for I/O ports */
757             info->mmap_map[1].voff = info->frame_buffer_phys & PAGE_MASK;
758             info->mmap_map[1].poff = info->io_base_phys & PAGE_MASK;
759             info->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
760             info->mmap_map[1].prot_mask = SRMMU_CACHE;
761             info->mmap_map[1].prot_flag = SRMMU_WRITE;
762 #endif /* __sparc__ */
763
764         return 0;
765 }
766
767 int __init igafb_setup(char *options)
768 {
769     char *this_opt;
770
771     if (!options || !*options)
772         return 0;
773
774     while ((this_opt = strsep(&options, ",")) != NULL) {
775         if (!strncmp(this_opt, "font:", 5)) {
776                 char *p;
777                 int i;
778
779                 p = this_opt + 5;
780                 for (i = 0; i < sizeof(fontname) - 1; i++)
781                         if (!*p || *p == ' ' || *p == ',')
782                                 break;
783                 memcpy(fontname, this_opt + 5, i);
784                 fontname[i] = 0;
785         }
786     }
787     return 0;
788 }
789
790 MODULE_LICENSE("GPL");