/*
 * pmac-cons.c: Console support for PowerMac (PCI-based).
 *
 * Copyright (C) 1996 Paul Mackerras.
 * 7200/Platinum code hacked by Mark Abene.
 * 16 color/gray hack (supports PowerBook 5300) by Michael Santos
 */
#include <linux/config.h>

#ifdef	CONFIG_OSFMACH3
#include <mach/mach_interface.h>
#include <ppc/video_console.h>

#include <osfmach3/mach_init.h>
#include <osfmach3/console.h>
#include <osfmach3/device_utils.h>
#include <osfmach3/mach3_debug.h>
#include <osfmach3/assert.h>
#endif	/* CONFIG_OSFMACH3 */

#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/vc_ioctl.h>
#ifdef	CONFIG_OSFMACH3
#include <linux/malloc.h>
#endif	/* CONFIG_OSFMACH3 */
#include <asm/processor.h>
#ifndef	CONFIG_OSFMACH3
#include <asm/prom.h>
#endif	/* CONFIG_OSFMACH3 */
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/segment.h>
#ifndef	CONFIG_OSFMACH3
#include <asm/cuda.h>
#endif	/* CONFIG_OSFMACH3 */
#include "selection.h"
#include "console_struct.h"
#include "vt_kern.h"

#ifdef	CONFIG_OSFMACH3
extern void register_console(void (*proc)(const char *));
extern void osfmach3_console_feed_init(void);
int pmac_optimize_scr_writew = 1;
#else	/* CONFIG_OSFMACH3 */
extern int serial_console;	/* set to use serial port as console */
#endif	/* CONFIG_OSFMACH3 */

/*
 * Video mode values.
 * These are supposed to be the same as the values that
 * Apple uses in MacOS.
 */
#define VMODE_NVRAM		0	/* use value stored in nvram */
#define VMODE_512_384_60I	1	/* 512x384, 60Hz interlaced (NTSC) */
#define VMODE_512_384_60	2	/* 512x384, 60Hz */
#define VMODE_640_480_50I	3	/* 640x480, 50Hz interlaced (PAL) */
#define VMODE_640_480_60I	4	/* 640x480, 60Hz interlaced (NTSC) */
#define VMODE_640_480_60	5	/* 640x480, 60Hz (VGA) */
#define VMODE_640_480_67	6	/* 640x480, 67Hz */
#define VMODE_640_870_75P	7	/* 640x870, 75Hz (portrait) */
#define VMODE_768_576_50I	8	/* 768x576, 50Hz (PAL full frame) */
#define VMODE_800_600_56	9	/* 800x600, 56Hz */
#define VMODE_800_600_60	10	/* 800x600, 60Hz */
#define VMODE_800_600_72	11	/* 800x600, 72Hz */
#define VMODE_800_600_75	12	/* 800x600, 75Hz */
#define VMODE_832_624_75	13	/* 832x624, 75Hz */
#define VMODE_1024_768_60	14	/* 1024x768, 60Hz */
#define VMODE_1024_768_70	15	/* 1024x768, 70Hz (or 72Hz?) */
#define VMODE_1024_768_75V	16	/* 1024x768, 75Hz (VESA) */
#define VMODE_1024_768_75	17	/* 1024x768, 75Hz */
#define VMODE_1152_870_75	18	/* 1152x870, 75Hz */
#define VMODE_1280_960_75	19	/* 1280x960, 75Hz */
#define VMODE_1280_1024_75	20	/* 1280x1024, 75Hz */
#define VMODE_1600_1200_75	21	/* 1600x1200, 75Hz */
#define VMODE_MAX		21
#define VMODE_CHOOSE		99	/* choose based on monitor sense */

/*
 * Color mode values, used to select number of bits/pixel.
 */
#define CMODE_NVRAM		-1	/* use value stored in nvram */
#define CMODE_8			0	/* 8 bits/pixel */
#define CMODE_16		1	/* 16 (actually 15) bits/pixel */
#define CMODE_32		2	/* 32 (actually 24) bits/pixel */
/* This value will need to be changed when linux-pmac supports it.  For
 * now we just set it to what was the default before, 0, so we don't break
 * linux-pmac.
 */
#define CMODE_4                 0       /* only used as index into tables */

#define CMODE_BITS_NVRAM       -1
#define CMODE_BITS_4           4
#define CMODE_BITS_8           8
#define CMODE_BITS_16          16
#define CMODE_BITS_32          32

int video_mode = VMODE_NVRAM;
int color_mode = CMODE_NVRAM;
int color_mode_bits = CMODE_BITS_NVRAM;

/*
 * Addresses in NVRAM where video mode and pixel size are stored.
 */
#define NV_VMODE	0x140f
#define NV_CMODE	0x1410

/*
 * The format of "screen_info" is strange, and due to early
 * i386-setup code. This is just enough to make the console
 * code think we're on a EGA+ colour display.
 */
struct screen_info screen_info = {
	0, 0,			/* orig-x, orig-y */
	{0, 0},			/* unused1 */
	0,			/* orig-video-page */
	0,			/* orig-video-mode */
	80,			/* orig-video-cols */
	0,			/* unused [short] */
	0,			/* ega_bx */
	0,			/* unused [short] */
	25,			/* orig-video-lines */
	0,			/* isVGA */
	16			/* video points */
};

/*
 * We allocate enough character+attribute memory for the largest
 * screen resolution supported.
 */
#define MAX_TEXT_COLS	(1600/8)
#define MAX_TEXT_ROWS	(1200/16)

#ifndef	CONFIG_OSFMACH3
/*
 * We get a sense value from the monitor and use it to choose
 * what resolution to use.  This structure maps sense values
 * to display mode values (which determine the resolution and
 * frequencies).
 */
struct mon_map {
	int	sense;
	int	vmode;
} monitor_map [] = {
	{0x000, VMODE_1280_1024_75},	/* 21" RGB */
	{0x114, VMODE_640_870_75P},	/* Portrait Monochrome */
	{0x221, VMODE_512_384_60},	/* 12" RGB*/
	{0x331, VMODE_1280_1024_75},	/* 21" RGB (Radius) */
	{0x334, VMODE_1280_1024_75},	/* 21" mono (Radius) */
	{0x335, VMODE_1280_1024_75},	/* 21" mono */
	{0x40A, VMODE_640_480_60I},	/* NTSC */
	{0x51E, VMODE_640_870_75P},	/* Portrait RGB */
	{0x603, VMODE_832_624_75},	/* 12"-16" multiscan */
	{0x60b, VMODE_1024_768_70},	/* 13"-19" multiscan */
	{0x623, VMODE_1152_870_75},	/* 13"-21" multiscan */
	{0x62b, VMODE_640_480_67},	/* 13"/14" RGB */
	{0x700, VMODE_640_480_50I},	/* PAL */
	{0x714, VMODE_640_480_60I},	/* NTSC */
	{0x717, VMODE_800_600_75},	/* VGA */
	{0x72d, VMODE_832_624_75},	/* 16" RGB (Goldfish) */
	{0x730, VMODE_768_576_50I},	/* PAL (Alternate) */
	{0x73a, VMODE_1152_870_75},	/* 3rd party 19" */
	{-1,	VMODE_640_480_60},	/* catch-all, must be last */
};

static int
map_monitor_sense(int sense)
{
	struct mon_map *map;

	for (map = monitor_map; map->sense >= 0; ++map)
		if (map->sense == sense)
			break;
	return map->vmode;
}
#endif	/* CONFIG_OSFMACH3 */

/*
 * Horizontal and vertical resolution for each mode.
 */
struct vmode_attr {
	int	hres;
	int	vres;
	int	vfreq;
	int	interlaced;
} vmode_attrs[VMODE_MAX] = {
	{512, 384, 60, 1},
	{512, 384, 60},
	{640, 480, 50, 1},
	{640, 480, 60, 1},
	{640, 480, 60},
	{640, 480, 67},
	{640, 870, 75},
	{768, 576, 50, 1},
	{800, 600, 56},
	{800, 600, 60},
	{800, 600, 72},
	{800, 600, 75},
	{832, 624, 75},
	{1024, 768, 60},
	{1024, 768, 72},
	{1024, 768, 75},
	{1024, 768, 75},
	{1152, 870, 75},
	{1280, 960, 75},
	{1280, 1024, 75},
	{1600, 1200, 75}
};

/*
 * Structure of the registers for the RADACAL colormap device.
 */
struct cmap_regs {
	unsigned char addr;
	char pad1[15];
	unsigned char d1;
	char pad2[15];
	unsigned char d2;
	char pad3[15];
	unsigned char lut;
	char pad4[15];
};

void set_palette(void);
void pmac_find_display(void);
#ifdef	CONFIG_OSFMACH3
static void osfmach3_vc_map(void);
static void osfmach3_vc_init(void);
static int osfmach3_vc_setmode(struct vc_mode *mode, int doit);
#else	/* CONFIG_OSFMACH3 */
static void map_control_display(struct device_node *);
static void control_init(void);
static int control_setmode(struct vc_mode *mode, int doit);
static void set_control_clock(unsigned char *params);
static int read_control_sense(void);
static int control_vram_reqd(int vmode, int cmode);
static void map_platinum(struct device_node *);
static void platinum_init(void);
static void set_platinum_clock(unsigned char *clksel);
static int platinum_setmode(struct vc_mode *mode, int doit);
static int read_platinum_sense(void);
static int platinum_vram_reqd(int vmode, int cmode);
#endif	/* CONFIG_OSFMACH3 */
static void invert_cursor(int);

