1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/config.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/string.h>
20#include <linux/mm.h>
21#include <linux/tty.h>
22#include <linux/slab.h>
23#include <linux/vmalloc.h>
24#include <linux/delay.h>
25#include <linux/interrupt.h>
26#include <linux/fb.h>
27#include <linux/selection.h>
28#include <linux/init.h>
29#include <linux/ioport.h>
30#ifdef CONFIG_FB_COMPAT_XPMAC
31#include <asm/vc_ioctl.h>
32#endif
33#include <asm/io.h>
34#include <asm/prom.h>
35#ifdef CONFIG_BOOTX_TEXT
36#include <asm/bootx.h>
37#endif
38
39#include <video/fbcon.h>
40#include <video/fbcon-cfb8.h>
41#include <video/fbcon-cfb16.h>
42#include <video/fbcon-cfb32.h>
43#include <video/macmodes.h>
44
45
46static int currcon = 0;
47
48
49enum {
50 cmap_unknown,
51 cmap_m64,
52 cmap_r128,
53 cmap_M3A,
54 cmap_M3B,
55 cmap_radeon,
56 cmap_gxt2000
57};
58
59struct fb_info_offb {
60 struct fb_info info;
61 struct fb_fix_screeninfo fix;
62 struct fb_var_screeninfo var;
63 struct display disp;
64 struct { u_char red, green, blue, pad; } palette[256];
65 volatile unsigned char *cmap_adr;
66 volatile unsigned char *cmap_data;
67 int cmap_type;
68 int blanked;
69 union {
70#ifdef FBCON_HAS_CFB16
71 u16 cfb16[16];
72#endif
73#ifdef FBCON_HAS_CFB32
74 u32 cfb32[16];
75#endif
76 } fbcon_cmap;
77};
78
79#ifdef __powerpc__
80#define mach_eieio() eieio()
81#else
82#define mach_eieio() do {} while (0)
83#endif
84
85
86
87
88
89
90int offb_init(void);
91
92static int offb_get_fix(struct fb_fix_screeninfo *fix, int con,
93 struct fb_info *info);
94static int offb_get_var(struct fb_var_screeninfo *var, int con,
95 struct fb_info *info);
96static int offb_set_var(struct fb_var_screeninfo *var, int con,
97 struct fb_info *info);
98static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
99 struct fb_info *info);
100static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
101 struct fb_info *info);
102#ifdef CONFIG_BOOTX_TEXT
103extern boot_infos_t *boot_infos;
104#endif
105
106static void offb_init_nodriver(struct device_node *);
107static void offb_init_fb(const char *name, const char *full_name, int width,
108 int height, int depth, int pitch, unsigned long address,
109 struct device_node *dp);
110
111
112
113
114
115static int offbcon_switch(int con, struct fb_info *info);
116static int offbcon_updatevar(int con, struct fb_info *info);
117static void offbcon_blank(int blank, struct fb_info *info);
118
119
120
121
122
123
124static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
125 u_int *transp, struct fb_info *info);
126static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
127 u_int transp, struct fb_info *info);
128static void do_install_cmap(int con, struct fb_info *info);
129
130
131static struct fb_ops offb_ops = {
132 owner: THIS_MODULE,
133 fb_get_fix: offb_get_fix,
134 fb_get_var: offb_get_var,
135 fb_set_var: offb_set_var,
136 fb_get_cmap: offb_get_cmap,
137 fb_set_cmap: offb_set_cmap,
138};
139
140
141
142
143
144static int offb_get_fix(struct fb_fix_screeninfo *fix, int con,
145 struct fb_info *info)
146{
147 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
148
149 memcpy(fix, &info2->fix, sizeof(struct fb_fix_screeninfo));
150 return 0;
151}
152
153
154
155
156
157
158static int offb_get_var(struct fb_var_screeninfo *var, int con,
159 struct fb_info *info)
160{
161 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
162
163 memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo));
164 return 0;
165}
166
167
168
169
170
171
172static int offb_set_var(struct fb_var_screeninfo *var, int con,
173 struct fb_info *info)
174{
175 struct display *display;
176 unsigned int oldbpp = 0;
177 int err;
178 int activate = var->activate;
179 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
180
181 if (con >= 0)
182 display = &fb_display[con];
183 else
184 display = &info2->disp;
185
186 if (var->xres > info2->var.xres || var->yres > info2->var.yres ||
187 var->xres_virtual > info2->var.xres_virtual ||
188 var->yres_virtual > info2->var.yres_virtual ||
189 var->bits_per_pixel > info2->var.bits_per_pixel ||
190 var->nonstd ||
191 (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
192 return -EINVAL;
193 memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo));
194
195 if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
196 oldbpp = display->var.bits_per_pixel;
197 display->var = *var;
198 }
199 if ((oldbpp != var->bits_per_pixel) || (display->cmap.len == 0)) {
200 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
201 return err;
202 do_install_cmap(con, info);
203 }
204 return 0;
205}
206
207
208
209
210
211
212static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
213 struct fb_info *info)
214{
215 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
216
217 if (con == currcon && !info2->blanked)
218 return fb_get_cmap(cmap, kspc, offb_getcolreg, info);
219 if (fb_display[con].cmap.len)
220 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
221 else
222 {
223 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
224 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
225 }
226 return 0;
227}
228
229
230
231
232
233static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
234 struct fb_info *info)
235{
236 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
237 int err;
238
239 if (!info2->cmap_adr)
240 return -ENOSYS;
241
242 if (!fb_display[con].cmap.len) {
243 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
244 if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
245 return err;
246 }
247 if (con == currcon && !info2->blanked)
248 return fb_set_cmap(cmap, kspc, offb_setcolreg, info);
249 else
250 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
251 return 0;
252}
253
254
255
256
257
258
259int __init offb_init(void)
260{
261 struct device_node *dp;
262 unsigned int dpy;
263#ifdef CONFIG_BOOTX_TEXT
264 struct device_node *displays = find_type_devices("display");
265 struct device_node *macos_display = NULL;
266
267
268 if (prom_num_displays == 0 && boot_infos != 0) {
269 unsigned long addr = (unsigned long) boot_infos->dispDeviceBase;
270
271 for (dp = displays; dp != NULL; dp = dp->next) {
272 int i;
273
274
275
276
277
278 if (strncmp(dp->name, "ATY,", 4) == 0 && dp->n_addrs == 1) {
279 unsigned int *ap = (unsigned int *)
280 get_property(dp, "AAPL,address", NULL);
281 if (ap != NULL) {
282 dp->addrs[0].address = *ap;
283 dp->addrs[0].size = 0x01000000;
284 }
285 }
286
287
288
289
290
291 if (dp->n_addrs == 0 && device_is_compatible(dp, "ATY,264LTPro")) {
292 int na;
293 unsigned int *ap = (unsigned int *)
294 get_property(dp, "AAPL,address", &na);
295 if (ap != 0)
296 for (na /= sizeof(unsigned int); na > 0; --na, ++ap)
297 if (*ap <= addr && addr < *ap + 0x1000000)
298 goto foundit;
299 }
300
301
302
303
304
305 for (i = 0; i < dp->n_addrs; ++i) {
306 if (dp->addrs[i].address <= addr
307 && addr < dp->addrs[i].address + dp->addrs[i].size)
308 break;
309 }
310 if (i < dp->n_addrs) {
311 foundit:
312 printk(KERN_INFO "MacOS display is %s\n", dp->full_name);
313 macos_display = dp;
314 break;
315 }
316 }
317
318
319 offb_init_fb(macos_display? macos_display->name: "MacOS display",
320 macos_display? macos_display->full_name: "MacOS display",
321 boot_infos->dispDeviceRect[2],
322 boot_infos->dispDeviceRect[3],
323 boot_infos->dispDeviceDepth,
324 boot_infos->dispDeviceRowBytes, addr, NULL);
325 }
326#endif
327
328 for (dpy = 0; dpy < prom_num_displays; dpy++) {
329 if ((dp = find_path_device(prom_display_paths[dpy])))
330 offb_init_nodriver(dp);
331 }
332 return 0;
333}
334
335
336static void __init offb_init_nodriver(struct device_node *dp)
337{
338 int *pp, i;
339 unsigned int len;
340 int width = 640, height = 480, depth = 8, pitch;
341 unsigned *up, address;
342
343 if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
344 && len == sizeof(int))
345 depth = *pp;
346 if ((pp = (int *)get_property(dp, "width", &len)) != NULL
347 && len == sizeof(int))
348 width = *pp;
349 if ((pp = (int *)get_property(dp, "height", &len)) != NULL
350 && len == sizeof(int))
351 height = *pp;
352 if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
353 && len == sizeof(int)) {
354 pitch = *pp;
355 if (pitch == 1)
356 pitch = 0x1000;
357 } else
358 pitch = width;
359 if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
360 && len == sizeof(unsigned))
361 address = (u_long)*up;
362 else {
363 for (i = 0; i < dp->n_addrs; ++i)
364 if (dp->addrs[i].size >= pitch*height*depth/8)
365 break;
366 if (i >= dp->n_addrs) {
367 printk(KERN_ERR "no framebuffer address found for %s\n", dp->full_name);
368 return;
369 }
370
371 address = (u_long)dp->addrs[i].address;
372
373
374 if (strcmp(dp->name, "valkyrie") == 0)
375 address += 0x1000;
376 }
377 offb_init_fb(dp->name, dp->full_name, width, height, depth,
378 pitch, address, dp);
379
380}
381
382static void __init offb_init_fb(const char *name, const char *full_name,
383 int width, int height, int depth,
384 int pitch, unsigned long address,
385 struct device_node *dp)
386{
387 int i;
388 struct fb_fix_screeninfo *fix;
389 struct fb_var_screeninfo *var;
390 struct display *disp;
391 struct fb_info_offb *info;
392 unsigned long res_start = address;
393 unsigned long res_size = pitch*height*depth/8;
394
395 if (!request_mem_region(res_start, res_size, "offb"))
396 return;
397
398 printk(KERN_INFO "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
399 width, height, name, address, depth, pitch);
400 if (depth != 8 && depth != 16 && depth != 32) {
401 printk(KERN_ERR "%s: can't use depth = %d\n", full_name, depth);
402 release_mem_region(res_start, res_size);
403 return;
404 }
405
406 info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
407 if (info == 0) {
408 release_mem_region(res_start, res_size);
409 return;
410 }
411 memset(info, 0, sizeof(*info));
412
413 fix = &info->fix;
414 var = &info->var;
415 disp = &info->disp;
416
417 strcpy(fix->id, "OFfb ");
418 strncat(fix->id, name, sizeof(fix->id));
419 fix->id[sizeof(fix->id)-1] = '\0';
420
421 var->xres = var->xres_virtual = width;
422 var->yres = var->yres_virtual = height;
423 fix->line_length = pitch;
424
425 fix->smem_start = address;
426 fix->smem_len = pitch * height;
427 fix->type = FB_TYPE_PACKED_PIXELS;
428 fix->type_aux = 0;
429
430 info->cmap_type = cmap_unknown;
431 if (depth == 8)
432 {
433
434 if (dp && !strncmp(name, "ATY,Rage128", 11)) {
435 unsigned long regbase = dp->addrs[2].address;
436 info->cmap_adr = ioremap(regbase, 0x1FFF);
437 info->cmap_type = cmap_r128;
438 } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
439 || !strncmp(name, "ATY,RageM3p12A", 14))) {
440 unsigned long regbase = dp->parent->addrs[2].address;
441 info->cmap_adr = ioremap(regbase, 0x1FFF);
442 info->cmap_type = cmap_M3A;
443 } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
444 unsigned long regbase = dp->parent->addrs[2].address;
445 info->cmap_adr = ioremap(regbase, 0x1FFF);
446 info->cmap_type = cmap_M3B;
447 } else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
448 unsigned long regbase = dp->addrs[1].address;
449 info->cmap_adr = ioremap(regbase, 0x1FFF);
450 info->cmap_type = cmap_radeon;
451 } else if (!strncmp(name, "ATY,", 4)) {
452
453
454
455
456
457 unsigned long base = address & 0xff000000UL;
458 info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
459 info->cmap_data = info->cmap_adr + 1;
460 info->cmap_type = cmap_m64;
461 } else if (dp && device_is_compatible(dp, "pci1014,b7")) {
462 unsigned long regbase = dp->addrs[0].address;
463 info->cmap_adr = ioremap(regbase + 0x6000, 0x1000);
464 info->cmap_type = cmap_gxt2000;
465 }
466 fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
467 : FB_VISUAL_STATIC_PSEUDOCOLOR;
468 }
469 else
470 fix->visual =
471FB_VISUAL_TRUECOLOR;
472
473 var->xoffset = var->yoffset = 0;
474 var->bits_per_pixel = depth;
475 switch (depth) {
476 case 8:
477 var->bits_per_pixel = 8;
478 var->red.offset = 0;
479 var->red.length = 8;
480 var->green.offset = 0;
481 var->green.length = 8;
482 var->blue.offset = 0;
483 var->blue.length = 8;
484 var->transp.offset = 0;
485 var->transp.length = 0;
486 break;
487 case 16:
488 var->bits_per_pixel = 16;
489 var->red.offset = 10;
490 var->red.length = 5;
491 var->green.offset = 5;
492 var->green.length = 5;
493 var->blue.offset = 0;
494 var->blue.length = 5;
495 var->transp.offset = 0;
496 var->transp.length = 0;
497 break;
498 case 32:
499 var->bits_per_pixel = 32;
500 var->red.offset = 16;
501 var->red.length = 8;
502 var->green.offset = 8;
503 var->green.length = 8;
504 var->blue.offset = 0;
505 var->blue.length = 8;
506 var->transp.offset = 24;
507 var->transp.length = 8;
508 break;
509 }
510 var->red.msb_right = var->green.msb_right = var->blue.msb_right = var->transp.msb_right = 0;
511 var->grayscale = 0;
512 var->nonstd = 0;
513 var->activate = 0;
514 var->height = var->width = -1;
515 var->pixclock = 10000;
516 var->left_margin = var->right_margin = 16;
517 var->upper_margin = var->lower_margin = 16;
518 var->hsync_len = var->vsync_len = 8;
519 var->sync = 0;
520 var->vmode = FB_VMODE_NONINTERLACED;
521
522 disp->var = *var;
523 disp->cmap.start = 0;
524 disp->cmap.len = 0;
525 disp->cmap.red = NULL;
526 disp->cmap.green = NULL;
527 disp->cmap.blue = NULL;
528 disp->cmap.transp = NULL;
529 disp->screen_base = ioremap(address, fix->smem_len);
530 disp->visual = fix->visual;
531 disp->type = fix->type;
532 disp->type_aux = fix->type_aux;
533 disp->ypanstep = 0;
534 disp->ywrapstep = 0;
535 disp->line_length = fix->line_length;
536 disp->can_soft_blank = info->cmap_adr ? 1 : 0;
537 disp->inverse = 0;
538 switch (depth) {
539#ifdef FBCON_HAS_CFB8
540 case 8:
541 disp->dispsw = &fbcon_cfb8;
542 break;
543#endif
544#ifdef FBCON_HAS_CFB16
545 case 16:
546 disp->dispsw = &fbcon_cfb16;
547 disp->dispsw_data = info->fbcon_cmap.cfb16;
548 for (i = 0; i < 16; i++)
549 if (fix->visual == FB_VISUAL_TRUECOLOR)
550 info->fbcon_cmap.cfb16[i] =
551 (((default_blu[i] >> 3) & 0x1f) << 10) |
552 (((default_grn[i] >> 3) & 0x1f) << 5) |
553 ((default_red[i] >> 3) & 0x1f);
554 else
555 info->fbcon_cmap.cfb16[i] =
556 (i << 10) | (i << 5) | i;
557 break;
558#endif
559#ifdef FBCON_HAS_CFB32
560 case 32:
561 disp->dispsw = &fbcon_cfb32;
562 disp->dispsw_data = info->fbcon_cmap.cfb32;
563 for (i = 0; i < 16; i++)
564 if (fix->visual == FB_VISUAL_TRUECOLOR)
565 info->fbcon_cmap.cfb32[i] =
566 (default_blu[i] << 16) |
567 (default_grn[i] << 8) |
568 default_red[i];
569 else
570 info->fbcon_cmap.cfb32[i] =
571 (i << 16) | (i << 8) | i;
572 break;
573#endif
574 default:
575 disp->dispsw = &fbcon_dummy;
576 }
577
578 disp->scrollmode = SCROLL_YREDRAW;
579
580 strcpy(info->info.modename, "OFfb ");
581 strncat(info->info.modename, full_name, sizeof(info->info.modename));
582 info->info.node = -1;
583 info->info.fbops = &offb_ops;
584 info->info.disp = disp;
585 info->info.fontname[0] = '\0';
586 info->info.changevar = NULL;
587 info->info.switch_con = &offbcon_switch;
588 info->info.updatevar = &offbcon_updatevar;
589 info->info.blank = &offbcon_blank;
590 info->info.flags = FBINFO_FLAG_DEFAULT;
591
592 for (i = 0; i < 16; i++) {
593 int j = color_table[i];
594 info->palette[i].red = default_red[j];
595 info->palette[i].green = default_grn[j];
596 info->palette[i].blue = default_blu[j];
597 }
598 offb_set_var(var, -1, &info->info);
599
600 if (register_framebuffer(&info->info) < 0) {
601 kfree(info);
602 release_mem_region(res_start, res_size);
603 return;
604 }
605
606 printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n",
607 GET_FB_IDX(info->info.node), full_name);
608
609#ifdef CONFIG_FB_COMPAT_XPMAC
610 if (!console_fb_info) {
611 display_info.height = var->yres;
612 display_info.width = var->xres;
613 display_info.depth = depth;
614 display_info.pitch = fix->line_length;
615 display_info.mode = 0;
616 strncpy(display_info.name, name, sizeof(display_info.name));
617 display_info.fb_address = address;
618 display_info.cmap_adr_address = 0;
619 display_info.cmap_data_address = 0;
620 display_info.disp_reg_address = 0;
621
622 if (info->cmap_type == cmap_m64) {
623 unsigned long base = address & 0xff000000UL;
624 display_info.disp_reg_address = base + 0x7ffc00;
625 display_info.cmap_adr_address = base + 0x7ffcc0;
626 display_info.cmap_data_address = base + 0x7ffcc1;
627 }
628 console_fb_info = &info->info;
629 }
630#endif
631}
632
633
634static int offbcon_switch(int con, struct fb_info *info)
635{
636 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
637
638
639 if (fb_display[currcon].cmap.len && !info2->blanked)
640 fb_get_cmap(&fb_display[currcon].cmap, 1, offb_getcolreg, info);
641
642 currcon = con;
643
644 do_install_cmap(con, info);
645 return 0;
646}
647
648
649
650
651
652static int offbcon_updatevar(int con, struct fb_info *info)
653{
654
655 return 0;
656}
657
658
659
660
661
662static void offbcon_blank(int blank, struct fb_info *info)
663{
664 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
665 int i, j;
666
667 if (!info2->cmap_adr)
668 return;
669
670 if (!info2->blanked) {
671 if (!blank)
672 return;
673 if (fb_display[currcon].cmap.len)
674 fb_get_cmap(&fb_display[currcon].cmap, 1, offb_getcolreg, info);
675 }
676
677 info2->blanked = blank;
678
679 if (blank)
680 for (i = 0; i < 256; i++) {
681 switch(info2->cmap_type) {
682 case cmap_m64:
683 *info2->cmap_adr = i;
684 mach_eieio();
685 for (j = 0; j < 3; j++) {
686 *info2->cmap_data = 0;
687 mach_eieio();
688 }
689 break;
690 case cmap_M3A:
691
692 out_le32((unsigned *)(info2->cmap_adr + 0x58),
693 in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20);
694 case cmap_r128:
695
696 out_8(info2->cmap_adr + 0xb0, i);
697 out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
698 break;
699 case cmap_M3B:
700
701 out_le32((unsigned *)(info2->cmap_adr + 0x58),
702 in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20);
703
704 out_8(info2->cmap_adr + 0xb0, i);
705 out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
706 break;
707 case cmap_radeon:
708 out_8(info2->cmap_adr + 0xb0, i);
709 out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
710 break;
711 case cmap_gxt2000:
712 out_le32((unsigned *)info2->cmap_adr + i, 0);
713 break;
714 }
715 }
716 else
717 do_install_cmap(currcon, info);
718}
719
720
721
722
723
724
725static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
726 u_int *transp, struct fb_info *info)
727{
728 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
729
730 if (!info2->cmap_adr || regno > 255)
731 return 1;
732
733 *red = (info2->palette[regno].red<<8) | info2->palette[regno].red;
734 *green = (info2->palette[regno].green<<8) | info2->palette[regno].green;
735 *blue = (info2->palette[regno].blue<<8) | info2->palette[regno].blue;
736 *transp = 0;
737 return 0;
738}
739
740
741
742
743
744
745
746
747static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
748 u_int transp, struct fb_info *info)
749{
750 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
751
752 if (!info2->cmap_adr || regno > 255)
753 return 1;
754
755 red >>= 8;
756 green >>= 8;
757 blue >>= 8;
758
759 info2->palette[regno].red = red;
760 info2->palette[regno].green = green;
761 info2->palette[regno].blue = blue;
762
763 switch(info2->cmap_type) {
764 case cmap_m64:
765 *info2->cmap_adr = regno;
766 mach_eieio();
767 *info2->cmap_data = red;
768 mach_eieio();
769 *info2->cmap_data = green;
770 mach_eieio();
771 *info2->cmap_data = blue;
772 mach_eieio();
773 break;
774 case cmap_M3A:
775
776 out_le32((unsigned *)(info2->cmap_adr + 0x58),
777 in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20);
778 case cmap_r128:
779
780 out_8(info2->cmap_adr + 0xb0, regno);
781 out_le32((unsigned *)(info2->cmap_adr + 0xb4),
782 (red << 16 | green << 8 | blue));
783 break;
784 case cmap_M3B:
785
786 out_le32((unsigned *)(info2->cmap_adr + 0x58),
787 in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20);
788
789 out_8(info2->cmap_adr + 0xb0, regno);
790 out_le32((unsigned *)(info2->cmap_adr + 0xb4),
791 (red << 16 | green << 8 | blue));
792 break;
793 case cmap_radeon:
794
795 out_8(info2->cmap_adr + 0xb0, regno);
796 out_le32((unsigned *)(info2->cmap_adr + 0xb4),
797 (red << 16 | green << 8 | blue));
798 break;
799 case cmap_gxt2000:
800 out_le32((unsigned *)info2->cmap_adr + regno,
801 (red << 16 | green << 8 | blue));
802 break;
803 }
804
805 if (regno < 16)
806 switch (info2->var.bits_per_pixel) {
807#ifdef FBCON_HAS_CFB16
808 case 16:
809 info2->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
810 break;
811#endif
812#ifdef FBCON_HAS_CFB32
813 case 32:
814 {
815 int i = (regno << 8) | regno;
816 info2->fbcon_cmap.cfb32[regno] = (i << 16) | i;
817 break;
818 }
819#endif
820 }
821
822 return 0;
823}
824
825
826static void do_install_cmap(int con, struct fb_info *info)
827{
828 if (con != currcon)
829 return;
830 if (fb_display[con].cmap.len)
831 fb_set_cmap(&fb_display[con].cmap, 1, offb_setcolreg, info);
832 else
833 {
834 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
835 fb_set_cmap(fb_default_cmap(size), 1, offb_setcolreg, info);
836 }
837}
838
839MODULE_LICENSE("GPL");
840