/****************************************************************************
 * GETINFO.C - ATI DFP mode setting sample code                             *
 *                                                                          *
 *                                                                          *
 * Copyright (c) 1999 ATI Technologies Inc.  All rights reserved.           *
 ****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <i86.h>
#include <dos.h>
#include "..\util\main.h"
#include "..\util\regdef.h"
#include "..\util\defines.h"

extern FILE *op;
#define PANEL_YRES 768
//#define HARDCODE_PANEL 1
/****************************************************************************
 * SetPanelMode (WORD xres, WORD yres, WORD bpp)                            *
 *  Function: Sets a display mode on the LCD                                *
 *    Inputs: WORD xres - X resolution for requested display mode           *
 *            WORD yres - Y resolution for requested display mode           *
 *            WORD bpp - bits per pixel for requested display mode          *
 *   Outputs: BYTE - 1 on success, 0 on failure                             *
 ****************************************************************************/
BYTE SetPanelMode (WORD xres, WORD yres, WORD bpp)
{
    WORD total;
    float Hratio, Vratio;
    DWORD ratio, temp, bppvalue;
    DWORD crtc[4];
    WORD end, loop;
    BYTE h_sync_dly[] = { 0, 0, 2, 1, 1, 6, 5 };

    // check the passed parameter values.  Make sure the X res is not
    // greater than the native panel X resolution.  If it is, we'll set it
    // to the native panel resolution
    GetPanelValues ();
    if (xres > P.xres)
    {
        xres = P.xres;
        yres = P.yres;
        R128_AdapterInfo.xres = xres;
        R128_AdapterInfo.yres = yres;
        R128_AdapterInfo.pitch = xres;
    }

    // Now, make sure we have enough display memory to set the display mode.
    total = (bpp + 1)/8;
    temp = xres * yres * total;

    if (temp > R128_AdapterInfo.memsize)
    {
        return 0;
    }

    // Set the CRTC to primary, and make the registers writeable
    temp = regr (FP_GEN_CNTL);
    temp &= 0xFECBDFFF; // clear bits 31 and 30
    temp |= 0x00010004; //enable TMDS
    regw (FP_GEN_CNTL, temp);

    // Calculate stretching ratios
    Hratio = (float)xres / (float)P.xres;
    Vratio = (float)yres / (float)P.yres;

    // Program Horizontal/Vertical ratios
    temp = regr(FP_HORZ_STRETCH);
    temp &= ~0x0000FFFF;
    ratio = (DWORD)(Hratio * 4096.0);
    temp |= (ratio & 0x0000FFFF); 
    regw (FP_HORZ_STRETCH, temp);

    temp = regr(FP_VERT_STRETCH);
    temp &= ~0x001FF800;
    ratio = (DWORD)(Vratio * 1024.0);
    temp |= ((ratio & 0x000003FF) << 11);
    regw (FP_VERT_STRETCH, temp);

    // Set CRTC_GEN_CNTL
    temp = regr (CRTC_GEN_CNTL);
    temp &= 0xF8E0F8EC; // preserve reserved bits

    bppvalue = R128_GetBPPValue (bpp);

    // set extended display mode, crtc enbl,
    // cursor disabled, pixel width=depth,
    // no composite sync
    temp |= (3 << 24) | (bppvalue << 8);

    regw (CRTC_GEN_CNTL, temp); // set CRTC_GEN_CNTL reg

    // Program CRTC_OFF_PITCH
    regw (CRTC_PITCH, (xres/8));

    // Compute the new CRTC H values
    end = xres/8 - 1;
    total = end + P.H_nonvisible;
    crtc[0] = (end << 16) | total;
    regw (CRTC_H_TOTAL_DISP, (end << 16) | (total));

    temp = regr (CRTC_H_SYNC_STRT_WID);
    temp &= 0xFFC0F000;
    temp |= ((end + P.H_overplus)<<3) | (h_sync_dly[bppvalue]);
    temp |= (P.H_syncwidth << 16) | (1 << 23);
    crtc[1] = temp;
    regw (CRTC_H_SYNC_STRT_WID, temp);

    // Compute the new CRTC V values
    end = yres - 1;
    total = end + P.V_nonvisible;
    crtc[2] = (end << 16) | total;
    regw (CRTC_V_TOTAL_DISP, (end << 16) | (total));

    temp = regr (CRTC_V_SYNC_STRT_WID);
    temp &= 0xFFE0F800;
    temp |= (end + P.V_overplus);
    temp |= (P.V_syncwidth << 16) | (1 << 23);
    crtc[3] = temp;
    regw (CRTC_V_SYNC_STRT_WID, temp);

    fprintf(op, "\n\n");
    fprintf(op, "Hratio: 0x%f\n", Hratio);
    fprintf(op, "Vratio: 0x%f\n", Vratio);
    // Program HORZ_STRETCH_MODE and HORZ_STRETCH_EN to 1
    if (Hratio != 1.0)
    {
        temp = regr (FP_HORZ_STRETCH);
        temp |= 0x06000000;
        regw (FP_HORZ_STRETCH, temp);
    }
    else
    {
        // Since Hratio = 1.0, we are setting the native mode.
        // No stretching should be enabled.
        temp = regr (FP_HORZ_STRETCH);
        temp &= ~0x06000000;
        regw (FP_HORZ_STRETCH, temp);
    }

    // Program USE_RATIO0, VERT_STRETCH_MODE and VERT_STRETCH_EN to 1
    temp = regr (FP_VERT_STRETCH);
    if (Vratio != 1.0)
    {
        temp |= 0x01000000;
    }
    else
    {
        temp &= ~0x01000000;
    }
	temp &= ~0x04000000; //disable auto calculation
	temp |= 0x02000000; //send mode to blending
    regw (FP_VERT_STRETCH, temp);

    R128_AdapterInfo.xres = xres;
    R128_AdapterInfo.yres = yres;
    R128_AdapterInfo.bpp = bpp;

    // Set the bytes per pixel and pitch value
    R128_AdapterInfo.bytepp = (R128_AdapterInfo.bpp+1)/8;
    if (R128_AdapterInfo.bpp == 24)
    {
        R128_AdapterInfo.pitch = R128_AdapterInfo.xres * 3;
    }
    else
    {
        R128_AdapterInfo.pitch = R128_AdapterInfo.xres;
    }

    if (R128_AdapterInfo.bpp == 8)
    {
        R128_InitPalette ();
    }
    else
    {
        R128_InitGamma ();
    }
    return 1;

} // SetPanelMode ()...