struct display_interface {
	char *name;
#ifdef	CONFIG_OSFMACH3
	void (*map_interface)(void);
#else	/* CONFIG_OSFMACH3 */
	void (*map_interface)(struct device_node *);
#endif	/* CONFIG_OSFMACH3 */
	void (*init_interface)(void);
	int  (*setmode)(struct vc_mode *, int);
} 
#ifdef	CONFIG_OSFMACH3
osfmach3_display =
	{ "vc0", osfmach3_vc_map, osfmach3_vc_init, osfmach3_vc_setmode };
#else	/* CONFIG_OSFMACH3 */
displays[] = {
	{ "control", map_control_display, control_init, control_setmode },
	{ "platinum", map_platinum, platinum_init, platinum_setmode },
	{ NULL }
};
#endif	/* CONFIG_OSFMACH3 */

void vesa_blank(void);
void vesa_unblank(void);
void set_vesa_blanking(const unsigned long);
void vesa_powerdown(void);
void hide_cursor(void);

struct display_interface *current_display;
unsigned char *frame_buffer;
unsigned char *base_frame_buffer;
struct cmap_regs *cmap_regs;

static int cursor_pos = -1;
static unsigned *cursor_fb;	/* address of cursor pos in frame buffer */
static unsigned cursor_bits;	/* bits changed to turn cursor on */

static int pixel_size;		/* in bytes */
static int pixel_size_bits;     /* in bits */
static int n_scanlines;		/* # of scan lines */
static int line_pitch;		/* # bytes in 1 scan line */
static int row_pitch;		/* # bytes in 1 row of characters */
static unsigned char *fb_start;	/* addr of top left pixel of top left char */
static int total_vram;		/* total amount of video memory, bytes */

static struct vc_mode display_info;

#define cmapsz	(16*256)
extern unsigned char vga_font[cmapsz];

extern unsigned long expand_bits_4[];

static int plat_alt_clock;

static inline unsigned pixel32(int currcons, int cidx)
{
  /*	cidx *= 3;*/
	cidx = 3*color_table[cidx];
	return (palette[cidx] << 16) | (palette[cidx + 1] << 8)
		| palette[cidx + 2];
}

static inline unsigned pixel16(int currcons, int cidx)
{
	unsigned p;

	p = ((cidx << 10) & 0x7c00) + ((cidx << 5) & 0x03e0)
		+ (cidx & 0x1f);
	return (p << 16) | p;
}

void
__set_origin(unsigned short offset)
{
}

static void
invert_cursor(int cpos)
{
	int row, col;
	int l, c, nw;
	unsigned *fb, mask;
	int currcons = fg_console;	/* for `color', which is a macro */

	if (cpos == -1) {
		/* turning cursor off */
		fb = cursor_fb;
		mask = cursor_bits;
	} else {
		row = cpos / video_num_columns;
		col = cpos - row * video_num_columns;
		fb = (unsigned *) (fb_start + row * row_pitch
		       + col * pixel_size_bits);
    switch (color_mode_bits) {
    case CMODE_BITS_16:
			mask = pixel16(currcons, foreground)
				^ pixel16(currcons, background >> 4);
			break;
    case CMODE_BITS_4:
      mask = (color ^ (color >> 4)) & 0xf;
      mask |= mask << 4;
      mask |= mask << 8;
      mask |= mask << 16;
      break;
		default:
			mask = (color ^ (color >> 4)) & 0xf;
			mask |= mask << 8;
			mask |= mask << 16;
			break;
		}
		cursor_fb = fb;
		cursor_bits = mask;
	}
  /* numwords = pixel_size_bits * 8 bits/char / 32 bits/word */
  nw = pixel_size_bits / 4;
	for (l = 0; l < 16; ++l) {
		for (c = 0; c < nw; ++c)
			fb[c] ^= mask;
		fb = (unsigned *) ((char *)fb + line_pitch);
	}
}

void
hide_cursor()
{
	unsigned long flags;

	save_flags(flags);
	cli();
	if (cursor_pos != -1) {
		invert_cursor(-1);
		cursor_pos = -1;
	}
	restore_flags(flags);
}

void
set_cursor(int currcons)
{
	unsigned long flags;
	int old_cursor;

	if (currcons != fg_console || console_blanked)
		return;

	save_flags(flags);
	cli();
	if (!deccm) {
		hide_cursor();
	} else {
		old_cursor = cursor_pos;
		cursor_pos = (pos - video_mem_base) >> 1;
		if (old_cursor != -1)
			invert_cursor(-1);
		invert_cursor(cursor_pos);
	}
	restore_flags(flags);
}

/*
 * NOTE: get_scrmem() and set_scrmem() are here only because
 * the VGA version of set_scrmem() has some direct VGA references.
 */
void
get_scrmem(int currcons)
{
	memcpyw((unsigned short *)vc_scrbuf[currcons],
		(unsigned short *)origin, video_screen_size);
	origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
	scr_end = video_mem_end = video_mem_start + video_screen_size;
	pos = origin + y*video_size_row + (x<<1);
}

void
set_scrmem(int currcons, long offset)
{
	if (video_mem_term - video_mem_base < offset + video_screen_size)
		offset = 0;
	memcpyw((unsigned short *)(video_mem_base + offset),
		(unsigned short *) origin, video_screen_size);
	video_mem_start = video_mem_base;
	video_mem_end = video_mem_term;
	origin = video_mem_base + offset;
	scr_end = origin + video_screen_size;
	pos = origin + y*video_size_row + (x<<1);
}

int
set_get_cmap(unsigned char *p, int set)
{
	int i, j, err;

	err = verify_area(set? VERIFY_READ: VERIFY_WRITE, p, 48);
	if (err)
		return err;

	for (i = 0; i < 16; ++i) {
		if (set) {
			default_red[i] = get_user(p++);
			default_grn[i] = get_user(p++);
			default_blu[i] = get_user(p++);
		} else {
			put_user(default_red[i], p++);
			put_user(default_grn[i], p++);
			put_user(default_blu[i], p++);
		}
	}

	if (set) {
		for (j = 0; j < MAX_NR_CONSOLES; ++j) {
			if (!vc_cons_allocated(j))
				continue;
			for (i = 0; i < 16; ++i) {
				vc_cons[j].d->vc_palette[3*i+0] = default_red[i];
				vc_cons[j].d->vc_palette[3*i+1] = default_grn[i];
				vc_cons[j].d->vc_palette[3*i+2] = default_blu[i];
			}
		}
		set_palette();
	}

	return 0;
}

int
set_get_font(char *p, int set, int ch512)
{
	return 0;
}

void
set_palette()
{
	int i;

#ifdef	CONFIG_OSFMACH3
	kern_return_t	kr;
	struct vc_color	vcc[16];

	for (i = 0; i < 16; ++i) {
		vcc[i].vp_index = i;
		vcc[i].vp_red = default_red[i];
		vcc[i].vp_green = default_grn[i];
		vcc[i].vp_blue = default_blu[i];
	}
	kr = device_set_status(osfmach3_video_port,
			       VC_SETCOLOR,
			       (dev_status_t) vcc,
			       sizeof (vcc) / sizeof (int));
	if (kr != D_SUCCESS) {
		MACH3_DEBUG(1, kr,
			    ("set_palette: device_set_status(0x%x)",
			     osfmach3_video_port));
	}
#else	/* CONFIG_OSFMACH3 */
	cmap_regs->addr = 0;
	for (i = 0; i < 16; ++i) {
		cmap_regs->lut = default_red[i];
		cmap_regs->lut = default_grn[i];
		cmap_regs->lut = default_blu[i];
	}
#endif	/* CONFIG_OSFMACH3 */
}

void
vesa_blank()
{
}

void
vesa_unblank()
{
}

void
set_vesa_blanking(const unsigned long arg)
{
}

void
vesa_powerdown()
{
}

void
memsetw(unsigned short *p, unsigned short c, unsigned count)
{
	count /= 2;
	if ((unsigned long)(p + count) > video_mem_base
	    && (unsigned long)p < video_mem_term) {
		for (; p < (unsigned short *) video_mem_base && count != 0; --count)
			*p++ = c;
		for (; p < (unsigned short *) video_mem_term && count != 0; --count) {
			if (*p != c) {
				*p = c;
				pmac_blitc(c, (unsigned long)p);
			}
			++p;
		}
	}
	for (; count != 0; --count)
		*p++ = c;
}

void
memcpyw(unsigned short *to, unsigned short *from, unsigned count)
{
	unsigned short c;

	count /= 2;
	if ((unsigned long)(to + count) > video_mem_base
	    && (unsigned long)to < video_mem_term) {
		for (; to < (unsigned short *) video_mem_base && count != 0; --count)
			*to++ = *from++;
		for (; to < (unsigned short *) video_mem_term && count != 0; --count) {
			c = *from++;
			if (*to != c) {
				*to = c;
				pmac_blitc(c, (unsigned long)to);
			}
			++to;
		}
	}
	for (; count != 0; --count)
		*to++ = *from++;
}

void
pmac_find_display()
{
#ifndef	CONFIG_OSFMACH3
	struct display_interface *disp;
	struct device_node *dp;
#endif	/* CONFIG_OSFMACH3 */
	struct vmode_attr *ap;

	current_display = NULL;
#ifdef	CONFIG_OSFMACH3
	if (osfmach3_video_port != MACH_PORT_NULL) {
		current_display = &osfmach3_display;
		current_display->map_interface();
	}
#else	/* CONFIG_OSFMACH3 */
	if (serial_console) 
		return;
	for (disp = displays; disp->name != NULL; ++disp) {
		dp = find_devices(disp->name);
		if (dp == 0)
			continue;
		current_display = disp;
		disp->map_interface(dp);
		break;
	}
#endif	/* CONFIG_OSFMACH3 */
	if (current_display == NULL
	    || video_mode <= 0 || video_mode > VMODE_MAX) {
#ifndef	CONFIG_OSFMACH3
		serial_console = 1;	/* no screen - fall back to serial */
#endif	/* CONFIG_OSFMACH3 */
		return;
	}
	ap = &vmode_attrs[video_mode - 1];
	screen_info.orig_video_cols = ap->hres / 8;
	screen_info.orig_video_lines = ap->vres / 16;
	printk("using video mode %d (%dx%d at %dHz%s), %d bits/pixel\n",
	       video_mode, ap->hres, ap->vres, ap->vfreq,
	       ap->interlaced? " interlaced": "",
	 color_mode_bits);
}

