blob: a92322558ec061a29344c00d85502d1f5c7b2ab5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* 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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/errno.h>
24#include <linux/string.h>
25#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/slab.h>
27#include <linux/delay.h>
28#include <linux/nubus.h>
29#include <linux/init.h>
30#include <linux/fb.h>
31
32#include <asm/setup.h>
33#include <asm/bootinfo.h>
34#include <asm/uaccess.h>
35#include <asm/pgtable.h>
36#include <asm/irq.h>
37#include <asm/macintosh.h>
38#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */
41#define DAC_BASE 0x50f24000
42
43/* Some addresses for the DAFB */
44#define DAFB_BASE 0xf9800200
45
46/* Address for the built-in Civic framebuffer in Quadra AVs */
47#define CIVIC_BASE 0x50f30800 /* Only tested on 660AV! */
48
49/* GSC (Gray Scale Controller) base address */
50#define GSC_BASE 0x50F20000
51
52/* CSC (Color Screen Controller) base address */
53#define CSC_BASE 0x50F20000
54
55static int (*macfb_setpalette) (unsigned int regno, unsigned int red,
56 unsigned int green, unsigned int blue,
57 struct fb_info *info) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058static int dafb_setpalette (unsigned int regno, unsigned int red,
59 unsigned int green, unsigned int blue,
60 struct fb_info *fb_info);
61static int rbv_setpalette (unsigned int regno, unsigned int red,
62 unsigned int green, unsigned int blue,
63 struct fb_info *fb_info);
64static int mdc_setpalette (unsigned int regno, unsigned int red,
65 unsigned int green, unsigned int blue,
66 struct fb_info *fb_info);
67static int toby_setpalette (unsigned int regno, unsigned int red,
68 unsigned int green, unsigned int blue,
69 struct fb_info *fb_info);
70static int civic_setpalette (unsigned int regno, unsigned int red,
71 unsigned int green, unsigned int blue,
72 struct fb_info *fb_info);
73static int csc_setpalette (unsigned int regno, unsigned int red,
74 unsigned int green, unsigned int blue,
75 struct fb_info *fb_info);
76
Finn Thain3839d012008-11-18 20:45:22 +010077static struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 unsigned char addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 unsigned char lut;
Finn Thain3839d012008-11-18 20:45:22 +010080} __iomem *v8_brazil_cmap_regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Finn Thain3839d012008-11-18 20:45:22 +010082static struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 unsigned char addr;
84 char pad1[3]; /* word aligned */
85 unsigned char lut;
86 char pad2[3]; /* word aligned */
87 unsigned char cntl; /* a guess as to purpose */
Finn Thain3839d012008-11-18 20:45:22 +010088} __iomem *rbv_cmap_regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Finn Thain3839d012008-11-18 20:45:22 +010090static struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 unsigned long reset;
92 unsigned long pad1[3];
93 unsigned char pad2[3];
94 unsigned char lut;
Finn Thain3839d012008-11-18 20:45:22 +010095} __iomem *dafb_cmap_regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Finn Thain3839d012008-11-18 20:45:22 +010097static struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 unsigned char addr; /* OFFSET: 0x00 */
99 unsigned char pad1[15];
100 unsigned char lut; /* OFFSET: 0x10 */
101 unsigned char pad2[15];
102 unsigned char status; /* OFFSET: 0x20 */
103 unsigned char pad3[7];
104 unsigned long vbl_addr; /* OFFSET: 0x28 */
105 unsigned int status2; /* OFFSET: 0x2C */
Finn Thain3839d012008-11-18 20:45:22 +0100106} __iomem *civic_cmap_regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Finn Thain3839d012008-11-18 20:45:22 +0100108static struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 char pad1[0x40];
110 unsigned char clut_waddr; /* 0x40 */
111 char pad2;
112 unsigned char clut_data; /* 0x42 */
113 char pad3[0x3];
114 unsigned char clut_raddr; /* 0x46 */
Finn Thain3839d012008-11-18 20:45:22 +0100115} __iomem *csc_cmap_regs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117/* We will leave these the way they are for the time being */
118struct mdc_cmap_regs {
119 char pad1[0x200200];
120 unsigned char addr;
121 char pad2[6];
122 unsigned char lut;
123};
124
125struct toby_cmap_regs {
126 char pad1[0x90018];
127 unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */
128 char pad2[3];
129 unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */
130};
131
132struct jet_cmap_regs {
133 char pad1[0xe0e000];
134 unsigned char addr;
135 unsigned char lut;
136};
137
138#define PIXEL_TO_MM(a) (((a)*10)/28) /* width in mm at 72 dpi */
139
140/* mode */
141static int video_slot = 0;
142
143static struct fb_var_screeninfo macfb_defined = {
144 .bits_per_pixel = 8,
145 .activate = FB_ACTIVATE_NOW,
146 .width = -1,
147 .height = -1,
148 .right_margin = 32,
149 .upper_margin = 16,
150 .lower_margin = 4,
151 .vsync_len = 4,
152 .vmode = FB_VMODE_NONINTERLACED,
153};
154
155static struct fb_fix_screeninfo macfb_fix = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 .type = FB_TYPE_PACKED_PIXELS,
157 .accel = FB_ACCEL_NONE,
158};
159
160static struct fb_info fb_info;
Antonino A. Daplas24fc7222007-07-17 04:05:37 -0700161static u32 pseudo_palette[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static int inverse = 0;
163static int vidtest = 0;
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165/* Unlike the Valkyrie, the DAFB cannot set individual colormap
166 registers. Therefore, we do what the MacOS driver does (no
167 kidding!) and simply set them one by one until we hit the one we
168 want. */
169static int dafb_setpalette (unsigned int regno, unsigned int red,
170 unsigned int green, unsigned int blue,
171 struct fb_info *info)
172{
173 /* FIXME: really, really need to use ioremap() here,
174 phys_to_virt() doesn't work anymore */
175 static int lastreg = -1;
176 unsigned long flags;
177
178 red >>= 8;
179 green >>= 8;
180 blue >>= 8;
181
182 local_irq_save(flags);
183
184 /* fbdev will set an entire colourmap, but X won't. Hopefully
185 this should accommodate both of them */
186 if (regno != lastreg+1) {
187 int i;
188
189 /* Stab in the dark trying to reset the CLUT pointer */
190 nubus_writel(0, &dafb_cmap_regs->reset);
191 nop();
192
193 /* Loop until we get to the register we want */
194 for (i = 0; i < regno; i++) {
195 nubus_writeb(info->cmap.red[i] >> 8, &dafb_cmap_regs->lut);
196 nop();
197 nubus_writeb(info->cmap.green[i] >> 8, &dafb_cmap_regs->lut);
198 nop();
199 nubus_writeb(info->cmap.blue[i] >> 8, &dafb_cmap_regs->lut);
200 nop();
201 }
202 }
203
204 nubus_writeb(red, &dafb_cmap_regs->lut);
205 nop();
206 nubus_writeb(green, &dafb_cmap_regs->lut);
207 nop();
208 nubus_writeb(blue, &dafb_cmap_regs->lut);
209
210 local_irq_restore(flags);
211 lastreg = regno;
212 return 0;
213}
214
215/* V8 and Brazil seem to use the same DAC. Sonora does as well. */
216static int v8_brazil_setpalette (unsigned int regno, unsigned int red,
217 unsigned int green, unsigned int blue,
218 struct fb_info *info)
219{
220 unsigned int bpp = info->var.bits_per_pixel;
221 unsigned char _red =red>>8;
222 unsigned char _green=green>>8;
223 unsigned char _blue =blue>>8;
224 unsigned char _regno;
225 unsigned long flags;
226
227 if (bpp > 8) return 1; /* failsafe */
228
229 local_irq_save(flags);
230
231 /* On these chips, the CLUT register numbers are spread out
232 across the register space. Thus:
233
234 In 8bpp, all regnos are valid.
235
236 In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
237
238 In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
239 _regno = (regno << (8 - bpp)) | (0xFF >> bpp);
240 nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
241
242 /* send one color channel at a time */
243 nubus_writeb(_red, &v8_brazil_cmap_regs->lut); nop();
244 nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop();
245 nubus_writeb(_blue, &v8_brazil_cmap_regs->lut);
246
247 local_irq_restore(flags);
248 return 0;
249}
250
251static int rbv_setpalette (unsigned int regno, unsigned int red,
252 unsigned int green, unsigned int blue,
253 struct fb_info *info)
254{
255 /* use MSBs */
256 unsigned char _red =red>>8;
257 unsigned char _green=green>>8;
258 unsigned char _blue =blue>>8;
259 unsigned char _regno;
260 unsigned long flags;
261
262 if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
263
264 local_irq_save(flags);
265
266 /* From the VideoToolbox driver. Seems to be saying that
267 * regno #254 and #255 are the important ones for 1-bit color,
268 * regno #252-255 are the important ones for 2-bit color, etc.
269 */
270 _regno = regno + (256-(1 << info->var.bits_per_pixel));
271
272 /* reset clut? (VideoToolbox sez "not necessary") */
273 nubus_writeb(0xFF, &rbv_cmap_regs->cntl); nop();
274
275 /* tell clut which address to use. */
276 nubus_writeb(_regno, &rbv_cmap_regs->addr); nop();
277
278 /* send one color channel at a time. */
279 nubus_writeb(_red, &rbv_cmap_regs->lut); nop();
280 nubus_writeb(_green, &rbv_cmap_regs->lut); nop();
281 nubus_writeb(_blue, &rbv_cmap_regs->lut);
282
283 local_irq_restore(flags); /* done. */
284 return 0;
285}
286
287/* Macintosh Display Card (8x24) */
288static int mdc_setpalette(unsigned int regno, unsigned int red,
289 unsigned int green, unsigned int blue,
290 struct fb_info *info)
291{
292 volatile struct mdc_cmap_regs *cmap_regs =
293 nubus_slot_addr(video_slot);
294 /* use MSBs */
295 unsigned char _red =red>>8;
296 unsigned char _green=green>>8;
297 unsigned char _blue =blue>>8;
298 unsigned char _regno=regno;
299 unsigned long flags;
300
301 local_irq_save(flags);
302
303 /* the nop's are there to order writes. */
304 nubus_writeb(_regno, &cmap_regs->addr); nop();
305 nubus_writeb(_red, &cmap_regs->lut); nop();
306 nubus_writeb(_green, &cmap_regs->lut); nop();
307 nubus_writeb(_blue, &cmap_regs->lut);
308
309 local_irq_restore(flags);
310 return 0;
311}
312
313/* Toby frame buffer */
314static int toby_setpalette(unsigned int regno, unsigned int red,
315 unsigned int green, unsigned int blue,
316 struct fb_info *info)
317{
318 volatile struct toby_cmap_regs *cmap_regs =
319 nubus_slot_addr(video_slot);
320 unsigned int bpp = info->var.bits_per_pixel;
321 /* use MSBs */
322 unsigned char _red =~(red>>8);
323 unsigned char _green=~(green>>8);
324 unsigned char _blue =~(blue>>8);
325 unsigned char _regno = (regno << (8 - bpp)) | (0xFF >> bpp);
326 unsigned long flags;
327
328 local_irq_save(flags);
329
330 nubus_writeb(_regno, &cmap_regs->addr); nop();
331 nubus_writeb(_red, &cmap_regs->lut); nop();
332 nubus_writeb(_green, &cmap_regs->lut); nop();
333 nubus_writeb(_blue, &cmap_regs->lut);
334
335 local_irq_restore(flags);
336 return 0;
337}
338
339/* Jet frame buffer */
340static int jet_setpalette(unsigned int regno, unsigned int red,
341 unsigned int green, unsigned int blue,
342 struct fb_info *info)
343{
344 volatile struct jet_cmap_regs *cmap_regs =
345 nubus_slot_addr(video_slot);
346 /* use MSBs */
347 unsigned char _red = (red>>8);
348 unsigned char _green = (green>>8);
349 unsigned char _blue = (blue>>8);
350 unsigned long flags;
351
352 local_irq_save(flags);
353
354 nubus_writeb(regno, &cmap_regs->addr); nop();
355 nubus_writeb(_red, &cmap_regs->lut); nop();
356 nubus_writeb(_green, &cmap_regs->lut); nop();
357 nubus_writeb(_blue, &cmap_regs->lut);
358
359 local_irq_restore(flags);
360 return 0;
361}
362
363/*
364 * Civic framebuffer -- Quadra AV built-in video. A chip
365 * called Sebastian holds the actual color palettes, and
366 * apparently, there are two different banks of 512K RAM
367 * which can act as separate framebuffers for doing video
368 * input and viewing the screen at the same time! The 840AV
369 * Can add another 1MB RAM to give the two framebuffers
370 * 1MB RAM apiece.
371 *
372 * FIXME: this doesn't seem to work anymore.
373 */
374static int civic_setpalette (unsigned int regno, unsigned int red,
375 unsigned int green, unsigned int blue,
376 struct fb_info *info)
377{
378 static int lastreg = -1;
379 unsigned long flags;
380 int clut_status;
381
382 if (info->var.bits_per_pixel > 8) return 1; /* failsafe */
383
384 red >>= 8;
385 green >>= 8;
386 blue >>= 8;
387
388 local_irq_save(flags);
389
390 /*
391 * Set the register address
392 */
393 nubus_writeb(regno, &civic_cmap_regs->addr); nop();
394
395 /*
396 * Wait for VBL interrupt here;
397 * They're usually not enabled from Penguin, so we won't check
398 */
399#if 0
400 {
401#define CIVIC_VBL_OFFSET 0x120
402 volatile unsigned long *vbl = nubus_readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
403 /* do interrupt setup stuff here? */
404 *vbl = 0L; nop(); /* clear */
405 *vbl = 1L; nop(); /* set */
406 while (*vbl != 0L) /* wait for next vbl */
407 {
408 usleep(10); /* needed? */
409 }
410 /* do interrupt shutdown stuff here? */
411 }
412#endif
413
414 /*
415 * Grab a status word and do some checking;
416 * Then finally write the clut!
417 */
418 clut_status = nubus_readb(&civic_cmap_regs->status2);
419
420 if ((clut_status & 0x0008) == 0)
421 {
422#if 0
423 if ((clut_status & 0x000D) != 0)
424 {
425 nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
426 nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
427 }
428#endif
429
430 nubus_writeb( red, &civic_cmap_regs->lut); nop();
431 nubus_writeb(green, &civic_cmap_regs->lut); nop();
432 nubus_writeb( blue, &civic_cmap_regs->lut); nop();
433 nubus_writeb( 0x00, &civic_cmap_regs->lut); nop();
434 }
435 else
436 {
437 unsigned char junk;
438
439 junk = nubus_readb(&civic_cmap_regs->lut); nop();
440 junk = nubus_readb(&civic_cmap_regs->lut); nop();
441 junk = nubus_readb(&civic_cmap_regs->lut); nop();
442 junk = nubus_readb(&civic_cmap_regs->lut); nop();
443
444 if ((clut_status & 0x000D) != 0)
445 {
446 nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
447 nubus_writeb(0x00, &civic_cmap_regs->lut); nop();
448 }
449
450 nubus_writeb( red, &civic_cmap_regs->lut); nop();
451 nubus_writeb(green, &civic_cmap_regs->lut); nop();
452 nubus_writeb( blue, &civic_cmap_regs->lut); nop();
453 nubus_writeb( junk, &civic_cmap_regs->lut); nop();
454 }
455
456 local_irq_restore(flags);
457 lastreg = regno;
458 return 0;
459}
460
461/*
462 * The CSC is the framebuffer on the PowerBook 190 series
463 * (and the 5300 too, but that's a PowerMac). This function
464 * brought to you in part by the ECSC driver for MkLinux.
465 */
466
467static int csc_setpalette (unsigned int regno, unsigned int red,
468 unsigned int green, unsigned int blue,
469 struct fb_info *info)
470{
471 mdelay(1);
Finn Thain3839d012008-11-18 20:45:22 +0100472 nubus_writeb(regno, &csc_cmap_regs->clut_waddr);
473 nubus_writeb(red, &csc_cmap_regs->clut_data);
474 nubus_writeb(green, &csc_cmap_regs->clut_data);
475 nubus_writeb(blue, &csc_cmap_regs->clut_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 return 0;
477}
478
479static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
480 unsigned blue, unsigned transp,
481 struct fb_info *fb_info)
482{
483 /*
484 * Set a single color register. The values supplied are
485 * already rounded down to the hardware's capabilities
486 * (according to the entries in the `var' structure). Return
487 * != 0 for invalid regno.
488 */
489
490 if (regno >= fb_info->cmap.len)
491 return 1;
492
Antonino A. Daplas24fc7222007-07-17 04:05:37 -0700493 if (fb_info->var.bits_per_pixel <= 8) {
494 switch (fb_info->var.bits_per_pixel) {
495 case 1:
496 /* We shouldn't get here */
497 break;
498 case 2:
499 case 4:
500 case 8:
501 if (macfb_setpalette)
502 macfb_setpalette(regno, red, green, blue,
503 fb_info);
504 else
505 return 1;
506 break;
507 }
508 } else if (regno < 16) {
509 switch (fb_info->var.bits_per_pixel) {
510 case 16:
511 if (fb_info->var.red.offset == 10) {
512 /* 1:5:5:5 */
513 ((u32*) (fb_info->pseudo_palette))[regno] =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 ((red & 0xf800) >> 1) |
515 ((green & 0xf800) >> 6) |
516 ((blue & 0xf800) >> 11) |
517 ((transp != 0) << 15);
Antonino A. Daplas24fc7222007-07-17 04:05:37 -0700518 } else {
519 /* 0:5:6:5 */
520 ((u32*) (fb_info->pseudo_palette))[regno] =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 ((red & 0xf800) ) |
522 ((green & 0xfc00) >> 5) |
523 ((blue & 0xf800) >> 11);
Antonino A. Daplas24fc7222007-07-17 04:05:37 -0700524 }
525 break;
526 /* I'm pretty sure that one or the other of these
527 doesn't exist on 68k Macs */
528 case 24:
529 red >>= 8;
530 green >>= 8;
531 blue >>= 8;
532 ((u32 *)(fb_info->pseudo_palette))[regno] =
533 (red << fb_info->var.red.offset) |
534 (green << fb_info->var.green.offset) |
535 (blue << fb_info->var.blue.offset);
536 break;
537 case 32:
538 red >>= 8;
539 green >>= 8;
540 blue >>= 8;
541 ((u32 *)(fb_info->pseudo_palette))[regno] =
542 (red << fb_info->var.red.offset) |
543 (green << fb_info->var.green.offset) |
544 (blue << fb_info->var.blue.offset);
545 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 }
Antonino A. Daplas24fc7222007-07-17 04:05:37 -0700547 }
548
549 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550}
551
552static struct fb_ops macfb_ops = {
553 .owner = THIS_MODULE,
554 .fb_setcolreg = macfb_setcolreg,
555 .fb_fillrect = cfb_fillrect,
556 .fb_copyarea = cfb_copyarea,
557 .fb_imageblit = cfb_imageblit,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558};
559
Adrian Bunk511e7482008-07-25 19:46:26 -0700560static void __init macfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
562 char *this_opt;
563
564 if (!options || !*options)
565 return;
566
567 while ((this_opt = strsep(&options, ",")) != NULL) {
568 if (!*this_opt) continue;
569
570 if (! strcmp(this_opt, "inverse"))
571 inverse=1;
572 /* This means "turn on experimental CLUT code" */
573 else if (!strcmp(this_opt, "vidtest"))
574 vidtest=1;
575 }
576}
577
Amol Lad164a7652006-12-08 02:40:09 -0800578static void __init iounmap_macfb(void)
579{
Amol Lad164a7652006-12-08 02:40:09 -0800580 if (dafb_cmap_regs)
581 iounmap(dafb_cmap_regs);
582 if (v8_brazil_cmap_regs)
583 iounmap(v8_brazil_cmap_regs);
584 if (rbv_cmap_regs)
585 iounmap(rbv_cmap_regs);
586 if (civic_cmap_regs)
587 iounmap(civic_cmap_regs);
588 if (csc_cmap_regs)
589 iounmap(csc_cmap_regs);
590}
591
Al Viroed1705a2006-01-12 01:06:39 -0800592static int __init macfb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
594 int video_cmap_len, video_is_nubus = 0;
595 struct nubus_dev* ndev = NULL;
596 char *option = NULL;
Al Viroed1705a2006-01-12 01:06:39 -0800597 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 if (fb_get_options("macfb", &option))
600 return -ENODEV;
601 macfb_setup(option);
602
603 if (!MACH_IS_MAC)
Al Viroed1705a2006-01-12 01:06:39 -0800604 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Finn Thain11e8fac2009-11-04 00:43:52 +1100606 if (mac_bi_data.id == MAC_MODEL_Q630 ||
607 mac_bi_data.id == MAC_MODEL_P588)
608 return -ENODEV; /* See valkyriefb.c */
609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 /* There can only be one internal video controller anyway so
611 we're not too worried about this */
612 macfb_defined.xres = mac_bi_data.dimensions & 0xFFFF;
613 macfb_defined.yres = mac_bi_data.dimensions >> 16;
614 macfb_defined.bits_per_pixel = mac_bi_data.videodepth;
615 macfb_fix.line_length = mac_bi_data.videorow;
616 macfb_fix.smem_len = macfb_fix.line_length * macfb_defined.yres;
617 /* Note: physical address (since 2.1.127) */
618 macfb_fix.smem_start = mac_bi_data.videoaddr;
619 /* This is actually redundant with the initial mappings.
620 However, there are some non-obvious aspects to the way
621 those mappings are set up, so this is in fact the safest
622 way to ensure that this driver will work on every possible
623 Mac */
624 fb_info.screen_base = ioremap(mac_bi_data.videoaddr, macfb_fix.smem_len);
625
626 printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
627 macfb_fix.smem_start, fb_info.screen_base, macfb_fix.smem_len/1024);
628 printk("macfb: mode is %dx%dx%d, linelength=%d\n",
629 macfb_defined.xres, macfb_defined.yres, macfb_defined.bits_per_pixel, macfb_fix.line_length);
630
631 /*
632 * Fill in the available video resolution
633 */
634
635 macfb_defined.xres_virtual = macfb_defined.xres;
636 macfb_defined.yres_virtual = macfb_defined.yres;
637 macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
638 macfb_defined.width = PIXEL_TO_MM(macfb_defined.xres);
639
640 printk("macfb: scrolling: redraw\n");
641 macfb_defined.yres_virtual = macfb_defined.yres;
642
643 /* some dummy values for timing to make fbset happy */
644 macfb_defined.pixclock = 10000000 / macfb_defined.xres * 1000 / macfb_defined.yres;
645 macfb_defined.left_margin = (macfb_defined.xres / 8) & 0xf8;
646 macfb_defined.hsync_len = (macfb_defined.xres / 8) & 0xf8;
647
648 switch (macfb_defined.bits_per_pixel) {
649 case 1:
650 /* XXX: I think this will catch any program that tries
651 to do FBIO_PUTCMAP when the visual is monochrome */
652 macfb_defined.red.length = macfb_defined.bits_per_pixel;
653 macfb_defined.green.length = macfb_defined.bits_per_pixel;
654 macfb_defined.blue.length = macfb_defined.bits_per_pixel;
655 video_cmap_len = 0;
656 macfb_fix.visual = FB_VISUAL_MONO01;
657 break;
658 case 2:
659 case 4:
660 case 8:
661 macfb_defined.red.length = macfb_defined.bits_per_pixel;
662 macfb_defined.green.length = macfb_defined.bits_per_pixel;
663 macfb_defined.blue.length = macfb_defined.bits_per_pixel;
664 video_cmap_len = 1 << macfb_defined.bits_per_pixel;
665 macfb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
666 break;
667 case 16:
668 macfb_defined.transp.offset = 15;
669 macfb_defined.transp.length = 1;
670 macfb_defined.red.offset = 10;
671 macfb_defined.red.length = 5;
672 macfb_defined.green.offset = 5;
673 macfb_defined.green.length = 5;
674 macfb_defined.blue.offset = 0;
675 macfb_defined.blue.length = 5;
676 printk("macfb: directcolor: "
677 "size=1:5:5:5, shift=15:10:5:0\n");
678 video_cmap_len = 16;
679 /* Should actually be FB_VISUAL_DIRECTCOLOR, but this
680 works too */
681 macfb_fix.visual = FB_VISUAL_TRUECOLOR;
682 break;
683 case 24:
684 case 32:
685 /* XXX: have to test these... can any 68k Macs
686 actually do this on internal video? */
687 macfb_defined.red.offset = 16;
688 macfb_defined.red.length = 8;
689 macfb_defined.green.offset = 8;
690 macfb_defined.green.length = 8;
691 macfb_defined.blue.offset = 0;
692 macfb_defined.blue.length = 8;
693 printk("macfb: truecolor: "
694 "size=0:8:8:8, shift=0:16:8:0\n");
695 video_cmap_len = 16;
696 macfb_fix.visual = FB_VISUAL_TRUECOLOR;
697 default:
698 video_cmap_len = 0;
699 macfb_fix.visual = FB_VISUAL_MONO01;
700 printk("macfb: unknown or unsupported bit depth: %d\n", macfb_defined.bits_per_pixel);
701 break;
702 }
703
704 /* Hardware dependent stuff */
705 /* We take a wild guess that if the video physical address is
706 * in nubus slot space, that the nubus card is driving video.
707 * Penguin really ought to tell us whether we are using internal
708 * video or not.
709 */
710 /* Hopefully we only find one of them. Otherwise our NuBus
711 code is really broken :-) */
712
713 while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev))
714 != NULL)
715 {
716 if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr
717 && (mac_bi_data.videoaddr <
718 (unsigned long)nubus_slot_addr(ndev->board->slot+1))))
719 continue;
720 video_is_nubus = 1;
721 /* We should probably just use the slot address... */
722 video_slot = ndev->board->slot;
723
724 switch(ndev->dr_hw) {
725 case NUBUS_DRHW_APPLE_MDC:
Finn Thain89c223a2008-11-18 20:40:40 +0100726 strcpy(macfb_fix.id, "Mac Disp. Card");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 macfb_setpalette = mdc_setpalette;
728 macfb_defined.activate = FB_ACTIVATE_NOW;
729 break;
730 case NUBUS_DRHW_APPLE_TFB:
Finn Thain89c223a2008-11-18 20:40:40 +0100731 strcpy(macfb_fix.id, "Toby");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 macfb_setpalette = toby_setpalette;
733 macfb_defined.activate = FB_ACTIVATE_NOW;
734 break;
735 case NUBUS_DRHW_APPLE_JET:
Finn Thain89c223a2008-11-18 20:40:40 +0100736 strcpy(macfb_fix.id, "Jet");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 macfb_setpalette = jet_setpalette;
738 macfb_defined.activate = FB_ACTIVATE_NOW;
739 break;
740 default:
Finn Thain89c223a2008-11-18 20:40:40 +0100741 strcpy(macfb_fix.id, "Generic NuBus");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 break;
743 }
744 }
745
746 /* If it's not a NuBus card, it must be internal video */
747 /* FIXME: this function is getting way too big. (this driver
748 is too...) */
749 if (!video_is_nubus)
750 switch( mac_bi_data.id )
751 {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 /* DAFB Quadras */
753 /* Note: these first four have the v7 DAFB, which is
754 known to be rather unlike the ones used in the
755 other models */
756 case MAC_MODEL_P475:
757 case MAC_MODEL_P475F:
758 case MAC_MODEL_P575:
759 case MAC_MODEL_Q605:
760
761 case MAC_MODEL_Q800:
762 case MAC_MODEL_Q650:
763 case MAC_MODEL_Q610:
764 case MAC_MODEL_C650:
765 case MAC_MODEL_C610:
766 case MAC_MODEL_Q700:
767 case MAC_MODEL_Q900:
768 case MAC_MODEL_Q950:
Finn Thain89c223a2008-11-18 20:40:40 +0100769 strcpy(macfb_fix.id, "DAFB");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 macfb_setpalette = dafb_setpalette;
771 macfb_defined.activate = FB_ACTIVATE_NOW;
772 dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
773 break;
774
775 /* LC II uses the V8 framebuffer */
776 case MAC_MODEL_LCII:
Finn Thain89c223a2008-11-18 20:40:40 +0100777 strcpy(macfb_fix.id, "V8");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 macfb_setpalette = v8_brazil_setpalette;
779 macfb_defined.activate = FB_ACTIVATE_NOW;
780 v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
781 break;
782
783 /* IIvi, IIvx use the "Brazil" framebuffer (which is
784 very much like the V8, it seems, and probably uses
785 the same DAC) */
786 case MAC_MODEL_IIVI:
787 case MAC_MODEL_IIVX:
788 case MAC_MODEL_P600:
Finn Thain89c223a2008-11-18 20:40:40 +0100789 strcpy(macfb_fix.id, "Brazil");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 macfb_setpalette = v8_brazil_setpalette;
791 macfb_defined.activate = FB_ACTIVATE_NOW;
792 v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
793 break;
794
795 /* LC III (and friends) use the Sonora framebuffer */
796 /* Incidentally this is also used in the non-AV models
797 of the x100 PowerMacs */
798 /* These do in fact seem to use the same DAC interface
799 as the LC II. */
800 case MAC_MODEL_LCIII:
801 case MAC_MODEL_P520:
802 case MAC_MODEL_P550:
803 case MAC_MODEL_P460:
804 macfb_setpalette = v8_brazil_setpalette;
805 macfb_defined.activate = FB_ACTIVATE_NOW;
Finn Thain89c223a2008-11-18 20:40:40 +0100806 strcpy(macfb_fix.id, "Sonora");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
808 break;
809
810 /* IIci and IIsi use the infamous RBV chip
811 (the IIsi is just a rebadged and crippled
812 IIci in a different case, BTW) */
813 case MAC_MODEL_IICI:
814 case MAC_MODEL_IISI:
815 macfb_setpalette = rbv_setpalette;
816 macfb_defined.activate = FB_ACTIVATE_NOW;
Finn Thain89c223a2008-11-18 20:40:40 +0100817 strcpy(macfb_fix.id, "RBV");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
819 break;
820
821 /* AVs use the Civic framebuffer */
822 case MAC_MODEL_Q840:
823 case MAC_MODEL_C660:
824 macfb_setpalette = civic_setpalette;
825 macfb_defined.activate = FB_ACTIVATE_NOW;
Finn Thain89c223a2008-11-18 20:40:40 +0100826 strcpy(macfb_fix.id, "Civic");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
828 break;
829
830
831 /* Write a setpalette function for your machine, then
832 you can add something similar here. These are
833 grouped by classes of video chipsets. Some of this
834 information is from the VideoToolbox "Bugs" web
835 page at
836 http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */
837
838 /* Assorted weirdos */
839 /* We think this may be like the LC II */
840 case MAC_MODEL_LC:
841 if (vidtest) {
842 macfb_setpalette = v8_brazil_setpalette;
843 macfb_defined.activate = FB_ACTIVATE_NOW;
844 v8_brazil_cmap_regs =
845 ioremap(DAC_BASE, 0x1000);
846 }
Finn Thain89c223a2008-11-18 20:40:40 +0100847 strcpy(macfb_fix.id, "LC");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 break;
849 /* We think this may be like the LC II */
850 case MAC_MODEL_CCL:
851 if (vidtest) {
852 macfb_setpalette = v8_brazil_setpalette;
853 macfb_defined.activate = FB_ACTIVATE_NOW;
854 v8_brazil_cmap_regs =
855 ioremap(DAC_BASE, 0x1000);
856 }
Finn Thain89c223a2008-11-18 20:40:40 +0100857 strcpy(macfb_fix.id, "Color Classic");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 break;
859
860 /* And we *do* mean "weirdos" */
861 case MAC_MODEL_TV:
Finn Thain89c223a2008-11-18 20:40:40 +0100862 strcpy(macfb_fix.id, "Mac TV");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 break;
864
865 /* These don't have colour, so no need to worry */
866 case MAC_MODEL_SE30:
867 case MAC_MODEL_CLII:
Finn Thain89c223a2008-11-18 20:40:40 +0100868 strcpy(macfb_fix.id, "Monochrome");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 break;
870
871 /* Powerbooks are particularly difficult. Many of
872 them have separate framebuffers for external and
873 internal video, which is admittedly pretty cool,
874 but will be a bit of a headache to support here.
875 Also, many of them are grayscale, and we don't
876 really support that. */
877
878 case MAC_MODEL_PB140:
879 case MAC_MODEL_PB145:
880 case MAC_MODEL_PB170:
Finn Thain89c223a2008-11-18 20:40:40 +0100881 strcpy(macfb_fix.id, "DDC");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 break;
883
884 /* Internal is GSC, External (if present) is ViSC */
885 case MAC_MODEL_PB150: /* no external video */
886 case MAC_MODEL_PB160:
887 case MAC_MODEL_PB165:
888 case MAC_MODEL_PB180:
889 case MAC_MODEL_PB210:
890 case MAC_MODEL_PB230:
Finn Thain89c223a2008-11-18 20:40:40 +0100891 strcpy(macfb_fix.id, "GSC");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 break;
893
894 /* Internal is TIM, External is ViSC */
895 case MAC_MODEL_PB165C:
896 case MAC_MODEL_PB180C:
Finn Thain89c223a2008-11-18 20:40:40 +0100897 strcpy(macfb_fix.id, "TIM");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 break;
899
900 /* Internal is CSC, External is Keystone+Ariel. */
901 case MAC_MODEL_PB190: /* external video is optional */
902 case MAC_MODEL_PB520:
903 case MAC_MODEL_PB250:
904 case MAC_MODEL_PB270C:
905 case MAC_MODEL_PB280:
906 case MAC_MODEL_PB280C:
907 macfb_setpalette = csc_setpalette;
908 macfb_defined.activate = FB_ACTIVATE_NOW;
Finn Thain89c223a2008-11-18 20:40:40 +0100909 strcpy(macfb_fix.id, "CSC");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
911 break;
912
913 default:
Finn Thain89c223a2008-11-18 20:40:40 +0100914 strcpy(macfb_fix.id, "Unknown");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 break;
916 }
917
918 fb_info.fbops = &macfb_ops;
919 fb_info.var = macfb_defined;
920 fb_info.fix = macfb_fix;
921 fb_info.pseudo_palette = pseudo_palette;
922 fb_info.flags = FBINFO_DEFAULT;
923
Finn Thain89c223a2008-11-18 20:40:40 +0100924 err = fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
925 if (err)
926 goto fail_unmap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Al Viroed1705a2006-01-12 01:06:39 -0800928 err = register_framebuffer(&fb_info);
Finn Thain89c223a2008-11-18 20:40:40 +0100929 if (err)
930 goto fail_dealloc;
931
932 printk("fb%d: %s frame buffer device\n",
933 fb_info.node, fb_info.fix.id);
934 return 0;
935
936fail_dealloc:
937 fb_dealloc_cmap(&fb_info.cmap);
938fail_unmap:
939 iounmap(fb_info.screen_base);
940 iounmap_macfb();
Al Viroed1705a2006-01-12 01:06:39 -0800941 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942}
943
944module_init(macfb_init);
945MODULE_LICENSE("GPL");