//****************************************************************************
//  module: ich8.c
//  notes: 
//	    0:19.0 GbE 
//          0:1A.0 UHCI4 Enabled
//          0:1A.1 UHCI5 Enabled
//          0:1A.7 EHCI2 Enabled
//          0:1B.0 HD Audio
//          0:1C.0 PCI Express Port1 (x1, or x4)
//          0:1C.1 PCI Express Port2
//          0:1C.2 PCI Express Port3
//          0:1C.3 PCI Express Port4
//          0:1C.4 PCI Express Port5
//          0:1C.5 PCI Express Port6  
//          0:1D.0 UHCI1
//          0:1D.1 UHCI2
//          0:1D.2 UHCI3
//          0:1D.7 EHCI1 
//          0:1E.0 ICH8_PTP
//          0:1F.0 ICH8_LPC
//          0:1F.2 ICH8_SATA1
//          0:1F.3 ICH8_SMBUS
//          0:1F.5 ICH8_SATA2
//          0:1F.6 ICH8_THERMAL          
//
//****************************************************************************
#include <pci.h>
#include <pci_ids.h>
#include <subr.h>
#include <delay.h>

#include <string.h>
#include <printk.h>
#include <std/io.h>

#include <legacy/rtc.h>

#include <device/device.h>
#include <device/pciide.h>
#include <device/wdc.h>

#include <std/pirq_routing.h>
//----------------------------------------------------------------------------
//#define ICH8_DBG 
#undef ICH8_DBG 

#if defined (ICH8_DBG)
  #define PRINTK_ICH8(x...) printk(x)
#else
  #define PRINTK_ICH8(x...)
#endif

//#ifdef	FG_DEBUG
extern int fg_debug_flag;
#define PRINTK_FG_DEBUG(x...) if(fg_debug_flag)printk(x)
//#else
//#define PRINTK_FG_DEBUG(x...)
//#endif

//----------------------------------------------------------------------------
#define ICH8_PTP	PCI_DEVFN(0x1E, 0)
#define ICH8_LPC	PCI_DEVFN(0x1F, 0)
#define ICH8_SMBUS	PCI_DEVFN(0x1F, 3)

#define RTC_BUS		0
#define RTC_DEVFN	ICH8_LPC
#define GEN_PMCON_3	0xA4
#define GEN_STS		0xD4

#define SMBUS_BUS	0
#define SMBUS_DEVFN	ICH8_SMBUS	

#define ICH8_STOP_SIGN_1 0
#define ICH8_STOP_SIGN_2 0xFF
#define TFTP_CHANNEL_OFFSET 61

