fbdev: Add gcnfb framebuffer device driver for gamecube/wii

based on Farter's work.

URL: https://fartersoft.com/blog/2011/07/31/hacking-up-an-rgb-framebuffer-driver-for-wii-linux-take-two
Signed-off-by: Maximilian Downey Twiss <creatorsmithmdt@gmail.com>
Signed-off-by: Helge Deller <deller@gmx.de>
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index cfc5527..65c1dd8 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1602,6 +1602,15 @@
 	  Use custom board timings.
 endchoice
 
+config FB_GAMECUBE
+	bool "Nintendo GameCube/Wii frame buffer"
+	depends on FB && GAMECUBE_COMMON
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the frame buffer device driver for the Nintendo GameCube.
+
 config FB_AU1100
 	bool "Au1100 LCD Driver"
 	depends on (FB = y) && MIPS_ALCHEMY
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 7795c41..61ec2f1 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -118,6 +118,7 @@
 obj-$(CONFIG_FB_HYPERV)		  += hyperv_fb.o
 obj-$(CONFIG_FB_OPENCORES)	  += ocfb.o
 obj-$(CONFIG_FB_SM712)		  += sm712fb.o
+obj-$(CONFIG_FB_GAMECUBE)	  += gcnfb.o
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
diff --git a/drivers/video/fbdev/gcnfb.c b/drivers/video/fbdev/gcnfb.c
new file mode 100644
index 0000000..df2d7dd
--- /dev/null
+++ b/drivers/video/fbdev/gcnfb.c
@@ -0,0 +1,2443 @@
+/*
+ * drivers/video/gcn-vifb.c
+ *
+ * Nintendo GameCube/Wii Video Interface (VI) frame buffer driver
+ * Copyright (C) 2004-2009 The GameCube Linux Team
+ * Copyright (C) 2004 Michael Steil <mist@c64.org>
+ * Copyright (C) 2004,2005 Todd Jeffreys <todd@voidpointer.org>
+ * Copyright (C) 2006,2007,2008,2009 Albert Herranz
+ *
+ * Based on vesafb (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/io.h>
+#ifdef CONFIG_WII_AVE_RVL
+#include <linux/i2c.h>
+#endif
+
+/* to support deferred IO */
+#include <linux/rmap.h>
+#include <linux/pagemap.h>
+
+#define DRV_MODULE_NAME   "gcn-vifb"
+#define DRV_DESCRIPTION   "Nintendo GameCube/Wii Video Interface (VI) driver"
+#define DRV_AUTHOR        "Michael Steil <mist@c64.org>, " \
+			  "Todd Jeffreys <todd@voidpointer.org>, " \
+			  "Albert Herranz"
+
+static char vifb_driver_version[] = "2.1i";
+
+#define drv_printk(level, format, arg...) \
+	 printk(level DRV_MODULE_NAME ": " format , ## arg)
+
+
+/*
+ * Hardware registers.
+ */
+
+#define __declare_vi_reg_set_field(reg_size, reg, field_size, field, \
+				   mask, shift) \
+static inline reg_size vi_##reg##_set_##field(reg_size reg, field_size field) \
+{									\
+	reg &= ~(mask << shift);					\
+	reg |= (field & mask) << shift;					\
+	return reg;							\
+}
+
+#define __declare_vi_reg_clear_field(reg_size, reg, field, mask, shift) \
+static inline reg_size vi_##reg##_clear_##field(reg_size reg)	\
+{									\
+	reg &= ~(mask << shift);					\
+	return reg;							\
+}
+
+#define __declare_vi_reg_get_field(reg_size, reg, field_size, field, \
+				   mask, shift) \
+static inline field_size vi_##reg##_get_##field(reg_size reg)	\
+{									\
+	return (reg>>shift)&mask;					\
+}
+
+#define __declare_vi_reg_field(reg_size, reg, field_size, field, \
+			       mask, shift) \
+static inline reg_size vi_##reg##_##field(field_size field)	\
+{									\
+	return (field & mask) << shift;					\
+}
+
+#define __vi_reg_field(reg_size, reg, field_size, field, mask, shift) \
+__declare_vi_reg_set_field(reg_size, reg, field_size, field, mask, shift) \
+__declare_vi_reg_clear_field(reg_size, reg, field, mask, shift) 	  \
+__declare_vi_reg_get_field(reg_size, reg, field_size, field, mask, shift) \
+__declare_vi_reg_field(reg_size, reg, field_size, field, mask, shift)
+
+
+#define VI_VTR			0x00 /* Vertical Timing, 16 bits */
+__vi_reg_field(u16, vtr, u16, acv, 0x3ff, 4);		/* ACtive Video */
+__vi_reg_field(u16, vtr, u8, equ, 0xf, 0);		/* EQUalization pulse */
+
+#define VI_DCR			0x02 /* Display Configuration, 16 bits */
+__vi_reg_field(u16, dcr, u8, fmt, 0x3, 8);		/* Format */
+__vi_reg_field(u16, dcr, u8, le1, 0x3, 6);		/* Latch Enable 1 */
+__vi_reg_field(u16, dcr, u8, le0, 0x3, 4);		/* Latch Enable 0 */
+__vi_reg_field(u16, dcr, u8, dlr, 0x1, 3);		/* 3D mode */
+__vi_reg_field(u16, dcr, u8, nin, 0x1, 2);		/* Non-Interlaced */
+__vi_reg_field(u16, dcr, u8, rst, 0x1, 1);		/* Reset */
+__vi_reg_field(u16, dcr, u8, enb, 0x1, 0);		/* Enable */
+
+#define VI_HTR0			0x04 /* Horizontal Timing 0, 32 bits */
+__vi_reg_field(u32, htr0, u8, hcs, 0x7f, 24);		/* Horz Color Start */
+__vi_reg_field(u32, htr0, u8, hce, 0x7f, 16);		/* Horz Color End */
+__vi_reg_field(u32, htr0, u16, hlw, 0x1ff, 0);		/* Half Line Width */
+
+#define VI_HTR1			0x08 /* Horizontal Timing 1, 32 bits */
+__vi_reg_field(u32, htr1, u16, hbs, 0x3ff, 17);		/* Horz Blank Start */
+__vi_reg_field(u32, htr1, u16, hbe, 0x3ff, 7);		/* Horz Blank End */
+__vi_reg_field(u32, htr1, u8, hsy, 0x7f, 0);		/* Horz Sync Width */
+
+#define VI_VTO			0x0c /* Vertical Timing Odd, 32 bits */
+__vi_reg_field(u32, vto, u16, psb, 0x3ff, 16);		/* Post Blanking */
+__vi_reg_field(u32, vto, u16, prb, 0x3ff, 0);		/* Pre Blanking */
+
+#define VI_VTE			0x10 /* Vertical Timing Even, 32 bits */
+__vi_reg_field(u32, vte, u16, psb, 0x3ff, 16);		/* Post Blanking */
+__vi_reg_field(u32, vte, u16, prb, 0x3ff, 0);		/* Pre Blanking */
+
+#define VI_BBOI			0x14 /* Burst Blanking Odd Interval, 32 bits */
+__vi_reg_field(u32, bboi, u16, be3, 0x7ff, 21);
+__vi_reg_field(u32, bboi, u8, bs3, 0x1f, 16);
+__vi_reg_field(u32, bboi, u16, be1, 0x7ff, 5);
+__vi_reg_field(u32, bboi, u8, bs1, 0x1f, 0);
+
+#define VI_BBEI			0x18 /* Burst Blanking Even Interval, 32 bits */
+__vi_reg_field(u32, bbei, u16, be4, 0x7ff, 21);
+__vi_reg_field(u32, bbei, u8, bs4, 0x1f, 16);
+__vi_reg_field(u32, bbei, u16, be2, 0x7ff, 5);
+__vi_reg_field(u32, bbei, u8, bs2, 0x1f, 0);
+
+#define VI_TFBL			0x1c /* Top Field Base (L), 32 bits */
+__vi_reg_field(u32, tfbl, u8, pob, 0x1, 28);		/* Page Offset Bit */
+__vi_reg_field(u32, tfbl, u8, xof, 0xf, 24);		/* X Offset */
+__vi_reg_field(u32, tfbl, u32, fba, 0xffffff, 0);	/* Frame Buf Address */
+
+#define VI_TFBR			0x20 /* Top Field Base (R), 32 bits */
+__vi_reg_field(u32, tfbr, u8, pob, 0x1, 28);		/* Page Offset Bit */
+__vi_reg_field(u32, tfbr, u32, fba, 0xffffff, 0);	/* Frame Buf Address */
+
+#define VI_BFBL			0x24 /* Bottom Field Base (L), 32 bits */
+__vi_reg_field(u32, bfbl, u8, pob, 0x1, 28);		/* Page Offset Bit */
+__vi_reg_field(u32, bfbl, u8, xof, 0xf, 24);		/* X Offset */
+__vi_reg_field(u32, bfbl, u32, fba, 0xffffff, 0);	/* Frame Buf Address */
+
+#define VI_BFBR			0x28 /* Bottom Field Base (R), 32 bits */
+__vi_reg_field(u32, bfbr, u8, pob, 0x1, 28);		/* Page Offset Bit */
+__vi_reg_field(u32, bfbr, u32, fba, 0xffffff, 0);	/* Frame Buf Address */
+
+#define VI_DPV			0x2c /* Display Position Vertical, 16 bits */
+__vi_reg_field(u16, dpv, u16, val, 0x7ff, 0);
+
+#define VI_DPH			0x2e /* Display Position Horizontal, 16 bits */
+__vi_reg_field(u16, dph, u16, val, 0x7ff, 0);
+
+#define VI_DI0			0x30 /* Display Interrupt 0, 32 bits */
+#define VI_DI1			0x34 /* Display Interrupt 1, 32 bits */
+#define VI_DI2			0x38 /* Display Interrupt 2, 32 bits */
+#define VI_DI3			0x3C /* Display Interrupt 3, 32 bits */
+__vi_reg_field(u32, dix, u8, irq, 0x1, 31);
+__vi_reg_field(u32, dix, u8, enb, 0x1, 28);
+__vi_reg_field(u32, dix, u16, vct, 0x3ff, 16);
+__vi_reg_field(u32, dix, u16, hct, 0x3ff, 0);
+
+#define VI_DL0			0x40 /* Display Latch 0, 32 bits */
+
+#define VI_DL1			0x44 /* Display Latch 1, 32 bits */
+
+#define VI_PCR			0x48 /* Picture Configuration, 16 bits */
+__vi_reg_field(u16, pcr, u8, wpl, 0xff, 8);	/* reads per line in words */
+__vi_reg_field(u16, pcr, u8, std, 0xff, 0);	/* stride per line in words */
+
+#define VI_HSR			0x4a /* Horizontal Scaling, 16 bits */
+__vi_reg_field(u16, hsr, u8, hs_en, 0x1, 12);
+__vi_reg_field(u16, hsr, u16, stp, 0x1ff, 0);
+
+#define VI_FCT0			0x4c /* Filter Coeficient Table 0, 32 bits */
+#define VI_FCT1			0x50 /* Filter Coeficient Table 1, 32 bits */
+#define VI_FCT2			0x54 /* Filter Coeficient Table 2, 32 bits */
+#define VI_FCT3			0x58 /* Filter Coeficient Table 3, 32 bits */
+#define VI_FCT4			0x5c /* Filter Coeficient Table 4, 32 bits */
+#define VI_FCT5			0x60 /* Filter Coeficient Table 5, 32 bits */
+#define VI_FCT6			0x64 /* Filter Coeficient Table 6, 32 bits */
+
+#define VI_AA			0x68 /* Anti-aliasing, 32 bits */
+
+#define VI_CLK			0x6c /* Video Clock, 16 bits */
+__vi_reg_field(u16, clk, u8, _54mhz, 0x1, 0);
+
+#define VI_SEL			0x6e /* DTV Status, 16 bits */
+__vi_reg_field(u16, sel, u8, component, 0x1, 0);
+
+#define VI_HSW			0x70 /* Horizontal Scaling Width, 16 bits */
+__vi_reg_field(u16, hsw, u16, width, 0x3ff, 0);
+
+#define VI_HBE			0x72 /* Horizontal Border End, 16 bits */
+#define VI_HBS			0x74 /* Horizontal Border Start, 16 bits */
+
+#define VI_UNK1			0x76 /* Unknown1, 16 bits */
+#define VI_UNK2			0x78 /* Unknown2, 32 bits */
+#define VI_UNK3			0x7c /* Unknown3, 32 bits */
+
+
+enum {
+	VI_SCAN_DONTCARE = 0,
+	VI_SCAN_INTERLACED,
+	VI_SCAN_PROGRESSIVE,
+};
+enum {
+	VI_RATE_DONTCARE = 0,
+	VI_RATE_50Hz,
+	VI_RATE_60Hz,
+};
+enum {
+	VI_TV_DONTCARE = 0,
+	VI_TV_NTSC,
+	VI_TV_PAL,
+};
+
+
+/*
+ * Video modes and timings.
+ *
+ */
+
+enum {
+	VI_VM_NTSC_480i = 0,
+	VI_VM_NTSC_480p,
+	VI_VM_PAL_576i50,
+	VI_VM_PAL_480i60,
+	VI_VM_PAL_480p,
+};
+
+enum vi_video_format {
+	VI_FMT_NTSC = 0,
+	VI_FMT_PAL,
+	VI_FMT_MPAL,
+	VI_FMT_DEBUG,
+};
+
+enum vi_tv_mode_flags {
+	__PAL_COLOR,	/* vs NTSC_COLOR */
+	__PROGRESSIVE,	/* vs interlaced */
+};
+
+#define VI_VMF_PAL_COLOR	(1<<__PAL_COLOR)
+#define VI_VMF_PROGRESSIVE	(1<<__PROGRESSIVE)
+
+
+#define VI_VERT_ALIGN		0x1	/* in lines-1 */
+#define VI_HORZ_ALIGN		0xf	/* in pixels-1 */
+#define VI_HORZ_WORD_SIZE	32	/* bytes */
+
+
+/*
+ * Video mode timings.
+ */
+struct vi_mode_timings {
+	/* VERTICAL SETTINGS */
+
+	/*
+	 * NTSC 480i
+	 * 1 field = 262.5 lines (242.5 active, 20 blank)
+	 * 1 frame = 2 fields = 2 x 262.5 = 525 lines (485 active, 40 blank)
+	 *
+	 * PAL 576i
+	 * 1 field = 312.5 lines (287.5 active, 25 blank)
+	 * 1 frame = 2 fields = 2 x 312.5 = 625 lines (575 active, 50 blank)
+	 *
+	 * NOTES:
+	 * - the start of sync is considered the start of a line
+	 * - the width of a half line is the width of a line divided by two
+	 *
+	 */
+
+	/*
+	 * Vertical position of the first active video line (0=top).
+	 */
+	unsigned int ypos;
+
+	/*
+	 * Horizontal position in pixels where the vertical blanking
+	 * interval starts. Used for signaling the start of the vertical
+	 * retrace.
+	 */
+	unsigned int htrap;
+
+	/*
+	 * Vertical position in field lines where the vertical blanking
+	 * interval starts. Used for signaling the start of the vertical
+	 * retrace.
+	 */
+	unsigned int vtrap;
+
+	/*
+	 * Active Video, specified in number of field lines.
+	 */
+	u16	acv;
+	/*
+	 * Equalization pulse, specified in number of half lines.
+	 */
+	u8	equ;
+
+	/*
+	 * Pre-blanking, specified in half lines.
+	 */
+	u16	prb_odd;
+	u16	prb_even;
+
+	/*
+	 * Post-blanking, specified in half lines.
+	 */
+	u16	psb_odd;
+	u16	psb_even;
+
+	/*
+	 * NOTE:
+	 * Irrespective of what patent 6,609,977 says:
+	 * - "bs*" seems to tell where the burst blanking for the current
+	 *   field ends
+	 * - "be*" seems to tell where the next burst blanking starts
+	 */
+
+	/*
+	 * Patent says: "Start to burst blanking start in half lines".
+	 */
+	u8	bs1;
+	u8	bs2;
+	u8	bs3;
+	u8	bs4;
+
+	/*
+	 * Patent says: "Start to burst blanking end in half lines".
+	 */
+	u16	be1;
+	u16	be2;
+	u16	be3;
+	u16	be4;
+
+	/* HORIZONTAL SETTINGS */
+
+	/*
+	 * A = Blank Start to Horizontal Sync Start, "Front Porch"
+	 *     right_margin
+	 * B = Horizontal Sync Width
+	 *     hsync_len
+	 * C = Horizontal Sync End to Blank End, "Back Porch"
+	 *     left_margin
+	 * D = Horizontal Line Width
+	 *     hsync_len + left_margin + xres + right_margin
+	 * E = Horizontal Visible Width
+	 *     xres
+	 *
+	 *               :<-----------------D----------------->:
+	 *           :   :     :     :<----------E-------->:   :
+	 *           :<A>:<-B->:<-C->:                     :<A>:<-B->:<-C->:
+	 *           :   :     :     :                     :   :     :     :
+	 *        ___                 __________//_________                 __
+	 *           |               |                     |               |
+	 *           |               |                     |               |
+	 * Blank     |___       _____|                     |___       _____|
+	 *               |     |                               |     |
+	 * Sync          |_____|                               |_____|
+	 *
+	 *
+	 * f = Sync Start to Color Burst Start
+	 * g = Color Burst Width
+	 *
+	 *  :       :             :                  :
+	 *  :<--A-->:<-----B----->:<-------C-------->:
+	 *  :       :             :                  :
+	 *                                             _ Peak white level
+	 *  |                            Color       |
+	 *  |                            Burst       |
+	 *  |_______               ______|||||||||___| _ Blanking level
+	 *          | Sync        |      |||||||||
+	 *          |_____________|                    _ Sync level
+	 *
+	 *  :       :                    :       :   :
+	 *  :       :<---------f-------->:<--g-->:   :
+	 *  :<--------------- A + B + C ------------>:
+	 *  :                                        :
+	 *
+	 */
+
+	/* Half (horizontal) line width, in pixel clocks (D/2)  */
+	u16 hlw;
+
+	/* Horizontal Sync Width, in pixel clocks (B) */
+	u8 hsy;
+
+	/* NOTE
+	 * The color burst interval falls within the back porch,
+	 * i.e. hcs must be greater than B and hce lower than B+C.
+	 */
+
+	/* Horizontal sync start to color burst start in pixel clocks (f) */
+	u8 hcs;
+	/* Horizontal sync start to color burst end in pixel clocks (f+g) */
+	u8 hce;
+
+	/*
+	 * The following two settings depend on the effective horizontal
+	 * line length, as they rely on A or C.
+	 */
+
+	/* Half line to horizontal blank start (D/2 - A)*/
+	u16 hbs;
+
+	/* Horizontal sync start to horizontal blank end (B+C)*/
+	u16 hbe;
+
+};
+
+/*
+ * TV mode.
+ */
+struct vi_tv_mode {
+	char *name;
+	__u32 flags;
+	int width;		/* visible width in pixels */
+	int height;		/* visible height in lines */
+	int lines;		/* total lines */
+};
+
+/*
+ * Video control data structure.
+ */
+struct vi_ctl {
+	spinlock_t lock;
+
+	void __iomem *io_base;
+	unsigned int irq;
+
+	int in_vtrace;
+	wait_queue_head_t vtrace_waitq;
+
+	int visible_page;
+	unsigned long page_address[2];
+	unsigned long flip_pending;
+
+	struct vi_tv_mode *mode;
+	struct vi_mode_timings timings;
+	int has_component_cable:1;	/* at last detection time */
+
+	struct fb_info *info;
+#ifdef CONFIG_WII_AVE_RVL
+	struct i2c_client *i2c_client;
+#endif
+};
+
+
+/*
+ * TV Mode Table
+ */
+static struct vi_tv_mode vi_tv_modes[] = {
+	[VI_VM_NTSC_480i] = {
+		.name = "NTSC 480i",
+		.width = 640,
+		.height = 480,
+		.lines = 525,
+	},
+	[VI_VM_NTSC_480p] = {
+		.name = "NTSC 480p",
+		.flags = VI_VMF_PROGRESSIVE,
+		.width = 640,
+		.height = 480,
+		.lines = 525,
+	},
+	[VI_VM_PAL_576i50] = {
+		.name = "PAL 576i",
+		.flags = VI_VMF_PAL_COLOR,
+		.width = 640,
+		.height = 574,
+		.lines = 625,
+	},
+	[VI_VM_PAL_480i60] = {
+		.name = "PAL 480i 60Hz",
+		.flags = VI_VMF_PAL_COLOR,
+		.width = 640,
+		.height = 480,
+		.lines = 525,
+	},
+	[VI_VM_PAL_480p] = {
+		.name = "PAL 480p",
+		.flags = VI_VMF_PROGRESSIVE|VI_VMF_PAL_COLOR,
+		.width = 640,
+		.height = 480,
+		.lines = 525,
+	},
+};
+
+/*
+ * Filter Coeficient Table
+ */
+static const u32 vi_fct[] = {
+	0x1AE771F0, 0x0DB4A574, 0x00C1188E, 0xC4C0CBE2,
+	0xFCECDECF, 0x13130F08, 0x00080C0F,
+};
+
+
+/*
+ * Default fix and var framebuffer data.
+ */
+static struct fb_fix_screeninfo vifb_fix __devinitdata = {
+	.id = DRV_MODULE_NAME,
+	.type = FB_TYPE_PACKED_PIXELS,
+	.visual = FB_VISUAL_TRUECOLOR,	/* lies, lies, lies, ... */
+	.accel = FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo vifb_var = {
+	.activate = FB_ACTIVATE_NOW,
+	.width = 640,
+	.height = 480,
+	.bits_per_pixel = 16,
+	.vmode = FB_VMODE_INTERLACED,
+};
+
+
+/*
+ * Setup parameters.
+ */
+static int want_ypan = 1;		/* 0..nothing, 1..ypan */
+
+/* use old behaviour for video mode settings */
+static int nostalgic;
+
+static int force_scan;
+static int force_rate;
+static int force_tv;
+
+static u32 pseudo_palette[17];
+
+/*
+ * fb_start: addr of the physical fb
+ * fb_mem:   virt (mapped) addr of physical fb
+ * fb_size:  size of physical fb
+ */
+static unsigned long fb_start;
+static void *fb_mem;
+static unsigned int fb_size;
+
+/*
+ *
+ *
+ */
+
+#ifdef CONFIG_WII_AVE_RVL
+static int vi_ave_setup(struct vi_ctl *ctl);
+static int vi_ave_get_video_format(struct vi_ctl *ctl,
+				   enum vi_video_format *fmt);
+#endif
+
+/* some glue to the gx side */
+static inline void gcngx_dispatch_vtrace(struct vi_ctl *ctl)
+{
+}
+
+
+/*
+ *
+ * Color space handling.
+ */
+
+/*
+ * RGB to YCbYCr conversion support bits.
+ * We are using here the ITU.BT-601 Y'CbCr standard.
+ *
+ * References:
+ * - "Colour Space Conversions" by Adrian Ford and Alan Roberts, 1998
+ *   (google for coloureq.pdf)
+ *
+ */
+
+#define RGB2YUV_SHIFT   16
+#define RGB2YUV_LUMA    16
+#define RGB2YUV_CHROMA 128
+
+#define Yr ((int)(0.299 * (1<<RGB2YUV_SHIFT)))
+#define Yg ((int)(0.587 * (1<<RGB2YUV_SHIFT)))
+#define Yb ((int)(0.114 * (1<<RGB2YUV_SHIFT)))
+
+#define Ur ((int)(-0.169 * (1<<RGB2YUV_SHIFT)))
+#define Ug ((int)(-0.331 * (1<<RGB2YUV_SHIFT)))
+#define Ub ((int)(0.500 * (1<<RGB2YUV_SHIFT)))
+
+#define Vr ((int)(0.500 * (1<<RGB2YUV_SHIFT)))	/* same as Ub */
+#define Vg ((int)(-0.419 * (1<<RGB2YUV_SHIFT)))
+#define Vb ((int)(-0.081 * (1<<RGB2YUV_SHIFT)))
+
+/*
+ * Converts two 16bpp rgb pixels into a dual yuy2 pixel.
+ */
+static inline uint32_t rgbrgb16toycbycr(uint32_t rgb1rgb2)
+{
+	uint16_t rgb1 = rgb1rgb2 >> 16, rgb2 = rgb1rgb2 & 0xFFFF;
+	register int Y1, Cb, Y2, Cr;
+	register int r1, g1, b1;
+	register int r2, g2, b2;
+	register int r, g, b;
+
+	/* fast path, thanks to bohdy */
+	if (!(rgb1 | rgb2))
+		return 0x00800080;	/* black, black */
+
+	/* RGB565 */
+	r1 = ((rgb1 >> 11) & 0x1f);
+	g1 = ((rgb1 >> 5) & 0x3f);
+	b1 = ((rgb1 >> 0) & 0x1f);
+
+	/* fast (approximated) scaling to 8 bits, thanks to Masken */
+	r1 = (r1 << 3) | (r1 >> 2);
+	g1 = (g1 << 2) | (g1 >> 4);
+	b1 = (b1 << 3) | (b1 >> 2);
+
+	Y1 = clamp(((Yr * r1 + Yg * g1 + Yb * b1) >> RGB2YUV_SHIFT)
+		   + RGB2YUV_LUMA, 16, 235);
+	if (rgb1 == rgb2) {
+		/* this is just another fast path */
+		Y2 = Y1;
+		r = r1;
+		g = g1;
+		b = b1;
+	} else {
+		/* same as we did for r1 before */
+		r2 = ((rgb2 >> 11) & 0x1f);
+		g2 = ((rgb2 >> 5) & 0x3f);
+		b2 = ((rgb2 >> 0) & 0x1f);
+		r2 = (r2 << 3) | (r2 >> 2);
+		g2 = (g2 << 2) | (g2 >> 4);
+		b2 = (b2 << 3) | (b2 >> 2);
+
+		Y2 = clamp(((Yr * r2 + Yg * g2 + Yb * b2) >> RGB2YUV_SHIFT)
+			   + RGB2YUV_LUMA,
+			   16, 235);
+
+		r = (r1 + r2) / 2;
+		g = (g1 + g2) / 2;
+		b = (b1 + b2) / 2;
+	}
+
+	Cb = clamp(((Ur * r + Ug * g + Ub * b) >> RGB2YUV_SHIFT)
+		   + RGB2YUV_CHROMA, 16, 240);
+	Cr = clamp(((Vr * r + Vg * g + Vb * b) >> RGB2YUV_SHIFT)
+		   + RGB2YUV_CHROMA, 16, 240);
+
+	return (((uint8_t) Y1) << 24) | (((uint8_t) Cb) << 16) |
+	    (((uint8_t) Y2) << 8) | (((uint8_t) Cr) << 0);
+}
+
+
+/*
+ * Video mode timings calculation.
+ *
+ * Please, refer to the definition of "struct vi_mode_timings" for
+ * a explanation of the different constants involved.
+ *
+ * References:
+ * - http://www.pembers.freeserve.co.uk/World-TV-Standards
+ */
+
+static inline int vi_vmode_is_progressive(__u32 vmode)
+{
+	return (vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED;
+}
+
+static int vi_calc_horz_timings(struct vi_mode_timings *timings,
+				 struct fb_var_screeninfo *var,
+				 u16 width, u16 max_active_width,
+				 u16 A, u8 B, u16 C, u16 D,
+				 u8 f, u16 g)
+{
+	u16 extra_blanking, margin;
+
+	if (width > max_active_width)
+		return -EINVAL;
+
+	/* adjusted horizontal settings */
+	extra_blanking = max_active_width - width;
+	margin = extra_blanking / 2;
+	A += margin;
+	C += extra_blanking - margin;
+
+	timings->hlw = D / 2;
+	timings->hsy = B;
+	timings->hcs = f;
+	timings->hce = f + g;
+	timings->hbs = (D/2) - A;
+	timings->hbe = B + C;
+
+	/*
+	 * Start of the blanking interval, between the first and second fields,
+	 * begins after the last half line of the field.
+	 */
+	timings->htrap = (D / 2) + 1;
+
+	var->left_margin = C;
+	var->right_margin = A;
+	var->hsync_len = B;
+
+	return 0;
+}
+
+static int vi_ntsc_525_calc_horz_timings(struct vi_mode_timings *timings,
+					  struct fb_var_screeninfo *var,
+					  u16 width)
+{
+	u16 max_active_width;
+	u16 A, C, D, g;
+	u8 B, f;
+
+	/* standard horizontal settings for 714 pixels */
+	D = 858;		/* pixel clocks (H=63.556us, 13.5MHz clock) */
+	max_active_width = 714;	/* (52.9us) 714.15 pixel clocks */
+	B = 64;			/* ( 4.7us)  63.45 pixel clocks */
+	f = 71;			/* ( 5.3us)  71.55 pixel clocks */
+	g = 34;			/* ( 2.5us)  33.75 pixel clocks */
+	A = 20;			/* ( 1.5us)  20.25 pixel clocks */
+	C = 60;			/* ( 4.5us)  60.75 pixel clocks */
+
+	return vi_calc_horz_timings(timings, var, width, max_active_width,
+				    A, B, C, D, f, g);
+}
+
+static int vi_calc_vert_timings(struct vi_mode_timings *timings,
+				struct fb_var_screeninfo *var,
+				u16 height, u16 max_active_height,
+				u16 P, u16 Q, u8 equ)
+{
+	u16 extra_blanking, margin, prb, psb;
+	u8 interlace_bias;
+	u8 shift;
+
+	if (height > max_active_height)
+		return -EINVAL;
+
+	extra_blanking = max_active_height - height;	/* in frame lines */
+	margin = extra_blanking / 2;			/* centered margins */
+	prb = margin; 					/* in half lines */
+	psb = extra_blanking - margin;			/* in half lines */
+
+	/*
+	 * Start of the blanking interval, between the first and second fields,
+	 * begins after the last line of the field.
+	 */
+	if (vi_vmode_is_progressive(var->vmode)) {
+		timings->acv = height;
+		timings->vtrap = prb + height;
+		interlace_bias = 0;
+		shift = 1;
+	} else {
+		timings->acv = height / 2;
+		timings->vtrap = (prb + height) / 2;
+		interlace_bias = 1;
+		shift = 0;
+	}
+
+	timings->equ = equ << shift;
+	var->vsync_len = (3 * timings->equ) / 2; /* pre-eq + sync + post-eq */
+
+	/*
+	 * prb_* is specified as the number of half-lines since the end of
+	 * the post-equalizing period.
+	 * psb_* is specified as the number of half-lines from the end of
+	 * the field.
+	 */
+
+	timings->ypos = margin;
+
+	if (timings->ypos & 0x01) {
+		/* odd field (1,3,5,...) */
+		timings->prb_odd = (P + interlace_bias + prb) << shift;
+		timings->psb_odd = (Q - interlace_bias + psb) << shift;
+		timings->prb_even = (P + prb) << shift;
+		timings->psb_even = (Q + psb) << shift;
+	} else {
+		/* even field (2,4,6,...) */
+		timings->prb_even = (P + interlace_bias + prb) << shift;
+		timings->psb_even = (Q - interlace_bias + psb) << shift;
+		timings->prb_odd = (P + prb) << shift;
+		timings->psb_odd = (Q + psb) << shift;
+	}
+
+	var->upper_margin = (Q + prb) / 2;
+	var->lower_margin = (P + psb) / 2;
+
+	return 0;
+}
+
+static int vi_ntsc_525_calc_vert_timings(struct vi_mode_timings *timings,
+					 struct fb_var_screeninfo *var,
+					 u16 height)
+{
+	u16 max_active_height;
+	u16 P, Q;
+	u8 equ;
+
+	/* standard vertical settings for 484 active lines */
+	max_active_height = 484;	/* 2 * 242.5 = 485 (*1) */
+
+	/* blanking interval */
+	/* from start of line 10, field 1 to end of line 20, field 1 */
+	P = 2 * (20-10 + 1);
+	Q = 1;	/* (*1) field line compensation for 484 vs 485 lines */
+
+	equ = 2 * 3;	/* 3 lines of equalization */
+
+	return vi_calc_vert_timings(timings, var, height, max_active_height,
+				    P, Q, equ);
+}
+
+static int vi_pal_625_calc_timings(struct vi_mode_timings *timings,
+				   struct fb_var_screeninfo *var,
+				   unsigned int width, unsigned int height)
+{
+	u16 max_active_height, max_active_width;
+	u16 A, C, D, g, P, Q;
+	u8 B, f, equ;
+	int error;
+
+	/* standard horizontal settings for 702 pixels */
+	D = 864;		/* pixel clocks (H=64us, 13.5MHz clock) */
+	max_active_width = 702; /* (51.95us) 701.32 pixel clocks */
+	B = 64;			/* ( 4.7us)   63.45 pixel clocks */
+	f = 75;			/* ( 5.6us)   75.6  pixel clocks */
+	g = 30;			/* ( 2.25us)  30.38 pixel clocks */
+	A = 22;			/* ( 1.65us)  22.27 pixel clocks */
+	C = 76;			/* ( 5.7us)   76.95 pixel clocks */
+
+	error = vi_calc_horz_timings(timings, var, width, max_active_width,
+				     A, B, C, D, f, g);
+	if (error)
+		goto err_out;
+
+	/* standard vertical settings for 574 active lines */
+	max_active_height = 574;	/* 2 * 287.5 = 575 (*1) */
+
+	/* blanking interval */
+	/* from start of line 6, field 1 to mid of line 23, field 1 */
+	P = (2 * (23-6 + 1)) - 1;
+	Q = 1;	/* (*1) field line compensation for 574 vs 575 lines */
+
+	equ = 2 * 2.5;		/* 2.5 lines of equalization */
+
+	error = vi_calc_vert_timings(timings, var, height, max_active_height,
+				     P, Q, equ);
+	if (error)
+		goto err_out;
+
+	/*
+	 * Location of the 9 lines of burst blanking for each field
+	 * (settings expressed in half lines).
+	 */
+
+	/* from start of line 1, field 1 to end of line 6, field 1 */
+	timings->bs1 = 2 * (6-1 + 1);
+
+	/* from start of line 1, field 1 to end of line 309, field 2 */
+	timings->be1 = 2 * (309-1 + 1);
+
+	/* from mid of line 313, field 2 to end of line 318, field 2 */
+	timings->bs2 = (2 * (318-313 + 1)) - 1;
+
+	/* from mid of line 313, field 2 to end of line 621, field 2 */
+	timings->be2 = (2 * (612-617 + 1)) - 1;
+
+	/* from start of line 1, field 3 to end of line 5, field 3 */
+	timings->bs3 = 2 * (5-1 + 1);
+
+	/* from start of line 1, field 3 to end of line 310, field 4 */
+	timings->be3 = 2 * (310-1 + 1);
+
+	/* from mid of line 313, field 4 to end of line 319, field 4 */
+	timings->bs4 = (2 * (319-313 + 1)) - 1;
+
+	/* from mid of line 313, field 4 to end of line 622, field 4 */
+	timings->be4 = (2 * (622-313 + 1)) - 1;
+
+err_out:
+	return error;
+}
+
+static int vi_ntsc_525_calc_timings(struct vi_mode_timings *timings,
+				    struct fb_var_screeninfo *var,
+				    unsigned int width, unsigned int height)
+{
+	int error;
+
+	error = vi_ntsc_525_calc_horz_timings(timings, var, width);
+	if (error)
+		goto err_out;
+
+	error = vi_ntsc_525_calc_vert_timings(timings, var, height);
+	if (error)
+		goto err_out;
+
+	/*
+	 * Location of the 9 lines of burst blanking for each field
+	 * (settings expressed in half lines).
+	 */
+
+	/* from start of line 4, field 1 to end of line 9, field 1 */
+	timings->bs1 = 2 * (9-4 + 1);
+
+	/* from start of line 4, field 1 to end of line 263, field 2 */
+	timings->be1 = 2 * (263-4 + 1);
+
+	/* from mid of line 266, field 2 to end of line 272, field 2 */
+	timings->bs2 = (2 * (272-266 + 1)) - 1;
+
+	/* from mid of line 266, field 2 to end of line 525, field 2 */
+	timings->be2 = (2 * (525-266 + 1)) - 1;
+
+	/* from start of line 4, field 3 to end of line 9, field 3 */
+	timings->bs3 = 2 * (9-4 + 1);
+
+	/* from start of line 4, field 3 to end of line 263, field 4 */
+	timings->be3 = 2 * (263-4 + 1);
+
+	/* from mid of line 266, field 4 to end of line 272, field 4 */
+	timings->bs4 = (2 * (272-266 + 1)) - 1;
+
+	/* from mid of line 266, field 4 to end of line 525, field 4 */
+	timings->be4 = (2 * (525-266 + 1)) - 1;
+
+err_out:
+	return error;
+}
+
+static int vi_ntsc_525_prog_calc_timings(struct vi_mode_timings *timings,
+					 struct fb_var_screeninfo *var,
+					 unsigned int width,
+					 unsigned int height)
+{
+	int error;
+
+	error = vi_ntsc_525_calc_horz_timings(timings, var, width);
+	if (error)
+		goto err_out;
+
+	error = vi_ntsc_525_calc_vert_timings(timings, var, height);
+	if (error)
+		goto err_out;
+
+	/*
+	 * Location of the 18 lines of burst blanking
+	 * (settings expressed in half lines).
+	 */
+
+	/*
+	 * |0 0 0 0 0 0|0 0 0 1 1 1|1 1 1 1 1 1|
+	 * |1,2,3,4,5,6|7,8,9,0,1,2|3,4,5,6,7,8|
+	 * :pre-equ    :sync       : post-equ  :
+	 */
+
+	/* from start of line 7 to end of line 18 */
+	timings->bs1 = 2 * (18-7 + 1);
+	timings->bs2 = timings->bs3 = timings->bs4 = timings->bs1;
+
+	/* from start of line 7 to end of line 525 (last) */
+	timings->be1 = 2 * (525-7 + 1);
+	timings->be2 = timings->be3 = timings->be4 = timings->be1;
+
+err_out:
+	return error;
+}
+
+
+
+/*
+ * Video hardware support.
+ *
+ */
+
+static inline int vi_has_component_cable(struct vi_ctl *ctl)
+{
+	return vi_sel_get_component(in_be16(ctl->io_base + VI_SEL));
+}
+
+/*
+ * Get video mode reported by hardware.
+ * 0=NTSC, 1=PAL, 2=MPAL, 3=debug
+ */
+static inline enum vi_video_format vi_get_video_format(struct vi_ctl *ctl)
+{
+	return vi_dcr_get_fmt(in_be16(ctl->io_base + VI_DCR));
+}
+
+static inline int vi_video_format_is_ntsc(struct vi_ctl *ctl)
+{
+	return vi_get_video_format(ctl) == VI_FMT_NTSC;
+}
+
+static void vi_reset_video(struct vi_ctl *ctl)
+{
+	void __iomem *io_base = ctl->io_base;
+	u16 dcr;
+
+	dcr = in_be16(io_base + VI_DCR);
+	out_be16(io_base + VI_DCR, vi_dcr_set_rst(dcr, 1));
+	out_be16(io_base + VI_DCR, vi_dcr_clear_rst(dcr));
+}
+
+/*
+ * Try to determine current TV video mode.
+ */
+static void vi_detect_tv_mode(struct vi_ctl *ctl)
+{
+	struct vi_tv_mode *modes = vi_tv_modes, *mode;
+	void __iomem *io_base = ctl->io_base;
+	char *guess = "";
+	enum vi_video_format fmt;
+	int ntsc_idx, pal_idx;
+	u16 dcr;
+	int error;
+
+	dcr = in_be16(io_base + VI_DCR);
+
+	ctl->has_component_cable = vi_has_component_cable(ctl);
+
+	if ((force_scan == VI_SCAN_PROGRESSIVE &&
+					ctl->has_component_cable) ||
+	    (force_scan != VI_SCAN_INTERLACED &&
+					ctl->has_component_cable &&
+					vi_dcr_get_nin(dcr))) {
+		/* progressive modes */
+		ntsc_idx = VI_VM_NTSC_480p;
+		pal_idx = VI_VM_PAL_480p;
+	} else {
+		/* interlaced modes */
+		ntsc_idx = VI_VM_NTSC_480i;
+		if (force_rate == VI_RATE_50Hz ||
+		    (force_rate != VI_RATE_60Hz &&
+		     vi_dcr_get_fmt(dcr) == VI_FMT_PAL))
+			pal_idx = VI_VM_PAL_576i50;
+		else
+			pal_idx = VI_VM_PAL_480i60;
+	}
+
+	if (force_tv == VI_TV_PAL ||
+	    (force_tv != VI_TV_NTSC && pal_idx == VI_VM_PAL_576i50))
+		fmt = VI_FMT_PAL;
+	else if (force_tv == VI_TV_NTSC)
+		fmt = VI_FMT_NTSC;
+	else {
+#ifdef CONFIG_WII_AVE_RVL
+		/*
+		 * Look at the audio/video encoder to detect true PAL vs NTSC.
+		 */
+		error = vi_ave_get_video_format(ctl, &fmt);
+		if (error) {
+			guess = " (initial guess)";
+			if (force_tv == VI_TV_PAL ||
+			    pal_idx == VI_VM_PAL_576i50)
+				fmt = VI_FMT_PAL;
+			else
+				fmt = VI_FMT_NTSC;
+		}
+#else
+		error = 0;
+		fmt = vi_get_video_format(ctl);
+#endif
+	}
+	switch (fmt) {
+	case VI_FMT_PAL:
+		mode = modes + pal_idx;
+		break;
+	case VI_FMT_MPAL:
+	case VI_FMT_DEBUG:
+		/* we currently don't support MPAL or DEBUG, sorry */
+		/* FALLTHROUGH */
+	case VI_FMT_NTSC:
+	default:
+		mode = modes + ntsc_idx;
+		break;
+	}
+
+	ctl->mode = mode;
+
+	drv_printk(KERN_INFO, "%s%s\n", mode->name, guess);
+}
+
+/*
+ * Initialize the video hardware for a given TV mode.
+ */
+static int vi_setup_tv_mode(struct vi_ctl *ctl)
+{
+	void __iomem *io_base = ctl->io_base;
+	struct vi_mode_timings *timings = &ctl->timings;
+	struct fb_var_screeninfo *var = &ctl->info->var;
+	unsigned int bytes_per_pixel = var->bits_per_pixel / 8;
+	struct vi_tv_mode *mode;
+	int has_component_cable;
+	u16 std, ppl;
+
+	/* we need to re-detect the tv mode if the cable type changes */
+	has_component_cable = vi_has_component_cable(ctl);
+	if ((ctl->has_component_cable && !has_component_cable) ||
+	    (!ctl->has_component_cable && has_component_cable))
+		vi_detect_tv_mode(ctl);
+
+	mode = ctl->mode;
+
+	out_be16(io_base + VI_DCR,
+		 vi_dcr_fmt((mode->lines == 625) ? VI_FMT_PAL : VI_FMT_NTSC) |
+		 vi_dcr_nin((mode->flags & VI_VMF_PROGRESSIVE) ?  1 : 0) |
+		 vi_dcr_enb(1));
+
+	out_be16(io_base + VI_VTR,
+		 vi_vtr_equ(timings->equ) | vi_vtr_acv(timings->acv));
+
+	out_be32(io_base + VI_HTR0,
+		 vi_htr0_hcs(timings->hcs) | vi_htr0_hce(timings->hce) |
+		 vi_htr0_hlw(timings->hlw));
+
+	out_be32(io_base + VI_HTR1,
+		 vi_htr1_hbs(timings->hbs) | vi_htr1_hbe(timings->hbe) |
+		 vi_htr1_hsy(timings->hsy));
+
+	out_be32(io_base + VI_VTO,
+		 vi_vto_prb(timings->prb_odd) | vi_vto_psb(timings->psb_odd));
+
+	out_be32(io_base + VI_VTE,
+		 vi_vte_prb(timings->prb_even) | vi_vte_psb(timings->psb_even));
+
+	out_be32(io_base + VI_BBOI,
+		 vi_bboi_bs1(timings->bs1) | vi_bboi_be1(timings->be1) |
+		 vi_bboi_bs3(timings->bs3) | vi_bboi_be3(timings->be3));
+
+	out_be32(io_base + VI_BBEI,
+		 vi_bbei_bs2(timings->bs2) | vi_bbei_be2(timings->be2) |
+		 vi_bbei_bs4(timings->bs4) | vi_bbei_be4(timings->be4));
+
+	/* used only for 3D stuff */
+	out_be32(io_base + VI_TFBR, 0);
+	out_be32(io_base + VI_BFBR, 0);
+
+	std = (var->xres_virtual * bytes_per_pixel) / VI_HORZ_WORD_SIZE;
+	if (!(mode->flags & VI_VMF_PROGRESSIVE))
+		std *= 2;
+	ppl = _ALIGN_UP((var->xoffset & VI_HORZ_ALIGN) + var->xres,
+			VI_HORZ_ALIGN+1);
+	out_be16(io_base + VI_PCR,
+		 vi_pcr_std(std) |
+		 vi_pcr_wpl((ppl * bytes_per_pixel) / VI_HORZ_WORD_SIZE));
+
+	/* scaler is disabled */
+	out_be16(io_base + VI_HSR, vi_hsr_stp(256) | vi_hsr_hs_en(0));
+
+	/* filter coeficient table, anti-aliasing */
+	out_be32(io_base + VI_FCT0, vi_fct[0]);
+	out_be32(io_base + VI_FCT1, vi_fct[1]);
+	out_be32(io_base + VI_FCT2, vi_fct[2]);
+	out_be32(io_base + VI_FCT3, vi_fct[3]);
+	out_be32(io_base + VI_FCT4, vi_fct[4]);
+	out_be32(io_base + VI_FCT5, vi_fct[5]);
+	out_be32(io_base + VI_FCT6, vi_fct[6]);
+	out_be32(io_base + VI_AA, 0x00ff0000);
+
+	/* clock */
+	out_be16(io_base + VI_CLK,
+		 vi_clk__54mhz((mode->flags & VI_VMF_PROGRESSIVE) ? 1 : 0));
+
+	/* superfluous, no scaler */
+	out_be16(io_base + VI_HSW, vi_hsw_width(var->xres));
+
+	/* borders for DEBUG mode encoder, not used in retail consoles */
+	out_be16(io_base + VI_HBE, 0);
+	out_be16(io_base + VI_HBS, 0);
+
+	/* whatever */
+	out_be16(io_base + VI_UNK1, 0x00ff);
+	out_be32(io_base + VI_UNK2, 0x00ff00ff);
+	out_be32(io_base + VI_UNK3, 0x00ff00ff);
+
+#ifdef CONFIG_WII_AVE_RVL
+	vi_ave_setup(ctl);
+#endif
+
+	return 0;
+}
+
+/*
+ * Set the address from where the video encoder will display data on screen.
+ */
+void vi_set_framebuffer(struct vi_ctl *ctl, u32 addr)
+{
+	struct fb_info *info = ctl->info;
+	void __iomem *io_base = ctl->io_base;
+	u32 top, bot;
+	u8 xof;
+
+	top = bot = addr;
+	if (!vi_vmode_is_progressive(info->var.vmode)) {
+		if (ctl->timings.ypos & 0x01)
+			top += info->fix.line_length;
+		else
+			bot += info->fix.line_length;
+	}
+	xof = (top / 2) & VI_HORZ_ALIGN;
+
+	out_be32(io_base + VI_TFBL,
+		 vi_tfbl_pob(1) | vi_tfbl_xof(xof) | vi_tfbl_fba(top >> 5));
+	out_be32(io_base + VI_BFBL, vi_bfbl_pob(1) | vi_bfbl_fba(bot >> 5));
+}
+
+/*
+ * Swap the visible and back pages.
+ */
+static inline void vi_flip_page(struct vi_ctl *ctl)
+{
+	ctl->visible_page ^= 1;
+	vi_set_framebuffer(ctl, ctl->page_address[ctl->visible_page]);
+
+	ctl->flip_pending = 0;
+}
+
+static void vi_enable_interrupts(struct vi_ctl *ctl, int enable)
+{
+	void __iomem *io_base = ctl->io_base;
+
+	if (enable) {
+		/*
+		 * We use DI0 and DI1 to signal the retrace interval.
+		 */
+
+		/* start of the vertical retrace */
+		out_be32(io_base + VI_DI1,
+			 vi_dix_irq(1) | vi_dix_enb(1) |
+			 vi_dix_vct(ctl->timings.vtrap) |
+			 vi_dix_hct(ctl->timings.htrap));
+
+		/* end of the vertical retrace */
+		out_be32(io_base + VI_DI0,
+			 vi_dix_irq(1) | vi_dix_enb(1) |
+			 vi_dix_vct(1) |
+			 vi_dix_hct(1));
+	} else {
+		out_be32(io_base + VI_DI0, 0);
+		out_be32(io_base + VI_DI1, 0);
+	}
+	/* these two are currently not used */
+	out_be32(io_base + VI_DI2, 0);
+	out_be32(io_base + VI_DI3, 0);
+}
+
+static void vi_dispatch_vtrace(struct vi_ctl *ctl)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctl->lock, flags);
+	if (ctl->flip_pending)
+		vi_flip_page(ctl);
+	spin_unlock_irqrestore(&ctl->lock, flags);
+
+	wake_up_interruptible(&ctl->vtrace_waitq);
+}
+
+static irqreturn_t vi_irq_handler(int irq, void *dev)
+{
+	struct fb_info *info = dev_get_drvdata((struct device *)dev);
+	struct vi_ctl *ctl = info->par;
+	void __iomem *io_base = ctl->io_base;
+	u32 val;
+
+	/* DI0 and DI1 are used to account for the vertical retrace */
+	val = in_be32(io_base + VI_DI0);
+	if (vi_dix_get_irq(val)) {
+		ctl->in_vtrace = 0;
+		gcngx_dispatch_vtrace(ctl); /* backwards compatibility */
+
+		out_be32(io_base + VI_DI0, vi_dix_clear_irq(val));
+		return IRQ_HANDLED;
+	}
+	val = in_be32(io_base + VI_DI1);
+	if (vi_dix_get_irq(val)) {
+		ctl->in_vtrace = 1;
+		vi_dispatch_vtrace(ctl);
+		gcngx_dispatch_vtrace(ctl); /* backwards compatibility */
+
+		out_be32(io_base + VI_DI1, vi_dix_clear_irq(val));
+		return IRQ_HANDLED;
+	}
+
+	/* currently unused, just in case */
+	val = in_be32(io_base + VI_DI2);
+	if (vi_dix_get_irq(val)) {
+		out_be32(io_base + VI_DI2, vi_dix_clear_irq(val));
+		return IRQ_HANDLED;
+	}
+	val = in_be32(io_base + VI_DI3);
+	if (vi_dix_get_irq(val)) {
+		out_be32(io_base + VI_DI3, vi_dix_clear_irq(val));
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+#ifdef CONFIG_WII_AVE_RVL
+
+/*
+ * Audio/Video Encoder hardware support.
+ *
+ */
+
+/*
+ * I/O accessors.
+ */
+
+static int vi_ave_outs(struct i2c_client *client, u8 reg,
+		       void *data, size_t len)
+{
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg[1];
+	u8 buf[34];
+	s32 result;
+	int error = -EINVAL;
+
+	if (len > sizeof(buf)-1)
+		goto err_out;
+
+	buf[0] = reg;
+	memcpy(&buf[1], data, len);
+
+	msg[0].addr = client->addr;
+	msg[0].flags = client->flags & I2C_M_TEN;
+	msg[0].len = len+1;
+	msg[0].buf = buf;
+
+	result = i2c_transfer(adap, msg, 1);
+	if (result < 0)
+		error = result;
+	else if (result == 1)
+		error = 0;
+	else
+		error = -EIO;
+
+err_out:
+	if (error)
+		drv_printk(KERN_ERR, "RVL-AVE: "
+			   "error (%d) writing to register %02Xh\n",
+			   error, reg);
+	return error;
+}
+
+static int vi_ave_out8(struct i2c_client *client, u8 reg, u8 data)
+{
+	return vi_ave_outs(client, reg, &data, sizeof(data));
+}
+
+static int vi_ave_out16(struct i2c_client *client, u8 reg, u16 data)
+{
+	cpu_to_be16s(&data);
+	return vi_ave_outs(client, reg, &data, sizeof(data));
+}
+
+static int vi_ave_out32(struct i2c_client *client, u8 reg, u32 data)
+{
+	cpu_to_be32s(&data);
+	return vi_ave_outs(client, reg, &data, sizeof(data));
+}
+
+static int vi_ave_ins(struct i2c_client *client, u8 reg,
+		      void *data, size_t len)
+{
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg[2];
+	s32 result;
+	int error;
+
+	msg[0].addr = client->addr;
+	msg[0].flags = client->flags & I2C_M_TEN;
+	msg[0].len = sizeof(reg);
+	msg[0].buf = &reg;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
+	msg[1].len = len;
+	msg[1].buf = data;
+
+	result = i2c_transfer(adap, msg, 2);
+	if (result < 0)
+		error = result;
+	else if (result == 2)
+		error = 0;
+	else
+		error = -EIO;
+
+	if (error)
+		drv_printk(KERN_ERR, "RVL-AVE: "
+			   "error (%d) reading from register %02Xh\n",
+			   error, reg);
+
+	return error;
+}
+
+static int vi_ave_in8(struct i2c_client *client, u8 reg, u8 *data)
+{
+	return vi_ave_ins(client, reg, data, sizeof(*data));
+}
+
+
+/*
+ * Try to detect current video format.
+ */
+static int vi_ave_get_video_format(struct vi_ctl *ctl,
+				   enum vi_video_format *fmt)
+{
+	u8 val = 0xff;
+	int error = -ENODEV;
+
+	if (!ctl->i2c_client)
+		goto err_out;
+
+	error = vi_ave_in8(ctl->i2c_client, 0x01, &val);
+	if (error)
+		goto err_out;
+
+	if ((val & 0x1f) == 2)
+		*fmt = VI_FMT_PAL;
+	else
+		*fmt = VI_FMT_NTSC;
+err_out:
+	return error;
+}
+
+
+static u8 vi_ave_gamma[] = {
+	0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00,
+	0x10, 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x60,
+	0x80, 0xa0, 0xeb, 0x10, 0x00, 0x20, 0x00, 0x40,
+	0x00, 0x60, 0x00, 0x80, 0x00, 0xa0, 0x00, 0xeb,
+	0x00
+};
+
+/*
+ * Initialize the audio/video encoder.
+ */
+static int vi_ave_setup(struct vi_ctl *ctl)
+{
+	struct i2c_client *client;
+	u8 macrovision[26];
+	u8 component, format, pal60;
+
+	if (!ctl->i2c_client)
+		return -ENODEV;
+
+	client = ctl->i2c_client;
+	memset(macrovision, 0, sizeof(macrovision));
+
+	/*
+	 * Magic initialization sequence borrowed from libogc.
+	 */
+
+	vi_ave_out8(client, 0x6a, 1);
+	vi_ave_out8(client, 0x65, 1);
+
+	/*
+	 * NOTE
+	 * We _can't_ use the fmt field in DCR to derive "format" here.
+	 * DCR uses fmt=0 (NTSC) also for PAL 525 modes.
+	 */
+
+	format = 0;		/* default to NTSC */
+	if ((ctl->mode->flags & VI_VMF_PAL_COLOR) != 0)
+		format = 2;	/* PAL */
+	component = (ctl->has_component_cable) ? 1<<5 : 0;
+	vi_ave_out8(client, 0x01, component | format);
+
+	vi_ave_out8(client, 0x00, 0);
+	vi_ave_out16(client, 0x71, 0x8e8e);
+	vi_ave_out8(client, 0x02, 7);
+	vi_ave_out16(client, 0x05, 0x0000);
+	vi_ave_out16(client, 0x08, 0x0000);
+	vi_ave_out32(client, 0x7a, 0x00000000);
+	vi_ave_outs(client, 0x40, macrovision, sizeof(macrovision));
+	vi_ave_out8(client, 0x0a, 0);
+	vi_ave_out8(client, 0x03, 1);
+	vi_ave_outs(client, 0x10, vi_ave_gamma, sizeof(vi_ave_gamma));
+	vi_ave_out8(client, 0x04, 1);
+
+	vi_ave_out32(client, 0x7a, 0x00000000);
+	vi_ave_out16(client, 0x08, 0x0000);
+
+	vi_ave_out8(client, 0x03, 1);
+
+	/* clear bit 1 otherwise red and blue get swapped  */
+	if (ctl->has_component_cable)
+		vi_ave_out8(client, 0x62, 0);
+
+	/* PAL 480i/60 supposedly needs a "filter" */
+	pal60 = !!(format == 2 && ctl->mode->lines == 525);
+	vi_ave_out8(client, 0x6e, pal60);
+
+	return 0;
+}
+
+static struct vi_ctl *first_vi_ctl;
+static struct i2c_client *first_vi_ave;
+
+static int vi_attach_ave(struct vi_ctl *ctl, struct i2c_client *client)
+{
+	if (!ctl)
+		return -ENODEV;
+	if (!client)
+		return -EINVAL;
+
+	spin_lock(&ctl->lock);
+	if (!ctl->i2c_client) {
+		ctl->i2c_client = i2c_use_client(client);
+		spin_unlock(&ctl->lock);
+		drv_printk(KERN_INFO, "AVE-RVL support loaded\n");
+		return 0;
+	}
+	spin_unlock(&ctl->lock);
+	return -EBUSY;
+}
+
+static void vi_dettach_ave(struct vi_ctl *ctl)
+{
+	struct i2c_client *client;
+
+	if (!ctl)
+		return;
+
+	spin_lock(&ctl->lock);
+	if (ctl->i2c_client) {
+		client = ctl->i2c_client;
+		ctl->i2c_client = NULL;
+		spin_unlock(&ctl->lock);
+		i2c_release_client(client);
+		drv_printk(KERN_INFO, "AVE-RVL support unloaded\n");
+		return;
+	}
+	spin_unlock(&ctl->lock);
+}
+
+static int vi_ave_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	int error;
+
+	/* attach first a/v encoder to first framebuffer */
+	if (!first_vi_ave) {
+		first_vi_ave = client;
+		error = vi_attach_ave(first_vi_ctl, client);
+		if (!error) {
+			/* setup again the video mode using the a/v encoder */
+			vi_detect_tv_mode(first_vi_ctl);
+			vi_setup_tv_mode(first_vi_ctl);
+		}
+	}
+	return 0;
+}
+
+static int vi_ave_remove(struct i2c_client *client)
+{
+	if (first_vi_ave == client)
+		first_vi_ave = NULL;
+	return 0;
+}
+
+static const struct i2c_device_id vi_ave_id[] = {
+	{ "wii-ave-rvl", 0 },
+	{ }
+};
+
+static struct i2c_driver vi_ave_driver = {
+	.driver = {
+		.name	= DRV_MODULE_NAME,
+	},
+	.probe		= vi_ave_probe,
+	.remove		= vi_ave_remove,
+	.id_table	= vi_ave_id,
+};
+
+#endif /* CONFIG_WII_AVE_RVL */
+
+
+/*
+ * Linux framebuffer support routines.
+ *
+ */
+
+/*
+ * This is just a quick, dirty and cheap way of getting right colors on the
+ * linux framebuffer console.
+
+unsigned int vifb_writel(unsigned int rgbrgb, void *address)
+{
+	uint16_t *rgb = (uint16_t *)&rgbrgb;
+	return fb_writel_real(rgbrgb16toycbycr(rgb[0], rgb[1]), address);
+}
+ */
+static int vifb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp, struct fb_info *info)
+{
+	/*
+	 *  Set a single color register. The values supplied are
+	 *  already rounded down to the hardware's capabilities
+	 *  (according to the entries in the `var' structure). Return
+	 *  != 0 for invalid regno.
+	 */
+
+	if (regno >= info->cmap.len)
+		return 1;
+
+	switch (info->var.bits_per_pixel) {
+	case 16:
+		if (info->var.red.offset == 10) {
+			/* 1:5:5:5, not used currently */
+			((u32 *) (info->pseudo_palette))[regno] =
+			    ((red & 0xf800) >> 1) |
+			    ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
+		} else {
+			/* 0:5:6:5 */
+			((u32 *) (info->pseudo_palette))[regno] =
+			    ((red & 0xf800)) |
+			    ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+		}
+		break;
+	case 8:
+	case 15:
+	case 24:
+	case 32:
+		break;
+	}
+	return 0;
+}
+
+/*
+ * Pan the display by altering the framebuffer address in hardware.
+ */
+static int vifb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct vi_ctl *ctl = info->par;
+	void __iomem *io_base = ctl->io_base;
+	unsigned int bytes_per_pixel = info->var.bits_per_pixel / 8;
+	unsigned long flags;
+	int offset;
+	u16 ppl;
+
+	ppl = _ALIGN_UP((var->xoffset & VI_HORZ_ALIGN) + var->xres,
+			VI_HORZ_ALIGN+1);
+	out_be16(io_base + VI_PCR,
+		 vi_pcr_set_wpl(in_be16(io_base + VI_PCR),
+				(ppl * bytes_per_pixel) / VI_HORZ_WORD_SIZE));
+
+	offset = (var->yoffset * info->fix.line_length) +
+		 var->xoffset * bytes_per_pixel;
+	vi_set_framebuffer(ctl, info->fix.smem_start + offset);
+
+	spin_lock_irqsave(&ctl->lock, flags);
+	if (info->fix.smem_start + offset >= ctl->page_address[1])
+		ctl->visible_page = 1;
+	else
+		ctl->visible_page = 0;
+	spin_unlock_irqrestore(&ctl->lock, flags);
+
+	return 0;
+}
+
+static int vifb_check_var_timings(struct fb_var_screeninfo *var,
+				  struct fb_info *info)
+{
+	struct vi_ctl *ctl = info->par;
+	struct vi_tv_mode *mode = ctl->mode;
+	struct vi_mode_timings timings;
+	u32 yres = var->yres;
+	int error = -EINVAL;
+
+	if (nostalgic && yres == 576)
+		yres = 574;
+
+	if (vi_vmode_is_progressive(var->vmode)) {
+		/* 480p */
+		error = vi_ntsc_525_prog_calc_timings(&timings, var,
+						      var->xres, var->yres);
+	} else {
+		if (mode->lines == 625)
+			/* 576i */
+			error = vi_pal_625_calc_timings(&timings, var,
+							var->xres, yres);
+		else
+			/* 480i */
+			error = vi_ntsc_525_calc_timings(&timings, var,
+							 var->xres, var->yres);
+	}
+	if (error)
+		goto err_out;
+
+	ctl->timings = timings;
+	var->pixclock = KHZ2PICOS(13.5 * 1000);
+	var->sync = FB_SYNC_BROADCAST;
+
+	error = 0;
+
+err_out:
+	return error;
+}
+
+/*
+ * Check var and eventually tweak it to something supported.
+ * Do not modify par here.
+ */
+static int vifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct vi_ctl *ctl = info->par;
+	struct vi_tv_mode *mode = ctl->mode;
+	int error = -EINVAL;
+	unsigned int bytes_per_pixel;
+	__u32 xres, yres, xres_virtual, yres_virtual;
+
+	/* we support only 16bpp */
+	if (var->bits_per_pixel != 16) {
+		drv_printk(KERN_ERR, "unsupported depth %u\n",
+				var->bits_per_pixel);
+		goto err_out;
+	}
+
+	yres = var->yres;
+	if (yres & VI_VERT_ALIGN)
+		yres = _ALIGN_UP(yres, VI_VERT_ALIGN+1);
+	if (yres > mode->height) {
+		if (!nostalgic) {
+			drv_printk(KERN_ERR, "yres %u out of bounds\n", yres);
+			goto err_out;
+		}
+		if (!(mode->height == 574 && yres == 576))
+			yres = mode->height;
+	}
+	if (yres < 16) {
+		/* XXX, fbcon will happily page fault for yres < 13 */
+		yres = 16;
+	}
+	if (!yres)
+		yres = mode->height;
+
+	yres_virtual = var->yres_virtual;
+	if (!yres_virtual || yres_virtual < yres)
+		yres_virtual = yres;
+
+	xres = var->xres;
+	if (xres & VI_HORZ_ALIGN)
+		xres = _ALIGN_UP(xres, VI_HORZ_ALIGN+1);
+	if (xres > mode->width) {
+		drv_printk(KERN_ERR, "xres %u out of bounds\n", var->xres);
+		goto err_out;
+	}
+	if (!xres)
+		xres = mode->width;
+
+	xres_virtual = var->xres_virtual;
+	if (xres_virtual & VI_HORZ_ALIGN)
+		xres_virtual = _ALIGN_UP(xres_virtual, VI_HORZ_ALIGN+1);
+	if (!xres_virtual || xres_virtual < xres)
+		xres_virtual = xres;
+
+	bytes_per_pixel = var->bits_per_pixel / 8;
+	if (xres_virtual * yres_virtual * bytes_per_pixel >
+		info->fix.smem_len) {
+		drv_printk(KERN_ERR, "not enough memory for virtual resolution"
+			   " (%ux%ux%u)\n",
+			   xres_virtual, yres_virtual,
+			   var->bits_per_pixel);
+		goto err_out;
+	}
+
+	var->xres = xres;
+	var->yres = yres;
+	var->xres_virtual = xres_virtual;
+	var->yres_virtual = yres_virtual;
+
+	var->xoffset = 0;
+	var->yoffset = 0;
+
+	var->grayscale = 0;
+
+	/* we support ony 16 bits per pixel */
+	var->red.offset = 11;
+	var->red.length = 5;
+	var->green.offset = 5;
+	var->green.length = 6;
+	var->blue.offset = 0;
+	var->blue.length = 5;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+
+	var->nonstd = 0;	/* lies... */
+
+	/* enable non-interlaced mode if supported */
+	if (force_scan != VI_SCAN_INTERLACED && ctl->has_component_cable) {
+		var->vmode = (mode->flags & VI_VMF_PROGRESSIVE) ?
+					FB_VMODE_NONINTERLACED :
+					FB_VMODE_INTERLACED;
+	} else
+		var->vmode = FB_VMODE_INTERLACED;
+
+	error = vifb_check_var_timings(var, info);
+	if (error)
+		goto err_out;
+
+err_out:
+	return error;
+}
+
+/*
+ * Set the video mode according to info->var.
+ */
+static int vifb_set_par(struct fb_info *info)
+{
+	struct vi_ctl *ctl = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	unsigned long flags;
+
+	/* horizontal line in bytes */
+	info->fix.line_length = var->xres_virtual * (var->bits_per_pixel / 8);
+
+	/* info->smem_* refer to vfb, here we wanna store physical fb info */
+	ctl->page_address[0] = fb_start;
+	if (var->yres * info->fix.line_length <= fb_size / 2)
+		ctl->page_address[1] =
+		    fb_start + var->yres * info->fix.line_length;
+	else
+		ctl->page_address[1] = fb_start;
+
+	/* set page 0 as the visible page and cancel pending flips */
+	spin_lock_irqsave(&ctl->lock, flags);
+	ctl->visible_page = 1;
+	vi_flip_page(ctl);
+	spin_unlock_irqrestore(&ctl->lock, flags);
+
+	info->flags = FBINFO_FLAG_DEFAULT;
+	if (want_ypan) {
+		info->fix.xpanstep = 2;
+		info->fix.ypanstep = 1;
+		info->flags |= FBINFO_HWACCEL_YPAN;
+	} else {
+		info->fix.xpanstep = 0;
+		info->fix.ypanstep = 0;
+	}
+
+	vi_setup_tv_mode(ctl);
+
+	/* enable the video retrace handling */
+	vi_enable_interrupts(ctl, 1);
+
+	return 0;
+}
+
+static int vifb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	unsigned long off;
+	unsigned long start;
+	u32 len;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	/* frame buffer memory */
+	start = info->fix.smem_start;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
+	start &= PAGE_MASK;
+	if ((vma->vm_end - vma->vm_start + off) > len)
+		return -EINVAL;
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	/* this is an IO map, tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+
+	/* we share RAM between the cpu and the video hardware */
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+		return -EAGAIN;
+	return 0;
+}
+
+static int vifb_ioctl(struct fb_info *info,
+		       unsigned int cmd, unsigned long arg)
+{
+	struct vi_ctl *ctl = info->par;
+	void __user *argp;
+	unsigned long flags;
+	int page;
+
+	switch (cmd) {
+	case FBIOWAITRETRACE:
+		interruptible_sleep_on(&ctl->vtrace_waitq);
+		return signal_pending(current) ? -EINTR : 0;
+	case FBIOFLIPHACK:
+		/*
+		 * If arg == NULL then
+		 *   Try to flip the video page as soon as possible.
+		 *   Returns the current visible video page number.
+		 */
+		if (!arg) {
+			spin_lock_irqsave(&ctl->lock, flags);
+			if (ctl->in_vtrace)
+				vi_flip_page(ctl);
+			else
+				ctl->flip_pending = 1;
+			spin_unlock_irqrestore(&ctl->lock, flags);
+			return ctl->visible_page;
+		}
+
+		/*
+		 * If arg != NULL then
+		 *   Wait until the video page number pointed by arg
+		 *   is not visible.
+		 *   Returns the current visible video page number.
+		 */
+		argp = (void __user *)arg;
+		if (copy_from_user(&page, argp, sizeof(int)))
+			return -EFAULT;
+
+		if (page != 0 && page != 1)
+			return -EINVAL;
+
+		spin_lock_irqsave(&ctl->lock, flags);
+		ctl->flip_pending = 0;
+		if (ctl->visible_page == page) {
+			if (ctl->in_vtrace) {
+				vi_flip_page(ctl);
+			} else {
+				ctl->flip_pending = 1;
+				spin_unlock_irqrestore(&ctl->lock, flags);
+				interruptible_sleep_on(&ctl->vtrace_waitq);
+				return signal_pending(current) ?
+					-EINTR : ctl->visible_page;
+			}
+		}
+		spin_unlock_irqrestore(&ctl->lock, flags);
+		return ctl->visible_page;
+	}
+	return -EINVAL;
+}
+
+static void gcnfb_render_hline(struct fb_info *info, const char *vfb_mem,
+				uint32_t byte_offset, uint32_t byte_width)
+{
+	uint32_t *addr0 = (uint32_t *)(vfb_mem + byte_offset);
+	uint32_t *addr1 = (uint32_t *)(fb_mem + byte_offset);
+	uint32_t *addr2 = addr0 + (info->fix.line_length * info->var.yres >> 2);
+
+	int j = byte_width >> 2;
+	while (j--) {
+		uint32_t k = *(addr0 + j);
+		if ( k != *(addr2 + j)) {
+			*(addr2 + j) = k;
+			*(addr1 + j) = rgbrgb16toycbycr(k);
+		}
+	}
+}
+
+static void gcnfb_deferred_io(struct fb_info *info,
+				struct list_head *pagelist)
+{
+	struct page *cur;
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+
+	if (!fbdefio)
+		return;
+
+	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+		gcnfb_render_hline(info, (char *) info->fix.smem_start,
+					cur->index << PAGE_SHIFT, PAGE_SIZE);
+	}
+}
+
+static void gcnfb_handle_damage(struct vi_ctl *ctl, int x, int y,
+				int width, int height, char *data)
+{
+	int i;
+	int aligned_x = _ALIGN_DOWN(x, 2);
+	width = _ALIGN_UP(width + (x - aligned_x), 2);
+	x = aligned_x;
+	if ((width <= 0) ||
+		(x + width > ctl->info->var.xres) ||
+		(y + height > ctl->info->var.yres))
+			return;
+	for (i = y; i < y + height ; i++) {
+		const int line_offset = ctl->info->fix.line_length * i;
+		const int byte_offset = line_offset + (x * 2);
+		gcnfb_render_hline(ctl->info,
+					(char *) ctl->info->fix.smem_start,
+					byte_offset, width * 2);
+	}
+}
+
+static void gcnfb_fillrect(struct fb_info *info,
+				   const struct fb_fillrect *rect)
+{
+	struct vi_ctl *ctl = info->par;
+
+	sys_fillrect(info, rect);
+
+	gcnfb_handle_damage(ctl, rect->dx, rect->dy, rect->width,
+				rect->height, info->screen_base);
+}
+
+static void gcnfb_copyarea(struct fb_info *info,
+				   const struct fb_copyarea *area)
+{
+	struct vi_ctl *ctl = info->par;
+
+	sys_copyarea(info, area);
+
+	gcnfb_handle_damage(ctl, area->dx, area->dy, area->width,
+				area->height, info->screen_base);
+}
+
+static void gcnfb_imageblit(struct fb_info *info,
+				const struct fb_image *image)
+{
+	struct vi_ctl *ctl = info->par;
+
+	sys_imageblit(info, image);
+
+	gcnfb_handle_damage(ctl, image->dx, image->dy, image->width,
+				image->height, info->screen_base);
+}
+
+static ssize_t gcnfb_write(struct fb_info *info, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	ssize_t result;
+	struct vi_ctl *ctl = info->par;
+	u32 offset = (u32) *ppos;
+
+	result = fb_sys_write(info, buf, count, ppos);
+
+	if (result > 0) {
+		int start = max((int)(offset / info->fix.line_length) - 1, 0);
+		int lines = min((u32)((result / info->fix.line_length) + 1),
+				(u32)info->var.yres);
+
+		gcnfb_handle_damage(ctl, 0, start, info->var.xres,
+					lines, info->screen_base);
+	}
+
+	return result;
+}
+
+struct fb_ops vifb_ops = {
+	.owner = THIS_MODULE,
+	.fb_setcolreg = vifb_setcolreg,
+	.fb_ioctl = vifb_ioctl,
+	.fb_set_par = vifb_set_par,
+	.fb_check_var = vifb_check_var,
+	.fb_fillrect = gcnfb_fillrect,
+	.fb_copyarea = gcnfb_copyarea,
+	.fb_imageblit = gcnfb_imageblit,
+	.fb_write = gcnfb_write,
+};
+
+static struct fb_deferred_io gcnfb_defio = {
+	.delay		= HZ / 60,
+	.deferred_io	= gcnfb_deferred_io,
+};
+
+/*
+ * Driver model helper routines.
+ *
+ */
+
+static int __devinit vifb_do_probe(struct device *dev,
+			 struct resource *mem, unsigned int irq,
+			 unsigned long xfb_start, unsigned long xfb_size)
+{
+	struct fb_info *info;
+	struct vi_ctl *ctl;
+	int video_cmap_len;
+	int error = -EINVAL;
+
+	info = framebuffer_alloc(sizeof(struct vi_ctl), dev);
+	if (!info)
+		goto err_framebuffer_alloc;
+
+	info->fbops = &vifb_ops;
+	info->var = vifb_var;
+	info->fix = vifb_fix;
+
+	ctl = info->par;
+	ctl->info = info;
+
+	/* first things first */
+	ctl->io_base = ioremap(mem->start, mem->end - mem->start + 1);
+	ctl->irq = irq;
+
+	void *vfb_mem;
+	unsigned long adr;
+	unsigned long size = PAGE_ALIGN(xfb_size);
+	vfb_mem = vmalloc_32(size);
+	if (!vfb_mem) {
+		drv_printk(KERN_ERR, "failed to allocate virtual framebuffer\n");
+		error = -ENOMEM;
+		goto err_framebuffer_alloc;
+	}
+        else {
+		memset(vfb_mem, 0, size);
+		drv_printk(KERN_INFO,
+			   "virtual framebuffer at 0x%p, size %dk\n",
+			   vfb_mem, PAGE_ALIGN(xfb_size) / 1024);
+	}
+
+	/*
+	 * Location and size of the external framebuffer.
+	 */
+	info->fix.smem_start = (unsigned long) vfb_mem;
+	info->fix.smem_len = xfb_size;
+
+	if (!request_mem_region(xfb_start, xfb_size,
+				DRV_MODULE_NAME)) {
+		drv_printk(KERN_WARNING,
+			   "failed to request video memory at %p\n",
+			   (void *)xfb_start);
+	}
+
+	/* Save the physical fb info */
+	fb_start = xfb_start;
+	fb_size = xfb_size;
+	fb_mem = ioremap(fb_start, fb_size);
+	if (!fb_mem) {
+		drv_printk(KERN_ERR,
+			   "failed to ioremap video memory at %p (%dk)\n",
+			   (void *)fb_start,
+			   info->fix.smem_len / 1024);
+		error = -EIO;
+		goto err_ioremap;
+	}
+
+	/* Clear screen */
+	int i = fb_size >> 2;
+	uint32_t * j = (uint32_t *)fb_mem;
+	while (i--) {
+		*(j++) = 0x10801080;
+	}
+	info->screen_base = (char __force __iomem *)vfb_mem;
+
+	spin_lock_init(&ctl->lock);
+	init_waitqueue_head(&ctl->vtrace_waitq);
+
+	vi_reset_video(ctl);
+	vi_detect_tv_mode(ctl);
+
+	if (!nostalgic) {
+		/* by default, start with overscan compensation */
+		info->var.xres = 576;
+		if (ctl->mode->height == 574)
+			info->var.yres = 516;
+		else
+			info->var.yres = 432;
+	} else {
+		info->var.xres = ctl->mode->width;
+		info->var.yres = ctl->mode->height;
+	}
+
+	ctl->visible_page = 0;
+	ctl->flip_pending = 0;
+
+	drv_printk(KERN_INFO,
+		   "framebuffer at 0x%p, mapped to 0x%p, size %dk\n",
+		   (void *)info->fix.smem_start, info->screen_base,
+		   info->fix.smem_len / 1024);
+
+	video_cmap_len = 16;
+	info->pseudo_palette = pseudo_palette;
+	if (fb_alloc_cmap(&info->cmap, video_cmap_len, 0)) {
+		error = -ENOMEM;
+		goto err_alloc_cmap;
+	}
+
+	error = vifb_check_var(&info->var, info);
+	if (error)
+		goto err_check_var;
+
+	drv_printk(KERN_INFO, "mode is %dx%dx%d\n", info->var.xres,
+		   info->var.yres, info->var.bits_per_pixel);
+
+	dev_set_drvdata(dev, info);
+
+	vi_enable_interrupts(ctl, 0);
+
+	error = request_irq(ctl->irq, vi_irq_handler, 0, DRV_MODULE_NAME, dev);
+	if (error) {
+		drv_printk(KERN_ERR, "unable to register IRQ %u\n", ctl->irq);
+		goto err_request_irq;
+	}
+
+	/* Init defio */
+	info->fbdefio = &gcnfb_defio;
+	fb_deferred_io_init(info);
+
+	/* now register us */
+	if (register_framebuffer(info) < 0) {
+		error = -EINVAL;
+		goto err_register_framebuffer;
+	}
+
+#ifdef CONFIG_WII_AVE_RVL
+	if (!first_vi_ctl)
+		first_vi_ctl = ctl;
+
+	/* try to attach the a/v encoder now */
+	vi_attach_ave(ctl, first_vi_ave);
+#endif
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+
+	return 0;
+
+err_register_framebuffer:
+	fb_deferred_io_cleanup(info);
+	free_irq(ctl->irq, 0);
+err_check_var:
+err_request_irq:
+	fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+	iounmap(fb_mem);
+err_ioremap:
+	release_mem_region(fb_start, fb_size);
+	vfree((void *)info->fix.smem_start);
+
+	dev_set_drvdata(dev, NULL);
+	iounmap(ctl->io_base);
+	framebuffer_release(info);
+err_framebuffer_alloc:
+	return error;
+}
+
+static int __devexit vifb_do_remove(struct device *dev)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct vi_ctl *ctl = info->par;
+
+	if (!info)
+		return -ENODEV;
+
+	free_irq(ctl->irq, dev);
+	fb_deferred_io_cleanup(info);
+	unregister_framebuffer(info);
+	fb_dealloc_cmap(&info->cmap);
+	iounmap(fb_mem);
+	release_mem_region(fb_start, fb_size);
+
+	vfree((void *)info->fix.smem_start);
+
+	dev_set_drvdata(dev, NULL);
+	iounmap(ctl->io_base);
+
+#ifdef CONFIG_WII_AVE_RVL
+	vi_dettach_ave(ctl);
+	if (first_vi_ctl == ctl)
+		first_vi_ctl = NULL;
+#endif
+	framebuffer_release(info);
+	return 0;
+}
+
+static int vifb_do_shutdown(struct device *dev)
+{
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct vi_ctl *ctl = info->par;
+	void __iomem *io_base = ctl->io_base;
+
+	vi_enable_interrupts(ctl, 0);
+	vi_reset_video(ctl);
+	out_be16(io_base + VI_DCR, vi_dcr_enb(0));
+
+	return 0;
+}
+
+#ifndef MODULE
+
+static int __devinit vifb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	drv_printk(KERN_INFO, "options: %s\n", options);
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+
+		if (!strcmp(this_opt, "redraw"))
+			want_ypan = 0;
+		else if (!strcmp(this_opt, "interlaced"))
+			force_scan = VI_SCAN_INTERLACED;
+		else if (!strcmp(this_opt, "progressive"))
+			force_scan = VI_SCAN_PROGRESSIVE;
+		else if (!strcmp(this_opt, "50Hz"))
+			force_rate = VI_RATE_50Hz;
+		else if (!strcmp(this_opt, "60Hz"))
+			force_rate = VI_RATE_60Hz;
+		else if (!strncmp(this_opt, "tv=", 3)) {
+			if (!strncmp(this_opt + 3, "PAL", 3))
+				force_tv = VI_TV_PAL;
+			else if (!strncmp(this_opt + 3, "NTSC", 4))
+				force_tv = VI_TV_NTSC;
+		} else if (!strcmp(this_opt, "nostalgic"))
+			nostalgic = 1;
+	}
+
+	if (force_scan == VI_SCAN_PROGRESSIVE || force_tv == VI_TV_NTSC) {
+		if (force_rate == VI_RATE_50Hz) {
+			drv_printk(KERN_INFO, "ignoring forced 50Hz setting\n");
+			force_rate = VI_RATE_DONTCARE;
+		}
+	}
+	return 0;
+}
+
+#endif	/* MODULE */
+
+
+/*
+ * OF platform driver hooks.
+ *
+ */
+
+static int __init vifb_of_probe(struct of_device *odev,
+				 const struct of_device_id *match)
+{
+	struct resource res;
+	const unsigned long *prop;
+	unsigned long xfb_start, xfb_size;
+	int retval;
+
+	retval = of_address_to_resource(odev->node, 0, &res);
+	if (retval) {
+		drv_printk(KERN_ERR, "no io memory range found\n");
+		return -ENODEV;
+	}
+
+	prop = of_get_property(odev->node, "xfb-start", NULL);
+	if (!prop) {
+		drv_printk(KERN_ERR, "no xfb start found\n");
+		return -ENODEV;
+	}
+	xfb_start = *prop;
+
+	prop = of_get_property(odev->node, "xfb-size", NULL);
+	if (!prop) {
+		drv_printk(KERN_ERR, "no xfb size found\n");
+		return -ENODEV;
+	}
+	xfb_size = *prop;
+
+	return vifb_do_probe(&odev->dev,
+			     &res, irq_of_parse_and_map(odev->node, 0),
+			     xfb_start, xfb_size);
+}
+
+static int __exit vifb_of_remove(struct of_device *odev)
+{
+	return vifb_do_remove(&odev->dev);
+}
+
+static int vifb_of_shutdown(struct of_device *odev)
+{
+	return vifb_do_shutdown(&odev->dev);
+}
+
+
+static struct of_device_id vifb_of_match[] = {
+	{ .compatible = "nintendo,flipper-video", },
+	{ .compatible = "nintendo,hollywood-video", },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, vifb_of_match);
+
+static struct of_platform_driver vifb_of_driver = {
+	.owner = THIS_MODULE,
+	.name = DRV_MODULE_NAME,
+	.match_table = vifb_of_match,
+	.probe = vifb_of_probe,
+	.remove = vifb_of_remove,
+	.shutdown = vifb_of_shutdown,
+};
+
+/*
+ * Module interface hooks
+ *
+ */
+
+static int __init vifb_init_module(void)
+{
+	int error;
+	char *option = NULL;
+
+	drv_printk(KERN_INFO, "%s - version %s\n", DRV_DESCRIPTION,
+		   vifb_driver_version);
+
+#ifndef MODULE
+	if (fb_get_options(DRV_MODULE_NAME, &option))
+		return -ENODEV;
+	if (!option) {
+		/* for backwards compatibility */
+		if (fb_get_options("gcnfb", &option))
+			return -ENODEV;
+	}
+	error = vifb_setup(option);
+#endif
+
+#ifdef CONFIG_WII_AVE_RVL
+	error = i2c_add_driver(&vi_ave_driver);
+	if (error)
+		drv_printk(KERN_ERR, "failed to register AVE (%d)\n", error);
+#endif
+
+	return of_register_platform_driver(&vifb_of_driver);
+}
+
+static void __exit vifb_exit_module(void)
+{
+	of_unregister_platform_driver(&vifb_of_driver);
+#ifdef CONFIG_WII_AVE_RVL
+	i2c_del_driver(&vi_ave_driver);
+#endif
+}
+
+module_init(vifb_init_module);
+module_exit(vifb_exit_module);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index 6d6f8c0..48ac28e 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -33,6 +33,11 @@
 	depends on MACH_DECSTATION || ALPHA
 	default y
 
