/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nsc/panel/cen9211.c,v 1.1tsi Exp $ */
/*
 * $Workfile: cen9211.c $
 *
 * File Contents: 	This file contains panel functions to interface with
 *                  the centaraus platform.
 *
 * SubModule:       Geode FlatPanel library
 *
 */

/* 
 * NSC_LIC_ALTERNATIVE_PREAMBLE
 *
 * Revision 1.0
 *
 * National Semiconductor Alternative GPL-BSD License
 *
 * National Semiconductor Corporation licenses this software 
 * ("Software"):
 *
 *     Geode graphics driver for panel support
 * under one of the two following licenses, depending on how the 
 * Software is received by the Licensee.
 * 
 * If this Software is received as part of the Linux Framebuffer or
 * other GPL licensed software, then the GPL license designated 
 * NSC_LIC_GPL applies to this Software; in all other circumstances 
 * then the BSD-style license designated NSC_LIC_BSD shall apply.
 *
 * END_NSC_LIC_ALTERNATIVE_PREAMBLE */

/* NSC_LIC_BSD
 *
 * National Semiconductor Corporation Open Source License for Durango
 *
 * (BSD License with Export Notice)
 *
 * Copyright (c) 1999-2001
 * National Semiconductor Corporation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 *
 *   * Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer. 
 *
 *   * Redistributions in binary form must reproduce the above 
 *     copyright notice, this list of conditions and the following 
 *     disclaimer in the documentation and/or other materials provided 
 *     with the distribution. 
 *
 *   * Neither the name of the National Semiconductor Corporation nor 
 *     the names of its contributors may be used to endorse or promote 
 *     products derived from this software without specific prior 
 *     written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY 
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE,
 * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF 
 * YOUR JURISDICTION. It is licensee's responsibility to comply with 
 * any export regulations applicable in licensee's jurisdiction. Under 
 * CURRENT (2001) U.S. export regulations this software 
 * is eligible for export from the U.S. and can be downloaded by or 
 * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed 
 * destinations which include Cuba, Iraq, Libya, North Korea, Iran, 
 * Syria, Sudan, Afghanistan and any other country to which the U.S. 
 * has embargoed goods and services. 
 *
 * END_NSC_LIC_BSD */

/* NSC_LIC_GPL
 *
 * National Semiconductor Corporation Gnu General Public License for Durango
 *
 * (GPL License with Export Notice)
 *
 * Copyright (c) 1999-2001
 * National Semiconductor Corporation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted 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  
 *
 * In addition to the terms of the GNU General Public License, neither 
 * the name of the National Semiconductor Corporation nor the names of 
 * its contributors may be used to endorse or promote products derived 
 * from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 * NATIONAL SEMICONDUCTOR CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY 
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE, 
 * INTELLECTUAL PROPERTY INFRINGEMENT, OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE. See the GNU General Public License for more details. 
 *
 * EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF 
 * YOUR JURISDICTION. It is licensee's responsibility to comply with 
 * any export regulations applicable in licensee's jurisdiction. Under 
 * CURRENT (2001) U.S. export regulations this software 
 * is eligible for export from the U.S. and can be downloaded by or 
 * otherwise exported or reexported worldwide EXCEPT to U.S. embargoed 
 * destinations which include Cuba, Iraq, Libya, North Korea, Iran, 
 * Syria, Sudan, Afghanistan and any other country to which the U.S. 
 * has embargoed goods and services. 
 *
 * You should have received a copy of the GNU General Public License 
 * along with this file; if not, write to the Free Software Foundation, 
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 *
 * END_NSC_LIC_GPL */

#include "cen9211.h"

static unsigned char sioc2_orig_val;
static unsigned char must_restore_97317 = FALSE;

/********************************************************************
 *
 * PASS_FAIL init_GPIO(void);
 * Initializes the GPIO pins in the Cx5530 or the National PC97317 
 * for use with a 9211 on a Marmot or Centaurus board. Uses 
 * the global variables RdPCIVal and sioc2_orig_val.
 *
 *********************************************************************/

