/*
 * (C) Copyright 2001
 * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * 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., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 *
 * TODO: clean-up
 */

#include <ppcboot.h>
#include "pip405.h"
#include <asm/processor.h>
#include <405gp_i2c.h>
#include "pip405_isa.h"
#include "video.h"


extern block_dev_desc_t * scsi_get_dev(int dev);
extern block_dev_desc_t * ide_get_dev(int dev);

#undef SDRAM_DEBUG

#define FALSE           0
#define TRUE            1

/* stdlib.h causes some compatibility problems; should fixe these! -- wd */
#ifndef __ldiv_t_defined
typedef struct {
	long int quot;		/* Quotient	*/
	long int rem;		/* Remainder	*/
} ldiv_t;
extern ldiv_t ldiv (long int __numer, long int __denom);
# define __ldiv_t_defined	1
#endif




typedef enum {
  SDRAM_NO_ERR,
  SDRAM_SPD_COMM_ERR,
  SDRAM_SPD_CHKSUM_ERR,
  SDRAM_UNSUPPORTED_ERR,
  SDRAM_UNKNOWN_ERR
} SDRAM_ERR;

typedef struct {
  const unsigned char mode;
  const unsigned char row;
  const unsigned char col;
  const unsigned char bank;
} SDRAM_SETUP;

static const SDRAM_SETUP sdram_setup_table[] = {
  {1, 11,  9, 2},
  {1, 11, 10, 2},
  {2, 12,  9, 4},
  {2, 12, 10, 4},
  {3, 13,  9, 4},
  {3, 13, 10, 4},
  {3, 13, 11, 4},
  {4, 12,  8, 2},
  {4, 12,  8, 4},
  {5, 11,  8, 2},
  {5, 11,  8, 4},
  {6, 13,  8, 2},
  {6, 13,  8, 4},
  {7, 13,  9, 2},
  {7, 13, 10, 2},
  {0,  0,  0, 0}
};

static const unsigned char cal_indextable[] = {
  9, 23, 25
};


/*
 * translate ns.ns/10 coding of SPD timing values
 * into 10 ps unit values
 */

unsigned short NS10to10PS(unsigned char spd_byte, unsigned char spd_version)
{
  unsigned short ns, ns10;

  /* isolate upper nibble */
  ns = (spd_byte >> 4) & 0x0F;
  /* isolate lower nibble */
  ns10 = (spd_byte & 0x0F);

  return(ns*100 + ns10*10);
}

/*
 * translate ns.ns/4 coding of SPD timing values
 * into 10 ps unit values
 */

unsigned short NS4to10PS(unsigned char spd_byte, unsigned char spd_version)
{
  unsigned short ns, ns4;

  /* isolate upper 6 bits */
  ns = (spd_byte >> 2) & 0x3F;
  /* isloate lower 2 bits */
  ns4 = (spd_byte & 0x03);

  return(ns*100 + ns4*25);
}

/*
 * translate ns coding of SPD timing values
 * into 10 ps unit values
 */

unsigned short NSto10PS(unsigned char spd_byte)
{
  return(spd_byte*100);
}

#ifdef SDRAM_DEBUG

void write_hex(unsigned char i)
{
	char cc;
	cc=i>>4;
	cc&=0xf;
	if(cc>9) 
		serial_putc(cc+55);
	else
		serial_putc(cc+48);
	cc=i&0xf;
	if(cc>9) 
		serial_putc(cc+55);
	else
		serial_putc(cc+48);
}
#endif

