[LinuxBIOS] r2421 - in trunk/LinuxBIOSv2/src/southbridge/amd: . cs5536_lx

svn at openbios.org svn at openbios.org
Tue Sep 19 00:52:25 CEST 2006


Author: rminnich
Date: 2006-09-19 00:52:24 +0200 (Tue, 19 Sep 2006)
New Revision: 2421

Added:
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/Config.lb
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/chip.h
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536.c
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536.h
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_early_setup.c
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_early_smbus.c
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_ide.c
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_smbus.h
   trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_smbus2.h
Log:
add the _lx flavor of the 5536. This will later be merged into the 
cs5536, but I don't want to mess up the OLPC, and we really need the lx
support NOW.


Added: trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/Config.lb
===================================================================
--- trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/Config.lb	                        (rev 0)
+++ trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/Config.lb	2006-09-18 22:52:24 UTC (rev 2421)
@@ -0,0 +1,5 @@
+config chip.h
+driver cs5536.o
+driver cs5536_usb.o
+#driver cs5536_pci.o
+#driver cs5536_ide.o

Added: trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/chip.h
===================================================================
--- trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/chip.h	                        (rev 0)
+++ trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/chip.h	2006-09-18 22:52:24 UTC (rev 2421)
@@ -0,0 +1,53 @@
+#ifndef _SOUTHBRIDGE_AMD_CS5536
+#define _SOUTHBRIDGE_AMD_CS5536
+
+#define MAX_UNWANTED_VPCI 10	/* increase if needed */
+
+extern struct chip_operations southbridge_amd_cs5536_ops;
+
+struct southbridge_amd_cs5536_config {
+	/* interrupt enable for LPC bus */
+	int lpc_serirq_enable;	/* how to enable, e.g. 0x80 */
+ 	int lpc_irq;		/* what to enable, e.g. 0x18 */
+	int enable_ide_nand_flash; /* if you are using nand flash instead of IDE drive */
+
+	/* following are IRQ numbers for various southbridge resources.
+	 * these are configured and PCI headers are set */
+	
+	int isa_irq;		// f.0, 1022:2090
+	int flash_irq;		// f.1, 1022:2091
+
+	// ide irq is tied to IRQ14, this can only be enabled or disabled
+	int enable_ide_irq;		// f.2, 1022:2092
+
+	int audio_irq; 		// f.3, 1022:2093
+	
+	int usb_irq;	// f.4,5,6,7, 1022:2094
+	// only one irq source for all usb devices
+
+	// internal UART IRQs
+	int uart0_irq;
+	int uart1_irq;
+
+	/* GPIO to IRQ mapping, intended to use for PCI IRQ's.
+	 * This only does physical mapping, no PCI headers are configured
+	 * PCI configuration is mainboard-specific and should be done in mainboard.c
+	 */
+	// pci IRQs A-D. Set this to 0 to disable.
+	int pci_int[4];
+	// and their GPIO pins
+	int pci_int_pin[4];
+
+
+	// Enable KEL keyboard IRQ2
+	int enable_kel_keyb_irq;
+	// Enable KEL mouse IRQ12
+	int enable_kel_mouse_irq;
+	// Configure KEL Emulation IRQ (input Y13)
+	int kel_emul_irq;
+
+	/* the following allow you to disable unwanted virtualized PCI devices */
+	unsigned long unwanted_vpci[MAX_UNWANTED_VPCI];
+};
+
+#endif	/* _SOUTHBRIDGE_AMD_CS5536 */

