/* $XConsortium: init.c,v 1.1 95/01/26 15:30:17 kaleb Exp $ */
/* $XFree86: xc/programs/Xserver/hw/xfree86/accel/ibm8514/init.c,v 3.2 1995/01/28 15:51:47 dawes Exp $ */
/*
 * Written by Jake Richter
 * Copyright (c) 1989, 1990 Panacea Inc., Londonderry, NH - All Rights Reserved
 *
 * This code may be freely incorporated in any program without royalty, as
 * long as the copyright notice stays intact.
 *
 * Additions by Kevin E. Martin (martin@cs.unc.edu)
 *
 * KEVIN E. MARTIN AND TIAGO GONS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 * IN NO EVENT SHALL KEVIN E. MARTIN OR TIAGO GONS BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Modified by Tiago Gons (tiago@comosjn.hobby.nl)
 */


#include "X.h"
#include "input.h"
#include "reg8514.h"
#include "ibm8514.h"
#include "xf86.h"
#include "xf86_OSlib.h"

static short numPlanes = -1;
static short resolution = -1;
static short old_DAC_MASK = -1;
static LUTENTRY oldlut[256];
static short LUTInited = -1;


void ibm8514CleanUp(void)
{
    int i;

    if (LUTInited != -1) {
	outb(DAC_W_INDEX, 0);
	for (i = 0; i < 256; i++) {
	    outb(DAC_DATA, oldlut[i].r);
	    outb(DAC_DATA, oldlut[i].g);
	    outb(DAC_DATA, oldlut[i].b);
	}
    }

    if (old_DAC_MASK != -1) {
	outb(DAC_MASK, old_DAC_MASK);
    }
    outw(ADVFUNC_CNTL, 6);

    xf86DisableIOPorts(ibm8514InfoRec.scrnIndex);
}

/*	ibm8514Init(res)

	Initializes the 8514/A into the requested resolution.  Valid input
        values are 0 for 640x480 and 1 for 1024x768.
*/
void ibm8514Init(short res)
{
    static short initRegs[] = {
	DISP_CNTL, ADVFUNC_CNTL, V_TOTAL, V_SYNC_STRT,
	V_DISP, H_TOTAL, H_SYNC_STRT, H_DISP,
	H_SYNC_WID, V_SYNC_WID, DISP_CNTL, 0
    };

    static short mode640x4[] = {
        0x0041, 0x0003, 0x0830, 0x07a8,
        0x0779, 0x0063, 0x0052, 0x004f,
        0x002c, 0x0022, 0x0021
    };

    static short mode640x8[] = {
        0x0043, 0x0003, 0x0418, 0x03d2,
        0x033b, 0x0063, 0x0052, 0x004f,
        0x002c, 0x0022, 0x0023
    };

    static short mode1024x4[] = {
        0x0053, 0x0007, 0x0660, 0x0600,
        0x05fb, 0x009d, 0x0081, 0x007f,
        0x0016, 0x0008, 0x0033
    };

    static short mode1024x8[] = {
        0x0053, 0x0007, 0x0660, 0x0600,
        0x05fb, 0x009d, 0x0081, 0x007f,
        0x0016, 0x0008, 0x0033
    };

    static short *modeList[] = {mode640x4, mode1024x4, mode640x8, mode1024x8};

    short i;

    /* Get board status information */
    i = inw(SUBSYS_STAT);

#if 0
    /* Check if monitor capable of 1024x768 is attached.
     * If not, print error message and abort.
     * In this case, we want an IBM 8514 compatible monitor.
     */
    if ((i & MONITORID_MASK) != MONITORID_8514) {
	ibm8514CleanUp();
	FatalError("Attached monitor not capable of displaying 8514!\n");
    }
#endif

    old_DAC_MASK = inb(DAC_MASK);
    outb(DAC_MASK, 0x00);

    /* Determine the pixel depth of the board.  Then, based on depth,
     * set the memory control register use the appropriate CAS (VRAM
     * Column Address Select) configuration.
     */
    if (i & _8PLANE) {
	numPlanes = 8;
	outw(MULTIFUNC_CNTL, MEM_CNTL | VRTCFG_4 | HORCFG_8);
    } else {
	numPlanes = 4;
	ibm8514CleanUp();
	FatalError("Video card only has 512Kb (1Mb required)!\n");
    }

    /* Now initialize the display controller part of the 8514/A.
     * We have set up the initialization values in two sets of
     * tables:  4 bpp and 8 bpp.  The "numPlanes" comparison below
     * determines which set of values to use (dual indices).
     */
    for (i = 0; initRegs[i] != 0; i++)
	outw(initRegs[i], modeList[res + (numPlanes == 4 ? 0:2)][i]);

    /* Now reenable the screen, but only the planes that actually exist.
     * Otherwise, you end up with bus noise on the display.
     */
    if (numPlanes == 8)
	outb(DAC_MASK, 0xff);
    else
	outb(DAC_MASK, 0x0f);

    resolution = res;
}