int board_pre_init (void)
{
  unsigned char dataout[1];
  unsigned char datain[128];
  unsigned long sdram_size;
  SDRAM_SETUP *t = (SDRAM_SETUP *)sdram_setup_table;
  unsigned long memclk;
  unsigned long tmemclk;
  unsigned long tmp, bank, baseaddr, bank_size;
  unsigned short i;
  unsigned char rows, cols, banks, sdram_banks, density;
  unsigned char supported_cal, trp_clocks, trcd_clocks, tras_clocks, trc_clocks;
  unsigned char cal_index, cal_val, spd_version, spd_chksum;
  unsigned char buf[8];
	
	memclk = get_bus_freq(tmemclk);
 	tmemclk = 1000000000 / (memclk / 100);  /* in 10 ps units */

#ifdef SDRAM_DEBUG
  serial_init(198000000,9600);
  serial_puts("\nstart SDRAM Setup\n");
#endif

  /* Read Serial Presence Detect Information */
  dataout[0] = 0;
  for (i=0; i<128;i++)
    datain[i] = 127;
  i2c_send(SDRAM_EEPROM_WRITE_ADDRESS,1,dataout);
  i2c_receive(SDRAM_EEPROM_READ_ADDRESS,128,datain);
#if 0
    for (i=0;i<128;i++)
  {
      write_hex(datain[i]);
      serial_puts(" ");
      if (((i+1)%16) == 0)
				serial_puts("\n");
  }
  serial_puts("\n");
#endif
  spd_chksum = 0;
  for (i = 0; i < 63; i++) {
        spd_chksum += datain[i];
  } /* endfor */
  if (datain[63] != spd_chksum) {
#ifdef SDRAM_DEBUG
    serial_puts("SPD chksum: 0x"); 
    write_hex(datain[63]);
    serial_puts(" != calc. chksum: 0x");
    write_hex(spd_chksum);
    serial_puts("\n");
#endif
   }
  /* SPD seems to be ok, use it */

  /* get SPD version */
  spd_version = datain[62];

  /* do some sanity checks on the kind of RAM */
  if ((datain[0] < 0x80) ||       /* less than 128 valid bytes in SPD */
      (datain[2] != 0x04) ||      /* if not SDRAM */
      (!((datain[6] == 0x40) ||
	 		(datain[6] == 0x48))) || /* or not (64 Bit or 72 Bit)  */
      (datain[7] != 0x00) ||
      (datain[8] != 0x01) ||      /* or not LVTTL signal levels */
      (datain[126] == 0x66))        /* or a 66Mhz modules */
    serial_puts("\nunsupported SDRAM\n");
#ifdef SDRAM_DEBUG
  serial_puts("SDRAM sanity ok\n");
#endif

  /* get number of rows/cols/banks out of byte 3+4+5 */
  rows = datain[3]; cols = datain[4]; banks = datain[5];

  /* get number of SDRAM banks out of byte 17 and  
     supported CAS latencies out of byte 18 */
  sdram_banks = datain[17]; supported_cal = datain[18] & ~0x81;

  while (t->mode != 0) {
  	if ((t->row == rows) &&	(t->col == cols) && (t->bank == sdram_banks))
      break;
    t++;
  } /* endwhile */

#ifdef SDRAM_DEBUG
  serial_puts("mode: "); 
  write_hex(t->mode);
  serial_puts("\n");
#endif
  if (t->mode == 0)
    puts("\nunsupported SDRAM\n");
  /* get tRP, tRCD, tRAS and density from byte 27+29+30+31 */
#ifdef SDRAM_DEBUG
  serial_puts("tRP: ");
  write_hex(datain[27]); 
  serial_puts("\ntRCD: ");
  write_hex(datain[29]);
  serial_puts("\ntRAS: ");
  write_hex(datain[30]); 
  serial_puts("\n");
#endif

  trp_clocks = (NSto10PS(datain[27])+(tmemclk-1)) / tmemclk;
  trcd_clocks = (NSto10PS(datain[29])+(tmemclk-1)) / tmemclk;
  tras_clocks = (NSto10PS(datain[30])+(tmemclk-1)) / tmemclk;
  density = datain[31];

  /* trc_clocks is sum of trp_clocks + tras_clocks */
  trc_clocks = trp_clocks + tras_clocks;
  
  cal_val = 255;
  for (i = 6, cal_index = 0; (i > 0) && (cal_index < 3); i--) {
    /* is this CAS latency supported ? */
    if ((supported_cal >> i) & 0x01) {
      buf[0]=datain[cal_indextable[cal_index]];
      if (cal_index < 2) {
				if (NS10to10PS(buf[0], spd_version) <= tmemclk)
	  		cal_val = i;
      } 
      else {
				/* SPD bytes 25+26 have another format */
				if (NS4to10PS(buf[0], spd_version) <= tmemclk)
	  			cal_val = i;
      } /* endif */
      cal_index++;
    } /* endif */
  } /* endfor */
#ifdef SDRAM_DEBUG
  serial_puts("CAL: ");
  write_hex(cal_val+1); 
  serial_puts("\n");
#endif

  if (cal_val == 255)
		puts("\nunsupported SDRAM\n");

  /* get SDRAM timing register */
  mtdcr(memcfga,mem_sdtr1);
  tmp=mfdcr(memcfgd) & ~0x018FC01F;
  /* insert CASL value */
  tmp |= ((unsigned long)cal_val) << 23;
  /* insert PTA value */
  tmp |= ((unsigned long)(trp_clocks - 1)) << 18;
  /* insert CTP value */
  tmp |= ((unsigned long)(trc_clocks - trp_clocks - trcd_clocks - 1)) << 16;
  /* insert LDF (always 01) */
  tmp |= ((unsigned long)0x01) << 14;
  /* insert RFTA value */
  tmp |= ((unsigned long)(trc_clocks - 4)) << 2;
  /* insert RCD value */
  tmp |= ((unsigned long)(trcd_clocks - 1)) << 0;

  /* write SDRAM timing register */
  mtdcr(memcfga,mem_sdtr1);
  mtdcr(memcfgd,tmp);
	baseaddr=CFG_SDRAM_BASE;
  bank_size = (((unsigned long)density) << 22) / 2;
  /* insert AM value */
  tmp = ((unsigned long)t->mode-1) << 13;
  /* insert SZ value; */
  switch (bank_size) {
    case 0x00400000: tmp |= ((unsigned long)0x00) << 17; break;
    case 0x00800000: tmp |= ((unsigned long)0x01) << 17; break;
    case 0x01000000: tmp |= ((unsigned long)0x02) << 17; break;
    case 0x02000000: tmp |= ((unsigned long)0x03) << 17; break;
    case 0x04000000: tmp |= ((unsigned long)0x04) << 17; break;
    case 0x08000000: tmp |= ((unsigned long)0x05) << 17; break;
    case 0x10000000: tmp |= ((unsigned long)0x06) << 17; break;
    default: serial_puts("unsupported SDRAM\n");
  } /* endswitch */
  
  /* get SDRAM bank 0 register */
  mtdcr(memcfga,mem_mb0cf);
  bank = mfdcr(memcfgd) & ~0xFFCEE001;
  bank |= (baseaddr | tmp | 0x01);
  baseaddr += bank_size;
  sdram_size += bank_size;

  /* write SDRAM bank 0 register */
  mtdcr(memcfga,mem_mb0cf);
  mtdcr(memcfgd,bank);

  /* get SDRAM bank 1 register */
  mtdcr(memcfga,mem_mb1cf);
  bank = mfdcr(memcfgd) & ~0xFFCEE001;
	sdram_size=0;
  if (banks == 2) {
    bank |= (baseaddr | tmp | 0x01);
    baseaddr += bank_size;
    sdram_size += bank_size;
  } /* endif */

  /* write SDRAM bank 1 register */
  mtdcr(memcfga,mem_mb1cf);
  mtdcr(memcfgd,bank);


  /* get SDRAM bank 2 register */
  mtdcr(memcfga,mem_mb2cf);
  bank = mfdcr(memcfgd) & ~0xFFCEE001;

  bank |= (baseaddr | tmp | 0x01);
  baseaddr += bank_size;
  sdram_size += bank_size;

  /* write SDRAM bank 2 register */
  mtdcr(memcfga,mem_mb2cf);
  mtdcr(memcfgd,bank);


  /* get SDRAM bank 3 register */
  mtdcr(memcfga,mem_mb3cf);
  bank = mfdcr(memcfgd) & ~0xFFCEE001;

  if (banks == 2) {
    bank |= (baseaddr | tmp | 0x01);
    baseaddr += bank_size;
    sdram_size += bank_size;
  } /* endif */

  /* write SDRAM bank 3 register */
  mtdcr(memcfga,mem_mb3cf);
  mtdcr(memcfgd,bank);


  /* get SDRAM refresh interval register */
  mtdcr(memcfga,mem_rtr);
  tmp = mfdcr(memcfgd) & ~0x3FF80000;

  if (tmemclk < NSto10PS(16))
    tmp |= 0x05F00000;
  else
    tmp |= 0x03F80000;

  /* write SDRAM refresh interval register */
  mtdcr(memcfga,mem_rtr);
  mtdcr(memcfgd,tmp);

  /* enable SDRAM controller with no ECC, 32-bit SDRAM width, 16 byte burst */
  mtdcr(memcfga,mem_mcopt1);
  tmp = (mfdcr(memcfgd) &  ~0xFFE00000) | 0x80C00000;
  mtdcr(memcfga,mem_mcopt1);
  mtdcr(memcfgd,tmp);


  
   /*-------------------------------------------------------------------------+
   | Interrupt controller setup for the PIP405 board.
   | Note: IRQ 0-15  405GP internally generated; active high; level sensitive
   |       IRQ 16    405GP internally generated; active low; level sensitive
   |       IRQ 17-24 RESERVED
   |       IRQ 25 (EXT IRQ 0) SouthBridg; active low; level sensitive
   |       IRQ 26 (EXT IRQ 1) NMI: active low; level sensitive
   |       IRQ 27 (EXT IRQ 2) SMI: active Low; level sensitive                          
   |       IRQ 28 (EXT IRQ 3) PCI SLOT 3; active low; level sensitive
   |       IRQ 29 (EXT IRQ 4) PCI SLOT 2; active low; level sensitive
   |       IRQ 30 (EXT IRQ 5) PCI SLOT 1; active low; level sensitive
   |       IRQ 31 (EXT IRQ 6) PCI SLOT 0; active low; level sensitive
   | Note for PIP405 board:
   |       An interrupt taken for the SouthBridge (IRQ 25) indicates that   
   |       the Interrupt Controller in the South Bridge has caused the 
   |       interrupt. The IC must be read to determine which device
   |       caused the interrupt.
   |          
   +-------------------------------------------------------------------------*/
  mtdcr(uicsr, 0xFFFFFFFF);        /* clear all ints */
  mtdcr(uicer, 0x00000000);        /* disable all ints */
  mtdcr(uiccr, 0x00000000);        /* set all to be non-critical (for now)*/
  mtdcr(uicpr, 0xFFFFFF80);        /* set int polarities */
  mtdcr(uictr, 0x10000000);        /* set int trigger levels */
  mtdcr(uicvcr, 0x00000001);       /* set vect base=0,INT0 highest priority*/
  mtdcr(uicsr, 0xFFFFFFFF);        /* clear all ints */

  return 0;
}


