/*
 * $Id: prep_pci.c,v 1.35.2.1 1999/07/22 01:49:42 cort Exp $
 * PReP pci functions.
 * Originally by Gary Thomas
 * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
 *
 * The motherboard routes/maps will disappear shortly. -- Cort
 */

#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/openpic.h>

#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/ptrace.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/residual.h>
#include <asm/processor.h>
#include <asm/irq.h>
#include <asm/machdep.h>

#include "pci.h"

#define MAX_DEVNR 22

/* Which PCI interrupt line does a given device [slot] use? */
/* Note: This really should be two dimensional based in slot/pin used */
unsigned char *Motherboard_map;
unsigned char *Motherboard_map_name;

/* How is the 82378 PIRQ mapping setup? */
unsigned char *Motherboard_routes;
void (*Motherboard_non0)(struct pci_dev *);

void Mesquite_Map_Non0(struct pci_dev *);

/* Used for Motorola to store system config register */
static unsigned long	*ProcInfo;

extern void chrp_do_IRQ(struct pt_regs *,int , int);

/* Tables for known hardware */   

/* Motorola PowerStackII - Utah */
static char Utah_pci_IRQ_map[23] __prepdata =
{
        0,   /* Slot 0  - unused */
        0,   /* Slot 1  - unused */
        5,   /* Slot 2  - SCSI - NCR825A  */
        0,   /* Slot 3  - unused */
        1,   /* Slot 4  - Ethernet - DEC2114x */
        0,   /* Slot 5  - unused */
        3,   /* Slot 6  - PCI Card slot #1 */
        4,   /* Slot 7  - PCI Card slot #2 */
        5,   /* Slot 8  - PCI Card slot #3 */
        5,   /* Slot 9  - PCI Bridge */
             /* added here in case we ever support PCI bridges */
             /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
        0,   /* Slot 10 - unused */
        0,   /* Slot 11 - unused */
        5,   /* Slot 12 - SCSI - NCR825A */
        0,   /* Slot 13 - unused */
        3,   /* Slot 14 - enet */
        0,   /* Slot 15 - unused */
        2,   /* Slot 16 - unused */
        3,   /* Slot 17 - unused */
        5,   /* Slot 18 - unused */
        0,   /* Slot 19 - unused */
        0,   /* Slot 20 - unused */
        0,   /* Slot 21 - unused */
        0,   /* Slot 22 - unused */
};

static char Utah_pci_IRQ_routes[] __prepdata =
{
        0,   /* Line 0 - Unused */
        9,   /* Line 1 */
	10,  /* Line 2 */
        11,  /* Line 3 */
        14,  /* Line 4 */
        15,  /* Line 5 */
};

/* Motorola PowerStackII - Omaha */
/* no integrated SCSI or ethernet */
static char Omaha_pci_IRQ_map[23] __prepdata =
{
        0,   /* Slot 0  - unused */
        0,   /* Slot 1  - unused */
        3,   /* Slot 2  - Winbond EIDE */
        0,   /* Slot 3  - unused */
        0,   /* Slot 4  - unused */
        0,   /* Slot 5  - unused */
        1,   /* Slot 6  - PCI slot 1 */
        2,   /* Slot 7  - PCI slot 2  */
        3,   /* Slot 8  - PCI slot 3 */
        4,   /* Slot 9  - PCI slot 4 */ /* needs indirect access */
        0,   /* Slot 10 - unused */
        0,   /* Slot 11 - unused */
        0,   /* Slot 12 - unused */
        0,   /* Slot 13 - unused */
        0,   /* Slot 14 - unused */
        0,   /* Slot 15 - unused */
        1,   /* Slot 16  - PCI slot 1 */
        2,   /* Slot 17  - PCI slot 2  */
        3,   /* Slot 18  - PCI slot 3 */
        4,   /* Slot 19  - PCI slot 4 */ /* needs indirect access */
        0,
        0,
        0,
};

static char Omaha_pci_IRQ_routes[] __prepdata =
{
        0,   /* Line 0 - Unused */
        9,   /* Line 1 */
        11,  /* Line 2 */
        14,  /* Line 3 */
        15   /* Line 4 */
};

/* Motorola PowerStack */
static char Blackhawk_pci_IRQ_map[19] __prepdata =
{
  	0,	/* Slot 0  - unused */
  	0,	/* Slot 1  - unused */
  	0,	/* Slot 2  - unused */
  	0,	/* Slot 3  - unused */
  	0,	/* Slot 4  - unused */
  	0,	/* Slot 5  - unused */
  	0,	/* Slot 6  - unused */
  	0,	/* Slot 7  - unused */
  	0,	/* Slot 8  - unused */
  	0,	/* Slot 9  - unused */
  	0,	/* Slot 10 - unused */
  	0,	/* Slot 11 - unused */
  	3,	/* Slot 12 - SCSI */
  	0,	/* Slot 13 - unused */
  	1,	/* Slot 14 - Ethernet */
  	0,	/* Slot 15 - unused */
 	1,	/* Slot P7 */
 	2,	/* Slot P6 */
 	3,	/* Slot P5 */
};