unsigned char
init_Centaurus_GPIO(void)
{
   unsigned char reg_val;
   static unsigned char first_time = TRUE;

   /* The Centaurus board uses ports 1 and 2 of the 97317 for GPIO. 
    * These ports require bank 0 to be active. The first thing we will
    * do is verify that bank 0 is active and set it if it is not.
    */

   /* set the index for access to the configuration register */
   gfx_outb(CENT_CONFIG_INDEX, CENT_SIOC2);
   reg_val = gfx_inb(CENT_CONFIG_DATA);

   /* set to bank 0 */
   if (reg_val & CENT_GPIO_BANK_SELECT) {
      gfx_outb(CENT_CONFIG_DATA,
	       (unsigned char)(reg_val & ~CENT_GPIO_BANK_SELECT));
   }

   /* If this is the first time we have modified sioc2, we must 
    * save the current value (set by the BIOS) for restoration by 
    * the calling program, set the global flag must_restore_97317, and set 
    * first_time to FALSE. 
    */

   if (first_time == TRUE) {
      sioc2_orig_val = reg_val;
      must_restore_97317 = TRUE;
      first_time = FALSE;
   }

   /* set port 1 direction */
   reg_val = gfx_inb(CENT_PORT1_DIRECTION);

   /* make GPIO 14 and 17 outputs  */
   reg_val |= CENT_97317_CLOCK_MASK | CENT_97317_DATA_OUT_MASK;
   gfx_outb(CENT_PORT1_DIRECTION, reg_val);

   /* set port 2 direction */
   reg_val = gfx_inb(CENT_PORT2_DIRECTION);

   /* make GPIO 20 an output */

   reg_val |= CENT_97317_CHIP_SEL_MASK;

   /* make GPIO 21 an input */

   reg_val &= ~CENT_97317_DATA_IN_MASK;
   gfx_outb(CENT_PORT2_DIRECTION, reg_val);

   /* make GPIO 14 and 17 push-pull */

   reg_val = gfx_inb(CENT_PORT1_OUTPUT_TYPE);
   reg_val |= CENT_97317_CLOCK_MASK | CENT_97317_DATA_OUT_MASK;
   gfx_outb(CENT_PORT1_OUTPUT_TYPE, reg_val);

   /* make GPIO 20 and 21 push-pull */
   reg_val = gfx_inb(CENT_PORT2_OUTPUT_TYPE);
   reg_val |= CENT_97317_CHIP_SEL_MASK | CENT_97317_DATA_IN_MASK;
   gfx_outb(CENT_PORT2_OUTPUT_TYPE, reg_val);
   return CENT_PASS;

}					/* end init_GPIO() */

/*********************************************************************
 *
 * PASS_FAIL init_9211(void);
 * Initializes (sets to 0) the clock, chip select, and data pins
 * of the Cx9211 on a Marmot or Centaurus board.
 *
 **********************************************************************/

unsigned char
init_Centaurus_9211(void)
{
   unsigned char ReadData;

   /* Uses the 97317 for GPIO. 
    * we will use the clock port define for port 1 
    */
   ReadData = gfx_inb(CENT_97317_CLOCK_PORT);
   ReadData &= ~CENT_97317_CLOCK_MASK & ~CENT_97317_DATA_OUT_MASK;
   gfx_outb(CENT_97317_CLOCK_PORT, ReadData);
   /* we will use the chip select port define for port 2 */
   ReadData = gfx_inb(CENT_97317_CHIP_SELECT);
   ReadData &= ~CENT_97317_CHIP_SEL_MASK & ~CENT_97317_DATA_IN_MASK;
   gfx_outb(CENT_97317_CHIP_SELECT, ReadData);
   return (CENT_PASS);

}					/*end init_9211() */

/******************************************************************
 *
 * PASS_FAIL restore_97317_SIOC2(void);
 * Restores the original value to the 97317 SIOC2 register using
 * the global variable sioc2_orig_val. Returns PASS if the value 
 * was written, FAIL if not.
 *
 *******************************************************************/