/****************************************************************************
 * GetPanelValues (void)                                                    *
 *  Function: Gets information about the currently enabled LCD, and fills   *
 *            in the global panelinf structure P.                           *
 *    Inputs: NONE                                                          *
 *   Outputs: NONE                                                          *
 ****************************************************************************/
void GetPanelValues (void)
{
    DWORD r, bppvalue;
    WORD a, b;
    BYTE adj[] = { 0, 0, 2, 1, 1, 0, 0 };

    // Determine the native values for the installed panel.
    // We assume that the BIOS has already initialized the display (at POST)
    // Thus, we simply snoop the registers to determine native panel settings

    // Determine the panel's native size by inspecting EXT_VERT_STRETCH
    r = regr (FP_VERT_STRETCH);
    r &= 0x000007FF;
    P.yres = (WORD)r + 1;

#ifdef HARDCODE_PANEL
    P.yres = PANEL_YRES;
    regw (FP_VERT_STRETCH, (PANEL_YRES-1));
#endif

    switch (P.yres)
    {
        case 480:   P.xres = 640;
                    break;
        case 600:   P.xres = 800;
                    break;
        case 768:   P.xres = 1024;
                    break;
        case 1024:  P.xres = 1280;
                    break;
        case 1200:  P.xres = 1600;
                    break;
        default:    P.xres = 0;
                    break;
    } // switch

    if (P.xres == 0)
    {
        R128_ShutDown ();
        printf ("\nCannot determine native panel resolution!");
        exit (1);
    }

    bppvalue = R128_GetBPPValue (R128_AdapterInfo.bpp);

    // Now determine the H_nonvisible and H_overplus values
    r = regr (CRTC_H_TOTAL_DISP);
    a = (r & 0x1FF) + 4;  // add adjustment because we are in a VGA mode
    b = (r & 0x01FF0000) >> 16;
    P.H_nonvisible = a - b;

    r = regr (CRTC_H_SYNC_STRT_WID);
    P.H_overplus = (WORD)((r & 0x00000FF8) >> 3) - b + adj[bppvalue];
    P.H_syncwidth = (WORD)((r & 0x3F0000) >> 16) + 14;

    // Now do the same for vertical values
    r = regr (CRTC_V_TOTAL_DISP);
    a = (r & 0x7FF) + 1;  // add 1 because we are in VGA mode
    b = (r & 0x07FF0000) >> 16;
    P.V_nonvisible = a - b;
    r = regr (CRTC_V_SYNC_STRT_WID);
    P.V_overplus = (WORD)(r & 0x7FF) - b - 1;
    P.V_syncwidth = (WORD)((r & 0x1F0000) >> 16) - 2;

} // GetPanelValues ()...


void PrintPanelRegs(void)
{
        fprintf(op, "\n\n");
	fprintf(op, "FP_CRTC_H_TOTAL_DISP: 0x%X\n",regr(FP_CRTC_H_TOTAL_DISP));
	fprintf(op, "FP_CRTC_V_TOTAL_DISP: 0x%X\n",regr(FP_CRTC_V_TOTAL_DISP));
	fprintf(op, "FP_GEN_CNTL         : 0x%X\n",regr(FP_GEN_CNTL));
	fprintf(op, "FP_PANEL_CNTL       : 0x%X\n",regr(FP_PANEL_CNTL));
	fprintf(op, "FP_HORZ_STRETCH     : 0x%X\n",regr(FP_HORZ_STRETCH));
	fprintf(op, "FP_VERT_STRETCH     : 0x%X\n",regr(FP_VERT_STRETCH));
	fprintf(op, "TMDS_CRC            : 0x%X\n",regr(TMDS_CRC));
	fprintf(op, "FP_H_SYNC_STRT_WID  : 0x%X\n",regr(FP_H_SYNC_STRT_WID));
	fprintf(op, "FP_V_SYNC_STRT_WID  : 0x%X\n",regr(FP_V_SYNC_STRT_WID));
}