//----------------------------------------------------------------------------
// ICH8 PCI TO PCI Bridge
const pci_cnf_t ICH8_PTP_CNF [] = {
	{ 0x04, 0xFFFFFEFF, 0x00000100 },
	{ 0x18, 0x00000000, 0X20040400 },
	{ 0x40, 0x00000000, 0x76302800 },
	{ 0x50, 0xFFFF0000, 0x00006402 },
	{ 0x70, 0xFFFFFF00, 0x00000040 },
	{ 0x80, 0xFFFFFFFF, 0x00000000 },
	{ 0x90, 0x00000000, 0x00000000 },
	{ 0xF8, 0xFFFF0000, 0x00000F66 },
	{ 0xFC, 0x0000FFFF, 0x3B4D0000 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

#define ICH8_PE1	PCI_DEVFN(0x1C, 0)
//PCIE port1
const pci_cnf_t ICH8_PE1_CNF [] = {
	{ 0x18, 0x00000000, 0X200C0700 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

#define ICH8_PE2	PCI_DEVFN(0x1C, 1)

const pci_cnf_t ICH8_PE2_CNF [] = {
	{ 0x18, 0x00000000, 0X200D0D00 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

#define ICH8_PE3	PCI_DEVFN(0x1C, 2)

const pci_cnf_t ICH8_PE3_CNF [] = {
	{ 0x18, 0x00000000, 0X200E0E00 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

#define ICH8_PE4	PCI_DEVFN(0x1C, 3)

const pci_cnf_t ICH8_PE4_CNF [] = {
	{ 0x18, 0x00000000, 0X200F0F00 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

#define ICH8_PE5	PCI_DEVFN(0x1C, 4)

const pci_cnf_t ICH8_PE5_CNF [] = {
	{ 0x18, 0x00000000, 0X20050500 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

#define ICH8_PE6	PCI_DEVFN(0x1C, 5)

const pci_cnf_t ICH8_PE6_CNF [] = {
	{ 0x18, 0x00000000, 0X20060600 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

#define ICH8_SATA	PCI_DEVFN(0x1F, 2)

//----------------------------------------------------------------------------
// ICH8 LPC Bridge
const pci_cnf_t ICH8_LPC_CNF [] = {
//	{ 0x04, 0xFFFFFEFF, 0x00000100 },
	{ 0x44, 0x00000000, 0x00000080 }, /* Enable ACPI IOPORT */
	{ 0x40, 0x00000000, 0x00004001 }, /* ACPI IOPORT */
	{ 0x48, 0x00000000, 0x00004201 }, /* GPIO IOPORT */
	{ 0x4C, 0x00000000, 0x00000010 }, /* GPIO enable */	
	{ 0x60, 0x00000000, 0x80808080 }, /* INT MAP */
	{ 0x64, 0xFFFFFF00, 0x000000D0 }, /* SIRQ */  // quiet mode will not work //
	{ 0x68, 0x00000000, 0x80808080 }, /* INT MAP */
	{ 0x80, 0x00000000, 0x3c0f0010 },  /*COMA,B LPT,FDD,KBC,MC,SIO */
	{ 0xF0, 0x00000000, 0xfed1c001 }, /* Base address */

	{ 0xA0, 0xFFFFFFDF, 0x00000020 }, /* APM Control */
	{ 0xA4, 0xFFFFFFF7, 0x00000008 },	
	{ 0xAC, 0xFFFFFCFF, 0x00000300 },	
	{ 0xB8, 0x00000000, 0x00050000 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

// ICH8 SATA Controller
const pci_cnf_t ICH8_SATA_CNF [] = {
//	{ 0x04, 0xFFFF0000, 0x00000004 },
//	{ 0x08, 0xFFFF00FF, 0x00000900 },
	{ 0x90, 0x00000000, 0x00FF0F40 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

#define ICH8_EHCI1	PCI_DEVFN(0x1D, 7)

const pci_cnf_t ICH8_EHCI1_CNF [] = {
	{ 0xFC, 0xDFFDFFFF, 0x20020000 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};
#define ICH8_EHCI2	PCI_DEVFN(0x1A, 7)

const pci_cnf_t ICH8_EHCI2_CNF [] = {
	{ 0xFC, 0xDFFDFFFF, 0x20020000 },
	{ ICH8_STOP_SIGN_1, 0x00000000, 0x00000000 },
};

//----------------------------------------------------------------------------
tag_pci_t TAG_ICH8 [] = {
  {.bus=0x00, .devfn=ICH8_PTP, .devID=0x244E, .venID=0x8086, .pci_cnf=ICH8_PTP_CNF},
  {.bus=0x00, .devfn=ICH8_PE1, .devID=0x283F, .venID=0x8086, .pci_cnf=ICH8_PE1_CNF},
  {.bus=0x00, .devfn=ICH8_PE2, .devID=0x2841, .venID=0x8086, .pci_cnf=ICH8_PE2_CNF},
  {.bus=0x00, .devfn=ICH8_PE3, .devID=0x2843, .venID=0x8086, .pci_cnf=ICH8_PE3_CNF},
  {.bus=0x00, .devfn=ICH8_PE4, .devID=0x2845, .venID=0x8086, .pci_cnf=ICH8_PE4_CNF},
  {.bus=0x00, .devfn=ICH8_PE5, .devID=0x2847, .venID=0x8086, .pci_cnf=ICH8_PE5_CNF},
  {.bus=0x00, .devfn=ICH8_PE6, .devID=0x2849, .venID=0x8086, .pci_cnf=ICH8_PE6_CNF},
  {.bus=0x00, .devfn=ICH8_LPC, .devID=0x2812, .venID=0x8086, .pci_cnf=ICH8_LPC_CNF},
  {.bus=0x00, .devfn=ICH8_LPC, .devID=0x2814, .venID=0x8086, .pci_cnf=ICH8_LPC_CNF},   //82801HDO
  {.bus=0x00, .devfn=ICH8_SATA, .devID=0x2820, .venID=0x8086, .pci_cnf=ICH8_SATA_CNF},
//  {.bus=0x00, .devfn=ICH8_EHCI1, .devID=0x2836, .venID=0x8086, .pci_cnf=ICH8_EHCI1_CNF},
//  {.bus=0x00, .devfn=ICH8_EHCI2, .devID=0x283A, .venID=0x8086, .pci_cnf=ICH8_EHCI2_CNF},
};

//----------------------------------------------------------------------------
#define RTC_FAILED  (1 <<2 )
#define SAFE_MODE   (1 <<2 )

static void ICH8_rtc_init (void)
{
	int rtc_failed = RTC_FAILED;
//	u32 dword;
	u8  byte;


	pcibios_read_config_byte (RTC_BUS, RTC_DEVFN, GEN_PMCON_3, &byte);
	rtc_failed = byte & RTC_FAILED;

	if (rtc_failed) {
		byte &= ~(1 << 1); /* preserve the power fail state */
		pcibios_write_config_byte(RTC_BUS, RTC_DEVFN, GEN_PMCON_3, byte);
	}

//	pcibios_read_config_dword(RTC_BUS, RTC_DEVFN, GEN_STS, &dword);
//	rtc_failed |= dword & SAFE_MODE;

	rtc_init(rtc_failed);
}

//----------------------------------------------------------------------------
typedef struct io_reg_s {
	u16 reg;
	u16 val;
	
} io_reg_t;

typedef struct io_reg32_s {
	u16 reg;
	u32 val;
	
} io_reg32_t;

const io_reg_t APM_set [] = {
  { 0x00, 0xFFFF },
  { 0x02, 0x0000 },
  { 0x04, 0x0000 },

  { 0x2A, 0x0000 },
  { 0x28, 0x0FFF },

  { 0x10, 0x0000 },
  { 0x12, 0x0000 },
  //{ 0x2C, 0xFFFF },
  { 0x2E, 0x0000 },
  { 0x30, 0x0000 },
  { 0x32, 0x0000 },
  { 0x34, 0xFFFF },
  { 0x36, 0xFFFF },
  { 0x40, 0x0000 },
  { 0x44, 0xFFFF },
  { 0x48, 0x0000 },

  { 0x60, 0x0004 },
  { 0x64, 0x0008 },
  { 0x66, 0x0002 },
  { 0x68, 0x0a00 },
  { 0x70, 0x0003 },

};

const io_reg32_t GPIO_set [] = {
  { 0x00, 0x195F3180 },
  { 0x04, 0xE0EA7FC3 },
  { 0x0C, 0xFAFFFDFF },
  { 0x18, 0x00000000 },
  { 0x2C, 0x00002100 },
  { 0x30, 0x000000FF },
  { 0x34, 0x00540FF0 },
  { 0x38, 0x00FC0F77 },
};

static void ICH8_APM_GPIO_Init (void) {
	u16 port;
	int i;

	pcibios_read_config_word (0, ICH8_LPC, 0x48, &port);
	port &= ~1;

	PRINTK_ICH8 ("GPIO Base Address: %04x\n", port);
	for (i = 0; i < sizeof (GPIO_set) / sizeof (io_reg32_t); i++)
	{
		PRINTK_ICH8 ("GPIO reg: %02X, val: %08X\n", GPIO_set[i].reg, GPIO_set[i].val);
		outl (GPIO_set [i].val, GPIO_set [i].reg + port);
	}

	
	pcibios_read_config_word (0, ICH8_LPC, 0x40, &port);
	port &= ~1;

	PRINTK_ICH8 ("ACPI Base Address: %04x\n", port);
	for (i = 0; i < sizeof (APM_set) / sizeof (io_reg_t); i++)
	{
		PRINTK_ICH8 ("ACPI reg: %02X, val: %04X\n", APM_set[i].reg, APM_set[i].val);
		outw (APM_set [i].val, APM_set [i].reg + port);
	}

};

struct ioapicreg {
	unsigned int reg;
	unsigned int value;
};

const unsigned long IOAPIC_BASE [] = {
 0xFEC00000, /* ICH8 internal IOAPIC */
};

/* For ISA interrupts  base address: 0xFEC00000 */
struct ioapicreg ioapic0[] = {
	{0x00, 0x08000000}, {0x02, 0x08000000},

	{0x10, 0x00010000}, {0x11, 0xFF000000},
	{0x12, 0x00010000}, {0x13, 0xFF000000},
	{0x14, 0x00010000}, {0x15, 0xFF000000},
	{0x16, 0x00010000}, {0x17, 0xFF000000},
	{0x18, 0x00010000}, {0x19, 0xFF000000},
	{0x1A, 0x00010000}, {0x1B, 0xFF000000},
	{0x1C, 0x00010000}, {0x1D, 0xFF000000},
	{0x1E, 0x00010000}, {0x1F, 0xFF000000},

	{0x20, 0x00010000}, {0x21, 0xFF000000},
	{0x22, 0x00010000}, {0x23, 0xFF000000},
	{0x24, 0x00010000}, {0x25, 0xFF000000},
	{0x26, 0x00010000}, {0x27, 0xFF000000},
	{0x28, 0x00010000}, {0x29, 0xFF000000},
	{0x2A, 0x00010000}, {0x2B, 0xFF000000},
	{0x2C, 0x00010000}, {0x2D, 0xFF000000},
	{0x2E, 0x00010000}, {0x2F, 0xFF000000},
	{0xFF, 0}
};


const unsigned long ioapicregvalues[] = {
	(unsigned long) &ioapic0[0],
};

static void ICH8_setup_ioapic(void)
{
	int i, j;
	volatile unsigned long *l;

	for (i = 0; i < sizeof(IOAPIC_BASE) / sizeof (unsigned long); i++) {
		struct ioapicreg * a = (struct ioapicreg *) ioapicregvalues[i];
		l = (unsigned long *) IOAPIC_BASE [i];

		for (j = 0; a->reg != (unsigned int) 0xFF; j++, a++) {
			*l = a->reg;
			*(l+4) = a->value;

			if ((j==0) && (*(l+4) == 0xFFFFFFFF)) {
				PRINTK_ICH8("IO APIC not responding.\n");
				return;
			}

		PRINTK_ICH8("IRQ: reg 0x%08x value %08lx %08lx\n", a->reg, *(l+4), a->value);
		}
	}

}



//----------------------------------------------------------------------------
typedef struct rsv_dev_s {
	const u8 bus;
	const u8 devfn;
	const u8 inta;    //used to build dynamic irq table; 
	const u8 intb;
	const u8 intc;
	const u8 intd;
} rsv_dev_t;

const rsv_dev_t rsv_dev [] = {
 
  { .bus = 0x00, .devfn = 0x8 }, // Q965 PCIE bridge
 
  { .bus = 0x00, .devfn = 0xc8 }, // GbE
  { .bus = 0x00, .devfn = 0xd0 }, // USB
  { .bus = 0x00, .devfn = 0xd8 }, // HD Audio
  { .bus = 0x00, .devfn = 0xe0 }, //PCIE port
  { .bus = 0x00, .devfn = 0xe8 }, // USB
  { .bus = 0x00, .devfn = 0xf8 }, // LPC, SATA

  { .bus = 0x2, .devfn = 0x8 },  //NP2
  { .bus = 0x3, .devfn = 0x8 }, //NP2
  
  { .bus = 0x4, .devfn = 0x8 }, // IDE
  { .bus = 0x4, .devfn = 0x10 }, // CP6
  { .bus = 0x4, .devfn = 0x20 }, // IDE
 
  { .bus = 0x5, .devfn = 0x0 }, // E1000
  { .bus = 0x6, .devfn = 0x0 }, // E1000

  { .bus = 0x7, .devfn = 0xff, .inta = 0x60, .intb = 0x61, .intc = 0x62, .intd = 0x63 }, // PCIE*4
  { .bus = 0x8, .devfn = 0xff, .inta = 0x60, .intb = 0x61, .intc = 0x62, .intd = 0x63 }, // PCIE*4
  { .bus = 0x9, .devfn = 0xff, .inta = 0x60, .intb = 0x61, .intc = 0x62, .intd = 0x63 }, // PCIE*4
  { .bus = 0xa, .devfn = 0xff, .inta = 0x60, .intb = 0x61, .intc = 0x62, .intd = 0x63 }, // PCIE*4
  { .bus = 0xb, .devfn = 0xff, .inta = 0x60, .intb = 0x61, .intc = 0x62, .intd = 0x63 }, // PCIE*4
  { .bus = 0xc, .devfn = 0xff, .inta = 0x60, .intb = 0x61, .intc = 0x62, .intd = 0x63 }, // PCIE*4

  { .bus = ICH8_STOP_SIGN_2, .devfn = ICH8_STOP_SIGN_2}, // STOP 
};

typedef struct irq_map_s {
	const u8 pirq;
	const u8 lirq;
} irq_map_t;

const irq_map_t irq_map [] = {
  {.pirq = 0x60, .lirq = 0x05 }, // PIRQA
  {.pirq = 0x61, .lirq = 0x0A }, // PIRQB
  {.pirq = 0x62, .lirq = 0x0B }, // PIRQC
  {.pirq = 0x63, .lirq = 0x0C }, // PIRQD

  {.pirq = 0x68, .lirq = 0x09 }, // PIRQE
  {.pirq = 0x69, .lirq = 0x80 }, // PIRQF
  {.pirq = 0x6A, .lirq = 0x80 }, // PIRQG
  {.pirq = 0x6B, .lirq = 0x09 }, // PIRQH
  {.pirq = ICH8_STOP_SIGN_2, .lirq = ICH8_STOP_SIGN_2}, // STOP 
};

struct pci_dev * first_nic_dev = NULL;
extern unsigned char g_tftp_channel;
extern unsigned char port_map[];

void add_dev_to_irq_table( struct pci_dev *dev , rsv_dev_t *r_dev)
{
	pirq_t *rt = &pirq_routing_table;
	irq_info_t *pirq_info = rt->slots;
	unsigned int index = 0;
	u8 sum;
	int i;
	u8 *addr;

	addr = (u8 *)rt;

	index = ( rt -> size - 32 ) / 16;

	rt -> size += 16;   //add one

	pirq_info[index]. bus = dev -> bus -> secondary;
	pirq_info[index]. devfn = dev -> devfn;
	pirq_info[index]. slot = 0;
	pirq_info[index]. rfu = 0;
	pirq_info[index]. irq[0].link = r_dev -> inta;
	pirq_info[index]. irq[1].link = r_dev -> intb;
	pirq_info[index]. irq[2].link = r_dev -> intc;
	pirq_info[index]. irq[3].link = r_dev -> intd;
	pirq_info[index]. irq[0].bitmap = 0xdcf8;;
	pirq_info[index]. irq[1].bitmap = 0xdcf8;
	pirq_info[index]. irq[2].bitmap = 0xdcf8;
	pirq_info[index]. irq[3].bitmap = 0xdcf8;
//recaculate checksum;

	for (i = 0, sum = 0; i < rt->size; i++)
		sum += addr [i];
	rt -> checksum = 0xff - sum + 1 + rt -> checksum;

	return;

}

void pci_alloc_irq (struct pci_dev *dev)
{
        const pirq_t *rt = &pirq_routing_table;

	u8 rtr_bus  = rt->rtr_bus;
	u8 rtr_devfn= rt->rtr_devfn;
	u8 pin = 0;

	irq_info_t *pirq_info = rt->slots;

	static int nic_cnt = 0;
	u16 IO4Dx = 0;
	u8  Trigger = 0;

	int i = 0;
	//--------------------------------------------------------------------
	// Check If The Device Need To Be Programmed

	while ((rsv_dev [i].bus   != dev->bus->secondary) ||
	       ((rsv_dev [i].devfn != (dev->devfn & 0xF8)) && ( rsv_dev [i].devfn != 0xff ) )) {
		if ((rsv_dev [i].bus   == ICH8_STOP_SIGN_2) &&
		    (rsv_dev [i].devfn == ICH8_STOP_SIGN_2)) {
			PRINTK_ICH8 ("\n%02x=%02x:%02x=%02x.%02x=%02x Not Reserved Device(%04x %04x)\n",
				rsv_dev[i].bus,
				dev->bus->secondary,
				PCI_SLOT(rsv_dev[i].devfn),
				PCI_SLOT(dev->devfn),
				PCI_FUNC(rsv_dev[i].devfn),
				PCI_FUNC(dev->devfn),
				dev->vendor,
				dev->device);
			return;
		}

		i++;
	}

//put a new device list in PIRQ table;(f0000 segment must be shadowed)
	if( (rsv_dev [i].bus == dev->bus->secondary) && ( rsv_dev[i].devfn == 0xff ) && ( PCI_FUNC(dev->devfn) == 0) )
	{
//printk("PCI_DEV: %x:%x.%x\n", dev->bus->secondary, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
		add_dev_to_irq_table( dev , (rsv_dev_t *)&rsv_dev[i]);
	}

	//--------------------------------------------------------------------
	// Slot In PIRQ Table
	for (i = 0; ; i++) {
		if ((dev->bus->secondary == pirq_info->bus) &&
			((dev->devfn & 0xF8) == pirq_info->devfn))
			break;

		pirq_info++;

  		if (i >= (rt->size - 32) >> 4) {
			PRINTK_ICH8 ("%02x:%02x.%02x Not Existed In Int. Table\n",
				dev->bus->secondary,
				PCI_SLOT(dev->devfn),
				PCI_FUNC(dev->devfn));
			return;
		}
	}


	pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &pin);
	if (pin < 1 || pin > 4)
		pci_write_config_byte (dev, PCI_INTERRUPT_PIN, 1);

	pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &pin);
	if (pin < 1 || pin > 4) {
		PRINTK_ICH8 ("PCI INT PIN(%02x:%02x.%02x) Is Invalid %02x\n",
			dev->bus->secondary,
			PCI_SLOT(dev->devfn),
			PCI_FUNC(dev->devfn),
			pin);
		return;
	}

	PRINTK_ICH8 ("PCI INT PIN(%02x:%02x.%02x) Is %02x\n",
		dev->bus->secondary,
		PCI_SLOT(dev->devfn),
		PCI_FUNC(dev->devfn),
		pin);
	//--------------------------------------------------------------------
	/* NIC irq */
	i = 0;
	while (pirq_info->irq [pin-1].link != irq_map [i].pirq) {
		if (irq_map [i].pirq == ICH8_STOP_SIGN_2) {
			PRINTK_ICH8 ("Not An Valid INT Link (%02x)\n",
				pirq_info->irq [pin-1].link);
			return;
		}
	
		i++;
	}

	dev->irq = irq_map [i].lirq;
	pci_write_config_byte (dev, PCI_INTERRUPT_LINE, dev->irq);

	pcibios_write_config_byte (rtr_bus, rtr_devfn, irq_map [i].pirq,
		irq_map [i].lirq);	

	IO4Dx = (irq_map [i].lirq >= 8) ? 0x4D1 : 0x4D0;
	Trigger = inb (IO4Dx) | (1 << (irq_map [i].lirq - 8 * (IO4Dx - 0x4D0)));
	outb (Trigger, IO4Dx);

	//--------------------------------------------------------------------
#ifdef INCLUDE_EEPRO1000
	if (0x1010 == dev->device || 0x1012 == dev->device ||
	    0x100C == dev->device || 0x100D == dev->device ||
	    0x1008 == dev->device || 0x1009 == dev->device || 
	    0x100E == dev->device || 0x1079 == dev->device ||
	    0x109A == dev->device )
	{
		if ((nic_cnt == g_tftp_channel) && (first_nic_dev == NULL))
			first_nic_dev = dev;

			nic_cnt++;
	}
#elif defined(INCLUDE_BCM5700)
	if (dev->device == 0x1644 || dev->device == 0x1645 
	   || dev->device == 0x1646 || dev->device == 0x1647
	   || dev->device == 0x1648 || dev->device == 0x164d 
	   || dev->device == 0x16a6 || dev->device == 0x16a7
	   || dev->device == 0x16a8 || dev->device == 0x16c6 || dev->device == 0x16c7
	   || dev->device == 0x4400 || dev->device == 0x03e8 || dev->device == 0x03ea 
	   || dev->device == 0x1668 || dev->device == 0x1659 ) {
		if ((nic_cnt == g_tftp_channel) && (first_nic_dev == NULL))
			first_nic_dev = dev;

			nic_cnt++;
	}

#else
	if (0x2449 == dev->device || 0x1209 == dev->device ||
	    0x1229 == dev->device) {
		if ((nic_cnt == g_tftp_channel) && (first_nic_dev == NULL))
			first_nic_dev = dev;

			nic_cnt++;
	}
#endif
}

#ifdef MAX_DOWNLOAD_PORT
#else
	#define MAX_DOWNLOAD_PORT TFTPCH + 1
#endif

//----------------------------------------------------------------------------
void SB_ICH8_Init (void)
{
        int i;
//	unsigned char val8;

	//--------------------------------------------------------------------
	// Download Default Setting To All PCI Devices On ICH4
	for (i = 0; i < sizeof (TAG_ICH8)/sizeof(tag_pci_t); i++) {
		int j;
		u32 val32;
		const pci_cnf_t * pci_cnf = TAG_ICH8 [i].pci_cnf;
		u8 bus    = TAG_ICH8 [i].bus;
		u8 devfn  = TAG_ICH8 [i].devfn;

		pcibios_read_config_dword (bus, devfn, PCI_VENDOR_ID, &val32);
		if (val32 != ((TAG_ICH8 [i].devID << 16) | (TAG_ICH8 [i].venID))) {
			PRINTK_ICH8 ("B(%02X):D(%02X).F(%02X) on ICH8 Wished.\n",
				bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
			continue;
		}

		for (j = 0; pci_cnf [j].reg != ICH8_STOP_SIGN_1; j++) {
			pcibios_read_config_dword (bus, devfn, pci_cnf [j].reg, &val32);
			val32 &= pci_cnf [j].MAND;
			val32 |= pci_cnf [j].MOR;
			PRINTK_ICH8 ("B(%02X):D(%02X).F(%02X), reg:%02X, val:%08X\n",
				bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pci_cnf [j].reg, val32);
			pcibios_write_config_dword (bus, devfn, pci_cnf [j].reg, val32);
		}
	}
	
// Enable IOapic
	//
	//
	*(unsigned int *)0xFED1C088 = 0x00109000;
	*(unsigned int *)0xFED1C1F4 = 0x86000040;
	*(unsigned short *)0xFED1C1FC = 0x060b;
	*(unsigned short *)0xFED1C200 = 0x2008;
	*(unsigned short *)0xFED1C220 = 0x45;
	*(unsigned char *)0xFED1DD40 = 0x1;
	*(unsigned int *)0xFED1E024 = 0x0b603000;
	*(unsigned int *)0xFED1E034 = 0xb2b577cc;
	*(unsigned int *)0xFED1F418 = 0x03000000;  //disable SATA2, thermal
	*(unsigned char *)0xFED1F430 = 0x3;
	*(unsigned int *)0xFED1F50C = 0x08000000;
	*(unsigned int *)0xFED1F52C = 0x00020000;

	*(unsigned char *)0xFED1F1FF = 1;

//	*(unsigned int *)0xFED1F10C = 0x00214324;   //PCIE port 1 use INTD, for debug
//	*(unsigned short *)0xFED1F146 = 0x3333;   //PCIE port route to INTD , for debug

//	*(unsigned short *)0xFED1F14C = 0x4250;
//	*(unsigned short *)0xFED1F144 = 0x0237;
//	*(unsigned short *)0xFED1F144 = 0x3213;

		       	
	pcibios_write_config_dword (0, ICH8_EHCI1, 0xFC, 0x20021706 );
	pcibios_write_config_dword (0, ICH8_EHCI2, 0xFC, 0x20021706 );

	//--------------------------------------------------------------------
	// RTC Power Check
	ICH8_APM_GPIO_Init ();
	ICH8_rtc_init ();
	//--------------------------------------------------------------------
	/* get tftp channel */
	outb (TFTP_CHANNEL_OFFSET, 0x70); 
	g_tftp_channel = inb ( 0x71 );
	for( i = 0; i < MAX_DOWNLOAD_PORT; i ++ )
	{
		if( ( port_map[i] | 0x80 ) == g_tftp_channel )
			break;
	}
	if( i == MAX_DOWNLOAD_PORT )
	{
		g_tftp_channel = TFTPCH;
		outb (TFTP_CHANNEL_OFFSET, 0x70); 
		outb ( TFTPCH, 0x71 );
	}
	else
		g_tftp_channel &= 0x7F;

};

void ICH8_SATA_Init( void )
{
	unsigned int val32;

	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0x40 );
	pcibios_write_config_byte(0, ICH8_SATA, 0xa6, 0x22 );
	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0x78 );
	pcibios_write_config_byte(0, ICH8_SATA, 0xa6, 0x22 );
	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0x94 );
	pcibios_write_config_byte(0, ICH8_SATA, 0xa4, 0x22 );
	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0x88 );

	pcibios_read_config_dword(0, ICH8_SATA, 0xa4, &val32 );
	val32 &= 0xc0c0c0c0;
	val32 |= 0x24242424;
	pcibios_write_config_dword(0, ICH8_SATA, 0xa4, val32 );

	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0x8c );

	pcibios_read_config_dword(0, ICH8_SATA, 0xa4, &val32 );
	val32 &= 0xc0c0ff00;
	val32 |= 0x090900aa;
	pcibios_write_config_dword(0, ICH8_SATA, 0xa4, val32 );

	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0xa8 );

	pcibios_read_config_dword(0, ICH8_SATA, 0xa4, &val32 );
	val32 &= 0xffc0ffc0;
	val32 |= 0x00240024;
	pcibios_write_config_dword(0, ICH8_SATA, 0xa4, val32 );

	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0xac );

	pcibios_read_config_dword(0, ICH8_SATA, 0xa4, &val32 );
	val32 &= 0xffc0fff0;
	val32 |= 0x0009000a;
	pcibios_write_config_dword(0, ICH8_SATA, 0xa4, val32 );

	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0x18 );

	pcibios_read_config_dword(0, ICH8_SATA, 0xa4, &val32 );
	val32 &= 0xfffffe00;
	val32 |= 0x0000001b;
	pcibios_write_config_dword(0, ICH8_SATA, 0xa4, val32 );

	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0x28 );

	pcibios_read_config_dword(0, ICH8_SATA, 0xa4, &val32 );
	val32 |= 0x000c0000;
	pcibios_write_config_dword(0, ICH8_SATA, 0xa4, val32 );

	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0x84 );

	pcibios_read_config_dword(0, ICH8_SATA, 0xa4, &val32 );
	val32 &= 0xffffffc0;
	val32 |= 0x0000001b;
	pcibios_write_config_dword(0, ICH8_SATA, 0xa4, val32 );

	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0xa0 );

	pcibios_read_config_dword(0, ICH8_SATA, 0xa4, &val32 );
	val32 &= 0xffffffc0;
	val32 |= 0x0000001b;
	pcibios_write_config_dword(0, ICH8_SATA, 0xa4, val32 );

	pcibios_write_config_byte(0, ICH8_SATA, 0xa0, 0x00 );

}


#define IT8213_BUS  	0x4
#define IT8213_SEC_BUS 	0x4
#define IT8213_SEC_DEVFN 	(0x4 << 3 )
#define IT8213_DEVFN 	(0x1 << 3 )

void SB_ICH8_Finishup(void)
{
	void cpu_thermal (void);
	int IT8213_IDE_Init( unsigned int bus, unsigned int devfn );
	// Must Be Set After PCI Resource Allocated
	PRINTK_FG_DEBUG("Start to initialize IDE device.\n");
//	ICH8_IDE_Init ();
	//
	//
/*
	{
		int bus, devfn;
		unsigned int value;
		unsigned char hdr_type;

						for( bus = 0 ; bus < 0x2f ; bus ++ )
						{
							for( devfn = 0 ; devfn < 0xff ; devfn ++ )
							{
								value = 0;
								hdr_type = 0;
								pcibios_read_config_dword( bus , devfn , PCI_VENDOR_ID , &value);
								if( value != 0xffffffff && value != 0x00000000 
										&& value != 0x0000ffff && value != 0xffff0000)
								{
									printk("%02x:%02x.%02x %04x:%04x\n" , bus , PCI_SLOT( devfn ) ,
										       	PCI_FUNC( devfn ),
											value & 0xffff,
											( value >> 16 ) & 0xffff
											);
									pcibios_read_config_byte( bus , devfn , PCI_HEADER_TYPE , &hdr_type );
									if( PCI_FUNC( devfn ) == 0  && ( hdr_type & 0x80 ) != 0x80 )
										devfn += 7;
								}
							}
						}

	}
*/
#if defined(IT8213_IDE)
	if( IT8213_IDE_Init( IT8213_BUS, IT8213_DEVFN ) != 0 )
		IT8213_IDE_Init( IT8213_SEC_BUS, IT8213_SEC_DEVFN );
#endif

	ICH8_setup_ioapic();

	ICH8_SATA_Init();
#if 0
	cpu_thermal ();
#endif
}
//----------------------------------------------------------------------------