static char Blackhawk_pci_IRQ_routes[] __prepdata =
{
   	0,	/* Line 0 - Unused */
   	9,	/* Line 1 */
   	11,	/* Line 2 */
   	15,	/* Line 3 */
   	15	/* Line 4 */
};
   
/* Motorola Mesquite */
static char Mesquite_pci_IRQ_map[23] __prepdata =
{
	0,	/* Slot 0  - unused */
	0,	/* Slot 1  - unused */
	0,	/* Slot 2  - unused */
	0,	/* Slot 3  - unused */
	0,	/* Slot 4  - unused */
	0,	/* Slot 5  - unused */
	0,	/* Slot 6  - unused */
	0,	/* Slot 7  - unused */
	0,	/* Slot 8  - unused */
	0,	/* Slot 9  - unused */
	0,	/* Slot 10 - unxued */
	0x1e,	/* Slot 11 - PCI-ISA/IDE/USB */
	0,	/* Slot 12 - unused */
	0,	/* Slot 13 - unused */
	2,	/* Slot 14 - Ethernet */
	0,	/* Slot 15 - unused */
	3,	/* Slot 16 - PMC */
	0,	/* Slot 17 - unused */
	0,	/* Slot 18 - unused */
	0,	/* Slot 19 - unused */
	0,	/* Slot 20 - unused */
	0,	/* Slot 21 - unused */
	0,	/* Slot 22 - unused */
};

/* Motorola Sitka */
static char Sitka_pci_IRQ_map[21] __prepdata =
{
	0,      /* Slot 0  - unused */
	0,      /* Slot 1  - unused */
	0,      /* Slot 2  - unused */
	0,      /* Slot 3  - unused */
	0,      /* Slot 4  - unused */
	0,      /* Slot 5  - unused */
	0,      /* Slot 6  - unused */
	0,      /* Slot 7  - unused */
	0,      /* Slot 8  - unused */
	0,      /* Slot 9  - unused */
	0,      /* Slot 10 - unxued */
	0x1e,   /* Slot 11 - PCI-ISA/IDE/USB */
	0,      /* Slot 12 - unused */
	0,      /* Slot 13 - unused */
	2,      /* Slot 14 - Ethernet */
	0,      /* Slot 15 - unused */
	9,      /* Slot 16 - PMC 1  */
	12,     /* Slot 17 - PMC 2  */
	0,      /* Slot 18 - unused */
	0,      /* Slot 19 - unused */
	4,      /* Slot 20 - NT P2P bridge */
};

/* Motorola MTX */
static char MTX_pci_IRQ_map[23] __prepdata =
{
	0,	/* Slot 0  - unused */
	0,	/* Slot 1  - unused */
	0,	/* Slot 2  - unused */
	0,	/* Slot 3  - unused */
	0,	/* Slot 4  - unused */
	0,	/* Slot 5  - unused */
	0,	/* Slot 6  - unused */
	0,	/* Slot 7  - unused */
	0,	/* Slot 8  - unused */
	0,	/* Slot 9  - unused */
	0,	/* Slot 10 - unused */
	0x1e,	/* Slot 11 - PCI-ISA/IDE/USB */
	3,	/* Slot 12 - SCSI */
	0,	/* Slot 13 - unused */
	2,	/* Slot 14 - Ethernet */
	0,	/* Slot 15 - unused */
	9,      /* Slot 16 - PCI/PMC slot 1 */
	10,     /* Slot 17 - PCI/PMC slot 2 */
	11,     /* Slot 18 - PCI slot 3 */
	0,	/* Slot 19 - unused */
	0,	/* Slot 20 - unused */
	0,	/* Slot 21 - unused */
	0,	/* Slot 22 - unused */
};

/* Motorola MTX Plus */
/* Secondary bus interrupt routing is not supported yet */
static char MTXplus_pci_IRQ_map[23] __prepdata =
{
        0,      /* Slot 0  - unused */
        0,      /* Slot 1  - unused */
        0,      /* Slot 2  - unused */
        0,      /* Slot 3  - unused */
        0,      /* Slot 4  - unused */
        0,      /* Slot 5  - unused */
        0,      /* Slot 6  - unused */
        0,      /* Slot 7  - unused */
        0,      /* Slot 8  - unused */
        0,      /* Slot 9  - unused */
        0,      /* Slot 10 - unused */
        0x1e,   /* Slot 11 - PCI-ISA/IDE/USB */
        3,      /* Slot 12 - SCSI */
        0,      /* Slot 13 - unused */
        2,      /* Slot 14 - Ethernet 1 */
        0,      /* Slot 15 - unused */
        9,      /* Slot 16 - PCI slot 1P */
        10,     /* Slot 17 - PCI slot 2P */
        11,     /* Slot 18 - PCI slot 3P */
        10,     /* Slot 19 - Ethernet 2 */
        0,      /* Slot 20 - P2P Bridge */
        0,      /* Slot 21 - unused */
        0,      /* Slot 22 - unused */
};

