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