int
console_getmode(struct vc_mode *mode)
{
	*mode = display_info;
	return 0;
}

int
console_setmode(struct vc_mode *mode, int doit)
{
	int err;

	if (current_display == NULL || current_display->setmode == NULL)
		return -EINVAL;
	err = (*current_display->setmode)(mode, doit);
	if (doit && err == 0)
		memset((void *)video_mem_base, 0, video_screen_size);
	return err;
}

#ifdef	CONFIG_OSFMACH3
int
console_set_get_cmap(void *arg, int doset)
{
	int err;
	unsigned long *sizep, size, num_colors, i;
	unsigned char *user_cmap, *cmap, *p;
	struct vc_color *vcc;
	kern_return_t kr;

	err = verify_area(VERIFY_READ, arg, sizeof (sizep));
	if (err)
		return err;
	sizep = (unsigned long *) arg;
	size = get_user(sizep);
	num_colors = size / 3;	/* 3 bytes per color (RGB) */
	user_cmap = (unsigned char *)((unsigned long *) arg + 1);
	err = verify_area(doset ? VERIFY_READ : VERIFY_WRITE,
			  (void *) arg,
			  size + sizeof (size));
	if (err)
		return err;
	if (doset) {
		cmap = (unsigned char *) kmalloc(size, GFP_KERNEL);
		if (! cmap)
			return -ENOMEM;
		vcc = (struct vc_color *)
			kmalloc(num_colors * sizeof (struct vc_color),
			       GFP_KERNEL);
		if (!vcc) {
			kfree(cmap);
			return -ENOMEM;
		}
		memcpy_fromfs(cmap, user_cmap, size);
		for (i = 0, p = cmap; i < num_colors; i++) {
			vcc[i].vp_index = i;
			vcc[i].vp_red = *p++;
			vcc[i].vp_green = *p++;
			vcc[i].vp_blue = *p++;
		}
		kr = device_set_status(osfmach3_video_port,
				       VC_SETCOLOR,
				       (dev_status_t) vcc,
				       ((num_colors * sizeof (struct vc_color))
					/ sizeof (int)));
		if (kr != D_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("console_set_get_cmap: "
				     "device_set_status(0x%x)",
				     osfmach3_video_port));
		}
		kfree(cmap);
		kfree(vcc);
	}
	return 0;
}
#endif	/* CONFIG_OSFMACH3 */

#ifndef	CONFIG_OSFMACH3
void
pmac_cons_setup(char *str, int *ints)
{
	if (strcmp(str, "ttya") == 0 || strcmp(str, "modem") == 0)
		serial_console = 1;
	else if (strcmp(str, "ttyb") == 0 || strcmp(str, "printer") == 0)
		serial_console = 2;
}
#endif	/* CONFIG_OSFMACH3 */

void
pmac_vmode_setup(char *str, int *ints)
{
	if (ints[0] >= 1) {
		video_mode = ints[1];
		/* temporary kludge for platinum */
		if (video_mode >= 100) {
			plat_alt_clock = 1 - plat_alt_clock;
			video_mode -= 100;
		}
	}
	if (ints[0] >= 2)
		color_mode = ints[2];
}

unsigned long
con_type_init(unsigned long mem_start, const char **type_p)
{
	if (current_display == NULL)
		panic("no display available");
	current_display->init_interface();
	can_do_color = 1;
	video_type = VIDEO_TYPE_PMAC;
	*type_p = display_info.name;
	video_mem_base = mem_start;
	mem_start += MAX_TEXT_COLS * MAX_TEXT_ROWS * 2;
	video_mem_term = mem_start;
	memset((char *) video_mem_base, 0, video_screen_size);
	return mem_start;
}

int
con_adjust_height(unsigned long height)
{
	return -EINVAL;
}


/* We have 2 to the (32 bits/word / 4 bits/pixel) possibilites */
static unsigned long expand_bits_4[256] = {
  0x00000000, 0x0000000F, 0x000000F0, 0x000000FF, 0x00000F00, 
  0x00000F0F, 0x00000FF0, 0x00000FFF, 0x0000F000, 0x0000F00F, 
  0x0000F0F0, 0x0000F0FF, 0x0000FF00, 0x0000FF0F, 0x0000FFF0, 
  0x0000FFFF, 0x000F0000, 0x000F000F, 0x000F00F0, 0x000F00FF, 
  0x000F0F00, 0x000F0F0F, 0x000F0FF0, 0x000F0FFF, 0x000FF000, 
  0x000FF00F, 0x000FF0F0, 0x000FF0FF, 0x000FFF00, 0x000FFF0F, 
  0x000FFFF0, 0x000FFFFF, 0x00F00000, 0x00F0000F, 0x00F000F0, 
  0x00F000FF, 0x00F00F00, 0x00F00F0F, 0x00F00FF0, 0x00F00FFF, 
  0x00F0F000, 0x00F0F00F, 0x00F0F0F0, 0x00F0F0FF, 0x00F0FF00, 
  0x00F0FF0F, 0x00F0FFF0, 0x00F0FFFF, 0x00FF0000, 0x00FF000F, 
  0x00FF00F0, 0x00FF00FF, 0x00FF0F00, 0x00FF0F0F, 0x00FF0FF0, 
  0x00FF0FFF, 0x00FFF000, 0x00FFF00F, 0x00FFF0F0, 0x00FFF0FF, 
  0x00FFFF00, 0x00FFFF0F, 0x00FFFFF0, 0x00FFFFFF, 0x0F000000, 
  0x0F00000F, 0x0F0000F0, 0x0F0000FF, 0x0F000F00, 0x0F000F0F, 
  0x0F000FF0, 0x0F000FFF, 0x0F00F000, 0x0F00F00F, 0x0F00F0F0, 
  0x0F00F0FF, 0x0F00FF00, 0x0F00FF0F, 0x0F00FFF0, 0x0F00FFFF, 
  0x0F0F0000, 0x0F0F000F, 0x0F0F00F0, 0x0F0F00FF, 0x0F0F0F00, 
  0x0F0F0F0F, 0x0F0F0FF0, 0x0F0F0FFF, 0x0F0FF000, 0x0F0FF00F, 
  0x0F0FF0F0, 0x0F0FF0FF, 0x0F0FFF00, 0x0F0FFF0F, 0x0F0FFFF0, 
  0x0F0FFFFF, 0x0FF00000, 0x0FF0000F, 0x0FF000F0, 0x0FF000FF, 
  0x0FF00F00, 0x0FF00F0F, 0x0FF00FF0, 0x0FF00FFF, 0x0FF0F000, 
  0x0FF0F00F, 0x0FF0F0F0, 0x0FF0F0FF, 0x0FF0FF00, 0x0FF0FF0F, 
  0x0FF0FFF0, 0x0FF0FFFF, 0x0FFF0000, 0x0FFF000F, 0x0FFF00F0, 
  0x0FFF00FF, 0x0FFF0F00, 0x0FFF0F0F, 0x0FFF0FF0, 0x0FFF0FFF, 
  0x0FFFF000, 0x0FFFF00F, 0x0FFFF0F0, 0x0FFFF0FF, 0x0FFFFF00, 
  0x0FFFFF0F, 0x0FFFFFF0, 0x0FFFFFFF, 0xF0000000, 0xF000000F, 
  0xF00000F0, 0xF00000FF, 0xF0000F00, 0xF0000F0F, 0xF0000FF0, 
  0xF0000FFF, 0xF000F000, 0xF000F00F, 0xF000F0F0, 0xF000F0FF, 
  0xF000FF00, 0xF000FF0F, 0xF000FFF0, 0xF000FFFF, 0xF00F0000, 
  0xF00F000F, 0xF00F00F0, 0xF00F00FF, 0xF00F0F00, 0xF00F0F0F, 
  0xF00F0FF0, 0xF00F0FFF, 0xF00FF000, 0xF00FF00F, 0xF00FF0F0, 
  0xF00FF0FF, 0xF00FFF00, 0xF00FFF0F, 0xF00FFFF0, 0xF00FFFFF, 
  0xF0F00000, 0xF0F0000F, 0xF0F000F0, 0xF0F000FF, 0xF0F00F00, 
  0xF0F00F0F, 0xF0F00FF0, 0xF0F00FFF, 0xF0F0F000, 0xF0F0F00F, 
  0xF0F0F0F0, 0xF0F0F0FF, 0xF0F0FF00, 0xF0F0FF0F, 0xF0F0FFF0, 
  0xF0F0FFFF, 0xF0FF0000, 0xF0FF000F, 0xF0FF00F0, 0xF0FF00FF, 
  0xF0FF0F00, 0xF0FF0F0F, 0xF0FF0FF0, 0xF0FF0FFF, 0xF0FFF000, 
  0xF0FFF00F, 0xF0FFF0F0, 0xF0FFF0FF, 0xF0FFFF00, 0xF0FFFF0F, 
  0xF0FFFFF0, 0xF0FFFFFF, 0xFF000000, 0xFF00000F, 0xFF0000F0, 
  0xFF0000FF, 0xFF000F00, 0xFF000F0F, 0xFF000FF0, 0xFF000FFF, 
  0xFF00F000, 0xFF00F00F, 0xFF00F0F0, 0xFF00F0FF, 0xFF00FF00, 
  0xFF00FF0F, 0xFF00FFF0, 0xFF00FFFF, 0xFF0F0000, 0xFF0F000F, 
  0xFF0F00F0, 0xFF0F00FF, 0xFF0F0F00, 0xFF0F0F0F, 0xFF0F0FF0, 
  0xFF0F0FFF, 0xFF0FF000, 0xFF0FF00F, 0xFF0FF0F0, 0xFF0FF0FF, 
  0xFF0FFF00, 0xFF0FFF0F, 0xFF0FFFF0, 0xFF0FFFFF, 0xFFF00000, 
  0xFFF0000F, 0xFFF000F0, 0xFFF000FF, 0xFFF00F00, 0xFFF00F0F, 
  0xFFF00FF0, 0xFFF00FFF, 0xFFF0F000, 0xFFF0F00F, 0xFFF0F0F0, 
  0xFFF0F0FF, 0xFFF0FF00, 0xFFF0FF0F, 0xFFF0FFF0, 0xFFF0FFFF, 
  0xFFFF0000, 0xFFFF000F, 0xFFFF00F0, 0xFFFF00FF, 0xFFFF0F00, 
  0xFFFF0F0F, 0xFFFF0FF0, 0xFFFF0FFF, 0xFFFFF000, 0xFFFFF00F, 
  0xFFFFF0F0, 0xFFFFF0FF, 0xFFFFFF00, 0xFFFFFF0F, 0xFFFFFFF0, 
  0xFFFFFFFF
};

