/*
 * 
 * (C) Copyright 2000
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 * 
 * (C) Copyright 2001
 * James Dougherty (jfd@cs.stanford.edu)
 *
 * 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
 */

/*
 * PCI Configuration space access support for MPC8240/MPC107 PCI Bridge
 */
#include <ppcboot.h>
#include "mpc8240.h"
#include "pci.h"
#include "mousse.h"

int  numPciBus = 1; /* One bus: MPC107 Internal bridge */

/*
 *
 * pci_dev_find - find the nth device with the given device & vendor ID
 *
 */
int pci_dev_find(int   vendorId,      /* vendor ID */
		 int   deviceId,      /* device ID */
		 int   index,	      /* desired instance of device */
		 int*  pBusNo,	      /* bus number */
		 int*  pDeviceNo,     /* device number */
		 int*  pFuncNo)	      /* function number */
{
  int status = ERROR;
  int   cont   = TRUE;
  int    busNo;
  int    deviceNo;
  int    funcNo;
  uint32 device;
  uint32 vendor;
  char   header;
  
  for (busNo = 0; cont == TRUE && busNo <= numPciBus; busNo++)
    for (deviceNo = 0;
	 ((cont == TRUE) && (deviceNo < PCI_MAX_DEV));
	 ++deviceNo)
      for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++){
	/* avoid a special bus cycle */
	
	if ((deviceNo == 0x1f) && (funcNo == 0x07))
	  continue;
	
	pci_config_inl (busNo, deviceNo, funcNo, PCI_CFG_VENDOR_ID,
			&vendor);
	
	/*
	 * If nonexistent device, skip to next, only look at
	 * vendor ID field for existence check
	 */
	if (((vendor & 0x0000ffff) == 0x0000FFFF) && (funcNo == 0))
	  break;
	device  = vendor >> 16;
	device &= 0x0000FFFF;
	vendor &= 0x0000FFFF;
	if ((vendor == (uint32)vendorId) &&
	    (device == (uint32)deviceId) &&
	    (index-- == 0)){
	  *pBusNo	= busNo;
	  *pDeviceNo	= deviceNo;
	  *pFuncNo	= funcNo;
	  status	= OK;
	  cont	= FALSE;	/* terminate all loops */
	  continue;
	}
	
	/* goto next if current device is single function */
	
	pci_config_inb (busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE, 
			&header);
	if ((header & PCI_HEADER_MULTI_FUNC) !=
	    PCI_HEADER_MULTI_FUNC && funcNo == 0)
	  break;
      }
  
  return status;
}

/*
 *
 * pci_class_find - find the nth occurence of a device by PCI class code.
 *
 * RETURNS:
 * OK, or ERROR if the class didn't match.
 */

int pci_class_find(int    classCode,	/* 24-bit class code */
		   int	   index,	/* desired instance of device */
		   int *  pBusNo,	/* bus number */
		   int *  pDeviceNo,	/* device number */
		   int *  pFuncNo)	/* function number */
{
  int status = ERROR;
  int   cont   = TRUE;
  int    busNo;
  int    deviceNo;
  int    funcNo;
  int    classCodeReg;
  int    vendor;
  char   header;
  
  
  for (busNo = 0; cont == TRUE && busNo <= numPciBus; busNo++)
    for (deviceNo = 0;
	 ((cont == TRUE) && (deviceNo < PCI_MAX_DEV));
	 ++deviceNo)
      for (funcNo = 0; cont == TRUE && funcNo < PCI_MAX_FUNC; funcNo++){
	
	/* avoid a special bus cycle */
	if ((deviceNo == 0x1f) && (funcNo == 0x07))
	  continue;
	
	pci_config_inl (busNo, deviceNo, funcNo, PCI_CFG_VENDOR_ID,
			&vendor);
	
	/*
	 * If nonexistent device, skip to next, only look at
	 * vendor ID field for existence check
	 */
	if (((vendor & 0x0000ffff) == 0x0000FFFF) && (funcNo == 0))
	  break;
	
	pci_config_inl (busNo, deviceNo, funcNo, PCI_CFG_REVISION,
			&classCodeReg);
	
	if ((((classCodeReg >> 8) & 0x00ffffff) == classCode) &&
	    (index-- == 0))
	  {
	    *pBusNo	= busNo;
	    *pDeviceNo	= deviceNo;
	    *pFuncNo	= funcNo;
	    status	= OK;
	    cont 	= FALSE;	/* terminate all loops */
	    continue;
	  }
	
	/* goto next if current device is single function */
	
	pci_config_inb (busNo, deviceNo, funcNo, PCI_CFG_HEADER_TYPE, 
			&header);
	if ((header & PCI_HEADER_MULTI_FUNC) !=
	    PCI_HEADER_MULTI_FUNC && funcNo == 0)
	  break;
      }
  return status;
}