Added: trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536.c
===================================================================
--- trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536.c	                        (rev 0)
+++ trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536.c	2006-09-18 22:52:24 UTC (rev 2421)
@@ -0,0 +1,331 @@
+
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ops.h>
+#include <device/pci_ids.h>
+#include <console/console.h>
+#include <cpu/amd/lxdef.h>
+#include <cpu/x86/msr.h>
+#include "chip.h"
+
+// prototypes here, avoid warnings
+void setup_i8259(void);
+void pci_assign_irqs(unsigned bus, unsigned slot, const unsigned char pIntAtoD[4]);
+void print_conf(void);
+
+#define PIN_OPT_IDE		(1ULL<<0)	/* 0 for flash, 1 for IDE */
+
+/* Intended value for LBAR_FLSH0: 4KiB, enabled, MMIO, NAND, @0x20000000 */
+/* NOTE: no longer used, prune at some point */
+/* OOPS: steve's changes don't work, so we have to keep this */
+msr_t flsh1 = { .hi=0xFFFFF007, .lo=0x20000000};
+
+// ide is ENABLED by default (in early init), this disables it if neccesary
+// and enables flash
+static void enable_ide_nand_flash()
+{
+	msr_t msr;
+	printk_debug("cs5536: %s\n", __FUNCTION__);
+#if 1
+	printk_err("WARNING: using deprecated flash enable mechanism\n");
+	/* steve took this one out ... not sure if needed or not */
+	msr = rdmsr(MDD_LBAR_FLSH1);
+
+	if ( ((msr.hi) & 7) != 7) {
+		printk_debug("MDD_LBAR_FLSH1 was 0x%08x%08x\n", msr.hi,msr.lo);
+		wrmsr(MDD_LBAR_FLSH1, flsh1);
+	}
+	msr = rdmsr(MDD_LBAR_FLSH1);
+	printk_debug("MDD_LBAR_FLSH1 is 0x%08x%08x\n", msr.hi,msr.lo);
+#endif
+	msr = rdmsr(MDD_PIN_OPT);
+	if (msr.lo & PIN_OPT_IDE) {
+		printk_debug("MDD_PIN_OPT was 0x%08x%08x\n", msr.hi,msr.lo);
+		msr.lo &= ~PIN_OPT_IDE;
+		wrmsr(MDD_PIN_OPT, msr);
+	}
+	msr = rdmsr(MDD_PIN_OPT);
+	printk_debug("MDD_PIN_OPT is 0x%08x%08x\n", msr.hi,msr.lo);
+
+	msr = rdmsr(MDD_NANDF_DATA);
+	if (msr.lo != 0x00100010) {
+		printk_debug("MDD_NANDF_DATA was 0x%08x%08x\n", msr.hi,msr.lo);
+		msr.lo = 0x00100010;
+		wrmsr(MDD_NANDF_DATA, msr);
+	}
+	msr = rdmsr(MDD_NANDF_DATA);
+	printk_debug("MDD_NANDF_DATA is 0x%08x%08x\n", msr.hi,msr.lo);
+
+	msr = rdmsr(MDD_NADF_CNTL);
+	if (msr.lo != 0x0010) {
+		printk_debug("MDD_NADF_CNTL was 0x%08x%08x\n", msr.hi,msr.lo);
+		msr.lo = 0x0010;
+		wrmsr(MDD_NADF_CNTL, msr);
+	}
+	msr = rdmsr(MDD_NADF_CNTL);
+	printk_debug("MDD_NADF_CNTL is 0x%08x%08x\n", msr.hi,msr.lo);
+	printk_debug("cs5536: EXIT %s\n", __FUNCTION__);
+}
+
+/* note: this is a candidate for inclusion in src/devices/pci_device.c */
+// set pci headers to indicate correct IRQ number of the device
+void setup_irq(unsigned irq, unsigned level, unsigned bus, unsigned device, unsigned fn)
+{
+	if (irq)
+	{
+		unsigned devfn = PCI_DEVFN(device,fn);
+		device_t dev  = dev_find_slot(bus, devfn);
+		if (dev) 
+		{
+			printk_debug("%s: assigning IRQ %d to %x.%x (0x%x)\n", 
+				__FUNCTION__, irq, device, fn, devfn);
+
+			pci_write_config8(dev, PCI_INTERRUPT_LINE, irq);
+			if (level) pci_level_irq(irq);
+		}
+		else
+			printk_err("%s: Can't find PCI device function 0x%x\n", __FUNCTION__, devfn);
+	}
+}
+
+// map an Y or Z irq source in programmable irq controller 
+// dev 0..15 Y, 16...31 Z
+void map_pic_irq(unsigned int dev, unsigned int irq){
+	msr_t msr;
+	unsigned long mask;
+	unsigned long val;
+	
+	
+	mask = ~(0xF<<((dev&7)<<2));
+	val = irq<<((dev&7)<<2);
+	
+	printk_debug("%s: mapping %d to src %d: mask %x val %x\n", 
+				__FUNCTION__, irq, dev,mask,val);
+	
+	switch (dev & 0x18){
+		case 0:
+			msr=rdmsr(MDD_IRQM_YLOW);
+			msr.lo = (msr.lo & mask) | val;
+			wrmsr(MDD_IRQM_YLOW,msr);
+			break;
+		case 8:
+			msr=rdmsr(MDD_IRQM_YHIGH);
+			msr.lo = (msr.lo & mask) | val;
+			wrmsr(MDD_IRQM_YHIGH,msr);
+			break;
+		case 16:
+			msr=rdmsr(MDD_IRQM_ZLOW);
+			msr.lo = (msr.lo & mask) | val;
+			wrmsr(MDD_IRQM_ZLOW,msr);
+			break;
+		case 24:
+			msr=rdmsr(MDD_IRQM_ZHIGH);
+			msr.lo = (msr.lo & mask) | val;
+			wrmsr(MDD_IRQM_ZHIGH,msr);
+	}
+}
+
+// map an GPIO pin to PIC Z source and that to an IRQ.
+void map_gpio_irq(unsigned int pin, unsigned int gpioirq, unsigned int irq, unsigned int invert){
+	
+	unsigned long temp;
+	unsigned long mask;
+	unsigned long val;
+
+	mask = ~(0xF<<((pin&7)<<2));
+	val = gpioirq<<((pin&7)<<2);
+	
+	// configure GPIO pin as INT source
+	outl(1<<(pin&0x0F), (pin<16)?GPIOL_INPUT_ENABLE:GPIOH_INPUT_ENABLE);
+	outl(1<<(pin&0x0F), (pin<16)?GPIOL_EVENTS_ENABLE:GPIOH_EVENTS_ENABLE);
+
+	if (invert) outl(1<<(pin&0x0F), (pin<16)?GPIOL_INPUT_INVERT_ENABLE:GPIOH_INPUT_INVERT_ENABLE);
+
+	// map current GPIO pin to PIC unrestricted Z GPIO irq source gpioirq
+	temp = inl((pin<16)?
+			((pin<8)?GPIO_MAPPER_X:GPIO_MAPPER_Y):
+			((pin<24)?GPIO_MAPPER_Z:GPIO_MAPPER_W));
+
+	outl((temp & mask)|val, 
+		(pin<16)?
+			((pin<8)?GPIO_MAPPER_X:GPIO_MAPPER_Y):
+			((pin<24)?GPIO_MAPPER_Z:GPIO_MAPPER_W));
+			
+	// map PIC unrestricted Z GPIO source i to IRQ needed
+	map_pic_irq(gpioirq+24,irq);
+}
+
+static void southbridge_init(struct device *dev)
+{
+	struct southbridge_amd_cs5536_config  *sb = (struct southbridge_amd_cs5536_config *)dev->chip_info;
+ 	msr_t msr;
+	int i;
+
+	printk_spew(">> Entering cs5536.c: %s\n", __FUNCTION__);
+
+	/*
+	 * struct device *gpiodev;
+	 * unsigned short gpiobase = MDD_GPIO;
+	 */
+
+	setup_i8259(); 
+
+	// at first, disable all primary IRQ inputs except timer, RTC and FPU
+	msr.lo=0x2101;
+	msr.hi=0;
+	wrmsr(MDD_IRQM_PRIM, msr);
+
+	// LPC bus IRQs are enabled here
+	if (sb->lpc_serirq_enable) {
+		msr.lo = sb->lpc_serirq_enable;
+		msr.hi  = 0;
+		wrmsr(MDD_LPC_SIRQ, msr);
+	}
+	if (sb->lpc_irq) {
+		msr.lo = sb->lpc_irq;
+		msr.hi = 0;
+		wrmsr(MDD_IRQM_LPC, msr);
+	}
+
+	// GPIO to IRQ mapping (meant for PCI IRQs)
+	//  here, only physical mapping is done. 
+	//  pci headers should be configured for all pci slots available in mainboard.c
+	//  so that operating system can read correct irq number from there
+	for (i=0; i<3; i++){
+		if (sb->pci_int[i]){
+			printk_debug("cs5536: %s: Configuring PCI INT%c from GPIO %d to INT %d.\n",
+				 __FUNCTION__, 'A'+i, sb->pci_int_pin[i], sb->pci_int[i]);
+			map_gpio_irq(sb->pci_int_pin[i], i, sb->pci_int[i], 1);
+		}
+	}
+/*	
+// PCI IRQ mapping should work like this through vsa, but it doesn't
+	outl(0xAC1C, 0xFC53); //magic word to enable hidden register
+	outl(0xAC1C, 0x0009); //command: PCI_INT_AB
+	outl(0xAC1E, 
+		(sb->pci_int[0]>0)?(sb->pci_int_pin[0]):0x21 |
+		(sb->pci_int[1]>0)?(sb->pci_int_pin[1]<<8):(0x21<<8)
+	);
+
+	outl(0x785C, sb->pci_int[0]|(sb->pci_int[1]<<8));
+*/
+
+	printk_debug("cs5536: %s: enable_ide_nand_flash is %d\n", __FUNCTION__, sb->enable_ide_nand_flash);
+	if (sb->enable_ide_nand_flash) {
+		enable_ide_nand_flash();
+	}
+
+ 	/* irq handling */
+ 	// setup_irq sets irq in pci headers only, no configuration is done.
+ 	// pci headers must be set, operating system reads IRQ numbers there.
+ 	// to disable, set IRQ=0
+ 	
+	if (sb->isa_irq){
+	 	setup_irq(sb->isa_irq, 1, 0, 0xf, 0);
+	}
+
+	if (sb->flash_irq){
+	 	setup_irq(sb->flash_irq, 1, 0, 0xf, 1);
+	 	map_pic_irq(6,sb->flash_irq);
+	 	map_pic_irq(7,sb->flash_irq);	 	
+	}
+
+	// IDE IRQ 14 (GPIO pin 2) can only be enabled or disabled
+	if (sb->enable_ide_irq){
+	 	setup_irq(14, 1, 0, 0xf, 2);
+
+		// set up IDE GPIO IRQ pin
+		outl(1<<2, GPIOL_INPUT_ENABLE);
+		outl(1<<2, GPIOL_IN_AUX1_SELECT);
+
+		// enable IDE IRQ in primary IRQ mask
+		msr=rdmsr(MDD_IRQM_PRIM);
+		msr.lo |= 0x4000;
+		wrmsr(MDD_IRQM_PRIM, msr);
+	}
+
+	if (sb->audio_irq){ 	
+	 	map_pic_irq(4,sb->audio_irq);
+	 	setup_irq(sb->audio_irq, 1, 0, 0xf, 3);
+	}
+
+	if (sb->uart0_irq){ 	
+	  	map_pic_irq(14,sb->uart0_irq);
+	}	
+	if (sb->uart1_irq){ 	
+	  	map_pic_irq(15,sb->uart1_irq);
+	}
+
+	if (sb->usb_irq){ 	
+	 	setup_irq(sb->usb_irq, 1, 0, 0xf, 4);
+	 	setup_irq(sb->usb_irq, 1, 0, 0xf, 5);
+	 	setup_irq(sb->usb_irq, 1, 0, 0xf, 6);
+	 	setup_irq(sb->usb_irq, 1, 0, 0xf, 7);
+	  	map_pic_irq(2,sb->usb_irq);
+	}
+
+	// KEL (Keyboard Emulation Logic) IRQs
+	if (sb->enable_kel_keyb_irq){
+		msr=rdmsr(MDD_IRQM_PRIM);
+		msr.lo |= 0x0002;
+		wrmsr(MDD_IRQM_PRIM, msr);
+	}
+
+	if (sb->enable_kel_mouse_irq){
+		msr=rdmsr(MDD_IRQM_PRIM);
+		msr.lo |= 0x1000;
+		wrmsr(MDD_IRQM_PRIM, msr);
+	}
+
+	if (sb->kel_emul_irq){
+	 	map_pic_irq(13,sb->kel_emul_irq);	 	
+	}
+
+
+
+
+	/* disable unwanted virtual PCI devices */
+	for (i = 0; (i < MAX_UNWANTED_VPCI) && (0 != sb->unwanted_vpci[i]); i++) {
+		printk_debug("Disabling VPCI device: 0x%08X\n", sb->unwanted_vpci[i]);
+		outl(sb->unwanted_vpci[i] + 0x7C, 0xCF8);
+		outl(0xDEADBEEF,                  0xCFC);
+	}
+
+	/* What do we have there? */
+	printk_debug("\nChipset config after southbridge_init():\n");
+	print_conf();
+}
+
+void southbridge_enable(struct device *dev)
+{
+}
+
+static void cs5536_pci_dev_enable_resources(device_t dev)
+{
+	printk_spew(">> Entering cs5536.c: %s\n", __FUNCTION__);
+	pci_dev_enable_resources(dev);
+	enable_childrens_resources(dev);
+}
+
+static struct device_operations southbridge_ops = {
+	.read_resources   = pci_dev_read_resources,
+	.set_resources    = pci_dev_set_resources,
+	.enable_resources = cs5536_pci_dev_enable_resources,
+	.init             = southbridge_init,
+	.scan_bus         = scan_static_bus,
+};
+
+static struct pci_driver cs5536_pci_driver __pci_driver = {
+	.ops 	= &southbridge_ops,
+	.vendor = PCI_VENDOR_ID_AMD,
+	.device = PCI_DEVICE_ID_AMD_CS5536_ISA
+};
+
+struct chip_operations southbridge_amd_cs5536_ops = {
+	CHIP_NAME("AMD cs5536")
+	/* This only called when this device is listed in the 
+	* static device tree.
+	*/
+	.enable_dev = southbridge_enable,
+};