static unsigned long expand_bits_8[16] = {
	0x00000000,
	0x000000ff,
	0x0000ff00,
	0x0000ffff,
	0x00ff0000,
	0x00ff00ff,
	0x00ffff00,
	0x00ffffff,
	0xff000000,
	0xff0000ff,
	0xff00ff00,
	0xff00ffff,
	0xffff0000,
	0xffff00ff,
	0xffffff00,
	0xffffffff
};

static unsigned long expand_bits_16[4] = {
	0x00000000,
	0x0000ffff,
	0xffff0000,
	0xffffffff
};

void
pmac_blitc(unsigned charattr, unsigned long addr)
{
	int col, row, fg, bg, l, bits;
	unsigned char *fp;
	unsigned long *fb;
	static int cached_row_start, cached_row_end = -1;
	static unsigned char *cached_fb;
	static int cached_attr = -1;
	static unsigned long cached_fg, cached_bg;

	col = (addr - video_mem_base) / 2;
	if (cursor_pos == col)
		cursor_pos = -1;
	if (!(col >= cached_row_start && col < cached_row_end)) {
		row = col / video_num_columns;
		cached_row_start = row * video_num_columns;
		cached_row_end = cached_row_start + video_num_columns;
		cached_fb = fb_start + row * row_pitch;
	}
	fb = (unsigned long *)
    (cached_fb + (col - cached_row_start) * (8 * pixel_size_bits / 8));

	if ((charattr & 0xff00) != cached_attr) {
		fg = (charattr >> 8) & 0xf;
		bg = (charattr >> 12) & 0xf;
    switch (color_mode_bits) {
    case CMODE_BITS_16:
			fg = pixel16(fg_console, fg);
			bg = pixel16(fg_console, bg);
			break;
    case CMODE_BITS_4:
      fg |= fg << 4;
      fg |= fg << 8;
      fg |= fg << 16;
      bg |= bg << 4;
      bg |= bg << 8;
      bg |= bg << 16;
      break;
		default:
			fg += fg << 8;
			fg += fg << 16;
			bg += bg << 8;
			bg += bg << 16;
		}
		fg ^= bg;
		cached_fg = fg;
		cached_bg = bg;
	} else {
		fg = cached_fg;
		bg = cached_bg;
	}

	fp = &vga_font[(charattr & 0xff) * 16];
  switch (color_mode_bits) {
  case CMODE_BITS_32:
		for (l = 0; l < 16; ++l) {
			bits = *fp++;
			fb[0] = (-(bits >> 7) & fg) ^ bg;
			fb[1] = (-((bits >> 6) & 1) & fg) ^ bg;
			fb[2] = (-((bits >> 5) & 1) & fg) ^ bg;
			fb[3] = (-((bits >> 4) & 1) & fg) ^ bg;
			fb[4] = (-((bits >> 3) & 1) & fg) ^ bg;
			fb[5] = (-((bits >> 2) & 1) & fg) ^ bg;
			fb[6] = (-((bits >> 1) & 1) & fg) ^ bg;
			fb[7] = (-(bits & 1) & fg) ^ bg;
			fb = (unsigned long *) ((char *)fb + line_pitch);
		}
		break;
  case CMODE_BITS_16:
		for (l = 0; l < 16; ++l) {
			bits = *fp++;
			fb[0] = (expand_bits_16[bits >> 6] & fg) ^ bg;
			fb[1] = (expand_bits_16[(bits >> 4) & 3] & fg) ^ bg;
			fb[2] = (expand_bits_16[(bits >> 2) & 3] & fg) ^ bg;
			fb[3] = (expand_bits_16[bits & 3] & fg) ^ bg;
			fb = (unsigned long *) ((char *)fb + line_pitch);
		}
		break;
  case CMODE_BITS_4:
    for (l = 0; l < 16; ++l) {
      bits = *fp++;
      fb[0] = (expand_bits_4[bits] & fg) ^ bg;
      fb = (unsigned long *) ((char *)fb + line_pitch);
    }
    break;
	default:
		for (l = 0; l < 16; ++l) {
			bits = *fp++;
			fb[0] = (expand_bits_8[bits >> 4] & fg) ^ bg;
			fb[1] = (expand_bits_8[bits & 0xf] & fg) ^ bg;
			fb = (unsigned long *) ((char *)fb + line_pitch);
		}
	}
}

#ifdef	CONFIG_OSFMACH3

static void
osfmach3_vc_map(void)
{
	kern_return_t		kr;
	mach_msg_type_number_t	count;
	struct vc_info		vci;

	count = sizeof vci / sizeof (int);
	kr = device_get_status(osfmach3_video_port,
			       VC_GETINFO,
			       (dev_status_t) &vci,
			       &count);
	if (kr != D_SUCCESS) {
		MACH3_DEBUG(0, kr, 
			    ("osfmach3_vc_map: "
			     "device_get_status(0x%x, VC_GETINFO)",
			     osfmach3_video_port));
		panic("osfmach3_vc_map: can't get status for video console\n");
	}
#if 1
	osfmach3_video_map_size = PAGE_ALIGN(vci.v_rowbytes * vci.v_height *
					     (vci.v_depth >= 8?
					      (vci.v_depth >> 3):
					      (vci.v_depth >> 2)));
#else
	osfmach3_video_map_size = 8 * 1024 * 1024;	/* XXX 8 MB */
#endif
	kr = device_map(osfmach3_video_port,
			VM_PROT_READ | VM_PROT_WRITE,
			0,
			osfmach3_video_map_size,
			&osfmach3_video_memory_object,
			0);
	if (kr != D_SUCCESS) {
		MACH3_DEBUG(0, kr,
			    ("osfmach3_vc_map: device_map(0x%x, 0x%x)",
			     osfmach3_video_port, osfmach3_video_map_size));
		panic("osfmach3_vc_map: can't map video console device\n");
	}

	osfmach3_video_map_base = (vm_address_t) 0;
	kr = vm_map(mach_task_self(),
		    &osfmach3_video_map_base,		/* address */
		    osfmach3_video_map_size,		/* size */
		    0,					/* mask */
		    TRUE,				/* anywhere */
		    osfmach3_video_memory_object,	/* memory object */
		    0,					/* offset */
		    FALSE,				/* copy */
		    VM_PROT_READ | VM_PROT_WRITE,	/* cur_protection */
		    VM_PROT_READ | VM_PROT_WRITE,	/* max_protection */
		    VM_INHERIT_NONE);			/* inheritance */
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(0, kr,
			    ("osfmach3_vc_map: vm_map(obj=0x%x, size=0x%x)",
			     osfmach3_video_memory_object,
			     osfmach3_video_map_size));
		panic("osfmach3_vc_map: can't map video console\n");
	}
	osfmach3_video_physaddr = vci.v_physaddr;

	frame_buffer = (unsigned char *) osfmach3_video_map_base +
		(vci.v_baseaddr % PAGE_SIZE);
	total_vram = osfmach3_video_map_size;

	for (video_mode = 1; video_mode <= VMODE_MAX; video_mode++) {
		if (vmode_attrs[video_mode - 1].hres == vci.v_width &&
		    vmode_attrs[video_mode - 1].vres == vci.v_height) {
			/* found a correct mode */
			break;
		}
	}

	/*
  printk("osfmach3_vc_map found display to have bitdepth = %d\n",
	 (int)vci.v_depth);
  printk("osfmach3_vc_map: vci.v_rowbytes = %d, computed = %d\n",
	 (int)vci.v_rowbytes, (int)(vci.v_width * vci.v_depth) >> 3);
	 */
   
	switch (vci.v_depth) {
  case 4:
    color_mode = CMODE_4;
    color_mode_bits = CMODE_BITS_4;
    break;
	    case 8:
		color_mode = CMODE_8;
    color_mode_bits = CMODE_BITS_8;
		break;
	    case 16:
		color_mode = CMODE_16;
    color_mode_bits = CMODE_BITS_16;
		break;
	    case 24:
	    case 32:
		color_mode = CMODE_32;
    color_mode_bits = CMODE_BITS_32;
		break;
	}
}

