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 
macfb_update_var(int con,struct fb_info * info)210 static int macfb_update_var(int con, struct fb_info *info)
211 {
212 	return 0;
213 }
214 
macfb_get_fix(struct fb_fix_screeninfo * fix,int con,struct fb_info * info)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 
macfb_get_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)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 
macfb_set_disp(int con)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 
macfb_set_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)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)
valkyrie_setpalette(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue)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. */
dafb_setpalette(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue)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. */
v8_brazil_setpalette(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue)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 
rbv_setpalette(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue)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) */
mdc_setpalette(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue)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 */
toby_setpalette(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue)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 */
jet_setpalette(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue)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  */
civic_setpalette(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue)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 
csc_setpalette(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue)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 
macfb_getcolreg(unsigned regno,unsigned * red,unsigned * green,unsigned * blue,unsigned * transp,struct fb_info * fb_info)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 
macfb_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info * fb_info)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 
do_install_cmap(int con,struct fb_info * info)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 
macfb_get_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)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 
macfb_set_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)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 
macfb_setup(char * options)842 void __init macfb_setup(char *options)
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 
macfb_switch(int con,struct fb_info * info)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 
macfb_blank(int blank,struct fb_info * info)878 static void macfb_blank(int blank, struct fb_info *info)
879 {
880 	/* Not supported */
881 }
882 
macfb_init(void)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");
1242