unsigned char
restore_Centaurus_97317_SIOC2(void)
{
   /* set the global flag */
   if (must_restore_97317 == TRUE) {
      unsigned char cfg;

      /* set the index for access to the configuration register */
      gfx_outb(CENT_CONFIG_INDEX, CENT_SIOC2);

      /* restore the value */
      gfx_outb(CENT_CONFIG_DATA, sioc2_orig_val);

      /* now read and verify */
      cfg = gfx_inb(CENT_CONFIG_DATA);
      if (cfg == sioc2_orig_val)
	 return (CENT_PASS);
      else
	 return (CENT_FAIL);

   }					/* end if() */
   return (CENT_FAIL);

}					/* end restore_97317_SIOC2bank() */

/* -----------------------------------------------------------------------
 *
 * SET_FLAT_PANEL_MODE
 *
 * This routine sets the specified flat panel moden parameters in 
 * the 9211.
 * Returns PASS if successful, FAIL if the mode parameters could 
 * not be set.
 *
 *------------------------------------------------------------------------*/

unsigned char
set_Centaurus_92xx_mode(Pnl_PanelStat * pstat)
{
   int mode;

   /* LOOP THROUGH THE AVAILABLE MODES TO FIND A MATCH */

   for (mode = 0; mode < NUM_92XX_MODES; mode++) {
      if ((FPModeParams[mode].xres == pstat->XRes) &&
	  (FPModeParams[mode].yres == pstat->YRes) &&
	  (FPModeParams[mode].bpp == pstat->Depth) &&
	  (FPModeParams[mode].panel_type == pstat->Type) &&
	  (FPModeParams[mode].color_type == pstat->MonoColor)) {

	 /* SET THE 92xx FOR THE SELECTED MODE */
	 set_Centaurus_92xx_mode_params(mode);
	 return (CENT_PASS);
      }					/* end if() */
   }					/* end for() */
   return (CENT_FAIL);

}					/* end set_Centaurus_92xx_mode() */

/*-------------------------------------------------------------------
 *
 * SET_92XX_MODE_PARAMS
 * This routine sets the 9211 mode parameters.  
 *
 *-------------------------------------------------------------------*/

void
set_Centaurus_92xx_mode_params(int mode)
{
   CS92xx_MODE *pMode = &FPModeParams[mode];
   unsigned long off_data = 0;

   /* Turn the 92xx power off before setting any new parameters. 
    * Since we are going to reset all the power bit positions, we will
    * force the power register to 0. 
    */

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_PWR_MAN, off_data);

   /* set 9211 registers using the desired panel settings */

   Centaurus_write_gpio(FOUR_BYTES,
			CS92xx_LCD_PAN_TIMING1, pMode->panel_timing1);

   Centaurus_write_gpio(FOUR_BYTES,
			CS92xx_LCD_PAN_TIMING2, pMode->panel_timing2);

   if (Pnl_Rev_ID == PNL_9211_C) {

      /* load the LSFR seeds */
      Centaurus_write_gpio(FOUR_BYTES,
			   CS92xx_LCD_DITH_FR_CNTRL, pMode->rev_C_dither_frc);

      Centaurus_write_gpio(FOUR_BYTES,
			   CS92xx_BLUE_LSFR_SEED, pMode->blue_lsfr_seed);

      Centaurus_write_gpio(FOUR_BYTES,
			   CS92xx_RED_GREEN_LSFR_SEED,
			   pMode->red_green_lsfr_seed);
   } else {

      Centaurus_write_gpio(FOUR_BYTES,
			   CS92xx_LCD_DITH_FR_CNTRL, pMode->pre_C_dither_frc);

      Centaurus_write_gpio(FOUR_BYTES,
			   CS92xx_LCD_BLOCK_SEL1, pMode->block_select1);

      Centaurus_write_gpio(FOUR_BYTES,
			   CS92xx_LCD_BLOCK_SEL2, pMode->block_select2);

      Centaurus_write_gpio(FOUR_BYTES,
			   CS92xx_LCD_DISPER1, pMode->dispersion1);

      Centaurus_write_gpio(FOUR_BYTES,
			   CS92xx_LCD_DISPER2, pMode->dispersion2);

      CentaurusProgramFRMload();
   }

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_MEM_CNTRL,
			pMode->memory_control);

   /* Set the power register last. This will turn the panel on at the 9211. */

   Centaurus_write_gpio(FOUR_BYTES,
			CS92xx_LCD_PWR_MAN, pMode->power_management);

}					/* end set_Centaurus_92xx_mode_params() */