static void
osfmach3_vc_init(void)
{
	int i, yoff, hres, offset;
	unsigned *p;
	kern_return_t		kr;
	mach_msg_type_number_t	count;
	struct vc_info		vci;

	if (video_mode <= 0 || video_mode > VMODE_MAX)
		panic("osfmach3_vc_init: display mode %d not supported",
		      video_mode);

	count = sizeof vci / sizeof (int);
	kr = device_get_status(osfmach3_video_port,
			       VC_GETINFO,
			       (dev_status_t) &vci,
			       &count);
	if (kr != D_SUCCESS) {
		MACH3_DEBUG(0, kr, 
			    ("osfmach3_vc_init: "
			     "device_get_status(0x%x, VC_GETINFO)",
			     osfmach3_video_port));
		panic("osfmach3_vc_init: can't get status for video console\n");
	}
	n_scanlines = vmode_attrs[video_mode-1].vres;
	hres = vmode_attrs[video_mode-1].hres;
	pixel_size = 1 << color_mode;
  pixel_size_bits = color_mode_bits;
	line_pitch = vci.v_rowbytes;	/* XXX includes hardware cursor */
	row_pitch = line_pitch * 16;
	ASSERT(n_scanlines == vci.v_height);
	ASSERT(hres == vci.v_width);
  ASSERT((1<<(color_mode+3)) == vci.v_depth ||
	 color_mode_bits == vci.v_depth);
	set_palette();

	yoff = (n_scanlines % 16) / 2;
#ifdef	CONFIG_OSFMACH3
	offset = 0;
#else	/* CONFIG_OSFMACH3 */
	switch (color_mode) {
	    case CMODE_8:
		offset = 0x10;	/* XXX */
		break;
	    case CMODE_16:
		offset = 0x28;	/* XXX */
		break;
	    case CMODE_32:
		offset = 0x50;	/* XXX */
		break;
	    default:
		offset = 0;	/* XXX */
	}
#endif	/* CONFIG_OSFMACH3 */
	fb_start = frame_buffer + yoff * line_pitch + offset;

#ifdef	CONFIG_OSFMACH3
	/* stop printing on the old console to avoid screwing the display */
	register_console(NULL);
	/* start collecting the micro-kernel console output ourselves */
	osfmach3_console_feed_init();
#endif	/* CONFIG_OSFMACH3 */

	/* Clear screen */
	p = (unsigned int *) (frame_buffer + offset);
	for (i = n_scanlines * line_pitch / sizeof (int); i != 0; --i) 
		*p++ = 0;

	display_info.height = n_scanlines;
	display_info.width = hres;
  display_info.depth = pixel_size_bits;
	display_info.pitch = line_pitch;
	display_info.mode = video_mode;
	// strncpy(display_info.name, "osfmach3_vc", sizeof display_info.name);
	strncpy(display_info.name, vci.v_name, sizeof display_info.name);
	display_info.fb_address = (unsigned long) osfmach3_video_physaddr;
	display_info.disp_reg_address = vci.v_reserved[0];
}

static int
osfmach3_vc_setmode(
	struct vc_mode	*mode,
	int		doit)
{
  int cmode, cmode_bits;
	struct vc_info		vci;
	kern_return_t		kr;

	if (mode->mode <= 0 || mode->mode > VMODE_MAX) 
		return -EINVAL;

  printk("osfmach3_vc_setmode called with mode->depth = %d\n", mode->depth);
   
	switch (mode->depth) {
	    case 24:
	    case 32:
		cmode = CMODE_32;
    cmode_bits = CMODE_BITS_32;
		break;
	    case 16:
		cmode = CMODE_16;
    cmode_bits = CMODE_BITS_16;
    break;
  case 4:
    cmode = CMODE_4;
    cmode_bits = CMODE_BITS_4;
		break;
	    case 8:
	    case 0:	/* (default) */
		cmode = CMODE_8;
    cmode_bits = CMODE_BITS_8;
		break;
	    default:
		return -EINVAL;
	}
	if (doit) {
		vci.v_height = vmode_attrs[mode->mode-1].vres;
		vci.v_width = vmode_attrs[mode->mode-1].hres;
		vci.v_depth = mode->depth;
		kr = device_set_status(osfmach3_video_port,
				       VC_SETVIDEOMODE,
				       (dev_status_t) &vci,
				       sizeof vci / sizeof (int));
		if (kr != D_SUCCESS) {
			MACH3_DEBUG(2, kr, 
				    ("osfmach3_vc_setmode: "
				     "device_set_status(0x%x, VC_SETINFO)",
				     osfmach3_video_port));
			return -EINVAL;
		}
		video_mode = mode->mode;
		color_mode = cmode;
    color_mode_bits = cmode_bits;
		osfmach3_vc_init();
	}
	return 0;
}

#else	/* CONFIG_OSFMACH3 */

/*
 * Screen driver for the "control" display adaptor.
 */
#define PAD(x)	char x[12]

struct preg {			/* padded register */
	unsigned r;
	char pad[12];
};

struct control_regs {
	struct preg vcount;	/* vertical counter */
	/* Vertical parameters are in units of 1/2 scan line */
	struct preg vswin;	/* between vsblank and vssync */
	struct preg vsblank;	/* vert start blank */
	struct preg veblank;	/* vert end blank (display start) */
	struct preg vewin;	/* between vesync and veblank */
	struct preg vesync;	/* vert end sync */
	struct preg vssync;	/* vert start sync */
	struct preg vperiod;	/* vert period */
	struct preg reg8;
	/* Horizontal params are in units of 2 pixels */
	struct preg hperiod;	/* horiz period - 2 */
	struct preg hsblank;	/* horiz start blank */
	struct preg heblank;	/* horiz end blank */
	struct preg hesync;	/* horiz end sync */
	struct preg hssync;	/* horiz start sync */
	struct preg rege;
	struct preg regf;
	struct preg reg10;
	struct preg reg11;
	struct preg ctrl;	/* display control */
	struct preg start_addr;	/* start address: 5 lsbs zero */
	struct preg pitch;	/* addrs diff between scan lines */
	struct preg mon_sense;	/* monitor sense bits */
	struct preg flags;
	struct preg mode;
	struct preg reg18;
	struct preg reg19;
	struct preg res[6];
};

struct control_regs *disp_regs;
static int control_use_bank2;

/*
 * Register initialization tables for the control display.
 *
 * Dot clock rate is
 * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
 *
 * The values for vertical frequency (V) in the comments below
 * are the values measured using the modes under MacOS.
 */
struct control_regvals {
	int	pitch[3];		/* bytes/line, indexed by color_mode */
	int	offset[3];		/* first pixel address */
	unsigned regs[16];		/* for vswin .. reg10 */
	unsigned char mode[3];		/* indexed by color_mode */
	unsigned char radacal_ctrl[3];
	unsigned char clock_params[3];
};

/* Register values for 1280x1024, 75Hz mode (20) */
static struct control_regvals control_reg_init_20 = {
	{ 1280, 2560, 5120 },
	{ 0x10, 0x28, 0x50 },
	{ 2129, 2128, 80, 42, 4, 2130, 2132, 88,
	  420, 411, 91, 35, 421, 18, 211, 386, },
	{ 1, 0, 0},
	{ 0x50, 0x54, 0x54 },
	{ 13, 56, 3 }	/* pixel clock = 134.61MHz for V=74.81Hz */
};

/* Register values for 1280x960, 75Hz mode (19) */
static struct control_regvals control_reg_init_19 = {
	{ 1280, 2560, 5120 },
	{ 0x10, 0x28, 0x50 },
	{ 1997, 1996, 76, 40, 4, 1998, 2000, 86,
	  418, 409, 89, 35, 419, 18, 210, 384, },
	{ 1, 0, 0 },
	{ 0x50, 0x54, 0x54 },
	{ 31, 125, 3 }	/* pixel clock = 126.01MHz for V=75.01 Hz */
};

/* Register values for 1152x870, 75Hz mode (18) */
static struct control_regvals control_reg_init_18 = {
	{ 1152, 2304, 4608 },
	{ 0x10, 0x28, 0x50 },
	{ 1825, 1822, 82, 43, 4, 1828, 1830, 120,
	  726, 705, 129, 63, 727, 32, 364, 664 },
	{ 2, 1, 0 },
	{ 0x10, 0x14, 0x18 },
	{ 19, 61, 3 }	/* pixel clock = 100.33MHz for V=75.31Hz */
};

/* Register values for 1024x768, 75Hz mode (17) */
static struct control_regvals control_reg_init_17 = {
	{ 1024, 2048, 4096 },
	{ 0x10, 0x28, 0x50 },
	{ 1603, 1600, 64, 34, 4, 1606, 1608, 120,
	  662, 641, 129, 47, 663, 24, 332, 616 },
	{ 2, 1, 0 },
	{ 0x10, 0x14, 0x18 },
	{ 11, 28, 3 }	/* pixel clock = 79.55MHz for V=74.50Hz */
};

/* Register values for 1024x768, 72Hz mode (15) */
static struct control_regvals control_reg_init_15 = {
	{ 1024, 2048, 4096 },
	{ 0x10, 0x28, 0x50 },
	{ 1607, 1604, 68, 39, 10, 1610, 1612, 132,
	  670, 653, 141, 67, 671, 34, 336, 604, },
	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
	{ 12, 30, 3 }	/* pixel clock = 78.12MHz for V=72.12Hz */
};

/* Register values for 1024x768, 60Hz mode (14) */
static struct control_regvals control_reg_init_14 = {
	{ 1024, 2048, 4096 },
	{ 0x10, 0x28, 0x50 },
	{ 1607, 1604, 68, 39, 10, 1610, 1612, 132,
	  670, 653, 141, 67, 671, 34, 336, 604, },
	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
	{ 15, 31, 3 }	/* pixel clock = 64.58MHz for V=59.62Hz */
};