/* ------------------------------------------------------------------------- */

/*
 * Check Board Identity:
 */

int checkboard (void)
{
    unsigned char s[32];
		unsigned char bc;
		int i;
		i=getenv_r("serial#",s,32);
    if ((i==0) || strncmp(s, "PIP405", 6)) {
			printf ("### No HW ID - assuming PIP405 ");
    }
    else {
    	s[6]=0;
    	printf("%s SN: %s",s,&s[7]);
		}
		bc=in8(CONFIG_PORT_ADDR);
		printf(" Boot Config: 0x%x\n",bc);
    return (0);
}


/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/*
  initdram(int board_type) reads EEPROM via I2c. EEPROM contains all of  
  the necessary info for SDRAM controller configuration
*/
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
long int initdram (int board_type)
{
  unsigned long bank_reg[4],tmp,bank_size;
 	int i,ds;
  unsigned long TotalSize;

	ds=0;
	/* since the DRAM controller is allready set up, calculate the size with the 
	  bank registers	 */
	mtdcr(memcfga,mem_mb0cf);
  bank_reg[0] = mfdcr(memcfgd);
	mtdcr(memcfga,mem_mb1cf);
  bank_reg[1] = mfdcr(memcfgd);
	mtdcr(memcfga,mem_mb2cf);
  bank_reg[2] = mfdcr(memcfgd);
	mtdcr(memcfga,mem_mb3cf);
  bank_reg[3] = mfdcr(memcfgd);
  TotalSize=0;
	for(i=0;i<4;i++)
	{
		if((bank_reg[i]&0x1)==0x1)
		{
			tmp=(bank_reg[i]>>17)&0x7;
			bank_size=4<<tmp;
			TotalSize+=bank_size;
		}
		else
			ds=1;
	}
	if(ds==1)
      printf("single-sided DIMM ");
  else
    printf("double-sided DIMM ");
  /* return size in Mb unit => *(1024*1024) */
  return (TotalSize*1024*1024);
}