Added: trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536.h
===================================================================
--- trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536.h	                        (rev 0)
+++ trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536.h	2006-09-18 22:52:24 UTC (rev 2421)
@@ -0,0 +1,6 @@
+#ifndef _CS5536_H
+#define _CS5536_H
+
+extern void southbridge_enable(device_t dev);
+
+#endif

Added: trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_early_setup.c
===================================================================
--- trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_early_setup.c	                        (rev 0)
+++ trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_early_setup.c	2006-09-18 22:52:24 UTC (rev 2421)
@@ -0,0 +1,336 @@
+
+/*
+ *
+ * cs5536_early_setup.c:	Early chipset initialization for CS5536 companion device
+ *
+ *
+ * This file implements the initialization sequence documented in section 4.2 of
+ * AMD Geode GX Processor CS5536 Companion Device GoedeROM Porting Guide.
+ *
+ */
+
+#define CS5536_GLINK_PORT_NUM	0x02	/* the geode link port number to the CS5536 */       
+#define CS5536_DEV_NUM 		0x0F	/* default PCI device number for CS5536 */
+
+
+/**
+ * By default, on cs5536 IDE is disabled and flash is enabled
+ * This function disables flash and enables IDE
+ */
+ 
+static void cs5536_enable_ide(void){
+	msr_t msr;
+	msr = __builtin_rdmsr(0x51400015);
+	msr.lo |= 0x00000001;
+	__builtin_wrmsr(0x51400015, msr.lo, msr.hi);
+}
+
+/**
+ * @brief Setup PCI IDSEL for CS5536
+ *
+ * 
+ */
+
+static void cs5536_setup_extmsr(void)
+{
+	msr_t msr;
+
+	/* forward MSR access to CS5536_GLINK_PORT_NUM to CS5536_DEV_NUM */
+	msr.hi = 0x00000000;
+	msr.lo = 0x00000000;
+	if (CS5536_GLINK_PORT_NUM <= 4) {
+		msr.lo = CS5536_DEV_NUM << ((CS5536_GLINK_PORT_NUM - 1) * 8);
+	} else {
+		msr.hi = CS5536_DEV_NUM << ((CS5536_GLINK_PORT_NUM - 5) * 8);
+	}
+	wrmsr(0x5000201e, msr);
+}
+
+static void cs5536_setup_idsel(void)
+{
+	/* write IDSEL to the write once register at address 0x0000 */
+	outl(0x1 << (CS5536_DEV_NUM + 10), 0);
+}
+
+static void cs5536_usb_swapsif(void)
+{
+	msr_t msr;
+
+	msr = rdmsr(0x51600005);
+	//USB Serial short detect bit.
+	if (msr.hi & 0x10) {
+		/* We need to preserve bits 32,33,35 and not clear any BIST error, but clear the
+		 * SERSHRT error bit */
+		msr.hi &= 0xFFFFFFFB;
+		wrmsr(0x51600005, msr);
+	}
+}
+
+static int cs5536_setup_iobase(void)
+{
+	msr_t msr;
+
+	/* setup LBAR for SMBus controller */
+	__builtin_wrmsr(0x5140000b, 0x00006000, 0x0000f001);
+	/* setup LBAR for GPIO */
+	__builtin_wrmsr(0x5140000c, 0x00006100, 0x0000f001);
+	/* setup LBAR for MFGPT */
+	__builtin_wrmsr(0x5140000d, 0x00006200, 0x0000f001);
+	/* setup LBAR for ACPI */
+	__builtin_wrmsr(0x5140000e, 0x00009c00, 0x0000f001);
+	/* setup LBAR for PM Support */
+	__builtin_wrmsr(0x5140000f, 0x00009d00, 0x0000f001);
+}
+
+static void cs5536_setup_power_bottun(void)
+{
+	/* not implemented yet */
+#if 0
+	pwrBtn_setup:
+	;
+	;	Power Button Setup
+	;
+	;mov	eax, 0C0020000h				; 4 seconds + lock
+	mov	eax, 040020000h				; 4 seconds no lock
+	mov	dx, PMLogic_BASE + 40h
+	out	dx, eax
+
+	; setup GPIO24, it is the external signal for 5536 vsb_work_aux
+	; which controls all voltage rails except Vstandby & Vmem.
+	; We need to enable, OUT_AUX1 and OUTPUT_ENABLE in this order.
+	; If GPIO24 is not enabled then soft-off will not work.
+	mov	dx, GPIOH_OUT_AUX1_SELECT
+	mov	eax, GPIOH_24_SET
+	out	dx, eax
+	mov	dx, GPIOH_OUTPUT_ENABLE
+	out	dx, eax
+
+#endif
+}
+
+static void cs5536_setup_gpio(void)
+{
+	uint32_t val;
+
+	/* setup GPIO pins 14/15 for SDA/SCL */
+	val = (1<<14 | 1<<15);
+	/* Output Enable */
+	outl(0x3fffc000, 0x6100 + 0x04);
+	//outl(val, 0x6100 + 0x04);
+	/* Output AUX1 */
+	outl(0x3fffc000, 0x6100 + 0x10);
+	//outl(val, 0x6100 + 0x10);
+	/* Input Enable */
+	//outl(0x0f5af0a5, 0x6100 + 0x20);
+	outl(0x3fffc000, 0x6100 + 0x20);
+	//outl(val, 0x6100 + 0x20);
+	/* Input AUX1 */
+	//outl(0x3ffbc004, 0x6100 + 0x34);
+	outl(0x3fffc000, 0x6100 + 0x34);
+	//outl(val, 0x6100 + 0x34);
+
+	/*   GX3: Enable GPIO pins for UART2 	*/
+	outl(0x00000010, GPIOL_OUT_AUX1_SELECT);
+	outl(0x00000010, GPIOL_OUTPUT_ENABLE);
+	outl(0x00000008, GPIOL_IN_AUX1_SELECT);
+	outl(0x00000008, GPIOL_INPUT_ENABLE);
+
+#if 0
+	/* changes proposed by Ollie; we will test this later. */
+	/* setup GPIO pins 14/15 for SDA/SCL */
+	val = GPIOL_15_SET | GPIOL_14_SET;
+	/* Output Enable */
+	//outl(0x3fffc000, 0x6100 + 0x04);
+	outl(val, 0x6100 + 0x04);
+	/* Output AUX1 */
+	//outl(0x3fffc000, 0x6100 + 0x10);
+	outl(val, 0x6100 + 0x10);
+	/* Input Enable */
+	//outl(0x3fffc000, 0x6100 + 0x20);
+	outl(val, 0x6100 + 0x20);
+	/* Input AUX1 */
+	//outl(0x3fffc000, 0x6100 + 0x34);
+	outl(val, 0x6100 + 0x34);
+#endif
+}
+
+static void cs5536_disable_internal_uart(void)
+{
+	/* not implemented yet */
+#if 0
+	; The UARTs default to enabled.
+	; Disable and reset them and configure them later. (SIO init)
+	mov	ecx, MDD_UART1_CONF
+	RDMSR
+	mov	eax, 1h					; reset
+	WRMSR
+	mov	eax, 0h					; disabled
+	WRMSR
+
+	mov	ecx, MDD_UART2_CONF
+	RDMSR
+	mov	eax, 1h					; reset
+	WRMSR
+	mov	eax, 0h					; disabled
+	WRMSR
+
+#endif
+}
+
+static void cs5536_setup_cis_mode(void)
+{
+	msr_t msr;
+
+	/* setup CPU interface serial to mode C on both sides */
+	msr = __builtin_rdmsr(0x51000010);
+	msr.lo &= ~0x18;
+	msr.lo |= 0x10;
+	__builtin_wrmsr(0x51000010, msr.lo, msr.hi);
+	//Only do this if we are building for 5536
+	__builtin_wrmsr(0x54002010, 0x00000002, 0x00000000);
+}
+
+static void dummy(void)
+{
+}
+
+/* see page 412 of the cs5536 companion book */
+static int cs5536_setup_onchipuart(void)
+{
+	unsigned long m;
+	
+	unsigned char n;
+	
+	/* 
+	 * 1. Eanble GPIO 8 to OUT_AUX1, 9 to IN_AUX1
+	 *    GPIO LBAR + 0x04, LBAR + 0x10, LBAR + 0x20, LBAR + 34
+	 * 2. Enable UART IO space in MDD
+	 *    MSR 0x51400014 bit 18:16
+	 * 3. Enable UART controller
+	 *    MSR 0x5140003A bit 0, 1
+	 * 4. IRQ routing on IRQ Mapper
+	 *    MSR 0x51400021 bit [27:24]
+	 */
+	msr_t msr;
+ 
+        /*  Bit 1 = DEVEN (device enable)
+         *  Bit 4 = EN_BANKS (allow access to the upper banks)
+         */
+ 
+        msr.lo = (1 << 4) | (1 << 1);
+	msr.hi = 0;
+	/* enable COM1 */
+	//wrmsr(0x5140003a, msr);
+	/* GPIO8 - UART1_TX */
+	/* Set: Output Enable  (0x4) */
+	m = inl(GPIOL_OUTPUT_ENABLE);
+	m |= GPIOL_8_SET;
+	m &= ~GPIOL_8_CLEAR;
+	//outl(m,GPIOL_OUTPUT_ENABLE);
+	/* Set: OUTAUX1 Select (0x10) */
+	m = inl(GPIOL_OUT_AUX1_SELECT);
+	m |= GPIOL_8_SET;
+	m &= ~GPIOL_8_CLEAR;
+	//outl(m,GPIOL_OUT_AUX1_SELECT);
+	/* Set: Pull Up        (0x18) */
+	m = inl(GPIOL_PULLUP_ENABLE);
+	m |= GPIOL_8_SET;
+	m &= ~GPIOL_8_CLEAR;
+	/* GPIO9 - UART1_RX */
+	/* Set: Pull Up        (0x18) */
+	m |= GPIOL_9_SET;
+	m &= ~GPIOL_9_CLEAR;
+	//outl(m,GPIOL_PULLUP_ENABLE);
+	/* Set: Input Enable   (0x20) */
+	m = inl(GPIOL_INPUT_ENABLE);
+	m |= GPIOL_9_SET;
+	m &= ~GPIOL_9_CLEAR;
+	//outl(m,GPIOL_INPUT_ENABLE);
+	/* Set: INAUX1 Select  (0x34) */
+	m = inl(GPIOL_IN_AUX1_SELECT);
+	m |= GPIOL_9_SET;
+	m &= ~GPIOL_9_CLEAR;
+	//outl(m,GPIOL_IN_AUX1_SELECT);
+
+	msr = rdmsr(MDD_LEG_IO);
+	msr.lo |= 0x7 << 16;
+	//wrmsr(MDD_LEG_IO,msr);
+	
+	// GX3: my board has UART2 wired up ;)
+
+
+	// enable UART2 as COM1
+	msr = rdmsr(MDD_LEG_IO);
+	msr.lo |= 0x700000;
+	wrmsr(MDD_LEG_IO, msr);
+
+	// reset UART2
+	msr = rdmsr(MDD_UART2_CONF);
+	msr.lo = 1;
+	wrmsr(MDD_UART2_CONF, msr);
+
+	// clear reset UART2
+	msr.lo = 0;
+	wrmsr(MDD_UART2_CONF, msr);
+
+	// enable UART2
+	msr.lo = 2;
+	wrmsr(MDD_UART2_CONF, msr);
+
+
+	// Set DLAB
+	n = 0x80;
+	outb(n, TTYS0_BASE + 3);
+ 
+	// Baud rate divisor
+	n = 0x01;
+	outb(n, TTYS0_BASE);
+
+	//  Line mode (8N1)
+	n = 0x03;
+	outb(n, TTYS0_BASE + 3);
+
+	//	Clear DTR & RTS
+	n = 0x00;
+	outb(n, TTYS0_BASE + 4);
+	
+}
+
+/* note: you can't do prints in here in most cases, 
+ * and we don't want to hang on serial, so they are 
+ * commented out 
+ */
+static int cs5536_early_setup(void)
+{
+	msr_t msr;
+
+	cs5536_setup_extmsr();
+
+/*	msr = rdmsr(GLCP_SYS_RSTPLL);
+	if (msr.lo & (0x3f << 26)) {
+		// PLL is already set and we are reboot from PLL reset
+		//print_debug("reboot from BIOS reset\n\r");
+		return;
+	}*/
+	
+	//print_debug("Setup idsel\r\n");
+	cs5536_setup_idsel();
+	//print_debug("Setup iobase\r\n");
+	cs5536_usb_swapsif();
+	cs5536_setup_iobase();
+	//print_debug("Setup gpio\r\n");
+	cs5536_setup_gpio();
+	//print_debug("Setup cis_mode\r\n");
+	cs5536_setup_cis_mode();
+	//print_debug("Setup smbus\r\n");
+	cs5536_enable_smbus();
+
+	// ide/flash bit goes to default on reset
+	// this value depends on boot straps
+	// lets set it to known enabled value
+	// later, cs5536_enable_ide_nand_flash changes it if needed.
+	//cs5536_enable_ide();
+
+
+	dummy();
+}