/* Register values for 832x624, 75Hz mode (13) */
static struct control_regvals control_reg_init_13 = {
	{ 832, 1664, 3328 },
	{ 0x10, 0x28, 0x50 },
	{ 1331, 1330, 82, 43, 4, 1332, 1334, 128,
	  574, 553, 137, 31, 575, 16, 288, 544 },
	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
	{ 23, 42, 3 }	/* pixel clock = 57.07MHz for V=74.27Hz */
};

/* Register values for 800x600, 75Hz mode (12) */
static struct control_regvals control_reg_init_12 = {
	{ 800, 1600, 3200 },
	{ 0x10, 0x28, 0x50 },
	{ 1247, 1246, 46, 25, 4, 1248, 1250, 104,
	  526, 513, 113, 39, 527, 20, 264, 488, },
	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
	{ 7, 11, 3 }	/* pixel clock = 49.11MHz for V=74.40Hz */
};

/* Register values for 800x600, 72Hz mode (11) */
static struct control_regvals control_reg_init_11 = {
	{ 800, 1600, 3200 },
	{ 0x10, 0x28, 0x50 },
	{ 1293, 1256, 56, 33, 10, 1330, 1332, 76,
	  518, 485, 85, 59, 519, 30, 260, 460, },
	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
	{ 17, 27, 3 }	/* pixel clock = 49.63MHz for V=71.66Hz */
};

/* Register values for 800x600, 60Hz mode (10) */
static struct control_regvals control_reg_init_10 = {
	{ 800, 1600, 3200 },
	{ 0x10, 0x28, 0x50 },
	{ 1293, 1256, 56, 33, 10, 1330, 1332, 76,
	  518, 485, 85, 59, 519, 30, 260, 460, },
	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
	{ 20, 53, 2 }	/* pixel clock = 41.41MHz for V=59.78Hz */
};

/* Register values for 640x870, 75Hz Full Page Display (7) */
static struct control_regvals control_reg_init_7 = {
        { 640, 1280, 2560 },
	{ 0x10, 0x30, 0x68 },
	{ 0x727, 0x724, 0x58, 0x2e, 0x4, 0x72a, 0x72c, 0x40,
	  0x19e, 0x18c, 0x4c, 0x27, 0x19f, 0x14, 0xd0, 0x178 },
	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
	{ 9, 33, 2 }	/* pixel clock = 57.29MHz for V=75.01Hz */
};

/* Register values for 640x480, 67Hz mode (6) */
static struct control_regvals control_reg_init_6 = {
	{ 640, 1280, 2560 },
	{ 0, 8, 0x10 },
	{ 1045, 1042, 82, 43, 4, 1048, 1050, 72,
	  430, 393, 73, 31, 431, 16, 216, 400 },
	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
	{ 14, 27, 2 }	/* pixel clock = 30.13MHz for V=66.43Hz */
};

/* Register values for 640x480, 60Hz mode (5) */
static struct control_regvals control_reg_init_5 = {
	{ 640, 1280, 2560 },
	{ 0x10, 0x28, 0x50 },
	{ 1037, 1026, 66, 34, 2, 1048, 1050, 56,
	  398, 385, 65, 47, 399, 24, 200, 352, },
	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
	{ 23, 37, 2 }	/* pixel clock = 25.14MHz for V=59.85Hz */
};

static struct control_regvals *control_reg_init[20] = {
	NULL, NULL, NULL, NULL,
	&control_reg_init_5,
	&control_reg_init_6,
	&control_reg_init_7,
	NULL, NULL,
	&control_reg_init_10,
	&control_reg_init_11,
	&control_reg_init_12,
	&control_reg_init_13,
	&control_reg_init_14,
	&control_reg_init_15,
	NULL,
	&control_reg_init_17,
	&control_reg_init_18,
	&control_reg_init_19,
	&control_reg_init_20
};

/*
 * Get the monitor sense value.
 * Note that this can be called before calibrate_delay,
 * so we can't use udelay.
 */
static int
read_control_sense()
{
	int sense;

	st_rev(&disp_regs->mon_sense.r, 7);	/* drive all lines high */
	eieio(); __delay(200);
	st_rev(&disp_regs->mon_sense.r, 077);	/* turn off drivers */
	eieio(); __delay(2000);
	sense = (ld_rev(&disp_regs->mon_sense.r) & 0x1c0) << 2;

	/* drive each sense line low in turn and collect the other 2 */
	st_rev(&disp_regs->mon_sense.r, 033);	/* drive A low */
	eieio(); __delay(2000);
	sense |= (ld_rev(&disp_regs->mon_sense.r) & 0xc0) >> 2;
	eieio();
	st_rev(&disp_regs->mon_sense.r, 055);	/* drive B low */
	eieio(); __delay(2000);
	sense |= ((ld_rev(&disp_regs->mon_sense.r) & 0x100) >> 5)
		| ((ld_rev(&disp_regs->mon_sense.r) & 0x40) >> 4);
	eieio();
	st_rev(&disp_regs->mon_sense.r, 066);	/* drive C low */
	eieio(); __delay(2000);
	sense |= (ld_rev(&disp_regs->mon_sense.r) & 0x180) >> 7;
	eieio();

	st_rev(&disp_regs->mon_sense.r, 077);	/* turn off drivers */
	return sense;
}

static inline int control_vram_reqd(int vmode, int cmode)
{
	return vmode_attrs[vmode-1].vres
		* control_reg_init[vmode-1]->pitch[cmode];
}

static void
map_control_display(struct device_node *dp)
{
	int i, sense;
	unsigned long addr, end;
	int bank1, bank2;

	if (dp->next != 0)
		printk("Warning: only using first control display device\n");
	if (dp->n_addrs != 2)
		panic("expecting 2 addresses for control (got %d)", dp->n_addrs);

#if 0
	printk("pmac_display_init: node = %p, addrs =", dp->node);
	for (i = 0; i < dp->n_addrs; ++i)
		printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
	printk(", intrs =");
	for (i = 0; i < dp->n_intrs; ++i)
		printk(" %x", dp->intrs[i]);
	printk("\n");
#endif

	/* Map in frame buffer and registers */
	for (i = 0; i < dp->n_addrs; ++i) {
		addr = dp->addrs[i].address;
		end = dp->addrs[i].size;
		if (end > 0x800000) {
			/* map at most 8MB for the frame buffer */
			end = 0x800000;
			/* use the big-endian aperture (??) */
			addr += 0x800000;
		}
		if (end >= 0x100000)
			/* the big one (>= 1MB) is the frame buffer */
			frame_buffer = (unsigned char *) addr;
		else
			disp_regs = (struct control_regs *) addr;
		end += addr;
		for (; addr < end; addr += PAGE_SIZE)
			MMU_map_page(&init_task.tss, addr, addr,
				_PAGE_PRESENT | _PAGE_RW | _PAGE_NO_CACHE);
	}

	cmap_regs = (struct cmap_regs *) 0xf301b000;	/* XXX not in prom? */

	/* Work out which banks of VRAM we have installed. */
	frame_buffer[0] = 0x5a;
	frame_buffer[1] = 0xc7;
	bank1 = frame_buffer[0] == 0x5a && frame_buffer[1] == 0xc7;
	frame_buffer[0x600000] = 0xa5;
	frame_buffer[0x600001] = 0x38;
	bank2 = frame_buffer[0x600000] == 0xa5 && frame_buffer[0x600001] == 0x38;
	total_vram = (bank1 + bank2) * 0x200000;
	/* If we don't have bank 1 installed, we hope we have bank 2 :-) */
	control_use_bank2 = !bank1;
	if (control_use_bank2)
		frame_buffer += 0x600000;

	sense = read_control_sense();
	if (video_mode == VMODE_NVRAM) {
		video_mode = nvram_readb(NV_VMODE);
		if (video_mode <= 0 || video_mode > VMODE_MAX
		    || control_reg_init[video_mode-1] == 0)
			video_mode = VMODE_CHOOSE;
	}
	if (video_mode == VMODE_CHOOSE)
		video_mode = map_monitor_sense(sense);
	if (control_reg_init[video_mode-1] == 0)
		video_mode = VMODE_640_480_60;

	/*
	 * Reduce the pixel size if we don't have enough VRAM.
	 */
  if (color_mode == CMODE_NVRAM) {
		color_mode = nvram_readb(NV_CMODE);
    color_mode_bits = 8 * color_mode;
  }
  if (color_mode < CMODE_8 || color_mode > CMODE_32) {
		color_mode = CMODE_8;
    color_mode_bits = CMODE_BITS_8;
  }
	while (color_mode > CMODE_8
	 && control_vram_reqd(video_mode, color_mode) > total_vram) {
		--color_mode;
    color_mode_bits -= 8;
  }

	printk("Monitor sense value = 0x%x, ", sense);
}

static void
set_control_clock(unsigned char *params)
{
	struct cuda_request req;
	int i;

	for (i = 0; i < 3; ++i) {
		cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
			     0x50, i + 1, params[i]);
		while (!req.got_reply)
			cuda_poll();
	}
}