void
Centaurus_write_gpio(int width, ULONG address, unsigned long data)
{
   int num_clock_toggles;
   int count;
   unsigned long Addr = address;

   enable_Centaurus_9211_chip_select();

   /* Write 1 Clock period of no valid transfer */
   write_Centaurus_CX9211_GPIO(CENT_NO_DATA);

   /* Write 1 control bit (the data book calls this the control bar write) */
   write_Centaurus_CX9211_GPIO(0x1);

   /* Write the 12-bit address */
   for (count = 0; count < 12; count++) {
      write_Centaurus_CX9211_GPIO((unsigned char)(Addr & 0x01));
      /*the 9211 expects data LSB->MSB */
      Addr = Addr >> 1;
   }

   /* write */
   write_Centaurus_CX9211_DWdata(data);

   /* a write will require four toggles after disabling CS */
   num_clock_toggles = CENT_NUM_WRITE_CLOCK_TOGGLES;
   disable_Centaurus_9211_chip_select();

   /* now toggle the clock */
   for (count = 0; count < num_clock_toggles; count++) {
      toggle_Centaurus_9211_clock();
   }
   return;

}					/* end Centaurus_write_gpio() */

unsigned long
Centaurus_read_gpio(int width, unsigned long address)
{
   int num_clock_toggles;
   int count;
   unsigned long Addr = address;
   unsigned long data;

   enable_Centaurus_9211_chip_select();

   /* Write 1 Clock period of no valid transfer */
   write_Centaurus_CX9211_GPIO(CENT_NO_DATA);

   /* Write 1 control bit (the data book calls this the control bar write) */
   write_Centaurus_CX9211_GPIO(0x1);

   /* Write the 12-bit address */
   for (count = 0; count < 12; count++) {
      write_Centaurus_CX9211_GPIO((unsigned char)(Addr & 0x01));

      /*the 9211 expects data LSB->MSB */
      Addr = Addr >> 1;
   }

   data = read_Centaurus_CX9211_DWdata();

   /* a read will require one toggle after disabling CS */
   num_clock_toggles = CENT_NUM_READ_CLOCK_TOGGLES;
   disable_Centaurus_9211_chip_select();

   /* now toggle the clock */
   for (count = 0; count < num_clock_toggles; count++) {
      toggle_Centaurus_9211_clock();
   }
   return data;

}					/* end Centaurus_read_gpio() */

/*******************************************************************
 *
 * void enable_Centaurus_9211_chip_select(void);
 * Enables the chip select of the CX9211 using the National 97317 
 * on a Centaurus board.
 *
 *******************************************************************/

void
enable_Centaurus_9211_chip_select(void)
{
   unsigned char cs_port_val;

   /* Set the chip select (GPIO20) high */
   cs_port_val = gfx_inb(CENT_97317_CHIP_SELECT);
   gfx_outb(CENT_97317_CHIP_SELECT,
	    (unsigned char)(cs_port_val | CENT_97317_CHIP_SEL_MASK));
   return;

}					/* end enable_Centaurus_9211_chip_select() */

/********************************************************************
 *
 * void disable_Centaurus_9211_chip_select(void);
 * Disables the chip select of the CX9211 using the National 97317 
 * on a Centaurus board.
 *
 *******************************************************************/

void
disable_Centaurus_9211_chip_select(void)
{
   unsigned char cs_port_val;

   /* Set the chip select (GPIO20) low */
   cs_port_val = gfx_inb(CENT_97317_CHIP_SELECT);
   gfx_outb(CENT_97317_CHIP_SELECT,
	    (unsigned char)(cs_port_val & ~CENT_97317_CHIP_SEL_MASK));
   return;

}					/* end disable_Centaurus_9211_chip_select() */