static char Raven_pci_IRQ_routes[] __prepdata =
{
   	0,	/* This is a dummy structure */
};
   
/* Motorola MVME16xx */
static char Genesis_pci_IRQ_map[16] __prepdata =
{
  	0,	/* Slot 0  - unused */
  	0,	/* Slot 1  - unused */
  	0,	/* Slot 2  - unused */
  	0,	/* Slot 3  - unused */
  	0,	/* Slot 4  - unused */
  	0,	/* Slot 5  - unused */
  	0,	/* Slot 6  - unused */
  	0,	/* Slot 7  - unused */
  	0,	/* Slot 8  - unused */
  	0,	/* Slot 9  - unused */
  	0,	/* Slot 10 - unused */
  	0,	/* Slot 11 - unused */
  	3,	/* Slot 12 - SCSI */
  	0,	/* Slot 13 - unused */
  	1,	/* Slot 14 - Ethernet */
  	0,	/* Slot 15 - unused */
};

static char Genesis_pci_IRQ_routes[] __prepdata =
{
   	0,	/* Line 0 - Unused */
   	10,	/* Line 1 */
   	11,	/* Line 2 */
   	14,	/* Line 3 */
   	15	/* Line 4 */
};
   
static char Genesis2_pci_IRQ_map[23] __prepdata =
{
	0,	/* Slot 0  - unused */
	0,	/* Slot 1  - unused */
	0,	/* Slot 2  - unused */
	0,	/* Slot 3  - unused */
	0,	/* Slot 4  - unused */
	0,	/* Slot 5  - unused */
	0,	/* Slot 6  - unused */
	0,	/* Slot 7  - unused */
	0,	/* Slot 8  - unused */
	0,	/* Slot 9  - unused */
	0,	/* Slot 10 - Ethernet */
	0,	/* Slot 11 - Universe PCI - VME Bridge */
	3,	/* Slot 12 - unused */
	5,	/* Slot 13 - VME */
	2,	/* Slot 14 - SCSI */
	0,	/* Slot 15 - graphics on 3600 */
	9,	/* Slot 16 - PMC */
	12,	/* Slot 17 - pci */
	11,	/* Slot 18 - pci */
	10,	/* Slot 19 - pci */
	0,	/* Slot 20 - pci */
	0,	/* Slot 21 - unused */
	0,	/* Slot 22 - unused */
};

/* Motorola Series-E */
static char Comet_pci_IRQ_map[23] __prepdata =
{
  	0,	/* Slot 0  - unused */
  	0,	/* Slot 1  - unused */
  	0,	/* Slot 2  - unused */
  	0,	/* Slot 3  - unused */
  	0,	/* Slot 4  - unused */
  	0,	/* Slot 5  - unused */
  	0,	/* Slot 6  - unused */
  	0,	/* Slot 7  - unused */
  	0,	/* Slot 8  - unused */
  	0,	/* Slot 9  - unused */
  	0,	/* Slot 10 - unused */
  	0,	/* Slot 11 - unused */
  	3,	/* Slot 12 - SCSI */
  	0,	/* Slot 13 - unused */
  	1,	/* Slot 14 - Ethernet */
  	0,	/* Slot 15 - unused */
	1,	/* Slot 16 - PCI slot 1 */
	2,	/* Slot 17 - PCI slot 2 */
	3,	/* Slot 18 - PCI slot 3 */
	4,	/* Slot 19 - PCI bridge */
	0,
	0,
	0,
};

static char Comet_pci_IRQ_routes[] __prepdata =
{
   	0,	/* Line 0 - Unused */
   	10,	/* Line 1 */
   	11,	/* Line 2 */
   	14,	/* Line 3 */
   	15	/* Line 4 */
};

/* Motorola Series-EX */
static char Comet2_pci_IRQ_map[23] __prepdata =
{
	0,	/* Slot 0  - unused */
	0,	/* Slot 1  - unused */
	3,	/* Slot 2  - SCSI - NCR825A */
	0,	/* Slot 3  - unused */
	1,	/* Slot 4  - Ethernet - DEC2104X */
	0,	/* Slot 5  - unused */
	1,	/* Slot 6  - PCI slot 1 */
	2,	/* Slot 7  - PCI slot 2 */
	3,	/* Slot 8  - PCI slot 3 */
	4,	/* Slot 9  - PCI bridge  */
	0,	/* Slot 10 - unused */
	0,	/* Slot 11 - unused */
	3,	/* Slot 12 - SCSI - NCR825A */
	0,	/* Slot 13 - unused */
	1,	/* Slot 14 - Ethernet - DEC2104X */
	0,	/* Slot 15 - unused */
	1,	/* Slot 16 - PCI slot 1 */
	2,	/* Slot 17 - PCI slot 2 */
	3,	/* Slot 18 - PCI slot 3 */
	4,	/* Slot 19 - PCI bridge */
	0,
	0,
	0,
};