/* ------------------------------------------------------------------------- */

int testdram (void)
{
    /* TODO: XXX XXX XXX */
    printf ("test: xxx MB - ok\n");

    return (0);
}

/* ------------------------------------------------------------------------- */

	/* switches the cs0 and the cs1 to the locations. 
	   When boot is TRUE, the the mapping is switched 
	   to the boot configuration, If it is FALSE, the
	   flash will be switched in the boot area */


int switch_cs(unsigned char boot)
{
  unsigned long pbcr;
	mtdcr(ebccfga, pb0cr); /* get cs0 config reg */
	pbcr = mfdcr(ebccfgd);
	if((pbcr&0x00002000)==0) {  
		/* we need only to switch if boot from MPS */
		/*printf(" MPS boot mode detected. ");*/ 
		/* printf("cs0 cfg: %lx\n",pbcr); */
		if(boot==TRUE) { 
			/* switch to boot configuration */
			/* this is a 8bit boot, switch cs0 to flash location */
			/* printf("switch to boot mode (MPS on High address\n"); */ 
			pbcr&=0x000FFFFF; /*mask base address of the cs0 */
			pbcr|=(FLASH_BASE0_PRELIM & 0xFFF00000);
			mtdcr(ebccfga, pb0cr);
			mtdcr(ebccfgd, pbcr);
			/* printf("new cs0 cfg: %lx\n",pbcr); */
			mtdcr(ebccfga, pb1cr); /* get cs1 config reg (flash) */
			pbcr = mfdcr(ebccfgd);
	/*		printf(" old cs1 cfg: %lx\n",pbcr); */
			pbcr&=0x000FFFFF; /*mask base address of the cs1 */
			pbcr|=(MULTI_PURPOSE_SOCKET_ADDR & 0xFFF00000);
			mtdcr(ebccfga, pb1cr);
			mtdcr(ebccfgd, pbcr);
	/*		printf("new cs1 cfg: %lx, MPS is on High Address\n",pbcr); */
		}
		else 
		{ 
			/* map flash to boot area, */
			/*printf("map Flash to boot area\n"); */
			pbcr&=0x000FFFFF; /*mask base address of the cs0 */
			pbcr|=(MULTI_PURPOSE_SOCKET_ADDR & 0xFFF00000);
			mtdcr(ebccfga, pb0cr);
			mtdcr(ebccfgd, pbcr);
/*			printf("new cs0 cfg: %lx\n",pbcr); */
			mtdcr(ebccfga, pb1cr); /* get cs1 config reg (flash) */
			pbcr = mfdcr(ebccfgd);
/*			printf("cs1 cfg: %lx\n",pbcr); */
			pbcr&=0x000FFFFF; /*mask base address of the cs1 */
			pbcr|=(FLASH_BASE0_PRELIM & 0xFFF00000);
			mtdcr(ebccfga, pb1cr);
			mtdcr(ebccfgd, pbcr);
/*			printf("new cs1 cfg: %lx Flash is on High Address\n",pbcr); */
		}
		return TRUE;
	}
	else
		return FALSE;
/*				printf("Normal boot, no switching necessary\n"); */
}

