18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Card specific code is based on XFree86's neomagic driver.
88c2ecf20Sopenharmony_ci * Framebuffer framework code is based on code of cyber2000fb.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General
118c2ecf20Sopenharmony_ci * Public License.  See the file COPYING in the main directory of this
128c2ecf20Sopenharmony_ci * archive for more details.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * 0.4.1
168c2ecf20Sopenharmony_ci *  - Cosmetic changes (dok)
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * 0.4
198c2ecf20Sopenharmony_ci *  - Toshiba Libretto support, allow modes larger than LCD size if
208c2ecf20Sopenharmony_ci *    LCD is disabled, keep BIOS settings if internal/external display
218c2ecf20Sopenharmony_ci *    haven't been enabled explicitly
228c2ecf20Sopenharmony_ci *                          (Thomas J. Moore <dark@mama.indstate.edu>)
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * 0.3.3
258c2ecf20Sopenharmony_ci *  - Porting over to new fbdev api. (jsimmons)
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * 0.3.2
288c2ecf20Sopenharmony_ci *  - got rid of all floating point (dok)
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * 0.3.1
318c2ecf20Sopenharmony_ci *  - added module license (dok)
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * 0.3
348c2ecf20Sopenharmony_ci *  - hardware accelerated clear and move for 2200 and above (dok)
358c2ecf20Sopenharmony_ci *  - maximum allowed dotclock is handled now (dok)
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * 0.2.1
388c2ecf20Sopenharmony_ci *  - correct panning after X usage (dok)
398c2ecf20Sopenharmony_ci *  - added module and kernel parameters (dok)
408c2ecf20Sopenharmony_ci *  - no stretching if external display is enabled (dok)
418c2ecf20Sopenharmony_ci *
428c2ecf20Sopenharmony_ci * 0.2
438c2ecf20Sopenharmony_ci *  - initial version (dok)
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * TODO
478c2ecf20Sopenharmony_ci * - ioctl for internal/external switching
488c2ecf20Sopenharmony_ci * - blanking
498c2ecf20Sopenharmony_ci * - 32bit depth support, maybe impossible
508c2ecf20Sopenharmony_ci * - disable pan-on-sync, need specs
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci * BUGS
538c2ecf20Sopenharmony_ci * - white margin on bootup like with tdfxfb (colormap problem?)
548c2ecf20Sopenharmony_ci *
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#include <linux/module.h>
588c2ecf20Sopenharmony_ci#include <linux/kernel.h>
598c2ecf20Sopenharmony_ci#include <linux/errno.h>
608c2ecf20Sopenharmony_ci#include <linux/string.h>
618c2ecf20Sopenharmony_ci#include <linux/mm.h>
628c2ecf20Sopenharmony_ci#include <linux/slab.h>
638c2ecf20Sopenharmony_ci#include <linux/delay.h>
648c2ecf20Sopenharmony_ci#include <linux/fb.h>
658c2ecf20Sopenharmony_ci#include <linux/pci.h>
668c2ecf20Sopenharmony_ci#include <linux/init.h>
678c2ecf20Sopenharmony_ci#ifdef CONFIG_TOSHIBA
688c2ecf20Sopenharmony_ci#include <linux/toshiba.h>
698c2ecf20Sopenharmony_ci#endif
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#include <asm/io.h>
728c2ecf20Sopenharmony_ci#include <asm/irq.h>
738c2ecf20Sopenharmony_ci#include <video/vga.h>
748c2ecf20Sopenharmony_ci#include <video/neomagic.h>
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define NEOFB_VERSION "0.4.2"
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic bool internal;
818c2ecf20Sopenharmony_cistatic bool external;
828c2ecf20Sopenharmony_cistatic bool libretto;
838c2ecf20Sopenharmony_cistatic bool nostretch;
848c2ecf20Sopenharmony_cistatic bool nopciburst;
858c2ecf20Sopenharmony_cistatic char *mode_option = NULL;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#ifdef MODULE
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ciMODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@convergence.de>");
908c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
928c2ecf20Sopenharmony_cimodule_param(internal, bool, 0);
938c2ecf20Sopenharmony_ciMODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
948c2ecf20Sopenharmony_cimodule_param(external, bool, 0);
958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(external, "Enable output on external CRT.");
968c2ecf20Sopenharmony_cimodule_param(libretto, bool, 0);
978c2ecf20Sopenharmony_ciMODULE_PARM_DESC(libretto, "Force Libretto 100/110 800x480 LCD.");
988c2ecf20Sopenharmony_cimodule_param(nostretch, bool, 0);
998c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nostretch,
1008c2ecf20Sopenharmony_ci		 "Disable stretching of modes smaller than LCD.");
1018c2ecf20Sopenharmony_cimodule_param(nopciburst, bool, 0);
1028c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
1038c2ecf20Sopenharmony_cimodule_param(mode_option, charp, 0);
1048c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Preferred video mode ('640x480-8@60', etc)");
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci#endif
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic biosMode bios8[] = {
1128c2ecf20Sopenharmony_ci	{320, 240, 0x40},
1138c2ecf20Sopenharmony_ci	{300, 400, 0x42},
1148c2ecf20Sopenharmony_ci	{640, 400, 0x20},
1158c2ecf20Sopenharmony_ci	{640, 480, 0x21},
1168c2ecf20Sopenharmony_ci	{800, 600, 0x23},
1178c2ecf20Sopenharmony_ci	{1024, 768, 0x25},
1188c2ecf20Sopenharmony_ci};
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic biosMode bios16[] = {
1218c2ecf20Sopenharmony_ci	{320, 200, 0x2e},
1228c2ecf20Sopenharmony_ci	{320, 240, 0x41},
1238c2ecf20Sopenharmony_ci	{300, 400, 0x43},
1248c2ecf20Sopenharmony_ci	{640, 480, 0x31},
1258c2ecf20Sopenharmony_ci	{800, 600, 0x34},
1268c2ecf20Sopenharmony_ci	{1024, 768, 0x37},
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic biosMode bios24[] = {
1308c2ecf20Sopenharmony_ci	{640, 480, 0x32},
1318c2ecf20Sopenharmony_ci	{800, 600, 0x35},
1328c2ecf20Sopenharmony_ci	{1024, 768, 0x38}
1338c2ecf20Sopenharmony_ci};
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET
1368c2ecf20Sopenharmony_ci/* FIXME: guessed values, wrong */
1378c2ecf20Sopenharmony_cistatic biosMode bios32[] = {
1388c2ecf20Sopenharmony_ci	{640, 480, 0x33},
1398c2ecf20Sopenharmony_ci	{800, 600, 0x36},
1408c2ecf20Sopenharmony_ci	{1024, 768, 0x39}
1418c2ecf20Sopenharmony_ci};
1428c2ecf20Sopenharmony_ci#endif
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic inline void write_le32(int regindex, u32 val, const struct neofb_par *par)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	writel(val, par->neo2200 + par->cursorOff + regindex);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int neoFindMode(int xres, int yres, int depth)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	int xres_s;
1528c2ecf20Sopenharmony_ci	int i, size;
1538c2ecf20Sopenharmony_ci	biosMode *mode;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	switch (depth) {
1568c2ecf20Sopenharmony_ci	case 8:
1578c2ecf20Sopenharmony_ci		size = ARRAY_SIZE(bios8);
1588c2ecf20Sopenharmony_ci		mode = bios8;
1598c2ecf20Sopenharmony_ci		break;
1608c2ecf20Sopenharmony_ci	case 16:
1618c2ecf20Sopenharmony_ci		size = ARRAY_SIZE(bios16);
1628c2ecf20Sopenharmony_ci		mode = bios16;
1638c2ecf20Sopenharmony_ci		break;
1648c2ecf20Sopenharmony_ci	case 24:
1658c2ecf20Sopenharmony_ci		size = ARRAY_SIZE(bios24);
1668c2ecf20Sopenharmony_ci		mode = bios24;
1678c2ecf20Sopenharmony_ci		break;
1688c2ecf20Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET
1698c2ecf20Sopenharmony_ci	case 32:
1708c2ecf20Sopenharmony_ci		size = ARRAY_SIZE(bios32);
1718c2ecf20Sopenharmony_ci		mode = bios32;
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci#endif
1748c2ecf20Sopenharmony_ci	default:
1758c2ecf20Sopenharmony_ci		return 0;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++) {
1798c2ecf20Sopenharmony_ci		if (xres <= mode[i].x_res) {
1808c2ecf20Sopenharmony_ci			xres_s = mode[i].x_res;
1818c2ecf20Sopenharmony_ci			for (; i < size; i++) {
1828c2ecf20Sopenharmony_ci				if (mode[i].x_res != xres_s)
1838c2ecf20Sopenharmony_ci					return mode[i - 1].mode;
1848c2ecf20Sopenharmony_ci				if (yres <= mode[i].y_res)
1858c2ecf20Sopenharmony_ci					return mode[i].mode;
1868c2ecf20Sopenharmony_ci			}
1878c2ecf20Sopenharmony_ci		}
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci	return mode[size - 1].mode;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/*
1938c2ecf20Sopenharmony_ci * neoCalcVCLK --
1948c2ecf20Sopenharmony_ci *
1958c2ecf20Sopenharmony_ci * Determine the closest clock frequency to the one requested.
1968c2ecf20Sopenharmony_ci */
1978c2ecf20Sopenharmony_ci#define MAX_N 127
1988c2ecf20Sopenharmony_ci#define MAX_D 31
1998c2ecf20Sopenharmony_ci#define MAX_F 1
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic void neoCalcVCLK(const struct fb_info *info,
2028c2ecf20Sopenharmony_ci			struct neofb_par *par, long freq)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	int n, d, f;
2058c2ecf20Sopenharmony_ci	int n_best = 0, d_best = 0, f_best = 0;
2068c2ecf20Sopenharmony_ci	long f_best_diff = 0x7ffff;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	for (f = 0; f <= MAX_F; f++)
2098c2ecf20Sopenharmony_ci		for (d = 0; d <= MAX_D; d++)
2108c2ecf20Sopenharmony_ci			for (n = 0; n <= MAX_N; n++) {
2118c2ecf20Sopenharmony_ci				long f_out;
2128c2ecf20Sopenharmony_ci				long f_diff;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci				f_out = ((14318 * (n + 1)) / (d + 1)) >> f;
2158c2ecf20Sopenharmony_ci				f_diff = abs(f_out - freq);
2168c2ecf20Sopenharmony_ci				if (f_diff <= f_best_diff) {
2178c2ecf20Sopenharmony_ci					f_best_diff = f_diff;
2188c2ecf20Sopenharmony_ci					n_best = n;
2198c2ecf20Sopenharmony_ci					d_best = d;
2208c2ecf20Sopenharmony_ci					f_best = f;
2218c2ecf20Sopenharmony_ci				}
2228c2ecf20Sopenharmony_ci				if (f_out > freq)
2238c2ecf20Sopenharmony_ci					break;
2248c2ecf20Sopenharmony_ci			}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
2278c2ecf20Sopenharmony_ci	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
2288c2ecf20Sopenharmony_ci	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
2298c2ecf20Sopenharmony_ci	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
2308c2ecf20Sopenharmony_ci		/* NOT_DONE:  We are trying the full range of the 2200 clock.
2318c2ecf20Sopenharmony_ci		   We should be able to try n up to 2047 */
2328c2ecf20Sopenharmony_ci		par->VCLK3NumeratorLow = n_best;
2338c2ecf20Sopenharmony_ci		par->VCLK3NumeratorHigh = (f_best << 7);
2348c2ecf20Sopenharmony_ci	} else
2358c2ecf20Sopenharmony_ci		par->VCLK3NumeratorLow = n_best | (f_best << 7);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	par->VCLK3Denominator = d_best;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci#ifdef NEOFB_DEBUG
2408c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "neoVCLK: f:%ld NumLow=%d NumHi=%d Den=%d Df=%ld\n",
2418c2ecf20Sopenharmony_ci	       freq,
2428c2ecf20Sopenharmony_ci	       par->VCLK3NumeratorLow,
2438c2ecf20Sopenharmony_ci	       par->VCLK3NumeratorHigh,
2448c2ecf20Sopenharmony_ci	       par->VCLK3Denominator, f_best_diff);
2458c2ecf20Sopenharmony_ci#endif
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/*
2498c2ecf20Sopenharmony_ci * vgaHWInit --
2508c2ecf20Sopenharmony_ci *      Handle the initialization, etc. of a screen.
2518c2ecf20Sopenharmony_ci *      Return FALSE on failure.
2528c2ecf20Sopenharmony_ci */
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int vgaHWInit(const struct fb_var_screeninfo *var,
2558c2ecf20Sopenharmony_ci		     struct neofb_par *par)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	int hsync_end = var->xres + var->right_margin + var->hsync_len;
2588c2ecf20Sopenharmony_ci	int htotal = (hsync_end + var->left_margin) >> 3;
2598c2ecf20Sopenharmony_ci	int vsync_start = var->yres + var->lower_margin;
2608c2ecf20Sopenharmony_ci	int vsync_end = vsync_start + var->vsync_len;
2618c2ecf20Sopenharmony_ci	int vtotal = vsync_end + var->upper_margin;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	par->MiscOutReg = 0x23;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
2668c2ecf20Sopenharmony_ci		par->MiscOutReg |= 0x40;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
2698c2ecf20Sopenharmony_ci		par->MiscOutReg |= 0x80;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/*
2728c2ecf20Sopenharmony_ci	 * Time Sequencer
2738c2ecf20Sopenharmony_ci	 */
2748c2ecf20Sopenharmony_ci	par->Sequencer[0] = 0x00;
2758c2ecf20Sopenharmony_ci	par->Sequencer[1] = 0x01;
2768c2ecf20Sopenharmony_ci	par->Sequencer[2] = 0x0F;
2778c2ecf20Sopenharmony_ci	par->Sequencer[3] = 0x00;	/* Font select */
2788c2ecf20Sopenharmony_ci	par->Sequencer[4] = 0x0E;	/* Misc */
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/*
2818c2ecf20Sopenharmony_ci	 * CRTC Controller
2828c2ecf20Sopenharmony_ci	 */
2838c2ecf20Sopenharmony_ci	par->CRTC[0] = htotal - 5;
2848c2ecf20Sopenharmony_ci	par->CRTC[1] = (var->xres >> 3) - 1;
2858c2ecf20Sopenharmony_ci	par->CRTC[2] = (var->xres >> 3) - 1;
2868c2ecf20Sopenharmony_ci	par->CRTC[3] = ((htotal - 1) & 0x1F) | 0x80;
2878c2ecf20Sopenharmony_ci	par->CRTC[4] = ((var->xres + var->right_margin) >> 3);
2888c2ecf20Sopenharmony_ci	par->CRTC[5] = (((htotal - 1) & 0x20) << 2)
2898c2ecf20Sopenharmony_ci	    | (((hsync_end >> 3)) & 0x1F);
2908c2ecf20Sopenharmony_ci	par->CRTC[6] = (vtotal - 2) & 0xFF;
2918c2ecf20Sopenharmony_ci	par->CRTC[7] = (((vtotal - 2) & 0x100) >> 8)
2928c2ecf20Sopenharmony_ci	    | (((var->yres - 1) & 0x100) >> 7)
2938c2ecf20Sopenharmony_ci	    | ((vsync_start & 0x100) >> 6)
2948c2ecf20Sopenharmony_ci	    | (((var->yres - 1) & 0x100) >> 5)
2958c2ecf20Sopenharmony_ci	    | 0x10 | (((vtotal - 2) & 0x200) >> 4)
2968c2ecf20Sopenharmony_ci	    | (((var->yres - 1) & 0x200) >> 3)
2978c2ecf20Sopenharmony_ci	    | ((vsync_start & 0x200) >> 2);
2988c2ecf20Sopenharmony_ci	par->CRTC[8] = 0x00;
2998c2ecf20Sopenharmony_ci	par->CRTC[9] = (((var->yres - 1) & 0x200) >> 4) | 0x40;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_DOUBLE)
3028c2ecf20Sopenharmony_ci		par->CRTC[9] |= 0x80;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	par->CRTC[10] = 0x00;
3058c2ecf20Sopenharmony_ci	par->CRTC[11] = 0x00;
3068c2ecf20Sopenharmony_ci	par->CRTC[12] = 0x00;
3078c2ecf20Sopenharmony_ci	par->CRTC[13] = 0x00;
3088c2ecf20Sopenharmony_ci	par->CRTC[14] = 0x00;
3098c2ecf20Sopenharmony_ci	par->CRTC[15] = 0x00;
3108c2ecf20Sopenharmony_ci	par->CRTC[16] = vsync_start & 0xFF;
3118c2ecf20Sopenharmony_ci	par->CRTC[17] = (vsync_end & 0x0F) | 0x20;
3128c2ecf20Sopenharmony_ci	par->CRTC[18] = (var->yres - 1) & 0xFF;
3138c2ecf20Sopenharmony_ci	par->CRTC[19] = var->xres_virtual >> 4;
3148c2ecf20Sopenharmony_ci	par->CRTC[20] = 0x00;
3158c2ecf20Sopenharmony_ci	par->CRTC[21] = (var->yres - 1) & 0xFF;
3168c2ecf20Sopenharmony_ci	par->CRTC[22] = (vtotal - 1) & 0xFF;
3178c2ecf20Sopenharmony_ci	par->CRTC[23] = 0xC3;
3188c2ecf20Sopenharmony_ci	par->CRTC[24] = 0xFF;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/*
3218c2ecf20Sopenharmony_ci	 * are these unnecessary?
3228c2ecf20Sopenharmony_ci	 * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
3238c2ecf20Sopenharmony_ci	 * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
3248c2ecf20Sopenharmony_ci	 */
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/*
3278c2ecf20Sopenharmony_ci	 * Graphics Display Controller
3288c2ecf20Sopenharmony_ci	 */
3298c2ecf20Sopenharmony_ci	par->Graphics[0] = 0x00;
3308c2ecf20Sopenharmony_ci	par->Graphics[1] = 0x00;
3318c2ecf20Sopenharmony_ci	par->Graphics[2] = 0x00;
3328c2ecf20Sopenharmony_ci	par->Graphics[3] = 0x00;
3338c2ecf20Sopenharmony_ci	par->Graphics[4] = 0x00;
3348c2ecf20Sopenharmony_ci	par->Graphics[5] = 0x40;
3358c2ecf20Sopenharmony_ci	par->Graphics[6] = 0x05;	/* only map 64k VGA memory !!!! */
3368c2ecf20Sopenharmony_ci	par->Graphics[7] = 0x0F;
3378c2ecf20Sopenharmony_ci	par->Graphics[8] = 0xFF;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	par->Attribute[0] = 0x00;	/* standard colormap translation */
3418c2ecf20Sopenharmony_ci	par->Attribute[1] = 0x01;
3428c2ecf20Sopenharmony_ci	par->Attribute[2] = 0x02;
3438c2ecf20Sopenharmony_ci	par->Attribute[3] = 0x03;
3448c2ecf20Sopenharmony_ci	par->Attribute[4] = 0x04;
3458c2ecf20Sopenharmony_ci	par->Attribute[5] = 0x05;
3468c2ecf20Sopenharmony_ci	par->Attribute[6] = 0x06;
3478c2ecf20Sopenharmony_ci	par->Attribute[7] = 0x07;
3488c2ecf20Sopenharmony_ci	par->Attribute[8] = 0x08;
3498c2ecf20Sopenharmony_ci	par->Attribute[9] = 0x09;
3508c2ecf20Sopenharmony_ci	par->Attribute[10] = 0x0A;
3518c2ecf20Sopenharmony_ci	par->Attribute[11] = 0x0B;
3528c2ecf20Sopenharmony_ci	par->Attribute[12] = 0x0C;
3538c2ecf20Sopenharmony_ci	par->Attribute[13] = 0x0D;
3548c2ecf20Sopenharmony_ci	par->Attribute[14] = 0x0E;
3558c2ecf20Sopenharmony_ci	par->Attribute[15] = 0x0F;
3568c2ecf20Sopenharmony_ci	par->Attribute[16] = 0x41;
3578c2ecf20Sopenharmony_ci	par->Attribute[17] = 0xFF;
3588c2ecf20Sopenharmony_ci	par->Attribute[18] = 0x0F;
3598c2ecf20Sopenharmony_ci	par->Attribute[19] = 0x00;
3608c2ecf20Sopenharmony_ci	par->Attribute[20] = 0x00;
3618c2ecf20Sopenharmony_ci	return 0;
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic void vgaHWLock(struct vgastate *state)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	/* Protect CRTC[0-7] */
3678c2ecf20Sopenharmony_ci	vga_wcrt(state->vgabase, 0x11, vga_rcrt(state->vgabase, 0x11) | 0x80);
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic void vgaHWUnlock(void)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	/* Unprotect CRTC[0-7] */
3738c2ecf20Sopenharmony_ci	vga_wcrt(NULL, 0x11, vga_rcrt(NULL, 0x11) & ~0x80);
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic void neoLock(struct vgastate *state)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	vga_wgfx(state->vgabase, 0x09, 0x00);
3798c2ecf20Sopenharmony_ci	vgaHWLock(state);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void neoUnlock(void)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	vgaHWUnlock();
3858c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x09, 0x26);
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci/*
3898c2ecf20Sopenharmony_ci * VGA Palette management
3908c2ecf20Sopenharmony_ci */
3918c2ecf20Sopenharmony_cistatic int paletteEnabled = 0;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic inline void VGAenablePalette(void)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	vga_r(NULL, VGA_IS1_RC);
3968c2ecf20Sopenharmony_ci	vga_w(NULL, VGA_ATT_W, 0x00);
3978c2ecf20Sopenharmony_ci	paletteEnabled = 1;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic inline void VGAdisablePalette(void)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	vga_r(NULL, VGA_IS1_RC);
4038c2ecf20Sopenharmony_ci	vga_w(NULL, VGA_ATT_W, 0x20);
4048c2ecf20Sopenharmony_ci	paletteEnabled = 0;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic inline void VGAwATTR(u8 index, u8 value)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	if (paletteEnabled)
4108c2ecf20Sopenharmony_ci		index &= ~0x20;
4118c2ecf20Sopenharmony_ci	else
4128c2ecf20Sopenharmony_ci		index |= 0x20;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	vga_r(NULL, VGA_IS1_RC);
4158c2ecf20Sopenharmony_ci	vga_wattr(NULL, index, value);
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic void vgaHWProtect(int on)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	unsigned char tmp;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	tmp = vga_rseq(NULL, 0x01);
4238c2ecf20Sopenharmony_ci	if (on) {
4248c2ecf20Sopenharmony_ci		/*
4258c2ecf20Sopenharmony_ci		 * Turn off screen and disable sequencer.
4268c2ecf20Sopenharmony_ci		 */
4278c2ecf20Sopenharmony_ci		vga_wseq(NULL, 0x00, 0x01);		/* Synchronous Reset */
4288c2ecf20Sopenharmony_ci		vga_wseq(NULL, 0x01, tmp | 0x20);	/* disable the display */
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci		VGAenablePalette();
4318c2ecf20Sopenharmony_ci	} else {
4328c2ecf20Sopenharmony_ci		/*
4338c2ecf20Sopenharmony_ci		 * Reenable sequencer, then turn on screen.
4348c2ecf20Sopenharmony_ci		 */
4358c2ecf20Sopenharmony_ci		vga_wseq(NULL, 0x01, tmp & ~0x20);	/* reenable display */
4368c2ecf20Sopenharmony_ci		vga_wseq(NULL, 0x00, 0x03);		/* clear synchronousreset */
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		VGAdisablePalette();
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic void vgaHWRestore(const struct fb_info *info,
4438c2ecf20Sopenharmony_ci			 const struct neofb_par *par)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	int i;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	vga_w(NULL, VGA_MIS_W, par->MiscOutReg);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	for (i = 1; i < 5; i++)
4508c2ecf20Sopenharmony_ci		vga_wseq(NULL, i, par->Sequencer[i]);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
4538c2ecf20Sopenharmony_ci	vga_wcrt(NULL, 17, par->CRTC[17] & ~0x80);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	for (i = 0; i < 25; i++)
4568c2ecf20Sopenharmony_ci		vga_wcrt(NULL, i, par->CRTC[i]);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	for (i = 0; i < 9; i++)
4598c2ecf20Sopenharmony_ci		vga_wgfx(NULL, i, par->Graphics[i]);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	VGAenablePalette();
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	for (i = 0; i < 21; i++)
4648c2ecf20Sopenharmony_ci		VGAwATTR(i, par->Attribute[i]);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	VGAdisablePalette();
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci/* -------------------- Hardware specific routines ------------------------- */
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci/*
4738c2ecf20Sopenharmony_ci * Hardware Acceleration for Neo2200+
4748c2ecf20Sopenharmony_ci */
4758c2ecf20Sopenharmony_cistatic inline int neo2200_sync(struct fb_info *info)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	while (readl(&par->neo2200->bltStat) & 1)
4808c2ecf20Sopenharmony_ci		cpu_relax();
4818c2ecf20Sopenharmony_ci	return 0;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic inline void neo2200_wait_fifo(struct fb_info *info,
4858c2ecf20Sopenharmony_ci				     int requested_fifo_space)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	//  ndev->neo.waitfifo_calls++;
4888c2ecf20Sopenharmony_ci	//  ndev->neo.waitfifo_sum += requested_fifo_space;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	/* FIXME: does not work
4918c2ecf20Sopenharmony_ci	   if (neo_fifo_space < requested_fifo_space)
4928c2ecf20Sopenharmony_ci	   {
4938c2ecf20Sopenharmony_ci	   neo_fifo_waitcycles++;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	   while (1)
4968c2ecf20Sopenharmony_ci	   {
4978c2ecf20Sopenharmony_ci	   neo_fifo_space = (neo2200->bltStat >> 8);
4988c2ecf20Sopenharmony_ci	   if (neo_fifo_space >= requested_fifo_space)
4998c2ecf20Sopenharmony_ci	   break;
5008c2ecf20Sopenharmony_ci	   }
5018c2ecf20Sopenharmony_ci	   }
5028c2ecf20Sopenharmony_ci	   else
5038c2ecf20Sopenharmony_ci	   {
5048c2ecf20Sopenharmony_ci	   neo_fifo_cache_hits++;
5058c2ecf20Sopenharmony_ci	   }
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	   neo_fifo_space -= requested_fifo_space;
5088c2ecf20Sopenharmony_ci	 */
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	neo2200_sync(info);
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic inline void neo2200_accel_init(struct fb_info *info,
5148c2ecf20Sopenharmony_ci				      struct fb_var_screeninfo *var)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
5178c2ecf20Sopenharmony_ci	Neo2200 __iomem *neo2200 = par->neo2200;
5188c2ecf20Sopenharmony_ci	u32 bltMod, pitch;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	neo2200_sync(info);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	switch (var->bits_per_pixel) {
5238c2ecf20Sopenharmony_ci	case 8:
5248c2ecf20Sopenharmony_ci		bltMod = NEO_MODE1_DEPTH8;
5258c2ecf20Sopenharmony_ci		pitch = var->xres_virtual;
5268c2ecf20Sopenharmony_ci		break;
5278c2ecf20Sopenharmony_ci	case 15:
5288c2ecf20Sopenharmony_ci	case 16:
5298c2ecf20Sopenharmony_ci		bltMod = NEO_MODE1_DEPTH16;
5308c2ecf20Sopenharmony_ci		pitch = var->xres_virtual * 2;
5318c2ecf20Sopenharmony_ci		break;
5328c2ecf20Sopenharmony_ci	case 24:
5338c2ecf20Sopenharmony_ci		bltMod = NEO_MODE1_DEPTH24;
5348c2ecf20Sopenharmony_ci		pitch = var->xres_virtual * 3;
5358c2ecf20Sopenharmony_ci		break;
5368c2ecf20Sopenharmony_ci	default:
5378c2ecf20Sopenharmony_ci		printk(KERN_ERR
5388c2ecf20Sopenharmony_ci		       "neofb: neo2200_accel_init: unexpected bits per pixel!\n");
5398c2ecf20Sopenharmony_ci		return;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	writel(bltMod << 16, &neo2200->bltStat);
5438c2ecf20Sopenharmony_ci	writel((pitch << 16) | pitch, &neo2200->pitch);
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic int
5498c2ecf20Sopenharmony_cineofb_open(struct fb_info *info, int user)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (!par->ref_count) {
5548c2ecf20Sopenharmony_ci		memset(&par->state, 0, sizeof(struct vgastate));
5558c2ecf20Sopenharmony_ci		par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
5568c2ecf20Sopenharmony_ci		save_vga(&par->state);
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci	par->ref_count++;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	return 0;
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_cistatic int
5648c2ecf20Sopenharmony_cineofb_release(struct fb_info *info, int user)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	if (!par->ref_count)
5698c2ecf20Sopenharmony_ci		return -EINVAL;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	if (par->ref_count == 1) {
5728c2ecf20Sopenharmony_ci		restore_vga(&par->state);
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci	par->ref_count--;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	return 0;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic int
5808c2ecf20Sopenharmony_cineofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
5838c2ecf20Sopenharmony_ci	int memlen, vramlen;
5848c2ecf20Sopenharmony_ci	int mode_ok = 0;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	DBG("neofb_check_var");
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (PICOS2KHZ(var->pixclock) > par->maxClock)
5898c2ecf20Sopenharmony_ci		return -EINVAL;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	/* Is the mode larger than the LCD panel? */
5928c2ecf20Sopenharmony_ci	if (par->internal_display &&
5938c2ecf20Sopenharmony_ci            ((var->xres > par->NeoPanelWidth) ||
5948c2ecf20Sopenharmony_ci	     (var->yres > par->NeoPanelHeight))) {
5958c2ecf20Sopenharmony_ci		printk(KERN_INFO
5968c2ecf20Sopenharmony_ci		       "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
5978c2ecf20Sopenharmony_ci		       var->xres, var->yres, par->NeoPanelWidth,
5988c2ecf20Sopenharmony_ci		       par->NeoPanelHeight);
5998c2ecf20Sopenharmony_ci		return -EINVAL;
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	/* Is the mode one of the acceptable sizes? */
6038c2ecf20Sopenharmony_ci	if (!par->internal_display)
6048c2ecf20Sopenharmony_ci		mode_ok = 1;
6058c2ecf20Sopenharmony_ci	else {
6068c2ecf20Sopenharmony_ci		switch (var->xres) {
6078c2ecf20Sopenharmony_ci		case 1280:
6088c2ecf20Sopenharmony_ci			if (var->yres == 1024)
6098c2ecf20Sopenharmony_ci				mode_ok = 1;
6108c2ecf20Sopenharmony_ci			break;
6118c2ecf20Sopenharmony_ci		case 1024:
6128c2ecf20Sopenharmony_ci			if (var->yres == 768)
6138c2ecf20Sopenharmony_ci				mode_ok = 1;
6148c2ecf20Sopenharmony_ci			break;
6158c2ecf20Sopenharmony_ci		case 800:
6168c2ecf20Sopenharmony_ci			if (var->yres == (par->libretto ? 480 : 600))
6178c2ecf20Sopenharmony_ci				mode_ok = 1;
6188c2ecf20Sopenharmony_ci			break;
6198c2ecf20Sopenharmony_ci		case 640:
6208c2ecf20Sopenharmony_ci			if (var->yres == 480)
6218c2ecf20Sopenharmony_ci				mode_ok = 1;
6228c2ecf20Sopenharmony_ci			break;
6238c2ecf20Sopenharmony_ci		}
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	if (!mode_ok) {
6278c2ecf20Sopenharmony_ci		printk(KERN_INFO
6288c2ecf20Sopenharmony_ci		       "Mode (%dx%d) won't display properly on LCD\n",
6298c2ecf20Sopenharmony_ci		       var->xres, var->yres);
6308c2ecf20Sopenharmony_ci		return -EINVAL;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	var->red.msb_right = 0;
6348c2ecf20Sopenharmony_ci	var->green.msb_right = 0;
6358c2ecf20Sopenharmony_ci	var->blue.msb_right = 0;
6368c2ecf20Sopenharmony_ci	var->transp.msb_right = 0;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	var->transp.offset = 0;
6398c2ecf20Sopenharmony_ci	var->transp.length = 0;
6408c2ecf20Sopenharmony_ci	switch (var->bits_per_pixel) {
6418c2ecf20Sopenharmony_ci	case 8:		/* PSEUDOCOLOUR, 256 */
6428c2ecf20Sopenharmony_ci		var->red.offset = 0;
6438c2ecf20Sopenharmony_ci		var->red.length = 8;
6448c2ecf20Sopenharmony_ci		var->green.offset = 0;
6458c2ecf20Sopenharmony_ci		var->green.length = 8;
6468c2ecf20Sopenharmony_ci		var->blue.offset = 0;
6478c2ecf20Sopenharmony_ci		var->blue.length = 8;
6488c2ecf20Sopenharmony_ci		break;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	case 16:		/* DIRECTCOLOUR, 64k */
6518c2ecf20Sopenharmony_ci		var->red.offset = 11;
6528c2ecf20Sopenharmony_ci		var->red.length = 5;
6538c2ecf20Sopenharmony_ci		var->green.offset = 5;
6548c2ecf20Sopenharmony_ci		var->green.length = 6;
6558c2ecf20Sopenharmony_ci		var->blue.offset = 0;
6568c2ecf20Sopenharmony_ci		var->blue.length = 5;
6578c2ecf20Sopenharmony_ci		break;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	case 24:		/* TRUECOLOUR, 16m */
6608c2ecf20Sopenharmony_ci		var->red.offset = 16;
6618c2ecf20Sopenharmony_ci		var->red.length = 8;
6628c2ecf20Sopenharmony_ci		var->green.offset = 8;
6638c2ecf20Sopenharmony_ci		var->green.length = 8;
6648c2ecf20Sopenharmony_ci		var->blue.offset = 0;
6658c2ecf20Sopenharmony_ci		var->blue.length = 8;
6668c2ecf20Sopenharmony_ci		break;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET
6698c2ecf20Sopenharmony_ci	case 32:		/* TRUECOLOUR, 16m */
6708c2ecf20Sopenharmony_ci		var->transp.offset = 24;
6718c2ecf20Sopenharmony_ci		var->transp.length = 8;
6728c2ecf20Sopenharmony_ci		var->red.offset = 16;
6738c2ecf20Sopenharmony_ci		var->red.length = 8;
6748c2ecf20Sopenharmony_ci		var->green.offset = 8;
6758c2ecf20Sopenharmony_ci		var->green.length = 8;
6768c2ecf20Sopenharmony_ci		var->blue.offset = 0;
6778c2ecf20Sopenharmony_ci		var->blue.length = 8;
6788c2ecf20Sopenharmony_ci		break;
6798c2ecf20Sopenharmony_ci#endif
6808c2ecf20Sopenharmony_ci	default:
6818c2ecf20Sopenharmony_ci		printk(KERN_WARNING "neofb: no support for %dbpp\n",
6828c2ecf20Sopenharmony_ci		       var->bits_per_pixel);
6838c2ecf20Sopenharmony_ci		return -EINVAL;
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	vramlen = info->fix.smem_len;
6878c2ecf20Sopenharmony_ci	if (vramlen > 4 * 1024 * 1024)
6888c2ecf20Sopenharmony_ci		vramlen = 4 * 1024 * 1024;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (var->xres_virtual < var->xres)
6918c2ecf20Sopenharmony_ci		var->xres_virtual = var->xres;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual >> 3;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (memlen > vramlen) {
6968c2ecf20Sopenharmony_ci		var->yres_virtual =  vramlen * 8 / (var->xres_virtual *
6978c2ecf20Sopenharmony_ci				   	var->bits_per_pixel);
6988c2ecf20Sopenharmony_ci		memlen = var->xres_virtual * var->bits_per_pixel *
6998c2ecf20Sopenharmony_ci				var->yres_virtual / 8;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	/* we must round yres/xres down, we already rounded y/xres_virtual up
7038c2ecf20Sopenharmony_ci	   if it was possible. We should return -EINVAL, but I disagree */
7048c2ecf20Sopenharmony_ci	if (var->yres_virtual < var->yres)
7058c2ecf20Sopenharmony_ci		var->yres = var->yres_virtual;
7068c2ecf20Sopenharmony_ci	if (var->xoffset + var->xres > var->xres_virtual)
7078c2ecf20Sopenharmony_ci		var->xoffset = var->xres_virtual - var->xres;
7088c2ecf20Sopenharmony_ci	if (var->yoffset + var->yres > var->yres_virtual)
7098c2ecf20Sopenharmony_ci		var->yoffset = var->yres_virtual - var->yres;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	var->nonstd = 0;
7128c2ecf20Sopenharmony_ci	var->height = -1;
7138c2ecf20Sopenharmony_ci	var->width = -1;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (var->bits_per_pixel >= 24 || !par->neo2200)
7168c2ecf20Sopenharmony_ci		var->accel_flags &= ~FB_ACCELF_TEXT;
7178c2ecf20Sopenharmony_ci	return 0;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic int neofb_set_par(struct fb_info *info)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
7238c2ecf20Sopenharmony_ci	unsigned char temp;
7248c2ecf20Sopenharmony_ci	int i, clock_hi = 0;
7258c2ecf20Sopenharmony_ci	int lcd_stretch;
7268c2ecf20Sopenharmony_ci	int hoffset, voffset;
7278c2ecf20Sopenharmony_ci	int vsync_start, vtotal;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	DBG("neofb_set_par");
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	neoUnlock();
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	vgaHWProtect(1);	/* Blank the screen */
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	vsync_start = info->var.yres + info->var.lower_margin;
7368c2ecf20Sopenharmony_ci	vtotal = vsync_start + info->var.vsync_len + info->var.upper_margin;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	/*
7398c2ecf20Sopenharmony_ci	 * This will allocate the datastructure and initialize all of the
7408c2ecf20Sopenharmony_ci	 * generic VGA registers.
7418c2ecf20Sopenharmony_ci	 */
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	if (vgaHWInit(&info->var, par))
7448c2ecf20Sopenharmony_ci		return -EINVAL;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	/*
7478c2ecf20Sopenharmony_ci	 * The default value assigned by vgaHW.c is 0x41, but this does
7488c2ecf20Sopenharmony_ci	 * not work for NeoMagic.
7498c2ecf20Sopenharmony_ci	 */
7508c2ecf20Sopenharmony_ci	par->Attribute[16] = 0x01;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	switch (info->var.bits_per_pixel) {
7538c2ecf20Sopenharmony_ci	case 8:
7548c2ecf20Sopenharmony_ci		par->CRTC[0x13] = info->var.xres_virtual >> 3;
7558c2ecf20Sopenharmony_ci		par->ExtCRTOffset = info->var.xres_virtual >> 11;
7568c2ecf20Sopenharmony_ci		par->ExtColorModeSelect = 0x11;
7578c2ecf20Sopenharmony_ci		break;
7588c2ecf20Sopenharmony_ci	case 16:
7598c2ecf20Sopenharmony_ci		par->CRTC[0x13] = info->var.xres_virtual >> 2;
7608c2ecf20Sopenharmony_ci		par->ExtCRTOffset = info->var.xres_virtual >> 10;
7618c2ecf20Sopenharmony_ci		par->ExtColorModeSelect = 0x13;
7628c2ecf20Sopenharmony_ci		break;
7638c2ecf20Sopenharmony_ci	case 24:
7648c2ecf20Sopenharmony_ci		par->CRTC[0x13] = (info->var.xres_virtual * 3) >> 3;
7658c2ecf20Sopenharmony_ci		par->ExtCRTOffset = (info->var.xres_virtual * 3) >> 11;
7668c2ecf20Sopenharmony_ci		par->ExtColorModeSelect = 0x14;
7678c2ecf20Sopenharmony_ci		break;
7688c2ecf20Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET
7698c2ecf20Sopenharmony_ci	case 32:		/* FIXME: guessed values */
7708c2ecf20Sopenharmony_ci		par->CRTC[0x13] = info->var.xres_virtual >> 1;
7718c2ecf20Sopenharmony_ci		par->ExtCRTOffset = info->var.xres_virtual >> 9;
7728c2ecf20Sopenharmony_ci		par->ExtColorModeSelect = 0x15;
7738c2ecf20Sopenharmony_ci		break;
7748c2ecf20Sopenharmony_ci#endif
7758c2ecf20Sopenharmony_ci	default:
7768c2ecf20Sopenharmony_ci		break;
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	par->ExtCRTDispAddr = 0x10;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/* Vertical Extension */
7828c2ecf20Sopenharmony_ci	par->VerticalExt = (((vtotal - 2) & 0x400) >> 10)
7838c2ecf20Sopenharmony_ci	    | (((info->var.yres - 1) & 0x400) >> 9)
7848c2ecf20Sopenharmony_ci	    | (((vsync_start) & 0x400) >> 8)
7858c2ecf20Sopenharmony_ci	    | (((vsync_start) & 0x400) >> 7);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	/* Fast write bursts on unless disabled. */
7888c2ecf20Sopenharmony_ci	if (par->pci_burst)
7898c2ecf20Sopenharmony_ci		par->SysIfaceCntl1 = 0x30;
7908c2ecf20Sopenharmony_ci	else
7918c2ecf20Sopenharmony_ci		par->SysIfaceCntl1 = 0x00;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	par->SysIfaceCntl2 = 0xc0;	/* VESA Bios sets this to 0x80! */
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	/* Initialize: by default, we want display config register to be read */
7968c2ecf20Sopenharmony_ci	par->PanelDispCntlRegRead = 1;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	/* Enable any user specified display devices. */
7998c2ecf20Sopenharmony_ci	par->PanelDispCntlReg1 = 0x00;
8008c2ecf20Sopenharmony_ci	if (par->internal_display)
8018c2ecf20Sopenharmony_ci		par->PanelDispCntlReg1 |= 0x02;
8028c2ecf20Sopenharmony_ci	if (par->external_display)
8038c2ecf20Sopenharmony_ci		par->PanelDispCntlReg1 |= 0x01;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	/* If the user did not specify any display devices, then... */
8068c2ecf20Sopenharmony_ci	if (par->PanelDispCntlReg1 == 0x00) {
8078c2ecf20Sopenharmony_ci		/* Default to internal (i.e., LCD) only. */
8088c2ecf20Sopenharmony_ci		par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03;
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	/* If we are using a fixed mode, then tell the chip we are. */
8128c2ecf20Sopenharmony_ci	switch (info->var.xres) {
8138c2ecf20Sopenharmony_ci	case 1280:
8148c2ecf20Sopenharmony_ci		par->PanelDispCntlReg1 |= 0x60;
8158c2ecf20Sopenharmony_ci		break;
8168c2ecf20Sopenharmony_ci	case 1024:
8178c2ecf20Sopenharmony_ci		par->PanelDispCntlReg1 |= 0x40;
8188c2ecf20Sopenharmony_ci		break;
8198c2ecf20Sopenharmony_ci	case 800:
8208c2ecf20Sopenharmony_ci		par->PanelDispCntlReg1 |= 0x20;
8218c2ecf20Sopenharmony_ci		break;
8228c2ecf20Sopenharmony_ci	case 640:
8238c2ecf20Sopenharmony_ci	default:
8248c2ecf20Sopenharmony_ci		break;
8258c2ecf20Sopenharmony_ci	}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	/* Setup shadow register locking. */
8288c2ecf20Sopenharmony_ci	switch (par->PanelDispCntlReg1 & 0x03) {
8298c2ecf20Sopenharmony_ci	case 0x01:		/* External CRT only mode: */
8308c2ecf20Sopenharmony_ci		par->GeneralLockReg = 0x00;
8318c2ecf20Sopenharmony_ci		/* We need to program the VCLK for external display only mode. */
8328c2ecf20Sopenharmony_ci		par->ProgramVCLK = 1;
8338c2ecf20Sopenharmony_ci		break;
8348c2ecf20Sopenharmony_ci	case 0x02:		/* Internal LCD only mode: */
8358c2ecf20Sopenharmony_ci	case 0x03:		/* Simultaneous internal/external (LCD/CRT) mode: */
8368c2ecf20Sopenharmony_ci		par->GeneralLockReg = 0x01;
8378c2ecf20Sopenharmony_ci		/* Don't program the VCLK when using the LCD. */
8388c2ecf20Sopenharmony_ci		par->ProgramVCLK = 0;
8398c2ecf20Sopenharmony_ci		break;
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	/*
8438c2ecf20Sopenharmony_ci	 * If the screen is to be stretched, turn on stretching for the
8448c2ecf20Sopenharmony_ci	 * various modes.
8458c2ecf20Sopenharmony_ci	 *
8468c2ecf20Sopenharmony_ci	 * OPTION_LCD_STRETCH means stretching should be turned off!
8478c2ecf20Sopenharmony_ci	 */
8488c2ecf20Sopenharmony_ci	par->PanelDispCntlReg2 = 0x00;
8498c2ecf20Sopenharmony_ci	par->PanelDispCntlReg3 = 0x00;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	if (par->lcd_stretch && (par->PanelDispCntlReg1 == 0x02) &&	/* LCD only */
8528c2ecf20Sopenharmony_ci	    (info->var.xres != par->NeoPanelWidth)) {
8538c2ecf20Sopenharmony_ci		switch (info->var.xres) {
8548c2ecf20Sopenharmony_ci		case 320:	/* Needs testing.  KEM -- 24 May 98 */
8558c2ecf20Sopenharmony_ci		case 400:	/* Needs testing.  KEM -- 24 May 98 */
8568c2ecf20Sopenharmony_ci		case 640:
8578c2ecf20Sopenharmony_ci		case 800:
8588c2ecf20Sopenharmony_ci		case 1024:
8598c2ecf20Sopenharmony_ci			lcd_stretch = 1;
8608c2ecf20Sopenharmony_ci			par->PanelDispCntlReg2 |= 0xC6;
8618c2ecf20Sopenharmony_ci			break;
8628c2ecf20Sopenharmony_ci		default:
8638c2ecf20Sopenharmony_ci			lcd_stretch = 0;
8648c2ecf20Sopenharmony_ci			/* No stretching in these modes. */
8658c2ecf20Sopenharmony_ci		}
8668c2ecf20Sopenharmony_ci	} else
8678c2ecf20Sopenharmony_ci		lcd_stretch = 0;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	/*
8708c2ecf20Sopenharmony_ci	 * If the screen is to be centerd, turn on the centering for the
8718c2ecf20Sopenharmony_ci	 * various modes.
8728c2ecf20Sopenharmony_ci	 */
8738c2ecf20Sopenharmony_ci	par->PanelVertCenterReg1 = 0x00;
8748c2ecf20Sopenharmony_ci	par->PanelVertCenterReg2 = 0x00;
8758c2ecf20Sopenharmony_ci	par->PanelVertCenterReg3 = 0x00;
8768c2ecf20Sopenharmony_ci	par->PanelVertCenterReg4 = 0x00;
8778c2ecf20Sopenharmony_ci	par->PanelVertCenterReg5 = 0x00;
8788c2ecf20Sopenharmony_ci	par->PanelHorizCenterReg1 = 0x00;
8798c2ecf20Sopenharmony_ci	par->PanelHorizCenterReg2 = 0x00;
8808c2ecf20Sopenharmony_ci	par->PanelHorizCenterReg3 = 0x00;
8818c2ecf20Sopenharmony_ci	par->PanelHorizCenterReg4 = 0x00;
8828c2ecf20Sopenharmony_ci	par->PanelHorizCenterReg5 = 0x00;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	if (par->PanelDispCntlReg1 & 0x02) {
8868c2ecf20Sopenharmony_ci		if (info->var.xres == par->NeoPanelWidth) {
8878c2ecf20Sopenharmony_ci			/*
8888c2ecf20Sopenharmony_ci			 * No centering required when the requested display width
8898c2ecf20Sopenharmony_ci			 * equals the panel width.
8908c2ecf20Sopenharmony_ci			 */
8918c2ecf20Sopenharmony_ci		} else {
8928c2ecf20Sopenharmony_ci			par->PanelDispCntlReg2 |= 0x01;
8938c2ecf20Sopenharmony_ci			par->PanelDispCntlReg3 |= 0x10;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci			/* Calculate the horizontal and vertical offsets. */
8968c2ecf20Sopenharmony_ci			if (!lcd_stretch) {
8978c2ecf20Sopenharmony_ci				hoffset =
8988c2ecf20Sopenharmony_ci				    ((par->NeoPanelWidth -
8998c2ecf20Sopenharmony_ci				      info->var.xres) >> 4) - 1;
9008c2ecf20Sopenharmony_ci				voffset =
9018c2ecf20Sopenharmony_ci				    ((par->NeoPanelHeight -
9028c2ecf20Sopenharmony_ci				      info->var.yres) >> 1) - 2;
9038c2ecf20Sopenharmony_ci			} else {
9048c2ecf20Sopenharmony_ci				/* Stretched modes cannot be centered. */
9058c2ecf20Sopenharmony_ci				hoffset = 0;
9068c2ecf20Sopenharmony_ci				voffset = 0;
9078c2ecf20Sopenharmony_ci			}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci			switch (info->var.xres) {
9108c2ecf20Sopenharmony_ci			case 320:	/* Needs testing.  KEM -- 24 May 98 */
9118c2ecf20Sopenharmony_ci				par->PanelHorizCenterReg3 = hoffset;
9128c2ecf20Sopenharmony_ci				par->PanelVertCenterReg2 = voffset;
9138c2ecf20Sopenharmony_ci				break;
9148c2ecf20Sopenharmony_ci			case 400:	/* Needs testing.  KEM -- 24 May 98 */
9158c2ecf20Sopenharmony_ci				par->PanelHorizCenterReg4 = hoffset;
9168c2ecf20Sopenharmony_ci				par->PanelVertCenterReg1 = voffset;
9178c2ecf20Sopenharmony_ci				break;
9188c2ecf20Sopenharmony_ci			case 640:
9198c2ecf20Sopenharmony_ci				par->PanelHorizCenterReg1 = hoffset;
9208c2ecf20Sopenharmony_ci				par->PanelVertCenterReg3 = voffset;
9218c2ecf20Sopenharmony_ci				break;
9228c2ecf20Sopenharmony_ci			case 800:
9238c2ecf20Sopenharmony_ci				par->PanelHorizCenterReg2 = hoffset;
9248c2ecf20Sopenharmony_ci				par->PanelVertCenterReg4 = voffset;
9258c2ecf20Sopenharmony_ci				break;
9268c2ecf20Sopenharmony_ci			case 1024:
9278c2ecf20Sopenharmony_ci				par->PanelHorizCenterReg5 = hoffset;
9288c2ecf20Sopenharmony_ci				par->PanelVertCenterReg5 = voffset;
9298c2ecf20Sopenharmony_ci				break;
9308c2ecf20Sopenharmony_ci			case 1280:
9318c2ecf20Sopenharmony_ci			default:
9328c2ecf20Sopenharmony_ci				/* No centering in these modes. */
9338c2ecf20Sopenharmony_ci				break;
9348c2ecf20Sopenharmony_ci			}
9358c2ecf20Sopenharmony_ci		}
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	par->biosMode =
9398c2ecf20Sopenharmony_ci	    neoFindMode(info->var.xres, info->var.yres,
9408c2ecf20Sopenharmony_ci			info->var.bits_per_pixel);
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	/*
9438c2ecf20Sopenharmony_ci	 * Calculate the VCLK that most closely matches the requested dot
9448c2ecf20Sopenharmony_ci	 * clock.
9458c2ecf20Sopenharmony_ci	 */
9468c2ecf20Sopenharmony_ci	neoCalcVCLK(info, par, PICOS2KHZ(info->var.pixclock));
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	/* Since we program the clocks ourselves, always use VCLK3. */
9498c2ecf20Sopenharmony_ci	par->MiscOutReg |= 0x0C;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	/* alread unlocked above */
9528c2ecf20Sopenharmony_ci	/* BOGUS  vga_wgfx(NULL, 0x09, 0x26); */
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	/* don't know what this is, but it's 0 from bootup anyway */
9558c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x15, 0x00);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	/* was set to 0x01 by my bios in text and vesa modes */
9588c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x0A, par->GeneralLockReg);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	/*
9618c2ecf20Sopenharmony_ci	 * The color mode needs to be set before calling vgaHWRestore
9628c2ecf20Sopenharmony_ci	 * to ensure the DAC is initialized properly.
9638c2ecf20Sopenharmony_ci	 *
9648c2ecf20Sopenharmony_ci	 * NOTE: Make sure we don't change bits make sure we don't change
9658c2ecf20Sopenharmony_ci	 * any reserved bits.
9668c2ecf20Sopenharmony_ci	 */
9678c2ecf20Sopenharmony_ci	temp = vga_rgfx(NULL, 0x90);
9688c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
9698c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2070:
9708c2ecf20Sopenharmony_ci		temp &= 0xF0;	/* Save bits 7:4 */
9718c2ecf20Sopenharmony_ci		temp |= (par->ExtColorModeSelect & ~0xF0);
9728c2ecf20Sopenharmony_ci		break;
9738c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2090:
9748c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2093:
9758c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2097:
9768c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2160:
9778c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2200:
9788c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2230:
9798c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2360:
9808c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2380:
9818c2ecf20Sopenharmony_ci		temp &= 0x70;	/* Save bits 6:4 */
9828c2ecf20Sopenharmony_ci		temp |= (par->ExtColorModeSelect & ~0x70);
9838c2ecf20Sopenharmony_ci		break;
9848c2ecf20Sopenharmony_ci	}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x90, temp);
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	/*
9898c2ecf20Sopenharmony_ci	 * In some rare cases a lockup might occur if we don't delay
9908c2ecf20Sopenharmony_ci	 * here. (Reported by Miles Lane)
9918c2ecf20Sopenharmony_ci	 */
9928c2ecf20Sopenharmony_ci	//mdelay(200);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	/*
9958c2ecf20Sopenharmony_ci	 * Disable horizontal and vertical graphics and text expansions so
9968c2ecf20Sopenharmony_ci	 * that vgaHWRestore works properly.
9978c2ecf20Sopenharmony_ci	 */
9988c2ecf20Sopenharmony_ci	temp = vga_rgfx(NULL, 0x25);
9998c2ecf20Sopenharmony_ci	temp &= 0x39;
10008c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x25, temp);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	/*
10038c2ecf20Sopenharmony_ci	 * Sleep for 200ms to make sure that the two operations above have
10048c2ecf20Sopenharmony_ci	 * had time to take effect.
10058c2ecf20Sopenharmony_ci	 */
10068c2ecf20Sopenharmony_ci	mdelay(200);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/*
10098c2ecf20Sopenharmony_ci	 * This function handles restoring the generic VGA registers.  */
10108c2ecf20Sopenharmony_ci	vgaHWRestore(info, par);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	/* linear colormap for non palettized modes */
10138c2ecf20Sopenharmony_ci	switch (info->var.bits_per_pixel) {
10148c2ecf20Sopenharmony_ci	case 8:
10158c2ecf20Sopenharmony_ci		/* PseudoColor, 256 */
10168c2ecf20Sopenharmony_ci		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
10178c2ecf20Sopenharmony_ci		break;
10188c2ecf20Sopenharmony_ci	case 16:
10198c2ecf20Sopenharmony_ci		/* TrueColor, 64k */
10208c2ecf20Sopenharmony_ci		info->fix.visual = FB_VISUAL_TRUECOLOR;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci		for (i = 0; i < 64; i++) {
10238c2ecf20Sopenharmony_ci			outb(i, 0x3c8);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci			outb(i << 1, 0x3c9);
10268c2ecf20Sopenharmony_ci			outb(i, 0x3c9);
10278c2ecf20Sopenharmony_ci			outb(i << 1, 0x3c9);
10288c2ecf20Sopenharmony_ci		}
10298c2ecf20Sopenharmony_ci		break;
10308c2ecf20Sopenharmony_ci	case 24:
10318c2ecf20Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET
10328c2ecf20Sopenharmony_ci	case 32:
10338c2ecf20Sopenharmony_ci#endif
10348c2ecf20Sopenharmony_ci		/* TrueColor, 16m */
10358c2ecf20Sopenharmony_ci		info->fix.visual = FB_VISUAL_TRUECOLOR;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci		for (i = 0; i < 256; i++) {
10388c2ecf20Sopenharmony_ci			outb(i, 0x3c8);
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci			outb(i, 0x3c9);
10418c2ecf20Sopenharmony_ci			outb(i, 0x3c9);
10428c2ecf20Sopenharmony_ci			outb(i, 0x3c9);
10438c2ecf20Sopenharmony_ci		}
10448c2ecf20Sopenharmony_ci		break;
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x0E, par->ExtCRTDispAddr);
10488c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x0F, par->ExtCRTOffset);
10498c2ecf20Sopenharmony_ci	temp = vga_rgfx(NULL, 0x10);
10508c2ecf20Sopenharmony_ci	temp &= 0x0F;		/* Save bits 3:0 */
10518c2ecf20Sopenharmony_ci	temp |= (par->SysIfaceCntl1 & ~0x0F);	/* VESA Bios sets bit 1! */
10528c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x10, temp);
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x11, par->SysIfaceCntl2);
10558c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x15, 0 /*par->SingleAddrPage */ );
10568c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x16, 0 /*par->DualAddrPage */ );
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	temp = vga_rgfx(NULL, 0x20);
10598c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
10608c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2070:
10618c2ecf20Sopenharmony_ci		temp &= 0xFC;	/* Save bits 7:2 */
10628c2ecf20Sopenharmony_ci		temp |= (par->PanelDispCntlReg1 & ~0xFC);
10638c2ecf20Sopenharmony_ci		break;
10648c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2090:
10658c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2093:
10668c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2097:
10678c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2160:
10688c2ecf20Sopenharmony_ci		temp &= 0xDC;	/* Save bits 7:6,4:2 */
10698c2ecf20Sopenharmony_ci		temp |= (par->PanelDispCntlReg1 & ~0xDC);
10708c2ecf20Sopenharmony_ci		break;
10718c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2200:
10728c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2230:
10738c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2360:
10748c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2380:
10758c2ecf20Sopenharmony_ci		temp &= 0x98;	/* Save bits 7,4:3 */
10768c2ecf20Sopenharmony_ci		temp |= (par->PanelDispCntlReg1 & ~0x98);
10778c2ecf20Sopenharmony_ci		break;
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x20, temp);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	temp = vga_rgfx(NULL, 0x25);
10828c2ecf20Sopenharmony_ci	temp &= 0x38;		/* Save bits 5:3 */
10838c2ecf20Sopenharmony_ci	temp |= (par->PanelDispCntlReg2 & ~0x38);
10848c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x25, temp);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
10878c2ecf20Sopenharmony_ci		temp = vga_rgfx(NULL, 0x30);
10888c2ecf20Sopenharmony_ci		temp &= 0xEF;	/* Save bits 7:5 and bits 3:0 */
10898c2ecf20Sopenharmony_ci		temp |= (par->PanelDispCntlReg3 & ~0xEF);
10908c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x30, temp);
10918c2ecf20Sopenharmony_ci	}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x28, par->PanelVertCenterReg1);
10948c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x29, par->PanelVertCenterReg2);
10958c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x2a, par->PanelVertCenterReg3);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
10988c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x32, par->PanelVertCenterReg4);
10998c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x33, par->PanelHorizCenterReg1);
11008c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x34, par->PanelHorizCenterReg2);
11018c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x35, par->PanelHorizCenterReg3);
11028c2ecf20Sopenharmony_ci	}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160)
11058c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
11088c2ecf20Sopenharmony_ci	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
11098c2ecf20Sopenharmony_ci	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
11108c2ecf20Sopenharmony_ci	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
11118c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);
11128c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x37, par->PanelVertCenterReg5);
11138c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x38, par->PanelHorizCenterReg5);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci		clock_hi = 1;
11168c2ecf20Sopenharmony_ci	}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	/* Program VCLK3 if needed. */
11198c2ecf20Sopenharmony_ci	if (par->ProgramVCLK && ((vga_rgfx(NULL, 0x9B) != par->VCLK3NumeratorLow)
11208c2ecf20Sopenharmony_ci				 || (vga_rgfx(NULL, 0x9F) != par->VCLK3Denominator)
11218c2ecf20Sopenharmony_ci				 || (clock_hi && ((vga_rgfx(NULL, 0x8F) & ~0x0f)
11228c2ecf20Sopenharmony_ci						  != (par->VCLK3NumeratorHigh &
11238c2ecf20Sopenharmony_ci						      ~0x0F))))) {
11248c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x9B, par->VCLK3NumeratorLow);
11258c2ecf20Sopenharmony_ci		if (clock_hi) {
11268c2ecf20Sopenharmony_ci			temp = vga_rgfx(NULL, 0x8F);
11278c2ecf20Sopenharmony_ci			temp &= 0x0F;	/* Save bits 3:0 */
11288c2ecf20Sopenharmony_ci			temp |= (par->VCLK3NumeratorHigh & ~0x0F);
11298c2ecf20Sopenharmony_ci			vga_wgfx(NULL, 0x8F, temp);
11308c2ecf20Sopenharmony_ci		}
11318c2ecf20Sopenharmony_ci		vga_wgfx(NULL, 0x9F, par->VCLK3Denominator);
11328c2ecf20Sopenharmony_ci	}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	if (par->biosMode)
11358c2ecf20Sopenharmony_ci		vga_wcrt(NULL, 0x23, par->biosMode);
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x93, 0xc0);	/* Gives 5x faster framebuffer writes !!! */
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	/* Program vertical extension register */
11408c2ecf20Sopenharmony_ci	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
11418c2ecf20Sopenharmony_ci	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
11428c2ecf20Sopenharmony_ci	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
11438c2ecf20Sopenharmony_ci	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
11448c2ecf20Sopenharmony_ci		vga_wcrt(NULL, 0x70, par->VerticalExt);
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	vgaHWProtect(0);	/* Turn on screen */
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	/* Calling this also locks offset registers required in update_start */
11508c2ecf20Sopenharmony_ci	neoLock(&par->state);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	info->fix.line_length =
11538c2ecf20Sopenharmony_ci	    info->var.xres_virtual * (info->var.bits_per_pixel >> 3);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
11568c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2200:
11578c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2230:
11588c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2360:
11598c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2380:
11608c2ecf20Sopenharmony_ci			neo2200_accel_init(info, &info->var);
11618c2ecf20Sopenharmony_ci			break;
11628c2ecf20Sopenharmony_ci		default:
11638c2ecf20Sopenharmony_ci			break;
11648c2ecf20Sopenharmony_ci	}
11658c2ecf20Sopenharmony_ci	return 0;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci/*
11698c2ecf20Sopenharmony_ci *    Pan or Wrap the Display
11708c2ecf20Sopenharmony_ci */
11718c2ecf20Sopenharmony_cistatic int neofb_pan_display(struct fb_var_screeninfo *var,
11728c2ecf20Sopenharmony_ci			     struct fb_info *info)
11738c2ecf20Sopenharmony_ci{
11748c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
11758c2ecf20Sopenharmony_ci	struct vgastate *state = &par->state;
11768c2ecf20Sopenharmony_ci	int oldExtCRTDispAddr;
11778c2ecf20Sopenharmony_ci	int Base;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	DBG("neofb_update_start");
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	Base = (var->yoffset * info->var.xres_virtual + var->xoffset) >> 2;
11828c2ecf20Sopenharmony_ci	Base *= (info->var.bits_per_pixel + 7) / 8;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	neoUnlock();
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	/*
11878c2ecf20Sopenharmony_ci	 * These are the generic starting address registers.
11888c2ecf20Sopenharmony_ci	 */
11898c2ecf20Sopenharmony_ci	vga_wcrt(state->vgabase, 0x0C, (Base & 0x00FF00) >> 8);
11908c2ecf20Sopenharmony_ci	vga_wcrt(state->vgabase, 0x0D, (Base & 0x00FF));
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	/*
11938c2ecf20Sopenharmony_ci	 * Make sure we don't clobber some other bits that might already
11948c2ecf20Sopenharmony_ci	 * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
11958c2ecf20Sopenharmony_ci	 * be needed.
11968c2ecf20Sopenharmony_ci	 */
11978c2ecf20Sopenharmony_ci	oldExtCRTDispAddr = vga_rgfx(NULL, 0x0E);
11988c2ecf20Sopenharmony_ci	vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	neoLock(state);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	return 0;
12038c2ecf20Sopenharmony_ci}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_cistatic int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
12068c2ecf20Sopenharmony_ci			   u_int transp, struct fb_info *fb)
12078c2ecf20Sopenharmony_ci{
12088c2ecf20Sopenharmony_ci	if (regno >= fb->cmap.len || regno > 255)
12098c2ecf20Sopenharmony_ci		return -EINVAL;
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	if (fb->var.bits_per_pixel <= 8) {
12128c2ecf20Sopenharmony_ci		outb(regno, 0x3c8);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci		outb(red >> 10, 0x3c9);
12158c2ecf20Sopenharmony_ci		outb(green >> 10, 0x3c9);
12168c2ecf20Sopenharmony_ci		outb(blue >> 10, 0x3c9);
12178c2ecf20Sopenharmony_ci	} else if (regno < 16) {
12188c2ecf20Sopenharmony_ci		switch (fb->var.bits_per_pixel) {
12198c2ecf20Sopenharmony_ci		case 16:
12208c2ecf20Sopenharmony_ci			((u32 *) fb->pseudo_palette)[regno] =
12218c2ecf20Sopenharmony_ci				((red & 0xf800)) | ((green & 0xfc00) >> 5) |
12228c2ecf20Sopenharmony_ci				((blue & 0xf800) >> 11);
12238c2ecf20Sopenharmony_ci			break;
12248c2ecf20Sopenharmony_ci		case 24:
12258c2ecf20Sopenharmony_ci			((u32 *) fb->pseudo_palette)[regno] =
12268c2ecf20Sopenharmony_ci				((red & 0xff00) << 8) | ((green & 0xff00)) |
12278c2ecf20Sopenharmony_ci				((blue & 0xff00) >> 8);
12288c2ecf20Sopenharmony_ci			break;
12298c2ecf20Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET
12308c2ecf20Sopenharmony_ci		case 32:
12318c2ecf20Sopenharmony_ci			((u32 *) fb->pseudo_palette)[regno] =
12328c2ecf20Sopenharmony_ci				((transp & 0xff00) << 16) | ((red & 0xff00) << 8) |
12338c2ecf20Sopenharmony_ci				((green & 0xff00)) | ((blue & 0xff00) >> 8);
12348c2ecf20Sopenharmony_ci			break;
12358c2ecf20Sopenharmony_ci#endif
12368c2ecf20Sopenharmony_ci		default:
12378c2ecf20Sopenharmony_ci			return 1;
12388c2ecf20Sopenharmony_ci		}
12398c2ecf20Sopenharmony_ci	}
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	return 0;
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci/*
12458c2ecf20Sopenharmony_ci *    (Un)Blank the display.
12468c2ecf20Sopenharmony_ci */
12478c2ecf20Sopenharmony_cistatic int neofb_blank(int blank_mode, struct fb_info *info)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	/*
12508c2ecf20Sopenharmony_ci	 *  Blank the screen if blank_mode != 0, else unblank.
12518c2ecf20Sopenharmony_ci	 *  Return 0 if blanking succeeded, != 0 if un-/blanking failed due to
12528c2ecf20Sopenharmony_ci	 *  e.g. a video mode which doesn't support it. Implements VESA suspend
12538c2ecf20Sopenharmony_ci	 *  and powerdown modes for monitors, and backlight control on LCDs.
12548c2ecf20Sopenharmony_ci	 *    blank_mode == 0: unblanked (backlight on)
12558c2ecf20Sopenharmony_ci	 *    blank_mode == 1: blank (backlight on)
12568c2ecf20Sopenharmony_ci	 *    blank_mode == 2: suspend vsync (backlight off)
12578c2ecf20Sopenharmony_ci	 *    blank_mode == 3: suspend hsync (backlight off)
12588c2ecf20Sopenharmony_ci	 *    blank_mode == 4: powerdown (backlight off)
12598c2ecf20Sopenharmony_ci	 *
12608c2ecf20Sopenharmony_ci	 *  wms...Enable VESA DPMS compatible powerdown mode
12618c2ecf20Sopenharmony_ci	 *  run "setterm -powersave powerdown" to take advantage
12628c2ecf20Sopenharmony_ci	 */
12638c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
12648c2ecf20Sopenharmony_ci	int seqflags, lcdflags, dpmsflags, reg, tmpdisp;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	/*
12678c2ecf20Sopenharmony_ci	 * Read back the register bits related to display configuration. They might
12688c2ecf20Sopenharmony_ci	 * have been changed underneath the driver via Fn key stroke.
12698c2ecf20Sopenharmony_ci	 */
12708c2ecf20Sopenharmony_ci	neoUnlock();
12718c2ecf20Sopenharmony_ci	tmpdisp = vga_rgfx(NULL, 0x20) & 0x03;
12728c2ecf20Sopenharmony_ci	neoLock(&par->state);
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	/* In case we blank the screen, we want to store the possibly new
12758c2ecf20Sopenharmony_ci	 * configuration in the driver. During un-blank, we re-apply this setting,
12768c2ecf20Sopenharmony_ci	 * since the LCD bit will be cleared in order to switch off the backlight.
12778c2ecf20Sopenharmony_ci	 */
12788c2ecf20Sopenharmony_ci	if (par->PanelDispCntlRegRead) {
12798c2ecf20Sopenharmony_ci		par->PanelDispCntlReg1 = tmpdisp;
12808c2ecf20Sopenharmony_ci	}
12818c2ecf20Sopenharmony_ci	par->PanelDispCntlRegRead = !blank_mode;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	switch (blank_mode) {
12848c2ecf20Sopenharmony_ci	case FB_BLANK_POWERDOWN:	/* powerdown - both sync lines down */
12858c2ecf20Sopenharmony_ci		seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */
12868c2ecf20Sopenharmony_ci		lcdflags = 0;			/* LCD off */
12878c2ecf20Sopenharmony_ci		dpmsflags = NEO_GR01_SUPPRESS_HSYNC |
12888c2ecf20Sopenharmony_ci			    NEO_GR01_SUPPRESS_VSYNC;
12898c2ecf20Sopenharmony_ci#ifdef CONFIG_TOSHIBA
12908c2ecf20Sopenharmony_ci		/* Do we still need this ? */
12918c2ecf20Sopenharmony_ci		/* attempt to turn off backlight on toshiba; also turns off external */
12928c2ecf20Sopenharmony_ci		{
12938c2ecf20Sopenharmony_ci			SMMRegisters regs;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci			regs.eax = 0xff00; /* HCI_SET */
12968c2ecf20Sopenharmony_ci			regs.ebx = 0x0002; /* HCI_BACKLIGHT */
12978c2ecf20Sopenharmony_ci			regs.ecx = 0x0000; /* HCI_DISABLE */
12988c2ecf20Sopenharmony_ci			tosh_smm(&regs);
12998c2ecf20Sopenharmony_ci		}
13008c2ecf20Sopenharmony_ci#endif
13018c2ecf20Sopenharmony_ci		break;
13028c2ecf20Sopenharmony_ci	case FB_BLANK_HSYNC_SUSPEND:		/* hsync off */
13038c2ecf20Sopenharmony_ci		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */
13048c2ecf20Sopenharmony_ci		lcdflags = 0;			/* LCD off */
13058c2ecf20Sopenharmony_ci		dpmsflags = NEO_GR01_SUPPRESS_HSYNC;
13068c2ecf20Sopenharmony_ci		break;
13078c2ecf20Sopenharmony_ci	case FB_BLANK_VSYNC_SUSPEND:		/* vsync off */
13088c2ecf20Sopenharmony_ci		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */
13098c2ecf20Sopenharmony_ci		lcdflags = 0;			/* LCD off */
13108c2ecf20Sopenharmony_ci		dpmsflags = NEO_GR01_SUPPRESS_VSYNC;
13118c2ecf20Sopenharmony_ci		break;
13128c2ecf20Sopenharmony_ci	case FB_BLANK_NORMAL:		/* just blank screen (backlight stays on) */
13138c2ecf20Sopenharmony_ci		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */
13148c2ecf20Sopenharmony_ci		/*
13158c2ecf20Sopenharmony_ci		 * During a blank operation with the LID shut, we might store "LCD off"
13168c2ecf20Sopenharmony_ci		 * by mistake. Due to timing issues, the BIOS may switch the lights
13178c2ecf20Sopenharmony_ci		 * back on, and we turn it back off once we "unblank".
13188c2ecf20Sopenharmony_ci		 *
13198c2ecf20Sopenharmony_ci		 * So here is an attempt to implement ">=" - if we are in the process
13208c2ecf20Sopenharmony_ci		 * of unblanking, and the LCD bit is unset in the driver but set in the
13218c2ecf20Sopenharmony_ci		 * register, we must keep it.
13228c2ecf20Sopenharmony_ci		 */
13238c2ecf20Sopenharmony_ci		lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */
13248c2ecf20Sopenharmony_ci		dpmsflags = 0x00;	/* no hsync/vsync suppression */
13258c2ecf20Sopenharmony_ci		break;
13268c2ecf20Sopenharmony_ci	case FB_BLANK_UNBLANK:		/* unblank */
13278c2ecf20Sopenharmony_ci		seqflags = 0;			/* Enable sequencer */
13288c2ecf20Sopenharmony_ci		lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */
13298c2ecf20Sopenharmony_ci		dpmsflags = 0x00;	/* no hsync/vsync suppression */
13308c2ecf20Sopenharmony_ci#ifdef CONFIG_TOSHIBA
13318c2ecf20Sopenharmony_ci		/* Do we still need this ? */
13328c2ecf20Sopenharmony_ci		/* attempt to re-enable backlight/external on toshiba */
13338c2ecf20Sopenharmony_ci		{
13348c2ecf20Sopenharmony_ci			SMMRegisters regs;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci			regs.eax = 0xff00; /* HCI_SET */
13378c2ecf20Sopenharmony_ci			regs.ebx = 0x0002; /* HCI_BACKLIGHT */
13388c2ecf20Sopenharmony_ci			regs.ecx = 0x0001; /* HCI_ENABLE */
13398c2ecf20Sopenharmony_ci			tosh_smm(&regs);
13408c2ecf20Sopenharmony_ci		}
13418c2ecf20Sopenharmony_ci#endif
13428c2ecf20Sopenharmony_ci		break;
13438c2ecf20Sopenharmony_ci	default:	/* Anything else we don't understand; return 1 to tell
13448c2ecf20Sopenharmony_ci			 * fb_blank we didn't aactually do anything */
13458c2ecf20Sopenharmony_ci		return 1;
13468c2ecf20Sopenharmony_ci	}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	neoUnlock();
13498c2ecf20Sopenharmony_ci	reg = (vga_rseq(NULL, 0x01) & ~0x20) | seqflags;
13508c2ecf20Sopenharmony_ci	vga_wseq(NULL, 0x01, reg);
13518c2ecf20Sopenharmony_ci	reg = (vga_rgfx(NULL, 0x20) & ~0x02) | lcdflags;
13528c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x20, reg);
13538c2ecf20Sopenharmony_ci	reg = (vga_rgfx(NULL, 0x01) & ~0xF0) | 0x80 | dpmsflags;
13548c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x01, reg);
13558c2ecf20Sopenharmony_ci	neoLock(&par->state);
13568c2ecf20Sopenharmony_ci	return 0;
13578c2ecf20Sopenharmony_ci}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_cistatic void
13608c2ecf20Sopenharmony_cineo2200_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
13618c2ecf20Sopenharmony_ci{
13628c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
13638c2ecf20Sopenharmony_ci	u_long dst, rop;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	dst = rect->dx + rect->dy * info->var.xres_virtual;
13668c2ecf20Sopenharmony_ci	rop = rect->rop ? 0x060000 : 0x0c0000;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	neo2200_wait_fifo(info, 4);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	/* set blt control */
13718c2ecf20Sopenharmony_ci	writel(NEO_BC3_FIFO_EN |
13728c2ecf20Sopenharmony_ci	       NEO_BC0_SRC_IS_FG | NEO_BC3_SKIP_MAPPING |
13738c2ecf20Sopenharmony_ci	       //               NEO_BC3_DST_XY_ADDR  |
13748c2ecf20Sopenharmony_ci	       //               NEO_BC3_SRC_XY_ADDR  |
13758c2ecf20Sopenharmony_ci	       rop, &par->neo2200->bltCntl);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	switch (info->var.bits_per_pixel) {
13788c2ecf20Sopenharmony_ci	case 8:
13798c2ecf20Sopenharmony_ci		writel(rect->color, &par->neo2200->fgColor);
13808c2ecf20Sopenharmony_ci		break;
13818c2ecf20Sopenharmony_ci	case 16:
13828c2ecf20Sopenharmony_ci	case 24:
13838c2ecf20Sopenharmony_ci		writel(((u32 *) (info->pseudo_palette))[rect->color],
13848c2ecf20Sopenharmony_ci		       &par->neo2200->fgColor);
13858c2ecf20Sopenharmony_ci		break;
13868c2ecf20Sopenharmony_ci	}
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	writel(dst * ((info->var.bits_per_pixel + 7) >> 3),
13898c2ecf20Sopenharmony_ci	       &par->neo2200->dstStart);
13908c2ecf20Sopenharmony_ci	writel((rect->height << 16) | (rect->width & 0xffff),
13918c2ecf20Sopenharmony_ci	       &par->neo2200->xyExt);
13928c2ecf20Sopenharmony_ci}
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_cistatic void
13958c2ecf20Sopenharmony_cineo2200_copyarea(struct fb_info *info, const struct fb_copyarea *area)
13968c2ecf20Sopenharmony_ci{
13978c2ecf20Sopenharmony_ci	u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
13988c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
13998c2ecf20Sopenharmony_ci	u_long src, dst, bltCntl;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	bltCntl = NEO_BC3_FIFO_EN | NEO_BC3_SKIP_MAPPING | 0x0C0000;
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	if ((dy > sy) || ((dy == sy) && (dx > sx))) {
14048c2ecf20Sopenharmony_ci		/* Start with the lower right corner */
14058c2ecf20Sopenharmony_ci		sy += (area->height - 1);
14068c2ecf20Sopenharmony_ci		dy += (area->height - 1);
14078c2ecf20Sopenharmony_ci		sx += (area->width - 1);
14088c2ecf20Sopenharmony_ci		dx += (area->width - 1);
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci		bltCntl |= NEO_BC0_X_DEC | NEO_BC0_DST_Y_DEC | NEO_BC0_SRC_Y_DEC;
14118c2ecf20Sopenharmony_ci	}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	src = sx * (info->var.bits_per_pixel >> 3) + sy*info->fix.line_length;
14148c2ecf20Sopenharmony_ci	dst = dx * (info->var.bits_per_pixel >> 3) + dy*info->fix.line_length;
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	neo2200_wait_fifo(info, 4);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	/* set blt control */
14198c2ecf20Sopenharmony_ci	writel(bltCntl, &par->neo2200->bltCntl);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	writel(src, &par->neo2200->srcStart);
14228c2ecf20Sopenharmony_ci	writel(dst, &par->neo2200->dstStart);
14238c2ecf20Sopenharmony_ci	writel((area->height << 16) | (area->width & 0xffff),
14248c2ecf20Sopenharmony_ci	       &par->neo2200->xyExt);
14258c2ecf20Sopenharmony_ci}
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_cistatic void
14288c2ecf20Sopenharmony_cineo2200_imageblit(struct fb_info *info, const struct fb_image *image)
14298c2ecf20Sopenharmony_ci{
14308c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
14318c2ecf20Sopenharmony_ci	int s_pitch = (image->width * image->depth + 7) >> 3;
14328c2ecf20Sopenharmony_ci	int scan_align = info->pixmap.scan_align - 1;
14338c2ecf20Sopenharmony_ci	int buf_align = info->pixmap.buf_align - 1;
14348c2ecf20Sopenharmony_ci	int bltCntl_flags, d_pitch, data_len;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	// The data is padded for the hardware
14378c2ecf20Sopenharmony_ci	d_pitch = (s_pitch + scan_align) & ~scan_align;
14388c2ecf20Sopenharmony_ci	data_len = ((d_pitch * image->height) + buf_align) & ~buf_align;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	neo2200_sync(info);
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	if (image->depth == 1) {
14438c2ecf20Sopenharmony_ci		if (info->var.bits_per_pixel == 24 && image->width < 16) {
14448c2ecf20Sopenharmony_ci			/* FIXME. There is a bug with accelerated color-expanded
14458c2ecf20Sopenharmony_ci			 * transfers in 24 bit mode if the image being transferred
14468c2ecf20Sopenharmony_ci			 * is less than 16 bits wide. This is due to insufficient
14478c2ecf20Sopenharmony_ci			 * padding when writing the image. We need to adjust
14488c2ecf20Sopenharmony_ci			 * struct fb_pixmap. Not yet done. */
14498c2ecf20Sopenharmony_ci			cfb_imageblit(info, image);
14508c2ecf20Sopenharmony_ci			return;
14518c2ecf20Sopenharmony_ci		}
14528c2ecf20Sopenharmony_ci		bltCntl_flags = NEO_BC0_SRC_MONO;
14538c2ecf20Sopenharmony_ci	} else if (image->depth == info->var.bits_per_pixel) {
14548c2ecf20Sopenharmony_ci		bltCntl_flags = 0;
14558c2ecf20Sopenharmony_ci	} else {
14568c2ecf20Sopenharmony_ci		/* We don't currently support hardware acceleration if image
14578c2ecf20Sopenharmony_ci		 * depth is different from display */
14588c2ecf20Sopenharmony_ci		cfb_imageblit(info, image);
14598c2ecf20Sopenharmony_ci		return;
14608c2ecf20Sopenharmony_ci	}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	switch (info->var.bits_per_pixel) {
14638c2ecf20Sopenharmony_ci	case 8:
14648c2ecf20Sopenharmony_ci		writel(image->fg_color, &par->neo2200->fgColor);
14658c2ecf20Sopenharmony_ci		writel(image->bg_color, &par->neo2200->bgColor);
14668c2ecf20Sopenharmony_ci		break;
14678c2ecf20Sopenharmony_ci	case 16:
14688c2ecf20Sopenharmony_ci	case 24:
14698c2ecf20Sopenharmony_ci		writel(((u32 *) (info->pseudo_palette))[image->fg_color],
14708c2ecf20Sopenharmony_ci		       &par->neo2200->fgColor);
14718c2ecf20Sopenharmony_ci		writel(((u32 *) (info->pseudo_palette))[image->bg_color],
14728c2ecf20Sopenharmony_ci		       &par->neo2200->bgColor);
14738c2ecf20Sopenharmony_ci		break;
14748c2ecf20Sopenharmony_ci	}
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	writel(NEO_BC0_SYS_TO_VID |
14778c2ecf20Sopenharmony_ci		NEO_BC3_SKIP_MAPPING | bltCntl_flags |
14788c2ecf20Sopenharmony_ci		// NEO_BC3_DST_XY_ADDR |
14798c2ecf20Sopenharmony_ci		0x0c0000, &par->neo2200->bltCntl);
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	writel(0, &par->neo2200->srcStart);
14828c2ecf20Sopenharmony_ci//      par->neo2200->dstStart = (image->dy << 16) | (image->dx & 0xffff);
14838c2ecf20Sopenharmony_ci	writel(((image->dx & 0xffff) * (info->var.bits_per_pixel >> 3) +
14848c2ecf20Sopenharmony_ci		image->dy * info->fix.line_length), &par->neo2200->dstStart);
14858c2ecf20Sopenharmony_ci	writel((image->height << 16) | (image->width & 0xffff),
14868c2ecf20Sopenharmony_ci	       &par->neo2200->xyExt);
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	memcpy_toio(par->mmio_vbase + 0x100000, image->data, data_len);
14898c2ecf20Sopenharmony_ci}
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_cistatic void
14928c2ecf20Sopenharmony_cineofb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
14938c2ecf20Sopenharmony_ci{
14948c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
14958c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2200:
14968c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2230:
14978c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2360:
14988c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2380:
14998c2ecf20Sopenharmony_ci			neo2200_fillrect(info, rect);
15008c2ecf20Sopenharmony_ci			break;
15018c2ecf20Sopenharmony_ci		default:
15028c2ecf20Sopenharmony_ci			cfb_fillrect(info, rect);
15038c2ecf20Sopenharmony_ci			break;
15048c2ecf20Sopenharmony_ci	}
15058c2ecf20Sopenharmony_ci}
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_cistatic void
15088c2ecf20Sopenharmony_cineofb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
15098c2ecf20Sopenharmony_ci{
15108c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
15118c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2200:
15128c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2230:
15138c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2360:
15148c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2380:
15158c2ecf20Sopenharmony_ci			neo2200_copyarea(info, area);
15168c2ecf20Sopenharmony_ci			break;
15178c2ecf20Sopenharmony_ci		default:
15188c2ecf20Sopenharmony_ci			cfb_copyarea(info, area);
15198c2ecf20Sopenharmony_ci			break;
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_cistatic void
15248c2ecf20Sopenharmony_cineofb_imageblit(struct fb_info *info, const struct fb_image *image)
15258c2ecf20Sopenharmony_ci{
15268c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
15278c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2200:
15288c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2230:
15298c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2360:
15308c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2380:
15318c2ecf20Sopenharmony_ci			neo2200_imageblit(info, image);
15328c2ecf20Sopenharmony_ci			break;
15338c2ecf20Sopenharmony_ci		default:
15348c2ecf20Sopenharmony_ci			cfb_imageblit(info, image);
15358c2ecf20Sopenharmony_ci			break;
15368c2ecf20Sopenharmony_ci	}
15378c2ecf20Sopenharmony_ci}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_cistatic int
15408c2ecf20Sopenharmony_cineofb_sync(struct fb_info *info)
15418c2ecf20Sopenharmony_ci{
15428c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
15438c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2200:
15448c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2230:
15458c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2360:
15468c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2380:
15478c2ecf20Sopenharmony_ci			neo2200_sync(info);
15488c2ecf20Sopenharmony_ci			break;
15498c2ecf20Sopenharmony_ci		default:
15508c2ecf20Sopenharmony_ci			break;
15518c2ecf20Sopenharmony_ci	}
15528c2ecf20Sopenharmony_ci	return 0;
15538c2ecf20Sopenharmony_ci}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci/*
15568c2ecf20Sopenharmony_cistatic void
15578c2ecf20Sopenharmony_cineofb_draw_cursor(struct fb_info *info, u8 *dst, u8 *src, unsigned int width)
15588c2ecf20Sopenharmony_ci{
15598c2ecf20Sopenharmony_ci	//memset_io(info->sprite.addr, 0xff, 1);
15608c2ecf20Sopenharmony_ci}
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_cistatic int
15638c2ecf20Sopenharmony_cineofb_cursor(struct fb_info *info, struct fb_cursor *cursor)
15648c2ecf20Sopenharmony_ci{
15658c2ecf20Sopenharmony_ci	struct neofb_par *par = (struct neofb_par *) info->par;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	* Disable cursor *
15688c2ecf20Sopenharmony_ci	write_le32(NEOREG_CURSCNTL, ~NEO_CURS_ENABLE, par);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	if (cursor->set & FB_CUR_SETPOS) {
15718c2ecf20Sopenharmony_ci		u32 x = cursor->image.dx;
15728c2ecf20Sopenharmony_ci		u32 y = cursor->image.dy;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci		info->cursor.image.dx = x;
15758c2ecf20Sopenharmony_ci		info->cursor.image.dy = y;
15768c2ecf20Sopenharmony_ci		write_le32(NEOREG_CURSX, x, par);
15778c2ecf20Sopenharmony_ci		write_le32(NEOREG_CURSY, y, par);
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	if (cursor->set & FB_CUR_SETSIZE) {
15818c2ecf20Sopenharmony_ci		info->cursor.image.height = cursor->image.height;
15828c2ecf20Sopenharmony_ci		info->cursor.image.width = cursor->image.width;
15838c2ecf20Sopenharmony_ci	}
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	if (cursor->set & FB_CUR_SETHOT)
15868c2ecf20Sopenharmony_ci		info->cursor.hot = cursor->hot;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	if (cursor->set & FB_CUR_SETCMAP) {
15898c2ecf20Sopenharmony_ci		if (cursor->image.depth == 1) {
15908c2ecf20Sopenharmony_ci			u32 fg = cursor->image.fg_color;
15918c2ecf20Sopenharmony_ci			u32 bg = cursor->image.bg_color;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci			info->cursor.image.fg_color = fg;
15948c2ecf20Sopenharmony_ci			info->cursor.image.bg_color = bg;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci			fg = ((fg & 0xff0000) >> 16) | ((fg & 0xff) << 16) | (fg & 0xff00);
15978c2ecf20Sopenharmony_ci			bg = ((bg & 0xff0000) >> 16) | ((bg & 0xff) << 16) | (bg & 0xff00);
15988c2ecf20Sopenharmony_ci			write_le32(NEOREG_CURSFGCOLOR, fg, par);
15998c2ecf20Sopenharmony_ci			write_le32(NEOREG_CURSBGCOLOR, bg, par);
16008c2ecf20Sopenharmony_ci		}
16018c2ecf20Sopenharmony_ci	}
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	if (cursor->set & FB_CUR_SETSHAPE)
16048c2ecf20Sopenharmony_ci		fb_load_cursor_image(info);
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	if (info->cursor.enable)
16078c2ecf20Sopenharmony_ci		write_le32(NEOREG_CURSCNTL, NEO_CURS_ENABLE, par);
16088c2ecf20Sopenharmony_ci	return 0;
16098c2ecf20Sopenharmony_ci}
16108c2ecf20Sopenharmony_ci*/
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_cistatic const struct fb_ops neofb_ops = {
16138c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
16148c2ecf20Sopenharmony_ci	.fb_open	= neofb_open,
16158c2ecf20Sopenharmony_ci	.fb_release	= neofb_release,
16168c2ecf20Sopenharmony_ci	.fb_check_var	= neofb_check_var,
16178c2ecf20Sopenharmony_ci	.fb_set_par	= neofb_set_par,
16188c2ecf20Sopenharmony_ci	.fb_setcolreg	= neofb_setcolreg,
16198c2ecf20Sopenharmony_ci	.fb_pan_display	= neofb_pan_display,
16208c2ecf20Sopenharmony_ci	.fb_blank	= neofb_blank,
16218c2ecf20Sopenharmony_ci	.fb_sync	= neofb_sync,
16228c2ecf20Sopenharmony_ci	.fb_fillrect	= neofb_fillrect,
16238c2ecf20Sopenharmony_ci	.fb_copyarea	= neofb_copyarea,
16248c2ecf20Sopenharmony_ci	.fb_imageblit	= neofb_imageblit,
16258c2ecf20Sopenharmony_ci};
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_cistatic struct fb_videomode mode800x480 = {
16308c2ecf20Sopenharmony_ci	.xres           = 800,
16318c2ecf20Sopenharmony_ci	.yres           = 480,
16328c2ecf20Sopenharmony_ci	.pixclock       = 25000,
16338c2ecf20Sopenharmony_ci	.left_margin    = 88,
16348c2ecf20Sopenharmony_ci	.right_margin   = 40,
16358c2ecf20Sopenharmony_ci	.upper_margin   = 23,
16368c2ecf20Sopenharmony_ci	.lower_margin   = 1,
16378c2ecf20Sopenharmony_ci	.hsync_len      = 128,
16388c2ecf20Sopenharmony_ci	.vsync_len      = 4,
16398c2ecf20Sopenharmony_ci	.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
16408c2ecf20Sopenharmony_ci	.vmode          = FB_VMODE_NONINTERLACED
16418c2ecf20Sopenharmony_ci};
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_cistatic int neo_map_mmio(struct fb_info *info, struct pci_dev *dev)
16448c2ecf20Sopenharmony_ci{
16458c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	DBG("neo_map_mmio");
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
16508c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2070:
16518c2ecf20Sopenharmony_ci			info->fix.mmio_start = pci_resource_start(dev, 0)+
16528c2ecf20Sopenharmony_ci				0x100000;
16538c2ecf20Sopenharmony_ci			break;
16548c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2090:
16558c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2093:
16568c2ecf20Sopenharmony_ci			info->fix.mmio_start = pci_resource_start(dev, 0)+
16578c2ecf20Sopenharmony_ci				0x200000;
16588c2ecf20Sopenharmony_ci			break;
16598c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2160:
16608c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2097:
16618c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2200:
16628c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2230:
16638c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2360:
16648c2ecf20Sopenharmony_ci		case FB_ACCEL_NEOMAGIC_NM2380:
16658c2ecf20Sopenharmony_ci			info->fix.mmio_start = pci_resource_start(dev, 1);
16668c2ecf20Sopenharmony_ci			break;
16678c2ecf20Sopenharmony_ci		default:
16688c2ecf20Sopenharmony_ci			info->fix.mmio_start = pci_resource_start(dev, 0);
16698c2ecf20Sopenharmony_ci	}
16708c2ecf20Sopenharmony_ci	info->fix.mmio_len = MMIO_SIZE;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	if (!request_mem_region
16738c2ecf20Sopenharmony_ci	    (info->fix.mmio_start, MMIO_SIZE, "memory mapped I/O")) {
16748c2ecf20Sopenharmony_ci		printk("neofb: memory mapped IO in use\n");
16758c2ecf20Sopenharmony_ci		return -EBUSY;
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	par->mmio_vbase = ioremap(info->fix.mmio_start, MMIO_SIZE);
16798c2ecf20Sopenharmony_ci	if (!par->mmio_vbase) {
16808c2ecf20Sopenharmony_ci		printk("neofb: unable to map memory mapped IO\n");
16818c2ecf20Sopenharmony_ci		release_mem_region(info->fix.mmio_start,
16828c2ecf20Sopenharmony_ci				   info->fix.mmio_len);
16838c2ecf20Sopenharmony_ci		return -ENOMEM;
16848c2ecf20Sopenharmony_ci	} else
16858c2ecf20Sopenharmony_ci		printk(KERN_INFO "neofb: mapped io at %p\n",
16868c2ecf20Sopenharmony_ci		       par->mmio_vbase);
16878c2ecf20Sopenharmony_ci	return 0;
16888c2ecf20Sopenharmony_ci}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_cistatic void neo_unmap_mmio(struct fb_info *info)
16918c2ecf20Sopenharmony_ci{
16928c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	DBG("neo_unmap_mmio");
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	iounmap(par->mmio_vbase);
16978c2ecf20Sopenharmony_ci	par->mmio_vbase = NULL;
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	release_mem_region(info->fix.mmio_start,
17008c2ecf20Sopenharmony_ci			   info->fix.mmio_len);
17018c2ecf20Sopenharmony_ci}
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_cistatic int neo_map_video(struct fb_info *info, struct pci_dev *dev,
17048c2ecf20Sopenharmony_ci			 int video_len)
17058c2ecf20Sopenharmony_ci{
17068c2ecf20Sopenharmony_ci	//unsigned long addr;
17078c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	DBG("neo_map_video");
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	info->fix.smem_start = pci_resource_start(dev, 0);
17128c2ecf20Sopenharmony_ci	info->fix.smem_len = video_len;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,
17158c2ecf20Sopenharmony_ci				"frame buffer")) {
17168c2ecf20Sopenharmony_ci		printk("neofb: frame buffer in use\n");
17178c2ecf20Sopenharmony_ci		return -EBUSY;
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	info->screen_base =
17218c2ecf20Sopenharmony_ci	    ioremap_wc(info->fix.smem_start, info->fix.smem_len);
17228c2ecf20Sopenharmony_ci	if (!info->screen_base) {
17238c2ecf20Sopenharmony_ci		printk("neofb: unable to map screen memory\n");
17248c2ecf20Sopenharmony_ci		release_mem_region(info->fix.smem_start,
17258c2ecf20Sopenharmony_ci				   info->fix.smem_len);
17268c2ecf20Sopenharmony_ci		return -ENOMEM;
17278c2ecf20Sopenharmony_ci	} else
17288c2ecf20Sopenharmony_ci		printk(KERN_INFO "neofb: mapped framebuffer at %p\n",
17298c2ecf20Sopenharmony_ci		       info->screen_base);
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	par->wc_cookie = arch_phys_wc_add(info->fix.smem_start,
17328c2ecf20Sopenharmony_ci					  pci_resource_len(dev, 0));
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	/* Clear framebuffer, it's all white in memory after boot */
17358c2ecf20Sopenharmony_ci	memset_io(info->screen_base, 0, info->fix.smem_len);
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	/* Allocate Cursor drawing pad.
17388c2ecf20Sopenharmony_ci	info->fix.smem_len -= PAGE_SIZE;
17398c2ecf20Sopenharmony_ci	addr = info->fix.smem_start + info->fix.smem_len;
17408c2ecf20Sopenharmony_ci	write_le32(NEOREG_CURSMEMPOS, ((0x000f & (addr >> 10)) << 8) |
17418c2ecf20Sopenharmony_ci					((0x0ff0 & (addr >> 10)) >> 4), par);
17428c2ecf20Sopenharmony_ci	addr = (unsigned long) info->screen_base + info->fix.smem_len;
17438c2ecf20Sopenharmony_ci	info->sprite.addr = (u8 *) addr; */
17448c2ecf20Sopenharmony_ci	return 0;
17458c2ecf20Sopenharmony_ci}
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_cistatic void neo_unmap_video(struct fb_info *info)
17488c2ecf20Sopenharmony_ci{
17498c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	DBG("neo_unmap_video");
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	arch_phys_wc_del(par->wc_cookie);
17548c2ecf20Sopenharmony_ci	iounmap(info->screen_base);
17558c2ecf20Sopenharmony_ci	info->screen_base = NULL;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	release_mem_region(info->fix.smem_start,
17588c2ecf20Sopenharmony_ci			   info->fix.smem_len);
17598c2ecf20Sopenharmony_ci}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_cistatic int neo_scan_monitor(struct fb_info *info)
17628c2ecf20Sopenharmony_ci{
17638c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
17648c2ecf20Sopenharmony_ci	unsigned char type, display;
17658c2ecf20Sopenharmony_ci	int w;
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	// Eventually we will have i2c support.
17688c2ecf20Sopenharmony_ci	info->monspecs.modedb = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL);
17698c2ecf20Sopenharmony_ci	if (!info->monspecs.modedb)
17708c2ecf20Sopenharmony_ci		return -ENOMEM;
17718c2ecf20Sopenharmony_ci	info->monspecs.modedb_len = 1;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	/* Determine the panel type */
17748c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x09, 0x26);
17758c2ecf20Sopenharmony_ci	type = vga_rgfx(NULL, 0x21);
17768c2ecf20Sopenharmony_ci	display = vga_rgfx(NULL, 0x20);
17778c2ecf20Sopenharmony_ci	if (!par->internal_display && !par->external_display) {
17788c2ecf20Sopenharmony_ci		par->internal_display = display & 2 || !(display & 3) ? 1 : 0;
17798c2ecf20Sopenharmony_ci		par->external_display = display & 1;
17808c2ecf20Sopenharmony_ci		printk (KERN_INFO "Autodetected %s display\n",
17818c2ecf20Sopenharmony_ci			par->internal_display && par->external_display ? "simultaneous" :
17828c2ecf20Sopenharmony_ci			par->internal_display ? "internal" : "external");
17838c2ecf20Sopenharmony_ci	}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	/* Determine panel width -- used in NeoValidMode. */
17868c2ecf20Sopenharmony_ci	w = vga_rgfx(NULL, 0x20);
17878c2ecf20Sopenharmony_ci	vga_wgfx(NULL, 0x09, 0x00);
17888c2ecf20Sopenharmony_ci	switch ((w & 0x18) >> 3) {
17898c2ecf20Sopenharmony_ci	case 0x00:
17908c2ecf20Sopenharmony_ci		// 640x480@60
17918c2ecf20Sopenharmony_ci		par->NeoPanelWidth = 640;
17928c2ecf20Sopenharmony_ci		par->NeoPanelHeight = 480;
17938c2ecf20Sopenharmony_ci		memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode));
17948c2ecf20Sopenharmony_ci		break;
17958c2ecf20Sopenharmony_ci	case 0x01:
17968c2ecf20Sopenharmony_ci		par->NeoPanelWidth = 800;
17978c2ecf20Sopenharmony_ci		if (par->libretto) {
17988c2ecf20Sopenharmony_ci			par->NeoPanelHeight = 480;
17998c2ecf20Sopenharmony_ci			memcpy(info->monspecs.modedb, &mode800x480, sizeof(struct fb_videomode));
18008c2ecf20Sopenharmony_ci		} else {
18018c2ecf20Sopenharmony_ci			// 800x600@60
18028c2ecf20Sopenharmony_ci			par->NeoPanelHeight = 600;
18038c2ecf20Sopenharmony_ci			memcpy(info->monspecs.modedb, &vesa_modes[8], sizeof(struct fb_videomode));
18048c2ecf20Sopenharmony_ci		}
18058c2ecf20Sopenharmony_ci		break;
18068c2ecf20Sopenharmony_ci	case 0x02:
18078c2ecf20Sopenharmony_ci		// 1024x768@60
18088c2ecf20Sopenharmony_ci		par->NeoPanelWidth = 1024;
18098c2ecf20Sopenharmony_ci		par->NeoPanelHeight = 768;
18108c2ecf20Sopenharmony_ci		memcpy(info->monspecs.modedb, &vesa_modes[13], sizeof(struct fb_videomode));
18118c2ecf20Sopenharmony_ci		break;
18128c2ecf20Sopenharmony_ci	case 0x03:
18138c2ecf20Sopenharmony_ci		/* 1280x1024@60 panel support needs to be added */
18148c2ecf20Sopenharmony_ci#ifdef NOT_DONE
18158c2ecf20Sopenharmony_ci		par->NeoPanelWidth = 1280;
18168c2ecf20Sopenharmony_ci		par->NeoPanelHeight = 1024;
18178c2ecf20Sopenharmony_ci		memcpy(info->monspecs.modedb, &vesa_modes[20], sizeof(struct fb_videomode));
18188c2ecf20Sopenharmony_ci		break;
18198c2ecf20Sopenharmony_ci#else
18208c2ecf20Sopenharmony_ci		printk(KERN_ERR
18218c2ecf20Sopenharmony_ci		       "neofb: Only 640x480, 800x600/480 and 1024x768 panels are currently supported\n");
18228c2ecf20Sopenharmony_ci		kfree(info->monspecs.modedb);
18238c2ecf20Sopenharmony_ci		return -1;
18248c2ecf20Sopenharmony_ci#endif
18258c2ecf20Sopenharmony_ci	default:
18268c2ecf20Sopenharmony_ci		// 640x480@60
18278c2ecf20Sopenharmony_ci		par->NeoPanelWidth = 640;
18288c2ecf20Sopenharmony_ci		par->NeoPanelHeight = 480;
18298c2ecf20Sopenharmony_ci		memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode));
18308c2ecf20Sopenharmony_ci		break;
18318c2ecf20Sopenharmony_ci	}
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	printk(KERN_INFO "Panel is a %dx%d %s %s display\n",
18348c2ecf20Sopenharmony_ci	       par->NeoPanelWidth,
18358c2ecf20Sopenharmony_ci	       par->NeoPanelHeight,
18368c2ecf20Sopenharmony_ci	       (type & 0x02) ? "color" : "monochrome",
18378c2ecf20Sopenharmony_ci	       (type & 0x10) ? "TFT" : "dual scan");
18388c2ecf20Sopenharmony_ci	return 0;
18398c2ecf20Sopenharmony_ci}
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_cistatic int neo_init_hw(struct fb_info *info)
18428c2ecf20Sopenharmony_ci{
18438c2ecf20Sopenharmony_ci	struct neofb_par *par = info->par;
18448c2ecf20Sopenharmony_ci	int videoRam = 896;
18458c2ecf20Sopenharmony_ci	int maxClock = 65000;
18468c2ecf20Sopenharmony_ci	int CursorMem = 1024;
18478c2ecf20Sopenharmony_ci	int CursorOff = 0x100;
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci	DBG("neo_init_hw");
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	neoUnlock();
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci#if 0
18548c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "--- Neo extended register dump ---\n");
18558c2ecf20Sopenharmony_ci	for (int w = 0; w < 0x85; w++)
18568c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "CR %p: %p\n", (void *) w,
18578c2ecf20Sopenharmony_ci		       (void *) vga_rcrt(NULL, w));
18588c2ecf20Sopenharmony_ci	for (int w = 0; w < 0xC7; w++)
18598c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "GR %p: %p\n", (void *) w,
18608c2ecf20Sopenharmony_ci		       (void *) vga_rgfx(NULL, w));
18618c2ecf20Sopenharmony_ci#endif
18628c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
18638c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2070:
18648c2ecf20Sopenharmony_ci		videoRam = 896;
18658c2ecf20Sopenharmony_ci		maxClock = 65000;
18668c2ecf20Sopenharmony_ci		break;
18678c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2090:
18688c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2093:
18698c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2097:
18708c2ecf20Sopenharmony_ci		videoRam = 1152;
18718c2ecf20Sopenharmony_ci		maxClock = 80000;
18728c2ecf20Sopenharmony_ci		break;
18738c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2160:
18748c2ecf20Sopenharmony_ci		videoRam = 2048;
18758c2ecf20Sopenharmony_ci		maxClock = 90000;
18768c2ecf20Sopenharmony_ci		break;
18778c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2200:
18788c2ecf20Sopenharmony_ci		videoRam = 2560;
18798c2ecf20Sopenharmony_ci		maxClock = 110000;
18808c2ecf20Sopenharmony_ci		break;
18818c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2230:
18828c2ecf20Sopenharmony_ci		videoRam = 3008;
18838c2ecf20Sopenharmony_ci		maxClock = 110000;
18848c2ecf20Sopenharmony_ci		break;
18858c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2360:
18868c2ecf20Sopenharmony_ci		videoRam = 4096;
18878c2ecf20Sopenharmony_ci		maxClock = 110000;
18888c2ecf20Sopenharmony_ci		break;
18898c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2380:
18908c2ecf20Sopenharmony_ci		videoRam = 6144;
18918c2ecf20Sopenharmony_ci		maxClock = 110000;
18928c2ecf20Sopenharmony_ci		break;
18938c2ecf20Sopenharmony_ci	}
18948c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
18958c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2070:
18968c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2090:
18978c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2093:
18988c2ecf20Sopenharmony_ci		CursorMem = 2048;
18998c2ecf20Sopenharmony_ci		CursorOff = 0x100;
19008c2ecf20Sopenharmony_ci		break;
19018c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2097:
19028c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2160:
19038c2ecf20Sopenharmony_ci		CursorMem = 1024;
19048c2ecf20Sopenharmony_ci		CursorOff = 0x100;
19058c2ecf20Sopenharmony_ci		break;
19068c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2200:
19078c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2230:
19088c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2360:
19098c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2380:
19108c2ecf20Sopenharmony_ci		CursorMem = 1024;
19118c2ecf20Sopenharmony_ci		CursorOff = 0x1000;
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci		par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
19148c2ecf20Sopenharmony_ci		break;
19158c2ecf20Sopenharmony_ci	}
19168c2ecf20Sopenharmony_ci/*
19178c2ecf20Sopenharmony_ci	info->sprite.size = CursorMem;
19188c2ecf20Sopenharmony_ci	info->sprite.scan_align = 1;
19198c2ecf20Sopenharmony_ci	info->sprite.buf_align = 1;
19208c2ecf20Sopenharmony_ci	info->sprite.flags = FB_PIXMAP_IO;
19218c2ecf20Sopenharmony_ci	info->sprite.outbuf = neofb_draw_cursor;
19228c2ecf20Sopenharmony_ci*/
19238c2ecf20Sopenharmony_ci	par->maxClock = maxClock;
19248c2ecf20Sopenharmony_ci	par->cursorOff = CursorOff;
19258c2ecf20Sopenharmony_ci	return videoRam * 1024;
19268c2ecf20Sopenharmony_ci}
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_cistatic struct fb_info *neo_alloc_fb_info(struct pci_dev *dev,
19308c2ecf20Sopenharmony_ci					 const struct pci_device_id *id)
19318c2ecf20Sopenharmony_ci{
19328c2ecf20Sopenharmony_ci	struct fb_info *info;
19338c2ecf20Sopenharmony_ci	struct neofb_par *par;
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	info = framebuffer_alloc(sizeof(struct neofb_par), &dev->dev);
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	if (!info)
19388c2ecf20Sopenharmony_ci		return NULL;
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	par = info->par;
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	info->fix.accel = id->driver_data;
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	par->pci_burst = !nopciburst;
19458c2ecf20Sopenharmony_ci	par->lcd_stretch = !nostretch;
19468c2ecf20Sopenharmony_ci	par->libretto = libretto;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	par->internal_display = internal;
19498c2ecf20Sopenharmony_ci	par->external_display = external;
19508c2ecf20Sopenharmony_ci	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	switch (info->fix.accel) {
19538c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2070:
19548c2ecf20Sopenharmony_ci		snprintf(info->fix.id, sizeof(info->fix.id),
19558c2ecf20Sopenharmony_ci				"MagicGraph 128");
19568c2ecf20Sopenharmony_ci		break;
19578c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2090:
19588c2ecf20Sopenharmony_ci		snprintf(info->fix.id, sizeof(info->fix.id),
19598c2ecf20Sopenharmony_ci				"MagicGraph 128V");
19608c2ecf20Sopenharmony_ci		break;
19618c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2093:
19628c2ecf20Sopenharmony_ci		snprintf(info->fix.id, sizeof(info->fix.id),
19638c2ecf20Sopenharmony_ci				"MagicGraph 128ZV");
19648c2ecf20Sopenharmony_ci		break;
19658c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2097:
19668c2ecf20Sopenharmony_ci		snprintf(info->fix.id, sizeof(info->fix.id),
19678c2ecf20Sopenharmony_ci				"MagicGraph 128ZV+");
19688c2ecf20Sopenharmony_ci		break;
19698c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2160:
19708c2ecf20Sopenharmony_ci		snprintf(info->fix.id, sizeof(info->fix.id),
19718c2ecf20Sopenharmony_ci				"MagicGraph 128XD");
19728c2ecf20Sopenharmony_ci		break;
19738c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2200:
19748c2ecf20Sopenharmony_ci		snprintf(info->fix.id, sizeof(info->fix.id),
19758c2ecf20Sopenharmony_ci				"MagicGraph 256AV");
19768c2ecf20Sopenharmony_ci		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
19778c2ecf20Sopenharmony_ci		               FBINFO_HWACCEL_COPYAREA |
19788c2ecf20Sopenharmony_ci                	       FBINFO_HWACCEL_FILLRECT;
19798c2ecf20Sopenharmony_ci		break;
19808c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2230:
19818c2ecf20Sopenharmony_ci		snprintf(info->fix.id, sizeof(info->fix.id),
19828c2ecf20Sopenharmony_ci				"MagicGraph 256AV+");
19838c2ecf20Sopenharmony_ci		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
19848c2ecf20Sopenharmony_ci		               FBINFO_HWACCEL_COPYAREA |
19858c2ecf20Sopenharmony_ci                	       FBINFO_HWACCEL_FILLRECT;
19868c2ecf20Sopenharmony_ci		break;
19878c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2360:
19888c2ecf20Sopenharmony_ci		snprintf(info->fix.id, sizeof(info->fix.id),
19898c2ecf20Sopenharmony_ci				"MagicGraph 256ZX");
19908c2ecf20Sopenharmony_ci		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
19918c2ecf20Sopenharmony_ci		               FBINFO_HWACCEL_COPYAREA |
19928c2ecf20Sopenharmony_ci                	       FBINFO_HWACCEL_FILLRECT;
19938c2ecf20Sopenharmony_ci		break;
19948c2ecf20Sopenharmony_ci	case FB_ACCEL_NEOMAGIC_NM2380:
19958c2ecf20Sopenharmony_ci		snprintf(info->fix.id, sizeof(info->fix.id),
19968c2ecf20Sopenharmony_ci				"MagicGraph 256XL+");
19978c2ecf20Sopenharmony_ci		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
19988c2ecf20Sopenharmony_ci		               FBINFO_HWACCEL_COPYAREA |
19998c2ecf20Sopenharmony_ci                	       FBINFO_HWACCEL_FILLRECT;
20008c2ecf20Sopenharmony_ci		break;
20018c2ecf20Sopenharmony_ci	}
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	info->fix.type = FB_TYPE_PACKED_PIXELS;
20048c2ecf20Sopenharmony_ci	info->fix.type_aux = 0;
20058c2ecf20Sopenharmony_ci	info->fix.xpanstep = 0;
20068c2ecf20Sopenharmony_ci	info->fix.ypanstep = 4;
20078c2ecf20Sopenharmony_ci	info->fix.ywrapstep = 0;
20088c2ecf20Sopenharmony_ci	info->fix.accel = id->driver_data;
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	info->fbops = &neofb_ops;
20118c2ecf20Sopenharmony_ci	info->pseudo_palette = par->palette;
20128c2ecf20Sopenharmony_ci	return info;
20138c2ecf20Sopenharmony_ci}
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_cistatic void neo_free_fb_info(struct fb_info *info)
20168c2ecf20Sopenharmony_ci{
20178c2ecf20Sopenharmony_ci	if (info) {
20188c2ecf20Sopenharmony_ci		/*
20198c2ecf20Sopenharmony_ci		 * Free the colourmap
20208c2ecf20Sopenharmony_ci		 */
20218c2ecf20Sopenharmony_ci		fb_dealloc_cmap(&info->cmap);
20228c2ecf20Sopenharmony_ci		framebuffer_release(info);
20238c2ecf20Sopenharmony_ci	}
20248c2ecf20Sopenharmony_ci}
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_cistatic int neofb_probe(struct pci_dev *dev, const struct pci_device_id *id)
20298c2ecf20Sopenharmony_ci{
20308c2ecf20Sopenharmony_ci	struct fb_info *info;
20318c2ecf20Sopenharmony_ci	u_int h_sync, v_sync;
20328c2ecf20Sopenharmony_ci	int video_len, err;
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci	DBG("neofb_probe");
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	err = pci_enable_device(dev);
20378c2ecf20Sopenharmony_ci	if (err)
20388c2ecf20Sopenharmony_ci		return err;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	err = -ENOMEM;
20418c2ecf20Sopenharmony_ci	info = neo_alloc_fb_info(dev, id);
20428c2ecf20Sopenharmony_ci	if (!info)
20438c2ecf20Sopenharmony_ci		return err;
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci	err = neo_map_mmio(info, dev);
20468c2ecf20Sopenharmony_ci	if (err)
20478c2ecf20Sopenharmony_ci		goto err_map_mmio;
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	err = neo_scan_monitor(info);
20508c2ecf20Sopenharmony_ci	if (err)
20518c2ecf20Sopenharmony_ci		goto err_scan_monitor;
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	video_len = neo_init_hw(info);
20548c2ecf20Sopenharmony_ci	if (video_len < 0) {
20558c2ecf20Sopenharmony_ci		err = video_len;
20568c2ecf20Sopenharmony_ci		goto err_init_hw;
20578c2ecf20Sopenharmony_ci	}
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	err = neo_map_video(info, dev, video_len);
20608c2ecf20Sopenharmony_ci	if (err)
20618c2ecf20Sopenharmony_ci		goto err_init_hw;
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	if (!fb_find_mode(&info->var, info, mode_option, NULL, 0,
20648c2ecf20Sopenharmony_ci			info->monspecs.modedb, 16)) {
20658c2ecf20Sopenharmony_ci		printk(KERN_ERR "neofb: Unable to find usable video mode.\n");
20668c2ecf20Sopenharmony_ci		err = -EINVAL;
20678c2ecf20Sopenharmony_ci		goto err_map_video;
20688c2ecf20Sopenharmony_ci	}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	/*
20718c2ecf20Sopenharmony_ci	 * Calculate the hsync and vsync frequencies.  Note that
20728c2ecf20Sopenharmony_ci	 * we split the 1e12 constant up so that we can preserve
20738c2ecf20Sopenharmony_ci	 * the precision and fit the results into 32-bit registers.
20748c2ecf20Sopenharmony_ci	 *  (1953125000 * 512 = 1e12)
20758c2ecf20Sopenharmony_ci	 */
20768c2ecf20Sopenharmony_ci	h_sync = 1953125000 / info->var.pixclock;
20778c2ecf20Sopenharmony_ci	h_sync =
20788c2ecf20Sopenharmony_ci	    h_sync * 512 / (info->var.xres + info->var.left_margin +
20798c2ecf20Sopenharmony_ci			    info->var.right_margin + info->var.hsync_len);
20808c2ecf20Sopenharmony_ci	v_sync =
20818c2ecf20Sopenharmony_ci	    h_sync / (info->var.yres + info->var.upper_margin +
20828c2ecf20Sopenharmony_ci		      info->var.lower_margin + info->var.vsync_len);
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	printk(KERN_INFO "neofb v" NEOFB_VERSION
20858c2ecf20Sopenharmony_ci	       ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
20868c2ecf20Sopenharmony_ci	       info->fix.smem_len >> 10, info->var.xres,
20878c2ecf20Sopenharmony_ci	       info->var.yres, h_sync / 1000, h_sync % 1000, v_sync);
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	err = fb_alloc_cmap(&info->cmap, 256, 0);
20908c2ecf20Sopenharmony_ci	if (err < 0)
20918c2ecf20Sopenharmony_ci		goto err_map_video;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	err = register_framebuffer(info);
20948c2ecf20Sopenharmony_ci	if (err < 0)
20958c2ecf20Sopenharmony_ci		goto err_reg_fb;
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	fb_info(info, "%s frame buffer device\n", info->fix.id);
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci	/*
21008c2ecf20Sopenharmony_ci	 * Our driver data
21018c2ecf20Sopenharmony_ci	 */
21028c2ecf20Sopenharmony_ci	pci_set_drvdata(dev, info);
21038c2ecf20Sopenharmony_ci	return 0;
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_cierr_reg_fb:
21068c2ecf20Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
21078c2ecf20Sopenharmony_cierr_map_video:
21088c2ecf20Sopenharmony_ci	neo_unmap_video(info);
21098c2ecf20Sopenharmony_cierr_init_hw:
21108c2ecf20Sopenharmony_ci	fb_destroy_modedb(info->monspecs.modedb);
21118c2ecf20Sopenharmony_cierr_scan_monitor:
21128c2ecf20Sopenharmony_ci	neo_unmap_mmio(info);
21138c2ecf20Sopenharmony_cierr_map_mmio:
21148c2ecf20Sopenharmony_ci	neo_free_fb_info(info);
21158c2ecf20Sopenharmony_ci	return err;
21168c2ecf20Sopenharmony_ci}
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_cistatic void neofb_remove(struct pci_dev *dev)
21198c2ecf20Sopenharmony_ci{
21208c2ecf20Sopenharmony_ci	struct fb_info *info = pci_get_drvdata(dev);
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	DBG("neofb_remove");
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	if (info) {
21258c2ecf20Sopenharmony_ci		unregister_framebuffer(info);
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci		neo_unmap_video(info);
21288c2ecf20Sopenharmony_ci		fb_destroy_modedb(info->monspecs.modedb);
21298c2ecf20Sopenharmony_ci		neo_unmap_mmio(info);
21308c2ecf20Sopenharmony_ci		neo_free_fb_info(info);
21318c2ecf20Sopenharmony_ci	}
21328c2ecf20Sopenharmony_ci}
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_cistatic const struct pci_device_id neofb_devices[] = {
21358c2ecf20Sopenharmony_ci	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
21368c2ecf20Sopenharmony_ci	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
21398c2ecf20Sopenharmony_ci	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
21428c2ecf20Sopenharmony_ci	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
21458c2ecf20Sopenharmony_ci	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
21488c2ecf20Sopenharmony_ci	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
21518c2ecf20Sopenharmony_ci	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
21548c2ecf20Sopenharmony_ci	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
21578c2ecf20Sopenharmony_ci	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
21608c2ecf20Sopenharmony_ci	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci	{0, 0, 0, 0, 0, 0, 0}
21638c2ecf20Sopenharmony_ci};
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, neofb_devices);
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_cistatic struct pci_driver neofb_driver = {
21688c2ecf20Sopenharmony_ci	.name =		"neofb",
21698c2ecf20Sopenharmony_ci	.id_table =	neofb_devices,
21708c2ecf20Sopenharmony_ci	.probe =	neofb_probe,
21718c2ecf20Sopenharmony_ci	.remove =	neofb_remove,
21728c2ecf20Sopenharmony_ci};
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci/* ************************* init in-kernel code ************************** */
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci#ifndef MODULE
21778c2ecf20Sopenharmony_cistatic int __init neofb_setup(char *options)
21788c2ecf20Sopenharmony_ci{
21798c2ecf20Sopenharmony_ci	char *this_opt;
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	DBG("neofb_setup");
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	if (!options || !*options)
21848c2ecf20Sopenharmony_ci		return 0;
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	while ((this_opt = strsep(&options, ",")) != NULL) {
21878c2ecf20Sopenharmony_ci		if (!*this_opt)
21888c2ecf20Sopenharmony_ci			continue;
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci		if (!strncmp(this_opt, "internal", 8))
21918c2ecf20Sopenharmony_ci			internal = 1;
21928c2ecf20Sopenharmony_ci		else if (!strncmp(this_opt, "external", 8))
21938c2ecf20Sopenharmony_ci			external = 1;
21948c2ecf20Sopenharmony_ci		else if (!strncmp(this_opt, "nostretch", 9))
21958c2ecf20Sopenharmony_ci			nostretch = 1;
21968c2ecf20Sopenharmony_ci		else if (!strncmp(this_opt, "nopciburst", 10))
21978c2ecf20Sopenharmony_ci			nopciburst = 1;
21988c2ecf20Sopenharmony_ci		else if (!strncmp(this_opt, "libretto", 8))
21998c2ecf20Sopenharmony_ci			libretto = 1;
22008c2ecf20Sopenharmony_ci		else
22018c2ecf20Sopenharmony_ci			mode_option = this_opt;
22028c2ecf20Sopenharmony_ci	}
22038c2ecf20Sopenharmony_ci	return 0;
22048c2ecf20Sopenharmony_ci}
22058c2ecf20Sopenharmony_ci#endif  /*  MODULE  */
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_cistatic int __init neofb_init(void)
22088c2ecf20Sopenharmony_ci{
22098c2ecf20Sopenharmony_ci#ifndef MODULE
22108c2ecf20Sopenharmony_ci	char *option = NULL;
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci	if (fb_get_options("neofb", &option))
22138c2ecf20Sopenharmony_ci		return -ENODEV;
22148c2ecf20Sopenharmony_ci	neofb_setup(option);
22158c2ecf20Sopenharmony_ci#endif
22168c2ecf20Sopenharmony_ci	return pci_register_driver(&neofb_driver);
22178c2ecf20Sopenharmony_ci}
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_cimodule_init(neofb_init);
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci#ifdef MODULE
22228c2ecf20Sopenharmony_cistatic void __exit neofb_exit(void)
22238c2ecf20Sopenharmony_ci{
22248c2ecf20Sopenharmony_ci	pci_unregister_driver(&neofb_driver);
22258c2ecf20Sopenharmony_ci}
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_cimodule_exit(neofb_exit);
22288c2ecf20Sopenharmony_ci#endif				/* MODULE */
2229