static char Comet2_pci_IRQ_routes[] __prepdata =
{
	0,	/* Line 0 - Unused */
	10,	/* Line 1 */
	11,	/* Line 2 */
	14,	/* Line 3 */
	15,	/* Line 4 */
};

/*
 * ibm 830 (and 850?).
 * This is actually based on the Carolina motherboard
 * -- Cort
 */
static char ibm8xx_pci_IRQ_map[23] __prepdata = {
        0, /* Slot 0  - unused */
        0, /* Slot 1  - unused */
        0, /* Slot 2  - unused */
        0, /* Slot 3  - unused */
        0, /* Slot 4  - unused */
        0, /* Slot 5  - unused */
        0, /* Slot 6  - unused */
        0, /* Slot 7  - unused */
        0, /* Slot 8  - unused */
        0, /* Slot 9  - unused */
        0, /* Slot 10 - unused */
        0, /* Slot 11 - FireCoral */
        4, /* Slot 12 - Ethernet  PCIINTD# */
        2, /* Slot 13 - PCI Slot #2 */
        2, /* Slot 14 - S3 Video PCIINTD# */
        0, /* Slot 15 - onboard SCSI (INDI) [1] */
        3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
        0, /* Slot 17 - unused */
        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
        0, /* Slot 19 - unused */
        0, /* Slot 20 - unused */
        0, /* Slot 21 - unused */
        2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
};

static char ibm8xx_pci_IRQ_routes[] __prepdata = {
        0,      /* Line 0 - unused */
        13,     /* Line 1 */
        10,     /* Line 2 */
        15,     /* Line 3 */
        15,     /* Line 4 */
};

/*
 * a 6015 ibm board
 * -- Cort
 */
static char ibm6015_pci_IRQ_map[23] __prepdata = {
        0, /* Slot 0  - unused */
        0, /* Slot 1  - unused */
        0, /* Slot 2  - unused */
        0, /* Slot 3  - unused */
        0, /* Slot 4  - unused */
        0, /* Slot 5  - unused */
        0, /* Slot 6  - unused */
        0, /* Slot 7  - unused */
        0, /* Slot 8  - unused */
        0, /* Slot 9  - unused */
        0, /* Slot 10 - unused */
        0, /* Slot 11 -  */
        1, /* Slot 12 - SCSI */
        2, /* Slot 13 -  */
        2, /* Slot 14 -  */
        1, /* Slot 15 -  */
        1, /* Slot 16 -  */
        0, /* Slot 17 -  */
        2, /* Slot 18 -  */
        0, /* Slot 19 -  */
        0, /* Slot 20 -  */
        0, /* Slot 21 -  */
        2, /* Slot 22 -  */
};
static char ibm6015_pci_IRQ_routes[] __prepdata = {
        0,      /* Line 0 - unused */
        13,     /* Line 1 */
        10,     /* Line 2 */
        15,     /* Line 3 */
        15,     /* Line 4 */
};


/* IBM Nobis and 850 */
static char Nobis_pci_IRQ_map[23] __prepdata ={
        0, /* Slot 0  - unused */
        0, /* Slot 1  - unused */
        0, /* Slot 2  - unused */
        0, /* Slot 3  - unused */
        0, /* Slot 4  - unused */
        0, /* Slot 5  - unused */
        0, /* Slot 6  - unused */
        0, /* Slot 7  - unused */
        0, /* Slot 8  - unused */
        0, /* Slot 9  - unused */
        0, /* Slot 10 - unused */
        0, /* Slot 11 - unused */
        3, /* Slot 12 - SCSI */
        0, /* Slot 13 - unused */
        0, /* Slot 14 - unused */
        0, /* Slot 15 - unused */
};

static char Nobis_pci_IRQ_routes[] __prepdata = {
        0, /* Line 0 - Unused */
        13, /* Line 1 */
        13, /* Line 2 */
        13, /* Line 3 */
        13      /* Line 4 */
};

/* We have to turn on LEVEL mode for changed IRQ's */
/* All PCI IRQ's need to be level mode, so this should be something
 * other than hard-coded as well... IRQ's are individually mappable
 * to either edge or level.
 */
#define CAROLINA_IRQ_EDGE_MASK_LO   0x00  /* IRQ's 0-7  */
#define CAROLINA_IRQ_EDGE_MASK_HI   0xA4  /* IRQ's 8-15 [10,13,15] */

/*
 * 8259 edge/level control definitions
 */
#define ISA8259_M_ELCR 0x4d0
#define ISA8259_S_ELCR 0x4d1

#define ELCRS_INT15_LVL         0x80
#define ELCRS_INT14_LVL         0x40
#define ELCRS_INT12_LVL         0x10
#define ELCRS_INT11_LVL         0x08
#define ELCRS_INT10_LVL         0x04
#define ELCRS_INT9_LVL          0x02
#define ELCRS_INT8_LVL          0x01
#define ELCRM_INT7_LVL          0x80
#define ELCRM_INT5_LVL          0x20