/*
 *
 * pci_dev_config - configure a device on a PCI bus
 *
 * This routine configures a device that is on a Peripheral Component
 * Interconnect (PCI) bus by writing to the configuration header of the
 * selected device.
 *
 * It first disables the device by clearing the command register in the
 * configuration header.  It then sets the I/O and/or memory space base
 * address registers, the latency timer value and the cache line size.
 * Finally, it re-enables the device by loading the command register with
 * the specified command.
 *
 * NOTE: This routine is designed for Type 0 PCI Configuration Headers ONLY.
 * It is NOT usable for configuring, for example, a PCI-to-PCI bridge.
 *
 * RETURNS: OK always.
 */
int pci_dev_config(int pciBusNo,          /* PCI bus number */
		   int pciDevNo,          /* PCI device number */
		   int pciFuncNo,         /* PCI function number */
		   uint32 devIoBaseAdrs,  /* device IO base address */
		   uint32 devMemBaseAdrs, /* device memory base address */
		   uint32 command)         /* command to issue */
{
  int    ix;
  uint32 tmp32;
  
  /*
   * Disable device by clearing its command register field in its
   * configuration header. Write 0 clears command and preserves status.
   */
  pci_config_outl (pciBusNo, pciDevNo, pciFuncNo, PCI_CFG_COMMAND, 0x0);
  
  for (ix = PCI_CFG_BASE_ADDRESS_0; ix <= PCI_CFG_BASE_ADDRESS_5; ix+=4){

    /* Write all f's and read back value */
    pci_config_outl (pciBusNo, pciDevNo, pciFuncNo, ix, 0xffffffff);
    pci_config_inl  (pciBusNo, pciDevNo, pciFuncNo, ix, &tmp32);
    
    if (tmp32 == 0){
      /* No bar */
      break;
    }
    
    /* I/O space requested */
    if (tmp32 & 0x1){
      pci_config_outl (pciBusNo, pciDevNo, pciFuncNo, ix,
		       devIoBaseAdrs | 0x1);
    } else{
      /* Memory space required, set specified base address */
      pci_config_outl (pciBusNo, pciDevNo, pciFuncNo, ix,
		       devMemBaseAdrs & ~0x1);
    }
  }
  
  /* Configure Cache Line Size Register */
  pci_config_outb (pciBusNo, pciDevNo, pciFuncNo,
		   PCI_CFG_CACHE_LINE_SIZE,
		   PCI_CACHE_LINE_SIZE);
  
  /* Configure Latency Timer */
  pci_config_outb (pciBusNo, pciDevNo, pciFuncNo,
		   PCI_CFG_LATENCY_TIMER,
		   PCI_LATENCY_TIMER);
  
  /*
   * Enable the device's capabilities as specified, do not
   * reset any status bits in doing so.
   */  
  pci_config_modl (pciBusNo, pciDevNo, pciFuncNo,
		   PCI_CFG_COMMAND,
		   (PCI_CMD_MASK | command), command);
  
  return OK;
}


/*
 *
 * pci_config_bdf_pack - pack parameters for the Configuration Address Register
 *
 * This routine packs three parameters into one integer for accessing the
 * Configuration Address Register
 *
 */

int pci_config_bdf_pack(int	busNo,    /* bus number */
			int	deviceNo, /* device number */
			int	funcNo)    /* function number */
{
  return (((busNo    << 16) & 0x00ff0000) |
	  ((deviceNo << 11) & 0x0000f800) |
	  ((funcNo   << 8)  & 0x00000700));
}	

/*
 * pci_config_inb - read one byte from the PCI configuration space
 *
 * This routine reads one byte from the PCI configuration space
 *
 */
