#if defined(JAZZ)

/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    jzvxl484.c

cAbstract:

    This module implements the video prom code for the Jazz VXL BT484

Author:

    Lluis Abello (lluis) 28-May-1992

Environment:

    Kernel mode.


Revision History:

--*/

#include "fwp.h"
#include "jzvxl484.h"
#include "jxvideo.h"
#include "jaginit.h"

#define KeFlushWriteBuffer()

ARC_STATUS
InitializeBt484(
    IN PVIDEO_VIRTUAL_SPACE VirtualAdr
    );

VOID
FillVideoMemory(
    IN ULONG StartAddress,
    IN ULONG Size,
    IN ULONG Pattern
    );

ULONG
CheckVideoMemoryAddressTest(
    IN ULONG StartAddress,
    IN ULONG Size
    );

VOID
WriteVideoMemoryAddressTest(
    IN ULONG StartAddress,
    IN ULONG Size
    );


//
// Define colors, HI = High Intensity
//

#define BT484_PALETTE_BLACK_R      0x00
#define BT484_PALETTE_BLACK_G      0x00
#define BT484_PALETTE_BLACK_B      0x00

#define BT484_PALETTE_RED_R        0xB0
#define BT484_PALETTE_RED_G        0x00
#define BT484_PALETTE_RED_B        0x00

#define BT484_PALETTE_GREEN_R      0x00
#define BT484_PALETTE_GREEN_B      0xB0
#define BT484_PALETTE_GREEN_G      0x00

#define BT484_PALETTE_YELLOW_R     0xB0
#define BT484_PALETTE_YELLOW_G     0xB0
#define BT484_PALETTE_YELLOW_B     0x00

#define BT484_PALETTE_BLUE_R       0x00
#define BT484_PALETTE_BLUE_G       0x00
#define BT484_PALETTE_BLUE_B       0xB0

#define BT484_PALETTE_MAGENTA_R    0xB0
#define BT484_PALETTE_MAGENTA_G    0x00
#define BT484_PALETTE_MAGENTA_B    0xB0

#define BT484_PALETTE_CYAN_R       0x00
#define BT484_PALETTE_CYAN_G       0xB0
#define BT484_PALETTE_CYAN_B       0xB0

#define BT484_PALETTE_WHITE_R      0xB0
#define BT484_PALETTE_WHITE_G      0xB0
#define BT484_PALETTE_WHITE_B      0xB0

#define BT484_PALETTE_HI_BLACK_R   0x00
#define BT484_PALETTE_HI_BLACK_G   0x00
#define BT484_PALETTE_HI_BLACK_B   0x00

#define BT484_PALETTE_HI_RED_R     0xFF
#define BT484_PALETTE_HI_RED_G     0x00
#define BT484_PALETTE_HI_RED_B     0x00

#define BT484_PALETTE_HI_GREEN_R   0x00
#define BT484_PALETTE_HI_GREEN_G   0xFF
#define BT484_PALETTE_HI_GREEN_B   0x00

#define BT484_PALETTE_HI_YELLOW_R  0xFF
#define BT484_PALETTE_HI_YELLOW_G  0xFF
#define BT484_PALETTE_HI_YELLOW_B  0x00

#define BT484_PALETTE_HI_BLUE_R    0x00
#define BT484_PALETTE_HI_BLUE_G    0x00
#define BT484_PALETTE_HI_BLUE_B    0xFF

#define BT484_PALETTE_HI_MAGENTA_R 0xFF
#define BT484_PALETTE_HI_MAGENTA_G 0x00
#define BT484_PALETTE_HI_MAGENTA_B 0xFF

#define BT484_PALETTE_HI_CYAN_R    0x00
#define BT484_PALETTE_HI_CYAN_G    0xFF
#define BT484_PALETTE_HI_CYAN_B    0xFF

#define BT484_PALETTE_HI_WHITE_R   0xFF
#define BT484_PALETTE_HI_WHITE_G   0xFF
#define BT484_PALETTE_HI_WHITE_B   0xFF