/**********************************************************************
 *
 * void toggle_Centaurus_9211_clock(void);
 * Toggles the clock bit of the CX9211 using the National 97317 on a 
 * Centaurus board. Assumes the 9211 clock bit has previously been 
 * initialized to 0 (this way we do not have to waste GPIO cycles 
 * windowing the clock pulse).
 *
 **********************************************************************/

void
toggle_Centaurus_9211_clock(void)
{
   unsigned char port_val;

   /* get the 97317 GPIO port contents for the 9211 clock */

   port_val = gfx_inb(CENT_97317_CLOCK_PORT);
   /* set the clock bit high */
   gfx_outb(CENT_97317_CLOCK_PORT,
	    (unsigned char)(port_val | CENT_97317_CLOCK_MASK));

   /* set the clock bit low */
   gfx_outb(CENT_97317_CLOCK_PORT,
	    (unsigned char)(port_val & ~CENT_97317_CLOCK_MASK));

}					/* end toggle_Centaurus_9211_clock() */

/********************************************************************
 *
 * void write_Centaurus_CX9211_GPIO(unsigned char databit);
 * Writes the value in bit 0 of the value passed in databit to 
 * the 9211 through the GPIO interface of the National 97317 on a 
 * Centaurus board.
 * NOTE: This function does not set or reset the chip select line!
 *
 *******************************************************************/

void
write_Centaurus_CX9211_GPIO(unsigned char databit)
{
   unsigned char data_port_val;

   /* Set the data bit for (GPIO17) */
   databit <<= 7;

   /* read the value of the other bits in the 97317 data port */
   data_port_val = gfx_inb(CENT_97317_DATA_OUTPORT);

   /* set the bit accordingly */
   data_port_val &= ~CENT_97317_DATA_OUT_MASK;
   data_port_val |= databit;
   gfx_outb(CENT_97317_DATA_OUTPORT, data_port_val);

   /* clock the data */
   toggle_Centaurus_9211_clock();
   return;

}					/* end write_Centaurus_CX9211_GPIO() */

/*****************************************************************
 *
 * void write_Centaurus_CX9211_DWdata(unsigned long data);
 * Writes the doubleword value passed in data to the CX9211 
 * using GPIO Pins of the National 97317 on a Centaurus board.
 * This function assumes the Direction register of the 97317 
 * and the address register of the CX9211 have been previously set.
 * Uses the global variable count.
 * NOTE: This function does not set or reset the chip select line!
 *
 ******************************************************************/

void
write_Centaurus_CX9211_DWdata(unsigned long data)
{
   int count;

   /* Send the read/write command to the 9211 first. */

   write_Centaurus_CX9211_GPIO(CENT_WRITE);

   /* Now write the 32-bit Data */
   for (count = 0; count < 32; count++) {
      write_Centaurus_CX9211_GPIO((unsigned char)(data & 0x01));

      /* the 9211 expects the data LSB->MSB */
      data >>= 1;
   }
   return;

}					/* end write_Centaurus_CX9211_DWdata() */

/*********************************************************************
 *
 * unsigned char read_Centaurus_CX9211_GPIO(void);
 * Returns the current value of the databit of the 9211 in bit 0 
 * using the GPIO interface of the National 97317 on a Centaurus board.
 * NOTE: This function does not set or reset the chip select line!
 *
 *********************************************************************/

unsigned char
read_Centaurus_CX9211_GPIO(void)
{
   unsigned char data_port_val;

   toggle_Centaurus_9211_clock();

   /* read the data */
   data_port_val = gfx_inb(CENT_97317_DATA_INPORT);

   /* Save the data from (GPIO21) as bit 0 */
   data_port_val >>= 1;
   return (data_port_val & 0x1);

}					/* end read_Centaurus_CX9211_GPIO() */