int pci_config_inb(int busNo,    /* bus number */
		   int deviceNo, /* device number */
		   int funcNo,	  /* function number */
		   int offset,	  /* offset into config space */
		   uint8 * pData) /* data read from the offset */
{
  uint8 retval = 0;
  int retStat = ERROR;
  
  mpc8240_mpc107_write32 (CHRP_REG_ADDR, 
			  pci_config_bdf_pack (busNo, deviceNo, funcNo) |
			  (offset & 0xfc) | 0x80000000);
  retval = mpc8240_mpc107_read8 (CHRP_REG_DATA + (offset & 0x3));
  retStat = OK;
  
  *pData = retval;
  
  return retStat;
}

/*
 *
 * pci_config_inw - read one word from the PCI configuration space
 *
 * This routine reads one word from the PCI configuration space
 *
 */
int pci_config_inw(int busNo,      /* bus number */
		   int deviceNo,   /* device number */
		   int funcNo,     /* function number */
		   int offset,     /* offset into config space */
		   uint16 * pData)  /* data read from the offset */
{
  int retStat = ERROR;
  uint16 retval = 0;
  
  if (((offset & (int)0x1) > 0) ) {
    return (retStat);
  }
  
  mpc8240_mpc107_write32 (CHRP_REG_ADDR, 
			  pci_config_bdf_pack (busNo, deviceNo, funcNo) |
			  (offset & 0xfc) | 0x80000000);
  retval = mpc8240_mpc107_read16 (CHRP_REG_DATA + (offset & 0x2));
  retStat = OK;
  *pData = retval;
  
  return retStat;
}

/*
 *
 * pci_config_inl - read one longword from the PCI configuration space
 *
 * This routine reads one longword from the PCI configuration space
 *
 */
int pci_config_inl(int	busNo,     /* bus number */
		   int	deviceNo,  /* device number */
		   int	funcNo,    /* function number */
		   int	offset,    /* offset into config space */
		   uint32 * pData) /* data read from the offset */
{
  int retStat = ERROR;
  uint32 retval = 0;
  
  if (((offset & (int)0x3) > 0) ) {
    return (retStat);
  }
  mpc8240_mpc107_write32 (CHRP_REG_ADDR, 
			  pci_config_bdf_pack (busNo, deviceNo, funcNo) |
			  (offset & 0xfc) | 0x80000000);
  retval = mpc8240_mpc107_read32 (CHRP_REG_DATA);
  asm volatile ("eieio");
  retStat = OK;
  *pData = retval;
  return retStat;
}

/*
 * pci_config_outb - write one byte to the PCI configuration space
 *
 * This routine writes one byte to the PCI configuration space.
 *
 */
int pci_config_outb(int busNo,    /* bus number */
		    int deviceNo, /* device number */
		    int funcNo,   /* function number */
		    int offset,   /* offset into config space */
		    uint8 data)    /* data written to the offset */
{
  
  mpc8240_mpc107_write32 (CHRP_REG_ADDR, 
			  pci_config_bdf_pack (busNo, deviceNo, funcNo) |
			  (offset & 0xfc) | 0x80000000);
  mpc8240_mpc107_write8 ((CHRP_REG_DATA + (offset & 0x3)), data);
  return OK;
}

/*
 * pci_config_outw - write one 16-bit word to the PCI configuration space
 *
 * This routine writes one 16-bit word to the PCI configuration space.
 *
 * RETURNS: OK, or ERROR if this library is not initialized
 */
int pci_config_outw(int busNo,    /* bus number */
		    int deviceNo, /* device number */
		    int funcNo,   /* function number */
		    int offset,   /* offset into config space */
		    uint16 data)   /* data written to the offset */
{
  if (((offset & (int)0x1) > 0) ){
    return (ERROR);
  }

  mpc8240_mpc107_write32 (CHRP_REG_ADDR,
			  pci_config_bdf_pack (busNo, deviceNo, funcNo) |
			  (offset & 0xfc) | 0x80000000);
  mpc8240_mpc107_write16 ((CHRP_REG_DATA + (offset & 0x2)), data);
  return OK;
}


/*
 *
 * pci_config_outl - write one longword to the PCI configuration space
 *
 * This routine writes one longword to the PCI configuration space.
 *
 */
int pci_config_outl(int busNo,    /* bus number */
		    int deviceNo, /* device number */
		    int funcNo,   /* function number */
		    int offset,   /* offset into config space */
		    uint32 data)   /* data written to the offset */
{
  if (((offset & (int)0x3) > 0) ){
    return (ERROR);
  }
  mpc8240_mpc107_write32 (CHRP_REG_ADDR,
			  pci_config_bdf_pack (busNo, deviceNo, funcNo) |
			  (offset & 0xfc) | 0x80000000);
  mpc8240_mpc107_write32 (CHRP_REG_DATA, data);
  asm volatile ("eieio");
  return OK;
}