UCHAR ColorTable[16*3]={
    BT484_PALETTE_BLACK_R,
    BT484_PALETTE_BLACK_G,
    BT484_PALETTE_BLACK_B,
    BT484_PALETTE_RED_R,
    BT484_PALETTE_RED_G,
    BT484_PALETTE_RED_B,
    BT484_PALETTE_GREEN_R,
    BT484_PALETTE_GREEN_B,
    BT484_PALETTE_GREEN_G,
    BT484_PALETTE_YELLOW_R,
    BT484_PALETTE_YELLOW_G,
    BT484_PALETTE_YELLOW_B,
    BT484_PALETTE_BLUE_R,
    BT484_PALETTE_BLUE_G,
    BT484_PALETTE_BLUE_B,
    BT484_PALETTE_MAGENTA_R,
    BT484_PALETTE_MAGENTA_G,
    BT484_PALETTE_MAGENTA_B,
    BT484_PALETTE_CYAN_R,
    BT484_PALETTE_CYAN_G,
    BT484_PALETTE_CYAN_B,
    BT484_PALETTE_WHITE_R,
    BT484_PALETTE_WHITE_G,
    BT484_PALETTE_WHITE_B,
    BT484_PALETTE_HI_BLACK_R,
    BT484_PALETTE_HI_BLACK_G,
    BT484_PALETTE_HI_BLACK_B,
    BT484_PALETTE_HI_RED_R,
    BT484_PALETTE_HI_RED_G,
    BT484_PALETTE_HI_RED_B,
    BT484_PALETTE_HI_GREEN_R,
    BT484_PALETTE_HI_GREEN_G,
    BT484_PALETTE_HI_GREEN_B,
    BT484_PALETTE_HI_YELLOW_R,
    BT484_PALETTE_HI_YELLOW_G,
    BT484_PALETTE_HI_YELLOW_B,
    BT484_PALETTE_HI_BLUE_R,
    BT484_PALETTE_HI_BLUE_G,
    BT484_PALETTE_HI_BLUE_B,
    BT484_PALETTE_HI_MAGENTA_R,
    BT484_PALETTE_HI_MAGENTA_G,
    BT484_PALETTE_HI_MAGENTA_B,
    BT484_PALETTE_HI_CYAN_R,
    BT484_PALETTE_HI_CYAN_G,
    BT484_PALETTE_HI_CYAN_B,
    BT484_PALETTE_HI_WHITE_R,
    BT484_PALETTE_HI_WHITE_G,
    BT484_PALETTE_HI_WHITE_B
    };

//
// Define colors, HI = High Intensity
//

#define FW_COLOR_BLACK      0x00
#define FW_COLOR_RED        0x01
#define FW_COLOR_GREEN      0x02
#define FW_COLOR_YELLOW     0x03
#define FW_COLOR_BLUE       0x04
#define FW_COLOR_MAGENTA    0x05
#define FW_COLOR_CYAN       0x06
#define FW_COLOR_WHITE      0x07
#define FW_COLOR_HI_BLACK   0x08
#define FW_COLOR_HI_RED     0x09
#define FW_COLOR_HI_GREEN   0x0A
#define FW_COLOR_HI_YELLOW  0x0B
#define FW_COLOR_HI_BLUE    0x0C
#define FW_COLOR_HI_MAGENTA 0x0D
#define FW_COLOR_HI_CYAN    0x0E
#define FW_COLOR_HI_WHITE   0x0F


ARC_STATUS
InitializeVXL (
    IN PVIDEO_VIRTUAL_SPACE VirtualAdr,
    IN PMONITOR_CONFIGURATION_DATA Monitor
    )

/*++

Routine Description:

    This routine initializes the JazzVxl Graphics accelerator.

Arguments:

    Monitor - Monitor configuration data.
    VirtualAdr - Pointer to a pair of virtual addresses for video&Control spaces.

Return Value:

    If the video was initialized, ESUCCESS is returned, otherwise an error
    code is returned.

--*/

