File: /usr/src/linux/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 char* 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     	writeb(regno, &valkyrie_cmap_regs->addr);
355     	nop();
356     
357     	/* send one color channel at a time */
358     	writeb(red, &valkyrie_cmap_regs->lut);
359     	nop();
360     	writeb(green, &valkyrie_cmap_regs->lut);
361     	nop();
362     	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     		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     			writeb(palette[i].red >> 8, &dafb_cmap_regs->lut);
400     			nop();
401     			writeb(palette[i].green >> 8, &dafb_cmap_regs->lut);
402     			nop();
403     			writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut);
404     			nop();
405     		}
406     	}
407     		
408     	writeb(red, &dafb_cmap_regs->lut);
409     	nop();
410     	writeb(green, &dafb_cmap_regs->lut);
411     	nop();
412     	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     	writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
445     
446     	/* send one color channel at a time */
447     	writeb(_red, &v8_brazil_cmap_regs->lut); nop();
448     	writeb(_green, &v8_brazil_cmap_regs->lut); nop();
449     	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     	writeb(0xFF, &rbv_cmap_regs->cntl); nop();
479     	
480     	/* tell clut which address to use. */
481     	writeb(_regno, &rbv_cmap_regs->addr); nop();
482     	
483     	/* send one color channel at a time. */
484     	writeb(_red,   &rbv_cmap_regs->lut); nop();
485     	writeb(_green, &rbv_cmap_regs->lut); nop();
486     	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     	writeb(_regno, &cmap_regs->addr); nop();
511     	writeb(_red, &cmap_regs->lut);    nop();
512     	writeb(_green, &cmap_regs->lut);  nop();
513     	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     	writeb(_regno, &cmap_regs->addr); nop();
536     	writeb(_red, &cmap_regs->lut);    nop();
537     	writeb(_green, &cmap_regs->lut);  nop();
538     	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     	writeb(regno, &cmap_regs->addr); nop();
560     	writeb(_red, &cmap_regs->lut); nop();
561     	writeb(_green, &cmap_regs->lut); nop();
562     	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     	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 = 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 =  readb(&civic_cmap_regs->status2);
624     
625     	if ((clut_status & 0x0008) == 0)
626     	{
627     #if 0
628     		if ((clut_status & 0x000D) != 0)
629     		{
630     			writeb(0x00, &civic_cmap_regs->lut); nop();
631     			writeb(0x00, &civic_cmap_regs->lut); nop();
632     		}
633     #endif
634     
635     		writeb(  red, &civic_cmap_regs->lut); nop();
636     		writeb(green, &civic_cmap_regs->lut); nop();
637     		writeb( blue, &civic_cmap_regs->lut); nop();
638     		writeb( 0x00, &civic_cmap_regs->lut); nop();
639     	}
640     	else
641     	{
642     		unsigned char junk;
643     
644     		junk = readb(&civic_cmap_regs->lut); nop();
645     		junk = readb(&civic_cmap_regs->lut); nop();
646     		junk = readb(&civic_cmap_regs->lut); nop();
647     		junk = readb(&civic_cmap_regs->lut); nop();
648     
649     		if ((clut_status & 0x000D) != 0)
650     		{
651     			writeb(0x00, &civic_cmap_regs->lut); nop();
652     			writeb(0x00, &civic_cmap_regs->lut); nop();
653     		}
654     
655     		writeb(  red, &civic_cmap_regs->lut); nop();
656     		writeb(green, &civic_cmap_regs->lut); nop();
657     		writeb( blue, &civic_cmap_regs->lut); nop();
658     		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     	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(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       = (void*) 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%p, 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");
1242