#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset)
#define DEVNO(dev)  (dev>>3)                                  

__prep
int
prep_pcibios_read_config_dword (unsigned char bus,
			   unsigned char dev, unsigned char offset, unsigned int *val)
{
	unsigned long _val;                                          
	unsigned long *ptr;

	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
	{                   
		*val = 0xFFFFFFFF;
		return PCIBIOS_DEVICE_NOT_FOUND;    
	} else                                                                
	{
		ptr = (unsigned long *)CFGPTR(dev);
		_val = le32_to_cpu(*ptr);
	}
	*val = _val;
	return PCIBIOS_SUCCESSFUL;
}

__prep
int
prep_pcibios_read_config_word (unsigned char bus,
			  unsigned char dev, unsigned char offset, unsigned short *val)
{
	unsigned short _val;                                          
	unsigned short *ptr;

	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
	{                   
		*val = 0xFFFF;
		return PCIBIOS_DEVICE_NOT_FOUND;    
	} else                                                                
	{
		ptr = (unsigned short *)CFGPTR(dev);
		_val = le16_to_cpu(*ptr);
	}
	*val = _val;
	return PCIBIOS_SUCCESSFUL;
}

__prep
int
prep_pcibios_read_config_byte (unsigned char bus,
			  unsigned char dev, unsigned char offset, unsigned char *val)
{
	unsigned char _val;                                          
	unsigned char *ptr;

	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
	{                   
		*val = 0xFF;
		return PCIBIOS_DEVICE_NOT_FOUND;    
	} else                                                                
	{
		ptr = (unsigned char *)CFGPTR(dev);
		_val = *ptr;
	}
	*val = _val;
	return PCIBIOS_SUCCESSFUL;
}

__prep
int
prep_pcibios_write_config_dword (unsigned char bus,
			    unsigned char dev, unsigned char offset, unsigned int val)
{
	unsigned long _val;
	unsigned long *ptr;

	_val = le32_to_cpu(val);
	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
	{
		return PCIBIOS_DEVICE_NOT_FOUND;
	} else
	{
		ptr = (unsigned long *)CFGPTR(dev);
		*ptr = _val;
	}
	return PCIBIOS_SUCCESSFUL;
}

__prep
int
prep_pcibios_write_config_word (unsigned char bus,
			   unsigned char dev, unsigned char offset, unsigned short val)
{
	unsigned short _val;
	unsigned short *ptr;

	_val = le16_to_cpu(val);
	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
	{
		return PCIBIOS_DEVICE_NOT_FOUND;
	} else
	{
		ptr = (unsigned short *)CFGPTR(dev);
		*ptr = _val;
	}
	return PCIBIOS_SUCCESSFUL;
}

__prep
int
prep_pcibios_write_config_byte (unsigned char bus,
			   unsigned char dev, unsigned char offset, unsigned char val)
{
	unsigned char _val;
	unsigned char *ptr;

	_val = val;
	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
	{
		return PCIBIOS_DEVICE_NOT_FOUND;
	} else
	{
		ptr = (unsigned char *)CFGPTR(dev);
		*ptr = _val;
	}
	return PCIBIOS_SUCCESSFUL;
}

#define MOTOROLA_CPUTYPE_REG	0x800
#define MOTOROLA_BASETYPE_REG	0x803
#define MPIC_RAVEN_ID		0x48010000
#define	MPIC_HAWK_ID		0x48030000
#define	MOT_PROC2_BIT		0x800

static u_char mvme2600_openpic_initsenses[] __initdata = {
    1,	/* MVME2600_INT_SIO */
    0,	/* MVME2600_INT_FALCN_ECC_ERR */
    1,	/* MVME2600_INT_PCI_ETHERNET */
    1,	/* MVME2600_INT_PCI_SCSI */
    1,	/* MVME2600_INT_PCI_GRAPHICS */
    1,	/* MVME2600_INT_PCI_VME0 */
    1,	/* MVME2600_INT_PCI_VME1 */
    1,	/* MVME2600_INT_PCI_VME2 */
    1,	/* MVME2600_INT_PCI_VME3 */
    1,	/* MVME2600_INT_PCI_INTA */
    1,	/* MVME2600_INT_PCI_INTB */
    1,	/* MVME2600_INT_PCI_INTC */
    1,	/* MVME2600_INT_PCI_INTD */
    1,	/* MVME2600_INT_LM_SIG0 */
    1,	/* MVME2600_INT_LM_SIG1 */
};

#define MOT_RAVEN_PRESENT	0x1
#define MOT_HAWK_PRESENT	0x2

/* Keyboard present flag */
int prep_kbd_present = 1;   /* Keyboard present by default */

int MotMPIC = 0;
int mot_multi = 0;