Added: trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_early_smbus.c
===================================================================
--- trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_early_smbus.c	                        (rev 0)
+++ trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_early_smbus.c	2006-09-18 22:52:24 UTC (rev 2421)
@@ -0,0 +1,45 @@
+#include "cs5536_smbus.h"
+
+#define SMBUS_IO_BASE 0x6000
+
+/* initialization for SMBus Controller */
+static int cs5536_enable_smbus(void)
+{
+	unsigned char val;
+
+	/* reset SMBUS controller */
+	outb(0, SMBUS_IO_BASE + SMB_CTRL2);
+
+	/* Set SCL freq and enable SMB controller */
+	val = inb(SMBUS_IO_BASE + SMB_CTRL2);
+	val |= ((0x20 << 1) | SMB_CTRL2_ENABLE);
+	outb(val, SMBUS_IO_BASE + SMB_CTRL2);
+
+	/* Setup SMBus host controller address to 0xEF */
+	val = inb(SMBUS_IO_BASE + SMB_ADD);
+	val |= (0xEF | SMB_ADD_SAEN);
+	outb(val, SMBUS_IO_BASE + SMB_ADD); 
+}
+
+static int smbus_read_byte(unsigned device, unsigned address)
+{
+        return do_smbus_read_byte(SMBUS_IO_BASE, device, address-1);
+}
+
+#if 0
+static int smbus_recv_byte(unsigned device)
+{
+        return do_smbus_recv_byte(SMBUS_IO_BASE, device);
+}
+
+static int smbus_send_byte(unsigned device, unsigned char val)
+{
+        return do_smbus_send_byte(SMBUS_IO_BASE, device, val);
+}
+
+
+static int smbus_write_byte(unsigned device, unsigned address, unsigned char val)
+{
+        return do_smbus_write_byte(SMBUS_IO_BASE, device, address, val);
+}
+#endif

