Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / drivers / video / offb.c
blob1a1b7a3db3697dbfa86f479afb8a352fbc2323d0
1 /*
2 * linux/drivers/video/offb.c -- Open Firmware based frame buffer device
4 * Copyright (C) 1997 Geert Uytterhoeven
6 * This driver is partly based on the PowerMac console driver:
8 * Copyright (C) 1996 Paul Mackerras
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file COPYING in the main directory of this archive for
12 * more details.
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/malloc.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 #include <asm/bootx.h>
37 #include <video/fbcon.h>
38 #include <video/fbcon-cfb8.h>
39 #include <video/fbcon-cfb16.h>
40 #include <video/fbcon-cfb32.h>
41 #include <video/macmodes.h>
44 static int currcon = 0;
46 /* Supported palette hacks */
47 enum {
48 cmap_unknown,
49 cmap_m64, /* ATI Mach64 */
50 cmap_r128, /* ATI Rage128 */
51 cmap_M3A, /* ATI Rage Mobility M3 Head A */
52 cmap_M3B /* ATI Rage Mobility M3 Head B */
55 struct fb_info_offb {
56 struct fb_info info;
57 struct fb_fix_screeninfo fix;
58 struct fb_var_screeninfo var;
59 struct display disp;
60 struct { u_char red, green, blue, pad; } palette[256];
61 volatile unsigned char *cmap_adr;
62 volatile unsigned char *cmap_data;
63 int cmap_type;
64 union {
65 #ifdef FBCON_HAS_CFB16
66 u16 cfb16[16];
67 #endif
68 #ifdef FBCON_HAS_CFB32
69 u32 cfb32[16];
70 #endif
71 } fbcon_cmap;
74 #ifdef __powerpc__
75 #define mach_eieio() eieio()
76 #else
77 #define mach_eieio() do {} while (0)
78 #endif
82 * Interface used by the world
85 int offb_init(void);
87 static int offb_get_fix(struct fb_fix_screeninfo *fix, int con,
88 struct fb_info *info);
89 static int offb_get_var(struct fb_var_screeninfo *var, int con,
90 struct fb_info *info);
91 static int offb_set_var(struct fb_var_screeninfo *var, int con,
92 struct fb_info *info);
93 static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
94 struct fb_info *info);
95 static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
96 struct fb_info *info);
98 extern boot_infos_t *boot_infos;
100 static void offb_init_nodriver(struct device_node *);
101 static void offb_init_fb(const char *name, const char *full_name, int width,
102 int height, int depth, int pitch, unsigned long address,
103 struct device_node *dp);
106 * Interface to the low level console driver
109 static int offbcon_switch(int con, struct fb_info *info);
110 static int offbcon_updatevar(int con, struct fb_info *info);
111 static void offbcon_blank(int blank, struct fb_info *info);
115 * Internal routines
118 static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
119 u_int *transp, struct fb_info *info);
120 static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
121 u_int transp, struct fb_info *info);
122 static void do_install_cmap(int con, struct fb_info *info);
125 static struct fb_ops offb_ops = {
126 owner: THIS_MODULE,
127 fb_get_fix: offb_get_fix,
128 fb_get_var: offb_get_var,
129 fb_set_var: offb_set_var,
130 fb_get_cmap: offb_get_cmap,
131 fb_set_cmap: offb_set_cmap,
135 * Get the Fixed Part of the Display
138 static int offb_get_fix(struct fb_fix_screeninfo *fix, int con,
139 struct fb_info *info)
141 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
143 memcpy(fix, &info2->fix, sizeof(struct fb_fix_screeninfo));
144 return 0;
149 * Get the User Defined Part of the Display
152 static int offb_get_var(struct fb_var_screeninfo *var, int con,
153 struct fb_info *info)
155 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
157 memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo));
158 return 0;
163 * Set the User Defined Part of the Display
166 static int offb_set_var(struct fb_var_screeninfo *var, int con,
167 struct fb_info *info)
169 struct display *display;
170 unsigned int oldbpp = 0;
171 int err;
172 int activate = var->activate;
173 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
175 if (con >= 0)
176 display = &fb_display[con];
177 else
178 display = &info2->disp; /* used during initialization */
180 if (var->xres > info2->var.xres || var->yres > info2->var.yres ||
181 var->xres_virtual > info2->var.xres_virtual ||
182 var->yres_virtual > info2->var.yres_virtual ||
183 var->bits_per_pixel > info2->var.bits_per_pixel ||
184 var->nonstd ||
185 (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
186 return -EINVAL;
187 memcpy(var, &info2->var, sizeof(struct fb_var_screeninfo));
189 if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
190 oldbpp = display->var.bits_per_pixel;
191 display->var = *var;
193 if ((oldbpp != var->bits_per_pixel) || (display->cmap.len == 0)) {
194 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
195 return err;
196 do_install_cmap(con, info);
198 return 0;
203 * Get the Colormap
206 static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
207 struct fb_info *info)
209 if (con == currcon) /* current console? */
210 return fb_get_cmap(cmap, kspc, offb_getcolreg, info);
211 else if (fb_display[con].cmap.len) /* non default colormap? */
212 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
213 else
215 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
216 fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
218 return 0;
222 * Set the Colormap
225 static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
226 struct fb_info *info)
228 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
229 int err;
231 if (!info2->cmap_adr)
232 return -ENOSYS;
234 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
235 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
236 if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
237 return err;
239 if (con == currcon) /* current console? */
240 return fb_set_cmap(cmap, kspc, offb_setcolreg, info);
241 else
242 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
243 return 0;
248 * Initialisation
251 int __init offb_init(void)
253 struct device_node *dp;
254 unsigned int dpy;
255 struct device_node *displays = find_type_devices("display");
256 struct device_node *macos_display = NULL;
258 /* If we're booted from BootX... */
259 if (prom_num_displays == 0 && boot_infos != 0) {
260 unsigned long addr = (unsigned long) boot_infos->dispDeviceBase;
261 /* find the device node corresponding to the macos display */
262 for (dp = displays; dp != NULL; dp = dp->next) {
263 int i;
265 * Grrr... It looks like the MacOS ATI driver
266 * munges the assigned-addresses property (but
267 * the AAPL,address value is OK).
269 if (strncmp(dp->name, "ATY,", 4) == 0 && dp->n_addrs == 1) {
270 unsigned int *ap = (unsigned int *)
271 get_property(dp, "AAPL,address", NULL);
272 if (ap != NULL) {
273 dp->addrs[0].address = *ap;
274 dp->addrs[0].size = 0x01000000;
279 * The LTPro on the Lombard powerbook has no addresses
280 * on the display nodes, they are on their parent.
282 if (dp->n_addrs == 0 && device_is_compatible(dp, "ATY,264LTPro")) {
283 int na;
284 unsigned int *ap = (unsigned int *)
285 get_property(dp, "AAPL,address", &na);
286 if (ap != 0)
287 for (na /= sizeof(unsigned int); na > 0; --na, ++ap)
288 if (*ap <= addr && addr < *ap + 0x1000000)
289 goto foundit;
293 * See if the display address is in one of the address
294 * ranges for this display.
296 for (i = 0; i < dp->n_addrs; ++i) {
297 if (dp->addrs[i].address <= addr
298 && addr < dp->addrs[i].address + dp->addrs[i].size)
299 break;
301 if (i < dp->n_addrs) {
302 foundit:
303 printk(KERN_INFO "MacOS display is %s\n", dp->full_name);
304 macos_display = dp;
305 break;
309 /* initialize it */
310 offb_init_fb(macos_display? macos_display->name: "MacOS display",
311 macos_display? macos_display->full_name: "MacOS display",
312 boot_infos->dispDeviceRect[2],
313 boot_infos->dispDeviceRect[3],
314 boot_infos->dispDeviceDepth,
315 boot_infos->dispDeviceRowBytes, addr, NULL);
318 for (dpy = 0; dpy < prom_num_displays; dpy++) {
319 if ((dp = find_path_device(prom_display_paths[dpy])))
320 offb_init_nodriver(dp);
322 return 0;
326 static void __init offb_init_nodriver(struct device_node *dp)
328 int *pp, i;
329 unsigned int len;
330 int width = 640, height = 480, depth = 8, pitch;
331 unsigned *up, address;
333 if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
334 && len == sizeof(int))
335 depth = *pp;
336 if ((pp = (int *)get_property(dp, "width", &len)) != NULL
337 && len == sizeof(int))
338 width = *pp;
339 if ((pp = (int *)get_property(dp, "height", &len)) != NULL
340 && len == sizeof(int))
341 height = *pp;
342 if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
343 && len == sizeof(int)) {
344 pitch = *pp;
345 if (pitch == 1)
346 pitch = 0x1000;
347 } else
348 pitch = width;
349 if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
350 && len == sizeof(unsigned))
351 address = (u_long)*up;
352 else {
353 for (i = 0; i < dp->n_addrs; ++i)
354 if (dp->addrs[i].size >= pitch*height*depth/8)
355 break;
356 if (i >= dp->n_addrs) {
357 printk(KERN_ERR "no framebuffer address found for %s\n", dp->full_name);
358 return;
361 address = (u_long)dp->addrs[i].address;
363 /* kludge for valkyrie */
364 if (strcmp(dp->name, "valkyrie") == 0)
365 address += 0x1000;
367 offb_init_fb(dp->name, dp->full_name, width, height, depth,
368 pitch, address, dp);
372 static void __init offb_init_fb(const char *name, const char *full_name,
373 int width, int height, int depth,
374 int pitch, unsigned long address,
375 struct device_node *dp)
377 int i;
378 struct fb_fix_screeninfo *fix;
379 struct fb_var_screeninfo *var;
380 struct display *disp;
381 struct fb_info_offb *info;
382 unsigned long res_start = address;
383 unsigned long res_size = pitch*height*depth/8;
385 if (!request_mem_region(res_start, res_size, "offb"))
386 return;
388 printk(KERN_INFO "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
389 width, height, name, address, depth, pitch);
390 if (depth != 8 && depth != 16 && depth != 32) {
391 printk(KERN_ERR "%s: can't use depth = %d\n", full_name, depth);
392 release_mem_region(res_start, res_size);
393 return;
396 info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
397 if (info == 0) {
398 release_mem_region(res_start, res_size);
399 return;
401 memset(info, 0, sizeof(*info));
403 fix = &info->fix;
404 var = &info->var;
405 disp = &info->disp;
407 strcpy(fix->id, "OFfb ");
408 strncat(fix->id, name, sizeof(fix->id));
409 fix->id[sizeof(fix->id)-1] = '\0';
411 var->xres = var->xres_virtual = width;
412 var->yres = var->yres_virtual = height;
413 fix->line_length = pitch;
415 fix->smem_start = address;
416 fix->smem_len = pitch * height;
417 fix->type = FB_TYPE_PACKED_PIXELS;
418 fix->type_aux = 0;
420 info->cmap_type = cmap_unknown;
421 if (depth == 8)
423 /* XXX kludge for ati */
424 if (dp && !strncmp(name, "ATY,Rage128", 11)) {
425 unsigned long regbase = dp->addrs[2].address;
426 info->cmap_adr = ioremap(regbase, 0x1FFF);
427 info->cmap_type = cmap_r128;
428 } else if (dp && !strncmp(name, "ATY,RageM3pA", 12)) {
429 unsigned long regbase = dp->parent->addrs[2].address;
430 info->cmap_adr = ioremap(regbase, 0x1FFF);
431 info->cmap_type = cmap_M3A;
432 } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
433 unsigned long regbase = dp->parent->addrs[2].address;
434 info->cmap_adr = ioremap(regbase, 0x1FFF);
435 info->cmap_type = cmap_M3B;
436 } else if (!strncmp(name, "ATY,", 4)) {
437 unsigned long base = address & 0xff000000UL;
438 info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
439 info->cmap_data = info->cmap_adr + 1;
440 info->cmap_type = cmap_m64;
442 fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
443 : FB_VISUAL_STATIC_PSEUDOCOLOR;
445 else
446 fix->visual = /*info->cmap_adr ? FB_VISUAL_DIRECTCOLOR
447 : */FB_VISUAL_TRUECOLOR;
449 var->xoffset = var->yoffset = 0;
450 var->bits_per_pixel = depth;
451 switch (depth) {
452 case 8:
453 var->bits_per_pixel = 8;
454 var->red.offset = 0;
455 var->red.length = 8;
456 var->green.offset = 0;
457 var->green.length = 8;
458 var->blue.offset = 0;
459 var->blue.length = 8;
460 var->transp.offset = 0;
461 var->transp.length = 0;
462 break;
463 case 16: /* RGB 555 */
464 var->bits_per_pixel = 16;
465 var->red.offset = 10;
466 var->red.length = 5;
467 var->green.offset = 5;
468 var->green.length = 5;
469 var->blue.offset = 0;
470 var->blue.length = 5;
471 var->transp.offset = 0;
472 var->transp.length = 0;
473 break;
474 case 32: /* RGB 888 */
475 var->bits_per_pixel = 32;
476 var->red.offset = 16;
477 var->red.length = 8;
478 var->green.offset = 8;
479 var->green.length = 8;
480 var->blue.offset = 0;
481 var->blue.length = 8;
482 var->transp.offset = 24;
483 var->transp.length = 8;
484 break;
486 var->red.msb_right = var->green.msb_right = var->blue.msb_right = var->transp.msb_right = 0;
487 var->grayscale = 0;
488 var->nonstd = 0;
489 var->activate = 0;
490 var->height = var->width = -1;
491 var->pixclock = 10000;
492 var->left_margin = var->right_margin = 16;
493 var->upper_margin = var->lower_margin = 16;
494 var->hsync_len = var->vsync_len = 8;
495 var->sync = 0;
496 var->vmode = FB_VMODE_NONINTERLACED;
498 disp->var = *var;
499 disp->cmap.start = 0;
500 disp->cmap.len = 0;
501 disp->cmap.red = NULL;
502 disp->cmap.green = NULL;
503 disp->cmap.blue = NULL;
504 disp->cmap.transp = NULL;
505 disp->screen_base = ioremap(address, fix->smem_len);
506 disp->visual = fix->visual;
507 disp->type = fix->type;
508 disp->type_aux = fix->type_aux;
509 disp->ypanstep = 0;
510 disp->ywrapstep = 0;
511 disp->line_length = fix->line_length;
512 disp->can_soft_blank = info->cmap_adr ? 1 : 0;
513 disp->inverse = 0;
514 switch (depth) {
515 #ifdef FBCON_HAS_CFB8
516 case 8:
517 disp->dispsw = &fbcon_cfb8;
518 break;
519 #endif
520 #ifdef FBCON_HAS_CFB16
521 case 16:
522 disp->dispsw = &fbcon_cfb16;
523 disp->dispsw_data = info->fbcon_cmap.cfb16;
524 for (i = 0; i < 16; i++)
525 if (fix->visual == FB_VISUAL_TRUECOLOR)
526 info->fbcon_cmap.cfb16[i] =
527 (((default_blu[i] >> 3) & 0x1f) << 10) |
528 (((default_grn[i] >> 3) & 0x1f) << 5) |
529 ((default_red[i] >> 3) & 0x1f);
530 else
531 info->fbcon_cmap.cfb16[i] =
532 (i << 10) | (i << 5) | i;
533 break;
534 #endif
535 #ifdef FBCON_HAS_CFB32
536 case 32:
537 disp->dispsw = &fbcon_cfb32;
538 disp->dispsw_data = info->fbcon_cmap.cfb32;
539 for (i = 0; i < 16; i++)
540 if (fix->visual == FB_VISUAL_TRUECOLOR)
541 info->fbcon_cmap.cfb32[i] =
542 (default_blu[i] << 16) |
543 (default_grn[i] << 8) |
544 default_red[i];
545 else
546 info->fbcon_cmap.cfb32[i] =
547 (i << 16) | (i << 8) | i;
548 break;
549 #endif
550 default:
551 disp->dispsw = &fbcon_dummy;
554 disp->scrollmode = SCROLL_YREDRAW;
556 strcpy(info->info.modename, "OFfb ");
557 strncat(info->info.modename, full_name, sizeof(info->info.modename));
558 info->info.node = -1;
559 info->info.fbops = &offb_ops;
560 info->info.disp = disp;
561 info->info.fontname[0] = '\0';
562 info->info.changevar = NULL;
563 info->info.switch_con = &offbcon_switch;
564 info->info.updatevar = &offbcon_updatevar;
565 info->info.blank = &offbcon_blank;
566 info->info.flags = FBINFO_FLAG_DEFAULT;
568 for (i = 0; i < 16; i++) {
569 int j = color_table[i];
570 info->palette[i].red = default_red[j];
571 info->palette[i].green = default_grn[j];
572 info->palette[i].blue = default_blu[j];
574 offb_set_var(var, -1, &info->info);
576 if (register_framebuffer(&info->info) < 0) {
577 kfree(info);
578 release_mem_region(res_start, res_size);
579 return;
582 printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n",
583 GET_FB_IDX(info->info.node), full_name);
585 #ifdef CONFIG_FB_COMPAT_XPMAC
586 if (!console_fb_info) {
587 display_info.height = var->yres;
588 display_info.width = var->xres;
589 display_info.depth = depth;
590 display_info.pitch = fix->line_length;
591 display_info.mode = 0;
592 strncpy(display_info.name, name, sizeof(display_info.name));
593 display_info.fb_address = address;
594 display_info.cmap_adr_address = 0;
595 display_info.cmap_data_address = 0;
596 display_info.disp_reg_address = 0;
597 /* XXX kludge for ati */
598 if (info->cmap_type == cmap_m64) {
599 unsigned long base = address & 0xff000000UL;
600 display_info.disp_reg_address = base + 0x7ffc00;
601 display_info.cmap_adr_address = base + 0x7ffcc0;
602 display_info.cmap_data_address = base + 0x7ffcc1;
604 console_fb_info = &info->info;
606 #endif /* CONFIG_FB_COMPAT_XPMAC) */
610 static int offbcon_switch(int con, struct fb_info *info)
612 /* Do we have to save the colormap? */
613 if (fb_display[currcon].cmap.len)
614 fb_get_cmap(&fb_display[currcon].cmap, 1, offb_getcolreg, info);
616 currcon = con;
617 /* Install new colormap */
618 do_install_cmap(con, info);
619 return 0;
623 * Update the `var' structure (called by fbcon.c)
626 static int offbcon_updatevar(int con, struct fb_info *info)
628 /* Nothing */
629 return 0;
633 * Blank the display.
636 static void offbcon_blank(int blank, struct fb_info *info)
638 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
639 int i, j;
641 if (!info2->cmap_adr)
642 return;
644 if (blank)
645 for (i = 0; i < 256; i++) {
646 switch(info2->cmap_type) {
647 case cmap_m64:
648 *info2->cmap_adr = i;
649 mach_eieio();
650 for (j = 0; j < 3; j++) {
651 *info2->cmap_data = 0;
652 mach_eieio();
654 break;
655 case cmap_M3A:
656 /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
657 out_le32((unsigned *)(info2->cmap_adr + 0x58),
658 in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20);
659 case cmap_r128:
660 /* Set palette index & data */
661 out_8(info2->cmap_adr + 0xb0, i);
662 out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
663 break;
664 case cmap_M3B:
665 /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
666 out_le32((unsigned *)(info2->cmap_adr + 0x58),
667 in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20);
668 /* Set palette index & data */
669 out_8(info2->cmap_adr + 0xb0, i);
670 out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
671 break;
674 else
675 do_install_cmap(currcon, info);
679 * Read a single color register and split it into
680 * colors/transparent. Return != 0 for invalid regno.
683 static int offb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
684 u_int *transp, struct fb_info *info)
686 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
688 if (!info2->cmap_adr || regno > 255)
689 return 1;
691 *red = (info2->palette[regno].red<<8) | info2->palette[regno].red;
692 *green = (info2->palette[regno].green<<8) | info2->palette[regno].green;
693 *blue = (info2->palette[regno].blue<<8) | info2->palette[regno].blue;
694 *transp = 0;
695 return 0;
700 * Set a single color register. The values supplied are already
701 * rounded down to the hardware's capabilities (according to the
702 * entries in the var structure). Return != 0 for invalid regno.
705 static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
706 u_int transp, struct fb_info *info)
708 struct fb_info_offb *info2 = (struct fb_info_offb *)info;
710 if (!info2->cmap_adr || regno > 255)
711 return 1;
713 red >>= 8;
714 green >>= 8;
715 blue >>= 8;
717 info2->palette[regno].red = red;
718 info2->palette[regno].green = green;
719 info2->palette[regno].blue = blue;
721 switch(info2->cmap_type) {
722 case cmap_m64:
723 *info2->cmap_adr = regno;
724 mach_eieio();
725 *info2->cmap_data = red;
726 mach_eieio();
727 *info2->cmap_data = green;
728 mach_eieio();
729 *info2->cmap_data = blue;
730 mach_eieio();
731 break;
732 case cmap_M3A:
733 /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
734 out_le32((unsigned *)(info2->cmap_adr + 0x58),
735 in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20);
736 case cmap_r128:
737 /* Set palette index & data */
738 out_8(info2->cmap_adr + 0xb0, regno);
739 out_le32((unsigned *)(info2->cmap_adr + 0xb4),
740 (red << 16 | green << 8 | blue));
741 break;
742 case cmap_M3B:
743 /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
744 out_le32((unsigned *)(info2->cmap_adr + 0x58),
745 in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20);
746 /* Set palette index & data */
747 out_8(info2->cmap_adr + 0xb0, regno);
748 out_le32((unsigned *)(info2->cmap_adr + 0xb4),
749 (red << 16 | green << 8 | blue));
750 break;
753 if (regno < 16)
754 switch (info2->var.bits_per_pixel) {
755 #ifdef FBCON_HAS_CFB16
756 case 16:
757 info2->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
758 break;
759 #endif
760 #ifdef FBCON_HAS_CFB32
761 case 32:
763 int i = (regno << 8) | regno;
764 info2->fbcon_cmap.cfb32[regno] = (i << 16) | i;
765 break;
767 #endif
770 return 0;
774 static void do_install_cmap(int con, struct fb_info *info)
776 if (con != currcon)
777 return;
778 if (fb_display[con].cmap.len)
779 fb_set_cmap(&fb_display[con].cmap, 1, offb_setcolreg, info);
780 else
782 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
783 fb_set_cmap(fb_default_cmap(size), 1, offb_setcolreg, info);