/*
 *
 * pci_config_modl - Perform a masked longword register update
 *
 * This function writes a field into a PCI configuration header without
 * altering any bits not present in the field.  It does this by first
 * doing a PCI configuration read (into a temporary location) of the PCI
 * configuration header word which contains the field to be altered.
 * It then alters the bits in the temporary location to match the desired
 * value of the field.  It then writes back the temporary location with
 * a configuration write.  All configuration accesses are long and the
 * field to alter is specified by the "1" bits in the 'bitMask' parameter.
 *
 */

int pci_config_modl(int busNo,        /* bus number */
		    int deviceNo,     /* device number */
		    int funcNo,       /* function number */
		    int offset,       /* offset into config space */
		    uint32 bitMask,   /* Mask of bits to alter */
		    uint32 data)      /* data written to the offset */
  
{
  uint32 temp;
  int stat;
  
  if (((offset & (int)0x3) > 0) ){
    return (ERROR);
  }

  stat = pci_config_inl (busNo, deviceNo, funcNo, offset, &temp);	
  if (stat == OK){
    temp = (temp & ~bitMask) | (data & bitMask);
    stat = pci_config_outl (busNo, deviceNo, funcNo, offset, temp);
  }
  return stat;
}


/*
 *
 * pci_config_modw - Perform a masked short register update
 *
 */
int pci_config_modw(int busNo,          /* bus number */
		    int deviceNo,       /* device number */
		    int funcNo,         /* function number */
		    int offset,         /* offset into config space */
		    uint16 bitMask,     /* Mask of bits to alter */
		    uint16 data)        /* data written to the offset */
{
  uint16 temp;
  int stat;    
  if (((offset & (int)0x1) > 0) ){
    return (ERROR);
  }
  stat = pci_config_inw (busNo, deviceNo, funcNo, offset, &temp);
  if (stat == OK){
    temp = (temp & ~bitMask) | (data & bitMask);
    stat = pci_config_outw (busNo, deviceNo, funcNo, offset, temp);
  }
  return stat;
}



/*
 * pci_config_modb - Perform a masked byte register update
 *
 */
int pci_config_modb(int busNo,          /* bus number */
		    int deviceNo,       /* device number */
		    int funcNo,         /* function number */
		    int offset,         /* offset into config space */
		    uint8 bitMask,      /* Mask of bits to alter */
		    uint8 data)         /* data written to the offset */
{
  uint8 temp;
  int stat;
  stat = pci_config_inb (busNo, deviceNo, funcNo, offset, &temp);
  if (stat == OK){
    temp = (temp & ~bitMask) | (data & bitMask);
    stat = pci_config_outb (busNo, deviceNo, funcNo, offset, temp);
  }
  return stat;
}

/*
 * pci_special_cycle - generate a special cycle with a message
 */
int
pci_special_cycle(int busNo,       /* bus number */
		  uint32 message)  /* data driven onto AD[31:0] */
{
  int deviceNo	= 0x0000001f;	
  int funcNo	= 0x00000007;
  
  mpc8240_mpc107_write32 (CHRP_REG_ADDR, 
			  pci_config_bdf_pack (busNo, deviceNo, funcNo) |
			  0x80000000);
  mpc8240_mpc107_write32 (CHRP_REG_DATA, message);
  return OK;
}


/*
 * Find the extent of a PCI decode..
 */
unsigned int
pci_size_bar(unsigned int base, unsigned long mask)
{
  uint32 size = mask & base;  /* Find the significant bits */
  size = size & ~(size-1); /* Get the lowest of them to find the decode size */
  return size-1;	   /* extent = size - 1 */
}


/*
 * Promise ATA/66 support.
 */
#define XFER_PIO_4	0x0C	/* 0000|1100 */
#define XFER_PIO_3	0x0B	/* 0000|1011 */
#define XFER_PIO_2	0x0A	/* 0000|1010 */
#define XFER_PIO_1	0x09	/* 0000|1001 */
#define XFER_PIO_0	0x08	/* 0000|1000 */
#define XFER_PIO_SLOW	0x00	/* 0000|0000 */