/*	InitLUT()

	Loads the Look-Up Table with all black.
	Assumes 8-bit board is in use.  If 4 bit board, the only the first
	16 entries in LUT will be used.
*/
void InitLUT(void)
{
    short i, j;

    outb(DAC_R_INDEX, 0);
    for (i = 0; i < 256; i++) {
	oldlut[i].r = inb(DAC_DATA);
	oldlut[i].g = inb(DAC_DATA);
	oldlut[i].b = inb(DAC_DATA);
    }
    LUTInited = 1;

    outb(DAC_W_INDEX, 0);

    /* Load the first 16 LUT entries */
    for (i = 0; i < 16; i++) {
	outb(DAC_DATA, 0);
	outb(DAC_DATA, 0);
	outb(DAC_DATA, 0);
    }

    if (numPlanes == 8) {
	/* Load the remaining 240 LUT entries */
	for (i = 1; i < 16; i++) {
	    for (j = 0; j < 16; j++) {
		outb(DAC_DATA, 0);
		outb(DAC_DATA, 0);
		outb(DAC_DATA, 0);
	    }
	}
    }
}

/*	InitEnvironment()

	Initializes the 8514/A's drawing environment and clears the display.
*/
void InitEnvironment(void)
{

    InitLUT();

    /* Current mixes, src, foreground active */
    outw(FRGD_MIX, FSS_FRGDCOL | MIX_SRC);
    outw(BKGD_MIX, BSS_BKGDCOL | MIX_SRC);

    /* Clipping rectangle to full drawable space */
    outw(MULTIFUNC_CNTL, SCISSORS_T | 0x000);
    outw(MULTIFUNC_CNTL, SCISSORS_L | 0x000);
    if (resolution == MODE_640) {
	outw(MULTIFUNC_CNTL, SCISSORS_R | 0x3ff); /* Should these be */
	outw(MULTIFUNC_CNTL, SCISSORS_B | 0x3ff); /* different???    */
    } else {
	outw(MULTIFUNC_CNTL, SCISSORS_R | 0x3ff);
	outw(MULTIFUNC_CNTL, SCISSORS_B | 0x3ff);
    }

    /* Enable writes to all planes and reset color compare */
    outw(WRT_MASK, 0xffff);
    outw(MULTIFUNC_CNTL, PIX_CNTL | 0x0000);

#ifndef DIRTY_STARTUP
    if (serverGeneration == 1) /* 5-5-93 TCG : servergen.. is always 1 ? */
    {
	/* Clear the display.  Need to set the color, origin, and size.
	 * Then draw.
	 */
	WaitQueue(6);
	outw(FRGD_COLOR, 1);
	outw(CUR_X, 0);
	outw(CUR_Y, 0);
	outw(MAJ_AXIS_PCNT, 1023);
	outw(MULTIFUNC_CNTL, MIN_AXIS_PCNT | 1023);
	outw(CMD, CMD_RECT | INC_Y | INC_X | DRAW | PLANAR | WRTDATA);
    }
#endif /* ! DIRTY_STARTUP */

    WaitQueue(4);

    /* Reset current draw position */
    outw(CUR_X, 0);
    outw(CUR_Y, 0);

    /* Reset current colors, foreground is all on, background is 0. */
    outw(FRGD_COLOR, 0xffff);
    outw(BKGD_COLOR, 0x0000);
}
