Index: via/cn400/Config.lb
===================================================================
--- via/cn400/Config.lb	(revision 1)
+++ via/cn400/Config.lb	(working copy)
@@ -19,6 +19,7 @@
 ##
 
 uses CONFIG_HAVE_HIGH_TABLES
+uses CONFIG_IOAPIC
 
 config chip.h
 
@@ -27,5 +28,6 @@
 driver northbridge.o
 driver agp.o
 driver vga.o
+driver vlink.o
 
 default CONFIG_HAVE_HIGH_TABLES=1
Index: via/cn400/raminit.c
===================================================================
--- via/cn400/raminit.c	(revision 1)
+++ via/cn400/raminit.c	(working copy)
@@ -1,5 +1,6 @@
 /*
  * (C) Copyright 2005 Nick Barker <nick.barker9@btinternet.com>
+ * (C) Copyright 2009 Jon Harrison <bothlyn@blueyonder.co.uk
  *
  *
  * This program is free software; you can redistribute it and/or
@@ -19,16 +20,13 @@
  */
 
 /* 
-  Automatically detect and set up ddr dram on the CLE266 chipset.
-  Assumes DDR memory, though chipset also supports SDRAM
-  Assumes at least 266Mhz memory as no attempt is made to clock
+  Automatically detect and set up ddr dram on the CN400 chipset.
+  Assumes DDR400 memory as no attempt is made to clock
   the chipset down if slower memory is installed.
   So far tested on:
-	256 Mb 266Mhz 1 Bank (i.e. single sided)
-	256 Mb 266Mhz 2 Bank (i.e. double sided)
-	512 Mb 266Mhz 2 Bank (i.e. double sided)
+	512 Mb DDR400 4 Bank / 2 Rank (1GB) (i.e. double sided)
 */
-/* ported and enhanced from assembler level code in coreboot v1 */
+/* ported from Via VT8263 Code*/
 
 #include <spd.h>
 #include <sdram_mode.h>
@@ -68,6 +66,7 @@
 {
 	/* Host bus interface registers (D0F2 0x50-0x67) */
 	/* Taken from CN700 and updated from running CN400 */
+	uint8_t reg8;
 	
 	/* Host Bus I/O Circuit (see datasheet) */
 	/* Host Address Pullup/down Driving */
@@ -87,6 +86,7 @@
 	
 	/* AGTL+ Auto Compensation Offest */
 	pci_write_config8(dev, 0x77, 0x00);
+	pci_write_config8(dev, 0x78, 0x94);
 	
 	/* Request phase control */
 	pci_write_config8(dev, 0x50, 0xA8);
@@ -135,7 +135,13 @@
 	
 	/* CPU Miscellaneous Control */
 	pci_write_config8(dev, 0x55, 0x28);
+	pci_write_config8(dev, 0x57, 0x69);
 	
+	/* CPU Host Bus Final Setup */	
+	reg8 = pci_read_config8(dev, 0x54);
+	reg8 |= 0x08;
+	pci_write_config8(dev, 0x54, reg8);
+	
 }
  
 static void ddr_ram_setup(void) 
@@ -177,7 +183,7 @@
 		/*
     		Read SPD byte 3, Number of row addresses.
 		*/
-		c = 0;
+		c = 0x01;
 		bank = 0x40;
 		b = smbus_read_byte(0x50, SPD_NUM_ROWS);
 		//print_val("\r\nNumber of Rows ", b);
@@ -195,7 +201,7 @@
 			b = smbus_read_byte(0x50, SPD_PRIMARY_SDRAM_WIDTH);
 			//print_val("\r\nPrimary DRAM width", b);
 			if( b != 4 )   // not 64/128Mb (x4)
-				c = 0x80;  // 256Mb
+				c = 0x81;  // 256Mb
 		}
 
 		/*
@@ -211,6 +217,10 @@
 		pci_write_config8(ctrl.d0f3, 0x50, c);
 
 	}
+	
+	/* Disable Upper Banks */
+	pci_write_config8(ctrl.d0f3, 0x51, 0x00);
+	
 /*	else
 	{
 		die("DRAM module size is not supported by CN400\r\n");
@@ -265,8 +275,6 @@
 	else if( b & 0x08) c = 0x01;    	// 32MB
 	else c = 0x01;                  	// Error, use default
 
-	//print_val("\r\nBank 0 (*32 Mb) ",c);
-
 	// set bank zero size
 	pci_write_config8(ctrl.d0f3, 0x40, c);
 	
@@ -278,7 +286,6 @@
 	{
 		c <<=1;
 		bank |= 0x80;
-		//print_val("\r\nTotal Memory (*32 Mb) ",c);
 	}
 /*	else
 	{
@@ -294,6 +301,10 @@
 	pci_write_config8(ctrl.d0f3, 0x46,c);
 	pci_write_config8(ctrl.d0f3, 0x47,c);
 	
+	/* Top Rank Address Mirrored to the South Bridge */
+	/* over the VLink								 */
+	pci_write_config8(ctrl.d0f7, 0x57, (c << 1));
+	
 	ma = bank;
 		
 	/* Read SPD byte 18 CAS Latency */