+config LOGO_GAMECUBE_CLUT224
+	bool "224-color GameCube Linux logo"
+	depends on GAMECUBE
+	default y
+
 config LOGO_MAC_CLUT224
 	bool "224-color Macintosh Linux logo"
 	depends on MAC
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
index 895c60b..6454c37 100644
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_LOGO_LINUX_VGA16)		+= logo_linux_vga16.o
 obj-$(CONFIG_LOGO_LINUX_CLUT224)	+= logo_linux_clut224.o
 obj-$(CONFIG_LOGO_DEC_CLUT224)		+= logo_dec_clut224.o
+obj-$(CONFIG_LOGO_GAMECUBE_CLUT224) 	+= logo_gcn_clut224.o
 obj-$(CONFIG_LOGO_MAC_CLUT224)		+= logo_mac_clut224.o
 obj-$(CONFIG_LOGO_PARISC_CLUT224)	+= logo_parisc_clut224.o
 obj-$(CONFIG_LOGO_SGI_CLUT224)		+= logo_sgi_clut224.o
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 141f15a..bbef42c 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -79,6 +79,10 @@ const struct linux_logo * __ref fb_find_logo(int depth)
 		/* DEC Linux logo on MIPS/MIPS64 or ALPHA */
 		logo = &logo_dec_clut224;
 #endif