/**********************************************************************
 *
 * void read_Centaurus_CX9211_DWdata(unsigned long *data);
 * Reads a doubleword value from the CX9211 using GPIO Pins of 
 * the National 97317 on a Centaurus board.
 * This function assumes the Direction register of the 97317 and 
 * the address register of the CX9211 have been previously set.
 * NOTE: This function does not set or reset the chip select line!
 *
 ***********************************************************************/

unsigned long
read_Centaurus_CX9211_DWdata(void)
{
   unsigned char ReadData;
   int count;
   unsigned long Data;

   /* Send read/write command word to the 9211 first. */
   write_Centaurus_CX9211_GPIO(CENT_READ);

   /* The data book (revision 0.1) states 8 clock periods of no valid data. 
    *   However, the data becomes valid on the eighth clock, making the eighth
    *   clock valid. Since read_Centaurus_GPIO() toggles the clock before 
    *   reading, we will only toggle the clock 7 times here. 
    */
   for (count = 0; count < 7; count++)	/* works */
      toggle_Centaurus_9211_clock();

   /* Now read the 32-bit Data, bit by bit in a single loop. */
   Data = 0;
   for (count = 0; count < 32; count++) {
      ReadData = read_Centaurus_CX9211_GPIO();
      /* 9211 sends data  LSB->MSB */
      Data = Data | (((unsigned long)ReadData) << count);
   }					/* end for() */

   return Data;

}					/* end read_Centaurus_CX9211_DWdata() */

void
Centaurus_Get_9211_Details(unsigned long flags, PPnl_PanelParams pParam)
{
   unsigned long PanelType;
   int i;

   for (i = 0; i < 0x7fff; i++) {
   }

   init_Centaurus_GPIO();

   for (i = 0; i < 5; i++)
      toggle_Centaurus_9211_clock();

   if (flags & PNL_PANELCHIP) {

      PanelType = Centaurus_read_gpio(FOUR_BYTES, 0x430);
      PanelType = Centaurus_read_gpio(FOUR_BYTES, 0x430);
      if ((PanelType & 0xFFFF0000) == 0x92110000) {

	 /* found 9211 */
	 /* check the values for revision ID */
	 if (PanelType >= 0x92110301)
	    pParam->PanelChip = PNL_9211_C;
	 else if ((PanelType >= 0x92110101) && (PanelType < 0x92110301))
	    pParam->PanelChip = PNL_9211_A;
	 else
	    pParam->PanelChip = PNL_UNKNOWN_CHIP;
      } else {				/* no 9211 present */
	 pParam->PanelChip = PNL_UNKNOWN_CHIP;
      }
      Pnl_Rev_ID = pParam->PanelChip;
   }
   /* if end */
   if ((pParam->PanelChip != PNL_UNKNOWN_CHIP) && (flags & PNL_PANELSTAT)) {
      PanelType = Centaurus_read_gpio(FOUR_BYTES, 0x438);
      PanelType &= 0x00f8f8f8;
      PanelType |= 0x00070000;
      Centaurus_write_gpio(FOUR_BYTES, 0x438, PanelType);
      PanelType = 0;
      PanelType = Centaurus_read_gpio(FOUR_BYTES, 0x434);
      PanelType = (PanelType >> 8);
      PanelType &= 0x7;

      switch (PanelType) {
      case 0:
	 pParam->PanelStat.XRes = 800;
	 pParam->PanelStat.YRes = 600;
	 pParam->PanelStat.Depth = 18;
	 pParam->PanelStat.MonoColor = PNL_COLOR_PANEL;
	 pParam->PanelStat.Type = PNL_TFT;
	 break;
      case 1:
	 pParam->PanelStat.XRes = 640;
	 pParam->PanelStat.YRes = 480;
	 pParam->PanelStat.Depth = 8;
	 pParam->PanelStat.MonoColor = PNL_COLOR_PANEL;
	 pParam->PanelStat.Type = PNL_SSTN;
	 break;
      case 2:
	 pParam->PanelStat.XRes = 1024;
	 pParam->PanelStat.YRes = 768;
	 pParam->PanelStat.Depth = 18;
	 pParam->PanelStat.MonoColor = PNL_COLOR_PANEL;
	 pParam->PanelStat.Type = PNL_TFT;
	 break;
      case 3:
	 pParam->PanelStat.XRes = 640;
	 pParam->PanelStat.YRes = 480;
	 pParam->PanelStat.Depth = 16;
	 pParam->PanelStat.MonoColor = PNL_COLOR_PANEL;
	 pParam->PanelStat.Type = PNL_DSTN;
	 break;
      case 4:
	 pParam->PanelStat.XRes = 640;
	 pParam->PanelStat.YRes = 480;
	 pParam->PanelStat.Depth = 18;
	 pParam->PanelStat.MonoColor = PNL_COLOR_PANEL;
	 pParam->PanelStat.Type = PNL_TFT;
	 break;
      case 5:
	 pParam->PanelStat.XRes = 1024;
	 pParam->PanelStat.YRes = 768;
	 pParam->PanelStat.Depth = 24;
	 pParam->PanelStat.MonoColor = PNL_COLOR_PANEL;
	 pParam->PanelStat.Type = PNL_DSTN;
	 break;
      case 6:
	 pParam->PanelStat.XRes = 640;
	 pParam->PanelStat.YRes = 480;
	 pParam->PanelStat.Depth = 8;
	 pParam->PanelStat.MonoColor = PNL_MONO_PANEL;
	 pParam->PanelStat.Type = PNL_DSTN;
	 break;
      case 7:
	 pParam->PanelStat.XRes = 800;
	 pParam->PanelStat.YRes = 600;
	 pParam->PanelStat.Depth = 16;
	 pParam->PanelStat.MonoColor = PNL_COLOR_PANEL;
	 pParam->PanelStat.Type = PNL_DSTN;
	 break;
      default:
	 break;
      }
   }

}