@@ -313,13 +324,11 @@
 	c = smbus_read_byte(0x50, SPD_SDRAM_CYCLE_TIME_3RD);
 	print_val("\r\nCycle time at CL X-1   (nS)", c);
 */	
+	/* Scaling of Cycle Time SPD data */
+	/* 7      4 3       0             */
+	/*    ns     x0.1ns               */
 	bank = smbus_read_byte(0x50, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
 
-	/* Setup DRAM Cycle Time */
-	if ( bank <= 0x50 ) bank = 0x14;
-	else if (bank <= 0x60) bank = 0x18;
-	else bank = 0x1E;
-		
 	if( b & 0x10 ){             // DDR offering optional CAS 3
 		//print_debug("\r\nStarting at CAS 3");
 		c = 0x30;
@@ -347,6 +356,13 @@
 		}
 	}	
 
+	/* Scale DRAM Cycle Time to tRP/tRCD */
+	/* 7      2 1       0             */
+	/*    ns     x0.25ns               */
+	if ( bank <= 0x50 ) bank = 0x14;
+	else if (bank <= 0x60) bank = 0x18;
+	else bank = 0x1E;
+		
 /*
     DRAM Timing  Device 0  Fn 3 Offset 56
 
@@ -401,8 +417,12 @@
     Read SPD byte 30, device min active to pre-charge time.
 */
 
+	/* tRAS is in whole ns */
+	bank = bank >> 2;
+	
 	b = smbus_read_byte(0x50, SPD_MIN_ACTIVE_TO_PRECHARGE_DELAY);
 	//print_val("\r\ntRAS ",b);
+	//print_val("\r\nBank ", bank);
 	if ( b >= (9 * bank)) c |= 0xC0;		// set tRAS = 9T
 	else if ( b >= (8 * bank)) c |= 0x80;	// set tRAS = 8T
 	else if ( b >= (7 * bank)) c |= 0x40;	// set tRAS = 7T
@@ -457,15 +477,20 @@
 	/* 4-Way Interleave With Multi-Paging (From Running System)*/
 	pci_write_config8(ctrl.d0f3, 0x69, c);
 	
+	/*DRAM Controller Internal Options */
+	pci_write_config8(ctrl.d0f3, 0x54, 0x01);
+	
 	/* DRAM Arbitration Control */
 	pci_write_config8(ctrl.d0f3, 0x66, 0x82);
 
 	/* DRAM Control */
-	pci_write_config8(ctrl.d0f3, 0x6e, 0x00);
+	pci_write_config8(ctrl.d0f3, 0x6e, 0x80);
 	
 	/* Disable refresh for now */
 	pci_write_config8(ctrl.d0f3, 0x6a, 0x00);
 
+	/* DDR Clock Gen Duty Cycle Control */
+	pci_write_config8(ctrl.d0f3, 0xEE, 0x01);		
 
 
 	/* DRAM Clock Control */
@@ -484,8 +509,9 @@
 	pci_write_config8(ctrl.d0f3, 0xe4, 0x99);
 
 	/* DRAM signal timing control */
-	pci_write_config8(ctrl.d0f3, 0x74, 0x99);	
+	pci_write_config8(ctrl.d0f3, 0x74, 0x99);
 	pci_write_config8(ctrl.d0f3, 0x76, 0x09);
+	pci_write_config8(ctrl.d0f3, 0x77, 0x12);	
 
 	pci_write_config8(ctrl.d0f3, 0xe0, 0xAA);
 	pci_write_config8(ctrl.d0f3, 0xe1, 0x00);
@@ -500,6 +526,9 @@
 
 	pci_write_config8(ctrl.d0f3, 0xb0, c);
 	
+	/* Set RAM Decode method */
+	pci_write_config8(ctrl.d0f3, 0x55, 0x0a);
+	
 	/* Enable DIMM Ranks */
 	pci_write_config8(ctrl.d0f3, 0x48, ma);
 	udelay(200);
@@ -528,7 +557,7 @@
 		i = 0x008; 		// Used later to set SDRAM MSR
 	}
 