static void
control_init()
{
	struct preg *rp;
	int i, yoff, hres;
	unsigned *p;
	struct control_regvals *init;

	if (video_mode <= 0 || video_mode > VMODE_MAX
	    || (init = control_reg_init[video_mode-1]) == 0)
		panic("control: display mode %d not supported", video_mode);
	n_scanlines = vmode_attrs[video_mode-1].vres;
	hres = vmode_attrs[video_mode-1].hres;
	pixel_size = 1 << color_mode;
  pixel_size_bits = color_mode_bits;
	line_pitch = init->pitch[color_mode];
	row_pitch = line_pitch * 16;

	/* Initialize display timing registers */
	st_rev(&disp_regs->ctrl.r, 0x43b);
	set_control_clock(init->clock_params);
	cmap_regs->addr = 0x20; cmap_regs->d2 = init->radacal_ctrl[color_mode];
	cmap_regs->addr = 0x21; cmap_regs->d2 = control_use_bank2? 0: 1;
	cmap_regs->addr = 0x10; cmap_regs->d2 = 0;
	cmap_regs->addr = 0x11; cmap_regs->d2 = 0;
	rp = &disp_regs->vswin;
	for (i = 0; i < 16; ++i, ++rp)
		st_rev(&rp->r, init->regs[i]);
	st_rev(&disp_regs->pitch.r, line_pitch);
	st_rev(&disp_regs->mode.r, init->mode[color_mode]);
	st_rev(&disp_regs->flags.r, control_use_bank2? 0x39: 0x31);
	st_rev(&disp_regs->start_addr.r, 0);
	st_rev(&disp_regs->reg18.r, 0x1e5);
	st_rev(&disp_regs->reg19.r, 0);
	set_palette();		/* Initialize colormap */
	st_rev(&disp_regs->ctrl.r, 0x3b);

	yoff = (n_scanlines % 16) / 2;
	fb_start = frame_buffer + yoff * line_pitch + init->offset[color_mode];

	/* Clear screen */
	p = (unsigned *) (frame_buffer + init->offset[color_mode]);
	for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
		*p++ = 0;

	display_info.height = n_scanlines;
	display_info.width = hres;
  display_info.depth = pixel_size_bits;
	display_info.pitch = line_pitch;
	display_info.mode = video_mode;
	strncpy(display_info.name, "control", sizeof(display_info.name));
	display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
	display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
	display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
	display_info.disp_reg_address = (unsigned long) &disp_regs;
}

static int
control_setmode(struct vc_mode *mode, int doit)
{
  int cmode, cmode_bits;

	if (mode->mode <= 0 || mode->mode > VMODE_MAX
	    || control_reg_init[mode->mode-1] == 0)
		return -EINVAL;
	switch (mode->depth) {
	case 24:
	case 32:
		cmode = CMODE_32;
    cmode_bits = CMODE_BITS_32;
		break;
	case 16:
		cmode = CMODE_16;
    cmode_bits = CMODE_BITS_16;
    break;
  case 4:
    cmode = CMODE_4;
    cmode_bits = CMODE_BITS_4;
		break;
	case 8:
	case 0:		/* (default) */
		cmode = CMODE_8;
    cmode_bits = CMODE_BITS_8;
		break;
	default:
		return -EINVAL;
	}
	if (control_vram_reqd(mode->mode, cmode) > total_vram)
		return -EINVAL;
	if (doit) {
		video_mode = mode->mode;
		color_mode = cmode;
    color_mode_bits = cmode_bits;
		control_init();
	}
	return 0;
}

/*
 * Screen driver for the platinum display adaptor.
 */
struct platinum_regs {
	struct preg reg[128];
};

volatile struct platinum_regs *plat_regs;

/*
 * Register initialization tables for the platinum display.
 *
 * It seems that there are two different types of platinum display
 * out there.  Older ones use the values in clocksel[1], for which
 * the formula for the clock frequency seems to be
 *	F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5))
 * Newer ones use the values in clocksel[0], for which the formula
v * seems to be
 *	F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5))
 */
 struct plat_regvals {
	int	fb_offset;
	int	pitch[3];
	unsigned regs[26];
	unsigned char plat_offset[3];
	unsigned char mode[3];
	unsigned char dacula_ctrl[3];
	unsigned char clocksel[2][2];
 };

#define DIV2	0x20
#define DIV4	0x40
#define DIV8	0x60
#define DIV16	0x80

/* 1280x1024, 75Hz (20) */
static struct plat_regvals platinum_reg_init_20 = {
	0x5c00,
	{ 1312, 2592, 2592 },
	{ 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
	  0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d,
	  0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50,
	  0x850, 0x851 }, { 0x58, 0x5d, 0x5d },
	{ 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
	{{ 45, 3 }, { 66, 7 }}
};

/* 1280x960, 75Hz (19) */
static struct plat_regvals platinum_reg_init_19 = {
	0x5c00,
	{ 1312, 2592, 2592 },
	{ 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
	  0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d,
	  0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c,
	  0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b },
	{ 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
	{{ 42, 3 }, { 44, 5 }}
};

/* 1152x870, 75Hz (18) */
static struct plat_regvals platinum_reg_init_18 = {
	0x11b0,
	{ 1184, 2336, 4640 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x38f, 0,
	  0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53,
	  0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52,
	  0x71e, 0x722 }, { 0x74, 0x7c, 0x81 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 26, 0 + DIV2 }, { 42, 6 }}
};

/* 1024x768, 75Hz (17) */
static struct plat_regvals platinum_reg_init_17 = {
	0x10b0,
	{ 1056, 2080, 4128 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b,
	  0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40,
	  0x640, 0x644 }, { 0x72, 0x7a, 0x7f },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 54, 3 + DIV2 }, { 67, 12 }}
};

/* 1024x768, 75Hz (16) */
static struct plat_regvals platinum_reg_init_16 = {
	0x10b0,
	{ 1056, 2080, 4128 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47,
	  0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c,
	  0x63c, 0x63d }, { 0x74, 0x7c, 0x81 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 20, 0 + DIV2 }, { 11, 2 }}
};

/* 1024x768, 70Hz (15) */
static struct plat_regvals platinum_reg_init_15 = {
	0x10b0,
	{ 1056, 2080, 4128 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b,
	  0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44,
	  0x644, 0x646 }, { 0x78, 0x80, 0x85 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 19, 0 + DIV2 }, { 110, 21 }}
};

/* 1024x768, 60Hz (14) */
static struct plat_regvals platinum_reg_init_14 = {
	0x10b0,
	{ 1056, 2080, 4128 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b,
	  0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44,
	  0x644, 0x646 }, { 0x80, 0x88, 0x8d },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }}
};

/* 832x624, 75Hz (13) */
static struct plat_regvals platinum_reg_init_13 = {
	0x70,
	{ 864, 1680, 3360 },	/* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
	{ 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
	  0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
	  0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
	  0x532, 0x533 }, { 0x7c, 0x84, 0x89 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
};

/* 800x600, 75Hz (12) */
static struct plat_regvals platinum_reg_init_12 = {
	0x1010,
	{ 832, 1632, 3232 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39,
	  0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e,
	  0x4de, 0x4df }, { 0x64, 0x6c, 0x71 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }}
};

/* 800x600, 72Hz (11) */
static struct plat_regvals platinum_reg_init_11 = {
	0x1010,
	{ 832, 1632, 3232 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d,
	  0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38,
	  0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }}
};

/* 800x600, 60Hz (10) */
static struct plat_regvals platinum_reg_init_10 = {
	0x1010,
	{ 832, 1632, 3232 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
	  0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
	  0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }}
};

/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */
static struct plat_regvals platinum_reg_init_9 = {
	0x1010,
	{ 832, 1632, 3232 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
	  0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
	  0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }}
};

/* 768x576, 50Hz Interlaced-PAL (8) */
static struct plat_regvals platinum_reg_init_8 = {
	0x1010,
	{ 800, 1568, 3104 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
	  0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27,
	  0x267, 0x26b }, { 0x39, 0x41, 0x46 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
};

/* 640x870, 75Hz Portrait (7) */
static struct plat_regvals platinum_reg_init_7 = {
	0xb10,
	{ 672, 1312, 2592 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f,
	  0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58,
	  0x724, 0x72a }, { 0x3c, 0x44, 0x49 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
};

/* 640x480, 67Hz (6) */
static struct plat_regvals platinum_reg_init_6 = {
	0x1010,
	{ 672, 1312, 2592 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x209, 0,
	  0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37,
	  0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52,
	  0x412, 0x416 }, { 0x3c, 0x44, 0x49 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }}
};

/* 640x480, 60Hz (5) */
static struct plat_regvals platinum_reg_init_5 = {
	0x1010,
	{ 672, 1312, 2592 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e,
	  0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44,
	  0x404, 0x408 }, { 0x34, 0x3c, 0x41 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }}
};