Added: trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_ide.c
===================================================================
--- trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_ide.c	                        (rev 0)
+++ trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_ide.c	2006-09-18 22:52:24 UTC (rev 2421)
@@ -0,0 +1,30 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include "cs5536.h"
+
+static void ide_init(struct device *dev)
+{
+	printk_spew("cs5536_ide: %s\n", __FUNCTION__);
+}
+
+static void ide_enable(struct device *dev)
+{
+	printk_spew("cs5536_ide: %s\n", __FUNCTION__);
+}
+
+static struct device_operations ide_ops = {
+	.read_resources   = pci_dev_read_resources,
+	.set_resources    = pci_dev_set_resources,
+	.enable_resources = pci_dev_enable_resources,
+	.init             = ide_init,
+	.enable           = ide_enable,
+};
+
+static struct pci_driver ide_driver __pci_driver = {
+	.ops 	= &ide_ops,
+	.vendor = PCI_VENDOR_ID_AMD,
+	.device = PCI_DEVICE_ID_AMD_CS5536_IDE,
+};

Added: trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_smbus.h
===================================================================
--- trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_smbus.h	                        (rev 0)
+++ trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_smbus.h	2006-09-18 22:52:24 UTC (rev 2421)
@@ -0,0 +1,180 @@
+//#include <device/smbus_def.h>
+#define SMBUS_ERROR -1
+#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
+#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT  -3
+
+#define	SMB_SDA		0x00
+#define SMB_STS		0x01
+#define SMB_CTRL_STS	0x02
+#define	SMB_CTRL1	0x03
+#define SMB_ADD		0x04
+#define SMB_CTRL2	0x05
+#define	SMB_CTRL3	0x06
+
+#define SMB_STS_SLVSTP	(0x01 << 7)
+#define SMB_STS_SDAST	(0x01 << 6)
+#define	SMB_STS_BER	(0x01 << 5)
+#define SMB_STS_NEGACK	(0x01 << 4)
+#define	SMB_STS_STASTR	(0x01 << 3)
+#define SMB_STS_NMATCH	(0x01 << 2)
+#define	SMB_STS_MASTER	(0x01 << 1)
+#define SMB_STS_XMIT	(0x01 << 0)
+
+#define	SMB_CSTS_TGSCL	(0x01 << 5)
+#define SMB_CSTS_TSDA	(0x01 << 4)
+#define	SMB_CSTS_GCMTCH	(0x01 << 3)
+#define SMB_CSTS_MATCH	(0x01 << 2)
+#define	SMB_CSTS_BB	(0x01 << 1)
+#define SMB_CSTS_BUSY	(0x01 << 0)
+
+#define	SMB_CTRL1_STASTRE (0x01 << 7)
+#define SMB_CTRL1_NMINTE  (0x01 << 6)
+#define	SMB_CTRL1_GCMEN   (0x01 << 5)
+#define SMB_CTRL1_ACK     (0x01 << 4)
+#define	SMB_CTRL1_RSVD    (0x01 << 3)
+#define SMB_CTRL1_INTEN   (0x01 << 2)
+#define	SMB_CTRL1_STOP    (0x01 << 1)
+#define SMB_CTRL1_START   (0x01 << 0)
+
+#define	SMB_ADD_SAEN	  (0x01 << 7)
+
+#define	SMB_CTRL2_ENABLE  0x01
+
+#define SMBUS_TIMEOUT (100*1000*10)
+#define SMBUS_STATUS_MASK 0xfbff
+
+#define SMBUS_IO_BASE 0x6000
+
+static void smbus_delay(void)
+{
+    	outb(0x80, 0x80);
+}
+
+/* generate a smbus start condition */
+static int smbus_start_condition(unsigned smbus_io_base)
+{
+	unsigned char val;
+	unsigned long loops;
+	loops = SMBUS_TIMEOUT;
+
+	/* issue a START condition */
+	val = inb(smbus_io_base + SMB_CTRL1);
+	outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1);
+
+	/* check for bus conflict */
+	val = inb(smbus_io_base + SMB_STS);
+	if ((val & SMB_STS_BER) != 0)
+		return SMBUS_ERROR;
+
+	/* check for SDA status */
+	do {
+		smbus_delay();
+		val = inw(smbus_io_base + SMB_STS);
+		if ((val & SMB_STS_SDAST) != 0) {
+			break;
+		}
+	} while(--loops);
+	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+}
+
+static int smbus_check_stop_condition(unsigned smbus_io_base)
+{
+	unsigned char val;
+	unsigned long loops;
+	loops = SMBUS_TIMEOUT;
+	/* check for SDA status */
+	do {
+		smbus_delay();
+		val = inw(smbus_io_base + SMB_CTRL1);
+		if ((val & SMB_CTRL1_STOP) == 0) {
+			break;
+		}
+	} while(--loops);
+	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+}
+
+static int smbus_stop_condition(unsigned smbus_io_base)
+{
+	unsigned char val;
+	val = inb(smbus_io_base + SMB_CTRL1);
+	outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1);
+}
+
+static int smbus_send_slave_address(unsigned smbus_io_base, unsigned char device)
+{
+	unsigned char val;
+	unsigned long loops;
+	loops = SMBUS_TIMEOUT;
+                        
+	/* send the slave address */
+	outb(device, smbus_io_base + SMB_SDA);
+
+	/* check for bus conflict and NACK */
+	val = inb(smbus_io_base + SMB_STS);
+	if (((val & SMB_STS_BER)    != 0) ||
+	    ((val & SMB_STS_NEGACK) != 0))
+		return SMBUS_ERROR;
+
+	/* check for SDA status */
+	do {
+		smbus_delay();
+		val = inw(smbus_io_base + SMB_STS);
+		if ((val & SMB_STS_SDAST) != 0) {
+			break;
+		}
+	} while(--loops);
+	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;	
+}
+
+static int smbus_send_command(unsigned smbus_io_base, unsigned char command)
+{
+        unsigned char val;
+	unsigned long loops;
+	loops = SMBUS_TIMEOUT;
+
+	/* send the command */
+	outb(command, smbus_io_base + SMB_SDA);
+
+	/* check for bus conflict and NACK */
+	val = inb(smbus_io_base + SMB_STS);
+	if (((val & SMB_STS_BER)    != 0) ||
+	    ((val & SMB_STS_NEGACK) != 0))
+		return SMBUS_ERROR;
+
+	/* check for SDA status */
+	do {
+		smbus_delay();
+		val = inw(smbus_io_base + SMB_STS);
+		if ((val & SMB_STS_SDAST) != 0) {
+			break;
+		}
+	} while(--loops);
+	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;	
+}
+
+static unsigned char do_smbus_read_byte(unsigned smbus_io_base, unsigned char device, unsigned char address)
+{
+	unsigned char val, val1;
+
+	smbus_check_stop_condition(smbus_io_base);
+
+	smbus_start_condition(smbus_io_base);
+
+	smbus_send_slave_address(smbus_io_base, device);
+
+	smbus_send_command(smbus_io_base, address);
+
+	smbus_start_condition(smbus_io_base);
+
+	smbus_send_slave_address(smbus_io_base, device | 0x01);
+
+	/* send NACK to slave */
+	val = inb(smbus_io_base + SMB_CTRL1);
+	outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
+
+	val = inb(smbus_io_base + SMB_SDA);
+
+	//smbus_stop_condition(smbus_io_base);
+
+	return val;
+}

