/****************************************************************************
 * Rage 128 Chapter 7 sample code                                           *
 *                                                                          *
 * ov1query.c - This module determines the available bandwidth for the      *
 *              overlay/scaler.  The pixel clock, memory specs, pixel       *
 *              depth and display FIFO size all factor into the bandwidth   *
 *              determination.                                              *
 *                                                                          *
 * Copyright (c) 1999 ATI Technologies Inc. All rights reserved.            *
 ****************************************************************************/
#include "overlay.h"

static WORD vclk_ref_freq;
static WORD vclk_div_freq;
static WORD xclk_ref_freq;
static WORD xclk_div_freq;

void GetClockConstants (void)
{
    R128_GetPLLInfo ();
   vclk_ref_freq = PLL_BLOCK.PCLK_ref_freq;
   vclk_div_freq = PLL_BLOCK.PCLK_ref_divider;
   xclk_ref_freq = PLL_BLOCK.XCLK_ref_freq;
   xclk_div_freq = PLL_BLOCK.XCLK_ref_divider;
}

void R128_GetBandwidthInfo (OVERLAY_DESCRIPTOR *OverlayDescriptor)
{
    long MEM_CFG_TYPE;
    long MEM_BUS_WIDTH;
    long MEM_TRP;
    long MEM_TWR;
    long MEM_TRCD;
    long MEM_TRAS;

    long Ext_mem_cntl;
    long CRTC_PIX_WIDTH;
    long RF;
    long M;
    long N;
    long P;

    float XCLK_Mhz;
    float VCLK_Mhz;

    int PPLL_DIV_SEL;

    unsigned BedRockPD[] = { 1, 2, 4, 8, 3, 5, 6, 12};

    GetClockConstants ();

    /* XCLK */
    RF = xclk_ref_freq;  /* ~2950, needed XCLK (38-39) */
    M  = xclk_div_freq;
    N = PLL_regr8 (X_MPLL_REF_FB_DIV); /* get X_MPLL_REF_DIV field */
    N = N * 2;
    P = (PLL_regr8 (XCLK_CNTL) & 0x7) - 1;

    XCLK_Mhz = ( 0.01 * (float) RF * (float) (N) / (float) M / (float) ( BedRockPD[P] ));

    OverlayDescriptor->MemoryClock_XCLK_PeriodInPicoSec = (DWORD)(1000000.0 / XCLK_Mhz);

    MEM_CFG_TYPE = regr (MEM_CNTL) & 0x3;

    MEM_BUS_WIDTH = (regr (MEM_ADDR_CONFIG) & 0x100) >> 8; /*ALPHA {"64 bits","128 bits"} */

    if ((MEM_CFG_TYPE==0) && (MEM_BUS_WIDTH==0))
    {
        /* SDR SGRAM (2:1) */
        OverlayDescriptor->CyclesPerOctword = 2;
    }
    else
    {
        OverlayDescriptor->CyclesPerOctword = 1;
    }

    /* The MissAllignmentPenalty is a lost cycle when the transfer requested is less that four. (1 octword takes 1 or 2 cycles, 2 octwords take 2 or 3 cycles, 3 octwords take 3 or 4 cycles) */
    /*TODO_Active: Verify this with Carl. */
    if (MEM_CFG_TYPE==1)
    {
        /* SDR SGRAM (2:1) */
        OverlayDescriptor->MissAllignmentPenalty = (DWORD) 0;
    }
    else
    {
        OverlayDescriptor->MissAllignmentPenalty = (DWORD) 1;
    }

    Ext_mem_cntl = regr (EXT_MEM_CNTL);

    MEM_TRP  = Ext_mem_cntl & 0x3;
    MEM_TWR  = (Ext_mem_cntl & 0x3000) >> 12;
    MEM_TRCD = (Ext_mem_cntl & 0xc) >> 2;
    MEM_TRAS = (Ext_mem_cntl & 0x70) >> 4;

    OverlayDescriptor->OpenPenalty = MEM_TRCD;
    OverlayDescriptor->WriteClosePenalty = MEM_TRP + MEM_TWR - 1;
    OverlayDescriptor->ReadClosePenalty = MEM_TRP;

    /* This is the worst case time it takes to change from the first bank to the */
    /* next inside a single burst. */
    OverlayDescriptor->BankChangePenalty = 3;

    /* ToDo_Active: We should derive the BankChangePenalty from registers if possible. */
    OverlayDescriptor->RefreshCycleTime = MEM_TRAS + MEM_TRP;
    OverlayDescriptor->MEM_CHECKBOARD = (regr (MEM_ADDR_CONFIG) & 0x30000) >> 16;
    OverlayDescriptor->HTOTAL_InCharactersMinusOne = (DWORD)(regr (CRTC_H_TOTAL_DISP) & 0x1ff);
    OverlayDescriptor->HDISP_InCharactersMinusOne  = (DWORD)((regr (CRTC_H_TOTAL_DISP) & 0xff0000) >> 16);

    CRTC_PIX_WIDTH = (regr (CRTC_GEN_CNTL) & 0x700) >> 8;

    switch (CRTC_PIX_WIDTH)
    {
        case 1: OverlayDescriptor->PrimaryPixelDepthInBytes = 1;
                /* It is actually 0.5, but this value isn't supported */
                break;
        case 2: OverlayDescriptor->PrimaryPixelDepthInBytes = 1;
                break;
        case 3: OverlayDescriptor->PrimaryPixelDepthInBytes = 2;
                break;
        case 4: OverlayDescriptor->PrimaryPixelDepthInBytes = 2;
                break;
        case 5: OverlayDescriptor->PrimaryPixelDepthInBytes = 3;
                break;
        case 6: OverlayDescriptor->PrimaryPixelDepthInBytes = 4;
                break;
    }

    OverlayDescriptor->DisplayFIFOSizeInBytes = (regr (DDA_ON_OFF) & 0xffff) /
                                                (regr (DDA_CONFIG) & 0x3fff) + 4;
    OverlayDescriptor->CRTCInterlaceEnable = (DWORD)((regr (CRTC_GEN_CNTL) & 0x2)>>1);

    /* XCLK */
    PPLL_DIV_SEL = (regr (CLOCK_CNTL_INDEX) & 0x300) >> 8;

    switch (PPLL_DIV_SEL)
    {
        case 0: N = PLL_regr (PPLL_DIV_0) & 0x7ff;
            P = (PLL_regr (PPLL_DIV_0) & 0x70000) >> 16;
            break;
            case 1: N = PLL_regr (PPLL_DIV_1) & 0x7ff;
                P = (PLL_regr (PPLL_DIV_1) & 0x70000) >> 16;
            break;
        case 2: N = PLL_regr (PPLL_DIV_2) & 0x7ff;
            P = (PLL_regr (PPLL_DIV_2) & 0x70000) >> 16;
            break;
        case 3: N = PLL_regr (PPLL_DIV_3) & 0x7ff;
                P = (PLL_regr (PPLL_DIV_3) & 0x70000) >> 16;
                break;
    }

    RF = vclk_ref_freq;
    M  = vclk_div_freq;

    VCLK_Mhz = ( 0.01 * (float) RF * (float) ( N ) / (float) M / (float) ( BedRockPD[P] ));

    /* Note that XTALFreq is in nsec. */
    /* Important Note: The following formula uses the PIX1_P value directly. Real hardware decodes this field to get the actual post divider. Thus, a different formula is needed for the real hardware. */
    OverlayDescriptor->PixelClock_VCLK_PeriodInPicoSec = (DWORD)(1000000 / VCLK_Mhz);
    OverlayDescriptor->ECP_DIV_ValueFromPLLRegs = (DWORD)((PLL_regr (VCLK_ECP_CNTL) & 0x300) >> 8);
    OverlayDescriptor->CAN_GUARANTEE_NO_SUBPICTURE = (DWORD) 1;
    OverlayDescriptor->CAN_GUARANTEE_NO_VIDEO_CAPTURE = (DWORD) 0;
    OverlayDescriptor->CAN_GUARANTEE_ONLY_ONE_VIDEO_CAPTURE = (DWORD) 0;
    OverlayDescriptor->CAN_GUARANTEE_THIS_IS_RAGE128_REV_A = (DWORD) 1;

}