/************************************************************************
* Print PIP405 Info
************************************************************************/
void print_pip405_info(void)
{
	unsigned char part,vers,cfg,ledu,sysman,flashcom,can,serpwr,compwr,nicvga,scsirst;

	part=in8(PLD_PART_REG);	
	vers=in8(PLD_VERS_REG);	
	cfg=in8(PLD_BOARD_CFG_REG);
	ledu=in8(PLD_LED_USER_REG);
	sysman=in8(PLD_SYS_MAN_REG);
	flashcom=in8(PLD_FLASH_COM_REG);
	can=in8(PLD_CAN_REG);
	serpwr=in8(PLD_SER_PWR_REG);
	compwr=in8(PLD_COM_PWR_REG);
	nicvga=in8(PLD_NIC_VGA_REG);
	scsirst=in8(PLD_SCSI_RST_REG);
	printf("PLD Part %d version %d\n",part&0xf,vers&0xf);
	printf("PLD Part %d version %d\n",(part>>4)&0xf,(vers>>4)&0xf);
	printf("Board Revision %c\n",(cfg&0xf)+'A');
	printf("Population Options %d %d %d %d\n",(cfg>>4)&0x1,(cfg>>5)&0x1,(cfg>>6)&0x1,(cfg>>7)&0x1);
	printf("User LED0 %s User LED1 %s\n",((ledu&0x1)==0x1) ? "on" : "off",((ledu&0x2)==0x2) ? "on" : "off");
	printf("Additionally Options %d %d\n",(ledu>>2)&0x1,(ledu>>3)&0x1);
	printf("User Config Switch %d %d %d %d\n",(ledu>>4)&0x1,(ledu>>5)&0x1,(ledu>>6)&0x1,(ledu>>7)&0x1);
	switch(sysman&0x3)
	{
		case 0:	printf("PCI Clocks are running\n"); break;
		case 1:	printf("PCI Clocks are stopped in POS State\n"); break;
		case 2:	printf("PCI Clocks are stopped when PCI_STP# is asserted\n"); break;
		case 3:	printf("PCI Clocks are stopped\n"); break;
	}
	switch((sysman>>2)&0x3)
	{
		case 0:	printf("Main Clocks are running\n"); break;
		case 1:	printf("Main Clocks are stopped in POS State\n"); break;
		case 2:	
		case 3:	printf("PCI Clocks are stopped\n"); break;
	}
	printf("INIT asserts %sINT2# (SMI)\n",((sysman&0x10)==0x10) ? "" : "not ");
	printf("INIT asserts %sINT1# (NMI)\n",((sysman&0x20)==0x20) ? "" : "not ");
	printf("INIT occured %d\n",(sysman>>6)&0x1);
	printf("SER1 is routed to %s\n",((flashcom&0x1)==0x1) ? "RS485" : "RS232");
	printf("COM2 is routed to %s\n",((flashcom&0x2)==0x2) ? "RS485" : "RS232");
	printf("RS485 is configured as %s duplex\n",((flashcom&0x4)==0x4) ? "full" : "half");
	printf("RS485 is connected to %s\n",((flashcom&0x8)==0x8) ? "COM1" : "COM2");
	printf("SER1 uses handshakes %s\n",((flashcom&0x10)==0x10) ? "DTR/DSR" : "RTS/CTS");
	printf("Bootflash is %swriteprotected\n",((flashcom&0x20)==0x20) ? "not " : "");
	printf("Bootflash VPP is %s\n",((flashcom&0x40)==0x40) ? "on" : "off");
	printf("Bootsector is %swriteprotected\n",((flashcom&0x80)==0x80) ? "not " : "");
	switch((can)&0x3)
	{
		case 0:	printf("CAN Controller is on address 0x1000..0x10FF\n"); break;
		case 1:	printf("CAN Controller is on address 0x8000..0x80FF\n"); break;
		case 2:	printf("CAN Controller is on address 0xE000..0xE0FF\n"); break;
		case 3:	printf("CAN Controller is disabled\n"); break;
	}
	switch((can>>2)&0x3)
	{
		case 0:	printf("CAN Controller Reset is ISA Reset\n"); break;
		case 1:	printf("CAN Controller Reset is ISA Reset and POS State\n"); break;
		case 2:	
		case 3:	printf("CAN Controller is in reset\n"); break;
	}
	if(((can>>4)<3)||((can>>4)==8)||((can>>4)==13))
		printf("CAN Interrupt is disabled\n");
	else
		printf("CAN Interrupt is ISA INT%d\n",(can>>4)&0xf);
	switch(serpwr&0x3)
	{
		case 0:	printf("SER0 Drivers are enabled\n"); break;
		case 1:	printf("SER0 Drivers are disabled in the POS state\n"); break;
		case 2:	
		case 3:	printf("SER0 Drivers are disabled\n"); break;
	}
	switch((serpwr>>2)&0x3)
	{
		case 0:	printf("SER1 Drivers are enabled\n"); break;
		case 1:	printf("SER1 Drivers are disabled in the POS state\n"); break;
		case 2:	
		case 3:	printf("SER1 Drivers are disabled\n"); break;
	}
	switch(compwr&0x3)
	{
		case 0:	printf("COM1 Drivers are enabled\n"); break;
		case 1:	printf("COM1 Drivers are disabled in the POS state\n"); break;
		case 2:	
		case 3:	printf("COM1 Drivers are disabled\n"); break;
	}
	switch((compwr>>2)&0x3)
	{
		case 0:	printf("COM2 Drivers are enabled\n"); break;
		case 1:	printf("COM2 Drivers are disabled in the POS state\n"); break;
		case 2:	
		case 3:	printf("COM2 Drivers are disabled\n"); break;
	}
	switch((nicvga)&0x3)
	{
		case 0:	printf("PHY is running\n"); break;
		case 1:	printf("PHY is in Power save mode in POS state\n"); break;
		case 2:	
		case 3:	printf("PHY is in Power save mode\n"); break;
	}
	switch((nicvga>>2)&0x3)
	{
		case 0:	printf("VGA is running\n"); break;
		case 1:	printf("VGA is in Power save mode in POS state\n"); break;
		case 2:	
		case 3:	printf("VGA is in Power save mode\n"); break;
	}
	printf("PHY is %sreseted\n",((nicvga&0x10)==0x10)?"":"not ");
	printf("VGA is %sreseted\n",((nicvga&0x20)==0x20)?"":"not ");
	printf("Reserved Configuration is %d %d\n",(nicvga>>6)&0x1,(nicvga>>7)&0x1);
	switch((scsirst)&0x3)
	{
		case 0:	printf("SCSI Controller is running\n"); break;
		case 1:	printf("SCSI Controller is in Power save mode in POS state\n"); break;
		case 2:	
		case 3:	printf("SCSI Controller is in Power save mode\n"); break;
	}
	printf("SCSI termination is %s\n",((scsirst&0x4)==0x4)?"disabled":"enabled");
	printf("SCSI Controller is %sreseted\n",((scsirst&0x10)==0x10)?"":"not ");
	printf("IDE disks are %sreseted\n",((scsirst&0x20)==0x20)?"":"not ");
	printf("ISA Bus is %sreseted\n",((scsirst&0x40)==0x40)?"":"not ");
	printf("Super IO is %sreseted\n",((scsirst&0x80)==0x80)?"":"not ");
}

