/****************************************************************************
 * VIPRW.C                                                                  *
 *                                                                          *
 * Purpose: To provide functions to access R128 registers to handle the     *
 *          actual read and write operations.                               *
 *                                                                          *
 * Copyright (C) 1999 ATI Technologies Inc.  All rights reserved.           *
 ****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>
#include <string.h>
#include "main.h"
#include "defines.h"
#include "regdef.h"

/****************************************************************************
 * R128_VIPIdle (void)                                                      *
 *  Function: checks to see if VIP hardware is idle                         *
 *    Inputs: NONE                                                          *
 *   Outputs: BYTE 0 - busy, 1 - idle                                       *
 ****************************************************************************/
BYTE R128_VIPIdle (void)
{
    DWORD TimeOut;

    TimeOut = regr (VIPH_TIMEOUT_STAT);

    if (TimeOut & VIPH_TIMEOUT_STAT__VIPH_REG_STAT) // register port timeout or hung
    {
        regw (VIPH_TIMEOUT_STAT, (TimeOut & 0xFFFFFF00) | VIPH_TIMEOUT_STAT__VIPH_REG_AK);  // write 1
        return (regr (VIPH_CONTROL) & 0x2000) ? VIP_BUSY:VIP_RESET;
    }
    return (regr (VIPH_CONTROL) & 0x2000 ) ? VIP_BUSY:VIP_IDLE;
} // R128_VIPIdle ()...


/****************************************************************************
 * R128_SetupRegistersForVIP (void)                                         *
 *  Function: Initializes appropriate registers to perform VIP functions    *
 *    Inputs: NONE                                                          *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void R128_InitVIP (void)
{
    regw (VIPH_CONTROL, 0x003F0004 );   // slowest, timeout in 16 phases
    regw (VIPH_TIMEOUT_STAT, (regr (VIPH_TIMEOUT_STAT ) & 0xFFFFFF00) | VIPH_TIMEOUT_STAT__VIPH_REGR_DIS );
    regw (VIPH_DV_LAT, 0x444400FF ); // set timeslice
    regw (VIPH_BM_CHUNK, 0x151);
    regw (TEST_DEBUG_CNTL, regr (TEST_DEBUG_CNTL ) & (~TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN) );
    regw (MPP_GP_CONFIG, 0 );
    regw (MPP_TB_CONFIG, 0 );

} // R128_InitVIP ()...

/****************************************************************************
 * VIP_Read (DWORD DeviceNum, BYTE RegorFifo, DWORD address,                *
 *           DWORD ReadSize, DWORD *Data)                                   *
 *  Function: peforms a synchronous read of the VIP port register or FIFO   *
 *    Inputs: DWORD DeviceNum - device number being addressed               *
 *            BYTE RegorFifo - 0 for register access, 1 for FIFO            *
 *            DWORD Address - register address                              *
 *            DWORD ReadSize - data size to read (BYTE, WORD, DWORD)        *
 *            DWORD *Data - pointer to the data that was read               *
 *   Outputs: DWORD - status of transfer                                    *
 ****************************************************************************/
