#ifndef __ASM_MPSPEC_H
#define __ASM_MPSPEC_H

#include <device/device.h>
/*
 * Structure definitions for SMP machines following the
 * Intel Multiprocessing Specification 1.1 and 1.4.
 */

/*
 * This tag identifies where the SMP configuration
 * information is.
 */

#define SMP_MAGIC_IDENT	(('_'<<24)|('P'<<16)|('M'<<8)|'_')

/*
 * a maximum of 16 APICs with the current APIC ID architecture.
 */
#define MAX_APICS 16


#define SMP_FLOATING_TABLE_LEN sizeof(struct intel_mp_floating)

struct intel_mp_floating
{
	char mpf_signature[4];		/* "_MP_" 			*/
	unsigned long mpf_physptr;	/* Configuration table address	*/
	unsigned char mpf_length;	/* Our length (paragraphs)	*/
	unsigned char mpf_specification;/* Specification version	*/
	unsigned char mpf_checksum;	/* Checksum (makes sum 0)	*/
	unsigned char mpf_feature1;	/* Standard or configuration ? 	*/
	unsigned char mpf_feature2;	/* Bit7 set for IMCR|PIC	*/
#define MP_FEATURE_VIRTUALWIRE (1 << 7)
#define MP_FEATURE_PIC         (0 << 7)
	unsigned char mpf_feature3;	/* Unused (0)			*/
	unsigned char mpf_feature4;	/* Unused (0)			*/
	unsigned char mpf_feature5;	/* Unused (0)			*/
} __attribute__((packed));

struct mp_config_table
{
	char mpc_signature[4];
#define MPC_SIGNATURE "PCMP"
	unsigned short mpc_length;	/* Size of table */
	char  mpc_spec;			/* 0x01 */
	char  mpc_checksum;
	char  mpc_oem[8];
	char  mpc_productid[12];
	unsigned long mpc_oemptr;	/* 0 if not present */
	unsigned short mpc_oemsize;	/* 0 if not present */
	unsigned short mpc_entry_count;
	unsigned long mpc_lapic;	/* APIC address */
	unsigned short mpe_length;	/* Extended Table size */
	unsigned char mpe_checksum;	/* Extended Table checksum */
	unsigned char reserved;
} __attribute__((packed));

/* Followed by entries */

#define	MP_PROCESSOR	0
#define	MP_BUS		1
#define	MP_IOAPIC	2
#define	MP_INTSRC	3
#define	MP_LINTSRC	4

struct mpc_config_processor
{
	unsigned char mpc_type;
	unsigned char mpc_apicid;	/* Local APIC number */
	unsigned char mpc_apicver;	/* Its versions */
	unsigned char mpc_cpuflag;
#define MPC_CPU_ENABLED		1	/* Processor is available */
#define MPC_CPU_BOOTPROCESSOR	2	/* Processor is the BP */
	unsigned long mpc_cpufeature;
#define MPC_CPU_STEPPING_MASK 0x0F
#define MPC_CPU_MODEL_MASK	0xF0
#define MPC_CPU_FAMILY_MASK	0xF00
	unsigned long mpc_featureflag;	/* CPUID feature value */
	unsigned long mpc_reserved[2];
} __attribute__((packed));

struct mpc_config_bus
{
	unsigned char mpc_type;
	unsigned char mpc_busid;
	unsigned char mpc_bustype[6];
} __attribute__((packed));

#define BUSTYPE_EISA	"EISA"
#define BUSTYPE_ISA	"ISA"
#define BUSTYPE_INTERN	"INTERN"	/* Internal BUS */
#define BUSTYPE_MCA	"MCA"
#define BUSTYPE_VL	"VL"		/* Local bus */
#define BUSTYPE_PCI	"PCI"
#define BUSTYPE_PCMCIA	"PCMCIA"

struct mpc_config_ioapic
{
	unsigned char mpc_type;
	unsigned char mpc_apicid;
	unsigned char mpc_apicver;
	unsigned char mpc_flags;
#define MPC_APIC_USABLE		0x01
	unsigned long mpc_apicaddr;
} __attribute__((packed));

struct mpc_config_intsrc
{
	unsigned char mpc_type;
	unsigned char mpc_irqtype;
	unsigned short mpc_irqflag;
	unsigned char mpc_srcbus;
	unsigned char mpc_srcbusirq;
	unsigned char mpc_dstapic;
	unsigned char mpc_dstirq;
} __attribute__((packed));

enum mp_irq_source_types {
	mp_INT = 0,
	mp_NMI = 1,
	mp_SMI = 2,
	mp_ExtINT = 3
};

#define MP_IRQ_POLARITY_DEFAULT	0x0
#define MP_IRQ_POLARITY_HIGH	0x1
#define MP_IRQ_POLARITY_LOW	0x3
#define MP_IRQ_POLARITY_MASK    0x3
#define MP_IRQ_TRIGGER_DEFAULT	0x0
#define MP_IRQ_TRIGGER_EDGE	0x4
#define MP_IRQ_TRIGGER_LEVEL	0xc
#define MP_IRQ_TRIGGER_MASK     0xc


struct mpc_config_lintsrc
{
	unsigned char mpc_type;
	unsigned char mpc_irqtype;
	unsigned short mpc_irqflag;
	unsigned char mpc_srcbusid;
	unsigned char mpc_srcbusirq;
	unsigned char mpc_destapic;
#define MP_APIC_ALL	0xFF
	unsigned char mpc_destapiclint;
} __attribute__((packed));