Added: trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_smbus2.h
===================================================================
--- trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_smbus2.h	                        (rev 0)
+++ trunk/LinuxBIOSv2/src/southbridge/amd/cs5536_lx/cs5536_smbus2.h	2006-09-18 22:52:24 UTC (rev 2421)
@@ -0,0 +1,299 @@
+//#include <device/smbus_def.h>
+#define SMBUS_ERROR -1
+#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
+#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT  -3
+
+#define	SMB_SDA		0x00
+#define SMB_STS		0x01
+#define SMB_CTRL_STS	0x02
+#define	SMB_CTRL1	0x03
+#define SMB_ADD		0x04
+#define SMB_CTRL2	0x05
+#define	SMB_CTRL3	0x06
+
+#define SMB_STS_SLVSTP	(0x01 << 7)
+#define SMB_STS_SDAST	(0x01 << 6)
+#define	SMB_STS_BER	(0x01 << 5)
+#define SMB_STS_NEGACK	(0x01 << 4)
+#define	SMB_STS_STASTR	(0x01 << 3)
+#define SMB_STS_NMATCH	(0x01 << 2)
+#define	SMB_STS_MASTER	(0x01 << 1)
+#define SMB_STS_XMIT	(0x01 << 0)
+
+#define	SMB_CSTS_TGSCL	(0x01 << 5)
+#define SMB_CSTS_TSDA	(0x01 << 4)
+#define	SMB_CSTS_GCMTCH	(0x01 << 3)
+#define SMB_CSTS_MATCH	(0x01 << 2)
+#define	SMB_CSTS_BB	(0x01 << 1)
+#define SMB_CSTS_BUSY	(0x01 << 0)
+
+#define	SMB_CTRL1_STASTRE (0x01 << 7)
+#define SMB_CTRL1_NMINTE  (0x01 << 6)
+#define	SMB_CTRL1_GCMEN   (0x01 << 5)
+#define SMB_CTRL1_ACK     (0x01 << 4)
+#define	SMB_CTRL1_RSVD    (0x01 << 3)
+#define SMB_CTRL1_INTEN   (0x01 << 2)
+#define	SMB_CTRL1_STOP    (0x01 << 1)
+#define SMB_CTRL1_START   (0x01 << 0)
+
+#define	SMB_ADD_SAEN	  (0x01 << 7)
+
+#define	SMB_CTRL2_ENABLE  0x01
+
+#define SMBUS_TIMEOUT (100*1000*10)
+#define SMBUS_STATUS_MASK 0xfbff
+
+#define SMBUS_IO_BASE 0x6000
+
+static void smbus_delay(void)
+{
+	outb(0x80, 0x80);
+}
+
+static int smbus_wait(unsigned smbus_io_base) {
+	unsigned long loops = SMBUS_TIMEOUT;
+	unsigned char val;
+
+	do {
+		smbus_delay();
+		val = inb(smbus_io_base + SMB_STS);
+		if ((val & SMB_STS_SDAST) != 0)
+			break;
+		if (val & (SMB_STS_BER | SMB_STS_NEGACK)) {
+			printk_debug("SMBUS WAIT ERROR %x\n", val);
+			return SMBUS_ERROR;
+		}
+	} while(--loops);
+
+	outb(0, smbus_io_base + SMB_STS);
+	return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+}
+
+static int smbus_write(unsigned smbus_io_base, unsigned char byte) {
+
+	outb(byte, smbus_io_base + SMB_SDA);
+	return smbus_wait(smbus_io_base);
+}
+
+/* generate a smbus start condition */
+static int smbus_start_condition(unsigned smbus_io_base)
+{
+	unsigned char val;
+
+	/* issue a START condition */
+	val = inb(smbus_io_base + SMB_CTRL1);
+	outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1);
+
+	/* check for bus conflict */
+	val = inb(smbus_io_base + SMB_STS);
+	if ((val & SMB_STS_BER) != 0)
+		return SMBUS_ERROR;
+
+	return smbus_wait(smbus_io_base);
+}
+
+static int smbus_check_stop_condition(unsigned smbus_io_base)
+{
+	unsigned char val;
+	unsigned long loops;
+	loops = SMBUS_TIMEOUT;
+	/* check for SDA status */
+	do {
+		smbus_delay();
+		val = inb(smbus_io_base + SMB_CTRL1);
+		if ((val & SMB_CTRL1_STOP) == 0) {
+			break;
+		}
+	} while(--loops);
+	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
+
+	/* Make sure everything is cleared and ready to go */
+
+	val = inb(smbus_io_base + SMB_CTRL1);
+	outb(val & ~(SMB_CTRL1_STASTRE | SMB_CTRL1_NMINTE),
+			smbus_io_base + SMB_CTRL1);
+
+	outb(SMB_STS_BER | SMB_STS_NEGACK | SMB_STS_STASTR,
+			smbus_io_base + SMB_STS);
+
+	val = inb(smbus_io_base + SMB_CTRL_STS);
+	outb(val | SMB_CSTS_BB, smbus_io_base + SMB_CTRL_STS);
+}
+
+static int smbus_stop_condition(unsigned smbus_io_base)
+{
+	unsigned char val;
+	val = inb(smbus_io_base + SMB_CTRL1);
+	outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1);
+
+	return 0;
+}
+
+static int smbus_ack(unsigned smbus_io_base, int state)
+{
+	unsigned char val = inb(smbus_io_base + SMB_CTRL1);
+
+	if (state)
+		outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
+	else
+		outb(val & ~SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
+
+	return 0;
+}
+
+static int smbus_send_slave_address(unsigned smbus_io_base, unsigned char device)
+{
+	unsigned char val;
+
+	/* send the slave address */
+	outb(device, smbus_io_base + SMB_SDA);
+
+	/* check for bus conflict and NACK */
+	val = inb(smbus_io_base + SMB_STS);
+	if (((val & SMB_STS_BER)    != 0) ||
+	    ((val & SMB_STS_NEGACK) != 0)) {
+		printk_debug("SEND SLAVE ERROR (%x)\n", val);
+		return SMBUS_ERROR;
+	}
+	return smbus_wait(smbus_io_base);
+}
+
+static int smbus_send_command(unsigned smbus_io_base, unsigned char command)
+{
+        unsigned char val;
+
+	/* send the command */
+	outb(command, smbus_io_base + SMB_SDA);
+
+	/* check for bus conflict and NACK */
+	val = inb(smbus_io_base + SMB_STS);
+	if (((val & SMB_STS_BER)    != 0) ||
+	    ((val & SMB_STS_NEGACK) != 0))
+		return SMBUS_ERROR;
+
+	return smbus_wait(smbus_io_base);
+}
+
+static void _doread(unsigned smbus_io_base, unsigned char device,
+		unsigned char address, unsigned char *data, int count)
+{
+	int ret;
+	int index = 0;
+	unsigned char val;
+
+	if ((ret = smbus_check_stop_condition(smbus_io_base)))
+		goto err;
+
+	index++;
+
+	if ((ret = smbus_start_condition(smbus_io_base)))
+		goto err;
+
+	index++; /* 2 */
+	if ((ret = smbus_send_slave_address(smbus_io_base, device)))
+		goto err;
+
+	index++;
+	if ((ret = smbus_send_command(smbus_io_base, address)))
+		goto err;
+
+	index++;
+	if ((ret = smbus_start_condition(smbus_io_base)))
+		goto err;
+
+	/* Clear the ack for multiple byte reads */
+	smbus_ack(smbus_io_base, (count == 1) ? 1 : 0);
+
+	index++;
+	if ((ret = smbus_send_slave_address(smbus_io_base, device | 0x01)))
+		goto err;
+
+	while(count) {
+		/* Set the ACK if this is the next to last byte */
+		smbus_ack(smbus_io_base, (count == 2) ? 1 : 0);
+
+		/* Set the stop bit if this is the last byte to read */
+
+		if (count == 1)
+			smbus_stop_condition(smbus_io_base);
+
+		val = inb(smbus_io_base + SMB_SDA);
+		*data++ = val;
+
+		if (count > 1) {
+			int ret = smbus_wait(smbus_io_base);
+			if (ret)
+				return ret;
+		}
+
+		count--;
+	}
+
+	return;
+
+ err:
+	printk_debug("SMBUS READ ERROR (%d): %d\n", index, ret);
+}
+
+static unsigned char do_smbus_read_byte(unsigned smbus_io_base,
+		unsigned char device,
+					unsigned char address)
+{
+	unsigned char val = 0;
+	_doread(smbus_io_base, device, address, &val, sizeof(val));
+	return val;
+}
+
+static unsigned short do_smbus_read_word(unsigned smbus_io_base,
+		unsigned char device, unsigned char address)
+{
+	unsigned short val = 0;
+	_doread(smbus_io_base, device, address, (unsigned char *) &val,
+			sizeof(val));
+	return val;
+}
+
+static int _dowrite(unsigned smbus_io_base, unsigned char device,
+		unsigned char address, unsigned char *data, int count) {
+
+	int ret;
+
+	if ((ret = smbus_check_stop_condition(smbus_io_base)))
+		goto err;
+
+	if ((ret = smbus_start_condition(smbus_io_base)))
+		goto err;
+
+	if ((ret = smbus_send_slave_address(smbus_io_base, device)))
+		goto err;
+
+	if ((ret = smbus_send_command(smbus_io_base, address)))
+		goto err;
+
+	while(count) {
+		if ((ret = smbus_write(smbus_io_base, *data++)))
+			goto err;
+		count--;
+	}
+
+	smbus_stop_condition(smbus_io_base);
+	return 0;
+
+ err:
+	printk_debug("SMBUS WRITE ERROR: %d\n", ret);
+	return -1;
+}
+
+
+static int do_smbus_write_byte(unsigned smbus_io_base, unsigned char device,
+		unsigned char address, unsigned char data)
+{
+	return _dowrite(smbus_io_base, device, address,
+			(unsigned char *) &data, 1);
+}
+
+static int do_smbus_write_word(unsigned smbus_io_base, unsigned char device, unsigned char address,
+			       unsigned short data)
+{
+	return _dowrite(smbus_io_base, device ,address, (unsigned char *) &data, 2);
+}





More information about the coreboot mailing list