/* Promise Regs */
#define REG_A		0x01
#define REG_B		0x02
#define REG_C		0x04
#define REG_D		0x08

void
pdc202xx_decode_registers (unsigned char registers, unsigned char value)
{
	unsigned char	bit = 0, bit1 = 0, bit2 = 0;
	switch(registers) {
		case REG_A:
			bit2 = 0;
			printf("  A Register ");
			if (value & 0x80) printf("SYNC_IN ");
			if (value & 0x40) printf("ERRDY_EN ");
			if (value & 0x20) printf("IORDY_EN ");
			if (value & 0x10) printf("PREFETCH_EN ");
			if (value & 0x08) { printf("PA3 ");bit2 |= 0x08; }
			if (value & 0x04) { printf("PA2 ");bit2 |= 0x04; }
			if (value & 0x02) { printf("PA1 ");bit2 |= 0x02; }
			if (value & 0x01) { printf("PA0 ");bit2 |= 0x01; }
			printf("PIO(A) = %d ", bit2);
			break;
		case REG_B:
			bit1 = 0;bit2 = 0;
			printf("  B Register ");
			if (value & 0x80) { printf("MB2 ");bit1 |= 0x80; }
			if (value & 0x40) { printf("MB1 ");bit1 |= 0x40; }
			if (value & 0x20) { printf("MB0 ");bit1 |= 0x20; }
			printf("DMA(B) = %d ", bit1 >> 5);
			if (value & 0x10) printf("PIO_FORCED/PB4 ");
			if (value & 0x08) { printf("PB3 ");bit2 |= 0x08; }
			if (value & 0x04) { printf("PB2 ");bit2 |= 0x04; }
			if (value & 0x02) { printf("PB1 ");bit2 |= 0x02; }
			if (value & 0x01) { printf("PB0 ");bit2 |= 0x01; }
			printf("PIO(B) = %d ", bit2);
			break;
		case REG_C:
			bit2 = 0;
			printf("  C Register ");
			if (value & 0x80) printf("DMARQp ");
			if (value & 0x40) printf("IORDYp ");
			if (value & 0x20) printf("DMAR_EN ");
			if (value & 0x10) printf("DMAW_EN ");

			if (value & 0x08) { printf("MC3 ");bit2 |= 0x08; }
			if (value & 0x04) { printf("MC2 ");bit2 |= 0x04; }
			if (value & 0x02) { printf("MC1 ");bit2 |= 0x02; }
			if (value & 0x01) { printf("MC0 ");bit2 |= 0x01; }
			printf("DMA(C) = %d ", bit2);
			break;
		case REG_D:
			printf("  D Register ");
			break;
		default:
			return;
	}
	printf("\n        %s ", (registers & REG_D) ? "DP" :
				(registers & REG_C) ? "CP" :
				(registers & REG_B) ? "BP" :
				(registers & REG_A) ? "AP" : "ERROR");
	for (bit=128;bit>0;bit/=2)
		printf("%s", (value & bit) ? "1" : "0");
	printf("\n");
}

/*
 * Promise ATA/66 Support: configure Promise ATA66 card in specified mode.
 */