void user_led0(unsigned char on)
{
	if(on==TRUE)
		out8(PLD_LED_USER_REG,(in8(PLD_LED_USER_REG)|0x1));
	else
		out8(PLD_LED_USER_REG,(in8(PLD_LED_USER_REG)&0xfe));
}

void user_led1(unsigned char on)
{
	if(on==TRUE)
		out8(PLD_LED_USER_REG,(in8(PLD_LED_USER_REG)|0x2));
	else
		out8(PLD_LED_USER_REG,(in8(PLD_LED_USER_REG)&0xfd));
}

void ide_set_reset(int idereset)
{
	/* if reset = 1 IDE reset will be asserted */
	unsigned char resreg;
	resreg=in8(PLD_SCSI_RST_REG);
	if(idereset==1)
		resreg|=0x20;
	else
		resreg&=0xdf;
	out8(PLD_SCSI_RST_REG,resreg); 
}


/******************************************************
 * Routines to display the Board information 
 * to the screen (since the VGA will be initialized as last,
 * we must resend the infos)
 */

void video_put_dev_string(block_dev_desc_t *dev_desc)
{
	char buf[80];
	ldiv_t mb;
	unsigned long lba512; /* number of blocks if 512bytes block size */

	if(dev_desc->type!=DEV_TYPE_UNKNOWN) {
		if(dev_desc->if_type==IF_TYPE_SCSI)
			sprintf(buf,"SCSI %d:  (%d:%d) ",dev_desc->dev,dev_desc->target,dev_desc->lun);
		else
			sprintf(buf,"IDE %d:   ",dev_desc->dev);
		video_puts(buf);
		switch(dev_desc->type & 0x1F) {
			case DEV_TYPE_HARDDISK: video_puts("Hard Disk"); break;
			case DEV_TYPE_CDROM: 		video_puts("CD ROM"); break;
			case DEV_TYPE_OPDISK: 	video_puts("Optical Device"); break;
			case DEV_TYPE_TAPE: 		video_puts("Tape"); break;
			default:   							video_puts("unknown"); break;
		}
		video_puts(" ");
		video_puts(dev_desc->vendor);
		video_puts(" ");
		if(dev_desc->if_type!=IF_TYPE_IDE)
			video_puts(dev_desc->product);
	
		if((dev_desc->lba * dev_desc->blksz)>0L) {
			lba512=dev_desc->lba * (dev_desc->blksz/512);
			mb = ldiv(lba512, 2048); /* (1024 *1024 / 512 MB */
			/* round to 1 digit */
			mb.rem *= 10 * 512;
			mb.rem += 512 * 1024;
			mb.rem /= 1024 * 1024;
			sprintf (buf," %ld x %ld Bytes = %ld.%ld MB\n",dev_desc->lba,dev_desc->blksz,mb.quot, mb.rem);
		}
		else {
			sprintf (buf," Capacity: not available\n");
		}
		video_puts(buf);
	}
} 