DWORD VIP_Read (DWORD DeviceNum, BYTE RegOrFifo, DWORD Address,
                DWORD ReadSize, DWORD *Data)
{
    DWORD CommandAddr;
    DWORD Temp;
    //enum VIP_READINESS eStatus;
    BYTE Status;

    {
        // Check to make sure we are requesting a valid read size.
        if ((VIP_FLAG_RW_BYTE != ReadSize) &
             (VIP_FLAG_RW_WORD != ReadSize) &
             (VIP_FLAG_RW_DWORD != ReadSize))
        {
            return VIP_ERROR_INVALID_PARAMETER;
        }

        *Data = 0;

        if (RegOrFifo)    // TRUE means FIFO, FALSE means register
        {
            CommandAddr = ( ( DeviceNum & 0x3) << 14 ) |    // device#
                            ( 0x3000 ) |                    // fifo read
                            ( Address );                    // 12-bit address
        }
        else
        {
            CommandAddr = ( ( DeviceNum & 0x3) << 14 ) |    // device#
                            ( 0x2000 ) |                    // register read
                            ( Address );                    // 12-bit address
        }

        regw (VIPH_REG_ADDR, CommandAddr);

        while (VIP_BUSY == (Status = R128_VIPIdle()));

        if (VIP_IDLE != Status)
        {
            return VIP_ERROR_TIMEOUT; //FAIL;
        }

        // disable VIPH_REGR_DIS to enable VIP cycle.
        // The LSB of VIPH_TIMEOUT_STAT are set to 0
        // because 1 would have acknowledged various VIP
        // interrupts unexpectedly
        regw (VIPH_TIMEOUT_STAT, regr (VIPH_TIMEOUT_STAT) & (0xffffff00 & ~VIPH_TIMEOUT_STAT__VIPH_REGR_DIS) );

        // the value returned here is garbage.  The read merely initiates
        // a register cycle
        switch (ReadSize)
        {
        case VIP_FLAG_RW_BYTE:
            Temp = (BYTE)(regr (VIPH_REG_DATA) & 0xff);
            break;
        case VIP_FLAG_RW_WORD:
            Temp = (WORD)(regr (VIPH_REG_DATA) & 0xffff);
            break;
        case VIP_FLAG_RW_DWORD:
            Temp = (DWORD)(regr (VIPH_REG_DATA) & 0xffffffff);
            break;
        }

        while (VIP_BUSY == (Status = R128_VIPIdle()));

        if (VIP_IDLE != Status)
        {
            return VIP_ERROR_TIMEOUT; //FAIL;
        }

        // set VIPH_REGR_DIS so that the read won't take too long.
        regw (VIPH_TIMEOUT_STAT, (regr (VIPH_TIMEOUT_STAT ) & 0xffffff00 ) | VIPH_TIMEOUT_STAT__VIPH_REGR_DIS );

        // the value returned here is real.
        switch (ReadSize)
        {
        case VIP_FLAG_RW_BYTE:
            *Data = (BYTE)(regr (VIPH_REG_DATA) & 0xff);
            break;
        case VIP_FLAG_RW_WORD:
            *Data = (WORD)(regr (VIPH_REG_DATA) & 0xffff);
            break;
        case VIP_FLAG_RW_DWORD:
            *Data = (DWORD)(regr (VIPH_REG_DATA) & 0xffffffff);
            break;
        }

        while (VIP_BUSY == (Status = R128_VIPIdle()));

        if (VIP_IDLE != Status)
        {
            return VIP_ERROR_TIMEOUT; //FAIL;
        }

    }

    if (VIP_IDLE == Status )
    {
        // so that reading VIPH_REG_DATA would not trigger unnecessary vip cycles.
        regw (VIPH_TIMEOUT_STAT, (regr (VIPH_TIMEOUT_STAT) & 0xffffff00 ) | VIPH_TIMEOUT_STAT__VIPH_REGR_DIS);
        return VIP_STATUS_COMPLETE;
    }
    else
    {
        return VIP_ERROR_TIMEOUT;
    }

}

/****************************************************************************
 * VIP_Write (DWORD DeviceNum, BYTE RegorFifo, DWORD address,               *
 *           DWORD ReadSize, DWORD *Data)                                   *
 *  Function: peforms a synchronous read of the VIP port register or FIFO   *
 *    Inputs: DWORD DeviceNum - device number being addressed               *
 *            BYTE RegorFifo - 0 for register access, 1 for FIFO            *
 *            DWORD Address - register address                              *
 *            DWORD WriteSize - data size to write (BYTE, WORD, DWORD)      *
 *            DWORD Data - data that will be written                        *
 *   Outputs: DWORD - status of transfer                                    *
 ****************************************************************************/