int
pdc202xx_tune_chipset (int bus, int dev, int func,
		       int drive, unsigned char speed)
{
	unsigned short		drive_conf;
	int			err;
	unsigned char			drive_pci, AP, BP, CP, DP;
	unsigned char			TA = 0, TB = 0;

	switch (drive) {
		case 0: drive_pci = 0x60; break;
		case 1: drive_pci = 0x64; break;
		case 2: drive_pci = 0x68; break;
		case 3: drive_pci = 0x6c; break;
		default: return -1;
	}

	pci_config_inw(bus,dev,func, drive_pci, &drive_conf);
	pci_config_inb(bus,dev,func, (drive_pci), &AP);
	pci_config_inb(bus,dev,func, (drive_pci)|0x01, &BP);
	pci_config_inb(bus,dev,func, (drive_pci)|0x02, &CP);
	pci_config_inb(bus,dev,func, (drive_pci)|0x03, &DP);

	if ((AP & 0x0F) || (BP & 0x07)) {
	  /* clear PIO modes of lower 8421 bits of A Register */
	  pci_config_outb(bus,dev,func, (drive_pci), AP & ~0x0F);
	  pci_config_inb(bus,dev,func, (drive_pci), &AP);
	  
	  /* clear PIO modes of lower 421 bits of B Register */
	  pci_config_outb(bus,dev,func, (drive_pci)|0x01, BP & ~0x07);
	  pci_config_inb(bus,dev,func, (drive_pci)|0x01, &BP);
	  
	  pci_config_inb(bus,dev,func, (drive_pci), &AP);
	  pci_config_inb(bus,dev,func, (drive_pci)|0x01, &BP);
	}

	pci_config_inb(bus,dev,func, (drive_pci), &AP);
	pci_config_inb(bus,dev,func, (drive_pci)|0x01, &BP);
	pci_config_inb(bus,dev,func, (drive_pci)|0x02, &CP);

	switch(speed) {
		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
		case XFER_PIO_0:
		default:		TA = 0x09; TB = 0x13; break;
	}

	pci_config_outb(bus,dev,func, (drive_pci), AP|TA);
	pci_config_outb(bus,dev,func, (drive_pci)|0x01, BP|TB);

	pci_config_inb(bus,dev,func, (drive_pci), &AP);
	pci_config_inb(bus,dev,func, (drive_pci)|0x01, &BP);
	pci_config_inb(bus,dev,func, (drive_pci)|0x02, &CP);
	pci_config_inb(bus,dev,func, (drive_pci)|0x03, &DP);


#ifdef PDC202XX_DEBUG
	pdc202xx_decode_registers(REG_A, AP);
	pdc202xx_decode_registers(REG_B, BP);
	pdc202xx_decode_registers(REG_C, CP);
	pdc202xx_decode_registers(REG_D, DP);
#endif
	return err;
}


/*
 * Show/Init PCI devices on the specified bus number.
 */