void
CentaurusProgramFRMload(void)
{
   unsigned long CentaurusFRMtable[] = {
      0x00000000,
      0x00000000,
      0x01000100,
      0x01000100,
      0x01010101,
      0x01010101,
      0x02081041,
      0x02081041,
      0x10111111,
      0x11111101,
      0x49249241,
      0x12412492,
      0x92244891,
      0x92244891,
      0x22252525,
      0x22252525,
      0x528294a5,
      0x2528494a,
      0x294a5295,
      0x294a5295,
      0x54a54a95,
      0x2952a52a,
      0x2a552a55,
      0x2a552a55,
      0x554aa955,
      0x2a9552aa,
      0x2aaa5555,
      0x2aaa5555,
      0x55555555,
      0x2aaaaaaa,
      0x55555555,
      0x55555555,
      0xaaaaaaab,
      0x55555555,
      0x5555aaab,
      0x5555aaab,
      0xaab556ab,
      0x556aad55,
      0x55ab55ab,
      0x55ab55ab,
      0xab5ab56b,
      0x56ad5ad5,
      0x56b5ad6b,
      0x56b5ad6b,
      0xad6d6b5b,
      0x5ad6b6b6,
      0x5b5b5b5b,
      0x5b5b5b5b,
      0x5F6db6db,
      0x5F6db6db,
      0xF776F776,
      0xF776F776,
      0xFBDEFBDE,
      0xFBDEFBDE,
      0x7eFFBFF7,
      0x7eFFBFF7,
      0xFF7FF7F7,
      0xFF7FF7F7,
      0xFF7FFF7F,
      0xFF7FFF7F,
      0xFFF7FFFF,
      0xFFF7FFFF,
      0xFFFFFFFF,
      0xFFFFFFFF,
   };

   unsigned char i;
   unsigned long data;

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_FRM_MEMORY_INDEX, 0);
   for (i = 0; i < 64; i += 2) {
      data = CentaurusFRMtable[i];
      Centaurus_write_gpio(FOUR_BYTES, CS92xx_FRM_MEMORY_DATA, data);
      data = CentaurusFRMtable[i + 1];
      Centaurus_write_gpio(FOUR_BYTES, CS92xx_FRM_MEMORY_DATA, data);
   }

   /*
    * The first FRM location (64 bits) does not program correctly.
    * This location always reads back with the last value programmed.
    * ie. If 32 64-bit values are programmed, location 0 reads 
    * back as the 32nd If 30 locations are programmed, location 0 
    * reads back as the 30th, etc.
    * Fix this by re-writing location 0 after programming all 64 in 
    * the writeFRM loop in RevCFrmload() in CS9211.
    */

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_FRM_MEMORY_INDEX, 0);
   Centaurus_write_gpio(FOUR_BYTES, CS92xx_FRM_MEMORY_DATA, 0);
   Centaurus_write_gpio(FOUR_BYTES, CS92xx_FRM_MEMORY_DATA, 0);
}