/*
 *	Default configurations
 *
 *	1	2 CPU ISA 82489DX
 *	2	2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining
 *	3	2 CPU EISA 82489DX
 *	4	2 CPU MCA 82489DX
 *	5	2 CPU ISA+PCI
 *	6	2 CPU EISA+PCI
 *	7	2 CPU MCA+PCI
 */

#define MAX_IRQ_SOURCES 128
#define MAX_MP_BUSSES 32
enum mp_bustype {
	MP_BUS_ISA,
	MP_BUS_EISA,
	MP_BUS_PCI,
	MP_BUS_MCA
};

/* Followed by entries */

#define	MPE_SYSTEM_ADDRESS_SPACE	0x80
#define	MPE_BUS_HIERARCHY		0x81
#define	MPE_COMPATIBILITY_ADDRESS_SPACE	0x82

struct mp_exten_config {
	unsigned char mpe_type;
	unsigned char mpe_length;
} __attribute__((packed));

typedef struct mp_exten_config *mpe_t;

struct mp_exten_system_address_space {
	unsigned char mpe_type;
	unsigned char mpe_length;
	unsigned char mpe_busid;
	unsigned char mpe_address_type;
#define ADDRESS_TYPE_IO       0
#define ADDRESS_TYPE_MEM      1
#define ADDRESS_TYPE_PREFETCH 2
	unsigned int  mpe_address_base_low;
	unsigned int  mpe_address_base_high;
	unsigned int  mpe_address_length_low;
	unsigned int  mpe_address_length_high;
} __attribute__((packed));

struct mp_exten_bus_hierarchy {
	unsigned char mpe_type;
	unsigned char mpe_length;
	unsigned char mpe_busid;
	unsigned char mpe_bus_info;
#define BUS_SUBTRACTIVE_DECODE 1
	unsigned char mpe_parent_busid;
	unsigned char reserved[3];
} __attribute__((packed));

struct mp_exten_compatibility_address_space {
	unsigned char mpe_type;
	unsigned char mpe_length;
	unsigned char mpe_busid;
	unsigned char mpe_address_modifier;
#define ADDRESS_RANGE_SUBTRACT 1
#define ADDRESS_RANGE_ADD      0
	unsigned int  mpe_range_list;
#define RANGE_LIST_IO_ISA	0
	/* X100 - X3FF
	 * X500 - X7FF
	 * X900 - XBFF
	 * XD00 - XFFF
	 */
#define RANGE_LIST_IO_VGA	1
	/* X3B0 - X3BB
	 * X3C0 - X3DF
	 * X7B0 - X7BB
	 * X7C0 - X7DF
	 * XBB0 - XBBB
	 * XBC0 - XBDF
	 * XFB0 - XFBB
	 * XFC0 - XCDF
	 */
} __attribute__((packed));

/* Default local apic addr */
#define LAPIC_ADDR 0xFEE00000

void mptable_init(struct mp_config_table *mc, u32 lapic_addr);

void *smp_next_mpc_entry(struct mp_config_table *mc);
void *smp_next_mpe_entry(struct mp_config_table *mc);

void smp_write_processor(struct mp_config_table *mc,
	unsigned char apicid, unsigned char apicver,
	unsigned char cpuflag, unsigned int cpufeature,
	unsigned int featureflag);
void smp_write_processors(struct mp_config_table *mc);
void smp_write_ioapic(struct mp_config_table *mc,
	unsigned char id, unsigned char ver,
	unsigned long apicaddr);
void smp_write_intsrc(struct mp_config_table *mc,
	unsigned char irqtype, unsigned short irqflag,
	unsigned char srcbus, unsigned char srcbusirq,
	unsigned char dstapic, unsigned char dstirq);
void smp_write_intsrc_pci_bridge(struct mp_config_table *mc,
	unsigned char irqtype, unsigned short irqflag,
	struct device *dev,
	unsigned char dstapic, unsigned char *dstirq);
void smp_write_lintsrc(struct mp_config_table *mc,
	unsigned char irqtype, unsigned short irqflag,
	unsigned char srcbusid, unsigned char srcbusirq,
	unsigned char destapic, unsigned char destapiclint);
void smp_write_address_space(struct mp_config_table *mc,
	unsigned char busid, unsigned char address_type,
	unsigned int address_base_low, unsigned int address_base_high,
	unsigned int address_length_low, unsigned int address_length_high);
void smp_write_bus_hierarchy(struct mp_config_table *mc,
	unsigned char busid, unsigned char bus_info,
	unsigned char parent_busid);
void smp_write_compatibility_address_space(struct mp_config_table *mc,
	unsigned char busid, unsigned char address_modifier,
	unsigned int range_list);
unsigned char smp_compute_checksum(void *v, int len);
void *smp_write_floating_table(unsigned long addr);
void *smp_write_floating_table_physaddr(unsigned long addr,
		unsigned long mpf_physptr);
unsigned long write_smp_table(unsigned long addr);

void mptable_add_isa_interrupts(struct mp_config_table *mc, unsigned long bus_isa, unsigned long apicid, int external);
void mptable_write_buses(struct mp_config_table *mc, int *max_pci_bus, int *isa_bus);

#endif

