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
69static int (*macfb_setpalette) (unsigned int regno, unsigned int red,
70				unsigned int green, unsigned int blue) = NULL;
71static int valkyrie_setpalette (unsigned int regno, unsigned int red,
72				unsigned int green, unsigned int blue);
73static int dafb_setpalette (unsigned int regno, unsigned int red,
74			    unsigned int green, unsigned int blue);
75static int rbv_setpalette (unsigned int regno, unsigned int red,
76			   unsigned int green, unsigned int blue);
77static int mdc_setpalette (unsigned int regno, unsigned int red,
78			   unsigned int green, unsigned int blue);
79static int toby_setpalette (unsigned int regno, unsigned int red,
80			    unsigned int green, unsigned int blue);
81static int civic_setpalette (unsigned int regno, unsigned int red,
82			     unsigned int green, unsigned int blue);
83static int csc_setpalette (unsigned int regno, unsigned int red,
84			     unsigned int green, unsigned int blue);
85
86static volatile struct {
87	unsigned char addr;
88	/* Note: word-aligned */
89	char pad[3];
90	unsigned char lut;
91} *valkyrie_cmap_regs;
92
93static volatile struct {
94	unsigned char addr;
95	unsigned char lut;
96} *v8_brazil_cmap_regs;
97
98static 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
106static 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
113static 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
124static 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 */
134struct mdc_cmap_regs {
135	char pad1[0x200200];
136	unsigned char addr;
137	char pad2[6];
138	unsigned char lut;
139};
140
141struct 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
148struct 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
158static unsigned long video_base;
159static int   video_size;
160static char* video_vbase;        /* mapped */
161
162/* mode */
163static int  video_bpp;
164static int  video_width;
165static int  video_height;
166static int  video_type = FB_TYPE_PACKED_PIXELS;
167static int  video_visual;
168static int  video_linelength;
169static int  video_cmap_len;
170static int  video_slot = 0;
171
172static 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
191static struct display disp;
192static struct fb_info fb_info;
193static struct { u_short blue, green, red, pad; } palette[256];
194static 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
206static int             inverse   = 0;
207static int             vidtest   = 0;
208static int             currcon   = 0;
209
210static int macfb_update_var(int con, struct fb_info *info)
211{
212	return 0;
213}
214
215static 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
231static 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
241static 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
313static 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)
341static 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. */
373static int dafb_setpalette (unsigned int regno, unsigned int red,
374			    unsigned int green, unsigned int blue)
375{
376	static int lastreg = -1;
377	unsigned long flags;
378
379	red >>= 8;
380	green >>= 8;
381	blue >>= 8;
382
383	save_flags(flags);
384	cli();
385
386	/* fbcon will set an entire colourmap, but X won't.  Hopefully
387	   this should accomodate both of them */
388	if (regno != lastreg+1) {
389		int i;
390
391		/* Stab in the dark trying to reset the CLUT pointer */
392		nubus_writel(0, &dafb_cmap_regs->reset);
393		nop();
394
395		/* Loop until we get to the register we want */
396		for (i = 0; i < regno; i++) {
397			nubus_writeb(palette[i].red >> 8, &dafb_cmap_regs->lut);
398			nop();
399			nubus_writeb(palette[i].green >> 8, &dafb_cmap_regs->lut);
400			nop();
401			nubus_writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut);
402			nop();
403		}
404	}
405
406	nubus_writeb(red, &dafb_cmap_regs->lut);
407	nop();
408	nubus_writeb(green, &dafb_cmap_regs->lut);
409	nop();
410	nubus_writeb(blue, &dafb_cmap_regs->lut);
411
412	restore_flags(flags);
413
414	lastreg = regno;
415	return 0;
416}
417
418/* V8 and Brazil seem to use the same DAC.  Sonora does as well. */
419static int v8_brazil_setpalette (unsigned int regno, unsigned int red,
420				 unsigned int green, unsigned int blue)
421{
422	unsigned char _red  =red>>8;
423	unsigned char _green=green>>8;
424	unsigned char _blue =blue>>8;
425	unsigned char _regno;
426	unsigned long flags;
427
428	if (video_bpp>8) return 1; /* failsafe */
429
430	save_flags(flags);
431	cli();
432
433	/* On these chips, the CLUT register numbers are spread out
434	   across the register space.  Thus:
435
436	   In 8bpp, all regnos are valid.
437
438	   In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
439
440	   In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
441  	_regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp);
442	nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
443
444	/* send one color channel at a time */
445	nubus_writeb(_red, &v8_brazil_cmap_regs->lut); nop();
446	nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop();
447	nubus_writeb(_blue, &v8_brazil_cmap_regs->lut);
448
449	restore_flags(flags);
450
451	return 0;
452}
453
454static int rbv_setpalette (unsigned int regno, unsigned int red,
455			   unsigned int green, unsigned int blue)
456{
457	/* use MSBs */
458	unsigned char _red  =red>>8;
459	unsigned char _green=green>>8;
460	unsigned char _blue =blue>>8;
461	unsigned char _regno;
462	unsigned long flags;
463
464	if (video_bpp>8) return 1; /* failsafe */
465
466	save_flags(flags);
467	cli();
468
469	/* From the VideoToolbox driver.  Seems to be saying that
470	 * regno #254 and #255 are the important ones for 1-bit color,
471	 * regno #252-255 are the important ones for 2-bit color, etc.
472	 */
473	_regno = regno + (256-(1<<video_bpp));
474
475	/* reset clut? (VideoToolbox sez "not necessary") */
476	nubus_writeb(0xFF, &rbv_cmap_regs->cntl); nop();
477
478	/* tell clut which address to use. */
479	nubus_writeb(_regno, &rbv_cmap_regs->addr); nop();
480
481	/* send one color channel at a time. */
482	nubus_writeb(_red,   &rbv_cmap_regs->lut); nop();
483	nubus_writeb(_green, &rbv_cmap_regs->lut); nop();
484	nubus_writeb(_blue,  &rbv_cmap_regs->lut);
485
486	restore_flags(flags);
487	/* done. */
488	return 0;
489}
490
491/* Macintosh Display Card (8x24) */
492static int mdc_setpalette(unsigned int regno, unsigned int red,
493			  unsigned int green, unsigned int blue)
494{
495	volatile struct mdc_cmap_regs *cmap_regs =
496		nubus_slot_addr(video_slot);
497	/* use MSBs */
498	unsigned char _red  =red>>8;
499	unsigned char _green=green>>8;
500	unsigned char _blue =blue>>8;
501	unsigned char _regno=regno;
502	unsigned long flags;
503
504	save_flags(flags);
505	cli();
506
507	/* the nop's are there to order writes. */
508	nubus_writeb(_regno, &cmap_regs->addr); nop();
509	nubus_writeb(_red, &cmap_regs->lut);    nop();
510	nubus_writeb(_green, &cmap_regs->lut);  nop();
511	nubus_writeb(_blue, &cmap_regs->lut);
512
513	restore_flags(flags);
514	return 0;
515}
516
517/* Toby frame buffer */
518static int toby_setpalette(unsigned int regno, unsigned int red,
519			   unsigned int green, unsigned int blue)
520{
521	volatile struct toby_cmap_regs *cmap_regs =
522		nubus_slot_addr(video_slot);
523	/* use MSBs */
524	unsigned char _red  =~(red>>8);
525	unsigned char _green=~(green>>8);
526	unsigned char _blue =~(blue>>8);
527	unsigned char _regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp);
528	unsigned long flags;
529
530	save_flags(flags);
531	cli();
532
533	nubus_writeb(_regno, &cmap_regs->addr); nop();
534	nubus_writeb(_red, &cmap_regs->lut);    nop();
535	nubus_writeb(_green, &cmap_regs->lut);  nop();
536	nubus_writeb(_blue, &cmap_regs->lut);
537
538	restore_flags(flags);
539	return 0;
540}
541
542/* Jet frame buffer */
543static int jet_setpalette(unsigned int regno, unsigned int red,
544			  unsigned int green, unsigned int blue)
545{
546	volatile struct jet_cmap_regs *cmap_regs =
547		nubus_slot_addr(video_slot);
548	/* use MSBs */
549	unsigned char _red   = (red>>8);
550	unsigned char _green = (green>>8);
551	unsigned char _blue  = (blue>>8);
552	unsigned long flags;
553
554	save_flags(flags);
555	cli();
556
557	nubus_writeb(regno, &cmap_regs->addr); nop();
558	nubus_writeb(_red, &cmap_regs->lut); nop();
559	nubus_writeb(_green, &cmap_regs->lut); nop();
560	nubus_writeb(_blue, &cmap_regs->lut);
561
562	restore_flags(flags);
563	return 0;
564}
565
566static int civic_setpalette (unsigned int regno, unsigned int red,
567			     unsigned int green, unsigned int blue)
568{
569	static int lastreg = -1;
570	unsigned long flags;
571	int clut_status;
572
573	if (video_bpp > 8) return 1; /* failsafe */
574
575	red   >>= 8;
576	green >>= 8;
577	blue  >>= 8;
578
579	save_flags(flags);
580	cli();
581
582	/*
583	 * Set the register address
584	 */
585	nubus_writeb(regno, &civic_cmap_regs->addr); nop();
586
587	/*
588	 * Wait for VBL interrupt here;
589	 * They're usually not enabled from Penguin, so we won't check
590	 */
591
592	/*
593	 * Grab a status word and do some checking;
594	 * Then finally write the clut!
595	 */
596	clut_status =  nubus_readb(&civic_cmap_regs->status2);
597
598	if ((clut_status & 0x0008) == 0)
599	{
600
601		nubus_writeb(  red, &civic_cmap_regs->lut); nop();
602		nubus_writeb(green, &civic_cmap_regs->lut); nop();
603		nubus_writeb( blue, &civic_cmap_regs->lut); nop();
604		nubus_writeb( 0x00, &civic_cmap_regs->lut); nop();
605	}
606	else
607	{
608		unsigned char junk;
609
610		junk = nubus_readb(&civic_cmap_regs->lut); nop();
611		junk = nubus_readb(&civic_cmap_regs->lut); nop();
612		junk = nubus_readb(&civic_cmap_regs->lut); nop();
613		junk = nubus_readb(&civic_cmap_regs->lut); nop();
614
615		if ((clut_status & 0x000D) != 0)
616		{
617			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
618			nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
619		}
620
621		nubus_writeb(  red, &civic_cmap_regs->lut); nop();
622		nubus_writeb(green, &civic_cmap_regs->lut); nop();
623		nubus_writeb( blue, &civic_cmap_regs->lut); nop();
624		nubus_writeb( junk, &civic_cmap_regs->lut); nop();
625	}
626
627	restore_flags(flags);
628
629	lastreg = regno;
630	return 0;
631}
632
633/*
634 * The CSC is the framebuffer on the PowerBook 190 series
635 * (and the 5300 too, but that's a PowerMac). This function
636 * brought to you in part by the ECSC driver for MkLinux.
637 */
638
639static int csc_setpalette (unsigned int regno, unsigned int red,
640			     unsigned int green, unsigned int blue)
641{
642	mdelay(1);
643	csc_cmap_regs->clut_waddr = regno;
644	csc_cmap_regs->clut_data = red;
645	csc_cmap_regs->clut_data = green;
646	csc_cmap_regs->clut_data = blue;
647	return 0;
648}
649
650#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB4 || FBCON_HAS_CFB2 */
651
652static int macfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
653			   unsigned *blue, unsigned *transp,
654			   struct fb_info *fb_info)
655{
656	/*
657	 *  Read a single color register and split it into colors/transparent.
658	 *  Return != 0 for invalid regno.
659	 */
660
661	if (regno >= video_cmap_len)
662		return 1;
663
664	*red   = palette[regno].red;
665	*green = palette[regno].green;
666	*blue  = palette[regno].blue;
667	*transp = 0;
668	return 0;
669}
670
671static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
672			   unsigned blue, unsigned transp,
673			   struct fb_info *fb_info)
674{
675	/*
676	 *  Set a single color register. The values supplied are
677	 *  already rounded down to the hardware's capabilities
678	 *  (according to the entries in the `var' structure). Return
679	 *  != 0 for invalid regno.
680	 */
681
682	if (regno >= video_cmap_len)
683		return 1;
684
685	palette[regno].red   = red;
686	palette[regno].green = green;
687	palette[regno].blue  = blue;
688
689	switch (video_bpp) {
690#ifdef FBCON_HAS_MFB
691	case 1:
692		/* We shouldn't get here */
693		break;
694#endif
695#ifdef FBCON_HAS_CFB2
696	case 2:
697		if (macfb_setpalette)
698			macfb_setpalette(regno, red, green, blue);
699		else
700			return 1;
701		break;
702#endif
703#ifdef FBCON_HAS_CFB4
704	case 4:
705		if (macfb_setpalette)
706			macfb_setpalette(regno, red, green, blue);
707		else
708			return 1;
709		break;
710#endif
711#ifdef FBCON_HAS_CFB8
712	case 8:
713		if (macfb_setpalette)
714			macfb_setpalette(regno, red, green, blue);
715		else
716			return 1;
717		break;
718#endif
719#ifdef FBCON_HAS_CFB16
720	case 15:
721	case 16:
722		/* 1:5:5:5 */
723		fbcon_cmap.cfb16[regno] =
724			((red   & 0xf800) >>  1) |
725			((green & 0xf800) >>  6) |
726			((blue  & 0xf800) >> 11) |
727			((transp != 0) << 15);
728		break;
729#endif
730		/* I'm pretty sure that one or the other of these
731		   doesn't exist on 68k Macs */
732#ifdef FBCON_HAS_CFB24
733	case 24:
734		red   >>= 8;
735		green >>= 8;
736		blue  >>= 8;
737		fbcon_cmap.cfb24[regno] =
738			(red   << macfb_defined.red.offset)   |
739			(green << macfb_defined.green.offset) |
740			(blue  << macfb_defined.blue.offset);
741		break;
742#endif
743#ifdef FBCON_HAS_CFB32
744	case 32:
745		red   >>= 8;
746		green >>= 8;
747		blue  >>= 8;
748		fbcon_cmap.cfb32[regno] =
749			(red   << macfb_defined.red.offset)   |
750			(green << macfb_defined.green.offset) |
751			(blue  << macfb_defined.blue.offset);
752		break;
753#endif
754    }
755    return 0;
756}
757
758static void do_install_cmap(int con, struct fb_info *info)
759{
760	if (con != currcon)
761		return;
762	if (fb_display[con].cmap.len)
763		fb_set_cmap(&fb_display[con].cmap, 1, macfb_setcolreg, info);
764	else
765		fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
766			    macfb_setcolreg, info);
767}
768
769static int macfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
770			  struct fb_info *info)
771{
772	if (con == currcon) /* current console? */
773		return fb_get_cmap(cmap, kspc, macfb_getcolreg, info);
774	else if (fb_display[con].cmap.len) /* non default colormap? */
775		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
776	else
777		fb_copy_cmap(fb_default_cmap(video_cmap_len),
778		     cmap, kspc ? 0 : 2);
779	return 0;
780}
781
782static int macfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
783			  struct fb_info *info)
784{
785	int err;
786
787	if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
788		err = fb_alloc_cmap(&fb_display[con].cmap,video_cmap_len,0);
789		if (err)
790			return err;
791	}
792	if (con == currcon)			/* current console? */
793		return fb_set_cmap(cmap, kspc, macfb_setcolreg, info);
794	else
795		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
796	return 0;
797}
798
799static struct fb_ops macfb_ops = {
800	owner:		THIS_MODULE,
801	fb_get_fix:	macfb_get_fix,
802	fb_get_var:	macfb_get_var,
803	fb_set_var:	macfb_set_var,
804	fb_get_cmap:	macfb_get_cmap,
805	fb_set_cmap:	macfb_set_cmap,
806};
807
808void __init macfb_setup(char *options, int *ints)
809{
810	char *this_opt;
811
812	fb_info.fontname[0] = '\0';
813
814	if (!options || !*options)
815		return;
816
817	while ((this_opt = strsep(&options, ",")) != NULL) {
818		if (!*this_opt) continue;
819
820		if (! strcmp(this_opt, "inverse"))
821			inverse=1;
822		else if (!strncmp(this_opt, "font:", 5))
823			strcpy(fb_info.fontname, this_opt+5);
824		/* This means "turn on experimental CLUT code" */
825		else if (!strcmp(this_opt, "vidtest"))
826			vidtest=1;
827	}
828}
829
830static int macfb_switch(int con, struct fb_info *info)
831{
832	/* Do we have to save the colormap? */
833	if (fb_display[currcon].cmap.len)
834		fb_get_cmap(&fb_display[currcon].cmap, 1, macfb_getcolreg,
835			    info);
836
837	currcon = con;
838	/* Install new colormap */
839	do_install_cmap(con, info);
840	macfb_update_var(con, info);
841	return 1;
842}
843
844static void macfb_blank(int blank, struct fb_info *info)
845{
846	/* Not supported */
847}
848
849void __init macfb_init(void)
850{
851	struct nubus_dev* ndev = NULL;
852	int video_is_nubus = 0;
853
854	if (!MACH_IS_MAC)
855		return;
856
857	/* There can only be one internal video controller anyway so
858	   we're not too worried about this */
859	video_width      = mac_bi_data.dimensions & 0xFFFF;
860	video_height     = mac_bi_data.dimensions >> 16;
861	video_bpp        = mac_bi_data.videodepth;
862	video_linelength = mac_bi_data.videorow;
863	video_size       = video_linelength * video_height;
864	/* Note: physical address (since 2.1.127) */
865	video_base       = mac_bi_data.videoaddr;
866	/* This is actually redundant with the initial mappings.
867	   However, there are some non-obvious aspects to the way
868	   those mappings are set up, so this is in fact the safest
869	   way to ensure that this driver will work on every possible
870	   Mac */
871	video_vbase	 = ioremap(mac_bi_data.videoaddr, video_size);
872
873	printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
874	       video_base, video_vbase, video_size/1024);
875	printk("macfb: mode is %dx%dx%d, linelength=%d\n",
876	       video_width, video_height, video_bpp, video_linelength);
877
878	/*
879	 *	Fill in the available video resolution
880	 */
881
882	macfb_defined.xres           = video_width;
883	macfb_defined.yres           = video_height;
884	macfb_defined.xres_virtual   = video_width;
885	macfb_defined.yres_virtual   = video_height;
886	macfb_defined.bits_per_pixel = video_bpp;
887	macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
888	macfb_defined.width  = PIXEL_TO_MM(macfb_defined.xres);
889
890	printk("macfb: scrolling: redraw\n");
891	macfb_defined.yres_virtual = video_height;
892
893	/* some dummy values for timing to make fbset happy */
894	macfb_defined.pixclock     = 10000000 / video_width * 1000 / video_height;
895	macfb_defined.left_margin  = (video_width / 8) & 0xf8;
896	macfb_defined.right_margin = 32;
897	macfb_defined.upper_margin = 16;
898	macfb_defined.lower_margin = 4;
899	macfb_defined.hsync_len    = (video_width / 8) & 0xf8;
900	macfb_defined.vsync_len    = 4;
901
902	switch (video_bpp) {
903	case 1:
904		video_cmap_len = 0;
905		video_visual = FB_VISUAL_MONO01;
906		break;
907	case 2:
908	case 4:
909	case 8:
910		macfb_defined.red.length = video_bpp;
911		macfb_defined.green.length = video_bpp;
912		macfb_defined.blue.length = video_bpp;
913		video_cmap_len = 1 << video_bpp;
914		video_visual = FB_VISUAL_PSEUDOCOLOR;
915		break;
916	case 16:
917		macfb_defined.transp.offset = 15;
918		macfb_defined.transp.length = 1;
919		macfb_defined.red.offset = 10;
920		macfb_defined.red.length = 5;
921		macfb_defined.green.offset = 5;
922		macfb_defined.green.length = 5;
923		macfb_defined.blue.offset = 0;
924		macfb_defined.blue.length = 5;
925		printk("macfb: directcolor: "
926		       "size=1:5:5:5, shift=15:10:5:0\n");
927		video_cmap_len = 16;
928		/* Should actually be FB_VISUAL_DIRECTCOLOR, but this
929		   works too */
930		video_visual = FB_VISUAL_TRUECOLOR;
931		break;
932	case 24:
933	case 32:
934		macfb_defined.red.offset = 16;
935		macfb_defined.red.length = 8;
936		macfb_defined.green.offset = 8;
937		macfb_defined.green.length = 8;
938		macfb_defined.blue.offset = 0;
939		macfb_defined.blue.length = 8;
940		printk("macfb: truecolor: "
941		       "size=0:8:8:8, shift=0:16:8:0\n");
942		video_cmap_len = 16;
943		video_visual = FB_VISUAL_TRUECOLOR;
944	default:
945		video_cmap_len = 0;
946		video_visual = FB_VISUAL_MONO01;
947		printk("macfb: unknown or unsupported bit depth: %d\n", video_bpp);
948		break;
949	}
950
951	/* Hardware dependent stuff */
952	/*  We take a wild guess that if the video physical address is
953	 *  in nubus slot space, that the nubus card is driving video.
954	 *  Penguin really ought to tell us whether we are using internal
955	 *  video or not.
956	 */
957	/* Hopefully we only find one of them.  Otherwise our NuBus
958           code is really broken :-) */
959
960	while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev))
961		!= NULL)
962	{
963		if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr
964		      && (mac_bi_data.videoaddr <
965			  (unsigned long)nubus_slot_addr(ndev->board->slot+1))))
966			continue;
967		video_is_nubus = 1;
968		/* We should probably just use the slot address... */
969		video_slot = ndev->board->slot;
970
971		switch(ndev->dr_hw) {
972		case NUBUS_DRHW_APPLE_MDC:
973			strcpy( fb_info.modename, "Macintosh Display Card" );
974			macfb_setpalette = mdc_setpalette;
975			macfb_defined.activate = FB_ACTIVATE_NOW;
976			break;
977		case NUBUS_DRHW_APPLE_TFB:
978			strcpy( fb_info.modename, "Toby" );
979			macfb_setpalette = toby_setpalette;
980			macfb_defined.activate = FB_ACTIVATE_NOW;
981			break;
982		case NUBUS_DRHW_APPLE_JET:
983			strcpy(fb_info.modename, "Jet");
984			macfb_setpalette = jet_setpalette;
985			macfb_defined.activate = FB_ACTIVATE_NOW;
986			break;
987		default:
988			strcpy( fb_info.modename, "Generic NuBus" );
989			break;
990		}
991	}
992
993	/* If it's not a NuBus card, it must be internal video */
994	if (!video_is_nubus)
995		switch( mac_bi_data.id )
996		{
997			/* These don't have onboard video.  Eventually, we may
998			   be able to write separate framebuffer drivers for
999			   them (tobyfb.c, hiresfb.c, etc, etc) */
1000		case MAC_MODEL_II:
1001		case MAC_MODEL_IIX:
1002		case MAC_MODEL_IICX:
1003		case MAC_MODEL_IIFX:
1004			strcpy( fb_info.modename, "Generic NuBus" );
1005			break;
1006
1007			/* Valkyrie Quadras */
1008		case MAC_MODEL_Q630:
1009			/* I'm not sure about this one */
1010		case MAC_MODEL_P588:
1011			strcpy( fb_info.modename, "Valkyrie built-in" );
1012			macfb_setpalette = valkyrie_setpalette;
1013			macfb_defined.activate = FB_ACTIVATE_NOW;
1014			valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000);
1015			break;
1016
1017			/* DAFB Quadras */
1018			/* Note: these first four have the v7 DAFB, which is
1019			   known to be rather unlike the ones used in the
1020			   other models */
1021		case MAC_MODEL_P475:
1022		case MAC_MODEL_P475F:
1023		case MAC_MODEL_P575:
1024		case MAC_MODEL_Q605:
1025
1026		case MAC_MODEL_Q800:
1027		case MAC_MODEL_Q650:
1028		case MAC_MODEL_Q610:
1029		case MAC_MODEL_C650:
1030		case MAC_MODEL_C610:
1031		case MAC_MODEL_Q700:
1032		case MAC_MODEL_Q900:
1033		case MAC_MODEL_Q950:
1034			strcpy( fb_info.modename, "DAFB built-in" );
1035			macfb_setpalette = dafb_setpalette;
1036			macfb_defined.activate = FB_ACTIVATE_NOW;
1037			dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
1038			break;
1039
1040			/* LC II uses the V8 framebuffer */
1041		case MAC_MODEL_LCII:
1042			strcpy( fb_info.modename, "V8 built-in" );
1043			macfb_setpalette = v8_brazil_setpalette;
1044			macfb_defined.activate = FB_ACTIVATE_NOW;
1045			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
1046			break;
1047
1048			/* IIvi, IIvx use the "Brazil" framebuffer (which is
1049			   very much like the V8, it seems, and probably uses
1050			   the same DAC) */
1051		case MAC_MODEL_IIVI:
1052		case MAC_MODEL_IIVX:
1053		case MAC_MODEL_P600:
1054			strcpy( fb_info.modename, "Brazil built-in" );
1055			macfb_setpalette = v8_brazil_setpalette;
1056			macfb_defined.activate = FB_ACTIVATE_NOW;
1057			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
1058			break;
1059
1060			/* LC III (and friends) use the Sonora framebuffer */
1061			/* Incidentally this is also used in the non-AV models
1062			   of the x100 PowerMacs */
1063			/* These do in fact seem to use the same DAC interface
1064			   as the LC II. */
1065		case MAC_MODEL_LCIII:
1066		case MAC_MODEL_P520:
1067		case MAC_MODEL_P550:
1068		case MAC_MODEL_P460:
1069			macfb_setpalette = v8_brazil_setpalette;
1070			macfb_defined.activate = FB_ACTIVATE_NOW;
1071			strcpy( fb_info.modename, "Sonora built-in" );
1072			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
1073			break;
1074
1075			/* IIci and IIsi use the infamous RBV chip
1076                           (the IIsi is just a rebadged and crippled
1077                           IIci in a different case, BTW) */
1078		case MAC_MODEL_IICI:
1079		case MAC_MODEL_IISI:
1080			macfb_setpalette = rbv_setpalette;
1081			macfb_defined.activate = FB_ACTIVATE_NOW;
1082			strcpy( fb_info.modename, "RBV built-in" );
1083			rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
1084			break;
1085
1086			/* AVs use the Civic framebuffer */
1087		case MAC_MODEL_Q840:
1088		case MAC_MODEL_C660:
1089			macfb_setpalette = civic_setpalette;
1090			macfb_defined.activate = FB_ACTIVATE_NOW;
1091			strcpy( fb_info.modename, "Civic built-in" );
1092			civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
1093			break;
1094
1095
1096			/* Write a setpalette function for your machine, then
1097			   you can add something similar here.  These are
1098			   grouped by classes of video chipsets.  Some of this
1099			   information is from the VideoToolbox "Bugs" web
1100			   page at
1101			   http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */
1102
1103			/* Assorted weirdos */
1104			/* We think this may be like the LC II */
1105		case MAC_MODEL_LC:
1106			if (vidtest) {
1107				macfb_setpalette = v8_brazil_setpalette;
1108				macfb_defined.activate = FB_ACTIVATE_NOW;
1109				v8_brazil_cmap_regs =
1110					ioremap(DAC_BASE, 0x1000);
1111			}
1112			strcpy( fb_info.modename, "LC built-in" );
1113			break;
1114			/* We think this may be like the LC II */
1115		case MAC_MODEL_CCL:
1116			if (vidtest) {
1117				macfb_setpalette = v8_brazil_setpalette;
1118				macfb_defined.activate = FB_ACTIVATE_NOW;
1119				v8_brazil_cmap_regs =
1120					ioremap(DAC_BASE, 0x1000);
1121			}
1122			strcpy( fb_info.modename, "Color Classic built-in" );
1123			break;
1124
1125			/* And we *do* mean "weirdos" */
1126		case MAC_MODEL_TV:
1127			strcpy( fb_info.modename, "Mac TV built-in" );
1128			break;
1129
1130			/* These don't have colour, so no need to worry */
1131		case MAC_MODEL_SE30:
1132		case MAC_MODEL_CLII:
1133			strcpy( fb_info.modename, "Monochrome built-in" );
1134			break;
1135
1136			/* Powerbooks are particularly difficult.  Many of
1137			   them have separate framebuffers for external and
1138			   internal video, which is admittedly pretty cool,
1139			   but will be a bit of a headache to support here.
1140			   Also, many of them are grayscale, and we don't
1141			   really support that. */
1142
1143		case MAC_MODEL_PB140:
1144		case MAC_MODEL_PB145:
1145		case MAC_MODEL_PB170:
1146			strcpy( fb_info.modename, "DDC built-in" );
1147			break;
1148
1149			/* Internal is GSC, External (if present) is ViSC */
1150		case MAC_MODEL_PB150:	/* no external video */
1151		case MAC_MODEL_PB160:
1152		case MAC_MODEL_PB165:
1153		case MAC_MODEL_PB180:
1154		case MAC_MODEL_PB210:
1155		case MAC_MODEL_PB230:
1156			strcpy( fb_info.modename, "GSC built-in" );
1157			break;
1158
1159			/* Internal is TIM, External is ViSC */
1160		case MAC_MODEL_PB165C:
1161		case MAC_MODEL_PB180C:
1162			strcpy( fb_info.modename, "TIM built-in" );
1163			break;
1164
1165			/* Internal is CSC, External is Keystone+Ariel. */
1166		case MAC_MODEL_PB190:	/* external video is optional */
1167		case MAC_MODEL_PB520:
1168		case MAC_MODEL_PB250:
1169		case MAC_MODEL_PB270C:
1170		case MAC_MODEL_PB280:
1171		case MAC_MODEL_PB280C:
1172			macfb_setpalette = csc_setpalette;
1173			macfb_defined.activate = FB_ACTIVATE_NOW;
1174			strcpy( fb_info.modename, "CSC built-in" );
1175			csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
1176			break;
1177
1178		default:
1179			strcpy( fb_info.modename, "Unknown/Unsupported built-in" );
1180			break;
1181		}
1182
1183	fb_info.changevar  = NULL;
1184	fb_info.node       = -1;
1185	fb_info.fbops      = &macfb_ops;
1186	fb_info.disp       = &disp;
1187	fb_info.switch_con = &macfb_switch;
1188	fb_info.updatevar  = &macfb_update_var;
1189	fb_info.blank      = &macfb_blank;
1190	fb_info.flags      = FBINFO_FLAG_DEFAULT;
1191	macfb_set_disp(-1);
1192	do_install_cmap(0, &fb_info);
1193
1194	if (register_framebuffer(&fb_info) < 0)
1195		return;
1196
1197	printk("fb%d: %s frame buffer device\n",
1198	       GET_FB_IDX(fb_info.node), fb_info.modename);
1199}
1200
1201MODULE_LICENSE("GPL");
1202