/* 640x480, 60Hz Interlaced-NTSC (4) */
static struct plat_regvals platinum_reg_init_4 = {
	0x1010,
	{ 672, 1312, 2592 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
	  0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23,
	  0x203, 0x206 }, { 0x29, 0x31, 0x36 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
};

/* 640x480, 50Hz Interlaced-PAL (3) */
static struct plat_regvals platinum_reg_init_3 = {
	0x1010,
	{ 672, 1312, 2592 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
	  0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57,
	  0x237, 0x26b }, { 0x59, 0x61, 0x66 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
};

/* 512x384, 60Hz (2) */
static struct plat_regvals platinum_reg_init_2 = {
	0x1010,
	{ 544, 1056, 2080 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f,
	  0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a,
	  0x32a, 0x32b }, { 0x5a, 0x62, 0x67 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }}
};

/* 512x384, 60Hz Interlaced-NTSC (1) */
static struct plat_regvals platinum_reg_init_1 = {
	0x1010,
	{ 544, 1056, 2080 },
	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
	  0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
	  0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53,
	  0x1d3, 0x206 }, { 0x49, 0x51, 0x56 },
	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
	{{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
};

static struct plat_regvals *platinum_reg_init[VMODE_MAX] = {
	&platinum_reg_init_1,
	&platinum_reg_init_2,
	&platinum_reg_init_3,
	&platinum_reg_init_4,
	&platinum_reg_init_5,
	&platinum_reg_init_6,
	&platinum_reg_init_7,
	&platinum_reg_init_8,
	&platinum_reg_init_9,
	&platinum_reg_init_10,
	&platinum_reg_init_11,
	&platinum_reg_init_12,
	&platinum_reg_init_13,
	&platinum_reg_init_14,
	&platinum_reg_init_15,
	&platinum_reg_init_16,
	&platinum_reg_init_17,
	&platinum_reg_init_18,
	&platinum_reg_init_19,
	&platinum_reg_init_20
};

/*
 * Get the monitor sense value.
 */
static int
read_platinum_sense()
{
	int sense;

	plat_regs->reg[23].r = 7;	/* turn off drivers */
	eieio(); __delay(2000);
	sense = (~plat_regs->reg[23].r & 7) << 8;

	/* drive each sense line low in turn and collect the other 2 */
	plat_regs->reg[23].r = 3;	/* drive A low */
	eieio(); __delay(2000);
	sense |= (~plat_regs->reg[23].r & 3) << 4;
	eieio();
	plat_regs->reg[23].r = 5;	/* drive B low */
	eieio(); __delay(2000);
	sense |= (~plat_regs->reg[23].r & 4) << 1;
	sense |= (~plat_regs->reg[23].r & 1) << 2;
	eieio();
	plat_regs->reg[23].r = 6;	/* drive C low */
	eieio(); __delay(2000);
	sense |= (~plat_regs->reg[23].r & 6) >> 1;
	eieio();

	plat_regs->reg[23].r = 7;	/* turn off drivers */
	return sense;
}

static inline int platinum_vram_reqd(int vmode, int cmode)
{
        return vmode_attrs[vmode-1].vres
                * platinum_reg_init[vmode-1]->pitch[cmode];
}

static void
map_platinum(struct device_node *dp)
{
	int i, sense;
	unsigned long addr, size, end;
	int bank0, bank1, bank2, bank3;

	if (dp->next != 0)
		printk("Warning: only using first platinum display device\n");
	if (dp->n_addrs != 2)
		panic("expecting 2 addresses for platinum (got %d)",
		      dp->n_addrs);

	/* Map in frame buffer and registers */
	for (i = 0; i < dp->n_addrs; ++i) {
		addr = dp->addrs[i].address;
		size = dp->addrs[i].size;
		if (size >= 0x400000) {
			/* frame buffer - map only 4MB */
			size = 0x400000;
			frame_buffer = (unsigned char *) addr;
			base_frame_buffer = (unsigned char *) addr;
		} else {
			/* registers */
			plat_regs = (volatile struct platinum_regs *) addr;
		}
		for (end = addr + size; addr < end; addr += PAGE_SIZE)
			MMU_map_page(&init_task.tss, addr, addr,
				_PAGE_PRESENT | _PAGE_RW | _PAGE_NO_CACHE);
	}
	cmap_regs = (struct cmap_regs *) 0xf301b000;	/* XXX not in prom? */

	/* Grok total video ram */
	plat_regs->reg[16].r = (unsigned)frame_buffer;
	plat_regs->reg[20].r = 0x1011;	/* select max vram */
	plat_regs->reg[24].r = 0;	/* switch in vram */
	eieio();
	frame_buffer[0x100000] = 0x34;
	frame_buffer[0x200000] = 0x56;
	frame_buffer[0x300000] = 0x78;
	bank0 = 1; /* builtin 1MB vram, always there */
	bank1 = frame_buffer[0x100000] == 0x34;
	bank2 = frame_buffer[0x200000] == 0x56;
	bank3 = frame_buffer[0x300000] == 0x78;
	total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
	printk("Total VRAM = %dMB\n", total_vram / 1024 / 1024);

	sense = read_platinum_sense();
	if (video_mode == VMODE_NVRAM) {
		video_mode = nvram_readb(NV_VMODE);
		if (video_mode <= 0 || video_mode > VMODE_MAX
		    || platinum_reg_init[video_mode-1] == 0)
			video_mode = VMODE_CHOOSE;
	}
	if (video_mode == VMODE_CHOOSE)
		video_mode = map_monitor_sense(sense);
	if (platinum_reg_init[video_mode-1] == 0)
		video_mode = VMODE_640_480_60;
	printk("Monitor sense value = 0x%x, ", sense);

	if (color_mode == CMODE_NVRAM)
                color_mode = nvram_readb(NV_CMODE);
        if (color_mode < CMODE_8 || color_mode > CMODE_32)
                color_mode = CMODE_8;
	/*
	 * Reduce the pixel size if we don't have enough VRAM.
	 */
	while (color_mode > CMODE_8
	       && platinum_vram_reqd(video_mode, color_mode) > total_vram)
		--color_mode;
	/*
	 * Reduce the video mode if we don't have enough VRAM.
	 */
	while (platinum_vram_reqd(video_mode, color_mode) > total_vram)
		--video_mode;
}

#define STORE_D2(a, v) { \
	cmap_regs->addr = (a+32); eieio(); \
	cmap_regs->d2 = (v); eieio(); \
}

static void
set_platinum_clock(unsigned char *clksel)
{
	STORE_D2(6, 0xc6);
	cmap_regs->addr = 3+32; eieio();
	if (cmap_regs->d2 == 2) {
		STORE_D2(7, clksel[0]);
		STORE_D2(8, clksel[1]);
		STORE_D2(3, 3);
	} else {
		STORE_D2(4, clksel[0]);
		STORE_D2(5, clksel[1]);
		STORE_D2(3, 2);
	}
	__delay(5000);
	STORE_D2(9, 0xa6);
}

static void
platinum_init()
{
	int i, yoff, width, clkmode, dtype;
	struct plat_regvals *init;
	unsigned *p;
	int one_mb = 0;

	if (total_vram == 0x100000) one_mb=1;

	if (video_mode <= 0 || video_mode > VMODE_MAX
	    || (init = platinum_reg_init[video_mode-1]) == 0)
		panic("platinum: video mode %d not supported", video_mode);

	frame_buffer = base_frame_buffer + init->fb_offset;
	/* printk("Frame buffer start address is %p\n", frame_buffer); */

	pixel_size = 1 << color_mode;
  pixel_size_bits = color_mode_bits;
	line_pitch = init->pitch[color_mode];
	width = vmode_attrs[video_mode-1].hres;
	n_scanlines = vmode_attrs[video_mode-1].vres;
	row_pitch = line_pitch * 16;

	/* Initialize display timing registers */
	plat_regs->reg[24].r = 7;	/* switch out video ram */
	eieio();

	for (i = 0; i < 26; ++i)
		plat_regs->reg[i+32].r = init->regs[i];
	plat_regs->reg[26+32].r = (one_mb ? init->plat_offset[color_mode] + 4 - color_mode : init->plat_offset[color_mode]);
	plat_regs->reg[16].r = (unsigned) frame_buffer;
	plat_regs->reg[18].r = line_pitch;
	plat_regs->reg[19].r = (one_mb ? init->mode[color_mode+1] : init->mode[color_mode]);
	plat_regs->reg[20].r = (one_mb ? 0x11 : 0x1011);
	plat_regs->reg[21].r = 0x100;
	plat_regs->reg[22].r = 1;
	plat_regs->reg[23].r = 1;
	plat_regs->reg[26].r = 0xc00;
	plat_regs->reg[27].r = 0x235;
	/* plat_regs->reg[27].r = 0x2aa; */

	STORE_D2(0, (one_mb ? init->dacula_ctrl[color_mode] & 0xf : init->dacula_ctrl[color_mode]));
	STORE_D2(1, 4);
	STORE_D2(2, 0);
	/*
	 * Try to determine whether we have an old or a new DACula.
	 */
	if (plat_alt_clock)
		clkmode = 1;
	else {
		cmap_regs->addr = 0x40; eieio();
		dtype = cmap_regs->d2;
		switch (dtype) {
		case 0x3c:
			clkmode = 1;
			break;
		case 0x84:
			clkmode = 0;
			break;
		default:
			clkmode = 0;
			printk("Unknown DACula type: %x\n", cmap_regs->d2);
		}
	}
	set_platinum_clock(init->clocksel[clkmode]);

	plat_regs->reg[24].r = 0;	/* switch in video ram */
	eieio();

	set_palette();

	yoff = (n_scanlines % 16) / 2;
	fb_start = frame_buffer + yoff * line_pitch + 0x10;

	/* Clear screen */
	p = (unsigned *) (frame_buffer + 0x10);
	for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
		*p++ = 0;

	display_info.height = n_scanlines;
	display_info.width = width;
  display_info.depth = pixel_size_bits;
	display_info.pitch = line_pitch;
	display_info.mode = video_mode;
	strncpy(display_info.name, "platinum", sizeof(display_info.name));
	display_info.fb_address = (unsigned long) frame_buffer + 0x10;
	display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
	display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
	display_info.disp_reg_address = (unsigned long) &plat_regs;
}

static int
platinum_setmode(struct vc_mode *mode, int doit)
{
	int cmode;

	if (mode->mode <= 0 || mode->mode > VMODE_MAX
	    || platinum_reg_init[mode->mode-1] == 0)
		return -EINVAL;
	if (mode->depth != 8 && mode->depth != 16 && mode->depth != 24 && mode->depth != 32)
		return -EINVAL;

	switch (mode->depth) {
        case 24:
        case 32:
                cmode = CMODE_32;
                break;
        case 16:
                cmode = CMODE_16;
                break;
        case 8:
                cmode = CMODE_8;
                break;
        default:
                return -EINVAL;
        }

	if (platinum_vram_reqd(mode->mode, cmode) > total_vram)
		return -EINVAL;

	if (doit) {
		video_mode = mode->mode;
		color_mode = cmode;
		platinum_init();
	}
	return 0;
}

#endif	/* CONFIG_OSFMACH3 */

unsigned char vga_font[cmapsz] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 
};