__initfunc(int raven_init(void))
{
	unsigned int	devid;
	unsigned int	pci_membase;
	unsigned char	base_mod;

	/* Check to see if the Raven chip exists. */
	if ( _prep_type != _PREP_Motorola) {
		OpenPIC = NULL;
		return 0;
	}

	/* Check to see if this board is a type that might have a Raven. */
	if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
		OpenPIC = NULL;
		return 0;
	}

	/* Check the first PCI device to see if it is a Raven. */
	pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &devid);

	switch (devid & 0xffff0000) {
	case MPIC_RAVEN_ID:
		MotMPIC = MOT_RAVEN_PRESENT;
		break;
	case MPIC_HAWK_ID:
		MotMPIC = MOT_HAWK_PRESENT;
		break;
	default:
		OpenPIC = NULL;
		return 0;
	}


	/* Read the memory base register. */
	pcibios_read_config_dword(0, 0, PCI_BASE_ADDRESS_1, &pci_membase);

	if (pci_membase == 0) {
		OpenPIC = NULL;
		return 0;
	}

	/* Map the Raven MPIC registers to virtual memory. */
	OpenPIC = (struct OpenPIC *)ioremap(pci_membase+0xC0000000, 0x22000);

	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);

	ppc_md.do_IRQ = chrp_do_IRQ;
	
	/* If raven is present on Motorola store the system config register
	 * for later use.
	 */
	ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);

	/* Indicate to system if this is a multiprocessor board */
	if (!(*ProcInfo & MOT_PROC2_BIT)) {
		mot_multi = 1;
	}

	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
	 * no keyboard controller and we have to indicate that.
	 */
	base_mod = inb(MOTOROLA_BASETYPE_REG);
	if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
	    (base_mod == 0xFA) || (base_mod == 0xE1))
		prep_kbd_present = 0;

	return 1;
}

struct mot_info {
	int		cpu_type;	/* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
					/* 0x200 if this board has a Hawk chip. */
	int		base_type;
	int		max_cpu;	/* ored with 0x80 if this board should be checked for multi CPU */
	const char	*name;
	unsigned char	*map;
	unsigned char	*routes;
	void		(*map_non0_bus)(struct pci_dev *);	/* For boards with more than bus 0 devices. */
} mot_info[] = {
	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, NULL},
	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes,	NULL},
	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL},
	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes,	NULL},
	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes,	NULL},
	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes,	NULL},
	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	Mesquite_Map_Non0},
	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
	{0x000, 0x00, 0x00, "",					NULL,			NULL,	NULL}
};