-		
+	
 	for( bank = 0 , bank_address=0; bank <= b ; bank++) {
 /*
     DDR init described in Via VT8623 BIOS Porting Guide.  Pg 28 (4.2.3.1)
@@ -641,6 +670,9 @@
 	pci_write_config8(ctrl.d0f3, 0x7A, 0xA1);
 	pci_write_config8(ctrl.d0f3, 0x7B, 0x62);	
 
+	/* DQS Duty Cycle Control */
+	pci_write_config8(ctrl.d0f3, 0xED, 0x11);
+	
 	/* SPD byte 5  # of physical banks */
 	b = smbus_read_byte(0x50, SPD_NUM_DIMM_BANKS) -1;
 	
@@ -650,7 +682,7 @@
 	else
 		bank_address = 0;
 
-	for(i = 0x40 ; i < 0x0ff; i++){
+	for(i = 0x30 ; i < 0x0ff; i++){
 		pci_write_config8(ctrl.d0f3,0x70,i);
 		// clear
 		*(volatile unsigned long*)(0x4000) = 0;
@@ -741,13 +773,15 @@
 		pci_write_config8(ctrl.d0f3,0x70,0x67);
 	}
 
-	/* Set DQS ChB Output to the default */
-	pci_write_config8(ctrl.d0f3, 0x71, 0x6c);
+	/* Set DQS ChA Data Output Delay to the default */
+	pci_write_config8(ctrl.d0f3, 0x71, 0x65);
 	
-	/* Set DQS Input Delays */
-	pci_write_config8(ctrl.d0f3, 0x72, 0x29);
-	pci_write_config8(ctrl.d0f3, 0x73, 0x99);	
+	/* Set Ch B DQS Output Delays */
+	pci_write_config8(ctrl.d0f3, 0x72, 0x2a);
+	pci_write_config8(ctrl.d0f3, 0x73, 0x29);	
 	
+	pci_write_config8(ctrl.d0f3, 0x78, 0x03);
+
 	/* Mystery Value */
 	pci_write_config8(ctrl.d0f3, 0x67, 0x50);
 	
@@ -765,14 +799,14 @@
 	//b = smbus_read_byte(0x50, SPD_REFRESH);
 	//print_val("SPD_REFRESH = ", b);
 
-	pci_write_config8(ctrl.d0f3,0x6a,0x6C);
+	pci_write_config8(ctrl.d0f3,0x6a,0x65);
 	
+	/* SMM and APIC decoding, we do not use SMM */
+	b = 0x29;
+	pci_write_config8(ctrl.d0f3, 0x86, b);
+	/* SMM and APIC decoding mirror */
+	pci_write_config8(ctrl.d0f7, 0xe6, b);
 	
-	/* Enable TLB Auto refresh */
-	b = pci_read_config8(ctrl.d0f3, 0x69);
-	b |= 0x10;
-	pci_write_config8(ctrl.d0f3, 0x69, b);
-
 	/* Open Up the Rest of the Shadow RAM */
 	pci_write_config8(ctrl.d0f3,0x80,0xff);
 	pci_write_config8(ctrl.d0f3,0x81,0xff);
@@ -784,26 +818,9 @@
 
 	pci_write_config8(ctrl.d0f7,0x71,0xc8);
 	
-    print_debug("CN400 Init done\r\n");
 
 	/* VGA device. */
 	pci_write_config16(ctrl.d0f3, 0xa0, (1 << 15));
 	pci_write_config16(ctrl.d0f3, 0xa4, 0x0010);
-	
-	/* Graphics Control Basic Init. */
-	//pci_write_config8(ctrl.d0f3, 0xb0, 0xFf);
-	//pci_write_config8(ctrl.d0f3, 0xb1, 0xAA);
-	//pci_write_config8(ctrl.d0f3, 0xb2, 0xAA);
-	//pci_write_config8(ctrl.d0f3, 0xb3, 0x5A);
-	//pci_write_config8(ctrl.d0f3, 0xb4, 0x0f);
-	
-	/* AGP Controller Interface Basic Init */
-	//pci_write_config8(ctrl.d0f3, 0xc0, 0x3b);
-	
-	/* VGA device, Basic frame Buffer Init. */
-	//pci_write_config8(ctrl.d0f3, 0xa0, 0x01);
-	/* Bit 7 = Enable VGA When Set to 1 */
-	//pci_write_config8(ctrl.d0f3, 0xa1, 0xef);
-	//pci_write_config8(ctrl.d0f3, 0xa4, 0x00);
-
+    print_debug("CN400 raminit.c done\r\n");	
 }	
Index: via/cn400/vlink.c
===================================================================
--- via/cn400/vlink.c	(revision 0)
+++ via/cn400/vlink.c	(revision 0)
@@ -0,0 +1,246 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 Jon Harrison <bothlyn@blueyonder.co.uk>
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include "chip.h"
+#include "northbridge.h"
+#include "cn400.h"
+
+static void noop_1k(u32 knops)
+{
+	u32 i;
+
+	for (i = 0; i < 1024 * knops; i++) {
+		__asm__ volatile ("nop\n\t");
+	}
+
+	return;
+}
+
+/* Vlink Performance Improvements */
+static void vlink_init(device_t dev)
+{
+	u8 reg, reg8;
+	int i, j;
+	
+	printk_spew("Entering CN400 %s\n", __func__);
+		
+	/* Disconnect the VLink Before Changing Settings */
+	reg = pci_read_config8(dev, 0x47);
+	reg |= 0x04;
+	pci_write_config8(dev, 0x47, reg);
+	
+	/* Wait for anything pending to flush */
+	noop_1k(20);
+	
+	/* Setup Vlink Mode 1 */
+	pci_write_config8(dev, 0x4F, 0x01);
+	pci_write_config8(dev, 0x48, 0x13);
+	
+	/* PCI Buffer Control */
+	pci_write_config8(dev, 0x70, 0x82);
+	
+	/* CPU to PCI Flow Control */
+	pci_write_config8(dev, 0x71, 0xc8);
+	pci_write_config8(dev, 0x72, 0xee);
+
+	/* PCI Master Control */
+	pci_write_config8(dev, 0x73, 0x01);	
+	pci_write_config8(dev, 0x74, 0x20);
+
+	/* PCI Arbitration 1 */
+	pci_write_config8(dev, 0x75, 0x0f);
+	
+	/* PCI Arbitration 2 */
+	pci_write_config8(dev, 0x76, 0x50);
+	pci_write_config8(dev, 0x77, 0x6e);
+	pci_write_config8(dev, 0x7F, 0x10);
+	
+	pci_write_config8(dev, 0x94, 0x20);
+	pci_write_config8(dev, 0x95, 0x0f);
+	
+	/* V-Link CKG Control 1 */
+	pci_write_config8(dev, 0xB0, 0x01);
+	
+	/* V-Link NB Compensation Control */
+	pci_write_config8(dev, 0xB5, 0x46);
+	pci_write_config8(dev, 0xB6, 0x68);
+	reg = pci_read_config8(dev, 0xB4);
+	reg |= 0x01;
+	pci_write_config8(dev, 0xB4, reg);
+
+	/* V-Link NB Receive Strobe Delay */
+	pci_write_config8(dev, 0xB7, 0x02);	
+	
+	/* V-Link SB Compensation Control */
+	pci_write_config8(dev, 0xB9, 0x84);
+	reg = pci_read_config8(dev, 0xB8);
+	reg |= 0x01;
+	pci_write_config8(dev, 0xB8, reg);	
+	
+	pci_write_config8(dev, 0xBA, 0x6a);
+	pci_write_config8(dev, 0xBB, 0x01);
+
+#ifdef DEBUG_CN400	
+	/* Reconnect the VLink Before Continuing*/
+	reg = pci_read_config8(dev, 0x47);
+	reg &= ~0x04;
+	pci_write_config8(dev, 0x47, reg);
+	
+	printk_spew("%s PCI Header Regs::\n", dev_path(dev));
+	 
+	for (i = 0 ; i < 16; i++)
+	{
+		printk_spew("%02X: ", i*16);
+		for (j = 0; j < 16; j++)
+		{
+			reg8 = pci_read_config8(dev, j+(i*16));
+			printk_spew("%02X ", reg8);
+		}
+		printk_spew("\n");
+	}		
+#endif	
+}
+
+static const struct device_operations vlink_operations = {
+	.read_resources   = pci_dev_read_resources,
+	.set_resources    = pci_dev_set_resources,
+	.enable_resources = pci_dev_enable_resources,
+	.init             = vlink_init,
+	.ops_pci          = 0,
+};
+ 
+static const struct pci_driver vlink_driver __pci_driver = {
+	.ops    = &vlink_operations,
+	.vendor = PCI_VENDOR_ID_VIA,
+	.device = PCI_DEVICE_ID_VIA_CN400_VLINK,
+}; 
+
+static void c3_host_init(device_t dev)
+{
+	u8 reg8;
+	int i, j;
+	
+	printk_spew("Entering CN400 %s\n", __func__);
+	
+	printk_spew("%s PCI Header Regs::\n", dev_path(dev));
+	 
+	for (i = 0 ; i < 16; i++)
+	{
+		printk_spew("%02X: ", i*16);
+		for (j = 0; j < 16; j++)
+		{
+			reg8 = pci_read_config8(dev, j+(i*16));
+			printk_spew("%02X ", reg8);
+		}
+		printk_spew("\n");
+	}		
+	
+}
+
+static const struct device_operations c3_host_operations = {
+	.read_resources   = cn400_noop,
+	.set_resources    = cn400_noop,
+	.enable_resources = cn400_noop,
+	.init             = c3_host_init,
+	.ops_pci          = 0,
+};
+ 
+static const struct pci_driver c3_host_driver __pci_driver = {
+	.ops    = &c3_host_operations,
+	.vendor = PCI_VENDOR_ID_VIA,
+	.device = PCI_DEVICE_ID_VIA_CN400_HOST,
+}; 
+
+
+static void c3_err_init(device_t dev)
+{
+	u8 reg8;
+	int i, j;
+	
+	printk_spew("Entering CN400 %s\n", __func__);
+		
+	printk_spew("%s PCI Header Regs::\n", dev_path(dev));
+	 
+	for (i = 0 ; i < 16; i++)
+	{
+		printk_spew("%02X: ", i*16);
+		for (j = 0; j < 16; j++)
+		{
+			reg8 = pci_read_config8(dev, j+(i*16));
+			printk_spew("%02X ", reg8);
+		}
+		printk_spew("\n");
+	}		
+	
+}
+
+static const struct device_operations c3_err_operations = {
+	.read_resources   = cn400_noop,
+	.set_resources    = cn400_noop,
+	.enable_resources = cn400_noop,
+	.init             = c3_err_init,
+	.ops_pci          = 0,
+};
+ 
+static const struct pci_driver c3_err_driver __pci_driver = {
+	.ops    = &c3_err_operations,
+	.vendor = PCI_VENDOR_ID_VIA,
+	.device = PCI_DEVICE_ID_VIA_CN400_ERR,
+}; 
+
+static void cn400_pm_init(device_t dev)
+{
+	u8 reg8;
+	int i, j;
+	
+	printk_spew("Entering CN400 %s\n", __func__);
+		
+	printk_spew("%s PCI Header Regs::\n", dev_path(dev));
+	 
+	for (i = 0 ; i < 16; i++)
+	{
+		printk_spew("%02X: ", i*16);
+		for (j = 0; j < 16; j++)
+		{
+			reg8 = pci_read_config8(dev, j+(i*16));
+			printk_spew("%02X ", reg8);
+		}
+		printk_spew("\n");
+	}		
+	
+}
+
+static const struct device_operations cn400_pm_operations = {
+	.read_resources   = cn400_noop,
+	.set_resources    = cn400_noop,
+	.enable_resources = cn400_noop,
+	.init             = cn400_pm_init,
+	.ops_pci          = 0,
+};
+ 
+static const struct pci_driver cn400_pm_driver __pci_driver = {
+	.ops    = &c3_err_operations,
+	.vendor = PCI_VENDOR_ID_VIA,
+	.device = PCI_DEVICE_ID_VIA_CN400_PM,
+}; 
Index: via/cn400/agp.c
===================================================================
--- via/cn400/agp.c	(revision 1)
+++ via/cn400/agp.c	(working copy)
@@ -32,21 +32,26 @@
 static void agp_init(device_t dev)
 {
 	u32 reg32;
+	u8 reg8;
+	int i, j;
 
 	/* Some of this may not be necessary (should be handled by the OS). */
 	printk_debug("Enabling AGP.\n");
 
 	/* Allow R/W access to AGP registers. */
-	pci_write_config8(dev, 0x4d, 0x15);
+	pci_write_config8(dev, 0x4d, 0x05);
 
 	/* Setup PCI latency timer. */
 	pci_write_config8(dev, 0xd, 0x8);
+	
+	/* Write Secondary Vendor Ids */
+	pci_write_config32(dev, 0x2C, 0xAA071106);
 
 	/*
 	 * Set to AGP 3.0 Mode, which should theoretically render the rest of
 	 * the registers set here pointless.
 	 */
-	pci_write_config8(dev, 0x84, 0xb);
+	pci_write_config8(dev, 0x84, 0x1b);
 
 	/* AGP Request Queue Size */
 	pci_write_config8(dev, 0x4a, 0x1f);
@@ -67,41 +72,60 @@
 	/* Enable AGP Backdoor */
 	pci_write_config8(dev, 0xb5, 0x03);
 
-	/* Set aperture to 32 MB. */
+	/* Set aperture to 128 MB. */
 	/* TODO: Use config option, explain how it works. */
-	pci_write_config32(dev, 0x94, 0x00010f38);
+	pci_write_config32(dev, 0x94, 0x00010f20);
 	/* Set GART Table Base Address (31:12). */
-	pci_write_config32(dev, 0x98, (0x1558 << 12));
+	pci_write_config32(dev, 0x98, (0x37b20 << 12));
 	/* Set AGP Aperture Base. */
-	pci_write_config32(dev, 0x10, 0xf8000008);
+	pci_write_config32(dev, 0x10, 0xe8000008);
 
-	/* Enable CPU/PMSTR GART Access. */
+	/* NMI/AGPBUSY# Function Select */
+	pci_write_config8(dev, 0xbe, 0x80);
+	
+	/* AGP Misc Control 1 */
+	pci_write_config8(dev, 0xc2, 0x40);
+	
+	/* Enable CPU/PMSTR GART Access and DBI function. */
 	reg32 = pci_read_config8(dev, 0xbf);
-	reg32 |= 0x80;
+	reg32 |= 0x8c;
 	pci_write_config8(dev, 0xbf, reg32);
 
 	/* Enable AGP Aperture. */
-	reg32 = pci_read_config32(dev, 0x94);
-	reg32 |= (3 << 7);
-	pci_write_config32(dev, 0x90, reg32);
+	pci_write_config32(dev, 0x90, 0x0180);
 
 	/* AGP Control */
-	pci_write_config8(dev, 0xbc, 0x21);
+	pci_write_config8(dev, 0xbc, 0x25);
 	pci_write_config8(dev, 0xbd, 0xd2);
 
 	/*
 	 * AGP Pad, driving strength, and delay control. All this should be
 	 * constant, seeing as the VGA controller is onboard.
 	 */
-	pci_write_config8(dev, 0x40, 0xc7);
-	pci_write_config8(dev, 0x41, 0xdb);
-	pci_write_config8(dev, 0x42, 0x10);
-	pci_write_config8(dev, 0x43, 0xdb);
-	pci_write_config8(dev, 0x44, 0x24);
+	pci_write_config8(dev, 0x40, 0xda);
+	pci_write_config8(dev, 0x41, 0xca);
+	pci_write_config8(dev, 0x42, 0x01);
+	pci_write_config8(dev, 0x43, 0xca);
+	pci_write_config8(dev, 0x44, 0x04);
 
 	/* AGPC CKG Control */
-	pci_write_config8(dev, 0xc0, 0x02);
+	pci_write_config8(dev, 0xc0, 0x04);
 	pci_write_config8(dev, 0xc1, 0x02);
+
+#ifdef DEBUG_CN400
+	printk_spew("%s PCI Header Regs::\n", dev_path(dev));
+	 
+	for (i = 0 ; i < 16; i++)
+	{
+		printk_spew("%02X: ", i*16);
+		for (j = 0; j < 16; j++)
+		{
+			reg8 = pci_read_config8(dev, j+(i*16));
+			printk_spew("%02X ", reg8);
+		}
+		printk_spew("\n");
+	}		
+#endif	
 }
 
 static const struct device_operations agp_operations = {
@@ -118,47 +142,89 @@
 	.device = PCI_DEVICE_ID_VIA_CN400_AGP,
 };
 
+static void agp_bridge_read_resources (device_t dev)
+{
+	struct resource *res;
+	
+	res = new_resource(dev, 1);
+	res->base = 0xF0000000ULL;
+	res->size = 0x06000000ULL;
+	res->limit = 0xffffffffULL;
+	res->flags = IORESOURCE_MEM | IORESOURCE_FIXED |
+		     		IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+						
+	res = new_resource(dev, 2);
+	res->base = 0xB000UL;
+	res->size = 4096;
+	res->limit = 0xffffUL;
+	res->flags = IORESOURCE_IO | IORESOURCE_FIXED |
+		     		IORESOURCE_STORED | IORESOURCE_ASSIGNED;	
+
+}
 /*
  * This is the AGP 3.0 "bridge" @Bus 0 Device 1 Func 0. When using AGP 3.0, the
  * config in this device takes presidence. We configure both just to be safe.
  */
 static void agp_bridge_init(device_t dev)
 {
-	printk_debug("Setting up AGP bridge device\n");
+	u8 reg8;
+	int i, j;
+	
+	printk_debug("Entering %s\n", __func__);
 
-	pci_write_config16(dev, 0x4, 0x0007);
+	pci_write_config16(dev, 0x4, 0x0107);
 
 	/* Secondary Bus Number */
 	pci_write_config8(dev, 0x19, 0x01);
 	/* Subordinate Bus Number */
 	pci_write_config8(dev, 0x1a, 0x01);
+
 	/* I/O Base */
-	pci_write_config8(dev, 0x1c, 0xd0);
+	pci_write_config8(dev, 0x1c, 0xf0);
+
 	/* I/O Limit */
-	pci_write_config8(dev, 0x1d, 0xd0);
+	pci_write_config8(dev, 0x1d, 0x00);
 
 	/* Memory Base */
-	pci_write_config16(dev, 0x20, 0xfb00);
+	pci_write_config16(dev, 0x20, 0xf400);
+
 	/* Memory Limit */
-	pci_write_config16(dev, 0x22, 0xfcf0);
+	pci_write_config16(dev, 0x22, 0xf5f0);
+
 	/* Prefetchable Memory Base */
-	pci_write_config16(dev, 0x24, 0xf400);
+	pci_write_config16(dev, 0x24, 0xf000);
+
 	/* Prefetchable Memory Limit */
-	pci_write_config16(dev, 0x26, 0xf7f0);
+	pci_write_config16(dev, 0x26, 0xf3f0);
+
 	/* Enable VGA Compatible Memory/IO Range */
-	pci_write_config8(dev, 0x3e, 0x08);
-
-	/* Second PCI Bus Control (see datasheet) */
+	pci_write_config8(dev, 0x3e, 0x0e);
+	
+	/* AGP Bus Control */
 	pci_write_config8(dev, 0x40, 0x83);
-	pci_write_config8(dev, 0x41, 0x43);
-	pci_write_config8(dev, 0x42, 0xe2);
+	pci_write_config8(dev, 0x41, 0xC7);
+	pci_write_config8(dev, 0x42, 0x02);
 	pci_write_config8(dev, 0x43, 0x44);
 	pci_write_config8(dev, 0x44, 0x34);
 	pci_write_config8(dev, 0x45, 0x72);
+
+	printk_spew("%s PCI Header Regs::\n", dev_path(dev));
+	 
+	for (i = 0 ; i < 16; i++)
+	{
+		printk_spew("%02X: ", i*16);
+		for (j = 0; j < 16; j++)
+		{
+			reg8 = pci_read_config8(dev, j+(i*16));
+			printk_spew("%02X ", reg8);
+		}
+		printk_spew("\n");
+	}		
+
 }
 
 static const struct device_operations agp_bridge_operations = {
-	.read_resources   = cn400_noop,
+	.read_resources   = agp_bridge_read_resources,
 	.set_resources    = pci_dev_set_resources,
 	.enable_resources = pci_bus_enable_resources,
 	.init             = agp_bridge_init,
Index: via/cn400/northbridge.c
===================================================================
--- via/cn400/northbridge.c	(revision 1)
+++ via/cn400/northbridge.c	(working copy)
@@ -38,16 +38,28 @@
 {
 	device_t vlink_dev;
 	u16 reg16;
-	u8 ranks, pagec, paged, pagee, pagef, shadowreg;
+	u8 ranks, pagec, paged, pagee, pagef, shadowreg, reg8;
+	int i, j;
 
 	printk_spew("Entering cn400 memctrl_init.\n");
+	/* vlink mirror */
+	vlink_dev = dev_find_device(PCI_VENDOR_ID_VIA,
+				    PCI_DEVICE_ID_VIA_CN400_VLINK, 0);
 	
-	/* Set up the VGA framebuffer size. */
-	reg16 = (log2(CONFIG_VIDEO_MB) << 12) | (1 << 15);
+	/* Setup Low Memory Top 						*/
+	/* 0x47 == HA(32:25)						    */
+	/* 0x84/85 == HA(31:20) << 4 | DRAM Granularity */
+	ranks = pci_read_config8(dev, 0x47);
+	reg16 = (((u16)(ranks - 1) << 9) & 0xFFF0) | 0x01F0;
+	
+	pci_write_config16(dev, 0x84, reg16);
+	printk_spew("Low Top Address = 0x%04X\n", reg16);
+	
+	/* Set up the VGA framebuffer size and Base Address   */
+	/* Note dependencies between agp.c and vga.c and here */
+	reg16 = (log2(CONFIG_VIDEO_MB) << 12) | (1 << 15) | 0xF00;
 	pci_write_config16(dev, 0xa0, reg16);
 
-	/* Set up VGA timers. */
-	pci_write_config8(dev, 0xa2, 0x44);
 
 	for (ranks = 0x4b; ranks >= 0x48; ranks--) {
 		if (pci_read_config8(dev, ranks)) {
@@ -60,10 +72,19 @@
 	reg16 = 0xaaf0;
 	reg16 |= ranks;
 	/* GMINT Misc. FrameBuffer rank */
-	pci_write_config16(dev, 0xb0, reg16);
+	pci_write_config16(dev, 0xb0, reg16);	
 	/* AGPCINT Misc. */
 	pci_write_config8(dev, 0xb8, 0x08);
 
+	/* Arbritation Counters */
+	pci_write_config8(dev, 0xb2, 0xaa);
+	
+	/* Write FIFO Setup */
+	pci_write_config8(dev, 0xb3, 0x5a);
+	
+	/* Graphics control optimisation */
+	pci_write_config8(dev, 0xb4, 0x0f);
+	
 	/* Shadow RAM */
 	pagec = 0xff, paged = 0xff, pagee = 0xff, pagef = 0x30;
 	/* PAGE C, D, E are all read write enable */
@@ -73,26 +94,44 @@
 	/* PAGE F are read/writable */
 	shadowreg = pci_read_config8(dev, 0x82);
 	shadowreg |= pagef;
-	pci_write_config8(dev, 0x82, shadowreg);
-	/* vlink mirror */
-	vlink_dev = dev_find_device(PCI_VENDOR_ID_VIA,
-				    PCI_DEVICE_ID_VIA_CN400_VLINK, 0);
-	if (vlink_dev) {
+	pci_write_config8(dev, 0x82, shadowreg);					
 		pci_write_config8(vlink_dev, 0x61, pagec);
 		pci_write_config8(vlink_dev, 0x62, paged);
 		pci_write_config8(vlink_dev, 0x64, pagee);
 
 		shadowreg = pci_read_config8(vlink_dev, 0x63);
 		shadowreg |= pagef;
-		pci_write_config8(vlink_dev, 0x63, shadowreg);
-	}
+		pci_write_config8(vlink_dev, 0x63, shadowreg);	
+
+	/* Activate VGA Frame Buffer */
 	
-	printk_spew("Leaving cn400 memctrl_init.\n");
+	reg8 = pci_read_config8(dev, 0xA0);
+	reg8 |= 0x01;
+	pci_write_config8(dev, 0xA0, reg8);
+
+#ifdef DEBUG_CN400	
+	printk_spew("%s PCI Header Regs::\n", dev_path(dev));
+	 
+	for (i = 0 ; i < 16; i++)
+	{
+		printk_spew("%02X: ", i*16);
+		for (j = 0; j < 16; j++)
+		{
+			reg8 = pci_read_config8(dev, j+(i*16));
+			printk_spew("%02X ", reg8);
+		}
+		printk_spew("\n");
+	}		
+#endif	
+	printk_spew("Leaving cn400 %s.\n", __func__);
 }
 
 static const struct device_operations memctrl_operations = {
 	.read_resources = cn400_noop,
+	.set_resources    = cn400_noop,
+	.enable_resources = cn400_noop,
 	.init           = memctrl_init,
+	.ops_pci          = 0,
 };
 
 static const struct pci_driver memctrl_driver __pci_driver = {
@@ -129,14 +168,27 @@
 
 	if (!sizek)
 		return;
-
 	resource = new_resource(dev, index);
-	resource->base = ((resource_t) basek) << 10;
-	resource->size = ((resource_t) sizek) << 10;
+	resource->base = (resource_t) (basek << 10);
+	resource->size = (resource_t) (sizek << 10);
 	resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE |
 	    IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
 }
 
+static void ram_reservation(device_t dev, unsigned long index,
+			 unsigned long base, unsigned long size)
+{
+	struct resource *res;
+	
+	printk_spew("Configuring Via C3 LAPIC Fixed Resource\n");
+	/* Fixed LAPIC resource */
+	res = new_resource(dev, 1);
+	res->base = (resource_t) base;
+	res->size = size;
+	res->flags = IORESOURCE_MEM | IORESOURCE_FIXED |
+		     IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+}
+
 static void tolm_test(void *gp, struct device *dev, struct resource *new)
 {
 	struct resource **best_p = gp;
@@ -150,24 +202,23 @@
 
 static u32 find_pci_tolm(struct bus *bus)
 {
-	struct resource *min;
+	struct resource *min = NULL;
 	u32 tolm;
 
-	print_debug("Entering CN400 find_pci_tolm\n");
+	printk_spew("Entering CN400 find_pci_tolm\n");
 
-	min = 0;
 	search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM,
 			     tolm_test, &min);
 	tolm = 0xffffffffUL;
 	if (min && tolm > min->base)
 		tolm = min->base;
 
-	print_debug("Leaving find_pci_tolm\n");
+	printk_spew("Leaving CN400 find_pci_tolm\n");
 
 	return tolm;
 }
 
-#if HAVE_HIGH_TABLES==1
+#if CONFIG_HAVE_HIGH_TABLES==1
 /* maximum size of high tables in KB */
 #define HIGH_TABLES_SIZE 64
 extern uint64_t high_tables_base, high_tables_size;
@@ -175,8 +226,6 @@
 
 static void cn400_domain_set_resources(device_t dev)
 {
-	/* The order is important to find the correct RAM size. */
-	static const u8 ramregs[] = { 0x43, 0x42, 0x41, 0x40 };
 	device_t mc_dev;
 	u32 pci_tolm;
 
@@ -191,29 +240,21 @@
 		unsigned char rambits;
 		int i, idx;
 
-		/*
-		 * Once the register value is not zero, the RAM size is
-		 * this register's value multiply 64 * 1024 * 1024.
-		 */
-		for (rambits = 0, i = 0; i < ARRAY_SIZE(ramregs); i++) {
-			rambits = pci_read_config8(mc_dev, ramregs[i]);
-			if (rambits != 0)
-				break;
-		}
-
-		tomk = rambits * 64 * 1024;
-		printk_spew("tomk is 0x%x\n", tomk);
+		rambits = pci_read_config8(mc_dev, 0x47);
+		tomk = rambits * 32 * 1024;
 		/* Compute the Top Of Low Memory (TOLM), in Kb. */
 		tolmk = pci_tolm >> 10;
+		printk_spew("tomk is 0x%x, tolmk is 0x%08X\n", tomk, tolmk);
 		if (tolmk >= tomk) {
 			/* The PCI hole does does not overlap the memory. */
 			tolmk = tomk;
 		}
 
-#if HAVE_HIGH_TABLES == 1
-		high_tables_base = (tolmk - HIGH_TABLES_SIZE) * 1024;
-		high_tables_size = HIGH_TABLES_SIZE* 1024;
-		printk_debug("tom: %lx, high_tables_base: %llx, high_tables_size: %llx\n", tomk*1024, high_tables_base, high_tables_size);
+#if CONFIG_HAVE_HIGH_TABLES == 1
+		/* Locate the High Tables at the Top of Low Memory below the Video RAM */
+		high_tables_base = (uint64_t) (tolmk - (CONFIG_VIDEO_MB *1024) - HIGH_TABLES_SIZE) * 1024;
+		high_tables_size = (uint64_t) HIGH_TABLES_SIZE* 1024;
+		printk_spew("tom: %lx, high_tables_base: %llx, high_tables_size: %llx\n", tomk*1024, high_tables_base, high_tables_size);
 #endif
 
 		/* Report the memory regions. */
Index: via/cn400/cn400.h
===================================================================
--- via/cn400/cn400.h	(revision 1)
+++ via/cn400/cn400.h	(working copy)
@@ -24,6 +24,8 @@
 }
 #endif
 
+#define DEBUG_CN400
+
 /* VGA stuff */
 #define SR_INDEX		0x3c4
 #define SR_DATA			0x3c5
Index: via/cn400/vga.c
===================================================================
--- via/cn400/vga.c	(revision 1)
+++ via/cn400/vga.c	(working copy)
@@ -47,6 +47,9 @@
 {
 	u8 reg8;
 	u32 temp;
+#ifdef DEBUG_CN400
+	int i, j;
+#endif
 
 	temp = (0xffffffff - CONFIG_FALLBACK_SIZE - 0xffff);
 	printk_debug("Copying BOCHS BIOS from 0x%08X	to 0xf000\n", temp);
@@ -73,8 +76,8 @@
 
 	pci_write_config8(dev, 0x04, 0x07);
 	pci_write_config8(dev, 0x0d, 0x20);
-	pci_write_config32(dev, 0x10, 0xf4000008);
-	pci_write_config32(dev, 0x14, 0xfb000000);
+	pci_write_config32(dev, 0x10, 0xf0000008);
+	pci_write_config32(dev, 0x14, 0xf4000000);
 
 	printk_debug("INSTALL REAL-MODE IDT\n");
 	setup_realmode_idt();
@@ -101,6 +104,21 @@
 
 	/* Clear the BOCHS BIOS out of memory, so it doesn't confuse Linux. */
 	memset(0xf0000, 0, 0x10000);
+
+#ifdef DEBUG_CN400
+	printk_spew("%s PCI Header Regs::\n", dev_path(dev));
+	 
+	for (i = 0 ; i < 16; i++)
+	{
+		printk_spew("%02X: ", i*16);
+		for (j = 0; j < 16; j++)
+		{
+			reg8 = pci_read_config8(dev, j+(i*16));
+			printk_spew("%02X ", reg8);
+		}
+		printk_spew("\n");
+	}		
+#endif
 }
 
 static void vga_read_resources(device_t dev)
