make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / video / macfb.c
1 /* macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
2    don't know how to set */
3
4 /* (c) 1999 David Huggins-Daines <dhd@debian.org>
5
6    Primarily based on vesafb.c, by Gerd Knorr
7    (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
8
9    Also uses information and code from:
10    
11    The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
12    Mellinger, Mikael Forselius, Michael Schmitz, and others.
13
14    valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
15    Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
16    
17    This code is free software.  You may copy, modify, and distribute
18    it subject to the terms and conditions of the GNU General Public
19    License, version 2, or any later version, at your convenience. */
20
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/sched.h>
24 #include <linux/errno.h>
25 #include <linux/string.h>
26 #include <linux/mm.h>
27 #include <linux/tty.h>
28 #include <linux/slab.h>
29 #include <linux/delay.h>
30 #include <linux/nubus.h>
31 #include <linux/init.h>
32 #include <linux/fb.h>
33
34 #include <asm/setup.h>
35 #include <asm/bootinfo.h>
36 #include <asm/uaccess.h>
37 #include <asm/pgtable.h>
38 #include <asm/irq.h>
39 #include <asm/macintosh.h>
40 #include <asm/io.h>
41 #include <asm/machw.h>
42
43 #include <video/fbcon.h>
44 #include <video/fbcon-mfb.h>
45 #include <video/fbcon-cfb2.h>
46 #include <video/fbcon-cfb4.h>
47 #include <video/fbcon-cfb8.h>
48 #include <video/fbcon-cfb16.h>
49 #include <video/fbcon-cfb24.h>
50 #include <video/fbcon-cfb32.h>
51
52 #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2)
53
54 /* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */
55 #define DAC_BASE 0x50f24000
56
57 /* Some addresses for the DAFB */
58 #define DAFB_BASE 0xf9800200
59
60 /* Address for the built-in Civic framebuffer in Quadra AVs */
61 #define CIVIC_BASE 0x50f30800   /* Only tested on 660AV! */
62
63 /* GSC (Gray Scale Controller) base address */
64 #define GSC_BASE 0x50F20000
65
66 /* CSC (Color Screen Controller) base address */
67 #define CSC_BASE 0x50F20000
68
69 static int (*macfb_setpalette) (unsigned int regno, unsigned int red,
70                                 unsigned int green, unsigned int blue) = NULL;
71 static int valkyrie_setpalette (unsigned int regno, unsigned int red,
72                                 unsigned int green, unsigned int blue);
73 static int dafb_setpalette (unsigned int regno, unsigned int red,
74                             unsigned int green, unsigned int blue);
75 static int rbv_setpalette (unsigned int regno, unsigned int red,
76                            unsigned int green, unsigned int blue);
77 static int mdc_setpalette (unsigned int regno, unsigned int red,
78                            unsigned int green, unsigned int blue);
79 static int toby_setpalette (unsigned int regno, unsigned int red,
80                             unsigned int green, unsigned int blue);
81 static int civic_setpalette (unsigned int regno, unsigned int red,
82                              unsigned int green, unsigned int blue);
83 static int csc_setpalette (unsigned int regno, unsigned int red,
84                              unsigned int green, unsigned int blue);
85
86 static volatile struct {
87         unsigned char addr;
88         /* Note: word-aligned */
89         char pad[3];
90         unsigned char lut;
91 } *valkyrie_cmap_regs;
92
93 static volatile struct {
94         unsigned char addr;
95         unsigned char lut;
96 } *v8_brazil_cmap_regs;
97
98 static volatile struct {
99         unsigned char addr;
100         char pad1[3]; /* word aligned */
101         unsigned char lut;
102         char pad2[3]; /* word aligned */
103         unsigned char cntl; /* a guess as to purpose */
104 } *rbv_cmap_regs;
105
106 static volatile struct {
107         unsigned long reset;
108         unsigned long pad1[3];
109         unsigned char pad2[3];
110         unsigned char lut;
111 } *dafb_cmap_regs;
112
113 static volatile struct {
114         unsigned char addr;     /* OFFSET: 0x00 */
115         unsigned char pad1[15];
116         unsigned char lut;      /* OFFSET: 0x10 */
117         unsigned char pad2[15];
118         unsigned char status;   /* OFFSET: 0x20 */
119         unsigned char pad3[7];
120         unsigned long vbl_addr; /* OFFSET: 0x28 */
121         unsigned int  status2;  /* OFFSET: 0x2C */
122 } *civic_cmap_regs;
123
124 static volatile struct {
125         char    pad1[0x40];
126         unsigned char   clut_waddr;     /* 0x40 */
127         char    pad2;
128         unsigned char   clut_data;      /* 0x42 */
129         char    pad3[0x3];
130         unsigned char   clut_raddr;     /* 0x46 */
131 } *csc_cmap_regs;
132
133 /* We will leave these the way they are for the time being */
134 struct mdc_cmap_regs {
135         char pad1[0x200200];
136         unsigned char addr;
137         char pad2[6];
138         unsigned char lut;
139 };
140
141 struct toby_cmap_regs {
142         char pad1[0x90018];
143         unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */
144         char pad2[3];
145         unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */
146 };
147
148 struct jet_cmap_regs {
149         char pad1[0xe0e000];
150         unsigned char addr;
151         unsigned char lut;
152 };
153
154 #endif
155
156 #define PIXEL_TO_MM(a)  (((a)*10)/28)   /* width in mm at 72 dpi */     
157
158 static unsigned long video_base;
159 static int   video_size;
160 static char* video_vbase;        /* mapped */
161
162 /* mode */
163 static int  video_bpp;
164 static int  video_width;
165 static int  video_height;
166 static int  video_type = FB_TYPE_PACKED_PIXELS;
167 static int  video_visual;
168 static int  video_linelength;
169 static int  video_cmap_len;
170 static int  video_slot = 0;
171
172 static struct fb_var_screeninfo macfb_defined={
173         0,0,0,0,        /* W,H, W, H (virtual) load xres,xres_virtual*/
174         0,0,            /* virtual -> visible no offset */
175         8,              /* depth -> load bits_per_pixel */
176         0,              /* greyscale ? */
177         {0,0,0},        /* R */
178         {0,0,0},        /* G */
179         {0,0,0},        /* B */
180         {0,0,0},        /* transparency */
181         0,              /* standard pixel format */
182         FB_ACTIVATE_NOW,
183         -1, -1,
184         FB_ACCEL_NONE,  /* The only way to accelerate a mac is .. */
185         0L,0L,0L,0L,0L,
186         0L,0L,0,        /* No sync info */
187         FB_VMODE_NONINTERLACED,
188         {0,0,0,0,0,0}
189 };
190
191 static struct display disp;
192 static struct fb_info fb_info;
193 static struct { u_short blue, green, red, pad; } palette[256];
194 static union {
195 #ifdef FBCON_HAS_CFB16
196     u16 cfb16[16];
197 #endif
198 #ifdef FBCON_HAS_CFB24
199     u32 cfb24[16];
200 #endif
201 #ifdef FBCON_HAS_CFB32
202     u32 cfb32[16];
203 #endif
204 } fbcon_cmap;
205
206 static int             inverse   = 0;
207 static int             vidtest   = 0;
208 static int             currcon   = 0;
209
210 static int macfb_update_var(int con, struct fb_info *info)
211 {
212         return 0;
213 }
214
215 static int macfb_get_fix(struct fb_fix_screeninfo *fix, int con,
216                          struct fb_info *info)
217 {
218         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
219         strcpy(fix->id, "Mac Generic");
220
221         fix->smem_start = video_base;
222         fix->smem_len = video_size;
223         fix->type = video_type;
224         fix->visual = video_visual;
225         fix->xpanstep = 0;
226         fix->ypanstep = 0;
227         fix->line_length=video_linelength;
228         return 0;
229 }
230
231 static int macfb_get_var(struct fb_var_screeninfo *var, int con,
232                          struct fb_info *info)
233 {
234         if(con==-1)
235                 memcpy(var, &macfb_defined, sizeof(struct fb_var_screeninfo));
236         else
237                 *var=fb_display[con].var;
238         return 0;
239 }
240
241 static void macfb_set_disp(int con)
242 {
243         struct fb_fix_screeninfo fix;
244         struct display *display;
245         
246         if (con >= 0)
247                 display = &fb_display[con];
248         else
249                 display = &disp;        /* used during initialization */
250
251         macfb_get_fix(&fix, con, &fb_info);
252
253         memset(display, 0, sizeof(struct display));
254         display->screen_base = video_vbase;
255         display->visual = fix.visual;
256         display->type = fix.type;
257         display->type_aux = fix.type_aux;
258         display->ypanstep = fix.ypanstep;
259         display->ywrapstep = fix.ywrapstep;
260         display->line_length = fix.line_length;
261         display->next_line = fix.line_length;
262         display->can_soft_blank = 0;
263         display->inverse = inverse;
264         display->scrollmode = SCROLL_YREDRAW;
265         macfb_get_var(&display->var, -1, &fb_info);
266
267         switch (video_bpp) {
268 #ifdef FBCON_HAS_MFB
269         case 1:
270                 display->dispsw = &fbcon_mfb;
271                 break;
272 #endif
273 #ifdef FBCON_HAS_CFB2
274         case 2:
275                 display->dispsw = &fbcon_cfb2;
276                 break;
277 #endif
278 #ifdef FBCON_HAS_CFB4
279         case 4:
280                 display->dispsw = &fbcon_cfb4;
281                 break;
282 #endif
283 #ifdef FBCON_HAS_CFB8
284         case 8:
285                 display->dispsw = &fbcon_cfb8;
286                 break;
287 #endif
288 #ifdef FBCON_HAS_CFB16
289         case 15:
290         case 16:
291                 display->dispsw = &fbcon_cfb16;
292                 display->dispsw_data = fbcon_cmap.cfb16;
293                 break;
294 #endif
295 #ifdef FBCON_HAS_CFB24
296         case 24:
297                 display->dispsw = &fbcon_cfb24;
298                 display->dispsw_data = fbcon_cmap.cfb24;
299                 break;
300 #endif
301 #ifdef FBCON_HAS_CFB32
302         case 32:
303                 display->dispsw = &fbcon_cfb32;
304                 display->dispsw_data = fbcon_cmap.cfb32;
305                 break;
306 #endif
307         default:
308                 display->dispsw = &fbcon_dummy;
309                 return;
310         }
311 }
312
313 static int macfb_set_var(struct fb_var_screeninfo *var, int con,
314                          struct fb_info *info)
315 {
316         static int first = 1;
317
318         if (var->xres           != macfb_defined.xres           ||
319             var->yres           != macfb_defined.yres           ||
320             var->xres_virtual   != macfb_defined.xres_virtual   ||
321             var->yres_virtual   != macfb_defined.yres           ||
322             var->xoffset                                        ||
323             var->bits_per_pixel != macfb_defined.bits_per_pixel ||
324             var->nonstd) {
325                 if (first) {
326                         printk("macfb does not support changing the video mode\n");
327                         first = 0;
328                 }
329                 return -EINVAL;
330         }
331
332         if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
333                 return 0;
334
335         if (var->yoffset)
336                 return -EINVAL;
337         return 0;
338 }
339
340 #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2)
341 static int valkyrie_setpalette (unsigned int regno, unsigned int red,
342                                 unsigned int green, unsigned int blue)
343 {
344         unsigned long flags;
345         
346         red >>= 8;
347         green >>= 8;
348         blue >>= 8;
349
350         save_flags(flags);
351         cli();
352         
353         /* tell clut which address to fill */
354         nubus_writeb(regno, &valkyrie_cmap_regs->addr);
355         nop();
356
357         /* send one color channel at a time */
358         nubus_writeb(red, &valkyrie_cmap_regs->lut);
359         nop();
360         nubus_writeb(green, &valkyrie_cmap_regs->lut);
361         nop();
362         nubus_writeb(blue, &valkyrie_cmap_regs->lut);
363
364         restore_flags(flags);
365
366         return 0;
367 }
368
369 /* Unlike the Valkyrie, the DAFB cannot set individual colormap
370    registers.  Therefore, we do what the MacOS driver does (no
371    kidding!) and simply set them one by one until we hit the one we
372    want. */
373 static int dafb_setpalette (unsigned int regno, unsigned int red,
374                             unsigned int green, unsigned int blue)
375 {
376         /* FIXME: really, really need to use ioremap() here,
377            phys_to_virt() doesn't work anymore */
378         static int lastreg = -1;
379         unsigned long flags;
380         
381         red >>= 8;
382         green >>= 8;
383         blue >>= 8;
384
385         save_flags(flags);
386         cli();
387         
388         /* fbcon will set an entire colourmap, but X won't.  Hopefully
389            this should accomodate both of them */
390         if (regno != lastreg+1) {
391                 int i;
392                 
393                 /* Stab in the dark trying to reset the CLUT pointer */
394                 nubus_writel(0, &dafb_cmap_regs->reset);
395                 nop();
396                 
397                 /* Loop until we get to the register we want */
398                 for (i = 0; i < regno; i++) {
399                         nubus_writeb(palette[i].red >> 8, &dafb_cmap_regs->lut);
400                         nop();
401                         nubus_writeb(palette[i].green >> 8, &dafb_cmap_regs->lut);
402                         nop();
403                         nubus_writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut);
404                         nop();
405                 }
406         }
407                 
408         nubus_writeb(red, &dafb_cmap_regs->lut);
409         nop();
410         nubus_writeb(green, &dafb_cmap_regs->lut);
411         nop();
412         nubus_writeb(blue, &dafb_cmap_regs->lut);
413         
414         restore_flags(flags);
415         
416         lastreg = regno;
417         return 0;
418 }
419
420 /* V8 and Brazil seem to use the same DAC.  Sonora does as well. */
421 static int v8_brazil_setpalette (unsigned int regno, unsigned int red,
422                                  unsigned int green, unsigned int blue)
423 {
424         unsigned char _red  =red>>8;
425         unsigned char _green=green>>8;
426         unsigned char _blue =blue>>8;
427         unsigned char _regno;
428         unsigned long flags;
429
430         if (video_bpp>8) return 1; /* failsafe */
431
432         save_flags(flags);
433         cli();
434
435         /* On these chips, the CLUT register numbers are spread out
436            across the register space.  Thus:
437
438            In 8bpp, all regnos are valid.
439            
440            In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
441            
442            In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
443         _regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp);
444         nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
445
446         /* send one color channel at a time */
447         nubus_writeb(_red, &v8_brazil_cmap_regs->lut); nop();
448         nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop();
449         nubus_writeb(_blue, &v8_brazil_cmap_regs->lut);
450
451         restore_flags(flags);
452         
453         return 0;
454 }
455
456 static int rbv_setpalette (unsigned int regno, unsigned int red,
457                            unsigned int green, unsigned int blue)
458 {
459         /* use MSBs */
460         unsigned char _red  =red>>8;
461         unsigned char _green=green>>8;
462         unsigned char _blue =blue>>8;
463         unsigned char _regno;
464         unsigned long flags;
465
466         if (video_bpp>8) return 1; /* failsafe */
467
468         save_flags(flags);
469         cli();
470         
471         /* From the VideoToolbox driver.  Seems to be saying that
472          * regno #254 and #255 are the important ones for 1-bit color,
473          * regno #252-255 are the important ones for 2-bit color, etc.
474          */
475         _regno = regno + (256-(1<<video_bpp));
476
477         /* reset clut? (VideoToolbox sez "not necessary") */
478         nubus_writeb(0xFF, &rbv_cmap_regs->cntl); nop();
479         
480         /* tell clut which address to use. */
481         nubus_writeb(_regno, &rbv_cmap_regs->addr); nop();
482         
483         /* send one color channel at a time. */
484         nubus_writeb(_red,   &rbv_cmap_regs->lut); nop();
485         nubus_writeb(_green, &rbv_cmap_regs->lut); nop();
486         nubus_writeb(_blue,  &rbv_cmap_regs->lut);
487         
488         restore_flags(flags);
489         /* done. */
490         return 0;
491 }
492
493 /* Macintosh Display Card (8x24) */
494 static int mdc_setpalette(unsigned int regno, unsigned int red,
495                           unsigned int green, unsigned int blue)
496 {
497         volatile struct mdc_cmap_regs *cmap_regs =
498                 nubus_slot_addr(video_slot);
499         /* use MSBs */
500         unsigned char _red  =red>>8;
501         unsigned char _green=green>>8;
502         unsigned char _blue =blue>>8;
503         unsigned char _regno=regno;
504         unsigned long flags;
505
506         save_flags(flags);
507         cli();
508         
509         /* the nop's are there to order writes. */
510         nubus_writeb(_regno, &cmap_regs->addr); nop();
511         nubus_writeb(_red, &cmap_regs->lut);    nop();
512         nubus_writeb(_green, &cmap_regs->lut);  nop();
513         nubus_writeb(_blue, &cmap_regs->lut);
514
515         restore_flags(flags);
516         return 0;
517 }
518
519 /* Toby frame buffer */
520 static int toby_setpalette(unsigned int regno, unsigned int red,
521                            unsigned int green, unsigned int blue)
522 {
523         volatile struct toby_cmap_regs *cmap_regs =
524                 nubus_slot_addr(video_slot);
525         /* use MSBs */
526         unsigned char _red  =~(red>>8);
527         unsigned char _green=~(green>>8);
528         unsigned char _blue =~(blue>>8);
529         unsigned char _regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp);
530         unsigned long flags;
531
532         save_flags(flags);
533         cli();
534         
535         nubus_writeb(_regno, &cmap_regs->addr); nop();
536         nubus_writeb(_red, &cmap_regs->lut);    nop();
537         nubus_writeb(_green, &cmap_regs->lut);  nop();
538         nubus_writeb(_blue, &cmap_regs->lut);
539
540         restore_flags(flags);
541         return 0;
542 }
543
544 /* Jet frame buffer */
545 static int jet_setpalette(unsigned int regno, unsigned int red,
546                           unsigned int green, unsigned int blue)
547 {
548         volatile struct jet_cmap_regs *cmap_regs =
549                 nubus_slot_addr(video_slot);
550         /* use MSBs */
551         unsigned char _red   = (red>>8);
552         unsigned char _green = (green>>8);
553         unsigned char _blue  = (blue>>8);
554         unsigned long flags;
555
556         save_flags(flags);
557         cli();
558         
559         nubus_writeb(regno, &cmap_regs->addr); nop();
560         nubus_writeb(_red, &cmap_regs->lut); nop();
561         nubus_writeb(_green, &cmap_regs->lut); nop();
562         nubus_writeb(_blue, &cmap_regs->lut);
563
564         restore_flags(flags);
565         return 0;
566 }
567
568 /*
569  * Civic framebuffer -- Quadra AV built-in video.  A chip
570  * called Sebastian holds the actual color palettes, and
571  * apparently, there are two different banks of 512K RAM 
572  * which can act as separate framebuffers for doing video
573  * input and viewing the screen at the same time!  The 840AV
574  * Can add another 1MB RAM to give the two framebuffers 
575  * 1MB RAM apiece.
576  *
577  * FIXME: this doesn't seem to work anymore.
578  */
579 static int civic_setpalette (unsigned int regno, unsigned int red,
580                              unsigned int green, unsigned int blue)
581 {
582         static int lastreg = -1;
583         unsigned long flags;
584         int clut_status;
585         
586         if (video_bpp > 8) return 1; /* failsafe */
587
588         red   >>= 8;
589         green >>= 8;
590         blue  >>= 8;
591
592         save_flags(flags);
593         cli();
594         
595         /*
596          * Set the register address
597          */
598         nubus_writeb(regno, &civic_cmap_regs->addr); nop();
599
600         /*
601          * Wait for VBL interrupt here;
602          * They're usually not enabled from Penguin, so we won't check
603          */
604 #if 0
605         {
606 #define CIVIC_VBL_OFFSET        0x120
607                 volatile unsigned long *vbl = nubus_readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
608                 /* do interrupt setup stuff here? */
609                 *vbl = 0L; nop();       /* clear */
610                 *vbl = 1L; nop();       /* set */
611                 while (*vbl != 0L)      /* wait for next vbl */
612                 {
613                         usleep(10);     /* needed? */
614                 }
615                 /* do interrupt shutdown stuff here? */
616         }
617 #endif
618
619         /*
620          * Grab a status word and do some checking;
621          * Then finally write the clut!
622          */
623         clut_status =  nubus_readb(&civic_cmap_regs->status2);
624
625         if ((clut_status & 0x0008) == 0)
626         {
627 #if 0
628                 if ((clut_status & 0x000D) != 0)
629                 {
630                         nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
631                         nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
632                 }
633 #endif
634
635                 nubus_writeb(  red, &civic_cmap_regs->lut); nop();
636                 nubus_writeb(green, &civic_cmap_regs->lut); nop();
637                 nubus_writeb( blue, &civic_cmap_regs->lut); nop();
638                 nubus_writeb( 0x00, &civic_cmap_regs->lut); nop();
639         }
640         else
641         {
642                 unsigned char junk;
643
644                 junk = nubus_readb(&civic_cmap_regs->lut); nop();
645                 junk = nubus_readb(&civic_cmap_regs->lut); nop();
646                 junk = nubus_readb(&civic_cmap_regs->lut); nop();
647                 junk = nubus_readb(&civic_cmap_regs->lut); nop();
648
649                 if ((clut_status & 0x000D) != 0)
650                 {
651                         nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
652                         nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
653                 }
654
655                 nubus_writeb(  red, &civic_cmap_regs->lut); nop();
656                 nubus_writeb(green, &civic_cmap_regs->lut); nop();
657                 nubus_writeb( blue, &civic_cmap_regs->lut); nop();
658                 nubus_writeb( junk, &civic_cmap_regs->lut); nop();
659         }
660
661         restore_flags(flags);
662
663         lastreg = regno;
664         return 0;
665 }
666
667 /*
668  * The CSC is the framebuffer on the PowerBook 190 series
669  * (and the 5300 too, but that's a PowerMac). This function
670  * brought to you in part by the ECSC driver for MkLinux.
671  */
672
673 static int csc_setpalette (unsigned int regno, unsigned int red,
674                              unsigned int green, unsigned int blue)
675 {
676         mdelay(1);
677         csc_cmap_regs->clut_waddr = regno;
678         csc_cmap_regs->clut_data = red;
679         csc_cmap_regs->clut_data = green;
680         csc_cmap_regs->clut_data = blue;
681         return 0;
682 }
683
684 #endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB4 || FBCON_HAS_CFB2 */
685
686 static int macfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
687                            unsigned *blue, unsigned *transp,
688                            struct fb_info *fb_info)
689 {
690         /*
691          *  Read a single color register and split it into colors/transparent.
692          *  Return != 0 for invalid regno.
693          */
694
695         if (regno >= video_cmap_len)
696                 return 1;
697
698         *red   = palette[regno].red;
699         *green = palette[regno].green;
700         *blue  = palette[regno].blue;
701         *transp = 0;
702         return 0;
703 }
704
705 static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
706                            unsigned blue, unsigned transp,
707                            struct fb_info *fb_info)
708 {
709         /*
710          *  Set a single color register. The values supplied are
711          *  already rounded down to the hardware's capabilities
712          *  (according to the entries in the `var' structure). Return
713          *  != 0 for invalid regno.
714          */
715         
716         if (regno >= video_cmap_len)
717                 return 1;
718
719         palette[regno].red   = red;
720         palette[regno].green = green;
721         palette[regno].blue  = blue;
722
723         switch (video_bpp) {
724 #ifdef FBCON_HAS_MFB
725         case 1:
726                 /* We shouldn't get here */
727                 break;
728 #endif
729 #ifdef FBCON_HAS_CFB2
730         case 2:
731                 if (macfb_setpalette)
732                         macfb_setpalette(regno, red, green, blue);
733                 else
734                         return 1;
735                 break;
736 #endif
737 #ifdef FBCON_HAS_CFB4
738         case 4:
739                 if (macfb_setpalette)
740                         macfb_setpalette(regno, red, green, blue);
741                 else
742                         return 1;
743                 break;
744 #endif
745 #ifdef FBCON_HAS_CFB8
746         case 8:
747                 if (macfb_setpalette)
748                         macfb_setpalette(regno, red, green, blue);
749                 else
750                         return 1;
751                 break;
752 #endif
753 #ifdef FBCON_HAS_CFB16
754         case 15:
755         case 16:
756                 /* 1:5:5:5 */
757                 fbcon_cmap.cfb16[regno] =
758                         ((red   & 0xf800) >>  1) |
759                         ((green & 0xf800) >>  6) |
760                         ((blue  & 0xf800) >> 11) |
761                         ((transp != 0) << 15);
762                 break;
763 #endif
764                 /* I'm pretty sure that one or the other of these
765                    doesn't exist on 68k Macs */
766 #ifdef FBCON_HAS_CFB24
767         case 24:
768                 red   >>= 8;
769                 green >>= 8;
770                 blue  >>= 8;
771                 fbcon_cmap.cfb24[regno] =
772                         (red   << macfb_defined.red.offset)   |
773                         (green << macfb_defined.green.offset) |
774                         (blue  << macfb_defined.blue.offset);
775                 break;
776 #endif
777 #ifdef FBCON_HAS_CFB32
778         case 32:
779                 red   >>= 8;
780                 green >>= 8;
781                 blue  >>= 8;
782                 fbcon_cmap.cfb32[regno] =
783                         (red   << macfb_defined.red.offset)   |
784                         (green << macfb_defined.green.offset) |
785                         (blue  << macfb_defined.blue.offset);
786                 break;
787 #endif
788     }
789     return 0;
790 }
791
792 static void do_install_cmap(int con, struct fb_info *info)
793 {
794         if (con != currcon)
795                 return;
796         if (fb_display[con].cmap.len)
797                 fb_set_cmap(&fb_display[con].cmap, 1, macfb_setcolreg, info);
798         else
799                 fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
800                             macfb_setcolreg, info);
801 }
802
803 static int macfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
804                           struct fb_info *info)
805 {
806         if (con == currcon) /* current console? */
807                 return fb_get_cmap(cmap, kspc, macfb_getcolreg, info);
808         else if (fb_display[con].cmap.len) /* non default colormap? */
809                 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
810         else
811                 fb_copy_cmap(fb_default_cmap(video_cmap_len),
812                      cmap, kspc ? 0 : 2);
813         return 0;
814 }
815
816 static int macfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
817                           struct fb_info *info)
818 {
819         int err;
820
821         if (!fb_display[con].cmap.len) {        /* no colormap allocated? */
822                 err = fb_alloc_cmap(&fb_display[con].cmap,video_cmap_len,0);
823                 if (err)
824                         return err;
825         }
826         if (con == currcon)                     /* current console? */
827                 return fb_set_cmap(cmap, kspc, macfb_setcolreg, info);
828         else
829                 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
830         return 0;
831 }
832
833 static struct fb_ops macfb_ops = {
834         owner:          THIS_MODULE,
835         fb_get_fix:     macfb_get_fix,
836         fb_get_var:     macfb_get_var,
837         fb_set_var:     macfb_set_var,
838         fb_get_cmap:    macfb_get_cmap,
839         fb_set_cmap:    macfb_set_cmap,
840 };
841
842 void __init macfb_setup(char *options, int *ints)
843 {
844         char *this_opt;
845         
846         fb_info.fontname[0] = '\0';
847         
848         if (!options || !*options)
849                 return;
850         
851         while ((this_opt = strsep(&options, ",")) != NULL) {
852                 if (!*this_opt) continue;
853                 
854                 if (! strcmp(this_opt, "inverse"))
855                         inverse=1;
856                 else if (!strncmp(this_opt, "font:", 5))
857                         strcpy(fb_info.fontname, this_opt+5);
858                 /* This means "turn on experimental CLUT code" */
859                 else if (!strcmp(this_opt, "vidtest"))
860                         vidtest=1;
861         }
862 }
863
864 static int macfb_switch(int con, struct fb_info *info)
865 {
866         /* Do we have to save the colormap? */
867         if (fb_display[currcon].cmap.len)
868                 fb_get_cmap(&fb_display[currcon].cmap, 1, macfb_getcolreg,
869                             info);
870         
871         currcon = con;
872         /* Install new colormap */
873         do_install_cmap(con, info);
874         macfb_update_var(con, info);
875         return 1;
876 }
877
878 static void macfb_blank(int blank, struct fb_info *info)
879 {
880         /* Not supported */
881 }
882
883 void __init macfb_init(void)
884 {
885         struct nubus_dev* ndev = NULL;
886         int video_is_nubus = 0;
887
888         if (!MACH_IS_MAC) 
889                 return;
890
891         /* There can only be one internal video controller anyway so
892            we're not too worried about this */
893         video_width      = mac_bi_data.dimensions & 0xFFFF;
894         video_height     = mac_bi_data.dimensions >> 16;
895         video_bpp        = mac_bi_data.videodepth;
896         video_linelength = mac_bi_data.videorow;
897         video_size       = video_linelength * video_height;
898         /* Note: physical address (since 2.1.127) */
899         video_base       = mac_bi_data.videoaddr;
900         /* This is actually redundant with the initial mappings.
901            However, there are some non-obvious aspects to the way
902            those mappings are set up, so this is in fact the safest
903            way to ensure that this driver will work on every possible
904            Mac */
905         video_vbase      = ioremap(mac_bi_data.videoaddr, video_size);
906         
907         printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
908                video_base, video_vbase, video_size/1024);
909         printk("macfb: mode is %dx%dx%d, linelength=%d\n",
910                video_width, video_height, video_bpp, video_linelength);
911         
912         /*
913          *      Fill in the available video resolution
914          */
915          
916         macfb_defined.xres           = video_width;
917         macfb_defined.yres           = video_height;
918         macfb_defined.xres_virtual   = video_width;
919         macfb_defined.yres_virtual   = video_height;
920         macfb_defined.bits_per_pixel = video_bpp;
921         macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
922         macfb_defined.width  = PIXEL_TO_MM(macfb_defined.xres);  
923
924         printk("macfb: scrolling: redraw\n");
925         macfb_defined.yres_virtual = video_height;
926
927         /* some dummy values for timing to make fbset happy */
928         macfb_defined.pixclock     = 10000000 / video_width * 1000 / video_height;
929         macfb_defined.left_margin  = (video_width / 8) & 0xf8;
930         macfb_defined.right_margin = 32;
931         macfb_defined.upper_margin = 16;
932         macfb_defined.lower_margin = 4;
933         macfb_defined.hsync_len    = (video_width / 8) & 0xf8;
934         macfb_defined.vsync_len    = 4;
935
936         switch (video_bpp) {
937         case 1:
938                 /* XXX: I think this will catch any program that tries
939                    to do FBIO_PUTCMAP when the visual is monochrome */
940                 video_cmap_len = 0;
941                 video_visual = FB_VISUAL_MONO01;
942                 break;
943         case 2:
944         case 4:
945         case 8:
946                 macfb_defined.red.length = video_bpp;
947                 macfb_defined.green.length = video_bpp;
948                 macfb_defined.blue.length = video_bpp;
949                 video_cmap_len = 1 << video_bpp;
950                 video_visual = FB_VISUAL_PSEUDOCOLOR;
951                 break;
952         case 16:
953                 macfb_defined.transp.offset = 15;
954                 macfb_defined.transp.length = 1;
955                 macfb_defined.red.offset = 10;
956                 macfb_defined.red.length = 5;
957                 macfb_defined.green.offset = 5;
958                 macfb_defined.green.length = 5;
959                 macfb_defined.blue.offset = 0;
960                 macfb_defined.blue.length = 5;
961                 printk("macfb: directcolor: "
962                        "size=1:5:5:5, shift=15:10:5:0\n");
963                 video_cmap_len = 16;
964                 /* Should actually be FB_VISUAL_DIRECTCOLOR, but this
965                    works too */
966                 video_visual = FB_VISUAL_TRUECOLOR;
967                 break;
968         case 24:
969         case 32:
970                 /* XXX: have to test these... can any 68k Macs
971                    actually do this on internal video? */
972                 macfb_defined.red.offset = 16;
973                 macfb_defined.red.length = 8;
974                 macfb_defined.green.offset = 8;
975                 macfb_defined.green.length = 8;
976                 macfb_defined.blue.offset = 0;
977                 macfb_defined.blue.length = 8;
978                 printk("macfb: truecolor: "
979                        "size=0:8:8:8, shift=0:16:8:0\n");
980                 video_cmap_len = 16;
981                 video_visual = FB_VISUAL_TRUECOLOR;
982         default:
983                 video_cmap_len = 0;
984                 video_visual = FB_VISUAL_MONO01;
985                 printk("macfb: unknown or unsupported bit depth: %d\n", video_bpp);
986                 break;
987         }
988         
989         /* Hardware dependent stuff */
990         /*  We take a wild guess that if the video physical address is
991          *  in nubus slot space, that the nubus card is driving video.
992          *  Penguin really ought to tell us whether we are using internal
993          *  video or not.
994          */
995         /* Hopefully we only find one of them.  Otherwise our NuBus
996            code is really broken :-) */
997
998         while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev))
999                 != NULL)
1000         {
1001                 if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr
1002                       && (mac_bi_data.videoaddr <
1003                           (unsigned long)nubus_slot_addr(ndev->board->slot+1))))
1004                         continue;
1005                 video_is_nubus = 1;
1006                 /* We should probably just use the slot address... */
1007                 video_slot = ndev->board->slot;
1008
1009                 switch(ndev->dr_hw) {
1010                 case NUBUS_DRHW_APPLE_MDC:
1011                         strcpy( fb_info.modename, "Macintosh Display Card" );
1012                         macfb_setpalette = mdc_setpalette;
1013                         macfb_defined.activate = FB_ACTIVATE_NOW;
1014                         break;
1015                 case NUBUS_DRHW_APPLE_TFB:
1016                         strcpy( fb_info.modename, "Toby" );
1017                         macfb_setpalette = toby_setpalette;
1018                         macfb_defined.activate = FB_ACTIVATE_NOW;
1019                         break;
1020                 case NUBUS_DRHW_APPLE_JET:
1021                         strcpy(fb_info.modename, "Jet");
1022                         macfb_setpalette = jet_setpalette;
1023                         macfb_defined.activate = FB_ACTIVATE_NOW;
1024                         break;                  
1025                 default:
1026                         strcpy( fb_info.modename, "Generic NuBus" );
1027                         break;
1028                 }
1029         }
1030
1031         /* If it's not a NuBus card, it must be internal video */
1032         /* FIXME: this function is getting way too big.  (this driver
1033            is too...) */
1034         if (!video_is_nubus)
1035                 switch( mac_bi_data.id )
1036                 {
1037                         /* These don't have onboard video.  Eventually, we may
1038                            be able to write separate framebuffer drivers for
1039                            them (tobyfb.c, hiresfb.c, etc, etc) */
1040                 case MAC_MODEL_II:
1041                 case MAC_MODEL_IIX:
1042                 case MAC_MODEL_IICX:
1043                 case MAC_MODEL_IIFX:
1044                         strcpy( fb_info.modename, "Generic NuBus" );
1045                         break;
1046
1047                         /* Valkyrie Quadras */
1048                 case MAC_MODEL_Q630:
1049                         /* I'm not sure about this one */
1050                 case MAC_MODEL_P588:
1051                         strcpy( fb_info.modename, "Valkyrie built-in" );
1052                         macfb_setpalette = valkyrie_setpalette;
1053                         macfb_defined.activate = FB_ACTIVATE_NOW;
1054                         valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000);
1055                         break;
1056
1057                         /* DAFB Quadras */
1058                         /* Note: these first four have the v7 DAFB, which is
1059                            known to be rather unlike the ones used in the
1060                            other models */
1061                 case MAC_MODEL_P475:
1062                 case MAC_MODEL_P475F:
1063                 case MAC_MODEL_P575:
1064                 case MAC_MODEL_Q605:
1065         
1066                 case MAC_MODEL_Q800:
1067                 case MAC_MODEL_Q650:
1068                 case MAC_MODEL_Q610:
1069                 case MAC_MODEL_C650:
1070                 case MAC_MODEL_C610:
1071                 case MAC_MODEL_Q700:
1072                 case MAC_MODEL_Q900:
1073                 case MAC_MODEL_Q950:
1074                         strcpy( fb_info.modename, "DAFB built-in" );
1075                         macfb_setpalette = dafb_setpalette;
1076                         macfb_defined.activate = FB_ACTIVATE_NOW;
1077                         dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
1078                         break;
1079
1080                         /* LC II uses the V8 framebuffer */
1081                 case MAC_MODEL_LCII:
1082                         strcpy( fb_info.modename, "V8 built-in" );
1083                         macfb_setpalette = v8_brazil_setpalette;
1084                         macfb_defined.activate = FB_ACTIVATE_NOW;
1085                         v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
1086                         break;
1087                 
1088                         /* IIvi, IIvx use the "Brazil" framebuffer (which is
1089                            very much like the V8, it seems, and probably uses
1090                            the same DAC) */
1091                 case MAC_MODEL_IIVI:
1092                 case MAC_MODEL_IIVX:
1093                 case MAC_MODEL_P600:
1094                         strcpy( fb_info.modename, "Brazil built-in" );
1095                         macfb_setpalette = v8_brazil_setpalette;
1096                         macfb_defined.activate = FB_ACTIVATE_NOW;
1097                         v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
1098                         break;
1099                 
1100                         /* LC III (and friends) use the Sonora framebuffer */
1101                         /* Incidentally this is also used in the non-AV models
1102                            of the x100 PowerMacs */
1103                         /* These do in fact seem to use the same DAC interface
1104                            as the LC II. */
1105                 case MAC_MODEL_LCIII:
1106                 case MAC_MODEL_P520:
1107                 case MAC_MODEL_P550:
1108                 case MAC_MODEL_P460:
1109                         macfb_setpalette = v8_brazil_setpalette;
1110                         macfb_defined.activate = FB_ACTIVATE_NOW;
1111                         strcpy( fb_info.modename, "Sonora built-in" );
1112                         v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
1113                         break;
1114
1115                         /* IIci and IIsi use the infamous RBV chip
1116                            (the IIsi is just a rebadged and crippled
1117                            IIci in a different case, BTW) */
1118                 case MAC_MODEL_IICI:
1119                 case MAC_MODEL_IISI:
1120                         macfb_setpalette = rbv_setpalette;
1121                         macfb_defined.activate = FB_ACTIVATE_NOW;
1122                         strcpy( fb_info.modename, "RBV built-in" );
1123                         rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
1124                         break;
1125
1126                         /* AVs use the Civic framebuffer */
1127                 case MAC_MODEL_Q840:
1128                 case MAC_MODEL_C660:
1129                         macfb_setpalette = civic_setpalette;
1130                         macfb_defined.activate = FB_ACTIVATE_NOW;
1131                         strcpy( fb_info.modename, "Civic built-in" );
1132                         civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
1133                         break;
1134
1135                 
1136                         /* Write a setpalette function for your machine, then
1137                            you can add something similar here.  These are
1138                            grouped by classes of video chipsets.  Some of this
1139                            information is from the VideoToolbox "Bugs" web
1140                            page at
1141                            http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */
1142
1143                         /* Assorted weirdos */
1144                         /* We think this may be like the LC II */
1145                 case MAC_MODEL_LC:
1146                         if (vidtest) {
1147                                 macfb_setpalette = v8_brazil_setpalette;
1148                                 macfb_defined.activate = FB_ACTIVATE_NOW;
1149                                 v8_brazil_cmap_regs =
1150                                         ioremap(DAC_BASE, 0x1000);
1151                         }
1152                         strcpy( fb_info.modename, "LC built-in" );
1153                         break;
1154                         /* We think this may be like the LC II */
1155                 case MAC_MODEL_CCL:
1156                         if (vidtest) {
1157                                 macfb_setpalette = v8_brazil_setpalette;
1158                                 macfb_defined.activate = FB_ACTIVATE_NOW;
1159                                 v8_brazil_cmap_regs =
1160                                         ioremap(DAC_BASE, 0x1000);
1161                         }
1162                         strcpy( fb_info.modename, "Color Classic built-in" );
1163                         break;
1164
1165                         /* And we *do* mean "weirdos" */
1166                 case MAC_MODEL_TV:
1167                         strcpy( fb_info.modename, "Mac TV built-in" );
1168                         break;
1169
1170                         /* These don't have colour, so no need to worry */
1171                 case MAC_MODEL_SE30:
1172                 case MAC_MODEL_CLII:
1173                         strcpy( fb_info.modename, "Monochrome built-in" );
1174                         break;
1175
1176                         /* Powerbooks are particularly difficult.  Many of
1177                            them have separate framebuffers for external and
1178                            internal video, which is admittedly pretty cool,
1179                            but will be a bit of a headache to support here.
1180                            Also, many of them are grayscale, and we don't
1181                            really support that. */
1182
1183                 case MAC_MODEL_PB140:
1184                 case MAC_MODEL_PB145:
1185                 case MAC_MODEL_PB170:
1186                         strcpy( fb_info.modename, "DDC built-in" );
1187                         break;
1188
1189                         /* Internal is GSC, External (if present) is ViSC */
1190                 case MAC_MODEL_PB150:   /* no external video */
1191                 case MAC_MODEL_PB160:
1192                 case MAC_MODEL_PB165:
1193                 case MAC_MODEL_PB180:
1194                 case MAC_MODEL_PB210:
1195                 case MAC_MODEL_PB230:
1196                         strcpy( fb_info.modename, "GSC built-in" );
1197                         break;
1198
1199                         /* Internal is TIM, External is ViSC */
1200                 case MAC_MODEL_PB165C:
1201                 case MAC_MODEL_PB180C:
1202                         strcpy( fb_info.modename, "TIM built-in" );
1203                         break;
1204
1205                         /* Internal is CSC, External is Keystone+Ariel. */
1206                 case MAC_MODEL_PB190:   /* external video is optional */
1207                 case MAC_MODEL_PB520:
1208                 case MAC_MODEL_PB250:
1209                 case MAC_MODEL_PB270C:
1210                 case MAC_MODEL_PB280:
1211                 case MAC_MODEL_PB280C:
1212                         macfb_setpalette = csc_setpalette;
1213                         macfb_defined.activate = FB_ACTIVATE_NOW;
1214                         strcpy( fb_info.modename, "CSC built-in" );
1215                         csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
1216                         break;
1217                 
1218                 default:
1219                         strcpy( fb_info.modename, "Unknown/Unsupported built-in" );
1220                         break;
1221                 }
1222         
1223         fb_info.changevar  = NULL;
1224         fb_info.node       = -1;
1225         fb_info.fbops      = &macfb_ops;
1226         fb_info.disp       = &disp;
1227         fb_info.switch_con = &macfb_switch;
1228         fb_info.updatevar  = &macfb_update_var;
1229         fb_info.blank      = &macfb_blank;
1230         fb_info.flags      = FBINFO_FLAG_DEFAULT;
1231         macfb_set_disp(-1);
1232         do_install_cmap(0, &fb_info);
1233         
1234         if (register_framebuffer(&fb_info) < 0)
1235                 return;
1236
1237         printk("fb%d: %s frame buffer device\n",
1238                GET_FB_IDX(fb_info.node), fb_info.modename);
1239 }
1240
1241 MODULE_LICENSE("GPL");