__initfunc(unsigned long prep_route_pci_interrupts(void))
{
	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
	int i;
	
	if ( _prep_type == _PREP_Motorola)
	{
		unsigned short irq_mode;
		unsigned char  cpu_type;
		unsigned char  base_mod;
		int	       entry;
		int	       mot_entry = -1;

		cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
		base_mod = inb(MOTOROLA_BASETYPE_REG);

		for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
			if (mot_info[entry].cpu_type & 0x200) {		 	/* Check for Hawk chip */
				if (!(MotMPIC & MOT_HAWK_PRESENT))
					continue;
			} else {						/* Check non hawk boards */
				if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
					continue;

				if (mot_info[entry].base_type == 0) {
					mot_entry = entry;
					break;
				}

				if (mot_info[entry].base_type != base_mod)
					continue;
			}

			if (!(mot_info[entry].max_cpu & 0x80)) {
				mot_entry = entry;
				break;
			}

			/* processor 1 not present and max processor zero indicated */
			if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
				mot_entry = entry;
				break;
			}

			/* processor 1 present and max processor zero indicated */
			if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
				mot_entry = entry;
				break;
			}
		}

		if (mot_entry == -1) 	/* No particular cpu type found - assume Blackhawk */
			mot_entry = 3;

		Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
		Motherboard_map = mot_info[mot_entry].map;
		Motherboard_routes = mot_info[mot_entry].routes;
		Motherboard_non0 = mot_info[mot_entry].map_non0_bus;

		if (!(mot_info[entry].cpu_type & 0x100)) {
			/* AJF adjust level/edge control according to routes */
			irq_mode = 0;
			for (i = 1;  i <= 4;  i++)
			{
				irq_mode |= ( 1 << Motherboard_routes[i] );
			}
			outb( irq_mode & 0xff, 0x4d0 );
			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
		}
	} else if ( _prep_type == _PREP_IBM )
	{
		unsigned char pl_id;
		/*
		 * my carolina is 0xf0
		 * 6015 has 0xfc
		 * -- Cort
		 */
		printk("IBM ID: %08x\n", inb(0x0852));
		switch(inb(0x0852))
		{
		case 0xff:
			Motherboard_map_name = "IBM 850/860 Portable\n";
			Motherboard_map = Nobis_pci_IRQ_map;
			Motherboard_routes = Nobis_pci_IRQ_routes;
			break;
		case 0xfc:
			Motherboard_map_name = "IBM 6015";
			Motherboard_map = ibm6015_pci_IRQ_map;
			Motherboard_routes = ibm6015_pci_IRQ_routes;
			break;			
		default:
			Motherboard_map_name = "IBM 8xx (Carolina)";
			Motherboard_map = ibm8xx_pci_IRQ_map;
			Motherboard_routes = ibm8xx_pci_IRQ_routes;
			break;
		}

		/*printk("Changing IRQ mode\n");*/
		pl_id=inb(0x04d0);
		/*printk("Low mask is %#0x\n", pl_id);*/
		outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
		
		pl_id=inb(0x04d1);
		/*printk("Hi mask is  %#0x\n", pl_id);*/
		outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
		pl_id=inb(0x04d1);
		/*printk("Hi mask now %#0x\n", pl_id);*/
	} else if ( _prep_type == _PREP_Radstone )
	{
		unsigned char ucElcrM, ucElcrS;

		/*
		 * Set up edge/level
		 */
		switch(ucSystemType)
		{
			case RS_SYS_TYPE_PPC1:
			{
				if(ucBoardRevMaj<5)
				{
					ucElcrS=ELCRS_INT15_LVL;
				}
				else
				{
					ucElcrS=ELCRS_INT9_LVL |
					        ELCRS_INT11_LVL |
					        ELCRS_INT14_LVL |
					        ELCRS_INT15_LVL;
				}
				ucElcrM=ELCRM_INT5_LVL | ELCRM_INT7_LVL;
				break;
			}

			case RS_SYS_TYPE_PPC1a:
			{
				ucElcrS=ELCRS_INT9_LVL |
				        ELCRS_INT11_LVL |
				        ELCRS_INT14_LVL |
				        ELCRS_INT15_LVL;
				ucElcrM=ELCRM_INT5_LVL;
				break;
			}

			case RS_SYS_TYPE_PPC2:
			case RS_SYS_TYPE_PPC2a:
			case RS_SYS_TYPE_PPC2ep:
			case RS_SYS_TYPE_PPC4:
			case RS_SYS_TYPE_PPC4a:
			default:
			{
				ucElcrS=ELCRS_INT9_LVL |
				        ELCRS_INT10_LVL |
				        ELCRS_INT11_LVL |
				        ELCRS_INT14_LVL |
				        ELCRS_INT15_LVL;
				ucElcrM=ELCRM_INT5_LVL |
				        ELCRM_INT7_LVL;
				break;
			}
		}

		/*
		 * Write edge/level selection
		 */
		outb(ucElcrS, ISA8259_S_ELCR);
		outb(ucElcrM, ISA8259_M_ELCR);

		/*
		 * Radstone boards have PCI interrupts all set up
		 * so leave well alone
		 */
		return 0;
	} else
	{
		printk("No known machine pci routing!\n");
		return -1;
	}
	
	/* Set up mapping from slots */
	for (i = 1;  i <= 4;  i++)
	{
		ibc_pirq[i-1] = Motherboard_routes[i];
	}
	/* Enable PCI interrupts */
	*ibc_pcicon |= 0x20;
	return 0;
}

static unsigned int pci_localpirqs[4] =
{
	24,
	25,
	26,
	27
};

static unsigned int pci_remotepirqs[4] =
{
	28,
	29,
	30,
	31
};

static unsigned int pci_remotedev = 0xc0;

void
Mesquite_Map_Non0(struct pci_dev *pdev)
{
	struct pci_bus  *pbus;          /* Parent Bus Structure Pointer */
	unsigned int    devnum;         /* Accumulated Device Number */
	unsigned int    irq;            /* IRQ Value */

	/*
	**    Device Interrupt Line register initialization.
	**    The IRQ line number will be generated after
	**    taking into account all the PCI-2-PCI bridge
	**    devices between the device and the Host Bridge.
	*/
	devnum = PCI_SLOT(pdev->devfn);
	pbus = pdev->bus;

	while ((pbus->parent)->primary != (pbus->parent)->secondary)
	{
	    devnum += PCI_SLOT((pbus->self)->devfn);

	    pbus = pbus->parent;
	}

	devnum &= 0x03;

	/*
	**    By default, get the PCI local domain IRQ value.
	*/
	irq = pci_localpirqs[devnum];

	/*
	**    Determine if the device is located in the
	**    remote domain or not. We must find the
	**    domain's bridge device located on bus 0.
	*/
	pbus = pdev->bus;

	while (pbus->primary != 0)
	    pbus = pbus->parent;

	/*
	**    Check the device/function of domain's bridge
	**    device against the remote device/function.
	**    If the same, then the device is located in
	**    the remote domain. Thus, get the PCI remote
	**    domain IRQ value.
	*/
	if ((pbus->self)->devfn == pci_remotedev)
        irq = pci_remotepirqs[devnum];

	/*
	**    Validate the IRQ number.
	*/
	if (irq <= 255)
	{
	    /*
	    **    Set the device's Interrupt Line register
	    **    to the IRQ number and save it in the
	    **    device's structure.
	    */

	    pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, (u8)irq);

	    pdev->irq = irq;

	}
	return;
}