+#ifdef CONFIG_LOGO_GAMECUBE_CLUT224
+		/* GameCube Linux logo */
+		logo = &logo_gcn_clut224;
+#endif
 #ifdef CONFIG_LOGO_MAC_CLUT224
 		/* Macintosh Linux logo on m68k */
 		if (MACH_IS_MAC)
diff --git a/drivers/video/logo/logo_gcn_clut224.ppm b/drivers/video/logo/logo_gcn_clut224.ppm
new file mode 100644
index 0000000..08e12b3
--- /dev/null
+++ b/drivers/video/logo/logo_gcn_clut224.ppm
@@ -0,0 +1,1123 @@
+P3
+80 80
+255
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+6 6 6  6 6 6  10 10 10  10 10 10  10 10 10  6 6 6
+6 6 6  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  6 6 6  10 10 10  14 14 14
+22 22 22  26 26 26  30 30 30  34 34 34  30 30 30  30 30 30
+26 26 26  18 18 17  14 14 14  10 10 10  6 6 6  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  14 14 14  26 26 26  42 42 42
+54 54 55  66 66 66  78 78 78  78 78 78  78 78 78  74 74 74
+66 66 66  54 54 55  42 42 42  26 26 26  18 18 17  10 10 10
+6 6 6  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  10 10 10  22 22 22  42 42 42  66 66 66  87 86 85
+66 66 66  38 38 38  38 38 38  22 22 22  26 26 26  34 34 34
+54 54 55  66 66 66  87 86 85  70 70 70  46 46 46  26 26 26
+14 14 14  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+10 10 10  26 26 26  50 50 50  82 82 82  58 58 58  6 6 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  6 6 6  54 54 55  87 86 85  66 66 66
+38 38 38  18 18 17  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  6 6 6
+22 22 22  50 50 50  78 78 78  34 34 34  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  6 6 6  70 70 70
+78 78 78  46 46 46  22 22 22  6 6 6  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  6 6 6  18 18 17
+42 42 42  82 82 82  26 26 26  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  14 14 14  46 46 46  34 34 34  6 6 6  2 2 6
+42 42 42  78 78 78  42 42 42  18 18 17  6 6 6  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  10 10 10  30 30 30
+66 66 66  58 58 58  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  26 26 26  87 86 85  102 98 90  46 46 46  10 10 10
+2 2 6  58 58 58  70 70 70  34 34 34  10 10 10  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  14 14 14  42 42 42
+87 86 85  10 10 10  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  30 30 30  94 94 98  94 94 94  58 58 58  26 26 26
+2 2 6  6 6 6  78 78 78  54 54 55  22 22 22  6 6 6
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  6 6 6  22 22 22  62 62 62
+62 62 62  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  26 26 26  54 54 55  38 38 38  18 18 17  10 10 10
+2 2 6  2 2 6  34 34 34  82 82 82  38 38 38  14 14 14
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  6 6 6  30 30 30  78 78 78
+30 30 30  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  10 10 10  10 10 10  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  78 78 78  50 50 50  18 18 17
+6 6 6  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  38 38 38  87 86 85
+14 14 14  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 2  54 54 55  66 66 66  26 26 26
+6 6 6  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  14 14 14  42 42 42  82 82 82
+2 2 6  2 2 6  2 2 6  6 6 6  10 10 10  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  6 6 6  14 14 14  10 10 10  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  18 18 17  82 82 82  34 34 34
+10 10 10  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  14 14 14  46 46 46  87 86 85
+2 2 6  2 2 6  6 6 6  6 6 6  22 22 22  34 34 34
+6 6 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+18 18 17  34 34 34  10 10 10  50 50 50  22 22 22  2 2 6
+2 2 6  2 2 6  2 2 6  10 10 10  87 86 85  42 42 42
+14 14 14  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  14 14 14  46 46 46  87 86 85
+2 2 6  2 2 6  38 38 38  118 118 118  94 94 94  22 22 22
+22 22 22  2 2 6  2 2 6  2 2 6  14 14 14  87 86 85
+141 139 143  160 158 162  152 152 152  38 38 38  26 26 26  6 6 6
+2 2 6  2 2 6  2 2 6  2 2 6  87 86 85  46 46 46
+14 14 14  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  14 14 14  46 46 46  87 86 85
+2 2 6  14 14 14  134 133 135  199 199 199  194 193 197  118 118 118
+10 10 10  2 2 6  2 2 6  6 6 6  102 98 90  190 190 190
+209 208 212  219 220 223  215 214 215  134 133 135  14 14 14  6 6 6
+2 2 6  2 2 6  2 2 6  2 2 6  87 86 85  50 50 50
+18 18 17  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  14 14 14  46 46 46  87 86 85
+2 2 6  54 54 55  219 220 223  199 199 199  219 220 223  246 246 246
+58 58 58  2 2 6  2 2 6  30 30 30  209 208 212  254 254 254
+173 173 174  121 121 122  219 220 223  236 233 239  74 74 74  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  70 70 70  58 58 58
+22 22 22  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  14 14 14  46 46 46  82 82 82
+2 2 6  104 103 100  173 173 174  26 26 26  90 90 90  229 226 233
+121 121 122  10 10 10  14 14 14  46 46 46  229 231 235  190 190 190
+6 6 6  74 74 74  90 90 90  239 238 242  160 158 162  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  70 70 70  58 58 58
+22 22 22  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  14 14 14  42 42 42  87 86 85
+6 6 6  118 118 118  104 103 100  6 6 6  70 70 70  152 152 152
+122 122 130  18 18 17  38 38 38  54 54 55  219 220 223  104 103 100
+2 2 2  14 14 14  46 46 46  190 190 190  199 199 199  2 2 2
+2 2 6  2 2 6  2 2 6  2 2 6  74 74 74  62 62 62
+22 22 22  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  14 14 14  42 42 42  94 94 94
+14 14 14  104 103 100  122 122 130  2 2 2  18 18 17  118 118 118
+124 98 46  122 94 10  122 94 10  101 78 10  163 163 162  107 107 108
+2 2 6  2 2 2  2 2 2  194 193 197  194 193 197  6 6 6
+2 2 6  2 2 6  2 2 6  2 2 6  74 74 74  62 62 62
+22 22 22  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  38 38 38  90 90 90
+14 14 14  62 62 62  209 208 212  26 26 26  44 31 8  158 118 10
+226 171 11  238 183 13  214 174 14  188 146 14  214 174 14  174 146 62
+26 26 26  2 2 2  70 70 70  246 246 246  141 139 143  2 2 2
+2 2 6  2 2 6  2 2 6  2 2 6  70 70 70  66 66 66
+26 26 26  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  38 38 38  87 86 85
+14 14 14  6 6 6  199 199 199  190 166 114  186 134 10  226 171 11
+238 178 14  234 193 17  234 193 17  236 202 20  246 206 46  242 210 18
+234 193 17  188 146 14  218 194 134  210 206 186  42 42 42  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  50 50 50  74 74 74
+30 30 30  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  34 34 34  87 86 85
+14 14 14  2 2 2  122 86 26  194 134 10  226 166 10  238 183 13
+226 186 14  234 193 17  236 202 20  246 216 61  246 217 39  246 217 39
+246 214 22  242 210 18  242 210 18  226 186 14  122 86 26  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  50 50 50  82 82 82
+34 34 34  10 10 10  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  34 34 34  82 82 82
+30 30 30  63 43 6  182 122 6  204 146 10  231 174 11  238 183 13
+234 193 17  236 202 20  242 210 18  246 216 61  246 217 39  246 214 22
+246 214 22  242 210 18  226 186 14  214 174 14  188 146 14  6 6 6
+2 2 6  2 2 6  2 2 6  2 2 6  26 26 26  94 94 94
+42 42 42  14 14 14  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  30 30 30  78 78 78
+50 50 50  104 70 6  186 134 10  218 158 10  238 178 14  242 186 14
+236 202 20  236 202 20  246 216 61  246 217 39  246 217 39  246 214 22
+242 210 18  198 154 10  198 138 10  218 158 10  154 114 10  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  6 6 6  90 90 90
+54 54 55  18 18 17  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  30 30 30  78 78 78
+46 46 46  22 22 22  138 93 6  198 154 10  238 183 13  238 183 13
+236 202 20  242 210 18  246 214 22  246 214 22  242 210 18  204 166 16
+186 134 10  210 150 10  216 162 10  210 150 10  101 78 10  2 2 6
+6 6 6  54 54 55  14 14 14  2 2 6  2 2 6  62 62 62
+74 74 74  30 30 30  10 10 10  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  34 34 34  78 78 78
+50 50 50  6 6 6  94 70 30  138 102 14  188 146 14  226 186 14
+236 202 20  234 193 17  214 174 14  188 146 14  173 119 7  186 134 10
+210 150 10  214 154 10  202 150 34  182 158 106  102 98 90  2 2 2
+2 2 6  78 78 78  118 118 118  54 54 55  2 2 6  22 22 22
+90 90 90  46 46 46  18 18 17  6 6 6  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  38 38 38  87 86 85
+50 50 50  6 6 6  132 131 125  174 154 114  160 108 10  173 119 7
+198 154 10  188 146 14  198 138 10  198 138 10  204 146 10  204 146 10
+198 138 10  190 166 114  194 193 197  199 199 199  173 173 174  14 14 14
+2 2 6  18 18 17  118 118 118  118 118 118  22 22 22  2 2 6
+74 74 74  70 70 70  30 30 30  10 10 10  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  18 18 17  50 50 50  104 103 100
+26 26 26  10 10 10  141 139 143  190 190 190  174 154 114  160 108 10
+198 138 10  188 146 14  198 138 10  194 134 10  182 122 6  190 142 34
+186 174 146  185 185 187  199 199 199  219 220 223  215 214 215  66 66 66
+2 2 6  2 2 6  50 50 50  62 62 62  6 6 6  2 2 2
+10 10 10  90 90 90  50 50 50  18 18 17  6 6 6  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  10 10 10  34 34 34  74 74 74  74 74 74
+2 2 2  6 6 6  141 139 143  199 199 199  190 190 190  163 163 162
+154 122 54  160 108 10  160 108 10  164 122 42  174 154 114  185 185 187
+194 193 197  209 208 212  250 250 250  254 254 254  250 250 250  182 182 182
+6 6 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  62 62 62  74 74 74  34 34 34  14 14 14  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  10 10 10  22 22 22  54 54 55  94 94 94  18 18 17
+2 2 6  50 50 50  229 231 235  219 220 223  194 193 197  190 190 190
+190 190 190  190 190 190  190 190 190  190 190 190  190 190 190  194 193 197
+215 214 215  242 242 242  254 254 254  254 254 254  250 250 250  254 254 254
+82 82 82  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  14 14 14  87 86 85  54 54 55  22 22 22  6 6 6
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+6 6 6  18 18 17  46 46 46  90 90 90  46 46 46  18 18 17
+6 6 6  182 182 182  254 254 254  250 250 250  210 206 186  190 190 190
+190 190 190  190 190 190  190 190 190  190 190 190  210 206 186  229 231 235
+254 254 254  250 250 250  250 250 250  254 254 254  254 254 254  254 254 254
+198 200 208  14 14 14  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  42 42 42  87 86 85  42 42 42  18 18 17
+6 6 6  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  6 6 6
+14 14 14  38 38 38  74 74 74  66 66 66  2 2 6  6 6 6
+90 90 90  250 250 250  250 250 250  254 254 254  239 238 242  199 199 199
+190 190 190  190 190 190  194 193 197  219 220 223  183 174 199  134 114 171
+207 201 219  254 254 254  254 254 254  254 254 254  250 250 250  254 254 254
+250 250 250  82 82 82  2 2 2  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  78 78 78  70 70 70  34 34 34
+14 14 14  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  14 14 14
+34 34 34  66 66 66  78 78 78  6 6 6  2 2 2  18 18 17
+219 220 223  254 254 254  254 254 254  250 250 250  254 254 254  246 246 246
+222 223 236  229 231 235  229 226 233  140 131 164  109 96 159  109 96 159
+120 106 166  170 156 193  236 233 239  254 254 254  254 254 254  254 254 254
+254 254 254  182 182 182  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  18 18 17  90 90 90  62 62 62
+30 30 30  10 10 10  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  10 10 10  26 26 26
+58 58 58  90 90 90  18 18 17  2 2 6  2 2 6  107 107 108
+254 254 254  254 254 254  254 254 254  250 250 250  250 250 250  254 254 254
+250 250 250  189 183 204  121 102 164  116 94 159  117 98 162  114 103 163
+114 103 163  120 106 166  136 121 175  146 139 165  107 107 108  118 118 118
+141 139 143  182 182 182  219 220 223  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  18 18 17  94 94 94
+54 54 55  26 26 26  10 10 10  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  6 6 6  22 22 22  50 50 50
+90 90 90  26 26 26  2 2 6  2 2 2  14 14 14  199 199 199
+250 250 250  254 254 254  254 254 254  254 254 254  254 254 254  229 226 233
+147 132 180  109 90 154  158 147 190  198 200 208  137 128 178  120 106 166
+121 102 164  120 106 166  130 120 175  130 120 175  127 110 169  76 72 88
+58 58 58  58 58 58  74 74 74  118 118 118  194 193 197  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  38 38 38
+87 86 85  50 50 50  22 22 22  6 6 6  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  14 14 14  38 38 38  82 82 82
+34 34 34  2 2 6  2 2 6  2 2 2  42 42 42  194 193 197
+246 246 246  254 254 254  254 254 254  254 254 254  200 193 212  122 98 164
+113 86 148  109 96 159  128 114 172  158 147 190  130 120 175  120 106 166
+127 110 169  127 110 169  130 120 175  130 120 175  142 128 179  140 131 164
+102 98 122  58 50 84  54 54 55  62 62 62  74 74 74  134 133 135
+236 233 239  2 2 2  2 2 6  2 2 6  2 2 6  2 2 6
+38 38 38  82 82 82  42 42 42  14 14 14  6 6 6  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  10 10 10  26 26 26  62 62 62  66 66 66
+2 2 6  2 2 6  2 2 6  6 6 6  70 70 70  169 165 179
+210 206 186  229 231 235  236 233 239  146 139 165  105 86 155  105 86 155
+109 96 159  109 90 154  109 96 159  114 103 163  114 103 163  120 106 166
+120 106 166  128 114 172  130 120 175  137 128 178  137 128 178  142 134 183
+155 141 181  140 131 164  70 70 70  58 50 84  66 66 66  84 82 94
+118 118 118  229 231 235  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  62 62 62  66 66 66  30 30 30  10 10 10  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  14 14 14  42 42 42  82 82 82  18 18 17
+2 2 6  2 2 6  2 2 6  10 10 10  94 94 94  182 182 182
+219 220 223  200 193 212  122 98 164  102 82 152  105 86 155  109 90 154
+109 96 159  109 90 154  109 96 159  114 103 163  114 103 163  127 110 169
+128 114 172  128 114 172  130 120 175  137 128 178  142 128 179  148 140 189
+148 140 189  158 147 190  158 147 190  118 110 134  76 72 88  94 90 106
+94 94 98  132 131 125  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  6 6 6  87 86 85  46 46 46  18 18 17  6 6 6
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  6 6 6  22 22 22  54 54 55  70 70 70  2 2 6
+2 2 6  10 10 10  2 2 2  22 22 22  173 173 174  236 233 239
+155 141 181  102 82 152  102 82 152  102 82 152  109 90 154  105 86 155
+109 90 154  87 78 126  58 50 84  45 38 66  45 38 66  54 46 76
+82 70 114  114 103 163  130 120 175  136 121 175  137 128 178  142 128 179
+142 134 183  148 140 189  158 147 190  158 147 190  146 139 165  118 106 138
+126 122 142  87 86 85  199 199 199  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  62 62 62  66 66 66  26 26 26  10 10 10
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  10 10 10  30 30 30  74 74 74  50 50 50  2 2 6
+26 26 26  26 26 26  2 2 6  107 107 108  207 201 219  120 106 166
+103 83 144  102 82 152  105 86 155  102 82 152  94 82 138  87 78 126
+34 26 54  6 6 6  6 6 6  2 2 6  2 2 6  2 2 2
+2 2 2  10 6 18  64 60 89  130 120 175  137 128 178  137 128 178
+142 128 179  148 140 189  142 134 183  146 140 180  142 134 183  148 140 189
+155 141 181  110 106 126  146 146 147  18 18 17  2 2 6  2 2 6
+2 2 6  2 2 6  18 18 17  87 86 85  42 42 42  14 14 14
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  14 14 14  42 42 42  90 90 90  22 22 22  2 2 6
+42 42 42  2 2 2  78 78 78  166 150 188  102 82 152  99 78 147
+111 77 141  102 82 152  99 78 147  105 86 155  87 78 126  10 10 10
+6 6 6  2 2 6  2 2 6  6 2 2  2 2 2  2 2 2
+2 2 6  6 6 6  2 2 6  45 38 66  130 120 175  136 121 175
+137 128 178  137 128 178  137 128 178  137 128 178  137 128 178  142 128 179
+142 134 183  140 131 164  138 131 154  38 38 38  10 10 10  2 2 6
+2 2 6  2 2 6  2 2 6  78 78 78  58 58 58  22 22 22
+6 6 6  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+6 6 6  18 18 17  54 54 55  82 82 82  2 2 6  26 26 26
+22 22 22  216 211 227  127 110 169  97 74 146  99 78 147  99 78 147
+102 82 152  102 82 152  99 78 147  94 82 138  34 26 54  2 2 6
+2 2 6  6 2 7  50 50 50  30 30 30  6 6 6  6 2 2
+2 2 2  2 2 2  2 2 6  2 2 6  87 78 126  130 120 175
+128 114 172  130 120 175  130 120 175  136 121 175  137 128 178  130 120 175
+130 120 175  137 128 178  142 134 183  213 206 226  38 38 38  2 2 6
+2 2 6  2 2 6  2 2 6  46 46 46  78 78 78  30 30 30
+10 10 10  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+10 10 10  30 30 30  74 74 74  58 58 58  2 2 6  42 42 42
+189 183 204  105 86 155  97 74 146  97 74 146  93 70 140  97 74 146
+105 86 155  99 78 147  102 82 152  94 82 138  10 6 18  6 2 7
+6 6 6  2 2 2  10 6 18  50 50 50  54 54 55  18 18 17
+6 2 2  6 2 7  6 2 7  2 2 6  54 46 76  120 106 166
+127 110 169  127 110 169  127 110 169  128 114 172  127 110 169  128 114 172
+128 114 172  127 110 169  128 114 172  130 120 175  38 38 38  14 14 14
+2 2 6  2 2 6  2 2 6  6 6 6  87 86 85  46 46 46
+14 14 14  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  6 6 6
+14 14 14  42 42 42  90 90 90  18 18 17  18 18 17  26 26 26
+183 174 199  122 98 164  97 74 146  99 78 147  97 74 146  97 74 146
+99 78 147  99 78 147  102 82 152  99 78 147  14 14 14  26 26 26
+26 26 26  6 2 7  6 2 7  6 2 7  22 22 22  66 66 66
+30 30 30  2 2 6  2 2 6  2 2 6  58 50 84  120 106 166
+114 103 163  114 103 163  114 103 163  114 103 163  114 103 163  114 103 163
+114 103 163  120 106 166  109 90 154  134 120 165  10 10 10  34 34 34
+2 2 6  2 2 6  2 2 6  2 2 6  74 74 74  58 58 58
+22 22 22  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  10 10 10
+26 26 26  66 66 66  82 82 82  2 2 6  38 38 38  6 2 7
+196 186 211  154 134 184  127 110 169  99 78 147  97 74 146  97 74 146
+99 78 147  99 78 147  99 78 147  102 82 152  45 38 66  58 50 84
+54 54 55  22 22 22  6 2 7  6 2 7  6 2 7  10 10 10
+14 14 14  6 2 2  2 2 2  10 6 18  94 82 138  109 96 159
+109 96 159  109 96 159  109 96 159  109 96 159  109 96 159  109 96 159
+109 96 159  105 86 155  116 94 159  147 132 180  2 2 6  46 46 46
+2 2 6  2 2 6  2 2 6  2 2 6  42 42 42  74 74 74
+30 30 30  10 10 10  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  6 6 6  14 14 14
+42 42 42  90 90 90  26 26 26  6 6 6  42 42 42  2 2 6
+200 193 212  154 134 184  154 134 184  136 121 175  105 86 155  97 74 146
+97 74 146  99 78 147  99 78 147  97 74 146  95 75 136  40 30 56
+94 90 106  104 103 100  50 50 50  26 26 26  6 2 7  6 2 7
+2 2 6  6 2 2  10 6 18  64 60 89  109 90 154  105 86 155
+105 86 155  105 86 155  105 86 155  105 86 155  105 86 155  102 82 152
+109 90 154  116 94 159  116 94 159  157 140 187  2 2 6  46 46 46
+2 2 6  2 2 6  2 2 6  2 2 6  10 10 10  87 86 85
+38 38 38  10 10 10  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  10 10 10  26 26 26
+66 66 66  82 82 82  2 2 6  22 22 22  18 18 17  6 2 7
+207 201 219  154 134 184  147 132 180  147 132 180  147 126 185  114 90 155
+97 74 146  97 74 146  111 77 141  130 90 130  99 78 147  95 75 136
+58 50 84  84 82 94  87 86 85  38 38 38  6 2 7  6 2 7
+10 6 18  34 26 54  86 66 120  102 82 152  99 78 147  102 82 152
+102 82 152  102 82 152  102 82 152  99 78 147  99 78 147  109 90 154
+114 90 155  116 94 159  116 94 159  170 156 193  2 2 6  38 38 38
+2 2 6  2 2 6  2 2 6  2 2 6  6 6 6  87 86 85
+46 46 46  14 14 14  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  6 6 6  18 18 17  46 46 46
+87 86 85  18 18 17  2 2 6  34 34 34  10 10 10  10 6 18
+213 206 226  162 146 182  183 174 199  147 132 180  142 134 183  147 132 180
+126 102 165  97 74 146  97 74 146  130 90 130  166 110 126  118 78 130
+93 70 140  97 74 146  86 66 120  70 56 108  70 56 108  70 56 108
+87 78 126  94 82 138  99 78 147  99 78 147  99 78 147  99 78 147
+97 74 146  97 74 146  97 74 146  102 82 152  114 90 155  116 94 159
+116 94 159  122 98 164  122 98 164  177 168 195  6 6 6  30 30 30
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  82 82 82
+54 54 55  18 18 17  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  26 26 26  66 66 66
+62 62 62  2 2 6  2 2 2  38 38 38  10 10 10  22 22 22
+226 218 234  170 156 193  207 201 219  194 193 197  146 139 165  147 126 185
+147 132 180  134 114 171  99 78 147  99 78 147  118 78 130  113 86 148
+97 74 146  97 74 146  97 74 146  97 74 146  97 74 146  99 78 147
+97 74 146  97 74 146  97 74 146  97 74 146  97 74 146  93 70 140
+97 74 146  93 70 140  105 86 155  109 90 154  93 70 140  116 94 159
+122 98 164  122 98 164  126 102 165  189 183 204  10 10 10  30 30 30
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  66 66 66
+58 58 58  22 22 22  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  10 10 10  38 38 38  78 78 78
+6 6 6  2 2 6  2 2 6  46 46 46  14 14 14  42 42 42
+229 226 233  170 156 193  183 174 199  132 131 125  198 200 208  158 147 190
+140 131 164  142 134 183  136 121 175  113 86 148  95 75 136  97 74 146
+97 74 146  95 75 136  93 70 140  93 70 140  97 74 146  102 82 152
+97 74 146  93 70 140  93 70 140  93 70 140  93 70 140  93 70 140
+97 74 146  105 86 155  99 78 147  88 65 130  92 71 128  116 94 159
+122 98 164  126 102 165  127 106 167  196 186 211  22 22 22  14 14 14
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  66 66 66
+62 62 62  22 22 22  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  18 18 17  50 50 50  74 74 74
+2 2 6  2 2 6  14 14 14  70 70 70  34 34 34  62 62 62
+236 233 239  170 156 193  194 193 197  46 42 70  200 193 212  199 199 199
+177 162 197  137 128 178  147 132 180  147 126 185  121 102 164  97 74 146
+93 70 140  93 70 140  97 74 146  93 70 140  93 70 140  88 65 130
+88 65 130  93 70 140  93 70 140  93 70 140  93 70 140  97 74 146
+113 86 148  97 74 146  86 66 120  92 71 128  93 70 140  122 98 164
+126 102 165  127 106 167  127 106 167  207 201 219  30 30 30  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  66 66 66
+62 62 62  22 22 22  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  18 18 17  54 54 55  62 62 62
+2 2 6  2 2 6  2 2 6  30 30 30  46 46 46  74 74 74
+254 254 254  158 147 190  236 233 239  199 199 199  215 214 215  190 190 190
+163 163 162  183 174 199  138 131 154  142 128 179  147 126 185  127 110 169
+99 78 147  93 70 140  97 74 146  93 70 140  93 70 140  88 65 130
+88 65 130  88 65 130  93 70 140  88 65 130  102 82 152  105 86 155
+92 71 128  86 66 120  86 66 120  92 71 128  95 75 136  126 102 165
+127 106 167  127 106 167  127 106 167  213 206 226  30 30 30  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  66 66 66
+58 58 58  22 22 22  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  22 22 22  58 58 58  62 62 62
+2 2 6  2 2 6  2 2 2  6 2 7  30 30 30  78 78 78
+250 250 250  162 146 182  207 201 219  222 223 236  229 231 235  173 173 174
+38 38 38  194 193 197  189 183 204  146 139 165  137 128 178  147 132 180
+136 121 175  105 86 155  88 65 130  93 70 140  93 70 140  88 65 130
+88 65 130  88 65 130  88 65 130  105 86 155  102 82 152  88 65 130
+86 66 120  88 65 130  82 70 114  92 71 128  99 78 147  127 106 167
+126 102 165  126 102 165  127 110 169  226 218 234  14 14 14  22 22 22
+26 26 26  18 18 17  6 6 6  2 2 6  2 2 2  82 82 82
+54 54 55  18 18 17  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  26 26 26  62 62 62  107 107 108
+74 54 14  186 134 10  216 162 10  122 94 10  6 6 6  62 62 62
+239 238 242  170 156 193  155 141 181  200 193 212  222 223 236  229 231 235
+134 133 135  198 200 208  194 193 197  183 174 199  152 152 152  136 121 175
+142 128 179  142 128 179  117 98 162  88 65 130  88 65 130  93 70 140
+88 65 130  99 78 147  109 90 154  114 90 155  95 75 136  86 66 120
+92 71 128  88 65 130  92 71 128  95 75 136  103 83 144  120 106 166
+127 106 167  127 110 169  155 141 181  160 158 162  2 2 2  2 2 2
+6 6 6  18 18 17  66 66 66  38 38 38  6 6 6  94 94 94
+50 50 50  18 18 17  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  6 6 6
+10 10 10  10 10 10  18 18 17  38 38 38  78 78 78  132 131 125
+218 158 10  242 186 14  246 190 14  246 190 14  158 118 10  10 10 10
+90 90 90  226 218 234  166 150 188  157 140 187  189 183 204  216 211 227
+229 231 235  219 220 223  173 173 174  74 74 74  189 183 204  169 165 179
+134 120 165  136 121 175  137 128 178  127 110 169  93 70 140  88 65 130
+102 82 152  113 86 148  114 90 155  114 90 155  92 71 128  86 66 120
+92 71 128  95 75 136  92 71 128  95 75 136  117 98 162  127 106 167
+127 110 169  177 162 197  6 2 7  6 2 7  2 2 6  2 2 6
+2 2 6  2 2 6  38 38 38  46 46 46  22 22 22  107 107 108
+54 54 55  18 18 17  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  6 6 6  14 14 14  22 22 22
+30 30 30  38 38 38  50 50 50  70 70 70  107 107 108  190 142 34
+226 171 11  242 186 14  246 190 14  246 190 14  246 190 14  154 114 10
+6 6 6  74 74 74  236 233 239  136 121 175  157 140 187  177 162 197
+216 211 227  236 233 239  209 208 212  66 66 66  169 165 179  194 193 197
+177 168 195  138 131 154  136 121 175  137 128 178  127 106 167  102 82 152
+109 90 154  109 90 154  109 90 154  116 94 159  99 78 147  86 66 120
+92 71 128  95 75 136  103 83 144  116 94 159  127 106 167  134 120 165
+196 186 211  44 31 8  2 2 2  2 2 6  2 2 6  2 2 6
+2 2 6  6 6 6  30 30 30  26 26 26  204 166 16  154 142 90
+66 66 66  26 26 26  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  18 18 17  38 38 38  58 58 58
+78 78 78  87 86 85  102 98 90  121 121 122  174 146 62  210 150 10
+231 174 11  246 186 14  246 190 14  246 190 14  246 186 14  234 193 17
+101 78 10  2 2 6  46 46 46  215 214 215  177 168 195  148 140 189
+158 147 190  222 223 236  239 238 242  215 214 215  215 214 215  185 185 187
+122 122 130  183 174 199  138 131 154  136 121 175  127 110 169  113 86 148
+109 90 154  114 90 155  116 94 159  122 98 164  99 78 147  95 75 136
+87 78 126  118 78 130  116 94 159  122 98 164  136 121 175  213 206 226
+204 166 16  18 18 17  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  6 6 6  122 94 10  236 202 20  234 193 17
+82 82 82  34 34 34  10 10 10  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  14 14 14  38 38 38  70 70 70  154 122 54
+190 142 34  204 146 10  198 138 10  198 138 10  214 154 10  226 171 11
+242 186 14  246 190 14  246 190 14  246 190 14  246 190 14  246 186 14
+226 171 11  44 31 8  6 2 7  22 22 22  160 158 162  200 193 212
+157 140 187  157 140 187  207 201 219  209 208 212  222 223 236  194 193 197
+30 30 30  146 139 165  146 139 165  134 120 165  134 114 171  114 90 155
+116 94 159  122 98 164  122 98 164  122 98 164  111 77 141  92 71 128
+109 90 154  122 98 164  126 102 165  142 128 179  229 226 233  242 186 14
+214 154 10  44 31 8  2 2 2  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  63 43 6  231 174 11  234 193 17  238 183 13
+114 102 78  38 38 38  14 14 14  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  6 6 6  22 22 22  54 54 55  154 122 54  214 154 10
+226 171 11  231 174 11  226 171 11  226 171 11  238 178 14  242 186 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+242 198 14  188 146 14  10 10 10  6 2 7  6 2 7  118 118 118
+216 211 227  157 140 187  154 134 184  183 174 199  215 214 215  222 223 236
+169 165 179  173 173 174  138 131 154  128 114 172  134 120 165  116 94 159
+122 98 164  122 98 164  121 102 164  126 102 165  103 83 144  116 94 159
+127 106 167  127 106 167  154 134 184  236 233 239  238 178 14  238 178 14
+210 150 10  138 93 6  14 14 14  2 2 6  2 2 6  2 2 6
+6 6 6  63 43 6  198 138 10  238 178 14  238 178 14  238 183 13
+126 114 90  58 58 58  22 22 22  6 6 6  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  10 10 10  30 30 30  70 70 70  179 134 43  226 171 11
+238 183 13  242 186 14  242 186 14  246 186 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  234 193 17  94 70 30  2 2 2  2 2 6  2 2 6
+66 66 66  229 226 233  170 156 193  147 132 180  170 156 193  207 201 219
+219 220 223  219 220 223  138 131 154  128 114 172  134 114 171  117 98 162
+121 102 164  121 102 164  121 102 164  120 106 166  116 94 159  127 106 167
+128 114 172  169 165 179  160 158 162  214 166 58  231 174 11  231 174 11
+218 158 10  194 134 10  160 108 10  118 82 10  101 78 10  118 82 10
+166 114 6  198 138 10  226 171 11  238 183 13  242 186 14  242 186 14
+162 146 94  78 78 78  34 34 34  14 14 14  6 6 6  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  6 6 6  30 30 30  78 78 78  190 142 34  226 166 10
+238 183 13  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  242 198 14  204 166 16  18 18 17  2 2 6  2 2 6
+2 2 6  38 38 38  160 158 162  177 168 195  142 134 183  155 141 181
+200 193 212  222 223 236  146 139 165  128 114 172  136 121 175  122 98 164
+122 98 164  122 98 164  126 102 165  114 90 155  122 98 164  128 114 172
+196 186 211  210 206 186  200 193 212  206 162 42  226 171 11  238 178 14
+226 166 10  204 146 10  204 146 10  194 134 10  186 134 10  198 138 10
+210 150 10  231 174 11  242 186 14  246 190 14  246 190 14  242 186 14
+226 171 11  126 114 90  62 62 62  30 30 30  14 14 14  6 6 6
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  10 10 10  30 30 30  78 78 78  179 134 43  226 166 10
+238 183 13  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  242 198 14  138 102 14  2 2 6  2 2 6
+2 2 6  2 2 6  78 78 78  250 250 250  196 186 211  147 132 180
+154 134 184  207 201 219  169 165 179  136 121 175  136 121 175  122 98 164
+126 102 165  122 98 164  114 90 155  121 102 164  134 120 165  213 206 226
+250 250 250  219 220 223  194 193 197  190 150 46  216 162 10  238 178 14
+231 174 11  226 166 10  218 158 10  214 154 10  214 154 10  218 158 10
+226 171 11  238 183 13  246 190 14  246 190 14  246 190 14  246 190 14
+242 186 14  206 162 42  102 98 90  58 58 58  30 30 30  14 14 14
+6 6 6  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  10 10 10  30 30 30  74 74 74  179 134 43  218 158 10
+238 178 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 186 14  242 198 14  226 186 14  63 43 6  2 2 6
+2 2 6  2 2 6  22 22 22  239 238 242  254 254 254  213 206 226
+157 140 187  147 132 180  155 141 181  136 121 175  136 121 175  121 102 164
+117 98 162  116 94 159  127 106 167  147 126 185  226 218 234  250 250 250
+250 250 250  222 223 236  190 190 190  179 134 43  218 158 10  238 178 14
+238 183 13  238 178 14  231 174 11  226 166 10  226 171 11  231 174 11
+238 178 14  242 186 14  246 190 14  246 190 14  246 190 14  246 190 14
+238 183 13  238 183 13  206 162 42  107 107 108  66 66 66  34 34 34
+14 14 14  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  6 6 6  26 26 26  70 70 70  162 134 66  210 150 10
+238 178 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 186 14  234 193 17  188 146 14  14 14 14
+2 2 6  2 2 6  46 46 46  246 246 246  254 254 254  254 254 254
+229 226 233  157 140 187  147 132 180  136 121 175  127 110 169  116 94 159
+121 102 164  121 102 164  162 146 182  236 233 239  254 254 254  254 254 254
+254 254 254  219 220 223  87 86 85  160 108 10  218 158 10  238 178 14
+242 186 14  246 186 14  242 186 14  238 183 13  238 183 13  242 186 14
+242 186 14  242 186 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  242 186 14  226 171 11  142 122 74  66 66 66
+30 30 30  10 10 10  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  6 6 6  26 26 26  70 70 70  162 134 66  210 150 10
+238 178 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  234 193 17  122 94 10
+30 30 30  107 107 108  219 220 223  254 254 254  250 250 250  250 250 250
+250 250 250  216 211 227  118 106 138  147 132 180  134 114 171  126 102 165
+127 106 167  177 168 195  250 250 250  254 254 254  254 254 254  254 254 254
+242 242 242  82 82 82  14 14 14  160 108 10  218 158 10  238 178 14
+242 186 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  238 183 13  162 134 66
+46 46 46  18 18 17  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  10 10 10  30 30 30  78 78 78  162 134 66  210 150 10
+238 178 14  242 186 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  242 198 14  214 174 14
+186 174 146  254 254 254  254 254 254  254 254 254  254 254 254  254 254 254
+254 254 254  250 250 250  250 250 250  196 186 211  136 121 175  134 114 171
+200 193 212  254 254 254  254 254 254  254 254 254  250 250 250  219 220 223
+58 58 58  2 2 2  18 18 17  166 114 6  218 158 10  231 174 11
+246 186 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 186 14  242 186 14  190 150 46
+54 54 55  22 22 22  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  14 14 14  38 38 38  87 86 85  179 134 43  214 154 10
+238 178 14  246 186 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  234 193 17
+188 146 14  215 214 215  250 250 250  254 254 254  254 254 254  254 254 254
+254 254 254  254 254 254  254 254 254  250 250 250  216 211 227  226 218 234
+250 250 250  254 254 254  254 254 254  250 250 250  173 173 174  26 26 26
+2 2 2  2 2 2  44 31 8  160 108 10  216 162 10  242 186 14
+246 186 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  238 178 14  226 166 10  142 122 74
+46 46 46  18 18 17  6 6 6  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+6 6 6  18 18 17  50 50 50  107 107 108  186 134 10  226 166 10
+242 186 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  226 186 14
+216 162 10  141 110 47  229 226 233  254 254 254  254 254 254  250 250 250
+254 254 254  254 254 254  254 254 254  250 250 250  250 250 250  254 254 254
+254 254 254  250 250 250  199 199 199  62 62 62  2 2 2  2 2 2
+2 2 2  2 2 6  44 31 8  160 108 10  216 162 10  238 183 13
+246 186 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  242 186 14  231 174 11  214 154 10  154 122 54  66 66 66
+30 30 30  10 10 10  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+6 6 6  22 22 22  54 54 55  154 122 54  204 146 10  231 174 11
+242 186 14  246 186 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  242 186 14  238 178 14
+216 162 10  160 108 10  63 43 6  134 133 135  219 220 223  250 250 250
+254 254 254  254 254 254  254 254 254  250 250 250  242 242 242  209 208 212
+141 139 143  66 66 66  6 6 6  6 2 7  2 2 6  2 2 6
+2 2 6  2 2 2  63 43 6  160 108 10  218 158 10  238 178 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  238 183 13
+231 174 11  218 158 10  190 142 34  126 114 90  70 70 70  38 38 38
+18 18 17  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+6 6 6  22 22 22  62 62 62  164 122 42  204 146 10  226 166 10
+238 178 14  238 183 13  238 183 13  242 186 14  246 186 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  238 178 14
+216 162 10  173 119 7  82 54 6  2 2 2  6 6 6  30 30 30
+54 54 55  62 62 62  50 50 50  38 38 38  18 18 17  6 6 6
+6 2 2  2 2 2  2 2 2  2 2 6  2 2 6  2 2 6
+2 2 6  6 6 6  82 54 6  166 114 6  214 154 10  238 178 14
+246 190 14  246 190 14  246 190 14  246 190 14  246 190 14  246 190 14
+246 190 14  246 190 14  238 183 13  238 183 13  226 171 11  210 150 10
+179 134 43  126 114 90  78 78 78  50 50 50  34 34 34  18 18 17
+6 6 6  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+6 6 6  18 18 17  46 46 46  164 122 42  194 134 10  198 138 10
+218 158 10  216 162 10  226 166 10  226 171 11  231 174 11  238 178 14
+238 183 13  238 183 13  242 186 14  246 186 14  246 190 14  246 190 14
+246 190 14  246 190 14  246 190 14  246 190 14  242 186 14  231 174 11
+210 150 10  160 108 10  104 70 6  10 10 10  6 2 2  2 2 2
+2 2 2  2 2 2  6 2 2  6 2 2  2 2 2  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  6 6 6  90 62 6  166 114 6  204 146 10  231 174 11
+242 186 14  246 190 14  246 190 14  246 190 14  246 186 14  242 186 14
+238 183 13  231 174 11  226 166 10  214 154 10  179 134 43  126 114 90
+87 86 85  58 58 58  38 38 38  22 22 22  10 10 10  6 6 6
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  14 14 14  34 34 34  66 66 66  141 110 47  158 118 10
+166 114 6  182 122 6  186 134 10  198 138 10  204 146 10  204 146 10
+210 150 10  216 162 10  226 166 10  231 174 11  238 183 13  246 186 14
+246 186 14  246 186 14  246 186 14  246 186 14  238 183 13  218 158 10
+186 134 10  154 98 6  104 70 6  14 14 14  2 2 2  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  2 2 6  2 2 6  2 2 6  2 2 6  2 2 6
+2 2 6  6 6 6  82 54 6  154 98 6  186 134 10  216 162 10
+238 178 14  238 183 13  246 186 14  242 186 14  238 183 13  231 174 11
+226 166 10  204 146 10  186 134 10  154 122 54  90 90 90  62 62 62
+42 42 42  22 22 22  14 14 14  6 6 6  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  6 6 6  18 18 17  34 34 34  62 62 62  78 78 78
+102 98 90  126 114 90  141 110 47  160 108 10  160 108 10  166 114 6
+173 119 7  182 122 6  186 134 10  198 138 10  210 150 10  216 162 10
+226 171 11  238 178 14  238 178 14  231 174 11  216 162 10  198 138 10
+160 108 10  127 82 6  90 62 6  10 10 10  2 2 6  2 2 6
+18 18 17  38 38 38  38 38 38  38 38 38  38 38 38  38 38 38
+38 38 38  38 38 38  38 38 38  38 38 38  26 26 26  2 2 6
+2 2 2  6 6 6  63 43 6  138 93 6  173 119 7  204 146 10
+216 162 10  231 174 11  231 174 11  231 174 11  216 162 10  210 150 10
+186 134 10  160 108 10  126 114 90  82 82 82  50 50 50  30 30 30
+14 14 14  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  14 14 14  22 22 22  34 34 34
+42 42 42  58 58 58  74 74 74  87 86 85  102 98 90  122 102 70
+124 98 46  122 86 26  138 93 6  154 98 6  160 108 10  182 122 6
+186 134 10  194 134 10  204 146 10  204 146 10  182 122 6  160 108 10
+134 86 6  104 70 6  44 31 8  54 54 55  107 107 108  102 98 90
+87 86 85  82 82 82  78 78 78  78 78 78  78 78 78  78 78 78
+78 78 78  78 78 78  78 78 78  82 82 82  87 86 85  94 94 94
+107 107 108  104 103 100  85 65 33  127 82 6  160 108 10  182 122 6
+186 134 10  204 146 10  204 146 10  204 146 10  194 134 10  173 119 7
+154 98 6  107 107 108  66 66 66  42 42 42  22 22 22  10 10 10
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  6 6 6  10 10 10
+14 14 14  22 22 22  30 30 30  38 38 38  50 50 50  62 62 62
+74 74 74  90 90 90  102 98 90  114 102 78  122 86 26  127 82 6
+138 93 6  154 98 6  154 98 6  154 98 6  134 86 6  118 82 10
+104 70 6  85 65 33  102 98 90  82 82 82  58 58 58  46 46 46
+38 38 38  34 34 34  34 34 34  34 34 34  34 34 34  34 34 34
+34 34 34  34 34 34  34 34 34  34 34 34  38 38 38  42 42 42
+54 54 55  82 82 82  91 83 66  90 62 6  127 82 6  160 108 10
+166 114 6  166 114 6  173 119 7  166 114 6  154 98 6  122 86 26
+102 98 90  62 62 62  34 34 34  18 18 17  6 6 6  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  6 6 6  6 6 6  10 10 10  18 18 17  22 22 22
+30 30 30  42 42 42  50 50 50  70 70 70  87 86 85  102 98 90
+104 84 56  104 70 6  104 70 6  104 70 6  104 70 6  90 62 6
+82 54 6  94 94 94  62 62 62  38 38 38  22 22 22  14 14 14
+10 10 10  10 10 10  10 10 10  10 10 10  10 10 10  10 10 10
+6 6 6  10 10 10  10 10 10  10 10 10  10 10 10  14 14 14
+22 22 22  42 42 42  70 70 70  91 83 66  82 54 6  104 70 6
+127 82 6  138 93 6  134 86 6  118 82 10  104 84 56  87 86 85
+58 58 58  30 30 30  14 14 14  6 6 6  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  6 6 6
+10 10 10  14 14 14  18 18 17  26 26 26  38 38 38  54 54 55
+74 74 74  87 86 85  91 83 66  91 83 66  91 83 66  87 86 85
+78 78 78  50 50 50  30 30 30  14 14 14  6 6 6  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+6 6 6  18 18 17  34 34 34  58 58 58  78 78 78  78 78 78
+91 83 66  91 83 66  91 83 66  91 83 66  74 74 74  50 50 50
+26 26 26  14 14 14  10 6 18  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  6 6 6  6 6 6  14 14 14  18 18 17
+30 30 30  38 38 38  46 46 46  50 50 50  46 46 46  42 42 42
+30 30 30  18 18 17  10 10 10  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  6 6 6  14 14 14  26 26 26  38 38 38  50 50 50
+54 54 55  58 58 58  54 54 55  42 42 42  30 30 30  18 18 17
+10 10 10  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  6 6 6
+6 6 6  10 10 10  14 14 14  18 18 17  18 18 17  14 14 14
+10 10 10  6 6 6  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  6 6 6  14 14 14  18 18 17
+22 22 22  22 22 22  18 18 17  14 14 14  10 10 10  6 6 6
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2  2 2 2  2 2 2  2 2 2  2 2 2
+2 2 2  2 2 2
diff --git a/include/linux/linux_logo.h b/include/linux/linux_logo.h
index d4d5b93..16b7956 100644
--- a/include/linux/linux_logo.h
+++ b/include/linux/linux_logo.h
@@ -37,6 +37,7 @@ extern const struct linux_logo logo_linux_mono;
 extern const struct linux_logo logo_linux_vga16;
 extern const struct linux_logo logo_linux_clut224;
 extern const struct linux_logo logo_dec_clut224;
+extern const struct linux_logo logo_gcn_clut224;
 extern const struct linux_logo logo_mac_clut224;
 extern const struct linux_logo logo_parisc_clut224;
 extern const struct linux_logo logo_sgi_clut224;
diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h
index 3a49913..5100222 100644
--- a/include/uapi/linux/fb.h
+++ b/include/uapi/linux/fb.h
@@ -36,6 +36,12 @@
 #define FBIOGET_DISPINFO        0x4618
 #define FBIO_WAITFORVSYNC	_IOW('F', 0x20, __u32)
 
+#define FBIOWAITRETRACE         0x4619
+#define FBIOWAITPEFINISH        0x4620
+#define FBIOVIRTTOPHYS          0x4621
+#define FBIOFLIP                0x4622
+#define FBIOFLIPHACK            0x4623 /* libsdl */
+
 #define FB_TYPE_PACKED_PIXELS		0	/* Packed Pixels	*/
 #define FB_TYPE_PLANES			1	/* Non interleaved planes */
 #define FB_TYPE_INTERLEAVED_PLANES	2	/* Interleaved planes	*/