root/drivers/video/fbdev/kyro/STG4000VTG.c
/*
 *  linux/drivers/video/kyro/STG4000VTG.c
 *
 *  Copyright (C) 2002 STMicroelectronics
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 */

#include <linux/types.h>
#include <video/kyro.h>

#include "STG4000Reg.h"
#include "STG4000Interface.h"

void DisableVGA(volatile STG4000REG __iomem *pSTGReg)
{
        u32 tmp;
        volatile u32 count = 0, i;

        /* Reset the VGA registers */
        tmp = STG_READ_REG(SoftwareReset);
        CLEAR_BIT(8);
        STG_WRITE_REG(SoftwareReset, tmp);

        /* Just for Delay */
        for (i = 0; i < 1000; i++) {
                count++;
        }

        /* Pull-out the VGA registers from reset */
        tmp = STG_READ_REG(SoftwareReset);
        tmp |= SET_BIT(8);
        STG_WRITE_REG(SoftwareReset, tmp);
}

void StopVTG(volatile STG4000REG __iomem *pSTGReg)
{
        u32 tmp = 0;

        /* Stop Ver and Hor Sync Generator */
        tmp = (STG_READ_REG(DACSyncCtrl)) | SET_BIT(0) | SET_BIT(2);
        CLEAR_BIT(31);
        STG_WRITE_REG(DACSyncCtrl, tmp);
}

void StartVTG(volatile STG4000REG __iomem *pSTGReg)
{
        u32 tmp = 0;

        /* Start Ver and Hor Sync Generator */
        tmp = ((STG_READ_REG(DACSyncCtrl)) | SET_BIT(31));
        CLEAR_BIT(0);
        CLEAR_BIT(2);
        STG_WRITE_REG(DACSyncCtrl, tmp);
}

void SetupVTG(volatile STG4000REG __iomem *pSTGReg,
              const struct kyrofb_info * pTiming)
{
        u32 tmp = 0;
        u32 margins = 0;
        u32 ulBorder;
        u32 xRes = pTiming->XRES;
        u32 yRes = pTiming->YRES;

        /* Horizontal */
        u32 HAddrTime, HRightBorder, HLeftBorder;
        u32 HBackPorcStrt, HFrontPorchStrt, HTotal,
            HLeftBorderStrt, HRightBorderStrt, HDisplayStrt;

        /* Vertical */
        u32 VDisplayStrt, VBottomBorder, VTopBorder;
        u32 VBackPorchStrt, VTotal, VTopBorderStrt,
            VFrontPorchStrt, VBottomBorderStrt, VAddrTime;

        /* Need to calculate the right border */
        if ((xRes == 640) && (yRes == 480)) {
                if ((pTiming->VFREQ == 60) || (pTiming->VFREQ == 72)) {
                        margins = 8;
                }
        }

        /* Work out the Border */
        ulBorder =
            (pTiming->HTot -
             (pTiming->HST + (pTiming->HBP - margins) + xRes +
              (pTiming->HFP - margins))) >> 1;

        /* Border the same for Vertical and Horizontal */
        VBottomBorder = HLeftBorder = VTopBorder = HRightBorder = ulBorder;

    /************ Get Timing values for Horizontal ******************/
        HAddrTime = xRes;
        HBackPorcStrt = pTiming->HST;
        HTotal = pTiming->HTot;
        HDisplayStrt =
            pTiming->HST + (pTiming->HBP - margins) + HLeftBorder;
        HLeftBorderStrt = HDisplayStrt - HLeftBorder;
        HFrontPorchStrt =
            pTiming->HST + (pTiming->HBP - margins) + HLeftBorder +
            HAddrTime + HRightBorder;
        HRightBorderStrt = HFrontPorchStrt - HRightBorder;

    /************ Get Timing values for Vertical ******************/
        VAddrTime = yRes;
        VBackPorchStrt = pTiming->VST;
        VTotal = pTiming->VTot;
        VDisplayStrt =
            pTiming->VST + (pTiming->VBP - margins) + VTopBorder;
        VTopBorderStrt = VDisplayStrt - VTopBorder;
        VFrontPorchStrt =
            pTiming->VST + (pTiming->VBP - margins) + VTopBorder +
            VAddrTime + VBottomBorder;
        VBottomBorderStrt = VFrontPorchStrt - VBottomBorder;

        /* Set Hor Timing 1, 2, 3 */
        tmp = STG_READ_REG(DACHorTim1);
        CLEAR_BITS_FRM_TO(0, 11);
        CLEAR_BITS_FRM_TO(16, 27);
        tmp |= (HTotal) | (HBackPorcStrt << 16);
        STG_WRITE_REG(DACHorTim1, tmp);

        tmp = STG_READ_REG(DACHorTim2);
        CLEAR_BITS_FRM_TO(0, 11);
        CLEAR_BITS_FRM_TO(16, 27);
        tmp |= (HDisplayStrt << 16) | HLeftBorderStrt;
        STG_WRITE_REG(DACHorTim2, tmp);

        tmp = STG_READ_REG(DACHorTim3);
        CLEAR_BITS_FRM_TO(0, 11);
        CLEAR_BITS_FRM_TO(16, 27);
        tmp |= (HFrontPorchStrt << 16) | HRightBorderStrt;
        STG_WRITE_REG(DACHorTim3, tmp);

        /* Set Ver Timing 1, 2, 3 */
        tmp = STG_READ_REG(DACVerTim1);
        CLEAR_BITS_FRM_TO(0, 11);
        CLEAR_BITS_FRM_TO(16, 27);
        tmp |= (VBackPorchStrt << 16) | (VTotal);
        STG_WRITE_REG(DACVerTim1, tmp);

        tmp = STG_READ_REG(DACVerTim2);
        CLEAR_BITS_FRM_TO(0, 11);
        CLEAR_BITS_FRM_TO(16, 27);
        tmp |= (VDisplayStrt << 16) | VTopBorderStrt;
        STG_WRITE_REG(DACVerTim2, tmp);

        tmp = STG_READ_REG(DACVerTim3);
        CLEAR_BITS_FRM_TO(0, 11);
        CLEAR_BITS_FRM_TO(16, 27);
        tmp |= (VFrontPorchStrt << 16) | VBottomBorderStrt;
        STG_WRITE_REG(DACVerTim3, tmp);

        /* Set Verical and Horizontal Polarity */
        tmp = STG_READ_REG(DACSyncCtrl) | SET_BIT(3) | SET_BIT(1);

        if ((pTiming->HSP > 0) && (pTiming->VSP < 0)) { /* +hsync -vsync */
                tmp &= ~0x8;
        } else if ((pTiming->HSP < 0) && (pTiming->VSP > 0)) {  /* -hsync +vsync */
                tmp &= ~0x2;
        } else if ((pTiming->HSP < 0) && (pTiming->VSP < 0)) {  /* -hsync -vsync */
                tmp &= ~0xA;
        } else if ((pTiming->HSP > 0) && (pTiming->VSP > 0)) {  /* +hsync -vsync */
                tmp &= ~0x0;
        }

        STG_WRITE_REG(DACSyncCtrl, tmp);
}