int pci_dev_init(int busNo)
{
  int deviceNo, a;
  uint32 cmd, bar;
  int devices;
  uint16 vendorId;
  uint16 deviceId;
  uint32 mbar0;
  uint32 mbar1;
  uint32 revId;
  uint32 iline,ipin;

  union {
    int classCode;
    char array[4];
  } u;
    
  printf("PCI:    scanning bus%d ...\n", busNo);
  printf("  bus dev fn venID devID class"
	 "  rev MBAR0    MBAR1    IPIN ILINE\n");
  
  devices = 0x1f;
  for (deviceNo=0; deviceNo < devices; deviceNo++) {

    /* Get device and vendor ID */
    pci_config_inw (busNo, deviceNo, 0, PCI_CFG_VENDOR_ID, &vendorId);
    pci_config_inw (busNo, deviceNo, 0, PCI_CFG_DEVICE_ID, &deviceId);
    
    /* MPC107 Bridge */
    if( deviceNo == 0x0){
      /* Don't do anything */
    }
    
    /* Make sure IRQ's on PCI devices get configured correctly */
    if( deviceNo == 0x0d){
      /* Onboard */
      pci_dev_config(busNo, deviceNo, 0,
		     PCI_ENET_IOADDR,
		     PCI_ENET_MEMADDR,
		     PCI_CMD_MEM_ENABLE |
		     PCI_CMD_MEM_ENABLE |			  
		     PCI_CMD_MASTER_ENABLE);
      /* DEC get's IRQ=1 */
      pci_config_outl(busNo, deviceNo, 0, PCI_CFG_DEV_INT_LINE, 0x00000101);
    }  /* PCI Slot */
    else if (deviceNo == 0x0e){

      if(vendorId == PCI_VENDOR_ID_PROMISE||
	 vendorId == 0x1095){
	/* PDC 202xx card is handled differently, it is a bootable
	 * device and needs all 5 MBAR's configured
	 */
	for(bar = 0; bar < 5; bar++){
	  pci_config_inl(busNo, deviceNo, 0,
			 PCI_CFG_BASE_ADDRESS_0+bar*4,
			 &mbar0);
	  pci_config_outl(busNo, deviceNo, 0,
			  PCI_CFG_BASE_ADDRESS_0+bar*4,
			  ~0);
	  pci_config_inl(busNo, deviceNo, 0,
			 PCI_CFG_BASE_ADDRESS_0+bar*4,
			 &mbar0);
	  /*	  printf("  ATA_bar[%d] = %dbytes\n",
		  bar,pci_size(mbar0,PCI_BASE_ADDRESS_MEM_MASK)); */
	}
	/* Program all BAR's */
	pci_config_outl(busNo, deviceNo, 0, PCI_CFG_BASE_ADDRESS_0,
			PROMISE_MBAR0);
	pci_config_outl(busNo, deviceNo, 0, PCI_CFG_BASE_ADDRESS_1,
			PROMISE_MBAR1);	
	pci_config_outl(busNo, deviceNo, 0, PCI_CFG_BASE_ADDRESS_2,
			PROMISE_MBAR2);
	pci_config_outl(busNo, deviceNo, 0, PCI_CFG_BASE_ADDRESS_3,
			PROMISE_MBAR3);
	pci_config_outl(busNo, deviceNo, 0, PCI_CFG_BASE_ADDRESS_4,
			PROMISE_MBAR4);
	pci_config_outl(busNo, deviceNo, 0, PCI_CFG_BASE_ADDRESS_5,
			PROMISE_MBAR5);
	for(bar = 0; bar < 5; bar++){

	  pci_config_inl(busNo, deviceNo, 0,
			 PCI_CFG_BASE_ADDRESS_0+bar*4,
			 &mbar0);
	  /* printf("  ATA_bar[%d]@0x%x\n", bar,mbar0);*/

	}
	/* Enable ROM Expansion base */
	pci_config_outl(busNo, deviceNo, 0, PCI_CFG_ROM_BASE,
			PROMISE_MBAR5|1);

	/* IRQ 3 */
	pci_config_outl(busNo, deviceNo, 0, PCI_CFG_DEV_INT_LINE,
			0x00000303);	

	/* Io enable, Memory enable, master enable */
	cmd = PCI_CMD_MASTER_ENABLE | PCI_CMD_MEM_ENABLE|PCI_CMD_IO_ENABLE;
	pci_config_modl (busNo, deviceNo, 0, PCI_CFG_COMMAND,
			 (PCI_CMD_MASK | cmd),cmd);

	/* Breath some life into the controller */
	for( a = 0; a < 4; a++) 
	  pdc202xx_tune_chipset(busNo,deviceNo, 0, a, XFER_PIO_0);
	
      } else { 
	/* Other PCI Devices */      

	pci_dev_config(busNo, deviceNo, 0,
		       PCI_SLOT_IOADDR,
		       PCI_SLOT_MEMADDR,
		       PCI_CMD_MEM_ENABLE |
		       PCI_CMD_MEM_ENABLE |			  
		       PCI_CMD_MASTER_ENABLE);
	/* PCI slot get's IRQ=3 */
	pci_config_outl(busNo, deviceNo, 0, PCI_CFG_DEV_INT_LINE, 0x00000303);
	pci_config_outl(busNo, deviceNo, 0, PCI_LATENCY_TIMER, 127);
      }


    }

    pci_config_inb (busNo, deviceNo, 0, PCI_CFG_PROGRAMMING_IF, 
		    &u.array[3]);
    pci_config_inb (busNo, deviceNo, 0, PCI_CFG_SUBCLASS, &u.array[2]);
    pci_config_inb (busNo, deviceNo, 0, PCI_CFG_CLASS, &u.array[1]);
    u.array[0] = 0;
    
    pci_config_inl(busNo, deviceNo, 0, PCI_CFG_BASE_ADDRESS_0, &mbar0);
    pci_config_inl(busNo, deviceNo, 0, PCI_CFG_BASE_ADDRESS_1, &mbar1);
    
    pci_config_inl(busNo, deviceNo, 0, PCI_CFG_REVISION, &revId);
    revId &= 0x000000ff;
    
    pci_config_inl(busNo, deviceNo, 0, PCI_CFG_DEV_INT_LINE, &iline);
    iline &= 0x000000ff;
    
    pci_config_inl(busNo, deviceNo, 0, PCI_CFG_DEV_INT_LINE, &ipin);
    ipin  &= 0x0000ff00;
    ipin >>= 8;


    /* There are two ways to find out an empty device.
     *   1. check Master Abort bit after the access.
     *   2. check whether the read value is 0xffff.
     * Since I didn't see the Master Abort bit of the host/PCI bridge
     * changing, I use the second method.
     */
    if (vendorId != 0xffff)
      
      printf("  %02x  %02x  %02x %04x  %04x  "
	     "%06x %02x  %08x %08x %02x   %02x\n",
	     busNo, deviceNo, 0,
	     vendorId, deviceId, u.classCode, revId,
	     mbar0, mbar1, ipin, iline);
  }
  return OK;
}