{
    ULONG Index;
    PJAGUAR_REGISTERS Jaguar = (PJAGUAR_REGISTERS)(VirtualAdr->ControlVirtualBase + VXL_JAGUAR_BASE_OFFSET);
    PBT484_REGISTERS  Bt484  = (PBT484_REGISTERS)(VirtualAdr->ControlVirtualBase + VXL_BT484_BASE_OFFSET);
    PUCHAR            Clock  = (PUCHAR)(VirtualAdr->ControlVirtualBase + VXL_CLOCK_BASE_OFFSET);
    UCHAR             DataChar;
    UCHAR             CmdReg0;
    ULONG             VideoMemory = VirtualAdr->MemoryVirtualBase;
    JAGUAR_REG_INIT   JagInitData;
    ULONG             Status;



    //
    // Define clock value for the ICS part (pS)
    //

    ULONG               ClockResList[32] = {    4,    4,    4,    4,    4,    4,    4,    4,
                                                4,    4,42918,40984,38760,36724,33523,31017,
                                            29197,27548,24882,23491,22482,21468,20509,19920,
                                            18692,18054,16722,15015,14773,14053,13040,    4};

    //
    //  Define a default jaguar init and monitor config for
    //  use when a BOGUS init value is sent.
    //

    JAGUAR_REG_INIT JagDefaultData = {
            0xc,        // Clock Selector
            0,          // Bt485 clock 2x multiply
            1,          // BitBlt Control
            0,          // TopOfScreen
            41,         // Horizontal Blank
            4,          // Horizontal Begin Sync
            29,         // Horizontal End Sync
            201,        // Horizontal Total
            45,         // Vertical Blank
            11,         // Vertical Begin Sync
            13,         // Vertical End Sync
            525,        // Vertical Total
            0x200,      // XFER LENGTH
            4,          // Vertival Interrupt Line
            640         // Screen X
    };


    MONITOR_CONFIGURATION_DATA  DefaultMonitor = {
        0,              // version      :do not change
        0,              // revision     :do not change
        640,            // HorizontalResolution
        25422,          // HorizontalDisplayTime
        636,            // HorizontalBackPorch
        1907,           // HorizontalFrontPorch
        3813,           // HorizontalSync
        480,            // VerticalResolution
        33,             // VerticalBackPorch
        10,             // VerticalFrontPorch
         2,             // VerticalSync
         0,             // HorizontalScreenSize    : do not change
         0              // VerticalScreenSize      : do not change
    };


    LONG                HorDisplayTime;
    LONG                HorResolutionDiv;
    LONG                ReqClockPeriod;
    LONG                CurrentClockError;
    LONG                MinErrorValue;
    USHORT              MinErrorIndex;
    LONG                ShiftClockPeriod;

    USHORT              BoardTypeBt485;


    //
    // Test the first bank of video memory
    //

    WriteVideoMemoryAddressTest(VideoMemory,
                    0x200000
                    );

    Status = CheckVideoMemoryAddressTest(VideoMemory,
                    0x200000
                    );

    if (Status != 0) {
        return EINVAL;
    }

    //
    //  Determine if this is a Bt484 or Bt485 board. To do this write a 1 to command
    //  register bit 07 then write 01 to the address register 0. This will enable
    //  read/writes to command register 3 on a Bt485 but not on a Bt484. Clear
    //  Command register 3 then read it back. On a Bt485 the return value will be 0x00,
    //  on a Bt484 it will be 0x40.
    //


    //
    // Get the value in command register 0, then set bit 07
    //

    DataChar = READ_REGISTER_UCHAR(&Bt484->Command0.Byte);
    DataChar |= 0x80;
    WRITE_REGISTER_UCHAR(&Bt484->Command0.Byte,DataChar);

    //
    //  Write 0x01 to the address register
    //

    WRITE_REGISTER_UCHAR(&Bt484->PaletteCursorWrAddress.Byte,0x01);

    //
    //  Clear command register 3
    //

    WRITE_REGISTER_UCHAR(&Bt484->Status.Byte,0x00);

    //
    // Read Command Register 3 back and compare
    //

    DataChar = READ_REGISTER_UCHAR(&Bt484->Status.Byte);

    if (DataChar != 0x00) {

        //
        // This is a Bt484
        //

        BoardTypeBt485   = 0;
        JagInitData.Bt485Multiply = 0;

    } else {

        //
        // This is a Bt485
        //

        BoardTypeBt485   = 1;
        JagInitData.Bt485Multiply = 0;
    }

    //
    //  Calculate the requested clock frequency then find the closest match in the
    //  ICS clock frequency table. The requested clock frequency in picoseconds =
    //
    //       Horizontal display time * 1000
    //       ------------------------------
    //           horizontal resolution
    //
    //

    HorDisplayTime = Monitor->HorizontalDisplayTime  * 1000;
    HorResolutionDiv = Monitor->HorizontalResolution;

    ReqClockPeriod = HorDisplayTime / HorResolutionDiv;

    //
    //  Check for a configuration needing a Bt485 and a board that is a 484. In
    //  This case we will have to resort to a default 640 x 480 config
    //

    if ((BoardTypeBt485 == 0) & (ReqClockPeriod < ClockResList[30])) {

        //
        // We were told to display a mode that we don't support, set
        // the output to the default mode and also return the monitor
        // info to a default mode which will later be stored into
        // NVRAM so that the HAL will init ok and also the next ROM init
        // will be correct.
        //

        JagInitData = JagDefaultData;

        Monitor->HorizontalResolution = DefaultMonitor.HorizontalResolution;
        Monitor->HorizontalDisplayTime = DefaultMonitor.HorizontalDisplayTime;
        Monitor->HorizontalBackPorch = DefaultMonitor.HorizontalBackPorch;
        Monitor->HorizontalFrontPorch = DefaultMonitor.HorizontalFrontPorch;
        Monitor->HorizontalSync = DefaultMonitor.HorizontalSync;
        Monitor->VerticalResolution = DefaultMonitor.VerticalResolution;
        Monitor->VerticalBackPorch = DefaultMonitor.VerticalBackPorch;
        Monitor->VerticalFrontPorch = DefaultMonitor.VerticalFrontPorch;
        Monitor->VerticalSync = DefaultMonitor.VerticalSync;

    } else {

        //
        // Check for a Bt485 frequency
        //

        if ((BoardTypeBt485 == 1) & (ReqClockPeriod < ClockResList[30])) {
            ReqClockPeriod = ReqClockPeriod * 2;
            JagInitData.Bt485Multiply = 1;
        }



        MinErrorIndex = 0;

        //
        //  Gaurentee a maximum starting error
        //

        MinErrorValue = ReqClockPeriod + 1;

        for (Index=0;Index<32;Index++) {

            //
            // Calculate the absolute value of clock error and find the
            // closest match in the array of clock values
            //

            CurrentClockError = ReqClockPeriod - ClockResList[Index];
            if (CurrentClockError < 0) {
                CurrentClockError *= -1;
            }

            if (CurrentClockError < MinErrorValue) {
                MinErrorValue = CurrentClockError;
                MinErrorIndex = Index;
            }
        }

        //
        //  We now have a closest match in the clock array, now calculate the
        //  values for the Bt484/Bt485 register values
        //

        JagInitData.ClockFreq               = MinErrorIndex;
        JagInitData.BitBltControl           = 1;
        JagInitData.TopOfScreen             = 0;
        JagInitData.XferLength              = 0x200;
        JagInitData.VerticalInterruptLine   = 4;
        JagInitData.HorizontalDisplay       = Monitor->HorizontalResolution;


        //
        //  All jaguar timing values are based on the brooktree shift clock value which
        //  is the clock frequency divided by 4. (period * 4) If this is a Bt485 using
        //  its internal 2x clock multiplier than is is period * 2; (freq * 2 / 4)
        //


        if (JagInitData.Bt485Multiply == 1) {
            ShiftClockPeriod      = ClockResList[MinErrorIndex] * 2;
        } else {
            ShiftClockPeriod      = ClockResList[MinErrorIndex] * 4;
        }


        JagInitData.HorizontalBlank     = ((Monitor->HorizontalBackPorch +
                                            Monitor->HorizontalSync      +
                                            Monitor->HorizontalFrontPorch) * 1000)
                                        / ShiftClockPeriod;

        JagInitData.HorizontalBeginSync = (Monitor->HorizontalFrontPorch * 1000)
                                        / ShiftClockPeriod;

        JagInitData.HorizontalEndSync   = ((Monitor->HorizontalSync      +
                                            Monitor->HorizontalFrontPorch) * 1000)
                                        / ShiftClockPeriod;

        JagInitData.HorizontalLine      = JagInitData.HorizontalBlank +
                                        (Monitor->HorizontalResolution / 4);


        JagInitData.VerticalBlank       = Monitor->VerticalBackPorch +
                                        Monitor->VerticalSync      +
                                        Monitor->VerticalFrontPorch;


        JagInitData.VerticalBeginSync   = Monitor->VerticalFrontPorch;

        JagInitData.VerticalEndSync     = Monitor->VerticalFrontPorch +
                                        Monitor->VerticalSync;

        JagInitData.VerticalLine        = Monitor->VerticalBackPorch +
                                        Monitor->VerticalSync      +
                                        Monitor->VerticalFrontPorch +
                                        Monitor->VerticalResolution;

    }

    //
    // Start ICS Clock pll and stabilize.
    //

    WRITE_REGISTER_UCHAR(Clock,JagInitData.ClockFreq);

    //
    //  Wait 10 uS for PLL clock to stabilize on the video board
    //
    for (Index=0;Index<10;Index++) {
        READ_REGISTER_UCHAR(Clock);
    }

    //
    // Initialize Bt484 Command Register 0 to:
    //
    // 8 Bit DAC Resolution
    //

    CmdReg0 = 0;
    ((PBT484_COMMAND0)(&CmdReg0))->DacResolution = 1;
    ((PBT484_COMMAND0)(&CmdReg0))->GreenSyncEnable = 1;
    ((PBT484_COMMAND0)(&CmdReg0))->SetupEnable = 1;
    WRITE_REGISTER_UCHAR(&Bt484->Command0.Byte,CmdReg0);

    //
    // Initialize Command Register 1 to:
    //

    DataChar = 0;

    ((PBT484_COMMAND1)(&DataChar))->BitsPerPixel = VXL_EIGHT_BITS_PER_PIXEL;


    WRITE_REGISTER_UCHAR(&Bt484->Command1.Byte,DataChar);

    //
    // Initialize Command Register 2 to:
    //
    // SCLK Enabled
    // TestMode disabled
    // PortselMask Non Masked
    // PCLK 1
    // NonInterlaced
    //

    DataChar = 0;
    ((PBT484_COMMAND2)(&DataChar))->SclkDisable = 0;
    ((PBT484_COMMAND2)(&DataChar))->TestEnable  = 0;
    ((PBT484_COMMAND2)(&DataChar))->PortselMask = 1;
    ((PBT484_COMMAND2)(&DataChar))->PclkSelect  = 1;
    ((PBT484_COMMAND2)(&DataChar))->InterlacedDisplay = 0;
    ((PBT484_COMMAND2)(&DataChar))->PaletteIndexing = CONTIGUOUS_PALETTE;
    ((PBT484_COMMAND2)(&DataChar))->CursorMode = BT_CURSOR_WINDOWS;


    WRITE_REGISTER_UCHAR(&Bt484->Command2.Byte,DataChar);

    //
    // if JagInitData.ClockFreq bit 8 is set then this is a Bt485 mode that requires
    // the internal 2x clock multiplier to be enabled.
    //

    if (JagInitData.Bt485Multiply == 1) {

        //
        // To access cmd register 3, first set bit CR17 in command register 0
        //

        CmdReg0 |= 0x80;
        WRITE_REGISTER_UCHAR(&Bt484->Command0.Byte,CmdReg0);

        //
        // Write a 0x01 to Address register
        //

        WRITE_REGISTER_UCHAR(&Bt484->PaletteCursorWrAddress.Byte,0x01);

        //
        //  Write to cmd register 3 in the status register location. Cmd3 is initialized
        //  to turn on the 2x clock multiplier.
        //

        DataChar = 0;
        ((PBT484_COMMAND3)(&DataChar))->ClockMultiplier = 1;

        WRITE_REGISTER_UCHAR(&Bt484->Status.Byte,DataChar);

        //
        //  Allow 10 uS for the 2x multiplier to stabilize
        //

        for (Index=0;Index<10;Index++) {
            READ_REGISTER_UCHAR(Clock);
        }
    }




    //
    // Initialize Color Palette.
    //
    // Set address pointer to base of color palette.
    // Initialize first 16 entries from color table.
    // Zero remaining entries.
    //

    WRITE_REGISTER_UCHAR(&Bt484->PaletteCursorWrAddress.Byte,0);

    for (Index=0;Index<16*3;Index++) {
        WRITE_REGISTER_UCHAR(&Bt484->PaletteColor.Byte,ColorTable[Index]);
    }

    for (;Index<256*3;Index++) {
        WRITE_REGISTER_UCHAR(&Bt484->PaletteColor.Byte,0);
    }

    //
    // Initialize Cursor and Overscan color.
    //
    // Set address pointer base.
    // Zero 4 entries.
    //

    WRITE_REGISTER_UCHAR(&Bt484->CursorColorWrAddress.Byte,0);

    for (Index=0;Index<4*3;Index++) {
        WRITE_REGISTER_UCHAR(&Bt484->CursorColor.Byte,0);
    }

    //
    // Initialize cursor RAM
    //
    // Set address pointer to base of ram.
    // Clear both planes
    //

    WRITE_REGISTER_UCHAR(&Bt484->PaletteCursorWrAddress.Byte,0);

    for (Index=0;Index<256;Index++) {
        WRITE_REGISTER_UCHAR(&Bt484->CursorRam.Byte,0);
    }


    //
    //  Initialize cursor position registers--cursor off.
    //

    WRITE_REGISTER_UCHAR(&Bt484->CursorXLow.Byte,0);
    WRITE_REGISTER_UCHAR(&Bt484->CursorXHigh.Byte,0);
    WRITE_REGISTER_UCHAR(&Bt484->CursorYLow.Byte,0);
    WRITE_REGISTER_UCHAR(&Bt484->CursorYHigh.Byte,0);

    //
    //  Initialize pixel mask.
    //

    WRITE_REGISTER_UCHAR(&Bt484->PixelMask.Byte,0xFF);

    //
    //  Init Jaguar Registers
    //

    WRITE_REGISTER_USHORT(&Jaguar->TopOfScreen.Short,
        JagInitData.TopOfScreen);

    WRITE_REGISTER_USHORT(&Jaguar->HorizontalBlank.Short,
        JagInitData.HorizontalBlank);

    WRITE_REGISTER_USHORT(&Jaguar->HorizontalBeginSync.Short,
        JagInitData.HorizontalBeginSync);

    WRITE_REGISTER_USHORT(&Jaguar->HorizontalEndSync.Short,
        JagInitData.HorizontalEndSync);

    WRITE_REGISTER_USHORT(&Jaguar->HorizontalLine.Short,
        JagInitData.HorizontalLine);

    WRITE_REGISTER_USHORT(&Jaguar->VerticalBlank.Short,
        JagInitData.VerticalBlank);

    WRITE_REGISTER_USHORT(&Jaguar->VerticalBeginSync.Short,
        JagInitData.VerticalBeginSync);

    WRITE_REGISTER_USHORT(&Jaguar->VerticalEndSync.Short,
        JagInitData.VerticalEndSync);

    WRITE_REGISTER_USHORT(&Jaguar->VerticalLine.Short,
        JagInitData.VerticalLine);

    WRITE_REGISTER_USHORT(&Jaguar->XferLength.Short,
        JagInitData.XferLength);

    WRITE_REGISTER_USHORT(&Jaguar->VerticalInterruptLine.Short,
        JagInitData.VerticalInterruptLine);

    WRITE_REGISTER_USHORT(&Jaguar->HorizontalDisplay.Short,
        JagInitData.HorizontalDisplay);

    WRITE_REGISTER_UCHAR(&Jaguar->BitBltControl.Byte,
        JagInitData.BitBltControl);

    //
    // Enable timing.
    //

    WRITE_REGISTER_UCHAR(&Jaguar->MonitorControl,MONITOR_TIMING_ENABLE);

    return ESUCCESS;

}

#endif