void video_write_board_info(void)
{
	extern char version_string[];
  unsigned long pvr = get_pvr();
  char buf[32],tmpbuf[80];
  PPC405_SYS_INFO sys_info;
  init_data_t *idata = (init_data_t *)(CFG_INIT_RAM_ADDR + CFG_INIT_DATA_OFFSET);
  unsigned char *s = getenv("serial#");
  unsigned char *e;
  unsigned char bc;
  block_dev_desc_t *dev_desc;
	int i;
	
	/* first write PPCBOOT Info */
	video_puts("\n");
	video_puts(version_string);
	video_puts("\n\n");
	/* then CPU and board infos */
  get_sys_info(&sys_info);
  video_puts("CPU:     IBM PowerPC 405GP Rev. ");
  switch (pvr) {
    case PVR_405GP_RB: video_putc('B'); break;
    case PVR_405GP_RC: video_putc('C'); break;
    case PVR_405GP_RD: video_putc('D'); break;
    default: video_puts("unknown"); break;
  }
  sprintf(tmpbuf," at %s MHz (PLB=%lu, OPB=%lu, EBC=%lu MHz)\n", strmhz(buf,idata->cpu_clk),
         sys_info.freqPLB / 1000000,
         sys_info.freqPLB / sys_info.pllOpbDiv / 1000000,
         sys_info.freqPLB / sys_info.pllExtBusDiv / 1000000);
	video_puts(tmpbuf);
  if (mfdcr(strap) & PSR_PCI_ASYNC_EN)
    video_puts("         PCI async ext clock used, ");
  else {
  	sprintf(buf,"         PCI sync clock at %lu MHz, ", sys_info.freqPLB / sys_info.pllPciDiv / 1000000);
    video_puts(buf);
  }
  if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
    video_puts("internal PCI arbiter enabled\n");
  else
    video_puts("external PCI arbiter enabled\n");
  video_puts("         16 kB I-Cache 8 kB D-Cache\n");
  /* now some board infos */
  video_puts("Board:   ");
  if (!s || strncmp(s, "PIP405", 6)) {
  	bc=video_set_attr(VGA_ATTR_CLR_RED | VGA_ATTR_ITN);
		video_puts("### No HW ID - assuming PIP405");
  }
  else {
  	bc=video_set_attr(VGA_ATTR_CLR_GRN);
  	for (e=s; *e; ++e) {
    	if (*e == ' ')
	    	break;
    }
    for ( ; s<e; ++s) {
    	if(*s=='_') {
				++s;
				break;
			}
			video_putc (*s);
	 	}
		video_puts("  Serial No.: ");
    for ( ; s<e; ++s) {
			video_putc (*s);
		}
  }
	video_set_attr(bc);
	bc=in8(CONFIG_PORT_ADDR);
	sprintf(buf," Boot Config 0x%02X\n",bc);
  video_puts(buf);
	/* DRAM size    */
  video_puts("DRAM:    ");
	sprintf(buf,"%lu MBytes\n",bd_ptr->bi_memsize/0x100000);		
  video_puts(buf);
  /* flash size: */
  video_puts("FLASH:   ");
  if(switch_cs(0)==0) {
  	bc=video_set_attr(VGA_ATTR_CLR_GRN);
		video_puts("(Flash boot)");
 		video_set_attr(bc);
	}
	else {
  	switch_cs(1); /* back to boot mode */
		bc=video_set_attr(VGA_ATTR_CLR_RED | VGA_ATTR_ITN);
		video_puts("(Multi Purpose Socket boot)");
 		video_set_attr(bc);
	}
	sprintf(buf," %lu MBytes\n",bd_ptr->bi_flashsize/0x100000);		
  video_puts(buf);
	/* revisions */
  video_puts("Rev:     ");
	sprintf(tmpbuf,"PCB Rev: %c PLD%d Rev %d PLD%d Rev %d\n\n",(in8(PLD_BOARD_CFG_REG)&0xf)+'A',
				in8(PLD_PART_REG)&0xf,in8(PLD_VERS_REG)&0xf,
				(in8(PLD_PART_REG)>>4)&0xf,(in8(PLD_VERS_REG)>>4)&0xf);		
  video_puts(tmpbuf);
	for(i=0;i<CFG_IDE_MAXDEVICE;i++) {
		dev_desc=(block_dev_desc_t *)ide_get_dev(i);
		video_put_dev_string(dev_desc);
	}
	video_puts("\n");
	for(i=0;i<CFG_SCSI_MAX_DEVICE;i++) {
		dev_desc=(block_dev_desc_t *)scsi_get_dev(i);
		video_put_dev_string(dev_desc);
	}
	video_puts("\n");
			
}