/********************************************************************
 *
 * void Centaurus_Enable_Power((void);
 * Enables the power of the CX9211 using the National 97317 on 
 * a Centaurus board.
 *
 ********************************************************************/

void
Centaurus_Power_Up(void)
{
   unsigned long off_data = 0x01000000;

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_PWR_MAN, off_data);
   return;

}					/* Centaurus_Disable_Power */

/***********************************************************************
 *
 * void Centaurus_Disable_Power((void);
 * Disables the power of the CX9211 using the National 97317 
 * on a Centaurus board.
 *
 **********************************************************************/

void
Centaurus_Power_Down(void)
{
   unsigned long off_data = 0;

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_PWR_MAN, off_data);
   return;

}					/* Centaurus_Disable_Power */

void
Centaurus_9211init(Pnl_PanelStat * pstat)
{
   init_Centaurus_GPIO();
   init_Centaurus_9211();
   set_Centaurus_92xx_mode(pstat);
   restore_Centaurus_97317_SIOC2();
}

void
Centaurus_Save_Panel_State(void)
{
   /* set 9211 registers using the desired panel settings */

   cs9211_regs.panel_timing1 =
	 Centaurus_read_gpio(FOUR_BYTES, CS92xx_LCD_PAN_TIMING1);
   cs9211_regs.panel_timing2 =
	 Centaurus_read_gpio(FOUR_BYTES, CS92xx_LCD_PAN_TIMING2);
   cs9211_regs.dither_frc_ctrl =
	 Centaurus_read_gpio(FOUR_BYTES, CS92xx_LCD_DITH_FR_CNTRL);
   cs9211_regs.blue_lsfr_seed =
	 Centaurus_read_gpio(FOUR_BYTES, CS92xx_BLUE_LSFR_SEED);

   cs9211_regs.red_green_lsfr_seed =
	 Centaurus_read_gpio(FOUR_BYTES, CS92xx_RED_GREEN_LSFR_SEED);
   /* CentaurusProgramFRMload(); */

   cs9211_regs.memory_control =
	 Centaurus_read_gpio(FOUR_BYTES, CS92xx_LCD_MEM_CNTRL);

   /* Set the power register last. 
    * This will turn the panel on at the 9211.
    */
   cs9211_regs.power_management =
	 Centaurus_read_gpio(FOUR_BYTES, CS92xx_LCD_PWR_MAN);
}

void
Centaurus_Restore_Panel_State(void)
{

   unsigned long off_data = 0;

   /* Before restoring the 9211 registers, power off the 9211. */
   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_PWR_MAN, off_data);

   /* set 9211 registers using the desired panel settings */

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_PAN_TIMING1,
			cs9211_regs.panel_timing1);

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_PAN_TIMING2,
			cs9211_regs.panel_timing2);

   /* load the LSFR seeds */

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_DITH_FR_CNTRL,
			cs9211_regs.dither_frc_ctrl);

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_BLUE_LSFR_SEED,
			cs9211_regs.blue_lsfr_seed);

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_RED_GREEN_LSFR_SEED,
			cs9211_regs.red_green_lsfr_seed);

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_MEM_CNTRL,
			cs9211_regs.memory_control);

   /* Set the power register last. This will turn the panel on at the 9211. */

   Centaurus_write_gpio(FOUR_BYTES, CS92xx_LCD_PWR_MAN,
			cs9211_regs.power_management);

}