int motopenpic_to_irq(int n)
{
       if (n & 0xF0) {
               return (n & 0x0F);
       } else {
               return(openpic_to_irq(n));
       }
}

void prep_pib_init(void)
{
unsigned char   reg;
unsigned short  short_reg;

struct pci_dev *dev = NULL;

	if (( _prep_type == _PREP_Motorola) && (OpenPIC)) {
		/*
		 * Perform specific configuration for the Via Tech or
		 * or Winbond PCI-ISA-Bridge part.
		 */
		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, 
					PCI_DEVICE_ID_VIA_82C586_1, dev))) {
			/*
			 * PPCBUG does not set the enable bits
			 * for the IDE device. Force them on here.
			 */
			pcibios_read_config_byte(dev->bus->number, 
					dev->devfn, 0x40, &reg);

			reg |= 0x03; /* IDE: Chip Enable Bits */
			pcibios_write_config_byte(dev->bus->number, 
					dev->devfn, 0x40, reg);

		} else if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, 
					PCI_DEVICE_ID_WINBOND_83C553, dev))) {
			/*
			 * Clear the PCI Interrupt Routing Control Register.
			 */
			short_reg = 0x0000;
			pcibios_write_config_word(dev->bus->number, 
					dev->devfn, 0x44, short_reg);
		}
	}
}
__initfunc(
void
prep_pcibios_fixup(void))
{
extern unsigned char *Motherboard_map;
extern unsigned char *Motherboard_routes;
unsigned char	i;
struct pci_dev  *dev;

	if (_prep_type == _PREP_Radstone) {
		printk("Radstone boards require no PCI fixups\n");
		return;
	}

	prep_route_pci_interrupts();

	prep_pib_init();

	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);

	if (OpenPIC) {

	    /* PCI interrupts are controlled by the OpenPIC */
	    for(dev=pci_devices; dev; dev=dev->next) {
		if (dev->bus->number == 0) {
		    dev->irq = 
		       motopenpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);

		    pcibios_write_config_byte(dev->bus->number, dev->devfn, 
					      PCI_INTERRUPT_PIN, dev->irq);
		} else {
			if (Motherboard_non0 != NULL)
				Motherboard_non0(dev);
		}

	    }
	return;
	}

	for(dev=pci_devices; dev; dev=dev->next) {
		/*
		 * Use our old hard-coded kludge to figure out what
		 * irq this device uses.  This is necessary on things
		 * without residual data. -- Cort
		 */
		unsigned char d = PCI_SLOT(dev->devfn);
		dev->irq = Motherboard_routes[Motherboard_map[d]];

		for ( i = 0 ; i <= 5 ; i++ ) {
			if ( dev->base_address[i] > 0x10000000 ) {
				printk("Relocating PCI address %lx -> %lx\n",
				dev->base_address[i],
				(dev->base_address[i] & 0x00FFFFFF)|0x01000000);

				dev->base_address[i] = (dev->base_address[i] & 
							0x00FFFFFF)|0x01000000;
				pci_write_config_dword(dev, 
						PCI_BASE_ADDRESS_0+(i*0x4),
						dev->base_address[i] );
			}
		}
#if 0
	/*
	 * If we have residual data and if it knows about this
	 * device ask it what the irq is.
	 *  -- Cort
	 */
	ppcd = residual_find_device_id( ~0L, dev->device, -1,-1,-1, 0);
#endif
	}
}

decl_config_access_method(indirect);

__initfunc(
void
prep_setup_pci_ptrs(void))
{
	PPC_DEVICE *hostbridge;

        printk("PReP architecture\n");
        if ( _prep_type == _PREP_Radstone )
        {
		pci_config_address = (unsigned *)0x80000cf8;
		pci_config_data = (char *)0x80000cfc;
                set_config_access_method(indirect);		
        }
        else
        {
                hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
		       BridgeController, PCIBridge, -1, 0);
                if (hostbridge &&
                    hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
                        PnP_TAG_PACKET * pkt;
                        set_config_access_method(indirect);
                        pkt = PnP_find_large_vendor_packet(
				res->DevicePnPHeap+hostbridge->AllocatedOffset,
				3, 0);
                        if(pkt)
			{
#define p pkt->L4_Pack.L4_Data.L4_PPCPack
                                pci_config_address= (unsigned *)ld_le32((unsigned *) p.PPCData);
				pci_config_data= (unsigned char *)ld_le32((unsigned *) (p.PPCData+8));
                        }
			else
			{
                                pci_config_address= (unsigned *) 0x80000cf8;
                                pci_config_data= (unsigned char *) 0x80000cfc;
                        }
                }
		else
		{
                        set_config_access_method(prep);
                }

        }

	ppc_md.pcibios_fixup = prep_pcibios_fixup;
}