DWORD VIP_Write (DWORD DeviceNum, BYTE RegOrFifo, DWORD Address,
                 DWORD WriteSize, DWORD Data)
{
    DWORD CommandAddr;
    BYTE Status;

    {
        // Check to make sure we are requesting a valid read size.
        if ( (VIP_FLAG_RW_BYTE != WriteSize) &
             (VIP_FLAG_RW_WORD != WriteSize) &
             (VIP_FLAG_RW_DWORD != WriteSize))
        {
            return VIP_ERROR_INVALID_PARAMETER;
        }

        if (RegOrFifo)    // TRUE means FIFO, FALSE means register
        {
            CommandAddr = ((DeviceNum & 0x3) << 14 ) |    // device#
                           (0x1000) |                     // fifo write
                           (Address);                   // 12-bit address
        }
        else
        {
            CommandAddr = ((DeviceNum & 0x3) << 14 ) |    // device#
                           (0x0000) |                     // register write
                           (Address);                     // 12-bit address
        }

        regw (VIPH_REG_ADDR, CommandAddr);

        while (VIP_BUSY == (Status = R128_VIPIdle()));

        if (VIP_IDLE != Status)
        {
            return VIP_ERROR_TIMEOUT; //FAIL;
        }

        switch (WriteSize)
        {
            case VIP_FLAG_RW_BYTE:
                regw8 (VIPH_REG_DATA, (BYTE)(Data & 0xff));
                break;
            case VIP_FLAG_RW_WORD:
                regw16 (VIPH_REG_DATA, (WORD)(Data & 0xffff));
                break;
            case VIP_FLAG_RW_DWORD:
                regw (VIPH_REG_DATA, (DWORD)Data);
                break;
        }

        while (VIP_BUSY == (Status = R128_VIPIdle()));

        if (VIP_IDLE != Status)
        {
            return VIP_ERROR_TIMEOUT;//FAIL;
        }
    }

    if (VIP_IDLE == Status)
    {
        return VIP_STATUS_COMPLETE;
    }
    else
    {
        return VIP_ERROR_TIMEOUT;
    }

} // VIP_Write ()...


/****************************************************************************
 * RT_regr (DWORD register, DWORD *data)                                    *
 *  Function: reads a register from the Rage Theater                        *
 *    Inputs: DWORD register = register to be read                          *
 *            DWORD *data = pointer to the data that was read               *
 *   Outputs: DWORD FALSE - register read failed.                           *
 *                  TRUE - register read completed.                         *
 ****************************************************************************/
DWORD RT_regr (DWORD reg, DWORD *data)
{
    if (VIP_Read (RT_DEVICE_NUM, REGACCESS, reg, VIP_FLAG_RW_DWORD, data) != VIP_STATUS_COMPLETE)
    {
        return (FALSE);
    }
    return (TRUE);
} // RT_regr ()...

/****************************************************************************
 * RT_regw (DWORD register, DWORD data)                                     *
 *  Function: reads a register from the Rage Theater                        *
 *    Inputs: DWORD register = register to be read                          *
 *            DWORD data = data that will be written to the register        *
 *   Outputs: DWORD FALSE - register write failed.                          *
 *                  TRUE - register write completed.                        *
 ****************************************************************************/
DWORD RT_regw (DWORD reg, DWORD data)
{
    if (VIP_Write (RT_DEVICE_NUM, REGACCESS, reg, VIP_FLAG_RW_DWORD, data) != VIP_STATUS_COMPLETE)
    {
        return (FALSE);
    }
    return (TRUE);
} // RT_regw ()...


/****************************************************************************
 * RT_GetVIPAddress (void)                                                  *
 *  Function: determines the device number of the installed Rage Theater    *
 *    Inputs: NONE                                                          *
 *   Outputs: int - VIP device number of the Rage Theater                   *
 ****************************************************************************/
int RT_GetVIPAddress (void)
{
    DWORD val, ret = 1 , i;
    int card = -1;

    for (i=0; i < 4; i++)
    {
        val = 0;
        ret = VIP_Read (i, REGACCESS, VIP_VIP_VENDOR_DEVICE_ID, VIP_FLAG_RW_DWORD, &val);
        if((ret == VIP_STATUS_COMPLETE) && (val == RT_ATI_ID))
        {
            card = i;
        }
    }
    return card;

}

