/*  SVGATextMode -- An SVGA textmode manipulation/enhancement tool
 *
 *  Copyright (C) 1995  Koen Gadeyne
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/***
 *** SVGA clockchip programming functions for SVGATextMode
 *** (c) 1995 Koen Gadeyne (kmg@barco.be)
 ***
 ***/

#include <stdio.h>
#include <unistd.h>
#ifndef DOS
#  include <asm/io.h>
#endif
#include "misc.h"
#include "vga_prg.h"
#include "confdefs.h"
#include "std_clock.h"
#include "clockchip.h"
#include "messages.h"  
#include "parse_opt.h"


void set_clockchip_clock(int chipset, int clockchip, long freq, int optmask)   /* "freq" is in Hz ! */
{
  int result=TRUE;
  
  PDEBUG(("Setting clock for chipset #%d through clock chip #%d. Freq = %ld Hz. Optionmask = 0x%x", chipset, clockchip, freq, optmask));
  switch(clockchip)
  {
     case CLKCHIP_ICS9161A:
     case CLKCHIP_DCS2834:   /* is this true ? the XFREE manual says this clock chip exists, but they don't use it. */
     case CLKCHIP_ICD2061A:
                           /* setting exactly 120 MHz doesn't work all the time */
                           if (freq > 119900000) freq = 119900000;
                           AltICD2061SetClock(freq, 2);
                           AltICD2061SetClock(freq, 2);
                           AltICD2061SetClock(freq, 2);
                           s3ClockSelect((optmask & OPT_SPEA_MERCURY) ? 6 : 2, optmask); /* select the clock */
                           break;
    case CLKCHIP_SC11412:
                           result = SC11412SetClock((long)freq/1000);
                           s3ClockSelect((optmask & OPT_SPEA_MERCURY) ? 6 : 2, optmask); /* select the clock */
                           break;
    case CLKCHIP_ICS2595:
                           result = ICS2595SetClock((long)freq/1000);
                           result = ICS2595SetClock((long)freq/1000);
                           break;
    case CLKCHIP_ICS5300:
    case CLKCHIP_S3_SDAC:
    case CLKCHIP_S3GENDAC:
                           (void) S3gendacSetClock((long)freq/1000, 2); /* can't fail */
                           s3ClockSelect(2, optmask); /* select the clock */
                           break;
    case CLKCHIP_S3TRIO:  
                           (void) S3TrioSetClock((long)freq/1000, 2); /* can't fail */
                           break;
    case CLKCHIP_ICS5342:
                           (void) ICS5342SetClock((long)freq/1000, 2); /* can't fail */
                           s3ClockSelect(2, optmask); /* select the clock */
                           break;
    case CLKCHIP_TI3025:
                           if (freq < 20000000) PERROR(("Ti3025SetClock: Min. clock is 20 MHz."));
                           xfree_Ti3025_init(optmask);
                           PDEBUG(("TI3025 Init done"));
                           Ti3025SetClock((long)freq/1000, 2);
                           s3ClockSelect(2, optmask); /* select the clock */
                           break;
    case CLKCHIP_CH8391:
                           if ((freq < 8500000) || (freq > 135000000))
                             PERROR(("Chrontel 8391 Clock chip: clock must be in range from 8.5 to 135 MHz"));
                           (void) Chrontel8391SetClock(freq, 2); /* can't fail */
                           s3ClockSelect(2, optmask); /* select the clock */
                           break;
    case CLKCHIP_ICS5341:
                           (void) ET4000gendacSetClock((long)freq/1000, 2); /* can't fail */
                           SET_CLOCKBITS_0_1(2);
                           Outbit_CRTC(0x34, 1, 0);  /* bit 2 of clock no */
                           Outbit_SEQ(7, 6, 0);      /* disable clock div 2 */
                           Outbit_SEQ(7, 0, 0);      /* disable clock div 4 */
                           break;
    case CLKCHIP_CIRRUS:
                           if ((freq>57900000) && (freq<58100000)) freq = 57900000;  /* bug in cirrus clockchip code */
                           CirrusClockSelect( (float)freq/1000000, optmask);
                           break;

    default: PERROR(("Unknown clock chip #%d.", clockchip));
  }
  if (result == FALSE) PWARNING(("ClockChip: error while programming clock chip"));
  usleep(50000);
}

/*****************************************************************************************************************************/

void set_clockchip_Mclock(int chipset, int clockchip, long freq, int optmask)   /* "freq" is in Hz ! */
{
  int result=TRUE;
  
  PDEBUG(("Setting MClk for chipset #%d through clock chip #%d. Freq = %ld Hz. Optionmask = 0x%x", chipset, clockchip, freq, optmask));
  SYNCRESET_SEQ;
  switch(clockchip)
  {
    case CLKCHIP_S3_SDAC:
    case CLKCHIP_S3GENDAC:
    case CLKCHIP_ICS5300:
                           (void) S3gendacSetClock((long)freq/1000, 10); /* can't fail */
                           break;
    case CLKCHIP_ICS5342:
                           (void) ICS5342SetClock((long)freq/1000, 10); /* can't fail */
                           s3ClockSelect(2, optmask); /* select the clock */
                           break;
    case CLKCHIP_ICS5341:
                           
                           (void) ET4000gendacSetClock((long)freq/1000, 10); /* can't fail */
                           break;

    default:
             ENDRESET_SEQ;
             PERROR(("MClk programming not supported on selected Clock chip"));
  }
  ENDRESET_SEQ;
  if (result == FALSE) PWARNING(("ClockChip: error while programming clock chip"));
  usleep(50000);
}
